move dcache unit test to separate test_dcache.py
[soc.git] / src / soc / experiment / test / test_dcache.py
1 """DCache
2
3 based on Anton Blanchard microwatt dcache.vhdl
4
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
8
9 IMPORTANT: for store, the data is sampled the cycle AFTER the "valid"
10 is raised. sigh
11
12 Links:
13
14 * https://libre-soc.org/3d_gpu/architecture/set_associative_cache.jpg
15 * https://bugs.libre-soc.org/show_bug.cgi?id=469
16
17 """
18
19 import sys
20
21 from nmutil.gtkw import write_gtkw
22
23 sys.setrecursionlimit(1000000)
24
25 from enum import Enum, unique
26
27 from nmigen import Module, Signal, Elaboratable, Cat, Repl, Array, Const
28
29 from copy import deepcopy
30 from random import randint, seed
31
32 from soc.experiment.cache_ram import CacheRam
33
34 # for test
35 from soc.bus.sram import SRAM
36 from nmigen import Memory
37 from nmigen.cli import rtlil
38
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
42
43 from nmutil.util import wrap
44
45 from soc.experiment.dcache import DCache
46
47
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)
54 yield
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):
58 yield
59 # yield # data is valid one cycle AFTER valid goes hi? (no it isn't)
60 data = yield dut.d_out.data
61 return data
62
63
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)
70 yield
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):
75 yield
76
77
78 def dcache_random_sim(dut, mem, nc=0):
79
80 # start copy of mem
81 sim_mem = deepcopy(mem)
82 memsize = len(sim_mem)
83 print ("mem len", memsize)
84
85 # clear stuff
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)
95 # wait 4 * clk_period
96 yield
97 yield
98 yield
99 yield
100
101 print ()
102
103 #for i in range(1024):
104 # sim_mem[i] = i
105
106 for i in range(1024):
107 addr = randint(0, memsize-1)
108 data = randint(0, (1<<64)-1)
109 sim_mem[addr] = data
110 row = addr
111 addr *= 8
112
113 print ("random testing %d 0x%x row %d data 0x%x" % (i, addr, row, data))
114
115 yield from dcache_load(dut, addr, nc)
116 yield from dcache_store(dut, addr, data, nc)
117
118 addr = randint(0, memsize-1)
119 sim_data = sim_mem[addr]
120 row = addr
121 addr *= 8
122
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)
127
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])
132
133
134 def dcache_regression_sim(dut, mem, nc=0):
135
136 # start copy of mem
137 sim_mem = deepcopy(mem)
138 memsize = len(sim_mem)
139 print ("mem len", memsize)
140
141 # clear stuff
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
152 yield
153 yield
154 yield
155 yield
156
157 addr = 0
158 row = addr
159 addr *= 8
160
161 print ("random testing %d 0x%x row %d" % (i, addr, row))
162
163 yield from dcache_load(dut, addr, nc)
164
165 addr = 2
166 sim_data = sim_mem[addr]
167 row = addr
168 addr *= 8
169
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)
174
175
176
177 def dcache_sim(dut, mem):
178 # clear stuff
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
189 yield
190 yield
191 yield
192 yield
193
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)
199
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)
205
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)
211
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)
217
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)
223
224 # Store at address 530
225 yield from dcache_store(dut, 0x530, 0x121)
226
227 # Store at address 30
228 yield from dcache_store(dut, 0x530, 0x12345678)
229
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)
235
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)
241
242 yield
243 yield
244 yield
245 yield
246
247
248 def test_dcache(mem, test_fn, test_name):
249 dut = DCache()
250
251 memory = Memory(width=64, depth=len(mem), init=mem, simulate=True)
252 sram = SRAM(memory=memory, granularity=8)
253
254 m = Module()
255 m.submodules.dcache = dut
256 m.submodules.sram = sram
257
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)
264
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)
267
268 dcache_write_gtkw(test_name)
269
270 # nmigen Simulation
271 sim = Simulator(m)
272 sim.add_clock(1e-6)
273
274 sim.add_sync_process(wrap(test_fn(dut, mem)))
275 with sim.write_vcd('test_dcache%s.vcd' % test_name):
276 sim.run()
277
278
279 def dcache_write_gtkw(test_name):
280 traces = [
281 'clk',
282 ('d_in', [
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'
285 ]),
286 ('d_out', [
287 'd_out_valid', 'd_out_data[63:0]'
288 ]),
289 ('wb_out', [
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]'
292 ]),
293 ('wb_in', [
294 'wb_in_stall', 'wb_in_ack', 'wb_in_dat[63:0]'
295 ])
296 ]
297 write_gtkw('test_dcache%s.gtkw' % test_name,
298 'test_dcache%s.vcd' % test_name,
299 traces, module='top.dcache')
300
301
302 if __name__ == '__main__':
303 seed(0)
304 dut = DCache()
305 vl = rtlil.convert(dut, ports=[])
306 with open("test_dcache.il", "w") as f:
307 f.write(vl)
308
309 mem = []
310 memsize = 16
311 for i in range(memsize):
312 mem.append(i)
313
314 test_dcache(mem, dcache_regression_sim, "simpleregression")
315
316 mem = []
317 memsize = 256
318 for i in range(memsize):
319 mem.append(i)
320
321 test_dcache(mem, dcache_random_sim, "random")
322
323 mem = []
324 for i in range(1024):
325 mem.append((i*2)| ((i*2+1)<<32))
326
327 test_dcache(mem, dcache_sim, "")
328