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, 7)
71 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
76 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
80 mask
= random
.randint(0, 255)
81 lst
= [f
"mtcrf {mask}, 2"]
82 cr
= random
.randint(0, (1<<32)-1)
83 initial_regs
= [0] * 32
84 initial_regs
[2] = random
.randint(0, (1<<32)-1)
85 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
87 def test_mtocrf(self
):
89 mask
= 1<<random
.randint(0, 7)
90 lst
= [f
"mtocrf {mask}, 2"]
91 cr
= random
.randint(0, (1<<32)-1)
92 initial_regs
= [0] * 32
93 initial_regs
[2] = random
.randint(0, (1<<32)-1)
94 self
.run_tst_program(Program(lst
), initial_regs
=initial_regs
,
100 cr
= random
.randint(0, (1<<32)-1)
101 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
103 def test_mfocrf(self
):
105 mask
= 1<<random
.randint(0, 7)
106 lst
= [f
"mfocrf 2, {mask}"]
107 cr
= random
.randint(0, (1<<32)-1)
108 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
111 def test_ilang(self
):
112 pspec
= CRPipeSpec(id_wid
=2)
113 alu
= CRBasePipe(pspec
)
114 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
115 with
open("cr_pipeline.il", "w") as f
:
119 class TestRunner(FHDLTestCase
):
120 def __init__(self
, test_data
):
121 super().__init
__("run_all")
122 self
.test_data
= test_data
124 def set_inputs(self
, alu
, dec2
, simulator
):
125 yield alu
.p
.data_i
.cr
.eq(simulator
.cr
.get_range().value
)
127 reg3_ok
= yield dec2
.e
.read_reg3
.ok
129 reg3_sel
= yield dec2
.e
.read_reg3
.data
130 reg3
= simulator
.gpr(reg3_sel
).value
131 yield alu
.p
.data_i
.a
.eq(reg3
)
136 instruction
= Signal(32)
138 pdecode
= create_pdecode()
140 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
142 pspec
= CRPipeSpec(id_wid
=2)
143 m
.submodules
.alu
= alu
= CRBasePipe(pspec
)
145 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
146 comb
+= alu
.p
.valid_i
.eq(1)
147 comb
+= alu
.n
.ready_i
.eq(1)
148 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
153 for test
in self
.test_data
:
155 program
= test
.program
156 self
.subTest(test
.name
)
157 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
158 gen
= program
.generate_instructions()
159 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
161 index
= simulator
.pc
.CIA
.value
//4
162 while index
< len(instructions
):
163 ins
, code
= instructions
[index
]
165 print("0x{:X}".format(ins
& 0xffffffff))
168 # ask the decoder to decode this binary data (endian'd)
169 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
170 yield instruction
.eq(ins
) # raw binary instr.
172 yield from self
.set_inputs(alu
, pdecode2
, simulator
)
173 fn_unit
= yield pdecode2
.e
.fn_unit
174 self
.assertEqual(fn_unit
, Function
.CR
.value
, code
)
176 opname
= code
.split(' ')[0]
177 yield from simulator
.call(opname
)
178 index
= simulator
.pc
.CIA
.value
//4
180 vld
= yield alu
.n
.valid_o
183 vld
= yield alu
.n
.valid_o
185 cr_out
= yield pdecode2
.e
.output_cr
187 cr_expected
= simulator
.cr
.get_range().value
188 cr_real
= yield alu
.n
.data_o
.cr
189 msg
= f
"real: {cr_expected:x}, actual: {cr_real:x}"
190 msg
+= " code: %s" % code
191 self
.assertEqual(cr_expected
, cr_real
, msg
)
193 reg_out
= yield pdecode2
.e
.write_reg
.ok
195 reg_sel
= yield pdecode2
.e
.write_reg
.data
196 reg_data
= simulator
.gpr(reg_sel
).value
197 output
= yield alu
.n
.data_o
.o
198 msg
= f
"real: {reg_data:x}, actual: {output:x}"
199 self
.assertEqual(reg_data
, output
)
201 sim
.add_sync_process(process
)
202 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
205 def check_extra_alu_outputs(self
, alu
, dec2
, sim
):
206 rc
= yield dec2
.e
.rc
.data
208 cr_expected
= sim
.crl
[0].get_range().value
209 cr_actual
= yield alu
.n
.data_o
.cr0
210 self
.assertEqual(cr_expected
, cr_actual
)
213 if __name__
== "__main__":
214 unittest
.main(exit
=False)
215 suite
= unittest
.TestSuite()
216 suite
.addTest(TestRunner(test_data
))
218 runner
= unittest
.TextTestRunner()