sdram: use wishbone cache as L2 cache and add optional L2 cache to Minicon
This commit is contained in:
parent
a1f7ecc8c5
commit
3b9f287bab
|
@ -58,8 +58,8 @@ class _Bank(Module):
|
||||||
|
|
||||||
|
|
||||||
class MiniconSettings:
|
class MiniconSettings:
|
||||||
def __init__(self):
|
def __init__(self, l2_size=0):
|
||||||
pass
|
self.l2_size = l2_size
|
||||||
|
|
||||||
|
|
||||||
class Minicon(Module):
|
class Minicon(Module):
|
||||||
|
|
|
@ -1,168 +1,49 @@
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
from migen.bus import wishbone
|
|
||||||
from migen.bank.description import *
|
|
||||||
from migen.genlib.fsm import FSM, NextState
|
from migen.genlib.fsm import FSM, NextState
|
||||||
from migen.genlib.misc import split, displacer, chooser
|
|
||||||
from migen.genlib.record import Record, layout_len
|
|
||||||
|
|
||||||
|
class WB2LASMI(Module):
|
||||||
# cachesize (in 32-bit words) is the size of the data store, must be a power of 2
|
def __init__(self, wishbone, lasmim):
|
||||||
class WB2LASMI(Module, AutoCSR):
|
|
||||||
def __init__(self, cachesize, lasmim):
|
|
||||||
self._cachesize = CSRStatus(8, reset=log2_int(cachesize))
|
|
||||||
self.wishbone = wishbone.Interface()
|
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
data_width = flen(self.wishbone.dat_r)
|
|
||||||
if lasmim.dw > data_width and (lasmim.dw % data_width) != 0:
|
|
||||||
raise ValueError("LASMI data width must be a multiple of {dw}".format(dw=data_width))
|
|
||||||
if lasmim.dw < data_width and (data_width % lasmim.dw) != 0:
|
|
||||||
raise ValueError("WISHBONE data width must be a multiple of {dw}".format(dw=lasmim.dw))
|
|
||||||
|
|
||||||
# Split address:
|
|
||||||
# TAG | LINE NUMBER | LINE OFFSET
|
|
||||||
offsetbits = log2_int(max(lasmim.dw//data_width, 1))
|
|
||||||
addressbits = lasmim.aw + offsetbits
|
|
||||||
linebits = log2_int(cachesize) - offsetbits
|
|
||||||
tagbits = addressbits - linebits
|
|
||||||
wordbits = log2_int(max(data_width//lasmim.dw, 1))
|
|
||||||
adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits)
|
|
||||||
word = Signal(wordbits) if wordbits else None
|
|
||||||
|
|
||||||
# Data memory
|
|
||||||
data_mem = Memory(lasmim.dw*2**wordbits, 2**linebits)
|
|
||||||
data_port = data_mem.get_port(write_capable=True, we_granularity=8)
|
|
||||||
self.specials += data_mem, data_port
|
|
||||||
|
|
||||||
write_from_lasmi = Signal()
|
|
||||||
write_to_lasmi = Signal()
|
|
||||||
if adr_offset is None:
|
|
||||||
adr_offset_r = None
|
|
||||||
else:
|
|
||||||
adr_offset_r = Signal(offsetbits)
|
|
||||||
self.sync += adr_offset_r.eq(adr_offset)
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
data_port.adr.eq(adr_line),
|
|
||||||
If(write_from_lasmi,
|
|
||||||
displacer(lasmim.dat_r, word, data_port.dat_w),
|
|
||||||
displacer(Replicate(1, lasmim.dw//8), word, data_port.we)
|
|
||||||
).Else(
|
|
||||||
data_port.dat_w.eq(Replicate(self.wishbone.dat_w, max(lasmim.dw//data_width, 1))),
|
|
||||||
If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack,
|
|
||||||
displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
If(write_to_lasmi,
|
|
||||||
chooser(data_port.dat_r, word, lasmim.dat_w),
|
|
||||||
lasmim.dat_we.eq(2**(lasmim.dw//8)-1)
|
|
||||||
),
|
|
||||||
chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# Tag memory
|
|
||||||
tag_layout = [("tag", tagbits), ("dirty", 1)]
|
|
||||||
tag_mem = Memory(layout_len(tag_layout), 2**linebits)
|
|
||||||
tag_port = tag_mem.get_port(write_capable=True)
|
|
||||||
self.specials += tag_mem, tag_port
|
|
||||||
tag_do = Record(tag_layout)
|
|
||||||
tag_di = Record(tag_layout)
|
|
||||||
self.comb += [
|
|
||||||
tag_do.raw_bits().eq(tag_port.dat_r),
|
|
||||||
tag_port.dat_w.eq(tag_di.raw_bits())
|
|
||||||
]
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
tag_port.adr.eq(adr_line),
|
|
||||||
tag_di.tag.eq(adr_tag)
|
|
||||||
]
|
|
||||||
if word is not None:
|
|
||||||
self.comb += lasmim.adr.eq(Cat(word, adr_line, tag_do.tag))
|
|
||||||
else:
|
|
||||||
self.comb += lasmim.adr.eq(Cat(adr_line, tag_do.tag))
|
|
||||||
|
|
||||||
# Lasmim word computation, word_clr and word_inc will be simplified
|
|
||||||
# at synthesis when wordbits=0
|
|
||||||
word_clr = Signal()
|
|
||||||
word_inc = Signal()
|
|
||||||
if word is not None:
|
|
||||||
self.sync += \
|
|
||||||
If(word_clr,
|
|
||||||
word.eq(0),
|
|
||||||
).Elif(word_inc,
|
|
||||||
word.eq(word+1)
|
|
||||||
)
|
|
||||||
|
|
||||||
def word_is_last(word):
|
|
||||||
if word is not None:
|
|
||||||
return word == 2**wordbits-1
|
|
||||||
else:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
# Control FSM
|
# Control FSM
|
||||||
assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1)
|
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||||
fsm = FSM(reset_state="IDLE")
|
|
||||||
self.submodules += fsm
|
|
||||||
|
|
||||||
|
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT"))
|
If(wishbone.cyc & wishbone.stb,
|
||||||
|
NextState("REQUEST")
|
||||||
|
)
|
||||||
)
|
)
|
||||||
fsm.act("TEST_HIT",
|
fsm.act("REQUEST",
|
||||||
word_clr.eq(1),
|
lasmim.stb.eq(1),
|
||||||
If(tag_do.tag == adr_tag,
|
lasmim.we.eq(wishbone.we),
|
||||||
self.wishbone.ack.eq(1),
|
If(lasmim.req_ack,
|
||||||
If(self.wishbone.we,
|
If(wishbone.we,
|
||||||
tag_di.dirty.eq(1),
|
NextState("WRITE_DATA")
|
||||||
tag_port.we.eq(1)
|
|
||||||
),
|
|
||||||
NextState("IDLE")
|
|
||||||
).Else(
|
|
||||||
If(tag_do.dirty,
|
|
||||||
NextState("EVICT_REQUEST")
|
|
||||||
).Else(
|
).Else(
|
||||||
NextState("REFILL_WRTAG")
|
NextState("READ_DATA")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
fsm.act("WRITE_DATA",
|
||||||
fsm.act("EVICT_REQUEST",
|
|
||||||
lasmim.stb.eq(1),
|
|
||||||
lasmim.we.eq(1),
|
|
||||||
If(lasmim.req_ack, NextState("EVICT_DATA"))
|
|
||||||
)
|
|
||||||
fsm.act("EVICT_DATA",
|
|
||||||
If(lasmim.dat_w_ack,
|
If(lasmim.dat_w_ack,
|
||||||
write_to_lasmi.eq(1),
|
lasmim.dat_we.eq(wishbone.sel),
|
||||||
word_inc.eq(1),
|
wishbone.ack.eq(1),
|
||||||
If(word_is_last(word),
|
NextState("IDLE")
|
||||||
NextState("REFILL_WRTAG"),
|
|
||||||
).Else(
|
|
||||||
NextState("EVICT_REQUEST")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
fsm.act("READ_DATA",
|
||||||
|
If(lasmim.dat_r_ack,
|
||||||
|
wishbone.ack.eq(1),
|
||||||
|
NextState("IDLE")
|
||||||
|
),
|
||||||
|
NextState("IDLE")
|
||||||
|
)
|
||||||
|
|
||||||
fsm.act("REFILL_WRTAG",
|
# Address / Datapath
|
||||||
# Write the tag first to set the LASMI address
|
self.comb += [
|
||||||
tag_port.we.eq(1),
|
lasmim.adr.eq(wishbone.adr),
|
||||||
word_clr.eq(1),
|
If(lasmim.dat_w_ack,
|
||||||
NextState("REFILL_REQUEST")
|
lasmim.dat_w.eq(wishbone.dat_w),
|
||||||
)
|
),
|
||||||
fsm.act("REFILL_REQUEST",
|
wishbone.dat_r.eq(lasmim.dat_r)
|
||||||
lasmim.stb.eq(1),
|
]
|
||||||
If(lasmim.req_ack, NextState("REFILL_DATA"))
|
|
||||||
)
|
|
||||||
fsm.act("REFILL_DATA",
|
|
||||||
If(lasmim.dat_r_ack,
|
|
||||||
write_from_lasmi.eq(1),
|
|
||||||
word_inc.eq(1),
|
|
||||||
If(word_is_last(word),
|
|
||||||
NextState("TEST_HIT"),
|
|
||||||
).Else(
|
|
||||||
NextState("REFILL_REQUEST")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ from misoclib.soc import SoC
|
||||||
class SDRAMSoC(SoC):
|
class SDRAMSoC(SoC):
|
||||||
csr_map = {
|
csr_map = {
|
||||||
"sdram": 8,
|
"sdram": 8,
|
||||||
"wishbone2lasmi": 9,
|
"l2_cache": 9,
|
||||||
"memtest_w": 10,
|
"memtest_w": 10,
|
||||||
"memtest_r": 11
|
"memtest_r": 11
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ class SDRAMSoC(SoC):
|
||||||
phy.module.geom_settings.colbits)*sdram_width//8
|
phy.module.geom_settings.colbits)*sdram_width//8
|
||||||
# XXX: Limit main_ram_size to 256MB, we should modify mem_map to allow larger memories.
|
# XXX: Limit main_ram_size to 256MB, we should modify mem_map to allow larger memories.
|
||||||
main_ram_size = min(main_ram_size, 256*1024*1024)
|
main_ram_size = min(main_ram_size, 256*1024*1024)
|
||||||
|
l2_size = self.sdram_controller_settings.l2_size
|
||||||
|
|
||||||
# LASMICON frontend
|
# LASMICON frontend
|
||||||
if isinstance(self.sdram_controller_settings, LASMIconSettings):
|
if isinstance(self.sdram_controller_settings, LASMIconSettings):
|
||||||
|
@ -55,23 +56,39 @@ class SDRAMSoC(SoC):
|
||||||
self.submodules.memtest_w = memtest.MemtestWriter(self.sdram.crossbar.get_master())
|
self.submodules.memtest_w = memtest.MemtestWriter(self.sdram.crossbar.get_master())
|
||||||
self.submodules.memtest_r = memtest.MemtestReader(self.sdram.crossbar.get_master())
|
self.submodules.memtest_r = memtest.MemtestReader(self.sdram.crossbar.get_master())
|
||||||
|
|
||||||
l2_size = self.sdram_controller_settings.l2_size
|
|
||||||
if l2_size:
|
if l2_size:
|
||||||
|
sdram_bus = wishbone.Interface()
|
||||||
|
lasmim = self.sdram.crossbar.get_master()
|
||||||
|
l2_cache = wishbone.Cache(l2_size//4, sdram_bus, wishbone.Interface(lasmim.dw))
|
||||||
# XXX Vivado ->2015.1 workaround, Vivado is not able to map correctly our L2 cache.
|
# XXX Vivado ->2015.1 workaround, Vivado is not able to map correctly our L2 cache.
|
||||||
# Issue is reported to Xilinx and should be fixed in next releases (2015.2?).
|
# Issue is reported to Xilinx and should be fixed in next releases (2015.2?).
|
||||||
# Remove this workaround when fixed by Xilinx.
|
# Remove this workaround when fixed by Xilinx.
|
||||||
from mibuild.xilinx.vivado import XilinxVivadoToolchain
|
from mibuild.xilinx.vivado import XilinxVivadoToolchain
|
||||||
if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
|
if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
|
||||||
from migen.fhdl.simplify import FullMemoryWE
|
from migen.fhdl.simplify import FullMemoryWE
|
||||||
self.submodules.wishbone2lasmi = FullMemoryWE()(wishbone2lasmi.WB2LASMI(l2_size//4, self.sdram.crossbar.get_master()))
|
self.submodules.l2_cache = FullMemoryWE()(l2_cache)
|
||||||
else:
|
else:
|
||||||
self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(l2_size//4, self.sdram.crossbar.get_master())
|
self.submodules.l2_cache = l2_cache
|
||||||
self.register_mem("main_ram", self.mem_map["main_ram"], self.wishbone2lasmi.wishbone, main_ram_size)
|
self.submodules.wishbone2lasmi = wishbone2lasmi.WB2LASMI(self.l2_cache.slave, lasmim)
|
||||||
|
self.register_mem("main_ram", self.mem_map["main_ram"], sdram_bus, main_ram_size)
|
||||||
|
|
||||||
# MINICON frontend
|
# MINICON frontend
|
||||||
elif isinstance(self.sdram_controller_settings, MiniconSettings):
|
elif isinstance(self.sdram_controller_settings, MiniconSettings):
|
||||||
self.submodules.converter = wishbone.Converter(wishbone.Interface(), self.sdram.controller.bus)
|
sdram_bus = wishbone.Interface()
|
||||||
self.register_mem("main_ram", self.mem_map["main_ram"], self.converter.master, main_ram_size)
|
if l2_size:
|
||||||
|
l2_cache = wishbone.Cache(l2_size//4, sdram_bus, self.sdram.controller.bus)
|
||||||
|
# XXX Vivado ->2015.1 workaround, Vivado is not able to map correctly our L2 cache.
|
||||||
|
# Issue is reported to Xilinx and should be fixed in next releases (2015.2?).
|
||||||
|
# Remove this workaround when fixed by Xilinx.
|
||||||
|
from mibuild.xilinx.vivado import XilinxVivadoToolchain
|
||||||
|
if isinstance(self.platform.toolchain, XilinxVivadoToolchain):
|
||||||
|
from migen.fhdl.simplify import FullMemoryWE
|
||||||
|
self.submodules.l2_cache = FullMemoryWE()(l2_cache)
|
||||||
|
else:
|
||||||
|
self.submodules.l2_cache = l2_cache
|
||||||
|
else:
|
||||||
|
self.submodules.converter = wishbone.Converter(sdram_bus, self.sdram.controller.bus)
|
||||||
|
self.register_mem("main_ram", self.mem_map["main_ram"], sdram_bus, main_ram_size)
|
||||||
|
|
||||||
def do_finalize(self):
|
def do_finalize(self):
|
||||||
if not self.integrated_main_ram_size:
|
if not self.integrated_main_ram_size:
|
||||||
|
|
|
@ -67,7 +67,7 @@ void flush_cpu_dcache(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CSR_WISHBONE2LASMI_BASE
|
#ifdef CSR_L2_CACHE_BASE
|
||||||
void flush_l2_cache(void)
|
void flush_l2_cache(void)
|
||||||
{
|
{
|
||||||
unsigned int l2_nwords;
|
unsigned int l2_nwords;
|
||||||
|
@ -75,7 +75,7 @@ void flush_l2_cache(void)
|
||||||
register unsigned int addr;
|
register unsigned int addr;
|
||||||
register unsigned int dummy;
|
register unsigned int dummy;
|
||||||
|
|
||||||
l2_nwords = 1 << wishbone2lasmi_cachesize_read();
|
l2_nwords = 1 << l2_cache_size_read();
|
||||||
for(i=0;i<2*l2_nwords;i++) {
|
for(i=0;i<2*l2_nwords;i++) {
|
||||||
addr = MAIN_RAM_BASE + i*4;
|
addr = MAIN_RAM_BASE + i*4;
|
||||||
#if defined (__lm32__)
|
#if defined (__lm32__)
|
||||||
|
|
Loading…
Reference in New Issue