rlm@1: #ifdef C_CORE rlm@1: #define NEG(i) ((i) >> 31) rlm@1: #define POS(i) ((~(i)) >> 31) rlm@1: #define ADDCARRY(a, b, c) \ rlm@1: C_FLAG = ((NEG(a) & NEG(b)) | \ rlm@1: (NEG(a) & POS(c)) | \ rlm@1: (NEG(b) & POS(c))) ? true : false; rlm@1: #define ADDOVERFLOW(a, b, c) \ rlm@1: V_FLAG = ((NEG(a) & NEG(b) & POS(c)) | \ rlm@1: (POS(a) & POS(b) & NEG(c))) ? true : false; rlm@1: #define SUBCARRY(a, b, c) \ rlm@1: C_FLAG = ((NEG(a) & POS(b)) | \ rlm@1: (NEG(a) & POS(c)) | \ rlm@1: (POS(b) & POS(c))) ? true : false; rlm@1: #define SUBOVERFLOW(a, b, c) \ rlm@1: V_FLAG = ((NEG(a) & POS(b) & POS(c)) | \ rlm@1: (POS(a) & NEG(b) & NEG(c))) ? true : false; rlm@1: #define ADD_RD_RS_RN \ rlm@1: { \ rlm@1: u32 lhs = reg[source].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs + rhs; \ rlm@1: reg[dest].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: ADDCARRY(lhs, rhs, res); \ rlm@1: ADDOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define ADD_RD_RS_O3 \ rlm@1: { \ rlm@1: u32 lhs = reg[source].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs + rhs; \ rlm@1: reg[dest].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: ADDCARRY(lhs, rhs, res); \ rlm@1: ADDOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define ADD_RN_O8(d) \ rlm@1: { \ rlm@1: u32 lhs = reg[(d)].I; \ rlm@1: u32 rhs = (opcode & 255); \ rlm@1: u32 res = lhs + rhs; \ rlm@1: reg[(d)].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: ADDCARRY(lhs, rhs, res); \ rlm@1: ADDOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define CMN_RD_RS \ rlm@1: { \ rlm@1: u32 lhs = reg[dest].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs + rhs; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: ADDCARRY(lhs, rhs, res); \ rlm@1: ADDOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define ADC_RD_RS \ rlm@1: { \ rlm@1: u32 lhs = reg[dest].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs + rhs + (u32)C_FLAG; \ rlm@1: reg[dest].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: ADDCARRY(lhs, rhs, res); \ rlm@1: ADDOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define SUB_RD_RS_RN \ rlm@1: { \ rlm@1: u32 lhs = reg[source].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs - rhs; \ rlm@1: reg[dest].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: SUBCARRY(lhs, rhs, res); \ rlm@1: SUBOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define SUB_RD_RS_O3 \ rlm@1: { \ rlm@1: u32 lhs = reg[source].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs - rhs; \ rlm@1: reg[dest].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: SUBCARRY(lhs, rhs, res); \ rlm@1: SUBOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define SUB_RN_O8(d) \ rlm@1: { \ rlm@1: u32 lhs = reg[(d)].I; \ rlm@1: u32 rhs = (opcode & 255); \ rlm@1: u32 res = lhs - rhs; \ rlm@1: reg[(d)].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: SUBCARRY(lhs, rhs, res); \ rlm@1: SUBOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define CMP_RN_O8(d) \ rlm@1: { \ rlm@1: u32 lhs = reg[(d)].I; \ rlm@1: u32 rhs = (opcode & 255); \ rlm@1: u32 res = lhs - rhs; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: SUBCARRY(lhs, rhs, res); \ rlm@1: SUBOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define SBC_RD_RS \ rlm@1: { \ rlm@1: u32 lhs = reg[dest].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs - rhs - !((u32)C_FLAG); \ rlm@1: reg[dest].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: SUBCARRY(lhs, rhs, res); \ rlm@1: SUBOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #define LSL_RD_RM_I5 \ rlm@1: { \ rlm@1: C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false; \ rlm@1: value = reg[source].I << shift; \ rlm@1: } rlm@1: #define LSL_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false; \ rlm@1: value = reg[dest].I << value; \ rlm@1: } rlm@1: #define LSR_RD_RM_I5 \ rlm@1: { \ rlm@1: C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false; \ rlm@1: value = reg[source].I >> shift; \ rlm@1: } rlm@1: #define LSR_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \ rlm@1: value = reg[dest].I >> value; \ rlm@1: } rlm@1: #define ASR_RD_RM_I5 \ rlm@1: { \ rlm@1: C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false; \ rlm@1: value = (s32)reg[source].I >> (int)shift; \ rlm@1: } rlm@1: #define ASR_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false; \ rlm@1: value = (s32)reg[dest].I >> (int)value; \ rlm@1: } rlm@1: #define ROR_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \ rlm@1: value = ((reg[dest].I << (32 - value)) | \ rlm@1: (reg[dest].I >> value)); \ rlm@1: } rlm@1: #define NEG_RD_RS \ rlm@1: { \ rlm@1: u32 lhs = reg[source].I; \ rlm@1: u32 rhs = 0; \ rlm@1: u32 res = rhs - lhs; \ rlm@1: reg[dest].I = res; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: SUBCARRY(rhs, lhs, res); \ rlm@1: SUBOVERFLOW(rhs, lhs, res); \ rlm@1: } rlm@1: #define CMP_RD_RS \ rlm@1: { \ rlm@1: u32 lhs = reg[dest].I; \ rlm@1: u32 rhs = value; \ rlm@1: u32 res = lhs - rhs; \ rlm@1: Z_FLAG = (res == 0) ? true : false; \ rlm@1: N_FLAG = NEG(res) ? true : false; \ rlm@1: SUBCARRY(lhs, rhs, res); \ rlm@1: SUBOVERFLOW(lhs, rhs, res); \ rlm@1: } rlm@1: #else rlm@1: #ifdef __GNUC__ rlm@1: #ifdef __POWERPC__ rlm@1: #define ADD_RD_RS_RN \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("addco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[source].I), \ rlm@1: "r" (value) \ rlm@1: ); \ rlm@1: reg[dest].I = Result; \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define ADD_RD_RS_O3 ADD_RD_RS_RN rlm@1: #define ADD_RN_O8(d) \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("addco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[(d)].I), \ rlm@1: "r" (opcode & 255) \ rlm@1: ); \ rlm@1: reg[(d)].I = Result; \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define CMN_RD_RS \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("addco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[dest].I), \ rlm@1: "r" (value) \ rlm@1: ); \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define ADC_RD_RS \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("mtspr xer, %4\n" \ rlm@1: "addeo. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[dest].I), \ rlm@1: "r" (value), \ rlm@1: "r" (C_FLAG << 29) \ rlm@1: ); \ rlm@1: reg[dest].I = Result; \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define SUB_RD_RS_RN \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("subco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[source].I), \ rlm@1: "r" (value) \ rlm@1: ); \ rlm@1: reg[dest].I = Result; \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define SUB_RD_RS_O3 SUB_RD_RS_RN rlm@1: #define SUB_RN_O8(d) \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("subco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[(d)].I), \ rlm@1: "r" (opcode & 255) \ rlm@1: ); \ rlm@1: reg[(d)].I = Result; \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define CMP_RN_O8(d) \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("subco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[(d)].I), \ rlm@1: "r" (opcode & 255) \ rlm@1: ); \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define SBC_RD_RS \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("mtspr xer, %4\n" \ rlm@1: "subfeo. %0, %3, %2\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[dest].I), \ rlm@1: "r" (value), \ rlm@1: "r" (C_FLAG << 29) \ rlm@1: ); \ rlm@1: reg[dest].I = Result; \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define LSL_RD_RM_I5 \ rlm@1: { \ rlm@1: C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false; \ rlm@1: value = reg[source].I << shift; \ rlm@1: } rlm@1: #define LSL_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false; \ rlm@1: value = reg[dest].I << value; \ rlm@1: } rlm@1: #define LSR_RD_RM_I5 \ rlm@1: { \ rlm@1: C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false; \ rlm@1: value = reg[source].I >> shift; \ rlm@1: } rlm@1: #define LSR_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \ rlm@1: value = reg[dest].I >> value; \ rlm@1: } rlm@1: #define ASR_RD_RM_I5 \ rlm@1: { \ rlm@1: C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false; \ rlm@1: value = (s32)reg[source].I >> (int)shift; \ rlm@1: } rlm@1: #define ASR_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false; \ rlm@1: value = (s32)reg[dest].I >> (int)value; \ rlm@1: } rlm@1: #define ROR_RD_RS \ rlm@1: { \ rlm@1: C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false; \ rlm@1: value = ((reg[dest].I << (32 - value)) | \ rlm@1: (reg[dest].I >> value)); \ rlm@1: } rlm@1: #define NEG_RD_RS \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("subfco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[source].I), \ rlm@1: "r" (0) \ rlm@1: ); \ rlm@1: reg[dest].I = Result; \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #define CMP_RD_RS \ rlm@1: { \ rlm@1: register int Flags; \ rlm@1: register int Result; \ rlm@1: asm volatile ("subco. %0, %2, %3\n" \ rlm@1: "mcrxr cr1\n" \ rlm@1: "mfcr %1\n" \ rlm@1: : "=r" (Result), \ rlm@1: "=r" (Flags) \ rlm@1: : "r" (reg[dest].I), \ rlm@1: "r" (value) \ rlm@1: ); \ rlm@1: Z_FLAG = (Flags >> 29) & 1; \ rlm@1: N_FLAG = (Flags >> 31) & 1; \ rlm@1: C_FLAG = (Flags >> 25) & 1; \ rlm@1: V_FLAG = (Flags >> 26) & 1; \ rlm@1: } rlm@1: #else rlm@1: #define ADD_RD_RS_RN \ rlm@1: asm ("add %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[dest].I) \ rlm@1: : "r" (value), "b" (reg[source].I)); rlm@1: #define ADD_RD_RS_O3 \ rlm@1: asm ("add %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[dest].I) \ rlm@1: : "r" (value), "b" (reg[source].I)); rlm@1: #define ADD_RN_O8(d) \ rlm@1: asm ("add %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[(d)].I) \ rlm@1: : "r" (opcode & 255), "b" (reg[(d)].I)); rlm@1: #define CMN_RD_RS \ rlm@1: asm ("add %0, %1;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : \ rlm@1: : "r" (value), "r" (reg[dest].I) : "1"); rlm@1: #define ADC_RD_RS \ rlm@1: asm ("bt $0, C_FLAG;" \ rlm@1: "adc %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[dest].I) \ rlm@1: : "r" (value), "b" (reg[dest].I)); rlm@1: #define SUB_RD_RS_RN \ rlm@1: asm ("sub %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setncb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[dest].I) \ rlm@1: : "r" (value), "b" (reg[source].I)); rlm@1: #define SUB_RD_RS_O3 \ rlm@1: asm ("sub %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setncb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[dest].I) \ rlm@1: : "r" (value), "b" (reg[source].I)); rlm@1: #define SUB_RN_O8(d) \ rlm@1: asm ("sub %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setncb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[(d)].I) \ rlm@1: : "r" (opcode & 255), "b" (reg[(d)].I)); rlm@1: #define CMP_RN_O8(d) \ rlm@1: asm ("sub %0, %1;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setncb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : \ rlm@1: : "r" (opcode & 255), "r" (reg[(d)].I) : "1"); rlm@1: #define SBC_RD_RS \ rlm@1: asm volatile ("bt $0, C_FLAG;" \ rlm@1: "cmc;" \ rlm@1: "sbb %1, %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setncb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[dest].I) \ rlm@1: : "r" (value), "b" (reg[dest].I) : "cc", "memory"); rlm@1: #define LSL_RD_RM_I5 \ rlm@1: asm ("shl %%cl, %%eax;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: : "=a" (value) \ rlm@1: : "a" (reg[source].I), "c" (shift)); rlm@1: #define LSL_RD_RS \ rlm@1: asm ("shl %%cl, %%eax;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: : "=a" (value) \ rlm@1: : "a" (reg[dest].I), "c" (value)); rlm@1: #define LSR_RD_RM_I5 \ rlm@1: asm ("shr %%cl, %%eax;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: : "=a" (value) \ rlm@1: : "a" (reg[source].I), "c" (shift)); rlm@1: #define LSR_RD_RS \ rlm@1: asm ("shr %%cl, %%eax;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: : "=a" (value) \ rlm@1: : "a" (reg[dest].I), "c" (value)); rlm@1: #define ASR_RD_RM_I5 \ rlm@1: asm ("sar %%cl, %%eax;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: : "=a" (value) \ rlm@1: : "a" (reg[source].I), "c" (shift)); rlm@1: #define ASR_RD_RS \ rlm@1: asm ("sar %%cl, %%eax;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: : "=a" (value) \ rlm@1: : "a" (reg[dest].I), "c" (value)); rlm@1: #define ROR_RD_RS \ rlm@1: asm ("ror %%cl, %%eax;" \ rlm@1: "setcb C_FLAG;" \ rlm@1: : "=a" (value) \ rlm@1: : "a" (reg[dest].I), "c" (value)); rlm@1: #define NEG_RD_RS \ rlm@1: asm ("neg %%ebx;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setncb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : "=b" (reg[dest].I) \ rlm@1: : "b" (reg[source].I)); rlm@1: #define CMP_RD_RS \ rlm@1: asm ("sub %0, %1;" \ rlm@1: "setsb N_FLAG;" \ rlm@1: "setzb Z_FLAG;" \ rlm@1: "setncb C_FLAG;" \ rlm@1: "setob V_FLAG;" \ rlm@1: : \ rlm@1: : "r" (value), "r" (reg[dest].I) : "1"); rlm@1: #endif rlm@1: #else rlm@1: #define ADD_RD_RS_RN \ rlm@1: { \ rlm@1: __asm mov eax, source \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm add ebx, value \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov dword ptr [OFFSET reg + 4 * eax], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define ADD_RD_RS_O3 \ rlm@1: { \ rlm@1: __asm mov eax, source \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm add ebx, value \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov dword ptr [OFFSET reg + 4 * eax], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define ADD_RN_O8(d) \ rlm@1: { \ rlm@1: __asm mov ebx, opcode \ rlm@1: __asm and ebx, 255 \ rlm@1: __asm add dword ptr [OFFSET reg + 4 * (d)], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define CMN_RD_RS \ rlm@1: { \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm add ebx, value \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define ADC_RD_RS \ rlm@1: { \ rlm@1: __asm mov ebx, dest \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \ rlm@1: __asm bt word ptr C_FLAG, 0 \ rlm@1: __asm adc ebx, value \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov dword ptr [OFFSET reg + 4 * eax], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define SUB_RD_RS_RN \ rlm@1: { \ rlm@1: __asm mov eax, source \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm sub ebx, value \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov dword ptr [OFFSET reg + 4 * eax], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setnc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define SUB_RD_RS_O3 \ rlm@1: { \ rlm@1: __asm mov eax, source \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm sub ebx, value \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov dword ptr [OFFSET reg + 4 * eax], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setnc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define SUB_RN_O8(d) \ rlm@1: { \ rlm@1: __asm mov ebx, opcode \ rlm@1: __asm and ebx, 255 \ rlm@1: __asm sub dword ptr [OFFSET reg + 4 * (d)], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setnc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define CMP_RN_O8(d) \ rlm@1: { \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * (d)] \ rlm@1: __asm mov ebx, opcode \ rlm@1: __asm and ebx, 255 \ rlm@1: __asm sub eax, ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setnc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define SBC_RD_RS \ rlm@1: { \ rlm@1: __asm mov ebx, dest \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \ rlm@1: __asm mov eax, value \ rlm@1: __asm bt word ptr C_FLAG, 0 \ rlm@1: __asm cmc \ rlm@1: __asm sbb ebx, eax \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov dword ptr [OFFSET reg + 4 * eax], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setnc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define LSL_RD_RM_I5 \ rlm@1: { \ rlm@1: __asm mov eax, source \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm mov cl, byte ptr shift \ rlm@1: __asm shl eax, cl \ rlm@1: __asm mov value, eax \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: } rlm@1: #define LSL_RD_RS \ rlm@1: { \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm mov cl, byte ptr value \ rlm@1: __asm shl eax, cl \ rlm@1: __asm mov value, eax \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: } rlm@1: #define LSR_RD_RM_I5 \ rlm@1: { \ rlm@1: __asm mov eax, source \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm mov cl, byte ptr shift \ rlm@1: __asm shr eax, cl \ rlm@1: __asm mov value, eax \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: } rlm@1: #define LSR_RD_RS \ rlm@1: { \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm mov cl, byte ptr value \ rlm@1: __asm shr eax, cl \ rlm@1: __asm mov value, eax \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: } rlm@1: #define ASR_RD_RM_I5 \ rlm@1: { \ rlm@1: __asm mov eax, source \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm mov cl, byte ptr shift \ rlm@1: __asm sar eax, cl \ rlm@1: __asm mov value, eax \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: } rlm@1: #define ASR_RD_RS \ rlm@1: { \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm mov cl, byte ptr value \ rlm@1: __asm sar eax, cl \ rlm@1: __asm mov value, eax \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: } rlm@1: #define ROR_RD_RS \ rlm@1: { \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov eax, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm mov cl, byte ptr value \ rlm@1: __asm ror eax, cl \ rlm@1: __asm mov value, eax \ rlm@1: __asm setc byte ptr C_FLAG \ rlm@1: } rlm@1: #define NEG_RD_RS \ rlm@1: { \ rlm@1: __asm mov ebx, source \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * ebx] \ rlm@1: __asm neg ebx \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov dword ptr [OFFSET reg + 4 * eax], ebx \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setnc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #define CMP_RD_RS \ rlm@1: { \ rlm@1: __asm mov eax, dest \ rlm@1: __asm mov ebx, dword ptr [OFFSET reg + 4 * eax] \ rlm@1: __asm sub ebx, value \ rlm@1: __asm sets byte ptr N_FLAG \ rlm@1: __asm setz byte ptr Z_FLAG \ rlm@1: __asm setnc byte ptr C_FLAG \ rlm@1: __asm seto byte ptr V_FLAG \ rlm@1: } rlm@1: #endif rlm@1: #endif rlm@1: rlm@1: u32 opcode = CPUReadHalfWordQuick(armNextPC); rlm@1: clockTicks = thumbCycles[opcode >> 8] + memoryWaitFetch[(armNextPC >> 24) & 15]; rlm@1: #ifndef FINAL_VERSION rlm@1: if (armNextPC == stop) rlm@1: { rlm@1: armNextPC = armNextPC++; rlm@1: } rlm@1: #endif rlm@1: rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: rlm@1: switch (opcode >> 8) rlm@1: { rlm@1: case 0x00: rlm@1: case 0x01: rlm@1: case 0x02: rlm@1: case 0x03: rlm@1: case 0x04: rlm@1: case 0x05: rlm@1: case 0x06: rlm@1: case 0x07: rlm@1: { rlm@1: // LSL Rd, Rm, #Imm 5 rlm@1: int dest = opcode & 0x07; rlm@1: int source = (opcode >> 3) & 0x07; rlm@1: int shift = (opcode >> 6) & 0x1f; rlm@1: u32 value; rlm@1: rlm@1: if (shift) rlm@1: { rlm@1: LSL_RD_RM_I5; rlm@1: } rlm@1: else rlm@1: { rlm@1: value = reg[source].I; rlm@1: } rlm@1: reg[dest].I = value; rlm@1: // C_FLAG set above rlm@1: N_FLAG = (value & 0x80000000 ? true : false); rlm@1: Z_FLAG = (value ? false : true); rlm@1: } rlm@1: break; rlm@1: case 0x08: rlm@1: case 0x09: rlm@1: case 0x0a: rlm@1: case 0x0b: rlm@1: case 0x0c: rlm@1: case 0x0d: rlm@1: case 0x0e: rlm@1: case 0x0f: rlm@1: { rlm@1: // LSR Rd, Rm, #Imm 5 rlm@1: int dest = opcode & 0x07; rlm@1: int source = (opcode >> 3) & 0x07; rlm@1: int shift = (opcode >> 6) & 0x1f; rlm@1: u32 value; rlm@1: rlm@1: if (shift) rlm@1: { rlm@1: LSR_RD_RM_I5; rlm@1: } rlm@1: else rlm@1: { rlm@1: C_FLAG = reg[source].I & 0x80000000 ? true : false; rlm@1: value = 0; rlm@1: } rlm@1: reg[dest].I = value; rlm@1: // C_FLAG set above rlm@1: N_FLAG = (value & 0x80000000 ? true : false); rlm@1: Z_FLAG = (value ? false : true); rlm@1: } rlm@1: break; rlm@1: case 0x10: rlm@1: case 0x11: rlm@1: case 0x12: rlm@1: case 0x13: rlm@1: case 0x14: rlm@1: case 0x15: rlm@1: case 0x16: rlm@1: case 0x17: rlm@1: { rlm@1: // ASR Rd, Rm, #Imm 5 rlm@1: int dest = opcode & 0x07; rlm@1: int source = (opcode >> 3) & 0x07; rlm@1: int shift = (opcode >> 6) & 0x1f; rlm@1: u32 value; rlm@1: rlm@1: if (shift) rlm@1: { rlm@1: ASR_RD_RM_I5; rlm@1: } rlm@1: else rlm@1: { rlm@1: if (reg[source].I & 0x80000000) rlm@1: { rlm@1: value = 0xFFFFFFFF; rlm@1: C_FLAG = true; rlm@1: } rlm@1: else rlm@1: { rlm@1: value = 0; rlm@1: C_FLAG = false; rlm@1: } rlm@1: } rlm@1: reg[dest].I = value; rlm@1: // C_FLAG set above rlm@1: N_FLAG = (value & 0x80000000 ? true : false); rlm@1: Z_FLAG = (value ? false : true); rlm@1: } rlm@1: break; rlm@1: case 0x18: rlm@1: case 0x19: rlm@1: { rlm@1: // ADD Rd, Rs, Rn rlm@1: int dest = opcode & 0x07; rlm@1: int source = (opcode >> 3) & 0x07; rlm@1: u32 value = reg[(opcode >> 6) & 0x07].I; rlm@1: ADD_RD_RS_RN; rlm@1: } rlm@1: break; rlm@1: case 0x1a: rlm@1: case 0x1b: rlm@1: { rlm@1: // SUB Rd, Rs, Rn rlm@1: int dest = opcode & 0x07; rlm@1: int source = (opcode >> 3) & 0x07; rlm@1: u32 value = reg[(opcode >> 6) & 0x07].I; rlm@1: SUB_RD_RS_RN; rlm@1: } rlm@1: break; rlm@1: case 0x1c: rlm@1: case 0x1d: rlm@1: { rlm@1: // ADD Rd, Rs, #Offset3 rlm@1: int dest = opcode & 0x07; rlm@1: int source = (opcode >> 3) & 0x07; rlm@1: u32 value = (opcode >> 6) & 7; rlm@1: ADD_RD_RS_O3; rlm@1: } rlm@1: break; rlm@1: case 0x1e: rlm@1: case 0x1f: rlm@1: { rlm@1: // SUB Rd, Rs, #Offset3 rlm@1: int dest = opcode & 0x07; rlm@1: int source = (opcode >> 3) & 0x07; rlm@1: u32 value = (opcode >> 6) & 7; rlm@1: SUB_RD_RS_O3; rlm@1: } rlm@1: break; rlm@1: case 0x20: rlm@1: // MOV R0, #Offset8 rlm@1: reg[0].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[0].I ? false : true); rlm@1: break; rlm@1: case 0x21: rlm@1: // MOV R1, #Offset8 rlm@1: reg[1].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[1].I ? false : true); rlm@1: break; rlm@1: case 0x22: rlm@1: // MOV R2, #Offset8 rlm@1: reg[2].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[2].I ? false : true); rlm@1: break; rlm@1: case 0x23: rlm@1: // MOV R3, #Offset8 rlm@1: reg[3].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[3].I ? false : true); rlm@1: break; rlm@1: case 0x24: rlm@1: // MOV R4, #Offset8 rlm@1: reg[4].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[4].I ? false : true); rlm@1: break; rlm@1: case 0x25: rlm@1: // MOV R5, #Offset8 rlm@1: reg[5].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[5].I ? false : true); rlm@1: break; rlm@1: case 0x26: rlm@1: // MOV R6, #Offset8 rlm@1: reg[6].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[6].I ? false : true); rlm@1: break; rlm@1: case 0x27: rlm@1: // MOV R7, #Offset8 rlm@1: reg[7].I = opcode & 255; rlm@1: N_FLAG = false; rlm@1: Z_FLAG = (reg[7].I ? false : true); rlm@1: break; rlm@1: case 0x28: rlm@1: // CMP R0, #Offset8 rlm@1: CMP_RN_O8(0); rlm@1: break; rlm@1: case 0x29: rlm@1: // CMP R1, #Offset8 rlm@1: CMP_RN_O8(1); rlm@1: break; rlm@1: case 0x2a: rlm@1: // CMP R2, #Offset8 rlm@1: CMP_RN_O8(2); rlm@1: break; rlm@1: case 0x2b: rlm@1: // CMP R3, #Offset8 rlm@1: CMP_RN_O8(3); rlm@1: break; rlm@1: case 0x2c: rlm@1: // CMP R4, #Offset8 rlm@1: CMP_RN_O8(4); rlm@1: break; rlm@1: case 0x2d: rlm@1: // CMP R5, #Offset8 rlm@1: CMP_RN_O8(5); rlm@1: break; rlm@1: case 0x2e: rlm@1: // CMP R6, #Offset8 rlm@1: CMP_RN_O8(6); rlm@1: break; rlm@1: case 0x2f: rlm@1: // CMP R7, #Offset8 rlm@1: CMP_RN_O8(7); rlm@1: break; rlm@1: case 0x30: rlm@1: // ADD R0,#Offset8 rlm@1: ADD_RN_O8(0); rlm@1: break; rlm@1: case 0x31: rlm@1: // ADD R1,#Offset8 rlm@1: ADD_RN_O8(1); rlm@1: break; rlm@1: case 0x32: rlm@1: // ADD R2,#Offset8 rlm@1: ADD_RN_O8(2); rlm@1: break; rlm@1: case 0x33: rlm@1: // ADD R3,#Offset8 rlm@1: ADD_RN_O8(3); rlm@1: break; rlm@1: case 0x34: rlm@1: // ADD R4,#Offset8 rlm@1: ADD_RN_O8(4); rlm@1: break; rlm@1: case 0x35: rlm@1: // ADD R5,#Offset8 rlm@1: ADD_RN_O8(5); rlm@1: break; rlm@1: case 0x36: rlm@1: // ADD R6,#Offset8 rlm@1: ADD_RN_O8(6); rlm@1: break; rlm@1: case 0x37: rlm@1: // ADD R7,#Offset8 rlm@1: ADD_RN_O8(7); rlm@1: break; rlm@1: case 0x38: rlm@1: // SUB R0,#Offset8 rlm@1: SUB_RN_O8(0); rlm@1: break; rlm@1: case 0x39: rlm@1: // SUB R1,#Offset8 rlm@1: SUB_RN_O8(1); rlm@1: break; rlm@1: case 0x3a: rlm@1: // SUB R2,#Offset8 rlm@1: SUB_RN_O8(2); rlm@1: break; rlm@1: case 0x3b: rlm@1: // SUB R3,#Offset8 rlm@1: SUB_RN_O8(3); rlm@1: break; rlm@1: case 0x3c: rlm@1: // SUB R4,#Offset8 rlm@1: SUB_RN_O8(4); rlm@1: break; rlm@1: case 0x3d: rlm@1: // SUB R5,#Offset8 rlm@1: SUB_RN_O8(5); rlm@1: break; rlm@1: case 0x3e: rlm@1: // SUB R6,#Offset8 rlm@1: SUB_RN_O8(6); rlm@1: break; rlm@1: case 0x3f: rlm@1: // SUB R7,#Offset8 rlm@1: SUB_RN_O8(7); rlm@1: break; rlm@1: case 0x40: rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: case 0x00: rlm@1: { rlm@1: // AND Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: reg[dest].I &= reg[(opcode >> 3) & 7].I; rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: #ifdef BKPT_SUPPORT rlm@1: #define THUMB_CONSOLE_OUTPUT(a, b) \ rlm@1: if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \ rlm@1: extern void (*dbgOutput)(char *, u32); \ rlm@1: dbgOutput((a), (b)); \ rlm@1: } rlm@1: #else rlm@1: #define THUMB_CONSOLE_OUTPUT(a, b) rlm@1: #endif rlm@1: THUMB_CONSOLE_OUTPUT(NULL, reg[2].I); rlm@1: } rlm@1: break; rlm@1: case 0x01: rlm@1: // EOR Rd, Rs rlm@1: { rlm@1: int dest = opcode & 7; rlm@1: reg[dest].I ^= reg[(opcode >> 3) & 7].I; rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: } rlm@1: break; rlm@1: case 0x02: rlm@1: // LSL Rd, Rs rlm@1: { rlm@1: int dest = opcode & 7; rlm@1: u32 value = reg[(opcode >> 3) & 7].B.B0; rlm@1: if (value) rlm@1: { rlm@1: if (value == 32) rlm@1: { rlm@1: value = 0; rlm@1: C_FLAG = (reg[dest].I & 1 ? true : false); rlm@1: } rlm@1: else if (value < 32) rlm@1: { rlm@1: LSL_RD_RS; rlm@1: } rlm@1: else rlm@1: { rlm@1: value = 0; rlm@1: C_FLAG = false; rlm@1: } rlm@1: reg[dest].I = value; rlm@1: } rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: clockTicks++; rlm@1: } rlm@1: break; rlm@1: case 0x03: rlm@1: { rlm@1: // LSR Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: u32 value = reg[(opcode >> 3) & 7].B.B0; rlm@1: if (value) rlm@1: { rlm@1: if (value == 32) rlm@1: { rlm@1: value = 0; rlm@1: C_FLAG = (reg[dest].I & 0x80000000 ? true : false); rlm@1: } rlm@1: else if (value < 32) rlm@1: { rlm@1: LSR_RD_RS; rlm@1: } rlm@1: else rlm@1: { rlm@1: value = 0; rlm@1: C_FLAG = false; rlm@1: } rlm@1: reg[dest].I = value; rlm@1: } rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: clockTicks++; rlm@1: } rlm@1: break; rlm@1: } rlm@1: break; rlm@1: case 0x41: rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: case 0x00: rlm@1: { rlm@1: // ASR Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: u32 value = reg[(opcode >> 3) & 7].B.B0; rlm@1: // ASR rlm@1: if (value) rlm@1: { rlm@1: if (value < 32) rlm@1: { rlm@1: ASR_RD_RS; rlm@1: reg[dest].I = value; rlm@1: } rlm@1: else rlm@1: { rlm@1: if (reg[dest].I & 0x80000000) rlm@1: { rlm@1: reg[dest].I = 0xFFFFFFFF; rlm@1: C_FLAG = true; rlm@1: } rlm@1: else rlm@1: { rlm@1: reg[dest].I = 0x00000000; rlm@1: C_FLAG = false; rlm@1: } rlm@1: } rlm@1: } rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: clockTicks++; rlm@1: } rlm@1: break; rlm@1: case 0x01: rlm@1: { rlm@1: // ADC Rd, Rs rlm@1: int dest = opcode & 0x07; rlm@1: u32 value = reg[(opcode >> 3) & 7].I; rlm@1: // ADC rlm@1: ADC_RD_RS; rlm@1: } rlm@1: break; rlm@1: case 0x02: rlm@1: { rlm@1: // SBC Rd, Rs rlm@1: int dest = opcode & 0x07; rlm@1: u32 value = reg[(opcode >> 3) & 7].I; rlm@1: rlm@1: // SBC rlm@1: SBC_RD_RS; rlm@1: } rlm@1: break; rlm@1: case 0x03: rlm@1: // ROR Rd, Rs rlm@1: { rlm@1: int dest = opcode & 7; rlm@1: u32 value = reg[(opcode >> 3) & 7].B.B0; rlm@1: rlm@1: if (value) rlm@1: { rlm@1: value = value & 0x1f; rlm@1: if (value == 0) rlm@1: { rlm@1: C_FLAG = (reg[dest].I & 0x80000000 ? true : false); rlm@1: } rlm@1: else rlm@1: { rlm@1: ROR_RD_RS; rlm@1: reg[dest].I = value; rlm@1: } rlm@1: } rlm@1: clockTicks++; rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: } rlm@1: break; rlm@1: } rlm@1: break; rlm@1: case 0x42: rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: case 0x00: rlm@1: { rlm@1: // TST Rd, Rs rlm@1: u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I; rlm@1: N_FLAG = value & 0x80000000 ? true : false; rlm@1: Z_FLAG = value ? false : true; rlm@1: } rlm@1: break; rlm@1: case 0x01: rlm@1: { rlm@1: // NEG Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: int source = (opcode >> 3) & 7; rlm@1: NEG_RD_RS; rlm@1: } rlm@1: break; rlm@1: case 0x02: rlm@1: { rlm@1: // CMP Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: u32 value = reg[(opcode >> 3) & 7].I; rlm@1: CMP_RD_RS; rlm@1: } rlm@1: break; rlm@1: case 0x03: rlm@1: { rlm@1: // CMN Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: u32 value = reg[(opcode >> 3) & 7].I; rlm@1: // CMN rlm@1: CMN_RD_RS; rlm@1: } rlm@1: break; rlm@1: } rlm@1: break; rlm@1: case 0x43: rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: case 0x00: rlm@1: { rlm@1: // ORR Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: reg[dest].I |= reg[(opcode >> 3) & 7].I; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: } rlm@1: break; rlm@1: case 0x01: rlm@1: { rlm@1: // MUL Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: u32 rm = reg[(opcode >> 3) & 7].I; rlm@1: reg[dest].I = reg[dest].I * rm; rlm@1: if (((s32)rm) < 0) rlm@1: rm = ~rm; rlm@1: if ((rm & 0xFFFFFF00) == 0) rlm@1: clockTicks += 1; rlm@1: else if ((rm & 0xFFFF0000) == 0) rlm@1: clockTicks += 2; rlm@1: else if ((rm & 0xFF000000) == 0) rlm@1: clockTicks += 3; rlm@1: else rlm@1: clockTicks += 4; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: } rlm@1: break; rlm@1: case 0x02: rlm@1: { rlm@1: // BIC Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: reg[dest].I &= (~reg[(opcode >> 3) & 7].I); rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: } rlm@1: break; rlm@1: case 0x03: rlm@1: { rlm@1: // MVN Rd, Rs rlm@1: int dest = opcode & 7; rlm@1: reg[dest].I = ~reg[(opcode >> 3) & 7].I; rlm@1: Z_FLAG = reg[dest].I ? false : true; rlm@1: N_FLAG = reg[dest].I & 0x80000000 ? true : false; rlm@1: } rlm@1: break; rlm@1: } rlm@1: break; rlm@1: case 0x44: rlm@1: { rlm@1: int dest = opcode & 7; rlm@1: int base = (opcode >> 3) & 7; rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: default: rlm@1: goto unknown_thumb; rlm@1: case 1: rlm@1: // ADD Rd, Hs rlm@1: reg[dest].I += reg[base + 8].I; rlm@1: break; rlm@1: case 2: rlm@1: // ADD Hd, Rs rlm@1: reg[dest + 8].I += reg[base].I; rlm@1: if (dest == 7) rlm@1: { rlm@1: reg[15].I &= 0xFFFFFFFE; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks++; rlm@1: } rlm@1: break; rlm@1: case 3: rlm@1: // ADD Hd, Hs rlm@1: reg[dest + 8].I += reg[base + 8].I; rlm@1: if (dest == 7) rlm@1: { rlm@1: reg[15].I &= 0xFFFFFFFE; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks++; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case 0x45: rlm@1: { rlm@1: int dest = opcode & 7; rlm@1: int base = (opcode >> 3) & 7; rlm@1: u32 value; rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: case 0: rlm@1: // CMP Rd, Hs rlm@1: value = reg[base].I; rlm@1: CMP_RD_RS; rlm@1: break; rlm@1: case 1: rlm@1: // CMP Rd, Hs rlm@1: value = reg[base + 8].I; rlm@1: CMP_RD_RS; rlm@1: break; rlm@1: case 2: rlm@1: // CMP Hd, Rs rlm@1: value = reg[base].I; rlm@1: dest += 8; rlm@1: CMP_RD_RS; rlm@1: break; rlm@1: case 3: rlm@1: // CMP Hd, Hs rlm@1: value = reg[base + 8].I; rlm@1: dest += 8; rlm@1: CMP_RD_RS; rlm@1: break; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case 0x46: rlm@1: { rlm@1: int dest = opcode & 7; rlm@1: int base = (opcode >> 3) & 7; rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: case 0: rlm@1: // this form should not be used... rlm@1: // MOV Rd, Rs rlm@1: reg[dest].I = reg[base].I; rlm@1: break; rlm@1: case 1: rlm@1: // MOV Rd, Hs rlm@1: reg[dest].I = reg[base + 8].I; rlm@1: break; rlm@1: case 2: rlm@1: // MOV Hd, Rs rlm@1: reg[dest + 8].I = reg[base].I; rlm@1: if (dest == 7) rlm@1: { rlm@1: reg[15].I &= 0xFFFFFFFE; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks++; rlm@1: } rlm@1: break; rlm@1: case 3: rlm@1: // MOV Hd, Hs rlm@1: reg[dest + 8].I = reg[base + 8].I; rlm@1: if (dest == 7) rlm@1: { rlm@1: reg[15].I &= 0xFFFFFFFE; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks++; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case 0x47: rlm@1: { rlm@1: int base = (opcode >> 3) & 7; rlm@1: switch ((opcode >> 6) & 3) rlm@1: { rlm@1: case 0: rlm@1: // BX Rs rlm@1: reg[15].I = (reg[base].I) & 0xFFFFFFFE; rlm@1: if (reg[base].I & 1) rlm@1: { rlm@1: armState = false; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: } rlm@1: else rlm@1: { rlm@1: armState = true; rlm@1: reg[15].I &= 0xFFFFFFFC; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 4; rlm@1: } rlm@1: break; rlm@1: case 1: rlm@1: // BX Hs rlm@1: reg[15].I = (reg[8 + base].I) & 0xFFFFFFFE; rlm@1: if (reg[8 + base].I & 1) rlm@1: { rlm@1: armState = false; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: } rlm@1: else rlm@1: { rlm@1: armState = true; rlm@1: reg[15].I &= 0xFFFFFFFC; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 4; rlm@1: } rlm@1: break; rlm@1: default: rlm@1: goto unknown_thumb; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case 0x48: rlm@1: // LDR R0,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[0].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x49: rlm@1: // LDR R1,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[1].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x4a: rlm@1: // LDR R2,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[2].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x4b: rlm@1: // LDR R3,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[3].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x4c: rlm@1: // LDR R4,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[4].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x4d: rlm@1: // LDR R5,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[5].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x4e: rlm@1: // LDR R6,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[6].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x4f: rlm@1: // LDR R7,[PC, #Imm] rlm@1: { rlm@1: u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2); rlm@1: reg[7].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x50: rlm@1: case 0x51: rlm@1: // STR Rd, [Rs, Rn] rlm@1: { rlm@1: u32 rlm@1: address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: CPUWriteMemory(address, rlm@1: reg[opcode & 7].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x52: rlm@1: case 0x53: rlm@1: // STRH Rd, [Rs, Rn] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: CPUWriteHalfWord(address, rlm@1: reg[opcode & 7].W.W0); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x54: rlm@1: case 0x55: rlm@1: // STRB Rd, [Rs, Rn] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: CPUWriteByte(address, rlm@1: reg[opcode & 7].B.B0); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x56: rlm@1: case 0x57: rlm@1: // LDSB Rd, [Rs, Rn] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: reg[opcode & 7].I = (s8)CPUReadByte(address); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x58: rlm@1: case 0x59: rlm@1: // LDR Rd, [Rs, Rn] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: reg[opcode & 7].I = CPUReadMemory(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x5a: rlm@1: case 0x5b: rlm@1: // LDRH Rd, [Rs, Rn] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: reg[opcode & 7].I = CPUReadHalfWord(address); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x5c: rlm@1: case 0x5d: rlm@1: // LDRB Rd, [Rs, Rn] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: reg[opcode & 7].I = CPUReadByte(address); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x5e: rlm@1: case 0x5f: rlm@1: // LDSH Rd, [Rs, Rn] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + reg[(opcode >> 6) & 7].I; rlm@1: reg[opcode & 7].I = (s16)CPUReadHalfWordSigned(address); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x60: rlm@1: case 0x61: rlm@1: case 0x62: rlm@1: case 0x63: rlm@1: case 0x64: rlm@1: case 0x65: rlm@1: case 0x66: rlm@1: case 0x67: rlm@1: // STR Rd, [Rs, #Imm] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 2); rlm@1: CPUWriteMemory(address, rlm@1: reg[opcode & 7].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x68: rlm@1: case 0x69: rlm@1: case 0x6a: rlm@1: case 0x6b: rlm@1: case 0x6c: rlm@1: case 0x6d: rlm@1: case 0x6e: rlm@1: case 0x6f: rlm@1: // LDR Rd, [Rs, #Imm] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 2); rlm@1: reg[opcode & 7].I = CPUReadMemory(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x70: rlm@1: case 0x71: rlm@1: case 0x72: rlm@1: case 0x73: rlm@1: case 0x74: rlm@1: case 0x75: rlm@1: case 0x76: rlm@1: case 0x77: rlm@1: // STRB Rd, [Rs, #Imm] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31)); rlm@1: CPUWriteByte(address, rlm@1: reg[opcode & 7].B.B0); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x78: rlm@1: case 0x79: rlm@1: case 0x7a: rlm@1: case 0x7b: rlm@1: case 0x7c: rlm@1: case 0x7d: rlm@1: case 0x7e: rlm@1: case 0x7f: rlm@1: // LDRB Rd, [Rs, #Imm] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31)); rlm@1: reg[opcode & 7].I = CPUReadByte(address); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x80: rlm@1: case 0x81: rlm@1: case 0x82: rlm@1: case 0x83: rlm@1: case 0x84: rlm@1: case 0x85: rlm@1: case 0x86: rlm@1: case 0x87: rlm@1: // STRH Rd, [Rs, #Imm] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 1); rlm@1: CPUWriteHalfWord(address, rlm@1: reg[opcode & 7].W.W0); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x88: rlm@1: case 0x89: rlm@1: case 0x8a: rlm@1: case 0x8b: rlm@1: case 0x8c: rlm@1: case 0x8d: rlm@1: case 0x8e: rlm@1: case 0x8f: rlm@1: // LDRH Rd, [Rs, #Imm] rlm@1: { rlm@1: u32 address = reg[(opcode >> 3) & 7].I + (((opcode >> 6) & 31) << 1); rlm@1: reg[opcode & 7].I = CPUReadHalfWord(address); rlm@1: clockTicks += CPUUpdateTicksAccess16(address); rlm@1: } rlm@1: break; rlm@1: case 0x90: rlm@1: // STR R0, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[0].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x91: rlm@1: // STR R1, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[1].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x92: rlm@1: // STR R2, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[2].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x93: rlm@1: // STR R3, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[3].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x94: rlm@1: // STR R4, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[4].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x95: rlm@1: // STR R5, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[5].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x96: rlm@1: // STR R6, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[6].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x97: rlm@1: // STR R7, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: CPUWriteMemory(address, reg[7].I); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x98: rlm@1: // LDR R0, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[0].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x99: rlm@1: // LDR R1, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[1].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x9a: rlm@1: // LDR R2, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[2].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x9b: rlm@1: // LDR R3, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[3].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x9c: rlm@1: // LDR R4, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[4].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x9d: rlm@1: // LDR R5, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[5].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x9e: rlm@1: // LDR R6, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[6].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0x9f: rlm@1: // LDR R7, [SP, #Imm] rlm@1: { rlm@1: u32 address = reg[13].I + ((opcode & 255) << 2); rlm@1: reg[7].I = CPUReadMemoryQuick(address); rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: } rlm@1: break; rlm@1: case 0xa0: rlm@1: // ADD R0, PC, Imm rlm@1: reg[0].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa1: rlm@1: // ADD R1, PC, Imm rlm@1: reg[1].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa2: rlm@1: // ADD R2, PC, Imm rlm@1: reg[2].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa3: rlm@1: // ADD R3, PC, Imm rlm@1: reg[3].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa4: rlm@1: // ADD R4, PC, Imm rlm@1: reg[4].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa5: rlm@1: // ADD R5, PC, Imm rlm@1: reg[5].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa6: rlm@1: // ADD R6, PC, Imm rlm@1: reg[6].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa7: rlm@1: // ADD R7, PC, Imm rlm@1: reg[7].I = (reg[15].I & 0xFFFFFFFC) + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa8: rlm@1: // ADD R0, SP, Imm rlm@1: reg[0].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xa9: rlm@1: // ADD R1, SP, Imm rlm@1: reg[1].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xaa: rlm@1: // ADD R2, SP, Imm rlm@1: reg[2].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xab: rlm@1: // ADD R3, SP, Imm rlm@1: reg[3].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xac: rlm@1: // ADD R4, SP, Imm rlm@1: reg[4].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xad: rlm@1: // ADD R5, SP, Imm rlm@1: reg[5].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xae: rlm@1: // ADD R6, SP, Imm rlm@1: reg[6].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xaf: rlm@1: // ADD R7, SP, Imm rlm@1: reg[7].I = reg[13].I + ((opcode & 255) << 2); rlm@1: break; rlm@1: case 0xb0: rlm@1: { rlm@1: // ADD SP, Imm rlm@1: int offset = (opcode & 127) << 2; rlm@1: if (opcode & 0x80) rlm@1: offset = -offset; rlm@1: reg[13].I += offset; rlm@1: } rlm@1: break; rlm@1: #define PUSH_REG(val, r) \ rlm@1: if (opcode & (val)) { \ rlm@1: CPUWriteMemory(address, reg[(r)].I); \ rlm@1: if (offset) \ rlm@1: clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \ rlm@1: else \ rlm@1: clockTicks += 1 + CPUUpdateTicksAccess32(address); \ rlm@1: offset = 1; \ rlm@1: address += 4; \ rlm@1: } rlm@1: case 0xb4: rlm@1: // PUSH {Rlist} rlm@1: { rlm@1: int offset = 0; rlm@1: u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff]; rlm@1: u32 address = temp & 0xFFFFFFFC; rlm@1: PUSH_REG(1, 0); rlm@1: PUSH_REG(2, 1); rlm@1: PUSH_REG(4, 2); rlm@1: PUSH_REG(8, 3); rlm@1: PUSH_REG(16, 4); rlm@1: PUSH_REG(32, 5); rlm@1: PUSH_REG(64, 6); rlm@1: PUSH_REG(128, 7); rlm@1: reg[13].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xb5: rlm@1: // PUSH {Rlist, LR} rlm@1: { rlm@1: int offset = 0; rlm@1: u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff]; rlm@1: u32 address = temp & 0xFFFFFFFC; rlm@1: PUSH_REG(1, 0); rlm@1: PUSH_REG(2, 1); rlm@1: PUSH_REG(4, 2); rlm@1: PUSH_REG(8, 3); rlm@1: PUSH_REG(16, 4); rlm@1: PUSH_REG(32, 5); rlm@1: PUSH_REG(64, 6); rlm@1: PUSH_REG(128, 7); rlm@1: PUSH_REG(256, 14); rlm@1: reg[13].I = temp; rlm@1: } rlm@1: break; rlm@1: #define POP_REG(val, r) \ rlm@1: if (opcode & (val)) { \ rlm@1: reg[(r)].I = CPUReadMemory(address); \ rlm@1: if (offset) \ rlm@1: clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); \ rlm@1: else \ rlm@1: clockTicks += 2 + CPUUpdateTicksAccess32(address); \ rlm@1: offset = 1; \ rlm@1: address += 4; \ rlm@1: } rlm@1: case 0xbc: rlm@1: // POP {Rlist} rlm@1: { rlm@1: int offset = 0; rlm@1: u32 address = reg[13].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[13].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: POP_REG(1, 0); rlm@1: POP_REG(2, 1); rlm@1: POP_REG(4, 2); rlm@1: POP_REG(8, 3); rlm@1: POP_REG(16, 4); rlm@1: POP_REG(32, 5); rlm@1: POP_REG(64, 6); rlm@1: POP_REG(128, 7); rlm@1: reg[13].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xbd: rlm@1: // POP {Rlist, PC} rlm@1: { rlm@1: int offset = 0; rlm@1: u32 address = reg[13].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[13].I + 4 + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: POP_REG(1, 0); rlm@1: POP_REG(2, 1); rlm@1: POP_REG(4, 2); rlm@1: POP_REG(8, 3); rlm@1: POP_REG(16, 4); rlm@1: POP_REG(32, 5); rlm@1: POP_REG(64, 6); rlm@1: POP_REG(128, 7); rlm@1: reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE); rlm@1: if (offset) rlm@1: clockTicks += CPUUpdateTicksAccessSeq32(address); rlm@1: else rlm@1: clockTicks += CPUUpdateTicksAccess32(address); rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: reg[13].I = temp; rlm@1: } rlm@1: break; rlm@1: #define THUMB_STM_REG(val, r, b) \ rlm@1: if (opcode & (val)) { \ rlm@1: CPUWriteMemory(address, reg[(r)].I); \ rlm@1: if (!offset) { \ rlm@1: reg[(b)].I = temp; \ rlm@1: clockTicks += 1 + CPUUpdateTicksAccess32(address); \ rlm@1: } else \ rlm@1: clockTicks += 1 + CPUUpdateTicksAccessSeq32(address); \ rlm@1: offset = 1; \ rlm@1: address += 4; \ rlm@1: } rlm@1: case 0xc0: rlm@1: { rlm@1: // STM R0!, {Rlist} rlm@1: u32 address = reg[0].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[0].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 0); rlm@1: THUMB_STM_REG(2, 1, 0); rlm@1: THUMB_STM_REG(4, 2, 0); rlm@1: THUMB_STM_REG(8, 3, 0); rlm@1: THUMB_STM_REG(16, 4, 0); rlm@1: THUMB_STM_REG(32, 5, 0); rlm@1: THUMB_STM_REG(64, 6, 0); rlm@1: THUMB_STM_REG(128, 7, 0); rlm@1: } rlm@1: break; rlm@1: case 0xc1: rlm@1: { rlm@1: // STM R1!, {Rlist} rlm@1: u32 address = reg[1].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[1].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 1); rlm@1: THUMB_STM_REG(2, 1, 1); rlm@1: THUMB_STM_REG(4, 2, 1); rlm@1: THUMB_STM_REG(8, 3, 1); rlm@1: THUMB_STM_REG(16, 4, 1); rlm@1: THUMB_STM_REG(32, 5, 1); rlm@1: THUMB_STM_REG(64, 6, 1); rlm@1: THUMB_STM_REG(128, 7, 1); rlm@1: } rlm@1: break; rlm@1: case 0xc2: rlm@1: { rlm@1: // STM R2!, {Rlist} rlm@1: u32 address = reg[2].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[2].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 2); rlm@1: THUMB_STM_REG(2, 1, 2); rlm@1: THUMB_STM_REG(4, 2, 2); rlm@1: THUMB_STM_REG(8, 3, 2); rlm@1: THUMB_STM_REG(16, 4, 2); rlm@1: THUMB_STM_REG(32, 5, 2); rlm@1: THUMB_STM_REG(64, 6, 2); rlm@1: THUMB_STM_REG(128, 7, 2); rlm@1: } rlm@1: break; rlm@1: case 0xc3: rlm@1: { rlm@1: // STM R3!, {Rlist} rlm@1: u32 address = reg[3].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[3].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 3); rlm@1: THUMB_STM_REG(2, 1, 3); rlm@1: THUMB_STM_REG(4, 2, 3); rlm@1: THUMB_STM_REG(8, 3, 3); rlm@1: THUMB_STM_REG(16, 4, 3); rlm@1: THUMB_STM_REG(32, 5, 3); rlm@1: THUMB_STM_REG(64, 6, 3); rlm@1: THUMB_STM_REG(128, 7, 3); rlm@1: } rlm@1: break; rlm@1: case 0xc4: rlm@1: { rlm@1: // STM R4!, {Rlist} rlm@1: u32 address = reg[4].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[4].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 4); rlm@1: THUMB_STM_REG(2, 1, 4); rlm@1: THUMB_STM_REG(4, 2, 4); rlm@1: THUMB_STM_REG(8, 3, 4); rlm@1: THUMB_STM_REG(16, 4, 4); rlm@1: THUMB_STM_REG(32, 5, 4); rlm@1: THUMB_STM_REG(64, 6, 4); rlm@1: THUMB_STM_REG(128, 7, 4); rlm@1: } rlm@1: break; rlm@1: case 0xc5: rlm@1: { rlm@1: // STM R5!, {Rlist} rlm@1: u32 address = reg[5].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[5].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 5); rlm@1: THUMB_STM_REG(2, 1, 5); rlm@1: THUMB_STM_REG(4, 2, 5); rlm@1: THUMB_STM_REG(8, 3, 5); rlm@1: THUMB_STM_REG(16, 4, 5); rlm@1: THUMB_STM_REG(32, 5, 5); rlm@1: THUMB_STM_REG(64, 6, 5); rlm@1: THUMB_STM_REG(128, 7, 5); rlm@1: } rlm@1: break; rlm@1: case 0xc6: rlm@1: { rlm@1: // STM R6!, {Rlist} rlm@1: u32 address = reg[6].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[6].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 6); rlm@1: THUMB_STM_REG(2, 1, 6); rlm@1: THUMB_STM_REG(4, 2, 6); rlm@1: THUMB_STM_REG(8, 3, 6); rlm@1: THUMB_STM_REG(16, 4, 6); rlm@1: THUMB_STM_REG(32, 5, 6); rlm@1: THUMB_STM_REG(64, 6, 6); rlm@1: THUMB_STM_REG(128, 7, 6); rlm@1: } rlm@1: break; rlm@1: case 0xc7: rlm@1: { rlm@1: // STM R7!, {Rlist} rlm@1: u32 address = reg[7].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[7].I + 4 * cpuBitsSet[opcode & 0xff]; rlm@1: int offset = 0; rlm@1: // store rlm@1: THUMB_STM_REG(1, 0, 7); rlm@1: THUMB_STM_REG(2, 1, 7); rlm@1: THUMB_STM_REG(4, 2, 7); rlm@1: THUMB_STM_REG(8, 3, 7); rlm@1: THUMB_STM_REG(16, 4, 7); rlm@1: THUMB_STM_REG(32, 5, 7); rlm@1: THUMB_STM_REG(64, 6, 7); rlm@1: THUMB_STM_REG(128, 7, 7); rlm@1: } rlm@1: break; rlm@1: #define THUMB_LDM_REG(val, r) \ rlm@1: if (opcode & (val)) { \ rlm@1: reg[(r)].I = CPUReadMemory(address); \ rlm@1: if (offset) \ rlm@1: clockTicks += 2 + CPUUpdateTicksAccessSeq32(address); \ rlm@1: else \ rlm@1: clockTicks += 2 + CPUUpdateTicksAccess32(address); \ rlm@1: offset = 1; \ rlm@1: address += 4; \ rlm@1: } rlm@1: case 0xc8: rlm@1: { rlm@1: // LDM R0!, {Rlist} rlm@1: u32 address = reg[0].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[0].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 1)) rlm@1: reg[0].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xc9: rlm@1: { rlm@1: // LDM R1!, {Rlist} rlm@1: u32 address = reg[1].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[1].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 2)) rlm@1: reg[1].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xca: rlm@1: { rlm@1: // LDM R2!, {Rlist} rlm@1: u32 address = reg[2].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[2].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 4)) rlm@1: reg[2].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xcb: rlm@1: { rlm@1: // LDM R3!, {Rlist} rlm@1: u32 address = reg[3].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[3].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 8)) rlm@1: reg[3].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xcc: rlm@1: { rlm@1: // LDM R4!, {Rlist} rlm@1: u32 address = reg[4].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[4].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 16)) rlm@1: reg[4].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xcd: rlm@1: { rlm@1: // LDM R5!, {Rlist} rlm@1: u32 address = reg[5].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[5].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 32)) rlm@1: reg[5].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xce: rlm@1: { rlm@1: // LDM R6!, {Rlist} rlm@1: u32 address = reg[6].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[6].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 64)) rlm@1: reg[6].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xcf: rlm@1: { rlm@1: // LDM R7!, {Rlist} rlm@1: u32 address = reg[7].I & 0xFFFFFFFC; rlm@1: u32 temp = reg[7].I + 4 * cpuBitsSet[opcode & 0xFF]; rlm@1: int offset = 0; rlm@1: // load rlm@1: THUMB_LDM_REG(1, 0); rlm@1: THUMB_LDM_REG(2, 1); rlm@1: THUMB_LDM_REG(4, 2); rlm@1: THUMB_LDM_REG(8, 3); rlm@1: THUMB_LDM_REG(16, 4); rlm@1: THUMB_LDM_REG(32, 5); rlm@1: THUMB_LDM_REG(64, 6); rlm@1: THUMB_LDM_REG(128, 7); rlm@1: if (!(opcode & 128)) rlm@1: reg[7].I = temp; rlm@1: } rlm@1: break; rlm@1: case 0xd0: rlm@1: // BEQ offset rlm@1: if (Z_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd1: rlm@1: // BNE offset rlm@1: if (!Z_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd2: rlm@1: // BCS offset rlm@1: if (C_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd3: rlm@1: // BCC offset rlm@1: if (!C_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd4: rlm@1: // BMI offset rlm@1: if (N_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd5: rlm@1: // BPL offset rlm@1: if (!N_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd6: rlm@1: // BVS offset rlm@1: if (V_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd7: rlm@1: // BVC offset rlm@1: if (!V_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd8: rlm@1: // BHI offset rlm@1: if (C_FLAG && !Z_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xd9: rlm@1: // BLS offset rlm@1: if (!C_FLAG || Z_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xda: rlm@1: // BGE offset rlm@1: if (N_FLAG == V_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xdb: rlm@1: // BLT offset rlm@1: if (N_FLAG != V_FLAG) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xdc: rlm@1: // BGT offset rlm@1: if (!Z_FLAG && (N_FLAG == V_FLAG)) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xdd: rlm@1: // BLE offset rlm@1: if (Z_FLAG || (N_FLAG != V_FLAG)) rlm@1: { rlm@1: reg[15].I += ((s8)(opcode & 0xFF)) << 1; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: clockTicks = 3; rlm@1: } rlm@1: break; rlm@1: case 0xdf: rlm@1: // SWI #comment rlm@1: CPUSoftwareInterrupt(opcode & 0xFF); rlm@1: break; rlm@1: case 0xe0: rlm@1: case 0xe1: rlm@1: case 0xe2: rlm@1: case 0xe3: rlm@1: case 0xe4: rlm@1: case 0xe5: rlm@1: case 0xe6: rlm@1: case 0xe7: rlm@1: { rlm@1: // B offset rlm@1: int offset = (opcode & 0x3FF) << 1; rlm@1: if (opcode & 0x0400) rlm@1: offset |= 0xFFFFF800; rlm@1: reg[15].I += offset; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: } rlm@1: break; rlm@1: case 0xf0: rlm@1: case 0xf1: rlm@1: case 0xf2: rlm@1: case 0xf3: rlm@1: { rlm@1: // BLL #offset rlm@1: int offset = (opcode & 0x7FF); rlm@1: reg[14].I = reg[15].I + (offset << 12); rlm@1: } rlm@1: break; rlm@1: case 0xf4: rlm@1: case 0xf5: rlm@1: case 0xf6: rlm@1: case 0xf7: rlm@1: { rlm@1: // BLL #offset rlm@1: int offset = (opcode & 0x7FF); rlm@1: reg[14].I = reg[15].I + ((offset << 12) | 0xFF800000); rlm@1: } rlm@1: break; rlm@1: case 0xf8: rlm@1: case 0xf9: rlm@1: case 0xfa: rlm@1: case 0xfb: rlm@1: case 0xfc: rlm@1: case 0xfd: rlm@1: case 0xfe: rlm@1: case 0xff: rlm@1: { rlm@1: // BLH #offset rlm@1: int offset = (opcode & 0x7FF); rlm@1: u32 temp = reg[15].I - 2; rlm@1: reg[15].I = (reg[14].I + (offset << 1)) & 0xFFFFFFFE; rlm@1: armNextPC = reg[15].I; rlm@1: reg[15].I += 2; rlm@1: reg[14].I = temp | 1; rlm@1: } rlm@1: break; rlm@1: #ifdef BKPT_SUPPORT rlm@1: case 0xbe: rlm@1: // BKPT #comment rlm@1: extern void (*dbgSignal)(int, int); rlm@1: reg[15].I -= 2; rlm@1: armNextPC -= 2; rlm@1: dbgSignal(5, opcode & 255); rlm@1: return; rlm@1: #endif rlm@1: case 0xb1: rlm@1: case 0xb2: rlm@1: case 0xb3: rlm@1: case 0xb6: rlm@1: case 0xb7: rlm@1: case 0xb8: rlm@1: case 0xb9: rlm@1: case 0xba: rlm@1: case 0xbb: rlm@1: #ifndef BKPT_SUPPORT rlm@1: case 0xbe: rlm@1: #endif rlm@1: case 0xbf: rlm@1: case 0xde: rlm@1: default: rlm@1: unknown_thumb: rlm@1: #ifdef GBA_LOGGING rlm@1: if (systemVerbose & VERBOSE_UNDEFINED) rlm@1: log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC - 2); rlm@1: #endif rlm@1: CPUUndefinedException(); rlm@1: break; rlm@1: }