etherbone: add record depacketizer/packetizer (wip)
This commit is contained in:
parent
247c30ae26
commit
abe6d87438
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
from liteeth.common import *
|
|
@ -1,5 +1,4 @@
|
|||
from liteeth.common import *
|
||||
from liteeth.core.etherbone import common
|
||||
|
||||
class LiteEthEtherboneWishboneMaster(Module):
|
||||
def __init__(self):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
)
|
||||
)
|
|
@ -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()
|
|
@ -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"),
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue