1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmutil
.formaltest
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
13 from soc
.config
.endian
import bigendian
16 from soc
.fu
.test
.common
import TestCase
, ALUHelpers
17 from soc
.fu
.logical
.pipeline
import LogicalBasePipe
18 from soc
.fu
.logical
.pipe_data
import LogicalPipeSpec
22 def get_cu_inputs(dec2
, sim
):
23 """naming (res) must conform to LogicalFunctionUnit input regspec
27 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
28 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
33 def set_alu_inputs(alu
, dec2
, sim
):
34 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
35 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
36 # and place it into data_i.b
38 inp
= yield from get_cu_inputs(dec2
, sim
)
39 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
40 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
43 # This test bench is a bit different than is usual. Initially when I
44 # was writing it, I had all of the tests call a function to create a
45 # device under test and simulator, initialize the dut, run the
46 # simulation for ~2 cycles, and assert that the dut output what it
47 # should have. However, this was really slow, since it needed to
48 # create and tear down the dut and simulator for every test case.
50 # Now, instead of doing that, every test case in ALUTestCase puts some
51 # data into the test_data list below, describing the instructions to
52 # be tested and the initial state. Once all the tests have been run,
53 # test_data gets passed to TestRunner which then sets up the DUT and
54 # simulator once, runs all the data through it, and asserts that the
55 # results match the pseudocode sim at every cycle.
57 # By doing this, I've reduced the time it takes to run the test suite
58 # massively. Before, it took around 1 minute on my computer, now it
59 # takes around 3 seconds
62 class LogicalTestCase(FHDLTestCase
):
64 def __init__(self
, name
):
65 super().__init
__(name
)
68 def run_tst_program(self
, prog
, initial_regs
=None, initial_sprs
=None):
69 tc
= TestCase(prog
, self
.test_name
, initial_regs
, initial_sprs
)
70 self
.test_data
.append(tc
)
73 insns
= ["and", "or", "xor"]
75 choice
= random
.choice(insns
)
76 lst
= [f
"{choice} 3, 1, 2"]
77 initial_regs
= [0] * 32
78 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
79 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
80 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
82 def test_rand_imm_logical(self
):
83 insns
= ["andi.", "andis.", "ori", "oris", "xori", "xoris"]
85 choice
= random
.choice(insns
)
86 imm
= random
.randint(0, (1 << 16)-1)
87 lst
= [f
"{choice} 3, 1, {imm}"]
89 initial_regs
= [0] * 32
90 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
91 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
94 insns
= ["cntlzd", "cnttzd", "cntlzw", "cnttzw"]
96 choice
= random
.choice(insns
)
97 lst
= [f
"{choice} 3, 1"]
99 initial_regs
= [0] * 32
100 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
101 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
103 def test_parity(self
):
104 insns
= ["prtyw", "prtyd"]
106 choice
= random
.choice(insns
)
107 lst
= [f
"{choice} 3, 1"]
109 initial_regs
= [0] * 32
110 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
111 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
113 def test_popcnt(self
):
114 insns
= ["popcntb", "popcntw", "popcntd"]
116 choice
= random
.choice(insns
)
117 lst
= [f
"{choice} 3, 1"]
119 initial_regs
= [0] * 32
120 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
121 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
123 def test_popcnt_edge(self
):
124 insns
= ["popcntb", "popcntw", "popcntd"]
126 lst
= [f
"{choice} 3, 1"]
127 initial_regs
= [0] * 32
129 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
132 lst
= ["cmpb 3, 1, 2"]
133 initial_regs
= [0] * 32
134 initial_regs
[1] = 0xdeadbeefcafec0de
135 initial_regs
[2] = 0xd0adb0000afec1de
136 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
138 def test_bpermd(self
):
139 lst
= ["bpermd 3, 1, 2"]
141 initial_regs
= [0] * 32
142 initial_regs
[1] = 1<<random
.randint(0,63)
143 initial_regs
[2] = 0xdeadbeefcafec0de
144 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
146 def test_ilang(self
):
147 pspec
= LogicalPipeSpec(id_wid
=2)
148 alu
= LogicalBasePipe(pspec
)
149 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
150 with
open("logical_pipeline.il", "w") as f
:
154 class TestRunner(FHDLTestCase
):
155 def __init__(self
, test_data
):
156 super().__init
__("run_all")
157 self
.test_data
= test_data
162 instruction
= Signal(32)
164 pdecode
= create_pdecode()
166 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
168 pspec
= LogicalPipeSpec(id_wid
=2)
169 m
.submodules
.alu
= alu
= LogicalBasePipe(pspec
)
171 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
172 comb
+= alu
.p
.valid_i
.eq(1)
173 comb
+= alu
.n
.ready_i
.eq(1)
174 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
180 for test
in self
.test_data
:
182 program
= test
.program
183 self
.subTest(test
.name
)
184 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
187 gen
= program
.generate_instructions()
188 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
190 index
= simulator
.pc
.CIA
.value
//4
191 while index
< len(instructions
):
192 ins
, code
= instructions
[index
]
194 print("0x{:X}".format(ins
& 0xffffffff))
197 # ask the decoder to decode this binary data (endian'd)
198 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
199 yield instruction
.eq(ins
) # raw binary instr.
201 fn_unit
= yield pdecode2
.e
.do
.fn_unit
202 self
.assertEqual(fn_unit
, Function
.LOGICAL
.value
, code
)
203 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
205 opname
= code
.split(' ')[0]
206 yield from simulator
.call(opname
)
207 index
= simulator
.pc
.CIA
.value
//4
209 vld
= yield alu
.n
.valid_o
212 vld
= yield alu
.n
.valid_o
215 yield from self
.check_alu_outputs(alu
, pdecode2
,
218 sim
.add_sync_process(process
)
219 with sim
.write_vcd("logical_simulator.vcd", "logical_simulator.gtkw",
223 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
225 rc
= yield dec2
.e
.do
.rc
.data
226 cridx_ok
= yield dec2
.e
.write_cr
.ok
227 cridx
= yield dec2
.e
.write_cr
.data
229 print ("check extra output", repr(code
), cridx_ok
, cridx
)
231 self
.assertEqual(cridx
, 0, code
)
236 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
237 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
239 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
240 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
242 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
243 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
246 if __name__
== "__main__":
247 unittest
.main(exit
=False)
248 suite
= unittest
.TestSuite()
249 suite
.addTest(TestRunner(LogicalTestCase
.test_data
))
251 runner
= unittest
.TextTestRunner()