【问题标题】:C64 Assembly Rendering a SpriteC64 程序集渲染精灵
【发布时间】:2023-03-08 22:40:01
【问题描述】:

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

这是我的程序集:

    .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

这是我的链接器脚本,改编自ca65's recommended linker script for hand-written assembler on the c64。我所做的唯一更改是添加“GFXDATA”段,以便我可以将我的精灵存储在地址$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;
}

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

cl65 -o graphics.prg --mapfile graphics.map -u __EXEHDR__ -t c64 -C linker.cfg graphics.asm

这是编译后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)

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

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

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

“CODE”段从通常的 BASIC 开始位置开始,ca65 正在为我插入一个 BASIC 加载程序,因此我可以在加载程序后键入 run

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

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

我错过了什么?

【问题讨论】:

  • 哦,回忆。当然,在过去,我们并没有弄乱疯狂的链接器的东西 :) 无论如何,让我看看。首先,你弄错了 X/Y 寄存器。它们应该是 $d000 和 $d001。
  • @Jester 感谢您的观看!是的,链接器的东西需要一段时间才能掌握。很多在线建议使用.org 指令或直接设置PC 来控制东西的存储位置。不过,ca65 不鼓励这样做,他认为控制二进制文件中放置位置的 正确 方法是使用链接器脚本。现在我已经(我认为?)正确设置了链接器,我确实明白了他们的观点——组织一切要容易得多。
  • @Jester 我应该添加 99% 的链接器脚本 came directly from ca65——我添加的只是“GFXDATA”段。
  • @Jester 哦,天哪,我确定我已经对这些寄存器进行了三次检查。我刚刚更新了我的代码以使用正确的 X 和 Y 寄存器......它工作得很好。我不敢相信我在这上面花了两个下午,却没有注意到。
  • 以防万一您不知道 - 有 Retrocomputing.SE,人们喜欢这些东西。

标签: assembly 6502 c64 commodore ca65


【解决方案1】:

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

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

这是更正后的代码:

    .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

下面是它的图片:

【讨论】:

  • 请不要滥用“社区维基”功能。这个答案没有任何意义。
  • @pipe 为什么不呢? Jester 回答了 cmets 中的问题。我邀请他发布它作为答案。他没有。所以我发布了它,但由于我不是找到答案的人,所以我似乎不适合在上面写上我的名字。
  • this thread 说,使用社区 wiki 的正确时间是“如果您的答案只是从 cmets 中其他人已经回答的内容汇总而成”。
  • this thread, with even more upvotes, 甚至说如果您愿意,可以总是在社区 wiki 中回答。
【解决方案2】:

如果包含c64.inc,则可以使用 VIC_SPR0_X 和 VIC_SPR0_Y。这可以让您的生活更轻松。

【讨论】:

  • 好提示,谢谢!我将来会这样做。如果您愿意,欢迎您将此添加到社区 wiki 答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多