LDTP

Load unprivileged pair of registers

This instruction calculates an address from a base register value and an immediate offset, loads two 64-bit doublewords from memory, and writes them to two registers.

Explicit Memory effects produced by the instruction behave as if the instruction was executed at EL0 if the Effective value of PSTATE.UAO is 0 and either:

  • The instruction is executed at EL1.
  • The instruction is executed at EL2 when the Effective value of HCR_EL2.{E2H, TGE} is {1, 1}.
  • Otherwise, the Explicit Memory effects operate with the restrictions determined by the Exception level at which the instruction is executed.

    For information about addressing modes, see Load/Store addressing modes.

    Encoding: Post-index

    Variants: FEAT_LSUI (ARMv9.6)

    313029282726252423222120191817161514131211109876543210
    1110100011
    opcVRLimm7Rt2RnRt

    LDTP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>

    Decoding algorithm

    if !IsFeatureImplemented(FEAT_LSUI) then EndOfDecode(Decode_UNDEF);
    boolean wback = TRUE;
    constant boolean postindex = TRUE;

    Encoding: Pre-index

    Variants: FEAT_LSUI (ARMv9.6)

    313029282726252423222120191817161514131211109876543210
    1110100111
    opcVRLimm7Rt2RnRt

    LDTP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!

    Decoding algorithm

    if !IsFeatureImplemented(FEAT_LSUI) then EndOfDecode(Decode_UNDEF);
    boolean wback = TRUE;
    constant boolean postindex = FALSE;

    Encoding: Signed offset

    Variants: FEAT_LSUI (ARMv9.6)

    313029282726252423222120191817161514131211109876543210
    1110100101
    opcVRLimm7Rt2RnRt

    LDTP <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]

    Decoding algorithm

    if !IsFeatureImplemented(FEAT_LSUI) then EndOfDecode(Decode_UNDEF);
    boolean wback = FALSE;
    constant boolean postindex = FALSE;

    Operation

    constant integer t = UInt(Rt);
    constant integer t2 = UInt(Rt2);
    constant integer n = UInt(Rn);
    constant boolean nontemporal = FALSE;
    constant integer scale = 2 + UInt(opc<1>);
    constant integer datasize = 64;
    constant bits(64) offset = LSL(SignExtend(imm7, 64), scale);
    constant boolean tagchecked = wback || n != 31;
    
    boolean rt_unknown = FALSE;
    boolean wb_unknown = FALSE;
    
    if wback && (t == n || t2 == n) && n != 31 then
        constant Constraint c = ConstrainUnpredictable(Unpredictable_WBOVERLAPLD);
        assert c IN {Constraint_WBSUPPRESS, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP};
        case c of
            when Constraint_WBSUPPRESS wback = FALSE;        // Writeback is suppressed
            when Constraint_UNKNOWN    wb_unknown = TRUE;    // Writeback is UNKNOWN
            when Constraint_UNDEF      EndOfDecode(Decode_UNDEF);
            when Constraint_NOP        EndOfDecode(Decode_NOP);
    
    if t == t2 then
        constant Constraint c = ConstrainUnpredictable(Unpredictable_LDPOVERLAP);
        assert c IN {Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP};
        case c of
            when Constraint_UNKNOWN    rt_unknown = TRUE;    // Result is UNKNOWN
            when Constraint_UNDEF      EndOfDecode(Decode_UNDEF);
            when Constraint_NOP        EndOfDecode(Decode_NOP);
    bits(64) address;
    bits(64) address2;
    bits(datasize) data1;
    bits(datasize) data2;
    constant integer dbytes = datasize DIV 8;
    
    constant boolean privileged = AArch64.IsUnprivAccessPriv();
    constant AccessDescriptor accdesc = CreateAccDescGPR(MemOp_LOAD, nontemporal, privileged,
                                                         tagchecked);
    
    if n == 31 then
        CheckSPAlignment();
        address = SP[64];
    else
        address = X[n, 64];
    
    if !postindex then
        address = AddressAdd(address, offset, accdesc);
    
    if accdesc.ispair then
        constant bits(2*datasize) full_data = Mem[address, 2 * dbytes, accdesc];
        if BigEndian(accdesc.acctype) then
            data2 = full_data<(datasize-1):0>;
            data1 = full_data<(2*datasize-1):datasize>;
        else
            data1 = full_data<(datasize-1):0>;
            data2 = full_data<(2*datasize-1):datasize>;
    else
        address2 = AddressIncrement(address, dbytes, accdesc);
        data1 = Mem[address , dbytes, accdesc];
        data2 = Mem[address2, dbytes, accdesc];
    
    if rt_unknown then
        data1 = bits(datasize) UNKNOWN;
        data2 = bits(datasize) UNKNOWN;
    
    X[t,  datasize] = data1;
    X[t2, datasize] = data2;
    
    if wback then
        if wb_unknown then
            address = bits(64) UNKNOWN;
        elsif postindex then
            address = AddressAdd(address, offset, accdesc);
        if n == 31 then
            SP[64] = address;
        else
            X[n, 64] = address;

    Explanations

    <Xt1>: Is the 64-bit name of the first general-purpose register to be transferred, encoded in the "Rt" field.
    <Xt2>: Is the 64-bit name of the second general-purpose register to be transferred, encoded in the "Rt2" field.
    <Xn|SP>: Is the 64-bit name of the general-purpose base register or stack pointer, encoded in the "Rn" field.
    <imm>: For the "Post-index" and "Pre-index" variants: is the signed immediate byte offset, a multiple of 8 in the range -512 to 504, encoded in the "imm7" field as <imm>/8.
    <imm>: For the "Signed offset" variant: is the optional signed immediate byte offset, a multiple of 8 in the range -512 to 504, defaulting to 0 and encoded in the "imm7" field as <imm>/8.

    Operational Notes

    If PSTATE.DIT is 1, the timing of this instruction is insensitive to the value of the data being loaded or stored.