According to cc65 / ca65 documentation, the .org
directive does not affect the placement of the code unlike with other 6502 assemblers. The docs suggest defining a memory segment with the intended address instead.
Following the instructions there I created an extended .cfg
file based on c64-asm.cfg that defines a new memory area HIMEM
and a new segment HIMEMSEG
:
FEATURES {
STARTADDRESS: default = $0801;
}
SYMBOLS {
__LOADADDR__: type = import;
}
MEMORY {
ZP: file = "", start = $0002, size = $00FE, define = yes;
LOADADDR: file = %O, start = %S - 2, size = $0002;
MAIN: file = %O, start = %S, size = $D000 - %S;
HIMEM: file = %O, start = $c000, size = $D000 - $c000; #this line was added
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, optional = yes;
LOADADDR: load = LOADADDR, type = ro;
EXEHDR: load = MAIN, type = ro, optional = yes;
CODE: load = MAIN, type = rw;
RODATA: load = MAIN, type = ro, optional = yes;
DATA: load = MAIN, type = rw, optional = yes;
BSS: load = MAIN, type = bss, optional = yes, define = yes;
HIMEMSEG: load = HIMEM, type = ro; #this line was added
}
The new segment HIMEMSEG
was then referenced in the code:
.export prg1,prg2
prg1:
lda #$41
jsr $ffd2
jmp prg1
.segment "HIMEMSEG"
prg2:
lda #$42
jsr $ffd2
jmp prg2
I assembled for target C64 with the command cl65 -t c64 -C c64x-asm.cfg prg.s -Ln labels.txt -o prg.prg
and would have expected to get a large program with code parts at $0801
and $c000
.
Interestingly, the result is a file that places all code closely together:
.C:0801 A9 41 LDA #$41
.C:0803 20 D2 FF JSR $FFD2
.C:0806 4C 01 08 JMP $0801
.C:0809 A9 42 LDA #$42
.C:080b 20 D2 FF JSR $FFD2
.C:080e 4C 00 C0 JMP $C000
Note the reference to $C000
t address 080f
, also the exported labels in labels.txt
indicate the code was meant to be placed in the defined HIMEMSEG
($C000
). However, the linker just added those parts one after the other, producing an executable with the second part of the code being at the wrong address.
I have already searched existing forums for solutions, without success. I'm grateful for any suggestions on how to effectively putting code into two different memory areas with cc65. I want to be able to refer to the other code parts via .export
/ .import
so building and loading the parts seperately is not an option.
.ORG
statement actually does work like it does in many other assemblers. You often still want a .CFG file though. If you want to see how cc65 compares to other cross-assemblers, see this test data, particularly2008-address-changes_*
. Note the segment directives are commented out. (If you've used 64tass,.org
works more like.logical
than* =
.) In any event, code should be relocated by the app loader or (if your OS doesn't do that) by the app's init code..incbin
commands to include various sprite data - these should be placed well aligned at a predefined memory area where the VIC can address them. The main program should know the start address of the sprites to be able to run an animation. So we need forced placement by the linker and the exported addresses from the second part.tass
assembler, I would have just written *=$2000 spritelbl1 .binary "sprites1.prg",2 spritelbl2 .binary "sprites2.prg",2 and the assembler would have placed the sprites to $2000 and following while the labels spritelbl1 and spritelbl2 can be used in the main program to refer to the address where the sprite sequences are placed.#addr/64
). For 64tass you would write.align 64
and let the assembler worry about picking an address. Because ca65 is designed to create relocatable object modules for compiler output it's a bit more awkward -- the.align
directive depends on the alignment of the full segment (see docs).