├── .gitignore ├── 65xx ├── addressing.md ├── cycle.md ├── isa │ ├── alu.md │ ├── control.md │ ├── jump.md │ ├── rotate_shift.md │ └── transfer.md └── register.md ├── README.md ├── cartridge └── header.md ├── cycle.md ├── images ├── hdma │ ├── example1.png │ └── example2.gif ├── mode0_1.webp ├── mode1_1.webp ├── mode1_2.webp ├── mode2_1.webp ├── mode5_1.webp ├── mode5_2.webp ├── mode7_1.webp ├── mode7_2.webp ├── modeprops │ ├── 2bpp.webp │ ├── 4bpp.webp │ ├── 8bpp.webp │ ├── bg1.webp │ ├── bg2.webp │ ├── bg3.webp │ ├── bg4.webp │ ├── colormath.webp │ ├── directcolor.webp │ ├── interlace.webp │ ├── mode0.webp │ ├── mode1.webp │ ├── mode2.webp │ ├── mode3.webp │ ├── mode4.webp │ ├── mode5.webp │ ├── mode6.webp │ ├── mode7.webp │ ├── mosaic.webp │ ├── ocpc.webp │ ├── p512.webp │ ├── t512.webp │ └── window.webp ├── sfc.webp ├── sound │ ├── com.webp │ ├── components.webp │ └── timer.webp └── window │ ├── example1.png │ └── example2.png ├── interrupt ├── README.md ├── ioreg.md └── irq.md ├── ioreg.md ├── keypad ├── joypad.md └── signal.md ├── memory ├── README.md ├── dma │ ├── README.md │ ├── hdma.md │ ├── ioreg.md │ └── timing.md ├── oam.md ├── palette.md ├── vram.md ├── wram.md └── ws2.md ├── muldiv.md ├── openbus.md ├── others └── anomie │ ├── apudsp_jwdonal.txt │ ├── c4.txt │ ├── memmap.txt │ ├── ob-wrap.txt │ ├── ports.txt │ ├── spc700.txt │ ├── spc700cyc.txt │ └── timing.txt ├── sound ├── README.md ├── ioreg.md └── spc700 │ ├── README.md │ ├── ioreg.md │ └── timer.md ├── spec.md ├── timing └── oscillator.md └── video ├── bg ├── README.md ├── bgmap.md ├── control.md ├── mode.md ├── mode7.md ├── mosaic.md └── scroll.md ├── colormath.md ├── control.md ├── layer.md ├── mul.md ├── obj ├── oam.md ├── obsel.md └── priority.md ├── palette.md ├── scanline.md ├── vram.md └── window.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.draft.md -------------------------------------------------------------------------------- /65xx/addressing.md: -------------------------------------------------------------------------------- 1 | # アドレッシングモード 2 | 3 | 命令のオペランドから操作対象のアドレスを取得する方法です。 4 | 5 | ``` 6 | 即値アドレッシング 7 | 正確にはアドレッシングではないです。 8 | オペコードの直後のオペランドをそのまま使用します。 9 | 10 | メリット: 11 | 他のアドレッシングモードは、アドレス取得から対象読み出しでメモリ読み込みが必要だが、即値アドレッシングでは必要ないため高速 12 | デメリット: 13 | 命令サイズが大きくなる 14 | ``` 15 | 16 | ``` 17 | 絶対アドレッシング 18 | 16bitのパラメータを使って、64KBのメモリ空間 0000h...FFFFh のアドレスのどこかを指定します。(バンクはDB) 19 | (24bitのパラメータを使ってバンクを含めて任意のアドレスを指定することもできます) 20 | 21 | メリット: 22 | どこでも指定可能 23 | デメリット: 24 | パラメータとして余計に1バイト追加されるため、ゼロページより少し遅い 25 | ``` 26 | 27 | ``` 28 | ゼロページアドレッシング 29 | ダイレクトアドレッシングとも呼ばれます。 30 | 8bitのパラメータ(1バイト)を使って、メモリの最初の256バイト 0000h...00FFh(=ゼロページ) 内のアドレスを指定します。 31 | 絶対アドレッシングの亜種で、上位8bitが 0x00 (ゼロページ)で固定された代わりにパラメータが8bitになりました。 32 | 33 | メリット: 34 | オペランドが1バイトで済む 35 | フェッチが1バイト少ないので絶対アドレッシングより高速 36 | カセット容量の小さいこの時代には1バイトでも小さいことが重宝されていた 37 | デメリット: 38 | ゼロページの範囲しか指定できない 39 | ``` 40 | 41 | ``` 42 | 間接アドレッシング 43 | オペランドで指定したアドレスに真のアドレスが入っています。メモリを中継するので正確には メモリ間接(アドレッシング) とも呼びます。 44 | スーファミの場合は、ゼロページアドレッシングで取得したアドレスから16bit値を読み出し、それをアドレスとします。 45 | 46 | メリット: 47 | ポインタの扱いが楽 48 | スーファミとは関係ないが、RISCは固定長という性質上、少ないbit数でアドレスを指定したいことが多いので役に立つ 49 | デメリット: 50 | メモリアクセスが余計に1回加わるため低速 51 | ``` 52 | 53 | ``` 54 | 指標アドレッシング 55 | インデックスアドレッシングとも呼ばれます。 56 | 他のアドレッシングモードで算出したアドレスに、インデックスレジスタ(X or Y)を足したものをアドレスとします。 57 | 58 | メリット: 59 | 配列などのメモリ上で連続したデータを処理するときに、インデックスレジスタを増やすことでループ上の同じ命令で配列を処理することができる 60 | デメリット: 61 | なし(元になったアドレッシングモードに依存) 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /65xx/cycle.md: -------------------------------------------------------------------------------- 1 | # CPUサイクル 2 | 3 | CPUサイクルは、CPUにとっての最短時間、つまり 1/CPUクロック 秒 です。 詳細は[こちら](../cycle.md)を見てください。 4 | 5 | 各CPUサイクルには、フェーズ1 と フェーズ2 の2つのフェーズがあります。 6 | 7 | ``` 8 | フェーズ1では、CPUがアドレスバス上で次のアドレスの準備をします。 9 | フェーズ2の間、CPUがメモリによってデータバスに値を入れられるのを待ちます。 10 | ``` 11 | 12 | フェーズ1は常に3マスターサイクル要します。 13 | 14 | フェーズ2はアクセス先のメモリによって要する時間が変わります。 15 | 16 | ``` 17 | フェーズ2: 18 | 高速メモリ(3.5MHz): 3マスターサイクル 19 | 低速メモリ(2.6MHz): 5マスターサイクル 20 | ``` 21 | 22 | ## 参考 23 | 24 | - https://discord.com/channels/388461081888292865/449676046736818178/713407616738656317 25 | 26 | ``` 27 | Each CPU cycle has two phases: phase 1 and phase 2. During phase 1, the CPU gets the next address ready on the address bus. During phase 2, the CPU is waiting for the memory to put a value on the data bus. Phase 1 always lasts 3 master clocks. When the CPU is accessing fast memory, phase 2 lasts 3 master clocks; when accessing slow memory, it lasts 5. 28 | ``` 29 | -------------------------------------------------------------------------------- /65xx/isa/alu.md: -------------------------------------------------------------------------------- 1 | # ALU 2 | 3 | ## オペコード 4 | 5 | Base | フラグ | Native | Nocash | オペランド | 名前 | 内容 6 | -- | -- | -- | -- | -- | -- | -- 7 | 00 | nz---- | ORA op | OR A,op | \ | OR | A=A OR op 8 | 20 | nz---- | AND op | AND A,op | \ | AND | A=A AND op 9 | 40 | nz---- | EOR op | XOR A,op | \ | XOR | A=A XOR op 10 | 60 | nzc--v | ADC op | ADC A,op | \ | Add | A=A+C+op 11 | E0 | nzc--v | SBC op | SBC A,op | \ | Subtract | A=A+C-1-op 12 | C0 | nzc--- | CMP op | CMP A,op | \ | Compare | A-op 13 | E0 | nzc--- | CPX op | CMP X,op | \ | Compare | X-op 14 | C0 | nzc--- | CPY op | CMP Y,op | \ | Compare | Y-op 15 | 16 | ## alu_types 17 | 18 | 上記オペコードの一部(OR,AND,XOR,ADC,SBC,CMP)のオペランド部分です。 19 | 20 | オペコード | サイクル | Native | Nocash | 名前 | 内容 21 | -- | -- | -- | -- | -- | -- 22 | Base+09 nn | 2 | #nn | nn | Immediate | nn 23 | Base+05 nn | 3 | nn | \[nn\] | Zero Page | \[D+nn\] 24 | Base+15 nn | 4 | nn,X | \[nn+X\] | Zero Page,X | \[D+nn+X\] 25 | Base+0D nn nn | 4 | nnnn | \[nnnn\] | Absolute | \[DB:nnnn\] 26 | Base+1D nn nn | 4* | nnnn,X | \[nnnn+X\] | Absolute,X | \[DB:nnnn+X\] 27 | Base+19 nn nn | 4* | nnnn,Y | \[nnnn+Y\] | Absolute,Y | \[DB:nnnn+Y\] 28 | Base+01 nn | 6 | (nn,X) | \[\[nn+X\]\] | (Indirect,X) | \[WORD\[D+nn+X\]\] 29 | Base+11 nn | 5* | (nn),Y | \[\[nn\]+Y\] | (Indirect),Y | \[WORD\[D+nn\]+Y\] 30 | Base+12 nn | | (nn) | \[\[nn\]\] | (Indirect) | \[WORD\[D+nn\]\] 31 | Base+03 nn | | nn,S | \[nn+S\] | | \[nn+S\] 32 | Base+13 nn | | (nn,S),Y | \[\[nn+S\]+Y\] | | \[WORD\[nn+S\]+Y\] 33 | Base+07 nn | | \[nn\] | \[FAR\[nn\]\] | | \[FAR\[D+nn\]\] 34 | Base+17 nn | | \[nn\],y | \[FAR\[nn\]+Y\] | | \[FAR\[D+nn\]+Y\] 35 | Base+0F nn nn nn | | nnnnnn | \[nnnnnn\] | | \[nnnnnn\] 36 | Base+1F nn nn nn | | nnnnnn,X | \[nnnnnn+X\] | | \[nnnnnn+X\] 37 | 38 | > \* Add one cycle if indexing crosses a page boundary. 39 | 40 | ## cpx_types 41 | 42 | 上記オペコードの一部(`CMP X`, `CMP Y`)のオペランド部分です。 43 | 44 | オペコード | サイクル | Native | Nocash | 名前 | 内容 45 | -- | -- | -- | -- | -- | -- 46 | Base+00 nn | 2 | #nn | nn | Immediate | nn 47 | Base+04 nn | 3 | nn | \[nn\] | Zero Page | \[D+nn\] 48 | Base+0C nn nn | 4 | nnnn | \[nnnn\] | Absolute | \[DB:nnnn\] 49 | 50 | ## ビットテスト 51 | 52 | オペコード | フラグ | サイクル | Native | Nocash | オペランド 53 | -- | -- | -- | -- | -- | -- 54 | 24 nn | xz---x | 3 | BIT nn | `TEST A,[nn]` | `[D+nn]` 55 | 2C nn nn | xz---x | 4 | BIT nnnn | `TEST A,[nnnn]` | `[DB:nnnn]` 56 | 34 nn | xz---x | | BIT nn,X | `TEST A,[nn+X]` | `[D+nn+X]` 57 | 3C nn nn | xz---x | | BIT nnnn,X | `TEST A,[nnnn+X]` | `[DB:nnnn+X]` 58 | 89 nn | -z---- | | BIT #nn | `TEST A,nn` | `nn` 59 | 60 | 各フラグは 61 | 62 | ```c 63 | // MSB: bit15 or bit7 (Mフラグに依存) 64 | Z = (A & op) == 0; 65 | N = Bit(op, MSB); 66 | V = Bit(op, MSB-1); 67 | ``` 68 | 69 | となっています。 70 | 71 | ## インクリメント 72 | 73 | オペコード | フラグ | サイクル | Native | Nocash | 内容 74 | -- | -- | -- | -- | -- | -- 75 | E6 nn | nz---- | 5 | INC nn | `INC [nn]` | `[D+nn]=[D+nn]+1` 76 | F6 nn | nz---- | 6 | INC nn,X | `INC [nn+X]` | `[D+nn+X]=[D+nn+X]+1` 77 | EE nn nn | nz---- | 6 | INC nnnn | `INC [nnnn]` | `[DB:nnnn]=[DB:nnnn]+1` 78 | FE nn nn | nz---- | 7 | INC nnnn,X | `INC [nnnn+X]` | `[DB:nnnn+X]=[DB:nnnn+X]+1` 79 | E8 | nz---- | 2 | INX | `INC X` | `X=X+1` 80 | C8 | nz---- | 2 | INY | `INC Y` | `Y=Y+1` 81 | 1A | nz---- | 2 | INA | `INC A` | `A=A+1` 82 | 83 | ## デクリメント 84 | 85 | オペコード | フラグ | サイクル | Native | Nocash | 内容 86 | -- | -- | -- | -- | -- | -- 87 | C6 nn | nz---- | 5 | DEC nn | `DEC [nn]` | `[D+nn]=[D+nn]-1` 88 | D6 nn | nz---- | 6 | DEC nn,X | `DEC [nn+X]` | `[D+nn+X]=[D+nn+X]-1` 89 | CE nn nn | nz---- | 6 | DEC nnnn | `DEC [nnnn]` | `[DB:nnnn]=[DB:nnnn]-1` 90 | DE nn nn | nz---- | 7 | DEC nnnn,X | `DEC [nnnn+X]` | `[DB:nnnn+X]=[DB:nnnn+X]-1` 91 | CA | nz---- | 2 | DEX | `DEC X` | `X=X-1` 92 | 88 | nz---- | 2 | DEY | `DEC Y` | `Y=Y-1` 93 | 3A | nz---- | 2 | DEA | `DEC A` | `A=A-1` 94 | 95 | ## TSB/TRB (Test and Set/Reset) 96 | 97 | オペコード | サイクル | Native | Nocash 98 | -- | -- | -- | -- 99 | 04 nn | -z---- | 5 | `TSB nn` | `SET [nn],A` 100 | 0C nn nn | -z---- | 6 | `TSB nnnn` | `SET [nnnn],A` 101 | 14 nn | -z---- | 5 | `TRB nn` | `CLR [nn],A` 102 | 1C nn nn | -z---- | 6 | `TRB nnnn` | `CLR [nnnn],A` 103 | 104 | ```c 105 | // TSB(SET) 106 | Z = (A & op) == 0; 107 | A |= op; 108 | 109 | // TRB(CLR) 110 | Z = (A & op) == 0; 111 | A = op & ^A; 112 | ``` 113 | 114 | -------------------------------------------------------------------------------- /65xx/isa/control.md: -------------------------------------------------------------------------------- 1 | # 制御命令 2 | 3 | ## 制御命令 4 | 5 | オペコード | フラグ | サイクル | Native | Nocash | 内容 6 | -- | -- | -- | -- | -- | -- 7 | 18 | --0--- | 2 | CLC | `CLC` | `C=0` 8 | 58 | ---0-- | 2 | CLI | `EI` | `I=0` 9 | D8 | ----0- | 2 | CLD | `CLD` | `D=0` 10 | B8 | -----0 | 2 | CLV | `CL?` | `V=0` 11 | 38 | --1--- | 2 | SEC | `STC` | `C=1` 12 | 78 | ---1-- | 2 | SEI | `DI` | `I=1` 13 | F8 | ----1- | 2 | SED | `STD` | `D=1` 14 | C2 nn | xxxxxx | 3 | REP #nn | `CLR P,nn` | `P=P AND NOT nn` 15 | E2 nn | xxxxxx | 3 | SEP #nn | `SET P,nn` | `P=P OR nn` 16 | FB | --c--- | 2 | XCE | `XCE` | `C=E, E=C` 17 | 18 | ## 特殊命令 19 | 20 | オペコード | フラグ | サイクル | Native | Nocash | 内容 21 | -- | -- | -- | -- | -- | -- 22 | DB | ------ | - | STP | KILL | STOP/KILL 23 | EB | nz---- | 3 | XBA | SWAP A | `A=B, B=A, NZ=LSB` 24 | CB | ------ | 3x | WAI | HALT | HALT命令 25 | 42 nn | | 2 | WDM #nn | NUL nn | 何もしない 26 | EA | ------ | 2 | NOP | NOP | 何もしない 27 | 28 | `WAI/HALT`命令は、(IRQ、NMIのような)例外リクエストが起きるまでCPUを停止させます。 IRQが起きた場合、`I=1`でIRQが無効になっていたとしても、これは機能します。 29 | 30 | ## 割り込み、例外、ブレーク 31 | 32 | ``` 33 | Opcode 6502 65C816 34 | 00 BRK Break B=1 [S]=$+2,[S]=P,D=0 I=1, PB=00, PC=[00FFFE] [00FFE6] 35 | 02 COP ;65C816 B=1 [S]=$+2,[S]=P,D=0 I=1, PB=00, PC=[00FFF4] [00FFE4] 36 | -- /ABORT ;65C816 PB=00, PC=[00FFF8] [00FFE8] 37 | -- /IRQ Interrupt B=0 [S]=PC, [S]=P,D=0 I=1, PB=00, PC=[00FFFE] [00FFEE] 38 | -- /NMI NMI B=0 [S]=PC, [S]=P,D=0 I=1, PB=00, PC=[00FFFA] [00FFEA] 39 | -- /RESET Reset D=0 E=1 I=1 D=0000, DB=00 PB=00, PC=[00FFFC] N/A 40 | ``` 41 | 42 | 例外(Exception)時は、まずBフラグが変更され(6502モードのとき)、次に`P`をスタックに書き込んだあと、Iフラグをセットし、Dフラグがクリアされます(オリジナルの6502とは異なります)。 43 | 44 | ソフトウェアまたはハードウェアは、`/IRQ`または`/NMI`信号を処理した後、アクノリッジまたはリセットを行うよう注意する必要があります。 45 | 46 | ``` 47 | IRQs are executed whenever "/IRQ=LOW AND I=0". 48 | NMIs are executed whenever "/NMI changes from HIGH to LOW". 49 | ``` 50 | 51 | `/IRQ`をLOWにした場合、`I=0`にするとすぐに同じ(古い)割り込みが再度実行されます。 `/NMI`をLOWにした場合、それ以上NMIを実行することはできません。 -------------------------------------------------------------------------------- /65xx/isa/jump.md: -------------------------------------------------------------------------------- 1 | # ジャンプ命令 2 | 3 | ## 無条件ジャンプ 4 | 5 | オペコード | フラグ | サイクル | Native | Nocash | 内容 6 | -- | -- | -- | -- | -- | -- 7 | 80 dd | ------ | 3xx | BRA disp8 | JMP disp | PC=PC+/-disp8 8 | 82 dd dd | ------ | 4 | BRL disp16 | JMP disp | PC=PC+/-disp16 9 | 4C nn nn | ------ | 3 | JMP nnnn | JMP nnnn | PC=nnnn 10 | 5C nn nn nn | ------ | 4 | JMP nnnnnn | JMP nnnnnn | PB:PC=nnnnnn 11 | 6C nn nn | ------ | 5 | JMP (nnnn) | JMP \[nnnn\] | PC=WORD\[00:nnnn\] 12 | 7C nn nn | ------ | 6 | JMP (nnnn,X) | JMP \[nnnn+X\] | PC=WORD\[PB:nnnn+X\] 13 | DC nn nn | ------ | 6 | JML ... | JMP FAR\[nnnn\] | PB:PC=\[00:nnnn\] 14 | 20 nn nn | ------ | 6 | JSR nnnn | CALL nnnn | \[S\]=PC+2,PC=nnnn 15 | 22 nn nn nn | ------ | 4 | JSL nnnnnn | CALL nnnnnn | PB:PC=nnnnnn \[S\]=PB:PC+3 16 | FC nn nn | ------ | 6 | JSR (nnnn,X) | CALL \[nnnn+X\] | PC=WORD\[PB:nnnn+X\] \[S\]=PC 17 | 40 | nzcidv | 6 | RTI | RETI | P=\[S+1\],PB:PC=\[S+2\],S=S+4 18 | 6B | ------ | ? | RTL | RETF | PB:PC=\[S+1\]+1, S=S+3 19 | 60 | ------ | 6 | RTS | RET | PC=\[S+1\]+1, S=S+2 20 | 21 | 22 | >**Note** 23 | > RTI命令は、BRK/IRQ/NMI からリターンする際に用います。BRKから戻るときのリターン先のアドレスは、BRK命令の2バイト後であることに注意してください。(つまりBRK命令後の1バイトは無視される) 24 | > RTIは、Bフラグおよび不使用フラグを変更することはできません。 25 | 26 | Glitch: For `JMP [nnnn]` the operand word cannot cross page boundaries, ie. `JMP [03FFh]` would fetch the MSB from `[0300h]` instead of `[0400h]`. Very simple workaround would be to place a ALIGN 2 before the data word. 27 | 28 | ## 条件付きジャンプ 29 | 30 | オペコード | フラグ | サイクル | Native | Nocash | 条件 31 | -- | -- | -- | -- | -- | -- 32 | 10 dd | ------ | 2[1](#cycle) | BPL | JNS disp | `N=0` (plus/positive) 33 | 30 dd | ------ | 2[1](#cycle) | BMI | JS disp | `N=1` (minus/negative/signed) 34 | 50 dd | ------ | 2[1](#cycle) | BVC | JNO disp | `V=0` (no overflow) 35 | 70 dd | ------ | 2[1](#cycle) | BVS | JO disp | `V=1` (overflow) 36 | 90 dd | ------ | 2[1](#cycle) | BCC/BLT | JNC/JB disp | `C=0` (less/below/no carry) 37 | B0 dd | ------ | 2[1](#cycle) | BCS/BGE | JC/JAE disp | `C=1` (above/greater/equal/carry) 38 | D0 dd | ------ | 2[1](#cycle) | BNE/BZC | JNZ/JNE disp | `Z=0` (not zero/not equal) 39 | F0 dd | ------ | 2[1](#cycle) | BEQ/BZS | JZ/JE disp | `Z=1` (zero/equal) 40 | 41 | 1: 実行時間は、条件が偽の場合(分岐が実行されない)、2サイクルです。それ以外の場合は、ジャンプ先が同じメモリページ内にある場合は3サイクル、ページ境界を越える場合は4サイクルです。 42 | 43 | >**Note** 44 | > x86やZ80のCPUとは異なり、減算(SBCやCMP)は以下(`A-B`として、`A >= B`)のときに`carry=set`となります。 45 | 46 | ## Conditional Branch Page Crossing 47 | 48 | The branch opcode with parameter takes up two bytes, causing the PC to get incremented twice (`PC=PC+2`), without any extra boundary cycle. 49 | 50 | The signed parameter is then added to the PC (`PC+disp`), the extra clock cycle occurs if the addition crosses a page boundary (next or previous 100h-page). 51 | 52 | -------------------------------------------------------------------------------- /65xx/isa/rotate_shift.md: -------------------------------------------------------------------------------- 1 | # 回転・シフト命令 2 | 3 | ## 算術・論理左シフト 4 | 5 | オペコード | フラグ | サイクル | Native | Nocash | 内容 6 | -- | -- | -- | -- | -- | -- 7 | 0A | nzc--- | 2 | ASL A | SHL A | SHL A 8 | 06 nn | nzc--- | 5 | ASL nn | SHL \[nn\] | SHL \[D+nn\] 9 | 16 nn | nzc--- | 6 | ASL nn,X | SHL \[nn+X\] | SHL \[D+nn+X\] 10 | 0E nn nn | nzc--- | 6 | ASL nnnn | SHL \[nnnn\] | SHL \[DB:nnnn\] 11 | 1E nn nn | nzc--- | 7 | ASL nnnn,X | SHL \[nnnn+X\] | SHL \[DB:nnnn+X\] 12 | 13 | ## 論理右シフト 14 | 15 | オペコード | フラグ | サイクル | Native | Nocash | 内容 16 | -- | -- | -- | -- | -- | -- 17 | 4A | 0zc--- | 2 | LSR A | SHR A | SHR A 18 | 46 nn | 0zc--- | 5 | LSR nn | SHR \[nn\] | SHR \[D+nn\] 19 | 56 nn | 0zc--- | 6 | LSR nn,X | SHR \[nn+X\] | SHR \[D+nn+X\] 20 | 4E nn nn | 0zc--- | 6 | LSR nnnn | SHR \[nnnn\] | SHR \[DB:nnnn\] 21 | 5E nn nn | 0zc--- | 7 | LSR nnnn,X | SHR \[nnnn+X\] | SHR \[DB:nnnn+X\] 22 | 23 | 24 | ## CY付き左ローテート 25 | 26 | オペコード | フラグ | サイクル | Native | Nocash | 内容 27 | -- | -- | -- | -- | -- | -- 28 | 2A | nzc--- | 2 | ROL A | RCL A | RCL A 29 | 26 nn | nzc--- | 5 | ROL nn | RCL \[nn\] | RCL \[D+nn\] 30 | 36 nn | nzc--- | 6 | ROL nn,X | RCL \[nn+X\] | RCL \[D+nn+X\] 31 | 2E nn nn | nzc--- | 6 | ROL nnnn | RCL \[nnnn\] | RCL \[DB:nnnn\] 32 | 3E nn nn | nzc--- | 7 | ROL nnnn,X | RCL \[nnnn+X\] | RCL \[DB:nnnn+X\] 33 | 34 | 35 | ## CY付き右ローテート 36 | 37 | オペコード | フラグ | サイクル | Native | Nocash | 内容 38 | -- | -- | -- | -- | -- | -- 39 | 6A | nzc--- | 2 | ROR A | RCR A | RCR A 40 | 66 nn | nzc--- | 5 | ROR nn | RCR \[nn\] | RCR \[D+nn\] 41 | 76 nn | nzc--- | 6 | ROR nn,X | RCR \[nn+X\] | RCR \[D+nn+X\] 42 | 6E nn nn | nzc--- | 6 | ROR nnnn | RCR \[nnnn\] | RCR \[DB:nnnn\] 43 | 7E nn nn | nzc--- | 7 | ROR nnnn,X | RCR \[nnnn+X\] | RCR \[DB:nnnn+X\] 44 | 45 | >**Note** 46 | > ROR命令は、1976年6月以降のMCS650Xマイクロプロセッサで利用可能です。 47 | > ROLとRORは8bitの値をキャリー付きで回転させます。(つまり合計9bitを回転させます) 48 | 49 | -------------------------------------------------------------------------------- /65xx/isa/transfer.md: -------------------------------------------------------------------------------- 1 | # データ転送命令 2 | 3 | ## レジスタからレジスタへのデータ転送 4 | 5 | オペコード | フラグ | サイクル | Native | Nocash | Bits | Effect 6 | -- | -- | -- | -- | -- | -- | -- 7 | A8 | nz---- | 2 | TAY | `MOV Y,A` | x | `Y=A` 8 | AA | nz---- | 2 | TAX | `MOV X,A` | x | `X=A` 9 | BA | nz---- | 2 | TSX | `MOV X,S` | x | `X=S` 10 | 98 | nz---- | 2 | TYA | `MOV A,Y` | m | `A=Y` 11 | 8A | nz---- | 2 | TXA | `MOV A,X` | m | `A=X` 12 | 9A | ------ | 2 | TXS | `MOV S,X` | e | `S=X` 13 | 9B | nz---- | 2 | TXY | `MOV Y,X` | x | `Y=X` 14 | BB | nz---- | 2 | TYX | `MOV X,Y` | x | `X=Y` 15 | 7B | nz---- | 2 | TDC | `MOV A,D` | 16 | `A=D` 16 | 5B | nz---- | 2 | TCD | `MOV D,A` | 16 | `D=A` 17 | 3B | nz---- | 2 | TSC | `MOV A,SP` | 16 | `A=SP` 18 | 1B | ------ | 2 | TCS | `MOV SP,A` | e? | `SP=A` 19 | 20 | ## メモリからレジスタへの読み込み 21 | 22 | オペコード | フラグ | サイクル | Native | Nocash | Bits | Effect 23 | -- | -- | -- | -- | -- | -- | -- 24 | A9 nn | nz---- | 2 | LDA #nn | MOV A,nn | -- | A=nn 25 | A5 nn | nz---- | 3 | LDA nn | MOV A,\[nn\] | -- | A=\[D+nn\] 26 | B5 nn | nz---- | 4 | LDA nn,X | MOV A,\[nn+X\] | -- | A=\[D+nn+X\] 27 | A3 nn | nz---- | | LDA nn,S | MOV A,\[nn+S\] | -- | A=\[nn+S\] 28 | AD nn nn | nz---- | 4 | LDA nnnn | MOV A,\[nnnn\] | -- | A=\[DB:nnnn\] 29 | BD nn nn | nz---- | 4* | LDA nnnn,X | MOV A,\[nnnn+X\] | -- | A=\[DB:nnnn+X\] 30 | B9 nn nn | nz---- | 4* | LDA nnnn,Y | MOV A,\[nnnn+Y\] | -- | A=\[DB:nnnn+Y\] 31 | AF nn nn nn | nz---- | | LDA nnnnnn | MOV A,\[nnnnnn\] | -- | A=\[nnnnnn\] 32 | BF nn nn nn | nz---- | | LDA nnnnnn,X | MOV A,\[nnnnnn+X\] | -- | A=\[nnnnnn+X\] 33 | B2 nn | nz---- | | LDA (nn) | MOV A,\[\[nn\]\] | -- | A=\[WORD\[D+nn\]\] 34 | A1 nn | nz---- | 6 | LDA (nn,X) | MOV A,\[\[nn+X\]\] | -- | A=\[WORD\[D+nn+X\]\] 35 | B1 nn | nz---- | 5* | LDA (nn),Y | MOV A,\[\[nn\]+Y\] | -- | A=\[WORD\[D+nn\]+Y\] 36 | B3 nn | nz---- | | LDA (nn,S),Y | MOV A,\[\[nn+S\]+Y\] | -- | A=\[WORD\[nn+S\]+Y\] 37 | A7 nn | nz---- | | LDA \[nn\] | MOV A,\[FAR\[nn\]\] | -- | A=\[FAR\[D+nn\]\] 38 | B7 nn | nz---- | | LDA \[nn\],y | MOV A,\[FAR\[nn\]+Y\] | -- | A=\[FAR\[D+nn\]+Y\] 39 | A2 nn | nz---- | 2 | LDX #nn | MOV X,nn | -- | X=nn 40 | A6 nn | nz---- | 3 | LDX nn | MOV X,\[nn\] | -- | X=\[D+nn\] 41 | B6 nn | nz---- | 4 | LDX nn,Y | MOV X,\[nn+Y\] | -- | X=\[D+nn+Y\] 42 | AE nn nn | nz---- | 4 | LDX nnnn | MOV X,\[nnnn\] | -- | X=\[DB:nnnn\] 43 | BE nn nn | nz---- | 4* | LDX nnnn,Y | MOV X,\[nnnn+Y\] | -- | X=\[DB:nnnn+Y\] 44 | A0 nn | nz---- | 2 | LDY #nn | MOV Y,nn | -- | Y=nn 45 | A4 nn | nz---- | 3 | LDY nn | MOV Y,\[nn\] | -- | Y=\[D+nn\] 46 | B4 nn | nz---- | 4 | LDY nn,X | MOV Y,\[nn+X\] | -- | Y=\[D+nn+X\] 47 | AC nn nn | nz---- | 4 | LDY nnnn | MOV Y,\[nnnn\] | -- | Y=\[DB:nnnn\] 48 | BC nn nn | nz---- | 4* | LDY nnnn,X | MOV Y,\[nnnn+X\] | -- | Y=\[DB:nnnn+X\] 49 | 50 | > \* Add one cycle if indexing crosses a page boundary. 51 | 52 | ## レジスタからメモリへの書き込み 53 | 54 | オペコード | フラグ | サイクル | Native | Nocash | Bits | Effect 55 | -- | -- | -- | -- | -- | -- | -- 56 | 64 nn | ------ | 3 | STZ nn | MOV \[nn\],0 | m | \[D+nn\]=0 57 | 74 nn | ------ | 4 | STZ nn_x | MOV \[nn+X\],0 | m | \[D+nn+X\]=0 58 | 9C nn nn | ------ | 4 | STZ nnnn | MOV \[nnnn\],0 | m | \[DB:nnnn\]=0 59 | 9E nn nn | ------ | 5 | STZ nnnn_x | MOV \[nnnn+X\],0 | m | \[DB:nnnn+X\]=0 60 | 85 nn | ------ | 3 | STA nn | MOV \[nn\],A | m | \[D+nn\]=A 61 | 95 nn | ------ | 4 | STA nn,X | MOV \[nn+X\],A | m | \[D+nn+X\]=A 62 | 83 nn | ------ | | STA nn,S | MOV \[nn+S\],A | m | \[nn+S\]=A 63 | 8D nn nn | ------ | 4 | STA nnnn | MOV \[nnnn\],A | m | \[DB:nnnn\]=A 64 | 9D nn nn | ------ | 5 | STA nnnn,X | MOV \[nnnn+X\],A | m | \[DB:nnnn+X\]=A 65 | 99 nn nn | ------ | 5 | STA nnnn,Y | MOV \[nnnn+Y\],A | m | \[DB:nnnn+Y\]=A 66 | 8F nn nn nn | ------ | | STA nnnnnn | MOV \[nnnnnn\],A | m | \[nnnnnn\]=A 67 | 9F nn nn nn | ------ | | STA nnnnnn,X | MOV \[nnnnnn+X\],A | m | \[nnnnnn+X\]=A 68 | 81 nn | ------ | 6 | STA (nn,X) | MOV \[\[nn+X\]\],A | m | \[WORD\[D+nn+X\]\]=A 69 | 91 nn | ------ | 6 | STA (nn),Y | MOV \[\[nn\]+Y\],A | m | \[WORD\[D+nn\]+Y\]=A 70 | 92 nn | ------ | | STA (nn) | MOV \[\[nn\]\],A | m | \[WORD\[D+nn\]\]=A 71 | 93 nn | ------ | | STA (nn,S),Y | MOV \[\[nn+S\]+Y\],A | m | \[WORD\[nn+S\]+Y\]=A 72 | 87 nn | ------ | | STA [nn] | MOV \[FAR\[nn\]\],A | m | \[FAR\[D+nn\]\]=A 73 | 97 nn | ------ | | STA [nn],y | MOV \[FAR\[nn\]+Y\],A | m | \[FAR\[D+nn\]+Y\]=A 74 | 86 nn | ------ | 3 | STX nn | MOV \[nn\],X | x | \[D+nn\]=X 75 | 96 nn | ------ | 4 | STX nn,Y | MOV \[nn+Y\],X | x | \[D+nn+Y\]=X 76 | 8E nn nn | ------ | 4 | STX nnnn | MOV \[nnnn\],X | x | \[DB:nnnn\]=X 77 | 84 nn | ------ | 3 | STY nn | MOV \[nn\],Y | x | \[D+nn\]=Y 78 | 94 nn | ------ | 4 | STY nn,X | MOV \[nn+X\],Y | x | \[D+nn+X\]=Y 79 | 8C nn nn | ------ | 4 | STY nnnn | MOV \[nnnn\],Y | x | \[DB:nnnn\]=Y 80 | 81 | ## スタックへのPush,Pull 82 | 83 | オペコード | フラグ | サイクル | Native | Nocash | Bits | Effect 84 | -- | -- | -- | -- | -- | -- | -- 85 | 48 | ------ | 3 | PHA | `PUSH A` | m | `[S]=A` 86 | DA | ------ | 3 | PHX | `PUSH X` | x | `[S]=X` 87 | 5A | ------ | 3 | PHY | `PUSH Y` | x | `[S]=Y` 88 | 08 | ------ | 3 | PHP | `PUSH P` | 8 | `[S]=P` 89 | 8B | ------ | 3 | PHB | `PUSH DB` | 8 | `[S]=DB` 90 | 4B | ------ | 3 | PHK | `PUSH PB` | 8 | `[S]=PB` 91 | 0B | ------ | 4 | PHD | `PUSH D` | 16 | `[S]=D` 92 | D4 nn | ------ | 6 | PEI nn | `PUSH WORD[nn]` | 16 | `[S]=WORD[D+nn]` 93 | F4 nn nn | ------ | 5 | PEA nnnn | `PUSH nnnn` | 16 | `[S]=NNNN` 94 | 62 nn nn | ------ | 6 | PER rel16 | `PUSH disp16` | 16 | `[S]=$+3+disp` 95 | 68 | nz---- | 4 | PLA | `POP A` | m | `A=[S]` 96 | FA | nz---- | 4 | PLX | `POP X` | x | `X=[S]` 97 | 7A | nz---- | 4 | PLY | `POP Y` | x | `Y=[S]` 98 | 2B | nz---- | 5 | PLD | `POP D` | 16 | `D=[S]` 99 | AB | nz---- | 4 | PLB | `POP DB` | 8 | `DB=[S]` 100 | 28 | nzcidv | 4 | PLP | `POP P` | 8 | `P=[S]` 101 | 102 | ## ブロック単位のメモリ転送 103 | 104 | オペコード | フラグ | サイクル | Native | Nocash | 備考 105 | -- | -- | -- | -- | -- | -- 106 | 44 dd ss | ------ | 7x | MVP ss,dd | `LDDR [dd:Y],[ss:X],A+1` | `DEC X/Y` 107 | 54 dd ss | ------ | 7x | MVN ss,dd | `LDIR [dd:Y],[ss:X],A+1` | `INC X/Y` 108 | 109 | ```go 110 | // MVP 111 | for (A != 0xFFFF) { 112 | val := load8(ss:X) 113 | store8(dd:Y, val) 114 | X--, Y--, A-- 115 | } 116 | 117 | // MVN 118 | for (A != 0xFFFF) { 119 | val := load8(ss:X) 120 | store8(dd:Y, val) 121 | X++, Y++, A-- 122 | } 123 | ``` -------------------------------------------------------------------------------- /65xx/register.md: -------------------------------------------------------------------------------- 1 | # [レジスタ](https://problemkaputt.de/fullsnes.htm#cpuregistersandflags) 2 | 3 | スーファミのCPUは汎用レジスタとして使えるレジスタはA,X,Yの最大3個だけです。 4 | 5 | しかし、レジスタの数が限られているというデメリットも、快適なでカバーできる部分もあります。 6 | 7 | 特にメモリのページ0(アドレス`0000h..00FFh`)は比較的高速で複雑な操作が可能であるため、実質的に、CPUはメモリ内に約256個の8bitレジスタ(または128個の16bitレジスタ)を持っていると言えるでしょう。 8 | 9 | 詳細を知りたい場合は、[アドレッシング](addressing.md)を参照してください。 10 | 11 | ## 👾 レジスタ 12 | 13 | bit幅 | 名前 | 内容 14 | ---- | ---- | ---- 15 | 8/16 | A | アキュムレータ 16 | 8/16 | X | インデックスレジスタX 17 | 8/16 | Y | インデックスレジスタY 18 | 16 | PC | プログラムカウンタ 19 | 8/16 | S | スタックポインタ 20 | 8 | P | ステータスレジスタ 21 | 16 | D | ゼロページオフセット(8bit`[nn]`を16bit`[00:nn+D]`に拡張する) 22 | 8 | DB | データバンク(16bit`[nnnn]`を24bit`[DB:nnnn]`に拡張する) 23 | 8 | PB | プログラムカウンタバンク(16bit`PC`を24bit`PB:PC`に拡張する) 24 | 25 | ## 📚 スタックポインタ 26 | 27 | スタックポインタは、メモリのページ1の256バイトを指定できます。つまり、`S=0xNN`のとき、スタックのトップは`0x01NN`となります。 28 | 29 | スタックは他の多くのCPUと同様、上に伸びていきます。つまりPUSHでデクリメントされ、POPでインクリメントされます。 30 | 31 | また、スタックポインタは最初のFREEバイトを指しているので、スタックをトップに初期化する際には、`S=(2)00h`ではなく、`S=(1)FFh`を設定します。 32 | 33 | ## 🚩 ステータスレジスタ(PSR) 34 | 35 | PSR = Processor Status Register 36 | 37 | Eがセットされているときにフラグの意味が変わるレジスタにはbitの後ろにEがついています。(4E, 5E) 38 | 39 | bit | 名前 | 内容 40 | ---- | ---- | ---- 41 | 0 | C | キャリー (0=No Carry, 1=Carry) 42 | 1 | Z | ゼロ (0=(前の計算結果が)非ゼロ, 1=ゼロ) 43 | 2 | I | 割り込み無効 (0=有効, 1=無効) 44 | 3 | D | デシマルモード (0=通常, 1=ADC/SBC時にBCDモードで動作) 45 | 4 | X | インデックスレジスタフラグ 46 | 4E | B | ブレークフラグ (0=IRQ, 1=BRK) 47 | 5 | M | アキュムレータフラグ 48 | 5E | U | 不使用 (常に1) 49 | 6 | V | オーバーフロー (0=No Overflow, 1=Overflow) 50 | 7 | N | ネガティブ (0=(前の計算結果が)正, 1=負) 51 | -- | E | 後述 (0=16bit, 1=8bit) 52 | 53 | ### エミュレーションフラグ (E) 54 | 55 | ファミコンのCPUである6502をエミュレーションするモード(6502互換モード)を起動します。このフラグはXCE命令でのみアクセスできます。 56 | 57 | このモードでは、A/X/Yは(X/Mを設定した場合と同じで)8bitとなります。Sも同様に8bit(`0100h..01FFh`)になります。 58 | 59 | 互換モード中は、XフラグはBフラグ(Break, 後述)に、MフラグはUフラグ(不使用、常に1)に変更されます。さらに、例外ベクタは6502アドレスに変更され、例外発生時はリターンアドレスとして(24bitではなく)16bitをプッシュします。条件付き分岐は、ページをまたぐときに1サイクル余分にかかります。 60 | 61 | ### アキュムレータフラグ (M) 62 | 63 | メモリフラグとも呼ばれているようです。 64 | 65 | Aを8bitモードに切り替えます。Aの上位8bitにはXBAでアクセス可能です。 66 | 67 | さらに、A,X,Yのオペランドを使用しないすべてのオペコード(STZや一部のINC/DECなど)を8bitモードに切り替えます。 68 | 69 | ### インデックスレジスタフラグ (X) 70 | 71 | インデックスレジスタX,Yを8bitモードに切り替えます。X,Yの上位8bitは強制的に`00h`になります 72 | 73 | ### キャリー (C) 74 | 75 | 減算(SBC、CMP)に使用される場合、キャリーフラグは0以上の場合にセットされます。これは通常の80x86やZ80のCPUのキャリーフラグとは逆の意味を持っていることに注意してください。 76 | 77 | 他のすべての命令(ADC、ASL、LSR、ROL、ROR)では通常通り動作しますが、ROL/RORはキャリーを介して回転します。これは80x86ではROL/RORよりも、RCL/RCRに近い挙動です。 78 | 79 | ### ゼロフラグ (Z), ネガティブフラグ (N), オーバーフローフラグ (V) 80 | 81 | Zは命令の結果がゼロのときにセットされ、Nは符号付き(bit7が1)のときにセットされます。 82 | 83 | Vは加算減算が符号付き数値の最大範囲(`-128..+127`)を超えた場合に設定されます。 84 | 85 | ### 割り込み無効フラグ (I) 86 | 87 | Iフラグをセットすると、IRQが無効化されます。NMIとBRK命令を無効にすることはできません。 88 | 89 | ### デシマルモードフラグ (D) 90 | 91 | Dフラグがセットされている場合、ACD、SBC命令がBCDモードで動作します。 92 | 93 | ### ブレークフラグ (B) 94 | 95 | 6502互換モード(E=1)のとき、BRKとIRQは同じ割り込みベクタのアドレス(`FFFEh`)にジャンプします。このBフラグはBRKとIRQを区別できるようにするためのもので、BRKならB=1、IRQならB=0となります。 96 | 97 | Bフラグに直接アクセスすることはできませんが、Pレジスタをスタックに書き込み、その値からBフラグを調べることができます。 98 | 99 | BRKとPHPは常にBフラグをセットし、IRQとNMIは常にBフラグをクリアします。 100 | 101 | ## 👽 レジスタ名のエイリアス一覧 102 | 103 | ``` 104 | DPR D (used in homebrew specs) 105 | K PB (used by PHK) 106 | PBR PB (used in specs) 107 | DBR DB (used in specs) 108 | B DB (used by PLB,PHB) 109 | B Upper 8bit of A (used by XBA) 110 | C Full 16bit of A (used by TDC,TCD,TSC,TCS) 111 | ``` 112 | 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # snes-docs-ja 2 | 3 | >**Warning** 4 | > このレポジトリは大半が執筆途中です。なので現在、ドキュメントとしての信頼性は皆無です。 5 | > また、コミット履歴は気まぐれで破壊されることがあります。 6 | 7 | >**Note** 8 | > 断りがない限り、情報は全てNTSC版です。 9 | 10 | 11 | 12 | スーパーファミコン(SFC)について、技術的な詳細を日本語でまとめたものです。 13 | 14 | 突然消えたり非公開にする可能性もあるので心配な方はクローンしておくことをお勧めします。 15 | 16 | ## コンテンツ一覧 17 | 18 | ### SNES 19 | 20 | - [仕様](spec.md) 21 | - [メモリマップ](memory/) 22 | - [I/Oレジスタの一覧](ioreg.md) 23 | - [乗算・除算](muldiv.md) 24 | - [サイクル](cycle.md) 25 | - [オープンバス](openbus.md) 26 | - [割り込み](interrupt/) 27 | - [IRQ](interrupt/irq.md) 28 | - [レジスタ](interrupt/ioreg.md) 29 | 30 | ### CPU 31 | 32 | - [レジスタ](65xx/register.md) 33 | - [アドレッシング](65xx/addressing.md) 34 | - [CPUサイクル](65xx/cycle.md) 35 | - 命令セット 36 | - [データ転送命令](65xx/isa/transfer.md) 37 | - [ALU](65xx/isa/alu.md) 38 | - [回転・シフト命令](65xx/isa/rotate_shift.md) 39 | - [ジャンプ命令](65xx/isa/jump.md) 40 | - [制御命令](65xx/isa/control.md) 41 | 42 | ### メモリ 43 | 44 | - [メモリマップ](memory/) 45 | - [ウェイトステート2](memory/ws2.md) 46 | - [WRAMへのレジスタ経由のアクセス](memory/wram.md) 47 | - [DMA](memory/dma/) 48 | - [HDMA](memory/dma/hdma.md) 49 | - [レジスタ](memory/dma/ioreg.md) 50 | - [タイミング(TODO)](memory/dma/timing.md) 51 | 52 | ### グラフィック 53 | 54 | - [レイヤ](video/layer.md) 55 | - [制御レジスタ](video/control.md) 56 | - [背景(BG)](video/bg/) 57 | - [BGマップ](video/bg/bgmap.md) 58 | - [BG制御レジスタ](video/bg/control.md) 59 | - [BGモード](video/bg/mode.md) 60 | - [モザイク](video/bg/mosaic.md) 61 | - [スクロール](video/bg/scroll.md) 62 | - [スプライト(OBJ)](video/obj/) 63 | - [OAM](video/obj/oam.md) 64 | - [OAMへのレジスタ経由のアクセス](memory/oam.md) 65 | - [優先度](video/obj/priority.md) 66 | - [タイルサイズ](video/obj/obsel.md) 67 | - [ベースアドレス](video/obj/obsel.md) 68 | - [VRAM](video/vram.md) 69 | - [タイルデータ](video/vram.md#-8x8タイルデータ-bg-and-obj) 70 | - [タイルマップ](video/bg/bgmap.md) 71 | - [VRAMへのレジスタ経由のアクセス](memory/vram.md) 72 | - [パレット](video/palette.md) 73 | - [パレットへのレジスタ経由のアクセス](memory/palette.md) 74 | - [ダイレクトカラーモード](video/palette.md#ダイレクトカラーモード) 75 | - [ウィンドウ](video/window.md) 76 | - [カラーマス](video/colormath.md) 77 | - [乗算](video/mul.md) 78 | - [描画サイクル](video/scanline.md) 79 | - [Hカウンタ](video/scanline.md) 80 | - [Vカウンタ](video/scanline.md) 81 | 82 | ### サウンド 83 | 84 | - [概要](sound/) 85 | - [レジスタ](sound/ioreg.md) 86 | - [SPC700](sound/spc700/) 87 | - [IOレジスタ](sound/spc700/ioreg.md) 88 | - [タイマー](sound/spc700/timer.md) 89 | 90 | ### カートリッジ 91 | 92 | - [カートリッジヘッダ](cartridge/header.md) 93 | 94 | ### キー入力 95 | 96 | - [キー入力](keypad/joypad.md) 97 | - [キー入力(信号単位)](keypad/signal.md) 98 | 99 | ## リソース 100 | 101 | - [snes-test-roms](https://github.com/akatsuki105/snes-test-roms) 102 | - [Anomie's Docs](./others/anomie/) 103 | 104 | ## 関連するレポジトリ 105 | 106 | - [gb-docs-ja](https://github.com/akatsuki105/gb-docs-ja): GameBoyについて 107 | - [gba-docs-ja](https://github.com/akatsuki105/gba-docs-ja): GameBoy Advanceについて 108 | - [nds-docs-ja](https://github.com/akatsuki105/nds-docs-ja): Nintendo DSについて 109 | 110 | ## 参考記事 111 | 112 | - [Fullsnes - nocash SNES hardware specifications](https://problemkaputt.de/fullsnes.htm) 113 | - [Wikipedia - スーパーファミコン](https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%BC%E3%83%91%E3%83%BC%E3%83%95%E3%82%A1%E3%83%9F%E3%82%B3%E3%83%B3) 114 | -------------------------------------------------------------------------------- /cartridge/header.md: -------------------------------------------------------------------------------- 1 | # [カートリッジヘッダ](https://problemkaputt.de/fullsnes.htm#snescartridgeromheader) 2 | 3 | カートリッジヘッダは、SNESのメモリでは`0x00_FFxxh`(例外ベクタの近く)にマッピングされています。 4 | 5 | 実際のハードウェア上でゲームを実行するためには必要ありませんが、カートリッジヘッダは任天堂の承認プロセスで検証のために使用され、SNESエミュレータでもメモリレイアウトやROMタイプを識別するために使用されます。 6 | 7 | ROMイメージでは、ROMヘッダのオフセットは 8 | 9 | ``` 10 | LoROM: 0x00_7Fxx 11 | HiROM: 0x00_FFxx 12 | ExHiROM: 0x40_FFxx 13 | ``` 14 | 15 | となっています。 16 | 17 | もし`(imagesize AND 3FFh)=200h`の場合、つまり SWC/UFO/その他のコピー機からの追加ヘッダがある場合は、このオフセットに `+200h` を加えます。 18 | 19 | ## カートリッジヘッダ 20 | 21 | カートリッジヘッダは`FFC0h..FFDFh`の32バイトです。 22 | 23 | オフセット | サイズ | 内容 24 | -- | -- | -- 25 | FFC0h | 21バイト | カートリッジのタイトル 26 | FFD5h | 1バイト | Rom Makeup / ROM Speed and Map Mode (後述) 27 | FFD6h | 1バイト | チップセット (カートリッジの基盤構成、後述) 28 | FFD7h | 1バイト | ROMサイズ(後述) 29 | FFD8h | 1バイト | RAMサイズ(後述) 30 | FFD9h | 1バイト | 製造地域コード(後述) 31 | FFDAh | 1バイト | 製造元ID (00h=不明/自作, 01h=Nintendo, etc.) (33h=後期型拡張ヘッダが存在) 32 | FFDBh | 1バイト | バージョン (0スタート、つまり v1.0 = 00h) 33 | FFDCh | 2バイト | チェックサムの補数(チェックサムの16bitの補数(ビット反転)) 34 | FFDEh | 2バイト | チェックサム (all bytes in ROM added together; assume \[FFDC-F\]=FF,FF,0,0) 35 | 36 | ``` 37 | Note: 38 | 39 | ROMサイズは`[FFD7h]`の値が`n`とすると`(1 SHL n) KB`となります。 40 | - 例えば、08hなら256KB、0Chなら4MBになります。 41 | - 10,12,20,24 Mbitsのカートの場合、値は切り上げられます。 42 | RAMサイズは`[FFD8h]`の値が`n`とすると`(1 SHL n) KB`となります。 43 | - 例えば、01hなら2KB、05hなら32KBになります。 44 | - 00hはRAMが搭載されていないカートリッジであることを示します。 45 | ``` 46 | 47 | ## 拡張ヘッダ 48 | 49 | 拡張ヘッダは、オフセット`FFB0h..FFBFh`に配置されており、比較的後に発売されたカートリッジに搭載されています。 50 | 51 | ### 初期型拡張ヘッダ (1993): 52 | 53 | `[FFD4h]=00h`、つまりカートリッジのタイトルの最後が`00h`のときは初期型拡張ヘッダを利用しています。 54 | 55 | オフセット | サイズ | 内容 56 | -- | -- | -- 57 | FFB0h | 15バイト | 予約領域(全部0) 58 | FFBFh | 1バイト | チップセットのサブタイプ (基本的に0、`[FFD6h]=Fxh`の場合のみ参照) 59 | 60 | ### 後期型拡張ヘッダ (1994): 61 | 62 | `[FFDAh]=33h`、つまり製造元IDが`33h`のときは後期型拡張ヘッダを利用しています。 63 | 64 | オフセット | サイズ | 内容 65 | -- | -- | -- 66 | FFB0h | 2バイト | 製造元ID(ASCII2文字, 例: "01"=Nintendo) 67 | FFB2h | 4バイト | ゲームコード (ASCII4文字) (古いタイプはASCII2文字で20h,20hでパディングされています) 68 | FFB6h | 6バイト | 予約領域(全部0) 69 | FFBCh | 1バイト | Expansion FLASH Size (1 SHL n) Kbytes (used in JRA PAT) 70 | FFBDh | 1バイト | Expansion RAM Size (1 SHL n) Kbytes (in GSUn games) (without battery?) 71 | FFBEh | 1バイト | Special Version(usually zero) (eg. promotional version) 72 | FFBFh | 1バイト | チップセットのサブタイプ (基本的に0、`[FFD6h]=Fxh`の場合のみ参照) 73 | 74 | 注意: 初期型拡張ヘッダは ST010/11 ゲーム でのみ使われていました。 75 | 76 | > ST0xxは セタ製のチップで、主にAIを強化する目的で使われていました。 77 | 78 | 4文字のゲームコードの最初の文字が "Z"の場合、そのカートリッジにはサテラビューのようなデータパック/フラッシュカートリッジスロットがあります。これは、"Zxxx"の4文字コードにのみ適用され、スペース埋めされた古い2文字コード(`Zx `)には適用されません。 79 | 80 | ## Cartridge Header Variants 81 | 82 | The BS-X Satellaview FLASH Card Files, and Sufami Turbo Mini-Cartridges are using similar looking (but not fully identical) headers (and usually the same .SMC file extension) than normal ROM cartridges. Detecting the content of .SMC files can be done by examining ID Strings (Sufami Turbo), or differently calculated checksum values (Satellaview). For details, see: 83 | 84 | - [SNES Cart Satellaview (satellite receiver & mini flashcard)](https://problemkaputt.github.io/fullsnes.htm#snescartsatellaviewsatellitereceiverminiflashcard) 85 | - [SNES Cart Sufami Turbo (Mini Cartridge Adaptor)](https://problemkaputt.github.io/fullsnes.htm#snescartsufamiturbominicartridgeadaptor) 86 | 87 | Homebrew games (and copiers & cheat devices) are usually having several errors in the cartridge header (usually no checksum, zero-padded title, etc), they should (hopefully) contain valid entryoints in range 8000h..FFFEh. Many Copiers are using 8Kbyte ROM bank(s) - in that special case the exception vectors are located at offset 1Fxxh within the ROM-image. 88 | 89 | ## テキストフィールド 90 | 91 | The ASCII fields can use chr(20h..7Eh), actually they are JIS (with Yen instead backslash). 92 | 93 | ## ROM Size / Checksum Notes 94 | 95 | ROMサイズは、`(1 << n) KB` となっていますが、例外もいくつかあります。 96 | 97 | - 2,3個のROMチップを利用するカートリッジ(例: 8Mbit + 2Mbit) 98 | - 2個のROMチップを利用するつもりだったが、結局1つしか使わなかったカートリッジ 99 | - 24MbitのROMチップ(23C2401)を使うカートリッジ 100 | 101 | 3つのケースとも、ROMサイズを表す`[FFD7h]`には切り上げられた値が入っています。 102 | 103 | メモリ上では、容量が大きいROMチップがアドレス0にマッピングされます。そして、その後のアドレスに小さい方のROMチップがマッピングされ、以降はその小さいROMチップのミラーが続きます。 104 | 105 | 例えば、10Mbit(8+2Mbit) のゲームは 16Mbit として扱われ、メモリ上のマッピングは "8Mbit + 4x2Mbit" のように行われます。 106 | 107 | **ROMサイズが特殊なゲーム一覧** 108 | 109 | タイトル | ハードウェア | サイズ | チェックサム 110 | -- | -- | -- | -- 111 | 大貝獣物語2(J) | ExHiROM+S-RTC | 5MB | 4MB + 4 x Last 1MB 112 | テイルズオブファンタジア(J) | ExHiROM | 6MB | \ 113 | Star Ocean (J) | LoROM+S-DD1 | 6MB | 4MB + 2 x Last 2MB 114 | 天外魔境ZERO(J) | HiROM+SPC7110+RTC | 5MB | 5MB 115 | 桃太郎電鉄HAPPY(J) | HiROM+SPC7110 | 3MB | 2 x 3MB 116 | Sufami Turbo BIOS | LoROM in Minicart | xx | without checksum 117 | Sufami Turbo Games | LoROM in Minicart | xx | without checksum 118 | Dragon Ball Z - Hyper Dimension | LoROM+SA-1 | 3MB | Overdump 4MB 119 | SDガンダム GNEXT(J) | LoROM+SA-1 | 1.5MB | Overdump 2MB 120 | Megaman X2 | LoROM+CX4 | 1.5MB | Overdump 2MB 121 | BS Super Mahjong Taikai (J) | BS | Overdump/Mirr+Empty | ? 122 | 123 | SPC7110タイトル | ROMサイズ(ヘッダ値) | チェックサム 124 | -- | -- | -- 125 | Super Power League 4 | 2MB (rounded to 2MB) | 1x(All 2MB) 126 | 桃太郎電鉄HAPPY(J) | 3MB (rounded to 4MB) | 2x(All 3MB) 127 | 天外魔境ZERO(J) | 5MB (rounded to 8MB) | 1x(All 5MB) 128 | 129 | On-chip ROM contained in external CPUs (DSPn,ST01n,CX4) is NOT counted in the ROM size entry, and not included in the checksum. 130 | 131 | Homebrew files often contain 0000h,0000h or FFFFh,0000h as checksum value. 132 | 133 | ## 動作速度,マッピングモード (FFD5h) 134 | 135 | ``` 136 | Bit 0-3 マッピングモード 137 | 0x0: LoROM/32K Banks Mode 20 (LoROM) 138 | 0x1: HiROM/64K Banks Mode 21 (HiROM) 139 | 0x2: LoROM/32K Banks + S-DD1 Mode 22 (mappable) "Super MMC" 140 | 0x3: LoROM/32K Banks + SA-1 Mode 23 (mappable) "Emulates Super MMC" 141 | 0x5: HiROM/64K Banks Mode 25 (ExHiROM) 142 | 0xA: HiROM/64K Banks + SPC7110 Mode 25? (mappable) 143 | Bit 4 動作速度 144 | 0: Slow(200ns) 145 | 1: Fast(120ns) 146 | Bit 5 0b1(bit4とbit5の2bitでROMの動作クロック(2 or 3)を表していると思われる) 147 | Bit 6-7 0b00 148 | ``` 149 | 150 | Note: ExHiROM は "大貝獣物語2(J)" と "テイルズオブファンタジア(J)" でのみ使われています。 151 | 152 | ## チップセット (ROM/RAM information on cart) (FFD6h) (and some subclassed via FFBFh) 153 | 154 | ``` 155 | 00h ROM 156 | 01h ROM+RAM 157 | 02h ROM+RAM+Battery 158 | x3h ROM+Co-processor 159 | x4h ROM+Co-processor+RAM 160 | x5h ROM+Co-processor+RAM+Battery 161 | x6h ROM+Co-processor+Battery 162 | x9h ROM+Co-processor+RAM+Battery+RTC-4513 163 | xAh ROM+Co-processor+RAM+Battery+overclocked GSU1 ? (Stunt Race) 164 | x2h Same as x5h, used in "F1 Grand Prix Sample (J)" (?) 165 | 0xh Co-processor is DSP (DSP1,DSP1A,DSP1B,DSP2,DSP3,DSP4) 166 | 1xh Co-processor is GSU (MarioChip1,GSU1,GSU2,GSU2-SP1) 167 | 2xh Co-processor is OBC1 168 | 3xh Co-processor is SA-1 169 | 4xh Co-processor is S-DD1 170 | 5xh Co-processor is S-RTC 171 | Exh Co-processor is Other (Super Gameboy/Satellaview) 172 | Fxh.xxh Co-processor is Custom (subclassed via [FFBFh]=xxh) 173 | Fxh.00h Co-processor is Custom (SPC7110) 174 | Fxh.01h Co-processor is Custom (ST010/ST011) 175 | Fxh.02h Co-processor is Custom (ST018) 176 | Fxh.10h Co-processor is Custom (CX4) 177 | ``` 178 | 179 | 実際には以下の値が使用されます。 180 | 181 | ``` 182 | 00h ROM ;if gamecode="042J" --> ROM+SGB2 183 | 01h ROM+RAM (if any such produced?) 184 | 02h ROM+RAM+Battery ;if gamecode="XBND" --> ROM+RAM+Batt+XBandModem 185 | ;if gamecode="MENU" --> ROM+RAM+Batt+Nintendo Power 186 | 03h ROM+DSP 187 | 04h ROM+DSP+RAM (no such produced) 188 | 05h ROM+DSP+RAM+Battery 189 | 13h ROM+MarioChip1/ExpansionRAM (and "hacked version of OBC1") 190 | 14h ROM+GSU+RAM ;\ROM size up to 1MByte -> GSU1 191 | 15h ROM+GSU+RAM+Battery ;/ROM size above 1MByte -> GSU2 192 | 1Ah ROM+GSU1+RAM+Battery+Fast Mode? (Stunt Race) 193 | 25h ROM+OBC1+RAM+Battery 194 | 32h ROM+SA1+RAM+Battery (?) "F1 Grand Prix Sample (J)" 195 | 34h ROM+SA1+RAM (?) "Dragon Ball Z - Hyper Dimension" 196 | 35h ROM+SA1+RAM+Battery 197 | 43h ROM+S-DD1 198 | 45h ROM+S-DD1+RAM+Battery 199 | 55h ROM+S-RTC+RAM+Battery 200 | E3h ROM+Super Gameboy (SGB) 201 | E5h ROM+Satellaview BIOS (BS-X) 202 | F5h.00h ROM+Custom+RAM+Battery (SPC7110) 203 | F9h.00h ROM+Custom+RAM+Battery+RTC (SPC7110+RTC) 204 | F6h.01h ROM+Custom+Battery (ST010/ST011) 205 | F5h.02h ROM+Custom+RAM+Battery (ST018) 206 | F3h.10h ROM+Custom (CX4) 207 | ``` 208 | 209 | ## 製造地域コード (FFD9h) 210 | 211 | 製造国が決まるとPAL/NTSCのどちらであるかも決まります。 212 | 213 | 値 | FFD9h | 地域 | PAL/NTSC 214 | -- | ---- | ---- | -- 215 | 00h | - | 全世界向け(SGBなど) | any 216 | 00h | J | 日本 | NTSC 217 | 01h | E | アメリカ、カナダ | NTSC 218 | 02h | P | ヨーロッパ、オセアニア、アジア | PAL 219 | 03h | W | スウェーデン、スカンジナビア | PAL 220 | 04h | - | フィンランド | PAL 221 | 05h | - | デンマーク | PAL 222 | 06h | F | フランス | SECAM, PAL-like 50Hz 223 | 07h | H | オランダ | PAL 224 | 08h | S | スペイン | PAL 225 | 09h | D | ドイツ、オーストラリア、スイス | PAL 226 | 0Ah | I | イタリア | PAL 227 | 0Bh | C | 中国、香港 | PAL 228 | 0Ch | - | インドネシア | PAL 229 | 0Dh | K | 韓国 | NTSC 230 | 0Eh | A | Common (?) | ? 231 | 0Fh | N | カナダ | NTSC 232 | 10h | B | ブラジル | PAL-M, NTSC-like 60Hz 233 | 11h | U | オーストラリア | PAL 234 | 12h | X | その他 | ? 235 | 13h | Y | その他 | ? 236 | 14h | Z | その他 | ? 237 | 238 | FFD9hの項目は、`[FFD9h]`の値とゲームコードの4文字目を表しています。(製造地域コードが決まると`[FFD9h]`とゲームコードの4文字目が一意に定まるものがある) 239 | 240 | ## ゲームコード (FFB2h) 241 | 242 | この領域は`[FFDAh]=33h`のときに利用されます。 243 | 244 | ``` 245 | "xxxx" Normal 4-letter code (usually "Axxx") (or "Bxxx" for newer codes) 246 | "xx " Old 2-letter code (space padded) 247 | "042J" Super Gameboy 2 248 | "MENU" Nintendo Power FLASH Cartridge Menu 249 | "Txxx" NTT JRA-PAT and SPAT4 (SFC Modem BIOSes) 250 | "XBND" X-Band Modem BIOS 251 | "Zxxx" Special Cartridge with satellaview-like Data Pack Slot 252 | ``` 253 | 254 | ゲームコードが2文字のみのもの、"MENU"/"XBND"以外の、ゲームコードは、4文字目が製造地域を表しています。 255 | 256 | -------------------------------------------------------------------------------- /cycle.md: -------------------------------------------------------------------------------- 1 | # サイクル 2 | 3 | スーファミの時間単位は、21.4772700MHz で動作する水晶発振器からもたらされるクロック信号を土台としています。[1](#masterclock) 4 | 5 | ## マスターサイクル 6 | 7 | マスタークロックの周期1回分の時間です。スーファミにおける時間の最小単位です。 8 | 9 | ``` 10 | 1サイクル = 1 / (21.4772700 * (1000 * 1000)) 秒 11 | ``` 12 | 13 | ## CPUサイクル 14 | 15 | "C-cycle" とも呼ばれます。 16 | 17 | CPUにとっての最短時間、つまり 1/CPUクロック 秒 です。 18 | 19 | CPUのクロックはメモリアクセスの長さによって変動するため、CPUサイクルも然りです。 20 | 21 | ``` 22 | 1サイクル = n / (21.4772700 * (1000 * 1000)) 秒 = n マスターサイクル (n=6,8,12) 23 | ``` 24 | 25 | ## ドットサイクル 26 | 27 | PPUが1ドット(1ピクセル)描画するのにかかる時間です。 28 | 29 | ``` 30 | 1cycle = 1 / (5.36931750 * (1000 * 1000)) 秒 = 4 マスターサイクル 31 | ``` 32 | 33 | 1: このような時間単位の基準となるクロック(信号)は マスタークロック と呼ばれます 34 | 35 | -------------------------------------------------------------------------------- /images/hdma/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/hdma/example1.png -------------------------------------------------------------------------------- /images/hdma/example2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/hdma/example2.gif -------------------------------------------------------------------------------- /images/mode0_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode0_1.webp -------------------------------------------------------------------------------- /images/mode1_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode1_1.webp -------------------------------------------------------------------------------- /images/mode1_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode1_2.webp -------------------------------------------------------------------------------- /images/mode2_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode2_1.webp -------------------------------------------------------------------------------- /images/mode5_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode5_1.webp -------------------------------------------------------------------------------- /images/mode5_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode5_2.webp -------------------------------------------------------------------------------- /images/mode7_1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode7_1.webp -------------------------------------------------------------------------------- /images/mode7_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/mode7_2.webp -------------------------------------------------------------------------------- /images/modeprops/2bpp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/2bpp.webp -------------------------------------------------------------------------------- /images/modeprops/4bpp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/4bpp.webp -------------------------------------------------------------------------------- /images/modeprops/8bpp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/8bpp.webp -------------------------------------------------------------------------------- /images/modeprops/bg1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/bg1.webp -------------------------------------------------------------------------------- /images/modeprops/bg2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/bg2.webp -------------------------------------------------------------------------------- /images/modeprops/bg3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/bg3.webp -------------------------------------------------------------------------------- /images/modeprops/bg4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/bg4.webp -------------------------------------------------------------------------------- /images/modeprops/colormath.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/colormath.webp -------------------------------------------------------------------------------- /images/modeprops/directcolor.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/directcolor.webp -------------------------------------------------------------------------------- /images/modeprops/interlace.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/interlace.webp -------------------------------------------------------------------------------- /images/modeprops/mode0.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode0.webp -------------------------------------------------------------------------------- /images/modeprops/mode1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode1.webp -------------------------------------------------------------------------------- /images/modeprops/mode2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode2.webp -------------------------------------------------------------------------------- /images/modeprops/mode3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode3.webp -------------------------------------------------------------------------------- /images/modeprops/mode4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode4.webp -------------------------------------------------------------------------------- /images/modeprops/mode5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode5.webp -------------------------------------------------------------------------------- /images/modeprops/mode6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode6.webp -------------------------------------------------------------------------------- /images/modeprops/mode7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mode7.webp -------------------------------------------------------------------------------- /images/modeprops/mosaic.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/mosaic.webp -------------------------------------------------------------------------------- /images/modeprops/ocpc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/ocpc.webp -------------------------------------------------------------------------------- /images/modeprops/p512.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/p512.webp -------------------------------------------------------------------------------- /images/modeprops/t512.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/t512.webp -------------------------------------------------------------------------------- /images/modeprops/window.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/modeprops/window.webp -------------------------------------------------------------------------------- /images/sfc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/sfc.webp -------------------------------------------------------------------------------- /images/sound/com.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/sound/com.webp -------------------------------------------------------------------------------- /images/sound/components.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/sound/components.webp -------------------------------------------------------------------------------- /images/sound/timer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/sound/timer.webp -------------------------------------------------------------------------------- /images/window/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/window/example1.png -------------------------------------------------------------------------------- /images/window/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akatsuki105/snes-docs-ja/0f708cddefdf0079794b6325345765b5b26da902/images/window/example2.png -------------------------------------------------------------------------------- /interrupt/README.md: -------------------------------------------------------------------------------- 1 | # 割り込み 2 | 3 | 割り込み関連のレジスタについては [こちら](ioreg.md) を参照。 4 | - [レジスタ](ioreg.md) 5 | - [割り込み、例外、ブレーク](../65xx/isa/control.md#割り込み例外ブレーク) 6 | 7 | ## 各種割り込み 8 | 9 | IRQはIフラグで無効にできますが、BRK,NMI,RESET はIフラグで無効にすることはできません。 10 | 11 | ソフトウェアまたはハードウェアは、IRQ または NMI を処理した後、アクノリッジまたはリセットを行う必要があります。 12 | 13 | ### RESET 14 | 15 | 文字通り、リセット時に起こる割り込みです。 16 | 17 | ```go 18 | REG.P[D], REG.P[E], REG.P[I] = 0, 1, 1; 19 | REG.D = 0x0000; 20 | REG.DB = 0x00; 21 | REG.PB, REG.PC = 0x00, load16(0xFFFC); 22 | ``` 23 | 24 | ### BRK 25 | 26 | `BRK`命令によって引き起こされます。ソフト開発時のデバッガ向けの割り込みです。 27 | 28 | 割り込みから復帰する時のリターン先のアドレスは、`BRK`命令の2バイト後であることに注意してください。(つまりBRK命令後の1バイトは無視される) 29 | 30 | ```go 31 | if REG.P[E] = 1 { 32 | REG.P[B] = 1; 33 | } 34 | if REG.P[E] = 0 { 35 | push8(REG.PB); 36 | } 37 | push16(REG.PC+1); // PC は BRK命令の1バイト後 38 | push8(REG.P); 39 | REG.P[D], REG.P[I] = 0, 1; 40 | REG.PB, REG.PC = 0x00, VEC_BRK; 41 | ``` 42 | 43 | ### COP 44 | 45 | `COP`命令によって引き起こされる割り込みで、現在実行中の処理を中断し、コプロセッサによるソフトウェア割込を実行するためのものです。 46 | 47 | ```go 48 | if REG.P[E] = 1 { 49 | REG.P[B] = 1; 50 | } 51 | if REG.P[E] = 0 { 52 | push8(REG.PB); 53 | } 54 | push16(REG.PC+1); // PC は COP命令の1バイト後 55 | push8(REG.P); 56 | REG.P[D], REG.P[I] = 0, 1; 57 | REG.PB, REG.PC = 0x00, VEC_COP; 58 | ``` 59 | 60 | ### ABORT 61 | 62 | ```go 63 | if REG.P[E] = 0 { 64 | push8(REG.PB); 65 | } 66 | push16(REG.PC); 67 | push8(REG.P); 68 | REG.P[I] = 1; 69 | REG.PB, REG.PC = 0x00, VEC_ABORT; 70 | ``` 71 | 72 | ### IRQ 73 | 74 | [IRQ](./irq.md) を参照してください。 75 | 76 | ### NMI 77 | 78 | NMIピンが HighからLow になると、現在実行中の命令終了後に割り込みシーケンスが開始されます。 79 | 80 | NMIはエッジ依存の入力[2](#edge)なので、前の割り込みの処理中にNMIピンが HighからLow になった場合は割り込みが再び発生します。 81 | 82 | 2: Lowであることではなく、HighからLowに切り替わることでトリガーされる 83 | 84 | ```go 85 | if REG.P[E] = 1 { 86 | REG.P[B] = 0; 87 | } 88 | if REG.P[E] = 0 { 89 | push8(REG.PB); 90 | } 91 | push16(REG.PC); 92 | push8(REG.P); 93 | REG.P[D], REG.P[I] = 0, 1; 94 | REG.PB, REG.PC = 0x00, VEC_NMI; 95 | ``` 96 | 97 | ## 例外ベクタ 98 | 99 | 例外ベクタはオフセット`FFE0h..FFFFh`に配置されています。 100 | 101 | SNESは、CPUに割り込みが発生した時に、対応する例外ベクタにジャンプします。 102 | 103 | リセット時は、6502モードで起動します。 104 | 105 | ### 65816モード(E=0) 106 | 107 | 名称 | ベクタ | ソフト/ハード | 発生条件 | 変化するレジスタ 108 | --- | ----- | ------------ | ------ | ------------- 109 | COP | 0xFFE4-0xFFE5 | ソフト | コプロセッサ割り込み | `P[I]=1, P[D]=0` 110 | BRK | 0xFFE6-0xFFE7 | ソフト | BRK命令実行時 | `P[I]=1, P[D]=0` 111 | ABORT | 0xFFE8-0xFFE9 | ハード | ハードウェア特殊信号 | `P[I]=1` 112 | NMI | 0xFFEA-0xFFEB | ハード | V-Blank割り込み | `P[I]=1` 113 | (予約) | 0xFFEC-0xFFED | ハード | -- | -- 114 | IRQ | 0xFFEE-0xFFEF | ハード/ソフト | ハードウェア信号 | `P[I]=1` 115 | 116 | ### 6502モード(E=1) 117 | 118 | 6502モードでは、BRKとIRQは同じベクタを共有しており、ソフトウェアはプッシュされたBフラグのみを調べることで、BRKとIRQを見分けることができます。 119 | 120 | 名称 | ベクタ | ソフト/ハード | 発生条件 | 変化するレジスタ 121 | --- | ----- | ------------ | ------ | ------------- 122 | COP | 0xFFF4-0xFFE5 | ソフト | コプロセッサ割り込み | `P[I]=1, P[D]=0` 123 | (予約) | 0xFFF6-0xFFE7 | ハード | -- | -- 124 | ABORT | 0xFFF8-0xFFE9 | ハード | ハードウェア特殊信号 | `P[I]=1` 125 | NMI | 0xFFFA-0xFFEB | ハード | V-Blank割り込み | `P[I]=1` 126 | RESET | 0xFFFC-0xFFED | ハード | 電源投入時、リセット時 | `P[I]=1, P[D]=0` 127 | IRQ/BRK | 0xFFFE-0xFFEF | ハード/ソフト | ハードウェア信号/BRK命令 | `P[I]=1, P[D]=0` 128 | -------------------------------------------------------------------------------- /interrupt/ioreg.md: -------------------------------------------------------------------------------- 1 | # 割り込み関連のレジスタ 2 | 3 | ## 4200h - NMITIMEN - 割り込み有効化レジスタ (W) 4 | 5 | ``` 6 | Bit 0 自動Joypad読み出し有効化フラグ (0=無効, 1=有効) 7 | Bit 1-3 不使用 8 | Bit 4-5 IRQフラグ 9 | 0: 無効 10 | 1: HIRQ (H, V) = (HTIME, any) 11 | 2: VIRQ (H, V) = (0, VTIME) 12 | 3: HVIRQ (H, V) = (HTIME, VTIME) 13 | Bit 6 不使用 14 | Bit 7 VBlank NMI 有効化フラグ (0=無効, 1=有効) 15 | NMI = マスク不可割り込み 16 | リセット時は0 17 | ``` 18 | 19 | bit4-5を0にしてIRQを無効にすると、IRQが追加でアクノリッジされます。bit7でNMIを無効にした場合は、そのような効果はありません。 20 | 21 | ## 4210h - RDNMI - NMIフラグ (R) 22 | 23 | ``` 24 | Bit 0-3 CPU 5A22のバージョン (version 2 exists) 25 | Bit 4-6 不使用 26 | Bit 7 NMIフラグ (0=None, 1=Interrupt Request) (VBlank開始時にセットされる) 27 | ``` 28 | 29 | NMIフラグ(bit7)は、VBlank開始時にセットされます。(NMITIMEN.7 で NMIが無効になっている場合でもNMIフラグはセットされます) 30 | 31 | NMIフラグは VBlank終了時に自動的にクリアされます。またこのレジスタ(RDNMI)を読み出した後にもクリアされます。 32 | 33 | SNES の NMI は VBlank でしか発生せず、さらに NMIフラグはVBlankの終わりに自動的にクリアされるので、基本的にはこのフラグは必要ありません。 34 | 35 | しかし、NMITIMEN.7 を `0` にして NMI を無効化し、また有効化する(`1`にする)と古いNMIが再び実行されてしまいます。このレジスタにアクノリッジ信号を送ればこれを防ぐことができます。 36 | 37 | CPUは内部NMIフラグを RDNMI.7 とは別に持っていて、`NMITIMEN.7 & RDNMI.7` が 0 から 1 に変わった時にこの内部NMIフラグがセットされます。この内部フラグはNMIが実行されるとクリアされます。 38 | 39 | ## 4212h - HVBJOY - H/VBlankフラグ & 自動Joypadビジーフラグ (R) 40 | 41 | ``` 42 | Bit 0 自動Joypad読み出し処理中か (1=Busy) (see 4200h, and 4218h..421Fh) 43 | Bit 1-5 不使用 44 | Bit 6 HBlankフラグ (1=HBlank中) 45 | Bit 7 VBlankフラグ (1=VBlank中) 46 | ``` 47 | 48 | HBlankフラグはVBlank/VSync中でもトグルします。 49 | 50 | HBlankフラグとVBlankフラグは(FBlank中でも、IRQやNMIが有効であっても)常にトグルします。 51 | -------------------------------------------------------------------------------- /interrupt/irq.md: -------------------------------------------------------------------------------- 1 | # IRQ 2 | 3 | スーファミの IRQ は PPU によってのみリクエストされます。 4 | 5 | IRQ は PPU が特定の場所を描画した瞬間にリクエストされます。 6 | 7 | X座標が満たされた時の HIRQ、 Y座標が満たされた時の VIRQ 、XY両方の座標が満たされたときの HVIRQ の3種類のIRQがあります。 8 | 9 | ## IRQの無効化 10 | 11 | CPUのIフラグをセットすることでIRQを無効化できます。 12 | 13 | また、`NMITIMEN.4-5` を 0 にすることでもIRQを無効化できます。 14 | 15 | ## IRQフラグ 16 | 17 | IRQがリクエストされると `TIMEUP.7`(0x4211) がセットされます。 18 | 19 | ``` 20 | TIMEUP(R): 21 | Bit 0-6 不使用 22 | Bit 7 IRQフラグ (0=通常, 1=リクエスト発生) 23 | ``` 24 | 25 | IRQフラグ(bit7)は、このレジスタから読み出した後、自動的にクリアされます。ただしIRQ条件が真であるまさにその時(4-8マスターサイクルの間続く)に読み出した場合はCPUは`bit7=1`を受け取りますが、bit7はクリアされません。 26 | 27 | IRQフラグ(bit7)は、`NMITIMEN.4-5`を 0 にしてIRQを無効にするときにも自動的にクリアされます。 28 | 29 | エッジ依存のNMIハンドラと違って、レベル依存のIRQハンドラはIRQを必ずアクノリッジしなければいけません。さもないと、RTIの直後に割り込みが再びリクエストされます。([詳細](README.md)) 30 | 31 | ## HIRQ 32 | 33 | HIRQは水平方向の描画座標(Hカウンタ)が、`HTIME`(0x4207,4208)で設定したX座標に到達した際にリクエスト(TIMEUP.7をセット)されます。`(x, y) = (HTIME, any)` 34 | 35 | ただし、`NMITIMEN.4-5` を 1 にしておく必要があります。 36 | 37 | ``` 38 | HTIME(W): 39 | Bit 0-8 HIRQ座標 (0..339) (+/-1 in long/short lines) (0=左端) 40 | Bit 9-15 不使用 41 | ``` 42 | 43 | ## VIRQ 44 | 45 | VIRQは垂直方向の描画座標(Vカウンタ)が、`VTIME`(0x4209,420A)で設定したY座標に到達した際にリクエスト(TIMEUP.7をセット)されます。`(x, y) = (0, VTIME)` 46 | 47 | ただし、`NMITIMEN.4-5` を 2 にしておく必要があります。 48 | 49 | ``` 50 | VTIME(W): 51 | Bit 0-8 VIRQ座標 (0..261) (+1 in interlace) (0=上端) 52 | Bit 9-15 不使用 53 | ``` 54 | 55 | ## HVIRQ 56 | 57 | HVIRQ は 描画座標が `(x, y) = (HTIME, VTIME)` となったときにリクエスト(TIMEUP.7をセット)されます。 58 | 59 | ただし、`NMITIMEN.4-5` を 3 にしておく必要があります。 60 | 61 | ## IRQシーケンス 62 | 63 | IRQピンがLowになると割り込みシーケンスの開始が要求されます。 64 | 65 | IRQが無効化されていないなら、現在実行中の命令終了後に割り込みを認識して、割り込みシーケンスが開始されます。 66 | 67 | IRQはレベル依存の入力[1](#level)なので、前回の割り込み以降、割り込みソースがクリアされていない場合は割り込みが発生します。また、割り込み認識前に割り込みソースをクリアした場合は、割り込みは発生しません。 68 | 69 | IRQが無視されず認識されたとき、以下の処理が行われます。 70 | 71 | ```go 72 | if REG.P[E] = 1 { 73 | REG.P[B] = 0; 74 | } 75 | if REG.P[E] = 0 { 76 | push8(REG.PB); 77 | } 78 | push16(REG.PC); 79 | push8(REG.P); 80 | REG.P[D], REG.P[I] = 0, 1; 81 | REG.PB, REG.PC = 0x00, VEC_IRQ; // VEC_IRQ: WORD[0xFFEE] or WORD[0xFFFE] 82 | ``` 83 | 84 | 1: HighからLowの切り替わりでなくLowであることでトリガーされる 85 | -------------------------------------------------------------------------------- /ioreg.md: -------------------------------------------------------------------------------- 1 | # I/Oレジスタ 一覧 2 | 3 | > **Note** 4 | > 右の列はリセット時の初期値を示します。 5 | > 括弧付きの値はリセット時にはセットされませんが、最初の電源投入時にはセットされます。 6 | 7 | >**Note** 8 | > WO: 書き込み専用, RO: 読み取り専用, RW: 読み書きOK 9 | 10 | ## PPU 11 | 12 | ``` 13 | 2100h WO - INIDISP - ディスプレイ制御レジスタ1 8xh 14 | 2101h WO - OBSEL - Object Size and Object Base (?) 15 | 2102h WO - OAMADDL - OAMアドレス (下位8bit) (?) 16 | 2103h WO - OAMADDH - OAMアドレス (上位1bit) (?) 17 | 2104h WO - OAMDATA - OAM書き込み (?) 18 | 2105h WO - BGMODE - BG制御レジスタ (xFh) 19 | 2106h WO - MOSAIC - モザイク (?) 20 | 2107h WO - BG1SC - BG1画面設定 (?) 21 | 2108h WO - BG2SC - BG2画面設定 (?) 22 | 2109h WO - BG3SC - BG3画面設定 (?) 23 | 210Ah WO - BG4SC - BG4画面設定 (?) 24 | 210Bh WO - BG12NBA - BG1,2タイルデータアドレス (?) 25 | 210Ch WO - BG34NBA - BG3,4タイルデータアドレス (?) 26 | 210Dh WO - BG1HOFS - BG1Xスクロール / M7HOFS (?,?) 27 | 210Eh WO - BG1VOFS - BG1Yスクロール / M7VOFS (?,?) 28 | 210Fh WO - BG2HOFS - BG2Xスクロール (?,?) 29 | 2110h WO - BG2VOFS - BG2Yスクロール (?,?) 30 | 2111h WO - BG3HOFS - BG3Xスクロール (?,?) 31 | 2112h WO - BG3VOFS - BG3Yスクロール (?,?) 32 | 2113h WO - BG4HOFS - BG4Xスクロール (?,?) 33 | 2114h WO - BG4VOFS - BG4Yスクロール (?,?) 34 | 2115h WO - VMAIN - VRAMアドレス増加レジスタ (?Fh) 35 | 2116h WO - VMADDL - VRAMアドレス (下位8bit) (?) 36 | 2117h WO - VMADDH - VRAMアドレス (上位8bit) (?) 37 | 2118h WO - VMDATAL - VRAMデータ書き込み (下位8bit) (?) 38 | 2119h WO - VMDATAH - VRAMデータ書き込み (上位8bit) (?) 39 | 211Ah WO - M7SEL - Rotation/Scaling Mode Settings (?) 40 | 211Bh WO - M7A - 伸縮回転パラメータA & PPU被乗数レジスタ(FFh)(w2) 41 | 211Ch WO - M7B - 伸縮回転パラメータB & PPU乗数レジスタ (FFh)(w2) 42 | 211Dh WO - M7C - 伸縮回転パラメータC (?) 43 | 211Eh WO - M7D - 伸縮回転パラメータD (?) 44 | 211Fh WO - M7X - 伸縮回転中心X座標 (?) 45 | 2120h WO - M7Y - 伸縮回転中心Y座標 (?) 46 | 2121h WO - CGADD - パレットアドレス (?) 47 | 2122h WO - CGDATA - パレット書き込み (?) 48 | 2123h WO - W12SEL - Window BG1/BG2 Mask Settings (?) 49 | 2124h WO - W34SEL - Window BG3/BG4 Mask Settings (?) 50 | 2125h WO - WOBJSEL - Window OBJ/MATH Mask Settings (?) 51 | 2126h WO - WH0 - Window座標1L (?) 52 | 2127h WO - WH1 - Window座標1R (?) 53 | 2128h WO - WH2 - Window座標2L (?) 54 | 2129h WO - WH3 - Window座標2R (?) 55 | 212Ah WO - WBGLOG - Window 1/2 Mask Logic (BG1-BG4) (?) 56 | 212Bh WO - WOBJLOG - Window 1/2 Mask Logic (OBJ/MATH) (?) 57 | 212Ch WO - TM - メイン画面レイヤ制御 (?) 58 | 212Dh WO - TS - サブ画面レイヤ制御 (?) 59 | 212Eh WO - TMW - Window Area Main Screen Disable (?) 60 | 212Fh WO - TSW - Window Area Sub Screen Disable (?) 61 | 2130h WO - CGWSEL - ColorMath制御レジスタA (?) 62 | 2131h WO - CGADSUB - ColorMath制御レジスタB (?) 63 | 2132h WO - COLDATA - Color Math Sub Screen Backdrop Color (?) 64 | 2133h WO - SETINI - ディスプレイ制御レジスタ2 00h? 65 | 2134h RO - MPYL - PPU積レジスタ (下位8bit) (01h) 66 | 2135h RO - MPYM - PPU積レジスタ (中位8bit) (00h) 67 | 2136h RO - MPYH - PPU積レジスタ (上位8bit) (00h) 68 | 2137h RO - SLHV - H/Vカウンタラッチ 69 | 2138h RO - RDOAM - OAM読み込み 70 | 2139h RO - RDVRAML - VRAMデータ読み込み (下位8bit) 71 | 213Ah RO - RDVRAMH - VRAMデータ読み込み (上位8bit) 72 | 213Bh RO - RDCGRAM - パレット読み込み 73 | 213Ch RO - OPHCT - Hカウンタ (01FFh) 74 | 213Dh RO - OPVCT - Vカウンタ (01FFh) 75 | 213Eh RO - STAT77 - PPU1ステータス 76 | 213Fh RO - STAT78 - PPU2ステータス Bit7=0 77 | ``` 78 | 79 | ## APU 80 | 81 | ``` 82 | 2140h RW - APUI00 - Main CPU to Sound CPU Communication Port 0 (00h/00h) 83 | 2141h RW - APUI01 - Main CPU to Sound CPU Communication Port 1 (00h/00h) 84 | 2142h RW - APUI02 - Main CPU to Sound CPU Communication Port 2 (00h/00h) 85 | 2143h RW - APUI03 - Main CPU to Sound CPU Communication Port 3 (00h/00h) 86 | 2144h..217Fh - APU Ports 2140-2143h mirrored to 2144h..217Fh 87 | ``` 88 | 89 | ## WRAM 90 | 91 | ``` 92 | 2180h RW - WMDATA - WRAMデータレジスタ 93 | 2181h WO - WMADDL - WRAMアドレスレジスタ (下位8bit) (W) 00h 94 | 2182h WO - WMADDM - WRAMアドレスレジスタ (中位8bit) (W) 00h 95 | 2183h WO - WMADDH - WRAMアドレスレジスタ (上位1bit) (W) 00h 96 | 2184h..21FFh - 不使用(Open Bus) / Expansion (B-Bus) - 97 | 2200h..3FFFh - 不使用(Open Bus) / Expansion (A-Bus) - 98 | ``` 99 | 100 | ## CPU 101 | 102 | **低速(1.78MHz)** 103 | 104 | ``` 105 | 4000h..4015h - 不使用(Open Bus) - 106 | 4016h WO - JOYWR - Joypad出力 00h 107 | 4016h RO - JOYA - Joypad入力A - 108 | 4017h RO - JOYB - Joypad入力B - 109 | 4018h..41FFh - 不使用(Open Bus) - 110 | ``` 111 | 112 | **高速(3.58MHz)** 113 | 114 | ``` 115 | 4200h WO - NMITIMEN- 割り込み有効化レジスタ 00h 116 | 4201h WO - WRIO - Joypad Programmable I/O Port (Open-Collector Output) FFh 117 | 4202h WO - WRMPYA - 被乗数レジスタ (FFh) 118 | 4203h WO - WRMPYB - 乗数レジスタ (FFh) 119 | 4204h WO - WRDIVL - 被除数レジスタ (下位8bit) (FFh) 120 | 4205h WO - WRDIVH - 被除数レジスタ (上位8bit) (FFh) 121 | 4206h WO - WRDIVB - 除数レジスタ (FFh) 122 | 4207h WO - HTIMEL - HIRQ座標 (下位8bits) (FFh) 123 | 4208h WO - HTIMEH - HIRQ座標 (上位1bit) (01h) 124 | 4209h WO - VTIMEL - VIRQ座標 (下位8bits) (FFh) 125 | 420Ah WO - VTIMEH - VIRQ座標 (上位1bit) (01h) 126 | 420Bh WO - MDMAEN - GDMAチャネルレジスタ 0 127 | 420Ch WO - HDMAEN - HDMAチャネルレジスタ 0 128 | 420Dh WO - MEMSEL - WS2制御レジスタ 0 129 | 420Eh..420Fh - 不使用(Open Bus) - 130 | 4210h RO - RDNMI - NMIフラグ (Read/Ack) 0xh 131 | 4211h RO - TIMEUP - H/VタイマーIRQフラグ 00h 132 | 4212h RO - HVBJOY - H/VBlankフラグ & 自動Joypadビジーフラグ (R) (?) 133 | 4213h RO - RDIO - Joypad Programmable I/O Port (Input) - 134 | 4214h RO - RDDIVL - 商レジスタ (下位8bit) (0) 135 | 4215h RO - RDDIVH - 商レジスタ (上位8bit) (0) 136 | 4216h RO - RDMPYL - 積/余りレジスタ (下位8bit) 137 | 4217h RO - RDMPYH - 積/余りレジスタ (上位8bit) 138 | 4218h RO - JOY1L - Joypad1レジスタ (下位8bit) 00h 139 | 4219h RO - JOY1H - Joypad1レジスタ (上位8bit) 00h 140 | 421Ah RO - JOY2L - Joypad2レジスタ (下位8bit) 00h 141 | 421Bh RO - JOY2H - Joypad2レジスタ (上位8bit) 00h 142 | 421Ch RO - JOY3L - Joypad3レジスタ (下位8bit) 00h 143 | 421Dh RO - JOY3H - Joypad3レジスタ (上位8bit) 00h 144 | 421Eh RO - JOY4L - Joypad4レジスタ (下位8bit) 00h 145 | 421Fh RO - JOY4H - Joypad4レジスタ (上位8bit) 00h 146 | 4220h..42FFh - 不使用(Open Bus) - 147 | ``` 148 | 149 | ## DMA 150 | 151 | x = DMAチャンネル番号(0..7) 152 | 153 | ``` 154 | (additional DMA control registers are 420Bh and 420Ch, see above) 155 | 43x0h RW - DMAPx - DMA設定レジスタ (FFh) 156 | 43x1h RW - BBADx - DBバスアドレス (FFh) 157 | 43x2h RW - A1TxL - Aバスアドレス (low) (FFh) 158 | 43x3h RW - A1TxH - Aバスアドレス (high)(FFh) 159 | 43x4h RW - A1Bx - Aバスアドレス (bank)(xxh) 160 | 43x5h RW - DASxL - Indirect HDMA Address (low) / DMA Byte-Counter (low) (FFh) 161 | 43x6h RW - DASxH - Indirect HDMA Address (high) / DMA Byte-Counter (high)(FFh) 162 | 43x7h RW - DASBx - Indirect HDMA Address (bank) (FFh) 163 | 43x8h RW - A2AxL - HDMA Table Current Address (low) (FFh) 164 | 43x9h RW - A2AxH - HDMA Table Current Address (high) (FFh) 165 | 43xAh RW - NTRLx - HDMA Line-Counter (from current Table entry) (FFh) 166 | 43xBh RW - UNUSEDx - 不使用 (FFh) 167 | 43xCh+ - 不使用(Open Bus) - 168 | 43xFh RW - MIRRx - 43xBhのミラー (R/W) (FFh) 169 | 4380h..5FFFh - 不使用(Open Bus) - 170 | ``` -------------------------------------------------------------------------------- /keypad/joypad.md: -------------------------------------------------------------------------------- 1 | # [キー入力](https://problemkaputt.de/fullsnes.htm#snescontrollersioportsautomaticreading) 2 | 3 | このレジスタは、[NMITIMEN.0](../interrupt/ioreg.md) で自動Joypad読み出し(`Auto Joypad Read`)を有効にした場合に有効です。 4 | 5 | ## 421xh - JOYnL/JOYnH - Joypad n レジスタ (R) 6 | 7 | ``` 8 | 4218h/4219h - JOY1L/JOY1H - Joypad 1 (gameport 1, pin 4) (R) 9 | 421Ah/421Bh - JOY2L/JOY2H - Joypad 2 (gameport 2, pin 4) (R) 10 | 421Ch/421Dh - JOY3L/JOY3H - Joypad 3 (gameport 1, pin 5) (R) 11 | 421Eh/421Fh - JOY4L/JOY4H - Joypad 4 (gameport 2, pin 5) (R) 12 | ``` 13 | 14 | ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 15 | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- 16 | ボタン | B | Y | SELECT | START | ↑ | ↓ | ← | → | A | X | L | R | 0 | 0 | 0 | 0 17 | 18 | ボタンが押されているときに`1`になります。 19 | 20 | シリアル転送の順番は`Bit15 -> Bit0`の順です。 21 | 22 | Before reading above ports, set Bit 0 in port 4200h to request automatic reading, then wait until Bit 0 of port 4212h gets set-or-cleared? Once 4200h enabled, seems to be automatically read on every retrace? 23 | 24 | Be sure that Out0 in Port 4016h is zero (otherwise the shift register gets stuck on the first bit, ie. all 16bit will be equal to the B-button state. 25 | 26 | ``` 27 | AUTO JOYPAD READ 28 | ---------------- 29 | この機能を有効にすると、4つのコントローラポートデータラインのそれぞれから16bitをレジスタ$4218-fに読み込みます。 30 | これは最初のVBlankスキャンラインのH=32.5とH=95.5の間で始まり、4224マスターサイクル後に終了します。 31 | この間,レジスタ$4212のbit0がセットされます。具体的には,1フレーム目のH=74.5から始まり,観測範囲に入る前回の読み出し開始後,256サイクルの倍数で終了します。 32 | When enabled, the SNES will read 16 bits from each of the 4 controller port 33 | data lines into registers $4218-f. This begins between H=32.5 and H=95.5 of 34 | the first V-Blank scanline, and ends 4224 master cycles later. Register $4212 35 | bit 0 is set during this time. Specifically, it begins at H=74.5 on the first 36 | frame, and thereafter some multiple of 256 cycles after the start of the 37 | previous read that falls within the observed range. 38 | 39 | Reading $4218-f during this time will read back incorrect values. The only 40 | reliable value is that no buttons pressed will return 0 (however, if buttons 41 | are pressed 0 could still be returned incorrectly). Presumably reading $4016/7 42 | or writing $4016 during this time will also screw things up. 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /keypad/signal.md: -------------------------------------------------------------------------------- 1 | # [キー入力](https://problemkaputt.de/fullsnes.htm#snescontrollersioportsautomaticreading) 2 | 3 | コントローラーデバイスからの信号単位の入出力です。 4 | 5 | ## 4016h - JOYWR/JOYA - Joypad出力/入力A (R/W) 6 | 7 | Read と Write で用途が変わります。 8 | 9 | ``` 10 | Read: JOYA(Joypad入力A) 11 | Bit 0 CPU の Pin 32 からの入力, connected to gameport 1, pin 4 (JOY1) (1=Low) 12 | Bit 1 CPU の Pin 33 からの入力, connected to gameport 1, pin 5 (JOY3) (1=Low) 13 | Bit 2-7 不使用 14 | 15 | このレジスタ(JOYA)を読み出すと自動的にCPUの35番ピンがクロックパルスを発生し、ゲームポート1の2番ピンと接続されます。 16 | 17 | Write: JOYWR(Joypad出力) 18 | Bit 0 OUT0, CPU の Pin 37 へ出力される (Joypad Strobe) (both gameports, pin 3) 19 | Bit 1 OUT1, CPU の Pin 38 へ出力される (実際はされない) (1=High) 20 | Bit 2 OUT2, CPU の Pin 39 へ出力される (実際はされない) (1=High) 21 | Bit 3-7 不使用 22 | 23 | Out0-2 は 仕様上は CPU の Pins 37-39 に接続されているはずですが、実際には Out0 しか繋がってないようです 24 | ``` 25 | 26 | ## 4017h - JOYB - Joypad入力B (R) 27 | 28 | ``` 29 | Bit 0 Input on CPU Pin 27, connected to gameport 2, pin 4 (JOY2) (1=Low) 30 | Bit 1 Input on CPU Pin 28, connected to gameport 2, pin 5 (JOY4) (1=Low) 31 | Bit 2 Input on CPU Pin 29, connected to GND (always 1=LOW) (1=Low) 32 | Bit 3 Input on CPU Pin 30, connected to GND (always 1=LOW) (1=Low) 33 | Bit 4 Input on CPU Pin 31, connected to GND (always 1=LOW) (1=Low) 34 | Bit 5-7 不使用 35 | ``` 36 | 37 | Reading from this register automatically generates a clock pulse on CPU Pin 36, which is connected to gameport 2, pin 2. 38 | 39 | ## 4201h - WRIO - Joypad Programmable I/O Port (Open-Collector Output) (W) 40 | 41 | ``` 42 | Bit 0-7 I/O PORT (0=Output Low, 1=HighZ/Input) 43 | Bit 0-5 Not connected (except, used by SFC-Box; see Hotel Boxes) 44 | Bit 6 Joypad 1 Pin 6 45 | Bit 7 Joypad 2 Pin 6 / PPU Lightgun input (should be usually always 1=Input) 46 | ``` 47 | 48 | Note: Due to the weak high-level, the raising "edge" is raising rather slowly, for sharper transitions one may need external pull-up resistors. 49 | 50 | ## 4213h - RDIO - Joypad Programmable I/O Port (Input) (R) 51 | 52 | ``` 53 | Bit 0-7 I/O PORT (0=Low, 1=High) 54 | ``` 55 | 56 | When used as Input via 4213h, set the corresponding bits in 4201h to HighZ. 57 | 58 | I/O Signals 0..7 are found on CPU Pins 19..26 (in that order). IO-6 connects to Pin 6 of Controller 1. IO-7 connects to Pin 6 of Controller 2, this pin is also shared for the light pen strobe. 59 | 60 | Wires are connected to IO-0..5, but the wires disappear somewhere in the multi-layer board (and might be dead-ends), none of them is output to any connectors (not to the Controller ports, not to the cartridge slot, and not to the EXT port). 61 | -------------------------------------------------------------------------------- /memory/README.md: -------------------------------------------------------------------------------- 1 | # 🗺 メモリマップ 2 | 3 | SNESは24bit幅(`000000h-FFFFFFh`)のアドレスバスを持っています。 4 | 5 | この24bitのアドレスは、8bitのバンク番号(`00h-FFh`)と16bitのオフセット(`0000h-FFFFh`)によく分けて説明されることが多く、このドキュメントでもそのように説明していきます。 6 | 7 | ## メモリマップ全体 8 | 9 | ``` 10 | 0x00..3F 0x40..7D 0x7E..7F 0x80..BF 0xC0..FF 11 | 0x0000 ┌─────────────────────┬────────────────────┬────────────┬───────────────────┬─────────────────┐ 12 | │ │ │ │ │ │ 13 | │ │ │ │ │ │ 14 | │ │ │ │ │ │ 15 | │ │ │ │ │ │ 16 | │ │ │ │ │ │ 17 | │ System │ │ │ System │ │ 18 | │ │ │ │ │ │ 19 | │ │ │ │ │ │ 20 | │ │ │ │ │ │ 21 | │ │ │ │ │ │ 22 | │ │ WS1 HiROM │ WRAM │ │ WS2 HiROM │ 23 | 0x8000 ├─────────────────────┤ │ ├───────────────────┤ │ 24 | │ │ │ │ │ │ 25 | │ │ │ │ │ │ 26 | │ │ │ │ │ │ 27 | │ WS1 LoROM │ │ │ WS2 LoROM │ │ 28 | │ │ │ │ │ │ 29 | │ │ │ │ │ │ 30 | │ │ │ │ │ │ 31 | │ │ │ │ │ │ 32 | └─────────────────────┴────────────────────┴────────────┴───────────────────┴─────────────────┘ 33 | ``` 34 | 35 | バンク | オフセット | 内容 | 動作速度 | サイズ | その他 36 | -- | -- | -- | -- | -- | -- 37 | 00h-3Fh | 0000h-7FFFh | システム領域 | 後述 | 後述 | -- 38 | 00h-3Fh | 8000h-FFFFh | WS1 LoROM | 2.68MHz | 2048KB(64x32KB) | -- 39 | 00h | FFE0h-FFFFh | 例外ベクタ | 2.68MHz | -- | -- 40 | 40h-7Dh | 0000h-FFFFh | WS1 HiROM | 2.68MHz | 3968KB(62x64KB) | -- 41 | 7Eh-7Fh | 0000h-FFFFh | WRAM | 2.68MHz | 128KB(2x64KB) | -- 42 | 80h-BFh | 0000h-7FFFh | システム領域 (8K WRAM, I/O Ports, Expansion) | 後述 | -- | バンク00-3Fhのミラー 43 | 80h-BFh | 8000h-FFFFh | WS2 LoROM | max 3.58MHz | 2048KB(64x32KB) | バンク00-3Fhのミラー 44 | C0h-FFh | 0000h-FFFFh | WS2 HiROM | max 3.58MHz | 4096KB(64x64KB) | バンク40-7Fhのミラー(?) 45 | 46 | 基本的に、バンク`80h-FFh`はバンク`00h-7Fh`のミラーです。(WRAM部分もミラーかは不明) 47 | 48 | 内部メモリ領域は、WRAMとメモリマップドI/Oポートです。 49 | 50 | 外部メモリ領域には、LoROM、HiROM、Expansion の各領域があります。 51 | 52 | CPUのアドレス空間にマッピングされていない、I/Oを通してアクセス可能な、追加メモリ領域は以下の通りです。 53 | 54 | ``` 55 | OAM (512+32 B) (256+16 words) 56 | VRAM (64 KB) (32 Kwords) 57 | Palette (512 B) (256 words) 58 | Sound RAM (64 KB) 59 | Sound ROM (64 B BIOS Boot ROM) 60 | ``` 61 | 62 | ## システム領域(バンク: 00-3Fh, 80-BFh) 63 | 64 | `0x00xxxx..3Fxxxx`部分です。(`xxxx=0000..7FFFh`) 65 | 66 | `0x80xxxx..BFxxxx`は`0x00xxxx..3Fxxxx`のミラーです。 67 | 68 | オフセット | 内容 | 動作速度 69 | -- | -- | -- 70 | 0000h-1FFFh | 7E0000h-7E1FFFh(WRAMの先頭8KB)のミラー | 2.68MHz 71 | 2000h-20FFh | 不使用 | 3.58MHz 72 | 2100h-21FFh | I/Oポート (B-Bus) | 3.58MHz 73 | 2200h-3FFFh | 不使用 | 3.58MHz 74 | 4000h-41FFh | I/Oポート (manual joypad access) | 1.78MHz 75 | 4200h-5FFFh | I/Oポート | 3.58MHz 76 | 6000h-7FFFh | Expansion | 2.68MHz 77 | 78 | ## カートリッジ容量 79 | 80 | 24bitのアドレスバスなので理論上は16MBのアドレスが可能ですが、かなりの部分がWRAMやI/Oのミラー領域で占められており、WS1/WS2のLoROM/HiROM領域のカートリッジROMは約11.9MBしか残っていません。 81 | 82 | ほとんどのカートリッジで、WS1とWS2はミラーの関係です。さらに、ほとんどのゲームは LoROM か HiROM の どちらかのみを使用するため、以下のような容量になります。 83 | 84 | ``` 85 | LoROMゲーム: 86 | 最大 2MB ROM 87 | banks 00h-3Fh, with mirror at 80h-BFh 88 | 0x8000(Bytes) x 64(Banks) = 2MB 89 | 90 | HiROMゲーム: 91 | 最大 4MB ROM 92 | banks 40h-7Dh, with mirror at C0h-FFh 93 | 0x10000(Bytes) x 64(Banks) = 4MB 94 | ``` 95 | 96 | カートリッジ容量の限界を克服する方法はいくつかあります。 97 | 98 | LoROMゲームの中には、追加の "LoROM"バンクをHiROMエリアにマッピングするもの(`BigLoROM`)やWS2エリアにマッピングするもの(`SpecialLoROM`)があります。 99 | 100 | HiROMゲームの中には、HiROMの追加バンクをWS2領域にマッピングするものがあります(`ExHiROM`)。 101 | 102 | また、SA-1、S-DD1、SPC7110、X-in-1などのマルチカートでは、バンク切り替えを採用しているカートリッジがあります。 103 | 104 | ## 32KB LoROM (システム領域を同一バンクに持つ32KBのROMバンク) 105 | 106 | ROMは非連続の32KBブロックに分割されています。 107 | 108 | CPUのDB、PBレジスタの設定を変更することなく、ROMやシステム領域(I/OポートやWRAM)にアクセスできるというメリットがあります。 109 | 110 | ## HiROM (64KBのROMバンク) 111 | 112 | HiROMマッピングは、連続したROMアドレスを提供しますが、ROMバンク内のI/OやWRAM領域は含まれません。 113 | 114 | HiROMバンク(64KB)の上半分は、通常、対応するLoROMバンク(32KB)とミラーリングされています。これは、`40FFE0h-40FFFFh`から`00FFE0h-00FFFFh`への割り込みベクタおよびリセットベクタのマッピングに重要です。 115 | 116 | HiROMのLoROMバンク領域へのミラーの例: 117 | 118 | ``` 119 | 0x00FFE0: 0x40FFE0 のミラー 120 | 0x3D8000: 0x7D8000 のミラー 121 | ``` 122 | 123 | ## SRAM 124 | 125 | 電池式のSRAMは、多くのゲームでセーブデータの保存に使用されています。 126 | 127 | SRAMのサイズは通常 2KB、8KB、32KB のどれかです。ゲームでは32KB以上使っているものも一部あります。 128 | 129 | SRAMのアドレスマッピングには、LoROMとHiROMの2つの基本方式があります。 130 | 131 | ``` 132 | HiROM: 133 | SRAM: 30h-3Fh,B0h-BFh:6000h-7FFFh ; バンク1つ当たり8KB 134 | 135 | LoROM: 136 | SRAM: 70h-7Dh,F0h-FFh:0000h-7FFFh ; バンク1つ当たり32KB 137 | ``` 138 | 139 | SRAMは通常、WS1とWS2の両エリアにもミラーリングされます。 140 | 141 | バンク`30h-3Fh`のSRAMは、しばしば`20h-2Fh`(場合によっては`10h-1Fh`)にもミラーリングされます。 142 | 143 | バンク`70h-7Dh`のSRAMは、`70h-71h`または`70h-77h`にcrippleされたり、`60h-7Dh`に拡張されたり、また、オフセット`8000h-FFFFh`にミラーリングされることもあります。 144 | 145 | ## AバスとBバス 146 | 147 | スーファミはAバスとBバスという、2種類のアドレスバス[1](#addrbus)を持っています。 148 | 149 | Aバスは24bit幅で任意のアドレスにアクセス可能です。CPUバス、CPU空間とも呼ばれます。 150 | 151 | Bバスは8bit幅で、アドレス空間`2100h..21FFh`にアクセス可能です。PPUバス、PPU空間とも呼ばれます。 152 | 153 | 2つのアドレスバスは同じデータバス[2](#databus)を共有していますが、それぞれのバスは独自のリード/ライト信号を持っています。 154 | 155 | DMAコントローラは、AバスとBバスの両方に同時にアクセスすることができます。DMA転送のソースアドレスとデスティネーションアドレスを同時に2つのアドレスバスに出力することができるので、これまでのように`Read-and-Write`ではなく、`Read-then-Write`を1つのステップで行うことができます。 156 | 157 | ## バンク切り替え 158 | 159 | ほとんどのスーファミゲームは、24bitのアドレス空間で満足しています。バンク切り替えは、特殊なチップを搭載した一部のゲームでのみ使用されています。 160 | 161 | ``` 162 | S-DD1, SA-1, and SPC7110 chips (with mappable 1MByte-banks) 163 | Satellaview FLASH carts (can enable/disable ROM, PSRAM, FLASH) 164 | Nintendo Power FLASH carts (can map FLASH and SRAM to desired address) 165 | Pirate X-in-1 multicart mappers (mappable offset in 256Kbyte units) 166 | Cheat devices (and X-Band modem) can map their BIOS and can patch ROM bytes 167 | Copiers can map internal BIOS/DRAM/SRAM and external Cartridge memory 168 | Hotel Boxes (eg. SFC-Box) can map multiple games/cartridges 169 | ``` 170 | 171 | また、APU側では、64BのブートROMを有効/無効にすることができます。 172 | 173 | 1: ROMチップなどからデータを読み取る際に対象のアドレスを伝達するためのバス 174 | 175 | 2: アドレスバスで指定したアドレスから読み取ったデータを伝達させるためのバス 176 | -------------------------------------------------------------------------------- /memory/dma/README.md: -------------------------------------------------------------------------------- 1 | # DMA転送 2 | 3 | DMA転送は Direct Memory Access転送 の略で、CPUを介さずに周辺機器やメモリ間で直接データ転送を行う転送方式です。 4 | 5 | スーファミのDMAは、Aバスの指すアドレス(任意のアドレス)とBバスの指すアドレス(`0x21xx`)間でデータを転送します。([Aバス、Bバスについて](README.md#aバスとbバス)) 6 | 7 | 通常のDMA転送は、HDMAと違いどんな用途でも利用可能なので GDMA(General DMA) と呼ばれることも多いです。 8 | 9 | >**Note** 以後、通常のDMAはGDMAと呼び、DMAと呼ぶときはGDMAとHDMAの両方を指します。 10 | 11 | [HDMA(HBlank DMA)](hdma.md) は 各スキャンラインの HBlank でちょっとしたデータ転送を行い、PPUレジスタを書き換えて画面効果を実現するためのDMAです。 12 | 13 | スーファミには、8つのDMAチャネルがあり、GDMA と HDMA で共有しています。優先度は 0が最高、7が最低 となっています。HDMA は GDMA よりも優先度が高いです。優先度の低いDMAチャネルは、優先度の高いチャネルが完了するまで一時停止されます。 14 | 15 | ## 転送速度 16 | 17 | ``` 18 | CPU: 336~413 KB/s 19 | DMA: 2680 KB/s 20 | ``` 21 | 22 | このようにDMA転送はCPUと比べて非常に高速なため、VBlank中 に急いでグラフィックデータのようなサイズの大きいデータ転送を行いたいときによく使われています。 23 | 24 | ## 参考 25 | 26 | - [DMA & HDMA - Super Nintendo Entertainment System Features Pt. 07](https://youtu.be/K7gWmdgXPgk) 27 | - [SNES on FPGA](https://pgate1.at-ninja.jp/SNES_on_FPGA/): HDMAの説明部分 28 | - [Grog's Guide to DMA and HDMA on the SNES](https://wiki.superfamicom.org/grog's-guide-to-dma-and-hdma-on-the-snes) 29 | -------------------------------------------------------------------------------- /memory/dma/hdma.md: -------------------------------------------------------------------------------- 1 | # HDMA 2 | 3 | HDMA(HBlank DMA) は 各スキャンラインの HBlank[1](#fblank) でちょっとしたデータ転送[2](#hdma)を行い、PPUレジスタを書き換えて画面効果を実現するためのDMAです。 4 | 5 | スキャンラインごとにPPUの内容を変更できるため、 6 | 7 | - スキャンラインごとに色を設定することで、クロノトリガーのメニューのようなグラデーション塗りや、 8 | - スキャンラインごとにウィンドウレジスタを変更することで、魔獣王のオプション画面のピンクのボーダー 9 | 10 | といった画面効果を実現できます。 11 | 12 | スキャンラインごとに色を設定して、グラデーションを実現  スキャンラインごとにウィンドウレジスタを変更している 13 | 14 | HDMAのテーブルアドレスレジスタは [H-IRQ中](../../interrupt/irq.md) に変更できるため、うまく使えればより高度な画面効果も実現可能です。 15 | 16 | ## HDMAテーブル 17 | 18 | HDMAテーブルは、どのデータをいつ転送する必要があるかについての指示を記したテーブルです。 19 | 20 | ``` 21 | 直接モード: 22 | 1 byte ヘッダ(リピートフラグ(bit7) & 転送行数) 23 | 00h HDMAテーブル終了 (until it restarts in next frame) 24 | 01h..80h 1ユニット転送して、後の"X-01h"行だけ停止 25 | 81h..FFh "X-80h"行かけて、"X-80h"ユニット転送を行う (1行、1ユニット) 26 | N bytes 転送データ 27 | nを転送ユニットとすると、 28 | ヘッダが 29 | 01h..80h: N = n バイト 30 | 81h..FFh: N = (X-80h) * n バイト 31 | 32 | 例(1ユニット=2バイト): 33 | $11 ; エントリ0 34 | $0000, $0000 ; 転送(y=n) 35 | 36 | $02 ; エントリ1 37 | $0100, $0040 ; 転送(y=n+16) 38 | 39 | $82 ; エントリ2 40 | $0104, $0041 ; 転送(y=n+17) 41 | $0108, $0042 ; 転送(y=n+18) 42 | 43 | $64 ; エントリ3 44 | $0114, $0045 ; 転送(y=n+19) 45 | 46 | $00 ; 終了(y=n+118) 47 | ``` 48 | 49 | 間接モードのHDMAテーブルは、生データの代わりに、データへのポインタを含むようにします。 50 | 51 | ``` 52 | 間接モード: 53 | 1 byte ヘッダ (直接モードと同じ) 54 | 2 bytes Nバイトの転送データへのポインタ (ポインタが指すデータの内容は直接モードと同じ) 55 | 56 | 例(1ユニット=2バイト): 57 | $11 58 | $E502 --> $0000, $0000 (y=n) 59 | 60 | $02 61 | $E506 --> $0100, $0040 (y=n+16) 62 | 63 | $82 64 | $E60E --> $0104, $0041 (y=n+17) 65 | $0108, $0042 (y=n+18) 66 | 67 | $64 68 | $E50A --> $0114, $0045 (y=n+19) 69 | 70 | $00 (y=n+118) 71 | ``` 72 | 73 | 転送データ数(`N`, GDMA) または 転送データへのポインタ(HDMA) の値は常にテーブルからREADされます。データ値は転送方向によって READ または WRITTEN になります。 74 | 75 | HDMAでは、テーブル自体も間接的にアドレス指定されたデータブロックも、転送ステップは常にインクリメンタルです。 76 | 77 | ## リロード 78 | 79 | `(H, V)=(6, 0)`のときに、アクティブなHDMAチャネルのHDMAレジスタに対して、リロードが起きます。 80 | 81 | リロード中はCPUが停止します。まず1つでもアクティブなHDMAチャネルがあれば、18サイクル停止します。さらにアクティブなHDMAチャネルごとに、直接HDMAなら 8サイクル、間接HDMAなら 24サイクル 停止します。[3](#indirect-reload) 82 | 83 | **リロードの内容** 84 | 85 | ``` 86 | A2Ax に A1Tx の値をコピー 87 | NTRLx に 現在のテーブルの内容をコピー 88 | 間接HDMAの場合は間接アドレスをロード 89 | ``` 90 | 91 | ## 注釈 92 | 93 | 1: 転送は FBlank中 でも実行されます。 94 | 2: 1回のHBlankで、最大4バイトまでです。 95 | 3: マスターサイクルです。 96 | 97 | -------------------------------------------------------------------------------- /memory/dma/ioreg.md: -------------------------------------------------------------------------------- 1 | # レジスタ 2 | 3 | ## 420Bh - MDMAEN - GDMAチャネルレジスタ (W) 4 | 5 | ``` 6 | Bit n DMAチャネルn で GDMA (0=無効, 1=有効) 7 | ``` 8 | 9 | このレジスタに0以外の値を書き込むと、GDMAが直ちに(数clkサイクル後に)開始されます。 10 | 11 | CPUは転送中、一時停止します。GDMA転送はHDMA転送により中断されることがあります。 12 | 13 | 複数のbitがセットされている場合、別々の転送がチャネル 0=先頭~7=末尾 の順に実行されます。 14 | 15 | 各bitは、チャネルの転送が完了すると自動的にクリアされます。 16 | 17 | HDMAEN で HDMA として使用しているチャネルは、GDMA に使用しないでください。 18 | 19 | ## 420Ch - HDMAEN - HDMAチャネルレジスタ (W) 20 | 21 | ``` 22 | Bit n DMAチャネルn で HDMA (0=無効, 1=有効) 23 | ``` 24 | 25 | MDMAEN の HDMA版 です。 26 | 27 | このレジスタのbitを立てると、bitに対応するDMAチャネルで HBlank時 にHDMA転送が実装されます。 28 | 29 | ## 43x0h - DMAPx - GDMA/HDMA設定レジスタ (R/W) 30 | 31 | ``` 32 | GDMA: 33 | Bit 0-2 転送ユニット(詳細は後述) 34 | 0: 1x1 (Bバス: xx) 35 | 1: 2x1 (Bバス: xx -> xx+1) 36 | 2: 1x2 (Bバス: xx -> xx) 37 | 3: 2x2 (Bバス: xx -> xx -> xx+1 -> xx+1) 38 | 4: 4x1 (Bバス: xx -> xx+1 -> xx+2 -> xx+3) 39 | 5: ??? (Bバス: xx -> xx+1 -> xx -> xx+1) 40 | 6: 1x2 (2と同じ) 41 | 7: 2x2 (3と同じ) 42 | Bit 3-4 Aバスのアドレス増加 43 | 0: インクリメント 44 | 1: 固定 45 | 2: デクリメント 46 | 3: 固定 47 | Bit 5-6 不使用 48 | Bit 7 転送方向 (0=Aバス->Bバス, 1=Bバス->Aバス) 49 | 50 | HDMA: 51 | Bit 0-2 転送ユニット (内容はGDMAと同じ) 52 | Bit 3-5 不使用 53 | Bit 6 テーブルモード (0=直接, 1=間接) 54 | Bit 7 転送方向 (0=Aバス->Bバス, 1=Bバス->Aバス) 55 | ``` 56 | 57 | 転送モード(bit0-2)の `NxM` は 同じBバスアドレスに対して`M`回処理を行ったのちアドレスをインクリメント、これを`N`回繰り返す ということを表しています。 58 | 59 | 擬似コードで表すと次のようになります。 60 | 61 | ```c 62 | // Aバス -> Bバス の場合 63 | void transfer_unit() { 64 | b = bus.b; 65 | 66 | for (n = 0; n < N; n++) { 67 | for (m = 0; m < M; m++) { 68 | val = read(bus.a); 69 | write(0x2100+b, val); 70 | bus.a += INCREMENT; 71 | } 72 | 73 | b++; 74 | } 75 | } 76 | ``` 77 | 78 | ## 43x1h - BBADx - Bバスアドレス (R/W) 79 | 80 | ``` 81 | Bit 0-7 Bバスアドレス (0xNN = 0x21NN) 82 | ``` 83 | 84 | GDMAでは基本的に `04h=OAM, 18h=VRAM, 22h=CGRAM, 80h=WRAM` のどれかになります。 85 | 86 | HDMAでは大抵の場合、PPUレジスタのどれかを指します。 87 | 88 | ## 43x2h/43x3h/43x4h - A1Tx - Aバスアドレス (R/W) 89 | 90 | このレジスタではAバスの指すアドレスを指定します。 91 | 92 | HDMAの場合は[HDMAテーブル](hdma.md)の開始アドレス(エントリ0)を指します。 93 | 94 | ``` 95 | GDMA: 96 | Bit 0-15 Aバスアドレス (bit0-15, 転送が進むごとに変化(DMAPx.3-4)する) 97 | Bit 16-23 Aバスアドレス (bit16-23, DMAPx.3-4の影響を受けず、ずっと固定) 98 | 99 | HDMA: 100 | Bit 0-15 HDMAテーブル開始アドレス (ずっと固定、43x8h/43x9h へとリロードされる) 101 | Bit 16-23 HDMAテーブル開始アドレス (ずっと固定、43x8h/43x9h のバンク番号) 102 | ``` 103 | 104 | ## 43x5h/43x6h/43x7h - DASx - GDMA転送サイズ/間接HDMAアドレス (R/W) 105 | 106 | 間接HDMAの場合、0x43x7 だけはプログラマが転送前に設定しておく必要があります。[1](#indirect_bank) 107 | 108 | ``` 109 | GDMA: 110 | Bit 0-15 残りの転送バイトサイズ (0のときは0x10000) 111 | 転送が進むと共に減っていき、0になると転送終了 112 | 例: 残り5バイトで転送ユニットが4バイトのとき、ユニット1個と2個目のユニットの1バイト目が転送される 113 | Bit 16-23 不使用 114 | 115 | HDMA(直接): 116 | Bit 0-23 不使用 (転送するデータはテーブルから直接読み込まれます) 117 | 118 | HDMA(間接): 119 | Bit 0-15 Current CPU-Bus Data Address (automatically loaded from the Table) 120 | Bit 16-23 Current CPU-Bus Data Address Bank (this must be set by software) 121 | ``` 122 | 123 | ## 43x8h/43x9h - A2Ax - HDMAテーブルアドレス (R/W) 124 | 125 | リロード時に、自動的に`A1Tx`(0x43x2)の値に設定されます。 126 | 127 | 現在の[HDMAテーブル](hdma.md)アドレスを示します。転送の進行によってインクリメントされていきます。 128 | 129 | テーブルアドレスの bit16-23(バンク) は A1Tx の bit16-23 になります。 130 | 131 | ``` 132 | GDMA: 133 | Bit 0-15 不使用 134 | 135 | HDMA: 136 | Bit 0-15 現在のHDMAテーブルアドレス (43x2h/43x3h の値でリロードされる) 137 | 転送の進行によってインクリメントされる 138 | - 現在のHDMAテーブルのバンク番号 (=43x4h) 139 | ``` 140 | 141 | ## 43xAh - NTRLx - HDMAテーブルヘッダ (R/W) 142 | 143 | [HDMAテーブル](hdma.md)の現在のエントリのヘッダが入っています。 144 | 145 | リロード時に自動で設定されるため、プログラマがこのレジスタを変更する必要はありません。 146 | 147 | ``` 148 | GDMA: 149 | Bit 0-7 不使用 150 | HDMA: 151 | Bit 0-7 ヘッダ (後述) 152 | ``` 153 | 154 | ## 43xBh - UNUSEDx - 用途なし (R/W) 155 | 156 | ``` 157 | Bit 0-7 用途なし 158 | ``` 159 | 160 | 使われていませんが、値を自由に読み書きできます。そのため、高速RAMとして使用可能です。(ただし、memfillの固定DMAソースアドレスとしては使用不可) 161 | 162 | このレジスタに値を格納しても、転送には何の影響もないようです。(値はそのまま残され、DMAや直接・間接HDMAによって変更されることはありません) 163 | 164 | ## 43xCh..43xEh - 不使用 (W) 165 | 166 | 使われていません。書き込んでも何も起こらないようです。 167 | 168 | 読み取ると、オープンバスからのゴミ値が返ってきます。 169 | 170 | ## 43xFh - MIRRx - 43xBhミラー (R/W) 171 | 172 | `43xBh`のミラーです。 173 | 174 | ## 注釈 175 | 176 | 1: 0x43x4 と同じバンクにある場合は,0x43x7 に書き込む必要はありません。 -------------------------------------------------------------------------------- /memory/dma/timing.md: -------------------------------------------------------------------------------- 1 | # DMAの実行タイミング 2 | 3 | TODO([Anomie's Docs](../../others/anomie/timing.txt)を参考に書く予定) 4 | 5 | ## メモ(GDMA) 6 | 7 | ``` 8 | DMA is activated by writing a 1 to any bit of CPU register $420b. The CPU is halted during the DMA transfer. 9 | 10 | DMAはCPUレジスタ$420bのいずれかのビットに1を書き込むことで起動します。 11 | DMA転送中、CPUは停止します。 12 | ``` 13 | 14 | ``` 15 | DMA takes 8 master cycles per byte transferred, regardless of the memory regions accessed. It is unknown what happens if you attempt DMA to or from $4000-$41ff, since that memory region requires 12 master cycles for access. There is also 8 master cycles overhead per channel. 16 | 17 | DMAは、アクセスするメモリ領域に関係なく、1バイトの転送に8マスターサイクルを要します。 18 | 4000-$41ffのメモリ領域へのアクセスには12マスターサイクルを要するため、この領域との間でDMAを試みた場合どうなるかは不明です。 19 | また、1チャネルあたり8マスターサイクルのオーバーヘッドが発生します。 20 | ``` 21 | 22 | ``` 23 | The exact DMA timing works as follows. After $420b is written, the CPU gets one more CPU cycle before the pause. For example, on a standard "STA $420b", this would be the opcode fetch for the next instruction The speed of the next CPU cycle to execute after the DMA determines the CPU Clock speed for the DMA transfer. 24 | 25 | 正確なDMAのタイミングは次のように動作します。 26 | $420bが書き込まれた後、CPUは一時停止の前にもう1つのCPUサイクルを取得します。 27 | 例えば、標準的な`STA $420b`の場合、これは次の命令のオペコードフェッチになります DMAの次に実行するCPUサイクルの速度によって、DMA転送のためのCPUクロック速度が決まります。 28 | ``` 29 | 30 | ``` 31 | Now, after the pause, wait 2-8 master cycles to reach a whole multiple of 8 master cycles since reset. 32 | The perform the DMA. 8 master cycles overhead and 8 master cycles per byte per channel, and an extra 8 master cycles overhead for the whole thing. 33 | Then wait 2-8 master cycles to reach a whole number of CPU Clock cycles since the pause, and only then resume S-CPU execution. 34 | 35 | ここで、一時停止後、リセットから8回の全倍数になるように2~8回のマスタサイクルを待ちます。 36 | DMAを実行します。8マスターサイクルのオーバーヘッドと、チャンネルごとにバイトあたり8マスターサイクル、そして全体で8マスターサイクルのオーバーヘッドを追加します。 37 | その後、一時停止からCPUクロックサイクルの整数倍に達するまで2~8マスタサイクルを待ち、その後のみS-CPUの実行を再開します。 38 | ``` 39 | 40 | ``` 41 | The exact timing of the read within the DMA period is not known. 42 | Best guess at this point is that 2-4 of the "whole DMA overhead" is before the transfer and the rest after. 43 | 44 | DMA期間内の読み出しの正確なタイミングはわかっていない。 45 | 現時点での最善の推測は、「DMA全体のオーバーヘッド」の2~4が転送前に、残りが転送後になることだ。 46 | ``` 47 | 48 | ``` 49 | An example: "STA $420b : NOP", one channel active for a 3 byte transfer. 50 | 51 | The pause occurs after the NOP opcode is fetched, so the CPU Clock Speed is 6 master cycles due to the following IO cycle in the NOP. 52 | 53 | Total = 0 54 | After the pause, say we need 2 master cycles to reach an even multiple of 8 master cycles since reset. 55 | Total = 2 56 | Then wait 8 for DMA init. 57 | Total = 10 58 | 8 for channel init. 59 | Total = 18 60 | 8*3 for the actual transfer. 61 | Total = 42 62 | To reach a whole number of CPU Clock cycles since the pause, we must wait 6 master cycles (remember, 0 is not 63 | an option). 64 | Total = 48 65 | 66 | 命令 67 | STA $420b; 68 | NOP; 69 | で3バイトのDMA転送をアクティベートした場合を考えましょう。 70 | 71 | NOPオペコードのフェッチ後にポーズが発生するため、NOPの次のIOサイクルの影響でCPUクロックスピードは6マスターサイクルになります。 72 | 73 | Total: 0 74 | 一時停止後、リセット後8サイクルの倍数まで2サイクルが必要だとします。 75 | Total: 2 76 | DMAの初期化処理で8サイクル待ちます 77 | Total: 10 78 | DMAチャネルの初期化処理で8サイクル待ちます 79 | Total: 18 80 | 実際の転送に 8x3 サイクルかかります 81 | Total: 42 82 | CPUクロックが一時停止から6の倍数になるには、6サイクルの待ちが必要です。(42は6の倍数だが、ここでは1サイクル以上の待ちが必要) 83 | Total: 48 84 | ``` 85 | 86 | ``` 87 | 上記の例と同じことを、2サイクルはやく始めた場合を考えましょう。 88 | 89 | Total = 0 90 | リセットから8の倍数になるには、4サイクルを待たなければなりません。 91 | Total = 4 92 | DMA転送に合計40サイクルかかります 93 | Total = 44 94 | 6の倍数まで4サイクル待つ必要があります 95 | Total = 48 96 | ``` 97 | -------------------------------------------------------------------------------- /memory/oam.md: -------------------------------------------------------------------------------- 1 | # OAMへのアクセス 2 | 3 | ## 2102h/2103h - OAMADD - OAMアドレス (W) 4 | 5 | ``` 6 | 2102h: OAMADDL 7 | 2103h: OAMADDH 8 | ``` 9 | 10 | ``` 11 | Bit 0-7 OAMアドレス (ワード単位) 12 | このアドレスを2で割った値、つまりbit1-7がアクセス対象のOBJ 13 | Bit 8 OAMテーブル (0= 0..511バイト, 1=512..543バイト) 14 | Bit 9-14 不使用 15 | Bit 15 OAM優先度回転フラグ (OBJ同士の優先度) 16 | 0: OBJ0が最大、OBJ127が最低 17 | 1: アクセス対象のOBJn(n = bit1-7)が優先度最大、OBJ(n+1)が次に優先され、OBJ(n-1)が優先度最低になる 18 | ``` 19 | 20 | このレジスタでアクセスするOAMのアドレスを設定します。 21 | 22 | 1: このレジスタでは合計9bitでアドレスを指定しますが、内部には(544バイトなので)10bitのアドレスレジスタが存在しており、OAMADDに書き込まれたときに、内部のアドレスレジスタに反映されます。 23 | 24 | ## 2104h/2138h - OAMDATA/RDOAM - OAM書き込み/読み込み 25 | 26 | OAMDATA(0x2104) は 書き込み専用、 RDOAM(0x2138) は読み取り専用です。 27 | 28 | ``` 29 | 1回目のアクセス: 下位8bit (偶数アドレス) 30 | 2回目のアクセス: 上位8bit (奇数アドレス) 31 | ``` 32 | 33 | Reads and Writes to EVEN and ODD byte-addresses work as follows: 34 | 35 | ``` 36 | Write to EVEN address --> set OAM_Lsb = Data ;memorize value 37 | Write to ODD address<200h --> set WORD[addr-1] = Data*256 + OAM_Lsb 38 | Write to ANY address>1FFh --> set BYTE[addr] = Data 39 | Read from ANY address --> return BYTE[addr] 40 | ``` 41 | 42 | 両方とも、1回目、2回目に関係なく、アクセスのたびにOAMのアドレスがインクリメントされます。 43 | 44 | OAM Size is 220h bytes (addresses 220h..3FFh are mirrors of 200h..21Fh). 45 | -------------------------------------------------------------------------------- /memory/palette.md: -------------------------------------------------------------------------------- 1 | # 🎨 パレットへのアクセス 2 | 3 | > **Note** CGRAM = パレットメモリ 4 | 5 | ## 🔰 概要 6 | 7 | ``` 8 | Write: 2122h (2回アクセス) 9 | Read: 213Bh (2回アクセス) 10 | Address: 2121h 11 | ``` 12 | 13 | ## 📮 2121h - CGADD - パレットアドレス (W) 14 | 15 | 0..255で色番号を指定します。(CGRAMは 1色=2バイト で256エントリ) 16 | 17 | このレジスタへの書き込みは CGDATA(`2122h`) と RDCGRAM(`213Bh`) へのアクセスをリセットします。(つまり、次のアクセスが2回目だったとしても、1回目にリセットされます) 18 | 19 | ## 🖌 2122h - CGDATA - パレット書き込み (W) 20 | 21 | ``` 22 | 1回目のアクセス: 下位8bit (偶数アドレス) 23 | 2回目のアクセス: 上位7bit (奇数アドレス) (upper 1bit = PPU2 open bus) 24 | ``` 25 | 26 | ``` 27 | 偶数アドレスへの書き込み: set Cgram_Lsb = Data ;memorize value 28 | 奇数アドレスへの書き込み: set WORD[addr-1] = Data*256 + Cgram_Lsb 29 | ``` 30 | 31 | 書き込みのたびにアドレスが自動的にインクリメントされます。 32 | 33 | ## 🔍 213Bh - RDCGRAM - パレット読み込み (R) 34 | 35 | ``` 36 | 1回目のアクセス: 下位8bit (偶数アドレス) 37 | 2回目のアクセス: 上位7bit (奇数アドレス) (upper 1bit = PPU2 open bus) 38 | ``` 39 | 40 | 読み出しのたびにアドレスが自動的にインクリメントされます。 41 | 42 | -------------------------------------------------------------------------------- /memory/vram.md: -------------------------------------------------------------------------------- 1 | # [VRAMへのアクセス](https://problemkaputt.de/fullsnes.htm#snesmemoryvramaccesstileandbgmap) 2 | 3 | このページでは、VRAMにアクセスするためのレジスタについて解説します。 4 | 5 | VRAM自体の内容については[こちら](../video/vram.md)を参照。 6 | 7 | ## 🔰 概要 8 | 9 | ``` 10 | High : Low 11 | Write: 2119h : 2118h 12 | Read: 213Ah : 2139h 13 | Address: 2117h : 2116h 14 | ``` 15 | 16 | ## 🗓 2115h - VMAIN - VRAMアドレス増加レジスタ (W) 17 | 18 | ``` 19 | Bit 0-1 VMADDのインクリメント量(word = 2byte単位) 20 | 0b00: 1 word 21 | 0b01: 32 word 22 | 0b10: 64 word 23 | 0b11: 128 word 24 | Bit 2-3 アドレス変換 (後述) 25 | 0b00: 0bit回転(アドレス変換なし) 26 | 0b01: 8bit回転 27 | 0b10: 9bit回転 28 | 0b11: 10bit回転 29 | Bit 4-6 不使用 30 | Bit 7 上位/下位バイトのどちらにアクセスした後、VRAMアドレスをインクリメントするか 31 | 0: 下位バイト(0x2118 or 0x2139) 32 | 1: 上位バイト(0x2119 or 0x213A) 33 | ``` 34 | 35 |
36 | アドレス変換機能について 37 | 38 | アドレス変換機能は、VRAMにアクセスする際に`VMADD`で指定したVRAMアドレスに一時的に適応される変換処理です。 39 | 40 | アドレス変換はビットマップ式を対象としており、技術的にはワードアドレスの下位8,9,10bitを3bitだけ左回転させます。 41 | 42 | 変換方法 | Bitmap Type | `Port [2116h/17h] --> VRAM Word-Address` 43 | -- | -- | -- 44 | 8bit rotate | 4-color; 1 word/plane | `aaaaaaaaYYYxxxxx --> aaaaaaaaxxxxxYYY` 45 | 9bit rotate | 16-color; 2 words/plane | `aaaaaaaYYYxxxxxP --> aaaaaaaxxxxxPYYY` 46 | 10bit rotate | 256-color; 4 words/plane | `aaaaaaYYYxxxxxPP --> aaaaaaxxxxxPPYYY` 47 | 48 | `aaaaa`は通常のアドレスのMSB、`YYY`は8x8タイル内のYインデックス、`xxxxx`は1ラインあたり32タイルのうちの1つを選択、`PP`はビットプレーンのインデックス(1プレーンに複数のWordがあるBGの場合)です。 49 | 50 | 256ピクセルの行を書きたいなら、アドレス変換する際には`Increment Step=1`と組み合わせる必要があります。 51 | 52 | Mode7のビットマップの場合、最終的には32/128ステップ(bit1-0)と8bit/10bit回転(bit3-2)の組み合わせになります。 53 | 54 | ``` 55 | 8bit-rotate/step32 aaaaaaaaXXXxxYYY --> aaaaaaaaxxYYYXXX 56 | 10bit-rotate/step128 aaaaaaXXXxxxxYYY --> aaaaaaxxxxYYYXXX 57 | ``` 58 | 59 | しかし、SNESはMode7ビットマップで画面全体を描画するのに十分大きなVRAMを持っていません。 60 | 61 | アドレス変換なしの32ステップはBGマップの列を更新するのに便利です。(例: X方向のスクロール後) 62 |
63 | 64 | ## 📮 2116h/2117h - VMADD - VRAMアドレス(W) 65 | 66 | ``` 67 | 2116h: VMADDL 68 | 2117h: VMADDH 69 | ``` 70 | 71 | VRAMの読み出し/書き込み用アドレスを指定するレジスタです。これはワード単位(2バイト単位)で指定します。つまり、実際のアドレスは`2 * VMADD`です。 72 | 73 | 理論上、最大128KB(64Kワード)までアドレス指定できますが、スーファミ本体にVRAMは64KB(32Kワード)しか搭載されていません。 そのため、VMADD.15は不使用で0扱いなので、`8000h..FFFFh`は`0..7FFFh`のミラーリングとなります。 74 | 75 | VRAMデータの読み出し/書き込み後、`VMAIN(2115h)`のインクリメントモードにより、ワードアドレス(`VMADD`)が 1,32,128ずつ自動的にインクリメントされることがあります。 76 | 77 | 注: アドレス変換機能は、メモリアクセス時に「一時的に」適用されるだけで、ポート`2116h..2117h`の値には影響を与えません。 78 | 79 | `2116h/2117h`への書き込みは、後で読み出すために新しいアドレスから16bitデータをプリフェッチします。 80 | 81 | ## 🖌 2118h/2119h - VMDATA - VRAM書き込み (W) 82 | 83 | ``` 84 | 2118h: VMDATAL 85 | 2119h: VMDATAH 86 | ``` 87 | 88 | `2118h`または`2119h`への書き込みは、現在(アドレス変換を適用した)アドレスで指定されているVRAMのLSBまたはMSBを変更するだけです。VMAINのインクリメントモードにより、書き込み後、アドレスは自動的にインクリメントされます。 89 | 90 | ## 🔍 2139h/213Ah - RDVRAM - VRAM読み込み (R) 91 | 92 | ``` 93 | 2139h: RDVRAML 94 | 213Ah: RDVRAMH 95 | ``` 96 | 97 | これらのレジスタから読み取りを行うと、内部の16bitプリフェッチレジスタのLSBまたはMSBが返されます。VMAINのインクリメントモードによって、読み出し後にアドレスが自動的にインクリメントされます。 98 | 99 | プリフェッチレジスタは、次の2つの場合に、VMADDL/VMADDHでアドレス指定されているVRAMワード(オプションのアドレス変換が適用されている)からデータで満たされます。 100 | 101 | ``` 102 | プリフェッチが行われる2つのパターン: 103 | 2116h/17hへの書き込みによってVRAMアドレスが変化したとき 104 | 2139h/3Ahからの読み取りでVRAMアドレスがインクリメントされたとき 105 | ``` 106 | 107 | `Prefetch BEFORE Increment`は一種のハードウェアグリッチで、基本的に`Prefetch AFTER Increment`のほうが有用です。 108 | 109 | Increment/Prefetch の処理は 110 | 111 | ``` 112 | 1. 古いプリフェッチからの1バイトをCPUに送る ;-this always 113 | 2. 古いVRAMアドレスから新しい値をプリフェッチレジスタにロード ;\these only if 114 | 3. VRAMアドレスをインクリメントして新しいアドレスにする ;/increment occurs 115 | ``` 116 | 117 | `2118h/19h`への書き込みでインクリメントが起きた場合、プリフェッチは行われません。(当然、内部のプリフェッチレジスタも変わりません) 118 | 119 | >**Note** 120 | > (`2116h/17h`経由で)VRAMアドレス変更後、最初のアクセス時はVRAMアドレスはインクリメントされません。そのため、1度ダミーの読み出しをする必要があります。 121 | -------------------------------------------------------------------------------- /memory/wram.md: -------------------------------------------------------------------------------- 1 | # WRAM 2 | 3 | SNESは128KBバイトのWork RAM(WRAM)を搭載しており、いくつかの方法でアクセスすることができます。 4 | 5 | ``` 6 | 128KBのWRAMはアドレス空間 7E0000h-7FFFFFh に配置されています。 7 | 先頭8KBは xx0000h-xx1FFFh (xx=00h..3Fh, 80h..BFh) にもミラーされています。 8 | 加えて、218xhレジスタを通じてWRAMにはアクセス可能です。(主にDMA関連で使用します。) 9 | ``` 10 | 11 | ## 🔰 概要 12 | 13 | ``` 14 | Write: 2180h 15 | Read: 2180h 16 | Address: 2183h : 2182h : 2181h 17 | ``` 18 | 19 | ## 🗃 2180h - WMDATA - WRAMデータ (R/W) 20 | 21 | ``` 22 | 7-0 WMADDで指定したアドレスのデータ内容 23 | ``` 24 | 25 | このレジスタでは、単純に`[2181h-2183h]`の示すアドレス上のバイトを読み書きし、**アドレスを1つインクリメント**します。 26 | 27 | このレジスタを通したWRAMの読み込み処理は`7E0000h-7FFFFFh`経由のアクセスより高速であるにもかかわらず、プリフェッチの有無とは無関係です。また、2180hを読むと、2180hや`7E0000h-7FFFFFFh`への書き込みと混在していても、常に現在アドレスされているバイトが返されます。 28 | 29 | ## 📮 2181h/2182h/2183h - WMADD - WRAMアドレス (W) 30 | 31 | このレジスタでは、WMDATA(`2180h`)を通して128KBのWRAMにアクセスするための17bitアドレスを保持します。 32 | 33 | ```c 34 | // 2181h: 0-7 bit 35 | // 2182h: 8-15 bit 36 | // 2183h: 16 bit 37 | addr = ([0x2183] << 16) | ([0x2182] << 8) | [0x2181] 38 | ``` 39 | 40 | ## DMAについて 41 | 42 | WRAM間のDMAはできません。A-BusからB-Bus方向にも、その逆にもできません。外部的には別々のアドレス線が存在しますが、WRAMのチップは両方を一度に処理することができないからです。 43 | 44 | ## アクセス速度 45 | 46 | WRAMは2.6MHzでアクセスされます。つまり、WRAM上のすべての変数、スタック、プログラムコードへのアクセスは低速です。 47 | 48 | なお、スーファミには高速アクセス可能なRAMは搭載されていません。しかし、次の工夫をすることで、3.5MHzでWRAMにアクセスすることができます。 49 | 50 | - `[2180h]`を通じたWRAMへのシーケンシャルな読み込みは3.5MHzでアクセスされ、読み出しアドレスも自動でインクリメントされます。 51 | - DMA registers at 43x0h-43xBh provide 8x12 bytes of read/write-able "memory". 52 | - External RAM could be mapped to 5000h-5FFFh (but usually it's at slow 6000h). 53 | - External RAM could be mapped to C00000h-FFFFFFh (probably rarely done too). 54 | 55 | ## Other Notes 56 | 57 | The B-Bus feature with auto-increment is making it fairly easy to boot the SNES without any ROM/EPROM by simply writing program bytes to WRAM (and mirroring it to the Program and Reset vector to ROM area): 58 | 59 | [SNES Xboo Upload (WRAM Boot)](SNES Xboo Upload (WRAM Boot)) 60 | 61 | Interestingly, the WRAM-to-ROM Area mirroring seems to be stable even when ROM Area is set to 3.5MHz Access Time - so it's unclear why Nintendo has restricted normal WRAM Access to 2.6MHz - maybe some WRAM chips are slower than others, or maybe they become unstable at certain room temperatures. 62 | -------------------------------------------------------------------------------- /memory/ws2.md: -------------------------------------------------------------------------------- 1 | # ウェイトステート2 2 | 3 | メモリアドレスの`0x80xxxx..0xFFxxxx`は基本的に、`0x00xxxx..0x7Fxxxx`のミラーです。 4 | 5 | ただし、メモリの動作速度が異なるため、CPUがメモリアクセスに要する時間(ウェイトステート)が異なります。 6 | 7 | `0x00xxxx..0x7Fxxxx`へのウェイトステートはウェイトステート1(ws1), `0x80xxxx..0xFFxxxx`へのウェイトステートはウェイトステート2(ws2)と呼ばれます。 8 | 9 | ウェイトステート1 は 2.68MHz に固定されていますが、ウェイトステート2 は 2.68MHz と 3.58MHz の動作速度のどちらかを選ぶことができます。 10 | 3.58MHz の場合、ウェイトステート1 より高速にメモリにアクセスできますが、要求されるカートリッジのスペックも高くなるため、カートリッジの値段も高くなると思われます。(実際に値段が違ったかは要調査) 11 | 12 | ## 420Dh - MEMSEL - WS2制御レジスタ (W) 13 | 14 | bit | 内容 15 | ---- | ---- 16 | 0 | WS2領域のアクセスに要するサイクル (0=2.68MHz, 1=3.58MHz) 17 | 1-7 | 不使用 18 | 19 | リセット時にbit0は0に設定されます。 20 | 21 | WS2領域は、バンク`80h..BFh`のアドレス`8000h..FFFFh`と、バンク`C0h..FFh`のアドレス`0000h..FFFFh`で構成されています。 22 | 23 | 3.58MHzの高速メモリは120ns以上のROM/EPROMが必要です。2.68MHzのメモリは、200ns以上のROM/EPROMが必要です。 24 | 25 | ``` 26 | 2.684658 MHz = 21.47727 MHz / 8 ; WRAMと同じ速度でアクセス可能 27 | 3.579545 MHz = 21.47727 MHz / 6 ; WRAMよりアクセスが高速 28 | ``` 29 | 30 | 3.58MHzの設定を使用するプログラムは、カートリッジのヘッダの`[FFD5h].4`にその旨を記載してください。 31 | -------------------------------------------------------------------------------- /muldiv.md: -------------------------------------------------------------------------------- 1 | # [乗算・除算](https://problemkaputt.de/fullsnes.htm#snesmathsmultiplydivide) 2 | 3 | >**Note** 4 | > ここでは サイクル = CPUサイクル とします。 5 | 6 | ## 4202h - WRMPYA - 被乗数レジスタ (W) 7 | 8 | 8bitの符号無し整数 9 | 10 | WRMPYB(`4203h`) 参照 11 | 12 | ## 4203h - WRMPYB - 乗数レジスタ (W) 13 | 14 | 8bitの符号無し整数 15 | 16 | ここに書き込みを行うと、8サイクルを使って WRMPYB(`4202h`) と掛け算を行います。 17 | 18 | 掛け算の結果は RDMPY(`4216h-4217h`) に 16bitの符号無し整数として格納されます。 19 | 20 | 掛け算を行うと、副作用として 21 | 22 | ```c 23 | RDDIVL = WRMPYB; 24 | RDDIVH = 0x00; 25 | ``` 26 | 27 | となることに注意してください。 28 | 29 | また、本来8サイクル必要ですが、WPMPYA(`4202h`)の上位 `N`ビットがすべて0であれば、`N`サイクルだけ処理時間が減るようです。 30 | 31 | ## 4204h/4205h - WRDIVL/WRDIVH - 被除数レジスタ (W) 32 | 33 | 16bitの符号無し整数 34 | 35 | ``` 36 | 4204h = 下位8bit 37 | 4205h = 上位8bit 38 | ``` 39 | 40 | WRDIVB(`4206h`) 参照 41 | 42 | ## 4206h - WRDIVB - 除数レジスタ (W) 43 | 44 | 8bitの符号無し整数 45 | 46 | ここに書き込みを行うと、16サイクルを使って WRDIV(`4204h-4205h`) と割り算を行います。 47 | 48 | 割り算の結果は、商が RDDIVL(`4214-4215h`) に、余りが RDMPY(`4216-4217h`) に 16bitの符号無し整数として格納されます。 49 | 50 | ```c 51 | RDDIV = WRDIV / WRDIVB; 52 | RDMPY = WRDIV % WRDIVB; 53 | ``` 54 | 55 | ゼロ除算を行う、つまり WRDIVB に 0 を書き込んだ場合は、 56 | 57 | ```c 58 | RDDIV = 0xFFFF; 59 | RDMPY = WRDIV; 60 | ``` 61 | 62 | となります。 63 | 64 | Note: ほとんどのゲームは初期化時にI/Oポートをゼロクリアするため、ゼロ除算が生じます。 65 | 66 | ## 4214h/4215h - RDDIVL/RDDIVH - 商レジスタ (R) 67 | 68 | 割り算の商が格納されます。WRDIVB(`4206h`) 参照 69 | 70 | 掛け算によって、このレジスタの中身は破壊されることに注意してください。 71 | 72 | ## 4216h/4217h - RDMPYL/RDMPYH - 積/余りレジスタ (R) 73 | 74 | 掛け算の積 か 割り算の余りが格納されます。 75 | 76 | 掛け算については、WRMPYB(`4203h`) 参照 77 | 78 | 割り算については、WRDIVB(`4206h`) 参照 79 | 80 | ## 待ち時間の必要性 81 | 82 | 掛け算/割り算の結果を読み出す際には、待ち時間が必要なことに注意してください。 83 | 84 | 例えば、`MOV r,[421xh]`で結果を読み出す場合、`MOV r,[421xh]`は3サイクル消費します。そのため、MUL(処理に8サイクル)では5サイクル、DIV(処理に16サイクル)では13サイクルだけ待ち時間が必要になります。 85 | 86 | 42xxh PortsはCPUクロックで動作するため、CPUクロックが3.5MHzでも2.6MHzでも関係ありません。 87 | 88 | 89 | -------------------------------------------------------------------------------- /openbus.md: -------------------------------------------------------------------------------- 1 | # オープンバス 2 | 3 | メモリ空間からの呼び出しでは、次の場合にMDR(Memory Data Resister)の値が返ってくることがあります。 4 | 5 | - 未使用アドレスからの読み出し 6 | - 8ビット未満のレジスタからの読み出し 7 | - (ほとんどの)書き込み専用レジスタからの読み出し 8 | 9 | このように、読み出しに対してMDRの値が返ってくるアドレス空間を、オープンバスといいます。 10 | 11 | MDRはW65C816プロセッサに存在すると仮定されているレジスタで、MDRの値は、最後にデータバスへ読み書きされた値になります。ほとんどの場合、オペコードの最後のバイト(直接読み出し)、または間接アドレスの上位バイト(間接読み出し)です。 12 | 13 | 例: 14 | 15 | ``` 16 | LDA IIJJ,Y aka MOV A,[IIJJ+Y] --> garbage = II 17 | LDA (NN),Y aka MOV A,[[NN]+Y] --> garbage = [NN+1] 18 | ``` 19 | 20 | GDMAを使用する場合、おそらくDMAを開始したストアオペコードに依存するでしょう(上記のロードと同様の方法)。HDMAの場合は予測不可能で、MDRの値は現在のオペコードに関連するあらゆる値になります。そして、もし2つのDMA転送が互いに直接続くなら、MDRはおそらく前のDMAから来るでしょう。 21 | 22 | Also, in 6502-mode (and maybe also in 65816-mode), the CPU may insert dummy-fetches from unintended addresses on page-wraps? 23 | 24 | ## PPUのオープンバス 25 | 26 | PPUのIOレジスタ(`0x2100..21FF`)のオープンバスは、基本的にCPUと同じ(つまり最後にデータバスに出力されていた値を返す)ですが、一部レジスタは返す値が異なるものがあります。 27 | 28 | ### PPU1オープンバス 29 | 30 | PPU1オープンバスの返す値は、`2134h..2136h, 2138h..213Ah, 213Eh`から直近で読み出した値に依存します。 31 | 32 | この記憶された値は、IOレジスタ`21x4h..21x6h`および`21x8h..21xAh`(x=0,1,2)と`STAT77.4`から読み出す際に返されます。 33 | 34 | ### PPU2オープンバス 35 | 36 | PPU2オープンバスの返す値は、`213Bh-213Dh, 213Fh`から直近で読み出した値に依存します。 37 | 38 | この記憶された値は、IOレジスタ`213Bh.2nd_read.Bit7`および`213Ch/213Dh.2nd_read.Bits7-1`と`STAT78.5`から読み出す際に返されます。 39 | 40 | ## DMAのオープンバス 41 | 42 | TODO 43 | -------------------------------------------------------------------------------- /others/anomie/memmap.txt: -------------------------------------------------------------------------------- 1 | ============================================================================= 2 | Anomie's SNES Memory Mapping Doc 3 | $Revision: 1160 $ 4 | $Date: 2008-12-21 12:40:39 -0500 (Sun, 21 Dec 2008) $ 5 | 6 | ============================================================================= 7 | 8 | This is a document intended to describe the SNES memory map. It will NOT 9 | include information on the MAD-1 or any other address decoder. 10 | 11 | HARDWARE 12 | ======== 13 | 14 | The SNES has one 8-bit data bus, two address busses typically known as 15 | "Address Bus A" and "Address Bus B". 16 | 17 | Data Bus 18 | -------- 19 | 20 | The data bus is 8 bits. If nothing sets a value on the data bus for any 21 | particular read request, the last value placed on the bus is read instead 22 | (this is known as "Open Bus"). 23 | 24 | LINE | CART | EXPAND 25 | -----+------+-------- 26 | D0 | 19 | 11 27 | D1 | 20 | 12 28 | D2 | 21 | 13 29 | D3 | 22 | 14 30 | D4 | 50 | 15 31 | D5 | 51 | 16 32 | D6 | 52 | 17 33 | D7 | 53 | 18 34 | 35 | Address Bus A 36 | ------------- 37 | 38 | This address bus is 24 bits, along with read and write lines (/RD and /WR) 39 | and 2 auxiliary lines (/CART and /WRAM). WRAM is connected to this bus, as 40 | well as the cart connector. 41 | 42 | LINE | CART LINE | CART 43 | -----+------ -------+------ 44 | A0 | 17 A14 | 39 45 | A1 | 16 A15 | 40 46 | A2 | 15 A16 | 41 47 | A3 | 14 A17 | 42 48 | A4 | 13 A18 | 43 49 | A5 | 12 A19 | 44 50 | A6 | 11 A20 | 45 51 | A7 | 10 A21 | 46 52 | A8 | 9 A22 | 47 53 | A9 | 8 A23 | 48 54 | A10 | 7 /RD | 23 55 | A11 | 6 /WR | 54 56 | A12 | 37 /CART | 49 57 | A13 | 38 /WRAM | 32 58 | 59 | Address Bus B 60 | ------------- 61 | 62 | This address bus is 8 bits, along with read and write lines (/RD and /WR). 63 | d /WRAM). WRAM, PPU1, PPU2, and APU are connected to this bus, as well as 64 | the cart and expansion ports. 65 | 66 | LINE | CART | EXPAND 67 | -----+------+-------- 68 | PA0 | 28 | 1 69 | PA1 | 59 | 2 70 | PA2 | 29 | 3 71 | PA3 | 60 | 4 72 | PA4 | 30 | 5 73 | PA5 | 61 | 6 74 | PA6 | 3 | 7 75 | PA7 | 34 | 8 76 | /PARD| 4 | 10 77 | /PAWR| 35 | 9 78 | 79 | 80 | MEMORY MAP 81 | ========== 82 | 83 | As far as the SNES is concerned, this is the memory map. "LoROM", "HiROM", 84 | and anything else is just the cart responding differently to the addresses 85 | placed on Address Bus A. 86 | 87 | WRAM responds to Address Bus A whenever /WRAM is active, and to registers 88 | $2180-$2183 on Address Bus B. APU responds to $40-$7F on Address Bus B. PPU1 89 | and PPU2 respond to $2100-$213F on Address Bus B. The cart is expected to 90 | respond when /CART is active, but it can respond to any address on either bus 91 | that is not otherwise mapped. Similarly, the device plugged into the expansion 92 | port may respond to any unmapped register on Address Bus B. 93 | 94 | The 'Speed' column indicates the memory access speed for that area of memory. 95 | The SNES master clock runs at about 21MHz (probably as close to 1.89e9/88 Hz as 96 | possible). Internal operation CPU cycles always take 6 master cycles. Fast 97 | memory access cycles also take 6 master cycles, Slow memory access cycles take 98 | 8 master cycles, and XSlow memory access cycles take 12 master cycles. 99 | 100 | 101 | Banks | Addresses | Speed | Mapping 102 | ---------+-------------+-------+--------- 103 | $00-$3F | $0000-$1FFF | Slow | Address Bus A + /WRAM (mirror $7E:0000-$1FFF) 104 | | $2000-$20FF | Fast | Address Bus A 105 | | $2100-$21FF | Fast | Address Bus B 106 | | $2200-$3FFF | Fast | Address Bus A 107 | | $4000-$41FF | XSlow | Internal CPU registers (see Note 1 below) 108 | | $4200-$43FF | Fast | Internal CPU registers (see Note 1 below) 109 | | $4400-$5FFF | Fast | Address Bus A 110 | | $6000-$7FFF | Slow | Address Bus A 111 | | $8000-$FFFF | Slow | Address Bus A + /CART 112 | ---------+-------------+-------+--------- 113 | $40-$7D | $0000-$FFFF | Slow | Address Bus A + /CART 114 | ---------+-------------+-------+--------- 115 | $7E-$7F | $0000-$FFFF | Slow | Address Bus A + /WRAM 116 | ---------+-------------+-------+--------- 117 | $80-$BF | $0000-$1FFF | Slow | Address Bus A + /WRAM (mirror $7E:0000-$1FFF) 118 | | $2000-$20FF | Fast | Address Bus A 119 | | $2100-$21FF | Fast | Address Bus B 120 | | $2200-$3FFF | Fast | Address Bus A 121 | | $4000-$41FF | XSlow | Internal CPU registers (see Note 1 below) 122 | | $4200-$43FF | Fast | Internal CPU registers (see Note 1 below) 123 | | $4400-$5FFF | Fast | Address Bus A 124 | | $6000-$7FFF | Slow | Address Bus A 125 | | $8000-$FFFF | Note2 | Address Bus A + /CART 126 | ---------+-------------+-------+--------- 127 | $C0-$FF | $0000-$FFFF | Note2 | Address Bus A + /CART 128 | 129 | Note 1: The address for internal CPU registers may go out Address Bus A, 130 | however the CPU ignores the data bus. It is unknown whether the data bus 131 | is ignored for the whole memory region, or just for those addresses which 132 | are actually registers. It is also unknown whether CPU writes show up on 133 | the data bus or not. Current theory is that addresses and writes will show 134 | up, but reads may or may not, and the data bus is only ignored for those 135 | bits of those registers actually mapped (e.g., data bus is ignored for only 136 | bit 7 of $4211). 137 | 138 | Note 2: If bit 0 of CPU register $420d is set, the speed is Fast, otherwise 139 | it is Slow. 140 | 141 | 142 | 143 | ============================================================================= 144 | HISTORY: 145 | 146 | Version 1.1: Jun 18, 2003 147 | * Tested the memory access speed of all 256-byte memory blocks, and filled in 148 | the table with the findings. 149 | 150 | Version 1.0: 151 | * Initial version. 152 | -------------------------------------------------------------------------------- /others/anomie/ob-wrap.txt: -------------------------------------------------------------------------------- 1 | ============================================================================= 2 | Anomie's SNES OpenBus & Wrapping Doc 3 | $Revision: 1126 $ 4 | $Date: 2007-04-21 15:07:05 -0400 (Sat, 21 Apr 2007) $ 5 | 6 | ============================================================================= 7 | 8 | Open Bus 9 | -------- 10 | The theory is that the S-CPU chip has something called a "Memory Data Register" 11 | or MDR, which stores the value for every read/write. When you attempt to read 12 | from unmapped memory, no new value is supplied for this register and so you 13 | read the same old value over and over. 14 | 15 | Note that CPU IO cycles do not affect the MDR (and therefore the Open Bus 16 | value), even though the datasheet specifies addresses for those cycles. 17 | 18 | Note that JSL a pushes the old PB before reading the new PB, in case the new PB 19 | is being read from Open Bus. Also note that JSR (a,X) pushes the old address 20 | (low byte second) before reading the high byte of the new address. 21 | 22 | The PPU chips also each have their own MDR, which is updated only when said PPU 23 | chip is read. When you read a register with unmapped bits, the PPU fills in 24 | only those bits that are defined and leaves the remaining bits as the MDR has 25 | them. PPU1's MDR is set by reading $2134-6 or $2138-A, and may also be read 26 | from the write-only registers $21x4-6 and $21x8-A (x=0-2). PPU2 involves 27 | registers $213B-D only (and maybe $21xB-D, but this is unverified). 28 | 29 | 30 | Instruction Wrapping 31 | -------------------- 32 | These are my results: 33 | 34 | * Program Counter Increment 35 | - Always wraps within the bank, at any point in the opcode. 36 | 37 | * Absolute -- a 38 | - Word reads in native mode will carry into the next bank. 39 | 40 | * Absolute Indexed X -- a,X 41 | - Adding X may carry into the next bank. 42 | - Word reads in native mode will carry into the next bank. 43 | 44 | * Absolute Indexed Y -- a,Y 45 | - Adding Y may carry into the next bank. 46 | - Word reads in native mode will carry into the next bank. 47 | 48 | * Absolute Indirect -- (a) 49 | - The "JMP ($xxFF)" bug is fixed. 50 | - There's no way to test address load wrapping behavior, since it uses Bank 51 | 0 as the base and $01:0000-1 is a mirror of $00:0000-1. 52 | - To be clear: the actual JMP will go to the loaded offset in the current 53 | PB, not Bank 0. 54 | 55 | * Absolute Indexed Indirect -- (a,X) 56 | - Adding X will wrap within the current bank. 57 | - Address load wraps within the bank (remember, this loads the target 58 | address from PB:a+X, not 00:a like (a) or DB:a+X like (a,X). 59 | 60 | * Absolute Long -- l 61 | - Word reads in native mode will carry into the next bank. 62 | 63 | * Absolute Long Indexed X -- l,X 64 | - Adding X may carry into the next bank. 65 | - Word reads in native mode will carry into the next bank. 66 | 67 | * Direct -- d 68 | - Word reads in native mode will always carry across pages. Theoretically, 69 | word reads in emulation mode will wrap within the page when DL=0, and 70 | carry when DL!=0. 71 | 72 | * Direct Indirect -- (d) 73 | - Address load: see 'Direct' above. 74 | - Data load: Word reads in native mode will carry across pages and banks. 75 | 76 | * Direct Indirect Long -- [d] 77 | - Address load: Always carries across pages. 78 | - Data load: Word reads in native mode will carry across pages and banks. 79 | 80 | * Direct Indirect Indexed -- (d),Y 81 | - Address load: see 'Direct Indirect' above. 82 | - When Y is added to the indirect address, it will always carry across banks. 83 | - Data load: Word reads in native mode will carry across pages and banks. 84 | 85 | * Direct Indirect Indexed Long -- [d],Y 86 | - Address load: see 'Direct Indirect Long' above. 87 | - When Y is added to the indirect address, it will always carry across banks. 88 | - Data load: Word reads in native mode will carry across pages and banks. 89 | 90 | * Direct Indexed X -- d,X 91 | - In native mode, always carry across pages. 92 | - In emulation mode, wrap within page if DL=0, otherwise carry. 93 | - Word reads in native mode will always carry across pages. Theoretically 94 | word reads in emulation mode will wrap within the page when DL=0, and 95 | carry when DL!=0. 96 | - Reads will NOT carry across banks! 97 | e.g. D=$8001, d=1, X=fffe => $00:8000, not $01:8000. 98 | 99 | * Direct Indexed Y -- d,Y 100 | - Same as Direct Indexed X 101 | 102 | * Direct Indexed Indirect -- (d,X) 103 | - For address load, see 'Direct Indexed X' above. 104 | - Data load: Word reads in native mode will carry across pages and banks. 105 | 106 | * PC Relative -- r 107 | - XXX: untested 108 | 109 | * PC Relative Long -- rl 110 | - XXX: untested 111 | 112 | * Stack Relative - d,S 113 | - The address always carries across page boundaries. Yes, this means it can 114 | exit the emulation mode stack page. 115 | 116 | * Stack Relative Indirect Indexed -- (d,S),Y 117 | - Address load: see 'Stack Relative' above. 118 | - When Y is added to the indirect address, it will always carry across banks. 119 | - Data load: Word reads in native mode will carry across pages and banks. 120 | 121 | * Block Move 122 | - Note that when E=1, X and Y are limited to 8 bits, so everything stays in 123 | $00xx. 124 | 125 | * Stack Ops 126 | - When E=1, SH is always 1 and so the stack will normally remain within 127 | $01xx. 128 | - According to the datasheet, the following will somehow access outside 129 | $01xx even in emulation mode: JSL; JSR (a,X); PEA; PEI; PER; PHD; PLD; 130 | RTL; d,S; (d,S),Y. This is confirmed for PEA; PLD; d,S; and (d,S),Y. 131 | - If S=0100, PEA will overwrite $0100 and $00ff, and S will end up being 132 | 01FE. $01FF will be unchanged. Obviously, a pull here will not read the 133 | data you just PEAed. 134 | - Similarly, a PLD at S=01FF will read D from $200, not $100 (OTOH a PLY 135 | will read Y from $100 as expected). 136 | -------------------------------------------------------------------------------- /others/anomie/ports.txt: -------------------------------------------------------------------------------- 1 | ============================================================================= 2 | Anomie's SNES Port Doc 3 | $Revision: 1132 $ 4 | $Date: 2007-04-27 19:31:57 -0400 (Fri, 27 Apr 2007) $ 5 | 6 | ============================================================================= 7 | 8 | This is a document intended to describe the various hardware ports on the 9 | SNES. It will not describe how these ports are used by what may be plugged 10 | into them. 11 | 12 | In the doc below, "active", "1", "logic-1", and so forth all mean the same 13 | thing. Note that "1" does not necessarily correspond to either high or low 14 | voltage. (BTW, i could use some help here: if anyone knows whether anything 15 | is active-high or active-low, or what the voltages for high and low are for 16 | any particular port, please let me know!) 17 | 18 | 19 | CONTROLLER PORTS 20 | ================ 21 | 22 | The controller ports of the SNES has 7 pins, laid out something like this: 23 | _________________ ____________ 24 | | | \ 25 | | (1) (2) (3) (4) | (5) (6) (7) | 26 | |_________________|____________/ 27 | 28 | The pins are: 29 | 1: +5v (power) 30 | 2: Clock 31 | 3: Latch 32 | 4: Data1 33 | 5: Data2 34 | 6: IOBit 35 | 7: Ground 36 | 37 | Latch is written through bit 0 of register $4016. Writing 1 to this bit 38 | results in Latch going to whatever state means 'latch' to a joypad. 39 | 40 | Clock of Port 1 is connected to the 'read' signal of $4016, in that reading 41 | $4016 causes Clock to transition. Data1 and Data2 are then read, and Clock 42 | transitions back (at this point, the pad is expected to stick its next bits 43 | of data on Data1 and Data2). Clock of Port 2 is connected to $4017. 44 | 45 | Data1 and Data2 are read through bits 0 and 1 (respectively) of $4016 and 46 | $4017 (for Ports 1 and 2, respectively). Thus, you must read both bits at 47 | once, you can't choose to read only Data1 and leave Data2 for later. 48 | 49 | IOBit is connected to the I/O Port (which is accessed through registers 50 | $4201 and $4213). Port 1's IOBit is connected to bit 6 of the I/O Port, and 51 | Port 2's IOBit is connected to bit 7. Note that, since bit 7 of the I/O Port 52 | is connected to the PPU Counter Latch, anything plugged into Port 2 may 53 | latch the H and V Counters by setting IOBit to 0. 54 | 55 | Data1 and Data2 are pulled to logic-0 within the SNES, so reads will return 56 | 0 if nothing is plugged in. 57 | 58 | 59 | CART CONNECTOR 60 | ============== 61 | 62 | The cart connector has 62 pads, laid out something like this: 63 | +--------+ 64 | 21.477MHz Clock | 1 32 | /WRAM 65 | EXPAND | 2 33 | REFRESH 66 | PA6 | 3 34 | PA7 67 | /PARD | 4 35 | /PAWR 68 | GND | 5 36 | GND 69 | F A11 | 6 37 | A12 70 | r A10 | 7 38 | A13 71 | o A9 | 8 39 | A14 72 | n A8 | 9 40 | A15 73 | t A7 | 10 41 | A16 74 | A6 | 11 42 | A17 75 | o A5 | 12 43 | A18 76 | f A4 | 13 44 | A19 77 | A3 | 14 45 | A20 78 | c A2 | 15 46 | A21 79 | a A1 | 16 47 | A22 80 | r A0 | 17 48 | A23 81 | t /IRQ | 18 49 | /CART 82 | D0 | 19 50 | D4 83 | D1 | 20 51 | D5 84 | D2 | 21 52 | D6 85 | D3 | 22 53 | D7 86 | /RD | 23 54 | /WR 87 | CIC out data (p1) | 24 55 | CIC out data (p2) 88 | CIC in data (p7) | 25 56 | CIC in clock (p6) 89 | /RESET | 26 57 | CPU_CLOCK 90 | Vcc | 27 58 | Vcc 91 | PA0 | 28 59 | PA1 92 | PA2 | 29 60 | PA3 93 | PA4 | 30 61 | PA5 94 | Left Audio Input | 31 62 | Right Audio Input 95 | +--------+ 96 | 97 | A0-A23 are the Address Bus A lines, /WR and /RD are the associated read 98 | and write lines, and /CART and /WRAM are the two auxiliary lines. 99 | 100 | PA0-PA7 are the Address Bus B lines, with /PARD and /PAWR the associated 101 | read and write lines. 102 | 103 | D0-D7 are the data bus lines. 104 | 105 | REFRESH is (presumably) the RAM refresh signal sent out each scanline for 40 106 | master cycles. 107 | 108 | EXPAND is connected to pad 24 of the expansion port. 109 | 110 | /IRQ is connected to the CPU's /IRQ line. This can be read by the cart, or 111 | activated by the cart to invoke an IRQ on the CPU. 112 | 113 | /RESET is the reset signal, activated by the big reset button on the 114 | console. It can also be activated by hardware on the cart, if the system needs 115 | to be reset at a hardware level. 116 | 117 | CPU_CLOCK is (presumably) the current CPU cycle clock, which is either 6, 8, 118 | or 12 master cycles per cycle (3.58MHz, 2.68MHz, or 1.79MHz). 119 | 120 | The signals input on Left and Right Audio Inputs are mixed into the APU's 121 | output audio. 122 | 123 | The CIC pins are connected to the CIC chip, which is used for region 124 | lockouts. If the CIC in the console doesn't get the proper handshake over 125 | these pads, the reset signal is never released on the PPU2 chip, and so you 126 | never get anything on the display. 127 | 128 | Many carts connect only to pins 5-27 and 36-58, as the remaining pins are 129 | mainly useful only if the cart contains special chips. 130 | 131 | 132 | EXPANSION PORT 133 | ============== 134 | 135 | The expansion port has 28 pads, laid out something like this. Note that I 136 | have no idea which side of this is towards the front of the SNES, nor 137 | whether this is the numbering looking into the console or into the cable. 138 | +--------+ 139 | PA0 | 1 2 | PA1 140 | PA2 | 3 4 | PA3 141 | PA4 | 5 6 | PA5 142 | PA6 | 7 8 | PA7 143 | /PAWR | 9 10 | /PARD 144 | D0 | 11 12 | D1 145 | D2 | 13 14 | D3 146 | D4 | 15 16 | D5 147 | D6 | 17 18 | D7 148 | /RESET | 19 20 | Vcc 149 | SMPCLK | 21 22 | DOTCK 150 | GND | 23 24 | EXPAND 151 | Mono Audio Out | 25 26 | /IRQ 152 | Left Audio In | 27 28 | Right Audio In 153 | +--------+ 154 | 155 | PA0-PA7 are the Address Bus B lines, with /PARD and /PAWR the associated 156 | read and write lines. 157 | 158 | D0-D7 are the data bus lines. 159 | 160 | /RESET is the reset signal, activated by the big reset button on the console. 161 | It can also be activated by hardware on the attached device, if the system 162 | needs to be reset at a hardware level. 163 | 164 | EXPAND is connected to pad 2 of the cart connector. 165 | 166 | /IRQ is connected to the CPU's /IRQ line. This can be read by the attached 167 | device, or activated by the attached device to invoke an IRQ on the CPU. 168 | 169 | The signals input on Left and Right Audio Inputs are mixed into the APU's 170 | output audio. The (mono) audio output is brought back into pin 25. 171 | 172 | SMPCLK and DOTCK are not really known. SMPCLK comes from the audio subsystem, 173 | reports are that it's about 8.192MHz (i.e. 3 APU master clock cycles per 174 | cycle). DOTCK comes from PPU2, and seems to be PPU dot clock at about 5.369 175 | MHz (that's 21.477/4). 176 | 177 | MULTI-OUT 178 | ========= 179 | 180 | The multi-out port has 12 pads, and looks something like this: 181 | 182 | --------^-------- 183 | /11 9 7 5 3 1\ 184 | | | 185 | \12 10 8 6 4 2/ 186 | ----------------- 187 | 188 | 1: Red analog out 189 | 2: Green analog out 190 | 3: Composite H/V sync out (+11V DC on PAL) 191 | 4: Blue analog out 192 | 5: GND 193 | 6: GND 194 | 7: S-VHS Y (luminance) signal 195 | 8: S-VHS C (chroma) signal 196 | 9: Composite video signal 197 | 10: Vcc 198 | 11: Mid sound (L+R) 199 | 12: Side sound (L-R) 200 | 201 | Note: this data from http://www.thepong.com/Sites/Left/Nintendo/SNTech.htm 202 | 203 | 204 | RF OUT 205 | ====== 206 | 207 | I know nothing about the output of this port, except that it has a Vcc, a 208 | GND, a video signal, and a mono audio signal. 209 | 210 | 211 | POWER 212 | ===== 213 | 214 | This one is simple. It's a hollow cylindrical plug. It expects to be 215 | supplied with DC 10V, 850mA, with negative in the center and positive on the 216 | outside. 217 | 218 | 219 | ============================================================================= 220 | HISTORY: 221 | 222 | Version 1.0: 223 | * Initial version. 224 | -------------------------------------------------------------------------------- /others/anomie/spc700cyc.txt: -------------------------------------------------------------------------------- 1 | ============================================================================= 2 | Anomie's SPC700 Cycle Doc 3 | $Revision: 1126 $ 4 | $Date: 2007-04-21 15:07:05 -0400 (Sat, 21 Apr 2007) $ 5 | 6 | ============================================================================= 7 | 8 | 1 Register, Immediate -- A,#i; X,#i; Y,#i 9 | (ADC,AND,CMP,CMP,CMP,EOR,MOV,MOV,MOV,OR,SBC) 10 | (2 bytes) 11 | (2 cycles) 12 | 1 PC Op Code 1 13 | 2 PC+1 Data 1 14 | * This should be accurate. 15 | 16 | 2 Register, Register -- A,X; A,Y; X,A; X,Y; Y,A; Y,X; SP,X; X,SP 17 | (MOV,MOV,MOV,MOV,MOV,MOV) 18 | (1 byte) 19 | (2 cycles) 20 | 1 PC Op Code 1 21 | 2 ?? IO ? 22 | * This should be accurate. 23 | 24 | 3 Register, Direct -- A,d; X,d; Y,d 25 | (ADC,AND,CMP,CMP,CMP,EOR,MOV,MOV,MOV,OR,SBC) 26 | (2 bytes) 27 | (3 cycles) 28 | 1 PC Op Code 1 29 | 2 PC+1 DO 1 30 | 3 DO Data 1 31 | * Verified by blargg. 32 | 33 | 4 Register, Direct Indexed -- A,d+X; X,d+Y; Y,d+X 34 | (ADC,AND,CMP,EOR,MOV,MOV,MOV,OR,SBC) 35 | (2 bytes) 36 | (4 cycles) 37 | 1 PC Op Code 1 38 | 2 PC+1 DO 1 39 | 3 ?? IO ? 40 | 4 DO Data 1 41 | * blargg verified Data read is cycle 4. 42 | * 2 and 3 could be swapped, but that would be odd. 43 | 44 | 5a Register, Indirect -- A,(X) 45 | (ADC,AND,CMP,EOR,MOV,OR,SBC) 46 | (1 byte) 47 | (3 cycles) 48 | 1 PC Op Code 1 49 | 2 ?? IO ? 50 | 3 X Data 1 51 | * Verified by blargg. 52 | 53 | 5b Register, Indirect++ -- A,(X)+ 54 | (MOV) 55 | (1 byte) 56 | (4 cycles) 57 | 1 PC Op Code 1 58 | 2 ?? IO ? 59 | 3 X Data 1 60 | 4 ?? IO ? 61 | * Verified by blargg. 62 | 63 | 6 Register, Indexed Indirect -- A,[d+X] 64 | (ADC,AND,CMP,EOR,MOV,OR,SBC) 65 | (2 bytes) 66 | (6 cycles) 67 | 1 PC Op Code 1 68 | 2 PC+1 DO 1 69 | 3 ?? IO ? 70 | 4 DO+X AAL 1 71 | 5 DO+X+1 AAH 1 72 | 6 AA Data 1 73 | * blargg verifies the Data read is cycle 6. 74 | * Cycles 2-5 could be rearranged, but this is most likely. 75 | 76 | 7 Register, Indirect Indexed -- A,[d]+Y 77 | (ADC,AND,CMP,EOR,MOV,OR,SBC) 78 | (2 bytes) 79 | (6 cycles) 80 | 1 PC Op Code 1 81 | 2 PC+1 DO 1 82 | 3 DO AAL 1 83 | 4 DO+1 AAH 1 84 | 5 ?? IO ? 85 | 6 AA+Y Data 1 86 | * blargg verifies the Data read is cycle 6. 87 | * Cycles 2-5 could be rearranged, but this is most likely. 88 | 89 | 8 Register, Absolute -- A,!a; X,!a; Y,!a 90 | (ADC,AND,CMP,CMP,CMP,EOR,MOV,MOV,MOV,OR,SBC) 91 | (3 bytes) 92 | (4 cycles) 93 | 1 PC Op Code 1 94 | 2 PC+1 AAL 1 95 | 3 PC+2 AAH 1 96 | 4 AA Data 1 97 | * Verified by blargg. 98 | * 2 and 3 could be swapped, but that would be odd. 99 | 100 | 9 Register, Absolute Indexed -- A,!a+X; A,!a+Y 101 | (ADC,ADC,AND,AND,CMP,CMP,EOR,EOR,MOV,MOV,OR,OR,SBC,SBC) 102 | (3 bytes) 103 | (5 cycles) 104 | 1 PC Op Code 1 105 | 2 PC+1 AAL 1 106 | 3 PC+2 AAH 1 107 | 4 ?? IO ? 108 | 5 AA+X/Y Data 1 109 | * blargg verifies Data read is cycle 5. 110 | * Cycles 2-4 could be in other orders, but this is most likely. 111 | 112 | 10 Direct, Immediate -- d,#i 113 | (ADC,AND,CMP,EOR,MOV,OR,SBC) 114 | (3 bytes) 115 | (5 cycles) 116 | 1 PC Op Code 1 117 | 2 PC+1 Data 1 1 118 | 3 PC+2 DO 1 119 | 4 DO Data 2 (read) 1 120 | 5 DO Data 2 (write) 0 121 | * Verified by blargg. 2 and 3 could be swapped, but that's unlikely. 122 | * Yes, RMW even for MOV. 123 | * CMP does not write for cycle 5; does it IO or read again? 124 | 125 | 11 Direct, Register -- d,A; d,X; d,Y 126 | (MOV,MOV,MOV) 127 | (2 bytes) 128 | (4 cycles) 129 | 1 PC Op Code 1 130 | 2 PC+1 DO 1 131 | 3 DO Data (read) 1 132 | 4 DO Data (write) 0 133 | * Verified by blargg. 134 | * Yes, RMW even for MOV 135 | 136 | 12 Direct Indexed, Register -- d+X,A; d+X,Y; d+Y,X 137 | (MOV,MOV,MOV) 138 | (2 bytes) 139 | (5 cycles) 140 | 1 PC Op Code 1 141 | 2 PC+1 DO 1 142 | 3 ?? IO 1 143 | 4 DO+X/Y Data (read) 1 144 | 5 DO+X/Y Data (write) 0 145 | * Verified by blargg. 2 and 3 could be swapped, but that's unlikely. 146 | * Yes, RMW even for MOV 147 | 148 | 13a Indirect, Register -- (X),A 149 | (MOV) 150 | (1 byte) 151 | (4 cycles) 152 | 1 PC Op Code 1 153 | 2 ?? IO ? 154 | 3 X Data (read) 1 155 | 4 X Data (write) 0 156 | * Verified by blargg. 157 | * Yes, RMW even for MOV 158 | 159 | 13b Indirect++, Register -- (X)+,A 160 | (MOV) 161 | (1 byte) 162 | (4 cycles) 163 | 1 PC Op Code 1 164 | 2 ?? IO ? 165 | 3 ?? IO ? 166 | 4 DO Data (write) 0 167 | * Verified by blargg. 168 | * No RMW here 169 | 170 | 14 Indexed Indirect, Register -- [d+X],A 171 | (MOV) 172 | (2 bytes) 173 | (7 cycles) 174 | 1 PC Op Code 1 175 | 2 PC+1 DO 1 176 | 3 ?? IO ? 177 | 4 DO+X AAL 1 178 | 5 DO+X+1 AAH 1 179 | 6 AA Data (read) 1 180 | 7 AA Data (write) 0 181 | * blargg verifies cycles 6 and 7. 182 | * Yes, RMW even for MOV 183 | 184 | 15 Indirect Indexed, Register -- [d]+Y,A 185 | (MOV) 186 | (2 bytes) 187 | (7 cycles) 188 | 1 PC Op Code 1 189 | 2 PC+1 DO 1 190 | 3 DO AAL 1 191 | 4 DO+1 AAH 1 192 | 5 ?? IO ? 193 | 6 AA+Y Data (read) 1 194 | 7 AA+Y Data (write) 0 195 | * blargg verifies cycles 6 and 7. 196 | * Yes, RMW even for MOV 197 | 198 | 16 Absolute, Register -- !a,A; !a,X; !a,Y 199 | (MOV,MOV,MOV) 200 | (3 bytes) 201 | (5 cycles) 202 | 1 PC Op Code 1 203 | 2 PC+1 AAL 1 204 | 3 PC+2 AAH 1 205 | 4 AA Data (read) 1 206 | 5 AA Data (write) 0 207 | * Verified by blargg. 2 and 3 could be swapped, but that's unlikely. 208 | * Yes, RMW even for MOV 209 | 210 | 17 Absolute Indexed, Register -- !a+X,A; !a+Y,A 211 | (MOV,MOV) 212 | (3 bytes) 213 | (6 cycles) 214 | 1 PC Op Code 1 215 | 2 PC+1 AAL 1 216 | 3 PC+2 AAH 1 217 | 4 ?? IO ? 218 | 5 AA+X/Y Data (read) 1 219 | 6 AA+X/Y Data (write) 0 220 | * blargg verified cycles 5 and 6. 221 | * Yes, RMW even for MOV 222 | 223 | 18 Direct, Direct -- dd,ds 224 | (ADC,AND,CMP,EOR,MOV,OR,SBC) 225 | (3 bytes) 226 | (5 or 6 cycles) 227 | 1 PC Op Code 1 228 | 2 PC+1 DS 1 229 | 3 DS Data 1 1 230 | 4 PC+2 DD 1 231 | [5] DD Data 2 (read) 1 232 | 6 DD Data 2 (write) 0 233 | * Verified by blargg. 234 | * Skip cycle 5 for MOV, no RMW. 235 | * CMP does not write for cycle 6; does it IO or read again? 236 | 237 | 19 Indirect, Indirect -- (X),(Y) 238 | (ADC,AND,CMP,EOR,OR,SBC) 239 | (1 byte) 240 | (5 cycles) 241 | 1 PC Op Code 1 242 | 2 ?? IO ? 243 | 3 Y Data 1 1 244 | 4 X Data 2 (read) 1 245 | 5 X Data 2 (write) 0 246 | * Verified by blargg. 247 | * CMP does not write for cycle 5; it is an IO cycle. 248 | 249 | 20a Direct (RMW) -- d 250 | (ASL,CLR1,DEC,INC,LSR,ROL,ROR,SET1) 251 | (2 bytes) 252 | (4 cycles) 253 | 1 PC Op Code 1 254 | 2 PC+1 DO 1 255 | 3 DO Data (read) 1 256 | 4 DO Data (write) 0 257 | * Verified by blargg. 258 | 259 | 20b Direct (RMW) -- m.b 260 | (NOT1) 261 | (3 bytes) 262 | (5 cycles) 263 | 1 PC Op Code 1 264 | 2 PC+1 AAL 1 265 | 3 PC+2 AAH & BIT 1 266 | 4 DO Data (read) 1 267 | 5 DO Data (write) 0 268 | * Verified by blargg. 2 and 3 could be swapped, but that's unlikely. 269 | 270 | 21 Direct Indexed (RMW) -- d+X 271 | (ASL,DEC,INC,LSR,ROL,ROR) 272 | (2 bytes) 273 | (5 cycles) 274 | 1 PC Op Code 1 275 | 2 PC+1 DO 1 276 | 3 ?? IO ? 277 | 4 DO Data (read) 1 278 | 5 DO Data (write) 0 279 | * blargg verified cycles 4 and 5. 280 | * 2 and 3 could be swapped, but that would be odd. 281 | 282 | 22 Absolute (RMW) -- !a 283 | (ASL,DEC,INC,LSR,ROL,ROR,TCLR1,TSET1) 284 | (3 bytes) 285 | (5 or 6 cycles) 286 | 1 PC Op Code 1 287 | 2 PC+1 AAL 1 288 | 3 PC+2 AAH 1 289 | [4] AA Data (read) 1 290 | 5 AA Data (read) 1 291 | 6 AA Data (write) 1 292 | * Verified by blargg. 293 | * 2 and 3 could be swapped, but that would be odd. 294 | * Cycle 4 only for TSET1 and TCLR1. 295 | 296 | 23 Carry, MemBit -- C,m.b; C,/m.b 297 | (AND1,AND1,MOV1,EOR1,OR1,OR1) 298 | (3 bytes) 299 | (4 or 5 cycles) 300 | 1 PC Op Code 1 301 | 2 PC+1 AAL 1 302 | 3 PC+2 AAH & BIT 1 303 | 4 AA Data 1 304 | [5] ?? IO ? 305 | * Verified by blargg. 306 | * Cycle 5 present only in EOR1 and OR1. 307 | 308 | 24 MemBit, Carry -- m.b,C 309 | MOV1 m.b, C CA 3 6 (m.b) = C ........ 310 | (MOV1) 311 | (3 bytes) 312 | (6 cycles) 313 | 1 PC Op Code 1 314 | 2 PC+1 AAL 1 315 | 3 PC+2 AAH & BIT 1 316 | 4 AA Data (read) 1 317 | 5 ?? IO ? 318 | 6 AA Data (write) 0 319 | * Verified by blargg. 2 and 3 could be swapped, but that's unlikely. 320 | 321 | 25 Implied 322 | (ASL,CLRC,CLRP,CLRV,DAA,DAS,DEC,DEC,DEC,DI,DIV,EI,INC,INC,INC,LSR,MUL,NOP, 323 | NOTC,ROL,ROR,SETC,SETP,XCN) 324 | (1 byte) 325 | (2, 3, 5, 9, or 12 cycles) 326 | 1 PC Op Code 1 327 | 2 ?? IO ? 328 | [3-12] ?? IO ? 329 | * This should be accurate. 330 | * The common theme here is that all these do no memory accesses. 331 | 332 | 26 Word-Register, Direct -- YA,d 333 | (ADDW,CMPW,MOVW,SUBW) 334 | (2 bytes) 335 | (4 or 5 cycles) 336 | 1 PC Op Code 1 337 | 2 PC+1 DO 1 338 | 3 DO Data 1 Low 1 339 | [4] ?? IO ? 340 | 5 DO+1 Data 1 High 1 341 | * Verified by blargg. 342 | * No cycle 4 for CMPW 343 | 344 | 27 Direct, Word-Register, Direct -- d,YA 345 | (MOVW) 346 | (2 bytes) 347 | (5 cycles) 348 | 1 PC Op Code 1 349 | 2 PC+1 DO 1 350 | 3 DO Data Low (read) 1 351 | 4 DO Data Low 0 352 | 5 DO+1 Data High 0 353 | * Verified by blargg. 354 | * Yes, RMW on low byte only... 355 | 356 | 28 Word-Direct (RMW) -- d 357 | (DECW,INCW) 358 | (2 bytes) 359 | (6 cycles) 360 | 1 PC Op Code 1 361 | 2 PC+1 DO 1 362 | 3 DO Data 1 Low 1 363 | 4 DO Data 1 Low 0 364 | 5 DO+1 Data 1 High 1 365 | 6 DO+1 Data 1 High 0 366 | * Verified by blargg. 367 | 368 | 29 Stack Ops 369 | (POP,POP,POP,POP,PUSH,PUSH,PUSH,PUSH) 370 | (1 byte) 371 | (4 cycles) 372 | 1 PC Op Code 1 373 | 2 ?? IO ? 374 | 3 S Data 0/1 375 | 4 ?? IO ? 376 | * Or is it Data-IO-IO or IO-IO-Data? 377 | 378 | 379 | 30a JMP Absolute -- !a 380 | (JMP) 381 | (3 bytes) 382 | (3 cycles) 383 | 1 PC Op Code 1 384 | 2 PC+1 AAL 1 385 | 3 PC+2 AAH 1 386 | (1) New PC Op Code 1 387 | * This should be accurate. 388 | 389 | 30b JMP Absolute Indexed Indirect -- [!a+X] 390 | (JMP) 391 | (3 bytes) 392 | (6 cycles) 393 | 1 PC Op Code 1 394 | 2 PC+1 AAL 1 395 | 3 PC+2 AAH 1 396 | 4 ?? IO ? 397 | 5 AA PCL 1 398 | 6 AA+1 PCH 1 399 | (1) New PC Op Code 1 400 | * This should be fairly accurate. 401 | * Any penalty for AA+X crossing pages? 402 | 403 | 31a Branch -- r 404 | (BCC,BCS,BEQ,BMI,BNE,BPL,BVC,BVS,BRA) 405 | (2 bytes) 406 | (2 or 4 cycles) 407 | 1 PC Op Code 1 408 | 2 PC+1 R 1 409 | [3] ?? IO ? 410 | [4] ?? IO ? 411 | * This should be accurate. 412 | * Cycles 3 and 4 only present if branch is taken. 413 | * BRA always takes the branch. 414 | 415 | 21b Test-and-Branch Direct -- d,r; d.b,r 416 | (BBC,BBS,CBNE) 417 | (3 bytes) 418 | (5 or 7 cycles) 419 | 1 PC Op Code 1 420 | 2 PC+1 DO 1 421 | 3 DO Data 1 422 | 4 PC+2 R 1 423 | 5 ?? IO ? 424 | [6] ?? IO ? 425 | [7] ?? IO ? 426 | * Cycles 6 and 7 only present if branch is taken 427 | * Cycles 1-3 are verified by blargg. 428 | 429 | 31c Test-and-Branch Direct Indexed -- d+X,r 430 | (CBNE) 431 | (3 bytes) 432 | (6 or 8 cycles) 433 | 1 PC Op Code 1 434 | 2 PC+1 DO 1 435 | 3 ?? IO ? 436 | 4 DO+X Data 1 437 | 5 PC+2 R 1 438 | 6 ?? IO ? 439 | [7] ?? IO ? 440 | [8] ?? IO ? 441 | * blargg verifies Data read is cycle 4; the rest is guesswork. 442 | * Order of cycles is unknown, except the two extras are probably are at the 443 | end. 444 | 445 | 31d Modify-and-Branch Direct -- d,r; d.b,r 446 | (DBNZ) 447 | (3 bytes) 448 | (5 or 7 cycles) 449 | 1 PC Op Code 1 450 | 2 PC+1 DO 1 451 | 3 DO Data (read) 1 452 | 4 DO Data-1 (write) 0 453 | 5 PC+2 R 1 454 | [6] ?? IO ? 455 | [7] ?? IO ? 456 | * blargg verifies cycles 3 and 4. 457 | * Cycles 6 and 7 only present if branch is taken 458 | * Order of cycles is unknown, except the two extras are probably are at the 459 | end. 460 | 461 | 31e Modify-and-Branch Register -- Y,r 462 | (DBNZ) 463 | (2 bytes) 464 | (4 or 6 cycles) 465 | 1 PC Op Code 1 466 | 2 PC+1 R 1 467 | 3 ?? IO ? 468 | 4 ?? IO ? 469 | [5] ?? IO ? 470 | [6] ?? IO ? 471 | * Cycles 5 and 6 only present if branch is taken 472 | * Order of cycles is unknown, except the two extras are probably are at the 473 | end. 474 | 475 | 32a CALL 476 | (CALL) 477 | (3 bytes) 478 | (8 cycles) 479 | 1 PC Op Code 1 480 | 2 SP PCH 0 481 | 3 SP-1 PCL 0 482 | 4 ?? IO ? 483 | 5 PC+1 AAL 1 484 | 6 PC+2 AAH 1 485 | 7 ?? IO ? 486 | 8 ?? IO ? 487 | (1) new PC Op Code 1 488 | * WTF with all the IO cycles? 489 | * Order of reading new addr and pushing old addr may be wrong. 490 | 491 | 32b PCALL 492 | (PCALL) 493 | (2 bytes) 494 | (6 cycles) 495 | 1 PC Op Code 1 496 | 2 SP PCH 0 497 | 3 SP-1 PCL 0 498 | 4 PC+1 U 1 499 | 5 Vec AAL 1 500 | 6 Vec+1 AAH 1 501 | (1) new PC Op Code 1 502 | * Order of reading new addr and pushing old addr may be wrong. 503 | 504 | 32c TCALL 505 | (TCALL) 506 | (1 byte) 507 | (8 cycles) 508 | 1 PC Op Code 1 509 | 2 SP PCH 0 510 | 3 SP-1 PCL 0 511 | 4 ?? IO ? 512 | 5 Vec AAL 1 513 | 6 Vec+1 AAH 1 514 | 7 ?? IO ? 515 | 8 ?? IO ? 516 | (1) new PC Op Code 1 517 | * WTF with all the IO cycles? 518 | * Order of reading new addr and pushing old addr may be wrong. 519 | 520 | 32d BRK 521 | (BRK) 522 | (1 byte) 523 | (8 cycles) 524 | 1 PC Op Code 1 525 | 2 SP PCH 0 526 | 3 SP-1 PCL 0 527 | 4 SP-2 PSW 0 528 | 5 $FFDE AAL 1 529 | 6 $FFDF AAH 1 530 | 7 ?? IO ? 531 | 8 ?? IO ? 532 | (1) new PC Op Code 1 533 | * WTF with all the IO cycles? 534 | * Order of reading new addr and pushing old addr may be wrong. 535 | 536 | 33a RET 537 | (RET) 538 | (1 byte) 539 | (5 cycles) 540 | 1 PC Op Code 1 541 | 2 SP PCL 0 542 | 3 SP+1 PCH 0 543 | 4 ?? IO ? 544 | 5 ?? IO ? 545 | (1) new PC Op Code 1 546 | * WTF with all the IO cycles? 547 | 548 | 33b RET1 549 | (RET1) 550 | (1 byte) 551 | (6 cycles) 552 | 1 PC Op Code 1 553 | 2 SP PSW 0 554 | 3 SP+1 PCL 0 555 | 4 SP+2 PCH 0 556 | 5 ?? IO ? 557 | 6 ?? IO ? 558 | (1) new PC Op Code 1 559 | * WTF with all the IO cycles? 560 | -------------------------------------------------------------------------------- /others/anomie/timing.txt: -------------------------------------------------------------------------------- 1 | ============================================================================= 2 | Anomie's SNES Timing Doc 3 | $Revision: 1160 $ 4 | $Date: 2008-12-21 12:40:39 -0500 (Sun, 21 Dec 2008) $ 5 | 6 | ============================================================================= 7 | 8 | This is a document intended to describe various aspects of SNES timing. It 9 | will probably not be useful unless you already know a good bit about the SNES. 10 | 11 | BTW, special credit to byuusan for the critical observation that the SNES 12 | returns to a known timing position on reset. Thus, a deterministic ROM (i.e. it 13 | doesn't depend on user input or any other randomness) will always give the same 14 | results on reset. And a series of ROMs which vary only in the master cycle 15 | count before testing some event (like the value of $4212) can tell us just when 16 | such events occur. 17 | 18 | A note on timings: stating that a bit set is at H=X means that a read that 19 | would latch X-.5 were it reading $2137 will see the bit not set, while a read 20 | that would latch X were it reading $2137 will see the bit set. The counter may 21 | also be latched by writing 0 to $4201 bit 7: this will latch 1 dot later than 22 | if the same memory access cycle were reading $2137. 23 | 24 | 25 | CONTENTS 26 | ======== 27 | 28 | - S-CPU (5A22) 29 | - Clocks & Refresh 30 | - Instructions 31 | - Interrupts 32 | - DMA 33 | - HDMA 34 | - Auto Joypad Read 35 | - Registers 36 | - S-PPU 37 | - Rendering 38 | - Blanking periods 39 | - Registers 40 | - OAM Reset 41 | - S-APU 42 | - SPC700 43 | - Clock 44 | - Instructions 45 | - Timers 46 | - DSP 47 | 48 | 49 | S-CPU (5A22) 50 | ============ 51 | 52 | CLOCKS & REFRESH 53 | ---------------- 54 | 55 | The SNES master clock runs at about 21.477MHz NTSC (theoretically 1.89e9/88 56 | Hz). The best number we have for PAL is 21.28137MHz. 57 | 58 | A CPU internal operation (an IO cycle) takes 6 master cycles. A memory access 59 | cycle takes 6, 8, or 12 master cycles, depending on the memory region accessed 60 | and bit 0 of CPU register $420d. 61 | 62 | The SNES runs 1 scanline every 1364 master cycles, except in non-interlace mode 63 | scanline $f0 of every other frame (those with $213f.7=1) is only 1360 cycles. 64 | Frames are 262 scanlines in non-interlace mode, while in interlace mode frames 65 | with $213f.7=0 are 263 scanlines. "V-Blank" runs from either scanline $e1 or 66 | $f0 until the end of the frame. 67 | 68 | The CPU is paused for 40 cycles beginning about 536 cycles after the start of 69 | each scanline. Current theory is that this is used for WRAM Refresh. The exact 70 | timing is that the refresh pause begins at 538 cycles into the first scanline 71 | of the first frame, and thereafter some multiple of 8 cycles after the previous 72 | pause that comes closest to 536. 73 | 74 | 75 | INSTRUCTIONS 76 | ------------ 77 | 78 | For specifics on particular instructions, see any generic 65816 doc. The GTE 79 | datasheet is particularly nice, as it identifies the CPU activity for each 80 | cycle of the instruction. 81 | 82 | To determine the exact length of any CPU instruction, you must examine its 83 | behavior for each cycle, and count 6, 8, or 12 master cycles as appropriate. 84 | 85 | The WAI instruction stops the processor. The processor restarts when either 86 | the /NMI or /IRQ line is low (or /RESET, but we don't care about that too 87 | much). It takes 12 master cycles (2 IO cycles) to end the WAI instruction, at 88 | which point the NMI or IRQ handler may actually be executed. 89 | 90 | 91 | INTERRUPTS 92 | ---------- 93 | 94 | The internal timer will set its NMI output low at H=0.5 at the beginning of 95 | V-Blank. The CPU's /NMI input is forced high by clearing bit 7 of register 96 | $4200, so the CPU may not actually see the NMI transition. The CPU will jump to 97 | the NMI routine at the end of the instruction during which /NMI transitions. 98 | 99 | The internal timer sets its NMI output high at H=0 V=0, or when register 100 | $4210 is read. Possibly also when $4200 is written? 101 | 102 | If the CPU is halted (i.e. for DMA) while /NMI goes low, the NMI will trigger 103 | after the DMA completes (even if /NMI goes high again before the DMA 104 | completes). In this case, there is a 24-30 cycle delay between the end of DMA 105 | and the NMI handler, time enough for an instruction or two. 106 | 107 | 108 | The internal timer will set its IRQ output low under the following conditions 109 | ('x' and 'y' are bits 4 and 5 of $4200, HTIME is registers $4207-8, and VTIME 110 | is $4209-a): 111 | yx trigger point 112 | 00 => Never 113 | 01 => H-IRQ: every scanline, H=HTIME+~3.5 114 | 10 => V-IRQ: V=VTIME, H=~2.5 115 | 11 => HV-IRQ: V=VTIME, H=HTIME+~3.5 116 | 117 | The actual formula for the trigger point is as follows. V-IRQ is just like 118 | HV-IRQ with H=0. If H=0, $4211 bit 7 gets set 1374 master cycles after dot 0.0 119 | of the previous scanline. Otherwise, it gets set 14+H*4 master cycles after 120 | dot 0.0 of the current scanline. Note that the 'dot offset' will change due to 121 | the two long dots per scanline. Also, no IRQ will trigger for dot 153 on the 122 | short scanline in non-interlace mode, and no IRQ will trigger for dot 153 on 123 | the last scanline of any frame. 124 | 125 | The internal timer will set its IRQ output high when $4211 is read, or when 126 | IRQs are disabled by a write to $4200. Note that the expansion port and the 127 | cart connector both have access to the /IRQ line, and may be able to trigger 128 | IRQs on their own. When enabling IRQs, the IRQ output will go low even if the 129 | enable write occurs at the exact cycle when the IRQ is scheduled to trigger 130 | For example, if HV-IRQ is set for (0,1) and the last cycle of the STA $4200 is 131 | at (0,0)+1372 master cycles, the IRQ line will still go low. 132 | 133 | 134 | The CPU will jump to the NMI or IRQ handler at the end of the instruction when 135 | /NMI transitions or when /IRQ is low and the I flag is clear. The actual check 136 | occurs just before the final CPU cycle of the instruction, which means that the 137 | jump will begin at the earliest 6 to 12 master cycles after /NMI or /IRQ. Also 138 | note that PLP, CLI, SEI, SEP #$04, and REP #$04 update the flags during their 139 | final CPU cycle, so the IRQ check will use the old value of I rather than the 140 | new one set by the current instruction. RTI, BRK, and COP on the other hand do 141 | not have this issue. 142 | 143 | So for the following code: 144 | > ; set up IRQ 145 | > SEI 146 | > WAI 147 | > STZ $00 148 | > LDA #$01 149 | > CLI 150 | > LDA #$42 151 | > STP 152 | > 153 | > IRQHandler: 154 | > STA $00 155 | > RTI 156 | Memory location $00 will end up set to 0x42, not 0 or 1, because the I flag 157 | isn't clear before the final cycle of CLI. And for the following code: 158 | > ; set up IRQ 159 | > SEI 160 | > WAI 161 | > CLI 162 | > SEI 163 | The IRQ will actually trigger following the SEI instruction, not before it (but 164 | the flags pushed during the IRQ handler will have the I flag set). OTOH, the 165 | following code will not allow an IRQ to trigger at all if the RTI sets the I 166 | flag: 167 | > ; set up IRQ 168 | > SEI 169 | > WAI 170 | > CLI 171 | > RTI 172 | And the following code (with RTI clearing I): 173 | > ; set up IRQ 174 | > SEI 175 | > WAI 176 | > STZ $00 177 | > LDA #$01 178 | > RTI 179 | > 180 | > ; -> RTI returns here 181 | > LDA #$42 182 | > STP 183 | > 184 | > IRQHandler: 185 | > STA $00 186 | > RTI 187 | Will result in memory location $00 being set to 1, not 0x42. 188 | 189 | If /NMI and /IRQ are both pending, NMI takes precedence. 190 | 191 | And the datasheet is inaccurate regarding that first cycle of the IRQ/NMI 192 | pseudo-opcode. It's an opcode fetch cycle from PB:PC (typically 6 or 8 master 193 | cycles), not an IO cycle (always 6 master cycles) as the datasheet claims. 194 | 195 | 196 | DMA 197 | --- 198 | 199 | DMA is activated by writing a 1 to any bit of CPU register $420b. The CPU is 200 | halted during the DMA transfer. 201 | 202 | DMA takes 8 master cycles per byte transferred, regardless of the memory 203 | regions accessed. It is unknown what happens if you attempt DMA to or from 204 | $4000-$41ff, since that memory region requires 12 master cycles for access. 205 | There is also 8 master cycles overhead per channel. 206 | 207 | The exact DMA timing works as follows: After $420b is written, the CPU gets one 208 | more CPU cycle before the pause (on a standard "STA $420b", this would be the 209 | opcode fetch for the next instruction). The speed of the next CPU cycle to 210 | execute after the DMA determines the CPU Clock speed for the DMA transfer. 211 | 212 | Now, after the pause, wait 2-8 master cycles to reach a whole multiple of 8 213 | master cycles since reset. The perform the DMA: 8 master cycles overhead and 8 214 | master cycles per byte per channel, and an extra 8 master cycles overhead for 215 | the whole thing. Then wait 2-8 master cycles to reach a whole number of CPU 216 | Clock cycles since the pause, and only then resume S-CPU execution. 217 | 218 | The exact timing of the read within the DMA period is not known. Best guess at 219 | this point is that 2-4 of the "whole DMA overhead" is before the transfer and 220 | the rest after. 221 | 222 | An example: "STA $420b : NOP", one channel active for a 3 byte transfer. The 223 | pause occurs after the NOP opcode is fetched, so the CPU Clock Speed is 6 224 | master cycles due to the following IO cycle in the NOP. After the pause, say we 225 | need 2 master cycles to reach an even multiple of 8 master cycles since reset 226 | [total=2]. Then wait 8 for DMA init [total=10], 8 for channel init [total=18], 227 | and 8*3 for the actual transfer [total=42]. To reach a whole number of CPU 228 | Clock cycles since the pause, we must wait 6 master cycles (remember, 0 is not 229 | an option) [total=48]. 230 | 231 | Same thing, but begin the pause 2 master cycles earlier. Thus, we must wait 4 232 | master cycles to get to a multiple of 8 since reset [total=4], then our 40 for 233 | the DMA transfer [total=44]. To get to a whole CPU Clock, 4 master cycles are 234 | needed [total=48]. 235 | 236 | Same thing, but begin the pause 2 master cycles earlier. Thus, we must wait 6 237 | master cycles to get to a multiple of 8 since reset [total=6], then our 40 for 238 | the DMA transfer [total=46]. To get to a whole CPU Clock, only 2 master cycles 239 | are needed [total=48]. 240 | 241 | One last time, begin the pause 2 master cycles earlier. Thus, we must wait 8 242 | master cycles to get to a multiple of 8 since reset [total=8], then our 40 for 243 | the DMA transfer [total=48]. To get to a whole CPU Clock since pause, 6 master 244 | cycles are again needed [total=54]. So this transfer took an extra 6 master 245 | cycles... 246 | 247 | 248 | HDMA 249 | ---- 250 | 251 | HDMA is enabled by writing a 1 to any bit of CPU register $420c. Much like 252 | DMA, the CPU is halted during HDMA operations. HDMA takes priority over DMA. 253 | 254 | For all active channels, the HDMA registers are initialized at about V=0 255 | H=6. The overhead is ~18 master cycles, plus 8 master cycles for each channel 256 | set for direct HDMA and 24 master cycles for each channel set for indirect 257 | HDMA. Presumably, the exact timing for the HDMA pause is the same as that for 258 | DMA. 259 | 260 | HDMA channels may be deactivated mid-frame if $00 is read into $43xA from 261 | the HDMA table (or possibly if $00 is written to $43xA manually). They may 262 | also be activated or deactivated by writing $420c. All HDMA channels are 263 | deactivated at the start of V-Blank. 264 | 265 | The actual HDMA transfer begins at dot 278 of the scanline (or just after, the 266 | current CPU cycle is completed before pausing), for every visible scanline 267 | (0-224 or 0-239, depending on $2133 bit 3). For each scanline during which HDMA 268 | is active (i.e. at least one channel has not yet terminated for the frame), 269 | there are ~18 master cycles overhead. Each active channel incurs another 8 270 | master cycles overhead for every scanline, whether or not a transfer actually 271 | occurs. If a new indirect address is required, 16 master cycles are taken to 272 | load it. Then 8 cycles per byte transferred are used. 273 | 274 | 275 | AUTO JOYPAD READ 276 | ---------------- 277 | 278 | When enabled, the SNES will read 16 bits from each of the 4 controller port 279 | data lines into registers $4218-f. This begins between dots 32.5 and 95.5 of 280 | the first V-Blank scanline, and ends 4224 master cycles later. Register $4212 281 | bit 0 is set during this time. Specifically, it begins at dot 74.5 on the first 282 | frame, and thereafter some multiple of 256 cycles after the start of the 283 | previous read that falls within the observed range. 284 | 285 | Reading $4218-f during this time will read back incorrect values. The only 286 | reliable value is that no buttons pressed will return 0 (however, if buttons 287 | are pressed 0 could still be returned incorrectly). Presumably reading $4016/7 288 | or writing $4016 during this time will also screw things up. 289 | 290 | 291 | REGISTERS 292 | --------- 293 | 294 | $4210 bit 7: shows the status of the internal timer's NMI output (1=low). 295 | Reading this bit causes the NMI output to go high. 296 | 297 | $4211 bit 7: shows the status of the internal timer's IRQ output (1=low) OR 298 | the status of the CPU's external /IRQ line. Reading this bit causes the 299 | internal timer's IRQ output to go high. 300 | 301 | $4212 bit 0: set when Auto Joypad Read is being performed. 302 | 303 | $4212 bit 6: indicates H-blank. Set at H=274 of every scanline, and cleared at 304 | H=1. 305 | 306 | $4212 bit 7: indicates V-blank. Set at H=0 at the beginning of V-Blank, and 307 | cleared at H=0 V=0. 308 | 309 | $4214-7: 8 cycles (8 master cycles or somewhere between 48 and 64 master 310 | cycles?) after $4203 is written, the multiplication result may be read. 16 311 | master cycles (or somewhere between 96 and 128 master cycles) after $4206 is 312 | written, the division result may be read. What happens before the time is up 313 | (or if you initiate another multiplication/division while calculating) is 314 | unknown. 315 | 316 | 317 | S-PPU 318 | ===== 319 | 320 | The PPU is clocked off the same oscillator as the S-CPU. 321 | 322 | RENDERING 323 | --------- 324 | 325 | The PPU uses the same measure of frames and scanlines as the 5A22 S-CPU. There 326 | are always 340 dots ('pixels') per scanline; normally dots 323 and 327 are 6 327 | master cycles instead of 4. 328 | 329 | Note that a superscope pointing at pixel (X, Y) on the screen will latch 330 | approximately dot X+40 on scanline Y+1. 331 | 332 | The PPU outputs one pixel every 4 master cycles, for dots 22-277(?) on 333 | scanlines 1-224 or 1-239. Note that (for NTSC) the color carrier is 6 master 334 | cycles, hence the interesting color effects seen with alternating pixel 335 | patterns. 336 | 337 | The PPU seems to access memory 2-3 tiles ahead of the pixel output. At least, 338 | when we disable Force Blank mid-scanline, there is garbage for about 16-24 339 | pixels. 340 | 341 | 342 | BLANKING PERIODS 343 | ---------------- 344 | 345 | V-Blank begins on scanline $E1 or $F0, at H=0, depending on bit 2 of 346 | $2133. If this bit is set, then cleared between $E0 and $F0, most "at the 347 | start of V-Blank" events will trigger at the next appropriate H point. Note 348 | though that clearing it too late may cause the TV to lose sync, possibly 349 | because the PPU doesn't get a chance to output a correct V-Blank signal. 350 | Setting the bit 'too late' will not resume HDMA or rendering or re-trigger 351 | NMI, but VRAM will be locked as if rendering were still proceeding. 352 | 353 | V-Blank ends at V=0 H=0. 354 | 355 | H-Blank begins at H=274 of every scanline, and ends at H=1. 356 | 357 | 358 | REGISTERS 359 | --------- 360 | 361 | $2134-6: Some unknown number of master cycles after $211c is set, the product 362 | may be read from these registers. What value may be read before these cycles 363 | have elapsed is unknown. 364 | 365 | $2137: Read to latch the PPU dot position. 366 | 367 | $213F bit 6: Set when the PPU dot counter is latched (or shortly thereafter), 368 | and cleared on read (and maybe the beginning/end of V-Blank too?). 369 | 370 | $213F bit 7: Toggles every frame, at V=0 H=1. 371 | 372 | 373 | OAM RESET 374 | --------- 375 | 376 | At the beginning of V-Blank if force-blank is disabled, the internal OAM 377 | address is reset to the value last written to $2102-3. byuu reports this occurs 378 | at H=10 on scanline 225/240. Also, byuu reports the reset occurs on any 1->0 379 | transition of $2100 bit 7. 380 | 381 | 382 | DETAILED RENDERER TIMING 383 | ------------------------ 384 | 385 | Most of this is conjecture, based on a NES timing expetiment conducted by 386 | Brad Taylor (big_time_software@hotmail.com) around Sept 25, 2000. 387 | 388 | All SNES VRAM memory access cycles are 4 master cycles long (the same amount 389 | of time it takes to output one pixel), compared to 8 (2 pixels) for the NES. 390 | The scanline is thus 340 memory accesses long. Also, the SNES PPU can access 391 | 2 bytes at a time (one from each VRAM chip) where the NES could only access 392 | one. Like the NES, 'rendering' begins on scanline 0, however nothing is 393 | actually output for scanline 0. 394 | 395 | Beginning when the PPU begins outputting the first pixel on the scanline 396 | (just after H-Blank), we load the data for 32 tiles. For Modes 0-4, each BG 397 | takes 1 memory access for the tilemap word, and either 1, 2, or 4 accesses for 398 | 8 pixels of character data (depending on if the BG is 2, 4, or 8 bits, and 399 | see now why the bitplanes are stored the way they are?). For Modes 5 and 6, 400 | 2 or 4 memory accesses (again, if the BG is 2 or 4 bits) are required for 16 401 | half-pixels of character data. Since this is at most 8 memory accesses for 402 | any BG mode, and 8 pixels are loaded at a time, you can see we just break 403 | even. For Mode 7, a tilemap entry is read from the low-byte VRAM chip and a 404 | pixel from the high-byte chip. During the rendering of the first tile, the 405 | third tile is being loaded from VRAM. This is a total of 256 memory access 406 | cycles. 407 | 408 | Also during this time, OAM is being examined to determine the first 32 409 | sprites on the next scanline. This (and the later loading during H-Blank) is 410 | the reason for the dummy scanline 0, otherwise there would be no sprite data 411 | for the first scanline on the screen. 412 | 413 | During H-Blank, 68 memory access cycles are devoted to loading the next 414 | scanline from 34 4-bit sprite tiles, and 16 memory access cycles to loading 415 | the scanline for the first two tiles of the next scanline (recall that the 416 | third tile is being loaded while the first is being rendered). This totals 417 | 340 memory access cycles. 418 | 419 | 420 | S-APU 421 | ===== 422 | 423 | SPC700 424 | ------ 425 | 426 | The SPC700 is nominally clocked at 1024000 Hz, however my SNES seems to run at 427 | ~1026900 Hz instead. 428 | 429 | Instruction timing is not well known. There are some docs available, but their 430 | accuracy is suspect. 431 | 432 | The SPC700 has 3 timers, one clocked at "64000 Hz" and two at "8000 Hz". In 433 | reality, the fast timer ticks every 16 cycles and the slow every 128, whatever 434 | length the SPC700 cycles really are. 435 | 436 | The SPC700 communicates with the S-CPU via 4 registers. Exact memory access 437 | timings on these registers is not known, however it is possible that the 5A22 438 | will be performing a read at the instant the SPC700 is performing a write. The 439 | 5A22 will then read the logical OR of the old and new values of the register. 440 | 441 | 442 | DSP 443 | --- 444 | 445 | The DSP outputs samples at "32000 Hz", although a real rate of one sample 446 | every 32 SPC700 cycles is more likely. 447 | 448 | Other timing is not known. If you do know, please fill in the details here. 449 | -------------------------------------------------------------------------------- /sound/README.md: -------------------------------------------------------------------------------- 1 | # サウンド 2 | 3 | スーファミのAPU(SPUとも呼ばれる)は、ファミコンのそれと比べると大幅に進化しています。 4 | 5 | サウンドデータ格納用として64KBのRAM(ARAM)が与えられていて、さらにはスーファミのメインCPUとは別のプロセッサ(SPC700)やDSP[1](#dsp)まで与えられています。 6 | 7 | 8 | 9 | APUとスーファミ本体のCPUは、4つのポート(IOレジスタ)を介してのみデータのやり取りを行います。そのため、APUは非常に独立性が高く、APUだけ取り外してスーファミ音源の再生機器として利用する人も多いようです。 10 | 11 | [![APU](http://img.youtube.com/vi/09P2IJnuZts/0.jpg)](https://www.youtube.com/watch?v=09P2IJnuZts) 12 | 13 | ## 注釈 14 | 15 | 1: デジタルシグナルプロセッサ。CPUと違って、信号処理で非常に多く使われる積和演算が得意 16 | 17 | ## 参考 18 | 19 | - [SPC700 & ARAM - Super Nintendo Entertainment System Features Pt. 10](https://youtu.be/n5eTOGZdnTU) 20 | - [SNES Audio System Overview - SPC700 Series pt. 1](https://youtu.be/zrn0QavLMyo) 21 | -------------------------------------------------------------------------------- /sound/ioreg.md: -------------------------------------------------------------------------------- 1 | # IOレジスタ 2 | 3 | スーファミ本体のCPUは、4つのIOレジスタ(8bit)を介して、APUとデータをやりとりしています。 4 | 5 | ## 214xh - APUI0x - APU通信レジスタx (R/W, x=0,1,2,3) 6 | 7 | ``` 8 | Bit 0-7 データ 9 | CPU目線で見て 10 | Write: CPU -> APU 11 | Read: APU -> CPU 12 | ``` 13 | 14 | 内部的には、APU行きのデータと、APUからのデータで、合計2バイトのデータを保持しています。 15 | 16 | これらのレジスタは8bitモードでのみ書き込んでください。 17 | 18 | > **Note** 19 | > ハードウェアの不具合により、 `[2140h..2141h]` への16bit書き込みが `[2143h]` を破壊することがあります。 ただしこれはカートリッジにROMチップが多く、バスに過度の負荷がかかる場合など、特定の状況でのみ発生する可能性があります。 20 | 21 | APU側からは、SPC(SPC700)のIOレジスタ、`CPUIOx`(`00F4..00F7h`)を通してこのレジスタにアクセスすることができます。 22 | 23 | 24 | 25 | ## Uploader 26 | 27 | ```c 28 | // 0x2140,2141 が 0xBBAA になるまで待つ 29 | WAIT(READ16(0x2140) == 0xBBAA); 30 | kick = 0xCC; // start-code for first command 31 | 32 | for (block = 1; block <= num_blocks ; block++) { 33 | STORE16(0x2142) = dest_addr; // usually 200h or higher (above stack and I/O ports) 34 | STORE8(0x2142) = 0x01; // command=transfer (can be any non-zero value) 35 | STORE8(0x2140) = kick; // start command (CCh on first block) 36 | WAIT(READ8(0x2140) == kick); // 0x2140 が kick になるまで待つ 37 | 38 | for (index = 0; index < length; i++) { 39 | READ8(0x2141) = BYTE(src_addr+index); // send data byte 40 | READ8(0x2140) = LSB(index); // send index LSB (mark data available) 41 | WAIT(READ8(0x2140) != LSB(index)); // wait for acknowledge 42 | } 43 | 44 | kick = (index+2 & 0xFF) | 1; 45 | } 46 | 47 | WRITE8(0x2142, entry_point); // entrypoint, must be below FFC0h (ROM region) 48 | WRITE8(0x2141, 0x0); // command=entry (must be zero value) 49 | WRITE8(0x2140, kick); // start command 50 | WAIT(READ8(0x2140) == kick); // wait for acknowledge 51 | ``` 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /sound/spc700/README.md: -------------------------------------------------------------------------------- 1 | # SPC700 2 | 3 | APUは、ソニーのSPC700命令セットを使用した8bitCPUであるS-SMPチップ(以後、SPC700と呼びます)で制御されています。 4 | 5 | SPC700 のクロック周波数は 1.024MHz です。[1](#clock) 6 | 7 | SPC700 のオペコードと3つのメインレジスタ(A,X,Y)は、オペコードの番号が異なるものの、明らかに6502命令セットからインスピレーションを受けており、いくつかの新しい/変更された命令を持っています。 8 | 9 | ## レジスタ 10 | 11 | ``` 12 | A アキュムレータ (8bit) 13 | X インデックスレジスタX (8bit) 14 | Y インデックスレジスタY (8bit) 15 | SP スタックポインタ (8bit, nn => 0x1nn) 16 | YA 16bit combination of Y=MSB, and A=LSB 17 | PC プログラムカウンタ (16bit) 18 | PSW ステータスレジスタ (8bit) 19 | bit0 C キャリー (0=No Carry, 1=Carry) 20 | bit1 Z ゼロ (0=(前の計算結果が)非ゼロ, 1=ゼロ) 21 | bit2 I 割り込み無効 (0=有効, 1=無効) 22 | bit3 H Half-carry (0=Borrow, or no-carry, 1=Carry, or no-borrow) 23 | bit4 B ブレークフラグ (0=RESET, 1=BRK) 24 | bit5 P Zero Page Location (0=00xxh, 1=01xxh) 25 | bit6 V オーバーフロー 26 | bit7 N ネガティブ (0=(前の計算結果が)正, 1=負) 27 | ``` 28 | 29 | 1: ウィキペディアには 2.048MHz とあるが、真偽不明 30 | -------------------------------------------------------------------------------- /sound/spc700/ioreg.md: -------------------------------------------------------------------------------- 1 | # IOレジスタ 2 | 3 | アドレスは、SPC700のメモリ空間のものです。 4 | 5 | ## 00F0h - TEST - テストレジスタ (W) 6 | 7 | プロセッサ自体の動作を変更します。 8 | 9 | ``` 10 | Bit 0 Timer-Enable (0=Normal, 1=Timers don't work) 11 | Bit 1 RAM Write Enable (0=Disable/Read-only, 1=Enable SPC700 & S-DSP writes) 12 | Bit 2 Crash SPC700 (0=Normal, 1=Crashes the CPU) 13 | Bit 3 Timer-Disable (0=Timers don't work, 1=Normal) 14 | Bit 4-5 Waitstates on RAM Access (0..3 = 0/1/4/9 cycles) (0=Normal) 15 | Bit 6-7 Waitstates on I/O and ROM Access (0..3 = 0/1/4/9 cycles) (0=Normal) 16 | ``` 17 | 18 | Default setting is 0Ah, software should never change this register. Normal memory access time is 1 cycle (adding 0/1/4/9 waits gives access times of 1/2/5/10 cycles). Using 4 or 9 waits doesn't work with some opcodes (0 or 1 waits seem to work stable). 19 | 20 | Internal cycles (those that do not access RAM, ROM, nor I/O) are either using the RAM or I/O access time (see notes at bottom of this chapter). 21 | 22 | ## 00F1h - CONTROL - 制御レジスタ (W) 23 | 24 | リセット時には `0xB0` になります。 25 | 26 | ``` 27 | Bit 0-2 タイマー0~2有効化フラグ (0=無効, 1=有効) 28 | タイマーnを無効化した場合、TnOUTがゼロクリアされ、dividerがリロードされます。 29 | Bit 3 不使用 30 | Bit 4 00F4h/00F5hのSNESからの入力値をゼロクリアする (1にしてる間ずっと) 31 | Bit 5 00F6h/00F7hのSNESからの入力値をゼロクリアする (1にしてる間ずっと) 32 | Bit 6 不使用 33 | Bit 7 アドレス FFC0h-FFFFh からの読み取り時に何を返すか (0=ARAM, 1=ブートROM) (書き込みは常にARAM) 34 | ``` 35 | 36 | ## 00F2h - DSPADDR - DSPレジスタ番号 (R/W) 37 | 38 | ``` 39 | Bit 0-7 DSPレジスタ番号 (usually 00h..7Fh) (80h..FFh are read-only mirrors) 40 | ``` 41 | 42 | ## 00F3h - DSPDATA - DSPレジスタデータ (R/W) 43 | 44 | ``` 45 | Bit 0-7 DSPレジスタデータ (read/write the register selected via Port 00F2h) 46 | ``` 47 | 48 | ## 00Fxh - CPUIOn - CPU通信レジスタn (R/W, n=0,1,2,3) 49 | 50 | ``` 51 | 00F4h - CPUIO0 52 | 00F5h - CPUIO1 53 | 00F6h - CPUIO2 54 | 00F7h - CPUIO3 55 | ``` 56 | 57 | これらのレジスタはスーファミ本体のCPU(S-CPU)との通信に使用されます。 58 | 59 | S-CPUへの出力ポート(書き込み専用)が4つ、S-CPUからの入力ポート(読み出し専用)が4つ、合計8つのレジスタがこの4つのアドレスでアクセスされます。 60 | 61 | ``` 62 | Bit 0-7 データ 63 | APU(SPC700)目線で見て 64 | Write: APU -> S-CPU 65 | Read: S-CPU -> APU 66 | ``` 67 | 68 | S-CPU側からは、`APUIOx`(`2140..2143h`)を通してこのレジスタにアクセスすることができます。 69 | 70 | 71 | 72 | If the SPC700 writes to an output port while the S-CPU is reading it, the S-CPU will read the logical OR of the old and new values. Possibly the same thing happens the other way around, but the details are unknown? 73 | 74 | ## 00Fxh - AUXIOn - 補助レジスタn (R/W, n=4,5) 75 | 76 | ``` 77 | 00F8h - AUXIO4 (S-SMP Pins 34-27) 78 | 00F9h - AUXIO5 (S-SMP Pins 25-18) 79 | ``` 80 | 81 | SPC700の AUXIOn に割り当てられたピンは、スーファミの場合、何にも接続されていないため、レジスタは実質的に汎用レジスタのように機能し、自由に使うことが可能です。 82 | 83 | ``` 84 | Bit 0-7 データ 85 | ``` 86 | 87 | ## 00Fxh - TnDIV - Dividerレジスタn (W, n=0,1,2) 88 | 89 | [タイマー](timer.md)のページを参照してください。 90 | 91 | ## 00Fxh - TnOUT - タイマーカウンタn (R, n=0,1,2) 92 | 93 | [タイマー](timer.md)のページを参照してください。 94 | 95 | 96 | -------------------------------------------------------------------------------- /sound/spc700/timer.md: -------------------------------------------------------------------------------- 1 | # タイマー 2 | 3 | タイマーは、APUで実行されているプログラムが適切なタイミングで実行されるために必要なコンポーネントです。 4 | 5 | スーファミ本体の場合は、NMIやブランク期間のような区切りがありますが、APUにはそのようなものが存在しないため、タイマーが必要になってきます。 6 | 7 | APUはタイマーを3つ備えており、タイマー0,1,2と呼ばれます。 8 | 9 | ## 仕組み 10 | 11 | DSPからSPC700には 2.048MHz のクロック信号が送られており、このクロックをマスタークロックとしてタイマーは機能します。( 1マスターサイクル= `1/(2048000)sec` ) 12 | 13 | タイマー0とタイマー1は、256マスターサイクルつまり、8KHzクロック信号を生成します。タイマー2は、32マスターサイクル、64KHzクロック信号を生成します。 14 | 15 | 各タイマーは、SPC700からは見えない内部カウンタを持っており、8KHz/64KHzクロック信号ごとにインクリメントされます。 16 | 17 | diagram 18 | 19 | ## 00Fxh - TnDIV - Dividerレジスタn (W, n=0,1,2) 20 | 21 | ``` 22 | 00FAh/00FBh/00FCh - T0DIV/T1DIV/T2DIV 23 | ``` 24 | 25 | タイマーの内部カウンタが `TnDIV` の値と等しくなった場合に、内部カウンタを 0 にします。(その際に、`TnOUT` をインクリメント) 26 | 27 | `TnDIV` に 0 を書き込んだ場合は、256 として扱われます。 28 | 29 | ## 00Fxh - TnOUT - タイマーカウンタn (R, n=0,1,2) 30 | 31 | ``` 32 | 00FDh/00FEh/00FFh - T0OUT/T1OUT/T2OUT 33 | ``` 34 | 35 | 内部カウンタが、0になったときにインクリメントされます。 36 | 37 | ``` 38 | Bit 0-3 現在のカウンタ値 (読み出すと0にリセットされます) 39 | Bit 4-7 不使用 (常に0) 40 | ``` -------------------------------------------------------------------------------- /spec.md: -------------------------------------------------------------------------------- 1 | # 仕様 2 | 3 | ## 概要 4 | 5 | - CPU: 65C816をカスタムした16bit CPU, 最大クロックは3.58MHz 6 | - RAM: 128KB 7 | - グラフィック: 256×224px で最大256色 8 | - サウンド: 8チャンネル 9 | 10 | ## 本体(スーファミ) 11 | 12 | - 発売日: 1990/11/21 13 | - 定価: 9800円(税別) 14 | - 売り上げ: 1717万台(日本), 4910万台(世界) 15 | - 大きさ(幅x奥行きx高さ): 200×242×72mm 16 | - 重量: 約600g 17 | - ファミコンソフトとの互換性なし 18 | 19 | ## CPU 20 | 21 | - CPU: 65C816をカスタムした16bit CPU 22 | - クロック周波数: 1.79MHz、2.68MHz、3.58MHzの三段階切替え 23 | - RAM: 128KB 24 | 25 | ## グラフィック 26 | 27 | - RAM: 64KB 28 | - 解像度: 256x224px[1](#resolution) 29 | - レイヤー: スプライトとバックグラウンド(BG)面最大4枚 30 | - 色: 31 | - 32768色から選択 32 | - 同時に使える色は最大256色 33 | - タイルサイズ: 34 | - 最大: 16×16px 35 | - 最小: 8×8px 36 | - スプライト: 37 | - 最大: 64×64px 38 | - 最小: 8×8px 39 | - 最大128個 40 | 41 | ## サウンド 42 | 43 | - サンプリング周波数: 32KHz 44 | - チャンネル数: 8 45 | - 音源: 16bit PCM音源 ステレオ 46 | - RAM: 64KB 47 | 48 | 1: 224px か 239px で選択可能。60HzのTV(NTSC)では224px、50HzのTV(PAL)では239pxが基本 49 | -------------------------------------------------------------------------------- /timing/oscillator.md: -------------------------------------------------------------------------------- 1 | # 周波数 2 | 3 | ## NTSC版 4 | 5 | ``` 6 | NTSC crystal 21.4772700MHz (X1, type number D214K1) 7 | NTSC color clock 3.57954500MHz (21.47727MHz/6) (generated by PPU2 chip) 8 | NTSC master clock 21.4772700MHz (21.47727MHz/1) (without multiplier/divider) 9 | NTSC dot clock 5.36931750MHz (21.47727MHz/4) (generated by PPU chip) 10 | NTSC cpu clock 3.57954500MHz (21.47727MHz/6) (without waitstates) 11 | NTSC cpu clock 2.68465875MHz (21.47727MHz/8) (short waitstates) 12 | NTSC cpu clock 1.78977250MHz (21.47727MHz/12) (joypad waitstates) 13 | NTSC frame rate 60.09880627Hz (21.477270MHz/(262*1364-4/2)) 14 | NTSC interlace 30.xxxxxxxxHz (21.477270MHz/(525*1364)) 15 | ``` 16 | 17 | ## PAL版 18 | 19 | ``` 20 | PAL crystal 17.7344750MHz (X1, type number D177F2) 21 | PAL color clock 4.43361875MHz (17.7344750MHz/4) (generated by S-CLK chip) 22 | PAL master clock 21.2813700MHz (17.7344750MHz*6/5) (generated by S-CLK chip) 23 | PAL dot clock 5.32034250MHz (21.2813700MHz/4) (generated by PPU chip) 24 | PAL cpu clock 3.54689500MHz (21.2813700MHz/6) (without waitstates) 25 | PAL cpu clock 2.66017125MHz (21.2813700MHz/8) (short waitstates) 26 | PAL cpu clock 1.77344750MHz (21.2813700MHz/12) (joypad waitstates) 27 | PAL frame rate 50.00697891Hz (21.281370MHz/(312*1364)) 28 | PAL interlace 25.xxxxxxxxHz (21.281370MHz/(625*1364+4/2)) 29 | ``` 30 | 31 | ## APU 32 | 33 | ``` 34 | APU oscillator 24.576MHz (X2, type number 24.57MX) 35 | DSP sample rate 32000Hz (24.576MHz/24/32) 36 | SPC700 cpu clock 1.024MHz (24.576MHz/24) 37 | SPC700 timer 0+1 8000Hz (24.576MHz/24/128) 38 | SPC700 timer 2 64000Hz (24.576MHz/24/16) 39 | CIC clock 3.072MHz (24.576MHz/8) 40 | Expansion Port 8.192MHz (24.576MHz/3) 41 | ``` 42 | 43 | ## CPUクロック 44 | 45 | CPUのクロックは通常3.5MHzまたは2.6MHz(またはその混在)です。 46 | 47 | ``` 48 | 3.5MHz Used for Fast ROM, most I/O ports, and internal CPU cycles 49 | 2.6MHz Used for Slow ROM, for WRAM, and for DMA/HDMA transfers 50 | 1.7MHz Used only for (some) Joypad I/O Ports 51 | ``` 52 | 53 | CPUはDRAMのリフレッシュのために(1364サイクルのスキャンラインあたり)40マスターサイクルだけ一時停止し、事実上CPUは約3%遅くなります。また、DMA/HDMA転送を使用する場合にも、CPUは一時停止します。 54 | 55 | Nintendo specifies the following ROM timings to be required: 56 | 57 | ``` 58 | 3.5MHz use 120ns or faster ROM/EPROMs 59 | 2.6MHz use 200ns or faster ROM/EPROMs 60 | ``` 61 | 62 | ## Dot Clock Notes 63 | 64 | ## カートリッジ内の外部デバイス 65 | 66 | -------------------------------------------------------------------------------- /video/bg/README.md: -------------------------------------------------------------------------------- 1 | # 🌄 背景(BG) 2 | 3 | スーファミでは、最大4つの背景レイヤ(BG1~BG4)を扱うことができます。 4 | 5 | - [BGマップ](bgmap.md) 6 | - [制御レジスタ](control.md) 7 | - [BGモード](mode.md) 8 | - [モザイク](mosaic.md) 9 | - [スクロール](scroll.md) 10 | 11 | -------------------------------------------------------------------------------- /video/bg/bgmap.md: -------------------------------------------------------------------------------- 1 | # 🗺 BGマップ 2 | 3 | BGマップは、タイルデータを画面上にどのように配置していくかを表すデータです。 4 | 5 | 背景マップや、タイルマップとも呼ばれます。 6 | 7 | 1つのBGマップで 32x32タイル(256×256px) を表します。(1タイル = 8x8 or 16x16) 8 | 9 | 各BGマップエントリ(タイルに対応)は、次のような16bitの値で構成されます。 10 | 11 | ``` 12 | Bit 0-9 タイル番号 (000h-3FFh) 13 | Bit 10-12 パレット番号 (0-7) 14 | Bit 13 BG優先度 (0=低, 1=高) 15 | Bit 14 X反転 (0=反転しない、 1=水平方向に反転) 16 | Bit 15 Y反転 (0=反転しない、 1=垂直方向に反転) 17 | ``` 18 | 19 | Mode 2,4,6 の `Offset-per-Tile`モードでは、BG3のBGマップのみエントリの内容が変わります。 20 | 21 | ``` 22 | Bit 0-9 スクロール量 23 | Bit 10-12 不使用 24 | Bit 13 スクロールをBG1に適用するか 25 | Bit 14 スクロールをBG2に適用するか 26 | Bit 15 スクロール方向 (0=H, 1=V, Mode4のみ) 27 | ``` 28 | 29 | Bit15が0、つまり、X方向(H)オフセットの場合、スクロール量(Bit0-9)の下位3bitは無視されます。 30 | 31 | Mode7では、BGマップは128x128であり、下位8bitのみをBGマップエントリとして使用します。 32 | 33 | ``` 34 | Bit 0-7 タイル番号 (00h-FFh) (without XYflip or other attributes) 35 | Bit 8-15 不使用 (contains tile-data; no relation to the BG-Map entry) 36 | ``` 37 | 38 | ## BGマップのアドレス 39 | 40 | 各BGレイヤのBGマップがVRAM上でどこに存在するかは、[BGnSC](./control.md)で指定します。 41 | -------------------------------------------------------------------------------- /video/bg/control.md: -------------------------------------------------------------------------------- 1 | # BG制御レジスタ 2 | 3 | ## 2105h - BGMODE - BG制御レジスタ (W) 4 | 5 | ``` 6 | Bit 0-2 BGモード (0..7) 7 | Bit 3 BG3優先度 (Mode1用、0=通常, 1=高) 8 | Bit 4 BG1タイルサイズ (0=8x8, 1=16x16) 9 | Bit 5 BG2タイルサイズ (0=8x8, 1=16x16) 10 | Bit 6 BG3タイルサイズ (0=8x8, 1=16x16) 11 | Bit 7 BG4タイルサイズ (0=8x8, 1=16x16) 12 | ``` 13 | 14 | >**Note** 15 | > Mode5では 8x8 は 16x8 として、Mode6ではタイルサイズは常に 16x8 として、Mode7ではタイルサイズは常に 8x8 として扱われます。 16 | 17 | BGモード0~7の詳細は[こちら](mode.md)を参照してください。 18 | 19 | ## 210xh - BGnSC - BGマップ設定 (W) 20 | 21 | ``` 22 | 2107h: BG1SC 23 | 2108h: BG2SC 24 | 2109h: BG3SC 25 | 210Ah: BG4SC 26 | ``` 27 | 28 | ``` 29 | Bit 0-1 仮想画面サイズ (0=1枚, 1=Yミラー, 2=Xミラー, 3=4枚) 30 | 0: 32x32 タイル 31 | (SC0 SC0) 32 | (SC0 SC0) 33 | 1: 64x32 タイル 34 | (SC0 SC1) 35 | (SC0 SC1) 36 | 2: 32x64 タイル 37 | (SC0 SC0) 38 | (SC1 SC1) 39 | 3: 64x64 タイル 40 | (SC0 SC1) 41 | (SC2 SC3) 42 | Bit 2-7 BGマップのベースアドレス (2KB単位) 43 | ``` 44 | 45 | このレジスタで、VRAMのBGマップアドレスを指定します。 46 | 47 | 画面`SCn`は 32x32枚のタイルで構成されています。 48 | 49 | Mode7ではこのレジスタは無視されます。(ベースアドレスは0で、サイズは128x128で固定) 50 | 51 | ## 210Bh/210Ch - BG12NBA/BG34NBA - BGタイルデータアドレス (W) 52 | 53 | ``` 54 | BG12NBA: 55 | Bit 0-3 BG1タイルデータのベースアドレス (8KB単位) 56 | Bit 4-7 BG2タイルデータのベースアドレス (8KB単位) 57 | 58 | BG34NBA: 59 | Bit 0-3 BG3タイルデータのベースアドレス (8KB単位) 60 | Bit 4-7 BG4タイルデータのベースアドレス (8KB単位) 61 | ``` 62 | 63 | Mode7ではこのレジスタは無視されます。(タイルデータのベースアドレスは0となります) 64 | -------------------------------------------------------------------------------- /video/bg/mode.md: -------------------------------------------------------------------------------- 1 | # BGモード 2 | 3 | 背景(BG)に関して、スーファミは7つのモードが存在しています。 4 | 5 | 各モードは Mode0, Mode1, ... Mode7 と呼ばれ、モードごとに 6 | 7 | - 利用できる背景レイヤの枚数と色数 8 | - レンダリングの特性 9 | 10 | が異なります。 11 | 12 | モードの切り替えは[BGMODE](bg_control.md)で設定します。 13 | 14 | **各モードが使える背景レイヤと色数** 15 | 16 | モード | BG1 | BG2 | BG3 | BG4 17 | -- | -- | -- | -- | -- 18 | Mode0 | 4 | 4 | 4 | 4 19 | Mode1 | 16 | 16 | 4 | - 20 | Mode2 | 16 | 16 | - | - 21 | Mode3 | 256 | 16 | - | - 22 | Mode4 | 256 | 4 | - | - 23 | Mode5 | 16 | 4 | - | - 24 | Mode6 | 16 | - | - | - 25 | Mode7 | 256 | EXTBG | - | - 26 | 27 | ## Mode0 28 | 29 | mode0 props 30 | 31 | ヨッシーアイランド 32 | 33 | 基本となるBGモードです。 34 | 35 | BG1,BG2,BG3,BG4 の全て利用可能で、タイルサイズも `8x8` か `16x16` から選択可能です。 36 | 37 | 特殊効果も、モザイク、ウィンドウ、ColorMath、インターレース(制限あり)、擬似512モードが利用可能です。 38 | 39 | 基本となるBGモードですが、どのBGも利用可能なのは4色だけなので、実際にゲームで使われることはあまりありませんでした。 40 | 41 | ## Mode1 42 | 43 | mode1 props 44 | 45 | ロックマンX2    クロノトリガー 46 | 47 | 最も使われているBGモードです。 48 | 49 | Mode0 の特殊効果はすべてサポートしています。タイルサイズも `8x8` か `16x16` から選択可能です。 50 | 51 | Mode0 との違いは、利用可能なBG数と、BGが使える色数です。 52 | 53 | ## Mode2 54 | 55 | mode2 props 56 | 57 | カービィSDX 58 | 59 | Mode2 はMode1とほとんど一緒ですが、`Offset-per-Tile`が使える点が異なっています。 60 | 61 | `Offset-per-Tile`はBG3を使う機能なので、背景として使えるBGはMode1と違ってBG1とBG2のみです。 62 | 63 | ## Mode3 64 | 65 | mode3 props 66 | 67 | Mode1 からBG1の表現力を高めたBGモードが、Mode3です。 68 | 69 | BG1は、256色利用可能になり、[ダイレクトカラーモード](palette.md)に対応しました。しかし、Mode1 では使えていたBG3は使用不可能になりました。 70 | 71 | ## Mode4 72 | 73 | mode4 props 74 | 75 | Mode4 は Mode2 と Mode3 を組み合わせたようなBGモードです。 76 | 77 | Mode2の`Offset-per-Tile`とMode3のダイレクトカラーモードの両方を使えますが、BG2が使えるのが4色に減っています。 78 | 79 | `Offset-per-Tile`もMode2と違って、X方向かY方向のどちらかにしかスクロールできなくなりました。 80 | 81 | ## Mode5 82 | 83 | mode5 props 84 | 85 | ルドラの秘宝    ロマサガ3 86 | 87 | Mode5の特徴は、擬似ではない512モード(真512モード)を利用可能なところです。 88 | 89 | ## Mode6 90 | 91 | mode6 props 92 | 93 | Mode6 は Mode2 と Mode5 を組み合わせたようなBGモードです。 94 | 95 | Mode2 の`Offset-per-Tile`と Mode5 の真512モードの両方を使えます。 96 | 97 | ただし、BG1しか使えず、色数も16色までです。そのせいか、Mode6が使われているゲームは(要調査)ほとんど存在しないようです。 98 | 99 | ## Mode7 100 | 101 | mode7 props 102 | 103 | F-ZERO    ヨッシーアイランド 104 | 105 | 背景レイヤを行列変換可能な特殊モードで、スーパマリオカートやF-ZEROのように擬似3D表現をするときに利用されます。 106 | 107 | Mode7では正確にはBG1の1つしか使えませんが、SETINI.6 のMode7拡張フラグをセットすると、BG2も使えるようになります。(このBG2のことをEXTBGと呼ぶこともある) 108 | 109 | Mode7の詳細については [個別ページ](./mode7.md) を参照してください。 110 | 111 | ## 参考 112 | 113 | - [SNES Background Modes 0-6](https://youtu.be/5SBEAZIfDAg) 114 | -------------------------------------------------------------------------------- /video/bg/mode7.md: -------------------------------------------------------------------------------- 1 | # Mode7 2 | 3 | mode7 props 4 | 5 | ## VRAM 6 | 7 | Mode7のVRAMは他のBGモードとは構成が異なっています。 8 | 9 | Mode7は64KBのVRAMのうち、前半32KB(0x0000..7FFF)しか利用しません。(要調査) 10 | 11 | タイルデータはVRAMの偶数バイトに、BGマップは奇数バイトに存在しています。 12 | 13 | ``` 14 | M: BGマップ(1byte) 15 | T: タイルデータ(1byte=1pixel) 16 | 17 | $0000 MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT 18 | $0020 MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT 19 | $0040 MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT 20 | .. 21 | $7FFF MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT MT 22 | ``` 23 | 24 | もともとBGマップとタイルデータを格納するメモリチップが分かれていて、それをインタリーブしたためこのよう奇妙な内容になっています。 25 | 26 | ## BGマップ 27 | 28 | BGマップでは16KBのVRAMを使用します。 29 | 30 | BGマップの大きさは 128x128タイル つまり、1024x1024px で固定です。 31 | 32 | BGマップの1エントリ(1タイル)は1バイトで、タイル番号を 0..255 の範囲で表しています。 33 | 34 | ## タイルデータ 35 | 36 | Mode7のタイルデータは 1byte = 1pixel に対応しており、256色パレットの色番号となっています。 37 | 38 | ## BG2 (EXTBG) 39 | 40 | Mode7では正確にはBG1の1つしか使えませんが、`SETINI`(0x2133) のMode7拡張フラグ(bit6)をセットすると、BG2も使えるようになります。 41 | 42 | BG2は、完全に新しいBGレイヤというわけではなく、BG1と**BGマップとタイルデータを共有**しています。 43 | 44 | ただし、タイルデータの最上位bitを優先bitとして扱うようになります。このため、BG2が利用できる色数は7bpp(128色)になります。 45 | -------------------------------------------------------------------------------- /video/bg/mosaic.md: -------------------------------------------------------------------------------- 1 | # モザイク 2 | 3 | モザイク機能は、BGレイヤに対して、画像を縦×横の一定サイズ(ブロック)で区切り、その部分を左上の色で塗りつぶすというものです。結果として、画面の解像度が下がります。 4 | 5 | **モザイク前 -> モザイク後** 6 | 7 | (これはGBAのモザイク機能ですが原理は全く同じです) 8 | 9 | 10 | 11 | ## 2106h - MOSAIC - モザイク (W) 12 | 13 | ``` 14 | Bit 0 BG1モザイク有効化フラグ (0=無効, 1=有効) 15 | Bit 1 BG2モザイク有効化フラグ (0=無効, 1=有効) 16 | Bit 2 BG3モザイク有効化フラグ (0=無効, 1=有効) 17 | Bit 3 BG4モザイク有効化フラグ (0=無効, 1=有効) 18 | Bit 4-7 モザイクサイズ (0=最小/1x1, 0Fh=最大/16x16) 19 | ``` 20 | 21 | X方向では、最初のブロックは常にテレビ画面の左端に配置されます。Y方向では、最初のブロックはテレビ画面の上部に配置されます。 22 | 23 | When changing the mosaic size mid-frame, the hardware does first finish current block (using the old vertical size) before applying the new vertical size. Technically, vertical mosaic is implemented as so: subtract the veritical index (within the current block) from the vertical scroll register (BGnVOFS). 24 | 25 | 26 | -------------------------------------------------------------------------------- /video/bg/scroll.md: -------------------------------------------------------------------------------- 1 | # スクロール 2 | 3 | ## 210Dh/210Eh- BG1HOFS/BG1VOFS - BG1(X/Y)スクロール (W) 4 | 5 | > **Note** 6 | > Mode7ではこのレジスタは違う使われ方をします。 7 | 8 | このレジスタは1バイトを2度書き込むことで16bit値を設定するレジスタで、1度目に書き込んだ値はバッファに保存されます。 9 | 10 | 2度目に書き込んだバイトを`Current`、1度目に書き込んだバイト(バッファ)を`Prev`とすると 11 | 12 | **BG1HOFS** 13 | 14 | ```c 15 | BG1HOFS = (Current<<8) | (Prev&~7) | ((BG1HOFS>>8)&7); 16 | Prev = Current; 17 | ``` 18 | 19 | **BG1VOFS** 20 | 21 | ```c 22 | BG1VOFS = (Current<<8) | Prev; 23 | Prev = Current; 24 | ``` 25 | 26 | となります。つまり、 27 | 28 | ``` 29 | 1度目の書き込み: スクロール量の下位 8bit を設定 30 | 2度目の書き込み: スクロール量の上位 2bit を設定 31 | ``` 32 | 33 | ということになります。 34 | 35 | ## 210Fh/2110h- BG2HOFS/BG2VOFS - BG2(X/Y)スクロール (W) 36 | 37 | BG1HOFS/BG1VOFS の BG2 版です。ただし、Mode7では不使用。 38 | 39 | ## 2111h/2112h- BG3HOFS/BG3VOFS - BG3(X/Y)スクロール (W) 40 | 41 | BG1HOFS/BG1VOFS の BG3 版です。ただし、Mode7では不使用。 42 | 43 | ## 2113h/2114h- BG4HOFS/BG4VOFS - BG4(X/Y)スクロール (W) 44 | 45 | BG1HOFS/BG1VOFS の BG4 版です。ただし、Mode7では不使用。 46 | 47 | -------------------------------------------------------------------------------- /video/colormath.md: -------------------------------------------------------------------------------- 1 | # カラーマス 2 | 3 | カラーマス(Color Math) はスーファミが、メイン画面、サブ画面、ウィンドウなどから実際の1枚の画面を生成するときに行う一連の処理のことです。 4 | 5 | カラーマスを使うと色々な視覚効果を生み出すことができます。例えば、スクリーン加算は光が当たっている演出を、スクリーン平均化では半透明の演出(水中など)が可能です。 6 | 7 | ## 2130h - CGWSEL - カラーマス制御レジスタA (W) 8 | 9 | ``` 10 | Bit 0 Direct Color (for 256-color BGs) (0=Use Palette, 1=Direct Color) 11 | Bit 1 Sub Screen BG/OBJ Enable (0=No/Backdrop only, 1=Yes/Backdrop+BG+OBJ) 12 | Bit 2-3 不使用 13 | Bit 4-5 カラーマス有効化 (0=Always, 1=MathWindow, 2=NotMathWin, 3=Never) 14 | Bit 6-7 Force Main Screen Black (3=Always, 2=MathWindow, 1=NotMathWin, 0=Never) 15 | ``` 16 | 17 | ## 2131h - CGADSUB - カラーマス制御レジスタB (W) 18 | 19 | ``` 20 | Bit 7 Color Math Add/Subtract (0=Add; Main+Sub, 1=Subtract; Main-Sub) 21 | Bit 6 Color Math "Div2" Half Result (0=No divide, 1=Divide result by 2) 22 | Bit 5 Color Math when Main Screen = Backdrop (0=Off, 1=On) ;\ 23 | Bit 4 Color Math when Main Screen = OBJ/Palette4..7 (0=Off, 1=On) ; OFF: Show 24 | - Color Math when Main Screen = OBJ/Palette0..3 (Always=Off) ; Raw Main, 25 | Bit 3 Color Math when Main Screen = BG4 (0=Off, 1=On) ; or 26 | Bit 2 Color Math when Main Screen = BG3 (0=Off, 1=On) ; ON: Show 27 | Bit 1 Color Math when Main Screen = BG2 (0=Off, 1=On) ; Main+/-Sub 28 | Bit 0 Color Math when Main Screen = BG1 (0=Off, 1=On) ;/ 29 | ``` 30 | 31 | Half-Color (Bit6): Ignored if "Force Main Screen Black" is used, also ignored on transparent subscreen pixels (those use the fixed color as sub-screen backdrop without division) (whilst 2130.1 uses the fixed color as non-transparent one, which allows division). 32 | 33 | Bit0-5: Seem to affect MAIN SCREEN layers: 34 | 35 | ``` 36 | Disable = Display RAW Main Screen as such (without math) 37 | Enable = Apply math on Mainscreen 38 | (Ie. 212Ch enables the main screen, 2131h selects if math is applied on it) 39 | ``` 40 | 41 | ## 2132h - COLDATA - Color Math Sub Screen Backdrop Color (W) 42 | 43 | This 8bit port allows to manipulate some (or all) bits of a 15bit RGB value. Examples: Black: write E0h (R,G,B=0), Cyan: write 20h (R=0) and DFh (G,B=1Fh). 44 | 45 | ``` 46 | Bit 7 Apply Blue (0=No change, 1=Apply Intensity as Blue) 47 | Bit 6 Apply Green (0=No change, 1=Apply Intensity as Green) 48 | Bit 5 Apply Red (0=No change, 1=Apply Intensity as Red) 49 | Bit 4-0 Intensity (0..31) 50 | ``` 51 | 52 | The Sub Screen Backdrop Color is used when all sub screen layers are disabled or transparent, in this case the "Div2" Half Color Math isn't applied (ie. 2131h.Bit6 is ignored); there is one exception: If "Sub Screen BG/OBJ Enable" is off (2130h.Bit1=0), then the "Div2" isn't forcefully ignored. 53 | For a FULLY TRANSPARENT backdrop: Set this register to Black (adding or subtracting black has no effect, and, with "Div2" disabled/ignored, the raw Main screen is displayed as is). 54 | 55 | ## カラーマス 56 | 57 | Color Math can be disabled by setting 2130h.Bit4-5, or by clearing 2131h.Bit0-5. When it is disabled, only the Main Screen is displayed, and the Sub Screen has no effect on the display. 58 | 59 | Color Math occurs only if the front-most Main Screen pixel has math enabled (via 2131h.Bit0-5.), and only if the front-most Sub Screen pixel has same or higher (XXX or is it same or lower -- or is it ANY priority?) priority than the Main Screen pixel. 60 | 61 | Same priority means that, for example, BG1 can be mathed with itself: BG1+BG1 gives double-brightness (or same brightness when Div2 is enabled), and, BG1-BG1 gives Black. 62 | 63 | Addition/Subtraction is done per R,G,B color fragment, the results can be (optionally) divided by 2, and are then saturated to Max=31 and Min=0). 64 | 65 | ## Force Main Screen Black 66 | 67 | This feature forces the whole Main Screen (including Backdrop) to become black, so, normally, the whole screen becomes black. However, color addition can be still applied (but, with the "Div2" not being applied). Whereas, although it looks all black, the Main Screen is still divided into black BG1 pixels, black BG2 pixels, and so on. Of which, one can disable Color Math for some of the pixels. Color Subtraction has no effect (since the pixels can't get blacker than black). 68 | 69 | ## Hires and Pseudo 3-Layer Math 70 | 71 | In Hires modes (BG Mode 5,6 and Pseudo Hires via SETINI), the main/sub screen pixels are rendered as half-pixels of the high-resolution image. The TV picture is so blurry, that the result will look quite similar to Color Addition with Div2 - some games (Jurassic Park and Kirby's Dream Land 3) are actually using it for that purpose; the advantage is that one can additionally apply COLDATA addition to (both) main/sub-screen layers, ie. the result looks like "(main+sub)/2+coldata". 72 | 73 | ## 参考 74 | 75 | - [Color Math - Super Nintendo Entertainment System Features Pt. 03b](https://youtu.be/zcoU6-9_fDM) 76 | -------------------------------------------------------------------------------- /video/control.md: -------------------------------------------------------------------------------- 1 | # 制御レジスタ 2 | 3 | ## 2100h - INIDISP - ディスプレイ制御レジスタ1 (W) 4 | 5 | ``` 6 | Bit 0-3 明るさ (0=真っ黒, or N=1..15: Brightness*(N+1)/16) 7 | Bit 4-6 不使用 8 | Bit 7 FBlankフラグ (FBlank = Forced blank, 0=何もしない, 1=画面を真っ黒に) 9 | ``` 10 | 11 | 通常時は VRAM,OAM,CGRAM には VBlank中 のみアクセスできますが、FBlank中 は自由にアクセスできます。 12 | 13 | FBlankであったとしても、TVは Vsync/Hsync の信号を受け取り続けます。(結果として、真っ黒な画面を描画し続けます) 14 | 15 | 同様にCPUも FBlank であったとしても、HBlank/VBlank の信号を受け取り続け、(有効化されている場合は)NMIs, IRQs, HDMAs も生成され続けます。 16 | 17 | ``` 18 | Forced blank doesn't apply immediately... so one must wait whatever 19 | (maybe a scanline) before VRAM can be freely accessed... or is it only 20 | vice-versa: disabling forced blank doesn't apply immediately/shows garbage 21 | pixels? 22 | ``` 23 | 24 | ## 212Ch/212Dh - TM/TS - メイン/サブ画面レイヤ制御 (W) 25 | 26 | 各画面レイヤをメイン画面に映すか、サブ画面に映すか、両方に映すかを制御するレジスタです。 27 | 28 | ``` 29 | Bit 0 BG1 (0=無効, 1=有効) 30 | Bit 1 BG2 (0=無効, 1=有効) 31 | Bit 2 BG3 (0=無効, 1=有効) 32 | Bit 3 BG4 (0=無効, 1=有効) 33 | Bit 4 OBJ (0=無効, 1=有効) 34 | Bit 5-7 不使用 35 | Bit - Backdrop (メイン/サブ両方で常に有効) 36 | ``` 37 | 38 | Backdrop(背景色)は、メイン画面とサブ画面の両方で常に有効になっています。そのうち、サブ画面の背景は、その色を黒に設定することで効果的に無効化(完全透過化)することができます。 39 | 40 | ## 2133h - SETINI - ディスプレイ制御レジスタ2 (W) 41 | 42 | ``` 43 | Bit 0 V-Scanning (0=Non Interlace, 1=Interlace) (See Port 2105h) 44 | Bit 1 OBJ V-Direction Display (0=Low, 1=High Resolution/Smaller OBJs) 45 | IN THE INTERLACE MODE, SELECT EITHER OF 1-DOT PER LINE OR 1-DOT 46 | REPEATED EVERY 2-LINES. IF "1" IS WRITTEN, THE OBJ SEEMS REDUCED 47 | HALF VERTICALLY IN APPEARANCE. 48 | Bit 2 オーバースキャンフラグ (0=無効(224), 1=有効(239)) 49 | Bit 3 擬似512モード (0=無効, 1=有効) (SHIFT SUBSCREEN HALF DOT TO THE LEFT) 50 | Bit 4-5 不使用 51 | Bit 6 EXTBGモード (0=無効, 1=有効) 52 | Bit 7 External Synchronization (0=Normal, 1=Super Impose and etc.) 53 | ``` 54 | 55 | ## 213Eh - STAT77 - PPU1ステータス (R) 56 | 57 | ``` 58 | Bit 0-3 PPU1バージョン番号 (確認されてる限り 1 のみ) 59 | Bit 4 不使用 (PPU1 open bus) (same as last value read from PPU1) 60 | Bit 5 マスター/スレーブモード (PPU1.Pin25) (0=Normal=Master) 61 | Bit 6 OBJ Range overflow (0=Okay, 1=More than 32 OBJs per scanline) 62 | Bit 7 OBJ Time overflow (0=Okay, 1=More than 8x34 OBJ pixels per scanline) 63 | ``` 64 | 65 | The overflow flags are cleared at end of V-Blank, but NOT during forced blank! 66 | 67 | The overflow flags are set (regardless of OBJ enable/disable in 212Ch), at following times: Bit6 when V=OBJ.YLOC/H=OAM.INDEX*2, bit7 when V=OBJ.YLOC+1/H=0. 68 | 69 | ## 213Fh - STAT78 - PPU2ステータス (R) 70 | 71 | ``` 72 | Bit 0-3 PPU2バージョン番号 (確認されてる限り 1,2,3 が存在) 73 | Bit 4 フレームレート (PPU2.Pin30) (0=NTSC/60Hz, 1=PAL/50Hz) 74 | Bit 5 不使用 (PPU2 open bus) (same as last value read from PPU2) 75 | Bit 6 H/V-Counter/Lightgun/Joypad2.Pin6 Latch Flag (0=No, 1=New Data Latched) 76 | Bit 7 現在のインターレース (0=1stフレーム, 1=2ndフレーム) 77 | ``` 78 | 79 | このレジスタを読み出すと、ラッチフラグ(bit6)がリセットされ、OPHCT/OPVCT の1st/2ndリードフリップフロップがリセットされます。 80 | 81 | 82 | -------------------------------------------------------------------------------- /video/layer.md: -------------------------------------------------------------------------------- 1 | # 画面レイヤ 2 | 3 | ## 描画先の画面 4 | 5 | スーファミにはメイン画面とサブ画面という2つの仮想画面があります。 6 | 7 | 描画の際には、この2つの画面を重ねることで1つの画面として出力します。 8 | 9 | 各画面レイヤを メイン画面に映すか、サブ画面に映すか、両方に映すか の制御は[TM/TS](control.md) で行っています。 10 | 11 | メイン画面は通常の画面で、サブ画面は[`Color Math`](colormath.md)と`512-pixel Hires Mode`でのみ使用されます。 12 | 13 | ## レイヤの優先度 14 | 15 | ``` 16 | 記法: 17 | BD: Backdrop、背景色 (常に一番後ろ) 18 | OBJ.N 優先度NのOBJ (OAMで設定 N=0,1,2,3) 19 | BGn.0 BGレイヤのタイル 20 | BGn.1 BGレイヤの優先タイル (BGマップのbit13が1) 21 | BG3.Na BGMODE.3 が 1 (モード1のみ) 22 | BG3.Nb BGMODE.3 が 0 (モード1のみ) 23 | BG2.1p Mode7のBG2のうち優先フラグが1のもの 24 | BG2.0p Mode7のBG2 25 | ``` 26 | 27 | ``` 28 | Mode0 Mode1 Mode2 Mode3 Mode4 Mode5 Mode6 Mode7 29 | - BG3.1a - - - - - - 30 | OBJ.3 OBJ.3 OBJ.3 OBJ.3 OBJ.3 OBJ.3 OBJ.3 OBJ.3 31 | BG1.1 BG1.1 BG1.1 BG1.1 BG1.1 BG1.1 BG1.1 - 32 | BG2.1 BG2.1 - - - - - - 33 | OBJ.2 OBJ.2 OBJ.2 OBJ.2 OBJ.2 OBJ.2 OBJ.2 OBJ.2 34 | BG1.0 BG1.0 BG2.1 BG2.1 BG2.1 BG2.1 - BG2.1p 35 | BG2.0 BG2.0 - - - - - - 36 | OBJ.1 OBJ.1 OBJ.1 OBJ.1 OBJ.1 OBJ.1 OBJ.1 OBJ.1 37 | BG3.1 BG3.1b BG1.0 BG1.0 BG1.0 BG1.0 BG1.0 BG1 38 | BG4.1 - - - - - - - 39 | OBJ.0 OBJ.0 OBJ.0 OBJ.0 OBJ.0 OBJ.0 OBJ.0 OBJ.0 40 | BG3.0 BG3.0a BG2.0 BG2.0 BG2.0 BG2.0 - BG2.0p 41 | BG4.0 BG3.0b - - - - - - 42 | BD BD BD BD BD BD BD BD 43 | ``` 44 | -------------------------------------------------------------------------------- /video/mul.md: -------------------------------------------------------------------------------- 1 | # [乗算](https://problemkaputt.de/fullsnes.htm#snesmathsmultiplydivide) 2 | 3 | Mode0-6のとき、以下のレジスタは掛け算用のレジスタとして使用できます。 4 | 5 | ```c 6 | MPY = M7A * M7B 7 | ``` 8 | 9 | ## 211Bh - M7A - PPU被乗数レジスタ (W) 10 | 11 | 符号付き16bit整数です。 12 | 13 | ``` 14 | 1度目の書き込み: 被乗数の下位 8bit を設定 15 | 2度目の書き込み: 被乗数の上位 8bit を設定 16 | ``` 17 | 18 | ## 211Ch - M7B - PPU乗数レジスタ (W) 19 | 20 | 符号付き8bit整数です。 21 | 22 | `211Bh` か `211Ch` に書き込みを行うと、結果が `2134h-2136h` に反映されます。 23 | 24 | `21xx`レジスタは高速なので、`MOV A,[211Ch]` か `MOV A,[1Ch]` (`D=2100h`)で結果を読み出す際に、(CPUのクロックが3.5MHz だとしても)掛け算終了まで待つための待機時間は不要です。 25 | 26 | ## 2134h/2135h/2136h - MPY - PPU積レジスタ (R) 27 | 28 | 符号付き24bit整数です。 29 | 30 | ``` 31 | MPYL(2134h) = 0-7bit 32 | MPYM(2135h) = 8-15bit 33 | MPYH(2136h) = 16-23bit 34 | ``` 35 | 36 | ## Mode7 について 37 | 38 | これらのレジスタは Mode7 では伸縮回転のパラメータレジスタとして使われます。 39 | 40 | Mode7 のときは、上記のレジスタは VBlank中 または 強制Blank(INIDISP.7)中にのみ利用可能です。 41 | 42 | それ以外のときにアクセスしてはいけません。例えば、MPYL/MPYM/MPYH からの読み出しはゴミ値を返し、M7A/M7B への書き込みは画面がおかしくなります。 43 | -------------------------------------------------------------------------------- /video/obj/oam.md: -------------------------------------------------------------------------------- 1 | # OAM 2 | 3 | スーファミには、544B のOAMがあります。OAMはアドレス空間にマッピングされておらず、[I/Oレジスタを通してアクセスする](../../memory/oam.md)必要があります。 4 | 5 | OAM は 128個のOBJ(スプライト)の情報を表しています。 6 | 7 | このメモリ領域には、128個のOBJについて、各OBJの座標、サイズ、タイル番号などの属性(アトリビュート)が格納されています。 8 | 9 | OAM は 0..511バイト と 512..544バイト で内容が異なっています。[1](#table) 10 | 11 | 0..511バイトは 4バイトのデータが128個並んでいて、各OBJに対応しています。 12 | 13 | ``` 14 | 0..3: OBJ0 15 | 4..7: OBJ1 16 | 8..11: OBJ2 17 | ... 18 | 507..511: OBJ127 19 | ``` 20 | 21 | 512..544バイトは 2bit のデータが128個並んでいて、同じく各OBJに対応しています。 22 | 23 | ``` 24 | 512: 25 | bit0-1: OBJ0 26 | bit2-3: OBJ1 27 | bit4-5: OBJ2 28 | bit6-7: OBJ3 29 | 513: 30 | bit0-1: OBJ4 31 | bit2-3: OBJ5 32 | bit4-5: OBJ6 33 | bit6-7: OBJ7 34 | ... 35 | 543: 36 | bit0-1: OBJ124 37 | bit2-3: OBJ125 38 | bit4-5: OBJ126 39 | bit6-7: OBJ127 40 | ``` 41 | 42 | つまり、1つのOBJあたり、4バイト と 2bit の属性データがあります。 43 | 44 | ``` 45 | 0..511バイト 46 | Byte 0 X座標(下位8bit) 47 | Byte 1 Y座標 48 | Byte 2 タイル番号(下位8bit) 49 | Byte 3 属性 50 | Bit0: タイル番号(上位1bit) 51 | Bit1-3: パレット番号 52 | Bit4-5: 優先度(0=最低, 3=最大) 53 | Bit6: X反転 54 | Bit7: Y反転 55 | 56 | 512..544バイト 57 | Bit 0 X座標(上位1bit) 58 | Bit 1 サイズ (0=小, 1=大 具体的なサイズはOBSELに依存) 59 | ``` 60 | 61 | 1: 0..511バイトをOAMの下位テーブル, 512..543バイトをOAMの上位テーブルと呼ぶこともあります 62 | -------------------------------------------------------------------------------- /video/obj/obsel.md: -------------------------------------------------------------------------------- 1 | # OBSEL 2 | 3 | ## 2101h - OBSEL - オブジェクトサイズ/ベースアドレス (W) 4 | 5 | ``` 6 | Bit 0-2 タイルデータ(前半)のベースアドレス (16KB単位) 7 | BASE = OBSEL.bit(0,2) * 16KB 8 | Bit 3-4 タイルデータ前後半のベースアドレスがどれだけ離れているか (8KB単位) 9 | タイルデータ前半: タイル番号 000h..0FFh 10 | タイルデータ後半: タイル番号 100h..1FFh 11 | BASE1 を タイルデータ前半 のベースアドレス、 BASE2 を後半のそれとすると、 12 | BASE1 = OBSEL.bit(0,2) * 16KB 13 | BASE2 = BASE1 + 0x2000 + (OBSEL.bit(3,4) * 8KB) 14 | Bit 5-7 OBJサイズ 15 | Val Small Large 16 | 0 = 8x8 16x16 ;Caution: 17 | 1 = 8x8 32x32 ;In 224-lines mode, OBJs with 64-pixel height 18 | 2 = 8x8 64x64 ;may wrap from lower to upper screen border. 19 | 3 = 16x16 32x32 ;In 239-lines mode, the same problem applies 20 | 4 = 16x16 64x64 ;also for OBJs with 32-pixel height. 21 | 5 = 32x32 64x64 22 | 6 = 16x32 32x64 (undocumented) 23 | 7 = 16x32 32x32 (undocumented) 24 | (Ie. a setting of 0 means Small OBJs=8x8, Large OBJs=16x16 pixels) 25 | (Whether an OBJ is "small" or "large" is selected by a bit in OAM) 26 | ``` -------------------------------------------------------------------------------- /video/obj/priority.md: -------------------------------------------------------------------------------- 1 | # 優先度 2 | 3 | OBJの優先度には 4 | 5 | - BGに対する優先度 6 | - OBJ同士の優先度 7 | 8 | の2種類あります。 9 | 10 | ## BGに対する優先度 11 | 12 | BGに対する優先度 は 0..3 です。各OBJがそれぞれ持っているもので、OAMの3nバイト目に格納されています。 モードによってどのBGレイヤの上にくるかが変わってきます。 13 | 14 | ## OBJ同士の優先度 15 | 16 | OBJ同士の優先度 は BGに対する優先度 が同じ場合に、OBJ同士が重なった時の優先度です。 17 | 18 | 最高優先度のOBJをOBJ(n)とすると、 19 | 20 | ``` 21 | 優先度 22 | 23 | 高 低 24 | OBJ(n) -> OBJ(n+1) -> OBJ(n+2) -> ... -> OBJ127 -> OBJ0 -> ... -> OBJ(n-1) 25 | ``` 26 | 27 | となります。デフォルトでは OBJ0 が 最高優先度になっていますが、[OAMADD](../../memory/oam.md) でこれは変更可能です。 28 | 29 | -------------------------------------------------------------------------------- /video/palette.md: -------------------------------------------------------------------------------- 1 | # 🎨 パレット 2 | 3 | SNESには、パレット用のメモリ(CGRAM)が 512B あります。 4 | 5 | パレットはアドレス空間にマッピングされておらず、[I/Oレジスタを通してアクセスする](../memory/palette.md)必要があります。 6 | 7 | パレットのエントリは2バイトで256個あります。エントリ1つが1色に対応しています。 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
bit1514131211109876543210
color--Blue(0..31)Green(0..31)Red(0..31)
41 | 42 | ## パレットの内訳 43 | 44 | エントリ | 内容 45 | -- | -- 46 | 00h | 背景色(BG/OBJが全て透明色の時に適用) 47 | 01h-FFh | 256色BGパレット 48 | 01h-7Fh | 128色BGパレット (Mode7のBG2) 49 | 01h-7Fh | 16色BGパレット x 8 50 | 01h-1Fh | 4色BGパレット x 8 (Mode0のBG2-4は除く) 51 | 21h-3Fh | 4色BGパレット x 8 (Mode0のBG2のみ) 52 | 41h-5Fh | 4色BGパレット x 8 (Mode0のBG3のみ) 53 | 61h-7Fh | 4色BGパレット x 8 (Mode0のBG4のみ) 54 | 81h-FFh | 16色BGパレット x 8 (このうち半分はColor-Mathは無効) 55 | N/A | サブ背景色 (CGRAM中にはなく、COLDATAを通して設定) 56 | 57 | ## ダイレクトカラーモード 58 | 59 | 背景が256色利用な場合(Mode3,4,7 の BG1)は、ダイレクトカラーモードが選択可能でした。(via 2130h.Bit0; this bit hides in one of the Color-Math registers, although it isn't related to Color-Math) 60 | 61 | 本来色番号だったはずの8bitは `BBGGGRRR` として解釈されます。また[BGマップ](vram.md)のパレット番号は `bgr` として解釈され、結果として RGB555 の `BBb00:RRRr0:GGGg0` が色として使われます。 62 | 63 | ただし、BGマップの`bgr`はタイルごとに適用されることと、`bgr`はMode3,4でしか使えない(Mode7のBGマップにはパレット番号を指定するbitがない)ことに注意してください。 64 | 65 | ``` 66 | Color Bit7-0 all zero --> Transparent ;-Color "Black" is Transparent! 67 | Color Bit7-6 Blue Bit4-3 ;\ 68 | Palette Bit 2 Blue Bit2 ; 5bit Blue 69 | N/A Blue Bit1-0 (always zero) ;/ 70 | Color Bit5-3 Green Bit4-2 ;\ 71 | Palette Bit 1 Green Bit1 ; 5bit Green 72 | N/A Green Bit0 (always zero) ;/ 73 | Color Bit2-0 Red Bit4-2 ;\ 74 | Palette Bit 0 Red Bit1 ; 5bit Red 75 | N/A Red Bit0 (always zero) ;/ 76 | ``` 77 | 78 | ダイレクトカラーモードで8bitをすべて0にした場合は透明色として扱われてしまうため、黒(`#000000`)を定義するには、背景色を黒に設定するか(BG1の後ろにレイヤーがない場合のみ有効)、黒に近い色(例: 01h=赤黒)で妥協する必要があります。 79 | 80 | またダイレクトカラーモードと対比して、通常のパレットを使った色指定はインデックスカラーモードと呼ばれることもあります。 81 | 82 | ## Screen Border Color 83 | 84 | The Screen Border is always Black (no matter of CGRAM settings and Sub Screen Backdrop Color). NTSC 256x224 images are (more or less) fullscreen, so there should be no visible screen border (however, a 2-3 pixel border may appear at the screen edges if the screen isn't properly centered). Both PAL 256x224 and PAL 256x239 images images will have black upper and lower screen borders (a fullscreen PAL picture would be around 256x264, which isn't supported by the SNES). 85 | 86 | ## Forced Blank Color 87 | 88 | In Forced Blank, the whole screen is Black (no matter of CGRAM settings, Sub Screen Backdrop Color, and Master Brightness settings). Vsync/Hsync are kept generated (sending a black picture with valid Sync signals to the TV set). 89 | -------------------------------------------------------------------------------- /video/scanline.md: -------------------------------------------------------------------------------- 1 | # 描画サイクル 2 | 3 | > **Note** 4 | > サイクルはマスターサイクルのことを指します。 5 | 6 | ``` 7 | 0 256 341 8 | ┌────────────────────────────────────┬─────────────┐ 9 | │ │ │ 10 | │ │ │ 11 | │ │ │ 12 | │ │ │ 13 | │ │ │ 14 | │ Drawing │ HBlank │ 15 | │ │ │ 16 | │ │ │ 17 | │ │ │ 18 | │ │ │ 19 | 224 ├────────────────────────────────────┴─────────────┤ 20 | │ │ 21 | │ VBlank │ 22 | │ │ 23 | 262 └──────────────────────────────────────────────────┘ 24 | ``` 25 | 26 | スーファミの1スキャンラインは1364サイクルで、1フレームは262スキャンラインです。(`21.442080 MHz/(262*1364) = 60 Hz`) 27 | 28 | また1スキャンラインごとに、40サイクルをDRAMのリフレッシュに費やすため、CPUは1スキャンラインあたり1324サイクルだけ実行可能です。 29 | 30 | HBlank[1](#hblank)は `H=256..341` までの間で、VBlank[2](#vblank)は `V=225..262` の間です。 31 | 32 | FBlank中 の場合を除いて HBlank または VBlank の間しかVRAMにアクセスすることはできません。 33 | 34 | スーファミのゲームでは、フレームの描画中(`V=0..224`)にキャラクターの移動や衝突判定、敵の行動などの入力を受けて処理し、VBlank中に新しいデータをVRAMにコピーするというのが一般的でした。 35 | 36 | ``` 37 | 要調査: 38 | スーファミは縦解像度を 224 lines or 239 lines のどちらかで選択可能だった?(それによってVBlankの期間が 38 lines or 23 lines と変わってきた。ただし、VBlank期間は貴重なのでほとんどのゲームは224だったっぽい) 39 | ``` 40 | 41 | 1: アナログTVの電子ビームが画面の左側に戻る時間を稼ぐために描画を無効化すること 42 | 43 | 2: アナログTVが描画を無効にして、TVの電子ビームが一旦画面の下に到達してから左上に戻る時間を確保すること 44 | 45 | ## 2137h - SLHV - H/Vカウンタラッチ (R) 46 | 47 | ``` 48 | Bit 0-7 不使用 (CPU Open Bus; usually last opcode, 21h for "MOV A,[2137h]") 49 | ``` 50 | 51 | このレジスタからリードしたときに、現在のH/Vカウンタが OPHCT/OPVCT にラッチ(セット)されます。 52 | 53 | Hカウンタは 0..339 の範囲の値を取り、22..277 が画面に表示されます。Vカウンタは 0..261 の範囲の値を取り、1..224 の範囲が画面に表示されます。 54 | 55 | Reading here works "as if" dragging IO7 low (but it does NOT actually output a LOW level to IO7 on joypad 2). 56 | 57 | ## 213Ch/213Dh - OPHCT/OPVCT - H/Vカウンタ (R) 58 | 59 | `WRIO.7`がセットされているときに、以下のどれかが起こったときにH/Vカウンタがラッチ(セット)されます。 60 | 61 | ``` 62 | * ソフトウェアによる SLHV(2137h) からの(ダミー)リード 63 | * ソフトウェアによって WRIO.7 が 1 から 0 になったとき 64 | * Lightgun が High から Low になったとき 65 | ``` 66 | 67 | データがラッチされると、STAT78.6 のラッチフラグがセットされます。 68 | 69 | ``` 70 | 1回目のRead: 下位8bit 71 | 2回目のRead: 上位1bit (other 7bit PPU2 open bus; last value read from PPU2) 72 | ``` 73 | 74 | There are two separate 1st/2nd-read flipflops (one for OPHCT, one for OPVCT), both flipflops can be reset by reading from Port 213Fh (STAT78), the flipflops aren't automatically reset when latching occurs. 75 | -------------------------------------------------------------------------------- /video/vram.md: -------------------------------------------------------------------------------- 1 | # VRAM 2 | 3 | スーファミには、64KBのVRAMがあります。VRAMはアドレス空間にマッピングされておらず、[I/Oレジスタを通してアクセスする](../memory/vram.md)必要があります。 4 | 5 | VRAMは BGマップ と タイルデータ を保持しています。 6 | 7 | BGマップが配置されるアドレスは [BGnSC](./bg/control.md) で、タイルデータが配置されるアドレスは [BGNBA](./bg/control.md) で設定します。 8 | 9 | ## 🗺 BGマップ 10 | 11 | [BGマップ](./bg/bgmap.md) を参照してください。 12 | 13 | ## 🟩 8x8タイルデータ 14 | 15 | 利用可能な色数に応じて、8x8タイルの使うバイト数は変わってきます。 16 | 17 | ``` 18 | 4色: 16バイト ; 2bpp 19 | 16色: 32バイト ; 4bpp 20 | 256色: 64バイト ; 8bpp 21 | ``` 22 | 23 | ``` 24 | 2bpp(4色, 16バイト): 25 | Row0: 00h, 01h 26 | Row1: 02h, 03h 27 | .. 28 | Row6: 0Ch, 0Dh 29 | Row7: 0Eh, 0Fh 30 | 31 | 4bpp(16色): 32 | Row0: 00h, 01h, 10h, 11h 33 | Row1: 02h, 03h, 12h, 13h 34 | .. 35 | Row6: 0Ch, 0Dh, 1Ch, 1Dh 36 | Row7: 0Eh, 0Fh, 1Eh, 1Fh 37 | 38 | 8bpp(256色): 39 | Row0: 00h, 01h, 10h, 11h, 20h, 21h, 30h, 31h 40 | Row1: 02h, 03h, 12h, 13h, 22h, 23h, 32h, 33h 41 | .. 42 | Row2: 0Ch, 0Dh, 1Ch, 1Dh, 2Ch, 2Dh, 3Ch, 3Dh 43 | Row3: 0Eh, 0Fh, 1Eh, 1Fh, 2Eh, 2Fh, 3Eh, 3Fh 44 | ``` 45 | 46 | BGタイルは、BGモードに応じて色数が 4/16/256 色のどれかになりますが、OBJタイルは常に16色です。 47 | 48 |
49 | Mode7の場合 50 | 51 | ただし、Mode7 のタイルデータだけは例外です。 52 | 53 | Mode7のタイルデータは 1byte = 1pixel に対応しており、256色パレットの色番号となっています。 54 | 55 | VRAMは、オフセット(バイト単位)が偶数のBGマップと奇数のタイルデータに分かれており、8x8タイルデータの内容は以下のようになります。 56 | 57 | ``` 58 | Row0: 01h,03h,05h,07h,09h,0Bh,0Dh,0Fh 59 | Row1: 11h,13h,15h,17h,19h,1Bh,1Dh,1Fh 60 | Row2: 21h,23h,25h,27h,29h,2Bh,2Dh,2Fh 61 | Row3: 31h,33h,35h,37h,39h,3Bh,3Dh,3Fh 62 | Row4: 41h,43h,45h,47h,49h,4Bh,4Dh,4Fh 63 | Row5: 51h,53h,55h,57h,59h,5Bh,5Dh,5Fh 64 | Row6: 61h,63h,65h,67h,69h,6Bh,6Dh,6Fh 65 | Row7: 71h,73h,75h,77h,79h,7Bh,7Dh,7Fh 66 | ``` 67 |
68 | 69 | ## 🟧 16x16(以上の)タイル 70 | 71 | BGタイルは 16x16、OBJは(最大で) 64x64 と8x8より大きいタイルサイズを取ることが可能です。 72 | 73 | 8x8より大きいタイルサイズは、8x8のタイルを複数組み合わせて実現されます。 74 | 75 | BGの場合、16x16なので、8x8のタイルが2x2集まって構成されています。BGマップのタイル番号Nは左上の8x8タイルを指します。 76 | 77 | このとき、16x16タイルは 78 | 79 | ``` 80 | N+00, N+01 81 | N+16, N+17 82 | ``` 83 | 84 | のようになります。 85 | 86 | 32x32のOBJの場合、OAMエントリ指すのタイル番号がNとすると 87 | 88 | ``` 89 | N+00, N+01, N+02, N+03 90 | N+16, N+17, N+18, N+19 91 | N+32, N+33, N+34, N+35 92 | N+48, N+49, N+50, N+51 93 | ``` 94 | 95 | となります。 96 | 97 | ただし、OBJタイルはタイル番号の桁上がりがないことに注意してください。 98 | 99 | ``` 100 | 16x16 BGタイル: 101 | 1FFh, 200h 102 | 20Fh, 210h 103 | 104 | 16x16 OBJタイル: 105 | 1FFh, 1F0h 106 | 10Fh, 100h 107 | ``` 108 | 109 | ## 🛎 VRAMへのアクセス 110 | 111 | [こちら](../memory/vram.md)を参照してください。 112 | -------------------------------------------------------------------------------- /video/window.md: -------------------------------------------------------------------------------- 1 | # 🪟 ウィンドウ 2 | 3 | ウィンドウを使うと、選択した領域のBG/OBJレイヤを無効化したり、選択した領域のカラーマス効果を変更することができます。 4 | 5 | 次のようにスポットライトのような効果を出したりできます。 6 | 7 | スーパーマリオコレクション  スーパーマリオワールド クッパの城裏口 8 | 9 | ## 2126h - WHx - Window座標 (W) 10 | 11 | ``` 12 | 2126h: WH0 - Window 1 左座標 13 | 2127h: WH1 - Window 1 右座標 14 | 2128h: WH2 - Window 2 左座標 15 | 2129h: WH3 - Window 2 右座標 16 | ``` 17 | 18 | ウィンドウのX方向の境界を指定します。Y方向の境界はないことに注意してください。 19 | 20 | IRQやHDMAでウィンドウレジスタを操作することで、これらの境界を実装することができます。 21 | 22 | ``` 23 | Bit 7-0 Window座標 (0=左端, 255=右端) 24 | ``` 25 | 26 | ウィンドウ内側の領域はX1からX2まで(X1とX2の座標を含む)なので、ウィンドウの幅はX2-X1+1です。 27 | 28 | 幅が0(または負)の場合、ウィンドウ内側の領域は空になり、画面全体がウィンドウ外側の領域として扱われます。 29 | 30 | ## 2123h - WxxSEL - Windowマスク設定 (W) 31 | 32 | ``` 33 | 2123h: W12SEL - Window BG1/BG2 マスク設定 34 | 2124h: W34SEL - Window BG3/BG4 マスク設定 35 | 2125h: WOBJSEL - Window OBJ/MATH マスク設定 36 | ``` 37 | 38 | ``` 39 | Bit 2123h 2124h 2125h 40 | 0-1 BG1 BG3 OBJ ウィンドウ1領域 (0..1=無効, 2=内, 3=外) 41 | 2-3 BG1 BG3 OBJ ウィンドウ2領域 (0..1=無効, 2=内, 3=外) 42 | 4-5 BG2 BG4 MATH ウィンドウ1領域 (0..1=無効, 2=内, 3=外) 43 | 6-7 BG2 BG4 MATH ウィンドウ2領域 (0..1=無効, 2=内, 3=外) 44 | ``` 45 | 46 | X1..X2 座標の内側か外側のどちらをウィンドウ領域として扱うかを選択したり、ウィンドウ領域を無効にすることができます。 47 | 48 | ## 212Ah/212Bh - WBGLOG/WOBJLOG - Window 1/2 マスク処理内容 (W) 49 | 50 | ``` 51 | Bit 212Ah 212Bh 52 | 0-1 BG1 OBJ Window 1/2 マスク処理内容 (0=OR, 1=AND, 2=XOR, 3=XNOR) 53 | 2-3 BG2 MATH Window 1/2 マスク処理内容 (0=OR, 1=AND, 2=XOR, 3=XNOR) 54 | 4-5 BG3 - Window 1/2 マスク処理内容 (0=OR, 1=AND, 2=XOR, 3=XNOR) 55 | 6-7 BG4 - Window 1/2 マスク処理内容 (0=OR, 1=AND, 2=XOR, 3=XNOR) 56 | ``` 57 | 58 | ウィンドウ1とウィンドウ2の領域を統合し、最終的に1つのウィンドウ領域にすることができます。統合された領域(最終ウィンドウ領域)は、TMW,TSW,CGWSEL によって利用されます。 59 | 60 | このレジスタでは、ウィンドウ1/2の統合をどのようなロジックで行うかを設定します。ロジック(OR/AND/XOR/XNOR)は、`WxxSEL`レジスタで、ウィンドウ1とウィンドウ2 の両方を有効にした場合に適用されます。[1](#xnor) 61 | 62 | 片方のウィンドウだけが有効な場合、そのウィンドウがそのまま最終ウィンドウ領域として使用されます。両方が無効の場合、最終ウィンドウ領域は空になります。 63 | 64 | ## 212Eh/212Fh - TMW/TSW - ウィンドウ領域無効化 (W) 65 | 66 | メイン/サブ画面のウィンドウ領域内のビデオレイヤを無効化することができます。 67 | 68 | ``` 69 | Bit 0 BG1 (0=無効, 1=有効) 70 | Bit 1 BG2 (0=無効, 1=有効) 71 | Bit 2 BG3 (0=無効, 1=有効) 72 | Bit 3 BG4 (0=無効, 1=有効) 73 | Bit 4 OBJ (0=無効, 1=有効) 74 | Bit 5-7 不使用 75 | Bit - Backdrop (メイン/サブ両方で常に有効) 76 | ``` 77 | 78 | 1: `XNOR` は `Not XOR` のことで、 `!(Win1 XOR Win2)` 79 | --------------------------------------------------------------------------------