NES: rework controller infrastructure. zappers and such will be coming soon now

This commit is contained in:
goyuken 2014-02-28 04:05:36 +00:00
parent f1cd0b888f
commit 3ffde6b88a
4 changed files with 97 additions and 108 deletions

View File

@ -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)

View File

@ -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)
{

View File

@ -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;

View File

@ -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)