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
15 from soc
.fu
.test
.common
import TestCase
, ALUHelpers
16 from soc
.fu
.branch
.pipeline
import BranchBasePipe
17 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
20 from soc
.regfile
.util
import fast_reg_to_spr
# HACK!
23 def get_rec_width(rec
):
25 # Setup random inputs for dut.op
32 # This test bench is a bit different than is usual. Initially when I
33 # was writing it, I had all of the tests call a function to create a
34 # device under test and simulator, initialize the dut, run the
35 # simulation for ~2 cycles, and assert that the dut output what it
36 # should have. However, this was really slow, since it needed to
37 # create and tear down the dut and simulator for every test case.
39 # Now, instead of doing that, every test case in ALUTestCase puts some
40 # data into the test_data list below, describing the instructions to
41 # be tested and the initial state. Once all the tests have been run,
42 # test_data gets passed to TestRunner which then sets up the DUT and
43 # simulator once, runs all the data through it, and asserts that the
44 # results match the pseudocode sim at every cycle.
46 # By doing this, I've reduced the time it takes to run the test suite
47 # massively. Before, it took around 1 minute on my computer, now it
48 # takes around 3 seconds
51 def get_cu_inputs(dec2
, sim
):
52 """naming (res) must conform to BranchFunctionUnit input regspec
57 res
['cia'] = sim
.pc
.CIA
.value
59 yield from ALUHelpers
.get_sim_fast_spr1(res
, sim
, dec2
)
60 yield from ALUHelpers
.get_sim_fast_spr2(res
, sim
, dec2
)
61 yield from ALUHelpers
.get_sim_cr_a(res
, sim
, dec2
)
63 print ("get inputs", res
)
67 class BranchTestCase(FHDLTestCase
):
69 def __init__(self
, name
):
70 super().__init
__(name
)
73 def run_tst_program(self
, prog
, initial_regs
=None,
74 initial_sprs
=None, initial_cr
=0):
75 tc
= TestCase(prog
, self
.test_name
,
76 initial_regs
, initial_sprs
, initial_cr
)
77 self
.test_data
.append(tc
)
79 def test_unconditional(self
):
80 choices
= ["b", "ba", "bl", "bla"]
82 choice
= random
.choice(choices
)
83 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
84 lst
= [f
"{choice} {imm}"]
85 initial_regs
= [0] * 32
86 self
.run_tst_program(Program(lst
), initial_regs
)
90 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
91 bo
= random
.choice([0b01100, 0b00100, 0b10100])
92 bi
= random
.randrange(0, 31)
93 cr
= random
.randrange(0, (1<<32)-1)
94 lst
= [f
"bc {bo}, {bi}, {bc}"]
95 initial_regs
= [0] * 32
96 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
98 def test_bc_ctr(self
):
100 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
101 bo
= random
.choice([0, 2, 8, 10, 16, 18])
102 bi
= random
.randrange(0, 31)
103 cr
= random
.randrange(0, (1<<32)-1)
104 ctr
= random
.randint(0, (1<<32)-1)
105 lst
= [f
"bc {bo}, {bi}, {bc}"]
106 initial_sprs
={9: SelectableInt(ctr
, 64)}
107 self
.run_tst_program(Program(lst
),
108 initial_sprs
=initial_sprs
,
111 def test_bc_reg(self
):
112 # XXX: bcctr and bcctrl time out (irony: they're counters)
113 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
116 bh
= random
.randrange(0, 3)
117 bo
= random
.choice([4, 12])
118 bi
= random
.randrange(0, 31)
119 cr
= random
.randrange(0, (1<<32)-1)
120 ctr
= random
.randint(0, (1<<32)-1)
121 lr
= random
.randint(0, (1<<64)-1) & ~
3
122 tar
= random
.randint(0, (1<<64)-1) & ~
3
123 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
124 initial_sprs
={9: SelectableInt(ctr
, 64),
125 8: SelectableInt(lr
, 64),
126 815: SelectableInt(tar
, 64)}
127 self
.run_tst_program(Program(lst
),
128 initial_sprs
=initial_sprs
,
131 def test_ilang(self
):
132 pspec
= BranchPipeSpec(id_wid
=2)
133 alu
= BranchBasePipe(pspec
)
134 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
135 with
open("branch_pipeline.il", "w") as f
:
139 class TestRunner(FHDLTestCase
):
140 def __init__(self
, test_data
):
141 super().__init
__("run_all")
142 self
.test_data
= test_data
147 instruction
= Signal(32)
149 pdecode
= create_pdecode()
151 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
153 pspec
= BranchPipeSpec(id_wid
=2)
154 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
156 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
157 comb
+= branch
.p
.valid_i
.eq(1)
158 comb
+= branch
.n
.ready_i
.eq(1)
159 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
164 for test
in self
.test_data
:
166 program
= test
.program
167 self
.subTest(test
.name
)
168 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
,
171 simulator
.set_pc(initial_cia
)
172 gen
= program
.generate_instructions()
173 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
175 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
176 while index
< len(instructions
) and index
>= 0:
178 ins
, code
= instructions
[index
]
180 print("0x{:X}".format(ins
& 0xffffffff))
183 # ask the decoder to decode this binary data (endian'd)
184 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
185 yield instruction
.eq(ins
) # raw binary instr.
186 # note, here, the op will need further decoding in order
187 # to set the correct SPRs on SPR1/2/3. op_bc* require
188 # spr1 to be set to CTR, op_bctar require spr2 to be
189 # set to TAR, op_bclr* require spr2 to be set to LR.
190 # if op_sc*, op_rf* and op_hrfid are to be added here
191 # then additional op-decoding is required, accordingly
193 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
194 fn_unit
= yield pdecode2
.e
.fn_unit
195 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
198 opname
= code
.split(' ')[0]
199 prev_nia
= simulator
.pc
.NIA
.value
200 yield from simulator
.call(opname
)
201 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
203 yield from self
.assert_outputs(branch
, pdecode2
,
204 simulator
, prev_nia
, code
)
206 sim
.add_sync_process(process
)
207 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
211 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
212 branch_taken
= yield branch
.n
.data_o
.nia
.ok
213 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
214 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
216 branch_addr
= yield branch
.n
.data_o
.nia
.data
217 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
218 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
220 # TODO: check write_fast1 as well (should contain CTR)
222 # TODO: this should be checking write_fast2
224 branch_lk
= yield branch
.n
.data_o
.lr
.ok
225 self
.assertEqual(lk
, branch_lk
, code
)
227 branch_lr
= yield branch
.n
.data_o
.lr
.data
228 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
230 def set_inputs(self
, branch
, dec2
, sim
):
231 print(f
"cr0: {sim.crl[0].get_range()}")
233 inp
= yield from get_cu_inputs(dec2
, sim
)
235 yield from ALUHelpers
.set_cia(branch
, dec2
, inp
)
236 yield from ALUHelpers
.set_fast_spr1(branch
, dec2
, inp
)
237 yield from ALUHelpers
.set_fast_spr2(branch
, dec2
, inp
)
238 yield from ALUHelpers
.set_cr_a(branch
, dec2
, inp
)
241 if __name__
== "__main__":
242 unittest
.main(exit
=False)
243 suite
= unittest
.TestSuite()
244 suite
.addTest(TestRunner(BranchTestCase
.test_data
))
246 runner
= unittest
.TextTestRunner()