Monday, February 17, 2020

Williams Defender Sound Disassembly

Here's something different, an in progress attempt to reverse engineer the sound board for the arcade game "Defender" (and others). The sounds are very recognizable, and unique to Williams arcade/pinball machines. They always interested me, so I'm making an attempt to understand them better.

The board is based around a 6808 CPU (relative of the 68000), and a DAC attached to an IO controller. The binary is floating around the web, as is this great disassembler: DASMx. I used it to disassemble the ROM into a code listing, and started commenting it.

Here are the schematics from one of the compatible service manuals:


I was able to use the schematics to figure out the memory map. This helps understand the significance of certain read/writes in the code.
RAM: $0000 - $007F (128 Bytes)
PIA: $0400 - $07FF
ROM: $F800 - $FFFF (2KB)

By loading the ROM into audacity I was able to see some recognizable shapes. These are the waveforms/look up tables stored alongside the code. Some are played directly, while others are used to modulate things like pitch, or volume.

There are some interesting tricks done in the code, and I hope to explain them here one day. Things like dynamically generated delay loops, and something akin to granular synthesis...

Until then, the current version of the commented disassembly lives here.

13 comments:

  1. Very interesting post. Would it be possible for you to share the original data file that you loaded into Audacity above, or explain that process in a little more detail? Thanks for writing this, its inspiring stuff.

    ReplyDelete
  2. Hi Alex,

    Thanks for reading!

    I'm not sure about the legality of sharing the binary (the disassembly is questionable enough).
    It can be found as part of the MAME ROM. Google should be able to pull it right up.
    You can also recreate it by assembling the source code I've posted.

    Loading it into Audacity is simple. Is that the part you're asking about?
    You use the "Import Raw Data" tool and select the ROM.
    The data is mono, 8-bit, though I forget if it's signed or not. Sample rate is irrelevant.

    - Zack

    ReplyDelete
    Replies
    1. As best I can tell, the waveforms are not signed, but "zero based."

      Delete
  3. Hi Zack, thanks for your reply. I tried importing the defend.snd ROM into Audacity earlier and didn't see the waveforms in your image above, but now I see them at the end of the file. Maybe I had the wrong import settings for 'Import Raw Data'.

    I'm currently working on some audio code to be able to modulate pitch and volume using a similar technique (reading data from a lookup table), so I thought it would be interesting if I could use the defender data curves during development, to see if my code could recreate sounds similar to those in defender, before moving on to my own sound design using different curves and additional features. So really I just needed to know where in which data file I could find the data that I wanted to work with. So I'm good to go now.

    Very interesting stuff, hope you get inspired to explore more arcade machine audio in the future. The Williams stuff is especially interesting, they achieved a very high level of audio/visual synesthesia in their games during that time (Defender, Joust, Robotron etc).

    I actually found your site due to the Novation Bass Station schematic, since I bought one of those recently and it blew my mind. So I appreciate your other hardware related posting as well.

    ReplyDelete
    Replies
    1. Good, glad you were able to get it loaded.

      That would be very cool if you were able to synthesize these (or similar) sounds again! I've done my best to label the tables at the end of the disassembly. You should be able to throw them into an array easily.
      Anyway, I'd love to see this functionality re-implemented and expanded on somehow. Please let me know how your project goes.

      There are more tricks that involve multiplying and subtracting waveforms from each other.
      It likes to modulate pulsewidth independent of frequency too. The absolute width (not ratio) might stay constant as the pitch changes.

      Thanks for the kind words. Happy that you enjoy the hardware too. It's all kind of fascinating.

      Delete
    2. To echo that - there's not as much "lookup table" playback as you might think. There are some waveforms which as zack says are (sort of) used to "seed" the various morphing algorithms, but there's only about 7 "basic" waveforms and they are mostly sine saves, one square an one that looks like a comb moddulated by a sine. The "heavy lifting" is done in the morphing algorithms effecting pulse width modulation (when working though the code, I tended to think of it as "sample hold time") thereby effecting pitch and timbre.

      Some of the algorithms don't use these wave tables at all and are purely (variable duty cycle) square waves, white noise, triangles which are morphed/modulated algorithmically. For example the "extra man" sound in Defender/Stargate/Robotron is an example of a "variable duty cycle" square wave synthesized entirely using an algorithm.

      Delete
    3. Dave, it sounds like you've gotten a good bit further than me in understanding the code. Do you have a write up anywhere? I'd love to understand the inner workings, but I don't have the time to keep reverse-engineering.

      Delete
    4. Zack, I don't have a "write up" as such, but I'm happy to discus what I've discovered. However, I am "alive" to the fact that the source code is, despite it's age, still subject to copyright and someone must nominally "own" it, so I have got to be respectful of that and could not (for example) publish lumps of code with a load of annotations. For those interested in sound synthesis, I suspect the algorithms used are going to be of more interest than anything.

      Looking at the architecture of the hardware, it's impressive what was achieved with about the most basic "computer" one could build - no DSP chips or anything like that, the board has a CPU, a ROM (of about 2K,) 128 bytes (just "bytes", not "kilo" or "mega,") of RAM and the PIA driving a D2A into an amplifier and a speaker. But then we are talking about something designed in (most likely) the late 1970's.

      For example, I can steer you the "right" direction as to which of the wavelets in graphic you created out of Audacity are actual sound wave sample data and which are "tables" of data values and not "sounds" in and of themselves. Counting in from the left and starting at "1" - boxes 3-9 are the only actual wavelets used to make sounds. The rest are various data tables use to drive the algorithms that are used to "process" (or "morph" as I call it) the waveforms as they are played out.

      Delete
    5. I don't claim to know the law, but I have a book or two of annotated disassemblies from the 80s. The Commodore 64 has at least six floating around the web now. I assume these are legal for the purpose of education.

      I do generally understand the hardware. It's very limited, but also I think it's pretty respectable for a sound subsystem at the time. It has very roughly the grunt of an Atari 2600, but it's dedicated to sound.

      Regardless, I would like to know more about the algorithms. If you'd be comfortable relating some address ranges to them, that might be the best of both worlds.

      Thanks

      Delete
    6. Thanks for your continued interest. Just to be clear, I have not reverse engineered from the ROM images (I'm not that cool!) Over on GitHub someone has posted the original (assembly language) source for the sounds ROM's (not to mention the original game code.) That might be a better starting point instead of a hex dump of the ROM images. Search for something like "williams sound roms source code" and hopefully you will find your way to the listings on Git. (Hopefully, that will also provide a useful frame of reference for further discussion.)

      The code is fairly sparsely commented and if you are not used to reading 6800 assembly language, may take a bit of time to work through. But having already "been there" myself, I can perhaps help out you find yourself getting stuck.


      Delete
  4. Hi Zack. I wanted to change the code to mask a specific sound request, if possible. Im not clear on where the code to poll the PIA port is. Do you know ? Marcel

    ReplyDelete
    Replies
    1. Hi Marcel.
      It might be easier to find it on the sending side rather than the receiving side.
      I've found the MAME debugger to be really helpful for this kind of thing.

      Delete
    2. The 8224 sound code doesn't "poll" the PIA in the proper "computing science" use of the term poll. It kind of works "the other way round" in that the PIA gets poked into life by the main (game logic) board, the PIA then pulls down an interrupt line of the 680X CPU on the sound board, the CPU then reacts to the interrupt and executes it's interrupt service routine (IRQ) and that then decodes the "sound number" requested and invokes the appropriate code to generate the requested sound which plays to conclusion or until the next such interrupt is received.

      This is a little, er, "backwards" to how one would "classically" be taught how to write an interrupt service routine, but for this use case it's OK as the board doesn't do anything else. So to mask a particular sound, you cold hack into the IRQ handler and amend it to ignore a particular sound, but that's a bit more of a re-write than just "masking" a particular value.

      For completeness - normally one would write an IRQ handler to be short and snappy, do something (like raise a flag or twiddle a few variables) then "return from interrupt" to whatever was being executed when the interrupt occurred. In this sound board's logic, whenever the IRQ fires, the code (almost) completely abandons everything it is doing and despatches itself to execute new sound. (For example, it resets the stack pointer and that's normally a complete no-no in an IRQ handler unless one is implementing, say, a "hard reset.") But to repeat, for this use case where all the board does is makes sounds, it's a neat way to handle it.

      Delete