From 226d1afd9a010817586fcc6681c175a6e793eb98 Mon Sep 17 00:00:00 2001 From: Fischer Moseley <42497969+fischermoseley@users.noreply.github.com> Date: Fri, 2 Jan 2026 13:19:50 -0700 Subject: [PATCH] ethernet: use new bridge in EthernetInterface --- src/manta/ethernet/__init__.py | 26 +++--- ether.py => src/manta/ethernet/bridge.py | 114 +---------------------- src/manta/ethernet/sink_bridge.py | 32 ------- src/manta/ethernet/source_bridge.py | 43 --------- src/manta/utils.py | 11 ++- test/test_ether_bridge_sim.py | 107 +++++++++++++++++++++ 6 files changed, 130 insertions(+), 203 deletions(-) rename ether.py => src/manta/ethernet/bridge.py (68%) delete mode 100644 src/manta/ethernet/sink_bridge.py delete mode 100644 src/manta/ethernet/source_bridge.py create mode 100644 test/test_ether_bridge_sim.py diff --git a/src/manta/ethernet/__init__.py b/src/manta/ethernet/__init__.py index fd6cc63..4baad57 100644 --- a/src/manta/ethernet/__init__.py +++ b/src/manta/ethernet/__init__.py @@ -4,8 +4,7 @@ from random import getrandbits from amaranth import * from amaranth.hdl import IOPort -from manta.ethernet.sink_bridge import UDPSinkBridge -from manta.ethernet.source_bridge import UDPSourceBridge +from manta.ethernet.bridge import EthernetBridge from manta.utils import * @@ -517,21 +516,20 @@ class EthernetInterface(Elaboratable): if platform: platform.add_file("liteeth.v", self.generate_liteeth_core()) - m.submodules.source_bridge = source_bridge = UDPSourceBridge() - m.submodules.sink_bridge = sink_bridge = UDPSinkBridge() + m.submodules.bridge = bridge = EthernetBridge() - m.d.comb += source_bridge.data_i.eq(self._source_data) - m.d.comb += source_bridge.last_i.eq(self._source_last) - m.d.comb += self._source_ready.eq(source_bridge.ready_o) - m.d.comb += source_bridge.valid_i.eq(self._source_valid) + m.d.comb += bridge.data_i.eq(self._source_data) + m.d.comb += bridge.last_i.eq(self._source_last) + m.d.comb += self._source_ready.eq(bridge.ready_o) + m.d.comb += bridge.valid_i.eq(self._source_valid) - m.d.comb += self._sink_data.eq(sink_bridge.data_o) - m.d.comb += self._sink_last.eq(sink_bridge.last_o) - m.d.comb += sink_bridge.ready_i.eq(self._sink_ready) - m.d.comb += self._sink_valid.eq(sink_bridge.valid_o) + m.d.comb += self._sink_data.eq(bridge.data_o) + m.d.comb += self._sink_last.eq(bridge.last_o) + m.d.comb += bridge.ready_i.eq(self._sink_ready) + m.d.comb += self._sink_valid.eq(bridge.valid_o) - m.d.comb += sink_bridge.bus_i.eq(self.bus_i) - m.d.comb += self.bus_o.eq(source_bridge.bus_o) + m.d.comb += bridge.bus_i.eq(self.bus_i) + m.d.comb += self.bus_o.eq(bridge.bus_o) return m diff --git a/ether.py b/src/manta/ethernet/bridge.py similarity index 68% rename from ether.py rename to src/manta/ethernet/bridge.py index 132006e..9e3ef7f 100644 --- a/ether.py +++ b/src/manta/ethernet/bridge.py @@ -1,19 +1,8 @@ -# Test with 32-bit data/valid/ready/last interface for input, and one for output - from amaranth import * -from amaranth.lib.enum import IntEnum from manta.utils import * -class MessageTypes(IntEnum, shape=unsigned(3)): - READ_REQUEST = 0 - WRITE_REQUEST = 1 - READ_RESPONSE = 2 - WRITE_RESPONSE = 3 - NACK = 4 - - class EthernetBridge(Elaboratable): def __init__(self): self.data_i = Signal(32) @@ -116,7 +105,7 @@ class EthernetBridge(Elaboratable): with m.State("WRITE_WAIT_FOR_ADDR"): with m.If(self.valid_i): - m.d.sync += self.bus_i.addr.eq(self.data_i) + m.d.sync += self.bus_o.addr.eq(self.data_i) m.next = "WRITE_FIRST" # Don't want to increment address on the first write, @@ -177,104 +166,3 @@ class EthernetBridge(Elaboratable): m.next = "IDLE" return m - - -# Actual testing below! - -ether_bridge = EthernetBridge() - -from random import randint - - -async def send_bytes(ctx, bytes): - ctx.set(ether_bridge.ready_i, 1) - ctx.set(ether_bridge.valid_i, 1) - - for i, byte in enumerate(bytes): - ctx.set(ether_bridge.data_i, byte) - ctx.set(ether_bridge.last_i, i == len(bytes) - 1) - - while not ctx.get(ether_bridge.ready_o): - await ctx.tick() - - await ctx.tick() - - ctx.set(ether_bridge.data_i, 0) - ctx.set(ether_bridge.last_i, 0) - ctx.set(ether_bridge.valid_i, 0) - await ctx.tick() - - -async def send_bytes_sporadic(ctx, bytes): - ctx.set(ether_bridge.ready_i, 1) - ctx.set(ether_bridge.valid_i, 1) - - for i, byte in enumerate(bytes): - if randint(0, 1): - ctx.set(ether_bridge.valid_i, 0) - for _ in range(0, randint(1, 4)): - await ctx.tick() - - ctx.set(ether_bridge.valid_i, 1) - ctx.set(ether_bridge.data_i, byte) - ctx.set(ether_bridge.last_i, i == len(bytes) - 1) - - while not ctx.get(ether_bridge.ready_o): - await ctx.tick() - - await ctx.tick() - - ctx.set(ether_bridge.data_i, 0) - ctx.set(ether_bridge.last_i, 0) - ctx.set(ether_bridge.valid_i, 0) - await ctx.tick() - - -# - type: 3 bits -# - seq_num: 13 bits -# - length (only if read request): 7 bits - - -async def send_write_request(ctx, seq_num, addr, write_data): - await send_bytes_sporadic( - ctx, [(seq_num << 3) | MessageTypes.WRITE_REQUEST, addr] + write_data - ) - - -async def send_read_request(ctx, seq_num, addr, read_length): - await send_bytes_sporadic( - ctx, [(read_length << 16) | (seq_num << 3) | MessageTypes.READ_REQUEST, addr] - ) - - -@simulate(ether_bridge) -async def test_ether_bridge(ctx): - await ctx.tick() - await ctx.tick() - await ctx.tick() - - # Send a read request with a bad sequence number - # await send_read_request(ctx, seq_num=1, addr=0, read_length=1) - # await ctx.tick() - # await send_read_request(ctx, seq_num=1, addr=1, read_length=1) - # await ctx.tick() - - # await send_write_request(ctx, seq_num=0, addr=0x1234_5678, write_data=[0x0000_0000, 0x1111_1111, 0x2222_2222]) - # ctx.tick() - - await send_write_request( - ctx, - seq_num=0, - addr=0x1234_5678, - write_data=[0x0000_0000, 0x1111_1111, 0x2222_2222, 0x3333_3333], - ) - # await send_write_request(ctx, seq_num=4, addr=0x1234_5678, write_data=[0x0000_0000, 0x1111_1111, 0x2222_2222]) - # await send_read_request(ctx, seq_num=0, addr=0x1234_5678, read_length=10) - # await send_bytes(ctx, [0x0123_4567]) - # await send_bytes(ctx, [0x0123_4567, 0x89AB_CDEF]) - # await send_bytes(ctx, [0x0123_4567, 0x89AB_CDEF, 0x0123_4567]) - # await send_bytes(ctx, [0x0123_4567, 0x89AB_CDEF, 0x0123_4567, 0x89AB_CDEF]) - ctx.tick() - - for _ in range(20): - await ctx.tick() diff --git a/src/manta/ethernet/sink_bridge.py b/src/manta/ethernet/sink_bridge.py deleted file mode 100644 index 27b065b..0000000 --- a/src/manta/ethernet/sink_bridge.py +++ /dev/null @@ -1,32 +0,0 @@ -from amaranth import * - -from manta.utils import * - - -class UDPSinkBridge(Elaboratable): - """ - A module for bridging Manta's internal bus to an AXI stream of UDP packet - data. Connects to the LiteEth core's "sink" port. - """ - - def __init__(self): - self.bus_i = Signal(InternalBus()) - - self.data_o = Signal(32) - self.last_o = Signal() - self.ready_i = Signal() - self.valid_o = Signal() - - def elaborate(self, platform): - m = Module() - - m.d.sync += self.data_o.eq(0) - m.d.sync += self.last_o.eq(0) - m.d.sync += self.valid_o.eq(0) - - with m.If((self.bus_i.valid) & (~self.bus_i.rw)): - m.d.sync += self.data_o.eq(self.bus_i.data) - m.d.sync += self.last_o.eq(self.bus_i.last) - m.d.sync += self.valid_o.eq(1) - - return m diff --git a/src/manta/ethernet/source_bridge.py b/src/manta/ethernet/source_bridge.py deleted file mode 100644 index 83c2127..0000000 --- a/src/manta/ethernet/source_bridge.py +++ /dev/null @@ -1,43 +0,0 @@ -from amaranth import * - -from manta.utils import * - - -class UDPSourceBridge(Elaboratable): - """ - A module for bridging the AXI-stream of incoming UDP packet data to Manta's - internal bus. Connects to the LiteEth core's "source" port. - """ - - def __init__(self): - self.bus_o = Signal(InternalBus()) - - self.data_i = Signal(32) - self.last_i = Signal() - self.ready_o = Signal() - self.valid_i = Signal() - - def elaborate(self, platform): - m = Module() - - state = Signal() # Can either be 0, for read/write, or 1, for data - rw_buf = Signal().like(self.bus_o.rw) - - # Can always take more data - m.d.sync += self.ready_o.eq(1) - - m.d.sync += self.bus_o.eq(0) - with m.If(self.valid_i): - m.d.sync += state.eq(~state) - - with m.If(state == 0): - m.d.sync += rw_buf.eq(self.data_i) - - with m.Else(): - m.d.sync += self.bus_o.addr.eq(self.data_i[:16]) - m.d.sync += self.bus_o.data.eq(self.data_i[16:]) - m.d.sync += self.bus_o.rw.eq(rw_buf) - m.d.sync += self.bus_o.valid.eq(1) - m.d.sync += self.bus_o.last.eq(self.last_i) - - return m diff --git a/src/manta/utils.py b/src/manta/utils.py index 953a6a6..dad03dd 100644 --- a/src/manta/utils.py +++ b/src/manta/utils.py @@ -3,8 +3,9 @@ from abc import ABC, abstractmethod from pathlib import Path from random import sample -from amaranth import Elaboratable +from amaranth import Elaboratable, unsigned from amaranth.lib import data +from amaranth.lib.enum import IntEnum from amaranth.sim import Simulator @@ -102,6 +103,14 @@ class InternalBus(data.StructLayout): ) +class MessageTypes(IntEnum, shape=unsigned(3)): + READ_REQUEST = 0 + WRITE_REQUEST = 1 + READ_RESPONSE = 2 + WRITE_RESPONSE = 3 + NACK = 4 + + def warn(message): """ Prints a warning to the user's terminal. Originally the warn() method diff --git a/test/test_ether_bridge_sim.py b/test/test_ether_bridge_sim.py new file mode 100644 index 0000000..a81253b --- /dev/null +++ b/test/test_ether_bridge_sim.py @@ -0,0 +1,107 @@ +# Test with 32-bit data/valid/ready/last interface for input, and one for output + +from amaranth import * +from amaranth.lib.enum import IntEnum + +from manta.ethernet import EthernetBridge +from manta.utils import * + +# Actual testing below! + +ether_bridge = EthernetBridge() + +from random import randint + + +async def send_bytes(ctx, bytes): + ctx.set(ether_bridge.ready_i, 1) + ctx.set(ether_bridge.valid_i, 1) + + for i, byte in enumerate(bytes): + ctx.set(ether_bridge.data_i, byte) + ctx.set(ether_bridge.last_i, i == len(bytes) - 1) + + while not ctx.get(ether_bridge.ready_o): + await ctx.tick() + + await ctx.tick() + + ctx.set(ether_bridge.data_i, 0) + ctx.set(ether_bridge.last_i, 0) + ctx.set(ether_bridge.valid_i, 0) + await ctx.tick() + + +async def send_bytes_sporadic(ctx, bytes): + ctx.set(ether_bridge.ready_i, 1) + ctx.set(ether_bridge.valid_i, 1) + + for i, byte in enumerate(bytes): + if randint(0, 1): + ctx.set(ether_bridge.valid_i, 0) + for _ in range(0, randint(1, 4)): + await ctx.tick() + + ctx.set(ether_bridge.valid_i, 1) + ctx.set(ether_bridge.data_i, byte) + ctx.set(ether_bridge.last_i, i == len(bytes) - 1) + + while not ctx.get(ether_bridge.ready_o): + await ctx.tick() + + await ctx.tick() + + ctx.set(ether_bridge.data_i, 0) + ctx.set(ether_bridge.last_i, 0) + ctx.set(ether_bridge.valid_i, 0) + await ctx.tick() + + +# - type: 3 bits +# - seq_num: 13 bits +# - length (only if read request): 7 bits + + +async def send_write_request(ctx, seq_num, addr, write_data): + await send_bytes_sporadic( + ctx, [(seq_num << 3) | MessageTypes.WRITE_REQUEST, addr] + write_data + ) + + +async def send_read_request(ctx, seq_num, addr, read_length): + await send_bytes_sporadic( + ctx, [(read_length << 16) | (seq_num << 3) | MessageTypes.READ_REQUEST, addr] + ) + + +@simulate(ether_bridge) +async def test_ether_bridge(ctx): + await ctx.tick() + await ctx.tick() + await ctx.tick() + + # Send a read request with a bad sequence number + # await send_read_request(ctx, seq_num=1, addr=0, read_length=1) + # await ctx.tick() + # await send_read_request(ctx, seq_num=1, addr=1, read_length=1) + # await ctx.tick() + + # await send_write_request(ctx, seq_num=0, addr=0x1234_5678, write_data=[0x0000_0000, 0x1111_1111, 0x2222_2222]) + # ctx.tick() + + await send_write_request( + ctx, + seq_num=0, + addr=0x1234_5678, + write_data=[0x0000_0000, 0x1111_1111, 0x2222_2222, 0x3333_3333], + ) + # await send_write_request(ctx, seq_num=4, addr=0x1234_5678, write_data=[0x0000_0000, 0x1111_1111, 0x2222_2222]) + # await send_read_request(ctx, seq_num=0, addr=0x1234_5678, read_length=10) + # await send_bytes(ctx, [0x0123_4567]) + # await send_bytes(ctx, [0x0123_4567, 0x89AB_CDEF]) + # await send_bytes(ctx, [0x0123_4567, 0x89AB_CDEF, 0x0123_4567]) + # await send_bytes(ctx, [0x0123_4567, 0x89AB_CDEF, 0x0123_4567, 0x89AB_CDEF]) + ctx.tick() + + for _ in range(20): + await ctx.tick()