Chris White - Emulation & Decompilation

Monday, February 22, 2010

C Compilers

Following my previous post, where I questioned whether Gauntlet's code was written in C as opposed to assembler, I've come to the realisation that OutRun's slave CPU code was probably generated by a compiler and is not hand-written assembler.

The slave CPU controls the road rendering. So essentially it generates the curves, height variation, road splitting and appearance, from the level data.

This has added an extra layer of obfuscation to the decompilation, as the resulting code is less logical and is convoluted to follow. Maybe AM2 had spare CPU cycles to play with, and decided to simplify the source code to this complex area by writing the code in C, as opposed to assembly code as used by the main CPU.

One of the first instructions sets one of the address registers to point at the start of RAM:

lea ($60000).l,a5

The a5 register is never changed and there seems to be an over-reliance on using this block of memory, where a data register would be much faster:

move.l  d1,$712(a5)
; ...
add.l   $712(a5),d2     ; Why not use add.l d1,d2?

And then there are blocks of code that are just pure spaghetti or irrelevant. I don't know much about compilers, but back in 1986 it's clear they produced dreadful code.

ROM:00001C80 tst.w   $720(a5)
ROM:00001C84 beq.w   *+4          ; What is this here for?
ROM:00001C88 addi.w  #$100,d1

On the other hand, a quick look at Gauntlet's code in Mame's debugger does not seem to yield equal levels of insanity. Maybe Gauntlet was coded in assembler after all.

I'd like to know what compiler Sega/AM2 were using. Does anyone know if it's possible to determine from a signature in the code? Is C the likely source language?

Labels:

Thursday, January 14, 2010

Hidden Voices

If you try OutRun's Sound Test, you'll notice there are four voices you can apparently play. These are the speech samples Get Ready, Congratulations and Check Point. The forth sample, "Voice 4", doesn't work. If, like me, you've lost sleep over such a monumental issue - read on!


The elusive fourth voice is, in fact, still in the ROM files, namely those containing the PCM sample data. You can import these ROMs straight into a sound editor like Audacity and play them. I imported the raw files as PCM 8-bit unsigned, with a sample rate of 8000Hz. Note that the sample rate of the individual samples does differ though.

The 192K of sample data is stored across the following files:

opr10188.71
opr10189.70
opr10190.69
opr10191.68 - This file contains Voice 4
opr10192.67
opr10193.66

These PCM files contain all samples from the drums used in the music, through to the sound effects and speech.

You can hear an mp3 I exported of the voice here. The voice is "You're Doing Great", and seems to be stored at around 4000Hz, which is a lower sample rate than the other voices, which are at 8000Hz. I imagine the sample was removed because the designers couldn't figure out a good way of invoking it.  There is already a voice at the checkpoint stage, which is the main way of determining your progress. Using the voice mid-level, based on your current position and time, could have created bugs or just not proved that compelling.

I should admit that I haven't debugged the sound code much, so a lot of this is based on pretty rough experimentation. I haven't delved into the code to see if it's easy to hook this sound up somewhere with brief debugging. There are certainly no high-level calls from the 68000 code, as I've listed every sound that can be played (and there are more than just those in the sound test). Looking at the Z80 code might yield more information. But I don't envisage having to port this directly, as I am planning with the 68000 code.

Update: Thanks to the JAMMA+ forum I've been informed this hidden voice is apparently used in Space Harrier. So maybe the OutRun developers started by using some of the Space Harrier code as a framework. Certainly some of the error messages are the same as shown in previous blog posts.

Labels:

Tuesday, January 12, 2010

Level Select

Yesterday proved a little more fun. Whilst debugging the slave road CPU code, I figured out how to change the level order in OutRun. Using this, you could easily make a level select. Also found a way to have the road data from one level, with the object data from another. It doesn't always work, but does allow you to make some interesting permutations. Some level data for Stage 1 is also hardcoded, but when I finally rewrite the engine in C, this will be trivial to solve.

Labels:

Monday, January 11, 2010

Slave CPU Code

Spent most of yesterday working on the code that runs on the slave CPU. On a positive note, there isn't much of it. The code is minimal compared with the main CPU. It's a loop that handles rendering the road. On a negative, progress is slow. I spent most of the afternoon trying to figure out a few hundred lines of assembler and now feel like gouging my eyes out.

Labels:

Tuesday, January 05, 2010

Outrun Unidesa Manual

I've had no free time lately. But the following manual arrived in the post:


It's an OutRun arcade manual from a Spanish company called Unidesa (Universal De Desarrollos Electronicos S.A.) who seem to have licensed OutRun at some stage. The company still exists and has a website here.

I expected it to be a straight translation of the common English Sega manual that can be found at KLOV.

Whilst the manual initially does contain translations of the service tests and dip switch settings, it interestingly contains additional technical information not present in the Sega manual. Most importantly, it contains a fantastic diagram of the OutRun PCB, with all components labelled. If I had a scanner, I would scan these in, but for now I will simply list the additional pages. The diagrams are not hand drawn, like the English Sega manual.

1/ Video Board Block Diagram:
- Video board clearly divided into labelled components including ROM, RAM, Power Outputs and the explanations of what functions the other areas of the board performs. Each component is numbered.

2/ CPU Board Block Diagram
- Similar to the above. Divided into Main CPU, Slave CPU, Road Character Generator etc.

3/ General Wiring
- A superclear wiring diagram for the Outrun cabinet. This is far better than the Sega effort. Each wire leading into the PCB and other components is clearly labelled with its function and colour.

There are also a couple of detailed technical pages about the Hantarex monitor, that don't appear in the Sega manuals including a nice circuit diagram.

If anyone knows whether there was another manual to accompany this one, or has further information - please let me know.

Update: Here is a picture of the Unidesa white OutRun cabinet, via the JAMMA+ forums. The PCB is different from the Sega version, which would explain the alternate diagram in the manual. The game uses the European track layout.

Labels:

Friday, November 27, 2009

Game Objects and Level Format

I've made a lot of progress. After a lot of hard work I've figured out the internal object format used by OutRun for most sprites and game objects which is a big breakthrough. I understand the complete format, with the exception of a single bit that eludes me right now. The internal format is a lot more complex than the values finally written directly to the sprite hardware, as it includes aspects like:

  • Both Screen Co-ordinates & World co-ordinates
  • Sprite Z Values
  • Independent priority settings in relation to the road layer and other sprites
  • Specific Sprite routines to use
  • X/Y Draw anchors
  • Sprite Type
  • Frame Number
  • The way in which the sprites utilise a series of lookup tables to extract more properties
  • All the usual things you'd expect: h-flip values, palette settings and so forth.
The traffic sprite format uses a version of this, but adds additional properties:
  • Bits to denote the traffic's position in relation to other traffic. This is used to control its speed and lane changing behaviour. 
  • Speed
  • Information regarding the side of the road the traffic has spawned on
Even after establishing the above, and also a lot of related code - one thing is pretty clear: the codebase to this game is advanced and complex.

I also understand the internal format used to store the scenery data for the entire set of levels. Writing a quick utility to spit this out in some kind of visual form would be an interesting exercise and a way of verifying this. Whilst all the code is documented and commented, looking at it actually hurts by brain. I'll follow up on this later.

Labels:

Wednesday, November 11, 2009

Look Both Ways!

One interesting aspect of disassembling games you're fond of, is that you might uncover hidden code that was unused in the final build. This can give an insight into some of the features that were planned that didn't make the final cut, either because of time, technical problems or maybe they simply didn't prove fun during playtesting.

Lately I've been disassembling the traffic handling code, and in doing so I stumbled upon an interesting memory address that controlled a block of code related to spawning traffic. I was unable to figure out exactly what it did from the code and couldn't find any references where the address was written to. So I fired up the MAME debugger and wrote to the memory address manually so that the block of code would always execute.

In Outrun, all traffic drives into the horizon before disappearing. To my surprise, setting this flag caused the traffic to drive away from the horizon in the opposite direction towards the player's Ferrari. I imagine that the original idea was to have two-way traffic. The fact that Outrun's hardware supports two separate road layers means that the final effect could have been quite impressive with independent flows of traffic on each road!

As it is, the code is clearly unfinished, and no graphics exist for traffic travelling in the opposite direction. But it demonstrates what the development team originally planned. It certainly would have been impressive back in 1986 if they'd pulled it off. 

You can see for yourself in the MAME debugger by changing the address with: b@60b6b = 1 once the game has booted.

Labels:

Tuesday, November 10, 2009

Extend Time!

One of the aspects of OutRun that somewhat puzzled me as a player, was exactly how the "Extend Time!" feature at the end of each level worked.

This is the additional time that is added to the countdown timer on passing a checkpoint. I've never seen details published - until now....

Here's a table that shows the time, in seconds, that is added to your overall counter per stage. The rightmost route is show first. The DIP switches of the arcade cabinet can be set to four difficulty settings for timing, and each respective setting has its own column. If you are lucky enough to find a working cabinet in the wild, it's easy to determine the setting by looking at how much time you start the game with.

.
         | Easy | Norm | Hard | VHar |
         '------'------'------'------'
Stage 1  |  80     75     72     70  |
         '---------------------------'
Stage 2a |  65     65     65     65  |
Stage 2b |  62     62     62     62  |
         '---------------------------'
Stage 3a |  57     55     57     57  |
Stage 3b |  62     60     60     60  |
Stage 3c |  60     60     59     58  |
         '---------------------------'
Stage 4a |  66     65     64     62  |
Stage 4b |  63     62     60     60  |
Stage 4c |  61     60     58     58  |
Stage 4d |  65     65     63     63  |
         '---------------------------'
Stage 5a |  58     56     54     54  |
Stage 5b |  55     56     54     54  |
Stage 5c |  56     56     54     54  |
Stage 5d |  58     56     54     54  |
Stage 5e |  56     56     56     56  |
         '---------------------------'

To be honest, some of the entries are a little strange. For example, why is Stage 3a (Cloudy Mountain) more difficult on Normal than Very Hard? Is this an error in the table?

I'm working from the Overseas version of Outrun. I'm not sure yet whether the table differs for the Japanese version where Gateway has been moved to Stage 4.

It should also be pointed out that all the tracks in Outrun are the same length from a technical point of view. Obviously some will be tougher in terms of sharp bends and thinner stretches of road. The road split at the end of each level is hard coded and not read from the level data.

Moving onto the traffic in the game. Once again, this can be set by the DIP switches to four independent settings. I haven't reverse engineered the traffic code in detail yet, but I can provide some rough guidance as to how the settings affect each level in the game. It's my understanding that the following table represents the maximum number of vehicles that can be spawned simultaneously on each level.

.
         | Easy | Norm | Hard | VHar |
         '------'------'------'------'
Stage 1  |   2      3      4      5  |
         '---------------------------'
Stage 2  |   2      4      5      6  |
         '---------------------------'
Stage 3  |   3      5      6      7  |
         '---------------------------'
Stage 4  |   4      6      7      8  |
         '---------------------------'
Stage 5  |   5      7      8      8  |
         '---------------------------'

Looking at the code which spawns the traffic, hacking the game to support more traffic wouldn't be trivial because there are only 8 slots in the jump table reserved for traffic sprite routines.

Labels:

Tuesday, October 20, 2009

OutRun Gameplay Laserdisc & VHS

I'm still beavering away, reverse engineering the OutRun source. I'm focusing on the sprite routines and level data at the moment. Both of which are quite complex. I've uncovered some pretty intriguing stuff, and understand why OutRun uses the convoluted jump table I mentioned in an earlier post. It's related to rendering the level data, and many of the repeated routines handle sprites.

But I'm not going to talk about that right now, as there's still further work to be done. Instead let's take a look at some curiosities I've found on ebay over the years.

First up is a rare Japanese video laser disc (i.e. not a game in anyway), manufactured by Pony Canyon in 1988. Pony Canyon are a Japanese publisher, who also published the MSX 2 version of Outrun. 




The laserdisc is a small 20cm disc, so requires an adapter to work in certain players. I don't have a laserdisc player, but the contents are probably an Outrun gameplay playthrough identical to the video below.

The accompanying booklet contains information on the stages in the game. I would love to get this translated if anyone can speak Japanese?






Pony Cannon also released the "Game Simulation Video" featured below in the same year. The video contains footage from Galaxy Force and Thunder Blade in addition to Outrun.






The booklet that accompanies the video, shows a range of these videos was available. Other titles included After Burner, Hang-On, R-Type, Street Fighter and more. Incidentally, at the time I purchased the Outrun LD, the same seller also had a Turbo Outrun disc. But I'm not a huge fan of Turbo Outrun, so I passed on that option.







I'd be interested to know if the recent Outrun anniversary soundtrack compilation contains the same gameplay video bonus disc. I notice it's also licensed from Pony Canyon.




I'll upload some more detailed images in a few days time. But for now, I'm heading to bed!

Update:
The following laserdisc appeared on ebay shortly after I posted this article. I'm presuming the contents are identical to the VHS and existing laserdisc I own.



 
 


Labels:

Tuesday, September 29, 2009

Tools and Tiles

Wrote a quick tool, which takes an Outrun CPU 0 memory dump from the MAME debugger as input. As output it prints the jump table from that stage of the game that has been built and stored in RAM.

This is handy, because it formats the data and only shows the addresses which are currently enabled, and doesn't repeat addresses when they're called in succession. The table in RAM itself is 124 entries long, and updated at various points during runtime.

So here's the in-game output:

0. 0xB15E
1. 0x74E2
2. 0x3BEE
3. 0x4048 (16 times)
21. 0x4828 (15 times)
82. 0x4ADC
83. 0x5248 (5 times)
91. 0x9862
92. 0x9C84
93. 0xA568 (2 times)
95. 0x5EA8
103. 0xA816
104. 0xA7D2
105. 0xA816
106. 0xC5A4
123. 0x78B0
124. 0xE644


This has made it easier to figure out exactly where in code the program is updating this table.

What else? I've been looking into the tile handling code. Tilemaps are used in OutRun for the horizon graphics (two layers) , the text layer is a tilemap and obvious things like the music selection screen are a tilemap. Each tile entry in the map is a word. The compression format for the first tilemap I've analysed in ROM is as follows:

1/ If a word is not '0x0000', copy immediate word directly to tileram
2/ If a word is '0x0000' a long follows which details the compression.
The upper word of the long is the tilemap value to copy.
The lower word of the long is the number of times to copy that value.

And here's how OutRun manages to store your exact route history through the levels in just a byte.

1/ There are 5 stages, and a memory location increases by 0x10 for each stage you progress.
2/ Each stage forks twice, giving 15 stages in total. At each stage, this same memory location increments as follows when the left hand route is selected:

Stage 1 = +8 (1 << 3 - 0)
Stage 2 = +4 (1 << 3 - 1)
Stage 3 = +2 (1 << 3 - 2)
Stage 4 = +1 (1 << 3 - 3)
Stage 5 = Road doesn't split on this stage

3/ Later this indexes into a lookup table, which then makes it easy to update things like the stage map at the bottom right hand corner of the screen during gameplay.

Other than that, I'm thinking about how to represent the graphics once I convert the engine to C. Do I keep them in a similar format, and just render a final array of pixel data (similar to how an emulator would render it's display), or do I convert them to a native PNG or similar? This would make it easier for someone to replace them and change the game, but could run into problems with palette changes and so forth. Thoughts...

Anyway, this post might give you some idea of some of the things I'm doing at the moment. There's still a long way to go.

Labels:

Thursday, September 17, 2009

Quick progress report: Commented all the code relating to detecting when the car is off-road. Figured out the memory location that determined which wheel was off. Established the memory location that determined the width of the road, and handles splitting the road between number of lanes and individual roads. Commented some slightly less interesting code relating to lap times, output lamps and various other areas.

Amusing OutRun link: Unbelievable. I have found someone with a more insane project than my own. A real world OutRun cabinet containing a golf-cart... The mind boggles?

Labels:

Thursday, September 10, 2009

Debugging

I reached a point where it was time to switch to a competent interactive debugger, instead of working out of a series of text files that were becoming increasingly difficult to manage.

It took me a good few days to transfer my comments and knowledge to the new system. But the payoff is massive - I've immediately spotted mistakes, and identifying blocks of code has become a lot less painful.



In the screenshot you can see the commented block of code that transfers the in-game timer to the on-screen HUD.

Yesterday I also documented how the main branch table works in memory. In fact, I'm not even sure if branch table is the correct terminology. Figuring this out was important because actually determining the program flow in Outrun is tricky. The list of functions that are finally called is generated at runtime, and differs at different points of the game.

Firstly, there's a portion of ROM that contains a series of long addresses. Each of these addresses is a pointer to another portion of ROM. This second portion of ROM contains a set of properties related to the function, and the final address of the function itself. The final step is to compile these to a table within RAM. This table contains bits so that the functions can be enabled or disabled.

I presume this is some kind of optimisation, but it seems to add a lot of indirection and makes following the flow of code rather tough from the onset. Maybe some level of obfuscation was the idea? Perhaps someone reading who is a 68000 wiz will know.

Update: Figured this out. Some useful information in the comments regarding this from one of the blog readers and myself :)

Labels:

Thursday, August 27, 2009

Decompilation Update

As predicted, progress is slow and steady.

The most satisfying way of working is attempting to solve as many unknowns in a particular area, and then moving on when the going gets tough. Going back to a set of routines with a fresh pair of eyes really helps.

Some areas that I've worked on:

1/ Car control (X Position, Acceleration, Gear Changes)
2/ Road splitting code (High level areas including the 'road splitting state')
3/ Elements relating to the current track segment
4/ Sprite rendering code (Very complex, so moved on temporarily from there)

I've successfully understood various memory locations, and slowly routines become understandable from the meaningless muddle they originally were.

Labels:

Tuesday, August 11, 2009

Outrun Decompilation Oddities

The decompilation is moving along reasonably nicely. I've slowly picking up a decent understanding of the game code.

One interesting thing with the decompilation is that it uncovers code routines and text that don't appear to be in the final game.

For example, check the strings in the following screenshot:



BIN CHAN E
COLOR BANK GA TARINA NOYO !
1 STAGE 127 KO INAINI SHITENE

If you set the program counter to 0x7644 (by typing pc=0x7644) in the mame debugger, and resume execution you will see for yourself.

Any idea if this string is used, or whether it means anything interesting?

UPDATED: Thanks to bluepillnation who points me towards the following link relating to Space Harrier.

Firstly, the text can be translated roughly as follows:

To BIN (a developer?)
Color bank is lacking.
Make it less than 128 for one stage.


It's suggested that this is some kind of protection. "Sega use the MCU to copy tilebank values on most of the system16 games, maybe they use it to copy a colour bank value on space harrier too, but it's not obvious until you get to that stage".

Labels:

Monday, August 10, 2009

OutRun Decompilation Project

I'm something of an OutRun obsessive. I've got the arcade machine in my parent's garage (they keep requesting that I remove it) and I coded the OutRun driver for Jemu2. The game has so many memories attached to it, and it will always hold a lofty place in my heart beyond what it probably deserves.


One coding project that I've dabbled with on rainy days, is a full decompilation and reverse engineering of the original arcade ROMs. This is a massive undertaking, and one that I suspect I will never truly complete. But it is intriguing to pull apart the game I loved so much as a kid, to find out exactly how it works.

The ultimate goals of this project are:

1/ Reimplement OutRun in portable C, so that it can be compiled to pretty much any modern handheld/computer. And the code can be easily extended/modified.

2/ Create a level editor for the game. Potentially for the original arcade version and the version created in step 1.

Realistically, it will probably just be a bit of fun. If you can call pouring through thousands of lines of unlabelled, uncommented, decompiled 68000 assembler fun that is.

So far, my steps have been as follows:

1/ Wrote a program to de-interleave the arcade ROMs and spit them back out. I've then decompiled them to text files.

2/ Made some notes on the OutRun hardware via reference to the Mame source code.

3/ Begun commenting the decompiled assembler, using the Mame debugger for assistance.

Progress is promising. I started by figuring out all the routines for the text layer of the hardware. As the name suggests, this is essentially a layer of 8x8 tiles that is used to print things like "INSERT COIN" to the screen, and some other static graphics like the HUD elements.

It's been quick to rattle through the code and comment exactly when and where the graphics are blitted. So I quickly have an understanding of the general code structure, from the service tests through to high score tables and even the OutRun easter egg, which prints Yu Suzuki's name.

I've also figured out a lot of other important information, including the memory address used to store the games internal state (e.g. attract mode / music selection / high score entry / in-game / clock countdown / map screen), which makes identifying roughly what individual areas of code are performing far simpler.

There's a lot more I've managed to achieve, although this is a project whereby progress is slow until you reach a tipping point. The most similar project I've worked on previously was converting Speedball 2 to J2ME phones. But as this was an official port, I had access to nicely commented and labelled 68000 assembler - much easier.

In other news, I haven't forgotten about FlashGear, just put it on hold for the time being, until I get the motivation to polish it up for a release.

Labels: