core_debug: Add support for detecting writes to a memory address
authorPaul Mackerras <paulus@ozlabs.org>
Mon, 28 Aug 2023 02:22:31 +0000 (12:22 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Fri, 15 Sep 2023 04:49:23 +0000 (14:49 +1000)
This adds a new type of stop trigger for the log buffer which triggers
when any byte(s) of a specified doubleword of memory are written.
The trigger logic snoops the wishbone for writes to the address
specified and stops the log 256 cycles later (same as for the
instruction fetch address trigger).  The trigger address is a real
address and sees DMA writes from devices as well as stores done by the
CPU.

The mw_debug command has a new 'mtrig' subcommand to set the trigger
and query its state.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
core.vhdl
core_debug.vhdl
scripts/mw_debug/mw_debug.c

index aef2d7f2177c2fb07ed29986df48fac46fab4afa..a5560690a087c6743f960ce5eccf9e354912fe85 100644 (file)
--- a/core.vhdl
+++ b/core.vhdl
@@ -521,6 +521,7 @@ begin
            core_stopped => dbg_core_is_stopped,
            nia => fetch1_to_icache.nia,
             msr => ctrl_debug.msr,
+            wb_snoop_in => wb_snoop_in,
             dbg_gpr_req => dbg_gpr_req,
             dbg_gpr_ack => dbg_gpr_ack,
             dbg_gpr_addr => dbg_gpr_addr,
index afebc7c45dec03db0be78826654b900533a7cb04..c7215ff43bacdfc89ddf0404f9fea2fb5861a1bf 100644 (file)
@@ -5,6 +5,7 @@ use ieee.numeric_std.all;
 library work;
 use work.utils.all;
 use work.common.all;
+use work.wishbone_types.all;
 
 entity core_debug is
     generic (
@@ -32,6 +33,7 @@ entity core_debug is
         core_stopped    : in std_ulogic;
         nia             : in std_ulogic_vector(63 downto 0);
         msr             : in std_ulogic_vector(63 downto 0);
+        wb_snoop_in     : in wishbone_master_out := wishbone_master_out_init;
 
         -- GPR/FPR register read port
         dbg_gpr_req     : out std_ulogic;
@@ -104,6 +106,7 @@ architecture behave of core_debug is
     constant DBG_CORE_LOG_ADDR       : std_ulogic_vector(3 downto 0) := "0110";
     constant DBG_CORE_LOG_DATA       : std_ulogic_vector(3 downto 0) := "0111";
     constant DBG_CORE_LOG_TRIGGER    : std_ulogic_vector(3 downto 0) := "1000";
+    constant DBG_CORE_LOG_MTRIGGER   : std_ulogic_vector(3 downto 0) := "1001";
 
     constant LOG_INDEX_BITS : natural := log2(LOG_LENGTH);
 
@@ -125,7 +128,11 @@ architecture behave of core_debug is
     signal log_dmi_addr        : std_ulogic_vector(31 downto 0) := (others => '0');
     signal log_dmi_data        : std_ulogic_vector(63 downto 0) := (others => '0');
     signal log_dmi_trigger     : std_ulogic_vector(63 downto 0) := (others => '0');
+    signal log_mem_trigger     : std_ulogic_vector(63 downto 0) := (others => '0');
     signal do_log_trigger      : std_ulogic := '0';
+    signal do_log_mtrigger     : std_ulogic := '0';
+    signal trigger_was_log     : std_ulogic := '0';
+    signal trigger_was_mem     : std_ulogic := '0';
     signal do_dmi_log_rd       : std_ulogic;
     signal dmi_read_log_data   : std_ulogic;
     signal dmi_read_log_data_1 : std_ulogic;
@@ -156,6 +163,7 @@ begin
         log_write_addr & log_dmi_addr when DBG_CORE_LOG_ADDR,
         log_dmi_data    when DBG_CORE_LOG_DATA,
         log_dmi_trigger when DBG_CORE_LOG_TRIGGER,
+        log_mem_trigger when DBG_CORE_LOG_MTRIGGER,
         (others => '0') when others;
 
     -- DMI writes
@@ -174,16 +182,27 @@ begin
                 log_trigger_delay <= 0;
                 gspr_index <= (others => '0');
                 log_dmi_addr <= (others => '0');
+                trigger_was_log <= '0';
+                trigger_was_mem <= '0';
             else
-                if do_log_trigger = '1' or log_trigger_delay /= 0 then
+                if do_log_trigger = '1' or do_log_mtrigger = '1' or log_trigger_delay /= 0 then
                     if log_trigger_delay = 255 or
                         (LOG_LENGTH < 1024 and log_trigger_delay = LOG_LENGTH / 4) then
-                        log_dmi_trigger(1) <= '1';
+                        log_dmi_trigger(1) <= trigger_was_log;
+                        log_mem_trigger(1) <= trigger_was_mem;
                         log_trigger_delay <= 0;
+                        trigger_was_log <= '0';
+                        trigger_was_mem <= '0';
                     else
                         log_trigger_delay <= log_trigger_delay + 1;
                     end if;
                 end if;
+                if do_log_trigger = '1' then
+                    trigger_was_log <= '1';
+                end if;
+                if do_log_mtrigger = '1' then
+                    trigger_was_mem <= '1';
+                end if;
                 -- Edge detect on dmi_req for 1-shot pulses
                 dmi_req_1 <= dmi_req;
                 if dmi_req = '1' and dmi_req_1 = '0' then
@@ -217,6 +236,8 @@ begin
                             do_dmi_log_rd <= '1';
                         elsif dmi_addr = DBG_CORE_LOG_TRIGGER then
                             log_dmi_trigger <= dmi_din;
+                        elsif dmi_addr = DBG_CORE_LOG_MTRIGGER then
+                            log_mem_trigger <= dmi_din;
                         end if;
                     else
                         report("DMI read from " & to_string(dmi_addr));
@@ -347,7 +368,7 @@ begin
 
     begin
         -- Use MSB of read addresses to stop the logging
-        log_wr_enable <= not (log_read_addr(31) or log_dmi_addr(31) or log_dmi_trigger(1));
+        log_wr_enable <= not (log_read_addr(31) or log_dmi_addr(31) or log_dmi_trigger(1) or log_mem_trigger(1));
 
         log_ram: process(clk)
         begin
@@ -398,6 +419,13 @@ begin
                     log_dmi_trigger(0) = '1' then
                     do_log_trigger <= '1';
                 end if;
+                do_log_mtrigger <= '0';
+                if (wb_snoop_in.cyc and wb_snoop_in.stb and wb_snoop_in.we) = '1' and
+                    wb_snoop_in.adr = log_mem_trigger(wishbone_addr_bits + wishbone_log2_width - 1
+                                                      downto wishbone_log2_width) and
+                    log_mem_trigger(0) = '1' then
+                    do_log_mtrigger <= '1';
+                end if;
             end if;
         end process;
         log_write_addr(LOG_INDEX_BITS - 1 downto 0) <= std_ulogic_vector(log_wr_ptr);
index 81e80941609bab183fb307b61ee21cc78fa8f3fd..07c10566b1e41738b4fabf25fb8306d03ccba224 100644 (file)
@@ -45,6 +45,7 @@
 #define DBG_LOG_ADDR           0x16
 #define DBG_LOG_DATA           0x17
 #define DBG_LOG_TRIGGER                0x18
+#define DBG_LOG_MTRIGGER       0x19
 
 static bool debug;
 
@@ -766,6 +767,28 @@ static void ltrig_set(uint64_t addr)
        check(dmi_write(DBG_LOG_TRIGGER, (addr & ~(uint64_t)2) | 1), "writing LOG_TRIGGER");
 }
 
+static void mtrig_show(void)
+{
+       uint64_t trig;
+
+       check(dmi_read(DBG_LOG_MTRIGGER, &trig), "reading LOG_MTRIGGER");
+       if (trig & 1)
+               printf("log memory stop trigger at %" PRIx64, trig & ~3);
+       else
+               printf("log memory stop trigger disabled");
+       printf(", %striggered\n", (trig & 2? "": "not "));
+}
+
+static void mtrig_off(void)
+{
+       check(dmi_write(DBG_LOG_MTRIGGER, 0), "writing LOG_MTRIGGER");
+}
+
+static void mtrig_set(uint64_t addr)
+{
+       check(dmi_write(DBG_LOG_MTRIGGER, (addr & ~(uint64_t)2) | 1), "writing LOG_MTRIGGER");
+}
+
 static void usage(const char *cmd)
 {
        fprintf(stderr, "Usage: %s -b <jtag|ecp5|sim> <command> <args>\n", cmd);
@@ -798,6 +821,9 @@ static void usage(const char *cmd)
        fprintf(stderr, "  ltrig                        show logging stop trigger status\n");
        fprintf(stderr, "  ltrig off                    clear logging stop trigger address\n");
        fprintf(stderr, "  ltrig <addr>                 set logging stop trigger address\n");
+       fprintf(stderr, "  mtrig                        show logging stop trigger status\n");
+       fprintf(stderr, "  mtrig off                    clear logging stop trigger address\n");
+       fprintf(stderr, "  mtrig <addr>                 set logging stop trigger address\n");
 
        fprintf(stderr, "\n");
        fprintf(stderr, " JTAG:\n");
@@ -967,6 +993,17 @@ int main(int argc, char *argv[])
                                addr = strtoul(argv[i], NULL, 16);
                                ltrig_set(addr);
                        }
+               } else if (strcmp(argv[i], "mtrig") == 0) {
+                       uint64_t addr;
+
+                       if ((i+1) >= argc)
+                               mtrig_show();
+                       else if (strcmp(argv[++i], "off") == 0)
+                               mtrig_off();
+                       else {
+                               addr = strtoul(argv[i], NULL, 16);
+                               mtrig_set(addr);
+                       }
                } else {
                        fprintf(stderr, "Unknown command %s\n", argv[i]);
                        usage(argv[0]);