1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
import Simulator
, Delay
, Settle
3 from nmigen
.test
.utils
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
, InternalOp
)
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
15 from soc
.fu
.branch
.pipeline
import BranchBasePipe
16 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
19 from soc
.regfile
.util
import fast_reg_to_spr
# HACK!
22 def __init__(self
, program
, regs
, sprs
, cr
, name
):
23 self
.program
= program
29 def get_rec_width(rec
):
31 # Setup random inputs for dut.op
38 # This test bench is a bit different than is usual. Initially when I
39 # was writing it, I had all of the tests call a function to create a
40 # device under test and simulator, initialize the dut, run the
41 # simulation for ~2 cycles, and assert that the dut output what it
42 # should have. However, this was really slow, since it needed to
43 # create and tear down the dut and simulator for every test case.
45 # Now, instead of doing that, every test case in ALUTestCase puts some
46 # data into the test_data list below, describing the instructions to
47 # be tested and the initial state. Once all the tests have been run,
48 # test_data gets passed to TestRunner which then sets up the DUT and
49 # simulator once, runs all the data through it, and asserts that the
50 # results match the pseudocode sim at every cycle.
52 # By doing this, I've reduced the time it takes to run the test suite
53 # massively. Before, it took around 1 minute on my computer, now it
54 # takes around 3 seconds
59 class BranchTestCase(FHDLTestCase
):
60 def __init__(self
, name
):
61 super().__init
__(name
)
63 def run_tst_program(self
, prog
, initial_regs
=[0] * 32,
64 initial_sprs
={}, initial_cr
=0):
65 tc
= TestCase(prog
, initial_regs
, initial_sprs
, initial_cr
,
69 def test_unconditional(self
):
70 choices
= ["b", "ba", "bl", "bla"]
72 choice
= random
.choice(choices
)
73 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
74 lst
= [f
"{choice} {imm}"]
75 initial_regs
= [0] * 32
76 self
.run_tst_program(Program(lst
), initial_regs
)
80 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
81 bo
= random
.choice([0b01100, 0b00100, 0b10100])
82 bi
= random
.randrange(0, 31)
83 cr
= random
.randrange(0, (1<<32)-1)
84 lst
= [f
"bc {bo}, {bi}, {bc}"]
85 initial_regs
= [0] * 32
86 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
88 def test_bc_ctr(self
):
90 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
91 bo
= random
.choice([0, 2, 8, 10, 16, 18])
92 bi
= random
.randrange(0, 31)
93 cr
= random
.randrange(0, (1<<32)-1)
94 ctr
= random
.randint(0, (1<<32)-1)
95 lst
= [f
"bc {bo}, {bi}, {bc}"]
96 initial_sprs
={9: SelectableInt(ctr
, 64)}
97 self
.run_tst_program(Program(lst
),
98 initial_sprs
=initial_sprs
,
101 def test_bc_reg(self
):
102 # XXX: bcctr and bcctrl time out (irony: they're counters)
103 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
106 bh
= random
.randrange(0, 3)
107 bo
= random
.choice([4, 12])
108 bi
= random
.randrange(0, 31)
109 cr
= random
.randrange(0, (1<<32)-1)
110 ctr
= random
.randint(0, (1<<32)-1)
111 lr
= random
.randint(0, (1<<64)-1) & ~
3
112 tar
= random
.randint(0, (1<<64)-1) & ~
3
113 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
114 initial_sprs
={9: SelectableInt(ctr
, 64),
115 8: SelectableInt(lr
, 64),
116 815: SelectableInt(tar
, 64)}
117 self
.run_tst_program(Program(lst
),
118 initial_sprs
=initial_sprs
,
123 def test_ilang(self
):
124 pspec
= BranchPipeSpec(id_wid
=2)
125 alu
= BranchBasePipe(pspec
)
126 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
127 with
open("branch_pipeline.il", "w") as f
:
131 class TestRunner(FHDLTestCase
):
132 def __init__(self
, test_data
):
133 super().__init
__("run_all")
134 self
.test_data
= test_data
139 instruction
= Signal(32)
141 pdecode
= create_pdecode()
143 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
145 pspec
= BranchPipeSpec(id_wid
=2)
146 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
148 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
149 comb
+= branch
.p
.valid_i
.eq(1)
150 comb
+= branch
.n
.ready_i
.eq(1)
151 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
156 for test
in self
.test_data
:
158 program
= test
.program
159 self
.subTest(test
.name
)
160 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
162 simulator
.set_pc(initial_cia
)
163 gen
= program
.generate_instructions()
164 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
166 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
167 while index
< len(instructions
) and index
>= 0:
169 ins
, code
= instructions
[index
]
171 print("0x{:X}".format(ins
& 0xffffffff))
174 # ask the decoder to decode this binary data (endian'd)
175 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
176 yield instruction
.eq(ins
) # raw binary instr.
177 yield branch
.p
.data_i
.cia
.eq(simulator
.pc
.CIA
.value
)
178 # note, here, the op will need further decoding in order
179 # to set the correct SPRs on SPR1/2/3. op_bc* require
180 # spr1 to be set to CTR, op_bctar require spr2 to be
181 # set to TAR, op_bclr* require spr2 to be set to LR.
182 # if op_sc*, op_rf* and op_hrfid are to be added here
183 # then additional op-decoding is required, accordingly
185 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
186 fn_unit
= yield pdecode2
.e
.fn_unit
187 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
190 opname
= code
.split(' ')[0]
191 prev_nia
= simulator
.pc
.NIA
.value
192 yield from simulator
.call(opname
)
193 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
195 yield from self
.assert_outputs(branch
, pdecode2
,
196 simulator
, prev_nia
, code
)
198 sim
.add_sync_process(process
)
199 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
203 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
204 branch_taken
= yield branch
.n
.data_o
.nia
.ok
205 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
206 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
208 branch_addr
= yield branch
.n
.data_o
.nia
.data
209 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
210 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
212 # TODO: check write_fast1 as well (should contain CTR)
214 # TODO: this should be checking write_fast2
216 branch_lk
= yield branch
.n
.data_o
.lr
.ok
217 self
.assertEqual(lk
, branch_lk
, code
)
219 branch_lr
= yield branch
.n
.data_o
.lr
.data
220 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
222 def get_inputs(self
, dec2
, sim
):
223 """naming (res) must conform to BranchFunctionUnit input regspec
228 res
['cia'] = sim
.pc
.CIA
.value
231 cr1_en
= yield dec2
.e
.read_cr1
.ok
233 cr1_sel
= yield dec2
.e
.read_cr1
.data
234 res
['cr_a'] = sim
.crl
[cr1_sel
].get_range().value
237 spr_ok
= yield dec2
.e
.read_fast1
.ok
238 spr_num
= yield dec2
.e
.read_fast1
.data
240 spr_num
= fast_reg_to_spr(spr_num
)
242 res
['spr1'] = sim
.spr
[spr_dict
[spr_num
].SPR
].value
245 spr_ok
= yield dec2
.e
.read_fast2
.ok
246 spr_num
= yield dec2
.e
.read_fast2
.data
248 spr_num
= fast_reg_to_spr(spr_num
)
250 res
['spr2'] = sim
.spr
[spr_dict
[spr_num
].SPR
].value
252 print ("get inputs", res
)
255 def set_inputs(self
, branch
, dec2
, sim
):
256 yield branch
.p
.data_i
.spr1
.eq(sim
.spr
['CTR'].value
)
257 print(f
"cr0: {sim.crl[0].get_range()}")
259 # TODO: this needs to now be read_fast1.data and read_fast2.data
260 fast1_en
= yield dec2
.e
.read_fast1
.ok
262 fast1_sel
= yield dec2
.e
.read_fast1
.data
263 spr1_sel
= fast_reg_to_spr(fast1_sel
)
264 spr1_data
= sim
.spr
[spr1_sel
].value
265 yield branch
.p
.data_i
.spr1
.eq(spr1_data
)
267 fast2_en
= yield dec2
.e
.read_fast2
.ok
269 fast2_sel
= yield dec2
.e
.read_fast2
.data
270 spr2_sel
= fast_reg_to_spr(fast2_sel
)
271 spr2_data
= sim
.spr
[spr2_sel
].value
272 yield branch
.p
.data_i
.spr2
.eq(spr2_data
)
275 cr_en
= yield dec2
.e
.read_cr1
.ok
277 cr_sel
= yield dec2
.e
.read_cr1
.data
278 cr
= sim
.crl
[cr_sel
].get_range().value
279 yield branch
.p
.data_i
.cr
.eq(cr
)
280 full_cr
= sim
.cr
.get_range().value
281 print(f
"full cr: {full_cr:x}, sel: {cr_sel}, cr: {cr:x}")
284 if __name__
== "__main__":
285 unittest
.main(exit
=False)
286 suite
= unittest
.TestSuite()
287 suite
.addTest(TestRunner(test_data
))
289 runner
= unittest
.TextTestRunner()