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_m(dut
, addr
, nc
=0):
55 pte
= RD | WR | REF | PRIV
56 yield dut
.m_in
.pte
.eq(pte
)
57 yield dut
.m_in
.addr
.eq(addr
)
58 yield dut
.m_in
.valid
.eq(1)
60 yield dut
.m_in
.valid
.eq(0)
61 while not (yield dut
.m_out
.done
):
63 # yield # data is valid one cycle AFTER valid goes hi? (no it isn't)
64 data
= yield dut
.m_out
.data
68 def dcache_load(dut
, addr
, nc
=0):
69 yield dut
.d_in
.load
.eq(1)
70 yield dut
.d_in
.nc
.eq(nc
)
71 yield dut
.d_in
.addr
.eq(addr
)
72 yield dut
.d_in
.byte_sel
.eq(~
0)
73 yield dut
.d_in
.valid
.eq(1)
75 yield dut
.d_in
.valid
.eq(0)
76 yield dut
.d_in
.byte_sel
.eq(0)
77 while not (yield dut
.d_out
.valid
):
79 # yield # data is valid one cycle AFTER valid goes hi? (no it isn't)
80 data
= yield dut
.d_out
.data
84 def dcache_store(dut
, addr
, data
, nc
=0):
85 yield dut
.d_in
.load
.eq(0)
86 yield dut
.d_in
.nc
.eq(nc
)
87 yield dut
.d_in
.byte_sel
.eq(~
0)
88 yield dut
.d_in
.addr
.eq(addr
)
89 yield dut
.d_in
.valid
.eq(1)
91 yield dut
.d_in
.data
.eq(data
) # leave set, but the cycle AFTER
92 yield dut
.d_in
.valid
.eq(0)
93 yield dut
.d_in
.byte_sel
.eq(0)
94 while not (yield dut
.d_out
.valid
):
98 def dcache_random_sim(dut
, mem
, nc
=0):
101 sim_mem
= deepcopy(mem
)
102 memsize
= len(sim_mem
)
103 print ("mem len", memsize
)
106 yield dut
.d_in
.valid
.eq(0)
107 yield dut
.d_in
.load
.eq(0)
108 yield dut
.d_in
.priv_mode
.eq(1)
109 yield dut
.d_in
.nc
.eq(0)
110 yield dut
.d_in
.addr
.eq(0)
111 yield dut
.d_in
.data
.eq(0)
112 yield dut
.m_in
.valid
.eq(0)
113 yield dut
.m_in
.addr
.eq(0)
114 yield dut
.m_in
.pte
.eq(0)
115 # wait 4 * clk_period
123 #for i in range(1024):
126 for i
in range(1024):
127 addr
= randint(0, memsize
-1)
128 data
= randint(0, (1<<64)-1)
133 print ("random testing %d 0x%x row %d data 0x%x" % (i
, addr
, row
, data
))
135 yield from dcache_load(dut
, addr
, nc
)
136 yield from dcache_store(dut
, addr
, data
, nc
)
138 addr
= randint(0, memsize
-1)
139 sim_data
= sim_mem
[addr
]
143 print (" load 0x%x row %d expect data 0x%x" % (addr
, row
, sim_data
))
144 data
= yield from dcache_load(dut
, addr
, nc
)
145 assert data
== sim_data
, \
146 "check addr 0x%x row %d data %x != %x" % (addr
, row
, data
, sim_data
)
148 for addr
in range(memsize
):
149 data
= yield from dcache_load(dut
, addr
*8, nc
)
150 assert data
== sim_mem
[addr
], \
151 "final check %x data %x != %x" % (addr
*8, data
, sim_mem
[addr
])
154 def dcache_regression_sim(dut
, mem
, nc
=0):
157 sim_mem
= deepcopy(mem
)
158 memsize
= len(sim_mem
)
159 print ("mem len", memsize
)
162 yield dut
.d_in
.valid
.eq(0)
163 yield dut
.d_in
.load
.eq(0)
164 yield dut
.d_in
.priv_mode
.eq(1)
165 yield dut
.d_in
.nc
.eq(0)
166 yield dut
.d_in
.addr
.eq(0)
167 yield dut
.d_in
.data
.eq(0)
168 yield dut
.m_in
.valid
.eq(0)
169 yield dut
.m_in
.addr
.eq(0)
170 yield dut
.m_in
.pte
.eq(0)
171 # wait 4 * clk_period
181 print ("random testing %d 0x%x row %d" % (i
, addr
, row
))
183 yield from dcache_load(dut
, addr
, nc
)
186 sim_data
= sim_mem
[addr
]
190 print (" load 0x%x row %d expect data 0x%x" % (addr
, row
, sim_data
))
191 data
= yield from dcache_load(dut
, addr
, nc
)
192 assert data
== sim_data
, \
193 "check addr 0x%x row %d data %x != %x" % (addr
, row
, data
, sim_data
)
197 def dcache_sim(dut
, mem
):
199 yield dut
.d_in
.valid
.eq(0)
200 yield dut
.d_in
.load
.eq(0)
201 yield dut
.d_in
.priv_mode
.eq(1)
202 yield dut
.d_in
.nc
.eq(0)
203 yield dut
.d_in
.addr
.eq(0)
204 yield dut
.d_in
.data
.eq(0)
205 yield dut
.m_in
.valid
.eq(0)
206 yield dut
.m_in
.addr
.eq(0)
207 yield dut
.m_in
.pte
.eq(0)
208 # wait 4 * clk_period
214 # Cacheable read of address 4
215 data
= yield from dcache_load_m(dut
, 0x58)
216 print ("dcache m_load 0x58", hex(data
))
220 # Cacheable read of address 4
221 data
= yield from dcache_load_m(dut
, 0x58)
222 print ("dcache m_load 0x58", hex(data
))
228 assert data
== 0x0000001700000016, \
229 f
"data @%x=%x expected 0x0000001700000016" % (addr
, data
)
231 # Cacheable read of address 20
232 data
= yield from dcache_load(dut
, 0x20)
233 addr
= yield dut
.d_in
.addr
234 assert data
== 0x0000000900000008, \
235 f
"data @%x=%x expected 0x0000000900000008" % (addr
, data
)
237 # Cacheable read of address 30
238 data
= yield from dcache_load(dut
, 0x530)
239 addr
= yield dut
.d_in
.addr
240 assert data
== 0x0000014D0000014C, \
241 f
"data @%x=%x expected 0000014D0000014C" % (addr
, data
)
243 # 2nd Cacheable read of address 30
244 data
= yield from dcache_load(dut
, 0x530)
245 addr
= yield dut
.d_in
.addr
246 assert data
== 0x0000014D0000014C, \
247 f
"data @%x=%x expected 0000014D0000014C" % (addr
, data
)
249 # Non-cacheable read of address 100
250 data
= yield from dcache_load(dut
, 0x100, nc
=1)
251 addr
= yield dut
.d_in
.addr
252 assert data
== 0x0000004100000040, \
253 f
"data @%x=%x expected 0000004100000040" % (addr
, data
)
255 # Store at address 530
256 yield from dcache_store(dut
, 0x530, 0x121)
258 # Store at address 30
259 yield from dcache_store(dut
, 0x530, 0x12345678)
261 # 3nd Cacheable read of address 530
262 data
= yield from dcache_load(dut
, 0x530)
263 addr
= yield dut
.d_in
.addr
264 assert data
== 0x12345678, \
265 f
"data @%x=%x expected 0x12345678" % (addr
, data
)
267 # 4th Cacheable read of address 20
268 data
= yield from dcache_load(dut
, 0x20)
269 addr
= yield dut
.d_in
.addr
270 assert data
== 0x0000000900000008, \
271 f
"data @%x=%x expected 0x0000000900000008" % (addr
, data
)
279 def test_dcache(mem
, test_fn
, test_name
):
282 memory
= Memory(width
=64, depth
=len(mem
), init
=mem
, simulate
=True)
283 sram
= SRAM(memory
=memory
, granularity
=8)
286 m
.submodules
.dcache
= dut
287 m
.submodules
.sram
= sram
289 m
.d
.comb
+= sram
.bus
.cyc
.eq(dut
.wb_out
.cyc
)
290 m
.d
.comb
+= sram
.bus
.stb
.eq(dut
.wb_out
.stb
)
291 m
.d
.comb
+= sram
.bus
.we
.eq(dut
.wb_out
.we
)
292 m
.d
.comb
+= sram
.bus
.sel
.eq(dut
.wb_out
.sel
)
293 m
.d
.comb
+= sram
.bus
.adr
.eq(dut
.wb_out
.adr
)
294 m
.d
.comb
+= sram
.bus
.dat_w
.eq(dut
.wb_out
.dat
)
296 m
.d
.comb
+= dut
.wb_in
.ack
.eq(sram
.bus
.ack
)
297 m
.d
.comb
+= dut
.wb_in
.dat
.eq(sram
.bus
.dat_r
)
299 dcache_write_gtkw(test_name
)
305 sim
.add_sync_process(wrap(test_fn(dut
, mem
)))
306 with sim
.write_vcd('test_dcache_m%s.vcd' % test_name
):
310 def dcache_write_gtkw(test_name
):
314 'm_in_doall', 'm_in_addr[63:0]', 'm_in_pte[63:0]',
315 'm_in_tlbie', 'm_in_tlbid', 'm_in_valid'
318 'm_out_done', 'm_out_data[63:0]', 'm_out_err', 'm_out_stall'
321 'd_in_load', 'd_in_nc', 'd_in_addr[63:0]', 'd_in_data[63:0]',
322 'd_in_byte_sel[7:0]', 'd_in_valid'
325 'd_out_valid', 'd_out_data[63:0]'
328 'wb_out_cyc', 'wb_out_stb', 'wb_out_we',
329 'wb_out_adr[31:0]', 'wb_out_sel[7:0]', 'wb_out_dat[63:0]'
332 'wb_in_stall', 'wb_in_ack', 'wb_in_dat[63:0]'
335 write_gtkw('test_dcache_m%s.gtkw' % test_name
,
336 'test_dcache_m%s.vcd' % test_name
,
337 traces
, module
='top.dcache')
340 if __name__
== '__main__':
343 vl
= rtlil
.convert(dut
, ports
=[])
344 with
open("test_dcache.il", "w") as f
:
350 for i
in range(memsize
):
353 test_dcache(mem
, dcache_regression_sim
, "simpleregression")
357 for i
in range(memsize
):
360 test_dcache(mem
, dcache_random_sim
, "random")
363 for i
in range(1024):
364 mem
.append((i
*2)|
((i
*2+1)<<32))
366 test_dcache(mem
, dcache_sim
, "")