This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH v5 8/9] sim/erc32: Add data watchpoint support.
- From: Jiri Gaisler <jiri at gaisler dot se>
- To: gdb-patches at sourceware dot org
- Cc: Jiri Gaisler <jiri at gaisler dot se>
- Date: Fri, 3 Apr 2015 22:35:55 +0200
- Subject: [PATCH v5 8/9] sim/erc32: Add data watchpoint support.
- Authentication-results: sourceware.org; auth=none
- Authorized-sender: jiri at gaisler dot se
- References: <1428093356-7296-1-git-send-email-jiri at gaisler dot se>
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);
--
1.9.1