Mercurial > nand-ecoscentric
changeset 338:5f6943a2e0a8
xscale stub fixes
| author | msalter |
|---|---|
| date | Fri, 20 Sep 2002 15:36:35 +0000 |
| parents | d640df2dd440 |
| children | 35d0def615e6 |
| files | packages/hal/arm/xscale/core/current/ChangeLog packages/hal/arm/xscale/core/current/src/xscale_stub.c |
| diffstat | 2 files changed, 99 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/hal/arm/xscale/core/current/ChangeLog +++ b/packages/hal/arm/xscale/core/current/ChangeLog @@ -1,3 +1,8 @@ +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.
--- a/packages/hal/arm/xscale/core/current/src/xscale_stub.c +++ b/packages/hal/arm/xscale/core/current/src/xscale_stub.c @@ -322,11 +322,35 @@ is_thumb_store_insn(unsigned pc) 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 @@ -337,7 +361,7 @@ find_thumb_watch_address(unsigned wa0, i 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; @@ -345,7 +369,7 @@ find_thumb_watch_address(unsigned wa0, i size = 0; is_store = 0; - use_val = 0; + val = use_val = 0; switch (opcode_f8) { case 0xc000: // STMIA Rn!, <list> @@ -359,10 +383,21 @@ find_thumb_watch_address(unsigned wa0, i 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; @@ -440,17 +475,20 @@ find_thumb_watch_address(unsigned wa0, i 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 @@ -460,7 +498,7 @@ find_watch_address(unsigned wa0, int mod { 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) @@ -485,6 +523,7 @@ find_watch_address(unsigned wa0, int mod 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); @@ -606,32 +645,69 @@ find_watch_address(unsigned wa0, int mod 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
