SURF  1.0
ArpEngine.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : ArpEngine.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2015-08-12
5 -- Last update: 2016-09-16
6 -------------------------------------------------------------------------------
7 -- Description: ARP Engine
8 -------------------------------------------------------------------------------
9 -- This file is part of 'SLAC Firmware Standard Library'.
10 -- It is subject to the license terms in the LICENSE.txt file found in the
11 -- top-level directory of this distribution and at:
12 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
13 -- No part of 'SLAC Firmware Standard Library', including this file,
14 -- may be copied, modified, propagated, or distributed except according to
15 -- the terms contained in the LICENSE.txt file.
16 -------------------------------------------------------------------------------
17 
18 library ieee;
19 use ieee.std_logic_1164.all;
20 use ieee.std_logic_unsigned.all;
21 use ieee.std_logic_arith.all;
22 
23 use work.StdRtlPkg.all;
24 use work.AxiStreamPkg.all;
25 use work.SsiPkg.all;
26 use work.EthMacPkg.all;
27 
28 --! @see entity
29  --! @ingroup ethernet_IpV4Engine
30 entity ArpEngine is
31  generic (
32  TPD_G : time := 1 ns;
33  CLIENT_SIZE_G : positive := 1;
34  CLK_FREQ_G : real := 156.25E+06; -- In units of Hz
35  VLAN_G : boolean := false);
36  port (
37  -- Local Configuration
38  localMac : in slv(47 downto 0);
39  localIp : in slv(31 downto 0);
40  -- Interface to Client Engine(s)
41  arpReqMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address
43  arpAckMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address
45  -- Interface to Ethernet Frame MUX/DEMUX
50  -- Clock and Reset
51  clk : in sl;
52  rst : in sl);
53 end ArpEngine;
54 
55 architecture rtl of ArpEngine is
56 
57  -- ARP Constants
58  constant BROADCAST_MAC_C : slv(47 downto 0) := (others => '1');
59  constant HARDWWARE_TYPE_C : slv(15 downto 0) := x"0100"; -- HardwareType = ETH = 0x0001
60  constant PROTOCOL_TYPE_C : slv(15 downto 0) := x"0008"; -- ProtocolType = IP = 0x0800
61  constant HARDWWARE_LEN_C : slv(7 downto 0) := x"06"; -- HardwareLength = 6 (6 Bytes/MAC)
62  constant PROTOCOL_LEN_C : slv(7 downto 0) := x"04"; -- ProtocolLength = 4 (6 Bytes/IP)
63  constant ARP_REQ_C : slv(15 downto 0) := x"0100"; -- OpCode = ARP Request = 0x0001
64  constant ARP_REPLY_C : slv(15 downto 0) := x"0200"; -- OpCode = ARP Reply = 0x0002
65  constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0);
66 
67  type StateType is (
68  IDLE_S,
69  RX_S,
70  CHECK_S,
71  SCAN_S,
72  TX_S);
73 
74  type RegType is record
75  cnt : natural range 0 to 3;
76  tData : Slv128Array(2 downto 0);
78  txArpMaster : AxiStreamMasterType;
81  arpTimers : NaturalArray(CLIENT_SIZE_G-1 downto 0);
82  reqCnt : natural range 0 to CLIENT_SIZE_G-1;
83  ackCnt : natural range 0 to CLIENT_SIZE_G-1;
84  state : StateType;
85  end record RegType;
86  constant REG_INIT_C : RegType := (
87  cnt => 0,
88  tData => (others => (others => '0')),
90  txArpMaster => AXI_STREAM_MASTER_INIT_C,
93  arpTimers => (others => 0),
94  reqCnt => 0,
95  ackCnt => 0,
96  state => IDLE_S);
97 
98  signal r : RegType := REG_INIT_C;
99  signal rin : RegType;
100 
101  -- attribute dont_touch : string;
102  -- attribute dont_touch of r : signal is "TRUE";
103 
104 begin
105 
107  variable v : RegType;
108  variable i : natural;
109  begin
110  -- Latch the current value
111  v := r;
112 
113  -- Reset the flags
115  if obArpSlave.tReady = '1' then
116  v.txArpMaster := AXI_STREAM_MASTER_INIT_C;
117  end if;
118  for i in CLIENT_SIZE_G-1 downto 0 loop
120  if arpAckSlaves(i).tReady = '1' then
122  end if;
123  end loop;
124 
125  -- Update the timers
126  for i in CLIENT_SIZE_G-1 downto 0 loop
127  if r.arpTimers(i) /= 0 then
128  -- Decrement the timers
129  v.arpTimers(i) := r.arpTimers(i) - 1;
130  end if;
131  end loop;
132 
133  -- State Machine
134  case r.state is
135  ----------------------------------------------------------------------
136  when IDLE_S =>
137  -- Reset the counter
138  v.cnt := 0;
139  -- Check for inbound data
140  if (ibArpMaster.tValid = '1') then
141  -- Next state
142  v.state := RX_S;
143  else
144  -- Increment the counter
145  if r.reqCnt = (CLIENT_SIZE_G-1) then
146  v.reqCnt := 0;
147  else
148  v.reqCnt := r.reqCnt + 1;
149  end if;
150  -- Check the tValid and timer
151  if (arpReqMasters(r.reqCnt).tValid = '1') and (r.arpTimers(r.reqCnt) = 0) then
152  -- Set the timer
153  v.arpTimers(r.reqCnt) := TIMER_1_SEC_C;
154  -- Check if localhost
155  if localIp = arpReqMasters(r.reqCnt).tData(31 downto 0) then
156  -- ACK the request
157  v.arpReqSlaves(r.ackCnt).tReady := '1';
158  v.arpAckMasters(r.ackCnt).tValid := '1';
159  v.arpAckMasters(r.ackCnt).tData(47 downto 0) := localMac;
160  else
161  ------------------------
162  -- Checking for non-VLAN
163  ------------------------
164  if (VLAN_G = false) then
165  v.tData(0)(47 downto 0) := BROADCAST_MAC_C;
166  v.tData(0)(95 downto 48) := localMac;
167  v.tData(0)(111 downto 96) := ARP_TYPE_C;
168  v.tData(0)(127 downto 112) := HARDWWARE_TYPE_C;
169  v.tData(1)(15 downto 0) := PROTOCOL_TYPE_C;
170  v.tData(1)(23 downto 16) := HARDWWARE_LEN_C;
171  v.tData(1)(31 downto 24) := PROTOCOL_LEN_C;
172  v.tData(1)(47 downto 32) := ARP_REQ_C;
173  v.tData(1)(95 downto 48) := localMac;
174  v.tData(1)(127 downto 96) := localIp;
175  v.tData(2)(47 downto 0) := BROADCAST_MAC_C;
176  v.tData(2)(79 downto 48) := arpReqMasters(r.reqCnt).tData(31 downto 0); -- Known IP address
177  v.tData(2)(127 downto 80) := (others => '0');
178  --------------------
179  -- Checking for VLAN
180  --------------------
181  else
182  v.tData(0)(47 downto 0) := BROADCAST_MAC_C;
183  v.tData(0)(95 downto 48) := localMac;
184  v.tData(0)(111 downto 96) := VLAN_TYPE_C;
185  v.tData(0)(127 downto 122) := (others => '0');
186  v.tData(1)(15 downto 0) := ARP_TYPE_C;
187  v.tData(1)(31 downto 16) := HARDWWARE_TYPE_C;
188  v.tData(1)(47 downto 32) := PROTOCOL_TYPE_C;
189  v.tData(1)(55 downto 48) := HARDWWARE_LEN_C;
190  v.tData(1)(63 downto 56) := PROTOCOL_LEN_C;
191  v.tData(1)(79 downto 64) := ARP_REQ_C;
192  v.tData(1)(127 downto 80) := localMac;
193  v.tData(2)(31 downto 0) := localIp;
194  v.tData(2)(79 downto 32) := BROADCAST_MAC_C;
195  v.tData(2)(111 downto 80) := arpReqMasters(r.reqCnt).tData(31 downto 0); -- Known IP address
196  v.tData(2)(127 downto 112) := (others => '0');
197  end if;
198  -- Next state
199  v.state := TX_S;
200  end if;
201  end if;
202  end if;
203  ----------------------------------------------------------------------
204  when RX_S =>
205  -- Check for data
206  if (ibArpMaster.tValid = '1') then
207  -- Accept for data
208  v.ibArpSlave.tReady := '1';
209  -- Word[0]
210  if r.cnt = 0 then
211  v.tData(0) := ibArpMaster.tData;
212  if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibArpMaster) = '1') then
213  -- Increment the counter
214  v.cnt := r.cnt + 1;
215  else
216  -- Next state
217  v.state := IDLE_S;
218  end if;
219  -- Word[1]
220  elsif r.cnt = 1 then
221  v.tData(1) := ibArpMaster.tData;
222  if (ibArpMaster.tLast = '0') then
223  -- Increment the counter
224  v.cnt := r.cnt + 1;
225  else
226  -- Next state
227  v.state := IDLE_S;
228  end if;
229  -- Word[2]
230  elsif r.cnt = 2 then
231  v.tData(2) := ibArpMaster.tData;
232  if (ibArpMaster.tLast = '0') then
233  -- Increment the counter
234  v.cnt := r.cnt + 1;
235  else
236  -- Check for EOFE error
237  if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibArpMaster) = '1') then
238  -- Next state
239  v.state := IDLE_S;
240  else
241  -- Next state
242  v.state := CHECK_S;
243  end if;
244  end if;
245  -- Word[3] (or more)
246  else
247  if ibArpMaster.tLast = '1' then
248  -- Check for EOFE error
249  if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibArpMaster) = '1') then
250  -- Next state
251  v.state := IDLE_S;
252  else
253  -- Next state
254  v.state := CHECK_S;
255  end if;
256  end if;
257  end if;
258  end if;
259  ----------------------------------------------------------------------
260  when CHECK_S =>
261  -- Default next state
262  v.state := IDLE_S;
263  -- Reset the counter
264  v.cnt := 0;
265  ------------------------
266  -- Checking for non-VLAN
267  ------------------------
268  if (VLAN_G = false) then
269  if (r.tData(0)(127 downto 112) = HARDWWARE_TYPE_C) -- Check for valid Hardware type
270  and (r.tData(1)(15 downto 0) = PROTOCOL_TYPE_C) -- Check for valid Protocol type
271  and (r.tData(1)(23 downto 16) = HARDWWARE_LEN_C) -- Check for valid Hardware Length
272  and (r.tData(1)(31 downto 24) = PROTOCOL_LEN_C) then -- Check for valid Protocol Length
273  -- Check OP-CODE = ARP Request
274  if (r.tData(1)(47 downto 32) = ARP_REQ_C) then
275  -- Check if the target IP address matches local address
276  if r.tData(2)(79 downto 48) = localIp then
277  -- Modified the local buffer to become a reply packet
278  v.tData(0)(47 downto 0) := r.tData(0)(95 downto 48);
279  v.tData(0)(95 downto 48) := localMac;
280  v.tData(1)(47 downto 32) := ARP_REPLY_C;
281  v.tData(1)(95 downto 48) := localMac;
282  v.tData(1)(127 downto 96) := localIp;
283  v.tData(2)(47 downto 0) := r.tData(1)(95 downto 48);
284  v.tData(2)(79 downto 48) := r.tData(1)(127 downto 96);
285  v.tData(2)(127 downto 80) := (others => '0');
286  -- Next state
287  v.state := TX_S;
288  end if;
289  -- Check OP-CODE = ARP Reply
290  elsif (r.tData(1)(47 downto 32) = ARP_REPLY_C) then
291  -- Check if the target IP + MAC address matches local address
292  if (r.tData(2)(47 downto 0) = localMac) and (r.tData(2)(79 downto 48) = localIp) then
293  -- Next state
294  v.state := SCAN_S;
295  end if;
296  end if;
297  end if;
298  --------------------
299  -- Checking for VLAN
300  --------------------
301  else
302  if (r.tData(1)(31 downto 16) = HARDWWARE_TYPE_C) -- Check for valid Hardware type
303  and (r.tData(1)(47 downto 32) = PROTOCOL_TYPE_C) -- Check for valid Protocol type
304  and (r.tData(1)(55 downto 48) = HARDWWARE_LEN_C) -- Check for valid Hardware Length
305  and (r.tData(1)(63 downto 56) = PROTOCOL_LEN_C) then -- Check for valid Protocol Length
306  -- Check OP-CODE = ARP Request
307  if (r.tData(1)(79 downto 64) = ARP_REQ_C) then
308  -- Check if the target IP address matches local address
309  if r.tData(2)(111 downto 80) = localIp then
310  -- Modified the local buffer to become a reply packet
311  v.tData(0)(47 downto 0) := r.tData(0)(95 downto 48);
312  v.tData(0)(95 downto 48) := localMac;
313  v.tData(1)(79 downto 64) := ARP_REPLY_C;
314  v.tData(1)(127 downto 80) := localMac;
315  v.tData(2)(31 downto 0) := localIp;
316  v.tData(2)(79 downto 32) := r.tData(1)(127 downto 80);
317  v.tData(2)(111 downto 80) := r.tData(2)(31 downto 0);
318  v.tData(2)(127 downto 112) := (others => '0');
319  -- Next state
320  v.state := TX_S;
321  end if;
322  -- Check OP-CODE = ARP Reply
323  elsif (r.tData(1)(79 downto 64) = ARP_REPLY_C) then
324  -- Check if the target IP + MAC address matches local address
325  if (r.tData(2)(79 downto 32) = localMac) and (r.tData(2)(111 downto 80) = localIp) then
326  -- Next state
327  v.state := SCAN_S;
328  end if;
329  end if;
330  end if;
331  end if;
332  ----------------------------------------------------------------------
333  when SCAN_S =>
334  -- Check the tValid
335  if (arpReqMasters(r.ackCnt).tValid = '1') and (v.arpAckMasters(r.ackCnt).tValid = '0') then
336  ------------------------
337  -- Checking for non-VLAN
338  ------------------------
339  if (VLAN_G = false) then
340  -- Check if Source's IP address match request IP address
341  if arpReqMasters(r.ackCnt).tData(31 downto 0) = r.tData(1)(127 downto 96) then
342  -- ACK the request
343  v.arpReqSlaves(r.ackCnt).tReady := '1';
344  v.arpAckMasters(r.ackCnt).tValid := '1';
345  v.arpAckMasters(r.ackCnt).tData(47 downto 0) := r.tData(1)(95 downto 48); -- Source's MAC address
346  -- Reset the timer
347  v.arpTimers(r.ackCnt) := 0;
348  end if;
349  else
350  -- Check if Source's IP address match request IP address
351  if arpReqMasters(r.ackCnt).tData(31 downto 0) = r.tData(2)(31 downto 0) then
352  -- ACK the request
353  v.arpReqSlaves(r.ackCnt).tReady := '1';
354  v.arpAckMasters(r.ackCnt).tValid := '1';
355  v.arpAckMasters(r.ackCnt).tData(47 downto 0) := r.tData(1)(127 downto 80); -- Source's MAC address
356  -- Reset the timer
357  v.arpTimers(r.ackCnt) := 0;
358  end if;
359  end if;
360  end if;
361  -- Check the counter
362  if r.ackCnt = (CLIENT_SIZE_G-1) then
363  -- Reset the counter
364  v.ackCnt := 0;
365  -- Next state
366  v.state := IDLE_S;
367  else
368  v.ackCnt := r.ackCnt + 1;
369  end if;
370  ----------------------------------------------------------------------
371  when TX_S =>
372  -- Check if ready to move data
373  if v.txArpMaster.tValid = '0' then
374  -- Move data
375  v.txArpMaster.tValid := '1';
376  v.txArpMaster.tData := r.tData(r.cnt);
377  -- Increment the counter
378  v.cnt := r.cnt + 1;
379  if r.cnt = 0 then
380  ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txArpMaster, '1');
381  elsif r.cnt = 2 then
382  -- Set the EOF flag
383  v.txArpMaster.tLast := '1';
384  -- Set the tKeep
385  if (VLAN_G = false) then
386  v.txArpMaster.tKeep := x"03FF";
387  else
388  v.txArpMaster.tKeep := x"3FFF";
389  end if;
390  -- Next state
391  v.state := IDLE_S;
392  end if;
393  end if;
394  ----------------------------------------------------------------------
395  end case;
396 
397  -- Reset
398  if (rst = '1') then
399  v := REG_INIT_C;
400  end if;
401 
402  -- Register the variable for next clock cycle
403  rin <= v;
404 
405  -- Outputs
408  ibArpSlave <= v.ibArpSlave;
409  obArpMaster <= r.txArpMaster;
410 
411  end process comb;
412 
413  seq : process (clk) is
414  begin
415  if rising_edge(clk) then
416  r <= rin after TPD_G;
417  end if;
418  end process seq;
419 
420 end rtl;
array(natural range <> ) of AxiStreamSlaveType AxiStreamSlaveArray
in localIpslv( 31 downto 0)
Definition: ArpEngine.vhd:39
std_logic sl
Definition: StdRtlPkg.vhd:28
CLIENT_SIZE_Gpositive := 1
Definition: ArpEngine.vhd:33
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
in localMacslv( 47 downto 0)
Definition: ArpEngine.vhd:38
slv( 15 downto 0) tKeep
CLK_FREQ_Greal := 156.25E+06
Definition: ArpEngine.vhd:34
out ibArpSlaveAxiStreamSlaveType
Definition: ArpEngine.vhd:47
slv( 15 downto 0) := x"0608" ARP_TYPE_C
Definition: EthMacPkg.vhd:34
slv( 127 downto 0) tData
in clksl
Definition: ArpEngine.vhd:51
array(natural range <> ) of natural NaturalArray
Definition: StdRtlPkg.vhd:34
AxiStreamSlaveType :=(tReady => '0') AXI_STREAM_SLAVE_INIT_C
out obArpMasterAxiStreamMasterType
Definition: ArpEngine.vhd:48
in ibArpMasterAxiStreamMasterType
Definition: ArpEngine.vhd:46
array(natural range <> ) of slv( 127 downto 0) Slv128Array
Definition: StdRtlPkg.vhd:283
out arpAckMastersAxiStreamMasterArray( CLIENT_SIZE_G- 1 downto 0)
Definition: ArpEngine.vhd:43
array(natural range <> ) of AxiStreamMasterType AxiStreamMasterArray
out arpReqSlavesAxiStreamSlaveArray( CLIENT_SIZE_G- 1 downto 0)
Definition: ArpEngine.vhd:42
VLAN_Gboolean := false
Definition: ArpEngine.vhd:35
TPD_Gtime := 1 ns
Definition: ArpEngine.vhd:32
slv( 15 downto 0) := x"0081" VLAN_TYPE_C
Definition: EthMacPkg.vhd:36
in arpReqMastersAxiStreamMasterArray( CLIENT_SIZE_G- 1 downto 0)
Definition: ArpEngine.vhd:41
in obArpSlaveAxiStreamSlaveType
Definition: ArpEngine.vhd:49
in rstsl
Definition: ArpEngine.vhd:52
in arpAckSlavesAxiStreamSlaveArray( CLIENT_SIZE_G- 1 downto 0)
Definition: ArpEngine.vhd:44
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