NES on FPGA 2004/11/29

PPU (Picture Processing Unit)

 PPUはバックグラウンドとスプライトそれぞれ一面を描画することができ、 ラスタ走査に基づいて描画を行います。 フレームは1秒間に60回描画されます。 描画に必要なデータは、CPUがPPUのI/Oを経由してVRAMやスプライトRAMにストアします。 このデータに基づき、PPUはパターンデータをカートリッジのCHR-ROMからフェッチします。 またスクロールレジスタにスクロール値をストアすることで画面の描画領域をスクロールします。

[I/Oレジスタ] [パターンテーブル] [バックグラウンド] [メモリマップ] [スプライト] [メモリアクセス] [フレームタイミング]

! 型番はRP2C02。

描画信号はメモリに一旦描画したものを出力するわけではなく、 直接生成している。

すいません。説明増やします。

_
I/Oレジスタ

 PPUのI/OレジスタはCPUのメモリマップに割り当てられています。 CPUからのread、writeによって、PPUの描画オプションの設定、描画状態の取得ができます。

書き込み
アドレス説明
$2000 コントロールレジスタ1
bit 用途
--------------------------------------------------------
7   VBlank時にNMIを発生 0:無効、1:発生
6   PPUマスタースレーブ、常に1
5   スプライトサイズ 0:8x8、1:8x16
4   背景パターンテーブルアドレス指定 0:$0000、1:$1000
3   スプライトパターンテーブルアドレス指定 0:$0000、1:$1000
2   PPUメモリアドレスインクリメント 0:+=1、1:+=32
1-0 ネームテーブルアドレス指定
        +-----------+-----------+
        | 2 ($2800) | 3 ($2C00) |
        +-----------+-----------+
        | 0 ($2000) | 1 ($2400) |
        +-----------+-----------+
$2001 コントロールレジスタ2
bit  説明
------------------------------------------
7-5  背景色
        000:黒
        001:緑
        010:青
        100:赤
4    スプライト有効 0:無効、1:有効
3    背景有効 0:無効、1:有効
2    スプライトマスク、画面左8ピクセルを描画しない。0:描画しない、1:描画
1    背景マスク、画面左8ピクセルを描画しない。0:描画しない、1:描画
0    ディスプレイタイプ 0:カラー、1:モノクロ
$2003 スプライトメモリアドレス
$2004を経由してスプライトメモリへ書き込む8ビットアドレスを指定。
$2004 スプライトメモリデータ
$2003によって指定されたスプライトメモリアドレスへデータを書き込む。 書き込む度にスプライトメモリアドレスはインクリメント(+=1)される。
$2005 背景スクロールオフセット
スクロール値を垂直、水平の順に書き込み。 指定した値によってネームテーブルアドレスが設定される。
$2006 PPUメモリアドレス
$2007を経由してPPUメモリへ書き込む16ビットアドレスを指定する。 上位8ビット、下位8ビットの順に書き込む。
$2007 PPUメモリデータ
$2006によって指定されたPPUメモリアドレスへデータを書き込む。 書き込む度にメモリアドレスはインクリメント($2000のビット2によって+=1、+=32)する。

読み込み
アドレス説明
$2002 ステータスレジスタ
読み込みによって$2005の書き込み順序がクリアされる。
bit 用途
--------------------------------------------------------
7   VBlank時に1、読み込みでクリアする。
6   スプライトヒット ヒット時に1
5   スキャンラインスプライト数 0:8個以下、1:9個以上
4-0 無効
      (ビット4はVRAM書き込みフラグ[0:成功,1:失敗]
           との情報もあるが、NESにその機能はない)
$2007 PPUメモリデータ
PPUメモリのデータをバッファを経由して読み込む。 PPUメモリアドレスは+=1、もしくは+=32される。

_
パターンテーブル

 パターンテーブルは$0000もしくは$1000から開始し、 それぞれ256個のパターンを持っています。 一つのパターンは8x8ピクセルで構成され、16バイトを要します。 各ピクセルはカラーパレットの下位2ビットのデータを保持します。

 例として、パターンテーブル$1000を使用し、 53番目のパターン(パターンIDは$34)を描画すると次のようになります。
ADDR   DATA
$1340  $C0 11000000 --
$1341  $C0 11000000  |
$1342  $C0 11000000  |
$1343  $F0 11110000  |
$1344  $F8 11111000  |
$1345  $DC 11011100  | Low  -- 01 01 00 00 00 10 10 00
$1346  $CE 11001110  |======|  01 01 00 00 10 10 00 00
$1347  $00 00000000 --      |  01 01 00 10 10 00 00 00
                            |  01 11 11 11 00 00 00 00
$1348  $06 00000110 --      |  01 01 11 11 11 00 00 00
$1349  $0C 00001100  | High |  01 01 00 11 11 11 00 00
$134A  $18 00011000  |======|  01 01 00 00 11 11 11 00
$134B  $70 01110000  |      -- 00 00 00 00 00 00 00 00
$134C  $38 00111000  |
$134D  $1C 00011100  |
$134E  $0E 00001110  |
$134F  $00 00000000 --
  


カラーパレット下位2ビット
00 01 10 11

_
バックグラウンド

 BG(Back Ground)は8×8のタイルパターンを32×30個配置することで、 256×240ピクセルの解像度を持ちます。 BG描画は、まずスキャン座標と設定されたスクロール値によって算出された座標を、 範囲内に持つネームテーブルから描画するパターンのアドレスIDをフェッチします。 また、色情報として属性テーブルからデータをフェッチします。 次にパターンアドレスIDに対応する下位パターンと上位パターンをフェッチします。 パターンは上位ビットから描画され、 下位パターンと上位パターンの各ビットが有効なら、 色情報とパターンビットによりBGパレットから色が選択されます。 パターンのいずれのビットも有効でなければ透過色となり、 スプライトパレットの$3F10の色が選択されます。

_
メモリマップ

アドレスサイズ用途
$0000〜$0FFF$1000パターンテーブル#0
$1000〜$1FFF$1000パターンテーブル#1
$2000〜$23BF$03C0ネームテーブル#0
$23C0〜$23FF$0040属性テーブル#0
$2400〜$27BF$03C0ネームテーブル#1
$27C0〜$27FF$0040属性テーブル#1
$2800〜$2BBF$03C0ネームテーブル#2
$2BC0〜$2BFF$0040属性テーブル#2
$2C00〜$2FBF$03C0ネームテーブル#3
$2FC0〜$2FFF$0040属性テーブル#3
$3000〜$3EFF
-
$2000-$2EFFのミラー
$3F00〜$3F0F$0010バックグラウンドパレット
$3F10〜$3F1F$0010スプライトパレット
$3F20〜$3FFF
-
$3F00-$3F1Fのミラー×7

 PPUはVRAM、スプライトRAM、パレットRAM、カートリッジのCHR-ROMにアクセスし、 メモリマップは表のようになっています。 パターンテーブルはカートリッジへのアクセスとなります。 ネームテーブルと属性テーブルは4組あり、 画面のスクロールに関連してVRAMとカートリッジ内の拡張RAMにマップされ、 その割り当てはカートリッジによって異なります。

_
スプライト

 スプライトRAMは256バイトが存在します。 一つのスプライトに4バイトが割り当てられるため、64個分のスプライトデータが保持できます。
offset用途
0Y座標-1
1パターンインデックス
2
アトリビュート
   VHP000CC
   |||   ||
   |||   ++-カラーパレット上位2ビット
   ||+------BGとの優先順位、0:SPR優先、1:BG優先
   |+-------左右反転フラグ、1:反転
   +--------上下反転フラグ、1:反転
3X座標

 描画されるべきスプライトのために、 スプライトテンポラリレジスタとスプライトバッファレジスタが8スプライト分だけ存在します。 あるラインにおいて次のラインで描画されるべきスプライトが見つかった場合、 スプライトテンポラリレジスタに保持されます。 スプライトの探索の後、 スプライトテンポラリレジスタに基づいてスプライトバッファレジスタにスプライトのパターンがフェッチされます。 このパターンデータが次のラインで描画されます。 またスプライト用レジスタの最初のスプライトはスプライト#0と呼ばれます。 このスプライトがBG上に描画されるピクセルにおいて、ヒットフラグがセットされます。 このヒットフラグの利用例として横スクロールゲームなどでは、 ヒットするまでは横スクロール値を0として点数やタイムなどの情報を描画し、 ヒットが検出されたら横スクロール値を設定してスクロールしたゲーム画面を描画しています。

_
メモリアクセス

 PPUは341クロックで一つのラインの描画と次のラインの準備を行います。 最初の256クロックでBGとスプライトの描画を行いながら、 次のスキャンラインで描画されるべきスプライトの探索を行います。 残りのクロックで探索されたスプライトのパターンを取得します。

PPUの外部へのメモリアクセスは、BGの256ピクセルを描画する間、

  1. ネームテーブルから1バイトフェッチ
  2. 属性テーブルから1バイトフェッチ
  3. パターンテーブルから2バイトフェッチ

を33回繰り返します。 また、水平帰還の間に次のスキャンラインで描画されるスプライトのために、 スプライトパターンから2バイトのフェッチを8回繰り返します。

_
フレームタイミング

 フレームは262本のスキャンラインで構成されます。 最初の240本で画面が描画され、残りのスキャンラインは垂直回帰時間となり、 CPUはこの時間を利用してVRAMへの書き込みを行います。 この垂直回帰タイミングのために,PPUはCPUに対してNMI割り込みを発生させます。


Copyright(C) pgate1 All Rights Reserved.