Пример #1
0
        /// <summary>
        /// Switches the CPU into an exception state. Each of the 7 exceptions that can be
        /// raised are unique. The CPU is switched into a new cpu mode, and interrupts
        /// may be disabled. The PC is set to the exception vector.
        /// Vector address is initially set to the "low" values. However of the HighVectors flag
        /// is set, then ARM exception vectors start at 0xffff0000
        /// </summary>
        /// <param name="armException"></param>
        private void SetExceptionState(ARMExceptions armException)
        {
            uint newPC;

            switch (armException)
            {
            case ARMExceptions.Reset:
                mCPSR.SwitchCPUMode(CPSR.CPUModeEnum.Supervisor);
                mCPSR.IRQDisable = true;
                mCPSR.FIQDisable = true;
                newPC            = 0x00000000;
                break;

            case ARMExceptions.UndefinedInstruction:
                mCPSR.SwitchCPUMode(CPSR.CPUModeEnum.Undefined);
                mCPSR.IRQDisable = true;
                newPC            = 0x00000004;
                break;

            case ARMExceptions.SoftwareInterrupt:
                mCPSR.SwitchCPUMode(CPSR.CPUModeEnum.Supervisor);
                mCPSR.IRQDisable = true;
                newPC            = 0x00000008;
                break;

            case ARMExceptions.PreFetchAbort:
                mCPSR.SwitchCPUMode(CPSR.CPUModeEnum.Abort);
                mCPSR.IRQDisable = true;
                newPC            = 0x0000000c;
                break;

            case ARMExceptions.DataAbort:
                mCPSR.SwitchCPUMode(CPSR.CPUModeEnum.Abort);
                mCPSR.IRQDisable = true;
                newPC            = 0x00000010;
                break;

            case ARMExceptions.IRQ:
                mCPSR.SwitchCPUMode(CPSR.CPUModeEnum.IRQ);
                mCPSR.IRQDisable = true;
                newPC            = 0x00000018;
                break;

            case ARMExceptions.FIQ:
                mCPSR.SwitchCPUMode(CPSR.CPUModeEnum.FIQ);
                mCPSR.IRQDisable = true;
                mCPSR.FIQDisable = true;
                newPC            = 0x0000001c;
                break;

            default: return;
            }//switch

            //save the PC into the new modes banked lr
            mGPR.LR = mGPR.PC;

            //if the "high" vectors mode is on, then set the top 16bits to a 1 of the new pc.
            mGPR.PC = this.HighVectors ? (newPC | 0xffff0000) : newPC;

            //always process the exception in ARM mode. When the exception returns and reloads
            //the cpsr from the scpsr, thumb mode will be reenabled if that was the starting mode.
            mCPSR.tf = false;
        }//SetExceptionState
Пример #2
0
        /// <summary>
        /// Execute the next instruction pointed to by the PC.
        /// Can be in either ARM or Thumb mode.
        /// </summary>
        public void Execute()
        {
            uint pcBefore = mGPR.PC;  // PC before op is executed

            try {
                ARMPluginInterfaces.MemorySize opcodeSize = mCPSR.tf ? ARMPluginInterfaces.MemorySize.HalfWord : ARMPluginInterfaces.MemorySize.Word;

                //this should never happen as the PC is checked after the opcode is executed,
                //but just being careful ...
                if (!this.InRange(pcBefore, opcodeSize))
                {
                    pcOutofRange(uint.MaxValue);  // we don't know the old address??
                    return;
                }

                //track the number of instructions executed.
                ++InstructionCount;

                //get the opcode and increment the PC. Fetch through the cache system if available.
                uint opcode = this.mL1InstructionCache.GetMemory(pcBefore, opcodeSize);

                //increment the PC by the current opcode size (ARM or Thumb mode).
                mGPR.PC = pcBefore + (uint)opcodeSize;

                uint cycleCount;
                bool swiInstruction;

                try
                {
                    cycleCount = ExecuteInstruction(opcode, out swiInstruction);
                }
                catch (UnalignedAccessException e)
                {
                    ReportRuntimeError(pcBefore, "{0}", e.Message);
                    HaltSimulation();
                    mGPR.PC = pcBefore;  // undo any advance of the PC
                    return;
                }
                catch (MemoryAccessException e)
                {
                    ReportRuntimeError(pcBefore, "{0}", e.Message);
                    HaltSimulation();
                    mGPR.PC = pcBefore;  // undo any advance of the PC
                    return;
                }
                // a cycle count of zero indicates an unknown instruction (including an swi instruction)
                if (cycleCount == 0)
                {
                    //let plugins have first crack at the unknown instruction.
                    //a return of 0 indicates it cannot handle it.
                    cycleCount = UnknownOpCode(opcode);
                }//if

                //if the cycle count is still 0 and it's an swi instruction, it wasn't handled by a plugin
                //invoke an ARM swi exception
                if (cycleCount == 0 && swiInstruction)
                {
                    this.RequestException(ARMExceptions.SoftwareInterrupt);
                }//if
                //otherwise its an unknown instruction that is not an swi instruction
                //so raise an ARM undefined instruction exception.
                else if (cycleCount == 0)
                {
                    this.RequestException(ARMExceptions.UndefinedInstruction);
                }//else if

                //if we actually expended cycles, let the plugins know and update local cycle count
                if (cycleCount > 0)
                {
                    CycleCount += cycleCount;
                    //todo - check overflow
                    HandleCycles((ushort)cycleCount);
                }//if

                //test the PC against valid memory. If it is not within the memory block, we have a problem
                if (!this.InRange(mGPR.PC, opcodeSize))
                {
                    pcOutofRange(pcBefore);
                }//if

                //check if any exceptions have been raised.
                //it is assumed that only 1 exception can be raised in a single instruction cycle.
                if (mRequestedException != 0)
                {
                    if ((mRequestedException & (uint)ARMExceptions.SoftwareInterrupt) != 0)
                    {
                        SetExceptionState(ARMExceptions.SoftwareInterrupt);
                    }//if
                    //FIQ has highest priority
                    else if (((mRequestedException & (uint)ARMExceptions.FIQ) != 0) && !mCPSR.FIQDisable)
                    {
                        SetExceptionState(ARMExceptions.FIQ);
                    }
                    else if (((mRequestedException & (uint)ARMExceptions.IRQ) != 0) && !mCPSR.IRQDisable)
                    {
                        SetExceptionState(ARMExceptions.IRQ);
                    }
                    else if ((mRequestedException & (uint)ARMExceptions.UndefinedInstruction) != 0)
                    {
                        SetExceptionState(ARMExceptions.UndefinedInstruction);
                    }
                    else if ((mRequestedException & (uint)ARMExceptions.Reset) != 0)
                    {
                        SetExceptionState(ARMExceptions.Reset);
                    }
                    mRequestedException = 0;
                }//if

                //test the PC against valid memory. If it is not within the memory block, we have a problem
                if (!this.InRange(mGPR.PC, opcodeSize))
                {
                    ARMExceptions possibleReason = interruptKind(mGPR.PC);
                    if (possibleReason != ARMExceptions.None)
                    {
                        if (possibleReason == ARMExceptions.SoftwareInterrupt)
                        {
                            ReportRuntimeError(pcBefore, "Unimplemented SWI code: (0x{0:X6})\n" +
                                               "[Check File/Preferences/Plugins to see which SWI sets have been enabled]",
                                               opcode & 0xFFFFFF);
                        }
                        else
                        {
                            ReportRuntimeError(pcBefore, "Unhandled interrupt of kind {0}",
                                               interruptKind(mGPR.PC));
                        }
                        HaltSimulation();
                        mGPR.PC = pcBefore; // leave PC stuck on the interrupting instruction
                    }
                    else
                    {
                        pcOutofRange(pcBefore);
                    }
                }
            }//try
            catch (ARMPluginInterfaces.MemoryAccessException ex)
            {
                ReportRuntimeError(pcBefore, "Attempt to access memory out of valid range: 0x{0:X8}",
                                   ex.Address);
                HaltSimulation();
                mGPR.PC = pcBefore; // leave PC stuck on the bad instruction
            }//catch
        }//Execute
Пример #3
0
 public void RequestException(ARMExceptions exception)
 {
     mRequestedException |= (uint)exception;
 }