summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/arm7/arm7exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/arm7/arm7exec.c')
-rw-r--r--src/emu/cpu/arm7/arm7exec.c1334
1 files changed, 1334 insertions, 0 deletions
diff --git a/src/emu/cpu/arm7/arm7exec.c b/src/emu/cpu/arm7/arm7exec.c
new file mode 100644
index 00000000000..9b9facf182c
--- /dev/null
+++ b/src/emu/cpu/arm7/arm7exec.c
@@ -0,0 +1,1334 @@
+/*****************************************************************************
+ *
+ * arm7exec.c
+ * Portable ARM7TDMI Core Emulator
+ *
+ * Copyright (c) 2004 Steve Ellenoff, all rights reserved.
+ *
+ * - This source code is released as freeware for non-commercial purposes.
+ * - You are free to use and redistribute this code in modified or
+ * unmodified form, provided you list me in the credits.
+ * - If you modify this source code, you must add a notice to each modified
+ * source file that it has been changed. If you're a nice person, you
+ * will clearly mark each change too. :)
+ * - If you wish to use this for commercial purposes, please contact me at
+ * sellenoff@hotmail.com
+ * - The author of this copywritten work reserves the right to change the
+ * terms of its usage and license at any time, including retroactively
+ * - This entire notice must remain in the source code.
+ *
+ * This work is based on:
+ * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999'
+ * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76)
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * Notes:
+ * This file contains the code to run during the CPU EXECUTE METHOD.
+ * It has been split into it's own file (from the arm7core.c) so it can be
+ * directly compiled into any cpu core that wishes to use it.
+ *
+ * It should be included as follows in your cpu core:
+ *
+ * int arm7_execute( int cycles )
+ * {
+ * #include "arm7exec.c"
+ * }
+ *
+*****************************************************************************/
+
+/* This implementation uses an improved switch() for hopefully faster opcode fetches compared to my last version
+.. though there's still room for improvement. */
+{
+ UINT32 pc;
+ UINT32 insn;
+
+ ARM7_ICOUNT = cycles;
+ do
+ {
+ CALL_MAME_DEBUG;
+
+ /* handle Thumb instructions if active */
+ if( T_IS_SET(GET_CPSR) )
+ {
+ UINT32 readword;
+ UINT32 addr;
+ UINT32 rm, rn, rs, rd, op2, imm, rrs, rrd;
+ INT32 offs;
+ pc = R15;
+
+ insn = cpu_readop16(pc & (~1));
+ ARM7_ICOUNT -= (3 - thumbCycles[insn >> 8]);
+ switch( ( insn & THUMB_INSN_TYPE ) >> THUMB_INSN_TYPE_SHIFT )
+ {
+ case 0x0: /* Logical shifting */
+ SET_CPSR(GET_CPSR &~ (N_MASK | Z_MASK));
+ if( insn & THUMB_SHIFT_R ) /* Shift right */
+ {
+ 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) ) )
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, 0 );
+ if( rrs & 0x80000000 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ SET_CPSR(GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ else /* Shift left */
+ {
+ 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 ) ) ) )
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, rrs );
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ break;
+ case 0x1: /* Arithmetic */
+ if( insn & THUMB_INSN_ADDSUB )
+ {
+ switch( ( insn & THUMB_ADDSUB_TYPE ) >> THUMB_ADDSUB_TYPE_SHIFT )
+ {
+ case 0x0: /* ADD Rd, Rs, Rn */
+ 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: /* SUB Rd, Rs, Rn */
+ 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: /* ADD Rd, Rs, #imm */
+ 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: /* SUB Rd, Rs, #imm */
+ 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:
+ fatalerror("%08x: G1 Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ }
+ else
+ {
+ /* ASR.. */
+ //if( insn & THUMB_SHIFT_R ) /* Shift right */
+ {
+ 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 )
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ SET_REGISTER( rd, ( rrs & 0x80000000 ) ? 0xFFFFFFFF : 0x00000000 );
+ }
+ else
+ {
+ if( ( rrs >> ( offs - 1 ) ) & 1 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ SET_REGISTER( rd, ( rrs & 0x80000000 ) ? ( ( 0xFFFFFFFF << ( 32 - offs ) ) | ( rrs >> offs ) ) : ( rrs >> offs ) );
+ }
+ SET_CPSR(GET_CPSR &~ (N_MASK | Z_MASK));
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+
+ }
+ break;
+ case 0x2: /* CMP / MOV */
+ 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 );
+ //mame_printf_debug("%08x: xxx Thumb instruction: CMP R%d (%08x), %02x (N=%d, Z=%d, C=%d, V=%d)\n", pc, ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT ), op2, N_IS_SET(GET_CPSR) ? 1 : 0, Z_IS_SET(GET_CPSR) ? 1 : 0, C_IS_SET(GET_CPSR) ? 1 : 0, V_IS_SET(GET_CPSR) ? 1 : 0);
+ }
+ else
+ {
+ rd = ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT;
+ op2 = ( insn & THUMB_INSN_IMM );
+ SET_REGISTER( rd, op2 );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ break;
+ case 0x3: /* ADD/SUB immediate */
+ if( insn & THUMB_INSN_SUB ) /* SUB Rd, #Offset8 */
+ {
+ rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
+ op2 = ( insn & THUMB_INSN_IMM );
+ //mame_printf_debug("%08x: Thumb instruction: SUB R%d, %02x\n", pc, ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, op2);
+ rd = rn - op2;
+ SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, rd );
+ HandleThumbALUSubFlags( rd, rn, op2 );
+ }
+ else /* ADD Rd, #Offset8 */
+ {
+ rn = GET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT );
+ op2 = insn & THUMB_INSN_IMM;
+ rd = rn + op2;
+ //mame_printf_debug("%08x: Thumb instruction: ADD R%d, %02x\n", pc, ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, op2);
+ SET_REGISTER( ( insn & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT, rd );
+ HandleThumbALUAddFlags( rd, rn, op2 );
+ }
+ break;
+ case 0x4: /* Rd & Rm instructions */
+ switch( ( insn & THUMB_GROUP4_TYPE ) >> THUMB_GROUP4_TYPE_SHIFT )
+ {
+ case 0x0:
+ switch( ( insn & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT )
+ {
+ case 0x0: /* AND Rd, Rs */
+ 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) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x1: /* EOR Rd, Rs */
+ 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) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x2: /* LSL Rd, Rs */
+ 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 ) ) ) )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else if( offs == 32 )
+ {
+ SET_REGISTER( rd, 0 );
+ if( rrd & 1 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, 0 );
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x3: /* LSR Rd, Rs */
+ 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 ) ) )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else if( offs == 32 )
+ {
+ SET_REGISTER( rd, 0 );
+ if( rrd & 0x80000000 )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ else
+ {
+ SET_REGISTER( rd, 0 );
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x4: /* ASR Rd, Rs */
+ {
+ 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)
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ SET_REGISTER( rd, (GET_REGISTER(rd) & 0x80000000) ? 0xFFFFFFFF : 0x00000000 );
+ }
+ else
+ {
+ if ((rrd>>(rs-1))&1)
+ {
+ SET_CPSR(GET_CPSR | C_MASK);
+ }
+ else
+ {
+ SET_CPSR(GET_CPSR &~ C_MASK);
+ }
+ SET_REGISTER( rd, (rrd & 0x80000000) ? ((0xFFFFFFFF<<(32-rrs)) | (rrd>>rrs)) : (rrd>>rrs));
+ }
+ }
+ SET_CPSR(GET_CPSR &~ (N_MASK | Z_MASK));
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ }
+ break;
+ case 0x5: /* ADC Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ op2=(GET_CPSR & C_MASK) ? 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: /* SBC Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ op2=(GET_CPSR & C_MASK) ? 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: /* ROR Rd, Rs */
+ 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 ) ) )
+ {
+ SET_CPSR( GET_CPSR | C_MASK );
+ }
+ else
+ {
+ SET_CPSR( GET_CPSR &~ C_MASK );
+ }
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0x8: /* TST Rd, Rs */
+ rs = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = ( insn & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT;
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) & GET_REGISTER(rs) ) );
+ R15 += 2;
+ break;
+ case 0x9: /* NEG Rd, Rs - todo: check me */
+ 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: /* CMP Rd, Rs */
+ 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: /* CMN Rd, Rs - check flags, add dasm */
+ 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: /* ORR Rd, Rs */
+ 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) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0xd: /* MUL Rd, Rs */
+ 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);
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_REGISTER( rd, rn );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( rn ) );
+ R15 += 2;
+ break;
+ case 0xe: /* BIC Rd, Rs */
+ 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)) );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ case 0xf: /* MVN Rd, Rs */
+ 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 );
+ SET_CPSR( GET_CPSR &~ ( Z_MASK | N_MASK ) );
+ SET_CPSR( GET_CPSR | HandleALUNZFlags( GET_REGISTER(rd) ) );
+ R15 += 2;
+ break;
+ default:
+ fatalerror("%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: /* ADD Rd, Rs */
+ 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: /* ADD Rd, HRs */
+ SET_REGISTER( rd, GET_REGISTER(rd) + GET_REGISTER(rs+8) );
+ // emulate the effects of pre-fetch
+ if (rs == 7)
+ {
+ SET_REGISTER(rd, GET_REGISTER(rd) + 4);
+ }
+ break;
+ case 0x2: /* ADD HRd, Rs */
+ SET_REGISTER( rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs) );
+ if (rd == 7)
+ {
+ R15 += 2;
+ change_pc(R15);
+ }
+ break;
+ case 0x3: /* Add HRd, HRs */
+ SET_REGISTER( rd+8, GET_REGISTER(rd+8) + GET_REGISTER(rs+8) );
+ // emulate the effects of pre-fetch
+ if (rs == 7)
+ {
+ SET_REGISTER(rd+8, GET_REGISTER(rd+8) + 4);
+ }
+ if (rd == 7)
+ {
+ R15 += 2;
+ change_pc(R15);
+ }
+ break;
+ default:
+ fatalerror("%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: /* CMP */
+ switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x0: /* CMP Rd, Rs */
+ 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: /* CMP Rd, Hs */
+ 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: /* CMP Hd, Rs */
+ 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: /* CMP Hd, Hs */
+ 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:
+ fatalerror("%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: /* MOV */
+ switch( ( insn & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT )
+ {
+ case 0x1: // MOV Rd, Hs
+ 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: // MOV Hd, Rs
+ 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: // MOV Hd, Hs
+ 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:
+ fatalerror("%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
+ {
+ SET_CPSR(GET_CPSR &~ T_MASK);
+ 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
+ {
+ SET_CPSR(GET_CPSR &~ T_MASK);
+ if( addr & 2 )
+ {
+ addr += 2;
+ }
+ }
+ R15 = addr;
+ break;
+ default:
+ fatalerror("%08x: G4-3 Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ default:
+ fatalerror("%08x: G4-x Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x2:
+ case 0x3:
+ readword = READ32( ( 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:
+ fatalerror("%08x: G4-y Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x5: /* LDR* STR* */
+ switch( ( insn & THUMB_GROUP5_TYPE ) >> THUMB_GROUP5_TYPE_SHIFT )
+ {
+ case 0x0: /* STR Rd, [Rn, Rm] */
+ 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);
+ WRITE32( addr, GET_REGISTER(rd) );
+ R15 += 2;
+ break;
+ case 0x1: /* STRH Rd, [Rn, Rm] */
+ 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);
+ WRITE16( addr, GET_REGISTER(rd) );
+ R15 += 2;
+ break;
+ case 0x2: /* STRB Rd, [Rn, Rm] */
+ 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);
+ WRITE8( addr, GET_REGISTER(rd) );
+ R15 += 2;
+ break;
+ case 0x3: /* LDSB Rd, [Rn, Rm] todo, add dasm */
+ 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 = READ8( addr );
+ if( op2 & 0x00000080 )
+ {
+ op2 |= 0xffffff00;
+ }
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ case 0x4: /* LDR Rd, [Rn, Rm] */
+ 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 = READ32( addr );
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ case 0x5: /* LDRH Rd, [Rn, Rm] */
+ 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 = READ16( addr );
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+
+ case 0x6: /* LDRB Rd, [Rn, Rm] */
+ 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 = READ8( addr );
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ case 0x7: /* LDSH Rd, [Rn, Rm] */
+ 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 = READ16( addr );
+ if( op2 & 0x00008000 )
+ {
+ op2 |= 0xffff0000;
+ }
+ SET_REGISTER( rd, op2 );
+ R15 += 2;
+ break;
+ default:
+ fatalerror("%08x: G5 Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0x6: /* Word Store w/ Immediate Offset */
+ if( insn & THUMB_LSOP_L ) /* Load */
+ {
+ 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, READ32(GET_REGISTER(rn) + offs) ); // fix
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = insn & THUMB_ADDSUB_RD;
+ offs = ( ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2;
+ WRITE32( GET_REGISTER(rn) + offs, GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0x7: /* Byte Store w/ Immeidate Offset */
+ if( insn & THUMB_LSOP_L ) /* Load */
+ {
+ 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, READ8( GET_REGISTER(rn) + offs ) );
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ rn = ( insn & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT;
+ rd = insn & THUMB_ADDSUB_RD;
+ offs = ( insn & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT;
+ WRITE8( GET_REGISTER(rn) + offs, GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0x8: /* Load/Store Halfword */
+ if( insn & THUMB_HALFOP_L ) /* Load */
+ {
+ 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, READ16( GET_REGISTER(rs) + ( imm << 1 ) ) );
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ 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;
+ WRITE16( GET_REGISTER(rs) + ( imm << 1 ), GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0x9: /* Stack-Relative Load/Store */
+ if( insn & THUMB_STACKOP_L )
+ {
+ rd = ( insn & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT;
+ offs = (UINT8)( insn & THUMB_INSN_IMM );
+ readword = READ32( 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 );
+ WRITE32( GET_REGISTER(13) + ( (UINT32)offs << 2 ), GET_REGISTER(rd) );
+ R15 += 2;
+ }
+ break;
+ case 0xa: /* Get relative address */
+ if( insn & THUMB_RELADDR_SP ) /* ADD Rd, SP, #nn */
+ {
+ 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 /* ADD Rd, PC, #nn */
+ {
+ 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: /* Stack-Related Opcodes */
+ switch( ( insn & THUMB_STACKOP_TYPE ) >> THUMB_STACKOP_TYPE_SHIFT )
+ {
+ case 0x0: /* ADD SP, #imm */
+ 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: /* PUSH {Rlist} */
+ for( offs = 7; offs >= 0; offs-- )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( 13, GET_REGISTER(13) - 4 );
+ WRITE32( GET_REGISTER(13), GET_REGISTER(offs) );
+ }
+ }
+ R15 += 2;
+ break;
+ case 0x5: /* PUSH {Rlist}{LR} */
+ SET_REGISTER( 13, GET_REGISTER(13) - 4 );
+ WRITE32( GET_REGISTER(13), GET_REGISTER(14) );
+ for( offs = 7; offs >= 0; offs-- )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( 13, GET_REGISTER(13) - 4 );
+ WRITE32( GET_REGISTER(13), GET_REGISTER(offs) );
+ }
+ }
+ R15 += 2;
+ break;
+ case 0xc: /* POP {Rlist} */
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( offs, READ32( GET_REGISTER(13) ) );
+ SET_REGISTER( 13, GET_REGISTER(13) + 4 );
+ }
+ }
+ R15 += 2;
+ break;
+ case 0xd: /* POP {Rlist}{PC} */
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( offs, READ32( GET_REGISTER(13) ) );
+ SET_REGISTER( 13, GET_REGISTER(13) + 4 );
+ }
+ }
+ R15 = READ32( GET_REGISTER(13) ) & ~1;
+ SET_REGISTER( 13, GET_REGISTER(13) + 4 );
+ break;
+ default:
+ fatalerror("%08x: Gb Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ break;
+ case 0xc: /* Multiple Load/Store */
+ if( insn & THUMB_MULTLS ) /* Load */
+ {
+ rd = ( insn & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ SET_REGISTER( offs, READ32( (GET_REGISTER(rd)&0xfffffffc) ) );
+ SET_REGISTER( rd, GET_REGISTER(rd) + 4 );
+ }
+ }
+ R15 += 2;
+ }
+ else /* Store */
+ {
+ rd = ( insn & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT;
+ for( offs = 0; offs < 8; offs++ )
+ {
+ if( insn & ( 1 << offs ) )
+ {
+ WRITE32( (GET_REGISTER(rd)&0xfffffffc), GET_REGISTER(offs) );
+ SET_REGISTER( rd, GET_REGISTER(rd) + 4 );
+ }
+ }
+ R15 += 2;
+ }
+ break;
+ case 0xd: /* Conditional Branch */
+ 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 & N_MASK) == !(GET_CPSR & V_MASK) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_LT:
+ if( !(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_GT:
+ if( Z_IS_CLEAR(GET_CPSR) && ( !(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK) ) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_LE:
+ if( Z_IS_SET(GET_CPSR) || ( !(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK) ) )
+ {
+ R15 += 4 + (offs << 1);
+ }
+ else
+ {
+ R15 += 2;
+ }
+ break;
+ case COND_AL:
+ fatalerror("%08x: Undefined Thumb instruction: %04x (ARM9 reserved)\n", pc, insn);
+ R15 += 2;
+ break;
+
+ case COND_NV: // SWI (this is sort of a "hole" in the opcode encoding)
+ ARM7.pendingSwi = 1;
+ ARM7_CHECKIRQ;
+ break;
+ }
+ break;
+ case 0xe: /* B #offs */
+ offs = ( insn & THUMB_BRANCH_OFFS ) << 1;
+ if( offs & 0x00000800 )
+ {
+ offs |= 0xfffff800;
+ }
+ R15 += 4 + offs;
+ break;
+ case 0xf: /* BL */
+ if( insn & THUMB_BLOP_LO )
+ {
+ addr = GET_REGISTER(14);
+ addr += ( insn & THUMB_BLOP_OFFS ) << 1;
+ SET_REGISTER( 14, ( R15 + 2 ) | 1 );
+ R15 = addr;
+ // R15 += 2;
+ }
+ else
+ {
+ addr = ( insn & THUMB_BLOP_OFFS ) << 12;
+ if( addr & ( 1 << 22 ) )
+ {
+ addr |= 0xff800000;
+ }
+ addr += R15 + 4;
+ SET_REGISTER( 14, addr );
+ R15 += 2;
+ }
+ break;
+ default:
+ fatalerror("%08x: Undefined Thumb instruction: %04x\n", pc, insn);
+ R15 += 2;
+ break;
+ }
+ }
+ else
+ {
+
+ /* load 32 bit instruction */
+ pc = R15;
+ insn = cpu_readop32(pc);
+
+ /* process condition codes for this instruction */
+ switch (insn >> INSN_COND_SHIFT)
+ {
+ case COND_EQ:
+ if (Z_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_NE:
+ if (Z_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_CS:
+ if (C_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_CC:
+ if (C_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_MI:
+ if (N_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_PL:
+ if (N_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_VS:
+ if (V_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_VC:
+ if (V_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_HI:
+ if (C_IS_CLEAR(GET_CPSR) || Z_IS_SET(GET_CPSR)) goto L_Next;
+ break;
+ case COND_LS:
+ if (C_IS_SET(GET_CPSR) && Z_IS_CLEAR(GET_CPSR)) goto L_Next;
+ break;
+ case COND_GE:
+ if (!(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK)) goto L_Next; /* Use x ^ (x >> ...) method */
+ break;
+ case COND_LT:
+ if (!(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK)) goto L_Next;
+ break;
+ case COND_GT:
+ if (Z_IS_SET(GET_CPSR) || (!(GET_CPSR & N_MASK) != !(GET_CPSR & V_MASK))) goto L_Next;
+ break;
+ case COND_LE:
+ if (Z_IS_CLEAR(GET_CPSR) && (!(GET_CPSR & N_MASK) == !(GET_CPSR & V_MASK))) goto L_Next;
+ break;
+ case COND_NV:
+ goto L_Next;
+ }
+ /*******************************************************************/
+ /* If we got here - condition satisfied, so decode the instruction */
+ /*******************************************************************/
+ switch( (insn & 0xF000000)>>24 )
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ /* Branch and Exchange (BX) */
+ if( (insn&0x0ffffff0)==0x012fff10 ) //bits 27-4 == 000100101111111111110001
+ {
+ R15 = GET_REGISTER(insn & 0x0f);
+ //If new PC address has A0 set, switch to Thumb mode
+ if(R15 & 1) {
+ SET_CPSR(GET_CPSR|T_MASK);
+ R15--;
+ }
+ }
+ else
+ /* Multiply OR Swap OR Half Word Data Transfer */
+ if( (insn & 0x0e000000)==0 && (insn & 0x80) && (insn & 0x10) ) //bits 27-25 == 000, bit 7=1, bit 4=1
+ {
+ /* Half Word Data Transfer */
+ if(insn & 0x60) //bits = 6-5 != 00
+ {
+ HandleHalfWordDT(insn);
+ }
+ else
+ /* Swap */
+ if(insn & 0x01000000) //bit 24 = 1
+ {
+ HandleSwap(insn);
+ }
+ /* Multiply Or Multiply Long */
+ else
+ {
+ /* multiply long */
+ if( insn&0x800000 ) //Bit 23 = 1 for Multiply Long
+ {
+ /* Signed? */
+ if( insn&0x00400000 )
+ HandleSMulLong(insn);
+ else
+ HandleUMulLong(insn);
+ }
+ /* multiply */
+ else
+ {
+ HandleMul(insn);
+ }
+ R15 += 4;
+ }
+ }
+ else
+ /* Data Processing OR PSR Transfer */
+ if( (insn & 0x0c000000) ==0 ) //bits 27-26 == 00 - This check can only exist properly after Multiplication check above
+ {
+ /* PSR Transfer (MRS & MSR) */
+ if( ((insn&0x0100000)==0) && ((insn&0x01800000)==0x01000000) ) //( S bit must be clear, and bit 24,23 = 10 )
+ {
+ HandlePSRTransfer(insn);
+ ARM7_ICOUNT += 2; //PSR only takes 1 - S Cycle, so we add + 2, since at end, we -3..
+ R15 += 4;
+ }
+ /* Data Processing */
+ else
+ {
+ HandleALU(insn);
+ }
+ }
+ break;
+ /* Data Transfer - Single Data Access */
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ HandleMemSingle(insn);
+ R15 += 4;
+ break;
+ /* Block Data Transfer/Access */
+ case 8:
+ case 9:
+ HandleMemBlock(insn);
+ R15 += 4;
+ break;
+ /* Branch or Branch & Link */
+ case 0xa:
+ case 0xb:
+ HandleBranch(insn);
+ break;
+ /* Co-Processor Data Transfer */
+ case 0xc:
+ case 0xd:
+ HandleCoProcDT(insn);
+ R15 += 4;
+ break;
+ /* Co-Processor Data Operation or Register Transfer */
+ case 0xe:
+ if(insn & 0x10)
+ HandleCoProcRT(insn);
+ else
+ HandleCoProcDO(insn);
+ R15 += 4;
+ break;
+ /* Software Interrupt */
+ case 0x0f:
+ ARM7.pendingSwi = 1;
+ ARM7_CHECKIRQ;
+ //couldn't find any cycle counts for SWI
+ break;
+ /* Undefined */
+ default:
+ ARM7.pendingSwi = 1;
+ ARM7_CHECKIRQ;
+ ARM7_ICOUNT -= 1; //undefined takes 4 cycles (page 77)
+ LOG(("%08x: Undefined instruction\n",pc-4));
+ L_Next:
+ R15 += 4;
+ ARM7_ICOUNT +=2; //Any unexecuted instruction only takes 1 cycle (page 193)
+ }
+ }
+
+ change_pc(R15);
+
+ ARM7_CHECKIRQ;
+
+ /* All instructions remove 3 cycles.. Others taking less / more will have adjusted this # prior to here */
+ ARM7_ICOUNT -= 3;
+ } while( ARM7_ICOUNT > 0 );
+
+ return cycles - ARM7_ICOUNT;
+}
+