core_debug: Add support for detecting writes to a memory address

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>
pull/420/head
Paul Mackerras 1 year ago
parent a2890745d5
commit 4bef477e29

@ -521,6 +521,7 @@ begin
core_stopped => dbg_core_is_stopped, core_stopped => dbg_core_is_stopped,
nia => fetch1_to_icache.nia, nia => fetch1_to_icache.nia,
msr => ctrl_debug.msr, msr => ctrl_debug.msr,
wb_snoop_in => wb_snoop_in,
dbg_gpr_req => dbg_gpr_req, dbg_gpr_req => dbg_gpr_req,
dbg_gpr_ack => dbg_gpr_ack, dbg_gpr_ack => dbg_gpr_ack,
dbg_gpr_addr => dbg_gpr_addr, dbg_gpr_addr => dbg_gpr_addr,

@ -5,6 +5,7 @@ use ieee.numeric_std.all;
library work; library work;
use work.utils.all; use work.utils.all;
use work.common.all; use work.common.all;
use work.wishbone_types.all;


entity core_debug is entity core_debug is
generic ( generic (
@ -32,6 +33,7 @@ entity core_debug is
core_stopped : in std_ulogic; core_stopped : in std_ulogic;
nia : in std_ulogic_vector(63 downto 0); nia : in std_ulogic_vector(63 downto 0);
msr : 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 -- GPR/FPR register read port
dbg_gpr_req : out std_ulogic; 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_ADDR : std_ulogic_vector(3 downto 0) := "0110";
constant DBG_CORE_LOG_DATA : std_ulogic_vector(3 downto 0) := "0111"; 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_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); 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_addr : std_ulogic_vector(31 downto 0) := (others => '0');
signal log_dmi_data : std_ulogic_vector(63 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_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_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 do_dmi_log_rd : std_ulogic;
signal dmi_read_log_data : std_ulogic; signal dmi_read_log_data : std_ulogic;
signal dmi_read_log_data_1 : 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_write_addr & log_dmi_addr when DBG_CORE_LOG_ADDR,
log_dmi_data when DBG_CORE_LOG_DATA, log_dmi_data when DBG_CORE_LOG_DATA,
log_dmi_trigger when DBG_CORE_LOG_TRIGGER, log_dmi_trigger when DBG_CORE_LOG_TRIGGER,
log_mem_trigger when DBG_CORE_LOG_MTRIGGER,
(others => '0') when others; (others => '0') when others;


-- DMI writes -- DMI writes
@ -174,16 +182,27 @@ begin
log_trigger_delay <= 0; log_trigger_delay <= 0;
gspr_index <= (others => '0'); gspr_index <= (others => '0');
log_dmi_addr <= (others => '0'); log_dmi_addr <= (others => '0');
trigger_was_log <= '0';
trigger_was_mem <= '0';
else 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 if log_trigger_delay = 255 or
(LOG_LENGTH < 1024 and log_trigger_delay = LOG_LENGTH / 4) then (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; log_trigger_delay <= 0;
trigger_was_log <= '0';
trigger_was_mem <= '0';
else else
log_trigger_delay <= log_trigger_delay + 1; log_trigger_delay <= log_trigger_delay + 1;
end if; end if;
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 -- Edge detect on dmi_req for 1-shot pulses
dmi_req_1 <= dmi_req; dmi_req_1 <= dmi_req;
if dmi_req = '1' and dmi_req_1 = '0' then if dmi_req = '1' and dmi_req_1 = '0' then
@ -217,6 +236,8 @@ begin
do_dmi_log_rd <= '1'; do_dmi_log_rd <= '1';
elsif dmi_addr = DBG_CORE_LOG_TRIGGER then elsif dmi_addr = DBG_CORE_LOG_TRIGGER then
log_dmi_trigger <= dmi_din; log_dmi_trigger <= dmi_din;
elsif dmi_addr = DBG_CORE_LOG_MTRIGGER then
log_mem_trigger <= dmi_din;
end if; end if;
else else
report("DMI read from " & to_string(dmi_addr)); report("DMI read from " & to_string(dmi_addr));
@ -347,7 +368,7 @@ begin


begin begin
-- Use MSB of read addresses to stop the logging -- 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) log_ram: process(clk)
begin begin
@ -398,6 +419,13 @@ begin
log_dmi_trigger(0) = '1' then log_dmi_trigger(0) = '1' then
do_log_trigger <= '1'; do_log_trigger <= '1';
end if; 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 if;
end process; end process;
log_write_addr(LOG_INDEX_BITS - 1 downto 0) <= std_ulogic_vector(log_wr_ptr); log_write_addr(LOG_INDEX_BITS - 1 downto 0) <= std_ulogic_vector(log_wr_ptr);

@ -45,6 +45,7 @@
#define DBG_LOG_ADDR 0x16 #define DBG_LOG_ADDR 0x16
#define DBG_LOG_DATA 0x17 #define DBG_LOG_DATA 0x17
#define DBG_LOG_TRIGGER 0x18 #define DBG_LOG_TRIGGER 0x18
#define DBG_LOG_MTRIGGER 0x19


static bool debug; 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"); 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) static void usage(const char *cmd)
{ {
fprintf(stderr, "Usage: %s -b <jtag|ecp5|sim> <command> <args>\n", 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 show logging stop trigger status\n");
fprintf(stderr, " ltrig off clear logging stop trigger address\n"); fprintf(stderr, " ltrig off clear logging stop trigger address\n");
fprintf(stderr, " ltrig <addr> set 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, "\n");
fprintf(stderr, " JTAG:\n"); fprintf(stderr, " JTAG:\n");
@ -967,6 +993,17 @@ int main(int argc, char *argv[])
addr = strtoul(argv[i], NULL, 16); addr = strtoul(argv[i], NULL, 16);
ltrig_set(addr); 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 { } else {
fprintf(stderr, "Unknown command %s\n", argv[i]); fprintf(stderr, "Unknown command %s\n", argv[i]);
usage(argv[0]); usage(argv[0]);

Loading…
Cancel
Save