tutorial · Mega Drivetutorial · Mega Drive
Assembler e C, perché tutti e due?Assembler and C, why both?
Il gioco per Mega Drive è scritto un po' in assembler e un po' in C. Perché due linguaggi per un gioco solo? Perché servono a cose diverse, e usati insieme fanno un lavoro migliore. Vediamo la differenza con qualche esempio di codice: per seguirlo bastano le figure e le note in verde. 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.
La CPU capisce un linguaggio soloThe CPU understands only one language
Dentro il Mega Drive c'è una CPU, il Motorola 68000: è il processore che esegue il gioco. Una CPU capisce soltanto il suo linguaggio macchina, fatto di istruzioni elementari: sposta un dato, sommalo, confrontalo, salta a un altro punto. L'assembler è il modo leggibile di scrivere quelle istruzioni, una per una. Per esempio, mettere un colore nella tavolozza (la palette) si fa così.
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 · linguaggio della CPUassembler · the CPU's language
Due istruzioni per un solo colore. Preciso, ma scrivere un gioco intero a questo livello sarebbe lentissimo e facile da sbagliare. Serve uno strato più comodo.
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.
Il C e il compilatoreC and the compiler
Ecco lo strato comodo: il C. Il C è un linguaggio più vicino al nostro modo di ragionare, dove le cose si dicono in modo corto e chiaro. La CPU però il C non lo esegue: serve un compilatore, un programma che traduce il C nelle tante istruzioni macchina che la CPU capisce. Il percorso è questo:
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:
A sinistra il C come si scrive, a destra il codice macchina che il compilatore produce.
On the left the C as it's written, on the right the machine code the compiler produces.
C · come si scriveC · how it's written
assembler · cosa genera il compilatoreassembler · what the compiler generates
Tre righe di C diventano sei istruzioni macchina, e le scrive il compilatore, senza sbagliare. Per questo la maggior parte del gioco è in C: più corto, più chiaro, più veloce da correggere.
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.
Allora perché non tutto in C?So why not everything in C?
Se il compilatore è così bravo, perché non scrivere tutto in C ed eliminare l'assembler? Perché ci sono tre punti in cui il compilatore non basta e l'assembler va scritto a mano. Vediamoli.
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.
L'avvio, prima che il C possa girareBoot, before C can run
All'accensione la CPU parte da uno stato grezzo: la memoria non è preparata e, soprattutto, non esiste ancora lo stack, l'area di memoria che il C usa per le chiamate di funzione e le variabili locali. Senza stack, il C non può girare. Quindi il primissimo codice, quello che imposta lo stack e poi passa il controllo al programma, è per forza in assembler. Per convenzione questo file si chiama crt0.
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:
in cima alla ROMtop of the ROM
imposta lo stack, spegne le interruzionisets up the stack, disables interrupts
init e game loop: il gioco parteinit and game loop: the game starts
crt0.s · assemblerassembler
main.c · CC
L'assembler prepara il terreno; poi entra il C. Senza quelle poche righe iniziali, il C non potrebbe nemmeno partire.
Assembler sets the stage; then C takes over. Without those few opening lines, C couldn't even start.
La tabella dei vettoriThe vector table
Appena accesa, la CPU legge in cima alla ROM una tabella dei vettori: una lista di indirizzi. Il primo dice dov'è lo stack, il secondo da quale indirizzo iniziare, altri dicono quale routine chiamare quando arriva un'interruzione o un errore. Deve stare in una posizione e in un ordine precisi, decisi dall'hardware: si scrive a mano in assembler, perché il compilatore non saprebbe collocarla esattamente lì.
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 · la tabella dei vettoriassembler · the vector table
dc.l significa «qui va un valore a 32 bit». Ogni riga è una voce della tabella. L'hardware la legge sempre in questo ordine: spostare le voci manda in crash l'avvio.
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.
Quando conta la velocitàWhen speed matters
Il compilatore genera codice buono, ma in certi punti serve la massima velocità: per esempio copiare molti dati nella VRAM (la memoria video) entro il tempo di un frame, altrimenti si vede uno scatto. In questi punti critici l'assembler scritto a mano, scegliendo le istruzioni migliori, batte il compilatore. Sono poche righe, ma decisive per la fluidità.
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 · scritto a mano, per la velocitàassembler · hand-written, for speed
Qui il controllo dev'essere totale: le istruzioni sono scelte a mano per essere le più rapide. È l'unico caso in cui l'assembler batte il compilatore, sfruttando un accorgimento che il compilatore non applica.
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.
Tutto il resto: la logica, in CEverything else: the logic, in C
Tolti quei tre punti, tutta la logica di gioco (movimento del personaggio, salti, nemici, collisioni, punteggio) si scrive in C. È la parte che cambia più spesso, e in C è più leggibile e più veloce da modificare.
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 · il salto del personaggiothe character's jump
Si legge quasi come pseudocodice: se si preme fuoco, salta; la gravità accelera verso il basso; aggiorna la posizione; fermati al pavimento. In assembler puro sarebbe il triplo delle righe e più difficile da modificare.
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.
Due strumenti, un lavoroTwo tools, one job
assembler · il basso livelloassembler · the low level
C · la logica di giocoC · the game logic
Assembler e C non sono in competizione: si dividono i compiti. L'assembler gestisce l'avvio e i punti a basso livello; il C esprime la logica in modo chiaro. Insieme sono più efficienti di ciascuno da solo. In più, lo stesso codice C si può compilare anche sul computer di sviluppo: così si collauda prima di metterlo nella ROM.
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.
← Tutti i tutorial← All tutorials I muri superati sul Mega DriveMega Drive walls overcome