add some data for MMU to actually look up
[soc.git] / src / soc / experiment / test / test_dcache_tlb.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_m(dut, addr, nc=0):
49 REF = 1<<8
50 CHG = 1<<7
51 NC = 1<<5
52 PRIV = 1<<3
53 RD = 1<<2
54 WR = 1<<1
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)
59 yield
60 yield dut.m_in.valid.eq(0)
61 while not (yield dut.m_out.done):
62 yield
63 # yield # data is valid one cycle AFTER valid goes hi? (no it isn't)
64 data = yield dut.m_out.data
65 return data
66
67
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)
74 yield
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):
78 yield
79 # yield # data is valid one cycle AFTER valid goes hi? (no it isn't)
80 data = yield dut.d_out.data
81 return data
82
83
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)
90 yield
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):
95 yield
96
97
98 def dcache_random_sim(dut, mem, nc=0):
99
100 # start copy of mem
101 sim_mem = deepcopy(mem)
102 memsize = len(sim_mem)
103 print ("mem len", memsize)
104
105 # clear stuff
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
116 yield
117 yield
118 yield
119 yield
120
121 print ()
122
123 #for i in range(1024):
124 # sim_mem[i] = i
125
126 for i in range(1024):
127 addr = randint(0, memsize-1)
128 data = randint(0, (1<<64)-1)
129 sim_mem[addr] = data
130 row = addr
131 addr *= 8
132
133 print ("random testing %d 0x%x row %d data 0x%x" % (i, addr, row, data))
134
135 yield from dcache_load(dut, addr, nc)
136 yield from dcache_store(dut, addr, data, nc)
137
138 addr = randint(0, memsize-1)
139 sim_data = sim_mem[addr]
140 row = addr
141 addr *= 8
142
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)
147
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])
152
153
154 def dcache_regression_sim(dut, mem, nc=0):
155
156 # start copy of mem
157 sim_mem = deepcopy(mem)
158 memsize = len(sim_mem)
159 print ("mem len", memsize)
160
161 # clear stuff
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
172 yield
173 yield
174 yield
175 yield
176
177 addr = 0
178 row = addr
179 addr *= 8
180
181 print ("random testing %d 0x%x row %d" % (i, addr, row))
182
183 yield from dcache_load(dut, addr, nc)
184
185 addr = 2
186 sim_data = sim_mem[addr]
187 row = addr
188 addr *= 8
189
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)
194
195
196
197 def dcache_sim(dut, mem):
198 # clear stuff
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
209 yield
210 yield
211 yield
212 yield
213
214 # Cacheable read of address 4
215 data = yield from dcache_load_m(dut, 0x58)
216 print ("dcache m_load 0x58", hex(data))
217 yield
218 yield
219
220 # Cacheable read of address 4
221 data = yield from dcache_load_m(dut, 0x58)
222 print ("dcache m_load 0x58", hex(data))
223 yield
224 yield
225
226 return
227
228 assert data == 0x0000001700000016, \
229 f"data @%x=%x expected 0x0000001700000016" % (addr, data)
230
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)
236
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)
242
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)
248
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)
254
255 # Store at address 530
256 yield from dcache_store(dut, 0x530, 0x121)
257
258 # Store at address 30
259 yield from dcache_store(dut, 0x530, 0x12345678)
260
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)
266
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)
272
273 yield
274 yield
275 yield
276 yield
277
278
279 def test_dcache(mem, test_fn, test_name):
280 dut = DCache()
281
282 memory = Memory(width=64, depth=len(mem), init=mem, simulate=True)
283 sram = SRAM(memory=memory, granularity=8)
284
285 m = Module()
286 m.submodules.dcache = dut
287 m.submodules.sram = sram
288
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)
295
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)
298
299 dcache_write_gtkw(test_name)
300
301 # nmigen Simulation
302 sim = Simulator(m)
303 sim.add_clock(1e-6)
304
305 sim.add_sync_process(wrap(test_fn(dut, mem)))
306 with sim.write_vcd('test_dcache_m%s.vcd' % test_name):
307 sim.run()
308
309
310 def dcache_write_gtkw(test_name):
311 traces = [
312 'clk',
313 ('m_in', [
314 'm_in_doall', 'm_in_addr[63:0]', 'm_in_pte[63:0]',
315 'm_in_tlbie', 'm_in_tlbid', 'm_in_valid'
316 ]),
317 ('m_out', [
318 'm_out_done', 'm_out_data[63:0]', 'm_out_err', 'm_out_stall'
319 ]),
320 ('d_in', [
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'
323 ]),
324 ('d_out', [
325 'd_out_valid', 'd_out_data[63:0]'
326 ]),
327 ('wb_out', [
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]'
330 ]),
331 ('wb_in', [
332 'wb_in_stall', 'wb_in_ack', 'wb_in_dat[63:0]'
333 ])
334 ]
335 write_gtkw('test_dcache_m%s.gtkw' % test_name,
336 'test_dcache_m%s.vcd' % test_name,
337 traces, module='top.dcache')
338
339
340 if __name__ == '__main__':
341 seed(0)
342 dut = DCache()
343 vl = rtlil.convert(dut, ports=[])
344 with open("test_dcache.il", "w") as f:
345 f.write(vl)
346
347 if False:
348 mem = []
349 memsize = 16
350 for i in range(memsize):
351 mem.append(i)
352
353 test_dcache(mem, dcache_regression_sim, "simpleregression")
354
355 mem = []
356 memsize = 256
357 for i in range(memsize):
358 mem.append(i)
359
360 test_dcache(mem, dcache_random_sim, "random")
361
362 mem = []
363 for i in range(1024):
364 mem.append((i*2)| ((i*2+1)<<32))
365
366 test_dcache(mem, dcache_sim, "")
367