Ca65 "Constant expression expected"

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Ca65 "Constant expression expected"
by on (#173499)
So, I have a struct for an object slot, and that's fine, but for whatever reason, ca65 doesn't like what I'm doing here:

Code:
ObjectTable:      .res *-ObjectSlot*16

Doesn't "*-" mean the size of?
Re: Ca65 "Constant expression expected"
by on (#173500)
I read *-ObjectSlot-16 to mean "{whatever the assembler thinks PC or the current 16-bit address is} minus {whatever ObjectSlot is} minus 16".
Re: Ca65 "Constant expression expected"
by on (#173501)
It's multiplied by 16.
Re: Ca65 "Constant expression expected"
by on (#173502)
You can use .sizeof to get the size of a struct.
Re: Ca65 "Constant expression expected"
by on (#173505)
When applying that to the code, it says "unexpected trailing garbage characters"

Code:
ObjectTable:      .res.sizeof(ObjectSlot)x16
Re: Ca65 "Constant expression expected"
by on (#173508)
Try a space after .res and an asterisk instead of an x:
Code:
ObjectTable:      .res .sizeof(ObjectSlot)*16
Re: Ca65 "Constant expression expected"
by on (#173510)
1. No space between .res and .sizeof?
2. Are you expecting x16 to mean "times 16"? You might meant * 16?
(Edit: tepples made both those points already.)

What's ObjectSlot? Is it in the same segment?

It seems like ObjectTable - ObjectSlot might substitute for * - ObjectSlot in this case. The expression * is constant at link time, but not at assembly time. I'm not sure how smart the assembler is at deducing relative constants with it; it might fare better with labels in this respect? Possibly the problem is exacerbated because .res needs to evaluate constant immediately during the single pass assembly.
Re: Ca65 "Constant expression expected"
by on (#173517)
It sounds like ObjectSlot is a struct, so they definitely don't want ObjectTable - ObjectSlot or * - ObjectSlot.
Re: Ca65 "Constant expression expected"
by on (#173552)
Yeah, thanks guys, this works. :)

Code:
.res .sizeof(ObjectSlot)*16
Re: Ca65 "Constant expression expected"
by on (#173952)
Not directly related to the problem earlier, but why start a new thread. I saw that I had something like:

Code:
SpriteBuf1:   .res $200
SpriteBuf1Size=   *-SpriteBuf1

So I went and replaced every instance of SpriteBuf1Size with *-SpriteBuf1. I also had something that was SpriteBuf1Size+SpriteBuf2Size, that was just called "SpriteBufSize". It was being used at this "assert" that I noticed:

Code:
.assert (SpriteBufSize < $10000), error, "SpriteBufs area too big for SNES DMA transfer"

So I changed it to this:

Code:
.assert (*-SpriteBuf1+*-SpriteBuf2 < $10000), error, "SpriteBufs area too big for SNES DMA transfer"

However, for some reason unknown to me, it triggers the error. Is this not right? There's no way it could be too big:

Code:
SpriteBuf1:      .res $200   ;Sprite buffer for OAM DMA, 512 ($200) bytes
SpriteBuf2:          .res $20   ;Sprite buffer for OAM DMA, 32  ($20) bytes

Actually, wait, what? (referring to "*")

Quote:
whatever the assembler thinks PC or the current 16-bit address is

How does this minus where something is equal the size of something?
Re: Ca65 "Constant expression expected"
by on (#173955)
Espozo wrote:
Code:
.assert (*-SpriteBuf1+*-SpriteBuf2 < $10000), error, "SpriteBufs area too big for SNES DMA transfer"

However, for some reason unknown to me, it triggers the error. Is this not right? There's no way it could be too big:

Code:
SpriteBuf1:      .res $200   ;Sprite buffer for OAM DMA, 512 ($200) bytes
SpriteBuf2:          .res $20   ;Sprite buffer for OAM DMA, 32  ($20) bytes

Actually, wait, what? (referring to "*")

Quote:
whatever the assembler thinks PC or the current 16-bit address is

How does this minus where something is equal the size of something?

You don't seem to understand what * actually does, or what it is for.

If there was a label on the current line, * would be the address of that label. It has a different value on every line.

I don't know what you expect to be doing by measuring some current address (wherever that assert gets assembled) against both SpriteBuf1 and SpriteBuf2 at the same time. Both * in that statement must have the same value! * is just a single address value, it is not some sort of "sizeof" operator.

Espozo wrote:
So I went and replaced every instance of SpriteBuf1Size with *-SpriteBuf1. I also had something that was SpriteBuf1Size+SpriteBuf2Size, that was just called "SpriteBufSize".

Have fun replacing them all again to fix the problems you've just created for yourself. :P

Here's a alternative:
Code:
SpriteBuf1Size = $200
SpriteBuf1: .res SpriteBuf1Size
Re: Ca65 "Constant expression expected"
by on (#173958)
Put another way, * is the current address wherever you happen to use it.

So, for this code:
Code:
SpriteBuf1:   .res $200
SpriteBuf1Size=   *-SpriteBuf1

Let's say SpriteBuf1 is at the address $1000. Then, after reserving $200 bytes, the current address is now $1200. Therefore, * is $1200 at this point, so (* - SpriteBuf1) = ($1200 - $1000) = $200. This is why your old code worked.

However, you can't just replace everywhere you used SpriteBuf1Size with * - SpriteBuf1, because *'s value changes depending on where it's used.

If you later have a line like this at address $5000:
Code:
lda *-SpriteBuf1

This won't have the desired effect, because the calculation will now be $5000 - $1000 = $4000.
Re: Ca65 "Constant expression expected"
by on (#173959)
I don't know where you got that "* minus something is the size of something" thing from, but like Nicole showed, this is only true if you do this calculation immediately after "something" is defined. Do this anywhere else you'll not get the size of "something".
Re: Ca65 "Constant expression expected"
by on (#173961)
tokumaru wrote:
I don't know where you got that "* minus something is the size of something" thing from, but like Nicole showed, this is only true if you do this calculation immediately after "something" is defined. Do this anywhere else you'll not get the size of "something".

He got it from me, where I misread *16 as -16, which he promptly noticed, which just makes (his) misunderstanding even more confusing.
Re: Ca65 "Constant expression expected"
by on (#173962)
I just figured I'd point out to Espozo that this is not wrong, it's a valid way to get the size of something that isn't a struct, but only if you do it right after the thing is defined. Just in case this wasn't clear in the place where he read about this.

Still, I wouldn't use this to get the size of a simple array... I would probably use a constant to hold the size, kinda like rainwarrior suggested. I use PC calculations for more complicated scenarios though, such as a bunch of variables I need 2 versions of (related to raster effects): the first block is declared normally, and then I get its size to reserve space for the second block. I also use the size as an index when I need to access the second block.
Re: Ca65 "Constant expression expected"
by on (#173963)
The only time I seem to use * in my code is with asserts.

Most often I use it to verify that I didn't make a mistake when creating a table (same as the "sizeof" idiom):
Code:
TABLE_SIZE = 30
table:
.byte 1,2,3,4,5,6,7,8,9
.byte 5,6,7,8,9
.assert (*-table) = TABLE_SIZE, error, "incorrect number of entries in table"


Sometimes I use it to verify code page alignment when specific timing is needed:
Code:
label:
   lda #1
   sta nmi_lock
   :
      bit $2002
      bvs :-
   :
      bit $2002
      bmi @fail
      bvc :-
   lda #0
   sta $2005
   sta $2006
   .assert (* & $FF00) = (label & $FF00), error, "code crosses page boundary"


Note that * is just a way of creating a temporary label for the current line, i.e. you can do the same stuff with a regular label:
Code:
SpriteBuf1: .res $200
SpriteBuf1End:
SpriteBuf1Size = SpriteBuf1End - SpriteBuf1