cores/up5kspram: simplify and add support for all width/depth configurations
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Sun, 21 Jul 2019 17:27:43 +0000 (19:27 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Sun, 21 Jul 2019 17:28:31 +0000 (19:28 +0200)
litex/soc/cores/up5kspram.py

index 2e4d7609f4163973c455a8bec6ec6147cf2215e7..4a790d1895ded2f202574c9aac07e010e1351d69 100644 (file)
 # This file is Copyright (c) 2019 William D. Jones <thor0505@comcast.net>
 # This file is Copyright (c) 2019 Tim 'mithro' Ansell <me@mith.ro>
+# This file is Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
 # License: BSD
 
-
 from migen import *
 from litex.soc.interconnect import wishbone
 
+kB = 1024
+
 """
-ICE40 UltraPlus family-specific Wishbone interface to the Single Port RAM
-(SPRAM) primitives. Because SPRAM is much more coarse grained than Block
-RAM resources, this RAM is only minimally configurable at present (64kB or
-128kB). Because it is single port, this module is meant to be used as the
-CPU's RAM region, leaving block RAM free for other use.
-"""
+ICE40 UltraPlus family-specific Wishbone interface to the Single Port RAM (SPRAM) primitives.
+Because SPRAM is much more coarse grained than Block RAM resources, this RAM is only minimally
+configurable (16 or 32-bit and 64kB, 128kB or 256kB). Because it is single port, this module is
+meant to be used as the CPU's RAM region, leaving block RAM free for other use.
 
-class Up5kSPRAM(Module):
-    def __init__(self, width=32, size=64*1024):
+Example: To get a 32-bit data bus, we must width-cascade 2 16-bit SPRAMs. We've already used 2 out
+of 4 SPRAMs for this, so the only other valid config is using all 4 SPRAMs by depth-cascading.
 
-        # Right now, LiteX only supports 32-bit CPUs. To get a 32-bit data bus,
-        # we must width-cascade 2 16-bit SPRAMs. We've already used 2 out of 4
-        # SPRAMs for this, so the only other valid config is using all 4 SPRAMs
-        # by depth-cascading.
-        if width != 32:
-            raise ValueError("Width of Up5kSPRAM must be 32 bits")
-        if size != 64*1024 and size != 128*1024:
-            raise ValueError("Size of Up5kSPRAM must be 64kB or 128kB.")
+"""
 
+class Up5kSPRAM(Module):
+    def __init__(self, width=32, size=64*kB):
         self.bus = wishbone.Interface(width)
 
-        bytesels = []
-        for i in range(0, 2):
-            datain = Signal(16)
-            dataout = Signal(16)
-            maskwren = Signal(4)
-            wren = Signal(1)
-
-            # 64k vs 128k-specific routing signals.
-            datain0 = Signal(16)
-            dataout0 = Signal(16)
-            maskwren0 = Signal(4)
+        # # #
 
-            if size == 128 * 1024:
-                datain1 = Signal(16)
-                dataout1 = Signal(16)
-                maskwren1 = Signal(4)
+        assert width in [16, 32, 64]
+        if width == 16:
+            assert size in [32*kB, 64*kB, 128*kB]
+            depth_cascading = size//(32*kB)
+            width_cascading = 1
+        if width == 32:
+            assert size in [64*kB, 128*kB]
+            depth_cascading = size//(64*kB)
+            width_cascading = 2
+        if width == 64:
+            assert size in [128*kB]
+            depth_cascading = size//(128*kB)
+            width_cascading = 4
 
-            # Generic routing common to all depths.
-            for j in range(16):
-                self.comb += [self.bus.dat_r[16*i + j].eq(dataout[j])]
-
-            self.comb += [
-                datain.eq(self.bus.dat_w[16*i:16*i+16]),
-                # MASKWREN is nibble-based, interestingly enough.
-                maskwren.eq(
-                    Cat(
-                        Replicate(self.bus.sel[2*i], 2),
-                        Replicate(self.bus.sel[2*i + 1], 2),
-                    )
-                ),
-                wren.eq(self.bus.we & self.bus.stb & self.bus.cyc)
-            ]
-
-            # Signals which must be routed differently based on depth.
-            # 64kB
-            if size == 64*1024:
-                self.comb += [
-                    datain0.eq(datain),
-                    dataout.eq(dataout0),
-                    maskwren0.eq(maskwren)
-                ]
-            # 128kB
-            else:
+        for d in range(depth_cascading):
+            for w in range(width_cascading):
+                datain = Signal(16)
+                dataout = Signal(16)
+                maskwren = Signal(4)
+                wren = Signal()
                 self.comb += [
-                    If(self.bus.adr[14],
-                        datain1.eq(datain),
-                        dataout.eq(dataout1),
-                        maskwren1.eq(maskwren)
-                    ).Else(
-                        datain0.eq(datain),
-                        dataout.eq(dataout0),
-                        maskwren0.eq(maskwren)
-                    )
+                    datain.eq(self.bus.dat_w[16*w:16*(w+1)]),
+                    If(self.bus.adr[14:16] == d,
+                        wren.eq(self.bus.we & self.bus.stb & self.bus.cyc),
+                        self.bus.dat_r[16*w:16*(w+1)].eq(dataout)
+                    ),
+                    # maskwren is nibble based
+                    maskwren[0].eq(self.bus.sel[2*w + 0]),
+                    maskwren[1].eq(self.bus.sel[2*w + 0]),
+                    maskwren[2].eq(self.bus.sel[2*w + 1]),
+                    maskwren[3].eq(self.bus.sel[2*w + 1]),
                 ]
-
-            self.specials.spram = Instance("SB_SPRAM256KA",
-                i_ADDRESS=self.bus.adr[0:14], i_DATAIN=datain0,
-                i_MASKWREN=maskwren0,
-                i_WREN=wren,
-                i_CHIPSELECT=C(1,1),
-                i_CLOCK=ClockSignal("sys"),
-                i_STANDBY=C(0,1),
-                i_SLEEP=C(0,1),
-                i_POWEROFF=C(1,1),
-                o_DATAOUT=dataout0
-            )
-
-            # We need to depth cascade if using 128kB.
-            if size == 128*1024:
-                self.specials.spram = Instance("SB_SPRAM256KA",
-                    i_ADDRESS=self.bus.adr[0:14], i_DATAIN=datain1,
-                    i_MASKWREN=maskwren1,
+                self.specials += Instance("SB_SPRAM256KA",
+                    i_ADDRESS=self.bus.adr[:14],
+                    i_DATAIN=datain,
+                    i_MASKWREN=maskwren,
                     i_WREN=wren,
-                    i_CHIPSELECT=C(1,1),
+                    i_CHIPSELECT=0b1,
                     i_CLOCK=ClockSignal("sys"),
-                    i_STANDBY=C(0,1),
-                    i_SLEEP=C(0,1),
-                    i_POWEROFF=C(1,1),
-                    o_DATAOUT=dataout1
+                    i_STANDBY=0b0,
+                    i_SLEEP=0b0,
+                    i_POWEROFF=0b1,
+                    o_DATAOUT=dataout
                 )
 
-        self.sync += [
-            self.bus.ack.eq(0),
-            If(self.bus.stb & self.bus.cyc & ~self.bus.ack,
-                self.bus.ack.eq(1)
-            )
-        ]
+        self.sync += self.bus.ack.eq(self.bus.stb & self.bus.cyc & ~self.bus.ack)