Dec13th

CC65(CA65) の変更点

Top / CC65(CA65)

  • 追加された行はこの色です。
  • 削除された行はこの色です。
  • CC65(CA65) へ行く。

*CC65(CA65) is [#h4e2e31b]
-各種ファミコンエミュレータで動作する.nesファイルを生成するassembler
-パッケージがCC65なのでこのタイトルですが、中身はCA65(アセンブラ)なのであしからず

*環境整備 [#ic5d41d2]
-CC65
--available for downloadからwindows版をダウンロード
http://www.cc65.org/oldindex.php#Download

-NES研究室さんのサンプル
--サンプル1をダウンロード
http://hp.vector.co.jp/authors/VA042397/nes/sample.html

-Virtual NES
--作成した.nesファイルのエミュレート用

-makeコマンド
--make for Windowsをインストール
Completeパッケージをダウンロード
http://gnuwin32.sourceforge.net/packages/make.htm
--.batでも代替可能 手打ちは面倒
~

*ビルド [#ge41a965]
-NES研究室さんのサンプル内のmakefileを利用してmake
--makeコマンドはcygwinを入れるかmake on Windowsを入れる
--メモリマップを記述したmain.cfgも必要

-以下のファイルを同じディレクトリに入れて,cmd.exeからmakeを実行
--CC65一式
--各種割り込みを記述した,mainとなる.asmファイル
--makefile
--main.cfg
~

*文法 [#jb601fa9]
-コントロールコマンド
ドットから始まる命令
C言語でのプリプロセッサに当たる処理を行う

-ラベル
文字列とコロンからなる
ジャンプ命令の行き先やメモリに配置したデータへのアクセスに使用

-16進数値
$を付ける
例: $00、$81

-即値
#を付ける
例: #$00、 #$29

-マクロ定数
コードの任意の位置で定数名=数値で定義できる
#highlight(cpp){{
MYCONST = 10
MYCONST2 = $20
}}

~

*コントロールコマンド [#h2cb4431]
-.segment
セグメントを切り替える。
データやニーモニックを配置するには、.cfgファイルでセグメントにメモリ割り当てをしておく必要がある。
#highlight(cpp){{
.segment "HEADER"
    ...
    ...

.segment "INIT"
    ...
    ...
}}

-.byte
バイトサイズのデータ(8bit)を配置する。
.cfgファイルでセグメントにメモリを割り当てる必要がある。
#highlight(cpp){{
.segment "DATA"
    .byte    $06    ;0x06
    .byte    $4E, $45, $53, $1A    ;NES Header
}}

-.word
ワードサイズのデータ(16bit)を配置する。
ラベルを指定した場合,そのラベルのアドレスが配置される。
#highlight(cpp){{
.segment "DATA"
    .word    $0000    ;0x0000
    .word    $3E64    ;0x3E64
}}

-.proc、.endproc
サブルーチンを定義する。
#highlight(cpp){{
.proc Reset
    ....
.endproc
}}

-.res
メモリ領域を予約する
変数領域として使用
#highlight(cpp){{
    .res    8          ;8バイト分確保
    .res    16, $A8    ;$F6で埋めた16バイト分の領域を確保
}}

-.include
他ファイルのソースコードを埋め込む

~

*サウンド再生 [#d3f2cde9]
-440Hz(ラ)の矩形波音を一瞬だけ再生
--レジスタにセットする値x = 1790000 / (f * 32) - 1 = 126 = $007e
--$4002にセットする値の下位8bit,$4003に上位8bitをセット
#highlight(cpp){{
;初期化ブロック 割り込み後など
.segment "STARTUP"
.proc    Reset
    ;サウンド有効化
    lda    #$1F
    sta    $4015

;ゲームループ
.proc    mainLoop
;再生
    lda    #$7e
    sta    $4002
    lda    #$00
    sta    $4003
}}

*cfgファイル [#f3e26ca0]
-メモリマップとセグメントを記述
--ld65呼び出し時に--configオプションで指定

-メモリマップ
--基本
---MEMORYと中括弧で記述
---各項目はメモリマップ名とコロンで記述
#highlight(cpp){{
MEMORY {
    HEADER:    start = $0000, size = $0010, file  = %0, fill = yes;
    ;etc
}
}}

--start
メモリの開始位置を指定
#highlight(cpp){{
{
    ZP:     start = $0000, ....;
    RAM:    start = $0100, ....;
}
}}

-セグメント
--基本
#highlight(cpp){{
SEGMENTS{
    ;中身
}
}}
~

*用語 [#jebc0c93]
-ネームテーブル
画面上のどのブロックにどのキャラクタを配置するのかを指定するテーブル。

*メモ [#e73c7d8d]
-a: というラベルは使えない。おそらくaレジスタと競合していると思われる

-BGM等の巨大なデータはラベルで細かく分けてアクセスする
-:+ ,:-
Unnamed Label、無名ラベル
+・-の数だけ前・後ろの無名ラベル:に飛ぶ
#highlight(cpp){{
    jmp    :+
    lda    #$00    ;スキップ
:   lda    #$01    ;ここから

    jmp    :+++    ;増やせる
:   lda    #$00    ;スキップ
:   lda    #$01    ;スキップ
:   lda    #$02    ;ここから    

}}
#highlight(cpp){{
:   lda    #$00    ;永久ループ
    jmp    :-
    lda    #$01    ;呼ばれない
}}

-@ラベル
普通のラベル内だけで有効なラベル
ループ等に用いられる
Cheap Labelと呼ばれる

-jmpで飛んだ先からrtsで帰ってこれる
.proc~.endprocとの違いは不明
jmpは一方通行もできるから、.procは戻ってくることを明確にしてるのかもしれない

-.ifdef、.else、.endifを使えばプリプロセスで分岐制御できる

-?jsrでラベル以外の番地に飛ぶ方法
8bitレジスタで16bitアドレスを計算する方法が分からんちん

-プログラムのエントリーポイントはリセット割り込みの指定先アドレスになる。

-$0000番地から4+12byte分の領域は、NES用ヘッダのデータが指定される。
先頭4byteには固有の値が、残りの12byteにはバンクの数やミラーリング方式が指定される。
#highlight(cpp){{
.segment "HEADER"    ;$0000に配置
    .byte    $4E, $45, $53, $1A    ;NES Header
    .byte    $02                            ;プログラムバンク数
    .byte    $01                            ;キャラクターバンク数
    .byte    $01                            ;ミラーリング方式(垂直ミラーリング)
    .byte    $00                            ;不明
    .byte    $00, $00, $00, $00    ;不明
    .byte    $00, $00, $00, $00    ;不明
}}

-$FFFA番地からword3つ分の領域は、各種割り込みの分岐先が指定される。
上から順に、VBlank割り込み、リセット割り込み、ハードウェア割り込み。
#highlight(cpp){{
.segment "STARTUP"
.proc Reset
.endproc

.segment "INTERRUPT"    ;$FFFAに配置
    .word    $0000    ;VBlank
    .word    Reset     ;リセット
    .word    $0000    ;ハードウェア
}}

-メモリサイズは8bit以上16bit以下なので、16bitの値で指定する。
レジスタにメモリアドレスを格納する場合2つ使用する必要がある。

-ROMとRAMの違いを押さえておく

-VirtualNESだと.incbinにオフセット値を与える命令が使えない
#highlight(cpp){{
    .incbin "data.dat", $100
}}
これが含まれると「未定義の命令が実行されました」のダイアログが出て止まる
~

*リンク [#xf983ebc]
-NES研究室
http://hp.vector.co.jp/authors/VA042397/nes/index.html
ニーモニックやアーキテクチャ、サンプルなどなど
サンプル必見

-CA65 Users Guide
http://www.cc65.org/doc/ca65.html

-Control Commands
http://www.cc65.org/doc/ca65-11.html
.byte等のCA65用プリプロセスコマンド集。

-System Memory Map Definition
http://www.cc65.org/doc/customizing-2.html
.cfgの書き方。

-Memory-Map of NES
http://www34.atwiki.jp/cc65/pub/dsoft/mmap.html

#highlight(end)