Hi,
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:
In other words, it sets the source address to $0200 and then starts the transfer.
However, in the source, the sprite pixel data is declared thus:
So, to find where data in the "CHARS" segment end up, I consult the linker configuration:
$ 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!
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:
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 transfer
sta $2003
lda #$02 ; set the high byte (02) of the RAM address
sta $4014 ; start the transfer
In other words, it sets the source address to $0200 and then starts the transfer.
However, in the source, the sprite pixel data is declared thus:
Code:
.segment "CHARS"
.incbin "mario.chr" ; includes 8KB graphics from SMB1
.incbin "mario.chr" ; includes 8KB graphics from SMB1
So, to find where data in the "CHARS" segment end up, I consult the linker configuration:
$ 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!