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
14 from soc
.fu
.branch
.pipeline
import BranchBasePipe
15 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
20 def __init__(self
, program
, regs
, sprs
, cr
, name
):
21 self
.program
= program
27 def get_rec_width(rec
):
29 # Setup random inputs for dut.op
36 # This test bench is a bit different than is usual. Initially when I
37 # was writing it, I had all of the tests call a function to create a
38 # device under test and simulator, initialize the dut, run the
39 # simulation for ~2 cycles, and assert that the dut output what it
40 # should have. However, this was really slow, since it needed to
41 # create and tear down the dut and simulator for every test case.
43 # Now, instead of doing that, every test case in ALUTestCase puts some
44 # data into the test_data list below, describing the instructions to
45 # be tested and the initial state. Once all the tests have been run,
46 # test_data gets passed to TestRunner which then sets up the DUT and
47 # simulator once, runs all the data through it, and asserts that the
48 # results match the pseudocode sim at every cycle.
50 # By doing this, I've reduced the time it takes to run the test suite
51 # massively. Before, it took around 1 minute on my computer, now it
52 # takes around 3 seconds
57 class BranchTestCase(FHDLTestCase
):
58 def __init__(self
, name
):
59 super().__init
__(name
)
61 def run_tst_program(self
, prog
, initial_regs
=[0] * 32,
62 initial_sprs
={}, initial_cr
=0):
63 tc
= TestCase(prog
, initial_regs
, initial_sprs
, initial_cr
,
67 def test_unconditional(self
):
68 choices
= ["b", "ba", "bl", "bla"]
70 choice
= random
.choice(choices
)
71 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
72 lst
= [f
"{choice} {imm}"]
73 initial_regs
= [0] * 32
74 self
.run_tst_program(Program(lst
), initial_regs
)
78 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
79 bo
= random
.choice([0b01100, 0b00100, 0b10100])
80 bi
= random
.randrange(0, 31)
81 cr
= random
.randrange(0, (1<<32)-1)
82 lst
= [f
"bc {bo}, {bi}, {bc}"]
83 initial_regs
= [0] * 32
84 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
86 def test_bc_ctr(self
):
88 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
89 bo
= random
.choice([0, 2, 8, 10, 16, 18])
90 bi
= random
.randrange(0, 31)
91 cr
= random
.randrange(0, (1<<32)-1)
92 ctr
= random
.randint(0, (1<<32)-1)
93 lst
= [f
"bc {bo}, {bi}, {bc}"]
94 initial_sprs
={9: SelectableInt(ctr
, 64)}
95 self
.run_tst_program(Program(lst
),
96 initial_sprs
=initial_sprs
,
100 pspec
= BranchPipeSpec(id_wid
=2)
101 alu
= BranchBasePipe(pspec
)
102 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
103 with
open("branch_pipeline.il", "w") as f
:
107 class TestRunner(FHDLTestCase
):
108 def __init__(self
, test_data
):
109 super().__init
__("run_all")
110 self
.test_data
= test_data
115 instruction
= Signal(32)
117 pdecode
= create_pdecode()
119 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
121 pspec
= BranchPipeSpec(id_wid
=2)
122 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
124 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
125 comb
+= branch
.p
.valid_i
.eq(1)
126 comb
+= branch
.n
.ready_i
.eq(1)
127 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
132 for test
in self
.test_data
:
134 program
= test
.program
135 self
.subTest(test
.name
)
136 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
138 simulator
.set_pc(initial_cia
)
139 gen
= program
.generate_instructions()
140 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
142 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
143 while index
< len(instructions
) and index
>= 0:
145 ins
, code
= instructions
[index
]
147 print("0x{:X}".format(ins
& 0xffffffff))
150 # ask the decoder to decode this binary data (endian'd)
151 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
152 yield instruction
.eq(ins
) # raw binary instr.
153 yield branch
.p
.data_i
.cia
.eq(simulator
.pc
.CIA
.value
)
154 # note, here, the op will need further decoding in order
155 # to set the correct SPRs on SPR1/2/3. op_bc* require
156 # spr1 to be set to CTR, op_bctar require spr2 to be
157 # set to TAR, op_bclr* require spr2 to be set to LR.
158 # if op_sc*, op_rf* and op_hrfid are to be added here
159 # then additional op-decoding is required, accordingly
160 yield branch
.p
.data_i
.spr1
.eq(simulator
.spr
['CTR'].value
)
161 print(f
"cr0: {simulator.crl[0].get_range()}")
164 cr_en
= yield pdecode2
.e
.read_cr1
.ok
166 cr_sel
= yield pdecode2
.e
.read_cr1
.data
167 cr
= simulator
.crl
[cr_sel
].get_range().value
168 yield branch
.p
.data_i
.cr
.eq(cr
)
169 full_cr
= simulator
.cr
.get_range().value
170 print(f
"full cr: {full_cr:x}, sel: {cr_sel}, cr: {cr:x}")
171 fn_unit
= yield pdecode2
.e
.fn_unit
172 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
175 opname
= code
.split(' ')[0]
176 prev_nia
= simulator
.pc
.NIA
.value
177 yield from simulator
.call(opname
)
178 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
180 yield from self
.assert_outputs(branch
, pdecode2
,
181 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()