/* arminit.c -- ARMulator initialization: ARM6 Instruction Emulator. Copyright (C) 1994 Advanced RISC Machines Ltd. 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "armdefs.h" #include "armemu.h" /***************************************************************************\ * Definitions for the emulator architecture * \***************************************************************************/ void ARMul_EmulateInit(void) ; ARMul_State *ARMul_NewState(void) ; void ARMul_Reset(ARMul_State *state) ; ARMword ARMul_DoCycle(ARMul_State *state) ; unsigned ARMul_DoCoPro(ARMul_State *state) ; ARMword ARMul_DoProg(ARMul_State *state) ; ARMword ARMul_DoInstr(ARMul_State *state) ; void ARMul_Abort(ARMul_State *state, ARMword address) ; unsigned ARMul_MultTable[32] = {1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9, 10,10,11,11,12,12,13,13,14,14,15,15,16,16,16} ; ARMword ARMul_ImmedTable[4096] ; /* immediate DP LHS values */ char ARMul_BitList[256] ; /* number of bits in a byte table */ /***************************************************************************\ * Call this routine once to set up the emulator's tables. * \***************************************************************************/ void ARMul_EmulateInit(void) {unsigned long i, j ; for (i = 0 ; i < 4096 ; i++) { /* the values of 12 bit dp rhs's */ ARMul_ImmedTable[i] = ROTATER(i & 0xffL,(i >> 7L) & 0x1eL) ; } for (i = 0 ; i < 256 ; ARMul_BitList[i++] = 0 ) ; /* how many bits in LSM */ for (j = 1 ; j < 256 ; j <<= 1) for (i = 0 ; i < 256 ; i++) if ((i & j) > 0 ) ARMul_BitList[i]++ ; for (i = 0 ; i < 256 ; i++) ARMul_BitList[i] *= 4 ; /* you always need 4 times these values */ } /***************************************************************************\ * Returns a new instantiation of the ARMulator's state * \***************************************************************************/ ARMul_State *ARMul_NewState(void) {ARMul_State *state ; unsigned i, j ; state = (ARMul_State *)malloc(sizeof(ARMul_State)) ; memset (state, 0, sizeof (ARMul_State)); state->Emulate = RUN ; for (i = 0 ; i < 16 ; i++) { state->Reg[i] = 0 ; for (j = 0 ; j < 7 ; j++) state->RegBank[j][i] = 0 ; } for (i = 0 ; i < 7 ; i++) state->Spsr[i] = 0 ; state->Mode = 0 ; state->CallDebug = FALSE ; state->Debug = FALSE ; state->VectorCatch = 0 ; state->Aborted = FALSE ; state->Reseted = FALSE ; state->Inted = 3 ; state->LastInted = 3 ; state->MemDataPtr = NULL ; state->MemInPtr = NULL ; state->MemOutPtr = NULL ; state->MemSparePtr = NULL ; state->MemSize = 0 ; state->OSptr = NULL ; state->CommandLine = NULL ; state->EventSet = 0 ; state->Now = 0 ; state->EventPtr = (struct EventNode **)malloc((unsigned)EVENTLISTSIZE * sizeof(struct EventNode *)) ; for (i = 0 ; i < EVENTLISTSIZE ; i++) *(state->EventPtr + i) = NULL ; #ifdef ARM61 state->prog32Sig = LOW ; state->data32Sig = LOW ; #else state->prog32Sig = HIGH ; state->data32Sig = HIGH ; #endif state->lateabtSig = LOW ; state->bigendSig = LOW ; ARMul_Reset(state) ; return(state) ; } /***************************************************************************\ * Call this routine to set ARMulator to model a certain processor * \***************************************************************************/ void ARMul_SelectProcessor(ARMul_State *state, unsigned processor) { if (processor & ARM_Fix26_Prop) { state->prog32Sig = LOW; state->data32Sig = LOW; }else{ state->prog32Sig = HIGH; state->data32Sig = HIGH; } state->lateabtSig = LOW; } /***************************************************************************\ * Call this routine to set up the initial machine state (or perform a RESET * \***************************************************************************/ void ARMul_Reset(ARMul_State *state) {state->NextInstr = 0 ; if (state->prog32Sig) { state->Reg[15] = 0 ; state->Cpsr = INTBITS | SVC32MODE ; } else { state->Reg[15] = R15INTBITS | SVC26MODE ; state->Cpsr = INTBITS | SVC26MODE ; } ARMul_CPSRAltered(state) ; state->Bank = SVCBANK ; FLUSHPIPE ; state->EndCondition = 0 ; state->ErrorCode = 0 ; state->Exception = FALSE ; state->NresetSig = HIGH ; state->NfiqSig = HIGH ; state->NirqSig = HIGH ; state->NtransSig = (state->Mode & 3)?HIGH:LOW ; state->abortSig = LOW ; state->AbortAddr = 1 ; state->NumInstrs = 0 ; state->NumNcycles = 0 ; state->NumScycles = 0 ; state->NumIcycles = 0 ; state->NumCcycles = 0 ; state->NumFcycles = 0 ; #ifdef ASIM (void)ARMul_MemoryInit() ; ARMul_OSInit(state) ; #endif } /***************************************************************************\ * Emulate the execution of an entire program. Start the correct emulator * * (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * * address of the last instruction that is executed. * \***************************************************************************/ ARMword ARMul_DoProg(ARMul_State *state) {ARMword pc = 0 ; state->Emulate = RUN ; while (state->Emulate != STOP) { state->Emulate = RUN ; if (state->prog32Sig && ARMul_MODE32BIT) pc = ARMul_Emulate32(state) ; else pc = ARMul_Emulate26(state) ; } return(pc) ; } /***************************************************************************\ * Emulate the execution of one instruction. Start the correct emulator * * (Emulate26 for a 26 bit ARM and Emulate32 for a 32 bit ARM), return the * * address of the instruction that is executed. * \***************************************************************************/ ARMword ARMul_DoInstr(ARMul_State *state) {ARMword pc = 0 ; state->Emulate = ONCE ; if (state->prog32Sig && ARMul_MODE32BIT) pc = ARMul_Emulate32(state) ; else pc = ARMul_Emulate26(state) ; return(pc) ; } /***************************************************************************\ * This routine causes an Abort to occur, including selecting the correct * * mode, register bank, and the saving of registers. Call with the * * appropriate vector's memory address (0,4,8 ....) * \***************************************************************************/ void ARMul_Abort(ARMul_State *state, ARMword vector) {ARMword temp ; state->Aborted = FALSE ; if (ARMul_OSException(state,vector,ARMul_GetPC(state))) return ; if (state->prog32Sig) if (ARMul_MODE26BIT) temp = R15PC ; else temp = state->Reg[15] ; else temp = R15PC | ECC | ER15INT | EMODE ; switch (vector) { case ARMul_ResetV : /* RESET */ state->Spsr[SVCBANK] = CPSR ; SETABORT(INTBITS,state->prog32Sig?SVC32MODE:SVC26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp ; break ; case ARMul_UndefinedInstrV : /* Undefined Instruction */ state->Spsr[state->prog32Sig?UNDEFBANK:SVCBANK] = CPSR ; SETABORT(IBIT,state->prog32Sig?UNDEF32MODE:SVC26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp - 4 ; break ; case ARMul_SWIV : /* Software Interrupt */ state->Spsr[SVCBANK] = CPSR ; SETABORT(IBIT,state->prog32Sig?SVC32MODE:SVC26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp - 4 ; break ; case ARMul_PrefetchAbortV : /* Prefetch Abort */ state->AbortAddr = 1 ; state->Spsr[state->prog32Sig?ABORTBANK:SVCBANK] = CPSR ; SETABORT(IBIT,state->prog32Sig?ABORT32MODE:SVC26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp - 4 ; break ; case ARMul_DataAbortV : /* Data Abort */ state->Spsr[state->prog32Sig?ABORTBANK:SVCBANK] = CPSR ; SETABORT(IBIT,state->prog32Sig?ABORT32MODE:SVC26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp - 4 ; /* the PC must have been incremented */ break ; case ARMul_AddrExceptnV : /* Address Exception */ state->Spsr[SVCBANK] = CPSR ; SETABORT(IBIT,SVC26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp - 4 ; break ; case ARMul_IRQV : /* IRQ */ state->Spsr[IRQBANK] = CPSR ; SETABORT(IBIT,state->prog32Sig?IRQ32MODE:IRQ26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp - 4 ; break ; case ARMul_FIQV : /* FIQ */ state->Spsr[FIQBANK] = CPSR ; SETABORT(INTBITS,state->prog32Sig?FIQ32MODE:FIQ26MODE) ; ARMul_CPSRAltered(state) ; state->Reg[14] = temp - 4 ; break ; } if (ARMul_MODE32BIT) ARMul_SetR15(state,vector) ; else ARMul_SetR15(state,R15CCINTMODE | vector) ; }