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
):
70 def __init__(self
, name
):
71 super().__init
__(name
)
74 def run_tst_program(self
, prog
, initial_regs
=None,
75 initial_sprs
=None, initial_cr
=0):
76 tc
= TestCase(prog
, self
.test_name
,
77 initial_regs
, initial_sprs
, initial_cr
)
78 self
.test_data
.append(tc
)
80 def test_0_regression_unconditional(self
):
82 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
84 initial_regs
= [0] * 32
85 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
87 def test_unconditional(self
):
88 choices
= ["b", "ba", "bl", "bla"]
90 choice
= random
.choice(choices
)
91 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
92 lst
= [f
"{choice} {imm}"]
93 initial_regs
= [0] * 32
94 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
98 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
99 bo
= random
.choice([0b01100, 0b00100, 0b10100])
100 bi
= random
.randrange(0, 31)
101 cr
= random
.randrange(0, (1<<32)-1)
102 lst
= [f
"bc {bo}, {bi}, {bc}"]
103 initial_regs
= [0] * 32
104 self
.run_tst_program(Program(lst
, bigendian
), initial_cr
=cr
)
106 def test_bc_ctr(self
):
108 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
109 bo
= random
.choice([0, 2, 8, 10, 16, 18])
110 bi
= random
.randrange(0, 31)
111 cr
= random
.randrange(0, (1<<32)-1)
112 ctr
= random
.randint(0, (1<<32)-1)
113 lst
= [f
"bc {bo}, {bi}, {bc}"]
114 initial_sprs
={9: SelectableInt(ctr
, 64)}
115 self
.run_tst_program(Program(lst
, bigendian
),
116 initial_sprs
=initial_sprs
,
119 def test_bc_reg(self
):
120 # XXX: bcctr and bcctrl time out (irony: they're counters)
121 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
124 bh
= random
.randrange(0, 3)
125 bo
= random
.choice([4, 12])
126 bi
= random
.randrange(0, 31)
127 cr
= random
.randrange(0, (1<<32)-1)
128 ctr
= random
.randint(0, (1<<32)-1)
129 lr
= random
.randint(0, (1<<64)-1) & ~
3
130 tar
= random
.randint(0, (1<<64)-1) & ~
3
131 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
132 initial_sprs
={9: SelectableInt(ctr
, 64),
133 8: SelectableInt(lr
, 64),
134 815: SelectableInt(tar
, 64)}
135 self
.run_tst_program(Program(lst
, bigendian
),
136 initial_sprs
=initial_sprs
,
139 def test_ilang(self
):
140 pspec
= BranchPipeSpec(id_wid
=2)
141 alu
= BranchBasePipe(pspec
)
142 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
143 with
open("branch_pipeline.il", "w") as f
:
147 class TestRunner(FHDLTestCase
):
148 def __init__(self
, test_data
):
149 super().__init
__("run_all")
150 self
.test_data
= test_data
155 instruction
= Signal(32)
157 pdecode
= create_pdecode()
159 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
161 pspec
= BranchPipeSpec(id_wid
=2)
162 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
164 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
165 comb
+= branch
.p
.valid_i
.eq(1)
166 comb
+= branch
.n
.ready_i
.eq(1)
167 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
172 for test
in self
.test_data
:
174 program
= test
.program
175 self
.subTest(test
.name
)
176 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
180 simulator
.set_pc(initial_cia
)
181 gen
= program
.generate_instructions()
182 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
184 pc
= simulator
.pc
.CIA
.value
185 msr
= simulator
.msr
.value
186 index
= (pc
- initial_cia
)//4
187 while index
< len(instructions
) and index
>= 0:
189 ins
, code
= instructions
[index
]
191 print("0x{:X}".format(ins
& 0xffffffff))
194 # ask the decoder to decode this binary data (endian'd)
195 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
196 yield pdecode2
.msr
.eq(msr
) # set MSR in pdecode2
197 yield pdecode2
.cia
.eq(pc
) # set PC in pdecode2
198 yield instruction
.eq(ins
) # raw binary instr.
199 # note, here, the op will need further decoding in order
200 # to set the correct SPRs on SPR1/2/3. op_bc* require
201 # spr1 to be set to CTR, op_bctar require spr2 to be
202 # set to TAR, op_bclr* require spr2 to be set to LR.
203 # if op_sc*, op_rf* and op_hrfid are to be added here
204 # then additional op-decoding is required, accordingly
206 lk
= yield pdecode2
.e
.do
.lk
208 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
209 fn_unit
= yield pdecode2
.e
.do
.fn_unit
210 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
213 opname
= code
.split(' ')[0]
214 prev_nia
= simulator
.pc
.NIA
.value
215 yield from simulator
.call(opname
)
216 pc
= simulator
.pc
.CIA
.value
217 msr
= simulator
.msr
.value
218 index
= (pc
- initial_cia
)//4
220 yield from self
.assert_outputs(branch
, pdecode2
,
221 simulator
, prev_nia
, code
)
223 sim
.add_sync_process(process
)
224 with sim
.write_vcd("branch_simulator.vcd"):
227 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
228 branch_taken
= yield branch
.n
.data_o
.nia
.ok
229 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
230 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
232 branch_addr
= yield branch
.n
.data_o
.nia
.data
233 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
234 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
236 # TODO: check write_fast1 as well (should contain CTR)
238 # TODO: this should be checking write_fast2
239 lk
= yield dec2
.e
.do
.lk
240 branch_lk
= yield branch
.n
.data_o
.lr
.ok
241 self
.assertEqual(lk
, branch_lk
, code
)
243 branch_lr
= yield branch
.n
.data_o
.lr
.data
244 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
246 def set_inputs(self
, branch
, dec2
, sim
):
247 print(f
"cr0: {sim.crl[0].get_range()}")
249 inp
= yield from get_cu_inputs(dec2
, sim
)
251 yield from ALUHelpers
.set_fast_spr1(branch
, dec2
, inp
)
252 yield from ALUHelpers
.set_fast_spr2(branch
, dec2
, inp
)
253 yield from ALUHelpers
.set_cr_a(branch
, dec2
, inp
)
256 if __name__
== "__main__":
257 unittest
.main(exit
=False)
258 suite
= unittest
.TestSuite()
259 suite
.addTest(TestRunner(BranchTestCase
.test_data
))
261 runner
= unittest
.TextTestRunner()