diff --git a/liteeth/common.py b/liteeth/common.py index 969d030a4..dcfb0516d 100644 --- a/liteeth/common.py +++ b/liteeth/common.py @@ -141,6 +141,13 @@ def _remove_from_layout(layout, *args): r.append(f) return r +def eth_raw_description(dw): + payload_layout = [ + ("data", dw), + ("error", dw//8) + ] + return EndpointDescription(payload_layout, packetized=True) + def eth_phy_description(dw): payload_layout = [ ("data", dw), @@ -250,14 +257,20 @@ def eth_etherbone_packet_description(dw): return EndpointDescription(payload_layout, param_layout, packetized=True) def eth_etherbone_packet_user_description(dw): - payload_layout = [("data", dw)] + payload_layout = [ + ("data", dw), + ("error", dw//8) + ] 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_record_description(dw): - payload_layout = [("data", dw)] + payload_layout = [ + ("data", dw), + ("error", dw//8) + ] param_layout = _layout_from_header(etherbone_record_header) return EndpointDescription(payload_layout, param_layout, packetized=True) diff --git a/liteeth/core/etherbone/__init__.py b/liteeth/core/etherbone/__init__.py index 5b5bc6f83..3be1f2a02 100644 --- a/liteeth/core/etherbone/__init__.py +++ b/liteeth/core/etherbone/__init__.py @@ -1,30 +1,21 @@ from liteeth.common import * -from liteeth.core.etherbone import common + +from liteeth.generic.arbiter import Arbiter +from liteeth.generic.dispatcher import Dispatcher + from liteeth.core.etherbone.packet import * +from liteeth.core.etherbone.probe import * +from liteeth.core.etherbone.record import * class LiteEthEtherbone(Module): def __init__(self, udp, udp_port): self.submodules.packet = packet = LiteEthEtherbonePacket(udp, udp_port) + self.submodules.probe = probe = LiteEthEtherboneProbe() + self.submodules.record = record = LiteEthEtherboneRecord() - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - 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") - ) - ) - ) - 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") - ) - ) + dispatcher = Dispatcher(packet.source, [probe.sink, record.sink]) + self.comb += dispatcher.sel.eq(~packet.source.pf) + self.submodules += dispatcher + + arbiter = Arbiter([probe.source, record.source], packet.sink) + self.submodules += arbiter diff --git a/liteeth/core/etherbone/common.py b/liteeth/core/etherbone/common.py deleted file mode 100644 index 22c8c63dc..000000000 --- a/liteeth/core/etherbone/common.py +++ /dev/null @@ -1 +0,0 @@ -from liteeth.common import * diff --git a/liteeth/core/etherbone/master.py b/liteeth/core/etherbone/master.py index 7508e922c..e960d3e16 100644 --- a/liteeth/core/etherbone/master.py +++ b/liteeth/core/etherbone/master.py @@ -1,5 +1,4 @@ from liteeth.common import * -from liteeth.core.etherbone import common class LiteEthEtherboneWishboneMaster(Module): def __init__(self): diff --git a/liteeth/core/etherbone/packet.py b/liteeth/core/etherbone/packet.py index 0a2bdbef5..872e8875b 100644 --- a/liteeth/core/etherbone/packet.py +++ b/liteeth/core/etherbone/packet.py @@ -1,7 +1,6 @@ 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): diff --git a/liteeth/core/etherbone/probe.py b/liteeth/core/etherbone/probe.py new file mode 100644 index 000000000..84ba069a2 --- /dev/null +++ b/liteeth/core/etherbone/probe.py @@ -0,0 +1,24 @@ +from liteeth.common import * + +class LiteEthEtherboneProbe(Module): + def __init__(self): + self.sink = sink = Sink(eth_etherbone_packet_user_description(32)) + self.source = source = Source(eth_etherbone_packet_user_description(32)) + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("PROBE_RESPONSE") + ) + ) + fsm.act("PROBE_RESPONSE", + Record.connect(sink, source), + source.pf.eq(0), + source.pr.eq(1), + If(source.stb & source.eop & source.ack, + NextState("IDLE") + ) + ) diff --git a/liteeth/core/etherbone/record.py b/liteeth/core/etherbone/record.py new file mode 100644 index 000000000..6eec7730a --- /dev/null +++ b/liteeth/core/etherbone/record.py @@ -0,0 +1,88 @@ +from liteeth.common import * +from liteeth.generic.depacketizer import LiteEthDepacketizer +from liteeth.generic.packetizer import LiteEthPacketizer + +class LiteEthEtherboneRecordPacketizer(LiteEthPacketizer): + def __init__(self): + LiteEthPacketizer.__init__(self, + eth_etherbone_record_description(32), + eth_raw_description(32), + etherbone_record_header, + etherbone_record_header_len) + +class LiteEthEtherboneRecordTX(Module): + def __init__(self): + self.sink = sink = Sink(eth_etherbone_record_description(32)) + self.source = source = Source(eth_raw_description(32)) + ### + self.submodules.packetizer = packetizer = LiteEthEtherboneRecordPacketizer() + self.comb += Record.connect(sink, packetizer.sink) + + 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), + If(source.stb & source.eop & source.ack, + NextState("IDLE") + ) + ) + +class LiteEthEtherboneRecordDepacketizer(LiteEthDepacketizer): + def __init__(self): + LiteEthDepacketizer.__init__(self, + eth_raw_description(32), + eth_etherbone_record_description(32), + etherbone_record_header, + etherbone_record_header_len) + +class LiteEthEtherboneRecordRX(Module): + def __init__(self): + self.sink = sink = Sink(eth_raw_description(32)) + self.source = source = Source(eth_etherbone_record_description(32)) + ### + self.submodules.depacketizer = depacketizer = LiteEthEtherboneRecordDepacketizer() + 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(1) # XXX + fsm.act("CHECK", + If(valid, + NextState("PRESENT") + ).Else( + NextState("DROP") + ) + ) + fsm.act("PRESENT", + Record.connect(depacketizer.source, source), + 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 LiteEthEtherboneRecord(Module): + def __init__(self): + self.sink = sink = Sink(eth_etherbone_packet_user_description(32)) + self.source = source = Sink(eth_etherbone_packet_user_description(32)) + ### + self.submodules.record_tx = record_tx = LiteEthEtherboneRecordTX() + self.submodules.record_rx = record_rx = LiteEthEtherboneRecordRX() diff --git a/liteeth/generic/depacketizer.py b/liteeth/generic/depacketizer.py index e43885793..fb1a1b394 100644 --- a/liteeth/generic/depacketizer.py +++ b/liteeth/generic/depacketizer.py @@ -16,36 +16,50 @@ class LiteEthDepacketizer(Module): ### dw = flen(sink.data) + header_words = (header_length*8)//dw + shift = Signal() - counter = Counter(max=header_length//(dw//8)) + counter = Counter(max=max(header_words, 2)) self.submodules += counter - self.sync += \ - If(shift, - self.header.eq(Cat(self.header[dw:], sink.data)) - ) + if header_words == 1: + self.sync += \ + If(shift, + self.header.eq(sink.data) + ) + else: + self.sync += \ + If(shift, + self.header.eq(Cat(self.header[dw:], sink.data)) + ) fsm = FSM(reset_state="IDLE") self.submodules += fsm + if header_words == 1: + idle_next_state = "COPY" + else: + idle_next_state = "RECEIVE_HEADER" + fsm.act("IDLE", sink.ack.eq(1), counter.reset.eq(1), If(sink.stb, shift.eq(1), - NextState("RECEIVE_HEADER") + NextState(idle_next_state) ) ) - fsm.act("RECEIVE_HEADER", - sink.ack.eq(1), - If(sink.stb, - counter.ce.eq(1), - shift.eq(1), - If(counter.value == header_length//(dw//8)-2, - NextState("COPY") + if header_words != 1: + fsm.act("RECEIVE_HEADER", + sink.ack.eq(1), + If(sink.stb, + counter.ce.eq(1), + shift.eq(1), + If(counter.value == header_words-2, + NextState("COPY") + ) ) ) - ) no_payload = Signal() self.sync += \ If(fsm.before_entering("COPY"), diff --git a/liteeth/generic/packetizer.py b/liteeth/generic/packetizer.py index 7ac0beb4f..627bb63d7 100644 --- a/liteeth/generic/packetizer.py +++ b/liteeth/generic/packetizer.py @@ -17,23 +17,36 @@ class LiteEthPacketizer(Module): dw = flen(self.sink.data) header_reg = Signal(header_length*8) + header_words = (header_length*8)//dw load = Signal() shift = Signal() - counter = Counter(max=header_length//(dw//8)) + counter = Counter(max=max(header_words, 2)) self.submodules += counter self.comb += _encode_header(header_type, self.header, sink) - self.sync += [ - If(load, - header_reg.eq(self.header) - ).Elif(shift, - header_reg.eq(Cat(header_reg[dw:], Signal(dw))) - ) - ] + if header_words == 1: + self.sync += [ + If(load, + header_reg.eq(self.header) + ) + ] + else: + self.sync += [ + If(load, + header_reg.eq(self.header) + ).Elif(shift, + header_reg.eq(Cat(header_reg[dw:], Signal(dw))) + ) + ] fsm = FSM(reset_state="IDLE") self.submodules += fsm + if header_words == 1: + idle_next_state = "COPY" + else: + idle_next_state = "SEND_HEADER" + fsm.act("IDLE", sink.ack.eq(1), counter.reset.eq(1), @@ -45,23 +58,24 @@ class LiteEthPacketizer(Module): source.data.eq(self.header[:dw]), If(source.stb & source.ack, load.eq(1), - NextState("SEND_HEADER"), + NextState(idle_next_state) ) ) ) - fsm.act("SEND_HEADER", - source.stb.eq(1), - source.sop.eq(0), - source.eop.eq(sink.eop & (counter.value == header_length//(dw//8)-2)), - source.data.eq(header_reg[dw:2*dw]), - If(source.stb & source.ack, - shift.eq(1), - counter.ce.eq(1), - If(counter.value == header_length//(dw//8)-2, - NextState("COPY") + if header_words != 1: + fsm.act("SEND_HEADER", + source.stb.eq(1), + source.sop.eq(0), + source.eop.eq(sink.eop & (counter.value == header_words-2)), + source.data.eq(header_reg[dw:2*dw]), + If(source.stb & source.ack, + shift.eq(1), + counter.ce.eq(1), + If(counter.value == header_words-2, + NextState("COPY") + ) ) ) - ) fsm.act("COPY", source.stb.eq(sink.stb), source.sop.eq(0),