I've almost finished decompiling OutRun's Z80 program code, so I'll be providing high level information regarding its workings over a series of posts.
The Z80 processor controls two pieces of sound hardware; a custom Sega PCM controller and a Yamaha YM2151 FM sound chip. This was a fairly standard configuration for Sega boardsets at the time. As you'd expect, some of the Z80 program code is in fact shared with other games of the era. However, most of the code is unique and written solely with OutRun in mind.
Commands are sent to the Z80 from the master 68000 program code. The Z80's interrupt routine reads from port 0x40 and places the values received into a sequential set of locations in RAM. Commands are high level and consist of a byte corresponding to a Z80 routine. So sending 0x81 plays the 'Passing Breeze' music, whereas 0x9d triggers the 'Checkpoint' PCM sample. From the 68000's point of view, playing a sound is simple and the complexity is nicely masked.
In addition to these commands, the 68000 sends data relating to the volume and pitch of the Ferrari's engine tone. It also sends volume and panning information relating to the passing traffic. This ensures that when you drive past a vehicle, the volume of its engine is proportional to the y distance from your Ferrari and the stereo panning corresponds to the x difference.
The core loop to achieve everything is as follows:
ROM:0039 main_loop:
ROM:0039 call DoFMTimerA ; Wait for timer on YM2151 chip
ROM:003C call ProcessCommand ; Process Command sent by 68000
ROM:003F call ProcessChannels ; Run logic on individual sound channel (both YM & PCM channels)
ROM:0042 call ProcessEngines ; Ferrari Engine Tone & Traffic Noise
ROM:0045 call ProcessTraffic ; Traffic Volume, Panning, Pitch
ROM:0048 jp main_loop
The Z80 maps the 16 channels of the PCM chip to various uses. 6 are reserved for the music's drum samples, 4 are used for sampled sound effects and the remainder are used for the Ferrari's engine sound and passing traffic. Each channel is allocated a 32 byte area of RAM by the Z80 program code, which stores its current state. This concept is extended to include the channels from the YM chip which are also allocated to these areas of RAM.
The usage of the 32 byte area of RAM differs dependent on whether it represents a YM or PCM channel. The area contains everything from basics including volume and pitch for PCM samples through to complex YM configuration including positional information within the current block of audio commands, section loop counters and the address of the next data block. This 32 byte block is used as a starting point to configure the separate PCM RAM area, which has a different format and to program the YM's registers.
Next time, I'll explain the interpreted language stored within the Z80 code. This is used by the Z80 to program the sound hardware. And you'll see how the music and sound effects are actually stored as an interpreted sequence of commands that call functions within the code.
The Z80 processor controls two pieces of sound hardware; a custom Sega PCM controller and a Yamaha YM2151 FM sound chip. This was a fairly standard configuration for Sega boardsets at the time. As you'd expect, some of the Z80 program code is in fact shared with other games of the era. However, most of the code is unique and written solely with OutRun in mind.
Commands are sent to the Z80 from the master 68000 program code. The Z80's interrupt routine reads from port 0x40 and places the values received into a sequential set of locations in RAM. Commands are high level and consist of a byte corresponding to a Z80 routine. So sending 0x81 plays the 'Passing Breeze' music, whereas 0x9d triggers the 'Checkpoint' PCM sample. From the 68000's point of view, playing a sound is simple and the complexity is nicely masked.
In addition to these commands, the 68000 sends data relating to the volume and pitch of the Ferrari's engine tone. It also sends volume and panning information relating to the passing traffic. This ensures that when you drive past a vehicle, the volume of its engine is proportional to the y distance from your Ferrari and the stereo panning corresponds to the x difference.
The core loop to achieve everything is as follows:
ROM:0039 main_loop:
ROM:0039 call DoFMTimerA ; Wait for timer on YM2151 chip
ROM:003C call ProcessCommand ; Process Command sent by 68000
ROM:003F call ProcessChannels ; Run logic on individual sound channel (both YM & PCM channels)
ROM:0042 call ProcessEngines ; Ferrari Engine Tone & Traffic Noise
ROM:0045 call ProcessTraffic ; Traffic Volume, Panning, Pitch
ROM:0048 jp main_loop
The Z80 maps the 16 channels of the PCM chip to various uses. 6 are reserved for the music's drum samples, 4 are used for sampled sound effects and the remainder are used for the Ferrari's engine sound and passing traffic. Each channel is allocated a 32 byte area of RAM by the Z80 program code, which stores its current state. This concept is extended to include the channels from the YM chip which are also allocated to these areas of RAM.
The usage of the 32 byte area of RAM differs dependent on whether it represents a YM or PCM channel. The area contains everything from basics including volume and pitch for PCM samples through to complex YM configuration including positional information within the current block of audio commands, section loop counters and the address of the next data block. This 32 byte block is used as a starting point to configure the separate PCM RAM area, which has a different format and to program the YM's registers.
Next time, I'll explain the interpreted language stored within the Z80 code. This is used by the Z80 to program the sound hardware. And you'll see how the music and sound effects are actually stored as an interpreted sequence of commands that call functions within the code.
3 comments:
Hi. A year or so ago I contacted you about decomposing the Z80 code in SEGA's Flicky game. I wondered if you could talk me through the tools used when dealing with the OutRun Z80 code?
Specifically, I'm trying to figure out why diamonds are only sometimes dropped when a cat is knocked out. A second part to the question would be concerned with the point value of these diamonds.
Any help appreciated. Thanks
Hi Matt. I don't remember the conversation about Flicky, so apologies if I repeat anything here.
The main tools I use are:
- MAME with the debugger enabled. Learn how to use the debugger, watch memory addresses and set breakpoints.
- MAME source code. Use this to understand the memory map and ports of the title.
- Hexray's IDA http://www.hex-rays.com/products/ida/index.shtml
Use this to comment the disassembly as you understand stuff.
Being a small Z80 game, it should be easy to locate the logic. But like all these things, be prepared to put in a good few hours of research.
Here is a good introductory reference for rom hacking:
http://www.jeffsromhack.com/toolbox/index.htm
If you have specific questions, I'm happy to try and help.
The best way to learn this stuff is to allocate yourself a big block of time and get stuck in!
Many thanks. I think you gave me similar advice by email. I'll look into it.
Post a Comment