/* * FrameAdvance() and MAME * * MAME fires the periodic callback on every video and debugger update, * which happens every VBlank and also repeatedly at certain time * intervals while paused. Since MAME's luaengine runs in a separate * thread, it's only safe to update everything we need per frame during * this callback, when it's explicitly waiting for further lua commands. * * If we disable throttling and pass -update_in_pause, there will be no * delay between video updates. This allows to run at full speed while * frame-stepping. * * MAME only captures new frame data once per VBlank, while unpaused. * But it doesn't have an exclusive VBlank callback we could attach to. * It has a LUA_ON_FRAME_DONE callback, but that fires even more * frequently and updates all sorts of other non-video stuff, and we * need none of that here. * * So we filter out all the calls that happen while paused (non-VBlank * updates). Then, when Hawk asks us to advance a frame, we virtually * unpause and declare the new frame unfinished. This informs MAME that * it should advance one frame internally. Hawk starts waiting for the * MAME thread to complete the request. * * After MAME's done advancing, it fires the periodic callback again. * That's when we update everything and declare the new frame finished, * filtering out any further updates again. Then we allow Hawk to * complete frame-advancing. */ private void MAMEPeriodicCallback() { if (_exiting) { LibMAME.mame_lua_execute(MAMELuaCommand.Exit); _exiting = false; } if (_memAccess) { _mamePeriodicComplete.Set(); _memoryAccessComplete.WaitOne(); return; } //int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber); if (!_paused) { LibMAME.mame_lua_execute(MAMELuaCommand.Step); _frameDone = false; _paused = true; } else if (!_frameDone) { Update(); _frameDone = true; _mameFrameComplete.Set(); } }
private void MAMEBootCallback() { LibMAME.mame_lua_execute(MAMELuaCommand.Pause); CheckVersions(); GetInputFields(); Update(); MAMEStartupComplete.Set(); }
private void SendInput() { foreach (var fieldPort in _fieldsPorts) { LibMAME.mame_lua_execute( "manager:machine():ioport()" + $".ports [\"{ fieldPort.Value }\"]" + $".fields [\"{ fieldPort.Key }\"]" + $":set_value({ (_controller.IsPressed(fieldPort.Key) ? 1 : 0) })"); } }
public void OverrideGameSettings() { foreach (KeyValuePair <string, string> setting in _syncSettings.DriverSettings) { DriverSetting s = CurrentDriverSettings.SingleOrDefault(s => s.LookupKey == setting.Key); if (s != null && s.Type == SettingType.DIPSWITCH) { LibMAME.mame_lua_execute($"{ s.LuaCode }.user_value = { setting.Value }"); } } }
private void MAMEBootCallback() { LibMAME.mame_lua_execute(MAMELuaCommand.Pause); CheckVersions(); GetInputFields(); Update(); UpdateGameName(); InitMemoryDomains(); _mameStartupComplete.Set(); }
public void LoadStateBinary(BinaryReader reader) { int length = reader.ReadInt32(); if (length != _mameSaveBuffer.Length) { throw new InvalidOperationException("Savestate buffer size mismatch!"); } reader.Read(_mameSaveBuffer, 0, _mameSaveBuffer.Length); Frame = reader.ReadInt32(); LibMAME.mame_lua_execute($"manager:machine():buffer_load({ _mameSaveBuffer })"); }
/* * FrameAdvance() and MAME * * MAME fires the periodic callback on every video and debugger update, * which happens every VBlank and also repeatedly at certain time * intervals while paused. Since MAME's luaengine runs in a separate * thread, it's only safe to update everything we need per frame during * this callback, when it's explicitly waiting for further lua commands. * * If we disable throttling and pass -update_in_pause, there will be no * delay between video updates. This allows to run at full speed while * frame-stepping. * * MAME only captures new frame data once per VBlank, while unpaused. * But it doesn't have an exclusive VBlank callback we could attach to. * It has a LUA_ON_FRAME_DONE callback, but that fires even more * frequently and updates all sorts of other non-video stuff, and we * need none of that here. * * So we filter out all the calls that happen while paused (non-VBlank * updates). Then, when Hawk asks us to advance a frame, we virtually * unpause and declare the new frame unfinished. This informs MAME that * it should advance one frame internally. Hawk starts waiting for the * MAME thread to complete the request. * * After MAME's done advancing, it fires the periodic callback again. * That's when we update everything and declare the new frame finished, * filtering out any further updates again. Then we allow Hawk to * complete frame-advancing. */ private void MAMEPeriodicCallback() { if (_exiting) { LibMAME.mame_lua_execute(MAMELuaCommand.Exit); _exiting = false; } if (_memAccess) { _mamePeriodicComplete.Set(); _memoryAccessComplete.WaitOne(); return; } //int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber); if (!_paused) { LibMAME.mame_lua_execute(MAMELuaCommand.Step); _frameDone = false; _paused = true; } else if (!_frameDone) { /* * IntPtr ptr = LibMAME.mame_lua_get_string(MAMELuaCommand.GetSpaceBuffer, out var lengthInBytes); * * if (ptr == IntPtr.Zero) * { * Console.WriteLine("LibMAME ERROR: audio buffer pointer is null"); * return; * } * * //byte[] buf = new byte[lengthInBytes]; * //Marshal.Copy(ptr, buf, 0, lengthInBytes); * * if (!LibMAME.mame_lua_free_string(ptr)) * { * Console.WriteLine("LibMAME ERROR: audio buffer wasn't freed"); * } */ Update(); _frameDone = true; _mameFrameComplete.Set(); } }
private void MAMEBootCallback() { LibMAME.mame_lua_execute(MAMELuaCommand.Pause); CheckVersions(); GetInputFields(); Update(); UpdateGameName(); InitMemoryDomains(); IntPtr ptr = LibMAME.mame_lua_get_string("return manager:machine():buffer_save()", out var lengthInBytes); _mameSaveBuffer = new byte[lengthInBytes]; _hawkSaveBuffer = new byte[lengthInBytes + 4 + 4]; _mameStartupComplete.Set(); }
private void _poke(long addr, byte val, int firstOffset, long size) { if (addr < 0 || addr >= size) { throw new ArgumentOutOfRangeException(); } if (!_memAccess) { _memAccess = true; _mamePeriodicComplete.WaitOne(); } addr += firstOffset; LibMAME.mame_lua_execute($"{ MAMELuaCommand.GetSpace }:write_u8({ addr << _systemBusAddressShift }, { val })"); _memoryAccessComplete.Set(); }
private void MAMEBootCallback() { LibMAME.mame_lua_execute(MAMELuaCommand.Pause); CheckVersions(); GetInputFields(); UpdateVideo(); UpdateAspect(); UpdateFramerate(); UpdateGameName(); InitMemoryDomains(); int length = LibMAME.mame_lua_get_int("return string.len(manager:machine():buffer_save())"); _mameSaveBuffer = new byte[length]; _hawkSaveBuffer = new byte[length + 4 + 4 + 4 + 1]; _mameStartupComplete.Set(); }
/* * FrameAdvance() and MAME * * MAME fires the periodic callback on every video and debugger update, * which happens every VBlank and also repeatedly at certain time * intervals while paused. Since MAME's luaengine runs in a separate * thread, it's only safe to update everything we need per frame during * this callback, when it's explicitly waiting for further lua commands. * * If we disable throttling and pass -update_in_pause, there will be no * delay between video updates. This allows to run at full speed while * frame-stepping. * * MAME only captures new frame data once per VBlank, while unpaused. * But it doesn't have an exclusive VBlank callback we could attach to. * It has a LUA_ON_FRAME_DONE callback, but that fires even more * frequently and updates all sorts of other non-video stuff, and we * need none of that here. * * So we filter out all the calls that happen while paused (non-VBlank * updates). Then, when Hawk asks us to advance a frame, we virtually * unpause and declare the new frame unfinished. This informs MAME that * it should advance one frame internally. Hawk starts waiting for the * MAME thread to complete the request. * * After MAME's done advancing, it fires the periodic callback again. * That's when we update everything and declare the new frame finished, * filtering out any further updates again. Then we allow Hawk to * complete frame-advancing. */ private void MAMEPeriodicCallback() { if (exiting) { LibMAME.mame_lua_execute(MAMELuaCommand.Exit); exiting = false; } int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber); if (!paused) { LibMAME.mame_lua_execute(MAMELuaCommand.Step); frameDone = false; paused = true; } else if (!frameDone) { Update(); frameDone = true; MAMEFrameComplete.Set(); } }
private void MAMEPeriodicCallback() { if (_exiting) { LibMAME.mame_lua_execute(MAMELuaCommand.Exit); _exiting = false; } for (; _memAccess;) { _mamePeriodicComplete.Set(); _memoryAccessComplete.WaitOne(); if (!_frameDone && !_paused || _exiting) // FrameAdvance() has been requested { _memAccess = false; return; } } //int MAMEFrame = LibMAME.mame_lua_get_int(MAMELuaCommand.GetFrameNumber); if (!_paused) { SendInput(); LibMAME.mame_lua_execute(MAMELuaCommand.Step); _frameDone = false; _paused = true; } else if (!_frameDone) { UpdateVideo(); _frameDone = true; _mameFrameComplete.Set(); } }
private void InitMemoryDomains() { var domains = new List <MemoryDomain>(); _systemBusAddressShift = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceAddressShift); var size = (long)LibMAME.mame_lua_get_double(MAMELuaCommand.GetSpaceAddressMask) + 1; var dataWidth = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceDataWidth) >> 3; // mame returns in bits var endianString = MameGetString(MAMELuaCommand.GetSpaceEndianness); MemoryDomain.Endian endian = MemoryDomain.Endian.Unknown; if (endianString == "little") { endian = MemoryDomain.Endian.Little; } else if (endianString == "big") { endian = MemoryDomain.Endian.Big; } var mapCount = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceMapCount); for (int i = 1; i <= mapCount; i++) { var read = MameGetString($"return { MAMELuaCommand.SpaceMap }[{ i }].readtype"); var write = MameGetString($"return { MAMELuaCommand.SpaceMap }[{ i }].writetype"); if (read == "ram" && write == "ram" /* || read == "rom" */) { var firstOffset = LibMAME.mame_lua_get_int($"return { MAMELuaCommand.SpaceMap }[{ i }].offset"); var lastOffset = LibMAME.mame_lua_get_int($"return { MAMELuaCommand.SpaceMap }[{ i }].endoff"); var name = $"{ read.ToUpper() } { firstOffset:X}-{ lastOffset:X}"; domains.Add(new MemoryDomainDelegate(name, lastOffset - firstOffset + 1, endian, delegate(long addr) { if (addr < 0 || addr >= size) { throw new ArgumentOutOfRangeException(); } _memAccess = true; _mamePeriodicComplete.WaitOne(); addr += firstOffset; var val = (byte)LibMAME.mame_lua_get_int($"{ MAMELuaCommand.GetSpace }:read_u8({ addr << _systemBusAddressShift })"); _memoryAccessComplete.Set(); _memAccess = false; return(val); }, read == "rom" ? (Action <long, byte>) null : delegate(long addr, byte val) { if (addr < 0 || addr >= size) { throw new ArgumentOutOfRangeException(); } _memAccess = true; _mamePeriodicComplete.WaitOne(); addr += firstOffset; LibMAME.mame_lua_execute($"{ MAMELuaCommand.GetSpace }:write_u8({ addr << _systemBusAddressShift }, { val })"); _memoryAccessComplete.Set(); _memAccess = false; }, dataWidth)); } } domains.Add(new MemoryDomainDelegate("System Bus", size, endian, delegate(long addr) { if (addr < 0 || addr >= size) { throw new ArgumentOutOfRangeException(); } _memAccess = true; _mamePeriodicComplete.WaitOne(); var val = (byte)LibMAME.mame_lua_get_int($"{ MAMELuaCommand.GetSpace }:read_u8({ addr << _systemBusAddressShift })"); _memoryAccessComplete.Set(); _memAccess = false; return(val); }, null, dataWidth)); _memoryDomains = new MemoryDomainList(domains); (ServiceProvider as BasicServiceProvider).Register <IMemoryDomains>(_memoryDomains); }