Disclaimer: This information is provided as is. There may be errors in this information. You may use this information only if you agree that Minimalist / Coinop.org, its employees, and noted authors will never be held responsible for any damage, injury, death, mayhem, etc. caused by errors in the information. When working with high voltage, never work alone and always follow safety precautions.

Document Title: [Boris - Understanding Mame drivers 1.html (html file)]

Understanding MAME Drivers Volume 1: Data Structures v1.0 Original URL: http://atarihq.com/danb/files/mamedrv1.txt

Understanding MAME Drivers
Volume 1: Data Structures v1.0
by Daniel Boris

Table of Contents

1.0 Introduction
2.0 /drivers/rockola.c
2.1 GameDriver Structure
2.2 MachineDriver Structure
2.3 ROM Definition
2.4 MemoryReadAddress Structure
2.5 MemoryWriteAddress Structure
2.6 Input Ports
2.7 GfxDecodeInfo Structure
2.8 GfxLayout Structure
3.0 Linking in the Driver

1.0 Introduction

The purpose of this document is to help people understand how a MAME driver
works and to help people who may want to write their own MAME drivers.
A driver is a set of files that are part of the MAME source that define
the operation of a specific arcade game.

For this document I will be describing the driver for the game Zarzon.
Before reading this document you may want to read over my Decoding Schematics
document which describes the hardware of Zarzon.

The driver I am going to describe is based on the MAME 0.33 source code for
DOS. Some of the things described here may not apply to other versions of the
MAME source.

The Zarzon driver can be found in two files, /driver/rockola.c and
/vidhrdw/rockola.c. It is found in this file because it's hardware is
similar to some of the other Rockola games. The data structures that make
up MAME are linked together in layers so you may not understand some of the
things in the higher level layers until you read about the lower level layers.

2.0 /drivers/rockola.c

The first part of the driver is contained in the /drivers/ directory. The files
in this directory are the main part of a MAME driver. They contain all
the data structures that define how the machine that is being emulated works.

2.1 GameDriver Structure

The highest level structure for each game in MAME is the GameDriver structure.
The GameDriver structure for Zarzon looks like this (the numbers at the
start of each line are there so I can refer to the lines easily in the text):

1  struct GameDriver zarzon_driver =
2  {
3     __FILE__,
4     &satansat_driver,
5     "zarzon",
6     "Zarzon",
7     "1981",
8     "[SNK] (Taito America license)",
9     "Dan Boris\nTheo Philips",
10    0,
11    &satansat_machine_driver,
13    zarzon_rom,
14    0, 0,
15    0,
16    0,      /* sound_prom */
18    satansat_input_ports,
20    satansat_color_prom,0,0,
23    0, 0
24  };

Line 1 starts the declaration of the driver. The name of the structure, in
this case zarzon_driver, is usually the name that is used to start the game
followed by "_driver".

Line 3 is the source file that this driver is contained in. It should always
be set to: __FILE__

If this game is a clone of another game, then line 4 should be a pointer
to the GameDriver structure of the parent game. For example Zarzon is a clone
of Satan of Saturn.

Line 5 is the name that is used to start the game and also the name of the
directory/zipfile where the ROMS for the game can be found. It has to be 8
characters or less and must be unique to each game.

Line 6 is the full name of the game.

Line 7 is the year the game was released and line 8 is the name of the company
that released it. Line 9 is the credits that are displayed when the driver is

Line 10 is designed to hold various flag values. Currently the only flag that
is defined is GAME_NOT_WORKING which indicates that a game currently does not

Line 11 is a pointer to the MachineDriver structure that defines how the hardware
for this machine works. It is possible for more the one game to run on the
same machine hardware. For example there are a bunch of different versions
of Pac-Man that all run on the same hardware, so each of the games will have
it's own GameDriver structure, but they can all share the same MachineDriver

Line 13 is a pointer to a structure that defines what ROMS the game uses and
where to load them.

The two zeros in line 14 can be a pointer to a routine to decrypt roms and
a pointer to a routine to decrypt opdcodes in the ROM. These are optional
and are not used by this game.

Line 15 is a pointer to an array of samples names that the game is going
to use to produce sound. This game does not currently use samples so this
is left as 0.

Line 16 is a pointer to sound ROM data. This is not used by this game.

Line 18 is a pointer to the InputPort structure for this game. Note that this
is defined as part of the game not as part of the hardware since it is
responsible for things like dipswitches that change function from game
to game.

The three values in line 20 are pointers to palette and color tables
that are stored in the driver. These tables are currently being removed
from the code and put into the ROM images like they where in the original
games, so it is best to load these tables from disk. The first value is a
pointer to the palette prom for the game, the second is a pointer to a table
of actual color values that make up the game's palette and the third is a
pointer to a color lookup table.

Line 21 defines the orientation of the games monitor. Look at driver.h for
the legal values for this line.

Line 23 are pointers to routines that are used to load and save high scores.
Zarzon currently doesn't have high score saving so these are 0.

2.2 MachineDriver Structure

The next level data structure is MachineDriver. This defines the hardware
that this game runs on. In this situation Zarzon is a clone of Satan of Saturn
so the MachineDriver structure is called satansat_machine_driver.

1  static struct MachineDriver satansat_machine_driver =
2  {
3          /* basic machine hardware */
4          {
5                 {
6                          CPU_M6502,
7                          11289000/16,    /* 700 kHz */
8                          0,
9                          satansat_readmem,satansat_writemem,0,0,
10                         satansat_interrupt,2
11               },
12        },
13        60, DEFAULT_60HZ_VBLANK_DURATION,       /* frames per second, vblank duration */
14        1,      /* single CPU, no need for interleaving */
15        0,
17        /* video hardware */
18        32*8, 32*8, { 0*8, 32*8-1, 0*8, 28*8-1 },
19        satansat_gfxdecodeinfo,
20        32,4*4 + 4*4,
21        satansat_vh_convert_color_prom,
24        0,
25        generic_vh_start,
26        generic_vh_stop,
27        satansat_vh_screenrefresh,
29        /* sound hardware */
30        0,0,0,0
31  };

Line 1 begins the definition of the MachineDriver for this game.

Lines 4-12 define the cpu that this game uses. It is possible for a game
to have multiple CPUs. Each cpu would have to have it's own MachineCPU
structure and each would be listed one after the other in the MachineDriver
structure. Zarzon only uses one cpu.

Line 6 defines the type of CPU, in this case a 6502.

Line 7 is the clock speed that the CPU is running at. This is important to 
keeping the game running at the correct speed. For Zarzon it is 11289000/16.
It is written this way because the main clock on the Zarzon board is 11289000
and is divided down by 16 by hardware on the board.

Line 8 is the memory region that this processor uses. When you load ROMS
you will define one or more memory regions to hold the data from the ROMS.
Each processor will have it's own memory region and there may be other
memory regions allocated for things like graphics ROMS. In this case this
cpu uses memory region 0.

Line 9 contains 4 pointers to the structures that define how to handle memory
and IO accesses. The pointers are Memory Read, Memory Write, IO Read, IO Write.
The 6502 does not have IO access so these are not defined.

Line 10 determines how vertical blank interrupts are handled. The first value is a
pointer to the routine that will handle the interrupt. The second value is
how many interrupts there should be per frame, this is usually 1.

Line 13 indicates how many video frames per second the game hardware
generates and the second value on that line indicates how long the VBLANK
should last (see driver.h for more info on this).

Line 14 is the CPU interleave value. This determines how often MAME switches
back and forth between each of the CPU's in the machine. The higher the value
the more often MAME will switch between processor. The more often it switches,
the slower the emulation will be, but it is sometimes necessary to keep processors
in sync with each other. Since Zarzon uses only one CPU this value is set to 1.

Line 15 is a pointer to a routine that is used to do any special initialization
that this machines hardware needs.

Line 18 defines the height and width of the games screen in pixels, and how
big the visible area of the screen is. Since Zarzon uses tile based graphics
the 32*8 notation is used to indicate that the screen is 32 tiles across and
each tile is 8 pixels wide, the screen is also 32*8 pixels high. The next
four values define the corners of the visible area of the screen. For zarzon
the upper left corner is at 0,0 and the lower right is at 255,223.

Line 19 is a pointer to the data structure that defines how the graphics in
the graphics ROMS are formatted.

In line 20 the first value is the number of colors in the games color palette.
The second value is the number of entries in the game's color lookup table.

Line 21 is a pointer to a routine that is called to convert the raw color
prom data into actual palette RGB values. This routine is usually found in

Line 23 is the video attributes. The attributes for this game indicate that
it is a raster game (as opposed to vector) and that it supports dirty rectangle
handling. For a complete list of attributes look at driver.h.

Line 24 ???

Lines 25,26 and 27 are pointers to the routines to start the display hardware,
stop the display hardware and refresh the screen respectively. Zarzon uses
MAME's generic start and stop routines since it does not need any special
setup for video. Most games will have their own screen refresh routine which
is the routine that actually draws the video display for the game.

The remainder of this structure describes the sound hardware. Since Zarzon
does not currently support sound I won't discuss this part of the driver at
this point.

2.3  ROM Definition

The next section of the driver defines what ROM images the game needs to
load and where to load them. This section does not look like normal C code
since macros are used to make it more readable.

1  ROM_START( zarzon_rom )
2     ROM_REGION(0x10000)     /* 64k for code */
3         ROM_LOAD( "ZARZ122.07", 0x4000, 0x0800, 0xa260b9f8 )
4         ROM_LOAD( "ZARZ123.08", 0x4800, 0x0800, 0xf2b8072c )
5         ROM_LOAD( "ZARZ124.09", 0x5000, 0x0800, 0xdea47b9a )
6         ROM_LOAD( "ZARZ125.10", 0x5800, 0x0800, 0xa30532d5 )
7         ROM_LOAD( "ZARZ126.13", 0x6000, 0x0800, 0x043c84ba )
8         ROM_LOAD( "ZARZ127.14", 0x6800, 0x0800, 0xa3f1286b )
9         ROM_LOAD( "ZARZ128.15", 0x7000, 0x0800, 0xfbc89252 )
10        ROM_LOAD( "ZARZ129.16", 0x7800, 0x0800, 0xc7440c84 )
11        ROM_RELOAD(             0xf800, 0x0800 ) /* for the reset/interrupt vectors */
12        ROM_LOAD( "ZARZ130.22", 0x8000, 0x0800, 0x78362c82 )
13        ROM_LOAD( "ZARZ131.23", 0x8800, 0x0800, 0x566914b5 )
14        ROM_LOAD( "ZARZ132.24", 0x9000, 0x0800, 0x7c4f3143 )
16    ROM_REGION(0x1000)  /* temporary space for graphics (disposed after conversion) */
17        ROM_LOAD( "ZARZ135.73", 0x0000, 0x0800, 0xbc67fa61 )
18        ROM_LOAD( "ZARZ136.75", 0x0800, 0x0800, 0x2364fe46 )
20    ROM_REGION(0x1000)  /* sound data for Vanguard-style audio section */
21        ROM_LOAD( "ZARZ133.53", 0x0000, 0x0800, 0x4b404b14 )
22        ROM_LOAD( "ZARZ134.54", 0x0800, 0x0800, 0x01380400 )

Line 1 defines that start of the ROM info for this game the name in parenthesis
(zarzon_rom) is the name that goes into the GameDriver structure.

Line 2 defines that start of a ROM region. The value in parenthesis is the size
of the region. This line for example define ROM region 0 to be 64K in size.

Lines 3 through 14 are the ROMs that are loaded into the current ROM region.
The first parameter in each line is the name of the ROM file to load. The
second parameter tells where in that memory region the ROM should be loaded.
The third parameter tells how many bytes long the ROM is. The final parameter
is the checksum of the ROM that is used to validate if the ROM is correct or
not. For example, line 3 would load 0x800 bytes from the file ZARZ122.07
starting at address 0x4000 in memory region 0.

Line 11 is a little different then the others. This line is a ROM_RELOAD
instead of a ROM_LOAD. ROM_RELOAD is used to reload the ROM that was just
loaded into a different area of memory. So line 10 loads ZARZ129.16 into
memory at 0x7800, and line 11 loads it again at memory location 0xf800.
The main purpose of this is that if the rom is missing or has a bad checksum
it will not be reported twice and an error like it would if you simply used
ROM_LOAD again.

Line 16 ends ROM region 0 and starts ROM region 1. In Zarzon this region of
memory is used to store the graphics ROMs. Line 20 ends ROM region 1 and starts
ROM region 2 which is used to store the PROMS that are used for sound
generation. Zarzon does not support sound yet so these ROMs just go unused.

Line 23 ends the definition of the ROMs.

2.4 MemoryReadAddress Structure

The MemoryReadAddress structure defines the memory map for the machine. It
tells MAME what it should do when the processor wants to read data from a
specific memory location. Here is the MemoryReadAddress structure for
Zarzon (remember Zarzon is a clone of Satan of Saturn, thus the name

1  static struct MemoryReadAddress satansat_readmem[] =
2  {
3        { 0x0000, 0x1fff, MRA_RAM },
4        { 0x4000, 0x97ff, MRA_ROM },
5        { 0xb004, 0xb004, input_port_0_r }, /* IN0 */
6        { 0xb005, 0xb005, input_port_1_r }, /* IN1 */
7        { 0xb006, 0xb006, input_port_2_r }, /* DSW */
8        { 0xb007, 0xb007, input_port_3_r }, /* IN2 */
9        { 0xf800, 0xffff, MRA_ROM },
10       { -1 }  /* end of table */
11 };

Line 1 start the definition of the structure. The name, satansat_readmem in
this case, goes into the MachineDriver structure.

Each line in the structure starts with 2 numbers that are the starting and
ending address of a section of memory. Following this are one or more items
that define what this section of memory is and how it should be handled.

Line 3 defines a memory region starting at 0x0000 and ending at 0x1FFF. It is
defined as MRA_RAM which means that the region is RAM. When a read is done to
an address in this section it will come from the corresponding location in
the memory region (defined when you loaded the ROMS) for this processor.

Line 4 is defined as MRA_ROM which means this section is ROM. This essentially
behaves the same way as MRA_RAM.

Line 5 shows a slightly different type of memory section. Since the start and
end addresses are the same it means that this section is only one byte long,
which is perfectly legal to do. For the function of this region instead of
having a pre-defined function it has the name of a routine. When the processor
reads from this memory location MAME will call the routine input_port_0_r and
this routine will return the appropriate value. In this situation
input_port_0_r is a function defined within MAME but it could have just as
easily been a routine you wrote yourself. input_port_0_r will be discussed
in further detail in the section on the IO structures.

Line 6,7, and 8 all function basically the same as line 5.

Line 9 defines a final piece of ROM from address 0xf800 to 0xffff.

Line 10 is set to -1 to indicate the end of the table

2.5 MemoryWriteAddress Structure

The MemoryWriteAddress structure is setup basically the same as
MemoryReadAddress, but instead of handling reads from memory it handles
writes to memory.

1  static struct MemoryWriteAddress satansat_writemem[] =
2  {
3          { 0x0000, 0x03ff, MWA_RAM },
4          { 0x0400, 0x07ff, MWA_RAM, &rockola_videoram2 },
5          { 0x0800, 0x0bff, videoram_w, &videoram, &videoram_size },
6          { 0x0c00, 0x0fff, colorram_w, &colorram },
7          { 0x1000, 0x1fff, rockola_characterram_w, &rockola_characterram },
8          { 0x4000, 0x97ff, MWA_ROM },
9  //      { 0xb000, 0xb000, satansat_sound0_w },
10 //      { 0xb001, 0xb001, satansat_sound1_w },
11         { 0xb002, 0xb002, satansat_b002_w },    /* flip screen & irq enable */
12         { 0xb003, 0xb003, satansat_backcolor_w },
13         { -1 }  /* end of table */
14 };

Line 3 defines a section of memory from location 0x0000 to 0x03FF and defines
it as being RAM.

Line 4 looks similar to line 3 in that it also defines the section as RAM,
but it has one more parameter then line 3. The &rockola_videoram2 is a pointer
variable that is declared as:

unsigned char *rockola_videoram2;

When MAME sets up the memory for this machine it will put the address of the
memory section 0x400-0x7ff in the pointer rockola_videoram2. This will allow
this section of memory to be accessed easily in other parts of the driver.
It is important to remember that the memory for this section is still in the
memory region declared during ROM loading, rockola_videoram2 is simply a
pointer to a part of this region.

Line 5 gets a little more complicated. As usual we define the memory section,
0x800 to 0xbff in this case. Next we have videoram_w, which is a routine that
will be called when ever a write is done to this section. videoram_w happens
to be a predefined routine in MAME. Next we have &videoram which is a pointer
variable just like in line 4. When the memory is setup &videoram will point to
this section of memory. Finally we have &videoram_size. When memory is setup
MAME will put the size of this memory region into the variable videoram_size.

Line 6 works just like line 5 but in this case we do not need the size of this
section on memory so the size variable is not included. colorram_w and colorram
are both defined in the MAME core.

Line 7 is just like line 6 except that custom variables are used instead of
using standard built in ones.

Line 8 defines a section of memory as ROM.

Lines 9-12 are similar to lines 5-8 in MemoryReadAddress. When these addresses
are written to the corresponding routines are called to handle the write.

Line 13 once again we end the structure with a -1.

2.6 Input Ports

The next section of the driver we will look at defines the operation the
machines input ports. This structure is used to define things like joystick
inputs, coin inputs, dipswitches, etc. I have broken this section up into a
couple smaller sections:

1 INPUT_PORTS_START( satansat_input_ports )
2    PORT_START  /* IN0 */

Line 1 begins the definition of the input ports for this game. The name,
satansat_input_port goes into the GameDriver structure.

Line 2 begins the definition of the first port (input port 0).

Lines 3 through 10 define what each bit in this port does. The first parameter
in each line is the mask. Each bit that is a 1 in the mask will be effected
by the function of this line. So in line 3 the mask is 0x01 which means that
this line effects bit 0. The next parameter sets whether this function is
active high or active low. the final parameter sets the function for that bit
and any special attributes it has. In line 3 the function is IPT_JOYSTICK_LEFT
which indicates that this bit is controlled by the joystick being pushed
left. The IP_ACTIVE_HIGH parameter in this line would mean that when the stick
is pushed left this bit should be a 1 and at all other times it should be a 0.
The IPF_2WAY attribute indicates that this is a 2 way joystick, it can only
be pushed left and right.

Line 4 is the same as line 3 but for JOYSTICK_RIGHT.

Line 5 defines a button. BUTTON1 is usually the 'fire' button for the

Line 6,7,8 define a second 2 way joystick and button, but this one has the
attribute IPF_COCKTAIL. This indicates that this stick is used in the cocktail
table version of the machine.

Line 9 and 10 define a second button for both the normal machine and the
cocktail version.

This is the next section of the input ports, it defines the bits for port 1:

1    PORT_START      /* IN1 */

Line 1 starts the second port (port1).

Lines 2 and 3 are similar to the lines in the first input port. Line 2
defines START1 which is usually the 1 player start button and line 2
defines START2 which is usually the 2 player start button.

If you look at line 4 you will notice that there is more then 1 bit set
in the mask. You can have as many bits in the mask set to 1 as you like
in each entry. Each bit that is set to 1 will be effected by the function
of the line. The function for line 4 is IPT_UNKNOWN which means that the
function of that bit is not currently known. Since this line is defined as
IP_ACTIVE_HIGH, and unknown inputs can never become active, these bits will
always be 0.

Line 5 is similar to line 4, but since it is IP_ACTIVE_LOW the bit will
always be high.

The next section is a little different since it defines a dipswitch instead
of inputs. Even though it is a dipswitch it is still referred to as an input
port, in this case input port 2.

1    PORT_START  /* DSW */
2       PORT_DIPNAME( 0x01, 0x01, "Cabinet", IP_KEY_NONE )
3       PORT_DIPSETTING(    0x01, "Upright")
4       PORT_DIPSETTING(    0x00, "Cocktail" )
5       PORT_DIPNAME (0x0a, 0x00, "Coinage", IP_KEY_NONE )
6       PORT_DIPSETTING (   0x08, "2 Coins/1 Credit" )
7       PORT_DIPSETTING (   0x00, "1 Coin/1 Credit" )
8       PORT_DIPSETTING (   0x02, "1 Coin/2 Credits" )
9       /* 0x0a gives 2/1 again */
10      PORT_DIPNAME (0x04, 0x00, "Bonus Life", IP_KEY_NONE )
11      PORT_DIPSETTING (   0x00, "5000" )
12      PORT_DIPSETTING (   0x04, "10000" )
13      PORT_DIPNAME (0x30, 0x00, "Lives", IP_KEY_NONE )
14      PORT_DIPSETTING (   0x00, "3" )
15      PORT_DIPSETTING (   0x10, "4" )
16      PORT_DIPSETTING (   0x20, "5" )
17      /* 0x30 gives 3 again */
18      PORT_DIPNAME (0x40, 0x00, "Unknown", IP_KEY_NONE )
19      PORT_DIPSETTING (   0x00, "Off" )
20      PORT_DIPSETTING (   0x40, "On" )
21      PORT_DIPNAME (0x80, 0x00, "Unknown", IP_KEY_NONE )
22      PORT_DIPSETTING (   0x00, "Off" )
23      PORT_DIPSETTING (   0x80, "On" )

Line 1 defines the start of the input port as usual.

Line 2 defines that start of the first section of the dipswitch. The first
parameter is the mask just like in a normal input port. Each bit that is a
1 in the mask will be effected by this dipswitch. The next parameter is the
default value for the dipswitch, in this case it is 0x01. The next parameter
is the name of the dipswitch, this will be displayed in the dipswitch menu
in MAME. The final parameter allows you to assign a key to control this
dipswitch. Since it is IP_KEY_NONE is means that there is no key to control it
and it has to be set on the dipswitch menu.

Lines 3 and 4 are PORT_DIPSETTINGs. These define the different settings for
the dipswitch section that we just defined. The first parameter in PORT_DIPSETTING
is the value that corresponds to the setting, and the second parameter is the name
of that setting. For example if the dipswitch "Cabinet" is set to "Upright"
then bit 0 of the port will be set to 0x01. If it is set to "Cocktail" then
bit 0 of the port will be set to 0x00.

Line 5 begins the definition of the next section of the dipswitch, this time
called "Coinage". Notice that there are two bits set in the mask meaning that
this dipswitch section can have more then two combination.

Lines 6-8 define the settings for the "Coinage" dipswitch. There are four
possible combinations for this dip section, but only 3 of them are defined.
As indicated by the comment in line 9, the fourth setting, 0x0A, is the
same as the setting for 0x08.

Lines 13-23 define the remained of the dipswitch sections and settings.

Here is the final section of the input ports:

1    PORT_START  /* IN2 */
3                        IP_NAME_DEFAULT, IP_KEY_DEFAULT, IP_JOY_DEFAULT, 1 )
5       PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNKNOWN )        /* connected to a counter - random number generator? */

Line 1 starts the definition of the final input port, port 3.

Line 2 is another type of port bit definition. PORT_BITX allows us to specify
some extra parameters for the port. The function of the bit is IPT_COIN1 which
is the first coin input. The attribute IPF_IMPULSE indicates that this is an
impulse input meaning the bit goes active for a period of time and then
goes back inactive on it's own. The only additional parameter that is used
in this line is the 1 at the end which is the length of the impulse time. All
the other additional parameters are set to DEFUALT since we do not need them.

Line 4 shows one more different function, IPT_UNUSED. This indicates that these
bits are not used by the game at all, usually meaning that they are not even
connected in the hardware. Just like UNKNOWN these can never become active. Since
the bit is defined as IP_ACTIVE_LOW the bits will always be high.

Line 6 marks the end of the input ports for this machine.

2.7 GfxDecodeInfo Structure

GfxDecodeInfo is the first of two structures that determine how the graphics
data for the game will be decoded. Graphics data is usually stored in ROMS
on the game board and these ROMS are organized in such a way as to make
it easy for the circuitry to draw the display image. Unfortunately the way
the data is stored in ROMS is usually not convenient for use in emulation.
The GfxDecode structures tell MAME how to convert the raw graphics ROMS into
a more useable format.

1  static struct GfxDecodeInfo satansat_gfxdecodeinfo[] =
2  {
3     { 0, 0x1000, &charlayout256,   0, 4 },      /* the game dynamically modifies this */
4     { 1, 0x0000, &charlayout256, 4*4, 4 },
5     { -1 }
6  };

Line 1 begins the definition of the GfxDecodeInfo structure. The name,
satansat_gfxdecodeinfo in this case, goes into the MachineDriver structure.

This machine has two different methods that are needed to decode the graphics,
lines 3 and 4 each define one of these methods. The first parameter in each of
these lines tells MAME in which memory region the data for the graphics can
be found. Line 4 is pretty obvious. It indicates that the graphics data can
be found in region 1 which if you look at the ROM load structure you can
see that the graphics ROMS are loaded into this region. Line 3 indicates that
the data comes from region 0 which is the processor's memory region. The reason
for this is that Zarzon stores some of it's graphics data in RAM. The next
parameter tells where within that region the data comes from. The third
parameter is a pointer to a GfxLayout structure which defines exactly how
the graphics data is formated.

The final 2 parameters in each line are used to determine the colors to draw
the graphics with. The first number in this pair is the offset into the
color lookup table where the colors for these graphics starts. The second
number in the pair is the total number of colors this graphic uses.

2.8 GfxLayout structure

The GfxLayout structure is the second part of defining how the graphics
ROMS are formatted. This structure defines the actual format of the data.

1  static struct GfxLayout charlayout256 =
2  {
3        8,8,    /* 8*8 characters */
4        256,    /* 256 characters */
5        2,      /* 2 bits per pixel */
6        { 0, 256*8*8 }, /* the two bitplanes are separated */
7        { 0, 1, 2, 3, 4, 5, 6, 7 },
8        { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
9        8*8     /* every char takes 8 consecutive bytes */
10  };

This can be a little confusing so follow it carefully.

Line 1 begins the structure. The name, charlayout256 in this case, goes into
the GfxDecodeInfo structure.

Line 3 defines the height and width of each character in pixels. So the characters
in Zarzon are 8 pixels wide by 8 pixels high.

Line 4 defines how many characters are in the graphics ROMS, in this case
there are 256 characters.

Line 5 defines how many bits are needed for each pixel in the character. Zarzon
has 2 bits per pixel. Since there are 4 different combinations of 2 bits
(00,01,10,11) each character can have up to 4 colors.

Line 6 contains the offset in bits to the beginning of the data for each bit
plane. Since Zarzon has 2 bits per pixel (as defined in line 5) it also has
2 bit planes. In the Zarzon hardware each of the two bits that makes up each
pixel is stored in a separate ROM chip. The first graphics ROM we loaded contains
the first bit plane, so the first bit plane offset is 0. The second ROM we
loaded contains the second bit plane so to get to it we have to skip over all
the data in the first ROM. The offset to the second plane is 256*8*8, where does
this number come from? The 256 is for the 256 characters in the ROM, the first
*8 is the because each character is 8 lines high so there are 8 bytes for each
character. 256*8=2048 which is the length of the graphics ROM in bytes. The
bit plane offsets are in units of bits, since there are 8 bits in each line
of each character we have to multiply the 2048 x 8 giving us a total offset of
256*8*8 = 16384.

Line 7 and 8 tell where to get the data for each pixel at each coordinate in
the characters. The characters in Zarzon are 8x8 pixels. Line 7 gives the
offset for each pixel across the character. Line 8 gives the offset for each
line down the character. This sounds a little confusing but it will be clearer
when we look at an example.

Line 9 gives the distance in bits between two consecutive characters. Each
character in Zarzon requires 8 bytes and each byte has 8 bits, so the total
is 8*8 = 64.

Ok, now lets look at how this all works together. When MAME decodes the
graphics ROMS it steps through the characters one bye one. So lets say it
wants to decode character number 10. Zarzon uses 2 bit planes (line 5) so
MAME first has to find the start of the data for each bit plane. From the
GfxDecodeInfo structure we know that the graphics ROMS are in memory region
1 starting at offset 0. From line 6 we know that bit plane one starts at
offset 0 and the bit plane 2 starts at offset 16384. From line 9 we know that
each character requires 64 bits, so we can calculate where the data for each
bit plane starts for this character:

Bit plane 1, 10th character * 64 bits per character + 0 plane offset = 640
Bit plane 2, 10th character * 64 bits per character + 16384 plane offset = 17024

Now that we know where in the data each bit plane starts, we can start decoding
the character. We start with the pixel in the upper left corner of the character.
This will be the first pixel in the first line. To find the offset to this
bit in the data look at the first value in line 8, 0*8, this is the offset
to the data for the first line on the character. Next look at the first value
in line 7, 0, this is the offset to the data for the first pixel in the each line.
So the offset to the data for this pixel will be (0*8) + 0. For the second
pixel on the first line we have 0*8 again since we are still on  the first line
but now we use the second value in line 7, which is 1. The offset for the second
pixel will be (0*8)+1. We continue the same way for each of the 8 pixel on the
first line. To get the first pixel in the second line of the character we
start with the second value in line 8 which is 1*8. The first pixel in the
second line will be (1*8)+0 = 8, the second pixel will be (1*8)+1 = 9, etc.

3.0 Linking In The Driver.

The final thing I will cover in this volume is how to link your driver into
the MAME source. First of all you have to put the names of all your source
files in the MAKEFILE. Since Zarzon is in the rockola driver source it will
look like this in the MAKEFILE:

obj/vidhrdw/rockola.o obj/sndhrdw/rockola.o obj/drivers/rockola.o \

This will compile the rockola driver and link it into MAME, but MAME still
does not know that the game exists, this requires one more step. In the file
driver.c there is an array of pointers to each of the GameDriver structures in
MAME. The line for zarzon looks like this:

&zarzon_driver,         /* (c) 1981 Taito, gameplay says SNK */

You also need to declare this in driver.c so that the compiler can find it:

extern struct GameDriver zarzon_driver;

That's all there is to linking the driver into the code.