SURF  1.0
IpV4EngineTx.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : IpV4EngineTx.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2015-08-12
5 -- Last update: 2016-09-16
6 -------------------------------------------------------------------------------
7 -- Description: IPv4 TX Engine Module
8 -- Note: IPv4 checksum checked in EthMac core
9 -------------------------------------------------------------------------------
10 -- This file is part of 'SLAC Firmware Standard Library'.
11 -- It is subject to the license terms in the LICENSE.txt file found in the
12 -- top-level directory of this distribution and at:
13 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
14 -- No part of 'SLAC Firmware Standard Library', including this file,
15 -- may be copied, modified, propagated, or distributed except according to
16 -- the terms contained in the LICENSE.txt file.
17 -------------------------------------------------------------------------------
18 
19 library ieee;
20 use ieee.std_logic_1164.all;
21 use ieee.std_logic_unsigned.all;
22 use ieee.std_logic_arith.all;
23 
24 use work.StdRtlPkg.all;
25 use work.AxiStreamPkg.all;
26 use work.SsiPkg.all;
27 use work.EthMacPkg.all;
28 
29 --! @see entity
30  --! @ingroup ethernet_IpV4Engine
31 entity IpV4EngineTx is
32  generic (
33  TPD_G : time := 1 ns;
34  PROTOCOL_SIZE_G : positive := 1;
35  PROTOCOL_G : Slv8Array := (0 => UDP_C);
36  TTL_G : slv(7 downto 0) := x"20";
37  VLAN_G : boolean := false);
38  port (
39  -- Local Configurations
40  localMac : in slv(47 downto 0); -- big-Endian configuration
41  -- Interface to Ethernet Frame MUX/DEMUX
44  localhostMaster : out AxiStreamMasterType;
45  localhostSlave : in AxiStreamSlaveType;
46  -- Interface to Protocol Engine
49  -- Clock and Reset
50  clk : in sl;
51  rst : in sl);
52 end IpV4EngineTx;
53 
54 architecture rtl of IpV4EngineTx is
55 
56  type StateType is (
57  IDLE_S,
58  IPV4_HDR0_S,
59  IPV4_HDR1_S,
60  IPV4_HDR2_S,
61  MOVE_S,
62  LAST_S);
63 
64  type RegType is record
65  eofe : sl;
66  tKeep : slv(15 downto 0);
67  tData : slv(127 downto 0);
68  tDest : slv(7 downto 0);
69  id : slv(15 downto 0);
70  rxSlave : AxiStreamSlaveType;
71  txMaster : AxiStreamMasterType;
72  state : StateType;
73  end record RegType;
74  constant REG_INIT_C : RegType := (
75  eofe => '0',
76  tKeep => (others => '0'),
77  tData => (others => '0'),
78  tDest => (others => '0'),
79  id => (others => '0'),
80  rxSlave => AXI_STREAM_SLAVE_INIT_C,
81  txMaster => AXI_STREAM_MASTER_INIT_C,
82  state => IDLE_S);
83 
84  signal r : RegType := REG_INIT_C;
85  signal rin : RegType;
86 
87  signal rxMaster : AxiStreamMasterType;
88  signal rxSlave : AxiStreamSlaveType;
89 
90  signal txMaster : AxiStreamMasterType;
91  signal txSlave : AxiStreamSlaveType;
92 
93  signal mAxisMaster : AxiStreamMasterType;
94  signal mAxisSlave : AxiStreamSlaveType;
95 
96  -- attribute dont_touch : string;
97  -- attribute dont_touch of r : signal is "TRUE";
98 
99 begin
100 
101  AxiStreamMux_Inst : entity work.AxiStreamMux
102  generic map (
103  TPD_G => TPD_G,
104  PIPE_STAGES_G => 0,
106  port map (
107  -- Clock and reset
108  axisClk => clk,
109  axisRst => rst,
110  -- Slave
113  -- Masters
114  mAxisMaster => rxMaster,
115  mAxisSlave => rxSlave);
116 
117  comb : process (localMac, r, rst, rxMaster, txSlave) is
118  variable v : RegType;
119  variable i : natural;
120  begin
121  -- Latch the current value
122  v := r;
123 
124  -- Reset the flags
125  v.rxSlave := AXI_STREAM_SLAVE_INIT_C;
126  if txSlave.tReady = '1' then
127  v.txMaster.tValid := '0';
128  v.txMaster.tLast := '0';
129  v.txMaster.tUser := (others => '0');
130  v.txMaster.tKeep := (others => '1');
131  end if;
132 
133  -- State Machine
134  case r.state is
135  ----------------------------------------------------------------------
136  when IDLE_S =>
137  -- Check if ready to move data
138  if (rxMaster.tValid = '1') and (v.txMaster.tValid = '0') then
139  -- Accept the data
140  v.rxSlave.tReady := '1';
141  -- Latch the TDEST
142  v.tDest := rxMaster.tDest;
143  -- Check for SOF with no EOF
144  if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, rxMaster) = '1') and (rxMaster.tLast = '0') then
145  -- Send the RAW Ethernet header
146  v.txMaster.tValid := '1';
147  -- Set the SOF bit
148  ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1');
149  -- Setup the tDest routing
150  if (localMac = rxMaster.tData(47 downto 0)) then
151  -- Local Host Path
152  v.txMaster.tDest := x"01";
153  else
154  -- Remote Host Path
155  v.txMaster.tDest := x"00";
156  end if;
157  -- Set the DST MAC and SRC MAC
158  v.txMaster.tData(47 downto 0) := rxMaster.tData(47 downto 0);
159  v.txMaster.tData(95 downto 48) := localMac;
160  -- Check for non-VLAN
161  if (VLAN_G = false) then
162  v.txMaster.tData(111 downto 96) := IPV4_TYPE_C;
163  v.txMaster.tData(119 downto 112) := x"45"; -- IPVersion = 4,Header length = 5
164  v.txMaster.tData(127 downto 120) := x"00"; --- DSCP and ECN
165  else
166  -- Set the EtherType = VLAN Type
167  v.txMaster.tData(111 downto 96) := VLAN_TYPE_C;
168  -- VID = 0x0 here because it gets overwritten in the MAC
169  v.txMaster.tData(127 downto 112) := (others => '0');
170  end if;
171  -- Track the leftovers
172  v.tData(63 downto 0) := rxMaster.tData(127 downto 64);
173  -- Next state
174  v.state := IPV4_HDR0_S;
175  end if;
176  end if;
177  ----------------------------------------------------------------------
178  when IPV4_HDR0_S =>
179  -- Check for data
180  if (v.txMaster.tValid = '0') then
181  -- Send the IPV4 header
182  v.txMaster.tValid := '1';
183  -- Check for non-VLAN
184  if (VLAN_G = false) then
185  v.txMaster.tData(7 downto 0) := x"00"; -- IPV4_Length(15 downto 8) Note: Calculated in EthMac core
186  v.txMaster.tData(15 downto 8) := x"00"; -- IPV4_Length(7 downto 0) Note: Calculated in EthMac core
187  v.txMaster.tData(23 downto 16) := r.id(15 downto 8); -- IPV4_ID(15 downto 8)
188  v.txMaster.tData(31 downto 24) := r.id(7 downto 0); -- IPV4_ID(7 downto 0)
189  v.txMaster.tData(39 downto 32) := x"40"; -- Flags(2 downto 0) = Don't Fragment (DF) and Fragment_Offsets(12 downto 8) = 0x0
190  v.txMaster.tData(47 downto 40) := x"00"; -- Fragment_Offsets(7 downto 0) = 0x0
191  v.txMaster.tData(55 downto 48) := TTL_G; -- Time-To-Live (number of hops before packet is discarded)
192  v.txMaster.tData(63 downto 56) := PROTOCOL_G(conv_integer(r.tDest)); -- Protocol
193  v.txMaster.tData(71 downto 64) := x"00"; -- IPV4_Checksum(15 downto 8) Note: Filled in next state
194  v.txMaster.tData(79 downto 72) := x"00"; -- IPV4_Checksum(7 downto 0) Note: Filled in next state
195  v.txMaster.tData(111 downto 80) := r.tData(31 downto 0); -- Source IP Address(31 downto 0)
196  v.txMaster.tData(127 downto 112) := r.tData(47 downto 32); -- Destination IP Address(31 downto 16)
197  else
198  v.txMaster.tData(15 downto 0) := IPV4_TYPE_C;
199  v.txMaster.tData(23 downto 16) := x"45"; -- IPVersion = 4,Header length = 5
200  v.txMaster.tData(31 downto 24) := x"00"; -- DSCP and ECN
201  v.txMaster.tData(39 downto 32) := x"00"; -- IPV4_Length(15 downto 8) Note: Calculated in EthMac core
202  v.txMaster.tData(47 downto 40) := x"00"; -- IPV4_Length(7 downto 0) Note: Calculated in EthMac core
203  v.txMaster.tData(55 downto 48) := r.id(15 downto 8); -- IPV4_ID(15 downto 8)
204  v.txMaster.tData(63 downto 56) := r.id(7 downto 0); -- IPV4_ID(7 downto 0)
205  v.txMaster.tData(71 downto 64) := x"40"; -- Flags(2 downto 0) = Don't Fragment (DF) and Fragment_Offsets(12 downto 8) = 0x0
206  v.txMaster.tData(79 downto 72) := x"00"; -- Fragment_Offsets(7 downto 0) = 0x0
207  v.txMaster.tData(87 downto 80) := TTL_G; -- Time-To-Live (number of hops before packet is discarded)
208  v.txMaster.tData(95 downto 88) := PROTOCOL_G(conv_integer(r.tDest)); -- Protocol
209  v.txMaster.tData(103 downto 96) := x"00"; -- IPV4_Checksum(15 downto 8) Note: Calculated in EthMac core
210  v.txMaster.tData(111 downto 104) := x"00"; -- IPV4_Checksum(7 downto 0) Note: Calculated in EthMac core
211  v.txMaster.tData(127 downto 112) := r.tData(15 downto 0); -- Source IP Address(31 downto 16)
212  end if;
213  -- Increment the counter
214  v.id := r.id + 1;
215  -- Next state
216  v.state := IPV4_HDR1_S;
217  end if;
218  ----------------------------------------------------------------------
219  when IPV4_HDR1_S =>
220  -- Check if ready to move data
221  if (rxMaster.tValid = '1') and (v.txMaster.tValid = '0') then
222  -- Accept the data
223  v.rxSlave.tReady := '1';
224  -- Check for non-VLAN
225  if (VLAN_G = false) then
226  -- Update the tData bus
227  v.txMaster.tData(15 downto 0) := r.tData(63 downto 48); -- Destination IP Address(15 downto 0)
228  v.txMaster.tData(111 downto 16) := rxMaster.tData(127 downto 32);
229  -- Update the tKeep bus
230  v.txMaster.tKeep(1 downto 0) := (others => '1');
231  v.txMaster.tKeep(13 downto 2) := rxMaster.tKeep(15 downto 4);
232  v.txMaster.tKeep(15 downto 14) := (others => '0');
233  -- Get the EOFE
234  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, rxMaster);
235  -- Check for tLast
236  if (rxMaster.tLast = '1') then
237  -- Move the data
238  v.txMaster.tValid := '1';
239  -- Set the tLast flag
240  v.txMaster.tLast := '1';
241  -- Set the EOFE
242  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
243  -- Next state
244  v.state := IDLE_S;
245  else
246  -- Next state
247  v.state := IPV4_HDR2_S;
248  end if;
249  else
250  -- Move the data
251  v.txMaster.tValid := '1';
252  -- Update the tData bus
253  v.txMaster.tData(15 downto 0) := r.tData(31 downto 16); -- Source IP Address(15 downto 0)
254  v.txMaster.tData(47 downto 16) := r.tData(63 downto 32); -- Destination IP Address(31 downto 0)
255  v.txMaster.tData(127 downto 48) := rxMaster.tData(111 downto 32);
256  -- Update the tKeep bus
257  v.txMaster.tKeep(5 downto 0) := (others => '1');
258  v.txMaster.tKeep(15 downto 6) := rxMaster.tKeep(13 downto 4);
259  -- Track the leftovers
260  v.tData(15 downto 0) := rxMaster.tData(127 downto 112);
261  v.tKeep(1 downto 0) := rxMaster.tKeep(15 downto 14);
262  -- Get the EOFE
263  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, rxMaster);
264  -- Check for tLast
265  if (rxMaster.tLast = '1') then
266  -- Check the leftover tKeep is not empty
267  if (v.tKeep /= 0) then
268  -- Next state
269  v.state := LAST_S;
270  else
271  -- Set the EOF/EOFE
272  v.txMaster.tLast := '1';
273  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
274  -- Next state
275  v.state := IDLE_S;
276  end if;
277  else
278  -- Next state
279  v.state := MOVE_S;
280  end if;
281  end if;
282  end if;
283  ----------------------------------------------------------------------
284  when IPV4_HDR2_S =>
285  -- Check for data
286  if (rxMaster.tValid = '1') and (v.txMaster.tValid = '0') then
287  -- Accept the data
288  v.rxSlave.tReady := '1';
289  -- Move the data
290  v.txMaster.tValid := '1';
291  v.txMaster.tData(127 downto 112) := rxMaster.tData(15 downto 0);
292  v.txMaster.tKeep(13 downto 0) := (others => '1');
293  v.txMaster.tKeep(15 downto 14) := rxMaster.tKeep(1 downto 0);
294  -- Track the leftovers
295  v.tData(111 downto 0) := rxMaster.tData(127 downto 16);
296  v.tKeep(13 downto 0) := rxMaster.tKeep(15 downto 2);
297  -- Get the EOFE
298  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, rxMaster);
299  -- Check for tLast
300  if (rxMaster.tLast = '1') then
301  -- Check the leftover tKeep is not empty
302  if (v.tKeep /= 0) then
303  -- Next state
304  v.state := LAST_S;
305  else
306  -- Set the EOF/EOFE
307  v.txMaster.tLast := '1';
308  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
309  -- Next state
310  v.state := IDLE_S;
311  end if;
312  else
313  -- Next state
314  v.state := MOVE_S;
315  end if;
316  end if;
317  ----------------------------------------------------------------------
318  when MOVE_S =>
319  -- Check for data
320  if (rxMaster.tValid = '1') and (v.txMaster.tValid = '0') then
321  -- Accept the data
322  v.rxSlave.tReady := '1';
323  -- Move the data
324  v.txMaster.tValid := '1';
325  -- Check for non-VLAN
326  if (VLAN_G = false) then
327  -- Move the data
328  v.txMaster.tData(111 downto 0) := r.tData(111 downto 0);
329  v.txMaster.tData(127 downto 112) := rxMaster.tData(15 downto 0);
330  v.txMaster.tKeep(13 downto 0) := r.tKeep(13 downto 0);
331  v.txMaster.tKeep(15 downto 14) := rxMaster.tKeep(1 downto 0);
332  -- Track the leftovers
333  v.tData(111 downto 0) := rxMaster.tData(127 downto 16);
334  v.tKeep(13 downto 0) := rxMaster.tKeep(15 downto 2);
335  -- Get the EOFE
336  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, rxMaster);
337  -- Check for tLast
338  if (rxMaster.tLast = '1') then
339  -- Check the leftover tKeep is not empty
340  if (v.tKeep /= 0) then
341  -- Next state
342  v.state := LAST_S;
343  else
344  -- Set the EOF/EOFE
345  v.txMaster.tLast := '1';
346  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
347  -- Next state
348  v.state := IDLE_S;
349  end if;
350  end if;
351  else
352  -- Move the data
353  v.txMaster.tData(15 downto 0) := r.tData(15 downto 0);
354  v.txMaster.tData(127 downto 16) := rxMaster.tData(111 downto 0);
355  v.txMaster.tKeep(1 downto 0) := r.tKeep(1 downto 0);
356  v.txMaster.tKeep(15 downto 2) := rxMaster.tKeep(13 downto 0);
357  -- Track the leftovers
358  v.tData(15 downto 0) := rxMaster.tData(127 downto 112);
359  v.tKeep(1 downto 0) := rxMaster.tKeep(15 downto 14);
360  -- Get the EOFE
361  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, rxMaster);
362  -- Check for tLast
363  if (rxMaster.tLast = '1') then
364  -- Check the leftover tKeep is not empty
365  if (v.tKeep /= 0) then
366  -- Next state
367  v.state := LAST_S;
368  else
369  -- Set the EOF/EOFE
370  v.txMaster.tLast := '1';
371  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
372  -- Next state
373  v.state := IDLE_S;
374  end if;
375  end if;
376  end if;
377  end if;
378  ----------------------------------------------------------------------
379  when LAST_S =>
380  -- Check for data
381  if (v.txMaster.tValid = '0') then
382  -- Move the data
383  v.txMaster.tValid := '1';
384  v.txMaster.tData := r.tData;
385  v.txMaster.tKeep := r.tKeep;
386  v.txMaster.tLast := '1';
387  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, r.eofe);
388  -- Next state
389  v.state := IDLE_S;
390  end if;
391  ----------------------------------------------------------------------
392  end case;
393 
394  -- Reset
395  if (rst = '1') then
396  v := REG_INIT_C;
397  end if;
398 
399  -- Register the variable for next clock cycle
400  rin <= v;
401 
402  -- Outputs
403  rxSlave <= v.rxSlave;
404  txMaster <= r.txMaster;
405 
406  end process comb;
407 
408  seq : process (clk) is
409  begin
410  if rising_edge(clk) then
411  r <= rin after TPD_G;
412  end if;
413  end process seq;
414 
415  U_TxPipeline : entity work.AxiStreamPipeline
416  generic map (
417  TPD_G => TPD_G,
418  PIPE_STAGES_G => 0)
419  port map (
420  axisClk => clk,
421  axisRst => rst,
422  sAxisMaster => txMaster,
423  sAxisSlave => txSlave,
424  mAxisMaster => mAxisMaster,
425  mAxisSlave => mAxisSlave);
426 
427  U_DeMux : entity work.AxiStreamDeMux
428  generic map (
429  TPD_G => TPD_G,
430  PIPE_STAGES_G => 1,
431  NUM_MASTERS_G => 2)
432  port map (
433  -- Clock and reset
434  axisClk => clk,
435  axisRst => rst,
436  -- Slave
437  sAxisMaster => mAxisMaster,
438  sAxisSlave => mAxisSlave,
439  -- Masters
440  mAxisMasters(0) => obIpv4Master,
441  mAxisMasters(1) => localhostMaster,
442  mAxisSlaves(0) => obIpv4Slave,
443  mAxisSlaves(1) => localhostSlave);
444 
445 end rtl;
PIPE_STAGES_Ginteger range 0 to 16:= 0
PIPE_STAGES_Gnatural range 0 to 16:= 0
TPD_Gtime := 1 ns
array(natural range <> ) of AxiStreamSlaveType AxiStreamSlaveArray
std_logic sl
Definition: StdRtlPkg.vhd:28
slv( 15 downto 0) := x"0008" IPV4_TYPE_C
Definition: EthMacPkg.vhd:35
AxiStreamMasterType :=(tValid => '0',tData =>( others => '0'),tStrb =>( others => '1'),tKeep =>( others => '1'),tLast => '0',tDest =>( others => '0'),tId =>( others => '0'),tUser =>( others => '0')) AXI_STREAM_MASTER_INIT_C
sl eofe
Definition: SsiPkg.vhd:74
out sAxisSlaveAxiStreamSlaveType
slv( 15 downto 0) tKeep
in obProtocolMastersAxiStreamMasterArray( PROTOCOL_SIZE_G- 1 downto 0)
in mAxisSlaveAxiStreamSlaveType
in localMacslv( 47 downto 0)
out sAxisSlaveAxiStreamSlaveType
out localhostMasterAxiStreamMasterType
slv( 127 downto 0) tData
in localhostSlaveAxiStreamSlaveType
out mAxisMasterAxiStreamMasterType
NUM_SLAVES_Ginteger range 1 to 32:= 4
in sAxisMasterAxiStreamMasterType
AxiStreamSlaveType :=(tReady => '0') AXI_STREAM_SLAVE_INIT_C
TPD_Gtime := 1 ns
in sAxisMastersAxiStreamMasterArray( NUM_SLAVES_G- 1 downto 0)
in sAxisMasterAxiStreamMasterType
slv( 127 downto 0) tUser
array(natural range <> ) of AxiStreamMasterType AxiStreamMasterArray
out sAxisSlavesAxiStreamSlaveArray( NUM_SLAVES_G- 1 downto 0)
out mAxisMasterAxiStreamMasterType
TPD_Gtime := 1 ns
VLAN_Gboolean := false
slv( 7 downto 0) tDest
slv( 15 downto 0) := x"0081" VLAN_TYPE_C
Definition: EthMacPkg.vhd:36
out obIpv4MasterAxiStreamMasterType
_library_ ieeeieee
TTL_Gslv( 7 downto 0) := x"20"
out obProtocolSlavesAxiStreamSlaveArray( PROTOCOL_SIZE_G- 1 downto 0)
slv( 7 downto 0) := x"11" UDP_C
Definition: EthMacPkg.vhd:39
PROTOCOL_GSlv8Array :=( 0=> UDP_C)
array(natural range <> ) of slv( 7 downto 0) Slv8Array
Definition: StdRtlPkg.vhd:403
PROTOCOL_SIZE_Gpositive := 1
in mAxisSlaveAxiStreamSlaveType
NUM_MASTERS_Ginteger range 1 to 32:= 12
AxiStreamConfigType :=(TSTRB_EN_C => false,TDATA_BYTES_C => 16,TDEST_BITS_C => 8,TID_BITS_C => 0,TKEEP_MODE_C => TKEEP_COMP_C,TUSER_BITS_C => 4,TUSER_MODE_C => TUSER_FIRST_LAST_C) EMAC_AXIS_CONFIG_C
Definition: EthMacPkg.vhd:58
in obIpv4SlaveAxiStreamSlaveType
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
PIPE_STAGES_Ginteger range 0 to 16:= 0