Add SMS Pause button for GPGX; do various cleanups/misc fixes
resolves #3942
This commit is contained in:
parent
fb76975bd2
commit
dc391721c8
|
@ -10,8 +10,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
public void SetCDL(ICodeDataLog cdl)
|
||||
{
|
||||
CDL = cdl;
|
||||
if (cdl == null) Core.gpgx_set_cd_callback(null);
|
||||
else Core.gpgx_set_cd_callback(CDCallback);
|
||||
Core.gpgx_set_cd_callback(cdl == null ? null : CDCallback);
|
||||
}
|
||||
|
||||
public void NewCDL(ICodeDataLog cdl)
|
||||
|
@ -21,7 +20,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
cdl["Z80 RAM"] = new byte[_memoryDomains["Z80 RAM"]!.Size];
|
||||
|
||||
var found = _memoryDomains["SRAM"];
|
||||
if (found is not null) cdl["SRAM"] = new byte[found.Size];
|
||||
if (found is not null)
|
||||
{
|
||||
cdl["SRAM"] = new byte[found.Size];
|
||||
}
|
||||
|
||||
cdl.SubType = "GEN";
|
||||
cdl.SubVer = 0;
|
||||
|
@ -29,24 +31,29 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
// TODO: we have Disassembling now
|
||||
// not supported
|
||||
public void DisassembleCDL(Stream s, ICodeDataLog cdl) { }
|
||||
public void DisassembleCDL(Stream s, ICodeDataLog cdl)
|
||||
{
|
||||
}
|
||||
|
||||
private ICodeDataLog CDL;
|
||||
private void CDCallbackProc(int addr, LibGPGX.CDLog_AddrType addrtype, LibGPGX.CDLog_Flags flags)
|
||||
{
|
||||
//TODO - hard reset makes CDL go nuts.
|
||||
// TODO - hard reset makes CDL go nuts.
|
||||
|
||||
if (CDL == null) return;
|
||||
if (!CDL.Active) return;
|
||||
string key;
|
||||
switch (addrtype)
|
||||
if (CDL is not { Active: true })
|
||||
{
|
||||
case LibGPGX.CDLog_AddrType.MDCART: key = "MD CART"; break;
|
||||
case LibGPGX.CDLog_AddrType.RAM68k: key = "68K RAM"; break;
|
||||
case LibGPGX.CDLog_AddrType.RAMZ80: key = "Z80 RAM"; break;
|
||||
case LibGPGX.CDLog_AddrType.SRAM: key = "SRAM"; break;
|
||||
default: throw new InvalidOperationException("Lagrangian earwax incident");
|
||||
return;
|
||||
}
|
||||
|
||||
var key = addrtype switch
|
||||
{
|
||||
LibGPGX.CDLog_AddrType.MDCART => "MD CART",
|
||||
LibGPGX.CDLog_AddrType.RAM68k => "68K RAM",
|
||||
LibGPGX.CDLog_AddrType.RAMZ80 => "Z80 RAM",
|
||||
LibGPGX.CDLog_AddrType.SRAM => "SRAM",
|
||||
_ => throw new InvalidOperationException("Lagrangian earwax incident")
|
||||
};
|
||||
|
||||
CDL[key][addr] |= (byte)flags;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.StringExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
@ -14,7 +15,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
var regs = new LibGPGX.RegisterInfo[Core.gpgx_getmaxnumregs()];
|
||||
var n = Core.gpgx_getregs(regs);
|
||||
if (n > regs.Length)
|
||||
{
|
||||
throw new InvalidOperationException("A buffer overrun has occured!");
|
||||
}
|
||||
|
||||
var ret = new Dictionary<string, RegisterValue>();
|
||||
using (_elf.EnterExit())
|
||||
{
|
||||
|
@ -24,7 +28,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
var name = Marshal.PtrToStringAnsi(regs[i].Name);
|
||||
byte size = 32;
|
||||
if (name!.Contains("68K SR") || name.StartsWithOrdinal("Z80"))
|
||||
{
|
||||
size = 16;
|
||||
}
|
||||
|
||||
ret[name] = new RegisterValue((ulong)regs[i].Value, size);
|
||||
}
|
||||
|
@ -35,9 +41,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
[FeatureNotImplemented]
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
=> throw new NotImplementedException();
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks
|
||||
{
|
||||
|
@ -60,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
[FeatureNotImplemented]
|
||||
public long TotalExecutedCycles => throw new NotImplementedException();
|
||||
|
||||
private readonly MemoryCallbackSystem _memoryCallbacks = new(new[] { "M68K BUS" });
|
||||
private readonly MemoryCallbackSystem _memoryCallbacks = new([ "M68K BUS" ]);
|
||||
|
||||
private LibGPGX.mem_cb ExecCallback;
|
||||
private LibGPGX.mem_cb ReadCallback;
|
||||
|
@ -105,8 +109,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
|
||||
private void KillMemCallbacks()
|
||||
{
|
||||
Core.gpgx_set_mem_callback(null, null, null);
|
||||
}
|
||||
=> Core.gpgx_set_mem_callback(null, null, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.M68000;
|
||||
|
||||
|
@ -23,17 +24,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
public string Disassemble(MemoryDomain m, uint addr, out int length)
|
||||
{
|
||||
_disassemblerInstance.ReadWord = (a) => (short)m.PeekUshort(a, m.EndianType == MemoryDomain.Endian.Big);
|
||||
_disassemblerInstance.ReadByte = (a) => (sbyte)m.PeekByte(a);
|
||||
_disassemblerInstance.ReadLong = (a) => (int)m.PeekUint(a, m.EndianType == MemoryDomain.Endian.Big);
|
||||
_disassemblerInstance.ReadWord = a => (short)m.PeekUshort(a, m.EndianType == MemoryDomain.Endian.Big);
|
||||
_disassemblerInstance.ReadByte = a => (sbyte)m.PeekByte(a);
|
||||
_disassemblerInstance.ReadLong = a => (int)m.PeekUint(a, m.EndianType == MemoryDomain.Endian.Big);
|
||||
var info = _disassemblerInstance.Disassemble((int)addr);
|
||||
|
||||
length = info.Length;
|
||||
|
||||
return $"{info.RawBytes.Substring(0, 4):X4} {info.Mnemonic,-7} {info.Args}";
|
||||
return $"{info.RawBytes[..4]} {info.Mnemonic,-7} {info.Args}";
|
||||
}
|
||||
|
||||
// TODO: refactor MC6800's disassembler to be a static call
|
||||
private readonly MC68000 _disassemblerInstance = new MC68000();
|
||||
private readonly MC68000 _disassemblerInstance = new();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||
|
@ -12,32 +13,47 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
public bool FrameAdvance(IController controller, bool render, bool renderSound = true)
|
||||
{
|
||||
if (controller.IsPressed("Reset"))
|
||||
{
|
||||
Core.gpgx_reset(false);
|
||||
}
|
||||
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
Core.gpgx_reset(true);
|
||||
}
|
||||
|
||||
if (_cds != null)
|
||||
{
|
||||
var prev = controller.IsPressed("Previous Disk");
|
||||
var next = controller.IsPressed("Next Disk");
|
||||
int newDisk = _discIndex;
|
||||
var newDisk = _discIndex;
|
||||
if (prev && !_prevDiskPressed)
|
||||
{
|
||||
newDisk--;
|
||||
}
|
||||
|
||||
if (next && !_nextDiskPressed)
|
||||
{
|
||||
newDisk++;
|
||||
}
|
||||
|
||||
_prevDiskPressed = prev;
|
||||
_nextDiskPressed = next;
|
||||
|
||||
if (newDisk < -1)
|
||||
{
|
||||
newDisk = -1;
|
||||
}
|
||||
|
||||
if (newDisk >= _cds.Length)
|
||||
{
|
||||
newDisk = _cds.Length - 1;
|
||||
}
|
||||
|
||||
if (newDisk != _discIndex)
|
||||
{
|
||||
_discIndex = newDisk;
|
||||
Core.gpgx_swap_disc(_discIndex == -1 ? null : GetCDDataStruct(_cds[_discIndex]));
|
||||
Console.WriteLine("IMMA CHANGING MAH DISKS");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,10 +63,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
ControlConverter.ScreenWidth = _vwidth;
|
||||
ControlConverter.ScreenHeight = _vheight;
|
||||
ControlConverter.Convert(controller, input);
|
||||
ControlConverter.Convert(controller, _input);
|
||||
|
||||
if (!Core.gpgx_put_control(input, inputsize))
|
||||
if (controller.IsPressed("Pause"))
|
||||
{
|
||||
_input.pad[0] |= LibGPGX.INPUT_KEYS.INPUT_START;
|
||||
}
|
||||
|
||||
if (!Core.gpgx_put_control(_input, _inputSize))
|
||||
{
|
||||
throw new Exception($"{nameof(Core.gpgx_put_control)}() failed!");
|
||||
}
|
||||
|
||||
IsLagFrame = true;
|
||||
|
||||
|
@ -58,18 +81,26 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
Core.gpgx_advance();
|
||||
|
||||
if (render)
|
||||
if (render)
|
||||
{
|
||||
UpdateVideo();
|
||||
}
|
||||
|
||||
if (renderSound)
|
||||
update_audio();
|
||||
if (renderSound)
|
||||
{
|
||||
UpdateAudio();
|
||||
}
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
if (_cds != null)
|
||||
DriveLightOn = _driveLight;
|
||||
|
||||
{
|
||||
DriveLightOn = _driveLight;
|
||||
}
|
||||
|
||||
Frame++;
|
||||
|
||||
return true;
|
||||
|
@ -93,9 +124,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
if (!_disposed)
|
||||
{
|
||||
_elf?.Dispose();
|
||||
|
||||
if (_cds != null)
|
||||
{
|
||||
foreach (var cd in _cds)
|
||||
{
|
||||
cd.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
private readonly LibGPGX.input_cb _inputCallback;
|
||||
|
||||
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
|
||||
private readonly InputCallbackSystem _inputCallbacks = [ ];
|
||||
|
||||
private void input_callback()
|
||||
private void InputCallback()
|
||||
{
|
||||
InputCallbacks.Call();
|
||||
IsLagFrame = false;
|
||||
|
|
|
@ -22,7 +22,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
var size = 0;
|
||||
var pName = Core.gpgx_get_memdom(i, ref area, ref size);
|
||||
if (area == IntPtr.Zero || pName == IntPtr.Zero || size == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = Marshal.PtrToStringAnsi(pName)!;
|
||||
|
||||
// typically Genesis domains will be 2 bytes large (and thus big endian and byteswapped)
|
||||
|
@ -32,96 +35,108 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
? MemoryDomain.Endian.Little
|
||||
: MemoryDomain.Endian.Big;
|
||||
|
||||
if (name == "VRAM")
|
||||
switch (name)
|
||||
{
|
||||
// vram pokes need to go through hook which invalidates cached tiles
|
||||
var p = (byte*)area;
|
||||
if (SystemId == VSystemID.Raw.GEN)
|
||||
case "VRAM":
|
||||
{
|
||||
// Genesis has more VRAM, and GPGX byteswaps it
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
if (addr is < 0 or > 0xFFFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
return p![addr ^ 1];
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
if (addr is < 0 or > 0xFFFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_vram((int)addr ^ 1, val);
|
||||
},
|
||||
wordSize: 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3FFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
return p![addr];
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3FFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_vram((int)addr, val);
|
||||
},
|
||||
wordSize: 1));
|
||||
}
|
||||
}
|
||||
else if (name == "CRAM")
|
||||
{
|
||||
var p = (byte*)area;
|
||||
if (SystemId == VSystemID.Raw.GEN)
|
||||
{
|
||||
// CRAM for Genesis in the core is internally a different format than what it is natively
|
||||
// this internal format isn't really useful, so let's convert it back
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
if (addr is < 0 or > 0x7F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
// vram pokes need to go through hook which invalidates cached tiles
|
||||
var p = (byte*)area;
|
||||
if (SystemId == VSystemID.Raw.GEN)
|
||||
{
|
||||
// Genesis has more VRAM, and GPGX byteswaps it
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
var c = *(ushort*)&p![addr & ~1];
|
||||
c = (ushort)(((c & 0x1C0) << 3) | ((c & 0x038) << 2) | ((c & 0x007) << 1));
|
||||
return (byte)((addr & 1) != 0 ? c & 0xFF : c >> 8);
|
||||
}
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
if (addr is < 0 or > 0x7F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_cram((int)addr, val);
|
||||
},
|
||||
wordSize: 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
if (addr is < 0 or > 0xFFFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
return p![addr ^ 1];
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
var c = *(ushort*)&p![addr & ~1];
|
||||
return (byte)((addr & 1) != 0 ? c & 0xFF : c >> 8);
|
||||
}
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_cram((int)addr, val);
|
||||
},
|
||||
wordSize: 2));
|
||||
if (addr is < 0 or > 0xFFFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_vram((int)addr ^ 1, val);
|
||||
},
|
||||
wordSize: 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3FFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
return p![addr];
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3FFF) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_vram((int)addr, val);
|
||||
},
|
||||
wordSize: 1));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "CRAM":
|
||||
{
|
||||
var p = (byte*)area;
|
||||
if (SystemId == VSystemID.Raw.GEN)
|
||||
{
|
||||
// CRAM for Genesis in the core is internally a different format than what it is natively
|
||||
// this internal format isn't really useful, so let's convert it back
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
if (addr is < 0 or > 0x7F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
{
|
||||
var c = *(ushort*)&p![addr & ~1];
|
||||
c = (ushort)(((c & 0x1C0) << 3) | ((c & 0x038) << 2) | ((c & 0x007) << 1));
|
||||
return (byte)((addr & 1) != 0 ? c & 0xFF : c >> 8);
|
||||
}
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
if (addr is < 0 or > 0x7F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_cram((int)addr, val);
|
||||
},
|
||||
wordSize: 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Big,
|
||||
addr =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
using (_elf.EnterExit())
|
||||
{
|
||||
var c = *(ushort*)&p![addr & ~1];
|
||||
return (byte)((addr & 1) != 0 ? c & 0xFF : c >> 8);
|
||||
}
|
||||
},
|
||||
(addr, val) =>
|
||||
{
|
||||
if (addr is < 0 or > 0x3F) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
|
||||
Core.gpgx_poke_cram((int)addr, val);
|
||||
},
|
||||
wordSize: 2));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (oneByteWidth)
|
||||
{
|
||||
mm.Add(new MemoryDomainIntPtrMonitor(name, endian, area, size, true, 1, _elf));
|
||||
}
|
||||
else
|
||||
{
|
||||
mm.Add(new MemoryDomainIntPtrSwap16Monitor(name, endian, area, size, true, _elf));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (oneByteWidth)
|
||||
{
|
||||
mm.Add(new MemoryDomainIntPtrMonitor(name, endian, area, size, true, 1, _elf));
|
||||
}
|
||||
else
|
||||
{
|
||||
mm.Add(new MemoryDomainIntPtrSwap16Monitor(name, endian, area, size, true, _elf));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
|
@ -9,14 +10,19 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
{
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
int size = 0;
|
||||
IntPtr area = Core.gpgx_get_sram(ref size);
|
||||
var size = 0;
|
||||
var area = Core.gpgx_get_sram(ref size);
|
||||
if (size == 0 || area == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] ret = new byte[size];
|
||||
var ret = new byte[size];
|
||||
using (_elf.EnterExit())
|
||||
{
|
||||
Marshal.Copy(area, ret, 0, size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -27,6 +33,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
// not sure how this is happening, but reject them
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Core.gpgx_put_sram(data, data.Length))
|
||||
{
|
||||
throw new Exception("Core rejected saveram");
|
||||
|
@ -37,8 +44,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
{
|
||||
get
|
||||
{
|
||||
int size = 0;
|
||||
IntPtr area = Core.gpgx_get_sram(ref size);
|
||||
var size = 0;
|
||||
var area = Core.gpgx_get_sram(ref size);
|
||||
return size > 0 && area != IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,24 +6,19 @@ using BizHawk.Common;
|
|||
using BizHawk.Emulation.Common;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||
{
|
||||
public partial class GPGX : ISettable<GPGX.GPGXSettings, GPGX.GPGXSyncSettings>
|
||||
{
|
||||
public GPGXSettings GetSettings()
|
||||
{
|
||||
return _settings.Clone();
|
||||
}
|
||||
=> _settings.Clone();
|
||||
|
||||
public GPGXSyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
=> _syncSettings.Clone();
|
||||
|
||||
public PutSettingsDirtyBits PutSettings(GPGXSettings o)
|
||||
{
|
||||
bool ret = GPGXSettings.NeedsReboot(_settings, o);
|
||||
var ret = GPGXSettings.NeedsReboot(_settings, o);
|
||||
_settings = o;
|
||||
Core.gpgx_set_draw_mask(_settings.GetDrawMask());
|
||||
Core.gpgx_set_sprite_limit_enabled(!_settings.NoSpriteLimit);
|
||||
|
@ -32,7 +27,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
public PutSettingsDirtyBits PutSyncSettings(GPGXSyncSettings o)
|
||||
{
|
||||
bool ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o);
|
||||
var ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o);
|
||||
_syncSettings = o;
|
||||
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
|
||||
}
|
||||
|
@ -40,18 +35,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
private class UintToHexConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
=> sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
=> destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(string) && value.GetType() == typeof(uint))
|
||||
if (destinationType == typeof(string) && value is uint)
|
||||
{
|
||||
return $"0x{value:x8}";
|
||||
}
|
||||
|
@ -61,13 +52,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value.GetType() == typeof(string))
|
||||
if (value?.GetType() == typeof(string))
|
||||
{
|
||||
string input = (string)value;
|
||||
var input = (string)value;
|
||||
if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
input = input.Substring(2);
|
||||
input = input[2..];
|
||||
}
|
||||
|
||||
return uint.Parse(input, NumberStyles.HexNumber, culture);
|
||||
}
|
||||
|
||||
|
@ -78,18 +70,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
private class UshortToHexConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
=> sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
=> destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(string) && value.GetType() == typeof(ushort))
|
||||
if (destinationType == typeof(string) && value is ushort)
|
||||
{
|
||||
return $"0x{value:x4}";
|
||||
}
|
||||
|
@ -99,13 +87,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||
{
|
||||
if (value.GetType() == typeof(string))
|
||||
if (value?.GetType() == typeof(string))
|
||||
{
|
||||
string input = (string)value;
|
||||
var input = (string)value;
|
||||
if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
input = input.Substring(2);
|
||||
input = input[2..];
|
||||
}
|
||||
|
||||
return ushort.Parse(input, NumberStyles.HexNumber, culture);
|
||||
}
|
||||
|
||||
|
@ -210,16 +199,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
set => _noSpriteLimit = value;
|
||||
}
|
||||
|
||||
|
||||
public GPGXSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
=> SettingsUtil.SetDefaultValues(this);
|
||||
|
||||
public GPGXSettings Clone()
|
||||
{
|
||||
return (GPGXSettings)MemberwiseClone();
|
||||
}
|
||||
=> (GPGXSettings)MemberwiseClone();
|
||||
|
||||
public LibGPGX.DrawMask GetDrawMask()
|
||||
{
|
||||
|
@ -233,11 +217,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
|
||||
public static bool NeedsReboot(GPGXSettings x, GPGXSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
|
||||
|
||||
=> !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
|
||||
[CoreSettings]
|
||||
|
@ -366,19 +346,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
|
||||
public GPGXSyncSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
=> SettingsUtil.SetDefaultValues(this);
|
||||
|
||||
public GPGXSyncSettings Clone()
|
||||
{
|
||||
return (GPGXSyncSettings)MemberwiseClone();
|
||||
}
|
||||
=> (GPGXSyncSettings)MemberwiseClone();
|
||||
|
||||
public static bool NeedsReboot(GPGXSyncSettings x, GPGXSyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
=> !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||
{
|
||||
|
@ -20,9 +21,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
_nsamp = 0;
|
||||
}
|
||||
=> _nsamp = 0;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
|
@ -30,23 +29,23 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
=> throw new InvalidOperationException("Async mode is not supported.");
|
||||
|
||||
private void update_audio()
|
||||
private void UpdateAudio()
|
||||
{
|
||||
IntPtr src = IntPtr.Zero;
|
||||
var src = IntPtr.Zero;
|
||||
Core.gpgx_get_audio(ref _nsamp, ref src);
|
||||
if (src != IntPtr.Zero)
|
||||
{
|
||||
using (_elf.EnterExit())
|
||||
{
|
||||
Marshal.Copy(src, _samples, 0, _nsamp * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||
|
@ -20,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
// any managed pointers that we sent to the core need to be resent now!
|
||||
Core.gpgx_set_input_callback(_inputCallback);
|
||||
RefreshMemCallbacks();
|
||||
Core.gpgx_set_cdd_callback(cd_callback_handle);
|
||||
Core.gpgx_set_cdd_callback(CDReadCallback);
|
||||
Core.gpgx_invalidate_pattern_cache();
|
||||
Core.gpgx_set_draw_mask(_settings.GetDrawMask());
|
||||
Core.gpgx_set_sprite_limit_enabled(!_settings.NoSpriteLimit);
|
||||
|
|
|
@ -9,17 +9,18 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
{
|
||||
private readonly ITraceable _tracer;
|
||||
|
||||
public class GPGXTraceBuffer : CallbackBasedTraceBuffer
|
||||
public class GPGXTraceBuffer(
|
||||
IDebuggable debuggableCore,
|
||||
IMemoryDomains memoryDomains,
|
||||
IDisassemblable disassembler)
|
||||
: CallbackBasedTraceBuffer(debuggableCore, memoryDomains, disassembler, TRACE_HEADER)
|
||||
{
|
||||
private const string TRACE_HEADER = "M68K: PC, machine code, mnemonic, operands, registers (D0-D7, A0-A7, SR, USP), flags (XNZVC)";
|
||||
|
||||
public GPGXTraceBuffer(IDebuggable debuggableCore, IMemoryDomains memoryDomains, IDisassemblable disassembler)
|
||||
: base(debuggableCore, memoryDomains, disassembler, TRACE_HEADER) {}
|
||||
|
||||
protected override void TraceFromCallback(uint addr, uint value, uint flags)
|
||||
{
|
||||
var regs = DebuggableCore.GetCpuFlagsAndRegisters();
|
||||
uint pc = (uint)regs["M68K PC"].Value;
|
||||
var pc = (uint)regs["M68K PC"].Value;
|
||||
var disasm = Disassembler.Disassemble(MemoryDomains.SystemBus, pc & 0xFFFFFF, out _);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
@ -36,6 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sr = regs["M68K SR"].Value;
|
||||
sb.Append(string.Concat(
|
||||
(sr & 16) > 0 ? "X" : "x",
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
public int VsyncDenominator { get; }
|
||||
|
||||
private int[] _vidBuff = Array.Empty<int>();
|
||||
private int[] _vidBuff = [ ];
|
||||
private int _vwidth;
|
||||
private int _vheight;
|
||||
|
||||
|
@ -70,7 +70,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
_vwidth = VirtualWidth;
|
||||
_vheight = VirtualHeight;
|
||||
_vidBuff = new int[_vwidth * _vheight];
|
||||
for (int i = 0; i < _vidBuff.Length; i++)
|
||||
for (var i = 0; i < _vidBuff.Length; i++)
|
||||
{
|
||||
_vidBuff[i] = unchecked((int)0xff000000);
|
||||
}
|
||||
|
@ -86,8 +86,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
using (_elf.EnterExit())
|
||||
{
|
||||
IntPtr src = IntPtr.Zero;
|
||||
|
||||
var src = IntPtr.Zero;
|
||||
Core.gpgx_get_video(out var gpwidth, out var gpheight, out var gppitch, ref src);
|
||||
|
||||
_vwidth = gpwidth;
|
||||
|
@ -96,31 +95,41 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
if (_settings.PadScreen320 && _vwidth < 320)
|
||||
_vwidth = 320;
|
||||
|
||||
int xpad = (_vwidth - gpwidth) / 2;
|
||||
int xpad2 = _vwidth - gpwidth - xpad;
|
||||
var xpad = (_vwidth - gpwidth) / 2;
|
||||
var xpad2 = _vwidth - gpwidth - xpad;
|
||||
|
||||
if (_vidBuff.Length < _vwidth * _vheight)
|
||||
{
|
||||
_vidBuff = new int[_vwidth * _vheight];
|
||||
}
|
||||
|
||||
int rinc = (gppitch / 4) - gpwidth;
|
||||
var rinc = (gppitch / 4) - gpwidth;
|
||||
fixed (int* pdst_ = _vidBuff)
|
||||
{
|
||||
int* pdst = pdst_;
|
||||
int* psrc = (int*)src;
|
||||
var pdst = pdst_;
|
||||
var psrc = (int*)src;
|
||||
|
||||
for (int j = 0; j < gpheight; j++)
|
||||
for (var j = 0; j < gpheight; j++)
|
||||
{
|
||||
for (int i = 0; i < xpad; i++)
|
||||
for (var i = 0; i < xpad; i++)
|
||||
{
|
||||
*pdst++ = unchecked((int)0xff000000);
|
||||
for (int i = 0; i < gpwidth; i++)
|
||||
}
|
||||
|
||||
for (var i = 0; i < gpwidth; i++)
|
||||
{
|
||||
*pdst++ = *psrc++;
|
||||
for (int i = 0; i < xpad2; i++)
|
||||
}
|
||||
|
||||
for (var i = 0; i < xpad2; i++)
|
||||
{
|
||||
*pdst++ = unchecked((int)0xff000000);
|
||||
}
|
||||
|
||||
psrc += rinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.PathExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.DiscSystem;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||
{
|
||||
|
@ -25,11 +25,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
[CoreConstructor(VSystemID.Raw.SG)]
|
||||
public GPGX(CoreLoadParameters<GPGXSettings, GPGXSyncSettings> lp)
|
||||
{
|
||||
LoadCallback = load_archive;
|
||||
_inputCallback = input_callback;
|
||||
LoadCallback = LoadArchive;
|
||||
_inputCallback = InputCallback;
|
||||
InitMemCallbacks(); // ExecCallback, ReadCallback, WriteCallback
|
||||
CDCallback = CDCallbackProc;
|
||||
cd_callback_handle = CDRead;
|
||||
CDReadCallback = CDRead;
|
||||
|
||||
ServiceProvider = new BasicServiceProvider(this);
|
||||
// this can influence some things internally (autodetect romtype, etc)
|
||||
|
@ -53,7 +53,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
// three or six button?
|
||||
// http://www.sega-16.com/forum/showthread.php?4398-Forgotten-Worlds-giving-you-GAME-OVER-immediately-Fix-inside&highlight=forgotten%20worlds
|
||||
|
||||
//hack, don't use
|
||||
// hack, don't use
|
||||
if (lp.Roms.FirstOrDefault()?.RomData.Length > 32 * 1024 * 1024)
|
||||
{
|
||||
throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?");
|
||||
|
@ -75,7 +75,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
var callingConventionAdapter = CallingConventionAdapters.MakeWaterbox(new Delegate[]
|
||||
{
|
||||
LoadCallback, _inputCallback, ExecCallback, ReadCallback, WriteCallback,
|
||||
CDCallback, cd_callback_handle,
|
||||
CDCallback, CDReadCallback,
|
||||
}, _elf);
|
||||
|
||||
using (_elf.EnterExit())
|
||||
|
@ -97,7 +97,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
_cds = lp.Discs.Select(d => d.DiscData).ToArray();
|
||||
_cdReaders = _cds.Select(c => new DiscSectorReader(c)).ToArray();
|
||||
Core.gpgx_set_cdd_callback(cd_callback_handle);
|
||||
Core.gpgx_set_cdd_callback(CDReadCallback);
|
||||
DriveLightEnabled = true;
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
// and CdCallback
|
||||
Core.gpgx_set_cdd_callback(null);
|
||||
_elf.Seal();
|
||||
Core.gpgx_set_cdd_callback(cd_callback_handle);
|
||||
Core.gpgx_set_cdd_callback(CDReadCallback);
|
||||
|
||||
SetControllerDefinition();
|
||||
|
||||
|
@ -158,29 +158,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
_romfile = null;
|
||||
}
|
||||
|
||||
private static LibGPGX.INPUT_SYSTEM SystemForSystem(ControlType c)
|
||||
private static LibGPGX.INPUT_SYSTEM SystemForSystem(ControlType c) => c switch
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
default:
|
||||
case ControlType.None:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_NONE;
|
||||
case ControlType.Normal:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_GAMEPAD;
|
||||
case ControlType.Xea1p:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P;
|
||||
case ControlType.Activator:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR;
|
||||
case ControlType.Teamplayer:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER;
|
||||
case ControlType.Wayplay:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY;
|
||||
case ControlType.Mouse:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE;
|
||||
case ControlType.Paddle:
|
||||
return LibGPGX.INPUT_SYSTEM.SYSTEM_PADDLE;
|
||||
}
|
||||
}
|
||||
ControlType.Normal => LibGPGX.INPUT_SYSTEM.SYSTEM_GAMEPAD,
|
||||
ControlType.Xea1p => LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P,
|
||||
ControlType.Activator => LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR,
|
||||
ControlType.Teamplayer => LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER,
|
||||
ControlType.Wayplay => LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY,
|
||||
ControlType.Mouse => LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE,
|
||||
ControlType.Paddle => LibGPGX.INPUT_SYSTEM.SYSTEM_PADDLE,
|
||||
_ => LibGPGX.INPUT_SYSTEM.SYSTEM_NONE
|
||||
};
|
||||
|
||||
private readonly LibGPGX Core;
|
||||
private readonly WaterboxHost _elf;
|
||||
|
@ -193,12 +181,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
private readonly byte[] _romfile;
|
||||
|
||||
private bool _disposed = false;
|
||||
private bool _disposed;
|
||||
|
||||
private LibGPGX.load_archive_cb LoadCallback;
|
||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||
private readonly LibGPGX.load_archive_cb LoadCallback;
|
||||
private bool _firmwareRequestFailed;
|
||||
|
||||
private readonly LibGPGX.InputData input = new LibGPGX.InputData();
|
||||
private readonly LibGPGX.InputData _input = new();
|
||||
|
||||
public enum ControlType
|
||||
{
|
||||
|
@ -212,7 +201,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
Paddle,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// core callback for file loading
|
||||
/// </summary>
|
||||
|
@ -220,9 +208,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
/// <param name="buffer">buffer to load file to</param>
|
||||
/// <param name="maxsize">maximum length buffer can hold</param>
|
||||
/// <returns>actual size loaded, or 0 on failure</returns>
|
||||
private int load_archive(string filename, IntPtr buffer, int maxsize)
|
||||
private int LoadArchive(string filename, IntPtr buffer, int maxsize)
|
||||
{
|
||||
byte[] srcdata = null;
|
||||
byte[] srcdata;
|
||||
|
||||
if (buffer == IntPtr.Zero)
|
||||
{
|
||||
|
@ -230,69 +218,66 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (filename == "PRIMARY_ROM")
|
||||
switch (filename)
|
||||
{
|
||||
if (_romfile == null)
|
||||
{
|
||||
case "PRIMARY_ROM" when _romfile == null:
|
||||
Console.WriteLine("Couldn't satisfy firmware request PRIMARY_ROM because none was provided.");
|
||||
return 0;
|
||||
}
|
||||
srcdata = _romfile;
|
||||
}
|
||||
else if (filename is "PRIMARY_CD" or "SECONDARY_CD")
|
||||
{
|
||||
if (filename == "PRIMARY_CD" && _romfile != null)
|
||||
{
|
||||
case "PRIMARY_ROM":
|
||||
srcdata = _romfile;
|
||||
break;
|
||||
case ("PRIMARY_CD" or "SECONDARY_CD") and "PRIMARY_CD" when _romfile != null:
|
||||
Console.WriteLine("Declined to satisfy firmware request PRIMARY_CD because PRIMARY_ROM was provided.");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
case "PRIMARY_CD" or "SECONDARY_CD" when _cds == null:
|
||||
Console.WriteLine("Couldn't satisfy firmware request {0} because none was provided.", filename);
|
||||
return 0;
|
||||
case "PRIMARY_CD" or "SECONDARY_CD":
|
||||
{
|
||||
if (_cds == null)
|
||||
{
|
||||
Console.WriteLine("Couldn't satisfy firmware request {0} because none was provided.", filename);
|
||||
return 0;
|
||||
}
|
||||
srcdata = GetCDData(_cds[0]);
|
||||
if (srcdata.Length != maxsize)
|
||||
{
|
||||
Console.WriteLine("Couldn't satisfy firmware request {0} because of struct size ({1} != {2}).", filename, srcdata.Length, maxsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// use fromtend firmware interface
|
||||
|
||||
FirmwareID? firmwareID = filename switch
|
||||
{
|
||||
"MD_BIOS" => new(system: VSystemID.Raw.GEN, firmware: "Boot"),
|
||||
"CD_BIOS_EU" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_EU"),
|
||||
"CD_BIOS_JP" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_JP"),
|
||||
"CD_BIOS_US" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_US"),
|
||||
"GG_BIOS" => new(system: VSystemID.Raw.GG, firmware: "Majesco"),
|
||||
"MS_BIOS_EU" => new(system: VSystemID.Raw.SMS, firmware: "Export"),
|
||||
"MS_BIOS_JP" => new(system: VSystemID.Raw.SMS, firmware: "Japan"),
|
||||
"MS_BIOS_US" => new(system: VSystemID.Raw.SMS, firmware: "Export"),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (firmwareID != null)
|
||||
default:
|
||||
{
|
||||
// this path will be the most common PEBKAC error, so be a bit more vocal about the problem
|
||||
srcdata = CoreComm.CoreFileProvider.GetFirmware(firmwareID.Value, "GPGX firmwares are usually required.");
|
||||
if (srcdata == null)
|
||||
// use fromtend firmware interface
|
||||
|
||||
FirmwareID? firmwareID = filename switch
|
||||
{
|
||||
_firmwareRequestFailed = true;
|
||||
Console.WriteLine($"Frontend couldn't satisfy firmware request {firmwareID}");
|
||||
"MD_BIOS" => new(system: VSystemID.Raw.GEN, firmware: "Boot"),
|
||||
"CD_BIOS_EU" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_EU"),
|
||||
"CD_BIOS_JP" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_JP"),
|
||||
"CD_BIOS_US" => new(system: VSystemID.Raw.GEN, firmware: "CD_BIOS_US"),
|
||||
"GG_BIOS" => new(system: VSystemID.Raw.GG, firmware: "Majesco"),
|
||||
"MS_BIOS_EU" => new(system: VSystemID.Raw.SMS, firmware: "Export"),
|
||||
"MS_BIOS_JP" => new(system: VSystemID.Raw.SMS, firmware: "Japan"),
|
||||
"MS_BIOS_US" => new(system: VSystemID.Raw.SMS, firmware: "Export"),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (firmwareID != null)
|
||||
{
|
||||
// this path will be the most common PEBKAC error, so be a bit more vocal about the problem
|
||||
srcdata = CoreComm.CoreFileProvider.GetFirmware(firmwareID.Value, "GPGX firmwares are usually required.");
|
||||
if (srcdata == null)
|
||||
{
|
||||
_firmwareRequestFailed = true;
|
||||
Console.WriteLine($"Frontend couldn't satisfy firmware request {firmwareID}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Unrecognized firmware request {0}", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Unrecognized firmware request {0}", filename);
|
||||
return 0;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -303,18 +288,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
Console.WriteLine("Couldn't satisfy firmware request {0} because {1} > {2}", filename, srcdata.Length, maxsize);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.Copy(srcdata, 0, buffer, srcdata.Length);
|
||||
Console.WriteLine("Firmware request {0} satisfied at size {1}", filename, srcdata.Length);
|
||||
return srcdata.Length;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Unknown error processing firmware");
|
||||
|
||||
Marshal.Copy(srcdata, 0, buffer, srcdata.Length);
|
||||
Console.WriteLine("Firmware request {0} satisfied at size {1}", filename, srcdata.Length);
|
||||
return srcdata.Length;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Unknown error processing firmware");
|
||||
}
|
||||
|
||||
private CoreComm CoreComm { get; }
|
||||
|
@ -339,7 +319,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
}
|
||||
|
||||
private readonly LibGPGX.cd_read_cb cd_callback_handle;
|
||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||
private readonly LibGPGX.cd_read_cb CDReadCallback;
|
||||
|
||||
public static LibGPGX.CDData GetCDDataStruct(Disc cd)
|
||||
{
|
||||
|
@ -397,61 +378,41 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
/// <summary>
|
||||
/// size of native input struct
|
||||
/// </summary>
|
||||
private int inputsize;
|
||||
private int _inputSize;
|
||||
|
||||
private GPGXControlConverter ControlConverter;
|
||||
|
||||
private void SetControllerDefinition()
|
||||
{
|
||||
inputsize = Marshal.SizeOf(typeof(LibGPGX.InputData));
|
||||
if (!Core.gpgx_get_control(input, inputsize))
|
||||
_inputSize = Marshal.SizeOf(typeof(LibGPGX.InputData));
|
||||
if (!Core.gpgx_get_control(_input, _inputSize))
|
||||
{
|
||||
throw new Exception($"{nameof(Core.gpgx_get_control)}() failed");
|
||||
}
|
||||
|
||||
ControlConverter = new(input, systemId: SystemId, cdButtons: _cds is not null);
|
||||
ControlConverter = new(_input, systemId: SystemId, cdButtons: _cds is not null);
|
||||
ControllerDefinition = ControlConverter.ControllerDef;
|
||||
}
|
||||
|
||||
public LibGPGX.INPUT_DEVICE[] GetDevices()
|
||||
{
|
||||
return (LibGPGX.INPUT_DEVICE[])input.dev.Clone();
|
||||
}
|
||||
=> (LibGPGX.INPUT_DEVICE[])_input.dev.Clone();
|
||||
|
||||
public bool IsMegaCD => _cds != null;
|
||||
|
||||
public class VDPView : IMonitor
|
||||
public class VDPView(in LibGPGX.VDPView v, IMonitor m) : IMonitor
|
||||
{
|
||||
private readonly IMonitor _m;
|
||||
|
||||
public VDPView(in LibGPGX.VDPView v, IMonitor m)
|
||||
{
|
||||
_m = m;
|
||||
VRAM = v.VRAM;
|
||||
PatternCache = v.PatternCache;
|
||||
ColorCache = v.ColorCache;
|
||||
NTA = v.NTA;
|
||||
NTB = v.NTB;
|
||||
NTW = v.NTW;
|
||||
}
|
||||
|
||||
public IntPtr VRAM;
|
||||
public IntPtr PatternCache;
|
||||
public IntPtr ColorCache;
|
||||
public LibGPGX.VDPNameTable NTA;
|
||||
public LibGPGX.VDPNameTable NTB;
|
||||
public LibGPGX.VDPNameTable NTW;
|
||||
|
||||
public IntPtr VRAM = v.VRAM;
|
||||
public IntPtr PatternCache = v.PatternCache;
|
||||
public IntPtr ColorCache = v.ColorCache;
|
||||
public LibGPGX.VDPNameTable NTA = v.NTA;
|
||||
public LibGPGX.VDPNameTable NTB = v.NTB;
|
||||
public LibGPGX.VDPNameTable NTW = v.NTW;
|
||||
|
||||
public void Enter()
|
||||
{
|
||||
_m.Enter();
|
||||
}
|
||||
=> m.Enter();
|
||||
|
||||
public void Exit()
|
||||
{
|
||||
_m.Exit();
|
||||
}
|
||||
=> m.Exit();
|
||||
}
|
||||
|
||||
public VDPView UpdateVDPViewContext()
|
||||
|
@ -462,14 +423,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
}
|
||||
|
||||
public int AddDeepFreezeValue(int address, byte value)
|
||||
{
|
||||
return Core.gpgx_add_deepfreeze_list_entry(address, value);
|
||||
}
|
||||
=> Core.gpgx_add_deepfreeze_list_entry(address, value);
|
||||
|
||||
public void ClearDeepFreezeList()
|
||||
{
|
||||
Core.gpgx_clear_deepfreeze_list();
|
||||
}
|
||||
=> Core.gpgx_clear_deepfreeze_list();
|
||||
|
||||
public DisplayType Region { get; }
|
||||
}
|
||||
|
|
|
@ -10,123 +10,118 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
{
|
||||
// this isn't all done
|
||||
|
||||
private struct CName
|
||||
private readonly struct CName(string name, LibGPGX.INPUT_KEYS key)
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly LibGPGX.INPUT_KEYS Key;
|
||||
public CName(string name, LibGPGX.INPUT_KEYS key)
|
||||
{
|
||||
Name = name;
|
||||
Key = key;
|
||||
}
|
||||
public readonly string Name = name;
|
||||
public readonly LibGPGX.INPUT_KEYS Key = key;
|
||||
}
|
||||
|
||||
private static readonly CName[] SMS2B =
|
||||
{
|
||||
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new CName("B1", LibGPGX.INPUT_KEYS.INPUT_BUTTON1),
|
||||
new CName("B2", LibGPGX.INPUT_KEYS.INPUT_BUTTON2)
|
||||
};
|
||||
[
|
||||
new("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new("B1", LibGPGX.INPUT_KEYS.INPUT_BUTTON1),
|
||||
new("B2", LibGPGX.INPUT_KEYS.INPUT_BUTTON2),
|
||||
];
|
||||
|
||||
private static readonly CName[] GameGear =
|
||||
{
|
||||
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new CName("B1", LibGPGX.INPUT_KEYS.INPUT_BUTTON1),
|
||||
new CName("B2", LibGPGX.INPUT_KEYS.INPUT_BUTTON2),
|
||||
new CName("Start", LibGPGX.INPUT_KEYS.INPUT_START),
|
||||
};
|
||||
[
|
||||
new("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new("B1", LibGPGX.INPUT_KEYS.INPUT_BUTTON1),
|
||||
new("B2", LibGPGX.INPUT_KEYS.INPUT_BUTTON2),
|
||||
new("Start", LibGPGX.INPUT_KEYS.INPUT_START),
|
||||
];
|
||||
|
||||
private static readonly CName[] Genesis3 =
|
||||
{
|
||||
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new CName("A", LibGPGX.INPUT_KEYS.INPUT_A),
|
||||
new CName("B", LibGPGX.INPUT_KEYS.INPUT_B),
|
||||
new CName("C", LibGPGX.INPUT_KEYS.INPUT_C),
|
||||
new CName("Start", LibGPGX.INPUT_KEYS.INPUT_START),
|
||||
};
|
||||
[
|
||||
new("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new("A", LibGPGX.INPUT_KEYS.INPUT_A),
|
||||
new("B", LibGPGX.INPUT_KEYS.INPUT_B),
|
||||
new("C", LibGPGX.INPUT_KEYS.INPUT_C),
|
||||
new("Start", LibGPGX.INPUT_KEYS.INPUT_START),
|
||||
];
|
||||
|
||||
private static readonly CName[] Genesis6 =
|
||||
{
|
||||
new CName("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new CName("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new CName("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new CName("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new CName("A", LibGPGX.INPUT_KEYS.INPUT_A),
|
||||
new CName("B", LibGPGX.INPUT_KEYS.INPUT_B),
|
||||
new CName("C", LibGPGX.INPUT_KEYS.INPUT_C),
|
||||
new CName("Start", LibGPGX.INPUT_KEYS.INPUT_START),
|
||||
new CName("X", LibGPGX.INPUT_KEYS.INPUT_X),
|
||||
new CName("Y", LibGPGX.INPUT_KEYS.INPUT_Y),
|
||||
new CName("Z", LibGPGX.INPUT_KEYS.INPUT_Z),
|
||||
new CName("Mode", LibGPGX.INPUT_KEYS.INPUT_MODE),
|
||||
};
|
||||
[
|
||||
new("Up", LibGPGX.INPUT_KEYS.INPUT_UP),
|
||||
new("Down", LibGPGX.INPUT_KEYS.INPUT_DOWN),
|
||||
new("Left", LibGPGX.INPUT_KEYS.INPUT_LEFT),
|
||||
new("Right", LibGPGX.INPUT_KEYS.INPUT_RIGHT),
|
||||
new("A", LibGPGX.INPUT_KEYS.INPUT_A),
|
||||
new("B", LibGPGX.INPUT_KEYS.INPUT_B),
|
||||
new("C", LibGPGX.INPUT_KEYS.INPUT_C),
|
||||
new("Start", LibGPGX.INPUT_KEYS.INPUT_START),
|
||||
new("X", LibGPGX.INPUT_KEYS.INPUT_X),
|
||||
new("Y", LibGPGX.INPUT_KEYS.INPUT_Y),
|
||||
new("Z", LibGPGX.INPUT_KEYS.INPUT_Z),
|
||||
new("Mode", LibGPGX.INPUT_KEYS.INPUT_MODE),
|
||||
];
|
||||
|
||||
private static readonly CName[] Mouse =
|
||||
{
|
||||
new CName("Mouse Left", LibGPGX.INPUT_KEYS.INPUT_MOUSE_LEFT),
|
||||
new CName("Mouse Center", LibGPGX.INPUT_KEYS.INPUT_MOUSE_CENTER),
|
||||
new CName("Mouse Right", LibGPGX.INPUT_KEYS.INPUT_MOUSE_RIGHT),
|
||||
new CName("Mouse Start", LibGPGX.INPUT_KEYS.INPUT_MOUSE_START),
|
||||
};
|
||||
[
|
||||
new("Mouse Left", LibGPGX.INPUT_KEYS.INPUT_MOUSE_LEFT),
|
||||
new("Mouse Center", LibGPGX.INPUT_KEYS.INPUT_MOUSE_CENTER),
|
||||
new("Mouse Right", LibGPGX.INPUT_KEYS.INPUT_MOUSE_RIGHT),
|
||||
new("Mouse Start", LibGPGX.INPUT_KEYS.INPUT_MOUSE_START),
|
||||
];
|
||||
|
||||
private static readonly CName[] Lightgun =
|
||||
{
|
||||
new CName("Lightgun Trigger", LibGPGX.INPUT_KEYS.INPUT_MENACER_TRIGGER),
|
||||
new CName("Lightgun Start", LibGPGX.INPUT_KEYS.INPUT_MENACER_START),
|
||||
new CName("Lightgun B", LibGPGX.INPUT_KEYS.INPUT_MENACER_B),
|
||||
new CName("Lightgun C", LibGPGX.INPUT_KEYS.INPUT_MENACER_C),
|
||||
};
|
||||
[
|
||||
new("Lightgun Trigger", LibGPGX.INPUT_KEYS.INPUT_MENACER_TRIGGER),
|
||||
new("Lightgun Start", LibGPGX.INPUT_KEYS.INPUT_MENACER_START),
|
||||
new("Lightgun B", LibGPGX.INPUT_KEYS.INPUT_MENACER_B),
|
||||
new("Lightgun C", LibGPGX.INPUT_KEYS.INPUT_MENACER_C),
|
||||
];
|
||||
|
||||
private static readonly CName[] Activator =
|
||||
{
|
||||
new CName("1L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_1L),
|
||||
new CName("1U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_1U),
|
||||
new CName("2L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_2L),
|
||||
new CName("2U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_2U),
|
||||
new CName("3L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_3L),
|
||||
new CName("3U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_3U),
|
||||
new CName("4L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_4L),
|
||||
new CName("4U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_4U),
|
||||
new CName("5L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_5L),
|
||||
new CName("5U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_5U),
|
||||
new CName("6L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_6L),
|
||||
new CName("6U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_6U),
|
||||
new CName("7L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_7L),
|
||||
new CName("7U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_7U),
|
||||
new CName("8L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_8L),
|
||||
new CName("8U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_8U),
|
||||
};
|
||||
[
|
||||
new("1L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_1L),
|
||||
new("1U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_1U),
|
||||
new("2L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_2L),
|
||||
new("2U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_2U),
|
||||
new("3L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_3L),
|
||||
new("3U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_3U),
|
||||
new("4L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_4L),
|
||||
new("4U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_4U),
|
||||
new("5L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_5L),
|
||||
new("5U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_5U),
|
||||
new("6L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_6L),
|
||||
new("6U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_6U),
|
||||
new("7L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_7L),
|
||||
new("7U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_7U),
|
||||
new("8L", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_8L),
|
||||
new("8U", LibGPGX.INPUT_KEYS.INPUT_ACTIVATOR_8U),
|
||||
];
|
||||
|
||||
private static readonly CName[] Xea1P =
|
||||
{
|
||||
new CName("XE A", LibGPGX.INPUT_KEYS.INPUT_XE_A),
|
||||
new CName("XE B", LibGPGX.INPUT_KEYS.INPUT_XE_B),
|
||||
new CName("XE C", LibGPGX.INPUT_KEYS.INPUT_XE_C),
|
||||
new CName("XE D", LibGPGX.INPUT_KEYS.INPUT_XE_D),
|
||||
new CName("XE Start", LibGPGX.INPUT_KEYS.INPUT_XE_START),
|
||||
new CName("XE Select", LibGPGX.INPUT_KEYS.INPUT_XE_SELECT),
|
||||
new CName("XE E1", LibGPGX.INPUT_KEYS.INPUT_XE_E1),
|
||||
new CName("XE E2", LibGPGX.INPUT_KEYS.INPUT_XE_E2),
|
||||
};
|
||||
[
|
||||
new("XE A", LibGPGX.INPUT_KEYS.INPUT_XE_A),
|
||||
new("XE B", LibGPGX.INPUT_KEYS.INPUT_XE_B),
|
||||
new("XE C", LibGPGX.INPUT_KEYS.INPUT_XE_C),
|
||||
new("XE D", LibGPGX.INPUT_KEYS.INPUT_XE_D),
|
||||
new("XE Start", LibGPGX.INPUT_KEYS.INPUT_XE_START),
|
||||
new("XE Select", LibGPGX.INPUT_KEYS.INPUT_XE_SELECT),
|
||||
new("XE E1", LibGPGX.INPUT_KEYS.INPUT_XE_E1),
|
||||
new("XE E2", LibGPGX.INPUT_KEYS.INPUT_XE_E2),
|
||||
];
|
||||
|
||||
private static readonly CName[] Paddle =
|
||||
{
|
||||
[
|
||||
new("B1", LibGPGX.INPUT_KEYS.INPUT_BUTTON1)
|
||||
};
|
||||
];
|
||||
|
||||
private LibGPGX.InputData _target;
|
||||
private IController _source;
|
||||
|
||||
private readonly List<Action> _converts = new List<Action>();
|
||||
private readonly List<Action> _converts = [ ];
|
||||
|
||||
public ControllerDefinition ControllerDef { get; }
|
||||
|
||||
|
@ -134,7 +129,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
{
|
||||
foreach (var button in buttons)
|
||||
{
|
||||
string name = $"P{player} {button.Name}";
|
||||
var name = $"P{player} {button.Name}";
|
||||
ControllerDef.BoolButtons.Add(name);
|
||||
var buttonFlag = button.Key;
|
||||
_converts.Add(() =>
|
||||
|
@ -207,25 +202,37 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
public GPGXControlConverter(LibGPGX.InputData input, string systemId, bool cdButtons)
|
||||
{
|
||||
Console.WriteLine("Genesis Controller report:");
|
||||
Console.WriteLine("GPGX Controller report:");
|
||||
foreach (var e in input.system)
|
||||
Console.WriteLine(" S:{0}", e);
|
||||
foreach (var e in input.dev)
|
||||
Console.WriteLine(" D:{0}", e);
|
||||
|
||||
int player = 1;
|
||||
var player = 1;
|
||||
|
||||
ControllerDef = new("GPGX Genesis Controller");
|
||||
ControllerDef = new(systemId switch
|
||||
{
|
||||
VSystemID.Raw.SMS or VSystemID.Raw.SG => "SMS Controller",
|
||||
VSystemID.Raw.GG => "GG Controller",
|
||||
VSystemID.Raw.GEN => "GPGX Genesis Controller", // GPGX in controller def name is more for backwards compat sake
|
||||
_ => throw new InvalidOperationException(),
|
||||
});
|
||||
|
||||
ControllerDef.BoolButtons.Add("Power");
|
||||
ControllerDef.BoolButtons.Add("Reset");
|
||||
|
||||
if (systemId is VSystemID.Raw.SMS or VSystemID.Raw.SG)
|
||||
{
|
||||
ControllerDef.BoolButtons.Add("Pause");
|
||||
}
|
||||
|
||||
if (cdButtons)
|
||||
{
|
||||
ControllerDef.BoolButtons.Add("Previous Disk");
|
||||
ControllerDef.BoolButtons.Add("Next Disk");
|
||||
}
|
||||
|
||||
for (int i = 0; i < LibGPGX.MAX_DEVICES; i++)
|
||||
for (var i = 0; i < LibGPGX.MAX_DEVICES; i++)
|
||||
{
|
||||
switch (input.dev[i])
|
||||
{
|
||||
|
@ -275,7 +282,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
// PICO isn't finished on the unmanaged side either
|
||||
throw new Exception("Sega PICO not implemented yet!");
|
||||
default:
|
||||
throw new Exception("Unknown Genesis control device! Something went wrong.");
|
||||
throw new Exception("Unknown GPGX control device! Something went wrong.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,6 +306,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
/// must be set for proper lightgun operation
|
||||
/// </summary>
|
||||
public int ScreenWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// must be set for proper lightgun operation
|
||||
/// </summary>
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
|
|||
using BizHawk.BizInvoke;
|
||||
|
||||
#pragma warning disable IDE1006
|
||||
#pragma warning disable CA1069
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||
{
|
||||
|
@ -49,12 +50,14 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
public short LowGain;
|
||||
public short MidGain;
|
||||
public short HighGain;
|
||||
|
||||
public enum FilterType : byte
|
||||
{
|
||||
None = 0,
|
||||
LowPass = 1,
|
||||
ThreeBand = 2
|
||||
}
|
||||
|
||||
public FilterType Filter;
|
||||
|
||||
public INPUT_SYSTEM InputSystemA;
|
||||
|
@ -68,6 +71,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
YM2413_MAME,
|
||||
YM2413_NUKED
|
||||
}
|
||||
|
||||
public SMSFMSoundChipType SMSFMSoundChip;
|
||||
|
||||
public enum GenesisFMSoundChipType : byte
|
||||
|
@ -78,6 +82,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
Nuked_YM2612,
|
||||
Nuked_YM3438
|
||||
}
|
||||
|
||||
public GenesisFMSoundChipType GenesisFMSoundChip;
|
||||
|
||||
public bool SpritesAlwaysOnTop;
|
||||
|
@ -91,6 +96,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
Horizontal = 1 << 1,
|
||||
All = Vertical | Horizontal,
|
||||
}
|
||||
|
||||
public OverscanType Overscan;
|
||||
public bool GGExtra;
|
||||
}
|
||||
|
@ -166,7 +172,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
DEVICE_ACTIVATOR = 0x0a,// Activator
|
||||
}
|
||||
|
||||
|
||||
public enum CDLog_AddrType
|
||||
{
|
||||
MDCART, RAM68k, RAMZ80, SRAM,
|
||||
|
@ -183,7 +188,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
DMASource = 0x40,
|
||||
}
|
||||
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void input_cb();
|
||||
|
||||
|
@ -276,22 +280,27 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public readonly INPUT_SYSTEM[] system = new INPUT_SYSTEM[2];
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICES)]
|
||||
public readonly INPUT_DEVICE[] dev = new INPUT_DEVICE[MAX_DEVICES];
|
||||
|
||||
/// <summary>
|
||||
/// digital inputs
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICES)]
|
||||
public readonly INPUT_KEYS[] pad = new INPUT_KEYS[MAX_DEVICES];
|
||||
|
||||
/// <summary>
|
||||
/// analog (x/y)
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DEVICES * 2)]
|
||||
public readonly short[] analog = new short[MAX_DEVICES * 2];
|
||||
|
||||
/// <summary>
|
||||
/// gun horizontal offset
|
||||
/// </summary>
|
||||
public int x_offset;
|
||||
|
||||
/// <summary>
|
||||
/// gun vertical offset
|
||||
/// </summary>
|
||||
|
@ -299,8 +308,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
|||
|
||||
public void ClearAllBools()
|
||||
{
|
||||
for (int i = 0; i < pad.Length; i++)
|
||||
for (var i = 0; i < pad.Length; i++)
|
||||
{
|
||||
pad[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue