etherbone_magic = 0x4e6f
etherbone_version = 1
-etherbone_header_len = 8
-etherbone_header = {
+etherbone_packet_header_len = 8
+etherbone_packet_header = {
"magic": HField( 0, 0, 16),
"version": HField( 2, 4, 4),
_layout.append((k, v.width))
return _layout
+def _remove_from_layout(layout, *args):
+ r = []
+ for f in layout:
+ remove = False
+ for arg in args:
+ if f[0] == arg:
+ remove = True
+ if not remove:
+ r.append(f)
+ return r
+
def eth_phy_description(dw):
payload_layout = [
("data", dw),
]
return EndpointDescription(payload_layout, param_layout, packetized=True)
-def eth_etherbone_description(dw):
+def eth_etherbone_packet_description(dw):
payload_layout = [
("data", dw),
("error", dw//8)
]
- param_layout = _layout_from_header(etherbone_header)
+ param_layout = _layout_from_header(etherbone_packet_header)
return EndpointDescription(payload_layout, param_layout, packetized=True)
-def eth_etherbone_description(dw):
- payload_layout = [
- ("data", dw),
- ("error", dw//8)
- ]
- param_layout = _layout_from_header(etherbone_header)
+def eth_etherbone_packet_user_description(dw):
+ payload_layout = [("data", dw)]
+ param_layout = _layout_from_header(etherbone_packet_header)
+ param_layout = _remove_from_layout(param_layout, "magic", "portsize", "addrsize", "version")
+ param_layout += eth_udp_user_description(dw).param_layout
return EndpointDescription(payload_layout, param_layout, packetized=True)
-def eth_etherbone_user_description(dw):
- payload_layout = [
- ("data", dw),
- ("error", dw//8)
- ]
- param_layout = [
- ("length", 16),
- ("ip_address", 32),
- ("wcount", 8),
- ("rcount", 8)
- ]
+def eth_etherbone_record_description(dw):
+ payload_layout = [("data", dw)]
+ param_layout = _layout_from_header(etherbone_record_header)
return EndpointDescription(payload_layout, param_layout, packetized=True)
-
# Generic classes
class Port:
def connect(self, port):
from liteeth.common import *
from liteeth.core.etherbone import common
+from liteeth.core.etherbone.packet import *
-class LiteEthEtherboneTX(Module):
- def __init__(self, udp_port):
- self.sink = sink = Sink(eth_etherbone_user_description(32))
- self.source = source = Source(eth_udp_user_description(32))
- ###
- self.submodules.packetizer = packetizer = LiteEthEtherbonePacketizer()
- self.comb += [
- packetizer.sink.stb.eq(sink.stb),
- packetizer.sink.sop.eq(sink.sop),
- packetizer.sink.eop.eq(sink.eop),
- sink.ack.eq(packetizer.sink.ack),
-
- packetizer.sink.magic.eq(etherbone_magic),
- packetizer.sink.portsize.eq(32), # XXX
- packetizer.sink.addrsize.eq(32), # XXX
- packetizer.sink.pf.eq(0), # XXX
- packetizer.sink.version.eq(etherbone_version),
-
- packetizer.sink.wff.eq(0), # XXX
- packetizer.sink.wca.eq(0), # XXX
- packetizer.sink.cyc.eq(0), # XXX
- packetizer.sink.rff.eq(0), # XXX
- packetizer.sink.rca.eq(0), # XXX
- packetizer.sink.bca.eq(0), # XXX
-
- packetizer.sink.rcount.eq(sink.rcount),
- packetier.sink.wconut.eq(sink.wcount),
-
- packetizer.sink.data.eq(sink.data)
- ]
-
- self.submodules.fsm = fsm = FSM(reset_state="IDLE")
- fsm.act("IDLE",
- packetizer.source.ack.eq(1),
- If(packetizer.source.stb & packetizer.source.sop,
- packetizer.source.ack.eq(0),
- NextState("SEND")
- )
- )
- self.comb += [
- source.src_port.eq(0x1234), # XXX,
- source.dst_port.eq(udp_port),
- source.ip_address.eq(sink.ip_address),
- source.length.eq(sink.length + eth_etherbone_header_len)
- ]
- fsm.act("SEND",
- Record.connect(packetizer.source, source),
- If(source.stb & source.eop & source.ack,
- NextState("IDLE")
- )
- )
-
-class LiteEthEtherboneRX(Module):
- def __init__(self):
- self.sink = sink = Sink(eth_udp_user_description(32))
- self.source = source = Source(eth_etherbone_user_description(32))
- ###
- self.submodules.depacketizer = depacketizer = LiteEtherboneDepacketizer()
- self.comb += Record.connect(sink, depacketizer.sink)
+class LiteEthEtherbone(Module):
+ def __init__(self, udp, udp_port):
+ self.submodules.packet = packet = LiteEthEtherbonePacket(udp, udp_port)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
- depacketizer.source.ack.eq(1),
- If(depacketizer.source.stb & depacketizer.source.sop,
- depacketizer.source.ack.eq(0),
- NextState("CHECK")
- )
- )
- valid = Signal()
- self.sync += valid.eq(
- depacketizer.source.stb &
- (depacketizer.source.magic == etherbone_magic) &
- (depacketizer.source.version == etherbone_version)
- )
-
- fsm.act("CHECK",
- If(valid,
- NextState("PRESENT")
- ).Else(
- NextState("DROP")
+ packet.source.ack.eq(1),
+ If(packet.source.stb & packet.source.sop,
+ If(packet.source.pf,
+ packet.source.ack.eq(0),
+ NextState("SEND_PROBE_RESPONSE")
+ )
)
)
- self.comb += [
- source.sop.eq(depacketizer.source.sop),
- source.eop.eq(depacketizer.source.eop),
- source.rcount.eq(depacketizer.source.rcount),
- source.wcount.eq(depacketizer.source.wcount),
- source.data.eq(depacketizer.source.data),
- source.error.eq(depacketizer.source.error)
- ]
- fsm.act("PRESENT",
- source.stb.eq(depacketizer.source.stb),
- depacketizer.source.ack.eq(source.ack),
- If(source.stb & source.eop & source.ack,
+ fsm.act("SEND_PROBE_RESPONSE",
+ packet.sink.stb.eq(1),
+ packet.sink.sop.eq(1),
+ packet.sink.eop.eq(1),
+ packet.sink.pr.eq(1),
+ packet.sink.ip_address.eq(packet.source.ip_address),
+ packet.sink.length.eq(0),
+ If(packet.sink.ack,
+ packet.source.ack.eq(1),
NextState("IDLE")
)
)
- fsm.act("DROP",
- depacketizer.source.ack.eq(1),
- If(depacketizer.source.stb & depacketizer.source.eop & depacketizer.source.ack,
- NextState("IDLE")
- )
- )
-
-class LiteEthEtherbone(Module):
- def __init__(self, udp, udp_port):
- self.submodules.tx = tx = LiteEthEtherboneTX(udp_port)
- self.submodules.rx = rx = LiteEthEtherboneRX()
- udp_port = udp.crossbar.get_port(udp_port, dw=32)
- self.comb += [
- Record.connect(tx.source, udp_port.sink),
- Record.connect(udp_port.source, rx.sink)
- ]
- self.master = master = LiteEthEtherboneWishboneMaster()
- self.comb += [
- Record.connect(rx.source.connect(master.sink)),
- Record.connect(master.source.connect(tx.sink))
- ]
from liteeth.common import *
-from liteeth.generic.depacketizer import LiteEthDepacketizer
-from liteeth.generic.packetizer import LiteEthPacketizer
-
-class LiteEthEtherboneDepacketizer(LiteEthDepacketizer):
- def __init__(self):
- LiteEthDepacketizer.__init__(self,
- eth_udp_user_description(32),
- eth_etherbone_description(32),
- etherbone_header,
- etherbone_header_len)
-
-class LiteEthEtherbonePacketizer(LiteEthPacketizer):
- def __init__(self):
- LiteEthPacketizer.__init__(self,
- eth_etherbone_description(32),
- eth_udp_user_description(32),
- etherbone_header,
- etherbone_header_len)
--- /dev/null
+from liteeth.common import *
+from liteeth.generic.depacketizer import LiteEthDepacketizer
+from liteeth.generic.packetizer import LiteEthPacketizer
+from liteeth.core.etherbone import common
+
+class LiteEthEtherbonePacketPacketizer(LiteEthPacketizer):
+ def __init__(self):
+ LiteEthPacketizer.__init__(self,
+ eth_etherbone_packet_description(32),
+ eth_udp_user_description(32),
+ etherbone_packet_header,
+ etherbone_packet_header_len)
+
+class LiteEthEtherbonePacketTX(Module):
+ def __init__(self, udp_port):
+ self.sink = sink = Sink(eth_etherbone_packet_user_description(32))
+ self.source = source = Source(eth_udp_user_description(32))
+ ###
+ self.submodules.packetizer = packetizer = LiteEthEtherbonePacketPacketizer()
+ self.comb += [
+ packetizer.sink.stb.eq(sink.stb),
+ packetizer.sink.sop.eq(sink.sop),
+ packetizer.sink.eop.eq(sink.eop),
+ sink.ack.eq(packetizer.sink.ack),
+
+ packetizer.sink.magic.eq(etherbone_magic),
+ packetizer.sink.port_size.eq(32//8),
+ packetizer.sink.addr_size.eq(32//8), # XXX add a parameter?
+ packetizer.sink.pf.eq(sink.pf),
+ packetizer.sink.pr.eq(sink.pr),
+ packetizer.sink.nr.eq(sink.nr),
+ packetizer.sink.version.eq(etherbone_version),
+
+ packetizer.sink.data.eq(sink.data)
+ ]
+ self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ packetizer.source.ack.eq(1),
+ If(packetizer.source.stb & packetizer.source.sop,
+ packetizer.source.ack.eq(0),
+ NextState("SEND")
+ )
+ )
+ fsm.act("SEND",
+ Record.connect(packetizer.source, source),
+ source.src_port.eq(0x1234), # XXX,
+ source.dst_port.eq(udp_port),
+ source.ip_address.eq(sink.ip_address),
+ source.length.eq(sink.length + etherbone_packet_header_len),
+ If(source.stb & source.eop & source.ack,
+ NextState("IDLE")
+ )
+ )
+
+class LiteEthEtherbonePacketDepacketizer(LiteEthDepacketizer):
+ def __init__(self):
+ LiteEthDepacketizer.__init__(self,
+ eth_udp_user_description(32),
+ eth_etherbone_packet_description(32),
+ etherbone_packet_header,
+ etherbone_packet_header_len)
+
+class LiteEthEtherbonePacketRX(Module):
+ def __init__(self):
+ self.sink = sink = Sink(eth_udp_user_description(32))
+ self.source = source = Source(eth_etherbone_packet_user_description(32))
+ ###
+ self.submodules.depacketizer = depacketizer = LiteEthEtherbonePacketDepacketizer()
+ self.comb += Record.connect(sink, depacketizer.sink)
+
+ self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+ fsm.act("IDLE",
+ depacketizer.source.ack.eq(1),
+ If(depacketizer.source.stb & depacketizer.source.sop,
+ depacketizer.source.ack.eq(0),
+ NextState("CHECK")
+ )
+ )
+ valid = Signal()
+ self.sync += valid.eq(
+ depacketizer.source.stb &
+ (depacketizer.source.magic == etherbone_magic)
+ )
+ fsm.act("CHECK",
+ If(valid,
+ NextState("PRESENT")
+ ).Else(
+ NextState("DROP")
+ )
+ )
+ self.comb += [
+ source.sop.eq(depacketizer.source.sop),
+ source.eop.eq(depacketizer.source.eop),
+
+ source.pf.eq(depacketizer.source.pf),
+ source.pr.eq(depacketizer.source.pr),
+ source.nr.eq(depacketizer.source.nr),
+
+ source.src_port.eq(sink.src_port),
+ source.dst_port.eq(sink.dst_port),
+ source.ip_address.eq(sink.ip_address),
+ source.length.eq(sink.length - etherbone_packet_header_len)
+ ]
+ fsm.act("PRESENT",
+ source.stb.eq(depacketizer.source.stb),
+ depacketizer.source.ack.eq(source.ack),
+ If(source.stb & source.eop & source.ack,
+ NextState("IDLE")
+ )
+ )
+ fsm.act("DROP",
+ depacketizer.source.ack.eq(1),
+ If(depacketizer.source.stb & depacketizer.source.eop & depacketizer.source.ack,
+ NextState("IDLE")
+ )
+ )
+
+class LiteEthEtherbonePacket(Module):
+ def __init__(self, udp, udp_port):
+ self.submodules.tx = tx = LiteEthEtherbonePacketTX(udp_port)
+ self.submodules.rx = rx = LiteEthEtherbonePacketRX()
+ udp_port = udp.crossbar.get_port(udp_port, dw=32)
+ self.comb += [
+ Record.connect(tx.source, udp_port.sink),
+ Record.connect(udp_port.source, rx.sink)
+ ]
+ self.sink, self.source = self.tx.sink, self.rx.source
)
)
)
+ no_payload = Signal()
self.sync += \
If(fsm.before_entering("COPY"),
- source.sop.eq(1)
+ source.sop.eq(1),
+ no_payload.eq(sink.eop)
).Elif(source.stb & source.ack,
source.sop.eq(0)
)
self.comb += [
- source.eop.eq(sink.eop),
+ source.eop.eq(sink.eop | no_payload),
source.data.eq(sink.data),
source.error.eq(sink.error),
_decode_header(header_type, self.header, source)
]
fsm.act("COPY",
sink.ack.eq(source.ack),
- source.stb.eq(sink.stb),
+ source.stb.eq(sink.stb | no_payload),
If(source.stb & source.ack & source.eop,
NextState("IDLE")
)
icmp_tb:
$(CMD) icmp_tb.py
+
+etherbone_tb:
+ $(CMD) etherbone_tb.py
--- /dev/null
+from migen.fhdl.std import *
+from migen.bus import wishbone
+from migen.bus.transactions import *
+from migen.sim.generic import run_simulation
+
+from liteeth.common import *
+from liteeth.core import LiteEthUDPIPCore
+from liteeth.core.etherbone import LiteEthEtherbone
+
+from liteeth.test.common import *
+from liteeth.test.model import phy, mac, arp, ip, udp, etherbone
+
+ip_address = 0x12345678
+mac_address = 0x12345678abcd
+
+class TB(Module):
+ def __init__(self):
+ self.submodules.phy_model = phy.PHY(8, debug=True)
+ self.submodules.mac_model = mac.MAC(self.phy_model, debug=True, loopback=False)
+ self.submodules.arp_model = arp.ARP(self.mac_model, mac_address, ip_address, debug=False)
+ self.submodules.ip_model = ip.IP(self.mac_model, mac_address, ip_address, debug=True, loopback=False)
+ self.submodules.udp_model = udp.UDP(self.ip_model, ip_address, debug=True, loopback=False)
+ self.submodules.etherbone_model = etherbone.Etherbone(self.udp_model, debug=True)
+
+ self.submodules.core = LiteEthUDPIPCore(self.phy_model, mac_address, ip_address, 100000)
+ self.submodules.etherbone = LiteEthEtherbone(self.core.udp, 20000)
+
+ # use sys_clk for each clock_domain
+ self.clock_domains.cd_eth_rx = ClockDomain()
+ self.clock_domains.cd_eth_tx = ClockDomain()
+ self.comb += [
+ self.cd_eth_rx.clk.eq(ClockSignal()),
+ self.cd_eth_rx.rst.eq(ResetSignal()),
+ self.cd_eth_tx.clk.eq(ClockSignal()),
+ self.cd_eth_tx.rst.eq(ResetSignal()),
+ ]
+
+ def gen_simulation(self, selfp):
+ selfp.cd_eth_rx.rst = 1
+ selfp.cd_eth_tx.rst = 1
+ yield
+ selfp.cd_eth_rx.rst = 0
+ selfp.cd_eth_tx.rst = 0
+
+ for i in range(100):
+ yield
+
+ # test probe
+ packet = etherbone.EtherbonePacket()
+ packet.pf = 1
+ self.etherbone_model.send(packet)
+
+if __name__ == "__main__":
+ run_simulation(TB(), ncycles=1024, vcd_name="my.vcd", keep_files=True)
\ No newline at end of file
self.encoded = init != []
self.records = []
+ self.magic = etherbone_magic
+ self.version = etherbone_version
+ self.addr_size = 32//8
+ self.port_size = 32//8
+ self.nr = 0
+ self.pr = 0
+ self.pf = 0
+
def get_records(self):
records = []
done = False
if not self.encoded:
raise ValueError
header = []
- for byte in self[:etherbone_header_len]:
+ for byte in self[:etherbone_packet_header_len]:
header.append(self.pop(0))
- for k, v in sorted(etherbone_header.items()):
+ for k, v in sorted(etherbone_packet_header.items()):
setattr(self, k, get_field_data(v, header))
self.records = self.get_records()
self.encoded = False
raise ValueError
self.set_records(self.records)
header = 0
- for k, v in sorted(etherbone_header.items()):
+ for k, v in sorted(etherbone_packet_header.items()):
value = merge_bytes(split_bytes(getattr(self, k), math.ceil(v.width/8)), "little")
header += (value << v.offset+(v.byte*8))
- for d in split_bytes(header, etherbone_header_len):
+ for d in split_bytes(header, etherbone_packet_header_len):
self.insert(0, d)
self.encoded = True
for d in self:
r += "{:02x}".format(d)
else:
- for k in sorted(etherbone_header.keys()):
+ for k in sorted(etherbone_packet_header.keys()):
r += k + " : 0x{:0x}\n".format(getattr(self,k))
for i, record in enumerate(self.records):
r += record.__repr__(i)
self.tx_packet = EtherbonePacket()
self.rx_packet = EtherbonePacket()
- self.udp.set_etherbone_callback(self.callback)
+ udp.set_etherbone_callback(self.callback)
def send(self, packet):
packet.encode()
print_etherbone(">>>>>>>>")
print_etherbone(packet)
udp_packet = udp.UDPPacket(packet)
- udp_packet.src_port = 0x1234
- udp_packet.dst_port = 0x5678
+ udp_packet.src_port = 0x1234 # XXX
+ udp_packet.dst_port = 20000 # XXX
udp_packet.length = len(packet)
udp_packet.checksum = 0
self.udp.send(udp_packet)
def callback(self, packet):
- packet = Etherbone(packet)
+ packet = EtherbonePacket(packet)
packet.decode()
if self.debug:
print_etherbone("<<<<<<<<")
# Packet
packet = EtherbonePacket()
packet.records = [copy.deepcopy(record) for i in range(8)]
- packet.magic = etherbone_magic
- packet.version = etherbone_version
packet.nr = 0
packet.pr = 0
packet.pf = 0
- packet.addr_size = 32//8
- packet.port_size = 32//8
#print(packet)
packet.encode()
#print(packet)
self.ip.set_udp_callback(self.callback)
- def set_etherbone_callback(callback):
+ def set_etherbone_callback(self, callback):
self.etherbone_callback = callback
def send(self, packet):
self.process(packet)
def process(self, packet):
- if packet.dst_port == 22000:
+ if packet.dst_port == 20000:
if self.etherbone_callback is not None:
self.etherbone_callback(packet)