core/arp: Switch LiteEthARPCache to a proper Memory and allow multiple entries.

This commit is contained in:
Florent Kermarrec 2023-07-31 16:15:10 +02:00
parent dc7ed0de6f
commit b74618d1ed
2 changed files with 80 additions and 33 deletions

View File

@ -15,7 +15,7 @@ from liteeth.core.icmp import LiteEthICMP
# IP Core ------------------------------------------------------------------------------------------ # IP Core ------------------------------------------------------------------------------------------
class LiteEthIPCore(Module, AutoCSR): 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_icmp = True,
with_ip_broadcast = True, with_ip_broadcast = True,
with_sys_datapath = False, with_sys_datapath = False,
@ -49,6 +49,7 @@ class LiteEthIPCore(Module, AutoCSR):
mac_address = mac_address, mac_address = mac_address,
ip_address = ip_address, ip_address = ip_address,
clk_freq = clk_freq, clk_freq = clk_freq,
entries = arp_entries,
dw = dw, dw = dw,
) )
@ -74,7 +75,7 @@ class LiteEthIPCore(Module, AutoCSR):
# UDP IP Core -------------------------------------------------------------------------------------- # UDP IP Core --------------------------------------------------------------------------------------
class LiteEthUDPIPCore(LiteEthIPCore): 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_icmp = True,
with_ip_broadcast = True, with_ip_broadcast = True,
with_sys_datapath = False, with_sys_datapath = False,
@ -94,6 +95,7 @@ class LiteEthUDPIPCore(LiteEthIPCore):
mac_address = mac_address, mac_address = mac_address,
ip_address = ip_address, ip_address = ip_address,
clk_freq = clk_freq, clk_freq = clk_freq,
arp_entries = arp_entries,
with_icmp = with_icmp, with_icmp = with_icmp,
dw = dw, dw = dw,
with_ip_broadcast = with_ip_broadcast, with_ip_broadcast = with_ip_broadcast,

View File

@ -156,9 +156,8 @@ class LiteEthARPRX(LiteXModule):
# ARP Cache ---------------------------------------------------------------------------------------- # ARP Cache ----------------------------------------------------------------------------------------
class LiteEthARPCache(LiteXModule): class LiteEthARPCache(Module):
def __init__(self, entries, clk_freq): def __init__(self, entries, clk_freq):
assert entries == 1
# Update interface. # Update interface.
self.update = stream.Endpoint([("ip_address", 32), ("mac_address", 48)]) 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 entries = max(entries, 2)
# 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) mem_width = 32 + 48 + 1 # IP + MAC + Valid.
self.sync += [ mem = Memory(mem_width, entries)
If(self.update.valid, mem_wr_port = mem.get_port(write_capable=True)
cached_valid.eq(1), mem_rd_port = mem.get_port(async_read=True) # FIXME: Avoid async_read.
cached_ip_address.eq(self.update.ip_address), self.specials += mem, mem_wr_port, mem_rd_port
cached_mac_address.eq(self.update.mac_address),
).Else( update_count = Signal(max=entries)
If(self.cached_timer.done, search_count = Signal(max=entries)
cached_valid.eq(0) 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) fsm.act("IDLE",
If(self.update.valid,
self.comb += self.request.ready.eq(1) NextState("MEM_UPDATE")
self.comb += self.response.valid.eq(self.request.valid) ),
self.comb += self.response.error.eq(~cached_valid | (self.request.ip_address != cached_ip_address)) If(self.request.valid,
self.comb += self.response.mac_address.eq(cached_mac_address) 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 ---------------------------------------------------------------------------------------- # ARP Table ----------------------------------------------------------------------------------------
class LiteEthARPTable(LiteXModule): 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.sink = sink = stream.Endpoint(_arp_table_layout) # from arp_rx
self.source = source = stream.Endpoint(_arp_table_layout) # to arp_tx 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.request_timer = WaitTimer(100e-3*clk_freq)
self.comb += self.request_timer.wait.eq(request_pending & ~self.request_timer.done) 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") self.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE", fsm.act("IDLE",
@ -274,6 +319,7 @@ class LiteEthARPTable(LiteXModule):
NextValue(request_ip_address, request.ip_address), NextValue(request_ip_address, request.ip_address),
NextState("SEND_REQUEST") NextState("SEND_REQUEST")
).Else( ).Else(
NextValue(response.mac_address, cache.response.mac_address),
NextState("PRESENT_RESPONSE"), NextState("PRESENT_RESPONSE"),
) )
) )
@ -289,7 +335,6 @@ class LiteEthARPTable(LiteXModule):
) )
fsm.act("PRESENT_RESPONSE", fsm.act("PRESENT_RESPONSE",
response.valid.eq(1), response.valid.eq(1),
response.mac_address.eq(cache.response.mac_address),
If(response.ready, If(response.ready,
NextValue(response.failed, 0), NextValue(response.failed, 0),
NextState("IDLE") NextState("IDLE")
@ -299,10 +344,10 @@ class LiteEthARPTable(LiteXModule):
# ARP ---------------------------------------------------------------------------------------------- # ARP ----------------------------------------------------------------------------------------------
class LiteEthARP(LiteXModule): 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.tx = tx = LiteEthARPTX(mac_address, ip_address, dw)
self.rx = rx = LiteEthARPRX(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 += [ self.comb += [
rx.source.connect(table.sink), rx.source.connect(table.sink),
table.source.connect(tx.sink) table.source.connect(tx.sink)