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 yield branch
.p
.data_i
.cr
.eq(simulator
.cr
.get_range().value
)
155 # note, here, the op will need further decoding in order
156 # to set the correct SPRs on SPR1/2/3. op_bc* require
157 # spr2 to be set to CTR, op_bctar require spr1 to be
158 # set to TAR, op_bclr* require spr1 to be set to LR.
159 # if op_sc*, op_rf* and op_hrfid are to be added here
160 # then additional op-decoding is required, accordingly
161 yield branch
.p
.data_i
.spr2
.eq(simulator
.spr
['CTR'].value
)
162 print(f
"cr0: {simulator.crl[0].get_range()}")
164 fn_unit
= yield pdecode2
.e
.fn_unit
165 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
168 opname
= code
.split(' ')[0]
169 prev_nia
= simulator
.pc
.NIA
.value
170 yield from simulator
.call(opname
)
171 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
173 yield from self
.assert_outputs(branch
, pdecode2
,
174 simulator
, prev_nia
, code
)
177 sim
.add_sync_process(process
)
178 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
182 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
183 branch_taken
= yield branch
.n
.data_o
.nia
.ok
184 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
185 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
187 branch_addr
= yield branch
.n
.data_o
.nia
.data
188 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
191 branch_lk
= yield branch
.n
.data_o
.lr
.ok
192 self
.assertEqual(lk
, branch_lk
, code
)
194 branch_lr
= yield branch
.n
.data_o
.lr
.data
195 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
198 if __name__
== "__main__":
199 unittest
.main(exit
=False)
200 suite
= unittest
.TestSuite()
201 suite
.addTest(TestRunner(test_data
))
203 runner
= unittest
.TextTestRunner()