tutorial · Mega Drive
Assembler and C, why both?
The Mega Drive game is written partly in assembler and partly in C. Why two languages for one game? Because they're good at different things, and used together they do a better job. Let's see the difference with a few code examples: the pictures and the green captions are enough to follow along.
The CPU understands only one language
Inside the Mega Drive there's a CPU, the Motorola 68000: it's the processor that runs the game. A CPU understands only its machine language, made of elementary instructions: move a value, add it, compare it, jump somewhere else. Assembler is the readable way to write those instructions, one by one. For example, putting a color into the palette looks like this.
assembler · the CPU's language
Two instructions for a single color. Precise, but writing a whole game at this level would be slow and error-prone. A more convenient layer is needed.
C and the compiler
Here's the convenient layer: C. C is a language closer to how we think, where things are said short and clear. But the CPU doesn't run C: it needs a compiler that turns C into machine instructions. The path is this:
On the left the C as it's written, on the right the machine code the compiler produces.
C · how it's written
assembler · what the compiler generates
Three lines of C become six machine instructions, and the compiler writes them, without mistakes. That's why most of the game is in C: shorter, clearer, faster to fix.
So why not everything in C?
If the compiler is so good, why not write everything in C and drop the assembler? Because there are three points where the compiler isn't enough and assembler must be written by hand. Let's look at them.
Boot, before C can run
At power-on the CPU starts in a raw state: memory isn't set up and, above all, there's no stack yet, the memory area C uses for function calls and local variables. Without a stack, C can't run. So the first bit of code, in assembler, prepares the ground and then hands over to C. By convention this file is called crt0. The boot sequence:
top of the ROM
sets up the stack, disables interrupts
init and game loop: the game starts
crt0.s · assembler
main.c · C
Assembler sets the stage; then C takes over. Without those few opening lines, C couldn't even start.
The vector table
The moment it powers on, the CPU reads a vector table at the top of the ROM: a list of addresses in a fixed order set by the hardware. Here's how the ROM is laid out, and which parts are assembler and which are C.
assembler · the vector table
dc.l means "a 32-bit value goes here". Each line is an entry in the table. The hardware always reads it in this order: move the entries and boot crashes.
When speed matters
The compiler generates good code, but in some spots maximum speed is needed: for example copying a lot of data into VRAM (video memory) within one frame, or a stutter shows. In these critical spots hand-written assembler, picking the best instructions, beats the compiler. Just a few lines, but decisive for smoothness.
assembler · hand-written, for speed
Here control must be total: the instructions are hand-picked to be the fastest. It's the one case where assembler beats the compiler, using a trick the compiler doesn't apply.
Everything else: the logic, in C
Apart from those three points, all the game logic (character movement, jumps, enemies, collisions, score) is written in C. It's the part that changes most often, and in C it's more readable and quicker to change.
game.c · the character's jump
It reads almost like pseudocode: if fire is pressed, jump; gravity accelerates downward; update position; stop at the floor. In pure assembler it would be three times the lines and harder to change.
Two tools, one job
assembler · the low level
C · the game logic
Assembler and C aren't in competition: they split the work. Assembler handles boot and the low-level spots; C expresses the logic clearly. Together they're more efficient than either alone. On top of that, the same C code can also be compiled on the development machine: that way it's tested before going into the ROM.