From 453baebdccf0d4b748679272adff74611e12685e Mon Sep 17 00:00:00 2001 From: zeromus Date: Sun, 10 May 2020 20:59:40 -0400 Subject: [PATCH 1/3] neshawk - fix poking wram (fixes ancillary unrelated issue in #1994) --- .../Consoles/Nintendo/NES/NES.Core.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 996d8563f3..68f7b6d823 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -841,6 +841,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { WriteReg(addr, value); } + else if (addr < 0x6000) + { + //let's ignore pokes to EXP until someone asks for it. there's really almost no way that could ever be done without the board having a PokeEXP method + } + else if (addr < 0x8000) + { + Board.WriteWram(addr - 0x6000, value); + } else { // apply a cheat to non-writable memory From f089fe5fcda7cf937a3c14f01761cc726e14baf1 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Mon, 11 May 2020 16:30:09 -0400 Subject: [PATCH 2/3] O2Hawk: Fix Catch the Ball collision detection (timer and counter can't be enabled at the same time.) --- .../CPUs/Intel8048/I8048.cs | 5 +- .../Consoles/Magnavox/Odyssey2/O2Hawk.cs | 24 ++- .../Consoles/Magnavox/Odyssey2/PPU.cs | 198 ++++++++++++++++-- 3 files changed, 198 insertions(+), 29 deletions(-) diff --git a/src/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs b/src/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs index 60d520b362..87965d981c 100644 --- a/src/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs +++ b/src/BizHawk.Emulation.Cores/CPUs/Intel8048/I8048.cs @@ -359,6 +359,7 @@ namespace BizHawk.Emulation.Cores.Components.I8048 case ST_CNT: counter_en = true; next_T1_check = TotalExecutedCycles + 20; + timer_en = false; break; case STP_CNT: counter_en = timer_en = false; @@ -366,6 +367,7 @@ namespace BizHawk.Emulation.Cores.Components.I8048 case ST_T: timer_en = true; timer_prescale = 0; + counter_en = false; break; case SET_ADDR_8: reg_d_ad = cur_instr[instr_pntr++]; @@ -487,6 +489,7 @@ namespace BizHawk.Emulation.Cores.Components.I8048 if (TimIntEn) { TIRQPending = true; + //Console.WriteLine("Timer: " + TotalExecutedCycles); } } Regs[TIM] = (ushort)((Regs[TIM] + 1) & 0xFF); @@ -504,7 +507,7 @@ namespace BizHawk.Emulation.Cores.Components.I8048 if (TimIntEn) { TIRQPending = true; - //Console.WriteLine(TotalExecutedCycles); + //Console.WriteLine("Counter: " + TotalExecutedCycles); } } Regs[TIM] = (ushort)((Regs[TIM] + 1) & 0xFF); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs index ce04d2e7c1..520afdb58b 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.cs @@ -61,8 +61,6 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk _syncSettings = (O2SyncSettings)syncSettings ?? new O2SyncSettings(); _controllerDeck = new O2HawkControllerDeck("O2 Controller", "O2 Controller"); - ppu = new PPU(); - _bios = comm.CoreFileProvider.GetFirmware("O2", "BIOS", true, "BIOS Not Found, Cannot Load") ?? throw new MissingFirmwareException("Missing Odyssey2 Bios"); @@ -75,11 +73,9 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk _frameHz = 60; - ppu.Core = this; cpu.Core = this; ser.Register(this); - ser.Register(ppu); ServiceProvider = ser; _settings = (O2Settings)settings ?? new O2Settings(); @@ -91,24 +87,30 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk SetupMemoryDomains(); cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory); - HardReset(); - // set up differences between PAL and NTSC systems - is_pal = true; - pic_height = 288; - _frameHz = 50; - if (game.Region == "US" || game.Region == "EU-US" || game.Region == null) { is_pal = false; pic_height = 240; _frameHz = 60; - } + ppu = new NTSC_PPU(); + } + else + { + is_pal = true; + pic_height = 288; + _frameHz = 50; + ppu = new PAL_PPU(); + } + ppu.Core = this; ppu.set_region(is_pal); + ser.Register(ppu); _vidbuffer = new int[372 * pic_height]; frame_buffer = new int[320 * pic_height]; + + HardReset(); } public DisplayType Region => DisplayType.NTSC; diff --git a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs index ea7dce4654..3014eaaa81 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/PPU.cs @@ -58,7 +58,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk int right_shift_even; int x_base; - public byte ReadReg(int addr) + public virtual byte ReadReg(int addr) { byte ret = 0; @@ -96,19 +96,20 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk if (VDC_collision.Bit(i)) { ret |= VDC_col_ret[i]; - } + //VDC_col_ret[i] = 0; + } } - // register is reset when read + // register is reset when read, but not external for (int i = 0; i < 8; i++) { VDC_col_ret[i] = 0; } - //Console.WriteLine("col: " + ret + " " + LY + " " + Core.cpu.TotalExecutedCycles); + //Console.WriteLine("col: " + VDC_collision + " " + ret + " " + LY + " " + Core.cpu.TotalExecutedCycles); } else if (addr == 0xA3) { ret = VDC_color; } - else if(addr == 0xA4) + else if (addr == 0xA4) { if (latch_x_y) { ret = A4_latch; } else { ret = (byte)((LY_ret >= 0) ? LY_ret : 0); } @@ -140,7 +141,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk } //Peek method for memory domains that doesn't effect IRQ - public byte PeekReg(int addr) + public virtual byte PeekReg(int addr) { byte ret = 0; @@ -150,7 +151,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk else if (addr < 0xA0) { ret = Sprite_Shapes[addr - 0x80]; } else if (addr == 0xA0) { ret = VDC_ctrl; } else if (addr == 0xA1) { ret = VDC_status; } - else if (addr == 0xA2) + else if (addr == 0xA2) { for (int i = 0; i < 8; i++) { @@ -185,7 +186,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk if (addr < 0x10) { if (!VDC_ctrl.Bit(5)) { Sprites[addr] = value; } - //Console.WriteLine("spr: " + addr + " " + value + " " + Core.cpu.TotalExecutedCycles); + //Console.WriteLine("spr: " + addr + " " + value + " " + Core.cpu.TotalExecutedCycles); } else if (addr < 0x40) { @@ -198,8 +199,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk { // chars position is not effected by last bit if ((addr % 4) == 0) { value &= 0xFE; } - if (!VDC_ctrl.Bit(5)) - { + if (!VDC_ctrl.Bit(5)) + { Quad_Chars[addr - 0x40] = value; // X and Y are mapped all together @@ -211,7 +212,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk } } } - + //Console.WriteLine("quad: " + (addr - 0x40) + " " + value + " " + Core.cpu.TotalExecutedCycles); } else if (addr < 0xA0) @@ -246,7 +247,8 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk else if (addr == 0xA2) { VDC_collision = value; - //Console.WriteLine("VDC_collide: " + value + " " + Core.cpu.TotalExecutedCycles); + + Console.WriteLine("VDC_collide: " + value + " " + Core.cpu.TotalExecutedCycles); } else if (addr == 0xA3) { @@ -282,7 +284,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk //Console.WriteLine(addr + " " + value + " " + LY + " " + Core.cpu.TotalExecutedCycles); } - public void tick() + public virtual void tick() { Pixel_Stat = 0; // drawing cycles @@ -356,11 +358,11 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk { HBL = false; Core.cpu.T1 = false; - } + } } } - public void Reset() + public virtual void Reset() { Sprites = new byte[16]; Sprite_Shapes = new byte[32]; @@ -378,7 +380,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk AudioReset(); } - public void set_region(bool pal_flag) + public virtual void set_region(bool pal_flag) { is_pal = pal_flag; @@ -394,7 +396,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk } } - public void process_pixel() + public virtual void process_pixel() { current_pixel_offset = cycle * 2; @@ -1219,4 +1221,166 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk #endregion } + + public class NTSC_PPU : PPU + { + public override void tick() + { + Pixel_Stat = 0; + // drawing cycles + // note: clipping might need to be handled differently between PAL and NTSC + if (cycle < 182) + { + if ((LY < LINE_VBL) && (LY >= 0)) + { + // draw a pixel + process_pixel(); + } + } + else + { + // NOTE: most games expect one less T1 pulse after VBL, maybe some pre-render line + if (cycle == 182 && (LY < LINE_VBL) && (LY > 0)) + { + HBL = true; + // Send T1 pulses + Core.cpu.T1 = true; + } + + if (cycle == 212 && (LY < LINE_VBL)) + { + VDC_status &= 0xFE; + if (VDC_ctrl.Bit(0)) { Core.cpu.IRQPending = false; } + LY_ret = LY_ret + 1; + } + } + + if (cycle == 113 && (LY < LINE_VBL)) + { + VDC_status |= 0x01; + if (VDC_ctrl.Bit(0) && HBL_req) { Core.cpu.IRQPending = true; HBL_req = false; } + } + + cycle++; + + // end of scanline + if (cycle == 228) + { + cycle = 0; + + LY++; + + if (LY == LINE_VBL) + { + VBL = true; + Core.in_vblank = true; + VDC_status |= 0x08; + Core.cpu.IRQPending = true; + Core.cpu.T1 = true; + } + + if (LY >= LINE_VBL) + { + LY_ret = 0; + } + + if (LY == LINE_MAX) + { + LY = 0; + VBL = false; + Core.in_vblank = false; + Core.cpu.T1 = false; + if (Core.is_pal) { Core.cpu.IRQPending = false; } + LY_ret = 0; + } + + if (LY < LINE_VBL) + { + HBL = false; + Core.cpu.T1 = false; + } + } + } + } + + public class PAL_PPU : PPU + { + public override void tick() + { + Pixel_Stat = 0; + // drawing cycles + // note: clipping might need to be handled differently between PAL and NTSC + if (cycle < 182) + { + if ((LY < LINE_VBL) && (LY >= 0)) + { + // draw a pixel + process_pixel(); + } + } + else + { + // NOTE: most games expect one less T1 pulse after VBL, maybe some pre-render line + if (cycle == 182 && (LY < LINE_VBL) && (LY > 0)) + { + HBL = true; + // Send T1 pulses + Core.cpu.T1 = true; + } + + if (cycle == 212 && (LY < LINE_VBL)) + { + VDC_status &= 0xFE; + if (VDC_ctrl.Bit(0)) { Core.cpu.IRQPending = false; } + LY_ret = LY_ret + 1; + } + } + + if (cycle == 113 && (LY < LINE_VBL)) + { + VDC_status |= 0x01; + if (VDC_ctrl.Bit(0) && HBL_req) { Core.cpu.IRQPending = true; HBL_req = false; } + } + + cycle++; + + // end of scanline + if (cycle == 228) + { + cycle = 0; + + LY++; + + if (LY == LINE_VBL) + { + VBL = true; + Core.in_vblank = true; + VDC_status |= 0x08; + Core.cpu.IRQPending = true; + Core.cpu.T1 = true; + } + + if (LY >= LINE_VBL) + { + LY_ret = 0; + } + + if (LY == LINE_MAX) + { + LY = 0; + VBL = false; + Core.in_vblank = false; + Core.cpu.T1 = false; + if (Core.is_pal) { Core.cpu.IRQPending = false; } + LY_ret = 0; + } + + if (LY < LINE_VBL) + { + HBL = false; + Core.cpu.T1 = false; + } + } + } + } } From 8d1a1e4c9233c5a18147b241f455fc008aa803e6 Mon Sep 17 00:00:00 2001 From: zeromus Date: Tue, 12 May 2020 22:39:41 -0400 Subject: [PATCH 3/3] Properly skip presentation and user prescale steps when taking "raw" screenshot. About a 10% chance of other regressions. fixes #1997. --- .../DisplayManager/DisplayManager.cs | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs index 2bf7c60be2..6629d5d3ab 100644 --- a/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs +++ b/src/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs @@ -305,11 +305,12 @@ namespace BizHawk.Client.EmuHawk //add lua layer 'emu' AppendLuaLayer(chain, "emu"); - if (Global.Config.DispPrescale != 1) - { - var fPrescale = new Filters.PrescaleFilter() { Scale = Global.Config.DispPrescale }; - chain.AddFilter(fPrescale, "user_prescale"); - } + if(includeUserFilters) + if (Global.Config.DispPrescale != 1) + { + var fPrescale = new Filters.PrescaleFilter() { Scale = Global.Config.DispPrescale }; + chain.AddFilter(fPrescale, "user_prescale"); + } // add user-selected retro shader if (selectedChain != null) @@ -352,7 +353,8 @@ namespace BizHawk.Client.EmuHawk } // add final presentation - chain.AddFilter(fPresent, "presentation"); + if (includeUserFilters) + chain.AddFilter(fPresent, "presentation"); //add lua layer 'native' AppendLuaLayer(chain, "native"); @@ -699,7 +701,8 @@ namespace BizHawk.Client.EmuHawk VideoProvider = fvp, Simulate = true, ChainOutsize = chainOutsize, - IncludeUserFilters = true + IncludeUserFilters = true, + IncludeOSD = true, }; var filterProgram = UpdateSourceInternal(job); @@ -723,6 +726,12 @@ namespace BizHawk.Client.EmuHawk public bool Offscreen; public BitmapBuffer OffscreenBb; public bool IncludeOSD; + + /// + /// This has been changed a bit to mean "not raw". + /// Someone needs to rename it, but the sense needs to be inverted and some method args need renaming too + /// Suggested: IsRaw (with inverted sense) + /// public bool IncludeUserFilters; } @@ -837,17 +846,20 @@ namespace BizHawk.Client.EmuHawk //setup the final presentation filter Filters.FinalPresentation fPresent = filterProgram["presentation"] as Filters.FinalPresentation; - fPresent.VirtualTextureSize = new Size(vw, vh); - fPresent.TextureSize = new Size(presenterTextureWidth, presenterTextureHeight); - fPresent.BackgroundColor = videoProvider.BackgroundColor; - fPresent.GuiRenderer = Renderer; - fPresent.Flip = isGlTextureId; - fPresent.Config_FixAspectRatio = Global.Config.DispFixAspectRatio; - fPresent.Config_FixScaleInteger = Global.Config.DispFixScaleInteger; - fPresent.Padding = ClientExtraPadding; - fPresent.AutoPrescale = Global.Config.DispAutoPrescale; + if (fPresent != null) + { + fPresent.VirtualTextureSize = new Size(vw, vh); + fPresent.TextureSize = new Size(presenterTextureWidth, presenterTextureHeight); + fPresent.BackgroundColor = videoProvider.BackgroundColor; + fPresent.GuiRenderer = Renderer; + fPresent.Flip = isGlTextureId; + fPresent.Config_FixAspectRatio = Global.Config.DispFixAspectRatio; + fPresent.Config_FixScaleInteger = Global.Config.DispFixScaleInteger; + fPresent.Padding = ClientExtraPadding; + fPresent.AutoPrescale = Global.Config.DispAutoPrescale; - fPresent.GL = GL; + fPresent.GL = GL; + } //POOPY. why are we delivering the GL context this way? such bad Filters.ScreenControlNDS fNDS = filterProgram["CoreScreenControl"] as Filters.ScreenControlNDS;