53758b1df6839256da681e026d5bdda938fc30b6
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
.br_input_record
import CompBROpSubset
17 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
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_ilang(self
):
102 rec
= CompBROpSubset()
104 pspec
= BranchPipeSpec(id_wid
=2, op_wid
=get_rec_width(rec
))
105 alu
= BranchBasePipe(pspec
)
106 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
107 with
open("branch_pipeline.il", "w") as f
:
111 class TestRunner(FHDLTestCase
):
112 def __init__(self
, test_data
):
113 super().__init
__("run_all")
114 self
.test_data
= test_data
119 instruction
= Signal(32)
121 pdecode
= create_pdecode()
123 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
125 rec
= CompBROpSubset()
127 pspec
= BranchPipeSpec(id_wid
=2, op_wid
=get_rec_width(rec
))
128 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
130 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
131 comb
+= branch
.p
.valid_i
.eq(1)
132 comb
+= branch
.n
.ready_i
.eq(1)
133 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
138 for test
in self
.test_data
:
140 program
= test
.program
141 self
.subTest(test
.name
)
142 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
144 simulator
.set_pc(initial_cia
)
145 gen
= program
.generate_instructions()
146 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
148 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
149 while index
< len(instructions
) and index
>= 0:
151 ins
, code
= instructions
[index
]
153 print("0x{:X}".format(ins
& 0xffffffff))
156 # ask the decoder to decode this binary data (endian'd)
157 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
158 yield instruction
.eq(ins
) # raw binary instr.
159 yield branch
.p
.data_i
.cia
.eq(simulator
.pc
.CIA
.value
)
160 yield branch
.p
.data_i
.cr
.eq(simulator
.cr
.get_range().value
)
161 # note, here, the op will need further decoding in order
162 # to set the correct SPRs on SPR1/2/3. op_bc* require
163 # spr2 to be set to CTR, op_bctar require spr1 to be
164 # set to TAR, op_bclr* require spr1 to be set to LR.
165 # if op_sc*, op_rf* and op_hrfid are to be added here
166 # then additional op-decoding is required, accordingly
167 yield branch
.p
.data_i
.spr2
.eq(simulator
.spr
['CTR'].value
)
168 print(f
"cr0: {simulator.crl[0].get_range()}")
170 fn_unit
= yield pdecode2
.e
.fn_unit
171 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
174 opname
= code
.split(' ')[0]
175 prev_nia
= simulator
.pc
.NIA
.value
176 yield from simulator
.call(opname
)
177 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
179 yield from self
.assert_outputs(branch
, pdecode2
,
180 simulator
, prev_nia
, code
)
183 sim
.add_sync_process(process
)
184 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
188 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
189 branch_taken
= yield branch
.n
.data_o
.nia
.ok
190 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
191 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
193 branch_addr
= yield branch
.n
.data_o
.nia
.data
194 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
197 branch_lk
= yield branch
.n
.data_o
.lr
.ok
198 self
.assertEqual(lk
, branch_lk
, code
)
200 branch_lr
= yield branch
.n
.data_o
.lr
.data
201 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
204 if __name__
== "__main__":
205 unittest
.main(exit
=False)
206 suite
= unittest
.TestSuite()
207 suite
.addTest(TestRunner(test_data
))
209 runner
= unittest
.TextTestRunner()