diff --git a/liteeth/common.py b/liteeth/common.py index 540747f4c..88433e5c1 100644 --- a/liteeth/common.py +++ b/liteeth/common.py @@ -93,7 +93,6 @@ def eth_mac_description(dw): def eth_arp_description(dw): layout = _layout_from_header(arp_header) + [ ("data", dw), - ("last_be", dw//8), ("error", dw//8) ] return EndpointDescription(layout, packetized=True) @@ -101,7 +100,6 @@ def eth_arp_description(dw): def eth_ipv4_description(dw): layout = _layout_from_header(ipv4_header) + [ ("data", dw), - ("last_be", dw//8), ("error", dw//8) ] return EndpointDescription(layout, packetized=True) @@ -109,8 +107,56 @@ def eth_ipv4_description(dw): def eth_udp_description(dw): layout = _layout_from_header(udp_header) + [ ("data", dw), - ("last_be", dw//8), ("error", dw//8) ] return EndpointDescription(layout, packetized=True) +# Generic modules +@DecorateModule(InsertReset) +@DecorateModule(InsertCE) +class Counter(Module): + def __init__(self, signal=None, **kwargs): + if signal is None: + self.value = Signal(**kwargs) + else: + self.value = signal + self.width = flen(self.value) + self.sync += self.value.eq(self.value+1) + +@DecorateModule(InsertReset) +@DecorateModule(InsertCE) +class Timeout(Module): + def __init__(self, length): + self.reached = Signal() + ### + value = Signal(max=length) + self.sync += value.eq(value+1) + self.comb += self.reached.eq(value == length) + +class BufferizeEndpoints(ModuleDecorator): + def __init__(self, submodule, *args): + ModuleDecorator.__init__(self, submodule) + + endpoints = get_endpoints(submodule) + sinks = {} + sources = {} + for name, endpoint in endpoints.items(): + if name in args or len(args) == 0: + if isinstance(endpoint, Sink): + sinks.update({name : endpoint}) + elif isinstance(endpoint, Source): + sources.update({name : endpoint}) + + # add buffer on sinks + for name, sink in sinks.items(): + buf = Buffer(sink.description) + self.submodules += buf + setattr(self, name, buf.d) + self.comb += Record.connect(buf.q, sink) + + # add buffer on sources + for name, source in sources.items(): + buf = Buffer(source.description) + self.submodules += buf + self.comb += Record.connect(source, buf.d) + setattr(self, name, buf.q) diff --git a/liteeth/mac/core/depacketizer.py b/liteeth/mac/core/depacketizer.py new file mode 100644 index 000000000..b0e1a08e7 --- /dev/null +++ b/liteeth/mac/core/depacketizer.py @@ -0,0 +1,63 @@ +import math + +from liteeth.common import * + +def _decode_header(h_dict, h_signal, obj): + r = [] + for k, v in sorted(h_dict.items()): + start = v.byte*8+v.offset + end = start+v.width + r.append(getattr(obj, k).eq(h_signal[start:end])) + return r + +class LiteEthMACDepacketizer(Module): + def __init__(self): + self.sink = sink = Sink(eth_mac_description(8)) + self.source = source = Source(eth_phy_description(8)) + ### + shift = Signal() + header = Signal(mac_header_length*8) + counter = Counter(max=mac_header_length) + self.submodules += counter + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + fsm.act("IDLE", + sink.ack.eq(1), + counter.reset.eq(1), + If(sink.stb, + shift.eq(1), + NextState("RECEIVE_HEADER") + ) + ) + fsm.act("RECEIVE_HEADER", + sink.ack.eq(1), + If(sink.stb, + counter.ce.eq(1), + shift.eq(1), + If(counter.value == mac_header_length-2, + NextState("COPY") + ) + ) + ) + self.sync += \ + If(fsm.before_entering("COPY"), + source.sop.eq(1) + ).Elif(source.stb & source.ack, + source.sop.eq(0) + ) + self.comb += [ + source.sop.eq(sop), + source.eop.eq(sink.eop), + source.data.eq(sink.data), + source.error.eq(sink.error), + _decode_header(mac_header, header, source) + ] + fsm.act("COPY", + sink.ack.eq(source.ack), + source.stb.eq(sink.stb), + If(source.stb & source.ack & source.eop, + NextState("IDLE") + ) + ) diff --git a/liteeth/mac/core/packetizer.py b/liteeth/mac/core/packetizer.py new file mode 100644 index 000000000..66600216a --- /dev/null +++ b/liteeth/mac/core/packetizer.py @@ -0,0 +1,73 @@ +from liteeth.common import * + +def _encode_header(h_dict, h_signal, obj): + r = [] + for k, v in sorted(h_dict.items()): + start = v.word*32+v.offset + end = start+v.width + r.append(h_signal[start:end].eq(getattr(obj, k))) + return r + +class LiteEthMACPacketizer(Module): + def __init__(self): + self.sink = sink = Sink(eth_phy_description(8)) + self.source = source = Source(eth_mac_description(8)) + ### + header = Signal(mac_header_length*8) + header_reg = Signal(mac_header_length*8) + load = Signal() + shift = Signal() + counter = Counter(max=mac_header_length) + self.submodules += counter + + self.comb += header.eq(_encode_header(mac_header, header, sink)) + self.sync += [ + If(load, + header_reg.eq(header) + ).Elif(shift, + header_reg.eq(Cat(header_reg[8:], Signal(8))) + ) + ] + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + load.eq(1), + sink.ack.eq(0), + source.stb.eq(1), + source.sop.eq(1), + source.eop.eq(0), + source.data.eq(header[:8]), + If(source.stb & source.ack, + NextState("SEND_HEADER"), + ) + ) + ) + fsm.act("SEND_HEADER", + source.stb.eq(1), + source.sop.eq(0), + source.eop.eq(sink.eop), + source.data.eq(header_reg[8:16]), + If(source.stb & source.ack, + sink.ack.eq(1), + If(counter == mac_header_length-2, + NextState("COPY") + ) + ) + ) + fsm.act("COPY", + source.stb.eq(sink.stb), + source.sop.eq(0), + source.eop.eq(sink_eop), + source.data.eq(sink.data), + source.error.eq(sink.error), + If(source.stb & source.ack, + sink.ack.eq(1), + If(source.eop, + NextState("IDLE") + ) + ) + )