C64 程序集渲染精灵

Woo*_*low 8 assembly c64 6502 commodore ca65

我使用ca65 汇编器ld65 链接器在 6502 汇编器中为 Commodore 64 编写了一个短程序。该程序应该在靠近显示器中心的某处呈现一个实心方形精灵,但我没有看到任何正在呈现的东西。

这是我的程序集:

    .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
Run Code Online (Sandbox Code Playgroud)

这是我的链接器脚本,改编自ca65 为 c64 上的手写汇编器推荐的链接器脚本。我所做的唯一更改是添加“GFXDATA”段,以便我可以将我的精灵存储在 address $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;
}
Run Code Online (Sandbox Code Playgroud)

这是我用来编译和链接的命令:

cl65 -o graphics.prg --mapfile graphics.map -u __EXEHDR__ -t c64 -C linker.cfg graphics.asm
Run Code Online (Sandbox Code Playgroud)

这是编译后的mapfile内容:

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)
Run Code Online (Sandbox Code Playgroud)

以及最终二进制文件的十六进制转储:

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
Run Code Online (Sandbox Code Playgroud)

“GFXDATA”段是我的精灵。精灵是 64 字节$FF,所以它应该看起来像一个实心方块。这个精灵数据位于地址$2000

“CODE”段从通常的 BASIC 开始位置开始,ca65 为我插入了一个 BASIC 加载器,这样我就可以run在加载程序后输入。

我没有切换 VIC 的银行,所以屏幕仍然在它的默认地址范围 ( $0400-$07FF),这个范围的最后 8 个字节是我的精灵指针。我只使用精灵指针 0 ( $07f8) 因为我只有一个精灵。

当我运行程序时,一切都锁定了——这是意料之中的,因为程序以无限循环结束。但我在屏幕上的任何地方都看不到精灵:

在 VICE 中运行的程序

我错过了什么?

Woo*_*low 5

正如@Jester 在评论中指出的那样,X 位置和 Y 位置内存地址是错误的。正确的地址是$d000$d001

; set x and y position
lda #$80
sta $d000
sta $d001
Run Code Online (Sandbox Code Playgroud)

这是更正后的代码:

    .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
Run Code Online (Sandbox Code Playgroud)

这是它的运行图片:

  • @管道为什么不呢?小丑回答了评论中的问题。我邀请他将其作为答案发布。他没有。所以我发布了它,但由于我不是找到答案的人,所以我在上面写上我的名字似乎不合适。 (2认同)
  • [这个线程,有更多的赞成票,](https://meta.stackoverflow.com/questions/369182/when-is-it-justified-to-community-wiki-your-own-answers)甚至达到如果您愿意的话,可以说在社区维基中做出回答_总是_可以的。 (2认同)