#include "arm7.h"
#include "arm7i.h"
#include "arm7thumb.h"
static const int thumbCycles[256] =
{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
#define IsNeg(i) ((i) >> 31)
#define IsPos(i) ((~(i)) >> 31)
#define N_BIT 31
#define Z_BIT 30
#define C_BIT 29
#define V_BIT 28
#define SIGN_BIT ((UINT32)(1<<31))
#define HandleThumbALUAddFlags(rd, rn, op2) \
ARM7_SetCPSR( \
((GET_CPSR &~ (ARM7_CPSR_N | ARM7_CPSR_Z | ARM7_CPSR_V | ARM7_CPSR_C)) \
| (((!THUMB_SIGN_BITS_DIFFER(rn, op2)) && THUMB_SIGN_BITS_DIFFER(rn, rd)) \
<< V_BIT) \
| (((~(rn)) < (op2)) << C_BIT) \
| HandleALUNZFlags(rd))); \
R15 += 2;
#define HandleThumbALUSubFlags(rd, rn, op2) \
ARM7_SetCPSR( \
((GET_CPSR &~ (ARM7_CPSR_N | ARM7_CPSR_Z | ARM7_CPSR_V | ARM7_CPSR_C)) \
| ((THUMB_SIGN_BITS_DIFFER(rn, op2) && THUMB_SIGN_BITS_DIFFER(rn, rd)) \
<< V_BIT) \
| (((IsNeg(rn) & IsPos(op2)) | (IsNeg(rn) & IsPos(rd)) | (IsPos(op2) & IsPos(rd))) ? ARM7_CPSR_C : 0) \
| HandleALUNZFlags(rd))); \
R15 += 2;
#define HandleALUNZFlags(rd) \
(((rd) & SIGN_BIT) | ((!(rd)) << Z_BIT))
#include "arm7memil.c"
int ARM7i_Thumb_Step()
{
UINT32 readword;
UINT32 addr, insn;
UINT32 rm, rn, rs, rd, op2, imm, rrs, rrd;
INT32 offs;
UINT32 pc = ARM7.Rx[ARM7_PC];
int cycles;
insn = arm7_read_16(pc & (~1));
cycles = (3 - thumbCycles[insn >> 8]);
switch( ( insn & THUMB_INSN_TYPE ) >> THUMB_INSN_TYPE_SHIFT )
{
case 0x0:
ARM7_SetCPSR(GET_CPSR &~ (ARM7_CPSR_N | ARM7_CPSR_Z));
if( insn & THUMB_SHIFT_R )
{
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrs = GET_REGISTER(rs);
offs = ( insn & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
if( offs != 0 )
{
SET_REGISTER( rd, rrs >> offs );
if( rrs & ( 1 << (offs-1) ) )
{
ARM7_SetCPSR(GET_CPSR | ARM7_CPSR_C);
}
else
{
ARM7_SetCPSR(GET_CPSR &~ ARM7_CPSR_C);
}
}
else
{
SET_REGISTER( rd, 0 );
if( rrs & 0x80000000 )
{
ARM7_SetCPSR( GET_CPSR | ARM7_CPSR_C );
}
else
{
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
}
ARM7_SetCPSR(GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
}
else
{
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrs = GET_REGISTER(rs);
offs = ( insn & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
if( offs != 0 )
{
SET_REGISTER( rd, rrs << offs );
if( rrs & ( 1 << ( 31 - ( offs - 1 ) ) ) )
{
ARM7_SetCPSR(GET_CPSR | ARM7_CPSR_C);
}
else
{
ARM7_SetCPSR(GET_CPSR &~ ARM7_CPSR_C);
}
}
else
{
SET_REGISTER( rd, rrs );
}
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
}
break;
case 0x1:
if( insn & THUMB_INSN_ADDSUB )
{
switch( ( insn & THUMB_ADDSUB_TYPE ) >> THUMB_ADDSUB_TYPE_SHIFT )
{
case 0x0:
rn = GET_REGISTER( ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT );
rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, rs + rn );
HandleThumbALUAddFlags( GET_REGISTER(rd), rs, rn );
break;
case 0x1:
rn = GET_REGISTER( ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT );
rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, rs - rn );
HandleThumbALUSubFlags( GET_REGISTER(rd), rs, rn );
break;
case 0x2:
imm = ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, rs + imm );
HandleThumbALUAddFlags( GET_REGISTER(rd), rs, imm );
break;
case 0x3:
imm = ( insn & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT;
rs = GET_REGISTER( ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT );
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, rs - imm );
HandleThumbALUSubFlags( GET_REGISTER(rd), rs,imm );
break;
default:
printf("%08x: G1 Undefined Thumb instruction: %04x\n", pc, insn);
R15 += 2;
break;
}
}
else
{
{
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrs = GET_REGISTER(rs);
offs = ( insn & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT;
if( offs == 0 )
{
offs = 32;
}
if( offs >= 32 )
{
if( rrs >> 31 )
{
ARM7_SetCPSR(GET_CPSR | ARM7_CPSR_C);
}
else
{
ARM7_SetCPSR(GET_CPSR &~ ARM7_CPSR_C);
}
SET_REGISTER( rd, ( rrs & 0x80000000 ) ? 0xFFFFFFFF : 0x00000000 );
}
else
{
if( ( rrs >> ( offs - 1 ) ) & 1 )
{
ARM7_SetCPSR( GET_CPSR | ARM7_CPSR_C );
}
else
{
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
SET_REGISTER( rd, ( rrs & 0x80000000 ) ? ( ( 0xFFFFFFFF << ( 32 - offs ) ) | ( rrs >> offs ) ) : ( rrs >> offs ) );
}
ARM7_SetCPSR(GET_CPSR &~ (ARM7_CPSR_N | ARM7_CPSR_Z));
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
}
}
break;
case 0x2:
if( insn & THUMB_INSN_CMP )
{
rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
op2 = ( insn & THUMB_INSN_IMM );
rd = rn - op2;
HandleThumbALUSubFlags( rd, rn, op2 );
}
else
{
rd = ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
op2 = ( insn & THUMB_INSN_IMM );
SET_REGISTER( rd, op2 );
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
}
break;
case 0x3:
if( insn & THUMB_INSN_SUB )
{
rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
op2 = ( insn & THUMB_INSN_IMM );
rd = rn - op2;
SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, rd );
HandleThumbALUSubFlags( rd, rn, op2 );
}
else
{
rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
op2 = insn & THUMB_INSN_IMM;
rd = rn + op2;
SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, rd );
HandleThumbALUAddFlags( rd, rn, op2 );
}
break;
case 0x4:
switch( ( insn & THUMB_GROUP4_TYPE ) >> THUMB_GROUP4_TYPE_SHIFT )
{
case 0x0:
switch( ( insn & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT )
{
case 0x0:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, GET_REGISTER(rd) & GET_REGISTER(rs) );
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
case 0x1:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, GET_REGISTER(rd) ^ GET_REGISTER(rs) );
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
case 0x2:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrd = GET_REGISTER(rd);
offs = GET_REGISTER(rs) & 0x000000ff;
if (offs > 0)
{
if ( offs < 32 )
{
SET_REGISTER( rd, rrd << offs );
if( rrd & ( 1 << ( 31 - ( offs - 1 ) ) ) )
{
ARM7_SetCPSR( GET_CPSR | ARM7_CPSR_C );
}
else
{
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
}
else if( offs == 32 )
{
SET_REGISTER( rd, 0 );
if( rrd & 1 )
{
ARM7_SetCPSR( GET_CPSR | ARM7_CPSR_C );
}
else
{
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
}
else
{
SET_REGISTER( rd, 0 );
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
}
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
case 0x3:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrd = GET_REGISTER(rd);
offs = GET_REGISTER(rs) & 0x000000ff;
if (offs > 0)
{
if( offs < 32 )
{
SET_REGISTER( rd, rrd >> offs );
if( rrd & ( 1 << ( offs - 1 ) ) )
{
ARM7_SetCPSR( GET_CPSR | ARM7_CPSR_C );
}
else
{
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
}
else if( offs == 32 )
{
SET_REGISTER( rd, 0 );
if( rrd & 0x80000000 )
{
ARM7_SetCPSR( GET_CPSR | ARM7_CPSR_C );
}
else
{
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
}
else
{
SET_REGISTER( rd, 0 );
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
}
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
case 0x4:
{
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrs = GET_REGISTER(rs)&0xff;
rrd = GET_REGISTER(rd);
if (rrs != 0)
{
if (rrs >= 32)
{
if (rrd>>31)
{
ARM7_SetCPSR(GET_CPSR | ARM7_CPSR_C);
}
else
{
ARM7_SetCPSR(GET_CPSR &~ ARM7_CPSR_C);
}
SET_REGISTER( rd, (GET_REGISTER(rd) & 0x80000000) ? 0xFFFFFFFF : 0x00000000 );
}
else
{
if ((rrd>>(rs-1))&1)
{
ARM7_SetCPSR(GET_CPSR | ARM7_CPSR_C);
}
else
{
ARM7_SetCPSR(GET_CPSR &~ ARM7_CPSR_C);
}
SET_REGISTER( rd, (rrd & 0x80000000) ? ((0xFFFFFFFF<<(32-rrs)) | (rrd>>rrs)) : (rrd>>rrs));
}
}
ARM7_SetCPSR(GET_CPSR &~ (ARM7_CPSR_N | ARM7_CPSR_Z));
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
}
break;
case 0x5:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
op2=(GET_CPSR & ARM7_CPSR_C) ? 1 : 0;
rn=GET_REGISTER(rd) + GET_REGISTER(rs) + op2;
HandleThumbALUAddFlags( rn, GET_REGISTER(rd), ( GET_REGISTER(rs) ) ); SET_REGISTER( rd, rn);
break;
case 0x6:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
op2=(GET_CPSR & ARM7_CPSR_C) ? 0 : 1;
rn=GET_REGISTER(rd) - GET_REGISTER(rs) - op2;
HandleThumbALUSubFlags( rn, GET_REGISTER(rd), ( GET_REGISTER(rs) ) ); SET_REGISTER( rd, rn);
break;
case 0x7:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrd = GET_REGISTER(rd);
imm = GET_REGISTER(rs) & 0x0000001f;
SET_REGISTER( rd, ( rrd >> imm ) | ( rrd << ( 32 - imm ) ) );
if( rrd & ( 1 << ( imm - 1 ) ) )
{
ARM7_SetCPSR( GET_CPSR | ARM7_CPSR_C );
}
else
{
ARM7_SetCPSR( GET_CPSR &~ ARM7_CPSR_C );
}
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
case 0x8:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) & GET_REGISTER(rs) ) );
R15 += 2;
break;
case 0x9:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rrs = GET_REGISTER(rs);
rn = 0 - rrs;
SET_REGISTER( rd, rn );
HandleThumbALUSubFlags( GET_REGISTER(rd), 0, rrs );
break;
case 0xa:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rn = GET_REGISTER(rd) - GET_REGISTER(rs);
HandleThumbALUSubFlags( rn, GET_REGISTER(rd), GET_REGISTER(rs) );
break;
case 0xb:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rn = GET_REGISTER(rd) + GET_REGISTER(rs);
HandleThumbALUAddFlags( rn, GET_REGISTER(rd), GET_REGISTER(rs) );
break;
case 0xc:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, GET_REGISTER(rd) | GET_REGISTER(rs) );
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
case 0xd:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
rn = GET_REGISTER(rd) * GET_REGISTER(rs);
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
SET_REGISTER( rd, rn );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( rn ) );
R15 += 2;
break;
case 0xe:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, GET_REGISTER(rd) & (~GET_REGISTER(rs)) );
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
case 0xf:
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
op2 = GET_REGISTER(rs);
SET_REGISTER( rd, ~op2 );
ARM7_SetCPSR( GET_CPSR &~ ( ARM7_CPSR_Z | ARM7_CPSR_N ) );
ARM7_SetCPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
R15 += 2;
break;
default:
printf("%08x: G4-0 Undefined Thumb instruction: %04x %x\n", pc, insn, ( insn & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT);
R15 += 2;
break;
}
break;
case 0x1:
switch( ( insn & THUMB_HIREG_OP ) >> THUMB_HIREG_OP_SHIFT )
{
case 0x0:
rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
rd = insn & THUMB_HIREG_RD;
switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
{
case 0x1:
SET_REGISTER( rd, GET_REGISTER(rd) + GET_REGISTER(rs+8) );
if (rs == 7)
{
SET_REGISTER(rd, GET_REGISTER(rd) + 4);
}
break;
case 0x2:
SET_REGISTER( rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs) );
if (rd == 7)
{
R15 += 2;
change_pc(R15);
}
break;
case 0x3:
SET_REGISTER( rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs+8) );
if (rs == 7)
{
SET_REGISTER(rd+8, GET_REGISTER(rd+8) + 4);
}
if (rd == 7)
{
R15 += 2;
change_pc(R15);
}
break;
default:
printf("%08x: G4-1-0 Undefined Thumb instruction: %04x %x\n", pc, insn, ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT );
break;
}
R15 += 2;
break;
case 0x1:
switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
{
case 0x0:
rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) );
rd = GET_REGISTER( insn & THUMB_HIREG_RD );
rn = rd - rs;
HandleThumbALUSubFlags( rn, rd, rs );
break;
case 0x1:
rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 );
rd = GET_REGISTER( insn & THUMB_HIREG_RD );
rn = rd - rs;
HandleThumbALUSubFlags( rn, rd, rs );
break;
case 0x2:
rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) );
rd = GET_REGISTER( (insn & THUMB_HIREG_RD) + 8 );
rn = rd - rs;
HandleThumbALUSubFlags( rn, rd, rs );
break;
case 0x3:
rs = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 );
rd = GET_REGISTER( (insn & THUMB_HIREG_RD) + 8 );
rn = rd - rs;
HandleThumbALUSubFlags( rn, rd, rs );
break;
default:
printf("%08x: G4-1 Undefined Thumb instruction: %04x %x\n", pc, insn, ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT);
R15 += 2;
break;
}
break;
case 0x2:
switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
{
case 0x1: rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
rd = insn & THUMB_HIREG_RD;
if( rs == 7 )
{
SET_REGISTER( rd, GET_REGISTER(rs + 8) + 4 );
}
else
{
SET_REGISTER( rd, GET_REGISTER(rs + 8) );
}
R15 += 2;
break;
case 0x2: rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
rd = insn & THUMB_HIREG_RD;
SET_REGISTER( rd + 8, GET_REGISTER(rs) );
if( rd != 7 )
{
R15 += 2;
}
else
{
R15 &= ~1;
change_pc(R15);
}
break;
case 0x3: rs = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
rd = insn & THUMB_HIREG_RD;
if (rs == 7)
{
SET_REGISTER( rd + 8, GET_REGISTER(rs+8)+4 );
}
else
{
SET_REGISTER( rd + 8, GET_REGISTER(rs+8) );
}
if( rd != 7 )
{
R15 += 2;
}
if( rd == 7 )
{
R15 &= ~1;
change_pc(R15);
}
break;
default:
printf("%08x: G4-2 Undefined Thumb instruction: %04x (%x)\n", pc, insn, ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT);
R15 += 2;
break;
}
break;
case 0x3:
switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
{
case 0x0:
rd = ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT;
addr = GET_REGISTER(rd);
if( addr & 1 )
{
addr &= ~1;
}
else
{
ARM7_SetCPSR(GET_CPSR &~ ARM7_CPSR_T);
if( addr & 2 )
{
addr += 2;
}
}
R15 = addr;
break;
case 0x1:
addr = GET_REGISTER( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 );
if( ( ( ( insn & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8 ) == 15 )
{
addr += 2;
}
if( addr & 1 )
{
addr &= ~1;
}
else
{
ARM7_SetCPSR(GET_CPSR &~ ARM7_CPSR_T);
if( addr & 2 )
{
addr += 2;
}
}
R15 = addr;
break;
default:
printf("%08x: G4-3 Undefined Thumb instruction: %04x\n", pc, insn);
R15 += 2;
break;
}
break;
default:
printf("%08x: G4-x Undefined Thumb instruction: %04x\n", pc, insn);
R15 += 2;
break;
}
break;
case 0x2:
case 0x3:
readword = arm7_read_32( ( R15 & ~2 ) + 4 + ( ( insn & THUMB_INSN_IMM ) << 2 ) );
SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, readword );
R15 += 2;
break;
default:
printf("%08x: G4-y Undefined Thumb instruction: %04x\n", pc, insn);
R15 += 2;
break;
}
break;
case 0x5:
switch( ( insn & THUMB_GROUP5_TYPE ) >> THUMB_GROUP5_TYPE_SHIFT )
{
case 0x0:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
arm7_write_32( addr, GET_REGISTER(rd) );
R15 += 2;
break;
case 0x1:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
arm7_write_16( addr, GET_REGISTER(rd) );
R15 += 2;
break;
case 0x2:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
arm7_write_8( addr, GET_REGISTER(rd) );
R15 += 2;
break;
case 0x3:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
op2 = arm7_read_8( addr );
if( op2 & 0x00000080 )
{
op2 |= 0xffffff00;
}
SET_REGISTER( rd, op2 );
R15 += 2;
break;
case 0x4:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
op2 = arm7_read_32( addr );
SET_REGISTER( rd, op2 );
R15 += 2;
break;
case 0x5:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
op2 = arm7_read_16( addr );
SET_REGISTER( rd, op2 );
R15 += 2;
break;
case 0x6:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
op2 = arm7_read_8( addr );
SET_REGISTER( rd, op2 );
R15 += 2;
break;
case 0x7:
rm = ( insn & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT;
rn = ( insn & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT;
rd = ( insn & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT;
addr = GET_REGISTER(rn) + GET_REGISTER(rm);
op2 = arm7_read_16( addr );
if( op2 & 0x00008000 )
{
op2 |= 0xffff0000;
}
SET_REGISTER( rd, op2 );
R15 += 2;
break;
default:
printf("%08x: G5 Undefined Thumb instruction: %04x\n", pc, insn);
R15 += 2;
break;
}
break;
case 0x6:
if( insn & THUMB_LSOP_L )
{
rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = insn & THUMB_ADDSUB_RD;
offs = ( ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2;
SET_REGISTER( rd, arm7_read_32(GET_REGISTER(rn) + offs) ); R15 += 2;
}
else
{
rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = insn & THUMB_ADDSUB_RD;
offs = ( ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2;
arm7_write_32( GET_REGISTER(rn) + offs, GET_REGISTER(rd) );
R15 += 2;
}
break;
case 0x7:
if( insn & THUMB_LSOP_L )
{
rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = insn & THUMB_ADDSUB_RD;
offs = ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT;
SET_REGISTER( rd, arm7_read_8( GET_REGISTER(rn) + offs ) );
R15 += 2;
}
else
{
rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = insn & THUMB_ADDSUB_RD;
offs = ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT;
arm7_write_8( GET_REGISTER(rn) + offs, GET_REGISTER(rd) );
R15 += 2;
}
break;
case 0x8:
if( insn & THUMB_HALFOP_L )
{
imm = ( insn & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT;
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
SET_REGISTER( rd, arm7_read_16( GET_REGISTER(rs) + ( imm << 1 ) ) );
R15 += 2;
}
else
{
imm = ( insn & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT;
rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
arm7_write_16( GET_REGISTER(rs) + ( imm << 1 ), GET_REGISTER(rd) );
R15 += 2;
}
break;
case 0x9:
if( insn & THUMB_STACKOP_L )
{
rd = ( insn & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT;
offs = (UINT8)( insn & THUMB_INSN_IMM );
readword = arm7_read_32( GET_REGISTER(13) + ( (UINT32)offs << 2 ) );
SET_REGISTER( rd, readword );
R15 += 2;
}
else
{
rd = ( insn & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT;
offs = (UINT8)( insn & THUMB_INSN_IMM );
arm7_write_32( GET_REGISTER(13) + ( (UINT32)offs << 2 ), GET_REGISTER(rd) );
R15 += 2;
}
break;
case 0xa:
if( insn & THUMB_RELADDR_SP )
{
rd = ( insn & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT;
offs = (UINT8)( insn & THUMB_INSN_IMM ) << 2;
SET_REGISTER( rd, GET_REGISTER(13) + offs );
R15 += 2;
}
else
{
rd = ( insn & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT;
offs = (UINT8)( insn & THUMB_INSN_IMM ) << 2;
SET_REGISTER( rd, ( ( R15 + 4 ) & ~2 ) + offs );
R15 += 2;
}
break;
case 0xb:
switch( ( insn & THUMB_STACKOP_TYPE ) >> THUMB_STACKOP_TYPE_SHIFT )
{
case 0x0:
addr = ( insn & THUMB_INSN_IMM );
addr &= ~THUMB_INSN_IMM_S;
SET_REGISTER( 13, GET_REGISTER(13) + ( ( insn & THUMB_INSN_IMM_S ) ? -( addr << 2 ) : ( addr << 2 ) ) );
R15 += 2;
break;
case 0x4:
for( offs = 7; offs >= 0; offs-- )
{
if( insn & ( 1 << offs ) )
{
SET_REGISTER( 13, GET_REGISTER(13) - 4 );
arm7_write_32( GET_REGISTER(13), GET_REGISTER(offs) );
}
}
R15 += 2;
break;
case 0x5:
SET_REGISTER( 13, GET_REGISTER(13) - 4 );
arm7_write_32( GET_REGISTER(13), GET_REGISTER(14) );
for( offs = 7; offs >= 0; offs-- )
{
if( insn & ( 1 << offs ) )
{
SET_REGISTER( 13, GET_REGISTER(13) - 4 );
arm7_write_32( GET_REGISTER(13), GET_REGISTER(offs) );
}
}
R15 += 2;
break;
case 0xc:
for( offs = 0; offs < 8; offs++ )
{
if( insn & ( 1 << offs ) )
{
SET_REGISTER( offs, arm7_read_32( GET_REGISTER(13) ) );
SET_REGISTER( 13, GET_REGISTER(13) + 4 );
}
}
R15 += 2;
break;
case 0xd:
for( offs = 0; offs < 8; offs++ )
{
if( insn & ( 1 << offs ) )
{
SET_REGISTER( offs, arm7_read_32( GET_REGISTER(13) ) );
SET_REGISTER( 13, GET_REGISTER(13) + 4 );
}
}
R15 = arm7_read_32( GET_REGISTER(13) ) & ~1;
SET_REGISTER( 13, GET_REGISTER(13) + 4 );
break;
default:
printf("%08x: Gb Undefined Thumb instruction: %04x\n", pc, insn);
R15 += 2;
break;
}
break;
case 0xc:
if( insn & THUMB_MULTLS )
{
rd = ( insn & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
for( offs = 0; offs < 8; offs++ )
{
if( insn & ( 1 << offs ) )
{
SET_REGISTER( offs, arm7_read_32( (GET_REGISTER(rd)&0xfffffffc) ) );
SET_REGISTER( rd, GET_REGISTER(rd) + 4 );
}
}
R15 += 2;
}
else
{
rd = ( insn & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
for( offs = 0; offs < 8; offs++ )
{
if( insn & ( 1 << offs ) )
{
arm7_write_32( (GET_REGISTER(rd)&0xfffffffc), GET_REGISTER(offs) );
SET_REGISTER( rd, GET_REGISTER(rd) + 4 );
}
}
R15 += 2;
}
break;
case 0xd:
offs = (INT8)( insn & THUMB_INSN_IMM );
switch( ( insn & THUMB_COND_TYPE ) >> THUMB_COND_TYPE_SHIFT )
{
case COND_EQ:
if( Z_IS_SET(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_NE:
if( Z_IS_CLEAR(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_CS:
if( C_IS_SET(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_CC:
if( C_IS_CLEAR(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_MI:
if( N_IS_SET(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_PL:
if( N_IS_CLEAR(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_VS:
if( V_IS_SET(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_VC:
if( V_IS_CLEAR(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_HI:
if( C_IS_SET(GET_CPSR) && Z_IS_CLEAR(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_LS:
if( C_IS_CLEAR(GET_CPSR) || Z_IS_SET(GET_CPSR) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_GE:
if( !(GET_CPSR & ARM7_CPSR_N) == !(GET_CPSR & ARM7_CPSR_V) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_LT:
if( !(GET_CPSR & ARM7_CPSR_N) != !(GET_CPSR & ARM7_CPSR_V) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_GT:
if( Z_IS_CLEAR(GET_CPSR) && ( !(GET_CPSR & ARM7_CPSR_N) == !(GET_CPSR & ARM7_CPSR_V) ) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_LE:
if( Z_IS_SET(GET_CPSR) || ( !(GET_CPSR & ARM7_CPSR_N) != !(GET_CPSR & ARM7_CPSR_V) ) )
{
R15 += 4 + (offs << 1);
}
else
{
R15 += 2;
}
break;
case COND_AL:
printf("%08x: Undefined Thumb instruction: %04x (ARM9 reserved)\n", pc, insn);
R15 += 2;
break;
case COND_NV: ARM7_SetSWI();
break;
}
break;
case 0xe:
if( insn & THUMB_BLOP_LO )
{
addr = GET_REGISTER(14);
addr += ( insn & THUMB_BLOP_OFFS ) << 1;
addr &= 0xfffffffc;
SET_REGISTER( 14, ( R15 + 4 ) | 1 );
R15 = addr;
}
else
{
offs = ( insn & THUMB_BRANCH_OFFS ) << 1;
if( offs & 0x00000800 )
{
offs |= 0xfffff800;
}
R15 += 4 + offs;
}
break;
case 0xf:
if( insn & THUMB_BLOP_LO )
{
addr = GET_REGISTER(14);
addr += ( insn & THUMB_BLOP_OFFS ) << 1;
SET_REGISTER( 14, ( R15 + 2 ) | 1 );
R15 = addr;
}
else
{
addr = ( insn & THUMB_BLOP_OFFS ) << 12;
if( addr & ( 1 << 22 ) )
{
addr |= 0xff800000;
}
addr += R15 + 4;
SET_REGISTER( 14, addr );
R15 += 2;
}
break;
default:
printf("%08x: Undefined Thumb instruction: %04x\n", pc, insn);
R15 += 2;
break;
}
return cycles;
}