962d47a20e9e11eaf992c91c5e424c4c7bbdae5f
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.
123 def __init__(self
, dut
, m
, pspec
):
124 super().__init
__("hdl", HDLRunner
)
127 self
.pc_i
= Signal(32)
128 self
.svstate_i
= Signal(64)
130 #hard_reset = Signal(reset_less=True)
131 self
.issuer
= TestIssuerInternal(pspec
)
132 # use DMI RESET command instead, this does actually work though
133 #issuer = ResetInserter({'coresync': hard_reset,
134 # 'sync': hard_reset})(issuer)
135 m
.submodules
.issuer
= self
.issuer
136 self
.dmi
= self
.issuer
.dbg
.dmi
139 comb
+= self
.issuer
.pc_i
.data
.eq(self
.pc_i
)
140 comb
+= self
.issuer
.svstate_i
.data
.eq(self
.svstate_i
)
142 def prepare_for_test(self
, test
):
145 # set up bigendian (TODO: don't do this, use MSR)
146 yield self
.issuer
.core_bigendian_i
.eq(bigendian
)
154 def setup_during_test(self
):
155 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1<<DBGCtrl
.STOP
)
158 def run_test(self
, instructions
):
159 """run_hdl_state - runs a TestIssuer nmigen HDL simulation
162 imem
= self
.issuer
.imem
._get
_memory
()
163 core
= self
.issuer
.core
164 dmi
= self
.issuer
.dbg
.dmi
165 pdecode2
= self
.issuer
.pdecode2
169 # establish the TestIssuer context (mem, regs etc)
171 pc
= 0 # start address
172 counter
= 0 # test to pause/start
174 yield from setup_i_memory(imem
, pc
, instructions
)
175 yield from setup_tst_memory(l0
, self
.test
.mem
)
176 yield from setup_regs(pdecode2
, core
, self
.test
)
179 yield self
.pc_i
.eq(pc
)
180 yield self
.issuer
.pc_i
.ok
.eq(1)
182 # copy initial SVSTATE
183 initial_svstate
= copy(self
.test
.svstate
)
184 if isinstance(initial_svstate
, int):
185 initial_svstate
= SVP64State(initial_svstate
)
186 yield self
.svstate_i
.eq(initial_svstate
.value
)
187 yield self
.issuer
.svstate_i
.ok
.eq(1)
190 print("instructions", instructions
)
192 # run the loop of the instructions on the current test
193 index
= (yield self
.issuer
.cur_state
.pc
) // 4
194 while index
< len(instructions
):
195 ins
, code
= instructions
[index
]
197 print("hdl instr: 0x{:X}".format(ins
& 0xffffffff))
203 yield from set_dmi(dmi
, DBGCore
.CTRL
,
205 yield self
.issuer
.pc_i
.ok
.eq(0) # no change PC after this
206 yield self
.issuer
.svstate_i
.ok
.eq(0) # ditto
210 counter
= counter
+ 1
212 # wait until executed
213 while not (yield self
.issuer
.insn_done
):
216 # okaaay long story: in overlap mode, PC is updated one cycle
218 if self
.dut
.allow_overlap
:
222 index
= (yield self
.issuer
.cur_state
.pc
) // 4
224 terminated
= yield self
.issuer
.dbg
.terminated_o
225 print("terminated", terminated
, index
, len(instructions
))
227 if index
< len(instructions
):
228 # Get HDL mem and state
229 state
= yield from TestState("hdl", core
, self
.dut
,
231 hdl_states
.append(state
)
233 if index
>= len(instructions
):
234 print ("index over, send dmi stop")
236 yield from set_dmi(dmi
, DBGCore
.CTRL
, 1<<DBGCtrl
.STOP
)
240 terminated
= yield self
.issuer
.dbg
.terminated_o
241 print("terminated(2)", terminated
)
245 if self
.dut
.allow_overlap
:
246 # wait until all settled
247 # XXX really this should be in DMI, which should in turn
248 # use issuer.any_busy to not send back "stopped" signal
249 while (yield self
.issuer
.any_busy
):
252 if self
.dut
.allow_overlap
:
253 # get last state, at end of run
254 state
= yield from TestState("hdl", core
, self
.dut
,
256 hdl_states
.append(state
)
261 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1<<DBGCtrl
.STOP
)
265 # TODO, here is where the static (expected) results
266 # can be checked: register check (TODO, memory check)
267 # see https://bugs.libre-soc.org/show_bug.cgi?id=686#c51
268 # yield from check_regs(self, sim, core, test, code,
269 # >>>expected_data<<<)
272 cr
= yield from get_dmi(self
.dmi
, DBGCore
.CR
)
273 print("after test %s cr value %x" % (self
.test
.name
, cr
))
276 xer
= yield from get_dmi(self
.dmi
, DBGCore
.XER
)
277 print("after test %s XER value %x" % (self
.test
.name
, xer
))
279 # test of dmi reg get
280 for int_reg
in range(32):
281 yield from set_dmi(self
.dmi
, DBGCore
.GSPR_IDX
, int_reg
)
282 value
= yield from get_dmi(self
.dmi
, DBGCore
.GSPR_DATA
)
284 print("after test %s reg %2d value %x" %
285 (self
.test
.name
, int_reg
, value
))
288 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1<<DBGCtrl
.RESET
)
292 class TestRunner(TestRunnerBase
):
293 def __init__(self
, tst_data
, microwatt_mmu
=False, rom
=None,
294 svp64
=True, run_hdl
=True, run_sim
=True,
295 allow_overlap
=False):
298 super().__init
__(tst_data
, microwatt_mmu
=microwatt_mmu
,
300 svp64
=svp64
, run_hdl
=run_hdl
, run_sim
=run_sim
,
301 allow_overlap
=allow_overlap
)