This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

xscale stub fixes


Index: hal/arm/xscale/core/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/xscale/core/current/ChangeLog,v
retrieving revision 1.1
diff -u -p -5 -r1.1 ChangeLog
--- hal/arm/xscale/core/current/ChangeLog	19 Sep 2002 15:51:54 -0000	1.1
+++ hal/arm/xscale/core/current/ChangeLog	20 Sep 2002 15:33:55 -0000
@@ -1,5 +1,10 @@
+2002-09-20  Mark Salter  <msalter@redhat.com>
+
+	* src/xscale_stub.c: Fill in holes in logic used to decide which
+	of two watchpoints caused exception.
+
 2002-09-19  Mark Salter  <msalter@redhat.com>
 
 	* Initial checkin.
 
 //===========================================================================
Index: hal/arm/xscale/core/current/src/xscale_stub.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/hal/arm/xscale/core/current/src/xscale_stub.c,v
retrieving revision 1.1
diff -u -p -5 -r1.1 xscale_stub.c
--- hal/arm/xscale/core/current/src/xscale_stub.c	19 Sep 2002 15:51:55 -0000	1.1
+++ hal/arm/xscale/core/current/src/xscale_stub.c	20 Sep 2002 15:33:56 -0000
@@ -320,34 +320,58 @@ is_thumb_store_insn(unsigned pc)
 
 // Return non-zero if given waddr matches an access at addr.
 static int
 waddr_match(unsigned waddr, unsigned addr, int size)
 {
-    if (addr <= waddr && waddr <= (addr + size))
+    if (addr <= waddr && waddr < (addr + size))
 	return 1;
     return 0;
 }
 
+// Return non-zero if given value matches value at watchpoint address.
+static int
+wval_match(unsigned waddr, unsigned val, int size)
+{
+    unsigned wval = *(unsigned *)(waddr & ~3);
+    int i;
+
+    if (size == 4)
+	return (wval == val);
+    if (size == 2) {
+	val &= 0xffff;
+	return ((wval & 0xffff) == val || ((wval >> 16) == val));
+    }
+    if (size == 1) {
+	val &= 0xff;
+	for (i = 0; i < 4; i++) {
+	    if ((wval & 0xff) == val)
+		return 1;
+	    wval >>= 8;
+	}
+    }
+    return 0;
+}
+
 static char _sztab[8] = { 4, 2, 1, 1, 4, 2, 1, 2 };
 
 // Given the watch addresses and watch modes for each of the enabled
 // watchpoints, figure out which one triggered the current exception.
 static unsigned
 find_thumb_watch_address(unsigned wa0, int mode0, unsigned wa1, int mode1)
 {
     unsigned pc = get_register(PC) - 4;
     unsigned short opcode = *(unsigned short *)pc;
     unsigned short opcode_f8, opcode_fe;
-    unsigned val, addr = 0;
+    unsigned val, wd0, wd1, addr = 0;
     int  is_store, use_val, i, offset, size, Rn, Rd, Rm;
 
     opcode_f8 = opcode & 0xf800;
     opcode_fe = opcode & 0xfe00;
 
     size = 0;
     is_store = 0;
-    use_val = 0;
+    val = use_val = 0;
 
     switch (opcode_f8) {
     case 0xc000: // STMIA Rn!, <list>
 	is_store = 1;
     case 0xc800: // LDMIA Rn!, <list>
@@ -357,14 +381,25 @@ find_thumb_watch_address(unsigned wa0, i
 	    if (opcode & (1 << i))
 		size += 4;
 	if (!is_store && (opcode & (1 << Rn))) {
 	    // We can't reconstruct address from opcode because base
 	    // was destroyed. Best we can do is try to match data at
-            // or around watchpoint addresses with data in one of the
-	    // registers.
-	    use_val = 1;
-	    val = 0;  // FIXME
+            // watchpoint addresses with data in one of the registers.
+	    wd0 = *(unsigned *)(wa0 & ~3);
+	    wd1 = *(unsigned *)(wa1 & ~3);
+	    if (wd0 != wd1) {
+		for (i = size = 0; i < 8; i++) {
+		    if (opcode & (1 << i)) {
+			val = get_register(i);
+			if (val == wd0)
+			    return wa0;
+			else if (val == wd1)
+			    return wa1;
+		    }
+		}
+	    }
+	    return wa0;  // 50% chance of being right
 	} else
 	    addr = get_register(Rn) - size;
 	break;
     case 0x6000: // STR  Rd, [Rn, #5bit]
     case 0x7000: // STRB Rd, [Rn, #5bit]
@@ -438,31 +473,34 @@ find_thumb_watch_address(unsigned wa0, i
 	    break;
 	}
 	break;
     }
     if (use_val) {
-	// FIXME
 	// We can read from watchpoint addresses and compare against
 	// whatever is in the Rd from a load. This is not perfect,
 	// but its the best we can do.
+	if (wval_match(wa0, val, size))
+	    return wa0;
+	if (wval_match(wa1, val, size))
+	    return wa1;
     } else if (size) {
 	if (waddr_match(wa0, addr, size))
 	    return wa0;
 	if (waddr_match(wa1, addr, size))
 	    return wa1;
     }
-    return 0;  // should never happen
+    return wa0;  // should never happen, but return valid address
 }
 
 // Given the watch addresses and watch modes for each of the enabled
 // watchpoints, figure out which one triggered the current exception.
 static unsigned
 find_watch_address(unsigned wa0, int mode0, unsigned wa1, int mode1)
 {
     unsigned pc = get_register(PC) - 4;
     unsigned cpsr = get_register(PS);
-    unsigned opcode, Rn, Rd, Rm, base, addr, val;
+    unsigned opcode, Rn, Rd, Rm, base, addr, val, wd0, wd1;
     int  is_store, use_val, i, offset, shift, size;
 
     if (cpsr & CPSR_THUMB_ENABLE)
 	is_store = is_thumb_store_insn(pc);
     else
@@ -483,10 +521,11 @@ find_watch_address(unsigned wa0, int mod
     if ((mode1 == WATCH_MODE_READ && is_store) ||
 	(mode1 == WATCH_MODE_WRITE && !is_store))
 	return wa0;
 
     // Okay. Now try to figure out address by decoding the opcode.
+
     if (cpsr & CPSR_THUMB_ENABLE)
 	return find_thumb_watch_address(wa0, mode0, wa1, mode1);
 
     opcode = *(unsigned *)pc;
     Rn = (opcode >> 16) & 15;
@@ -604,36 +643,73 @@ find_watch_address(unsigned wa0, int mod
 	// LDM/STM      xxxx 100P USWL _Rn_ rrrr rrrr rrrr rrrr
 	for (i = size = 0; i < 16; i++)
 	    if (opcode & (1 << i))
 		size += 4;
 
-	if ((opcode & (1 << Rn)) && (opcode & L_bit)) {
+	base = get_register(Rn);
+	if (!is_store && (opcode & (1 << Rn))) {
 	    // We can't reconstruct address from opcode because base
 	    // was destroyed. Best we can do is try to match data at
-            // or around watchpoint addresses with data in one of the
-	    // registers.
-	    use_val = 1;
-	    val = 0;  // FIXME
+            // watchpoint addresses with data in one of the registers.
+	    wd0 = *(unsigned *)(wa0 & ~3);
+	    wd1 = *(unsigned *)(wa1 & ~3);
+	    if (wd0 != wd1) {
+		for (i = size = 0; i < 16; i++) {
+		    if (opcode & (1 << i)) {
+			val = get_register(i);
+			if (val == wd0)
+			    return wa0;
+			else if (val == wd1)
+			    return wa1;
+		    }
+		}
+	    }
+	    return wa0;  // 50% chance of being right
 	} else {
+	    if (opcode & U_bit){
+		if (opcode & W_bit)
+		    addr = base - size;
+		else
+		    addr = base;
+		if (opcode & P_bit)
+		    addr += 4;
+	    } else {
+		if (opcode & W_bit)
+		    addr = base;
+		else
+		    addr = base - size;
+		if ((opcode & P_bit) == 0)
+		    addr += 4;
+	    }
 	}
     } else if ((opcode & 0x0e000000) == 0x0c000000) {
 	// LDC/STC      xxxx 110P UNWL _Rn_ CRd_ CP#_ iiii iiii
-	// FIXME
+	size = 4;
+	offset = (opcode & 0xff) * 4;
+	if ((opcode & U_bit) == 0)
+	    offset = -offset;
+	if ((opcode & P_bit) && (opcode & W_bit))
+	    addr = get_register(Rn);
+	else
+	    addr = get_register(Rn) + offset;
     }
 
     if (use_val) {
-	// FIXME
 	// We can read from watchpoint addresses and compare against
 	// whatever is in the Rd from a load. This is not perfect,
 	// but its the best we can do.
+	if (wval_match(wa0, val, size))
+	    return wa0;
+	if (wval_match(wa1, val, size))
+	    return wa1;
     } else {
 	if (waddr_match(wa0, addr, size))
 	    return wa0;
 	if (waddr_match(wa1, addr, size))
 	    return wa1;
     }
-    return 0;  // should never happen
+    return wa0;  // should never happen, but return valid address
 }
 #endif
 
 // Return indication of whether or not we stopped because of a
 // watchpoint or hardware breakpoint. If stopped by a watchpoint,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]