Add tests for load/store with immediate offset
[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 class DecoderTestCase(FHDLTestCase):
180
181 def get_assembled_instruction(self, instruction):
182 with tempfile.NamedTemporaryFile(suffix=".o") as outfile:
183 args = ["powerpc64-linux-gnu-as",
184 "-o",
185 outfile.name]
186 p = subprocess.Popen(args, stdin=subprocess.PIPE)
187 p.communicate(instruction.encode('utf-8'))
188 assert(p.wait() == 0)
189
190 with tempfile.NamedTemporaryFile(suffix=".bin") as binfile:
191 args = ["powerpc64-linux-gnu-objcopy",
192 "-O", "binary",
193 outfile.name,
194 binfile.name]
195 subprocess.check_output(args)
196 binary = struct.unpack('>i', binfile.read(4))[0]
197 return binary
198
199 def run_tst(self, kls, name):
200 m = Module()
201 comb = m.d.comb
202 instruction = Signal(32)
203
204 pdecode = create_pdecode()
205
206 m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
207 comb += pdecode2.dec.opcode_in.eq(instruction)
208
209 sim = Simulator(m)
210
211 def process():
212 for i in range(20):
213 checker = kls()
214
215 instruction_str = checker.generate_instruction()
216 print("instr", instruction_str.strip())
217 instruction_bin = self.get_assembled_instruction(
218 instruction_str)
219 print("code", hex(instruction_bin), bin(instruction_bin))
220
221 yield instruction.eq(instruction_bin)
222 yield Delay(1e-6)
223
224 yield from checker.check_results(pdecode2)
225
226
227 sim.add_process(process)
228 with sim.write_vcd("%s.vcd" % name, "%s.gtkw" % name,
229 traces=[pdecode2.ports()]):
230 sim.run()
231 def test_reg_reg(self):
232 self.run_tst(RegRegOp, "reg_reg")
233
234 def test_reg_imm(self):
235 self.run_tst(RegImmOp, "reg_imm")
236
237 def test_ldst_imm(self):
238 self.run_tst(LdStOp, "ldst_imm")
239
240
241 if __name__ == "__main__":
242 unittest.main()