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 def get_cu_inputs(dec2
, sim
):
60 """naming (res) must conform to BranchFunctionUnit input regspec
65 res
['cia'] = sim
.pc
.CIA
.value
67 fast1_en
= yield dec2
.e
.read_fast1
.ok
69 fast1_sel
= yield dec2
.e
.read_fast1
.data
70 spr1_sel
= fast_reg_to_spr(fast1_sel
)
71 spr1_data
= sim
.spr
[spr1_sel
].value
72 res
['spr1'] = spr1_data
74 fast2_en
= yield dec2
.e
.read_fast2
.ok
76 fast2_sel
= yield dec2
.e
.read_fast2
.data
77 spr2_sel
= fast_reg_to_spr(fast2_sel
)
78 spr2_data
= sim
.spr
[spr2_sel
].value
79 res
['spr2'] = spr2_data
81 cr_en
= yield dec2
.e
.read_cr1
.ok
83 cr_sel
= yield dec2
.e
.read_cr1
.data
84 cr
= sim
.crl
[cr_sel
].get_range().value
87 print ("get inputs", res
)
91 class BranchTestCase(FHDLTestCase
):
92 def __init__(self
, name
):
93 super().__init
__(name
)
95 def run_tst_program(self
, prog
, initial_regs
=[0] * 32,
96 initial_sprs
={}, initial_cr
=0):
97 tc
= TestCase(prog
, initial_regs
, initial_sprs
, initial_cr
,
101 def test_unconditional(self
):
102 choices
= ["b", "ba", "bl", "bla"]
104 choice
= random
.choice(choices
)
105 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
106 lst
= [f
"{choice} {imm}"]
107 initial_regs
= [0] * 32
108 self
.run_tst_program(Program(lst
), initial_regs
)
110 def test_bc_cr(self
):
112 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
113 bo
= random
.choice([0b01100, 0b00100, 0b10100])
114 bi
= random
.randrange(0, 31)
115 cr
= random
.randrange(0, (1<<32)-1)
116 lst
= [f
"bc {bo}, {bi}, {bc}"]
117 initial_regs
= [0] * 32
118 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
120 def test_bc_ctr(self
):
122 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
123 bo
= random
.choice([0, 2, 8, 10, 16, 18])
124 bi
= random
.randrange(0, 31)
125 cr
= random
.randrange(0, (1<<32)-1)
126 ctr
= random
.randint(0, (1<<32)-1)
127 lst
= [f
"bc {bo}, {bi}, {bc}"]
128 initial_sprs
={9: SelectableInt(ctr
, 64)}
129 self
.run_tst_program(Program(lst
),
130 initial_sprs
=initial_sprs
,
133 def test_bc_reg(self
):
134 # XXX: bcctr and bcctrl time out (irony: they're counters)
135 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
138 bh
= random
.randrange(0, 3)
139 bo
= random
.choice([4, 12])
140 bi
= random
.randrange(0, 31)
141 cr
= random
.randrange(0, (1<<32)-1)
142 ctr
= random
.randint(0, (1<<32)-1)
143 lr
= random
.randint(0, (1<<64)-1) & ~
3
144 tar
= random
.randint(0, (1<<64)-1) & ~
3
145 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
146 initial_sprs
={9: SelectableInt(ctr
, 64),
147 8: SelectableInt(lr
, 64),
148 815: SelectableInt(tar
, 64)}
149 self
.run_tst_program(Program(lst
),
150 initial_sprs
=initial_sprs
,
155 def test_ilang(self
):
156 pspec
= BranchPipeSpec(id_wid
=2)
157 alu
= BranchBasePipe(pspec
)
158 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
159 with
open("branch_pipeline.il", "w") as f
:
163 class TestRunner(FHDLTestCase
):
164 def __init__(self
, test_data
):
165 super().__init
__("run_all")
166 self
.test_data
= test_data
171 instruction
= Signal(32)
173 pdecode
= create_pdecode()
175 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
177 pspec
= BranchPipeSpec(id_wid
=2)
178 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
180 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
181 comb
+= branch
.p
.valid_i
.eq(1)
182 comb
+= branch
.n
.ready_i
.eq(1)
183 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
188 for test
in self
.test_data
:
190 program
= test
.program
191 self
.subTest(test
.name
)
192 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
194 simulator
.set_pc(initial_cia
)
195 gen
= program
.generate_instructions()
196 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
198 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
199 while index
< len(instructions
) and index
>= 0:
201 ins
, code
= instructions
[index
]
203 print("0x{:X}".format(ins
& 0xffffffff))
206 # ask the decoder to decode this binary data (endian'd)
207 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
208 yield instruction
.eq(ins
) # raw binary instr.
209 yield branch
.p
.data_i
.cia
.eq(simulator
.pc
.CIA
.value
)
210 # note, here, the op will need further decoding in order
211 # to set the correct SPRs on SPR1/2/3. op_bc* require
212 # spr1 to be set to CTR, op_bctar require spr2 to be
213 # set to TAR, op_bclr* require spr2 to be set to LR.
214 # if op_sc*, op_rf* and op_hrfid are to be added here
215 # then additional op-decoding is required, accordingly
217 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
218 fn_unit
= yield pdecode2
.e
.fn_unit
219 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
222 opname
= code
.split(' ')[0]
223 prev_nia
= simulator
.pc
.NIA
.value
224 yield from simulator
.call(opname
)
225 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
227 yield from self
.assert_outputs(branch
, pdecode2
,
228 simulator
, prev_nia
, code
)
230 sim
.add_sync_process(process
)
231 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
235 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
236 branch_taken
= yield branch
.n
.data_o
.nia
.ok
237 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
238 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
240 branch_addr
= yield branch
.n
.data_o
.nia
.data
241 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
242 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
244 # TODO: check write_fast1 as well (should contain CTR)
246 # TODO: this should be checking write_fast2
248 branch_lk
= yield branch
.n
.data_o
.lr
.ok
249 self
.assertEqual(lk
, branch_lk
, code
)
251 branch_lr
= yield branch
.n
.data_o
.lr
.data
252 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
254 def set_inputs(self
, branch
, dec2
, sim
):
255 print(f
"cr0: {sim.crl[0].get_range()}")
257 inp
= yield from get_cu_inputs(dec2
, sim
)
260 yield branch
.p
.data_i
.spr1
.eq(inp
['spr1'])
262 yield branch
.p
.data_i
.spr2
.eq(inp
['spr2'])
264 yield branch
.p
.data_i
.cr
.eq(inp
['cr_a'])
267 if __name__
== "__main__":
268 unittest
.main(exit
=False)
269 suite
= unittest
.TestSuite()
270 suite
.addTest(TestRunner(test_data
))
272 runner
= unittest
.TextTestRunner()