947cff28d5292a0f94b8d8b75b9c9147bca41a38
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
, 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
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_unconditional(self
):
81 choices
= ["b", "ba", "bl", "bla"]
83 choice
= random
.choice(choices
)
84 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
85 lst
= [f
"{choice} {imm}"]
86 initial_regs
= [0] * 32
87 self
.run_tst_program(Program(lst
, bigendian
), initial_regs
)
91 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
92 bo
= random
.choice([0b01100, 0b00100, 0b10100])
93 bi
= random
.randrange(0, 31)
94 cr
= random
.randrange(0, (1<<32)-1)
95 lst
= [f
"bc {bo}, {bi}, {bc}"]
96 initial_regs
= [0] * 32
97 self
.run_tst_program(Program(lst
, bigendian
), initial_cr
=cr
)
99 def test_bc_ctr(self
):
101 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
102 bo
= random
.choice([0, 2, 8, 10, 16, 18])
103 bi
= random
.randrange(0, 31)
104 cr
= random
.randrange(0, (1<<32)-1)
105 ctr
= random
.randint(0, (1<<32)-1)
106 lst
= [f
"bc {bo}, {bi}, {bc}"]
107 initial_sprs
={9: SelectableInt(ctr
, 64)}
108 self
.run_tst_program(Program(lst
, bigendian
),
109 initial_sprs
=initial_sprs
,
112 def test_bc_reg(self
):
113 # XXX: bcctr and bcctrl time out (irony: they're counters)
114 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
117 bh
= random
.randrange(0, 3)
118 bo
= random
.choice([4, 12])
119 bi
= random
.randrange(0, 31)
120 cr
= random
.randrange(0, (1<<32)-1)
121 ctr
= random
.randint(0, (1<<32)-1)
122 lr
= random
.randint(0, (1<<64)-1) & ~
3
123 tar
= random
.randint(0, (1<<64)-1) & ~
3
124 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
125 initial_sprs
={9: SelectableInt(ctr
, 64),
126 8: SelectableInt(lr
, 64),
127 815: SelectableInt(tar
, 64)}
128 self
.run_tst_program(Program(lst
, bigendian
),
129 initial_sprs
=initial_sprs
,
132 def test_ilang(self
):
133 pspec
= BranchPipeSpec(id_wid
=2)
134 alu
= BranchBasePipe(pspec
)
135 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
136 with
open("branch_pipeline.il", "w") as f
:
140 class TestRunner(FHDLTestCase
):
141 def __init__(self
, test_data
):
142 super().__init
__("run_all")
143 self
.test_data
= test_data
148 instruction
= Signal(32)
150 pdecode
= create_pdecode()
152 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
154 pspec
= BranchPipeSpec(id_wid
=2)
155 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
157 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
158 comb
+= branch
.p
.valid_i
.eq(1)
159 comb
+= branch
.n
.ready_i
.eq(1)
160 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
165 for test
in self
.test_data
:
167 program
= test
.program
168 self
.subTest(test
.name
)
169 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
173 simulator
.set_pc(initial_cia
)
174 gen
= program
.generate_instructions()
175 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
177 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
178 while index
< len(instructions
) and index
>= 0:
180 ins
, code
= instructions
[index
]
182 print("0x{:X}".format(ins
& 0xffffffff))
185 # ask the decoder to decode this binary data (endian'd)
186 yield pdecode2
.dec
.bigendian
.eq(bigendian
) # little / big?
187 yield instruction
.eq(ins
) # raw binary instr.
188 # note, here, the op will need further decoding in order
189 # to set the correct SPRs on SPR1/2/3. op_bc* require
190 # spr1 to be set to CTR, op_bctar require spr2 to be
191 # set to TAR, op_bclr* require spr2 to be set to LR.
192 # if op_sc*, op_rf* and op_hrfid are to be added here
193 # then additional op-decoding is required, accordingly
195 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
196 fn_unit
= yield pdecode2
.e
.do
.fn_unit
197 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
200 opname
= code
.split(' ')[0]
201 prev_nia
= simulator
.pc
.NIA
.value
202 yield from simulator
.call(opname
)
203 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
205 yield from self
.assert_outputs(branch
, pdecode2
,
206 simulator
, prev_nia
, code
)
208 sim
.add_sync_process(process
)
209 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
213 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
214 branch_taken
= yield branch
.n
.data_o
.nia
.ok
215 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
216 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
218 branch_addr
= yield branch
.n
.data_o
.nia
.data
219 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
220 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
222 # TODO: check write_fast1 as well (should contain CTR)
224 # TODO: this should be checking write_fast2
225 lk
= yield dec2
.e
.do
.lk
226 branch_lk
= yield branch
.n
.data_o
.lr
.ok
227 self
.assertEqual(lk
, branch_lk
, code
)
229 branch_lr
= yield branch
.n
.data_o
.lr
.data
230 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
232 def set_inputs(self
, branch
, dec2
, sim
):
233 print(f
"cr0: {sim.crl[0].get_range()}")
235 inp
= yield from get_cu_inputs(dec2
, sim
)
237 yield from ALUHelpers
.set_cia(branch
, dec2
, inp
)
238 yield from ALUHelpers
.set_fast_spr1(branch
, dec2
, inp
)
239 yield from ALUHelpers
.set_fast_spr2(branch
, dec2
, inp
)
240 yield from ALUHelpers
.set_cr_a(branch
, dec2
, inp
)
243 if __name__
== "__main__":
244 unittest
.main(exit
=False)
245 suite
= unittest
.TestSuite()
246 suite
.addTest(TestRunner(BranchTestCase
.test_data
))
248 runner
= unittest
.TextTestRunner()