Articles posted August 2006

Upcoming Changes, part 2

If there's one area that's been sadly neglected in MAME, it's been outputs. Most game PCBs have some means of communicating to the outside world, and while for the most part these outgoing signals are not important from a gameplay perspective, it is not in keeping with the spirit of a documentation project to neglect them as much as we have in the past. Over the years, a couple of standard outputs have been supported: 3 LED outputs have been commonly mapped to the num lock, caps lock, and scroll lock LEDs on your keyboard, and generic support coin counters has been present for a while now. When the old artwork system was introduced, it provided another means of connecting outputs to some kind of visual representation. But nothing tied any of this together. Furthermore, there was no generic means of supporting arbitrary outputs, like the pinball knocker in Q*Bert or other oddities.

In order to help rectify this situation, as of MAME 0.107u4 there is now a generic output support system. It's actually quite simple. You assign each output a name, and the driver calls a new function output_set_value() with the updated value. All the drivers that previously used artwork to indicate the state of an output have been changed to use this new function instead, and the new renderer now queries the output system to get the current state. In addition, the existing LED system now routes all of its outputs through this mechanism, using the names "led0", "led1", "led2", etc. However, a few outputs such as coin counters and ticket dispensing are not reflected this way. You'll see why in a moment.

So you're thinking to yourself, well, what good is this new system? Sure, internally this will help us properly document how the outputs behave on various games, but why make a big deal out of it? Well, if you've ever wanted to hook up a real pinball knocker to fire in Q*Bert or ever tried hacking MAME to route some output to an external connection, this is where it gets interesting.

In addition to keeping track of all the output states, the new output module also allows various components to register for notification when one of these states changes. In the Windows build, the OSD layer does just this, listening for changes in the outputs, and then providing a brand new mechanism for exposing these states to other applications running on your machine. This mechanism takes the form of a few simple custom windows messages that are sent to specially written listener clients. Writing a new client is quite straightforward, and I've even taken the liberty of writing an example client to show exactly how it's done.

Which is why I've removed the keyboard LED support from the Windows builds of MAME.

See, the keyboard LED support is a big hack, and as you all know, I'm not a big fan of hacks. But wait, all is not lost. I took this opportunity to write a little sample output listener client called ledutil.exe. Run this program in the background while MAME is running and you will have your keyboard LED support back. ledutil.exe simply uses the newly provided messages from MAME to do exactly what the old keyboard LED support used to do, but completely external to MAME. If you really like the keyboard LEDs, I recommend you just copy ledutil.exe into your startup folder and never worry about it again.

Here's a basic rundown of how the external messaging works:

When MAME starts up, it broadcasts a message (I call it OM_MAME_START) to all windows in the system letting them know what's going on. All non-listening applications will just ignore this message, but if you've written an app that knows about this message, you can listen for it and respond. Once you get the OM_MAME_START message, you need to respond to MAME in order to register to receive notifications by sending back an OM_MAME_REGISTER_CLIENT message. This tells MAME that you want to hear about changes in any of the outputs.

At this point, you'll start getting some OM_MAME_UPDATE_STATE messages. These messages contain the ID of an output and its current value. But wait, aren't outputs specified by name? Yes, but due to the limits of Windows messages, you only have a couple of integers to pass back and forth, so you will just get an ID.

The first time you see an ID, you'll want to figure out what name it maps to. In order to do that, you'll send MAME an OM_MAME_GET_ID_STRING message, which it will respond to with a standard WM_COPYDATA message. The WM_COPYDATA message is unique in that you can pass larger amounts of data between applications with it. In this case, MAME will respond with a copydata_id_string structure, which contains the ID you requested along with a string containing the output name. You should cache this ID-to-name mapping in your program so that you don't have to keep asking MAME what each ID is.

When you're finished listening, you can send MAME an OM_MAME_UNREGISTER_CLIENT message to tell it to stop sending you stuff. And when MAME shuts down, it will broadcast an OM_MAME_STOP message in case you need to reset any of your state back to normal (for keyboard LEDs we restore the original state at that time). This is also the signal to flush the cache of ID-to-name mappings that you have been accumulating.

And that's pretty much it. It sounds more complicated when I describe it here, but it's actually rather straightforward. The ledutil.c source code in the windows directory is set up in a way that you can change a couple of constants at the top, snip away the LED-specific code at the bottom, and drop in your own implementation which doesn't have to worry about a lot of the details.

I'm hoping this new functionality will inspire some of the BYOAC folks to update their MAME hacks to use this new solution instead, and come up with some other new cool ideas. I'm also hoping it will inspire folks documenting the outputs better in MAME proper, which is something I've been wanting to see for quite some time.

Upcoming Changes, part 1

So I took a break from rewriting the Sega G-80 raster games to fix a few issues in the core system that have come up in the last couple weeks. Screenshots for vector games now work again, and MNG recording is no longer broken. Also, some more cleanup from the video rewrite is still rippling through the system. I'm really excited at all the hacks I've been able to remove now that the video is composited by the OS-dependent layer.

One of the side-effects of the new video system is that drivers aren't allowed to write to the UI layer directly. They can call popmessage() to display a popup at the bottom of the screen, but that's about it in the new system. The problem is that a few drivers were displaying important game-related information using the UI font. Specifically, Atari Football was using it to show which plays had been selected, and the Exidy Max-a-Flex system was using it to draw the status of the lamps and timer. It retrospect, it is actually good that these cases broke because the way it was being done before was a big hack. For one thing, it meant that the game screen area was artificially increased to make room for the text. And second, the state of these lamps was not being properly exposed to the outside world (or in the case of Football, it was being changed via the rendering system in addition to being displayed on screen).

Ideally, the state of these indicators should be made visible via the rendering system. This is great, except that in the absence of an external artwork file, there would be no visible indication at all. This is one of the reasons why it's good to have built-in layouts in the MAME code -- even if they are crude approximations of the original artwork, they at least can reflect important functional information. The problem is, built-in layouts can't really reference image files. All they can do is draw rectangles and disks, which is sufficient for basic overlays on top of old black & white games, but isn't really enough to provide textual information.

In order to solve this problem, I've added a couple of new primitives to the layouts. In addition to rect and disk primitives, there are two new primitives: text and led7seg.

The text primitive lets you add text anywhere within the artwork area. You can specify color and bounds just like the other primitives. The text is drawn using the built-in fixed-width MAME font (even if you have a different UI font), and is centered within the bounds. If there is too much text to fit in the area provided, the font will be squashed horizontally to fit. Here's an example that positions the text "GAME OVER" in red centered within the given rectangle:

<text string="GAME OVER">
    <bounds x="0" y="0" height="10" width="200" />
    <color red="1.0" green="0.0" blue="0.0" />
</text>

The led7seg primitive lets you position a standard 7-segment LED somewhere in the artwork. The LEDs are drawn a high resolution and oversampled down so they look nice. Typically these are used to specify a digit from 0-9. Turbo is one example. To use this, you would typically create an element with multiple states, each state reflecting the corresponding digit. Here's an example that positions a red LED with the number "2" that is only visible with the containing element is in state "2":

<led7seg pattern="10111010" state="2">
    <color red="1.0" green="0.0" blue="0.0" />
</text>

The pattern attribute specifies which of the segments is visible. A 1 means "on", and a 0 means "off". They are specified in the following order:


  1. Top horizontal segment

  2. Upper left vertical segment

  3. Upper right vertical segment

  4. Middle horizontal segment

  5. Lower left vertical segment

  6. Lower right vertical segment

  7. Bottom horizontal segment

  8. Decimal point

Using these two new primitives, I've created built-in layouts for the Atari sports games (Football and Baseball), the Sega Z80 scaling games (Turbo, Subroc 3D, Buck Rogers), Taito's Super Speed Race, and the Exidy Max-a-Flex system that display all the essential lamps and score/timing information. Of course, you can continue to use the externally-provided artwork for a better visual appearance, but now it's possible to provide vital lamps and LEDs via the new built-in layouts without affecting the core game screen or abusing the UI system.

Tomorrow I'll write about the second big change coming, which is related to the issue of lamps and other signals output from the arcade PCBs.

Revisiting the Past

It's been a long-time goal of mine to revisit many of the classic game drivers and give them an overhaul. Apart from my strange obsession with breaking things and reassembling them, there's actually a really good reason for doing so. When MAME was first developed, the obvious focus was on emulating the classics. After all, that's what everyone was most interested in, and since developers on free projects tend to work on what interests them, that's what they worked on. There was a lot of excitement about emulation back then, and for the most part, once a game worked, it was time to move on to the next game. I'm sure the thought that we would have 3000+ games emulated someday was an impossible vision.

Over the past 9 years, there have been a number of important improvements to the core MAME system. Things like tilemaps were added, more accurate timing was provided, better sound routing, improved input port options, more flexible and dynamic memory options, etc, etc. As these things were added, most drivers were updated only in the most fundamental manner, not to really take advantage of any of these features, but just to make sure that they still actually worked. And so today, we have a number of drivers that are very old, which haven't been looked at or updated in years.

But they still work, don't they? Well, yes, they mostly produce seemingly accurate results. But they are far from perfect. And while I don't know that I would call any MAME driver "perfect", most of the early drivers are really quite far from where they could be. For example, I know a number of people have used MAME to develop multigame hacks or hiscore hacks or other interesting variants of arcade systems. And invariably, I hear complaints that what works during development on MAME doesn't work on real hardware, due to the incompleteness of the emulation.

In addition, over the last few years, a much larger collection of arcade schematics and documentation has been discovered, scanned, and made available. Up until the mid-80's, complete schematics for many arcade games were produced and made available to operators so that they could repair problems with the PCBs. This means that many of the "golden age" games are actually well-documented, which makes it a shame that they are largely only very loosely documented in MAME. A large part of the problem with most of the early MAME work is that there was a lot of guesswork involved. Most of the people writing drivers (myself included) couldn't read schematics and didn't have access to a lot of arcade hardware. Thus you find things where, for example, the devs just slapped RAM anywhere the game wrote in the hopes of making it work, without any considering for how much actual RAM was present on the boards.

Finally, a lot of the early drivers were overly optimized. After all, computers 9 years ago weren't nearly as powerful as they are today, and it made sense that you optimized the drivers to ensure that you could hit a solid 60fps on systems of the time. But the problem with optimizations is that they by and large obfuscate what is actually happening. Over the years, I have removed a number of hacks and optimizations from MAME as they became less necessary to achieve an accurate framerate, and this has resulted in much easier to understand code. As a documentation project, it is important that the code make sense and reveal as much as possible about how the hardware actually works.

So far, I've done a fairly complete overhaul of the Crystal Castles and Missile Command drivers, though there are still a few things left to be done. Some important fixes there included getting the correct frame rates based on actual documented video timings, implementing video bitmap access techiques which were not hidden by the optimizations, and correctly emulating the CPU speed in Missile Command (it switches to half frequency for the last 32 scanlines of each frame).

In addition, I used what I learned from Crystal Castles to reimplement the Cloud 9 driver, which now also supports the Atari prototype game Firebeast. These games ran on what is an obvious predecessor to the final Crystal Castles hardware. And thanks to the person who loaned me his Firebeast PCB, I was able to trace out some of the circuits and determine the correct behaviors.

What's next? Well, obviously I have a certain affinity for Atari, Williams, and Sega, so those are obvious candidates. At the moment I am overhauling the Zaxxon driver. Thanks to a tip from one of the other devs, it was pointed out to me that Razmataz and Ixion used the universal sound board that I recently emulated for the old Sega vector games, and that got me interested in cleaning up the whole Zaxxon mess. Beyond that, who knows? And no, I'm not taking requests. :)