+--------+
| 4. PPU |
+--------+

A. 一般情報
-------------
ミラーリング ("シャドーイング"とも呼ばれる) とはハードウェアによって
特定のアドレスやアドレス範囲が他のアドレスにマッピングされることである。


B. メモリマップ
-----------------
ここには2つのメモリマップがある。
最初はあまり冗長ではない"RAMメモリマップ"で、NES内部にある物理的RAMを指し示す
実際の領域について述べてある。

2つ目は非常に冗長な"プログラマメモリマップ"で、NESの全てのメモリ領域と
それをどのように使用・操作するのかが書かれている。

RAM Memory Map
+---------+-------+--------------------+
|アドレス |サイズ | 解説 |
+---------+-------+--------------------+
| $0000 | $1000 | Pattern Table #0 |
| $1000 | $1000 | Pattern Table #1 |
| $2000 | $800 | Name Tables |
| $3F00 | $20 | Palettes |
+---------+-------+--------------------+


Programmer Memory Map
+---------+-------+-------+---------------------+
|アドレス |サイズ |フラグ | 解説 |
+---------+-------+-------+---------------------+
| $0000 | $1000 | C | パターンテーブル #0 |
| $1000 | $1000 | C | パターンテーブル #1 |
| $2000 | $3C0 | | ネームテーブル #0 |
| $23C0 | $40 | N | 属性テーブル #0 |
| $2400 | $3C0 | N | ネームテーブル #1 |
| $27C0 | $40 | N | 属性テーブル #1 |
| $2800 | $3C0 | N | ネームテーブル #2 |
| $2BC0 | $40 | N | 属性テーブル #2 |
| $2C00 | $3C0 | N | ネームテーブル #3 |
| $2FC0 | $40 | N | 属性テーブル #3 |
| $3000 | $F00 | R | |
| $3F00 | $10 | | イメージパレット#1 |
| $3F10 | $10 | | スプライトパレット#1|
| $3F20 | $E0 | P | |
| $4000 | $C000 | F | |
+---------+-------+-------+---------------------+
C = 恐らくCHR-ROM
N = Mirrored (項目G参照)
P = Mirrored (項目H参照)
R = Mirror of $2000-2EFF (VRAM)
F = Mirror of $0000-3FFF (VRAM)


C. ネームテーブル
-------------------
NESはタイルのマトリックスを使って画像を表示する。
この格子はネームテーブルと呼ばれる。
タイル自身は8x8ピクセルで、
ネームテーブル全体で32x30タイル(256x240ピクセル)である。
ただしNTSCとPALで表示される解像度が異なることを念頭におくこと。

ネームテーブルはパターンテーブルの中に保持されているデータの
タイル番号を持つ。


D. パターンテーブル
---------------------
パターンテーブルはネームテーブルで参照する実際の8x8のタイルを含む。
NESのパレットの16色全てにアクセスするために必要な4ビットカラーマトリックスの
下位2ビットも保持する。
例:

VRAM Contents of Colour
Addr Pattern Table Result
------ --------------- --------
$0000: %00010000 = $10 --+ ...1.... ピリオドは色0を表す。
.. %00000000 = $00 | ..2.2...
.. %01000100 = $44 | .3...3..
.. %00000000 = $00 +-- Bit 0 2.....2. 番号は実際のパレット
.. %11111110 = $FE | 1111111. 色番号を表す。
.. %00000000 = $00 | 2.....2.
.. %10000010 = $82 | 3.....3.
$0007: %00000000 = $00 --+ ........

$0008: %00000000 = $00 --+
.. %00101000 = $28 |
.. %01000100 = $44 |
.. %10000010 = $82 +-- Bit 1
.. %00000000 = $00 |
.. %10000010 = $82 |
.. %10000010 = $82 |
$000F: %00000000 = $00 --+

上のパターンテーブルの結果は文字'A'であり、
"色の結果"は右上にある。


E. 属性テーブル
-----------------
属性テーブルのそれぞれのバイトはスクリーン上の4x4のタイルのグループを表す。
属性テーブルの1バイトの機能が何であるかはいくつもの言い方があり、


* 16x16ピクセルにつき、32x32ピクセルの格子の上位2ビットを保持する。
* 16枚の8x8タイルの上位2ビットを保持する。
* 4つの4x4タイルの格子の上位2ビットを保持する。

これは非常に混乱させる。2つの図表は理解を助けてくれるだろう。

+------------+------------+
| Square 0 | Square 1 | #0-Fは8x8のタイルを表す
| #0 #1 | #4 #5 |
| #2 #3 | #6 #7 | Square [x]は4つの8x8タイルを表す。
+------------+------------+ (すなわち16x16ピクセルの格子)
| Square 2 | Square 3 |
| #8 #9 | #C #D |
| #A #B | #E #F |
+------------+------------+

属性のバイトの実際のフォーマットは次の通りである
(上記の例に対応している)

Attribute Byte
(Square #)
----------------
33221100
||||||+--- Upper two (2) colour bits for Square 0 (Tiles #0,1,2,3)
||||+----- Upper two (2) colour bits for Square 1 (Tiles #4,5,6,7)
||+------- Upper two (2) colour bits for Square 2 (Tiles #8,9,A,B)
+--------- Upper two (2) colour bits for Square 3 (Tiles #C,D,E,F)


F. パレット
-------------
NESにはイメージパレットとスプライトパレットの2個の16色パレットが存在する。
それらは物理的なRGB値を持たないので、
これらのパレットは実際のパレットではなく「ルックアップテーブル」である。

$3F00-3FFFに書き込まれたバイトのD7-D6(上位2ビット)は無視される.


G. ネームテーブルのミラーリング
---------------------------------
NESを理解する時、多くの形式のミラーリングがあることを念頭に置くべきである。

Some methods even use CHR-ROM-mapped Name Tables (mapper-specific).

NES自身は、ネームテーブルのためのRAMは2048 ($800)バイトしか持たない。
しかしながら、項目Bにあるように、NESは最高4つまでのネームテーブルを
扱う能力を持っている。

デフォルトでは、多くのカートリッジは"水平"と"垂直"ミラーリングを伴い、

allowing you to change where the Name Tables point into the NES's PPU
RAM.

このミラーリングの形式は同時に2つのネームテーブルに影響を与える。
そのため、独立してネームテーブルを切り替えることは出来ない。

次のチャートはNESにおけるミラーリングの種類を理解するのを助けるだろう。
12ビットサイズで示されたアドレスがNESのPPU RAMのネームテーブル部について
言及していることに気が付いて欲しい。
VRAM領域で"$2xxx"と同じ意味であると考えても良い。

Name NT#0 NT#1 NT#2 NT#3 Flags
+--------------------------+------+------+------+------+-------+
| 水平 | $000 | $000 | $400 | $400 | |
| 垂直 | $000 | $400 | $000 | $400 | |
| 4画面 | $000 | $400 | $800 | $C00 | F |
| 単画面 | | | | | S |
| CHR-ROM mirroring | | | | | C |
+--------------------------+------+------+------+------+-------+
F = 4画面ミラーリングは(カートリッジに積まれた)2048($800)バイトの
拡張RAMに依存し、4つの物理的な独立したネームテーブルをもたらす。
S = 単画面のゲームはどのPPU RAM領域($000,$400,$800,or $C00)
を使用するのかを選択できるマッパーを持ち、
全てのネームテーブルは同じPPU RAMアドレスを指し示す。
C = マッパー#68(アフターバーナー2)はNESのPPU RAMのネームテーブル領域に
CHR-ROMを配置することが出来る。
当然、ネームテーブルはROMベースなものになり、書き込み不可となる。
しかし、この機能はマッパー自身によって有効/無効を変更できる。


H. パレットのミラーリング
---------------------------
イメージパレットとスプライトパレット間にもミラーリングは発生する。
$3F00に書かれたデータは$3F10にミラーされ、
$3F04に書かれたデータは$3F14にミラーされ、………

イメージパレット、スプライトパレットともに
上の3つのパレット(0,1,2,3のうち1〜3)の色#0は透明と定義されている。
(そこにある実際の色データはスクリーンに描画されない)

PPUは$3F00の値を背景色として使用する。

長い説明として、次の事を想定する。

* $0Dを$3F00に書き込む ($3F10にミラー)
* $03を$3F08に書き込む ($3F18にミラー)
* $1Aを$3F18に書き込む
* $3F08をアキュムレータに読み込む

$3F08が値$03であるにも関わらず、$0Dが背景色となる。
(全てのパレットの色#0は透明と定義され、描画されないため)
最終的に、アキュムレータは$3F18からミラーされた値$1Aを保持している。
再び、色#0は透明と定義されている為、値$1Aは描画されない。

イメージ・スプライトパレットの全体は共にVRAMの他の領域にミラーされている。
$3F20-3FFFが両パレットのミラーである。

$3F00-3FFFのD7-D6(上位2ビット)は無視される。


I. 背景スクロール
-------------------
背景(前述のネームテーブル+パターンテーブル+属性テーブル)は
背景の上に重ねられるスプライトとは独立してスクロールする事ができる。
背景は水平・垂直にスクロール可能である。

スクロールは次のように動作する:

水平スクロール 垂直スクロール
0 512
+-----+-----+ +-----+ 0
| | | | |
| A | B | | A |
| | | | |
+-----+-----+ +-----+
| |
| B |
| |
+-----+ 480

ネームテーブル"A"はレジスタ$2000のビットD1-D0で指定され、
"B"は後のネームテーブルである(これはミラーリングのために動的である)。
これは水平・垂直スクロールを同時に行うゲームには動作しない。

背景はここに示されるように複数のネームテーブルをまたぐ。

+---------------+---------------+
| Name Table #2 | Name Table #3 |
| ($2800) | ($2C00) |
+---------------+---------------+
| Name Table #0 | Name Table #1 |
| ($2000) | ($2400) |
+---------------+---------------+

$2005に書き込む水平スクロール値の範囲は0から256である。
垂直スクロール値の範囲は0から239で、239より大きい値を使った場合
マイナスの値になることが考えられる。(例 248を書き込むと実際は-8)


J. スプライトの重ね合わせ
---------------------------
NESが描画する時には特定の順序がある。

FRONT BACK
+----+-----------+----+-----------+-----+
| CI | OBJs 0-63 | BG | OBJs 0-63 | EXT |
+----+-----------+----+-----------+-----+
| SPR-RAM | | SPR-RAM |
| BGPRI==0 | | BGPRI==1 |
+-----------+ +-----------+

CIは'Colour Intensity'を意味し、これは$2001のD7-D5と同じである。
BGは背景であり、EXTは拡張ポートビデオシグナルである。

'BGPRI'はSPR-RAMの中のスプライト毎のデータ列の D5, Byte 2(次項参照)にある
'Background Priority'(背景優先度)ビットを意味している。

OBJの番号はスプライト番号を表し、タイルインデックス番号ではない。

FRONTは全ての一番上の層に表示され(最後に描画される)、
BACKは最下層に表示される(最初に描画される)。


K. スプライトとSPR-RAM
------------------------
NESは64個のスプライトをサポートし、
それは8x8あるいは8x16ピクセルのサイズを取ることが出来る。
スプライトのデータはVRAMのパターンテーブル領域の中に保持されている。

反転や優先度などのスプライト属性は、ROMやVRAMからは独立した
256バイトのメモリ領域であるSPR-RAMの中に持たれる。
SPR-RAMの形式は以下の通りである。

+-----------+-----------+-----+------------+
| Sprite #0 | Sprite #1 | ... | Sprite #63 |
+-+------+--+-----------+-----+------------+
| |
+------+----------+--------------------------------------+
+ Byte | Bits | 解説 |
+------+----------+--------------------------------------+
| 0 | YYYYYYYY | Y座標 - 1 |
| | | 座標はスプライトの左上端の座標で |
| | | あると考えられる。 |
| 1 | IIIIIIII | タイルインデックス番号 |
| 2 | vhp000cc | 属性 |
| | | v = 垂直反転 (1=Flip) |
| | | h = 水平反転 (1=Flip) |
| | | p = 優先度 |
| | | 0 = スプライトが手前 |
| | | 1 = 背景が手前 |
| | | c = 色の上位2ビット |
| 3 | XXXXXXXX | X座標 (左上端) |
+------+----------+--------------------------------------+

タイルインデックス番号はネームテーブルのデータと同じ方法で得られる。

8x16サイズのスプライトは多少異なった動作をする。
タイルインデックス番号が偶数の8x16スプライトは
VRAMの$0000のパターンテーブルを使用する。
タイルインデックス番号が奇数の8x16スプライトは
VRAMの$1000のパターンテーブルを使用する。
*注意*レジスタ$2000は8x16スプライトには影響しない。

64個のスプライトは内部優先度を持っている;スプライト#0はスプライト#63より
優先度が高い(スプライト#0は最後に描画されているはずである)。

スキャンライン毎にスプライトは8個までしか表示させることは出来ない。
SPR-RAMの中の各スプライトエントリは、
他のスプライトの水平の範囲の中にあるかどうかチェックされる。
これは1スキャンライン毎に行われ、スプライト毎でないことを覚えておきなさい。
(例 これは256/8や256/16回ではなく256回を行われる)

(注意:実際のNESにおいては、スプライトが無効($2000のD4=0)ならば、
長い一定の時間、SPR-RAMは徐々に分解するであろう。
提言されたコンセプトは、SPR-RAMは実はDRAMであり、
D4がDRAMのリフレッシュサイクルをコントロールしているということである)


L. スプライト#0ヒットフラグ
-----------------------------
PPUはどこにスプライト#0があるのか理解することができ、
その調査結果を$2002のD6に持つことができる。
どのようにして働くかは次の通り。

PPUは初めの透明でない"スプライトピクセル"と
初めの透明でない"バックグラウンドピクセル"を探す。
"バックグラウンドピクセル"とはネームテーブルで使われるタイルのことである。
色#0は透明と定義されていることを覚えておきなさい。

D6をセットするピクセルは描画*される*。

次の例が助けとなるだろう。これらは2つのタイルである。
透明色(色#0)はアンダースコア('_')で示されている。
アスタリスク('*')はD6がセットされる点を示している。

Sprite BG Result
------ -- ------
__1111__ ________ __1111__
_111111_ _______2 _1111112
11222211 ______21 11222211
112__211 + _____211 = 112__*11 '*'には色#2が描画される
112__211 ____2111 112_2211 訳者注:この図は間違いかもしれない。
11222211 ___21111 11222211 '*'の右上の点でD6がセットされるはず。
_111111_ __211111 _1111111
__1111__ _2111111 _2111111

これは上記の例とは違って'BG+Sprite'になるものの、
(優先度ビットの設定によって)BGの下にあるスプライトにも当てはまる。

また、VBlankの発生後毎にD6はクリア(0にセット)される。


M. 水平・垂直Blank
-----------------------------------
他のどのコンソールとも同じように、NESにもリフレッシュ:ディスプレイ装置が
データを表示するための電子銃を移動させる場所 がある。
最も普通のディスプレイ装置はテレビである。
リフレッシュは、NTSCの装置では1秒間に60回、PALの装置では50回発生する。

電子銃はピクセルを左から右に向かって描画する:このプロセスは
1本の水平スキャンラインを描画する。
※1本のスキャンライン全体を描き終えるとディスプレイの左端に戻り、
次のスキャンラインの描画をするための準備を始める。
(※1本のスキャンライン全体を描き終えると次のスキャンラインの描画を
するための準備を始めながらディスプレイの左端に戻る  か?(訳者))
電子銃がディスプレイ左端に戻る過程は水平ブランク期間(HBlank)である。

全てのスキャンラインを描画し終えると、
ディスプレイの上端に戻らなければならない。
この、電子銃がディスプレイ上端に戻る時間を垂直ブランク期間(VBlank)と呼ぶ。

下図を見ればわかるように、VBlankに到達するまでの間は多かれ少なかれ
ジグザグのパターンで動作する。そしてそれを繰り返す。

+-----------+
+--->|***********| <-- Scanline 0
| | ___---~~~ | <-- HBlank
V |***********| <-- Scanline 1
B | ___---~~~ | <-- HBlank
l | ... | ...
a | ... | ...
n |***********| <-- Scanline 239
k +-----+-----+
| |
+--VBlank--+

NTSCのNESは次のようなリフレッシュ・スクリーンのレイアウトになっている。

+--------+ 0 ----+
| | |
| | |
| Screen | +-- (0-239) 256x240 on-screen results
| | |
| | |
+--------+ 240 --+
| ?? | +-- (240-242) Unknown
+--------+ 243 --+
| | |
| VBlank | +-- (243-262) VBlank
| | |
+--------+ 262 --+

VBlankフラグは$2002のD7にある。これはPPUがVBlankにあるかどうかを示す。
$2002を読むことによってD7をリセットすることができる。


N. $2005/2006 Magic
-------------------
$2005と$2006のレジスタに関しての詳細情報については、
Loopyの$2005/2006ドキュメントを読みなさい。
彼の文書はこれらのレジスタの動作に関して完全に正確な情報を提供してくれる。
さらなる情報についてはLoopyに連絡を取りなさい。


O. PPUの奇癖
-------------
VRAMからの最初の読込は有効ではない。
この局面のために、NESは予想される順序正しい値ではなく
VRAMから疑似バッファ値を返すのだろう。(? 以下原文)
(Due to this aspect, the NES will returned pseudo-buffered values from VRAM
rather than linear as expected.)
次の例を見なさい。

VRAMは$2000から $AA $BB $CC $DDを持つ。
VRAM増加値は1である。
実行の結果はコメントに記してある。

LDA #$20
STA $2006
LDA #$00
STA $2006 ; VRAMアドレスを$2000にセット
LDA $2007 ; A=?? VRAM Buffer=$AA
LDA $2007 ; A=$AA VRAM Buffer=$BB
LDA $2007 ; A=$BB VRAM Buffer=$CC
LDA #$20
STA $2006
LDA #$00
STA $2006 ; VRAMアドレスを$2000にセット
LDA $2007 ; A=$CC VRAM Buffer=$AA
LDA $2007 ; A=$AA VRAM Buffer=$BB

これで見られるように、
PPUは最初の読込が実行された後で内部アドレスを増加させる。
これはVRAMの$0000-3EFFに*のみ適用される。*
(例 パレットデータとそれらのそれぞれのミラーはこの現象に苦しめられない。)


P. メモ
--------
PPUは$2007にアクセスした後に($2000のD2に基づいて)1または32だけ
VRAMアドレスを自動増加させる。



+---------+
| 5. pAPU |
+---------+
To be written. Prior information was inaccurate or incorrect. No one
has 100% accurate sound information at this time. This section will
be completed when someone decides to reverse engineer the pAPU section
of the NES, and provide me with information (or a reference to infor-
mation).



次へ