??? In my quote that you truncated I said I think of it as useful for that kind of thing like a couple words after you truncated it. ???tepples wrote:And unfortunately no "I care, but I'd like to be able to move the most commonly accessed variables into zero page and less commonly used variables out as part of a size optimization effort late in development once I start seeing MEMORY area overflow errors from ld65, and I don't know yet which variables those will be" option.
CA65: zp -> abs when using nested .procs
Moderator: Moderators
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: CA65: zp -> abs when using nested .procs
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: CA65: zp -> abs when using nested .procs
I'm trying to understand why my code is now successfully assembling zp instructions with nested scopes. Using the old example in this thread, I found if I declare an equate outside the nested scope and assign the zp variable in question to it, then I get zp instructions as inspected.
Coincidentally, the macro system I came up with for declaring zp equates here puts most of my code into this pattern, so I get the code I expect. Does anyone understand why this works around the issue?
This example will compile just fine, whereas the OP generates absolute instructions and a range error.
*edit* Perhaps the reason it works is that it ultimately works the same as though I typed ::b0 instead of using the equate my_b0. (the wiki article linked in the op refers to the :: operator to search the global scope)
Coincidentally, the macro system I came up with for declaring zp equates here puts most of my code into this pattern, so I get the code I expect. Does anyone understand why this works around the issue?
This example will compile just fine, whereas the OP generates absolute instructions and a range error.
*edit* Perhaps the reason it works is that it ultimately works the same as though I typed ::b0 instead of using the equate my_b0. (the wiki article linked in the op refers to the :: operator to search the global scope)
Code: Select all
.globalzp b0
.proc test
my_b0 = b0
lda b0
.proc nested_proc
beq label
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
sta my_b0
.repeat 86
nop
.endrepeat
label:
rts
.endproc
.endproc
Last edited by GradualGames on Sun Aug 06, 2017 5:44 pm, edited 1 time in total.
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: CA65: zp -> abs when using nested .procs
I know that you're using all those nops to generate a range error, but it really hurts my ability to try and read this thread. A comment that says "generates a ZP instruction" or something would be sufficient, or even a .repeat to make it shorter.
In your new example "lda b0" is referencing b0, known from one scope above, and known to be ZP, so it's ZP.
Secondly "sta my_b0" is referencing my_b0, also known from one scope above. Since you're saying it correctly realizes it's ZP, I would guess it's inheriting the ZP property from b0 from that = assignment.
At least, that's presuming my belief that it looks for matching symbols from one scope above (but no deeper) when determining operand size is correct.
Edit: It's not correct, see thefox's explanation below.
In your new example "lda b0" is referencing b0, known from one scope above, and known to be ZP, so it's ZP.
Secondly "sta my_b0" is referencing my_b0, also known from one scope above. Since you're saying it correctly realizes it's ZP, I would guess it's inheriting the ZP property from b0 from that = assignment.
At least, that's presuming my belief that it looks for matching symbols from one scope above (but no deeper) when determining operand size is correct.
Edit: It's not correct, see thefox's explanation below.
Last edited by rainwarrior on Mon Aug 07, 2017 5:25 am, edited 1 time in total.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: CA65: zp -> abs when using nested .procs
Interestingly, I'm getting zp instructions as expected at least 2 scopes deep in cases I've inspected (been looking at one routine where I used a ton of scopes), using this pattern. You can even add further nested scopes in this example and it will still work.rainwarrior wrote:I know that you're using all those nops to generate a range error, but it really hurts my ability to try and read this thread. A comment that says "generates a ZP instruction" or something would be sufficient, or even a .repeat to make it shorter.
In your new example "lda b0" is referencing b0, known from one scope above, and known to be ZP, so it's ZP.
Secondly "sta my_b0" is referencing my_b0, also known from one scope above. Since you're saying it correctly realizes it's ZP, I would guess it's inheriting the ZP property from b0 from that = assignment.
At least, that's presuming my belief that it looks for matching symbols from one scope above (but no deeper) when determining operand size is correct.
*edit* Nevermind, I found a counterexample (using the example code. In my game's code, I'm still getting zp where I expect, for some reason.)
Code: Select all
000004r 1 .scope
000004r 1 85 rr sta my_b0
000006r 1 85 rr sta my_b0
000008r 1 85 rr sta my_b0
00000Ar 1 85 rr sta my_b0
00000Cr 1 85 rr sta my_b0
00000Er 1 85 rr sta my_b0
000010r 1 .scope
000010r 1 8D rr rr sta my_b0
000013r 1 8D rr rr sta my_b0
000016r 1 8D rr rr sta my_b0
000019r 1 8D rr rr sta my_b0
00001Cr 1 .endscope
00001Cr 1 85 rr sta my_b0
00001Er 1 85 rr sta my_b0
000020r 1 85 rr sta my_b0
000022r 1 85 rr sta my_b0
000024r 1 .endscope
Re: CA65: zp -> abs when using nested .procs
I think the first part is true (my_b0 gets flagged SF_DEFINED and the address size is derived from the expression), but the second part is not.rainwarrior wrote:Secondly "sta my_b0" is referencing my_b0, also known from one scope above. Since you're saying it correctly realizes it's ZP, I would guess it's inheriting the ZP property from b0 from that = assignment.
At least, that's presuming my belief that it looks for matching symbols from one scope above (but no deeper) when determining operand size is correct.
It's easy to disprove the theory that it only looks one scope above:
Code: Select all
.globalzp foo
start:
.scope
.scope
.scope
.scope
lda foo ; uses zp
.endscope
.endscope
.endscope
.endscope
end:
.out .sprintf("size=%d", end-start)
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: CA65: zp -> abs when using nested .procs
Well, I've got no clue then.
Is nesting depths a red herring? Why does it happen in the case I wrote but not this one? Does the problem ever happen when scopes are just a single level?
Is nesting depths a red herring? Why does it happen in the case I wrote but not this one? Does the problem ever happen when scopes are just a single level?
Re: CA65: zp -> abs when using nested .procs
In the case you wrote var0 was referenced in the first scope, so the reference itself gets an internal new symbol (with name var0) in the symbol table of that scope. Then in the inner scope second when it starts recursively looking for var0 in parent scopes, it finds that symbol reference, and uses it. But the reference doesn't have a size assigned to it, so it defaults to abs.rainwarrior wrote:Is nesting depths a red herring? Why does it happen in the case I wrote but not this one? Does the problem ever happen when scopes are just a single level?
It seems like the fact that it even considers symbol references here could be a bug, but what do I know. At the very least the behavior is very inconsistent. The comment at https://github.com/cc65/cc65/blob/maste ... tab.c#L440 says that it ignores symbols with type SF_UNUSED because for such symbols "there is a real entry in one of the parent scopes". It seems that the same should be true for SF_REFERENCED. (That said, it's certainly possible to reference symbols which have not been defined yet...)
I don't think the problem can happen with single-level scopes:
Code: Select all
.globalzp foo ; "foo" gets added in the symbol table with SF_GLOBAL and address size=1.
lda foo ; Uses zp. SF_REFERENCED flag is added to the existing symbol foo (NOTE: SF_xxx is a bitmask).
.scope s
lda foo ; Finds "foo" in the parent scope with proper size, so uses zp. A new symbol named "foo" with SF_REFERENCED is added in this scope.
.endscope
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: CA65: zp -> abs when using nested .procs
Oh! So the problem is that using a symbol from a parent scope creates some kind of "dummy" version of that symbol that might block the ZP property from propagating to any nested scopes?
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: CA65: zp -> abs when using nested .procs
It seems if I have an equate set to the global zp value at the top level or just one level down, it propagates as far as one would like. but if I put the equate itself inside any of the nested scopes, then I get abs.
Example with equate in inner scope (abs instruction generated)
Example with equate at top level scope (zp generated). *edit* Noticed moving "my_b0 = b0" to global scope also generates zp. Maybe the point is that .globalzp doesn't define a symbol but only a property a symbol should have ONCE defined. So if you define them at the top level or global scope, you're fine. This makes me quite happy with my zp_equates macros, as I apparently accidentally solved this problem for myself, just didn't realize it was this thoroughly solved til now. Haha!
*edit* Amusingly the documentation pretty much spells this out. "Of course the most simple solution for the problem is to move the definition of foo in scope inner upwards, so it precedes its use." But, one doesn't think about this normally. One would like to just use an include with a .globalzp my_symbol and just use it and know it is zp. But re-creating an equate seems like a fine workaround to me.
Example with equate in inner scope (abs instruction generated)
Code: Select all
.globalzp b0
.scope
lda b0
.scope
my_b0 = b0
.scope
.scope
lda my_b0
.endscope
.endscope
.endscope
.endscope
*****LISTING*****
000000r 1 .globalzp b0
000000r 1
000000r 1 .scope
000000r 1
000000r 1 A5 rr lda b0
000002r 1
000002r 1 .scope
000002r 1 my_b0 = b0
000002r 1 .scope
000002r 1 .scope
000002r 1 AD rr rr lda my_b0
000005r 1 .endscope
000005r 1 .endscope
000005r 1 .endscope
000005r 1
000005r 1 .endscope
000005r 1
000005r 1
Code: Select all
.globalzp b0
.scope
my_b0 = b0
lda b0
.scope
.scope
.scope
lda my_b0
.endscope
.endscope
.endscope
.endscope
*****LISTING*****
000000r 1 .globalzp b0
000000r 1
000000r 1 .scope
000000r 1
000000r 1 my_b0 = b0
000000r 1
000000r 1 A5 rr lda b0
000002r 1
000002r 1 .scope
000002r 1 .scope
000002r 1 .scope
000002r 1 A5 rr lda my_b0
000004r 1 .endscope
000004r 1 .endscope
000004r 1 .endscope
000004r 1
000004r 1 .endscope
000004r 1
000004r 1
Last edited by GradualGames on Mon Aug 07, 2017 5:55 am, edited 3 times in total.
Re: CA65: zp -> abs when using nested .procs
Yeah, it kind of makes sense and kind of doesn't. In the single-level scope example in my previous post, I guess it's adding the "dummy" reference symbol in case a symbol named "foo" gets defined later in the same scope (if it does get defined, SF_DEFINED would be added to the "dummy" symbol). What doesn't make so much sense is the fact it still uses the address size from "foo" from the parent scope. So it's kind of pessimistic by making the assumption that it might get redefined, but then still uses information from the parent scope's symbol.rainwarrior wrote:Oh! So the problem is that using a symbol from a parent scope creates some kind of "dummy" version of that symbol that might block the ZP property from propagating to any nested scopes?
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: CA65: zp -> abs when using nested .procs
Since creating an equate and assigning a .globalzp'd symbol seems to propagate "this is zp" as far down in scopes as one would like, does anyone think it might be worthwhile to propose adding something like this to ca65?
since going:
seems to allow my_b0 to generate zp instructions as deep as one likes?
Code: Select all
.globaldefzp b0 ;when used as an import, will import the symbol AND re-define it at the global scope of the current module
Code: Select all
.globalzp b0
my_b0 = b0 ;at global scope
Re: CA65: zp -> abs when using nested .procs
It doesn't work like that. As soon as you reference my_b0 in one of the scopes, the further nested scopes will find the reference (not the global-level my_b0), and not use the correct size.GradualGames wrote:seems to allow my_b0 to generate zp instructions as deep as one likes?Code: Select all
.globalzp b0 my_b0 = b0 ;at global scope
Code: Select all
.globalzp b0
my_b0 = b0 ;at global scope
.scope s1
start1:
lda my_b0 ; size=2
end1:
.scope s2
start2:
lda my_b0 ; size=3
end2:
.endscope
.endscope
.out .sprintf("size=%d", s1::end1 - s1::start1)
.out .sprintf("size=%d", s1::s2::end2 - s1::s2::start2)
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: CA65: zp -> abs when using nested .procs
So...if I only use these equates ONCE anywhere in my nested scopes, it's working by coincidence for me? I think that may be what's really going on, given what you're saying.
It appears one can work around this with the :: operator and redefine the symbol with the same name. Perhaps we could propose adding a directive that modifies all nested scopes' symbol tables to behave as though one did this manually. or a .feature or something.
It appears one can work around this with the :: operator and redefine the symbol with the same name. Perhaps we could propose adding a directive that modifies all nested scopes' symbol tables to behave as though one did this manually. or a .feature or something.
Code: Select all
.globalzp b0
my_b0 = b0 ;at global scope
.scope s1
start1:
lda my_b0 ; size=2
end1:
.scope s2
my_b0 = ::my_b0
start2:
lda my_b0 ; size=2 because we used :: to redefine the symbol for this scope
end2:
.endscope
.endscope
.out .sprintf("size=%d", s1::end1 - s1::start1)
.out .sprintf("size=%d", s1::s2::end2 - s1::s2::start2)
****OUTPUT****
$ ca65 scope_test.asm -llisting.lst
size=2
size=2
- rainwarrior
- Posts: 8732
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: CA65: zp -> abs when using nested .procs
I think it's just flat out a bug that should be fixed, not a new feature that should be added.GradualGames wrote:Perhaps we could propose adding a directive that modifies all nested scopes' symbol tables to behave as though one did this manually. or a .feature or something.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: CA65: zp -> abs when using nested .procs
It is really weird isn't it. Like, how many times is somebody going to import a global variable from zp and then want to use the exact same name afresh in some inner scope AND generate a non zp instruction from it? I'm guessing pretty much never. I can't think of anything except bad naming habits that would get one into that situation normally.rainwarrior wrote:I think it's just flat out a bug that should be fixed, not a new feature that should be added.GradualGames wrote:Perhaps we could propose adding a directive that modifies all nested scopes' symbol tables to behave as though one did this manually. or a .feature or something.