STTP

Store unprivileged pair of registers

This instruction calculates an address from a base register value and an immediate offset, and stores two 64-bit doublewords to the calculated address, from 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
    1110100010
    opcVRLimm7Rt2RnRt

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

    Decoding algorithm

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

    Encoding: Pre-index

    Variants: FEAT_LSUI (ARMv9.6)

    313029282726252423222120191817161514131211109876543210
    1110100110
    opcVRLimm7Rt2RnRt

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

    Decoding algorithm

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

    Encoding: Signed offset

    Variants: FEAT_LSUI (ARMv9.6)

    313029282726252423222120191817161514131211109876543210
    1110100100
    opcVRLimm7Rt2RnRt

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

    Decoding algorithm

    if !IsFeatureImplemented(FEAT_LSUI) then EndOfDecode(Decode_UNDEF);
    constant 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;
    if wback && (t == n || t2 == n) && n != 31 then
        constant Constraint c = ConstrainUnpredictable(Unpredictable_WBOVERLAPST);
        assert c IN {Constraint_NONE, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP};
        case c of
            when Constraint_NONE       rt_unknown = FALSE;   // Value stored is pre-writeback
            when Constraint_UNKNOWN    rt_unknown = TRUE;    // Value stored 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_STORE, 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 rt_unknown && t == n then
        data1 = bits(datasize) UNKNOWN;
    else
        data1 = X[t, datasize];
    if rt_unknown && t2 == n then
        data2 = bits(datasize) UNKNOWN;
    else
        data2 = X[t2, datasize];
    
    if accdesc.ispair then
        constant bits(2*datasize) full_data = (if BigEndian(accdesc.acctype) then data1:data2
                                                     else data2:data1);
        Mem[address, 2 * dbytes, accdesc] = full_data;
    else
        address2 = AddressIncrement(address, dbytes, accdesc);
        Mem[address , dbytes, accdesc] = data1;
        Mem[address2, dbytes, accdesc] = data2;
    
    if wback then
        if 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.