CentraleSupélecDépartement informatique
Plateau de Moulon
3 rue Joliot-Curie
F-91192 Gif-sur-Yvette cedex
Bureau d'Etude 1 : Circuits combinatoires et séquentiels

Exercices

Ce bureau d'étude a pour objectif d'approfondir les principes de base des circuits combinatoires et séquentiels vus en cours. Il permettra d'arriver à la réalisation de la machine du cours.

Compétences visées:

  • Concevoir un circuit logique simple et observer son comportement dans un simulateur.
  • Distinguer les circuits combinatoires des circuits séquentiels.
  • Modéliser l'addition et la soustraction des entiers à l'aide d'opérations booléennes.
  • Distinguer chemin de données et séquenceur dans un microprocesseur.
  • Déterminer les séquences d'opérations élémentaires nécessaires à l'exécution des instructions d'un microprocesseur.

Optionnellement:

  • Décrire les problèmes de débordement arithmétique lors d'opérations sur des entiers représentés sur n bits en complément à 2.
  • Concevoir une unité arithmétique et logique.

Les circuits seront réalisés à l'aide du logiciel Logisim . Vous trouverez les versions de Logisim pour Mac OS X, Windows et Linux sur cette page.

Téléchargez le kit qui vous est fourni et décompressez-le dans votre répertoire personnel. Ce fichier contient :

  • Le fichier be-1-kit.circ. Ouvrez-le dans Logisim en choisissant File --> Open.
  • Le fichier ese1010.jar, contenant la définition de plusieurs composants dont vous vous servirez pendant ce bureau d'étude.

Introduction à Logisim

Logisim est un logiciel open-source qui permet de réaliser et simuler des circuits logiques.


Figure 1. Interface de Logisim

L'interface de Logisim consiste de trois parties principales (Figure 1) :

  1. La zone d'édition et simulation, permettant de réaliser et simuler un circuit.
  2. La bibliothèque des composants, contenant un ensemble de composants (portes logiques, bascules...) à utiliser pour la réalisation d'un circuit.
  3. Les attributs des composants, permettant de modifier l'aspect graphique et le comportement d'un composant sélectionné. En modifiant les attributs d'un composant on peut, entre autres, lui affecter une étiquette (label), changer la position de son étiquette, le nombre de ses entrées, et son orientation.

Logisim a deux modes de fonctionnement : le mode édition et le mode simulation.

Le mode édition, activé lorsqu'on sélectionne la flèche dans le menu en haut à gauche (affichée dans un carré vert en Figure 1), permet de dessiner un circuit.

  1. Pour ajouter un composant au circuit, il suffit de cliquer sur celui-ci dans la bibliothèque des composants et de cliquer sur la zone d'édition et simulation à l'endroit où on veut le placer.
  2. Chaque composant possède un ou plusieurs ports d'entrée/sortie permettant la connexion entre les composants.
    • Pour changer le nombre de ports, il suffit de modifier la valeur de l'attribut Number Of Inputs du composant.
    • Pour changer le nombre de bits sur les ports d'entrée et sortie, il suffit de modifier la valeur de l'attribut Data Bits du composant.
  3. Pour ajouter une connexion (un fil) entre deux composants, cliquez sur un des ports à connecter et déplacez la souris jusqu'au port de destination.
  4. Un circuit a au moins une broche d'entrée (input pin, en Anglais) permettant de définir les valeurs en entrée du circuit.
    • Vous trouverez la broche d'entrée () dans le menu en haut de Logisim.
  5. Un circuit a au moins une broche de sortie (output pin, en Anglais) permettant de vérifier les valeurs en sortie et donc le bon fonctionnement du circuit.
    • Vous trouverez la broche de sortie () dans le menu en haut de Logisim.
  6. Toute broche a une taille, indiquant le nombre de bits de la broche.
    • Pour changer la taille d'une broche, il suffit de modifier la valeur de l'attribut Data Bits de la broche.
  7. Pour changer l'orientation d'un composant, modifiez la valeur de l'attribut Facing de celui-ci.

Le mode simulation, qui est activé en sélectionnant la main dans le menu en haut à gauche (affichée dans un carré jaune en Figure 1), permet de verifier le bon fonctionnement d'un circuit, en affichant directement sur le circuit les valeurs des signaux (broches et fils).

  1. Pour définir des valeurs sur une broche d'entrée, il suffit de cliquer sur celle-ci. Sa valeur devrait alterner entre 0 et 1. Si la taille de la broche est supérieure à 1, il faut cliquer sur chaque bit pour en changer sa valeur.
  2. En fonction des valeurs sur les entrées, les différents fils et sorties changeront de valeur.
  3. Logisim utilise un ensemble de couleurs pour dénoter les valeurs sur les fils :
    • Gris : Le fil n'est relié à aucune entrée ou sortie.
    • Bleu : Le fil a une valeur inconnue.
    • Vert foncé : Le fil a valeur 0.
    • Vert clair : Le fil a valeur 1.
    • Noir : Le fil comporte plusieurs bits.
    • Rouge : Le fil comporte une erreur.
    • Orange : Les ports reliés au fils n'ont pas la bonne taille (par ex., un port a 8 bits et l'autre port a 2 bits).

1. Circuit combinatoires

Un circuit à entrées et sorties multiples est dit combinatoire si la valeur des sorties ne dépend que de la valeur des entrées. Cet exercice vous permettra d'étudier en profondeur l'additionneur, qui est un example classique de circuit combinatoire.

1.1 Additionneur

Nous allons réaliser un additionneur pour sommer deux entiers codés sur 4 bits en complément 2 en utilisant deux briques de base : un demi-additionneur et un additionneur complet qui traitent des entiers codés sur un seul bit.

1.1.1 Demi-additionneur

Le demi-additionneur est un circuit capable de faire la somme de deux entiers codés sur un bit et de produire une retenue. Les fonctions logiques qui lient les entrées {$A$} et {$B$} aux sorties {$Sum$} (somme) et {$Carry$} (retenue) sont déterminées à l'aide d'une table de vérité (Figure 2).


Figure 2. Demi-additionneur

{$Sum$} est obtenu par une fonction OU exclusif (XOR) des deux bits en entrées {$A$} et {$B$} et {$Carry$} est le résultat d'un ET logique des entrées. Formellement :

{$$Sum = A \oplus B\quad Carry = A \cdot B$$}

Exercice 1 :

  1. Créez un nouveau circuit nommé Half-adder en sélectionnant Project --> Add circuit dans Logisim. Cela ajoutera un nouveau circuit dans la bibliothèque des composants.
  2. Réalisez en mode édition le demi-additionneur montré en Figure 2. Il vous faudra :
    • Deux broches d'entrée {$A$} et {$B$}.
    • Deux broches de sortie {$Carry$} et {$Sum$}.
    • Une porte logique XOR. Vous la trouverez dans le répertoire Gates dans le menu à gauche.
    • Une porte logique AND. Vous la trouverez dans le répertoire Gates dans le menu à gauche.
  3. Testez le circuit en mode simulation pour vérifier que la table de vérité de la Figure 2 est bien respectée.


IMPORTANT : il faut positionner les broches d'entrée et de sortie dans la position indiquée en Figure 2. Cela simplifiera la réutilisation du demi-additionneur par la suite.

1.1.2 Additionneur complet (1 bit)

Un demi-additionneur peut additionner les bits de poids faible de deux entiers codés sur plusieurs bits, mais il ne peut pas additionner les bits des positions intermédiaires, car il ne possède aucune entrée représentant la retenue qui provient du bit de droite précédent. Pour ça il nous faut réaliser un additionneur complet (Figure 3), qui permet de calculer la somme de deux entiers en tenant compte de la retenue en entrée.

Nous commençons par un additionneur à 1 bit, qui fait la somme entre deux entiers codés sur 1 bit.


Figure 3. Additionneur complet

Exercice 2 :

  1. Créez un nouveau circuit en Logisim nommé Full-adder et réalisez l'additionneur complet en utilisant le demi-additionneur que vous avez créé auparavant.
    • Pour réutiliser le demi-additionneur, cliquez sur celui-ci et cliquez sur la zone d'édition et simulation à l'endroit où vous voulez le placer.
  2. Testez le circuit en mode simulation pour en vérifier le bon fonctionnement.


IMPORTANT :

  • Positionnez les broches d'entrée et de sortie comme la Figure 3 l'indique.

1.1.3 Additionneur complet (4 bit)

La Figure 4 montre un additionneur complet à 4 bit, obtenu en répliquant quatre fois le full-adder que vous venez de réaliser. Chaque full-adder fait la somme de deux bits :

  • le premier en haut somme les deux bits de poids faible {$A0$} et {$B0$} des deux opérandes et produit le bit de poids faible {$S0$} de la somme.
  • le dernier en bas somme les deux bits de poids fort {$A3$} et {$B3$} des deux opérandes et produit le bit de poids fort {$S3$} de la somme.

Remarquez que la retenue en sortie d'un full-adder est utilisée comme retenue en entrée du full-adder suivant. La retenue en entrée du premier full-adder (celui qui somme les bits de poids faible) a toujours valeur 0.

Pour la réalisation de cet additionneur, il faut prendre en compte les éléments suivants :

  • Il vous faudra utiliser deux broches d'entrée à 4 bits et une broche de sortie à 4 bits.
    • Rappel : pour changer le nombre de bits d'une broche (sa taille), modifiez la valeur de l'attribut Data Bits de la broche.
  • Pour relier chaque bit d'entrée aux quatre additionneurs à 1 bit, utilisez le composant Splitter, que vous trouverez dans le répertoire Wiring de la bibliothèque des composants.
    • Mettez la valeur 4 aux attributs Fan out et Bit Width In du Splitter.
    • En sortie du Splitter, vous aurez 4 fils, un pour chaque bit d'entrée. Le bit de poids faible est indexé à 0 en sortie du splitter.
  • Vous devez également utiliser un splitter pour regrouper les sorties des quatre additionneurs dans un seul bus à 4 bits qui sera relié à la broche de sortie.

Figure 4. Additionneur complet à 4 bits.

Exercice 3 :

  1. Créez un nouveau circuit nommé 4bit-full-adder et réalisez un additionneur complet à 4 bit.
  2. Testez le circuit en mode simulation pour en vérifier le bon fonctionnement.
    • 0011 (3) + 0010 (2) devrait produire 0101 (5).
    • 1101 (-3) + 0001 (1) devrait produire 1110 (-2).
  1. Pour imposer la valeur 0 sur le port {$C_{in}$} du premier additionneur, utilisez une constante
    • Vous trouverez le composant Constant dans le répertoire Wiring de la bibliothèque des composants.
    • Spécifiez 0x00 comme valeur de la constante.

2. Circuit séquentiels

Dans un circuit séquentiel les valeurs en sortie ne dépendent pas uniquement des valeurs actuelles en entrée, mais aussi des valeurs que les entrées ont eu précédemment. Cet exercice vous permettra d'approfondir vos connaissances des circuits séquentiels ainsi que de comprendre la logique sous-jacente.

2.1 Réalisation d'un circuit bi-stable

On veut réaliser en Logisim un circuit pour contrôler une lampe {$L$} à travers deux boutons poussoirs {$ON$} et {$OFF$} :

  • lorsqu'on appuie sur {$ON$} la lampe s'allume et reste allumée même quand le bouton {$ON$} est relâché.
  • lorsqu'on appuie sur le bouton {$OFF$}, la lampe {$L$} s'éteint et reste éteinte même quand le bouton {$OFF$} est relâché.
  • on suppose qu'on ne peut pas appuyer sur {$ON$} et {$OFF$} en même temps.

Un tel circuit est qualifié de bi-stable car il possède deux états stables, et passe de l'un à l'autre selon l'entrée qui est activée.

Exercice 4 :

  1. Créez un nouveau circuit nommé Light dans Logisim et réalisez le circuit à partir de l'équation logique.
    • L'idée est d'arriver à dériver l'équation d'un circuit séquentiel que vous avez vu en cours. Lequel?
  2. Testez le circuit en mode simulation pour en vérifier le bon fonctionnement.

3. Conception d'un microprocesseur de type ARM 3. Microprocesseur

L'objectif de cet exercice est de déterminer comment les signaux du chemin de données doivent être pilotés pour séquencer l'exécution des instructions. Cela vous permettra d'établir les équations du séquenceur de la machine de cours, lors de l'étude de laboratoire n°1.

Dans un premier temps, vous allez utiliser le chemin de données du microprocesseur sans séquenceur. Vous séquencerez manuellement l'exécution des instructions.

Téléchargez le kit KitManu.zip, ouvrez le fichier miniARMManu.circ dans Logisim, et chargez le programme manu.mem dans la mémoire.

Ce programme exécute les instructions suivantes :

      add r0, r0, #1  % r0 <- r0 + 1
      add r1, r1, #2  % r1 <- r1 + 2
      add r2, r0, r1  % r2 <- r0 + r1
      str r2, var     % Mem[var] <- r2
      ldr r3, var     % r3 <- Mem[var]

@var  rmw 1           % case mémoire pour stocker une variable

Si les registres sont initialement à 0, ce programme charge donc la valeur 1 dans r0, la valeur 2 dans r1, puis la somme de r0 et r1 dans r2. Il écrit ensuite la valeur de r2 dans le mot mémoire d'adresse var (qui est égale à 9), puis charge dans r3 le contenu de la mémoire à cette adresse. Après l'exécution de ces instructions, r2 et r3 doivent valoir 3, et le mot mémoire d'adresse 9 doit également contenir la valeur 3.

Le circuit miniARMManu.circ contient le chemin de données du processeur, sans le séquenceur. Les signaux de contrôle du chemin de données peuvent être positionnés à l'aide de bouton poussoirs et d'entrées.

Exercice 5 :

  1. Pilotez manuellement le chemin de données pour exécuter les instructions de ce petit programme
  2. Notez dans un tableau (feuille de calcul) les séquences de signaux nécessaires pour exécuter ces instructions.

Conservez ce tableau, il vous sera utile pour déterminer les équations du séquenceur lors de la première étude de laboratoire.

  • Pour exécuter une instruction, il faut tout d'abord aller lire son code en mémoire.
  • L'adresse à laquelle se trouve le code de la prochaine instruction à exécuter se trouve dans le compteur ordinal (registre PC, pour Program Counter).
  • Pour que la mémoire sélectionne le mot situé à une adresse, il faut mettre cette adresse dans le registre RADM (registre adresse mémoire).
  • Pour que les registres du banc de registres soient correctement sélectionnés, le code de l'instruction en cours d'exécution doit se trouver dans le RI (registre d'instruction).
  • Les signaux MemB et PCA vous permettent de choisir les données envoyées sur les entrées A et B de l'UAL.
  • Pour incrémenter le compteur ordinal, vous pouvez utiliser le code UAL 1100 (A+1).

4. Pour aller plus loin

Cette section est destinée à ceux d'entre vous qui auront la curiosité de compléter certains des exercices commencés dans ce bureau d'étude.

4.1 Réalisation d'une simple unité arithmétique logique

Nous allons réaliser une petite unité arithmétique logique (UAL) 4 bits, permettant de faire les opérations de somme, soustraction, ET et OU logique.

4.1.1 Détection du dépassement de capacité

Le dépassement de capacité (overflow, en anglais) est une condition qui se produit quand la somme de deux entiers de même signe donne un résultat de signe opposé. Cela arrive quand le résultat est un entier qui ne peut pas être représenté sur le même nombre de bits que les opérandes. Dans notre cas, avec 4 bits nous pouvons représenter les valeurs entre -8 et +7. Si on somme 5 (0101) et 3 (0011), le résultat sur 4 bits sera 1000 (-8).

En général, si on représente les entiers sur {$k$} bits, il y a dépassement de capacité quand le résultat est supérieur à {$2^{k-1} -1$} ou inférieur à {$-2^{k-1}$}.

La formule pour la détection de dépassement de capacité est la suivante :

{$$ V = c_{k-1}\oplus c_{k-2} $$}

où {$ c_{k-2} $} et {$ c_{k-1} $} sont respectivement la retenue en entrée et en sortie de l'additionneur qui somme les bits de poids fort (le dernier en bas en Figure 4).
Par définition de la fonction logique OU exclusif, il y a dépassement de capacité si {$ c_{k-2} \neq c_{k-1} $}. Pourquoi? Il y a deux cas :

  1. {$ c_{k-1} = 1 $} et {$ c_{k-2} = 0 $}. Cela se produit quand les bits de poids fort de {$A$} et {$B$} ont valeur 1 ({$A$} et {$B$} sont négatifs). Par conséquent, le bit de poids fort du résultat vaut 0 (un résultat positif).
  2. {$ c_{k-1} = 0 $} et {$ c_{k-2} = 1 $}. Cela se produit quand les bits de poids fort de {$A$} et {$B$} ont valeur 0 ({$A$} et {$B$} sont positifs). Par conséquent, le bit de poids fort du résultat vaut 1 (un résultat négatif).

Exercice 6 :

  1. Modifiez le circuit 4bit-full-adder en rajoutant le bit {$V$} en sortie.
  2. Testez le circuit en mode simulation pour en vérifier le bon fonctionnement.
    • 0101 (5) + 0011 (3) devrait produire comme résultat 1000 (-8) et mettre le bit {$V$} à 1

4.1.2 Résultat négatif et nul

Dans plusieurs situations, il est important de pouvoir tester rapidement si le résultat d'une addition est un numéro négatif ou nul. C'est pourquoi nous allons doter notre additionneur de deux bits en sortie supplémentaires :

  • un bit {$N$} qui vaut 1 si le résultat est négatif.
  • un bit {$Z$} qui vaut 1 si le résultat est nul.

Exercice 7 :

  1. Modifiez le circuit 4bit-full-adder en rajoutant les bits {$N$} et {$Z$} en sortie.
  2. Testez le circuit en mode simulation pour en vérifier le bon fonctionnement.
    • 1011 (-5) + 0101 (5) devrait produire comme résultat 0000 (0) et mettre le bit {$Z$} à 1.
    • 1011 (-5) + 0010 (2) devrait produire comme résultat 1101 (-3) et mettre le bit {$N$} à 1.

4.1.3 Soustracteur

Pour la réalisation d'un soustracteur, nous pouvons adopter la même stratégie que nous avons suivie pour assembler un additionneur (création d'une table de vérité, dérivation des formules logiques...). Cependant, une solution beaucoup plus simple consiste à réutiliser un additionneur et exploiter le fait que {$A - B = A + (-B)$}.
La seule difficulté consiste à inverser le signe de {$B$}. {$B$} étant codé en complément 2, il suffit d'inverser tous les bits de {$B$} et ajouter 1 au résultat.


Exercice 8 :

  1. Créez un nouveau circuit nommé 4bit-subtractor.
  2. Réalisez un soustracteur à 4 bit en réutilisant le 4bit-full-adder.
    • Le soustracteur devra prévoir en sortie les bits {$V$}, {$Z$} et {$N$}.
  3. Testez le circuit en mode simulation pour en vérifier le bon fonctionnement.
    • 0101 (5) - 0010 (2) devrait produire 0011 (3).
    • 0010 (2) - 0111 (7) devrait produire 1011 (-5) et mettre à 1 le signal {$N$}.
    • 0011 (3) - 1000 (-8) devrait produire 1011 (-5) et mettre à l le signal {$V$}.

Pour inverser les bits de {$B$} vous pouvez utiliser une porte logique NOT à 4 bits.

4.1.4 Unité arithmétique et logique 8 bits

Nous allons réaliser une simple unité arithmétique logique (UAL, ou bien Arithmetic Logic Unit, ALU, en anglais), capable d'effectuer quatre opérations : addition, soustraction, ET logique et OU logique.


Figure 5. Schéma de l'UAL

Comme la Figure 5 le montre, notre UAL possède trois entrées et cinq sorties. Les entrées sont :

  • les deux opérandes {$A$} et {$B$} représentant deux entiers codés sur 4 bits en complément 2.
  • les bits de contrôle {$F$} qui permettent de spécifier l'opération à appliquer sur les entrées. Notre UAL réalisant 4 opérations, {$F$} nécessitera de 2 bits : addition ({$F=00$}), soustraction ({$F=01$}), ET logique ({$F=10$}), OU logique ({$F=11$})

Les sorties sont :

  • Le résultat de l'opération sélectionnée {$R$} représentant un entier codé sur 4 bits en complement 2.
  • La valeur de la retenue {$C$} ("carry bit") d'une opération de somme ou soustraction, codé sur 1 bit.
  • Le bit de dépassement {$V$} ("overflow bit"), codé sur 1 bit, indiquant que le résultat a engendré un dépassement de capacité.
  • {$N$}, codé sur 1 bit, indiquant que le résultat est négatif (strictement inférieur à zero).
  • {$Z$}, codé sur 1 bit, indiquant que le résultat est nul.

Exercice 9 :

  1. Créez un nouveau circuit nommé 8bit-alu et réalisez la UAL montrée en Figure 5, en réutilisant l'additionneur et le soustracteur que vous venez de créer.
  2. Testez votre UAL en mode simulation.
  1. Les opérations ET/OU logique peuvent être réalisées en utilisant les portes ET et OU de Logisim.
    • Il suffit seulement de changer la valeur de l'attribut Data Bits à 8.
  2. La valeur en sortie de l'UAL devra être le résultat de l'opération sélectionnée à travers les bits de contrôle {$F$}.
    • Utilisez un multiplexeur que vous trouverez dans le repertoire Plexers de la bibliothèque des composants.
  3. Il faut également prévoir un multiplexeur pour les sorties {$N$}, {$Z$}, {$V$} et {$C$} de l'UAL, car la valeur sur ces sorties dépend de l'opération sélectionnée.
    • Elles seront toujours à 0, si l'opération sélectionnée est un ET/OU logique;
    • Elles aurons les mêmes valeurs des sorties correspondantes dans un additionneur ou soustracteur si l'opération sélectionnée est une addition ou une soustraction.

4.2 Réalisation d'une lampe clignotante

On souhaite modifier le circuit réalisé à l'exercice 6 (la lampe) afin d'ajouter la fonction de clignotement à la lampe. Le nouveau circuit doit prévoir :

  • Un seul bouton {$ON/OFF$} pour allumer/éteindre la lampe.
  • Un bouton {$C$} pour activer la fonction de clignotement.
  • Une horloge qui contrôle le clignotement.
    • Vous trouverez l'horloge (clock) dans le répertoire Wiring de la bibliothèque des composants de Logisim.

Exercice 10 :

  1. Créez un nouveau circuit nommé blinking-light et réalisez le nouveau circuit en modifiant le circuit Light
  2. Testez le circuit en mode simulation pour en vérifier le bon fonctionnement.
  1. Inspirez-vous de la bascule D pour la réalisation du circuit.
  2. Pour activer l'horloge en Logisim sélectionnez Simulate --> Ticks Enabled.
  3. Pour changer la fréquence de l'horloge sélectionnez Simulate --> Tick Frequency

Format des instructions

 codeimmrxryrz
 4 bits1 bit3 bits3 bits3 bits2 bits
ldr rx,[ry, offset]00000rxry  
 offset
ldr rx,offset00001rx   
 offset
str rz,[ry, offset]00010 ryrz 
 offset
str rz,offset00011  rz 
 offset
mov rx,ry00100rxry  
mov rx,#val00101rx   
 val
add rx,ry,rz00110rxryrz 
add rx,ry,#val00111rxry  
 val
sub rx,ry,rz01000rxryrz 
sub rx,ry,#val01001rxry  
 val
cmp ry,rz01010 ryrz 
cmp ry,#val01011 ry  
 val
beq rz01100 rz 
 address
beq address01101 
 address
blt rz01110 rz 
 address
blt address01111 
 address
b rz10000 rz 
 address
b address10001 
 address
bl rx, rz10010rx rz 
 address
bl rx, address10011rx 
 address
ldr rx,[ry, offset]charge le registre rx avec le contenu de la mémoire à l'adresse ry+offset (adressage indexé)
str rz,[ry, offset]écrit le contenu du registre rz en mémoire à l'adresse ry+offset (adressage indexé)
mov rx,rycharge la valeur du registre ry dans le registre rx
mov rx,#valcharge la valeur immédiate val dans le registre rx
add rx,ry,rzcharge le registre rx avec la somme des registres ry et rz
add rx,ry,#valcharge le registre rx avec la somme du registre ry et de val
sub rx,ry,rzcharge le registre rx avec la différence des registres ry et rz
sub rx,ry,#valcharge le registre rx avec la différence du registre ry et de val
cmp ry,rzchange les indicateurs N et Z du registre d'état en fonction de la différence ry-rz
cmp ry,#valchange les indicateurs N et Z du registre d'état en fonction de la différence ry-val
beq rzsaute à l'adresse contenue dans rz si le bit Z du registre d'état vaut 1
beq addresssaute à l'adresse address si le bit Z du registre d'état vaut 1
blt rzsaute à l'adresse contenue dans rz si le bit N du registre d'état vaut 1
blt addresssaute à l'adresse address si le bit N du registre d'état vaut 1
b rzsaute à l'adresse contenue dans rz
b addresssaute à l'adresse address
bl rx, rzcopie le PC dans rx et saute à l'adresse contenue dans rz (Branch and Link)
bl rx, addresscopie le PC dans rx et saute à l'adresse address (Branch and Link)
Instructions émulées
push rzempile la valeur du registre rz en utilisant le registre r6 (sp) comme pointeur de pile
pop rxdépile une valeur et la range dans le registre rx en utilisant le registre r6 (sp) comme pointeur de pile

Matériel

Le processeur est de 16 bits, traite des entiers codés sur 16 bits en complément 2 et dispose de :

  • Huit registres banalisés (r0, ..., r7).
    • Le registre r7, identifié par le nom symbolique lr (Link Register), est utilisé pour stocker l'adresse de retour lors d'un appel de fonction
    • Le registre r6, identifié par le nom symbolique sp (Stack Pointer), est utilisé comme pointeur de pile.
  • Un compteur ordinal CO dédié.
  • Un registre instruction RI.
  • Un registre d'adresse mémoire RADM.
  • Un registre d'état SR, contenant le résultat de la comparaison de deux entiers {$a$} et {$b$}:
    • Let bit N du registre d'état sera mis à 1, lorsque {$a - b < 0$}.
    • Let bit Z du registre d'état sera mis à 1, lorsque {$a - b = 0$}.
  • Une unité arithmétique logique (UAL) à 16 bits.
  • Un séquenceur, qui pilote le chemin de données du processeur.

Instructions

La table ci-dessous décrit chaque instruction, qui est codée sur 16 bits décomposés comme suit :

  • Code opération, 4 bits (les 4 bits de poids fort).
  • imm, 1 bit, indiquant si le mode d'adressage immédiat est utilisé (1) ou pas (0).
  • rx, 3 bits, indiquant le registre résultat rx.
  • ry, 3 bits, indiquant le registre du premier opérande ry.
  • rz, 3 bits, indiquant le registre du second opérande rz.
  • Les deux bits de poids faible sont banalisés (leurs valeurs sont indifférentes).
InstructionFormat de l'instruction (16 bits)Description
Codeimmrxryrz 
4 bits1 bit3bits3 bits3 bits2 bits
ldr rx, ry00000rxry  rx ← Mem[ry]
str rz, ry00010 ryrz Mem[ry] ← rz
mov rx, ry00100rxry  rx ← ry
mov rx, #value00101rx   rx ← value
value
add rx, ry, rz00110rxryrz rx ← ry + rz
add rx, ry, #value00111rxry  rx ← ry + value
value
sub rx, ry, rz01000rxryrz rx ← ry - rz
sub rx, ry, #value01001rxry  rx ← ry - value
value
cmp ry, rz01010 ryrz N ← (ry < rz); Z ← (ry = rz)
cmp ry, #value01011 ry  N ← (ry < value); Z ← (ry = value)
value
beq rz01100  rz CO ← rz if Z = 1
beq address01101    CO ← address if Z = 1
address
blt rz01110  rz CO ← rz if N = 1
blt address01111    CO ← address if N = 1
address
b rz10000  rz CO ← rz
b address10001    CO ← address
address

Ce jeu d'instructions utilise les modes d'adressage par registre, direct (dans le cas des instructions de branchement) et immédiat. Pour simplifier la conception, cette version place systématiquement les valeurs immédiates (comme {$value$} ou {$address$}) dans un mot qui suit l'instruction. On conserve toutefois l'architecture load/store, seules les instructions ldr, et str, accèdent à la mémoire (en mode d'adressage par registre).

Les instructions arithmétiques sont à 3 adresses : rx, est le registre résultat, ry, est le registre contenant le premier opérande et rz est le registre contenant le second opérande.

Il vous est fourni un assembleur qui fournit deux pseudo-instructions :

  • push, ajoute une valeur sur la pile ;
  • pop, enleve une valeur de la pile.

push et pop sont émulés respectivement par :

add sp,sp,#1; str rz, sp, 0

ldr rx, sp, 0; sub sp,sp,#1

Appel de fonction

Lors de l'appel d'une fonction, les six premiers paramètres sont passés en utilisant les registres r0, ..., r5. Les paramètres au-delà du sixième sont passés en utilisant la pile. Le registre r0 est utilisé pour stocker la valeur de retour, si présente, de la fonction. Tous les paramètres, à l'exception de celui contenu dans r0, sont passés par valeur. Cela signifie que si la fonction nécessite d'utiliser un des registres r1, ..., r5 elle doit impérativement sauvegarder sa valeur courante sur la pile avant de la modifier; une fois que la fonction a terminé d'utiliser le registre, il faut récupérer de la pile son ancienne valeur.

3.2 Travail à faire

Le circuit data-path qui vous est fourni contient une ébauche du chemin de données à réaliser. Les composants présents dans le circuits sont (de gauche à droite) :

  • le registre RADM. Le composant Logisim utilisé est D Flip-Flop dans le répertoire Memory .
  • la mémoire RAM. Le composant Logisim utilisé est RAM dans le répertoire Memory .
  • le registre RI. Le composant Logisim utilisé est D Flip-Flop dans le répertoire Memory .
  • le compteur ordinal CO. Le composant Logisim utilisé est Inc Register dans le répertoire ESE1010 .
  • les registres r0, ..., r7, contenus dans un composant R. Le composant Logisim utilisé est Register File dans le répertoire ESE1010 .
  • l'unité arithmétique logique UAL. Le composant Logisim utilisé est ALU dans le répertoire ESE1010 .
  • le registre d'état SR, qui contient la valeurs des bits N et Z de l'UAL lors de la dernière comparaison. Le composant Logisim utilisé est D Flip-Flop dans le répertoire Memory .
  • le séquenceur (control unit en anglais), avec 7 entrées et 14 sorties.
  • Les entrées sont :
    • N et Z, reliées à la sortie du SR, indiquant si le résultat produit par le UAL est négatif ou nul respectivement.
    • RI15, RI14, RI13, RI12, IMM correspondent aux 5 bits de poids fort de la valeur actuelle du RI. Il s'agit du code de l'instruction à executer.
  • Les sorties sont :
    • U0, U1, U2 et U3 qui sont reliées aux bits de contrôle de l'UAL à travers un tunnel (CodeUAL) afin de réduire le nombre de connexions sur le circuit. Vous trouverez le tunnel dans le répertoire Wiring de la bibliothèque des composants. Les tunnels qui portent le même nom ont la même valeur.
    • HRADM, le signal d'horloge du RADM.
    • HRI, le signal d'horloge du RI.
    • HCO, le signal d'horloge du CO.
    • HR, le signal d'horloge de l'ensemble des registres dans R.
    • HSR, le signal d'horloge du registre SR
    • RW, le signal read/write de la RAM. RW = 1 correspond à une opération d'écriture, RW = 0 une opération de lecture.
    • HEM, le signal d'horloge de la RAM.
    • CCO, le bit d'incrément du CO.