Last updated August 25, 2008
Binaries can be downloaded from the main FreeWPC page. Source code is also available in tarball format, or you can browse it online.
At the moment, FreeWPC isn't ready for everyone to put into their pinball machine. Testing is mostly done in the PinMAME emulator instead. I use both Visual PinMAME on Windows and xpinmame on Unix.
For a first-time user, the best way to test is to simply to play it under PinMAME and report back to me any anomalies that you find.
Alternatively, you can compile and test the code in simulation mode, which produces a standalone executable that does the simulation inside the program, without the need for PinMAME, and with the ability to use gdb.
Game play and test mode should work as you would expect in a regular WPC machine. The basic pinball machine features are all there and working OK.
General illumination is not very robust. Sound also isn't handled well. I'm sure there are other things that belong here, once more testing has been done.
FreeWPC is stable in the sense that release versions aren't known to crash under normal conditions. FreeWPC hasn't been adequately stress tested to see how it behaves under constant switch closures and multiple game effects running.
This stability is good enough for playing under the emulators like PinMAME. Note that I have placed it into my World Cup Soccer and had no trouble whatsoever. I do not recommend that anyone else do that yet, though. I am not liable for anything you do to your game!
Twilight Zone is the main game used for development. TZ was chosen based on my experience with the machine, and also, it seemed like a good way to test out a lot of features that I thought FreeWPC ought to have. TZ has a lot going on, so getting it to work should prove the system out.
As proof that variations of WPC are supported, T2, World Cup Soccer, and Attack From Mars ROMs have also been built and run under PinMAME, but without any real rule set.
Note that real WPC hardware has a watchdog feature that will restart the CPU in the event of runaway code. PinMAME doesn't emulate it, but FreeWPC does use it and that is good protection against a large class of errors.
The periodic timer interrupt (IRQ) handler also has a check to make sure that task scheduling is going OK. No task is allowed to run for longer than 128ms. If that occurs, the system is restarted.
There are various sanity checks throughout the code that will also throw a fatal error if something is not right.
On any fatal error, the hardware is immediately reinitialized so that all solenoids and flashers are left off. A message is written to the DMD (hopefully, things are working enough that it can be read!), then the system will reset itself automatically.
No, at least not that I am aware of. If anyone sees differently, please let me know immediately. I will work hard to ensure that FreeWPC truly remains free and steers clear of any patent-related issues.
Maybe, although this hasn't been tried. There is support for cross-compiling between the 6809 and native Linux, so some of the hooks for this are already there. If the platform uses a 6809 also, then chances are better. If it's a different MPU, odds are GCC doesn't support it.
The most likely candidate to try would be Sega Whitestar. Some effort has been put into this already, but not much. Also some effort into compiling a WPC sound board ROM is there, also not much.
It is indeed slow, running at 2MHz, but it is adequate. On average about 22% of the processing time is spent in the IRQ handler, which takes care of all the important, realtime hardware refresh. The remaining CPU time is available for other tasks to run.
Great care is taken to make sure that IRQ-level functions are as optimal as possible, otherwise it would indeed be impossible.
The other performance critical routines are those that update the dot matrix. Many of the C routines have been rewritten in assembler to get better performance, at the expense of portability. As it is now, I don't think it can be optimized much more.
First, you need to add a machine description file for the game in the machine subdirectory; see tz for an example of what goes in there. Create a Makefile there also that has the name of the md file and any other C files you want to write. To build it, make sure MACHINE is defined to the machine name you chose; this is best done by creating a .config file before running make.
The md file format is best explained by reading the TZ version, and modified it as necessary. It's modelled after the Windows INI format. See below for more details.
FreeWPC is self-contained and provides its own multitasking OS. Tasks are not preemptible; that is, they run until they exit via task_exit(), or yield control via task_sleep() or task_yield(). Then the next task starts.
There is no notion of priority at present, but this is being considered for the future.
There are also a number of 'idle' functions defined throughout the code that are intended to be called when no tasks are ready to run. The present implementation is slightly off from that, but not too far off. Idle functions don't execute in a task context and therefore can't sleep. In the future, some of these will get a priority boost, since they are really doing important things that can currently be starved out.
There is a malloc() for dynamic allocation, but most memory is statically allocated at compile time. The main user of malloc() now is the display effect (deff) module, but I plan to rewrite it not to use malloc() soon.
When you build the native version that includes built-in emulation, these OS functions are generally bypassed in favor of the native versions. Task emulation is then done using the pth library, which is most similar to FreeWPC's version.
Callsets are an implementation of static event publish/subscribe. Each instance of CALLSET_ENTRY denotes a function that is called back when an event occurs. The first parameter is a string denoting the name of the module; the second is the name of the event.
Events are generated by calling callset_invoke(), with the name of the event as the single parameter. This causes all corresponding CALLSET_ENTRY functions to be invoked.
During the compile, all of the source is scanned to match invokes and entry points. A file build/callset.c is automatically generated that implements the event catching.
The script tools/gencallset does all of this.
Early versions of FreeWPC required that lots of constant information about a machine be provided in the form of C code. Sometimes, information had to be specified multiple times; also, the format varied greatly.
Much of this type of information is now described in the .md file format instead. As part of the build process, the contents of the md file are turned into the underlying C code that is needed. The benefits are that a lot of the redundancy has been removed, and some syntactic sugar was added so that the representation is cleaner and easier to understand. It is way more English-like than C code, for sure.
For example, an entry that defines the properties of the Start Button would generate a #define named SW_START_BUTTON for its switch number, an event named sw_start_button that represents C code to be executed when the switch is triggered, and a string entry "START BUTTON" into the switch name table. Autogenerating these ensures consistency throughout the code but also makes it easier on the programmer.
The script tools/genmachine does all of this.
Gendefines are #defines that are automatically generated by scanning the source code to see all uses of the #define. They may be deprecated in the future; they are currently only used for task group IDs (GIDs).
All fonts were derived automatically from freely available X11 fonts, or from free TrueType fonts on the web. The included fontgen and fontgen2 scripts convert these to .fon files. A .fon file is just a C code data structure that represents the font in a way that FreeWPC understands. The script uses netpbm utilities to generate the font data.
Actually, one of the fonts -- mono5, was the first font to be used and was created by hand, way before the advent of fontgen.
The graphics format has changed a few times, and probably will continue to do so, as I figure out what works well and what doesn't.
FreeWPC ultimately needs graphics in XBM format, sized 128x32. If it's a 3-color image (4 including black), you need two XBMs, one for each bit plane.
FreeWPC also defines an image format called FIF that is just an XBM or two with a small header. The XBMs may be compressed to save space, using simple run-length encoding. This is currently the preferred image format.
The script tools/makefif can convert an XBM or PGM (grayscale image) to FIF. You can export PGM from any decent graphics program, then use makefif to compress it.
The list of graphics to be included goes into FIF_SRCS. You can add your own sources per-machine in its Makefile, then use dmd_draw_fif() in the code to display it.
FreeWPC does use the memory protection feature, which causes a special area of the regular RAM to be read-only thanks to the WPC memory protection circuit. Note that using FreeWPC will cause any protected data you already have in PinMAME or a real machine to be wiped once you load FreeWPC.
Access functions use checksumming to detect errors, and will reset any bogus fields back to factory defaults to ensure sanity.
Note that protected RAM is also emulated in native mode, by reading/writing the file 'freewpc.mem'.
The core system files are in the kernel directory. This has all of the hardware-related functionality, plus a few other key functions. This code is put into the fixed area of ROM that doesn't have to be bank switched to be accessed.
Other common files are in common. These functions have to be bank switched. This is for occasional functions that are common to all games, like the ball device code, match algorithm, etc.
Game specific files are in machine/gamename.
The system starts in a platform-specific file (start.s for the 6809), then branches into kernel/init.c. Unless you're delving into the extreme low-level details, do_reset in this file is a good place to start.
All switches are polled every 2ms by the IRQ handler. Later, a background task that runs frequently, but at no guaranteed rate, will scan for changes and throw events for servicing the newly activated switches.
The lamp matrix is strobed every 2ms. WPC hardware allows only a single column of 8 lamps to be enabled at any time. The IRQ function rapidly switches between the 8 columns to give the illusion that all 64 lamps are being controlled simultaneously. So the entire matrix is actually updated only once per 16ms. This works well because the lamps have some "memory" after power is cut, causing them to glow a little bit longer.
Less frequently, another realtime task will toggle the states of all lamps that are in 'flashing' state. All of these flashing lamps flash at exactly the same rate, in step with each other.
Lamps whose state is shared among different game modes are periodically redrawn based on game state.
Lamp effects, used for temporary light shows or effects that are more complicated than simple flashing, are drawn onto additional, virtual lamp matrices. These are all overlaid to produce the final image that is drawn onto the physical lamps.
Task-level code can manipulate solenoids (and other drives, like motors) using the functions in include/sys/sol.h. They only modify variables in RAM and never touch the real hardware. At IRQ time, the variables are scanned and the hardware is updated.
The IRQ handler refreshes 1 of 4 banks of 8 solenoids every 1ms; this means each solenoid is updated once every 4ms. Each solenoid has an on/off state and an 8-bit duty cycle mask that allows for efficient strobing at less than full power. Up to 8 phases per cycle can be defined, allowing down to 1/8 power. Anything more complicated requires something at task-level to refresh it.
Absolutely not. More than 98% of the code is in C. The machine description files are even in a more human-readable language. This should make it easier for more people to contribute.
The assembly portions have to do with multitasking, bank switching, and dot matrix drawing. The OS-level code is very stable and isn't likely to change much anymore. The DMD routines are still changing, but may not be of much interest to everyone.
Knowledge of the 6809 is useful, though. The performance of the 6809 C compiler is not perfect, and it's good to inspect the assembly output occasionally to see what it's doing. In most cases, bad code can be improved by rewriting it. Occasionally, patterns are seen which can only be fixed in the compiler itself, but this is very rare.
FreeWPC requires a UNIX-like development system, such as Linux or Cygwin. It probably will work with any of the BSDs just fine, too. Standard system utilities like GCC, bash, perl, and make are required. Also, you'll need a copy of the 6809 GCC compiler, unless you only want to compile in native mode.
FreeWPC comes with an S-record converter to build the final ROM images, and a few other utilities which may be of interest outside this project.
It also uses some other Unix tools that you probably have, too, like the bc calculator program to figure out how much padding is needed on the ROM files.
Contact brian@oddchange.com.
Copy one of the ZIP files into your mame roms directory, renaming it to match what pinmame will look for. If there are sound ROMs, you'll need to put these into the ZIP manually.
If you download a source code package, you can set TARGET_ROMPATH in your configuration file to where PinMAME ROMs are kept, and 'make' will also install it for you.
PinMAME does a lot of things wrong, but does them well enough so that no one will notice. Through the use of schematics and talking with former WMS employees, some of those details have been figured out. PinMAME is getting better and better over time, too.
There are many things that can go wrong on real hardware that can never happen in an emulator. This is why I warn about putting in a real machine. Just because it works on PinMAME doesn't mean it will work elsewhere. I learned a lot of things I didn't know before I put the software into my World Cup Soccer, and continue to do so.
First, welcome to the club :-) Embedded programming isn't easy. There's nothing like GDB to help you on the 6809, but there are ways of debugging that have been incredibly useful to me so far.
PinMAME, at least on Unix, has a debug mode that can be activated using the -d option. This will let you single-step and view memory, although you'll be working in 6809 assembly and not C. Use the map file at build/freewpc.map to correlate addresses to objects.
xpinmame's tracing mode will dump executed addresses to a file. FreeWPC has a script named 'tracer' that can parse these files and report lots of useful info.
You can add debug prints to the code. Use the dbprintf() function to write to the WPC debugger port. On Unix systems, use the patched xpinmame and the wpcdebug utility to view the print messages in realtime. On Windows, you can define CONFIG_PARALLEL_DEBUG to force the messages out the WPC parallel port instead. However, you won't be able to view the data until you exit PinMAME.
Latest version is 0.17