const char* ARMv7DOpcodeAddSubtractImmediate8::format() { appendInstructionName(opName(), !inITBlock()); appendRegisterName(rdn()); appendSeparator(); appendUnsignedImmediate(immediate8()); return m_formatBuffer; }
const char* ARMv7DOpcodeMoveImmediateT1::format() { appendInstructionName("mov", !inITBlock()); appendRegisterName(rd()); appendSeparator(); appendUnsignedImmediate(immediate8()); return m_formatBuffer; }
const char* ARMv7DOpcodeAddSubtractT1::format() { appendInstructionName(opName(), !inITBlock()); appendRegisterName(rd()); appendSeparator(); appendRegisterName(rn()); appendSeparator(); appendRegisterName(rm()); return m_formatBuffer; }
const char* ARMv7DOpcodeDataProcessingRegisterT1::format() { appendInstructionName(opName(), inITBlock() && (!(op() == 0x8) || (op() == 0xa) || (op() == 0xb))); appendRegisterName(rdn()); appendSeparator(); appendRegisterName(rm()); if (op() == 0x9) // rsb T1 appendString(", #0"); else if (op() == 0xd) { // mul T1 appendSeparator(); appendRegisterName(rdn()); } return m_formatBuffer; }
/*Test Register Encoding T1 TST<c> <Rn>,<Rm> 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |0 1 0 0 0 0| 1 0 0 0| Rm | Rn | unused | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rn> Specifies the register that contains the first operand. <Rm> Specifies the register that is optionally shifted and used as the second operand. <shift> Specifies the shift to apply to the value read from <Rm>. If <shift> is omitted, no shift is applied and both encodings are permitted. If <shift> is specified, only encoding T2 is permitted. The possible shifts and how they are encoded are described in Shifts applied to a register on page A6-12. */ void TSTRegisterT1(uint32_t instruction) { uint32_t Rm = getBits(instruction,21,19); uint32_t Rn = getBits(instruction,18,16); if(inITBlock()) { if( checkCondition(cond) ) executeTSTRegister(Rn, Rm, 0, 0); shiftITState(); } else executeTSTRegister(Rn, Rm, 0, 0); coreReg[PC] += 2; }
/*Load Register(Immediate) Encoding T3 LDR<c>.W <Rt>,[<Rn>{,#<imm12>}] 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 1 1 1 1| 0 0| 0 1 1 0 1| Rn | Rt | imm12 | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the destination register. This register is allowed to be the SP. It is also allowed to be the PC, provided the instruction is either outside an IT block or the last instruction of an IT block. If it is the PC, it causes a branch to the address (data) loaded into the PC. <Rn> Specifies the base register. This register is allowed to be the SP. If this register is the PC, see LDR (literal) on page A6-90. +/- Is + or omitted to indicate that the immediate offset is added to the base register value (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different instructions are generated for #0 and #-0. <imm> Specifies the immediate offset added to or subtracted from the value of <Rn> to form the address. Allowed values are multiples of 4 in the range 0-124 for encoding T1, multiples of 4 in the range 0-1020 for encoding T2, any value in the range 0-4095 for encoding T3, and any value in the range 0-255 for encoding T4. For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0. */ void LDRImmediateT3(uint32_t instruction) { uint32_t imm12 = getBits(instruction,11,0); uint32_t Rn = getBits(instruction,19,16); uint32_t Rt = getBits(instruction,15,12); uint32_t address = coreReg[Rn] + imm12; if(inITBlock()) { if( checkCondition(cond) ) { if(Rt == PC) { if( getBits(address,1,0) == 0b00) writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); else { //placePCtoVectorTable(UsageFault); ThrowError(); } } else writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); } shiftITState(); } else { if(Rt == PC) { if( getBits(address,1,0) == 0b00) writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); else { //placePCtoVectorTable(UsageFault); ThrowError(); } } else writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); } if(Rt != PC) coreReg[PC] += 4; }
const char* ARMv7DOpcode::disassemble(uint16_t*& currentPC) { const char* result; fetchOpcode(currentPC); if (is32BitInstruction()) result = reinterpret_cast<ARMv7D32BitOpcode*>(this)->doDisassemble(); else result = reinterpret_cast<ARMv7D16BitOpcode*>(this)->doDisassemble(); if (startingITBlock()) m_ITConditionIndex = 0; else if (inITBlock() && (++m_ITConditionIndex >= m_ITBlocksize)) endITBlock(); return result; }
/*Load Register Signed Byte (immediate) Encoding T1 LDRSB<c> <Rt>,[<Rn>,#<imm12>] 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 1 1 1 1 1| 0 0| 1 1 0 0 1| Rn | Rt | imm12 | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the destination register. <Rn> Specifies the base register. This register is allowed to be the SP. If this register is the PC, see LDRSB (literal) on page A6-120. +/- Is + or omitted to indicate that the immediate offset is added to the base register value (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different instructions are generated for #0 and #-0. <imm> Specifies the immediate offset added to or subtracted from the value of <Rn> to form the address. The range of allowed values is 0-4095 for encoding T1, and 0-255 for encoding T2. For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0. */ void LDRSBImmediateT1(uint32_t instruction) { uint32_t Rn = getBits(instruction,19,16); uint32_t Rt = getBits(instruction,15,12); uint32_t imm12 = getBits(instruction,11,0); uint32_t address = coreReg[Rn] + imm12; if(inITBlock()) { if( checkCondition(cond) ) writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) ); shiftITState(); } else writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) ); coreReg[PC] += 4; }
/*Load Register Byte Unprivileged Encoding T1 LDRBT<c> <Rt>,[<Rn>,#<imm8>] 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 1 1 1 1 1| 0 0| 0 0 0 0 1| Rn | Rt | 1| 1 1 0| imm8 | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the destination register. <Rn> Specifies the base register. This register is allowed to be the SP. <imm> Specifies the immediate offset added to the value of <Rn> to form the address. The range of allowed values is 0-255. <imm> can be omitted, meaning an offset of 0. */ void LDRBT(uint32_t instruction) { uint32_t Rn = getBits(instruction,19,16); uint32_t Rt = getBits(instruction,15,12); uint32_t imm8 = getBits(instruction,7,0); uint32_t address = coreReg[Rn] + imm8; if(inITBlock()) { if( checkCondition(cond) ) writeToCoreRegisters(Rt , loadByteFromMemory(address, 1) ); shiftITState(); } else writeToCoreRegisters(Rt , loadByteFromMemory(address, 1) ); coreReg[PC] += 4; }
/*Load Register Halfword (immediate) Encoding T1 LDRH<c> <Rt>,[<Rn>{,#<imm5>}] 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 0 0 0 1| imm5 | Rn | Rt | unused | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the destination register. <Rn> Specifies the base register. This register is allowed to be the SP. If this register is the PC, see LDRH (literal) on page A6-96. +/- Is + or omitted to indicate that the immediate offset is added to the base register value (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different instructions are generated for #0 and #-0. <imm> Specifies the immediate offset added to or subtracted from the value of <Rn> to form the address. The range of allowed values is 0-31 for encoding T1, 0-4095 for encoding T2, and 0-255 for encoding T3. For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0. The pre-UAL syntax LDR<c>B is equivalent to LDRB<c>. */ void LDRHImmediateT1(uint32_t instruction) { uint32_t imm5 = getBits(instruction,26,22); uint32_t Rn = getBits(instruction,21,19); uint32_t Rt = getBits(instruction,18,16); uint32_t address = coreReg[Rn] + 2*imm5; if(inITBlock()) { if( checkCondition(cond) ) writeToCoreRegisters(Rt , loadByteFromMemory(address, 2) ); shiftITState(); } else writeToCoreRegisters(Rt , loadByteFromMemory(address, 2) ); coreReg[PC] += 2; }
/* Test Register Encoding T2 TST<c>.W <Rn>,<Rm>{,<shift>} 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 1 1 0 1 |0 1 |0 0 0 0 |1| Rn |0| imm3 |1 1 1 1|imm2| t | Rm | t => type where: <c><q> See Standard assembler syntax fields on page A6-7. <Rn> Specifies the register that contains the first operand. <Rm> Specifies the register that is optionally shifted and used as the second operand. <shift> Specifies the shift to apply to the value read from <Rm>. If <shift> is omitted, no shift is applied and both encodings are permitted. If <shift> is specified, only encoding T2 is permitted. The possible shifts and how they are encoded are described in Shifts applied to a register on page A6-12. */ void TSTRegisterT2(uint32_t instruction) { uint32_t Rm = getBits(instruction, 3, 0); uint32_t Rn = getBits(instruction, 19, 16); uint32_t imm2 = getBits(instruction, 7, 6); uint32_t imm3 = getBits(instruction, 14, 12); uint32_t shiftType = getBits(instruction, 5, 4); uint32_t shiftImm = (imm3 << 2 ) | imm2; if(inITBlock()) { if( checkCondition(cond) ) executeTSTRegister(Rn, Rm, shiftType, shiftImm); shiftITState(); } else executeTSTRegister(Rn, Rm, shiftType, shiftImm); coreReg[PC] += 4; }
const char* ARMv7DOpcodeLogicalImmediateT1::format() { if (!op() && !immediate5()) { // mov T2 appendInstructionName("movs"); appendRegisterName(rd()); appendSeparator(); appendRegisterName(rm()); return m_formatBuffer; } appendInstructionName(opName(), !inITBlock()); appendRegisterName(rd()); appendSeparator(); appendRegisterName(rm()); appendSeparator(); appendUnsignedImmediate((op() && !immediate5()) ? 32 : immediate5()); return m_formatBuffer; }
/* VCVT, VCVTR (between floating-point and integer) Floating-point Convert (between floating-point and integer) converts a value in a register from floating-point to a 32-bit integer, or from a 32-bit integer to floating-point, and places the result in a second register. VCVT{R}<c>.S32.F32 <Sd>, <Sm> VCVT{R}<c>.U32.F32 <Sd>, <Sm> VCVT<c>.F32.<Tm> <Sd>, <Sm> 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 1 1 1| 1 1 1 0 1| D| 1 1 1 1| RM | Vd | 1 0 1|sz op 1 M 0| Vm | where : R If R is specified, the operation uses the rounding mode specified by the FPSCR. Encoded as op = 0. If R is omitted. the operation uses the Round towards Zero rounding mode. For syntaxes in which R is optional, op is encoded as 1 if R is omitted. <c>, <q> See Standard assembler syntax fields on page A7-175. <Tm> The data type for the operand. It must be one of: S32 Encoded as op = 1. U32 Encoded as op = 0. <Sd>, <Sm> The destination register and the operand register, for a single-precision operand or result. <Sd>, <Dm> The destination register and the operand register, for a double-precision operand. <Dd>, <Sm> The destination register and the operand register, for a double-precision result. */ void VCVTR(uint32_t instruction) { uint32_t Vd = getBits(instruction,15,12); uint32_t Vm = getBits(instruction,3,0); uint32_t sz = getBits(instruction,8,8); uint32_t M = getBits(instruction,5,5); uint32_t D = getBits(instruction,22,22); uint32_t op = getBits(instruction,7,7); uint32_t RM = getBits(instruction,17,16); uint32_t m = determineRegisterBasedOnSZ(M, Vm, sz); executeFPUChecking(); bool unsign = (getBits(instruction,16,16) == 0); bool roundZero = (op == 1); uint32_t d = (Vd << 1) | D; if(inITBlock()) { if( checkCondition(cond) ) { if(sz == 1) ThrowError(); //undefined instruction if sz == 1 in FPv4-SP architecture else writeSinglePrecision(d, FPToFixed(fpuSinglePrecision[m], 32, 0, unsign, roundZero, fPSCR) ); } shiftITState(); } else { if(sz == 1) ThrowError(); //undefined instruction if sz == 1 in FPv4-SP architecture else writeSinglePrecision(d, FPToFixed(fpuSinglePrecision[m], 32, 0, unsign, roundZero, fPSCR) ); } coreReg[PC] += 4; }
/* VMUL Floating-point Multiply multiplies two floating-point register values, and places the result in the destination floating-point register. VMUL<c>.F32 <Sd>, <Sn>, <Sm> VMUL<c>.F64 <Dd>, <Dn>, <Dm> 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 1 1 0| 1 1 1 0 0|D| 1 0| Vn | Vd | 1 0 1|sz|N 0 M 0| Vm | where : <c>, <q> See Standard assembler syntax fields on page A7-175. <Sd>, <Sn>, <Sm> The destination single-precision register and the operand single-precision registers. <Dd>, <Dn>, <Dm> The destination double-precision register and the operand double-precision registers. */ void VMUL(uint32_t instruction) { uint32_t sz = getBits(instruction,8,8); uint32_t op = getBits(instruction,6,6); uint32_t Vm = getBits(instruction,3,0); uint32_t Vn = getBits(instruction,19,16); uint32_t Vd = getBits(instruction,15,12); uint32_t D = getBits(instruction,22,22); uint32_t N = getBits(instruction,7,7); uint32_t M = getBits(instruction,5,5); uint32_t d = determineRegisterBasedOnSZ(D, Vd, sz); uint32_t n = determineRegisterBasedOnSZ(N, Vn, sz); uint32_t m = determineRegisterBasedOnSZ(M, Vm, sz); executeFPUChecking(); if(inITBlock()) { if( checkCondition(cond) ) { if(sz == 1) ThrowError(); //undefined instruction if sz == 1 in FPv4-SP architecture else writeSinglePrecision(d, FPMulSinglePrecision( fpuSinglePrecision[d], fpuSinglePrecision[m], fPSCR) ); } shiftITState(); } else { if(sz == 1) ThrowError(); //undefined instruction if sz == 1 in FPv4-SP architecture else writeSinglePrecision(d, FPMulSinglePrecision( fpuSinglePrecision[d], fpuSinglePrecision[m], fPSCR) ); } coreReg[PC] += 4; }
/*Load Register(Immediate) Encoding T2 LDR<c> <Rt>,[SP{,#<imm8>}] 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 0 0 1 1| Rt | imm8 | unused | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the destination register. This register is allowed to be the SP. It is also allowed to be the PC, provided the instruction is either outside an IT block or the last instruction of an IT block. If it is the PC, it causes a branch to the address (data) loaded into the PC. <Rn> Specifies the base register. This register is allowed to be the SP. If this register is the PC, see LDR (literal) on page A6-90. +/- Is + or omitted to indicate that the immediate offset is added to the base register value (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different instructions are generated for #0 and #-0. <imm> Specifies the immediate offset added to or subtracted from the value of <Rn> to form the address. Allowed values are multiples of 4 in the range 0-124 for encoding T1, multiples of 4 in the range 0-1020 for encoding T2, any value in the range 0-4095 for encoding T3, and any value in the range 0-255 for encoding T4. For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0. */ void LDRImmediateT2(uint32_t instruction) { uint32_t imm8 = getBits(instruction,23,16); uint32_t Rt = getBits(instruction,26,24); if(inITBlock()) { if( checkCondition(cond) ) { uint32_t address = coreReg[SP] + 4*imm8; coreReg[Rt] = loadByteFromMemory(address, 4); //load a word from the address and store it into the register } shiftITState(); } else { uint32_t address = coreReg[SP] + 4*imm8; coreReg[Rt] = loadByteFromMemory(address, 4); //load a word from the address and store it into the register } coreReg[PC] += 2; }
/*Load Register Signed Byte (immediate) Encoding T2 LDRSB<c> <Rt>,[<Rn>,#-<imm8>] LDRSB<c> <Rt>,[<Rn>],#+/-<imm8> LDRSB<c> <Rt>,[<Rn>,#+/-<imm8>]! 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | 1 1 1 1 1| 0 0| 1 0 0 0 1| Rn | Rt |1 |P| U|W| imm8 | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the destination register. <Rn> Specifies the base register. This register is allowed to be the SP. If this register is the PC, see LDRSB (literal) on page A6-120. +/- Is + or omitted to indicate that the immediate offset is added to the base register value (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different instructions are generated for #0 and #-0. <imm> Specifies the immediate offset added to or subtracted from the value of <Rn> to form the address. The range of allowed values is 0-4095 for encoding T1, and 0-255 for encoding T2. For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0. */ void LDRSBImmediateT2(uint32_t instruction) { uint32_t imm8 = getBits(instruction, 7, 0); uint32_t Rt = getBits(instruction,15,12); uint32_t Rn = getBits(instruction,19,16); uint32_t W = getBits(instruction,8,8); uint32_t U = getBits(instruction,9,9); uint32_t P = getBits(instruction,10,10); uint32_t address; if(U == 1) address = coreReg[Rn] + imm8; else address = coreReg[Rn] - imm8; int check = isOffPostOrPreIndex(P,W); if(check == UNDEFINED || Rt == 0b1111 || Rn == 0b1111) { //placePCtoVectorTable(UsageFault); ThrowError(); } if(inITBlock()) { if( checkCondition(cond) ) { if(check == OFFINDEX) writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) ); else if(check == PREINDEX) { writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) ); coreReg[Rn] = address; } else { writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(coreReg[Rn], 1), 8) ); coreReg[Rn] = address; } } shiftITState(); } else { if(check == OFFINDEX) writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) ); else if(check == PREINDEX) { writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) ); coreReg[Rn] = address; } else { writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(coreReg[Rn], 1), 8) ); coreReg[Rn] = address; } } coreReg[PC] += 4; }
/* VCVT, VCVTR (between floating-point and integer) Floating-point Convert (between floating-point and integer) converts a value in a register from floating-point to a 32-bit integer, or from a 32-bit integer to floating-point, and places the result in a second register. The fixed-point value can be 16-bit or 32-bit. Conversions from fixed-point values take their operand from the low-order bits of the source register and ignore any remaining bits. Signed conversions to fixed-point values sign-extend the result value to the destination register width. Unsigned conversions to fixed-point values zero-extend the result value to the destination register width. VCVT<c>.<Td>.F32 <Sd>, <Sd>, #<fbits> VCVT<c>.F32.<Td> <Sd>, <Sd>, #<fbits> 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 1 1 0| 1 1 1 0 1| D| 1 1 1 op| 1 U| Vd | 1 0 1|sf sx 1 i 0| imm4 | where : <c>, <q> See Standard assembler syntax fields on page A7-175. <Td> The data type for the fixed-point number. It must be one of: S16 Encoded as U = 0, sx = 0. U16 Encoded as U = 1, sx = 0 S32 Encoded as U = 0, sx = 1. U32 Encoded as U = 1, sx = 1. <Sd> The destination and operand register, for a single-precision operand. <Dd> The destination and operand register, for a double-precision operand. <fbits> The number of fraction bits in the fixed-point number: • If <Td> is S16 or U16, <fbits> must be in the range 0-16. (16 - <fbits>) is encoded in [imm4,i] • I f <Td> is S32 or U32, <fbits> must be in the range 1-32. (32 - <fbits>) is encoded in [imm4,i]. */ void VCVTT2(uint32_t instruction) { uint32_t Vd = getBits(instruction,15,12); uint32_t imm4 = getBits(instruction,3,0); uint32_t sf = getBits(instruction,8,8); uint32_t sx = getBits(instruction,7,7); uint32_t i = getBits(instruction,5,5); uint32_t op = getBits(instruction,18,18); uint32_t U = getBits(instruction,16,16); uint32_t D = getBits(instruction,22,22); uint32_t d = determineRegisterBasedOnSZ(D, Vd, sf); uint32_t result; executeFPUChecking(); bool roundNearest = false; bool roundZero = false; bool toFixed = (op == 1); bool dpOperation = (sf == 1); bool unsign = (U == 1); uint32_t size = (sx == 0) ? 16 : 32; uint32_t fracBits = size - ( (imm4 << 1) | i); if(toFixed) roundZero = true; else roundNearest = true; if(inITBlock()) { if( checkCondition(cond) ) { if(toFixed) { if(dpOperation) ThrowError(); else { result = FPToFixed(fpuSinglePrecision[d], size, fracBits, unsign, roundZero, fPSCR); if(unsign) writeSinglePrecision(d, result); else writeSinglePrecision(d, signExtend(result, 32) ); } } else { if(dpOperation) ThrowError(); else result = FixedToFP( getBits(fpuSinglePrecision[d], (size-1), 0), 32, fracBits, unsign, roundNearest, fPSCR); writeSinglePrecision(d, result); } } shiftITState(); } else { if(toFixed) { if(dpOperation) ThrowError(); else { result = FPToFixed(fpuSinglePrecision[d], size, fracBits, unsign, roundZero, fPSCR); if(unsign) writeSinglePrecision(d, result); else writeSinglePrecision(d, signExtend(result, 32) ); } } else { if(dpOperation) ThrowError(); else result = FixedToFP( getBits(fpuSinglePrecision[d], (size-1), 0), 32, fracBits, unsign, roundNearest, fPSCR); writeSinglePrecision(d, result); } } coreReg[PC] += 4; }
/*Load Register Dual (immediate) Encoding T1 LDRD<c> <Rt>,<Rt2>,[<Rn>{,#+/-<imm8>}] LDRD<c> <Rt>,<Rt2>,[<Rn>],#+/-<imm8> LDRD<c> <Rt>,<Rt2>,[<Rn>,#+/-<imm8>]! 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 1 1 0 1| 0 0| P U 1 W 1| Rn | Rt | Rt2 | imm8 | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the first source register. <Rt2> Specifies the second source register. <Rn> Specifies the base register. This register is allowed to be the SP. +/- Is + or omitted to indicate that the immediate offset is added to the base register value (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different instructions are generated for #0 and #-0. <imm> Specifies the immediate offset added to or subtracted from the value of <Rn> to form the address. Allowed values are multiples of 4 in the range 0-1020. For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0. */ void LDRDImmediate(uint32_t instruction) { uint32_t imm8 = getBits(instruction, 7, 0); uint32_t Rt = getBits(instruction,15,12); uint32_t Rt2 = getBits(instruction,11,8); uint32_t Rn = getBits(instruction,19,16); uint32_t W = getBits(instruction,21,21); uint32_t U = getBits(instruction,23,23); uint32_t P = getBits(instruction,24,24); uint32_t address; if(U == 1) address = coreReg[Rn] + (imm8 << 2); else address = coreReg[Rn] - (imm8 << 2); int check = isOffPostOrPreIndex(P,W); if(Rn == 0b1111) { LDRDLiteral(instruction); } else { if(inITBlock()) { if( checkCondition(cond) ) { if(check == OFFINDEX) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); writeToCoreRegisters(Rt2 , loadByteFromMemory(address+4, 4) ); } else if(check == PREINDEX) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); writeToCoreRegisters(Rt2 , loadByteFromMemory(address+4, 4) ); coreReg[Rn] = address; } else { writeToCoreRegisters(Rt , loadByteFromMemory(coreReg[Rn], 4) ); writeToCoreRegisters(Rt2 , loadByteFromMemory(coreReg[Rn]+4, 4) ); coreReg[Rn] = address; } } shiftITState(); } else { if(check == OFFINDEX) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); writeToCoreRegisters(Rt2 , loadByteFromMemory(address+4, 4) ); } else if(check == PREINDEX) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); writeToCoreRegisters(Rt2 , loadByteFromMemory(address+4, 4) ); coreReg[Rn] = address; } else { writeToCoreRegisters(Rt , loadByteFromMemory(coreReg[Rn], 4) ); writeToCoreRegisters(Rt2 , loadByteFromMemory(coreReg[Rn]+4, 4) ); coreReg[Rn] = address; } } } coreReg[PC] += 4; }
/*Load Register(Immediate) Encoding T4 LDR<c> <Rt>,[<Rn>,#-<imm8>] LDR<c> <Rt>,[<Rn>],#+/-<imm8> LDR<c> <Rt>,[<Rn>,#+/-<imm8>]! 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |1 1 1 1 1| 0 0| 0 0 1 0 1| Rn | Rt | 1| P U W| imm8 | where: <c><q> See Standard assembler syntax fields on page A6-7. <Rt> Specifies the destination register. This register is allowed to be the SP. It is also allowed to be the PC, provided the instruction is either outside an IT block or the last instruction of an IT block. If it is the PC, it causes a branch to the address (data) loaded into the PC. <Rn> Specifies the base register. This register is allowed to be the SP. If this register is the PC, see LDR (literal) on page A6-90. +/- Is + or omitted to indicate that the immediate offset is added to the base register value (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different instructions are generated for #0 and #-0. <imm> Specifies the immediate offset added to or subtracted from the value of <Rn> to form the address. Allowed values are multiples of 4 in the range 0-124 for encoding T1, multiples of 4 in the range 0-1020 for encoding T2, any value in the range 0-4095 for encoding T3, and any value in the range 0-255 for encoding T4. For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0. */ void LDRImmediateT4(uint32_t instruction) { uint32_t address; uint32_t imm8 = getBits(instruction,7,0); uint32_t Rn = getBits(instruction,19,16); uint32_t Rt = getBits(instruction,15,12); uint32_t P = getBits(instruction,10,10); uint32_t U = getBits(instruction,9,9); uint32_t W = getBits(instruction,8,8); if(inITBlock()) { if( checkCondition(cond) ) { if(U == 1) address = coreReg[Rn] + imm8; else address = coreReg[Rn] - imm8; if(P == 1 && W == 0) { if(Rt == PC) { if( getBits(address,1,0) == 0b00) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); // uint32_t bit0 = getBits(coreReg[Rt], 0, 0); // coreReg[xPSR] = setBits(coreReg[xPSR], bit0, 24, 24); // EPSR.T = coreReg[Rt]<0> } else { //placePCtoVectorTable(UsageFault); ThrowError(); } } else writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); } else if(P == 1 && W == 1) { if(Rt != PC) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); coreReg[Rn] = address; } else { if( getBits(address,1,0) == 0b00) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); // uint32_t bit0 = getBits(coreReg[Rt], 0, 0); // coreReg[xPSR] = setBits(coreReg[xPSR], bit0, 24, 24); // EPSR.T = coreReg[Rt]<0> coreReg[Rn] = address; } else { //placePCtoVectorTable(UsageFault); ThrowError(); } } } else if(P == 0 && W == 1) { if(Rt != PC) { writeToCoreRegisters(Rt , loadByteFromMemory(coreReg[Rn], 4) ); coreReg[Rn] = address; } else { if( getBits(coreReg[Rn],1,0) == 0b00) { writeToCoreRegisters(Rt , loadByteFromMemory(coreReg[Rn], 4) ); // uint32_t bit0 = getBits(coreReg[Rt], 0, 0); // coreReg[xPSR] = setBits(coreReg[xPSR], bit0, 24, 24); // EPSR.T = coreReg[Rt]<0> coreReg[Rn] = address; } else { //placePCtoVectorTable(UsageFault); ThrowError(); } } } } shiftITState(); } else { if(U == 1) address = coreReg[Rn] + imm8; else address = coreReg[Rn] - imm8; if(P == 1 && W == 0) { if(Rt == PC) { if( getBits(address,1,0) == 0b00) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); // uint32_t bit0 = getBits(coreReg[Rt], 0, 0); // coreReg[xPSR] = setBits(coreReg[xPSR], bit0, 24, 24); // EPSR.T = coreReg[Rt]<0> } else { //placePCtoVectorTable(UsageFault); ThrowError(); } } else writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); } else if(P == 1 && W == 1) { if(Rt != PC) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); coreReg[Rn] = address; } else { if( getBits(address,1,0) == 0b00) { writeToCoreRegisters(Rt , loadByteFromMemory(address, 4) ); // uint32_t bit0 = getBits(coreReg[Rt], 0, 0); // coreReg[xPSR] = setBits(coreReg[xPSR], bit0, 24, 24); // EPSR.T = coreReg[Rt]<0> coreReg[Rn] = address; } else { //placePCtoVectorTable(UsageFault); ThrowError(); } } } else if(P == 0 && W == 1) { if(Rt != PC) { writeToCoreRegisters(Rt , loadByteFromMemory(coreReg[Rn], 4) ); coreReg[Rn] = address; } else { if( getBits(coreReg[Rn],1,0) == 0b00) { writeToCoreRegisters(Rt , loadByteFromMemory(coreReg[Rn], 4) ); // uint32_t bit0 = getBits(coreReg[Rt], 0, 0); // coreReg[xPSR] = setBits(coreReg[xPSR], bit0, 24, 24); // EPSR.T = coreReg[Rt]<0> coreReg[Rn] = address; } else { //placePCtoVectorTable(UsageFault); ThrowError(); } } } } if(Rt != PC) coreReg[PC] += 4; }