CR = 0b1000 # CR (read only)
XER = 0b1001 # XER (read only) - note this is a TEMPORARY hack
SVSTATE = 0b1010 # SVSTATE register (read only for now)
+ STOPADDR = 0b1011 # Address at which the core automatically stops
# CTRL register (direct actions, write 1 to act, read back 0)
self.log_read_data_o = Signal(64)
self.log_write_addr_o = Signal(32)
+ # address at which the processor stops automatically
+ # set to 0xffffffffffffffff by default (impossible to reach)
+ self.stop_addr_o = Signal(64, reset=-1)
+
# Misc
self.terminated_o = Signal()
comb += dmi.dout.eq(d_cr.data)
with m.Case(DBGCore.XER):
comb += dmi.dout.eq(d_xer.data)
+ with m.Case(DBGCore.STOPADDR): # Halt PC
+ comb += dmi.dout.eq(self.stop_addr_o)
# DMI writes
# Reset the 1-cycle "do" signals
with m.Elif(dmi.addr_i == DBGCore.LOG_ADDR):
sync += log_dmi_addr.eq(dmi.din)
sync += do_dmi_log_rd.eq(1)
+
+ # set PC Halt address
+ with m.Elif(dmi.addr_i == DBGCore.STOPADDR):
+ sync += self.stop_addr_o.eq(dmi.din)
+
with m.Else():
# sync += Display("DMI read from " & to_string(dmi_addr))
pass
comb += d_gpr.addr.eq(gspr_index)
# Core control signals generated by the debug module
- comb += self.core_stop_o.eq(stopping & ~do_step)
+ comb += self.core_stop_o.eq((stopping & ~do_step) | self.terminate_i)
comb += self.core_rst_o.eq(do_reset)
comb += self.icache_rst_o.eq(do_icreset)
- comb += self.terminated_o.eq(terminated)
+ comb += self.terminated_o.eq(terminated | self.terminate_i)
# Logging RAM (none)
with m.If(core_rst):
m.d.sync += self.cur_state.eq(0)
+ # check halted condition: requested PC to execute matches DMI stop addr
+ # and immediately stop. address of 0xffff_ffff_ffff_ffff can never
+ # match
+ halted = Signal()
+ comb += halted.eq(dbg.stop_addr_o == dbg.state.pc)
+ with m.If(halted):
+ comb += dbg.core_stopped_i.eq(1)
+ comb += dbg.terminate_i.eq(1)
+
# PC and instruction from I-Memory
comb += self.pc_o.eq(cur_state.pc)
self.pc_changed = Signal() # note write to PC
# waiting (zzz)
with m.State("IDLE"):
- with m.If(~dbg.stopping_o & ~fetch_failed):
+ with m.If(~dbg.stopping_o & ~fetch_failed & ~dbg.core_stop_o):
comb += fetch_pc_o_ready.eq(1)
- with m.If(fetch_pc_i_valid & ~pdecode2.instr_fault):
+ with m.If(fetch_pc_i_valid & ~pdecode2.instr_fault
+ & ~dbg.core_stop_o):
# instruction allowed to go: start by reading the PC
# capture the PC and also drop it into Insn Memory
# we have joined a pair of combinatorial memory
print("instructions", instructions)
+ # before starting the simulation, set the core stop address to be
+ # just after the last instruction. if a load of an instruction is
+ # requested at this address, the core is immediately put into "halt"
+ # XXX: keep an eye out for in-order problems
+ yield from set_dmi(dmi, DBGCore.STOPADDR, len(instructions)*4)
+
# run the loop of the instructions on the current test
index = (yield self.issuer.cur_state.pc) // 4
while index < len(instructions):
yield
break
-
terminated = yield self.issuer.dbg.terminated_o
print("terminated(2)", terminated)
if terminated: