![]() |
![]()
| ![]() |
![]()
NAMEMAME - MAME Documentation [image: MAME] [image] NOTE: This documentation is a work in progress. You can track
the status of these topics through MAME's issue tracker. Learn how you
can contribute.
WHAT IS MAMEMAME is a multi-purpose emulation framework. MAME’s purpose is to preserve decades of software history. As electronic technology continues to rush forward, MAME prevents this important “vintage” software from being lost and forgotten. This is achieved by documenting the hardware and how it functions. The source code to MAME serves as this documentation. The fact that the software is usable serves primarily to validate the accuracy of the documentation (how else can you prove that you have recreated the hardware faithfully?). MAME, originally the Multiple Arcade Machine Emulator, absorbed sister-projects, including MESS (Multi-Emulator Super System) and AGEMAME (Arcade Gambling Extensions for MAME), so MAME now documents a wide variety of (mostly vintage) computers, video game consoles, calculators and gambling machines, in addition to the arcade video games that were its initial focus. MAME® Copyright © 1997-2025 MAMEdev and contributors MAME is a registered trademark of Gregory Ember I. PurposeMAME’s main purpose is to be a reference to the inner workings of the emulated machines. This is done both for educational purposes and for preservation purposes, in order to prevent historical software from disappearing forever once the hardware it runs on stops working. Of course, in order to preserve the software and demonstrate that the emulated behavior matches the original, one must also be able to actually use the software. This is considered a nice side effect, and is not MAME’s primary focus. It is not our intention to infringe on any copyrights or patents on the original software and systems. All of MAME’s source code is either our own or freely available. To operate, the emulator requires images of the original ROMs, CDs, hard disks or other media from the machines, which must be provided by the user. No portions of the original software are included in the MAME executable. II. CostMAME is made available at no cost. Its source code is freely available. The project as whole is distributed under the terms of the GNU General Public License, version 2 or later (GPL-2.0+), but most of code, including core functionality, is also available under the terms of the more permissive 3-clause BSD license (BSD-3-clause). III. Software Image FilesROM, CD, hard disk and other media images are all copyrighted material. They may not be lawfully distributed without the explicit permission of the copyright holder(s). They are not “abandonware”, nor has copyright expired on any of the software supported by MAME. MAME is not intended to be used as a tool for mass copyright infringement. Therefore, it is strongly against the authors’ wishes to sell, advertise, or link to resources that provide illegal copies of ROM, CD, hard disk or other media images. IV. Derivative WorksBecause the name MAME is trademarked, you must abide by the rules set out for trademark usage if you wish to use “MAME” as part of the name your derivative work. In general, this means you must request permission, which requires that you follow the guidelines above. The version number of any derivative work should reflect the version number of the MAME release from which it was derived. V. Official Contact InformationFor questions regarding the MAME license, trademark, or other usage, see https://www.mamedev.org/legal.html HEALTH WARNINGSEpilepsy WarningA very small percentage of individuals may experience epileptic seizures when exposed to certain light patterns or flashing lights. Exposure to certain patterns or backgrounds on a television screen or computer monitor, or while playing video games may induce an epileptic seizure in these individuals. Certain conditions may induce previously undetected epileptic symptoms even in persons who have no history of prior seizures or epilepsy. These conditions can include emulation accuracy or inaccuracy, computer performance at the time of running MAME, video card drivers, your monitor, and a lot of other factors. If you, or anyone in your family, has an epileptic condition, consult your physician prior to using MAME. If you experience any of the following while using MAME, IMMEDIATELY discontinue use and consult your physician before resuming use of MAME.
GETTING MAME PREPAREDThis section covers initial preparation work needed to use MAME, including downloading MAME, compiling MAME from source, and configuring MAME. An Introduction to MAMEMAME, formerly an acronym which stood for Multi Arcade Machine Emulator, documents and reproduces through emulation the inner components of arcade machines, computers, consoles, chess computers, calculators, and many other types of electronic amusement machines. As a nice side-effect, MAME allows to use on a modern PC those programs and games which were originally developed for the emulated machines. At one point there were actually two separate projects, MAME and MESS. MAME covered arcade video games, while MESS covered home and business systems. They are now merged into the one MAME. MAME is written in C++ and can currently emulate over 32,000 individual systems from the last five decades. Purpose of MAMEThe primary purpose of MAME is to preserve decades of arcade, computer, and console history. As technology continues to rush forward, MAME prevents these important “vintage” systems from being lost and forgotten. Systems Emulated by MAMEThe Arcade Database contains a complete list of the systems currently emulated. As you will notice, being supported does not always mean that the status of the emulation is perfect. You may want
Alternatively, you can simply see the status by yourself, launching the system emulation and taking a look at the red or yellow warning screen which appears before the emulation starts, if any. Notice that if you have information which can help to improve the emulation of a supported system, or if you can directly contribute fixes and/or addition to the current source, you can do any of the following:
Supported OSThe current source code can be directly compiled under all the main operating systems: Microsoft Windows (both with DirectX/BGFX native support or with SDL support), Linux, FreeBSD, and macOS. System RequirementsMAME is written in C++, and has been ported to numerous platforms. Over time, as computer hardware has evolved, the MAME code has evolved as well to take advantage of the greater processing power and hardware capabilities offered. The official MAME binaries are compiled and designed to run on a standard Windows-based system. The minimum requirements are:
Of course, the minimum requirements are just that: minimal. You may not get optimal performance from such a system, but MAME should run. Modern versions of MAME require more power than older versions, so if you have a less-capable PC, you may find that using an older version of MAME may get you better performance, at the cost of greatly lowered accuracy and fewer supported systems. MAME will take advantage of 3D hardware for compositing artwork and scaling displayed software to full screen. To make use of this, you should have at least a semi-modern computer with semi-modern 3D hardware made within the last five to ten years. HLSL or GLSL special effects such as CRT simulation will put a very heavy load on your video card, especially at higher resolutions. You will need a fairly powerful modern video card, and the load on your video card goes up exponentially as your resolution increases. If HLSL or GLSL are too intensive, try reducing your output resolution. Keep in mind that even on the fastest computers available, MAME is still incapable of playing some systems at full speed. The goal of the project isn’t to make all system run speedy on your system; the goal is to document the hardware and reproduce the behavior of the hardware as faithfully as possible. BIOS Dumps and SoftwareMost of the systems emulated by MAME requires a dump of the internal chips of the original system. These can be obtained by extracting the data from an original unit, or finding them (at your own risk) on various place on the Internet. Being copyrighted material, MAME does not come with any of these. Also, you may want to find some software to be run on the emulated machine where it does not have internal software (e.g. some computers will need a disk to boot to an operating system). Again, Google and other search engines are your best friends. MAME does not provide any software in the MAME package to be run on the emulated machines because it is very often (almost always, in the case of console software) protected by copyright. The MAME team has been permitted to redistribute some old software, which can be found in the ROMS section of the MAME site. Installing MAMEMicrosoft WindowsYou simply have to download the latest binary archive available from http://www.mamedev.org and to extract its content to a folder. You will end up with many files (below you will find explanations about some of these), and in particular mame.exe. This is a command line program. The installation procedure ends here. Easy, isn’t it? Other Operating SystemsIn this case, you can either look for pre-compiled (SDL)MAME binaries (e.g. in the repositories of your favorite Linux distro) which should simply extract all the needed files in a folder you choose, or compile the source code by yourself. In the latter case, see our section on compiling MAME. Compiling MAME
All Platforms
Putting all of these together, we get a couple of examples: Rebuilding MAME on a dual-core (e.g. i3 or laptop i5) machine: make -j3 Rebuilding MAME for just the Pac-Man and Galaxian families of systems, with tools, on a quad-core (e.g. i5 or i7) machine: make SUBTARGET=pacem SOURCES=src/mame/pacman,src/mame/galaxian TOOLS=1 REGENIE=1 -j5 Rebuilding MAME for just the Apple II systems, compiling up to six sources in parallel: make SUBTARGET=appulator SOURCES=apple/apple2.cpp,apple/apple2e.cpp,apple/apple2gs.cpp REGENIE=1 -j6 Microsoft WindowsMAME for Windows is built using the MSYS2 environment. You will need Windows 7 or later and a reasonably up-to-date MSYS2 installation. We strongly recommend building MAME on a 64-bit system. Instructions may need to be adjusted for 32-bit systems. Building for 64-bit ARM (AArch64) requires a 64-bit ARM system running Windows 11 or later.
Using a standard MSYS2 installationYou may also build MAME using a standard MSYS2 installation and adding the tools needed for building MAME. These instructions assume you have some familiarity with MSYS2 and the pacman package manager.
The additional packages you’ll need depend on the CPU architecture you’re building for. 64-bit x86-64
32-bit x86
64-bit ARM (AArch64)
For example you could use these commands to ensure you have the packages you need to compile MAME, omitting the ones for configurations you don’t plan to build for or combining multiple pacman commands to install more packages at once: pacman -Syu pacman -S curl git make pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-python pacman -S mingw-w64-x86_64-llvm mingw-w64-x86_64-libc++ mingw-w64-x86_64-lld pacman -S mingw-w64-x86_64-SDL2 mingw-w64-x86_64-SDL2_ttf pacman -S mingw-w64-x86_64-qt5 pacman -S mingw-w64-i686-gcc mingw-w64-i686-python pacman -S mingw-w64-i686-llvm mingw-w64-i686-libc++ mingw-w64-i686-lld pacman -S mingw-w64-i686-SDL2 mingw-w64-i686-SDL2_ttf pacman -S mingw-w64-i686-qt5 pacman -S mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-python mingw-w64-clang-aarch64-gcc-compat pacman -S mingw-w64-clang-aarch64-lld mingw-w64-clang-aarch64-llvm mingw-w64-clang-aarch64-libc++ pacman -S mingw-w64-clang-aarch64-SDL2 mingw-w64-clang-aarch64-SDL2_ttf pacman -S mingw-w64-clang-aarch64-qt5 You could use these commands to install the current version of the mame-essentials package and add the MAME package repository to your pacman configuration: curl -O "https://repo.mamedev.org/x86_64/mame-essentials-1.0.6-1-x86_64.pkg.tar.xz" pacman -U mame-essentials-1.0.6-1-x86_64.pkg.tar.xz echo -e '\n[mame]\nInclude = /etc/pacman.d/mirrorlist.mame\nSigLevel = Never' >> /etc/pacman.conf Building with Microsoft Visual Studio
Some notes about the MSYS2 environmentMSYS2 uses the pacman tool from Arch Linux for package management. There is a page on the Arch Linux wiki with helpful information on using the pacman package management tool. The MSYS2 environment includes two kinds of tools: MSYS2 tools designed to work in a UNIX-like environment on top of Windows, and MinGW tools designed to work in a more Windows-like environment. The MSYS2 tools are installed in /usr/bin while the MinGW tools are installed in /ming64/bin, /mingw32/bin and/or /clangarm64/bin (relative to the MSYS2 installation directory). MSYS2 tools work best in an MSYS2 terminal, while MinGW tools work best in a Microsoft command prompt. The most obvious symptom of this is that arrow keys don’t work in interactive programs if you run them in the wrong kind of terminal. If you run MinGW gdb or python from an MSYS2 terminal window, command history won’t work and it may not be possible to interrupt an attached program with gdb. Similarly it may be very difficult to edit using MSYS2 vim in a Microsoft command prompt window. MAME is built using the MinGW compilers, so the MinGW directories are included earlier in the PATH environment variable for the build environments. If you want to use an interactive MSYS2 program from an MSYS2 shell, you may need to type the absolute path to avoid using the MinGW equivalent instead. MSYS2 gdb may have issues debugging MinGW programs like MAME. You may get better results by installing the MinGW version of gdb and running it from a Microsoft command prompt window to debug MAME. GNU make supports both POSIX-style shells (e.g. bash) and the Microsoft cmd.exe shell. One issue to be aware of when using the cmd.exe shell is that the copy command doesn’t provide a useful exit status, so file copy tasks can fail silently. This may cause your build to appear to succeed while producing incorrect results. It is not possible to cross-compile a 32-bit version of MAME using 64-bit MinGW tools on Windows, the 32-bit MinGW tools must be used. This causes issues due to the size of MAME. It’s impossible to make a 32-bit build with full local variable symbols. GCC may run out of memory, and certain source files may exceed the limit of 32,768 sections imposed by the PE/COFF object file format. A complete build of MAME including line number symbols exceeds the size limit imposed by the PE file format and cannot be run. Workarounds include including only a subset of the systems supported by MAME or extracting symbols to a separate file and stripping excess symbols from the MAME executable. Fedora LinuxYou’ll need a few prerequisites from your Linux distribution. Make sure you get SDL 2 version 2.0.14 or later as earlier versions lack required functionality: sudo dnf install gcc gcc-c++ SDL2-devel SDL2_ttf-devel libXi-devel libXinerama-devel qt5-qtbase-devel qt5-qttools expat-devel fontconfig-devel alsa-lib-devel pulseaudio-libs-devel If you want to use the more efficient LLVM tools for archiving static libraries and linking, you’ll need to install the corresponding packages: sudo dnf install lld llvm Compilation is exactly as described above in All Platforms. To build the HTML user/developer documentation, you’ll need Sphinx, as well as the theme and the SVG converter: sudo dnf install python3-sphinx python3-sphinx_rtd_theme python3-sphinxcontrib-rsvgconverter The HTML documentation can be built with this command: make -C docs SPHINXBUILD=sphinx-build-3 html Debian and Ubuntu (including Raspberry Pi and ODROID devices)You’ll need a few prerequisites from your Linux distribution. Make sure you get SDL 2 version 2.0.14 or later as earlier versions lack required functionality: sudo apt-get install git build-essential python3 libsdl2-dev libsdl2-ttf-dev libfontconfig-dev libpulse-dev qtbase5-dev qtbase5-dev-tools qtchooser qt5-qmake Compilation is exactly as described above in All Platforms. Note the Ubuntu Linux modifies GCC to enable the GNU C Library “fortify source” feature by default, which may cause issues compiling MAME (see Known Issues). Arch LinuxYou’ll need a few prerequisites from your distro: sudo pacman -S base-devel git sdl2_ttf python libxinerama libpulse alsa-lib qt5-base Compilation is exactly as described above in All Platforms. Apple macOSYou’ll need a few prerequisites to get started. Make sure you’re on macOS 11.0 Big Sur or later. You will need SDL 2 version 2.0.14 or later. You’ll also need to install Python 3 – it’s currently included with the Xcode command line tools, but you can also install a stand-alone version or get it via the Homebrew package manager.
Next you’ll need to get SDL 2 installed.
If you don’t already have it, get Python 3 set up:
Finally to begin compiling, use Terminal to navigate to where you have the MAME source tree (cd command) and follow the normal compilation instructions from above in All Platforms. Emscripten Javascript and HTMLFirst, download and install Emscripten 3.1.35 or later by following the instructions at the official site. Once Emscripten has been installed, it should be possible to compile MAME out-of-the-box using Emscripten’s emmake tool. Because a full MAME compile is too large to load into a web browser at once, you will want to use the SOURCES parameter to compile only a subset of the project, e.g. (in the MAME directory): emmake make SUBTARGET=pacmantest SOURCES=src/mame/pacman/pacman.cpp The SOURCES parameter should have the path to at least one driver .cpp file. The make process will attempt to locate and include all dependencies necessary to produce a complete build including the specified driver(s). However, sometimes it is necessary to manually specify additional files (using commas) if this process misses something. e.g. emmake make SUBTARGET=apple2e SOURCES=src/mame/apple/apple2e.cpp,src/devices/machine/applefdc.cpp The value of the SUBTARGET parameter serves only to differentiate multiple builds and need not be set to any specific value. Emscripten supports compiling to WebAssembly with a JavaScript loader instead of all-JavaScript, and in later versions this is actually the default. To force WebAssembly on or off, add WEBASSEMBLY=1 or WEBASSEMBLY=0 to the make command line, respectively. Other make parameters can also be used, e.g. -j for multithreaded compilation as described earlier. When the compilation reaches the emcc phase, you may see a number of "unresolved symbol" warnings. At the moment, this is expected for OpenGL-related functions such as glPointSize. Any others may indicate that an additional dependency file needs to be specified in the SOURCES list. Unfortunately this process is not automated and you will need to search the source tree to locate the files supplying the missing symbols. You may also be able to get away with ignoring the warnings if the code path referencing them is not used at run-time. If all goes well, a .js file will be output to the current directory. This file cannot be run by itself, but requires an HTML loader to provide it with a canvas to draw to and to pass in command-line parameters. The Emularity project provides such a loader. There are example .html files in that repository which can be edited to point to your newly compiled MAME .js file and pass in whatever parameters you desire. You will then need to place all of the following on a web server:
You need to use a web server instead of opening the local files directly due to security restrictions in modern web browsers. If the result fails to run, you can open the Web Console in your browser to see any error output which may have been produced (e.g. missing or incorrect ROM files). A “ReferenceError: foo is not defined” error most likely indicates that a needed source file was omitted from the SOURCES list. Compiling the DocumentationCompiling the documentation will require you to install several packages depending on your operating system. Compiling the Documentation on Microsoft WindowsOn Windows, you’ll need a couple of packages from the MSYS2 environment. You can install these packages with pacman -S mingw-w64-x86_64-librsvg mingw-w64-x86_64-python-sphinx mingw-w64-x86_64-python-sphinxcontrib-svg2pdfconverter If you intend to make a PDF via LaTeX, you’ll need to install a LaTeX distribution such as TeX Live: pacman -S mingw-w64-x86_64-texlive-fonts-recommended mingw-w64-x86_64-texlive-latex-extra Compiling the Documentation on Debian and UbuntuOn Debian/Ubuntu flavors of Linux, you’ll need python3-sphinx/python-sphinx and the python3-pip/python-pip packages: sudo apt-get install python3-sphinx python3-pip pip3 install sphinxcontrib-svg2pdfconverter On Debian, you’ll need to install the librsvg2-bin package: sudo apt-get install librsvg2-bin If you intend to make a PDF via LaTeX, you’ll need to install a LaTeX distribution such as TeX Live: sudo apt-get install librsvg2-bin latexmk texlive texlive-science texlive-formats-extra From this point you can do make html or make latexpdf from the docs folder to generate the output of your choice. Typing make by itself will tell you all available formats. The output will be in the docs/build folder in a subfolder based on the type chosen (e.g. make html will create docs/build/html with the output.) Useful OptionsThis section summarises some of the more useful options recognised by the main makefile. You use these options by appending them to the make command, setting them as environment variables, or adding them to your prefix makefile. Note that in order to apply many of these settings when rebuilding, you need to set REGENIE=1 the first time you build after changing the option(s). Also note that GENie does not automatically rebuild affected files when you change an option that affects compiler settings. Overall build options
Tool locations
Including subsets of supported systems
Optional features
Compilation options
Library/framework locations
Known IssuesIssues with specific compiler versions
GNU C Library fortify source featureThe GNU C Library has options to perform additional compile- and run-time checks on string operations, enabled by defining the _FORTIFY_SOURCE preprocessor macro. This is intended to improve security at the cost of a small amount of overhead. MAME is not secure software, and we do not support building with _FORTIFY_SOURCE defined. Some Linux distributions (including Gentoo and Ubuntu) have patched GCC to define _FORTIFY_SOURCE to 1 as a built-in macro. This is problematic for more projects than just MAME, as it makes it hard to disable the additional checks (e.g. if you don’t want the performance impact of the run-time checks), and it also makes it hard to define _FORTIFY_SOURCE to 2 if you want to enable stricter checks. You should really take it up with the distribution maintainers, and make it clear you don’t want non-standard GCC behaviour. It would be better if these distributions defined this macro by default in their packaging environments if they think it’s important, rather than trying to force it on everything compiled on their distributions. (This is what Red Hat does: the _FORTIFY_SOURCE macro is set in the RPM build environment, and not by distributing a modified version of GCC.) If you get compilation errors in bits/string_fortified.h you should first ensure that the _FORTIY_SOURCE macro is defined via the environment (e.g. a CFLAGS or CXXFLAGS environment variable). You can check to see whether the _FORTIFY_SOURCE macro is a built-in macro with your version of GCC with a command like this: gcc -dM -E - < /dev/null | grep _FORTIFY_SOURCE If _FORTIFY_SOURCE is defined to a non-zero value by default, you can work around it by adding -U_FORTIFY_SOURCE to the compiler flags (e.g. by using the ARCHOPTS setting, or setting the CFLAGS and CXXFLAGS environment variables. Issues affecting Microsoft Visual StudioMicrosoft introduced a new version of XAudio2 with Windows 8 that’s incompatible with the version included with DirectX for prior Windows versions at the API level. Newer versions of the Microsoft Windows SDK include headers and libraries for the new version of XAudio2. By default, the target Windows version is set to Windows Vista (6.0) when compiling MAME, which prevents the use of this version of the XAudio2 headers and libraries. To build MAME with XAudio2 support using the Microsoft Windows SDK, you must do one of the following:
The MSVC compiler produces spurious warnings about potentially uninitialised local variables. You currently need to add NOWERROR=1 to the options passed to make when generating the Visual Studio project files. This stops warnings from being treated as errors. (MSVC seems to lack options to control which specific warnings are treated as errors, which other compilers support.) Unusual Build ConfigurationsLinking using the LLVM linkerThe LLVM linker is generally faster than the GNU linker that GCC uses by default. This is more pronounced on systems with a high overhead for file system operations (e.g. Microsoft Windows, or when compiling on a disk mounted over a network). To use the LLVM linker with GCC, ensure the LLVM linker is installed and add -fuse-ld=lld to the linker options (e.g. in the LDFLAGS environment variable or in the ARCHOPTS setting). Cross-compiling MAMEMAME’s build system has basic support for cross-compilation. Set CROSS_BUILD=1 to enable separate host and target compilers, set OVERRIDE_CC and OVERRIDE_CXX to the target C/C++ compiler commands, and if necessary set CC and CXX to the host C/C++ compiler commands. If the target OS is different to the host OS, set it with TARGETOS. For example it may be possible to build a MinGW32 x64 build on a Linux host using a command like this: make TARGETOS=windows PTR64=1 OVERRIDE_CC=x86_64-w64-mingw32-gcc OVERRIDE_CXX=x86_64-w64-mingw32-g++ OVERRIDE_LD=x86_64-w64-mingw32-ld MINGW64=/usr** (The additional packages required for producing a standard MinGW32 x64 build on a Fedora Linux host are mingw64-gcc-c++, mingw64-winpthreads-static and their dependencies. Non-standard builds may require additional packages.) Using libc++ on LinuxMAME may be built using the LLVM project’s “libc++” C++ Standard Library. The prerequisites are a working clang/LLVM installation, and the libc++ development libraries. On Fedora Linux, the necessary packages are libcxx, libcxx-devel, libcxxabi and libcxxabi-devel. Set the C and C++ compiler commands to use clang, and add -stdlib=libc++ to the C++ compiler and linker options. You could use a command like this: env LDFLAGS=-stdlib=libc++ make OVERRIDE_CC=clang OVERRIDE_CXX=clang++ ARCHOPTS_CXX=-stdlib=libc++ ARCHOPTS_OBJCXX=-stdlib=libc++ The options following the make command may be placed in a prefix makefile if you want to use this configuration regularly, but LDFLAGS needs to be be set in the environment. Using a GCC/GNU libstdc++ installation in a non-standard location on LinuxGCC may be built and installed to a custom location, typically by supplying the --prefix= option to the configure command. This may be useful if you want to build MAME on a Linux distribution that still uses a version of GNU libstdC++ that predates C++17 support. To use an alternate GCC installation to, build MAME, set the C and C++ compilers to the full paths to the gcc and g++ commands, and add the library path to the run-time search path. If you installed GCC in /opt/local/gcc72, you might use a command like this: make OVERRIDE_CC=/opt/local/gcc72/bin/gcc OVERRIDE_CXX=/opt/local/gcc72/bin/g++ ARCHOPTS=-Wl,-R,/opt/local/gcc72/lib64 You can add these options to a prefix makefile if you plan to use this configuration regularly. Configuring MAME
Getting Started: A Quick PrefaceOnce you have MAME installed, the next step is to configure it. There are several ways to do this, and each will be covered in turn. If you are on Windows, the MAME executable will be called mame.exe. If you are on Linux or MacOS, the MAME executable will be called mame. Initial Setup: Creating mame.ini From Command Line on WindowsFirst, you will need to cd to the directory where you installed MAME into. If, for instance, you have MAME installed in C:\Users\Public\MAME you will need to type cd C:\Users\Public\MAME into the command prompt. Then you have MAME create the config file by typing mame -createconfig. MAME will then create the mame.ini file in the MAME installation folder. This file contains the default configuration settings for a new MAME installation. Initial Setup: Creating mame.ini From Command Line on Linux or MacOSThe steps for Linux and MacOS are similar to those of Windows. If you installed MAME using the package manager that came from a Linux distro, you will type mame -createconfig into your terminal of choice. If you have compiled from source or downloaded a binary package of MAME, you will cd into the directory you put the MAME files into. For instance, cd /home/myusername/mame Then you will type ./mame -createconfig into your terminal of choice. You can then need to edit the mame.ini file in your favorite text editor, e.g. Notepad on Windows or vi on Linux/MacOS, or you can change settings from inside of MAME. Initial Setup: Graphical SetupThis is the easiest way to get started. Start MAME by opening the MAME icon in the location where you installed it. This will be mame.exe on Windows, mame on Linux and macOS. Once MAME has started, you can either use your mouse to click on the Configure Options menu selection at the bottom center of your screen, or you can switch panes to the bottom one (default key is Tab), then press the menu accept button (default key is Return/Enter) to go into the Configuration menu. Choose Save Configuration to create the mame.ini file with default settings. From here, you can either continue to configure things from the graphical user interface or edit the mame.ini file in your favorite text editor. BASIC MAME USAGE AND CONFIGURATIONThis section describes general usage information about MAME. It is intended to cover aspects of using and configuring MAME that are common across all operating systems. For additional OS-specific options, please see the separate documentation for your platform of choice. Using MAMEIf you want to dive right in and skip the command line, there's a nice graphical way to use MAME without the need to download and set up a front end. Simply start MAME with no parameters, by double-clicking the mame.exe file or running it directly from the command line. If you're looking to harness the full power of MAME, keep reading further. On macOS and *nix-based platforms, please be sure to set your font up to match your locale before starting, otherwise you may not be able to read the text due to missing glyphs. If you are a new MAME user, you could find this emulator a bit complex at first. Let's take a moment to talk about software lists, as they can simplify matters quite a bit. If the content you are trying to play is a documented entry on one of the MAME software lists, starting the content is as easy as mame.exe <system>
<software>
For instance: mame.exe nes metroidu
will load the USA version of Metroid for the Nintendo Entertainment System. Alternatively, you could start MAME with mame.exe nes
and choose the software list from the cartridge slot. From there, you could pick any software list-compatible software you have in your roms folders. Please note that many older dumps of cartridges and discs may either be bad or require renaming to match up to the software list in order to work in this way. If you are loading an arcade board or other non-software list content, things are only a little more complicated: The basic usage, from command line, is mame.exe <system>
<media> <software> <options>
where
Remember that if you type a <system> name which does not correspond to any emulated system, MAME will suggest some possible choices which are close to what you typed; and if you don't know which <media> switch are available, you can always launch mame.exe <system>
-listmedia
If you don't know what <options> are available, there are a few things you can do. First of all, you can check the command line options section of this manual. You can also try one of the many Front-ends available for MAME. Alternatively, you should keep in mind the following command line options, which might be very useful on occasion: mame.exe -help
gives a basic summary of command line options for MAME, as explained above. mame.exe -showusage
gives you the (quite long) list of available command line options for MAME. The main options are described, in the Universal Command-line Options section of this manual. mame.exe -showconfig
gives you a (quite long) list of available configuration options for MAME. These options can always be modified at command line, or by editing them in mame.ini which is the main configuration file for MAME. You can find a description of some configuration options in the Universal Command-line Options section of the manual (in most cases, each configuration option has a corresponding command line option to configure and modify it). mame.exe -createconfig
creates a brand new mame.ini file, with default configuration settings. Notice that mame.ini is basically a plain text file, so you can open it with any text editor (e.g. Notepad, Emacs or TextEdit) and configure every option you need. However, no particular tweaks are needed to start, so you can leave most of the options unaltered. If you execute mame -createconfig when you already have an existing mame.ini from a previous MAME version, MAME automatically updates the pre-existing mame.ini by copying changed options into it. Once you are more confident with MAME options, you may want to adjust the configuration of your setup a bit more. In this case, keep in mind the order in which options are read; see Order of Config Loading for details. MAME’s User Interface
IntroductionMAME provides a simple user interface for selecting the system and software to run and changing settings while running an emulated system. MAME’s user interface is designed to be usable with a keyboard, game controller, or pointing device, but will require a keyboard for initial configuration. The default settings for the most important controls to know when running an emulated system, and the settings they correspond to in case you want to change them, are as follows:
Navigating menusBy default, MAME menus can be navigated using the keyboard cursor keys. All the UI controls can be changed by going to the General Inputs menu and then selecting User Interface. The default keyboard controls on a US ANSI QWERTY layout keyboard, and the settings they correspond to, are as follows:
Using a game controllerMAME supports navigating menus with a game controller or joystick, but only the most important UI controls have joystick assignments by default:
For gamepad-style controllers, the left analog thumb stick and directional pad usually control UI navigation. Depending on the controller, the right analog thumb stick, triggers and additional buttons may automatically be assigned to UI inputs. Check the User Interface input assignments menu to see how controls are assigned. If you want to be able to use MAME with a game controller without needing a keyboard, you’ll need to assign joystick buttons (or combinations of buttons) to these controls as well:
If you’re not using an external front-end to launch systems in MAME, you should assign joystick buttons (or combinations of buttons) to these controls to make full use of the system and software selection menus:
Using a mouse or trackballMAME supports navigating menus using a mouse or trackball that works as a system pointing device:
If you have enough additional mouse buttons, you may want to assign button combinations to the Show/Hide Menu, Pause, UI Back and/or UI Cancel inputs to make it possible to use MAME without a keyboard. Using a touch screenMAME has basic support for navigating menus using a touch screen:
Note that for SDL-based MAME, the enable_touch option must be switched on to use touch screen support. Configuring inputsMAME needs a flexible input system to support the control schemes of the vast array of systems it emulates. In MAME, inputs that only have two distinct states, on and off or active and inactive, are called digital inputs, and all other inputs are called analog inputs, even if this is not strictly true (for example multi-position switches are called analog inputs in MAME). To assign MAME’s user interface controls or the default inputs for all systems, select Input Settings from the main menu during emulation and then select Input Assignments (general) from the Input Settings menu, or select General Settings from the system selection menu and then select Input Assignments from the General Settings menu. From there, select a category. To assign inputs for the currently running system, select Input Settings from the main menu during emulation and then select Input Assignments (this system) from the Input Settings menu. Inputs are grouped by device and sorted by type. You can move between devices with the next group and previous group keys/buttons (opening/closing brackets [ and ] on the keyboard by default). The input assignment menus show the name of the emulated input or user interface control on the left, and the controls (or combination of controls) assigned to it on the right. To adjust the sensitivity, auto-centre speed and inversion settings, or to see how emulated analog controls react to your inputs, select Input Settings from the main menu during emulation, and then select Analog Input Adjustments from the Input Settings Menu (this item only appears on the Input Settings menu for systems with analog controls). Digital input settingsEach emulated digital input has a single assignment setting. For flexibility, MAME can combine controls (keys, buttons and joystick axes) using logical and, not and or operations. This is best illustrated with some examples:
(In technical terms, MAME uses Boolean sum of products logic to combine inputs.) When a digital input setting is highlighted, the prompt below the menu shows whether selecting it will replace the current assignment or append an or operation to it. Press UI Left/Right before selecting the setting to switch between replacing the assignment or appending an or operation to it. Press UI Clear (Delete or Forward Delete by default) to clear the highlighted setting, or restore the default assignment if it is currently cleared. When you select a digital input setting, MAME will wait for you to enter an input or a combination of inputs for a logical and operation:
Here’s how to produce some example settings:
Analog input settingsEach emulated analog input has three assignment settings:
The increment and decrement settings are most useful for controlling an emulated analog input using digital controls (for example keyboard keys, joystick buttons, or a directional pad). They are configured in the same way as emulated digital inputs (see above). It’s important that you don’t assign the same control to the axis setting as well as the increment and/or decrement settings for the same emulated input at the same time. For example if you assign Ridge Racer’s Steering Wheel Analog setting to the X axis of the left analog stick on your controller, you should not assign either the Steering Wheel Analog Inc or Steering Wheel Analog Dec setting to the X axis of the same analog stick. You can assign one or more analog axes to the axis setting for an emulated analog input. When multiple axes are assigned to an axis setting, they will be added together, but absolute position controls will override relative position controls. For example suppose for Arkanoid you assign the Dial Analog axis setting to Mouse X or Joy 1 LSX or Joy 1 RSX on a mouse and Xbox-style controller. You will be able to control the paddle with the mouse or either analog stick, but the mouse will only take effect if both analog sticks are in the neutral position (centred) on the X axis. If either analog stick is not centred on the X axis, the mouse will have no effect, because a mouse is a relative position control while joysticks are absolute position controls. For absolute position controls like joysticks and pedals, MAME allows you to assign either the full range of an axis or the range on one side of the neutral position (a half axis) to an axis setting. Assigning a half axis is usually used for pedals or other absolute inputs where the neutral position is at one end of the input range. For example suppose for Ridge Racer you assign the Brake Pedal Analog setting to the portion of a vertical joystick axis below the neutral position. If the joystick is at or above the neutral position vertically, the brake pedal will be released; if the joystick is below the neutral position vertically, the brake pedal will be applied proportionally. Half axes are displayed as the name of the axis followed by a plus or minus sign (+ or -). Plus refers to the portion of the axis below or to the right of the neutral position; minus refers to the portion of the axis above or to the left of the neutral position. For pedal or analog trigger controls, the active range is treated as being above the neutral position (the half axis indicated by a minus sign). When keys or buttons are assigned to an axis setting, they conditionally enable analog controls assigned to the setting. This can be used in conjunction with an absolute position control to create a “sticky” control. Here are some examples of some possible axis setting assignments, assuming an Xbox-style controller and a mouse are used:
When you select an axis setting, MAME will wait for you to enter an input:
To adjust sensitivity, auto-centring speed and inversion settings for emulated analog inputs, or to see how they respond to controls with your settings, select Input Settings from the main menu during emulation, and then select Analog Input Adjustments from the Input Settings Menu. Settings for emulated analog inputs are grouped by device and sorted by type. You can move between devices with the next group and previous group keys/buttons (opening/closing brackets [ and ] on the keyboard by default). The state of the emulated analog inputs is shown below the menu, and reacts in real time. Press the On Screen Display key or button (the backtick/tilde key by default on a US ANSI QWERTY keyboard) to hide the menu to make it easier to test without changing settings. Press the same key or button to show the menu again. Each emulated input has four settings on the Analog Controls menu:
Use the UI left/right keys or buttons to adjust the highlighted setting. Selecting a setting or pressing the UI clear key/button (Forward Delete by default) restores its default value. The units for the increment/decrement speed, auto-centering speed and sensitivity settings are tied to the driver/device implementation. The increment/decrement speed and auto-centering speed settings are also tied to the frame rate of the first emulated screen in the system. The response to controls assigned to the increment/decrement settings will change if the system changes the frame rate of this screen. The system and software selection menusIf you start MAME without specifying a system on the command line, the system selection menu will be shown (assuming the ui option is set to cabinet). The system selection menu is also shown if you select Select New System from the main menu during emulation. Selecting a system that uses software lists shows the similar software selection menu. The system and software selection menus have the following parts:
You can type to search the displayed list of systems or software. Systems are searched by full name, manufacturer and full name, and short name. If you are using localised system names, phonetic names will also be searched if present. Software items are searched by description, alternate titles (alt_title info elements in the software lists), and short name. UI Cancel (Escape by default) will clear the search if currently searching. Navigation controlsIn addition to the usual menu navigation controls, the system and software selection menus have additional configurable controls for navigating the multi-pane layout, and providing alternatives to toolbar buttons if you don’t want to use a pointing device. The default additional controls (with a US ANSI QWERTY keyboard), and the settings they correspond to, are:
When focus is on the filter list, you can use the menu navigation controls (up, down, home and end) to highlight a filter, and UI Select (Return/Enter by default) apply it. When focus is on any area besides the info/image tabs, you can change the image or info source with left/right. When focus is on the info/image tabs, left/right switch between tabs. When focus is on the image/info tabs or source, you can scroll the info using up, down, page up, page down, home and end. You can move focus to an area by clicking on it with the middle mouse button. The simple system selection menuIf you start MAME without specifying a system on the command line (or choose Select New System from the main menu during emulation) with the ui option set to simple, the simple system selection menu will be shown. The simple system selection menu shows fifteen randomly selected systems that have ROM sets present in your configured ROM folder(s). You can type to search for a system. Clearing the search causes fifteen systems to be randomly selected again. The info panel below the menu shows summary information about the highlighted system. The background colour changes depending on the emulation status: green for working, amber for imperfectly emulated features or known issues, or red for more serious issues. Default Keyboard Controls
Controls ForewordMAME supports a vast array of different types of machines, with a significantly different array of inputs across them. This means that some keyboard keys, mouse buttons, and joystick buttons will be used for multiple functions. As a result, the control charts below are separated by machine-types to make it easier to find what you’re looking for. All of the controls below are fully configurable in the user interface. These charts show the default configuration. Note that the defaults shown here are arranged by US ANSI key positioning. If you are using a different layout, the keys will vary. MAME User Interface ControlsThe controls here cover MAME functions such as MAME’s menus, machine pause, and saving/loading save states.
Graphics mode:
Tilemap mode:
Note: Not all systems have decoded graphics and/or tilemaps.
System and software selection menusThe system and software selection menus use additional controls
Default Arcade Machine ControlsThis section covers controls that are applicable to most kinds of arcade machines. Note that not all machines will have all of these controls. All the controls below are fully configurable in the user interface. This list shows the standard keyboard configuration.
Default Arcade Game ControlsThis section covers controls for arcade games using common joystick/button control schemes. All the controls below are fully configurable in the user interface. This list shows the standard keyboard configuration.
Player 1 Controls
Player 2 ControlsPlayer 3 Controls
Player 4 Controls
Default Mahjong and Hanafuda KeysMost mahjong and hanafuda games use a standard control panel layout. Some keys may not be present, depending on the kind of game. For example games without a bonus game feature may lack the Take Score, Double Up, Big and Small keys, and games without gambling features may also lack the Bet key. Some games may not use all keys that are present. For example many games do not use the Flip Flop and Last Chance keys. [image: Standard mahjong control panel layout] [image] Due to the large number of keys, MAME only provides default input configuration for a single set of player controls. For multi-player mahjong/hanafuda games, or mahjong/hanafuda games with multiple player positions, manual configuration is required. All the keys below are fully configurable in the user interface. This list shows the standard keyboard configuration.
Default Gambling KeysAll the keys below are fully configurable in the user interface. This list shows the standard keyboard configuration. Note that many gambling games use buttons for multiple functions. For example a slots game may use the Start button to stop all reels, lacking a dedicated Stop All Reels button, or a poker game may use the hold buttons to control the double-up bonus game, lacking dedicated Take Score, Double Up, High and Low buttons.
Default Blackjack KeysAll the keys below are fully configurable in the user interface. This list shows the standard keyboard configuration.
Default Poker KeysAll the keys below are fully configurable in the user interface. This list shows the standard keyboard configuration.
Default Slots KeysAll the keys below are fully configurable in the user interface. This list shows the standard keyboard configuration. Default Computer KeysAll the keys below are fully configurable in the user interface. This list shows the standard keyboard configuration. Note that controls can vary widely by computer type, so not all keys are shown here. See the Input Assignments (this system) section of MAME’s Input Settings menu for details for the machine you are currently using.
Other MachinesAll the keys are fully configurable in the user interface. Note that controls can vary widely by machine type, so default keys are not shown here and defaults will vary considerably based on the manufacturer and style. See the Input Assignments (this system) section of MAME’s Input Settings menu for details for the machine you are currently using. MAME Menus
IntroductionTo show the main menu while running an emulated system in MAME, press the Show/Hide Menu key or button (Tab by default). If the emulated system has keyboard inputs, you may need to press the Toggle UI Controls key or button (Scroll Lock, or Forward Delete on macOS, by default) to enable user interface controls first. You can dismiss a menu by pressing the UI Back key or button (Escape by default). Dismissing a menu will return to its parent menu, or to the running system in the case of the main menu. You can hide a menu and return to the running system by pressing the Show/Hide Menu key or button. Pressing the Show/Hide Menu key or button again will jump back to the same menu. This is useful when testing changes to settings. Emulated system inputs are ignored while menus are displayed. You can still pause or resume the running system while most menus are displayed by pressing the Pause key or button (F5 on the keyboard by default). If you start MAME without specifying a system on the command line, the system selection menu will be shown (assuming the ui option is set to cabinet). The system selection menu is also shown if you select Select New System from the main menu during emulation. For more information on navigating menus, see the relevant section. Main menuThe main menu is shown when you press the Show/Hide Menu key or button while running an emulated system or while the system information screen is displayed. It provides access to menus used to change settings, control various features, and show information about the running system and MAME itself. If you press the Show/Hide Menu key or button to show the main menu while the system information screen is displayed, the emulated system will not start until the main menu is dismissed (either by selecting Start System, pressing the UI Back key or button, or pressing the Show/Hide Menu key or button). This can be useful for mounting media images or changing DIP switches and machine configuration settings before the emulated system starts.
Input Settings menuThe Input Settings provides options for assigning controls to emulated inputs, adjusting analog control settings, controlling toggle inputs, and testing input devices. You can reach the Input Settings menu by selecting Input Settings from the main menu. The items shown on this menu depend on available emulated inputs for the running system. Available emulated inputs may depend on slot options, machine configuration settings and DIP switch settings.
Toggle Inputs menuThe Toggle Inputs menu shows the current state of multi-position or toggle inputs. Common examples include mechanically locking Caps Lock keys on computers, and two-position gear shit levers on driving games. You can reach the Toggle Inputs menu by selecting Toggle Inputs from the Input Settings menu. Note that available emulated inputs may depend on slot options, machine configuration settings and DIP switch settings. Inputs are grouped by the emulated device they belong to. You can move between devices using the Next Group and Previous Group keys or buttons. Names of inputs are shown on the left, and the current settings are shown on the right. To change the state of an input, highlight it and use the UI Left and UI Right keys or buttons, or click the arrows beside the current setting. Keyboard Selection menuThe Keyboard Selection menu lets your switch between emulated and natural keyboard modes, and enable or disable keyboard inputs for individual emulated devices. You can reach the Keyboard Selection menu by selecting Keyboard Selection from the Input Settings menu. In emulated keyboard mode, keyboard and keypad inputs behave like any other digital inputs, responding to their assigned controls. In natural keyboard mode, MAME attempts to translate typed characters to emulated keystrokes. The initial keyboard mode is set using the natural option. There are a number of unavoidable limitations in natural keyboard mode:
Each emulated device in the system that has keyboard and/or keypad inputs is listed on the menu, allowing keyboard/keypad inputs to be enabled or disabled for individual devices. By default, keyboard/keypad inputs are enabled for the first device with keyboard inputs (if any), and for all other devices that have keypad inputs but no keyboard inputs. The enabled keyboard/keypad inputs are automatically saved to the configuration file for the system when the emulation session ends. Input Devices menuThe Input Devices menu lists input devices recognised by MAME and enabled with your current settings. Recognised input devices depend on the keyboardprovider, mouseprovider, lightgunprovider and joystickprovider options. Classes of input devices can be enabled or disabled using the mouse, lightgun and joystick options. You can reach the Input Devices menu by selecting Input Devices from the Input Settings menu or the General Settings menu. Input devices are grouped by device class (for example keyboards or light guns). You can move between device classes using the Next Group and Previous Group keys or buttons. For each device, the device number (within its class) is shown on the left, and the name is shown on the right. Select a device to show the supported controls for the device. The name of each control is displayed on the left and its current state is shown on the right. When an analog axis control is highlighted, its state is also shown in graphical form below the menu. Digital control states are either zero (inactive) or one (active). Analog axis input states range from -65,536 to 65,536 with the neutral position at zero. You can also select Copy Device ID to copy the device’s ID to the clipboard. This is useful for setting up stable controller IDs in controller configuration files. How does MAME look for files?
IntroductionUnlike typical desktop applications where you browse your disk and select a file to open or a location to save to, MAME has settings to tell it where to look for the files it needs. You can change these settings by starting MAME without specifying a system, selecting Configure Options from the system selection menu, and then selecting Configure Directories (remember to select Save Configuration if you want to keep your changes). You can also change settings by editing your mame.ini and ui.ini files directly, or specify settings on the command line. For information on available options for controlling where MAME searches for files, see Core Search Path Options. TerminologyIt’s necessary to understand some MAME-specific terminology used in the explanations here:
Search path optionsMost options for specifying locations to search allow multiple directories to be specified, separated by semicolon (;) characters. Environment variables are expanded, using CMD shell syntax on Windows, or Bourne shell syntax on UNIX-like systems. Relative paths are interpreted relative to the current working directory at the time of use. If you start MAME by double-clicking it in Windows Explorer, the working directory is set to the folder containing the MAME executable. If you start MAME by double-clicking it in the macOS Finder or from most Linux desktop environments, the working directory will be set to your home directory. Archive filesMAME can load files from PKZIP and 7-Zip archives (these must have .zip and .7z file name extensions, respectively). A number of extensions to the PKZIP format are supported, including Zip64 for large archives, NTFS timestamps, and LZMA compression. Only ASCII or UTF-8 filenames are supported in PKZIP archives (7-Zip archives always use UTF-16 filenames). MAME does not load files from nested archives. MAME will not load files stored in a PKZIP or 7-Zip archive which is itself contained within a PKZIP or 7-Zip archive. Multi-segment archives and encrypted archives are not supported. The legacy “implode” compression method in PKZIP archives is not supported. MAME may perform poorly with archives containing large numbers of files. Files compressed using the LZMA compression algorithm are inherently more CPU-intensive to decompress than files compressed using simpler algorithms. MAME does not take the archive layout into consideration when loading files from archives, so using “solid compression” often results in MAME decompressing the same data repeatedly when loading media. How does MAME search for media?Use the rompath option sets the folders where searches for ROM dumps, disk images, and other media. By default MAME looks for media in a folder called roms in the working directory. For the purpose of this discussion, floppy disk, cassette, paper tape and other media images that are not stored in CHD format are treated as ROM dumps. When searching for system, device and software ROM dumps, MAME treats folders and archives inside the folders configured in you rompath setting as equivalent, but remember the limitation that MAME cannot load files from an archive contained within another archive. MAME looks for a folder first, then a PKZIP archive, and finally a 7-Zip archive. When searching for a ROM dump in an archive, MAME first looks for a file with the expected name and CRC. If no matching file is found, MAME looks for a file with the expected CRC ignoring the name. If no matching file is found, MAME finally looks for a file with the expected name, ignoring the CRC. While MAME can load disk images in CHD format from inside archives, this is not recommended. CHD files contain compressed data stored in a format allowing random access. If a CHD format disk image is stored in a PKZIP or 7-Zip archive, MAME needs to load the entire file into memory in order to use it. For hard disk or LaserDisc images in particular, this will likely use an excessive amount of swap file space, hurting performance and possibly reducing the life expectancy of your disks or SSDs. It’s best to keep CHD format disk images in folders. System ROMsFor each folder configured in your rompath setting, MAME looks for system ROMs in the following locations:
Using Shiritsu Justice Gakuen as an example, MAME will search for system ROMs as follows:
Device ROMsFor each folder configured in your rompath setting, MAME looks for device ROMs in the following locations:
Using a Unitron 1024 Macintosh clone with a French Macintosh Plus keyboard with integrated numeric keypad attached as an example, MAME will look for the keyboard microcontroller ROM as follows:
Software Item ROMsFor each folder configured in your rompath setting, MAME looks for software item ROMs in the following locations:
If you load the German version of Dune II from the Mega Drive/Genesis cartridge software list in the PAL Mega Drive console, MAME will look for the cartridge ROM as follows:
CHD format disk imagesMAME searches for system, device and software item CHD format disk images in almost the same way it searches for ROMs, with just a few differences:
To save space, MAME allows delta CHD files to be used for clone systems, devices with parent ROM devices and clone software items. The delta CHD file must use a CHD format disk image from the parent system, parent ROM device or parent software item as its parent CHD file. The space saved depends on how much content can be reused from the parent CHD file. MAME searches the same locations for parent CHD files that it would search for the disk image itself. Loose softwareMany systems support loading media from a file by supplying the path on the command line for one of the media options. Relative paths are interpreted relative to the current working directory. You can specify a path to a file inside a PKZIP or 7-Zip archive similarly to specifying a path to a file in a folder (keep in mind that you can have at most a single archive file in a path, as MAME does not support loading files from archives contained within other archives). If you specify a path to a PKZIP or 7-Zip archive, MAME will use the first file found in the archive (this depends on the order that files are stored in the archive – it’s most useful for archives containing a single file). Start the Nintendo Entertainment System/Famicom system with the file amazon_diet_EN.nes mounted in the cartridge slot: mame nes -cart amazon_diet_EN.nes Start the Osborne-1 system with the first file in the archive os1xutls.zip mounted in the first floppy disk drive: mame osborne1 -flop1 os1xutils.zip Start the Macintosh Plus system with the file system tools.img in the archive sys603.zip mounted in the first floppy disk drive: mame macplus -flop1 "sys603.zip/system tools.img" Diagnosing missing mediaWhen starting a system from MAME’s system selection menu or software selection menu, MAME will list any missing system or device ROM dumps or disk images, as long as at least one ROM dump or disk image for the system is present. For clone systems, at least one ROM dump or disk image unique to the clone must be present for MAME to list missing ROM dumps and disk images. If all system and device ROM dump and disk images are present and the system is being started with a software item, MAME will check that ROM dumps and disk images for the software item are present. If at least one ROM dump or disk image for the software item is present, MAME will list any missing ROM dumps or disk images. For example if you try to start the Macintosh Plus system and the keyboard microcontroller ROM dump is missing, MAME displays the following error message: Required ROM/disk images for the selected system are
missing or incorrect. Please acquire the correct files or select a different
system.
341-0332-a.bin (mackbd_m0110a) - not found Press any key to continue. The name of the missing ROM dump is shown (341-0332-a.bin), as well as the short name of the device it belongs to (mackbd_m0110a). When a missing ROM dump or disk image is not specific to the selected system, the short name of the system or device it belongs to is shown. If you start a system in MAME from a command prompt, MAME will show where it searched for any ROM dumps or disk images that were not found. Using the example of a Unitron 1024 Macintosh clone with a French keyboard connected, MAME will show the following error messages if no ROMs are present: mame utrn1024 -kbd frp 342-0341-a.u6d NOT FOUND (tried in utrn1024 macplus) 342-0342-a.u8d NOT FOUND (tried in utrn1024 macplus) 341-0332-a.bin NOT FOUND (tried in mackbd_m0110a_f mackbd_m0110a utrn1024 macplus) MAME used the system short name utrn1024 and the parent system short name macplus when searching for system ROMs. When searching for the keyboard microcontroller ROM, MAME used the device short name mackbd_m0110a_f, the parent ROM device short name mackbd_m0110a, the system short name utrn1024, and the parent system short name macplus. Software parts that use the ROM loader (typically cartridge media) show similar messages when ROM dumps are not found. Using the example of the German version of Dune II on a PAL Mega Drive, MAME will show the following error messages if no ROMs are present: mame megadriv dune2g mpr-16838-f.u1 NOT FOUND (tried in megadriv\dune2g megadriv\dune2 dune2g dune2 megadriv genesis) Fatal error: Required files are missing, the machine cannot be run. MAME searched for the cartridge ROM using:
Software parts that use the image file loader (including floppy disk and cassette media) only check for media after ROM images are loaded, and missing media files are shown differently. Using the example of Macintosh System 6.0.3, MAME will show these error messages if the software is missing: mame macplus -flop1 sys603:flop1 :fdc:0:35dd: error opening image file system tools.img: No such file or directory (generic:2) (tried in mac_flop\sys603 sys603 macplus) Fatal error: Device Apple/Sony 3.5 DD (400/800K GCR) load (-floppydisk1 sys603:flop1) failed: No such file or directory The error messages show where MAME searched for the image file in the same format. In this case, it used the software list short name mac_flop and the software short name sys603, the software short name sys603 only, and the locations that would be searched for system ROMs. Front-endsA number of third party tools for MAME to make system and software selection simpler are available. These tools are called “front-ends”, and there are far too many to list exhaustively here. Some are free, some are commercial – caveat emptor. Some older front-ends predate the merging of MAME and MESS and do not support the additional console, hand-held, and computer functionality inherited from MESS. This following list is not an endorsement of any of these front-ends by the MAME team. It simply shows a number of commonly used free front-ends to provide a starting point.
The MAME team will not provide support for issues with front-ends. For support, we suggest contacting the front-end author or asking on one of the popular MAME-friendly forums on the Internet. About ROMs and SetsHandling and updating of ROMs and Sets used in MAME is probably the biggest area of confusion and frustration that MAME users will run into. This section aims to clear up a lot of the most common questions and cover simple details you'll need to know to use MAME effectively. Let's start with a simple definition of what a ROM is. What is a ROM image?For arcade games, a ROM image or file is a copy of all of the data inside a given chip on the arcade motherboard. For most consoles and handhelds, the individual chips are frequently (but not always) merged into a single file. As arcade machines are much more complicated in their design, you'll typically need the data from a number of different chips on the board. Grouping all of the files from Puckman together will get you a ROM set of Puckman. An example ROM image would be the file pm1_prg1.6e stored in the Puckman ROM set. Why ROM and not some other name?ROM stands for Read-Only Memory. The chips used to store the game data were not rewritable and were permanent (as long as the chip wasn't damaged or aged to death!) As such, a copy of the data necessary to reconstitute and replace a dead data chip on a board became known as a "ROM image" or ROMs for short. Parents, Clones, Splitting, and MergingAs the MAME developers received their third or fourth revision of Pac-Man, with bugfixes and other code changes, they quickly discovered that nearly all of the board and chips were identical to the previously dumped version. In order to save space, MAME was adjusted to use a parent/clone set system. A given set, usually (but not necessarily) the most recent bugfixed World revision of a game, will be designated as the parent. All sets that use mostly the same chips (e.g. Japanese Puckman and USA/World Pac-Man) will be clones that contain only the changed data compared to the parent set. This typically comes up as an error message to the user when trying to run a Clone set without having the Parent set handy. Using the above example, trying to play the USA version of Pac-Man without having the PUCKMAN.ZIP parent set will result in an error message that there are missing files. Now we add the final pieces of the puzzle: non-merged, split, and merged sets. MAME is extremely versatile about where ROM data is located and is quite intelligent about looking for what it needs. This allows us to do some magic with how we store these ROM sets to save further space. A non-merged set is one that contains absolutely everything necessary for a given game to run in one ZIP file. This is ordinarily very space-inefficient, but is a good way to go if you want to have very few sets and want everything self-contained and easy to work with. We do not recommend this for most users. A split set is one where the parent set contains all of the normal data it should, and the clone sets contain only what has changed as compared to the parent set. This saves some space, but isn't quite as efficient as A merged set takes the parent set and one or more clone sets and puts them all inside the parent set's storage. For instance, if we combine the Puckman sets, Midway Pac-Man (USA) sets, and various other related official and bootleg sets all into PUCKMAN.ZIP, the result would be a merged set. A complete merged set with the parent and all clones uses less disk space than a split set. With those basic principles, there are two other kinds of set that will come up in MAME use from time to time. First, the BIOS set: Some arcade machines shared a common hardware platform, such as the Neo-Geo arcade hardware. As the main board had data necessary to start up and self-test the hardware before passing it off to the game cartridge, it's not really appropriate to store that data as part of the game ROM sets. Instead, it is stored as a BIOS image for the system itself (e.g. NEOGEO.ZIP for Neo-Geo games) Secondly, the device set. Frequently the arcade manufacturers would reuse pieces of their designs multiple times in order to save on costs and time. Some of these smaller circuits would reappear in later boards that had minimal common ground with the previous boards that used the circuit, so you couldn't just have them share the circuit/ROM data through a normal parent/clone relationship. Instead, these re-used designs and ROM data are categorized as a Device, with the data stored as a Device set. For instance, Namco used the Namco 51xx custom I/O chip to handle the joystick and DIP switches for Galaga and other games, and as such you'll also need the NAMCO51.ZIP device set as well as any needed for the game. Troubleshooting your ROM sets and the history of ROMsA lot of the frustration users feel towards MAME can be directly tied to what may feel like pointless ROM changes that seem to only serve to make life more difficult for end-users. Understanding the source of these changes and why they are necessary will help you to avoid being blindsided by change and to know what you need to do to keep your sets running. A large chunk of arcade ROMs and sets existed before emulation did. These early sets were created by arcade owners and used to repair broken boards by replacing damaged chips. Unfortunately, these sets eventually proved to be missing critical information. Many of the early dumps missed a new type of chip that contained, for instance, color palette information for the screen. The earliest emulators approximated colors until the authors discovered the existence of these missing chips. This resulted in a need to go back and get the missing data and update the sets to add the new dumps as needed. It wouldn't be much longer before it would be discovered that many of the existing sets had bad data for one or more chips. These, too, would need to be re-dumped, and many sets would need complete overhauls. Occasionally games would be discovered to be completely wrongly documented. Some games thought to be legitimate ended up being bootleg copies from pirate manufacturers. Some games thought to be bootlegs ended up being legit. Some games were completely mistaken as to which region the board was actually from (e.g. World as compared to Japan) and this too would require adjustments and renaming. Even now, occasional miracle finds occur that change our understanding of these games. As accurate documentation is critical to detailing the history of the arcades, MAME will change sets as needed to keep things as accurate as possible within what the team knows at the time of each release. This results in very spotty compatibility for ROM sets designated for older versions of MAME. Some games may not have changed much within 20-30 revisions of MAME, and others may have drastically changed multiple times. If you hit problems with a set not working, there are several things to check-- are you trying to run a set meant for an older version of MAME? Do you have any necessary BIOS or Device ROMs? Is this a Clone set that would need to have the Parent as well? MAME will tell you what files are missing as well as where it looked for these files. Use that to determine which set(s) may be missing files. ROMs and CHDsROM chip data tends to be relatively small and are loaded into system memory in their entirety. Some games also used additional storage media such as hard disks, CD-ROMs, DVDs, and LaserDiscs. Those storage media are, for multiple technical reasons, not well-suited to being stored the same way as ROM data and won’t fully fit in memory in some cases. Thus, a new format was created for these in the CHD file. Compressed Hunks of Data files, or CHD files for short, are designed very specifically around the needs of mass storage media. Some arcade games, consoles, and PCs will require one or more CHD files to run. As CHD files are already compressed, they should not be stored PKZIP or 7-Zip archives as ROM images would be. To save space when multiple variants of a system or software item are present, MAME supports delta CHD files. A delta CHD file only stores the parts of the data that differ from its parent CHD file. This allows large space savings when different variants share a lot of data. Delta CHD files can only be used for clone systems, devices with a parent ROM device, and clone software items. A delta CHD file must use a (non-delta) CHD file from the parent system, parent ROM device or parent software item as its parent CHD file. The parent CHD file must be present to use a delta CHD file, or MAME will not be able to read the shared data from it. Common Issues and Questions (FAQ)Disclaimer: The following information is not legal advice and was not written by a lawyer.
Why does my game show an error screen if I insert coins rapidly?This is not a bug in MAME. On original arcade hardware, you simply could not insert coins as fast as you can mash the button. The only ways you could feed credits at that kind of pace was if the coin mech hardware was defective or if you were physically trying to cheat the coin mech. In either case, the game would display an error for the operator to look into the situation to prevent cheating them out of their hard-earned cash. Keep a slow, coin-insert-ish pace and you won’t trigger this. Why is my non-official MAME package (e.g. EmuCR build) broken? Why is my official update broken?Many MAME features, such as software lists, HLSL or BGFX shaders, Lua plugins and UI translations, use external files. Updates to these features often require the external files to be updated along with MAME. Unfortunately, builds provided by third parties may only include the main MAME executable, or may include outdated external files. Using an updated MAME executable with outdated external files causes issues with features reliant on the external files. Despite repeated requests that they distribute MAME complete with matching external files, some of these third parties persist in distributing incomplete or broken MAME updates. As we have no control over how third parties distribute MAME, all we really can do is recommend against obtaining MAME from sites like EmuCR. We cannot provide any support for packages we didn’t build ourselves. You can completely avoid these issues by compiling MAME yourself, or using an official package we provide. You may also encounter this problem if you do not update the contents of the hlsl, bgfx or plugins folders when updating your MAME installation with a new official build. Why does MAME support console games and dumb terminals? Wouldn't it be faster if MAME had just the arcade games? Wouldn't it take less RAM? Wouldn't MAME be faster if you just X?This is a common misconception. The actual size of the MAME file doesn't affect the speed of it; only the parts that are actively being used are in memory at any given time. In truth, the additional supported devices are a good thing for MAME as they allow us to stress test sections of the various CPU cores and other parts of the emulation that don't normally see heavy utilization. While a computer and an arcade machine may use the exact same CPU, how they use that CPU can differ pretty dramatically. No part of MAME is a second-class citizen to any other part. Video poker machines are just as important to document and preserve as arcade games. There's still room for improvements in MAME's speed, but chances are that if you're not already a skilled programmer any ideas you have will have already been covered. Don't let that discourage you-- MAME is open source, and improvements are always welcome. Why do my Neo Geo ROMs no longer work? How do I get the Humble Bundle Neo Geo sets working?Recently the Neo Geo BIOS was updated to add a new version of the Universe BIOS. This was done between 0.171 and 0.172, and results in an error trying to load Neo Geo games with an un-updated neogeo.zip set. This also affects the Humble Bundle set: the games themselves are correct and up to date as of MAME 0.173 (and most likely will remain so) though you'll have to pull the ROM set .ZIP files out of the package somehow yourself. However, the Neo Geo BIOS set (neogeo.zip) included in the Humble Bundle set is incomplete as of the 0.172 release of MAME. We suggest you contact the provider of your sets (Humble Bundle and DotEmu) and ask them to update their content to the newest revision. If enough people ask nicely, maybe they'll update the package. How can I use the Sega Genesis & Mega Drive Classics collection from Steam with MAME?As of the April 2016 update to the program, the ROM images included in the set are now 100% compatible with MAME and other Genesis/Mega Drive emulators. The ROMs are contained in the steamapps\Sega Classics\uncompressed ROMs folder as a series of .68K and .SGD images that can be loaded directly into MAME. PDF manuals for the games can be found in steamapps\Sega Classics\manuals as well. Why does MAME report "missing files" even if I have the ROMs?There can be several reasons for this:
How can I be sure I have the right ROMs?MAME checks to be sure you have the right ROMs before emulation begins. If you see any error messages, your ROMs are not those tested to work properly with MAME. You will need to obtain a correct set of ROMs through legal methods. If you have several games and you wish to verify that they are compatible with the current version of MAME, you can use the -verifyroms parameter. For example: mame -verifyroms robby ...checks your ROMs for the game Robby Roto and displays the results on the screen. mame -verifyroms * >verify.txt ...checks the validity of ALL the ROMs in your ROMS directory, and writes the results to a textfile called verify.txt. Why is it that some games have the US version as the main set, some have Japanese, and some are the World?Parent and clone sets are a convenience feature to help keep different versions of the same system or software together. The decision on which set to make the parent will always be somewhat arbitrary, but we do have some guidelines:
It’s not always possible to choose a set that’s preferred according to all criteria. As an example, the World release of Ghouls’n Ghosts (ghouls) is the parent of the US release (ghoulsu) and the Japanese original Daimakaimura, as it is the most widespread English-language release, and has the story and cutscenes intact. Another example is Midway Pac-Man (pacman), which is a clone of Namco Puck Man (puckman), because Pac-Man is a licensed version for the US market, while Puck Man was released by Namco themselves. How do I legally obtain ROMs or disk images to run on MAME?You have several options:
Beyond these options, you are on your own. Isn't copying ROMs a legal gray area?No, it’s not. You are not permitted to make copies of software without the copyright owner’s permission. This is a black and white issue. Can't game ROMs be considered abandonware?No. Even the companies that went under had their assets purchased by somebody, and that person is the copyright owner. I had ROMs that worked with an old version of MAME and now they don't. What happened?As time passes, MAME is perfecting the emulation of older games, even when the results aren't immediately obvious to the user. Often times the better emulation requires more data from the original game to operate. Sometimes the data was overlooked, sometimes it simply wasn't feasible to get at it (for instance, chip "decapping" is a technique that only became affordable very recently for people not working in high-end laboratories). In other cases it's much simpler: more sets of a game were dumped and it was decided to change which sets were which version. What about those arcade cabinets on eBay that come with all the ROMs?If the seller does not have a proper license to include the ROMs with their system, they are not legally permitted to include any ROMs with the system. If they have purchased a license to the ROMs in your name from a distributor or vendor with legitimate licenses, then they may include the ROMs with the cabinet. After signing an agreement, cabinet owners that include legitimate licensed ROMs may be permitted to include a version of MAME that runs those ROMs and nothing more. What about those guys who burn DVDs of ROMs for the price of the media?What they are doing is just as unlawful as selling the ROMs outright. As long as somebody holds the copyright, making unauthorised copies is unlawful. If someone went on the internet and started a business of selling cheap copies of U2 albums for the price of media, do you think they would get away with it? Even worse, a lot of these people like to claim that they are helping the project. In reality, they only create more problems for the MAME team. We are not associated with these people in any way, regardless of how “official” they may attempt to appear. By buying from them, you only help criminals profit from selling software they have no right to sell. Anyone using the MAME name and/or logo to sell such products is also in violation of the MAME trademark. But isn't there a special DMCA exemption that makes ROM copying legal?No, you have misread the exemptions. The exemption allows people to reverse-engineer the copy protection or encryption in computer programs that are obsolete. The exemption simply means that figuring out how these obsolete programs worked is not illegal according to the DMCA. It does not have any effect on the legality of making unauthorised copies of computer programs, which is what you are doing if you make copies of ROMs. But isn't it OK to download and "try" ROMs for 24 hours?This is an urban legend that was made up by people who made ROMs available for download from their web sites, in order to justify the fact that they were breaking the law. There is no provision like this in any copyright law. If I buy a cabinet with legitimate ROMs, can I set it up in a public place to make money?Probably not. ROMs are typically only licensed for personal, non-commercial purposes. But I've seen Ultracade and Global VR Classics cabinets out in public places? Why can they do it?Ultracade had two separate products. The Ultracade product is a commercial machine with commercial licenses to the games. These machines were designed to be put on location and make money, like traditional arcade machines. Their other product is the Arcade Legends series. These are home machines with non- commercial licenses for the games, and can only be legally operated in a private environment. Since their buyout by Global VR they only offer the Global VR Classics cabinet, which is equivalent to the earlier Ultracade product. HELP! I'm getting a black screen or an error message in regards to DirectX on Windows!You probably have missing or damaged DirectX runtimes. You can download the latest DirectX setup tool from Microsoft at https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=35 Additional troubleshooting information can be found on Microsoft's website at https://support.microsoft.com/en-us/kb/179113 I have a controller that doesn't want to work with the standard Microsoft Windows version of MAME, what can I do?By default, MAME on Microsoft Windows tries to read joystick(s), mouse/mice and keyboard(s) using the RawInput API. This works with most devices, and allows multiple keyboards and mice to be used independently. However, some device drivers are not compatible with RawInput, and it may be necessary to use DirectInput or window events to receive input. This is also the case for most software that simulates mouse or keyboard input, like JoyToKey, VNC or Remote Desktop. You can try changing the keyboardprovider, mouseprovider, joystickprovider or lightgunprovider setting (depending on which kind of device you’re having issues with) from rawinput to one of the other options such as dinput or win32. See OSD-related Options for details on input provider options What happened to the MAME support for external OPL2-carrying soundcards?MAME 0.23 added support for using a sound card’s onboard OPL2 (Yamaha YM3812 chip) instead of emulating the OPL2. This feature was only supported for DOS – it was never supported in official Windows versions of MAME. It dropped entirely as of MAME 0.60, as the OPL2 emulation in MAME had become advanced enough to be a better solution in almost all cases. MAME’s OPL2 emulation is now superior to using a sound card’s YM3812 in all cases, especially as modern sound cards lack a YM3812. What happened to the MAME support for autofire?A Lua plugin providing enhanced autofire support was added in MAME 0.210, and the built-in autofire functionality was removed in MAME 0.216. This plugin has more functionality than the built-in autofire feature it replaced; for example, you can configure alternate buttons for different autofire rates. You can enable and configure the new autofire system with the following steps:
The setting will be automatically saved for future use. See Autofire Plugin for more information about using the autofire plugin, or Plugins for more information about using plugins with MAME in general. Does MAME support G-Sync or FreeSync? How do I configure MAME to use them?MAME supports both G-Sync and FreeSync right out of the box for Windows and Linux, however macOS does not support G-Sync or FreeSync.
The effects of G-Sync and FreeSync will be most noticeable in drivers that run at refresh rates that are very different from normal PC refresh rates. For instance, the first three Mortal Kombat titles run at 54.706841Hz. MAME COMMAND-LINE USAGE AND OS-SPECIFIC CONFIGURATIONUniversal Command-line OptionsThis section contains configuration options that are applicable to all MAME configurations (including both SDL and Windows native).
Commands and VerbsCommands include mame itself as well as various tools included with the MAME distribution such as romcmp and srcclean. Verbs are actions to take upon something with the command (e.g. mame -validate pacman has mame as a command and -validate as a verb) PatternsMany verbs support the use of patterns, which are either a system or device short name (e.g. a2600, zorba_kbd) or a glob pattern that matches either (e.g. zorba_*). Depending on the command you're using the pattern with, pattern matching may match systems or systems and devices. It is advised to put quotes around your patterns to avoid having your shell try to expand them against filenames (e.g. mame -validate "pac*"). File Names and Directory PathsA number of options for specifying directories support multiple paths (for example to search for ROMs in multiple locations). MAME expects multiple paths to be separated with semicolons ( ; ). MAME expands environment variable expressions in paths. The syntax used depends on your operating system. On Windows, % (percent) syntax is used. For example %APPDATA%\mame\cfg will expand the application data path for the current user's roaming profile. On UNIX-like system (including macOS and Linux), Bourne shell syntax is used, and a leading ~ expands to the current user's home directory. For example, ~/.mame/${HOSTNAME}/cfg expands to a host-specific path inside the .mame directory in the current user's home directory. Note that only simple variable substitutions are supported; more complex expressions supported by Bash, ksh or zsh are not recognized by MAME. Relative paths are resolved relative to the current working directory. If you start MAME by double-clicking it in Windows Explorer, the working directory is set to the folder containing the MAME executable. If you start MAME by double-clicking it in the macOS Finder, it will open a Terminal window with the working directory is set to your home directory (usually /Users/<username> ) and start MAME. If you want behaviour similar to what Windows Explorer provides on macOS, create a script file containing these lines in the directory containing the MAME executable (for example you could call it mame-here ): #!/bin/sh cd "`dirname "$0"`" exec ./mame You should be able to use any text editor. If you have a choice of file format or line ending style, choose UNIX. This assumes you're using a 64-bit release build of MAME, but if you aren't you just need to change mame to the name of your MAME executable (e.g. mamed, mamep, mamedp). Once you've created the file, you need to mark it as executable. You can do this by opening a Terminal window, typing chmod a+x followed by a space, dragging the file you created onto the window (this causes Terminal to insert the full escaped path to the file), and then ensuring the Terminal window is active and hitting Return (or Enter) on your keyboard. You can close the Terminal window after doing this. Now if you double-click the script in the Finder, it will open a Terminal window, set the working directory to the location of the script (i.e. the folder containing MAME), and then start MAME. Core VerbsTIP: Examples that have the output abbreviated for space
reasons will show "..." in the output where needed. For
instance: .. code-block:: bash
A B C ... Z
-help / -h / -? Displays current MAME version and copyright notice.
-validate / -valid [<pattern>] Performs internal validation on one or more drivers and
devices in the system. Run this before submitting changes to ensure that you
haven't violated any of the core system rules.
If a pattern is specified, it will validate systems matching the pattern, otherwise it will validate all systems and devices. Note that if a pattern is specified, it will be matched against systems only (not other devices), and no device type validation will be performed. mame -validate Driver ace100 (file apple2.cpp): 1 errors, 0 warnings Errors: Software List device 'flop525_orig': apple2_flop_orig.xml: Errors parsing software list: apple2_flop_orig.xml(126.2): Unknown tag: year apple2_flop_orig.xml(126.8): Unexpected content apple2_flop_orig.xml(127.2): Unknown tag: publisher apple2_flop_orig.xml(127.13): Unexpected content apple2_flop_orig.xml(128.2): Unknown tag: info apple2_flop_orig.xml(129.2): Unknown tag: sharedfeat apple2_flop_orig.xml(132.2): Unknown tag: part apple2_flop_orig.xml(133.3): Tag dataarea found outside of software context apple2_flop_orig.xml(134.4): Tag rom found outside of part context apple2_flop_orig.xml(137.3): mismatched tag Configuration Verbs-createconfig / -cc Creates the default mame.ini file. All the
configuration options (not verbs) described below can be permanently changed
by editing this configuration file.
-showconfig / -sc Displays the current configuration settings. If you route
this to a file, you can use it as an INI file.
-showusage / -su Displays a summary of all the command line options. For
options that are not mentioned here, the short summary given by "mame
-showusage" is usually a sufficient description.
Frontend VerbsNote: By default, all the '-list' verbs below write info to the standard output (usually the terminal/command window where you typed the command). If you wish to write the info to a text file instead, add this to the end of your command: > filename
where filename is the name of the file to save the output in (e.g. list.txt ). Note that if this file already exists, it will be completely overwritten. This creates (or overwrites the existing file if already there) list.txt and fills the file with the results of -listcrc puckman. In other words, the list of each ROM used in Puckman and the CRC for that ROM are written into that file. -listxml / -lx [<pattern>...] List comprehensive details for all of the supported
systems and devices in XML format. The output is quite long, so it is usually
better to redirect this into a file. By default all systems are listed;
however, you can limit this list by specifying one or more patterns
after the -listxml verb.
This XML output is typically imported into other tools (like graphical front-ends and ROM managers), or processed with scripts query detailed information. mame galaxian -listxml <?xml version="1.0"?> <!DOCTYPE mame [ <!ELEMENT mame (machine+)> TIP: Output from this command is typically more useful if
redirected to an output file. For instance, doing mame -listxml galaxian
> galax.xml will make galax.xml or overwrite any existing data
in the file with the results of -listxml; this will allow you to view
it in a text editor or parse it with external tools.
-listfull / -ll [<pattern>...] mame -listfull galaxian* Name: Description: galaxian "Galaxian (Namco set 1)" galaxiana "Galaxian (Namco set 2)" galaxianbl "Galaxian (bootleg, set 2)" galaxianbl2 "Galaxian (bootleg, set 4)" galaxiani "Galaxian (Irem)" galaxianm "Galaxian (Midway set 1)" galaxianmo "Galaxian (Midway set 2)" galaxiant "Galaxian (Taito)" galaxian_sound "Galaxian Custom Sound" Displays a list of system driver names and descriptions. By default all systems and devices are listed; however, you can limit this list by specifying one or more patterns after the -listfull verb. -listsource / -ls [<pattern>...] Displays a list of system drivers/devices and the names
of the source files where they are defined. Useful for finding which driver a
system runs on in order to fix bugs. By default all systems and devices are
listed; however, you can limit this list by specifying one or more
pattern after the -listsource verb.
-listclones / -lc [<pattern>] Displays a list of clones. By default all clones are
listed; however, you can limit this list by specifying a pattern after
the -listsource verb. If a pattern is specified, MAME will list clones
of systems that match the pattern, as well as clones that match the pattern
themselves.
mame pacman -listclones Name: Clone of: pacman puckman
mame puckman -listclones Name: Clone of: abscam puckman bucaner puckman crockman puckman crockmnf puckman ... puckmod puckman titanpac puckman -listbrothers / -lb [<pattern>] Displays a list of brothers, i.e. other systems
that are defined in the same source file as a system that matches the
specified pattern.
mame galaxian -listbrothers Source file: Name: Parent: galaxian.cpp amidar galaxian.cpp amidar1 amidar galaxian.cpp amidarb amidar ... galaxian.cpp zigzagb galaxian.cpp zigzagb2 zigzagb -listcrc [<pattern>...] Displays a full list of CRCs and names of all ROM images
referenced by systems and devices matching the specified pattern(s). If no
patterns are specified, ROMs referenced by all supported systems and devices
will be included.
mame playch10 -listcrc d52fa07a pch1-c__8t_e-2.8t playch10 PlayChoice-10 BIOS 503ee8b1 pck1-c.8t playch10 PlayChoice-10 BIOS 123ffa37 pch1-c_8te.8t playch10 PlayChoice-10 BIOS 0be8ceb4 pck1-c_fix.8t playch10 PlayChoice-10 BIOS 9acffb30 pch1-c__8k.8k playch10 PlayChoice-10 BIOS c1232eee pch1-c__8m_e-1.8m playch10 PlayChoice-10 BIOS 30c15e23 pch1-c__8p_e-1.8p playch10 PlayChoice-10 BIOS 9acffb30 pch1-c__8k.8k playch10 PlayChoice-10 BIOS c1232eee pch1-c__8m_e-1.8m playch10 PlayChoice-10 BIOS 30c15e23 pch1-c__8p_e-1.8p playch10 PlayChoice-10 BIOS 9acffb30 pch1-c__8k.8k playch10 PlayChoice-10 BIOS 83ebc7a3 pch1-c_8m.8m playch10 PlayChoice-10 BIOS 90e1b80c pch1-c_8p-8p playch10 PlayChoice-10 BIOS 9acffb30 pch1-c__8k.8k playch10 PlayChoice-10 BIOS c1232eee pch1-c__8m_e-1.8m playch10 PlayChoice-10 BIOS 30c15e23 pch1-c__8p_e-1.8p playch10 PlayChoice-10 BIOS e5414ca3 pch1-c-6f.82s129an.6f playch10 PlayChoice-10 BIOS a2625c6e pch1-c-6e.82s129an.6e playch10 PlayChoice-10 BIOS 1213ebd4 pch1-c-6d.82s129an.6d playch10 PlayChoice-10 BIOS 48de65dc rp2c0x.pal playch10 PlayChoice-10 BIOS -listroms / -lr [<pattern>...] Displays a list of ROM images referenced by supported
systems/devices that match the specified pattern(s). If no patterns are
specified, the results will include all supported systems and devices.
mame neogeo -listroms ROMs required for driver "neogeo". Name Size Checksum sp-s2.sp1 131072 CRC(9036d879) SHA1(4f5ed7105b7128794654ce82b51723e16e389543) sp-s.sp1 131072 CRC(c7f2fa45) SHA1(09576ff20b4d6b365e78e6a5698ea450262697cd) sp-45.sp1 524288 CRC(03cc9f6a) SHA1(cdf1f49e3ff2bac528c21ed28449cf35b7957dc1) ... sm1.sm1 131072 CRC(94416d67) SHA1(42f9d7ddd6c0931fd64226a60dc73602b2819dcf) 000-lo.lo 131072 CRC(5a86cff2) SHA1(5992277debadeb64d1c1c64b0a92d9293eaf7e4a) sfix.sfix 131072 CRC(c2ea0cfd) SHA1(fd4a618cdcdbf849374f0a50dd8efe9dbab706c3) -listsamples [<pattern>] Displays a list of samples referenced by the specified
pattern of system or device names. If no pattern is specified, the results
will be all systems and devices.
mame armorap -listsamples Samples required for driver "armorap". loexp jeepfire hiexp tankfire tankeng beep chopper -verifyroms [<pattern>] Checks for invalid or missing ROM images. By default all
drivers that have valid ZIP files or directories in the rompath are verified;
however, you can limit this list by specifying a pattern after the
-verifyroms command.
-verifysamples [<pattern>] Checks for invalid or missing samples. By default all
drivers that have valid ZIP files or directories in the samplepath are
verified; however, you can limit this list by specifying a pattern
after the -verifyroms command.
mame armorap -verifysamples sampleset armorap [armora] is good 1 samplesets found, 1 were OK. -romident [path/to/romstocheck.zip] Attempts to identify ROM files, if they are known to
MAME, in the specified .zip file or directory. This command can be used to try
and identify ROM sets taken from unknown boards. On exit, the errorlevel is
returned as one of the following:
mame unknown.rom -romident Identifying unknown.rom.... unknown.rom = 456-a07.17l gradius Gradius (Japan, ROM version) -listdevices / -ld [<pattern>] Displays a list of all devices known to be hooked up to a
system. The ":" is considered the system itself with the devices
list being attached to give the user a better understanding of what the
emulation is using.
If slots are populated with devices, any additional slots those devices provide will be visible with -listdevices as well. For instance, installing a floppy controller into a PC will expose the disk drive slots. mame apple2e -listdevices Driver apple2e (Apple //e): -listslots / -lslot [<pattern>] Show available slots and options for each slot (if
available). Primarily used for MAME to allow control over internal plug-in
cards, much like PCs needing video, sound and other expansion cards.
If slots are populated with devices, any additional slots those devices provide will be visible with -listslots as well. For instance, installing a floppy controller into a PC will expose the disk drive slots. The slot name (e.g. ctrl1) can be used from the command line (-ctrl1 in this case) mame apple2e -listslots SYSTEM SLOT NAME SLOT OPTIONS SLOT DEVICE NAME ---------------- ---------------- ---------------- ---------------------------- apple2e sl1 4play 4play Joystick Card (rev. B) -listbios [<pattern>] Show available BIOS options for a system (if available).
BIOS options may be available for the system or any devices selected as slot
options.
If no pattern is specified, the results will include all supported systems. mamed -listbios apple2 -sl2 grapplus -sl4 videoterm BIOS options for system Apple ][ (apple2): -listmedia / -lm [<pattern>] List available media that the chosen system allows to be
used. This includes media types (cartridge, cassette, diskette and more) as
well as common file extensions which are supported.
mame coco3 -listmedia SYSTEM MEDIA NAME (brief) IMAGE FILE EXTENSIONS SUPPORTED ---------------- --------------------------- ------------------------------- coco3 cassette (cass) .wav .cas -listsoftware / -lsoft [<pattern>] Displays the contents of all software lists that can be
used by the system or systems represented by pattern.
mame coco3 -listsoftware <?xml version="1.0"?> <!DOCTYPE softwarelists [ <!ELEMENT softwarelists (softwarelist*)> -verifysoftware / -vsoft [<pattern>] Checks for invalid or missing ROM images in your software
lists. By default all drivers that have valid ZIP files or directories in the
rompath are verified; however, you can limit this list by specifying a
specific driver name or pattern after the -verifysoftware
command.
mame coco3 -verifysoftware romset coco_cart:7cardstd is good coco_cart:amazing: a mazing world of malcom mortar (1987)(26-3160)(zct systems).rom (16384 bytes) - NEEDS REDUMP romset coco_cart:amazing is best available coco_cart:amazing1: a mazing world of malcom mortar (1987)(26-3160)(zct systems)[a].rom (16384 bytes) - NEEDS REDUMP romset coco_cart:amazing1 is best available romset coco_cart:androne is good ... -getsoftlist / -glist [<pattern>] Displays the contents of a specific softlist with the
filename represented by pattern.
mame -getsoftlist apple2_flop_orig <?xml version="1.0"?> <!DOCTYPE softwarelists [ <!ELEMENT softwarelists (softwarelist*)> -verifysoftlist / -vlist [softwarelistname] Checks a specified software list for missing ROM images
if files exist for issued softwarelistname. By default, all drivers that have
valid ZIP files or directories in the rompath are verified; however, you can
limit this list by specifying a specific softwarelistname (without .XML) after
the -verifysoftlist command.
mame -verifysoftlist apple2_flop_orig romset apple2_flop_orig:agentusa is good romset apple2_flop_orig:airheart is good romset apple2_flop_orig:aplpanic is good romset apple2_flop_orig:alambush is good romset apple2_flop_orig:ankh is good romset apple2_flop_orig:aplcdspd is good romset apple2_flop_orig:agalxian is good romset apple2_flop_orig:aquatron is good romset apple2_flop_orig:archon is good romset apple2_flop_orig:archon2 is good romset apple2_flop_orig:ardyardv is good romset apple2_flop_orig:autobahn is good ... OSD-related Options-uimodekey [keystring] Key used to enable/disable MAME keyboard controls when
the emulated system has keyboard inputs. The default setting is Forward
Delete on macOS or SCRLOCK on other operating systems (including
Windows and Linux). Use FN-Delete on Macintosh computers with
notebook/compact keyboards.
-controller_map / -ctrlmap <filename> Path to a text file containing game controller button and
axis mappings in the format used by SDL2 and Steam, or none to use only
built-in mappings. Must use an ASCII-compatible text encoding with native line
endings (e.g. CRLF on Windows). Currently only supported when using the
sdlgame joystick provider. The default setting is none.
A community-sourced list of game controller mappings can be found on GitHub. Besides using a text editor, several tools are available for creating game controller mappings, including SDL2 Gamepad Mapper and SDL2 ControllerMap which is supplied with SDL. You can also configure your controller in Steam’s Big Picture mode, then copy the mappings from SDL_GamepadBind entries in the config.vdf file found in the config folder inside your Steam installation folder. -[no]background_input Sets whether input is accepted or ignored when MAME does
not have UI focus. This setting is ignored when the debugger is enabled. The
default is OFF (-nobackground_input).
Currently supported for RawInput mouse/keyboard input, DirectInput mouse/keyboard/joystick input and XInput joystick input on Windows, and SDL game controller/joystick input. -uifontprovider <module> Chooses provider for UI font rendering. The default
setting is auto.
Supported UI font providers per-platform
FOOTNOTES
-keyboardprovider <module> Chooses how MAME will get keyboard input. The default is
auto.
Supported keyboard input providers per-platform
FOOTNOTES
Note that user-mode keyboard emulation tools such as
joy2key will almost certainly require the use of -keyboardprovider
win32 on Windows machines.
-mouseprovider <module> Chooses how MAME will get mouse input. The default is
auto.
Supported mouse input providers per-platform
FOOTNOTES
-lightgunprovider <module> Chooses how MAME will get light gun input. The default is
auto.
Supported light gun input providers per-platform
FOOTNOTES
-joystickprovider <module> Chooses how MAME will get joystick and other game
controller input. The default is auto.
Supported joystick input providers per-platform
FOOTNOTES
mame mk2 -joystickprovider winhybrid -midiprovider <module> Chooses how MAME will communicate with MIDI devices and
applications (e.g. music keyboards and synthesisers). Supported options are
pm to use the PortMidi library, or none to disable MIDI input
and output (MIDI files can still be played). The default is auto, which
will use PortMidi if available.
-networkprovider <module> Chooses how MAME will provide communication for emulated
packet-oriented network interfaces (e.g. Ethernet cards). Supported options
are taptun to use the TUN/TAP, TAP-Windows or similar, pcap to
use a pcap library, or none to disable communication for emulated
network interfaces. Available options depend on your operating system. By
default, taptun and none are available on Windows and Linux, and
pcap and none are available on macOS.
The default is auto which will use taptun if available, falling back to pcap. OSD Command-Line Verbs-listmidi List available MIDI I/O devices for use with emulation.
mame -listmidi MIDI input ports: MIDI output ports: Microsoft MIDI Mapper (default) Microsoft GS Wavetable Synth -listnetwork List available network adapters for use with emulation.
mame -listnetwork No network adapters were found
mame -listnetwork Available network adapters: TIP: On Windows, you'll need the TAP driver from OpenVPN for
MAME to see any network adapters.
OSD Output Options-output Chooses how MAME will handle processing of output
notifiers. These are used to connect external outputs such as the LED lights
for the Player 1/2 start buttons on certain arcade machines.
You can choose from: auto, none, console or network Note that network port is fixed at 8000. Configuration Options-[no]readconfig / -[no]rc Enables or disables the reading of the config files. When
enabled (which is the default), MAME reads the following config files in
order:
(See Order of Config Loading for further details) The settings in the later INIs override those in the earlier INIs. So, for example, if you wanted to disable overlay effects in the vector systems, you can create a vector.ini with line effect none in it, and it will override whatever effect value you have in your mame.ini. The default is ON (-readconfig). Core Search Path Options-homepath <path> Specifies a path for Lua plugins to store data.
The default is . (that is, in the current working directory). -rompath / -rp <path> Specifies one or more paths within which to find ROM or
disk images. Multiple paths can be specified by separating them with
semicolons.
The default is roms (that is, a directory roms in the current working directory). -hashpath / -hash_directory / -hash <path> Specifies one or more paths within which to find software
definition files. Multiple paths can be specified by separating them with
semicolons.
The default is hash (that is, a directory hash in the current working directory). -samplepath / -sp <path> Specifies one or more paths within which to find audio
sample files. Multiple paths can be specified by separating them with
semicolons.
The default is samples (that is, a directory samples in the current working directory). -artpath <path> Specifies one or more paths within which to find external
layout and artwork files. Multiple paths can be specified by separating them
with semicolons.
The default is artwork (that is, a directory artwork in the current working directory). -ctrlrpath <path> Specifies one or more paths within which to find
controller configuration files. Multiple paths can be specified by separating
them with semicolons. Used in conjunction with the -ctrlr option.
The default is ctrlr (that is, a directory ctrlr in the current working directory). -inipath <path> Specifies one or more paths within which to find INI
files. Multiple paths can be specified by separating them with semicolons.
On Windows, the default is .;ini;ini/presets (that is, search in the current directory first, then in the directory ini in the current working directory, and finally the directory presets inside that directory). On macOS, the default is $HOME/Library/Application Support/mame;$HOME/.mame;.;ini (that is, search the mame folder inside the current user's Application Support folder, followed by the .mame folder in the current user's home directory, then the current working directory, and finally the directory ini in the current working directory). On other platforms (including Linux), the default is $HOME/.mame;.;ini (that is search the .mame directory in the current user's home directory, followed by the current working directory, and finally the directory ini in the current working directory). -fontpath <path> Specifies one or more paths within which to find BDF
(Adobe Glyph Bitmap Distribution Format) font files. Multiple paths can be
specified by separating them with semicolons.
The default is . (that is, search in the current working directory). -cheatpath <path> Specifies one or more paths within which to find XML
cheat files. Multiple paths can be specified by separating them with
semicolons.
The default is cheat (that is, a folder called cheat located in the current working directory). -crosshairpath <path> Specifies one or more paths within which to find
crosshair image files. Multiple paths can be specified by separating them with
semicolons.
The default is crsshair (that is, a directory crsshair in the current working directory). -pluginspath <path> Specifies one or more paths within which to find Lua
plugins for MAME.
The default is plugins (that is, a directory plugins in the current working directory). -languagepath <path> Specifies one or more paths within which to find language
files for localized UI text.
The default is language (that is, a directory language in the current working directory). -swpath <path> Specifies the default path from which to load loose
software image files.
The default is sofware (that is, a directory software in the current working directory). Core Output Directory Options-cfg_directory <path> Specifies the directory where configuration files are
stored. Configuration files are read when starting MAME or when starting an
emulated machine, and written on exit. Configuration files preserve settings
including input assignment, DIP switch settings, bookkeeping statistics, and
debugger window arrangement.
The default is cfg (that is, a directory cfg in the current working directory). If this directory does not exist, it will be created automatically. -nvram_directory <path> Specifies the directory where NVRAM files are stored.
NVRAM files store the contents of EEPROM, non-volatile RAM (NVRAM), and other
programmable devices for systems that used this type of hardware. This data is
read when starting an emulated machine and written on exit.
The default is nvram (that is, a directory nvram in the current working directory)). If this directory does not exist, it will be created automatically. -input_directory <path> Specifies the directory where input recording files are
stored. Input recordings are created using the -record option and
played back using the -playback option.
The default is inp (that is, a directory inp in the current working directory). If this directory does not exist, it will be created automatically. -state_directory <path> Specifies the directory where save state files are
stored. Save state files are read and written either upon user request, or
when using the -autosave option.
The default is sta (that is, a directory sta in the current working directory). If this directory does not exist, it will be created automatically. -snapshot_directory <path> Specifies the directory where screen snapshots and video
recordings are stored when requested by the user.
The default is snap (that is, a directory snap in the current working directory). If this directory does not exist, it will be created automatically. -diff_directory <path> Specifies the directory where hard drive difference files
are stored. Hard drive difference files store data that is written back to an
emulated hard disk, in order to preserve the original image file. The
difference files are created when starting an emulated system with a
compressed hard disk image.
The default is diff (that is, a directory diff in the current working directory). If this directory does not exist, it will be created automatically. -comment_directory <path> Specifies a directory where debugger comment files are
stored. Debugger comment files are written by the debugger when comments are
added to the disassembly for a system.
The default is comments (that is, a directory comments in the current working directory). If this directory does not exist, it will be created automatically. Core State/Playback Options-[no]rewind When enabled and emulation is paused, automatically
creates a save state in memory every time a frame is advanced. Rewind save
states can then be loaded consecutively by pressing the rewind single step
shortcut key (Left Shift + Tilde by default).
The default rewind value is OFF (-norewind). If debugger is in a 'break' state, a save state is instead created every time step in, step over, or step out occurs. In that mode, rewind save states can be loaded by executing the debugger rewind (or rw) command. -rewind_capacity <value> Sets the rewind capacity value, in megabytes. It is the
total amount of memory rewind savestates can occupy. When capacity is hit, old
savestates get erased as new ones are captured. Setting capacity lower than
the current savestate size disables rewind. Values below 0 are automatically
clamped to 0.
-state <slot> Immediately after starting the specified system, will
cause the save state in the specified <slot> to be loaded.
-[no]autosave When enabled, automatically creates a save state file
when exiting MAME and automatically attempts to reload it when later starting
MAME with the same system. This only works for systems that have explicitly
enabled save state support in their driver.
The default is OFF (-noautosave). -playback / -pb <filename> Specifies a file from which to play back a series of
inputs. This feature does not work reliably for all systems, but can be used
to watch a previously recorded game session from start to finish.
The default is NULL (no playback). TIP: You may experience desync in playback if the
configuration, NVRAM, and memory card files don't match the original; this is
why it is suggested you should only record and playback with all configuration
(.cfg), NVRAM (.nv), and memory card files deleted.
-[no]exit_after_playback When used in conjunction with the -playback
option, MAME will exit after playing back the input file. By default, MAME
continues to run the emulated system after playback completes.
The default is OFF (-noexit_after_playback). -record / -rec <filename> Specifies a file to record all input from a session. This
can be used to record a session for later playback. This feature does not work
reliably for all systems, but can be used to record a session from start to
finish.
The default is NULL (no recording). TIP: You may experience desync in playback if the
configuration, NVRAM, and memory card files don't match the original; this is
why it is suggested you should only record and playback with all configuration
(.cfg), NVRAM (.nv), and memory card files deleted.
-mngwrite <filename> Writes each video frame to the given <filename> in
MNG format, producing an animation of the session. Note that -mngwrite
only writes video frames; it does not save any audio data. Either use
-wavwrite to record audio and combine the audio and video tracks using
video editing software, or use -aviwrite to record audio and video to a
single file.
The default is NULL (no recording). -aviwrite <filename> Stream video and sound data to the given <filename>
in uncompressed AVI format, producing an animation of the session complete
with sound. Note that the AVI format does not changes to resolution or frame
rate, uncompressed video consumes a lot of disk space, and recording
uncompressed video in realtime requires a fast disk. It may be more practical
to record an emulation session using -record then make a video of it
with -aviwrite in combination with -playback and
-exit_after_playback options.
The default is NULL (no recording). -wavwrite <filename> Writes the final mixer output to the given
<filename> in WAV format, producing an audio recording of the session.
The default is NULL (no recording). -snapname <name> Describes how MAME should name files for snapshots.
<name> is a string that provides a template that is used to generate a
filename.
Three simple substitutions are provided: the / character represents the path separator on any target platform (even Windows); the string %g represents the driver name of the current system; and the string %i represents an incrementing index. If %i is omitted, then each snapshot taken will overwrite the previous one; otherwise, MAME will find the next empty value for %i and use that for a filename. The default is %g/%i, which creates a separate folder for each system, and names the snapshots under it starting with 0000 and increasing from there. In addition to the above, for drivers using different media, like carts or floppy disks, you can also use the %d_[media] indicator. Replace [media] with the media switch you want to use.
mame robby -snapname foo\%g%i Snapshots will be saved as snaps\foo\robby0000.png, snaps\foo\robby0001.png and so on.
mame nes -cart robby -snapname %g\%d_cart Snapshots will be saved as snaps\nes\robby.png.
mame c64 -flop1 robby -snapname %g\%d_flop1/%i Snapshots will be saved as snaps\c64\robby\0000.png. -snapsize <width>x<height> Hard-codes the size for snapshots and movie recording. By
default, MAME will create snapshots at the system's current resolution in raw
pixels, and will create movies at the system's starting resolution in raw
pixels. If you specify this option, then MAME will create both snapshots and
movies at the size specified, and will bilinear filter the result.
The default is auto. TIP: -snapsize does not automatically rotate if the system is
vertically oriented, so for vertical systems you'll want to swap the width and
height options.
-snapview <viewname> Specifies the view to use when rendering snapshots and
videos. The <viewname> does not need to be the full name of a
view, MAME will choose the first view with a name that has the
<viewname> as a prefix. For example -snapview "screen 0
pixel" will match the “Screen 0 Pixel Aspect
(10:7)” view.
If the <viewname> is auto or an empty string, MAME will select a view based on the number of emulated screens in the system, and the available external and internal artwork. MAME tries to select a view that shows all emulated screens by default. If the <viewname> is native, MAME uses special internal view to save a separate snapshot for each visible emulated screen, or to record a video for the first visible screen only. The snapshot(s) or video will have the same resolution as the emulated screen(s) with no artwork elements drawn or effects applied. The default value is auto. -[no]snapbilinear Specify if the snapshot or movie should have bilinear
filtering applied. Disabling this off can improve performance while recording
video to a file.
The default is ON (-snapbilinear). -statename <name> Describes how MAME should store save state files,
relative to the state_directory path. <name> is a string that provides a
template that is used to generate a relative path.
Two simple substitutions are provided: the / character represents the path separator on any target platform (even Windows); the string %g represents the driver name of the current system. The default is %g, which creates a separate folder for each system. In addition to the above, for drivers using different media, like carts or floppy disks, you can also use the %d_[media] indicator. Replace [media] with the media switch you want to use.
mame robby -statename foo\%g All save states will be stored inside sta\foo\robby\
mame nes -cart robby -statename %g/%d_cart All save states will be stored inside sta\nes\robby\
mame c64 -flop1 robby -statename %g/%d_flop1 All save states will be stored inside sta\c64\robby\ TIP: Note that even on Microsoft Windows, you should use
/ as your path seperator for -statename
-[no]burnin Tracks brightness of the screen during play and at the
end of emulation generates a PNG that can be used to simulate burn-in effects
on other systems. The resulting PNG is created such that the least used-areas
of the screen are fully white (since burned-in areas are darker, all other
areas of the screen must be lightened a touch).
The intention is that this PNG can be loaded via an artwork file with a low alpha (e.g, 0.1-0.2 seems to work well) and blended over the entire screen. The PNG files are saved in the snap directory under the <systemname>/burnin-<screen.name>.png. The default is OFF (-noburnin). Core Performance Options-[no]autoframeskip / -[no]afs Dynamically adjust the frameskip level while you're
running the system to maintain full speed. Turning this on overrides the
-frameskip setting described below.
This is off by default (-noautoframeskip). -frameskip / -fs <level> Specifies the frameskip value. This is the number of
frames out of every 12 to drop when running. For example, if you specify
-frameskip 2, MAME will render and display 10 out of every 12 emulated
frames. By skipping some frames, you may be able to get full speed emulation
for a system that would otherwise be too demanding for your computer.
The default value is -frameskip 0, which skips no frames. -seconds_to_run / -str <seconds> This option tells MAME to automatically stop emulation
after a fixed number of seconds of emulated time have elapsed. This may be
useful for benchmarking and automated testing. By combining this with a fixed
set of other command line options, you can set up a consistent environment for
benchmarking MAME's emulation performance. In addition, upon exit, the
-str option will write a screenshot to the system's snapshot directory
with the file name determined by the -snapname option.
-[no]throttle Enable or disable throttling emulation speed. When
throttling is enabled, MAME limits emulation speed to so the emulated system
will not run faster than the original hardware. When throttling is disabled,
MAME runs the emulation as fast as possible. Depending on your settings and
the characteristics of the emulated system, performance may be limited by your
CPU, graphics card, or even memory performance.
The default is to enable throttling (-throttle). -[no]sleep When enabled along with -throttle, MAME will yield
the CPU when limiting emulation speed. This allows other programs to use CPU
time, assuming the main emulation thread isn't completely utilising a CPU
core. This option can potentially cause hiccups in performance if other
demanding programs are running.
The default is on (-sleep). -speed <factor> Changes the way MAME throttles the emulation so that it
runs at some multiple of the system's original speed. A <factor>
of 1.0 means to run the system at its normal speed, a
<factor> of 0.5 means run at half speed, and a
<factor> of 2.0 means run at double speed. Note that changing
this value affects sound playback as well, which will scale in pitch
accordingly. The internal precision of the fraction is two decimal places, so
a <factor> of 1.002 is rounded to 1.00.
The default is 1.0 (normal speed). -[no]refreshspeed / -[no]rs Allows MAME to adjust the emulation speed so that the
refresh rate of the first emulated screen does not exceed the slowest refresh
rate for any targeted monitors in your system. Thus, if you have a 60Hz
monitor and run a system that is designed to run at 60.6Hz, MAME will reduce
the emulation speed to 99% in order to prevent sound hiccups or other
undesirable side effects of running at a slower refresh rate.
The default is off (-norefreshspeed). -numprocessors / -np auto|<value> Specify the number of threads to use for work queues.
Specifying auto will use the value reported by the system or
environment variable OSDPROCESSORS. This value is internally limited to
four times the number of processors reported by the system.
The default is auto. -bench <n> Benchmark for <n> emulated seconds. This is
equivalent to the following options:
-str <n> -video none -sound none -nothrottle -[no]lowlatency This tells MAME to draw a new frame before throttling to
reduce input latency. This is particularly effective with VRR (Variable
Refresh Rate) displays.
This may cause frame pacing issues in the form of jitter with some systems (especially newer 3D-based systems or systems that run software akin to an operating system), so the default is off (-nolowlatency). Core Rotation Options-[no]rotate Rotate the system to match its normal state
(horizontal/vertical). This ensures that both vertically and horizontally
oriented systems show up correctly without the need to rotate your monitor. If
you want to keep the system displaying 'raw' on the screen the way it would
have in the arcade, turn this option OFF.
The default is ON (-rotate). -[no]ror -[no]rol Rotate the system screen to the right (clockwise) or left
(counter-clockwise) relative to either its normal state (if -rotate is
specified) or its native state (if -norotate is specified).
The default for both of these options is OFF (-noror -norol).
mame pacman -ror
mame pacman -rol -[no]autoror -[no]autorol These options are designed for use with pivoting screens
that only pivot in a single direction. If your screen only pivots clockwise,
use -autorol to ensure that the system will fill the screen either
horizontally or vertically in one of the directions you can handle. If your
screen only pivots counter-clockwise, use -autoror.
mame pacman -autoror
mame pacman -autorol TIP: If you have a display that can be rotated,
-autorol or -autoror will allow you to get a larger display for
both horizontal and vertical systems.
-[no]flipx -[no]flipy Flip (mirror) the system screen either horizontally
(-flipx) or vertically (-flipy). The flips are applied after the
-rotate and -ror/-rol options are applied.
The default for both of these options is OFF (-noflipx -noflipy).
mame -flipx pacman
mame -flipy suprmrio Core Video Options-video <bgfx|gdi|d3d|opengl|soft|accel|none> Specifies which video subsystem to use for drawing.
Options here depend on the operating system and whether this is an
SDL-compiled version of MAME.
Generally Available:
On Windows:
On other platforms (including SDL on Windows):
Defaults:
-numscreens <count> Tells MAME how many output windows or screens to create.
For most systems, a single output window is all you need, but some systems
originally used multiple screens (e.g. Darius and PlayChoice-10 arcade
machines). Some systems with front panel controls and/or status lights
also may let you put these in different windows/screens. Each screen (up to 4)
has its own independent settings for physical monitor, aspect ratio,
resolution, and view, which can be set using the options below.
The default is 1.
mame darius -numscreens 3
mame pc_cntra -numscreens 2 -[no]window / -[no]w Run MAME in either a window or full screen.
The default is OFF (-nowindow). -[no]maximize / -[no]max Controls initial window size in windowed mode. If it is
set on, the window will initially be set to the maximum supported size when
you start MAME. If it is turned off, the window will start out at the closest
possible size to the original size of the display; it will scale on only one
axis where non-square pixels are used. This option only has an effect when the
-window option is used.
The default is ON (-maximize). -[no]keepaspect / -[no]ka When enabled, MAME preserves the correct aspect ratio for
the emulated system's screen(s). This is most often 4:3 or 3:4 for CRT
monitors (depending on the orientation), though many other aspect ratios have
been used, such as 3:2 (Nintendo Game Boy), 5:4 (some workstations), and
various other ratios. If the emulated screen and/or artwork does not fill
MAME's screen or Window, the image will be centred and black bars will be
added as necessary to fill unused space (either above/below or to the left and
right).
When this option is disabled, the emulated screen and/or artwork will be stretched to fill MAME's screen or window. The image will be distorted by non-proportional scaling if the aspect ratio does not match. This is very pronounced when the emulated system uses a vertically-oriented screen and MAME stretches the image to fill a horizontally-oriented screen. On Windows, when this option is enabled and MAME is running in a window (not full screen), the aspect ratio will be maintained when you resize the window unless you hold the Control (or Ctrl) key on your keyboard. The window size will not be restricted when this option is disabled. The default is ON (-keepaspect). The MAME team strongly recommends leaving this option enabled. Stretching systems beyond their original aspect ratio will mangle the appearance of the system in ways that no filtering or shaders can repair. -[no]waitvsync Waits for the refresh period on your computer's monitor
to finish before starting to draw video to your screen. If this option is off,
MAME will just draw to the screen as a frame is ready, even if in the middle
of a refresh cycle. This can cause "tearing" artifacts, where the
top portion of the screen is out of sync with the bottom portion.
The effect of turning -waitvsync on differs a bit between combinations of different operating systems and video drivers. On Windows, -waitvsync will block until video blanking before allowing MAME to draw the next frame, limiting the emulated machine's framerate to that of the host display. Note that this option does not work with -video gdi mode in Windows. On macOS, -waitvsync does not block; instead the most recent completely drawn frame will be displayed at vblank. This means that if an emulated system has a higher framerate than your host display, emulated frames will be dropped periodically resulting in motion judder. On Windows, you should only need to turn this on in windowed mode. In full screen mode, it is only needed if -triplebuffer does not remove the tearing, in which case you should use -notriplebuffer -waitvsync. Note that SDL-based MAME support for this option depends entirely on your operating system and video drivers; in general it will not work in windowed mode so -video opengl and fullscreen give the greatest chance of success with SDL builds of MAME. The default is OFF (-nowaitvsync). -[no]syncrefresh Enables speed throttling only to the refresh of your
monitor. This means that the system's actual refresh rate is ignored; however,
the sound code still attempts to keep up with the system's original refresh
rate, so you may encounter sound problems.
This option is intended mainly for those who have tweaked their video card's settings to provide carefully matched refresh rate options. Note that this option does not work with -video gdi mode. The default is OFF (-nosyncrefresh). -prescale <amount> Controls the size of the screen images when they are
passed off to the graphics system for scaling. At the minimum setting of 1,
the screen is rendered at its original resolution before being scaled. At
higher settings, the screen is expanded in both axes by a factor of
<amount> using nearest-neighbor sampling before applying filters
or shaders. With -video d3d, this produces a less blurry image at the
expense of speed.
The default is 1. This is supported with all video output types ( bgfx, d3d, etc.) on Windows and is supported with BGFX and OpenGL on other platforms. -[no]filter / -[no]d3dfilter / -[no]flt Enable bilinear filtering on the system screen graphics.
When disabled, point filtering is applied, which is crisper but leads to
scaling artifacts. If you don't like the filtered look, you are probably
better off increasing the -prescale value rather than turning off
filtering altogether.
The default is ON (-filter). This is supported with OpenGL and D3D video on Windows and is ONLY supported with OpenGL on other platforms. Use bgfx_screen_chains in your INI file(s) to adjust filtering with the BGFX video system. -[no]unevenstretch Allow non-integer scaling factors allowing for great
window sizing flexibility.
The default is ON. (-unevenstretch) Core Full Screen Options-[no]switchres Enables resolution switching. This option is required for
the -resolution* options to switch resolutions in full screen mode.
On modern video cards, there is little reason to switch resolutions unless you are trying to achieve the "exact" pixel resolutions of the original systems, which requires significant tweaking. This is also true on LCD displays, since they run with a fixed resolution and switching resolutions on them is just silly. This option does not work with -video gdi and -video bgfx. The default is OFF (-noswitchres). Core Per-Window Options-screen <display> -screen0 <display> -screen1 <display> -screen2 <display> -screen3 <display> Specifies which physical monitor on your system you wish
to have each window use by default. In order to use multiple windows, you must
have increased the value of the -numscreens option. The name of each
display in your system can be determined by running MAME with the -verbose
option. The display names are typically in the format of:
\\\\.\\DISPLAYn, where 'n' is a number from 1 to the number of
connected monitors.
The default value for these options is auto, which means that the first window is placed on the first display, the second window on the second display, etc. The -screen0, -screen1, -screen2, -screen3 parameters apply to the specific window. The -screen parameter applies to all windows. The window-specific options override values from the all window option.
mame pc_cntra -numscreens 2 -screen0 \\.\DISPLAY1 -screen1 \\.\DISPLAY2
mame darius -numscreens 3 -screen0 \\.\DISPLAY1 -screen1 \\.\DISPLAY3 -screen2 \\.\DISPLAY2 TIP: Using -verbose will tell you which displays you
have on your system, where they are connected, and what their current
resolutions are.
TIP: Multiple Screens may fail to work correctly on some
Mac machines as of right now.
-aspect <width:height> / -screen_aspect <num:den> -aspect0 <width:height> -aspect1 <width:height> -aspect2 <width:height> -aspect3 <width:height> Specifies the physical aspect ratio of the physical
monitor for each window. In order to use multiple windows, you must have
increased the value of the -numscreens option. The physical aspect
ratio can be determined by measuring the width and height of the visible
screen image and specifying them separated by a colon.
The default value for these options is auto, which means that MAME assumes the aspect ratio is proportional to the number of pixels in the desktop video mode for each monitor. The -aspect0, -aspect1, -aspect2, -aspect3 parameters apply to the specific window. The -aspect parameter applies to all windows. The window-specific options override values from the all window option.
mame contra -aspect 16:9
mame pc_cntra -numscreens 2 -aspect0 16:9 -aspect1 5:4 -resolution <widthxheight[@refresh]> / -r <widthxheight[@refresh]> -resolution0 <widthxheight[@refresh]> / -r0 <widthxheight[@refresh]> -resolution1 <widthxheight[@refresh]> / -r1 <widthxheight[@refresh]> -resolution2 <widthxheight[@refresh]> / -r2 <widthxheight[@refresh]> -resolution3 <widthxheight[@refresh]> / -r3 <widthxheight[@refresh]> Specifies an exact resolution to run in. In full screen
mode, MAME will try to use the specific resolution you request. The width and
height are required; the refresh rate is optional. If omitted or set to 0,
MAME will determine the mode automatically. For example, -resolution
640x480 will force 640x480 resolution, but MAME is free to choose the
refresh rate. Similarly, -resolution 0x0@60 will force a 60Hz refresh
rate, but allows MAME to choose the resolution. The string auto is also
supported, and is equivalent to 0x0@0.
In window mode, this resolution is used as a maximum size for the window. This option requires the -switchres option as well in order to actually enable resolution switching with -video d3d. The default value for these options is auto. The -resolution0, -resolution1, -resolution2, -resolution3 parameters apply to the specific window. The -resolution parameter applies to all windows. The window-specific options override values from the all window option. -view <viewname> -view0 <viewname> -view1 <viewname> -view2 <viewname> -view3 <viewname> Specifies the initial view setting for each
window/screen. The <viewname> does not need to be the full name
of a view, MAME will choose the first view with a name that has the
<viewname> as a prefix. For example -view "screen 0
pixel" will match the “Screen 0 Pixel Aspect
(10:7)” view.
If the <viewname> is auto or an empty string, MAME will select views based on the number of emulated screens in the system, the number of windows/screens MAME is using, and the available external and internal artwork. MAME tries to select views so that all emulated screens are visible by default. The default value for these options is auto. The -view0, -view1, -view2, -view3 parameters apply to the specific window. The -view parameter applies to all windows. The window-specific options override values from the all windows option. Note that view settings saved in the configuration file for the machine take precedence over the initial view settings. If you change the selected views in the Video Options menu, this will be saved in the configuration file for the machine and take precedence over any initial views specified in INI files or on the command line. Core Artwork Options-[no]artwork_crop / -[no]artcrop Enable cropping of artwork to the system screen area
only. This means that vertically oriented systems running full screen can
display their artwork to the left and right sides of the screen. This option
can also be controlled via the Video Options menu in the user interface.
The default is OFF -noartwork_crop. TIP: -artwork_crop is great for widescreen displays.
You will get a full-sized system display and the artwork will fill the empty
space on the sides as much as possible.
-fallback_artwork Specifies fallback artwork if no external artwork or
internal driver layout is defined. If external artwork for the system is
present or a layout is included in the driver for the system, then that will
take precedence.
TIP: You can use fallback_artwork <artwork name>
in horizontal.ini and vertical.ini to specify different fallback
artwork choices for horizontal and vertical systems.
-override_artwork Specifies override artwork for external artwork and
internal driver layout.
Core Screen Options-brightness <value> Controls the default brightness, or black level, of the
system screens. This option does not affect the artwork or other parts of the
display. Using the MAME UI, you can individually set the brightness for each
system screen; this option controls the initial value for all visible system
screens. The standard and default value is 1.0. Selecting lower values
(down to 0.1) will produce a darkened display, while selecting higher values
(up to 2.0) will give a brighter display.
-contrast <value> Controls the contrast, or white level, of the system
screens. This option does not affect the artwork or other parts of the
display. Using the MAME UI, you can individually set the contrast for each
system screen; this option controls the initial value for all visible system
screens. The standard and default value is 1.0. Selecting lower values
(down to 0.1) will produce a dimmer display, while selecting higher values (up
to 2.0) will give a more saturated display.
-gamma <value> Controls the gamma, which produces a potentially
nonlinear black to white ramp, for the system screens. This option does not
affect the artwork or other parts of the display. Using the MAME UI, you can
individually set the gamma for each system screen; this option controls the
initial value for all visible system screens. The standard and default value
is 1.0, which gives a linear ramp from black to white. Selecting lower
values (down to 0.1) will increase the nonlinearity toward black, while
selecting higher values (up to 3.0) will push the nonlinearity toward white.
The default is 1.0. -pause_brightness <value> This controls the brightness level when MAME is paused.
The default value is 0.65. -effect <filename> Specifies a single PNG file that is used as an overlay
over any system screens in the video display. This PNG file is assumed to live
in the root of one of the artpath directories. The pattern in the PNG file is
repeated both horizontally and vertically to cover the entire system screen
areas (but not any external artwork), and is rendered at the target resolution
of the system image.
For -video gdi and -video d3d modes, this means that one pixel in the PNG will map to one pixel on your output display. The RGB values of each pixel in the PNG are multiplied against the RGB values of the target screen. The default is none, meaning no effect. Core Vector Options-beam_width_min <width> Sets the vector beam minimum width. The beam width varies
between the minimum and maximum beam widths as the intensity of the vector
drawn changes. To disable vector width changes based on intensity, set the
maximum equal to the minimum.
-beam_width_max <width> Sets the vector beam maximum width. The beam width varies
between the minimum and maximum beam widths as the intensity of the vector
drawn changes. To disable vector width changes based on intensity, set the
maximum equal to the minimum.
-beam_intensity_weight <weight> Sets the vector beam intensity weight. This value
determines how the intensity of the vector drawn affects the width. A value of
0 creates a linear mapping from intensity to width. Negative values mean that
lower intensities will increase the width toward maximum faster, while
positive values will increase the width toward maximum more slowly.
-beam_dot_size <scale> Scale factor to apply to the size of single-point dots in
vector games. Normally these are rendered according to the computed beam
width; however, it is common for this to produce dots that are difficult to
see. The beam_dot_size option applies a scale factor on top of the beam width
to help them show up better.
The default is 1. -flicker <value> Simulates a vector "flicker" effect, similar to
a vector monitor that needs adjustment. This option requires a float argument
in the range of 0.00 - 100.00 (0=none, 100=maximum).
The default is 0. Core Video OpenGL Feature OptionsThese options are for compatibility in -video opengl. If you report rendering artifacts you may be asked to try messing with them by the developers, but normally they should be left at their defaults which results in the best possible video performance. TIP: Examples are not provided for these options as MAMEdev
will provide suitable test options in the case of needing them for
debugging.
-[no]gl_forcepow2texture Always use only power-of-2 sized textures.
The default is OFF. (-nogl_forcepow2texture) -[no]gl_notexturerect Don't use OpenGL GL_ARB_texture_rectangle.
The default is ON. (-gl_notexturerect) -[no]gl_vbo Enable OpenGL VBO (Vertex Buffer Objects), if available.
The default is ON. (-gl_vbo) -[no]gl_pbo Enable OpenGL PBO (Pixel Buffer Objects), if available
(default on )
The default is ON. (-gl_pbo) Core Video OpenGL GLSL Options-[no]gl_glsl -gl_glsl_filter Use OpenGL GLSL shader-based filtering instead of fixed
function pipeline-based filtering.
0-plain, 1-bilinear, 2-bicubic The default is 1. (-gl_glsl_filter 1) -glsl_shader_mame0 -glsl_shader_mame1 ... -glsl_shader_mame9 Set a custom OpenGL GLSL shader effect to the internal
system screen in the given slot. MAME does not include a vast selection of
shaders by default; more can be found online.
mame suprmrio -gl_glsl -glsl_shader_mame0 NTSC/NTSC_chain -glsl_shader_mame1 CRT-geom/CRT-geom -glsl_shader_screen0 -glsl_shader_screen1 ... -glsl_shader_screen9 Set a custom OpenGL GLSL shader effect to the whole
scaled-up output screen that will be rendered by your graphics card. MAME does
not include a vast selection of shaders by default; more can be found online.
mame suprmrio -gl_glsl -glsl_shader_screen0 gaussx -glsl_shader_screen1 gaussy -glsl_shader_screen2 CRT-geom-halation Core Sound Options-samplerate <value> / -sr <value> Sets the audio sample rate. Smaller values (e.g. 11025)
cause lower audio quality but faster emulation speed. Higher values (e.g.
48000) cause higher audio quality but slower emulation speed.
The default is 48000. -[no]samples -[no]compressor Enable audio compressor. It temporarily reduces the
overall volume when the audio output is overdriven.
The default is ON (-compressor). -volume / -vol <value> Sets the initial sound volume. It can be changed later
with the user interface (see Keys section). The volume is an attenuation in
decibels: e.g. "-volume -12" will start with
-12 dB attenuation. Note that if the volume is changed in the user
interface it will be saved to the configuration file for the system. The value
from the configuration file for the system has priority over volume
settings in general INI files.
The default is 0 (no attenuation, or full volume). -sound <dsound | coreaudio | sdl | xaudio2 | portaudio | none> Specifies which sound subsystem to use. Selecting
none disables sound output altogether (sound hardware is still
emulated).
On Windows and Linux, portaudio is likely to give the lowest possible latency, while Mac users will find coreaudio provides the best results. When using the sdl sound subsystem, the audio API to use may be selected by setting the SDL_AUDIODRIVER environment variable. Available audio APIs depend on the operating system. On Windows, it may be necessary to set SDL_AUDIODRIVER=directsound if no sound output is produced by default. The default is dsound on Windows. On Mac, coreaudio is the default. On all other platforms, sdl is the default. Supported sound subsystems per-platform
FOOTNOTES
The exact behavior depends on the selected audio output
module. Smaller values provide less audio delay while requiring better system
performance. Higher values increase audio delay but may help avoid buffer
under-runs and audio interruptions.
The default is 1.
Core Input Options-[no]coin_lockout / -[no]coinlock Enables simulation of the "coin lockout"
feature that is implemented on a number of arcade game PCBs. It was up to the
operator whether or not the coin lockout outputs were actually connected to
the coin mechanisms. If this feature is enabled, then attempts to enter a coin
while the lockout is active will fail and will display a popup message in the
user interface (in debug mode). If this feature is disabled, the coin lockout
signal will be ignored.
The default is ON (-coin_lockout). -ctrlr <controller> Specifies a controller configuration file, typically used
to set more suitable default input assignments for special controllers.
Directories specified using the ctrlrpath option are searched.
Controller configuration files use a similar format to .cfg used to
save system settings. See Controller Configuration Files for more
details.
The default is NULL (no controller configuration file). -[no]mouse Controls whether or not MAME makes use of mouse
controllers. When this is enabled, you will likely be unable to use your mouse
for other purposes until you exit or pause the system. Supported mouse
controllers depend on your mouseprovider setting.
Note that if this setting is off (-nomouse), mouse input may still be enabled depending on the inputs present on the emulated system and your automatic input enable settings. In particular, the default is to enable mouse input when the emulated system has mouse inputs (-mouse_device mouse), so MAME will capture your mouse pointer when you run a system with mouse inputs unless you also change the mouse_device setting. The default is OFF (-nomouse). -[no]joystick / -[no]joy Controls whether or not MAME makes use of game
controllers (e.g. joysticks, gamepads and simulation controls). Supported game
controllers depend on your joystickprovider setting.
When this is enabled, MAME will ask the system about which controllers are connected. Note that if this setting is off (-nojoystick), joystick input may still be enabled depending on the inputs present on the emulated system and your automatic input enable settings. The default is OFF (-nojoystick). -[no]lightgun / -[no]gun Controls whether or not MAME makes use of lightgun
controllers. Note that most lightguns also produce mouse input, so enabling
mouse and lightgun controllers simultaneously (using -lightgun and
-mouse together) may produce strange behaviour. Supported lightgun
controllers depend on your lightgunprovider setting.
Note that if this setting is off (-nolightgun), lightgun input may still be enabled depending on the inputs present on the emulated system and your automatic input enable settings. The default is OFF (-nolightgun). -[no]multikeyboard / -[no]multikey Determines whether MAME differentiates between multiple
keyboards. Some systems may report more than one keyboard; by default, the
data from all of these keyboards is combined so that it looks like a single
keyboard.
Turning this option on will enable MAME to report keypresses on different keyboards independently. The default is OFF (-nomultikeyboard). -[no]multimouse Determines whether MAME differentiates between multiple
mice. Some systems may report more than one mouse device; by default, the data
from all of these mice is combined so that it looks like a single mouse.
Turning this option on will enable MAME to report mouse movement and button
presses on different mice independently.
The default is OFF (-nomultimouse). -[no]steadykey / -[no]steady Some systems require two or more buttons to be pressed at
exactly the same time to make special moves. Due to limitations in the
keyboard hardware, it can be difficult or even impossible to accomplish that
using the standard keyboard handling. This option selects a different handling
that makes it easier to register simultaneous button presses, but has the
disadvantage of making controls less responsive.
The default is OFF (-nosteadykey) -[no]ui_active Enable user interface on top of emulated keyboard (if
present).
The default is OFF (-noui_active) -[no]offscreen_reload / -[no]reload Controls whether or not MAME treats a second button input
from a lightgun as a reload signal. In this case, MAME will report the gun's
position as (0,MAX) with the trigger held, which is equivalent to an offscreen
reload.
This is only needed for games that required you to shoot offscreen to reload, and then only if your gun does not support off screen reloads. The default is OFF (-nooffscreen_reload). -joystick_map <map> / -joymap <map> Controls how analog joystick values map to digital
joystick controls.
Systems such as Pac-Man use a 4-way digital joystick and will exhibit undesired behavior when a diagonal is triggered; in the case of Pac-Man, movement will stop completely at intersections when diagonals are triggered and the game will be considerably harder to play correctly. Many other arcade cabinets used 4-way or 8-way joysticks (as opposed to full analog joysticks), so for true analog joysticks such as flight sticks and analog thumb sticks, this then needs to be mapped down to the expected 4-way or 8-way digital joystick values. To do this, MAME divides the analog range into a 9x9 grid that looks like this: insert 9x9 grid picture here MAME then takes the joystick axis position (for X and Y axes only), maps it to this grid, and then looks up a translation from a joystick map. This parameter allows you to specify the map. For instance, an 8-way joystick map traditionally looks like this: insert 8-way map picture here This mapping gives considerable leeway to the angles accepted for a given direction, so that being approximately in the area of the direction you want will give you the results you want. Without that, if you were slightly off center while holding the stick left, it would not recognize the action correctly. The default is auto, which means that a standard 8-way, 4-way, or 4-way diagonal map is selected automatically based on the input port configuration of the current system. Generally you will want to set up the -joystick_map setting in the per-system <system>.ini file as opposed to the main MAME.INI file so that the mapping only affects the systems you want it to. See Multiple Configuration Files for further details on per-system configuration. Maps are defined as a string of numbers and characters. Since the grid is 9x9, there are a total of 81 characters necessary to define a complete map. Below is an example map for an 8-way joystick that matches the picture shown above:
To specify the map for this parameter, you can specify a string of rows separated by a '.' (which indicates the end of a row), like so:
However, this can be reduced using several shorthands supported by the <map> parameter. If information about a row is missing, then it is assumed that any missing data in columns 5-9 are left/right symmetric with data in columns 0-4; and any missing data in columns 0-4 is assumed to be copies of the previous data. The same logic applies to missing rows, except that up/down symmetry is assumed. By using these shorthands, the 81 character map can be simply specified by this 11 character string: 7778...4445 (which means we then use -joymap 7778...4445) Looking at the first row, 7778 is only 4 characters long. The 5th entry can't use symmetry, so it is assumed to be equal to the previous character '8'. The 6th character is left/right symmetric with the 4th character, giving an '8'. The 7th character is left/right symmetric with the 3rd character, giving a '9' (which is '7' with left/right flipped). Eventually this gives the full 777888999 string of the row. The second and third rows are missing, so they are assumed to be identical to the first row. The fourth row decodes similarly to the first row, producing 444555666. The fifth row is missing so it is assumed to be the same as the fourth. The remaining three rows are also missing, so they are assumed to be the up/down mirrors of the first three rows, giving three final rows of 111222333. With 4-way games, sticky becomes important to avoid problems with diagonals. Typically you would choose a map that looks something like this: insert 9x9 4-way sticky grid picture here This means that if you press left, then roll the stick towards up (without re-centering it) you'll pass through the sticky section in the corner. As you do, MAME will read that sticky corner as left as that's the last non-sticky input it received. As the roll gets into the upward space of the map, this then switches to an up motion. This map would look somewhat like:
To specify the map for this parameter, you can specify a string of rows separated by a '.' (which indicates the end of a row), like so:
Like before, because of the symmetry between top and bottom and left and right, we can shorten this down to:
-joystick_deadzone <value> / -joy_deadzone <value> / -jdz <value> If you play with an analog joystick, the center can drift
a little. joystick_deadzone tells how far along an axis you must move before
the axis starts to change. This option expects a float in the range of 0.0 to
1.0. Where 0 is the center of the joystick and 1 is the outer limit.
The default is 0.15. -joystick_saturation <value> / joy_saturation <value> / -jsat <value> If you play with an analog joystick, the ends can drift a
little, and may not match in the +/- directions. joystick_saturation tells how
far along an axis movement change will be accepted before it reaches the
maximum range. This option expects a float in the range of 0.0 to 1.0, where 0
is the center of the joystick and 1 is the outer limit.
The default is 0.85. -joystick_threshold <value> / joy_threshold <value> / -jthresh <value> When a joystick axis (or other absolute analog axis) is
assigned to a digital input, this controls how far it must be moved from the
neutral position (or centre) to be considered active or switched on. This
option expects a float in the range of 0.0 to 1.0, where 0 means any movement
from the neutral position is considered active, and 1 means only the outer
limits are considered active. This threshold is not adjusted to the
range between the dead zone and saturation point.
Note that if a joystick map is configured, that will take precedence over this setting when a joystick’s main X/Y axes are assigned to digital inputs. The default is 0.3. -[no]natural Allows user to specify whether or not to use a natural
keyboard or not. This allows you to start your system in a 'native' mode,
depending on your region, allowing compatibility for non-"QWERTY"
style keyboards.
The default is OFF (-nonatural) In "emulated keyboard" mode (the default mode), MAME translates pressing/releasing host keys/buttons to emulated keystrokes. When you press/release a key/button mapped to an emulated key, MAME presses/releases the emulated key. In "natural keyboard" mode, MAME attempts to translate characters to keystrokes. The OS translates keystrokes to characters (similarly to when you type into a text editor), and MAME attempts to translate these characters to emulated keystrokes. There are a number of unavoidable limitations in "natural keyboard" mode:
-[no]joystick_contradictory Enable contradictory direction digital joystick input at
the same time such as Left and Right or Up and Down at the same
time.
The default is OFF (-nojoystick_contradictory) -coin_impulse [n] Set coin impulse time based on n (n<0 disable impulse,
n==0 obey driver, 0<n set time n).
Default is 0. Core Input Automatic Enable Options-paddle_device ( none | keyboard | mouse | lightgun | joystick ) -adstick_device ( none | keyboard | mouse | lightgun | joystick ) -pedal_device ( none | keyboard | mouse | `lightgun | joystick ) -dial_device ( none | keyboard | mouse | lightgun | joystick ) -trackball_device ( none | keyboard | mouse | lightgun | joystick ) -lightgun_device ( none | keyboard | mouse | lightgun | joystick ) -positional_device ( none | keyboard | mouse | lightgun | joystick ) -mouse_device ( none | keyboard | mouse | lightgun | joystick ) Each of these options sets whether mouse, joystick or
lightgun controllers should be enabled when running an emulated system that
uses a particular class of analog inputs. These options can effectively set
-mouse, -joystick and/or -lightgun depending on the type
of inputs present on the emulated system. Note that these options will
not override explicit -nomouse, -nojoystick and/or
-nolightgun settings at a higher priority level (e.g. in a more
specific INI file or on the command line).
For example, if you specify the option -paddle_device mouse, then mouse controls will automatically be enabled when you run a game that has paddle controls (e.g. Super Breakout), even if you specified -nomouse . The default is to automatically enable mouse controls when running emulated systems with mouse inputs (-mouse_device mouse). TIP: Note that these settings can override -nomouse,
-nojoystick and/or -nolightgun depending on the inputs present
on the emulated system.
Debugging Options-[no]verbose / -[no]v Displays internal diagnostic information. This
information is very useful for debugging problems with your configuration.
The default is OFF (-noverbose). TIP: IMPORTANT: When reporting bugs to MAMEdev, please run
with -verbose and include the resulting information.
-[no]oslog Output error.log messages to the system diagnostic
output, if one is present.
By default messages are sent to the standard error output (this is typically displayed in the terminal or command prompt window, or saved to a system log file). On Windows, if a debugger is attached (e.g. the Visual Studio debugger or WinDbg), messages will be sent to the debugger instead. The default is OFF (-nooslog). -[no]log Creates a file called error.log which contains all of the
internal log messages generated by the MAME core and system drivers. This can
be used at the same time as -oslog to output the log data to both
targets as well.
The default is OFF (-nolog).
mame qbert -log
mame qbert -oslog -log -[no]debug Activates the integrated debugger. By default, pressing
the backtick/tilde (~) key during emulation breaks into the debugger.
MAME also breaks into the debugger after the initial soft reset on startup if
the debugger is active. See MAME Debugger for information on using the
debugger.
The default is OFF (-nodebug). -debugger <module> Chooses the module to use for debugging the target system
when the debug option is on. Available debugger modules depend on the
host platform and build options.
Supported debugger modules:
mame ambush -debug -debugger qt -debugscript <filename> Specifies a file that contains a list of debugger
commands to execute immediately upon startup.
The default is NULL (no commands). -[no]update_in_pause Enables updating of the main screen bitmap while the
system is paused. This means that the video update callback will be called
repeatedly while the emulation is paused, which can be useful for debugging.
The default is OFF (-noupdate_in_pause). -watchdog <duration> / -wdog <duration> Enables an internal watchdog timer that will
automatically kill the MAME process if more than <duration>
seconds passes without a frame update. Keep in mind that some systems sit for
a while during load time without updating the screen, so
<duration> should be long enough to cover that.
10-30 seconds on a modern system should be plenty in general. By default there is no watchdog. -debugger_host <address> Set the IP address to listen on to accept GDB connections
when using the GDB stub debugger module (see the debugger option).
The default is localhost. -debugger_port <port> Set the TCP port number to accept GDB connections on when
using the GDB stub debugger module (see the debugger option).
The default is 23946. -debugger_font <fontname> / -dfont <fontname> Specifies the name of the font to use for debugger
windows.
The Windows default font is Lucida Console. The Mac (Cocoa) default font is system fixed-pitch font default (typically Monaco). The Qt default font is Courier New. -debugger_font_size <points> / -dfontsize <points> Specifies the size of the font to use for debugger
windows, in points.
The Windows default size is 9 points. The Qt default size is 11 points. The Mac (Cocoa) default size is the system default size. Core Communication Options-comm_localhost <string> Local address to bind to. This can be a traditional
xxx.xxx.xxx.xxx address or a string containing a resolvable hostname.
The default is value is 0.0.0.0 (which binds to all local IPv4 addresses). -comm_localport <string> Local port to bind to. This can be any traditional
communications port as an unsigned 16-bit integer (0-65535).
The default value is 15122. -comm_remotehost <string> Remote address to connect to. This can be a traditional
xxx.xxx.xxx.xxx address or a string containing a resolvable hostname.
The default is value is "0.0.0.0" (which binds to all local IPv4 addresses). -comm_remoteport <string> Remote port to connect to. This can be any traditional
communications port as an unsigned 16-bit integer (0-65535).
The default value is "15122". -[no]comm_framesync Synchronize frames between the communications network.
The default is OFF (-nocomm_framesync). Core Misc Options-[no]drc Enable DRC (dynamic recompiler) CPU core if available for
maximum speed.
The default is ON (-drc). -[no]drc_use_c Force DRC to use the C code backend.
The default is OFF (-nodrc_use_c). -[no]drc_log_uml Write DRC UML disassembly log.
The default is OFF (-nodrc_log_uml). -[no]drc_log_native Write DRC native disassembly log.
The default is OFF (-nodrc_log_native). -bios <biosname> Specifies the specific BIOS to use with the current
system, for systems that make use of a BIOS. The -listbios output will
list all of the possible BIOS names for a system, as does the -listxml
output.
The default is default. -[no]cheat / -[no]c Activates the cheat menu with autofire options and other
tricks from the cheat database, if present. This also activates additional
options on the slider menu for overclocking/underclocking.
Be advised that savestates created with cheats on may not work correctly with this turned off and vice-versa. The default is OFF (-nocheat). -[no]skip_gameinfo Forces MAME to skip displaying the system info screen.
The default is OFF (-noskip_gameinfo). -uifont <fontname> Specifies the name of a font file to use for the UI font.
If this font cannot be found or cannot be loaded, the system will fall back to
its built-in UI font. On some platforms fontname can be a system font
name instead of a BDF font file.
The default is default (use the OSD-determined default font). -ui <type> Specifies the type of UI to use, either simple or
cabinet.
The default is cabinet (-ui cabinet). -ramsize [n] Allows you to change the default RAM size (if supported
by driver).
-[no]confirm_quit Display a Confirm Quit dialog to screen on exit,
requiring one extra step to exit MAME.
The default is OFF (-noconfirm_quit). -[no]ui_mouse Displays a mouse cursor when using the built-in MAME user
interface.
The default is ON (-ui_mouse). -language <language> Specify a localization language found in the
languagepath tree.
-[no]nvram_save Save the NVRAM contents when exiting machine emulation.
By turning this off, you can retain your previous NVRAM contents as any
current changes made will not be saved. Turning this option off will also
unconditionally suppress the saving of .nv files associated with some types of
software cartridges.
The default is ON (-nvram_save). Scripting Options-autoboot_command "<command>" Command string to execute after machine boot (in quotes
" "). To issue a quote to the emulation, use """ in
the string. Using \n will create a new line, issuing what was typed
prior as a command.
This works only with systems that support natural keyboard mode. -autoboot_delay [n] Timer delay (in seconds) to trigger command execution on
autoboot.
-autoboot_script / -script [filename.lua] File containing scripting to execute after machine boot.
-[no]console Enables emulator Lua Console window.
The default of OFF (-noconsole). -plugins -plugin [plugin shortname] A list of Lua Plugins to enable, comma separated.
-noplugin [plugin shortname] A list of Lua Plugins to disable, comma separated.
HTTP Server Options-[no]http -http_port <port> -http_root <rootfolder> Choose HTTP server document root.
The default is web. PortAudio Options-pa_api API Choose which API that PortAudio should use to talk to
your sound hardware. You can use -verbose to see which APIs are
available.
The default is none.
mame -sound portaudio -verbose Attempting load of mame.ini ... PortAudio: API MME has 20 devices PortAudio: MME: " - Input" PortAudio: MME: "Microphone (3- USB Camera-B4.09" PortAudio: MME: "Line (AVerMedia Live Gamer HD 2" PortAudio: MME: "Digital Audio Interface (AVerMe" PortAudio: MME: "Headset Microphone (Razer Krake" ... PortAudio: MME: " - Output" PortAudio: MME: "Headset Earphone (Razer Kraken " PortAudio: MME: "Digital Audio (S/PDIF) (High De" PortAudio: MME: "NX-EDG27 (NVIDIA High Definitio" ... PortAudio: API Windows DirectSound has 20 devices PortAudio: Windows DirectSound: "Primary Sound Capture Driver" PortAudio: Windows DirectSound: "Headset Microphone (Razer Kraken 7.1 V2)" PortAudio: Windows DirectSound: "Primary Sound Driver" (default) PortAudio: Windows DirectSound: "Headset Earphone (Razer Kraken 7.1 V2)" PortAudio: Windows DirectSound: "Digital Audio (S/PDIF) (High Definition Audio Device)" PortAudio: Windows DirectSound: "NX-EDG27 (NVIDIA High Definition Audio)" ... PortAudio: API Windows WASAPI has 18 devices PortAudio: Windows WASAPI: "Headset Earphone (Razer Kraken 7.1 V2)" PortAudio: Windows WASAPI: "Digital Audio (S/PDIF) (High Definition Audio Device)" PortAudio: Windows WASAPI: "NX-EDG27 (NVIDIA High Definition Audio)" PortAudio: Windows WASAPI: "Headset Microphone (Razer Kraken 7.1 V2)" ... PortAudio: API Windows WDM-KS has 22 devices PortAudio: Windows WDM-KS: "Output (NVIDIA High Definition Audio)" PortAudio: Windows WDM-KS: "SPDIF Out (HD Audio SPDIF out)" PortAudio: Windows WDM-KS: "Headset Microphone (Razer Kraken 7.1 V2)" PortAudio: Windows WDM-KS: "Headset Earphone (Razer Kraken 7.1 V2)" PortAudio: Windows WDM-KS: "Microphone (VDVAD Wave)" PortAudio: Windows WDM-KS: "Speakers (VDVAD Wave)" ... PortAudio: Sample rate is 48000 Hz, device output latency is 218.67 ms PortAudio: Allowed additional buffering latency is 18.00 ms/864 frames
mame suprmrio -sound portaudio -pa_api "Windows WASAPI" -pa_device device Choose which sound device to output through. This would
typically be one of the outputs on your sound card or a USB headset.
The default is none. mame suprmrio -sound portaudio -pa_api "Windows WASAPI" -pa_device "NX-EDG27 (NVIDIA High Definition Audio)" -pa_latency latency Choose the buffer size for PortAudio output; this is
specified in seconds. Lower numbers have less latency but may increase stutter
in the sound. Decimal places are supported. Try starting from 0.20 and
decrease or increase until you find the best number your hardware and OS are
capable of handling.
The default is 0. mame suprmrio -sound portaudio -pa_api "Windows WASAPI" -pa_device "NX-EDG27 (NVIDIA High Definition Audio)" -pa_latency 0.20 Windows-Specific Command-line OptionsThis section contains configuration options that are specific to the native (non-SDL) Windows version of MAME. Performance options-priority <priority> Sets the thread priority for the MAME threads. By default
the priority is left alone to guarantee proper cooperation with other
applications. The valid range is -15 to 1, with 1 being the highest priority.
The default is 0 (NORMAL priority).
-profile [n] Enables profiling, specifying the stack depth of
[n] to track.
Full screen options-[no]triplebuffer / -[no]tb Enables or disables “triple buffering”.
Normally, MAME just draws directly to the screen, without any fancy buffering.
But with this option enabled, MAME creates three buffers to draw to, and
cycles between them in order. It attempts to keep things flowing such that one
buffer is currently displayed, the second buffer is waiting to be displayed,
and the third buffer is being drawn to. -triplebuffer will override
-waitvsync, if the buffer is successfully created. This option does not
work with -video gdi. The default is OFF
(-notriplebuffer).
-full_screen_brightness <value> / -fsb <value> Controls the brightness, or black level, of the entire
display. The standard value is 1.0. Lower values (down to 0.1) will produce a
darkened display, while higher values (up to 2.0) will give a brighter
display. Note that not all video cards have hardware to support this option.
This option does not work with -video gdi. The default is
1.0.
-full_screen_contrast <value> / -fsc <value> Controls the contrast, or white level, of the entire
display. The standard value is 1.0. Lower values (down to 0.1) will produce a
dimmer display, while higher values (up to 2.0) will give a more saturated
display. Note that not all video cards have hardware to support this option.
This option does not work with -video gdi. The default is
1.0.
-full_screen_gamma <value> / -fsg <value> Controls the gamma, which produces a potentially
nonlinear black to white ramp, for the entire display. The standard value is
1.0, which gives a linear ramp from black to white. Lower values (down to 0.1)
will increase the nonlinearity toward black, while higher values (up to 3.0)
will push the nonlinearity toward white. Note that not all video cards have
hardware to support this option. This option does not work with -video
gdi. The default is 1.0.
Input device options-[no]dual_lightgun / -[no]dual Controls whether or not MAME attempts to track two
lightguns that appear as a single mouse. This option requires the lightgun
option to be on and the lightgunprovider option to be set to
win32.
This option supports certain older dual lightgun setups that work by setting the mouse pointer location at the moment a lightgun trigger is activated. The primary and secondary triggers on the first lightgun correspond to the first and second mouse buttons, and the primary and secondary triggers on the second lightgun correspond to the third and fourth mouse buttons. If you have multiple lightguns connected, you will probably just need to enable the lightgun option, use the default lightgunprovider option of rawinput, and configure each lightgun individually. The default is OFF (-nodual_lightgun). SDL-Specific Command-line OptionsThis section contains configuration options that are specific to any build supported by SDL (including Windows when built with SDL instead of native). Performance Options-[no]sdlvideofps Enable output of benchmark data on the SDL video
subsystem, including your system’s video driver, X server (if
applicable), and OpenGL stack in -video opengl mode.
Video Options-[no]centerh Center horizontally within the view area. Default is ON
(-centerh).
-[no]centerv Center vertically within the view area. Default is ON
(-centerv).
Video Soft-Specific Options-scalemode Scale mode: none, async, yv12, yuy2, yv12x2, yuy2x2
(-video soft only). Default is none.
SDL Keyboard Mapping-keymap Enable keymap. Default is OFF (-nokeymap)
-keymap_file <file> Keymap file name. Default is keymap.dat.
SDL Input Options-enable_touch Enable support for touch input. If this option is
switched off, mouse input simulated from touch devices will be used instead.
Default is OFF (-noenable_touch)
-sixaxis Use special handling for PlayStation 3 SixAxis
controllers. May cause undesirable behaviour with other controllers. Only
affects the sdljoy joystick provider. Default is OFF
(-nosixaxis)
-[no]dual_lightgun / -[no]dual Controls whether or not MAME attempts to track two
lightguns that appear as a single mouse. This option requires the lightgun
option to be on and the lightgunprovider option to be set to
sdl.
This option supports dual lightgun setups that work by setting the mouse pointer location at the moment a lightgun trigger is activated. The primary and secondary triggers on the first lightgun correspond to the first and second mouse buttons, and the primary and secondary triggers on the second lightgun correspond to the third and fourth mouse buttons. The default is OFF (-nodual_lightgun). SDL Lightgun Mapping-lightgun_index1 <name> -lightgun_index2 <name> ... -lightgun_index8 <name> Device name or ID mapped to a given lightgun slot. SDL Low-level Driver Options-videodriver <driver> SDL video driver to use ('x11', 'directfb', ... or
'auto' for SDL default)
-audiodriver <driver> SDL audio driver to use ('alsa', 'arts', ... or
'auto' for SDL default)
-gl_lib <driver> Alternative libGL.so to use; 'auto' for
system default
Command-line IndexThis is a complete index of all command-line options and verbs for MAME, suitable for quickly finding a given option. Universal Command-line OptionsThis section contains configuration options that are applicable to all MAME configurations (including both SDL and Windows native). Core Verbshelp validate Configuration Verbscreateconfig showconfig showusage Frontend Verbslistxml listfull listsource listclones listbrothers listcrc listroms listbios listsamples verifyroms verifysamples romident listdevices listslots listmedia listsoftware verifysoftware getsoftlist verifysoftlist OSD-related Optionsuimodekey controller_map background_input uifontprovider keyboardprovider mouseprovider lightgunprovider joystickprovider midiprovider networkprovider OSD CLI Verbslistmidi listnetwork OSD Output Optionsoutput Configuration Optionsnoreadconfig Core Search Path Optionshomepath rompath hashpath samplepath artpath ctrlrpath inipath fontpath cheatpath crosshairpath pluginspath languagepath swpath Core Output Directory Optionscfg_directory nvram_directory input_directory state_directory snapshot_directory diff_directory comment_directory Core State/Playback Options[no]rewind / rewind rewind_capacity state [no]autosave playback [no]exit_after_playback record mngwrite aviwrite wavwrite snapname snapsize snapview [no]snapbilinear statename [no]burnin Core Performance Options[no]autoframeskip frameskip seconds_to_run [no]throttle [no]sleep speed [no]refreshspeed numprocessors bench [no]lowlatency Core Rotation Options[no]rotate [no]ror [no]rol [no]autoror [no]autorol [no]flipx [no]flipy Core Video Optionsvideo numscreens [no]window [no]maximize [no]keepaspect [no]waitvsync [no]syncrefresh prescale [no]filter [no]unevenstretch Core Full Screen Options[no]switchres Core Per-Window Video Optionsscreen aspect resolution view Core Artwork Options[no]artwork_crop fallback_artwork override_artwork Core Screen Optionsbrightness contrast gamma pause_brightness effect Core Vector Optionsbeam_width_min beam_width_max beam_intensity_weight beam_dot_size flicker Core Video OpenGL Debugging Options[no]gl_forcepow2texture [no]gl_notexturerect [no]gl_vbo [no]gl_pbo Core Video OpenGL GLSL Options[no]gl_glsl gl_glsl_filter glsl_shader_mame[0-9] glsl_shader_screen[0-9] Core Sound Optionssamplerate [no]samples [no]compressor volume sound audio_latency Core Input Options[no]coin_lockout ctrlr [no]mouse [no]joystick [no]lightgun [no]multikeyboard [no]multimouse [no]steadykey [no]ui_active [no]offscreen_reload joystick_map joystick_deadzone joystick_saturation joystick_threshold [no]natural [no]joystick_contradictory coin_impulse Core Input Automatic Enable Optionspaddle_device adstick_device pedal_device dial_device trackball_device lightgun_device positional_device mouse_device Core Debugging Options[no]verbose [no]oslog [no]log [no]debug debugger debugscript [no]update_in_pause watchdog debugger_host debugger_port debugger_font debugger_font_size Core Communication Optionscomm_localhost comm_localport comm_remotehost comm_remoteport [no]comm_framesync Core Misc Options[no]drc [no]drc_use_c [no]drc_log_uml [no]drc_log_native bios [no]cheat [no]skip_gameinfo uifont ui ramsize [no]confirm_quit [no]ui_mouse language [no]nvram_save Scripting Optionsautoboot_command autoboot_delay autoboot_script [no]console [no]plugins plugin noplugin HTTP Server Optionshttp http_port http_root PortAudio Optionspa_api pa_device pa_latency Windows-Specific Command-line OptionsThis section contains configuration options that are specific to the native (non-SDL) Windows version of MAME. Windows Performance Optionspriority profile Windows Full Screen Options[no]triplebuffer full_screen_brightness full_screen_contrast full_screen_gamma Windows Input Device Options[no]dual_lightgun SDL-Specific Command-line OptionsThis section contains configuration options that are specific to any build supported by SDL (including Windows when built with SDL instead of native). SDL Performance Options[no]sdlvideofps SDL Video Options[no]centerh [no]centerv SDL Video Soft-Specific Optionsscalemode SDL Keyboard Mappingkeymap keymap_file SDL Input Options[no]enable_touch [no]sixaxis [no]dual_lightgun SDL Lightgun Mappinglightgun_index SDL Low-level Driver Optionsvideodriver audiodriver gl_lib PLUGINS
IntroductionMAME supports plugins that can provide additional functionality. Plugins have been written to communicate with external programs, play games automatically, display internal game structures like hitboxes, provide alternate user interfaces, and automatically test emulation. See Lua Scripting Interface for more information about MAME’s Lua API. Using pluginsTo enable plugins, you need to turn on the plugins option, and make sure the pluginspath option includes the folder where your plugins are stored. You can set the plugins option in an INI file or on the command line. You can set the pluginspath option by selecting Configure Options from the system selection menu, then selecting Configure Directories, and then selecting Plugins (you can also set it in an INI file or on the command line). Many plugins need to store settings and/or data. The homepath option sets the folder where plugins should save data (defaults to the working directory). You can change this by selecting Configure Options from the system selection menu, then selecting Configure Directories, and then selecting Plugin Data. To turn individual plugins on or off, first make sure plugins are enabled, then select Configure Options from the system selection menu, and then select Plugins. You will need to completely exit MAME and start it again for changes to the enabled plugins to take effect. You can also use the plugin option on the command line, or change the settings in the plugin.ini file. If an enabled plugin needs additional configuration, or if it needs to show information, a Plugin Options item will appear in the main menu (accessed by pressing Tab during emulation by default). Included pluginsMAME includes several plugins providing useful functionality, and serving as sample code that you can use as a starting point when writing your own plugins. Autofire Plugin
IntroductionThe autofire plugin allows you to simulate repeatedly pressing an emulated button by holding down a key or button combination. This can help people with certain disabilities or injuries play shooting games, and may help reduce the risk of repetitive strain injuries (or keyboard damage). To configure the autofire plugin, activate the main menu (press Tab during emulation by default), select Plugin Options, and then select Autofire. Configured autofire buttons for the current system are listed, along with their repetition rates and activation hotkeys (initially there will be no autofire buttons configured). Select an autofire button to change settings, or choose Add autofire button to set up a new autofire button. See Autofire buttons settings for details on setting up an autofire button. You can delete an autofire button by highlighting it in the menu and pressing the UI Clear key (Del/Delete/Forward Delete on the keyboard by default). Autofire settings are saved in the autofire folder in the plugin data folder (see the homepath option). A file is created for each system with autofire buttons configured, named according to the system’s short name (or ROM set name), with the extension .cfg. For example, autofire settings for Super-X will be saved in the file superx.cfg in the autofire folder in your plugin data folder. The autofire settings are stored in JSON format. Autofire buttons settingsThe options for adding a new autofire button or modifying an existing autofire button are the same. Select Input to set the emulated button that you want to simulate pressing repeatedly. Currently, only player buttons are supported. Typically you’ll set this to the primary fire button for shooting games. This is most often P1 Button 1 or the equivalent for another player, but it might have a different name. On Konami’s Gradius games, P1 Button 2 is the primary fire button. Select Hotkey to set the control (or combination of controls) you’ll use to activate the autofire button. This can be any combination that MAME supports for activating a digital input. On frames and Off frames are the number of consecutive emulated video frames that the emulated button will be held and released for, respectively. Adjust the value with the UI Left/Right keys, or click the arrows. Press the UI Clear key to reset the values to one frame. Lower values correspond to pressing the button at a faster rate. Depending on how fast the system reads inputs, you may need higher numbers than 1 for the system to recognise the button being released and pressed again (e.g. 2 on frames and 2 off frames works for Alcon). Experiment with different values to get the best effect. When adding a new autofire button, there is a Cancel option that changes to Create after you set the input and hotkey. Select Create to finish creating the autofire button and return to the list of autofire buttons. The new autofire button will be added at the end of the list. Press the UI Back key (Escape/Esc on the keyboard by default), or select Cancel before setting the input/hotkey, to return to the previous menu without creating the new autofire button. When modifying an existing autofire button, select Done or press the UI Cancel key to return to the list of autofire buttons. Changes take effect immediately. Notes and potential pitfallsAutofire buttons act as if they’re wired in parallel with MAME’s regular controls. This means that if you set the activation hotkey for an autofire button to a button or key that’s also assigned to one of the emulated inputs directly, you may get unexpected results. Using Gradius as an example:
It is recommended that you choose control combinations for autofire hotkeys that are not assigned to any other emulated inputs in the system. Autofire is not necessarily desirable in all situations. For example using autofire in Super-X with the blue “lightning” weapon equipped at high power levels will only produce a single beam, greatly reducing the weapon’s effectiveness. The fire button must be held down to produce all beams. Some shooting games (e.g. Raiden Fighters) require the primary fire button to be held down for a charged special attack. This means it’s often necessary to have a non-autofire input for the primary fire button assigned to play effectively. Console PluginThe console plugin provides functionality for MAME’s interactive Lua console. It is not used directly. Use the console option to activate the interactive Lua console. See Lua Scripting Interface for more information about MAME’s Lua API. Data PluginThe data plugin loads information from various external support files so it can be displayed in MAME. If the plugin is enabled, info is show in the Infos tab of the right-hand pane on the system and software selection menus. The info viewer can be shown by clicking the toolbar button on the system and software selection menus, or by choosing External DAT View from the main menu during emulation (this menu item will not appear if the data plugin is not enabled, or if no information is available for the emulated system). To set the folders where the data plugin looks for supported files, choose Configure Options on the system selection menu, then choose Configure Directories, and then choose DATs. You can also set the historypath option in your ui.ini file. Loading large data files like history.xml can take quite a while, so please be patient the first time you start MAME after updating or adding new data files. The following files are supported:
If you install hi2txt, the data plugin can also show high scores from non-volatile memory or saved by the hiscore support plugin for supported games. Note that you can only use a single file of each type at a time. You cannot, for example, use the English and Japanese mameinfo.dat files simultaneously. The data plugin creates a history.db file in the data folder in the plugin data folder (see the homepath option). This file stores the information from the support files in a format suitable for rapid loading. It uses the SQLite3 database format. Discord Presence PluginThe Discord presence plugin works with the Discord app for Windows, macOS or Linux to set your activity to show what you’re doing in MAME. The activity is set to In menu if you’re using the system or software selection menu, Playing if emulation is running, or Paused if emulation is paused. The details are set to show the system name and software description if applicable. Dummy Test PluginThis is a sample plugin that shows how to set necessary plugin metadata, register callbacks, and display a simple menu. It prints status messages, and it adds a Dummy option to the Plugin Options menu. GDB Stub PluginThe GDB stub plugin acts as a remote debugging server for the GNU debugger (GDB). This allows you to connect to MAME and debug supported systems using GDB. The plugin listens for connections on port 2159 on the IPv4 loopback address (127.0.0.1). Only Intel 80386 (i386) family processors are supported. See the debugger option for another GDB remote debugging implementation with support for more CPUs and configurable listening ports. Hiscore Support PluginThe hiscore support plugin saves and restores high scores for games that did not originally save high scores in non-volatile memory. Note that this plugin modifies the contents of memory directly with no coordination with the emulated software, and hence changes behaviour. This may have undesirable effects, including broken gameplay or causing the emulated software to crash. The plugin includes a hiscore.dat file that contains the information on how to save and restore high scores for supported systems. This file must be kept up-to-date when system definitions change in MAME. High scores can be saved automatically either on exit, or a few seconds after they’re updated in memory. To change the setting, activate the main menu (press Tab during emulation by default), select Plugin Options, and then select Hiscore Support. Change the Save scores option by highlighting it and using the UI Left/Right keys, or clicking the arrows. High score data is saved in the hiscore folder in the plugin data folder (see the homepath option). A file with a name corresponding the system short name (or ROM set name) with the extension .hi. For example, high scores for the game Moon Cresta will be saved in the file mooncrst.hi in the hiscore folder in your plugin data folder. The settings for the hiscore support plugin are stored in the file plugin.cfg in the hiscore folder in the plugin data folder (this file is in JSON format). Input Macro Plugin
IntroductionThe input macro plugin allows you to trigger a sequence of emulated input actions with a key or button combination. This can help people with disabilities or injuries that make some input sequences difficult. It can also be used as a way to cheat in games that require rapid sequences of inputs, like the running events in Track & Field, or the eating minigame in Daisu-Kiss. To configure the input macro plugin, activate the main menu (press Tab during emulation by default), select Plugin Options, and then select Input Macros. Configured input macros for the current system are listed, along with their activation sequences (initially there will be no input macros configured). Select a macro to edit it, or choose Add macro to set up a new input macro. See Editing input macros for details on editing input macros. You can delete an input macro by highlighting it in the menu and pressing the UI Clear key (Del/Delete/Forward Delete on the keyboard by default). Input macros are saved in the inputmacro folder in the plugin data folder (see the homepath option). A file is created for each system with input macros configured, named according to the system’s short name (or ROM set name), with the extension .cfg. For example, input macros for Daisu-Kiss will be saved in the file daiskiss.cfg in the inputmacro folder in your plugin data folder. The input macros are stored in JSON format. Editing input macrosThe options for editing input macros are the same whether you’re creating a new macro or editing an existing macro. Input macros consist of a sequence of steps. Each step optionally waits for a configurable delay, then activates one or more emulated inputs for a specified duration. You can choose what should happen if the activation sequence is still held when the final step of the macro completes: the emulated inputs can be released, the final step can be prolonged, or the macro can loop back to any step in the sequence. The settings in first section of the macro editing menu apply to the macro as a whole:
Each step has delay, duration and input settings:
To add a step to the macro, highlight Add step at position (below the existing steps), use the UI Left/Right keys or click the arrows to set the position where you’d like to insert the new step, and then press the UI Select key (or double-click the menu item) to add the new step. You will be prompted to set the first input for the new step. Remember to check the On release and When held settings after adding steps. The Add step at position item will only appear after you set the first input for the initially created step when creating a new macro. When creating a new macro, there is a Cancel option that changes to Create after you set the activating sequence and the first input for the initially created step. Select Create to finish creating the macro and return to the list of input macros. The new macro will be added at the end of the list. Press the UI Back key, or select Cancel before setting the activation sequence/input, to return to the previous menu without creating the new macro. When editing an existing macro, select Done or press the UI Back key to return to the list of input macros. Changes take effect immediately. Example macrosRaiden autofireThis provides player 1 autofire functionality using the space bar. The same thing could be achieved using the Autofire Plugin, but this demonstrates a simple looping macro:
The first step has no delay so that firing begins as soon as the space bar is pressed. The second step has sufficient delay to ensure the game recognises the button being pressed and released again. The second step is repeated as long as the space bar is held down. Track & Field sprint cheatThis allows you to run in Konami Track & Field by holding a single button. This takes most of the skill (and fun) out of the game:
This macro rapidly alternates pressing buttons 1 and 3 – the pattern required to run in the game. Street Fighter II ShoryukenThis macro allows you to perform a right-facing Shōryūken (Dragon Punch) by pressing a single key:
This macro involves steps that activate multiple inputs. The macro will complete if the activation sequence is released early, allowing you to tap the key momentarily to perform the move. Holding the activation sequence holds down the attack button. Layout PluginWhen enabled, the layout plugin allows embedded Lua scripts in layout files to run. Built-in artwork for some machines and some external artwork packages can use Lua scripts to provide enhanced interactive features. See MAME Layout Scripting for an introduction to layout file scripting. Timecode Recorder PluginThe timecode recorder plugin logs time codes to a text file in conjunction with creating an input recording file to assist people creating gameplay videos. The time code log file is only created when making an input recording. The time code log file has the same name as the input recording file with the extension .timecode appended. Use the record and input_directory options to create an input recording and specify the location for the output files. By default, the plugin records a time code when you press the F12 key on the keyboard while not pressing either Shift or Alt key. You can change this setting in the options menu for the plugin (choose Plugin Options from the main menu during emulation, and then choose Timecode Recorder). Settings for the plugin are stored in JSON format in the file plugin.cfg in the timecode folder inside your plugin data folder (see the homepath option). Game Play Timer PluginThe timer plugin records the total time spent emulating each combination of a system and a software list item, as well as the number of times each combination has been launched. To see the statistics, bring up the main menu (press Tab during emulation by default), choose Plugin Options, and then choose Timer. This plugin records wall clock time (the real time duration elapsed while emulation is running, according to the host OS) as well as emulated time. The elapsed wall clock time may be shorter than the elapsed emulated time if you turn off throttling or use MAME’s “fast forward” feature, or it may be longer than the elapsed emulated time if you pause the emulation of if the emulation is too demanding to run at full speed. The statistics are stored in the file timer.db in the timer folder inside your plugin data folder (see the homepath option). The file is a SQLite3 database. ADVANCED CONFIGURATIONMultiple Configuration FilesMAME has a very powerful configuration file system that can allow you to tweak settings on a per-game, per-system, or even per-monitor type basis, but requires careful thought about how you arrange your configs. Order of Config Loading
Examples of Config Loading Order
Remember command line parameters take precedence over all else! Tricks to Make Life EasierSome users may have a wall-mounted or otherwise rotatable monitor, and may wish to actually play vertical games with the rotated display. The easiest way to accomplish this is to put your rotation modifiers into vertical.ini, where they will only affect vertical games. MAME Path HandlingMAME has a specific order it uses when checking for user files such as ROM sets and cheat files. Order of Path LoadingLet's use an example of the cheat file for AfterBurner 2 for Sega Genesis/MegaDrive (aburner2 in the megadrive softlist), and your cheatpath is set to "cheat" (as per the default) -- this is how MAME will search for that cheat file:
[todo: ROM set loading is slightly more complicated, adding CRC. Get that documented in the next day or two.] Shifter Toggle DisableThis is an advanced feature for alternative shifter handling for certain older arcade machines such as Spy Hunter and Outrun that used a two-way toggle switch for the shifter. By default, the shifter is treated as a toggle switch. One press of the mapped control for the shifter will switch it from low to high, and another will switch it back. This may not be ideal if you have access to a physical shifter that works identically to how the original machines did. (The input is on when in one gear, the input is off otherwise) Note that this feature will not help controller users and will not help with games that have more than two shifter states (e.g. five gears in modern racing games) This feature is not exposed through the graphical user interface in any way, as it is an extremely advanced tweak intended explicitly for people who have this specific need, have the hardware to take advantage of it, and the knowledge to use it correctly. Disabling and Enabling Shifter ToggleThis example will use the game Spy Hunter (set spyhunt) to demonstrate the exact change needed: You will need to manually edit the game .CFG file in the CFG folder (e.g. spyhunt.cfg) Start by loading MAME with the game in question. In our case, that will be mame spyhunt. Set up the controls as you would please, including mapping the shifter. Exit MAME, open the .cfg file in your text editor of choice. Inside the spyhunt.cfg file, you will find the following for the input. The actual input code in the middle can and will vary depending on the controller number and what input you have mapped. <port tag=":ssio:IP0" type="P1_BUTTON2" mask="16" defvalue="16"> The line you need to edit will be the port line defining the actual input. For Spy Hunter, that's going to be P1_BUTTON2. Add toggle="no" to the end of the tag, like follows: <port tag=":ssio:IP0" type="P1_BUTTON2" mask="16" defvalue="16" toggle="no"> Save and exit. To disable this, simply remove the toggle="no" from each desired .CFG input. BGFX Effects for (nearly) Everyone
IntroductionBy default, MAME outputs an idealized version of the video as it would be on the way to the arcade cabinet’s monitor, with minimal modification of the output (primarily to stretch the game image back to the aspect ratio the monitor would traditionally have, usually 4:3). This works well, but misses some of the nostalgia factor. Arcade monitors were never ideal, even in perfect condition, and the nature of a CRT display distorts that image in ways that change the appearance significantly. Modern LCD monitors simply do not look the same, and even computer CRT monitors cannot match the look of an arcade monitor without help. That’s where the new BGFX renderer with HLSL comes into the picture. HLSL simulates most of the effects that a CRT arcade monitor has on the video, making the result look a lot more authentic. However, HLSL requires some effort on the user’s part: the settings you use are going to be tailored to your PC’s system specs, and especially the monitor you’re using. Additionally, there were hundreds of thousands of monitors out there in arcades. Each was tuned and maintained differently, meaning there is no one correct appearance to judge by either. Basic guidelines will be provided here to help you, but you may also wish to ask for opinions on popular MAME-centric forums. Resolution and Aspect RatioResolution is a very important subject for HLSL settings. You will want MAME to be using the native resolution of your monitor to avoid additional distortion and lag caused by your monitor upscaling the display image. While most arcade machines used a 4:3 ratio display (or 3:4 for vertically oriented monitors like Pac-Man), it’s difficult to find a consumer display that is 4:3 at this point. The good news is that that extra space on the sides isn’t wasted. Many arcade cabinets used bezel artwork around the main display, and should you have the necessary artwork files, MAME will display that artwork. Turn the Zoom to Screen Area setting in the video options menu to scale and crop the artwork so the emulated screen fills your display in one direction. Some older LCD displays used a native resolution of 1280×1024 and were a 5:4 aspect ratio. There’s not enough extra space to display artwork, and you’ll end up with some very slight pillarboxing, but the results will be still be good and on-par with a 4:3 monitor. Getting Started with BGFXYou will need to have followed the initial MAME setup instructions elsewhere in this manual before beginning. Official MAME distributions include BGFX as of MAME 0.172, so you don’t need to download any additional files. Open your mame.ini file in your text editor of choice (e.g. Notepad), and make sure the following options are set correctly:
Now, you may want to take a moment to look below at the Configuration Settings section to see how to set up these next options. As explained in Order of Config Loading, MAME has a order in which it processes INI files. The BGFX settings can be edited in mame.ini, but to take full advantage of the power of MAME’s configuration files, you’ll want to copy the BGFX settings from mame.ini to one of the other configuration files and make changes there. In particular, you will want the bgfx_screen_chains to be specific to each game. Save your INI file(s) and you’re ready to begin. Configuration Settings
We make a distinction between emulated screens (which we’ll call a screen) and output windows or monitors (which we’ll call a window, set by the -numscreens option) here. Use colons (:) to separate windows, and commas (,) to separate screens in the -bgfx_screen_chains setting value. For the simple single window, single screen case, such as Pac-Man on one physical PC monitor, you can specify one entry like: bgfx_screen_chains hlsl Things get only slightly more complicated when we get to multiple windows and multiple screens. On a single window, multiple screen game, such as Darius on one physical PC monitor, specify screen chains (one per window) like: bgfx_screen_chains hlsl,hlsl,hlsl This also works with single screen games where you are mirroring the output to more than one physical display. For instance, you could set up Pac-Man to have one unfiltered output for use with video broadcasting while a second display is set up HLSL for playing on. On a multiple window, multiple screen game, such as Darius on three physical PC monitors, specify multiple entries (one per window) like: bgfx_screen_chains hlsl:hlsl:hlsl Another example game would be Taisen Hot Gimmick, which used two CRTs to show individual player hands to just that player. If using two windows (two physical displays): bgfx_screen_chains hlsl:hlsl One more special case is that Nichibutsu had a special cocktail mahjong cabinet that used a CRT in the middle along with two LCD displays to show each player their hand. We would want the LCDs to be unfiltered and untouched as they were, while the CRT would be improved through HLSL. Since we want to give each player their own full screen display (two physical monitors) along with the LCD, we’ll go with: -numscreens 2 -view0 "Player 1" -view1 "Player 2" -video bgfx -bgfx_screen_chains hlsl,unfiltered:hlsl,unfiltered This sets up the view for each display respectively, keeping HLSL effect on the CRT for each window (physical display) while going unfiltered for the LCD screens. If using only one window (one display), keep in mind the game still has three screens, so we would use: bgfx_screen_chains hlsl,unfiltered,unfiltered Note that the commas are on the outside edges, and any colons are in the middle.
Tweaking BGFX HLSL Settings inside MAMEStart by loading MAME with the game of your choice (e.g. mame pacman). The tilde key (~) brings up the on-screen display options. Use up and down to go through the various settings, while left and right will allow you to change that setting. Results will be shown in real time as you’re changing these settings. Note that settings are individually changeable on a per-screen basis. BGFX slider settings are saved per-system in CFG files. If the bgfx_screen_chains setting has been set (either in an INI file or on the command line), it will set the initial effects. If the bgfx_screen_chains setting has not been set, MAME will use the effects you chose the last time you ran the system. Using the included pillarbox filtersMAME includes example BGFX shaders and layouts for filling unused space on a 16:9 widescreen display with a blurred version of the emulated video. The all the necessary files are included, and just need to be enabled. For systems using 4:3 horizontal monitors, use these options: -override_artwork bgfx/border_blur -view Horizontal -bgfx_screen_chains crt-geom,pillarbox_left_horizontal,pillarbox_right_horizontal For systems using 3:4 vertical monitors, use these options: -override_artwork bgfx/border_blur -view Vertical -bgfx_screen_chains crt-geom,pillarbox_left_vertical,pillarbox_right_vertical
HLSL Effects for WindowsBy default, MAME outputs an idealized version of the video as it would be on the way to the arcade cabinet's monitor, with minimal modification of the output (primarily to stretch the game image back to the aspect ratio the monitor would traditionally have, usually 4:3) -- this works well, but misses some of the nostalgia factor. Arcade monitors were never ideal, even in perfect condition, and the nature of a CRT display distorts that image in ways that change the appearance significantly. Modern LCD monitors simply do not look the same, and even computer CRT monitors cannot match the look of an arcade monitor without help. That's where HLSL comes into the picture. HLSL simulates most of the effects that a CRT arcade monitor has on the video, making the result look a lot more authentic. However, HLSL requires some effort on the user's part: the settings you use are going to be tailored to your PC's system specs, and especially the monitor you're using. Additionally, there were hundreds of thousands of monitors out there in arcades. Each was tuned and maintained differently, meaning there is no one correct appearance to judge by either. Basic guidelines will be provided here to help you, but you may also wish to ask for opinions on popular MAME-centric forums. Resolution and Aspect RatioResolution is a very important subject for HLSL settings. You will want MAME to be using the native resolution of your monitor to avoid additional distortion and lag created by your monitor upscaling the display image. While most arcade machines used a 4:3 ratio display (or 3:4 for vertically oriented monitors like Pac-Man), it's difficult to find a consumer display that is 4:3 at this point. The good news is that that extra space on the sides isn't wasted. Many arcade cabinets used bezel artwork around the main display, and should you have the necessary artwork files, MAME will display that artwork. Turn the artwork view to Cropped for best results. Some older LCD displays used a native resolution of 1280x1024 and were a 5:4 aspect ratio. There's not enough extra space to display artwork, and you'll end up with some very slight pillarboxing, but the results will be still be good and on-par with a 4:3 monitor. Getting Started with HLSLYou will need to have followed the initial MAME setup instructions elsewhere in this manual before beginning. Official MAME distributions include HLSL by default, so you don't need to download any additional files. Open your mame.ini in your text editor of choice (e.g. Notepad), and make sure the following options are set correctly:
The former is required because HLSL requires Direct3D support. The latter turns off extra filtering that interferes with HLSL output. Lastly, one more edit will turn HLSL on:
Save the .INI file and you're ready to begin. Several presets have been included in the INI folder with MAME, allowing for good quick starting points for Nintendo Game Boy, Nintendo Game Boy Advance, Raster, and Vector monitor settings. Tweaking HLSL Settings inside MAMEFor multiple, complicated to explain reasons, HLSL settings are no longer saved when you exit MAME. This means that while tweaking settings is a little more work on your part, the results will always come out as expected. Start by loading MAME with the game of your choice (e.g. mame pacman) The tilde key (~) brings up the on-screen display options. Use up and down to go through the various settings, while left and right will allow you to change that setting. Results will be shown in real time as you're changing these settings. Once you've found settings you like, write the numbers down on a notepad and exit MAME. Configuration EditingAs referenced in Order of Config Loading, MAME has a order in which it processes INI files. The HLSL settings can be edited in mame.ini, but to take full advantage of the power of MAME's config files, you'll want to copy the HLSL settings from mame.ini to one of the other config files and make changes there. For instance, once you've found HLSL settings you think are appropriate for Neo Geo games, you can put those settings into neogeo.ini so that all Neo-Geo games will be able to take advantage of those settings without needing to add it to every game INI manually. Configuration Settingshlslpath Suggested defaults for raster-based games:
Vector GamesHLSL effects can also be used with vector games. Due to a wide variance of vector settings to optimize for each individual game, it is heavily suggested you add these to per-game INI files (e.g. tempest.ini) Shadowmasks were only present on color vector games, and should not be used on monochrome vector games. Additionally, vector games did not use scanlines, so that should also be turned off. Open your INI file in your text editor of choice (e.g. Notepad), and make sure the following options are set correctly:
In the Core Vector Options section:
In the Vector Post-Processing Options section:
Suggested settings for vector games:
GLSL Effects for *nix, OS X, and WindowsBy default, MAME outputs an idealized version of the video as it would be on the way to the arcade cabinet's monitor, with minimal modification of the output (primarily to stretch the game image back to the aspect ratio the monitor would traditionally have, usually 4:3) -- this works well, but misses some of the nostalgia factor. Arcade monitors were never ideal, even in perfect condition, and the nature of a CRT display distorts that image in ways that change the appearance significantly. Modern LCD monitors simply do not look the same, and even computer CRT monitors cannot match the look of an arcade monitor without help. That's where GLSL comes into the picture. GLSL simulates most of the effects that a CRT arcade monitor has on the video, making the result look a lot more authentic. However, GLSL requires some effort on the user's part: the settings you use are going to be tailored to your PC's system specs, and especially the monitor you're using. Additionally, there were hundreds of thousands of monitors out there in arcades. Each was tuned and maintained differently, meaning there is no one correct appearance to judge by either. Basic guidelines will be provided here to help you, but you may also wish to ask for opinions on popular MAME-centric forums. Resolution and Aspect RatioResolution is a very important subject for GLSL settings. You will want MAME to be using the native resolution of your monitor to avoid additional distortion and lag created by your monitor upscaling the display image. While most arcade machines used a 4:3 ratio display (or 3:4 for vertically oriented monitors like Pac-Man), it's difficult to find a consumer display that is 4:3 at this point. The good news is that that extra space on the sides isn't wasted. Many arcade cabinets used bezel artwork around the main display, and should you have the necessary artwork files, MAME will display that artwork. Turn the artwork view to Cropped for best results. Some older LCD displays used a native resolution of 1280x1024, which is a 5:4 aspect ratio. There's not enough extra space to display artwork, and you'll end up with some very slight pillarboxing, but the results will be on-par with a 4:3 monitor. Getting Started with GLSLYou will need to have followed the initial MAME setup instructions elsewhere in this manual before beginning. Official MAME distributions include GLSL support by default, but do NOT include the GLSL shader files. You will need to obtain the shader files from third party online sources. Open your mame.ini in your text editor of choice (e.g. Notepad), and make sure the following options are set correctly:
The former is required because GLSL requires OpenGL support. The latter turns off extra filtering that interferes with GLSL output. Lastly, one more edit will turn GLSL on:
Save the .INI file and you're ready to begin. Tweaking GLSL Settings inside MAMEFor multiple, complicated to explain reasons, GLSL settings are no longer saved when you exit MAME. This means that while tweaking settings is a little more work on your part, the results will always come out as expected. Start by loading MAME with the game of your choice (e.g. mame pacman) The tilde key (~) brings up the on-screen display options. Use up and down to go through the various settings, while left and right will allow you to change that setting. Results will be shown in real time as you're changing these settings. Once you've found settings you like, write the numbers down on a notepad and exit MAME. Configuration EditingAs referenced in Order of Config Loading, MAME has a order in which it processes INI files. The GLSL settings can be edited in mame.ini, but to take full advantage of the power of MAME's config files, you'll want to copy the GLSL settings from mame.ini to one of the other config files and make changes there. For instance, once you've found GLSL settings you think are appropriate for Neo Geo games, you can put those settings into neogeo.ini so that all Neo-Geo games will be able to take advantage of those settings without needing to add it to every game INI manually. Configuration Settingsgl_glsl Controller Configuration Files
IntroductionController configuration files can be used to modify MAME’s default input settings. Controller configuration files may be supplied with an input device to provide more suitable defaults, or used as profiles that can be selected for different situations. MAME includes a few sample controller configuration files in the ctrlr folder, designed to provide useful defaults for certain arcade-style controllers. Controller configuration files are an XML application, using the .cfg filename extension. MAME searches for controller configuration files in the directories specified using the ctrlrpath option. A controller configuration file is selected by setting the ctrlr option to its filename, excluding the .cfg extension (e.g. set the ctrlr option to scorpionxg to use scorpionxg.cfg). It is an error if the specified controller configuration file does not exist, or if it contains no sections applicable to the emulated system. Controller configuration files use implementation-dependent input tokens. The values available and their precise meanings depend on the exact version of MAME used, the input devices connected, the selected input provider modules (keyboardprovider, mouseprovider, lightgunprovider and joystickprovider options), and possibly other settings. Basic structureController configuration files follow a similar format to the system configuration files that MAME uses to save things like input settings and bookkeeping data (created in the folder specified using the cfg_directory option). This example shows the overall structure of a controller configuration file: <?xml version="1.0"?> <mameconfig version="10"> The root of a controller configuration file must be a mameconfig element, with a version attribute specifying the configuration format version (currently 10 – MAME will not load a file using a different version). The mameconfig element contains one or more system elements, each of which has a name attribute specifying the system(s) it applies to. Each system element may contain an input element which holds the actual remap and port configuration elements, which will be described later. Each system element may also contain a pointer_input element to set pointer input options for systems with interactive artwork. When launching an emulated system, MAME will apply configuration from system elements where the value of the name attribute meets one of the following criteria:
For example, for the game “DaeJeon! SanJeon SuJeon (AJTUE 990412 V1.000)”, system elements will be applied if their name attribute has the value default (applies to all systems), sanjeon (short name of the system itself), sasissu (short name of the parent system), stvbios (short name of the BIOS system), or stv.cpp (source file where the system is defined). As another example, a system element whose name attribute has the value zac2650.cpp will be applied for the systems “The Invaders”, “Super Invader Attack (bootleg of The Invaders)”, and “Dodgem”. Applicable system elements are applied in the order they appear in the controller configuration file. Settings from elements that appear later in the file may modify or override settings from elements that appear earlier. Within a system element, remap elements are applied before port elements. Substituting default controlsYou can use a remap element to substitute one host input for another in MAME’s default input configuration. For example, this substitutes keys on the numeric keypad for the cursor direction keys: <input> The origcode attribute specifies the token for the host input to be substituted, and the newcode attribute specifies the token for the replacement host input. In this case, assignments using the cursor up, down, left and right arrows will be replaced with the numeric 8, 2, 4 and 6 keys on the numeric keypad, respectively. Note that substitutions specified using remap elements only apply to inputs that use MAME’s default assignment for the input type. That is, they only apply to default assignments for control types set in the “Input Assignments (general)” menus. They do not apply to default control assignments set in driver/device I/O port definitions (using the PORT_CODE macro). MAME applies remap elements found inside any applicable system element. Overriding defaults by input typeUse port elements with type attributes but without tag attributes to override the default control assignments for emulated inputs by type: <input> This sets the following default input assignments:
Note that this will only apply for inputs that use MAME’s default assignment for the input type. That is, port elements without tag attributes only override default assignments for control types set in the “Input Assignments (general)” menus. They do not override default control assignments set in driver/device I/O port definitions (using the PORT_CODE macro). MAME applies port elements without tag attributes found inside any applicable system element. Overriding defaults for specific inputsUse port elements with tag, type, mask and defvalue attributes to override defaults for specific inputs. These port elements should only occur inside system elements that apply to particular systems or source files (i.e. they should not occur inside system elements where the name attribute has the value default). The default control assignments can be overridden, as well as the toggle setting for digital inputs. The tag, type, mask and defvalue are used to identify the affected input. You can find out the values to use for a particular input by changing its control assignment, exiting MAME, and checking the values in the system configuration file (created in the folder specified using the cfg_directory option). Note that these values are not guaranteed to be stable, and may change between MAME versions. Here’s an example that overrides defaults for 280-ZZZAP: <system name="280zzzap"> This sets the controls to steer left and right to the K and J keys, respectively, and disables the toggle setting for the gear shift input. Assigning input device numbersUse mapdevice elements with device and controller attributes to assign stable numbers to input devices. Note that all devices explicitly configured in this way must be connected when MAME starts for this to work as expected. Set the device attribute to the device ID of the input device, and set the controller attribute to the desired input device token (device type and number). Here’s an example numbering two light guns and two XInput game controllers: <system name="default"> MAME applies mapdevice elements found inside the first applicable system element only. To avoid confusion, it’s simplest to place the system element applying to all systems (name attribute set to default) first in the file, and use it to assign input device numbers. Setting pointer input optionsA pointer_input element may contain target elements to set pointer input options for each output screen or window. Each target element must have an index attribute containing the zero-based index of the screen to which it applies. Each target element may have an activity_timeout attribute to set the time after which a mouse pointer that has not moved and has no buttons pressed will be considered inactive. The value is specified in seconds, and must be in the range of 0.1 seconds to 10 seconds, inclusive. Each target element may have a hide_inactive element to set whether inactive pointers may be hidden. If the value is 0 (zero), inactive pointers will not be hidden. If the value is 1, inactive pointers may be hidden, but layout views can still specify that inactive pointers should not be hidden. Here’s an example demonstrating the use of this feature: <system name="default"> For all systems, pointers over the first output screen or window will be considered inactive after not moving for 1.5 seconds with no buttons pressed. For systems defined in intellec4.cpp, inactive pointers over the first window will not be hidden. Stable Controller IDsBy default, MAME does not assign stable numbers to input devices. For instance, a game pad controller may be assigned to “Joy 1” initially, but after restarting, the same game pad may be reassigned to “Joy 3”. The reason is that MAME assigns numbers to input devices in the based on enumeration order. Factors that can cause this to change include disconnecting and reconnecting USB or Bluetooth devices, changing ports/hubs, and even just restarting the computer. Input device numbers can be quite unpredictable. This is where the mapdevice configuration setting comes into the picture. By adding this setting to a controller configuration file, you can ensure that a given input device is always assigned the same number in MAME. Using mapdeviceThe mapdevice XML element is added to the input XML element in the controller configuration file. It requires two attributes, device and controller. Note that mapdevice elements only take effect in the controller configuration file (set using the -ctrlr option) – they are ignored in system configuration files and the default configuration file. The device attribute specifies the device ID of the input device to match. It may also be a substring of the device ID. To obtain the device ID for an input device, select it in the Input Devices menu, and then select Copy Device ID. The device ID will be copied to the clipboard. You can also see input device IDs by turning on verbose logging (more on this later). The format of device IDs depends the type of device, selected input provider module and operating system. Your input device IDs may look very different to the examples here. The controller attribute specifies the input token for the input device type (i.e. JOYCODE, GUNCODE, MOUSECODE) and number to assign to the device, separated by an underscore. Numbering starts from 1. For example the token for the first joystick device will be JOYCODE_1, the second will be JOYCODE_2, and so on. ExampleHere’s an example: <mameconfig version="10"> In the above example, we have four device mappings specified:
Listing Available DevicesThere are two ways to obtain device IDs: by copying them from the Input Devices menu, or by turning on verbose logging and finding the messages logged when input devices are added. To reach the Input Devices menu from the system selection menu, select General Settings, and the select Input Devices. To reach the input devices menu from the main menu, select Input Settings, then select Input Devices. From the Input Devices menu, select a device, then select Copy Device ID to copy its device ID to the clipboard. To use verbose logging, run MAME with the -v or -verbose option on the command line. Search the output for messages starting with “Input: Adding…” that show recognised input devices and their respective IDs. Here an example: Input: Adding lightgun #1: Input: Adding lightgun #2: Input: Adding lightgun #3: HID-compliant mouse (device id: \\?\HID#VID_045E&PID_0053#7&18297dcb&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}) Input: Adding lightgun #4: HID-compliant mouse (device id: \\?\HID#IrDeviceV2&Col08#2&2818a073&0&0007#{378de44c-56ef-11d1-bc8c-00a0c91405dd}) Input: Adding lightgun #5: HID-compliant mouse (device id: \\?\HID#VID_D209&PID_1602&MI_02#8&389ab7f3&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}) Input: Adding lightgun #6: HID-compliant mouse (device id: \\?\HID#VID_D209&PID_1601&MI_02#9&375eebb1&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}) Input: Adding lightgun #7: HID-compliant mouse (device id: \\?\HID#VID_1241&PID_1111#8&198f3adc&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}) Skipping DirectInput for XInput compatible joystick Controller (XBOX 360 For Windows). Input: Adding joystick #1: ATRAK Device #1 (device id: ATRAK Device #1) Skipping DirectInput for XInput compatible joystick Controller (XBOX 360 For Windows). Input: Adding joystick #2: ATRAK Device #2 (device id: ATRAK Device #2) Input: Adding joystick #3: XInput Player 1 (device id: XInput Player 1) Input: Adding joystick #4: XInput Player 2 (device id: XInput Player 2) Furthermore, when devices are reassigned using mapdevice elements in the controller configuration file, you’ll see that in the verbose log output, too, such as: Input: Remapped lightgun #1: HID-compliant mouse (device id: \\?\HID#VID_D209&PID_1601&MI_02#9&375eebb1&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}) Input: Remapped lightgun #2: HID-compliant mouse (device id: \\?\HID#VID_D209&PID_1602&MI_02#8&389ab7f3&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}) Input: Remapped joystick #1: XInput Player 1 (device id: XInput Player 1) Input: Remapped joystick #2: XInput Player 2 (device id: XInput Player 2) LimitationsYou can only assign stable numbers to devices if MAME receives stable, unique device IDs from the input device provider and operating system. This is not always the case. For example the SDL joystick provider is not capable of providing unique IDs for many USB game controllers. If not all configured devices are connected when MAME starts, the devices that are connected may not be numbered as expected. Linux LightgunsMany lightguns (especially the Ultimarc AimTrak) may work better in MAME under Linux when using a slightly more complicated configuration. The instructions here are for getting an AimTrak working on Ubuntu using udev and Xorg, but other Linux distributions and lightguns may work with some changes to the steps. Configure udev rulesFor the AimTrak, each lightgun exposes several USB devices once connected: 2 mouse emulation devices, and 1 joystick emulation device. We need to instruct libinput via udev to ignore all but the correct emulated mouse device. This prevents each lightgun from producing multiple mouse devices, which would result in non-deterministic selection between the "good" and "bad" emulated mouse devices by Xorg. Create a new file named /etc/udev/rules.d/65-aimtrak.rules and place the following contents into it: # Set mode (0666) & disable libinput handling to avoid X11 picking up the wrong # interfaces/devices. SUBSYSTEMS=="usb", ATTRS{idVendor}=="d209", ATTRS{idProduct}=="160*", This configuration will be correct for the AimTrak lightguns, however each brand of lightgun will require their own settings. Configure Xorg inputsNext, we'll configure Xorg to treat the lightguns as a "Floating" device. This is important for multiple lightguns to work correctly and ensures each gun's emulated mouse pointer is NOT merged with the main system mouse pointer. In /etc/X11/xorg.conf.d/60-aimtrak.conf we will need: Section "InputClass" Configure MAMENext, we'll need to configure MAME via mame.ini to use the new lightgun device(s).
These first three lines tell MAME to enable lightgun support, to tell MAME that we're using a lightgun instead of a mouse, and to use the x11 provider.
These next lines then tell MAME to keep lightguns consistent across sessions.
Lastly, as most lightgun games require offscreen reloading and we're using a device that actually can point away from the screen, we enable that functionality. MAME DEBUGGER
IntroductionMAME includes an interactive low-level debugger that targets the emulated system. This can be a useful tool for diagnosing emulation issues, developing software to run on vintage systems, creating cheats, ROM hacking, or just investigating how software works. Use the -debug command line option to start MAME with the debugger activated. By default, pressing the backtick/tilde (~) during emulation breaks into the debugger (this can be changed by reassigning the Break in Debugger input). The exact appearance of the debugger depends on your operating system and the options MAME was built with. All variants of the debugger provide a multi-window interface for viewing the contents of memory and disassembled code. The debugger console window is a special window that shows the contents of CPU registers and disassembled code around the current program counter address, and provides a command-line interface to most of the debugging functionality. Debugger commandsDebugger commands are described in the sections below. You can also type help <topic> in the debugger console, where <topic> is the name of a command, to see documentation directly in MAME. General Debugger Commands
helphelp [<topic>] Displays built-in debugger help in the debugger console. If no <topic> is specified, top-level topics are listed. Most debugger commands have correspondingly named help topics. Examples:
Back to General Debugger Commands dodo <expression> The do command simply evaluates the supplied expression. This is often used to set or modify device state variable (e.g. CPU registers), or to write to memory. See Debugger expression syntax for details about expression syntax. Examples:
Back to General Debugger Commands symlistsymlist [<cpu>] Lists registered symbols and their values. If <cpu> is not specified, symbols in the global symbol table are displayed; otherwise, symbols specific to the device <cpu> are displayed. Symbols are listed alphabetically. Read-only symbols are noted. See Specifying devices and address spaces for details on how to specify a CPU. Examples:
Back to General Debugger Commands softresetsoftreset Executes a soft reset. This calls the reset member functions of all the devices in the system (by default, pressing F3 during emulation has the same effect). Examples:
Back to General Debugger Commands hardresethardreset Executes a hard reset. This tears down the emulation session and starts another session with the same system and options (by default, pressing Shift+F3 during emulation has the same effect). Note that this will lose history in the debugger console and error log. Examples:
Back to General Debugger Commands print <item>[,…] The print command prints the results of one or more expressions to the debugger console as hexadecimal numbers. Examples:
Back to General Debugger Commands printfprintf <format>[,<argument>[,…]] Prints a C-style formatted message to the debugger console. Only a very limited subset of format specifiers and escape sequences are available:
All other format specifiers are ignored. Examples:
Back to General Debugger Commands logerrorlogerror <format>[,<argument>[,…]] Prints a C-style formatted message to the error log. See printf for details about the limited set of supported format specifiers and escape sequences. Examples:
Back to General Debugger Commands tracelogtracelog <format>[,<argument>[,…]] Prints a C-style formatted message to the currently open trace file (see trace for more information). If no trace file is open, this command has no effect. See printf for details about the limited set of supported format specifiers and escape sequences. Examples:
Back to General Debugger Commands tracesymtracesym <item>[,…] Prints the specified symbols to the currently open trace file (see trace for more information). If no trace file is open, this command has no effect. Examples:
Back to General Debugger Commands historyhistory [<CPU>[,<length>]] Displays recently visited PC addresses, and disassembly of the instructions at those addresses. If present, the first argument selects the CPU (see Specifying devices and address spaces for details); if no CPU is specified, the visible CPU is assumed. The second argument, if present, limits the maximum number of addresses shown. Addresses are shown in order from least to most recently visited. Examples:
trackpctrackpc [<enable>[,<CPU>[,<clear>]]] Turns visited PC address tracking for disassembly views on or off. Instructions at addresses visited while tracking is on are highlighted in debugger disassembly views. The first argument is a Boolean specifying whether tracking should be turned on or off (defaults to on). The second argument specifies the CPU to enable or disable tracking for (see Specifying devices and address spaces for details); if no CPU is specified, the visible CPU is assumed. The third argument is a Boolean specifying whether existing data should be cleared (defaults to false). Examples:
Back to General Debugger Commands trackmemtrackmem [<enable>,[<CPU>,[<clear>]]] Enables or disables logging the PC address each time a memory address is written to. The first argument is a Boolean specifying whether tracking should be enabled or disabled (defaults to enabled). The second argument specifies the CPU to enable or disable tracking for (see Specifying devices and address spaces for details); if no CPU is specified, the visible CPU is assumed. The third argument is a Boolean specifying whether existing data should be cleared (defaults to false). Use pcatmem to retrieve this data. Right-clicking a debugger memory view will also display the logged PC value for the given address in some configurations. Examples:
Back to General Debugger Commands pcatmempcatmem[{d|i|o}] <address>[:<space>] Returns the PC value at the time the specified address was most recently written to. The argument is the requested address, optionally followed by a colon and a CPU and/or address space (see Specifying devices and address spaces for details). The optional d, i or o suffix controls the default address space for the command. Tracking must be enabled for the data this command uses to be recorded (see trackmem). Right-clicking a debugger memory view will also display the logged PC value for the given address in some configurations. Examples:
Back to General Debugger Commands rewindrewind Loads the most recent RAM-based saved state. When enabled, rewind states are saved when step, over and out commands are used, storing the machine state as of the moment before stepping. May be abbreviated to rw. Consecutively loading rewind states can work like reverse execution. Depending on which steps forward were taken previously, the behavior can be similar to GDB's reverse-stepi and reverse-next commands. All output for this command is currently echoed into the running machine window. Previous memory and PC tracking statistics are cleared. Actual reverse execution does not occur. Examples:
Back to General Debugger Commands statesavestatesave <filename> Creates a save state at the current moment in emulated time. The state file is written to the configured save state directory (see the state_directory option), and the .sta extension is automatically appended to the specified file name. May be abbreviates to ss. All output from this command is currently echoed into the running machine window. Examples:
Back to General Debugger Commands stateloadstateload <filename> Restores a saved state file from disk. The specified state file is read from the configured save state directory (see the state_directory option), and the .sta extension is automatically appended to the specified file name. May be abbreviated to sl. All output for this command is currently echoed into the running machine window. Previous memory and PC tracking statistics are cleared. Examples:
Back to General Debugger Commands snapsnap [<filename>[,<scrnum>]] Takes a snapshot of the emulated video display and saves it to the configured snapshot directory (see the snapshot_directory option). If a file name is specified, a single screenshot for the specified screen is saved using the specified filename (or the first emulated screen in the system if a screen is not specified). If a file name is not specified, the configured snapshot view and file name pattern are used (see the snapview and snapname options). If a file name is specified, the .png extension is automatically appended. The screen number is specified as a zero-based index, as seen in the names of automatically-generated single-screen views in MAME’s video options menus. Examples:
Back to General Debugger Commands sourcesource <filename> Reads the specified file in text mode and executes each line as a debugger command. This is similar to running a shell script or batch file. Examples:
Back to General Debugger Commands timePrints the total elapsed emulated time to the debugger console. Examples:
Back to General Debugger Commands quitquit Closes the debugger and ends the emulation session immediately. Either exits MAME or returns to the system selection menu, depending on whether the system was specified on the command line when starting MAME. Examples:
Back to General Debugger Commands Memory Debugger Commands
dasmdasm <filename>,<address>,<length>[,<opcodes>[,<CPU>]] Disassembles program memory to the file specified by the <filename> parameter. The <address> parameter specifies the address to start disassembling from, and the <length> parameter specifies how much memory to disassemble. The range <address> through <address>+<length>-1, inclusive, will be disassembled to the file. By default, raw opcode data is output with each line. The optional <opcodes> parameter is a Boolean that enables disables this feature. By default, program memory for the visible CPU is disassembled. To disassemble program memory for a different CPU, specify it using the optional fifth parameter (see Specifying devices and address spaces for details). Examples:
Back to Memory Debugger Commands findf[ind][{d|i|o}] <address>[:<space>],<length>[,<data>[,…]] Search through memory for the specified sequence of data. The <address> is the address to begin searching from, optionally followed by a device and/or address space (see Specifying devices and address spaces for details); the <length> specifies how much memory to search. If an address space is not specified, the command suffix sets the address space: find defaults to the first address space exposed by the device, findd defaults to the space with index 1 (data), findi default to the space with index 2 (I/O), and findo defaults to the space with index 3 (opcodes). The <data> can either be a quoted string, a numeric value or expression, or the wildcard character ?. By default, strings imply a byte-sized search; by default non-string data is searched using the native word size of the address space. To override the search size for non-string data, you can prefix values with b. to force byte-sized search, w. for word-sized search, d. for double word-sized search, and q. for quadruple word-sized search. Overrides propagate to subsequent values, so if you want to search for a sequence of words, you need only prefix the first value with w.. Also note that you can intermix sizes to perform more complex searches. The entire range <address> through <address>+<length>-1, inclusive, will be searched for the sequence, and all occurrences will be displayed. Examples:
Back to Memory Debugger Commands fillfill[{d|i|o}] <address>[:<space>],<length>[,<data>[,…]] Overwrite a block of memory with copies of the supplied data sequence. The <address> specifies the address to begin writing at, optionally followed by a device and/or address space (see Specifying devices and address spaces for details); the <length> specifies how much memory to fill. If an address space is not specified, the command suffix sets the address space: fill defaults to the first address space exposed by the device, filld defaults to the space with index 1 (data), filli default to the space with index 2 (I/O), and fillo defaults to the space with index 3 (opcodes). The <data> can either be a quoted string, or a numeric value or expression. By default, non-string data is written using the native word size of the address space. To override the data size for non-string data, you can prefix values with b. to force byte-sized fill, w. for word-sized fill, d. for double word-sized fill, and q. for quadruple word-sized fill. Overrides propagate to subsequent values, so if you want to fill with a series of words, you need only prefix the first value with w.. Also note that you can intermix sizes to perform more complex fills. The fill operation may be truncated if a page fault occurs or if part of the sequence or string would fall beyond <address>+<length>-1. Back to Memory Debugger Commands dumpdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<group>[,<ascii>[,<rowsize>]]] Dump memory to the text file specified by the <filename> parameter. The <address> specifies the address to start dumping from, optionally followed by a device and/or address space (see Specifying devices and address spaces for details); the <length> specifies how much memory to dump. If an address space is not specified, the command suffix sets the address space: dump defaults to the first address space exposed by the device, dumpd defaults to the space with index 1 (data), dumpi default to the space with index 2 (I/O), and dumpo defaults to the space with index 3 (opcodes). The range <address> through <address>+<length>-1, inclusive, will be output to the file. By default, the data will be output using the native word size of the address space. You can override this by specifying the <group> parameter, which can be used to group the data in 1-, 2-, 4- or 8-byte chunks. The optional <ascii> parameter is a Boolean value used to enable or disable output of ASCII characters on the right of each line (enabled by default). The optional <rowsize> parameter specifies the amount of data on each line in address units (defaults to 16 bytes). Examples:
Back to Memory Debugger Commands strdumpstrdump[{d|i|o}] <filename>,<address>[:<space>],<length>[,<term>] Dump memory to the text file specified by the <filename> parameter. The <address> specifies the address to start dumping from, optionally followed by a device and/or address space (see Specifying devices and address spaces for details); the <length> specifies how much memory to dump. If an address space is not specified, the command suffix sets the address space: strdump defaults to the first address space exposed by the device, strdumpd defaults to the space with index 1 (data), strdumpi default to the space with index 2 (I/O), and strdumpo defaults to the space with index 3 (opcodes). By default, the data will be interpreted as a series of NUL-terminated (ASCIIZ) strings, the dump will have one string per line, and C-style escapes sequences will be used for bytes that do not represent printable ASCII characters. The optional <term> parameter can be used to specify a different string terminator character. Back to Memory Debugger Commands savesave[{d|i|o}] <filename>,<address>[:<space>],<length> Save raw memory to the binary file specified by the <filename> parameter. The <address> specifies the address to start saving from, optionally followed by a device and/or address space (see Specifying devices and address spaces for details); the <length> specifies how much memory to save. If an address space is not specified, the command suffix sets the address space: save defaults to the first address space exposed by the device, saved defaults to the space with index 1 (data), savei default to the space with index 2 (I/O), and saveo defaults to the space with index 3 (opcodes). The range <address> through <address>+<length>-1, inclusive, will be output to the file. Examples:
Back to Memory Debugger Commands saversaver <filename>,<address>,<length>,<region> Save raw content of memory region specified by the <region> parameter to the binary file specified by the <filename> parameter. Regions tags follow the same rules as device tags (see Specifying devices and address spaces). The <address> specifies the address to start saving from, and the <length> specifies how much memory to save. The range <address> through <address>+<length>-1, inclusive, will be output to the file. Examples:
Back to Memory Debugger Commands loadload[{d|i|o}] <filename>,<address>[:<space>][,<length>] Load raw memory from the binary file specified by the <filename> parameter. The <address> specifies the address to start loading to, optionally followed by a device and/or address space (see Specifying devices and address spaces for details); the <length> specifies how much memory to load. If an address space is not specified, the command suffix sets the address space: load defaults to the first address space exposed by the device, loadd defaults to the space with index 1 (data), loadi default to the space with index 2 (I/O), and loado defaults to the space with index 3 (opcodes). The range <address> through <address>+<length>-1, inclusive, will be read in from the file. If the <length> is omitted, if it is zero, or if it is greater than the total length of the file, the entire contents of the file will be loaded but no more. Note that this has the same effect as writing to the address space from a debugger memory view, or using the b@, w@, d@ or q@ memory accessors in debugger expressions. Read-only memory will not be overwritten, and writing to I/O addresses may have effects beyond setting register values. Examples:
Back to Memory Debugger Commands loadrloadr <filename>,<address>,<length>,<region> Load memory in the memory region specified by the <region> with raw data from the binary file specified by the <filename> parameter. Regions tags follow the same rules as device tags (see Specifying devices and address spaces). The <address> specifies the address to start loading to, and the <length> specifies how much memory to load. The range <address> through <address>+<length>-1, inclusive, will be read in from the file. If the <length> is zero, or is greater than the total length of the file, the entire contents of the file will be loaded but no more. Examples:
Back to Memory Debugger Commands mapmap[{d|i|o}] <address>[:<space>] Map a logical memory address to the corresponding physical address, as well as reporting the handler name. The address may optionally be followed by a colon and device and/or address space (see Specifying devices and address spaces for details). If an address space is not specified, the command suffix sets the address space: map defaults to the first address space exposed by the device, mapd defaults to the space with index 1 (data), mapi default to the space with index 2 (I/O), and mapo defaults to the space with index 3 (opcodes). Examples:
Back to Memory Debugger Commands memdumpmemdump [<filename>,[<device>]] Dumps the current memory maps to the file specified by <filename>, or memdump.log if omitted. If <device> is specified (see Specifying devices and address spaces), only memory maps for the part of the device tree rooted at this device will be dumped. Examples:
Back to Memory Debugger Commands Execution Debugger Commands
steps[tep] [<count>] Single steps one or more instructions on the currently executing CPU. Executes one instruction if <count> is omitted, or steps <count> instructions if it is supplied. Examples:
Back to Execution Debugger Commands overo[ver] [<count>] The over command single steps “over” one or more instructions on the currently executing CPU, stepping over subroutine calls and exception handler traps and counting them as a single instruction. Note that when stepping over a subroutine call, code may execute on other CPUs before the subroutine returns. Steps over one instruction if <count> is omitted, or steps over <count> instructions if it is supplied. Note that the step over functionality may not be implemented for all CPU types. If it is not implemented, then over will behave exactly like step. Examples:
Back to Execution Debugger Commands outout Single steps until a return from subroutine or return from exception instruction is encountered. Note that because it detects return from exception conditions, if you attempt to step out of a subroutine and an interrupt/exception occurs before the subroutine completes, execution may stop prematurely at the end of the exception handler. Note that the step out functionality may not be implemented for all CPU types. If it is not implemented, then out will behave exactly like step. Example:
Back to Execution Debugger Commands gog[o] [<address>] Resumes execution. Control will not be returned to the debugger until a breakpoint or watchpoint is triggered, or a debugger break is manually requested. If the optional <address> is supplied, a temporary unconditional breakpoint will be set for the visible CPU at the specified address. It will be cleared automatically when triggered. Examples: Back to Execution Debugger Commands gbfgbf [<condition>] Resumes execution. Control will not be returned to the debugger until a breakpoint or watchpoint is triggered, or until a conditional branch or skip instruction is not taken, following any delay slots. The optional <condition> parameter lets you specify an expression that will be evaluated each time a conditional branch is encountered. If the result of the expression is true (non-zero), execution will be halted after the branch if it is not taken; otherwise, execution will continue with no notification. Examples:
Back to Execution Debugger Commands gbtgbt [<condition>] Resumes execution. Control will not be returned to the debugger until a breakpoint or watchpoint is triggered, or until a conditional branch or skip instruction is taken, following any delay slots. The optional <condition> parameter lets you specify an expression that will be evaluated each time a conditional branch is encountered. If the result of the expression is true (non-zero), execution will be halted after the branch if it is taken; otherwise, execution will continue with no notification. Examples:
Back to Execution Debugger Commands gexge[x] [<exception>,[<condition>]] Resumes execution. Control will not be returned to the debugger until a breakpoint or watchpoint is triggered, or until an exception condition is raised on the current CPU. Use the optional <exception> parameter to stop execution only for a specific exception condition. If <exception> is omitted, execution will stop for any exception condition. The optional <condition> parameter lets you specify an expression that will be evaluated each time the specified exception condition is raised. If the result of the expression is true (non-zero), the exception will halt execution; otherwise, execution will continue with no notification. Examples:
Back to Execution Debugger Commands gintgi[nt] [<irqline>] Resumes execution. Control will not be returned to the debugger until a breakpoint or watchpoint is triggered, or until an interrupt is asserted and acknowledged on the current CPU. Use the optional <irqline> parameter to stop execution only for a specific interrupt line being asserted and acknowledged. If <irqline> is omitted, execution will stop when any interrupt is acknowledged. Examples:
Back to Execution Debugger Commands gnigni [<count>] Resumes execution. Control will not be returned to the debugger until a breakpoint or watchpoint is triggered. A temporary unconditional breakpoint is set at the program address <count> instructions sequentially past the current one. When this breakpoint is hit, it is automatically removed. The <count> parameter is optional and defaults to 1 if omitted. If <count> is specified as zero, the command does nothing. <count> is not permitted to exceed 512 decimal. Examples:
Back to Execution Debugger Commands gtimegt[ime] <milliseconds> Resumes execution. Control will not be returned to the debugger until a specified interval of emulated time has elapsed. The interval is specified in milliseconds. Example:
Back to Execution Debugger Commands gvblankgv[blank] Resumes execution. Control will not be returned to the debugger until a breakpoint or watchpoint is triggered, or until the beginning of the vertical blanking interval for an emulated screen. Example:
Back to Execution Debugger Commands nextn[ext] Resumes execution until a different CPU is scheduled. Execution will not stop when a CPU is scheduled if it is ignored due to the use of ignore or focus. Example:
Back to Execution Debugger Commands focusfocus <CPU> Focus exclusively on to the specified <CPU>, ignoring all other CPUs. The <CPU> argument can be a device tag or debugger CPU number (see Specifying devices and address spaces for details). This is equivalent to using the ignore command to ignore all CPUs besides the specified CPU. Examples:
Back to Execution Debugger Commands ignoreignore [<CPU>[,<CPU>[,…]]] Ignores the specified CPUs in the debugger. CPUs can be specified by tag or debugger CPU number (see Specifying devices and address spaces for details). The debugger never shows execution for ignored CPUs, and breakpoints or watchpoints on ignored CPUs have no effect. If no CPUs are specified, currently ignored CPUs will be listed. Use the observe command to stop ignoring a CPU. Note that you cannot ignore all CPUs; at least CPU must be observed at all times. Examples:
Back to Execution Debugger Commands observeobserve [<CPU>[,<CPU>[,…]]] Allow interaction with the specified CPUs in the debugger. CPUs can be specified by tag or debugger CPU number (see Specifying devices and address spaces for details). This command reverses the effects of the ignore command. If no CPUs are specified, currently observed CPUs will be listed. Examples:
Back to Execution Debugger Commands tracetrace {<filename>|off}[,<CPU>[,[noloop|logerror][,<action>]]] Starts or stops tracing for execution of the specified <CPU>, or the currently visible CPU if no CPU is specified. To enable tracing, specify the trace log file name in the <filename> parameter. To disable tracing, use the keyword off for the <filename> parameter. If the <filename> argument begins with two right angle brackets (>>), it is treated as a directive to open the file for appending rather than overwriting. The optional third parameter is a flags field. The supported flags are noloop and logerror. Multiple flags must be separated by | (pipe) characters. By default, loops are detected and condensed to a single line. If the noloop flag is specified, loops will not be detected and every instruction will be logged as executed. If the logerror flag is specified, error log output will be included in the trace log. The optional <action> parameter is a debugger command to execute before each trace message is logged. Generally, this will include a tracelog or tracesym command to include additional information in the trace log. Note that you may need to surround the action within braces { } to ensure commas and semicolons within the command are not interpreted in the context of the trace command itself. Examples:
Back to Execution Debugger Commands traceovertraceover {<filename>|off}[,<CPU>[,[noloop|logerror][,<action>]]] Starts or stops tracing for execution of the specified <CPU>, or the currently visible CPU if no CPU is specified. When a subroutine call is encountered, tracing will skip over the subroutine. The same algorithm is used as is used in the step over command. It will not work properly with recursive functions, or if the return address does not immediately follow the call instruction. This command accepts the same parameters as the trace command. Please refer to the corresponding section for a detailed description of options and more examples. Examples:
Back to Execution Debugger Commands traceflushtraceflush Flushes all open trace log files to disk. Example:
Back to Execution Debugger Commands Breakpoint Debugger Commands
Breakpoints halt execution and activate the debugger before a CPU executes an instruction at a particular address. bpsetbp[set] <address>[:<CPU>][,<condition>[,<action>]] Sets a new execution breakpoint at the specified <address>. The <address> may optionally be followed by a colon and a tag or debugger CPU number to set a breakpoint for a specific CPU. If no CPU is specified, the breakpoint will be set for the CPU currently visible in the debugger. The optional <condition> parameter lets you specify an expression that will be evaluated each time the breakpoint address is hit. If the result of the expression is true (non-zero), the breakpoint will halt execution; otherwise, execution will continue with no notification. The optional <action> parameter provides a command to be executed whenever the breakpoint is hit and the <condition> is true. Note that you may need to surround the action with braces { } to ensure commas and semicolons within the command are not interpreted in the context of the bpset command itself. Each breakpoint that is set is assigned a numeric index which can be used to refer to it in other breakpoint commands. Breakpoint indices are unique throughout a session. Examples:
Back to Breakpoint Debugger Commands bpclearbpclear [<bpnum>[,…]] Clear breakpoints. If <bpnum> is specified, the breakpoints referred to will be cleared. If <bpnum> is not specified, all breakpoints will be cleared. Examples:
Back to Breakpoint Debugger Commands bpdisablebpdisable [<bpnum>[,…]] Disable breakpoints. If <bpnum> is specified, the breakpoints referred to will be disabled. If <bpnum> is not specified, all breakpoints will be disabled. Note that disabling a breakpoint does not delete it, it just temporarily marks the breakpoint as inactive. Disabled breakpoints will not cause execution to halt, their associated condition expressions will not be evaluated, and their associated commands will not be executed. Examples:
Back to Breakpoint Debugger Commands bpenablebpenable [<bpnum>[,…]] Enable breakpoints. If <bpnum> is specified, the breakpoint referred to will be enabled. If <bpnum> is not specified, all breakpoints will be enabled. Examples:
Back to Breakpoint Debugger Commands bplistbplist [<CPU>] List current breakpoints, along with their indices and any associated conditions or actions. If no <CPU> is specified, breakpoints for all CPUs in the system will be listed; if a <CPU> is specified, only breakpoints for that CPU will be listed. The <CPU> can be specified by tag or by debugger CPU number (see Specifying devices and address spaces for details). Examples:
Back to Breakpoint Debugger Commands Watchpoint Debugger Commands
Watchpoints halt execution and activate the debugger when a CPU accesses a location in a particular memory range. wpsetwp[{d|i|o}][set] <address>[:<space>],<length>,<type>[,<condition>[,<action>]] Sets a new watchpoint starting at the specified <address> and extending for <length>. The range of the watchpoint is <address> through <address>+<length>-1, inclusive. The <address> may optionally be followed by a CPU and/or address space (see Specifying devices and address spaces for details). If an address space is not specified, the command suffix sets the address space: wpset defaults to the first address space exposed by the CPU, wpdset defaults to the space with index 1 (data), wpiset defaults to the space with index 2 (I/O), and wposet defaults to the space with index 3 (opcodes). The <type> parameter specifies the access types to trap on – it can be one of three values: r for read accesses, w for write accesses, or rw for both read and write accesses. The optional <condition> parameter lets you specify an expression that will be evaluated each time the watchpoint is triggered. If the result of the expression is true (non-zero), the watchpoint will halt execution; otherwise, execution will continue with no notification. The optional <action> parameter provides a command to be executed whenever the watchpoint is triggered and the <condition> is true. Note that you may need to surround the action with braces { } to ensure commas and semicolons within the command are not interpreted in the context of the wpset command itself. Each watchpoint that is set is assigned a numeric index which can be used to refer to it in other watchpoint commands. Watchpoint indices are unique throughout a session. To make <condition> expressions more useful, two variables are available: for all watchpoints, the variable wpaddr is set to the access address that triggered the watchpoint; for write watchpoints, the variable wpdata is set to the data being written. Examples:
Back to Watchpoint Debugger Commands wpclearwpclear [<wpnum>[,…]] Clear watchpoints. If <wpnum> is specified, the watchpoints referred to will be cleared. If <wpnum> is not specified, all watchpoints will be cleared. Examples:
Back to Watchpoint Debugger Commands wpdisablewpdisable [<wpnum>[,…]] Disable watchpoints. If <wpnum> is specified, the watchpoints referred to will be disabled. If <wpnum> is not specified, all watchpoints will be disabled. Note that disabling a watchpoint does not delete it, it just temporarily marks the watchpoint as inactive. Disabled watchpoints will not cause execution to halt, their associated condition expressions will not be evaluated, and their associated commands will not be executed. Examples:
Back to Watchpoint Debugger Commands wpenablewpenable [<wpnum>[,…]] Enable watchpoints. If <wpnum> is specified, the watchpoints referred to will be enabled. If <wpnum> is not specified, all watchpoints will be enabled. Examples:
Back to Watchpoint Debugger Commands wplistwplist [<CPU>] List current watchpoints, along with their indices and any associated conditions or actions. If no <CPU> is specified, watchpoints for all CPUs in the system will be listed; if a <CPU> is specified, only watchpoints for that CPU will be listed. The <CPU> can be specified by tag or by debugger CPU number (see Specifying devices and address spaces for details). Examples:
Back to Watchpoint Debugger Commands Registerpoint Debugger Commands
Registerpoints evaluate an expression each time a CPU executes an instruction and halt execution and activate the debugger if the result is true (non-zero). rpsetrp[set] <condition>[,<action>] Sets a new registerpoint which will be triggered when the expression supplied as the <condition> evaluates to true (non-zero). Note that the condition may need to be surrounded with braces { } to prevent it from being interpreted as an assignment. The optional <action> parameter provides a command to be executed whenever the registerpoint is triggered. Note that you may need to surround the action with braces { } to ensure commas and semicolons within the command are not interpreted in the context of the rpset command itself. Each registerpoint that is set is assigned a numeric index which can be used to refer to it in other registerpoint commands. Registerpoint indices are unique throughout a session. Examples:
Back to Registerpoint Debugger Commands rpclearrpclear [<rpnum>,[,…]] Clears registerpoints. If <rpnum> is specified, the registerpoints referred to will be cleared. If <rpnum> is not specified, all registerpoints will be cleared. Examples:
Back to Registerpoint Debugger Commands rpdisablerpdisable [<rpnum>[,…]] Disables registerpoints. If <rpnum> is specified, the registerpoints referred to will be disabled. If <rpnum> is not specified, all registerpoints will be disabled. Note that disabling a registerpoint does not delete it, it just temporarily marks the registerpoint as inactive. Disabled registerpoints will not cause execution to halt, their condition expressions will not be evaluated, and their associated commands will not be executed. Examples:
Back to Registerpoint Debugger Commands rpenablerpenable [<rpnum>[,…]] Enables registerpoints. If <rpnum> is specified, the registerpoints referred to will be enabled. If <rpnum> is not specified, all registerpoints will be enabled. Examples:
Back to Registerpoint Debugger Commands rplistrplist [<CPU>] List current registerpoints, along with their indices and conditions, and any associated actions. If no <CPU> is specified, registerpoints for all CPUs in the system will be listed; if a <CPU> is specified, only registerpoints for that CPU will be listed. The <CPU> can be specified by tag or by debugger CPU number (see Specifying devices and address spaces for details). Examples:
Back to Registerpoint Debugger Commands Exceptionpoint Debugger Commands
Exceptionpoints halt execution and activate the debugger when a CPU raises a particular exception number. epsetep[set] <type>[,<condition>[,<action>]] Sets a new exceptionpoint for exceptions of type <type>. The optional <condition> parameter lets you specify an expression that will be evaluated each time the exceptionpoint is hit. If the result of the expression is true (non-zero), the exceptionpoint will actually halt execution at the start of the exception handler; otherwise, execution will continue with no notification. The optional <action> parameter provides a command that is executed whenever the exceptionpoint is hit and the <condition> is true. Note that you may need to embed the action within braces { } in order to prevent commas and semicolons from being interpreted as applying to the epset command itself. The numbering of exceptions depends upon the CPU type. Causes of exceptions may include internally or externally vectored interrupts, errors occurring within instructions and system calls. Each exceptionpoint that is set is assigned an index which can be used in other exceptionpoint commands to reference this exceptionpoint. Examples:
Back to Exceptionpoint Debugger Commands epclearepclear [<epnum>[,…]] The epclear command clears exceptionpoints. If <epnum> is specified, only the requested exceptionpoints are cleared, otherwise all exceptionpoints are cleared. Examples:
Back to Exceptionpoint Debugger Commands epdisableepdisable [<epnum>[,…]] The epdisable command disables exceptionpoints. If <epnum> is specified, only the requested exceptionpoints are disabled, otherwise all exceptionpoints are disabled. Note that disabling an exceptionpoint does not delete it, it just temporarily marks the exceptionpoint as inactive. Examples:
Back to Exceptionpoint Debugger Commands epenableepenable [<epnum>[,…]] The epenable command enables exceptionpoints. If <epnum> is specified, only the requested exceptionpoints are enabled, otherwise all exceptionpoints are enabled. Examples:
Back to Exceptionpoint Debugger Commands eplisteplist The eplist command lists all the current exceptionpoints, along with their index and any conditions or actions attached to them. Back to Exceptionpoint Debugger Commands Code Annotation Debugger Commands
comaddcomadd <address>,<comment> Sets the specified comment for the specified address in the disassembled code for the visible CPU. This command may be abbreviated to //. Examples:
comdeletecomdelete Deletes the comment at the specified address for the visible CPU. Examples:
comsavecomsave Saves the current comments to the XML comment file for the emulated system. This file will be loaded by the debugger the next time the system is run with debugging enabled. The directory for saving these files is set using the comment_directory option. Examples:
comlistcomlist Reads the comments stored in the XML comment file for the emulated system and prints them to the debugger console. This command does not affect the comments for the current session, it reads the file directly. The directory for these files is set using the comment_directory option. Examples:
commitcommit <address>,<comment> Sets the specified comment for the specified address in the disassembled code for the visible CPU, and saves comments to the file for the current emulated system (equivalent to comadd followed by comsave). This command may be abbreviated to /*. Examples:
Cheat Debugger Commands
The debugger includes basic cheat search functionality, which works by saving the contents of memory, and then filtering locations according to how the values change. We’ll demonstrate use of the cheat search functionality to make an infinite lives cheat for Raiden (raiden):
>cheatinit ub 36928 cheat locations initialized for NEC V30 ':maincpu' program space
>cheatnext -,1 12 cheats found
>cheatnext -,1 Address=0B85 Start=03 Current=01 1 cheats found
>cheatlist raiden-p1-lives.xml
<cheat desc="Possibility 1: 00B85 (01)"> cheatinitcheatinit [[<sign>[<width>[<swap>]]],[<address>,<length>[,<space>]]] Initialize the cheat search to writable RAM areas in the specified address space. May be abbreviated to ci. The first argument specifies the data format to search for. The <sign> may be u for unsigned or s for signed, the <width> may be b for 8-bit (byte), w for 16-bit (word), d for 32-bit (double word), or q for 64-bit (quadruple word); <swap> may be s for reversed byte order. If the first argument is omitted or empty, the data format from the previous cheat search is used, or unsigned 8-bit format if this is the first cheat search. The <address> specifies the address to start searching from, and the <length> specifies how much memory to search. If specified, writable RAM in the range <address> through <address>+<length>-1, inclusive, will be searched; otherwise, all writable RAM in the address space will be searched. See Specifying devices and address spaces for details on specifying address spaces. If the address space is not specified, it defaults to the first address space exposed by the visible CPU. Examples:
Back to Cheat Debugger Commands cheatrangecheatrange <address>,<length> Add writable RAM areas to the cheat search. May be abbreviated to cr. Before using this command, the cheatinit command must be used to initialize the cheat search and set the address space and data format. The <address> specifies the address to start searching from, and the <length> specifies how much memory to search. Writable RAM in the range <address> through <address>+<length>-1, inclusive, will be added to the areas to search. Examples:
Back to Cheat Debugger Commands cheatnextcheatnext <condition>[,<comparisonvalue>] Filter candidates by comparing to the previous search values. If five or fewer candidates remain, they will be shown in the debugger console. May be abbreviated to cn. Possible <condition> arguments:
Examples:
Back to Cheat Debugger Commands cheatnextfcheatnextf <condition>[,<comparisonvalue>] Filter candidates by comparing to the initial search values. If five or fewer candidates remain, they will be shown in the debugger console. May be abbreviated to cn. Possible <condition> arguments:
Examples:
Back to Cheat Debugger Commands cheatlistcheatlist [<filename>] Without <filename>, show the current cheat matches in the debugger console; with <filename>, save the current cheat matches in basic XML format to the specified file. May be abbreviated to cl. Examples:
Back to Cheat Debugger Commands cheatundocheatundo Undo filtering of cheat candidates by the most recent cheatnext or cheatnextf command. Note that the previous values are not rolled back. May be abbreviated to cu. Examples:
Back to Cheat Debugger Commands Media Image Debugger Commands
imagesimages Lists the instance names for media images devices in the system and the currently mounted media images, if any. Brief instance names, as allowed for command line media options, are listed. Mounted software list items are displayed as the list name, software item short name, and part name, separated by colons; other mounted images are displayed as file names. Example:
Back to Media Image Debugger Commands mountmount <instance>,<filename> Mounts a file on a media device. The device may be specified by its instance name or brief instance name, as allowed for command line media options. Some media devices allow software list items to be mounted using this command by supplying the short name of the software list item in place of a filename for the <filename> parameter. Examples:
Back to Media Image Debugger Commands unmountunmount <instance> Unmounts the mounted media image (if any) from a device. The device may be specified by its instance name or brief instance name, as allowed for command line media options. Examples:
Back to Media Image Debugger Commands Specifying devices and address spacesMany debugger commands accept parameters specifying which device to operate on. If a device is not specified explicitly, the CPU currently visible in the debugger is used. Devices can be specified by tag, or by CPU number:
If a tag starts with a caret (^) or dot (.), it is interpreted relative to the CPU currently visible in the debugger, otherwise it is interpreted relative to the root machine device. If a device argument is ambiguously valid as both a tag and a CPU number, it will be interpreted as a tag. Examples:
Commands that operate on memory extend this by allowing the device tag or CPU number to be optionally followed by an address space identifier. Address space identifiers are tag-like strings. You can see them in debugger memory viewer source lists. If the address space identifier is omitted, a default address space will be used. Usually, this is the address space that appears first for the device. Many commands have variants with d, i and o (data, I/O and opcodes) suffixes that default to the address spaces at indices 1, 2 and 3, respectively, as these have special significance for CPU-like devices. In ambiguous cases, the default address space of a child device will be used rather than a specific address space. Examples:
If a command takes an emulated memory address as a parameter, the address may optionally be followed by an address space specification, as described above. Examples:
The examples here include a lot of corner cases, but in general the debugger should take the most likely meaning for a device or address space specification. Debugger expression syntaxExpressions can be used anywhere a numeric or Boolean parameter is expected. The syntax for expressions is similar to a subset of C-style expression syntax, with full operator precedence and parentheses. There are a few operators missing (notably the ternary conditional operator), and a few new ones (memory accessors). The table below lists all the operators, ordered from highest to lowest precedence:
Major differences from C expression semantics:
NumbersLiteral numbers are prefixed according to their bases:
Examples:
Boolean valuesAny expression that evaluates to a number can be used where a Boolean value is required. Zero is treated as false, and all non-zero values are treated as true. Additionally, the string true is treated as true, and the string false is treated as false. An empty string may be supplied as an argument for Boolean parameters to debugger commands to use the default value, even when subsequent parameters are specified. Memory accessesThe memory access prefix operators allow reading from and writing to emulated address spaces. The memory prefix operators specify the access size and whether side effects are disabled, and may optionally be preceded by an address space specification. The supported access sizes and side effect modes are as follows:
Suppressing side effects of a read access yields the value reading from address would, with no further effects. For example reading a mailbox with side effects disabled will not clear the pending flag, and reading a FIFO with side effects disabled will not remove an item. For write accesses, suppressing side effects doesn’t change behaviour in most cases – you want to see the effects of writing to a location. However, there are some exceptions where it is useful to separate multiple effects of a write access. For example:
The size may optionally be preceded by an access type specification:
Finally, this may be preceded by a tag and/or address space name followed by a dot (.). That may seem like a lot to digest, so let’s look at the simplest examples:
Adding access types gives additional possibilities:
If we want to access an address space of a device other than the current CPU, an address space beyond the first four indices, or a memory region, we need to include a tag or name:
Some combinations are not useful. For example physical and logical addresses are equivalent for some CPUs, and direct read/write pointer accesses never have side effects. Accessing a memory region (m access type) requires a tag to be specified. Memory accesses can be used as both lvalues and rvalues, so you can write b@100 = ff to store a byte in memory. FunctionsThe debugger supports a number of useful utility functions in expressions.
LUA SCRIPTING INTERFACE
IntroductionMAME provides Lua script bindings for a useful set of core functionality. This feature first appeared in version 0.148, when a minimal Lua interface was implemented. Today, the Lua interface is rich enough to let you inspect and manipulate device state, access CPU registers, read and write memory, and draw custom graphical overlays. There are three ways to use MAME’s Lua scripting capabilities:
Internally, MAME makes extensive use of Sol3 to implement Lua bindings. The Lua API is not yet declared stable and may suddenly change without prior notice. However, we expose methods to let you know at runtime which API version you are running against, and most objects support some level of runtime introspection. FeaturesThe API is not yet complete, but this is a partial list of capabilities exposed to Lua scripts:
API referenceLua Common Types and Globals
ContainersMany properties yield container wrappers. Container wrappers are cheap to create, and provide an interface that is similar to a read-only table. The complexity of operations may vary. Container wrappers usually provide most of these operations:
Emulator interfaceThe emulator interface emu provides access to core functionality. Many classes are also available as properties of the emulator interface. Methods
Lua Core ClassesMany of MAME’s core classes used to implement an emulation session are available to Lua scripts.
Notifier subscriptionWraps MAME’s util::notifier_subscription class, which manages a subscription to a broadcast notification. Methods
Properties
AttotimeWraps MAME’s attotime class, which represents a high-precision time interval. Attotime values support addition and subtraction with other attotime values, and multiplication and division by integers. Instantiation
Methods
Properties
MAME machine managerWraps MAME’s mame_machine_manager class, which holds the running machine, UI manager, and other global components. Instantiation
Properties
Running machineWraps MAME’s running_machine class, which represents an emulation session. It provides access to the other core objects that implement an emulation session as well as the emulated device tree. Instantiation
Methods
Properties
Video managerWraps MAME’s video_manager class, which is responsible for coordinating emulated video drawing, speed throttling, and reading host inputs. Instantiation
Methods
Properties
Sound managerWraps MAME’s sound_manager class, which manages the emulated sound stream graph and coordinates sound output. Instantiation
Methods
Properties
Output managerWraps MAME’s output_manager class, providing access to system outputs that can be used for interactive artwork or consumed by external programs. Instantiation
Methods
Parameters managerWraps MAME’s parameters_manager class, which provides a simple key-value store for metadata from system ROM definitions. Instantiation
Methods
UI managerWraps MAME’s mame_ui_manager class, which handles menus and other user interface functionality. Instantiation
Methods
Properties
System driver metadataProvides some metadata for an emulated system. Instantiation
Properties
Lua pluginProvides a description of an available Lua plugin. Instantiation
Properties
Lua Device ClassesSeveral device classes and device mix-ins classes are exposed to Lua. Devices can be looked up by tag or enumerated.
Device enumeratorsDevice enumerators are special containers that allow iterating over devices and looking up devices by tag. A device enumerator can be created to find any kind of device, to find devices of a particular type, or to find devices that implement a particular interface. When iterating using pairs or ipairs, devices are returned by walking the device tree depth-first in creation order. The index get operator looks up a device by tag. It returns nil if no device with the specified tag is found, or if the device with the specified tag does not meet the type/interface requirements of the device enumerator. The complexity is O(1) if the result is cached, but an uncached device lookup is expensive. The at method has O(n) complexity. If you create a device enumerator with a starting point other than the root machine device, passing an absolute tag or a tag containing parent references to the index operator may return a device that would not be discovered by iteration. If you create a device enumerator with restricted depth, devices that would not be found due to being too deep in the hierarchy can still be looked up by tag. Creating a device enumerator with depth restricted to zero can be used to downcast a device or test whether a device implements a certain interface. For example this will test whether a device implements the media image interface: image_intf = emu.image_enumerator(device, 0):at(1) if image_intf then Instantiation
DeviceWraps MAME’s device_t class, which is a base of all device classes. Instantiation
Methods
Properties
Palette deviceWraps MAME’s device_palette_interface class, which represents a device that translates pen values to colours. Colours are represented in alpha/red/green/blue (ARGB) format. Channel values range from 0 (transparent or off) to 255 (opaque or full intensity), inclusive. Colour channel values are not pre-multiplied by the alpha value. Channel values are packed into the bytes of 32-bit unsigned integers, in the order alpha, red, green, blue from most-significant to least-significant byte. Instantiation
Methods
Properties
Screen deviceWraps MAME’s screen_device class, which represents an emulated video output. Instantiation
Base classes
Methods
Properties
Cassette image deviceWraps MAME’s cassette_image_device class, representing a compact cassette mechanism typically used by a home computer for program storage. Instantiation
Base classes
Methods
Properties
Image device interfaceWraps MAME’s device_image_interface class which is a mix-in implemented by devices that can load media image files. Instantiation
Methods
Properties
Slot device interfaceWraps MAME’s device_slot_interface class which is a mix-in implemented by devices that instantiate a user-specified child device. Instantiation
Properties
Device state entryWraps MAME’s device_state_entry class, which allows access to named registers exposed by a device. Supports conversion to string for display. Instantiation
Properties
Media image formatWraps MAME’s image_device_format class, which describes a media file format supported by a media image device. Instantiation
Properties
Slot optionWraps MAME’s device_slot_interface::slot_option class, which represents a child device that a slot device can be configured to instantiate. Instantiation
Properties
Lua Memory System ClassesMAME’s Lua interface exposes various memory system objects, including address spaces, memory shares, memory banks, and memory regions. Scripts can read from and write to the emulated memory system.
Memory managerWraps MAME’s memory_manager class, which allows the memory shares, banks and regions in a system to be enumerated. Instantiation
Properties
Address spaceWraps MAME’s address_space class, which represents an address space belonging to a device. Instantiation
Methods
Properties
Pass-through handlerTracks a pass-through handler installed in an address space. A memory pass-through handler receives notifications on accesses to a specified range of addresses, and can modify the data that is read or written if desired. Note that pass-through handler callbacks are not run as coroutines. Instantiation
Methods
Properties
Address mapWraps MAME’s address_map class, used to configure handlers for an address space. Instantiation
Properties
Address map entryWraps MAME’s address_map_entry class, representing an entry in a configured address map. Instantiation
Properties
Address map handler dataWraps MAME’s map_handler_data class, which provides configuration data to handlers in address maps. Instantiation
Properties
Memory shareWraps MAME’s memory_share class, representing a named allocated memory zone. Instantiation
Methods
Properties
Memory bankWraps MAME’s memory_bank class, representing a named memory zone indirection. Instantiation
Properties
Memory regionWraps MAME’s memory_region class, representing a memory region used to store read-only data like ROMs or the result of fixed decryptions. Instantiation
Methods
Properties
Lua Input System ClassesAllows scripts to get input from the user, and access I/O ports in the emulated system.
I/O port managerWraps MAME’s ioport_manager class, which provides access to emulated I/O ports and handles input configuration. Instantiation
Methods
Properties
Natural keyboard managerWraps MAME’s natural_keyboard class, which manages emulated keyboard and keypad inputs. Instantiation
Methods
Properties
Keyboard input deviceRepresents a keyboard or keypad input device managed by the natural keyboard manager. Note that this is not a device class. Instantiation
Properties
I/O portWraps MAME’s ioport_port class, representing an emulated I/O port. Instantiation
Methods
Properties
I/O port fieldWraps MAME’s ioport_field class, representing a field within an I/O port. Instantiation
Methods
Properties
Live I/O port field stateWraps MAME’s ioport_field_live class, representing the live state of an I/O port field. Instantiation
Properties
Input typeWraps MAME’s input_type_entry class, representing an emulated input type or emulator UI input type. Input types are uniquely identified by the combination of their enumerated type value and player index. Instantiation
Properties
Input managerWraps MAME’s input_manager class, which reads host input devices and checks whether configured inputs are active. Instantiation
Methods
Properties
Input code pollerWraps MAME’s input_code_poller class, used to poll for host inputs being activated. Instantiation
Methods
Input sequence pollerWraps MAME’s input_sequence_poller poller class, which allows users to assign host input combinations to emulated inputs and other actions. Instantiation
Methods
Properties
Input sequenceWraps MAME’s input_seq class, representing a combination of host inputs that can be read or assigned to an emulated input. Input sequences can be manipulated using input manager methods. Use an input sequence poller to obtain an input sequence from the user. Instantiation
Methods
Properties
Host input device classWraps MAME’s input_class class, representing a category of host input devices (e.g. keyboards or joysticks). Instantiation
Properties
Host input deviceWraps MAME’s input_device class, representing a host input device. Instantiation
Properties
Host input device itemWraps MAME’s input_device_item class, representing a single host input (e.g. a key, button, or axis). Instantiation
Properties
UI input managerWraps MAME’s ui_input_manager class, which is used for high-level input. Instantiation
Methods
Properties
Lua Render System ClassesThe render system is responsible for drawing what you see in MAME’s windows, including emulated screens, artwork, and UI elements.
Render boundsWraps MAME’s render_bounds class, which represents a rectangle using floating-point coordinates. Instantiation
Methods
Properties
Render colourWraps MAME’s render_color class, which represents an ARGB (alpha, red, green, blue) format colour. Channels are floating-point values ranging from zero (0, transparent alpha or colour off) to one (1, opaque or full colour intensity). Colour channel values are not pre-multiplied by the alpha channel value. Instantiation
Methods
Properties
PaletteWraps MAME’s palette_t class, which represents a table of colours that can be looked up by zero-based index. Palettes always contain additional special entries for black and white. Each colour has an associated contrast adjustment value. Each adjustment group has associated brightness and contrast adjustment values. The palette also has overall brightness, contrast and gamma adjustment values. Colours are represented in alpha/red/green/blue (ARGB) format. Channel values range from 0 (transparent or off) to 255 (opaque or full intensity), inclusive. Colour channel values are not pre-multiplied by the alpha value. Channel values are packed into the bytes of 32-bit unsigned integers, in the order alpha, red, green, blue from most-significant to least-significant byte. Instantiation
Methods
Properties
BitmapWraps implementations of MAME’s bitmap_t and bitmap_specific classes, which represent two-dimensional bitmaps stored in row-major order. Pixel coordinates are zero-based, increasing to the right and down. Several pixel formats are supported. Instantiation
Methods
Properties
Render textureWraps MAME’s render_texture class, representing a texture that cam be drawn in a render container. Render textures must be freed before the emulation session ends. Instantiation
Methods
Properties
Render managerWraps MAME’s render_manager class, responsible for managing render targets and textures. Instantiation
Methods
Properties
Render targetWrap’s MAME’s render_target class, which represents a video output channel. This could be a host window or screen, or a hidden target used for rendering screenshots. Instantiation
Properties
Render containerWraps MAME’s render_container class. Instantiation
Methods
Properties
Container user settingsWraps MAME’s render_container::user_settings class, representing image adjustments applied to a render container. Instantiation
Properties
Layout fileWraps MAME’s layout_file class, representing the views loaded from a layout file for use by a render target. Note that layout file callbacks are not run as coroutines. InstantiationA layout file object is supplied to its layout script in the file variable. Layout file objects are not instantiated directly from Lua scripts. Methods
Properties
Layout viewWraps MAME’s layout_view class, representing a view that can be displayed in a render target. Views are created from XML layout files, which may be loaded from external artwork, internal to MAME, or automatically generated based on the screens in the emulated system. Note that layout view callbacks are not run as coroutines. Instantiation
Methods
Call with nil to remove the callback.
Call with nil to remove the callback.
Call with nil to remove the callback.
Properties
Layout view itemWraps MAME’s layout_view_item class, representing an item in a layout view. An item is drawn as a rectangular textured surface. The texture is supplied by an emulated screen or a layout element. Note that layout view item callbacks are not run as coroutines. Instantiation
Methods
Properties
Layout elementWraps MAME’s layout_element class, representing a visual element that can be drawn in a layout view. Elements are created from XML layout files, which may be loaded from external artwork or internal to MAME. Note that layout element callbacks are not run as coroutines. Instantiation
Methods
Properties
Lua Debugger ClassesSome of MAME’s core debugging features can be controlled from Lua script. The debugger must be enabled to use the debugger features (usually by passing -debug on the command line).
Symbol tableWrap’s MAME’s symbol_table class, providing named symbols that can be used in expressions. Note that symbol tables can be created and used even when the debugger is not enabled. Instantiation
Methods
Properties
Parsed expressionWraps MAME’s parsed_expression class, which represents a tokenised debugger expression. Note that parsed expressions can be created and used even when the debugger is not enabled. Instantiation
Methods
Properties
Symbol entryWraps MAME’s symbol_entry class, which represents an entry in a symbol table. Note that symbol entries must not be used after the symbol table they belong to is destroyed. Instantiation
Properties
Debugger managerWraps MAME’s debugger_manager class, providing the main interface to control the debugger. Instantiation
Methods
Properties
Device debugger interfaceWraps MAME’s device_debug class, providing the debugger interface to an emulated CPU device. Instantiation
Methods
BreakpointWraps MAME’s debug_breakpoint class, representing a breakpoint for an emulated CPU device. Instantiation
Properties
WatchpointWraps MAME’s debug_watchpoint class, representing a watchpoint for an emulated CPU device. Instantiation
Properties
Expression errorWraps MAME’s expression_error class, describing an error occurring while parsing or executing a debugger expression. Raised on errors when using parsed expressions. Can be converted to a string to provide a description of the error. Properties
Interactive Lua console tutorialFirst run an arcade game in MAME at the command prompt with the -console and -window options to enable the Lua console: $ mame -console -window YOUR_SYSTEM At this point, your game is probably running in attract mode. Let’s pause it: [MAME]> emu.pause() [MAME]> Even without textual feedback on the console, you’ll notice the game is now paused. In general, commands are quiet and only print error messages. You can check the version of MAME you are running with: [MAME]> print(emu.app_name() .. " " .. emu.app_version()) mame 0.255 Let’s examine the emulated screens. First, enumerate the screen devices in the system: [MAME]> for tag, screen in pairs(manager.machine.screens) do print(tag) end :screen manager.machine is the running machine object for the current emulation session. We will be using this frequently. screens is a device enumerator that yields all emulated screens in the system. Most arcade games only have one main screen. In our case, the main and only screen has the absolute tag :screen. We can examine it further: [MAME]> -- keep a reference to the main screen in a variable [MAME]> s = manager.machine.screens[':screen'] [MAME]> print(s.width .. 'x' .. s.height) 320x224 Several methods are available for drawing an overlay on the screen using lines, rectangles and text: [MAME]> -- define a function for drawing an overlay and call it [MAME]> function draw_overlay() [MAME]>> s:draw_text(40, 40, 'foo') -- (x0, y0, msg) [MAME]>> s:draw_box(20, 20, 80, 80, 0xff00ffff, 0) -- (x0, y0, x1, y1, line-color, fill-color) [MAME]>> s:draw_line(20, 20, 80, 80, 0xff00ffff) -- (x0, y0, x1, y1, line-color) [MAME]>> end [MAME]> draw_overlay() This will draw some useless lines and text over the screen. However, when the emulated system is resumed, your overlay needs to be refreshed or it will just disappear. In order to do this, you have to register your function to be called on every video update: [MAME]> emu.register_frame_done(draw_overlay, 'frame') All colors are specified in ARGB format (eight bits per channel). The coordinate origin (0,0) normally corresponds to the top-left corner of the screen. As with screens, you can examine all the emulated devices in the running system: [MAME]> for tag, device in pairs(manager.machine.devices) do print(tag) end :audiocpu :maincpu :saveram :screen :palette [...] For some of them, you can also inspect and manipulate memory and state: [MAME]> cpu = manager.machine.devices[':maincpu'] [MAME]> -- enumerate, read and write register state [MAME]> for k, v in pairs(cpu.state) do print(k) end CURPC rPC IR CURFLAGS SSR D0 [...] [MAME]> print(cpu.state["D0"].value) 303 [MAME]> cpu.state['D0'].value = 255 [MAME]> print(cpu.state['D0'].value) 255 [MAME]> -- inspect memory [MAME]> for name, space in pairs(cpu.spaces) do print(name) end program cpu_space [MAME]> mem = cpu.spaces['program'] [MAME]> print(mem:read_i8(0xc000)) 41 Note that many objects support symbol completion if you type part of a method or property name and press the Tab key: [MAME]>print(mem:read_<TAB> read_direct_i8 read_u16 read_range read_direct_u16 read_direct_i64 read_i64 read_i32 read_direct_u64 read_i8 read_u32 read_u8 read_u64 read_direct_u32 read_direct_i16 read_direct_i32 read_direct_u8 read_i16 [MAME]>print(mem:read_direct_i8 MAME EXTERNAL TOOLSThis section describes additional tools that are built alongside and typically distributed with MAME. chdman – CHD (Compressed Hunks of Data) File Managerchdman can be used to create, convert, check the integrity of and extract data from media images in CHD (Compressed Hunks of Data) format. The basic usage is chdman <command> <option>...
Common optionsThe options available depend on the command, but the following options are used by multiple commands:
CommandsinfoDisplay information about a CHD format file. Information includes:
Common options supported:
verifyVerify the integrity of a CHD format file. The input file must be a read-only CHD format file (the integrity of writable CHD files cannot be verified). Note that this command modifies its input file if the --fix/-f option is specified. Common options supported:
Additional options:
createrawCreate a CHD format file from a raw media image. Common options supported:
Additional options:
If the --hunksize or -hs option is not supplied, the default will be:
If the --compression or -c option is not supplied, it defaults to lzma,zlib,huff,flac. createhdCreate a CHD format hard disk image file. Common options supported:
Additional options:
Creates a blank (zero-filled) hard disk image if no input file is supplied. The input start/length (--inputstartbyte/-isb, --inputstarthunk/-ish, --inputbytes/-ib and --inputhunks/-ih options) cannot be used if no input file is supplied. If the --hunksize or -hs option is not supplied, the default will be:
If the --compression or -c option is not supplied, it defaults to lzma,zlib,huff,flac if an input file is supplied, or none if no input file is supplied. createcdCreate a CHD format CD-ROM image file. Common options supported:
If the --hunksize or -hs option is not supplied, the default will be the hunk size of the parent CHD if a parent CHD file for the output is supplied, or eight sectors per hunk (18,816 bytes) otherwise. If the --compression or -c option is not supplied, it defaults to cdlz,cdzl,cdfl. createdvdCreate a CHD format DVD-ROM image file. Common options supported:
If the --hunksize or -hs option is not supplied, the default will be the hunk size of the parent CHD if a parent CHD file for the output is supplied, or two sectors per hunk (4096 bytes) otherwise. If the --compression or -c option is not supplied, it defaults to lzma,zlib,huff,flac. createldCreate a CHD format LaserDisc image file. Common options supported:
Additional options:
If the --compression or -c option is not supplied, it defaults to avhu. extractrawExtract data from a CHD format raw media image. Common options supported:
extracthdExtract data from a CHD format hard disk image. Common options supported:
extractcdExtract data from a CHD format CD-ROM image. Common options supported:
Additional options:
extractdvdExtract data from a CHD format DVD-ROM image. Common options supported:
extractldExtract data from a CHD format DVD-ROM image. Common options supported:
Additional options:
addmetaAdd a metadata item to a CHD format file. Note that this command modifies its input file. Common options supported:
Additional options:
delmetaDelete a metadata item from a CHD format file. Note that this command modifies its input file. Common options supported:
Additional options:
dumpmetaExtract metadata items from a CHD format file to the standard output or to a file. Common options supported:
Additional options:
listtemplatesList available hard disk templates. This command does not accept any options. Compression algorithmsThe following compression algorithms are supported:
Imgtool - A generic image manipulation tool for MAMEImgtool is a tool for the maintenance and manipulation of disk and other types of images that MAME users need to deal with. Functions include retrieving and storing files and CRC checking/validation. Imgtool is part of the MAME project. It shares large portions of code with MAME, and its existence would not be if it were not for MAME. As such, the distribution terms are the same as MAME. Please read the MAME license thoroughly. Some portions of Imgtool are Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved. Using ImgtoolImgtool is a command line program that contains several "subcommands" that actually do all of the work. Most commands are invoked in a manner along the lines of this: imgtool <subcommand> <format>
<image> ...
Further details vary with each subcommand. Also note that not all subcommands are applicable or supported for different image formats. Imgtool Subcommandscreate imgtool create <format> <imagename>
[--(createoption)=value]
Creates an image dir imgtool dir <format> <imagename>
[path]
Lists the contents of an image get imgtool get <format> <imagename>
<filename> [newname] [--filter=filter] [--fork=fork]
Gets a single file from an image put imgtool put <format> <imagename>
<filename>... <destname> [--(fileoption)=value] [--filter=filter]
[--fork=fork]
Puts a single file on an image (wildcards supported) getall imgtool getall <format> <imagename> [path]
[--filter=filter]
Gets all files off an image del imgtool del <format> <imagename>
<filename>...
Deletes a file on an image mkdir imgtool mkdir <format> <imagename>
<dirname>
Creates a subdirectory on an image rmdir imgtool rmdir <format> <imagename>
<dirname>...
Deletes a subdirectory on an image readsector imgtool readsector <format> <imagename>
<track> <head> <sector> <filename>
Read a sector on an image and output it to specified <filename> writesector imgtool writesector <format> <imagename>
<track> <head> <sector> <filename>
Write a sector to an image from specified <filename> identify
imgtool identify <imagename> listformats Lists all image file formats supported by imgtool
listfilters Lists all filters supported by imgtool
listdriveroptions imgtool listdriveroptions <format>
Lists all format-specific options for the 'put' and 'create' commands Imgtool FiltersFilters are a means to process data being written into or read out of an image in a certain way. Filters can be specified on the get, put, and getall commands by specifying --filter=xxxx on the command line. Currently, the following filters are supported: ascii Translates end-of-lines to the appropriate format
cocobas Processes tokenized TRS-80 Color Computer (CoCo) BASIC
programs
dragonbas Processes tokenized Tano/Dragon Data Dragon 32/64 BASIC
programs
macbinary Processes Apple MacBinary-formatted (merged forks)
files
vzsnapshot [todo: VZ Snapshot? Find out what this is...]
vzbas Processes Laser/VZ Tokenized Basic Files
thombas5 Thomson MO5 w/ BASIC 1.0, Tokenized Files (read-only,
auto-decrypt)
thombas7 Thomson TO7 w/ BASIC 1.0, Tokenized Files (read-only,
auto-decrypt)
thombas128 Thomson w/ BASIC 128/512, Tokenized Files (read-only,
auto-decrypt)
thomcrypt Thomson BASIC, Protected file encryption (no
tokenization)
bm13bas Basic Master Level 3 Tokenized Basic Files
Imgtool Format InfoAmiga floppy disk image (OFS/FFS format) - (amiga_floppy)Driver specific options for module 'amiga_floppy': No image specific file options Image specific creation options (usable on the 'create' command):
Apple ][ DOS order disk image (ProDOS format) - (apple2_do_prodos_525)Driver specific options for module 'apple2_do_prodos_525': No image specific file options Image specific creation options (usable on the 'create' command):
Apple ][ Nibble order disk image (ProDOS format) - (apple2_nib_prodos_525)Driver specific options for module 'apple2_nib_prodos_525': No image specific file options Image specific creation options (usable on the 'create' command):
Apple ][ ProDOS order disk image (ProDOS format) - (apple2_po_prodos_525)Driver specific options for module 'apple2_po_prodos_525': No image specific file options Image specific creation options (usable on the 'create' command):
Apple ][gs 2IMG disk image (ProDOS format) - (apple35_2img_prodos_35)Driver specific options for module 'apple35_2img_prodos_35': No image specific file options Image specific creation options (usable on the 'create' command):
Apple DiskCopy disk image (Mac HFS Floppy) - (apple35_dc_mac_hfs)Driver specific options for module 'apple35_dc_mac_hfs': No image specific file options Image specific creation options (usable on the 'create' command):
Apple DiskCopy disk image (Mac MFS Floppy) - (apple35_dc_mac_mfs)Driver specific options for module 'apple35_dc_mac_mfs': No image specific file options Image specific creation options (usable on the 'create' command):
Apple DiskCopy disk image (ProDOS format) - (apple35_dc_prodos_35)Driver specific options for module 'apple35_dc_prodos_35': No image specific file options Image specific creation options (usable on the 'create' command):
Apple raw 3.5" disk image (Mac HFS Floppy) - (apple35_raw_mac_hfs)Driver specific options for module 'apple35_raw_mac_hfs': No image specific file options Image specific creation options (usable on the 'create' command):
Apple raw 3.5" disk image (Mac MFS Floppy) - (apple35_raw_mac_mfs)Driver specific options for module 'apple35_raw_mac_mfs': No image specific file options Image specific creation options (usable on the 'create' command):
Apple raw 3.5" disk image (ProDOS format) - (apple35_raw_prodos_35)Driver specific options for module 'apple35_raw_prodos_35': No image specific file options Image specific creation options (usable on the 'create' command):
CoCo DMK disk image (OS-9 format) - (coco_dmk_os9)Driver specific options for module 'coco_dmk_os9': No image specific file options Image specific creation options (usable on the 'create' command):
CoCo DMK disk image (RS-DOS format) - (coco_dmk_rsdos)Driver specific options for module 'coco_dmk_rsdos': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
CoCo JVC disk image (OS-9 format) - (coco_jvc_os9)Driver specific options for module 'coco_jvc_os9': No image specific file options Image specific creation options (usable on the 'create' command):
CoCo JVC disk image (RS-DOS format) - (coco_jvc_rsdos)Driver specific options for module 'coco_jvc_rsdos': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
CoCo OS-9 disk image (OS-9 format) - (coco_os9_os9)Driver specific options for module 'coco_os9_os9': No image specific file options Image specific creation options (usable on the 'create' command):
CoCo VDK disk image (OS-9 format) - (coco_vdk_os9)Driver specific options for module 'coco_vdk_os9': No image specific file options Image specific creation options (usable on the 'create' command):
CoCo VDK disk image (RS-DOS format) - (coco_vdk_rsdos)Driver specific options for module 'coco_vdk_rsdos': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
Concept floppy disk image - (concept)Driver specific options for module 'concept': No image specific file options No image specific creation options CopyQM floppy disk image (Basic Master Level 3 format) - (cqm_bml3)Driver specific options for module 'cqm_bml3': Image specific file options (usable on the 'put' command):
No image specific creation options CopyQM floppy disk image (FAT format) - (cqm_fat)Driver specific options for module 'cqm_fat': No image specific file options No image specific creation options CopyQM floppy disk image (Mac HFS Floppy) - (cqm_mac_hfs)Driver specific options for module 'cqm_mac_hfs': No image specific file options No image specific creation options CopyQM floppy disk image (Mac MFS Floppy) - (cqm_mac_mfs)Driver specific options for module 'cqm_mac_mfs': No image specific file options No image specific creation options CopyQM floppy disk image (OS-9 format) - (cqm_os9)Driver specific options for module 'cqm_os9': No image specific file options No image specific creation options CopyQM floppy disk image (ProDOS format) - (cqm_prodos_35)Driver specific options for module 'cqm_prodos_35': No image specific file options No image specific creation options CopyQM floppy disk image (ProDOS format) - (cqm_prodos_525)Driver specific options for module 'cqm_prodos_525': No image specific file options No image specific creation options CopyQM floppy disk image (RS-DOS format) - (cqm_rsdos)Driver specific options for module 'cqm_rsdos': Image specific file options (usable on the 'put' command):
No image specific creation options CopyQM floppy disk image (VZ-DOS format) - (cqm_vzdos)Driver specific options for module 'cqm_vzdos': Image specific file options (usable on the 'put' command):
No image specific creation options Cybiko Classic File System - (cybiko)Driver specific options for module 'cybiko': No image specific file options Image specific creation options (usable on the 'create' command):
Cybiko Xtreme File System - (cybikoxt)Driver specific options for module 'cybikoxt': No image specific file options No image specific creation options D88 Floppy Disk image (Basic Master Level 3 format) - (d88_bml3)Driver specific options for module 'd88_bml3': Image specific file options (usable on the 'put' command):
No image specific creation options D88 Floppy Disk image (FAT format) - (d88_fat)Driver specific options for module 'd88_fat': No image specific file options No image specific creation options D88 Floppy Disk image (Mac HFS Floppy) - (d88_mac_hfs)Driver specific options for module 'd88_mac_hfs': No image specific file options No image specific creation options D88 Floppy Disk image (Mac MFS Floppy) - (d88_mac_mfs)Driver specific options for module 'd88_mac_mfs': No image specific file options No image specific creation options D88 Floppy Disk image (OS-9 format) - (d88_os9)Driver specific options for module 'd88_os9': No image specific file options No image specific creation options D88 Floppy Disk image (OS-9 format) - (d88_os9)Driver specific options for module 'd88_prodos_35': No image specific file options No image specific creation options D88 Floppy Disk image (ProDOS format) - (d88_prodos_525)Driver specific options for module 'd88_prodos_525': No image specific file options No image specific creation options D88 Floppy Disk image (RS-DOS format) - (d88_rsdos)Driver specific options for module 'd88_rsdos': Image specific file options (usable on the 'put' command):
No image specific creation options D88 Floppy Disk image (VZ-DOS format) - (d88_vzdos)Driver specific options for module 'd88_vzdos': Image specific file options (usable on the 'put' command):
No image specific creation options DSK floppy disk image (Basic Master Level 3 format) - (dsk_bml3)Driver specific options for module 'dsk_bml3': Image specific file options (usable on the 'put' command):
No image specific creation options DSK floppy disk image (FAT format) - (dsk_fat)Driver specific options for module 'dsk_fat': No image specific file options No image specific creation options DSK floppy disk image (Mac HFS Floppy) - (dsk_mac_hfs)Driver specific options for module 'dsk_mac_hfs': No image specific file options No image specific creation options DSK floppy disk image (Mac MFS Floppy) - (dsk_mac_mfs)Driver specific options for module 'dsk_mac_mfs': No image specific file options No image specific creation options DSK floppy disk image (OS-9 format) - (dsk_os9)Driver specific options for module 'dsk_os9': No image specific file options No image specific creation options DSK floppy disk image (ProDOS format) - (dsk_prodos_35)Driver specific options for module 'dsk_prodos_35': No image specific file options No image specific creation options DSK floppy disk image (ProDOS format) - (dsk_prodos_525)Driver specific options for module 'dsk_prodos_525': No image specific file options No image specific creation options DSK floppy disk image (RS-DOS format) - (dsk_rsdos)Driver specific options for module 'dsk_rsdos': Image specific file options (usable on the 'put' command):
No image specific creation options DSK floppy disk image (VZ-DOS format) - (dsk_vzdos)Driver specific options for module 'dsk_vzdos': Image specific file options (usable on the 'put' command):
No image specific creation options Formatted Disk Image (Basic Master Level 3 format) - (fdi_bml3)Driver specific options for module 'fdi_bml3': Image specific file options (usable on the 'put' command):
No image specific creation options Formatted Disk Image (FAT format) - (fdi_fat)Driver specific options for module 'fdi_fat': No image specific file options No image specific creation options Formatted Disk Image (Mac HFS Floppy) - (fdi_mac_hfs)Driver specific options for module 'fdi_mac_hfs': No image specific file options No image specific creation options Formatted Disk Image (Mac MFS Floppy) - (fdi_mac_mfs)Driver specific options for module 'fdi_mac_mfs': No image specific file options No image specific creation options Formatted Disk Image (OS-9 format) - (fdi_os9)Driver specific options for module 'fdi_os9': No image specific file options No image specific creation options Formatted Disk Image (ProDOS format) - (fdi_prodos_35)Driver specific options for module 'fdi_prodos_35': No image specific file options No image specific creation options Formatted Disk Image (ProDOS format) - (fdi_prodos_525)Driver specific options for module 'fdi_prodos_525': No image specific file options No image specific creation options Formatted Disk Image (RS-DOS format) - (fdi_rsdos)Driver specific options for module 'fdi_rsdos': Image specific file options (usable on the 'put' command):
No image specific creation options Formatted Disk Image (VZ-DOS format) - (fdi_vzdos)Driver specific options for module 'fdi_vzdos': Image specific file options (usable on the 'put' command):
No image specific creation options HP48 SX/GX memory card - (hp48)Driver specific options for module 'hp48': No image specific file options Image specific creation options (usable on the 'create' command):
IMD floppy disk image (Basic Master Level 3 format) - (imd_bml3)Driver specific options for module 'imd_bml3': Image specific file options (usable on the 'put' command):
No image specific creation options IMD floppy disk image (FAT format) - (imd_fat)Driver specific options for module 'imd_fat': No image specific file options No image specific creation options IMD floppy disk image (Mac HFS Floppy) - (imd_mac_hfs)Driver specific options for module 'imd_mac_hfs': No image specific file options No image specific creation options IMD floppy disk image (Mac MFS Floppy) - (imd_mac_mfs)Driver specific options for module 'imd_mac_mfs': No image specific file options No image specific creation options IMD floppy disk image (OS-9 format) - (imd_os9)Driver specific options for module 'imd_os9': No image specific file options No image specific creation options IMD floppy disk image (ProDOS format) - (imd_prodos_35)Driver specific options for module 'imd_prodos_35': No image specific file options No image specific creation options IMD floppy disk image (ProDOS format) - (imd_prodos_525)Driver specific options for module 'imd_prodos_525': No image specific file options No image specific creation options IMD floppy disk image (RS-DOS format) - (imd_rsdos)Driver specific options for module 'imd_rsdos': Image specific file options (usable on the 'put' command):
No image specific creation options IMD floppy disk image (VZ-DOS format) - (imd_vzdos)Driver specific options for module 'imd_vzdos': Image specific file options (usable on the 'put' command):
No image specific creation options MESS hard disk image - (mess_hd)Driver specific options for module 'mess_hd': No image specific file options Image specific creation options (usable on the 'create' command):
TI99 Diskette (PC99 FM format) - (pc99fm)Driver specific options for module 'pc99fm': No image specific file options No image specific creation options TI99 Diskette (PC99 MFM format) - (pc99mfm)Driver specific options for module 'pc99mfm': No image specific file options No image specific creation options PC CHD disk image - (pc_chd)Driver specific options for module 'pc_chd': No image specific file options Image specific creation options (usable on the 'create' command):
PC floppy disk image (FAT format) - (pc_dsk_fat)Driver specific options for module 'pc_dsk_fat': No image specific file options Image specific creation options (usable on the 'create' command):
Psion Organiser II Datapack - (psionpack)Driver specific options for module 'psionpack': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
Teledisk floppy disk image (Basic Master Level 3 format) - (td0_bml3)Driver specific options for module 'td0_bml3': Image specific file options (usable on the 'put' command):
No image specific creation options Teledisk floppy disk image (FAT format) - (td0_fat)Driver specific options for module 'td0_fat': No image specific file options No image specific creation options Teledisk floppy disk image (Mac HFS Floppy) - (td0_mac_hfs)Driver specific options for module 'td0_mac_hfs': No image specific file options No image specific creation options Teledisk floppy disk image (Mac MFS Floppy) - (td0_mac_mfs)Driver specific options for module 'td0_mac_mfs': No image specific file options No image specific creation options Teledisk floppy disk image (OS-9 format) - (td0_os9)Driver specific options for module 'td0_os9': No image specific file options No image specific creation options Teledisk floppy disk image (ProDOS format) - (td0_prodos_35)Driver specific options for module 'td0_prodos_35': No image specific file options No image specific creation options Teledisk floppy disk image (ProDOS format) - (td0_prodos_525)Driver specific options for module 'td0_prodos_525': No image specific file options No image specific creation options Teledisk floppy disk image (RS-DOS format) - (td0_rsdos)Driver specific options for module 'td0_rsdos': Image specific file options (usable on the 'put' command):
No image specific creation options Teledisk floppy disk image (VZ-DOS format) - (td0_vzdos)Driver specific options for module 'td0_vzdos': Image specific file options (usable on the 'put' command):
No image specific creation options Thomson .fd disk image, BASIC format - (thom_fd)Driver specific options for module 'thom_fd': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
Thomson .qd disk image, BASIC format - (thom_qd)Driver specific options for module 'thom_qd': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
Thomson .sap disk image, BASIC format - (thom_sap)Driver specific options for module 'thom_sap': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
TI990 Hard Disk - (ti990hd)Driver specific options for module 'ti990hd': No image specific file options Image specific creation options (usable on the 'create' command):
TI99 Diskette (old MESS format) - (ti99_old)Driver specific options for module 'ti99_old': No image specific file options Image specific creation options (usable on the 'create' command):
TI99 Harddisk - (ti99hd)Driver specific options for module 'ti99hd': No image specific file options No image specific creation options TI99 Diskette (V9T9 format) - (v9t9)Driver specific options for module 'v9t9': No image specific file options Image specific creation options (usable on the 'create' command):
Laser/VZ disk image (VZ-DOS format) - (vtech1_vzdos)Driver specific options for module 'vtech1_vzdos': Image specific file options (usable on the 'put' command):
Image specific creation options (usable on the 'create' command):
[todo: fill out the command structures, describe commands better. These descriptions came from the imgtool.txt file and are barebones] Castool - A generic cassette image manipulation tool for MAMECastool is a tool for the maintenance and manipulation of cassette images that MAME users need to deal with. MAME directly supports .WAV audio formatted images, but many of the existing images out there may come in forms such as .TAP for Commodore 64 tapes, .CAS for Tandy Color Computer tapes, and so forth. Castool will convert these other formats to .WAV for use in MAME. Castool is part of the MAME project. It shares large portions of code with MAME, and its existence would not be if it were not for MAME. As such, the distribution terms are the same as MAME. Please read the MAME license thoroughly. Using CastoolCastool is a command line program that contains a simple set of instructions. Commands are invoked in a manner along the lines of this: castool convert <format> <inputfile>
<outputfile>
Castool FormatsThese are the formats supported by Castool for conversion to .WAV files. A26 Atari 2600 SuperCharger image
File extension: a26 APF APF Imagination Machine
File extensions: cas, cpf, apt ATOM Acorn Atom
File extensions: tap, csw, uef BBC Acorn BBC & Electron
File extensions: csw, uef CBM Commodore 8-bit series
File extensions: tap CDT Amstrad CPC
File extensions: cdt CGENIE EACA Colour Genie
File extensions: cas COCO Tandy Radio Shack Color Computer
File extensions: cas CSW Compressed Square Wave
File extensions: csw DDP Coleco ADAM
File extensions: ddp FM7 Fujitsu FM-7
File extensions: t77 FMSX MSX
File extensions: tap, cas GTP Elektronika inzenjering Galaksija
File extensions: gtp HECTOR Micronique Hector & Interact Family Computer
File extensions: k7, cin, for JUPITER Jupiter Cantab Jupiter Ace
File extensions: tap KC85 VEB Mikroelektronik KC 85
File extensions: kcc, kcb, tap, 853, 854, 855, tp2, kcm, sss KIM1 MOS KIM-1
File extensions: kim, kim1 LVIV PK-01 Lviv
File extensions: lvt, lvr, lv0, lv1, lv2, lv3 MO5 Thomson MO-series
File extensions: k5, k7 MZ Sharp MZ-700
File extensions: m12, mzf, mzt ORAO PEL Varazdin Orao
File extensions: tap ORIC Tangerine Oric
File extensions: tap PC6001 NEC PC-6001
File extensions: cas PHC25 Sanyo PHC-25
File extensions: phc PMD85 Tesla PMD-85
File extensions: pmd, tap, ptp PRIMO Microkey Primo
File extensions: ptp RKU UT-88
File extensions: rku RK8 Mikro-80
File extensions: rk8 RKS Specialist
File extensions: rks RKO Orion
File extensions: rko RKR Radio-86RK
File extensions: rk, rkr, gam, g16, pki RKA Zavod BRA Apogee BK-01
File extensions: rka RKM Mikrosha
File extensions: rkm RKP SAM SKB VM Partner-01.01
File extensions: rkp SC3000 Sega SC-3000
File extensions: bit SOL20 PTC SOL-20
File extensions: svt SORCERER Exidy Sorcerer
File extensions: tape SORDM5 Sord M5
File extensions: cas SPC1000 Samsung SPC-1000
File extensions: tap, cas SVI Spectravideo SVI-318 & SVI-328
File extensions: cas TO7 Thomson TO-series
File extensions: k7 TRS8012 TRS-80 Level 2
File extensions: cas TVC64 Videoton TVC 64
File extensions: cas TZX Sinclair ZX Spectrum
File extensions: tzx, tap, blk VG5K Philips VG 5000
File extensions: k7 VTECH1 Video Technology Laser 110-310
File extensions: cas VTECH2 Video Technology Laser 350-700
File extensions: cas X07 Canon X-07
File extensions: k7, lst, cas X1 Sharp X1
File extensions: tap ZX80_O Sinclair ZX80
File extensions: o, 80 ZX81_P Sinclair ZX81
File extensions: p, 81 Floptool - A generic floppy image manipulation tool for MAMEFloptool is a tool for the maintenance and manipulation of floppy images that MAME users need to deal with. MAME directly supports .WAV audio formatted images, but many of the existing images out there may come in forms such as .TAP for Commodore 64 tapes, .CAS for Tandy Color Computer tapes, and so forth. Castool will convert these other formats to .WAV for use in MAME. Floptool is part of the MAME project. It shares large portions of code with MAME, and its existence would not be if it were not for MAME. As such, the distribution terms are the same as MAME. Please read the MAME license thoroughly. Using FloptoolFloptool is a command line program that contains a simple set of instructions. Commands are invoked in a manner along the lines of this: floptool identify <inputfile> [<inputfile>
...] floptool convert [input_format|auto] output_format
<inputfile> <outputile>
Floptool FormatsThese are the formats supported by Floptool for conversion to other formats. MFI MAME floppy image
File extension: mfi DFI DiscFerret flux dump format
File extensions: dfi IPF SPS floppy disk image
File extensions: ipf MFM HxC Floppy Emulator floppy disk image
File extensions: mfm ADF Amiga ADF floppy disk image
File extensions: adf ST Atari ST floppy disk image
File extensions: st MSA Atari MSA floppy disk image
File extensions: msa PASTI Atari PASTI floppy disk image
File extensions: stx DSK CPC DSK format
File extensions: dsk D88 D88 disk image
File extensions: d77, d88, 1dd IMD IMD disk image
File extensions: imd TD0 Teledisk disk image
File extensions: td0 CQM CopyQM disk image
File extensions: cqm, cqi, dsk PC PC floppy disk image
File extensions: dsk, ima, img, ufi, 360 NASLITE NASLite disk image
File extensions: img DC42 DiskCopy 4.2 image
File extensions: dc42 A2_16SECT Apple II 16-sector disk image
File extensions: dsk, do, po A2_RWTS18 Apple II RWTS18-type image
File extensions: rti A2_EDD Apple II EDD image
File extensions: edd ATOM Acorn Atom disk image
File extensions: 40t, dsk SSD Acorn SSD disk image
File extensions: ssd, bbc, img DSD Acorn DSD disk image
File extensions: dsd DOS Acorn DOS disk image
File extensions: img ADFS_O Acorn ADFS (OldMap) disk image
File extensions: adf, ads, adm, adl ADFS_N Acorn ADFS (NewMap) disk image
File extensions: adf ORIC_DSK Oric disk image
File extensions: dsk APPLIX Applix disk image
File extensions: raw HPI HP9845A floppy disk image
File extensions: hpi Other tools included with MAMEledutil.exe/ledutil.shOn Microsoft Windows, ledutil.exe can take control of your keyboard LEDs to mirror those that were present on some early arcade games (e.g. Asteroids) Start ledutil.exe from the command line to enable LED handling. Run ledutil.exe -kill to stop the handler. On SDLMAME platforms such as Mac OS X and Linux, ledutil.sh can be used. Use ledutil.sh -a to have it automatically close when you exit SDLMAME. Developer-focused tools included with MAMEpngcmpThis tool is used in regression testing to compare PNG screenshot results with the runtest.cmd script found in the source archive. This script works only on Microsoft Windows. nltoolDiscrete component conversion tool. nlwavDiscrete component conversion and testing tool. jedutilPAL/PLA/PLD/GAL dump handling tool. It can convert between the industry-standard JED format and MAME's proprietary packed binary format and it can show logic equations for the types of devices it knows the internal logic of. ldresampleThis tool recompresses video data for laserdisc and VHS dumps. ldverifyThis tool is used for comparing laserdisc or VHS CHD images with the source AVI. romcmpThis tool is used to perform basic data comparisons and integrity checks on binary dumps. With the -h switch, it can also be used to calculate hash functions. unidasmUniversal disassembler for many of the architectures supported in MAME. CONTRIBUTING TO MAMESo you want to contribute to MAME but aren’t sure where to start? Well the great news is that there’s always plenty to do for people with a variety of skill sets. Testing and reporting bugsOne thing MAME can always do with is more testing and bug reports. If you’re familiar with a system that MAME emulates and notice something wrong, or if you find a bug in MAME’s user interface, you can head over to MAME Testers and, assuming it isn’t already reported, register an account and open an issue. Be sure to read the FAQ and rules first to ensure you start out on the right foot. Please note that MAME Testers only accepts user-facing bugs in tagged release versions. For other kinds of issues, we have GitHub Issues. There’s a bit more leeway here. For example we accept developer-facing issues (e.g. bugs in internal APIs, or build system inadequacies), feature requests, and major regressions before they make it into a released version. Please respect the fact that the issue tracker is not a discussion or support forum, it’s only for reporting reproducible issues. Don’t open issues to ask questions or request support. Also, keep in mind that the master branch is unstable. If the current revision doesn’t compile at all or is completely broken, we’re probably already aware of it and don’t need issues opened for that. Wait a while and see if there’s an update. You might want to comment on the commit in question with the compiler error message, particularly if you’re compiling in an unorthodox but supported configuration. When opening an issue, remember to provide as much information as possible to help others understand, reproduce, and diagnose the issue. Things that are helpful to include:
Contributing to MAME’s source codeMAME itself is written in C++, but that isn’t the sum total of the source code. The source code also includes:
Our primary source code repository is hosted on GitHub. We prefer to receive source code contributions in the form of pull requests. You’ll need to learn the basics of git distributed version control and familiarise yourself with the git tools. The basic process for creating a pull request is as follows:
Please keep the following in mind (note that not all points are relevant to all kinds of changes):
We have guidelines for specific parts of the source: C++ Coding Guidelines
IntroductionIn terms of coding conventions, the style present within an existing source file should be favoured over the standards found below. When a new source file is being created, the following coding conventions should be observed if creating a new file within the MAME core (src/emu and src/lib). If the source file is outside the core, deference can be given to a contributor’s preferred style, although it is strongly encouraged to code with the understanding that the file may need to be comprehensible by more than one person as time marches forward. Definitions
Source file formatMAME C++ source files are encoded as UTF-8 text, assuming fixed-width characters, with tab stops at four-space intervals. Source files should end with a terminating end-of-line. Any valid printable Unicode text is permitted in comments. Outside comments and strings, only the printable ASCII subset of Unicode is permitted. The srcclean tool is used to enforce file format rules before each release. You can build this tool and apply it to the files you modify before opening a pull request to avoid conflicts or surprising changes later. Naming conventions
Identifiers containing two consecutive underscores or starting with an underscore followed by an uppercase letter are always reserved and should not be used. Type names and other identifiers with a leading underscore should be avoided within the global namespace, as they are explicitly reserved according to the C++ standard. Additionally, identifiers suffixed with _t should be avoided within the global namespace, as they are also reserved according to POSIX standards. While MAME violates this policy occasionally – most notably with device_t – it’s considered to be an unfortunate legacy decision that should be avoided in any new code. Variables and literalsOctal literals are discouraged from use outside of specific cases. They lack the obvious letter-based prefixes found in hexadecimal and binary literals, and therefore can be difficult to distinguish at a glance from a decimal literal to coders who are unfamiliar with octal notation. Lower-case hexadecimal literals are preferred, e.g. 0xbadc0de rather than 0xBADC0DE. For clarity, try not to exceed the bit width of the variable which will be used to store it. Binary literals have rarely been used in the MAME source code due to the 0b prefix not being standardised until C++14, but there is no policy to avoid their use. Integer suffix notation should be used when specifying 64-bit literals, but is not strictly required in other cases. It can, however, clarify the intended use of a given literal at a glance. Uppercase long integer literal suffixes should be used to avoid confusion with the digit 1, e.g. 7LL rather than 7ll. Digit grouping should be used for longer numeric literals, as it aids in recognising order of magnitude or bit field positions at a glance. Decimal literals should use groups of three digits, and hexadecimal literals should use groups of four digits, outside of specific situations where different grouping would be easier to understand, e.g. 4'433'619 or 0xfff8'1fff. Types that do not have a specifically defined size should be avoided if they are to be registered with MAME’s save-state system, as it harms portability. In general, this means avoiding the use of int for these members. It's encouraged, but not required, for class data members to be prefixed with m_ for non-static instance members and s_ for static members. This does not apply to nested classes or structs. Bracing and indentationTabs are used for initial indentation of lines, with one tab used per nested scope level. Statements split across multiple lines should be indented by two tabs. Spaces are used for alignment at other places within a line. Either K&R or Allman-style bracing is preferred. There is no specific preference for bracing on single-line statements, although bracing should be consistent for a given if/else block, as shown: if (x == 0) { When using a series of if/else or if/else if/else blocks with comments at the top indentation level, avoid extraneous newlines. The use of additional newlines may lead to else if or else blocks being missed due to the newlines pushing the blocks outside the visible editor height: // Early-out if our hypothetical counter has run out. if (x == 0) { Indentation for case statements inside a switch body can either be on the same level as the switch statement or inward by one level. There is no specific style which is used across all core files, although indenting by one level appears to be used most often. SpacingConsistent single-spacing between binary operators, variables, and literals is strongly preferred. The following examples exhibit reasonably consistent spacing: uint8_t foo = (((bar + baz) + 3) & 7) << 1; uint8_t foo = ((bar << 1) + baz) & 0x0e; uint8_t foo = bar ? baz : 5; The following examples exhibit extremes in either direction, although having extra spaces is less difficult to read than having too few: uint8_t foo = ( ( ( bar + baz ) + 3 ) & 7 ) << 1; uint8_t foo = ((bar<<1)+baz)&0x0e; uint8_t foo = (bar?baz:5); A space should be used between a fundamental C++ statement and its opening parenthesis, e.g.: switch (value) ... if (a != b) ... for (int i = 0; i < foo; i++) ... ScopingVariables should be scoped as narrowly as is reasonably possible. There are many instances of C89-style local variable declaration in the MAME codebase, but this is largely a hold-over from MAME’s early days, which pre-date the C99 specification. The following two snippets exhibit the legacy style of local variable declaration, followed by the more modern and preferred style: void example_device::some_function() { void example_device::some_function() { Enumerated values, structs, and classes used only by one specific device should be declared within the device's class itself. This avoids pollution of the global namespace and makes the device-specific use of them more obvious at a glance. Const CorrectnessConst-correctness has not historically been a strict requirement of code that goes into MAME, but there’s increasing value in it as the amount of code refactoring increases and technical debt decreases. When writing new code, it’s worth taking the time to determine if a local variable can be declared const. Similarly, it's encouraged to consider which member functions of a new class can be const qualified. In a similar vein, arrays of constants should be declared constexpr and should use screaming snake case, as outlined towards the top of this document. Lastly, arrays of C-style strings should be declared as both a const array of const strings, as so: static const char *const EXAMPLE_NAMES[4] = { CommentsWhile /* ANSI C comments */ are often found in the codebase, there has been a gradual shift towards // C++-style comments for single-line comments. This is very much a guideline, and coders are encouraged to use whichever style is most comfortable. Unless specifically quoting content from a machine or ancillary materials, comments should be in English so as to match the predominant language that the MAME team shares worldwide. Commented-out code should typically be removed prior to authoring a pull request, as it has a tendency to rot due to the fast-moving nature of MAME’s core API. If there is a desire known beforehand for the code to eventually be included, it should be bookended in if (0) or if (false), as code removed through a preprocessor macro will rot at the same rate. MAME-Specific HelpersWhen at all possible, use helper functions and macros for bit manipulation operations. The BIT(value, bit) helper can be used to extract the state of a bit at a given position from an integer value. The resulting value will be aligned to the least significant bit position, i.e. will be either 0 or 1. An overload of the same function, BIT(value, bit, width) can be used to extract a bit field of a specified width from an integer value, starting at the specified bit position. The result will also be right-justified and will be of the same type as the incoming value. There are, additionally, a number of helpers for functionality such as counting leading zeroes/ones, population count, and signed/unsigned integer multiplication and division for both 32-bit and 64-bit results. Not all of these helpers have wide use in the MAME codebase, but using them in new code is strongly preferred when that code is performance- critical, as they utilise inline assembly or compiler intrinsics per- platform when available.
For documentation on helpers related to multiplication and division, refer to src/osd/eminline.h. LoggingMAME has multiple logging function for different purposes. Two of the most frequently used logging functions are logerror and osd_printf_verbose:
The osd_printf_verbose function should be used for logging that is useful for diagnosing user issues, while logerror should be used for messages more relevant to developers (either developing MAME itself, or developing software for emulated systems using MAME’s debugger). For debug logging, a channel-based logging system exists via the header logmacro.h. It can be used as a generic logging system as follows, without needing to make use of its ability to mask out specific channels: // All other headers in the .cpp file should be above this line. #define VERBOSE (1) #include "logmacro.h" ... void some_device::some_reg_write(u8 data) { The above example also makes use of a helper function which is available in all derivatives of device_t: machine().describe_context(). This function will return a string that describes the emulation context in which the function is being run. This includes the fully-qualified tag of the currently executing device (if any). If the relevant device implements device_state_interface, it will also include the current program-counter value reported by the device. For more fine-grained control, specific bit masks can be defined and used via the LOGMASKED macro: // All other headers in the .cpp file should be above this line. #define LOG_FOO (1 << 1U) #define LOG_BAR (1 << 2U) #define VERBOSE (LOG_FOO | LOG_BAR) #include "logmacro.h" ... void some_device::some_reg_write(u8 data) { Note that the least significant bit position for user-supplied masks is 1, as bit position 0 is reserved for LOG_GENERAL. By default, LOG and LOGMASKED will use the device-supplied logerror function. However, this can be redirected as desired. The most common use case would be to direct output to the standard output instead, which can be accomplished by explicitly defining LOG_OUTPUT_FUNC as so: #define LOG_OUTPUT_FUNC osd_printf_info A developer should always ensure that VERBOSE is set to 0 and that any definition of LOG_OUTPUT_FUNC is commented out prior to opening a pull request. Structural organizationAll C++ source files must begin with a two comments listing the distribution license and copyright holders in a standard format. Licenses are specified by their SPDX short identifier if available. Here is an example of the standard format: // license:BSD-3-Clause // copyright-holders:David Haywood, Tomasz Slanina Header includes should generally be grouped from most-dependent to least-dependent, and sorted alphabetically within said groups:
Finally, task-specific headers such as logmacro.h - described in the previous section - should be included last. A practical example follows: #include "emu.h" #include "cpu/m68000/m68000.h" #include "machine/mc68328.h" #include "machine/ram.h" #include "sound/dac.h" #include "video/mc68328lcd.h" #include "video/sed1375.h" #include "emupal.h" #include "screen.h" #include "speaker.h" #include "pilot1k.lh" #define VERBOSE (0) #include "logmacro.h" In most cases, the class declaration for a system driver should be within the corresponding source file along with the implementation. In such cases, the class declaration and all contents of the source file, excluding the GAME, COMP, or CONS macro, should be enclosed in an anonymous namespace (this produces better compiler diagnostics, allows more aggressive optimisation, reduces the chance of duplicate symbols, and reduces linking time). Within a class declaration, there should be one section for each member access level (public, protected and private) if practical. This may not be possible in cases where private constants and/or types need to be declared before public members. Members should use the least public access level necessary. Overridden virtual member functions should generally use the same access level as the corresponding member function in the base class. Class member declarations should be grouped to aid understanding:
For classes with multiple overloaded constructors, constructor delegation should be used where possible to avoid repeated member initialiser lists. Constants which are used by a device or machine driver should be in the form of explicitly-sized enumerated values within the class declaration, or be relegated to #define macros within the source file. This helps avoid polluting the preprocessor. Guidelines for Software Lists
IntroductionMAME’s software lists describe known software media for emulated systems in a form that can be used to identify media image files for known software, verify media image file integrity, and load media image files for emulation. Software lists are implemented as XML files in the hash folder. The XML structure is described in the file hash/softwarelist.dtd. Philosophically, software list items should represent the original media, rather than a specific dump of the media. Ideally, it should be possible for anyone with the media to dump it and produce the same image file. Of course, this isn’t always possible in practice – in particular it’s problematic for inherently analog media, like home computer software stored on audio tape cassettes. MAME strives to document the best available media images. It is not our intention to propagate corrupted, truncated, defaced, watermarked, or otherwise bad media images. Where possible, file structures matching the original media structure are preferred. For example we prefer individual files for separate ROM chips in cartridge media, and we use disk images rather than archives of files extracted from the original disks. Items and partsA software list is a collection of items and each item may have multiple parts. An item represents a piece of software, as distributed as a complete package. A part represents a single piece of media within the package. Parts can be mounted individually in emulated media devices. For example a piece of software distributed on three floppy disks will be a single item, while each floppy disk will be one part within that item. Sometimes, logically separate parts of a single physical piece of media are represented as separate parts within a software item. For example each side of an audio tape cassette is represented as a separate part. However individual ROM chips within a cartridge may be separate files, but they are not separate parts, as the cartridge is mounted as a whole. Each item is a software element. The software element may have the following attributes:
Each part is a part element within the software element. The part element must have the following attributes:
MetadataSoftware lists support various kinds of metadata. All software list items require the following metadata elements to be present:
Most user-visible software item metadata is provided using info elements. Each info element must have a name attribute and a value attribute. The name attribute identifies the type of metadata, and the value attribute is the metadata value itself. Note that name attributes do not need to be unique within an item. Multiple info elements with the same name may be present if appropriate. This is frequently seen for software sold using different titles in different regions. MAME displays metadata from info elements in the software selection menu. The following name attributes are recognised specifically, and can show localised names:
TECHNICAL SPECIFICATIONSThis section covers technical specifications useful to programmers working on MAME’s source or working on scripts that run within the MAME framework. MAME Naming Conventions
IntroductionTo promote consistency and readability in MAME source code, we have some naming conventions for various elements. TransliterationFor better or worse, the most broadly recognised script in the world is English Latin. Conveniently, it’s also included in almost all character encodings. To make MAME more globally accessible, we require Latin transliterations of titles and other metadata from other scripts. Do not use translations in metadata – translations are inherently subjective and error-prone. Translations may be included in comments if they may be helpful. If general, if an official Latin script name is known, it should be used in favour of a naïve transliteration. For titles containing foreign loanwords, the conventional Latin spelling should be used for the loanwords (the most obvious example of this is the use of “Mahjong” in Japanese titles rather than “Maajan”).
Titles and descriptionsTry to reproduce the original title faithfully where possible. Try to preserve the case convention used by the manufacturer/publisher. If no official English Latin title is known, use a standard transliteration. For software list entries where a transliteration is used for the description element, put the title in an info element with a name="alt_title" attribute. For software items that have multiple titles (for example different regional titles with the same installation media), use the most widespread English Latin title for the description element, and put the other titles in info elements with name="alt_title" attributes. If disambiguation is needed, try to be descriptive as possible. For example, use the manufacturer’s version number, regional licensee’s name, or terse description of hardware differences in preference to arbitrary set numbers. Surround the disambiguation text with parentheses, preserve original case for names and version text, but use lowercase for anything else besides proper nouns and initialisms. C++ naming conventionsFor C++ naming conventions, see the relevant section in the C++ Coding Guidelines: Naming conventions MAME Layout Files
IntroductionLayout files are used to tell MAME what to display when running an emulated system, and how to arrange it. MAME can render emulated screens, images, text, shapes, and specialised objects for common output devices. Elements can be static, or dynamically update to reflect the state of inputs and outputs. Layouts may be automatically generated based on the number/type of emulated screens, built and linked into the MAME binary, or provided externally. MAME layout files are an XML application, using the .lay filename extension. Core conceptsNumbersThere are two kinds of numbers in MAME layouts: integers and floating-point numbers. Integers may be supplied in decimal or hexadecimal notation. A decimal integer consists of an optional # (hash) prefix, an optional +/- (plus or minus) sign character, and a sequence of digits 0-9. A hexadecimal number consists of one of the prefixes $ (dollar sign) or 0x (zero ex) followed by a sequence of hexadecimal digits 0-9 and A-F. Hexadecimal numbers are case-insensitive for both the prefix and digits. Floating-point numbers may be supplied in decimal fixed-point or scientific notation. Note that integer prefixes and hexadecimal values are not accepted where a floating-point number is expected. For a few attributes, both integers and floating-point numbers are allowed. In these cases, the presence of a # (hash), $ (dollar sign) or 0x (zero ex) prefix causes the value to be interpreted as an integer. If no recognised integer prefix is found and the value contains a decimal point or the letter E (uppercase or lowercase) introducing an exponent, it is interpreted as a floating-point number. If no integer prefix, decimal point or letter E is found, the number will be interpreted as an integer. Numbers are parsed using the "C" locale for portability. CoordinatesLayout coordinates are internally represented as IEEE754 32-bit binary floating-point numbers (also known as “single precision”). Coordinates increase in the rightward and downward directions. The origin (0,0) has no particular significance, and you may freely use negative coordinates in layouts. Coordinates are supplied as floating-point numbers. MAME assumes that view coordinates have the same aspect ratio as pixels on the output device (host screen or window). Assuming square pixels and no rotation, this means equal distances in X and Y axes correspond to equal horizontal and vertical distances in the rendered output. Views, groups and elements all have their own internal coordinate systems. When an element or group is referenced from a view or another group, its coordinates are scaled as necessary to fit the specified bounds. Objects are positioned and sized using bounds elements. The horizontal position and size may be specified in three ways: left edge and width using x and width attributes, horizontal centre and width using xc and width attributes, or left and right edges using left and right attributes. Similarly, the vertical position and size may be specified in terms of the top edge and height using y and height attributes, vertical centre and height using yc and height attributes, or top and bottom edges using top and bottom attributes. These three bounds elements are equivalent: <bounds x="455" y="120" width="12" height="8" /> <bounds xc="461" yc="124" width="12" height="8" /> <bounds left="455" top="120" right="467" bottom="128" /> It’s possible to use different schemes in the horizontal and vertical directions. For example, these equivalent bounds elements are also valid: <bounds x="455" top="120" width="12" bottom="128" /> <bounds left="455" yc="124" right="467" height="8" /> The width/height or right/bottom default to 1.0 if not supplied. It is an error if width or height are negative, if right is less than left, or if bottom is less than top. ColoursColours are specified in RGBA space. MAME is not aware of colour profiles and gamuts, so colours will typically be interpreted as sRGB with your system’s target gamma (usually 2.2). Channel values are specified as floating-point numbers. Red, green and blue channel values range from 0.0 (off) to 1.0 (full intensity). Alpha ranges from 0.0 (fully transparent) to 1.0 (opaque). Colour channel values are not pre-multiplied by the alpha value. Component and view item colour is specified using color elements. Meaningful attributes are red, green, blue and alpha. This example color element specifies all channel values: <color red="0.85" green="0.4" blue="0.3" alpha="1.0" /> Any omitted channel attributes default to 1.0 (full intensity or opaque). It is an error if any channel value falls outside the range of 0.0 to 1.0 (inclusive). ParametersParameters are named variables that can be used in most attributes. To use a parameter in an attribute, surround its name with tilde (~) characters. If a parameter is not defined, no substitution occurs. Here is an examples showing two instances of parameter use – the values of the digitno and x parameters will be substituted for ~digitno~ and ~x~: <element name="digit~digitno~" ref="digit"> A parameter name is a sequence of uppercase English letters A-Z, lowercase English letters a-z, decimal digits 0-9, and/or underscore (_) characters. Parameter names are case-sensitive. When looking for a parameter, the layout engine starts at the current, innermost scope and works outwards. The outermost scope level corresponds to the top-level mamelayout element. Each repeat, group or view element creates a new, nested scope level. Internally a parameter can hold a string, integer, or floating-point number, but this is mostly transparent. Integers are stored as 64-bit signed twos-complement values, and floating-point numbers are stored as IEEE754 64-bit binary floating-point numbers (also known as “double precision”). Integers are substituted in decimal notation, and floating point numbers are substituted in default format, which may be decimal fixed-point or scientific notation depending on the value). There is no way to override the default formatting of integer and floating-point number parameters. There are two kinds of parameters: value parameters and generator parameters. Value parameters keep their assigned value until reassigned. Generator parameters have a starting value and an increment and/or shift to be applied for each iteration. Value parameters are assigned using a param element with name and value attributes. Value parameters may appear inside the top-level mamelayout element, inside repeat, and view elements, and inside group definition elements (that is, group elements in the top-level mamelayout element, as opposed to group reference elements inside view elements other group definition elements). A value parameter may be reassigned at any point. Here’s an example assigning the value “4” to the value parameter “firstdigit”: <param name="firstdigit" value="4" /> Generator parameters are assigned using a param element with name and start attributes, and increment, lshift and/or rshift attributes. Generator parameters may only appear inside repeat elements (see Repeating blocks for details). A generator parameter must not be reassigned in the same scope (an identically named parameter may be defined in a child scope). Here are some example generator parameters: <param name="nybble" start="3" increment="-1" /> <param name="switchpos" start="74" increment="156" /> <param name="mask" start="0x0800" rshift="4" />
The increment attribute must be an integer or floating-point number to be added to the parameter’s value. The lshift and rshift attributes must be non-negative integers specifying numbers of bits to shift the parameter’s value to the left or right. The increment and shift are applied at the end of the repeating block before the next iteration starts. The parameter’s value will be interpreted as an integer or floating-point number before the increment and/or shift are applied. If both an increment and shift are supplied, the increment is applied before the shift. If the increment attribute is present and is a floating-point number, the parameter’s value will be converted to a floating-point number if necessary before the increment is added. If the increment attribute is present and is an integer while the parameter’s value is a floating-point number, the increment will be converted to a floating-point number before the addition. If the lshift and/or rshift attributes are present and not equal, the parameter’s value will be converted to an integer if necessary, and shifted accordingly. Shifting to the left is defined as shifting towards the most significant bit. If both lshift and rshift are supplied, they are netted off before being applied. This means you cannot, for example, use equal lshift and rshift attributes to clear bits at one end of a parameter’s value after the first iteration. It is an error if a param element has neither value nor start attributes, and it is an error if a param element has both a value attribute and any of the start, increment, lshift, or rshift attributes. A param element defines a parameter or reassigns its value in the current, innermost scope. It is not possible to define or reassign parameters in a containing scope. Pre-defined parametersA number of pre-defined value parameters are available providing information about the running machine:
For screen-related parameters, screens are numbered from zero in the order they appear in machine configuration, and all screens are included (not just subdevices of the device that caused the layout to be loaded). X/width and Y/height refer to the horizontal and vertical dimensions of the screen before rotation is applied. Values based on the visible area are calculated at the end of configuration. Values are not updated and layouts are not recomputed if the system reconfigures the screen while running. Parts of a layoutA view specifies an arrangement graphical object to display. A MAME layout file can contain multiple views. Views are built up from elements and screens. To simplify complex layouts, reusable groups and repeating blocks are supported. The top-level element of a MAME layout file must be a mamelayout element with a version attribute. The version attribute must be an integer. Currently MAME only supports version 2, and will not load any other version. This is an example opening tag for a top-level mamelayout element: <mamelayout version="2"> In general, children of the top-level mamelayout element are processed in reading order from top to bottom. The exception is that, for historical reasons, views are processed last. This means views see the final values of all parameters at the end of the mamelayout element, and may refer to elements and groups that appear after them. The following elements are allowed inside the top-level mamelayout element:
ElementsElements are one of the basic visual objects that may be arranged, along with screens, to make up a view. Elements may be built up of one or more components, but an element is treated as a single surface when building the scene graph and rendering. An element may be used in multiple views, and may be used multiple times within a view. An element’s appearance depends on its state. The state is an integer which usually comes from an I/O port field or an emulated output (see Element state for information on connecting an element to an emulated I/O port or output). Any component of an element may be restricted to only drawing when the element’s state is a particular value. Some components (e.g. multi-segment displays) use the state directly to determine their appearance. Each element has its own internal coordinate system. The bounds of the element’s coordinate system are computed as the union of the bounds of the individual components it’s composed of. Every element must have a name attribute specifying its name. Elements are referred to by name when instantiated in groups or views. It is an error for a layout file to contain multiple elements with identical name attributes. Elements may optionally supply a default state value with a defstate attribute, to be used if not connected to an emulated output or I/O port. If present, the defstate attribute must be a non-negative integer. Child elements of the element element instantiate components, which are drawn into the element texture in reading order from first to last using alpha blending (components draw over and may obscure components that come before them). All components support a few common features:
The following components are supported:
An example element that draws a static left-aligned text string: <element name="label_reset_cpu"> An example element that displays a circular LED where the intensity depends on the state of an active-high output: <element name="led" defstate="0"> An example element for a button that gives visual feedback when clicked: <element name="btn_rst"> An example of an element that draws a seven-segment LED display using external segment images: <element name="digit_a" defstate="0"> An example of a bar graph that grows vertically and changes colour from green, through yellow, to red as the state increases: <element name="pedal"> An example of a bar graph that grows horizontally to the left or right and changes colour from green, through yellow, to red as the state changes from the neutral position: <element name="wheel"> ViewsA view defines an arrangement of elements and/or emulated screen images that can be displayed in a window or on a screen. Views also connect elements to emulated I/O ports and/or outputs. A layout file may contain multiple views. If a view references a non-existent screen, it will be considered unviable. MAME will print a warning message, skip over the unviable view, and continue to load views from the layout file. This is particularly useful for systems where a screen is optional, for example computer systems with front panel controls and an optional serial terminal. Views are identified by name in MAME’s user interface and in command-line options. For layouts files associated with devices other than the root driver device, view names are prefixed with the device’s tag (with the initial colon omitted) – for example a view called “Keyboard LEDs” loaded for the device :tty:ie15 will be called “tty:ie15 Keyboard LEDs” in MAME’s user interface. Views are listed in the order they are loaded. Within a layout file, views are loaded in the order they appear, from top to bottom. Views are created with view elements inside the top-level mamelayout element. Each view element must have a name attribute, supplying its human-readable name for use in the user interface and command-line options. This is an example of a valid opening tag for a view element: <view name="Control panel"> A view creates a nested parameter scope inside the parameter scope of the top-level mamelayout element. For historical reasons, view elements are processed after all other child elements of the top-level mamelayout element. This means a view can reference elements and groups that appear after it in the file, and parameters from the enclosing scope will have their final values from the end of the mamelayout element. A view element may have a showpointers attribute to set whether mouse and pen pointers should be shown for the view. If present, the value must be either yes or no. If the showpointers attribute is not present, pen and mouse pointers are shown for views that contain items bound to I/O ports. The following child elements are allowed inside a view element:
Screens (screen elements) and layout elements (element elements) may have an id attribute. If present, the id attribute must not be empty, and must be unique within a view, including screens and elements instantiated via reusable groups and repeating blocks. Screens and layout elements with id attributes can be looked up by Lua scripts (see MAME Layout Scripting). Screens (screen elements), layout elements (element elements) and groups (group elements) may have their orientation altered using an orientation child element. For screens, the orientation modifiers are applied in addition to the orientation modifiers specified on the screen device and on the machine. The orientation element supports the following attributes, all of which are optional:
Screens (screen elements) and layout elements (element elements) may have a blend attribute to set the blending mode. Supported values are none (no blending), alpha (alpha blending), multiply (RGB multiplication), and add (additive blending). The default for screens is to allow the driver to specify blending per layer; the default blending mode for layout elements is alpha blending. Screens (screen elements), layout elements (element elements) and groups (group elements) may be positioned and sized using a bounds child element (see Coordinates for details). In the absence of a bounds child element, screens’ and layout elements’ bounds default to a unit square (origin at 0,0 and height and width both equal to 1). In the absence of a bounds child element, groups are expanded with no translation/scaling (note that groups may position screens/elements outside their bounds). This example shows a view instantiating and positioning a screen, an individual layout element, and two element groups: <view name="LED Displays, Terminal and Keypad"> Screens (screen elements), layout elements (element elements) and groups (group elements) may have a color child element (see Colours) specifying a modifier colour. The component colours of the screen or layout element(s) are multiplied by this colour. Screens (screen elements) and layout elements (element elements) may have their colour and position/size animated by supplying multiple color and/or bounds child elements with state attributes. See View item animation for details. Layout elements (element elements) may be configured to show only part of the element’s width or height using xscroll and/or yscroll child elements. This can be used for devices like slot machine reels. The xscroll and yscroll elements support the same attributes:
CollectionsCollections of screens and/or layout elements can be shown or hidden by the user as desired. For example, a single view could include both displays and a clickable keypad, and allow the user to hide the keypad leaving only the displays visible. Collections are created using collection elements inside view, group and other collection elements. A collection element must have a name attribute providing the display name for the collection. Collection names must be unique within a view. The initial visibility of a collection may be specified by providing a visible attribute. Set the visible attribute to yes if the collection should be initially visible, or no if it should be initially hidden. Collections are initially visible by default. Here is an example demonstrating the use of collections to allow parts of a view to be hidden by the user: <view name="LED Displays, CRT and Keypad"> A collection creates a nested parameter scope. Any param elements inside the collection element set parameters in the local scope for the collection. See Parameters for more detail on parameters. (Note that the collection’s name and default visibility are not part of its content, and any parameter references in the name and visible attributes themselves will be substituted using parameter values from the collection’s parent’s scope.) Reusable groupsGroups allow an arrangement of screens and/or layout elements to be used multiple times in views or other groups. Groups can be beneficial even if you only use the arrangement once, as they can be used to encapsulate part of a complex layout. Groups are defined using group elements inside the top-level mamelayout element, and instantiated using group elements inside view and other group elements. Each group definition element must have a name attribute providing a unique identifier. It is an error if a layout file contains multiple group definitions with identical name attributes. The value of the name attribute is used when instantiating the group from a view or another group. This is an example opening tag for a group definition element inside the top-level mamelayout element: <group name="panel"> This group may then be instantiated in a view or another group element using a group reference element, optionally supplying destination bounds, orientation, and/or modifier colour. The ref attribute identifies the group to instantiate – in this example, destination bounds are supplied: <group ref="panel"><bounds x="87" y="58" width="23" height="23.5" /></group> Group definition elements allow all the same child elements as views. Positioning and orienting screens, layout elements and nested groups works the same way as for views. See Views for details. A group may instantiate other groups, but recursive loops are not permitted. It is an error if a group directly or indirectly instantiates itself. Groups have their own internal coordinate systems. If a group definition element has no bounds element as a direct child, its bounds are computed as the union of the bounds of all the screens, layout elements and/or nested groups it instantiates. A bounds child element may be used to explicitly specify group bounds (see Coordinates for details). Note that groups’ bounds are only used for the purpose of calculating the coordinate transform when instantiating a group. A group may position screens and/or elements outside its bounds, and they will not be cropped. To demonstrate how bounds calculation works, consider this example: <group name="autobounds"> This is relatively straightforward, as all elements inherently fall within the group’s automatically computed bounds. Now consider what happens if a group positions elements outside its explicit bounds: <group name="periphery"> The group’s elements are translated and scaled as necessary to distort the group’s internal bounds to the destination bounds in the view. The group’s content is not restricted to its bounds. The view considers the bounds of the actual layout elements when computing its bounds, not the destination bounds specified for the group. When a group is instantiated, it creates a nested parameter scope. The logical parent scope is the parameter scope of the view, group or repeating block where the group is instantiated (not its lexical parent, the top-level mamelayout element). Any param elements inside the group definition element set parameters in the local scope for the group instantiation. Local parameters do not persist across multiple instantiations. See Parameters for more detail on parameters. (Note that the group’s name is not part of its content, and any parameter references in the name attribute itself will be substituted at the point where the group definition appears in the top-level mamelayout element’s scope.) Repeating blocksRepeating blocks provide a concise way to generate or arrange large numbers of similar elements. Repeating blocks are generally used in conjunction with generator parameters (see Parameters). Repeating blocks may be nested for more complex arrangements. Repeating blocks are created with repeat elements. Each repeat element requires a count attribute specifying the number of iterations to generate. The count attribute must be a positive integer. Repeating blocks are allowed inside the top-level mamelayout element, inside group and view elements, and insider other repeat elements. The exact child elements allowed inside a repeat element depend on where it appears:
A repeating block effectively repeats its contents the number of times specified by its count attribute. See the relevant sections for details on how the child elements are used (Parts of a layout, Reusable groups, and Views). A repeating block creates a nested parameter scope inside the parameter scope of its lexical (DOM) parent element. Generating white number labels from zero to eleven named label_0, label_1, and so on (inside the top-level mamelayout element): <repeat count="12"> A horizontal row of forty digital displays, with five units space between them, controlled by outputs digit0 to digit39 (inside a group or view element): <repeat count="40"> Eight five-by-seven dot matrix displays in a row, with pixels controlled by outputs Dot_000 to Dot_764 (inside a group or view element): <repeat count="8"> <!-- 8 digits --> Two horizontally separated, clickable, four-by-four keypads (inside a group or view element): <repeat count="2"> The buttons are drawn using elements btn00 in the top left, bnt07 in the top right, btn30 in the bottom left, and btn37 in the bottom right, counting in between. The four rows are connected to I/O ports row0, row1, row2, and row3, from top to bottom. The columns are connected to consecutive I/O port bits, starting with the least significant bit on the left. Note that the mask parameter in the innermost repeat element takes its initial value from the correspondingly named parameter in the enclosing scope, but does not modify it. Generating a chequerboard pattern with alternating alpha values 0.4 and 0.2 (inside a group or view element): <repeat count="4"> The outermost repeat element generates a group of two rows on each iteration; the next repeat element generates an individual row on each iteration; the innermost repeat element produces two horizontally adjacent tiles on each iteration. Rows are connected to I/O ports board:IN.7 at the top to board.IN.0 at the bottom. InteractivityInteractive views are supported by allowing items to be bound to emulated outputs and I/O ports. Five kinds of interactivity are supported:
Clickable itemsIf a view item (element or screen element) has inputtag and inputmask attribute values that correspond to a digital switch field in the emulated system, clicking the element will activate the switch. The switch will remain active as long as the primary button is held down and the pointer is within the item’s current bounds. (Note that the bounds may change depending on the item’s animation state, see View item animation). The inputtag attribute specifies the tag path of an I/O port relative to the device that caused the layout file to be loaded. The inputmask attribute must be an integer specifying the bits of the I/O port field that the item should activate. This sample shows instantiation of clickable buttons: The clickthrough attribute controls whether clicks can pass through the view item to other view items drawn above it. The clickthrough attribute must be yes or no if present. The default is no (clicks do not pass through) for view items with inputtag and inputmask attributes, and yes (clicks pass through) for other view items. <element ref="btn_3" inputtag="X2" inputmask="0x10"> When handling pointer input, MAME treats all layout elements as being rectangular. Element stateA view item that instantiates an element (element element) may supply a state value to the element from an emulated I/O port or output. See Elements for details on how an element’s state affects its appearance. If the element element has a name attribute, the element state value will be taken from the value of the correspondingly named emulated output. Note that output names are global, which can become an issue when a machine uses multiple instances of the same type of device. This example shows how digital displays may be connected to emulated outputs: <element name="digit6" ref="digit"><bounds x="16" y="16" width="48" height="80" /></element> <element name="digit5" ref="digit"><bounds x="64" y="16" width="48" height="80" /></element> <element name="digit4" ref="digit"><bounds x="112" y="16" width="48" height="80" /></element> <element name="digit3" ref="digit"><bounds x="160" y="16" width="48" height="80" /></element> <element name="digit2" ref="digit"><bounds x="208" y="16" width="48" height="80" /></element> <element name="digit1" ref="digit"><bounds x="256" y="16" width="48" height="80" /></element> If the element element has inputtag and inputmask attributes but lacks a name attribute, the element state value will be taken from the value of the corresponding I/O port, masked with the inputmask value. The inputtag attribute specifies the tag path of an I/O port relative to the device that caused the layout file to be loaded. The inputmask attribute must be an integer specifying the bits of the I/O port field to use. If the element element has no inputraw attribute, or if the value of the inputraw attribute is no, the I/O port’s value is masked with the inputmask value and XORed with the I/O port default field value. If the result is non-zero, the element state is 1, otherwise it’s 0. This is often used or provide visual feedback for clickable buttons, as values for active-high and active-low switches are normalised. If the element element has an inputraw attribute with the value yes, the element state will be taken from the I/O port’s value masked with the inputmask value and shifted to the right to remove trailing zeroes (for example a mask of 0x05 will result in no shift, while a mask of 0xb0 will result in the value being shifted four bits to the right). This is useful for obtaining the value of analog or positional inputs. View item animationItems’ colour and position/size within their containing view may be animated. This is achieved by supplying multiple color and/or bounds child elements with state attributes. The state attribute of each color or bounds child element must be a non-negative integer. Within a view item, no two color elements may have equal state state attributes, and no two bounds elements may have equal state attributes. If the item’s animation state is lower than the state value of any bounds child element, the position/size specified by the bounds child element with the lowest state value will be used. If the item’s animation state is higher than the state value of any bounds child element, the position/size specified by the bounds child element with the highest state value will be used. If the item’s animation state is between the state values of two bounds child elements, the position/size will be interpolated linearly. If the item’s animation state is lower than the state value of any color child element, the colour specified by the color child element with the lowest state value will be used. If the item’s animation state is higher than the state value of any color child element, the colour specified by the color child element with the highest state value will be used. If the item’s animation state is between the state values of two color child elements, the RGBA colour components will be interpolated linearly. An item’s animation state may be bound to an emulated output or input port by supplying an animate child element. If present, the animate element must have either an inputtag attribute or a name attribute (but not both). If the animate child element is not present, the item’s animation state is the same as its element state (see Element state). If the animate child element is present and has an inputtag attribute, the item’s animation state will be taken from the value of the corresponding I/O port. The inputtag attribute specifies the tag path of an I/O port relative to the device that caused the layout file to be loaded. The raw value from the input port is used, active-low switch values are not normalised. If the animate child element is present and has a name attribute, the item’s animation state will be taken from the value of the correspondingly named emulated output. Note that output names are global, which can become an issue when a machine uses multiple instances of the same type of device. If the animate child element has a mask attribute, the item’s animation state will be masked with the mask value and shifted to the right to remove trailing zeroes (for example a mask of 0x05 will result in no shift, while a mask of 0xb0 will result in the value being shifted four bits to the right). Note that the mask attribute applies to output values (specified with the name attribute) as well as input port values (specified with the inputtag attribute). If the mask attribute is present, it must be an integer value. If the mask attribute is not present, it is equivalent to all 32 bits being set. This example shows elements with independent element state and animation state, using the animation state taken from emulated outputs to control their position: <repeat count="5"> This example shows elements with independent element state and animation state, using the animation state taken from an emulated positional input to control their positions: <repeat count="4"> Error handling
Automatically-generated viewsAfter loading internal (developer-supplied) and external (user-supplied) layouts, MAME automatically generates views based on the machine configuration. The following views will be automatically generated:
Using complay.pyThe MAME source contains a Python script called complay.py, found in the scripts/build subdirectory. This script is used as part of MAME’s build process to reduce the size of data for internal layouts and convert it to a form that can be built into the executable. However, it can also detect many common layout file format errors, and generally provides better error messages than MAME does when loading a layout file. Note that it doesn’t actually run the whole layout engine, so it can’t detect errors like undefined element references when parameters are used, or recursively nested groups. The complay.py script is compatible with both Python 2.7 and Python 3 interpreters. The complay.py script takes three parameters – an input file name, an output file name, and a base name for variables in the output: python scripts/build/complay.py
<input> [<output> [<varname>]]
The input file name is required. If no output file name is supplied, complay.py will parse and check the input, reporting any errors found, without producing output. If no base variable name is provided, complay.py will generate one based on the input file name. This is not guaranteed to produce valid identifiers. The exit status is 0 (zero) on success, 1 on an error in the command invocation, 2 if error are found in the input file, or 3 in case of an I/O error. If an output file name is specified, the file will be created/overwritten on success or removed on failure. To check a layout file for common errors, run the script with the path to the file to check and no output file name or base variable name. For example: python scripts/build/complay.py
artwork/dino/default.lay
Example layout filesThese layout files demonstrate various artwork system features. They are all internal layouts included in MAME.
MAME Layout Scripting
IntroductionMAME layout files can embed Lua script to provide enhanced functionality. Although there’s a lot you can do with conditionally drawn components and parameter animation, some things can only be done with scripting. MAME uses an event-based model. Scripts can supply functions that will be called after certain events, or when certain data is required. Layout scripting requires the layout plugin to be enabled. For example, to run BWB Double Take with the Lua script in the layout enabled, you might use this command: mame -plugins -plugin layout v4dbltak You may want to add the settings to enable the layout plugin to an INI file to save having to enable it every time you start a system. See Plugins for more information about using plugins with MAME. Practical examplesBefore diving into the technical details of how it works, we’ll start with some example layout files using Lua script for enhancement. It’s assumed that you’re familiar with MAME’s artwork system and have a basic understanding of Lua scripting. For details on MAME’s layout file, see MAME Layout Files; for detailed descriptions of MAME’s Lua interface, see Lua Scripting Interface. Espial: joystick split across portsTake a look at the player input definitions for Espial: PORT_START("IN1") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_START1 ) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_START2 ) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_COCKTAIL PORT_START("IN2") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_COCKTAIL PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY There are two joysticks, one used for both players on an upright cabinet or the first player on a cocktail cabinet, and one used for the second player on a cocktail cabinet. Notice that the switches for the first joystick are split across the two I/O ports. There’s no layout file syntax to build the element state using bits from multiple I/O ports. It’s also inconvenient if each joystick needs to be defined as a separate element because the bits for the switches aren’t arranged the same way. We can overcome these limitations using a script to read the player inputs and set the items’ element state: <?xml version="1.0"?> <mamelayout version="2"> The layout has a script element containing the Lua script. This is called as a function by the layout plugin when the layout file is loaded. The layout views have been built at this point, but the emulated system has not finished starting. In particular, it’s not safe to access inputs and outputs at this time. The key variable in the script environment is file, which gives the script access to its layout file. We supply a function to be called after tags in the layout file have been resolved. At this point, the emulated system will have completed starting. This function does the following tasks:
The function called before view items are added to the render target reads the player inputs, and shuffles the bits into the order needed by the joystick element. Star Wars: animation on two axesWe’ll make a layout that shows the position of the flight yoke for Atari Star Wars. The input ports are straightforward – each analog axis produces a value in the range from 0x00 (0) to 0xff (255), inclusive: PORT_START("STICKY") PORT_BIT( 0xff, 0x80, IPT_AD_STICK_Y ) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_START("STICKX") PORT_BIT( 0xff, 0x80, IPT_AD_STICK_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) Here’s our layout file: <?xml version="1.0"?> <mamelayout version="2"> The layout has a script element containing the Lua script, to be called as a function by the layout plugin when the layout file is loaded. This happens after the layout views have been build, but before the emulated system has finished starting. The layout file object is supplied to the script in the file variable. We supply a function to be called after tags in the layout file have been resolved. This function does the following:
The view is looked up by name (value of its name attribute), and items within the view are looked up by ID (values of their id attributes). Layout view dimensions are recomputed in response to several events, including the window being resized, entering/leaving full screen mode, toggling visibility of item collections, and changing the zoom to screen area setting. When this happens, we need to update our size and animation scale factors. We get the bounds of the square where the yoke position is displayed, calculate the size for the animated items, and calculate the ratios of axis units to render target coordinates in each direction. It’s more efficient to do these calculations only when the results may change. Before view items are added to the render target, we read the analog axis inputs and convert the values to coordinates positions for the animated items. The Y axis input uses larger values to aim higher, so we need to reverse the value by subtracting it from 0xff (255). We add in the coordinates of the top left corner of the square where we’re displaying the yoke position. We do this once each time the layout is drawn for efficiency, since we can use the values for all three animated items. Finally, we supply bounds for the animated items when required. These functions need to return render_bounds objects giving the position and size of the items in render target coordinates. (Since the vertical and horizontal line elements each only move on a single axis, it would be possible to animate them using the layout file format’s item animation features. Only the box at the intersection of the line actually requires scripting. It’s done entirely using scripting here for illustrative purposes.) The layout script environmentThe Lua environment is provided by the layout plugin. It’s fairly minimal, only providing what’s needed:
Layout eventsMAME layout scripting uses an event-based model. Scripts can supply functions to be called after events occur, or when data is needed. There are three levels of events: layout file events, layout view events, and layout view item events. Layout file eventsLayout file events apply to the file as a whole, and not to an individual view.
Layout view eventsLayout view events apply to an individual view.
The callback function has no return value. Call with nil as the argument to remove the event handler.
The callback function has no return value. Call with nil as the argument to remove the event handler.
The callback function has no return value. Call with nil as the argument to remove the event handler.
The callback function has no return value and takes no parameters. Call with nil as the argument to remove the event handler. Layout view item eventsLayout view item callbacks apply to individual items within a view. They are used to override items’ default element state, animation state, bounds and colour behaviour.
Layout element eventsLayout element events apply to an individual visual element definition.
Object Finders
IntroductionObject finders are an important part of the glue MAME provides to tie the devices that make up an emulated system together. Object finders are used to specify connections between devices, to efficiently access resources, and to check that necessary resources are available on validation. Object finders search for a target object by tag relative to a base device. Some types of object finder require additional parameters. Most object finders have required and optional versions. The required versions will raise an error if the target object is not found. This will prevent a device from starting or cause a validation error. The optional versions will log a verbose message if the target object is not found, and provide additional members for testing whether the target object was found or not. Object finder classes are declared in the header src/emu/devfind.h and have Doxygen format API documentation. Types of object finder
Finding resourcesWe’ll start with a simple example of a device that uses object finders to access its own child devices, inputs and ROM region. The code samples here are based on the Apple II Parallel Printer Interface card, but a lot of things have been removed for clarity. Object finders are declared as members of the device class: class a2bus_parprn_device : public device_t, public device_a2bus_card_interface { public: We want to find a centronics_device, an output_latch_device, an I/O port, and an 8-bit memory region. In the constructor, we set the initial target for the object finders: a2bus_parprn_device::a2bus_parprn_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : Each object finder takes a base device and tag as constructor arguments. The base device supplied at construction serves two purposes. Most obviously, the tag is specified relative to this device. Possibly more importantly, the object finder registers itself with this device so that it will be called to perform validation and object resolution. Note that the object finders do not copy the tag strings. The caller must ensure the tag string remains valid until after validation and/or object resolution is complete. The memory region and I/O port come from the ROM definition and input definition, respectively: namespace { ROM_START(parprn) Note that the tags "prom" and "CFG" match the tags passed to the object finders on construction. Child devices are instantiated in the device’s machine configuration member function: void a2bus_parprn_device::device_add_mconfig(machine_config &config) { Object finders are passed to device types to provide tags when instantiating child devices. After instantiating a child device in this way, the object finder can be used like a pointer to the device until the end of the machine configuration member function. Note that to use an object finder like this, its base device must be the same as the device being configured (the this pointer of the machine configuration member function). After the emulated machine has been started, the object finders can be used in much the same way as pointers: void a2bus_parprn_device::write_c0nx(u8 offset, u8 data) { For convenience, object finders that target the base pointer of memory regions and shares can be indexed like arrays. Connections between devicesDevices need to be connected together within a system. For example the Sun SBus device needs access to the host CPU and address space. Here’s how we declare the object finders in the device class (with all distractions removed): DECLARE_DEVICE_TYPE(SBUS, sbus_device) class sbus_device : public device_t, public device_memory_interface { There are several things to take note of here:
The constant finder_base::DUMMY_TAG is guaranteed to be invalid and will not resolve to an object. This makes it easy to detect incomplete configuration and report an error. Address spaces are numbered from zero, so a negative address space number is invalid. The member functions for configuring object finders take a universal reference to a tag-like object (templated type with && qualifier), as well as any other parameters needed by the specific type of object finder. An address space finder needs an address space number in addition to a tag-like object. So what’s a tag-like object? Three things are supported:
The additional constructor that sets initial configuration delegates to the standard constructor and then calls the configuration member functions. It’s purely for convenience. When we want to instantiate this device and hook it up, we do this: SPARCV7(config, m_maincpu, 20'000'000); ADDRESS_MAP_BANK(config, m_type1space); SBUS(config, m_sbus, 20'000'000); m_sbus->set_cpu(m_maincpu); m_sbus->set_type1space(m_type1space, 0); We supply the same object finders to instantiate the CPU and address space devices, and to configure the SBus device. Note that we could also use literal C strings to configure the SBus device, at the cost of needing to update the tags in multiple places if they change: SBUS(config, m_sbus, 20'000'000); m_sbus->set_cpu("maincpu"); m_sbus->set_type1space("type1", 0); If we want to use the convenience constructor, we just supply additional arguments when instantiating the device: SBUS(config, m_sbus, 20'000'000, m_maincpu, m_type1space, 0); Object finder arraysMany systems have multiple similar devices, I/O ports or other resources that can be logically organised as an array. To simplify these use cases, object finder array types are provided. The object finder array type names have _array added to them:
A common case for an object array finder is a key matrix: class keyboard_base : public device_t, public device_mac_keyboard_interface { protected: Constructing an object finder array is similar to constructing an object finder, except that rather than just a tag you supply a tag format string and index offset. In this case, the tags of the I/O ports in the array will be ROW0, ROW1, ROW2, … ROW9. Note that the object finder array allocates dynamic storage for the tags, which remain valid until destruction. The object finder array is used in much the same way as a std::array of the underlying object finder type. It supports indexing, iterators, and range-based for loops. Because an index offset is specified, the tags don’t need to use zero-based indices. It’s common to use one-based indexing like this: class dooyong_state : public driver_device { protected: This causes m_bg to find devices with tags bg1 and bg2, while m_fg finds devices with tags fg1 and fg2. Note that the indexes into the object finder arrays are still zero-based like any other C array. It’s also possible to other format conversions, like hexadecimal (%x and %X) or character (%c): class eurit_state : public driver_device { public: In this case, the key matrix ports use tags KEYA, KEYB, KEYC, KEYD and KEYE. When the tags don’t follow a simple ascending sequence, you can supply a brace-enclosed initialiser list of tags: class seabattl_state : public driver_device { public: If the underlying object finders require additional constructor arguments, supply them after the tag format and index offset (the same values will be used for all elements of the array): class dreamwld_state : public driver_device { public: This finds or creates memory shares with tags vram_0 and vram_1, each of which is 8 KiB organised as 4,096 big-Endian 16-bit words. Optional object findersOptional object finders don’t raise an error if the target object isn’t found. This is useful in two situations: driver_device implementations (state classes) representing a family of systems where some components aren’t present in all configurations, and devices that can optionally use a resource. Optional object finders provide additional member functions for testing whether the target object was found. Optional system componentsOften a class is used to represent a family of related systems. If a component isn’t present in all configurations, it may be convenient to use an optional object finder to access it. We’ll use the Sega X-board device as an example: class segaxbd_state : public device_t { protected: The optional_device and optional_ioport_array members are declared and constructed in the usual way. Before accessing the target object, we call an object finder’s found() member function to check whether it’s present in the system (the explicit cast-to-Boolean operator can be used for the same purpose): void segaxbd_state::pc_0_w(u8 data) { Optional I/O ports provide a convenience member function called read_safe that reads the port value if present, or returns the supplied default value otherwise: u8 segaxbd_state::analog_r() { The ADC ports return 0x10 (16 decimal) if they are not present, while the multiplexed digital ports return 0xff (255 decimal) if they are not present. Note that read_safe is a member of the optional_ioport itself, and not a member of the target ioport_port object (the optional_ioport is not dereferenced when using it). There are some disadvantages to using optional object finders:
Consider whether optional object finders are the best solution, or whether creating a derived class for the system with additional components is more appropriate. Optional resourcesSome devices can optionally use certain resources. If the host system doesn’t supply them, the device will still function, although some functionality may not be available. For example, the Virtual Boy cartridge slot responds to three address spaces, called EXP, CHIP and ROM. If the host system will never use one or more of them, it doesn’t need to supply a place for the cartridge to install the corresponding handlers. (For example a copier may only use the ROM space.) Let’s look at how this is implemented. The Virtual Boy cartridge slot device declares optional_address_space members for the three address spaces, offs_t members for the base addresses in these spaces, and inline member functions for configuring them: class vboy_cart_slot_device : The object finders are constructed with dummy values for the tags and space numbers (finder_base::DUMMY_TAG and -1): vboy_cart_slot_device::vboy_cart_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : To help detect configuration errors, we’ll check for cases where address spaces have been configured but aren’t present: void vboy_cart_slot_device::device_start() { Object finder types in more detailAll object finders provide configuration functionality: char const *finder_tag() const { return m_tag; } std::pair<device_t &, char const *> finder_target(); void set_tag(device_t &base, char const *tag); void set_tag(char const *tag); void set_tag(finder_base const &finder); The finder_tag and finder_target member function provides access to the currently configured target. Note that the tag returned by finder tag is relative to the base device. It is not sufficient on its own to identify the target. The set_tag member functions configure the target of the object finder. These members must not be called after the object finder is resolved. The first form configures the base device and relative tag. The second form sets the relative tag and also implicitly sets the base device to the device that is currently being configured. This form must only be called from machine configuration functions. The third form sets the base object and relative tag to the current target of another object finder. Note that the set_tag member functions do not copy the relative tag. It is the caller’s responsibility to ensure the C string remains valid until the object finder is resolved (or reconfigured with a different tag). The base device must also be valid at resolution time. This may not be the case if the device could be removed or replaced later. All object finders provide the same interface for accessing the target object: ObjectClass *target() const; operator ObjectClass *() const; ObjectClass *operator->() const; These members all provide access to the target object. The target member function and cast-to-pointer operator will return nullptr if the target has not been found. The pointer member access operator asserts that the target has been found. Optional object finders additionally provide members for testing whether the target object has been found: bool found() const; explicit operator bool() const; These members return true if the target was found, on the assumption that the target pointer will be non-null if the target was found. Device findersDevice finders require one template argument for the expected device class. This should derive from either device_t or device_interface. The target device object must either be an instance of this class, an instance of a class that derives from it. A warning message is logged if a matching device is found but it is not an instance of the expected class. Device finders provide an additional set_tag overload: set_tag(DeviceClass &object); This is equivalent to calling set_tag(object, DEVICE_SELF). Note that the device object must not be removed or replaced before the object finder is resolved. Memory system object findersThe memory system object finders, required_memory_region, optional_memory_region, required_memory_bank, optional_memory_bank and memory_bank_creator, do not have any special functionality. They are often used in place of literal tags when installing memory banks in an address space. Example using memory bank finders in an address map: class qvt70_state : public driver_device { public: Example using a memory bank creator to install a memory bank dynamically: class vegaeo_state : public eolith_state { public: I/O port findersOptional I/O port finders provide an additional convenience member function: ioport_value read_safe(ioport_value defval); This will read the port’s value if the target I/O port was found, or return defval otherwise. It is useful in situations where certain input devices are not always present. Address space findersAddress space finders accept an additional argument for the address space number to find. A required data width can optionally be supplied to the constructor. address_space_finder(device_t &base, char const *tag, int spacenum, u8 width = 0); void set_tag(device_t &base, char const *tag, int spacenum); void set_tag(char const *tag, int spacenum); void set_tag(finder_base const &finder, int spacenum); template <bool R> void set_tag(address_space_finder<R> const &finder); The base device and tag must identify a device that implements device_memory_interface. The address space number is a zero-based index to one of the device’s address spaces. If the width is non-zero, it must match the target address space’s data width in bits. If the target address space exists but has a different data width, a warning message will be logged, and it will be treated as not being found. If the width is zero (the default argument value), the target address space’s data width won’t be checked. Member functions are also provided to get the configured address space number and set the required data width: int spacenum() const; void set_data_width(u8 width); Memory pointer findersThe memory pointer finders, required_region_ptr, optional_region_ptr, required_shared_ptr, optional_shared_ptr and memory_share_creator, all require one template argument for the element type of the memory area. This should usually be an explicitly-sized unsigned integer type (u8, u16, u32 or u64). The size of this type is compared to the width of the memory area. If it doesn’t match, a warning message is logged and the region or share is treated as not being found. The memory pointer finders provide an array access operator, and members for accessing the size of the memory area: PointerType &operator[](int index) const; size_t length() const; size_t bytes() const; The array access operator returns a non-const reference to an element of the memory area. The index is in units of the element type; it must be non-negative and less than the length of the memory area. The length member returns the number of elements in the memory area. The bytes member returns the size of the memory area in bytes. These members should not be called if the target region/share has not been found. The memory_share_creator requires additional constructor arguments for the size and Endianness of the memory share: memory_share_creator(device_t &base, char const *tag, size_t bytes, endianness_t endianness); The size is specified in bytes. If an existing memory share is found, it is an error if its size does not match the specified size. If the width is wider than eight bits and an existing memory share is found, it is an error if its Endianness does not match the specified Endianness. The memory_share_creator provides additional members for accessing properties of the memory share: endianness_t endianness() const; u8 bitwidth() const; u8 bytewidth() const; These members return the Endianness, width in bits and width in bytes of the memory share, respectively. They must not be called if the memory share has not been found. Output findersOutput finders are used for exposing outputs that can be used by the artwork system, or by external programs. A common application using an external program is a control panel or cabinet lighting controller. Output finders are not really object finders, but they’re described here because they’re used in a similar way. There are a number of important differences to be aware of:
Output finders take a variable number of template arguments corresponding to the number of array dimensions you want. Let’s look at an example that uses zero-, one- and two-dimensional output finders: class mmd2_state : public driver_device { public: The m_led_halt and m_led_hold members are zero-dimensional output finders. They find a single output each. The m_digits member is a one-dimensional output finder. It finds nine outputs organised as a single-dimensional array. The m_p member is a two-dimensional output finder. It finds 24 outputs organised as three rows of eight columns each. Larger numbers of dimensions are supported. The output finder constructor takes a base device reference, a format string, and an index offset for each dimension. In this case, all the offsets are zero. The one-dimensional output finder m_digits will find outputs digit0, digit1, digit2, … digit8. The two-dimensional output finder m_p will find the outputs p0_0, p0_1, … p0_7 for the first row, p1_0, p1_1, … p1_7 for the second row, and p2_0, p2_1, … p2_7 for the third row. You must call resolve on each output finder before it can be used. This should be done at start time for the output values to be included in save states: void mmd2_state::machine_start() { Output finders provide operators allowing them to be assigned from or cast to 32-bit signed integers. The assignment operator will send a notification if the new value is different to the output’s current value. operator s32() const; s32 operator=(s32 value); To set output values, assign through the output finders, as you would with an array of the same rank: void mmd2_state::round_leds_w(offs_t offset, u8 data) { Input System
IntroductionThe variety of systems MAME emulates, as well as the variation in host systems and peripherals, necessitates a flexible, configurable input system. Note that the input system is concerned with low-level user input. High-level user interaction, involving things like text input and pointing devices, is handled separately. ComponentsFrom the emulated system’s point of view, the input system has the following conceptual components. Input deviceInput devices supply input values. An input device typically corresponds to a physical device in the host system, for example a keyboard, mouse or game controller. However, there isn’t always a one-to-one correspondence between input devices and physical devices. For example the SDL keyboard provider module aggregates all keyboards into a single input device, and the Win32 lightgun provider module can present two input devices using input from a single mouse. Input devices are identified by their device class (keyboard, mouse, joystick or lightgun) and device number within the class. Input provider modules can also supply an implementation-dependent identifier to allow the user to configure stable device numbering. Note that input devices are unrelated to emulated devices (device_t implementations) despite the similar name. Input device itemAlso known as a control, and input device item corresponds to a input source that produces a single value. This usually corresponds to a physical control or sensor, for example a joystick axis, a button or an accelerometer. MAME supports three kinds of controls: switches, absolute axes and relative axes:
Negative axis values should correspond to directions up, to the left, away from the player, or anti-clockwise. For single-ended axes (e.g. pedals or displacement-sensitive triggers and buttons), only zero and the negative portion of the range should be used. Switches are used to represent controls that naturally have two distinct states, like buttons and toggle switches. Absolute axes are used to represent controls with a definite range and/or neutral position. Examples include steering wheels with limit stops, joystick axes, and displacement-sensitive triggers. Relative axes are used to represent controls with an effectively infinite range. Examples include mouse/trackball axes, incremental encoder dials, and gyroscopes. Accelerometers and force sensing joystick axes should be represented as absolute axes, even though the range is theoretically open-ended. In practice, there is a limit to the range the transducers can report, which is usually substantially larger than needed for normal operation. Input device items are identified by their associated device’s class and device number along with an input item ID. MAME supplies item IDs for common types of controls. Additional controls or controls that do not correspond to a common type are dynamically assigned item IDs. MAME supports hundreds to items per input device. I/O port fieldAn I/O port field represents an input source in an emulated device or system. Most types of I/O port fields can be assigned one or more combinations of controls, allowing the user to control the input to the emulated system. Similarly to input device items, there are multiple types of I/O port fields:
A digital field appears to the user as a single assignable input, which accepts switch values. An analog field appears to the user as three assignable inputs: an axis input, which accepts axis values; and an increment input and a decrement input which accept switch values. Input managerThe input manager has several responsibilities:
In practice, emulated devices and systems rarely interact with the input manager directly. The most common reason to access the input manager is implementing special debug controls, which should be disabled in release builds. Plugins that respond to input need to call the input manager to read inputs. I/O port managerThe I/O port manager’s primary responsibilities include:
Like the input manager, the I/O port manager is largely transparent to emulated devices and systems. You just need to set up your I/O ports and fields, and the I/O port manager handles the rest. Structures and data typesThe following data types are used for dealing with input. Input codeAn input code specifies an input device item and how it should be interpreted. It is a tuple consisting of the following values: device class, device number, item class, item modifier and item ID:
If the specified input item is a switch, it can only be read using the switch class, and no modifiers are supported. Attempting to read a switch as an absolute or relative axis always returns zero. If the specified input item is an absolute axis, it can be read as an absolute axis or as a switch:
If the specified input item is a relative axis, it can be read as a relative axis or as a switch:
There are also special input codes used for specifying how multiple controls are to be combined in an input sequence. The most common place you’ll encounter input codes in device and system driver code is when specifying initial assignments for I/O port fields that don’t have default assignments supplied by the core. The PORT_CODE macro is used for this purpose. MAME provides macros and helper functions for producing commonly used input codes, including standard keyboard keys and mouse/joystick/lightgun axes and buttons. Input sequenceAn input sequence specifies a combination controls that can be assigned to an input. The name refers to the fact that it is implemented as a sequence container with input codes as elements. It is somewhat misleading, as input sequences are interpreted using instantaneous control values. Input sequences are interpreted differently for switch and axis input. Input sequences for switch input must only contain input codes with the item class set to switch along with the special or and not input codes. The input sequence is interpreted using sum-of-products logic. A not code causes the value returned by the immediately following code to be inverted. The conjunction of values returned by successive codes is evaluated until an or code is encountered. If the current value is 1 when an or code is encountered it is returned, otherwise evaluation continues. Input sequences for axis input can contain input codes with the item class set to switch, absolute axis or relative axis along with the special or and not codes. It’s helpful to think of the input sequence as containing one or more groups of input codes separated by or codes:
Emulation code rarely needs to deal with input sequences directly, as they’re handled internally between the I/O port manager and input manager. The input manager also converts input sequences to and from the token strings stored in configuration files and produces text for displaying input sequences to users. Plugins with controls or hotkeys need to use input sequences to allow configuration. Utility classes are provided to allow input sequences to be entered by the user in a consistent way, and the input manager can be used for conversions to and from configuration and display strings. It is very rare to need to directly manipulate input sequences. Input provider modulesInput provider modules are part of the OS-dependent layer (OSD), and are not directly exposed to emulation and user interface code. Input provider modules are responsible for detecting available host input devices, setting up input devices for the input manager, and providing callbacks to read the current state of input device items. Input provider modules may also provide additional default input assignments suitable for host input devices that are present. The user is given a choice of input modules to use. One input provider module is used for each of the four input device classes (keyboard, mouse, joystick and lightgun). The available modules depend on the host operating system and OSD implementation. Different modules may use different APIs, support different kinds of devices, or present devices in different ways. Player positionsMAME uses a concept called player positions to help manage input assignments. The number of player positions supported depends on the I/O port field type:
The user can configure default input assignments per player position for supported I/O port field types which are saved in the file default.cfg. These assignments are used for all systems unless the device/system driver supplies its own default assignments, or the user configures system-specific input assignments. In order to facilitate development of reusable emulated devices with inputs, particularly slot devices, the I/O port manager automatically renumbers player positions when setting up the emulated system:
For a simple example, consider what happens when you run a Sega Mega Drive console with two game pads connected:
Updating I/O port fieldsThe I/O port manager updates I/O port fields once for each video frame produced by the first emulated screen in the system. How a field is updated depends on whether it is a digital or analog field. Updating digital fieldsUpdating digital I/O port fields is simple:
Updating absolute analog fieldsUpdating absolute analog I/O port fields is more complex due to the need to support a variety of control setups:
Note that the sensitivity setting value for absolute analog fields affects the response to relative axis input device items and increment/decrement inputs, but it does not affect the response to absolute axis input device items or the auto-centring speed. Updating relative analog fieldsRelative analog I/O port fields also need special handling to cater for multiple control setups, but they are a little simpler than absolute analog fields:
Note that the sensitivity setting value for relative analog fields affects the response to all user input. The device_memory_interface
1. CapabilitiesThe device memory interface provides devices with the capability of creating address spaces, to which address maps can be associated. It’s used for any device that provides a (logical) address/data bus that other devices can be connected to. That’s mainly, but not solely, CPUs. The interface allows for an unlimited set of address spaces, numbered with small, non-negative values. The IDs index vectors, so they should stay small to keep the lookup fast. Spaces numbered 0-3 have associated constant name:
Spaces 0 and 3, i.e. AS_PROGRAM and AS_OPCODES, are special for the debugger and some CPUs. AS_PROGRAM is use by the debugger and the CPUs as the space from which the CPU reads its instructions for the disassembler. When present, AS_OPCODES is used by the debugger and some CPUs to read the opcode part of the instruction. What opcode means is device-dependant, for instance for the Z80 it's the initial byte(s) which are read with the M1 signal asserted, while for the 68000 is means every instruction word plus PC-relative accesses. The main, but not only, use of AS_OPCODES is to implement hardware decryption of instructions separately from data. 2. Setupstd::vector<std::pair<int, const address_space_config *>> memory_space_config() const; The device must override that method to provide a vector of pairs comprising of a space number and an associated address_space_config describing its configuration. Some examples to look up when needed:
bool has_configured_map(int index = 0) const; The has_configured_map method allows to test whether an address_map has been associated with a given space in the memory_space_config method. That allows optional memory spaces to be implemented, such as AS_OPCODES in certain CPU cores. 3. Associating maps to spacesAssociating maps to spaces is done at the machine configuration level, after the device is instantiated. void set_addrmap(int spacenum, T &obj, Ret (U::*func)(Params...)); void set_addrmap(int spacenum, Ret (T::*func)(Params...)); void set_addrmap(int spacenum, address_map_constructor map); These function associate a map with a given space. Address maps associated with non-existent spaces are ignored (no warning given). The first form takes a reference to an object and a method to call on that object. The second form takes a method to call on the current device being configured. The third form takes an address_map_constructor to copy. In each case, the function must be callable with reference to an address_map object as an argument. To remove a previously configured address map, call set_addrmap with a default-constructed address_map_constructor (useful for removing a map for an optional space in a derived machine configuration). As an example, here’s the address map configuration for the main CPU in the Hana Yayoi and Hana Fubuki machines, with all distractions removed: class hnayayoi_state : public driver_device { public: 4. Accessing the spacesaddress_space &space(int index = 0) const; Returns the specified address space post-initialization. The specified address space must exist. bool has_space(int index = 0) const; Indicates whether a given space actually exists. 5. MMU support for disassemblerbool translate(int spacenum, int intention, offs_t &address, address_space *&target_space); Does a logical to physical address translation through the device's MMU. spacenum gives the space number, intention for the type of the future access (TR_(READ\|WRITE\|FETCH)), address is an in/out parameter holding the address to translate on entry and the translated version on return, and finally target_space is the actual space the access would end up in, which may be in a different device. Should return true if the translation went correctly, or false if the address is unmapped. The call must not change the state of the device. Note that for some historical reason, the device itself must override the virtual method memory_translate with the same signature. The device_rom_interface
1. CapabilitiesThis interface is designed for devices that expect to have a ROM connected to them on a dedicated bus. It’s mostly designed for sound chips. Other devices types may be interested but other considerations may make it impractical (graphics decode caching, for instance). The interface provides the capability to connect a ROM region, connect an address map, or dynamically set up a block of memory as ROM. In the region/memory block cases, banking is handled automatically. 2. Setupdevice_rom_interface<AddrWidth, DataWidth=0, AddrShift=0, Endian=ENDIANNESS_LITTLE> The interface is a template that takes the address width of the dedicated bus as a parameter. In addition the data bus width (if not byte), address shift (if non-zero) and Endianness (if not little Endian or byte-sized bus) can be provided. Data bus width is 0 for byte, 1 for word, etc. void set_map(map); Use that method at machine configuration time to provide an address map for the bus to connect to. It has priority over a ROM region if one is also present. void set_device_rom_tag(tag); Used to specify a ROM region to use if a device address map is not given. Defaults to DEVICE_SELF, i.e. the device’s tag. ROM_REGION(length, tag, flags) If a ROM region with the tag specified using set_device_rom_tag if present, or identical to the device tag otherwise, is provided in the ROM definitions for the system, it will be automatically picked up as the connected ROM. An address map has priority over the region if present in the machine configuration. void override_address_width(u8 width); This method allows the address bus width to be overridden. It must be called from within the device before config_complete time. void set_rom(const void *base, u32 size); At any time post-interface_pre_start, a memory block can be set up as the connected ROM with that method. It overrides any previous setup that may have been provided. It can be done multiple times. 3. ROM accessu8 read_byte(offs_t addr); u16 read_word(offs_t addr); u32 read_dword(offs_t addr); u64 read_qword(offs_t addr); These methods provide read access to the connected ROM. Out-of-bounds access results in standard unmapped read logerror messages. 4. ROM bankingIf the ROM region or the memory block in set_rom is larger than the address bus can access, banking is automatically set up. void set_rom_bank(int bank); That method selects the current bank number. 5. CaveatsUsing that interface makes the device derive from device_memory_interface. If the device wants to actually use the memory interface for itself, remember that space zero (0, or AS_PROGRAM) is used by the ROM interface, and don’t forget to call the base memory_space_config method. For devices which have outputs that can be used to address ROMs but only to forward the data to another device for processing, it may be helpful to disable the interface when it is not required. This can be done by overriding memory_space_config to return an empty vector. The device_disasm_interface and the disassemblers1. CapabilitiesThe disassemblers are classes that provide disassembly and opcode meta-information for the cpu cores and unidasm. The device_disasm_interface connects a cpu core with its disassembler. 2. The disassemblers2.1. DefinitionA disassembler is a class that derives from util::disasm_interface. It then has two required methods to implement, opcode_alignment and disassemble, and 6 optional, interface_flags, page_address_bits, pc_linear_to_real, pc_real_to_linear, and one with four possible variants, decrypt8/16/32/64. 2.2. opcode_alignmentu32 opcode_alignment() const Returns the required alignment of opcodes by the cpu, in PC-units. In other words, the required alignment for the PC register of the cpu. Tends to be 1 (almost everything), 2 (68000...), 4 (mips, ppc...), which an exceptional 8 (tms 32082 parallel processor) and 16 (tms32010, instructions are 16-bits aligned and the PC targets bits). It must be a power-of-two or things will break. Note that processors like the tms32031 which have 32-bits instructions but where the PC targets 32-bits values have an alignment of 1. 2.3. disassembleoffs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) This is the method where the real work is done. This method must disassemble the instruction at address pc and write the result to stream. The values to decode are retrieved from the opcode buffer. A data_buffer object offers four accessor methods: u8 util::disasm_interface::data_buffer::r8 (offs_t pc) const u16 util::disasm_interface::data_buffer::r16(offs_t pc) const u32 util::disasm_interface::data_buffer::r32(offs_t pc) const u64 util::disasm_interface::data_buffer::r64(offs_t pc) const They read the data at a given address and take endianness and nonlinear PCs for larger-than-bus-width accesses. The debugger variant also caches the read data in one block, so for that reason one should not read data too far from the base pc (e.g. stay within 16K or so, careful when trying to follow indirect accesses). A number of CPUs have an external signal that splits fetches into an opcode part and a parameter part. This is for instance the M1 signal of the z80 or the SYNC signal of the 6502. Some systems present different values to the cpu depending on whether that signal is active, usually for protection purposes. On these cpus the opcode part should be read from the opcode buffer, and the parameter part from the params buffer. They will or will not be the same buffer depending on the system itself. The method returns the size of the instruction in PC units, with a maximum of 65535. In addition, if possible, the disassembler should give some meta-information about the opcode by OR-ing in into the result:
In addition, to indicated that these flags are supported, OR the result with SUPPORTED. An annoying number of disassemblers lies about that support (e.g. they do a or with SUPPORTED without even generating the STEP_OVER or STEP_OUT information). Don't do that, it breaks the step over/step out functionality of the debugger. 2.4. interface_flagsu32 interface_flags() const That optional method indicates specifics of the disassembler. Default of zero is correct most of the time. Possible flags, which need to be OR-ed together, are:
Note that in practice non-linear pc systems are also paged, that PAGED2LEVEL implies PAGED, and that SPLIT_DECRYPTION implies DECRYPTION. 2.5. pc_linear_to_real and pc_real_to_linearoffs_t pc_linear_to_real(offs_t pc) const offs_t pc_real_to_linear(offs_t pc) const These methods should be present only when NONLINEAR_PC is set in the interface flags. They must convert pc to and from a value to a linear domain where the instruction parameters and next instruction are reached by incrementing the value. pc_real_to_linear converts to that domain, pc_linear_to_real converts back from that domain. 2.6. page_address_bitsu32 page_address_bits() const Present on when PAGED or PAGED2LEVEL is set, gives the number of address bits in the lowest page. 2.7. page2_address_bitsu32 page2_address_bits() const Present on when PAGED2LEVEL is set, gives the number of address bits in the upper page. 2.8. decryptnnu8 decrypt8 (u8 value, offs_t pc, bool opcode) const u16 decrypt16(u16 value, offs_t pc, bool opcode) const u32 decrypt32(u32 value, offs_t pc, bool opcode) const u64 decrypt64(u64 value, offs_t pc, bool opcode) const One of these must be defined when INTERNAL_DECRYPTION or SPLIT_DECRYPTION is set. The chosen one is the one which takes what opcode_alignment represents in bytes. That method decrypts a given value read from address pc (from AS_PROGRAM) and gives the result which will be passed to the disassembler. In the split decryption case, opcode indicates whether we're in the opcode (true) or parameter (false) part of the instruction. 3. Disassembler interface, device_disasm_interface3.1. DefinitionA CPU core derives from device_disasm_interface through cpu_device. One method has to be implemented, create_disassembler. 3.2. create_disassemblerutil::disasm_interface *create_disassembler() That method must return a pointer to a newly allocated disassembler object. The caller takes ownership and handles the lifetime. This method will be called at most one in the lifetime of the cpu object. 4. Disassembler configuration and communicationSome disassemblers need to be configured. Configuration can be unchanging (static) for the duration of the run (cpu model type for instance) or dynamic (state of a flag or a user preference). Static configuration can be done through either (a) parameter(s) to the disassembler constructor, or through deriving a main disassembler class. If the information is short and its semantics obvious (like a model name), feel free to use a parameter. Otherwise derive the class. Dynamic configuration must be done by first defining a nested public struct called config in the disassembler, with virtual destructor and pure virtual methods to pull the required information. A pointer to that struct should be passed to the disassembler constructor. The cpu core should then add a derivation from that config struct and implement the methods. Unidasm will have to derive a small class from the config class to give the information. 5. Missing stuffThere currently is no way for the debugger GUI to add per-core configuration. In particular, it is needed for the s2650 and Saturn cores. It should go through the cpu core class itself, since it's pulled from the config struct. There is support missing in unidasm for per-cpu configuration. That's needed for a lot of things, see the unidasm source code for the current list ("Configuration missing" comments). Emulated system memory and address spaces management
1. OverviewThe memory subsystem (emumem and addrmap) combines multiple functions useful for system emulation:
Devices create address spaces, e.g. decodable buses, through the device_memory_interface. The machine configuration sets up address maps to put in the address spaces, then the device can do read and writes through the bus. 2. Basic concepts2.1 Address spacesAn address space, implemented in the class address_space, represents an addressable bus with potentially multiple sub-devices connected requiring a decode. It has a number of data lines (8, 16, 32 or 64) called data width, a number of address lines (1 to 32) called address width and an Endianness. In addition an address shift allows for buses that have an atomic granularity different than a byte. Address space objects provide a series of methods for read and write access, and a second series of methods for dynamically changing the decode. 2.2 Address mapsAn address map is a static description of the decode expected when using a bus. It connects to memory, other devices and methods, and is installed, usually at startup, in an address space. That description is stored in an address_map structure which is filled programmatically. 2.3 Shares, banks and regionsMemory shares are allocated memory zones that can be put in multiple places in the same or different address spaces, and can also be directly accessed from devices. Memory banks are zones that indirect memory access, giving the possibility to dynamically and efficiently change where a zone actually points to. Memory regions are read-only memory zones in which ROMs are loaded. All of these have names allowing to access them. 2.4 ViewsViews are a way to multiplex different submaps over a memory range with fast switching. It is to be used when multiple devices map at the same addresses and are switched in externally. They must be created as an object of the device and then setup either statically in a memory map or dynamically through install_* calls. Switchable submaps, aka variants, are named through an integer. An internal indirection through a map ensures that any integer value can be used. 3. Memory objects3.1 Shares - memory_shareclass memory_share { A memory share is a named allocated memory zone that is automatically saved in save states and can be mapped in address spaces. It is the standard container for memory that is shared between spaces, but also shared between an emulated CPU and a driver. As such one has easy access to its contents from the driver class. required_shared_ptr<uNN> m_share_ptr; optional_shared_ptr<uNN> m_share_ptr; required_shared_ptr_array<uNN, count> m_share_ptr_array; optional_shared_ptr_array<uNN, count> m_share_ptr_array; [device constructor] m_share_ptr(*this, "name"), [device constructor] m_share_ptr_array(*this, "name%u", 0U), At the device level, a pointer to the memory zone can easily be retrieved by building one of these four finders. Note that like for every finder calling target() on the finder gives you the base pointer of the memory_share object. memory_share_creator<uNN> m_share; [device constructor] m_share(*this, "name", size, endianness), A memory share can be created if it doesn’t exist in a memory map through that creator class. If it already exists it is just retrieved. That class behaves like a pointer but also has the target(), length(), bytes(), endianness(), bitwidth() and bytewidth() methods for share information. The desired size is specified in bytes. memory_share *memshare(string tag) const; The memshare device method retrieves a memory share by name. Beware that the lookup can be expensive, prefer finders instead. 3.2 Banks - memory_bankclass memory_bank { A memory bank is a named memory zone indirection that can be mapped in address spaces. It points to nullptr when created. configure_entry associates an entry number and a base pointer. configure_entries does the same for multiple consecutive entries spanning a memory zone. set_base sets the base address for the active entry. If there are no entries, entry 0 (zero) is automatically created and selected. Use of set_base should be avoided in favour of pre-configured entries unless there are an impractically large number of possible base addresses. set_entry dynamically and efficiently selects the active entry, entry() returns the active entry number, and base() gets the associated base pointer. required_memory_bank m_bank; optional_memory_bank m_bank; required_memory_bank_array<count> m_bank_array; optional_memory_bank_array<count> m_bank_array; [device constructor] m_bank(*this, "name"), [device constructor] m_bank_array(*this, "name%u", 0U), At the device level, a pointer to the memory bank object can easily be retrieved by building one of these four finders. memory_bank_creator m_bank; [device constructor] m_bank(*this, "name"), A memory bank can be created if it doesn’t exist in a memory map through that creator class. If it already exists it is just retrieved. memory_bank *membank(string tag) const; The membank device method retrieves a memory bank by name. Beware that the lookup can be expensive, prefer finders instead. 3.3 Regions - memory_regionclass memory_region { A region is used to store read-only data like ROMs or the result of fixed decryptions. Their contents are not saved, which is why they should not being written to from the emulated system. They don’t really have an intrinsic width (base() returns an u8 * always), which is historical and pretty much unfixable at this point. The as_* methods allow for accessing them at a given width. required_memory_region m_region; optional_memory_region m_region; required_memory_region_array<count> m_region_array; optional_memory_region_array<count> m_region_array; [device constructor] m_region(*this, "name"), [device constructor] m_region_array(*this, "name%u", 0U), At the device level, a pointer to the memory region object can easily be retrieved by building one of these four finders. memory_region *memregion(string tag) const; The memregion device method retrieves a memory region by name. Beware that the lookup can be expensive, prefer finders instead. 3.4 Views - memory_viewclass memory_view { A view allows to switch part of a memory map between multiple possibilities, or even disable it entirely to see what was there before. It is created as an object of the device. memory_view m_view; [device constructor] m_view(*this, "name"), It is then setup through the address map API or dynamically. At runtime, a numbered variant can be selected using the select method, or the view can be disabled using the disable method. A disabled view can be re-enabled at any time. 3.5 Bus contention handlingSome specific CPUs have been upgraded to be interruptible which allows to add bus contention and wait states capabitilites. Being interruptible means, in practice, that an instruction can be interrupted at any time and the execute_run method of the core exited. Other devices can then run, then eventually controls returns to the core and the instruction continues from the point it was started. Importantly, this can be triggered from a handler and even be used to interrupt just before the access that is currently done (e.g. continuation will redo the access). The CPUs supporting that declare their capability by overriding the method cpu_is_interruptible to return true. Three intermediate contention handlers can be added to accesses:
For the delay handlers, a method or lambda is called which returns the number of cycles to wait (as a u32). The before_time is special. First, the time is compared to the current value of cpu->total_cycles(). That value is the number of cycles elapsed since the last reset of the cpu. It is passed as a parameter to the method as a u64 and must return the earliest time as a u64 when the access can be done, which can be equal to the passed-in time. From there two things can happen: either the running cpu has enough cycles left to consume to reach that time. In that case, the necessary number of cycles is consumed, and the access is done. Otherwise, when there isn't enough, the remaining cycles are consumed, the access aborted, scheduling happens, and eventually the access is redone. In that case the method is called again with the new current time, and must return the (probably same) earliest time again. This will happen until enough cycles to consume are available to directly do the access. This approach allows to for instance handle consecutive DMAs. A first DMA grabs the bus for a transfer. This shows up as the method answering for the earliest time for access the time of the end of the dma. If no timer happens until that time the access will then happen just after the dma finishes. But if a timer elapses before that and as a consequence another dma is queued while the first is running, the cycle will be aborted for lack of remaining time, and the method will eventually be called again. It will then give the time of when the second dma will finish, and all will be well. It can also allow to reduce said earlier time when circumstances require it. For instance a PIO latch that waits up to 64 cycles that data arrives can indicate that current time + 64 as a target (which will trigger a bus error for instance) but if a timer elapses and fills the latch meanwhile the method will be called again and that time can just return the current time to let the access pass though. Beware that if the timer elapsing did not fill the latch then the method must return the time it returned previously, e.g. the initial access time + 64, otherwise irrelevant timers happening or simply scheduling quantum effects will delay the timeout, possibly to infinity if the quantum is small enough. Contention handlers on the same address are taken into account in the before_time, before_delay then after_delay order. Contention handlers of the same type on the same address at last-one-wins. Installing any non-contention handler on a range where a contention handler was removes it. 4. Address maps API4.1 General API structureAn address map is a method of a device which fills an address_map structure, usually called map, passed by reference. The method then can set some global configuration through specific methods and then provide address range-oriented entries which indicate what should happen when a specific range is accessed. The general syntax for entries uses method chaining: map(start, end).handler(...).handler_qualifier(...).range_qualifier().contention(); The values start and end define the range, the handler() block determines how the access is handled, the handler_qualifier() block specifies some aspects of the handler (memory sharing for instance) and the range_qualifier() block refines the range (mirroring, masking, lane selection, etc.). The contention methods handle bus contention and wait states for cpus supporting them. The map follows a “last one wins” principle, where the handler specified last is selected when multiple handlers match a given address. 4.2 Global configurations4.2.1 Global maskingmap.global_mask(offs_t mask); Specifies a mask to be applied to all addresses when accessing the space that map is installed in. 4.2.2 Returned value on unmapped/nop-ed readmap.unmap_value_low(); map.unmap_value_high(); map.unmap_value(u8 value); Sets the value to return on reads to an unmapped or nopped-out address. Low means 0, high ~0. 4.3 Handler setting4.3.1 Method on the current device(...).r(FUNC(my_device::read_method)) (...).w(FUNC(my_device::write_method)) (...).rw(FUNC(my_device::read_method), FUNC(my_device::write_method)) uNN my_device::read_method(address_space &space, offs_t offset, uNN mem_mask) uNN my_device::read_method(address_space &space, offs_t offset) uNN my_device::read_method(address_space &space) uNN my_device::read_method(offs_t offset, uNN mem_mask) uNN my_device::read_method(offs_t offset) uNN my_device::read_method() void my_device::write_method(address_space &space, offs_t offset, uNN data, uNN mem_mask) void my_device::write_method(address_space &space, offs_t offset, uNN data) void my_device::write_method(address_space &space, uNN data) void my_device::write_method(offs_t offset, uNN data, uNN mem_mask) void my_device::write_method(offs_t offset, uNN data) void my_device::write_method(uNN data) Sets a method of the current device or driver to read, write or both for the current entry. The prototype of the method can take multiple forms making some elements optional. uNN represents u8, u16, u32 or u64 depending on the data width of the handler. The handler can be narrower than the bus itself (for instance an 8-bit device on a 32-bit bus). The offset passed in is built from the access address. It starts at zero at the start of the range, and increments for each uNN unit. An u8 handler will get an offset in bytes, an u32 one in double words. The mem_mask has its bits set where the accessors actually drive the bit. It’s usually built in byte units, but in some cases of I/O chips ports with per-bit direction registers the resolution can be at the bit level. 4.3.2 Method on a different device(...).r(m_other_device, FUNC(other_device::read_method)) (...).r("other-device-tag", FUNC(other_device::read_method)) (...).w(m_other_device, FUNC(other_device::write_method)) (...).w("other-device-tag", FUNC(other_device::write_method)) (...).rw(m_other_device, FUNC(other_device::read_method), FUNC(other_device::write_method)) (...).rw("other-device-tag", FUNC(other_device::read_method), FUNC(other_device::write_method)) Sets a method of another device, designated by an object finder (usually required_device or optional_device) or its tag, to read, write or both for the current entry. 4.3.3 Lambda function(...).lr{8,16,32,64}(NAME([...](address_space &space, offs_t offset, uNN mem_mask) -> uNN { ... })) (...).lr{8,16,32,64}([...](address_space &space, offs_t offset, uNN mem_mask) -> uNN { ... }, "name") (...).lw{8,16,32,64}(NAME([...](address_space &space, offs_t offset, uNN data, uNN mem_mask) -> void { ... })) (...).lw{8,16,32,64}([...](address_space &space, offs_t offset, uNN data, uNN mem_mask) -> void { ... }, "name") (...).lrw{8,16,32,64}(NAME(read), NAME(write)) (...).lrw{8,16,32,64}(read, "name_r", write, "name_w") Sets a lambda called on read, write or both. The lambda prototype can be any of the six available for methods. One can either use NAME() over the whole lambda, or provide a name after the lambda definition. The number is the data width of the access, e.g. the NN. 4.3.4 Direct memory access(...).rom() (...).writeonly() (...).ram() Selects the range to access a memory zone as read-only, write-only or read/write respectively. Specific handler qualifiers specify the location of this memory zone. There are two cases when no qualifier is acceptable:
(...).rom().region("name", offset) The region qualifier causes a read-only zone point to the contents of a given region at a given offset. (...).rom().share("name") (...).writeonly.share("name") (...).ram().share("name") The share qualifier causes the zone point to a shared memory region identified by its name. If the share is present in multiple spaces, the size, bus width, and, if the bus is more than byte-wide, the Endianness must match. 4.3.5 Bank access(...).bankr("name") (...).bankw("name") (...).bankrw("name") Sets the range to point at the contents of a memory bank in read, write or read/write mode. 4.3.6 Port access(...).portr("name") (...).portw("name") (...).portrw("name") Sets the range to point at an I/O port. 4.3.7 Dropped access(...).nopr() (...).nopw() (...).noprw() Sets the range to drop the access without logging. When reading, the unmap value is returned. 4.3.8 Unmapped access(...).unmapr() (...).unmapw() (...).unmaprw() Sets the range to drop the access with logging. When reading, the unmap value is returned. 4.3.9 Subdevice mapping(...).m(m_other_device, FUNC(other_device::map_method)) (...).m("other-device-tag", FUNC(other_device::map_method)) Includes a device-defined submap. The start of the range indicates where the address zero of the submap ends up, and the end of the range clips the submap if needed. Note that range qualifiers (defined later) apply. Currently, only handlers are allowed in submaps and not memory zones or banks. 4.4 Range qualifiers4.4.1 Mirroring(...).mirror(mask) Duplicate the range on the addresses reachable by setting any of the 1 bits present in mask. For instance, a range 0-0x1f with mirror 0x300 will be present on 0-0x1f, 0x100-0x11f, 0x200-0x21f and 0x300-0x31f. The addresses passed in to the handler stay in the 0-0x1f range, the mirror bits are not seen by the handler. 4.4.2 Masking(...).mask(mask) Only valid with handlers, the address will be masked with the mask before being passed to the handler. 4.4.3 Selection(...).select(mask) Only valid with handlers, the range will be mirrored as with mirror, but the mirror address bits are preserved in the offset passed to the handler when it is called. This is useful for devices like sound chips where the low bits of the address select a function and the high bits a voice number. 4.4.4 Sub-unit selection(...).umask16(16-bits mask) (...).umask32(32-bits mask) (...).umask64(64-bits mask) Only valid with handlers and submaps, selects which data lines of the bus are actually connected to the handler or the device. The mask value should be a multiple of a byte, e.g. the mask is a series of 00 and ff. The offset will be adjusted accordingly, so that a difference of 1 means the next handled unit in the access. If the mask is narrower than the bus width, the mask is replicated in the upper lines. 4.4.5 Chip select handling on sub-unit(...).cselect(16/32/64) When a device is connected to part of the bus, like a byte on a 16-bits bus, the target handler is only activated when that part is actually accessed. In some cases, very often byte access on a 68000 16-bits bus, the actual hardware only checks the word address and not if the correct byte is accessed. cswidth tells the memory system to trigger the handler if a wider part of the bus is accessed. The parameter is that trigger width (would be 16 in the 68000 case). 4.4.6 User flags(...).flags(16-bits mask) This parameter allows to set user-defined flags on the handler which can then be retrieved by an accessing device to change their behaviour. An example of use the i960 which marks burstable zones that way (they have a specific hardware-level support). 4.5 Contention(...).before_time(method).(...) (...).before_delay(method).(...) (...).after_delay(method).(...) These three methods allow to add the contention methods to a handler. See section 3.5. Multiple methods can be handler to one handler. 4.6 View setupmap(start, end).view(m_view); m_view[0](start1, end1).[...]; A view is setup in a address map with the view method. The only qualifier accepted is mirror. The “disabled” version of the view will include what was in the range prior to the view setup. The different variants are setup by indexing the view with the variant number and setting up an entry in the usual way. The entries within a variant must of course stay within the range. There are no other additional constraints. The contents of a variant, by default, are what was there before, i.e. the contents of the disabled view, and setting it up allows part or all of it to be overridden. Variants can only be setup once the view itself has been setup with the view method. A view can only be put in one address map and in only one position. If multiple views have identical or similar contents, remember that setting up a map is nothing more than a method call, and creating a second method to setup a view is perfectly reasonable. A view is of type memory_view and an indexed entry (e.g. a variant to setup) is of type memory_view::memory_view_entry &. A view can be installed in another view, but don’t forget that a view can be installed only once. A view can also be part of “what was there before”. 5. Address space dynamic mapping API5.1 General API structureA series of methods allow the bus decoding of an address space to be changed on-the-fly. They’re powerful but have some issues:
The methods, rather than decomposing the information in handler, handler qualifier and range qualifier, put them all together as method parameters. To make things a little more readable, lots of them are optional. 5.2 Handler mappinguNN my_device::read_method(address_space &space, offs_t offset, uNN mem_mask) uNN my_device::read_method_m(address_space &space, offs_t offset) uNN my_device::read_method_mo(address_space &space) uNN my_device::read_method_s(offs_t offset, uNN mem_mask) uNN my_device::read_method_sm(offs_t offset) uNN my_device::read_method_smo() void my_device::write_method(address_space &space, offs_t offset, uNN data, uNN mem_mask) void my_device::write_method_m(address_space &space, offs_t offset, uNN data) void my_device::write_method_mo(address_space &space, uNN data) void my_device::write_method_s(offs_t offset, uNN data, uNN mem_mask) void my_device::write_method_sm(offs_t offset, uNN data) void my_device::write_method_smo(uNN data) readNN_delegate (device, FUNC(read_method)) readNNm_delegate (device, FUNC(read_method_m)) readNNmo_delegate (device, FUNC(read_method_mo)) readNNs_delegate (device, FUNC(read_method_s)) readNNsm_delegate (device, FUNC(read_method_sm)) readNNsmo_delegate(device, FUNC(read_method_smo)) writeNN_delegate (device, FUNC(write_method)) writeNNm_delegate (device, FUNC(write_method_m)) writeNNmo_delegate (device, FUNC(write_method_mo)) writeNNs_delegate (device, FUNC(write_method_s)) writeNNsm_delegate (device, FUNC(write_method_sm)) writeNNsmo_delegate(device, FUNC(write_method_smo)) To be added to a map, a method call and the device it is called onto have to be wrapped in the appropriate delegate type. There are twelve types, for read and for write and for all six possible prototypes. Note that as all delegates, they can also wrap lambdas. space.install_read_handler(addrstart, addrend, read_delegate, unitmask, cswidth, flags) space.install_read_handler(addrstart, addrend, addrmask, addrmirror, addrselect, read_delegate, unitmask, cswidth, flags) space.install_write_handler(addrstart, addrend, write_delegate, unitmask, cswidth, flags) space.install_write_handler(addrstart, addrend, addrmask, addrmirror, addrselect, write_delegate, unitmask, cswidth, flags) space.install_readwrite_handler(addrstart, addrend, read_delegate, write_delegate, unitmask, cswidth, flags) space.install_readwrite_handler(addrstart, addrend, addrmask, addrmirror, addrselect, read_delegate, write_delegate, unitmask, cswidth, flags) These six methods allow to install delegate-wrapped handlers in a live address space. Either plain or with mask, mirror and select. In the read/write case both delegates must be of the same flavor (smo stuff) to avoid a combinatorial explosion of method types. The unitmask, cswidth and flags arguments are optional. 5.3 Direct memory range mappingspace.install_rom(addrstart, addrend, void *pointer) space.install_rom(addrstart, addrend, addrmirror, void *pointer) space.install_rom(addrstart, addrend, addrmirror, flags, void *pointer) space.install_writeonly(addrstart, addrend, void *pointer) space.install_writeonly(addrstart, addrend, addrmirror, void *pointer) space.install_writeonly(addrstart, addrend, addrmirror, flags, void *pointer) space.install_ram(addrstart, addrend, void *pointer) space.install_ram(addrstart, addrend, addrmirror, void *pointer) space.install_ram(addrstart, addrend, addrmirror, flags, void *pointer) Installs a memory block in an address space, with or without mirror and flags. _rom is read-only, _ram is read/write, _writeonly is write-only. The pointer must be non-null, this method will not allocate the memory. 5.4 Bank mappingspace.install_read_bank(addrstart, addrend, memory_bank *bank) space.install_read_bank(addrstart, addrend, addrmirror, memory_bank *bank) space.install_read_bank(addrstart, addrend, addrmirror, flags, memory_bank *bank) space.install_write_bank(addrstart, addrend, memory_bank *bank) space.install_write_bank(addrstart, addrend, addrmirror, memory_bank *bank) space.install_write_bank(addrstart, addrend, addrmirror, flags, memory_bank *bank) space.install_readwrite_bank(addrstart, addrend, memory_bank *bank) space.install_readwrite_bank(addrstart, addrend, addrmirror, memory_bank *bank) space.install_readwrite_bank(addrstart, addrend, addrmirror, flags, memory_bank *bank) Install an existing memory bank for reading, writing or both in an address space. 5.5 Port mappingspace.install_read_port(addrstart, addrend, const char *rtag) space.install_read_port(addrstart, addrend, addrmirror, const char *rtag) space.install_read_port(addrstart, addrend, addrmirror, flags, const char *rtag) space.install_write_port(addrstart, addrend, const char *wtag) space.install_write_port(addrstart, addrend, addrmirror, const char *wtag) space.install_write_port(addrstart, addrend, addrmirror, flags, const char *wtag) space.install_readwrite_port(addrstart, addrend, const char *rtag, const char *wtag) space.install_readwrite_port(addrstart, addrend, addrmirror, const char *rtag, const char *wtag) space.install_readwrite_port(addrstart, addrend, addrmirror, flags, const char *rtag, const char *wtag) Install ports by name for reading, writing or both. 5.6 Dropped accessesspace.nop_read(addrstart, addrend, addrmirror, flags) space.nop_write(addrstart, addrend, addrmirror, flags) space.nop_readwrite(addrstart, addrend, addrmirror, flags) Drops the accesses for a given range with an optional mirror and flags; 5.7 Unmapped accessesspace.unmap_read(addrstart, addrend, addrmirror, flags) space.unmap_write(addrstart, addrend, addrmirror, flags) space.unmap_readwrite(addrstart, addrend, addrmirror, flags) Unmaps the accesses (e.g. logs the access as unmapped) for a given range with an optional mirror and flags. 5.8 Device map installationspace.install_device(addrstart, addrend, device, map, unitmask, cswidth, flags) Install a device address with an address map in a space. The unitmask, cswidth and flags arguments are optional. 5.9 Contentionusing ws_time_delegate = device_delegate<u64 (offs_t, u64)>; using ws_delay_delegate = device_delegate<u32 (offs_t)>; space.install_read_before_time(addrstart, addrend, addrmirror, ws_time_delegate) space.install_write_before_time(addrstart, addrend, addrmirror, ws_time_delegate) space.install_readwrite_before_time(addrstart, addrend, addrmirror, ws_time_delegate) space.install_read_before_delay(addrstart, addrend, addrmirror, ws_delay_delegate) space.install_write_before_delay(addrstart, addrend, addrmirror, ws_delay_delegate) space.install_readwrite_before_delay(addrstart, addrend, addrmirror, ws_delay_delegate) space.install_read_after_delay(addrstart, addrend, addrmirror, ws_delay_delegate) space.install_write_after_delay(addrstart, addrend, addrmirror, ws_delay_delegate) space.install_readwrite_after_delay(addrstart, addrend, addrmirror, ws_delay_delegate) Install a contention handler in the decode path. The addrmirror parameter is optional. 5.10 View installationspace.install_view(addrstart, addrend, view) space.install_view(addrstart, addrend, addrmirror, view) view[0].install... Installs a view in a space. This can be only done once and in only one space, and the view must not have been setup through the address map API before. Once the view is installed, variants can be selected by indexing to call a dynamic mapping method on it. A view can be installed into a variant of another view without issues, with only the usual constraint of single installation. 5.11 Tapsusing tap = std::function<void (offs_t offset, uNN &data, uNN mem_mask) memory_passthrough_handler mph = space.install_read_tap(addrstart, addrend, name, read_tap, &mph); memory_passthrough_handler mph = space.install_write_tap(addrstart, addrend, name, write_tap, &mph); memory_passthrough_handler mph = space.install_readwrite_tap(addrstart, addrend, name, read_tap, write_tap, &mph); mph.remove(); A tap is a method that is be called when a specific range of addresses is accessed without overriding the actual access. Taps can change the data passed around. A write tap happens before the access, and can change the value to be written. A read tap happens after the access, and can change the value returned. Taps must be of the same width and alignement than the bus. Multiple taps can act over the same addresses. The memory_passthrough_handler object collates a number of taps and allow to remove them all in one call. The mph parameter is optional and a new one will be created if absent. Taps are lost when a new handler is installed at the same addresses (under the usual principle of last one wins). If they need to be preserved, one should install a change notifier on the address space, and remove + reinstall the taps when notified. CPU devices
1. OverviewCPU devices derivatives are used, unsurprisingly, to implement the emulation of CPUs, MCUs and SOCs. A CPU device is first a combination of device_execute_interface, device_memory_interface, device_state_interface and device_disasm_interface. Refer to the associated documentations when they exist. Two more functionalities are specific to CPU devices which are the DRC and the interruptibility support. 2. DRCTODO. 3. Interruptibility3.1 DefinitionAn interruptible CPU is defined as a core which is able to suspend the execution of one instruction at any time, exit execute_run, then at the next call of execute_run keep going from where it was. This includes being able to abort an issued memory access, quit execute_run, then upon the next call of execute_run reissue the exact same access. 3.2 Implementation requirementsMemory accesses must be done with read_interruptible or write_interruptible on a memory_access_specific or a memory_access_cache. The access must be done as bus width and bus alignment. After each access the core must test whether icount <= 0. This test should be done after icount is decremented of the time taken by the access itself, to limit the number of tests. When icount reaches 0 or less it means that the instruction emulation needs to be suspended. To know whether the access needs to be re-issued, access_to_be_redone() needs to be called. If it returns true then the time taken by the access needs to be credited back, since it hasn't yet happened, and the access will need to be re-issued. The call to access_to_be_redone() clears the reissue flag. If you need to check the flag without clearing it use access_to_be_redone_noclear(). The core needs to do enough bookkeeping to eventually restart the instruction execution just before the access or just after the test, depending on the need of reissue. Finally, to indicate to the rest of the infrastructure the support, it must override cpu_is_interruptible() to return true. 3.3 Example implementation with generatorsTo ensure decent performance, the current implementations (h8, 6502 and 68000) use a python generator to generate two versions of each instruction interpreter, one for the normal emulation, and one for restarting the instruction. The restarted version looks like that (for a 4-cycles per access cpu): void device::execute_inst_restarted() { The non-restarted version is the same thing with the switch and the final m_inst_substate clearing removed. void device::execute_inst_non_restarted() { The main loop then looks like this: void device::execute_run() { The idea is thus that m_inst_substate indicates where in an instruction one is, but only when an interruption happens. It otherwise stays at 0 and is essentially never looked at. Having two versions of the interpretation allows to remove the overhead of the switch and the end-of-instruction substate clearing. It is not a requirement to use a generator-based that method, but a different one which does not have unacceptable performance implications has not yet been found. 3.4 Bus contention cpu_device interfaceThe main way to setup bus contention is through the memory maps. Lower-level access can be obtained through some methods on cpu_device though. bool cpu_device::access_before_time(u64 access_time, u64 current_time) noexcept; The method access_before_time allows to try to run an access at a given time in cpu cycles. It takes the current time (total_cycles()) and the expected time for the access. If there aren't enough cycles to reach that time the remaining cycles are eaten and the method returns true to tell not to do the access and call the method again eventually. Otherwise enough cycles are eaten to reach the access time and false is returned to tell to do the access. bool cpu_device::access_before_delay(u32 cycles, const void *tag) noexcept; The method access_before_delay allows to try to run an access after a given delay. The tag is an opaque, non-nullptr value used to characterize the source of the delay, so that the delay is not applied multiple times. Similarly to the previous method cycles are eaten and true is returned to abort the access, false to execute it. void cpu_device::access_after_delay(u32 cycles) noexcept; The method access_after_delay allows to add a delay after an access is done. There is no abort possible, hence no return boolean. void cpu_device::defer_access() noexcept; The method defer_access tells the cpu that we need to wait for an external event. It marks the access as to be redone, and eats all the remaining cycles of the timeslice. The idea is then that the access will be retried after time advances up to the next global system synchronisation event (sync, timer timeout or set_input_line). This is the method to use when for instance waiting on a magic latch for data expected from scsi transfers, which happen on timer timeouts. void cpu_device::retry_access() noexcept; The method retry_access tells the cpu that the access will need to be retried, and nothing else. This can easily reach a situation of livelock, so be careful. It is used for instance to simulate a wait line (for the z80 for instance) which is controlled through set_input_line. The idea is that the device setting wait does the set_input_line and a retry_access. The cpu core, as long as the wait line is set just eats cycles. Then, when the line is cleared the core will retry the access. 3.5 Interaction with DRCAt this point, interruptibility and DRC are entirely incompatible. We do not have a method to quit the generated code before or after an access. It's theorically possible but definitely non-trivial. The new floppy subsystem1. IntroductionThe new floppy subsystem aims at emulating the behaviour of floppies and floppy controllers at a level low enough that protections work as a matter of course. It reaches its goal by following the real hardware configuration:
2. Floppy storage 1012.1. Floppy diskA floppy disk is a disc that stores magnetic orientations on their surface disposed in a series on concentric circles called tracks or cylinders [1]. Its main characteristics are its size (goes from a diameter of around 2.8" to 8") , its number of writable sides (1 or 2) and its magnetic resistivity. The magnetic resistivity indicates how close magnetic orientation changes can happen and the information kept. That's one third of what defines the term "density" that is so often used for floppies (the other two are floppy drive head size and bit-level encoding). The magnetic orientations are always binary, e.g. they're one way or the opposite, there's no intermediate state. Their direction can either be tangentially to the track, i.e. in the direction of or opposite to the rotation, or in the case of perpendicular recording the direction is perpendicular to the disc surface (hence the name). Perpendicular recording allows for closer orientation changes by writing the magnetic information more deeply, but arrived late in the technology lifetime. 2.88Mb disks and the floppy children (Zip drives, etc.) used perpendicular recording. For simulation purposes the direction is not important, only the fact that only two orientations are possible is. Two more states are possible though: a portion of a track can be demagnetized (no orientation) or damaged (no orientation and can't be written to). A specific position in the disk rotation triggers an index pulse. That position can be detected through a hole in the surface (very visible in 5.25" and 3" floppies for instance) or through a specific position of the rotating center (3.5" floppies, perhaps others). This index pulse is used to designate the beginning of the track, but is not used by every system. Older 8" floppies have multiple index holes used to mark the beginning of sectors (called hard sectoring) but one of them is positioned differently to be recognized as the track start, and the others are at fixed positions relative to the origin one. 2.2. Floppy driveA floppy drive is what reads and writes a floppy disk. It includes an assembly capable of rotating the disk at a fixed speed and one or two magnetic heads tied to a positioning motor to access the tracks. The head width and positioning motor step size decides how many tracks are written on the floppy. Total number of tracks goes from 32 to 84 depending on the floppy and drive, with the track 0 being the most exterior (longer) one of the concentric circles, and the highest numbered the smallest interior circle. As a result the tracks with the lowest numbers have the lowest physical magnetic orientation density, hence the best reliability. Which is why important and/or often changed structures like the boot block or the fat allocation table are at track 0. That is also where the terminology "stepping in" to increase the track number and "stepping out" to decrease it comes from. The number of tracks available is the second part of what is usually behind the term "density". A sensor detects when the head is on track 0 and the controller is not supposed to try to go past it. In addition physical blocks prevent the head from going out of the correct track range. Some systems (Apple II, some C64) do not take the track 0 sensor into account and just wham the head against the track 0 physical block, giving a well-known crash noise and eventually damaging the head alignment. Also, some systems (Apple II and C64 again) have direct access to the phases of the head positioning motor, allowing to trick the head into going between tracks, in middle or even quarter positions. That was not usable to write more tracks, since the head width did not change, but since reliable reading was only possible with the correct position it was used for some copy protection systems. The disk rotates at a fixed speed for a given track. The most usual speed is 300 rpm for every track, with 360 rpm found for HD 5.25" floppies and most 8" ones, and a number of different values like 90 rpm for the earlier floppies or 150 rpm for an HD floppy in an Amiga. Having a fixed rotational speed for the whole disk is called Constant Angular Velocity (CAV, almost everybody) or Zoned Constant Angular Velocity (ZCAV, C64) depending on whether the read/write bitrate is constant or track-dependant. Some systems (Apple II, Mac) vary the rotational speed depending on the track (something like 394 rpm up to 590 rpm) to end up with a Constant Linear Velocity (CLV). The idea behind ZCAV/CLV is to get more bits out of the media by keeping the minimal spacing between magnetic orientation transitions close to the best the support can do. It seems that the complexity was not deemed worth it since almost no system does it. Finally, after the disc rotates and the head is over the proper track reading happens. The reading is done through an inductive head, which gives it the interesting characteristic of not reading the magnetic orientation directly but instead of being sensitive to orientation inversions, called flux transitions. This detection is weak and somewhat uncalibrated, so an amplifier with Automatic Gain Calibration (AGC) and a peak detector are put behind the head to deliver clean pulses. The AGC slowly increases the amplification level until a signal goes over the threshold, then modulates its gain so that said signal is at a fixed position over the threshold. Afterwards the increase happens again. This makes the amplifier calibrate itself to the signals read from the floppy as long as flux transitions happen often enough. Too long and the amplification level will reach a point where the random noise the head picks from the environment is amplified over the threshold, creating a pulse where none should be. Too long in our case happens to be around 16-20us with no transitions. That means a long enough zone with a fixed magnetic orientation or no orientation at all (demagnetized or damaged) is going to be read as a series of random pulses after a brief delay. This is used by protections and is known as "weak bits", which read differently each time they're accessed. A second level of filtering happens after the peak detector. When two transitions are a little close (but still over the media threshold) a bouncing effect happens between them giving two very close pulses in the middle in addition to the two normal pulses. The floppy drive detects when pulses are too close and filter them out, leaving the normal ones. As a result, if one writes a train of high-frequency pulses to the floppy they will be read back as a train of too close pulses (weak because they're over the media tolerance, but picked up by the AGC anyway, only somewhat unreliably) they will be all filtered out, giving a large amount of time without any pulse in the output signal. This is used by some protections since it's not writable with a normally clocked controller. Writing is symmetrical, with a series of pulses sent which make the write head invert the magnetic field orientation each time a pulse is received. So, in conclusion, the floppy drive provides inputs to control disk rotation and head position (and choice when double-sided), and the data goes both way as a train of pulses representing magnetic orientation inversions. The absolute value of the orientation itself is never known. 2.3. Floppy controllerThe task of the floppy controller is to turn the signals to/from the floppy drive into something the main CPU can digest. The level of support actually done by the controller is extremely variable from one device to the other, from pretty much nothing (Apple II, C64) through minimal (Amiga) to complete (Western Digital chips, uPD765 family). Usual functions include drive selection, motor control, track seeking and of course reading and writing data. Of these only the last two need to be described, the rest is obvious. The data is structured at two levels: how individual bits (or nibbles, or bytes) are encoded on the surface, and how these are grouped in individually-addressable sectors. Two standards exist for these, called FM and MFM, and in addition a number of systems use their home-grown variants. Moreover, some systems such as the Amiga use a standard bit-level encoding (MFM) but a homegrown sector-level organisation. 2.3.1. Bit-level encodings2.3.1.1. Cell organizationAll floppy controllers, even the wonkiest like the Apple II one, start by dividing the track in equally-sized cells. They're angular sections in the middle of which a magnetic orientation inversion may be present. From a hardware point of view the cells are seen as durations, which combined with the floppy rotation give the section. For instance the standard MFM cell size for a 3" double-density floppy is 2us, which combined with the also standard 300 rpm rotational speed gives an angular size of 1/100000th of a turn. Another way of saying it is that there are 100K cells in a 3" DD track. In every cell there may or may not be a magnetic orientation transition, e.g. a pulse coming from (reading) or going to (writing) the floppy drive. A cell with a pulse is traditionally noted '1', and one without '0'. Two constraints apply to the cell contents though. First, pulses must not be too close together or they'll blur each-other and/or be filtered out. The limit is slightly better than 1/50000th of a turn for single and double density floppies, half that for HD floppys, and half that again for ED floppies with perpendicular recording. Second, they must not be too away from each other or either the AGC is going to get wonky and introduce phantom pulses or the controller is going to lose sync and get a wrong timing on the cells on reading. Conservative rule of thumb is not to have more than three consecutive '0' cells. Of course protections play with that to make formats not reproducible by the system controller, either breaking the three-zeroes rule or playing with the cells durations/sizes. Bit encoding is then the art of transforming raw data into a cell 0/1 configuration that respects the two constraints. 2.3.1.2. FM encodingThe very first encoding method developed for floppies is called Frequency Modulation, or FM. The cell size is set at slightly over the physical limit, e.g. 4us. That means it is possible to reliably have consecutive '1' cells. Each bit is encoded on two cells:
Since every other cell at least is '1' there is no risk of going over three zeroes. The name Frequency Modulation simply derives from the fact that a 0 is encoded with one period of a 125Khz pulse train while a 1 is two periods of a 250Khz pulse train. 2.3.1.3. MFM encodingThe FM encoding has been superseded by the Modified Frequency Modulation encoding, which can cram exactly twice as much data on the same surface, hence its other name of "double density". The cell size is set at slightly over half the physical limit, e.g. 2us usually. The constraint means that two '1' cells must be separated by at least one '0' cell. Each bit is once again encoded on two cells:
The minimum space rule is respected since a '1' clock bit is by definition surrounded by two '0' data bits, and a '1' data bit is surrounded by two '0' clock bits. The longest '0'-cell string possible is when encoding 101 which gives x10001, respecting the maximum of three zeroes. 2.3.1.4. GCR encodingsGroup Coded Recording, or GCR, encodings are a class of encodings where strings of bits at least nibble-size are encoded into a given cell stream given by a table. It has been used in particular by the Apple II, the Mac and the C64, and each system has its own table, or tables. 2.3.1.5. Other encodingsOther encodings exist, like M2FM, but they're very rare and system-specific. 2.3.1.6. Reading back encoded dataWriting encoded data is easy: you only need a clock at the appropriate frequency and send or not a pulse on the clock edges. Reading back the data is where the fun is. Cells are a logical construct and not a physical measurable entity. Rotational speeds very around the defined one (±2% is not rare), and local perturbations (air turbulence, surface distance…) make the instantaneous speed very variable in general. So to extract the cell values stream, the controller must dynamically synchronize with the pulse train that the floppy head picks up. The principle is simple: a cell-sized duration window is built within which the presence of at least one pulse indicates the cell is a '1', and the absence of any a '0'. After reaching the end of the window, the starting time is moved appropriately to try to keep the observed pulse at the exact middle of the window. This allows the phase to be corrected on every '1' cell, making the synchronization work if the rotational speed is not too off. Subsequent generations of controllers used Phase-Locked Loops (PLLs) which vary both phase and window duration to adapt better to inaccuarate rotational speeds, usually with a tolerance of ±15%. Once the cell data stream is extracted, decoding depends on the encoding. In the FM and MFM case the only question is to recognize data bits from clock bits, while in GCR the start position of the first group should be found. That second level of synchronization is handled at a higher level using patterns not found in a normal stream. 2.3.2. Sector-level organizationFloppies have been designed for read/write random access to reasonably sized blocks of data. Track selection allows for a first level of random access and sizing, but the ~6K of a double density track would be too big a block to handle. 256/512 bytes are considered a more appropriate value. To that end data on a track is organized as a series of (sector header, sector data) pairs where the sector header indicates important information like the sector number and size, and the sector data contains the data. Sectors have to be broken in two parts because while reading is easy, read the header then read the data if you want it, writing requires reading the header to find the correct place then once that is done switching on the writing head for the data. Starting writing is not instantaneous and will not be perfectly phase-aligned with the read header, so space for synchronization is required between header and data. In addition somewhere in the sector header and in the sector data are pretty much always added some kind of checksum allowing to know whether the data was damaged or not. FM and MFM have (not always used) standard sector layout methods. 2.3.2.1. FM sector layoutThe standard "PC" track/sector layout for FM is as such:
Then for each sector: - 6 FM-encoded 0x00 (giving a steady 125KHz pulse train)
The track is finished with a stream of '1' cells. The 125KHz pulse trains are used to lock the PLL to the signal correctly. The specific 16-cells streams allow to distinguish between clock and data bits by providing a pattern that is not supposed to happen in normal FM-encoded data. In the sector header track numbers start at 0, heads are 0/1 depending on the size, sector numbers usually start at 1 and size code is 0 for 128 bytes, 1 for 256, 2 for 512, etc. The CRC is a cyclic redundancy check of the data bits starting with the mark just after the pulse train using polynom 0x11021. The Western Digital-based controllers usually get rid of everything but some 0xff before the first sector and allow a better use of space as a result. 2.3.2.2. MFM sector layoutThe standard "PC" track/sector layout for MFM is as such:
Then for each sector:
The track is finished with a stream of MFM-encoded 0x4e. The 250KHz pulse trains are used to lock the PLL to the signal correctly. The cell pattern 4489 does not appear in normal MFM-encoded data and is used for clock/data separation. As for FM, the Western Digital-based controllers usually get rid of everything but some 0x4e before the first sector and allow a better use of space as a result. 2.3.2.3. Formatting and write splicesTo be usable, a floppy must have the sector headers and default sector data written on every track before using it. The controller starts writing at a given place, often the index pulse but on some systems whenever the command is sent, and writes until a complete turn is done. That's called formatting the floppy. At the point where the writing stops there is a synchronization loss since there is no chance the cell stream clock warps around perfectly. This brutal phase change is called a write splice, specifically the track write splice. It is the point where writing should start if one wants to raw copy the track to a new floppy. Similarly two write splices are created when a sector is written at the start and end of the data block part. They're not supposed to happen on a mastered disk though, even if there are some rare exceptions. 3. The new implementation3.1. Floppy disk representationThe floppy disk contents are represented by the class floppy_image. It contains information of the media type and a representation of the magnetic state of the surface. The media type is divided in two parts. The first half indicates the physical form factor, i.e. all medias with that form factor can be physically inserted in a reader that handles it. The second half indicates the variants which are usually detectable by the reader, such as density and number of sides. Track data consists of a series of 32-bits lsb-first values representing magnetic cells. Bits 0-27 indicate the absolute position of the start of the cell (not the size), and bits 28-31 the type. Type can be:
The position is in angular units of 1/200,000,000th of a turn. It corresponds to one nanosecond when the drive rotates at 300 rpm. The last cell implicit end position is of course 200,000,000. Unformatted tracks are encoded as zero-size. The "track splice" information indicates where to start writing if you try to rewrite a physical disk with the data. Some preservation formats encode that information, it is guessed for others. The write track function of fdcs should set it. The representation is the angular position relative to the index. 3.2. Converting to and from the internal representation3.2.1. Class and interfaceWe need to be able to convert on-disk formats of the floppy data to and from the internal representation. This is done through classes derived from floppy_image_format_t. The interface to be implemented includes: - name() gives the short name of the on-disk format
All of these methods are supposed to be stateless. 3.2.2. Conversion helper methodsA number of methods are provided to simplify writing the converter classes. 3.2.2.1. Load-oriented conversion methodsgenerate_track_from_bitstream(track number, Takes a stream of cell types (0/1), MSB-first, converts
it to the internal format and stores it at the given track and head in the
given image.
generate_track_from_levels(track number, Takes a variant of the internal format where each value
represents a cell, the position part of the values is the size of the cell and
the level part is MG_0, MG_1 for normal cell types, MG_N, MG_D for
unformatted/damaged cells, and MG_W for Dungeon-Master style weak bits.
Converts it into the internal format. The sizes are normalized so that they
total to a full turn.
normalize_times(UINT32 *levels, Takes an internal-format buffer where the position part
represents angle until the next change and turns it into a normal positional
stream, first ensuring that the total size is normalized to a full turn.
3.2.2.2. Save-oriented conversion methodsgenerate_bitstream_from_track(track number, Extract a cell 0/1 stream from the internal format using
a PLL setup with an initial cell size set to 'base cell size' and a +/- 25%
tolerance.
struct desc_xs { int track, head, size; const UINT8 *data } extract_sectors_from_bitstream_mfm_pc(...) extract_sectors_from_bitstream_fm_pc(const UINT8 *cell stream, Extract standard mfm or fm sectors from a regenerated
cell stream. Sectors must point to an array of 256 desc_xs.
An existing sector is recognizable by having ->data non-null. Sector data is written in sectdata up to sectdata_size bytes. get_geometry_mfm_pc(...) get_geometry_fm_pc(floppy image, Extract the geometry (heads, tracks, sectors) from a
pc-ish floppy image by checking track 20.
get_track_data_mfm_pc(...) get_track_data_fm_pc(track number, Extract what you'd get by reading in order 'sector
size'-sized sectors from number 1 to sector count and put the result in sector
data.
3.3. Floppy driveThe class floppy_image_interface simulates the floppy
drive. That includes a number of control signals, reading, and writing.
Control signal changes must be synchronized, e.g. fired off a timer to ensure
the current time is the same for all devices.
3.3.1. Control signalsDue to the way they're usually connected to CPUs (e.g.
directly on an I/O port), the control signals work with physical instead of
logical values. Which means than in general 0 means active, 1 means inactive.
Some signals also have a callback associated called when they change.
mon_w(state) / mon_r() Motor on signal, rotates on 0.
idx_r() / setup_index_pulse_cb(cb) Index signal, goes 0 at start of track for about 2ms.
Callback is synchronized. Only happens when a disk is in and the motor is
running.
ready_r() / setup_ready_cb(cb) Ready signal, goes to 1 when the disk is removed or the
motor stopped. Goes to 0 after two index pulses.
wpt_r() / setup_wpt_cb(cb) Write protect signal (1 = readonly). Callback is
unsynchronized.
dskchg_r() Disk change signal, goes to 1 when a disk is change, goes
to 0 on track change.
dir_w(dir) Selects track stepping direction (1 = out = decrease
track number).
stp_w(state) Step signal, moves by one track on 1->0
transition.
trk00_r() Track 0 sensor, returns 0 when on track 0.
ss_w(ss) / ss_r() Side select
3.3.2. Read/write interfaceThe read/write interface is designed to work asynchronously, e.g. somewhat independently of the current time.
The new SCSI subsystemIntroductionThe nscsi subsystem was created to allow an implementation to be closer to the physical reality, making it easier (hopefully) to implement new controller chips from the documentations. Global structureParallel SCSI is built around a symmetric bus to which a number of devices are connected. The bus is composed of 9 control lines (for now, later SCSI versions may have more) and up to 32 data lines (but currently implemented chips only handle 8). All the lines are open collector, which means that either one or multiple chip connect the line to ground and the line, of course, goes to ground, or no chip drives anything and the line stays at Vcc. Also, the bus uses inverted logic, where ground means 1. SCSI chips traditionally work in logical and not physical levels, so the nscsi subsystem also works in logical levels and does a logical-or of all the outputs of the devices. Structurally, the implementation is done around two main classes: nscsi_bus_devices represents the bus, and nscsi_device represents an individual device. A device only communicate with the bus, and the bus takes care of transparently handling the device discovery and communication. In addition the nscsi_full_device class proposes a SCSI device with the SCSI protocol implemented making building generic SCSI devices like hard drives or CD-ROM readers easier. Plugging in a SCSI bus in a driverThe nscsi subsystem leverages the slot interfaces and the device naming to allow for a configurable yet simple bus implementation. First you need to create a list of acceptable devices to plug on the bus. This usually comprises of cdrom, harddisk and the controller chip. For instance: static SLOT_INTERFACE_START( next_scsi_devices ) The _INTERNAL interface indicates a device that is not user-selectable, which is useful for the controller. Then in the machine config (or in a fragment config) you need to first add the bus, and then the (potential) devices as sub-devices of the bus with the SCSI ID as the name. For instance you can use:
That configuration puts as default a CD-ROM reader on SCSI ID 0 and a hard drive on SCSI ID 1, and forces the controller on ID 7. The parameters of add are:
The full device name, for mapping purposes, will be bus-tag:scsi-id:device-type, i.e. "scsibus:7:ncr5390" for our controller here. Creating a new SCSI device using nscsi_deviceThe base class "nscsi_device" is to be used for down-to-the-metal devices, i.e. SCSI controller chips. The class provides three variables and one method. The first variable, scsi_bus, is a pointer to the nscsi_bus_device. The second, scsi_refid, is an opaque reference to pass to the bus on some operations. Finally, scsi_id gives the SCSI ID as per the device tag. It's written once at startup and never written or read afterwards, the device can do whatever it wants with the value or the variable. The virtual method scsi_ctrl_changed is called when watched-for control lines change. Which lines are watched is defined through the bus. The bus proposes five methods to access the lines. The read methods are ctrl_r() and data_r(). The meaning of the control bits are defined in the S_* enum of nscsi_device. The bottom three bits (INP, CTL and MSG) are setup so that masking with 7 (S_PHASE_MASK) gives the traditional numbers for the phases, which are also available with the S_PHASE_* enum. Writing the data lines is done with data_w(scsi_refid, value). Writing the control lines is done with ctrl_w(scsi_refid, value, mask-of-lines-to-change). To change all control lines in one call use S_ALL as the mask. Of course, what is read is the logical-or of all of what is driven by all devices. Finally, the method ctrl_wait_w(scsi_id, value, mask-of-wait-lines-to-change) allows to select which control lines are watched. The watch mask is per-device, and the device method scsi_ctrl_changed is called whenever a control line in the mask changes due to an action of another device (not itself, to avoid an annoying and somewhat useless recursion). Implementing the controller is then just a matter of following the state machines descriptions, at least if they're available. The only part often not described is the arbitration/selection, which is documented in the SCSI standard though. For an initiator (which is what the controller essentially always is), it goes like this:
and then you're done, you're connected with the target until the target de-asserts the busy line, either because you asked it to or just to annoy you. The de-assert is called a disconnect. The ncr5390 is an example of how to use a two-level state machine to handle all the events. Creating a new SCSI device using nscsi_full_deviceThe base class "nscsi_full_device" is used to create HLE-d SCSI devices intended for generic uses, like hard drives, CD-ROMs, perhaps scanners, etc. The class provides the SCSI protocol handling, leaving only the command handling and (optionally) the message handling to the implementation. The class currently only support target devices. The first method to implement is scsi_command(). That method is called when a command has fully arrived. The command is available in scsi_cmdbuf[], and its length is in scsi_cmdsize (but the length is generally useless, the command first byte giving it). The 4096-bytes scsi_cmdbuf array is then freely modifiable. In scsi_command(), the device can either handle the command or pass it up with nscsi_full_device::scsi_command(). To handle the command, a number of methods are available:
The scsi_data_* and scsi_status_complete commands are queued, the command handler should call them all without waiting. buffer-id identifies a buffer. 0, aka SBUF_MAIN, targets the scsi_cmdbuf buffer. Other acceptable values are 2 or more. 2+ ids are handled through the scsi_get_data method for read and scsi_put_data for write. UINT8 device::scsi_get_data(int id, int pos) must return byte pos of buffer id, upcalling in nscsi_full_device for id < 2. void device::scsi_put_data(int id, int pos, UINT8 data) must write byte pos in buffer id, upcalling in nscsi_full_device for id < 2. scsi_get_data and scsi_put_data should do the external reads/writes when needed. The device can also override scsi_message to handle SCSI messages other than the ones generically handled, and it can also override some of the timings (but a lot of them aren't used, beware). A number of enums are defined to make things easier. The SS_* enum gives status returns (with SS_GOOD for all's well). The SC_* enum gives the scsi commands. The SM_* enum gives the SCSI messages, with the exception of identify (which is 80-ff, doesn't really fit in an enum). What's missing in scsi_full_device
What's missing in the ncr5390 (and probably future other controllers)
The new 6502 family implementationIntroductionThe new 6502 family implementation has been created to reach sub-instruction accuracy in observable behaviour. It is designed with 3 goals in mind:
Point 1 has been ensured through bisimulation with the gate-level simulation perfect6502. Point 2 has been ensured structurally through a code generator which will be explained in section 8. Point 3 is not done yet due to lack of support on the memory subsystem side, but section 9 shows how it will be handled. The 6502 familyThe MOS 6502 family has been large and productive. A large number of variants exist, varying on bus sizes, I/O, and even opcodes. Some offshoots (g65c816, hu6280) even exist that live elsewhere in the mame tree. The final class hierarchy is this:
The 6510 adds an up to 8 bits I/O port, with the 6510t, 7501 and 8502 being software-identical variants with different pin count (hence I/O count), die process (NMOS, HNMOS, etc.) and clock support. The deco16 is a Deco variant with a small number of not really understood additional instructions and some I/O. The 6504 is a pin and address-bus reduced version. The 6509 adds internal support for paging. The rp2a03 is the NES variant with the D flag disabled and sound functionality integrated. The 65c02 is the very first cmos variant with some additional instructions, some fixes, and most of the undocumented instructions turned into nops. The R (Rockwell, but eventually produced by WDC too among others) variant adds a number of bitwise instructions and also stp and wai. The SC variant, used by the Lynx portable console, looks identical to the R variant. The 'S' probably indicates a static-ram-cell process allowing full DC-to-max clock control. The 65ce02 is the final evolution of the ISA in this hierarchy, with additional instructions, registers, and removals of a lot of dummy accesses that slowed the original 6502 down by at least 25%. The 4510 is a 65ce02 with integrated MMU and GPIO support. Usage of the classesAll the CPUs are standard modern CPU devices, with all the normal interaction with the device infrastructure. To include one of these CPUs in your driver you need to include "CPU/m6502/<CPU>.h" and then do a MCFG_CPU_ADD("tag", <CPU>, clock).
In that case, transparent decryption support is also disabled, everything goes through normal memory-map read/write calls. The state of the sync line is given by the CPU method get_sync(), making implementing the decryption in the handler possible. Also, as for every executable device, the CPU method total_cycles() gives the current time in cycles since the start of the machine from the point of view of the CPU. Or, in other words, what is usually called the cycle number for the CPU when somebody talks about bus contention or wait states. The call is designed to be fast (no system-wide sync, no call to machine.time()) and is precise. Cycle number for every access is exact at the sub-instruction level. The 4510 special nomap line is accessible through get_nomap(). Other than these specifics, these are perfectly normal CPU classes. General structure of the emulationsEach variant is emulated through up to 4 files:
The last two are optional. They're used to generate a <CPU>.inc file in the object directory which is included by the .c file. At a minimum, the class must include a constructor and an enum picking up the correct input line ids. See m65sc02 for a minimalist example. The header can also include specific configuration macros (see m8502) and also the class can include specific memory accessors (more on these later, simple example in m6504). If the CPU has its own dispatch table, the class must also include the declaration (but not definition) of disasm_entries, do_exec_full and do_exec_partial, the declaration and definition of disasm_disassemble (identical for all classes but refers to the class-specific disasm_entries array) and include the .inc file (which provides the missing definitions). Support for the generation must also be added to CPU.mak. If the CPU has in addition its own opcodes, their declaration must be done through a macro, see f.i. m65c02. The .inc file will provide the definitions. Dispatch tablesEach d<CPU>.lst is the dispatch table for the CPU. Lines starting with '#' are comments. The file must include 257 entries, the first 256 being opcodes and the 257th what the CPU should do on reset. In the 6502 irq and nmi actually magically call the "brk" opcode, hence the lack of specific description for them. Entries 0 to 255, i.e. the opcodes, must have one of these two structures:
Opcode is traditionally a three-character value. Addressing mode must be a 3-letter value corresponding to one of the DASM_* macros in m6502.h. Opcode and addressing mode are used to generate the disassembly table. The full entry text is used in the opcode description file and the dispatching methods, allowing for per-CPU variants for identical-looking opcodes. An entry of "." was usable for unimplemented/unknown opcodes, generating "???" in the disassembly, but is not a good idea at this point since it will infloop in execute() if encountered. Opcode descriptionsEach o<CPU>.lst file includes the CPU-specific opcodes descriptions. An opcode description is a series of lines starting by an opcode entry by itself and followed by a series of indented lines with code executing the opcode. For instance the asl <absolute address> opcode looks like this: asl_aba First the low part of the address is read, then the high part (read_pc is auto-incrementing). Then, now that the address is available the value to shift is read, then re-written (yes, the 6502 does that), shifted then the final result is written (do_asl takes care of the flags). The instruction finishes with a prefetch of the next instruction, as all non-CPU-crashing instructions do. Available bus-accessing functions are:
Cycle counting is done by the code generator which detects (through string matching) the accesses and generates the appropriate code. In addition to the bus-accessing functions a special line can be used to wait for the next event (irq or whatever). "eat-all-cycles;" on a line will do that wait then continue. It is used by wai_imp and stp_imp for the m65c02. Due to the constraints of the code generation, some rules have to be followed:
The per-opcode generated code are methods of the CPU class. As such they have complete access to other methods of the class, variables of the class, everything. Memory interfaceFor better opcode reuse with the MMU/banking variants, a memory access subclass has been created. It's called memory_interface, declared in m6502_device, and provides the following accessors:
Two implementations are given by default, one usual, mi_default_normal, one disabling direct access, mi_default_nd. A CPU that wants its own interface (see 6504 or 6509 for instance) must override device_start, intialize mintf there then call init(). The generated codeA code generator is used to support interrupting and restarting an instruction in the middle. This is done through a two-level state machine with updates only at the boundaries. More precisely, inst_state tells you which main state you're in. It's equal to the opcode byte when 0-255, and 0xff00 means reset. It's always valid and used by instructions like rmb. inst_substate indicates at which step we are in an instruction, but it set only when an instruction has been interrupted. Let's go back to the asl <abs> code: asl_aba The complete generated code is: void m6502_device::asl_aba_partial() { switch(inst_substate) { case 0: One can see that the initial switch() restarts the instruction at the appropriate substate, that icount is updated after each access, and upon reaching 0 the instruction is interrupted and the substate updated. Since most instructions are started from the beginning a specific variant is generated for when inst_substate is known to be 0: void m6502_device::asl_aba_full() { That variant removes the switch, avoiding a costly computed branch and also an inst_substate write. There is in addition a fair chance that the decrement-test with zero pair is compiled into something efficient. All these opcode functions are called through two virtual methods, do_exec_full and do_exec_partial, which are generated into a 257-entry switch statement. Pointers-to-methods being expensive to call, a virtual function implementing a switch has a fair chance of being better. The execute main call ends up very simple: void m6502_device::execute_run() { If an instruction was partially executed finish it (icount will then be zero if it still doesn't finish). Then try to run complete instructions. The NPC/IR dance is due to the fact that the 6502 does instruction prefetching, so the instruction PC and opcode come from the prefetch results. Future bus contention/delay slot supportSupporting bus contention and delay slots in the context of the code generator only requires being able to abort a bus access when not enough cycles are available into icount, and restart it when cycles have become available again. The implementation plan is to:
void m6502_device::asl_aba_partial() { switch(inst_substate) { case 0: A modern try/catch costs nothing if an exception is not thrown. Using this the control will go back to the main loop, which will then look like this: void m6502_device::execute_run() { A negative icount means that the CPU won't be able to do anything for some time in the future, because it's either waiting for the bus to be free or for a peripheral to answer. These cycles will be counted until elapsed and then normal processing will go on. It's important to note that the exception path only happens when the contention/wait state goes further than the scheduling slice of the CPU. That should not usually be the case, so the cost should be minimal. Multi-dispatch variantsSome variants currently in the process of being supported change instruction set depending on an internal flag, either switching to a 16-bits mode or changing some register accesses to memory accesses. This is handled by having multiple dispatch tables for the CPU, the d<CPU>.lst not being 257 entries anymore but 256*n+1. The variable inst_state_base must select which instruction table to use at a given time. It must be a multiple of 256, and is in fact simply OR-ed to the first instruction byte to get the dispatch table index (aka inst_state). Current TO-DO:
UML Instruction Reference
IntroductionUML is the instruction set used by MAME’s recompiler framework. Front-ends translate code running on the guest CPUs to UML instructions, and back-ends convert the UML instructions to a form that can be executed or interpreted on the host system. Flow controlCOMMENTInsert a comment into logged UML code.
Operands
Flags
NOPNo operation.
Flags
LABELAssociate a location with a label number local to the current generated code block. Label numbers must not be reused within a generated code block. The JMP instruction may be used to transfer control to the location associated with a label number.
Operands
Flags
HANDLEMark a location as an entry point of a subroutine. Subroutines may be called using the CALLH and EXH instructions, and also by the HASHJMP <umlinst-hashjmp> if no location is associated with the specified mode and emulated program counter.
Operands
Flags
HASHAssociate a location with the specified mode and emulated program counter values. The HASHJMP instruction may be used to transfer control to the location associated with a mode and emulated program counter value. This is usually used to mark the location of the generated code for an emulated instruction or sequence of instructions.
Operands
Flags
JMPJump to the location associated with a label number within the current block.
Operands
Flags
CALLHCall the subroutine beginning at the specified code handle.
Operands
Flags
EXHSet the EXP register and call the subroutine beginning at the specified code handle. The EXP register is a 32-bit special function register that may be retrieved with the GETEXP instruction.
Operands
Flags
Simplification rules
RETReturn from a subroutine, transferring control to the instruction following the CALLH or EXH instruction used to call the subroutine. This instruction must only be used within generated code subroutines. The EXIT instruction must be used to exit from the generated code.
Operands
Flags
HASHJMPUnwind all nested generated code subroutine frames and transfer control to the location associated with the specified mode and emulated program counter values. If no location is associated with the specified mode and program counter values, call the subroutine beginning at the specified code handle. Note that all nested generated code subroutine frames are unwound in either case. This is usually used to jump to the generated code corresponding to the emulated code at a particular address when it is not known to be in the current generated code block or when the mode changes.
Operands
Flags
EXITExit from the generated code, returning control to the caller. May be used from within any level of nested subroutine calls in the generated code.
Operands
Flags
Simplification rules
CALLCCall a C function with the signature void (*)(void *).
Operands
Flags
DEBUGCall the debugger instruction hook function if appropriate. If the debugger is active, this should be executed before each emulated instruction. Any emulated CPU state kept in UML registers should be flushed to memory before executing this instruction and reloaded afterwards to ensure the debugger can display and modify values correctly.
Operands
Flags
Simplification rules
BREAKBreak into the host debugger if attached. Has no effect or crashes if no host debugger is attached depending on the host system and configuration. This is intended as a developer aid and should not be left in final code.
Flags
Data movementMOVCopy an integer value.
Operands
Flags
Simplification rules
FMOVCopy a floating point value. The binary value will be preserved even if it is not a valid representation of a floating point number.
Operands
Flags
Simplification rules
FCOPYIReinterpret an integer value as a floating point value. The binary value will be preserved even if it is not a valid representation of a floating point number.
Operands
Flags
ICOPYFReinterpret a floating point value as an integer value. The binary value will be preserved even if it is not a valid representation of a floating point number.
Operands
Flags
LOADLoad an unsigned integer value from a memory location with variable displacement. The value is zero-extended to the size of the destination. Host system rules for integer alignment must be followed.
Operands
Flags
LOADSLoad a signed integer value from a memory location with variable displacement. The value is sign-extended to the size of the destination. Host system rules for integer alignment must be followed.
Operands
Flags
STOREStore an integer value to a location in memory with variable displacement. Host system rules for integer alignment must be followed.
Operands
Flags
FLOADLoad a floating point value from a memory location with variable displacement. The binary value will be preserved even if it is not a valid representation of a floating point number. Host system rules for memory access alignment must be followed.
Operands
Flags
FSTOREStore a floating point value to a memory location with variable displacement. The binary value will be preserved even if it is not a valid representation of a floating point number. Host system rules for memory access alignment must be followed.
Operands
Flags
GETEXPCopy the value of the EXP register. The EXP register can be set using the EXH instruction.
Operands
Flags
MAPVARSet the value of a map variable starting at the current location in the current generated code block.
Operands
Flags
RECOVERRetrieve the value of a map variable at the location of the call instruction in the outermost generated code frame. This instruction should only be used from within a generated code subroutine. Results are undefined if this instruction is executed from outside any generated code subroutines.
Operands
Flags
Emulated memory accessREADRead from an emulated address space. The access mask is implied to have all bits set.
Operands
Flags
Simplification rules
READMRead from an emulated address space with access mask specified.
Operands
Flags
Simplification rules
WRITEWrite to an emulated address space. The access mask is implied to have all bits set.
Operands
Flags
Simplification rules
WRITEMWrite to an emulated address space with access mask specified.
Operands
Flags
Simplification rules
FREADRead a floating point value from an emulated address space. The binary value will be preserved even if it is not a valid representation of a floating point number. The access mask is implied to have all bits set.
Operands
Flags
Simplification rules
FWRITEWrite a floating point value to an emulated address space. The binary value will be preserved even if it is not a valid representation of a floating point number. The access mask is implied to have all bits set.
Operands
Flags
Simplification rules
Software 3D Rendering in MAME
BackgroundBeginning in the late 1980s, many arcade games began incorporating hardware-rendered 3D graphics into their video. These 3D graphics are typically rendered from low-level primitives into a frame buffer (usually double- or triple-buffered), then perhaps combined with traditional tilemaps or sprites, before being presented to the player. When it comes to emulating 3D games, there are two general approaches. The first approach is to leverage modern 3D hardware by mapping the low-level primitives onto modern equivalents. For a cross-platform emulator like MAME, this requires having an API that is flexible enough to describe the primitives and all their associated behaviors with high accuracy. It also requires the emulator to be able to read back from the rendered frame buffer (since many games do this) and combine it with other elements, in a way that is properly synchronized with background rendering. The alternative approach is to render the low-level primitives directly in software. This has the advantage of being able to achieve pretty much any behavior exhibited by the original hardware, but at the cost of speed. In MAME, since all emulation happens on one thread, this is particularly painful. However, just as with the 3D hardware approach, in theory a software-based approach could be spun off to other threads to handle the work, as long as mechanisms were present to synchronize when necessary, for example, when reading/writing directly to/from the frame buffer. For the time being, MAME has opted for the second approach, leveraging a templated helper class called poly_manager to handle common situations. ConceptsAt its core, poly_manager is a mechanism to support multi-threaded rendering of low-level 3D primitives. Callers provide poly_manager with a set of vertices for a primitive plus a render callback. poly_manager breaks the primitive into clipped scanline extents and distributes the work among a pool of worker threads. The render callback is then called on the worker thread for each extent, where game-specific logic can do whatever needs to happen to render the data. One key responsibility that poly_manager takes care of is ensuring order. Given a pool of threads and a number of work items to complete, it is important that—at least within a given scanline—all work is performed serially in order. The basic approach is to assign each extent to a bucket based on the Y coordinate. poly_manager then ensures that only one worker thread at a time is responsible for processing work in a given bucket. Vertices in poly_manager consist of simple 2D X and Y coordinates, plus zero or more additional iterated parameters. These iterated parameters can be anything: intensity values for lighting; RGB(A) colors for Gouraud shading; normalized U, V coordinates for texture mapping; 1/Z values for Z buffering; etc. Iterated parameters, regardless of what they represent, are interpolated linearly across the primitive in screen space and provided as part of the extent to the render callback. ObjectTypeWhen creating a poly_manager class, you must provide it a special type that you define, known as ObjectType. Because rendering happens asynchronously on worker threads, the idea is that the ObjectType class will hold a snapshot of all the relevant data needed for rendering. This allows the main thread to proceed—potentially modifying some of the relevant state—while rendering happens elsewhere. In theory, we could allocate a new ObjectType class for each primitive rendered; however, that would be rather inefficient. It is quite common to set up the rendering state and then render several primitives using the same state. For this reason, poly_manager maintains an internal array of ObjectType objects and keeps a copy of the last ObjectType used. Before submitting a new primitive, callers can see if the rendering state has changed. If it has, it can ask poly_manager to allocate a new ObjectType class and fill it in. When the primitive is submitted for rendering, the most recently allocated ObjectType instance is implicitly captured and provided to the render callbacks. For more complex scenarios, where data might change even more infrequently, there is a poly_array template, which can be used to manage data in a similar way. In fact, internally poly_manager uses the poly_array class to manage its ObjectType allocations. More information on the poly_array class is provided later. Primitivespoly_manager supports several different types of primitives:
SynchronizationOne of the key requirements of providing an asynchronous rendering mechanism is synchronization. Synchronization in poly_manager is super simple: just call the wait() function. There are several common reasons for issuing a wait:
Because the wait operation knows after it is done that all rendering is complete, poly_manager also takes this opportunity to reclaim all memory allocated for its internal structures, as well as memory allocated for ObjectType structures. Thus it is important that you don’t hang onto any ObjectType pointers after a wait is called. The poly_manager classIn most applications, poly_manager is not used directly, but rather serves as the base class for a more complete rendering class. The poly_manager class itself is a template: template<typename BaseType, class ObjectType, int MaxParams, u8 Flags = 0> class poly_manager; and the template parameters are:
Types & Constantsvertex_tWithin the poly_manager class, you’ll find a vertex_t type that describes a single vertex. All primitive drawing methods accept 2 or more of these vertex_t objects. The vertex_t includes the X and Y coordinates along with an array of iterated parameter values at that vertex: struct vertex_t { Note that vertex_t itself is defined in terms of the BaseType and MaxParams template values of the owning poly_manager class. All of poly_manager’s primitives operate in screen space, where (0,0) represents the top-left corner of the top-left pixel, and (0.5,0.5) represents the center of that pixel. Left and top pixel values are inclusive, while right and bottom pixel values are exclusive. Thus, a tile rendered from (2,2)-(4,3) will completely cover 2 pixels: (2,2) and (3,2). When calling a primitive drawing method, the iterated parameter array p need not be completely filled out. The number of valid iterated parameter values is specified as a template parameter to the primitive drawing methods, so only that many parameters need to actually be populated in the vertex_t structures that are passed in. extent_tpoly_manager breaks primitives into extents, which are contiguous horizontal spans contained within a single scanline. These extents are then distributed to worker threads, who will call the render callback with information on how to render each extent. The extent_t type describes one such extent, providing the bounding X coordinates along with an array of iterated parameter start values and deltas across the span: struct extent_t { For each iterated parameter, the start value contains the value at the left side of the span. The dpdx value contains the change of the parameter’s value per X coordinate. There is also a userdata field in the extent_t structure, which is not normally used, except when performing custom rendering. render_delegateWhen rendering a primitive, in addition to the vertices, you must also provide a render_delegate callback of the form: void render(int32_t y, extent_t const &extent, ObjectType const &object, int threadid) This callback is responsible for the actual rendering. It will be called at a later time, likely on a different thread, for each extent. The parameters passed are:
Methodspoly_managerpoly_manager(running_machine &machine); The poly_manager constructor takes just one parameter, a reference to the running_machine. This grants poly_manager access to the work queues needed for multithreaded running. waitvoid wait(char const *debug_reason = "general"); Calling wait() stalls the calling thread until all outstanding rendering is complete:
Return value: none. object_dataobjectdata_array &object_data(); This method just returns a reference to the internally-maintained poly_array of the ObjectType you specified when creating poly_manager. For most applications, the only interesting thing to do with this object is call the next() method to allocate a new object to fill out. Return value: reference to a poly_array of ObjectType. register_poly_arrayvoid register_poly_array(poly_array_base &array); For advanced applications, you may choose to create your own poly_array objects to manage large chunks of infrequently-changed data, such a palettes. After each wait(), poly_manager resets all the poly_array objects it knows about in order to reclaim all outstanding allocated memory. By registering your poly_array objects here, you can ensure that your arrays will also be reset after an wait() call. Return value: none. render_tiletemplate<int ParamCount> uint32_t render_tile(rectangle const &cliprect, render_delegate callback, This method enqueues a single tile primitive for rendering:
Return value: the total number of clipped pixels represented by the enqueued extents. render_triangletemplate<int ParamCount> uint32_t render_triangle(rectangle const &cliprect, render_delegate callback, This method enqueues a single triangle primitive for rendering:
Return value: the total number of clipped pixels represented by the enqueued extents. render_triangle_fantemplate<int ParamCount> uint32_t render_triangle_fan(rectangle const &cliprect, render_delegate callback, This method enqueues one or more triangle primitives for rendering, specified in fan order:
Return value: the total number of clipped pixels represented by the enqueued extents. render_triangle_striptemplate<int ParamCount> uint32_t render_triangle_strip(rectangle const &cliprect, render_delegate callback, This method enqueues one or more triangle primitives for rendering, specified in strip order:
Return value: the total number of clipped pixels represented by the enqueued extents. render_polygontemplate<int NumVerts, int ParamCount> uint32_t render_polygon(rectangle const &cliprect, render_delegate callback, vertex_t const *v); This method enqueues a single polygon primitive for rendering:
Return value: the total number of clipped pixels represented by the enqueued extents. render_extentstemplate<int ParamCount> uint32_t render_extents(rectangle const &cliprect, render_delegate callback, This method enqueues custom extents directly:
Return value: the total number of clipped pixels represented by the enqueued extents. zclip_if_lesstemplate<int ParamCount> int zclip_if_less(int numverts, vertex_t const *v, vertex_t *outv, BaseType clipval); This method is a helper method to clip a polygon against a provided Z value. It assumes that the first iterated parameter in vertex_t represents the Z coordinate. If any edge crosses the Z plane represented by clipval that edge is clipped.
Return value: the number of output vertices written to outv. Note that by design it is possible for this method to produce more vertices than the input array, so callers should ensure there is enough room in the output buffer to accommodate this. Example RendererHere is a complete example of how to create a software 3D renderer using poly_manager. Our example renderer will only handle flat and Gouraud-shaded triangles with depth (Z) buffering. TypesThe first thing we need to define is our externally-visible vertex format, which is distinct from the internal vertex_t that poly_manager will define. In theory you could use vertex_t directly, but the generic nature of poly_manager’s iterated parameters make it awkward: struct example_vertex { Next we define the ObjectType needed by poly_manager. For our simple case, we define an example_object_data struct that consists of pointers to our rendering buffers, plus a couple of fixed values that are consumed in some cases. More complex renderers would typically have many more object-wide parameters defined here: struct example_object_data { Now it’s time to define our renderer class, which we derive from poly_manager. As template parameters we specify float as the base type for our data, since that will be enough accuracy for this example, and we also provide our example_object_data as the ObjectType class, plus the maximum number of iterated parameters our renderer will ever need (4 in this case): class example_renderer : public poly_manager<float, example_object_data, 4> { public: ConstructorThe constructor for our example renderer just initializes poly_manager and allocates the rendering and depth buffers: example_renderer::example_renderer(running_machine &machine, uint32_t width, uint32_t height) : swap_buffersThe first interesting method in our renderer is swap_buffers(), which returns a pointer to the buffer we’ve been drawing to, and sets up the other buffer as the new drawing target. The idea is that the display update handler will call this method to get ahold of the bitmap to display to the user: bitmap_rgb32 *example_renderer::swap_buffers() { The most important thing here to note here is the call to poly_manager’s wait(), which will block the current thread until all rendering is complete. This is important because otherwise the caller may receive a bitmap that is still being drawn to, leading to torn or corrupt visuals. clear_buffersOne of the most common operations to perform when doing 3D rendering is to initialize or clear the display and depth buffers to a known value. This method below leverages the tile primitive to render a rectangle over the screen by passing in (0,0) and (width,height) for the two vertices. Because the color and depth values to clear the buffer to are constant, they are stored in a freshly-allocated example_object_data object, along with a pointer to the buffers in question. The render_tile() call is made with a <0> suffix indicating that there are no iterated parameters to worry about: void example_renderer::clear_buffers(rgb_t color, uint16_t depthval) { The render callback provided to render_tile() is also defined (privately) in our class, and handles a single span. Note how the rendering parameters are extracted from the example_object_data struct provided: void example_renderer::render_clear(int32_t y, extent_t const &extent, example_object_data const &object, int threadid) { Another important point to make is that the X coordinates provided by extent struct are inclusive of startx but exclusive of stopx. Clipping is performed ahead of time so that the render callback can focus on laying down pixels as quickly as possible with minimal overhead. draw_triangleNext up, we have our actual triangle rendering function, which will draw a single triangle given an array of three vertices provided in the external example_vertex format: void example_renderer::draw_triangle(example_vertex const *verts) { Because it is simpler and faster to render a flat shaded triangle, the code checks to see if the colors are the same on all three vertices. If they are, we call through to a special flat-shaded case, otherwise we process it as a full Gouraud-shaded triangle. This is a common technique to optimize rendering performance: identify special cases that reduce the per-pixel work, and route them to separate render callbacks that are optimized for that special case. draw_triangle_flatHere’s the setup code for rendering a flat-shaded triangle: void example_renderer::draw_triangle_flat(example_vertex const *verts) { First, we put the fixed color into the example_object_data directly, and then fill out three vertex_t objects with the X and Y coordinates in the usual spot, and 1/Z as our one and only iterated parameter. (We use 1/Z here because iterated parameters are interpolated linearly in screen space. Z is not linear in screen space, but 1/Z is due to perspective correction.) Our flat-shaded case then calls render_trangle specifying <1> iterated parameter to interpolate, and pointing to a special-case flat render callback: void example_renderer::render_flat(int32_t y, extent_t const &extent, example_object_data const &object, int threadid) { This render callback is a bit more involved than the clearing case. First, we have an iterated parameter (1/Z) to deal with, whose starting and X-delta values we extract from the extent before the start of the inner loop. Second, we perform depth buffer testing, using ooz_to_depthval() as a helper to transform the floating-point 1/Z value into a 16-bit integer. We compare this value against the current depth buffer value, and only store the pixel/depth value if it’s less. At the end of each iteration, we advance the 1/Z value by the X-delta in preparation for the next pixel. draw_triangle_gouraudFinally we get to the code for the full-on Gouraud-shaded case: void example_renderer::draw_triangle_gouraud(example_vertex const *verts) { Here we have 4 iterated parameters: the 1/Z depth value, plus red, green, and blue, stored as floating point values. We call render_triangle() with <4> as the number of iterated parameters to process, and point to the full Gouraud render callback: void example_renderer::render_gouraud(int32_t y, extent_t const &extent, example_object_data const &object, int threadid) { This follows the same pattern as the flat-shaded callback, except we have 4 iterated parameters to step through. Note that even though the iterated parameters are of float type, we convert the color values to fixed-point integers when iterating over them. This saves us doing 3 float-to-int conversions each pixel. The original RGB values were 0-255, so interpolation can only produce values in the 0-255 range. Thus we can use 24 bits of a 32-bit integer as the fraction, which is plenty accurate for this case. Advanced Topic: the poly_array classpoly_array is a template class that is used to manage a dynamically-sized vector of objects whose lifetime starts at allocation and ends when reset() is called. The poly_manager class uses several poly_array objects internally, including one for allocated ObjectType data, one for each primitive rendered, and one for holding all allocated extents. poly_array has an additional property where after a reset it retains a copy of the most recently allocated object. This ensures that callers can always call last() and get a valid object, even immediately after a reset. The poly_array class requires two template parameters: template<class ArrayType, int TrackingCount> class poly_array; These parameters are:
Note that objects allocated by poly_array are owned by poly_array and will be automatically freed upon exit. poly_array is optimized for use in high frequency multi-threaded systems. Therefore, one added feature of the class is that it rounds the allocation size of ArrayType to the nearest cache line boundary, on the assumption that neighboring entries could be accessed by different cores simultaneously. Keeping each ArrayType object in its own cache line ensures no false sharing performance impacts. Currently, poly_array has no mechanism to determine cache line size at runtime, so it presumes that 64 bytes is a typical cache line size, which is true for most x64 and ARM chips as of 2021. This value can be altered by changing the CACHE_LINE_SHIFT constant defined at the top of the class. Objects allocated by poly_array are created in 64k chunks. At construction time, one chunk’s worth of objects is allocated up front. The chunk size is controlled by the CHUNK_GRANULARITY constant defined at the top of the class. As more objects are allocated, if poly_array runs out of space, it will dynamically allocate more. This will produce discontiguous chunks of objects until the next reset() call, at which point poly_array will reallocate all the objects into a contiguous vector once again. For the case where poly_array is used to manage a shared pool of objects, it can be configured to retain multiple most recently allocated items by using a TrackingCount greater than 1. For example, if poly_array is managing objects for two texture units, then it can set TrackingCount equal to 2, and pass the index of the texture unit in calls to next() and last(). After a reset, poly_array will remember the most recently allocated object for each of the units independently. Methodspoly_arraypoly_array(); The poly_array constructor requires no parameters and simply pre-allocates one chunk of objects in preparation for future allocations. countu32 count() const; Return value: the number of objects currently allocated. maxu32 max() const; Return value: the maximum number of objects ever allocated at one time. itemsizesize_t itemsize() const; Return value: the size of an object, rounded up to the nearest cache line boundary. allocatedu32 allocated() const; Return value: the number of objects that fit within what’s currently been allocated. byindexArrayType &byindex(u32 index); Returns a reference to an object in the array by index. Equivalent to [index] on a normal array:
Return value: a reference to the object in question. Since a reference is returned, it is your responsibility to ensure that index is less than count() as there is no mechanism to return an invalid result. contiguousArrayType *contiguous(u32 index, u32 count, u32 &chunk); Returns a pointer to the base of a contiguous section of count items starting at index. Because poly_array dynamically resizes, it may not be possible to access all count objects contiguously, so the number of actually contiguous items is returned in chunk:
Return value: a pointer to the first item in the contiguous chunk. No range checking is performed, so it is your responsibility to ensure that index + count is less than or equal to count(). indexofint indexof(ArrayType &item) const; Returns the index within the array of the given item:
Return value: the index of the item. It should always be the case that: array.indexof(array.byindex(index)) == index resetvoid reset(); Resets the poly_array by semantically deallocating all objects. If previous allocations created a discontiguous array, a fresh vector is allocated at this time so that future allocations up to the same level will remain contiguous. Note that the ArrayType destructor is not called on objects as they are deallocated. Return value: none. nextArrayType &next(int tracking_index = 0); Allocates a new object and returns a reference to it. If there is not enough space for a new object in the current array, a new discontiguous array is created to hold it:
Return value: a reference to the object. Note that the placement new operator is called on this object, so the default ArrayType constructor will be invoked here. lastArrayType &last(int tracking_index = 0) const; Returns a reference to the last object allocated:
Return value: a reference to the last allocated object. MAME AND SECURITY CONCERNSMAME is not intended or designed to run in secure sites. It has not been security audited for such types of usage, and has been known in the past to have flaws that could be used for malicious intent if run as administrator or root. We do not suggest or condone the use of MAME as administrator or root and use as such is done at your own risk. Bug reports, however, are always welcome. THE MAME LICENSEThe MAME project as a whole is distributed under the terms of the GNU General Public License, version 2 or later (GPL-2.0+), since it contains code made available under multiple GPL-compatible licenses. A great majority of files (over 90% including core files) are under the 3-Clause BSD License and we would encourage new contributors to distribute files under this license. Please note that MAME is a registered trademark of Gregory Ember, and permission is required to use the “MAME” name, logo, or wordmark. Copyright (c) 1997-2025 MAMEDev and contributors
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Please see the license information for further details. CONTRIBUTEThe documentation on this site is the handiwork of our many contributors. AUTHORMAMEdev Team COPYRIGHT1997-2025, MAMEdev and contributors
|