unsafe static void DrawNameTable(LibGPGX.VDPNameTable NT, ushort* vram, byte* tiles, int* pal, BmpView bv) { ushort* nametable = vram + NT.Baseaddr / 2; int tilew = NT.Width; int tileh = NT.Height; Size pixsize = new Size(tilew * 8, tileh * 8); bv.Size = pixsize; bv.ChangeBitmapSize(pixsize); var lockdata = bv.bmp.LockBits(new Rectangle(Point.Empty, pixsize), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int pitch = lockdata.Stride / sizeof(int); int* dest = (int*)lockdata.Scan0; for (int tiley = 0; tiley < tileh; tiley++) { for (int tilex = 0; tilex < tilew; tilex++) { ushort bgent = *nametable++; int palidx = bgent >> 9 & 0x30; int tileent = bgent & 0x1fff; // h and v flip are stored separately in cache DrawTile(dest, pitch, tiles + tileent * 64, pal + palidx); dest += 8; } dest -= 8 * tilew; dest += 8 * pitch; } bv.bmp.UnlockBits(lockdata); bv.Refresh(); }
public void SaveStateBinary(System.IO.BinaryWriter writer) { if (!LibGPGX.gpgx_state_save(savebuff, savebuff.Length)) { throw new Exception("gpgx_state_save() returned false"); } writer.Write(savebuff.Length); writer.Write(savebuff); // other variables writer.Write(Frame); writer.Write(LagCount); writer.Write(IsLagFrame); }
unsafe void update_video() { int gppitch, gpwidth, gpheight; IntPtr src = IntPtr.Zero; LibGPGX.gpgx_get_video(out gpwidth, out gpheight, out gppitch, ref src); vwidth = gpwidth; vheight = gpheight; if (_Settings.PadScreen320 && vwidth == 256) { vwidth = 320; } int xpad = (vwidth - gpwidth) / 2; int xpad2 = vwidth - gpwidth - xpad; if (vidbuff.Length < vwidth * vheight) { vidbuff = new int[vwidth * vheight]; } int rinc = (gppitch / 4) - gpwidth; fixed(int *pdst_ = &vidbuff[0]) { int *pdst = pdst_; int *psrc = (int *)src; for (int j = 0; j < gpheight; j++) { for (int i = 0; i < xpad; i++) { *pdst++ = unchecked ((int)0xff000000); } for (int i = 0; i < gpwidth; i++) { *pdst++ = *psrc++; // | unchecked((int)0xff000000); } for (int i = 0; i < xpad2; i++) { *pdst++ = unchecked ((int)0xff000000); } psrc += rinc; } } }
unsafe void SetMemoryDomains() { var mm = new List <MemoryDomain>(); for (int i = LibGPGX.MIN_MEM_DOMAIN; i <= LibGPGX.MAX_MEM_DOMAIN; i++) { IntPtr area = IntPtr.Zero; int size = 0; IntPtr pname = LibGPGX.gpgx_get_memdom(i, ref area, ref size); if (area == IntPtr.Zero || pname == IntPtr.Zero || size == 0) { continue; } string name = Marshal.PtrToStringAnsi(pname); if (name == "VRAM") { // vram pokes need to go through hook which invalidates cached tiles byte *p = (byte *)area; mm.Add(new MemoryDomain(name, size, MemoryDomain.Endian.Unknown, delegate(long addr) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } return(p[addr ^ 1]); }, delegate(long addr, byte val) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } LibGPGX.gpgx_poke_vram(((int)addr) ^ 1, val); }, byteSize: 2)); } else { var byteSize = name.Contains("Z80") ? 1 : 2; mm.Add(MemoryDomain.FromIntPtrSwap16(name, size, MemoryDomain.Endian.Big, area, writable: true, byteSize: byteSize)); } } MemoryDomains = new MemoryDomainList(mm); (ServiceProvider as BasicServiceProvider).Register <IMemoryDomains>(MemoryDomains); }
private void CDCallbackProc(int addr, LibGPGX.CDLog_AddrType addrtype, LibGPGX.CDLog_Flags flags) { //TODO - hard reset makes CDL go nuts. if (CDL == null) return; if (!CDL.Active) return; string key; switch (addrtype) { 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"); } CDL[key][addr] |= (byte)flags; }
// TODO: use render and rendersound public void FrameAdvance(bool render, bool rendersound = true) { if (Controller["Reset"]) { LibGPGX.gpgx_reset(false); } if (Controller["Power"]) { LibGPGX.gpgx_reset(true); } // do we really have to get each time? nothing has changed if (!LibGPGX.gpgx_get_control(input, inputsize)) { throw new Exception("gpgx_get_control() failed!"); } ControlConverter.ScreenWidth = vwidth; ControlConverter.ScreenHeight = vheight; ControlConverter.Convert(Controller, input); if (!LibGPGX.gpgx_put_control(input, inputsize)) { throw new Exception("gpgx_put_control() failed!"); } IsLagFrame = true; Frame++; drivelight = false; RefreshMemCallbacks(); LibGPGX.gpgx_advance(); update_video(); update_audio(); if (IsLagFrame) { LagCount++; } if (CD != null) { CoreComm.DriveLED = drivelight; } }
public Dictionary <string, int> GetCpuFlagsAndRegisters() { LibGPGX.RegisterInfo[] regs = new LibGPGX.RegisterInfo[LibGPGX.gpgx_getmaxnumregs()]; int n = LibGPGX.gpgx_getregs(regs); if (n > regs.Length) { throw new InvalidOperationException("A buffer overrun has occured!"); } var ret = new Dictionary <string, int>(); for (int i = 0; i < n; i++) { ret[Marshal.PtrToStringAnsi(regs[i].Name)] = regs[i].Value; } return(ret); }
public void LoadStateBinary(System.IO.BinaryReader reader) { int newlen = reader.ReadInt32(); if (newlen != savebuff.Length) { throw new Exception("Unexpected state size"); } reader.Read(savebuff, 0, savebuff.Length); if (!LibGPGX.gpgx_state_load(savebuff, savebuff.Length)) { throw new Exception("gpgx_state_load() returned false"); } // other variables Frame = reader.ReadInt32(); LagCount = reader.ReadInt32(); IsLagFrame = reader.ReadBoolean(); update_video(); }
public byte[] ReadSaveRam() { if (disposed) { return(DisposedSaveRam ?? new byte[0]); } else { int size = 0; IntPtr area = IntPtr.Zero; LibGPGX.gpgx_get_sram(ref area, ref size); if (size <= 0 || area == IntPtr.Zero) { return(new byte[0]); } LibGPGX.gpgx_sram_prepread(); byte[] ret = new byte[size]; Marshal.Copy(area, ret, 0, size); return(ret); } }
unsafe void SetMemoryDomains() { var mm = new List <MemoryDomain>(); for (int i = LibGPGX.MIN_MEM_DOMAIN; i <= LibGPGX.MAX_MEM_DOMAIN; i++) { IntPtr area = IntPtr.Zero; int size = 0; IntPtr pname = LibGPGX.gpgx_get_memdom(i, ref area, ref size); if (area == IntPtr.Zero || pname == IntPtr.Zero || size == 0) { continue; } string name = Marshal.PtrToStringAnsi(pname); byte * p = (byte *)area; mm.Add(new MemoryDomain(name, size, MemoryDomain.Endian.Unknown, delegate(int addr) { if (addr < 0 || addr >= size) { throw new ArgumentOutOfRangeException(); } return(p[addr]); }, delegate(int addr, byte val) { if (addr < 0 || addr >= size) { throw new ArgumentOutOfRangeException(); } p[addr] = val; })); } MemoryDomains = new MemoryDomainList(mm, 0); }
public void StoreSaveRam(byte[] data) { if (disposed) { throw new ObjectDisposedException(typeof(GPGX).ToString()); } else { int size = 0; IntPtr area = IntPtr.Zero; LibGPGX.gpgx_get_sram(ref area, ref size); if (size <= 0 || area == IntPtr.Zero) { return; } if (size != data.Length) { throw new Exception("Unexpected saveram size"); } Marshal.Copy(data, 0, area, size); LibGPGX.gpgx_sram_commitwrite(); } }
public bool PutSettings(GPGXSettings o) { _Settings = o; LibGPGX.gpgx_set_draw_mask(_Settings.GetDrawMask()); return(false); }
private unsafe void UpdateVideo() { int gppitch, gpwidth, gpheight; IntPtr src = IntPtr.Zero; LibGPGX.gpgx_get_video(out gpwidth, out gpheight, out gppitch, ref src); //in case we're receiving high vertical resolution video, we shall double the horizontal resolution to keep the same proportions //(concept pioneered for snes) bool dotDouble = (gpheight == 448); //todo: pal? bool lineDouble = false; vwidth = gpwidth; vheight = gpheight; if (_settings.AlwaysDoubleSize) { dotDouble = true; if (gpheight == 224 || gpheight == 240) { lineDouble = true; vheight *= 2; } } if (_settings.PadScreen320 && vwidth == 256) { vwidth = 320; } int xpad = (vwidth - gpwidth) / 2; int xpad2 = vwidth - gpwidth - xpad; if (dotDouble) { vwidth *= 2; } if (vidbuff.Length < vwidth * vheight) { vidbuff = new int[vwidth * vheight]; } int xskip = 1; if (dotDouble) { xskip = 2; } int lines = lineDouble ? 2: 1; for (int D = 0; D < xskip; D++) { int rinc = (gppitch / 4) - gpwidth; fixed(int *pdst_ = &vidbuff[0]) { int *pdst = pdst_ + D; int *psrc = (int *)src; for (int j = 0; j < gpheight; j++) { int *ppsrc = psrc; for (int L = 0; L < lines; L++) { int *pppsrc = ppsrc; for (int i = 0; i < xpad; i++) { *pdst = unchecked ((int)0xff000000); pdst += xskip; } for (int i = 0; i < gpwidth; i++) { *pdst = *pppsrc++; // | unchecked((int)0xff000000); pdst += xskip; } for (int i = 0; i < xpad2; i++) { *pdst = unchecked ((int)0xff000000); pdst += xskip; } psrc = pppsrc; } psrc += rinc; } } } }
public void UpdateVDPViewContext(LibGPGX.VDPView view) { LibGPGX.gpgx_get_vdp_view(view); }
public void Convert(IController source, LibGPGX.InputData target) { this.source = source; this.target = target; target.ClearAllBools(); foreach (var f in Converts) f(); this.source = null; this.target = null; }
public CName(string Name, LibGPGX.INPUT_KEYS Key) { this.Name = Name; this.Key = Key; }
public GPGXControlConverter(LibGPGX.InputData input) { Console.WriteLine("Genesis 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; ControllerDef = new ControllerDefinition(); ControllerDef.BoolButtons.Add("Power"); ControllerDef.BoolButtons.Add("Reset"); for (int i = 0; i < LibGPGX.MAX_DEVICES; i++) { switch (input.dev[i]) { case LibGPGX.INPUT_DEVICE.DEVICE_PAD3B: AddToController(i, player, Genesis3); player++; break; case LibGPGX.INPUT_DEVICE.DEVICE_PAD6B: AddToController(i, player, Genesis6); player++; break; case LibGPGX.INPUT_DEVICE.DEVICE_MOUSE: AddToController(i, player, Mouse); DoMouseAnalog(i, player); player++; break; case LibGPGX.INPUT_DEVICE.DEVICE_NONE: break; case LibGPGX.INPUT_DEVICE.DEVICE_LIGHTGUN: // supports menacers and justifiers AddToController(i, player, Lightgun); DoLightgunAnalog(i, player); player++; break; case LibGPGX.INPUT_DEVICE.DEVICE_PAD2B: case LibGPGX.INPUT_DEVICE.DEVICE_PADDLE: case LibGPGX.INPUT_DEVICE.DEVICE_SPORTSPAD: case LibGPGX.INPUT_DEVICE.DEVICE_TEREBI: throw new Exception("Master System only device? Something went wrong."); case LibGPGX.INPUT_DEVICE.DEVICE_ACTIVATOR: AddToController(i, player, Activator); player++; break; case LibGPGX.INPUT_DEVICE.DEVICE_XE_A1P: AddToController(i, player, XEA1P); DoXEA1PAnalog(i, player); player++; break; case LibGPGX.INPUT_DEVICE.DEVICE_PICO: // 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."); } } ControllerDef.Name = "GPGX Genesis Controller"; }
private unsafe void SetMemoryDomains() { var mm = new List <MemoryDomain>(); for (int i = LibGPGX.MIN_MEM_DOMAIN; i <= LibGPGX.MAX_MEM_DOMAIN; i++) { IntPtr area = IntPtr.Zero; int size = 0; IntPtr pname = LibGPGX.gpgx_get_memdom(i, ref area, ref size); if (area == IntPtr.Zero || pname == IntPtr.Zero || size == 0) { continue; } string name = Marshal.PtrToStringAnsi(pname); if (name == "VRAM") { // vram pokes need to go through hook which invalidates cached tiles byte *p = (byte *)area; mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Unknown, delegate(long addr) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } return(p[addr ^ 1]); }, delegate(long addr, byte val) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } LibGPGX.gpgx_poke_vram(((int)addr) ^ 1, val); }, wordSize: 2)); } else { // TODO: are the Z80 domains really Swap16 in the core? Check this //var byteSize = name.Contains("Z80") ? 1 : 2; mm.Add(MemoryDomain.FromIntPtrSwap16(name, size, MemoryDomain.Endian.Big, area, name != "MD CART" && name != "CD BOOT ROM")); } } var m68Bus = new MemoryDomainDelegate("M68K BUS", 0x1000000, MemoryDomain.Endian.Big, delegate(long addr) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } return(LibGPGX.gpgx_peek_m68k_bus(a)); }, delegate(long addr, byte val) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } LibGPGX.gpgx_write_m68k_bus(a, val); }, 2); mm.Add(m68Bus); var s68Bus = new MemoryDomainDelegate("S68K BUS", 0x1000000, MemoryDomain.Endian.Big, delegate(long addr) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } return(LibGPGX.gpgx_peek_s68k_bus(a)); }, delegate(long addr, byte val) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } LibGPGX.gpgx_write_s68k_bus(a, val); }, 2); if (IsSegaCD) { mm.Add(s68Bus); } MemoryDomains = new MemoryDomainList(mm); MemoryDomains.SystemBus = m68Bus; (ServiceProvider as BasicServiceProvider).Register <IMemoryDomains>(MemoryDomains); }
public GPGX(CoreComm comm, byte[] rom, DiscSystem.Disc CD, object settings, object syncSettings) { ServiceProvider = new BasicServiceProvider(this); // this can influence some things internally string romextension = "GEN"; // 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 if (rom != null && rom.Length > 32 * 1024 * 1024) { throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); } try { _syncSettings = (GPGXSyncSettings)syncSettings ?? new GPGXSyncSettings(); _settings = (GPGXSettings)settings ?? new GPGXSettings(); CoreComm = comm; if (AttachedCore != null) { AttachedCore.Dispose(); AttachedCore = null; } AttachedCore = this; LoadCallback = new LibGPGX.load_archive_cb(load_archive); this.romfile = rom; this.CD = CD; this.DiscSectorReader = new DiscSystem.DiscSectorReader(CD); LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; LibGPGX.INPUT_SYSTEM system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; switch (_syncSettings.ControlType) { case ControlType.None: default: break; case ControlType.Activator: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; break; case ControlType.Normal: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.OnePlayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.Xea1p: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P; break; case ControlType.Teamplayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; break; case ControlType.Wayplay: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; break; case ControlType.Mouse: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; // seems like mouse in port 1 would be supported, but not both at the same time system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE; break; } if (!LibGPGX.gpgx_init(romextension, LoadCallback, _syncSettings.UseSixButton, system_a, system_b, _syncSettings.Region, _settings.GetNativeSettings())) { throw new Exception("gpgx_init() failed"); } { int fpsnum = 60; int fpsden = 1; LibGPGX.gpgx_get_fps(ref fpsnum, ref fpsden); VsyncNumerator = fpsnum; VsyncDenominator = fpsden; Region = VsyncNumerator / VsyncDenominator > 55 ? DisplayType.NTSC : DisplayType.PAL; } // compute state size { byte[] tmp = new byte[LibGPGX.gpgx_state_max_size()]; int size = LibGPGX.gpgx_state_size(tmp, tmp.Length); if (size <= 0) { throw new Exception("Couldn't Determine GPGX internal state size!"); } _savebuff = new byte[size]; _savebuff2 = new byte[_savebuff.Length + 13]; Console.WriteLine("GPGX Internal State Size: {0}", size); } SetControllerDefinition(); // pull the default video size from the core UpdateVideoInitial(); SetMemoryDomains(); InputCallback = new LibGPGX.input_cb(input_callback); LibGPGX.gpgx_set_input_callback(InputCallback); if (CD != null) { DriveLightEnabled = true; } // process the non-init settings now PutSettings(_settings); //TODO - this hits performance, we need to make it controllable CDCallback = new LibGPGX.CDCallback(CDCallbackProc); InitMemCallbacks(); KillMemCallbacks(); ConnectTracer(); } catch { Dispose(); throw; } }
public void UpdateVDPViewContext(LibGPGX.VDPView view) { LibGPGX.gpgx_get_vdp_view(view); LibGPGX.gpgx_flush_vram(); // fully regenerate internal caches as needed }
public GPGX(CoreComm NextComm, byte[] romfile, DiscSystem.Disc CD, string romextension, object Settings, object SyncSettings) { // 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 //romfile = File.ReadAllBytes(@"D:\encodes\bizhawksrc\output\SANIC CD\PierSolar (E).bin"); if (romfile != null && romfile.Length > 16 * 1024 * 1024) { throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); } try { _SyncSettings = (GPGXSyncSettings)SyncSettings ?? new GPGXSyncSettings(); CoreComm = NextComm; if (AttachedCore != null) { AttachedCore.Dispose(); AttachedCore = null; } AttachedCore = this; LoadCallback = new LibGPGX.load_archive_cb(load_archive); this.romfile = romfile; this.CD = CD; LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; LibGPGX.INPUT_SYSTEM system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; switch (this._SyncSettings.ControlType) { case ControlType.None: default: break; case ControlType.Activator: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; break; case ControlType.Normal: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.OnePlayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.Xea1p: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P; break; case ControlType.Teamplayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; break; case ControlType.Wayplay: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; break; case ControlType.Mouse: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; // seems like mouse in port 1 would be supported, but not both at the same time system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE; break; } if (!LibGPGX.gpgx_init(romextension, LoadCallback, this._SyncSettings.UseSixButton, system_a, system_b, this._SyncSettings.Region)) { throw new Exception("gpgx_init() failed"); } { int fpsnum = 60; int fpsden = 1; LibGPGX.gpgx_get_fps(ref fpsnum, ref fpsden); CoreComm.VsyncNum = fpsnum; CoreComm.VsyncDen = fpsden; DisplayType = CoreComm.VsyncRate > 55 ? DisplayType.NTSC : DisplayType.PAL; } // compute state size { byte[] tmp = new byte[LibGPGX.gpgx_state_max_size()]; int size = LibGPGX.gpgx_state_size(tmp, tmp.Length); if (size <= 0) { throw new Exception("Couldn't Determine GPGX internal state size!"); } savebuff = new byte[size]; savebuff2 = new byte[savebuff.Length + 13]; Console.WriteLine("GPGX Internal State Size: {0}", size); } SetControllerDefinition(); // pull the default video size from the core update_video(); SetMemoryDomains(); InputCallback = new LibGPGX.input_cb(input_callback); LibGPGX.gpgx_set_input_callback(InputCallback); if (CD != null) { CoreComm.UsesDriveLed = true; } PutSettings(Settings ?? new GPGXSettings()); InitMemCallbacks(); KillMemCallbacks(); } catch { Dispose(); throw; } }
public GPGX(CoreComm comm, byte[] rom, DiscSystem.Disc CD, object Settings, object SyncSettings) { ServiceProvider = new BasicServiceProvider(this); // this can influence some things internally (autodetect romtype, etc) string romextension = "GEN"; // 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 if (rom != null && rom.Length > 32 * 1024 * 1024) { throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); } try { Elf = new ElfRunner(Path.Combine(comm.CoreFileProvider.DllPath(), "gpgx.elf"), 8 * 1024 * 1024, 36 * 1024 * 1024, 4 * 1024 * 1024); if (Elf.ShouldMonitor) { Core = BizInvoker.GetInvoker <LibGPGX>(Elf, Elf); } else { Core = BizInvoker.GetInvoker <LibGPGX>(Elf); } _syncSettings = (GPGXSyncSettings)SyncSettings ?? new GPGXSyncSettings(); _settings = (GPGXSettings)Settings ?? new GPGXSettings(); CoreComm = comm; LoadCallback = new LibGPGX.load_archive_cb(load_archive); this.romfile = rom; this.CD = CD; if (CD != null) { this.DiscSectorReader = new DiscSystem.DiscSectorReader(CD); cd_callback_handle = new LibGPGX.cd_read_cb(CDRead); Core.gpgx_set_cdd_callback(cd_callback_handle); } LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; LibGPGX.INPUT_SYSTEM system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; switch (_syncSettings.ControlType) { case ControlType.None: default: break; case ControlType.Activator: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; break; case ControlType.Normal: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.OnePlayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.Xea1p: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P; break; case ControlType.Teamplayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; break; case ControlType.Wayplay: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; break; case ControlType.Mouse: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; // seems like mouse in port 1 would be supported, but not both at the same time system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE; break; } if (!Core.gpgx_init(romextension, LoadCallback, _syncSettings.UseSixButton, system_a, system_b, _syncSettings.Region, _settings.GetNativeSettings())) { throw new Exception("gpgx_init() failed"); } { int fpsnum = 60; int fpsden = 1; Core.gpgx_get_fps(ref fpsnum, ref fpsden); CoreComm.VsyncNum = fpsnum; CoreComm.VsyncDen = fpsden; Region = CoreComm.VsyncRate > 55 ? DisplayType.NTSC : DisplayType.PAL; } // compute state size InitStateBuffers(); SetControllerDefinition(); // pull the default video size from the core UpdateVideoInitial(); SetMemoryDomains(); InputCallback = new LibGPGX.input_cb(input_callback); Core.gpgx_set_input_callback(InputCallback); if (CD != null) { DriveLightEnabled = true; } // process the non-init settings now PutSettings(_settings); //TODO - this hits performance, we need to make it controllable CDCallback = new LibGPGX.CDCallback(CDCallbackProc); InitMemCallbacks(); KillMemCallbacks(); Tracer = new GPGXTraceBuffer(this, MemoryDomains, this); (ServiceProvider as BasicServiceProvider).Register <ITraceable>(Tracer); Elf.Seal(); } catch { Dispose(); throw; } }
private void KillMemCallbacks() { LibGPGX.gpgx_set_mem_callback(null, null, null); }
public GPGX(CoreComm comm, byte[] rom, DiscSystem.Disc CD, object Settings, object SyncSettings) { ServiceProvider = new BasicServiceProvider(this); // this can influence some things internally (autodetect romtype, etc) string romextension = "GEN"; // 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 if (rom != null && rom.Length > 32 * 1024 * 1024) { throw new InvalidOperationException("ROM too big! Did you try to load a CD as a ROM?"); } try { Elf = new ElfRunner(Path.Combine(comm.CoreFileProvider.DllPath(), "gpgx.elf"), 8 * 1024 * 1024, 36 * 1024 * 1024, 4 * 1024 * 1024); if (Elf.ShouldMonitor) Core = BizInvoker.GetInvoker<LibGPGX>(Elf, Elf); else Core = BizInvoker.GetInvoker<LibGPGX>(Elf); _syncSettings = (GPGXSyncSettings)SyncSettings ?? new GPGXSyncSettings(); _settings = (GPGXSettings)Settings ?? new GPGXSettings(); CoreComm = comm; LoadCallback = new LibGPGX.load_archive_cb(load_archive); this.romfile = rom; this.CD = CD; if (CD != null) { this.DiscSectorReader = new DiscSystem.DiscSectorReader(CD); cd_callback_handle = new LibGPGX.cd_read_cb(CDRead); Core.gpgx_set_cdd_callback(cd_callback_handle); } LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; LibGPGX.INPUT_SYSTEM system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; switch (_syncSettings.ControlType) { case ControlType.None: default: break; case ControlType.Activator: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_ACTIVATOR; break; case ControlType.Normal: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.OnePlayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; break; case ControlType.Xea1p: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_XE_A1P; break; case ControlType.Teamplayer: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_TEAMPLAYER; break; case ControlType.Wayplay: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_WAYPLAY; break; case ControlType.Mouse: system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_MD_GAMEPAD; // seems like mouse in port 1 would be supported, but not both at the same time system_b = LibGPGX.INPUT_SYSTEM.SYSTEM_MOUSE; break; } if (!Core.gpgx_init(romextension, LoadCallback, _syncSettings.UseSixButton, system_a, system_b, _syncSettings.Region, _settings.GetNativeSettings())) throw new Exception("gpgx_init() failed"); { int fpsnum = 60; int fpsden = 1; Core.gpgx_get_fps(ref fpsnum, ref fpsden); CoreComm.VsyncNum = fpsnum; CoreComm.VsyncDen = fpsden; Region = CoreComm.VsyncRate > 55 ? DisplayType.NTSC : DisplayType.PAL; } // compute state size InitStateBuffers(); SetControllerDefinition(); // pull the default video size from the core UpdateVideoInitial(); SetMemoryDomains(); InputCallback = new LibGPGX.input_cb(input_callback); Core.gpgx_set_input_callback(InputCallback); if (CD != null) DriveLightEnabled = true; // process the non-init settings now PutSettings(_settings); //TODO - this hits performance, we need to make it controllable CDCallback = new LibGPGX.CDCallback(CDCallbackProc); InitMemCallbacks(); KillMemCallbacks(); Tracer = new GPGXTraceBuffer(this, MemoryDomains, this); (ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer); Elf.Seal(); } catch { Dispose(); throw; } }
private unsafe void SetMemoryDomains() { var mm = new List <MemoryDomain>(); for (int i = LibGPGX.MIN_MEM_DOMAIN; i <= LibGPGX.MAX_MEM_DOMAIN; i++) { IntPtr area = IntPtr.Zero; int size = 0; IntPtr pname = LibGPGX.gpgx_get_memdom(i, ref area, ref size); if (area == IntPtr.Zero || pname == IntPtr.Zero || size == 0) { continue; } string name = Marshal.PtrToStringAnsi(pname); if (name == "VRAM") { // vram pokes need to go through hook which invalidates cached tiles byte *p = (byte *)area; mm.Add(new MemoryDomainDelegate(name, size, MemoryDomain.Endian.Unknown, delegate(long addr) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } return(p[addr ^ 1]); }, delegate(long addr, byte val) { if (addr < 0 || addr >= 65536) { throw new ArgumentOutOfRangeException(); } LibGPGX.gpgx_poke_vram(((int)addr) ^ 1, val); }, wordSize: 2)); } else { // TODO: are the Z80 domains really Swap16 in the core? Check this //var byteSize = name.Contains("Z80") ? 1 : 2; mm.Add(new MemoryDomainIntPtrSwap16(name, MemoryDomain.Endian.Big, area, size, name != "MD CART" && name != "CD BOOT ROM")); } } //it's gross for this not to be the full 32bits. //Uhh I mean, I guess the bus is physically smaller.. but the cpu's view of it is larger... //So... I guess no matter what we do, some badness will propagate. This is probably least bad. //Anyway, the disassembler, for instance, must have been masked down to size, since code can run from FFxxxxxxxx... var m68Bus = new MemoryDomainDelegate("M68K BUS", 0x1000000, MemoryDomain.Endian.Big, delegate(long addr) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } return(LibGPGX.gpgx_peek_m68k_bus(a)); }, delegate(long addr, byte val) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } LibGPGX.gpgx_write_m68k_bus(a, val); }, 2); mm.Add(m68Bus); var s68Bus = new MemoryDomainDelegate("S68K BUS", 0x1000000, MemoryDomain.Endian.Big, delegate(long addr) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } return(LibGPGX.gpgx_peek_s68k_bus(a)); }, delegate(long addr, byte val) { var a = (uint)addr; if (a >= 0x1000000) { throw new ArgumentOutOfRangeException(); } LibGPGX.gpgx_write_s68k_bus(a, val); }, 2); if (IsSegaCD) { mm.Add(s68Bus); } MemoryDomains = new MemoryDomainList(mm); MemoryDomains.SystemBus = m68Bus; (ServiceProvider as BasicServiceProvider).Register <IMemoryDomains>(MemoryDomains); }