Re: [cc65] Re: Porting to CC65

From: doynax <doynax1gmail.com>
Date: 2010-10-10 16:18:28
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