1 """TestRunner class, runs TestIssuer instructions
5 * https://bugs.libre-soc.org/show_bug.cgi?id=363
6 * https://bugs.libre-soc.org/show_bug.cgi?id=686#c51
8 from nmigen
import Module
, Signal
9 from nmigen
.hdl
.xfrm
import ResetInserter
12 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
13 # Also, check out the cxxsim nmigen branch, and latest yosys from git
14 from nmutil
.sim_tmp_alternative
import Simulator
, Settle
16 from openpower
.decoder
.isa
.caller
import SVP64State
17 from openpower
.decoder
.isa
.all
import ISA
18 from openpower
.endian
import bigendian
20 from soc
.simple
.issuer
import TestIssuerInternal
22 from soc
.simple
.test
.test_core
import (setup_regs
, check_regs
, check_mem
,
25 from soc
.fu
.compunits
.test
.test_compunit
import (setup_tst_memory
,
27 from soc
.debug
.dmi
import DBGCore
, DBGCtrl
, DBGStat
28 from nmutil
.util
import wrap
29 from openpower
.test
.state
import TestState
, StateRunner
30 from openpower
.test
.runner
import TestRunnerBase
33 def setup_i_memory(imem
, startaddr
, instructions
):
35 print("insn before, init mem", mem
.depth
, mem
.width
, mem
,
37 for i
in range(mem
.depth
):
38 yield mem
._array
[i
].eq(0)
40 startaddr
//= 4 # instructions are 32-bit
43 for ins
in instructions
:
44 if isinstance(ins
, tuple):
48 insn
= insn
& 0xffffffff
49 yield mem
._array
[startaddr
].eq(insn
)
52 print("instr: %06x 0x%x %s" % (4*startaddr
, insn
, code
))
54 startaddr
= startaddr
& mask
59 for ins
in instructions
:
60 if isinstance(ins
, tuple):
64 insn
= insn
& 0xffffffff
65 msbs
= (startaddr
>> 1) & mask
66 val
= yield mem
._array
[msbs
]
68 print("before set", hex(4*startaddr
),
69 hex(msbs
), hex(val
), hex(insn
))
70 lsb
= 1 if (startaddr
& 1) else 0
71 val
= (val |
(insn
<< (lsb
*32)))
73 yield mem
._array
[msbs
].eq(val
)
76 print("after set", hex(4*startaddr
), hex(msbs
), hex(val
))
77 print("instr: %06x 0x%x %s %08x" % (4*startaddr
, insn
, code
, val
))
79 startaddr
= startaddr
& mask
82 def set_dmi(dmi
, addr
, data
):
84 yield dmi
.addr_i
.eq(addr
)
85 yield dmi
.din
.eq(data
)
94 yield dmi
.addr_i
.eq(0)
100 def get_dmi(dmi
, addr
):
101 yield dmi
.req_i
.eq(1)
102 yield dmi
.addr_i
.eq(addr
)
106 ack
= yield dmi
.ack_o
111 data
= yield dmi
.dout
# get data after ack valid for 1 cycle
112 yield dmi
.req_i
.eq(0)
113 yield dmi
.addr_i
.eq(0)
119 class HDLRunner(StateRunner
):
120 """HDLRunner: Implements methods for the setup, preparation, and
121 running of tests using nmigen HDL simulation.
124 def __init__(self
, dut
, m
, pspec
):
125 super().__init
__("hdl", HDLRunner
)
128 self
.pc_i
= Signal(32)
129 self
.svstate_i
= Signal(64)
131 #hard_reset = Signal(reset_less=True)
132 self
.issuer
= TestIssuerInternal(pspec
)
133 # use DMI RESET command instead, this does actually work though
134 # issuer = ResetInserter({'coresync': hard_reset,
135 # 'sync': hard_reset})(issuer)
136 m
.submodules
.issuer
= self
.issuer
137 self
.dmi
= self
.issuer
.dbg
.dmi
140 comb
+= self
.issuer
.pc_i
.data
.eq(self
.pc_i
)
141 comb
+= self
.issuer
.svstate_i
.data
.eq(self
.svstate_i
)
143 def prepare_for_test(self
, test
):
146 # set up bigendian (TODO: don't do this, use MSR)
147 yield self
.issuer
.core_bigendian_i
.eq(bigendian
)
155 def setup_during_test(self
):
156 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.STOP
)
159 def run_test(self
, instructions
):
160 """run_hdl_state - runs a TestIssuer nmigen HDL simulation
163 imem
= self
.issuer
.imem
._get
_memory
()
164 core
= self
.issuer
.core
165 dmi
= self
.issuer
.dbg
.dmi
166 pdecode2
= self
.issuer
.pdecode2
170 # establish the TestIssuer context (mem, regs etc)
172 pc
= 0 # start address
173 counter
= 0 # test to pause/start
175 yield from setup_i_memory(imem
, pc
, instructions
)
176 yield from setup_tst_memory(l0
, self
.test
.mem
)
177 yield from setup_regs(pdecode2
, core
, self
.test
)
180 yield self
.pc_i
.eq(pc
)
181 yield self
.issuer
.pc_i
.ok
.eq(1)
183 # copy initial SVSTATE
184 initial_svstate
= copy(self
.test
.svstate
)
185 if isinstance(initial_svstate
, int):
186 initial_svstate
= SVP64State(initial_svstate
)
187 yield self
.svstate_i
.eq(initial_svstate
.value
)
188 yield self
.issuer
.svstate_i
.ok
.eq(1)
191 print("instructions", instructions
)
193 # run the loop of the instructions on the current test
194 index
= (yield self
.issuer
.cur_state
.pc
) // 4
195 while index
< len(instructions
):
196 ins
, code
= instructions
[index
]
198 print("hdl instr: 0x{:X}".format(ins
& 0xffffffff))
204 yield from set_dmi(dmi
, DBGCore
.CTRL
,
206 yield self
.issuer
.pc_i
.ok
.eq(0) # no change PC after this
207 yield self
.issuer
.svstate_i
.ok
.eq(0) # ditto
211 counter
= counter
+ 1
213 # wait until executed
214 while not (yield self
.issuer
.insn_done
):
217 # okaaay long story: in overlap mode, PC is updated one cycle
219 if self
.dut
.allow_overlap
:
223 index
= (yield self
.issuer
.cur_state
.pc
) // 4
225 terminated
= yield self
.issuer
.dbg
.terminated_o
226 print("terminated", terminated
, index
, len(instructions
))
228 if index
< len(instructions
):
229 # Get HDL mem and state
230 state
= yield from TestState("hdl", core
, self
.dut
,
232 hdl_states
.append(state
)
234 if index
>= len(instructions
):
235 print("index over, send dmi stop")
237 yield from set_dmi(dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.STOP
)
241 terminated
= yield self
.issuer
.dbg
.terminated_o
242 print("terminated(2)", terminated
)
246 if self
.dut
.allow_overlap
:
247 # wait until all settled
248 # XXX really this should be in DMI, which should in turn
249 # use issuer.any_busy to not send back "stopped" signal
250 while (yield self
.issuer
.any_busy
):
253 if self
.dut
.allow_overlap
:
254 # get last state, at end of run
255 state
= yield from TestState("hdl", core
, self
.dut
,
257 hdl_states
.append(state
)
262 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.STOP
)
266 # TODO, here is where the static (expected) results
267 # can be checked: register check (TODO, memory check)
268 # see https://bugs.libre-soc.org/show_bug.cgi?id=686#c51
269 # yield from check_regs(self, sim, core, test, code,
270 # >>>expected_data<<<)
273 cr
= yield from get_dmi(self
.dmi
, DBGCore
.CR
)
274 print("after test %s cr value %x" % (self
.test
.name
, cr
))
277 xer
= yield from get_dmi(self
.dmi
, DBGCore
.XER
)
278 print("after test %s XER value %x" % (self
.test
.name
, xer
))
280 # test of dmi reg get
281 for int_reg
in range(32):
282 yield from set_dmi(self
.dmi
, DBGCore
.GSPR_IDX
, int_reg
)
283 value
= yield from get_dmi(self
.dmi
, DBGCore
.GSPR_DATA
)
285 print("after test %s reg %2d value %x" %
286 (self
.test
.name
, int_reg
, value
))
289 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.RESET
)
293 class TestRunner(TestRunnerBase
):
294 def __init__(self
, tst_data
, microwatt_mmu
=False, rom
=None,
295 svp64
=True, run_hdl
=True, run_sim
=True,
296 allow_overlap
=False):
299 super().__init
__(tst_data
, microwatt_mmu
=microwatt_mmu
,
301 svp64
=svp64
, run_hdl
=run_hdl
, run_sim
=run_sim
,
302 allow_overlap
=allow_overlap
)