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 soc
.experiment
.test
.test_mmu_dcache
import wb_get
30 from openpower
.test
.state
import TestState
, StateRunner
31 from openpower
.test
.runner
import TestRunnerBase
34 def setup_i_memory(imem
, startaddr
, instructions
):
36 print("insn before, init mem", mem
.depth
, mem
.width
, mem
,
38 for i
in range(mem
.depth
):
39 yield mem
._array
[i
].eq(0)
41 startaddr
//= 4 # instructions are 32-bit
44 for ins
in instructions
:
45 if isinstance(ins
, tuple):
49 insn
= insn
& 0xffffffff
50 yield mem
._array
[startaddr
].eq(insn
)
53 print("instr: %06x 0x%x %s" % (4*startaddr
, insn
, code
))
55 startaddr
= startaddr
& mask
60 for ins
in instructions
:
61 if isinstance(ins
, tuple):
65 insn
= insn
& 0xffffffff
66 msbs
= (startaddr
>> 1) & mask
67 val
= yield mem
._array
[msbs
]
69 print("before set", hex(4*startaddr
),
70 hex(msbs
), hex(val
), hex(insn
))
71 lsb
= 1 if (startaddr
& 1) else 0
72 val
= (val |
(insn
<< (lsb
*32)))
74 yield mem
._array
[msbs
].eq(val
)
77 print("after set", hex(4*startaddr
), hex(msbs
), hex(val
))
78 print("instr: %06x 0x%x %s %08x" % (4*startaddr
, insn
, code
, val
))
80 startaddr
= startaddr
& mask
83 def set_dmi(dmi
, addr
, data
):
85 yield dmi
.addr_i
.eq(addr
)
86 yield dmi
.din
.eq(data
)
95 yield dmi
.addr_i
.eq(0)
101 def get_dmi(dmi
, addr
):
102 yield dmi
.req_i
.eq(1)
103 yield dmi
.addr_i
.eq(addr
)
107 ack
= yield dmi
.ack_o
112 data
= yield dmi
.dout
# get data after ack valid for 1 cycle
113 yield dmi
.req_i
.eq(0)
114 yield dmi
.addr_i
.eq(0)
120 class HDLRunner(StateRunner
):
121 """HDLRunner: Implements methods for the setup, preparation, and
122 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 # wait until all settled
247 #while (yield self.issuer.any_busy):
250 if self
.dut
.allow_overlap
:
251 # get last state, at end of run
252 state
= yield from TestState("hdl", core
, self
.dut
,
254 hdl_states
.append(state
)
259 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1<<DBGCtrl
.STOP
)
263 # TODO, here is where the static (expected) results
264 # can be checked: register check (TODO, memory check)
265 # see https://bugs.libre-soc.org/show_bug.cgi?id=686#c51
266 # yield from check_regs(self, sim, core, test, code,
267 # >>>expected_data<<<)
270 cr
= yield from get_dmi(self
.dmi
, DBGCore
.CR
)
271 print("after test %s cr value %x" % (self
.test
.name
, cr
))
274 xer
= yield from get_dmi(self
.dmi
, DBGCore
.XER
)
275 print("after test %s XER value %x" % (self
.test
.name
, xer
))
277 # test of dmi reg get
278 for int_reg
in range(32):
279 yield from set_dmi(self
.dmi
, DBGCore
.GSPR_IDX
, int_reg
)
280 value
= yield from get_dmi(self
.dmi
, DBGCore
.GSPR_DATA
)
282 print("after test %s reg %2d value %x" %
283 (self
.test
.name
, int_reg
, value
))
286 yield from set_dmi(self
.dmi
, DBGCore
.CTRL
, 1<<DBGCtrl
.RESET
)
290 class TestRunner(TestRunnerBase
):
291 def __init__(self
, tst_data
, microwatt_mmu
=False, rom
=None,
292 svp64
=True, run_hdl
=True, run_sim
=True,
293 allow_overlap
=False):
296 super().__init
__(tst_data
, microwatt_mmu
=microwatt_mmu
,
298 svp64
=svp64
, run_hdl
=run_hdl
, run_sim
=run_sim
,
299 allow_overlap
=allow_overlap
)