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 TestAccumulatorBase
, 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(TestAccumulatorBase
):
65 insns
= ["and", "or", "xor"]
67 choice
= random
.choice(insns
)
68 lst
= [f
"{choice} 3, 1, 2"]
69 initial_regs
= [0] * 32
70 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
71 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
72 self
.add_case(Program(lst
, bigendian
), initial_regs
)
74 def case_rand_imm_logical(self
):
75 insns
= ["andi.", "andis.", "ori", "oris", "xori", "xoris"]
77 choice
= random
.choice(insns
)
78 imm
= random
.randint(0, (1 << 16)-1)
79 lst
= [f
"{choice} 3, 1, {imm}"]
81 initial_regs
= [0] * 32
82 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
83 self
.add_case(Program(lst
, bigendian
), initial_regs
)
86 insns
= ["cntlzd", "cnttzd", "cntlzw", "cnttzw"]
88 choice
= random
.choice(insns
)
89 lst
= [f
"{choice} 3, 1"]
91 initial_regs
= [0] * 32
92 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
93 self
.add_case(Program(lst
, bigendian
), initial_regs
)
95 def case_parity(self
):
96 insns
= ["prtyw", "prtyd"]
98 choice
= random
.choice(insns
)
99 lst
= [f
"{choice} 3, 1"]
101 initial_regs
= [0] * 32
102 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
103 self
.add_case(Program(lst
, bigendian
), initial_regs
)
105 def case_popcnt(self
):
106 insns
= ["popcntb", "popcntw", "popcntd"]
108 choice
= random
.choice(insns
)
109 lst
= [f
"{choice} 3, 1"]
111 initial_regs
= [0] * 32
112 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
113 self
.add_case(Program(lst
, bigendian
), initial_regs
)
115 def case_popcnt_edge(self
):
116 insns
= ["popcntb", "popcntw", "popcntd"]
118 lst
= [f
"{choice} 3, 1"]
119 initial_regs
= [0] * 32
121 self
.add_case(Program(lst
, bigendian
), initial_regs
)
124 lst
= ["cmpb 3, 1, 2"]
125 initial_regs
= [0] * 32
126 initial_regs
[1] = 0xdeadbeefcafec0de
127 initial_regs
[2] = 0xd0adb0000afec1de
128 self
.add_case(Program(lst
, bigendian
), initial_regs
)
130 def case_bpermd(self
):
131 lst
= ["bpermd 3, 1, 2"]
133 initial_regs
= [0] * 32
134 initial_regs
[1] = 1 << random
.randint(0, 63)
135 initial_regs
[2] = 0xdeadbeefcafec0de
136 self
.add_case(Program(lst
, bigendian
), initial_regs
)
138 def case_ilang(self
):
139 pspec
= LogicalPipeSpec(id_wid
=2)
140 alu
= LogicalBasePipe(pspec
)
141 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
142 with
open("logical_pipeline.il", "w") as f
:
146 class TestRunner(FHDLTestCase
):
147 def __init__(self
, test_data
):
148 super().__init
__("run_all")
149 self
.test_data
= test_data
154 instruction
= Signal(32)
156 pdecode
= create_pdecode()
158 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
160 pspec
= LogicalPipeSpec(id_wid
=2)
161 m
.submodules
.alu
= alu
= LogicalBasePipe(pspec
)
163 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
164 comb
+= alu
.n
.ready_i
.eq(1)
165 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
171 for test
in self
.test_data
:
173 program
= test
.program
174 self
.subTest(test
.name
)
175 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
178 gen
= program
.generate_instructions()
179 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
181 index
= simulator
.pc
.CIA
.value
//4
182 while index
< len(instructions
):
183 ins
, code
= instructions
[index
]
185 print("0x{:X}".format(ins
& 0xffffffff))
188 # ask the decoder to decode this binary data (endian'd)
189 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
190 yield instruction
.eq(ins
) # raw binary instr.
192 fn_unit
= yield pdecode2
.e
.do
.fn_unit
193 self
.assertEqual(fn_unit
, Function
.LOGICAL
.value
, code
)
194 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
196 # set valid for one cycle, propagate through pipeline...
197 yield alu
.p
.valid_i
.eq(1)
199 yield alu
.p
.valid_i
.eq(0)
201 opname
= code
.split(' ')[0]
202 yield from simulator
.call(opname
)
203 index
= simulator
.pc
.CIA
.value
//4
205 vld
= yield alu
.n
.valid_o
208 vld
= yield alu
.n
.valid_o
211 yield from self
.check_alu_outputs(alu
, pdecode2
,
216 sim
.add_sync_process(process
)
217 with sim
.write_vcd("logical_simulator.vcd", "logical_simulator.gtkw",
221 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
223 rc
= yield dec2
.e
.do
.rc
.data
224 cridx_ok
= yield dec2
.e
.write_cr
.ok
225 cridx
= yield dec2
.e
.write_cr
.data
227 print("check extra output", repr(code
), cridx_ok
, cridx
)
229 self
.assertEqual(cridx
, 0, code
)
234 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
235 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
237 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
238 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
240 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
241 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
244 if __name__
== "__main__":
245 unittest
.main(exit
=False)
246 suite
= unittest
.TestSuite()
247 suite
.addTest(TestRunner(LogicalTestCase().test_data
))
249 runner
= unittest
.TextTestRunner()