From patchwork Fri Apr 3 20:35:55 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiri Gaisler X-Patchwork-Id: 6005 X-Patchwork-Delegate: vapier@gentoo.org Received: (qmail 26195 invoked by alias); 3 Apr 2015 20:36:26 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 26049 invoked by uid 89); 3 Apr 2015 20:36:24 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.9 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.2 X-HELO: bin-vsp-out-01.atm.binero.net Received: from vsp-unauthed01.binero.net (HELO bin-vsp-out-01.atm.binero.net) (195.74.38.225) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Fri, 03 Apr 2015 20:36:21 +0000 X-Halon-ID: 1881103d-da41-11e4-8277-005056917a89 Authorized-sender: jiri@gaisler.se Received: from localhost.localdomain (unknown [78.68.139.28]) by bin-vsp-out-01.atm.binero.net (Halon Mail Gateway) with ESMTPSA; Fri, 3 Apr 2015 22:36:24 +0200 (CEST) From: Jiri Gaisler To: gdb-patches@sourceware.org Cc: Jiri Gaisler Subject: [PATCH v5 8/9] sim/erc32: Add data watchpoint support. Date: Fri, 3 Apr 2015 22:35:55 +0200 Message-Id: <1428093356-7296-9-git-send-email-jiri@gaisler.se> In-Reply-To: <1428093356-7296-1-git-send-email-jiri@gaisler.se> References: <1428093356-7296-1-git-send-email-jiri@gaisler.se> X-IsSubscribed: yes Add watchpoint to all SPARC targets (erc32, leon2, leon3). * exec.c (wpmask): New function to calculate address mask. (dispatch_instruction): send WPT_TRAP when breakpoint is hit. Check on load and store instructions. (execute_trap): convert special traps to gdb signals. * func.c (exec_cmd): add watchpoint commands to the command parser. (check_wpr, check_wpw): new functions to check for watchpoint hits. * interf.c (run_sim): Move initialization of sis_gdb_break to run_sim(). * sis.c (run_sim): halt simulation on watchpoint hit. (main): print watchpoint information when simulator stops. * sis.h: add watchpoint variables to simulator state struct, new function defines. --- sim/erc32/exec.c | 56 ++++++++++++++++++++++++++++------- sim/erc32/func.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++- sim/erc32/interf.c | 3 +- sim/erc32/sis.c | 34 +++++++++++++++------ sim/erc32/sis.h | 23 ++++++++++++++- 5 files changed, 180 insertions(+), 23 deletions(-) diff --git a/sim/erc32/exec.c b/sim/erc32/exec.c index 2a7248d..6c536ba 100644 --- a/sim/erc32/exec.c +++ b/sim/erc32/exec.c @@ -395,6 +395,20 @@ extract_byte_signed (uint32 data, uint32 address) return tmp; } +/* Decode watchpoint address mask from opcode. Not correct for LDST, + SWAP and STFSR but watchpoints will work anyway. */ + +static unsigned char +wpmask (uint32 op3) +{ + switch (op3 & 3) { + case 0: return 3; /* word */ + case 1: return 0; /* byte */ + case 2: return 1; /* half-word */ + case 3: return 7; /* double word */ + } +} + int dispatch_instruction(sregs) struct pstate *sregs; @@ -698,6 +712,12 @@ dispatch_instruction(sregs) } if (eicc & 1) { sregs->trap = (0x80 | ((rs1 + operand2) & 0x7f)); + if ((sregs->trap == 129) && (sis_gdb_break) && + (sregs->inst == 0x91d02001)) + { + sregs->trap = WPT_TRAP; + sregs->bphit = 1; + } } break; @@ -1211,18 +1231,25 @@ dispatch_instruction(sregs) address = rs1 + operand2; - if (sregs->psr & PSR_S) - asi = 11; - else - asi = 10; - if (op3 & 4) { sregs->icnt = T_ST; /* Set store instruction count */ + if (sregs->wpwnum) { + if (sregs->wphit = check_wpw (sregs, address, wpmask(op3))) { + sregs->trap = WPT_TRAP; + break; + } + } #ifdef STAT sregs->nstore++; #endif } else { sregs->icnt = T_LD; /* Set load instruction count */ + if (sregs->wprnum) { + if (sregs->wphit = check_wpr (sregs, address, wpmask(op3))) { + sregs->trap = WPT_TRAP; + break; + } + } #ifdef STAT sregs->nload++; #endif @@ -2128,12 +2155,20 @@ execute_trap(sregs) { int32 cwp; - if (sregs->trap == 256) { - sregs->pc = 0; - sregs->npc = 4; - sregs->trap = 0; - } else if (sregs->trap == 257) { + if (sregs->trap >= 256) { + switch (sregs->trap) { + case 256: + sregs->pc = 0; + sregs->npc = 4; + sregs->trap = 0; + break; + case ERROR_TRAP: return ERROR; + case WPT_TRAP: + return WPT_HIT; + default: + return WPT_HIT; + } } else { if ((sregs->psr & PSR_ET) == 0) @@ -2226,6 +2261,7 @@ init_regs(sregs) sregs->fpu_pres = !nfp; set_fsr(sregs->fsr); sregs->bphit = 0; + sregs->wphit = 0; sregs->ildreg = 0; sregs->ildtime = 0; diff --git a/sim/erc32/func.c b/sim/erc32/func.c index 86e7a0a..11f6fdd 100644 --- a/sim/erc32/func.c +++ b/sim/erc32/func.c @@ -56,7 +56,9 @@ uint32 last_load_addr = 0; int nouartrx = 0; host_callback *sim_callback; const struct memsys *ms = &erc32sys; -int cputype = 0; /* 0 = erc32, 3 = leon3 */ +int cputype = 0; /* 0 = erc32, 2 = leon2,3 = leon3 */ +int sis_gdb_break; + #ifdef ERRINJ uint32 errcnt = 0; @@ -611,6 +613,53 @@ exec_cmd(struct pstate *sregs, const char *cmd) stat = run_sim(sregs, UINT64_MAX, 0); daddr = sregs->pc; ms->sim_halt (); + } else if (strncmp (cmd1, "wp", clen) == 0) { + for (i = 0; i < sregs->wprnum; i++) { + printf (" %d : 0x%08x (read)\n", i + 1, sregs->wprs[i]); + } + for (i = 0; i < sregs->wpwnum; i++) { + printf (" %d : 0x%08x (write)\n", i + 1, sregs->wpws[i]); + } + } else if (strncmp (cmd1, "+wpr", clen) == 0) { + if ((cmd1 = strtok (NULL, " \t\n\r")) != NULL) { + sregs->wprs[sregs->wprnum] = VAL (cmd1) & ~0x3; + sregs->wprm[sregs->wprnum] = 3; + printf ("added read watchpoint %d at 0x%08x\n", + sregs->wprnum + 1, sregs->wprs[sregs->wprnum]); + sregs->wprnum += 1; + } + } else if (strncmp (cmd1, "-wpr", clen) == 0) { + if ((cmd1 = strtok (NULL, " \t\n\r")) != NULL) { + i = VAL (cmd1) - 1; + if ((i >= 0) && (i < sregs->wprnum)) { + printf ("deleted read watchpoint %d at 0x%08x\n", i + 1, + sregs->wprs[i]); + for (; i < sregs->wprnum - 1; i++) { + sregs->wprs[i] = sregs->wprs[i + 1]; + } + sregs->wprnum -= 1; + } + } + } else if (strncmp (cmd1, "+wpw", clen) == 0) { + if ((cmd1 = strtok (NULL, " \t\n\r")) != NULL) { + sregs->wpws[sregs->wpwnum] = VAL (cmd1) & ~0x3; + sregs->wpwm[sregs->wpwnum] = 3; + printf ("added write watchpoint %d at 0x%08x\n", + sregs->wpwnum + 1, sregs->wpws[sregs->wpwnum]); + sregs->wpwnum += 1; + } + } else if (strncmp (cmd1, "-wpw", clen) == 0) { + if ((cmd1 = strtok (NULL, " \t\n\r")) != NULL) { + i = VAL (cmd1) - 1; + if ((i >= 0) && (i < sregs->wpwnum)) { + printf ("deleted write watchpoint %d at 0x%08x\n", i + 1, + sregs->wpws[i]); + for (; i < sregs->wpwnum - 1; i++) { + sregs->wpws[i] = sregs->wpws[i + 1]; + } + sregs->wpwnum -= 1; + } + } } else printf("syntax error\n"); } @@ -701,6 +750,8 @@ init_bpt(sregs) struct pstate *sregs; { sregs->bptnum = 0; + sregs->wprnum = 0; + sregs->wpwnum = 0; sregs->histlen = 0; sregs->histind = 0; sregs->histbuf = NULL; @@ -1008,6 +1059,40 @@ check_bpt(sregs) return 0; } +int +check_wpr(struct pstate *sregs, int32 address, unsigned char mask) +{ + int32 i, msk; + + for (i = 0; i < sregs->wprnum; i++) { + msk = ~(mask | sregs->wprm[i]); + if (((address ^ sregs->wprs[i]) & msk) == 0) { + sregs->wpaddress = address; + if (sregs->wphit) + return 0; + return WPT_HIT; + } + } + return 0; +} + +int +check_wpw(struct pstate *sregs, int32 address, unsigned char mask) +{ + int32 i, msk; + + for (i = 0; i < sregs->wpwnum; i++) { + msk = ~(mask | sregs->wpwm[i]); + if (((address ^ sregs->wpws[i]) & msk) == 0) { + sregs->wpaddress = address; + if (sregs->wphit) + return 0; + return WPT_HIT; + } + } + return 0; +} + void reset_all() { diff --git a/sim/erc32/interf.c b/sim/erc32/interf.c index e254d87..bd4b017 100644 --- a/sim/erc32/interf.c +++ b/sim/erc32/interf.c @@ -36,8 +36,6 @@ #define PSR_CWP 0x7 -int sis_gdb_break = 1; - int run_sim(sregs, icount, dis) struct pstate *sregs; @@ -149,6 +147,7 @@ sim_open (kind, callback, abfd, argv) int freq = 0; sim_callback = callback; + sis_gdb_break = 1; while (argv[argc]) argc++; diff --git a/sim/erc32/sis.c b/sim/erc32/sis.c index 7f384e7..1fb9d1d 100644 --- a/sim/erc32/sis.c +++ b/sim/erc32/sis.c @@ -75,29 +75,36 @@ run_sim(sregs, icount, dis) sregs->trap = I_ACC_EXC; } else { if (deb) { - if ((sregs->bphit = check_bpt(sregs)) != 0) { - ms->restore_stdio (); - return BPT_HIT; - } - if (sregs->histlen) { + if (sregs->histlen) { sregs->histbuf[sregs->histind].addr = sregs->pc; sregs->histbuf[sregs->histind].time = ebase.simtime; sregs->histind++; if (sregs->histind >= sregs->histlen) - sregs->histind = 0; + sregs->histind = 0; } if (dis) { printf(" %8" PRIu64 " ", ebase.simtime); dis_mem(sregs->pc, 1, &dinfo); } + if ((sregs->bptnum) && (sregs->bphit = check_bpt (sregs))) + icount = 0; + else { + dispatch_instruction (sregs); + icount--; + } + } else { + dispatch_instruction (sregs); + icount--; } - dispatch_instruction(sregs); - icount--; } } if (sregs->trap) { irq = 0; - sregs->err_mode = execute_trap(sregs); + if ((sregs->err_mode = execute_trap (sregs)) == WPT_HIT) { + sregs->err_mode = 0; + sregs->trap = 0; + icount = 0; + } if (sregs->err_mode) { ms->error_mode (sregs->pc); icount = 0; @@ -118,6 +125,10 @@ run_sim(sregs, icount, dis) ctrl_c = 0; return CTRL_C; } + if (sregs->bphit) + return BPT_HIT; + if (sregs->wphit) + return WPT_HIT; return TIME_OUT; } @@ -283,6 +294,11 @@ main(argc, argv) printf(" %8" PRIu64 " ", ebase.simtime); dis_mem(sregs.pc, 1, &dinfo); break; + case WPT_HIT: + printf ("watchpoint at 0x%08x reached, pc = 0x%08x\n", + sregs.wpaddress, sregs.pc); + sregs.wphit = 1; + break; default: break; } diff --git a/sim/erc32/sis.h b/sim/erc32/sis.h index be80728..e53ba3a 100644 --- a/sim/erc32/sis.h +++ b/sim/erc32/sis.h @@ -42,8 +42,10 @@ /* Maximum # of floating point queue */ #define FPUQN 1 -/* Maximum # of breakpoints */ +/* Maximum # of breakpoints and watchpoints */ #define BPT_MAX 256 +#define WPR_MAX 256 +#define WPW_MAX 256 struct histype { unsigned addr; @@ -103,6 +105,14 @@ struct pstate { uint32 bptnum; uint32 bphit; uint32 bpts[BPT_MAX]; /* Breakpoints */ + uint32 wprnum; + uint32 wphit; + uint32 wprs[WPR_MAX]; /* Read Watchpoints */ + unsigned char wprm[WPR_MAX]; /* Read Watchpoint masks*/ + uint32 wpwnum; + uint32 wpws[WPW_MAX]; /* Write Watchpoints */ + unsigned char wpwm[WPW_MAX]; /* Write Watchpoint masks */ + uint32 wpaddress; uint32 ltime; /* Load interlock time */ uint32 hold; /* IU hold cycles in current inst */ @@ -178,12 +188,19 @@ struct memsys { void (*boot_init) (void); }; +/* return values for run_sim */ #define OK 0 #define TIME_OUT 1 #define BPT_HIT 2 #define ERROR 3 #define CTRL_C 4 +#define WPT_HIT 5 +/* special simulator trap types */ +#define ERROR_TRAP 257 +#define WPT_TRAP 258 + +/* cpu type defines */ #define CPU_LEON2 2 #define CPU_LEON3 3 @@ -232,6 +249,9 @@ extern void advance_time (struct pstate *sregs); extern uint32 now (void); extern int wait_for_irq (void); extern int check_bpt (struct pstate *sregs); +extern int check_wpr (struct pstate *sregs, int32 address, unsigned char mask); +extern int check_wpw (struct pstate *sregs, int32 address, unsigned char mask); + extern void reset_all (void); extern void sys_reset (void); extern void sys_halt (void); @@ -241,6 +261,7 @@ extern int nouartrx; extern host_callback *sim_callback; extern int dumbio; extern int cputype; +extern int sis_gdb_break; /* exec.c */ extern int dispatch_instruction (struct pstate *sregs);