Example #1
0
        internal uint data1(uint opcode)
        {
            uint Rd  = (opcode >> 8) & 0x07;
            uint imm = opcode & 0x00ff;
            uint result;

            switch (opcode & 0x1800)
            {
            case 0x0000:
                //MOV (1)
                result = imm;
                CPSR.set_NZ(result);
                mGPR[Rd] = result;
                break;

            case 0x0800:
            {        //CMP (1)
                uint op1 = get_reg(Rd);
                result = (op1 - imm);
                CPSR.set_flags_sub(op1, imm, result, true);
            } break;

            case 0x1000:
            {        //ADD (2)
                uint op1 = get_reg(Rd);
                result = (op1 + imm);
                CPSR.set_flags_add(op1, imm, result, false);
                mGPR[Rd] = result;
            } break;

            case 0x1800:
            {        //SUB (2)
                uint op1 = get_reg(Rd);
                result = (op1 - imm);
                CPSR.set_flags_sub(op1, imm, result, true);
                mGPR[Rd] = result;
            } break;
            } //switch
            return(1);
        }     //data1
Example #2
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
Example #3
0
        /// <summary>
        /// Perform the ARM instruction MUL
        /// </summary>
        /// <param name="op_code"></param>
        /// <returns></returns>
        internal uint multiply(uint opcode)
        {
            uint Rs = ((opcode & rs_mask) >> 8);
            uint Rm = (opcode & rm_mask);
            uint Rd = ((opcode & rd_mask) >> 12);
            uint Rn = ((opcode & rn_mask) >> 16);

            uint RsData = get_reg(Rs);
            uint RmData = get_reg(Rm);
            uint M      = calculateMultM(RsData);

            if ((opcode & mul_long_bit) == 0)
            {//Normal:mla,mul
                uint cycles = 1;
                uint acc    = (RmData * RsData);
                if ((opcode & mul_acc_bit) != 0)
                {
                    acc += get_reg(Rd);
                    ++cycles;
                }
                mGPR[Rn] = acc;

                if ((opcode & s_mask) != 0)
                {
                    CPSR.set_NZ(acc);//flags
                }
                return(cycles + M);
            }//if
            else
            {//Long:xMLAL,xMULL
                uint cycles = 2;
                bool sign   = false;

                if ((opcode & 0x00400000) != 0)
                {//Signed
                    if (Utils.msb(RmData))
                    {
                        RmData = ~RmData + 1;
                        sign   = true;
                    }
                    if (Utils.msb(RsData))
                    {
                        RsData = ~RsData + 1;
                        sign   = !sign;
                    }
                }//if

                //Everything now `positive
                uint tl = (RmData & 0x0000ffff) * (RsData & 0x0000ffff);
                uint th = ((RmData >> 16) & 0X0000ffff) * ((RsData >> 16) & 0X0000ffff);
                uint tm = ((RmData >> 16) & 0X0000ffff) * (RsData & 0X0000ffff);

                RmData = ((RsData >> 16) & 0X0000ffff) * (RmData & 0X0000ffff);  /* Rm no longer needed */
                tm     = tm + RmData;
                if (tm < RmData)
                {
                    th = th + 0X00010000;                                    /* Propagate carry */
                }
                tl = tl + (tm << 16);
                if (tl < (tm << 16))
                {
                    th = th + 1;
                }
                th = th + ((tm >> 16) & 0X0000ffff);

                if (sign)
                {
                    th = ~th;
                    tl = ~tl + 1;
                    if (tl == 0)
                    {
                        th = th + 1;
                    }
                }

                if ((opcode & mul_acc_bit) != 0)
                {
                    ++cycles;
                    tm = tl + get_reg(Rd);
                    if (tm < tl)
                    {
                        th = th + 1;//Propagate carry
                    }
                    tl  = tm;
                    th += get_reg(Rn);
                }

                mGPR[Rd] = tl;
                mGPR[Rn] = th;

                if ((opcode & s_mask) != 0)
                {
                    CPSR.set_NZ(th | (((tl >> 16) | tl) & 0x0000ffff));
                }
                return(cycles + M);
            } //else
        }     //multiply
Example #4
0
        }//data0(Thumb)

        internal uint data_transfer(uint opcode)
        {
            if ((opcode & 0x1000) == 0)
            {         //NOT load/store
                if ((opcode & 0x0800) == 0)
                {     //NOT load literal pool
                    if ((opcode & 0x0400) == 0)
                    { //Data processing
                        uint Rd = (opcode & 0x07);
                        uint Rm = ((opcode >> 3) & 7);

                        uint op1 = get_reg(Rd);
                        uint op2 = get_reg(Rm);
                        uint result;

                        //data processing opcode
                        switch (opcode & 0x03c0)
                        {
                        case 0x0000:
                            //AND
                            result = op1 & op2;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                            break;

                        case 0x0040:
                            //EOR
                            result = op1 ^ op2;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                            break;

                        case 0x0080:
                        {
                            //LSL(2)
                            bool cf = CPSR.cf;
                            result  = lsl(op1, op2 & 0x00ff, ref cf);
                            CPSR.cf = cf;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                        } break;

                        case 0x00c0:
                            //LSR(2)
                        {
                            bool cf = CPSR.cf;
                            result  = lsr(op1, op2 & 0x00ff, ref cf);
                            CPSR.cf = cf;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                        } break;

                        case 0x0100:
                            //ASR (2)
                        {
                            bool cf = CPSR.cf;
                            result  = asr(op1, op2 & 0x00ff, ref cf);
                            CPSR.cf = cf;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                        } break;

                        case 0x0140:
                            //ADC
                            result = op1 + op2;
                            if (CPSR.cf)
                            {
                                result++;    //Add CF
                            }
                            CPSR.set_flags_add(op1, op2, result, CPSR.cf);
                            mGPR[Rd] = result;
                            break;

                        case 0x0180:
                            //SBC
                            result = op1 - op2 - 1;
                            if (CPSR.cf)
                            {
                                result++;    //Add CF
                            }
                            CPSR.set_flags_sub(op1, op2, result, CPSR.cf);
                            mGPR[Rd] = result;
                            break;

                        case 0x01c0:
                        {        //ROR
                            bool cf = CPSR.cf;
                            result  = ror(op1, op2 & 0x00ff, ref cf);
                            CPSR.cf = cf;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                        } break;

                        case 0x0200:
                            //TST
                            CPSR.set_NZ(op1 & op2);
                            break;

                        case 0x0240:
                            //NEG
                            result = (uint)(0 - (int)op2);
                            CPSR.set_flags_sub(0, op2, result, true);
                            mGPR[Rd] = result;
                            break;

                        case 0x0280:
                            //CMP(2)
                            CPSR.set_flags_sub(op1, op2, op1 - op2, true);
                            break;

                        case 0x02c0:
                            //CMN
                            CPSR.set_flags_add(op1, op2, op1 + op2, false);
                            break;

                        case 0x0300:
                            //ORR
                            result = op1 | op2;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                            break;

                        case 0x0340:
                            //MUL
                            result = op1 * op2;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                            break;

                        case 0x0380:
                            //BIC
                            result = op1 & ~op2;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                            break;

                        case 0x03c0:
                            //MVN
                            result = ~op2;
                            CPSR.set_NZ(result);
                            mGPR[Rd] = result;
                            break;
                        }//switch
                    }
                    else
                    {//special data processing -- NO FLAG UPDATE
                        //ADD(4),CMP(3),MOV(2),BX,BLX
                        uint Rd = ((opcode & 0x0080) >> 4) | (opcode & 0x07);
                        uint Rm = ((opcode >> 3) & 15);

                        switch (opcode & 0x0300)
                        {
                        case 0x0000:
                            //ADD (4) high registers
                            mGPR[Rd] = get_reg(Rd) + get_reg(Rm);
                            break;

                        case 0x0100:
                        {        //CMP (3) high registers
                            uint op1 = get_reg(Rd);
                            uint op2 = get_reg(Rm);
                            CPSR.set_flags_sub(op1, op2, op1 - op2, true);
                        } break;

                        case 0x0200:
                        {        //MOV (2) high registers
                            uint op2 = get_reg(Rm);
                            if (Rd == GeneralPurposeRegisters.PCRegisterIndex)
                            {
                                op2 = op2 & 0xfffffffe;        //Tweak mov to PC
                            }
                            mGPR[Rd] = op2;
                        } break;

                        case 0x0300:
                        {        //BX/BLX Rm
                            bool link = ((opcode & 0x0080) != 0);
                            old_bx((opcode >> 3) & 0x0f, link);
                        } break;
                        }//switch
                    }
                }
                else
                {//load from literal pool -- LDR PC
                    uint Rd      = ((opcode >> 8) & 0x07);
                    uint address = (((opcode & 0x00ff) << 2)) + (get_reg(GeneralPurposeRegisters.PCRegisterIndex) & 0xfffffffc);
                    mGPR[Rd] = GetMemory(address, ARMPluginInterfaces.MemorySize.Word);
                }//else
            }
            else
            {
                data_transfer_load_store(opcode);
            }
            return(1);
        }//data_transfer(Thumb)