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
, MicrOp
)
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
.regfile
.regfiles
import FastRegs
14 from soc
.config
.endian
import bigendian
16 from soc
.fu
.test
.common
import TestCase
, ALUHelpers
17 from soc
.fu
.branch
.pipeline
import BranchBasePipe
18 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
21 from soc
.regfile
.util
import fast_reg_to_spr
# HACK!
24 def get_rec_width(rec
):
26 # Setup random inputs for dut.op
33 # This test bench is a bit different than is usual. Initially when I
34 # was writing it, I had all of the tests call a function to create a
35 # device under test and simulator, initialize the dut, run the
36 # simulation for ~2 cycles, and assert that the dut output what it
37 # should have. However, this was really slow, since it needed to
38 # create and tear down the dut and simulator for every test case.
40 # Now, instead of doing that, every test case in ALUTestCase puts some
41 # data into the test_data list below, describing the instructions to
42 # be tested and the initial state. Once all the tests have been run,
43 # test_data gets passed to TestRunner which then sets up the DUT and
44 # simulator once, runs all the data through it, and asserts that the
45 # results match the pseudocode sim at every cycle.
47 # By doing this, I've reduced the time it takes to run the test suite
48 # massively. Before, it took around 1 minute on my computer, now it
49 # takes around 3 seconds
52 def get_cu_inputs(dec2
, sim
):
53 """naming (res) must conform to BranchFunctionUnit input regspec
58 #res['cia'] = sim.pc.CIA.value
60 yield from ALUHelpers
.get_sim_fast_spr1(res
, sim
, dec2
)
61 yield from ALUHelpers
.get_sim_fast_spr2(res
, sim
, dec2
)
62 yield from ALUHelpers
.get_sim_cr_a(res
, sim
, dec2
)
64 print("get inputs", res
)
68 class BranchTestCase(FHDLTestCase
):
71 def __init__(self
, name
):
72 super().__init
__(name
)
75 def run_tst_program(self
, prog
, initial_regs
=None,
76 initial_sprs
=None, initial_cr
=0):
77 tc
= TestCase(prog
, self
.test_name
,
78 initial_regs
, initial_sprs
, initial_cr
)
79 self
.test_data
.append(tc
)
81 def test_0_regression_unconditional(self
):
83 imm
= random
.randrange(-1 << 23, (1 << 23)-1) * 4
85 initial_regs
= [0] * 32
86 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
88 def test_unconditional(self
):
89 choices
= ["b", "ba", "bl", "bla"]
91 choice
= random
.choice(choices
)
92 imm
= random
.randrange(-1 << 23, (1 << 23)-1) * 4
93 lst
= [f
"{choice} {imm}"]
94 initial_regs
= [0] * 32
95 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
99 bc
= random
.randrange(-1 << 13, (1 << 13)-1) * 4
100 bo
= random
.choice([0b01100, 0b00100, 0b10100])
101 bi
= random
.randrange(0, 31)
102 cr
= random
.randrange(0, (1 << 32)-1)
103 lst
= [f
"bc {bo}, {bi}, {bc}"]
104 initial_regs
= [0] * 32
105 self
.run_tst_program(Program(lst
, bigendian
), initial_cr
=cr
)
107 def test_bc_ctr(self
):
109 bc
= random
.randrange(-1 << 13, (1 << 13)-1) * 4
110 bo
= random
.choice([0, 2, 8, 10, 16, 18])
111 bi
= random
.randrange(0, 31)
112 cr
= random
.randrange(0, (1 << 32)-1)
113 ctr
= random
.randint(0, (1 << 32)-1)
114 lst
= [f
"bc {bo}, {bi}, {bc}"]
115 initial_sprs
= {9: SelectableInt(ctr
, 64)}
116 self
.run_tst_program(Program(lst
, bigendian
),
117 initial_sprs
=initial_sprs
,
120 def test_bc_reg(self
):
121 # XXX: bcctr and bcctrl time out (irony: they're counters)
122 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
125 bh
= random
.randrange(0, 3)
126 bo
= random
.choice([4, 12])
127 bi
= random
.randrange(0, 31)
128 cr
= random
.randrange(0, (1 << 32)-1)
129 ctr
= random
.randint(0, (1 << 32)-1)
130 lr
= random
.randint(0, (1 << 64)-1) & ~
3
131 tar
= random
.randint(0, (1 << 64)-1) & ~
3
132 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
133 initial_sprs
= {9: SelectableInt(ctr
, 64),
134 8: SelectableInt(lr
, 64),
135 815: SelectableInt(tar
, 64)}
136 self
.run_tst_program(Program(lst
, bigendian
),
137 initial_sprs
=initial_sprs
,
140 def test_ilang(self
):
141 pspec
= BranchPipeSpec(id_wid
=2)
142 alu
= BranchBasePipe(pspec
)
143 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
144 with
open("branch_pipeline.il", "w") as f
:
148 class TestRunner(FHDLTestCase
):
149 def __init__(self
, test_data
):
150 super().__init
__("run_all")
151 self
.test_data
= test_data
156 instruction
= Signal(32)
158 pdecode
= create_pdecode()
160 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
162 pspec
= BranchPipeSpec(id_wid
=2)
163 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
165 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
166 comb
+= branch
.p
.valid_i
.eq(1)
167 comb
+= branch
.n
.ready_i
.eq(1)
168 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
174 for test
in self
.test_data
:
176 program
= test
.program
177 self
.subTest(test
.name
)
178 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
182 simulator
.set_pc(initial_cia
)
183 gen
= program
.generate_instructions()
184 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
186 pc
= simulator
.pc
.CIA
.value
187 msr
= simulator
.msr
.value
188 index
= (pc
- initial_cia
)//4
189 while index
< len(instructions
) and index
>= 0:
191 ins
, code
= instructions
[index
]
193 print("0x{:X}".format(ins
& 0xffffffff))
196 # ask the decoder to decode this binary data (endian'd)
197 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
198 yield pdecode2
.msr
.eq(msr
) # set MSR in pdecode2
199 yield pdecode2
.cia
.eq(pc
) # set PC in pdecode2
200 yield instruction
.eq(ins
) # raw binary instr.
201 # note, here, the op will need further decoding in order
202 # to set the correct SPRs on SPR1/2/3. op_bc* require
203 # spr1 to be set to CTR, op_bctar require spr2 to be
204 # set to TAR, op_bclr* require spr2 to be set to LR.
205 # if op_sc*, op_rf* and op_hrfid are to be added here
206 # then additional op-decoding is required, accordingly
208 lk
= yield pdecode2
.e
.do
.lk
210 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
211 fn_unit
= yield pdecode2
.e
.do
.fn_unit
212 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
215 opname
= code
.split(' ')[0]
216 prev_nia
= simulator
.pc
.NIA
.value
217 yield from simulator
.call(opname
)
218 pc
= simulator
.pc
.CIA
.value
219 msr
= simulator
.msr
.value
220 index
= (pc
- initial_cia
)//4
222 yield from self
.assert_outputs(branch
, pdecode2
,
223 simulator
, prev_nia
, code
)
225 sim
.add_sync_process(process
)
226 with sim
.write_vcd("branch_simulator.vcd"):
229 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
230 branch_taken
= yield branch
.n
.data_o
.nia
.ok
231 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
232 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
234 branch_addr
= yield branch
.n
.data_o
.nia
.data
235 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
236 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
238 # TODO: check write_fast1 as well (should contain CTR)
240 # TODO: this should be checking write_fast2
241 lk
= yield dec2
.e
.do
.lk
242 branch_lk
= yield branch
.n
.data_o
.lr
.ok
243 self
.assertEqual(lk
, branch_lk
, code
)
245 branch_lr
= yield branch
.n
.data_o
.lr
.data
246 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
248 def set_inputs(self
, branch
, dec2
, sim
):
249 print(f
"cr0: {sim.crl[0].get_range()}")
251 inp
= yield from get_cu_inputs(dec2
, sim
)
253 yield from ALUHelpers
.set_fast_spr1(branch
, dec2
, inp
)
254 yield from ALUHelpers
.set_fast_spr2(branch
, dec2
, inp
)
255 yield from ALUHelpers
.set_cr_a(branch
, dec2
, inp
)
258 if __name__
== "__main__":
259 unittest
.main(exit
=False)
260 suite
= unittest
.TestSuite()
261 suite
.addTest(TestRunner(BranchTestCase
.test_data
))
263 runner
= unittest
.TextTestRunner()