Next: , Previous: The WPC Hardware, Up: Top


Appendix B The Machine Definition

Machines define most of their hardware configuration in the form of an "md" file. Long ago, this was done by directly writing a .h file with the required information. The .h file approach was more cumbersome and somewhat error- prone.

The md file is "compiled" by the script genmachine, which writes out a .h file and also some .c files that get linked in to the final program. genmachine will do some consistency checking on the input to make sure it is sane.

It will enforce naming consistency between identifiers, declarations, and strings. For example, the start button gets a define for its switch number (SW_START_BUTTON), an identifier for callback events (sw_start_button), and a string in the menus ("START BUTTON"). gendefine can produce all of these automatically from a single "Start Button:" declaration in the .md file.

Though the syntax is fairly strict, there is a bit of magic in how different categories need to be written. The easiest way to write a config for a new game is to copy from another one. The Twilight Zone and World Cup Soccer configs are the most complete. There is more documentation in those files on how things should be set up.

B.1 Syntax

The "md" file is just a text file. Blank lines and lines beginning with a '#' are ignored, like in a shell script.

Long lines can be broken up like in C, with a backslash at the end of each line. A comma also acts as a line continuation character, which is useful when defining long lists.

The file is divided into sections, which begin with a section header in square brackets. For example:

     global-statements
     
     [section1]
     section1-statements
     
     [section2]
     section2-statements

Only section names that are known to genmachine are permitted. The list of permitted sections is listed near the top of the genmachine script, and includes: switches, lamp, drives, gi, lamplists, containers, etc.

Notice that there is a global section that is in effect at the top of a file, before you declare any sections.

Within a section, you declare items that fit that category. All declarations take this form:

     key: property1 [, property2...]

A declaration begins with a key, followed by a colon, followed by a comma- separated list of properties. The key and/or properties can contain any characters, including spaces, but not commas or colons.

There are two types of declarations: fixed objects and dynamic objects. They are written similarly but not exactly the same.

B.2 Fixed Objects

In one style, used mostly for hardware layout, the key refers to the object's physical identification, such as the switch, lamp, or solenoid number. Here the key is generally numeric, although for solenoids the syntax is slightly different to specify the solenoid bank. The first property of these declarations should always be the human readable name of the object. Depending on the type of declaration, genmachine can validate that the key name is valid.

An example:

     [switches]
     14: Tilt, tilt, ingame, noplay

The key, 14, identifies which switch is being described. For switches and lamps, the key is given as a pair of column/row digits, as it would be listed in the game manual. The first property, Tilt, gives it a name. This is used to generate the defines and strings related to the switch.

Everything else identifies the properties of the switch. Different types of objects will have different properties. Here, we say three things: (1) it is an instance of a well-known switch class, called 'tilt'; this ties it directly to system code for processing tilts automatically. (2) The tilt switch should only be serviced during a game. (3) A closure does not mark valid playfield.

B.3 Variable Objects

In the second type of object definition, there is no physical identifier, and so the name before the colon is the human readable name. These are generally used for software constructs. For these, genmachine automatically assigns a number based on the order of the declarations. There can be an unlimited number of objects of these types, unlike those tied to hardware where there is a physical limit.

For example:

     [deffs]
     Multiball Start: page(MACHINE_PAGE), PRI_GAME_QUICK6

This defines a display effect for multiball start. A #define is generated, DEFF_MULTIBALL_START, which is a numeric ID used to refer to the effect. The IDs for all deffs are assigned sequentially, and do not need to be specified as with the switches above. Everything following the colon is treat as a property just as above.

This example also shows a variation in the property syntax. Above, we saw properties 'ingame' and 'noplay', which are binary properties: just stating them causes them to be turned on. Binary properties can be listed in any order; genmachine knows what all of the allowable binary properties are and will handle them correctly. In the deff declaration above, there is a 'page' property, which is not binary – it has a value, MACHINE_PAGE. For these valued properties, the syntax is always ‘variable(value)’.

B.4 Directives

B.4.1 include

The 'include' directive can be used to include config syntax from another file, much like a C '#include'. This is used to bring in common definitions for the platform, that can be shared across games.

For example, no game defines a switch entry for the "ALWAYS CLOSED" switch, which is the same in every WPC game. This can be put into a file shared by all machines.

By convention, the machine-specific file includes the platform-specific file, which may itself include other files. The WPC platform provides different files for the different hardware generations, one per variation and one that is common for all.

All include files are read and parsed before any of the output is generated. It is thus possible to override definitions that were seen in an earlier include. The default WPC md file provides names for all of the switches and lamps, so if you omit one from the machine file, you get a default definition. The tester ROM uses this facility.

B.4.2 define

The 'define' directive is used for miscellaneous settings. It gets translated to a C '#define' in the output file mach-config.h. For example,

define MACHINE_NUMBER 531

is converted to:

#define MACHINE_NUMBER 531

Note that the pound sign is not included in the mdfile, as it would be treated as a comment.

B.5 Global Configuration

Certain things need to be defined in the global sections, using Key: Value syntax. The human readable name of the machine, the system type, and a few other things can be given here. These do not appear directly in the mach-config.h, but are used by genmachine to guide the compilation. Again, see any existing config file for an example.

B.6 Section Summary

Here is a list of the sections that can appear.

switches
Defines the physical switches.

The possible attributes for switches are:

opto
edge
noplay
ingame
intest
button
noscore

Additionally, these attributes are used to tag special switches. There should only be one switch of each type.

outhole
shooter
tilt
slam-tilt
buyin-button
launch-button
start-button
trough-stack

lamps
Defines the controlled lamps. You can also give each lamp a color and a playfield position; there are ways of using this data to auto-generate lamp effects.

These attributes are used to tag special lamps:

start
buyin
extra-ball
shoot-again

drives
Defines the solenoids and flashers. Use the flash attribute to say which ones are flashers. Use motor to say which ones are motors.

These attributes are used to tag special drives:

ballserve
knocker
launch

gi
Defines the G.I. string names, for display in test mode.
lamplists
Defines the lamplists. The attribute list defines an ordered list of lamps. Each attribute can be a physical lamp name, as defined in the [lamps] section; a range of lamps in the form lamp_start..lamp_end; or another lamplist name, allowing for nested declarations.
containers
Defines the containers/ball devices. The attribute list begins with the name of the release solenoid, followed by the names of the counting switches (in order from entry to exit).

The trough container should be marked with the attribute trough.

templates
Lists the template instantiations. The key gives a name to the instance. The first property should be the name of the common driver that implements it. The remaining properties give values to all of the driver's parameters.
tests
Defines additional hardware tests that are put into the Tests menu. The name of the item corresponds to the name of the test item. These should be defined in a separate C file from the rest of the machine code, and linked into the TEST_OBJS section with the rest of the test module.
deffs
Define the display effects.
leffs
Define the lamp effects.
adjustments
Define the machine's feature adjustments. For each adjustment, you give a type, which is an object that defines its allowable values, and a default.
audits
Defines feature audit variables.
system_sounds
Gives the machine-specific sound codes that are to be used for certain system events, like coin insertion and tilt.
system_music
Likewise but for the default background music to be used in well-known situations.
highscores
Defines the default high scores.
flags
Declares bit flags. These are handled similarly to lamps; they are per-player. All flags are zero at the start of each player's game.
globalflags
Like ‘flags’, except these are global and not per-player. These must be initialized explicitly.
scores
Declares the score table, which associates a short 8-bit ID to a binary-coded decimal score value. Some of the scoring APIs use IDs instead of the expanded values for space efficiency.
fonts
Declares which fonts should be included in this game.
timers
Declares the freerunning timers that are needed.

B.7 How genmachine works

genmachine is a Perl script. It parses all of the md commands and builds a giant hash with all of the data. genmachine is invoked multiple times with different options, requesting that different output files be generated. All of the output files are C or H files put into the 'build' subdirectory, which are then compiled normally.

For the Perl programmer, each object declaration is itself a Perl anonymous hash, where each property of the object is one of the hash entries. Using the variable(value) syntax, it is possible to put anything into the object definition. However, only certain keys are recognized by the output functions. Adding new properties generally doesn't require a parser change, but only a change to the output routines. Binary properties and well-known object classes do need to be stated – there are constant tables at the top of the script that declare these.