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
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue