private void UpdateVideo()
        {
            BufferWidth  = LibMAME.mame_lua_get_int(MAMELuaCommand.GetWidth);
            BufferHeight = LibMAME.mame_lua_get_int(MAMELuaCommand.GetHeight);
            int    expectedSize  = BufferWidth * BufferHeight;
            int    bytesPerPixel = 4;
            IntPtr ptr           = LibMAME.mame_lua_get_string(MAMELuaCommand.GetPixels, out var lengthInBytes);

            if (ptr == IntPtr.Zero)
            {
                Console.WriteLine("LibMAME ERROR: frame buffer pointer is null");
                return;
            }

            if (expectedSize * bytesPerPixel != lengthInBytes)
            {
                Console.WriteLine(
                    "LibMAME ERROR: frame buffer has wrong size\n" +
                    $"width:    { BufferWidth                  } pixels\n" +
                    $"height:   { BufferHeight                 } pixels\n" +
                    $"expected: { expectedSize * bytesPerPixel } bytes\n" +
                    $"received: { lengthInBytes                } bytes\n");
                return;
            }

            _frameBuffer = new int[expectedSize];
            Marshal.Copy(ptr, _frameBuffer, 0, expectedSize);

            if (!LibMAME.mame_lua_free_string(ptr))
            {
                Console.WriteLine("LibMAME ERROR: frame buffer wasn't freed");
            }
        }
Beispiel #2
0
        private void InitMemoryDomains()
        {
            var domains = new List <MemoryDomain>();

            _systemBusAddressShift = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceAddressShift);
            var dataWidth    = LibMAME.mame_lua_get_int(MAMELuaCommand.GetSpaceDataWidth) >> 3;          // mame returns in bits
            var size         = (long)LibMAME.mame_lua_get_double(MAMELuaCommand.GetSpaceAddressMask) + dataWidth;
            var endianString = MameGetString(MAMELuaCommand.GetSpaceEndianness);
            var deviceName   = MameGetString(MAMELuaCommand.GetMainCPUName);

            //var addrSize = (size * 2).ToString();

            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        = $"{ deviceName } : { read } : 0x{ firstOffset:X}-0x{ lastOffset:X}";

                    domains.Add(new MemoryDomainDelegate(name, lastOffset - firstOffset + 1, endian,
                                                         delegate(long addr)
                    {
                        return(_peek(addr, firstOffset, size));
                    },
                                                         read == "rom" ? (Action <long, byte>) null : delegate(long addr, byte val)
                    {
                        _poke(addr, val, firstOffset, size);
                    },
                                                         dataWidth));
                }
            }

            domains.Add(new MemoryDomainDelegate(deviceName + " : System Bus", size, endian,
                                                 delegate(long addr)
            {
                return(_peek(addr, 0, size));
            },
                                                 null, dataWidth));

            _memoryDomains = new MemoryDomainList(domains);
            (ServiceProvider as BasicServiceProvider).Register <IMemoryDomains>(_memoryDomains);
        }
Beispiel #3
0
        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();
        }
Beispiel #4
0
        private byte _peek(long addr, int firstOffset, long size)
        {
            if (addr < 0 || addr >= size)
            {
                throw new ArgumentOutOfRangeException();
            }

            if (!_memAccess)
            {
                _memAccess = true;
                _mamePeriodicComplete.WaitOne();
            }

            addr += firstOffset;

            var val = (byte)LibMAME.mame_lua_get_int($"{ MAMELuaCommand.GetSpace }:read_u8({ addr << _systemBusAddressShift })");

            _memoryAccessComplete.Set();

            return(val);
        }
Beispiel #5
0
        /*
         * 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();
            }
        }
Beispiel #6
0
        public void FetchDefaultGameSettings()
        {
            string DIPSwitchTags = MameGetString(MAMELuaCommand.GetDIPSwitchTags);

            string[] tags = DIPSwitchTags.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string tag in tags)
            {
                string   DIPSwitchFields = MameGetString(MAMELuaCommand.GetDIPSwitchFields(tag));
                string[] fieldNames      = DIPSwitchFields.Split(new char[] { '^' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string fieldName in fieldNames)
                {
                    DriverSetting setting = new DriverSetting()
                    {
                        Name         = fieldName,
                        GameName     = _gameShortName,
                        LuaCode      = MAMELuaCommand.InputField(tag, fieldName),
                        Type         = SettingType.DIPSWITCH,
                        DefaultValue = LibMAME.mame_lua_get_int(
                            $"return { MAMELuaCommand.InputField(tag, fieldName) }.defvalue").ToString()
                    };

                    string   DIPSwitchOptions = MameGetString(MAMELuaCommand.GetDIPSwitchOptions(tag, fieldName));
                    string[] options          = DIPSwitchOptions.Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (string option in options)
                    {
                        string[] opt = option.Split(new char[] { '~' }, StringSplitOptions.RemoveEmptyEntries);
                        setting.Options.Add(opt[0], opt[1]);
                    }

                    CurrentDriverSettings.Add(setting);
                }
            }
        }
Beispiel #7
0
        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);
        }