It is currently Tue Nov 21, 2017 10:43 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 89 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next
Author Message
PostPosted: Tue Nov 03, 2015 7:56 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
tokumaru wrote:
Any way to achieve similar behavior in ca65, without having to create hundreds of overlapping segments, one for each subroutine?

In ca65 .enum has a different meaning, but .struct should be more or less equivalent. I would shy away from any solution that requires the linker configuration to be modified whenever a subroutine is added or removed.

tepples wrote:
Is there a counterpart to GREATEST() or MAX() function in ld65 config language?

The expressions allowed in the linker scripts seem to be more limited than in the assembler. Apparently only addition, subtraction, multiplication and division (and parentheses) are allowed (I didn't check the source, though).

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 8:29 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
tepples wrote:
I wonder whether scratchpad variables in $0000-$001F could be defined with a .struct.

Yeah, I was thinking of something along those lines.

Quote:
[tokumaru]not automatic[/tokumaru]

I don't know if this is a criticism (don't worry, I won't be offended if it is), but I fail to see how wanting things to be automatic could be a bad thing. This is not about laziness (even though saving time is always a good thing!), but about making things more flexible and error-free. Flexibility means you can more easily reuse code across different projects without worrying about adjusting lots of tiny little details in your templates. At the same time, not having to type redundant pieces of information, that can be deduced from things you actually do have to type, completely eliminates the chances of you screwing up and creating inconsistencies. Sure, it may be more complicated to setup at first, but in the long run you have less things to worry about.

thefox wrote:
I would shy away from any solution that requires the linker configuration to be modified whenever a subroutine is added or removed.

Precisely! I will look .struct up.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 9:07 am 
Offline
User avatar

Joined: Sun Nov 09, 2008 9:18 pm
Posts: 987
Location: Pennsylvania, USA
From my experience making two full size games with CA65, I find the most that I had to fiddle with linker configuration and rom layout came pretty early in the Nomolos project when I had little feeling for relative sizes of different types of code and data. So I basically lined everything up as I added them to the project. This resulted in having to juggle my rom layout fairly frequently, editing many files for .segment "ROMXX" and constants/luts for specifying which bank various objects reside in. After that first project I developed better habits for organizing data, dedicating certain roms exclusively to bg graphics, spr graphics, animations, music, engine extensions, and lookup tables. In short, once you get used to it I don't think that you'll feel it gets in your way. I can't say for sure how it would really differ from ASM6 for a large project, having never created a large project with ASM6. One thing that's nice about CA65 is it is pretty easy to stuff things in a few different banks all in one file just with the .segment directive. The linker config basically abstracts away all the .org, .pad that you would normally have to do in an ASM6 program. My feeling is it must be a big time saver.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 10:26 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5824
Location: Canada
I don't think I'd bother trying to make the linker sort out unions on such a small scale. You can always just create alias labels. Maybe it's not as convenient as .res but for individual functions you probably don't have a lot of allocations to make. Doing it manually shouldn't be too onerous:
Code:
; alllocate scratchpad
.segment "ZP": zeropage
scratchpad: .res 32

...

; alias new allocations from scratchpad for each function as needed

.proc myfunc
param_a = scratchpad + 0
param_b = scratchpad + 1
temp_c  = scartchpad + 2
    ; code goes here
    rts
.endproc

; bonus: using .proc puts these aliases in their own scope, so they don't pollute the global space, and you can also access them from outside the function:

    stx myfunc::param_a
    sty myfunc::param_b
    jsr myfunc


Edit: ZP segment must be identified as zeropage.


Last edited by rainwarrior on Tue Nov 03, 2015 11:18 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 10:35 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
Yeah, that's the first solution that came to mind, and I do consider using it if I can't find a better one. Most subroutines use so few variables that this shouldn't be particularly annoying to manage.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 10:38 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19238
Location: NE Indiana, USA (NTSC)
I think the idea of the whole "union" thing is that the entire game needs certain variables, while other variables apply only to certain game phases, such as title screen, cut scenes, level intro and outro screens, and in-game. In RHDE, I had to use a ton of alias labels for memory maps that apply only to one of help screens, furnish phase, battle phase, and build phase.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 11:02 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
Another question: what are the rules for naming the MEMORY and SEGMENT entries in the config file? All examples I could find don't repeat names in those two sections, not even for the header, which is just 1 simple entry in each section. I don't want to use abbreviations (e.g. HDR) or make arbitrary modifications to the names before understanding what the best practices are.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 11:17 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5824
Location: Canada
Ah, that's a good question actually. My above example has an error in it. If you have a segment called "ZEROPAGE" it will be automatically assumed by the assembler to be a zeropage segment.

Otherwise you have to manually do it:
Code:
.segment "ZP": zeropage


If you forget, you get absolute addressing for everything. (Hopefully you'd catch this when getting an assembly error when trying to use a pointer, etc.)

Other than that, there's no special names for segments or memory blocks unless you want to use cc65 (it expects a bunch of specifically named segments by default, but they can all be changed). MEMORY regions can share the same names as SEGMENTS (i.e. they're different namespaces), but I always keep them unique, myself, for no particular reason.

See: ca65 docs: .segment

If you use .segment once with zeropage, it should generate an error if you ever forget to use zeropage anywhere else (this is checked globally by the linker), so there is a good amount of safety checks against doing it wrong. As long as you remember at least once, you're safe.

I tend to put all my allocations together in one file, so I forget about these rules; I don't have to think about them often. :P Usually I just name the zeropage segment "ZEROPAGE" so I don't have to remember this rule.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 2:15 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
rainwarrior wrote:
Otherwise you have to manually do it:
Code:
.segment "ZP": zeropage

Wait, what's the point of having type = zp in the segment definitions then?

Quote:
Usually I just name the zeropage segment "ZEROPAGE" so I don't have to remember this rule.

I can't do that because ZP, like the rest of RAM, is divided into permanent and temporary sections, so I'll have several references to it. Do I need write : zeropage every time I switch to one of these segments? This isn't so bad, I just want to be sure it's necessary.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 3:25 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5824
Location: Canada
tokumaru wrote:
Wait, what's the point of having type = zp in the segment definitions then?

Not really certain, but the types are ro/rw/bss/zp. Both bss and zp seem to have the same function (i.e. they enforce no initialized data in the segment). I wish it also made the linker enforce the missing "zeropage" on .segment but it does not appear to. Actually, I think I'll suggest this to the list...

tokumaru wrote:
Do I need write : zeropage every time I switch to one of these segments? This isn't so bad, I just want to be sure it's necessary.

Yes, but as long as you remember to do it once, assembler/linker errors will enforce that you do it everywhere else that's needed.


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 3:47 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19238
Location: NE Indiana, USA (NTSC)
That's not how I understand the docs. You only have to declare a segment as : zeropage the first time. The docs give this example:
Code:
.segment "ROM2"                 ; Switch to ROM2 segment
.segment "ZP2": zeropage        ; New direct segment
.segment "ZP2"                  ; Ok, will use last attribute
.segment "ZP2": absolute        ; zp2.s(4): Error: Segment attribute mismatch

So you might define each zeropage segment by switching to it once in a global file that all your .s files .include:
Code:
.pushseg
.segment "ZP1": zeropage
.segment "ZP2": zeropage
.segment "ZP3": zeropage
.popseg


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 4:26 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5824
Location: Canada
Ah, I didn't realize subsequent uses of .segment with no qualifier will assume the previous state. I was just going by some quick tests I threw together, i.e.
Code:
; this creates an error:

.segment "ZP" ; no specification: assumes absolute
.segment "ZP": zeropage ; error

; VS this apparently does not:

.segment "ZP": zeropage
.segment "ZP" ; OK: assumes previous usage


Top
 Profile  
 
PostPosted: Tue Nov 03, 2015 9:45 pm 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
thefox wrote:
tepples wrote:
Is there a counterpart to GREATEST() or MAX() function in ld65 config language?

The expressions allowed in the linker scripts seem to be more limited than in the assembler. Apparently only addition, subtraction, multiplication and division (and parentheses) are allowed (I didn't check the source, though).

Possible solution for this one (this is getting a little bit hacky) is to export a symbol containing the necessary information from assembly code, and then import that in the linker config:
Code:
.import __FOO_LAST__
; bogus expression, but full expression evaluation capabilities of the assembler available
; (can be used to implement stuff like MIN/MAX/...)
.export whatever = (__FOO_LAST__ < $8100)*$1234

Code:
# linker.cfg
SYMBOLS { whatever: type=import; }

I tested this, and it seemed to work as expected, i.e. if the imported symbol was used before the "FOO" memory area had appeared in the config, it caused an error. And if it was used after (when the value of __FOO_LAST__ is known), it worked.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
PostPosted: Wed Nov 04, 2015 3:30 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10117
Location: Rio de Janeiro - Brazil
I have one more question: How do I go about making sure that timing-sensitive code doesn't cross page boundaries? So far I've used a macro to detect page crossing and generate an error in case it does happen, and then I'd manually shuffle subroutines around to prevent the situation. What is the recommended approach in ca65?


Top
 Profile  
 
PostPosted: Wed Nov 04, 2015 3:51 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19238
Location: NE Indiana, USA (NTSC)
tokumaru wrote:
How do I go about making sure that timing-sensitive code doesn't cross page boundaries?

.align 256 is one option. Another is
Code:
.assert >function_end = >function, error, "I wanted Animal Crossing, not Page Crossing"


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 89 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group