OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [sim/] [arm/] [armsupp.c] - Diff between revs 1181 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1181 Rev 1765
/*  armsupp.c -- ARMulator support code:  ARM6 Instruction Emulator.
/*  armsupp.c -- ARMulator support code:  ARM6 Instruction Emulator.
    Copyright (C) 1994 Advanced RISC Machines Ltd.
    Copyright (C) 1994 Advanced RISC Machines Ltd.
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
    (at your option) any later version.
 
 
    This program is distributed in the hope that it will be useful,
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    GNU General Public License for more details.
 
 
    You should have received a copy of the GNU General Public License
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 
 
#include "armdefs.h"
#include "armdefs.h"
#include "armemu.h"
#include "armemu.h"
#include "ansidecl.h"
#include "ansidecl.h"
 
 
/* Definitions for the support routines.  */
/* Definitions for the support routines.  */
 
 
static ARMword ModeToBank (ARMword);
static ARMword ModeToBank (ARMword);
static void    EnvokeList (ARMul_State *, unsigned long, unsigned long);
static void    EnvokeList (ARMul_State *, unsigned long, unsigned long);
 
 
struct EventNode
struct EventNode
{                                       /* An event list node.  */
{                                       /* An event list node.  */
  unsigned (*func) (ARMul_State *);     /* The function to call.  */
  unsigned (*func) (ARMul_State *);     /* The function to call.  */
  struct EventNode *next;
  struct EventNode *next;
};
};
 
 
/* This routine returns the value of a register from a mode.  */
/* This routine returns the value of a register from a mode.  */
 
 
ARMword
ARMword
ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg)
{
{
  mode &= MODEBITS;
  mode &= MODEBITS;
  if (mode != state->Mode)
  if (mode != state->Mode)
    return (state->RegBank[ModeToBank ((ARMword) mode)][reg]);
    return (state->RegBank[ModeToBank ((ARMword) mode)][reg]);
  else
  else
    return (state->Reg[reg]);
    return (state->Reg[reg]);
}
}
 
 
/* This routine sets the value of a register for a mode.  */
/* This routine sets the value of a register for a mode.  */
 
 
void
void
ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value)
{
{
  mode &= MODEBITS;
  mode &= MODEBITS;
  if (mode != state->Mode)
  if (mode != state->Mode)
    state->RegBank[ModeToBank ((ARMword) mode)][reg] = value;
    state->RegBank[ModeToBank ((ARMword) mode)][reg] = value;
  else
  else
    state->Reg[reg] = value;
    state->Reg[reg] = value;
}
}
 
 
/* This routine returns the value of the PC, mode independently.  */
/* This routine returns the value of the PC, mode independently.  */
 
 
ARMword
ARMword
ARMul_GetPC (ARMul_State * state)
ARMul_GetPC (ARMul_State * state)
{
{
  if (state->Mode > SVC26MODE)
  if (state->Mode > SVC26MODE)
    return state->Reg[15];
    return state->Reg[15];
  else
  else
    return R15PC;
    return R15PC;
}
}
 
 
/* This routine returns the value of the PC, mode independently.  */
/* This routine returns the value of the PC, mode independently.  */
 
 
ARMword
ARMword
ARMul_GetNextPC (ARMul_State * state)
ARMul_GetNextPC (ARMul_State * state)
{
{
  if (state->Mode > SVC26MODE)
  if (state->Mode > SVC26MODE)
    return state->Reg[15] + isize;
    return state->Reg[15] + isize;
  else
  else
    return (state->Reg[15] + isize) & R15PCBITS;
    return (state->Reg[15] + isize) & R15PCBITS;
}
}
 
 
/* This routine sets the value of the PC.  */
/* This routine sets the value of the PC.  */
 
 
void
void
ARMul_SetPC (ARMul_State * state, ARMword value)
ARMul_SetPC (ARMul_State * state, ARMword value)
{
{
  if (ARMul_MODE32BIT)
  if (ARMul_MODE32BIT)
    state->Reg[15] = value & PCBITS;
    state->Reg[15] = value & PCBITS;
  else
  else
    state->Reg[15] = R15CCINTMODE | (value & R15PCBITS);
    state->Reg[15] = R15CCINTMODE | (value & R15PCBITS);
  FLUSHPIPE;
  FLUSHPIPE;
}
}
 
 
/* This routine returns the value of register 15, mode independently.  */
/* This routine returns the value of register 15, mode independently.  */
 
 
ARMword
ARMword
ARMul_GetR15 (ARMul_State * state)
ARMul_GetR15 (ARMul_State * state)
{
{
  if (state->Mode > SVC26MODE)
  if (state->Mode > SVC26MODE)
    return (state->Reg[15]);
    return (state->Reg[15]);
  else
  else
    return (R15PC | ECC | ER15INT | EMODE);
    return (R15PC | ECC | ER15INT | EMODE);
}
}
 
 
/* This routine sets the value of Register 15.  */
/* This routine sets the value of Register 15.  */
 
 
void
void
ARMul_SetR15 (ARMul_State * state, ARMword value)
ARMul_SetR15 (ARMul_State * state, ARMword value)
{
{
  if (ARMul_MODE32BIT)
  if (ARMul_MODE32BIT)
    state->Reg[15] = value & PCBITS;
    state->Reg[15] = value & PCBITS;
  else
  else
    {
    {
      state->Reg[15] = value;
      state->Reg[15] = value;
      ARMul_R15Altered (state);
      ARMul_R15Altered (state);
    }
    }
  FLUSHPIPE;
  FLUSHPIPE;
}
}
 
 
/* This routine returns the value of the CPSR.  */
/* This routine returns the value of the CPSR.  */
 
 
ARMword
ARMword
ARMul_GetCPSR (ARMul_State * state)
ARMul_GetCPSR (ARMul_State * state)
{
{
  return (CPSR | state->Cpsr);
  return (CPSR | state->Cpsr);
}
}
 
 
/* This routine sets the value of the CPSR.  */
/* This routine sets the value of the CPSR.  */
 
 
void
void
ARMul_SetCPSR (ARMul_State * state, ARMword value)
ARMul_SetCPSR (ARMul_State * state, ARMword value)
{
{
  state->Cpsr = value;
  state->Cpsr = value;
  ARMul_CPSRAltered (state);
  ARMul_CPSRAltered (state);
}
}
 
 
/* This routine does all the nasty bits involved in a write to the CPSR,
/* This routine does all the nasty bits involved in a write to the CPSR,
   including updating the register bank, given a MSR instruction.  */
   including updating the register bank, given a MSR instruction.  */
 
 
void
void
ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs)
{
{
  state->Cpsr = ARMul_GetCPSR (state);
  state->Cpsr = ARMul_GetCPSR (state);
 
 
  if (state->Mode != USER26MODE
  if (state->Mode != USER26MODE
      && state->Mode != USER32MODE)
      && state->Mode != USER32MODE)
    {
    {
      /* In user mode, only write flags.  */
      /* In user mode, only write flags.  */
      if (BIT (16))
      if (BIT (16))
        SETPSR_C (state->Cpsr, rhs);
        SETPSR_C (state->Cpsr, rhs);
      if (BIT (17))
      if (BIT (17))
        SETPSR_X (state->Cpsr, rhs);
        SETPSR_X (state->Cpsr, rhs);
      if (BIT (18))
      if (BIT (18))
        SETPSR_S (state->Cpsr, rhs);
        SETPSR_S (state->Cpsr, rhs);
    }
    }
  if (BIT (19))
  if (BIT (19))
    SETPSR_F (state->Cpsr, rhs);
    SETPSR_F (state->Cpsr, rhs);
  ARMul_CPSRAltered (state);
  ARMul_CPSRAltered (state);
}
}
 
 
/* Get an SPSR from the specified mode.  */
/* Get an SPSR from the specified mode.  */
 
 
ARMword
ARMword
ARMul_GetSPSR (ARMul_State * state, ARMword mode)
ARMul_GetSPSR (ARMul_State * state, ARMword mode)
{
{
  ARMword bank = ModeToBank (mode & MODEBITS);
  ARMword bank = ModeToBank (mode & MODEBITS);
 
 
  if (! BANK_CAN_ACCESS_SPSR (bank))
  if (! BANK_CAN_ACCESS_SPSR (bank))
    return ARMul_GetCPSR (state);
    return ARMul_GetCPSR (state);
 
 
  return state->Spsr[bank];
  return state->Spsr[bank];
}
}
 
 
/* This routine does a write to an SPSR.  */
/* This routine does a write to an SPSR.  */
 
 
void
void
ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value)
{
{
  ARMword bank = ModeToBank (mode & MODEBITS);
  ARMword bank = ModeToBank (mode & MODEBITS);
 
 
  if (BANK_CAN_ACCESS_SPSR (bank))
  if (BANK_CAN_ACCESS_SPSR (bank))
    state->Spsr[bank] = value;
    state->Spsr[bank] = value;
}
}
 
 
/* This routine does a write to the current SPSR, given an MSR instruction.  */
/* This routine does a write to the current SPSR, given an MSR instruction.  */
 
 
void
void
ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs)
{
{
  if (BANK_CAN_ACCESS_SPSR (state->Bank))
  if (BANK_CAN_ACCESS_SPSR (state->Bank))
    {
    {
      if (BIT (16))
      if (BIT (16))
        SETPSR_C (state->Spsr[state->Bank], rhs);
        SETPSR_C (state->Spsr[state->Bank], rhs);
      if (BIT (17))
      if (BIT (17))
        SETPSR_X (state->Spsr[state->Bank], rhs);
        SETPSR_X (state->Spsr[state->Bank], rhs);
      if (BIT (18))
      if (BIT (18))
        SETPSR_S (state->Spsr[state->Bank], rhs);
        SETPSR_S (state->Spsr[state->Bank], rhs);
      if (BIT (19))
      if (BIT (19))
        SETPSR_F (state->Spsr[state->Bank], rhs);
        SETPSR_F (state->Spsr[state->Bank], rhs);
    }
    }
}
}
 
 
/* This routine updates the state of the emulator after the Cpsr has been
/* This routine updates the state of the emulator after the Cpsr has been
   changed.  Both the processor flags and register bank are updated.  */
   changed.  Both the processor flags and register bank are updated.  */
 
 
void
void
ARMul_CPSRAltered (ARMul_State * state)
ARMul_CPSRAltered (ARMul_State * state)
{
{
  ARMword oldmode;
  ARMword oldmode;
 
 
  if (state->prog32Sig == LOW)
  if (state->prog32Sig == LOW)
    state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS);
    state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS);
 
 
  oldmode = state->Mode;
  oldmode = state->Mode;
 
 
  if (state->Mode != (state->Cpsr & MODEBITS))
  if (state->Mode != (state->Cpsr & MODEBITS))
    {
    {
      state->Mode =
      state->Mode =
        ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
        ARMul_SwitchMode (state, state->Mode, state->Cpsr & MODEBITS);
 
 
      state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
      state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
    }
    }
  state->Cpsr &= ~MODEBITS;
  state->Cpsr &= ~MODEBITS;
 
 
  ASSIGNINT (state->Cpsr & INTBITS);
  ASSIGNINT (state->Cpsr & INTBITS);
  state->Cpsr &= ~INTBITS;
  state->Cpsr &= ~INTBITS;
  ASSIGNN ((state->Cpsr & NBIT) != 0);
  ASSIGNN ((state->Cpsr & NBIT) != 0);
  state->Cpsr &= ~NBIT;
  state->Cpsr &= ~NBIT;
  ASSIGNZ ((state->Cpsr & ZBIT) != 0);
  ASSIGNZ ((state->Cpsr & ZBIT) != 0);
  state->Cpsr &= ~ZBIT;
  state->Cpsr &= ~ZBIT;
  ASSIGNC ((state->Cpsr & CBIT) != 0);
  ASSIGNC ((state->Cpsr & CBIT) != 0);
  state->Cpsr &= ~CBIT;
  state->Cpsr &= ~CBIT;
  ASSIGNV ((state->Cpsr & VBIT) != 0);
  ASSIGNV ((state->Cpsr & VBIT) != 0);
  state->Cpsr &= ~VBIT;
  state->Cpsr &= ~VBIT;
  ASSIGNS ((state->Cpsr & SBIT) != 0);
  ASSIGNS ((state->Cpsr & SBIT) != 0);
  state->Cpsr &= ~SBIT;
  state->Cpsr &= ~SBIT;
#ifdef MODET
#ifdef MODET
  ASSIGNT ((state->Cpsr & TBIT) != 0);
  ASSIGNT ((state->Cpsr & TBIT) != 0);
  state->Cpsr &= ~TBIT;
  state->Cpsr &= ~TBIT;
#endif
#endif
 
 
  if (oldmode > SVC26MODE)
  if (oldmode > SVC26MODE)
    {
    {
      if (state->Mode <= SVC26MODE)
      if (state->Mode <= SVC26MODE)
        {
        {
          state->Emulate = CHANGEMODE;
          state->Emulate = CHANGEMODE;
          state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
          state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
        }
        }
    }
    }
  else
  else
    {
    {
      if (state->Mode > SVC26MODE)
      if (state->Mode > SVC26MODE)
        {
        {
          state->Emulate = CHANGEMODE;
          state->Emulate = CHANGEMODE;
          state->Reg[15] = R15PC;
          state->Reg[15] = R15PC;
        }
        }
      else
      else
        state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
        state->Reg[15] = ECC | ER15INT | EMODE | R15PC;
    }
    }
}
}
 
 
/* This routine updates the state of the emulator after register 15 has
/* This routine updates the state of the emulator after register 15 has
   been changed.  Both the processor flags and register bank are updated.
   been changed.  Both the processor flags and register bank are updated.
   This routine should only be called from a 26 bit mode.  */
   This routine should only be called from a 26 bit mode.  */
 
 
void
void
ARMul_R15Altered (ARMul_State * state)
ARMul_R15Altered (ARMul_State * state)
{
{
  if (state->Mode != R15MODE)
  if (state->Mode != R15MODE)
    {
    {
      state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
      state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE);
      state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
      state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
    }
    }
 
 
  if (state->Mode > SVC26MODE)
  if (state->Mode > SVC26MODE)
    state->Emulate = CHANGEMODE;
    state->Emulate = CHANGEMODE;
 
 
  ASSIGNR15INT (R15INT);
  ASSIGNR15INT (R15INT);
 
 
  ASSIGNN ((state->Reg[15] & NBIT) != 0);
  ASSIGNN ((state->Reg[15] & NBIT) != 0);
  ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
  ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
  ASSIGNC ((state->Reg[15] & CBIT) != 0);
  ASSIGNC ((state->Reg[15] & CBIT) != 0);
  ASSIGNV ((state->Reg[15] & VBIT) != 0);
  ASSIGNV ((state->Reg[15] & VBIT) != 0);
}
}
 
 
/* This routine controls the saving and restoring of registers across mode
/* This routine controls the saving and restoring of registers across mode
   changes.  The regbank matrix is largely unused, only rows 13 and 14 are
   changes.  The regbank matrix is largely unused, only rows 13 and 14 are
   used across all modes, 8 to 14 are used for FIQ, all others use the USER
   used across all modes, 8 to 14 are used for FIQ, all others use the USER
   column.  It's easier this way.  old and new parameter are modes numbers.
   column.  It's easier this way.  old and new parameter are modes numbers.
   Notice the side effect of changing the Bank variable.  */
   Notice the side effect of changing the Bank variable.  */
 
 
ARMword
ARMword
ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode)
{
{
  unsigned i;
  unsigned i;
  ARMword  oldbank;
  ARMword  oldbank;
  ARMword  newbank;
  ARMword  newbank;
 
 
  oldbank = ModeToBank (oldmode);
  oldbank = ModeToBank (oldmode);
  newbank = state->Bank = ModeToBank (newmode);
  newbank = state->Bank = ModeToBank (newmode);
 
 
  /* Do we really need to do it?  */
  /* Do we really need to do it?  */
  if (oldbank != newbank)
  if (oldbank != newbank)
    {
    {
      /* Save away the old registers.  */
      /* Save away the old registers.  */
      switch (oldbank)
      switch (oldbank)
        {
        {
        case USERBANK:
        case USERBANK:
        case IRQBANK:
        case IRQBANK:
        case SVCBANK:
        case SVCBANK:
        case ABORTBANK:
        case ABORTBANK:
        case UNDEFBANK:
        case UNDEFBANK:
          if (newbank == FIQBANK)
          if (newbank == FIQBANK)
            for (i = 8; i < 13; i++)
            for (i = 8; i < 13; i++)
              state->RegBank[USERBANK][i] = state->Reg[i];
              state->RegBank[USERBANK][i] = state->Reg[i];
          state->RegBank[oldbank][13] = state->Reg[13];
          state->RegBank[oldbank][13] = state->Reg[13];
          state->RegBank[oldbank][14] = state->Reg[14];
          state->RegBank[oldbank][14] = state->Reg[14];
          break;
          break;
        case FIQBANK:
        case FIQBANK:
          for (i = 8; i < 15; i++)
          for (i = 8; i < 15; i++)
            state->RegBank[FIQBANK][i] = state->Reg[i];
            state->RegBank[FIQBANK][i] = state->Reg[i];
          break;
          break;
        case DUMMYBANK:
        case DUMMYBANK:
          for (i = 8; i < 15; i++)
          for (i = 8; i < 15; i++)
            state->RegBank[DUMMYBANK][i] = 0;
            state->RegBank[DUMMYBANK][i] = 0;
          break;
          break;
        default:
        default:
          abort ();
          abort ();
        }
        }
 
 
      /* Restore the new registers.  */
      /* Restore the new registers.  */
      switch (newbank)
      switch (newbank)
        {
        {
        case USERBANK:
        case USERBANK:
        case IRQBANK:
        case IRQBANK:
        case SVCBANK:
        case SVCBANK:
        case ABORTBANK:
        case ABORTBANK:
        case UNDEFBANK:
        case UNDEFBANK:
          if (oldbank == FIQBANK)
          if (oldbank == FIQBANK)
            for (i = 8; i < 13; i++)
            for (i = 8; i < 13; i++)
              state->Reg[i] = state->RegBank[USERBANK][i];
              state->Reg[i] = state->RegBank[USERBANK][i];
          state->Reg[13] = state->RegBank[newbank][13];
          state->Reg[13] = state->RegBank[newbank][13];
          state->Reg[14] = state->RegBank[newbank][14];
          state->Reg[14] = state->RegBank[newbank][14];
          break;
          break;
        case FIQBANK:
        case FIQBANK:
          for (i = 8; i < 15; i++)
          for (i = 8; i < 15; i++)
            state->Reg[i] = state->RegBank[FIQBANK][i];
            state->Reg[i] = state->RegBank[FIQBANK][i];
          break;
          break;
        case DUMMYBANK:
        case DUMMYBANK:
          for (i = 8; i < 15; i++)
          for (i = 8; i < 15; i++)
            state->Reg[i] = 0;
            state->Reg[i] = 0;
          break;
          break;
        default:
        default:
          abort ();
          abort ();
        }
        }
    }
    }
 
 
  return newmode;
  return newmode;
}
}
 
 
/* Given a processor mode, this routine returns the
/* Given a processor mode, this routine returns the
   register bank that will be accessed in that mode.  */
   register bank that will be accessed in that mode.  */
 
 
static ARMword
static ARMword
ModeToBank (ARMword mode)
ModeToBank (ARMword mode)
{
{
  static ARMword bankofmode[] =
  static ARMword bankofmode[] =
  {
  {
    USERBANK,  FIQBANK,   IRQBANK,   SVCBANK,
    USERBANK,  FIQBANK,   IRQBANK,   SVCBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK,
    USERBANK,  FIQBANK,   IRQBANK,   SVCBANK,
    USERBANK,  FIQBANK,   IRQBANK,   SVCBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK,
    DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
    DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK
  };
  };
 
 
  if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0])))
  if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0])))
    return DUMMYBANK;
    return DUMMYBANK;
 
 
  return bankofmode[mode];
  return bankofmode[mode];
}
}
 
 
/* Returns the register number of the nth register in a reg list.  */
/* Returns the register number of the nth register in a reg list.  */
 
 
unsigned
unsigned
ARMul_NthReg (ARMword instr, unsigned number)
ARMul_NthReg (ARMword instr, unsigned number)
{
{
  unsigned bit, upto;
  unsigned bit, upto;
 
 
  for (bit = 0, upto = 0; upto <= number; bit ++)
  for (bit = 0, upto = 0; upto <= number; bit ++)
    if (BIT (bit))
    if (BIT (bit))
      upto ++;
      upto ++;
 
 
  return (bit - 1);
  return (bit - 1);
}
}
 
 
/* Assigns the N and Z flags depending on the value of result.  */
/* Assigns the N and Z flags depending on the value of result.  */
 
 
void
void
ARMul_NegZero (ARMul_State * state, ARMword result)
ARMul_NegZero (ARMul_State * state, ARMword result)
{
{
  if (NEG (result))
  if (NEG (result))
    {
    {
      SETN;
      SETN;
      CLEARZ;
      CLEARZ;
    }
    }
  else if (result == 0)
  else if (result == 0)
    {
    {
      CLEARN;
      CLEARN;
      SETZ;
      SETZ;
    }
    }
  else
  else
    {
    {
      CLEARN;
      CLEARN;
      CLEARZ;
      CLEARZ;
    }
    }
}
}
 
 
/* Compute whether an addition of A and B, giving RESULT, overflowed.  */
/* Compute whether an addition of A and B, giving RESULT, overflowed.  */
 
 
int
int
AddOverflow (ARMword a, ARMword b, ARMword result)
AddOverflow (ARMword a, ARMword b, ARMword result)
{
{
  return ((NEG (a) && NEG (b) && POS (result))
  return ((NEG (a) && NEG (b) && POS (result))
          || (POS (a) && POS (b) && NEG (result)));
          || (POS (a) && POS (b) && NEG (result)));
}
}
 
 
/* Compute whether a subtraction of A and B, giving RESULT, overflowed.  */
/* Compute whether a subtraction of A and B, giving RESULT, overflowed.  */
 
 
int
int
SubOverflow (ARMword a, ARMword b, ARMword result)
SubOverflow (ARMword a, ARMword b, ARMword result)
{
{
  return ((NEG (a) && POS (b) && POS (result))
  return ((NEG (a) && POS (b) && POS (result))
          || (POS (a) && NEG (b) && NEG (result)));
          || (POS (a) && NEG (b) && NEG (result)));
}
}
 
 
/* Assigns the C flag after an addition of a and b to give result.  */
/* Assigns the C flag after an addition of a and b to give result.  */
 
 
void
void
ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
{
{
  ASSIGNC ((NEG (a) && NEG (b)) ||
  ASSIGNC ((NEG (a) && NEG (b)) ||
           (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
           (NEG (a) && POS (result)) || (NEG (b) && POS (result)));
}
}
 
 
/* Assigns the V flag after an addition of a and b to give result.  */
/* Assigns the V flag after an addition of a and b to give result.  */
 
 
void
void
ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
{
{
  ASSIGNV (AddOverflow (a, b, result));
  ASSIGNV (AddOverflow (a, b, result));
}
}
 
 
/* Assigns the C flag after an subtraction of a and b to give result.  */
/* Assigns the C flag after an subtraction of a and b to give result.  */
 
 
void
void
ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result)
{
{
  ASSIGNC ((NEG (a) && POS (b)) ||
  ASSIGNC ((NEG (a) && POS (b)) ||
           (NEG (a) && POS (result)) || (POS (b) && POS (result)));
           (NEG (a) && POS (result)) || (POS (b) && POS (result)));
}
}
 
 
/* Assigns the V flag after an subtraction of a and b to give result.  */
/* Assigns the V flag after an subtraction of a and b to give result.  */
 
 
void
void
ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
{
{
  ASSIGNV (SubOverflow (a, b, result));
  ASSIGNV (SubOverflow (a, b, result));
}
}
 
 
/* This function does the work of generating the addresses used in an
/* This function does the work of generating the addresses used in an
   LDC instruction.  The code here is always post-indexed, it's up to the
   LDC instruction.  The code here is always post-indexed, it's up to the
   caller to get the input address correct and to handle base register
   caller to get the input address correct and to handle base register
   modification. It also handles the Busy-Waiting.  */
   modification. It also handles the Busy-Waiting.  */
 
 
void
void
ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address)
{
{
  unsigned cpab;
  unsigned cpab;
  ARMword data;
  ARMword data;
 
 
  UNDEF_LSCPCBaseWb;
  UNDEF_LSCPCBaseWb;
 
 
  if (! CP_ACCESS_ALLOWED (state, CPNum))
  if (! CP_ACCESS_ALLOWED (state, CPNum))
    {
    {
      ARMul_UndefInstr (state, instr);
      ARMul_UndefInstr (state, instr);
      return;
      return;
    }
    }
 
 
  if (ADDREXCEPT (address))
  if (ADDREXCEPT (address))
    INTERNALABORT (address);
    INTERNALABORT (address);
 
 
  cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
  cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0);
  while (cpab == ARMul_BUSY)
  while (cpab == ARMul_BUSY)
    {
    {
      ARMul_Icycles (state, 1, 0);
      ARMul_Icycles (state, 1, 0);
 
 
      if (IntPending (state))
      if (IntPending (state))
        {
        {
          cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          return;
          return;
        }
        }
      else
      else
        cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
        cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, 0);
    }
    }
  if (cpab == ARMul_CANT)
  if (cpab == ARMul_CANT)
    {
    {
      CPTAKEABORT;
      CPTAKEABORT;
      return;
      return;
    }
    }
 
 
  cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
  cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0);
  data = ARMul_LoadWordN (state, address);
  data = ARMul_LoadWordN (state, address);
  BUSUSEDINCPCN;
  BUSUSEDINCPCN;
 
 
  if (BIT (21))
  if (BIT (21))
    LSBase = state->Base;
    LSBase = state->Base;
  cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
  cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
 
 
  while (cpab == ARMul_INC)
  while (cpab == ARMul_INC)
    {
    {
      address += 4;
      address += 4;
      data = ARMul_LoadWordN (state, address);
      data = ARMul_LoadWordN (state, address);
      cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
      cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data);
    }
    }
 
 
  if (state->abortSig || state->Aborted)
  if (state->abortSig || state->Aborted)
    TAKEABORT;
    TAKEABORT;
}
}
 
 
/* This function does the work of generating the addresses used in an
/* This function does the work of generating the addresses used in an
   STC instruction.  The code here is always post-indexed, it's up to the
   STC instruction.  The code here is always post-indexed, it's up to the
   caller to get the input address correct and to handle base register
   caller to get the input address correct and to handle base register
   modification. It also handles the Busy-Waiting.  */
   modification. It also handles the Busy-Waiting.  */
 
 
void
void
ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
ARMul_STC (ARMul_State * state, ARMword instr, ARMword address)
{
{
  unsigned cpab;
  unsigned cpab;
  ARMword data;
  ARMword data;
 
 
  UNDEF_LSCPCBaseWb;
  UNDEF_LSCPCBaseWb;
 
 
  if (! CP_ACCESS_ALLOWED (state, CPNum))
  if (! CP_ACCESS_ALLOWED (state, CPNum))
    {
    {
      ARMul_UndefInstr (state, instr);
      ARMul_UndefInstr (state, instr);
      return;
      return;
    }
    }
 
 
  if (ADDREXCEPT (address) || VECTORACCESS (address))
  if (ADDREXCEPT (address) || VECTORACCESS (address))
    INTERNALABORT (address);
    INTERNALABORT (address);
 
 
  cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
  cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data);
  while (cpab == ARMul_BUSY)
  while (cpab == ARMul_BUSY)
    {
    {
      ARMul_Icycles (state, 1, 0);
      ARMul_Icycles (state, 1, 0);
      if (IntPending (state))
      if (IntPending (state))
        {
        {
          cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          return;
          return;
        }
        }
      else
      else
        cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
        cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, &data);
    }
    }
 
 
  if (cpab == ARMul_CANT)
  if (cpab == ARMul_CANT)
    {
    {
      CPTAKEABORT;
      CPTAKEABORT;
      return;
      return;
    }
    }
#ifndef MODE32
#ifndef MODE32
  if (ADDREXCEPT (address) || VECTORACCESS (address))
  if (ADDREXCEPT (address) || VECTORACCESS (address))
    INTERNALABORT (address);
    INTERNALABORT (address);
#endif
#endif
  BUSUSEDINCPCN;
  BUSUSEDINCPCN;
  if (BIT (21))
  if (BIT (21))
    LSBase = state->Base;
    LSBase = state->Base;
  cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
  cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
  ARMul_StoreWordN (state, address, data);
  ARMul_StoreWordN (state, address, data);
 
 
  while (cpab == ARMul_INC)
  while (cpab == ARMul_INC)
    {
    {
      address += 4;
      address += 4;
      cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
      cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data);
      ARMul_StoreWordN (state, address, data);
      ARMul_StoreWordN (state, address, data);
    }
    }
 
 
  if (state->abortSig || state->Aborted)
  if (state->abortSig || state->Aborted)
    TAKEABORT;
    TAKEABORT;
}
}
 
 
/* This function does the Busy-Waiting for an MCR instruction.  */
/* This function does the Busy-Waiting for an MCR instruction.  */
 
 
void
void
ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
{
{
  unsigned cpab;
  unsigned cpab;
 
 
  if (! CP_ACCESS_ALLOWED (state, CPNum))
  if (! CP_ACCESS_ALLOWED (state, CPNum))
    {
    {
      ARMul_UndefInstr (state, instr);
      ARMul_UndefInstr (state, instr);
      return;
      return;
    }
    }
 
 
  cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
  cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source);
 
 
  while (cpab == ARMul_BUSY)
  while (cpab == ARMul_BUSY)
    {
    {
      ARMul_Icycles (state, 1, 0);
      ARMul_Icycles (state, 1, 0);
 
 
      if (IntPending (state))
      if (IntPending (state))
        {
        {
          cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          return;
          return;
        }
        }
      else
      else
        cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
        cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, source);
    }
    }
 
 
  if (cpab == ARMul_CANT)
  if (cpab == ARMul_CANT)
    ARMul_Abort (state, ARMul_UndefinedInstrV);
    ARMul_Abort (state, ARMul_UndefinedInstrV);
  else
  else
    {
    {
      BUSUSEDINCPCN;
      BUSUSEDINCPCN;
      ARMul_Ccycles (state, 1, 0);
      ARMul_Ccycles (state, 1, 0);
    }
    }
}
}
 
 
/* This function does the Busy-Waiting for an MRC instruction.  */
/* This function does the Busy-Waiting for an MRC instruction.  */
 
 
ARMword
ARMword
ARMul_MRC (ARMul_State * state, ARMword instr)
ARMul_MRC (ARMul_State * state, ARMword instr)
{
{
  unsigned cpab;
  unsigned cpab;
  ARMword result = 0;
  ARMword result = 0;
 
 
  if (! CP_ACCESS_ALLOWED (state, CPNum))
  if (! CP_ACCESS_ALLOWED (state, CPNum))
    {
    {
      ARMul_UndefInstr (state, instr);
      ARMul_UndefInstr (state, instr);
      return;
      return;
    }
    }
 
 
  cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
  cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result);
  while (cpab == ARMul_BUSY)
  while (cpab == ARMul_BUSY)
    {
    {
      ARMul_Icycles (state, 1, 0);
      ARMul_Icycles (state, 1, 0);
      if (IntPending (state))
      if (IntPending (state))
        {
        {
          cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, instr, 0);
          return (0);
          return (0);
        }
        }
      else
      else
        cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
        cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, &result);
    }
    }
  if (cpab == ARMul_CANT)
  if (cpab == ARMul_CANT)
    {
    {
      ARMul_Abort (state, ARMul_UndefinedInstrV);
      ARMul_Abort (state, ARMul_UndefinedInstrV);
      /* Parent will destroy the flags otherwise.  */
      /* Parent will destroy the flags otherwise.  */
      result = ECC;
      result = ECC;
    }
    }
  else
  else
    {
    {
      BUSUSEDINCPCN;
      BUSUSEDINCPCN;
      ARMul_Ccycles (state, 1, 0);
      ARMul_Ccycles (state, 1, 0);
      ARMul_Icycles (state, 1, 0);
      ARMul_Icycles (state, 1, 0);
    }
    }
 
 
  return result;
  return result;
}
}
 
 
/* This function does the Busy-Waiting for an CDP instruction.  */
/* This function does the Busy-Waiting for an CDP instruction.  */
 
 
void
void
ARMul_CDP (ARMul_State * state, ARMword instr)
ARMul_CDP (ARMul_State * state, ARMword instr)
{
{
  unsigned cpab;
  unsigned cpab;
 
 
  if (! CP_ACCESS_ALLOWED (state, CPNum))
  if (! CP_ACCESS_ALLOWED (state, CPNum))
    {
    {
      ARMul_UndefInstr (state, instr);
      ARMul_UndefInstr (state, instr);
      return;
      return;
    }
    }
 
 
  cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
  cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr);
  while (cpab == ARMul_BUSY)
  while (cpab == ARMul_BUSY)
    {
    {
      ARMul_Icycles (state, 1, 0);
      ARMul_Icycles (state, 1, 0);
      if (IntPending (state))
      if (IntPending (state))
        {
        {
          cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
          cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, instr);
          return;
          return;
        }
        }
      else
      else
        cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
        cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr);
    }
    }
  if (cpab == ARMul_CANT)
  if (cpab == ARMul_CANT)
    ARMul_Abort (state, ARMul_UndefinedInstrV);
    ARMul_Abort (state, ARMul_UndefinedInstrV);
  else
  else
    BUSUSEDN;
    BUSUSEDN;
}
}
 
 
/* This function handles Undefined instructions, as CP isntruction.  */
/* This function handles Undefined instructions, as CP isntruction.  */
 
 
void
void
ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
ARMul_UndefInstr (ARMul_State * state, ARMword instr ATTRIBUTE_UNUSED)
{
{
  ARMul_Abort (state, ARMul_UndefinedInstrV);
  ARMul_Abort (state, ARMul_UndefinedInstrV);
}
}
 
 
/* Return TRUE if an interrupt is pending, FALSE otherwise.  */
/* Return TRUE if an interrupt is pending, FALSE otherwise.  */
 
 
unsigned
unsigned
IntPending (ARMul_State * state)
IntPending (ARMul_State * state)
{
{
  if (state->Exception)
  if (state->Exception)
    {
    {
      /* Any exceptions.  */
      /* Any exceptions.  */
      if (state->NresetSig == LOW)
      if (state->NresetSig == LOW)
        {
        {
          ARMul_Abort (state, ARMul_ResetV);
          ARMul_Abort (state, ARMul_ResetV);
          return TRUE;
          return TRUE;
        }
        }
      else if (!state->NfiqSig && !FFLAG)
      else if (!state->NfiqSig && !FFLAG)
        {
        {
          ARMul_Abort (state, ARMul_FIQV);
          ARMul_Abort (state, ARMul_FIQV);
          return TRUE;
          return TRUE;
        }
        }
      else if (!state->NirqSig && !IFLAG)
      else if (!state->NirqSig && !IFLAG)
        {
        {
          ARMul_Abort (state, ARMul_IRQV);
          ARMul_Abort (state, ARMul_IRQV);
          return TRUE;
          return TRUE;
        }
        }
    }
    }
 
 
  return FALSE;
  return FALSE;
}
}
 
 
/* Align a word access to a non word boundary.  */
/* Align a word access to a non word boundary.  */
 
 
ARMword
ARMword
ARMul_Align (state, address, data)
ARMul_Align (state, address, data)
     ARMul_State * state ATTRIBUTE_UNUSED;
     ARMul_State * state ATTRIBUTE_UNUSED;
     ARMword address;
     ARMword address;
     ARMword data;
     ARMword data;
{
{
  /* This code assumes the address is really unaligned,
  /* This code assumes the address is really unaligned,
     as a shift by 32 is undefined in C.  */
     as a shift by 32 is undefined in C.  */
 
 
  address = (address & 3) << 3; /* Get the word address.  */
  address = (address & 3) << 3; /* Get the word address.  */
  return ((data >> address) | (data << (32 - address)));        /* rot right */
  return ((data >> address) | (data << (32 - address)));        /* rot right */
}
}
 
 
/* This routine is used to call another routine after a certain number of
/* This routine is used to call another routine after a certain number of
   cycles have been executed. The first parameter is the number of cycles
   cycles have been executed. The first parameter is the number of cycles
   delay before the function is called, the second argument is a pointer
   delay before the function is called, the second argument is a pointer
   to the function. A delay of zero doesn't work, just call the function.  */
   to the function. A delay of zero doesn't work, just call the function.  */
 
 
void
void
ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay,
                     unsigned (*what) (ARMul_State *))
                     unsigned (*what) (ARMul_State *))
{
{
  unsigned long when;
  unsigned long when;
  struct EventNode *event;
  struct EventNode *event;
 
 
  if (state->EventSet++ == 0)
  if (state->EventSet++ == 0)
    state->Now = ARMul_Time (state);
    state->Now = ARMul_Time (state);
  when = (state->Now + delay) % EVENTLISTSIZE;
  when = (state->Now + delay) % EVENTLISTSIZE;
  event = (struct EventNode *) malloc (sizeof (struct EventNode));
  event = (struct EventNode *) malloc (sizeof (struct EventNode));
  event->func = what;
  event->func = what;
  event->next = *(state->EventPtr + when);
  event->next = *(state->EventPtr + when);
  *(state->EventPtr + when) = event;
  *(state->EventPtr + when) = event;
}
}
 
 
/* This routine is called at the beginning of
/* This routine is called at the beginning of
   every cycle, to envoke scheduled events.  */
   every cycle, to envoke scheduled events.  */
 
 
void
void
ARMul_EnvokeEvent (ARMul_State * state)
ARMul_EnvokeEvent (ARMul_State * state)
{
{
  static unsigned long then;
  static unsigned long then;
 
 
  then = state->Now;
  then = state->Now;
  state->Now = ARMul_Time (state) % EVENTLISTSIZE;
  state->Now = ARMul_Time (state) % EVENTLISTSIZE;
  if (then < state->Now)
  if (then < state->Now)
    /* Schedule events.  */
    /* Schedule events.  */
    EnvokeList (state, then, state->Now);
    EnvokeList (state, then, state->Now);
  else if (then > state->Now)
  else if (then > state->Now)
    {
    {
      /* Need to wrap around the list.  */
      /* Need to wrap around the list.  */
      EnvokeList (state, then, EVENTLISTSIZE - 1L);
      EnvokeList (state, then, EVENTLISTSIZE - 1L);
      EnvokeList (state, 0L, state->Now);
      EnvokeList (state, 0L, state->Now);
    }
    }
}
}
 
 
/* Envokes all the entries in a range.  */
/* Envokes all the entries in a range.  */
 
 
static void
static void
EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
EnvokeList (ARMul_State * state, unsigned long from, unsigned long to)
{
{
  for (; from <= to; from++)
  for (; from <= to; from++)
    {
    {
      struct EventNode *anevent;
      struct EventNode *anevent;
 
 
      anevent = *(state->EventPtr + from);
      anevent = *(state->EventPtr + from);
      while (anevent)
      while (anevent)
        {
        {
          (anevent->func) (state);
          (anevent->func) (state);
          state->EventSet--;
          state->EventSet--;
          anevent = anevent->next;
          anevent = anevent->next;
        }
        }
      *(state->EventPtr + from) = NULL;
      *(state->EventPtr + from) = NULL;
    }
    }
}
}
 
 
/* This routine is returns the number of clock ticks since the last reset.  */
/* This routine is returns the number of clock ticks since the last reset.  */
 
 
unsigned long
unsigned long
ARMul_Time (ARMul_State * state)
ARMul_Time (ARMul_State * state)
{
{
  return (state->NumScycles + state->NumNcycles +
  return (state->NumScycles + state->NumNcycles +
          state->NumIcycles + state->NumCcycles + state->NumFcycles);
          state->NumIcycles + state->NumCcycles + state->NumFcycles);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.