75cac8090f561b80d86defbccf3fc05c77353755
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
)
10 from soc
.decoder
.selectable_int
import SelectableInt
11 from soc
.simulator
.program
import Program
12 from soc
.decoder
.isa
.all
import ISA
15 from soc
.fu
.branch
.pipeline
import BranchBasePipe
16 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
21 def __init__(self
, program
, regs
, sprs
, cr
, name
):
22 self
.program
= program
28 def get_rec_width(rec
):
30 # Setup random inputs for dut.op
37 # This test bench is a bit different than is usual. Initially when I
38 # was writing it, I had all of the tests call a function to create a
39 # device under test and simulator, initialize the dut, run the
40 # simulation for ~2 cycles, and assert that the dut output what it
41 # should have. However, this was really slow, since it needed to
42 # create and tear down the dut and simulator for every test case.
44 # Now, instead of doing that, every test case in ALUTestCase puts some
45 # data into the test_data list below, describing the instructions to
46 # be tested and the initial state. Once all the tests have been run,
47 # test_data gets passed to TestRunner which then sets up the DUT and
48 # simulator once, runs all the data through it, and asserts that the
49 # results match the pseudocode sim at every cycle.
51 # By doing this, I've reduced the time it takes to run the test suite
52 # massively. Before, it took around 1 minute on my computer, now it
53 # takes around 3 seconds
58 class BranchTestCase(FHDLTestCase
):
59 def __init__(self
, name
):
60 super().__init
__(name
)
62 def run_tst_program(self
, prog
, initial_regs
=[0] * 32,
63 initial_sprs
={}, initial_cr
=0):
64 tc
= TestCase(prog
, initial_regs
, initial_sprs
, initial_cr
,
68 def test_unconditional(self
):
69 choices
= ["b", "ba", "bl", "bla"]
71 choice
= random
.choice(choices
)
72 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
73 lst
= [f
"{choice} {imm}"]
74 initial_regs
= [0] * 32
75 self
.run_tst_program(Program(lst
), initial_regs
)
79 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
80 bo
= random
.choice([0b01100, 0b00100, 0b10100])
81 bi
= random
.randrange(0, 31)
82 cr
= random
.randrange(0, (1<<32)-1)
83 lst
= [f
"bc {bo}, {bi}, {bc}"]
84 initial_regs
= [0] * 32
85 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
87 def test_bc_ctr(self
):
89 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
90 bo
= random
.choice([0, 2, 8, 10, 16, 18])
91 bi
= random
.randrange(0, 31)
92 cr
= random
.randrange(0, (1<<32)-1)
93 ctr
= random
.randint(0, (1<<32)-1)
94 lst
= [f
"bc {bo}, {bi}, {bc}"]
95 initial_sprs
={9: SelectableInt(ctr
, 64)}
96 self
.run_tst_program(Program(lst
),
97 initial_sprs
=initial_sprs
,
100 def test_ilang(self
):
101 rec
= BranchPipeSpec
.opsubsetkls()
103 pspec
= BranchPipeSpec(id_wid
=2, op_wid
=get_rec_width(rec
))
104 alu
= BranchBasePipe(pspec
)
105 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
106 with
open("branch_pipeline.il", "w") as f
:
110 class TestRunner(FHDLTestCase
):
111 def __init__(self
, test_data
):
112 super().__init
__("run_all")
113 self
.test_data
= test_data
118 instruction
= Signal(32)
120 pdecode
= create_pdecode()
122 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
124 rec
= BranchPipeSpec
.opsubsetkls()
126 pspec
= BranchPipeSpec(id_wid
=2, op_wid
=get_rec_width(rec
))
127 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
129 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
130 comb
+= branch
.p
.valid_i
.eq(1)
131 comb
+= branch
.n
.ready_i
.eq(1)
132 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
137 for test
in self
.test_data
:
139 program
= test
.program
140 self
.subTest(test
.name
)
141 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
143 simulator
.set_pc(initial_cia
)
144 gen
= program
.generate_instructions()
145 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
147 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
148 while index
< len(instructions
) and index
>= 0:
150 ins
, code
= instructions
[index
]
152 print("0x{:X}".format(ins
& 0xffffffff))
155 # ask the decoder to decode this binary data (endian'd)
156 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
157 yield instruction
.eq(ins
) # raw binary instr.
158 yield branch
.p
.data_i
.cia
.eq(simulator
.pc
.CIA
.value
)
159 yield branch
.p
.data_i
.cr
.eq(simulator
.cr
.get_range().value
)
160 # note, here, the op will need further decoding in order
161 # to set the correct SPRs on SPR1/2/3. op_bc* require
162 # spr2 to be set to CTR, op_bctar require spr1 to be
163 # set to TAR, op_bclr* require spr1 to be set to LR.
164 # if op_sc*, op_rf* and op_hrfid are to be added here
165 # then additional op-decoding is required, accordingly
166 yield branch
.p
.data_i
.spr2
.eq(simulator
.spr
['CTR'].value
)
167 print(f
"cr0: {simulator.crl[0].get_range()}")
169 fn_unit
= yield pdecode2
.e
.fn_unit
170 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
173 opname
= code
.split(' ')[0]
174 prev_nia
= simulator
.pc
.NIA
.value
175 yield from simulator
.call(opname
)
176 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
178 yield from self
.assert_outputs(branch
, pdecode2
,
179 simulator
, prev_nia
, code
)
182 sim
.add_sync_process(process
)
183 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
187 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
188 branch_taken
= yield branch
.n
.data_o
.nia
.ok
189 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
190 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
192 branch_addr
= yield branch
.n
.data_o
.nia
.data
193 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
196 branch_lk
= yield branch
.n
.data_o
.lr
.ok
197 self
.assertEqual(lk
, branch_lk
, code
)
199 branch_lr
= yield branch
.n
.data_o
.lr
.data
200 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
203 if __name__
== "__main__":
204 unittest
.main(exit
=False)
205 suite
= unittest
.TestSuite()
206 suite
.addTest(TestRunner(test_data
))
208 runner
= unittest
.TextTestRunner()