whitespace
[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
93
94 def icache_sim(dut, mem):
95 i_out = dut.i_in
96 i_in = dut.i_out
97 m_out = dut.m_in
98
99 for k,v in mem.items():
100 yield i_in.valid.eq(0)
101 yield i_out.priv_mode.eq(1)
102 yield i_out.req.eq(0)
103 yield i_out.nia.eq(0)
104 yield i_out.stop_mark.eq(0)
105 yield m_out.tlbld.eq(0)
106 yield m_out.tlbie.eq(0)
107 yield m_out.addr.eq(0)
108 yield m_out.pte.eq(0)
109 yield
110 yield
111 yield
112 yield
113 yield i_out.req.eq(1)
114 yield i_out.nia.eq(C(k, 64))
115 while True:
116 yield
117 valid = yield i_in.valid
118 if valid:
119 break
120 nia = yield i_out.nia
121 insn = yield i_in.insn
122 yield
123 assert insn == v, \
124 "insn @%x=%x expected %x" % (nia, insn, v)
125 yield i_out.req.eq(0)
126 yield
127
128
129 def test_icache_il():
130 dut = ICache()
131 vl = rtlil.convert(dut, ports=[])
132 with open("test_icache.il", "w") as f:
133 f.write(vl)
134
135
136 def test_icache():
137 # create a random set of addresses and "instructions" at those addresses
138 mem = {}
139 # fail 'AssertionError: insn @1d8=0 expected 61928a6100000000'
140 #random.seed(41)
141 # fail infinite loop 'cache read adr: 24 data: 0'
142 random.seed(43)
143 for i in range(3):
144 mem[random.randint(0, 1<<10)] = b(random.randint(0,1<<32))
145
146 # set up module for simulation
147 m = Module()
148 icache = ICache()
149 m.submodules.icache = icache
150
151 # nmigen Simulation
152 sim = Simulator(m)
153 sim.add_clock(1e-6)
154
155 # read from "memory" process and corresponding wishbone "read" process
156 sim.add_sync_process(wrap(icache_sim(icache, mem)))
157 sim.add_sync_process(wrap(wb_get(icache, mem, "ICACHE")))
158 with sim.write_vcd('test_icache.vcd'):
159 sim.run()
160
161
162 def mmu_lookup(mmu, addr):
163 global stop
164
165 yield mmu.l_in.load.eq(1)
166 yield mmu.l_in.priv.eq(1)
167 yield mmu.l_in.addr.eq(addr)
168 yield mmu.l_in.valid.eq(1)
169 while not stop: # wait for dc_valid / err
170 l_done = yield (mmu.l_out.done)
171 l_err = yield (mmu.l_out.err)
172 l_badtree = yield (mmu.l_out.badtree)
173 l_permerr = yield (mmu.l_out.perm_error)
174 l_rc_err = yield (mmu.l_out.rc_error)
175 l_segerr = yield (mmu.l_out.segerr)
176 l_invalid = yield (mmu.l_out.invalid)
177 if (l_done or l_err or l_badtree or
178 l_permerr or l_rc_err or l_segerr or l_invalid):
179 break
180 yield
181 phys_addr = yield mmu.d_out.addr
182 pte = yield mmu.d_out.pte
183 print ("translated done %d err %d badtree %d addr %x pte %x" % \
184 (l_done, l_err, l_badtree, phys_addr, pte))
185 yield
186 yield mmu.l_in.valid.eq(0)
187
188 return phys_addr
189
190
191 def mmu_sim(mmu):
192 global stop
193 yield mmu.rin.prtbl.eq(0x1000000) # set process table
194 yield
195
196 phys_addr = yield from mmu_lookup(mmu, 0x10000)
197 assert phys_addr == 0x40000
198
199 phys_addr = yield from mmu_lookup(mmu, 0x10000)
200 assert phys_addr == 0x40000
201
202 stop = True
203
204
205 def test_mmu():
206 mmu = MMU()
207 dcache = DCache()
208 m = Module()
209 m.submodules.mmu = mmu
210 m.submodules.dcache = dcache
211
212 # link mmu and dcache together
213 m.d.comb += dcache.m_in.eq(mmu.d_out)
214 m.d.comb += mmu.d_in.eq(dcache.m_out)
215
216 # nmigen Simulation
217 sim = Simulator(m)
218 sim.add_clock(1e-6)
219
220 sim.add_sync_process(wrap(mmu_sim(mmu)))
221 sim.add_sync_process(wrap(wb_get(dcache, default_mem, "DCACHE")))
222 with sim.write_vcd('test_mmu.vcd'):
223 sim.run()
224
225
226 if __name__ == '__main__':
227 test_mmu()
228 #test_icache_il()
229 #test_icache()