        title   **** Patch to implement SDOS:TIMEOUT handler for 6809 ONLY ****
        list    0
IOPKDEFS equ    1
        include SDOS11DEFS.ASM
        ifund   m6811
m6811   equ     0
        fin
        list    1
; Extends SDOS EXTENSION entry point table
sdos:schedulesoonflag equ $FFB2-8      0 --> run scheduler after next tick
sdos:timeoutcount  equ $FFB2-7         holds # timeouts in list
sdos:timeoutinsert equ $FFB2-6         entry point to insert a new block
sdos:timeoutdelete equ $FFB2-3         entry point to remove a block
        org     $2366
        inc     CODE+sdos:timeoutcount count a timeout block

        ifund   code
code    equ     $B200                  ORG for 60K SDOS11g.689
        fin

        org     CODE+sdos:schedulesoonflag set up extension to SDOS: table
        fcb     1                      scheduler need not run after tick
        fcb     0                      initialize # blocks to zero
        jmp     TIMEOUTINSERT          add a new timeout to TIMEOUT list
        jmp     TIMEOUTDELETE          remove a timeout from TIMEOUT list

        org     CODE+$B265-$B200
TIMEOUTINSERT ; Insert a timeout block into timeout chain
; Called from interrupt level routines with interrupts DISABLED.
; Entered with (X) pointing to timeout block
;       sei                            assert: this has been done by caller
        inc     CODE+sdos:timeoutcount bump # timeout blocks in list
        clr     timeout:fuse,x         store zeroed fuse into timeout block
        clr     timeout:fuse+1,x
        if      m6809
        ldu     CODE+sdos:configuration get pointer to configuration table
        ldd     cnfg:timeoutlist,u     fetch pointer to 1st block in list
        stx     cnfg:timeoutlist,u     make new block be 1st block in list
        std     timeout:link,x         make new block point to rest of list
        elseif  m6800!m6801
        stx     itempx                 save pointer to new timeout block
        ldx     CODE+sdos:configuration get pointer to configuration table
        ldd     cnfg:timeoutlist,x     fetch pointer to 1st block in list
        ldx     itempx                 get pointer to new timeout block
        std     timeout:link,x         make new block point to rest of list
        ldd     itempx                 get pointer to new timeout block
        ldx     CODE+sdos:configuration get pointer to configuration table
        std     cnfg:timeoutlist,x     make new block be 1st block in list
        else    (m6811)
        ldy     CODE+sdos:configuration get pointer to configuration table
        ldd     cnfg:timeoutlist,y     fetch pointer to 1st block in list
        stx     cnfg:timeoutlist,y     make new block be 1st block in list
        std     timeout:link,x         make new block point to rest of list
        fin
TIMEOUTINSERTbumpfusesloop ; adjust fuses of rest of timeout blocks
        ldx     timeout:link,x         find next block in list
TIMEOUTINSERTbumpfuses1 ; enter here from TIMEOUTDELETEcant
        beq     TIMEOUTINSERTrts       b/ all blocks adjusted
        ldd     timeout:fuse,x         is this fuse zero ?
        beqd    TIMEOUTINSERTbumpfusesloop b/ yes, leave it alone!
        inc     timeout:fuse+1,x       no, revise fuse delay upwards
        bne     TIMEOUTINSERTbumpfusesloop b/ fuse delay adjusted
        inc     timeout:fuse,x         propogate carry
        bne     TIMEOUTINSERTbumpfusesloop b/ fuse delay adjusted
        dec     timeout:fuse,x         fuse overflowed, set back to max
        dec     timeout:fuse+1,x
        bra     TIMEOUTINSERTbumpfusesloop

TIMEOUTINSERTrts ; all timeout blocks adjusted
        rts

TIMEOUTDELETEcant ; TIMEOUT specified is not in CNFG:TIMEOUTLIST chain
        ldx     CODE+sdos:configuration find chain of timeout blocks
        ldx     cnfg:timeoutlist,x     find 1st timeout block in list
        bra     TIMEOUTINSERTbumpfuses1 go adjust fuses values back they were

        if      *>>CODE+$B299-$B200
        ? not enough patch space ?
        fin
        page
        org     CODE+$DD21-$B200       on top of part of old Block Transfer

TIMEOUTDELETE ; remove TIMEOUT block at (X) from TIMEOUT list
; Called from interrupt level routines with interrupts DISABLED.
;       sei                            assert: this has been done by caller
        cmpx    TIMEOUTLEPTR           deleting timeout block to be processed...
        bne     TIMEOUTDELETE1         next by by tick handler ? (b/ no)
        ldd     timeout:link,x         find timeout following one to be deleted
        std     TIMEOUTLEPTR           tell tick handler to use next instead
TIMEOUTDELETE1
        if      m6800
        stx     itempx                 save pointer to block to be deleted
        ldd     CODE+sdos:configuration find chain of timeout blocks
        addd    #cnfg:timeoutlist-timeout:link form pointer to list head
        pshd
        pulx
        ldd     itempx                 set (D) to timeout address for search
        elseif  m6801!m6811
        stx     itempx                 save pointer to block to be deleted
        ldx     CODE+sdos:configuration find chain of timeout blocks
        ldb     #cnfg:timeoutlist-timeout:link form pointer to list head
        abx
        ldd     itempx                 set (D) to timeout address for search
        else    (m6809)
        tfr     x,d                    set (D) to timeout address for search
        ldx     CODE+sdos:configuration find chain of timeout blocks
        leax    cnfg:timeoutlist-timeout:link,x
        fin
        cmpd    timeout:link,x         is next TIMEOUT the one to remove ?
        lbeq    TIMEOUTDELETEfoundblock b/ yes, go delete it from chain
        jmp     TIMEOUTDELETEfindblockloop
        page
        org     CODE+$DFC2-$B200
TIMEOUTDELETEfindblockloop ; see if next TIMEOUT block is one to remove
        ldx     timeout:link,x         follow link pointer to next timeout block
        beq     TIMEOUTDELETECANT      b/ not in list, just exit!
; Remember that TIMEOUT:FUSE holds (desireddelay+numberoftimeoutblock)
; Since we are going to remove a block, decrement the fuse in all blocks
        tst     timeout:fuse+1,x       lower 8 bits zero ?
        bne     TIMEOUTDELETEfindblock1 b/ yes, safe to decrement
        tst     timeout:fuse,x         upper 8 bits also zero ?
        beq     TIMEOUTDELETEfindblock2 b/ yes, leave this fuse alone
        dec     timeout:fuse,x         propogate borrow from following decrement
TIMEOUTDELETEfindblock1
        dec     timeout:fuse+1,x       decrement lower 8 bits of fuse
TIMEOUTDELETEfindblock2 ; enter loop here on 1st iteration or fuse is zero
        cmpd    timeout:link,x         is next TIMEOUT the one to remove ?
        bne     TIMEOUTDELETEfindblockloop b/ no, find another
TIMEOUTDELETEfoundblock ; timeout block to delete is at TIMEOUT:LINK,x
        if      m6809
        ldu     timeout:link,x         fetch pointer to block to remove
        ldu     timeout:link,u         fetch pointer to block after one to remove
        stu     timeout:link,x         remove block from list
        elseif  m6811
        ldy     timeout:link,x         fetch pointer to block to remove
        ldy     timeout:link,y         fetch pointer to block after one to remove
        sty     timeout:link,x         remove block from list
        else    (m6800!m6801)
        ldx     timeout:link,x         fetch pointer to block to remove
        ldd     timeout:link,x         fetch pointer to block after one to remove
        ldx     itempx                 get pointer to block to adjust
        std     timeout:link,x         remove block from list
        fin
        dec     CODE+sdos:timeoutcount decrement timeout block count
        bra     TIMEOUTDELETEdecrementrestoffuses decrement fuses in rest of blocks
        page
TIMEOUTDELETEdecrementfusethis ; (X) points to another block to adjust
; Remember that TIMEOUT:FUSE holds (desireddelay+numberoftimeoutblocks)
; Since we have removed a block, decrement the fuse in all blocks
        ldb     timeout:fuse+1,x       lower 8 bits zero ?
        bne     TIMEOUTDELETEdecrementfuse1 b/ yes, safe to decrement
        lda     timeout:fuse,x         upper 8 bits also zero ?
        beq     TIMEOUTDELETEdecrementrestoffuses b/ yes, leave this fuse alone
        dec     timeout:fuse,x         propogate borrow from following decrement
TIMEOUTDELETEdecrementfuse1
        dec     timeout:fuse+1,x       decrement lower 8 bits of fuse
TIMEOUTDELETEdecrementrestoffuses ; decrement all fuses in rest of list
        ldx     timeout:link,x         follow link pointer
        bne     TIMEOUTDELETEdecrementfusethis b/ another block to adjust
TIMEOUTDELETErts ; timeout block has been removed from list
        rts                            block has been removed from list
        if      *>>CODE+$DFFF-$B200
        ? not enough patch space ?
        fin
        page
sdos:surprise equ $B388-$B200
CLOCKTICKEDEVENT equ   CODE+$B25B-$B200
TIMEOUTLEPTR     equ   CODE+$B25C-$B200
IORTI            equ   CODE+$DE45-$B200
        org     TIMEOUTLEPTR
        fdb     0                      set TIMEOUTLEPTR to "nil" initially

        org     CODE+$DD3D-$B200
CLOCKTICKED ; come here with (A) holding # 60Hz ticks
        psha                           save tick count
        adda    CODE+SDOS:CLOCK+2      adjust TIME-OF-DAY
        staa    CODE+SDOS:CLOCK+2
        bcc     CODE+$DD56-$B200
        bra     CODE+$DD4E-$B200
        $3F,$3F,$3F,$3F,$3F

        org     CODE+$DDB2-$B200
        bra     CODE+$DDDD-$B200
        swi

        org     CODE+$DDDD-$B200
; CLOCKTICKEXIT ; come here when thru adjusting SDOS:CLOCK with (A)=ticks elapsed
        pula                           restore tick count
; Interrupts are disabled here, but stacks are switched to interrupt stack
        adda    CLOCKTICKEDEVENT       adjust ticks to be processed
        ldab    CLOCKTICKEDEVENT       a thread of execution already in tick handler ?
        bne     TIMEOUTTICKstaarti     store (A) as CLOCKTICKEVENT and exit
TIMEOUTTICKHANDLER ; enter tick handler (only one thread executes thru here!)
; If a timeout block goes off, and the interrupt code associated with that
; timeout re-enables, AND a clock tick happens, then it is possible that
; two threads of execution could try to enter here. Careful coding prevents it.
        staa    CLOCKTICKEDEVENT       remember # ticks we need to process
        page
TIMEOUTTICKHANDLERloop ; handle next timeout block
; While we should theoretically enable interrupts momentarily here,
; we don't do it because CLOCKTICKEDEVENT almost always contains 1 or 2,
; and thus this routine is generally very fast.
        ldx     TIMEOUTLEPTR           get pointer to next TIMEOUT block
        bne     TIMEOUTTICK1           b/ points to valid block
        ldx     CODE+sdos:configuration get pointer to 1st block in list
        ldx     cnfg:timeoutlist,x
        beq     TIMEOUTTICKHANDLERdone b/ no timeout blocks to process!
TIMEOUTTICK1 ; (X) points to valid TIMEOUT block
        ldd     timeout:link,x         find pointer to next TIMEOUT block
        std     TIMEOUTLEPTR           and save for next round
        ldd     timeout:fuse,x         fetch remaining delay
        beqd    TIMEOUTTICKnext        b/ no need to fool with this block
        subb    CODE+sdos:timeoutcount down count delay
        sbca    #0                     propogate borrow
        bcs     TIMEOUTTICKtimedout    b/ TIMEOUT block timed out!
        std     timeout:fuse,x         update remaining delay
        bned    TIMEOUTTICKnext        b/ TIMEOUT block did not time out
TIMEOUTTICKtimedout ; TIMEOUT block timed out!
        clr     timeout:fuse,x         zero the remaining delay
        clr     timeout:fuse+1,x
        bsr     TIMEOUTTICKtimeoutinterrupt
TIMEOUTTICKnext ; all done handling this TIMEOUT block
; >>>> CODE FOR SECONDARY CHECKSUM CHECK GOES HERE!
; Note: interrupts are off from here thru STAA below
        dec     CLOCKTICKEDEVENT       all tick events processed ?
        bne     TIMEOUTTICKHANDLERloop b/ no, go process another event
TIMEOUTTICKHANDLERdone ; (branch here if CNFG:TIMEOUTLIST is empty)
        ldaa    CODE+sdos:schedulesoonflag = 0 if scheduling required after tick
        bne     TIMEOUTTICKHANDLERdone1 b/ no scheduling required after tick
        staa    CODE+sdos:surprise     signal scheduling required immediately
        inc     CODE+sdos:schedulesoonflag remember scheduling not req'd after tick
TIMEOUTTICKHANDLERdone1
        clra                           don't need to process any more ticks
TIMEOUTTICKstaarti ; store (A) as CLOCKTICKEVENT and exit
        staa    CLOCKTICKEDEVENT       set remaining tick count
        bra     IORTI                  all we need do is exit from interrupt routine
        page
TIMEOUTTICKtimeoutinterrupt ; simulate interrupt to TIMEOUT:ROUTINE(X)
; note: called routine may re-enable interrupts and be interrupted!
        inc     CODE+sdos:stackswitched count simulated interrupt as nested
        ; This forces control to come back here.
        if      m6800
        pshb                           push dummy (X)
        psha
        pshb                           push dummy (D)
        psha
        ldaa    #$FF                   push "interrupt disabled" CCR
        psha
        ldd     timeout:dcb,x          get TIMEOUT:PARAMETER
        ldx     timeout:routine,x      fetch pointer to routine to call
        jmp     0,x
        elseif  m6801
        pshx                           push dummy (X)
        pshd                           push (D)
        ldaa    #$FF                   push "interrupt disabled" CCR
        psha
        ldd     timeout:dcb,x          get TIMEOUT:PARAMETER
        ldx     timeout:routine,x      fetch pointer to routine to call
        jmp     0,x
        elseif  m6811
        pshx                           push dummy (Y)
        pshx                           push dummy (X)
        pshd                           push (D)
        ldaa    #$FF                   push "interrupt disabled" CCR
        psha
        ldd     timeout:dcb,x          get TIMEOUT:PARAMETER
        ldx     timeout:routine,x      fetch pointer to routine to call
        jmp     0,x
        else    (m6809)
        pshs    cc,a,b,dp,x,y,u
        ldd     timeout:dcb,x          get TIMEOUT:PARAMETER
        jmp     [timeout:routine,x]    fetch pointer to routine to call
        rpt     8
        swi                            space available for patches
        fin

        org     $237d                  patch timeout task TCB out of task q
        ldd     #CODE+$B299-$B200      ptr to user task tcb
        page    PATCH TO SDOS11GxxK.689 TO ENHANCE BLOCK MOVE PERFORMANCE
        org     CODE+$dd01-$B200
BLOCKMOVEDOWN ; ENTRY POINT TO BLOCKMOVE FOR '09, PRESERVES DCBPOINTER
*       (X) = from address
*       (Y) = to address
*       (D) = count (0..65535)
*
*       On exit, (X) has old (X)+(D); (Y) has old (Y)+(D)
*       Assumes that Copy-to region does NOT overlap Copy-from region
*       or, if there is an overlap, that FROM >= TO.
*
        leau    d,x     compute "end of transfer address"
        leau    -16,u   to counter offsets used in MoveDownLoop
        ; = center of last block of 16 bytes to transfer
        stu     tempx   save for loop limit comparison
        bitb    #1      moving an even number of bytes ?
        beq     BlockMoveDown0         b/ yes
        ldaa    ,x+     take care of moving odd byte
        staa    ,y+
BlockMoveDown0 ; even number of bytes left to move
;
;  Following picture is state of affairs at BlockMoveUp0
;
;                !----------!
; ^   (X) -->    !          !
; |              !  first   !
; |              !  block   !   This block is EVEN (odd byte already done)
; count mod 32   !  copied  !   but usually NOT 32 bytes in size
; |              !          !
; |              !----------!
; v          A   !          !   (offset -16)
;                !          !
;                    ...        Multiple blocks of 32 bytes
;                !          !
;                !          !
;                !----------!
;                !          !   (offset -16)
;                !  final   !
;    (TEMPX) --> !  block   !   (offset 0)
;                !  copied  !   (Generally) Block of 32 bytes
;                !          !
;                !          !   (offset +14)
;                !----------!
;    (X)+(D) --> !          !
;                    ....
;
;  Our intent is that each loop iteration copies 32 bytes, because
;  we can do this most efficiently using 5 bit index register offsets.
;  The first loop copies just enough so the rest of the iterations can
;  always copy 32 bytes. Each iteration advances (X) and (Y) by 32
;  (we must do it this because FROM >= TO, or we may scramble the data
;  we are moving), so that the last loop iteration has (X)+16 pointing to
;  the end-of-transfer address.  The loop terminates when (X) points to
;  the middle of last block that needs data transferred. To do this, we
;  need to arrange things so that the point labelled A has offset -16
;  on the second iteration of the loop.  Setting (X)-16+(count mod 32)
;  accomplishes this nicely.
;
        andb    #%11110 take xfer count mod 32 (assert: count is even!)
        tfr     b,a     adjust source and destination pointers...
        adda    #-16    to point to middle of block of 32 bytes
        leax    a,x     add (count mod 32)-16
        leay    a,y
        eorb    #%11110 complement so 0 maps to 15
        aslb            shift to make multiple of 4
        ldu     #BlockMoveDown32+4 set up to jump into loop
        jmp     b,u     jmp to LDD instruction
; Note: block count of 2 takes us to LDD 14,x
;       block count which is multiple of 32 jmps to CMPX
;
; BytesToMove   Enter Loop at           Add To X,Y
;              BlockMoveDown32+...
;
;    32               0                     16
;    30               4                     14
;    28               8                     12
;                 .........
;     2              60                    -14
;     0              64                    -16
;
        page
        org      CODE+$DF71-$B200
BlockMoveDownLoop ; come here to move next block of 32 bytes
        leax     32,x   (4+1~) advance source pointer
        leay     32,y   (4+1~) advance destination pointer
BlockMoveDown32 ; move block of 32 bytes centered around (X)
        ldd     -16,x   (5+1~) fetch source pair
        std     -16,y   (5+1~) store destination pair
        ldd     -14,x   (5+1~) fetch source pair
        std     -14,y   (5+1~) store destination pair
        ldd     -12,x   (5+1~) fetch source pair
        std     -12,y   (5+1~) store destination pair
        ldd     -10,x   (5+1~) fetch source pair
        std     -10,y   (5+1~) store destination pair
        ldd      -8,x   (5+1~) fetch source pair
        std      -8,y   (5+1~) store destination pair
        ldd      -6,x   (5+1~) fetch source pair
        std      -6,y   (5+1~) store destination pair
        ldd      -4,x   (5+1~) fetch source pair
        std      -4,y   (5+1~) store destination pair
        ldd      -2,x   (5+1~) fetch source pair
        std      -2,y   (5+1~) store destination pair
        ldd       0,x   (5+0~) fetch source pair
        std       0,y   (5+0~) store destination pair
        ldd       2,x   (5+1~) fetch source pair
        std       2,y   (5+1~) store destination pair
        ldd       4,x   (5+1~) fetch source pair
        std       4,y   (5+1~) store destination pair
        ldd       6,x   (5+1~) fetch source pair
        std       6,y   (5+1~) store destination pair
        ldd       8,x   (5+1~) fetch source pair
        std       8,y   (5+1~) store destination pair
        ldd      10,x   (5+1~) fetch source pair
        std      10,y   (5+1~) store destination pair
        ldd      12,x   (5+1~) fetch source pair
        std      12,y   (5+1~) store destination pair
        ldd      14,x   (5+1~) fetch source pair
        std      14,y   (5+1~) store destination pair
        cmpx     tempx  (6~) check limit
        bne     BlockMoveDownLoop (3~) b/ limit not reached
;                       --------
;                       15*(6+6)+5+5+5+5+6+3 = 209~/32 bytes --> 6.53~/byte
        leax     16,x   Set (X) at exit to entry (X)+(D)
        leay     16,y   Set (Y) at exit to entry (Y)+(D)
        rts
        page
        if      0
; following block move is intended for placement in BASRTP14L.689
        org     $1000
BLOCKMOVEUP ; ENTRY POINT TO BLOCKMOVE FOR '09, PRESERVES DCBPOINTER
*       (X) = from address
*       (Y) = to address
*       (D) = count (0..65535)
*
*       On exit, (X) has old (X)+(D); (Y) has old (Y)+(D)
*       Assumes that Copy-to region does NOT overlap Copy-from region
*       or, if there is an overlap, that FROM <= TO.
*
        leau    16,x    to counter offsets used in MoveUpLoop
        ; = center of last block of 16 bytes to transfer
        stu     tempx   save for loop limit comparison
        leax    d,x     compute "end of source address"
        leay    d,y     compute "ending destination address"
        pshs    x,y     save as exit results
        bitb    #1      moving an even number of bytes ?
        beq     BlockMoveUp0         b/ yes
        ldaa    ,-x     take care of moving odd byte
        staa    ,-y
BlockMoveUp0 ; even number of bytes left to move
;
;  Following picture is state of affairs at BlockMoveUp0
;
;                !----------!
;  entry (X) --> !          !   (offset -16)
;                !  final   !
;    (TEMPX) --> !  block   !   (offset 0)
;                !  copied  !   (Generally) Block of 32 bytes
;                !          !
;                !          !   (offset +14)
;                !----------!
;                !          !
;                !          !
;                    ...        Multiple blocks of 32 bytes
;                !          !
;                !          !
;                !----------!
;  ^          A  !  first   !   (needs to be offset -16)
;  |             !  block   !   This block is EVEN (odd byte already done)
; count mod 32   !  copied  !   but usually NOT 32 bytes in size
;  |             !----------!
;  v    (X) -->  !  bytes   !
;                !   not    !
;                !  copied  !
;                !----------!
;
;  Our intent is that each loop iteration copies 32 bytes, because
;  we can do this efficiently using 5 bit index register offsets.
;  The first loop copies just enough so the rest of the iterations can
;  always copy 32 bytes.  Each iterations backs up (X) and (Y) by 32
;  (we must do it this way to handle the fact that FROM <= TO, or we
;  may scramble some of the data when moving it), so the last loop iteration
;  has the address of (X) on entry at offset -16.
;  The loop terminates when (X) points to middle of last block that needs
;  data transferred. To do this, we need to arrange things so that the
;  point labelled A has offset -16 from (X) when we enter the loop.
;  (X)-(count mod 32)+16 is the address we desire.
;
        andb    #%11110 take xfer count mod 32 (assert: count is even!)
        tfr     b,a     adjust source and destination pointers...
        nega            compute -(count mod 32)
        adda    #16     determine offset to location A, above
        leax    a,x     adjust (X) so A is at offset -16
        leay    a,y     corresponding computation needed for (Y)
        eorb    #%11110 complement so 0 maps to 15
        aslb            shift to make multiple of 4
        ldu     #BlockMoveUp32+4 set up to jump into loop
        jmp     b,u     jmp to LDD instruction
; Note: block count of 2 takes us to LDD -16,x
;       block count which is multiple of 32 jmps to CMPX
;
; BytesToMove   Enter Loop at           Add To X,Y
;              BlockMoveUp32+...
;
;    32               0                     16 (or -16)
;    30               4                     -14
;    28               8                     -12
;                 .........
;     2              60                     +14
;     0              64                     +16
;
        page
BlockMoveUpLoop ; come here to move next block of 32 bytes
        leax    -32,x   (4+1~) "advance" source pointer
        leay    -32,y   (4+1~) "advance" destination pointer
BlockMoveUp32 ; move block of 32 bytes centered around (X)
        ldd      14,x   (5+1~) fetch source pair
        std      14,y   (5+1~) store destination pair
        ldd      12,x   (5+1~) fetch source pair
        std      12,y   (5+1~) store destination pair
        ldd      10,x   (5+1~) fetch source pair
        std      10,y   (5+1~) store destination pair
        ldd       8,x   (5+1~) fetch source pair
        std       8,y   (5+1~) store destination pair
        ldd       6,x   (5+1~) fetch source pair
        std       6,y   (5+1~) store destination pair
        ldd       4,x   (5+1~) fetch source pair
        std       4,y   (5+1~) store destination pair
        ldd       2,x   (5+1~) fetch source pair
        std       2,y   (5+1~) store destination pair
        ldd       0,x   (5+1~) fetch source pair
        std       0,y   (5+1~) store destination pair
        ldd      -2,x   (5+0~) fetch source pair
        std      -2,y   (5+0~) store destination pair
        ldd      -4,x   (5+1~) fetch source pair
        std      -4,y   (5+1~) store destination pair
        ldd      -6,x   (5+1~) fetch source pair
        std      -6,y   (5+1~) store destination pair
        ldd      -8,x   (5+1~) fetch source pair
        std      -8,y   (5+1~) store destination pair
        ldd     -10,x   (5+1~) fetch source pair
        std     -10,y   (5+1~) store destination pair
        ldd     -12,x   (5+1~) fetch source pair
        std     -12,y   (5+1~) store destination pair
        ldd     -14,x   (5+1~) fetch source pair
        std     -14,y   (5+1~) store destination pair
        ldd     -16,x   (5+1~) fetch source pair
        std     -16,y   (5+1~) store destination pair
        cmpx     tempx  (6~) check limit
        bne     BlockMoveUpLoop (3~) b/ limit not reached
;                       --------
;                       15*(6+6)+5+5+5+5+6+3 = 209~/32 bytes --> 6.53~/byte
        puls     x,y    set (X) and (Y) to end addresses after transfer
        rts             done!
        fin     0
        END
