[PATCH v4 12/13] sim/erc32: Add data watchpoint support
Jiri Gaisler
jiri@gaisler.se
Tue Mar 17 21:03:00 GMT 2015
Add watchpoint to all SPARC targets (erc32, leon2, leon3).
---
sim/erc32/exec.c | 54 ++++++++++++++++++++++++++------
sim/erc32/func.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
sim/erc32/interf.c | 3 +-
sim/erc32/sis.c | 32 ++++++++++++++-----
sim/erc32/sis.h | 23 +++++++++++++-
5 files changed, 181 insertions(+), 22 deletions(-)
diff --git a/sim/erc32/exec.c b/sim/erc32/exec.c
index 65d7487..44d4dda 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
@@ -2133,12 +2160,18 @@ 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);
+ }
} else {
if ((sregs->psr & PSR_ET) == 0)
@@ -2231,6 +2264,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 ae740ec..0be47f0 100644
--- a/sim/erc32/func.c
+++ b/sim/erc32/func.c
@@ -62,7 +62,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;
@@ -626,6 +628,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");
}
@@ -716,6 +765,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;
@@ -1029,6 +1080,44 @@ check_bpt(sregs)
return (0);
}
+int
+check_wpr(sregs, address, mask)
+ 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(sregs, address, mask)
+ 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 2ed9914..f04041c 100644
--- a/sim/erc32/interf.c
+++ b/sim/erc32/interf.c
@@ -37,8 +37,6 @@
#define PSR_CWP 0x7
-int sis_gdb_break = 1;
-
int
run_sim(sregs, icount, dis)
struct pstate *sregs;
@@ -163,6 +161,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 99d5286..7c984bc 100644
--- a/sim/erc32/sis.c
+++ b/sim/erc32/sis.c
@@ -75,11 +75,7 @@ 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++;
@@ -90,14 +86,25 @@ run_sim(sregs, icount, 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 aef501b..abd21da 100644
--- a/sim/erc32/sis.h
+++ b/sim/erc32/sis.h
@@ -40,8 +40,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;
@@ -101,6 +103,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 */
@@ -176,12 +186,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
@@ -230,6 +247,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);
@@ -240,6 +260,7 @@ extern host_callback *sim_callback;
extern int current_target_byte_order;
extern int dumbio;
extern int cputype;
+extern int sis_gdb_break;
/* exec.c */
extern int dispatch_instruction (struct pstate *sregs);
--
1.9.1
More information about the Gdb-patches
mailing list