soc/cores: create ram directory and move SPRAM/LRAM implementation to it.

Will ease maintenance and future additions similarly to clock wrappers. Provide
retro-compatibily layer for Up5kSPRAM that we could remove after next release.
This commit is contained in:
Florent Kermarrec 2020-11-09 11:04:31 +01:00
parent ea8be6adcd
commit 50a47f551e
4 changed files with 85 additions and 76 deletions

View File

@ -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

View File

@ -0,0 +1,76 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2019 William D. Jones <thor0505@comcast.net>
# Copyright (c) 2019 Tim 'mithro' Ansell <me@mith.ro>
# Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
# 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)

View File

@ -1,76 +1,2 @@
# # Retro-compatibility 2020-11-09, remove.
# This file is part of LiteX. from litex.soc.cores.ram.lattice_ice40 import Up5kSPRAM
#
# Copyright (c) 2019 William D. Jones <thor0505@comcast.net>
# Copyright (c) 2019 Tim 'mithro' Ansell <me@mith.ro>
# Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
# 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)