Newbie question: accessing a 16-bit memory address

Programming the 6502 microprocessor and its relatives in assembly and other languages.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

Do you have a way to run it on the actual hardware? The NMOS processor had a few bugs and quirks but this is not one of them, and the CMOS has them all fixed; so this instruction will always operate correctly on both. I'm not familiar with either of the simulators Stella or Z26. I wonder if they both came from a common source with a bug... unless we're still missing something you or your system is doing. Just out of curiosity, see if pointer+1 still has the right value in it, or if something else put a 0 there.
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

wstjohn wrote:

Code: Select all

;however, after this:
LDA  (pointer)
STA  PF0
;PF0 contains the data from $55, not from $9955

Does your code literally contain the line .. ?

Code: Select all

LDA  (pointer)
If your assembler (or selected processor) does not support indirect addressing then '(pointer)' may being interpreted as a parenthenised expression (e.g like C * (A + B) ) in which case the assember would generate a zero page load and not an indirect load. This would explain the behaviour you describe.

Look at your assembler listing and compare the opcode with the table here http://www.obelisk.demon.co.uk/6502/reference.html#LDA.
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
wstjohn
Posts: 19
Joined: 04 Mar 2007

Post by wstjohn »

I originally tried
LDA (pointer)
but dasm wouldnt compile it saying it was an unsupported address mode.
So the code I used is:
LDY #0
LDA (pointer),Y ;which is supported
STA PF1

Here's the actual code:

Code: Select all

;------------------------------------------------
; Addressing Test
;------------------------------------------------
  processor 6502
  include vcs.h
  include macro.h
;------------------------------------------------
; Constants and Variables
;------------------------------------------------
  SEG.U   variables
  ORG     $80
PF1_pointer   .word                  ;the two byte pointer in ZP
Screen_PF1 = $FFAA                ;the address of the actual data I want (I won't really know this at compile time in the actual program)
Screen_WrongAddress = $AA   ;the address that actually gets loaded
;------------------------------------------------
; START OF ROM
;------------------------------------------------
  SEG   Bank0
	ORG   $F000       	; 4k ROM start point
;-------------------------------------------------------------------------
; Game
;------------------------------------------------
Start 
  CLEAN_START			; Clear RAM and Registers
  lda   #%10101010
  sta   Screen_PF1
  lda   #%11111111
  sta   Screen_WrongAddress

  LDA #<Screen_PF1  ; Get Lowbyte of Address
  STA PF1_pointer    ; Store in pointer
  LDA #>Screen_PF1 ; Get Hibyte of Address
  STA PF1_pointer+1  ; Store in pointer+1
      
  ldy   #0
  lda   (PF1_pointer),Y          ;I WANT TO LOAD $FFAA INTO A
  sta   PF1                           ;BUT PF1 ONLY GETS $AA

  ;the rest is just Atari stuff...

.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
Thanks again for all your help. I hope this isnt a bug in the compiler or emulator...
gnb10
Posts: 5
Joined: 06 Mar 2007

Post by gnb10 »

The test case is confusing because $AA is both one of the values stored and
part of the address. In general it's worth putting together such tests so that
each number can come from only one possible place in the code. So here, if you change
lda #%10101010
sta Screen_PF1
to
lda #%01010101
sta Screen_PF1

you should see that
lda (PF1_pointer),Y
sets A to $55. This is what indirect addressing does: the word 'pointer' is set to
the value $FFAA (with the correct byte order) so
lda (PF1_pointer),Y loads the value of the byte at location $FFAA
(assuming Y is zero) in A. The fact that that value happened to be $AA in
your example is just a distraction.
By the way, the comment says:
;I WANT TO LOAD $FFAA INTO A
;BUT PF1 ONLY GETS $AA
The wording seems wrong: A is only 8 bits wide, but the comment reads as
though you expect to get the _value_ $FFAA into, rather than the byte stored
at $FFAA.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

I see gnb10 posted while I was writing this, but I'll finish anyway.

Code: Select all

 CLEAN_START         ; Clear RAM and Registers
  lda   #%10101010
  sta   Screen_PF1
  .
  .
  .
  ldy   #0
  lda   (PF1_pointer),Y          ;I WANT TO LOAD $FFAA INTO A
  sta   PF1                      ;BUT PF1 ONLY GETS $AA 
If you mean the data you pick up is AA, that's what you put in Screen_PF1, so it's working right. If the data you're reading is FF from location 00AA, then it seems like there's a bug in the simulator.

Are you set up to try it on actual hardware? Simulators are of course intended to be a tool to get you going faster and help you see exactly what's going on, but after years of talking to people on these forums (this one, plus the 6502 Yahoo forum which was basically ruined by spammers, and earlier, the Delphi forum), it seems to me that the people using simulators generally don't get as far as those not using them. I'd be happy to hear discussion on it and try to nail down the exact reasons better (I think it's the mentality), but this has been my perception. My own limited use of simulators has been rather frustrating. I've written 10,000-line applications and debugged them without a simulator, writing my own routines to examine the contents of registers and the progress of other routines in the process. I'll save that discussion for later. (I'll get off my "philosopher" podium now... <stepping down>...)
wstjohn
Posts: 19
Joined: 04 Mar 2007

Post by wstjohn »

gnb10 wrote:
The test case is confusing because $AA is both one of the values stored and
part of the address. In general it's worth putting together such tests so that
each number can come from only one possible place in the code. So here, if you change
lda #%10101010
sta Screen_PF1
to
lda #%01010101
sta Screen_PF1

you should see that
lda (PF1_pointer),Y
sets A to $55. This is what indirect addressing does: the word 'pointer' is set to
the value $FFAA (with the correct byte order) so
lda (PF1_pointer),Y loads the value of the byte at location $FFAA
(assuming Y is zero) in A. The fact that that value happened to be $AA in
your example is just a distraction.
By the way, the comment says:
;I WANT TO LOAD $FFAA INTO A
;BUT PF1 ONLY GETS $AA
The wording seems wrong: A is only 8 bits wide, but the comment reads as
though you expect to get the _value_ $FFAA into, rather than the byte stored
at $FFAA.
No, the value in A wasn't $AA, it was the value at memory location $AA, which is #%11111111.
I followed your advice on changing the data in Screen_PF1 to #$55 (01010101). However, register A still gets the value at location $AA, which is #%11111111, not the value at location $FFAA, which is #%01010101.

I'm pretty sure I'm doing what everyone has suggested, but it just isnt working the way is should. Maybe the compiler is the culprit???

Thanks again.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

Quote:
Maybe the compiler is the culprit???
If your assembler offer the option of making a .lst file, use that first. It will show your original source code along with, to the left of each line, the actual bytes laid down for the processor to use. If you don't have that, you can pick apart the .hex code. That's more of a hassle, but I've done it to figure out problems in a compiler for a higher-level language we bought that had more bugs than an ant hill.
wstjohn
Posts: 19
Joined: 04 Mar 2007

Post by wstjohn »

Garth,
I don't have access to the actual hardware yet, but I can work on that. I tried it on two different emulators with the same effect...

AHA! I tried with a third emulator, and it works the way it should!!!

I guess this teaches me a lesson about real hardware vs. emulators.

I really appreciate everyone's help!

Wes
gnb10
Posts: 5
Joined: 06 Mar 2007

Post by gnb10 »

Ah, I'd misunderstood what you meant by ;BUT PF1 ONLY GETS $AA
sorry about the noise.
Mats
Posts: 111
Joined: 24 Aug 2003

Post by Mats »

Many people have the ambition to write 6502 simulators, obviously not all these attempts result in perfect products!

I personally recommend Michal Kowalski's simulator (with integrated assembler) that is much used and certainly is completly "bug free". Can be downloaded from:

http://home.pacbell.net/michal_k/6502.html

If the assembler/simulator you are using not even works for the simple construction

LDY #$00
STA (ZPADD),Y

you better put it in the trash bin!
Mats
Posts: 111
Joined: 24 Aug 2003

Post by Mats »

Here it is, runs perfectly on the Kowalski simulator. Note that with the Kowalski system one has to use ".BYTE" instead of ".BYT". There is no generally used standard!

Code: Select all

PF0_addr = $00   ;SOME ZERO PAGE ADDRESS, HERE $00 SELECTED
; 
 *=$0302          ;START OF CODE
;
;SET_POINTER PF0_addr, TitleScreen_PF0 ;Macro storing addr of TitleScreen into PFO_addr
;CODE REPLACING MACRO ABOVE FOR THE CASE THAT "addr of TitleScreen" IS "TitleScreen_PF0" = $0400
;
      LDA #<TitleScreen_PF0
      STA PF0_addr
      LDA #>TitleScreen_PF0
      STA PF0_addr+1
;
;LOOP ACCESSING THE 10 FIRST VALUES OF TABLE
;
      LDY #$00
LOOP  LDA (PF0_addr),Y
;
;DO SOEMETHING
;
      INY
      CPY #$0A
      BNE LOOP
      BRK
 *=$0400
TitleScreen_PF0   .BYTE  $00
                  .BYTE  $01
                  .BYTE  $02
                  .BYTE  $03
                  .BYTE  $04
                  .BYTE  $05
                  .BYTE  $06
                  .BYTE  $07
                  .BYTE  $08
                  .BYTE  $09

Mats
Posts: 111
Joined: 24 Aug 2003

Post by Mats »

Sorry not

CPY #$0A

but

CPY #$09

to get the 10 values 0,..,9
wstjohn
Posts: 19
Joined: 04 Mar 2007

Post by wstjohn »

Thanks Mats, I will try that one.
I will need to because I had tried just what you have in your example and it didnt work. If I did it manually, like this:

Code: Select all

  LDX  #0
  LDA  (ZPpointer),X
  STA  PF0
  ;do something with PF0
  LDX  #1
  LDA  (ZPpointer),X
  STA  PF0
  ;do something with PF0
  LDX  #2
  ;etc
then it would actually get each line from the rom table. However, if I did it in a loop, it didnt work at all:

Code: Select all

  LDX  #0
.loop
  LDA  (ZPpointer),X
  STA  PF0
  ;do something with PF0
  INX
  CPX  #9 ;or however many lines it has
  BNE  .loop
I tried this with the dasm assembler on three different emulators with the same results, so I will take your advice...
Mats
Posts: 111
Joined: 24 Aug 2003

Post by Mats »

Sorry not

CPY #$0A

but

CPY #$09

to get the 10 values 0,..,9
Mats
Posts: 111
Joined: 24 Aug 2003

Post by Mats »

Hello

I just looked at your code! You must use the Y-register, not the X-register

LDA (zp),Y

is fine but

LDA (zp),X

is illegal addressing, not implemented on the 6502.
Post Reply