Correct nMigen transition bugs
authorJean THOMAS <git0@pub.jeanthomas.me>
Thu, 4 Jun 2020 15:06:22 +0000 (17:06 +0200)
committerJean THOMAS <git0@pub.jeanthomas.me>
Thu, 4 Jun 2020 15:06:22 +0000 (17:06 +0200)
13 files changed:
gram/common.py
gram/compat.py
gram/core/__init__.py
gram/core/bankmachine.py
gram/core/controller.py
gram/core/crossbar.py
gram/core/multiplexer.py
gram/core/refresher.py
gram/dfii.py
gram/frontend/axi.py
gram/phy/ecp5ddrphy.py
gram/phy/model.py
gram/stream.py

index 8b7f0a6ebda42be1aba78e730483ebb9f27bd2da..b733f353776fdf4b627f4ed8cb9236b1a05c5b6e 100644 (file)
@@ -9,6 +9,9 @@ from operator import add
 from collections import OrderedDict
 
 from nmigen import *
+from nmigen.hdl.rec import *
+from nmigen.utils import log2_int
+
 import gram.stream as stream
 
 # Helpers ------------------------------------------------------------------------------------------
@@ -117,7 +120,7 @@ class BitSlip(Elaboratable):
     def elaborate(self, platform):
         m = Module()
 
-        value = Signal(max=self._cycles*dw)
+        value = Signal(range(self._cycles*dw))
         with m.If(self.slp):
             m.d.sync += value.eq(value+1)
         with m.Elif(self.rst):
@@ -260,7 +263,7 @@ def cmd_request_rw_layout(a, ba):
     ]
 
 
-class LiteDRAMInterface(Record):
+class gramInterface(Record):
     def __init__(self, address_align, settings):
         rankbits = log2_int(settings.phy.nranks)
         self.address_align = address_align
@@ -276,7 +279,7 @@ class LiteDRAMInterface(Record):
 
 # Ports --------------------------------------------------------------------------------------------
 
-class LiteDRAMNativePort(Settings):
+class gramNativePort(Settings):
     def __init__(self, mode, address_width, data_width, clock_domain="sys", id=0):
         self.set_attributes(locals())
 
@@ -308,12 +311,12 @@ class LiteDRAMNativePort(Settings):
             return self.cmd.addr[:cba_shift]
 
 
-class LiteDRAMNativeWritePort(LiteDRAMNativePort):
+class gramNativeWritePort(gramNativePort):
     def __init__(self, *args, **kwargs):
         LiteDRAMNativePort.__init__(self, "write", *args, **kwargs)
 
 
-class LiteDRAMNativeReadPort(LiteDRAMNativePort):
+class gramNativeReadPort(gramNativePort):
     def __init__(self, *args, **kwargs):
         LiteDRAMNativePort.__init__(self, "read", *args, **kwargs)
 
@@ -325,16 +328,17 @@ class tXXDController(Elaboratable):
         self.valid = Signal()
         self.ready = ready = Signal(reset=txxd is None)
         #ready.attr.add("no_retiming") TODO
+        self._txxd = txxd
 
     def elaborate(self, platform):
         m = Module()
 
-        if txxd is not None:
-            count = Signal(range(max(txxd, 2)))
+        if self._txxd is not None:
+            count = Signal(range(max(self._txxd, 2)))
             with m.If(self.valid):
                 m.d.sync += [
-                    count.eq(txxd-1),
-                    self.ready.eq((txxd - 1) == 0),
+                    count.eq(self._txxd-1),
+                    self.ready.eq((self._txxd - 1) == 0),
                 ]
             with m.Else():
                 m.d.sync += count.eq(count-1)
@@ -348,15 +352,16 @@ class tFAWController(Elaboratable):
         self.valid = Signal()
         self.ready = Signal(reset=1)
         #ready.attr.add("no_retiming") TODO
+        self._tfaw = tfaw
 
     def elaborate(self, platform):
         m = Module()
 
-        if tfaw is not None:
-            count  = Signal(range(max(tfaw, 2)))
-            window = Signal(tfaw)
+        if self._tfaw is not None:
+            count  = Signal(range(max(self._tfaw, 2)))
+            window = Signal(self._tfaw)
             m.d.sync += window.eq(Cat(self.valid, window))
-            m.d.comb += count.eq(reduce(add, [window[i] for i in range(tfaw)]))
+            m.d.comb += count.eq(reduce(add, [window[i] for i in range(self._tfaw)]))
             with m.If(count < 4):
                 with m.If(count == 3):
                     m.d.sync += self.ready.eq(~self.valid)
index 938ce67f2637a786aa87ad1a27a404795c6922af..90ebf3c3ea69eea6e40fcd7373f99dcfd07d09b6 100644 (file)
@@ -1,4 +1,5 @@
 from nmigen import *
+from nmigen.compat import Case
 
 __ALL__ = ["delayed_enter", "RoundRobin", "Timeline"]
 
@@ -19,47 +20,41 @@ def delayed_enter(m, src, dst, delay):
         with m.State(statename):
             m.next = deststate
 
-(SP_WITHDRAW, SP_CE) = range(2)
-
+# Original nMigen implementation by HarryHo90sHK
 class RoundRobin(Elaboratable):
-    def __init__(self, n, switch_policy=SP_WITHDRAW):
+    """A round-robin scheduler.
+    Parameters
+    ----------
+    n : int
+        Maximum number of requests to handle.
+    Attributes
+    ----------
+    request : Signal(n)
+        Signal where a '1' on the i-th bit represents an incoming request from the i-th device.
+    grant : Signal(range(n))
+        Signal that equals to the index of the device which is currently granted access.
+    stb : Signal()
+        Strobe signal to enable granting access to the next device requesting. Externally driven.
+    """
+    def __init__(self, n):
+        self.n = n
         self.request = Signal(n)
-        self.grant = Signal(max=max(2, n))
-        self.switch_policy = switch_policy
-        if self.switch_policy == SP_CE:
-            self.ce = Signal()
+        self.grant = Signal(range(n))
+        self.stb = Signal()
 
     def elaborate(self, platform):
         m = Module()
 
-        # TODO: fix
-
-        if n > 1:
-            cases = {}
-            for i in range(n):
-                switch = []
-                for j in reversed(range(i+1, i+n)):
-                    t = j % n
-                    switch = [
-                        If(self.request[t],
-                            self.grant.eq(t)
-                        ).Else(
-                            *switch
-                        )
-                    ]
-                if self.switch_policy == SP_WITHDRAW:
-                    case = [If(~self.request[i], *switch)]
-                else:
-                    case = switch
-                cases[i] = case
-            statement = Case(self.grant, cases)
-            if self.switch_policy == SP_CE:
-                with m.If(self.ce):
-                    m.d.sync += statement
-            else:
-                m.d.sync += statement
-        else:
-            m.d.comb += self.grant.eq(0)
+        with m.If(self.stb):
+            with m.Switch(self.grant):
+                for i in range(self.n):
+                    with m.Case(i):
+                        for j in reversed(range(i+1, i+self.n)):
+                            # If i+1 <= j < n, then t == j;     (after i)
+                            # If n <= j < i+n, then t == j - n  (before i)
+                            t = j % self.n
+                            with m.If(self.request[t]):
+                                m.d.sync += self.grant.eq(t)
 
         return m
 
index 7f2254ff41eee30d89454872c1f560dbda5ed2b4..a570ad390ca48ae9365930fe618ff77048aa0c8d 100644 (file)
@@ -19,13 +19,13 @@ class gramCore(Peripheral, Elaboratable):
     def elaborate(self, platform):
         m = Module()
 
-        m.submodules.dfii = DFIInjector(
+        m.submodules.dfii = dfii = DFIInjector(
             addressbits = self._geom_settings.addressbits,
             bankbits    = self._geom_settings.bankbits,
             nranks      = self._phy.settings.nranks,
             databits    = self._phy.settings.dfi_databits,
             nphases     = self._phy.settings.nphases)
-        m.d.comb += self.dfii.master.connect(self._phy.dfi)
+        m.d.comb += dfii.master.connect(self._phy.dfi)
 
         m.submodules.controller = controller = gramController(
             phy_settings    = self._phy.settings,
@@ -33,8 +33,8 @@ class gramCore(Peripheral, Elaboratable):
             timing_settings = self._timing_settings,
             clk_freq        = self._clk_freq,
             **self._kwargs)
-        m.d.comb += controller.dfi.connect(self.dfii.slave)
+        m.d.comb += controller.dfi.connect(dfii.slave)
 
-        m.submodules.crossbar = LiteDRAMCrossbar(controller.interface)
+        m.submodules.crossbar = gramCrossbar(controller.interface)
 
         return m
index b22a9961e890595050c3267ae55de952eea05f57..d96230feb258adde0a10039b86e41842223c2772 100644 (file)
@@ -32,7 +32,7 @@ class _AddressSlicer:
 
     def col(self, address):
         split = self.colbits - self.address_align
-        return Cat(Replicate(0, self.address_align), address[:split])
+        return Cat(Repl(0, self.address_align), address[:split])
 
 # BankMachine --------------------------------------------------------------------------------------
 
@@ -85,6 +85,7 @@ class BankMachine(Elaboratable):
         Stream of commands to the Multiplexer
     """
     def __init__(self, n, address_width, address_align, nranks, settings):
+        self.settings = settings
         self.req = req = Record(cmd_layout(address_width))
         self.refresh_req = refresh_req = Signal()
         self.refresh_gnt = refresh_gnt = Signal()
@@ -99,23 +100,23 @@ class BankMachine(Elaboratable):
         auto_precharge = Signal()
 
         # Command buffer ---------------------------------------------------------------------------
-        cmd_buffer_layout    = [("we", 1), ("addr", len(req.addr))]
+        cmd_buffer_layout    = [("we", 1), ("addr", len(self.req.addr))]
         cmd_buffer_lookahead = stream.SyncFIFO(
-            cmd_buffer_layout, settings.cmd_buffer_depth,
-            buffered=settings.cmd_buffer_buffered)
+            cmd_buffer_layout, self.settings.cmd_buffer_depth,
+            buffered=self.settings.cmd_buffer_buffered)
         cmd_buffer = stream.Buffer(cmd_buffer_layout) # 1 depth buffer to detect row change
         m.submodules += cmd_buffer_lookahead, cmd_buffer
         m.d.comb += [
-            req.connect(cmd_buffer_lookahead.sink, keep={"valid", "ready", "we", "addr"}),
+            self.req.connect(cmd_buffer_lookahead.sink, include={"valid", "ready", "we", "addr"}),
             cmd_buffer_lookahead.source.connect(cmd_buffer.sink),
-            cmd_buffer.source.ready.eq(req.wdata_ready | req.rdata_valid),
-            req.lock.eq(cmd_buffer_lookahead.source.valid | cmd_buffer.source.valid),
+            cmd_buffer.source.ready.eq(self.req.wdata_ready | self.req.rdata_valid),
+            self.req.lock.eq(cmd_buffer_lookahead.source.valid | cmd_buffer.source.valid),
         ]
 
-        slicer = _AddressSlicer(settings.geom.colbits, address_align)
+        slicer = _AddressSlicer(self.settings.geom.colbits, address_align)
 
         # Row tracking -----------------------------------------------------------------------------
-        row        = Signal(settings.geom.rowbits)
+        row        = Signal(self.settings.geom.rowbits)
         row_opened = Signal()
         row_hit    = Signal()
         row_open   = Signal()
@@ -138,17 +139,17 @@ class BankMachine(Elaboratable):
             m.d.comb += cmd.a.eq((auto_precharge << 10) | slicer.col(cmd_buffer.source.addr))
 
         # tWTP (write-to-precharge) controller -----------------------------------------------------
-        write_latency = math.ceil(settings.phy.cwl / settings.phy.nphases)
-        precharge_time = write_latency + settings.timing.tWR + settings.timing.tCCD # AL=0
+        write_latency = math.ceil(self.settings.phy.cwl / self.settings.phy.nphases)
+        precharge_time = write_latency + self.settings.timing.tWR + self.settings.timing.tCCD # AL=0
         m.submodules.twtpcon = twtpcon = tXXDController(precharge_time)
         m.d.comb += twtpcon.valid.eq(cmd.valid & cmd.ready & cmd.is_write)
 
         # tRC (activate-activate) controller -------------------------------------------------------
-        m.submodules.trccon = trccon = tXXDController(settings.timing.tRC)
+        m.submodules.trccon = trccon = tXXDController(self.settings.timing.tRC)
         m.d.comb += trccon.valid.eq(cmd.valid & cmd.ready & row_open)
 
         # tRAS (activate-precharge) controller -----------------------------------------------------
-        m.submodules.trascon = trascon = tXXDController(settings.timing.tRAS)
+        m.submodules.trascon = trascon = tXXDController(self.settings.timing.tRAS)
         m.d.comb += trascon.valid.eq(cmd.valid & cmd.ready & row_open)
 
         # Auto Precharge generation ----------------------------------------------------------------
@@ -173,13 +174,13 @@ class BankMachine(Elaboratable):
                             ]
                             with m.If(cmd_buffer.source.we):
                                 m.d.comb += [
-                                    req.wdata_ready.eq(cmd.ready),
+                                    self.req.wdata_ready.eq(cmd.ready),
                                     cmd.is_write.eq(1),
                                     cmd.we.eq(1),
                                 ]
                             with m.Else():
                                 m.d.comb += [
-                                    req.rdata_valid.eq(cmd.ready),
+                                    self.req.rdata_valid.eq(cmd.ready),
                                     cmd.is_read.eq(1),
                                 ]
                             with m.If(cmd.ready & auto_precharge):
@@ -232,7 +233,7 @@ class BankMachine(Elaboratable):
                 with m.If(~refresh_req):
                     m.next = "Regular"
 
-            delayed_enter(m, "TRP", "ACTIVATE", settings.timing.tRP - 1)
-            delayed_enter(m, "TRCD", "REGULAR", settings.timing.tRCD - 1)
+            delayed_enter(m, "tRP", "Activate", self.settings.timing.tRP - 1)
+            delayed_enter(m, "tRCD", "Regular", self.settings.timing.tRCD - 1)
 
         return m
index 5ef23cc52ed5a40acbb578fec48ded931cd31085..987ea86a3ba0b254cf8c3479928c1e2049076881 100644 (file)
@@ -6,6 +6,7 @@
 """LiteDRAM Controller."""
 
 from nmigen import *
+from nmigen.utils import log2_int
 
 from gram.common import *
 from gram.phy import dfi
@@ -46,7 +47,7 @@ class ControllerSettings(Settings):
 class gramController(Elaboratable):
     def __init__(self, phy_settings, geom_settings, timing_settings, clk_freq,
         controller_settings=ControllerSettings()):
-        address_align = log2_int(burst_lengths[phy_settings.memtype])
+        self._address_align = log2_int(burst_lengths[phy_settings.memtype])
 
         # Settings ---------------------------------------------------------------------------------
         self.settings        = controller_settings
@@ -54,11 +55,8 @@ class gramController(Elaboratable):
         self.settings.geom   = geom_settings
         self.settings.timing = timing_settings
 
-        nranks = phy_settings.nranks
-        nbanks = 2**geom_settings.bankbits
-
         # LiteDRAM Interface (User) ----------------------------------------------------------------
-        self.interface = interface = LiteDRAMInterface(address_align, self.settings)
+        self.interface = interface = gramInterface(self._address_align, self.settings)
 
         # DFI Interface (Memory) -------------------------------------------------------------------
         self.dfi = dfi.Interface(
@@ -68,12 +66,17 @@ class gramController(Elaboratable):
             databits    = phy_settings.dfi_databits,
             nphases     = phy_settings.nphases)
 
+        self._clk_freq = clk_freq
+
     def elaborate(self, platform):
         m = Module()
 
+        nranks = self.settings.phy.nranks
+        nbanks = 2**self.settings.geom.bankbits
+
         # Refresher --------------------------------------------------------------------------------
         m.submodules.refresher = self.settings.refresh_cls(self.settings,
-            clk_freq   = clk_freq,
+            clk_freq   = self._clk_freq,
             zqcs_freq  = self.settings.refresh_zqcs_freq,
             postponing = self.settings.refresh_postponing)
 
@@ -81,21 +84,21 @@ class gramController(Elaboratable):
         bank_machines = []
         for n in range(nranks*nbanks):
             bank_machine = BankMachine(n,
-                address_width = interface.address_width,
-                address_align = address_align,
+                address_width = self.interface.address_width,
+                address_align = self._address_align,
                 nranks        = nranks,
                 settings      = self.settings)
             bank_machines.append(bank_machine)
             m.submodules += bank_machine
-            m.d.comb += getattr(interface, "bank"+str(n)).connect(bank_machine.req)
+            m.d.comb += getattr(self.interface, "bank"+str(n)).connect(bank_machine.req)
 
         # Multiplexer ------------------------------------------------------------------------------
         m.submodules.multiplexer = Multiplexer(
             settings      = self.settings,
             bank_machines = bank_machines,
-            refresher     = self.refresher,
+            refresher     = m.submodules.refresher,
             dfi           = self.dfi,
-            interface     = interface)
+            interface     = self.interface)
 
         return m
 
index e71650f369cdaee4ae3a94a19b7d9f926a0e6c68..5efbd2b079e620a012efd896d38a3d4b5f25cb6f 100644 (file)
@@ -19,7 +19,7 @@ import gram.stream as stream
 
 # LiteDRAMCrossbar ---------------------------------------------------------------------------------
 
-class gramCrossbar(Module):
+class gramCrossbar(Elaboratable):
     """Multiplexes LiteDRAMController (slave) between ports (masters)
 
     To get a port to LiteDRAM, use the `get_port` method. It handles data width
@@ -119,7 +119,9 @@ class gramCrossbar(Module):
 
         return port
 
-    def do_finalize(self):
+    def elaborate(self, platform):
+        m = Module()
+
         controller = self.controller
         nmasters   = len(self.masters)
 
@@ -133,8 +135,8 @@ class gramCrossbar(Module):
         master_wdata_readys = [0]*nmasters
         master_rdata_valids = [0]*nmasters
 
-        arbiters = [roundrobin.RoundRobin(nmasters, roundrobin.SP_CE) for n in range(self.nbanks)]
-        self.submodules += arbiters
+        arbiters = [RoundRobin(nmasters) for n in range(self.nbanks)]
+        m.submodules += arbiters
 
         for nb, arbiter in enumerate(arbiters):
             bank = getattr(controller, "bank"+str(nb))
@@ -152,13 +154,13 @@ class gramCrossbar(Module):
             # Arbitrate ----------------------------------------------------------------------------
             bank_selected  = [(ba == nb) & ~locked for ba, locked in zip(m_ba, master_locked)]
             bank_requested = [bs & master.cmd.valid for bs, master in zip(bank_selected, self.masters)]
-            self.comb += [
+            m.d.comb += [
                 arbiter.request.eq(Cat(*bank_requested)),
-                arbiter.ce.eq(~bank.valid & ~bank.lock)
+                arbiter.stb.eq(~bank.valid & ~bank.lock)
             ]
 
             # Route requests -----------------------------------------------------------------------
-            self.comb += [
+            m.d.comb += [
                 bank.addr.eq(Array(m_rca)[arbiter.grant]),
                 bank.we.eq(Array(self.masters)[arbiter.grant].cmd.we),
                 bank.valid.eq(Array(bank_requested)[arbiter.grant])
@@ -174,23 +176,23 @@ class gramCrossbar(Module):
         for nm, master_wdata_ready in enumerate(master_wdata_readys):
             for i in range(self.write_latency):
                 new_master_wdata_ready = Signal()
-                self.sync += new_master_wdata_ready.eq(master_wdata_ready)
+                m.d.sync += new_master_wdata_ready.eq(master_wdata_ready)
                 master_wdata_ready = new_master_wdata_ready
             master_wdata_readys[nm] = master_wdata_ready
 
         for nm, master_rdata_valid in enumerate(master_rdata_valids):
             for i in range(self.read_latency):
                 new_master_rdata_valid = Signal()
-                self.sync += new_master_rdata_valid.eq(master_rdata_valid)
+                m.d.sync += new_master_rdata_valid.eq(master_rdata_valid)
                 master_rdata_valid = new_master_rdata_valid
             master_rdata_valids[nm] = master_rdata_valid
 
         for master, master_ready in zip(self.masters, master_readys):
-            self.comb += master.cmd.ready.eq(master_ready)
+            m.d.comb += master.cmd.ready.eq(master_ready)
         for master, master_wdata_ready in zip(self.masters, master_wdata_readys):
-            self.comb += master.wdata.ready.eq(master_wdata_ready)
+            m.d.comb += master.wdata.ready.eq(master_wdata_ready)
         for master, master_rdata_valid in zip(self.masters, master_rdata_valids):
-            self.comb += master.rdata.valid.eq(master_rdata_valid)
+            m.d.comb += master.rdata.valid.eq(master_rdata_valid)
 
         # Route data writes ------------------------------------------------------------------------
         wdata_cases = {}
@@ -203,8 +205,10 @@ class gramCrossbar(Module):
             controller.wdata.eq(0),
             controller.wdata_we.eq(0)
         ]
-        self.comb += Case(Cat(*master_wdata_readys), wdata_cases)
+        m.d.comb += Case(Cat(*master_wdata_readys), wdata_cases)
 
         # Route data reads -------------------------------------------------------------------------
         for master in self.masters:
-            self.comb += master.rdata.data.eq(controller.rdata)
+            m.d.comb += master.rdata.data.eq(controller.rdata)
+
+        return m
index 3a9203d830b28a02ebbe3af3552bee3937211388..433f1947e7334ad59bd0fae3b6f6f353463a0eab 100644 (file)
@@ -69,11 +69,11 @@ class _CommandChooser(Elaboratable):
             command = request.is_cmd & self.want_cmds & (~is_act_cmd | self.want_activates)
             read = request.is_read == self.want_reads
             write = request.is_write == self.want_writes
-            self.comb += valids[i].eq(request.valid & (command | (read & write)))
+            m.d.comb += valids[i].eq(request.valid & (command | (read & write)))
 
 
-        arbiter = RoundRobin(n, SP_CE)
-        self.submodules += arbiter
+        arbiter = RoundRobin(n)
+        m.submodules += arbiter
         choices = Array(valids[i] for i in range(n))
         m.d.comb += [
             arbiter.request.eq(valids),
@@ -82,13 +82,13 @@ class _CommandChooser(Elaboratable):
 
         for name in ["a", "ba", "is_read", "is_write", "is_cmd"]:
             choices = Array(getattr(req, name) for req in self._requests)
-            self.comb += getattr(self.cmd, name).eq(choices[arbiter.grant])
+            m.d.comb += getattr(self.cmd, name).eq(choices[arbiter.grant])
 
         for name in ["cas", "ras", "we"]:
             # we should only assert those signals when valid is 1
             choices = Array(getattr(req, name) for req in self._requests)
             with m.If(self.cmd.valid):
-                m.d.comb += getattr(cmd, name).eq(choices[arbiter.grant])
+                m.d.comb += getattr(self.cmd, name).eq(choices[arbiter.grant])
 
         for i, request in enumerate(self._requests):
             with m.If(self.cmd.valid & self.cmd.ready & (arbiter.grant == i)):
@@ -96,7 +96,7 @@ class _CommandChooser(Elaboratable):
 
         # Arbitrate if a command is being accepted or if the command is not valid to ensure a valid
         # command is selected when cmd.ready goes high.
-        m.d.comb += arbiter.ce.eq(self.cmd.ready | ~self.cmd.valid)
+        m.d.comb += arbiter.stb.eq(self.cmd.ready | ~self.cmd.valid)
 
         return m
 
@@ -164,14 +164,14 @@ class _Steerer(Elaboratable):
             nranks   = len(phase.cs_n)
             rankbits = log2_int(nranks)
             if hasattr(phase, "reset_n"):
-                self.comb += phase.reset_n.eq(1)
-            m.d.comb += phase.cke.eq(Replicate(Signal(reset=1), nranks))
+                m.d.comb += phase.reset_n.eq(1)
+            m.d.comb += phase.cke.eq(Repl(Signal(reset=1), nranks))
             if hasattr(phase, "odt"):
                 # FIXME: add dynamic drive for multi-rank (will be needed for high frequencies)
-                m.d.comb += phase.odt.eq(Replicate(Signal(reset=1), nranks))
+                m.d.comb += phase.odt.eq(Repl(Signal(reset=1), nranks))
             if rankbits:
                 rank_decoder = Decoder(nranks)
-                self.submodules += rank_decoder
+                m.submodules += rank_decoder
                 m.d.comb += rank_decoder.i.eq((Array(cmd.ba[-rankbits:] for cmd in commands)[sel]))
                 if i == 0: # Select all ranks on refresh.
                     with m.If(sel == STEER_REFRESH):
@@ -233,6 +233,20 @@ class Multiplexer(Peripheral, Elaboratable):
             dfi,
             interface):
         assert(settings.phy.nphases == len(dfi.phases))
+        self._settings = settings
+        self._bank_machines = bank_machines
+        self._refresher = refresher
+        self._dfi = dfi
+        self._interface = interface
+
+    def elaborate(self, platform):
+        m = Module()
+
+        settings = self._settings
+        bank_machines = self._bank_machines
+        refresher = self._refresher
+        dfi = self._dfi
+        interface = self._interface
 
         ras_allowed = Signal(reset=1)
         cas_allowed = Signal(reset=1)
@@ -300,11 +314,10 @@ class Multiplexer(Peripheral, Elaboratable):
                 t = timeout - 1
                 time = Signal(range(t+1))
                 m.d.comb += max_time.eq(time == 0)
-                m.d.sync += If(~en,
-                        time.eq(t)
-                    ).Elif(~max_time,
-                        time.eq(time - 1)
-                    )
+                with m.If(~en):
+                    m.d.sync += time.eq(t)
+                with m.Elif(~max_time):
+                    m.d.sync += time.eq(time - 1)
             else:
                 m.d.comb += max_time.eq(0)
             return en, max_time
@@ -409,8 +422,10 @@ class Multiplexer(Peripheral, Elaboratable):
                     m.next = "Read"
             
             # TODO: reduce this, actual limit is around (cl+1)/nphases
-            delayed_enter(m, "RTW", "WRITE", settings.phy.read_latency-1)
+            delayed_enter(m, "RTW", "Write", settings.phy.read_latency-1)
 
         if settings.with_bandwidth:
             data_width = settings.phy.dfi_databits*settings.phy.nphases
-            self.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width)
+            m.submodules.bandwidth = Bandwidth(self.choose_req.cmd, data_width)
+
+        return m
index ebaea329664a10e45501a80f3bd7b7a511de6b00..6be5b2a3859cc37723547672668b66558d62706a 100644 (file)
@@ -6,11 +6,11 @@
 """LiteDRAM Refresher."""
 
 from nmigen import *
-
-from litex.soc.interconnect import stream
+from nmigen.utils import bits_for, log2_int
 
 from gram.core.multiplexer import *
 from gram.compat import Timeline
+import gram.stream as stream
 
 # RefreshExecuter ----------------------------------------------------------------------------------
 
@@ -36,7 +36,7 @@ class RefreshExecuter(Elaboratable):
         trp = self._trp
         trfc = self._trfc
 
-        self.sync += [
+        m.d.sync += [
             self._cmd.a.eq(  0),
             self._cmd.ba.eq( 0),
             self._cmd.cas.eq(0),
@@ -87,20 +87,19 @@ class RefreshSequencer(Elaboratable):
     def __init__(self, cmd, trp, trfc, postponing=1):
         self.start = Signal()
         self.done  = Signal()
+
         self._trp = trp
         self._trfc = trfc
         self._postponing = postponing
+        self._cmd = cmd
 
     def elaborate(self, platform):
         m = Module()
 
-        trp = self._trp
-        trfc = self._trfc
+        executer = RefreshExecuter(self._cmd, self._trp, self._trfc)
+        m.submodules += executer
 
-        executer = RefreshExecuter(cmd, trp, trfc)
-        self.submodules += executer
-
-        count = Signal(bits_for(postponing), reset=postponing-1)
+        count = Signal(bits_for(self._postponing), reset=self._postponing-1)
         with m.If(self.start):
             m.d.sync += count.eq(count.reset)
         with m.Elif(executer.done):
@@ -161,6 +160,7 @@ class RefreshPostponer(Elaboratable):
         self._postponing = postponing
 
     def elaborate(self, platform):
+        m = Module()
 
         count = Signal(bits_for(self._postponing), reset=self._postponing-1)
 
@@ -257,6 +257,9 @@ class Refresher(Elaboratable):
         babits = settings.geom.bankbits + log2_int(settings.phy.nranks)
         self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a=abits, ba=babits))
         self._postponing = postponing
+        self._settings = settings
+        self._clk_freq = clk_freq
+        self._zqcs_freq = zqcs_freq
 
     def elaborate(self, platform):
         m = Module()
@@ -264,32 +267,34 @@ class Refresher(Elaboratable):
         wants_refresh = Signal()
         wants_zqcs    = Signal()
 
+        settings = self._settings
+
         # Refresh Timer ----------------------------------------------------------------------------
         timer = RefreshTimer(settings.timing.tREFI)
-        self.submodules.timer = timer
+        m.submodules.timer = timer
         m.d.comb += timer.wait.eq(~timer.done)
 
         # Refresh Postponer ------------------------------------------------------------------------
         postponer = RefreshPostponer(self._postponing)
-        self.submodules.postponer = postponer
+        m.submodules.postponer = postponer
         m.d.comb += [
-            postponer.req_i.eq(self.timer.done),
+            postponer.req_i.eq(timer.done),
             wants_refresh.eq(postponer.req_o),
         ]
 
         # Refresh Sequencer ------------------------------------------------------------------------
-        sequencer = RefreshSequencer(cmd, settings.timing.tRP, settings.timing.tRFC, self._postponing)
-        self.submodules.sequencer = sequencer
+        sequencer = RefreshSequencer(self.cmd, settings.timing.tRP, settings.timing.tRFC, self._postponing)
+        m.submodules.sequencer = sequencer
 
         if settings.timing.tZQCS is not None:
             # ZQCS Timer ---------------------------------------------------------------------------
-            zqcs_timer = RefreshTimer(int(clk_freq/zqcs_freq))
-            self.submodules.zqcs_timer = zqcs_timer
+            zqcs_timer = RefreshTimer(int(self._clk_freq/self._zqcs_freq))
+            m.submodules.zqcs_timer = zqcs_timer
             m.d.comb += wants_zqcs.eq(zqcs_timer.done)
 
             # ZQCS Executer ------------------------------------------------------------------------
-            zqcs_executer = ZQCSExecuter(cmd, settings.timing.tRP, settings.timing.tZQCS)
-            self.submodules.zqs_executer = zqcs_executer
+            zqcs_executer = ZQCSExecuter(self.cmd, settings.timing.tRP, settings.timing.tZQCS)
+            m.submodules.zqs_executer = zqcs_executer
             m.d.comb += zqcs_timer.wait.eq(~zqcs_executer.done)
 
         # Refresh FSM ------------------------------------------------------------------------------
@@ -299,40 +304,40 @@ class Refresher(Elaboratable):
                     m.next = "Wait-Bank-Machines"
 
             with m.State("Wait-Bank-Machines"):
-                m.d.comb += cmd.valid.eq(1)
-                with m.If(cmd.ready):
+                m.d.comb += self.cmd.valid.eq(1)
+                with m.If(self.cmd.ready):
                     m.d.comb += sequencer.start.eq(1)
                     m.next = "Do-Refresh"
 
             if settings.timing.tZQCS is None:
                 with m.State("Do-Refresh"):
-                    m.d.comb += cmd.valid.eq(1)
+                    m.d.comb += self.cmd.valid.eq(1)
                     with m.If(sequencer.done):
                         m.d.comb += [
-                            cmd.valid.eq(0),
-                            cmd.last.eq(1),
+                            self.cmd.valid.eq(0),
+                            self.cmd.last.eq(1),
                         ]
                         m.next = "Idle"
             else:
                 with m.State("Do-Refresh"):
-                    m.d.comb += cmd.valid.eq(1)
+                    m.d.comb += self.cmd.valid.eq(1)
                     with m.If(sequencer.done):
                         with m.If(wants_zqcs):
                             m.d.comb += zqcs_executer.start.eq(1)
                             m.next = "Do-Zqcs"
                         with m.Else():
                             m.d.comb += [
-                                cmd.valid.eq(0),
-                                cmd.last.eq(1),
+                                self.cmd.valid.eq(0),
+                                self.cmd.last.eq(1),
                             ]
                             m.next = "Idle"
 
                 with m.State("Do-Zqcs"):
-                    m.d.comb += cmd.valid.eq(1)
+                    m.d.comb += self.cmd.valid.eq(1)
                     with m.If(zqcs_executer.done):
                         m.d.comb += [
-                            cmd.valid.eq(0),
-                            cmd.last.eq(1),
+                            self.cmd.valid.eq(0),
+                            self.cmd.last.eq(1),
                         ]
                         m.next = "Idle"
 
index 11db5d6fa3c44d6496c2a0d1d003ce026e1fcf87..3436e33a92c02b3509238ce3fde421f20b0ea214 100644 (file)
@@ -12,43 +12,47 @@ from lambdasoc.periph import Peripheral
 
 class PhaseInjector(Peripheral, Elaboratable):
     def __init__(self, phase):
+        super().__init__(name = "phaseinjector")
+
         bank = self.csr_bank()
         self._command = bank.csr(6, "rw")
         self._command_issue = bank.csr(1, "rw")
-        self._address = bank.csr(len(phase.address), "rw", reset_less=True)
-        self._baddress = bank.csr(len(phase.bank), "rw", reset_less=True)
-        self._wrdata = bank.csr(len(phase.wrdata), "rw", reset_less=True)
-        self._rddata = bank.csr(len(phase.rddata))
+        self._address = bank.csr(len(phase.address), "rw")
+        self._baddress = bank.csr(len(phase.bank), "rw")
+        self._wrdata = bank.csr(len(phase.wrdata), "rw")
+        self._rddata = bank.csr(len(phase.rddata), "rw")
+
+        self._phase = phase
 
     def elaborate(self, platform):
         m = Module()
 
         m.d.comb += [
-            phase.address.eq(self._address.storage),
-            phase.bank.eq(self._baddress.storage),
-            phase.wrdata_en.eq(self._command_issue.re & self._command.storage[4]),
-            phase.rddata_en.eq(self._command_issue.re & self._command.storage[5]),
-            phase.wrdata.eq(self._wrdata.storage),
-            phase.wrdata_mask.eq(0)
+            self._phase.address.eq(self._address.r_data),
+            self._phase.bank.eq(self._baddress.r_data),
+            self._phase.wrdata_en.eq(self._command_issue.r_stb & self._command.r_data[4]),
+            self._phase.rddata_en.eq(self._command_issue.r_stb & self._command.r_data[5]),
+            self._phase.wrdata.eq(self._wrdata.r_data),
+            self._phase.wrdata_mask.eq(0)
         ]
 
-        with m.If(self._command_issue.re):
+        with m.If(self._command_issue.r_stb):
             m.d.comb += [
-                phase.cs_n.eq(Replicate(~self._command.storage[0], len(phase.cs_n))),
-                phase.we_n.eq(~self._command.storage[1]),
-                phase.cas_n.eq(~self._command.storage[2]),
-                phase.ras_n.eq(~self._command.storage[3]),
+                self._phase.cs_n.eq(Repl(value=~self._command.r_data[0], count=len(self._phase.cs_n))),
+                self._phase.we_n.eq(~self._command.r_data[1]),
+                self._phase.cas_n.eq(~self._command.r_data[2]),
+                self._phase.ras_n.eq(~self._command.r_data[3]),
             ]
         with m.Else():
             m.d.comb += [
-                phase.cs_n.eq(Replicate(1, len(phase.cs_n))),
-                phase.we_n.eq(1),
-                phase.cas_n.eq(1),
-                phase.ras_n.eq(1),
+                self._phase.cs_n.eq(Repl(value=1, count=len(self._phase.cs_n))),
+                self._phase.we_n.eq(1),
+                self._phase.cas_n.eq(1),
+                self._phase.ras_n.eq(1),
             ]
 
-        with m.If(phase.rddata_valid):
-            m.d.sync += self._rddata.status.eq(phase.rddata)
+        with m.If(self._phase.rddata_valid):
+            m.d.sync += self._rddata.w_data.eq(self._phase.rddata)
 
         return m
 
@@ -56,29 +60,31 @@ class PhaseInjector(Peripheral, Elaboratable):
 
 class DFIInjector(Peripheral, Elaboratable):
     def __init__(self, addressbits, bankbits, nranks, databits, nphases=1):
+        super().__init__(name = "dfii")
+
+        self._nranks = nranks
+
         self._inti  = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
         self.slave  = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
         self.master = dfi.Interface(addressbits, bankbits, nranks, databits, nphases)
 
         bank = self.csr_bank()
-        self._control = bank.csr(4)  # sel, cke, odt, reset_n
-
-        #for n, phase in enumerate(inti.phases):
-        #    setattr(self.submodules, "pi" + str(n), PhaseInjector(phase)) TODO
-
-        # # #
+        self._control = bank.csr(4, "rw")  # sel, cke, odt, reset_n
 
     def elaborate(self, platform):
         m = Module()
 
-        with m.If(self._control.storage[0]):
+        for n, phase in enumerate(self._inti.phases):
+            setattr(m.submodules, "pi" + str(n), PhaseInjector(phase))
+
+        with m.If(self._control.r_data[0]):
             m.d.comb += self.slave.connect(self.master)
         with m.Else():
             m.d.comb += self._inti.connect(self.master)
 
-        for i in range(nranks):
-            m.d.comb += [phase.cke[i].eq(self._control.storage[1]) for phase in self._inti.phases]
-            m.d.comb += [phase.odt[i].eq(self._control.storage[2]) for phase in self._inti.phases if hasattr(phase, "odt")]
-        m.d.comb += [phase.reset_n.eq(self._control.storage[3]) for phase in self._inti.phases if hasattr(phase, "reset_n")]
+        for i in range(self._nranks):
+            m.d.comb += [phase.cke[i].eq(self._control.r_data[1]) for phase in self._inti.phases]
+            m.d.comb += [phase.odt[i].eq(self._control.r_data[2]) for phase in self._inti.phases if hasattr(phase, "odt")]
+        m.d.comb += [phase.reset_n.eq(self._control.r_data[3]) for phase in self._inti.phases if hasattr(phase, "reset_n")]
 
         return m
index d310f658561c7c085a6ad390c92bcbc1b098650e..c2b868bf9c6f733a84383c1f1381f10783e3aea3 100644 (file)
@@ -188,9 +188,9 @@ class LiteDRAMAXI2Native(Module):
         self.submodules.read = LiteDRAMAXI2NativeR(axi, port, r_buffer_depth, base_address)
 
         # Write / Read arbitration -----------------------------------------------------------------
-        arbiter = RoundRobin(2, SP_CE)
+        arbiter = RoundRobin(2)
         self.submodules += arbiter
-        self.comb += arbiter.ce.eq(~port.cmd.valid | port.cmd.ready)
+        self.comb += arbiter.stb.eq(~port.cmd.valid | port.cmd.ready)
         for i, master in enumerate([self.write, self.read]):
             self.comb += arbiter.request[i].eq(master.cmd_request)
             self.comb += master.cmd_grant.eq(arbiter.grant == i)
index 10706850b81d6274e2cca51fad436d40174424b9..b9a9576beaf8bd5b938ed61e3738f7edfa2b000c 100644 (file)
@@ -18,7 +18,7 @@ from lambdasoc.periph import Peripheral
 import gram.stream as stream
 from gram.common import *
 from gram.phy.dfi import *
-from gram.timeline import Timeline
+from gram.compat import Timeline
 
 # Lattice ECP5 DDR PHY Initialization --------------------------------------------------------------
 
@@ -88,7 +88,7 @@ class ECP5DDRPHYInit(Elaboratable):
 
 class ECP5DDRPHY(Peripheral, Elaboratable):
     def __init__(self, pads, sys_clk_freq=100e6):
-        super().__init__() # Peripheral init
+        super().__init__()
 
         #self.pads = PHYPadsCombiner(pads)
         self.pads = pads
index 33ca2d8e87363198c0c8de423d24397e8216233d..1bfd13cee18207829ec2a3c643690511fdadcd67 100644 (file)
@@ -71,7 +71,7 @@ class BankModel(Module):
                 write_port.adr.eq(wraddr),
                 write_port.dat_w.eq(self.write_data),
                 If(we_granularity,
-                    write_port.we.eq(Replicate(self.write, data_width//8) & ~self.write_mask),
+                    write_port.we.eq(Repl(self.write, data_width//8) & ~self.write_mask),
                 ).Else(
                     write_port.we.eq(self.write),
                 ),
index bde9c6c29eb84e23bb9898b260d2e9fdaeadb43e..921cb554b57bb5ff2aed10117e8b0539fbdaf964 100644 (file)
@@ -3,7 +3,7 @@ from nmigen.hdl.rec import *
 from nmigen.lib import fifo
 
 
-__all__ = ["Endpoint", "SyncFIFO", "AsyncFIFO"]
+__all__ = ["Endpoint", "SyncFIFO", "AsyncFIFO", "Buffer"]
 
 
 def _make_fanout(layout):
@@ -93,9 +93,12 @@ class _FIFOWrapper:
 
 
 class SyncFIFO(Elaboratable, _FIFOWrapper):
-    def __init__(self, layout, depth, fwft=True):
+    def __init__(self, layout, depth, fwft=True, buffered=False):
         super().__init__(layout)
-        self.fifo = fifo.SyncFIFO(width=len(Record(self.layout)), depth=depth, fwft=fwft)
+        if buffered:
+            self.fifo = fifo.SyncFIFOBuffered(width=len(Record(self.layout)), depth=depth, fwft=fwft)
+        else:
+            self.fifo = fifo.SyncFIFO(width=len(Record(self.layout)), depth=depth, fwft=fwft)
         self.depth = self.fifo.depth
         self.level = self.fifo.level
 
@@ -106,3 +109,27 @@ class AsyncFIFO(Elaboratable, _FIFOWrapper):
         self.fifo = fifo.AsyncFIFO(width=len(Record(self.layout)), depth=depth,
                                    r_domain=r_domain, w_domain=w_domain)
         self.depth = self.fifo.depth
+
+class PipeValid(Elaboratable):
+    """Pipe valid/payload to cut timing path"""
+    def __init__(self, layout):
+        self.sink = Endpoint(layout)
+        self.source = Endpoint(layout)
+
+    def elaborate(self, platform):
+        m = Module()
+
+        # Pipe when source is not valid or is ready.
+        with m.If(~self.source.valid | self.source.ready):
+            m.d.sync += [
+                self.source.valid.eq(self.sink.valid),
+                self.source.first.eq(self.sink.first),
+                self.source.last.eq(self.sink.last),
+                self.source.payload.eq(self.sink.payload),
+                self.source.param.eq(self.sink.param),
+            ]
+        m.d.comb += self.sink.ready.eq(~self.source.valid | self.source.ready)
+
+        return m
+
+class Buffer(PipeValid): pass # FIXME: Replace Buffer with PipeValid in codebase?