Using an FPGA to
replicate no longer available components on the
and CPU Boards in a WPC-DCS Pinball Machine.
These include the two ASICs and PAL.
With the introduction of Indiana
Jones in 1993, Williams Pinball
started to base their audio system on the Digital Compression
System. The main CPU for this system is an ADSP-2105 DSP
chip. There were two main generations of these boards, the
(used in the IJ) used a PAL to contain the decoding logic.
is known as the WPC-DCS audio
board. In the second generation, Williams combined the dot
controller onto the same board, and moved all the logic into an
ASIC. This latter generation is known as WPC-95.
Due to the unavailability of the ASIC, the WPC-95 audio boards have
soared in price (RGP
They are commonly several hundred dollars each. In the summer
2007, I was looking for a pinball/FPGA related project, and this seemed
like a good one to dive into. After some discussion with
Reynolds, I decided to give it a try.
The first step was to reproduce the WPC-DCS circuit, since it was
simpler (only uses a PAL). My hope was that once it was
using IJ ROMs, I could make some small changes, load in MM ROMs, and
that WPC-95 was simply a repackaging of WPC-DCS. To get
I needed to know the equations for U16, the PAL on the WPC-DCS
board. Help came from Brent Butler, who was the one who
engineered the WPC Security PIC. He read the contents of his
and sent me the equations. This, along with the WPC-DCS
schematics, and the part datasheets were all the ingredients I needed
to start coding.
The platform I chose to use was the Spartan3A
development board. It includes
a Spartan3A FPGA, and lots of peripherals such as 4 MBytes of Flash,
buttons, LEDs, a power supply, a USB
programmer, and an expansion connector. This latter connector
allowed the connection to wire
wrap boards, where the DSP and D/A chips would
self-contained Flash memory was nice because it would allow me to
eliminate the large PROM chips, and put their contents in a compact
modern part. IJ needs 3.5 MBytes, so it should fit quite
The first step was to load the ROMs for the IJ into the Flash of the
Spartan3A board. The image of the seven sound ROMs were
into one large binary file, and I then used Ken Chapman's excellent
loader (see link below) to transfer this into the Spartan 3A.
Once that was complete, I could use his bootloader program to read back
sections, and I could see that the 7 chip
image was correctly loaded into the Flash. The next step was
develop the VHDL code. A simulation of the result is shown
Simulation of the VHDL
code shows no bus contention and the proper data
being fetched for the DSP. In general, the signal names are
on the WPC-DCS schematic.
In the above waveform diagram, the signals from 'cmd_read' to
'ram_read' indicate what the decoding logic thinks the DSP is
doing. We can see only one of these become asserted at any
time. Also, an inspection of the databus shows the proper
being fetched for the DSP. This shows that the PAL equations
my reading of the schematic appear to be correct.
Once the code was complete, it came time to assemble the
prototype. As mentioned before, the DSP and D/A were to be
installed onto the breadboard that plugs into the Spartan3A.
decided to mount them pin side up to allow access to all the
connections. A photograph of the completed prototype is shown
The WPC-DCS prototype board. The board on the right holds the
and the D/A.
All other components are on the other board.
Close-up of the DSP and D/A area. The two components are on
The DSP is mounted into
a socket, and
then plugged into some wire wrap pins. This is the square
pins in the above image. To the right of that is the 16-pin
chip, also mounted pin side up. The D/A needs a -5V supply,
this is supplied by a AA battery pack. As you can see in the
image above, the DSP connects to the Spartan via series
resistors. These are included to protect the Spartan 3 device
because its inputs are not 5V tolerant.
I did some tests to characterize what the DSP is supposed to do on
startup. When an original WPC-DCS board is properly running,
clock (DacClk) and strobe (DacStb) lines from the DSP to the D/A are
expected to be clocking, but the data (DacDat) line will be
static. The data line will have transitions only when a sound
being played. Also, the power-up BONG is expected to be
the DSP a few seconds after bootup. In contrast, a WPC-DCS
with no ROMs installed, will have these lines as hi-Z, which is
presumably the power-on state for this port. Clearly, there
be no sound issued by the DSP if it does not boot. This information
will allow me to gauge if the DSP on the prototype is running or
Up to this point, a lot of effort had been invested, and if the DSP did
not boot, I would have very few options to incrementally debug the
problem. A great deal was at stake here, and it would all
on the initial power-up. I flipped the power switch, and to
relief, the DSP appeared to be working. I could see the D/A
clocking, and a single burst would appear on the data line a few
seconds after power-up. Also, I programmed the switches on
Spartan 3A for command input (to play sounds), and when a command was
sent to the DSP, I could see it fetch the command, and clear the
interrupt flag. This was very promising.
I then plugged in the D/A chip next. In addition to the usual
this chip requires -5V as well. Presumably for the internal
op amp. This latter supply is provided by a battery
connected the audio output of this chip to a signal tracer (basically a
small audio amplifier with speaker). On the subsequent power
I get a cool single "BONG" from the prototype. This indicates
DSP boots and that the checksum of all the Flash was good.
The DCS audio board is controlled by a bus consisting of 8 data bits, 5
and 2 control lines. I needed to know what
commands the DSP code would recognize so
that I can stimulate it on my test bench. Help came
Martin, who knows how to run PinMAMED.
Using this emulator/debugger, we were able to figure out that command
packets are two bytes long. For example "0001" causes the
march to play on PinMAMED. A check with an oscilloscope on my
shows that the two
bytes are normally separated by about 1 millisecond. Based on
initial testing with sending single bytes, the DSP times out after a
certain period, and the two bytes in the packet need to follow each
other by 1
millisecond or less. I then changed my user interface to send
bytes in rapid succession, with the bottom nibble controlled by the
four slide switches on the Spartan3A board. This proved
successful, and I was able to get my prototype to play all the sounds
identified by 0001 through 000F on PinMAMED.
A short video of
the board playing the Indy march.
The next step was to emulate/replicate the WPC-95 A/V board.
this project was started, I had hoped to be able to simply port the
WPC-95 ROMs into the testbed above. This would eliminate my
having to reverse engineer the ASIC. However, examination of
schematic shows why this would not work.
WPC-95 ROMs are larger than WPC-DCS. Per the
address bus for the WPC-DCS ROMs is 23 bits wide (8 Mbytes address
space). In contrast, the address bus on WPC-95 is 24 bits (16
Mbytes address space).
Of this latter 24 bits, the 10 LSB bits come directly from
DSP address bus, while the remaining 14 come from a paging register
inside the ASIC. This is much different than WPC-DCS, where
bottom 12 bits are from the DSP, and the top 11 from a paging register.
Only 8 bits of the DSP's data bus is connected to the ASIC,
the 14 bits of the paging register must be stored as two separate
writes. This makes the two platforms incompatible.
the paging register is completely
different in one configuration compared to the other.
There are two RAM enable signals on WPC-95 (both from ASIC)
one on the
An important tool to understand what the ASIC and DSP are doing is a
logic analyzer. I connected three pods of my unit to the
points on the WPC-95 board that was loaned from Jim Knight.
unit had Scared Stiff ROMs on it. I was able to slowly gain
understanding of what the DSP does using this setup. It felt
the process of cracking a cipher code or opening a combination lock.
The logic analyzer connected to a WPC-95 board.
The order of operations of the DSP is as follows:
When the POR timer expires, the DSP reads the inital boot
from ROM using the BMS signal. This takes about 610 useconds.
The internal boot functions take about 300 useconds, and
first of the RAM checks then start.
A pattern is written to the entire range of RAM using the
The pattern is read back using the DMS line.
Another pattern is written to RAM with the PMS line.
The pattern is read back using the PMS line.
If any of the previous four steps fail, the DSP issues ten
bongs. This checkout takes about 200 microseconds.
RAM is then erased with the PMS line.
Another erasure of RAM with the DMS line.
The DSP then proceeds to the checksum calculation of the
This takes about 2 seconds on Scared Stiff ROMs.
If all is well, at t=2.5 seconds, the BONG
starts. A single
sound indicates all is well with the ROMs. This takes about
At t=3.4 seconds, the DSP reads from ROMs again with the
line. At this point, the DSP starts to operate.
While this is going on, every second or so, the DSP writes
register in the ASIC to flash the red LED on the board on and off.
Another important tool
This allows one to see live data from an FPGA using only its JTAG
port. Although I extensively tested my code with the
do not have a simulation of the DSP, and this tool allows me to see the
interaction of the DSP on the prototype board, and my FPGA code.
View of Xilinx's
Chipscope Pro tool. It allows you to display
live data from the
FPGA design using only the JTAG interface. For example, at
cursor, the DSP is writing "F20B00" to the
address "2FFF". This maps to RAM.
After implementing the
relationships that were read with the logic analyzer, my prototype
initially bonged ten times. This indicated a communication
problem with the embedded FPGA RAM. After debugging with
(see above), I found the problem, and the prototype
bonged twice on startup, indicating a remaining problem with the way
the paging register is being handled. After about one month
I finally fixed all the bugs, and the prototype bonged once on startup,
and flashed one of the LEDs on the Spartan board, matching the
operation of the loaned WPC-95 board. This represented a huge
milestone in the project, and I was very pleased to get to this point.
To understand how the CPU commands the WPC-95 A/V board, I
inserted the loaned board into a WPC-95 machine, to see how it
with the CPU. The kids were tickled when they heard our TOTAN machine
producing Scared Stiff sounds. By activating the sound test
I could see how the ASIC interrupts the DSP, and how the command is
delivered to the DSP.
The loaner board with all the probes hooked up installed
into my Tales of the Arabian Nights machine.
With the information
created a command interface with a pushbutton and the four slide
switches on the Spartan board similar to the interface to the WPC-DCS
board above. On the first try, I was able to get the
play Scared Stiff sounds! I had successfully reproduced the
portion of the ASIC.
Youtube video of the
Note the flashing LED on the prototype, matching the original board.
The second half of the A/V board is the DMD interface. After
above results, I took a few months off from this project, and returned
to it during the 2007 Christmas season. After a week or two
work, I was able to display a test pattern on my IJ's DMD on the first
The test image shown on the DMD is produced by the Spartan development
The image is sharp with no ghosting showing that the timing
In the above image, the DMD data cable is plugged into a solderless
breadboard that is in turn plugged into the Spartan board. I
initially started to implement the circuit by simply converting the
schematic from the WPC-89 schematics into VHDL. I soon
that the discrete design was not very suitable for implementation in an
FPGA. This is because good FPGA coding practices recommend a
fully synchronous design. The original WPC-89 implementation
far from it. I rewrote the VHDL code as a fully synchronous
design, and using only one clock (the CPU E-clock) rather than two as
the original DMD interface board. By using a single clock, it
makes it easier to one day integrate everything into one FPGA.
The DMD display shown working on a WPC-89 machine.
I develop the code on my laptop and load it into the FPGA via JTAG.
After another week's work, I found all the bugs and was able to drive
the DMD by plugging into the CPUs IO expansion ribbon cables!
took more effort than I thought it would, and was mainly stymied by the
design of the original controller. The way it switches the
address bus into the RAM violated the FPGA RAM's hold time, and it took
me a while to figure it out.
The photo above shows my development system. The solderless
breadboard has the three connectors to the IJ (two to the CPU board,
and one for the DMD). The Spartan board interfaces to these
connectors, and is controlled by the CPU board. The laptop is
simply set on the playfield glass, and connected via JTAG to the
Spartan. I can then develop the code, and run it with
(on the laptop). This allows me access to the signals without
logic analyzer connected.
A day after I was able to successfully use the programmed Spartan on my
Indiana Jones (WPC-89), I was able to use it on my Medieval Madness
(WPC-95). This shows that the DMD interface on both
are the same.
In September 2007, after the successful
the WPC-95 A/V VHDL code, I started working on an FPGA
the CPU board. Since so much of this board is digital in
it would lend itself well to recasting into an FPGA. After
searching, I found a 6809
core. If I could also combine the RAM and the
functionality, we would have the essential parts of the CPU board on a
single FPGA. I also previously had the good fortune of
a CPU board (with
valuable ASIC) on Ebay for $65. The board did not initially
but after I replaced the RAM, it booted fine. I was thus set
start the replication process.
I first loaded the game ROM code into the Flash memory that is on the
Spartan board, and started by tackling the ROM paging that is done
inside the ASIC. Information on how this is done is very
and even looking at the logic analyzer plots showed very little
information. I then found this
memory map by Matthias Bucher, and the
PinMAME source code. Among the files in this latter resource, the file
WPC.H contains the memory map locations of the ASIC
a description of the "shifted bit hardware". I implemented my
best guess of the paging
algorithm, and it appeared to successfully step through the ROM check
process (by using Chipscope).
With the logic analyzer hooked up to read the CPU's activity, I could
roughly see what the WPC CPU does during the boot process:
After the reset is deasserted, the reset vector is fetched
FFFE and FFFF. These are the last two bytes of the program
The ROM is checked first starting with the highest
32kbytes. This is the non-paged section. Then, the
ones are checked in turn by using the paging register at 3FFC.
If that passes, the CPU moves onto the RAM check.
this by writing and then reading the data byte 0x55 to the RAM, and
then repeating the test with 0xAA as data.
If that is ok, it continues with inits to the I/O such as
flippers, sound board, DMD, etc.
Then comes a lot of initialization which purpose is not
After about one second of initialization, the main code
infinite loop and waits for an interrupt.
It took me one month to
get my VHDL code to this point.
I did not at the time suspect the role of the interrupt.
Therefore, I could not figure out why the code was getting stuck in the
infinite loop. This prevented the LED on the Spartan board
flashing, which is how the game code indicates that all is well with
the tests. It was very puzzling and somewhat
then decided to set aside this project for a few months and take a
fresh look later.
In January 2008, I completed the DMD
above, and decided to tackle this again. One tool that I had
up was a separate Spartan board consisting of a simple 24 bit counter
that would basically be my time keeper for the WPC CPU board.
With this addition, I could tell how many clock cycles had elapsed
since the reset was released. This data was available on the
logic analyzer, and I could trigger on events (such as writing to a
register or memory location), and see the accompanying count of the
elapsed clock cycles. The use of this latter counter allows
know where in the boot process the CPU board was. I had
noticed that the first flash of the LED always occurs with some spread
in the values for the elapsed time count, and I could never figure out
why. Then it hit me that the LED process may be controlled by
another separate asynchronous process...... such as an
A quick check of the IRQ line on the WPC CPU showed that it pulsed at
1kHz. Thus the WPC ASIC interrupts the processor at that
and this is probably why the main code on my Spartan board was stuck in
an infinite loop!
I added the interrupt feature in my VHDL ASIC in the Spartan, and
bingo! the LED on the Spartan board flashes rapidly and continuously
after a second from power
up, just like the WPC CPU board. Then, intentionally
the ROM paging results in one flash of the LED, and corrupting the RAM
mapping results in two flashes. These results agree with the
diagnostic information from my IJ manual. All this means I am
successfully get the game code to boot up. The RAM, CPU, ASIC
other minor glue logic from the CPU board were all inside a single FPGA.
the CPU board and the DMD interface
To truly verify that the game code is running properly on the Spartan
board, I decided to integrate the previously developed DMD interface in
the same FPGA. This would allow the board to drive a DMD
the game code that is loaded into the Flash memory. It should
have not taken me much time, but a simple mistake cost me a few days to
track down. Once that was corrected, success! As
seen in the animated GIF below, the game code boots up and drives the
DMD display cleanly. If I hit the reset button after initial
bootup, the display shows the familiar "Testing..." message, and then a
"Check Fuses...." message. This is because the switch matrix
not been hooked up, and the game code thinks a fuse is blown.
An animated GIF showing the Spartan board running WPC code.
"Slug Fest". The only connections to the IJ machine is power
The DMD data is driven by
the Spartan board.
A VGA Interface
Up to this point, if I
wanted to test
the DMD interface, I had to walk down two floors from my office to my
basement where my machines are located. This started to get
and I wanted to find another way to display the DMD
I hit upon the idea of using a VGA interface so that the TV/monitor in
my office could be used. This idea has several advantages:
As mentioned, I would be able to test the WPC prototype
with a VGA monitor.
This is consistent with the underlying theme of this
which is prevention of hardware obsolesence. Although
monitors could be substituted if DMD displays become unavailable one
Since only one third of the display is used, the rest could
used for display of animation. For example, with a machine
IJ, the video scenes from where the quotes are taken could be displayed
along with the sound. The index of which sound is being
can be obtained by intercepting the command to the DCS sound board.
The Spartan board has a
VGA interface connector, and the associated
hardware is very simple. It consists only of a dozen
and the connector. I found a document that describes the VGA
interface timing, and started work on the
interface. The WPC
DMD is refreshed at about 122 Hz. The normal VGA frequency is
60Hz. I knew from my previous work that the WPC CPU switches
rapidly between two screens to form pixels of half intensity.
wanted to make sure that this feature was preserved with the VGA
display. However, since it only displays about one
other DMD screen, some special accomodations needed to be
Another aspect is that the VGA display is 640 pixels wide, which is
five times more than a DMD display. It means that each DMD
can be mapped to one five by five grid of VGA pixels.
The VGA interface hardware on the Spartan board is very simple, and
just some resistors. It is possible to get by with just six
(fewer bits and no blue resistors).
The VGA interface on the
prototype works by writing the DMD data into a separate buffer, and
'smooths' the value across two screens. This analog value is
sent to the monitor for display. This simulates a persistence that
lasts across multiple VGA screenfuls. I coded this idea up,
found it to work quite well. After initial testing, I refined
code to provide a black border around each pixel, and rounded the
pixels' corners. This makes it much more like a real
Referring to the image below, one can see half-intensity round pixels
in the simulated DMD.
The VGA interface at work. I can now debug the WPC Spartan
anywhere such as my home office. Note the monitor cable
the top connector of the Spartan board. The
code being run here is "Slug Fest",
a baseball themed game. Note that I no longer get the "Check
because I faked out
the switch matrix and simulated some closed switches.
Close-up of the VGA screen shows that the displayed dots are round with
gaps in between. This is meant to match the appearance of a
DMD. This hardware could in principle be added to any
that uses the 128x32 dot DMD display.
it may be difficult for a Dayton criminal
defense lawyer to believe that pinball machines were at one
illegal in some U.S. cities. Early machines were considered games of
much like gambling, rather than a game of skill.
6/20/07 - Start of Project.
6/21/07 - Equations for U16 PAL from Brent Butler
8/13/07 - WPC-95 prototype bongs ten times on
initialization. This indicates that the critical boot ROM
is good, but
the DSP RAM interface is faulty.
8/16/07 - Fixed DSP RAM problem, and WPC-95 prototype bongs
on startup. Now I need to fix the page register.
9/1/07 - A/V board prototype finally issues a single BONG
startup! One of the LEDs on the Spartan board serves as the
LED on the WPC-95 board, and flashes just like the original
board. Another huge milestone passed.