Page 1 of 2
Using x and y registers as an address
Posted: Wed Dec 15, 2021 7:08 pm
by Oman395
Hey, very much a noob to 6502 assembly. I'm working on something that should ideally be able to increment fully up from $4000 to $7fff, but obv 8 bit registers aren't enough. Is there any way to use both x and y registers for an address?
Re: Using x and y registers as an address
Posted: Wed Dec 15, 2021 7:12 pm
by BigEd
Welcome! I've seen X and Y used in a convention for passing parameters, but really an address can only live in one of two places: the instruction stream, and zero page. Oh, and the stack. Three places.
So, the normal scheme is to put the address in two consecutive zero page locations, use an appropriate indirect mode to use that pointer, and then to use the INC (or DEC) operations on zero page to increment and decrement. And, because these are 8 bit operations, you increment the low byte, and then detect overflow and increment the high byte if needed.
Re: Using x and y registers as an address
Posted: Thu Dec 16, 2021 7:30 pm
by BigDumbDinosaur
Hey, very much a noob to 6502 assembly. I'm working on something that should ideally be able to increment fully up from $4000 to $7fff, but obv 8 bit registers aren't enough. Is there any way to use both x and y registers for an address?
.X and/or .Y can be used as an offset to a base address, but in themselves can't be used to form an address. As Ed noted, you need to use one of the indirect addressing modes, which involves page zero. Think of page zero as a set of (slightly slower) registers, a concept referred to as “addressable register architecture.”
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 3:20 pm
by teamtempest
If all you want to do is count from $4000 to $7fff using just the X- and Y-registers, yes, you can do that. If you want to use one of those values to form an address you can use to read from or write to, no, there's no direct way to do that. No 6502 instruction uses the paired X- and Y-registers as an address for something the A-register is doing.
What you can do, as has been pointed out above, is put the value $4000 in a pair of consecutive zero page locations (lo-byte, hi-byte) and use it as the base address of an indirect instruction. Then you can increment that value as needed to reach higher and higher addresses. The slowest way to do that would be to increment the base address by one each time while holding X or Y constant. The faster way is to increment Y by one each time and increment the base address just once every 256 times.
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 6:21 pm
by DRG
Something like this will store $FF in memory locations $4000 to $7FFF...
Code: Select all
; ? means the value of the memory location referenced.
; $10 holds low byte of address.
; $11 hold high byte of address.
.ORG $200
LDY #$00 ; Y = $00
TYA ; A = $00
STA $10 ; Memory location $10 = $00
LDA #$40 ; A = $40
STA $11 ; Memory location $11 = $40
loop1 LDA #$FF ; A = $FF
loop2 STA ($10),Y ; ?$11 * 256 + ?$10 + Y = A
INY ; Y = Y + 1
BNE loop2 ; Y <> 0 goto loop2
INC $11 ; $11 = $11 + 1
LDA $11 ; A = ?$11
CMP #$80 ; A = $80
BNE loop1 ; If yes goto loop1
BRK ; End
Why can't I get this code to line up?

<= Fixed!
Thank you, BigEd - tabs replaced by spaces and a little tinkering did it!
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 6:26 pm
by BigEd
You need to use spaces, not tabs, I think. I usually do a lot of tweaking with the preview function - to get it right on the forum, which is what matters, and whatever it has to be in the text entry box.
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 7:03 pm
by BigDumbDinosaur
Something like this will store $FF in memory locations $4000 to $7FFF...
I'd do it this way:
Code: Select all
; ? means the value of the memory location referenced.
; $10 holds low byte of address.
; $11 hold high byte of address.
;
; Below executes in 180,813 clock cycles.
;
.ORG $200
;
LDA #$40 ; A = $40
LDX #$80-$40 ; page counter (64 pages)
LDY #$00 ; Y = $00
STA $11 ; Memory location $11 = $40
STY $10 ; Memory location $10 = $00
LDA #$FF ; A = $FF
;
loop STA ($10),Y ; ?$11 * 256 + ?$10 + Y = A
INY ; Y = Y + 1
BNE loop ; Y <> 0 goto loop2
;
INC $11 ; $11 = $11 + 1
DEX ; page count = page count -1
BNE loop ; not done
;
BRK ; End
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 7:30 pm
by DRG
Just checked in the 6502 Simulator and mine was 118,131 clock cycles. But, that LDA/CMP pairing of mine seemed clumsy to me.
Just goes to show the OP that there are many way to skin a cat in 6502.
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 8:02 pm
by plasmo
I guess if you truly only want to use X and Y registers only, you can do it with self-modifying code where the base address of "STA $4000,x" is modified.
Am I banished from 6502.org forever for suggesting that?
Bill
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 8:25 pm
by BigEd
I don't do it often, but I wrote some self-modifying code today...
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 9:01 pm
by GARTHWILSON
I guess if you truly only want to use X and Y registers only, you can do it with self-modifying code where the base address of "STA $4000,x" is modified.
Am I banished from 6502.org forever for suggesting that?
Bill
Not at all. The more I look, the more I think there is significant capability there that most of us have been neglecting.
http://wilsonminesco.com/SelfModCode/
Re: Using x and y registers as an address
Posted: Fri Dec 17, 2021 10:40 pm
by JimBoyd
Am I banished from 6502.org forever for suggesting that?
Bill
Nope.
Here are some links for self modifying code in the Programming and Forth subforums.
Re: Using x and y registers as an address
Posted: Sat Dec 18, 2021 5:53 am
by BigDumbDinosaur
I guess if you truly only want to use X and Y registers only, you can do it with self-modifying code where the base address of "STA $4000,x" is modified.
Am I banished from 6502.org forever for suggesting that?
Bill
Not at all. The more I look, the more I think there is significant capability there that most of us have been neglecting.
http://wilsonminesco.com/SelfModCode/
I have something like that in POC V1.3's SCSI driver. During the data-in and data-out bus phases, some code is copied from ROM to low RAM and self-modification sets the target address. It runs faster than using an indirect addressing mode.
Re: Using x and y registers as an address
Posted: Sat Dec 18, 2021 10:00 am
by DRG
How bizarre! A self modifying code is what I actually thought of overnight having slept on it.
I thought this could actually be much closer aligned to the OP's, Oman395, original thoughts i.e. can an address "shared" between the X and Y registers be used to access memory.
In essence, the code below does what a "STA X:Y" instruction would do where X=lsb and Y=msb. The STA $1234 is just a sacrificial address to ensure the correct LDA instruction is generated by the assembler. Oh, and you couldn't run it in ROM!
Code: Select all
; smc = self modifying code location.
; -> smc + 0 = $8D (LDA absolute from non-zero page address).
; -> smc + 1 = lsb of absolute address.
; -> smc + 2 = msb of absolute address.
;
; X holds the lsb of the address.
; Y holds the msb of the address.
;
; Acts as a pseudo "STA X:Y" instruction.
.ORG $200
LDX #$00 ; X = $00
LDY #$40 ; Y = $40
LDA #$FF ; A = $FF
loopy STY smc+2 ; Overwrite the msb
loopx STX smc+1 ; Overwrite the lsb
smc STA $1234 ; Absolute non-zeropage
INX ; X = X + 1
BNE loopx ; X <> 0 goto loopx
INY ; Y = Y + 1
CPY #$80 ; Does Y - $80 == 0
BNE loopy ; If yes goto loopy
BRK ; End
It takes longer (213,637 clock cycles) but, somehow, seems more elegant (IMHO).
I also worried what the reception to self modifying code would be - glad to see nothing is ruled out.
Such as code that has 64 lines of STA instructions (STA $4000,Y; STA $4100,Y; STA $4200,Y ... STA $7F00,Y). Much faster (2.55 times), but takes up more memory.
Re: Using x and y registers as an address
Posted: Sat Dec 18, 2021 10:55 am
by GARTHWILSON
Taking advantage of SMC would be something like
Code: Select all
STZ smc+1
LDA #$40
STA smc+2
LDA #$FF
smc: STA $1234 ; Absolute non-zeropage.
INC smc+1 ; Incr ADL.
BNE smc ; If it rolled over,
INC smc+2 ; then incr ADH also
BPL smc ; Loop until ADH reaches $80.