Exemplo n.º 1
0
const char* ARMv7DOpcodeAddSubtractImmediate8::format()
{
    appendInstructionName(opName(), !inITBlock());
    appendRegisterName(rdn());
    appendSeparator();
    appendUnsignedImmediate(immediate8());

    return m_formatBuffer;
}
Exemplo n.º 2
0
const char* ARMv7DOpcodeMoveImmediateT1::format()
{
    appendInstructionName("mov", !inITBlock());
    appendRegisterName(rd());
    appendSeparator();
    appendUnsignedImmediate(immediate8());

    return m_formatBuffer;
}
Exemplo n.º 3
0
const char* ARMv7DOpcodeAddSubtractT1::format()
{
    appendInstructionName(opName(), !inITBlock());
    appendRegisterName(rd());
    appendSeparator();
    appendRegisterName(rn());
    appendSeparator();
    appendRegisterName(rm());

    return m_formatBuffer;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 12
0
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;  
}
Exemplo n.º 14
0
/* 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;
}