Counting "trick"/memory copy

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
pixel
Vic 20 Scientist
Posts: 1328
Joined: Fri Feb 28, 2014 3:56 am
Website: http://hugbox.org/
Location: Berlin, Germany
Occupation: Pan–galactic shaman

Counting "trick"/memory copy

Post by pixel »

In the course of trying to hammer Pulse into unexpanded machines alongside darkatx' title screen and audio player for borays tune "No syrup" (don't miss the original recording) a false assumption got in the way: that the INC and DEC instructions would modify the carry flag. That "Oh no!" scream from Bridlington must have been heard in Denmark. But out came this counting trick which I haven't seen anywhere else yet. Anybody seeing issues with this one?

Code: Select all

.export moveram

.importzp s, d, c

.code

.proc moveram
    ldy #0
    ldx c
    sty c
    inc c+1			; *honk!*
    cmp #0
    bne copy_backwards

copy_forwards:
l:  lda (s),y
    sta (d),y
    inc s
    beq k
n:  inc d
    beq m
q:  dex
    bne l
    dec c+1
    bne l
    rts

k:  inc s+1
    jmp n

m:  inc d+1
    jmp q

copy_backwards:
l2: lda (s),y
    sta (d),y
    dec s
    lda s
    cmp #$ff
    beq m2
n2: dec d
    lda d
    cmp #$ff
    beq j2
q2: dex
    bne l2
    dec c+1
    bne l2
    rts

m2: dec s+1
    jmp n2

j2: dec d+1
    jmp q2
.endproc                                                                                                                                                                                                                          
A man without talent or ambition is most easily pleased. Others set his path and he is content.
https://github.com/SvenMichaelKlose
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Counting "trick"/memory copy

Post by Mike »

Usually, copy routines on the 65xx with LDA/STA (),Y modify Y with INY/DEY instead of doing a costly INC/DEC on the low-byte ZP address base. That way, the fix-up of the high-byte only needs to be done on over-/underflow of Y, simultaneously for both src and dst pointers, and doesn't require independent checks of both low-bytes on each loop iteration. Like:

Code: Select all

.loop
 LDA (src),Y
 STA (dst),Y
 INY
 BNE loop
 INC src+1
 INC dst+1
 DEX
 BNE loop
... and the loop is entered with a non-0 value of Y, if the transfer contains a non-complete page (adjusting src and dst beforehand).

Likewise for the other direction:

Code: Select all

.start
 CPY #0        /* fix-up for a single */
 BEQ skip      /* byte in the last page */
.loop
 LDA (src),Y
 STA (dst),Y
 DEY
 BNE loop
.skip
 LDA (src),Y   /* these */
 STA (dst),Y   /* three */
 DEY           /* go extra */
 DEC src+1
 DEC dst+1
 DEX
 BNE loop
... where the routine is entered with a non-255 value of Y for a non-complete page. Y=0 needs the special fix-up once at the start, otherwise errorneously a full page is copied. The high-bytes of src and dst need to be adjusted to point to the last page.
User avatar
pixel
Vic 20 Scientist
Posts: 1328
Joined: Fri Feb 28, 2014 3:56 am
Website: http://hugbox.org/
Location: Berlin, Germany
Occupation: Pan–galactic shaman

Re: Counting "trick"/memory copy

Post by pixel »

Mike wrote:Usually, copy routines on the 65xx with LDA/STA (),Y modify Y with INY/DEY instead of doing a costly INC/DEC on the low-byte ZP address base. That way, the fix-up of the high-byte only needs to be done on over-/underflow of Y, simultaneously for both src and dst pointer, and doesn't require independent checks of both low-bytes on each loop iteration.
:shock: Oh, crap. How could I be THAT stupid!?!? At least it's now obvious why I'd better ask for review... an update of 'g'. Thanks, Mike!

Code: Select all

.export moveram                                                                                                                                                                                                                   

.importzp s, d, c

.code

.proc moveram
    ldy #0
    ldx c
    sty c
    inc c+1			; <- the counting trick
    cmp #0
    bne copy_backwards

copy_forwards:
l:  lda (s),y
    sta (d),y
    iny
    beq k
q:  dex
    bne l
    dec c+1
    bne l
    rts

k:  inc s+1
    inc d+1
    jmp q

copy_backwards:
l2: lda (s),y
    sta (d),y
    dey
    cpy #$ff
    beq m2
q2: dex
    bne l2
    dec c+1
    bne l2
    rts

m2: dec s+1
    dec d+1
    jmp q2
.endproc
A man without talent or ambition is most easily pleased. Others set his path and he is content.
https://github.com/SvenMichaelKlose
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Counting "trick"/memory copy

Post by Mike »

I found a nice collection of memory move routines on 6502.org: Practical Memory Move Routines.
Bruce Clark wrote:Here are some reasonably fast general-purpose routines for moving blocks of memory. You simply specify the address to move from, the address to move to, and the size of the block. [...] These routines are intended to be both flexible and practical, without being excessively lengthy or excessively slow. To that end, they can be placed in ROM or in RAM.

There are three routines moving memory upward (i.e. to a higher address), each of which is tailored to a slightly different set of input parameters.
User avatar
pixel
Vic 20 Scientist
Posts: 1328
Joined: Fri Feb 28, 2014 3:56 am
Website: http://hugbox.org/
Location: Berlin, Germany
Occupation: Pan–galactic shaman

Re: Counting "trick"/memory copy

Post by pixel »

My gut feeling was about right: there's something wrong with this trick. The high byte must only be incremented if the low byte is not 0.
A man without talent or ambition is most easily pleased. Others set his path and he is content.
https://github.com/SvenMichaelKlose
Post Reply