summaryrefslogtreecommitdiff
path: root/plugins/ao/eng_dsf/arm7i.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ao/eng_dsf/arm7i.c')
-rw-r--r--plugins/ao/eng_dsf/arm7i.c1339
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