I'm having difficultly correctly using .incbin via the linker as suggested here. I'm using the VICE c64 emulator on macOS. Manually including the binary with .res and .org works perfectly fine, but editing my config.cfg seems to merely fill the correct memory region with garbage. I'm kind of baffled why there is any difference in output whatsoever, but the method described in the wiki doesn't seem to work at all on my system. I'm still a 6502 newbie, so if this is jibberish, feel free to close it.
Here's the code which should work, but doesn't
.segment "GFX"
.incbin "Sprites.raw"
.code
sprite:
lda #$80 ;to start a sprite at a memory location $x divide by #$40. We're selecting $2000 here.
sta $07f8 ; store the sprite
lda #$01
sta $d015 ; enable sprite
lda #$80
sta $d000 ; place sprite
sta $d001
jmp end
end: rts
Here is the incorrect version, which works just fine (but which the wiki advises against)
.code
.org $1000
sprite:
lda #$80 ;to start a sprite at a memory location $x divide by #$40
sta $07f8 ; store the sprite
lda #$01
sta $d015 ; enable sprite
lda #$80
sta $d000 ; place sprite
sta $d001
jmp end
end: rts
.res $2000-*
.incbin "Sprites.raw"
my cfg file is as follows:
FEATURES {
STARTADDRESS: default = $1000;
}
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;
GFX: start = $2000, size = $0802, type = ro, file = %O, fill = yes;
}
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;
GFX: load = GFX, type = ro;
}
And my build script is more or less: cl65 -C config.cfg new.asm -o new.prg
Yes. Your config file and non-working example don't work as is.
The wiki page seems to omit an important part. The MEMORY blocks there which have file=%O are written in the order they appear to the output file. There is no inherent provision that a memory block at $2000 will be loaded to address $2000 when the file is loaded.
Modify the MAIN memory line in the config file to this
MAIN: file = %O, start = %S, size = $2000 - %S, fill=yes;
size is corrected, and fill=yes is added. Then the linker fills the memory area to its full size. Therefore the sprite data will land on the expected memory address.
In order to reduce file size and increase load time in these cases it's ofter preferable to have a small startup routine which copies the data to the correct location.
I don't know if there are additional other issues with your code, but what I see right now is:
In the "undesired" but working variant you do .res $2000-* to have enough zero's in your binary to fill the gap between the end of your code at $1000 and $2000.
But you don't do anything in the "nice" but not working variant to cause the same effect. You need the fill = yes for the memory area(s) _below_ the one you want to end up at a certain place after loading the binary. So here you need it for MAIN, and not for GFX.
However, using the start attribute for a segment (instead of a separate memory area) makes it much simpler what you want to archive in the first place. Check out
for a working example. It's a binary loaded at $803 making sure that the content of the file werner.hgr ends up at $2000 after loading.
@groessler's suggestion worked perfectly. Clearly I didn't understand how the linker places data! Thanks for the help.