📄 ppu.cpp
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and * Jerremy Koot (jkoot@snes9x.com) * * Super FX C emulator code * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and * Gary Henderson. * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. * * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: www.snes9x.com * * Permission to use, copy, modify and distribute Snes9x in both binary and * source form, for non-commercial purposes, is hereby granted without fee, * providing that this license information and copyright notice appear with * all copies and any derived work. * * This software is provided 'as-is', without any express or implied * warranty. In no event shall the authors be held liable for any damages * arising from the use of this software. * * Snes9x is freeware for PERSONAL USE only. Commercial users should * seek permission of the copyright holders first. Commercial use includes * charging money for Snes9x or software derived from Snes9x. * * The copyright holders request that bug fixes and improvements to the code * should be forwarded to them so everyone can benefit from the modifications * in future versions. * * Super NES and Super Nintendo Entertainment System are trademarks of * Nintendo Co., Limited and its subsidiary companies. */#include "snes9x.h"#include "memmap.h"#include "ppu.h"#include "cpuexec.h"#include "missing.h"#include "apu.h"#include "dma.h"#include "gfx.h"#include "display.h"#include "sa1.h"#include "netplay.h"#include "sdd1.h"#include "srtc.h"#ifndef ZSNES_FX#include "fxemu.h"#include "fxinst.h"extern struct FxInit_s SuperFX;#elseEXTERN_C void S9xSuperFXWriteReg (uint8, uint32);EXTERN_C uint8 S9xSuperFXReadReg (uint32);#endifvoid S9xUpdateHTimer (){ if (PPU.HTimerEnabled) {#ifdef DEBUGGER missing.hirq_pos = PPU.IRQHBeamPos;#endif PPU.HTimerPosition = PPU.IRQHBeamPos * Settings.H_Max / SNES_HCOUNTER_MAX; if (PPU.HTimerPosition == Settings.H_Max || PPU.HTimerPosition == Settings.HBlankStart) { PPU.HTimerPosition--; } if (!PPU.VTimerEnabled || CPU.V_Counter == PPU.IRQVBeamPos) { if (PPU.HTimerPosition <= CPU.Cycles) { // Missed the IRQ on this line already if (CPU.WhichEvent == HBLANK_END_EVENT || CPU.WhichEvent == HTIMER_AFTER_EVENT) { CPU.WhichEvent = HBLANK_END_EVENT; CPU.NextEvent = Settings.H_Max; } else { CPU.WhichEvent = HBLANK_START_EVENT; CPU.NextEvent = Settings.HBlankStart; } } else { if (CPU.WhichEvent == HTIMER_BEFORE_EVENT || CPU.WhichEvent == HBLANK_START_EVENT) { if (PPU.HTimerPosition > Settings.HBlankStart) { // HTimer was to trigger before h-blank start, // now triggers after start of h-blank CPU.NextEvent = Settings.HBlankStart; CPU.WhichEvent = HBLANK_START_EVENT; } else { CPU.NextEvent = PPU.HTimerPosition; CPU.WhichEvent = HTIMER_BEFORE_EVENT; } } else { CPU.WhichEvent = HTIMER_AFTER_EVENT; CPU.NextEvent = PPU.HTimerPosition; } } } }}void S9xFixColourBrightness (){ IPPU.XB = mul_brightness [PPU.Brightness]; if (Settings.SixteenBit) { for (int i = 0; i < 256; i++) { IPPU.Red [i] = IPPU.XB [PPU.CGDATA [i] & 0x1f]; IPPU.Green [i] = IPPU.XB [(PPU.CGDATA [i] >> 5) & 0x1f]; IPPU.Blue [i] = IPPU.XB [(PPU.CGDATA [i] >> 10) & 0x1f]; IPPU.ScreenColors [i] = BUILD_PIXEL (IPPU.Red [i], IPPU.Green [i], IPPU.Blue [i]); } }}/**********************************************************************************************//* S9xSetPPU() *//* This function sets a PPU Register to a specific byte *//**********************************************************************************************/void S9xSetPPU (uint8 Byte, uint16 Address){ if (Address <= 0x2183) { switch (Address) { case 0x2100: // Brightness and screen blank bit if (Byte != Memory.FillRAM [0x2100]) { FLUSH_REDRAW (); if (PPU.Brightness != (Byte & 0xF)) { IPPU.ColorsChanged = TRUE; IPPU.DirectColourMapsNeedRebuild = TRUE; PPU.Brightness = Byte & 0xF; S9xFixColourBrightness (); if (PPU.Brightness > IPPU.MaxBrightness) IPPU.MaxBrightness = PPU.Brightness; } if ((Memory.FillRAM[0x2100] & 0x80) != (Byte & 0x80)) { IPPU.ColorsChanged = TRUE; PPU.ForcedBlanking = (Byte >> 7) & 1; } } break; case 0x2101: // Sprite (OBJ) tile address if (Byte != Memory.FillRAM [0x2101]) { FLUSH_REDRAW (); PPU.OBJNameBase = (Byte & 3) << 14; PPU.OBJNameSelect = ((Byte >> 3) & 3) << 13; PPU.OBJSizeSelect = (Byte >> 5) & 7; IPPU.OBJChanged = TRUE; } break; case 0x2102: // Sprite write address (low) PPU.OAMAddr = Byte; PPU.OAMFlip = 2; PPU.OAMReadFlip = 0; PPU.SavedOAMAddr = PPU.OAMAddr; if (PPU.OAMPriorityRotation) { PPU.FirstSprite = PPU.OAMAddr & 0x7f;#ifdef DEBUGGER missing.sprite_priority_rotation = 1;#endif } break; case 0x2103: // Sprite register write address (high), sprite priority rotation // bit. if ((PPU.OAMPriorityRotation = (Byte & 0x80) == 0 ? 0 : 1)) { PPU.FirstSprite = PPU.OAMAddr & 0x7f;#ifdef DEBUGGER missing.sprite_priority_rotation = 1;#endif } // Only update the sprite write address top bit if the low byte has // been written to first. if (PPU.OAMFlip & 2) { PPU.OAMAddr &= 0x00FF; PPU.OAMAddr |= (Byte & 1) << 8; } PPU.OAMFlip = 0; PPU.OAMReadFlip = 0; PPU.SavedOAMAddr = PPU.OAMAddr; break; case 0x2104: // Sprite register write REGISTER_2104(Byte); break; case 0x2105: // Screen mode (0 - 7), background tile sizes and background 3 // priority if (Byte != Memory.FillRAM [0x2105]) { FLUSH_REDRAW (); PPU.BG3Priority = (Byte >> 3) & 1; PPU.BG[0].BGSize = (Byte >> 4) & 1; PPU.BG[1].BGSize = (Byte >> 5) & 1; PPU.BG[2].BGSize = (Byte >> 6) & 1; PPU.BG[3].BGSize = (Byte >> 7) & 1; PPU.BGMode = Byte & 7;#ifdef DEBUGGER missing.modes[PPU.BGMode] = 1;#endif } break; case 0x2106: // Mosaic pixel size and enable if (Byte != Memory.FillRAM [0x2106]) { FLUSH_REDRAW ();#ifdef DEBUGGER if ((Byte & 0xf0) && (Byte & 0x0f)) missing.mosaic = 1;#endif PPU.Mosaic = (Byte >> 4) + 1; PPU.BGMosaic [0] = (Byte & 1) && PPU.Mosaic > 1; PPU.BGMosaic [1] = (Byte & 2) && PPU.Mosaic > 1; PPU.BGMosaic [2] = (Byte & 4) && PPU.Mosaic > 1; PPU.BGMosaic [3] = (Byte & 8) && PPU.Mosaic > 1; } break; case 0x2107: // [BG0SC] if (Byte != Memory.FillRAM [0x2107]) { FLUSH_REDRAW (); PPU.BG[0].SCSize = Byte & 3; PPU.BG[0].SCBase = (Byte & 0x7c) << 8; } break; case 0x2108: // [BG1SC] if (Byte != Memory.FillRAM [0x2108]) { FLUSH_REDRAW (); PPU.BG[1].SCSize = Byte & 3; PPU.BG[1].SCBase = (Byte & 0x7c) << 8; } break; case 0x2109: // [BG2SC] if (Byte != Memory.FillRAM [0x2109]) { FLUSH_REDRAW (); PPU.BG[2].SCSize = Byte & 3; PPU.BG[2].SCBase = (Byte & 0x7c) << 8; } break; case 0x210A: // [BG3SC] if (Byte != Memory.FillRAM [0x210a]) { FLUSH_REDRAW (); PPU.BG[3].SCSize = Byte & 3; PPU.BG[3].SCBase = (Byte & 0x7c) << 8; } break; case 0x210B: // [BG01NBA] if (Byte != Memory.FillRAM [0x210b]) { FLUSH_REDRAW (); PPU.BG[0].NameBase = (Byte & 7) << 12; PPU.BG[1].NameBase = ((Byte >> 4) & 7) << 12; } break; case 0x210C: // [BG23NBA] if (Byte != Memory.FillRAM [0x210c]) { FLUSH_REDRAW (); PPU.BG[2].NameBase = (Byte & 7) << 12; PPU.BG[3].NameBase = ((Byte >> 4) & 7) << 12; } break; case 0x210D: PPU.BG[0].HOffset = ((PPU.BG[0].HOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x210E: PPU.BG[0].VOffset = ((PPU.BG[0].VOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x210F: PPU.BG[1].HOffset = ((PPU.BG[1].HOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x2110: PPU.BG[1].VOffset = ((PPU.BG[1].VOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x2111: PPU.BG[2].HOffset = ((PPU.BG[2].HOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x2112: PPU.BG[2].VOffset = ((PPU.BG[2].VOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x2113: PPU.BG[3].HOffset = ((PPU.BG[3].HOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x2114: PPU.BG[3].VOffset = ((PPU.BG[3].VOffset >> 8) & 0xff) | ((uint16) Byte << 8); break; case 0x2115: // VRAM byte/word access flag and increment PPU.VMA.High = (Byte & 0x80) == 0 ? FALSE : TRUE; switch (Byte & 3) { case 0: PPU.VMA.Increment = 1; break; case 1: PPU.VMA.Increment = 32; break; case 2: PPU.VMA.Increment = 128; break; case 3: PPU.VMA.Increment = 128; break; }#ifdef DEBUGGER if ((Byte & 3) != 0) missing.vram_inc = Byte & 3;#endif if (Byte & 0x0c) { static uint16 IncCount [4] = { 0, 32, 64, 128 }; static uint16 Shift [4] = { 0, 5, 6, 7 };#ifdef DEBUGGER missing.vram_full_graphic_inc = (Byte & 0x0c) >> 2;#endif PPU.VMA.Increment = 1; uint8 i = (Byte & 0x0c) >> 2; PPU.VMA.FullGraphicCount = IncCount [i]; PPU.VMA.Mask1 = IncCount [i] * 8 - 1; PPU.VMA.Shift = Shift [i]; } else PPU.VMA.FullGraphicCount = 0; break; case 0x2116: // VRAM read/write address (low) PPU.VMA.Address &= 0xFF00; PPU.VMA.Address |= Byte; IPPU.FirstVRAMRead = TRUE; break; case 0x2117: // VRAM read/write address (high) PPU.VMA.Address &= 0x00FF; PPU.VMA.Address |= Byte << 8; IPPU.FirstVRAMRead = TRUE; break; case 0x2118: // VRAM write data (low) IPPU.FirstVRAMRead = TRUE; REGISTER_2118(Byte); break; case 0x2119: // VRAM write data (high) IPPU.FirstVRAMRead = TRUE; REGISTER_2119(Byte); break; case 0x211a: // Mode 7 outside rotation area display mode and flipping if (Byte != Memory.FillRAM [0x211a]) { FLUSH_REDRAW (); PPU.Mode7Repeat = Byte >> 6; PPU.Mode7VFlip = (Byte & 2) >> 1; PPU.Mode7HFlip = Byte & 1; } break; case 0x211b: // Mode 7 matrix A (low & high) PPU.MatrixA = ((PPU.MatrixA >> 8) & 0xff) | (Byte << 8); PPU.Need16x8Mulitply = TRUE; break; case 0x211c: // Mode 7 matrix B (low & high) PPU.MatrixB = ((PPU.MatrixB >> 8) & 0xff) | (Byte << 8); PPU.Need16x8Mulitply = TRUE; break; case 0x211d: // Mode 7 matrix C (low & high) PPU.MatrixC = ((PPU.MatrixC >> 8) & 0xff) | (Byte << 8); break; case 0x211e: // Mode 7 matrix D (low & high) PPU.MatrixD = ((PPU.MatrixD >> 8) & 0xff) | (Byte << 8); break; case 0x211f: // Mode 7 centre of rotation X (low & high) PPU.CentreX = ((PPU.CentreX >> 8) & 0xff) | (Byte << 8); break; case 0x2120: // Mode 7 centre of rotation Y (low & high) PPU.CentreY = ((PPU.CentreY >> 8) & 0xff) | (Byte << 8); break; case 0x2121: // CG-RAM address PPU.CGFLIP = 0; PPU.CGFLIPRead = 0; PPU.CGADD = Byte; break; case 0x2122: REGISTER_2122(Byte); break; case 0x2123: // Window 1 and 2 enable for backgrounds 1 and 2 if (Byte != Memory.FillRAM [0x2123]) { FLUSH_REDRAW (); PPU.ClipWindow1Enable [0] = !!(Byte & 0x02); PPU.ClipWindow1Enable [1] = !!(Byte & 0x20); PPU.ClipWindow2Enable [0] = !!(Byte & 0x08); PPU.ClipWindow2Enable [1] = !!(Byte & 0x80); PPU.ClipWindow1Inside [0] = !(Byte & 0x01); PPU.ClipWindow1Inside [1] = !(Byte & 0x10); PPU.ClipWindow2Inside [0] = !(Byte & 0x04); PPU.ClipWindow2Inside [1] = !(Byte & 0x40); PPU.RecomputeClipWindows = TRUE;#ifdef DEBUGGER if (Byte & 0x80) missing.window2[1] = 1; if (Byte & 0x20) missing.window1[1] = 1; if (Byte & 0x08) missing.window2[0] = 1; if (Byte & 0x02) missing.window1[0] = 1;#endif } break; case 0x2124: // Window 1 and 2 enable for backgrounds 3 and 4 if (Byte != Memory.FillRAM [0x2124]) { FLUSH_REDRAW (); PPU.ClipWindow1Enable [2] = !!(Byte & 0x02); PPU.ClipWindow1Enable [3] = !!(Byte & 0x20); PPU.ClipWindow2Enable [2] = !!(Byte & 0x08); PPU.ClipWindow2Enable [3] = !!(Byte & 0x80); PPU.ClipWindow1Inside [2] = !(Byte & 0x01); PPU.ClipWindow1Inside [3] = !(Byte & 0x10); PPU.ClipWindow2Inside [2] = !(Byte & 0x04); PPU.ClipWindow2Inside [3] = !(Byte & 0x40); PPU.RecomputeClipWindows = TRUE;#ifdef DEBUGGER if (Byte & 0x80) missing.window2[3] = 1; if (Byte & 0x20) missing.window1[3] = 1; if (Byte & 0x08) missing.window2[2] = 1; if (Byte & 0x02) missing.window1[2] = 1;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -