From bb99c4685a2940dbfc0216e95ce37bbfa154e527 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sun, 21 Jul 2019 19:27:43 +0200 Subject: [PATCH] cores/up5kspram: simplify and add support for all width/depth configurations --- litex/soc/cores/up5kspram.py | 148 ++++++++++++----------------------- 1 file changed, 52 insertions(+), 96 deletions(-) diff --git a/litex/soc/cores/up5kspram.py b/litex/soc/cores/up5kspram.py index 2e4d7609..4a790d18 100644 --- a/litex/soc/cores/up5kspram.py +++ b/litex/soc/cores/up5kspram.py @@ -1,117 +1,73 @@ # This file is Copyright (c) 2019 William D. Jones # This file is Copyright (c) 2019 Tim 'mithro' Ansell +# This file is Copyright (c) 2019 Florent Kermarrec # 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) -- 2.30.2