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