スプライトをレンダリングするC64アセンブリ


8

私は、Ca65アセンブラld65リンカを使用して、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

これは私のリンカースクリプトで、c64での手書きのアセンブラ用にca65が推奨するリンカースクリプトから改作されたものです。私が行った唯一の変更は、「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;
}

これは、コンパイルとリンクに使用しているコマンドです。

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

これはコンパイル後のマップファイルの内容です:

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)

そして、最終的なバイナリファイルの16進ダンプ:

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のバンクを切り替えていないため、画面はデフォルトのアドレス範囲($0400-$07FF)のままです。この範囲の最後の8バイトは私のスプライトポインターです。スプライト$07f8が1つしかないため、スプライトポインター0()のみを使用しています。

プログラムを実行すると、すべてがハングアップします。これは、プログラムが無限ループで終了するためです。しかし、スプライトは画面のどこにも表示されません。

VICEで実行中のプログラム

何が欠けていますか?


1
ああ、思い出。もちろん、私たちはクレイジーなリンカーのものをいじらなかったその日に戻ります:)とにかく、私に見てみましょう。手始めに、X / Yレジスタが間違っている。$ d000と$ d001である必要があります。
道化師

@道化師、見てくれてありがとう!ええ、リンカがコツをつかむのにしばらく時間がかかりました。多くのアドバイスは、オンラインで.orgディレクティブを使用したり、PCを直接設定して、保存場所を制御したりしました。ca65ただし、バイナリのどこに配置するかを制御する適切な方法はリンカースクリプトを使用することであると主張して、これは推奨されません。そして、私は(私はそう思いますか?)リンカーセットアップを正しく取得したので、それらのポイントを確認します-すべてを整理する方がはるかに簡単です。
Woodrow Barlow、

@Jester私はそのリンカースクリプトの99%がca65から直接来たことを追加する必要があります-私が追加したのは「GFXDATA」セグメントだけでした。
Woodrow Barlow

2
@ジェスターああ、まあ、私はそれらのレジスタをトリプルチェックしたと確信していた。正しいXレジスタとYレジスタを使用するようにコードを更新したところ...それは完全に機能します。私はこれに2つの午後を費やしたとは信じられず、それに気づきませんでした。
Woodrow Barlow

1
ご存じないかもしれませんが、Retrocomputing.SEがあり、人々はこれを気に入っています。
tum_

回答:


5

@Jesterがコメントで指摘したように、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

そして、これが実際の写真です:


「コミュニティウィキ」機能を乱用しないでください。この答えは1つのビジネスではありません。
パイプ

1
@pipeどうして?道化師はコメントの質問に答えました。私は彼にそれを回答として投稿するように誘った。彼はしませんでした。投稿したのですが、答えを見つけたのが自分ではなかったので、自分の名前をつけるのは適切ではないようでした。
Woodrow Barlow

1
このスレッドは、コミュニティwikiを使用する適切なタイミングは、「あなたの回答が、コメントで他の人がすでに回答しているものから単にまとめられている場合」であると述べています。
Woodrow Barlow

1
このスレッドは、より多くの賛成投票があり、コミュニティウィキに回答したい場合はいつでも大丈夫です。
Woodrow Barlow

2

を含める場合、VIC_SPR0_XおよびVIC_SPR0_Yを使用できますc64.inc。これはあなたの人生をはるかに簡単にすることができます。


良いヒント、ありがとう!将来はやります。必要に応じて、コミュニティのWiki回答にこれを追加できます。
Woodrow Barlow
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.