[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