From 948842f8117a0d95f4af8de2149d65f706bfb5f8 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Fri, 13 Sep 2024 14:02:52 +0200 Subject: [PATCH 01/15] first version of multi-arp --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 127 +++++++++++ ethernet/UdpEngine/rtl/UdpEngine.vhd | 2 +- ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd | 261 ++++++++++++++++++++++ ethernet/UdpEngine/tb/UdpEngineTb.vhd | 24 +- 4 files changed, 408 insertions(+), 6 deletions(-) create mode 100644 ethernet/UdpEngine/rtl/ArpIpTable.vhd create mode 100644 ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd new file mode 100644 index 0000000000..6de587ef2c --- /dev/null +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -0,0 +1,127 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + + +library surf; +use surf.StdRtlPkg.all; + +entity ArpIpTable is + + generic ( + TPD_G : time := 1 ns; + ENTRIES_G : positive := 4); + port ( + -- Clock and Reset + clk : in sl; + rst : in sl; + -- Read LUT + ipAddr : in slv(31 downto 0); + pos : out slv(31 downto 0); + found : out sl; + macAddr : out slv(47 downto 0); + -- Write LUT + ipWrEn : in sl; + IpWrAddr : in slv(31 downto 0); + macWrEn : in sl; + macWrAddr : in slv(47 downto 0)); +end entity ArpIpTable; + +architecture rtl of ArpIpTable is + + type wRegType is record + ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); + macLutTable : Slv48Array(ENTRIES_G-1 downto 0); + entryCount : slv(15 downto 0); + end record wRegType; + + constant W_REG_INIT_C : wRegType := ( + ipLutTable => (others => (others => '0')), + -- ipLutTable => (0 => x"0B02A8C0", 1 => (others => '1')), + macLutTable => (others => (others => '0')), + -- macLutTable => (0 => x"020300564400", 1 => (others => '1')), + entryCount => (others => '0') + ); + + signal wR : wRegType := W_REG_INIT_C; + signal wRin : wRegType; + + signal matchArray : slv(ENTRIES_G-1 downto 0); + +begin -- architecture rtl + + -- Write process comb + wrComb : process (ipWrAddr, ipWrEn, macWrAddr, macWrEn, rst, wR) is + variable v : wRegType; + variable wrAddInt : integer; + begin + -- Latch the current value + v := wR; + + -- Write IP to LUT + if ipWrEn = '1' then + wrAddInt := conv_integer(wR.entryCount); + if wrAddInt < ENTRIES_G then + v.ipLutTable(wrAddInt) := ipWrAddr; + end if; + + -- Update write LUT pointer + if wr.entryCount < ENTRIES_G - 1 then + v.entryCount := wr.entryCount + 1; + else + v.entryCount := (others => '0'); + end if; + end if; + + -- Write MAC to LUT + if macWrEn = '1' then + wrAddInt := conv_integer(wR.entryCount); + if wrAddInt < ENTRIES_G then + v.macLutTable(wrAddInt) := macWrAddr; + end if; + end if; + + -- Reset + if (rst = '1') then + v := W_REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + wRin <= v; + + end process wrComb; + + wrSeq : process (clk) is + begin + if rising_edge(clk) then + wR <= wRin after TPD_G; + end if; + end process wrSeq; + + -- Read process + -- Check for a match + gen_compare : for i in 0 to ENTRIES_G-1 generate + matchArray(i) <= '1' when (wR.ipLutTable(i) = ipAddr) else '0'; + end generate; + + -- Encode the position based on the match_array + process(matchArray, wR.macLutTable) + variable posI : integer; + variable ipFound : sl := '0'; + begin + ipFound := '0'; + posI := 0; -- Default value if no match is found + for i in 0 to ENTRIES_G-1 loop + if matchArray(i) = '1' then + posI := i; + ipFound := '1'; + exit; -- Exit as soon as a match is found + end if; + end loop; + found <= ipFound; + pos <= conv_std_logic_vector(posI, 32); + macAddr <= wR.macLutTable(posI); + end process; + +end architecture rtl; diff --git a/ethernet/UdpEngine/rtl/UdpEngine.vhd b/ethernet/UdpEngine/rtl/UdpEngine.vhd index 7b7a26303d..b6138c8f65 100644 --- a/ethernet/UdpEngine/rtl/UdpEngine.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngine.vhd @@ -206,7 +206,7 @@ begin GEN_CLIENT : if (CLIENT_EN_G = true) generate - U_UdpEngineArp : entity surf.UdpEngineArp + U_UdpEngineArp : entity surf.UdpEngineArpV2 generic map ( TPD_G => TPD_G, CLIENT_SIZE_G => CLIENT_SIZE_G, diff --git a/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd b/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd new file mode 100644 index 0000000000..faade9fe81 --- /dev/null +++ b/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd @@ -0,0 +1,261 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: UDP Client's ARP Messaging Module +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.std_logic_arith.all; + + +library surf; +use surf.StdRtlPkg.all; +use surf.AxiStreamPkg.all; + +entity UdpEngineArpV2 is + generic ( + TPD_G : time := 1 ns; + CLIENT_SIZE_G : positive := 1; + CLK_FREQ_G : real := 156.25E+06; + COMM_TIMEOUT_G : positive := 30; + RESP_TIMEOUT_G : positive := 5); + port ( + -- Local Configurations + localIp : in slv(31 downto 0); -- big-Endian configuration + -- Interface to ARP Engine + arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address + arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address + arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + -- Interface to UDP Client engine(s) + clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); + -- Clock and Reset + clk : in sl; + rst : in sl); +end UdpEngineArpV2; + +architecture rtl of UdpEngineArpV2 is + + constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); + type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; + + type StateType is ( + CHECK_S, + IDLE_S, + WAIT_S, + COMM_MONITOR_S); + type StateArray is array (natural range <>) of StateType; + + type RegType is record + clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteMacWrEn : slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteIpWrEn : slv(CLIENT_SIZE_G-1 downto 0); + arpAckSlaves : AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpReqMasters : AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + timerEn : sl; + timer : natural range 0 to (TIMER_1_SEC_C-1); + arpTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); + respTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); + state : StateArray(CLIENT_SIZE_G-1 downto 0); + end record RegType; + constant REG_INIT_C : RegType := ( + clientRemoteMac => (others => (others => '0')), + clientRemoteMacWrEn => (others => '0'), + clientRemoteIpWrEn => (others => '0'), + arpAckSlaves => (others => AXI_STREAM_SLAVE_INIT_C), + arpReqMasters => (others => AXI_STREAM_MASTER_INIT_C), + timerEn => '0', + timer => 0, + arpTimers => (others => 0), + respTimers => (others => 0), + state => (others => IDLE_S)); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal arpIpFound : slv(CLIENT_SIZE_G-1 downto 0); + signal arpMacAddr : Slv48Array(CLIENT_SIZE_G-1 downto 0); + +begin + + ----------------------------------------------------------------------------- + -- ARP Tables + ----------------------------------------------------------------------------- + GEN_ARP_TABLES : for i in 0 to CLIENT_SIZE_G-1 generate + ArpIpTable_1 : entity surf.ArpIpTable + generic map ( + ENTRIES_G => 2) + port map ( + clk => clk, + rst => rst, + ipAddr => clientRemoteIp(i), + pos => open, + found => arpIpFound(i), + macAddr => arpMacAddr(i), + ipWrEn => r.clientRemoteIpWrEn(i), + IpWrAddr => clientRemoteIp(i), + macWrEn => r.clientRemoteMacWrEn(i), + macWrAddr => r.clientRemoteMac(i)); + end generate GEN_ARP_TABLES; + + comb : process (arpAckMasters, arpReqSlaves, arpIpFound, arpMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is + variable v : RegType; + variable i : natural; + begin + -- Latch the current value + v := r; + + -- Reset the flags + v.timerEn := '0'; + v.clientRemoteMacWrEn := (others => '0'); + v.clientRemoteIpWrEn := (others => '0'); + for i in CLIENT_SIZE_G-1 downto 0 loop + v.arpAckSlaves(i) := AXI_STREAM_SLAVE_INIT_C; + if arpReqSlaves(i).tReady = '1' then + v.arpReqMasters(i).tValid := '0'; + end if; + end loop; + + + -- Increment the timer + if r.timer = (TIMER_1_SEC_C-1) then + v.timer := 0; + v.timerEn := '1'; + else + v.timer := r.timer + 1; + end if; + + -- Loop through the clients + for i in CLIENT_SIZE_G-1 downto 0 loop + + -- Update the timers + if (r.timerEn = '1') and (r.arpTimers(i) /= 0) then + -- Decrement the timers + v.arpTimers(i) := r.arpTimers(i) - 1; + end if; + if (r.timerEn = '1') and (r.respTimers(i) /= 0) then + -- Decrement the timers + v.respTimers(i) := r.respTimers(i) - 1; + end if; + + -- Update the IP address + v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); + + -- Check for dynamic change in IP address + -- if (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) or (clientRemoteIp(i) = 0) then + if (clientRemoteIp(i) = 0) then + -- Stop any outstanding requests + v.arpReqMasters(i).tValid := '0'; + -- Reset the remote MAC address + v.clientRemoteMac(i) := (others => '0'); + -- Next state + v.state(i) := IDLE_S; + elsif (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) then + -- Stop any outstanding requests + v.arpReqMasters(i).tValid := '0'; + -- Reset the remote MAC address + v.clientRemoteMac(i) := (others => '0'); + -- Next state + v.state(i) := CHECK_S; + else + -- State Machine + case r.state(i) is + ---------------------------------------------------------------------- + when CHECK_S => + if arpIpFound(i) = '1' then + -- Set found MAC addr + v.clientRemoteMac(i) := arpMacAddr(i); + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + -- Next state + v.state(i) := COMM_MONITOR_S; + else + -- Write IP to ARP table + v.clientRemoteIpWrEn(i) := '1'; + -- Next state + v.state(i) := IDLE_S; + end if; + ---------------------------------------------------------------------- + when IDLE_S => + -- Reset the counter + v.arpTimers(i) := 0; + -- Check if we have a non-zero IP address to request + if clientRemoteIp(i) /= 0 then + -- Make an ARP request + v.arpReqMasters(i).tValid := '1'; + -- Set the response timer + v.respTimers(i) := RESP_TIMEOUT_G; + -- Next state + v.state(i) := WAIT_S; + end if; + ---------------------------------------------------------------------- + when WAIT_S => + -- Reset the remote MAC address if ARP response times out + if r.respTimers(i) = 0 then + v.clientRemoteMac(i) := (others => '0'); + end if; + -- Wait for the ARP response + if arpAckMasters(i).tValid = '1' then + -- Accept the data + v.arpAckSlaves(i).tReady := '1'; + -- Latch the MAC address value + v.clientRemoteMac(i) := arpAckMasters(i).tData(47 downto 0); + -- Write to ARP table + v.clientRemoteMacWrEn(i) := '1'; + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + -- Next state + v.state(i) := COMM_MONITOR_S; + end if; + ---------------------------------------------------------------------- + when COMM_MONITOR_S => + -- Check for inbound client communication + if clientRemoteDet(i) = '1' then + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + elsif r.arpTimers(i) = 0 then + -- Next state + v.state(i) := IDLE_S; + end if; + ---------------------------------------------------------------------- + end case; + end if; + end loop; + + -- Combinatorial outputs before the reset + arpAckSlaves <= v.arpAckSlaves; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + -- Registered Outputs + arpReqMasters <= r.arpReqMasters; + clientRemoteMac <= r.clientRemoteMac; + + end process comb; + + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; + end if; + end process seq; + +end rtl; diff --git a/ethernet/UdpEngine/tb/UdpEngineTb.vhd b/ethernet/UdpEngine/tb/UdpEngineTb.vhd index cdd6f66700..aa5278c002 100644 --- a/ethernet/UdpEngine/tb/UdpEngineTb.vhd +++ b/ethernet/UdpEngine/tb/UdpEngineTb.vhd @@ -80,6 +80,8 @@ architecture testbed of UdpEngineTb is signal rxBusy : sl; signal txBusy : sl; + signal remoteIpAddr : slv(31 downto 0); + begin ClkRst_Inst : entity surf.ClkRst @@ -114,6 +116,18 @@ begin trig => r.trig, busy => txBusy); + ---------------------------------------------------------------------------- + -- Set Remote IP addr + ---------------------------------------------------------------------------- + process is + begin -- process + remoteIpAddr <= (others => '0'); + wait for 1300 ns; + wait until rising_edge(clk); + remoteIpAddr <= IP_ADDR_C(1); + wait; + end process; + ---------------------- -- IPv4/ARP/UDP Engine ---------------------- @@ -134,7 +148,7 @@ begin localIp => IP_ADDR_C(0), -- Remote Configurations clientRemotePort(0) => x"0020", -- PORT = 8192 = 0x2000 (0x0020 in big endianness) - clientRemoteIp(0) => IP_ADDR_C(1), + clientRemoteIp(0) => remoteIpAddr, -- Interface to Ethernet Media Access Controller (MAC) obMacMaster => obMacMasters(0), obMacSlave => obMacSlaves(0), @@ -281,10 +295,10 @@ begin --------------------------------- -- Simulation Error Self-checking --------------------------------- - if r.errorDet = '1' then - assert false - report "Simulation Failed!" severity failure; - end if; + --if r.errorDet = '1' then + -- assert false + -- report "Simulation Failed!" severity failure; + --end if; -- Register the variable for next clock cycle rin <= v; From cdfb73e2a6a682beeab3f2ef26e7192c0d0c1b44 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Mon, 16 Sep 2024 18:10:12 +0200 Subject: [PATCH 02/15] to check for ip address with tDest --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 69 +- ethernet/UdpEngine/rtl/UdpEngine.vhd | 560 ++++++++-------- ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd | 35 +- ethernet/UdpEngine/rtl/UdpEngineTx.vhd | 772 ++++++++++++---------- ethernet/UdpEngine/tb/UdpEngineTb.vhd | 580 ++++++++-------- 5 files changed, 1073 insertions(+), 943 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 6de587ef2c..fa0b5b091c 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -10,17 +10,18 @@ use surf.StdRtlPkg.all; entity ArpIpTable is generic ( - TPD_G : time := 1 ns; - ENTRIES_G : positive := 4); + TPD_G : time := 1 ns; + ENTRIES_G : positive range 1 to 255 := 4); port ( -- Clock and Reset clk : in sl; rst : in sl; -- Read LUT - ipAddr : in slv(31 downto 0); - pos : out slv(31 downto 0); + ipAddrIn : in slv(31 downto 0); + pos : in slv(7 downto 0); found : out sl; macAddr : out slv(47 downto 0); + ipAddrOut : out slv(31 downto 0); -- Write LUT ipWrEn : in sl; IpWrAddr : in slv(31 downto 0); @@ -33,14 +34,12 @@ architecture rtl of ArpIpTable is type wRegType is record ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); macLutTable : Slv48Array(ENTRIES_G-1 downto 0); - entryCount : slv(15 downto 0); + entryCount : slv(7 downto 0); end record wRegType; constant W_REG_INIT_C : wRegType := ( ipLutTable => (others => (others => '0')), - -- ipLutTable => (0 => x"0B02A8C0", 1 => (others => '1')), macLutTable => (others => (others => '0')), - -- macLutTable => (0 => x"020300564400", 1 => (others => '1')), entryCount => (others => '0') ); @@ -65,13 +64,6 @@ begin -- architecture rtl if wrAddInt < ENTRIES_G then v.ipLutTable(wrAddInt) := ipWrAddr; end if; - - -- Update write LUT pointer - if wr.entryCount < ENTRIES_G - 1 then - v.entryCount := wr.entryCount + 1; - else - v.entryCount := (others => '0'); - end if; end if; -- Write MAC to LUT @@ -80,6 +72,13 @@ begin -- architecture rtl if wrAddInt < ENTRIES_G then v.macLutTable(wrAddInt) := macWrAddr; end if; + + -- Update write LUT pointer + if wr.entryCount < ENTRIES_G - 1 then + v.entryCount := wr.entryCount + 1; + else + v.entryCount := (others => '0'); + end if; end if; -- Reset @@ -102,26 +101,40 @@ begin -- architecture rtl -- Read process -- Check for a match gen_compare : for i in 0 to ENTRIES_G-1 generate - matchArray(i) <= '1' when (wR.ipLutTable(i) = ipAddr) else '0'; + matchArray(i) <= '1' when (wR.ipLutTable(i) = ipAddrIn) else '0'; end generate; -- Encode the position based on the match_array - process(matchArray, wR.macLutTable) - variable posI : integer; - variable ipFound : sl := '0'; + process(matchArray, pos, wr.macLutTable) + variable ipFound : sl := '0'; + variable posI : integer; + variable foundMacAddr : slv(47 downto 0); + variable foundIpAddr : slv(31 downto 0); begin - ipFound := '0'; - posI := 0; -- Default value if no match is found - for i in 0 to ENTRIES_G-1 loop - if matchArray(i) = '1' then - posI := i; + ipFound := '0'; + foundMacAddr := (others => '0'); + foundIpAddr := (others => '0'); + if pos > 0 then + posI := conv_integer(pos-1); + foundMacAddr := wr.macLutTable(posI); + foundIpAddr := wr.ipLutTable(posI); + if foundMacAddr = x"000000000000" or foundIpAddr = x"00000000" then + ipFound := '0'; + else ipFound := '1'; - exit; -- Exit as soon as a match is found end if; - end loop; - found <= ipFound; - pos <= conv_std_logic_vector(posI, 32); - macAddr <= wR.macLutTable(posI); + else + for i in 0 to ENTRIES_G-1 loop + if matchArray(i) = '1' then + foundMacAddr := wr.macLutTable(i); + ipFound := '1'; + exit; -- Exit as soon as a match is found + end if; + end loop; + end if; + found <= ipFound; + macAddr <= foundMacAddr; + ipAddrOut <= foundIpAddr; end process; end architecture rtl; diff --git a/ethernet/UdpEngine/rtl/UdpEngine.vhd b/ethernet/UdpEngine/rtl/UdpEngine.vhd index b6138c8f65..ecd300b832 100644 --- a/ethernet/UdpEngine/rtl/UdpEngine.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngine.vhd @@ -20,282 +20,320 @@ use surf.StdRtlPkg.all; use surf.AxiStreamPkg.all; entity UdpEngine is - generic ( - -- Simulation Generics - TPD_G : time := 1 ns; - -- UDP Server Generics - SERVER_EN_G : boolean := true; - SERVER_SIZE_G : positive := 1; - SERVER_PORTS_G : PositiveArray := (0 => 8192); - -- UDP Client Generics - CLIENT_EN_G : boolean := true; - CLIENT_SIZE_G : positive := 1; - CLIENT_PORTS_G : PositiveArray := (0 => 8193); - -- General UDP/IGMP/ARP/DHCP Generics - TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up - DHCP_G : boolean := false; - IGMP_G : boolean := false; - IGMP_GRP_SIZE : positive := 1; - CLK_FREQ_G : real := 156.25E+06; -- In units of Hz - COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request - SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs - port ( - -- Local Configurations - localMac : in slv(47 downto 0); -- big-Endian configuration - broadcastIp : in slv(31 downto 0); -- big-Endian configuration - igmpIp : in Slv32Array(IGMP_GRP_SIZE-1 downto 0); -- big-Endian configuration - localIpIn : in slv(31 downto 0); -- big-Endian configuration - dhcpIpOut : out slv(31 downto 0); -- big-Endian configuration - -- Interface to IPV4 Engine - obUdpMaster : out AxiStreamMasterType; - obUdpSlave : in AxiStreamSlaveType; - ibUdpMaster : in AxiStreamMasterType; - ibUdpSlave : out AxiStreamSlaveType; - -- Interface to ARP Engine - arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - -- Interface to UDP Server engine(s) - serverRemotePort : out Slv16Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration - serverRemoteIp : out Slv32Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration - obServerMasters : out AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration - obServerSlaves : in AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); - ibServerMasters : in AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); - ibServerSlaves : out AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration - -- Interface to UDP Client engine(s) - clientRemotePort : in Slv16Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration - clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration - obClientMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration - obClientSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - ibClientMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - ibClientSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration - -- Clock and Reset - clk : in sl; - rst : in sl); + generic ( + -- Simulation Generics + TPD_G : time := 1 ns; + -- UDP Server Generics + SERVER_EN_G : boolean := true; + SERVER_SIZE_G : positive := 1; + SERVER_PORTS_G : PositiveArray := (0 => 8192); + -- UDP Client Generics + CLIENT_EN_G : boolean := true; + CLIENT_SIZE_G : positive := 1; + CLIENT_PORTS_G : PositiveArray := (0 => 8193); + ARP_TAB_ENTRIES_G : positive range 1 to 255 := 4; + -- General UDP/IGMP/ARP/DHCP Generics + TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up + DHCP_G : boolean := false; + IGMP_G : boolean := false; + IGMP_GRP_SIZE : positive := 1; + CLK_FREQ_G : real := 156.25E+06; -- In units of Hz + COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request + SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs + port ( + -- Local Configurations + localMac : in slv(47 downto 0); -- big-Endian configuration + broadcastIp : in slv(31 downto 0); -- big-Endian configuration + igmpIp : in Slv32Array(IGMP_GRP_SIZE-1 downto 0); -- big-Endian configuration + localIpIn : in slv(31 downto 0); -- big-Endian configuration + dhcpIpOut : out slv(31 downto 0); -- big-Endian configuration + -- Interface to IPV4 Engine + obUdpMaster : out AxiStreamMasterType; + obUdpSlave : in AxiStreamSlaveType; + ibUdpMaster : in AxiStreamMasterType; + ibUdpSlave : out AxiStreamSlaveType; + -- Interface to ARP Engine + arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + -- Interface to UDP Server engine(s) + serverRemotePort : out Slv16Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration + serverRemoteIp : out Slv32Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration + obServerMasters : out AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration + obServerSlaves : in AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); + ibServerMasters : in AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); + ibServerSlaves : out AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration + -- Interface to UDP Client engine(s) + clientRemotePort : in Slv16Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration + clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration + obClientMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration + obClientSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + ibClientMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + ibClientSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration + -- Clock and Reset + clk : in sl; + rst : in sl); end UdpEngine; architecture mapping of UdpEngine is - signal clientRemoteDet : slv(CLIENT_SIZE_G-1 downto 0); - signal clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); + signal clientRemoteDet : slv(CLIENT_SIZE_G-1 downto 0); + signal clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); - signal remotePort : Slv16Array(SERVER_SIZE_G-1 downto 0); - signal remoteIp : Slv32Array(SERVER_SIZE_G-1 downto 0); - signal serverRemoteMac : Slv48Array(SERVER_SIZE_G-1 downto 0); + signal remotePort : Slv16Array(SERVER_SIZE_G-1 downto 0); + signal remoteIp : Slv32Array(SERVER_SIZE_G-1 downto 0); + signal serverRemoteMac : Slv48Array(SERVER_SIZE_G-1 downto 0); - signal obUdpMasters : AxiStreamMasterArray(1 downto 0); - signal obUdpSlaves : AxiStreamSlaveArray(1 downto 0); + signal obUdpMasters : AxiStreamMasterArray(1 downto 0); + signal obUdpSlaves : AxiStreamSlaveArray(1 downto 0); - signal ibDhcpMaster : AxiStreamMasterType; - signal ibDhcpSlave : AxiStreamSlaveType; + signal ibDhcpMaster : AxiStreamMasterType; + signal ibDhcpSlave : AxiStreamSlaveType; - signal obDhcpMaster : AxiStreamMasterType; - signal obDhcpSlave : AxiStreamSlaveType; + signal obDhcpMaster : AxiStreamMasterType; + signal obDhcpSlave : AxiStreamSlaveType; - signal localIp : slv(31 downto 0); + signal localIp : slv(31 downto 0); + + signal arpTabFound : slv(CLIENT_SIZE_G-1 downto 0); + signal arpTabMacAddr : Slv48Array(CLIENT_SIZE_G-1 downto 0); + signal arpTabIpAddr : Slv32Array(CLIENT_SIZE_G-1 downto 0); + signal arpTabIpWe : slv(CLIENT_SIZE_G-1 downto 0); + signal arpTabMacWe : slv(CLIENT_SIZE_G-1 downto 0); + signal arpTabMacAddrW : Slv48Array(CLIENT_SIZE_G-1 downto 0); + signal arpTabPos : Slv8Array(CLIENT_SIZE_G-1 downto 0); begin - assert ((SERVER_EN_G = true) or (CLIENT_EN_G = true)) report - "UdpEngine: Either SERVER_EN_G or CLIENT_EN_G must be true" severity failure; + assert ((SERVER_EN_G = true) or (CLIENT_EN_G = true)) report + "UdpEngine: Either SERVER_EN_G or CLIENT_EN_G must be true" severity failure; + + serverRemotePort <= remotePort; -- Debug Only + serverRemoteIp <= remoteIp; -- Debug Only + dhcpIpOut <= localIp; + + U_UdpEngineRx : entity surf.UdpEngineRx + generic map ( + TPD_G => TPD_G, + DHCP_G => DHCP_G, + IGMP_G => IGMP_G, + IGMP_GRP_SIZE => IGMP_GRP_SIZE, + SERVER_EN_G => SERVER_EN_G, + SERVER_SIZE_G => SERVER_SIZE_G, + SERVER_PORTS_G => SERVER_PORTS_G, + CLIENT_EN_G => CLIENT_EN_G, + CLIENT_SIZE_G => CLIENT_SIZE_G, + CLIENT_PORTS_G => CLIENT_PORTS_G) + port map ( + -- Local Configurations + localIp => localIp, + broadcastIp => broadcastIp, + igmpIp => igmpIp, + -- Interface to IPV4 Engine + ibUdpMaster => ibUdpMaster, + ibUdpSlave => ibUdpSlave, + -- Interface to UDP Server engine(s) + serverRemotePort => remotePort, + serverRemoteIp => remoteIp, + serverRemoteMac => serverRemoteMac, + obServerMasters => obServerMasters, + obServerSlaves => obServerSlaves, + -- Interface to UDP Client engine(s) + clientRemoteDet => clientRemoteDet, + obClientMasters => obClientMasters, + obClientSlaves => obClientSlaves, + -- Interface to DHCP Engine + ibDhcpMaster => ibDhcpMaster, + ibDhcpSlave => ibDhcpSlave, + -- Clock and Reset + clk => clk, + rst => rst); + + GEN_DHCP : if (DHCP_G = true) generate + + U_UdpEngineDhcp : entity surf.UdpEngineDhcp + generic map ( + -- Simulation Generics + TPD_G => TPD_G, + -- UDP ARP/DHCP Generics + CLK_FREQ_G => CLK_FREQ_G, + COMM_TIMEOUT_G => COMM_TIMEOUT_G, + SYNTH_MODE_G => SYNTH_MODE_G) + port map ( + -- Local Configurations + localMac => localMac, + localIp => localIpIn, + dhcpIp => localIp, + -- Interface to DHCP Engine + ibDhcpMaster => ibDhcpMaster, + ibDhcpSlave => ibDhcpSlave, + obDhcpMaster => obDhcpMaster, + obDhcpSlave => obDhcpSlave, + -- Clock and Reset + clk => clk, + rst => rst); + + end generate; + + BYPASS_DHCP : if (DHCP_G = false) generate - serverRemotePort <= remotePort; -- Debug Only - serverRemoteIp <= remoteIp; -- Debug Only - dhcpIpOut <= localIp; + localIp <= localIpIn; + ibDhcpSlave <= AXI_STREAM_SLAVE_FORCE_C; + obDhcpMaster <= AXI_STREAM_MASTER_INIT_C; - U_UdpEngineRx : entity surf.UdpEngineRx + end generate; + + GEN_SERVER : if (SERVER_EN_G = true) generate + + U_UdpEngineTx : entity surf.UdpEngineTx generic map ( - TPD_G => TPD_G, - DHCP_G => DHCP_G, - IGMP_G => IGMP_G, - IGMP_GRP_SIZE => IGMP_GRP_SIZE, - SERVER_EN_G => SERVER_EN_G, - SERVER_SIZE_G => SERVER_SIZE_G, - SERVER_PORTS_G => SERVER_PORTS_G, - CLIENT_EN_G => CLIENT_EN_G, - CLIENT_SIZE_G => CLIENT_SIZE_G, - CLIENT_PORTS_G => CLIENT_PORTS_G) + TPD_G => TPD_G, + SIZE_G => SERVER_SIZE_G, + TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, + PORT_G => SERVER_PORTS_G) port map ( - -- Local Configurations - localIp => localIp, - broadcastIp => broadcastIp, - igmpIp => igmpIp, - -- Interface to IPV4 Engine - ibUdpMaster => ibUdpMaster, - ibUdpSlave => ibUdpSlave, - -- Interface to UDP Server engine(s) - serverRemotePort => remotePort, - serverRemoteIp => remoteIp, - serverRemoteMac => serverRemoteMac, - obServerMasters => obServerMasters, - obServerSlaves => obServerSlaves, - -- Interface to UDP Client engine(s) - clientRemoteDet => clientRemoteDet, - obClientMasters => obClientMasters, - obClientSlaves => obClientSlaves, - -- Interface to DHCP Engine - ibDhcpMaster => ibDhcpMaster, - ibDhcpSlave => ibDhcpSlave, - -- Clock and Reset - clk => clk, - rst => rst); - - GEN_DHCP : if (DHCP_G = true) generate - - U_UdpEngineDhcp : entity surf.UdpEngineDhcp - generic map ( - -- Simulation Generics - TPD_G => TPD_G, - -- UDP ARP/DHCP Generics - CLK_FREQ_G => CLK_FREQ_G, - COMM_TIMEOUT_G => COMM_TIMEOUT_G, - SYNTH_MODE_G => SYNTH_MODE_G) - port map ( - -- Local Configurations - localMac => localMac, - localIp => localIpIn, - dhcpIp => localIp, - -- Interface to DHCP Engine - ibDhcpMaster => ibDhcpMaster, - ibDhcpSlave => ibDhcpSlave, - obDhcpMaster => obDhcpMaster, - obDhcpSlave => obDhcpSlave, - -- Clock and Reset - clk => clk, - rst => rst); - - end generate; - - BYPASS_DHCP : if (DHCP_G = false) generate - - localIp <= localIpIn; - ibDhcpSlave <= AXI_STREAM_SLAVE_FORCE_C; - obDhcpMaster <= AXI_STREAM_MASTER_INIT_C; - - end generate; - - GEN_SERVER : if (SERVER_EN_G = true) generate - - U_UdpEngineTx : entity surf.UdpEngineTx - generic map ( - TPD_G => TPD_G, - SIZE_G => SERVER_SIZE_G, - TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, - PORT_G => SERVER_PORTS_G) - port map ( - -- Interface to IPV4 Engine - obUdpMaster => obUdpMasters(0), - obUdpSlave => obUdpSlaves(0), - -- Interface to User Application - localMac => localMac, - localIp => localIp, - remotePort => remotePort, - remoteIp => remoteIp, - remoteMac => serverRemoteMac, - ibMasters => ibServerMasters, - ibSlaves => ibServerSlaves, - -- Interface to DHCP Engine - obDhcpMaster => obDhcpMaster, - obDhcpSlave => obDhcpSlave, - -- Clock and Reset - clk => clk, - rst => rst); - - end generate; - - GEN_CLIENT : if (CLIENT_EN_G = true) generate - - U_UdpEngineArp : entity surf.UdpEngineArpV2 - generic map ( - TPD_G => TPD_G, - CLIENT_SIZE_G => CLIENT_SIZE_G, - CLK_FREQ_G => CLK_FREQ_G, - COMM_TIMEOUT_G => COMM_TIMEOUT_G) - port map ( - -- Local Configurations - localIp => localIp, - -- Interface to ARP Engine - arpReqMasters => arpReqMasters, - arpReqSlaves => arpReqSlaves, - arpAckMasters => arpAckMasters, - arpAckSlaves => arpAckSlaves, - -- Interface to UDP Client engine(s) - clientRemoteDet => clientRemoteDet, - clientRemoteIp => clientRemoteIp, - clientRemoteMac => clientRemoteMac, - -- Clock and Reset - clk => clk, - rst => rst); - - U_UdpEngineTx : entity surf.UdpEngineTx - generic map ( - TPD_G => TPD_G, - SIZE_G => CLIENT_SIZE_G, - TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, - PORT_G => CLIENT_PORTS_G) - port map ( - -- Interface to IPV4 Engine - obUdpMaster => obUdpMasters(1), - obUdpSlave => obUdpSlaves(1), - -- Interface to User Application - localMac => localMac, - localIp => localIp, - remotePort => clientRemotePort, - remoteIp => clientRemoteIp, - remoteMac => clientRemoteMac, - ibMasters => ibClientMasters, - ibSlaves => ibClientSlaves, - -- Clock and Reset - clk => clk, - rst => rst); - - end generate; - - GEN_MUX : if ((SERVER_EN_G = true) and (CLIENT_EN_G = true)) generate - - U_AxiStreamMux : entity surf.AxiStreamMux - generic map ( - TPD_G => TPD_G, - NUM_SLAVES_G => 2) - port map ( - -- Clock and reset - axisClk => clk, - axisRst => rst, - -- Slaves - sAxisMasters => obUdpMasters, - sAxisSlaves => obUdpSlaves, - -- Master - mAxisMaster => obUdpMaster, - mAxisSlave => obUdpSlave); - - end generate; - - NO_CLIENT : if ((SERVER_EN_G = true) and (CLIENT_EN_G = false)) generate - - -- Pass the server buses - obUdpMaster <= obUdpMasters(0); - obUdpSlaves(0) <= obUdpSlave; - - -- Terminated the client buses - ibClientSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); - obUdpMasters(1) <= AXI_STREAM_MASTER_INIT_C; - arpReqMasters <= (others => AXI_STREAM_MASTER_INIT_C); - arpAckSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); - clientRemoteMac <= (others => (others => '0')); - - end generate; - - NO_SERVER : if ((SERVER_EN_G = false) and (CLIENT_EN_G = true)) generate - - -- Pass the client buses - obUdpMaster <= obUdpMasters(1); - obUdpSlaves(1) <= obUdpSlave; - - -- Terminated the server buses - ibServerSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); - obUdpMasters(0) <= AXI_STREAM_MASTER_INIT_C; - - end generate; + -- Interface to IPV4 Engine + obUdpMaster => obUdpMasters(0), + obUdpSlave => obUdpSlaves(0), + -- Interface to User Application + localMac => localMac, + localIp => localIp, + remotePort => remotePort, + remoteIp => remoteIp, + remoteMac => serverRemoteMac, + ibMasters => ibServerMasters, + ibSlaves => ibServerSlaves, + -- Interface to DHCP Engine + obDhcpMaster => obDhcpMaster, + obDhcpSlave => obDhcpSlave, + -- Clock and Reset + clk => clk, + rst => rst); + + end generate; + + GEN_CLIENT : if (CLIENT_EN_G = true) generate + + GEN_ARP_TABLES : for i in 0 to CLIENT_SIZE_G-1 generate + ArpIpTable_1 : entity surf.ArpIpTable + generic map ( + TPD_G => TPD_G, + ENTRIES_G => ARP_TAB_ENTRIES_G) + port map ( + clk => clk, + rst => rst, + ipAddrIn => clientRemoteIp(i), + pos => arpTabPos(i), + found => arpTabFound(i), + macAddr => arpTabMacAddr(i), + ipAddrOut => arpTabIpAddr(i), + ipWrEn => arpTabIpWe(i), + IpWrAddr => clientRemoteIp(i), + macWrEn => arpTabMacWe(i), + macWrAddr => arpTabMacAddrW(i)); + end generate GEN_ARP_TABLES; + + U_UdpEngineArp : entity surf.UdpEngineArpV2 + generic map ( + TPD_G => TPD_G, + CLIENT_SIZE_G => CLIENT_SIZE_G, + CLK_FREQ_G => CLK_FREQ_G, + COMM_TIMEOUT_G => COMM_TIMEOUT_G) + port map ( + -- Local Configurations + localIp => localIp, + -- Interface to ARP Engine + arpReqMasters => arpReqMasters, + arpReqSlaves => arpReqSlaves, + arpAckMasters => arpAckMasters, + arpAckSlaves => arpAckSlaves, + -- Interface to ARP Table + arpTabFound => arpTabFound, + arpTabMacAddr => arpTabMacAddr, + arpTabIpWe => arpTabIpWe, + arpTabMacWe => arpTabMacWe, + arpTabMacAddrW => arpTabMacAddrW, + -- Interface to UDP Client engine(s) + clientRemoteDet => clientRemoteDet, + clientRemoteIp => clientRemoteIp, + clientRemoteMac => clientRemoteMac, + -- Clock and Reset + clk => clk, + rst => rst); + + U_UdpEngineTx : entity surf.UdpEngineTx + generic map ( + TPD_G => TPD_G, + SIZE_G => CLIENT_SIZE_G, + TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, + PORT_G => CLIENT_PORTS_G) + port map ( + -- Interface to IPV4 Engine + obUdpMaster => obUdpMasters(1), + obUdpSlave => obUdpSlaves(1), + -- Interface to User Application + localMac => localMac, + localIp => localIp, + remotePort => clientRemotePort, + remoteIp => clientRemoteIp, + remoteMac => clientRemoteMac, + ibMasters => ibClientMasters, + ibSlaves => ibClientSlaves, + arpTabPos => arpTabPos, + arpTabFound => arpTabFound, + arpTabIpAddr => arpTabIpAddr, + arpTabMacAddr => arpTabMacAddr, + -- Clock and Reset + clk => clk, + rst => rst); + + end generate; + + GEN_MUX : if ((SERVER_EN_G = true) and (CLIENT_EN_G = true)) generate + + U_AxiStreamMux : entity surf.AxiStreamMux + generic map ( + TPD_G => TPD_G, + NUM_SLAVES_G => 2) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slaves + sAxisMasters => obUdpMasters, + sAxisSlaves => obUdpSlaves, + -- Master + mAxisMaster => obUdpMaster, + mAxisSlave => obUdpSlave); + + end generate; + + NO_CLIENT : if ((SERVER_EN_G = true) and (CLIENT_EN_G = false)) generate + + -- Pass the server buses + obUdpMaster <= obUdpMasters(0); + obUdpSlaves(0) <= obUdpSlave; + + -- Terminated the client buses + ibClientSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); + obUdpMasters(1) <= AXI_STREAM_MASTER_INIT_C; + arpReqMasters <= (others => AXI_STREAM_MASTER_INIT_C); + arpAckSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); + clientRemoteMac <= (others => (others => '0')); + + end generate; + + NO_SERVER : if ((SERVER_EN_G = false) and (CLIENT_EN_G = true)) generate + + -- Pass the client buses + obUdpMaster <= obUdpMasters(1); + obUdpSlaves(1) <= obUdpSlave; + + -- Terminated the server buses + ibServerSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); + obUdpMasters(0) <= AXI_STREAM_MASTER_INIT_C; + + end generate; end mapping; diff --git a/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd b/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd index faade9fe81..a6f441856b 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd @@ -37,6 +37,12 @@ entity UdpEngineArpV2 is arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + -- Interface to ARP Table + arpTabFound : in slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddr : in Slv48Array(CLIENT_SIZE_G-1 downto 0); + arpTabIpWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddrW : out Slv48Array(CLIENT_SIZE_G-1 downto 0); -- Interface to UDP Client engine(s) clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); @@ -85,32 +91,12 @@ architecture rtl of UdpEngineArpV2 is signal r : RegType := REG_INIT_C; signal rin : RegType; - signal arpIpFound : slv(CLIENT_SIZE_G-1 downto 0); - signal arpMacAddr : Slv48Array(CLIENT_SIZE_G-1 downto 0); - begin ----------------------------------------------------------------------------- -- ARP Tables ----------------------------------------------------------------------------- - GEN_ARP_TABLES : for i in 0 to CLIENT_SIZE_G-1 generate - ArpIpTable_1 : entity surf.ArpIpTable - generic map ( - ENTRIES_G => 2) - port map ( - clk => clk, - rst => rst, - ipAddr => clientRemoteIp(i), - pos => open, - found => arpIpFound(i), - macAddr => arpMacAddr(i), - ipWrEn => r.clientRemoteIpWrEn(i), - IpWrAddr => clientRemoteIp(i), - macWrEn => r.clientRemoteMacWrEn(i), - macWrAddr => r.clientRemoteMac(i)); - end generate GEN_ARP_TABLES; - - comb : process (arpAckMasters, arpReqSlaves, arpIpFound, arpMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is + comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is variable v : RegType; variable i : natural; begin @@ -174,9 +160,9 @@ begin case r.state(i) is ---------------------------------------------------------------------- when CHECK_S => - if arpIpFound(i) = '1' then + if arpTabFound(i) = '1' then -- Set found MAC addr - v.clientRemoteMac(i) := arpMacAddr(i); + v.clientRemoteMac(i) := arpTabMacAddr(i); -- Preset the timer v.arpTimers(i) := COMM_TIMEOUT_G; -- Next state @@ -248,6 +234,9 @@ begin -- Registered Outputs arpReqMasters <= r.arpReqMasters; clientRemoteMac <= r.clientRemoteMac; + arpTabIpWe <= r.clientRemoteIpWrEn; + arpTabMacWe <= r.clientRemoteMacWrEn; + arpTabMacAddrW <= r.clientRemoteMac; end process comb; diff --git a/ethernet/UdpEngine/rtl/UdpEngineTx.vhd b/ethernet/UdpEngine/rtl/UdpEngineTx.vhd index 7cc5938003..e68567377b 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineTx.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineTx.vhd @@ -26,390 +26,452 @@ use surf.SsiPkg.all; use surf.EthMacPkg.all; entity UdpEngineTx is - generic ( - -- Simulation Generics - TPD_G : time := 1 ns; - -- UDP General Generic - SIZE_G : positive := 1; - TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up - PORT_G : PositiveArray := (0 => 8192)); - port ( - -- Interface to IPV4 Engine - obUdpMaster : out AxiStreamMasterType; - obUdpSlave : in AxiStreamSlaveType; - -- Interface to User Application - linkUp : out slv(SIZE_G-1 downto 0); - localMac : in slv(47 downto 0); - localIp : in slv(31 downto 0); - remotePort : in Slv16Array(SIZE_G-1 downto 0); - remoteIp : in Slv32Array(SIZE_G-1 downto 0); - remoteMac : in Slv48Array(SIZE_G-1 downto 0); - ibMasters : in AxiStreamMasterArray(SIZE_G-1 downto 0); - ibSlaves : out AxiStreamSlaveArray(SIZE_G-1 downto 0); - -- Interface to DHCP Engine - obDhcpMaster : in AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; - obDhcpSlave : out AxiStreamSlaveType; - -- Clock and Reset - clk : in sl; - rst : in sl); + generic ( + -- Simulation Generics + TPD_G : time := 1 ns; + -- UDP General Generic + SIZE_G : positive := 1; + TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up + PORT_G : PositiveArray := (0 => 8192)); + port ( + -- Interface to IPV4 Engine + obUdpMaster : out AxiStreamMasterType; + obUdpSlave : in AxiStreamSlaveType; + -- Interface to User Application + linkUp : out slv(SIZE_G-1 downto 0); + localMac : in slv(47 downto 0); + localIp : in slv(31 downto 0); + remotePort : in Slv16Array(SIZE_G-1 downto 0); + remoteIp : in Slv32Array(SIZE_G-1 downto 0); + remoteMac : in Slv48Array(SIZE_G-1 downto 0); + ibMasters : in AxiStreamMasterArray(SIZE_G-1 downto 0); + ibSlaves : out AxiStreamSlaveArray(SIZE_G-1 downto 0); + arpTabPos : out Slv8Array(SIZE_G-1 downto 0); + arpTabFound : in slv(SIZE_G-1 downto 0) := (others => '0'); + arpTabIpAddr : in Slv32Array(SIZE_G-1 downto 0) := (others => (others => '0')); + arpTabMacAddr : in Slv48Array(SIZE_G-1 downto 0) := (others => (others => '0')); + -- Interface to DHCP Engine + obDhcpMaster : in AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + obDhcpSlave : out AxiStreamSlaveType; + -- Clock and Reset + clk : in sl; + rst : in sl); end UdpEngineTx; architecture rtl of UdpEngineTx is - constant PORT_C : Slv16Array(SIZE_G-1 downto 0) := EthPortArrayBigEndian(PORT_G, SIZE_G); + constant PORT_C : Slv16Array(SIZE_G-1 downto 0) := EthPortArrayBigEndian(PORT_G, SIZE_G); - type StateType is ( - IDLE_S, - DHCP_HDR_S, - HDR_S, - DHCP_BUFFER_S, - BUFFER_S, - LAST_S); + type StateType is ( + IDLE_S, + ACC_ARP_TAB_S, + DHCP_HDR_S, + HDR_S, + DHCP_BUFFER_S, + BUFFER_S, + LAST_S); - type RegType is record - linkUp : slv(SIZE_G-1 downto 0); - tKeep : slv(15 downto 0); - tData : slv(127 downto 0); - tLast : sl; - eofe : sl; - chPntr : natural range 0 to SIZE_G-1; - index : natural range 0 to SIZE_G-1; - obDhcpSlave : AxiStreamSlaveType; - ibSlaves : AxiStreamSlaveArray(SIZE_G-1 downto 0); - txMaster : AxiStreamMasterType; - state : StateType; - end record RegType; - constant REG_INIT_C : RegType := ( - linkUp => (others => '0'), - tKeep => (others => '0'), - tData => (others => '0'), - tLast => '0', - eofe => '0', - chPntr => 0, - index => 0, - obDhcpSlave => AXI_STREAM_SLAVE_INIT_C, - ibSlaves => (others => AXI_STREAM_SLAVE_INIT_C), - txMaster => AXI_STREAM_MASTER_INIT_C, - state => IDLE_S); + type RegType is record + linkUp : slv(SIZE_G-1 downto 0); + tKeep : slv(15 downto 0); + tData : slv(127 downto 0); + tLast : sl; + eofe : sl; + chPntr : natural range 0 to SIZE_G-1; + index : natural range 0 to SIZE_G-1; + arpPos : Slv8Array(SIZE_G-1 downto 0); + obDhcpSlave : AxiStreamSlaveType; + ibSlaves : AxiStreamSlaveArray(SIZE_G-1 downto 0); + txMaster : AxiStreamMasterType; + state : StateType; + end record RegType; + constant REG_INIT_C : RegType := ( + linkUp => (others => '0'), + tKeep => (others => '0'), + tData => (others => '0'), + tLast => '0', + eofe => '0', + chPntr => 0, + index => 0, + arpPos => (others => (others => '0')), + obDhcpSlave => AXI_STREAM_SLAVE_INIT_C, + ibSlaves => (others => AXI_STREAM_SLAVE_INIT_C), + txMaster => AXI_STREAM_MASTER_INIT_C, + state => IDLE_S); - signal r : RegType := REG_INIT_C; - signal rin : RegType; + signal r : RegType := REG_INIT_C; + signal rin : RegType; - signal txMaster : AxiStreamMasterType; - signal txSlave : AxiStreamSlaveType; + signal txMaster : AxiStreamMasterType; + signal txSlave : AxiStreamSlaveType; - -- attribute dont_touch : string; - -- attribute dont_touch of r : signal is "TRUE"; + -- attribute dont_touch : string; + -- attribute dont_touch of r : signal is "TRUE"; begin - comb : process (ibMasters, localIp, localMac, obDhcpMaster, r, remoteIp, - remoteMac, remotePort, rst, txSlave) is - variable v : RegType; - variable i : natural; - begin - -- Latch the current value - v := r; + comb : process (ibMasters, localIp, localMac, obDhcpMaster, r, remoteIp, + remoteMac, remotePort, rst, txSlave) is + variable v : RegType; + variable arpPosV : Slv8Array(SIZE_G-1 downto 0); + variable i : natural; + begin + -- Latch the current value + v := r; - -- Reset the flags - v.obDhcpSlave := AXI_STREAM_SLAVE_INIT_C; - v.ibSlaves := (others => AXI_STREAM_SLAVE_INIT_C); - if (txSlave.tReady = '1') then - v.txMaster.tValid := '0'; - v.txMaster.tLast := '0'; - v.txMaster.tUser := (others => '0'); - v.txMaster.tKeep := (others => '1'); - end if; + -- Reset the flags + v.obDhcpSlave := AXI_STREAM_SLAVE_INIT_C; + v.ibSlaves := (others => AXI_STREAM_SLAVE_INIT_C); + if (txSlave.tReady = '1') then + v.txMaster.tValid := '0'; + v.txMaster.tLast := '0'; + v.txMaster.tUser := (others => '0'); + v.txMaster.tKeep := (others => '1'); + end if; - for i in SIZE_G-1 downto 0 loop - -- Check if link is up - if (localMac /= 0) and -- Non-zero local MAC address - (localIp /= 0) and -- Non-zero local IP address - (PORT_G(i) /= 0) and -- Non-zero local UDP port - (remoteMac(i) /= 0) and -- Non-zero remote MAC address - (remoteIp(i) /= 0) and -- Non-zero remote IP address - (remotePort(i) /= 0) then -- Non-zero remote UDP port - -- Link Up - v.linkUp(i) := '1'; - else - -- Link down - v.linkUp(i) := '0'; - end if; - end loop; + for i in SIZE_G-1 downto 0 loop + -- Check if link is up + if (localMac /= 0) and -- Non-zero local MAC address + (localIp /= 0) and -- Non-zero local IP address + (PORT_G(i) /= 0) and -- Non-zero local UDP port + (remoteMac(i) /= 0) and -- Non-zero remote MAC address + (remoteIp(i) /= 0) and -- Non-zero remote IP address + (remotePort(i) /= 0) then -- Non-zero remote UDP port + -- Link Up + v.linkUp(i) := '1'; + else + -- Link down + v.linkUp(i) := '0'; + end if; + end loop; - -- State Machine - case r.state is - ---------------------------------------------------------------------- - when IDLE_S => - -- Check for roll over - if (r.index = (SIZE_G-1)) then - -- Reset the counter - v.index := 0; + -- State Machine + case r.state is + ---------------------------------------------------------------------- + when IDLE_S => + -- Check for roll over + if (r.index = (SIZE_G-1)) then + -- Reset the counter + v.index := 0; + else + -- Increment the counter + v.index := r.index + 1; + end if; + -- Check for DHCP data and remote MAC is non-zero + if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then + -- Check for SOF + if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, obDhcpMaster) = '1') then + -- Write the first header + v.txMaster.tValid := '1'; + v.txMaster.tData(47 downto 0) := (others => '1'); -- Destination MAC address + v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s + v.txMaster.tData(95 downto 64) := (others => '0'); -- Source IP address + v.txMaster.tData(127 downto 96) := (others => '1'); -- Destination IP address + ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); + -- Next state + v.state := DHCP_HDR_S; + else + -- Blow off the data + v.obDhcpSlave.tReady := '1'; + end if; + -- Check for data and remote MAC is non-zero + elsif (ibMasters(r.index).tValid = '1') and (v.txMaster.tValid = '0') then + -- Check if need to access ARP Table + if ibMasters(r.index).tDest = x"00" then + -- Check if link down and blowing off the data + if (r.linkUp(r.index) = '0') and TX_FLOW_CTRL_G then + -- Blow off the data + v.ibSlaves(r.index).tReady := '1'; + -- Check for SOF + elsif (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.index)) = '1') then + -- Check if link up + if (r.linkUp(r.index) = '1') then + -- Latch the index + v.chPntr := r.index; + -- Write the first header + v.txMaster.tValid := '1'; + v.txMaster.tData(47 downto 0) := remoteMac(r.index); -- Destination MAC address + v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s + v.txMaster.tData(95 downto 64) := localIp; -- Source IP address + v.txMaster.tData(127 downto 96) := remoteIp(r.index); -- Destination IP address + ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); + -- Next state + v.state := HDR_S; + end if; else - -- Increment the counter - v.index := r.index + 1; + -- Blow off the data + v.ibSlaves(r.index).tReady := '1'; end if; - -- Check for DHCP data and remote MAC is non-zero - if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then - -- Check for SOF - if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, obDhcpMaster) = '1') then - -- Write the first header - v.txMaster.tValid := '1'; - v.txMaster.tData(47 downto 0) := (others => '1'); -- Destination MAC address - v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s - v.txMaster.tData(95 downto 64) := (others => '0'); -- Source IP address - v.txMaster.tData(127 downto 96) := (others => '1'); -- Destination IP address - ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); - -- Next state - v.state := DHCP_HDR_S; - else - -- Blow off the data - v.obDhcpSlave.tReady := '1'; - end if; - -- Check for data and remote MAC is non-zero - elsif (ibMasters(r.index).tValid = '1') and (v.txMaster.tValid = '0') then - -- Check if link down and blowing off the data - if (r.linkUp(r.index) = '0') and TX_FLOW_CTRL_G then - -- Blow off the data - v.ibSlaves(r.index).tReady := '1'; - -- Check for SOF - elsif (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.index)) = '1') then - -- Check if link up - if (r.linkUp(r.index) = '1') then - -- Latch the index - v.chPntr := r.index; - -- Write the first header - v.txMaster.tValid := '1'; - v.txMaster.tData(47 downto 0) := remoteMac(r.index); -- Destination MAC address - v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s - v.txMaster.tData(95 downto 64) := localIp; -- Source IP address - v.txMaster.tData(127 downto 96) := remoteIp(r.index); -- Destination IP address - ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); - -- Next state - v.state := HDR_S; - end if; - else - -- Blow off the data - v.ibSlaves(r.index).tReady := '1'; - end if; + else + v.chPntr := r.index; + arpPosV(r.index) := ibMasters(r.index).tDest; + v.state := ACC_ARP_TAB_S; + end if; + end if; + ----------------------------------------------------------------------- + when ACC_ARP_TAB_S => + arpPosV(r.chPntr) := ibMasters(r.chPntr).tDest; + if arpTabFound(r.chPntr) = '0' then + v.linkUp(r.chPntr) := '0'; + -- Blow off the data.. + v.ibSlaves(r.chPntr).tReady := '1'; + -- ..until the last frame + if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then + v.state := IDLE_S; + end if; + else + -- Check if link down and blowing off the data + if (r.linkUp(r.chPntr) = '0') and TX_FLOW_CTRL_G then + -- Blow off the data.. + v.ibSlaves(r.chPntr).tReady := '1'; + -- ..until the last frame + if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then + v.state := IDLE_S; end if; - ------------------------------------------------ - -- Notes: Non-Standard IPv4 Pseudo Header Format - ------------------------------------------------ - -- tData[0][47:0] = DST MAC Address - -- tData[0][63:48] = zeros - -- tData[0][95:64] = SRC IP Address - -- tData[0][127:96] = DST IP address - -- tData[1][7:0] = zeros - -- tData[1][15:8] = Protocol Type = UDP - -- tData[1][31:16] = IPv4 Pseudo header length - -- tData[1][47:32] = SRC Port - -- tData[1][63:48] = DST Port - -- tData[1][79:64] = UDP Length - -- tData[1][95:80] = UDP Checksum - -- tData[1][127:96] = UDP Datagram - ------------------------------------------------ - ---------------------------------------------------------------------- - when DHCP_HDR_S => - -- Check if ready to move data - if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.obDhcpSlave.tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - v.txMaster.tData(7 downto 0) := x"00"; -- All 0s - v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP - v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core - v.txMaster.tData(47 downto 32) := DHCP_CPORT; -- Source port - v.txMaster.tData(63 downto 48) := DHCP_SPORT; -- Destination port - v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core - v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core - v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); -- UDP Datagram - v.txMaster.tKeep(11 downto 0) := x"FFF"; - v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); -- UDP Datagram - -- Track the leftovers - v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); - v.tData(127 downto 96) := (others => '0'); - v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); - v.tKeep(15 downto 12) := (others => '0'); - v.tLast := obDhcpMaster.tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; - end if; - else - -- Next state - v.state := DHCP_BUFFER_S; - end if; + -- Check for SOF + elsif (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1') then + -- Check if link up + if (r.linkUp(r.chPntr) = '1') then + -- Latch the index + v.chPntr := r.chPntr; + -- Write the first header + v.txMaster.tValid := '1'; + v.txMaster.tData(47 downto 0) := arpTabMacAddr(r.chPntr); -- Destination MAC address + v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s + v.txMaster.tData(95 downto 64) := localIp; -- Source IP address + v.txMaster.tData(127 downto 96) := arpTabIpAddr(r.chPntr); -- Destination IP address + ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); + -- Next state + v.state := HDR_S; end if; - ---------------------------------------------------------------------- - when HDR_S => - -- Check if ready to move data - if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.ibSlaves(r.chPntr).tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - v.txMaster.tData(7 downto 0) := x"00"; -- All 0s - v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP - v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core - v.txMaster.tData(47 downto 32) := PORT_C(r.chPntr); -- Source port - v.txMaster.tData(63 downto 48) := remotePort(r.chPntr); -- Destination port - v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core - v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core - v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); -- UDP Datagram - v.txMaster.tKeep(11 downto 0) := x"FFF"; - v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); -- UDP Datagram - -- Track the leftovers - v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); - v.tData(127 downto 96) := (others => '0'); - v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); - v.tKeep(15 downto 12) := (others => '0'); - v.tLast := ibMasters(r.chPntr).tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; - end if; - else - -- Next state - v.state := BUFFER_S; - end if; + else + -- Blow off the data.. + v.ibSlaves(r.chPntr).tReady := '1'; + -- ..until the last frame + if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then + v.state := IDLE_S; end if; - ---------------------------------------------------------------------- - when DHCP_BUFFER_S => - -- Check if ready to move data - if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.obDhcpSlave.tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - -- Move the data - v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); - v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); - v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); - v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); - -- Track the leftovers - v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); - v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); - v.tLast := obDhcpMaster.tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; - end if; - end if; + end if; + end if; + + ------------------------------------------------ + -- Notes: Non-Standard IPv4 Pseudo Header Format + ------------------------------------------------ + -- tData[0][47:0] = DST MAC Address + -- tData[0][63:48] = zeros + -- tData[0][95:64] = SRC IP Address + -- tData[0][127:96] = DST IP address + -- tData[1][7:0] = zeros + -- tData[1][15:8] = Protocol Type = UDP + -- tData[1][31:16] = IPv4 Pseudo header length + -- tData[1][47:32] = SRC Port + -- tData[1][63:48] = DST Port + -- tData[1][79:64] = UDP Length + -- tData[1][95:80] = UDP Checksum + -- tData[1][127:96] = UDP Datagram + ------------------------------------------------ + ---------------------------------------------------------------------- + when DHCP_HDR_S => + -- Check if ready to move data + if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.obDhcpSlave.tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + v.txMaster.tData(7 downto 0) := x"00"; -- All 0s + v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP + v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core + v.txMaster.tData(47 downto 32) := DHCP_CPORT; -- Source port + v.txMaster.tData(63 downto 48) := DHCP_SPORT; -- Destination port + v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core + v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core + v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); -- UDP Datagram + v.txMaster.tKeep(11 downto 0) := x"FFF"; + v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); -- UDP Datagram + -- Track the leftovers + v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); + v.tData(127 downto 96) := (others => '0'); + v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); + v.tKeep(15 downto 12) := (others => '0'); + v.tLast := obDhcpMaster.tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; end if; - ---------------------------------------------------------------------- - when BUFFER_S => - -- Check if ready to move data - if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.ibSlaves(r.chPntr).tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - -- Move the data - v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); - v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); - v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); - v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); - -- Track the leftovers - v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); - v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); - v.tLast := ibMasters(r.chPntr).tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; - end if; - end if; + else + -- Next state + v.state := DHCP_BUFFER_S; + end if; + end if; + ---------------------------------------------------------------------- + when HDR_S => + -- Check if ready to move data + if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.ibSlaves(r.chPntr).tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + v.txMaster.tData(7 downto 0) := x"00"; -- All 0s + v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP + v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core + v.txMaster.tData(47 downto 32) := PORT_C(r.chPntr); -- Source port + v.txMaster.tData(63 downto 48) := remotePort(r.chPntr); -- Destination port + v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core + v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core + v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); -- UDP Datagram + v.txMaster.tKeep(11 downto 0) := x"FFF"; + v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); -- UDP Datagram + -- Track the leftovers + v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); + v.tData(127 downto 96) := (others => '0'); + v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); + v.tKeep(15 downto 12) := (others => '0'); + v.tLast := ibMasters(r.chPntr).tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; end if; - ---------------------------------------------------------------------- - when LAST_S => - -- Check if ready to move data - if (v.txMaster.tValid = '0') then - -- Move the data - v.txMaster.tValid := '1'; - v.txMaster.tData(127 downto 0) := r.tData; - v.txMaster.tKeep(15 downto 0) := r.tKeep; - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, r.eofe); - -- Next state - v.state := IDLE_S; + else + -- Next state + v.state := BUFFER_S; + end if; + end if; + ---------------------------------------------------------------------- + when DHCP_BUFFER_S => + -- Check if ready to move data + if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.obDhcpSlave.tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + -- Move the data + v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); + v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); + v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); + v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); + -- Track the leftovers + v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); + v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); + v.tLast := obDhcpMaster.tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; end if; + end if; + end if; ---------------------------------------------------------------------- - end case; + when BUFFER_S => + -- Check if ready to move data + if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.ibSlaves(r.chPntr).tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + -- Move the data + v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); + v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); + v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); + v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); + -- Track the leftovers + v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); + v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); + v.tLast := ibMasters(r.chPntr).tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; + end if; + end if; + end if; + ---------------------------------------------------------------------- + when LAST_S => + -- Check if ready to move data + if (v.txMaster.tValid = '0') then + -- Move the data + v.txMaster.tValid := '1'; + v.txMaster.tData(127 downto 0) := r.tData; + v.txMaster.tKeep(15 downto 0) := r.tKeep; + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, r.eofe); + -- Next state + v.state := IDLE_S; + end if; + ---------------------------------------------------------------------- + end case; - -- Outputs - ibSlaves <= v.ibSlaves; - obDhcpSlave <= v.obDhcpSlave; - txMaster <= r.txMaster; - linkUp <= r.linkUp; + -- Outputs + ibSlaves <= v.ibSlaves; + obDhcpSlave <= v.obDhcpSlave; + txMaster <= r.txMaster; + linkUp <= r.linkUp; + arpTabPos <= arpPosV; - -- Reset - if (rst = '1') then - v := REG_INIT_C; - end if; + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; - -- Register the variable for next clock cycle - rin <= v; + -- Register the variable for next clock cycle + rin <= v; - end process comb; + end process comb; - seq : process (clk) is - begin - if rising_edge(clk) then - r <= rin after TPD_G; - end if; - end process seq; + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; + end if; + end process seq; - U_TxPipeline : entity surf.AxiStreamPipeline - generic map ( - TPD_G => TPD_G, - PIPE_STAGES_G => 1) - port map ( - axisClk => clk, - axisRst => rst, - sAxisMaster => txMaster, - sAxisSlave => txSlave, - mAxisMaster => obUdpMaster, - mAxisSlave => obUdpSlave); + U_TxPipeline : entity surf.AxiStreamPipeline + generic map ( + TPD_G => TPD_G, + PIPE_STAGES_G => 1) + port map ( + axisClk => clk, + axisRst => rst, + sAxisMaster => txMaster, + sAxisSlave => txSlave, + mAxisMaster => obUdpMaster, + mAxisSlave => obUdpSlave); end rtl; diff --git a/ethernet/UdpEngine/tb/UdpEngineTb.vhd b/ethernet/UdpEngine/tb/UdpEngineTb.vhd index aa5278c002..7a6fff963e 100644 --- a/ethernet/UdpEngine/tb/UdpEngineTb.vhd +++ b/ethernet/UdpEngine/tb/UdpEngineTb.vhd @@ -27,289 +27,317 @@ entity UdpEngineTb is end UdpEngineTb; architecture testbed of UdpEngineTb is - - constant CLK_PERIOD_C : time := 6.4 ns; - constant TPD_G : time := (CLK_PERIOD_C/4); - - constant MAC_ADDR_C : Slv48Array(1 downto 0) := ( - 0 => x"010300564400", --00:44:56:00:03:01 - 1 => x"020300564400"); --00:44:56:00:03:02 - - constant IP_ADDR_C : Slv32Array(1 downto 0) := ( - 0 => x"0A02A8C0", -- 192.168.2.10 - 1 => x"0B02A8C0"); -- 192.168.2.11 - - type RegType is record - packetLength : slv(31 downto 0); - trig : sl; - txBusy : sl; - errorDet : sl; - end record RegType; - - constant REG_INIT_C : RegType := ( - packetLength => toSlv(0, 32), - trig => '0', - txBusy => '0', - errorDet => '0'); - - signal r : RegType := REG_INIT_C; - signal rin : RegType; - - signal clk : sl := '0'; - signal rst : sl := '0'; - - signal txMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; - signal txSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; - - signal obMacMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); - signal obMacSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_INIT_C); - - signal ibMacMasters : AxiStreamMasterArray(1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); - signal ibMacSlaves : AxiStreamSlaveArray(1 downto 0) := (others => AXI_STREAM_SLAVE_INIT_C); - - signal ethConfig : EthMacConfigArray(1 downto 0) := (others => ETH_MAC_CONFIG_INIT_C); - signal phyD : Slv64Array(1 downto 0) := (others => (others => '0')); - signal phyC : Slv8Array(1 downto 0) := (others => (others => '0')); - - signal rxMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; - signal rxSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; - - signal phyReady : sl; - signal updatedResults : sl; - signal errorDet : sl; - signal rxBusy : sl; - signal txBusy : sl; - - signal remoteIpAddr : slv(31 downto 0); + constant NUM_CLIENT_C : positive := 3; + constant CLK_PERIOD_C : time := 6.4 ns; + constant TPD_G : time := (CLK_PERIOD_C/4); + + constant MAC_ADDR_C : Slv48Array(3 downto 0) := ( + 0 => x"010300564400", --00:44:56:00:03:01 + 1 => x"020300564400", --00:44:56:00:03:02 + 2 => x"030300564400", --00:44:56:00:03:03 + 3 => x"040300564400" --00:44:56:00:03:04 + ); + constant IP_ADDR_C : Slv32Array(3 downto 0) := ( + 0 => x"0A02A8C0", -- 192.168.2.10 + 1 => x"0B02A8C0", -- 192.168.2.11 + 2 => x"0C02A8C0", -- 192.168.2.12 + 3 => x"0D02A8C0" -- 192.168.2.13 + ); + + type RegType is record + packetLength : slv(31 downto 0); + trig : sl; + txBusy : sl; + errorDet : sl; + end record RegType; + + constant REG_INIT_C : RegType := ( + packetLength => toSlv(0, 32), + trig => '0', + txBusy => '0', + errorDet => '0'); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; + + signal clk : sl := '0'; + signal rst : sl := '0'; + + signal txMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal txSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; + + signal obMacMasters : AxiStreamMasterArray((NUM_CLIENT_C-1)+1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + signal obMacSlaves : AxiStreamSlaveArray((NUM_CLIENT_C-1)+1 downto 0) := (others => AXI_STREAM_SLAVE_INIT_C); + + signal ibMacMasters : AxiStreamMasterArray((NUM_CLIENT_C-1)+1 downto 0) := (others => AXI_STREAM_MASTER_INIT_C); + signal ibMacSlaves : AxiStreamSlaveArray((NUM_CLIENT_C-1)+1 downto 0) := (others => AXI_STREAM_SLAVE_INIT_C); + + signal ethConfig : EthMacConfigArray((NUM_CLIENT_C-1)+1 downto 0) := (others => ETH_MAC_CONFIG_INIT_C); + signal phyD : Slv64Array((NUM_CLIENT_C-1)+1 downto 0) := (others => (others => '0')); + signal phyC : Slv8Array((NUM_CLIENT_C-1)+1 downto 0) := (others => (others => '0')); + signal phyD_def : slv(63 downto 0); + signal phyC_def : slv(7 downto 0); + + signal rxMaster : AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + signal rxSlave : AxiStreamSlaveType := AXI_STREAM_SLAVE_INIT_C; + + signal phyReady : sl; + signal updatedResults : sl; + signal errorDet : sl; + signal rxBusy : sl; + signal txBusy : sl; + + signal remoteIpAddr : slv(31 downto 0); + + signal sel_phy : natural; begin - ClkRst_Inst : entity surf.ClkRst - generic map ( - CLK_PERIOD_G => CLK_PERIOD_C, - RST_START_DELAY_G => 0 ns, - RST_HOLD_TIME_G => 1000 ns) - port map ( - clkP => clk, - clkN => open, - rst => rst, - rstL => phyReady); - - ---------- - -- PRBS TX - ---------- - U_TX : entity surf.SsiPrbsTx + ClkRst_Inst : entity surf.ClkRst + generic map ( + CLK_PERIOD_G => CLK_PERIOD_C, + RST_START_DELAY_G => 0 ns, + RST_HOLD_TIME_G => 1000 ns) + port map ( + clkP => clk, + clkN => open, + rst => rst, + rstL => phyReady); + + ---------- + -- PRBS TX + ---------- + U_TX : entity surf.SsiPrbsTx + generic map ( + TPD_G => TPD_G, + AXI_EN_G => '0', + MASTER_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C) + port map ( + -- Master Port (mAxisClk) + mAxisClk => clk, + mAxisRst => rst, + mAxisMaster => txMaster, + mAxisSlave => txSlave, + -- Trigger Signal (locClk domain) + locClk => clk, + locRst => rst, + packetLength => r.packetLength, + trig => r.trig, + busy => txBusy); + + ---------------------------------------------------------------------------- + -- Set Remote IP addr + ---------------------------------------------------------------------------- + process is + begin -- process + remoteIpAddr <= (others => '0'); + sel_phy <= 1; + wait for 1300 ns; + wait until rising_edge(clk); + remoteIpAddr <= IP_ADDR_C(1); + sel_phy <= 1; + wait for 16 us; + wait until rising_edge(clk); + remoteIpAddr <= IP_ADDR_C(2); + sel_phy <= 2; + wait for 4 us; + wait until rising_edge(clk); + remoteIpAddr <= IP_ADDR_C(3); + sel_phy <= 3; + wait for 4 us; + wait until rising_edge(clk); + remoteIpAddr <= IP_ADDR_C(1); + sel_phy <= 1; + wait; + end process; + + phyD_def <= phyD(sel_phy); + phyC_def <= phyC(sel_phy); + + ---------------------- + -- IPv4/ARP/UDP Engine + ---------------------- + U_UDP_Client : entity surf.UdpEngineWrapper + generic map ( + -- Simulation Generics + TPD_G => TPD_G, + -- UDP Server Generics + SERVER_EN_G => false, + -- UDP Client Generics + CLIENT_EN_G => true, + CLIENT_SIZE_G => 1, + CLIENT_PORTS_G => (0 => 8193), + CLIENT_EXT_CONFIG_G => true) + port map ( + -- Local Configurations + localMac => MAC_ADDR_C(0), + localIp => IP_ADDR_C(0), + -- Remote Configurations + clientRemotePort(0) => x"0020", -- PORT = 8192 = 0x2000 (0x0020 in big endianness) + clientRemoteIp(0) => remoteIpAddr, + -- Interface to Ethernet Media Access Controller (MAC) + obMacMaster => obMacMasters(0), + obMacSlave => obMacSlaves(0), + ibMacMaster => ibMacMasters(0), + ibMacSlave => ibMacSlaves(0), + -- Interface to UDP Server engine(s) + obClientMasters => open, + obClientSlaves(0) => AXI_STREAM_SLAVE_FORCE_C, + ibClientMasters(0) => txMaster, + ibClientSlaves(0) => txSlave, + -- Clock and Reset + clk => clk, + rst => rst); + + -------------------- + -- Ethernet MAC core + -------------------- + U_MAC0 : entity surf.EthMacTop + generic map ( + TPD_G => TPD_G, + PHY_TYPE_G => "XGMII", + PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) + port map ( + -- DMA Interface + primClk => clk, + primRst => rst, + ibMacPrimMaster => ibMacMasters(0), + ibMacPrimSlave => ibMacSlaves(0), + obMacPrimMaster => obMacMasters(0), + obMacPrimSlave => obMacSlaves(0), + -- Ethernet Interface + ethClk => clk, + ethRst => rst, + ethConfig => ethConfig(0), + phyReady => phyReady, + -- XGMII PHY Interface + xgmiiTxd => phyD(0), + xgmiiTxc => phyC(0), + xgmiiRxd => phyD_def, + xgmiiRxc => phyC_def); + ethConfig(0).macAddress <= MAC_ADDR_C(0); + + GEN_RX_MACS : for i in 0 to NUM_CLIENT_C-1 generate + U_MAC1 : entity surf.EthMacTop generic map ( - TPD_G => TPD_G, - AXI_EN_G => '0', - MASTER_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C) + TPD_G => TPD_G, + PHY_TYPE_G => "XGMII", + PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) port map ( - -- Master Port (mAxisClk) - mAxisClk => clk, - mAxisRst => rst, - mAxisMaster => txMaster, - mAxisSlave => txSlave, - -- Trigger Signal (locClk domain) - locClk => clk, - locRst => rst, - packetLength => r.packetLength, - trig => r.trig, - busy => txBusy); - - ---------------------------------------------------------------------------- - -- Set Remote IP addr - ---------------------------------------------------------------------------- - process is - begin -- process - remoteIpAddr <= (others => '0'); - wait for 1300 ns; - wait until rising_edge(clk); - remoteIpAddr <= IP_ADDR_C(1); - wait; - end process; - - ---------------------- - -- IPv4/ARP/UDP Engine - ---------------------- - U_UDP_Client : entity surf.UdpEngineWrapper + -- DMA Interface + primClk => clk, + primRst => rst, + ibMacPrimMaster => ibMacMasters(i+1), + ibMacPrimSlave => ibMacSlaves(i+1), + obMacPrimMaster => obMacMasters(i+1), + obMacPrimSlave => obMacSlaves(i+1), + -- Ethernet Interface + ethClk => clk, + ethRst => rst, + ethConfig => ethConfig(i+1), + phyReady => phyReady, + -- XGMII PHY Interface + xgmiiTxd => phyD(i+1), + xgmiiTxc => phyC(i+1), + xgmiiRxd => phyD(0), + xgmiiRxc => phyC(0)); + ethConfig(i+1).macAddress <= MAC_ADDR_C(i+1); + + ---------------------- + -- IPv4/ARP/UDP Engine + ---------------------- + U_UDP_Server : entity surf.UdpEngineWrapper generic map ( - -- Simulation Generics - TPD_G => TPD_G, - -- UDP Server Generics - SERVER_EN_G => false, - -- UDP Client Generics - CLIENT_EN_G => true, - CLIENT_SIZE_G => 1, - CLIENT_PORTS_G => (0 => 8193), - CLIENT_EXT_CONFIG_G => true) + -- Simulation Generics + TPD_G => TPD_G, + -- UDP Server Generics + SERVER_EN_G => true, + SERVER_SIZE_G => 1, + SERVER_PORTS_G => (0 => 8192), + -- UDP Client Generics + CLIENT_EN_G => false) port map ( - -- Local Configurations - localMac => MAC_ADDR_C(0), - localIp => IP_ADDR_C(0), - -- Remote Configurations - clientRemotePort(0) => x"0020", -- PORT = 8192 = 0x2000 (0x0020 in big endianness) - clientRemoteIp(0) => remoteIpAddr, - -- Interface to Ethernet Media Access Controller (MAC) - obMacMaster => obMacMasters(0), - obMacSlave => obMacSlaves(0), - ibMacMaster => ibMacMasters(0), - ibMacSlave => ibMacSlaves(0), - -- Interface to UDP Server engine(s) - obClientMasters => open, - obClientSlaves(0) => AXI_STREAM_SLAVE_FORCE_C, - ibClientMasters(0) => txMaster, - ibClientSlaves(0) => txSlave, - -- Clock and Reset - clk => clk, - rst => rst); - - -------------------- - -- Ethernet MAC core - -------------------- - U_MAC0 : entity surf.EthMacTop - generic map ( - TPD_G => TPD_G, - PHY_TYPE_G => "XGMII", - PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) - port map ( - -- DMA Interface - primClk => clk, - primRst => rst, - ibMacPrimMaster => ibMacMasters(0), - ibMacPrimSlave => ibMacSlaves(0), - obMacPrimMaster => obMacMasters(0), - obMacPrimSlave => obMacSlaves(0), - -- Ethernet Interface - ethClk => clk, - ethRst => rst, - ethConfig => ethConfig(0), - phyReady => phyReady, - -- XGMII PHY Interface - xgmiiRxd => phyD(0), - xgmiiRxc => phyC(0), - xgmiiTxd => phyD(1), - xgmiiTxc => phyC(1)); - ethConfig(0).macAddress <= MAC_ADDR_C(0); - - U_MAC1 : entity surf.EthMacTop - generic map ( - TPD_G => TPD_G, - PHY_TYPE_G => "XGMII", - PRIM_CONFIG_G => EMAC_AXIS_CONFIG_C) - port map ( - -- DMA Interface - primClk => clk, - primRst => rst, - ibMacPrimMaster => ibMacMasters(1), - ibMacPrimSlave => ibMacSlaves(1), - obMacPrimMaster => obMacMasters(1), - obMacPrimSlave => obMacSlaves(1), - -- Ethernet Interface - ethClk => clk, - ethRst => rst, - ethConfig => ethConfig(1), - phyReady => phyReady, - -- XGMII PHY Interface - xgmiiRxd => phyD(1), - xgmiiRxc => phyC(1), - xgmiiTxd => phyD(0), - xgmiiTxc => phyC(0)); - ethConfig(1).macAddress <= MAC_ADDR_C(1); - - ---------------------- - -- IPv4/ARP/UDP Engine - ---------------------- - U_UDP_Server : entity surf.UdpEngineWrapper - generic map ( - -- Simulation Generics - TPD_G => TPD_G, - -- UDP Server Generics - SERVER_EN_G => true, - SERVER_SIZE_G => 1, - SERVER_PORTS_G => (0 => 8192), - -- UDP Client Generics - CLIENT_EN_G => false) - port map ( - -- Local Configurations - localMac => MAC_ADDR_C(1), - localIp => IP_ADDR_C(1), - -- Interface to Ethernet Media Access Controller (MAC) - obMacMaster => obMacMasters(1), - obMacSlave => obMacSlaves(1), - ibMacMaster => ibMacMasters(1), - ibMacSlave => ibMacSlaves(1), - -- Interface to UDP Server engine(s) - obServerMasters(0) => rxMaster, - obServerSlaves(0) => rxSlave, - ibServerMasters(0) => AXI_STREAM_MASTER_INIT_C, - ibServerSlaves => open, - -- Clock and Reset - clk => clk, - rst => rst); - - ---------- - -- PRBS RX - ---------- - U_RX : entity surf.SsiPrbsRx - generic map ( - TPD_G => TPD_G, - SLAVE_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C) - port map ( - -- Slave Port (sAxisClk) - sAxisClk => clk, - sAxisRst => rst, - sAxisMaster => rxMaster, - sAxisSlave => rxSlave, - -- Error Detection Signals (sAxisClk domain) - updatedResults => updatedResults, - errorDet => errorDet, - busy => rxBusy); - - comb : process (errorDet, r, rst, txBusy) is - variable v : RegType; - begin - -- Latch the current value - v := r; - - -- Keep delay copies - v.errorDet := errorDet; - v.txBusy := txBusy; - v.trig := not(r.txBusy); - - -- Check for the packet completion - if (txBusy = '1') and (r.txBusy = '0') then - -- Sweeping the packet size size - v.packetLength := r.packetLength + 1; - -- Check for Jumbo frame roll over - if (r.packetLength = (8192/4)-1) then - -- Reset the counter - v.packetLength := (others => '0'); - end if; - end if; - - -- Reset - if (rst = '1') then - v := REG_INIT_C; - end if; - - --------------------------------- - -- Simulation Error Self-checking - --------------------------------- - --if r.errorDet = '1' then - -- assert false - -- report "Simulation Failed!" severity failure; - --end if; - - -- Register the variable for next clock cycle - rin <= v; - - end process comb; - - seq : process (clk) is - begin - if (rising_edge(clk)) then - r <= rin after TPD_G; + -- Local Configurations + localMac => MAC_ADDR_C(i+1), + localIp => IP_ADDR_C(i+1), + -- Interface to Ethernet Media Access Controller (MAC) + obMacMaster => obMacMasters(i+1), + obMacSlave => obMacSlaves(i+1), + ibMacMaster => ibMacMasters(i+1), + ibMacSlave => ibMacSlaves(i+1), + -- Interface to UDP Server engine(s) + obServerMasters(0) => rxMaster, + obServerSlaves(0) => rxSlave, + ibServerMasters(0) => AXI_STREAM_MASTER_INIT_C, + ibServerSlaves => open, + -- Clock and Reset + clk => clk, + rst => rst); + end generate GEN_RX_MACS; + + ---------- + -- PRBS RX + ---------- + U_RX : entity surf.SsiPrbsRx + generic map ( + TPD_G => TPD_G, + SLAVE_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C) + port map ( + -- Slave Port (sAxisClk) + sAxisClk => clk, + sAxisRst => rst, + sAxisMaster => rxMaster, + sAxisSlave => rxSlave, + -- Error Detection Signals (sAxisClk domain) + updatedResults => updatedResults, + errorDet => errorDet, + busy => rxBusy); + + comb : process (errorDet, r, rst, txBusy) is + variable v : RegType; + begin + -- Latch the current value + v := r; + + -- Keep delay copies + v.errorDet := errorDet; + v.txBusy := txBusy; + v.trig := not(r.txBusy); + + -- Check for the packet completion + if (txBusy = '1') and (r.txBusy = '0') then + -- Sweeping the packet size size + v.packetLength := r.packetLength + 1; + -- Check for Jumbo frame roll over + if (r.packetLength = (8192/4)-1) then + -- Reset the counter + v.packetLength := (others => '0'); end if; - end process seq; + end if; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; + + --------------------------------- + -- Simulation Error Self-checking + --------------------------------- + --if r.errorDet = '1' then + -- assert false + -- report "Simulation Failed!" severity failure; + --end if; + + -- Register the variable for next clock cycle + rin <= v; + + end process comb; + + seq : process (clk) is + begin + if (rising_edge(clk)) then + r <= rin after TPD_G; + end if; + end process seq; end testbed; From 4fde3c4e2aa6be4286c6a59e870de7266fcc9cbe Mon Sep 17 00:00:00 2001 From: FilMarini Date: Mon, 16 Sep 2024 19:39:30 +0200 Subject: [PATCH 03/15] Seems like tDest is working --- ethernet/UdpEngine/rtl/UdpEngine.vhd | 2 +- ethernet/UdpEngine/rtl/UdpEngineArp.vhd | 374 ++++++++++++---------- ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd | 250 --------------- ethernet/UdpEngine/tb/UdpEngineTb.vhd | 45 ++- 4 files changed, 240 insertions(+), 431 deletions(-) mode change 100755 => 100644 ethernet/UdpEngine/rtl/UdpEngineArp.vhd delete mode 100644 ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd diff --git a/ethernet/UdpEngine/rtl/UdpEngine.vhd b/ethernet/UdpEngine/rtl/UdpEngine.vhd index ecd300b832..e0909f3e5d 100644 --- a/ethernet/UdpEngine/rtl/UdpEngine.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngine.vhd @@ -234,7 +234,7 @@ begin macWrAddr => arpTabMacAddrW(i)); end generate GEN_ARP_TABLES; - U_UdpEngineArp : entity surf.UdpEngineArpV2 + U_UdpEngineArp : entity surf.UdpEngineArp generic map ( TPD_G => TPD_G, CLIENT_SIZE_G => CLIENT_SIZE_G, diff --git a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd old mode 100755 new mode 100644 index 96f7a31e43..6efa06e75e --- a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd @@ -23,184 +23,228 @@ use surf.StdRtlPkg.all; use surf.AxiStreamPkg.all; entity UdpEngineArp is - generic ( - TPD_G : time := 1 ns; - CLIENT_SIZE_G : positive := 1; - CLK_FREQ_G : real := 156.25E+06; - COMM_TIMEOUT_G : positive := 30; - RESP_TIMEOUT_G : positive := 5); - port ( - -- Local Configurations - localIp : in slv(31 downto 0); -- big-Endian configuration - -- Interface to ARP Engine - arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address - arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address - arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - -- Interface to UDP Client engine(s) - clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); - clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); - clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); - -- Clock and Reset - clk : in sl; - rst : in sl); + generic ( + TPD_G : time := 1 ns; + CLIENT_SIZE_G : positive := 1; + CLK_FREQ_G : real := 156.25E+06; + COMM_TIMEOUT_G : positive := 30; + RESP_TIMEOUT_G : positive := 5); + port ( + -- Local Configurations + localIp : in slv(31 downto 0); -- big-Endian configuration + -- Interface to ARP Engine + arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address + arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address + arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + -- Interface to ARP Table + arpTabFound : in slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddr : in Slv48Array(CLIENT_SIZE_G-1 downto 0); + arpTabIpWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddrW : out Slv48Array(CLIENT_SIZE_G-1 downto 0); + -- Interface to UDP Client engine(s) + clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); + -- Clock and Reset + clk : in sl; + rst : in sl); end UdpEngineArp; architecture rtl of UdpEngineArp is - constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); - type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; - - type StateType is ( - IDLE_S, - WAIT_S, - COMM_MONITOR_S); - type StateArray is array (natural range <>) of StateType; - - type RegType is record - clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); - arpAckSlaves : AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpReqMasters : AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - timerEn : sl; - timer : natural range 0 to (TIMER_1_SEC_C-1); - arpTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); - respTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); - state : StateArray(CLIENT_SIZE_G-1 downto 0); - end record RegType; - constant REG_INIT_C : RegType := ( - clientRemoteMac => (others => (others => '0')), - arpAckSlaves => (others => AXI_STREAM_SLAVE_INIT_C), - arpReqMasters => (others => AXI_STREAM_MASTER_INIT_C), - timerEn => '0', - timer => 0, - arpTimers => (others => 0), - respTimers => (others => 0), - state => (others => IDLE_S)); - - signal r : RegType := REG_INIT_C; - signal rin : RegType; + constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); + type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; + + type StateType is ( + CHECK_S, + IDLE_S, + WAIT_S, + COMM_MONITOR_S); + type StateArray is array (natural range <>) of StateType; + + type RegType is record + clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteMacWrEn : slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteIpWrEn : slv(CLIENT_SIZE_G-1 downto 0); + arpAckSlaves : AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpReqMasters : AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + timerEn : sl; + timer : natural range 0 to (TIMER_1_SEC_C-1); + arpTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); + respTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); + state : StateArray(CLIENT_SIZE_G-1 downto 0); + end record RegType; + constant REG_INIT_C : RegType := ( + clientRemoteMac => (others => (others => '0')), + clientRemoteMacWrEn => (others => '0'), + clientRemoteIpWrEn => (others => '0'), + arpAckSlaves => (others => AXI_STREAM_SLAVE_INIT_C), + arpReqMasters => (others => AXI_STREAM_MASTER_INIT_C), + timerEn => '0', + timer => 0, + arpTimers => (others => 0), + respTimers => (others => 0), + state => (others => IDLE_S)); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; begin - comb : process (arpAckMasters, arpReqSlaves, clientRemoteDet, clientRemoteIp, r, rst) is - variable v : RegType; - variable i : natural; - begin - -- Latch the current value - v := r; - - -- Reset the flags - v.timerEn := '0'; - for i in CLIENT_SIZE_G-1 downto 0 loop - v.arpAckSlaves(i) := AXI_STREAM_SLAVE_INIT_C; - if arpReqSlaves(i).tReady = '1' then - v.arpReqMasters(i).tValid := '0'; - end if; - end loop; - - - -- Increment the timer - if r.timer = (TIMER_1_SEC_C-1) then - v.timer := 0; - v.timerEn := '1'; - else - v.timer := r.timer + 1; + ----------------------------------------------------------------------------- + -- ARP Tables + ----------------------------------------------------------------------------- + comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is + variable v : RegType; + variable i : natural; + begin + -- Latch the current value + v := r; + + -- Reset the flags + v.timerEn := '0'; + v.clientRemoteMacWrEn := (others => '0'); + v.clientRemoteIpWrEn := (others => '0'); + for i in CLIENT_SIZE_G-1 downto 0 loop + v.arpAckSlaves(i) := AXI_STREAM_SLAVE_INIT_C; + if arpReqSlaves(i).tReady = '1' then + v.arpReqMasters(i).tValid := '0'; end if; + end loop; - -- Loop through the clients - for i in CLIENT_SIZE_G-1 downto 0 loop - - -- Update the timers - if (r.timerEn = '1') and (r.arpTimers(i) /= 0) then - -- Decrement the timers - v.arpTimers(i) := r.arpTimers(i) - 1; - end if; - if (r.timerEn = '1') and (r.respTimers(i) /= 0) then - -- Decrement the timers - v.respTimers(i) := r.respTimers(i) - 1; - end if; - - -- Update the IP address - v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); - - -- Check for dynamic change in IP address - if (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) or (clientRemoteIp(i) = 0) then - -- Stop any outstanding requests - v.arpReqMasters(i).tValid := '0'; - -- Reset the remote MAC address - v.clientRemoteMac(i) := (others => '0'); - -- Next state - v.state(i) := IDLE_S; - else - -- State Machine - case r.state(i) is - ---------------------------------------------------------------------- - when IDLE_S => - -- Reset the counter - v.arpTimers(i) := 0; - -- Check if we have a non-zero IP address to request - if clientRemoteIp(i) /= 0 then - -- Make an ARP request - v.arpReqMasters(i).tValid := '1'; - -- Set the response timer - v.respTimers(i) := RESP_TIMEOUT_G; - -- Next state - v.state(i) := WAIT_S; - end if; - ---------------------------------------------------------------------- - when WAIT_S => - -- Reset the remote MAC address if ARP response times out - if r.respTimers(i) = 0 then - v.clientRemoteMac(i) := (others => '0'); - end if; - -- Wait for the ARP response - if arpAckMasters(i).tValid = '1' then - -- Accept the data - v.arpAckSlaves(i).tReady := '1'; - -- Latch the MAC address value - v.clientRemoteMac(i) := arpAckMasters(i).tData(47 downto 0); - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - -- Next state - v.state(i) := COMM_MONITOR_S; - end if; - ---------------------------------------------------------------------- - when COMM_MONITOR_S => - -- Check for inbound client communication - if clientRemoteDet(i) = '1' then - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - elsif r.arpTimers(i) = 0 then - -- Next state - v.state(i) := IDLE_S; - end if; - ---------------------------------------------------------------------- - end case; - end if; - end loop; - - -- Combinatorial outputs before the reset - arpAckSlaves <= v.arpAckSlaves; - - -- Reset - if (rst = '1') then - v := REG_INIT_C; - end if; - -- Register the variable for next clock cycle - rin <= v; + -- Increment the timer + if r.timer = (TIMER_1_SEC_C-1) then + v.timer := 0; + v.timerEn := '1'; + else + v.timer := r.timer + 1; + end if; - -- Registered Outputs - arpReqMasters <= r.arpReqMasters; - clientRemoteMac <= r.clientRemoteMac; + -- Loop through the clients + for i in CLIENT_SIZE_G-1 downto 0 loop - end process comb; + -- Update the timers + if (r.timerEn = '1') and (r.arpTimers(i) /= 0) then + -- Decrement the timers + v.arpTimers(i) := r.arpTimers(i) - 1; + end if; + if (r.timerEn = '1') and (r.respTimers(i) /= 0) then + -- Decrement the timers + v.respTimers(i) := r.respTimers(i) - 1; + end if; - seq : process (clk) is - begin - if rising_edge(clk) then - r <= rin after TPD_G; + -- Update the IP address + v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); + + -- Check for dynamic change in IP address + -- if (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) or (clientRemoteIp(i) = 0) then + if (clientRemoteIp(i) = 0) then + -- Stop any outstanding requests + v.arpReqMasters(i).tValid := '0'; + -- Reset the remote MAC address + v.clientRemoteMac(i) := (others => '0'); + -- Next state + v.state(i) := IDLE_S; + elsif (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) then + -- Stop any outstanding requests + v.arpReqMasters(i).tValid := '0'; + -- Reset the remote MAC address + v.clientRemoteMac(i) := (others => '0'); + -- Next state + v.state(i) := CHECK_S; + else + -- State Machine + case r.state(i) is + ---------------------------------------------------------------------- + when CHECK_S => + if arpTabFound(i) = '1' then + -- Set found MAC addr + v.clientRemoteMac(i) := arpTabMacAddr(i); + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + -- Next state + v.state(i) := COMM_MONITOR_S; + else + -- Write IP to ARP table + v.clientRemoteIpWrEn(i) := '1'; + -- Next state + v.state(i) := IDLE_S; + end if; + ---------------------------------------------------------------------- + when IDLE_S => + -- Reset the counter + v.arpTimers(i) := 0; + -- Check if we have a non-zero IP address to request + if clientRemoteIp(i) /= 0 then + -- Make an ARP request + v.arpReqMasters(i).tValid := '1'; + -- Set the response timer + v.respTimers(i) := RESP_TIMEOUT_G; + -- Next state + v.state(i) := WAIT_S; + end if; + ---------------------------------------------------------------------- + when WAIT_S => + -- Reset the remote MAC address if ARP response times out + if r.respTimers(i) = 0 then + v.clientRemoteMac(i) := (others => '0'); + end if; + -- Wait for the ARP response + if arpAckMasters(i).tValid = '1' then + -- Accept the data + v.arpAckSlaves(i).tReady := '1'; + -- Latch the MAC address value + v.clientRemoteMac(i) := arpAckMasters(i).tData(47 downto 0); + -- Write to ARP table + v.clientRemoteMacWrEn(i) := '1'; + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + -- Next state + v.state(i) := COMM_MONITOR_S; + end if; + ---------------------------------------------------------------------- + when COMM_MONITOR_S => + -- Check for inbound client communication + if clientRemoteDet(i) = '1' then + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + elsif r.arpTimers(i) = 0 then + -- Next state + v.state(i) := IDLE_S; + end if; + ---------------------------------------------------------------------- + end case; end if; - end process seq; + end loop; + + -- Combinatorial outputs before the reset + arpAckSlaves <= v.arpAckSlaves; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + rin <= v; + + -- Registered Outputs + arpReqMasters <= r.arpReqMasters; + clientRemoteMac <= r.clientRemoteMac; + arpTabIpWe <= r.clientRemoteIpWrEn; + arpTabMacWe <= r.clientRemoteMacWrEn; + arpTabMacAddrW <= r.clientRemoteMac; + + end process comb; + + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; + end if; + end process seq; end rtl; diff --git a/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd b/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd deleted file mode 100644 index a6f441856b..0000000000 --- a/ethernet/UdpEngine/rtl/UdpEngineArpV2.vhd +++ /dev/null @@ -1,250 +0,0 @@ -------------------------------------------------------------------------------- --- Company : SLAC National Accelerator Laboratory -------------------------------------------------------------------------------- --- Description: UDP Client's ARP Messaging Module -------------------------------------------------------------------------------- --- This file is part of 'SLAC Firmware Standard Library'. --- It is subject to the license terms in the LICENSE.txt file found in the --- top-level directory of this distribution and at: --- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. --- No part of 'SLAC Firmware Standard Library', including this file, --- may be copied, modified, propagated, or distributed except according to --- the terms contained in the LICENSE.txt file. -------------------------------------------------------------------------------- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.std_logic_unsigned.all; -use ieee.std_logic_arith.all; - - -library surf; -use surf.StdRtlPkg.all; -use surf.AxiStreamPkg.all; - -entity UdpEngineArpV2 is - generic ( - TPD_G : time := 1 ns; - CLIENT_SIZE_G : positive := 1; - CLK_FREQ_G : real := 156.25E+06; - COMM_TIMEOUT_G : positive := 30; - RESP_TIMEOUT_G : positive := 5); - port ( - -- Local Configurations - localIp : in slv(31 downto 0); -- big-Endian configuration - -- Interface to ARP Engine - arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address - arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address - arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - -- Interface to ARP Table - arpTabFound : in slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacAddr : in Slv48Array(CLIENT_SIZE_G-1 downto 0); - arpTabIpWe : out slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacWe : out slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacAddrW : out Slv48Array(CLIENT_SIZE_G-1 downto 0); - -- Interface to UDP Client engine(s) - clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); - clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); - clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); - -- Clock and Reset - clk : in sl; - rst : in sl); -end UdpEngineArpV2; - -architecture rtl of UdpEngineArpV2 is - - constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); - type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; - - type StateType is ( - CHECK_S, - IDLE_S, - WAIT_S, - COMM_MONITOR_S); - type StateArray is array (natural range <>) of StateType; - - type RegType is record - clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); - clientRemoteMacWrEn : slv(CLIENT_SIZE_G-1 downto 0); - clientRemoteIpWrEn : slv(CLIENT_SIZE_G-1 downto 0); - arpAckSlaves : AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpReqMasters : AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - timerEn : sl; - timer : natural range 0 to (TIMER_1_SEC_C-1); - arpTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); - respTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); - state : StateArray(CLIENT_SIZE_G-1 downto 0); - end record RegType; - constant REG_INIT_C : RegType := ( - clientRemoteMac => (others => (others => '0')), - clientRemoteMacWrEn => (others => '0'), - clientRemoteIpWrEn => (others => '0'), - arpAckSlaves => (others => AXI_STREAM_SLAVE_INIT_C), - arpReqMasters => (others => AXI_STREAM_MASTER_INIT_C), - timerEn => '0', - timer => 0, - arpTimers => (others => 0), - respTimers => (others => 0), - state => (others => IDLE_S)); - - signal r : RegType := REG_INIT_C; - signal rin : RegType; - -begin - - ----------------------------------------------------------------------------- - -- ARP Tables - ----------------------------------------------------------------------------- - comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is - variable v : RegType; - variable i : natural; - begin - -- Latch the current value - v := r; - - -- Reset the flags - v.timerEn := '0'; - v.clientRemoteMacWrEn := (others => '0'); - v.clientRemoteIpWrEn := (others => '0'); - for i in CLIENT_SIZE_G-1 downto 0 loop - v.arpAckSlaves(i) := AXI_STREAM_SLAVE_INIT_C; - if arpReqSlaves(i).tReady = '1' then - v.arpReqMasters(i).tValid := '0'; - end if; - end loop; - - - -- Increment the timer - if r.timer = (TIMER_1_SEC_C-1) then - v.timer := 0; - v.timerEn := '1'; - else - v.timer := r.timer + 1; - end if; - - -- Loop through the clients - for i in CLIENT_SIZE_G-1 downto 0 loop - - -- Update the timers - if (r.timerEn = '1') and (r.arpTimers(i) /= 0) then - -- Decrement the timers - v.arpTimers(i) := r.arpTimers(i) - 1; - end if; - if (r.timerEn = '1') and (r.respTimers(i) /= 0) then - -- Decrement the timers - v.respTimers(i) := r.respTimers(i) - 1; - end if; - - -- Update the IP address - v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); - - -- Check for dynamic change in IP address - -- if (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) or (clientRemoteIp(i) = 0) then - if (clientRemoteIp(i) = 0) then - -- Stop any outstanding requests - v.arpReqMasters(i).tValid := '0'; - -- Reset the remote MAC address - v.clientRemoteMac(i) := (others => '0'); - -- Next state - v.state(i) := IDLE_S; - elsif (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) then - -- Stop any outstanding requests - v.arpReqMasters(i).tValid := '0'; - -- Reset the remote MAC address - v.clientRemoteMac(i) := (others => '0'); - -- Next state - v.state(i) := CHECK_S; - else - -- State Machine - case r.state(i) is - ---------------------------------------------------------------------- - when CHECK_S => - if arpTabFound(i) = '1' then - -- Set found MAC addr - v.clientRemoteMac(i) := arpTabMacAddr(i); - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - -- Next state - v.state(i) := COMM_MONITOR_S; - else - -- Write IP to ARP table - v.clientRemoteIpWrEn(i) := '1'; - -- Next state - v.state(i) := IDLE_S; - end if; - ---------------------------------------------------------------------- - when IDLE_S => - -- Reset the counter - v.arpTimers(i) := 0; - -- Check if we have a non-zero IP address to request - if clientRemoteIp(i) /= 0 then - -- Make an ARP request - v.arpReqMasters(i).tValid := '1'; - -- Set the response timer - v.respTimers(i) := RESP_TIMEOUT_G; - -- Next state - v.state(i) := WAIT_S; - end if; - ---------------------------------------------------------------------- - when WAIT_S => - -- Reset the remote MAC address if ARP response times out - if r.respTimers(i) = 0 then - v.clientRemoteMac(i) := (others => '0'); - end if; - -- Wait for the ARP response - if arpAckMasters(i).tValid = '1' then - -- Accept the data - v.arpAckSlaves(i).tReady := '1'; - -- Latch the MAC address value - v.clientRemoteMac(i) := arpAckMasters(i).tData(47 downto 0); - -- Write to ARP table - v.clientRemoteMacWrEn(i) := '1'; - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - -- Next state - v.state(i) := COMM_MONITOR_S; - end if; - ---------------------------------------------------------------------- - when COMM_MONITOR_S => - -- Check for inbound client communication - if clientRemoteDet(i) = '1' then - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - elsif r.arpTimers(i) = 0 then - -- Next state - v.state(i) := IDLE_S; - end if; - ---------------------------------------------------------------------- - end case; - end if; - end loop; - - -- Combinatorial outputs before the reset - arpAckSlaves <= v.arpAckSlaves; - - -- Reset - if (rst = '1') then - v := REG_INIT_C; - end if; - - -- Register the variable for next clock cycle - rin <= v; - - -- Registered Outputs - arpReqMasters <= r.arpReqMasters; - clientRemoteMac <= r.clientRemoteMac; - arpTabIpWe <= r.clientRemoteIpWrEn; - arpTabMacWe <= r.clientRemoteMacWrEn; - arpTabMacAddrW <= r.clientRemoteMac; - - end process comb; - - seq : process (clk) is - begin - if rising_edge(clk) then - r <= rin after TPD_G; - end if; - end process seq; - -end rtl; diff --git a/ethernet/UdpEngine/tb/UdpEngineTb.vhd b/ethernet/UdpEngine/tb/UdpEngineTb.vhd index 7a6fff963e..8971eb9b99 100644 --- a/ethernet/UdpEngine/tb/UdpEngineTb.vhd +++ b/ethernet/UdpEngine/tb/UdpEngineTb.vhd @@ -22,6 +22,7 @@ use surf.StdRtlPkg.all; use surf.AxiStreamPkg.all; use surf.SsiPkg.all; use surf.EthMacPkg.all; +use surf.AxiLitePkg.all; entity UdpEngineTb is end UdpEngineTb; @@ -88,8 +89,13 @@ architecture testbed of UdpEngineTb is signal txBusy : sl; signal remoteIpAddr : slv(31 downto 0); + signal tDest : slv(7 downto 0); - signal sel_phy : natural; + signal sel_phy : natural; + signal axilReadMaster : AxiLiteReadMasterType := AXI_LITE_READ_MASTER_INIT_C; + signal axilReadSlave : AxiLiteReadSlaveType; + signal axilWriteMaster : AxiLiteWriteMasterType := AXI_LITE_WRITE_MASTER_INIT_C; + signal axilWriteSlave : AxiLiteWriteSlaveType; begin @@ -114,16 +120,22 @@ begin MASTER_AXI_STREAM_CONFIG_G => EMAC_AXIS_CONFIG_C) port map ( -- Master Port (mAxisClk) - mAxisClk => clk, - mAxisRst => rst, - mAxisMaster => txMaster, - mAxisSlave => txSlave, + mAxisClk => clk, + mAxisRst => rst, + mAxisMaster => txMaster, + mAxisSlave => txSlave, + -- AxiLite + axilReadMaster => axilReadMaster, + axilReadSlave => axilReadSlave, + axilWriteMaster => axilWriteMaster, + axilWriteSlave => axilWriteSlave, -- Trigger Signal (locClk domain) - locClk => clk, - locRst => rst, - packetLength => r.packetLength, - trig => r.trig, - busy => txBusy); + locClk => clk, + locRst => rst, + packetLength => r.packetLength, + tDest => tDest, + trig => r.trig, + busy => txBusy); ---------------------------------------------------------------------------- -- Set Remote IP addr @@ -142,11 +154,14 @@ begin sel_phy <= 2; wait for 4 us; wait until rising_edge(clk); - remoteIpAddr <= IP_ADDR_C(3); - sel_phy <= 3; - wait for 4 us; - wait until rising_edge(clk); - remoteIpAddr <= IP_ADDR_C(1); + -- remoteIpAddr <= IP_ADDR_C(3); + -- sel_phy <= 3; + -- wait for 4 us; + -- wait until rising_edge(clk); + -- remoteIpAddr <= IP_ADDR_C(1); + -- tDest = 1 + -- axiLiteBusSimWrite(clk, axilWriteMaster, axilWriteSlave, x"00000008", x"01"); + tDest <= x"01"; sel_phy <= 1; wait; end process; From fc0d5eabc5067371215b8cdc77297c72edc1b09d Mon Sep 17 00:00:00 2001 From: FilMarini Date: Tue, 17 Sep 2024 15:12:54 +0200 Subject: [PATCH 04/15] Adding assertion if position is out of bounds --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index fa0b5b091c..7a261620ce 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -115,13 +115,20 @@ begin -- architecture rtl foundMacAddr := (others => '0'); foundIpAddr := (others => '0'); if pos > 0 then - posI := conv_integer(pos-1); - foundMacAddr := wr.macLutTable(posI); - foundIpAddr := wr.ipLutTable(posI); - if foundMacAddr = x"000000000000" or foundIpAddr = x"00000000" then - ipFound := '0'; + posI := conv_integer(pos-1); + if posI < ENTRIES_G then + foundMacAddr := wr.macLutTable(posI); + foundIpAddr := wr.ipLutTable(posI); + if foundMacAddr = x"000000000000" or foundIpAddr = x"00000000" then + ipFound := '0'; + else + ipFound := '1'; + end if; else - ipFound := '1'; + ipFound := '0'; + foundMacAddr := (others => '0'); + foundIpAddr := (others => '0'); + assert false report "Position in the LUT outside of bounds" severity error; end if; else for i in 0 to ENTRIES_G-1 loop From b50bab8065bf6fa903103d986cb91af38724db23 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Tue, 17 Sep 2024 15:31:24 +0200 Subject: [PATCH 05/15] fixed oversight on comment --- ethernet/UdpEngine/rtl/UdpEngineArp.vhd | 3 --- 1 file changed, 3 deletions(-) diff --git a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd index 6efa06e75e..7bf594bf1e 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd @@ -93,9 +93,6 @@ architecture rtl of UdpEngineArp is begin - ----------------------------------------------------------------------------- - -- ARP Tables - ----------------------------------------------------------------------------- comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is variable v : RegType; variable i : natural; From 49ef66ba8598c83b0915e6dc52ed0f150085ecf6 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Wed, 25 Sep 2024 11:41:01 +0200 Subject: [PATCH 06/15] slac beautification --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 234 +++---- ethernet/UdpEngine/rtl/UdpEngine.vhd | 596 ++++++++--------- ethernet/UdpEngine/rtl/UdpEngineArp.vhd | 412 ++++++------ ethernet/UdpEngine/rtl/UdpEngineTx.vhd | 822 ++++++++++++------------ 4 files changed, 1032 insertions(+), 1032 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 7a261620ce..974125c5d5 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -9,139 +9,139 @@ use surf.StdRtlPkg.all; entity ArpIpTable is - generic ( - TPD_G : time := 1 ns; - ENTRIES_G : positive range 1 to 255 := 4); - port ( - -- Clock and Reset - clk : in sl; - rst : in sl; - -- Read LUT - ipAddrIn : in slv(31 downto 0); - pos : in slv(7 downto 0); - found : out sl; - macAddr : out slv(47 downto 0); - ipAddrOut : out slv(31 downto 0); - -- Write LUT - ipWrEn : in sl; - IpWrAddr : in slv(31 downto 0); - macWrEn : in sl; - macWrAddr : in slv(47 downto 0)); + generic ( + TPD_G : time := 1 ns; + ENTRIES_G : positive range 1 to 255 := 4); + port ( + -- Clock and Reset + clk : in sl; + rst : in sl; + -- Read LUT + ipAddrIn : in slv(31 downto 0); + pos : in slv(7 downto 0); + found : out sl; + macAddr : out slv(47 downto 0); + ipAddrOut : out slv(31 downto 0); + -- Write LUT + ipWrEn : in sl; + IpWrAddr : in slv(31 downto 0); + macWrEn : in sl; + macWrAddr : in slv(47 downto 0)); end entity ArpIpTable; architecture rtl of ArpIpTable is - type wRegType is record - ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); - macLutTable : Slv48Array(ENTRIES_G-1 downto 0); - entryCount : slv(7 downto 0); - end record wRegType; + type wRegType is record + ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); + macLutTable : Slv48Array(ENTRIES_G-1 downto 0); + entryCount : slv(7 downto 0); + end record wRegType; - constant W_REG_INIT_C : wRegType := ( - ipLutTable => (others => (others => '0')), - macLutTable => (others => (others => '0')), - entryCount => (others => '0') - ); + constant W_REG_INIT_C : wRegType := ( + ipLutTable => (others => (others => '0')), + macLutTable => (others => (others => '0')), + entryCount => (others => '0') + ); - signal wR : wRegType := W_REG_INIT_C; - signal wRin : wRegType; + signal wR : wRegType := W_REG_INIT_C; + signal wRin : wRegType; - signal matchArray : slv(ENTRIES_G-1 downto 0); + signal matchArray : slv(ENTRIES_G-1 downto 0); begin -- architecture rtl - -- Write process comb - wrComb : process (ipWrAddr, ipWrEn, macWrAddr, macWrEn, rst, wR) is - variable v : wRegType; - variable wrAddInt : integer; - begin - -- Latch the current value - v := wR; - - -- Write IP to LUT - if ipWrEn = '1' then - wrAddInt := conv_integer(wR.entryCount); - if wrAddInt < ENTRIES_G then - v.ipLutTable(wrAddInt) := ipWrAddr; + -- Write process comb + wrComb : process (ipWrAddr, ipWrEn, macWrAddr, macWrEn, rst, wR) is + variable v : wRegType; + variable wrAddInt : integer; + begin + -- Latch the current value + v := wR; + + -- Write IP to LUT + if ipWrEn = '1' then + wrAddInt := conv_integer(wR.entryCount); + if wrAddInt < ENTRIES_G then + v.ipLutTable(wrAddInt) := ipWrAddr; + end if; end if; - end if; - -- Write MAC to LUT - if macWrEn = '1' then - wrAddInt := conv_integer(wR.entryCount); - if wrAddInt < ENTRIES_G then - v.macLutTable(wrAddInt) := macWrAddr; + -- Write MAC to LUT + if macWrEn = '1' then + wrAddInt := conv_integer(wR.entryCount); + if wrAddInt < ENTRIES_G then + v.macLutTable(wrAddInt) := macWrAddr; + end if; + + -- Update write LUT pointer + if wr.entryCount < ENTRIES_G - 1 then + v.entryCount := wr.entryCount + 1; + else + v.entryCount := (others => '0'); + end if; end if; - -- Update write LUT pointer - if wr.entryCount < ENTRIES_G - 1 then - v.entryCount := wr.entryCount + 1; - else - v.entryCount := (others => '0'); + -- Reset + if (rst = '1') then + v := W_REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + wRin <= v; + + end process wrComb; + + wrSeq : process (clk) is + begin + if rising_edge(clk) then + wR <= wRin after TPD_G; end if; - end if; - - -- Reset - if (rst = '1') then - v := W_REG_INIT_C; - end if; - - -- Register the variable for next clock cycle - wRin <= v; - - end process wrComb; - - wrSeq : process (clk) is - begin - if rising_edge(clk) then - wR <= wRin after TPD_G; - end if; - end process wrSeq; - - -- Read process - -- Check for a match - gen_compare : for i in 0 to ENTRIES_G-1 generate - matchArray(i) <= '1' when (wR.ipLutTable(i) = ipAddrIn) else '0'; - end generate; - - -- Encode the position based on the match_array - process(matchArray, pos, wr.macLutTable) - variable ipFound : sl := '0'; - variable posI : integer; - variable foundMacAddr : slv(47 downto 0); - variable foundIpAddr : slv(31 downto 0); - begin - ipFound := '0'; - foundMacAddr := (others => '0'); - foundIpAddr := (others => '0'); - if pos > 0 then - posI := conv_integer(pos-1); - if posI < ENTRIES_G then - foundMacAddr := wr.macLutTable(posI); - foundIpAddr := wr.ipLutTable(posI); - if foundMacAddr = x"000000000000" or foundIpAddr = x"00000000" then - ipFound := '0'; - else - ipFound := '1'; - end if; + end process wrSeq; + + -- Read process + -- Check for a match + gen_compare : for i in 0 to ENTRIES_G-1 generate + matchArray(i) <= '1' when (wR.ipLutTable(i) = ipAddrIn) else '0'; + end generate; + + -- Encode the position based on the match_array + process(matchArray, pos, wr.macLutTable) + variable ipFound : sl := '0'; + variable posI : integer; + variable foundMacAddr : slv(47 downto 0); + variable foundIpAddr : slv(31 downto 0); + begin + ipFound := '0'; + foundMacAddr := (others => '0'); + foundIpAddr := (others => '0'); + if pos > 0 then + posI := conv_integer(pos-1); + if posI < ENTRIES_G then + foundMacAddr := wr.macLutTable(posI); + foundIpAddr := wr.ipLutTable(posI); + if foundMacAddr = x"000000000000" or foundIpAddr = x"00000000" then + ipFound := '0'; + else + ipFound := '1'; + end if; + else + ipFound := '0'; + foundMacAddr := (others => '0'); + foundIpAddr := (others => '0'); + assert false report "Position in the LUT outside of bounds" severity error; + end if; else - ipFound := '0'; - foundMacAddr := (others => '0'); - foundIpAddr := (others => '0'); - assert false report "Position in the LUT outside of bounds" severity error; + for i in 0 to ENTRIES_G-1 loop + if matchArray(i) = '1' then + foundMacAddr := wr.macLutTable(i); + ipFound := '1'; + exit; -- Exit as soon as a match is found + end if; + end loop; end if; - else - for i in 0 to ENTRIES_G-1 loop - if matchArray(i) = '1' then - foundMacAddr := wr.macLutTable(i); - ipFound := '1'; - exit; -- Exit as soon as a match is found - end if; - end loop; - end if; - found <= ipFound; - macAddr <= foundMacAddr; - ipAddrOut <= foundIpAddr; - end process; + found <= ipFound; + macAddr <= foundMacAddr; + ipAddrOut <= foundIpAddr; + end process; end architecture rtl; diff --git a/ethernet/UdpEngine/rtl/UdpEngine.vhd b/ethernet/UdpEngine/rtl/UdpEngine.vhd index e0909f3e5d..c6325b63f3 100644 --- a/ethernet/UdpEngine/rtl/UdpEngine.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngine.vhd @@ -20,320 +20,320 @@ use surf.StdRtlPkg.all; use surf.AxiStreamPkg.all; entity UdpEngine is - generic ( - -- Simulation Generics - TPD_G : time := 1 ns; - -- UDP Server Generics - SERVER_EN_G : boolean := true; - SERVER_SIZE_G : positive := 1; - SERVER_PORTS_G : PositiveArray := (0 => 8192); - -- UDP Client Generics - CLIENT_EN_G : boolean := true; - CLIENT_SIZE_G : positive := 1; - CLIENT_PORTS_G : PositiveArray := (0 => 8193); - ARP_TAB_ENTRIES_G : positive range 1 to 255 := 4; - -- General UDP/IGMP/ARP/DHCP Generics - TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up - DHCP_G : boolean := false; - IGMP_G : boolean := false; - IGMP_GRP_SIZE : positive := 1; - CLK_FREQ_G : real := 156.25E+06; -- In units of Hz - COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request - SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs - port ( - -- Local Configurations - localMac : in slv(47 downto 0); -- big-Endian configuration - broadcastIp : in slv(31 downto 0); -- big-Endian configuration - igmpIp : in Slv32Array(IGMP_GRP_SIZE-1 downto 0); -- big-Endian configuration - localIpIn : in slv(31 downto 0); -- big-Endian configuration - dhcpIpOut : out slv(31 downto 0); -- big-Endian configuration - -- Interface to IPV4 Engine - obUdpMaster : out AxiStreamMasterType; - obUdpSlave : in AxiStreamSlaveType; - ibUdpMaster : in AxiStreamMasterType; - ibUdpSlave : out AxiStreamSlaveType; - -- Interface to ARP Engine - arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - -- Interface to UDP Server engine(s) - serverRemotePort : out Slv16Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration - serverRemoteIp : out Slv32Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration - obServerMasters : out AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration - obServerSlaves : in AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); - ibServerMasters : in AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); - ibServerSlaves : out AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration - -- Interface to UDP Client engine(s) - clientRemotePort : in Slv16Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration - clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration - obClientMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration - obClientSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - ibClientMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - ibClientSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration - -- Clock and Reset - clk : in sl; - rst : in sl); -end UdpEngine; - -architecture mapping of UdpEngine is - - signal clientRemoteDet : slv(CLIENT_SIZE_G-1 downto 0); - signal clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); - - signal remotePort : Slv16Array(SERVER_SIZE_G-1 downto 0); - signal remoteIp : Slv32Array(SERVER_SIZE_G-1 downto 0); - signal serverRemoteMac : Slv48Array(SERVER_SIZE_G-1 downto 0); - - signal obUdpMasters : AxiStreamMasterArray(1 downto 0); - signal obUdpSlaves : AxiStreamSlaveArray(1 downto 0); - - signal ibDhcpMaster : AxiStreamMasterType; - signal ibDhcpSlave : AxiStreamSlaveType; - - signal obDhcpMaster : AxiStreamMasterType; - signal obDhcpSlave : AxiStreamSlaveType; - - signal localIp : slv(31 downto 0); - - signal arpTabFound : slv(CLIENT_SIZE_G-1 downto 0); - signal arpTabMacAddr : Slv48Array(CLIENT_SIZE_G-1 downto 0); - signal arpTabIpAddr : Slv32Array(CLIENT_SIZE_G-1 downto 0); - signal arpTabIpWe : slv(CLIENT_SIZE_G-1 downto 0); - signal arpTabMacWe : slv(CLIENT_SIZE_G-1 downto 0); - signal arpTabMacAddrW : Slv48Array(CLIENT_SIZE_G-1 downto 0); - signal arpTabPos : Slv8Array(CLIENT_SIZE_G-1 downto 0); - -begin - - assert ((SERVER_EN_G = true) or (CLIENT_EN_G = true)) report - "UdpEngine: Either SERVER_EN_G or CLIENT_EN_G must be true" severity failure; - - serverRemotePort <= remotePort; -- Debug Only - serverRemoteIp <= remoteIp; -- Debug Only - dhcpIpOut <= localIp; - - U_UdpEngineRx : entity surf.UdpEngineRx - generic map ( - TPD_G => TPD_G, - DHCP_G => DHCP_G, - IGMP_G => IGMP_G, - IGMP_GRP_SIZE => IGMP_GRP_SIZE, - SERVER_EN_G => SERVER_EN_G, - SERVER_SIZE_G => SERVER_SIZE_G, - SERVER_PORTS_G => SERVER_PORTS_G, - CLIENT_EN_G => CLIENT_EN_G, - CLIENT_SIZE_G => CLIENT_SIZE_G, - CLIENT_PORTS_G => CLIENT_PORTS_G) - port map ( + generic ( + -- Simulation Generics + TPD_G : time := 1 ns; + -- UDP Server Generics + SERVER_EN_G : boolean := true; + SERVER_SIZE_G : positive := 1; + SERVER_PORTS_G : PositiveArray := (0 => 8192); + -- UDP Client Generics + CLIENT_EN_G : boolean := true; + CLIENT_SIZE_G : positive := 1; + CLIENT_PORTS_G : PositiveArray := (0 => 8193); + ARP_TAB_ENTRIES_G : positive range 1 to 255 := 4; + -- General UDP/IGMP/ARP/DHCP Generics + TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up + DHCP_G : boolean := false; + IGMP_G : boolean := false; + IGMP_GRP_SIZE : positive := 1; + CLK_FREQ_G : real := 156.25E+06; -- In units of Hz + COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request + SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs + port ( -- Local Configurations - localIp => localIp, - broadcastIp => broadcastIp, - igmpIp => igmpIp, + localMac : in slv(47 downto 0); -- big-Endian configuration + broadcastIp : in slv(31 downto 0); -- big-Endian configuration + igmpIp : in Slv32Array(IGMP_GRP_SIZE-1 downto 0); -- big-Endian configuration + localIpIn : in slv(31 downto 0); -- big-Endian configuration + dhcpIpOut : out slv(31 downto 0); -- big-Endian configuration -- Interface to IPV4 Engine - ibUdpMaster => ibUdpMaster, - ibUdpSlave => ibUdpSlave, + obUdpMaster : out AxiStreamMasterType; + obUdpSlave : in AxiStreamSlaveType; + ibUdpMaster : in AxiStreamMasterType; + ibUdpSlave : out AxiStreamSlaveType; + -- Interface to ARP Engine + arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); -- Interface to UDP Server engine(s) - serverRemotePort => remotePort, - serverRemoteIp => remoteIp, - serverRemoteMac => serverRemoteMac, - obServerMasters => obServerMasters, - obServerSlaves => obServerSlaves, + serverRemotePort : out Slv16Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration + serverRemoteIp : out Slv32Array(SERVER_SIZE_G-1 downto 0); -- big-Endian configuration + obServerMasters : out AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration + obServerSlaves : in AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); + ibServerMasters : in AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); + ibServerSlaves : out AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); -- tData is big-Endian configuration -- Interface to UDP Client engine(s) - clientRemoteDet => clientRemoteDet, - obClientMasters => obClientMasters, - obClientSlaves => obClientSlaves, - -- Interface to DHCP Engine - ibDhcpMaster => ibDhcpMaster, - ibDhcpSlave => ibDhcpSlave, + clientRemotePort : in Slv16Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration + clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); -- big-Endian configuration + obClientMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration + obClientSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + ibClientMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + ibClientSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); -- tData is big-Endian configuration -- Clock and Reset - clk => clk, - rst => rst); - - GEN_DHCP : if (DHCP_G = true) generate - - U_UdpEngineDhcp : entity surf.UdpEngineDhcp - generic map ( - -- Simulation Generics - TPD_G => TPD_G, - -- UDP ARP/DHCP Generics - CLK_FREQ_G => CLK_FREQ_G, - COMM_TIMEOUT_G => COMM_TIMEOUT_G, - SYNTH_MODE_G => SYNTH_MODE_G) - port map ( - -- Local Configurations - localMac => localMac, - localIp => localIpIn, - dhcpIp => localIp, - -- Interface to DHCP Engine - ibDhcpMaster => ibDhcpMaster, - ibDhcpSlave => ibDhcpSlave, - obDhcpMaster => obDhcpMaster, - obDhcpSlave => obDhcpSlave, - -- Clock and Reset - clk => clk, - rst => rst); - - end generate; - - BYPASS_DHCP : if (DHCP_G = false) generate - - localIp <= localIpIn; - ibDhcpSlave <= AXI_STREAM_SLAVE_FORCE_C; - obDhcpMaster <= AXI_STREAM_MASTER_INIT_C; + clk : in sl; + rst : in sl); +end UdpEngine; - end generate; +architecture mapping of UdpEngine is - GEN_SERVER : if (SERVER_EN_G = true) generate + signal clientRemoteDet : slv(CLIENT_SIZE_G-1 downto 0); + signal clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); - U_UdpEngineTx : entity surf.UdpEngineTx - generic map ( - TPD_G => TPD_G, - SIZE_G => SERVER_SIZE_G, - TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, - PORT_G => SERVER_PORTS_G) - port map ( - -- Interface to IPV4 Engine - obUdpMaster => obUdpMasters(0), - obUdpSlave => obUdpSlaves(0), - -- Interface to User Application - localMac => localMac, - localIp => localIp, - remotePort => remotePort, - remoteIp => remoteIp, - remoteMac => serverRemoteMac, - ibMasters => ibServerMasters, - ibSlaves => ibServerSlaves, - -- Interface to DHCP Engine - obDhcpMaster => obDhcpMaster, - obDhcpSlave => obDhcpSlave, - -- Clock and Reset - clk => clk, - rst => rst); - - end generate; - - GEN_CLIENT : if (CLIENT_EN_G = true) generate - - GEN_ARP_TABLES : for i in 0 to CLIENT_SIZE_G-1 generate - ArpIpTable_1 : entity surf.ArpIpTable - generic map ( - TPD_G => TPD_G, - ENTRIES_G => ARP_TAB_ENTRIES_G) - port map ( - clk => clk, - rst => rst, - ipAddrIn => clientRemoteIp(i), - pos => arpTabPos(i), - found => arpTabFound(i), - macAddr => arpTabMacAddr(i), - ipAddrOut => arpTabIpAddr(i), - ipWrEn => arpTabIpWe(i), - IpWrAddr => clientRemoteIp(i), - macWrEn => arpTabMacWe(i), - macWrAddr => arpTabMacAddrW(i)); - end generate GEN_ARP_TABLES; - - U_UdpEngineArp : entity surf.UdpEngineArp - generic map ( - TPD_G => TPD_G, - CLIENT_SIZE_G => CLIENT_SIZE_G, - CLK_FREQ_G => CLK_FREQ_G, - COMM_TIMEOUT_G => COMM_TIMEOUT_G) - port map ( - -- Local Configurations - localIp => localIp, - -- Interface to ARP Engine - arpReqMasters => arpReqMasters, - arpReqSlaves => arpReqSlaves, - arpAckMasters => arpAckMasters, - arpAckSlaves => arpAckSlaves, - -- Interface to ARP Table - arpTabFound => arpTabFound, - arpTabMacAddr => arpTabMacAddr, - arpTabIpWe => arpTabIpWe, - arpTabMacWe => arpTabMacWe, - arpTabMacAddrW => arpTabMacAddrW, - -- Interface to UDP Client engine(s) - clientRemoteDet => clientRemoteDet, - clientRemoteIp => clientRemoteIp, - clientRemoteMac => clientRemoteMac, - -- Clock and Reset - clk => clk, - rst => rst); - - U_UdpEngineTx : entity surf.UdpEngineTx - generic map ( - TPD_G => TPD_G, - SIZE_G => CLIENT_SIZE_G, - TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, - PORT_G => CLIENT_PORTS_G) - port map ( - -- Interface to IPV4 Engine - obUdpMaster => obUdpMasters(1), - obUdpSlave => obUdpSlaves(1), - -- Interface to User Application - localMac => localMac, - localIp => localIp, - remotePort => clientRemotePort, - remoteIp => clientRemoteIp, - remoteMac => clientRemoteMac, - ibMasters => ibClientMasters, - ibSlaves => ibClientSlaves, - arpTabPos => arpTabPos, - arpTabFound => arpTabFound, - arpTabIpAddr => arpTabIpAddr, - arpTabMacAddr => arpTabMacAddr, - -- Clock and Reset - clk => clk, - rst => rst); - - end generate; - - GEN_MUX : if ((SERVER_EN_G = true) and (CLIENT_EN_G = true)) generate - - U_AxiStreamMux : entity surf.AxiStreamMux - generic map ( - TPD_G => TPD_G, - NUM_SLAVES_G => 2) - port map ( - -- Clock and reset - axisClk => clk, - axisRst => rst, - -- Slaves - sAxisMasters => obUdpMasters, - sAxisSlaves => obUdpSlaves, - -- Master - mAxisMaster => obUdpMaster, - mAxisSlave => obUdpSlave); + signal remotePort : Slv16Array(SERVER_SIZE_G-1 downto 0); + signal remoteIp : Slv32Array(SERVER_SIZE_G-1 downto 0); + signal serverRemoteMac : Slv48Array(SERVER_SIZE_G-1 downto 0); - end generate; + signal obUdpMasters : AxiStreamMasterArray(1 downto 0); + signal obUdpSlaves : AxiStreamSlaveArray(1 downto 0); - NO_CLIENT : if ((SERVER_EN_G = true) and (CLIENT_EN_G = false)) generate + signal ibDhcpMaster : AxiStreamMasterType; + signal ibDhcpSlave : AxiStreamSlaveType; - -- Pass the server buses - obUdpMaster <= obUdpMasters(0); - obUdpSlaves(0) <= obUdpSlave; + signal obDhcpMaster : AxiStreamMasterType; + signal obDhcpSlave : AxiStreamSlaveType; - -- Terminated the client buses - ibClientSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); - obUdpMasters(1) <= AXI_STREAM_MASTER_INIT_C; - arpReqMasters <= (others => AXI_STREAM_MASTER_INIT_C); - arpAckSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); - clientRemoteMac <= (others => (others => '0')); + signal localIp : slv(31 downto 0); - end generate; + signal arpTabFound : slv(CLIENT_SIZE_G-1 downto 0); + signal arpTabMacAddr : Slv48Array(CLIENT_SIZE_G-1 downto 0); + signal arpTabIpAddr : Slv32Array(CLIENT_SIZE_G-1 downto 0); + signal arpTabIpWe : slv(CLIENT_SIZE_G-1 downto 0); + signal arpTabMacWe : slv(CLIENT_SIZE_G-1 downto 0); + signal arpTabMacAddrW : Slv48Array(CLIENT_SIZE_G-1 downto 0); + signal arpTabPos : Slv8Array(CLIENT_SIZE_G-1 downto 0); - NO_SERVER : if ((SERVER_EN_G = false) and (CLIENT_EN_G = true)) generate +begin - -- Pass the client buses - obUdpMaster <= obUdpMasters(1); - obUdpSlaves(1) <= obUdpSlave; + assert ((SERVER_EN_G = true) or (CLIENT_EN_G = true)) report + "UdpEngine: Either SERVER_EN_G or CLIENT_EN_G must be true" severity failure; - -- Terminated the server buses - ibServerSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); - obUdpMasters(0) <= AXI_STREAM_MASTER_INIT_C; + serverRemotePort <= remotePort; -- Debug Only + serverRemoteIp <= remoteIp; -- Debug Only + dhcpIpOut <= localIp; - end generate; + U_UdpEngineRx : entity surf.UdpEngineRx + generic map ( + TPD_G => TPD_G, + DHCP_G => DHCP_G, + IGMP_G => IGMP_G, + IGMP_GRP_SIZE => IGMP_GRP_SIZE, + SERVER_EN_G => SERVER_EN_G, + SERVER_SIZE_G => SERVER_SIZE_G, + SERVER_PORTS_G => SERVER_PORTS_G, + CLIENT_EN_G => CLIENT_EN_G, + CLIENT_SIZE_G => CLIENT_SIZE_G, + CLIENT_PORTS_G => CLIENT_PORTS_G) + port map ( + -- Local Configurations + localIp => localIp, + broadcastIp => broadcastIp, + igmpIp => igmpIp, + -- Interface to IPV4 Engine + ibUdpMaster => ibUdpMaster, + ibUdpSlave => ibUdpSlave, + -- Interface to UDP Server engine(s) + serverRemotePort => remotePort, + serverRemoteIp => remoteIp, + serverRemoteMac => serverRemoteMac, + obServerMasters => obServerMasters, + obServerSlaves => obServerSlaves, + -- Interface to UDP Client engine(s) + clientRemoteDet => clientRemoteDet, + obClientMasters => obClientMasters, + obClientSlaves => obClientSlaves, + -- Interface to DHCP Engine + ibDhcpMaster => ibDhcpMaster, + ibDhcpSlave => ibDhcpSlave, + -- Clock and Reset + clk => clk, + rst => rst); + + GEN_DHCP : if (DHCP_G = true) generate + + U_UdpEngineDhcp : entity surf.UdpEngineDhcp + generic map ( + -- Simulation Generics + TPD_G => TPD_G, + -- UDP ARP/DHCP Generics + CLK_FREQ_G => CLK_FREQ_G, + COMM_TIMEOUT_G => COMM_TIMEOUT_G, + SYNTH_MODE_G => SYNTH_MODE_G) + port map ( + -- Local Configurations + localMac => localMac, + localIp => localIpIn, + dhcpIp => localIp, + -- Interface to DHCP Engine + ibDhcpMaster => ibDhcpMaster, + ibDhcpSlave => ibDhcpSlave, + obDhcpMaster => obDhcpMaster, + obDhcpSlave => obDhcpSlave, + -- Clock and Reset + clk => clk, + rst => rst); + + end generate; + + BYPASS_DHCP : if (DHCP_G = false) generate + + localIp <= localIpIn; + ibDhcpSlave <= AXI_STREAM_SLAVE_FORCE_C; + obDhcpMaster <= AXI_STREAM_MASTER_INIT_C; + + end generate; + + GEN_SERVER : if (SERVER_EN_G = true) generate + + U_UdpEngineTx : entity surf.UdpEngineTx + generic map ( + TPD_G => TPD_G, + SIZE_G => SERVER_SIZE_G, + TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, + PORT_G => SERVER_PORTS_G) + port map ( + -- Interface to IPV4 Engine + obUdpMaster => obUdpMasters(0), + obUdpSlave => obUdpSlaves(0), + -- Interface to User Application + localMac => localMac, + localIp => localIp, + remotePort => remotePort, + remoteIp => remoteIp, + remoteMac => serverRemoteMac, + ibMasters => ibServerMasters, + ibSlaves => ibServerSlaves, + -- Interface to DHCP Engine + obDhcpMaster => obDhcpMaster, + obDhcpSlave => obDhcpSlave, + -- Clock and Reset + clk => clk, + rst => rst); + + end generate; + + GEN_CLIENT : if (CLIENT_EN_G = true) generate + + GEN_ARP_TABLES : for i in 0 to CLIENT_SIZE_G-1 generate + ArpIpTable_1 : entity surf.ArpIpTable + generic map ( + TPD_G => TPD_G, + ENTRIES_G => ARP_TAB_ENTRIES_G) + port map ( + clk => clk, + rst => rst, + ipAddrIn => clientRemoteIp(i), + pos => arpTabPos(i), + found => arpTabFound(i), + macAddr => arpTabMacAddr(i), + ipAddrOut => arpTabIpAddr(i), + ipWrEn => arpTabIpWe(i), + IpWrAddr => clientRemoteIp(i), + macWrEn => arpTabMacWe(i), + macWrAddr => arpTabMacAddrW(i)); + end generate GEN_ARP_TABLES; + + U_UdpEngineArp : entity surf.UdpEngineArp + generic map ( + TPD_G => TPD_G, + CLIENT_SIZE_G => CLIENT_SIZE_G, + CLK_FREQ_G => CLK_FREQ_G, + COMM_TIMEOUT_G => COMM_TIMEOUT_G) + port map ( + -- Local Configurations + localIp => localIp, + -- Interface to ARP Engine + arpReqMasters => arpReqMasters, + arpReqSlaves => arpReqSlaves, + arpAckMasters => arpAckMasters, + arpAckSlaves => arpAckSlaves, + -- Interface to ARP Table + arpTabFound => arpTabFound, + arpTabMacAddr => arpTabMacAddr, + arpTabIpWe => arpTabIpWe, + arpTabMacWe => arpTabMacWe, + arpTabMacAddrW => arpTabMacAddrW, + -- Interface to UDP Client engine(s) + clientRemoteDet => clientRemoteDet, + clientRemoteIp => clientRemoteIp, + clientRemoteMac => clientRemoteMac, + -- Clock and Reset + clk => clk, + rst => rst); + + U_UdpEngineTx : entity surf.UdpEngineTx + generic map ( + TPD_G => TPD_G, + SIZE_G => CLIENT_SIZE_G, + TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, + PORT_G => CLIENT_PORTS_G) + port map ( + -- Interface to IPV4 Engine + obUdpMaster => obUdpMasters(1), + obUdpSlave => obUdpSlaves(1), + -- Interface to User Application + localMac => localMac, + localIp => localIp, + remotePort => clientRemotePort, + remoteIp => clientRemoteIp, + remoteMac => clientRemoteMac, + ibMasters => ibClientMasters, + ibSlaves => ibClientSlaves, + arpTabPos => arpTabPos, + arpTabFound => arpTabFound, + arpTabIpAddr => arpTabIpAddr, + arpTabMacAddr => arpTabMacAddr, + -- Clock and Reset + clk => clk, + rst => rst); + + end generate; + + GEN_MUX : if ((SERVER_EN_G = true) and (CLIENT_EN_G = true)) generate + + U_AxiStreamMux : entity surf.AxiStreamMux + generic map ( + TPD_G => TPD_G, + NUM_SLAVES_G => 2) + port map ( + -- Clock and reset + axisClk => clk, + axisRst => rst, + -- Slaves + sAxisMasters => obUdpMasters, + sAxisSlaves => obUdpSlaves, + -- Master + mAxisMaster => obUdpMaster, + mAxisSlave => obUdpSlave); + + end generate; + + NO_CLIENT : if ((SERVER_EN_G = true) and (CLIENT_EN_G = false)) generate + + -- Pass the server buses + obUdpMaster <= obUdpMasters(0); + obUdpSlaves(0) <= obUdpSlave; + + -- Terminated the client buses + ibClientSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); + obUdpMasters(1) <= AXI_STREAM_MASTER_INIT_C; + arpReqMasters <= (others => AXI_STREAM_MASTER_INIT_C); + arpAckSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); + clientRemoteMac <= (others => (others => '0')); + + end generate; + + NO_SERVER : if ((SERVER_EN_G = false) and (CLIENT_EN_G = true)) generate + + -- Pass the client buses + obUdpMaster <= obUdpMasters(1); + obUdpSlaves(1) <= obUdpSlave; + + -- Terminated the server buses + ibServerSlaves <= (others => AXI_STREAM_SLAVE_FORCE_C); + obUdpMasters(0) <= AXI_STREAM_MASTER_INIT_C; + + end generate; end mapping; diff --git a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd index 7bf594bf1e..aaf8baa1ce 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd @@ -23,225 +23,225 @@ use surf.StdRtlPkg.all; use surf.AxiStreamPkg.all; entity UdpEngineArp is - generic ( - TPD_G : time := 1 ns; - CLIENT_SIZE_G : positive := 1; - CLK_FREQ_G : real := 156.25E+06; - COMM_TIMEOUT_G : positive := 30; - RESP_TIMEOUT_G : positive := 5); - port ( - -- Local Configurations - localIp : in slv(31 downto 0); -- big-Endian configuration - -- Interface to ARP Engine - arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address - arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address - arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - -- Interface to ARP Table - arpTabFound : in slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacAddr : in Slv48Array(CLIENT_SIZE_G-1 downto 0); - arpTabIpWe : out slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacWe : out slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacAddrW : out Slv48Array(CLIENT_SIZE_G-1 downto 0); - -- Interface to UDP Client engine(s) - clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); - clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); - clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); - -- Clock and Reset - clk : in sl; - rst : in sl); + generic ( + TPD_G : time := 1 ns; + CLIENT_SIZE_G : positive := 1; + CLK_FREQ_G : real := 156.25E+06; + COMM_TIMEOUT_G : positive := 30; + RESP_TIMEOUT_G : positive := 5); + port ( + -- Local Configurations + localIp : in slv(31 downto 0); -- big-Endian configuration + -- Interface to ARP Engine + arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address + arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address + arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + -- Interface to ARP Table + arpTabFound : in slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddr : in Slv48Array(CLIENT_SIZE_G-1 downto 0); + arpTabIpWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddrW : out Slv48Array(CLIENT_SIZE_G-1 downto 0); + -- Interface to UDP Client engine(s) + clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); + -- Clock and Reset + clk : in sl; + rst : in sl); end UdpEngineArp; architecture rtl of UdpEngineArp is - constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); - type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; - - type StateType is ( - CHECK_S, - IDLE_S, - WAIT_S, - COMM_MONITOR_S); - type StateArray is array (natural range <>) of StateType; - - type RegType is record - clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); - clientRemoteMacWrEn : slv(CLIENT_SIZE_G-1 downto 0); - clientRemoteIpWrEn : slv(CLIENT_SIZE_G-1 downto 0); - arpAckSlaves : AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpReqMasters : AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - timerEn : sl; - timer : natural range 0 to (TIMER_1_SEC_C-1); - arpTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); - respTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); - state : StateArray(CLIENT_SIZE_G-1 downto 0); - end record RegType; - constant REG_INIT_C : RegType := ( - clientRemoteMac => (others => (others => '0')), - clientRemoteMacWrEn => (others => '0'), - clientRemoteIpWrEn => (others => '0'), - arpAckSlaves => (others => AXI_STREAM_SLAVE_INIT_C), - arpReqMasters => (others => AXI_STREAM_MASTER_INIT_C), - timerEn => '0', - timer => 0, - arpTimers => (others => 0), - respTimers => (others => 0), - state => (others => IDLE_S)); - - signal r : RegType := REG_INIT_C; - signal rin : RegType; + constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); + type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; + + type StateType is ( + CHECK_S, + IDLE_S, + WAIT_S, + COMM_MONITOR_S); + type StateArray is array (natural range <>) of StateType; + + type RegType is record + clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteMacWrEn : slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteIpWrEn : slv(CLIENT_SIZE_G-1 downto 0); + arpAckSlaves : AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpReqMasters : AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + timerEn : sl; + timer : natural range 0 to (TIMER_1_SEC_C-1); + arpTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); + respTimers : TimerArray(CLIENT_SIZE_G-1 downto 0); + state : StateArray(CLIENT_SIZE_G-1 downto 0); + end record RegType; + constant REG_INIT_C : RegType := ( + clientRemoteMac => (others => (others => '0')), + clientRemoteMacWrEn => (others => '0'), + clientRemoteIpWrEn => (others => '0'), + arpAckSlaves => (others => AXI_STREAM_SLAVE_INIT_C), + arpReqMasters => (others => AXI_STREAM_MASTER_INIT_C), + timerEn => '0', + timer => 0, + arpTimers => (others => 0), + respTimers => (others => 0), + state => (others => IDLE_S)); + + signal r : RegType := REG_INIT_C; + signal rin : RegType; begin - comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is - variable v : RegType; - variable i : natural; - begin - -- Latch the current value - v := r; - - -- Reset the flags - v.timerEn := '0'; - v.clientRemoteMacWrEn := (others => '0'); - v.clientRemoteIpWrEn := (others => '0'); - for i in CLIENT_SIZE_G-1 downto 0 loop - v.arpAckSlaves(i) := AXI_STREAM_SLAVE_INIT_C; - if arpReqSlaves(i).tReady = '1' then - v.arpReqMasters(i).tValid := '0'; + comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is + variable v : RegType; + variable i : natural; + begin + -- Latch the current value + v := r; + + -- Reset the flags + v.timerEn := '0'; + v.clientRemoteMacWrEn := (others => '0'); + v.clientRemoteIpWrEn := (others => '0'); + for i in CLIENT_SIZE_G-1 downto 0 loop + v.arpAckSlaves(i) := AXI_STREAM_SLAVE_INIT_C; + if arpReqSlaves(i).tReady = '1' then + v.arpReqMasters(i).tValid := '0'; + end if; + end loop; + + + -- Increment the timer + if r.timer = (TIMER_1_SEC_C-1) then + v.timer := 0; + v.timerEn := '1'; + else + v.timer := r.timer + 1; end if; - end loop; + -- Loop through the clients + for i in CLIENT_SIZE_G-1 downto 0 loop + + -- Update the timers + if (r.timerEn = '1') and (r.arpTimers(i) /= 0) then + -- Decrement the timers + v.arpTimers(i) := r.arpTimers(i) - 1; + end if; + if (r.timerEn = '1') and (r.respTimers(i) /= 0) then + -- Decrement the timers + v.respTimers(i) := r.respTimers(i) - 1; + end if; + + -- Update the IP address + v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); + + -- Check for dynamic change in IP address + -- if (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) or (clientRemoteIp(i) = 0) then + if (clientRemoteIp(i) = 0) then + -- Stop any outstanding requests + v.arpReqMasters(i).tValid := '0'; + -- Reset the remote MAC address + v.clientRemoteMac(i) := (others => '0'); + -- Next state + v.state(i) := IDLE_S; + elsif (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) then + -- Stop any outstanding requests + v.arpReqMasters(i).tValid := '0'; + -- Reset the remote MAC address + v.clientRemoteMac(i) := (others => '0'); + -- Next state + v.state(i) := CHECK_S; + else + -- State Machine + case r.state(i) is + ---------------------------------------------------------------------- + when CHECK_S => + if arpTabFound(i) = '1' then + -- Set found MAC addr + v.clientRemoteMac(i) := arpTabMacAddr(i); + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + -- Next state + v.state(i) := COMM_MONITOR_S; + else + -- Write IP to ARP table + v.clientRemoteIpWrEn(i) := '1'; + -- Next state + v.state(i) := IDLE_S; + end if; + ---------------------------------------------------------------------- + when IDLE_S => + -- Reset the counter + v.arpTimers(i) := 0; + -- Check if we have a non-zero IP address to request + if clientRemoteIp(i) /= 0 then + -- Make an ARP request + v.arpReqMasters(i).tValid := '1'; + -- Set the response timer + v.respTimers(i) := RESP_TIMEOUT_G; + -- Next state + v.state(i) := WAIT_S; + end if; + ---------------------------------------------------------------------- + when WAIT_S => + -- Reset the remote MAC address if ARP response times out + if r.respTimers(i) = 0 then + v.clientRemoteMac(i) := (others => '0'); + end if; + -- Wait for the ARP response + if arpAckMasters(i).tValid = '1' then + -- Accept the data + v.arpAckSlaves(i).tReady := '1'; + -- Latch the MAC address value + v.clientRemoteMac(i) := arpAckMasters(i).tData(47 downto 0); + -- Write to ARP table + v.clientRemoteMacWrEn(i) := '1'; + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + -- Next state + v.state(i) := COMM_MONITOR_S; + end if; + ---------------------------------------------------------------------- + when COMM_MONITOR_S => + -- Check for inbound client communication + if clientRemoteDet(i) = '1' then + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + elsif r.arpTimers(i) = 0 then + -- Next state + v.state(i) := IDLE_S; + end if; + ---------------------------------------------------------------------- + end case; + end if; + end loop; + + -- Combinatorial outputs before the reset + arpAckSlaves <= v.arpAckSlaves; + + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; - -- Increment the timer - if r.timer = (TIMER_1_SEC_C-1) then - v.timer := 0; - v.timerEn := '1'; - else - v.timer := r.timer + 1; - end if; + -- Register the variable for next clock cycle + rin <= v; - -- Loop through the clients - for i in CLIENT_SIZE_G-1 downto 0 loop + -- Registered Outputs + arpReqMasters <= r.arpReqMasters; + clientRemoteMac <= r.clientRemoteMac; + arpTabIpWe <= r.clientRemoteIpWrEn; + arpTabMacWe <= r.clientRemoteMacWrEn; + arpTabMacAddrW <= r.clientRemoteMac; - -- Update the timers - if (r.timerEn = '1') and (r.arpTimers(i) /= 0) then - -- Decrement the timers - v.arpTimers(i) := r.arpTimers(i) - 1; - end if; - if (r.timerEn = '1') and (r.respTimers(i) /= 0) then - -- Decrement the timers - v.respTimers(i) := r.respTimers(i) - 1; - end if; + end process comb; - -- Update the IP address - v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); - - -- Check for dynamic change in IP address - -- if (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) or (clientRemoteIp(i) = 0) then - if (clientRemoteIp(i) = 0) then - -- Stop any outstanding requests - v.arpReqMasters(i).tValid := '0'; - -- Reset the remote MAC address - v.clientRemoteMac(i) := (others => '0'); - -- Next state - v.state(i) := IDLE_S; - elsif (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) then - -- Stop any outstanding requests - v.arpReqMasters(i).tValid := '0'; - -- Reset the remote MAC address - v.clientRemoteMac(i) := (others => '0'); - -- Next state - v.state(i) := CHECK_S; - else - -- State Machine - case r.state(i) is - ---------------------------------------------------------------------- - when CHECK_S => - if arpTabFound(i) = '1' then - -- Set found MAC addr - v.clientRemoteMac(i) := arpTabMacAddr(i); - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - -- Next state - v.state(i) := COMM_MONITOR_S; - else - -- Write IP to ARP table - v.clientRemoteIpWrEn(i) := '1'; - -- Next state - v.state(i) := IDLE_S; - end if; - ---------------------------------------------------------------------- - when IDLE_S => - -- Reset the counter - v.arpTimers(i) := 0; - -- Check if we have a non-zero IP address to request - if clientRemoteIp(i) /= 0 then - -- Make an ARP request - v.arpReqMasters(i).tValid := '1'; - -- Set the response timer - v.respTimers(i) := RESP_TIMEOUT_G; - -- Next state - v.state(i) := WAIT_S; - end if; - ---------------------------------------------------------------------- - when WAIT_S => - -- Reset the remote MAC address if ARP response times out - if r.respTimers(i) = 0 then - v.clientRemoteMac(i) := (others => '0'); - end if; - -- Wait for the ARP response - if arpAckMasters(i).tValid = '1' then - -- Accept the data - v.arpAckSlaves(i).tReady := '1'; - -- Latch the MAC address value - v.clientRemoteMac(i) := arpAckMasters(i).tData(47 downto 0); - -- Write to ARP table - v.clientRemoteMacWrEn(i) := '1'; - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - -- Next state - v.state(i) := COMM_MONITOR_S; - end if; - ---------------------------------------------------------------------- - when COMM_MONITOR_S => - -- Check for inbound client communication - if clientRemoteDet(i) = '1' then - -- Preset the timer - v.arpTimers(i) := COMM_TIMEOUT_G; - elsif r.arpTimers(i) = 0 then - -- Next state - v.state(i) := IDLE_S; - end if; - ---------------------------------------------------------------------- - end case; + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; end if; - end loop; - - -- Combinatorial outputs before the reset - arpAckSlaves <= v.arpAckSlaves; - - -- Reset - if (rst = '1') then - v := REG_INIT_C; - end if; - - -- Register the variable for next clock cycle - rin <= v; - - -- Registered Outputs - arpReqMasters <= r.arpReqMasters; - clientRemoteMac <= r.clientRemoteMac; - arpTabIpWe <= r.clientRemoteIpWrEn; - arpTabMacWe <= r.clientRemoteMacWrEn; - arpTabMacAddrW <= r.clientRemoteMac; - - end process comb; - - seq : process (clk) is - begin - if rising_edge(clk) then - r <= rin after TPD_G; - end if; - end process seq; + end process seq; end rtl; diff --git a/ethernet/UdpEngine/rtl/UdpEngineTx.vhd b/ethernet/UdpEngine/rtl/UdpEngineTx.vhd index e68567377b..c3cac69e4b 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineTx.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineTx.vhd @@ -26,452 +26,452 @@ use surf.SsiPkg.all; use surf.EthMacPkg.all; entity UdpEngineTx is - generic ( - -- Simulation Generics - TPD_G : time := 1 ns; - -- UDP General Generic - SIZE_G : positive := 1; - TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up - PORT_G : PositiveArray := (0 => 8192)); - port ( - -- Interface to IPV4 Engine - obUdpMaster : out AxiStreamMasterType; - obUdpSlave : in AxiStreamSlaveType; - -- Interface to User Application - linkUp : out slv(SIZE_G-1 downto 0); - localMac : in slv(47 downto 0); - localIp : in slv(31 downto 0); - remotePort : in Slv16Array(SIZE_G-1 downto 0); - remoteIp : in Slv32Array(SIZE_G-1 downto 0); - remoteMac : in Slv48Array(SIZE_G-1 downto 0); - ibMasters : in AxiStreamMasterArray(SIZE_G-1 downto 0); - ibSlaves : out AxiStreamSlaveArray(SIZE_G-1 downto 0); - arpTabPos : out Slv8Array(SIZE_G-1 downto 0); - arpTabFound : in slv(SIZE_G-1 downto 0) := (others => '0'); - arpTabIpAddr : in Slv32Array(SIZE_G-1 downto 0) := (others => (others => '0')); - arpTabMacAddr : in Slv48Array(SIZE_G-1 downto 0) := (others => (others => '0')); - -- Interface to DHCP Engine - obDhcpMaster : in AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; - obDhcpSlave : out AxiStreamSlaveType; - -- Clock and Reset - clk : in sl; - rst : in sl); + generic ( + -- Simulation Generics + TPD_G : time := 1 ns; + -- UDP General Generic + SIZE_G : positive := 1; + TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up + PORT_G : PositiveArray := (0 => 8192)); + port ( + -- Interface to IPV4 Engine + obUdpMaster : out AxiStreamMasterType; + obUdpSlave : in AxiStreamSlaveType; + -- Interface to User Application + linkUp : out slv(SIZE_G-1 downto 0); + localMac : in slv(47 downto 0); + localIp : in slv(31 downto 0); + remotePort : in Slv16Array(SIZE_G-1 downto 0); + remoteIp : in Slv32Array(SIZE_G-1 downto 0); + remoteMac : in Slv48Array(SIZE_G-1 downto 0); + ibMasters : in AxiStreamMasterArray(SIZE_G-1 downto 0); + ibSlaves : out AxiStreamSlaveArray(SIZE_G-1 downto 0); + arpTabPos : out Slv8Array(SIZE_G-1 downto 0); + arpTabFound : in slv(SIZE_G-1 downto 0) := (others => '0'); + arpTabIpAddr : in Slv32Array(SIZE_G-1 downto 0) := (others => (others => '0')); + arpTabMacAddr : in Slv48Array(SIZE_G-1 downto 0) := (others => (others => '0')); + -- Interface to DHCP Engine + obDhcpMaster : in AxiStreamMasterType := AXI_STREAM_MASTER_INIT_C; + obDhcpSlave : out AxiStreamSlaveType; + -- Clock and Reset + clk : in sl; + rst : in sl); end UdpEngineTx; architecture rtl of UdpEngineTx is - constant PORT_C : Slv16Array(SIZE_G-1 downto 0) := EthPortArrayBigEndian(PORT_G, SIZE_G); + constant PORT_C : Slv16Array(SIZE_G-1 downto 0) := EthPortArrayBigEndian(PORT_G, SIZE_G); - type StateType is ( - IDLE_S, - ACC_ARP_TAB_S, - DHCP_HDR_S, - HDR_S, - DHCP_BUFFER_S, - BUFFER_S, - LAST_S); + type StateType is ( + IDLE_S, + ACC_ARP_TAB_S, + DHCP_HDR_S, + HDR_S, + DHCP_BUFFER_S, + BUFFER_S, + LAST_S); - type RegType is record - linkUp : slv(SIZE_G-1 downto 0); - tKeep : slv(15 downto 0); - tData : slv(127 downto 0); - tLast : sl; - eofe : sl; - chPntr : natural range 0 to SIZE_G-1; - index : natural range 0 to SIZE_G-1; - arpPos : Slv8Array(SIZE_G-1 downto 0); - obDhcpSlave : AxiStreamSlaveType; - ibSlaves : AxiStreamSlaveArray(SIZE_G-1 downto 0); - txMaster : AxiStreamMasterType; - state : StateType; - end record RegType; - constant REG_INIT_C : RegType := ( - linkUp => (others => '0'), - tKeep => (others => '0'), - tData => (others => '0'), - tLast => '0', - eofe => '0', - chPntr => 0, - index => 0, - arpPos => (others => (others => '0')), - obDhcpSlave => AXI_STREAM_SLAVE_INIT_C, - ibSlaves => (others => AXI_STREAM_SLAVE_INIT_C), - txMaster => AXI_STREAM_MASTER_INIT_C, - state => IDLE_S); + type RegType is record + linkUp : slv(SIZE_G-1 downto 0); + tKeep : slv(15 downto 0); + tData : slv(127 downto 0); + tLast : sl; + eofe : sl; + chPntr : natural range 0 to SIZE_G-1; + index : natural range 0 to SIZE_G-1; + arpPos : Slv8Array(SIZE_G-1 downto 0); + obDhcpSlave : AxiStreamSlaveType; + ibSlaves : AxiStreamSlaveArray(SIZE_G-1 downto 0); + txMaster : AxiStreamMasterType; + state : StateType; + end record RegType; + constant REG_INIT_C : RegType := ( + linkUp => (others => '0'), + tKeep => (others => '0'), + tData => (others => '0'), + tLast => '0', + eofe => '0', + chPntr => 0, + index => 0, + arpPos => (others => (others => '0')), + obDhcpSlave => AXI_STREAM_SLAVE_INIT_C, + ibSlaves => (others => AXI_STREAM_SLAVE_INIT_C), + txMaster => AXI_STREAM_MASTER_INIT_C, + state => IDLE_S); - signal r : RegType := REG_INIT_C; - signal rin : RegType; + signal r : RegType := REG_INIT_C; + signal rin : RegType; - signal txMaster : AxiStreamMasterType; - signal txSlave : AxiStreamSlaveType; + signal txMaster : AxiStreamMasterType; + signal txSlave : AxiStreamSlaveType; - -- attribute dont_touch : string; - -- attribute dont_touch of r : signal is "TRUE"; + -- attribute dont_touch : string; + -- attribute dont_touch of r : signal is "TRUE"; begin - comb : process (ibMasters, localIp, localMac, obDhcpMaster, r, remoteIp, - remoteMac, remotePort, rst, txSlave) is - variable v : RegType; - variable arpPosV : Slv8Array(SIZE_G-1 downto 0); - variable i : natural; - begin - -- Latch the current value - v := r; + comb : process (ibMasters, localIp, localMac, obDhcpMaster, r, remoteIp, + remoteMac, remotePort, rst, txSlave) is + variable v : RegType; + variable arpPosV : Slv8Array(SIZE_G-1 downto 0); + variable i : natural; + begin + -- Latch the current value + v := r; - -- Reset the flags - v.obDhcpSlave := AXI_STREAM_SLAVE_INIT_C; - v.ibSlaves := (others => AXI_STREAM_SLAVE_INIT_C); - if (txSlave.tReady = '1') then - v.txMaster.tValid := '0'; - v.txMaster.tLast := '0'; - v.txMaster.tUser := (others => '0'); - v.txMaster.tKeep := (others => '1'); - end if; + -- Reset the flags + v.obDhcpSlave := AXI_STREAM_SLAVE_INIT_C; + v.ibSlaves := (others => AXI_STREAM_SLAVE_INIT_C); + if (txSlave.tReady = '1') then + v.txMaster.tValid := '0'; + v.txMaster.tLast := '0'; + v.txMaster.tUser := (others => '0'); + v.txMaster.tKeep := (others => '1'); + end if; - for i in SIZE_G-1 downto 0 loop - -- Check if link is up - if (localMac /= 0) and -- Non-zero local MAC address + for i in SIZE_G-1 downto 0 loop + -- Check if link is up + if (localMac /= 0) and -- Non-zero local MAC address (localIp /= 0) and -- Non-zero local IP address (PORT_G(i) /= 0) and -- Non-zero local UDP port (remoteMac(i) /= 0) and -- Non-zero remote MAC address (remoteIp(i) /= 0) and -- Non-zero remote IP address (remotePort(i) /= 0) then -- Non-zero remote UDP port - -- Link Up - v.linkUp(i) := '1'; - else - -- Link down - v.linkUp(i) := '0'; - end if; - end loop; + -- Link Up + v.linkUp(i) := '1'; + else + -- Link down + v.linkUp(i) := '0'; + end if; + end loop; - -- State Machine - case r.state is - ---------------------------------------------------------------------- - when IDLE_S => - -- Check for roll over - if (r.index = (SIZE_G-1)) then - -- Reset the counter - v.index := 0; - else - -- Increment the counter - v.index := r.index + 1; - end if; - -- Check for DHCP data and remote MAC is non-zero - if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then - -- Check for SOF - if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, obDhcpMaster) = '1') then - -- Write the first header - v.txMaster.tValid := '1'; - v.txMaster.tData(47 downto 0) := (others => '1'); -- Destination MAC address - v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s - v.txMaster.tData(95 downto 64) := (others => '0'); -- Source IP address - v.txMaster.tData(127 downto 96) := (others => '1'); -- Destination IP address - ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); - -- Next state - v.state := DHCP_HDR_S; - else - -- Blow off the data - v.obDhcpSlave.tReady := '1'; - end if; - -- Check for data and remote MAC is non-zero - elsif (ibMasters(r.index).tValid = '1') and (v.txMaster.tValid = '0') then - -- Check if need to access ARP Table - if ibMasters(r.index).tDest = x"00" then - -- Check if link down and blowing off the data - if (r.linkUp(r.index) = '0') and TX_FLOW_CTRL_G then - -- Blow off the data - v.ibSlaves(r.index).tReady := '1'; - -- Check for SOF - elsif (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.index)) = '1') then - -- Check if link up - if (r.linkUp(r.index) = '1') then - -- Latch the index - v.chPntr := r.index; - -- Write the first header - v.txMaster.tValid := '1'; - v.txMaster.tData(47 downto 0) := remoteMac(r.index); -- Destination MAC address - v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s - v.txMaster.tData(95 downto 64) := localIp; -- Source IP address - v.txMaster.tData(127 downto 96) := remoteIp(r.index); -- Destination IP address - ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); - -- Next state - v.state := HDR_S; - end if; + -- State Machine + case r.state is + ---------------------------------------------------------------------- + when IDLE_S => + -- Check for roll over + if (r.index = (SIZE_G-1)) then + -- Reset the counter + v.index := 0; else - -- Blow off the data - v.ibSlaves(r.index).tReady := '1'; - end if; - else - v.chPntr := r.index; - arpPosV(r.index) := ibMasters(r.index).tDest; - v.state := ACC_ARP_TAB_S; - end if; - end if; - ----------------------------------------------------------------------- - when ACC_ARP_TAB_S => - arpPosV(r.chPntr) := ibMasters(r.chPntr).tDest; - if arpTabFound(r.chPntr) = '0' then - v.linkUp(r.chPntr) := '0'; - -- Blow off the data.. - v.ibSlaves(r.chPntr).tReady := '1'; - -- ..until the last frame - if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then - v.state := IDLE_S; - end if; - else - -- Check if link down and blowing off the data - if (r.linkUp(r.chPntr) = '0') and TX_FLOW_CTRL_G then - -- Blow off the data.. - v.ibSlaves(r.chPntr).tReady := '1'; - -- ..until the last frame - if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then - v.state := IDLE_S; + -- Increment the counter + v.index := r.index + 1; end if; - -- Check for SOF - elsif (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1') then - -- Check if link up - if (r.linkUp(r.chPntr) = '1') then - -- Latch the index - v.chPntr := r.chPntr; - -- Write the first header - v.txMaster.tValid := '1'; - v.txMaster.tData(47 downto 0) := arpTabMacAddr(r.chPntr); -- Destination MAC address - v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s - v.txMaster.tData(95 downto 64) := localIp; -- Source IP address - v.txMaster.tData(127 downto 96) := arpTabIpAddr(r.chPntr); -- Destination IP address - ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); - -- Next state - v.state := HDR_S; + -- Check for DHCP data and remote MAC is non-zero + if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then + -- Check for SOF + if (ssiGetUserSof(EMAC_AXIS_CONFIG_C, obDhcpMaster) = '1') then + -- Write the first header + v.txMaster.tValid := '1'; + v.txMaster.tData(47 downto 0) := (others => '1'); -- Destination MAC address + v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s + v.txMaster.tData(95 downto 64) := (others => '0'); -- Source IP address + v.txMaster.tData(127 downto 96) := (others => '1'); -- Destination IP address + ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); + -- Next state + v.state := DHCP_HDR_S; + else + -- Blow off the data + v.obDhcpSlave.tReady := '1'; + end if; + -- Check for data and remote MAC is non-zero + elsif (ibMasters(r.index).tValid = '1') and (v.txMaster.tValid = '0') then + -- Check if need to access ARP Table + if ibMasters(r.index).tDest = x"00" then + -- Check if link down and blowing off the data + if (r.linkUp(r.index) = '0') and TX_FLOW_CTRL_G then + -- Blow off the data + v.ibSlaves(r.index).tReady := '1'; + -- Check for SOF + elsif (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.index)) = '1') then + -- Check if link up + if (r.linkUp(r.index) = '1') then + -- Latch the index + v.chPntr := r.index; + -- Write the first header + v.txMaster.tValid := '1'; + v.txMaster.tData(47 downto 0) := remoteMac(r.index); -- Destination MAC address + v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s + v.txMaster.tData(95 downto 64) := localIp; -- Source IP address + v.txMaster.tData(127 downto 96) := remoteIp(r.index); -- Destination IP address + ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); + -- Next state + v.state := HDR_S; + end if; + else + -- Blow off the data + v.ibSlaves(r.index).tReady := '1'; + end if; + else + v.chPntr := r.index; + arpPosV(r.index) := ibMasters(r.index).tDest; + v.state := ACC_ARP_TAB_S; + end if; end if; - else - -- Blow off the data.. - v.ibSlaves(r.chPntr).tReady := '1'; - -- ..until the last frame - if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then - v.state := IDLE_S; + ----------------------------------------------------------------------- + when ACC_ARP_TAB_S => + arpPosV(r.chPntr) := ibMasters(r.chPntr).tDest; + if arpTabFound(r.chPntr) = '0' then + v.linkUp(r.chPntr) := '0'; + -- Blow off the data.. + v.ibSlaves(r.chPntr).tReady := '1'; + -- ..until the last frame + if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then + v.state := IDLE_S; + end if; + else + -- Check if link down and blowing off the data + if (r.linkUp(r.chPntr) = '0') and TX_FLOW_CTRL_G then + -- Blow off the data.. + v.ibSlaves(r.chPntr).tReady := '1'; + -- ..until the last frame + if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then + v.state := IDLE_S; + end if; + -- Check for SOF + elsif (ssiGetUserSof(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1') then + -- Check if link up + if (r.linkUp(r.chPntr) = '1') then + -- Latch the index + v.chPntr := r.chPntr; + -- Write the first header + v.txMaster.tValid := '1'; + v.txMaster.tData(47 downto 0) := arpTabMacAddr(r.chPntr); -- Destination MAC address + v.txMaster.tData(63 downto 48) := x"0000"; -- All 0s + v.txMaster.tData(95 downto 64) := localIp; -- Source IP address + v.txMaster.tData(127 downto 96) := arpTabIpAddr(r.chPntr); -- Destination IP address + ssiSetUserSof(EMAC_AXIS_CONFIG_C, v.txMaster, '1'); + -- Next state + v.state := HDR_S; + end if; + else + -- Blow off the data.. + v.ibSlaves(r.chPntr).tReady := '1'; + -- ..until the last frame + if (ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)) = '1' or ibMasters(r.chPntr).tLast = '1') then + v.state := IDLE_S; + end if; + end if; end if; - end if; - end if; - ------------------------------------------------ - -- Notes: Non-Standard IPv4 Pseudo Header Format - ------------------------------------------------ - -- tData[0][47:0] = DST MAC Address - -- tData[0][63:48] = zeros - -- tData[0][95:64] = SRC IP Address - -- tData[0][127:96] = DST IP address - -- tData[1][7:0] = zeros - -- tData[1][15:8] = Protocol Type = UDP - -- tData[1][31:16] = IPv4 Pseudo header length - -- tData[1][47:32] = SRC Port - -- tData[1][63:48] = DST Port - -- tData[1][79:64] = UDP Length - -- tData[1][95:80] = UDP Checksum - -- tData[1][127:96] = UDP Datagram - ------------------------------------------------ - ---------------------------------------------------------------------- - when DHCP_HDR_S => - -- Check if ready to move data - if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.obDhcpSlave.tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - v.txMaster.tData(7 downto 0) := x"00"; -- All 0s - v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP - v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core - v.txMaster.tData(47 downto 32) := DHCP_CPORT; -- Source port - v.txMaster.tData(63 downto 48) := DHCP_SPORT; -- Destination port - v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core - v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core - v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); -- UDP Datagram - v.txMaster.tKeep(11 downto 0) := x"FFF"; - v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); -- UDP Datagram - -- Track the leftovers - v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); - v.tData(127 downto 96) := (others => '0'); - v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); - v.tKeep(15 downto 12) := (others => '0'); - v.tLast := obDhcpMaster.tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; + ------------------------------------------------ + -- Notes: Non-Standard IPv4 Pseudo Header Format + ------------------------------------------------ + -- tData[0][47:0] = DST MAC Address + -- tData[0][63:48] = zeros + -- tData[0][95:64] = SRC IP Address + -- tData[0][127:96] = DST IP address + -- tData[1][7:0] = zeros + -- tData[1][15:8] = Protocol Type = UDP + -- tData[1][31:16] = IPv4 Pseudo header length + -- tData[1][47:32] = SRC Port + -- tData[1][63:48] = DST Port + -- tData[1][79:64] = UDP Length + -- tData[1][95:80] = UDP Checksum + -- tData[1][127:96] = UDP Datagram + ------------------------------------------------ + ---------------------------------------------------------------------- + when DHCP_HDR_S => + -- Check if ready to move data + if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.obDhcpSlave.tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + v.txMaster.tData(7 downto 0) := x"00"; -- All 0s + v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP + v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core + v.txMaster.tData(47 downto 32) := DHCP_CPORT; -- Source port + v.txMaster.tData(63 downto 48) := DHCP_SPORT; -- Destination port + v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core + v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core + v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); -- UDP Datagram + v.txMaster.tKeep(11 downto 0) := x"FFF"; + v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); -- UDP Datagram + -- Track the leftovers + v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); + v.tData(127 downto 96) := (others => '0'); + v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); + v.tKeep(15 downto 12) := (others => '0'); + v.tLast := obDhcpMaster.tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; + end if; + else + -- Next state + v.state := DHCP_BUFFER_S; + end if; end if; - else - -- Next state - v.state := DHCP_BUFFER_S; - end if; - end if; - ---------------------------------------------------------------------- - when HDR_S => - -- Check if ready to move data - if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.ibSlaves(r.chPntr).tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - v.txMaster.tData(7 downto 0) := x"00"; -- All 0s - v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP - v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core - v.txMaster.tData(47 downto 32) := PORT_C(r.chPntr); -- Source port - v.txMaster.tData(63 downto 48) := remotePort(r.chPntr); -- Destination port - v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core - v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core - v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); -- UDP Datagram - v.txMaster.tKeep(11 downto 0) := x"FFF"; - v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); -- UDP Datagram - -- Track the leftovers - v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); - v.tData(127 downto 96) := (others => '0'); - v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); - v.tKeep(15 downto 12) := (others => '0'); - v.tLast := ibMasters(r.chPntr).tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; + ---------------------------------------------------------------------- + when HDR_S => + -- Check if ready to move data + if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.ibSlaves(r.chPntr).tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + v.txMaster.tData(7 downto 0) := x"00"; -- All 0s + v.txMaster.tData(15 downto 8) := UDP_C; -- Protocol Type = UDP + v.txMaster.tData(31 downto 16) := x"0000"; -- IPv4 Pseudo header length = Calculated in EthMac core + v.txMaster.tData(47 downto 32) := PORT_C(r.chPntr); -- Source port + v.txMaster.tData(63 downto 48) := remotePort(r.chPntr); -- Destination port + v.txMaster.tData(79 downto 64) := x"0000"; -- UDP length = Calculated in EthMac core + v.txMaster.tData(95 downto 80) := x"0000"; -- UDP checksum = Calculated in EthMac core + v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); -- UDP Datagram + v.txMaster.tKeep(11 downto 0) := x"FFF"; + v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); -- UDP Datagram + -- Track the leftovers + v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); + v.tData(127 downto 96) := (others => '0'); + v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); + v.tKeep(15 downto 12) := (others => '0'); + v.tLast := ibMasters(r.chPntr).tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; + end if; + else + -- Next state + v.state := BUFFER_S; + end if; end if; - else - -- Next state - v.state := BUFFER_S; - end if; - end if; - ---------------------------------------------------------------------- - when DHCP_BUFFER_S => - -- Check if ready to move data - if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.obDhcpSlave.tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - -- Move the data - v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); - v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); - v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); - v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); - -- Track the leftovers - v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); - v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); - v.tLast := obDhcpMaster.tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; + ---------------------------------------------------------------------- + when DHCP_BUFFER_S => + -- Check if ready to move data + if (obDhcpMaster.tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.obDhcpSlave.tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + -- Move the data + v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); + v.txMaster.tData(127 downto 96) := obDhcpMaster.tData(31 downto 0); + v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); + v.txMaster.tKeep(15 downto 12) := obDhcpMaster.tKeep(3 downto 0); + -- Track the leftovers + v.tData(95 downto 0) := obDhcpMaster.tData(127 downto 32); + v.tKeep(11 downto 0) := obDhcpMaster.tKeep(15 downto 4); + v.tLast := obDhcpMaster.tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, obDhcpMaster); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; + end if; + end if; end if; - end if; - end if; - ---------------------------------------------------------------------- - when BUFFER_S => - -- Check if ready to move data - if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then - -- Accept the data - v.ibSlaves(r.chPntr).tReady := '1'; - -- Write the Second header - v.txMaster.tValid := '1'; - -- Move the data - v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); - v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); - v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); - v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); - -- Track the leftovers - v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); - v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); - v.tLast := ibMasters(r.chPntr).tLast; - v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); - -- Check for tLast - if (v.tLast = '1') then - -- Check the leftover tKeep is not empty - if (v.tKeep /= 0) then - -- Next state - v.state := LAST_S; - else - -- Set EOF and EOFE - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); - -- Next state - v.state := IDLE_S; + ---------------------------------------------------------------------- + when BUFFER_S => + -- Check if ready to move data + if (ibMasters(r.chPntr).tValid = '1') and (v.txMaster.tValid = '0') then + -- Accept the data + v.ibSlaves(r.chPntr).tReady := '1'; + -- Write the Second header + v.txMaster.tValid := '1'; + -- Move the data + v.txMaster.tData(95 downto 0) := r.tData(95 downto 0); + v.txMaster.tData(127 downto 96) := ibMasters(r.chPntr).tData(31 downto 0); + v.txMaster.tKeep(11 downto 0) := r.tKeep(11 downto 0); + v.txMaster.tKeep(15 downto 12) := ibMasters(r.chPntr).tKeep(3 downto 0); + -- Track the leftovers + v.tData(95 downto 0) := ibMasters(r.chPntr).tData(127 downto 32); + v.tKeep(11 downto 0) := ibMasters(r.chPntr).tKeep(15 downto 4); + v.tLast := ibMasters(r.chPntr).tLast; + v.eofe := ssiGetUserEofe(EMAC_AXIS_CONFIG_C, ibMasters(r.chPntr)); + -- Check for tLast + if (v.tLast = '1') then + -- Check the leftover tKeep is not empty + if (v.tKeep /= 0) then + -- Next state + v.state := LAST_S; + else + -- Set EOF and EOFE + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, v.eofe); + -- Next state + v.state := IDLE_S; + end if; + end if; + end if; + ---------------------------------------------------------------------- + when LAST_S => + -- Check if ready to move data + if (v.txMaster.tValid = '0') then + -- Move the data + v.txMaster.tValid := '1'; + v.txMaster.tData(127 downto 0) := r.tData; + v.txMaster.tKeep(15 downto 0) := r.tKeep; + v.txMaster.tLast := '1'; + ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, r.eofe); + -- Next state + v.state := IDLE_S; end if; - end if; - end if; ---------------------------------------------------------------------- - when LAST_S => - -- Check if ready to move data - if (v.txMaster.tValid = '0') then - -- Move the data - v.txMaster.tValid := '1'; - v.txMaster.tData(127 downto 0) := r.tData; - v.txMaster.tKeep(15 downto 0) := r.tKeep; - v.txMaster.tLast := '1'; - ssiSetUserEofe(EMAC_AXIS_CONFIG_C, v.txMaster, r.eofe); - -- Next state - v.state := IDLE_S; - end if; - ---------------------------------------------------------------------- - end case; + end case; - -- Outputs - ibSlaves <= v.ibSlaves; - obDhcpSlave <= v.obDhcpSlave; - txMaster <= r.txMaster; - linkUp <= r.linkUp; - arpTabPos <= arpPosV; + -- Outputs + ibSlaves <= v.ibSlaves; + obDhcpSlave <= v.obDhcpSlave; + txMaster <= r.txMaster; + linkUp <= r.linkUp; + arpTabPos <= arpPosV; - -- Reset - if (rst = '1') then - v := REG_INIT_C; - end if; + -- Reset + if (rst = '1') then + v := REG_INIT_C; + end if; - -- Register the variable for next clock cycle - rin <= v; + -- Register the variable for next clock cycle + rin <= v; - end process comb; + end process comb; - seq : process (clk) is - begin - if rising_edge(clk) then - r <= rin after TPD_G; - end if; - end process seq; + seq : process (clk) is + begin + if rising_edge(clk) then + r <= rin after TPD_G; + end if; + end process seq; - U_TxPipeline : entity surf.AxiStreamPipeline - generic map ( - TPD_G => TPD_G, - PIPE_STAGES_G => 1) - port map ( - axisClk => clk, - axisRst => rst, - sAxisMaster => txMaster, - sAxisSlave => txSlave, - mAxisMaster => obUdpMaster, - mAxisSlave => obUdpSlave); + U_TxPipeline : entity surf.AxiStreamPipeline + generic map ( + TPD_G => TPD_G, + PIPE_STAGES_G => 1) + port map ( + axisClk => clk, + axisRst => rst, + sAxisMaster => txMaster, + sAxisSlave => txSlave, + mAxisMaster => obUdpMaster, + mAxisSlave => obUdpSlave); end rtl; From 9bf72f5b7002c8d814135457e491f8b684a22bf4 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Thu, 26 Sep 2024 10:11:12 +0200 Subject: [PATCH 07/15] added coding header --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 974125c5d5..7ce00463c6 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -1,3 +1,17 @@ +------------------------------------------------------------------------------- +-- Company : SLAC National Accelerator Laboratory +------------------------------------------------------------------------------- +-- Description: Top-Level UDP/DHCP Module +------------------------------------------------------------------------------- +-- This file is part of 'SLAC Firmware Standard Library'. +-- It is subject to the license terms in the LICENSE.txt file found in the +-- top-level directory of this distribution and at: +-- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html. +-- No part of 'SLAC Firmware Standard Library', including this file, +-- may be copied, modified, propagated, or distributed except according to +-- the terms contained in the LICENSE.txt file. +------------------------------------------------------------------------------- + library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; From 8eca41056b3ac82af25c973a02e1ee22d9a7fc13 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Wed, 2 Oct 2024 13:49:27 +0200 Subject: [PATCH 08/15] base code to add expiration --- ethernet/UdpEngine/rtl/UdpEngineArp.vhd | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd index aaf8baa1ce..06e7a72324 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd @@ -133,11 +133,7 @@ begin v.respTimers(i) := r.respTimers(i) - 1; end if; - -- Update the IP address - v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); - -- Check for dynamic change in IP address - -- if (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) or (clientRemoteIp(i) = 0) then if (clientRemoteIp(i) = 0) then -- Stop any outstanding requests v.arpReqMasters(i).tValid := '0'; @@ -146,6 +142,8 @@ begin -- Next state v.state(i) := IDLE_S; elsif (r.arpReqMasters(i).tData(31 downto 0) /= clientRemoteIp(i)) then + -- Update the IP address + v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); -- Stop any outstanding requests v.arpReqMasters(i).tValid := '0'; -- Reset the remote MAC address From d0034c322828b68e37f970d259b4e9e6b134fbc5 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Thu, 3 Oct 2024 13:18:33 +0200 Subject: [PATCH 09/15] basic expire table added --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 213 ++++++++++++++++++++++++-- 1 file changed, 196 insertions(+), 17 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 7ce00463c6..800bfa0a36 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -24,44 +24,95 @@ use surf.StdRtlPkg.all; entity ArpIpTable is generic ( - TPD_G : time := 1 ns; - ENTRIES_G : positive range 1 to 255 := 4); + TPD_G : time := 1 ns; + CLK_FREQ_G : real := 156.25E+06; + -- COMM_TIMEOUT_G : positive := 30; + COMM_TIMEOUT_G : positive := 3; + ENTRIES_G : positive range 1 to 255 := 4); port ( -- Clock and Reset - clk : in sl; - rst : in sl; + clk : in sl; + rst : in sl; -- Read LUT - ipAddrIn : in slv(31 downto 0); - pos : in slv(7 downto 0); - found : out sl; - macAddr : out slv(47 downto 0); - ipAddrOut : out slv(31 downto 0); + ipAddrIn : in slv(31 downto 0); + pos : in slv(7 downto 0); + found : out sl; + macAddr : out slv(47 downto 0); + ipAddrOut : out slv(31 downto 0); + -- Refresh LUT + clientRemoteDetIp : in slv(31 downto 0) := (others => '0'); + clientRemoteDetValid : in sl := '0'; -- Write LUT - ipWrEn : in sl; - IpWrAddr : in slv(31 downto 0); - macWrEn : in sl; - macWrAddr : in slv(47 downto 0)); + ipWrEn : in sl; + IpWrAddr : in slv(31 downto 0); + macWrEn : in sl; + macWrAddr : in slv(47 downto 0)); end entity ArpIpTable; architecture rtl of ArpIpTable is + -- Write stuff type wRegType is record ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); macLutTable : Slv48Array(ENTRIES_G-1 downto 0); + fifoRdEn : sl; entryCount : slv(7 downto 0); end record wRegType; constant W_REG_INIT_C : wRegType := ( ipLutTable => (others => (others => '0')), macLutTable => (others => (others => '0')), + fifoRdEn => '0', entryCount => (others => '0') ); signal wR : wRegType := W_REG_INIT_C; signal wRin : wRegType; + -- Read Stuff signal matchArray : slv(ENTRIES_G-1 downto 0); + -- Expire stuff + -- constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); + constant TIMER_1_SEC_C : natural := 100; + type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; + type ExpStateType is ( + IDLE_S, + MONITOR_S, + EXPIRE_S + ); + type ExpStateArray is array (natural range <>) of ExpStateType; + + type eRegType is record + timerEn : sl; + state : ExpStateArray(ENTRIES_G-1 downto 0); + timer : natural range 0 to (TIMER_1_SEC_C-1); + arpTimers : TimerArray(ENTRIES_G-1 downto 0); + arbRequest : slv(ENTRIES_G-1 downto 0); + end record eRegType; + + constant E_REG_INIT_C : eRegType := + ( + timerEn => '0', + state => (others => IDLE_S), + timer => 0, + arpTimers => (others => 0), + arbRequest => (others => '0') + ); + + signal eR : eRegType := E_REG_INIT_C; + signal eRin : eRegType; + + -- Arbiter + signal arbSelected : slv(bitSize(ENTRIES_G-1)-1 downto 0); + signal arbSelectedResized : slv(7 downto 0); + signal arbValid : sl; + + -- FIFO + signal fifoData : slv(7 downto 0); + signal fifoValid : sl; + signal fifoEmpty : sl; + begin -- architecture rtl -- Write process comb @@ -88,11 +139,20 @@ begin -- architecture rtl end if; -- Update write LUT pointer - if wr.entryCount < ENTRIES_G - 1 then - v.entryCount := wr.entryCount + 1; + if fifoEmpty = '0' then + v.fifoRdEn := '1'; + if fifoValid = '1' then + v.entryCount := fifoData; + v.fifoRdEn := '0'; + end if; else - v.entryCount := (others => '0'); + if wr.entryCount < ENTRIES_G - 1 then + v.entryCount := wr.entryCount + 1; + else + v.entryCount := (others => '0'); + end if; end if; + end if; -- Reset @@ -133,7 +193,7 @@ begin -- architecture rtl if posI < ENTRIES_G then foundMacAddr := wr.macLutTable(posI); foundIpAddr := wr.ipLutTable(posI); - if foundMacAddr = x"000000000000" or foundIpAddr = x"00000000" then + if uOr(foundMacAddr) = '0' or uOr(foundIpAddr) = '0' then ipFound := '0'; else ipFound := '1'; @@ -158,4 +218,123 @@ begin -- architecture rtl ipAddrOut <= foundIpAddr; end process; + -- Expiration process + expComb : process (arbSelected, arbValid, clientRemoteDetIp, + clientRemoteDetValid, eR, rst, wR) is + variable v : eRegType; + begin -- process expComb + -- Latch the current value + v := eR; + + -- Reset the flags + v.timerEn := '0'; + + -- Increment the timer + if eR.timer = (TIMER_1_SEC_C-1) then + v.timer := 0; + v.timerEn := '1'; + else + v.timer := eR.timer + 1; + end if; + + -- Loop through the entries + for i in 0 to ENTRIES_G-1 loop + + -- Update the timers + if (eR.timerEn = '1') and (eR.arpTimers(i) /= 0) then + -- Decrement the timers + v.arpTimers(i) := eR.arpTimers(i) - 1; + end if; + + case eR.state(i) is + ------------------------------------------------------------------- + when IDLE_S => + if (uOr(wR.ipLutTable(i)) /= '0' and uOr(wR.macLutTable(i)) /= '0') then + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + -- Next state + v.state(i) := MONITOR_S; + end if; + ---------------------------------------------------------------- + when MONITOR_S => + if clientRemoteDetValid = '1' and clientRemoteDetIp = wR.ipLutTable(i) then + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; + elsif eR.arpTimers(i) = 0 then + -- Next state + v.state(i) := EXPIRE_S; + end if; + ---------------------------------------------------------------- + when EXPIRE_S => + -- Raise hand + v.arbRequest(i) := '1'; + if arbSelected = i and arbValid = '1' then + -- Lower hand + v.arbRequest(i) := '0'; + -- Next state + v.state(i) := IDLE_S; + end if; + ---------------------------------------------------------------- + when others => + -- Fallback on idle state + v.state(i) := IDLE_S; + ---------------------------------------------------------------- + end case; + + end loop; -- i + + -- Reset + if (rst = '1') then + v := E_REG_INIT_C; + end if; + + -- Register the variable for next clock cycle + eRin <= v; + + end process expComb; + + expSeq : process (clk) is + begin + if rising_edge(clk) then + eR <= eRin after TPD_G; + end if; + end process expSeq; + + -- Arbiter + U_Arbiter : entity surf.Arbiter + generic map ( + TPD_G => TPD_G, + REQ_SIZE_G => ENTRIES_G) + port map ( + clk => clk, + rst => rst, + req => eR.arbRequest, + selected => arbSelected, + valid => arbValid, + ack => open); + + arbSelectedResized <= resize(arbSelected, 8); + + -- Empty spaces FIFO + U_ExpFifo : entity surf.Fifo + generic map ( + TPD_G => TPD_G, + GEN_SYNC_FIFO_G => true, + FWFT_EN_G => false, + DATA_WIDTH_G => 8, + ADDR_WIDTH_G => 8) + port map ( + rst => rst, + -- Write ports + wr_clk => clk, + wr_en => arbValid, + din => arbSelectedResized, + wr_ack => open, + -- Read ports + rd_clk => clk, + rd_en => wR.fifoRdEn, + dout => fifoData, + valid => fifoValid, + empty => fifoEmpty); + end architecture rtl; From 9082ea3592ea9ee934a8463cf6ce6caa8dbbfb83 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Fri, 4 Oct 2024 14:32:54 +0200 Subject: [PATCH 10/15] arpIpTable with expiration entries --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 54 ++++++++++++++++++--------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 800bfa0a36..24e8508fbf 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -26,8 +26,8 @@ entity ArpIpTable is generic ( TPD_G : time := 1 ns; CLK_FREQ_G : real := 156.25E+06; - -- COMM_TIMEOUT_G : positive := 30; - COMM_TIMEOUT_G : positive := 3; + COMM_TIMEOUT_G : positive := 30; + -- COMM_TIMEOUT_G : positive := 3; ENTRIES_G : positive range 1 to 255 := 4); port ( -- Clock and Reset @@ -56,6 +56,7 @@ architecture rtl of ArpIpTable is ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); macLutTable : Slv48Array(ENTRIES_G-1 downto 0); fifoRdEn : sl; + overwrite : boolean; entryCount : slv(7 downto 0); end record wRegType; @@ -63,6 +64,7 @@ architecture rtl of ArpIpTable is ipLutTable => (others => (others => '0')), macLutTable => (others => (others => '0')), fifoRdEn => '0', + overwrite => false, entryCount => (others => '0') ); @@ -73,8 +75,8 @@ architecture rtl of ArpIpTable is signal matchArray : slv(ENTRIES_G-1 downto 0); -- Expire stuff - -- constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); - constant TIMER_1_SEC_C : natural := 100; + constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); + -- constant TIMER_1_SEC_C : natural := 100; type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; type ExpStateType is ( IDLE_S, @@ -116,17 +118,25 @@ architecture rtl of ArpIpTable is begin -- architecture rtl -- Write process comb - wrComb : process (ipWrAddr, ipWrEn, macWrAddr, macWrEn, rst, wR) is + wrComb : process (arbSelected, arbValid, fifoData, fifoEmpty, fifoValid, + ipWrAddr, ipWrEn, macWrAddr, macWrEn, rst, wR) is variable v : wRegType; variable wrAddInt : integer; begin -- Latch the current value v := wR; + -- Update flags + v.overwrite := false; + -- Write IP to LUT - if ipWrEn = '1' then + if ipWrEn = '1' or wR.overwrite then wrAddInt := conv_integer(wR.entryCount); - if wrAddInt < ENTRIES_G then + if fifoEmpty = '0' then + v.fifoRdEn := '1'; + v.overwrite := true; + end if; + if wrAddInt < ENTRIES_G and (not v.overwrite) then v.ipLutTable(wrAddInt) := ipWrAddr; end if; end if; @@ -139,20 +149,24 @@ begin -- architecture rtl end if; -- Update write LUT pointer - if fifoEmpty = '0' then - v.fifoRdEn := '1'; - if fifoValid = '1' then - v.entryCount := fifoData; - v.fifoRdEn := '0'; - end if; + if wr.entryCount < ENTRIES_G - 1 then + v.entryCount := wr.entryCount + 1; else - if wr.entryCount < ENTRIES_G - 1 then - v.entryCount := wr.entryCount + 1; - else - v.entryCount := (others => '0'); - end if; + v.entryCount := (others => '0'); end if; + end if; + + -- Overwrite LUT pointer if there are empty spaces + if fifoValid = '1' then + v.entryCount := fifoData; + v.fifoRdEn := '0'; + end if; + -- Remove entry from LUT + if arbValid = '1' then + wrAddInt := conv_integer(arbSelected); + v.macLutTable(wrAddInt) := (others => '0'); + v.ipLutTable(wrAddInt) := (others => '0'); end if; -- Reset @@ -264,6 +278,10 @@ begin -- architecture rtl -- Next state v.state(i) := EXPIRE_S; end if; + if (uOr(wR.ipLutTable(i)) = '0' and uOr(wR.macLutTable(i)) = '0') then + -- Next state + v.state(i) := IDLE_S; + end if; ---------------------------------------------------------------- when EXPIRE_S => -- Raise hand From 3d6b71f4cd4839c49e4a92f5e0c27968b5b33732 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Fri, 4 Oct 2024 15:21:49 +0200 Subject: [PATCH 11/15] first version of multi-arp with expiring entries --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 6 +- ethernet/UdpEngine/rtl/UdpEngine.vhd | 105 +++++++++++--------- ethernet/UdpEngine/rtl/UdpEngineArp.vhd | 43 ++++---- ethernet/UdpEngine/rtl/UdpEngineRx.vhd | 127 ++++++++++++------------ 4 files changed, 149 insertions(+), 132 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 24e8508fbf..237b163601 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -27,7 +27,6 @@ entity ArpIpTable is TPD_G : time := 1 ns; CLK_FREQ_G : real := 156.25E+06; COMM_TIMEOUT_G : positive := 30; - -- COMM_TIMEOUT_G : positive := 3; ENTRIES_G : positive range 1 to 255 := 4); port ( -- Clock and Reset @@ -40,8 +39,8 @@ entity ArpIpTable is macAddr : out slv(47 downto 0); ipAddrOut : out slv(31 downto 0); -- Refresh LUT - clientRemoteDetIp : in slv(31 downto 0) := (others => '0'); - clientRemoteDetValid : in sl := '0'; + clientRemoteDetIp : in slv(31 downto 0); + clientRemoteDetValid : in sl; -- Write LUT ipWrEn : in sl; IpWrAddr : in slv(31 downto 0); @@ -76,7 +75,6 @@ architecture rtl of ArpIpTable is -- Expire stuff constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); - -- constant TIMER_1_SEC_C : natural := 100; type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; type ExpStateType is ( IDLE_S, diff --git a/ethernet/UdpEngine/rtl/UdpEngine.vhd b/ethernet/UdpEngine/rtl/UdpEngine.vhd index c6325b63f3..b9793ff74b 100644 --- a/ethernet/UdpEngine/rtl/UdpEngine.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngine.vhd @@ -78,8 +78,9 @@ end UdpEngine; architecture mapping of UdpEngine is - signal clientRemoteDet : slv(CLIENT_SIZE_G-1 downto 0); - signal clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); + signal clientRemoteDetValid : slv(CLIENT_SIZE_G-1 downto 0); + signal clientRemoteDetIp : Slv32Array(CLIENT_SIZE_G-1 downto 0); + signal clientRemoteMac : Slv48Array(CLIENT_SIZE_G-1 downto 0); signal remotePort : Slv16Array(SERVER_SIZE_G-1 downto 0); signal remoteIp : Slv32Array(SERVER_SIZE_G-1 downto 0); @@ -127,28 +128,29 @@ begin CLIENT_PORTS_G => CLIENT_PORTS_G) port map ( -- Local Configurations - localIp => localIp, - broadcastIp => broadcastIp, - igmpIp => igmpIp, + localIp => localIp, + broadcastIp => broadcastIp, + igmpIp => igmpIp, -- Interface to IPV4 Engine - ibUdpMaster => ibUdpMaster, - ibUdpSlave => ibUdpSlave, + ibUdpMaster => ibUdpMaster, + ibUdpSlave => ibUdpSlave, -- Interface to UDP Server engine(s) - serverRemotePort => remotePort, - serverRemoteIp => remoteIp, - serverRemoteMac => serverRemoteMac, - obServerMasters => obServerMasters, - obServerSlaves => obServerSlaves, + serverRemotePort => remotePort, + serverRemoteIp => remoteIp, + serverRemoteMac => serverRemoteMac, + obServerMasters => obServerMasters, + obServerSlaves => obServerSlaves, -- Interface to UDP Client engine(s) - clientRemoteDet => clientRemoteDet, - obClientMasters => obClientMasters, - obClientSlaves => obClientSlaves, + clientRemoteDetValid => clientRemoteDetValid, + clientRemoteDetIp => clientRemoteDetIp, + obClientMasters => obClientMasters, + obClientSlaves => obClientSlaves, -- Interface to DHCP Engine - ibDhcpMaster => ibDhcpMaster, - ibDhcpSlave => ibDhcpSlave, + ibDhcpMaster => ibDhcpMaster, + ibDhcpSlave => ibDhcpSlave, -- Clock and Reset - clk => clk, - rst => rst); + clk => clk, + rst => rst); GEN_DHCP : if (DHCP_G = true) generate @@ -218,20 +220,28 @@ begin GEN_ARP_TABLES : for i in 0 to CLIENT_SIZE_G-1 generate ArpIpTable_1 : entity surf.ArpIpTable generic map ( - TPD_G => TPD_G, - ENTRIES_G => ARP_TAB_ENTRIES_G) + TPD_G => TPD_G, + CLK_FREQ_G => CLK_FREQ_G, + COMM_TIMEOUT_G => COMM_TIMEOUT_G, + ENTRIES_G => ARP_TAB_ENTRIES_G) port map ( - clk => clk, - rst => rst, - ipAddrIn => clientRemoteIp(i), - pos => arpTabPos(i), - found => arpTabFound(i), - macAddr => arpTabMacAddr(i), - ipAddrOut => arpTabIpAddr(i), - ipWrEn => arpTabIpWe(i), - IpWrAddr => clientRemoteIp(i), - macWrEn => arpTabMacWe(i), - macWrAddr => arpTabMacAddrW(i)); + -- Clock and Reset + clk => clk, + rst => rst, + -- Read LUT + ipAddrIn => clientRemoteIp(i), + pos => arpTabPos(i), + found => arpTabFound(i), + macAddr => arpTabMacAddr(i), + ipAddrOut => arpTabIpAddr(i), + -- Refresh LUT + clientRemoteDetValid => clientRemoteDetValid(i), + clientRemoteDetIp => clientRemoteDetIp(i), + -- Write LUT + ipWrEn => arpTabIpWe(i), + IpWrAddr => clientRemoteIp(i), + macWrEn => arpTabMacWe(i), + macWrAddr => arpTabMacAddrW(i)); end generate GEN_ARP_TABLES; U_UdpEngineArp : entity surf.UdpEngineArp @@ -242,25 +252,26 @@ begin COMM_TIMEOUT_G => COMM_TIMEOUT_G) port map ( -- Local Configurations - localIp => localIp, + localIp => localIp, -- Interface to ARP Engine - arpReqMasters => arpReqMasters, - arpReqSlaves => arpReqSlaves, - arpAckMasters => arpAckMasters, - arpAckSlaves => arpAckSlaves, + arpReqMasters => arpReqMasters, + arpReqSlaves => arpReqSlaves, + arpAckMasters => arpAckMasters, + arpAckSlaves => arpAckSlaves, -- Interface to ARP Table - arpTabFound => arpTabFound, - arpTabMacAddr => arpTabMacAddr, - arpTabIpWe => arpTabIpWe, - arpTabMacWe => arpTabMacWe, - arpTabMacAddrW => arpTabMacAddrW, + arpTabFound => arpTabFound, + arpTabMacAddr => arpTabMacAddr, + arpTabIpWe => arpTabIpWe, + arpTabMacWe => arpTabMacWe, + arpTabMacAddrW => arpTabMacAddrW, -- Interface to UDP Client engine(s) - clientRemoteDet => clientRemoteDet, - clientRemoteIp => clientRemoteIp, - clientRemoteMac => clientRemoteMac, + clientRemoteDetValid => clientRemoteDetValid, + clientRemoteDetIp => clientRemoteDetIp, + clientRemoteIp => clientRemoteIp, + clientRemoteMac => clientRemoteMac, -- Clock and Reset - clk => clk, - rst => rst); + clk => clk, + rst => rst); U_UdpEngineTx : entity surf.UdpEngineTx generic map ( diff --git a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd index 06e7a72324..85dd7c77f5 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineArp.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineArp.vhd @@ -31,25 +31,26 @@ entity UdpEngineArp is RESP_TIMEOUT_G : positive := 5); port ( -- Local Configurations - localIp : in slv(31 downto 0); -- big-Endian configuration + localIp : in slv(31 downto 0); -- big-Endian configuration -- Interface to ARP Engine - arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address - arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); - arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address - arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpReqMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Request via IP address + arpReqSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + arpAckMasters : in AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); -- Respond with MAC address + arpAckSlaves : out AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); -- Interface to ARP Table - arpTabFound : in slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacAddr : in Slv48Array(CLIENT_SIZE_G-1 downto 0); - arpTabIpWe : out slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacWe : out slv(CLIENT_SIZE_G-1 downto 0); - arpTabMacAddrW : out Slv48Array(CLIENT_SIZE_G-1 downto 0); + arpTabFound : in slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddr : in Slv48Array(CLIENT_SIZE_G-1 downto 0); + arpTabIpWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacWe : out slv(CLIENT_SIZE_G-1 downto 0); + arpTabMacAddrW : out Slv48Array(CLIENT_SIZE_G-1 downto 0); -- Interface to UDP Client engine(s) - clientRemoteDet : in slv(CLIENT_SIZE_G-1 downto 0); - clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); - clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteDetValid : in slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteDetIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteIp : in Slv32Array(CLIENT_SIZE_G-1 downto 0); + clientRemoteMac : out Slv48Array(CLIENT_SIZE_G-1 downto 0); -- Clock and Reset - clk : in sl; - rst : in sl); + clk : in sl; + rst : in sl); end UdpEngineArp; architecture rtl of UdpEngineArp is @@ -93,7 +94,9 @@ architecture rtl of UdpEngineArp is begin - comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, clientRemoteDet, clientRemoteIp, r, rst) is + comb : process (arpAckMasters, arpReqSlaves, arpTabFound, arpTabMacAddr, + clientRemoteDetIp, clientRemoteDetValid, clientRemoteIp, r, + rst) is variable v : RegType; variable i : natural; begin @@ -145,11 +148,11 @@ begin -- Update the IP address v.arpReqMasters(i).tData(31 downto 0) := clientRemoteIp(i); -- Stop any outstanding requests - v.arpReqMasters(i).tValid := '0'; + v.arpReqMasters(i).tValid := '0'; -- Reset the remote MAC address - v.clientRemoteMac(i) := (others => '0'); + v.clientRemoteMac(i) := (others => '0'); -- Next state - v.state(i) := CHECK_S; + v.state(i) := CHECK_S; else -- State Machine case r.state(i) is @@ -203,7 +206,7 @@ begin ---------------------------------------------------------------------- when COMM_MONITOR_S => -- Check for inbound client communication - if clientRemoteDet(i) = '1' then + if clientRemoteDetValid(i) = '1' and clientRemoteDetIp(i) = clientRemoteIp(i) then -- Preset the timer v.arpTimers(i) := COMM_TIMEOUT_G; elsif r.arpTimers(i) = 0 then diff --git a/ethernet/UdpEngine/rtl/UdpEngineRx.vhd b/ethernet/UdpEngine/rtl/UdpEngineRx.vhd index fc5269c60b..d63a40c0ca 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineRx.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineRx.vhd @@ -42,28 +42,29 @@ entity UdpEngineRx is CLIENT_PORTS_G : PositiveArray := (0 => 8193)); port ( -- Local Configurations - localIp : in slv(31 downto 0); -- big-Endian configuration - broadcastIp : in slv(31 downto 0); -- big-Endian configuration - igmpIp : in Slv32Array(IGMP_GRP_SIZE-1 downto 0); -- big-Endian configuration + localIp : in slv(31 downto 0); -- big-Endian configuration + broadcastIp : in slv(31 downto 0); -- big-Endian configuration + igmpIp : in Slv32Array(IGMP_GRP_SIZE-1 downto 0); -- big-Endian configuration -- Interface to IPV4 Engine - ibUdpMaster : in AxiStreamMasterType; - ibUdpSlave : out AxiStreamSlaveType; + ibUdpMaster : in AxiStreamMasterType; + ibUdpSlave : out AxiStreamSlaveType; -- Interface to UDP Server engine(s) - serverRemotePort : out Slv16Array(SERVER_SIZE_G-1 downto 0); - serverRemoteIp : out Slv32Array(SERVER_SIZE_G-1 downto 0); - serverRemoteMac : out Slv48Array(SERVER_SIZE_G-1 downto 0); - obServerMasters : out AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); - obServerSlaves : in AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); + serverRemotePort : out Slv16Array(SERVER_SIZE_G-1 downto 0); + serverRemoteIp : out Slv32Array(SERVER_SIZE_G-1 downto 0); + serverRemoteMac : out Slv48Array(SERVER_SIZE_G-1 downto 0); + obServerMasters : out AxiStreamMasterArray(SERVER_SIZE_G-1 downto 0); + obServerSlaves : in AxiStreamSlaveArray(SERVER_SIZE_G-1 downto 0); -- Interface to UDP Client engine(s) - clientRemoteDet : out slv(CLIENT_SIZE_G-1 downto 0); - obClientMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); - obClientSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); + clientRemoteDetValid : out slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteDetIp : out Slv32Array(CLIENT_SIZE_G-1 downto 0); + obClientMasters : out AxiStreamMasterArray(CLIENT_SIZE_G-1 downto 0); + obClientSlaves : in AxiStreamSlaveArray(CLIENT_SIZE_G-1 downto 0); -- Interface to DHCP Engine - ibDhcpMaster : out AxiStreamMasterType; - ibDhcpSlave : in AxiStreamSlaveType; + ibDhcpMaster : out AxiStreamMasterType; + ibDhcpSlave : in AxiStreamSlaveType; -- Clock and Reset - clk : in sl; - rst : in sl); + clk : in sl; + rst : in sl); end UdpEngineRx; architecture rtl of UdpEngineRx is @@ -84,40 +85,42 @@ architecture rtl of UdpEngineRx is LAST_S); type RegType is record - tDestServer : slv(7 downto 0); - tDestClient : slv(7 downto 0); - serverRemotePort : Slv16Array(SERVER_SIZE_G-1 downto 0); - serverRemoteIp : Slv32Array(SERVER_SIZE_G-1 downto 0); - serverRemoteMac : Slv48Array(SERVER_SIZE_G-1 downto 0); - clientRemoteDet : slv(CLIENT_SIZE_G-1 downto 0); - byteCnt : slv(15 downto 0); - tData : slv(127 downto 0); - sof : sl; - localHost : sl; - route : RouteType; - rxSlave : AxiStreamSlaveType; - dhcpMaster : AxiStreamMasterType; - serverMaster : AxiStreamMasterType; - clientMaster : AxiStreamMasterType; - state : StateType; + tDestServer : slv(7 downto 0); + tDestClient : slv(7 downto 0); + serverRemotePort : Slv16Array(SERVER_SIZE_G-1 downto 0); + serverRemoteIp : Slv32Array(SERVER_SIZE_G-1 downto 0); + serverRemoteMac : Slv48Array(SERVER_SIZE_G-1 downto 0); + clientRemoteDetValid : slv(CLIENT_SIZE_G-1 downto 0); + clientRemoteDetIp : Slv32Array(CLIENT_SIZE_G-1 downto 0); + byteCnt : slv(15 downto 0); + tData : slv(127 downto 0); + sof : sl; + localHost : sl; + route : RouteType; + rxSlave : AxiStreamSlaveType; + dhcpMaster : AxiStreamMasterType; + serverMaster : AxiStreamMasterType; + clientMaster : AxiStreamMasterType; + state : StateType; end record RegType; constant REG_INIT_C : RegType := ( - tDestServer => (others => '0'), - tDestClient => (others => '0'), - serverRemotePort => (others => (others => '0')), - serverRemoteIp => (others => (others => '0')), - serverRemoteMac => (others => (others => '0')), - clientRemoteDet => (others => '0'), - byteCnt => (others => '0'), - tData => (others => '0'), - sof => '1', - localHost => '0', - route => NULL_S, - rxSlave => AXI_STREAM_SLAVE_INIT_C, - dhcpMaster => AXI_STREAM_MASTER_INIT_C, - serverMaster => AXI_STREAM_MASTER_INIT_C, - clientMaster => AXI_STREAM_MASTER_INIT_C, - state => IDLE_S); + tDestServer => (others => '0'), + tDestClient => (others => '0'), + serverRemotePort => (others => (others => '0')), + serverRemoteIp => (others => (others => '0')), + serverRemoteMac => (others => (others => '0')), + clientRemoteDetValid => (others => '0'), + clientRemoteDetIp => (others => (others => '0')), + byteCnt => (others => '0'), + tData => (others => '0'), + sof => '1', + localHost => '0', + route => NULL_S, + rxSlave => AXI_STREAM_SLAVE_INIT_C, + dhcpMaster => AXI_STREAM_MASTER_INIT_C, + serverMaster => AXI_STREAM_MASTER_INIT_C, + clientMaster => AXI_STREAM_MASTER_INIT_C, + state => IDLE_S); signal r : RegType := REG_INIT_C; signal rin : RegType; @@ -156,8 +159,8 @@ begin v := r; -- Reset the flags - v.clientRemoteDet := (others => '0'); - v.rxSlave := AXI_STREAM_SLAVE_INIT_C; + v.clientRemoteDetValid := (others => '0'); + v.rxSlave := AXI_STREAM_SLAVE_INIT_C; if serverSlave.tReady = '1' then v.serverMaster.tValid := '0'; v.serverMaster.tLast := '0'; @@ -247,9 +250,10 @@ begin for i in (CLIENT_SIZE_G-1) downto 0 loop -- Check if port is defined if (v.route = NULL_S) and (rxMaster.tData(63 downto 48) = CLIENT_PORTS_C(i)) then - v.route := CLIENT_S; - v.tDestClient := toSlv(i, 8); - v.clientRemoteDet(i) := '1'; + v.route := CLIENT_S; + v.tDestClient := toSlv(i, 8); + v.clientRemoteDetValid(i) := '1'; + v.clientRemoteDetIp(i) := rxMaster.tData(95 downto 64); end if; end loop; end if; @@ -265,12 +269,12 @@ begin v.byteCnt := v.byteCnt - 8; -- Remove the RoCEv2 iCRC if rxMaster.tData(63 downto 48) = x"B712" then - v.byteCnt := v.byteCnt - 4; + v.byteCnt := v.byteCnt - 4; end if; -- Track the leftovers - v.tData(31 downto 0) := rxMaster.tData(127 downto 96); + v.tData(31 downto 0) := rxMaster.tData(127 downto 96); -- Set the flag - v.sof := '1'; + v.sof := '1'; -- Check if localhost if (localIp = r.tData(95 downto 64)) then v.localHost := '1'; @@ -496,10 +500,11 @@ begin rin <= v; -- Registered Outputs - serverRemotePort <= r.serverRemotePort; - serverRemoteIp <= r.serverRemoteIp; - serverRemoteMac <= r.serverRemoteMac; - clientRemoteDet <= r.clientRemoteDet; + serverRemotePort <= r.serverRemotePort; + serverRemoteIp <= r.serverRemoteIp; + serverRemoteMac <= r.serverRemoteMac; + clientRemoteDetValid <= r.clientRemoteDetValid; + clientRemoteDetIp <= r.clientRemoteDetIp; end process comb; From ea4f066ee4c2fa35a1cf04e6a348ce9afa6dea22 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Wed, 9 Oct 2024 10:17:04 +0200 Subject: [PATCH 12/15] fixed way to get rx ip address --- ethernet/UdpEngine/rtl/UdpEngineRx.vhd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethernet/UdpEngine/rtl/UdpEngineRx.vhd b/ethernet/UdpEngine/rtl/UdpEngineRx.vhd index d63a40c0ca..e4ed74ad76 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineRx.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineRx.vhd @@ -253,7 +253,7 @@ begin v.route := CLIENT_S; v.tDestClient := toSlv(i, 8); v.clientRemoteDetValid(i) := '1'; - v.clientRemoteDetIp(i) := rxMaster.tData(95 downto 64); + v.clientRemoteDetIp(i) := r.tData(95 downto 64); end if; end loop; end if; From 8e8c34174c11661c3dc923eadf06f32068231f9d Mon Sep 17 00:00:00 2001 From: FilMarini Date: Wed, 9 Oct 2024 12:55:38 +0200 Subject: [PATCH 13/15] added possibility of tagging rx ip in tUser field --- ethernet/UdpEngine/rtl/UdpEngine.vhd | 52 ++++++++-------- ethernet/UdpEngine/rtl/UdpEngineRx.vhd | 24 ++++---- ethernet/UdpEngine/rtl/UdpEngineWrapper.vhd | 66 +++++++++++---------- 3 files changed, 76 insertions(+), 66 deletions(-) diff --git a/ethernet/UdpEngine/rtl/UdpEngine.vhd b/ethernet/UdpEngine/rtl/UdpEngine.vhd index b9793ff74b..8beef04c21 100644 --- a/ethernet/UdpEngine/rtl/UdpEngine.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngine.vhd @@ -22,24 +22,25 @@ use surf.AxiStreamPkg.all; entity UdpEngine is generic ( -- Simulation Generics - TPD_G : time := 1 ns; + TPD_G : time := 1 ns; -- UDP Server Generics - SERVER_EN_G : boolean := true; - SERVER_SIZE_G : positive := 1; - SERVER_PORTS_G : PositiveArray := (0 => 8192); + SERVER_EN_G : boolean := true; + SERVER_SIZE_G : positive := 1; + SERVER_PORTS_G : PositiveArray := (0 => 8192); -- UDP Client Generics - CLIENT_EN_G : boolean := true; - CLIENT_SIZE_G : positive := 1; - CLIENT_PORTS_G : PositiveArray := (0 => 8193); - ARP_TAB_ENTRIES_G : positive range 1 to 255 := 4; + CLIENT_EN_G : boolean := true; + CLIENT_TAG_IP_IN_TUSER : boolean := false; + CLIENT_SIZE_G : positive := 1; + CLIENT_PORTS_G : PositiveArray := (0 => 8193); + ARP_TAB_ENTRIES_G : positive range 1 to 255 := 4; -- General UDP/IGMP/ARP/DHCP Generics - TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up - DHCP_G : boolean := false; - IGMP_G : boolean := false; - IGMP_GRP_SIZE : positive := 1; - CLK_FREQ_G : real := 156.25E+06; -- In units of Hz - COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request - SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs + TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up + DHCP_G : boolean := false; + IGMP_G : boolean := false; + IGMP_GRP_SIZE : positive := 1; + CLK_FREQ_G : real := 156.25E+06; -- In units of Hz + COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request + SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs port ( -- Local Configurations localMac : in slv(47 downto 0); -- big-Endian configuration @@ -116,16 +117,17 @@ begin U_UdpEngineRx : entity surf.UdpEngineRx generic map ( - TPD_G => TPD_G, - DHCP_G => DHCP_G, - IGMP_G => IGMP_G, - IGMP_GRP_SIZE => IGMP_GRP_SIZE, - SERVER_EN_G => SERVER_EN_G, - SERVER_SIZE_G => SERVER_SIZE_G, - SERVER_PORTS_G => SERVER_PORTS_G, - CLIENT_EN_G => CLIENT_EN_G, - CLIENT_SIZE_G => CLIENT_SIZE_G, - CLIENT_PORTS_G => CLIENT_PORTS_G) + TPD_G => TPD_G, + DHCP_G => DHCP_G, + IGMP_G => IGMP_G, + IGMP_GRP_SIZE => IGMP_GRP_SIZE, + SERVER_EN_G => SERVER_EN_G, + SERVER_SIZE_G => SERVER_SIZE_G, + SERVER_PORTS_G => SERVER_PORTS_G, + CLIENT_EN_G => CLIENT_EN_G, + CLIENT_TAG_IP_IN_TUSER => CLIENT_TAG_IP_IN_TUSER, + CLIENT_SIZE_G => CLIENT_SIZE_G, + CLIENT_PORTS_G => CLIENT_PORTS_G) port map ( -- Local Configurations localIp => localIp, diff --git a/ethernet/UdpEngine/rtl/UdpEngineRx.vhd b/ethernet/UdpEngine/rtl/UdpEngineRx.vhd index e4ed74ad76..882eb36d0b 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineRx.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineRx.vhd @@ -27,19 +27,20 @@ use surf.EthMacPkg.all; entity UdpEngineRx is generic ( -- Simulation Generics - TPD_G : time := 1 ns; + TPD_G : time := 1 ns; -- UDP General Generic - DHCP_G : boolean := false; - IGMP_G : boolean := false; - IGMP_GRP_SIZE : positive := 1; + DHCP_G : boolean := false; + IGMP_G : boolean := false; + IGMP_GRP_SIZE : positive := 1; -- UDP Server Generics - SERVER_EN_G : boolean := true; - SERVER_SIZE_G : positive := 1; - SERVER_PORTS_G : PositiveArray := (0 => 8192); + SERVER_EN_G : boolean := true; + SERVER_SIZE_G : positive := 1; + SERVER_PORTS_G : PositiveArray := (0 => 8192); -- UDP Client Generics - CLIENT_EN_G : boolean := true; - CLIENT_SIZE_G : positive := 1; - CLIENT_PORTS_G : PositiveArray := (0 => 8193)); + CLIENT_EN_G : boolean := true; + CLIENT_TAG_IP_IN_TUSER : boolean := false; + CLIENT_SIZE_G : positive := 1; + CLIENT_PORTS_G : PositiveArray := (0 => 8193)); port ( -- Local Configurations localIp : in slv(31 downto 0); -- big-Endian configuration @@ -254,6 +255,9 @@ begin v.tDestClient := toSlv(i, 8); v.clientRemoteDetValid(i) := '1'; v.clientRemoteDetIp(i) := r.tData(95 downto 64); + if CLIENT_TAG_IP_IN_TUSER then + v.clientMaster.tUser(39 downto 8) := r.tData(95 downto 64); + end if; end if; end loop; end if; diff --git a/ethernet/UdpEngine/rtl/UdpEngineWrapper.vhd b/ethernet/UdpEngine/rtl/UdpEngineWrapper.vhd index 7763736090..5816c74423 100644 --- a/ethernet/UdpEngine/rtl/UdpEngineWrapper.vhd +++ b/ethernet/UdpEngine/rtl/UdpEngineWrapper.vhd @@ -26,26 +26,28 @@ use surf.EthMacPkg.all; entity UdpEngineWrapper is generic ( -- Simulation Generics - TPD_G : time := 1 ns; + TPD_G : time := 1 ns; -- UDP Server Generics - SERVER_EN_G : boolean := true; - SERVER_SIZE_G : positive := 1; - SERVER_PORTS_G : PositiveArray := (0 => 8192); + SERVER_EN_G : boolean := true; + SERVER_SIZE_G : positive := 1; + SERVER_PORTS_G : PositiveArray := (0 => 8192); -- UDP Client Generics - CLIENT_EN_G : boolean := true; - CLIENT_SIZE_G : positive := 1; - CLIENT_PORTS_G : PositiveArray := (0 => 8193); - CLIENT_EXT_CONFIG_G : boolean := false; + CLIENT_EN_G : boolean := true; + CLIENT_TAG_IP_IN_TUSER : boolean := false; + CLIENT_SIZE_G : positive := 1; + CLIENT_PORTS_G : PositiveArray := (0 => 8193); + CLIENT_EXT_CONFIG_G : boolean := false; + ARP_TAB_ENTRIES_G : positive range 1 to 255 := 4; -- General IPv4/IGMP/ICMP/ARP/DHCP Generics - TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up - DHCP_G : boolean := false; - IGMP_G : boolean := false; - IGMP_GRP_SIZE : positive range 1 to 8 := 1; - IGMP_INIT_G : Slv32Array := (0 => x"0000_0000"); - CLK_FREQ_G : real := 156.25E+06; -- In units of Hz - COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request - TTL_G : slv(7 downto 0) := x"20"; -- IPv4's Time-To-Live (TTL) - SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs + TX_FLOW_CTRL_G : boolean := true; -- True: Blow off the UDP TX data if link down, False: Backpressure until TX link is up + DHCP_G : boolean := false; + IGMP_G : boolean := false; + IGMP_GRP_SIZE : positive range 1 to 8 := 1; + IGMP_INIT_G : Slv32Array := (0 => x"0000_0000"); + CLK_FREQ_G : real := 156.25E+06; -- In units of Hz + COMM_TIMEOUT_G : positive := 30; -- In units of seconds, Client's Communication timeout before re-ARPing or DHCP discover/request + TTL_G : slv(7 downto 0) := x"20"; -- IPv4's Time-To-Live (TTL) + SYNTH_MODE_G : string := "inferred"); -- Synthesis mode for internal RAMs port ( -- Local Configurations localMac : in slv(47 downto 0); -- big-Endian configuration @@ -164,23 +166,25 @@ begin UdpEngine_Inst : entity surf.UdpEngine generic map ( -- Simulation Generics - TPD_G => TPD_G, - IGMP_G => IGMP_G, - IGMP_GRP_SIZE => IGMP_GRP_SIZE, + TPD_G => TPD_G, + IGMP_G => IGMP_G, + IGMP_GRP_SIZE => IGMP_GRP_SIZE, -- UDP Server Generics - SERVER_EN_G => SERVER_EN_G, - SERVER_SIZE_G => SERVER_SIZE_G, - SERVER_PORTS_G => SERVER_PORTS_G, + SERVER_EN_G => SERVER_EN_G, + SERVER_SIZE_G => SERVER_SIZE_G, + SERVER_PORTS_G => SERVER_PORTS_G, -- UDP Client Generics - CLIENT_EN_G => CLIENT_EN_G, - CLIENT_SIZE_G => CLIENT_SIZE_G, - CLIENT_PORTS_G => CLIENT_PORTS_G, + CLIENT_EN_G => CLIENT_EN_G, + CLIENT_TAG_IP_IN_TUSER => CLIENT_TAG_IP_IN_TUSER, + CLIENT_SIZE_G => CLIENT_SIZE_G, + CLIENT_PORTS_G => CLIENT_PORTS_G, + ARP_TAB_ENTRIES_G => ARP_TAB_ENTRIES_G, -- UDP ARP/DHCP Generics - TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, - DHCP_G => DHCP_G, - CLK_FREQ_G => CLK_FREQ_G, - COMM_TIMEOUT_G => COMM_TIMEOUT_G, - SYNTH_MODE_G => SYNTH_MODE_G) + TX_FLOW_CTRL_G => TX_FLOW_CTRL_G, + DHCP_G => DHCP_G, + CLK_FREQ_G => CLK_FREQ_G, + COMM_TIMEOUT_G => COMM_TIMEOUT_G, + SYNTH_MODE_G => SYNTH_MODE_G) port map ( -- Local Configurations localMac => localMac, From 28f9393169a88c341d52643def9b8a0ba7805692 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Fri, 11 Oct 2024 15:32:09 +0200 Subject: [PATCH 14/15] fixed bugs --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 68 +++++++++++++++++---------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 237b163601..6a0dcd68bf 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -52,19 +52,23 @@ architecture rtl of ArpIpTable is -- Write stuff type wRegType is record - ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); - macLutTable : Slv48Array(ENTRIES_G-1 downto 0); - fifoRdEn : sl; - overwrite : boolean; - entryCount : slv(7 downto 0); + ipLutTable : Slv32Array(ENTRIES_G-1 downto 0); + macLutTable : Slv48Array(ENTRIES_G-1 downto 0); + fifoRdEn : sl; + fifoValid : sl; + overwrite : boolean; + writingNewIp : boolean; + entryCount : slv(7 downto 0); end record wRegType; constant W_REG_INIT_C : wRegType := ( - ipLutTable => (others => (others => '0')), - macLutTable => (others => (others => '0')), - fifoRdEn => '0', - overwrite => false, - entryCount => (others => '0') + ipLutTable => (others => (others => '0')), + macLutTable => (others => (others => '0')), + fifoRdEn => '0', + fifoValid => '0', + overwrite => false, + writingNewIp => false, + entryCount => (others => '0') ); signal wR : wRegType := W_REG_INIT_C; @@ -74,7 +78,8 @@ architecture rtl of ArpIpTable is signal matchArray : slv(ENTRIES_G-1 downto 0); -- Expire stuff - constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); + --constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); + constant TIMER_1_SEC_C : natural := 238; type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; type ExpStateType is ( IDLE_S, @@ -118,36 +123,39 @@ begin -- architecture rtl -- Write process comb wrComb : process (arbSelected, arbValid, fifoData, fifoEmpty, fifoValid, ipWrAddr, ipWrEn, macWrAddr, macWrEn, rst, wR) is - variable v : wRegType; - variable wrAddInt : integer; + variable v : wRegType; + variable wrAddInt : integer; + variable wrAddIntMac : integer; begin -- Latch the current value v := wR; -- Update flags - v.overwrite := false; + v.overwrite := false; + v.fifoValid := '0'; + v.writingNewIp := false; -- Write IP to LUT if ipWrEn = '1' or wR.overwrite then wrAddInt := conv_integer(wR.entryCount); - if fifoEmpty = '0' then - v.fifoRdEn := '1'; - v.overwrite := true; - end if; - if wrAddInt < ENTRIES_G and (not v.overwrite) then + if fifoEmpty = '0' and (not wR.overwrite) then + v.fifoRdEn := '1'; + elsif wrAddInt < ENTRIES_G then v.ipLutTable(wrAddInt) := ipWrAddr; + v.writingNewIp := true; + wrAddIntMac := wrAddInt; end if; end if; -- Write MAC to LUT if macWrEn = '1' then - wrAddInt := conv_integer(wR.entryCount); - if wrAddInt < ENTRIES_G then - v.macLutTable(wrAddInt) := macWrAddr; - end if; + -- wrAddInt := conv_integer(wR.entryCount); + -- if wrAddInt < ENTRIES_G then + v.macLutTable(wrAddIntMac) := macWrAddr; + -- end if; -- Update write LUT pointer - if wr.entryCount < ENTRIES_G - 1 then + if wR.entryCount < ENTRIES_G - 1 then v.entryCount := wr.entryCount + 1; else v.entryCount := (others => '0'); @@ -156,8 +164,13 @@ begin -- architecture rtl -- Overwrite LUT pointer if there are empty spaces if fifoValid = '1' then + v.fifoValid := '1'; + v.fifoRdEn := '0'; + end if; + + if wR.fifoValid = '1' then v.entryCount := fifoData; - v.fifoRdEn := '0'; + v.overwrite := true; end if; -- Remove entry from LUT @@ -272,6 +285,9 @@ begin -- architecture rtl if clientRemoteDetValid = '1' and clientRemoteDetIp = wR.ipLutTable(i) then -- Preset the timer v.arpTimers(i) := COMM_TIMEOUT_G; + elsif wR.writingNewIp and conv_integer(wR.entryCount) = i then + -- Preset the timer + v.arpTimers(i) := COMM_TIMEOUT_G; elsif eR.arpTimers(i) = 0 then -- Next state v.state(i) := EXPIRE_S; @@ -324,7 +340,7 @@ begin -- architecture rtl port map ( clk => clk, rst => rst, - req => eR.arbRequest, + req => eRin.arbRequest, selected => arbSelected, valid => arbValid, ack => open); From 300a5ae99cc7a265023f667a33a256df883b9e17 Mon Sep 17 00:00:00 2001 From: FilMarini Date: Fri, 11 Oct 2024 15:34:13 +0200 Subject: [PATCH 15/15] fixed tb leftovers --- ethernet/UdpEngine/rtl/ArpIpTable.vhd | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ethernet/UdpEngine/rtl/ArpIpTable.vhd b/ethernet/UdpEngine/rtl/ArpIpTable.vhd index 6a0dcd68bf..d4e72f9dc3 100644 --- a/ethernet/UdpEngine/rtl/ArpIpTable.vhd +++ b/ethernet/UdpEngine/rtl/ArpIpTable.vhd @@ -78,8 +78,7 @@ architecture rtl of ArpIpTable is signal matchArray : slv(ENTRIES_G-1 downto 0); -- Expire stuff - --constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); - constant TIMER_1_SEC_C : natural := 238; + constant TIMER_1_SEC_C : natural := getTimeRatio(CLK_FREQ_G, 1.0); type TimerArray is array (natural range <>) of natural range 0 to COMM_TIMEOUT_G; type ExpStateType is ( IDLE_S,