1999-04-16 01:33:56 +00:00
/* armemu.c -- Main instruction emulation: ARM7 Instruction Emulator.
Copyright ( C ) 1994 Advanced RISC Machines Ltd .
Modifications to add arch . v4 support by < jsmith @ cygnus . com > .
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"
1999-04-26 18:30:24 +00:00
# include "armos.h"
1999-04-16 01:33:56 +00:00
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 ARMword GetLS7RHS ( ARMul_State * state , ARMword instr ) ;
static unsigned LoadWord ( ARMul_State * state , ARMword instr , ARMword address ) ;
static unsigned LoadHalfWord ( ARMul_State * state , ARMword instr , ARMword address , int signextend ) ;
static unsigned LoadByte ( ARMul_State * state , ARMword instr , ARMword address , int signextend ) ;
static unsigned StoreWord ( ARMul_State * state , ARMword instr , ARMword address ) ;
static unsigned StoreHalfWord ( 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 ) ;
static unsigned Multiply64 ( ARMul_State * state , ARMword instr , int signextend , int scc ) ;
static unsigned MultiplyAdd64 ( ARMul_State * state , ARMword instr , int signextend , int scc ) ;
# define LUNSIGNED (0) /* unsigned operation */
# define LSIGNED (1) /* signed operation */
# define LDEFAULT (0) /* default : do nothing */
# define LSCC (1) /* set condition codes on result */
1999-04-26 18:30:24 +00:00
# ifdef NEED_UI_LOOP_HOOK
/* How often to run the ui_loop update, when in use */
# define UI_LOOP_POLL_INTERVAL 0x32000
/* Counter for the ui_loop_hook update */
static long ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL ;
/* Actual hook to call to run through gdb's gui event loop */
extern int ( * ui_loop_hook ) ( int ) ;
# endif /* NEED_UI_LOOP_HOOK */
extern int stop_simulator ;
1999-04-16 01:33:56 +00:00
/***************************************************************************\
* short - hand macros for LDR / STR *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* store post decrement writeback */
# define SHDOWNWB() \
lhs = LHS ; \
if ( StoreHalfWord ( state , instr , lhs ) ) \
LSBase = lhs - GetLS7RHS ( state , instr ) ;
/* store post increment writeback */
# define SHUPWB() \
lhs = LHS ; \
if ( StoreHalfWord ( state , instr , lhs ) ) \
LSBase = lhs + GetLS7RHS ( state , instr ) ;
/* store pre decrement */
# define SHPREDOWN() \
( void ) StoreHalfWord ( state , instr , LHS - GetLS7RHS ( state , instr ) ) ;
/* store pre decrement writeback */
# define SHPREDOWNWB() \
temp = LHS - GetLS7RHS ( state , instr ) ; \
if ( StoreHalfWord ( state , instr , temp ) ) \
LSBase = temp ;
/* store pre increment */
# define SHPREUP() \
( void ) StoreHalfWord ( state , instr , LHS + GetLS7RHS ( state , instr ) ) ;
/* store pre increment writeback */
# define SHPREUPWB() \
temp = LHS + GetLS7RHS ( state , instr ) ; \
if ( StoreHalfWord ( state , instr , temp ) ) \
LSBase = temp ;
/* load post decrement writeback */
# define LHPOSTDOWN() \
{ \
int done = 1 ; \
lhs = LHS ; \
switch ( BITS ( 5 , 6 ) ) { \
case 1 : /* H */ \
if ( LoadHalfWord ( state , instr , lhs , LUNSIGNED ) ) \
LSBase = lhs - GetLS7RHS ( state , instr ) ; \
break ; \
case 2 : /* SB */ \
if ( LoadByte ( state , instr , lhs , LSIGNED ) ) \
LSBase = lhs - GetLS7RHS ( state , instr ) ; \
break ; \
case 3 : /* SH */ \
if ( LoadHalfWord ( state , instr , lhs , LSIGNED ) ) \
LSBase = lhs - GetLS7RHS ( state , instr ) ; \
break ; \
case 0 : /* SWP handled elsewhere */ \
default : \
done = 0 ; \
break ; \
} \
if ( done ) \
break ; \
}
/* load post increment writeback */
# define LHPOSTUP() \
{ \
int done = 1 ; \
lhs = LHS ; \
switch ( BITS ( 5 , 6 ) ) { \
case 1 : /* H */ \
if ( LoadHalfWord ( state , instr , lhs , LUNSIGNED ) ) \
LSBase = lhs + GetLS7RHS ( state , instr ) ; \
break ; \
case 2 : /* SB */ \
if ( LoadByte ( state , instr , lhs , LSIGNED ) ) \
LSBase = lhs + GetLS7RHS ( state , instr ) ; \
break ; \
case 3 : /* SH */ \
if ( LoadHalfWord ( state , instr , lhs , LSIGNED ) ) \
LSBase = lhs + GetLS7RHS ( state , instr ) ; \
break ; \
case 0 : /* SWP handled elsewhere */ \
default : \
done = 0 ; \
break ; \
} \
if ( done ) \
break ; \
}
/* load pre decrement */
# define LHPREDOWN() \
{ \
int done = 1 ; \
temp = LHS - GetLS7RHS ( state , instr ) ; \
switch ( BITS ( 5 , 6 ) ) { \
case 1 : /* H */ \
( void ) LoadHalfWord ( state , instr , temp , LUNSIGNED ) ; \
break ; \
case 2 : /* SB */ \
( void ) LoadByte ( state , instr , temp , LSIGNED ) ; \
break ; \
case 3 : /* SH */ \
( void ) LoadHalfWord ( state , instr , temp , LSIGNED ) ; \
break ; \
case 0 : /* SWP handled elsewhere */ \
default : \
done = 0 ; \
break ; \
} \
if ( done ) \
break ; \
}
/* load pre decrement writeback */
# define LHPREDOWNWB() \
{ \
int done = 1 ; \
temp = LHS - GetLS7RHS ( state , instr ) ; \
switch ( BITS ( 5 , 6 ) ) { \
case 1 : /* H */ \
if ( LoadHalfWord ( state , instr , temp , LUNSIGNED ) ) \
LSBase = temp ; \
break ; \
case 2 : /* SB */ \
if ( LoadByte ( state , instr , temp , LSIGNED ) ) \
LSBase = temp ; \
break ; \
case 3 : /* SH */ \
if ( LoadHalfWord ( state , instr , temp , LSIGNED ) ) \
LSBase = temp ; \
break ; \
case 0 : /* SWP handled elsewhere */ \
default : \
done = 0 ; \
break ; \
} \
if ( done ) \
break ; \
}
/* load pre increment */
# define LHPREUP() \
{ \
int done = 1 ; \
temp = LHS + GetLS7RHS ( state , instr ) ; \
switch ( BITS ( 5 , 6 ) ) { \
case 1 : /* H */ \
( void ) LoadHalfWord ( state , instr , temp , LUNSIGNED ) ; \
break ; \
case 2 : /* SB */ \
( void ) LoadByte ( state , instr , temp , LSIGNED ) ; \
break ; \
case 3 : /* SH */ \
( void ) LoadHalfWord ( state , instr , temp , LSIGNED ) ; \
break ; \
case 0 : /* SWP handled elsewhere */ \
default : \
done = 0 ; \
break ; \
} \
if ( done ) \
break ; \
}
/* load pre increment writeback */
# define LHPREUPWB() \
{ \
int done = 1 ; \
temp = LHS + GetLS7RHS ( state , instr ) ; \
switch ( BITS ( 5 , 6 ) ) { \
case 1 : /* H */ \
if ( LoadHalfWord ( state , instr , temp , LUNSIGNED ) ) \
LSBase = temp ; \
break ; \
case 2 : /* SB */ \
if ( LoadByte ( state , instr , temp , LSIGNED ) ) \
LSBase = temp ; \
break ; \
case 3 : /* SH */ \
if ( LoadHalfWord ( state , instr , temp , LSIGNED ) ) \
LSBase = temp ; \
break ; \
case 0 : /* SWP handled elsewhere */ \
default : \
done = 0 ; \
break ; \
} \
if ( done ) \
break ; \
}
/***************************************************************************\
* EMULATION of ARM6 *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* The PC pipeline value depends on whether ARM or Thumb instructions
are being executed : */
ARMword isize ;
# 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 */
# ifdef MODET
if ( TFLAG ) {
isize = 2 ;
} else
# endif
isize = 4 ;
switch ( state - > NextInstr ) {
case SEQ :
state - > Reg [ 15 ] + = isize ; /* Advance the pipeline, and an S cycle */
pc + = isize ;
instr = decoded ;
decoded = loaded ;
loaded = ARMul_LoadInstrS ( state , pc + ( isize * 2 ) , isize ) ;
break ;
case NONSEQ :
state - > Reg [ 15 ] + = isize ; /* Advance the pipeline, and an N cycle */
pc + = isize ;
instr = decoded ;
decoded = loaded ;
loaded = ARMul_LoadInstrN ( state , pc + ( isize * 2 ) , isize ) ;
NORMALCYCLE ;
break ;
case PCINCEDSEQ :
pc + = isize ; /* Program counter advanced, and an S cycle */
instr = decoded ;
decoded = loaded ;
loaded = ARMul_LoadInstrS ( state , pc + ( isize * 2 ) , isize ) ;
NORMALCYCLE ;
break ;
case PCINCEDNONSEQ :
pc + = isize ; /* Program counter advanced, and an N cycle */
instr = decoded ;
decoded = loaded ;
loaded = ARMul_LoadInstrN ( state , pc + ( isize * 2 ) , isize ) ;
NORMALCYCLE ;
break ;
case RESUME : /* The program counter has been changed */
pc = state - > Reg [ 15 ] ;
# ifndef MODE32
pc = pc & R15PCBITS ;
# endif
state - > Reg [ 15 ] = pc + ( isize * 2 ) ;
state - > Aborted = 0 ;
instr = ARMul_ReLoadInstr ( state , pc , isize ) ;
decoded = ARMul_ReLoadInstr ( state , pc + isize , isize ) ;
loaded = ARMul_ReLoadInstr ( state , pc + isize * 2 , isize ) ;
NORMALCYCLE ;
break ;
default : /* The program counter has been changed */
pc = state - > Reg [ 15 ] ;
# ifndef MODE32
pc = pc & R15PCBITS ;
# endif
state - > Reg [ 15 ] = pc + ( isize * 2 ) ;
state - > Aborted = 0 ;
instr = ARMul_LoadInstrN ( state , pc , isize ) ;
decoded = ARMul_LoadInstrS ( state , pc + ( isize ) , isize ) ;
loaded = ARMul_LoadInstrS ( state , pc + ( isize * 2 ) , isize ) ;
NORMALCYCLE ;
break ;
}
if ( state - > EventSet )
ARMul_EnvokeEvent ( state ) ;
#if 0
/* Enable this for a helpful bit of debugging when tracing is needed. */
fprintf ( stderr , " pc: %x, instr: %x \n " , pc & ~ 1 , instr ) ;
if ( instr = = 0 ) abort ( ) ;
# endif
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 + + ;
# ifdef MODET
/* Provide Thumb instruction decoding. If the processor is in Thumb
mode , then we can simply decode the Thumb instruction , and map it
to the corresponding ARM instruction ( by directly loading the
instr variable , and letting the normal ARM simulator
execute ) . There are some caveats to ensure that the correct
pipelined PC value is used when executing Thumb code , and also for
dealing with the BL instruction . */
if ( TFLAG ) { /* check if in Thumb mode */
ARMword new ;
switch ( ARMul_ThumbDecode ( state , pc , instr , & new ) ) {
case t_undefined :
ARMul_UndefInstr ( state , instr ) ; /* This is a Thumb instruction */
break ;
case t_branch : /* already processed */
goto donext ;
case t_decoded : /* ARM instruction available */
instr = new ; /* so continue instruction decoding */
break ;
}
}
# endif
/***************************************************************************\
* 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 */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, no write-back, down, post indexed */
SHDOWNWB ( ) ;
break ;
}
/* TODO: CHECK: should 0xD and 0xF generate undefined intruction aborts? */
# endif
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 */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, no write-back, down, post indexed */
LHPOSTDOWN ( ) ;
/* fall through to rest of decoding */
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, write-back, down, post indexed */
SHDOWNWB ( ) ;
break ;
}
# endif
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 */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, write-back, down, post-indexed */
LHPOSTDOWN ( ) ;
/* fall through to rest of the decoding */
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, no write-back, down, post indexed */
SHDOWNWB ( ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = LHS - rhs ;
WRITEDEST ( dest ) ;
break ;
case 0x05 : /* SUBS reg */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, no write-back, down, post indexed */
LHPOSTDOWN ( ) ;
/* fall through to the rest of the instruction decoding */
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, write-back, down, post indexed */
SHDOWNWB ( ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = rhs - LHS ;
WRITEDEST ( dest ) ;
break ;
case 0x07 : /* RSBS reg */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, write-back, down, post indexed */
LHPOSTDOWN ( ) ;
/* fall through to remainder of instruction decoding */
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, no write-back, up, post indexed */
SHUPWB ( ) ;
break ;
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32 = 64 */
ARMul_Icycles ( state , Multiply64 ( state , instr , LUNSIGNED , LDEFAULT ) , 0L ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = LHS + rhs ;
WRITEDEST ( dest ) ;
break ;
case 0x09 : /* ADDS reg */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, no write-back, up, post indexed */
LHPOSTUP ( ) ;
/* fall through to remaining instruction decoding */
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32=64 */
ARMul_Icycles ( state , Multiply64 ( state , instr , LUNSIGNED , LSCC ) , 0L ) ;
break ;
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, write-back, up, post-indexed */
SHUPWB ( ) ;
break ;
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32=64 */
ARMul_Icycles ( state , MultiplyAdd64 ( state , instr , LUNSIGNED , LDEFAULT ) , 0L ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = LHS + rhs + CFLAG ;
WRITEDEST ( dest ) ;
break ;
case 0x0b : /* ADCS reg */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, write-back, up, post indexed */
LHPOSTUP ( ) ;
/* fall through to remaining instruction decoding */
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32=64 */
ARMul_Icycles ( state , MultiplyAdd64 ( state , instr , LUNSIGNED , LSCC ) , 0L ) ;
break ;
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, no write-back, up post indexed */
SHUPWB ( ) ;
break ;
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32=64 */
ARMul_Icycles ( state , Multiply64 ( state , instr , LSIGNED , LDEFAULT ) , 0L ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = LHS - rhs - ! CFLAG ;
WRITEDEST ( dest ) ;
break ;
case 0x0d : /* SBCS reg */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, no write-back, up, post indexed */
LHPOSTUP ( ) ;
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32=64 */
ARMul_Icycles ( state , Multiply64 ( state , instr , LSIGNED , LSCC ) , 0L ) ;
break ;
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, write-back, up, post indexed */
SHUPWB ( ) ;
break ;
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32=64 */
ARMul_Icycles ( state , MultiplyAdd64 ( state , instr , LSIGNED , LDEFAULT ) , 0L ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = rhs - LHS - ! CFLAG ;
WRITEDEST ( dest ) ;
break ;
case 0x0f : /* RSCS reg */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, write-back, up, post indexed */
LHPOSTUP ( ) ;
/* fall through to remaining instruction decoding */
}
# endif
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0x9 ) { /* MULL */
/* 32x32=64 */
ARMul_Icycles ( state , MultiplyAdd64 ( state , instr , LSIGNED , LSCC ) , 0L ) ;
break ;
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, no write-back, down, pre indexed */
SHPREDOWN ( ) ;
break ;
}
# endif
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 */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, no write-back, down, pre indexed */
LHPREDOWN ( ) ;
/* continue with remaining instruction decode */
}
# endif
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 (ARM6) */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, write-back, down, pre indexed */
SHPREDOWNWB ( ) ;
break ;
}
# endif
# 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 ;
}
}
# endif
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 */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, write-back, down, pre indexed */
LHPREDOWNWB ( ) ;
/* continue with remaining instruction decode */
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, no write-back, down, pre indexed */
SHPREDOWN ( ) ;
break ;
}
# endif
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 */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, no write-back, down, pre indexed */
LHPREDOWN ( ) ;
/* continue with remaining instruction decode */
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, write-back, down, pre indexed */
SHPREDOWNWB ( ) ;
break ;
}
# endif
if ( DESTReg = = 15 & & BITS ( 17 , 18 ) = = 0 ) { /* MSR */
UNDEF_MSRPC ;
ARMul_FixSPSR ( state , instr , DPRegRHS ) ;
}
else {
UNDEF_Test ;
}
break ;
case 0x17 : /* CMNP reg */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, write-back, down, pre indexed */
LHPREDOWNWB ( ) ;
/* continue with remaining instruction decoding */
}
# endif
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 */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, no write-back, up, pre indexed */
SHPREUP ( ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = LHS | rhs ;
WRITEDEST ( dest ) ;
break ;
case 0x19 : /* ORRS reg */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, no write-back, up, pre indexed */
LHPREUP ( ) ;
/* continue with remaining instruction decoding */
}
# endif
rhs = DPSRegRHS ;
dest = LHS | rhs ;
WRITESDEST ( dest ) ;
break ;
case 0x1a : /* MOV reg */
# ifdef MODET
if ( BITS ( 4 , 11 ) = = 0xB ) {
/* STRH register offset, write-back, up, pre indexed */
SHPREUPWB ( ) ;
break ;
}
# endif
dest = DPRegRHS ;
WRITEDEST ( dest ) ;
break ;
case 0x1b : /* MOVS reg */
# ifdef MODET
if ( ( BITS ( 4 , 11 ) & 0xF9 ) = = 0x9 ) {
/* LDR register offset, write-back, up, pre indexed */
LHPREUPWB ( ) ;
/* continue with remaining instruction decoding */
}
# endif
dest = DPSRegRHS ;
WRITESDEST ( dest ) ;
break ;
case 0x1c : /* BIC reg */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, no write-back, up, pre indexed */
SHPREUP ( ) ;
break ;
}
# endif
rhs = DPRegRHS ;
dest = LHS & ~ rhs ;
WRITEDEST ( dest ) ;
break ;
case 0x1d : /* BICS reg */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, no write-back, up, pre indexed */
LHPREUP ( ) ;
/* continue with instruction decoding */
}
# endif
rhs = DPSRegRHS ;
dest = LHS & ~ rhs ;
WRITESDEST ( dest ) ;
break ;
case 0x1e : /* MVN reg */
# ifdef MODET
if ( BITS ( 4 , 7 ) = = 0xB ) {
/* STRH immediate offset, write-back, up, pre indexed */
SHPREUPWB ( ) ;
break ;
}
# endif
dest = ~ DPRegRHS ;
WRITEDEST ( dest ) ;
break ;
case 0x1f : /* MVNS reg */
# ifdef MODET
if ( ( BITS ( 4 , 7 ) & 0x9 ) = = 0x9 ) {
/* LDR immediate offset, write-back, up, pre indexed */
LHPREUPWB ( ) ;
/* continue instruction decoding */
}
# endif
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 , LUNSIGNED ) )
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 , LUNSIGNED ) )
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 , LUNSIGNED ) )
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 , LUNSIGNED ) )
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 , LUNSIGNED ) ;
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 , LUNSIGNED ) )
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 , LUNSIGNED ) ;
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 , LUNSIGNED ) )
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 , LUNSIGNED ) )
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 , LUNSIGNED ) )
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 , LUNSIGNED ) )
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 , LUNSIGNED ) )
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 , LUNSIGNED ) ;
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 , LUNSIGNED ) )
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 , LUNSIGNED ) ;
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 */
1999-04-26 18:30:24 +00:00
if ( BIT ( 4 ) )
{
/* Check for the special breakpoint opcode.
This value should correspond to the value defined
as ARM_BE_BREAKPOINT in gdb / arm - tdep . c . */
if ( BITS ( 0 , 19 ) = = 0xfdefe )
{
if ( ! ARMul_OSHandleSWI ( state , SWI_Breakpoint ) )
ARMul_Abort ( state , ARMul_SWIV ) ;
}
else
ARMul_UndefInstr ( state , instr ) ;
break ;
}
1999-04-16 01:33:56 +00:00
UNDEF_LSRBaseEQOffWb ;
UNDEF_LSRBaseEQDestWb ;
UNDEF_LSRPCBaseWb ;
UNDEF_LSRPCOffWb ;
temp = LHS + LSRegRHS ;
if ( LoadByte ( state , instr , temp , LUNSIGNED ) )
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 ] + isize ) ;
# else
ARMul_MCR ( state , instr , ECC | ER15INT | EMODE |
( ( state - > Reg [ 15 ] + isize ) & 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 */
# ifdef MODET
donext :
# endif
1999-04-26 18:30:24 +00:00
# ifdef NEED_UI_LOOP_HOOK
if ( ui_loop_hook ! = NULL & & ui_loop_hook_counter - - < 0 )
{
ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL ;
ui_loop_hook ( 0 ) ;
}
# endif /* NEED_UI_LOOP_HOOK */
1999-04-16 01:33:56 +00:00
if ( state - > Emulate = = ONCE )
state - > Emulate = STOP ;
else if ( state - > Emulate ! = RUN )
break ;
1999-04-26 18:30:24 +00:00
} while ( ! stop_simulator ) ; /* do loop */
1999-04-16 01:33:56 +00:00
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 )
{
/* The ARM documentation implies (but doe snot state) that the bottom bit of the PC is never set */
# ifdef MODE32
state - > Reg [ 15 ] = src & PCBITS & ~ 0x1 ;
# else
state - > Reg [ 15 ] = ( src & R15PCBITS & ~ 0x1 ) | 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 routine evaluates the ARM7T halfword and signed transfer RHS ' s . *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ARMword GetLS7RHS ( ARMul_State * state , ARMword instr )
{
if ( BIT ( 22 ) = = 0 ) { /* register */
# ifndef MODE32
if ( RHSReg = = 15 )
return ECC | ER15INT | R15PC | EMODE ; /* Now forbidden, but ... */
# endif
return state - > Reg [ RHSReg ] ;
}
/* else immediate */
return BITS ( 0 , 3 ) | ( BITS ( 8 , 11 ) < < 4 ) ;
}
/***************************************************************************\
* 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 ) ;
}
# ifdef MODET
/***************************************************************************\
* This function does the work of loading a halfword . *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static unsigned LoadHalfWord ( ARMul_State * state , ARMword instr , ARMword address , int signextend )
{
ARMword dest ;
BUSUSEDINCPCS ;
# ifndef MODE32
if ( ADDREXCEPT ( address ) ) {
INTERNALABORT ( address ) ;
}
# endif
dest = ARMul_LoadHalfWord ( state , address ) ;
if ( state - > Aborted ) {
TAKEABORT ;
return ( state - > lateabtSig ) ;
}
UNDEF_LSRBPC ;
if ( signextend )
{
if ( dest & 1 < < ( 16 - 1 ) )
dest = ( dest & ( ( 1 < < 16 ) - 1 ) ) - ( 1 < < 16 ) ;
}
WRITEDEST ( dest ) ;
ARMul_Icycles ( state , 1 , 0L ) ;
return ( DESTReg ! = LHSReg ) ;
}
# endif /* MODET */
/***************************************************************************\
* This function does the work of loading a byte for a LDRB instruction . *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static unsigned LoadByte ( ARMul_State * state , ARMword instr , ARMword address , int signextend )
{
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 ;
if ( signextend )
{
if ( dest & 1 < < ( 8 - 1 ) )
dest = ( dest & ( ( 1 < < 8 ) - 1 ) ) - ( 1 < < 8 ) ;
}
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 ) ;
}
# ifdef MODET
/***************************************************************************\
* This function does the work of storing a byte for a STRH instruction . *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static unsigned StoreHalfWord ( ARMul_State * state , ARMword instr , ARMword address )
{ BUSUSEDINCPCN ;
# ifndef MODE32
if ( DESTReg = = 15 )
state - > Reg [ 15 ] = ECC | ER15INT | R15PC | EMODE ;
# endif
# ifdef MODE32
ARMul_StoreHalfWord ( state , address , DEST ) ;
# else
if ( VECTORACCESS ( address ) | | ADDREXCEPT ( address ) ) {
INTERNALABORT ( address ) ;
( void ) ARMul_LoadHalfWord ( state , address ) ;
}
else
ARMul_StoreHalfWord ( state , address , DEST ) ;
# endif
if ( state - > Aborted ) {
TAKEABORT ;
return ( state - > lateabtSig ) ;
}
return ( TRUE ) ;
}
# endif /* MODET */
/***************************************************************************\
* 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 ;
if ( ! TFLAG ) {
BUSUSEDINCPCN ; /* N-cycle, increment the PC and update the NextInstr state */
}
# 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 ;
}
}
/***************************************************************************\
* This function does the work of adding two 32 bit values together , and *
* calculating if a carry has occurred . *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static ARMword Add32 ( ARMword a1 , ARMword a2 , int * carry )
{
ARMword result = ( a1 + a2 ) ;
unsigned int uresult = ( unsigned int ) result ;
unsigned int ua1 = ( unsigned int ) a1 ;
/* If (result == RdLo) and (state->Reg[nRdLo] == 0),
or ( result > RdLo ) then we have no carry : */
if ( ( uresult = = ua1 ) ? ( a2 ! = 0 ) : ( uresult < ua1 ) )
* carry = 1 ;
else
* carry = 0 ;
return ( result ) ;
}
/***************************************************************************\
* This function does the work of multiplying two 32 bit values to give a *
* 64 bit result . *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static unsigned Multiply64 ( ARMul_State * state , ARMword instr , int msigned , int scc )
{
int nRdHi , nRdLo , nRs , nRm ; /* operand register numbers */
ARMword RdHi , RdLo , Rm ;
int scount ; /* cycle count */
nRdHi = BITS ( 16 , 19 ) ;
nRdLo = BITS ( 12 , 15 ) ;
nRs = BITS ( 8 , 11 ) ;
nRm = BITS ( 0 , 3 ) ;
/* Needed to calculate the cycle count: */
Rm = state - > Reg [ nRm ] ;
/* Check for illegal operand combinations first: */
if ( nRdHi ! = 15
& & nRdLo ! = 15
& & nRs ! = 15
& & nRm ! = 15
& & nRdHi ! = nRdLo
& & nRdHi ! = nRm
& & nRdLo ! = nRm )
{
ARMword lo , mid1 , mid2 , hi ; /* intermediate results */
int carry ;
ARMword Rs = state - > Reg [ nRs ] ;
int sign = 0 ;
if ( msigned )
{
/* Compute sign of result and adjust operands if necessary. */
sign = ( Rm ^ Rs ) & 0x80000000 ;
if ( ( ( signed long ) Rm ) < 0 )
Rm = - Rm ;
if ( ( ( signed long ) Rs ) < 0 )
Rs = - Rs ;
}
/* We can split the 32x32 into four 16x16 operations. This ensures
that we do not lose precision on 32 bit only hosts : */
lo = ( ( Rs & 0xFFFF ) * ( Rm & 0xFFFF ) ) ;
mid1 = ( ( Rs & 0xFFFF ) * ( ( Rm > > 16 ) & 0xFFFF ) ) ;
mid2 = ( ( ( Rs > > 16 ) & 0xFFFF ) * ( Rm & 0xFFFF ) ) ;
hi = ( ( ( Rs > > 16 ) & 0xFFFF ) * ( ( Rm > > 16 ) & 0xFFFF ) ) ;
/* We now need to add all of these results together, taking care
to propogate the carries from the additions : */
RdLo = Add32 ( lo , ( mid1 < < 16 ) , & carry ) ;
RdHi = carry ;
RdLo = Add32 ( RdLo , ( mid2 < < 16 ) , & carry ) ;
RdHi + = ( carry + ( ( mid1 > > 16 ) & 0xFFFF ) + ( ( mid2 > > 16 ) & 0xFFFF ) + hi ) ;
if ( sign )
{
/* Negate result if necessary. */
RdLo = ~ RdLo ;
RdHi = ~ RdHi ;
if ( RdLo = = 0xFFFFFFFF )
{
RdLo = 0 ;
RdHi + = 1 ;
}
else
RdLo + = 1 ;
}
state - > Reg [ nRdLo ] = RdLo ;
state - > Reg [ nRdHi ] = RdHi ;
} /* else undefined result */
else fprintf ( stderr , " MULTIPLY64 - INVALID ARGUMENTS \n " ) ;
if ( scc )
{
if ( ( RdHi = = 0 ) & & ( RdLo = = 0 ) )
ARMul_NegZero ( state , RdHi ) ; /* zero value */
else
ARMul_NegZero ( state , scc ) ; /* non-zero value */
}
/* The cycle count depends on whether the instruction is a signed or
unsigned multiply , and what bits are clear in the multiplier : */
if ( msigned & & ( Rm & ( ( unsigned ) 1 < < 31 ) ) )
Rm = ~ Rm ; /* invert the bits to make the check against zero */
if ( ( Rm & 0xFFFFFF00 ) = = 0 )
scount = 1 ;
else if ( ( Rm & 0xFFFF0000 ) = = 0 )
scount = 2 ;
else if ( ( Rm & 0xFF000000 ) = = 0 )
scount = 3 ;
else
scount = 4 ;
return 2 + scount ;
}
/***************************************************************************\
* This function does the work of multiplying two 32 bit values and adding *
* a 64 bit value to give a 64 bit result . *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static unsigned MultiplyAdd64 ( ARMul_State * state , ARMword instr , int msigned , int scc )
{
unsigned scount ;
ARMword RdLo , RdHi ;
int nRdHi , nRdLo ;
int carry = 0 ;
nRdHi = BITS ( 16 , 19 ) ;
nRdLo = BITS ( 12 , 15 ) ;
RdHi = state - > Reg [ nRdHi ] ;
RdLo = state - > Reg [ nRdLo ] ;
scount = Multiply64 ( state , instr , msigned , LDEFAULT ) ;
RdLo = Add32 ( RdLo , state - > Reg [ nRdLo ] , & carry ) ;
RdHi = ( RdHi + state - > Reg [ nRdHi ] ) + carry ;
state - > Reg [ nRdLo ] = RdLo ;
state - > Reg [ nRdHi ] = RdHi ;
if ( scc ) {
if ( ( RdHi = = 0 ) & & ( RdLo = = 0 ) )
ARMul_NegZero ( state , RdHi ) ; /* zero value */
else
ARMul_NegZero ( state , scc ) ; /* non-zero value */
}
return scount + 1 ; /* extra cycle for addition */
}