mac: add packetizer/depacketizer (untested)
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 28 Jan 2015 23:02:50 +0000 (00:02 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 28 Jan 2015 23:02:50 +0000 (00:02 +0100)
liteeth/common.py
liteeth/mac/core/depacketizer.py [new file with mode: 0644]
liteeth/mac/core/packetizer.py [new file with mode: 0644]

index 540747f4c26b9e29034f839670e2e97dfda08811..88433e5c12e890142839352b8d4492d80ecdd9d0 100644 (file)
@@ -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 (file)
index 0000000..b0e1a08
--- /dev/null
@@ -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 (file)
index 0000000..6660021
--- /dev/null
@@ -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")
+                               )
+                       )
+               )