radix: reading first page table entry
[soc.git] / src / soc / decoder / test / test_decoder_gas.py
1 from nmigen import Module, Signal
2
3 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
4 # Also, check out the cxxsim nmigen branch, and latest yosys from git
5 from nmutil.sim_tmp_alternative import Simulator, Delay
6
7 from nmutil.formaltest import FHDLTestCase
8 import unittest
9 from soc.decoder.power_decoder import (create_pdecode)
10 from soc.decoder.power_enums import (Function, MicrOp,
11 In1Sel, In2Sel, In3Sel,
12 OutSel, RC, LdstLen, CryIn,
13 single_bit_flags, Form, SPR,
14 get_signal_name, get_csv)
15 from soc.decoder.power_decoder2 import (PowerDecode2)
16 from soc.simulator.gas import get_assembled_instruction
17 import random
18
19
20 class Register:
21 def __init__(self, num):
22 self.num = num
23
24
25 class Checker:
26 def __init__(self):
27 self.imm = 0
28
29 def get_imm(self, in2_sel):
30 if in2_sel == In2Sel.CONST_UI.value:
31 return self.imm & 0xffff
32 if in2_sel == In2Sel.CONST_UI_HI.value:
33 return (self.imm & 0xffff) << 16
34 if in2_sel == In2Sel.CONST_SI.value:
35 sign_bit = 1 << 15
36 return (self.imm & (sign_bit-1)) - (self.imm & sign_bit)
37 if in2_sel == In2Sel.CONST_SI_HI.value:
38 imm = self.imm << 16
39 sign_bit = 1 << 31
40 return (imm & (sign_bit-1)) - (imm & sign_bit)
41
42
43 class RegRegOp:
44 def __init__(self):
45 self.ops = {
46 "add": MicrOp.OP_ADD,
47 "and": MicrOp.OP_AND,
48 "or": MicrOp.OP_OR,
49 "add.": MicrOp.OP_ADD,
50 "lwzx": MicrOp.OP_LOAD,
51 "stwx": MicrOp.OP_STORE,
52 }
53 self.opcodestr = random.choice(list(self.ops.keys()))
54 self.opcode = self.ops[self.opcodestr]
55 self.r1 = Register(random.randrange(32))
56 self.r2 = Register(random.randrange(32))
57 self.r3 = Register(random.randrange(32))
58
59 def generate_instruction(self):
60 string = "{} {}, {}, {}\n".format(self.opcodestr,
61 self.r1.num,
62 self.r2.num,
63 self.r3.num)
64 return string
65
66 def check_results(self, pdecode2):
67 if self.opcode == MicrOp.OP_STORE:
68 r1sel = yield pdecode2.e.read_reg3.data
69 else:
70 r1sel = yield pdecode2.e.write_reg.data
71
72 r3sel = yield pdecode2.e.read_reg2.data
73
74 # For some reason r2 gets decoded either in read_reg1
75 # or read_reg3
76 out_sel = yield pdecode2.dec.op.out_sel
77 if out_sel == OutSel.RA.value:
78 r2sel = yield pdecode2.e.read_reg3.data
79 else:
80 r2sel = yield pdecode2.e.read_reg1.data
81 assert(r1sel == self.r1.num)
82 assert(r3sel == self.r3.num)
83 assert(r2sel == self.r2.num)
84
85 opc_out = yield pdecode2.dec.op.internal_op
86 assert(opc_out == self.opcode.value)
87 # check RC value (the dot in the instruction)
88 rc = yield pdecode2.e.rc.data
89 if '.' in self.opcodestr:
90 assert(rc == 1)
91 else:
92 assert(rc == 0)
93
94
95 class RegImmOp(Checker):
96 def __init__(self):
97 super().__init__()
98 self.ops = {
99 "addi": MicrOp.OP_ADD,
100 "addis": MicrOp.OP_ADD,
101 "andi.": MicrOp.OP_AND,
102 "ori": MicrOp.OP_OR,
103 }
104 self.opcodestr = random.choice(list(self.ops.keys()))
105 self.opcode = self.ops[self.opcodestr]
106 self.r1 = Register(random.randrange(32))
107 self.r2 = Register(random.randrange(32))
108 self.imm = random.randrange(32767)
109
110 def generate_instruction(self):
111 string = "{} {}, {}, {}\n".format(self.opcodestr,
112 self.r1.num,
113 self.r2.num,
114 self.imm)
115 return string
116
117 def check_results(self, pdecode2):
118 print("Check")
119 r1sel = yield pdecode2.e.write_reg.data
120 # For some reason r2 gets decoded either in read_reg1
121 # or read_reg3
122 out_sel = yield pdecode2.dec.op.out_sel
123 if out_sel == OutSel.RA.value:
124 r2sel = yield pdecode2.e.read_reg3.data
125 else:
126 r2sel = yield pdecode2.e.read_reg1.data
127 assert(r1sel == self.r1.num)
128 assert(r2sel == self.r2.num)
129
130 imm = yield pdecode2.e.imm_data.data
131 in2_sel = yield pdecode2.dec.op.in2_sel
132 imm_expected = self.get_imm(in2_sel)
133 msg = "imm: got {:x}, expected {:x}".format(imm, imm_expected)
134 assert imm == imm_expected, msg
135
136 rc = yield pdecode2.e.rc.data
137 if '.' in self.opcodestr:
138 assert(rc == 1)
139 else:
140 assert(rc == 0)
141
142
143 class LdStOp(Checker):
144 def __init__(self):
145 super().__init__()
146 self.ops = {
147 "lwz": MicrOp.OP_LOAD,
148 "stw": MicrOp.OP_STORE,
149 "lwzu": MicrOp.OP_LOAD,
150 "stwu": MicrOp.OP_STORE,
151 "lbz": MicrOp.OP_LOAD,
152 "lhz": MicrOp.OP_LOAD,
153 "stb": MicrOp.OP_STORE,
154 "sth": MicrOp.OP_STORE,
155 }
156 self.opcodestr = random.choice(list(self.ops.keys()))
157 self.opcode = self.ops[self.opcodestr]
158 self.r1 = Register(random.randrange(32))
159 self.r2 = Register(random.randrange(1, 32))
160 while self.r2.num == self.r1.num:
161 self.r2 = Register(random.randrange(1, 32))
162 self.imm = random.randrange(32767)
163
164 def generate_instruction(self):
165 string = "{} {}, {}({})\n".format(self.opcodestr,
166 self.r1.num,
167 self.imm,
168 self.r2.num)
169 return string
170
171 def check_results(self, pdecode2):
172 print("Check")
173 r2sel = yield pdecode2.e.read_reg1.data
174 if self.opcode == MicrOp.OP_STORE:
175 r1sel = yield pdecode2.e.read_reg3.data
176 else:
177 r1sel = yield pdecode2.e.write_reg.data
178 assert(r1sel == self.r1.num)
179 assert(r2sel == self.r2.num)
180
181 imm = yield pdecode2.e.imm_data.data
182 in2_sel = yield pdecode2.dec.op.in2_sel
183 assert(imm == self.get_imm(in2_sel))
184
185 update = yield pdecode2.e.update
186 if "u" in self.opcodestr:
187 assert(update == 1)
188 else:
189 assert(update == 0)
190
191 size = yield pdecode2.e.data_len
192 if "w" in self.opcodestr:
193 assert(size == 4)
194 elif "h" in self.opcodestr:
195 assert(size == 2)
196 elif "b" in self.opcodestr:
197 assert(size == 1)
198 else:
199 assert(False)
200
201
202 class CmpRegOp:
203 def __init__(self):
204 self.ops = {
205 "cmp": MicrOp.OP_CMP,
206 }
207 self.opcodestr = random.choice(list(self.ops.keys()))
208 self.opcode = self.ops[self.opcodestr]
209 self.r1 = Register(random.randrange(32))
210 self.r2 = Register(random.randrange(32))
211 self.cr = Register(random.randrange(8))
212
213 def generate_instruction(self):
214 string = "{} {}, 0, {}, {}\n".format(self.opcodestr,
215 self.cr.num,
216 self.r1.num,
217 self.r2.num)
218 return string
219
220 def check_results(self, pdecode2):
221 r1sel = yield pdecode2.e.read_reg1.data
222 r2sel = yield pdecode2.e.read_reg2.data
223 crsel = yield pdecode2.dec.BF
224
225 assert(r1sel == self.r1.num)
226 assert(r2sel == self.r2.num)
227 assert(crsel == self.cr.num)
228
229
230 class RotateOp:
231 def __init__(self):
232 self.ops = {
233 "rlwinm": MicrOp.OP_CMP,
234 "rlwnm": MicrOp.OP_CMP,
235 "rlwimi": MicrOp.OP_CMP,
236 "rlwinm.": MicrOp.OP_CMP,
237 "rlwnm.": MicrOp.OP_CMP,
238 "rlwimi.": MicrOp.OP_CMP,
239 }
240 self.opcodestr = random.choice(list(self.ops.keys()))
241 self.opcode = self.ops[self.opcodestr]
242 self.r1 = Register(random.randrange(32))
243 self.r2 = Register(random.randrange(32))
244 self.shift = random.randrange(32)
245 self.mb = random.randrange(32)
246 self.me = random.randrange(32)
247
248 def generate_instruction(self):
249 string = "{} {},{},{},{},{}\n".format(self.opcodestr,
250 self.r1.num,
251 self.r2.num,
252 self.shift,
253 self.mb,
254 self.me)
255 return string
256
257 def check_results(self, pdecode2):
258 r1sel = yield pdecode2.e.write_reg.data
259 r2sel = yield pdecode2.e.read_reg3.data
260 dec = pdecode2.dec
261
262 if "i" in self.opcodestr:
263 shift = yield dec.SH
264 else:
265 shift = yield pdecode2.e.read_reg2.data
266 mb = yield dec.MB
267 me = yield dec.ME
268
269 assert(r1sel == self.r1.num)
270 assert(r2sel == self.r2.num)
271 assert(shift == self.shift)
272 assert(mb == self.mb)
273 assert(me == self.me)
274
275 rc = yield pdecode2.e.rc.data
276 if '.' in self.opcodestr:
277 assert(rc == 1)
278 else:
279 assert(rc == 0)
280
281
282 class Branch:
283 def __init__(self):
284 self.ops = {
285 "b": MicrOp.OP_B,
286 "bl": MicrOp.OP_B,
287 "ba": MicrOp.OP_B,
288 "bla": MicrOp.OP_B,
289 }
290 self.opcodestr = random.choice(list(self.ops.keys()))
291 self.opcode = self.ops[self.opcodestr]
292 self.addr = random.randrange(2**23) * 4
293
294 def generate_instruction(self):
295 string = "{} {}\n".format(self.opcodestr,
296 self.addr)
297 return string
298
299 def check_results(self, pdecode2):
300 imm = yield pdecode2.e.imm_data.data
301
302 assert(imm == self.addr)
303 lk = yield pdecode2.e.lk
304 if "l" in self.opcodestr:
305 assert(lk == 1)
306 else:
307 assert(lk == 0)
308 aa = yield pdecode2.dec.AA
309 if "a" in self.opcodestr:
310 assert(aa == 1)
311 else:
312 assert(aa == 0)
313
314
315 class BranchCond:
316 def __init__(self):
317 self.ops = {
318 "bc": MicrOp.OP_B,
319 "bcl": MicrOp.OP_B,
320 "bca": MicrOp.OP_B,
321 "bcla": MicrOp.OP_B,
322 }
323 # Given in Figure 40 "BO field encodings" in section 2.4, page
324 # 33 of the Power ISA v3.0B manual
325 self.branchops = [0b00000, 0b00010, 0b00100, 0b01000, 0b01010,
326 0b01100, 0b10000, 0b10100]
327 self.opcodestr = random.choice(list(self.ops.keys()))
328 self.opcode = self.ops[self.opcodestr]
329 self.addr = random.randrange(2**13) * 4
330 self.bo = random.choice(self.branchops)
331 self.bi = random.randrange(32)
332
333 def generate_instruction(self):
334 string = "{} {},{},{}\n".format(self.opcodestr,
335 self.bo,
336 self.bi,
337 self.addr)
338 return string
339
340 def check_results(self, pdecode2):
341 imm = yield pdecode2.e.imm_data.data
342 bo = yield pdecode2.dec.BO
343 bi = yield pdecode2.dec.BI
344
345 assert(imm == self.addr)
346 assert(bo == self.bo)
347 assert(bi == self.bi)
348 lk = yield pdecode2.e.lk
349 if "l" in self.opcodestr:
350 assert(lk == 1)
351 else:
352 assert(lk == 0)
353 aa = yield pdecode2.dec.AA
354 if "a" in self.opcodestr:
355 assert(aa == 1)
356 else:
357 assert(aa == 0)
358
359 cr_sel = yield pdecode2.e.read_cr1.data
360 assert cr_sel == (self.bi//8), f"{cr_sel} {self.bi}"
361
362
363
364 class BranchRel:
365 def __init__(self):
366 self.ops = {
367 "bclr": MicrOp.OP_B,
368 "bcctr": MicrOp.OP_B,
369 "bclrl": MicrOp.OP_B,
370 "bcctrl": MicrOp.OP_B,
371 }
372 # Given in Figure 40 "BO field encodings" in section 2.4, page
373 # 33 of the Power ISA v3.0B manual
374 self.branchops = [0b00100, 0b01100, 0b10100]
375 self.opcodestr = random.choice(list(self.ops.keys()))
376 self.opcode = self.ops[self.opcodestr]
377 self.bh = random.randrange(4)
378 self.bo = random.choice(self.branchops)
379 self.bi = random.randrange(32)
380
381 def generate_instruction(self):
382 string = "{} {},{},{}\n".format(self.opcodestr,
383 self.bo,
384 self.bi,
385 self.bh)
386 return string
387
388 def check_results(self, pdecode2):
389 bo = yield pdecode2.dec.BO
390 bi = yield pdecode2.dec.BI
391
392 assert(bo == self.bo)
393 assert(bi == self.bi)
394
395 spr = yield pdecode2.e.read_spr2.data
396 if "lr" in self.opcodestr:
397 assert(spr == SPR.LR.value)
398 else:
399 assert(spr == SPR.CTR.value)
400
401 lk = yield pdecode2.e.lk
402 if self.opcodestr[-1] == 'l':
403 assert(lk == 1)
404 else:
405 assert(lk == 0)
406
407 class CROp:
408 def __init__(self):
409 self.ops = {
410 "crand": MicrOp.OP_CROP,
411 }
412 # Given in Figure 40 "BO field encodings" in section 2.4, page
413 # 33 of the Power ISA v3.0B manual
414 self.opcodestr = random.choice(list(self.ops.keys()))
415 self.opcode = self.ops[self.opcodestr]
416 self.ba = random.randrange(32)
417 self.bb = random.randrange(32)
418 self.bt = random.randrange(32)
419
420 def generate_instruction(self):
421 string = "{} {},{},{}\n".format(self.opcodestr,
422 self.bt,
423 self.ba,
424 self.bb)
425 return string
426
427 def check_results(self, pdecode2):
428 cr1 = yield pdecode2.e.read_cr1.data
429 assert cr1 == self.ba//4
430
431 cr2 = yield pdecode2.e.read_cr2.data
432 assert cr2 == self.bb//4
433
434 cr_out = yield pdecode2.e.write_cr.data
435 cr3 = yield pdecode2.e.read_cr3.data
436 assert cr_out == self.bt//4
437 assert cr3 == self.bt//4
438
439
440
441 class DecoderTestCase(FHDLTestCase):
442
443 def run_tst(self, kls, name):
444 m = Module()
445 comb = m.d.comb
446 instruction = Signal(32)
447
448 pdecode = create_pdecode()
449
450 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
451 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
452 sim = Simulator(m)
453
454 def process():
455 for i in range(20):
456 checker = kls()
457 ins = checker.generate_instruction()
458 print("instr", ins.strip())
459 for mode in [0, 1]:
460
461 # turn the instruction into binary data (endian'd)
462 ibin = get_assembled_instruction(ins, mode)
463 print("code", mode, hex(ibin), bin(ibin))
464
465 # ask the decoder to decode this binary data (endian'd)
466 yield pdecode2.dec.bigendian.eq(mode) # little / big?
467 yield instruction.eq(ibin) # raw binary instr.
468 yield Delay(1e-6)
469
470 yield from checker.check_results(pdecode2)
471
472 sim.add_process(process)
473 ports = pdecode2.ports()
474 print(ports)
475 with sim.write_vcd("%s.vcd" % name, "%s.gtkw" % name,
476 traces=ports):
477 sim.run()
478
479 def test_reg_reg(self):
480 self.run_tst(RegRegOp, "reg_reg")
481
482 def test_reg_imm(self):
483 self.run_tst(RegImmOp, "reg_imm")
484
485 def test_ldst_imm(self):
486 self.run_tst(LdStOp, "ldst_imm")
487
488 def test_cmp_reg(self):
489 self.run_tst(CmpRegOp, "cmp_reg")
490
491 def test_rot(self):
492 self.run_tst(RotateOp, "rot")
493
494 def test_branch(self):
495 self.run_tst(Branch, "branch")
496
497 def test_branch_cond(self):
498 self.run_tst(BranchCond, "branch_cond")
499
500 def test_branch_rel(self):
501 self.run_tst(BranchRel, "branch_rel")
502
503 def test_cr_op(self):
504 self.run_tst(CROp, "cr_op")
505
506
507 if __name__ == "__main__":
508 unittest.main()