Timers, Events and State Machines

The code for Pacman is a series of event-driven state machines.  The basic unit of measurement is the video interrupt which occurs at 60Hz (every 16.667 milliseconds).  After game initialisation and self test the interrupt vector is set to #008d and this interrupt service routine (ISR) drives various events and timers.

Interrupt Service Routine

The video timer inerrupt performs the following functions in sequence:

  • Disables interrupts
  • Copies the audio frequency data to the hardware registers
  • Updates the audio wave form registers
  • Copies sprite attribute and location data to the hardware registers
  • Reorders sprites if necessary
    • A ghost that has just been eaten is the highest priority so the points are not hidden by other sprites
    • Pacman is higher priority than the ghosts if he is powered up
  • Updates counters
  • Dispatches ISR tasks
  • Drives the main state machine
  • Mutes the sound if in demo mode
  • Calls the sound effect update state machine
  • Calls the songs state machine
  • Re-enables interrupts and returns.

Counters

A 2-byte sound counter is maintained at RAM #4c84.  The low byte is incremented on every clock tick and the high byte is decremented.  The incremented value is used to drive the volume decay of some of the sound effects.  The high byte does not seem to be used.

Counters are maintained for 1/60th of a second, 1/10th of a second, 1 second, 10 seconds, 1 minute, 10 minutes, 1 hour and 10 hours.  Although I have not seen anywhere in the code that uses units other than 1/10ths seconds or seconds.  These counters occupy 4 bytes of RAM from #4c86 to #4c89.  They are stored in BCD format and there are two values per byte.  An 8-byte table at ROM #0219 is used to check the increment limit for each nybble.  For example, the first byte is #06.  When the 1/60th of a second counter reaches this limit, it is reset and the next digit is incremented to give 1/10ths of a second.  This repeats up to the 10 hr counter.

Scheduled Tasks

The ROM code frequently schedules a task to occur sometime in the future.  Tasks are scheduled by calling RST #30 which calls addISRTask_0051 to find a free slot in the task list and add the task.  These tasks are then examined by the ISR and used to advance state machines and other activities with a configurable delay.  There can be up to 16 ISR tasks outstanding at a time.  Each task is 3 bytes long and they are stored in a circular buffer at RAM #4c90.  The 3 bytes in a task are:
  • timer
  • function
  • parameter
The timer byte's lower 6 bits contain a value from 0 to 63 (#3f) which is the number of intervals to allow pass before the function is called.  The upper two bits choose which unit to use for the timer (1/10ths of a second, etc).

The function is the number of the routine to call.  The table at ROM #0247 defines these functions and there are 10 of them.

The parameter is not used.

Immediate tasks

As well scheduled tasks, there is a list of tasks that are to be executed immediately.  These are 2-byte values stored in a queue from RAM #4cc0 to RAM #4cff.  The head and tail pointers for this task list are RAM #4c82 and RAM #4c80 respectively.  An empty slot is indicated by #ff in both bytes.  The first byte in a task is the function to call and the second is the parameter to supply.  There are 32 functions defined in the table at ROM #23aa.

State Machines

Various state machines are used to drive the game play.  The outermost state machine is the main state machine.  It has 4 states:
  • Reset
  • Intro
  • Coin Inserted
  • Play game

The reset state machine has only two states.  Once initialised it advances the state to Intro.

The intro state machine has 35 states.  Each state performs a different part of the intro, such as introducing the ghosts, the points, playing the intro sequence and finally playing a demo of the game.

The coin inserted state machine has 5 states.  In the first state, it displays the "push start button" message.  In the second, it waits for a start button to be pressed, and so on.

The game play state machine has 38 states.  The 4th state is the main game play state.  16 of the states are for flashing the maze from blue to white at the end of a frame.

Many of the state machines states have an ISR task to advance their state so that state timing can be controlled.  In some states, the function #000c is called, which does nothing as it just a ret opcode.  These states are generally waiting for a timer to expire and advance the state.

Ghost States


Each ghost also has a state, and a sub-state.  The ghost states are 
  • 0 - alive
  • 1 - dead
  • 2 - entering house
  • 3 - moving sideways in house

Not all ghosts use all states.  For example, Blinky doesn't need to move sideways in the house.  The ghost substates are:
  • 0 - in the house
  • 1 - chasing
  • 2 - leaving the house
  • 3 - moving sideways in the house to leave
Each ghost has its own state machine function to call the appropriate function for their state.  For example, clydeStateMachine_10b4 () acts on Clyde's state.

The "Pacman dead" state machine has 17 states.  This is used to animate Pacman as he is dying as each state advances the animation.  There are 15 functions that each just call the animation with a new sprite.  I'm sure that could have been a table!

Comments

Popular posts from this blog

Translating pacman into C

Movement patterns