From 0abd3fa9fcf00300ad7518bbf35e3ee88e252ef8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 11:00:31 +0200 Subject: [PATCH 01/11] core/arp: Simplify request_ip_address. --- liteeth/core/arp.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index b100258..118af91 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -176,15 +176,7 @@ class LiteEthARPTable(LiteXModule): request_pending.eq(1) ) - request_ip_address = Signal(32, reset_less=True) - request_ip_address_reset = Signal() - request_ip_address_update = Signal() - self.sync += \ - If(request_ip_address_reset, - request_ip_address.eq(0) - ).Elif(request_ip_address_update, - request_ip_address.eq(request.ip_address) - ) + request_ip_address = Signal(32, reset_less=True) request_timer = WaitTimer(int(clk_freq//10)) self.submodules += request_timer @@ -217,7 +209,7 @@ class LiteEthARPTable(LiteXModule): NextState("SEND_REPLY") ).Elif(sink.valid & sink.reply & request_pending, NextState("UPDATE_TABLE"), - ).Elif(request_counter == max_requests-1, + ).Elif(request_counter == (max_requests - 1), NextState("PRESENT_RESPONSE") ).Elif(request.valid | (request_pending & request_timer.done), NextState("CHECK_TABLE") @@ -251,17 +243,21 @@ class LiteEthARPTable(LiteXModule): fsm.act("CHECK_TABLE", If(cached_valid, If(request_ip_address == cached_ip_address, - request_ip_address_reset.eq(1), + NextValue(request_ip_address, 0), NextState("PRESENT_RESPONSE"), ).Elif(request.ip_address == cached_ip_address, request.ready.eq(request.valid), NextState("PRESENT_RESPONSE"), ).Else( - request_ip_address_update.eq(request.valid), + If(request.valid, + NextValue(request_ip_address, request.ip_address), + ), NextState("SEND_REQUEST") ) ).Else( - request_ip_address_update.eq(request.valid), + If(request.valid, + NextValue(request_ip_address, request.ip_address), + ), NextState("SEND_REQUEST") ) ) @@ -278,15 +274,15 @@ class LiteEthARPTable(LiteXModule): ) ) self.comb += [ - If(request_counter == max_requests - 1, + If(request_counter == (max_requests - 1), response.failed.eq(1), request_counter_reset.eq(1), request_pending_clr.eq(1) - ), - response.mac_address.eq(cached_mac_address) + ) ] fsm.act("PRESENT_RESPONSE", response.valid.eq(1), + response.mac_address.eq(cached_mac_address), If(response.ready, NextState("IDLE") ) From 4dbcb53411dfdfd0e289f39f1fe4cc9161135893 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 11:12:58 +0200 Subject: [PATCH 02/11] core/arp: Simplify request_counter/timer. --- liteeth/core/arp.py | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index 118af91..ffa26b8 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -176,20 +176,11 @@ class LiteEthARPTable(LiteXModule): request_pending.eq(1) ) + request_counter = Signal(max=max_requests) request_ip_address = Signal(32, reset_less=True) - request_timer = WaitTimer(int(clk_freq//10)) - self.submodules += request_timer - request_counter = Signal(max=max_requests) - request_counter_reset = Signal() - request_counter_ce = Signal() - self.sync += \ - If(request_counter_reset, - request_counter.eq(0) - ).Elif(request_counter_ce, - request_counter.eq(request_counter + 1) - ) - self.comb += request_timer.wait.eq(request_pending & ~request_counter_ce) + self.request_timer = WaitTimer(int(clk_freq//10)) + self.comb += self.request_timer.wait.eq(request_pending) # Note: Store only 1 IP/MAC couple, can be improved with a real # table in the future to improve performance when packets are @@ -211,7 +202,7 @@ class LiteEthARPTable(LiteXModule): NextState("UPDATE_TABLE"), ).Elif(request_counter == (max_requests - 1), NextState("PRESENT_RESPONSE") - ).Elif(request.valid | (request_pending & request_timer.done), + ).Elif(request.valid | (request_pending & self.request_timer.done), NextState("CHECK_TABLE") ) ) @@ -266,23 +257,25 @@ class LiteEthARPTable(LiteXModule): source.request.eq(1), source.ip_address.eq(request_ip_address), If(source.ready, - request_counter_reset.eq(request.valid), - request_counter_ce.eq(1), + If(request.valid, + NextValue(request_counter, 0), + ).Else( + self.request_timer.wait.eq(0), + NextValue(request_counter, request_counter + 1), + ), request_pending_set.eq(1), request.ready.eq(1), NextState("IDLE") ) ) - self.comb += [ - If(request_counter == (max_requests - 1), - response.failed.eq(1), - request_counter_reset.eq(1), - request_pending_clr.eq(1) - ) - ] fsm.act("PRESENT_RESPONSE", response.valid.eq(1), response.mac_address.eq(cached_mac_address), + If(request_counter == (max_requests - 1), + response.failed.eq(1), + NextValue(request_counter, 0), + request_pending_clr.eq(1) + ), If(response.ready, NextState("IDLE") ) From fc4ed41dcfeb12cd89bfbfd44729ca047f46649a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 11:16:19 +0200 Subject: [PATCH 03/11] core/arp: Simplify request_pending. --- liteeth/core/arp.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index ffa26b8..77baec1 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -166,20 +166,11 @@ class LiteEthARPTable(LiteXModule): # # # - request_pending = Signal() - request_pending_clr = Signal() - request_pending_set = Signal() - self.sync += \ - If(request_pending_clr, - request_pending.eq(0) - ).Elif(request_pending_set, - request_pending.eq(1) - ) - + request_pending = Signal() request_counter = Signal(max=max_requests) request_ip_address = Signal(32, reset_less=True) - self.request_timer = WaitTimer(int(clk_freq//10)) + self.request_timer = WaitTimer(int(100e-3*clk_freq)) self.comb += self.request_timer.wait.eq(request_pending) # Note: Store only 1 IP/MAC couple, can be improved with a real @@ -202,7 +193,7 @@ class LiteEthARPTable(LiteXModule): NextState("UPDATE_TABLE"), ).Elif(request_counter == (max_requests - 1), NextState("PRESENT_RESPONSE") - ).Elif(request.valid | (request_pending & self.request_timer.done), + ).Elif(request.valid | self.request_timer.done, NextState("CHECK_TABLE") ) ) @@ -216,7 +207,7 @@ class LiteEthARPTable(LiteXModule): ) ) fsm.act("UPDATE_TABLE", - request_pending_clr.eq(1), + NextValue(request_pending, 0), update.eq(1), NextState("CHECK_TABLE") ) @@ -263,7 +254,7 @@ class LiteEthARPTable(LiteXModule): self.request_timer.wait.eq(0), NextValue(request_counter, request_counter + 1), ), - request_pending_set.eq(1), + NextValue(request_pending, 1), request.ready.eq(1), NextState("IDLE") ) @@ -274,7 +265,7 @@ class LiteEthARPTable(LiteXModule): If(request_counter == (max_requests - 1), response.failed.eq(1), NextValue(request_counter, 0), - request_pending_clr.eq(1) + NextValue(request_pending, 0), ), If(response.ready, NextState("IDLE") From 538a4e407c76e1c9c855b2eba660dae0b19bdcea Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 11:23:12 +0200 Subject: [PATCH 04/11] core/arp: Cosmetic cleanups. --- liteeth/core/arp.py | 54 +++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index 77baec1..b8fbd61 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -53,8 +53,8 @@ class LiteEthARPTX(LiteXModule): self.comb += [ packetizer.sink.last.eq(counter == (packet_words - 1)), If(packetizer.sink.last, - packetizer.sink.last_be.eq( - 1 if len(packetizer.sink.last_be) == 1 else 2**(packet_length % (dw // 8) - 1) + packetizer.sink.last_be.eq(1 if len(packetizer.sink.last_be) == 1 else + 2**(packet_length % (dw // 8) - 1) ), ), packetizer.sink.hwtype.eq(arp_hwtype_ethernet), @@ -97,7 +97,8 @@ class LiteEthARPDepacketizer(Depacketizer): Depacketizer.__init__(self, eth_mac_description(dw), eth_arp_description(dw), - arp_header) + arp_header + ) class LiteEthARPRX(LiteXModule): @@ -105,7 +106,7 @@ class LiteEthARPRX(LiteXModule): self.sink = sink = stream.Endpoint(eth_mac_description(dw)) self.source = source = stream.Endpoint(_arp_table_layout) - # # #s + # # # self.depacketizer = depacketizer = LiteEthARPDepacketizer(dw) self.comb += sink.connect(depacketizer.sink) @@ -121,19 +122,19 @@ class LiteEthARPRX(LiteXModule): valid = Signal(reset_less=True) self.sync += valid.eq( depacketizer.source.valid & - (depacketizer.source.hwtype == arp_hwtype_ethernet) & - (depacketizer.source.proto == arp_proto_ip) & - (depacketizer.source.hwsize == 6) & + (depacketizer.source.hwtype == arp_hwtype_ethernet) & + (depacketizer.source.proto == arp_proto_ip) & + (depacketizer.source.hwsize == 6) & (depacketizer.source.protosize == 4) & (depacketizer.source.target_ip == ip_address) ) - reply = Signal() + reply = Signal() request = Signal() self.comb += Case(depacketizer.source.opcode, { - arp_opcode_request: [request.eq(1)], - arp_opcode_reply: [reply.eq(1)], - "default": [] - }) + arp_opcode_request : [request.eq(1)], + arp_opcode_reply : [reply.eq(1)], + "default" : [] + }) self.comb += [ source.ip_address.eq(depacketizer.source.sender_ip), source.mac_address.eq(depacketizer.source.sender_mac) @@ -176,12 +177,24 @@ class LiteEthARPTable(LiteXModule): # Note: Store only 1 IP/MAC couple, can be improved with a real # table in the future to improve performance when packets are # targeting multiple destinations. - update = Signal() + cached_update = Signal() cached_valid = Signal() cached_ip_address = Signal(32, reset_less=True) cached_mac_address = Signal(48, reset_less=True) - cached_timer = WaitTimer(int(clk_freq*10)) + cached_timer = WaitTimer(int(100e-3*clk_freq)) self.submodules += cached_timer + self.sync += [ + If(cached_update, + cached_valid.eq(1), + cached_ip_address.eq(sink.ip_address), + cached_mac_address.eq(sink.mac_address), + ).Else( + If(cached_timer.done, + cached_valid.eq(0) + ) + ) + ] + self.comb += cached_timer.wait.eq(~cached_update) self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", @@ -208,20 +221,9 @@ class LiteEthARPTable(LiteXModule): ) fsm.act("UPDATE_TABLE", NextValue(request_pending, 0), - update.eq(1), + cached_update.eq(1), NextState("CHECK_TABLE") ) - self.sync += \ - If(update, - cached_valid.eq(1), - cached_ip_address.eq(sink.ip_address), - cached_mac_address.eq(sink.mac_address), - ).Else( - If(cached_timer.done, - cached_valid.eq(0) - ) - ) - self.comb += cached_timer.wait.eq(~update) fsm.act("CHECK_TABLE", If(cached_valid, If(request_ip_address == cached_ip_address, From f33d5b59599bd04cd2401021e8e67c1b22291326 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 11:45:13 +0200 Subject: [PATCH 05/11] core/arp: Add CHECK_REQUEST state to generate failed response if so and simplify FSM. --- liteeth/core/arp.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index b8fbd61..e4f2b93 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -171,7 +171,7 @@ class LiteEthARPTable(LiteXModule): request_counter = Signal(max=max_requests) request_ip_address = Signal(32, reset_less=True) - self.request_timer = WaitTimer(int(100e-3*clk_freq)) + self.request_timer = WaitTimer(100e-3*clk_freq) self.comb += self.request_timer.wait.eq(request_pending) # Note: Store only 1 IP/MAC couple, can be improved with a real @@ -181,7 +181,7 @@ class LiteEthARPTable(LiteXModule): cached_valid = Signal() cached_ip_address = Signal(32, reset_less=True) cached_mac_address = Signal(48, reset_less=True) - cached_timer = WaitTimer(int(100e-3*clk_freq)) + cached_timer = WaitTimer(100e-3*clk_freq) self.submodules += cached_timer self.sync += [ If(cached_update, @@ -198,16 +198,14 @@ class LiteEthARPTable(LiteXModule): self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", - # Note: for simplicicy, if ARP table is busy response from arp_rx - # is lost. This is compensated by the protocol (retries) + # Note: for simplicicy, if ARP table is busy response from arp_rx is lost. This is + # compensated by the protocol (retries) If(sink.valid & sink.request, NextState("SEND_REPLY") ).Elif(sink.valid & sink.reply & request_pending, NextState("UPDATE_TABLE"), - ).Elif(request_counter == (max_requests - 1), - NextState("PRESENT_RESPONSE") ).Elif(request.valid | self.request_timer.done, - NextState("CHECK_TABLE") + NextState("CHECK_REQUEST") ) ) fsm.act("SEND_REPLY", @@ -222,7 +220,17 @@ class LiteEthARPTable(LiteXModule): fsm.act("UPDATE_TABLE", NextValue(request_pending, 0), cached_update.eq(1), - NextState("CHECK_TABLE") + NextState("CHECK_REQUEST") + ) + fsm.act("CHECK_REQUEST", + If(request_counter == (max_requests - 1), + NextValue(response.failed, 1), + NextValue(request_counter, 0), + NextValue(request_pending, 0), + NextState("PRESENT_RESPONSE") + ).Else( + NextState("CHECK_TABLE") + ) ) fsm.act("CHECK_TABLE", If(cached_valid, @@ -264,12 +272,8 @@ class LiteEthARPTable(LiteXModule): fsm.act("PRESENT_RESPONSE", response.valid.eq(1), response.mac_address.eq(cached_mac_address), - If(request_counter == (max_requests - 1), - response.failed.eq(1), - NextValue(request_counter, 0), - NextValue(request_pending, 0), - ), If(response.ready, + NextValue(response.failed, 0), NextState("IDLE") ) ) From 4327adcab4112c434f37cf53c13a4868c0795862 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 12:04:34 +0200 Subject: [PATCH 06/11] core/arp: Simplify FSM CHECK_TABLE state. --- liteeth/core/arp.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index e4f2b93..0dc37a2 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -204,7 +204,9 @@ class LiteEthARPTable(LiteXModule): NextState("SEND_REPLY") ).Elif(sink.valid & sink.reply & request_pending, NextState("UPDATE_TABLE"), - ).Elif(request.valid | self.request_timer.done, + ).Elif(request.valid, + NextState("CHECK_TABLE") + ).Elif(self.request_timer.done, NextState("CHECK_REQUEST") ) ) @@ -220,7 +222,7 @@ class LiteEthARPTable(LiteXModule): fsm.act("UPDATE_TABLE", NextValue(request_pending, 0), cached_update.eq(1), - NextState("CHECK_REQUEST") + NextState("CHECK_TABLE") ) fsm.act("CHECK_REQUEST", If(request_counter == (max_requests - 1), @@ -233,19 +235,12 @@ class LiteEthARPTable(LiteXModule): ) ) fsm.act("CHECK_TABLE", - If(cached_valid, - If(request_ip_address == cached_ip_address, - NextValue(request_ip_address, 0), - NextState("PRESENT_RESPONSE"), - ).Elif(request.ip_address == cached_ip_address, - request.ready.eq(request.valid), - NextState("PRESENT_RESPONSE"), - ).Else( - If(request.valid, - NextValue(request_ip_address, request.ip_address), - ), - NextState("SEND_REQUEST") - ) + If(cached_valid & (request_ip_address == cached_ip_address), + NextValue(request_ip_address, 0), + NextState("PRESENT_RESPONSE"), + ).Elif(cached_valid & (request.ip_address == cached_ip_address), + request.ready.eq(request.valid), + NextState("PRESENT_RESPONSE"), ).Else( If(request.valid, NextValue(request_ip_address, request.ip_address), From fba8925f605c826142c1d82c8e13460557f9c4cd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 12:29:48 +0200 Subject: [PATCH 07/11] core/arp: Another FSM simplification pass. --- liteeth/core/arp.py | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index 0dc37a2..8f8d6a5 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -172,7 +172,7 @@ class LiteEthARPTable(LiteXModule): request_ip_address = Signal(32, reset_less=True) self.request_timer = WaitTimer(100e-3*clk_freq) - self.comb += self.request_timer.wait.eq(request_pending) + self.comb += self.request_timer.wait.eq(request_pending & ~self.request_timer.done) # Note: Store only 1 IP/MAC couple, can be improved with a real # table in the future to improve performance when packets are @@ -202,7 +202,7 @@ class LiteEthARPTable(LiteXModule): # compensated by the protocol (retries) If(sink.valid & sink.request, NextState("SEND_REPLY") - ).Elif(sink.valid & sink.reply & request_pending, + ).Elif(sink.valid & sink.reply, NextState("UPDATE_TABLE"), ).Elif(request.valid, NextState("CHECK_TABLE") @@ -220,9 +220,13 @@ class LiteEthARPTable(LiteXModule): ) ) fsm.act("UPDATE_TABLE", - NextValue(request_pending, 0), - cached_update.eq(1), - NextState("CHECK_TABLE") + If(request_pending & (request_ip_address == sink.ip_address), + cached_update.eq(1), + NextValue(request_pending, 0), + NextState("PRESENT_RESPONSE") + ).Else( + NextState("IDLE") + ) ) fsm.act("CHECK_REQUEST", If(request_counter == (max_requests - 1), @@ -231,20 +235,18 @@ class LiteEthARPTable(LiteXModule): NextValue(request_pending, 0), NextState("PRESENT_RESPONSE") ).Else( - NextState("CHECK_TABLE") + NextState("SEND_REQUEST") ) ) fsm.act("CHECK_TABLE", - If(cached_valid & (request_ip_address == cached_ip_address), - NextValue(request_ip_address, 0), - NextState("PRESENT_RESPONSE"), - ).Elif(cached_valid & (request.ip_address == cached_ip_address), + If(cached_valid & (request.ip_address == cached_ip_address), request.ready.eq(request.valid), NextState("PRESENT_RESPONSE"), ).Else( - If(request.valid, - NextValue(request_ip_address, request.ip_address), - ), + request.ready.eq(1), + NextValue(request_counter, 0), + NextValue(request_pending, 1), + NextValue(request_ip_address, request.ip_address), NextState("SEND_REQUEST") ) ) @@ -253,14 +255,7 @@ class LiteEthARPTable(LiteXModule): source.request.eq(1), source.ip_address.eq(request_ip_address), If(source.ready, - If(request.valid, - NextValue(request_counter, 0), - ).Else( - self.request_timer.wait.eq(0), - NextValue(request_counter, request_counter + 1), - ), - NextValue(request_pending, 1), - request.ready.eq(1), + NextValue(request_counter, request_counter + 1), NextState("IDLE") ) ) From dc7ed0de6f3c257d7ecf56a332e1e6f24fc994e4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 14:46:16 +0200 Subject: [PATCH 08/11] core/arp: Move ARP cache logic to LiteEthARPCache and define interfaces. --- liteeth/core/arp.py | 94 +++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index 8f8d6a5..bb0c79c 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -154,6 +154,47 @@ class LiteEthARPRX(LiteXModule): ) ) +# ARP Cache ---------------------------------------------------------------------------------------- + +class LiteEthARPCache(LiteXModule): + def __init__(self, entries, clk_freq): + assert entries == 1 + # Update interface. + self.update = stream.Endpoint([("ip_address", 32), ("mac_address", 48)]) + + # Request/Response interface. + self.request = stream.Endpoint([("ip_address", 32)]) + self.response = stream.Endpoint([("mac_address", 48), ("error", 1)]) + + # # # + + # Note: Store only 1 IP/MAC couple, can be improved with a real + # table in the future to improve performance when packets are + # targeting multiple destinations. + cached_valid = Signal() + cached_ip_address = Signal(32, reset_less=True) + cached_mac_address = Signal(48, reset_less=True) + self.cached_timer = WaitTimer(int(clk_freq*10)) + + self.comb += self.update.ready.eq(1) + self.sync += [ + If(self.update.valid, + cached_valid.eq(1), + cached_ip_address.eq(self.update.ip_address), + cached_mac_address.eq(self.update.mac_address), + ).Else( + If(self.cached_timer.done, + cached_valid.eq(0) + ) + ) + ] + self.comb += self.cached_timer.wait.eq(~self.update.valid) + + self.comb += self.request.ready.eq(1) + self.comb += self.response.valid.eq(self.request.valid) + self.comb += self.response.error.eq(~cached_valid | (self.request.ip_address != cached_ip_address)) + self.comb += self.response.mac_address.eq(cached_mac_address) + # ARP Table ---------------------------------------------------------------------------------------- class LiteEthARPTable(LiteXModule): @@ -174,27 +215,7 @@ class LiteEthARPTable(LiteXModule): self.request_timer = WaitTimer(100e-3*clk_freq) self.comb += self.request_timer.wait.eq(request_pending & ~self.request_timer.done) - # Note: Store only 1 IP/MAC couple, can be improved with a real - # table in the future to improve performance when packets are - # targeting multiple destinations. - cached_update = Signal() - cached_valid = Signal() - cached_ip_address = Signal(32, reset_less=True) - cached_mac_address = Signal(48, reset_less=True) - cached_timer = WaitTimer(100e-3*clk_freq) - self.submodules += cached_timer - self.sync += [ - If(cached_update, - cached_valid.eq(1), - cached_ip_address.eq(sink.ip_address), - cached_mac_address.eq(sink.mac_address), - ).Else( - If(cached_timer.done, - cached_valid.eq(0) - ) - ) - ] - self.comb += cached_timer.wait.eq(~cached_update) + self.cache = cache = LiteEthARPCache(entries=1, clk_freq=clk_freq) self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", @@ -221,9 +242,13 @@ class LiteEthARPTable(LiteXModule): ) fsm.act("UPDATE_TABLE", If(request_pending & (request_ip_address == sink.ip_address), - cached_update.eq(1), - NextValue(request_pending, 0), - NextState("PRESENT_RESPONSE") + cache.update.valid.eq(1), + cache.update.ip_address.eq(sink.ip_address), + cache.update.mac_address.eq(sink.mac_address), + If(cache.update.ready, + NextValue(request_pending, 0), + NextState("PRESENT_RESPONSE") + ) ).Else( NextState("IDLE") ) @@ -239,15 +264,18 @@ class LiteEthARPTable(LiteXModule): ) ) fsm.act("CHECK_TABLE", - If(cached_valid & (request.ip_address == cached_ip_address), - request.ready.eq(request.valid), - NextState("PRESENT_RESPONSE"), - ).Else( + cache.request.valid.eq(1), + cache.request.ip_address.eq(request.ip_address), + If(cache.response.valid, request.ready.eq(1), - NextValue(request_counter, 0), - NextValue(request_pending, 1), - NextValue(request_ip_address, request.ip_address), - NextState("SEND_REQUEST") + If(cache.response.error, + NextValue(request_counter, 0), + NextValue(request_pending, 1), + NextValue(request_ip_address, request.ip_address), + NextState("SEND_REQUEST") + ).Else( + NextState("PRESENT_RESPONSE"), + ) ) ) fsm.act("SEND_REQUEST", @@ -261,7 +289,7 @@ class LiteEthARPTable(LiteXModule): ) fsm.act("PRESENT_RESPONSE", response.valid.eq(1), - response.mac_address.eq(cached_mac_address), + response.mac_address.eq(cache.response.mac_address), If(response.ready, NextValue(response.failed, 0), NextState("IDLE") From b74618d1ed98b1e84de80d80f887553962dbf2f3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 16:15:10 +0200 Subject: [PATCH 09/11] core/arp: Switch LiteEthARPCache to a proper Memory and allow multiple entries. --- liteeth/core/__init__.py | 6 ++- liteeth/core/arp.py | 107 +++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 33 deletions(-) diff --git a/liteeth/core/__init__.py b/liteeth/core/__init__.py index 4eca800..7f6c0a6 100644 --- a/liteeth/core/__init__.py +++ b/liteeth/core/__init__.py @@ -15,7 +15,7 @@ from liteeth.core.icmp import LiteEthICMP # IP Core ------------------------------------------------------------------------------------------ class LiteEthIPCore(Module, AutoCSR): - def __init__(self, phy, mac_address, ip_address, clk_freq, dw=8, + def __init__(self, phy, mac_address, ip_address, clk_freq, arp_entries=1, dw=8, with_icmp = True, with_ip_broadcast = True, with_sys_datapath = False, @@ -49,6 +49,7 @@ class LiteEthIPCore(Module, AutoCSR): mac_address = mac_address, ip_address = ip_address, clk_freq = clk_freq, + entries = arp_entries, dw = dw, ) @@ -74,7 +75,7 @@ class LiteEthIPCore(Module, AutoCSR): # UDP IP Core -------------------------------------------------------------------------------------- class LiteEthUDPIPCore(LiteEthIPCore): - def __init__(self, phy, mac_address, ip_address, clk_freq, dw=8, + def __init__(self, phy, mac_address, ip_address, clk_freq, arp_entries=1, dw=8, with_icmp = True, with_ip_broadcast = True, with_sys_datapath = False, @@ -94,6 +95,7 @@ class LiteEthUDPIPCore(LiteEthIPCore): mac_address = mac_address, ip_address = ip_address, clk_freq = clk_freq, + arp_entries = arp_entries, with_icmp = with_icmp, dw = dw, with_ip_broadcast = with_ip_broadcast, diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index bb0c79c..8e80e91 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -156,9 +156,8 @@ class LiteEthARPRX(LiteXModule): # ARP Cache ---------------------------------------------------------------------------------------- -class LiteEthARPCache(LiteXModule): +class LiteEthARPCache(Module): def __init__(self, entries, clk_freq): - assert entries == 1 # Update interface. self.update = stream.Endpoint([("ip_address", 32), ("mac_address", 48)]) @@ -168,37 +167,83 @@ class LiteEthARPCache(LiteXModule): # # # - # Note: Store only 1 IP/MAC couple, can be improved with a real - # table in the future to improve performance when packets are - # targeting multiple destinations. - cached_valid = Signal() - cached_ip_address = Signal(32, reset_less=True) - cached_mac_address = Signal(48, reset_less=True) - self.cached_timer = WaitTimer(int(clk_freq*10)) + entries = max(entries, 2) - self.comb += self.update.ready.eq(1) - self.sync += [ - If(self.update.valid, - cached_valid.eq(1), - cached_ip_address.eq(self.update.ip_address), - cached_mac_address.eq(self.update.mac_address), - ).Else( - If(self.cached_timer.done, - cached_valid.eq(0) - ) + mem_width = 32 + 48 + 1 # IP + MAC + Valid. + mem = Memory(mem_width, entries) + mem_wr_port = mem.get_port(write_capable=True) + mem_rd_port = mem.get_port(async_read=True) # FIXME: Avoid async_read. + self.specials += mem, mem_wr_port, mem_rd_port + + update_count = Signal(max=entries) + search_count = Signal(max=entries) + error = Signal() + + mem_wr_port_valid = mem_wr_port.dat_w[80] + mem_wr_port_ip_address = mem_wr_port.dat_w[0:32] + mem_wr_port_mac_address = mem_wr_port.dat_w[32:80] + + mem_rd_port_valid = mem_rd_port.dat_r[80] + mem_rd_port_ip_address = mem_rd_port.dat_r[0:32] + mem_rd_port_mac_address = mem_rd_port.dat_r[32:80] + + self.submodules.fsm = fsm = FSM(reset_state="CLEAR") + fsm.act("CLEAR", + mem_wr_port.we.eq(1), + mem_wr_port.adr.eq(update_count), + mem_wr_port_valid.eq(0), + NextValue(update_count, update_count + 1), + If(update_count == (entries - 1), + NextState("IDLE") ) - ] - self.comb += self.cached_timer.wait.eq(~self.update.valid) - - self.comb += self.request.ready.eq(1) - self.comb += self.response.valid.eq(self.request.valid) - self.comb += self.response.error.eq(~cached_valid | (self.request.ip_address != cached_ip_address)) - self.comb += self.response.mac_address.eq(cached_mac_address) + ) + fsm.act("IDLE", + If(self.update.valid, + NextState("MEM_UPDATE") + ), + If(self.request.valid, + NextValue(search_count, 0), + NextState("MEM_SEARCH") + ) + ) + fsm.act("MEM_UPDATE", + mem_wr_port.we.eq(1), + mem_wr_port.adr.eq(update_count), + mem_wr_port_valid.eq(1), + mem_wr_port_ip_address.eq( self.update.ip_address), + mem_wr_port_mac_address.eq(self.update.mac_address), + self.update.ready.eq(1), + If(update_count == (entries - 1), + NextValue(update_count, 0) + ).Else( + NextValue(update_count, update_count + 1) + ), + NextState("IDLE") + ) + fsm.act("MEM_SEARCH", + mem_rd_port.adr.eq(search_count), + If(mem_rd_port_valid & (mem_rd_port_ip_address == self.request.ip_address), + NextValue(error, 0), + NextState("RESPONSE") + ).Elif(search_count == (entries - 1), + NextValue(error, 1), + NextState("RESPONSE") + ).Else( + NextValue(search_count, search_count + 1) + ) + ) + fsm.act("RESPONSE", + self.request.ready.eq(1), + self.response.valid.eq(1), + self.response.error.eq(error), + self.response.mac_address.eq(mem_rd_port_mac_address), + NextState("IDLE") + ) # ARP Table ---------------------------------------------------------------------------------------- class LiteEthARPTable(LiteXModule): - def __init__(self, clk_freq, max_requests=8): + def __init__(self, clk_freq, entries=1, max_requests=8): self.sink = sink = stream.Endpoint(_arp_table_layout) # from arp_rx self.source = source = stream.Endpoint(_arp_table_layout) # to arp_tx @@ -215,7 +260,7 @@ class LiteEthARPTable(LiteXModule): self.request_timer = WaitTimer(100e-3*clk_freq) self.comb += self.request_timer.wait.eq(request_pending & ~self.request_timer.done) - self.cache = cache = LiteEthARPCache(entries=1, clk_freq=clk_freq) + self.cache = cache = LiteEthARPCache(entries=entries, clk_freq=clk_freq) self.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", @@ -274,6 +319,7 @@ class LiteEthARPTable(LiteXModule): NextValue(request_ip_address, request.ip_address), NextState("SEND_REQUEST") ).Else( + NextValue(response.mac_address, cache.response.mac_address), NextState("PRESENT_RESPONSE"), ) ) @@ -289,7 +335,6 @@ class LiteEthARPTable(LiteXModule): ) fsm.act("PRESENT_RESPONSE", response.valid.eq(1), - response.mac_address.eq(cache.response.mac_address), If(response.ready, NextValue(response.failed, 0), NextState("IDLE") @@ -299,10 +344,10 @@ class LiteEthARPTable(LiteXModule): # ARP ---------------------------------------------------------------------------------------------- class LiteEthARP(LiteXModule): - def __init__(self, mac, mac_address, ip_address, clk_freq, dw=8): + def __init__(self, mac, mac_address, ip_address, clk_freq, entries=1, dw=8): self.tx = tx = LiteEthARPTX(mac_address, ip_address, dw) self.rx = rx = LiteEthARPRX(mac_address, ip_address, dw) - self.table = table = LiteEthARPTable(clk_freq) + self.table = table = LiteEthARPTable(clk_freq, entries=entries) self.comb += [ rx.source.connect(table.sink), table.source.connect(tx.sink) From c5b53326bb3fc3e9f89f451e9d9663b7a6449dcc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 16:57:42 +0200 Subject: [PATCH 10/11] core/arp: Add clear timer to clear cache periodically and minor cleanups. --- liteeth/core/arp.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index 8e80e91..fac1722 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -156,7 +156,7 @@ class LiteEthARPRX(LiteXModule): # ARP Cache ---------------------------------------------------------------------------------------- -class LiteEthARPCache(Module): +class LiteEthARPCache(LiteXModule): def __init__(self, entries, clk_freq): # Update interface. self.update = stream.Endpoint([("ip_address", 32), ("mac_address", 48)]) @@ -167,27 +167,37 @@ class LiteEthARPCache(Module): # # # - entries = max(entries, 2) + # Parameters. + entries = max(entries, 2) # Minimal number of entries is 2. + # Signals. + update_count = Signal(max=entries) + search_count = Signal(max=entries) + error = Signal() + + # Memory mem_width = 32 + 48 + 1 # IP + MAC + Valid. mem = Memory(mem_width, entries) mem_wr_port = mem.get_port(write_capable=True) mem_rd_port = mem.get_port(async_read=True) # FIXME: Avoid async_read. self.specials += mem, mem_wr_port, mem_rd_port - update_count = Signal(max=entries) - search_count = Signal(max=entries) - error = Signal() - + # Memory wr_port aliases. mem_wr_port_valid = mem_wr_port.dat_w[80] mem_wr_port_ip_address = mem_wr_port.dat_w[0:32] mem_wr_port_mac_address = mem_wr_port.dat_w[32:80] + # Memory rd_port aliases. mem_rd_port_valid = mem_rd_port.dat_r[80] mem_rd_port_ip_address = mem_rd_port.dat_r[0:32] mem_rd_port_mac_address = mem_rd_port.dat_r[32:80] - self.submodules.fsm = fsm = FSM(reset_state="CLEAR") + # Clear Timer to clear table every 100ms. + self.clear_timer = WaitTimer(100e-3*clk_freq) + self.comb += self.clear_timer.wait.eq(~self.clear_timer.done) + + # FSM. + self.fsm = fsm = FSM(reset_state="CLEAR") fsm.act("CLEAR", mem_wr_port.we.eq(1), mem_wr_port.adr.eq(update_count), @@ -204,6 +214,10 @@ class LiteEthARPCache(Module): If(self.request.valid, NextValue(search_count, 0), NextState("MEM_SEARCH") + ), + If(self.clear_timer.done, + NextValue(update_count, 0), + NextState("CLEAR") ) ) fsm.act("MEM_UPDATE", From ea45c8704f3afc8663e8cb4d1622ffbcee8c1399 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 31 Jul 2023 17:26:58 +0200 Subject: [PATCH 11/11] core/arp: Add enable signals for Cache/Clear for optional external control. --- liteeth/core/arp.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py index fac1722..5edfbb8 100644 --- a/liteeth/core/arp.py +++ b/liteeth/core/arp.py @@ -165,6 +165,10 @@ class LiteEthARPCache(LiteXModule): self.request = stream.Endpoint([("ip_address", 32)]) self.response = stream.Endpoint([("mac_address", 48), ("error", 1)]) + # Enable. + self.enable = Signal(reset=1) + self.clear_enable = Signal(reset=1) + # # # # Parameters. @@ -208,14 +212,14 @@ class LiteEthARPCache(LiteXModule): ) ) fsm.act("IDLE", - If(self.update.valid, + If(self.enable & self.update.valid, NextState("MEM_UPDATE") ), - If(self.request.valid, + If(self.enable & self.request.valid, NextValue(search_count, 0), NextState("MEM_SEARCH") ), - If(self.clear_timer.done, + If(self.clear_enable & self.clear_timer.done, NextValue(update_count, 0), NextState("CLEAR") )