3. Architecture de von Neumann

Du point de vue historique, le rapport de von Neumann sorti en 1945 ( "First Draft of a Report on the EDVAC" ) constitue un moment-clé, puisqu'il propose une architecture pour une machine informatique autonome ( c'est à dire avec programme enregistré en mémoire; auparavant la programmation se faisait en connectant et déconnectant des dizaines de cables ! ), architecture qui est toujours celle utilisée dans les machines actuelles.

Programmation cablage
La programmation sans clavier...
( source : Aconit - Grenoble )

Une machine dans l'architecture de von Neumann

On dispose donc de circuits électroniques capables de faire des calculs arithmétiques et logiques, capables de mémoriser des données, etc...

Les ordinateurs construits avec l’architecture de von Neumann sont constitués de quatre composants utilisant ces circuits :

  1. l’unité arithmétique et logique (UAL) ou unité de traitement, qui effectue les opérations de base : addition, opérations logiques, etc...
  2. l’unité de commande, qui est chargée du "timing" des opérations qui doivent s'exécuter
  3. la mémoire
  4. les dispositifs d’entrées-sorties, qui permettent de communiquer avec le monde extérieur

La particularité de cette architecture est que les programmes et les données qu'ils manipulent partagent la même mémoire; dans certaines architectures ( comme celle dite de Harvard ), programmes et données disposent au contraire de mémoires séparées.

Tous ces composants communiquent les uns avec les autres par l'intermédiaire d'un ensemble de connexions appelées bus ( en jaune sur la figure ).

La mémoire

On peut se représenter la mémoire comme une série de cellules, chaque cellule étant capable de stocker 1 octet.
Chacune de ces cellules possède une adresse, exprimée sous forme de valeur numérique.
Les opérations sur la mémoire sont de 2 types : lecture / écriture. Une opération de lecture consiste à aller lire l’octet situé à l’adresse mémoire XXXXX et une opération d’écriture consiste à écrire un octet donné à l’adresse mémoire YYYYY.

Interactions CPU - RAM

Toute donnée informatique ne peut y être représentée que par un nombre ( binaire, de surcroît...), puisque c'est la seule information qu'une machine peut traiter.

Cependant, du fait de l'architecture de von Neumann, qui stocke aussi bien programmes que données dans la même mémoire, ces nombres peuvent représenter diverses informations :

Différents types de mémoire existent dans une machine : selon les cas, le processeur peut avoir besoin d'une mémoire très rapide pour exécuter les opérations les plus courantes, ou alors de mémoires pas forcément rapides mais de grande capacité.

  • les mémoires les plus rapides sont des emplacements situés au sein-même de l'UAL, que l'on appelle des registres. Un registre en particulier, l'accumulateur, est très utilisé puisque tout calcul doit obligatoirement passer par lui.
  • on trouve ensuite différents types de mémoire électroniques, de vitesse décroissante mais de taille croissante, comme la mémoire cache ( intégrée au processeur ), et la mémoire dynamique ( sous forme de barrettes externes au processeur ). Ces mémoires ne conservent pas les informations de manière permanente.
  • enfin on trouve les mémoires de masse ( disque dur, mémoires flash,...), de vitesse bien plus faible mais de capacité beaucoup plus élevée, qui vont stocker de manière permanente les informations.
Hiérarchie mémoire

Fonctionnement

Si l'unité arithmétique et logique (UAL) est chargée d'effectuer les opérations arithmétiques (addition, soustraction, changement de signe etc.), les opérations logiques (and, or, xor, not etc.) et les tests (test d'égalité, de supériorité etc.), c'est l'unité de contrôle d'un processeur qui en est le "chef-d'orchestre" et qui gère le déroulement des opérations ayant successivement lieu, ce que l'on appelle le séquençage.

Elle est "pilotée" par une horloge très stable qui lui envoie un "top" régulièrement toutes les XXXX secondes ( ou plutôt ms, voire ns : c'est la fréquence du processeur qui indique cette durée; plus la fréquence est élevée, plus les "top" sont rapprochés dans le temps ).

Chaque "top" correspond à un "pas" de fonctionnement du microprocesseur; un pas de fonctionnement peut correspondre à une opération :

  • de lecture mémoire
  • d'écriture mémoire
  • arithmétique ou logique
  • de transfert vers ou depuis les entrée/sorties.

Un registre particulier du processeur, nommé compteur programme ou PC ( Program Counter ), contient l’adresse-mémoire de la prochaine instruction à exécuter ( ce qui lui permet de savoir "où il en est du programme"...); au démarrage du processeur, le registre PC est normalement initialisé à l'adresse 0, début de la mémoire, puis il est automatiquement incrémenté par l'unité de contrôle après chaque opération.

Processeur

Les programmes sont donc lus linéairement par le processeur, instruction après instruction.
Le CPU a un fonctionnement cyclique :

  • il lit le contenu de la RAM à l’adresse pointée par le registre PC
  • il décode l’instruction
  • il exécute l’instruction décodée

La capacité du processeur à exécuter tous les programmes s’explique par ce fonctionnement très souple

Langage machine

Un processeur donné est capable d’exécuter un certain nombre d’opérations de base, celles pour lesquelles il dispose d’un circuit électronique qui les réalise.
L’ensemble des instructions exécutables directement par le microprocesseur (instructions machines) constitue ce que l’on appelle le langage machine du processeur.

Chaque instruction machine correspond à une configuration électronique binaire composée principalement de 2 parties :

Assembleur

Voila donc comment était programmé les premières machines : des interrupteurs, ou des connexions filaires, étaient "basculés" pour "entrer" les interminables successions de "0" et de "1" nécessaires pour réaliser la programmation; inutile de préciser le temps que cela pouvait prendre, et les innombrables erreurs que cela engendrait...

Une amélioration pour l'ergonomie du codage a été, dans les listings de programme, de remplacer les nombres binaires par des mnémoniques, courts ensembles de quelques lettres qui indiquent de manière non ambiguë le rôle de l'instruction.
Le mnémonique du code de l'opération vue dans l'exemple précédent est ainsi "ADDA"; l'instruction complète s'écrira alors : "ADDA $2".

L'assembleur n'est pas un autre langage, distinct du langage machine; c'est simplement une "traduction" pour que la compréhension humaine des programmes et leur correction devienne plus facile; bien entendu, c'est toujours des "0" et des "1" qu'il faut coder dans la machine.

Haut et bas niveau

Le langage machine/assembleur est toujours utilisé aujourd'hui quand on a besoin d'un accès bas-niveau à une machine, comme lorsqu'on code le pilote d'un périphérique. Ce terme de bas-niveau n'a rien de péjoratif, mais signifie "au plus près de la machine"; c'est lui qui permet en effet de manipuler directement le processeur et la mémoire.
Les langages haut-niveau permettent au contraire de les utiliser de manière "transparente" avec un langage beaucoup plus proche de la pensée humaine.

Haut / bas niveau

Une autre énorme différence entre langages de haut et bas-niveau et la suivante :

  • le langage machine est spécifique à un type de processeur en particulier : il existe donc un langage machine différent pour chaque famille de processeurs
  • les langages de haut-niveau sont au contraire destinés à s'abstraire du matériel : un langage de haut-niveau comme Python par exemple s'éxécutera avec le même code sur n'importe quel type de processeur.

Difficulté de la programmation assembleur/langage machine

Une des premières difficultés est déja de connaître le langage machine du processeur sur lequel on veut travailler, et de devoir s'adapter en cas de changement d'architecture.

Ensuite, une des propriétés des UAL est qu'elles ne travaillent en pratique qu'avec deux opérandes.

Conséquence, on ne peut pas demander à une UAL de faire par exemple directement le calcul : 2 + 7 - 5 + 99
En effet ce calcul comporte quatre opérandes (ou quatre valeurs). Il va donc falloir décomposer le travail en demandant à l'UAL trois calculs successifs avec deux opérandes :

De plus, pour des raisons d'optimisation diverses , les valeurs des opérandes doivent être chargées explicitement dans des registres avant de faire un calcul, et la valeur du résultat devra être mémorisée explicitement dans un registre ou un emplacement mémoire; c'est ainsi par exemple par le registre A appelé accumulateur que "transitent" tous les calculs.

Par exemple, pour réaliser la simple opération d'addition suivante : R = S + 2, il faudra en fait écrire quelque chose comme :

Moralité : un processeur ne pouvant effectuer que des taches "de base", il va donc falloir en assembleur ( ou en langage machine...) décomposer au maximum le travail à faire, de façon à lui "mâcher" le travail...

Programmation en langage machine / assembleur

Aujourd'hui, vous allez coder une machine en langage machine et en assembleur pour que vous compreniez bien ce qu'est la programmation bas-niveau, et à quoi on échappe en utilisant des langages haut-niveau comme Python !

La machine utilisée

Programmer en assembleur sur un PC est possible, mais compliqué...Des simulateurs logiciels existent, mais nous vous proposons d'utiliser une vraie machine, très simplifiée, dont les entrées/sorties sont visualisées grâce à des LED, exactement comme pour les premiers kits de micro-ordinateurs des années 70 qui ont lancé la vague de l'informatique personnelle ( Altair 8800 et IMSAI 8080. ).

Cette machine se nomme le Digirule 2A, se programme en assembleur / langage machine, et peut s' acheter pour une dizaine d'euros sur le web; vous disposez dans la salle de quelques "clones" de la machine d'origine.

Caractéristiques :

  • horloge de 4 MHz
  • 256 octets de mémoire RAM
  • 2 ko de stockage de masse, enregistrement de 8 programmes maximum.
  • 35 instructions machine
  • 8 LEDs de données, 8 LEDs d'adresse
  • 8 boutons poussoir pour entrer les données
Digirule 2A
En haut, le Digirule 2A "officiel" - en bas, un clone

Principe de fonctionnement

Principe Digirule

Programmation

Vous l'aurez compris...il va falloir vous mettre dans la peau des pionniers de l'informatique des années 40 pour entrer les 0 et les 1 qui constitueront votre programme...

Heureusement, vous serez aidé par une feuille de tableur LibreOffice, dans laquelle vous écrirez votre code en assembleur et qui vous donnera automatiquement le code binaire des instructions et opérandes correspondants.
Enregistrez cette feuille de calcul sur votre zone personnelle / clé USB.

Dans cette feuille de calcul, seule la colonne "Instruction" doit être complétée avec, à chaque ligne, l'instruction ou l'opérande à entrer; ne touchez pas aux autres colonnes.

Digirule Coder

Pour programmer réellement le Digirule, vous utiliserez les nombres binaires de la colonne "Code machine (binaire)".

Les instructions du langage machine du Digirule que vous utiliserez par la suite sont présentées dans ce document.

Un premier exemple

Pour bien comprendre comment on programme le Digirule, vous allez entrer le programme correspondant à l'exemple de la feuille de calcul, dont voici le listing complet :


	Adresse	Opcode	Opérande			Commentaire

	0		SPEED	124					règle la vitesse d'éxécution ( 0 = le plus rapide / 255 = le plus lent )
	2		COPYLA	170					copie la valeur 170 ( 10101010 ) dans l'accumulateur A
	4		COPYAR	255					copie l'accumulateur vers le registre LEDs de donnée
	6		SHIFTRL	255					décale vers la gauche les bits du registre LEDs de données ( = adresse 255 )
	8		JUMP	6					saut vers l'adresse 6
			

( En réalité, les opcodes et opérandes apparaissent les uns en dessous des autres dans la feuille de calcul puisqu'il est possible de n'en mettre qu'une seule par adresse mémoire.)

Si vous ne vous êtes pas trompés, vous devez voir une "animation" qui fait "défiler" les LEDs de données vers la gauche.

Quelques explications

Modification du programme

Apporter des modifications au programme pour faire défiler vers la droite, partir d'un affichage différent, etc...

Travail à faire

Sur la feuille d'exercices, vous trouverez quelques programmes à écrire/modifier/programmer selon la situation.

Il vous sera demandé de tracer l'exécution des programmes ( on dit aussi dérouler la séquence d'instructions ), c'est à dire de déterminer à chaque pas du programme le contenu de certains registres ou adresses mémoires, ou le résultat d'une opération.

Quand on vous demande d'écrire un programme, il faudra bien entendu le faire d'abord sur papier, puis sur la feuille de calcul et enfin le programmer sur le Digirule.

Aidez-vous du document pour déterminer les instructions à utiliser et la manière de les écrire.