1 from nmigen
import Module
, Signal
3 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
4 # Also, check out the cxxsim nmigen branch, and latest yosys from git
5 from nmutil
.sim_tmp_alternative
import Simulator
, Settle
7 from nmutil
.formaltest
import FHDLTestCase
8 from nmigen
.cli
import rtlil
10 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
11 from soc
.decoder
.power_decoder
import (create_pdecode
)
12 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
13 from soc
.decoder
.power_enums
import (XER_bits
, Function
)
14 from soc
.decoder
.selectable_int
import SelectableInt
15 from soc
.simulator
.program
import Program
16 from soc
.decoder
.isa
.all
import ISA
17 from soc
.config
.endian
import bigendian
20 from soc
.fu
.test
.common
import TestAccumulatorBase
, TestCase
, ALUHelpers
21 from soc
.fu
.logical
.pipeline
import LogicalBasePipe
22 from soc
.fu
.logical
.pipe_data
import LogicalPipeSpec
26 def get_cu_inputs(dec2
, sim
):
27 """naming (res) must conform to LogicalFunctionUnit input regspec
31 yield from ALUHelpers
.get_sim_int_ra(res
, sim
, dec2
) # RA
32 yield from ALUHelpers
.get_sim_int_rb(res
, sim
, dec2
) # RB
33 yield from ALUHelpers
.get_sim_xer_so(res
, sim
, dec2
) # XER.so
35 print("alu get_cu_inputs", res
)
40 def set_alu_inputs(alu
, dec2
, sim
):
41 # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
42 # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
43 # and place it into data_i.b
45 inp
= yield from get_cu_inputs(dec2
, sim
)
46 print ("set alu inputs", inp
)
47 yield from ALUHelpers
.set_int_ra(alu
, dec2
, inp
)
48 yield from ALUHelpers
.set_int_rb(alu
, dec2
, inp
)
49 yield from ALUHelpers
.set_xer_so(alu
, dec2
, inp
)
52 # This test bench is a bit different than is usual. Initially when I
53 # was writing it, I had all of the tests call a function to create a
54 # device under test and simulator, initialize the dut, run the
55 # simulation for ~2 cycles, and assert that the dut output what it
56 # should have. However, this was really slow, since it needed to
57 # create and tear down the dut and simulator for every test case.
59 # Now, instead of doing that, every test case in ALUTestCase puts some
60 # data into the test_data list below, describing the instructions to
61 # be tested and the initial state. Once all the tests have been run,
62 # test_data gets passed to TestRunner which then sets up the DUT and
63 # simulator once, runs all the data through it, and asserts that the
64 # results match the pseudocode sim at every cycle.
66 # By doing this, I've reduced the time it takes to run the test suite
67 # massively. Before, it took around 1 minute on my computer, now it
68 # takes around 3 seconds
71 class LogicalTestCase(TestAccumulatorBase
):
73 def case_complement(self
):
74 insns
= ["andc", "orc", "nand", "nor"]
76 choice
= random
.choice(insns
)
77 lst
= [f
"{choice} 3, 1, 2"]
78 initial_regs
= [0] * 32
79 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
80 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
81 self
.add_case(Program(lst
, bigendian
), initial_regs
)
84 insns
= ["and", "or", "xor", "eqv"]
86 choice
= random
.choice(insns
)
87 lst
= [f
"{choice} 3, 1, 2"]
88 initial_regs
= [0] * 32
89 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
90 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
91 self
.add_case(Program(lst
, bigendian
), initial_regs
)
94 insns
= ["and.", "or.", "xor.", "eqv.", "andc.",
95 "orc.", "nand.", "nor."]
96 for XER
in [0, 0xe00c0000]:
98 choice
= random
.choice(insns
)
99 lst
= [f
"{choice} 3, 1, 2"]
100 initial_regs
= [0] * 32
101 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
102 initial_regs
[2] = random
.randint(0, (1 << 64)-1)
103 self
.add_case(Program(lst
, bigendian
), initial_regs
,
104 initial_sprs
= {'XER': XER
})
106 def case_rand_imm_so(self
):
107 insns
= ["andi.", "andis."]
109 choice
= random
.choice(insns
)
110 imm
= random
.randint(0, (1 << 16)-1)
111 lst
= [f
"{choice} 3, 1, {imm}"]
113 initial_regs
= [0] * 32
114 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
115 initial_sprs
= {'XER': 0xe00c0000}
117 self
.add_case(Program(lst
, bigendian
), initial_regs
,
118 initial_sprs
=initial_sprs
)
120 def case_rand_imm_logical(self
):
121 insns
= ["andi.", "andis.", "ori", "oris", "xori", "xoris"]
123 choice
= random
.choice(insns
)
124 imm
= random
.randint(0, (1 << 16)-1)
125 lst
= [f
"{choice} 3, 1, {imm}"]
127 initial_regs
= [0] * 32
128 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
129 self
.add_case(Program(lst
, bigendian
), initial_regs
)
132 insns
= ["cntlzd", "cnttzd", "cntlzw", "cnttzw"]
134 choice
= random
.choice(insns
)
135 lst
= [f
"{choice} 3, 1"]
137 initial_regs
= [0] * 32
138 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
139 self
.add_case(Program(lst
, bigendian
), initial_regs
)
141 def case_parity(self
):
142 insns
= ["prtyw", "prtyd"]
144 choice
= random
.choice(insns
)
145 lst
= [f
"{choice} 3, 1"]
147 initial_regs
= [0] * 32
148 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
149 self
.add_case(Program(lst
, bigendian
), initial_regs
)
151 def case_popcnt(self
):
152 insns
= ["popcntb", "popcntw", "popcntd"]
154 choice
= random
.choice(insns
)
155 lst
= [f
"{choice} 3, 1"]
157 initial_regs
= [0] * 32
158 initial_regs
[1] = random
.randint(0, (1 << 64)-1)
159 self
.add_case(Program(lst
, bigendian
), initial_regs
)
161 def case_popcnt_edge(self
):
162 insns
= ["popcntb", "popcntw", "popcntd"]
164 lst
= [f
"{choice} 3, 1"]
165 initial_regs
= [0] * 32
167 self
.add_case(Program(lst
, bigendian
), initial_regs
)
170 lst
= ["cmpb 3, 1, 2"]
171 initial_regs
= [0] * 32
172 initial_regs
[1] = 0xdeadbeefcafec0de
173 initial_regs
[2] = 0xd0adb0000afec1de
174 self
.add_case(Program(lst
, bigendian
), initial_regs
)
176 def case_bpermd(self
):
177 lst
= ["bpermd 3, 1, 2"]
179 initial_regs
= [0] * 32
180 initial_regs
[1] = 1 << random
.randint(0, 63)
181 initial_regs
[2] = 0xdeadbeefcafec0de
182 self
.add_case(Program(lst
, bigendian
), initial_regs
)
184 def case_ilang(self
):
185 pspec
= LogicalPipeSpec(id_wid
=2)
186 alu
= LogicalBasePipe(pspec
)
187 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
188 with
open("logical_pipeline.il", "w") as f
:
192 class TestRunner(FHDLTestCase
):
193 def __init__(self
, test_data
):
194 super().__init
__("run_all")
195 self
.test_data
= test_data
197 def execute(self
, alu
,instruction
, pdecode2
, test
):
199 program
= test
.program
200 self
.subTest(test
.name
)
201 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
204 gen
= program
.generate_instructions()
205 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
207 index
= simulator
.pc
.CIA
.value
//4
208 while index
< len(instructions
):
209 ins
, code
= instructions
[index
]
211 print("0x{:X}".format(ins
& 0xffffffff))
214 # ask the decoder to decode this binary data (endian'd)
215 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
216 yield instruction
.eq(ins
) # raw binary instr.
218 fn_unit
= yield pdecode2
.e
.do
.fn_unit
219 self
.assertEqual(fn_unit
, Function
.LOGICAL
.value
, code
)
220 yield from set_alu_inputs(alu
, pdecode2
, simulator
)
222 # set valid for one cycle, propagate through pipeline...
223 yield alu
.p
.valid_i
.eq(1)
225 yield alu
.p
.valid_i
.eq(0)
227 opname
= code
.split(' ')[0]
228 yield from simulator
.call(opname
)
229 index
= simulator
.pc
.CIA
.value
//4
231 vld
= yield alu
.n
.valid_o
234 vld
= yield alu
.n
.valid_o
237 yield from self
.check_alu_outputs(alu
, pdecode2
,
244 instruction
= Signal(32)
246 pdecode
= create_pdecode()
248 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
250 pspec
= LogicalPipeSpec(id_wid
=2)
251 m
.submodules
.alu
= alu
= LogicalBasePipe(pspec
)
253 comb
+= alu
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.do
)
254 comb
+= alu
.n
.ready_i
.eq(1)
255 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
261 for test
in self
.test_data
:
263 program
= test
.program
264 with self
.subTest(test
.name
):
265 yield from self
.execute(alu
, instruction
, pdecode2
, test
)
267 sim
.add_sync_process(process
)
268 with sim
.write_vcd("logical_simulator.vcd", "logical_simulator.gtkw",
272 def check_alu_outputs(self
, alu
, dec2
, sim
, code
):
274 rc
= yield dec2
.e
.do
.rc
.data
275 cridx_ok
= yield dec2
.e
.write_cr
.ok
276 cridx
= yield dec2
.e
.write_cr
.data
278 print("check extra output", repr(code
), cridx_ok
, cridx
)
280 self
.assertEqual(cridx
, 0, code
)
285 yield from ALUHelpers
.get_cr_a(res
, alu
, dec2
)
286 yield from ALUHelpers
.get_int_o(res
, alu
, dec2
)
288 yield from ALUHelpers
.get_sim_int_o(sim_o
, sim
, dec2
)
289 yield from ALUHelpers
.get_wr_sim_cr_a(sim_o
, sim
, dec2
)
291 ALUHelpers
.check_cr_a(self
, res
, sim_o
, "CR%d %s" % (cridx
, code
))
292 ALUHelpers
.check_xer_ca(self
, res
, sim_o
, code
)
293 ALUHelpers
.check_int_o(self
, res
, sim_o
, code
)
296 if __name__
== "__main__":
297 unittest
.main(exit
=False)
298 suite
= unittest
.TestSuite()
299 suite
.addTest(TestRunner(LogicalTestCase().test_data
))
301 runner
= unittest
.TextTestRunner()