3 based on Anton Blanchard microwatt dcache.vhdl
5 note that the microwatt dcache wishbone interface expects "stall".
6 for simplicity at the moment this is hard-coded to cyc & ~ack.
7 see WB4 spec, p84, section 5.2.1
9 IMPORTANT: for store, the data is sampled the cycle AFTER the "valid"
14 * https://libre-soc.org/3d_gpu/architecture/set_associative_cache.jpg
15 * https://bugs.libre-soc.org/show_bug.cgi?id=469
21 from nmutil
.gtkw
import write_gtkw
23 sys
.setrecursionlimit(1000000)
25 from enum
import Enum
, unique
27 from nmigen
import Module
, Signal
, Elaboratable
, Cat
, Repl
, Array
, Const
29 from copy
import deepcopy
30 from random
import randint
, seed
32 from soc
.experiment
.cache_ram
import CacheRam
35 from soc
.bus
.sram
import SRAM
36 from nmigen
import Memory
37 from nmigen
.cli
import rtlil
39 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
40 # Also, check out the cxxsim nmigen branch, and latest yosys from git
41 from nmutil
.sim_tmp_alternative
import Simulator
43 from nmutil
.util
import wrap
45 from soc
.experiment
.dcache
import DCache
48 def dcache_load(dut
, addr
, nc
=0):
49 yield dut
.d_in
.load
.eq(1)
50 yield dut
.d_in
.nc
.eq(nc
)
51 yield dut
.d_in
.addr
.eq(addr
)
52 yield dut
.d_in
.byte_sel
.eq(~
0)
53 yield dut
.d_in
.valid
.eq(1)
55 yield dut
.d_in
.valid
.eq(0)
56 yield dut
.d_in
.byte_sel
.eq(0)
57 while not (yield dut
.d_out
.valid
):
59 # yield # data is valid one cycle AFTER valid goes hi? (no it isn't)
60 data
= yield dut
.d_out
.data
64 def dcache_store(dut
, addr
, data
, nc
=0):
65 yield dut
.d_in
.load
.eq(0)
66 yield dut
.d_in
.nc
.eq(nc
)
67 yield dut
.d_in
.byte_sel
.eq(~
0)
68 yield dut
.d_in
.addr
.eq(addr
)
69 yield dut
.d_in
.valid
.eq(1)
71 yield dut
.d_in
.data
.eq(data
) # leave set, but the cycle AFTER
72 yield dut
.d_in
.valid
.eq(0)
73 yield dut
.d_in
.byte_sel
.eq(0)
74 while not (yield dut
.d_out
.valid
):
78 def dcache_random_sim(dut
, mem
, nc
=0):
81 sim_mem
= deepcopy(mem
)
82 memsize
= len(sim_mem
)
83 print ("mem len", memsize
)
86 yield dut
.d_in
.valid
.eq(0)
87 yield dut
.d_in
.load
.eq(0)
88 yield dut
.d_in
.priv_mode
.eq(1)
89 yield dut
.d_in
.nc
.eq(0)
90 yield dut
.d_in
.addr
.eq(0)
91 yield dut
.d_in
.data
.eq(0)
92 yield dut
.m_in
.valid
.eq(0)
93 yield dut
.m_in
.addr
.eq(0)
94 yield dut
.m_in
.pte
.eq(0)
103 #for i in range(1024):
106 for i
in range(1024):
107 addr
= randint(0, memsize
-1)
108 data
= randint(0, (1<<64)-1)
113 print ("random testing %d 0x%x row %d data 0x%x" % (i
, addr
, row
, data
))
115 yield from dcache_load(dut
, addr
, nc
)
116 yield from dcache_store(dut
, addr
, data
, nc
)
118 addr
= randint(0, memsize
-1)
119 sim_data
= sim_mem
[addr
]
123 print (" load 0x%x row %d expect data 0x%x" % (addr
, row
, sim_data
))
124 data
= yield from dcache_load(dut
, addr
, nc
)
125 assert data
== sim_data
, \
126 "check addr 0x%x row %d data %x != %x" % (addr
, row
, data
, sim_data
)
128 for addr
in range(memsize
):
129 data
= yield from dcache_load(dut
, addr
*8, nc
)
130 assert data
== sim_mem
[addr
], \
131 "final check %x data %x != %x" % (addr
*8, data
, sim_mem
[addr
])
134 def dcache_regression_sim(dut
, mem
, nc
=0):
137 sim_mem
= deepcopy(mem
)
138 memsize
= len(sim_mem
)
139 print ("mem len", memsize
)
142 yield dut
.d_in
.valid
.eq(0)
143 yield dut
.d_in
.load
.eq(0)
144 yield dut
.d_in
.priv_mode
.eq(1)
145 yield dut
.d_in
.nc
.eq(0)
146 yield dut
.d_in
.addr
.eq(0)
147 yield dut
.d_in
.data
.eq(0)
148 yield dut
.m_in
.valid
.eq(0)
149 yield dut
.m_in
.addr
.eq(0)
150 yield dut
.m_in
.pte
.eq(0)
151 # wait 4 * clk_period
161 print ("random testing %d 0x%x row %d" % (i
, addr
, row
))
163 yield from dcache_load(dut
, addr
, nc
)
166 sim_data
= sim_mem
[addr
]
170 print (" load 0x%x row %d expect data 0x%x" % (addr
, row
, sim_data
))
171 data
= yield from dcache_load(dut
, addr
, nc
)
172 assert data
== sim_data
, \
173 "check addr 0x%x row %d data %x != %x" % (addr
, row
, data
, sim_data
)
177 def dcache_sim(dut
, mem
):
179 yield dut
.d_in
.valid
.eq(0)
180 yield dut
.d_in
.load
.eq(0)
181 yield dut
.d_in
.priv_mode
.eq(1)
182 yield dut
.d_in
.nc
.eq(0)
183 yield dut
.d_in
.addr
.eq(0)
184 yield dut
.d_in
.data
.eq(0)
185 yield dut
.m_in
.valid
.eq(0)
186 yield dut
.m_in
.addr
.eq(0)
187 yield dut
.m_in
.pte
.eq(0)
188 # wait 4 * clk_period
194 # Cacheable read of address 4
195 data
= yield from dcache_load(dut
, 0x58)
196 addr
= yield dut
.d_in
.addr
197 assert data
== 0x0000001700000016, \
198 f
"data @%x=%x expected 0x0000001700000016" % (addr
, data
)
200 # Cacheable read of address 20
201 data
= yield from dcache_load(dut
, 0x20)
202 addr
= yield dut
.d_in
.addr
203 assert data
== 0x0000000900000008, \
204 f
"data @%x=%x expected 0x0000000900000008" % (addr
, data
)
206 # Cacheable read of address 30
207 data
= yield from dcache_load(dut
, 0x530)
208 addr
= yield dut
.d_in
.addr
209 assert data
== 0x0000014D0000014C, \
210 f
"data @%x=%x expected 0000014D0000014C" % (addr
, data
)
212 # 2nd Cacheable read of address 30
213 data
= yield from dcache_load(dut
, 0x530)
214 addr
= yield dut
.d_in
.addr
215 assert data
== 0x0000014D0000014C, \
216 f
"data @%x=%x expected 0000014D0000014C" % (addr
, data
)
218 # Non-cacheable read of address 100
219 data
= yield from dcache_load(dut
, 0x100, nc
=1)
220 addr
= yield dut
.d_in
.addr
221 assert data
== 0x0000004100000040, \
222 f
"data @%x=%x expected 0000004100000040" % (addr
, data
)
224 # Store at address 530
225 yield from dcache_store(dut
, 0x530, 0x121)
227 # Store at address 30
228 yield from dcache_store(dut
, 0x530, 0x12345678)
230 # 3nd Cacheable read of address 530
231 data
= yield from dcache_load(dut
, 0x530)
232 addr
= yield dut
.d_in
.addr
233 assert data
== 0x12345678, \
234 f
"data @%x=%x expected 0x12345678" % (addr
, data
)
236 # 4th Cacheable read of address 20
237 data
= yield from dcache_load(dut
, 0x20)
238 addr
= yield dut
.d_in
.addr
239 assert data
== 0x0000000900000008, \
240 f
"data @%x=%x expected 0x0000000900000008" % (addr
, data
)
248 def test_dcache(mem
, test_fn
, test_name
):
251 memory
= Memory(width
=64, depth
=len(mem
), init
=mem
, simulate
=True)
252 sram
= SRAM(memory
=memory
, granularity
=8)
255 m
.submodules
.dcache
= dut
256 m
.submodules
.sram
= sram
258 m
.d
.comb
+= sram
.bus
.cyc
.eq(dut
.wb_out
.cyc
)
259 m
.d
.comb
+= sram
.bus
.stb
.eq(dut
.wb_out
.stb
)
260 m
.d
.comb
+= sram
.bus
.we
.eq(dut
.wb_out
.we
)
261 m
.d
.comb
+= sram
.bus
.sel
.eq(dut
.wb_out
.sel
)
262 m
.d
.comb
+= sram
.bus
.adr
.eq(dut
.wb_out
.adr
)
263 m
.d
.comb
+= sram
.bus
.dat_w
.eq(dut
.wb_out
.dat
)
265 m
.d
.comb
+= dut
.wb_in
.ack
.eq(sram
.bus
.ack
)
266 m
.d
.comb
+= dut
.wb_in
.dat
.eq(sram
.bus
.dat_r
)
268 dcache_write_gtkw(test_name
)
274 sim
.add_sync_process(wrap(test_fn(dut
, mem
)))
275 with sim
.write_vcd('test_dcache%s.vcd' % test_name
):
279 def dcache_write_gtkw(test_name
):
283 'd_in_load', 'd_in_nc', 'd_in_addr[63:0]', 'd_in_data[63:0]',
284 'd_in_byte_sel[7:0]', 'd_in_valid'
287 'd_out_valid', 'd_out_data[63:0]'
290 'wb_out_cyc', 'wb_out_stb', 'wb_out_we',
291 'wb_out_adr[31:0]', 'wb_out_sel[7:0]', 'wb_out_dat[63:0]'
294 'wb_in_stall', 'wb_in_ack', 'wb_in_dat[63:0]'
297 write_gtkw('test_dcache%s.gtkw' % test_name
,
298 'test_dcache%s.vcd' % test_name
,
299 traces
, module
='top.dcache')
302 if __name__
== '__main__':
305 vl
= rtlil
.convert(dut
, ports
=[])
306 with
open("test_dcache.il", "w") as f
:
311 for i
in range(memsize
):
314 test_dcache(mem
, dcache_regression_sim
, "simpleregression")
318 for i
in range(memsize
):
321 test_dcache(mem
, dcache_random_sim
, "random")
324 for i
in range(1024):
325 mem
.append((i
*2)|
((i
*2+1)<<32))
327 test_dcache(mem
, dcache_sim
, "")