引っ掛かったところ


ゆるゆるファミコン・NESの開発を進めていますが、ここまで良く分からなくて躓いたところをまとめておきます。
※初心者なので、まぁ、簡単なところで引っ掛かってます。

■ エミュレーター関係
SRAM を使うときは、iNES ヘッダのROMコントロールを書き換えること。
NES研究所様のサンプル だとこんな感じになっているので、

; iNESヘッダ
.segment "HEADER"
  .byte $4E, $45, $53, $1A  ; "NES" Header
  .byte $02           ; PRG-BANKS
  .byte $01           ; CHR-BANKS
  .byte $01           ; Vetrical Mirror
  .byte $00           ;
  .byte $00, $00, $00, $00  ;
  .byte $00, $00, $00, $00  ;


こう変える。

; iNESヘッダ
.segment "HEADER"
  .byte $4E, $45, $53, $1A  ; "NES" Header
  .byte $02           ; PRG-BANKS
  .byte $01           ; CHR-BANKS
  .byte $03           ; Vetrical Mirror   ← b1 を立てる
  .byte $00           ;
  .byte $00, $00, $00, $00  ;
  .byte $00, $00, $00, $00  ;


内容については、こちら が詳しかったです。
この設定が分からなかったおかげで、nestopia では動かず、悩むこと数日・・・。


■ 初期化
電源投入時(リセット時)には CPU と VDP が同時に起動するとは限らないため、$2002 の b7 をリセット(0)したした後に、$2002 の b7 に「1」がセットされるの2回待たなければいけない。


■ コントローラー
デルタ・モジュレーション音源(DMC)を使う場合、読み込んだコントローラーの値が2回連続して同じ値になるまで読み込み続けるべし。
※DMC を使うとコントローラーの値にエラーが出ることがあるそうで、同値を2回連続で読みこめば正しい値として使ってよしみたいなことらしい。

コントローラーIIの読み込み、

  lda #1
  sta $4016
  lda #0
  sta $4016
  lda $4017


うっかり、$4017 に1 & 0 をセットしたら、ナゼか三角波のコントロールが利かなくなってしまった。
ちゃんとポートには正しい値を書き込んでいたが、鳴りっぱなしになるか、音が出ないかのどちらか。
これが判明するまで1日潰す。


■ VRAM
VRAM に書き込んだあとは、スクロール値をリセットすること。
スクロールは使わない場合は、こんな感じで処理。

  lda #0
  sta $2005
  sta $2005


VRAM は Vblank 中に転送するので、転送量に限度がある。これを超えると画面レイアウトが崩れる。
大体、 32バイト程度が限度。

グラフィック処理は、Vblankのできるだけ最初のほうで行わなわなくていけない。
処理落ちすると、VRAMの書き換えが間に合わなくなり、予期せぬ箇所を書き換えちゃったりする。


■ スプライト
ネット検索してみると、VRAM 転送と同じように $2003 にアドレス、$2004 にデータを書き込むような記述も見受けられますが、どうやらそんな必要はなく、NMI の先頭に近い箇所(511.9マシンサイクル以内)に $4014 で指定するスプライトのセグメント($2 なら、$200~$2ff)の領域に直接書き込めばOKみたいです。
$200~$2ffに直接、スプライトの情報を書き込んだあと、$4014 に書き込むと DMA 転送されるようです。
※$2003 には $00 以外は書き込んではいけないみたいなので、全キャラ書き換えるとき以外は使いづらいですしね。


■ サウンド
矩形波2チャンネルと三角波1チャンネルの計3チャンネルは、$4003、$4007、$400b に周波数データの上位バイトを書き込むと再生のトリガーが掛かります。
しかし、毎回書き込むとノイズが発生するため、上位バイトに変化があったときだけ書き込むようにする。

三角波を無音にしたい場合は、$4008 の長さデータ b0 ~ b6 を 0 にする。連続音指定の場合は $80 にすれば無音になる。
また、三角波には音量指定がないので、連続音を再生するときは長さデータ b0 ~ b6 に適当な値をセットする。
※0以外なら再生。

三角波で空きポートになっている $4009 (矩形波ではスイープ値指定用)、書き込んでも影響なさそげ。
ので、$4008 (発音・無音)以外の周波数の処理は、矩形波と共通でも大丈夫かも。

ノイズ・チャンネルのトリガーは、長さデータの書き込みポート $400f で行いますが、連続音の場合、$00 の書き込みでOK。

DMC の再生手順としては、$4015 で DMC を一旦ディゼイブルにして、$4010、$4012、$4014 をセットしたあと、$4015 で DMC をイネーブルにする。

周波数の計算方法
CPUクロック周波数/(再生したい音程の周波数×32)-1
CPUクロック周波数はファミコンだと、1790000 らしい。

デルタモジュレーションのデータについて
$4013 に送るデータの長さ(量)の指定データは、実際の容量を $10 で割る。
$200 なら $20 なので、簡単。

$4012 に送るデータの先頭アドレスの指定データは、実際のアドレスを の上位2bitをマスク(AND $3fff)して、$40 で割る。
$c200 なら、8 。

■ 割り込み
この辺も全然分からなくて、NMI でレジスタ退避したあとで、$2000 の b7に0を書き込んで割り込み禁止→ VBLANK中の処理→ $2000 の b7に1を書き込んで割り込み許可、という処理にしていたんだけど、それではダメで、$2002 を読み出して、割り込みフラグをリセットしなくてならなった模様。
割り込み関係はいくつかフラグや設定ポートがあるので理解するのが難しい。
知人のファミコン開発経験者に直接尋ねて分かりました。

スポンサーサイト

コメント

非公開コメント