2643 lines
85 KiB
C
2643 lines
85 KiB
C
/* armemu.c -- Main instruction emulation: ARM6 Instruction Emulator.
|
|
Copyright (C) 1994 Advanced RISC Machines Ltd.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
#include "armdefs.h"
|
|
#include "armemu.h"
|
|
|
|
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 ARMword GetLSRegRHS(ARMul_State *state, ARMword instr) ;
|
|
static unsigned LoadWord(ARMul_State *state, ARMword instr, ARMword address) ;
|
|
static unsigned LoadByte(ARMul_State *state, ARMword instr, ARMword address) ;
|
|
static unsigned StoreWord(ARMul_State *state, ARMword instr, ARMword address) ;
|
|
static unsigned StoreByte(ARMul_State *state, ARMword instr, ARMword address) ;
|
|
static void LoadMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
|
|
static void StoreMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
|
|
static void LoadSMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
|
|
static void StoreSMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
|
|
|
|
/***************************************************************************\
|
|
* EMULATION of ARM6 *
|
|
\***************************************************************************/
|
|
|
|
#ifdef MODE32
|
|
ARMword ARMul_Emulate32(register ARMul_State *state)
|
|
{
|
|
#else
|
|
ARMword ARMul_Emulate26(register ARMul_State *state)
|
|
{
|
|
#endif
|
|
register ARMword instr, /* the current instruction */
|
|
dest, /* almost the DestBus */
|
|
temp, /* ubiquitous third hand */
|
|
pc ; /* the address of the current instruction */
|
|
ARMword lhs, rhs ; /* almost the ABus and BBus */
|
|
ARMword decoded, loaded ; /* instruction pipeline */
|
|
|
|
/***************************************************************************\
|
|
* Execute the next instruction *
|
|
\***************************************************************************/
|
|
|
|
if (state->NextInstr < PRIMEPIPE) {
|
|
decoded = state->decoded ;
|
|
loaded = state->loaded ;
|
|
pc = state->pc ;
|
|
}
|
|
|
|
do { /* just keep going */
|
|
switch (state->NextInstr) {
|
|
case SEQ :
|
|
state->Reg[15] += 4 ; /* Advance the pipeline, and an S cycle */
|
|
pc += 4 ;
|
|
instr = decoded ;
|
|
decoded = loaded ;
|
|
loaded = ARMul_LoadInstrS(state,pc+8) ;
|
|
break ;
|
|
|
|
case NONSEQ :
|
|
state->Reg[15] += 4 ; /* Advance the pipeline, and an N cycle */
|
|
pc += 4 ;
|
|
instr = decoded ;
|
|
decoded = loaded ;
|
|
loaded = ARMul_LoadInstrN(state,pc+8) ;
|
|
NORMALCYCLE ;
|
|
break ;
|
|
|
|
case PCINCEDSEQ :
|
|
pc += 4 ; /* Program counter advanced, and an S cycle */
|
|
instr = decoded ;
|
|
decoded = loaded ;
|
|
loaded = ARMul_LoadInstrS(state,pc+8) ;
|
|
NORMALCYCLE ;
|
|
break ;
|
|
|
|
case PCINCEDNONSEQ :
|
|
pc += 4 ; /* Program counter advanced, and an N cycle */
|
|
instr = decoded ;
|
|
decoded = loaded ;
|
|
loaded = ARMul_LoadInstrN(state,pc+8) ;
|
|
NORMALCYCLE ;
|
|
break ;
|
|
|
|
case RESUME : /* The program counter has been changed */
|
|
pc = state->Reg[15] ;
|
|
#ifndef MODE32
|
|
pc = pc & R15PCBITS ;
|
|
#endif
|
|
state->Reg[15] = pc + 8 ;
|
|
state->Aborted = 0 ;
|
|
instr = ARMul_ReadWord(state,pc) ;
|
|
decoded = ARMul_ReadWord(state,pc + 4) ;
|
|
loaded = ARMul_ReadWord(state,pc + 8) ;
|
|
NORMALCYCLE ;
|
|
break ;
|
|
|
|
default : /* The program counter has been changed */
|
|
pc = state->Reg[15] ;
|
|
#ifndef MODE32
|
|
pc = pc & R15PCBITS ;
|
|
#endif
|
|
state->Reg[15] = pc + 8 ;
|
|
state->Aborted = 0 ;
|
|
instr = ARMul_LoadInstrN(state,pc) ;
|
|
decoded = ARMul_LoadInstrS(state,pc + 4) ;
|
|
loaded = ARMul_LoadInstrS(state,pc + 8) ;
|
|
NORMALCYCLE ;
|
|
break ;
|
|
}
|
|
if (state->EventSet)
|
|
ARMul_EnvokeEvent(state) ;
|
|
|
|
if (state->Exception) { /* Any exceptions */
|
|
if (state->NresetSig == LOW) {
|
|
ARMul_Abort(state,ARMul_ResetV) ;
|
|
break ;
|
|
}
|
|
else if (!state->NfiqSig && !FFLAG) {
|
|
ARMul_Abort(state,ARMul_FIQV) ;
|
|
break ;
|
|
}
|
|
else if (!state->NirqSig && !IFLAG) {
|
|
ARMul_Abort(state,ARMul_IRQV) ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
if (state->CallDebug > 0) {
|
|
instr = ARMul_Debug(state,pc,instr) ;
|
|
if (state->Emulate < ONCE) {
|
|
state->NextInstr = RESUME ;
|
|
break ;
|
|
}
|
|
if (state->Debug) {
|
|
fprintf(stderr,"At %08lx Instr %08lx Mode %02lx\n",pc,instr,state->Mode) ;
|
|
(void)fgetc(stdin) ;
|
|
}
|
|
}
|
|
else
|
|
if (state->Emulate < ONCE) {
|
|
state->NextInstr = RESUME ;
|
|
break ;
|
|
}
|
|
|
|
state->NumInstrs++ ;
|
|
|
|
/***************************************************************************\
|
|
* Check the condition codes *
|
|
\***************************************************************************/
|
|
if ((temp = TOPBITS(28)) == AL)
|
|
goto mainswitch ; /* vile deed in the need for speed */
|
|
|
|
switch ((int)TOPBITS(28)) { /* check the condition code */
|
|
case AL : temp=TRUE ;
|
|
break ;
|
|
case NV : temp=FALSE ;
|
|
break ;
|
|
case EQ : temp=ZFLAG ;
|
|
break ;
|
|
case NE : temp=!ZFLAG ;
|
|
break ;
|
|
case VS : temp=VFLAG ;
|
|
break ;
|
|
case VC : temp=!VFLAG ;
|
|
break ;
|
|
case MI : temp=NFLAG ;
|
|
break ;
|
|
case PL : temp=!NFLAG ;
|
|
break ;
|
|
case CS : temp=CFLAG ;
|
|
break ;
|
|
case CC : temp=!CFLAG ;
|
|
break ;
|
|
case HI : temp=(CFLAG && !ZFLAG) ;
|
|
break ;
|
|
case LS : temp=(!CFLAG || ZFLAG) ;
|
|
break ;
|
|
case GE : temp=((!NFLAG && !VFLAG) || (NFLAG && VFLAG)) ;
|
|
break ;
|
|
case LT : temp=((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) ;
|
|
break ;
|
|
case GT : temp=((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG)) ;
|
|
break ;
|
|
case LE : temp=((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG ;
|
|
break ;
|
|
} /* cc check */
|
|
|
|
/***************************************************************************\
|
|
* Actual execution of instructions begins here *
|
|
\***************************************************************************/
|
|
|
|
if (temp) { /* if the condition codes don't match, stop here */
|
|
mainswitch:
|
|
switch ((int)BITS(20,27)) {
|
|
|
|
/***************************************************************************\
|
|
* Data Processing Register RHS Instructions *
|
|
\***************************************************************************/
|
|
|
|
case 0x00 : /* AND reg and MUL */
|
|
if (BITS(4,7) == 9) { /* MUL */
|
|
rhs = state->Reg[MULRHSReg] ;
|
|
if (MULLHSReg == MULDESTReg) {
|
|
UNDEF_MULDestEQOp1 ;
|
|
state->Reg[MULDESTReg] = 0 ;
|
|
}
|
|
else if (MULDESTReg != 15)
|
|
state->Reg[MULDESTReg] = state->Reg[MULLHSReg] * rhs ;
|
|
else {
|
|
UNDEF_MULPCDest ;
|
|
}
|
|
for (dest = 0, temp = 0 ; dest < 32 ; dest++)
|
|
if (rhs & (1L << dest))
|
|
temp = dest ; /* mult takes this many/2 I cycles */
|
|
ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
|
|
}
|
|
else { /* AND reg */
|
|
rhs = DPRegRHS ;
|
|
dest = LHS & rhs ;
|
|
WRITEDEST(dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x01 : /* ANDS reg and MULS */
|
|
if (BITS(4,7) == 9) { /* MULS */
|
|
rhs = state->Reg[MULRHSReg] ;
|
|
if (MULLHSReg == MULDESTReg) {
|
|
UNDEF_MULDestEQOp1 ;
|
|
state->Reg[MULDESTReg] = 0 ;
|
|
CLEARN ;
|
|
SETZ ;
|
|
}
|
|
else if (MULDESTReg != 15) {
|
|
dest = state->Reg[MULLHSReg] * rhs ;
|
|
ARMul_NegZero(state,dest) ;
|
|
state->Reg[MULDESTReg] = dest ;
|
|
}
|
|
else {
|
|
UNDEF_MULPCDest ;
|
|
}
|
|
for (dest = 0, temp = 0 ; dest < 32 ; dest++)
|
|
if (rhs & (1L << dest))
|
|
temp = dest ; /* mult takes this many/2 I cycles */
|
|
ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
|
|
}
|
|
else { /* ANDS reg */
|
|
rhs = DPSRegRHS ;
|
|
dest = LHS & rhs ;
|
|
WRITESDEST(dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x02 : /* EOR reg and MLA */
|
|
if (BITS(4,7) == 9) { /* MLA */
|
|
rhs = state->Reg[MULRHSReg] ;
|
|
if (MULLHSReg == MULDESTReg) {
|
|
UNDEF_MULDestEQOp1 ;
|
|
state->Reg[MULDESTReg] = state->Reg[MULACCReg] ;
|
|
}
|
|
else if (MULDESTReg != 15)
|
|
state->Reg[MULDESTReg] = state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg] ;
|
|
else {
|
|
UNDEF_MULPCDest ;
|
|
}
|
|
for (dest = 0, temp = 0 ; dest < 32 ; dest++)
|
|
if (rhs & (1L << dest))
|
|
temp = dest ; /* mult takes this many/2 I cycles */
|
|
ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
|
|
}
|
|
else {
|
|
rhs = DPRegRHS ;
|
|
dest = LHS ^ rhs ;
|
|
WRITEDEST(dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x03 : /* EORS reg and MLAS */
|
|
if (BITS(4,7) == 9) { /* MLAS */
|
|
rhs = state->Reg[MULRHSReg] ;
|
|
if (MULLHSReg == MULDESTReg) {
|
|
UNDEF_MULDestEQOp1 ;
|
|
dest = state->Reg[MULACCReg] ;
|
|
ARMul_NegZero(state,dest) ;
|
|
state->Reg[MULDESTReg] = dest ;
|
|
}
|
|
else if (MULDESTReg != 15) {
|
|
dest = state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg] ;
|
|
ARMul_NegZero(state,dest) ;
|
|
state->Reg[MULDESTReg] = dest ;
|
|
}
|
|
else {
|
|
UNDEF_MULPCDest ;
|
|
}
|
|
for (dest = 0, temp = 0 ; dest < 32 ; dest++)
|
|
if (rhs & (1L << dest))
|
|
temp = dest ; /* mult takes this many/2 I cycles */
|
|
ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
|
|
}
|
|
else { /* EORS Reg */
|
|
rhs = DPSRegRHS ;
|
|
dest = LHS ^ rhs ;
|
|
WRITESDEST(dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x04 : /* SUB reg */
|
|
rhs = DPRegRHS;
|
|
dest = LHS - rhs ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x05 : /* SUBS reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = lhs - rhs ;
|
|
if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,lhs,rhs,dest) ;
|
|
ARMul_SubOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x06 : /* RSB reg */
|
|
rhs = DPRegRHS ;
|
|
dest = rhs - LHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x07 : /* RSBS reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = rhs - lhs ;
|
|
if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,rhs,lhs,dest) ;
|
|
ARMul_SubOverflow(state,rhs,lhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x08 : /* ADD reg */
|
|
rhs = DPRegRHS ;
|
|
dest = LHS + rhs ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x09 : /* ADDS reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = lhs + rhs ;
|
|
ASSIGNZ(dest==0) ;
|
|
if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
|
|
ASSIGNN(NEG(dest)) ;
|
|
ARMul_AddCarry(state,lhs,rhs,dest) ;
|
|
ARMul_AddOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARN ;
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x0a : /* ADC reg */
|
|
rhs = DPRegRHS ;
|
|
dest = LHS + rhs + CFLAG ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x0b : /* ADCS reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = lhs + rhs + CFLAG ;
|
|
ASSIGNZ(dest==0) ;
|
|
if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
|
|
ASSIGNN(NEG(dest)) ;
|
|
ARMul_AddCarry(state,lhs,rhs,dest) ;
|
|
ARMul_AddOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARN ;
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x0c : /* SBC reg */
|
|
rhs = DPRegRHS ;
|
|
dest = LHS - rhs - !CFLAG ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x0d : /* SBCS reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = lhs - rhs - !CFLAG ;
|
|
if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,lhs,rhs,dest) ;
|
|
ARMul_SubOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x0e : /* RSC reg */
|
|
rhs = DPRegRHS ;
|
|
dest = rhs - LHS - !CFLAG ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x0f : /* RSCS reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = rhs - lhs - !CFLAG ;
|
|
if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,rhs,lhs,dest) ;
|
|
ARMul_SubOverflow(state,rhs,lhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x10 : /* TST reg and MRS CPSR and SWP word */
|
|
if (BITS(4,11) == 9) { /* SWP */
|
|
UNDEF_SWPPC ;
|
|
temp = LHS ;
|
|
BUSUSEDINCPCS ;
|
|
#ifndef MODE32
|
|
if (VECTORACCESS(temp) || ADDREXCEPT(temp)) {
|
|
INTERNALABORT(temp) ;
|
|
(void)ARMul_LoadWordN(state,temp) ;
|
|
(void)ARMul_LoadWordN(state,temp) ;
|
|
}
|
|
else
|
|
#endif
|
|
dest = ARMul_SwapWord(state,temp,state->Reg[RHSReg]) ;
|
|
if (temp & 3)
|
|
DEST = ARMul_Align(state,temp,dest) ;
|
|
else
|
|
DEST = dest ;
|
|
if (state->abortSig || state->Aborted) {
|
|
TAKEABORT ;
|
|
}
|
|
}
|
|
else if ((BITS(0,11)==0) && (LHSReg==15)) { /* MRS CPSR */
|
|
UNDEF_MRSPC ;
|
|
DEST = ECC | EINT | EMODE ;
|
|
}
|
|
else {
|
|
UNDEF_Test ;
|
|
}
|
|
break ;
|
|
|
|
case 0x11 : /* TSTP reg */
|
|
if (DESTReg == 15) { /* TSTP reg */
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
rhs = DPRegRHS ;
|
|
temp = LHS & rhs ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
}
|
|
else { /* TST reg */
|
|
rhs = DPSRegRHS ;
|
|
dest = LHS & rhs ;
|
|
ARMul_NegZero(state,dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x12 : /* TEQ reg and MSR reg to CPSR */
|
|
if (DESTReg==15 && BITS(17,18)==0) { /* MSR reg to CPSR */
|
|
UNDEF_MSRPC ;
|
|
temp = DPRegRHS ;
|
|
ARMul_FixCPSR(state,instr,temp) ;
|
|
}
|
|
else {
|
|
UNDEF_Test ;
|
|
}
|
|
break ;
|
|
|
|
case 0x13 : /* TEQP reg */
|
|
if (DESTReg == 15) { /* TEQP reg */
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
rhs = DPRegRHS ;
|
|
temp = LHS ^ rhs ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
}
|
|
else { /* TEQ Reg */
|
|
rhs = DPSRegRHS ;
|
|
dest = LHS ^ rhs ;
|
|
ARMul_NegZero(state,dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x14 : /* CMP reg and MRS SPSR and SWP byte */
|
|
if (BITS(4,11) == 9) { /* SWP */
|
|
UNDEF_SWPPC ;
|
|
temp = LHS ;
|
|
BUSUSEDINCPCS ;
|
|
#ifndef MODE32
|
|
if (VECTORACCESS(temp) || ADDREXCEPT(temp)) {
|
|
INTERNALABORT(temp) ;
|
|
(void)ARMul_LoadByte(state,temp) ;
|
|
(void)ARMul_LoadByte(state,temp) ;
|
|
}
|
|
else
|
|
#endif
|
|
DEST = ARMul_SwapByte(state,temp,state->Reg[RHSReg]) ;
|
|
if (state->abortSig || state->Aborted) {
|
|
TAKEABORT ;
|
|
}
|
|
}
|
|
else if ((BITS(0,11)==0) && (LHSReg==15)) { /* MRS SPSR */
|
|
UNDEF_MRSPC ;
|
|
DEST = GETSPSR(state->Bank) ;
|
|
}
|
|
else {
|
|
UNDEF_Test ;
|
|
}
|
|
break ;
|
|
|
|
case 0x15 : /* CMPP reg */
|
|
if (DESTReg == 15) { /* CMPP reg */
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
rhs = DPRegRHS ;
|
|
temp = LHS - rhs ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
}
|
|
else { /* CMP reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = lhs - rhs ;
|
|
ARMul_NegZero(state,dest) ;
|
|
if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,lhs,rhs,dest) ;
|
|
ARMul_SubOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case 0x16 : /* CMN reg and MSR reg to SPSR */
|
|
if (DESTReg==15 && BITS(17,18)==0) { /* MSR */
|
|
UNDEF_MSRPC ;
|
|
ARMul_FixSPSR(state,instr,DPRegRHS);
|
|
}
|
|
else {
|
|
UNDEF_Test ;
|
|
}
|
|
break ;
|
|
|
|
case 0x17 : /* CMNP reg */
|
|
if (DESTReg == 15) {
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
rhs = DPRegRHS ;
|
|
temp = LHS + rhs ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
break ;
|
|
}
|
|
else { /* CMN reg */
|
|
lhs = LHS ;
|
|
rhs = DPRegRHS ;
|
|
dest = lhs + rhs ;
|
|
ASSIGNZ(dest==0) ;
|
|
if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
|
|
ASSIGNN(NEG(dest)) ;
|
|
ARMul_AddCarry(state,lhs,rhs,dest) ;
|
|
ARMul_AddOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARN ;
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case 0x18 : /* ORR reg */
|
|
rhs = DPRegRHS ;
|
|
dest = LHS | rhs ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x19 : /* ORRS reg */
|
|
rhs = DPSRegRHS ;
|
|
dest = LHS | rhs ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x1a : /* MOV reg */
|
|
dest = DPRegRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x1b : /* MOVS reg */
|
|
dest = DPSRegRHS ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x1c : /* BIC reg */
|
|
rhs = DPRegRHS ;
|
|
dest = LHS & ~rhs ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x1d : /* BICS reg */
|
|
rhs = DPSRegRHS ;
|
|
dest = LHS & ~rhs ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x1e : /* MVN reg */
|
|
dest = ~DPRegRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x1f : /* MVNS reg */
|
|
dest = ~DPSRegRHS ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Data Processing Immediate RHS Instructions *
|
|
\***************************************************************************/
|
|
|
|
case 0x20 : /* AND immed */
|
|
dest = LHS & DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x21 : /* ANDS immed */
|
|
DPSImmRHS ;
|
|
dest = LHS & rhs ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x22 : /* EOR immed */
|
|
dest = LHS ^ DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x23 : /* EORS immed */
|
|
DPSImmRHS ;
|
|
dest = LHS ^ rhs ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x24 : /* SUB immed */
|
|
dest = LHS - DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x25 : /* SUBS immed */
|
|
lhs = LHS ;
|
|
rhs = DPImmRHS ;
|
|
dest = lhs - rhs ;
|
|
if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,lhs,rhs,dest) ;
|
|
ARMul_SubOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x26 : /* RSB immed */
|
|
dest = DPImmRHS - LHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x27 : /* RSBS immed */
|
|
lhs = LHS ;
|
|
rhs = DPImmRHS ;
|
|
dest = rhs - lhs ;
|
|
if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,rhs,lhs,dest) ;
|
|
ARMul_SubOverflow(state,rhs,lhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x28 : /* ADD immed */
|
|
dest = LHS + DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x29 : /* ADDS immed */
|
|
lhs = LHS ;
|
|
rhs = DPImmRHS ;
|
|
dest = lhs + rhs ;
|
|
ASSIGNZ(dest==0) ;
|
|
if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
|
|
ASSIGNN(NEG(dest)) ;
|
|
ARMul_AddCarry(state,lhs,rhs,dest) ;
|
|
ARMul_AddOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARN ;
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x2a : /* ADC immed */
|
|
dest = LHS + DPImmRHS + CFLAG ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x2b : /* ADCS immed */
|
|
lhs = LHS ;
|
|
rhs = DPImmRHS ;
|
|
dest = lhs + rhs + CFLAG ;
|
|
ASSIGNZ(dest==0) ;
|
|
if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
|
|
ASSIGNN(NEG(dest)) ;
|
|
ARMul_AddCarry(state,lhs,rhs,dest) ;
|
|
ARMul_AddOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARN ;
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x2c : /* SBC immed */
|
|
dest = LHS - DPImmRHS - !CFLAG ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x2d : /* SBCS immed */
|
|
lhs = LHS ;
|
|
rhs = DPImmRHS ;
|
|
dest = lhs - rhs - !CFLAG ;
|
|
if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,lhs,rhs,dest) ;
|
|
ARMul_SubOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x2e : /* RSC immed */
|
|
dest = DPImmRHS - LHS - !CFLAG ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x2f : /* RSCS immed */
|
|
lhs = LHS ;
|
|
rhs = DPImmRHS ;
|
|
dest = rhs - lhs - !CFLAG ;
|
|
if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,rhs,lhs,dest) ;
|
|
ARMul_SubOverflow(state,rhs,lhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x30 : /* TST immed */
|
|
UNDEF_Test ;
|
|
break ;
|
|
|
|
case 0x31 : /* TSTP immed */
|
|
if (DESTReg == 15) { /* TSTP immed */
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
temp = LHS & DPImmRHS ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
}
|
|
else {
|
|
DPSImmRHS ; /* TST immed */
|
|
dest = LHS & rhs ;
|
|
ARMul_NegZero(state,dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x32 : /* TEQ immed and MSR immed to CPSR */
|
|
if (DESTReg==15 && BITS(17,18)==0) { /* MSR immed to CPSR */
|
|
ARMul_FixCPSR(state,instr,DPImmRHS) ;
|
|
}
|
|
else {
|
|
UNDEF_Test ;
|
|
}
|
|
break ;
|
|
|
|
case 0x33 : /* TEQP immed */
|
|
if (DESTReg == 15) { /* TEQP immed */
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
temp = LHS ^ DPImmRHS ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
}
|
|
else {
|
|
DPSImmRHS ; /* TEQ immed */
|
|
dest = LHS ^ rhs ;
|
|
ARMul_NegZero(state,dest) ;
|
|
}
|
|
break ;
|
|
|
|
case 0x34 : /* CMP immed */
|
|
UNDEF_Test ;
|
|
break ;
|
|
|
|
case 0x35 : /* CMPP immed */
|
|
if (DESTReg == 15) { /* CMPP immed */
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
temp = LHS - DPImmRHS ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
break ;
|
|
}
|
|
else {
|
|
lhs = LHS ; /* CMP immed */
|
|
rhs = DPImmRHS ;
|
|
dest = lhs - rhs ;
|
|
ARMul_NegZero(state,dest) ;
|
|
if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
|
|
ARMul_SubCarry(state,lhs,rhs,dest) ;
|
|
ARMul_SubOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case 0x36 : /* CMN immed and MSR immed to SPSR */
|
|
if (DESTReg==15 && BITS(17,18)==0) /* MSR */
|
|
ARMul_FixSPSR(state, instr, DPImmRHS) ;
|
|
else {
|
|
UNDEF_Test ;
|
|
}
|
|
break ;
|
|
|
|
case 0x37 : /* CMNP immed */
|
|
if (DESTReg == 15) { /* CMNP immed */
|
|
#ifdef MODE32
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
#else
|
|
temp = LHS + DPImmRHS ;
|
|
SETR15PSR(temp) ;
|
|
#endif
|
|
break ;
|
|
}
|
|
else {
|
|
lhs = LHS ; /* CMN immed */
|
|
rhs = DPImmRHS ;
|
|
dest = lhs + rhs ;
|
|
ASSIGNZ(dest==0) ;
|
|
if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
|
|
ASSIGNN(NEG(dest)) ;
|
|
ARMul_AddCarry(state,lhs,rhs,dest) ;
|
|
ARMul_AddOverflow(state,lhs,rhs,dest) ;
|
|
}
|
|
else {
|
|
CLEARN ;
|
|
CLEARC ;
|
|
CLEARV ;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
case 0x38 : /* ORR immed */
|
|
dest = LHS | DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x39 : /* ORRS immed */
|
|
DPSImmRHS ;
|
|
dest = LHS | rhs ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x3a : /* MOV immed */
|
|
dest = DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x3b : /* MOVS immed */
|
|
DPSImmRHS ;
|
|
WRITESDEST(rhs) ;
|
|
break ;
|
|
|
|
case 0x3c : /* BIC immed */
|
|
dest = LHS & ~DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x3d : /* BICS immed */
|
|
DPSImmRHS ;
|
|
dest = LHS & ~rhs ;
|
|
WRITESDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x3e : /* MVN immed */
|
|
dest = ~DPImmRHS ;
|
|
WRITEDEST(dest) ;
|
|
break ;
|
|
|
|
case 0x3f : /* MVNS immed */
|
|
DPSImmRHS ;
|
|
WRITESDEST(~rhs) ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Single Data Transfer Immediate RHS Instructions *
|
|
\***************************************************************************/
|
|
|
|
case 0x40 : /* Store Word, No WriteBack, Post Dec, Immed */
|
|
lhs = LHS ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = lhs - LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x41 : /* Load Word, No WriteBack, Post Dec, Immed */
|
|
lhs = LHS ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs - LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x42 : /* Store Word, WriteBack, Post Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
temp = lhs - LSImmRHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = temp ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x43 : /* Load Word, WriteBack, Post Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs - LSImmRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x44 : /* Store Byte, No WriteBack, Post Dec, Immed */
|
|
lhs = LHS ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs - LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x45 : /* Load Byte, No WriteBack, Post Dec, Immed */
|
|
lhs = LHS ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs - LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x46 : /* Store Byte, WriteBack, Post Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs - LSImmRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x47 : /* Load Byte, WriteBack, Post Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs - LSImmRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x48 : /* Store Word, No WriteBack, Post Inc, Immed */
|
|
lhs = LHS ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x49 : /* Load Word, No WriteBack, Post Inc, Immed */
|
|
lhs = LHS ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x4a : /* Store Word, WriteBack, Post Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x4b : /* Load Word, WriteBack, Post Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x4c : /* Store Byte, No WriteBack, Post Inc, Immed */
|
|
lhs = LHS ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x4d : /* Load Byte, No WriteBack, Post Inc, Immed */
|
|
lhs = LHS ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
break ;
|
|
|
|
case 0x4e : /* Store Byte, WriteBack, Post Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x4f : /* Load Byte, WriteBack, Post Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs + LSImmRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
|
|
case 0x50 : /* Store Word, No WriteBack, Pre Dec, Immed */
|
|
(void)StoreWord(state,instr,LHS - LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x51 : /* Load Word, No WriteBack, Pre Dec, Immed */
|
|
(void)LoadWord(state,instr,LHS - LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x52 : /* Store Word, WriteBack, Pre Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS - LSImmRHS ;
|
|
if (StoreWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x53 : /* Load Word, WriteBack, Pre Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS - LSImmRHS ;
|
|
if (LoadWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x54 : /* Store Byte, No WriteBack, Pre Dec, Immed */
|
|
(void)StoreByte(state,instr,LHS - LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x55 : /* Load Byte, No WriteBack, Pre Dec, Immed */
|
|
(void)LoadByte(state,instr,LHS - LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x56 : /* Store Byte, WriteBack, Pre Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS - LSImmRHS ;
|
|
if (StoreByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x57 : /* Load Byte, WriteBack, Pre Dec, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS - LSImmRHS ;
|
|
if (LoadByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x58 : /* Store Word, No WriteBack, Pre Inc, Immed */
|
|
(void)StoreWord(state,instr,LHS + LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x59 : /* Load Word, No WriteBack, Pre Inc, Immed */
|
|
(void)LoadWord(state,instr,LHS + LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x5a : /* Store Word, WriteBack, Pre Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS + LSImmRHS ;
|
|
if (StoreWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x5b : /* Load Word, WriteBack, Pre Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS + LSImmRHS ;
|
|
if (LoadWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x5c : /* Store Byte, No WriteBack, Pre Inc, Immed */
|
|
(void)StoreByte(state,instr,LHS + LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x5d : /* Load Byte, No WriteBack, Pre Inc, Immed */
|
|
(void)LoadByte(state,instr,LHS + LSImmRHS) ;
|
|
break ;
|
|
|
|
case 0x5e : /* Store Byte, WriteBack, Pre Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS + LSImmRHS ;
|
|
if (StoreByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x5f : /* Load Byte, WriteBack, Pre Inc, Immed */
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
temp = LHS + LSImmRHS ;
|
|
if (LoadByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Single Data Transfer Register RHS Instructions *
|
|
\***************************************************************************/
|
|
|
|
case 0x60 : /* Store Word, No WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x61 : /* Load Word, No WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x62 : /* Store Word, WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x63 : /* Load Word, WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x64 : /* Store Byte, No WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x65 : /* Load Byte, No WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x66 : /* Store Byte, WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x67 : /* Load Byte, WriteBack, Post Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs - LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x68 : /* Store Word, No WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x69 : /* Load Word, No WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x6a : /* Store Word, WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreWord(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x6b : /* Load Word, WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadWord(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x6c : /* Store Byte, No WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x6d : /* Load Byte, No WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
break ;
|
|
|
|
case 0x6e : /* Store Byte, WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (StoreByte(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
case 0x6f : /* Load Byte, WriteBack, Post Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
lhs = LHS ;
|
|
state->NtransSig = LOW ;
|
|
if (LoadByte(state,instr,lhs))
|
|
LSBase = lhs + LSRegRHS ;
|
|
state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
|
|
break ;
|
|
|
|
|
|
case 0x70 : /* Store Word, No WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)StoreWord(state,instr,LHS - LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x71 : /* Load Word, No WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)LoadWord(state,instr,LHS - LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x72 : /* Store Word, WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS - LSRegRHS ;
|
|
if (StoreWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x73 : /* Load Word, WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS - LSRegRHS ;
|
|
if (LoadWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x74 : /* Store Byte, No WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)StoreByte(state,instr,LHS - LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x75 : /* Load Byte, No WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)LoadByte(state,instr,LHS - LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x76 : /* Store Byte, WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS - LSRegRHS ;
|
|
if (StoreByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x77 : /* Load Byte, WriteBack, Pre Dec, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS - LSRegRHS ;
|
|
if (LoadByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x78 : /* Store Word, No WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)StoreWord(state,instr,LHS + LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x79 : /* Load Word, No WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)LoadWord(state,instr,LHS + LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x7a : /* Store Word, WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS + LSRegRHS ;
|
|
if (StoreWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x7b : /* Load Word, WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS + LSRegRHS ;
|
|
if (LoadWord(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x7c : /* Store Byte, No WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)StoreByte(state,instr,LHS + LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x7d : /* Load Byte, No WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
(void)LoadByte(state,instr,LHS + LSRegRHS) ;
|
|
break ;
|
|
|
|
case 0x7e : /* Store Byte, WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS + LSRegRHS ;
|
|
if (StoreByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
case 0x7f : /* Load Byte, WriteBack, Pre Inc, Reg */
|
|
if (BIT(4)) {
|
|
ARMul_UndefInstr(state,instr) ;
|
|
break ;
|
|
}
|
|
UNDEF_LSRBaseEQOffWb ;
|
|
UNDEF_LSRBaseEQDestWb ;
|
|
UNDEF_LSRPCBaseWb ;
|
|
UNDEF_LSRPCOffWb ;
|
|
temp = LHS + LSRegRHS ;
|
|
if (LoadByte(state,instr,temp))
|
|
LSBase = temp ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Multiple Data Transfer Instructions *
|
|
\***************************************************************************/
|
|
|
|
case 0x80 : /* Store, No WriteBack, Post Dec */
|
|
STOREMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x81 : /* Load, No WriteBack, Post Dec */
|
|
LOADMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x82 : /* Store, WriteBack, Post Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
STOREMULT(instr,temp + 4L,temp) ;
|
|
break ;
|
|
|
|
case 0x83 : /* Load, WriteBack, Post Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
LOADMULT(instr,temp + 4L,temp) ;
|
|
break ;
|
|
|
|
case 0x84 : /* Store, Flags, No WriteBack, Post Dec */
|
|
STORESMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x85 : /* Load, Flags, No WriteBack, Post Dec */
|
|
LOADSMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x86 : /* Store, Flags, WriteBack, Post Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
STORESMULT(instr,temp + 4L,temp) ;
|
|
break ;
|
|
|
|
case 0x87 : /* Load, Flags, WriteBack, Post Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
LOADSMULT(instr,temp + 4L,temp) ;
|
|
break ;
|
|
|
|
|
|
case 0x88 : /* Store, No WriteBack, Post Inc */
|
|
STOREMULT(instr,LSBase,0L) ;
|
|
break ;
|
|
|
|
case 0x89 : /* Load, No WriteBack, Post Inc */
|
|
LOADMULT(instr,LSBase,0L) ;
|
|
break ;
|
|
|
|
case 0x8a : /* Store, WriteBack, Post Inc */
|
|
temp = LSBase ;
|
|
STOREMULT(instr,temp,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
case 0x8b : /* Load, WriteBack, Post Inc */
|
|
temp = LSBase ;
|
|
LOADMULT(instr,temp,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
case 0x8c : /* Store, Flags, No WriteBack, Post Inc */
|
|
STORESMULT(instr,LSBase,0L) ;
|
|
break ;
|
|
|
|
case 0x8d : /* Load, Flags, No WriteBack, Post Inc */
|
|
LOADSMULT(instr,LSBase,0L) ;
|
|
break ;
|
|
|
|
case 0x8e : /* Store, Flags, WriteBack, Post Inc */
|
|
temp = LSBase ;
|
|
STORESMULT(instr,temp,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
case 0x8f : /* Load, Flags, WriteBack, Post Inc */
|
|
temp = LSBase ;
|
|
LOADSMULT(instr,temp,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
|
|
case 0x90 : /* Store, No WriteBack, Pre Dec */
|
|
STOREMULT(instr,LSBase - LSMNumRegs,0L) ;
|
|
break ;
|
|
|
|
case 0x91 : /* Load, No WriteBack, Pre Dec */
|
|
LOADMULT(instr,LSBase - LSMNumRegs,0L) ;
|
|
break ;
|
|
|
|
case 0x92 : /* Store, WriteBack, Pre Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
STOREMULT(instr,temp,temp) ;
|
|
break ;
|
|
|
|
case 0x93 : /* Load, WriteBack, Pre Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
LOADMULT(instr,temp,temp) ;
|
|
break ;
|
|
|
|
case 0x94 : /* Store, Flags, No WriteBack, Pre Dec */
|
|
STORESMULT(instr,LSBase - LSMNumRegs,0L) ;
|
|
break ;
|
|
|
|
case 0x95 : /* Load, Flags, No WriteBack, Pre Dec */
|
|
LOADSMULT(instr,LSBase - LSMNumRegs,0L) ;
|
|
break ;
|
|
|
|
case 0x96 : /* Store, Flags, WriteBack, Pre Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
STORESMULT(instr,temp,temp) ;
|
|
break ;
|
|
|
|
case 0x97 : /* Load, Flags, WriteBack, Pre Dec */
|
|
temp = LSBase - LSMNumRegs ;
|
|
LOADSMULT(instr,temp,temp) ;
|
|
break ;
|
|
|
|
|
|
case 0x98 : /* Store, No WriteBack, Pre Inc */
|
|
STOREMULT(instr,LSBase + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x99 : /* Load, No WriteBack, Pre Inc */
|
|
LOADMULT(instr,LSBase + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x9a : /* Store, WriteBack, Pre Inc */
|
|
temp = LSBase ;
|
|
STOREMULT(instr,temp + 4L,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
case 0x9b : /* Load, WriteBack, Pre Inc */
|
|
temp = LSBase ;
|
|
LOADMULT(instr,temp + 4L,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
case 0x9c : /* Store, Flags, No WriteBack, Pre Inc */
|
|
STORESMULT(instr,LSBase + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x9d : /* Load, Flags, No WriteBack, Pre Inc */
|
|
LOADSMULT(instr,LSBase + 4L,0L) ;
|
|
break ;
|
|
|
|
case 0x9e : /* Store, Flags, WriteBack, Pre Inc */
|
|
temp = LSBase ;
|
|
STORESMULT(instr,temp + 4L,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
case 0x9f : /* Load, Flags, WriteBack, Pre Inc */
|
|
temp = LSBase ;
|
|
LOADSMULT(instr,temp + 4L,temp + LSMNumRegs) ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Branch forward *
|
|
\***************************************************************************/
|
|
|
|
case 0xa0 : case 0xa1 : case 0xa2 : case 0xa3 :
|
|
case 0xa4 : case 0xa5 : case 0xa6 : case 0xa7 :
|
|
state->Reg[15] = pc + 8 + POSBRANCH ;
|
|
FLUSHPIPE ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Branch backward *
|
|
\***************************************************************************/
|
|
|
|
case 0xa8 : case 0xa9 : case 0xaa : case 0xab :
|
|
case 0xac : case 0xad : case 0xae : case 0xaf :
|
|
state->Reg[15] = pc + 8 + NEGBRANCH ;
|
|
FLUSHPIPE ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Branch and Link forward *
|
|
\***************************************************************************/
|
|
|
|
case 0xb0 : case 0xb1 : case 0xb2 : case 0xb3 :
|
|
case 0xb4 : case 0xb5 : case 0xb6 : case 0xb7 :
|
|
#ifdef MODE32
|
|
state->Reg[14] = pc + 4 ; /* put PC into Link */
|
|
#else
|
|
state->Reg[14] = pc + 4 | ECC | ER15INT | EMODE ; /* put PC into Link */
|
|
#endif
|
|
state->Reg[15] = pc + 8 + POSBRANCH ;
|
|
FLUSHPIPE ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Branch and Link backward *
|
|
\***************************************************************************/
|
|
|
|
case 0xb8 : case 0xb9 : case 0xba : case 0xbb :
|
|
case 0xbc : case 0xbd : case 0xbe : case 0xbf :
|
|
#ifdef MODE32
|
|
state->Reg[14] = pc + 4 ; /* put PC into Link */
|
|
#else
|
|
state->Reg[14] = (pc + 4) | ECC | ER15INT | EMODE ; /* put PC into Link */
|
|
#endif
|
|
state->Reg[15] = pc + 8 + NEGBRANCH ;
|
|
FLUSHPIPE ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Co-Processor Data Transfers *
|
|
\***************************************************************************/
|
|
|
|
case 0xc0 :
|
|
case 0xc4 : /* Store , No WriteBack , Post Dec */
|
|
ARMul_STC(state,instr,LHS) ;
|
|
break ;
|
|
|
|
case 0xc1 :
|
|
case 0xc5 : /* Load , No WriteBack , Post Dec */
|
|
ARMul_LDC(state,instr,LHS) ;
|
|
break ;
|
|
|
|
case 0xc2 :
|
|
case 0xc6 : /* Store , WriteBack , Post Dec */
|
|
lhs = LHS ;
|
|
state->Base = lhs - LSCOff ;
|
|
ARMul_STC(state,instr,lhs) ;
|
|
break ;
|
|
|
|
case 0xc3 :
|
|
case 0xc7 : /* Load , WriteBack , Post Dec */
|
|
lhs = LHS ;
|
|
state->Base = lhs - LSCOff ;
|
|
ARMul_LDC(state,instr,lhs) ;
|
|
break ;
|
|
|
|
case 0xc8 :
|
|
case 0xcc : /* Store , No WriteBack , Post Inc */
|
|
ARMul_STC(state,instr,LHS) ;
|
|
break ;
|
|
|
|
case 0xc9 :
|
|
case 0xcd : /* Load , No WriteBack , Post Inc */
|
|
ARMul_LDC(state,instr,LHS) ;
|
|
break ;
|
|
|
|
case 0xca :
|
|
case 0xce : /* Store , WriteBack , Post Inc */
|
|
lhs = LHS ;
|
|
state->Base = lhs + LSCOff ;
|
|
ARMul_STC(state,instr,LHS) ;
|
|
break ;
|
|
|
|
case 0xcb :
|
|
case 0xcf : /* Load , WriteBack , Post Inc */
|
|
lhs = LHS ;
|
|
state->Base = lhs + LSCOff ;
|
|
ARMul_LDC(state,instr,LHS) ;
|
|
break ;
|
|
|
|
|
|
case 0xd0 :
|
|
case 0xd4 : /* Store , No WriteBack , Pre Dec */
|
|
ARMul_STC(state,instr,LHS - LSCOff) ;
|
|
break ;
|
|
|
|
case 0xd1 :
|
|
case 0xd5 : /* Load , No WriteBack , Pre Dec */
|
|
ARMul_LDC(state,instr,LHS - LSCOff) ;
|
|
break ;
|
|
|
|
case 0xd2 :
|
|
case 0xd6 : /* Store , WriteBack , Pre Dec */
|
|
lhs = LHS - LSCOff ;
|
|
state->Base = lhs ;
|
|
ARMul_STC(state,instr,lhs) ;
|
|
break ;
|
|
|
|
case 0xd3 :
|
|
case 0xd7 : /* Load , WriteBack , Pre Dec */
|
|
lhs = LHS - LSCOff ;
|
|
state->Base = lhs ;
|
|
ARMul_LDC(state,instr,lhs) ;
|
|
break ;
|
|
|
|
case 0xd8 :
|
|
case 0xdc : /* Store , No WriteBack , Pre Inc */
|
|
ARMul_STC(state,instr,LHS + LSCOff) ;
|
|
break ;
|
|
|
|
case 0xd9 :
|
|
case 0xdd : /* Load , No WriteBack , Pre Inc */
|
|
ARMul_LDC(state,instr,LHS + LSCOff) ;
|
|
break ;
|
|
|
|
case 0xda :
|
|
case 0xde : /* Store , WriteBack , Pre Inc */
|
|
lhs = LHS + LSCOff ;
|
|
state->Base = lhs ;
|
|
ARMul_STC(state,instr,lhs) ;
|
|
break ;
|
|
|
|
case 0xdb :
|
|
case 0xdf : /* Load , WriteBack , Pre Inc */
|
|
lhs = LHS + LSCOff ;
|
|
state->Base = lhs ;
|
|
ARMul_LDC(state,instr,lhs) ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Co-Processor Register Transfers (MCR) and Data Ops *
|
|
\***************************************************************************/
|
|
|
|
case 0xe0 : case 0xe2 : case 0xe4 : case 0xe6 :
|
|
case 0xe8 : case 0xea : case 0xec : case 0xee :
|
|
if (BIT(4)) { /* MCR */
|
|
if (DESTReg == 15) {
|
|
UNDEF_MCRPC ;
|
|
#ifdef MODE32
|
|
ARMul_MCR(state,instr,state->Reg[15] + 4) ;
|
|
#else
|
|
ARMul_MCR(state,instr,ECC | ER15INT | EMODE |
|
|
((state->Reg[15] + 4) & R15PCBITS) ) ;
|
|
#endif
|
|
}
|
|
else
|
|
ARMul_MCR(state,instr,DEST) ;
|
|
}
|
|
else /* CDP Part 1 */
|
|
ARMul_CDP(state,instr) ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* Co-Processor Register Transfers (MRC) and Data Ops *
|
|
\***************************************************************************/
|
|
|
|
case 0xe1 : case 0xe3 : case 0xe5 : case 0xe7 :
|
|
case 0xe9 : case 0xeb : case 0xed : case 0xef :
|
|
if (BIT(4)) { /* MRC */
|
|
temp = ARMul_MRC(state,instr) ;
|
|
if (DESTReg == 15) {
|
|
ASSIGNN((temp & NBIT) != 0) ;
|
|
ASSIGNZ((temp & ZBIT) != 0) ;
|
|
ASSIGNC((temp & CBIT) != 0) ;
|
|
ASSIGNV((temp & VBIT) != 0) ;
|
|
}
|
|
else
|
|
DEST = temp ;
|
|
}
|
|
else /* CDP Part 2 */
|
|
ARMul_CDP(state,instr) ;
|
|
break ;
|
|
|
|
/***************************************************************************\
|
|
* SWI instruction *
|
|
\***************************************************************************/
|
|
|
|
case 0xf0 : case 0xf1 : case 0xf2 : case 0xf3 :
|
|
case 0xf4 : case 0xf5 : case 0xf6 : case 0xf7 :
|
|
case 0xf8 : case 0xf9 : case 0xfa : case 0xfb :
|
|
case 0xfc : case 0xfd : case 0xfe : case 0xff :
|
|
if (instr == ARMul_ABORTWORD && state->AbortAddr == pc) { /* a prefetch abort */
|
|
ARMul_Abort(state,ARMul_PrefetchAbortV) ;
|
|
break ;
|
|
}
|
|
|
|
if (!ARMul_OSHandleSWI(state,BITS(0,23))) {
|
|
ARMul_Abort(state,ARMul_SWIV) ;
|
|
}
|
|
break ;
|
|
} /* 256 way main switch */
|
|
} /* if temp */
|
|
|
|
if (state->Emulate == ONCE)
|
|
state->Emulate = STOP;
|
|
else if (state->Emulate != RUN)
|
|
break;
|
|
} while (1) ; /* do loop */
|
|
|
|
state->decoded = decoded ;
|
|
state->loaded = loaded ;
|
|
state->pc = pc ;
|
|
return(pc) ;
|
|
} /* Emulate 26/32 in instruction based mode */
|
|
|
|
|
|
/***************************************************************************\
|
|
* This routine evaluates most Data Processing register RHS's with the S *
|
|
* bit clear. It is intended to be called from the macro DPRegRHS, which *
|
|
* filters the common case of an unshifted register with in line code *
|
|
\***************************************************************************/
|
|
|
|
static ARMword GetDPRegRHS(ARMul_State *state, ARMword instr)
|
|
{ARMword shamt , base ;
|
|
|
|
base = RHSReg ;
|
|
if (BIT(4)) { /* shift amount in a register */
|
|
UNDEF_Shift ;
|
|
INCPC ;
|
|
#ifndef MODE32
|
|
if (base == 15)
|
|
base = ECC | ER15INT | R15PC | EMODE ;
|
|
else
|
|
#endif
|
|
base = state->Reg[base] ;
|
|
ARMul_Icycles(state,1,0L) ;
|
|
shamt = state->Reg[BITS(8,11)] & 0xff ;
|
|
switch ((int)BITS(5,6)) {
|
|
case LSL : if (shamt == 0)
|
|
return(base) ;
|
|
else if (shamt >= 32)
|
|
return(0) ;
|
|
else
|
|
return(base << shamt) ;
|
|
case LSR : if (shamt == 0)
|
|
return(base) ;
|
|
else if (shamt >= 32)
|
|
return(0) ;
|
|
else
|
|
return(base >> shamt) ;
|
|
case ASR : if (shamt == 0)
|
|
return(base) ;
|
|
else if (shamt >= 32)
|
|
return((ARMword)((long int)base >> 31L)) ;
|
|
else
|
|
return((ARMword)((long int)base >> (int)shamt)) ;
|
|
case ROR : shamt &= 0x1f ;
|
|
if (shamt == 0)
|
|
return(base) ;
|
|
else
|
|
return((base << (32 - shamt)) | (base >> shamt)) ;
|
|
}
|
|
}
|
|
else { /* shift amount is a constant */
|
|
#ifndef MODE32
|
|
if (base == 15)
|
|
base = ECC | ER15INT | R15PC | EMODE ;
|
|
else
|
|
#endif
|
|
base = state->Reg[base] ;
|
|
shamt = BITS(7,11) ;
|
|
switch ((int)BITS(5,6)) {
|
|
case LSL : return(base<<shamt) ;
|
|
case LSR : if (shamt == 0)
|
|
return(0) ;
|
|
else
|
|
return(base >> shamt) ;
|
|
case ASR : if (shamt == 0)
|
|
return((ARMword)((long int)base >> 31L)) ;
|
|
else
|
|
return((ARMword)((long int)base >> (int)shamt)) ;
|
|
case ROR : if (shamt==0) /* its an RRX */
|
|
return((base >> 1) | (CFLAG << 31)) ;
|
|
else
|
|
return((base << (32 - shamt)) | (base >> shamt)) ;
|
|
}
|
|
}
|
|
return(0) ; /* just to shut up lint */
|
|
}
|
|
/***************************************************************************\
|
|
* This routine evaluates most Logical Data Processing register RHS's *
|
|
* with the S bit set. It is intended to be called from the macro *
|
|
* DPSRegRHS, which filters the common case of an unshifted register *
|
|
* with in line code *
|
|
\***************************************************************************/
|
|
|
|
static ARMword GetDPSRegRHS(ARMul_State *state, ARMword instr)
|
|
{ARMword shamt , base ;
|
|
|
|
base = RHSReg ;
|
|
if (BIT(4)) { /* shift amount in a register */
|
|
UNDEF_Shift ;
|
|
INCPC ;
|
|
#ifndef MODE32
|
|
if (base == 15)
|
|
base = ECC | ER15INT | R15PC | EMODE ;
|
|
else
|
|
#endif
|
|
base = state->Reg[base] ;
|
|
ARMul_Icycles(state,1,0L) ;
|
|
shamt = state->Reg[BITS(8,11)] & 0xff ;
|
|
switch ((int)BITS(5,6)) {
|
|
case LSL : if (shamt == 0)
|
|
return(base) ;
|
|
else if (shamt == 32) {
|
|
ASSIGNC(base & 1) ;
|
|
return(0) ;
|
|
}
|
|
else if (shamt > 32) {
|
|
CLEARC ;
|
|
return(0) ;
|
|
}
|
|
else {
|
|
ASSIGNC((base >> (32-shamt)) & 1) ;
|
|
return(base << shamt) ;
|
|
}
|
|
case LSR : if (shamt == 0)
|
|
return(base) ;
|
|
else if (shamt == 32) {
|
|
ASSIGNC(base >> 31) ;
|
|
return(0) ;
|
|
}
|
|
else if (shamt > 32) {
|
|
CLEARC ;
|
|
return(0) ;
|
|
}
|
|
else {
|
|
ASSIGNC((base >> (shamt - 1)) & 1) ;
|
|
return(base >> shamt) ;
|
|
}
|
|
case ASR : if (shamt == 0)
|
|
return(base) ;
|
|
else if (shamt >= 32) {
|
|
ASSIGNC(base >> 31L) ;
|
|
return((ARMword)((long int)base >> 31L)) ;
|
|
}
|
|
else {
|
|
ASSIGNC((ARMword)((long int)base >> (int)(shamt-1)) & 1) ;
|
|
return((ARMword)((long int)base >> (int)shamt)) ;
|
|
}
|
|
case ROR : if (shamt == 0)
|
|
return(base) ;
|
|
shamt &= 0x1f ;
|
|
if (shamt == 0) {
|
|
ASSIGNC(base >> 31) ;
|
|
return(base) ;
|
|
}
|
|
else {
|
|
ASSIGNC((base >> (shamt-1)) & 1) ;
|
|
return((base << (32-shamt)) | (base >> shamt)) ;
|
|
}
|
|
}
|
|
}
|
|
else { /* shift amount is a constant */
|
|
#ifndef MODE32
|
|
if (base == 15)
|
|
base = ECC | ER15INT | R15PC | EMODE ;
|
|
else
|
|
#endif
|
|
base = state->Reg[base] ;
|
|
shamt = BITS(7,11) ;
|
|
switch ((int)BITS(5,6)) {
|
|
case LSL : ASSIGNC((base >> (32-shamt)) & 1) ;
|
|
return(base << shamt) ;
|
|
case LSR : if (shamt == 0) {
|
|
ASSIGNC(base >> 31) ;
|
|
return(0) ;
|
|
}
|
|
else {
|
|
ASSIGNC((base >> (shamt - 1)) & 1) ;
|
|
return(base >> shamt) ;
|
|
}
|
|
case ASR : if (shamt == 0) {
|
|
ASSIGNC(base >> 31L) ;
|
|
return((ARMword)((long int)base >> 31L)) ;
|
|
}
|
|
else {
|
|
ASSIGNC((ARMword)((long int)base >> (int)(shamt-1)) & 1) ;
|
|
return((ARMword)((long int)base >> (int)shamt)) ;
|
|
}
|
|
case ROR : if (shamt == 0) { /* its an RRX */
|
|
shamt = CFLAG ;
|
|
ASSIGNC(base & 1) ;
|
|
return((base >> 1) | (shamt << 31)) ;
|
|
}
|
|
else {
|
|
ASSIGNC((base >> (shamt - 1)) & 1) ;
|
|
return((base << (32-shamt)) | (base >> shamt)) ;
|
|
}
|
|
}
|
|
}
|
|
return(0) ; /* just to shut up lint */
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This routine handles writes to register 15 when the S bit is not set. *
|
|
\***************************************************************************/
|
|
|
|
static void WriteR15(ARMul_State *state, ARMword src)
|
|
{
|
|
#ifdef MODE32
|
|
state->Reg[15] = src & PCBITS ;
|
|
#else
|
|
state->Reg[15] = (src & R15PCBITS) | ECC | ER15INT | EMODE ;
|
|
ARMul_R15Altered(state) ;
|
|
#endif
|
|
FLUSHPIPE ;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This routine handles writes to register 15 when the S bit is set. *
|
|
\***************************************************************************/
|
|
|
|
static void WriteSR15(ARMul_State *state, ARMword src)
|
|
{
|
|
#ifdef MODE32
|
|
state->Reg[15] = src & PCBITS ;
|
|
if (state->Bank > 0) {
|
|
state->Cpsr = state->Spsr[state->Bank] ;
|
|
ARMul_CPSRAltered(state) ;
|
|
}
|
|
#else
|
|
if (state->Bank == USERBANK)
|
|
state->Reg[15] = (src & (CCBITS | R15PCBITS)) | ER15INT | EMODE ;
|
|
else
|
|
state->Reg[15] = src ;
|
|
ARMul_R15Altered(state) ;
|
|
#endif
|
|
FLUSHPIPE ;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This routine evaluates most Load and Store register RHS's. It is *
|
|
* intended to be called from the macro LSRegRHS, which filters the *
|
|
* common case of an unshifted register with in line code *
|
|
\***************************************************************************/
|
|
|
|
static ARMword GetLSRegRHS(ARMul_State *state, ARMword instr)
|
|
{ARMword shamt, base ;
|
|
|
|
base = RHSReg ;
|
|
#ifndef MODE32
|
|
if (base == 15)
|
|
base = ECC | ER15INT | R15PC | EMODE ; /* Now forbidden, but .... */
|
|
else
|
|
#endif
|
|
base = state->Reg[base] ;
|
|
|
|
shamt = BITS(7,11) ;
|
|
switch ((int)BITS(5,6)) {
|
|
case LSL : return(base << shamt) ;
|
|
case LSR : if (shamt == 0)
|
|
return(0) ;
|
|
else
|
|
return(base >> shamt) ;
|
|
case ASR : if (shamt == 0)
|
|
return((ARMword)((long int)base >> 31L)) ;
|
|
else
|
|
return((ARMword)((long int)base >> (int)shamt)) ;
|
|
case ROR : if (shamt==0) /* its an RRX */
|
|
return((base >> 1) | (CFLAG << 31)) ;
|
|
else
|
|
return((base << (32-shamt)) | (base >> shamt)) ;
|
|
}
|
|
return(0) ; /* just to shut up lint */
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of loading a word for a LDR instruction. *
|
|
\***************************************************************************/
|
|
|
|
static unsigned LoadWord(ARMul_State *state, ARMword instr, ARMword address)
|
|
{
|
|
ARMword dest ;
|
|
|
|
BUSUSEDINCPCS ;
|
|
#ifndef MODE32
|
|
if (ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
}
|
|
#endif
|
|
dest = ARMul_LoadWordN(state,address) ;
|
|
if (state->Aborted) {
|
|
TAKEABORT ;
|
|
return(state->lateabtSig) ;
|
|
}
|
|
if (address & 3)
|
|
dest = ARMul_Align(state,address,dest) ;
|
|
WRITEDEST(dest) ;
|
|
ARMul_Icycles(state,1,0L) ;
|
|
|
|
return(DESTReg != LHSReg) ;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of loading a byte for a LDRB instruction. *
|
|
\***************************************************************************/
|
|
|
|
static unsigned LoadByte(ARMul_State *state, ARMword instr, ARMword address)
|
|
{
|
|
ARMword dest ;
|
|
|
|
BUSUSEDINCPCS ;
|
|
#ifndef MODE32
|
|
if (ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
}
|
|
#endif
|
|
dest = ARMul_LoadByte(state,address) ;
|
|
if (state->Aborted) {
|
|
TAKEABORT ;
|
|
return(state->lateabtSig) ;
|
|
}
|
|
UNDEF_LSRBPC ;
|
|
WRITEDEST(dest) ;
|
|
ARMul_Icycles(state,1,0L) ;
|
|
return(DESTReg != LHSReg) ;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of storing a word from a STR instruction. *
|
|
\***************************************************************************/
|
|
|
|
static unsigned StoreWord(ARMul_State *state, ARMword instr, ARMword address)
|
|
{BUSUSEDINCPCN ;
|
|
#ifndef MODE32
|
|
if (DESTReg == 15)
|
|
state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
|
|
#endif
|
|
#ifdef MODE32
|
|
ARMul_StoreWordN(state,address,DEST) ;
|
|
#else
|
|
if (VECTORACCESS(address) || ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
(void)ARMul_LoadWordN(state,address) ;
|
|
}
|
|
else
|
|
ARMul_StoreWordN(state,address,DEST) ;
|
|
#endif
|
|
if (state->Aborted) {
|
|
TAKEABORT ;
|
|
return(state->lateabtSig) ;
|
|
}
|
|
return(TRUE) ;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of storing a byte for a STRB instruction. *
|
|
\***************************************************************************/
|
|
|
|
static unsigned StoreByte(ARMul_State *state, ARMword instr, ARMword address)
|
|
{BUSUSEDINCPCN ;
|
|
#ifndef MODE32
|
|
if (DESTReg == 15)
|
|
state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
|
|
#endif
|
|
#ifdef MODE32
|
|
ARMul_StoreByte(state,address,DEST) ;
|
|
#else
|
|
if (VECTORACCESS(address) || ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
(void)ARMul_LoadByte(state,address) ;
|
|
}
|
|
else
|
|
ARMul_StoreByte(state,address,DEST) ;
|
|
#endif
|
|
if (state->Aborted) {
|
|
TAKEABORT ;
|
|
return(state->lateabtSig) ;
|
|
}
|
|
UNDEF_LSRBPC ;
|
|
return(TRUE) ;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of loading the registers listed in an LDM *
|
|
* instruction, when the S bit is clear. The code here is always increment *
|
|
* after, it's up to the caller to get the input address correct and to *
|
|
* handle base register modification. *
|
|
\***************************************************************************/
|
|
|
|
static void LoadMult(ARMul_State *state, ARMword instr,
|
|
ARMword address, ARMword WBBase)
|
|
{ARMword dest, temp ;
|
|
|
|
UNDEF_LSMNoRegs ;
|
|
UNDEF_LSMPCBase ;
|
|
UNDEF_LSMBaseInListWb ;
|
|
BUSUSEDINCPCS ;
|
|
#ifndef MODE32
|
|
if (ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
}
|
|
#endif
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
|
|
for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
|
|
dest = ARMul_LoadWordN(state,address) ;
|
|
if (!state->abortSig && !state->Aborted)
|
|
state->Reg[temp++] = dest ;
|
|
else
|
|
if (!state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
|
|
for (; temp < 16 ; temp++) /* S cycles from here on */
|
|
if (BIT(temp)) { /* load this register */
|
|
address += 4 ;
|
|
dest = ARMul_LoadWordS(state,address) ;
|
|
if (!state->abortSig && !state->Aborted)
|
|
state->Reg[temp] = dest ;
|
|
else
|
|
if (!state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
}
|
|
|
|
if (BIT(15)) { /* PC is in the reg list */
|
|
#ifdef MODE32
|
|
state->Reg[15] = PC ;
|
|
#endif
|
|
FLUSHPIPE ;
|
|
}
|
|
|
|
ARMul_Icycles(state,1,0L) ; /* to write back the final register */
|
|
|
|
if (state->Aborted) {
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
TAKEABORT ;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of loading the registers listed in an LDM *
|
|
* instruction, when the S bit is set. The code here is always increment *
|
|
* after, it's up to the caller to get the input address correct and to *
|
|
* handle base register modification. *
|
|
\***************************************************************************/
|
|
|
|
static void LoadSMult(ARMul_State *state, ARMword instr,
|
|
ARMword address, ARMword WBBase)
|
|
{ARMword dest, temp ;
|
|
|
|
UNDEF_LSMNoRegs ;
|
|
UNDEF_LSMPCBase ;
|
|
UNDEF_LSMBaseInListWb ;
|
|
BUSUSEDINCPCS ;
|
|
#ifndef MODE32
|
|
if (ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
}
|
|
#endif
|
|
|
|
if (!BIT(15) && state->Bank != USERBANK) {
|
|
(void)ARMul_SwitchMode(state,state->Mode,USER26MODE) ; /* temporary reg bank switch */
|
|
UNDEF_LSMUserBankWb ;
|
|
}
|
|
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
|
|
for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
|
|
dest = ARMul_LoadWordN(state,address) ;
|
|
if (!state->abortSig)
|
|
state->Reg[temp++] = dest ;
|
|
else
|
|
if (!state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
|
|
for (; temp < 16 ; temp++) /* S cycles from here on */
|
|
if (BIT(temp)) { /* load this register */
|
|
address += 4 ;
|
|
dest = ARMul_LoadWordS(state,address) ;
|
|
if (!state->abortSig || state->Aborted)
|
|
state->Reg[temp] = dest ;
|
|
else
|
|
if (!state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
}
|
|
|
|
if (BIT(15)) { /* PC is in the reg list */
|
|
#ifdef MODE32
|
|
if (state->Mode != USER26MODE && state->Mode != USER32MODE) {
|
|
state->Cpsr = GETSPSR(state->Bank) ;
|
|
ARMul_CPSRAltered(state) ;
|
|
}
|
|
state->Reg[15] = PC ;
|
|
#else
|
|
if (state->Mode == USER26MODE || state->Mode == USER32MODE) { /* protect bits in user mode */
|
|
ASSIGNN((state->Reg[15] & NBIT) != 0) ;
|
|
ASSIGNZ((state->Reg[15] & ZBIT) != 0) ;
|
|
ASSIGNC((state->Reg[15] & CBIT) != 0) ;
|
|
ASSIGNV((state->Reg[15] & VBIT) != 0) ;
|
|
}
|
|
else
|
|
ARMul_R15Altered(state) ;
|
|
#endif
|
|
FLUSHPIPE ;
|
|
}
|
|
|
|
if (!BIT(15) && state->Mode != USER26MODE && state->Mode != USER32MODE)
|
|
(void)ARMul_SwitchMode(state,USER26MODE,state->Mode) ; /* restore the correct bank */
|
|
|
|
ARMul_Icycles(state,1,0L) ; /* to write back the final register */
|
|
|
|
if (state->Aborted) {
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
TAKEABORT ;
|
|
}
|
|
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of storing the registers listed in an STM *
|
|
* instruction, when the S bit is clear. The code here is always increment *
|
|
* after, it's up to the caller to get the input address correct and to *
|
|
* handle base register modification. *
|
|
\***************************************************************************/
|
|
|
|
static void StoreMult(ARMul_State *state, ARMword instr,
|
|
ARMword address, ARMword WBBase)
|
|
{ARMword temp ;
|
|
|
|
UNDEF_LSMNoRegs ;
|
|
UNDEF_LSMPCBase ;
|
|
UNDEF_LSMBaseInListWb ;
|
|
BUSUSEDINCPCN ;
|
|
#ifndef MODE32
|
|
if (VECTORACCESS(address) || ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
}
|
|
if (BIT(15))
|
|
PATCHR15 ;
|
|
#endif
|
|
|
|
for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
|
|
#ifdef MODE32
|
|
ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
|
|
#else
|
|
if (state->Aborted) {
|
|
(void)ARMul_LoadWordN(state,address) ;
|
|
for ( ; temp < 16 ; temp++) /* Fake the Stores as Loads */
|
|
if (BIT(temp)) { /* save this register */
|
|
address += 4 ;
|
|
(void)ARMul_LoadWordS(state,address) ;
|
|
}
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
TAKEABORT ;
|
|
return ;
|
|
}
|
|
else
|
|
ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
|
|
#endif
|
|
if (state->abortSig && !state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
|
|
for ( ; temp < 16 ; temp++) /* S cycles from here on */
|
|
if (BIT(temp)) { /* save this register */
|
|
address += 4 ;
|
|
ARMul_StoreWordS(state,address,state->Reg[temp]) ;
|
|
if (state->abortSig && !state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
}
|
|
if (state->Aborted) {
|
|
TAKEABORT ;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* This function does the work of storing the registers listed in an STM *
|
|
* instruction when the S bit is set. The code here is always increment *
|
|
* after, it's up to the caller to get the input address correct and to *
|
|
* handle base register modification. *
|
|
\***************************************************************************/
|
|
|
|
static void StoreSMult(ARMul_State *state, ARMword instr,
|
|
ARMword address, ARMword WBBase)
|
|
{ARMword temp ;
|
|
|
|
UNDEF_LSMNoRegs ;
|
|
UNDEF_LSMPCBase ;
|
|
UNDEF_LSMBaseInListWb ;
|
|
BUSUSEDINCPCN ;
|
|
#ifndef MODE32
|
|
if (VECTORACCESS(address) || ADDREXCEPT(address)) {
|
|
INTERNALABORT(address) ;
|
|
}
|
|
if (BIT(15))
|
|
PATCHR15 ;
|
|
#endif
|
|
|
|
if (state->Bank != USERBANK) {
|
|
(void)ARMul_SwitchMode(state,state->Mode,USER26MODE) ; /* Force User Bank */
|
|
UNDEF_LSMUserBankWb ;
|
|
}
|
|
|
|
for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
|
|
#ifdef MODE32
|
|
ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
|
|
#else
|
|
if (state->Aborted) {
|
|
(void)ARMul_LoadWordN(state,address) ;
|
|
for ( ; temp < 16 ; temp++) /* Fake the Stores as Loads */
|
|
if (BIT(temp)) { /* save this register */
|
|
address += 4 ;
|
|
(void)ARMul_LoadWordS(state,address) ;
|
|
}
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
TAKEABORT ;
|
|
return ;
|
|
}
|
|
else
|
|
ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
|
|
#endif
|
|
if (state->abortSig && !state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
|
|
if (BIT(21) && LHSReg != 15)
|
|
LSBase = WBBase ;
|
|
|
|
for (; temp < 16 ; temp++) /* S cycles from here on */
|
|
if (BIT(temp)) { /* save this register */
|
|
address += 4 ;
|
|
ARMul_StoreWordS(state,address,state->Reg[temp]) ;
|
|
if (state->abortSig && !state->Aborted)
|
|
state->Aborted = ARMul_DataAbortV ;
|
|
}
|
|
|
|
if (state->Mode != USER26MODE && state->Mode != USER32MODE)
|
|
(void)ARMul_SwitchMode(state,USER26MODE,state->Mode) ; /* restore the correct bank */
|
|
|
|
if (state->Aborted) {
|
|
TAKEABORT ;
|
|
}
|
|
}
|