Newbie question: accessing a 16-bit memory address
Newbie question: accessing a 16-bit memory address
I have a two byte variable in zero page memory which contains the 16-bit address of a ROM table.
I need to access that memory location, but I'm confused on how to do it.
I can LDA , but how do I 'concatenate' the low and hi bytes of the address? Or is there a better way?
Thanks, here's my code:
PF0_addr .word ;zero page variable
...
SET_POINTER PF0_addr, TitleScreen_PF0 ;Macro storing addr of TitleScreen into PFO_addr
...
lda PF0_addr-1,x ;???????
sta PF0
...
TitleScreen_PF0
.byte #%00001100 ; ROM table
.byte #%00010010
...
MAC SET_POINTER
.POINTER SET {1}
.ADDRESS SET {2}
LDA #<.ADDRESS ; Get Lowbyte of Address
STA .POINTER ; Store in pointer
LDA #>.ADDRESS ; Get Hibyte of Address
STA .POINTER+1 ; Store in pointer+1
ENDM
I need to access that memory location, but I'm confused on how to do it.
I can LDA , but how do I 'concatenate' the low and hi bytes of the address? Or is there a better way?
Thanks, here's my code:
PF0_addr .word ;zero page variable
...
SET_POINTER PF0_addr, TitleScreen_PF0 ;Macro storing addr of TitleScreen into PFO_addr
...
lda PF0_addr-1,x ;???????
sta PF0
...
TitleScreen_PF0
.byte #%00001100 ; ROM table
.byte #%00010010
...
MAC SET_POINTER
.POINTER SET {1}
.ADDRESS SET {2}
LDA #<.ADDRESS ; Get Lowbyte of Address
STA .POINTER ; Store in pointer
LDA #>.ADDRESS ; Get Hibyte of Address
STA .POINTER+1 ; Store in pointer+1
ENDM
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
I'm not sure exactly what you're trying to do, but if you don't need indexing and all you want to do is load the accumulator with the contents of the address pointed to by a pair of bytes in ZP, all you need is the one instruction LDA (ZP). It's a two-byte instruction, op code B2, with one byte of operand, and it takes 5 clocks to execute.
If you need indexing into the table and the table is no more than 256 bytes, put the index value in Y and use LDA (ZP),Y, again a 2-byte instruction, with op code B1. Then to step through the table, just increment or decrement Y with the single-byte, two-clock instructions INY or DEY, instead of having to modify the address in ZP.
If you know where the table is at compilation time so you don't even need to refer to the table's address in ZP, just use LDA abs,X, a 3-byte, 4-clock instruction with op code BD.
If you need indexing into the table and the table is no more than 256 bytes, put the index value in Y and use LDA (ZP),Y, again a 2-byte instruction, with op code B1. Then to step through the table, just increment or decrement Y with the single-byte, two-clock instructions INY or DEY, instead of having to modify the address in ZP.
If you know where the table is at compilation time so you don't even need to refer to the table's address in ZP, just use LDA abs,X, a 3-byte, 4-clock instruction with op code BD.
Still not working...
Thanks for your help. This is what I tried...
I have a 2 byte pointer in ZP memory, and another var (ScreenFake) in ZP with an arbitrary value.
I also have a byte past ZP memory (Screen_PF1) with different data. In this example I explicitly set the address for testing purposes. In the real program I wont know it at compile time.
Anyway, the code runs, but only seems to get the LSB of the address, thus loading the data in ScreenFake, not Screen_PF1...
What am I doing wrong?
Thanks again.
Code:
;------------------------------------------------
; Addressing Test
;------------------------------------------------
processor 6502
include vcs.h
include macro.h
;------------------------------------------------
; Constants and Variables
;------------------------------------------------
SEG.U variables
ORG $80
PF1_pointer .word
ScreenFake = $AA
Screen_PF1 = $01AA
;------------------------------------------------
; START OF ROM
;------------------------------------------------
SEG Bank0
ORG $F000 ; 4k ROM start point
;-------------------------------------------------------------------------
; Game
;------------------------------------------------
Start
CLEAN_START ; Clear RAM and Registers
lda #%10001000
sta Screen_PF1
lda #%11111111
sta ScreenFake
SET_POINTER PF1_pointer, Screen_PF1
ldy #0
lda (PF1_pointer),Y
sta PF1
lda #$94
sta COLUPF
.mainLoop
jsr VERTICAL_BLANK
jsr DRAW
jsr WAIT_V_BLANK
jsr OVERSCAN
jmp .mainLoop
;-------------------------------------------------------------------------
; SUBROUTINES
;------------------------------------------------
;***** VERTICAL_BLANK *****
VERTICAL_BLANK
lda #0
sta VBLANK
VERTICAL_SYNC
lda #41 ;41 64-cycle ticks
sta TIM64T
RTS
;***** WAIT_V_BLANK *****
WAIT_V_BLANK
.waitForVBlank
lda INTIM
bne .waitForVBlank
RTS
;***** DRAW *****
DRAW
ldx #220
.drawLine
sta WSYNC
dex
bne .drawLine
RTS
;***** OVERSCAN *****
OVERSCAN
lda #%01000010
sta VBLANK
lda #35
sta TIM64T
.waitForOverscan
lda INTIM
bne .waitForOverscan
RTS
;------------------------------------------------
; Interrupt Vectors
;------------------------------------------------
echo [*-$F000]d, " ROM bytes used"
ORG $FFFA
.word Start ; NMI
.word Start ; RESET
.word Start ; IRQ
END
I have a 2 byte pointer in ZP memory, and another var (ScreenFake) in ZP with an arbitrary value.
I also have a byte past ZP memory (Screen_PF1) with different data. In this example I explicitly set the address for testing purposes. In the real program I wont know it at compile time.
Anyway, the code runs, but only seems to get the LSB of the address, thus loading the data in ScreenFake, not Screen_PF1...
What am I doing wrong?
Thanks again.
Code:
;------------------------------------------------
; Addressing Test
;------------------------------------------------
processor 6502
include vcs.h
include macro.h
;------------------------------------------------
; Constants and Variables
;------------------------------------------------
SEG.U variables
ORG $80
PF1_pointer .word
ScreenFake = $AA
Screen_PF1 = $01AA
;------------------------------------------------
; START OF ROM
;------------------------------------------------
SEG Bank0
ORG $F000 ; 4k ROM start point
;-------------------------------------------------------------------------
; Game
;------------------------------------------------
Start
CLEAN_START ; Clear RAM and Registers
lda #%10001000
sta Screen_PF1
lda #%11111111
sta ScreenFake
SET_POINTER PF1_pointer, Screen_PF1
ldy #0
lda (PF1_pointer),Y
sta PF1
lda #$94
sta COLUPF
.mainLoop
jsr VERTICAL_BLANK
jsr DRAW
jsr WAIT_V_BLANK
jsr OVERSCAN
jmp .mainLoop
;-------------------------------------------------------------------------
; SUBROUTINES
;------------------------------------------------
;***** VERTICAL_BLANK *****
VERTICAL_BLANK
lda #0
sta VBLANK
VERTICAL_SYNC
lda #41 ;41 64-cycle ticks
sta TIM64T
RTS
;***** WAIT_V_BLANK *****
WAIT_V_BLANK
.waitForVBlank
lda INTIM
bne .waitForVBlank
RTS
;***** DRAW *****
DRAW
ldx #220
.drawLine
sta WSYNC
dex
bne .drawLine
RTS
;***** OVERSCAN *****
OVERSCAN
lda #%01000010
sta VBLANK
lda #35
sta TIM64T
.waitForOverscan
lda INTIM
bne .waitForOverscan
RTS
;------------------------------------------------
; Interrupt Vectors
;------------------------------------------------
echo [*-$F000]d, " ROM bytes used"
ORG $FFFA
.word Start ; NMI
.word Start ; RESET
.word Start ; IRQ
END
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Quote:
Anyway, the code runs, but only seems to get the LSB of the address, thus loading the data in ScreenFake, not Screen_PF1...
What am I doing wrong?
What am I doing wrong?
Quote:
it told me it was an illegal addressing mode...
Depending on whether the stack is getting initialized at 1FF at reset and whether there's a system running in the background that might eat up a lot of stack space, it might be a little dangerous to put Screen_PF1 in $01AA where it could get stepped on by the stack. Page 1, especially high in the page, is generally not a good place to put variables.
When you list code on this forum, in order to keep the spaces from getting gobbled up and everything shoved against the left margin, bracket the code with left-square-bracket CODE right-square-bracket (or just mark the block and then click "Code"), and uncheck the "disable BB code" box at the bottom.
SET_POINTER macro
Garth, thanks for the replies. I'm just getting started and this is clearing a lot of things up.
I am coding for the Atari VCS, so I guess I will just use a zero offset when addressing like this.
Here is the SET_POINTER macro. I didn't write it, but it looks like it should write the low and high bytes...
I am coding for the Atari VCS, so I guess I will just use a zero offset when addressing like this.
Here is the SET_POINTER macro. I didn't write it, but it looks like it should write the low and high bytes...
Code: Select all
;-------------------------------------------------------
; SET_POINTER
; Original author: Manuel Rotschkar
;
; Sets a 2 byte RAM pointer to an absolute address.
;
; Usage: SET_POINTER pointer, address
; Example: SET_POINTER SpritePTR, SpriteData
;
; Note: Alters the accumulator, NZ flags
; IN 1: 2 byte RAM location reserved for pointer
; IN 2: absolute address
MAC SET_POINTER
.POINTER SET {1}
.ADDRESS SET {2}
LDA #<.ADDRESS ; Get Lowbyte of Address
STA .POINTER ; Store in pointer
LDA #>.ADDRESS ; Get Hibyte of Address
STA .POINTER+1 ; Store in pointer+1
ENDM
SET_POINTER works, but...
OK, I changed the address to $0AAA.
I did some tests and it looks like both the low and high bytes are getting set,
but LDA (PF1_pointer),#0 only goes to the low byte $0A and
LDA (PF1_pointer+1),#0 only goes to the high byte $AA.
So I still cant get the data from $0AAA...
I did some tests and it looks like both the low and high bytes are getting set,
but LDA (PF1_pointer),#0 only goes to the low byte $0A and
LDA (PF1_pointer+1),#0 only goes to the high byte $AA.
So I still cant get the data from $0AAA...
- BitWise
- In Memoriam
- Posts: 996
- Joined: 02 Mar 2004
- Location: Berkshire, UK
- Contact:
Re: SET_POINTER works, but...
wstjohn wrote:
LDA (PF1_pointer),#0
LDA (PF1_pointer+1),#0
LDA (PF1_pointer+1),#0
Code: Select all
LDY #0
LDA (PF1_pointer),Y ; Fetch first byte
STA XXX ; And do something with it
INY
LDA (PF1_pointer),Y ; Fetch following byte.
STA YYY ; ...
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
BitWise,
I'm not sure I understand you. In my example, PF1_pointer is a 2 byte pointer to some location past zero page memory, say $FFAA.
The first byte contains the low byte of the address #$AA and the second byte contains the high byte of the address #$FF.
I need to use the pointer to somehow load the value at $FFAA into a register.
Can LDA (PF1_pointer), #0 do this?
Thanks for the input.
I'm not sure I understand you. In my example, PF1_pointer is a 2 byte pointer to some location past zero page memory, say $FFAA.
The first byte contains the low byte of the address #$AA and the second byte contains the high byte of the address #$FF.
I need to use the pointer to somehow load the value at $FFAA into a register.
Can LDA (PF1_pointer), #0 do this?
Thanks for the input.
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
When you do LDY #0, LDA (PF1_pointer),Y, the processor reads two bytes in ZP to get the 16-bit address at PF1_pointer, and adds the Y value to it to get the address of the one byte it will read into the accumulator. The Y being outside the parentheses means the Y value is not added until after the address is read from ZP. So LDA (anything),Y will always read two consecutive ZP bytes, and of course put one byte at the final resulting address into A.
LDA (PF1_pointer),Y can do it, all in one instruction if 0 is already in Y. The way you wrote it, although not a legal notation, is what LDA (PF1_pointer) on the 65c02 would do, without your needing to load 0 into Y first.
Quote:
Can LDA (PF1_pointer), #0 do this?
- BitWise
- In Memoriam
- Posts: 996
- Joined: 02 Mar 2004
- Location: Berkshire, UK
- Contact:
wstjohn wrote:
BitWise,
I'm not sure I understand you. In my example, PF1_pointer is a 2 byte pointer to some location past zero page memory, say $FFAA.
The first byte contains the low byte of the address #$AA and the second byte contains the high byte of the address #$FF.
I need to use the pointer to somehow load the value at $FFAA into a register.
Can LDA (PF1_pointer), #0 do this?
Thanks for the input.
I'm not sure I understand you. In my example, PF1_pointer is a 2 byte pointer to some location past zero page memory, say $FFAA.
The first byte contains the low byte of the address #$AA and the second byte contains the high byte of the address #$FF.
I need to use the pointer to somehow load the value at $FFAA into a register.
Can LDA (PF1_pointer), #0 do this?
Thanks for the input.
Code: Select all
DATAVAL EQU $FFAA
ZPPTR EQU $80
LDA #<DATAVAL ; Should evaluate to $AA
STA ZPPTR
LDA #>DATAVAL ; Should evaluate to $FF
STA ZPPTR+1
; then either
LDY #0
LDA (ZPPTR),Y ; A contains byte at DATAVAL ($FFAA) address
; or
LDX #0
LDA (ZPPTR,X) ; A contains byte at DATAVAL ($FFAA) address
The (),Y form is more useful if you are going to access several (usually contiguous) bytes from the same memory area.
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
BitWise,
Yeah, that is exactly what I'm trying to do, and exactly the code I used.
But, what gets loaded into A is only the low byte, not both together!!!
Is this what should happen?
???
Yeah, that is exactly what I'm trying to do, and exactly the code I used.
But, what gets loaded into A is only the low byte, not both together!!!
Is this what should happen?
Code: Select all
pointer .word
data = $9955
...
LDA #<data
STA pointer
LDA #>data
STA pointer+1
...
;at this point I have verified that pointer contains #$55
;and pointer+1 contains #$99
...
;however, after this:
LDA (pointer)
STA PF0
;PF0 contains the data from $55, not from $9955
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact: