On entend par code machine le langage du processeur de l'ordinateur. Le modèle d'un processeur est toujours sensiblement le même, il correspond grosso-modo au modèle de Van Neuman, modèle fondateur de l'ordinateur concret.
Selon ce modèle, l'ordinateur est composé en première approximation d'un processeur d'un banc de registres et d'une mémoire, la mémoire est un grand tableau d'entiers, dit aussi mots mémoire. Les registres sont une petite quantité de mémoire rapidement accessible. Le processeur lit une instruction à partir de la mémoire, l'exécute, lit une autre instruction l'exécute etc.
Les instructions du processeur sont élémentaires, ce peuvent être des lectures ou des écritures en mémoire, des opérations arithmétiques simples entières ou flottantes, des sauts (qui font que l'instruction exécutée ensuite ne suit pas l'instruction de saut dans la mémoire). Elle sont simples parce que réalisées par des circuits électroniques. L'innovation de Van Neuman est que le programme réside dans la mémoire et que le processeur l'interprète en quelque sorte. Une machine connue précédente (l'ENIAC) n'était pas un ordinateur au sens moderne, mais plutôt une grosse calculatrice : il n'existait pas à proprement parler de programme, pour calculer un résultat spécifique, il fallait changer les câblages entre les diverses unités de calcul. Par contraste la machine de Van Neuman est un calculateur dont la tâche est d'interpréter des programmes, on parle aussi de machine universelle.
En particulier, et c'est cela qui nous intéresse dans notre cours les programmes sont des données résidant en mémoire, ils peuvent être lus ou produits par d'autre programmes. En ce sens, la machine de Van Neuman ouvre la porte de la compilation.
On comprendra donc que les processeurs se ressemblent tous du point de vue de l'utilisateur, puisqu'ils se conforment tous au modèle initial. Les différences entre processeurs proviennent surtout du jeu d'instructions. On distingue :
•Les (vieux) processeurs CISC (Complex Instruction Set).
◦Leurs instructions sont complexes, de tailles variables, Beaucoup réalisent des transferts avec la mémoire; ils possèdent en général peu de registres. Une opération CISC typique est l'addition d'un registre et d'une case de la mémoire, le résultat étant rangé dans la mémoire, ou une instruction spécialisée dans le transfert des zones de mémoire.
◦Ce type de conception correspond d'abord à l'idée d'une programmation directe de la machine, le programmeur apprécie alors les instructions synthétiques qui lui permettent de faire réaliser des opérations compliquées plus rapidement que par une suite d'instructions. Notons que cette attitude perdure, par exemple les instructions MMX réalisent directement en machine des opérations flottantes sur de petits vecteurs, afin d'accélérer les applications de traitement du signal (ie. image et son).
◦Toutefois, les compilateurs ont du mal à bien utiliser ces instructions. Plus grave, leur présence complique notablement le décodage des instructions par le processeur. En particulier, le format des instructions est peu uniforme : les instructions peuvent occuper un nombre variable de mots.
◦Il s'agit plutôt de processeurs un peu anciens, conçus avant 1985. Typiquement: Intel 8086 et Motorola 68000.
•Les (nouveaux) processeurs RISC (Reduced Instruction Set)
◦Le jeu d'instruction est réduit et très régulier. Les registres sont nombreux (typiquement 32). En radicalisant, seules deux instructions lisent et écrivent la mémoire (lecture dans un registre, écriture d'un registre). Toutes les autres opèrent entre registres, toujours selon le même schéma.
◦La simplicité du jeu d'instruction autorise des logiques de décodage simples et surtout plus facilement réalisables en parallèle, selon le principe du tuyau (pipe). Par exemple, pendant qu'une addition s'exécute dans l'unité de calcul du processeur, l'unité de de décodage des instructions peut être en train de s'occuper de l'instruction suivante, tandis que l'unité de chargement des instructions peu être en train de lire l'instruction suivant l'instruction suivante. En pratique pour une tâche donnée, on peut s'attendre à ce qu'une machine RISC se montre plus rapide qu'une machine CISC, en raison de ce parallélisme interne. Notons aussi que, lors de l'apparition des RISC, la simplicité des processeurs entraînait une conception rapide et donc la mise à disposition du public des technologies de fabrication des circuits les plus récentes (et les plus efficaces).
◦Un compilateur se débrouille bien avec un jeu d'instruction peu étendu et très régulier. Il sait exploiter des registres nombreux. D'autre part, l'exécution en parallèle des instructions impose des contraintes supplémentaires (par ex, le résultat d'une opération n'est pas disponible pour l'instruction suivante) difficiles (mais aussi inhabituelles) pour un humain.
◦Conçus après 1985. Typiquement: Alpha, Sparc et Mips. G4.
Il faut tout de même reconnaître que le fossé entre RISC et CISC n'est pas aussi grand que l'on le pensait dans les années 80. Ici tout est affaire de degré. Les premiers processeurs RISC ne possédaient pas de multiplications câblée (sous prétexte que la multiplication est rare en pratique !), ce n'est plus le cas. À l'inverse, le Pentium (héritier du 8086) a un jeu d'instructions très varié, mais ses diverses incarnations exécutent bien les instructions en parallèle, ce qui était présenté comme propre aux purs RISC à l'origine.