Properly sign extend immediates
[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 self.imm = random.randrange(32767)
156
157 def generate_instruction(self):
158 string = "{} {}, {}({})\n".format(self.opcodestr,
159 self.r1.num,
160 self.imm,
161 self.r2.num)
162 return string
163
164 def check_results(self, pdecode2):
165 print("Check")
166 r2sel = yield pdecode2.e.read_reg1.data
167 if self.opcode == InternalOp.OP_STORE:
168 r1sel = yield pdecode2.e.read_reg3.data
169 else:
170 r1sel = yield pdecode2.e.write_reg.data
171 assert(r1sel == self.r1.num)
172 assert(r2sel == self.r2.num)
173
174 imm = yield pdecode2.e.imm_data.data
175 in2_sel = yield pdecode2.dec.op.in2_sel
176 assert(imm == self.get_imm(in2_sel))
177
178 update = yield pdecode2.e.update
179 if "u" in self.opcodestr:
180 assert(update == 1)
181 else:
182 assert(update == 0)
183
184 size = yield pdecode2.e.data_len
185 if "w" in self.opcodestr:
186 assert(size == 4)
187 elif "h" in self.opcodestr:
188 assert(size == 2)
189 elif "b" in self.opcodestr:
190 assert(size == 1)
191 else:
192 assert(False)
193
194
195 class CmpRegOp:
196 def __init__(self):
197 self.ops = {
198 "cmp": InternalOp.OP_CMP,
199 }
200 self.opcodestr = random.choice(list(self.ops.keys()))
201 self.opcode = self.ops[self.opcodestr]
202 self.r1 = Register(random.randrange(32))
203 self.r2 = Register(random.randrange(32))
204 self.cr = Register(random.randrange(8))
205
206 def generate_instruction(self):
207 string = "{} {}, 0, {}, {}\n".format(self.opcodestr,
208 self.cr.num,
209 self.r1.num,
210 self.r2.num)
211 return string
212
213 def check_results(self, pdecode2):
214 r1sel = yield pdecode2.e.read_reg1.data
215 r2sel = yield pdecode2.e.read_reg2.data
216 crsel = yield pdecode2.dec.BF[0:-1]
217
218 assert(r1sel == self.r1.num)
219 assert(r2sel == self.r2.num)
220 assert(crsel == self.cr.num)
221
222
223 class RotateOp:
224 def __init__(self):
225 self.ops = {
226 "rlwinm": InternalOp.OP_CMP,
227 "rlwnm": InternalOp.OP_CMP,
228 "rlwimi": InternalOp.OP_CMP,
229 "rlwinm.": InternalOp.OP_CMP,
230 "rlwnm.": InternalOp.OP_CMP,
231 "rlwimi.": InternalOp.OP_CMP,
232 }
233 self.opcodestr = random.choice(list(self.ops.keys()))
234 self.opcode = self.ops[self.opcodestr]
235 self.r1 = Register(random.randrange(32))
236 self.r2 = Register(random.randrange(32))
237 self.shift = random.randrange(32)
238 self.mb = random.randrange(32)
239 self.me = random.randrange(32)
240
241 def generate_instruction(self):
242 string = "{} {},{},{},{},{}\n".format(self.opcodestr,
243 self.r1.num,
244 self.r2.num,
245 self.shift,
246 self.mb,
247 self.me)
248 return string
249
250 def check_results(self, pdecode2):
251 r1sel = yield pdecode2.e.write_reg.data
252 r2sel = yield pdecode2.e.read_reg3.data
253 dec = pdecode2.dec
254
255 if "i" in self.opcodestr:
256 shift = yield dec.SH[0:-1]
257 else:
258 shift = yield pdecode2.e.read_reg2.data
259 mb = yield dec.MB[0:-1]
260 me = yield dec.ME[0:-1]
261
262 assert(r1sel == self.r1.num)
263 assert(r2sel == self.r2.num)
264 assert(shift == self.shift)
265 assert(mb == self.mb)
266 assert(me == self.me)
267
268 rc = yield pdecode2.e.rc.data
269 if '.' in self.opcodestr:
270 assert(rc == 1)
271 else:
272 assert(rc == 0)
273
274
275 class Branch:
276 def __init__(self):
277 self.ops = {
278 "b": InternalOp.OP_B,
279 "bl": InternalOp.OP_B,
280 "ba": InternalOp.OP_B,
281 "bla": InternalOp.OP_B,
282 }
283 self.opcodestr = random.choice(list(self.ops.keys()))
284 self.opcode = self.ops[self.opcodestr]
285 self.addr = random.randrange(2**23) * 4
286
287 def generate_instruction(self):
288 string = "{} {}\n".format(self.opcodestr,
289 self.addr)
290 return string
291
292 def check_results(self, pdecode2):
293 imm = yield pdecode2.e.imm_data.data
294
295 assert(imm == self.addr)
296 lk = yield pdecode2.e.lk
297 if "l" in self.opcodestr:
298 assert(lk == 1)
299 else:
300 assert(lk == 0)
301 aa = yield pdecode2.dec.AA[0:-1]
302 if "a" in self.opcodestr:
303 assert(aa == 1)
304 else:
305 assert(aa == 0)
306
307
308 class BranchCond:
309 def __init__(self):
310 self.ops = {
311 "bc": InternalOp.OP_B,
312 "bcl": InternalOp.OP_B,
313 "bca": InternalOp.OP_B,
314 "bcla": InternalOp.OP_B,
315 }
316 # Given in Figure 40 "BO field encodings" in section 2.4, page
317 # 33 of the Power ISA v3.0B manual
318 self.branchops = [0b00000, 0b00010, 0b00100, 0b01000, 0b01010,
319 0b01100, 0b10000, 0b10100]
320 self.opcodestr = random.choice(list(self.ops.keys()))
321 self.opcode = self.ops[self.opcodestr]
322 self.addr = random.randrange(2**13) * 4
323 self.bo = random.choice(self.branchops)
324 self.bi = random.randrange(32)
325
326 def generate_instruction(self):
327 string = "{} {},{},{}\n".format(self.opcodestr,
328 self.bo,
329 self.bi,
330 self.addr)
331 return string
332
333 def check_results(self, pdecode2):
334 imm = yield pdecode2.e.imm_data.data
335 bo = yield pdecode2.dec.BO[0:-1]
336 bi = yield pdecode2.dec.BI[0:-1]
337
338 assert(imm == self.addr)
339 assert(bo == self.bo)
340 assert(bi == self.bi)
341 lk = yield pdecode2.e.lk
342 if "l" in self.opcodestr:
343 assert(lk == 1)
344 else:
345 assert(lk == 0)
346 aa = yield pdecode2.dec.AA[0:-1]
347 if "a" in self.opcodestr:
348 assert(aa == 1)
349 else:
350 assert(aa == 0)
351
352
353 class BranchRel:
354 def __init__(self):
355 self.ops = {
356 "bclr": InternalOp.OP_B,
357 "bcctr": InternalOp.OP_B,
358 "bclrl": InternalOp.OP_B,
359 "bcctrl": InternalOp.OP_B,
360 }
361 # Given in Figure 40 "BO field encodings" in section 2.4, page
362 # 33 of the Power ISA v3.0B manual
363 self.branchops = [0b00100, 0b01100, 0b10100]
364 self.opcodestr = random.choice(list(self.ops.keys()))
365 self.opcode = self.ops[self.opcodestr]
366 self.bh = random.randrange(4)
367 self.bo = random.choice(self.branchops)
368 self.bi = random.randrange(32)
369
370 def generate_instruction(self):
371 string = "{} {},{},{}\n".format(self.opcodestr,
372 self.bo,
373 self.bi,
374 self.bh)
375 return string
376
377 def check_results(self, pdecode2):
378 bo = yield pdecode2.dec.BO[0:-1]
379 bi = yield pdecode2.dec.BI[0:-1]
380
381 assert(bo == self.bo)
382 assert(bi == self.bi)
383
384 spr = yield pdecode2.e.read_spr2.data
385 if "lr" in self.opcodestr:
386 assert(spr == SPR.LR.value)
387 else:
388 assert(spr == SPR.CTR.value)
389
390 lk = yield pdecode2.e.lk
391 if self.opcodestr[-1] == 'l':
392 assert(lk == 1)
393 else:
394 assert(lk == 0)
395
396
397 class DecoderTestCase(FHDLTestCase):
398
399 def run_tst(self, kls, name):
400 m = Module()
401 comb = m.d.comb
402 instruction = Signal(32)
403
404 pdecode = create_pdecode()
405
406 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
407 comb += pdecode2.dec.raw_opcode_in.eq(instruction)
408 sim = Simulator(m)
409
410 def process():
411 for i in range(20):
412 checker = kls()
413 ins = checker.generate_instruction()
414 print("instr", ins.strip())
415 for mode in [0, 1]:
416
417 # turn the instruction into binary data (endian'd)
418 ibin = get_assembled_instruction(ins, mode)
419 print("code", mode, hex(ibin), bin(ibin))
420
421 # ask the decoder to decode this binary data (endian'd)
422 yield pdecode2.dec.bigendian.eq(mode) # little / big?
423 yield instruction.eq(ibin) # raw binary instr.
424 yield Delay(1e-6)
425
426 yield from checker.check_results(pdecode2)
427
428 sim.add_process(process)
429 with sim.write_vcd("%s.vcd" % name, "%s.gtkw" % name,
430 traces=[pdecode2.ports()]):
431 sim.run()
432
433 def test_reg_reg(self):
434 self.run_tst(RegRegOp, "reg_reg")
435
436 def test_reg_imm(self):
437 self.run_tst(RegImmOp, "reg_imm")
438
439 def test_ldst_imm(self):
440 self.run_tst(LdStOp, "ldst_imm")
441
442 def test_cmp_reg(self):
443 self.run_tst(CmpRegOp, "cmp_reg")
444
445 def test_rot(self):
446 self.run_tst(RotateOp, "rot")
447
448 def test_branch(self):
449 self.run_tst(Branch, "branch")
450
451 def test_branch_cond(self):
452 self.run_tst(BranchCond, "branch_cond")
453
454 def test_branch_rel(self):
455 self.run_tst(BranchRel, "branch_rel")
456
457
458 if __name__ == "__main__":
459 unittest.main()