X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fexperiment%2Fdcache.py;h=e1f82b77dc337467c1f9eeff306adc2ade4a7120;hb=41d2c31f6f0d184a57f468d5b157d6e8c0a44af1;hp=44aff9e43e340e5a9e6d4759f66d5fefe72ff9b6;hpb=ba220fd24d3965891ed46080b8eff0027cf83a1f;p=soc.git diff --git a/src/soc/experiment/dcache.py b/src/soc/experiment/dcache.py index 44aff9e4..e1f82b77 100644 --- a/src/soc/experiment/dcache.py +++ b/src/soc/experiment/dcache.py @@ -7,12 +7,13 @@ based on Anton Blanchard microwatt dcache.vhdl from enum import Enum, unique from nmigen import Module, Signal, Elaboratable, Cat, Repl, Array, Const +from nmutil.util import Display + +from random import randint + from nmigen.cli import main from nmutil.iocontrol import RecordObject from nmigen.utils import log2_int -from nmigen.cli import rtlil - - from soc.experiment.mem_types import (LoadStore1ToDCacheType, DCacheToLoadStore1Type, MMUToDCacheType, @@ -25,15 +26,27 @@ from soc.experiment.wb_types import (WB_ADDR_BITS, WB_DATA_BITS, WB_SEL_BITS, WBIOMasterOut, WBIOSlaveOut) from soc.experiment.cache_ram import CacheRam -from soc.experiment.plru import PLRU +#from soc.experiment.plru import PLRU +from nmutil.plru import PLRU + +# for test +from nmigen_soc.wishbone.sram import SRAM +from nmigen import Memory +from nmigen.cli import rtlil + +# NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell +# Also, check out the cxxsim nmigen branch, and latest yosys from git +from nmutil.sim_tmp_alternative import Simulator + +from nmutil.util import wrap # TODO: make these parameters of DCache at some point LINE_SIZE = 64 # Line size in bytes -NUM_LINES = 32 # Number of lines in a set +NUM_LINES = 16 # Number of lines in a set NUM_WAYS = 4 # Number of ways TLB_SET_SIZE = 64 # L1 DTLB entries per set -TLB_NUM_WAYS = 2 # L1 DTLB number of sets +TLB_NUM_WAYS = 4 # L1 DTLB number of sets TLB_LG_PGSZ = 12 # L1 DTLB log_2(page_size) LOG_LENGTH = 0 # Non-zero to enable log data collection @@ -54,6 +67,10 @@ ROW_PER_LINE = LINE_SIZE // ROW_SIZE # to represent the full dcache BRAM_ROWS = NUM_LINES * ROW_PER_LINE +print ("ROW_SIZE", ROW_SIZE) +print ("ROW_PER_LINE", ROW_PER_LINE) +print ("BRAM_ROWS", BRAM_ROWS) +print ("NUM_WAYS", NUM_WAYS) # Bit fields counts in the address @@ -94,26 +111,39 @@ TAG_WIDTH = TAG_BITS + 7 - ((TAG_BITS + 7) % 8) WAY_BITS = log2_int(NUM_WAYS) # Example of layout for 32 lines of 64 bytes: -# -# .. tag |index| line | -# .. | row | | -# .. | |---| | ROW_LINE_BITS (3) -# .. | |--- - --| LINE_OFF_BITS (6) -# .. | |- --| ROW_OFF_BITS (3) -# .. |----- ---| | ROW_BITS (8) -# .. |-----| | INDEX_BITS (5) -# .. --------| | TAG_BITS (45) +layout = """\ + .. tag |index| line | + .. | row | | + .. | |---| | ROW_LINE_BITS (3) + .. | |--- - --| LINE_OFF_BITS (6) + .. | |- --| ROW_OFF_BITS (3) + .. |----- ---| | ROW_BITS (8) + .. |-----| | INDEX_BITS (5) + .. --------| | TAG_BITS (45) +""" +print (layout) +print ("Dcache TAG %d IDX %d ROW_BITS %d ROFF %d LOFF %d RLB %d" % \ + (TAG_BITS, INDEX_BITS, ROW_BITS, + ROW_OFF_BITS, LINE_OFF_BITS, ROW_LINE_BITS)) +print ("index @: %d-%d" % (LINE_OFF_BITS, SET_SIZE_BITS)) +print ("row @: %d-%d" % (LINE_OFF_BITS, ROW_OFF_BITS)) +print ("tag @: %d-%d width %d" % (SET_SIZE_BITS, REAL_ADDR_BITS, TAG_WIDTH)) TAG_RAM_WIDTH = TAG_WIDTH * NUM_WAYS +print ("TAG_RAM_WIDTH", TAG_RAM_WIDTH) + def CacheTagArray(): - return Array(Signal(TAG_RAM_WIDTH) for x in range(NUM_LINES)) + return Array(Signal(TAG_RAM_WIDTH, name="cachetag_%d" % x) \ + for x in range(NUM_LINES)) def CacheValidBitsArray(): - return Array(Signal(INDEX_BITS) for x in range(NUM_LINES)) + return Array(Signal(NUM_WAYS, name="cachevalid_%d" % x) \ + for x in range(NUM_LINES)) def RowPerLineValidArray(): - return Array(Signal() for x in range(ROW_PER_LINE)) + return Array(Signal(name="rows_valid%d" % x) \ + for x in range(ROW_PER_LINE)) # L1 TLB TLB_SET_BITS = log2_int(TLB_SET_SIZE) @@ -123,10 +153,13 @@ TLB_TAG_WAY_BITS = TLB_NUM_WAYS * TLB_EA_TAG_BITS TLB_PTE_BITS = 64 TLB_PTE_WAY_BITS = TLB_NUM_WAYS * TLB_PTE_BITS; +def ispow2(x): + return (1< 64, -# NUM_LINES => 4 -# ) -# port map( -# clk => clk, -# rst => rst, -# d_in => d_in, -# d_out => d_out, -# m_in => m_in, -# m_out => m_out, -# wishbone_out => wb_bram_in, -# wishbone_in => wb_bram_out -# ); -# -# -- BRAM Memory slave -# bram0: entity work.wishbone_bram_wrapper -# generic map( -# MEMORY_SIZE => 1024, -# RAM_INIT_FILE => "icache_test.bin" -# ) -# port map( -# clk => clk, -# rst => rst, -# wishbone_in => wb_bram_in, -# wishbone_out => wb_bram_out -# ); -# -# clk_process: process -# begin -# clk <= '0'; -# wait for clk_period/2; -# clk <= '1'; -# wait for clk_period/2; -# end process; -# -# rst_process: process -# begin -# rst <= '1'; -# wait for 2*clk_period; -# rst <= '0'; -# wait; -# end process; -# -# stim: process -# begin -# -- Clear stuff -# d_in.valid <= '0'; -# d_in.load <= '0'; -# d_in.nc <= '0'; -# d_in.addr <= (others => '0'); -# d_in.data <= (others => '0'); -# m_in.valid <= '0'; -# m_in.addr <= (others => '0'); -# m_in.pte <= (others => '0'); -# -# wait for 4*clk_period; -# wait until rising_edge(clk); -# -# -- Cacheable read of address 4 -# d_in.load <= '1'; -# d_in.nc <= '0'; -# d_in.addr <= x"0000000000000004"; -# d_in.valid <= '1'; -# wait until rising_edge(clk); -# d_in.valid <= '0'; -# -# wait until rising_edge(clk) and d_out.valid = '1'; -# assert d_out.data = x"0000000100000000" -# report "data @" & to_hstring(d_in.addr) & -# "=" & to_hstring(d_out.data) & -# " expected 0000000100000000" -# severity failure; -# -- wait for clk_period; -# -# -- Cacheable read of address 30 -# d_in.load <= '1'; -# d_in.nc <= '0'; -# d_in.addr <= x"0000000000000030"; -# d_in.valid <= '1'; -# wait until rising_edge(clk); -# d_in.valid <= '0'; -# -# wait until rising_edge(clk) and d_out.valid = '1'; -# assert d_out.data = x"0000000D0000000C" -# report "data @" & to_hstring(d_in.addr) & -# "=" & to_hstring(d_out.data) & -# " expected 0000000D0000000C" -# severity failure; -# -# -- Non-cacheable read of address 100 -# d_in.load <= '1'; -# d_in.nc <= '1'; -# d_in.addr <= x"0000000000000100"; -# d_in.valid <= '1'; -# wait until rising_edge(clk); -# d_in.valid <= '0'; -# wait until rising_edge(clk) and d_out.valid = '1'; -# assert d_out.data = x"0000004100000040" -# report "data @" & to_hstring(d_in.addr) & -# "=" & to_hstring(d_out.data) & -# " expected 0000004100000040" -# severity failure; -# -# wait until rising_edge(clk); -# wait until rising_edge(clk); -# wait until rising_edge(clk); -# wait until rising_edge(clk); -# -# std.env.finish; -# end process; -# end; -def dcache_sim(dut): # clear stuff yield dut.d_in.valid.eq(0) yield dut.d_in.load.eq(0) + yield dut.d_in.priv_mode.eq(1) yield dut.d_in.nc.eq(0) - yield dut.d_in.adrr.eq(0) + yield dut.d_in.addr.eq(0) yield dut.d_in.data.eq(0) yield dut.m_in.valid.eq(0) yield dut.m_in.addr.eq(0) @@ -1781,48 +1712,97 @@ def dcache_sim(dut): yield yield yield - # wait_until rising_edge(clk) - yield - # Cacheable read of address 4 - yield dut.d_in.load.eq(1) + + print () + + for i in range(256): + addr = randint(0, 255) + data = randint(0, (1<<64)-1) + sim_mem[addr] = data + addr *= 8 + + print ("testing %x data %x" % (addr, data)) + + yield from dcache_load(dut, addr) + yield from dcache_store(dut, addr, data) + + addr = randint(0, 255) + sim_data = sim_mem[addr] + addr *= 8 + + data = yield from dcache_load(dut, addr) + assert data == sim_data, \ + "check %x data %x != %x" % (addr, data, sim_data) + + for addr in range(256): + data = yield from dcache_load(dut, addr*8) + assert data == sim_mem[addr], \ + "final check %x data %x != %x" % (addr*8, data, sim_mem[addr]) + +def dcache_sim(dut): + # clear stuff + yield dut.d_in.valid.eq(0) + yield dut.d_in.load.eq(0) + yield dut.d_in.priv_mode.eq(1) yield dut.d_in.nc.eq(0) - yield dut.d_in.addr.eq(Const(0x0000000000000004, 64)) - yield dut.d_in.valid.eq(1) - # wait-until rising_edge(clk) + yield dut.d_in.addr.eq(0) + yield dut.d_in.data.eq(0) + yield dut.m_in.valid.eq(0) + yield dut.m_in.addr.eq(0) + yield dut.m_in.pte.eq(0) + # wait 4 * clk_period yield - yield dut.d_in.valid.eq(0) yield - while not (yield dut.d_out.valid): - yield - assert dut.d_out.data == 0x0000000100000000, \ - f"data @ {dut.d_in.addr}={dut.d_in.data} expected 0000000100000000" + yield + yield + + # Cacheable read of address 4 + data = yield from dcache_load(dut, 0x58) + addr = yield dut.d_in.addr + assert data == 0x0000001700000016, \ + f"data @%x=%x expected 0x0000001700000016" % (addr, data) + # Cacheable read of address 20 + data = yield from dcache_load(dut, 0x20) + addr = yield dut.d_in.addr + assert data == 0x0000000900000008, \ + f"data @%x=%x expected 0x0000000900000008" % (addr, data) # Cacheable read of address 30 - yield dut.d_in.load.eq(1) - yield dut.d_in.nc.eq(0) - yield dut.d_in.addr.eq(Const(0x0000000000000030, 64)) - yield dut.d_in.valid.eq(1) - yield - yield dut.d_in.valid.eq(0) - yield - while not (yield dut.d_out.valid): - yield - assert dut.d_out.data == 0x0000000D0000000C, \ - f"data @{dut.d_in.addr}={dut.d_out.data} expected 0000000D0000000C" + data = yield from dcache_load(dut, 0x530) + addr = yield dut.d_in.addr + assert data == 0x0000014D0000014C, \ + f"data @%x=%x expected 0000014D0000014C" % (addr, data) + + # 2nd Cacheable read of address 30 + data = yield from dcache_load(dut, 0x530) + addr = yield dut.d_in.addr + assert data == 0x0000014D0000014C, \ + f"data @%x=%x expected 0000014D0000014C" % (addr, data) # Non-cacheable read of address 100 - yield dut.d_in.load.eq(1) - yield dut.d_in.nc.eq(1) - yield dut.d_in.addr.eq(Const(0x0000000000000100, 64)) - yield dut.d_in.valid.eq(1) - yield - yield dut.d_in.valid.eq(0) - yield - while not (yield dut.d_out.valid): - yield - assert dut.d_out.data == 0x0000004100000040, \ - f"data @ {dut.d_in.addr}={dut.d_out.data} expected 0000004100000040" + data = yield from dcache_load(dut, 0x100, nc=1) + addr = yield dut.d_in.addr + assert data == 0x0000004100000040, \ + f"data @%x=%x expected 0000004100000040" % (addr, data) + + # Store at address 530 + yield from dcache_store(dut, 0x530, 0x121) + + # Store at address 30 + yield from dcache_store(dut, 0x530, 0x12345678) + + # 3nd Cacheable read of address 530 + data = yield from dcache_load(dut, 0x530) + addr = yield dut.d_in.addr + assert data == 0x12345678, \ + f"data @%x=%x expected 0x12345678" % (addr, data) + + # 4th Cacheable read of address 20 + data = yield from dcache_load(dut, 0x20) + addr = yield dut.d_in.addr + assert data == 0x0000000900000008, \ + f"data @%x=%x expected 0x0000000900000008" % (addr, data) yield yield @@ -1830,14 +1810,44 @@ def dcache_sim(dut): yield -def test_dcache(): +def test_dcache(mem, test_fn, test_name): + dut = DCache() + + memory = Memory(width=64, depth=16*64, init=mem) + sram = SRAM(memory=memory, granularity=8) + + m = Module() + m.submodules.dcache = dut + m.submodules.sram = sram + + m.d.comb += sram.bus.cyc.eq(dut.wb_out.cyc) + m.d.comb += sram.bus.stb.eq(dut.wb_out.stb) + m.d.comb += sram.bus.we.eq(dut.wb_out.we) + m.d.comb += sram.bus.sel.eq(dut.wb_out.sel) + m.d.comb += sram.bus.adr.eq(dut.wb_out.adr) + m.d.comb += sram.bus.dat_w.eq(dut.wb_out.dat) + + m.d.comb += dut.wb_in.ack.eq(sram.bus.ack) + m.d.comb += dut.wb_in.dat.eq(sram.bus.dat_r) + + # nmigen Simulation + sim = Simulator(m) + sim.add_clock(1e-6) + + sim.add_sync_process(wrap(test_fn(dut))) + with sim.write_vcd('test_dcache%s.vcd' % test_name): + sim.run() + +if __name__ == '__main__': dut = DCache() vl = rtlil.convert(dut, ports=[]) with open("test_dcache.il", "w") as f: f.write(vl) - #run_simulation(dut, dcache_sim(), vcd_name='test_dcache.vcd') + mem = [] + for i in range(0,512): + mem.append((i*2)| ((i*2+1)<<32)) -if __name__ == '__main__': - test_dcache() + test_dcache(mem, dcache_sim, "") + test_dcache(None, dcache_random_sim, "random")