1fd58c073c35831563a5efe97655d83fa52c21f3
[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 from random import randint
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 for i in range(30):
106 yield
107 yield
108 valid = yield i_in.valid
109 nia = yield i_out.nia
110 insn = yield i_in.insn
111 print(f"valid? {valid}")
112 assert valid
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():
120 dut = ICache()
121 vl = rtlil.convert(dut, ports=[])
122 with open("test_icache.il", "w") as f:
123 f.write(vl)
124
125 icache = ICache()
126
127 mem = {}
128
129 for i in range(100):
130 mem[randint(0,1<<64)] = b(randint(0,1<<64))
131
132 m = Module()
133
134 m.submodules.icache = icache
135
136
137 # nmigen Simulation
138 sim = Simulator(m)
139 sim.add_clock(1e-6)
140
141 sim.add_sync_process(wrap(icache_sim(icache, mem)))
142 sim.add_sync_process(wrap(wb_get(icache, mem, "ICACHE")))
143 with sim.write_vcd('test_icache.vcd'):
144 sim.run()
145
146 def mmu_lookup(mmu, addr):
147 global stop
148
149 yield mmu.l_in.load.eq(1)
150 yield mmu.l_in.priv.eq(1)
151 yield mmu.l_in.addr.eq(addr)
152 yield mmu.l_in.valid.eq(1)
153 while not stop: # wait for dc_valid / err
154 l_done = yield (mmu.l_out.done)
155 l_err = yield (mmu.l_out.err)
156 l_badtree = yield (mmu.l_out.badtree)
157 l_permerr = yield (mmu.l_out.perm_error)
158 l_rc_err = yield (mmu.l_out.rc_error)
159 l_segerr = yield (mmu.l_out.segerr)
160 l_invalid = yield (mmu.l_out.invalid)
161 if (l_done or l_err or l_badtree or
162 l_permerr or l_rc_err or l_segerr or l_invalid):
163 break
164 yield
165 phys_addr = yield mmu.d_out.addr
166 pte = yield mmu.d_out.pte
167 print ("translated done %d err %d badtree %d addr %x pte %x" % \
168 (l_done, l_err, l_badtree, phys_addr, pte))
169 yield
170 yield mmu.l_in.valid.eq(0)
171
172 return phys_addr
173
174 def mmu_sim(mmu):
175 global stop
176 yield mmu.rin.prtbl.eq(0x1000000) # set process table
177 yield
178
179 phys_addr = yield from mmu_lookup(mmu, 0x10000)
180 assert phys_addr == 0x40000
181
182 phys_addr = yield from mmu_lookup(mmu, 0x10000)
183 assert phys_addr == 0x40000
184
185 stop = True
186
187 def test_mmu():
188 mmu = MMU()
189 dcache = DCache()
190 m = Module()
191 m.submodules.mmu = mmu
192 m.submodules.dcache = dcache
193
194 # link mmu and dcache together
195 m.d.comb += dcache.m_in.eq(mmu.d_out)
196 m.d.comb += mmu.d_in.eq(dcache.m_out)
197
198 # nmigen Simulation
199 sim = Simulator(m)
200 sim.add_clock(1e-6)
201
202 sim.add_sync_process(wrap(mmu_sim(mmu)))
203 sim.add_sync_process(wrap(wb_get(dcache, default_mem, "DCACHE")))
204 with sim.write_vcd('test_mmu.vcd'):
205 sim.run()
206
207 if __name__ == '__main__':
208 test_mmu()
209 # test_icache()