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:
parent
ea8be6adcd
commit
50a47f551e
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
||||||
|
|
Loading…
Reference in New Issue