275 lines
7.9 KiB
C
275 lines
7.9 KiB
C
//
|
|
// ARM7 processor emulator
|
|
// version 1.6 / 2008-02-16
|
|
// (c) Radoslaw Balcewicz
|
|
//
|
|
|
|
#include "arm7.h"
|
|
#include "arm7i.h"
|
|
|
|
#ifdef ARM7_THUMB
|
|
#include "arm7thumb.h"
|
|
#endif
|
|
|
|
//--------------------------------------------------------------------------
|
|
// definitions and macros
|
|
|
|
/** Macro for accessing banked registers. */
|
|
#define RX_BANK(t,r) (ARM7.Rx_bank [t][r - 8])
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
// private functions
|
|
|
|
/** CPU Reset. */
|
|
static void Reset (void);
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
// public variables
|
|
|
|
/** ARM7 state. */
|
|
struct sARM7 ARM7;
|
|
|
|
// private variables
|
|
|
|
/** Table for decoding bit-coded mode to zero based index. */
|
|
static const int s_tabTryb [32] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
-1, -1, -1, -1, -1, -1, ARM7_MODE_usr, ARM7_MODE_fiq, ARM7_MODE_irq,
|
|
ARM7_MODE_svc, -1, -1, -1, ARM7_MODE_abt, -1, -1, -1, ARM7_MODE_und,
|
|
-1, -1, -1, ARM7_MODE_sys};
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
// public functions
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** ARM7 emulator init. */
|
|
void ARM7_Init ()
|
|
{
|
|
// sane startup values
|
|
ARM7.fiq = 0;
|
|
ARM7.irq = 0;
|
|
ARM7.carry = 0;
|
|
ARM7.overflow = 0;
|
|
ARM7.flagi = FALSE;
|
|
ARM7.cykle = 0;
|
|
|
|
// reset will do the rest
|
|
ARM7_HardReset ();
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** Power-ON reset. */
|
|
void ARM7_HardReset ()
|
|
{
|
|
// CPSR that makes sense
|
|
ARM7.Rx [ARM7_CPSR] = ARM7_CPSR_I | ARM7_CPSR_F | ARM7_CPSR_M_svc;
|
|
Reset ();
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** Hardware reset via /RESET line. */
|
|
void ARM7_SoftReset ()
|
|
{
|
|
Reset ();
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** CPSR update, possibly changing operating mode. */
|
|
void ARM7_SetCPSR (ARM7_REG sr)
|
|
{
|
|
int stary, nowy;
|
|
|
|
stary = s_tabTryb [ARM7_CPSR_M (ARM7.Rx [ARM7_CPSR])];
|
|
nowy = s_tabTryb [ARM7_CPSR_M (sr)];
|
|
// do we have to change modes?
|
|
if (nowy != stary)
|
|
{
|
|
// save this mode registers
|
|
RX_BANK (stary, ARM7_SP) = ARM7.Rx [ARM7_SP],
|
|
RX_BANK (stary, ARM7_LR) = ARM7.Rx [ARM7_LR],
|
|
RX_BANK (stary, ARM7_SPSR) = ARM7.Rx [ARM7_SPSR];
|
|
if (stary == ARM7_MODE_fiq)
|
|
{
|
|
// copy R8-R12
|
|
RX_BANK (ARM7_MODE_fiq, 8) = ARM7.Rx [8],
|
|
RX_BANK (ARM7_MODE_fiq, 9) = ARM7.Rx [9],
|
|
RX_BANK (ARM7_MODE_fiq, 10) = ARM7.Rx [10],
|
|
RX_BANK (ARM7_MODE_fiq, 11) = ARM7.Rx [11],
|
|
RX_BANK (ARM7_MODE_fiq, 12) = ARM7.Rx [12];
|
|
ARM7.Rx [8] = RX_BANK (ARM7_MODE_usr, 8),
|
|
ARM7.Rx [9] = RX_BANK (ARM7_MODE_usr, 9),
|
|
ARM7.Rx [10] = RX_BANK (ARM7_MODE_usr, 10),
|
|
ARM7.Rx [11] = RX_BANK (ARM7_MODE_usr, 11),
|
|
ARM7.Rx [12] = RX_BANK (ARM7_MODE_usr, 12);
|
|
}
|
|
|
|
// fetch new mode registers
|
|
ARM7.Rx [ARM7_SP] = RX_BANK (nowy, ARM7_SP),
|
|
ARM7.Rx [ARM7_LR] = RX_BANK (nowy, ARM7_LR),
|
|
ARM7.Rx [ARM7_SPSR] = RX_BANK (nowy, ARM7_SPSR);
|
|
if (nowy == ARM7_MODE_fiq)
|
|
{
|
|
// copy R8-R12
|
|
RX_BANK (ARM7_MODE_usr, 8) = ARM7.Rx [8],
|
|
RX_BANK (ARM7_MODE_usr, 9) = ARM7.Rx [9],
|
|
RX_BANK (ARM7_MODE_usr, 10) = ARM7.Rx [10],
|
|
RX_BANK (ARM7_MODE_usr, 11) = ARM7.Rx [11],
|
|
RX_BANK (ARM7_MODE_usr, 12) = ARM7.Rx [12];
|
|
ARM7.Rx [8] = RX_BANK (ARM7_MODE_fiq, 8),
|
|
ARM7.Rx [9] = RX_BANK (ARM7_MODE_fiq, 9),
|
|
ARM7.Rx [10] = RX_BANK (ARM7_MODE_fiq, 10),
|
|
ARM7.Rx [11] = RX_BANK (ARM7_MODE_fiq, 11),
|
|
ARM7.Rx [12] = RX_BANK (ARM7_MODE_fiq, 12);
|
|
}
|
|
}
|
|
|
|
// new CPSR value
|
|
ARM7.Rx [ARM7_CPSR] = sr;
|
|
|
|
// mode change could've enabled interrups, so we test for those and set
|
|
// appropriate flag for the instruction loop to catch
|
|
if (ARM7.fiq)
|
|
ARM7.flagi |= ARM7_FL_FIQ;
|
|
#ifndef ARM7_DREAMCAST
|
|
if (ARM7.irq)
|
|
ARM7.flagi |= ARM7_FL_IRQ;
|
|
#endif
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** Sets FIQ line state. */
|
|
void ARM7_SetFIQ (int stan)
|
|
{
|
|
stan = stan ? TRUE : FALSE;
|
|
// we catch changes only
|
|
if (stan ^ ARM7.fiq)
|
|
{
|
|
ARM7.fiq = stan;
|
|
if (ARM7.fiq)
|
|
ARM7.flagi |= ARM7_FL_FIQ;
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** Sets IRQ line state. */
|
|
void ARM7_SetIRQ (int stan)
|
|
{
|
|
stan = stan ? TRUE : FALSE;
|
|
// we catch changes only
|
|
if (stan ^ ARM7.irq)
|
|
{
|
|
ARM7.irq = stan;
|
|
if (ARM7.irq)
|
|
ARM7.flagi |= ARM7_FL_IRQ;
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** Tests for pending interrupts, switches to one if possible. */
|
|
void ARM7_CheckIRQ ()
|
|
{
|
|
UINT32 sr = ARM7.Rx [ARM7_CPSR];
|
|
|
|
// clear all interrupt flags
|
|
ARM7.flagi &= ~(ARM7_FL_FIQ | ARM7_FL_IRQ);
|
|
|
|
// check for pending interrupts we can switch to
|
|
// (FIQ can interrupt IRQ, but not the other way around)
|
|
if (ARM7.fiq)
|
|
{
|
|
if (!(sr & ARM7_CPSR_F))
|
|
{
|
|
// FIQ
|
|
ARM7_SetCPSR (ARM7_CPSR_MX (sr, ARM7_CPSR_M_fiq) | ARM7_CPSR_F | ARM7_CPSR_I);
|
|
ARM7.Rx [ARM7_SPSR] = sr;
|
|
// set new PC (return from interrupt will subtract 4)
|
|
ARM7.Rx [ARM7_LR] = ARM7.Rx [ARM7_PC] + 4;
|
|
ARM7.Rx [ARM7_PC] = 0x0000001c;
|
|
}
|
|
}
|
|
#ifndef ARM7_DREAMCAST
|
|
if (ARM7.irq)
|
|
{
|
|
if (!(sr & ARM7_CPSR_I))
|
|
{
|
|
// IRQ
|
|
ARM7_SetCPSR (ARM7_CPSR_MX (sr, ARM7_CPSR_M_irq) | ARM7_CPSR_I);
|
|
ARM7.Rx [ARM7_SPSR] = sr;
|
|
// set new PC (return from interrupt will subtract 4)
|
|
ARM7.Rx [ARM7_LR] = ARM7.Rx [ARM7_PC] + 4;
|
|
ARM7.Rx [ARM7_PC] = 0x00000018;
|
|
ARM7.irq = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** Single step. */
|
|
void ARM7_Step ()
|
|
{
|
|
// make a step
|
|
#ifdef ARM7_THUMB
|
|
if (ARM7.Rx[ARM7_CPSR] & ARM7_CPSR_T)
|
|
{
|
|
ARM7i_Thumb_Step();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
ARM7i_Step ();
|
|
}
|
|
// and test interrupts
|
|
ARM7_CheckIRQ ();
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** Runs emulation for at least n cycles, returns actual amount of cycles
|
|
burned - normal interpreter. */
|
|
int ARM7_Execute (int n)
|
|
{
|
|
ARM7.cykle = 0;
|
|
while (ARM7.cykle < n)
|
|
{
|
|
ARM7_CheckIRQ ();
|
|
while (!ARM7.flagi && ARM7.cykle < n)
|
|
// make one step, sum up cycles
|
|
ARM7.cykle += ARM7i_Step ();
|
|
}
|
|
return ARM7.cykle;
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
// private functions
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
/** CPU Reset. */
|
|
void Reset (void)
|
|
{
|
|
// clear ALU flags
|
|
ARM7.carry = 0;
|
|
ARM7.overflow = 0;
|
|
// test CPSR mode and pick a valid one if necessary
|
|
if (s_tabTryb [ARM7_CPSR_M (ARM7.Rx [ARM7_CPSR])] < 0)
|
|
ARM7.Rx [ARM7_CPSR] = ARM7_CPSR_I | ARM7_CPSR_F | ARM7_CPSR_M_svc;
|
|
// set up registers according to manual
|
|
RX_BANK (ARM7_MODE_svc, ARM7_LR) = ARM7.Rx [ARM7_PC];
|
|
RX_BANK (ARM7_MODE_svc, ARM7_SPSR) = ARM7.Rx [ARM7_CPSR];
|
|
ARM7_SetCPSR (ARM7_CPSR_I | ARM7_CPSR_F | ARM7_CPSR_M_svc);
|
|
ARM7.Rx [ARM7_PC] = 0x00000000;
|
|
}
|
|
//--------------------------------------------------------------------------
|