Quick update on what I've been upto over the past week. I've decompiled and commented the following code:
- Palette setup for ground colour, road colours etc.
- Palette setup for sky shading effect
- Code to convert internal increment value to user friendly KP/H display. Including tile blitting.
- Code to setup the speed at which to scroll the sprites. This is independent from the road scrolling.
- Code to adjust x position of the car based on the curvature of the road, to ensure car 'sticks' to the road on curves.
- Code to convert steering value from hardware to a meaningful change in x position
- Code to prevent car from straying too far from the boundaries of the road.
There is still a LOT of code to go. This is a long slog!
Monday, April 12, 2010
OutRun Version Differences
Here are some details of the visual differences between the first revision of the OutRun ROMs (deluxe sitdown) and the final revision (sitdown/upright, Rev B).
Notice the omission of "Select Music By Steering" on the original version:
Stage 1, Coconut Beach, has a different track layout.
Notice the absence of scenery on the right hand side, and in the central reservation.
The dual lanes at the start of the track also merge more quickly into a single road on this version.
Notice the strange positioning of the Flamingo huts on the right hand side of the road. These are replaced with palm trees on the later revision.
The well documented course map differences. Older revision shown top. I presume the levels were reordered, so that the more visually impressive levels were shown earlier in the game.
Service Test. Lack of Backup Ram clearing.
Memory Test. Deluxe Sitdown and later revisions.
Can anyone find any more? Once I complete the disassembly of OutRun, then it will be easier to compare the revisions to find out what other subtle, non-visual, changes were made.
Thursday, April 08, 2010
Code Reuse At Sega
Out of curiosity, and to follow up a previous post, I examined some of the Super Hang-On code to figure out the level of code reuse between the games as they share the same hardware. A quick glance at the code shows that a lot of the core routines, responsible for generating the road detailed in this post are identical. It appears that the slave CPU code to handle road splits is removed from Super Hang-On.
It's probably not a surprise, given that there are other obvious similarities between the titles, including some of the sampled sounds being identical.
Now the OutRun hardware supports two road layers. But as far as I know, Super Hang-On only uses a single road layer. Interestingly, there was a conversion of Super Hang-On to the Space Harrier hardware, which only supports a single road layer. Presumably, OutRun wasn't converted in the same manner, because of its reliance on two road layers for the wider roads (even when two distinct roads aren't displayed, the two road layers are sometimes in use).
One other example of code reuse I've found is between OutRun and Sonic the Hedgehog 2 on the Megadrive. Both games share the same random number generator, right down to the default random seed that's used.
It's probably not a surprise, given that there are other obvious similarities between the titles, including some of the sampled sounds being identical.
Now the OutRun hardware supports two road layers. But as far as I know, Super Hang-On only uses a single road layer. Interestingly, there was a conversion of Super Hang-On to the Space Harrier hardware, which only supports a single road layer. Presumably, OutRun wasn't converted in the same manner, because of its reliance on two road layers for the wider roads (even when two distinct roads aren't displayed, the two road layers are sometimes in use).
One other example of code reuse I've found is between OutRun and Sonic the Hedgehog 2 on the Megadrive. Both games share the same random number generator, right down to the default random seed that's used.
Wednesday, April 07, 2010
OutRun Yu Suzuki Interview
Back in 2008, RetroGamer magazine ran an interview with Yu Suzuki discussing the development of OutRun.
The article can be read online here.
It's interesting to read about the features that didn't make it into the final game:
Personally, I'm pleased the checkpoint events didn't make it, as they'd have potentially spoilt the flow of the gameplay. The changeable characters make sense, as the player sprites are drawn separately from the car sprite and have a table of offset co-ordinates. This also allows the car sprite to be horizontally flipped (it wouldn't look good if the players swapped seats, as per the Amiga port). There's no mention of the dual direction traffic that I uncovered in the game code though... :)
In other news, I've returned to working on the Master CPU decompilation at the moment. There's still a heck of a lot of code to plough through, but it's relatively trivial compared with the previous Slave CPU work.
One subtlety that I noticed whilst working on the code is that the position of the shadows in the game change dependent on which direction the car is facing (in practical terms it's set by the x position of the tilemap backdrop). This attention to detail is somewhat outstanding - I'd never even noticed this previously...
The article can be read online here.
It's interesting to read about the features that didn't make it into the final game:
“Because of budget and development time limitations, some of the contents I’d planned had to be squeezed or cut. I’d made preparations for eight individual characters and I wanted to include various events at each checkpoint, which would have made the player experience a story; something like the Cannonball Run film. I also wanted to give players a choice of supercars to drive, so that they could enjoy differences in car performance.”
Personally, I'm pleased the checkpoint events didn't make it, as they'd have potentially spoilt the flow of the gameplay. The changeable characters make sense, as the player sprites are drawn separately from the car sprite and have a table of offset co-ordinates. This also allows the car sprite to be horizontally flipped (it wouldn't look good if the players swapped seats, as per the Amiga port). There's no mention of the dual direction traffic that I uncovered in the game code though... :)
In other news, I've returned to working on the Master CPU decompilation at the moment. There's still a heck of a lot of code to plough through, but it's relatively trivial compared with the previous Slave CPU work.
One subtlety that I noticed whilst working on the code is that the position of the shadows in the game change dependent on which direction the car is facing (in practical terms it's set by the x position of the tilemap backdrop). This attention to detail is somewhat outstanding - I'd never even noticed this previously...
Wednesday, March 10, 2010
OutRun Automapping Tool
At last! I've completed my disassembly of OutRun's slave CPU code. This was by far the most difficult part of the project to date. First, a quick summary of how the road data is stored.
The road data is split into three main components:
1/ The path that the road takes. This is stored as a set of words. Each word ultimately represents the x change of the next road segment, and length of that segment. This data is parsed by a series of functions that interpolate the data and create a nice smooth curve, dependent on the adjacent road segments.
It should be noted that this data does not control the width of the road, the height of the road or how many road layers are enabled.
From what I've seen each stage has a unique path and no data is reused. However, the road split at the end of each segment is reused and the data is mirrored on the x-axis to create the road split.
2/ The height of the road segment. This is divided into a series of segments. Multiple segments are applied to any stage and are reused between stages.
3/ The width of the road segment. This is actually controlled by the Master CPU. I've disassembled the relevant code, but will revisit it at some stage soon.
Finally, the x1, x2 co-ordinates of the road segment are used by the sprite hardware and the scenery positioned on the level.
Interestingly, this means that Outrun's road layer is very dynamic. It's possible to swap the sprites from one stage, with the road data from another. And it's easy to change the height mapping of any point of a level. Very little is hardcoded in terms of screen positioning, and the final world is very much generated in realtime. It's easy to see why an entire 68000 CPU was dedicated to this one task.
As a test of my understanding, I've already converted some of the functions from assembler to a quick java utility. This utility can output the path (point 1 of the list above) of any stage of the game as a CSV file that can be represented by Microsoft Excel. So now it's easy to create an accurate visual map of all the levels, to aid players of the game. Admittedly, once I amend this tool to take the width into account, it will be more useful.
Here is a link to an example from Stage 1 (coconut beach). As mentioned, this map doesn't contain the road split information at the end of the level.
Finally, pleased and amused that people have found the blog interesting - most unexpected. Keep the comments coming.
The road data is split into three main components:
1/ The path that the road takes. This is stored as a set of words. Each word ultimately represents the x change of the next road segment, and length of that segment. This data is parsed by a series of functions that interpolate the data and create a nice smooth curve, dependent on the adjacent road segments.
It should be noted that this data does not control the width of the road, the height of the road or how many road layers are enabled.
From what I've seen each stage has a unique path and no data is reused. However, the road split at the end of each segment is reused and the data is mirrored on the x-axis to create the road split.
2/ The height of the road segment. This is divided into a series of segments. Multiple segments are applied to any stage and are reused between stages.
3/ The width of the road segment. This is actually controlled by the Master CPU. I've disassembled the relevant code, but will revisit it at some stage soon.
Finally, the x1, x2 co-ordinates of the road segment are used by the sprite hardware and the scenery positioned on the level.
Interestingly, this means that Outrun's road layer is very dynamic. It's possible to swap the sprites from one stage, with the road data from another. And it's easy to change the height mapping of any point of a level. Very little is hardcoded in terms of screen positioning, and the final world is very much generated in realtime. It's easy to see why an entire 68000 CPU was dedicated to this one task.
As a test of my understanding, I've already converted some of the functions from assembler to a quick java utility. This utility can output the path (point 1 of the list above) of any stage of the game as a CSV file that can be represented by Microsoft Excel. So now it's easy to create an accurate visual map of all the levels, to aid players of the game. Admittedly, once I amend this tool to take the width into account, it will be more useful.
Here is a link to an example from Stage 1 (coconut beach). As mentioned, this map doesn't contain the road split information at the end of the level.
Finally, pleased and amused that people have found the blog interesting - most unexpected. Keep the comments coming.
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:
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:
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.
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?
UPDATE: Some useful information in the comments below. Thanks to the help of a couple of readers, it's possible that portions of this code have been adapted from a previous Sega title that uses similar road hardware. The original Hang-On from 1985 could be a contender, despite the road hardware differing. Would have to examine the code to be sure. I'd assume that Super Hang On, released after OutRun, which had identical road hardware, reuses this code.
This would also explain why certain blocks of code are unused, the alternate coding style and the relative addresses. As pointed out, you might expect to see NOPs and other quirks if C compiled.
UPDATE 2: Checked Super Hang-On, which runs on the OutRun hardware. A quick look through its slave CPU code reveals much of it is identical.
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?
UPDATE: Some useful information in the comments below. Thanks to the help of a couple of readers, it's possible that portions of this code have been adapted from a previous Sega title that uses similar road hardware. The original Hang-On from 1985 could be a contender, despite the road hardware differing. Would have to examine the code to be sure. I'd assume that Super Hang On, released after OutRun, which had identical road hardware, reuses this code.
This would also explain why certain blocks of code are unused, the alternate coding style and the relative addresses. As pointed out, you might expect to see NOPs and other quirks if C compiled.
UPDATE 2: Checked Super Hang-On, which runs on the OutRun hardware. A quick look through its slave CPU code reveals much of it is identical.
Tuesday, February 02, 2010
C Compilers for 68000
Reading The Making of Gauntlet, I was interested to read the following comment:
Was the game really programmed in C, as opposed to assembler, back in 1985 or is Ed Logg remembering this wrongly? Firstly, the Gauntlet hardware consisted of a 68010 CPU (not the 68000), with a 6502 for sound. Secondly, C compilers in the mid-80s weren't as robust and optimised as today. I can envisage a front-end or name entry screen being programmed in C. But I would expect the majority of the game engine to be assembler for performance reasons. Especially when the article mentions that optimisation was required to ensure the game ran acceptably with so many characters on-screen.
Does anyone have any thoughts on this?
With the switchover from the 6502 to the more capable 68000 microprocessor, the development environment at Atari had changed considerably. “We were actually entering our own code at this point. Our development tools changed, too. We were now programming in C instead of assembly language,” says Logg.
Was the game really programmed in C, as opposed to assembler, back in 1985 or is Ed Logg remembering this wrongly? Firstly, the Gauntlet hardware consisted of a 68010 CPU (not the 68000), with a 6502 for sound. Secondly, C compilers in the mid-80s weren't as robust and optimised as today. I can envisage a front-end or name entry screen being programmed in C. But I would expect the majority of the game engine to be assembler for performance reasons. Especially when the article mentions that optimisation was required to ensure the game ran acceptably with so many characters on-screen.
Does anyone have any thoughts on this?
Subscribe to:
Posts (Atom)












