Add tests for branch instructions
[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,
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 import pdb
17
18
19
20 class Register:
21 def __init__(self, num):
22 self.num = num
23
24 class RegRegOp:
25 def __init__(self):
26 self.ops = {
27 "add": InternalOp.OP_ADD,
28 "and": InternalOp.OP_AND,
29 "or": InternalOp.OP_OR,
30 "add.": InternalOp.OP_ADD,
31 "lwzx": InternalOp.OP_LOAD,
32 "stwx": InternalOp.OP_STORE,
33 }
34 self.opcodestr = random.choice(list(self.ops.keys()))
35 self.opcode = self.ops[self.opcodestr]
36 self.r1 = Register(random.randrange(32))
37 self.r2 = Register(random.randrange(32))
38 self.r3 = Register(random.randrange(32))
39
40 def generate_instruction(self):
41 string = "{} {}, {}, {}\n".format(self.opcodestr,
42 self.r1.num,
43 self.r2.num,
44 self.r3.num)
45 return string
46
47 def check_results(self, pdecode2):
48 if self.opcode == InternalOp.OP_STORE:
49 r1sel = yield pdecode2.e.read_reg3.data
50 else:
51 r1sel = yield pdecode2.e.write_reg.data
52
53 r3sel = yield pdecode2.e.read_reg2.data
54
55 # For some reason r2 gets decoded either in read_reg1
56 # or read_reg3
57 out_sel = yield pdecode2.dec.op.out_sel
58 if out_sel == OutSel.RA.value:
59 r2sel = yield pdecode2.e.read_reg3.data
60 else:
61 r2sel = yield pdecode2.e.read_reg1.data
62 assert(r1sel == self.r1.num)
63 assert(r3sel == self.r3.num)
64 assert(r2sel == self.r2.num)
65
66 opc_out = yield pdecode2.dec.op.internal_op
67 assert(opc_out == self.opcode.value)
68 # check RC value (the dot in the instruction)
69 rc = yield pdecode2.e.rc.data
70 if '.' in self.opcodestr:
71 assert(rc == 1)
72 else:
73 assert(rc == 0)
74
75
76
77 class RegImmOp:
78 def __init__(self):
79 self.ops = {
80 "addi": InternalOp.OP_ADD,
81 "addis": InternalOp.OP_ADD,
82 "andi.": InternalOp.OP_AND,
83 "ori": InternalOp.OP_OR,
84 }
85 self.opcodestr = random.choice(list(self.ops.keys()))
86 self.opcode = self.ops[self.opcodestr]
87 self.r1 = Register(random.randrange(32))
88 self.r2 = Register(random.randrange(32))
89 self.imm = random.randrange(32767)
90
91 def generate_instruction(self):
92 string = "{} {}, {}, {}\n".format(self.opcodestr,
93 self.r1.num,
94 self.r2.num,
95 self.imm)
96 return string
97
98 def check_results(self, pdecode2):
99 print("Check")
100 r1sel = yield pdecode2.e.write_reg.data
101 # For some reason r2 gets decoded either in read_reg1
102 # or read_reg3
103 out_sel = yield pdecode2.dec.op.out_sel
104 if out_sel == OutSel.RA.value:
105 r2sel = yield pdecode2.e.read_reg3.data
106 else:
107 r2sel = yield pdecode2.e.read_reg1.data
108 assert(r1sel == self.r1.num)
109 assert(r2sel == self.r2.num)
110
111 imm = yield pdecode2.e.imm_data.data
112 in2_sel = yield pdecode2.dec.op.in2_sel
113 if in2_sel in [In2Sel.CONST_SI_HI.value, In2Sel.CONST_UI_HI.value]:
114 assert(imm == (self.imm << 16))
115 else:
116 assert(imm == self.imm)
117
118 rc = yield pdecode2.e.rc.data
119 if '.' in self.opcodestr:
120 assert(rc == 1)
121 else:
122 assert(rc == 0)
123
124 class LdStOp:
125 def __init__(self):
126 self.ops = {
127 "lwz": InternalOp.OP_LOAD,
128 "stw": InternalOp.OP_STORE,
129 "lwzu": InternalOp.OP_LOAD,
130 "stwu": InternalOp.OP_STORE,
131 "lbz": InternalOp.OP_LOAD,
132 "lhz": InternalOp.OP_LOAD,
133 "stb": InternalOp.OP_STORE,
134 "sth": InternalOp.OP_STORE,
135 }
136 self.opcodestr = random.choice(list(self.ops.keys()))
137 self.opcode = self.ops[self.opcodestr]
138 self.r1 = Register(random.randrange(32))
139 self.r2 = Register(random.randrange(1,32))
140 self.imm = random.randrange(32767)
141
142 def generate_instruction(self):
143 string = "{} {}, {}({})\n".format(self.opcodestr,
144 self.r1.num,
145 self.imm,
146 self.r2.num)
147 return string
148
149 def check_results(self, pdecode2):
150 print("Check")
151 r2sel = yield pdecode2.e.read_reg1.data
152 if self.opcode == InternalOp.OP_STORE:
153 r1sel = yield pdecode2.e.read_reg3.data
154 else:
155 r1sel = yield pdecode2.e.write_reg.data
156 assert(r1sel == self.r1.num)
157 assert(r2sel == self.r2.num)
158
159 imm = yield pdecode2.e.imm_data.data
160 in2_sel = yield pdecode2.dec.op.in2_sel
161 assert(imm == self.imm)
162
163 update = yield pdecode2.e.update
164 if "u" in self.opcodestr:
165 assert(update == 1)
166 else:
167 assert(update == 0)
168
169 size = yield pdecode2.e.data_len
170 if "w" in self.opcodestr:
171 assert(size == 4)
172 elif "h" in self.opcodestr:
173 assert(size == 2)
174 elif "b" in self.opcodestr:
175 assert(size == 1)
176 else:
177 assert(False)
178
179
180 class CmpRegOp:
181 def __init__(self):
182 self.ops = {
183 "cmp": InternalOp.OP_CMP,
184 }
185 self.opcodestr = random.choice(list(self.ops.keys()))
186 self.opcode = self.ops[self.opcodestr]
187 self.r1 = Register(random.randrange(32))
188 self.r2 = Register(random.randrange(32))
189 self.cr = Register(random.randrange(8))
190
191 def generate_instruction(self):
192 string = "{} {}, 0, {}, {}\n".format(self.opcodestr,
193 self.cr.num,
194 self.r1.num,
195 self.r2.num)
196 return string
197
198 def check_results(self, pdecode2):
199 r1sel = yield pdecode2.e.read_reg1.data
200 r2sel = yield pdecode2.e.read_reg2.data
201 crsel = yield pdecode2.dec.BF[0:-1]
202
203 assert(r1sel == self.r1.num)
204 assert(r2sel == self.r2.num)
205 assert(crsel == self.cr.num)
206
207
208 class RotateOp:
209 def __init__(self):
210 self.ops = {
211 "rlwinm": InternalOp.OP_CMP,
212 "rlwnm": InternalOp.OP_CMP,
213 "rlwimi": InternalOp.OP_CMP,
214 "rlwinm.": InternalOp.OP_CMP,
215 "rlwnm.": InternalOp.OP_CMP,
216 "rlwimi.": InternalOp.OP_CMP,
217 }
218 self.opcodestr = random.choice(list(self.ops.keys()))
219 self.opcode = self.ops[self.opcodestr]
220 self.r1 = Register(random.randrange(32))
221 self.r2 = Register(random.randrange(32))
222 self.shift = random.randrange(32)
223 self.mb = random.randrange(32)
224 self.me = random.randrange(32)
225
226 def generate_instruction(self):
227 string = "{} {},{},{},{},{}\n".format(self.opcodestr,
228 self.r1.num,
229 self.r2.num,
230 self.shift,
231 self.mb,
232 self.me)
233 return string
234
235 def check_results(self, pdecode2):
236 r1sel = yield pdecode2.e.write_reg.data
237 r2sel = yield pdecode2.e.read_reg3.data
238 dec = pdecode2.dec
239
240 if "i" in self.opcodestr:
241 shift = yield dec.SH[0:-1]
242 else:
243 shift = yield pdecode2.e.read_reg2.data
244 mb = yield dec.MB[0:-1]
245 me = yield dec.ME[0:-1]
246
247 assert(r1sel == self.r1.num)
248 assert(r2sel == self.r2.num)
249 assert(shift == self.shift)
250 assert(mb == self.mb)
251 assert(me == self.me)
252
253 rc = yield pdecode2.e.rc.data
254 if '.' in self.opcodestr:
255 assert(rc == 1)
256 else:
257 assert(rc == 0)
258
259
260 class Branch:
261 def __init__(self):
262 self.ops = {
263 "b": InternalOp.OP_B,
264 "ba": InternalOp.OP_B,
265 "bla": InternalOp.OP_B,
266 }
267 self.opcodestr = random.choice(list(self.ops.keys()))
268 self.opcode = self.ops[self.opcodestr]
269 self.addr = random.randrange(2**23) * 4
270
271 def generate_instruction(self):
272 string = "{} {}\n".format(self.opcodestr,
273 self.addr)
274 return string
275
276 def check_results(self, pdecode2):
277 imm = yield pdecode2.e.imm_data.data
278
279 assert(imm == self.addr)
280 lk = yield pdecode2.e.lk
281 if "l" in self.opcodestr:
282 assert(lk == 1)
283 else:
284 assert(lk == 0)
285 aa = yield pdecode2.dec.AA[0:-1]
286 if "a" in self.opcodestr:
287 assert(aa == 1)
288 else:
289 assert(aa == 0)
290
291
292 class DecoderTestCase(FHDLTestCase):
293
294 def get_assembled_instruction(self, instruction):
295 with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
296 args = ["powerpc64-linux-gnu-as",
297 "-o",
298 outfile.name]
299 p = subprocess.Popen(args, stdin=subprocess.PIPE)
300 p.communicate(instruction.encode('utf-8'))
301 assert(p.wait() == 0)
302
303 with tempfile.NamedTemporaryFile(suffix=".bin") as binfile:
304 args = ["powerpc64-linux-gnu-objcopy",
305 "-O", "binary",
306 outfile.name,
307 binfile.name]
308 subprocess.check_output(args)
309 binary = struct.unpack('>i', binfile.read(4))[0]
310 return binary
311
312 def run_tst(self, kls, name):
313 m = Module()
314 comb = m.d.comb
315 instruction = Signal(32)
316
317 pdecode = create_pdecode()
318
319 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
320 comb += pdecode2.dec.opcode_in.eq(instruction)
321
322 sim = Simulator(m)
323
324 def process():
325 for i in range(20):
326 checker = kls()
327
328 instruction_str = checker.generate_instruction()
329 print("instr", instruction_str.strip())
330 instruction_bin = self.get_assembled_instruction(
331 instruction_str)
332 print("code", hex(instruction_bin), bin(instruction_bin))
333
334 yield instruction.eq(instruction_bin)
335 yield Delay(1e-6)
336
337 yield from checker.check_results(pdecode2)
338
339
340 sim.add_process(process)
341 with sim.write_vcd("%s.vcd" % name, "%s.gtkw" % name,
342 traces=[pdecode2.ports()]):
343 sim.run()
344 def test_reg_reg(self):
345 self.run_tst(RegRegOp, "reg_reg")
346
347 def test_reg_imm(self):
348 self.run_tst(RegImmOp, "reg_imm")
349
350 def test_ldst_imm(self):
351 self.run_tst(LdStOp, "ldst_imm")
352
353 def test_cmp_reg(self):
354 self.run_tst(CmpRegOp, "cmp_reg")
355
356 def test_rot(self):
357 self.run_tst(RotateOp, "rot")
358
359 def test_branch(self):
360 self.run_tst(Branch, "branch_abs")
361
362 if __name__ == "__main__":
363 unittest.main()