diff options
Diffstat (limited to 'plugins/ao/eng_dsf/arm7i.c')
-rw-r--r-- | plugins/ao/eng_dsf/arm7i.c | 1339 |
1 files changed, 1339 insertions, 0 deletions
diff --git a/plugins/ao/eng_dsf/arm7i.c b/plugins/ao/eng_dsf/arm7i.c new file mode 100644 index 00000000..cb6c7106 --- /dev/null +++ b/plugins/ao/eng_dsf/arm7i.c @@ -0,0 +1,1339 @@ +// +// ARM7 processor emulator - interpreter core +// version 1.6 / 2008-02-16 +// (c) Radoslaw Balcewicz +// + +#include "arm7.h" +#include "arm7i.h" + + //-------------------------------------------------------------------------- + // definitions and macros + + /** PC is being incremented after every instruction fetch, so we adjust for + that on all stores and jumps. */ +#define PC_ADJUSTMENT (-4) + + /** Memory access routines. */ +#include "arm7memil.c" + + /** Bit shifts compatible with IA32. */ +#define SHL(w, k) (((UINT32)(w)) << (k)) +#define SHR(w, k) (((UINT32)(w)) >> (k)) +#define SAR(w, k) (((INT32)(w)) >> (k)) +#define ROR(w, k) (SHR (w, k) | SHL (w, 32 - (k))) + + /** Byte rotation for unaligned 32-bit read. */ +#define RBOD(w, i) (ROR (w, (i) * 8)) + + /** Data processing macros. */ +#define NEG(i) ((i) & (1 << 31)) +#define POS(i) (~(i) & (1 << 31)) +#define ADDCARRY(a, b, c) \ + ((NEG (a) & NEG (b)) |\ + (NEG (a) & POS (c)) |\ + (NEG (b) & POS (c))) ? 1 : 0; +#define ADDOVERFLOW(a, b, c) \ + ((NEG (a) & NEG (b) & POS (c)) |\ + (POS (a) & POS (b) & NEG (c))) ? 1 : 0; +#define SUBCARRY(a, b, c) \ + ((NEG (a) & POS (b)) |\ + (NEG (a) & POS (c)) |\ + (POS (b) & POS (c))) ? 1 : 0; +#define SUBOVERFLOW(a, b, c)\ + ((NEG (a) & POS (b) & POS (c)) |\ + (POS (a) & NEG (b) & NEG (c))) ? 1 : 0; + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // private functions + + /** Condition EQ. */ +static int R_WEQ (void); + /** Condition NE. */ +static int R_WNE (void); + /** Condition CS. */ +static int R_WCS (void); + /** Condition CC. */ +static int R_WCC (void); + /** Condition MI. */ +static int R_WMI (void); + /** Condition PL. */ +static int R_WPL (void); + /** Condition VS. */ +static int R_WVS (void); + /** Condition VC. */ +static int R_WVC (void); + /** Condition HI. */ +static int R_WHI (void); + /** Condition LS. */ +static int R_WLS (void); + /** Condition GE. */ +static int R_WGE (void); + /** Condition LT. */ +static int R_WLT (void); + /** Condition GT. */ +static int R_WGT (void); + /** Condition LE. */ +static int R_WLE (void); + /** Condition AL. */ +static int R_WAL (void); + /** Undefined condition. */ +static int R_Wxx (void); + + /** Calculates barrel shifter output. */ +static UINT32 WyliczPrzes (void); + /** Logical shift left. */ +static UINT32 LSL_x (UINT32 w, int i); + /** Logical shift right. */ +static UINT32 LSR_x (UINT32 w, int i); + /** Arithmetic shift right. */ +static UINT32 ASR_x (UINT32 w, int i); + /** Rotate right. */ +static UINT32 ROR_x (UINT32 w, int i); + /** Rotate right extended. */ +static UINT32 RRX_1 (UINT32 w); + + /** Group 00x opcodes. */ +static void R_G00x (void); + /** Multiply instructions. */ +static void R_MUL_MLA (void); + /** Single data swap. */ +static void R_SWP (void); + /** PSR Transfer. */ +static void R_PSR (void); + /** Data processing instructions. */ +static void R_DP (void); + /** Data processing result writeback. */ +static void R_WynikDP (ARM7_REG w); + /** Data processing flags writeback. */ +static void R_FlagiDP (ARM7_REG w); + /** Single data transfer. */ +static void R_SDT (void); + /** Rozkaz "Undefined". */ +static void R_Und (); + /** Block Data Transfer. */ +static void R_BDT (); + /** Block load instructions. */ +static void R_LDM (int Rn, UINT32 adres); + /** Block store instructions. */ +static void R_STM (int Rn, UINT32 adres); + /** Branch/Branch with link. */ +static void R_B_BL (void); + /** Group 110 opcodes. */ +static void R_G110 (void); + /** Group 111 opcodes. */ +static void R_G111 (void); + +#ifdef ARM7_THUMB + /** Halfword and Signed Data Transfer. */ +static void R_HSDT (); +#endif + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + // private data + + /** Flag testing functions for conditional execution. */ +static int (*s_tabWar [16]) (void) = {R_WEQ, R_WNE, R_WCS, R_WCC, R_WMI, R_WPL, + R_WVS, R_WVC, R_WHI, R_WLS, R_WGE, R_WLT, R_WGT, R_WLE, R_WAL, R_Wxx}; + /** Handler table for instruction groups. */ +static void (*s_tabGrup [8]) (void) = {R_G00x, R_G00x, R_SDT, R_SDT, R_BDT, + R_B_BL, R_G110, R_G111}; + /** Data processing instructions split to arithmetic and logical. */ +static int s_tabAL [16] = {FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, + FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE}; + + /** Cycles it took for current instruction to complete. */ +static int s_cykle; + //-------------------------------------------------------------------------- + + + // public functions + + + //-------------------------------------------------------------------------- + /** Single step, returns number of burned cycles. */ +int ARM7i_Step () + { + ARM7.kod = arm7_read_32 (ARM7.Rx [ARM7_PC] & ~3); + + // we increment PC here, and if there's a load from memory it will simply + // overwrite it (all PC modyfing code should be aware of this) + ARM7.Rx [ARM7_PC] += 4; + s_cykle = 2; + // condition test and group selection + if (s_tabWar [(ARM7.kod >> 28) & 15] ()) + s_tabGrup [(ARM7.kod >> 25) & 7] (); + return s_cykle; + } + //-------------------------------------------------------------------------- + + + // private functions + + + //-------------------------------------------------------------------------- + /** Condition EQ. */ +int R_WEQ () + { + // "Z set" + return ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_Z; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition NE. */ +int R_WNE () + { + // "Z clear" + return !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_Z); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition CS. */ +int R_WCS () + { + // "C set" + return ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition CC. */ +int R_WCC () + { + // "C clear" + return !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition MI. */ +int R_WMI () + { + // "N set" + return ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_N; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition PL. */ +int R_WPL () + { + // "N clear" + return !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_N); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition VS. */ +int R_WVS () + { + // "V set" + return ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_V; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition VC. */ +int R_WVC () + { + // "V clear" + return !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_V); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition HI. */ +int R_WHI () + { + // "C set and Z clear" + return (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) &&\ + !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_Z); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition LS. */ +int R_WLS () + { + // "C clear or Z set" + return !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) ||\ + (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_Z); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition GE. */ +int R_WGE () + { + // "N equals V" + return (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_N) &&\ + (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_V) || !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_N) &&\ + !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_V); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition LT. */ +int R_WLT () + { + // "N not equal to V" + return !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_N) &&\ + (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_V) || (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_N) &&\ + !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_V); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition GT. */ +int R_WGT () + { + // "Z clear AND (N equals V)" + return !(ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_Z) && R_WGE (); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition LE. */ +int R_WLE () + { + // "Z set OR (N not equal to V)" + return (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_Z) || R_WLT (); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Condition AL. */ +int R_WAL () + { + // "(ignored)" + return TRUE; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Undefined condition. */ +int R_Wxx () + { + // behaviour undefined + return FALSE; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Calculates barrel shifter output. */ +UINT32 WyliczPrzes () + { + int Rm, Rs, i; + UINT32 w; + + // Rm is source for the shift operation + Rm = ARM7.kod & 15; + + if (ARM7.kod & (1 << 4)) + { + s_cykle++; + // shift count in Rs (8 lowest bits) + if (Rm != ARM7_PC) + w = ARM7.Rx [Rm]; + else + w = (ARM7.Rx [ARM7_PC] & ~3) + 12 + PC_ADJUSTMENT; + // Rs can't be PC + Rs = (ARM7.kod >> 8) & 15; + i = (UINT8)ARM7.Rx [Rs]; + if (i == 0) + { + // special case + ARM7.carry = (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) ? 1 : 0; + return w; + } + + switch ((ARM7.kod >> 5) & 3) + { + case 0: + w = LSL_x (w, i); + break; + case 1: + w = LSR_x (w, i); + break; + case 2: + w = ASR_x (w, i); + break; + case 3: + w = ROR_x (w, i); + break; + } + } + else + { + // shift count as immediate in opcode + if (Rm != ARM7_PC) + w = ARM7.Rx [Rm]; + else + w = (ARM7.Rx [ARM7_PC] & ~3) + 8 + PC_ADJUSTMENT; + i = (ARM7.kod >> 7) & 31; + + switch ((ARM7.kod >> 5) & 3) + { + case 0: + w = LSL_x (w, i); + break; + case 1: + if (i > 0) + w = LSR_x (w, i); + else + w = LSR_x (w, 32); + break; + case 2: + if (i > 0) + w = ASR_x (w, i); + else + w = ASR_x (w, 32); + break; + case 3: + if (i > 0) + w = ROR_x (w, i); + else + w = RRX_1 (w); + break; + } + } + return w; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Logical shift left. */ +UINT32 LSL_x (UINT32 w, int i) +{ + // LSL #0 copies C into carry out and returns unmodified value + if (i == 0) + { + ARM7.carry = (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) ? 1 : 0; + return w; + } + // LSL #32 copies LSB to carry out and returns zero + if (i == 32) + { + ARM7.carry = w & 1; + return 0; + } + // LSL > #32 returns zero for both carry and output + if (i > 32) + { + ARM7.carry = 0; + return 0; + } + // normal shift + ARM7.carry = (w & (1 << (32 - i))) ? 1 : 0; + w = SHL (w, i); + return w; +} + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Logical shift right. */ +UINT32 LSR_x (UINT32 w, int i) +{ + // LSR #32 copies MSB to carry out and returns zero + if (i == 32) + { + ARM7.carry = (w & (1 << 31)) ? 1 : 0; + return 0; + } + // LSR > #32 returns zero for both carry and output + if (i > 32) + { + ARM7.carry = 0; + return 0; + } + // normal shift + ARM7.carry = (w & (1 << (i - 1))) ? 1 : 0; + w = SHR (w, i); + return w; +} + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Arithmetic shift right. */ +UINT32 ASR_x (UINT32 w, int i) +{ + // ASR >= #32 carry out and output value depends on the minus sign + if (i >= 32) + { + if (w & (1 << 31)) + { + ARM7.carry = 1; + return ~0; + } + + ARM7.carry = 0; + return 0; + } + // normal shift + ARM7.carry = (w & (1 << (i - 1))) ? 1 : 0; + w = SAR (w, i); + return w; +} + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Rotate right. */ +UINT32 ROR_x (UINT32 w, int i) +{ + // mask count to [0; 31] + i &= 0x1f; + // ROR #32,#64,etc. copies MSB into carry out and returns unmodified value + if (i == 0) + { + ARM7.carry = (w & (1 << 31)) ? 1 : 0; + return w; + } + // normal shift + ARM7.carry = (w & (1 << (i-1))) ? 1 : 0; + w = ROR (w, i); + return w; +} + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Rotate right extended. */ +UINT32 RRX_1 (UINT32 w) + { + // same as RCR by 1 in IA32 + ARM7.carry = w & 1; + return (w >> 1) | ((ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) << 2); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Group 00x opcodes. */ +void R_G00x () + { +#ifdef ARM7_THUMB + // 24 constant bits + if ((ARM7.kod & 0x0ffffff0) == 0x012fff10) // BX - branch with possible mode transfer + { + #ifdef ARM7_THUMB + int Rn = ARM7.Rx[ARM7.kod & 0xf]; + + // switching to Thumb mode? + if (Rn & 1) + { + ARM7_SetCPSR(ARM7.Rx[ARM7_CPSR] | ARM7_CPSR_T); + } + + ARM7.Rx[ARM7_PC] = Rn & ~1; + #endif + } + // 15 constant bits + else if ((ARM7.kod & 0x0fb00ff0) == 0x01000090) + R_SWP (); + // 10 constant bits + else if ((ARM7.kod & 0x0fc000f0) == 0x00000090) + R_MUL_MLA (); + // 10 constant bits + else if ((ARM7.kod & 0x0e400f90) == 0x00000090) + R_HSDT (); + // 9 constant bits + else if ((ARM7.kod & 0x0f8000f0) == 0x00800090) + { +// logerror("G00x / Multiply long\n"); + } + // 6 constant bits + else if ((ARM7.kod & 0x0e400090) == 0x00400090) + R_HSDT (); + // 2 constant bits + else + { + if ((ARM7.kod & 0x01900000) == 0x01000000) + // TST, TEQ, CMP & CMN without S bit are "PSR Transfer" + R_PSR (); + else + // the rest is "Data processing" + R_DP (); + } +#else + if ((ARM7.kod & 0x03b00090) == 0x01000090) + R_SWP (); + else if ((ARM7.kod & 0x03c00090) == 0x00000090) + R_MUL_MLA (); + else + { + if ((ARM7.kod & 0x01900000) == 0x01000000) + // TST, TEQ, CMP & CMN without S bit are "PSR Transfer" + R_PSR (); + else + // the rest is "Data processing" + R_DP (); + } +#endif + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Single data swap. */ +void R_SWP () + { + int Rn, Rd, Rm; + UINT32 adres, w; + +#define BIT_B (ARM7.kod & (1 << 21)) + + s_cykle += 4; + // none of these can be PC + Rn = (ARM7.kod >> 16) & 15; + Rd = (ARM7.kod >> 12) & 15; + Rm = ARM7.kod & 15; + adres = ARM7.Rx [Rn]; + + if (BIT_B) + { + // "byte" + w = arm7_read_8 (adres); + arm7_write_8 (adres, (UINT8)ARM7.Rx [Rm]); + } + else + { + // "word" + w = RBOD (arm7_read_32 (adres & ~3), adres & 3); + arm7_write_32 (adres & ~3, ARM7.Rx [Rm]); + } + ARM7.Rx [Rd] = w; + +#undef BIT_B + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Multiply instructions. */ +void R_MUL_MLA () + { + int Rm, Rs, Rn, Rd; + UINT32 wynik; + +#define BIT_A (ARM7.kod & (1 << 21)) +#define BIT_S (ARM7.kod & (1 << 20)) + + s_cykle += 2; + // none of these can be PC, also Rd != Rm + Rd = (ARM7.kod >> 16) & 15, + Rs = (ARM7.kod >> 8) & 15, + Rm = ARM7.kod & 15; + + // MUL + wynik = ARM7.Rx [Rm] * ARM7.Rx [Rs]; + if (BIT_A) + { + // MLA + Rn = (ARM7.kod >> 12) & 15; + wynik += ARM7.Rx [Rn]; + } + ARM7.Rx [Rd] = wynik; + + if (BIT_S) + { + // V remains unchanged, C is undefined + ARM7.Rx [ARM7_CPSR] &= ~(ARM7_CPSR_N | ARM7_CPSR_Z); + if (wynik == 0) + ARM7.Rx [ARM7_CPSR] |= ARM7_CPSR_Z; + ARM7.Rx [ARM7_CPSR] |= wynik & 0x80000000; + } + +#undef BIT_S +#undef BIT_A + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** PSR Transfer. */ +void R_PSR () + { + int Rd, Rm; + UINT32 w, arg; + +#define BIT_I (ARM7.kod & (1 << 25)) +#define BIT_P (ARM7.kod & (1 << 22)) + + // none of the registers involved can be PC + + if (ARM7.kod & (1 << 21)) + { + // MSR + Rm = ARM7.kod & 15; + if (BIT_I) + // immediate (lower 12 bits) + arg = ROR (ARM7.kod & 0xff, ((ARM7.kod >> 8) & 0xf) * 2); + else + // register + arg = ARM7.Rx [Rm]; + + // decode mask bits + if (BIT_P) + { + w = ARM7.Rx [ARM7_SPSR]; + if (ARM7_CPSR_M (ARM7.Rx [ARM7_CPSR]) > ARM7_CPSR_M_usr &&\ + ARM7_CPSR_M (ARM7.Rx [ARM7_CPSR]) < ARM7_CPSR_M_sys) + { + if (ARM7.kod & (1 << 16)) + w = (w & 0xffffff00) | (arg & 0x000000ff); + if (ARM7.kod & (1 << 17)) + w = (w & 0xffff00ff) | (arg & 0x0000ff00); + if (ARM7.kod & (1 << 18)) + w = (w & 0xff00ffff) | (arg & 0x00ff0000); + if (ARM7.kod & (1 << 19)) + // ARMv5E should have 0xf8000000 argument mask + w = (w & 0x00ffffff) | (arg & 0xf0000000); + } + // force valid mode + w |= 0x10; + ARM7.Rx [ARM7_SPSR] = w; + } + else + { + w = ARM7.Rx [ARM7_CPSR]; + // only flags can be changed in User mode + if (ARM7_CPSR_M (ARM7.Rx [ARM7_CPSR]) != ARM7_CPSR_M_usr) + { + if (ARM7.kod & (1 << 16)) + w = (w & 0xffffff00) | (arg & 0x000000ff); + if (ARM7.kod & (1 << 17)) + w = (w & 0xffff00ff) | (arg & 0x0000ff00); + if (ARM7.kod & (1 << 18)) + w = (w & 0xff00ffff) | (arg & 0x00ff0000); + } + if (ARM7.kod & (1 << 19)) + // ARMv5E should have 0xf8000000 argument mask + w = (w & 0x00ffffff) | (arg & 0xf0000000); + // force valid mode + w |= 0x10; + ARM7_SetCPSR (w); + } + } + else + { + // MRS + Rd = (ARM7.kod >> 12) & 15; + if (BIT_P) + ARM7.Rx [Rd] = ARM7.Rx [ARM7_SPSR]; + else + ARM7.Rx [Rd] = ARM7.Rx [ARM7_CPSR]; + } + +#undef BIT_P +#undef BIT_I + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Data processing instructions. */ +void R_DP () + { + int Rn; + ARM7_REG arg1, arg2, w; + +#define BIT_I (ARM7.kod & (1 << 25)) + + // Rn can be PC, so we need to account for that + Rn = (ARM7.kod >> 16) & 15; + + if (BIT_I) + { + if (Rn != ARM7_PC) + arg1 = ARM7.Rx [Rn]; + else + arg1 = (ARM7.Rx [ARM7_PC] & ~3) + 8 + PC_ADJUSTMENT; + // immediate in lowest 12 bits + arg2 = ROR (ARM7.kod & 0xff, ((ARM7.kod >> 8) & 0xf) * 2); + // preload carry out from C + ARM7.carry = (ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) ? 1 : 0; + } + else + { + if (Rn != ARM7_PC) + arg1 = ARM7.Rx [Rn]; + else + // register or immediate shift? + if (ARM7.kod & (1 << 4)) + arg1 = (ARM7.Rx [ARM7_PC] & ~3) + 12 + PC_ADJUSTMENT; + else + arg1 = (ARM7.Rx [ARM7_PC] & ~3) + 8 + PC_ADJUSTMENT; + // calculate in barrel shifter + arg2 = WyliczPrzes (); + } + + // decode instruction type + switch ((ARM7.kod >> 21) & 15) + { + case 0: + // AND + R_WynikDP (arg1 & arg2); + break; + + case 1: + // EOR + R_WynikDP (arg1 ^ arg2); + break; + + case 2: + // SUB + w = arg1 - arg2; + ARM7.carry = SUBCARRY (arg1, arg2, w); + ARM7.overflow = SUBOVERFLOW (arg1, arg2, w); + R_WynikDP (w); + break; + + case 3: + // RSB + w = arg2 - arg1; + ARM7.carry = SUBCARRY (arg2, arg1, w); + ARM7.overflow = SUBOVERFLOW (arg2, arg1, w); + R_WynikDP (w); + break; + + case 4: + // ADD + w = arg1 + arg2; + ARM7.carry = ADDCARRY (arg1, arg2, w); + ARM7.overflow = ADDOVERFLOW (arg1, arg2, w); + R_WynikDP (w); + break; + + case 5: + // ADC + w = arg1 + arg2 + ((ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) ? 1 : 0); + ARM7.carry = ADDCARRY (arg1, arg2, w); + ARM7.overflow = ADDOVERFLOW (arg1, arg2, w); + R_WynikDP (w); + break; + + case 6: + // SBC + w = arg1 - arg2 - ((ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) ? 0 : 1); + ARM7.carry = SUBCARRY (arg1, arg2, w); + ARM7.overflow = SUBOVERFLOW (arg1, arg2, w); + R_WynikDP (w); + break; + + case 7: + // RSC + w = arg2 - arg1 - ((ARM7.Rx [ARM7_CPSR] & ARM7_CPSR_C) ? 0 : 1); + ARM7.carry = SUBCARRY (arg2, arg1, w); + ARM7.overflow = SUBOVERFLOW (arg2, arg1, w); + R_WynikDP (w); + break; + + case 8: + // TST + R_FlagiDP (arg1 & arg2); + break; + + case 9: + // TEQ + R_FlagiDP (arg1 ^ arg2); + break; + + case 10: + // CMP + w = arg1 - arg2; + ARM7.carry = SUBCARRY (arg1, arg2, w); + ARM7.overflow = SUBOVERFLOW (arg1, arg2, w); + R_FlagiDP (w); + break; + + case 11: + // CMN + w = arg1 + arg2; + ARM7.carry = ADDCARRY (arg1, arg2, w); + ARM7.overflow = ADDOVERFLOW (arg1, arg2, w); + R_FlagiDP (w); + break; + + case 12: + // ORR + R_WynikDP (arg1 | arg2); + break; + + case 13: + // MOV + R_WynikDP (arg2); + break; + + case 14: + // BIC + R_WynikDP (arg1 & ~arg2); + break; + + case 15: + // MVN + R_WynikDP (~arg2); + break; + } + +#undef BIT_I + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Data processing result writeback. */ +void R_WynikDP (ARM7_REG w) + { + int Rd; + +#define BIT_S (ARM7.kod & (1 << 20)) + + Rd = (ARM7.kod >> 12) & 15; + ARM7.Rx [Rd] = w; + if (BIT_S) + { + if (Rd == ARM7_PC) + { + s_cykle += 4; + // copy current SPSR to CPSR + ARM7_SetCPSR (ARM7.Rx [ARM7_SPSR]); + } + else + // save new flags + R_FlagiDP (w); + } + +#undef BIT_S + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Data processing flags writeback. */ +void R_FlagiDP (ARM7_REG w) + { + // arithmetic or logical instruction? + if (s_tabAL [(ARM7.kod >> 21) & 15]) + { + ARM7.Rx [ARM7_CPSR] &= ~(ARM7_CPSR_N | ARM7_CPSR_Z | ARM7_CPSR_C |\ + ARM7_CPSR_V); + ARM7.Rx [ARM7_CPSR] |= ARM7.overflow << 28; + } + else + ARM7.Rx [ARM7_CPSR] &= ~(ARM7_CPSR_N | ARM7_CPSR_Z | ARM7_CPSR_C); + ARM7.Rx [ARM7_CPSR] |= ARM7.carry << 29; + if (w == 0) + ARM7.Rx [ARM7_CPSR] |= ARM7_CPSR_Z; + ARM7.Rx [ARM7_CPSR] |= w & 0x80000000; + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Single data transfer. */ +void R_SDT (void) + { + int Rn, Rd, offset; + UINT32 adres, w = 0; + +#define BIT_I (ARM7.kod & (1 << 25)) +#define BIT_P (ARM7.kod & (1 << 24)) +#define BIT_U (ARM7.kod & (1 << 23)) +#define BIT_B (ARM7.kod & (1 << 22)) +#define BIT_W (ARM7.kod & (1 << 21)) +#define BIT_L (ARM7.kod & (1 << 20)) + + if (BIT_I && (ARM7.kod & (1 << 4))) + { + R_Und (); + return; + } + + Rn = (ARM7.kod >> 16) & 15, + Rd = (ARM7.kod >> 12) & 15; + if (Rn != ARM7_PC) + adres = ARM7.Rx [Rn]; + else + adres = ARM7.Rx [ARM7_PC] & ~3; + if (!BIT_L) + if (Rd != ARM7_PC) + w = ARM7.Rx [Rd]; + else + w = (ARM7.Rx [ARM7_PC] & ~3) + 12 + PC_ADJUSTMENT; + + if (BIT_I) + // calculate value in barrel shifter + offset = WyliczPrzes (); + else + // immediate in lowest 12 bits + offset = ARM7.kod & 0xfff; + + if (!BIT_U) + offset = -offset; + if (BIT_P) + { + // "pre-index" + adres += offset; + if (BIT_W) + // "write-back" + ARM7.Rx [Rn] = adres; + } + else + // "post-index" + ARM7.Rx [Rn] += offset; + if (Rn == ARM7_PC) + adres += 8 + PC_ADJUSTMENT; + + if (BIT_L) + { + s_cykle += 3; + // "load" + if (BIT_B) + // "byte" + ARM7.Rx [Rd] = arm7_read_8 (adres); + else + // "word" + ARM7.Rx [Rd] = RBOD (arm7_read_32 (adres & ~3), adres & 3); + } + else + { + s_cykle += 2; + // "store" + if (BIT_B) + // "byte" + arm7_write_8 (adres, (UINT8)w); + else + // "word" + arm7_write_32 (adres & ~3, w); + } + +#undef BIT_L +#undef BIT_W +#undef BIT_B +#undef BIT_U +#undef BIT_P +#undef BIT_I + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Undefined. */ +void R_Und () + { + UINT32 sr = ARM7.Rx [ARM7_CPSR]; + ARM7_SetCPSR (ARM7_CPSR_MX (sr, ARM7_CPSR_M_und) | ARM7_CPSR_I); + ARM7.Rx [ARM7_SPSR] = sr; + ARM7.Rx [ARM7_LR] = ARM7.Rx [ARM7_PC] + 4; + ARM7.Rx [ARM7_PC] = 0x00000004; + } + //-------------------------------------------------------------------------- + +#define BIT_U (ARM7.kod & (1 << 23)) +#define BIT_S (ARM7.kod & (1 << 22)) + //-------------------------------------------------------------------------- + /** Block Data Transfer. */ +void R_BDT () + { + int Rn, usr = FALSE; + UINT32 adres; + ARM7_REG cpsr = 0; + +#define BIT_L (ARM7.kod & (1 << 20)) + + // Rn can't be PC + Rn = (ARM7.kod >> 16) & 15; + adres = ARM7.Rx [Rn]; + + // transfer in User mode + if (BIT_S) + if (!BIT_L || !(ARM7.kod & (1 << ARM7_PC))) + usr = TRUE; + + if (usr) + { +//EMU_BLAD (BLAD_WEWNETRZNY, "BDT: user transfer"); + cpsr = ARM7.Rx [ARM7_CPSR]; + ARM7_SetCPSR (ARM7_CPSR_MX (cpsr, ARM7_CPSR_M_usr)); + } + + if (BIT_L) + // "load" + R_LDM (Rn, adres); + else + // "store" + R_STM (Rn, adres); + + if (usr) + ARM7_SetCPSR (cpsr); + +#undef BIT_L + } + //-------------------------------------------------------------------------- + +#define BIT_P (ARM7.kod & (1 << 24)) +#define BIT_W (ARM7.kod & (1 << 21)) + //-------------------------------------------------------------------------- + /** Block load instructions. */ +void R_LDM (int Rn, UINT32 adres) + { + int i, n, sp; + + // count registers on the list + for (i = 0, n = 0; i < 16; i++) + if (ARM7.kod & (1 << i)) + n++; + s_cykle += n * 2 + 1; + + n <<= 2; + // transfer type + sp = BIT_P; + if (!BIT_U) + { + // "down" + n = -n; + adres += n; + sp = !sp; + } + if (BIT_W) + // "write-back" + ARM7.Rx [Rn] += n; + + // for all registers in mask + if (sp) + for (i = 0; i < 16; i++) + { + if (!(ARM7.kod & (1 << i))) + continue; + adres += 4; + ARM7.Rx [i] = arm7_read_32 (adres); + } + else + for (i = 0; i < 16; i++) + { + if (!(ARM7.kod & (1 << i))) + continue; + ARM7.Rx [i] = arm7_read_32 (adres); + adres += 4; + } + + // special case - mode change when PC is written + if ((ARM7.kod & (1 << ARM7_PC)) && BIT_S) + ARM7_SetCPSR (ARM7.Rx [ARM7_SPSR]); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Block store instructions. */ +void R_STM (int Rn, UINT32 adres) + { + int i, n, p, sp; + + // count registers on the list and remember the first one + for (i = 0, n = 0, p = -1; i < 16; i++) + if (ARM7.kod & (1 << i)) + { + n++; + if (p < 0) + p = i; + } + s_cykle += n * 2; + + n <<= 2; + // transfer type + sp = BIT_P; + if (!BIT_U) + { + // "down" + n = -n; + adres += n; + sp = !sp; + } + // if base register is not the first one to transfer, writeback happens here + if (BIT_W && Rn != p) + // "write-back" + ARM7.Rx [Rn] += n; + + // registers R0-R14 + if (sp) + for (i = 0; i < 15; i++) + { + if (!(ARM7.kod & (1 << i))) + continue; + adres += 4; + arm7_write_32 (adres, ARM7.Rx [i]); + } + else + for (i = 0; i < 15; i++) + { + if (!(ARM7.kod & (1 << i))) + continue; + arm7_write_32 (adres, ARM7.Rx [i]); + adres += 4; + } + + // PC is a special case + if (ARM7.kod & (1 << ARM7_PC)) + { + if (sp) + { + adres += 4; + arm7_write_32 (adres, (ARM7.Rx [ARM7_PC] & ~3) + 12 + PC_ADJUSTMENT); + } + else + { + arm7_write_32 (adres, (ARM7.Rx [ARM7_PC] & ~3) + 12 + PC_ADJUSTMENT); + adres += 4; + } + } + + // if base register is the first one to transfer, writeback happens here + if (BIT_W && Rn == p) + // "write-back" + ARM7.Rx [Rn] += n; + } + //-------------------------------------------------------------------------- +#undef BIT_W +#undef BIT_P +#undef BIT_S +#undef BIT_U + + //-------------------------------------------------------------------------- + /** Branch/Branch with link. */ +void R_B_BL () + { + INT32 offset; + +#define BIT_L (ARM7.kod & (1 << 24)) + + s_cykle += 4; + offset = (ARM7.kod & 0x00ffffff) << 2; + if (offset & 0x02000000) + offset |= 0xfc000000; + offset += 8 + PC_ADJUSTMENT; + if (BIT_L) + // "Branch with link" + ARM7.Rx [ARM7_LR] = (ARM7.Rx [ARM7_PC] & ~3) + 4 + PC_ADJUSTMENT; + // "Branch" + ARM7.Rx [ARM7_PC] += offset; + +#undef BIT_L + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Group 110 opcodes. */ +void R_G110 () + { +// logerror("ARM7: G110 / Coprocessor data transfer\n"); + } + //-------------------------------------------------------------------------- + + //-------------------------------------------------------------------------- + /** Group 111 opcodes. */ +void R_G111 () + { + if ((ARM7.kod & 0xf0000000) == 0xe0000000) + { +/* if (ARM7.kod & (1 << 4)) + logerror("ARM7: G111 / Coprocessor register transfer\n"); + else + logerror("ARM7: G111 / Coprocessor data operation\n"); */ + } + else + { + UINT32 sr = ARM7.Rx [ARM7_CPSR]; + ARM7_SetCPSR (ARM7_CPSR_MX (sr, ARM7_CPSR_M_svc) | ARM7_CPSR_I); + ARM7.Rx [ARM7_SPSR] = sr; + ARM7.Rx [ARM7_LR] = ARM7.Rx [ARM7_PC]; + ARM7.Rx [ARM7_PC] = 0x00000008; + } + } + //-------------------------------------------------------------------------- + +#ifdef ARM7_THUMB + //-------------------------------------------------------------------------- + /** Halfword and Signed Data Transfer. */ +void R_HSDT () + { + int Rm, Rd, Rn, offset; + uint32_t adres, w; + +#define BIT_P (ARM7.kod & (1 << 24)) +#define BIT_U (ARM7.kod & (1 << 23)) +#define BIT_W (ARM7.kod & (1 << 21)) +#define BIT_L (ARM7.kod & (1 << 20)) +#define BIT_S (ARM7.kod & (1 << 6)) +#define BIT_H (ARM7.kod & (1 << 5)) + + // Rm can't be PC + Rn = (ARM7.kod >> 16) & 15; + Rd = (ARM7.kod >> 12) & 15; + if (Rn != ARM7_PC) + adres = ARM7.Rx [Rn]; + else + adres = ARM7.Rx [ARM7_PC] & ~3; + if (!BIT_L) + if (Rd != ARM7_PC) + w = ARM7.Rx [Rd]; + else + w = (ARM7.Rx [ARM7_PC] & ~3) + 12 + POPRAWKA_PC; + + if (1 << 22) + // immediate + offset = ((ARM7.kod >> 4) & 0xf0) | (ARM7.kod & 15); + else + { + // register + Rm = ARM7.kod & 15; + offset = ARM7.Rx [Rm]; + } + + if (!BIT_U) + offset = -offset; + if (BIT_P) + { + // "pre-index" + adres += offset; + if (BIT_W) + // "write-back" + ARM7.Rx [Rn] = adres; + } + else + // "post-index" + ARM7.Rx [Rn] += offset; + if (Rn == ARM7_PC) + adres += 8 + POPRAWKA_PC; + + if (BIT_L) + { + // "load" + s_cykle += 3; + if (BIT_S) + { + if (BIT_H) + // "signed halfword" + ARM7.Rx [Rd] = (INT32)(INT16)arm7_read_16 (adres); + else + // "signed byte" + ARM7.Rx [Rd] = (INT32)(INT8)arm7_read_8 (adres); + } + else + // "unsigned halfword" + ARM7.Rx [Rd] = arm7_read_16 (adres); + } + else + { + // store + s_cykle += 2; + if (BIT_H) + // "halfword" + arm7_write_16 (adres, (UINT16)w); + else + // "byte" + arm7_write_8 (adres, (UINT8)w); + } + +#undef BIT_H +#undef BIT_S +#undef BIT_L +#undef BIT_W +#undef BIT_U +#undef BIT_P + } + //-------------------------------------------------------------------------- +#endif |