1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmigen
.cli
import rtlil
5 from soc
.decoder
.isa
.caller
import ISACaller
, special_sprs
6 from soc
.decoder
.power_decoder
import (create_pdecode
)
7 from soc
.decoder
.power_decoder2
import (PowerDecode2
)
8 from soc
.decoder
.power_enums
import (XER_bits
, Function
, MicrOp
)
9 from soc
.decoder
.selectable_int
import SelectableInt
10 from soc
.simulator
.program
import Program
11 from soc
.decoder
.isa
.all
import ISA
12 from soc
.regfile
.regfiles
import FastRegs
13 from soc
.config
.endian
import bigendian
15 from soc
.fu
.test
.common
import TestAccumulatorBase
, TestCase
, ALUHelpers
16 from soc
.fu
.branch
.pipeline
import BranchBasePipe
17 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
20 from soc
.regfile
.util
import fast_reg_to_spr
# HACK!
23 def get_rec_width(rec
):
25 # Setup random inputs for dut.op
32 # This test bench is a bit different than is usual. Initially when I
33 # was writing it, I had all of the tests call a function to create a
34 # device under test and simulator, initialize the dut, run the
35 # simulation for ~2 cycles, and assert that the dut output what it
36 # should have. However, this was really slow, since it needed to
37 # create and tear down the dut and simulator for every test case.
39 # Now, instead of doing that, every test case in ALUTestCase puts some
40 # data into the test_data list below, describing the instructions to
41 # be tested and the initial state. Once all the tests have been run,
42 # test_data gets passed to TestRunner which then sets up the DUT and
43 # simulator once, runs all the data through it, and asserts that the
44 # results match the pseudocode sim at every cycle.
46 # By doing this, I've reduced the time it takes to run the test suite
47 # massively. Before, it took around 1 minute on my computer, now it
48 # takes around 3 seconds
51 def get_cu_inputs(dec2
, sim
):
52 """naming (res) must conform to BranchFunctionUnit input regspec
57 #res['cia'] = sim.pc.CIA.value
59 yield from ALUHelpers
.get_sim_fast_spr1(res
, sim
, dec2
)
60 yield from ALUHelpers
.get_sim_fast_spr2(res
, sim
, dec2
)
61 yield from ALUHelpers
.get_sim_cr_a(res
, sim
, dec2
)
63 print("get inputs", res
)
67 class BranchTestCase(TestAccumulatorBase
):
69 def case_0_regression_unconditional(self
):
71 imm
= random
.randrange(-1 << 23, (1 << 23)-1) * 4
73 initial_regs
= [0] * 32
74 self
.add_case(Program(lst
, bigendian
), initial_regs
)
76 def case_unconditional(self
):
77 choices
= ["b", "ba", "bl", "bla"]
79 choice
= random
.choice(choices
)
80 imm
= random
.randrange(-1 << 23, (1 << 23)-1) * 4
81 lst
= [f
"{choice} {imm}"]
82 initial_regs
= [0] * 32
83 self
.add_case(Program(lst
, bigendian
), initial_regs
)
87 bc
= random
.randrange(-1 << 13, (1 << 13)-1) * 4
88 bo
= random
.choice([0b01100, 0b00100, 0b10100])
89 bi
= random
.randrange(0, 31)
90 cr
= random
.randrange(0, (1 << 32)-1)
91 lst
= [f
"bc {bo}, {bi}, {bc}"]
92 initial_regs
= [0] * 32
93 self
.add_case(Program(lst
, bigendian
), initial_cr
=cr
)
95 def case_bc_ctr(self
):
97 bc
= random
.randrange(-1 << 13, (1 << 13)-1) * 4
98 bo
= random
.choice([0, 2, 8, 10, 16, 18])
99 bi
= random
.randrange(0, 31)
100 cr
= random
.randrange(0, (1 << 32)-1)
101 ctr
= random
.randint(0, (1 << 32)-1)
102 lst
= [f
"bc {bo}, {bi}, {bc}"]
103 initial_sprs
= {9: SelectableInt(ctr
, 64)}
104 self
.add_case(Program(lst
, bigendian
),
105 initial_sprs
=initial_sprs
,
108 def case_bc_reg(self
):
109 # XXX: bcctr and bcctrl time out (irony: they're counters)
110 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
113 bh
= random
.randrange(0, 3)
114 bo
= random
.choice([4, 12])
115 bi
= random
.randrange(0, 31)
116 cr
= random
.randrange(0, (1 << 32)-1)
117 ctr
= random
.randint(0, (1 << 32)-1)
118 lr
= random
.randint(0, (1 << 64)-1) & ~
3
119 tar
= random
.randint(0, (1 << 64)-1) & ~
3
120 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
121 initial_sprs
= {9: SelectableInt(ctr
, 64),
122 8: SelectableInt(lr
, 64),
123 815: SelectableInt(tar
, 64)}
124 self
.add_case(Program(lst
, bigendian
),
125 initial_sprs
=initial_sprs
,
128 def case_ilang(self
):
129 pspec
= BranchPipeSpec(id_wid
=2)
130 alu
= BranchBasePipe(pspec
)
131 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
132 with
open("branch_pipeline.il", "w") as f
:
136 class TestRunner(unittest
.TestCase
):
137 def __init__(self
, test_data
):
138 super().__init
__("run_all")
139 self
.test_data
= test_data
144 instruction
= Signal(32)
146 pdecode
= create_pdecode()
148 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
150 pspec
= BranchPipeSpec(id_wid
=2)
151 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
153 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
154 comb
+= branch
.p
.valid_i
.eq(1)
155 comb
+= branch
.n
.ready_i
.eq(1)
156 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
162 for test
in self
.test_data
:
164 program
= test
.program
165 self
.subTest(test
.name
)
166 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
170 simulator
.set_pc(initial_cia
)
171 gen
= program
.generate_instructions()
172 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
174 pc
= simulator
.pc
.CIA
.value
175 msr
= simulator
.msr
.value
176 index
= (pc
- initial_cia
)//4
177 while index
< len(instructions
) and index
>= 0:
179 ins
, code
= instructions
[index
]
181 print("0x{:X}".format(ins
& 0xffffffff))
184 # ask the decoder to decode this binary data (endian'd)
185 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
186 yield pdecode2
.msr
.eq(msr
) # set MSR in pdecode2
187 yield pdecode2
.cia
.eq(pc
) # set PC in pdecode2
188 yield instruction
.eq(ins
) # raw binary instr.
189 # note, here, the op will need further decoding in order
190 # to set the correct SPRs on SPR1/2/3. op_bc* require
191 # spr1 to be set to CTR, op_bctar require spr2 to be
192 # set to TAR, op_bclr* require spr2 to be set to LR.
193 # if op_sc*, op_rf* and op_hrfid are to be added here
194 # then additional op-decoding is required, accordingly
196 lk
= yield pdecode2
.e
.do
.lk
198 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
199 fn_unit
= yield pdecode2
.e
.do
.fn_unit
200 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
203 opname
= code
.split(' ')[0]
204 prev_nia
= simulator
.pc
.NIA
.value
205 yield from simulator
.call(opname
)
206 pc
= simulator
.pc
.CIA
.value
207 msr
= simulator
.msr
.value
208 index
= (pc
- initial_cia
)//4
210 yield from self
.assert_outputs(branch
, pdecode2
,
211 simulator
, prev_nia
, code
)
213 sim
.add_sync_process(process
)
214 with sim
.write_vcd("branch_simulator.vcd"):
217 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
218 branch_taken
= yield branch
.n
.data_o
.nia
.ok
219 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
220 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
222 branch_addr
= yield branch
.n
.data_o
.nia
.data
223 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
224 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
226 # TODO: check write_fast1 as well (should contain CTR)
228 # TODO: this should be checking write_fast2
229 lk
= yield dec2
.e
.do
.lk
230 branch_lk
= yield branch
.n
.data_o
.lr
.ok
231 self
.assertEqual(lk
, branch_lk
, code
)
233 branch_lr
= yield branch
.n
.data_o
.lr
.data
234 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
236 def set_inputs(self
, branch
, dec2
, sim
):
237 print(f
"cr0: {sim.crl[0].get_range()}")
239 inp
= yield from get_cu_inputs(dec2
, sim
)
241 yield from ALUHelpers
.set_fast_spr1(branch
, dec2
, inp
)
242 yield from ALUHelpers
.set_fast_spr2(branch
, dec2
, inp
)
243 yield from ALUHelpers
.set_cr_a(branch
, dec2
, inp
)
246 if __name__
== "__main__":
247 unittest
.main(exit
=False)
248 suite
= unittest
.TestSuite()
249 suite
.addTest(TestRunner(BranchTestCase().test_data
))
251 runner
= unittest
.TextTestRunner()