This is a cross-referenced version of mvch.plan, to download the unmodified source try mvch.plan.
#PROGRAM       /MVCH(15AM,22AM,DBM,EBM)
#PAGE

#              MVCH (LEN, FROM, TO)

#              Attempts to optimise to word moves when it can
#              allows any length to be moved

#              Internal use - calling sequence is 
#              X4 = source (Character address)
#              X5 = dest   (Character address)
#              X6 = chars to move
#              CALL 1  MVCHARS

#              On exit X4 points after last char moved from
#                      X5 points after last char moved to

#              All other registers may be trashed

#PROGRAM

      LDX   0  6              [ get chars to move
      SBNC  0  7              [ at least one whole word?
      BCS      TRAIL          [ if not, simple char move

      LDX   0  4              [ get source addr
      ERX   0  5              [ compare with dest
      SLC   0  2              [ move diff in offset to low bits
      ANDN  0  #3             [ mask boring
      BNZ   0  CHAR           [ jump if char offsets different
      
#              Char offsets are same, move 'till word boundary

      LDX   0  4
      SLC   0  2               [ so just what is the offset, anyway?
      ANDN  0  #3

      BZE   0  WORD            [ jif already on word boundary
      LDN   1  4
      SBX   1  0               [ move 1..3 chars before word boundary
      MVCH  4  0(1) 
     
      SBX   6  1               [ amount left to move      

WORD  LDX   3  6               [ chars left to move
      SRL   3  2               [ convert to words

      LDX   7  3               [ words to move

W512  SBNC  7  512             [ more than 512 words to move?
      BCS      REST
      MOVE  4  0               [ move 512 words
      ADN   4  512             [ increment pointers
      ADN   5  512
      SBN   6  2048            [ decrement chars left to move
      BRN      W512

REST  MOVE  4  0(3)            [ move words
      ADX   4  3
      ADX   5  3               [ MOVE, unlike MVCH, doesn't update
      SLL   3  2               [ How many chars were moved?
      SBX   6  3               [ decrement chars left to move

TRAIL BZE   6  BYE             [ jump if move finished
      STO   6  3
      MVCH  4  0(3)            [ move trailing chars

BYE   EXIT  1  0               [ All done.

#              If source and dest don't have same alignment we'll have
#              to use MVCH for whole move

CHAR  LDX   7  6                [ more than 512 chars?
      SBNC  7  512
      BCS      TRAIL            [ no, just do the end bit

      MVCH  4  0                [ move 512 chars
      STO   7  6
      BRN      CHAR

#END
#FINISH