musix 0.3.3

Music player library for esoteric audio formats (music from C64,Amiga etc)
Documentation
//
// 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;
  }
  //--------------------------------------------------------------------------