core/arp: Switch LiteEthARPCache to a proper Memory and allow multiple entries.
This commit is contained in:
parent
dc7ed0de6f
commit
b74618d1ed
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue