Thanks for your reply, I'll try to elaborate. >> 2. My old code makes frequent use of a certain "single_page N" macro >> which insures that the following N-byte array stays within a single >> page. Is there any way I can handle this efficiently in CA65? As far >> as I can see just aligning would waste up to 4*(N-1) bytes. > > That depends. You can use .assert statements if all you want is to get a > warning or an error from the linker if the requirements aren't met. You can > use segments to actively place these arrays. > > How does your current code avoid wasting space for alignment? No, the macro relies on knowing the current PC value to add alignment only when necessary. Without a linker it's essentially implemented like this: .mac single_page len .if >* <> >*+(len) .align 256 .endif .endmac Here's an example of a typical usage in the player state-machine: state := *+1 jmp (states) single_page 5*2 states: st_dead = <* .word do_nothing st_walk = <* .word do_walk st_jump = <* .word do_jump st_crawl = <* .word do_crawl st_climb = <* .word do_climb Granted it's not a critical operation, and for really large stuff like full-page tables I can set up a separate segment, but I've got dozens of these so a less wasteful approach than a direct .align would be nice. Of course ideally I would have liked to place the aligned block in a scope and avoid hard-coding a size, but the limitations of ACME forced this approach. To be honest I'm not quite sure how CA65's alignment pseudo-op works. Looking at the code it seems to align relative to the start of the segment within the object file and exports a minimum alignment requirement, yet the linker script still needs an alignment attribute. Is the segment alignment forced on each fragment from every object file? >> 3. Should I be using the preprocessor to implement non-trivial loops? >> I can't see how to redefine labels imperatively so I tried using macro >> recursion but ran into if-nesting limits. > > My suggestion is to avoid .define (if that is, what you call the > "preprocessor") if you can. .define works on token level, and therefore > ignores scoping. You can get all sorts of weird side effects when using it. > > Apart from that I'm not able to make any suggestions, without knowing a bit > more about what you're trying to do. I meant looping at compile-time in order to generate tables and code, e.g. what .repeat is normally used for. Here's an example of the sort of thing I mean. This macros is used to generate sector interleave tables for the drive-code by recursively ticking off bits in a bit-mask representing the track: .mac interleave limit,mask,offset .local bit,reduced,rotated bit = 1<<offset reduced = mask&~bit .if reduced = 0 .byte offset|$00 .exitmacro .elseif mask <> reduced .byte offset|$80 rotated = offset+drive_interleave .else rotated = offset+1 .endif interleave limit,reduced,(rotated .mod limit) .endmac Usually this kind of thing can be handled by writing external code/data-generator tools, but being able to handle simple cases from within the assembler is obviously convenient. Oh, and I realize that you're swamped with feature requests but better error messages for macro expansions would be really nice. I realize that you might not save the needed line-information but perhaps you could trace the tokens on the offending line or something? It's just that half of my code is defined within macros as I have a tendency to inline functions which are only called once, and getting a cryptic error message for a two-hundred line macro isn't terribly useful.. Also an alternative macro pseudo-op (say .xmac) with pre-evaluated parameters (or perhaps a per-argument operator) would be great as it's awfully easy to forget to parenthesize expressions. I suppose I should be used to this from all those years of writing C code but I still managed to get bitten in that interleave macro ;) > My usual approach is to do it in a similar way as with C sources: > > * An include files defines an interface to a module. So it contains > constantds, structures and has .global statements for the external > identifiers, but no data or code definitions. > > * The implementation module includes above file and defines the necessary > code and data. In this case the .global directives will turn into .export > statements. > > * Other modules will just reference the stuff defined in the include file, > so the .global directives will turn into .import statements. > > This has proved to work quite well, especially for bigger projects. That sounds like exactly what I am trying to do, the equivalent of C header files, except I tried to export functions within a scope. So I might for instance refer access all loader-related functions and constants through a loader:: namespace, and ended up with colliding scope definitions in the include file and the module code. Being able to define the labels outside of the scope they belong to would kind of solve this problem but I'd lose the convenience of leaving out the prefixes within module itself, so I'll probably go back to prefixing my labels with "ld_" instead. Frankly namespaces in C++ also always seemed to cause more problems than they solved. /doynax ---------------------------------------------------------------------- To unsubscribe from the list send mail to majordomo@musoftware.de with the string "unsubscribe cc65" in the body(!) of the mail.Received on Sun Oct 10 16:18:37 2010
This archive was generated by hypermail 2.1.8 : 2010-10-10 16:18:40 CEST