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