1339 lines
32 KiB
C
1339 lines
32 KiB
C
//
|
|
// 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
|