NES: rework controller infrastructure. zappers and such will be coming soon now
This commit is contained in:
parent
f1cd0b888f
commit
3ffde6b88a
|
@ -40,7 +40,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
//user configuration
|
//user configuration
|
||||||
int[,] palette = new int[64,3];
|
int[,] palette = new int[64,3];
|
||||||
int[] palette_compiled = new int[64*8];
|
int[] palette_compiled = new int[64*8];
|
||||||
IPortDevice[] ports;
|
|
||||||
|
// new input system
|
||||||
|
IControllerDeck ControllerDeck;
|
||||||
|
byte latched4016;
|
||||||
|
|
||||||
private DisplayType _display_type = DisplayType.NTSC;
|
private DisplayType _display_type = DisplayType.NTSC;
|
||||||
|
|
||||||
|
@ -166,9 +169,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
ppu = new PPU(this);
|
ppu = new PPU(this);
|
||||||
ram = new byte[0x800];
|
ram = new byte[0x800];
|
||||||
CIRAM = new byte[0x800];
|
CIRAM = new byte[0x800];
|
||||||
ports = new IPortDevice[2];
|
|
||||||
ports[0] = new JoypadPortDevice(this, 0);
|
// wire controllers
|
||||||
ports[1] = new JoypadPortDevice(this, 1);
|
// 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
|
// don't replace the magicSoundProvider on reset, as it's not needed
|
||||||
// if (magicSoundProvider != null) magicSoundProvider.Dispose();
|
// if (magicSoundProvider != null) magicSoundProvider.Dispose();
|
||||||
|
@ -384,8 +407,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
case 0x4014: Exec_OAMDma(val); break;
|
case 0x4014: Exec_OAMDma(val); break;
|
||||||
case 0x4015: apu.WriteReg(addr, val); break;
|
case 0x4015: apu.WriteReg(addr, val); break;
|
||||||
case 0x4016:
|
case 0x4016:
|
||||||
ports[0].Write(val & 1);
|
write_joyport(val);
|
||||||
ports[1].Write(val & 1);
|
|
||||||
break;
|
break;
|
||||||
case 0x4017: apu.WriteReg(addr, val); break;
|
case 0x4017: apu.WriteReg(addr, val); break;
|
||||||
default:
|
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)
|
byte read_joyport(int addr)
|
||||||
{
|
{
|
||||||
CoreComm.InputCallback.Call();
|
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)
|
byte peek_joyport(int addr)
|
||||||
{
|
{
|
||||||
return handle_read_joyport(addr, true);
|
// at the moment, the new system doesn't support peeks
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Exec_OAMDma(byte val)
|
void Exec_OAMDma(byte val)
|
||||||
|
|
|
@ -33,16 +33,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
SetPalette(Palettes.FCEUX_Standard);
|
SetPalette(Palettes.FCEUX_Standard);
|
||||||
videoProvider = new MyVideoProvider(this);
|
videoProvider = new MyVideoProvider(this);
|
||||||
Init(game, rom, fdsbios);
|
Init(game, rom, fdsbios);
|
||||||
ControllerDefinition = new ControllerDefinition(NESController);
|
|
||||||
if (board is FDS)
|
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;
|
CoreComm.UsesDriveLed = true;
|
||||||
b.SetDriveLightCallback((val) => CoreComm.DriveLED = val);
|
(board as FDS).SetDriveLightCallback((val) => CoreComm.DriveLED = val);
|
||||||
}
|
}
|
||||||
PutSettings(Settings ?? new NESSettings());
|
PutSettings(Settings ?? new NESSettings());
|
||||||
}
|
}
|
||||||
|
@ -123,7 +117,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
return (flags & EFlags.GameGenie) != 0;
|
return (flags & EFlags.GameGenie) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte ApplyGameGenie(byte curr)
|
public byte ApplyGameGenie(byte curr)
|
||||||
{
|
{
|
||||||
if (!HasGameGenie)
|
if (!HasGameGenie)
|
||||||
|
@ -165,7 +159,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
//public int pal_bottom = 239;
|
//public int pal_bottom = 239;
|
||||||
public int left = 0;
|
public int left = 0;
|
||||||
public int right = 255;
|
public int right = 255;
|
||||||
|
|
||||||
NES emu;
|
NES emu;
|
||||||
public MyVideoProvider(NES emu)
|
public MyVideoProvider(NES emu)
|
||||||
{
|
{
|
||||||
|
@ -229,7 +223,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MyVideoProvider videoProvider;
|
MyVideoProvider videoProvider;
|
||||||
|
@ -258,74 +252,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
set { controller = value; }
|
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 _frame;
|
||||||
int _lagcount;
|
int _lagcount;
|
||||||
bool lagged = true;
|
bool lagged = true;
|
||||||
|
@ -354,7 +280,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
if (board == null || board.SaveRam == null)
|
if (board == null || board.SaveRam == null)
|
||||||
return null;
|
return null;
|
||||||
return (byte[])board.SaveRam.Clone();
|
return (byte[])board.SaveRam.Clone();
|
||||||
}
|
}
|
||||||
public void StoreSaveRam(byte[] data)
|
public void StoreSaveRam(byte[] data)
|
||||||
{
|
{
|
||||||
|
@ -478,7 +404,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
class MyWriter : StringWriter
|
class MyWriter : StringWriter
|
||||||
{
|
{
|
||||||
public MyWriter(TextWriter _loadReport)
|
public MyWriter(TextWriter _loadReport)
|
||||||
{
|
{
|
||||||
loadReport = _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 this is still null, we have to try it some other way. nescartdb perhaps?
|
||||||
|
|
||||||
if (choice == null)
|
if (choice == null)
|
||||||
{
|
{
|
||||||
choice = IdentifyFromBootGodDB(hash_sha1_several);
|
choice = IdentifyFromBootGodDB(hash_sha1_several);
|
||||||
|
@ -826,7 +752,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
void SyncState(Serializer ser)
|
void SyncState(Serializer ser)
|
||||||
{
|
{
|
||||||
int version = 2;
|
int version = 3;
|
||||||
ser.BeginSection("NES");
|
ser.BeginSection("NES");
|
||||||
ser.Sync("version", ref version);
|
ser.Sync("version", ref version);
|
||||||
ser.Sync("Frame", ref _frame);
|
ser.Sync("Frame", ref _frame);
|
||||||
|
@ -851,6 +777,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
if (version >= 2)
|
if (version >= 2)
|
||||||
ser.Sync("DB", ref DB);
|
ser.Sync("DB", ref DB);
|
||||||
|
if (version >= 3)
|
||||||
|
{
|
||||||
|
ser.Sync("latched4016", ref latched4016);
|
||||||
|
ser.BeginSection("ControllerDeck");
|
||||||
|
ControllerDeck.SyncState(ser);
|
||||||
|
ser.EndSection();
|
||||||
|
}
|
||||||
|
|
||||||
ser.EndSection();
|
ser.EndSection();
|
||||||
}
|
}
|
||||||
|
@ -898,7 +831,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
public object GetSettings() { return Settings.Clone(); }
|
public object GetSettings() { return Settings.Clone(); }
|
||||||
public object GetSyncSettings() { return SyncSettings.Clone(); }
|
public object GetSyncSettings() { return SyncSettings.Clone(); }
|
||||||
public bool PutSettings(object o)
|
public bool PutSettings(object o)
|
||||||
{
|
{
|
||||||
Settings = (NESSettings)o;
|
Settings = (NESSettings)o;
|
||||||
if (Settings.ClipLeftAndRight)
|
if (Settings.ClipLeftAndRight)
|
||||||
{
|
{
|
||||||
|
@ -963,7 +896,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
Palette = (int[,])Palettes.FCEUX_Standard.Clone();
|
Palette = (int[,])Palettes.FCEUX_Standard.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Newtonsoft.Json.JsonConstructor]
|
[Newtonsoft.Json.JsonConstructor]
|
||||||
public NESSettings(int[,] Palette)
|
public NESSettings(int[,] Palette)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
public int OUT0old;
|
public int OUT0old;
|
||||||
public int OUT1old;
|
public int OUT1old;
|
||||||
public int OUT2old;
|
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
|
public interface IControllerDeck
|
||||||
|
@ -380,7 +390,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
byte ret = 0;
|
byte ret = 0;
|
||||||
if (c["0Fire"])
|
if (c["0Fire"])
|
||||||
ret |= 0x08;
|
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;
|
ret |= 0x10;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -943,13 +953,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
{
|
{
|
||||||
string r = Allocate(s, ref plr, ref plrnext);
|
string r = Allocate(s, ref plr, ref plrnext);
|
||||||
ret.BoolButtons.Add(r);
|
ret.BoolButtons.Add(r);
|
||||||
remaps[s] = r;
|
remaps[r] = s;
|
||||||
}
|
}
|
||||||
foreach (string s in def.FloatControls)
|
foreach (string s in def.FloatControls)
|
||||||
{
|
{
|
||||||
string r = Allocate(s, ref plr, ref plrnext);
|
string r = Allocate(s, ref plr, ref plrnext);
|
||||||
ret.FloatControls.Add(r);
|
ret.FloatControls.Add(r);
|
||||||
remaps[s] = r;
|
remaps[r] = s;
|
||||||
}
|
}
|
||||||
ret.FloatRanges.AddRange(def.FloatRanges);
|
ret.FloatRanges.AddRange(def.FloatRanges);
|
||||||
plr = plrnext;
|
plr = plrnext;
|
||||||
|
|
|
@ -42,6 +42,31 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
public DebugCallback NTViewCallback;
|
public DebugCallback NTViewCallback;
|
||||||
public DebugCallback PPUViewCallback;
|
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
|
//when the ppu issues a write it goes through here and into the game board
|
||||||
public void ppubus_write(int addr, byte value)
|
public void ppubus_write(int addr, byte value)
|
||||||
|
|
Loading…
Reference in New Issue