Range error with indirect addressing in CC65

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Range error with indirect addressing in CC65
by on (#152090)
Since I didn't find an NES game with a female character that matches my taste, I decided to program one myself. So, I picked up NES programming again.
Last time, I didn't have an idea for a game, so I made slow progress, but this time I have a concept and I'm much more motivated.
I went through the Nerdy Nights tutorials again and now I also have a much better understanding of all that stuff than last time.

Since I'm planning to write some of the code in C, my first step is to convert my NESASM3 sample program into CC65 syntax. And there's where I've encountered the first problem:

In NESASM3, I had the following code to fill all the background tiles with values:
Code:
   LDA #LOW(background)
   STA pointerLo
   LDA #HIGH(background)
   STA pointerHi
   LDX #$00
   LDY #$00
OutsideLoop:
InsideLoop:
   LDA [pointerLo], y
   ; and so on.

In CC65, this produced errors and I changed the following:


I changed #HIGH to .HIWORD and #LOW to .LOWORD.
Is this the correct function?


Then I changed LDA [pointerLo], y to LDA (pointerLo), y.

But now, regarding this line, the compiler tells me:
"Error: Range error"

The pointer variable is declared in the zero page:
Code:
.segment "ZP"

pointerLo: .res 1
pointerHi: .res 1

And my call is simply:
ca65 Test.s
(I don't link yet, I just try to create the object file for now.)

What am I doing wrong here?
Re: Range error with indirect addressing in CC65
by on (#152092)
DRW wrote:
I changed #HIGH to .HIWORD and #LOW to .LOWORD.
Is this the correct function?

Nope. HIGH should become .HIBYTE and LOW should become .LOBYTE.

Quote:
Then I changed LDA [pointerLo], y to LDA (pointerLo), y.

That's correct.

Quote:
But now, regarding this line, the compiler tells me:
"Error: Range error"

The pointer variable is declared in the zero page:
Code:
.segment "ZP"

pointerLo: .res 1
pointerHi: .res 1


What am I doing wrong here?

You need to specify that the segment is a zeropage segment like this:
Code:
.segment "ZP" : zeropage

If the segment's name is "ZEROPAGE" or you use .zeropage, this is done automatically.
Re: Range error with indirect addressing in CC65
by on (#152103)
thefox wrote:
If the segment's name is "ZEROPAGE", this is done automatically. If you use .zeropage, this is done automatically.

Both the stricken statement and the added statement are correct, to the best of my knowledge. I use .segment "ZEROPAGE" and it's automatically marked as zero page.

Is there a difference between the syntax .segment "ZEROPAGE", zeropage and .segment "ZEROPAGE": zeropage?
Re: Range error with indirect addressing in CC65
by on (#152106)
tepples wrote:
thefox wrote:
If the segment's name is "ZEROPAGE", this is done automatically. If you use .zeropage, this is done automatically.

Both the stricken statement and the added statement are correct, to the best of my knowledge. I use .segment "ZEROPAGE" and it's automatically marked as zero page.

Ah, that might be. I also had a faint memory it might be true, but didn't see a mention about it in the docs and couldn't bother to test it. :)

Quote:
Is there a difference between the syntax .segment "ZEROPAGE", zeropage and .segment "ZEROPAGE": zeropage?

Yes, the syntax used in the docs doesn't work. I also noticed that earlier and opened an issue about it in cc65 issue tracker.
Re: Range error with indirect addressing in CC65
by on (#152113)
Thanks for the answers. I see it now: The name "ZP" in the config file is part of the "MEMORY" section, but I of course have to take the values from the "SEGMENTS" section where it's indeed called "ZEROPAGE".


thefox wrote:
DRW wrote:
I changed #HIGH to .HIWORD and #LOW to .LOWORD.
Is this the correct function?

Nope. HIGH should become .HIBYTE and LOW should become .LOBYTE.

While it doesn't produce an error anymore, the code
Code:
   LDA .LOBYTE(background)
   ; ...
   LDA .HIBYTE(background)

produces a warning for each line:
"Warning: Suspicious address expression"

The background label is in the RODATA segment:
Code:
.segment "RODATA"
background:
   .byte $24, $24, $24, $24, $24, $24, $24, $24, $24, $24, $24, $24, $24, $24, $24, $24
   ; etc.

Can this warning be circumvented?
Re: Range error with indirect addressing in CC65
by on (#152115)
The "Suspicious address expression" is defined in instr.c. Based on my reading of the if statement that triggers this warning, it appears to happen when you take the low byte or high byte of an address defined in a zeropage segment. Beyond that, I don't know; I'm just giving others a starting point for research.
Re: Range error with indirect addressing in CC65
by on (#152140)
The warning "Suspicious address expression" is a warning for when you load a high or low byte of a label and don't use the immediate operator:

Example:
Code:
mydata: .byte 12h,23h,34h,45h,57h

lda >mydata     ; the same as lda .hibyte(mydata)
ldx <mydata     ; the same as ldx .lobyte(mydata)
jsr processData

vs
Code:
mydata: .byte 12h,23h,34h,45h,57h

lda #>mydata     ; the same as lda #.hibyte(mydata)
ldx #<mydata     ; the same as ldx #.lobyte(mydata)
jsr processData

You probably want the second thing. If you want to just load data from the table, just do:
Code:
lda mydata

Or use x indexing or constant offset or both.
Re: Range error with indirect addressing in CC65
by on (#152159)
Thanks a lot for the solution. Not only did it remove the warning, but it also corrected the faulty behavior that I got that I would have asked about next. (The background data was all nonsense. But now that I changed the lines by using the direct value with #, it works exactly as my NESASM program.)

Edit:
And now I also see why I did the error in the first place: I thought #LOW is the function name. But actually, the function name is LOW and the # is of course the "value of address" operator.