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
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
53 def get_cu_inputs(dec2
, sim
):
54 """naming (res) must conform to BranchFunctionUnit input regspec
59 res
['cia'] = sim
.pc
.CIA
.value
61 fast1_en
= yield dec2
.e
.read_fast1
.ok
63 fast1_sel
= yield dec2
.e
.read_fast1
.data
64 spr1_sel
= fast_reg_to_spr(fast1_sel
)
65 spr1_data
= sim
.spr
[spr1_sel
].value
66 res
['spr1'] = spr1_data
68 fast2_en
= yield dec2
.e
.read_fast2
.ok
70 fast2_sel
= yield dec2
.e
.read_fast2
.data
71 spr2_sel
= fast_reg_to_spr(fast2_sel
)
72 spr2_data
= sim
.spr
[spr2_sel
].value
73 res
['spr2'] = spr2_data
75 cr_en
= yield dec2
.e
.read_cr1
.ok
77 cr_sel
= yield dec2
.e
.read_cr1
.data
78 cr
= sim
.crl
[cr_sel
].get_range().value
81 print ("get inputs", res
)
85 class BranchTestCase(FHDLTestCase
):
86 def __init__(self
, name
):
87 super().__init
__(name
)
90 def run_tst_program(self
, prog
, initial_regs
=None,
91 initial_sprs
=None, initial_cr
=0):
92 tc
= TestCase(prog
, self
.test_name
,
93 initial_regs
, initial_sprs
, initial_cr
)
96 def test_unconditional(self
):
97 choices
= ["b", "ba", "bl", "bla"]
99 choice
= random
.choice(choices
)
100 imm
= random
.randrange(-1<<23, (1<<23)-1) * 4
101 lst
= [f
"{choice} {imm}"]
102 initial_regs
= [0] * 32
103 self
.run_tst_program(Program(lst
), initial_regs
)
105 def test_bc_cr(self
):
107 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
108 bo
= random
.choice([0b01100, 0b00100, 0b10100])
109 bi
= random
.randrange(0, 31)
110 cr
= random
.randrange(0, (1<<32)-1)
111 lst
= [f
"bc {bo}, {bi}, {bc}"]
112 initial_regs
= [0] * 32
113 self
.run_tst_program(Program(lst
), initial_cr
=cr
)
115 def test_bc_ctr(self
):
117 bc
= random
.randrange(-1<<13, (1<<13)-1) * 4
118 bo
= random
.choice([0, 2, 8, 10, 16, 18])
119 bi
= random
.randrange(0, 31)
120 cr
= random
.randrange(0, (1<<32)-1)
121 ctr
= random
.randint(0, (1<<32)-1)
122 lst
= [f
"bc {bo}, {bi}, {bc}"]
123 initial_sprs
={9: SelectableInt(ctr
, 64)}
124 self
.run_tst_program(Program(lst
),
125 initial_sprs
=initial_sprs
,
128 def test_bc_reg(self
):
129 # XXX: bcctr and bcctrl time out (irony: they're counters)
130 choices
= ["bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl"]
133 bh
= random
.randrange(0, 3)
134 bo
= random
.choice([4, 12])
135 bi
= random
.randrange(0, 31)
136 cr
= random
.randrange(0, (1<<32)-1)
137 ctr
= random
.randint(0, (1<<32)-1)
138 lr
= random
.randint(0, (1<<64)-1) & ~
3
139 tar
= random
.randint(0, (1<<64)-1) & ~
3
140 lst
= [f
"{insn} {bo}, {bi}, {bh}"]
141 initial_sprs
={9: SelectableInt(ctr
, 64),
142 8: SelectableInt(lr
, 64),
143 815: SelectableInt(tar
, 64)}
144 self
.run_tst_program(Program(lst
),
145 initial_sprs
=initial_sprs
,
148 def test_ilang(self
):
149 pspec
= BranchPipeSpec(id_wid
=2)
150 alu
= BranchBasePipe(pspec
)
151 vl
= rtlil
.convert(alu
, ports
=alu
.ports())
152 with
open("branch_pipeline.il", "w") as f
:
156 class TestRunner(FHDLTestCase
):
157 def __init__(self
, test_data
):
158 super().__init
__("run_all")
159 self
.test_data
= test_data
164 instruction
= Signal(32)
166 pdecode
= create_pdecode()
168 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
170 pspec
= BranchPipeSpec(id_wid
=2)
171 m
.submodules
.branch
= branch
= BranchBasePipe(pspec
)
173 comb
+= branch
.p
.data_i
.ctx
.op
.eq_from_execute1(pdecode2
.e
)
174 comb
+= branch
.p
.valid_i
.eq(1)
175 comb
+= branch
.n
.ready_i
.eq(1)
176 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
181 for test
in self
.test_data
:
183 program
= test
.program
184 self
.subTest(test
.name
)
185 simulator
= ISA(pdecode2
, test
.regs
, test
.sprs
, test
.cr
)
187 simulator
.set_pc(initial_cia
)
188 gen
= program
.generate_instructions()
189 instructions
= list(zip(gen
, program
.assembly
.splitlines()))
191 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
192 while index
< len(instructions
) and index
>= 0:
194 ins
, code
= instructions
[index
]
196 print("0x{:X}".format(ins
& 0xffffffff))
199 # ask the decoder to decode this binary data (endian'd)
200 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
201 yield instruction
.eq(ins
) # raw binary instr.
202 # note, here, the op will need further decoding in order
203 # to set the correct SPRs on SPR1/2/3. op_bc* require
204 # spr1 to be set to CTR, op_bctar require spr2 to be
205 # set to TAR, op_bclr* require spr2 to be set to LR.
206 # if op_sc*, op_rf* and op_hrfid are to be added here
207 # then additional op-decoding is required, accordingly
209 yield from self
.set_inputs(branch
, pdecode2
, simulator
)
210 fn_unit
= yield pdecode2
.e
.fn_unit
211 self
.assertEqual(fn_unit
, Function
.BRANCH
.value
, code
)
214 opname
= code
.split(' ')[0]
215 prev_nia
= simulator
.pc
.NIA
.value
216 yield from simulator
.call(opname
)
217 index
= (simulator
.pc
.CIA
.value
- initial_cia
)//4
219 yield from self
.assert_outputs(branch
, pdecode2
,
220 simulator
, prev_nia
, code
)
222 sim
.add_sync_process(process
)
223 with sim
.write_vcd("simulator.vcd", "simulator.gtkw",
227 def assert_outputs(self
, branch
, dec2
, sim
, prev_nia
, code
):
228 branch_taken
= yield branch
.n
.data_o
.nia
.ok
229 sim_branch_taken
= prev_nia
!= sim
.pc
.CIA
230 self
.assertEqual(branch_taken
, sim_branch_taken
, code
)
232 branch_addr
= yield branch
.n
.data_o
.nia
.data
233 print(f
"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
234 self
.assertEqual(branch_addr
, sim
.pc
.CIA
.value
, code
)
236 # TODO: check write_fast1 as well (should contain CTR)
238 # TODO: this should be checking write_fast2
240 branch_lk
= yield branch
.n
.data_o
.lr
.ok
241 self
.assertEqual(lk
, branch_lk
, code
)
243 branch_lr
= yield branch
.n
.data_o
.lr
.data
244 self
.assertEqual(sim
.spr
['LR'], branch_lr
, code
)
246 def set_inputs(self
, branch
, dec2
, sim
):
247 print(f
"cr0: {sim.crl[0].get_range()}")
249 inp
= yield from get_cu_inputs(dec2
, sim
)
252 yield branch
.p
.data_i
.cia
.eq(inp
['cia'])
254 yield branch
.p
.data_i
.spr1
.eq(inp
['spr1'])
256 yield branch
.p
.data_i
.spr2
.eq(inp
['spr2'])
258 yield branch
.p
.data_i
.cr
.eq(inp
['cr_a'])
261 if __name__
== "__main__":
262 unittest
.main(exit
=False)
263 suite
= unittest
.TestSuite()
264 suite
.addTest(TestRunner(test_data
))
266 runner
= unittest
.TextTestRunner()