test in sram for deliberately delaying response
[nmigen-soc.git] / nmigen_soc / wishbone / sram.py
index de5c15d551c081a224590ee4ba8706ca3d2d7547..22b0efdd330f2af99dc25bcdc0133f95b0e59957 100644 (file)
@@ -1,19 +1,21 @@
-from nmigen import *
-from nmigen.utils import *
+from nmigen import Elaboratable, Memory, Module, Signal
+from nmigen.utils import log2_int
 
-from .bus import Interface
+from nmigen_soc.wishbone.bus import Interface
 
 
 __all__ = ["SRAM"]
 
 
 class SRAM(Elaboratable):
-    """SRAM module carrying a volatile memory block (implemented with :class:`Memory`)
-    that can be read and write (or only read if the SRAM is read-only) through a Wishbone bus.
+    """SRAM module carrying a volatile memory block (implemented with
+    :class:`Memory`) that can be read and write (or only read if the
+    SRAM is read-only) through a Wishbone bus.
 
-    If no Wishbone bus is specified during initialisation, this creates one whose address width
-    is just enough to fit the whole memory (i.e. equals to the log2(memory depth) rounded up), and
-    whose data width is equal to the memory width.
+    If no Wishbone bus is specified during initialisation, this creates
+    one whose address width is just enough to fit the whole memory
+    (i.e. equals to the log2(memory depth) rounded up), and whose data
+    width is equal to the memory width.
 
     Parameters
     ----------
@@ -22,33 +24,39 @@ class SRAM(Elaboratable):
     read_only : bool
         Whether or not the memory is read-only. Defaults to False.
     bus : :class:`Interface` or None
-        The Wishbone bus interface providing access to the read/write ports of the memory.
-        Optional and defaults to None, which lets this module to instantiate one as described
-        above, having the granularity, features and alignment as specified by their
+        The Wishbone bus interface providing access to the read/write
+        ports of the memory.  Optional and defaults to None, which
+        lets this module to instantiate one as described above, having
+        the granularity, features and alignment as specified by their
         corresponding parameters.
     granularity : int or None
-        If the Wishbone bus is not sepcified, this is the granularity of the Wishbone bus.
-        Optional. See :class:`Interface`.
+        If the Wishbone bus is not specified, this is the granularity
+        of the Wishbone bus.  Optional. See :class:`Interface`.
     features : iter(str)
-        If the Wishbone bus is not sepcified, this is the optional signal set for the Wishbone bus.
-        See :class:`Interface`.
+        If the Wishbone bus is not specified, this is the optional signal
+        set for the Wishbone bus.  See :class:`Interface`.
 
     Attributes
     ----------
     memory : :class:`Memory`
         The memory to be accessed via the Wishbone bus.
     bus : :class:`Interface`
-        The Wishbone bus interface providing access to the read/write ports of the memory.
+        The Wishbone bus interface providing access to the read/write
+        ports of the memory.
     """
+
     def __init__(self, memory, read_only=False, bus=None,
-                 granularity=None, features=frozenset()):
+                 granularity=None, features=None):
+        if features is None:
+            features = frozenset()
         if not isinstance(memory, Memory):
             raise TypeError("Memory {!r} is not a Memory"
                             .format(memory))
         self.memory = memory
         self.read_only = read_only
         if bus is None:
-            bus = Interface(addr_width=log2_int(self.memory.depth, need_pow2=False),
+            bus = Interface(addr_width=log2_int(self.memory.depth,
+                                                need_pow2=False),
                             data_width=self.memory.width,
                             granularity=granularity,
                             features=features,
@@ -72,18 +80,31 @@ class SRAM(Elaboratable):
 
         # write
         if not self.read_only:
-            m.submodules.wrport = wrport = self.memory.write_port(granularity=self.granularity)
+            m.submodules.wrport = wrport = self.memory.write_port(
+                granularity=self.granularity)
             m.d.comb += [
                 wrport.addr.eq(self.bus.adr[:len(rdport.addr)]),
                 wrport.data.eq(self.bus.dat_w)
             ]
-            for i in range(4):
-                m.d.comb += wrport.en[i].eq(self.bus.cyc & self.bus.stb &
-                                            self.bus.we & self.bus.sel[i])
+            n_wrport = wrport.en.width
+            n_bussel = self.bus.sel.width
+            assert n_wrport == n_bussel, "bus enable count %d " \
+                    "must match memory wen count %d" % (n_wrport, n_bussel)
+            wen = Signal()
+            m.d.comb += wen.eq(self.bus.cyc & self.bus.stb & self.bus.we)
+            with m.If(wen):
+                m.d.comb += wrport.en.eq(self.bus.sel)
 
         # generate ack
         m.d.sync += self.bus.ack.eq(0)
         with m.If(self.bus.cyc & self.bus.stb & ~self.bus.ack):
-            m.d.sync += self.bus.ack.eq(1)
+            if False: # test which deliberately delays response
+                counter = Signal(3)
+                m.d.sync += counter.eq(counter + 1)
+                with m.If(counter == 7):
+                    m.d.sync += self.bus.ack.eq(1)
+                    m.d.sync += counter.eq(0)
+            else:
+                m.d.sync += self.bus.ack.eq(1)
 
-        return m
\ No newline at end of file
+        return m