STP

Store pair of registers

This instruction calculates an address from a base register value and an immediate offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from two registers. For information about addressing modes, see Load/Store addressing modes.

Encoding: Post-index

313029282726252423222120191817161514131211109876543210
x010100010
opcVRLimm7Rt2RnRt

32-bit (opc == 00)

STP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>

64-bit (opc == 10)

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

Decoding algorithm

constant boolean wback = TRUE;
constant boolean postindex = TRUE;

Encoding: Pre-index

313029282726252423222120191817161514131211109876543210
x010100110
opcVRLimm7Rt2RnRt

32-bit (opc == 00)

STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!

64-bit (opc == 10)

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

Decoding algorithm

constant boolean wback = TRUE;
constant boolean postindex = FALSE;

Encoding: Signed offset

313029282726252423222120191817161514131211109876543210
x010100100
opcVRLimm7Rt2RnRt

32-bit (opc == 00)

STP <Wt1>, <Wt2>, [<Xn|SP>{, #<imm>}]

64-bit (opc == 10)

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

Decoding algorithm

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 = 8 << scale;
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 = PSTATE.EL != EL0;
constant boolean ispair = IsFeatureImplemented(FEAT_LSE2);

constant AccessDescriptor accdesc = CreateAccDescGPR(MemOp_STORE, nontemporal, privileged,
                                                     tagchecked, ispair);

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

<Wt1>: Is the 32-bit name of the first general-purpose register to be transferred, encoded in the "Rt" field.
<Wt2>: Is the 32-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 "32-bit Post-index" and "32-bit Pre-index" variants: is the signed immediate byte offset, a multiple of 4 in the range -256 to 252, encoded in the "imm7" field as <imm>/4.
<imm>: For the "64-bit Post-index" and "64-bit 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 "32-bit Signed offset" variant: is the optional signed immediate byte offset, a multiple of 4 in the range -256 to 252, defaulting to 0 and encoded in the "imm7" field as <imm>/4.
<imm>: For the "64-bit 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.
<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.

Operational Notes

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