add DMI STOPADDR register and use it in HDLRunner to halt simulations
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 19 Dec 2021 15:47:13 +0000 (15:47 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 19 Dec 2021 15:47:13 +0000 (15:47 +0000)
at exactly the right point.  very useful also for gdb hardware-level
breakpoints

src/soc/debug/dmi.py
src/soc/simple/issuer.py
src/soc/simple/test/test_runner.py

index 8a6686df5c26af6d26052598552d0e7ad3fb4921..8a3aaea504d7aa8290a2da6a54e619190f6f026e 100644 (file)
@@ -26,6 +26,7 @@ class DBGCore:
     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)
@@ -120,6 +121,10 @@ class CoreDebug(Elaboratable):
         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()
 
@@ -191,6 +196,8 @@ class CoreDebug(Elaboratable):
                 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
@@ -231,6 +238,11 @@ class CoreDebug(Elaboratable):
                 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
@@ -255,10 +267,10 @@ class CoreDebug(Elaboratable):
         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)
 
index 7c69eef9d18c4d6606eac129f1c0dce4cb8d0052..15391fe80c68fa3f8768c297761501c6adeea43a 100644 (file)
@@ -525,6 +525,15 @@ class TestIssuerBase(Elaboratable):
         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
@@ -710,9 +719,10 @@ class FetchFSM(ControlBase):
 
             # 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
index 3f637059fe50fc278128d966f147c804bb80bc2c..e83a39b729ad3be5db70b2f8e5e0abc234a70de9 100644 (file)
@@ -265,6 +265,12 @@ class HDLRunner(StateRunner):
 
         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):
@@ -320,7 +326,6 @@ class HDLRunner(StateRunner):
                     yield
                 break
 
-
             terminated = yield self.issuer.dbg.terminated_o
             print("terminated(2)", terminated)
             if terminated: