soc/interconnect: rename stream_packet to packet & cleanup (with retro-compat)
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 30 Sep 2019 21:31:34 +0000 (23:31 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 30 Sep 2019 21:41:07 +0000 (23:41 +0200)
litex/__init__.py
litex/soc/interconnect/packet.py [new file with mode: 0644]
litex/soc/interconnect/stream_packet.py [deleted file]

index e1534fda3231430e937a07e5535faf0366d6a893..ca1e6d75bf2c5de0c466f78dbf7688faafae424f 100644 (file)
@@ -1,6 +1,11 @@
 import sys
-from litex.tools.litex_client import RemoteClient
+
+# retro-compat 2019-09-30
+from litex.soc.interconnect import packet
+sys.modules["litex.soc.interconnect.stream_packet"] = packet
 
 # retro-compat 2019-09-29
 from litex.soc.integration import export
-sys.modules["litex.soc.integration.cpu_interface"] = export
\ No newline at end of file
+sys.modules["litex.soc.integration.cpu_interface"] = export
+
+from litex.tools.litex_client import RemoteClient
diff --git a/litex/soc/interconnect/packet.py b/litex/soc/interconnect/packet.py
new file mode 100644 (file)
index 0000000..d1d02fe
--- /dev/null
@@ -0,0 +1,329 @@
+# This file is Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
+# License: BSD
+
+from migen import *
+from migen.genlib.roundrobin import *
+from migen.genlib.record import *
+from migen.genlib.fsm import FSM, NextState
+
+from litex.gen import *
+
+from litex.soc.interconnect import stream
+
+# Status -------------------------------------------------------------------------------------------
+
+class Status(Module):
+    def __init__(self, endpoint):
+        self.first   = Signal(reset=1)
+        self.last    = Signal()
+        self.ongoing = Signal()
+
+        ongoing = Signal()
+        self.comb += \
+            If(endpoint.valid,
+                self.last.eq(endpoint.last & endpoint.ready)
+            )
+        self.sync += ongoing.eq((endpoint.valid | ongoing) & ~self.last)
+        self.comb += self.ongoing.eq((endpoint.valid | ongoing) & ~self.last)
+
+        self.sync += [
+            If(self.last,
+                self.first.eq(1)
+            ).Elif(endpoint.valid & endpoint.ready,
+                self.first.eq(0)
+            )
+        ]
+
+# Arbiter ------------------------------------------------------------------------------------------
+
+class Arbiter(Module):
+    def __init__(self, masters, slave):
+        if len(masters) == 0:
+            pass
+        elif len(masters) == 1:
+            self.grant = Signal()
+            self.comb += masters.pop().connect(slave)
+        else:
+            self.submodules.rr = RoundRobin(len(masters))
+            self.grant = self.rr.grant
+            cases = {}
+            for i, master in enumerate(masters):
+                status = Status(master)
+                self.submodules += status
+                self.comb += self.rr.request[i].eq(status.ongoing)
+                cases[i] = [master.connect(slave)]
+            self.comb += Case(self.grant, cases)
+
+# Dispatcher ---------------------------------------------------------------------------------------
+
+class Dispatcher(Module):
+    def __init__(self, master, slaves, one_hot=False):
+        if len(slaves) == 0:
+            self.sel = Signal()
+        elif len(slaves) == 1:
+            self.comb += master.connect(slaves.pop())
+            self.sel = Signal()
+        else:
+            if one_hot:
+                self.sel = Signal(len(slaves))
+            else:
+                self.sel = Signal(max=len(slaves))
+
+            # # #
+
+            status = Status(master)
+            self.submodules += status
+
+            sel = Signal.like(self.sel)
+            sel_ongoing = Signal.like(self.sel)
+            self.sync += \
+                If(status.first,
+                    sel_ongoing.eq(self.sel)
+                )
+            self.comb += \
+                If(status.first,
+                    sel.eq(self.sel)
+                ).Else(
+                    sel.eq(sel_ongoing)
+                )
+            cases = {}
+            for i, slave in enumerate(slaves):
+                if one_hot:
+                    idx = 2**i
+                else:
+                    idx = i
+                cases[idx] = [master.connect(slave)]
+            cases["default"] = [master.ready.eq(1)]
+            self.comb += Case(sel, cases)
+
+# Header -------------------------------------------------------------------------------------------
+
+class HeaderField:
+    def __init__(self, byte, offset, width):
+        self.byte   = byte
+        self.offset = offset
+        self.width  = width
+
+
+class Header:
+    def __init__(self, fields, length, swap_field_bytes=True):
+        self.fields = fields
+        self.length = length
+        self.swap_field_bytes = swap_field_bytes
+
+    def get_layout(self):
+        layout = []
+        for k, v in sorted(self.fields.items()):
+            layout.append((k, v.width))
+        return layout
+
+    def get_field(self, obj, name, width):
+        if "_lsb" in name:
+            field = getattr(obj, name.replace("_lsb", ""))[:width]
+        elif "_msb" in name:
+            field = getattr(obj, name.replace("_msb", ""))[width:2*width]
+        else:
+            field = getattr(obj, name)
+        if len(field) != width:
+            raise ValueError("Width mismatch on " + name + " field")
+        return field
+
+    def encode(self, obj, signal):
+        r = []
+        for k, v in sorted(self.fields.items()):
+            start = v.byte*8 + v.offset
+            end = start + v.width
+            field = self.get_field(obj, k, v.width)
+            if self.swap_field_bytes:
+                field = reverse_bytes(field)
+            r.append(signal[start:end].eq(field))
+        return r
+
+    def decode(self, signal, obj):
+        r = []
+        for k, v in sorted(self.fields.items()):
+            start = v.byte*8 + v.offset
+            end = start + v.width
+            field = self.get_field(obj, k, v.width)
+            if self.swap_field_bytes:
+                r.append(field.eq(reverse_bytes(signal[start:end])))
+            else:
+                r.append(field.eq(signal[start:end]))
+        return r
+
+# Packetizer ---------------------------------------------------------------------------------------
+
+class Packetizer(Module):
+    def __init__(self, sink_description, source_description, header):
+        self.sink   =   sink = stream.Endpoint(sink_description)
+        self.source = source = stream.Endpoint(source_description)
+        self.header = Signal(header.length*8)
+
+        # # #
+
+        dw = len(self.sink.data)
+
+        header_reg    = Signal(header.length*8, reset_less=True)
+        header_words  = (header.length*8)//dw
+        load          = Signal()
+        shift         = Signal()
+        counter       = Signal(max=max(header_words, 2))
+        counter_reset = Signal()
+        counter_ce    = Signal()
+        self.sync += \
+            If(counter_reset,
+                counter.eq(0)
+            ).Elif(counter_ce,
+                counter.eq(counter + 1)
+            )
+
+        self.comb += header.encode(sink, self.header)
+        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.ready.eq(1),
+            counter_reset.eq(1),
+            If(sink.valid,
+                sink.ready.eq(0),
+                source.valid.eq(1),
+                source.last.eq(0),
+                source.data.eq(self.header[:dw]),
+                If(source.valid & source.ready,
+                    load.eq(1),
+                    NextState(idle_next_state)
+                )
+            )
+        )
+        if header_words != 1:
+            fsm.act("SEND-HEADER",
+                source.valid.eq(1),
+                source.last.eq(0),
+                source.data.eq(header_reg[dw:2*dw]),
+                If(source.valid & source.ready,
+                    shift.eq(1),
+                    counter_ce.eq(1),
+                    If(counter == header_words-2,
+                        NextState("COPY")
+                    )
+                )
+            )
+        if hasattr(sink, "error"):
+            self.comb += source.error.eq(sink.error)
+        fsm.act("COPY",
+            source.valid.eq(sink.valid),
+            source.last.eq(sink.last),
+            source.data.eq(sink.data),
+            If(source.valid & source.ready,
+                sink.ready.eq(1),
+                If(source.last,
+                    NextState("IDLE")
+                )
+            )
+        )
+
+# Depacketizer -------------------------------------------------------------------------------------
+
+class Depacketizer(Module):
+    def __init__(self, sink_description, source_description, header):
+        self.sink = sink = stream.Endpoint(sink_description)
+        self.source = source = stream.Endpoint(source_description)
+        self.header = Signal(header.length*8)
+
+        # # #
+
+        dw = len(sink.data)
+
+        header_reg = Signal(header.length*8, reset_less=True)
+        header_words = (header.length*8)//dw
+
+        shift         = Signal()
+        counter       = Signal(max=max(header_words, 2))
+        counter_reset = Signal()
+        counter_ce    = Signal()
+        self.sync += \
+            If(counter_reset,
+                counter.eq(0)
+            ).Elif(counter_ce,
+                counter.eq(counter + 1)
+            )
+
+        if header_words == 1:
+            self.sync += \
+                If(shift,
+                    header_reg.eq(sink.data)
+                )
+        else:
+            self.sync += \
+                If(shift,
+                    header_reg.eq(Cat(header_reg[dw:], sink.data))
+                )
+        self.comb += self.header.eq(header_reg)
+
+        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.ready.eq(1),
+            counter_reset.eq(1),
+            If(sink.valid,
+                shift.eq(1),
+                NextState(idle_next_state)
+            )
+        )
+        if header_words != 1:
+            fsm.act("RECEIVE_HEADER",
+                sink.ready.eq(1),
+                If(sink.valid,
+                    counter_ce.eq(1),
+                    shift.eq(1),
+                    If(counter == header_words-2,
+                        NextState("COPY")
+                    )
+                )
+            )
+        no_payload = Signal()
+        self.sync += \
+            If(fsm.before_entering("COPY"),
+                no_payload.eq(sink.last)
+            )
+
+        if hasattr(sink, "error"):
+            self.comb += source.error.eq(sink.error)
+        self.comb += [
+            source.last.eq(sink.last | no_payload),
+            source.data.eq(sink.data),
+            header.decode(self.header, source)
+        ]
+        fsm.act("COPY",
+            sink.ready.eq(source.ready),
+            source.valid.eq(sink.valid | no_payload),
+            If(source.valid & source.ready & source.last,
+                NextState("IDLE")
+            )
+        )
diff --git a/litex/soc/interconnect/stream_packet.py b/litex/soc/interconnect/stream_packet.py
deleted file mode 100644 (file)
index b9fd28a..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-# This file is Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
-# License: BSD
-
-from migen import *
-from migen.genlib.roundrobin import *
-from migen.genlib.record import *
-from migen.genlib.fsm import FSM, NextState
-
-from litex.gen import *
-
-from litex.soc.interconnect import stream
-
-# TODO: clean up code below
-# XXX
-
-class Status(Module):
-    def __init__(self, endpoint):
-        self.first = first = Signal(reset=1)
-        self.last = last = Signal()
-        self.ongoing = Signal()
-
-        ongoing = Signal()
-        self.comb += \
-            If(endpoint.valid,
-                last.eq(endpoint.last & endpoint.ready)
-            )
-        self.sync += ongoing.eq((endpoint.valid | ongoing) & ~last)
-        self.comb += self.ongoing.eq((endpoint.valid | ongoing) & ~last)
-
-        self.sync += [
-            If(last,
-                first.eq(1)
-            ).Elif(endpoint.valid & endpoint.ready,
-                first.eq(0)
-            )
-        ]
-
-
-class Arbiter(Module):
-    def __init__(self, masters, slave):
-        if len(masters) == 0:
-            pass
-        elif len(masters) == 1:
-            self.grant = Signal()
-            self.comb += masters.pop().connect(slave)
-        else:
-            self.submodules.rr = RoundRobin(len(masters))
-            self.grant = self.rr.grant
-            cases = {}
-            for i, master in enumerate(masters):
-                status = Status(master)
-                self.submodules += status
-                self.comb += self.rr.request[i].eq(status.ongoing)
-                cases[i] = [master.connect(slave)]
-            self.comb += Case(self.grant, cases)
-
-
-class Dispatcher(Module):
-    def __init__(self, master, slaves, one_hot=False):
-        if len(slaves) == 0:
-            self.sel = Signal()
-        elif len(slaves) == 1:
-            self.comb += master.connect(slaves.pop())
-            self.sel = Signal()
-        else:
-            if one_hot:
-                self.sel = Signal(len(slaves))
-            else:
-                self.sel = Signal(max=len(slaves))
-
-            # # #
-
-            status = Status(master)
-            self.submodules += status
-
-            sel = Signal.like(self.sel)
-            sel_ongoing = Signal.like(self.sel)
-            self.sync += \
-                If(status.first,
-                    sel_ongoing.eq(self.sel)
-                )
-            self.comb += \
-                If(status.first,
-                    sel.eq(self.sel)
-                ).Else(
-                    sel.eq(sel_ongoing)
-                )
-            cases = {}
-            for i, slave in enumerate(slaves):
-                if one_hot:
-                    idx = 2**i
-                else:
-                    idx = i
-                cases[idx] = [master.connect(slave)]
-            cases["default"] = [master.ready.eq(1)]
-            self.comb += Case(sel, cases)
-
-
-class HeaderField:
-    def __init__(self, byte, offset, width):
-        self.byte = byte
-        self.offset = offset
-        self.width = width
-
-
-class Header:
-    def __init__(self, fields, length, swap_field_bytes=True):
-        self.fields = fields
-        self.length = length
-        self.swap_field_bytes = swap_field_bytes
-
-    def get_layout(self):
-        layout = []
-        for k, v in sorted(self.fields.items()):
-            layout.append((k, v.width))
-        return layout
-
-    def get_field(self, obj, name, width):
-        if "_lsb" in name:
-            field = getattr(obj, name.replace("_lsb", ""))[:width]
-        elif "_msb" in name:
-            field = getattr(obj, name.replace("_msb", ""))[width:2*width]
-        else:
-            field = getattr(obj, name)
-        if len(field) != width:
-            raise ValueError("Width mismatch on " + name + " field")
-        return field
-
-    def encode(self, obj, signal):
-        r = []
-        for k, v in sorted(self.fields.items()):
-            start = v.byte*8 + v.offset
-            end = start + v.width
-            field = self.get_field(obj, k, v.width)
-            if self.swap_field_bytes:
-                field = reverse_bytes(field)
-            r.append(signal[start:end].eq(field))
-        return r
-
-    def decode(self, signal, obj):
-        r = []
-        for k, v in sorted(self.fields.items()):
-            start = v.byte*8 + v.offset
-            end = start + v.width
-            field = self.get_field(obj, k, v.width)
-            if self.swap_field_bytes:
-                r.append(field.eq(reverse_bytes(signal[start:end])))
-            else:
-                r.append(field.eq(signal[start:end]))
-        return r
-
-
-class Packetizer(Module):
-    def __init__(self, sink_description, source_description, header):
-        self.sink = sink = stream.Endpoint(sink_description)
-        self.source = source = stream.Endpoint(source_description)
-        self.header = Signal(header.length*8)
-
-        # # #
-
-        dw = len(self.sink.data)
-
-        header_reg = Signal(header.length*8, reset_less=True)
-        header_words = (header.length*8)//dw
-        load = Signal()
-        shift = Signal()
-        counter = Signal(max=max(header_words, 2))
-        counter_reset = Signal()
-        counter_ce = Signal()
-        self.sync += \
-            If(counter_reset,
-                counter.eq(0)
-            ).Elif(counter_ce,
-                counter.eq(counter + 1)
-            )
-
-        self.comb += header.encode(sink, self.header)
-        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.ready.eq(1),
-            counter_reset.eq(1),
-            If(sink.valid,
-                sink.ready.eq(0),
-                source.valid.eq(1),
-                source.last.eq(0),
-                source.data.eq(self.header[:dw]),
-                If(source.valid & source.ready,
-                    load.eq(1),
-                    NextState(idle_next_state)
-                )
-            )
-        )
-        if header_words != 1:
-            fsm.act("SEND_HEADER",
-                source.valid.eq(1),
-                source.last.eq(0),
-                source.data.eq(header_reg[dw:2*dw]),
-                If(source.valid & source.ready,
-                    shift.eq(1),
-                    counter_ce.eq(1),
-                    If(counter == header_words-2,
-                        NextState("COPY")
-                    )
-                )
-            )
-        if hasattr(sink, "error"):
-            self.comb += source.error.eq(sink.error)
-        fsm.act("COPY",
-            source.valid.eq(sink.valid),
-            source.last.eq(sink.last),
-            source.data.eq(sink.data),
-            If(source.valid & source.ready,
-                sink.ready.eq(1),
-                If(source.last,
-                    NextState("IDLE")
-                )
-            )
-        )
-
-
-class Depacketizer(Module):
-    def __init__(self, sink_description, source_description, header):
-        self.sink = sink = stream.Endpoint(sink_description)
-        self.source = source = stream.Endpoint(source_description)
-        self.header = Signal(header.length*8)
-
-        # # #
-
-        dw = len(sink.data)
-
-        header_reg = Signal(header.length*8, reset_less=True)
-        header_words = (header.length*8)//dw
-
-        shift = Signal()
-        counter = Signal(max=max(header_words, 2))
-        counter_reset = Signal()
-        counter_ce = Signal()
-        self.sync += \
-            If(counter_reset,
-                counter.eq(0)
-            ).Elif(counter_ce,
-                counter.eq(counter + 1)
-            )
-
-        if header_words == 1:
-            self.sync += \
-                If(shift,
-                    header_reg.eq(sink.data)
-                )
-        else:
-            self.sync += \
-                If(shift,
-                    header_reg.eq(Cat(header_reg[dw:], sink.data))
-                )
-        self.comb += self.header.eq(header_reg)
-
-        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.ready.eq(1),
-            counter_reset.eq(1),
-            If(sink.valid,
-                shift.eq(1),
-                NextState(idle_next_state)
-            )
-        )
-        if header_words != 1:
-            fsm.act("RECEIVE_HEADER",
-                sink.ready.eq(1),
-                If(sink.valid,
-                    counter_ce.eq(1),
-                    shift.eq(1),
-                    If(counter == header_words-2,
-                        NextState("COPY")
-                    )
-                )
-            )
-        no_payload = Signal()
-        self.sync += \
-            If(fsm.before_entering("COPY"),
-                no_payload.eq(sink.last)
-            )
-
-        if hasattr(sink, "error"):
-            self.comb += source.error.eq(sink.error)
-        self.comb += [
-            source.last.eq(sink.last | no_payload),
-            source.data.eq(sink.data),
-            header.decode(self.header, source)
-        ]
-        fsm.act("COPY",
-            sink.ready.eq(source.ready),
-            source.valid.eq(sink.valid | no_payload),
-            If(source.valid & source.ready & source.last,
-                NextState("IDLE")
-            )
-        )
-
-# XXX