/// <summary> /// メモリを1回右ローテート /// N: 結果の最上位ビット /// Z: 結果が0であるか /// C: はみ出たビット /// </summary> void ROR(ref byte value) { byte tmp = Nes.FetchBit(value, 0); value = (byte)((value >> 1) + Convert.ToInt32(cFlag) * 0x80); cFlag = tmp != 0; FlagNandZ(value); }
/// <summary> /// メモリを1回左ローテート /// N: 結果の最上位ビット /// Z: 結果が0であるか /// C: はみ出たビット /// </summary> void ROL(ref byte value) { byte tmp = Nes.FetchBit(value, 7); value = (byte)((value << 1) + Convert.ToInt32(cFlag)); cFlag = tmp != 0; FlagNandZ(value); }
/// <summary> /// bitテストを行う /// N: メモリのbit7 /// V: メモリのbit6 /// Z: 結果が0であるか /// </summary> /// <param name="address">実効アドレス</param> void BIT(ushort address) { byte value = ReadMemory(address); nFlag = Nes.FetchBit(value, 7) != 0; vFlag = Nes.FetchBit(value, 6) != 0; zFlag = (registerA & value) == 0; }
/// <summary> /// Pのセッター各bitをフラグに格納 /// </summary> /// <param name="value">P</param> void SetRegisterP(byte value) { nFlag = Nes.FetchBit(value, 7) != 0; vFlag = Nes.FetchBit(value, 6) != 0; bFlag = Nes.FetchBit(value, 4) != 0; iFlag = Nes.FetchBit(value, 2) != 0; zFlag = Nes.FetchBit(value, 1) != 0; cFlag = Nes.FetchBit(value, 0) != 0; }
/// <summary> /// PPUレジスタの書き込み /// </summary> /// <param name="address">Address.</param> /// <param name="value">Value.</param> public void WritePpuRegister(ushort address, byte value) { switch (address) { /* * 0x2000 PPUCTRL W コントロールレジスタ1 割り込みなどPPUの設定 * bit 76543210 * VPHBSINN * * V : VBLANK 開始時に NMI 割り込みを発生 (0:off, 1:on) * P : P: PPU マスター/スレーブ * H : スプライトサイズ (0:8*8, 1:8*16) * B : BG パターンテーブル (0:$0000, 1:$1000) * S : スプライトパターンテーブル (0:$0000, 1:$1000) * I : PPU アドレスインクリメント (0:+1, 1:+32) - VRAM 上で +1 は横方向、+32 は縦方向 * N : ネームテーブル (0:$2000, 1:$2400, 2:$2800, 3:$2C00) */ case 0x2000: nmiInterrupt = Nes.FetchBit(value, 7) == 1; ppuAddressInc = (byte)(Nes.FetchBit(value, 2) * 31 + 1); renderer.SpriteSize = Nes.FetchBit(value, 5) * 8 + 8; renderer.BgPatternTable = 256 * Nes.FetchBit(value, 4); renderer.SpritePatternTable = 256 * Nes.FetchBit(value, 3); renderer.DisplayTable = Nes.FetchBit(value, 1) * 2 + Nes.FetchBit(value, 0); break; /* 0x2001 PPUMASK W コントロールレジスタ2 背景イネーブルなどPPUの設定 * bit 76543210 * BGRsbMmG * * B : 色強調(青) * G : 色強調(緑) * R : 色強調(赤) * s : スプライト描画(0:off, 1:on) * b : BG 描画 (0:off, 1:on) * M : 画面左端 8px でスプライトクリッピング (0:有効, 1:無効) * m : 画面左端 8px で BG クリッピング (0:有効, 1:無効) * G : 0:カラー, 1:モノクロ */ case 0x2001: renderer.IsSpriteVisible = Nes.FetchBit(value, 4) == 1; renderer.IsBGVisible = Nes.FetchBit(value, 3) == 1; break; //読み書きするOAMアドレスを指定 case 0x2003: oamAddr = value; break; //0x2003で指定したOAMアドレスにy, tile, attr, xの順に書き込む case 0x2004: oamDataWriteCount++; tempOamData[oamDataWriteCount - 1] = value; if (oamDataWriteCount == 4) { renderer.WriteOamTable(oamAddr, tempOamData[3], tempOamData[0], tempOamData[1], tempOamData[2]); oamDataWriteCount = 0; } break; //1回目の書き込みでx, 2回目の書き込みでyのスクロールオフセットを指定 case 0x2005: switch (ppuWriteCount) { case 0: //scrollOffsetX = value; renderer.ScrollOffsetX = value; ppuWriteCount++; break; case 1: //scrollOffsetY = value; renderer.ScrollOffsetY = value; ppuWriteCount = 0; break; } break; //1回目の書き込みで上位バイト, 2回目の書き込みで下位バイトを設定 case 0x2006: switch (ppuWriteCount) { case 0: ppuAddr = (ushort)(value * 0x100); ppuWriteCount++; break; case 1: ppuAddr += value; ppuWriteCount = 0; break; } break; //ppuAddrのアドレスに書き込み case 0x2007: ppuData = value; WriteMemory(ppuAddr, value); ppuAddr += ppuAddressInc; break; //OMAへDMA転送 case 0x4014: for (int i = 0, j = value * 0x100; i < 0x40; i++, j += 4) { renderer.WriteOamTable(i, nes.ReadCpuMemory((ushort)(j + 3)), nes.ReadCpuMemory((ushort)j), nes.ReadCpuMemory((ushort)(j + 1)), nes.ReadCpuMemory((ushort)(j + 2))); } PpuCycle = 514; break; } }
/// <summary> /// oamメモリへの書き込み /// </summary> /// <param name="offset">Offset.</param> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> /// <param name="tile">Tile.</param> /// <param name="attr">Attr.</param> public void WriteOamTable(int offset, int x, int y, int tile, int attr) { if (spritePosition[offset] != null) { foreach (int position in spritePosition[offset]) { spriteRenderPosition.Remove(position); } spritePosition[offset] = null; } bool spriteHit = false; if (offset == 0) { spriteHit = true; } int tileID = tile; int patternTableNumber = SpritePatternTable; if (SpriteSize > 8) { patternTableNumber = Nes.FetchBit(tileID, 0) * 256; tileID = 2 * (tileID >> 1); } bool verticalReverse = Nes.FetchBit(attr, 7) == 1; bool horizontalReverse = Nes.FetchBit(attr, 6) == 1; bool priority = Nes.FetchBit(attr, 5) == 0; int palette = Nes.FetchBit(attr, 1) * 2 + Nes.FetchBit(attr, 0); oamTable[offset] = new Oam { X = x, Y = y + 1, TileID = tileID, PatternTable = patternTableNumber, HorizontalReverse = horizontalReverse, VerticalReverse = verticalReverse, Priority = priority, Palette = palette, SpriteHit = spriteHit }; spritePosition[offset] = new List <int>(); for (int i = x + y * 256, k = 0; i < SpriteSize * 256 + y * 256 + x; i += 256, k++) { for (int j = 0; j < 8; j++) { if (!spriteRenderPosition.ContainsKey(i + j)) { spriteRenderPosition.Add(i + j, oamTable[offset]); } else { spriteRenderPosition[i + j] = oamTable[offset]; } spritePosition[offset].Add(i + j); } if (k == 7) { oamTable[offset] = new Oam { X = x, Y = y + 9, TileID = tileID + 1, PatternTable = patternTableNumber, HorizontalReverse = horizontalReverse, VerticalReverse = verticalReverse, Priority = priority, Palette = palette }; } } }
/// <summary> /// フラグN, Zを決める /// N: 結果の最上位ビット /// Z: 結果が0であるか /// </summary> /// <param name="value">結果</param> void FlagNandZ(int value) { zFlag = value == 0; nFlag = Nes.FetchBit(value, 7) != 0; }
/// <summary> /// メモリを1回右シフト /// N: 結果の最上位ビット /// Z: 結果が0であるか /// C: はみ出たビット /// </summary> void LSR(ref byte value) { cFlag = Nes.FetchBit(value, 0) != 0; value >>= 1; FlagNandZ(value); }