1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmigen
.test
.utils
import FHDLTestCase
4 from nmigen
.cli
import rtlil
6 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
7 from soc
.decoder
.power_decoder
import (create_pdecode
)
8 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
9 from soc
.decoder
.power_enums
import (XER_bits
, Function
)
10 from soc
.decoder
.selectable_int
import SelectableInt
11 from soc
.simulator
.program
import Program
12 from soc
.decoder
.isa
.all
import ISA
15 from soc
.fu
.cr
.pipeline
import CRBasePipe
16 from soc
.fu
.alu
.alu_input_record
import CompALUOpSubset
17 from soc
.fu
.cr
.pipe_data
import CRPipeSpec
22 def __init__(self
, program
, regs
, sprs
, cr
, name
):
23 self
.program
= program
30 # This test bench is a bit different than is usual. Initially when I
31 # was writing it, I had all of the tests call a function to create a
32 # device under test and simulator, initialize the dut, run the
33 # simulation for ~2 cycles, and assert that the dut output what it
34 # should have. However, this was really slow, since it needed to
35 # create and tear down the dut and simulator for every test case.
37 # Now, instead of doing that, every test case in ALUTestCase puts some
38 # data into the test_data list below, describing the instructions to
39 # be tested and the initial state. Once all the tests have been run,
40 # test_data gets passed to TestRunner which then sets up the DUT and
41 # simulator once, runs all the data through it, and asserts that the
42 # results match the pseudocode sim at every cycle.
44 # By doing this, I've reduced the time it takes to run the test suite
45 # massively. Before, it took around 1 minute on my computer, now it
46 # takes around 3 seconds
51 class CRTestCase(FHDLTestCase
):
52 def __init__(self
, name
):
53 super().__init
__(name
)
55 def run_tst_program(self
, prog
, initial_regs
=[0] * 32, initial_sprs
={},
57 tc
= TestCase(prog
, initial_regs
, initial_sprs
, initial_cr
,
62 insns
= ["crand", "cror", "crnand", "crnor", "crxor", "creqv",
65 choice
= random
.choice(insns
)
66 ba
= random
.randint(0, 31)
67 bb
= random
.randint(0, 31)
68 bt
= random
.randint(0, 31)
69 lst
= [f
"{choice} {ba}, {bb}, {bt}"]
70 cr
= random
.randint(0, (1<<32)-1)
71 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
75 lst
= ["crand 0, 11, 13"]
76 cr
= random
.randint(0, (1<<32)-1)
77 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
82 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
84 @unittest.skip("broken")
87 mask
= random
.randint(0, 255)
88 lst
= [f
"mtcrf {mask}, 2"]
89 cr
= random
.randint(0, (1<<32)-1)
90 initial_regs
= [0] * 32
91 initial_regs
[2] = random
.randint(0, (1<<32)-1)
92 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
94 @unittest.skip("broken")
95 def test_mtocrf(self
):
97 mask
= 1<<random
.randint(0, 7)
98 lst
= [f
"mtocrf {mask}, 2"]
99 cr
= random
.randint(0, (1<<32)-1)
100 initial_regs
= [0] * 32
101 initial_regs
[2] = random
.randint(0, (1<<32)-1)
102 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
105 @unittest.skip("broken")
109 cr
= random
.randint(0, (1<<32)-1)
110 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
112 @unittest.skip("broken")
113 def test_mfocrf(self
):
115 mask
= 1<<random
.randint(0, 7)
116 lst
= [f
"mfocrf 2, {mask}"]
117 cr
= random
.randint(0, (1<<32)-1)
118 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
121 def test_ilang(self
):
122 pspec
= CRPipeSpec(id_wid
=2)
123 alu
= CRBasePipe(pspec
)
124 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
125 with
open("cr_pipeline.il", "w") as f
:
129 class TestRunner(FHDLTestCase
):
130 def __init__(self
, test_data
):
131 super().__init
__("run_all")
132 self
.test_data
= test_data
134 def set_inputs(self
, alu
, dec2
, simulator
):
135 full_reg
= yield dec2
.e
.read_cr_whole
137 print(simulator
.cr
.get_range().value
)
139 yield alu
.p
.data_i
.full_cr
.eq(simulator
.cr
.get_range().value
)
141 cr1_en
= yield dec2
.e
.read_cr1
.ok
143 cr1_sel
= yield dec2
.e
.read_cr1
.data
144 cr1
= simulator
.crl
[cr1_sel
].get_range().value
145 yield alu
.p
.data_i
.cr_a
.eq(cr1
)
146 cr2_en
= yield dec2
.e
.read_cr2
.ok
148 cr2_sel
= yield dec2
.e
.read_cr2
.data
149 cr2
= simulator
.crl
[cr2_sel
].get_range().value
150 yield alu
.p
.data_i
.cr_b
.eq(cr2
)
151 cr3_en
= yield dec2
.e
.read_cr3
.ok
153 cr3_sel
= yield dec2
.e
.read_cr3
.data
154 cr3
= simulator
.crl
[cr3_sel
].get_range().value
155 yield alu
.p
.data_i
.cr_c
.eq(cr3
)
157 reg3_ok
= yield dec2
.e
.read_reg3
.ok
159 reg3_sel
= yield dec2
.e
.read_reg3
.data
160 reg3
= simulator
.gpr(reg3_sel
).value
161 yield alu
.p
.data_i
.a
.eq(reg3
)
163 def assert_outputs(self
, alu
, dec2
, simulator
):
164 whole_reg
= yield dec2
.e
.write_cr_whole
165 cr_en
= yield dec2
.e
.write_cr
.ok
167 full_cr
= yield alu
.n
.data_o
.full_cr
168 expected_cr
= simulator
.cr
.get_range().value
169 self
.assertEqual(expected_cr
, full_cr
)
171 cr_sel
= yield dec2
.e
.write_cr
.data
172 expected_cr
= simulator
.crl
[cr_sel
].get_range().value
173 real_cr
= yield alu
.n
.data_o
.cr_o
174 self
.assertEqual(expected_cr
, real_cr
)
180 instruction
= Signal(32)
182 pdecode
= create_pdecode()
184 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
186 pspec
= CRPipeSpec(id_wid
=2)
187 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
189 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
190 comb
+= alu
.n
.ready_i
.eq(1)
191 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
196 for test
in self
.test_data
:
198 program
= test
.program
199 self
.subTest(test
.name
)
200 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
201 gen
= program
.generate_instructions()
202 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
204 index
= simulator
.pc
.CIA
.value
//4
205 while index
< len(instructions
):
206 ins
, code
= instructions
[index
]
208 print("0x{:X}".format(ins
& 0xffffffff))
211 # ask the decoder to decode this binary data (endian'd)
212 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
213 yield instruction
.eq(ins
) # raw binary instr.
215 yield from self
.set_inputs(alu
, pdecode2
, simulator
)
216 yield alu
.p
.valid_i
.eq(1)
217 fn_unit
= yield pdecode2
.e
.fn_unit
218 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
220 opname
= code
.split(' ')[0]
221 yield from simulator
.call(opname
)
222 index
= simulator
.pc
.CIA
.value
//4
224 vld
= yield alu
.n
.valid_o
227 vld
= yield alu
.n
.valid_o
229 yield from self
.assert_outputs(alu
, pdecode2
, simulator
)
231 sim
.add_sync_process(process
)
232 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
235 def check_extra_alu_outputs(self
, alu
, dec2
, sim
):
236 rc
= yield dec2
.e
.rc
.data
238 cr_expected
= sim
.crl
[0].get_range().value
239 cr_actual
= yield alu
.n
.data_o
.cr0
240 self
.assertEqual(cr_expected
, cr_actual
)
243 if __name__
== "__main__":
244 unittest
.main(exit
=False)
245 suite
= unittest
.TestSuite()
246 suite
.addTest(TestRunner(test_data
))
248 runner
= unittest
.TextTestRunner()