SURF  1.0
UdpEngineTx.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : UdpEngineTx.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2015-08-20
5 -- Last update: 2016-09-16
6 -------------------------------------------------------------------------------
7 -- Description: UDP TX Engine Module
8 -- Note: UDP 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_UdpEngine
31 entity UdpEngineTx is
32  generic (
33  -- Simulation Generics
34  TPD_G : time := 1 ns;
35  -- UDP General Generic
36  SIZE_G : positive := 1;
37  PORT_G : PositiveArray := (0 => 8192));
38  port (
39  -- Interface to IPV4 Engine
42  -- Interface to User Application
43  localIp : in slv(31 downto 0);
44  remotePort : in Slv16Array(SIZE_G-1 downto 0);
45  remoteIp : in Slv32Array(SIZE_G-1 downto 0);
46  remoteMac : in Slv48Array(SIZE_G-1 downto 0);
48  ibSlaves : out AxiStreamSlaveArray(SIZE_G-1 downto 0);
49  -- Interface to DHCP Engine
52  -- Clock and Reset
53  clk : in sl;
54  rst : in sl);
55 end UdpEngineTx;
56 
57 architecture rtl of UdpEngineTx is
58 
59  constant PORT_C : Slv16Array(SIZE_G-1 downto 0) := EthPortArrayBigEndian(PORT_G, SIZE_G);
60 
61  type StateType is (
62  IDLE_S,
63  DHCP_HDR_S,
64  HDR_S,
65  DHCP_BUFFER_S,
66  BUFFER_S,
67  LAST_S);
68 
69  type RegType is record
70  tKeep : slv(15 downto 0);
71  tData : slv(127 downto 0);
72  tLast : sl;
73  eofe : sl;
74  chPntr : natural range 0 to SIZE_G-1;
75  index : natural range 0 to SIZE_G-1;
77  ibSlaves : AxiStreamSlaveArray(SIZE_G-1 downto 0);
78  txMaster : AxiStreamMasterType;
79  state : StateType;
80  end record RegType;
81  constant REG_INIT_C : RegType := (
82  tKeep => (others => '0'),
83  tData => (others => '0'),
84  tLast => '0',
85  eofe => '0',
86  chPntr => 0,
87  index => 0,
89  ibSlaves => (others => AXI_STREAM_SLAVE_INIT_C),
90  txMaster => AXI_STREAM_MASTER_INIT_C,
91  state => IDLE_S);
92 
93  signal r : RegType := REG_INIT_C;
94  signal rin : RegType;
95 
96  signal txMaster : AxiStreamMasterType;
97  signal txSlave : AxiStreamSlaveType;
98 
99  -- attribute dont_touch : string;
100  -- attribute dont_touch of r : signal is "TRUE";
101 
102 begin
103 
104  comb : process (ibMasters, localIp, obDhcpMaster, r, remoteIp, remoteMac, remotePort, rst,
105  txSlave) is
106  variable v : RegType;
107  variable i : natural;
108  begin
109  -- Latch the current value
110  v := r;
111 
112  -- Reset the flags
114  v.ibSlaves := (others => AXI_STREAM_SLAVE_INIT_C);
115  if (txSlave.tReady = '1') then
116  v.txMaster.tValid := '0';
117  v.txMaster.tLast := '0';
118  v.txMaster.tUser := (others => '0');
119  v.txMaster.tKeep := (others => '1');
120  end if;
121 
122  -- State Machine
123  case r.state is
124  ----------------------------------------------------------------------
125  when IDLE_S =>
126  -- Check for roll over
127  if (r.index = (SIZE_G-1)) then
128  -- Reset the counter
129  v.index := 0;
130  else
131  -- Increment the counter
132  v.index := r.index + 1;
133  end if;
134  -- Check for DHCP data and remote MAC is non-zero
135  if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then
136  -- Check for SOF
137  if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, obDhcpMaster) = '1') then
138  -- Write the first header
139  v.txMaster.tValid := '1';
140  v.txMaster.tData(47 downto 0) := (others => '1'); -- Destination MAC address
141  v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s
142  v.txMaster.tData(95 downto 64) := (others => '0'); -- Source IP address
143  v.txMaster.tData(127 downto 96) := (others => '1'); -- Destination IP address
144  ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1');
145  -- Next state
146  v.state := DHCP_HDR_S;
147  else
148  -- Blow off the data
149  v.obDhcpSlave.tReady := '1';
150  end if;
151  -- Check for data and remote MAC is non-zero
152  elsif (ibMasters(r.index).tValid = '1') and (v.txMaster.tValid = '0')and (remoteMac(r.index) /= 0) then
153  -- Check for SOF
154  if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.index)) = '1') then
155  -- Latch the index
156  v.chPntr := r.index;
157  -- Write the first header
158  v.txMaster.tValid := '1';
159  v.txMaster.tData(47 downto 0) := remoteMac(r.index); -- Destination MAC address
160  v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s
161  v.txMaster.tData(95 downto 64) := localIp; -- Source IP address
162  v.txMaster.tData(127 downto 96) := remoteIp(r.index); -- Destination IP address
163  ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1');
164  -- Next state
165  v.state := HDR_S;
166  else
167  -- Blow off the data
168  v.ibSlaves(r.index).tReady := '1';
169  end if;
170  end if;
171  ------------------------------------------------
172  -- Notes: Non-Standard IPv4 Pseudo Header Format
173  ------------------------------------------------
174  -- tData[0][47:0] = DST MAC Address
175  -- tData[0][63:48] = zeros
176  -- tData[0][95:64] = SRC IP Address
177  -- tData[0][127:96] = DST IP address
178  -- tData[1][7:0] = zeros
179  -- tData[1][15:8] = Protocol Type = UDP
180  -- tData[1][31:16] = IPv4 Pseudo header length
181  -- tData[1][47:32] = SRC Port
182  -- tData[1][63:48] = DST Port
183  -- tData[1][79:64] = UDP Length
184  -- tData[1][95:80] = UDP Checksum
185  -- tData[1][127:96] = UDP Datagram
186  ------------------------------------------------
187  ----------------------------------------------------------------------
188  when DHCP_HDR_S =>
189  -- Check if ready to move data
190  if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then
191  -- Accept the data
192  v.obDhcpSlave.tReady := '1';
193  -- Write the Second header
194  v.txMaster.tValid := '1';
195  v.txMaster.tData(7 downto 0) := x"00"; -- All 0s
196  v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP
197  v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core
198  v.txMaster.tData(47 downto 32) := DHCP_CPORT; -- Source port
199  v.txMaster.tData(63 downto 48) := DHCP_SPORT; -- Destination port
200  v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core
201  v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core
202  v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); -- UDP Datagram
203  v.txMaster.tKeep(11 downto 0) := x"FFF";
204  v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); -- UDP Datagram
205  -- Track the leftovers
206  v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32);
207  v.tData(127 downto 96) := (others => '0');
208  v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4);
209  v.tKeep(15 downto 12) := (others => '0');
210  v.tLast := obDhcpMaster.tLast;
211  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster);
212  -- Check for tLast
213  if (v.tLast = '1') then
214  -- Check the leftover tKeep is not empty
215  if (v.tKeep /= 0) then
216  -- Next state
217  v.state := LAST_S;
218  else
219  -- Set EOF and EOFE
220  v.txMaster.tLast := '1';
221  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
222  -- Next state
223  v.state := IDLE_S;
224  end if;
225  else
226  -- Next state
227  v.state := DHCP_BUFFER_S;
228  end if;
229  end if;
230  ----------------------------------------------------------------------
231  when HDR_S =>
232  -- Check if ready to move data
233  if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then
234  -- Accept the data
235  v.ibSlaves(r.chPntr).tReady := '1';
236  -- Write the Second header
237  v.txMaster.tValid := '1';
238  v.txMaster.tData(7 downto 0) := x"00"; -- All 0s
239  v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP
240  v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core
241  v.txMaster.tData(47 downto 32) := PORT_C(r.chPntr); -- Source port
242  v.txMaster.tData(63 downto 48) := remotePort(r.chPntr); -- Destination port
243  v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core
244  v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core
245  v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); -- UDP Datagram
246  v.txMaster.tKeep(11 downto 0) := x"FFF";
247  v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); -- UDP Datagram
248  -- Track the leftovers
249  v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32);
250  v.tData(127 downto 96) := (others => '0');
251  v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4);
252  v.tKeep(15 downto 12) := (others => '0');
253  v.tLast := ibMasters(r.chPntr).tLast;
254  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr));
255  -- Check for tLast
256  if (v.tLast = '1') then
257  -- Check the leftover tKeep is not empty
258  if (v.tKeep /= 0) then
259  -- Next state
260  v.state := LAST_S;
261  else
262  -- Set EOF and EOFE
263  v.txMaster.tLast := '1';
264  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
265  -- Next state
266  v.state := IDLE_S;
267  end if;
268  else
269  -- Next state
270  v.state := BUFFER_S;
271  end if;
272  end if;
273  ----------------------------------------------------------------------
274  when DHCP_BUFFER_S =>
275  -- Check if ready to move data
276  if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then
277  -- Accept the data
278  v.obDhcpSlave.tReady := '1';
279  -- Write the Second header
280  v.txMaster.tValid := '1';
281  -- Move the data
282  v.txMaster.tData(95 downto 0) := r.tData(95 downto 0);
283  v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0);
284  v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0);
285  v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0);
286  -- Track the leftovers
287  v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32);
288  v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4);
289  v.tLast := obDhcpMaster.tLast;
290  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster);
291  -- Check for tLast
292  if (v.tLast = '1') then
293  -- Check the leftover tKeep is not empty
294  if (v.tKeep /= 0) then
295  -- Next state
296  v.state := LAST_S;
297  else
298  -- Set EOF and EOFE
299  v.txMaster.tLast := '1';
300  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
301  -- Next state
302  v.state := IDLE_S;
303  end if;
304  end if;
305  end if;
306  ----------------------------------------------------------------------
307  when BUFFER_S =>
308  -- Check if ready to move data
309  if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then
310  -- Accept the data
311  v.ibSlaves(r.chPntr).tReady := '1';
312  -- Write the Second header
313  v.txMaster.tValid := '1';
314  -- Move the data
315  v.txMaster.tData(95 downto 0) := r.tData(95 downto 0);
316  v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0);
317  v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0);
318  v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0);
319  -- Track the leftovers
320  v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32);
321  v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4);
322  v.tLast := ibMasters(r.chPntr).tLast;
323  v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr));
324  -- Check for tLast
325  if (v.tLast = '1') then
326  -- Check the leftover tKeep is not empty
327  if (v.tKeep /= 0) then
328  -- Next state
329  v.state := LAST_S;
330  else
331  -- Set EOF and EOFE
332  v.txMaster.tLast := '1';
333  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe);
334  -- Next state
335  v.state := IDLE_S;
336  end if;
337  end if;
338  end if;
339  ----------------------------------------------------------------------
340  when LAST_S =>
341  -- Check if ready to move data
342  if (v.txMaster.tValid = '0') then
343  -- Move the data
344  v.txMaster.tValid := '1';
345  v.txMaster.tData := r.tData;
346  v.txMaster.tKeep := r.tKeep;
347  v.txMaster.tLast := '1';
348  ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, r.eofe);
349  -- Next state
350  v.state := IDLE_S;
351  end if;
352  ----------------------------------------------------------------------
353  end case;
354 
355  -- Reset
356  if (rst = '1') then
357  v := REG_INIT_C;
358  end if;
359 
360  -- Register the variable for next clock cycle
361  rin <= v;
362 
363  -- Outputs
364  ibSlaves <= v.ibSlaves;
365  txMaster <= r.txMaster;
367 
368  end process comb;
369 
370  seq : process (clk) is
371  begin
372  if rising_edge(clk) then
373  r <= rin after TPD_G;
374  end if;
375  end process seq;
376 
377  U_TxPipeline : entity work.AxiStreamPipeline
378  generic map (
379  TPD_G => TPD_G,
380  PIPE_STAGES_G => 1)
381  port map (
382  axisClk => clk,
383  axisRst => rst,
384  sAxisMaster => txMaster,
385  sAxisSlave => txSlave,
387  mAxisSlave => obUdpSlave);
388 
389 end rtl;
PIPE_STAGES_Gnatural range 0 to 16:= 0
array(natural range <> ) of AxiStreamSlaveType AxiStreamSlaveArray
array(natural range <> ) of slv( 31 downto 0) Slv32Array
Definition: StdRtlPkg.vhd:379
slv( 15 downto 0) := x"4300" DHCP_SPORT
Definition: EthMacPkg.vhd:45
in localIpslv( 31 downto 0)
Definition: UdpEngineTx.vhd:43
std_logic sl
Definition: StdRtlPkg.vhd:28
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
array(natural range <> ) of slv( 47 downto 0) Slv48Array
Definition: StdRtlPkg.vhd:363
in remoteIpSlv32Array( SIZE_G- 1 downto 0)
Definition: UdpEngineTx.vhd:45
out obDhcpSlaveAxiStreamSlaveType
Definition: UdpEngineTx.vhd:51
sl eofe
Definition: SsiPkg.vhd:74
out sAxisSlaveAxiStreamSlaveType
PORT_GPositiveArray :=( 0=> 8192)
Definition: UdpEngineTx.vhd:37
slv( 15 downto 0) tKeep
out ibSlavesAxiStreamSlaveArray( SIZE_G- 1 downto 0)
Definition: UdpEngineTx.vhd:48
in mAxisSlaveAxiStreamSlaveType
slv( 15 downto 0) := x"4400" DHCP_CPORT
Definition: EthMacPkg.vhd:44
_library_ ieeeieee
Definition: UdpEngineRx.vhd:19
slv( 127 downto 0) tData
in ibMastersAxiStreamMasterArray( SIZE_G- 1 downto 0)
Definition: UdpEngineTx.vhd:47
array(natural range <> ) of positive PositiveArray
Definition: StdRtlPkg.vhd:35
in sAxisMasterAxiStreamMasterType
AxiStreamSlaveType :=(tReady => '0') AXI_STREAM_SLAVE_INIT_C
slv( 127 downto 0) tUser
in remoteMacSlv48Array( SIZE_G- 1 downto 0)
Definition: UdpEngineTx.vhd:46
in remotePortSlv16Array( SIZE_G- 1 downto 0)
Definition: UdpEngineTx.vhd:44
array(natural range <> ) of AxiStreamMasterType AxiStreamMasterArray
out mAxisMasterAxiStreamMasterType
array(natural range <> ) of slv( 15 downto 0) Slv16Array
Definition: StdRtlPkg.vhd:395
in obDhcpMasterAxiStreamMasterType := AXI_STREAM_MASTER_INIT_C
Definition: UdpEngineTx.vhd:50
TPD_Gtime := 1 ns
Definition: UdpEngineTx.vhd:34
SIZE_Gpositive := 1
Definition: UdpEngineTx.vhd:36
slv( 7 downto 0) := x"11" UDP_C
Definition: EthMacPkg.vhd:39
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
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
in obUdpSlaveAxiStreamSlaveType
Definition: UdpEngineTx.vhd:41
out obUdpMasterAxiStreamMasterType
Definition: UdpEngineTx.vhd:40