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