Game Drivers

From MAMEDEV Wiki

Probably the most common question when it comes down to how MAME works is: how do I write a driver? In order to understand how to write a driver, you need to understand how drivers are connected into MAME, and what the various driver-related pieces of the puzzle are. This article should provide you with a basic overview of what goes into a driver at the topmost level. Future articles will address many of the details beyond that.

So, to get started, you will want to take a peek at the code in src/mame/mame.lst. Essentially all this module does is produce a list of references to all the drivers supported by MAME:

...
@source:tvgame.cpp
tvgame                          // 2011
...

The @source: directive tells the build scripts the name of the source file where the following system drivers are defined. The following lines (up to the next @source: directive) list the "short names" of the system drivers defined in that source file.

With those lines inserted into the list alongside all the other entries, your driver is now referenced by the master driver list in MAME! Of course, this now means that you actually need to have a system driver with the same short name living elsewhere in MAME in order to successfully link the application. So how exactly do you define a system driver?

The system driver structure contains some basic information used to find or list the system, as well as references to the classes, structures and functions that describe the hardware. System driver structures are instantiated using the GAME/GAMEL, COMP, CONS and SYST macros (used for arcade games, computers, consoles and other systems, respectively). If you look at the bottom of any of the files in the src/mame/drivers directory, you will see a number of these macros describing the drivers defined in that file:

CONS( 2011, tvgame, 0, 0, tvgame, tvgame, tvgame_state, empty_init, "Mr. Isizu", "Z80 TV Game System", 0 )

The main disadvantage to using a macro like this is that it is not immediately obvious what each argument is for. A number of them even have the same value (tvgame). This is something you get used to, however. Going through the arguments from left to right, here is what is being defined:

  • The first argument (2011) is the release year for the system. In general, if the system shows a copyright year, it's used as the definitive year. It isn't necessarily completely accurate, but it's usually close. If the system doesn't display a copyright notice with a year, we need to rely on other sources like manuals, magazine advertisements and catalogues.
  • The second argument (tvgame) is the short name of the system driver itself. This must match the short name listed in src/mame/mame.lst. The actual name of the variable will have driver_ prepended to it. In this example, the system driver variable's name will be driver_tvgame. Short names are restricted to sixteen characters length, using lowercase English letters (“a” to “z”), digits (“0” to “9”) and underscores (“_”). The short name is when searching for external files required to run the system (like ROMs or artwork), and when creating files to save persistent state related to the system (like input mappings and non-volatile RAM contents). It’s also used for launching the system from the command line.
  • The third and fourth arguments (both 0 in this example) are used for parent/clone and software compatibility relationships. They're set to zero when they're not used. Parent/clone relationships are used to group multiple versions of the same system. The parent will generally be the latest English-language release with the widest release. Note that parent/clone relationships mainly exist to group different versions of the same system and are somewhat arbitrary. There’s no implication that the parent is the original or somehow superior to its clones.
  • The fifth argument (tvgame) is the name of the machine configuration function, which creates the devices in the system and makes connections between them. Machine configuration functions are worth a whole article themselves, so they won't be discussed in much detail here. It is quite common for multiple system drivers to all share one machine configuration function, especially for arcade platforms that had a common set of hardware for a number of games. The machine configuration function is a member function of the state class (seventh argument) with a standard signature. In this case, the machine configuration function will be:
void tvgame_state::tvgame(machine_config &config)
  • The sixth argument (also tvgame) is the name of the input port definitions. Input ports will be described elsewhere, but in short, they describe various external inputs to the system (for example controls and DIP switches). Input ports are constructed at runtime by code, and this macro prepends construct_ioport_ to the specified name to get the function name to use. In the example above, the macro will generate a pointer to the function construct_ioport_tvgame.
  • The seventh argument (tvgame_state) is the name of the driver state class. This class must derive from driver_device, which is itself a specialisation of device_t. The driver_device class provides virtual member functions that the state class can override to handle different phases of an emulation session. The state class will also have member functions to build machine configurations, describe address maps, provide glue logic, and emulate functionality that isn't provided by reusable device classes.
  • The eighth argument (empty_init) is the name of an initialisation function. In this case it's unused, but some systems use this for tasks like unscrambling ROM code. Like the machine configuration function, this must be a member function of the state class. The empty_init member function is provided by driver_device for systems that don't need to do anything in an initialisation function.
  • The ninth argument ("Mr. Isizu") is called the “manufacturer”. It’s the brand name displayed in the internal user interface, and used for searching and filtering. This may be the manufacturer, licensee, distributor, publisher or developer as appropriate. In this case it’s the developer/publisher of the homebrew system.
  • The tenth argument ("Z80 TV Game System") is the display name of the system. For game systems, this is taken from the title screen if possible. If the system doesn’t have a title screen, it may be taken from branding on the unit itself, a manufacturers nameplate, documentation, packaging, marketing material, or identification strings in the ROM. Display names must be unique across all systems in MAME. For identically-named systems, disambiguation text is added to the name. This may be the manufacturer, revision/version, release region, hardware platform, or an arbitrary “set number”.
  • The eleventh and final argument (0 in this case) is a flags bit field. It can be used to flag certain requirements or emulation issues. In this case there are no flags set. Many of these flags cause a warning to be displayed on starting emulation. Additional flags can be set in the state class. Possible values include:
    • MACHINE_NOT_WORKING – the system is not fully emulated. This causes a red warning to be displayed when starting emulation.
    • MACHINE_SUPPORTS_SAVE – MAME supports saving and loading state for this system, and rewind features. If this is not set, MAME may warn the user that save states are not supported. If this is set, the -autosave option will automatically load system state on start and save it on exit.
    • MACHINE_NO_COCKTAIL – screen flipping in cocktail mode is not emulated (yellow colour).
    • MACHINE_IS_BIOS_ROOT – this represents a system with no software loaded. This is often set for a system representing an arcade mainboard that supports interchangeable games when no game is present.
    • MACHINE_REQUIRES_ARTWORK – warns the user that the machine requires external artwork files to be usable (yellow colour).
    • MACHINE_CLICKABLE_ARTWORK – ensures a mouse cursor is displayed when the mouse is captured so the user can interact with the system by clicking artwork elements.
    • MACHINE_UNOFFICIAL – this system represents a common user modification to a system that was not supported by the manufacturer.
    • MACHINE_NO_SOUND_HW – displays a notice when starting emulation that the system has no sound output hardware, so it’s normal to hear no sound.
    • MACHINE_MECHANICAL – warns the user that the system relies on mechanical features. For example this is set for pinball games, coin pushers and crane games.
    • MACHINE_IS_INCOMPLETE – warns the user that the system is an incomplete prototype.
    • MACHINE_UNEMULATED_PROTECTION – warns the user that the system has unemulated protection features (red colour).
    • MACHINE_WRONG_COLORS and MACHINE_IMPERFECT_COLORS – displays a red or yellow warning indicating that colours are incorrect when starting. These flags are mutually exclusive.
    • MACHINE_IMPERFECT_GRAPHICS – warns the user that graphics are imperfectly emulated (yellow colour).
    • MACHINE_NO_SOUND and MACHINE_IMPERFECT_SOUND – warns the user that sound hardware is unemulated (red colour) or imperfectly emulated (yellow colour). These flags are mutually exclusive.
    • MACHINE_IMPERFECT_CONTROLS – warns the user that controls are imperfectly emulated (yellow colour).
    • MACHINE_NODEVICE_MICROPHONE, MACHINE_NODEVICE_PRINTER and MACHINE_NODEVICE_LAN – warn the user about unemulated hardware features (red colour). Additional unemulated hardware features may indicated with emulation flags on the state class.
    • MACHINE_IMPERFECT_TIMING – warns the user that the system has timing issues (yellow colour). This could manifest in various ways, including incorrect speed.
    • MACHINE_IS_SKELETON – combination of MACHINE_NO_SOUND and MACHINE_NOT_WORKING.
    • MACHINE_IS_SKELETON_MECHANICAL – combination of MACHINE_IS_SKELETON, MACHINE_MECHANICAL and MACHINE_REQUIRES_ARTWORK.

For mostly historical reasons, the macro for arcade games has slightly different parameters. Here are some examples:

GAME( 1994, superx,  0,      superx, superx, rshark_state, empty_init, ROT270, "Dooyong (NTC license)",      "Super-X (NTC)",      MACHINE_SUPPORTS_SAVE )
GAME( 1994, superxm, superx, superx, superx, rshark_state, empty_init, ROT270, "Dooyong (Mitchell license)", "Super-X (Mitchell)", MACHINE_SUPPORTS_SAVE )
  • The first argument (1994 in both cases) is the release year.
  • The second argument (superx/superxm) is the short name of the system. This is a good time to mention a convention: where there are multiple versions of a system, the clones’ short names will be the parent’s short name with suffixes appended.
  • The third argument is the parent. It’s 0 for superx because, which has no parent, and superx for superxm – this means that superx is the parent of superxm and superxm is a clone of superx.
  • The fourth argument (superx in both cases) is the name of the machine configuration function. Both versions of this game use the same machine configuration function, as they run on identical hardware. Remember the the machine configuration function is a member of the state class – in this case it will be:
void rshark_state::superx(machine_config &config)
  • The fifth argument (also superx in both cases) is the name of the input port definitions. The macros will generate a pointers to the function construct_ioport_superx.
  • The sixth argument (rshark_state in both cases) is the name of the driver state class. Both these systems use the same state class.
  • The seventh argument (empty_init in both cases) is the name of an initialisation function. Neither of these systems need to do anything in an initialisation function, so they use empty_init from driver_device.
  • The eighth argument (ROT270 in both cases) specifies orientation transforms to be applied to all video screens in the system. Many systems have screens mounted vertically, and some systems’ screens are viewed via mirrors. Possible values are ROT0, ROT90, ROT180 and ROT270 to rotate by 0°, 90°, 180° or 270°, ORIENTATION_FLIP_X and ORIENTATION_FLIP_Y to flip horizontally or vertically, and ORIENTATION_SWAP_XY to flip around a diagonal line from upper left to lower right (the ROT constants are made by combining ORIENTATION_FLIP_ constants). This argument is logically combined with the system flags – it’s a separate argument for arcade games for historical reasons. For systems that have multiple screens in different orientations, orientation flags are applied to the screens in the machine configuration function. Both these systems use a single 4:3 monitor rotated 270° so the raster is scanned top to bottom left to right.
  • The ninth argument (Dooyong (NTC license) and Dooyong (Mitchell license)) is the manufacturer. The systems (software and hardware) were developed by Dooyong, but licensed to different companies (NTC and Mitchell) for distribution.
  • The tenth argument (Super-X (NTC) and Super-X (Mitchell)) is the display name. Since both these systems have the same name, we add the licensee for disambiguation.
  • The eleventh and final argument (MACHINE_SUPPORTS_SAVE in both cases) is the system flags bit field. Saving and restoring state is supported for both these systems in MAME.