Eu escrevi um programa curto no 6502 assembler para o Commodore 64 usando o ca65 assembler e o ld65 linker . O programa deve renderizar um sprite quadrado sólido em algum lugar próximo ao centro da tela, mas não vejo nada sendo renderizado.
Esta é a minha assembléia:
.segment "CODE"
; set sprite pointer index
; this, multiplied by $40, is the address
; in this case, the address is $2000
; $80 * $40 = $2000
lda #$80
sta $07f8
; enable sprite 0
lda #$01
sta $d015
; set x and y position
lda #$80
sta $d001
sta $d002
loop:
jmp loop
.segment "GFXDATA"
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
Este é o meu script vinculador, adaptado do script vinculador recomendado do ca65 para assembler escrito à mão no c64 . A única alteração que fiz foi adicionar o segmento "GFXDATA", para que eu pudesse armazenar meus sprites no endereço $2000
.
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;
}
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;
GFXDATA: load = MAIN, type = ro, optional = yes, start = $2000;
BSS: load = MAIN, type = bss, optional = yes, define = yes;
}
Este é o comando que estou usando para compilar e vincular:
cl65 -o graphics.prg --mapfile graphics.map -u __EXEHDR__ -t c64 -C linker.cfg graphics.asm
Este é o conteúdo do arquivo de mapa após a compilação:
Modules list:
-------------
graphics.o:
CODE Offs=000000 Size=000015 Align=00001 Fill=0000
GFXDATA Offs=000000 Size=000040 Align=00001 Fill=0000
/usr/share/cc65/lib/c64.lib(exehdr.o):
EXEHDR Offs=000000 Size=00000C Align=00001 Fill=0000
/usr/share/cc65/lib/c64.lib(loadaddr.o):
LOADADDR Offs=000000 Size=000002 Align=00001 Fill=0000
Segment list:
-------------
Name Start End Size Align
----------------------------------------------------
LOADADDR 0007FF 000800 000002 00001
EXEHDR 000801 00080C 00000C 00001
CODE 00080D 000821 000015 00001
GFXDATA 002000 00203F 000040 00001
Exports list by name:
---------------------
__EXEHDR__ 000001 REA __LOADADDR__ 000001 REA
Exports list by value:
----------------------
__EXEHDR__ 000001 REA __LOADADDR__ 000001 REA
Imports list:
-------------
__EXEHDR__ (exehdr.o):
[linker generated]
__LOADADDR__ (loadaddr.o):
[linker generated] linker.cfg(5)
E um hexdump do arquivo binário final:
0000000 0801 080b 0320 329e 3630 0031 0000 80a9
0000010 f88d a907 8d01 d015 80a9 018d 8dd0 d002
0000020 1f4c 0008 0000 0000 0000 0000 0000 0000
0000030 0000 0000 0000 0000 0000 0000 0000 0000
*
0001800 ff00 ffff ffff ffff ffff ffff ffff ffff
0001810 ffff ffff ffff ffff ffff ffff ffff ffff
*
0001840 00ff
0001841
O segmento "GFXDATA" é o meu sprite. O sprite tem 64 bytes de $FF
, portanto deve parecer um quadrado sólido. Estes dados sprite está localizado no endereço $2000
.
O segmento "CODE" é iniciado no local de início do BASIC habitual e o ca65 está inserindo um carregador BASIC para mim, para que eu possa digitar run
depois de carregar o programa.
Como não mudei o banco da VIC, a tela ainda está em seu intervalo de endereços padrão ( $0400-$07FF
), com os últimos 8 bytes desse intervalo sendo meus indicadores de sprite. Eu só estou usando o ponteiro do sprite 0 ( $07f8
) porque só tenho um sprite.
Quando executo o programa, tudo trava - o que é esperado, porque o programa termina em um loop infinito. Mas não vejo o sprite em nenhum lugar da tela:
o que estou perdendo?
.org
diretivas ou configuram o PC diretamente para controlar onde as coisas são armazenadas. ca65
desencoraja isso, porém, argumentando que a maneira correta de controlar onde as coisas são colocadas no binário é usar scripts de vinculador. e agora que eu tenho (acho?) a configuração do vinculador corretamente, entendo o ponto deles - é muito mais fácil organizar tudo.