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
11 from pprint
import pprint
13 # NOTE: to use cxxsim, export NMIGEN_SIM_MODE=cxxsim from the shell
14 # Also, check out the cxxsim nmigen branch, and latest yosys from git
15 from nmutil
.sim_tmp_alternative
import Simulator
, Settle
17 from openpower
.decoder
.isa
.caller
import SVP64State
18 from openpower
.decoder
.isa
.all
import ISA
19 from openpower
.endian
import bigendian
21 from soc
.simple
.issuer
import TestIssuerInternal
23 from soc
.simple
.test
.test_core
import (setup_regs
, check_regs
, check_mem
,
26 from soc
.fu
.compunits
.test
.test_compunit
import (setup_tst_memory
,
28 from soc
.debug
.dmi
import DBGCore
, DBGCtrl
, DBGStat
29 from nmutil
.util
import wrap
30 from openpower
.test
.state
import TestState
, StateRunner
31 from openpower
.test
.runner
import TestRunnerBase
34 def insert_into_rom(startaddr
, instructions
, rom
):
35 print("insn before, init rom", len(instructions
))
38 startaddr
//= 4 # instructions are 32-bit
42 for ins
in instructions
:
43 if isinstance(ins
, tuple):
47 insn
= insn
& 0xffffffff
48 msbs
= (startaddr
>> 1) & mask
49 lsb
= 1 if (startaddr
& 1) else 0
50 print ("insn", hex(insn
), hex(msbs
), hex(lsb
))
52 val
= rom
.get(msbs
<<3, 0)
54 print("before set", hex(4*startaddr
),
55 hex(msbs
), hex(val
), hex(insn
))
56 val
= (val |
(insn
<< (lsb
*32)))
60 print("after set", hex(4*startaddr
), hex(msbs
), hex(val
))
61 print("instr: %06x 0x%x %s %08x" % (4*startaddr
, insn
, code
, val
))
63 startaddr
= startaddr
& mask
65 print ("after insn insert")
69 def setup_i_memory(imem
, startaddr
, instructions
, rom
):
71 print("insn before, init mem", mem
.depth
, mem
.width
, mem
,
75 # initialise mem array to zero
76 for i
in range(mem
.depth
):
77 yield mem
._array
[i
].eq(0)
80 startaddr
//= 4 # instructions are 32-bit
82 assert rom
is None, "cannot do 32-bit from wb_get ROM yet"
84 for ins
in instructions
:
85 if isinstance(ins
, tuple):
89 insn
= insn
& 0xffffffff
90 yield mem
._array
[startaddr
].eq(insn
)
93 print("instr: %06x 0x%x %s" % (4*startaddr
, insn
, code
))
95 startaddr
= startaddr
& mask
100 for ins
in instructions
:
101 if isinstance(ins
, tuple):
105 insn
= insn
& 0xffffffff
106 msbs
= (startaddr
>> 1) & mask
107 lsb
= 1 if (startaddr
& 1) else 0
109 if rom
: # must put the value into the wb_get area
112 val
= yield mem
._array
[msbs
]
114 print("before set", hex(4*startaddr
),
115 hex(msbs
), hex(val
), hex(insn
))
116 val
= (val |
(insn
<< (lsb
*32)))
118 if rom
: # must put the value into the wb_get area
121 yield mem
._array
[msbs
].eq(val
)
124 print("after set", hex(4*startaddr
), hex(msbs
), hex(val
))
125 print("instr: %06x 0x%x %s %08x" % (4*startaddr
, insn
, code
, val
))
127 startaddr
= startaddr
& mask
130 def set_dmi(dmi
, addr
, data
):
131 yield dmi
.req_i
.eq(1)
132 yield dmi
.addr_i
.eq(addr
)
133 yield dmi
.din
.eq(data
)
136 ack
= yield dmi
.ack_o
141 yield dmi
.req_i
.eq(0)
142 yield dmi
.addr_i
.eq(0)
148 def get_dmi(dmi
, addr
):
149 yield dmi
.req_i
.eq(1)
150 yield dmi
.addr_i
.eq(addr
)
154 ack
= yield dmi
.ack_o
159 data
= yield dmi
.dout
# get data after ack valid for 1 cycle
160 yield dmi
.req_i
.eq(0)
161 yield dmi
.addr_i
.eq(0)
167 class HDLRunner(StateRunner
):
168 """HDLRunner: Implements methods for the setup, preparation, and
169 running of tests using nmigen HDL simulation.
172 def __init__(self
, dut
, m
, pspec
):
173 super().__init
__("hdl", HDLRunner
)
177 self
.pc_i
= Signal(32)
178 self
.svstate_i
= Signal(64)
180 #hard_reset = Signal(reset_less=True)
181 self
.issuer
= TestIssuerInternal(pspec
)
182 # use DMI RESET command instead, this does actually work though
183 # issuer = ResetInserter({'coresync': hard_reset,
184 # 'sync': hard_reset})(issuer)
185 m
.submodules
.issuer
= self
.issuer
186 self
.dmi
= self
.issuer
.dbg
.dmi
189 comb
+= self
.issuer
.pc_i
.data
.eq(self
.pc_i
)
190 comb
+= self
.issuer
.svstate_i
.data
.eq(self
.svstate_i
)
192 def prepare_for_test(self
, test
):
194 #print ("preparing for test name", test.name)
196 # set up bigendian (TODO: don't do this, use MSR)
197 yield self
.issuer
.core_bigendian_i
.eq(bigendian
)
204 #print ("end of test preparation", test.name)
206 def setup_during_test(self
):
207 # first run a manual hard-reset of the debug interface.
208 # core is counting down on a 3-clock delay at this point
209 yield self
.issuer
.dbg_rst_i
.eq(1)
211 yield self
.issuer
.dbg_rst_i
.eq(0)
213 # now run a DMI-interface reset. because DMI is running
214 # in dbgsync domain its reset is *NOT* connected to
215 # core reset (hence the dbg_rst_i blip, above)
216 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.STOP
)
220 def run_test(self
, instructions
):
221 """run_hdl_state - runs a TestIssuer nmigen HDL simulation
224 #print("starting test")
226 if self
.dut
.rom
is None:
227 imem
= self
.issuer
.imem
._get
_memory
()
228 #print("got memory", imem)
230 print("skipping memory get due to rom")
232 core
= self
.issuer
.core
233 dmi
= self
.issuer
.dbg
.dmi
234 pdecode2
= self
.issuer
.pdecode2
238 # establish the TestIssuer context (mem, regs etc)
240 pc
= 0 # start address
241 counter
= 0 # test to pause/start
243 # XXX for now, when ROM (run under wb_get) is detected,
244 # skip setup of memories. must be done a different way
246 yield from setup_i_memory(imem
, pc
, instructions
, self
.dut
.rom
)
247 yield from setup_tst_memory(l0
, self
.test
.mem
)
249 insert_into_rom(pc
, instructions
, self
.dut
.rom
)
250 print("about to setup regs")
251 yield from setup_regs(pdecode2
, core
, self
.test
)
252 #print("setup mem and regs done")
255 yield self
.pc_i
.eq(pc
)
256 yield self
.issuer
.pc_i
.ok
.eq(1)
258 # copy initial SVSTATE
259 initial_svstate
= copy(self
.test
.svstate
)
260 if isinstance(initial_svstate
, int):
261 initial_svstate
= SVP64State(initial_svstate
)
262 yield self
.svstate_i
.eq(initial_svstate
.value
)
263 yield self
.issuer
.svstate_i
.ok
.eq(1)
266 print("instructions", instructions
)
268 # before starting the simulation, set the core stop address to be
269 # just after the last instruction. if a load of an instruction is
270 # requested at this address, the core is immediately put into "halt"
271 # XXX: keep an eye out for in-order problems
272 yield from set_dmi(dmi
, DBGCore
.STOPADDR
, len(instructions
)*4)
274 # run the loop of the instructions on the current test
275 index
= (yield self
.issuer
.cur_state
.pc
) // 4
276 while index
< len(instructions
):
277 ins
, code
= instructions
[index
]
279 print("hdl instr: 0x{:X}".format(ins
& 0xffffffff))
285 yield from set_dmi(dmi
, DBGCore
.CTRL
,
287 yield self
.issuer
.pc_i
.ok
.eq(0) # no change PC after this
288 yield self
.issuer
.svstate_i
.ok
.eq(0) # ditto
292 counter
= counter
+ 1
294 # wait until executed
295 while not (yield self
.issuer
.insn_done
):
298 # okaaay long story: in overlap mode, PC is updated one cycle
300 if self
.dut
.allow_overlap
:
304 index
= (yield self
.issuer
.cur_state
.pc
) // 4
306 terminated
= yield self
.issuer
.dbg
.terminated_o
307 print("terminated", terminated
, index
, len(instructions
))
309 if index
< len(instructions
):
310 # Get HDL mem and state
311 state
= yield from TestState("hdl", core
, self
.dut
,
313 hdl_states
.append(state
)
315 if index
>= len(instructions
):
316 print("index over, send dmi stop")
318 yield from set_dmi(dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.STOP
)
321 # hmm really should use DMI status check here but hey it's quick
323 stopped
= yield self
.issuer
.dbg
.core_stop_o
329 terminated
= yield self
.issuer
.dbg
.terminated_o
330 print("terminated(2)", terminated
)
334 if self
.dut
.allow_overlap
: # or not self.dut.rom: ??
335 # wait until all settled
336 # XXX really this should be in DMI, which should in turn
337 # use issuer.any_busy to not send back "stopped" signal
338 while (yield self
.issuer
.any_busy
):
341 if self
.dut
.allow_overlap
:
342 # get last state, at end of run
343 state
= yield from TestState("hdl", core
, self
.dut
,
345 hdl_states
.append(state
)
350 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.STOP
)
354 # TODO, here is where the static (expected) results
355 # can be checked: register check (TODO, memory check)
356 # see https://bugs.libre-soc.org/show_bug.cgi?id=686#c51
357 # yield from check_regs(self, sim, core, test, code,
358 # >>>expected_data<<<)
361 cr
= yield from get_dmi(self
.dmi
, DBGCore
.CR
)
362 print("after test %s cr value %x" % (self
.test
.name
, cr
))
365 xer
= yield from get_dmi(self
.dmi
, DBGCore
.XER
)
366 print("after test %s XER value %x" % (self
.test
.name
, xer
))
368 # test of dmi reg get
369 for int_reg
in range(32):
370 yield from set_dmi(self
.dmi
, DBGCore
.GSPR_IDX
, int_reg
)
371 value
= yield from get_dmi(self
.dmi
, DBGCore
.GSPR_DATA
)
373 print("after test %s reg %2d value %x" %
374 (self
.test
.name
, int_reg
, value
))
377 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1 << DBGCtrl
.RESET
)
381 class TestRunner(TestRunnerBase
):
382 def __init__(self
, tst_data
, microwatt_mmu
=False, rom
=None,
383 svp64
=True, run_hdl
=True, run_sim
=True,
384 allow_overlap
=False):
387 super().__init
__(tst_data
, microwatt_mmu
=microwatt_mmu
,
389 svp64
=svp64
, run_hdl
=run_hdl
, run_sim
=run_sim
,
390 allow_overlap
=allow_overlap
)