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
, 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
.branch
.pipeline
import BranchBasePipe
16 from soc
.fu
.branch
.pipe_data
import BranchPipeSpec
19 from soc
.regfile
.util
import fast_reg_to_spr
# HACK!
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 def get_cu_inputs(dec2
, sim
):
60 """naming (res) must conform to BranchFunctionUnit input regspec
65 res
['cia'] = sim
.pc
.CIA
.value
67 fast1_en
= yield dec2
.e
.read_fast1
.ok
69 fast1_sel
= yield dec2
.e
.read_fast1
.data
70 spr1_sel
= fast_reg_to_spr(fast1_sel
)
71 spr1_data
= sim
.spr
[spr1_sel
].value
72 res
['spr1'] = spr1_data
74 fast2_en
= yield dec2
.e
.read_fast2
.ok
76 fast2_sel
= yield dec2
.e
.read_fast2
.data
77 spr2_sel
= fast_reg_to_spr(fast2_sel
)
78 spr2_data
= sim
.spr
[spr2_sel
].value
79 res
['spr2'] = spr2_data
81 cr_en
= yield dec2
.e
.read_cr1
.ok
83 cr_sel
= yield dec2
.e
.read_cr1
.data
84 cr
= sim
.crl
[cr_sel
].get_range().value
87 print ("get inputs", res
)
91 class BranchTestCase(FHDLTestCase
):
92 def __init__(self
, name
):
93 super().__init
__(name
)
95 def run_tst_program(self
, prog
, initial_regs
=[0] * 32,
96 initial_sprs
={}, initial_cr
=0):
97 tc
= TestCase(prog
, initial_regs
, initial_sprs
, initial_cr
,
101 def test_unconditional(self
):
102 choices
= ["b", "ba", "bl", "bla"]
104 choice
= random
.choice(choices
)
105 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
106 lst
= [f
"{choice} {imm}"]
107 initial_regs
= [0] * 32
108 self
.run_tst_program(Program(lst
), initial_regs
)
110 def test_bc_cr(self
):
112 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
113 bo
= random
.choice([0b01100, 0b00100, 0b10100])
114 bi
= random
.randrange(0, 31)
115 cr
= random
.randrange(0, (1<<32)-1)
116 lst
= [f
"bc {bo}, {bi}, {bc}"]
117 initial_regs
= [0] * 32
118 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
120 def test_bc_ctr(self
):
122 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
123 bo
= random
.choice([0, 2, 8, 10, 16, 18])
124 bi
= random
.randrange(0, 31)
125 cr
= random
.randrange(0, (1<<32)-1)
126 ctr
= random
.randint(0, (1<<32)-1)
127 lst
= [f
"bc {bo}, {bi}, {bc}"]
128 initial_sprs
={9: SelectableInt(ctr
, 64)}
129 self
.run_tst_program(Program(lst
),
130 initial_sprs
=initial_sprs
,
133 def test_bc_reg(self
):
134 # XXX: bcctr and bcctrl time out (irony: they're counters)
135 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
138 bh
= random
.randrange(0, 3)
139 bo
= random
.choice([4, 12])
140 bi
= random
.randrange(0, 31)
141 cr
= random
.randrange(0, (1<<32)-1)
142 ctr
= random
.randint(0, (1<<32)-1)
143 lr
= random
.randint(0, (1<<64)-1) & ~
3
144 tar
= random
.randint(0, (1<<64)-1) & ~
3
145 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
146 initial_sprs
={9: SelectableInt(ctr
, 64),
147 8: SelectableInt(lr
, 64),
148 815: SelectableInt(tar
, 64)}
149 self
.run_tst_program(Program(lst
),
150 initial_sprs
=initial_sprs
,
155 def test_ilang(self
):
156 pspec
= BranchPipeSpec(id_wid
=2)
157 alu
= BranchBasePipe(pspec
)
158 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
159 with
open("branch_pipeline.il", "w") as f
:
163 class TestRunner(FHDLTestCase
):
164 def __init__(self
, test_data
):
165 super().__init
__("run_all")
166 self
.test_data
= test_data
171 instruction
= Signal(32)
173 pdecode
= create_pdecode()
175 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
177 pspec
= BranchPipeSpec(id_wid
=2)
178 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
180 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
181 comb
+= branch
.p
.valid_i
.eq(1)
182 comb
+= branch
.n
.ready_i
.eq(1)
183 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
188 for test
in self
.test_data
:
190 program
= test
.program
191 self
.subTest(test
.name
)
192 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
194 simulator
.set_pc(initial_cia
)
195 gen
= program
.generate_instructions()
196 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
198 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
199 while index
< len(instructions
) and index
>= 0:
201 ins
, code
= instructions
[index
]
203 print("0x{:X}".format(ins
& 0xffffffff))
206 # ask the decoder to decode this binary data (endian'd)
207 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
208 yield instruction
.eq(ins
) # raw binary instr.
209 # note, here, the op will need further decoding in order
210 # to set the correct SPRs on SPR1/2/3. op_bc* require
211 # spr1 to be set to CTR, op_bctar require spr2 to be
212 # set to TAR, op_bclr* require spr2 to be set to LR.
213 # if op_sc*, op_rf* and op_hrfid are to be added here
214 # then additional op-decoding is required, accordingly
216 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
217 fn_unit
= yield pdecode2
.e
.fn_unit
218 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
221 opname
= code
.split(' ')[0]
222 prev_nia
= simulator
.pc
.NIA
.value
223 yield from simulator
.call(opname
)
224 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
226 yield from self
.assert_outputs(branch
, pdecode2
,
227 simulator
, prev_nia
, code
)
229 sim
.add_sync_process(process
)
230 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
234 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
235 branch_taken
= yield branch
.n
.data_o
.nia
.ok
236 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
237 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
239 branch_addr
= yield branch
.n
.data_o
.nia
.data
240 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
241 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
243 # TODO: check write_fast1 as well (should contain CTR)
245 # TODO: this should be checking write_fast2
247 branch_lk
= yield branch
.n
.data_o
.lr
.ok
248 self
.assertEqual(lk
, branch_lk
, code
)
250 branch_lr
= yield branch
.n
.data_o
.lr
.data
251 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
253 def set_inputs(self
, branch
, dec2
, sim
):
254 print(f
"cr0: {sim.crl[0].get_range()}")
256 inp
= yield from get_cu_inputs(dec2
, sim
)
259 yield branch
.p
.data_i
.cia
.eq(inp
['cia'])
261 yield branch
.p
.data_i
.spr1
.eq(inp
['spr1'])
263 yield branch
.p
.data_i
.spr2
.eq(inp
['spr2'])
265 yield branch
.p
.data_i
.cr
.eq(inp
['cr_a'])
268 if __name__
== "__main__":
269 unittest
.main(exit
=False)
270 suite
= unittest
.TestSuite()
271 suite
.addTest(TestRunner(test_data
))
273 runner
= unittest
.TextTestRunner()