SURF  1.0
AxiStreamPacketizerMux.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : AxiStreamPacketizer
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2015-09-29
5 -- Last update: 2016-04-30
6 -------------------------------------------------------------------------------
7 -- Description: Formats an AXI-Stream for a transport link.
8 -- Sideband fields are placed into the data stream in a header.
9 -- Long frames are broken into smaller packets. (non-interleave only)
10 -------------------------------------------------------------------------------
11 -- This file is part of 'SLAC Firmware Standard Library'.
12 -- It is subject to the license terms in the LICENSE.txt file found in the
13 -- top-level directory of this distribution and at:
14 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
15 -- No part of 'SLAC Firmware Standard Library', including this file,
16 -- may be copied, modified, propagated, or distributed except according to
17 -- the terms contained in the LICENSE.txt file.
18 -------------------------------------------------------------------------------
19 
20 library ieee;
21 use ieee.std_logic_1164.all;
22 use ieee.std_logic_unsigned.all;
23 use ieee.std_logic_arith.all;
24 
25 use work.StdRtlPkg.all;
26 use work.ArbiterPkg.all;
27 use work.AxiStreamPkg.all;
28 use work.SsiPkg.all;
29 
30 --! @see entity
31  --! @ingroup axi
33 
34  generic (
35  TPD_G : time := 1 ns;
36  MAX_PACKET_BYTES_G : integer := 1440; -- Must be a multiple of 8
37  MIN_TKEEP_G : slv(15 downto 0) := X"0001";
38  INPUT_PIPE_STAGES_G : integer := 0;
39  OUTPUT_PIPE_STAGES_G : integer := 0;
40  NUM_SLAVES_G : integer range 1 to 32 := 4;
41  TDEST_HIGH_G : integer range 0 to 7 := 7;
42  TDEST_LOW_G : integer range 0 to 7 := 0;
43  KEEP_TDEST_G : boolean := true);
44 
45 
46  port (
47  -- AXI-Lite Interface for local registers
48  axisClk : in sl;
49  axisRst : in sl;
50 
53  disableSel : in slv(NUM_SLAVES_G-1 downto 0) := (others => '0');
54 
57 
58 end entity AxiStreamPacketizerMux;
59 
60 architecture rtl of AxiStreamPacketizerMux is
61 
62  -- Packetizer constants
63  constant MAX_WORD_COUNT_C : integer := (MAX_PACKET_BYTES_G / 8) - 3;
64  constant AXIS_CONFIG_C : AxiStreamConfigType := ssiAxiStreamConfig(8, TKEEP_NORMAL_C);
65  constant VERSION_C : slv(3 downto 0) := "0000";
66 
67  -- Mux arbiter constants
68  constant DEST_SIZE_C : integer := bitSize(NUM_SLAVES_G-1);
69  constant ARB_BITS_C : integer := 2**DEST_SIZE_C;
70 
71  type StateType is (ARBITRATE_S, HEADER_S, MOVE_S, TAIL_S);
72 
73  type RegType is record
74  state : StateType;
75  frameNumber : slv(11 downto 0);
76  packetNumber : slv(23 downto 0);
77  packetNumberWe : sl;
78  wordCount : slv(bitSize(MAX_WORD_COUNT_C)-1 downto 0);
79  eof : sl;
80  tUserLast : slv(7 downto 0);
81  acks : slv(ARB_BITS_C-1 downto 0);
82  ackNum : slv(DEST_SIZE_C-1 downto 0);
83  valid : sl;
84  selDest : slv(7 downto 0);
85  inputAxisSlaves : AxiStreamSlaveArray(NUM_SLAVES_G-1 downto 0);
86  outputAxisMaster : AxiStreamMasterType;
87  end record RegType;
88 
89  constant REG_INIT_C : RegType := (
90  state => ARBITRATE_S,
91  frameNumber => (others => '0'),
92  packetNumber => (others => '0'),
93  packetNumberWe => '0',
94  wordCount => (others => '0'),
95  eof => '0',
96  tUserLast => (others => '0'),
97  acks => (others => '0'),
98  ackNum => (others => '1'),
99  valid => '0',
100  selDest => (others => '0'),
101  inputAxisSlaves => (others => AXI_STREAM_SLAVE_INIT_C),
102  outputAxisMaster => axiStreamMasterInit(AXIS_CONFIG_C));
103 
104  signal r : RegType := REG_INIT_C;
105  signal rin : RegType;
106 
107  signal packetNumberOut : slv(23 downto 0);
108 
109  signal inputAxisMasters : AxiStreamMasterArray(NUM_SLAVES_G-1 downto 0);
110  signal inputAxisSlaves : AxiStreamSlaveArray(NUM_SLAVES_G-1 downto 0);
111  signal outputAxisMaster : AxiStreamMasterType;
112  signal outputAxisSlave : AxiStreamSlaveType;
113 
114 begin
115 
116  assert ((MAX_PACKET_BYTES_G rem 8) = 0)
117  report "MAX_PACKET_BYTES_G must be a multiple of 8" severity error;
118 
119  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
120  -- Input pipeline
121  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
122  INPUT_PIPELINES : for i in NUM_SLAVES_G-1 downto 0 generate
123  U_AxiStreamPipeline_Input : entity work.AxiStreamPipeline
124  generic map (
125  TPD_G => TPD_G,
127  port map (
128  axisClk => axisClk, -- [in]
129  axisRst => axisRst, -- [in]
130  sAxisMaster => sAxisMasters(i), -- [in]
131  sAxisSlave => sAxisSlaves(i), -- [out]
132  mAxisMaster => inputAxisMasters(i), -- [out]
133  mAxisSlave => inputAxisSlaves(i)); -- [in]
134  end generate;
135 
136  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
137  -- Output pipeline
138  -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
139  U_AxiStreamPipeline_Output : entity work.AxiStreamPipeline
140  generic map (
141  TPD_G => TPD_G,
143  port map (
144  axisClk => axisClk, -- [in]
145  axisRst => axisRst, -- [in]
146  sAxisMaster => outputAxisMaster, -- [in]
147  sAxisSlave => outputAxisSlave, -- [out]
148  mAxisMaster => mAxisMaster, -- [out]
149  mAxisSlave => mAxisSlave); -- [in]
150 
151  -------------------------------------------------------------------------------------------------
152  -- Packet Count ram
153  -- track current packet count for each tDest
154  -------------------------------------------------------------------------------------------------
155  U_QuadPortRam_1 : entity work.QuadPortRam
156  generic map (
157  TPD_G => TPD_G,
158  REG_EN_G => false,
159  BYTE_WR_EN_G => false,
160  DATA_WIDTH_G => 24,
161  ADDR_WIDTH_G => 8)
162  port map (
163  clka => axisClk, -- [in]
164  wea => r.packetNumberWe, -- [in]
165  rsta => axisRst, -- [in]
166  addra => r.selDest, -- [in]
167  dina => r.packetNumber, -- [in]
168  douta => packetNumberOut); -- [out]
169 
170  -------------------------------------------------------------------------------------------------
171  -- Accumulation sequencing, DMA ring buffer, and AXI-Lite logic
172  -------------------------------------------------------------------------------------------------
173  comb : process (axisRst, disableSel, outputAxisSlave, packetNumberOut, r, sAxisMasters) is
174  variable v : RegType;
175  variable requests : slv(ARB_BITS_C-1 downto 0);
176  variable selData : AxiStreamMasterType;
177  begin
178  v := r;
179 
180  if (outputAxisSlave.tReady = '1') then
181  v.outputAxisMaster.tValid := '0';
182  end if;
183 
184  -- input tReadys 0 by default
185  for i in 0 to NUM_SLAVES_G-1 loop
186  v.inputAxisSlaves(i).tReady := '0';
187  end loop;
188 
189  -- Select source
190  selData := sAxisMasters(conv_integer(r.ackNum));
191 
192  -- Assign tdest
193  if (KEEP_TDEST_G = false) then
194  selData.tDest(7 downto TDEST_LOW_G) := (others => '0');
195  selData.tDest(DEST_SIZE_C+TDEST_LOW_G-1 downto TDEST_LOW_G) := r.ackNum;
196  end if;
197 
198  -- Format requests
199  requests := (others => '0');
200  for i in 0 to (NUM_SLAVES_G-1) loop
201  requests(i) := sAxisMasters(i).tValid and not disableSel(i);
202  end loop;
203 
204  -- Don't write new packet number by default
205  v.packetNumberWe := '0';
206 
207  case r.state is
208  when ARBITRATE_S =>
209  -- Arbitrate between requesters
210  if r.valid = '0' then
211  arbitrate(requests, r.ackNum, v.ackNum, v.valid, v.acks);
212  else
213  -- Reset the Arbitration flag
214  -- Register the selected tDest
215  -- Go to header state
216  v.valid := '0';
217  v.selDest := selData.tDest;
218  v.state := HEADER_S;
219  end if;
220 
221  when HEADER_S =>
222  v.wordCount := (others => '0');
223 
224  -- Place header on output when new data arrived and previous output clear
225  if (selData.tValid = '1' and v.outputAxisMaster.tValid = '0') then
226  v.outputAxisMaster := axiStreamMasterInit(AXIS_CONFIG_C);
227  v.outputAxisMaster.tValid := selData.tValid;
228  v.outputAxisMaster.tData(3 downto 0) := VERSION_C;
229  v.outputAxisMaster.tData(15 downto 4) := r.frameNumber;
230  v.outputAxisMaster.tData(39 downto 16) := packetNumberOut;
231  v.outputAxisMaster.tData(47 downto 40) := selData.tDest(7 downto 0);
232  v.outputAxisMaster.tData(55 downto 48) := selData.tId(7 downto 0);
233  v.outputAxisMaster.tData(63 downto 56) := selData.tUser(7 downto 0);
234  axiStreamSetUserBit(AXIS_CONFIG_C, v.outputAxisMaster, SSI_SOF_C, '1', 0); -- SOF
235  v.state := MOVE_S;
236  v.packetNumber := packetNumberOut + 1;
237  end if;
238 
239  when MOVE_S =>
240 
241  -- Check if clear to move data
242  if (v.outputAxisMaster.tValid = '0') then
243 
244  -- Accept the data
245  v.inputAxisSlaves(conv_integer(r.ackNum)).tReady := '1';
246 
247  -- Send data through
248  v.outputAxisMaster := selData;
249  v.outputAxisMaster.tUser := (others => '0');
250  v.outputAxisMaster.tDest := (others => '0');
251  v.outputAxisMaster.tId := (others => '0');
252 
253  -- Increment word count with each txn
254  v.wordCount := r.wordCount + 1;
255 
256  -- Reach max packet size. Append tail.
257  if (r.wordCount = MAX_WORD_COUNT_C) then
258  v.state := TAIL_S;
259  end if;
260 
261  -- End of frame
262  if (selData.tLast = '1') then
263  -- Increment frame number, clear packetNumber
264  v.frameNumber := r.frameNumber + 1;
265  v.packetNumber := (others => '0');
266  v.state := ARBITRATE_S;
267 
268  -- Need to either append tail to current txn or put tail on next txn (TAIL_S)
269  -- depending on tKeep
270  v.outputAxisMaster.tKeep := MIN_TKEEP_G or (selData.tKeep(14 downto 0) & '1');
271 
272  case (selData.tKeep) is
273  when X"0000" =>
274  v.outputAxisMaster.tData(7 downto 0) := '1' & selData.tUser(6 downto 0);
275  when X"0001" =>
276  v.outputAxisMaster.tData(15 downto 8) := '1' & selData.tUser(14 downto 8);
277  when X"0003" =>
278  v.outputAxisMaster.tData(23 downto 16) := '1' & selData.tUser(22 downto 16);
279  when X"0007" =>
280  v.outputAxisMaster.tData(31 downto 24) := '1' & selData.tUser(30 downto 24);
281  when X"000F" =>
282  v.outputAxisMaster.tData(39 downto 32) := '1' & selData.tUser(38 downto 32);
283  when X"001F" =>
284  v.outputAxisMaster.tData(47 downto 40) := '1' & selData.tUser(46 downto 40);
285  when X"003F" =>
286  v.outputAxisMaster.tData(55 downto 48) := '1' & selData.tUser(54 downto 48);
287  when X"007F" =>
288  v.outputAxisMaster.tData(63 downto 56) := '1' & selData.tUser(62 downto 56);
289  when others => --X"0FFF" or anything else
290  -- Full tkeep. Add new word for tail
291  v.outputAxisMaster.tKeep := selData.tKeep;
292  v.state := TAIL_S;
293  v.tUserLast := selData.tUser(7 downto 0);
294  v.eof := '1';
295  v.outputAxisMaster.tLast := '0';
296  end case;
297 
298  end if;
299  end if;
300 
301  when TAIL_S =>
302  -- Hold off slave side while inserting tail
303  v.inputAxisSlaves(conv_integer(r.ackNum)).tReady := '0';
304 
305  -- Insert tail when master side is ready for it
306  if (v.outputAxisMaster.tValid = '0') then
307  v.outputAxisMaster.tValid := '1';
308  v.outputAxisMaster.tKeep := MIN_TKEEP_G; --X"0001";
309  v.outputAxisMaster.tData := (others => '0');
310  v.outputAxisMaster.tData(7) := r.eof;
311  v.outputAxisMaster.tData(6 downto 0) := r.tUserLast(6 downto 0);
312  v.outputAxisMaster.tUser := (others => '0');
313  v.outputAxisMaster.tLast := '1';
314  v.eof := '0'; -- Clear EOF for next frame
315  v.tUserLast := (others => '0');
316  v.packetNumberWe := '1';
317  v.state := ARBITRATE_S; -- Go to idle and wait for new data
318  end if;
319 
320  end case;
321 
322  ----------------------------------------------------------------------------------------------
323  -- Reset and output assignment
324  ----------------------------------------------------------------------------------------------
325  if (axisRst = '1') then
326  v := REG_INIT_C;
327  end if;
328 
329  rin <= v;
330 
331  inputAxisSlaves <= v.inputAxisSlaves;
332  outputAxisMaster <= r.outputAxisMaster;
333 
334  end process comb;
335 
336  seq : process (axisClk) is
337  begin
338  if (rising_edge(axisClk)) then
339  r <= rin after TPD_G;
340  end if;
341  end process seq;
342 
343 end architecture rtl;
344 
out mAxisMasterAxiStreamMasterType
slv( 7 downto 0) tId
in weasl := '0'
Definition: QuadPortRam.vhd:42
PIPE_STAGES_Gnatural range 0 to 16:= 0
array(natural range <> ) of AxiStreamSlaveType AxiStreamSlaveArray
in dinaslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')
Definition: QuadPortRam.vhd:46
in clkasl := '0'
Definition: QuadPortRam.vhd:40
BYTE_WR_EN_Gboolean := false
Definition: QuadPortRam.vhd:33
out sAxisSlavesAxiStreamSlaveArray( NUM_SLAVES_G- 1 downto 0)
std_logic sl
Definition: StdRtlPkg.vhd:28
integer := 1 SSI_SOF_C
Definition: SsiPkg.vhd:31
TDEST_HIGH_Ginteger range 0 to 7:= 7
out sAxisSlaveAxiStreamSlaveType
slv( 15 downto 0) tKeep
in mAxisSlaveAxiStreamSlaveType
ADDR_WIDTH_Ginteger range 1 to ( 2** 24):= 4
Definition: QuadPortRam.vhd:36
in sAxisMastersAxiStreamMasterArray( NUM_SLAVES_G- 1 downto 0)
TPD_Gtime := 1 ns
Definition: QuadPortRam.vhd:29
out doutaslv( DATA_WIDTH_G- 1 downto 0)
Definition: QuadPortRam.vhd:47
slv( 127 downto 0) tData
in addraslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
Definition: QuadPortRam.vhd:45
in sAxisMasterAxiStreamMasterType
in disableSelslv( NUM_SLAVES_G- 1 downto 0) :=( others => '0')
AxiStreamSlaveType :=(tReady => '0') AXI_STREAM_SLAVE_INIT_C
slv( 127 downto 0) tUser
NUM_SLAVES_Ginteger range 1 to 32:= 4
in mAxisSlaveAxiStreamSlaveType
array(natural range <> ) of AxiStreamMasterType AxiStreamMasterArray
sl valid
Definition: SsiPkg.vhd:66
out mAxisMasterAxiStreamMasterType
slv( 7 downto 0) tDest
TDEST_LOW_Ginteger range 0 to 7:= 0
in rstasl :=not ( RST_POLARITY_G)
Definition: QuadPortRam.vhd:44
sl eof
Definition: SsiPkg.vhd:73
MIN_TKEEP_Gslv( 15 downto 0) := X"0001"
REG_EN_Gboolean := true
Definition: QuadPortRam.vhd:31
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
Definition: QuadPortRam.vhd:34
std_logic_vector slv
Definition: StdRtlPkg.vhd:29