C64 程序集渲染精灵
C64 Assembly Rendering a Sprite
我使用 ca65 assembler and ld65 linker 在 6502 汇编器中为 Commodore 64 编写了一个短程序。该程序应该在显示器中心附近的某处呈现一个实心方形精灵,但我没有看到任何东西被呈现。
这是我的程序集:
.segment "CODE"
; set sprite pointer index
; this, multiplied by , is the address
; in this case, the address is 00
; * = 00
lda #
sta f8
; enable sprite 0
lda #
sta $d015
; set x and y position
lda #
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
这是我的 linker 脚本,改编自 ca65's recommended linker script for hand-written assembler on the c64。我所做的唯一更改是添加 "GFXDATA" 段,这样我就可以将精灵存储在地址 00
.
FEATURES {
STARTADDRESS: default = 01;
}
SYMBOLS {
__LOADADDR__: type = import;
}
MEMORY {
ZP: file = "", start = [=11=]02, size = [=11=]FE, define = yes;
LOADADDR: file = %O, start = %S - 2, size = [=11=]02;
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 = 00;
BSS: load = MAIN, type = bss, optional = yes, define = yes;
}
这是我用来编译的命令 link:
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)
以及最终二进制文件的 hexdump:
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"段是我的精灵。精灵是 $FF
的 64 字节,因此它应该看起来像一个实心正方形。此精灵数据位于地址 00
.
"CODE" 段从通常的 BASIC 起始位置开始,ca65 正在为我插入一个 BASIC 加载程序,因此我可以在加载程序后键入 run
。
我没有切换 VIC 的银行,所以屏幕仍然在它的默认地址范围 (00-FF
),这个范围的最后 8 个字节是我的精灵指针。我只使用精灵指针 0 (f8
) 因为我只有一个精灵。
当我 运行 程序时,一切都锁定了——这是预料之中的,因为程序以无限循环结束。但是我在屏幕上的任何地方都看不到精灵:
我错过了什么?
正如@Jester 在评论中指出的那样,X 位置和 Y 位置内存地址是错误的。正确的地址是 $d000
和 $d001
:
; set x and y position
lda #
sta $d000
sta $d001
这是更正后的代码:
.segment "CODE"
; set sprite pointer index
; this, multiplied by , is the address
; in this case, the address is 00
; * = 00
lda #
sta f8
; enable sprite 0
lda #
sta $d015
; set x and y position
lda #
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
这是它的实际照片:
如果包含 c64.inc
,则可以使用 VIC_SPR0_X 和 VIC_SPR0_Y。这可以让您的生活更轻松。
我使用 ca65 assembler and ld65 linker 在 6502 汇编器中为 Commodore 64 编写了一个短程序。该程序应该在显示器中心附近的某处呈现一个实心方形精灵,但我没有看到任何东西被呈现。
这是我的程序集:
.segment "CODE"
; set sprite pointer index
; this, multiplied by , is the address
; in this case, the address is 00
; * = 00
lda #
sta f8
; enable sprite 0
lda #
sta $d015
; set x and y position
lda #
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
这是我的 linker 脚本,改编自 ca65's recommended linker script for hand-written assembler on the c64。我所做的唯一更改是添加 "GFXDATA" 段,这样我就可以将精灵存储在地址 00
.
FEATURES {
STARTADDRESS: default = 01;
}
SYMBOLS {
__LOADADDR__: type = import;
}
MEMORY {
ZP: file = "", start = [=11=]02, size = [=11=]FE, define = yes;
LOADADDR: file = %O, start = %S - 2, size = [=11=]02;
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 = 00;
BSS: load = MAIN, type = bss, optional = yes, define = yes;
}
这是我用来编译的命令 link:
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)
以及最终二进制文件的 hexdump:
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"段是我的精灵。精灵是 $FF
的 64 字节,因此它应该看起来像一个实心正方形。此精灵数据位于地址 00
.
"CODE" 段从通常的 BASIC 起始位置开始,ca65 正在为我插入一个 BASIC 加载程序,因此我可以在加载程序后键入 run
。
我没有切换 VIC 的银行,所以屏幕仍然在它的默认地址范围 (00-FF
),这个范围的最后 8 个字节是我的精灵指针。我只使用精灵指针 0 (f8
) 因为我只有一个精灵。
当我 运行 程序时,一切都锁定了——这是预料之中的,因为程序以无限循环结束。但是我在屏幕上的任何地方都看不到精灵:
我错过了什么?
正如@Jester 在评论中指出的那样,X 位置和 Y 位置内存地址是错误的。正确的地址是 $d000
和 $d001
:
; set x and y position
lda #
sta $d000
sta $d001
这是更正后的代码:
.segment "CODE"
; set sprite pointer index
; this, multiplied by , is the address
; in this case, the address is 00
; * = 00
lda #
sta f8
; enable sprite 0
lda #
sta $d015
; set x and y position
lda #
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
这是它的实际照片:
如果包含 c64.inc
,则可以使用 VIC_SPR0_X 和 VIC_SPR0_Y。这可以让您的生活更轻松。