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
/*----------------------------------------------------------------------------*/ //---------------------------------------------------------------------------- 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
/// <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
}//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)