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