<?xml-stylesheet type="text/xsl" encoding="UTF-8" href="iform.xsl" version="1.0"?>
<!DOCTYPE instructionsection PUBLIC "-//ARM//DTD instructionsection //EN" "iform-p.dtd">
<!-- Copyright (c) 2010-2025 Arm Limited or its affiliates. All rights reserved. -->
<!-- This document is Non-Confidential. This document may only be used and distributed in accordance with the terms of the agreement entered into by Arm and the party that Arm delivered this document to. -->
<instructionsection id="CPYPWTN" title="CPYPWTN, CPYMWTN, CPYEWTN -- A64" type="instruction">
  <docvars>
    <docvar key="instr-class" value="general"/>
    <docvar key="isa" value="A64"/>
  </docvars>
  <heading>CPYPWTN, CPYMWTN, CPYEWTN</heading>
  <desc>
    <brief>
      <para>Memory copy, writes unprivileged, reads and writes non-temporal</para>
    </brief>
    <authored>
      <para>These instructions copy a requested number of bytes in memory from a source address to a
destination address. The prologue, main, and epilogue instructions are expected to be run
in succession and to appear consecutively in memory: CPYPWTN, then CPYMWTN,
and then CPYEWTN.</para>
      <para>CPYPWTN performs some preconditioning of the arguments suitable for using the
CPYMWTN instruction, and copies an <arm-defined-word>IMPLEMENTATION DEFINED</arm-defined-word> portion of the requested
number of bytes. CPYMWTN copies a further <arm-defined-word>IMPLEMENTATION DEFINED</arm-defined-word> portion of the
remaining bytes. CPYEWTN copies any final remaining bytes.</para>
      <note>
        <para>The ability to copy an <arm-defined-word>IMPLEMENTATION DEFINED</arm-defined-word> number of bytes allows an implementation
to optimize how the bytes being copied are divided between the different instructions.</para>
      </note>
      <para>For more information on exceptions specific to memory copy instructions,
see <xref linkend="ARMARM_MDSec.memcpy_and_memset_exceptions">Memory Copy and Memory Set exceptions</xref>.</para>
      <para>The architecture supports two algorithms for the memory copy: option A and option B.
Which algorithm is used is <arm-defined-word>IMPLEMENTATION DEFINED</arm-defined-word>.</para>
      <note>
        <para>Portable software should not assume that the choice of algorithm is constant.</para>
      </note>
      <para>For CPYPWTN:</para>
      <list type="unordered">
        <listitem>
          <content>
            <para>If Xn[63:55] != '000000000', the copy size Xn is saturated to <hexnumber>0x007FFFFFFFFFFFFF</hexnumber>.</para>
          </content>
        </listitem>
        <listitem>
          <content>
            <para>After saturation is performed, the direction of the memory copy is based on
the following:</para>
            <para>If (Xs[55:0] &gt; Xd[55:0]) and (Xd[55:0] + saturated copy size) &gt; Xs[55:0], then the direction is forward.</para>
            <para>If (Xs[55:0] &lt; Xd[55:0]) and (Xs[55:0] + saturated copy size) &gt; Xd[55:0], then the direction is backward.</para>
            <para>Otherwise, the direction is an <arm-defined-word>IMPLEMENTATION DEFINED</arm-defined-word> choice between forward and backward.</para>
          </content>
        </listitem>
      </list>
      <para>On completion of CPYPWTN, option A:</para>
      <list type="unordered">
        <listitem>
          <content>PSTATE.{N,Z,C,V} are set to {0,0,0,0}.</content>
        </listitem>
        <listitem>
          <content>If the copy is in the forward direction, then:<list type="unordered">
              <listitem>
                <content>Xn holds -1 times the number of bytes in the saturated copy size remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs holds the original Xs + saturated copy size.</content>
              </listitem>
              <listitem>
                <content>Xd holds the original Xd + saturated copy size.</content>
              </listitem>
            </list>
          </content>
        </listitem>
        <listitem>
          <content>If the copy is in the backward direction, then:<list type="unordered">
              <listitem>
                <content>Xn holds the number of bytes in the saturated copy size remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs and Xd are unchanged.</content>
              </listitem>
            </list>
          </content>
        </listitem>
      </list>
      <para>On completion of CPYPWTN, option B:</para>
      <list type="unordered">
        <listitem>
          <content>If the copy is in the forward direction, then:<list type="unordered">
              <listitem>
                <content>Xn holds the number of bytes in the saturated copy size remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs holds the lowest address that has not been copied from.</content>
              </listitem>
              <listitem>
                <content>Xd holds the lowest address that has not been copied to.</content>
              </listitem>
              <listitem>
                <content>PSTATE.{N,Z,C,V} are set to {0,0,1,0}.</content>
              </listitem>
            </list>
          </content>
        </listitem>
        <listitem>
          <content>If the copy is in the backward direction, then:<list type="unordered">
              <listitem>
                <content>Xn holds the number of bytes in the saturated copy size remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs holds the highest address that has not been copied from + 1.</content>
              </listitem>
              <listitem>
                <content>Xd holds the highest address that has not been copied to + 1.</content>
              </listitem>
              <listitem>
                <content>PSTATE.{N,Z,C,V} are set to {1,0,1,0}.</content>
              </listitem>
            </list>
          </content>
        </listitem>
      </list>
      <para>For CPYMWTN, option A, when PSTATE.C = 0:</para>
      <list type="unordered">
        <listitem>
          <content>Xn holds a signed 64-bit integer.</content>
        </listitem>
        <listitem>
          <content>If the copy is in the forward direction (Xn holds a negative number), then:<list type="unordered">
              <listitem>
                <content>Xn holds -1 times the number of bytes remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs holds the lowest address to be copied from - Xn.</content>
              </listitem>
              <listitem>
                <content>Xd holds the lowest address to be copied to - Xn.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction, Xn holds -1 times the number of bytes
remaining to be copied.</content>
              </listitem>
            </list>
          </content>
        </listitem>
        <listitem>
          <content>If the copy is in the backward direction (Xn holds a positive number), then:<list type="unordered">
              <listitem>
                <content>Xn holds the number of bytes remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs holds the highest address to be copied from + 1 - Xn.</content>
              </listitem>
              <listitem>
                <content>Xd holds the highest address to be copied to + 1 - Xn.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction, Xn holds the number of bytes
remaining to be copied.</content>
              </listitem>
            </list>
          </content>
        </listitem>
      </list>
      <para>For CPYMWTN, option B, when PSTATE.C = 1:</para>
      <list type="unordered">
        <listitem>
          <content>Xn holds the number of bytes remaining to be copied.</content>
        </listitem>
        <listitem>
          <content>If the copy is in the forward direction (PSTATE.N == 0), then:<list type="unordered">
              <listitem>
                <content>Xs holds the lowest address to be copied from.</content>
              </listitem>
              <listitem>
                <content>Xd holds the lowest address to be copied to.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction:<list type="unordered">
                    <listitem>
                      <content>Xn holds the number of bytes remaining to be copied.</content>
                    </listitem>
                    <listitem>
                      <content>Xs holds the lowest address that has not been copied from.</content>
                    </listitem>
                    <listitem>
                      <content>Xd holds the lowest address that has not been copied to.</content>
                    </listitem>
                  </list>
                </content>
              </listitem>
            </list>
          </content>
        </listitem>
        <listitem>
          <content>If the copy is in the backward direction (PSTATE.N == 1), then:<list type="unordered">
              <listitem>
                <content>Xs holds the highest address to be copied from + 1.</content>
              </listitem>
              <listitem>
                <content>Xd holds the highest address to be copied to + 1.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction:<list type="unordered">
                    <listitem>
                      <content>Xn holds the number of bytes remaining to be copied.</content>
                    </listitem>
                    <listitem>
                      <content>Xs holds the highest address that has not been copied from + 1.</content>
                    </listitem>
                    <listitem>
                      <content>Xd holds the highest address that has not been copied to + 1.</content>
                    </listitem>
                  </list>
                </content>
              </listitem>
            </list>
          </content>
        </listitem>
      </list>
      <para>For CPYEWTN, option A, when PSTATE.C = 0:</para>
      <list type="unordered">
        <listitem>
          <content>Xn holds a signed 64-bit integer.</content>
        </listitem>
        <listitem>
          <content>If the copy is in the forward direction (Xn holds a negative number), then:<list type="unordered">
              <listitem>
                <content>Xn holds -1 times the number of bytes remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs holds the lowest address to be copied from - Xn.</content>
              </listitem>
              <listitem>
                <content>Xd holds the lowest address to be copied to - Xn.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction, Xn holds 0.</content>
              </listitem>
            </list>
          </content>
        </listitem>
        <listitem>
          <content>If the copy is in the backward direction (Xn holds a positive number), then:<list type="unordered">
              <listitem>
                <content>Xn holds the number of bytes remaining to be copied.</content>
              </listitem>
              <listitem>
                <content>Xs holds the highest address to be copied from + 1 - Xn.</content>
              </listitem>
              <listitem>
                <content>Xd holds the highest address to be copied to + 1 - Xn.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction, Xn holds 0.</content>
              </listitem>
            </list>
          </content>
        </listitem>
      </list>
      <para>For CPYEWTN, option B, when PSTATE.C = 1:</para>
      <list type="unordered">
        <listitem>
          <content>Xn holds the number of bytes remaining to be copied.</content>
        </listitem>
        <listitem>
          <content>If the copy is in the forward direction (PSTATE.N == 0), then:<list type="unordered">
              <listitem>
                <content>Xs holds the lowest address to be copied from.</content>
              </listitem>
              <listitem>
                <content>Xd holds the lowest address to be copied to.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction:<list type="unordered">
                    <listitem>
                      <content>Xn holds 0.</content>
                    </listitem>
                    <listitem>
                      <content>Xs holds the lowest address that has not been copied from.</content>
                    </listitem>
                    <listitem>
                      <content>Xd holds the lowest address that has not been copied to.</content>
                    </listitem>
                  </list>
                </content>
              </listitem>
            </list>
          </content>
        </listitem>
        <listitem>
          <content>If the copy is in the backward direction (PSTATE.N == 1), then:<list type="unordered">
              <listitem>
                <content>Xs holds the highest address to be copied from + 1.</content>
              </listitem>
              <listitem>
                <content>Xd holds the highest address to be copied to + 1.</content>
              </listitem>
              <listitem>
                <content>On completion of the instruction:<list type="unordered">
                    <listitem>
                      <content>Xn holds 0.</content>
                    </listitem>
                    <listitem>
                      <content>Xs holds the highest address that has not been copied from + 1.</content>
                    </listitem>
                    <listitem>
                      <content>Xd holds the highest address that has not been copied to + 1.</content>
                    </listitem>
                  </list>
                </content>
              </listitem>
            </list>
          </content>
        </listitem>
      </list>
      <para>Explicit Memory Write  effects produced by the instruction behave as if the instruction was
  executed at EL0 if the <xref linkend="ARMARM_Effective_value">Effective value</xref> of
  PSTATE.UAO is 0 and either:</para>
      <list type="unordered">
        <listitem>
          <content>The instruction is executed at EL1.</content>
        </listitem>
        <listitem>
          <content>The instruction is executed at EL2 when the <xref linkend="ARMARM_Effective_value">Effective value</xref>
  of <register_link id="AArch64-hcr_el2.xml" state="AArch64">HCR_EL2()</register_link>.{E2H, TGE} is '11'.</content>
        </listitem>
      </list>
      <para>Otherwise, the Explicit Memory Write  effects operate with the restrictions determined by
  the Exception level at which the instruction is executed.</para>
    </authored>
    <encodingnotes>
      <para>For information about the <arm-defined-word>CONSTRAINED UNPREDICTABLE</arm-defined-word> behavior of this instruction, see <xref linkend="CJAEGDJC">Architectural Constraints on UNPREDICTABLE behaviors</xref>, and particularly <xref linkend="CEGCIDDEI6">Memory Copy and Memory Set CPY*</xref> and <xref linkend="ARMARM_CEGCCGAE">Crossing a page boundary with different memory types or Shareability attributes</xref>.</para>
    </encodingnotes>
  </desc>
  <alias_list howmany="0"/>
  <classes>
    <iclass name="Integer" oneof="1" id="iclass_integer" no_encodings="3" isa="A64">
      <docvars>
        <docvar key="instr-class" value="general"/>
        <docvar key="isa" value="A64"/>
      </docvars>
      <iclassintro count="3"/>
      <arch_variants>
        <arch_variant feature="FEAT_MOPS" name="v8Ap8"/>
      </arch_variants>
      <regdiagram form="32" psname="A64.ldst.memcms.CPYPWTN_CPY_memcms" tworows="1">
        <box hibit="31" width="2" name="sz" usename="1">
          <c colspan="2"/>
        </box>
        <box hibit="29" width="3" settings="3">
          <c>0</c>
          <c>1</c>
          <c>1</c>
        </box>
        <box hibit="26" name="o0" usename="1" settings="1" psbits="x">
          <c>1</c>
        </box>
        <box hibit="25" width="2" settings="2">
          <c>0</c>
          <c>1</c>
        </box>
        <box hibit="23" width="2" name="op1" usename="1">
          <c colspan="2"/>
        </box>
        <box hibit="21" width="1" settings="1">
          <c>0</c>
        </box>
        <box hibit="20" width="5" name="Rs" usename="1">
          <c colspan="5"/>
        </box>
        <box hibit="15" width="4" name="op2" usename="1" settings="4" psbits="xxxx">
          <c>1</c>
          <c>1</c>
          <c>0</c>
          <c>1</c>
        </box>
        <box hibit="11" width="2" settings="2">
          <c>0</c>
          <c>1</c>
        </box>
        <box hibit="9" width="5" name="Rn" usename="1">
          <c colspan="5"/>
        </box>
        <box hibit="4" width="5" name="Rd" usename="1">
          <c colspan="5"/>
        </box>
      </regdiagram>
      <encoding name="CPYPWTN_CPY_memcms" oneofinclass="3" oneof="3" label="Prologue" bitdiffs="op1 == 00">
        <docvars>
          <docvar key="instr-class" value="general"/>
          <docvar key="isa" value="A64"/>
          <docvar key="pme" value="pme-prologue"/>
          <docvar key="mnemonic" value="CPYPWTN"/>
        </docvars>
        <box hibit="23" width="2" name="op1">
          <c>0</c>
          <c>0</c>
        </box>
        <asmtemplate><text>CPYPWTN  [</text><a hover="For the &quot;Prologue&quot; variant: is the 64-bit name of the general-purpose register that holds the destination address and is updated by the instruction, encoded in the &quot;Rd&quot; field." link="XdOrXZR">&lt;Xd&gt;</a><text>]!, [</text><a hover="For the &quot;Prologue&quot; variant: is the 64-bit name of the general-purpose register that holds the source address and is updated by the instruction, encoded in the &quot;Rs&quot; field." link="XsOrXZR__5">&lt;Xs&gt;</a><text>]!, </text><a hover="For the &quot;Prologue&quot; variant: is the 64-bit name of the general-purpose register that holds the number of bytes to be transferred and is updated by the instruction to encode the remaining size and destination, encoded in the &quot;Rn&quot; field." link="XnOrXZR__2">&lt;Xn&gt;</a><text>!</text></asmtemplate>
      </encoding>
      <encoding name="CPYMWTN_CPY_memcms" oneofinclass="3" oneof="3" label="Main" bitdiffs="op1 == 01">
        <docvars>
          <docvar key="instr-class" value="general"/>
          <docvar key="isa" value="A64"/>
          <docvar key="pme" value="pme-main"/>
          <docvar key="mnemonic" value="CPYMWTN"/>
        </docvars>
        <box hibit="23" width="2" name="op1">
          <c>0</c>
          <c>1</c>
        </box>
        <asmtemplate><text>CPYMWTN  [</text><a hover="For the &quot;Epilogue&quot; and &quot;Main&quot; variants: is the 64-bit name of the general-purpose register that holds an encoding of the destination address, encoded in the &quot;Rd&quot; field." link="XdOrXZR__2">&lt;Xd&gt;</a><text>]!, [</text><a hover="For the &quot;Epilogue&quot; and &quot;Main&quot; variants: is the 64-bit name of the general-purpose register that holds an encoding of the source address, encoded in the &quot;Rs&quot; field." link="XsOrXZR__6">&lt;Xs&gt;</a><text>]!, </text><a hover="For the &quot;Main&quot; variant: is the 64-bit name of the general-purpose register that holds an encoding of the number of bytes to be transferred, encoded in the &quot;Rn&quot; field." link="XnOrXZR__3">&lt;Xn&gt;</a><text>!</text></asmtemplate>
      </encoding>
      <encoding name="CPYEWTN_CPY_memcms" oneofinclass="3" oneof="3" label="Epilogue" bitdiffs="op1 == 10">
        <docvars>
          <docvar key="instr-class" value="general"/>
          <docvar key="isa" value="A64"/>
          <docvar key="pme" value="pme-epilogue"/>
          <docvar key="mnemonic" value="CPYEWTN"/>
        </docvars>
        <box hibit="23" width="2" name="op1">
          <c>1</c>
          <c>0</c>
        </box>
        <asmtemplate><text>CPYEWTN  [</text><a hover="For the &quot;Epilogue&quot; and &quot;Main&quot; variants: is the 64-bit name of the general-purpose register that holds an encoding of the destination address, encoded in the &quot;Rd&quot; field." link="XdOrXZR__2">&lt;Xd&gt;</a><text>]!, [</text><a hover="For the &quot;Epilogue&quot; and &quot;Main&quot; variants: is the 64-bit name of the general-purpose register that holds an encoding of the source address, encoded in the &quot;Rs&quot; field." link="XsOrXZR__6">&lt;Xs&gt;</a><text>]!, </text><a hover="For the &quot;Epilogue&quot; variant: is the 64-bit name of the general-purpose register that holds an encoding of the number of bytes to be transferred and is set to zero on completion of the instruction, encoded in the &quot;Rn&quot; field." link="XnOrXZR__4">&lt;Xn&gt;</a><text>!</text></asmtemplate>
      </encoding>
      <ps_section howmany="1">
        <ps name="A64.ldst.memcms.CPYPWTN_CPY_memcms" sections="1" secttype="noheading">
          <pstext mayhavelinks="1" section="Decode" rep_section="decode">if !IsFeatureImplemented(FEAT_MOPS) || sz != '00' then EndOfDecode(Decode_UNDEF); end;

var memcpy : CPYParams;
memcpy.d = UInt(Rd);
memcpy.s = UInt(Rs);
memcpy.n = UInt(Rn);
let options : bits(4) = op2;
let rnontemporal : boolean = options[3] == '1';
let wnontemporal : boolean = options[2] == '1';
case op1 of
    when '00' =&gt; memcpy.stage = MOPSStage_Prologue;
    when '01' =&gt; memcpy.stage = MOPSStage_Main;
    when '10' =&gt; memcpy.stage = MOPSStage_Epilogue;
end;</pstext></ps>
      </ps_section>
    </iclass>
  </classes>
  <explanations scope="all">
    <explanation enclist="CPYPWTN_CPY_memcms" symboldefcount="1">
      <symbol link="XdOrXZR">&lt;Xd&gt;</symbol>
      <account encodedin="Rd">
        <intro>
          <para>For the "Prologue" variant: is the 64-bit name of the general-purpose register that holds the destination address and is updated by the instruction, encoded in the "Rd" field.</para>
        </intro>
      </account>
    </explanation>
    <explanation enclist="CPYMWTN_CPY_memcms, CPYEWTN_CPY_memcms" symboldefcount="2">
      <symbol link="XdOrXZR__2">&lt;Xd&gt;</symbol>
      <account encodedin="Rd">
        <intro>
          <para>For the "Epilogue" and "Main" variants: is the 64-bit name of the general-purpose register that holds an encoding of the destination address, encoded in the "Rd" field.</para>
        </intro>
      </account>
    </explanation>
    <explanation enclist="CPYPWTN_CPY_memcms" symboldefcount="1">
      <symbol link="XsOrXZR__5">&lt;Xs&gt;</symbol>
      <account encodedin="Rs">
        <intro>
          <para>For the "Prologue" variant: is the 64-bit name of the general-purpose register that holds the source address and is updated by the instruction, encoded in the "Rs" field.</para>
        </intro>
      </account>
    </explanation>
    <explanation enclist="CPYMWTN_CPY_memcms, CPYEWTN_CPY_memcms" symboldefcount="2">
      <symbol link="XsOrXZR__6">&lt;Xs&gt;</symbol>
      <account encodedin="Rs">
        <intro>
          <para>For the "Epilogue" and "Main" variants: is the 64-bit name of the general-purpose register that holds an encoding of the source address, encoded in the "Rs" field.</para>
        </intro>
      </account>
    </explanation>
    <explanation enclist="CPYPWTN_CPY_memcms" symboldefcount="1">
      <symbol link="XnOrXZR__2">&lt;Xn&gt;</symbol>
      <account encodedin="Rn">
        <intro>
          <para>For the "Prologue" variant: is the 64-bit name of the general-purpose register that holds the number of bytes to be transferred and is updated by the instruction to encode the remaining size and destination, encoded in the "Rn" field.</para>
        </intro>
      </account>
    </explanation>
    <explanation enclist="CPYMWTN_CPY_memcms" symboldefcount="2">
      <symbol link="XnOrXZR__3">&lt;Xn&gt;</symbol>
      <account encodedin="Rn">
        <intro>
          <para>For the "Main" variant: is the 64-bit name of the general-purpose register that holds an encoding of the number of bytes to be transferred, encoded in the "Rn" field.</para>
        </intro>
      </account>
    </explanation>
    <explanation enclist="CPYEWTN_CPY_memcms" symboldefcount="3">
      <symbol link="XnOrXZR__4">&lt;Xn&gt;</symbol>
      <account encodedin="Rn">
        <intro>
          <para>For the "Epilogue" variant: is the 64-bit name of the general-purpose register that holds an encoding of the number of bytes to be transferred and is set to zero on completion of the instruction, encoded in the "Rn" field.</para>
        </intro>
      </account>
    </explanation>
  </explanations>
  <ps_section howmany="1">
    <ps name="A64.ldst.memcms.CPYPWTN_CPY_memcms" sections="1" secttype="Operation">
      <pstext mayhavelinks="1" section="Execute" rep_section="execute">CheckMOPSEnabled();

CheckCPYConstrainedUnpredictable(memcpy.n, memcpy.d, memcpy.s);

memcpy.nzcv        = PSTATE.[N,Z,C,V];
memcpy.toaddress   = X{64}(memcpy.d);
memcpy.fromaddress = X{64}(memcpy.s);

if memcpy.stage == MOPSStage_Prologue then
    memcpy.cpysize = UInt(X{64}(memcpy.n));
else
    memcpy.cpysize = SInt(X{64}(memcpy.n));
end;

memcpy.implements_option_a = CPYOptionA();

let rprivileged : boolean = (if options[1] == '1' then AArch64_IsUnprivAccessPriv()
                                else PSTATE.EL != EL0);
let wprivileged : boolean = (if options[0] == '1' then AArch64_IsUnprivAccessPriv()
                                else PSTATE.EL != EL0);

let raccdesc : AccessDescriptor = CreateAccDescMOPS(MemOp_LOAD,  rprivileged, rnontemporal);
let waccdesc : AccessDescriptor = CreateAccDescMOPS(MemOp_STORE, wprivileged, wnontemporal);

if memcpy.stage == MOPSStage_Prologue then
    if memcpy.cpysize &gt; ArchMaxMOPSCPYSize then
        memcpy.cpysize = ArchMaxMOPSCPYSize;
    end;

    memcpy.forward = IsMemCpyForward(memcpy);

    if memcpy.implements_option_a then
        memcpy.nzcv = '0000';
        if memcpy.forward then
            // Copy in the forward direction offsets the arguments.
            memcpy.toaddress   = memcpy.toaddress   + memcpy.cpysize;
            memcpy.fromaddress = memcpy.fromaddress + memcpy.cpysize;
            memcpy.cpysize     = 0 - memcpy.cpysize;
        end;
    else
        if !memcpy.forward then
            // Copy in the reverse direction offsets the arguments.
            memcpy.toaddress   = memcpy.toaddress   + memcpy.cpysize;
            memcpy.fromaddress = memcpy.fromaddress + memcpy.cpysize;
            memcpy.nzcv = '1010';
        else
            memcpy.nzcv = '0010';
        end;
    end;
end;

memcpy.stagecpysize = MemCpyStageSize(memcpy);

if memcpy.stage != MOPSStage_Prologue then
    memcpy.forward = memcpy.cpysize &lt; 0 || (!memcpy.implements_option_a &amp;&amp; memcpy.nzcv[3] == '0');
    CheckMemCpyParams(memcpy, options);
end;

var copied : integer;
var iswrite : boolean;
var memaddrdesc : AddressDescriptor;
var memstatus : PhysMemRetStatus;
var fault : boolean = FALSE;
var B : <a link="MOPSBlockSize" file="shared_pseudocode.xml" hover="type MOPSBlockSize">MOPSBlockSize</a> = 0;

if memcpy.implements_option_a then
    while memcpy.stagecpysize != 0 &amp;&amp; !fault looplimit ArchMaxMOPSCPYSize do
        // IMP DEF selection of the block size that is worked on. While many
        // implementations might make this constant, that is not assumed.
        B = CPYSizeChoice(memcpy);

        if memcpy.forward then
            assert B &lt;= -1 * memcpy.stagecpysize;
            (copied, iswrite, memaddrdesc, memstatus) = MemCpyBytes(
                                                                memcpy.toaddress + memcpy.cpysize,
                                                                memcpy.fromaddress + memcpy.cpysize,
                                                                memcpy.forward, B,
                                                                raccdesc, waccdesc);
            if copied != B then
                fault = TRUE;
            else
                memcpy.cpysize      = memcpy.cpysize      + B;
                memcpy.stagecpysize = memcpy.stagecpysize + B;
            end;

        else
            assert B &lt;= memcpy.stagecpysize;
            memcpy.cpysize      = memcpy.cpysize      - B;
            memcpy.stagecpysize = memcpy.stagecpysize - B;

            (copied, iswrite, memaddrdesc, memstatus) = MemCpyBytes(
                                                                memcpy.toaddress   + memcpy.cpysize,
                                                                memcpy.fromaddress + memcpy.cpysize,
                                                                memcpy.forward, B, raccdesc,
                                                                waccdesc);
            if copied != B then
                fault               = TRUE;
                memcpy.cpysize      = memcpy.cpysize      + B;
                memcpy.stagecpysize = memcpy.stagecpysize + B;
            end;
        end;
    end;

else
    while memcpy.stagecpysize &gt; 0 &amp;&amp; !fault looplimit ArchMaxMOPSCPYSize do
        // IMP DEF selection of the block size that is worked on. While many
        // implementations might make this constant, that is not assumed.
        B = CPYSizeChoice(memcpy);
        assert B &lt;= memcpy.stagecpysize;

        if memcpy.forward then
            (copied, iswrite, memaddrdesc, memstatus) = MemCpyBytes(memcpy.toaddress,
                                                                    memcpy.fromaddress,
                                                                    memcpy.forward, B,
                                                                    raccdesc, waccdesc);
            if copied != B then
                fault = TRUE;
            else
                memcpy.fromaddress = memcpy.fromaddress + B;
                memcpy.toaddress   = memcpy.toaddress   + B;
            end;
        else
            (copied, iswrite, memaddrdesc, memstatus) = MemCpyBytes(memcpy.toaddress   - B,
                                                                    memcpy.fromaddress - B,
                                                                    memcpy.forward, B,
                                                                    raccdesc, waccdesc);

            if copied != B then
                fault = TRUE;
            else
                memcpy.fromaddress = memcpy.fromaddress - B;
                memcpy.toaddress   = memcpy.toaddress   - B;
            end;
        end;

        if !fault then
            memcpy.cpysize      = memcpy.cpysize        - B;
            memcpy.stagecpysize = memcpy.stagecpysize   - B;
        end;
    end;
end;

UpdateCpyRegisters(memcpy, fault, copied);

if fault then
    if IsFault(memaddrdesc) then
        AArch64_Abort(memaddrdesc.fault);
    else
        let accdesc : AccessDescriptor = if iswrite then waccdesc else raccdesc;
        HandleExternalAbort(memstatus, iswrite, memaddrdesc, B, accdesc);
    end;
end;

if memcpy.stage == MOPSStage_Prologue then
    PSTATE.[N,Z,C,V] = memcpy.nzcv;
end;</pstext></ps>
  </ps_section>
  <timestamp>2026-03-12 12:23:09</timestamp>
  <commit_id>2025-09_rel_asl1</commit_id>
</instructionsection>
