Architecture de Von Neumann

I/ Addition

1) Ou exclusif

Voici la table de vérité de (a ∧ ¬b) ∨ (¬a ∧ b) (on rappelle que 0 représente le faux et 1 représente le vrai)) :

ab¬a¬ba ∧ ¬b(¬a ∧ b)(a ∧ ¬b) ∨ (¬a ∧ b)
0011000
0110011
1001101
1100000

L'opération ainsi réalisée est appelée ou exclusif et notée xor ou  : elle ne renvoie la valeur 1 que lorsque a≠b. Elle est à la base de l'addition binaire.

2) Additionneur un bit

Voici une table d'addition de deux nombres a et b à un bit chacun :

ab21
0000
0101
1001
1110

On constate que le chiffre des unités se calcule par un ou exclusif entre a et b, et que le chiffre des deuxaines (ou retenue engendrée) se calcule par un et entre a et b. On a là, la base d'un additionneur de deux nombres binaires avec génération d'une retenue.

Pour additionner a et b avec une éventuelle retenue c, si on note r la retenue engendrée par a+b (chiffre des deuxaines) et s le chiffre des unités de a+b (s==a⊕b) alors on entre s et c dans une autre porte ou exclusif (a⊕b⊕c==(a⊕b)⊕c=s⊕c). Et pour savoir si une retenue est engendrée, on peut faire (a∧b)∨(b∧c)∨(a∧c) comme le montre la table de vérité de cette expression :

abca∧bb∧ca∧c(a∧b)∨(b∧c)∨(a∧c)
0000000
0010000
0100000
0110101
1000000
1010011
1101001
1111111

Théorème (Shannon 1937) : on peut construire un additionneur binaire un bit avec retenue, uniquement en câblant des portes non, et et ou.

3) Additionneur 8 bits

Pour obtenir un additionneur 8 bits (additionneur d'octets), il suffit de brancher en cascade des additionneurs 1 bit avec retenue. Par exemple si deux registres A et B d'un octet chacun contiennent respectivement les nombres 86 (01010110 en binaire) et 61 (00111101) alors avant l'addition, on a :

A01010110
B00111101
R
S

Ensuite,

  1. l'additionneur des deux chiffres des unités calcule 0+1=1 sans retenue
    A01010110
    B00111101
    R0
    S1
  2. l'additionneur des trois chiffres des deuxaines calcule 1+0+0=1 sans retenue
    A01010110
    B00111101
    R00
    S11
  3. l'additionneur des trois chiffres des quatraines calcule 1+1+0=0 avec retenue
    A01010110
    B00111101
    R100
    S011
  4. l'additionneur des trois chiffres des huitaines calcule 0+1+1=0 avec retenue
    A01010110
    B00111101
    R1100
    S0011
  5. l'additionneur des trois chiffres des seizaines calcule 1+1+1=1 avec retenue
    A01010110
    B00111101
    R11100
    S10011
  6. l'additionneur des trois chiffres des trente-deuxaines calcule 0+1+1=0 avec retenue
    A01010110
    B00111101
    R111100
    S010011
  7. l'additionneur des trois chiffres des soixante-quatraines calcule 1+0+1=0 avec retenue
    A01010110
    B00111101
    R1111100
    S0010011
  8. l'additionneur des trois chiffres des cent-vingt-huitaines calcule 0+0+1=1 sans retenue
    A01010110
    B00111101
    R1111100
    S10010011

La somme de 86 et 61 est, en binaire, 10010011 soit 147.

En réalité, les additionneurs 1 bit fonctionnent tous en même temps, et les délais successifs aboutissent (assez rapidement) à la stabilisation des retenues.

  1. Au début il n'y a pas de retenue :
    A01010110
    B00111101
    R00010100
    S01101011
  2. Avec les retenues l'addition se refait :
    A01010110
    B00111101
    R00101000
    S01111111
  3. Puis une nouvelle stabilisation :
    A01010110
    B00111101
    R00111000
    S01000011
  4. Encore une stabilisation :
    A01010110
    B00111101
    R01111000
    S01010011
  5. Une autre :
    A01010110
    B00111101
    R11111000
    S00010011
  6. Et une dernière :
    A01010110
    B00111101
    R11111000
    S10010011

4) En assembleur

Un additionneur de ce genre est présent (entre autres) dans l'ALU du microprocesseur Z80 (en bas à droite) :

Supposons qu'à l'adresse 42 de la mémoire, soit stocké le nombre 128, et que le registre PC contienne justement le nombre 42 :

PC00101010
A01010110
B00111101

Alors, au cours d'un cycle de calcul du CPU,

  1. le contenu du registre PC est placé sur le bus d'adresse, déclenchant ainsi un cycle de lecture,
  2. L'octet stocké à l'adresse 42 est lu : il s'agit de 128 (80 en hexadécimal ou 10000000 en binaire)
  3. Cet octet est transféré dans le registre d'instructions I qui contient alors 10000000
  4. Le contenu de PC est incrémenté (c'est-à-dire que 1 lui est additionné) :
    PC00101011
    A01010110
    B00111101
  5. Le mot 10000000 qui est dans I est décodé par la logique de décodage : le 10000 veut dire additionner à A et le 000 qui suit signifie que c'est B qui doit être additionné à A.
  6. Donc c'est le circuit additionneur de l'ALU qui est activé, on voit que A est déjà branché à l'une des entrées ACU de l'additionneur, et B est, via un multiplexeur MUX, envoyé sur le bus interne et de là, à l'autre entrée TEMP.
  7. L'additionneur effectue l'addition et renvoie le résultat 147 (soit 10010011) dans le registre A :
    PC00101011
    A10010011
    B00111101
  8. Le registre d'état est mis à jour selon le résultat du calcul. En particulier, son bit C (carry veut dire retenue) aurait été positionné s'il y avait eu une retenue de poids 256 à la fin de l'addition.

En assembleur Z80, l'octet 10000000 est traduit par ADD A, B.

II/ Décalage

1) Doublement

En binaire, pour doubler un registre, il suffit de décaler vers la gauche tous ses chiffres, en insérant un 0 à droite du registre. Par exemple si un registre contient le nombre 13

B00001101

après décalage vers la gauche, il contient

B00011010

soit 26 qui est le double de 13. Le bit le plus à gauche, qui est sorti du registre lors du décalage, est stocké comme flag de dépassement : il était nul donc il n'y a pas eu de dépassement de capacité.

Par exemple si, à l'adresse 43 de la mémoire, est stocké l'octet 00100000 soit SLA B (00100 codant SLA et comme déjà vu, 000 désignant le registre B), le prochain cycle d'exécution passe de

PC00101011
A10010011
B00111101

à

PC00101100
A10010011
B01111010

Il est bien plus rapide de faire un doublement par décalage, que d'additionner un registre avec lui-même.

2) Division par 2

Pour diviser un registre par 2, on effectue un décalage vers la droite. Le bit des unités est perdu, mais dans le Z80 il est stocké comme retenue.

Par exemple si à l'adresse 44 est stocké l'octet codant SRA A (soit 00101111 qui se décompose en 00101 pour SRA et 111 pour le registre A, un cycle machine passe de

PC00101100
A10010011
B01111010

à

PC00101101
A01001001
B01111010

avec un 1 dans le bit C de retenue. 73 est bien la moitié de 147 mais avec un reste de 1.

En résumé, le contenu de mémoire suivant

adressedonnée
42128
4332
4447

signifie, pour le Z80,

ADD A, B
SLA B
SRA A

III/ Multiplication

Il est possible de réaliser des circuits logiques combinatoires pour faire un multiplicateur, mais sur le Z80 on programme la multiplication en assembleur. Par exemple si on veut multiplier 13 par 11 en binaire :

    1101
×   1011
--------
    1101
   1101
 1101
--------
10001111

on voit qu'on obtient les termes à additionner (avec un additionneur binaire) par décalage du multiplicande, et on n'additionne les termes que si le bit correspondant du multiplicateur est égal à 1. Or celui-ci peut s'obtenir par SRA en regardant le bit C de retenue.

1) Programme assembleur

On suppose qu'au début

A00000000
B00001101
C00001011
D00000100

Alors on utilise le programme en assembleur suivant :

label retour
SRA C
JP NC, suite
ADD A, B
label suite
SLA B
DEC D
JP NZ, retour
HALT

2) Déroulé

À la fin du programme, le registre A contient 10001111 soit le nombre 143 qui est bien le produit de 13 par 11.

3) Histoire

Cet algorithme a été proposé par Von Neumann en 1946, pour les plans du premier ordinateur américain, mais il est équivalent à un algorithme connu des égyptiens.