Page 1 of 1
Counting "trick"/memory copy
Posted: Mon May 22, 2017 5:27 am
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
Re: Counting "trick"/memory copy
Posted: Mon May 22, 2017 6:01 am
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.
Re: Counting "trick"/memory copy
Posted: Mon May 22, 2017 6:30 am
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.
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
Re: Counting "trick"/memory copy
Posted: Wed Feb 07, 2018 1:32 am
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.
Re: Counting "trick"/memory copy
Posted: Mon Feb 19, 2018 4:04 pm
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.