Let's assume that you are using AXI-Stream and you have defined
1 2 3 4 5 6 7 8 9 10 | type AxiStreamType is record Data : std_logic_vector(63 downto 0); Last : std_logic; Valid : std_logic; Good : std_logic; Keep : std_logic_vector(7 downto 0); end record; signal Data1 : AxiStreamType; signal Data2 : AxiStreamType; |
Then you can assign signals without having to assign each field individually.
1 2 3 4 5 6 7 8 9 | NoRstProc : process (clk) is begin if rising_edge(clk) then Data2 <= Data1; if SomeCodition then Data2.Last <= '1'; end if; end if; end process; |
Try to repeat the same without records and fill the difference.
But how do you reset such a signal? Of course you use the right reset style and reset only signals, you need to reset, but how exactly? You can do it like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 | SimpleProc : process (clk) is begin if rising_edge(clk) then Data2 <= Data1; if SomeCodition then Data2.Last <= '1'; end if; if rst = '1' then Data2.Valid <= '0'; end if; end if; end process; |
but it doesn't scale well. For example, it becomes inconvenient to reset complex data types like records, containing an array of records or even something like this
1 2 | type AxiStreamArrayType is array(0 to 7) of AxiStreamType; |
There is a neat trick I use. Each time I define a record, I also define a reset value for this type.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | type AxiStreamType is record Data : std_logic_vector(63 downto 0); Last : std_logic; Valid : std_logic; Good : std_logic; Keep : std_logic_vector(7 downto 0); end record; constant InvalidAxiStream : AxiStreamType := ( Data => (others => 'U'), Last => 'U', Valid => '0', Good => 'U', Keep => (others => 'U') ); type AxiStreamArrayType is array(0 to 7) of AxiStreamType; constant InvalidAxiStreamArray : AxiStreamArrayType := (others => InvalidAxiStream); |
Having done this, you can reset your signals using this predefined constants.
1 2 3 4 5 6 7 8 9 10 11 12 13 | NeatProc : process (clk) is begin if rising_edge(clk) then Data4 <= Data3; if SomeCodition then -- some other actions end if; if rst = '1' then Data4 <= InvalidAxiStreamArray; end if; end if; end process; |
You can see how laconic it is. You can see that all fields in InvalidAxiStream have undefined values except for Valid field, which we really need to reset. We explicitly tell to synthesizer that we don't care about values of this signals during reset and the synthesizer doesn't generate any logic to reset these signals or to preserve their values during reset. It's exactly what we want. There will be neither reset generated for, say, Keep signal, nor CE logic for the FFs.
Unfortunately, this trick cannot be used for record fields of type integer or enumerated types, so I have to assign some real values to them and reset these fields even if I don't need to. In case I feel super frugal and I don't want to reset additional FFs, I reset only Valid field explicitly:
1 2 3 4 5 | if rst = '1' then for stream in Data4'range loop Data4(stream).Valid <= '0'; end loop; end if; |
This situation is an exception, however. In all other cases this coding style works great!
Please, tell me what you think! Thanks!
No comments:
Post a Comment