diff options
-rw-r--r-- | sim/arm/ChangeLog | 8 | ||||
-rw-r--r-- | sim/arm/armemu.c | 72 | ||||
-rw-r--r-- | sim/arm/armemu.h | 5 |
3 files changed, 48 insertions, 37 deletions
diff --git a/sim/arm/ChangeLog b/sim/arm/ChangeLog index 1b3a557..526b49d 100644 --- a/sim/arm/ChangeLog +++ b/sim/arm/ChangeLog @@ -1,5 +1,13 @@ 2000-07-04 Alexandre Oliva <aoliva@redhat.com> + * armemu.h (WRITEDESTB): New macro. + * armemu.c (ARMul_Emulate26, bl): Use WriteR15Branch() to + modify PC. Moved the existing logic... + (WriteR15Branch): ... here. New function. + (WriteR15, WriteSR15): Drop the two least significant bits. + (LoadSMult): Use WriteR15Branch() to modify PC. + (LoadMult): Use WRITEDESTB() instead of WRITEDEST(). + * armemu.h (GETSPSR): Call ARMul_GetSPSR(). * armsupp.c (ARMul_CPSRAltered): Zero out bits as they're extracted from state->Cpsr, but preserve the unused bits. diff --git a/sim/arm/armemu.c b/sim/arm/armemu.c index 373ec72..2fc0eda 100644 --- a/sim/arm/armemu.c +++ b/sim/arm/armemu.c @@ -24,6 +24,7 @@ static ARMword GetDPRegRHS (ARMul_State * state, ARMword instr); static ARMword GetDPSRegRHS (ARMul_State * state, ARMword instr); static void WriteR15 (ARMul_State * state, ARMword src); static void WriteSR15 (ARMul_State * state, ARMword src); +static void WriteR15Branch (ARMul_State * state, ARMword src); static ARMword GetLSRegRHS (ARMul_State * state, ARMword instr); static ARMword GetLS7RHS (ARMul_State * state, ARMword instr); static unsigned LoadWord (ARMul_State * state, ARMword instr, @@ -1082,35 +1083,8 @@ ARMul_Emulate26 (register ARMul_State * state) #ifdef MODET if (BITS (4, 27) == 0x12FFF1) { /* BX */ - /* Branch to the address in RHSReg. If bit0 of - destination address is 1 then switch to Thumb mode: */ - ARMword addr = state->Reg[RHSReg]; - - /* If we read the PC then the bottom bit is clear */ - if (RHSReg == 15) - addr &= ~1; - - /* Enable this for a helpful bit of debugging when - GDB is not yet fully working... - fprintf (stderr, "BX at %x to %x (go %s)\n", - state->Reg[15], addr, (addr & 1) ? "thumb": "arm" ); */ - - if (addr & (1 << 0)) - { /* Thumb bit */ - SETT; - state->Reg[15] = addr & 0xfffffffe; - /* NOTE: The other CPSR flag setting blocks do not - seem to update the state->Cpsr state, but just do - the explicit flag. The copy from the seperate - flags to the register must happen later. */ - FLUSHPIPE; - } - else - { - CLEART; - state->Reg[15] = addr & 0xfffffffc; - FLUSHPIPE; - } + WriteR15Branch (state, state->Reg[RHSReg]); + break; } #endif if (DESTReg == 15) @@ -3128,11 +3102,14 @@ GetDPSRegRHS (ARMul_State * state, ARMword instr) static void WriteR15 (ARMul_State * state, ARMword src) { - /* The ARM documentation implies (but doe snot state) that the bottom bit of the PC is never set */ + /* The ARM documentation states that the two least significant bits + are discarded when setting PC, except in the cases handled by + WriteR15Branch() below. */ + src &= 0xfffffffc; #ifdef MODE32 - state->Reg[15] = src & PCBITS & ~0x1; + state->Reg[15] = src & PCBITS; #else - state->Reg[15] = (src & R15PCBITS & ~0x1) | ECC | ER15INT | EMODE; + state->Reg[15] = (src & R15PCBITS) | ECC | ER15INT | EMODE; ARMul_R15Altered (state); #endif FLUSHPIPE; @@ -3145,6 +3122,7 @@ WriteR15 (ARMul_State * state, ARMword src) static void WriteSR15 (ARMul_State * state, ARMword src) { + src &= 0xfffffffc; #ifdef MODE32 state->Reg[15] = src & PCBITS; if (state->Bank > 0) @@ -3162,6 +3140,29 @@ WriteSR15 (ARMul_State * state, ARMword src) FLUSHPIPE; } +/* In machines capable of running in Thumb mode, BX, BLX, LDR and LDM + will switch to Thumb mode if the least significant bit is set. */ + +static void +WriteR15Branch (ARMul_State * state, ARMword src) +{ +#ifdef MODET + if (src & 1) + { /* Thumb bit */ + SETT; + state->Reg[15] = src & 0xfffffffe; + } + else + { + CLEART; + state->Reg[15] = src & 0xfffffffc; + } + FLUSHPIPE; +#else + WriteR15 (state, src); +#endif +} + /***************************************************************************\ * This routine evaluates most Load and Store register RHS's. It is * * intended to be called from the macro LSRegRHS, which filters the * @@ -3249,7 +3250,7 @@ LoadWord (ARMul_State * state, ARMword instr, ARMword address) } if (address & 3) dest = ARMul_Align (state, address, dest); - WRITEDEST (dest); + WRITEDESTB (dest); ARMul_Icycles (state, 1, 0L); return (DESTReg != LHSReg); @@ -3471,10 +3472,7 @@ LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase) if (BIT (15) && !state->Aborted) { /* PC is in the reg list */ -#ifdef MODE32 - state->Reg[15] = PC; -#endif - FLUSHPIPE; + WriteR15Branch(state, PC); } ARMul_Icycles (state, 1, 0L); /* to write back the final register */ diff --git a/sim/arm/armemu.h b/sim/arm/armemu.h index da7fb2b..ad89294 100644 --- a/sim/arm/armemu.h +++ b/sim/arm/armemu.h @@ -332,6 +332,11 @@ extern ARMword isize; ARMul_NegZero(state, d) ; \ } +#define WRITEDESTB(d) if (DESTReg == 15) \ + WriteR15Branch(state, d) ; \ + else \ + DEST = d + #define BYTETOBUS(data) ((data & 0xff) | \ ((data & 0xff) << 8) | \ ((data & 0xff) << 16) | \ |