I've just started out with NES programming, and it's time for my first question.
I'm using the ca65 assembler (together with the ld65 linker) on OS X. At https://bitbucket.org/ddribin/nerdy-nights/src, there is a ca65 version of some of the Nerdy Night tutorials. I will refer to tutorial 6 in the following, but my question applies to all ca65 code. It seems to me that the following happens: Sprite data gets loaded into CPU address $0200, and then dma'd into PPU memory. Here is the question: *Why* does it end up at $0200? I can find no reference to the address in the code (I don't expect to, since that's not how ca65 rolls), or in the linker configuration (this is where I expected to find it).
I run 'make' to build example 6. The following command line is executed:
cl65 -vm -l -g -t nes -m background2.map -Ln background2.lbl -o background2.nes background2.asm
When I run it, I see the Mario sprite.
The following code from the example starts the dma copy:
Code: Select all
lda #$00 ; set the low byte (00) of the RAM address
sta $2003
lda #$02 ; set the high byte (02) of the RAM address
sta $4014 ; start the transferHowever, in the source, the sprite pixel data is declared thus:
Code: Select all
.segment "CHARS"
.incbin "mario.chr" ; includes 8KB graphics from SMB1$ ld65 --dump-config nes
MEMORY {
ZP: start = $02, size = $1A, type = rw, define = yes;
HEADER: start = $0, size = $10, file = %O ,fill = yes;
ROM0: start = $8000, size = $7ff4, file = %O ,fill = yes, define = yes;
ROMV: start = $fff6, size = $c, file = %O, fill = yes;
ROM2: start = $0000, size = $2000, file = %O, fill = yes;
SRAM: start = $0500, size = $0300, define = yes;
RAM: start = $6000, size = $2000, define = yes;
}
SEGMENTS {
HEADER: load = HEADER, type = ro;
STARTUP: load = ROM0, type = ro, define = yes;
LOWCODE: load = ROM0, type = ro, optional = yes;
INIT: load = ROM0, type = ro, define = yes, optional = yes;
CODE: load = ROM0, type = ro, define = yes;
RODATA: load = ROM0, type = ro, define = yes;
DATA: load = ROM0, run = RAM, type = rw, define = yes;
VECTORS: load = ROMV, type = rw;
CHARS: load = ROM2, type = rw;
BSS: load = RAM, type = bss, define = yes;
HEAP: load = RAM, type = bss, optional = yes;
ZEROPAGE: load = ZP, type = zp;
}
FEATURES {
CONDES: segment = INIT,
type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__;
CONDES: segment = RODATA,
type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__;
CONDES: type = interruptor,
segment = RODATA,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__;
}
SYMBOLS {
__STACKSIZE__ = $0300;
}
It seems that "CHARS" data is loaded into address "ROM2", which in turn is set to 0. So, why does it get loaded into $0200?
(I assume that does in fact end up at $0200, since the dma transfer seems to work. However, since I'm a complete newbie at this, I can't be completely sure).
Thanks in advance!