From 3ffde6b88aebf0914013f3fe5abc5b6f9cb14094 Mon Sep 17 00:00:00 2001 From: goyuken Date: Fri, 28 Feb 2014 04:05:36 +0000 Subject: [PATCH] NES: rework controller infrastructure. zappers and such will be coming soon now --- .../Consoles/Nintendo/NES/Core.cs | 63 +++++++---- .../Consoles/Nintendo/NES/NES.cs | 101 +++--------------- .../Consoles/Nintendo/NES/NESControllers.cs | 16 ++- .../Consoles/Nintendo/NES/PPU.cs | 25 +++++ 4 files changed, 97 insertions(+), 108 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Core.cs index 6e3386a80d..675a142a35 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Core.cs @@ -40,7 +40,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //user configuration int[,] palette = new int[64,3]; int[] palette_compiled = new int[64*8]; - IPortDevice[] ports; + + // new input system + IControllerDeck ControllerDeck; + byte latched4016; private DisplayType _display_type = DisplayType.NTSC; @@ -166,9 +169,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppu = new PPU(this); ram = new byte[0x800]; CIRAM = new byte[0x800]; - ports = new IPortDevice[2]; - ports[0] = new JoypadPortDevice(this, 0); - ports[1] = new JoypadPortDevice(this, 1); + + // wire controllers + // todo: allow changing this + ControllerDeck = new NesDeck( + new ControllerNES(), + new ControllerNES(), + ppu.LightGunCallback); + // set controller definition first time only + if (ControllerDefinition == null) + { + ControllerDefinition = new ControllerDefinition(ControllerDeck.GetDefinition()); + ControllerDefinition.Name = "NES Controller"; + // controls other than the deck + ControllerDefinition.BoolButtons.Add("Power"); + ControllerDefinition.BoolButtons.Add("Reset"); + if (board is FDS) + { + var b = board as FDS; + ControllerDefinition.BoolButtons.Add("FDS Eject"); + for (int i = 0; i < b.NumSides; i++) + ControllerDefinition.BoolButtons.Add("FDS Insert " + i); + } + } // don't replace the magicSoundProvider on reset, as it's not needed // if (magicSoundProvider != null) magicSoundProvider.Dispose(); @@ -384,8 +407,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES case 0x4014: Exec_OAMDma(val); break; case 0x4015: apu.WriteReg(addr, val); break; case 0x4016: - ports[0].Write(val & 1); - ports[1].Write(val & 1); + write_joyport(val); break; case 0x4017: apu.WriteReg(addr, val); break; default: @@ -394,28 +416,27 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } + void write_joyport(byte value) + { + var si = new StrobeInfo(latched4016, value); + ControllerDeck.Strobe(si, Controller); + latched4016 = value; + } + byte read_joyport(int addr) { CoreComm.InputCallback.Call(); - return handle_read_joyport(addr, false); + lagged = false; + byte ret = addr == 0x4016 ? ControllerDeck.ReadA(Controller) : ControllerDeck.ReadB(Controller); + ret &= 0x1f; + ret |= (byte)(0xe0 & DB); + return ret; } byte peek_joyport(int addr) { - return handle_read_joyport(addr, true); - } - - byte handle_read_joyport(int addr, bool peek) - { - //read joystick port - //many todos here - lagged = false; - byte ret; - if (addr == 0x4016) - ret = ports[0].Read(peek); - else - ret = ports[1].Read(peek); - return ret; + // at the moment, the new system doesn't support peeks + return 0; } void Exec_OAMDma(byte val) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs index 6950e57a3c..af703e7fe8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs @@ -33,16 +33,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES SetPalette(Palettes.FCEUX_Standard); videoProvider = new MyVideoProvider(this); Init(game, rom, fdsbios); - ControllerDefinition = new ControllerDefinition(NESController); if (board is FDS) { - var b = board as FDS; - ControllerDefinition.BoolButtons.Add("FDS Eject"); - for (int i = 0; i < b.NumSides; i++) - ControllerDefinition.BoolButtons.Add("FDS Insert " + i); - CoreComm.UsesDriveLed = true; - b.SetDriveLightCallback((val) => CoreComm.DriveLED = val); + (board as FDS).SetDriveLightCallback((val) => CoreComm.DriveLED = val); } PutSettings(Settings ?? new NESSettings()); } @@ -123,7 +117,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES return (flags & EFlags.GameGenie) != 0; } } - + public byte ApplyGameGenie(byte curr) { if (!HasGameGenie) @@ -165,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //public int pal_bottom = 239; public int left = 0; public int right = 255; - + NES emu; public MyVideoProvider(NES emu) { @@ -229,7 +223,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } } - + } MyVideoProvider videoProvider; @@ -258,74 +252,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES set { controller = value; } } - interface IPortDevice - { - void Write(int value); - byte Read(bool peek); - void Update(); - } - - //static INPUTC GPC = { ReadGP, 0, StrobeGP, UpdateGP, 0, 0, LogGP, LoadGP }; - class JoypadPortDevice : NullPortDevice - { - int state; - NES nes; - int player; - public JoypadPortDevice(NES nes, int player) - { - this.nes = nes; - this.player = player; - } - void Strobe() - { - value = 0; - foreach ( - string str in new string[] { - "P" + (player + 1).ToString() + " Right", "P" + (player + 1).ToString() + " Left", - "P" + (player + 1).ToString() + " Down", "P" + (player + 1).ToString() + " Up", - "P" + (player + 1).ToString() + " Start", "P" + (player + 1).ToString() + " Select", - "P" + (player + 1).ToString() + " B", "P" + (player + 1).ToString() + " A" - } - ) - { - value <<= 1; - value |= nes.Controller.IsPressed(str) ? 1 : 0; - } - } - public override void Write(int value) - { - if (state == 1 && value == 0) - Strobe(); - state = value; - } - public override byte Read(bool peek) - { - int ret = value & 1; - if(!peek) value >>= 1; - // more information is needed - return (byte)(ret | (nes.DB & 0xe0)); - } - public override void Update() - { - - } - int value; - } - - class NullPortDevice : IPortDevice - { - public virtual void Write(int value) - { - } - public virtual byte Read(bool peek) - { - return 0xFF; - } - public virtual void Update() - { - } - } - int _frame; int _lagcount; bool lagged = true; @@ -354,7 +280,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (board == null || board.SaveRam == null) return null; - return (byte[])board.SaveRam.Clone(); + return (byte[])board.SaveRam.Clone(); } public void StoreSaveRam(byte[] data) { @@ -478,7 +404,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES class MyWriter : StringWriter { - public MyWriter(TextWriter _loadReport) + public MyWriter(TextWriter _loadReport) { loadReport = _loadReport; } @@ -621,7 +547,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //if this is still null, we have to try it some other way. nescartdb perhaps? - + if (choice == null) { choice = IdentifyFromBootGodDB(hash_sha1_several); @@ -826,7 +752,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES void SyncState(Serializer ser) { - int version = 2; + int version = 3; ser.BeginSection("NES"); ser.Sync("version", ref version); ser.Sync("Frame", ref _frame); @@ -851,6 +777,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (version >= 2) ser.Sync("DB", ref DB); + if (version >= 3) + { + ser.Sync("latched4016", ref latched4016); + ser.BeginSection("ControllerDeck"); + ControllerDeck.SyncState(ser); + ser.EndSection(); + } ser.EndSection(); } @@ -898,7 +831,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public object GetSettings() { return Settings.Clone(); } public object GetSyncSettings() { return SyncSettings.Clone(); } public bool PutSettings(object o) - { + { Settings = (NESSettings)o; if (Settings.ClipLeftAndRight) { @@ -963,7 +896,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { Palette = (int[,])Palettes.FCEUX_Standard.Clone(); } - + [Newtonsoft.Json.JsonConstructor] public NESSettings(int[,] Palette) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NESControllers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NESControllers.cs index 2deaf760fc..3329d95c01 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NESControllers.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NESControllers.cs @@ -19,6 +19,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int OUT0old; public int OUT1old; public int OUT2old; + + public StrobeInfo(byte oldvalue, byte newvalue) + { + OUT0old = oldvalue & 1; + OUT1old = oldvalue >> 1 & 1; + OUT2old = oldvalue >> 2 & 1; + OUT0 = newvalue & 1; + OUT1 = newvalue >> 1 & 1; + OUT2 = newvalue >> 2 & 1; + } } public interface IControllerDeck @@ -380,7 +390,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES byte ret = 0; if (c["0Fire"]) ret |= 0x08; - if (PPUCallback((int)c.GetFloat("0Zapper X"), (int)c.GetFloat("0Zapper Y"))) + if (!PPUCallback((int)c.GetFloat("0Zapper X"), (int)c.GetFloat("0Zapper Y"))) ret |= 0x10; return ret; } @@ -943,13 +953,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { string r = Allocate(s, ref plr, ref plrnext); ret.BoolButtons.Add(r); - remaps[s] = r; + remaps[r] = s; } foreach (string s in def.FloatControls) { string r = Allocate(s, ref plr, ref plrnext); ret.FloatControls.Add(r); - remaps[s] = r; + remaps[r] = s; } ret.FloatRanges.AddRange(def.FloatRanges); plr = plrnext; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index aa9bd01d9d..69bcbd8eb1 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -42,6 +42,31 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public DebugCallback NTViewCallback; public DebugCallback PPUViewCallback; + // true = light sensed + public bool LightGunCallback(int x, int y) + { + // untested so far + + int sum = 0; + int ymin = Math.Max(Math.Max(y - 20, ppur.status.sl - 30), 0); + int ymax = Math.Min(Math.Min(y + 20, ppur.status.sl + 5),239); + int xmin = Math.Max(0, x - 20); + int xmax = Math.Min(255, x + 20); + + for (int j = ymin; j <= ymax; j++) + { + for (int i = xmin; i <= xmax; i++) + { + short s = xbuf[y * 256 + x]; + int lum = s & 0x30; + if ((s & 0x0f) >= 0x0e) + lum = 0; + sum += lum; + } + } + return sum >= 40000; + } + //when the ppu issues a write it goes through here and into the game board public void ppubus_write(int addr, byte value)