fix wb_get error where data was being corrupted
[soc.git] / src / soc / experiment / test / test_mmu_dcache.py
1 from nmigen import (C, Module, Signal, Elaboratable, Mux, Cat, Repl, Signal)
2 from nmigen.cli import main
3 from nmigen.cli import rtlil
4 from nmutil.iocontrol import RecordObject
5 from nmutil.byterev import byte_reverse
6 from nmutil.mask import Mask, masked
7 from nmutil.util import Display
8
9 if True:
10 from nmigen.back.pysim import Simulator, Delay, Settle
11 else:
12 from nmigen.sim.cxxsim import Simulator, Delay, Settle
13 from nmutil.util import wrap
14
15 from soc.experiment.mem_types import (LoadStore1ToMMUType,
16 MMUToLoadStore1Type,
17 MMUToDCacheType,
18 DCacheToMMUType,
19 MMUToICacheType)
20
21 from soc.experiment.mmu import MMU
22 from soc.experiment.dcache import DCache
23 from soc.experiment.icache import ICache
24
25 import random
26
27 stop = False
28
29 def set_stop(newval):
30 global stop
31 stop = newval
32
33
34 def b(x):
35 return int.from_bytes(x.to_bytes(8, byteorder='little'),
36 byteorder='big', signed=False)
37
38
39 default_mem = { 0x10000: # PARTITION_TABLE_2
40 # PATB_GR=1 PRTB=0x1000 PRTS=0xb
41 b(0x800000000100000b),
42
43 0x30000: # RADIX_ROOT_PTE
44 # V = 1 L = 0 NLB = 0x400 NLS = 9
45 b(0x8000000000040009),
46
47 0x40000: # RADIX_SECOND_LEVEL
48 # V = 1 L = 1 SW = 0 RPN = 0
49 # R = 1 C = 1 ATT = 0 EAA 0x7
50 b(0xc000000000000187),
51
52 0x1000000: # PROCESS_TABLE_3
53 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13
54 b(0x40000000000300ad),
55 }
56
57
58 def wb_get(c, mem, name):
59 """simulator process for getting memory load requests
60 """
61
62 logfile = open("/tmp/wb_get.log","w")
63
64 def log(msg):
65 logfile.write(msg+"\n")
66 print(msg)
67
68 global stop
69 while not stop:
70 while True: # wait for dc_valid
71 if stop:
72 log("stop")
73 return
74 cyc = yield (c.wb_out.cyc)
75 stb = yield (c.wb_out.stb)
76 if cyc and stb:
77 break
78 yield
79 addr = (yield c.wb_out.adr) << 3
80 if addr not in mem:
81 log("%s LOOKUP FAIL %x" % (name, addr))
82 stop = True
83 return
84
85 yield
86 data = mem[addr]
87 yield c.wb_in.dat.eq(data)
88 log("%s get %x data %x" % (name, addr, data))
89 yield c.wb_in.ack.eq(1)
90 yield
91 yield c.wb_in.ack.eq(0)
92 yield
93
94
95 def icache_sim(dut, mem):
96 i_out = dut.i_in
97 i_in = dut.i_out
98 m_out = dut.m_in
99
100 for k,v in mem.items():
101 yield i_in.valid.eq(0)
102 yield i_out.priv_mode.eq(1)
103 yield i_out.req.eq(0)
104 yield i_out.nia.eq(0)
105 yield i_out.stop_mark.eq(0)
106 yield m_out.tlbld.eq(0)
107 yield m_out.tlbie.eq(0)
108 yield m_out.addr.eq(0)
109 yield m_out.pte.eq(0)
110 yield
111 yield
112 yield
113 yield
114 yield i_out.req.eq(1)
115 yield i_out.nia.eq(C(k, 64))
116 while True:
117 yield
118 valid = yield i_in.valid
119 if valid:
120 break
121 nia = yield i_out.nia
122 insn = yield i_in.insn
123 yield
124 assert insn == v, \
125 "insn @%x=%x expected %x" % (nia, insn, v)
126 yield i_out.req.eq(0)
127 yield
128
129
130 def test_icache_il():
131 dut = ICache()
132 vl = rtlil.convert(dut, ports=[])
133 with open("test_icache.il", "w") as f:
134 f.write(vl)
135
136
137 def test_icache():
138 # create a random set of addresses and "instructions" at those addresses
139 mem = {}
140 # fail 'AssertionError: insn @1d8=0 expected 61928a6100000000'
141 #random.seed(41)
142 # fail infinite loop 'cache read adr: 24 data: 0'
143 random.seed(43)
144 for i in range(3):
145 mem[random.randint(0, 1<<10)] = b(random.randint(0,1<<32))
146
147 # set up module for simulation
148 m = Module()
149 icache = ICache()
150 m.submodules.icache = icache
151
152 # nmigen Simulation
153 sim = Simulator(m)
154 sim.add_clock(1e-6)
155
156 # read from "memory" process and corresponding wishbone "read" process
157 sim.add_sync_process(wrap(icache_sim(icache, mem)))
158 sim.add_sync_process(wrap(wb_get(icache, mem, "ICACHE")))
159 with sim.write_vcd('test_icache.vcd'):
160 sim.run()
161
162
163 def mmu_lookup(mmu, addr):
164 global stop
165
166 yield mmu.l_in.load.eq(1)
167 yield mmu.l_in.priv.eq(1)
168 yield mmu.l_in.addr.eq(addr)
169 yield mmu.l_in.valid.eq(1)
170 while not stop: # wait for dc_valid / err
171 l_done = yield (mmu.l_out.done)
172 l_err = yield (mmu.l_out.err)
173 l_badtree = yield (mmu.l_out.badtree)
174 l_permerr = yield (mmu.l_out.perm_error)
175 l_rc_err = yield (mmu.l_out.rc_error)
176 l_segerr = yield (mmu.l_out.segerr)
177 l_invalid = yield (mmu.l_out.invalid)
178 if (l_done or l_err or l_badtree or
179 l_permerr or l_rc_err or l_segerr or l_invalid):
180 break
181 yield
182 phys_addr = yield mmu.d_out.addr
183 pte = yield mmu.d_out.pte
184 print ("translated done %d err %d badtree %d addr %x pte %x" % \
185 (l_done, l_err, l_badtree, phys_addr, pte))
186 yield
187 yield mmu.l_in.valid.eq(0)
188
189 return phys_addr
190
191
192 def mmu_sim(mmu):
193 global stop
194 yield mmu.rin.prtbl.eq(0x1000000) # set process table
195 yield
196
197 phys_addr = yield from mmu_lookup(mmu, 0x10000)
198 assert phys_addr == 0x40000
199
200 phys_addr = yield from mmu_lookup(mmu, 0x10000)
201 assert phys_addr == 0x40000
202
203 stop = True
204
205
206 def test_mmu():
207 mmu = MMU()
208 dcache = DCache()
209 m = Module()
210 m.submodules.mmu = mmu
211 m.submodules.dcache = dcache
212
213 # link mmu and dcache together
214 m.d.comb += dcache.m_in.eq(mmu.d_out)
215 m.d.comb += mmu.d_in.eq(dcache.m_out)
216
217 # nmigen Simulation
218 sim = Simulator(m)
219 sim.add_clock(1e-6)
220
221 sim.add_sync_process(wrap(mmu_sim(mmu)))
222 sim.add_sync_process(wrap(wb_get(dcache, default_mem, "DCACHE")))
223 with sim.write_vcd('test_mmu.vcd'):
224 sim.run()
225
226
227 if __name__ == '__main__':
228 test_mmu()
229 #test_icache_il()
230 #test_icache()