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
}//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)
}//thumb_branch1 internal uint data0(uint opcode) { if ((opcode & 0x1800) != 0x1800) { //Either LSL,LSR or ASR uint Rm = ((opcode >> 3) & 0x07); //Source register uint Rd = (opcode & 0x07); //Destination register uint shift = ((opcode >> 6) & 0x1f); //Shift value uint result = 0; bool cf = (this.CPSR.cf); switch (opcode & 0X1800) { case 0x0000: //LSL(1) result = lsl(get_reg(Rm), shift, ref cf); break; case 0x0800: //LSR(1) //A shift value of 0 means shift by 32 if (shift == 0) { shift = 32; } result = lsr(get_reg(Rm), shift, ref cf); break; case 0x1000: //ASR(1) //A shift value of 0 means shift by 32 if (shift == 0) { shift = 32; } result = asr(get_reg(Rm), shift, ref cf); break; default: //Can't get here, but just in case return(1); }//switch this.CPSR.cf = cf; this.CPSR.set_NZ(result); mGPR[Rd] = result; }//if else {//Either ADD or SUB uint Rd = (opcode & 0x07); //Destination register uint Rn = ((opcode >> 3) & 0x07); uint Rm = ((opcode >> 6) & 0x07); uint op2; if ((opcode & 0x0400) == 0) {//ADD(3) or SUB(3) op2 = get_reg(Rm); } else {//ADD(1) or SUB(1) op2 = Rm; } uint result; uint op1 = get_reg(Rn); if ((opcode & 0x0200) == 0) { result = op1 + op2; CPSR.set_flags_add(op1, op2, result, false); } else { result = op1 - op2; CPSR.set_flags_sub(op1, op2, result, true); } //else mGPR[Rd] = result; } //else return(1); }//data0(Thumb)