The previous article described the internal workings of the noise generator used in Pole Position. This article tackles the actual application of Namco 54xx in the Pole Position game.
MAME Command Captures
The Multiple Arcade Machine Emulator makes it easy to inspect the internal operation of Pole Position, since it emulates the CPUs and MCUs well enough for our purposes. A small modification to namco54.cpp allows the bytes written to the chip to be logged with an accurate timestamp.
It's evident from such captures that the Namco 54xx.cpp is updated with a regular loop with a period of about 16.5 ms. In all likelihood this is simply the video vertical blanking that drives the major state of the game generally.
In fact, the Namco 54xx is updated twice per vertical blank, with the second update appearing about 0.5 ms after the first.
During game power-up, and while not generating any noise, the writes at each VBLANK is a burst of two copies of the same information.
|Burst Position||Command (Hex)||Description|
|+0.0 ms||70||Set channel C to zero amplitude|
|+0.0 ms||60 06 00 00 00 00||Set channel C parameters: base increment=0x60, others zero|
|+0.5 ms||70||Set channel C to zero amplitude|
|+0.5 ms||60 06 00 00 00 00||Set channel C parameters: base increment=0x60, others zero|
Observed During Play
Channel A Not Used
Notably, channel A is never used in Pole Position.
Channel B Explosions
Channel B is used in a constrained way to generate explosion sounds after a collision.
|40 60 30 03 66||attack duration=6, decay duration=3, sustain duration=0x30, sustain amplitude=6, attack amplitude=6|
|20||kick off channel B|
There are no variations on this pattern.
Channel C Tire Screech
Channel C is used in a limited way to generate the tire screech when speeding through a tight turn. The application of parameters limits the operation of channel C to a square-wave generator with a handful of discrete frequencies and amplitudes.
|60 xy 00 00 00 00||base increment=yx, supplemental increment=0, sustain duration=0, attack duration=0, attack amplitude=0|
|7z||external envelope control to amplitude z|
Only the base increment and the instantaneous amplitude of channel C is ever varied. Hex values encountered for yx are 70, 79, and 7b. Hex values encountered for the channel C amplitude (z above) are a, 8, 4, and 0.
Emulating The Namco 54xx For Pole Position
There is little reason to implement the MB88xx core and run the original ROM code in a programmable logic device, since the entire scope of actual operation can be easily implemented in an accurate fashion with dedicated logic.
It's evident from the previous observations, an equivalent to the Namco 54xx can be developed by:
- deleting channel A output and envelope state machine since it is never used,
- ignoring hex commands 1x and 3x since channel A is deleted,
- implementing the full channel B state, output, and envelope but with fixed values,
- ignoring command 4x since fixed values apply to channel B,
- implementing the channel C state and output, but without the envelope state machine,
- ignoring command 5x since it is never invoked, and
- ignoring all but the first parameter of command 6x.
This leaves us with:
- the LFSR,
- a pared-down slave interface that only accepts command 2x, command 6x and one parameter, and command 7z,
- the channel B envelope state machine, and
- the channel C state adder and amplitude (operates as a square-wave generator).
Analog Audio Filters
Between the Namco 54xx and the loudspeakers, Pole Position applies first-order analog bandpass filtering. Each audio channel applies a different filter passband.
|Channel||Approximate Passband||Pole Position Use|
|A||600 Hz to 1000 Hz||not used|
|B||200 Hz to 300 Hz||explosions|
|C||2000 Hz to 3000 Hz||tire screech|
Implementing these filters digitally is a straightforward engineering exercise.
Main Loop Statistics
A simulation of the MB88xx running the Namco 54xx ROM, and performing discrete operations, indicates the following statistics for the LFSR (main loop) update.
|Sound||Miniminum Cycles||Maximum Cycles||Mean||Deviation|
Note that as channel C is applied in Pole Position, strictly as a square-wave generator, and without the envelope state machine, its operation is deterministic, and therefore contributes negligble jitter to the loop duration.
This leaves the baseline loop operating at 256000.0 / 103.3 = 2478 Hz with 160 Hz RMS jitter.
As usual a little bit of Python can go a long way. A pure-Python application that implements the LFSR, fixed channel B (explosion) envelope, and channel C (tire screech) square-wave generator was developed.
The design is based on a 7434 Hz audio sampling rate, with suitable FIR filters implemented for channels B and C. The main loop code, that updates the LFSR and channel states, is executed once every three audio samples. The normal pattern is audio-mainloop-audio-audio, and it applies to 95% of the iterations. However, with 2.5% probability, the main loop execution is executed early: mainloop-audio-audio-audio. Similarly, 2.5% of the time the main loop is executed late: audio-audio-mainloop-audio. This models the jitter found in the Namco 54xx mask ROM execution.
Here are the Pole Position sounds generated by the Python.