13. TP CPU

Le processeur, aussi appelé CPU (Central processing Unit) ou unité de traitement central, lit des instructions dans la mémoire programme et les exécute.

Tout ce que le processeur fait peut être décrit en 3 lignes:

  • chercher une instruction dans la mémoire de programme (Fetch)

  • exécuter cette instruction (Execute)

  • incrémenter le pointeur vers la prochaine instruction (Increment)

Dans cette section nous allons étudier comment encoder des instructions en code binaire, et comment ensuite exécuter ce code dans le CPU. Nous allons nous inspirer du premier microprocesseur, la puce Intel 4004, sortie en 1971.

boitier

13.1. Intel 4004

Le premier CPU sur un seul circuit intégré fut le 4004 commercialisé par Intel en 1971. Il contenait les éléments suivants:

  • une ALU (unité arithmétique et logique)

  • 16 registres de travail

  • un accumulateur (accumulator)

  • un bus de données (data bus)

  • un bus d’adresses (adress bus)

  • des fanions (flags)

  • un registre d’instruction (instruction register)

  • un compteur de programme (program counter)

  • un pointeur de pile (stack pointer)

  • une pile (stack)

  • une unité de contrôle (control unit)

Voici le schéma de l’architecture du 4004.

4004

13.2. Langage assembleur

Nous allons commencer tout de suite avec un exemple de programme pour le 4004, en langage assembleur. Voici un bout de programme qui additionne deux nombres 4 bits.

ADD2
; add two 4bit numbers on the Intel 4004
;
    FIM P0, $A2 ; initialize: R0=2 R1=A
    LDR R0      ; load R0 into accumulator
    ADD R1      ; add R1 into accumulator
    XCH R1      ; and store in R1

Le point-virgule (;) sert comme symbole de commentaire. C’est l’équivalent du # en Python. Un programme en assembleur est typiquement structuré en 4 colonnes :

  1. Une étiquette pour désigner une adresse de programme (ADD2)

  2. Une mnémonique de l’opération (FIM, LDR, ADD, XCH)

  3. Des données (P0, $A2, R0, R1)

  4. Des commentaires en fin de ligne

13.3. Le langage machine

Le langage machine, ou code machine, est la suite de bits qui est interprétée par le processeur d’un ordinateur exécutant un programme informatique. C’est le langage natif d’un processeur, c’est-à-dire le seul qu’il puisse traiter. Il est composé d’instructions et de données à traiter codées en binaire.

  • 1000RRRR additionne (ADD) le registre RRRR à l’accumulateur

  • 1001RRRR soustrait (SUB) le registre RRRR de l’accumulateur

  • 1101DDDD charge (LDM = load) le nombre DDDD vers l’accumulateur

Le code machine est composée de :

  • la partie instruction ou opcode, tel que 1000=ADD, 1001=SUB

  • la partie donnée ou data, qui indique un registre RRRR où un nombre DDDD

Par exemple l’instruction en assembleur ADD R3 se traduit en code machine comme 10000011.

Trouvez les deux autres codes machine.

13.4. Mémoire de programme

Le CPU 4004 traite des données de 4 bits. Les données que ce processeur peut traiter avec une seule instruction sont limitées à une plage de 0 à 15 (de 0000 à 1111). On dit que c’est un processeur 4 bits ou une architecture 4 bits.

Chaque instruction par contre est encodée sur 8 bits. Ce processeur pourrait donc avoir au maximum 256 instructions différentes. En réalité il a 46 instructions.

Le vrai CPU 4004 peut adresser un espace mémoire de programme avec une adresse 12 bits. Ceci lui permet d’adresser un maximum de \(2^{12}\) instructions différentes dans sa mémoire programme. Ici nous simplifions beaucoup et utilisons des adresses de 4 bits. Notre mémoire programme a une taille de 16 x 8 bits. Notre programme peut avoir un maximum de 16 instructions.

Beaucoup d’instructions sont composées d’une partie

  • instruction (4 bits), appelée opcode

  • données (4 bits), appelé data

Dans le circuit ci-dessous, ajoutez :

  • une broche 4 bits

  • une sortie 4 bits

  • un affichage 4 bits (en hexadécimal)

  • une étiquette opcode

  • Mettez les instructions ADD R3, SUB R15 et LDM 13 dans les 3 premiers octets de la mémoire programme.

13.5. Le jeu d’instructions

On appelle jeu d’instruction (instruction set) la totalité des instructions qu’un processeur peut exécuter. Ces instructions sont représentées par une abréviation à 3 lettres (mnémonique). Les premières 14 instructions sont composées d’une partie:

  • instruction (4 bits), appelée opcode, de 0000 à 1101

  • données (4 bits), appelé data

La partie `data’ peu représenter 3 types de données :

  • AAAA une adresse dans la mémoire programme

  • RRRR un registre dans la banque des registres

  • DDDD une donnée immédiate (un nombre de 0 à 15)

NOP 00000000  No Operation
JCN 0001AAAA  Jump Conditional
FIM 0010RRR0  DDDDDDDD  Fetch Immediate
FIN 0011RRR0  Fetch Indirect
JUN 0100AAAA  Jump Unconditional
JMS 0101AAAA  Jump to Subroutine
INC 0110RRRR  Increment
ISZ 0111RRRR  AAAAAAAA  Increment and Skip

ADD 1000RRRR  Add register
SUB 1001RRRR  Subtract register
LDR 1010RRRR  Load register
XCH 1011RRRR  Exchange register
BBL 1100DDDD  Branch Back and Load
LDM 1101DDDD  Load Immediate data

13.6. Décoder une instruction

Pour décoder les 14 instructions, nous pouvons utiliser un démultiplexeur. Pour compléter le circuit de décodage d’instruction :

  • Ajoutez un deuxième démultiplexeur

  • Ajoutez les 11 sorties manquantes

  • Ajoutez les étiquettes (FIN à LDM)

  • Remplissez la mémoire programme avec les 14 instructions (NOP à LDM)

  • Vérifiez que chaque instruction est décodée correctement

Par exemple à l’adresse 0100 (4) se trouve l’instruction 00010001 (JCN 1) et le décodeur active correctement la sortie JCN.

13.7. Bus 4 bits

Une ALU doit acheminer différents signaux sur une même ligne de transfert des données. On appelle un tel chemin un bus de données. Pour y connecter plusieurs sources, nous devons utiliser un multiplexeur.

  • Ajoutez une deuxième entrée 4 bits

  • Liez le multiplexeur et le démultiplexeur à travers une broche 4 bits

  • Ajoutez les 2 entrées de sélection

  • Ajoutez 4 affichages 4 bits pour montrer tous les signaux

13.8. Charger imméd. (LDM)

La commande LDM (Load immediate) va charger une valeur directe (0-15), contenue dans le code de l’instruction, dans l’accumulateur.

1101DDDD

La partie 1101 est l’opcode (LDM) et la partie DDDD représente les 4 bits des données à charger dans l’accumulateur.

  • Liez les bits b0-b3 avec l’accumulateur

  • Utilisez la porte ET pour charger cette valeur dans l’accumulateur seulement si le signal execute est activé ET l’instruction LDM est décodée

  • Placez un affichage à la sorte de l’accumulateur et à la sortie de l’ALU

  • Mettez une valeur dans les bits b0-b3 et exécutez l’instruction avec execute

13.9. Charger depuis reg (LDR)

L’instruction LDR (load from register) charge l’accumulateur avec le contenu d’un des 16 registres.

1010RRRR

La parte 1010 est l’opcode (LD) et la parte RRRR représente un des 16 registres

  • Ajoutez la RAM avec les 16 registres

  • Créez le circuit de décodage pour charger registre RRRR dans l’accumulateur

  • Placez un affichage à la sortie de l’accumulateur et à la sortie de l’ALU

  • Mettez une valeur dans R5

  • Mettez l’instruction LDR R5 et exécutez l’instruction avec execute

13.10. Choix entre LDR/LDM

Avec les deux opcode différents, le circuit de décodage du CPU choisit un registre ou une donnée immédiate comme valeur à charger dans l’accumulateur.

  • Ajoutez la RAM avec les 16 registres

  • Ajoutez un multiplexeur 8x4

  • Créez le circuit de décodage pour choisir entre un registre RRRR ou une donnée immédiate DDDD

  • Placez un affichage à la sortie de l’accumulateur et à la sortie de l’ALU

  • Mettez une valeur dans R5

  • Mettez l’instruction LDR R5 et exécutez l’instruction avec execute

  • Mettez l’instruction LDM 13 et exécutez l’instruction avec execute

13.11. Choix entre ADD/SUB

L’addition et la soustraction se distinguent dans l’opcode d’un seul bit.

  • 1000RRRR ADD additionner registre RRRR à l’accumulateur

  • 1001RRRR SUB soustraire registre RRRR de l’accumulateur

Créez le circuit pour décoder et exécuter ces deux instructions.

  • Ajoutez la RAM avec les 16 registres

  • Créez le circuit de décodage pour choisir entre ADD et SUB

  • Placez un affichage à la sortie de l’accumulateur et nommez le acc (y mettre 9)

  • Placez un affichage à la sortie de la RAM et nommez le reg

  • Placez un affichage à la sortie de l’ALU et nommez le result

  • Mettez la valeur 3 dans R5

  • Mettez l’instruction ADD R5 et vous devriez avoir result = 12 (9 + 3)

  • Mettez l’instruction SUB R5 et vous devriez avoir result = 6 (9 - 3)

13.12. Program counter (PC)

Le pointeur de programme, PC (program counter), pointe toujours à la prochaine instruction dans la mémoire de programme. Le contenu à l’adresse pointé par le PC est celui qui est chargé dans le registre d’instruction (IR) et exécuté au prochain pas.

  • Liez la sortie du PC avec l’entrée A du l’ALU pour incrémenter de 1 à chaque pas

  • Placez un affichage à la sortie du registre et nommez le PC

  • Liez le PC avec l’entrée adresse de la mémoire de programme

  • Liez l’entrée clock avec l’horloge de l’ALU et l’horloge des deux registres IR

  • Faites avancer le PC et chargez des instructions successives dans le registre IR

13.13. Le saut (jump)

Le saut est une instruction qui permet de changer l’avancement linéaire du compteur de programme. L’instruction de saut a la forme :

Jump Uncoditional JUN 0100AAAA

Pour l’exécuter, le CPU doit d’abord détecter l’opcode 0100. Ceci peut être fait avec une porte ET à 4 entrées et des inverseurs.

Ensuite la valeur actuelle du compteur de programme doit être remplacée par la nouvelle adresse de destination du saut AAAA. Pour ceci nous utilisons un multiplexeur 8 vers 4.

Utilisez des portes NON et ET pour décoder l’opcode 0100 et l’utiliser pour sélectionner entre incrémentation normale et destination de saut.

A l’adresse 14 se trouve l’instruction 01000011 (JUN 3). Si le décodeur fonctionne correctement le programme va faire une boucle entre les addresses 3 et 14.

13.14. La pile (stack)

La pile est un espace de sauvegarde temporaire. Elle est utilisée pour sauvegarder les adresses de retour lors d’un saut vers une sous-routine.

Ici nous créons une pile de 16 mots à 4 bits. D’habitude on commence la pile en bas de l’espace mémoire (adresse 15) et on empile les valeurs.

Le pointeur de pile (stack pointer) est un registre 4 bit, qui utilise une ALU pour être incrémenté ou décrémenté. Si l’entrée Op = 0 il incrémente. Si l’entrée Op = 1 il décrémente.

Ajoutez les circuits de contrôle.

  • Le signal clear efface la pile et met le pointeur de pile à 1111 (tout en bas)

  • Le signal push choisit la décrémentation (sp–) et envoie un coup d’horloge vers le registre du pointeur et la pile

  • Le signal pop choisit l’incrémentation (sp++) et envoie un coup d’horloge vers le registre du pointeur et la pile

Mettez dans la pile 3141592 (les 7 premiers chiffres du nombre pi) avec l’instruction push.
Ensuite, lisez ces chiffres dans l’ordre inverse avec l’instruction pop

13.15. Projet final

Ouvrez l’éditer logique dans une page entière du navigateur et choisissez un des projets suivants:

  1. Complétez l’architecture du CPU 4004 pour en faire un processeur fonctionnel.
    Voici le jeu d’instructions complet.

  2. Créez une calculatrice avec les touches 0 à 10, les opérations + et -, et un affichage à 7 segments avec 4 chiffres ou plus. Le point décimal est optionnel.

  3. Créez une horloge avec un affichage à 7 segments du style HH:MM:SS, avec des boutons up/down pour mettre le temps.

  4. Créez un minuteur avec un affichage à 7 segments du style MM:SS qui décompte, avec des boutons up/down pour mettre le temps, et des boutons start/stop/clear.

  5. Créez un chronomètre avec un affichage à 7 segments du style MM:SS.S qui affiche des dixièmes de seconde. Ajoutez des boutons start/stop/clear.

13.16. Nand Game

Dans le jeu Nand Game vous allez construire un ordinateur à partir de composants de base.

Le jeu se compose d’une série de niveaux. Dans chaque niveau, vous êtes chargé de construire un composant qui se comporte selon une spécification. Ce composant peut ensuite être utilisé comme bloc de construction dans le niveau suivant.

Le jeu ne nécessite aucune connaissance préalable de l’architecture informatique ou des logiciels, et ne nécessite aucune compétence en mathématiques au-delà de l’addition et de la soustraction. (Cela demande un peu de patience - certaines tâches peuvent prendre un certain temps à résoudre !)

Votre première tâche est de créer un composant nand (Non-Et).

Bonne chance!