Function unit interfaces follow a certain de facto standard in TCE. Here is an example of a such interface:
entity fu_add_sub_eq_gt_always_1 is generic ( dataw : integer := 32; busw : integer := 32); port ( -- trigger port / operand2 input port t1data : in std_logic_vector (dataw-1 downto 0); t1opcode : in std_logic_vector (1 downto 0); t1load : in std_logic; -- operand1 input port o1data : in std_logic_vector (dataw-1 downto 0); o1load : in std_logic; -- result output port r1data : out std_logic_vector (busw-1 downto 0); -- control signals glock : in std_logic; rstx : in std_logic; clk : in std_logic); end fu_add_sub_eq_gt_always_1;
As you can see the actual implementation interface has more inputs/outputs than the architecture model of a FU. Architecture input ports are called o1data and t1data and the output port is called r1data. In addition there are load ports, operation code port and some control signals.
It is good practice to use (integer) generics for the port widths in the data I/O ports. This makes the managing of Hardware Database (HDB) easier because you can use the name of the generic to define port width formulas instead of using magic numbers. Whether the value of a generic is constant or parametrizable depends on how you define it in the HDB. In the example entity declaration we have used two different generics, data width (dataw) and bus width (busw). The input data ports depend on the dataw and the output port is defined using busw. You can also use only one generic but with 2 generics you can define different widths for input and output data if needed.
The names you set for the ports in VHDL code is up to you. When you define an FU implementation in HDB you'll have to do port mapping where you map the VHDL implementation names to the HDB counterparts. I strongly recommend to use a consistent naming convention to avoid confusion. HDBEditor prefills the common control signal dialog fields with the defacto standard names. If you use your own naming style for the ports I still recommend to use the standard names for control signals which are used in the example above (glock = Global Lock, rstx = reset (x stands for active low), clk = clock).
The input ports have also load ports. The load signal is active high when the input value of an input port is valid and should be read (most probably to a register inside the FU). If the input port is also a trigger port the operation should be initiated.
If the FU has multiple operations there is also an operation code port in the interface. Opcode port is usually bound to the trigger port because operations have at least one input. And if you wish to initiate an operation with one input operand, the operand has to be written to the trigger port. Operation codes also have to be declared in HDB.
FUs can also have ports connecting to the external of the TTA processor core. They are declared like any other ports in the entity declaration but these ports must be defined as external in HDB.
See the TCE Tour-tutorial (Section 3.1) for an example how to add an FU implementation to hdb.
Operation name | Operation code |
Add | 0 |
And | 1 |
Not | 2 |
Sub | 3 |
Xor | 4 |
HDBEditor and Processor Generator will issue a warning message if this guideline is not used in operation code numbering. Currently other numbering conventions can still be used but the support might be dropped in future versions of TCE. In order to ensure compatibility it is recommended that you use this new convention.
VHDL-type: std_logic_vector
t1data
for the triggering input port
and o1data, o2data ...
etc. for the rest of input operands. Output port
is usually called r1data
.
Use generics when you define widths for these ports.
VHDL-type: std_logic
t1load
and o1data is o1load
.
VHDL-type: std_logic_vector
t1opcode
and it is bound to the
trigger port.
VHDL-type: std_logic
clk
is the most obvious, it is the clock signal
rstx
is active low reset (x stands for active low)
glock
is a Global Lock signal. For example if the global control unit
(GCU) issues global lock the ongoing operation should freeze and wait for
the global lock signal to become inactive before resuming execution.
glock_r
is global lock request. Rarely used in normal function units.
It can be used to request global lock state, for example, in case the
result does not arrive in the time set by the static latency of the
operation.
A common example using this signal is a load-store unit of which memory latency is sometimes larger than the static latency informed to the compiler due to dynamic behavior of the memory system. In that case, a global lock is requested after the static number of cycles has passed and the data has not arrived to the load-store-unit from the memory system.
Currently there is only one reserved keyword in generic definitions and it is
addrw
. This keyword is used in load-store units to define trigger
port's width according to the data address space width. Processor Generator
identifies this keyword and defines the port width from the data address space
assigned to the LSU in the ADF.
Pekka Jääskeläinen 2018-03-12