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
pistolhamster wrote:
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
gfoot wrote:
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
richardc64 wrote:
pistolhamster wrote:
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
gfoot wrote:
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
pistolhamster wrote:
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
gfoot wrote:
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
gfoot wrote:
pistolhamster wrote:
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
pistolhamster wrote:
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