Page 2 of 2
Re: Using x and y registers as an address
Posted: Fri Nov 10, 2023 10:10 pm
by pistolhamster
This was a good read, thank you to those who gave such well explained advice.
Allow me to ask a question: Like the OP, I dabble a bit with a simple project where I need to dynamically change memory addresses.
I want to print a series of characters on the screen starting with $0400 and ending with $07e7. To do that I have written four loops Right, down, left, up.
something like this
Code: Select all
*=$1000
right:
lda #$d7 // petscii circle
sta $0400,x
inx
cpx #40 // max length of row.
bne right
That is not too hard, the X index stops at 40, but I struggle with the "down" bit
Code: Select all
ldy #0
stx $1100
down:
lda #$d7 // petscii circle
sta $0400,x // X must increase 40 per cycle to print downwards in a line
lda $1100 //get the stored X value (should be 40 first pass)
adc #40
sta $1101 //
ldx $1100
iny
cpy #25 // with 25 rows this is the max
bne down
It works until x ($1100) reaches 255, then the x index flips because it has 8 bits only, and my whole little thing comes crashung down.
Could I change the routine so that I don't address $0400,x but increment the address itself that the petscii circle is stored to?
Re: Using x and y registers as an address
Posted: Fri Nov 10, 2023 11:46 pm
by richardc64
It works until x ($1100) reaches 255, then the x index flips because it has 8 bits only, and my whole little thing comes crashung down.
Is that a typo or have you coined a neologism, a new word for flawed code, combining "crash" & "hung", much like hangry?
Re: Using x and y registers as an address
Posted: Sat Nov 11, 2023 12:51 am
by gfoot
Typically you would store the address in two consecutive bytes of page zero, and adjust them there by doing 16-bit adds or subtracts. Then to read or write the target memory location you set X or Y to zero and use indexed indirect addressing, i.e. (zpaddr,x) or (zpaddr),y.
However you can certainly use self-modifying code instead, if your code is in RAM. Garth linked to some examples of that upthread.
The case where self-modifying code doesn't work so well is where there are two or more instructions that all need to use the same address. There are some more complex techniques to cater for that a bit but it's simpler to just use indirect indexed addressing.
Re: Using x and y registers as an address
Posted: Sat Nov 11, 2023 1:33 am
by GARTHWILSON
Then to read or write the target memory location you set X or Y to zero and use indexed indirect addressing, i.e. (zpaddr,x) or (zpaddr),y.
On the 65c02, you can also do it without indexing, with: ADC (ZP), AND (ZP), CMP (ZP), EOR (ZP), LDA (ZP), ORA (ZP), SBC (ZP), and STA (ZP).
Re: Using x and y registers as an address
Posted: Sat Nov 11, 2023 8:35 am
by pistolhamster
It works until x ($1100) reaches 255, then the x index flips because it has 8 bits only, and my whole little thing comes crashung down.
Is that a typo or have you coined a neologism, a new word for flawed code, combining "crash" & "hung", much like hangry?
It would be an excellent example of serendipity. Alas, it was a typo. But yes, why not? "It crashung"
Re: Using x and y registers as an address
Posted: Sun Nov 12, 2023 2:43 pm
by pistolhamster
Typically you would store the address in two consecutive bytes of page zero, and adjust them there by doing 16-bit adds or subtracts. Then to read or write the target memory location you set X or Y to zero and use indexed indirect addressing, i.e. (zpaddr,x) or (zpaddr),y.
Thanks, you put me on the track again. This is what I managed to write and test, I now have a nice column of petscii circles.
Code: Select all
ldx #$27
ldy #$04
stx $60 // low byte address
sty $61 // high byte address
ldy #0 // counter
down:
clc
lda #81 //petscii circle
sta ($60),y
lda $60 // get low byte
adc #40 // add 40 for next line
sta $60 // store new value
lda $61 // get high byte
adc #0
sta $61
inx
cpx #25 // max rows
bne down
Re: Using x and y registers as an address
Posted: Sun Nov 12, 2023 3:07 pm
by gfoot
Thanks, you put me on the track again. This is what I managed to write and test, I now have a nice column of petscii circles.
Yes that's the idea. Note Garth's point that with a modern 65C02 you can also do it without using an index register.
Even on older CPUs you can also speed things up a little by swapping the roles of the Y register and the low byte of the address, i.e. $60. So you'd store zero at $60 and put the low byte of your target address into Y instead. This doesn't affect the function of the STA line, but it allows you to save a few cycles in the addition as now you can use TYA instead of LDA $60, and TAY instead of STA $60.
Re: Using x and y registers as an address
Posted: Mon Nov 13, 2023 1:19 am
by BigDumbDinosaur
Code: Select all
ldx #$27
ldy #$04
stx $60 // low byte address
sty $61 // high byte address
ldx #25 ;rows
ldy #0 // counter
down:
lda #81 //petscii circle
sta ($60),y
clc
lda $60 // get low byte
adc #40 // add 40 for next line
sta $60 // store new value
lda $61 // get high byte
adc #0
sta $61
dex
bne down ;more rows
Re: Using x and y registers as an address
Posted: Wed Nov 15, 2023 9:09 am
by barrym95838
Even on older CPUs you can also speed things up a little by swapping the roles of the Y register and the low byte of the address, i.e. $60. So you'd store zero at $60 and put the low byte of your target address into Y instead. This doesn't affect the function of the STA line, but it allows you to save a few cycles in the addition as now you can use TYA instead of LDA $60, and TAY instead of STA $60.
Solid advice, every word. Shaved two bytes and ten cycles from the inner loop.
Code: Select all
ldy #$27
ldx #$04
stx $61 // high byte address
ldx #0
stx $60 // low byte address
ldx #25 // counter
down:
clc
down2:
lda #81 // petscii circle
sta ($60),y
dex
beq done
tya // get low byte
adc #40 // add 40 for next line
tay // store new value
bcc down2
inc $61 // update high byte
bcs down
done:
Re: Using x and y registers as an address
Posted: Wed Nov 15, 2023 8:49 pm
by pistolhamster
Thanks, you put me on the track again. This is what I managed to write and test, I now have a nice column of petscii circles.
Yes that's the idea. Note Garth's point that with a modern 65C02 you can also do it without using an index register.
Even on older CPUs you can also speed things up a little by swapping the roles of the Y register and the low byte of the address, i.e. $60. So you'd store zero at $60 and put the low byte of your target address into Y instead. This doesn't affect the function of the STA line, but it allows you to save a few cycles in the addition as now you can use TYA instead of LDA $60, and TAY instead of STA $60.
Oh, that was a clever thing. Thank you.
IS the 65C02 the same as the WDC 65C02 that is still manufactured? I've seen that it will be the heart of the new Commander X16.
Re: Using x and y registers as an address
Posted: Thu Nov 16, 2023 4:02 am
by Dr Jefyll
IS the 65C02 the same as the WDC 65C02 that is still manufactured?
Yeah, pretty much... especially software-wise. Compared with C02's from Rockwell and CMD, for example, the current WDC product has a couple of new instructions, but they're ones you're unlikely to use -- STP and WAI. (And are you concerned about the hardware side of things? Briefly, the WDC chips can be run faster and they have some slight but important changes to the pinout; also the inputs no longer accept TTL voltage levels.)
-- Jeff