cog/Frameworks/AudioOverload/aosdk/eng_dsf/arm7.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;
}
//--------------------------------------------------------------------------