diff --git a/litex/soc/cores/ram/__init__.py b/litex/soc/cores/ram/__init__.py new file mode 100644 index 000000000..a2be9b323 --- /dev/null +++ b/litex/soc/cores/ram/__init__.py @@ -0,0 +1,7 @@ +# Xilinx + +# Intel + +# Lattice +from litex.soc.cores.ram.lattice_ice40 import Up5kSPRAM +from litex.soc.cores.ram.lattice_nx import NXLRAM diff --git a/litex/soc/cores/ram/lattice_ice40.py b/litex/soc/cores/ram/lattice_ice40.py new file mode 100644 index 000000000..5f8ecfb76 --- /dev/null +++ b/litex/soc/cores/ram/lattice_ice40.py @@ -0,0 +1,76 @@ +# +# This file is part of LiteX. +# +# Copyright (c) 2019 William D. Jones +# Copyright (c) 2019 Tim 'mithro' Ansell +# Copyright (c) 2019 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +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 (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. + +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. + +""" + +class Up5kSPRAM(Module): + def __init__(self, width=32, size=64*kB): + self.bus = wishbone.Interface(width) + + # # # + + 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 + + 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 += [ + datain.eq(self.bus.dat_w[16*w:16*(w+1)]), + If(self.bus.adr[14:14+log2_int(depth_cascading)+1] == 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 += Instance("SB_SPRAM256KA", + i_ADDRESS=self.bus.adr[:14], + i_DATAIN=datain, + i_MASKWREN=maskwren, + i_WREN=wren, + i_CHIPSELECT=0b1, + i_CLOCK=ClockSignal("sys"), + i_STANDBY=0b0, + i_SLEEP=0b0, + i_POWEROFF=0b1, + o_DATAOUT=dataout + ) + + self.sync += self.bus.ack.eq(self.bus.stb & self.bus.cyc & ~self.bus.ack) diff --git a/litex/soc/cores/nxlram.py b/litex/soc/cores/ram/lattice_nx.py similarity index 100% rename from litex/soc/cores/nxlram.py rename to litex/soc/cores/ram/lattice_nx.py diff --git a/litex/soc/cores/up5kspram.py b/litex/soc/cores/up5kspram.py index 5f8ecfb76..64e9e0141 100644 --- a/litex/soc/cores/up5kspram.py +++ b/litex/soc/cores/up5kspram.py @@ -1,76 +1,2 @@ -# -# This file is part of LiteX. -# -# Copyright (c) 2019 William D. Jones -# Copyright (c) 2019 Tim 'mithro' Ansell -# Copyright (c) 2019 Florent Kermarrec -# SPDX-License-Identifier: BSD-2-Clause - -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 (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. - -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. - -""" - -class Up5kSPRAM(Module): - def __init__(self, width=32, size=64*kB): - self.bus = wishbone.Interface(width) - - # # # - - 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 - - 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 += [ - datain.eq(self.bus.dat_w[16*w:16*(w+1)]), - If(self.bus.adr[14:14+log2_int(depth_cascading)+1] == 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 += Instance("SB_SPRAM256KA", - i_ADDRESS=self.bus.adr[:14], - i_DATAIN=datain, - i_MASKWREN=maskwren, - i_WREN=wren, - i_CHIPSELECT=0b1, - i_CLOCK=ClockSignal("sys"), - i_STANDBY=0b0, - i_SLEEP=0b0, - i_POWEROFF=0b1, - o_DATAOUT=dataout - ) - - self.sync += self.bus.ack.eq(self.bus.stb & self.bus.cyc & ~self.bus.ack) +# Retro-compatibility 2020-11-09, remove. +from litex.soc.cores.ram.lattice_ice40 import Up5kSPRAM