Exemplo n.º 1
0
 internal void DataOpHandleSetFlagsAWC_NonCMP(uint opcode, uint Rd, AWCResult awcResult)
 {
     if (Rd == GeneralPurposeRegisters.PCRegisterIndex)
     {
         CPSR.RestoreCPUMode();
     }
     else
     {
         DataOpHandleSetFlagsAWC_CMP(opcode, Rd, awcResult);
     }
 }
Exemplo n.º 2
0
 internal void DataOpHandleSetFlagsLogical_NonCMP(uint opcode, uint Rd, uint result, bool shift_carry)
 {
     if (Rd == GeneralPurposeRegisters.PCRegisterIndex)
     {
         CPSR.RestoreCPUMode();
     }
     else
     {
         DataOpHandleSetFlagsLogical_CMP(opcode, Rd, result, shift_carry);
     }
 }
Exemplo n.º 3
0
        /*----------------------------------------------------------------------------*/



        //----------------------------------------------------------------------------
        internal uint normal_data_op(uint op_code, uint operation)
        {
            //extract the S bit value from the opcode
            bool SBit = ((op_code & s_mask) != 0);

            //extract destination register from opcode
            uint Rd = ((op_code & rd_mask) >> 12);

            //extract operand register and get first operand
            uint Rn = ((op_code & rn_mask) >> 16);
            uint a  = get_reg(Rn);

            bool shift_carry = false;

            uint b;

            if ((op_code & imm_mask) == 0)
            {
                b = b_reg(op_code & op2_mask, ref shift_carry);
            }
            else
            {
                b = b_immediate(op_code & op2_mask, ref shift_carry);
            }

            uint rd = 0;

            switch (operation)                                               /* R15s @@?! */
            {
            case 0x0: rd = a & b; break;                                     //AND

            case 0x1: rd = a ^ b; break;                                     //EOR

            case 0x2: rd = a - b; break;                                     //SUB

            case 0x3: rd = b - a; break;                                     //RSB

            case 0x4: rd = a + b; break;                                     //ADD

            case 0x5: rd = a + b;                                            //ADC
                if (CPSR.cf)
                {
                    ++rd;
                }
                break;

            case 0x6: rd = a - b - 1;                                                   //SBC
                if (CPSR.cf)
                {
                    ++rd;
                }
                break;

            case 0x7: rd = b - a - 1;                                                   //RSC
                if (CPSR.cf)
                {
                    ++rd;
                }
                break;

            case 0x8: rd = a & b; break;                                        //TST

            case 0x9: rd = a ^ b; break;                                        //TEQ

            case 0xa: rd = a - b; break;                                        //CMP

            case 0xb: rd = a + b; break;                                        //CMN

            case 0xc: rd = a | b; break;                                        //ORR

            case 0xd: rd = b; break;                                            //MOV

            case 0xe: rd = a & ~b; break;                                       //BIC

            case 0xf: rd = ~b; break;                                           //MVN
            }//switch

            if ((operation & 0xc) != 0x8)                                                       //Return result unless a compare
            {
                //write result into destination register
                mGPR[Rd] = rd;

                //if S bit is set and if the destination register is r15(pc) then this instruction has
                //special meaning. We are returning from a non-user mode to user-mode.
                //ie  movs pc,r14
                if (SBit && (Rd == GeneralPurposeRegisters.PCRegisterIndex))
                {
                    CPSR.RestoreCPUMode();
                    return(1);
                } //if
            }     //if

            //if S bit is not set, we do not need to set any cpu flags, so we are done here
            if (!SBit)
            {
                return(1);
            }

            switch (operation)
            {                                                           //LOGICALs
            case 0x0:                                                   //AND
            case 0x1:                                                   //EOR
            case 0x8:                                                   //TST
            case 0x9:                                                   //TEQ
            case 0xc:                                                   //ORR
            case 0xd:                                                   //MOV
            case 0xe:                                                   //BIC
            case 0xf:                                                   //MVN
                CPSR.set_NZ(rd);
                CPSR.cf = shift_carry;
                break;

            case 0x2:                                                   //SUB
            case 0xa:                                                   //CMP
                CPSR.set_flags_sub(a, b, rd, true);
                break;

            case 0x6:                                                   //SBC
                CPSR.set_flags_sub(a, b, rd, CPSR.cf);
                break;

            case 0x3:                                                   //RSB
                CPSR.set_flags_sub(b, a, rd, true);
                break;

            case 0x7:                                                   //RSC
                CPSR.set_flags_sub(b, a, rd, CPSR.cf);
                break;

            case 0x4:                                                   //ADD
            case 0xb:                                                   //CMN
                CPSR.set_flags_add(a, b, rd, false);
                break;

            case 0x5:                                                   //ADC
                CPSR.set_flags_add(a, b, rd, CPSR.cf);
                break;

            default: break;
            } //switch
            return(1);
        }     //normal_data_op
Exemplo n.º 4
0
        }        //stm

        /// <summary>
        /// LDM - perform a multi-register load from memory
        /// </summary>
        /// <returns>Number of clock cycles executed</returns>
        internal uint ldm(uint opcode)
        {
            uint mode         = (opcode & 0x01800000) >> 23;              //isolate PU bits
            uint Rn           = (opcode & rn_mask) >> 16;                 //get base register
            uint reg_list     = opcode & 0x0000ffff;                      //get the register list
            bool writeback    = (opcode & write_back_mask) != 0;          //determine writeback flag
            bool userModeLoad = ((opcode & 0x00400000) != 0);             //get user mode load flag

            uint address = Utils.valid_address(get_reg(Rn));              //make sure it is word aligned.
            int  first_reg;
            uint count      = bit_count(reg_list, out first_reg);
            bool includesPC = ((reg_list & 0x00008000) != 0);

            uint new_base;

            switch (mode)
            {
            case 0: new_base = address - 4 * count; address = new_base + 4; break;                      //DA (Decrement After)

            case 1: new_base = address + 4 * count; break;                                              //IA (Increment After)

            case 2: new_base = address - 4 * count; address = new_base; break;                          //DB (Decrement Before)

            case 3: new_base = address + 4 * count; address = address + 4; break;                       //IB (Increment Before)

            default: return(0);
            }            //switch

            if (writeback)
            {
                mGPR[Rn] = new_base;
            }

            uint reg         = 0;
            uint extraCycles = 0;

            //check
            while (reg_list != 0)
            {
                if (Utils.lsb(reg_list))
                {
                    uint data = this.GetMemory(address, ARMPluginInterfaces.MemorySize.Word);
                    if (reg == GeneralPurposeRegisters.PCRegisterIndex)
                    {                    //We are loading a new value into the PC, check if entering Thumb or ARM mode
                        extraCycles = 2;

                        //if the user mode flag is set and r15 is being loaded, we are executing
                        //LDM(3) and returning from an exception. We may be returning to Thumb mode or
                        //ARM mode. In each case, force align the returning address.
                        if (userModeLoad)
                        {                                  //we are returning from an exception, check if returning to ARM or Thumb mode
                            if ((CPSR.SPSR & 0x0020) != 0) //check thumb bit of saved CPSR
                            {
                                data = data & 0xfffffffe;  //returning to thumb mode, force align HWord
                            }
                            else
                            {
                                data = data & 0xfffffffc;                                   //returning to arm mode, force align Word
                            }
                        }
                        else if ((data & 0x01) != 0)
                        {                        //Entering Thumb mode. Make sure destination address is HWord aligned
                            CPSR.tf = true;
                            data    = data & 0xfffffffe;
                        }                        //if
                        else
                        {                        //Entering ARM mode. Make sure destination address is Word aligned
                            CPSR.tf = false;
                            data    = data & 0xfffffffc;
                        }                //else
                    }                    //if

                    if (userModeLoad & !includesPC)
                    {
                        mGPR.SetUserModeRegister(reg, data);
                    }
                    else
                    {
                        mGPR[reg] = data;
                    }

                    address += 4;
                }                //if
                reg_list >>= 1;
                ++reg;
            }            //while

            //if the PC was loaded during this instruction and the user mode load was specified
            //then we are returning from an exception.
            if (includesPC && userModeLoad)
            {
                CPSR.RestoreCPUMode();
            }

            return(2 + count + extraCycles);
        }        //ldm