This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
xscale stub fixes
- From: Mark Salter <msalter at redhat dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: Fri, 20 Sep 2002 11:37:10 -0400
- Subject: 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,