Montagem C64 renderizando um sprite

8

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 rundepois 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:

Programa em execução no VICE

o que estou perdendo?

Woodrow Barlow
fonte
1
Oh, as memórias. É claro que antigamente não mexíamos com coisas malucas de linkers :) De qualquer forma, deixe-me dar uma olhada. Para iniciantes, você errou os registros X / Y. Eles devem ser $ d000 e $ d001.
Jester
@ Jester obrigado por dar uma olhada! Sim, o material do vinculador demorou um pouco para entender. muitos conselhos online usaram .orgdiretivas ou configuram o PC diretamente para controlar onde as coisas são armazenadas. ca65desencoraja 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.
Woodrow Barlow
@ Jester, devo acrescentar que 99% desse script vinculador veio diretamente do ca65 - tudo o que adicionei foi o segmento "GFXDATA".
Woodrow Barlow
2
@ Jester oh meu Deus, eu tinha certeza que tinha verificado três vezes esses registros. Acabei de atualizar meu código para usar os registros X e Y corretos ... e funciona perfeitamente. Não acredito que passei duas tardes nisso e não percebi isso.
Woodrow Barlow
1
Apenas no caso de você não estar ciente - existe o Retrocomputing.SE , onde as pessoas adoram essas coisas.
tum_ 14/02

Respostas:

5

Como o @Jester apontou nos comentários, os endereços de memória das posições X e Y estão incorretos. Os endereços corretos são $d000e $d001:

; set x and y position
lda #$80
sta $d000
sta $d001

Este é o código corrigido:

    .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 $d000
    sta $d001

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

E aqui está uma foto em ação:

Woodrow Barlow
fonte
Por favor, não abuse do recurso "wiki da comunidade". Esta resposta não tem nada a ver.
pipe
1
@ pipe por que não? O bobo da corte respondeu às perguntas nos comentários. eu o convidei a postar como resposta. ele não fez. então publiquei, mas como não encontrei a resposta, não me pareceu apropriado colocar meu nome nela.
Woodrow Barlow
1
este tópico diz que o momento certo para usar um wiki da comunidade é "se a sua resposta for meramente compilada do que já foi respondido por outras pessoas nos comentários".
Woodrow Barlow
1
esse tópico, com ainda mais votos positivos, chega ao ponto de dizer que sempre é bom fazer uma resposta em um wiki da comunidade, se você quiser.
Woodrow Barlow
2

Você pode usar VIC_SPR0_X e VIC_SPR0_Y se incluir c64.inc. Isso pode facilitar sua vida.

Polluks
fonte
boa dica, obrigado! Eu farei isso no futuro. você pode adicioná-lo à resposta do wiki da comunidade, se desejar.
Woodrow Barlow