I see nothing special in CA65 syntax, but the main difficulty with it is cfg-files.
It insist on avoiding .org directive and use segment's layout configuration file.
In some cases it looks like serious limitation (fixed address tables), but there are several tricks to do it: manual segment definition or using .align directive.
As a result CA65 allows to intermix .asm modules with .c modules in linkage stage without problems. And this is main idea behind it: linkability. By default segments are movable and linkable entities and if you want fixed addresses - define them in cfg file to allow linker work correctly.
.org directive destroys etherything in this approach and should be avoided.
Example of bank-switching layout:
Code: Select all
MEMORY
{
HEADER: start = $0000, size = $0010, type = ro, file = %O, fill=yes;
ZPAGE: start = $0000, size = $0100, type = rw;
RAM: start = $0300, size = $0500, type = rw;
ROM_0: start = $8000, size = $2000, type = ro, file = %O, fill=yes, fillval = $D0;
ROM_1: start = $8000, size = $2000, type = ro, file = %O, fill=yes, fillval = $D1;
ROM_2: start = $8000, size = $2000, type = ro, file = %O, fill=yes, fillval = $D2;
ROM_3: start = $8000, size = $2000, type = ro, file = %O, fill=yes, fillval = $D3;
ROM_4: start = $A000, size = $2000, type = ro, file = %O, fill=yes, fillval = $D4;
ROM_5: start = $A000, size = $2000, type = ro, file = %O, fill=yes, fillval = $D5;
ROM_H: start = $C000, size = $4000, type = ro, file = %O, fill=yes, fillval = $CC;
}
SEGMENTS
{
HEADER: load = HEADER, type = ro;
ZPAGE: load = ZPAGE, type = zp;
RAM: load = RAM, type = bss, define = yes;
ROM_0: load = ROM_0, type = ro, align = $0100;
ROM_1: load = ROM_1, type = ro, align = $0100;
ROM_2: load = ROM_2, type = ro, align = $0100;
ROM_3: load = ROM_3, type = ro, align = $0100;
ROM_4: load = ROM_4, type = ro, align = $0100;
ROM_5: load = ROM_5, type = ro, align = $0100;
ROM_H: load = ROM_H, type = ro, align = $0100;
VECTORS: load = ROM_H, type = ro, start = $FFFA;
}
FILES
{
%O: format = bin;
}
It instruct linker to produce binary file filling it with memory fragments defined in MEMORY section (including NES header) in order of definition where file=%O property is defined. And SEGMENTS section defines names for .segment directive binding them to memory fragments. Later another tool will add CHR data to that file and .NES image will be done.
This configuration is for MMC3 64KbROM (+64Kb CHR, but it's outside of here). 8-Kb sized banked segments ROM_0-ROM_3 are binded to low page, ROM_4-ROM-5 (banked too) are binded to high page and 16Kb-sized (unbanked) are binded to end of ROM address space.
And so on.