PacMan Memory-Map

Address
1111 1100 0000 0000
5432 1098 7654 3210
Bus Cycle
Affect
0000 0000 0000 0000
Read/Write
0000        Start of ROM
0011 1111 1111 1111
Read/Write
3FFF        End of ROM
0100 0000 0000 0000
Read/Write
4000        Start of Char Video RAM (See below)
0100 0011 1111 1111
Read/Write
43FF        End of Character Video RAM
0100 0100 0000 0000
Read/Write
4400        Start of Character Color RAM
0100 0111 1111 1111
Read/Write
47FF        End of Character Color RAM
0100 1000 0000 0000
Read/Write
4800        Start of CPU Ram
0100 1111 1110 1111
Read/Write
4FEF        End of CPU RAM
0100 1111 1111 xxxx
Read/Write
   Sprite Hardware

   0x4ff0 SPRITE_BASE -- 8 pairs of 2 bytes

   byte0: bits 2-7 sprite image number
   byte0: bit 0 Y flip
   byte0: bit 1 X flip
   byte1: color

   Byte 0:                  Byte 1:
   [7][6][5][4][3][2][1][0] [7][6][5][4][3][2][1][0]
   [ Sprite number  ][x][y] [ color ]

0x9060 SPRITE_COORDS -- xy pairs for 8 sprites

0101 0000 00XX XXXX
Write
9000-903F        out
0101 0000 0100 XXXX
Write
9040-904F        WR0
0101 0000 0101 XXXX
Write
9050-905F        WR1
0101 0000 0110 XXXX
Write
9060-906F        WR2 ..... SPRITE_COORDS - xy pairs for 8 sprites
0101 0000 0111 XXXX
Write
9070-907F        Not Used
0101 0000 10XX XXXX
Write
9080-90BF        Not Used
0101 0000 11XX XXXX
Write
90C0-90FF        Watch Dog Reset
0101 0000 00XX XXXX
Read
9000-903F        IN0 - Data bus:
Bit
7
6
5
4
3
2
1
0
Meaning
CREDIT
COIN2
COIN1
DIP6
DOWN
RIGHT
LEFT
UP
0101 0000 01XX XXXX
Read
9040-907F        IN1 - Data bus:
Bit
7
6
5
4
3
2
1
0
Meaning
TABLE
START1
START2
TEST
DOWN2
RIGHT2
LEFT2
UP2
0101 0000 10XX XXXX
Read
9080-90BF        DIPSWITCH - Data bus:
Bit
7
6
5
4
3
2
1
0
Meaning
Solder1
Solder2
DIP5
DIP4
DIP3
DIP2
DIP1
DIP0
0101 0000 11XX XXXX
Read
90C0-90FF        Not Used
XXXX XXXX XXXX XXXX
IN/OUT
Interrupt Register


Character RAM Layout

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX =43C0
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX =43E0
VVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
VVVVVVVVVVVVVVVVVVVVVVVVVVVV
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX =4000
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX =4020

Key:

XVThis is a standard screen location.

XThis location exists, but is not visible on the screen.

This is not visible on the screen, nor is there any memory associated with this block. It is a placeholder.

The direction of the arrow gives the direction of the next character more or less.

Character RAM starts at 0x4000.

XThis is offset 0x00 in character memory. Therefore, if you write into location 0x4000 it will go here.

XThis is offset 0x20 in character memory.

This is offset 0x40 in character memory.

This is offset 0x60 in character memory.

The rest of the blue section continues down and to the left.

XThis is offset 0x3C0 in character memory.

XThis is offset 0x3E0 in character memory.







Pac-Man Memory layout:

0000 - 3FFF ROM
0000 - 0FFF pacman 6e mspacman boot1
1000 - 1FFF pacman 6f mspacman boot2
2000 - 2FFF pacman 6h mspacman boot3
3000 - 3FFF pacman 6j mspacman boot4

4000 - 43FF Video RAM
4400 - 47FF Color RAM
4c00 - 4FFF CPU work-RAM
8000 - 9FFF ROM (Ms Pac-Man and Ponpoko only)
8000 - 8FFF mspacman boot5
9000 - 9FFF mspacman boot6

A000 - BFFF ROM (Ponpoko only)

memory mapped ports:

read:
5000               IN0
5040               IN1
5080               DSW 1
50c0               DSW 2 (Ponpoko only)

IN0:     (5000)
01 up
02 left
04 right
08 down
10 rack test
20 coin 1
40 coin 2
80 coin 3

IN1:     (5040)
01 up
02 left
04 right
08 down
10 service
20 start 1
40 start 2
80 cabinet (set - upright)

write:
4FF0 - 4FFF         8 pairs of two bytes:

         the first byte contains the sprite image number (bits 2-7),
         Y flip (bit 0),
         X flip (bit 1);
         the second byte the color

5000            interrupt enable
5001            sound enable
5002            ????
5003            flip screen
5004            1 player start lamp
5005            2 players start lamp
5006            coin lockout
5007            coin counter
5040 - 5044 sound voice 1 accumulator (nibbles) (used by the sound hardware only)
5045            sound voice 1 waveform (nibble)
5046 - 5049 sound voice 2 accumulator (nibbles) (used by the sound hardware only)
504a            sound voice 2 waveform (nibble)
504b - 504e sound voice 3 accumulator (nibbles) (used by the sound hardware only)
504f            sound voice 3 waveform (nibble)
5050 - 5054 sound voice 1 frequency (nibbles)
5055            sound voice 1 volume (nibble)
5056 - 5059 sound voice 2 frequency (nibbles)
505a            sound voice 2 volume (nibble)
505b - 505e sound voice 3 frequency (nibbles)
505f            sound voice 3 volume (nibble)
5060 - 506f Sprite coordinates, x/y pairs for 8 sprites
50c0            Watchdog reset


I/O ports:
OUT on port $0 sets the interrupt vector





Programming For Pac-Man And Pengo Hardware

The Hardware


Scott "Jerry" Lawrence
pacman@absynth.com

2001-February-11


This document and all of the information in it is
freely distributable. I only ask that you leave it
intact, without modifying its contents. Enjoy!


The most recent version of this document can be found at:
http://www.cis.rit.edu/~jerry/Software/pengo

========================================
THE HARDWARE
========================================

Contents:
Introduction
Sprite Based Graphics
The Memory Map
Floating Sprite Hardware
Collision Detection
Color
Palette ROM Layout
Lookup ROM Layout
Color ROMS
Video RAM Layout
Watchdog Timer
Timing and Initialization
Control and Dipswitches
Other Registers
Acknowledgment


----------------------------------------
Introduction

Pac-Man and Pengo are two games from the early 1980's. Pac-Man came out in 1980, and Pengo in 1982. Pengo, was released by SEGA, as opposed to Pac-Man, which was released by Namco/Midway. Many variants of both machines also exist. There are over 30 different versions and bootlegs of Pac-Man, and on top of that, it is one of the most abundant and recognizable arcade video games. There are also quite a few games that work directly on Pac-Man hardware with a simple ROM swap. Eyes Ms. Pacman, Crush Roller, are amongst the list. However, you cannot just take a Pac-Man romset and drop it into Pengo, or vice versa.

So, why group them together?

The hardware in Pengo is a superset of the hardware in Pac-Man. That is to say that Pengo hardware can do everything that Pac-Man hardware can do, plus a little more. For example, Pengo supports twice as many graphics sets as Pac-Man. So you can see, that if you were to just start writing a program to be run on Pac-Man hardware, it should be trivial to get it working on Pengo hardware. Well, it is, and it isn't, let me explain;

Although the two machines posess similar hardware, they're not at the same places in memory. Think of it like on your PC if you had two parallel ports, and in one, you have your scanner, and in the other you have your Zip drive. If you were to bring your copy of windows and hardware over to another machine, it might have its parallel ports swapped, and then windows might get confused, cause it'd be telling scanner commands to the zip drive and vice-versa.

We have the same problem here.

For example, both machines posess joysticks. Pac-Man is wired such that the order is UP, LEFT, RIGHT, DOWN, whereas Pengo is wired such that the order is UP, DOWN, LEFT, RIGHT. But that's just the tip of the iceberg. Pac-Man only has half as much ROM "program" space as Pengo, so you have to limit how big your program gets to half of what Pengo is capable of if you want to be able to use it on both. And also as well, your RAM and Video Hardware are at different locations in memory on the two machines... but i'll get into that a bit later.

What I have done is to make a common environment so that you can write a program (or game) once. Then just by changing one line in a Makefile, it will be built for one or the other. That is to say that I have taken the hardware, and abstracted the specifics out so that you, as a programmer, needn't know exactly where things are. You can just use the RAM, or check to see if the user has moved right, etc. I've successfully built two different applications, and had it run identically on emulated Pac-Man and Pengo hardware.


----------------------------------------
Sprite Based Graphics

If you've done any programming for modern-day video hardware at all, then you're probably familiar with bitmapped raster graphics. Sprite based graphics are a little different. Instead of having a pixel by pixel resolution, you have a sprite by sprite based resolution. It is akin to text mode on a PC, where you have just 255 characters to work with. You can change the font, but you only get one font per screen. Some text-mode demos for the PC, like 'Textro' by OTM, actually build a new font for every image they want to draw. On the other hand, you could do things like ANSI graphics, which is using the standard textmode font to display low resolution images on your screen.

This is essentially what you have to work with on Pengo and Pac-Man hardware. (Crush Roller, Rally X, Arabian, and a few others either use the same or similar hardware.) About the only addition is that there is some extra hardware that lets you also display floating sprites over this tiled display at a pixel by pixel resolution.

So what is the resolution we have here?

The hardware displays a 28 by 32 tile of 8x8 pixel sprites.. Every character on the display can be using a different color set, and every character itself is a four-color character. Background sprites are 8x8 pixels, Floating sprites are 16x16 pixels. Background sprites can only be displayed in that 28x32 grid, whereas floating sprites can be anywhere in the 224x256 display. ( 8*28 x 8*32 ) = ( 224 x 256 )
The background sprites and the Floating sprites are stored in different roms, so you can have completely unrelated sprites in the background or floating over it in the foreground. However, they both reference the same color palettes. Pac-Man allows for only one set of each to be available. (One background sprite set and one floating sprite set.) Pengo hardware allows you to switch between two sets of each. (two background sprite sets, and two floating sprite sets). These can be switched between at runtime.


----------------------------------------
The Memory Map

So now you're wondering, how do I program for this? How do I draw something on the background, and move some floating sprites over it? Well, it's actually a lot easier than you might think.

All of the hardware is memory mapped. That is to say that the control registers for the hardware are at specific locations in memory. Unlike a PC, where all of the 'ports' require IO calls, you can just write out to a bit of memory to do stuff. On PC's, the Parallel port requires reading in from a port 0x37f, or writing out to that port to read or write the bits. This hardware would just have that port at a specific location in memory, so you can just read or write it like any other variable.

Let's look at the Pengo memory map:

Memory Location What it is

0x0000 - 0x7fff Program ROM
0x8000 - 0x83ff Video RAM
0x8400 - 0x87ff Color RAM
0x8800 - 0x8fff RAM

0x9000 Dip Switch 1
0x9040 Dip Switch 0
0x9080 Control Input 1
0x90c0 Control Input 0

etc...

If you look at this, you will notice that you have 32 kilobytes of ROM space, 1 kilobyte of video ram, 1 kilobyte of color ram, and 2 kilobytes of RAM. (Incidently, this is quite a bit more than the Atari 2600 VCS, which had _NO_ video ram, and 128 bytes of ram. The VCS was the most popular home machine when Pengo was out in the arcades.)

So, you can see that you don't have much elbowroom to work with.


So what is this Video RAM and Color RAM? Is the Color RAM where the
palettes go?

Nope. Palettes are stored elsewhere. I'll get to those in a bit.

The Video RAM is the space in memory where you setup the background tiles of sprites. This is almost the same as drawing with ANSI graphics in MS-DOS. The Video RAM is where you would write sprites to be displayed. For example, at coordinate (4,5) place the letter "J". The Color RAM is where you choose what colors the sprites in the video ram get displayed with. Again, at coordinate (4,5) set the color "Green". If you were to do both of those, you would have placed a Green "J" at coordinate (4,5) on the screen. You can modify one and leave the other alone. So you could constantly change the colors of coordinate (4,5), and the "J" will appear to cycle through colors, or flash or what have you.

One clever thing you can do is that you can display the same sprite with different colors. Think about Pac-Man... You have four ghosts chasing your little yellow circle dude around the maze. One Red, Pink, Aqua, and Orange. All four use the same sprite graphics, but with different colors.

The resolution of the palette is a set of four colors. That is to say that each palette entry consists of a collection of four colors. Each sprite (for this hardware) is a four-color sprite. I'll get into
color more in a bit...


----------------------------------------
Floating Sprite Hardware

So what are 'floating sprites' then?

This hardware also has an extra chip for adding sprites over the background tiles at arbitrary locations. I call these "floating sprites", since they float over the background, independant of it. You can have 8 floating sprites in Pac-Man, but only 6 in Pengo. Similarly to the Video and Color RAM, you specify the sprite and its color. But along with these, you also specify its location on the screen, as well as whether or not you want to flip it in the x and y directions.

This is how they got the single Pac-Man sprite to be facing left, right up and down without having to have too many repeats of the sprites. You just need one pointing up, and one pointing to the right. The rest is done by mirroring the sprite in hardware using the x and y flip.

So how do you use it?

This is easily done, not as easily said. heh. As with everything else, the hardware is the same between Pac-Man and Pengo, but is in a different memory locations on both. There are two important bits to look for. The first is the base registers, the second is the coordinate registers.

The base registers contain the sprite number, x/y flip, and color. These are all stored in two bytes for each floating sprite supported. (Pengo supports 6, Pac-Man supports 8 floating sprites.) For every sprite are these consecutive bytes. The two bytes for floating sprite 0 are at the base and base +1 addresses. The two bytes for floating sprite 1 is at the base+2 and base+3 address, and so on.

Base Registers:

Byte 0: Byte 1:
[7][6][5][4][3][2][1][0] [7][6][5][4][3][2][1][0]
[ Sprite number ][x][y] [ color ]


It really is as simple as you think it is. Just shove the number for the sprite you want in bits 2-7 of byte 0, set bits 1 and 0 on byte 0 if you want to flip the sprite horizontally or vertically. Also, just drop the color you want the sprite to be in Byte 1.

The color? Single color?

Well, not really. It's an entry into a palette, where each entry is a set of four colors. All sprites on this hardware are four color sprites. Color 0 is used to signify transparency on the sprite. When the sprite is a background tile (which i'll get into later) then color 0 is not transparent anymore. More about color in a bit...

The other registers you'll need to use are the coordinate registers. Similarly to the base registers, these are pairs of bytes, arranged sequencially. First the X value, then the Y value for sprite 0, then the x and y values for sprite 1 and so on.

Byte 0 is the X value for sprite 0. Byte 1 is the Y value for sprite 0.
Byte 2 is the X value for sprite 1. Byte 3 is the Y value for sprite 1.
And so on...

The coordinate is the location on the screen where the upper left of the sprite is positioned on the screen. The coordinates start on the bottom right of the screen. The first coordinate that the 16x16 sprite is completely visible is at 31x16. If it's lower than that, it starts appearing at the top of the screen. Be aware however that the sprite does not appear on the bottom 16 or top 16 pixels of the display. These are in the horizontally arranged background tiles which will be explained later in the Video RAM Layout section.

Horizontally, however, there is a section off the right and left sides of the screen where the sprites are invisible. That is to say that you can scroll a sprite off the left or the right


vertical wrap is visible
(239,256) +----------------------------+ (31,256)
| |
horizontal ~ ~ horizontal
wrap is hidden ~ ~ wrap is hidden
| |
(239,16) +----------------------------+ (31,16)
vertical wrap is visible


----------------------------------------
Collsion Detection

If you're going to have floating sprites, you're probably going to need some way to tell when they overlap. This is called "Collsion Detection", where you're detecting when one sprite "collides" with another sprite, or a wall in your maze, or the like.

There are many ways to do this, some require many cycles of processor time, some require very few, some are very accurate, and some are very 'messy'.

For most applications, a quick, messy algorithm is really about all you will need. (Besides, it gives you more time for your game code.)


if (sprite_x % (sprite width) == sprite_N_x % (sprite width))
{
/* they're about in the same column... check the row now */
if (sprite_y % (sprite height) == sprite_N_y % (sprite height))
{
/* the sprite has collided with sprite_N. */

/* insert appropriate code here. */
}
}


It's not the most accurate routine, but it will work for most games.


----------------------------------------
Color

There is no mechanism or ability to change the color or palettes once the ROMS have been created. The next section will describe how the palette roms are layed out, so that you can modify them if you like.

There are two different roms here. The first is the Palette ROM. This one contains all of the individual colors we may wish to use. The second is the Lookup ROM. This rom contains collections of four-color entries which are used to color the sprites.

----------------------------------------
Palette ROM Layout

One byte specifies a color. It specifies an RGB value. Three bits for
each red and green, and two bits for blue. (Your eye and video display
systems are weak in the blue region, so this is not a problem at all.) The Palette ROM is just a collection of 32 1 byte entries, specifying
all of the colors we may wish to use in our lookup table entries. (Both
Pac-Man and Pengo have 32 entries available to them.)

For example, if you're going to be using Red multiple times, you don't need to have multiple Red entries. Just one. The lookup rom just references that specific "red" entry in the Palette ROM for each instance of "red" that it needs.


for each entry:
bits 7,6 - blue
bits 5-3 - green
bits 2-0 - red

ie:
Red = %0000 0111 = 0x07
Green = %0011 1000 = 0x38
Blue = %1100 0000 = 0xc0

Yel = %0011 1111 = 0x3f
Cyan = %1111 1000 = 0xf8
pur = %1100 0111 = 0xc7

etc...

byte1 is color0
byte2 is color1
etc


----------------------------------------
Lookup ROM Layout

This is just a collection of four-byte sets, specifying each of the color entries available for the Color RAM or Floating Sprite hardware. You will reference one of these color entries for each sprite you want to put to the screen.

Quite simply, they specify what color 0, 1, 2, and 3 on the sprite maps to on the palette. They are just stored raw in the rom. ie:

[byte 0] [byte 1] [byte 2] [byte 3] = color entry 0.
[byte 4] [byte 5] [byte 6] [byte 7] = color entry 1.

These reference back into the Palette ROM. So if the palette rom had the following colors as bytes 0 thru 7:

0 1 2 3 4 5 6 7
[black][red][yellow][green][cyan][blue][purple][white]

And the lookup ROM had: (starting at the beginning of the Lookup ROM)

0x00 0x00 0x00 0x00 /* color entry 0: black black black black */
0x00 0x01 0x05 0x07 /* color entry 1: black red blue white */
0x00 0x01 0x04 0x07 /* color entry 2: black red cyan white */

This means that if you were to use color 0 on a character or sprite, it would all be black. If you used color 1, then the four colors used to paint that sprite or character on the screen are black, red, blue, and white.


----------------------------------------
Color ROMS

Pacman and Pengo have different capabilties for color. Both have support for 32 colors, but Pengo can have four times as many lookup entries.

Type File Entries What it means

Pacman palette .7f 32x1 byte 32 discrete colors max
lookup .4a 64x4 byte 64 four-color entries

Pengo palette .078 32x1 byte 32 discrete colors max
lookup .088 256x4 byte 256 four-color entries


----------------------------------------
Video RAM Layout

The layout of video ram (and color ram -- they're identically layed out)
is kind of strange. It basically looks like this:

A 55 54 53 52 51 50 49 48
B 63 62 61 60 59 58 57 56
C 40 32 24 16
D 41 33 25 17
E 42 34 26 18
F 43 35 27 19
G 44 36 28 20
H 45 37 29 21
I 46 38 30 22
J 47 39 31 23
K 07 06 05 04 03 02 01 00
L 15 14 13 12 11 10 09 08


NOTE: This is just an example, but it shows the real memory layout. The example here is shown as being 4x10 resolution, when the real hardware has a 28x36 resolution.

That is to say at offset of 55 into the video ram is the upper left corner, and an offset of 08 os the lower right corner. But it doesn't stop there. The four sprites in each of the corners (55, 54, 63, 62), (49, 48, 57, 56), (07, 06, 15, 14), and (01, 00, 09, 08) don't show up on the display. That's how we get a width of 4 in this example, and not 8, as you might think. I've no idea why they decided to lay out the memory in this fashion, but run with it.

In the real hardware, the top two and bottom two rows (A, B, K, L) are 32 bytes long, instead of the 8 bytes in this example. Also in the real hardware, the vertical rows (C thru J) also 32 bytes long, instead of the 8 bytes in this example. There are also 28 of them, instead of 4 in this example.


NOTE: So that you know, here are how the offsets in this example corrolate to real hardware:

this example real hardware
00 0x0000
08 0x0020
48 0x03C0
56 0x03E0

One thing that is easy to remember is that for the vertical section, the upper left corner is at an offset of 900 (decimal) on the Pacman and Pengo hardware. On our example here, it's 40. So to write out a string of text, first find the origin of the text:

offset = TOP_CORNER - ( x * (HEIGHT_OF_COLUMN) ) + y

so, for the above example:

TOP_CORNER = 40
HEIGHT_OF_COLUMN = 8

or for real hardware:

TOP_CORNER = 900
HEIGHT_OF_COLUMN = 32


And then from there, every character to the right is at -HEIGHT_OF_COLUMN (-32) from the previous character. So a function to put a text string out to the display might look like this:

#define HEIGHT_OF_COLUMN 32
#define TOP_CORNER 900

putstring(int x, int y, char * text, int color)
{
int pos = 0;
int loc = TOP_CORNER - ( x * HEIGHT_OF_COLUMN ) + y;

while (text[pos] != '\0')
{
videobuffer[pos] = text[pos];
colorbuffer[pos] = color;
pos++;
loc -= HEIGHT_OF_COLUMN;
}
}

Of course, you realize that this does not take into accout the topmost two lines, nor does it do the bottommost two lines. Those are just stored right-to-left in the video memory. You can figure out how to put text out to those yourself. ;)


----------------------------------------
Watchdog Timer

Another thing you will have to do, is to occasionally reset the watchdog timer. The watchdog timer sits out there, constantly counting upwards. When it reaches its limit, it will reset the machine. This is imperative to have on this kind of hardware, for if some wierd unexpected thing occurs, and the machine is "hung", it must be able to reset itself without the arcade owner's intervention.

The counter itself is triggered off of the VBLANK, or "vertical blanking" interrupt. This gets triggered 60 times a second, or every 16.7mSec, when the screen is done being drawn by the monitor. When the count reaches 16, the four bit counter (74ls161 at 9c on the Pac-Man board) will "carry", and will reset the machine. So you basically need to clear the watchdog timer quicker than four times a second otherwise it will reset itself on you. All you need to do is to just put a lot of these in your code:

in c:
char * watchdog;
watchdog = 0x50c0; /* pac-man watchdog address */
/* use 0x9070 for pengo */

*watchdog = 0; /* clear the watchdog timer */

in Z80 asm:
.equ watch, 0x50c0 ; pac-man watchdog address
; use 0x9070 for pengo

xor a
ld (watch),a ; clear the watchdog timer


----------------------------------------
Timing and Initialization

There are two methods to do timing in the hardware. The first is a simple
busy loop, the second watches the vertical blank to judge actual time.

The first, a busy loop, is very simple, and can be quite inaccurate.
It is a simple for loop that counts to some arbitrary value, which after
experimentation and testing, will delay the required amount of time.

It looks like this:


/* wait for about three to four seconds... */
for ( x=0 ; x<10000 ; x++)
{
/* put code here to check the inputs */
}


The problem with this, is that depending on what you do in the loop, will change the amount of time it sits waiting. Obviously, nothing else in the system can happen while this loop is executing, so you should at least reset the watchdog timer, and count coin drops while this is happening.

The other method is to setup an IRQ routine, and handle timing off of a real clock source. Unfortunately, there is nothing like a realtime clock in the pac-man hardware... but we have something close. There is an interrupt that happens between every frame that gets drawn on the screen. (When the vertical blank, or VBLANK happens.) This happens 60 times per second, like clockwork, if you forgive the pun.

So how do you use this timer? Well, it's a two step process. You should look at the 'rst' opcode for the Z80 to start off with:

;restart location
rst 0x0000 ; C7 rst 0
rst 0x0008 ; CF rst 1
rst 0x0010 ; D7 rst 2
rst 0x0018 ; DF rst 3
rst 0x0020 ; E7 rst 4
rst 0x0028 ; EF rst 5
rst 0x0030 ; F7 rst 6
rst 0x0038 ; FF rst 7

Those are all of the 'rst' opcodes. So, what are these, and what do they have to do with anything? The 'rst' opcode is a single byte opcode that does the equivalent to a jump ('jp') or a call ('call') method to go to a subroutine. The 'jp' and 'call' opcodes require three bytes, rather than just one for 'rst'. The limitation is that there are only 8 valid 'rst' opcodes, which jump to eight specific locations. The 8 locations are 0x0000, 0x0008, 0x0010, and so on. They are 8 bytes apart, so there is space in there for a 'jp' to the handling routine for that 'rst' call.

When the system starts up, it does the equivalent to "rst 0x0000", and starts at memory location 0x0000. From there, there should be a jump to your initialization routine.

That initialization routine should first set up any timers, then any other system initializaion, and then call your own game routine. As would be expected, when setting up interrupts, you should turn off interrupts. Then re-enable them after the setup is complete.


irqen = 0x5000 ; pac-man irq enable register

.init:
di ; disable processor interrupts
ld sp, #.stack ; setup the stack pointer.
im 1 ; set interrupt mode 1
; all interrupts go through vector 0x0038

ld a, #0xff ; fill register 'a' with 0xff
out (0x00), a ; do an 'out' to port 0x00 with data 0xff
ld a, #0x01 ; fill register 'a' with 0x01
ld (irqen), a ; enable the external interrupt mechanism

ei ; enable processor interrupts
call your_routine ; call your main game/app routine


If you notice in there, we do an 'out' to port 0x00 with 0xff. If we look above, the opcde "0xff" is the "rst 0x38" opcode. This is setting the VBLANK interrupt request routine (IRQ), to opcode 0xff, meaning that when the VBLANK interrupt occurs, it will do the equivalent of the "rst 0x38" opcode. Your IRQ routine should be at 0x0038 in the memory space of the processor. For Pac-Man, this memory space is in the first ROM. Of the three Interrupt modes, mode 1 is the only one we need to care about. It sends all interrupts (not including the NMI) through our routine at 0x0038. (For Mode 0, it will vector off to whatever data is on the databuss, Mode 2 will do something similar, where some data is passed in and the vector is computed.)

Since this IRQ routine is the last one in the list, we can just start the IRQ code at 0x0038 in the rom. The following sample routine just increments a counter variable (a 16 bit (two byte) value). At normal operation, it takes about 18 minutes for this variable to overflow, and loop around. This should not be a problem.


timer = 0x4c00 ; timer variable -- at base of RAM

.irq:
di ; disable processor interrupts
push af ; store aside register 'af' to the stack
push bc ; store aside register 'bc' to the stack
xor a ; a = 0
ld (irqen), a ; disable the external interrupt mechanism

ld bc, (timer) ; bc = timer
inc bc ; bc++
ld (timer), bc ; timer = bc

; do any other code here if you like

ld a, #1 ; a = 1
ld (irqen), a ; enable the external interrupt mechanism

pop bc ; restore register 'bc' from the stack
pop af ; restore register 'af' from the stack
ei ; enable processor interrupts
reti ; return from interrupt routine


This is about as simple as you can get. You can actually put some logic in here for registering inputs and coin drops if you like, but this should get it on its feet. Just be sure to save and restore any registers you may use. You also need to be sure that this routine does not take longer than 1/60th of a second to execute, or your main code will never get a chance to execute... or the IRQ routine will re-enter itself, and things will die a horrible, miserable death.

If you want to see how this is used in practice, look in the 0crt.asm file which is the runtime Small C compiler. The one that is available from my development environment has been modified from the generic one (which is also there) so that all of this is already done for you. Also done already in that file, is that all of these bits are in their proper locations.

Once all of that is set up, you will need to use it in your program. All you need to do for a two second delay, for example, is the following:


int wait_until;

/* set the final end time to be:
now + (60 ticks per second) * (2 seconds)
*/
wait_until = timer + (60 * 2);

/* wait for it to happen */
while (timer <= wait_until)
{
reset_watchdog_timer();
check_for_user_input();
/* do other appropriate things here */
}


That's it. If you look in my "hello" source, you can see how I use the
timer to animate the sprites at a specific rate.


This method is a bit more complex to get it working, but yields much
more accurate results. Once you have the mechanism set up, it's easy to re-use it for all of your projects.


----------------------------------------
Control and Dipswitches

Since all of the hardware is all memory mapped, we can just look out into memory at the dipswitches and input ports. Pengo and Pac-Man have them located at different places in memory, but the technique is the same for both.

Most, if not all of the control lines for these games are normally closed That is to say that if you look at the data stored in IN0 at the Player 1 Joystick Up bit, it will be 1 when the joystick isn't "up", and it will be 0 when the user pushes the joystick upwards. This is true for the coin slots as well.

Dipswitches are usually in banks of 8. If you just read the byte at the hardware's memory location for the dipswitch, you will see the state of all 8 switches. "OFF" switches set that bit to 0. "ON" switches will set that bit to 1.


----------------------------------------
Other Registers

I'm not entirey sure about most of these. I'm also not sure if some of these registers (ie: palette bank selector, color lookup bank) are even emulated. I also know that the Watchdog Counter is important, but i'm not sure what do do with it, as I have found no information if the watchdog circuitry is even emulated in MAME. So the problem here is that if the watchdog is not reset properly, your programs may work fine on the emulator, but might just sit and reset itself on real hardware.


interrupt enable
----------------
Enables and disables the interrupt mechanism.

set to 0 to disable interrupts
set to 1 to enable interrupts

sound enable
------------
Enables and disables audio output

set to 0 to disable sound output
set to 1 to enable sound output

flip screen
-----------
Set to 1: The background video buffer is rendered vertically.
This _DOES_NOT_ change the floating sprites at all.

Set to 0: The background video buffer is rendered normally.

This is useful for "Cocktail" use, where you have to flip the screen
vertically for player 2 to play the game right-side-up.

sprite bank
-----------
Set to 0: BOTH the background and floating sprite banks to bank 0
Set to 1: BOTH the background and floating sprite banks to bank 1

start lamps
-----------
not totally sure
Set to 0: the lamp associated with that register turns off
Set to 1: the lamp associated with that register lights up

coin counters
-------------
not totally sure
set to 1, then 0 I imagine to toggle a pulse for the coin counter

coin lockout
------------
not sure.. Pac-Man doesn't have coin lockout hardware or circuitry.

watchdog reset
--------------
On the real hardware, this needs to be reset to zero frequently to prevent the hardware from automatically resetting itself. Just set to zero a lot, and you should be fine.

palette bank selector
---------------------
not sure

color lookup bank
-----------------
not sure


----------------------------------------
Acknowledgment

Many thanks go out to Clayton Cowgill for many key bits of information which will help your program work on real hardware. Visit his cool site at http://www.multigame.com Thanks Clay!

And of course, Kev "Mowerman" for supplying me a Pac-Man board with which I will be testing later on. Visit his fact-filled site at http://users.erols.com/mowerman/ You rock, Kev!