Activité : Little Man Computer (LMC)
Rappel d'ouverture (5 minutes, cours fermé)
- Une instruction machine se décompose en deux parties. Lesquelles, et à quoi sert chacune ?
- Dans une machine où une instruction s'écrit sur trois chiffres, combien de chiffres reste-t-il pour désigner une adresse ?
- Pourquoi le processeur n'a-t-il pas besoin de savoir que
007était une donnée ?
Corrigé
- Le code opération (quelle opération effectuer) et l'opérande (sur quelle donnée ou quelle adresse travailler).
- Deux, le premier chiffre étant pris par le code opération. On peut donc adresser 100 cases, de 00 à 99.
- Parce qu'il n'en a aucun moyen, et que cela ne l'empêche pas de fonctionner : il exécute ce que le compteur ordinal désigne, sans se demander ce que le programmeur avait en tête.
Introduction
Le Little Man Computer (LMC) est un simulateur pédagogique qui modélise une architecture simplifiée de processeur. Il permet de comprendre concrètement comment fonctionne un ordinateur en visualisant :
- Le chargement du programme en mémoire
- Le cycle fetch-decode-execute
- Le rôle du compteur ordinal (PC)
Le simulateur
URL du simulateur : https://wellingborough.github.io/LMC/LMC0.3.html
Le LMC est construit autour d'une architecture simplifiée :
- 100 emplacements mémoire (adresses 00 à 99)
- Un accumulateur (ACC) : unique espace de travail pour les calculs
- Un compteur ordinal (PC) : indique l'adresse de la prochaine instruction
- Une ALU (Unité Arithmétique et Logique) : effectue les additions et soustractions
Particularité pédagogique : Le LMC utilise des nombres décimaux (et non binaires) pour simplifier l'apprentissage.
Jeu d'instructions du LMC
Le LMC possède 11 instructions simples. Chaque instruction est codée sur 3 chiffres en code machine.
Instructions d'entrée/sortie
| Mnémonique | Nom | Description | Code machine |
|---|---|---|---|
INP |
INPUT | Demande une entrée utilisateur et la stocke dans l'accumulateur | 901 |
OUT |
OUTPUT | Affiche la valeur contenue dans l'accumulateur | 902 |
Instructions de transfert mémoire
| Mnémonique | Nom | Description | Code machine |
|---|---|---|---|
LDA xx |
LOAD | Charge dans l'accumulateur la valeur située à l'adresse mémoire xx |
5xx |
STA xx |
STORE | Stocke la valeur de l'accumulateur à l'adresse mémoire xx |
3xx |
Instructions arithmétiques
| Mnémonique | Nom | Description | Code machine |
|---|---|---|---|
ADD xx |
ADD | Ajoute à l'accumulateur la valeur située à l'adresse xx |
1xx |
SUB xx |
SUBTRACT | Soustrait de l'accumulateur la valeur située à l'adresse xx |
2xx |
Instructions de branchement (saut)
| Mnémonique | Nom | Description | Code machine |
|---|---|---|---|
BRA xx |
BRANCH ALWAYS | Saute toujours à l'adresse xx (branchement inconditionnel) |
6xx |
BRZ xx |
BRANCH IF ZERO | Saute à l'adresse xx si l'accumulateur vaut zéro |
7xx |
BRP xx |
BRANCH IF POSITIVE | Saute à l'adresse xx si l'accumulateur est positif ou nul |
8xx |
Instructions spéciales
| Mnémonique | Nom | Description | Code machine |
|---|---|---|---|
HLT |
HALT | Arrête l'exécution du programme | 000 |
DAT |
DATA | Réserve un emplacement mémoire pour une variable (optionnellement avec une valeur initiale) | - |
Utilisation de DAT
DAT n'est pas une instruction exécutable, c'est une directive pour l'assembleur. Elle permet de définir des variables avec un nom symbolique.
Exemples :
nombre DAT # Réserve un emplacement nommé "nombre" (valeur initiale 0)
valeur DAT 42 # Réserve un emplacement nommé "valeur" avec 42 comme valeur initiale
Exemple de programme commenté
Voici un programme simple qui additionne deux nombres :
INP # Demander le premier nombre → ACC
STA nb1 # Stocker ACC dans la variable "nb1"
INP # Demander le deuxième nombre → ACC
ADD nb1 # Ajouter nb1 à ACC
OUT # Afficher le résultat
HLT # Arrêter le programme
nb1 DAT # Variable pour stocker le premier nombre
Observation pendant l'exécution :
- Le PC (compteur ordinal) commence à 0
- L'instruction
INPest chargée depuis la mémoire - Le PC s'incrémente automatiquement
- L'instruction est décodée puis exécutée
- Les données circulent sur les bus entre les registres
Avant les défis : assembler à la main
Vous allez écrire vos programmes en mnémoniques (INP, STA nb1, ADD nb1), parce que c'est lisible. La machine, elle, ne connaît que des nombres. Quelqu'un doit donc traduire, et cette activité consiste à faire ce travail une fois vous-même, pour savoir ce que le simulateur fait à votre place ensuite.
Traduire un programme en code machine
Voici un programme en mnémoniques, déjà placé en mémoire. Chaque ligne occupe une case, à partir de l'adresse 00.
| Adresse | Mnémonique |
|---|---|
| 00 | INP |
| 01 | STA 06 |
| 02 | INP |
| 03 | ADD 06 |
| 04 | OUT |
| 05 | HLT |
| 06 | DAT |
1. À l'aide du jeu d'instructions ci-dessus, écrivez le code machine de chaque ligne, c'est-à-dire les trois chiffres que contiendra réellement la case.
2. Recopiez la suite obtenue et vérifiez que le programme fonctionne : dans le simulateur, saisissez ces nombres directement dans les cases mémoire, sans passer par les mnémoniques, puis exécutez.
3. Combien de tables de correspondance avez-vous utilisées pour faire cette traduction ?
Correction
1.
| Adresse | Mnémonique | Code machine |
|---|---|---|
| 00 | INP |
901 |
| 01 | STA 06 |
306 |
| 02 | INP |
901 |
| 03 | ADD 06 |
106 |
| 04 | OUT |
902 |
| 05 | HLT |
000 |
| 06 | DAT |
000 |
La suite est donc : 901 306 901 106 902 000 000
2. Le programme fonctionne exactement de la même façon. C'est normal : c'est le même programme. Les mnémoniques n'existent que pour vous, elles ne sont jamais chargées dans la machine.
3. Une seule, celle du jeu d'instructions du LMC. Et c'est le point : vous venez de faire, à la main, ce qu'un programme appelé assembleur fait automatiquement. Traduire des mnémoniques en code machine, ce n'est pas comprendre un programme, c'est appliquer une table.
Ce que vous venez de faire, et pourquoi cela referme la boucle
Souvenez-vous de l'activité de rentrée : votre groupe avait fabriqué une table associant un nombre à chaque mot, et le programme codé était illisible pour qui n'avait pas la table.
La table du LMC est exactement de même nature. Elle n'est ni plus vraie ni plus logique que la vôtre : elle a simplement été décidée par les concepteurs de cette machine, et gravée dans son circuit. C'est pourquoi 901 veut dire « lire une valeur » ici, et voudrait dire tout autre chose sur un processeur différent.
Un assembleur est donc un traducteur qui connaît une table. Un compilateur, que vous rencontrerez plus tard, fait un travail beaucoup plus difficile : il traduit un langage où une seule ligne peut valoir des dizaines d'instructions machine.
Pourquoi le faire une seule fois
Une fois cette traduction faite à la main, elle n'a plus d'intérêt : le simulateur la fait sans erreur et sans fatigue. Ce que vous devez en garder n'est pas la capacité de traduire vite, mais la certitude qu'il n'y a rien de magique entre ce que vous écrivez et ce que la machine exécute. Pour les 12 défis, écrivez donc en mnémoniques.
Les 12 défis
Voici une série de 12 exercices progressifs pour maîtriser la programmation en LMC. Commencez par les plus simples et avancez progressivement.
Niveau 1 : Séquence simple (Instructions de base)
Défi 1 : Écho simple
Objectif : Demander un nombre à l'utilisateur et l'afficher.
Programme attendu :
- Lire une entrée
- Afficher cette entrée
Instructions à utiliser : INP, OUT, HLT
Défi 2 : Deux nombres
Objectif : Demander deux nombres à l'utilisateur et les afficher dans le même ordre.
Programme attendu :
- Lire un premier nombre et le stocker
- Lire un deuxième nombre et le stocker
- Afficher le premier nombre
- Afficher le deuxième nombre
Instructions à utiliser : INP, OUT, STA, LDA, HLT, DAT
Correction — Défi 2
Défi 3 : Addition
Objectif : Demander deux nombres à l'utilisateur et afficher leur somme.
Programme attendu :
- Lire le premier nombre et le stocker
- Lire le deuxième nombre
- Additionner les deux nombres
- Afficher le résultat
Instructions à utiliser : INP, OUT, STA, ADD, HLT, DAT
Correction — Défi 3
Défi 4 : Soustraction
Objectif : Demander deux nombres à l'utilisateur et afficher leur différence (premier - deuxième).
Programme attendu :
- Lire le premier nombre et le stocker
- Lire le deuxième nombre et le stocker
- Calculer premier - deuxième
- Afficher le résultat
Instructions à utiliser : INP, OUT, STA, LDA, SUB, HLT, DAT
Correction — Défi 4
Défi 5 : Moyenne de trois nombres
Objectif : Demander trois nombres à l'utilisateur et afficher leur moyenne (somme divisée par 3).
Programme attendu :
- Lire trois nombres successivement
- Calculer leur somme
- Diviser par 3 (soustraire 3 plusieurs fois jusqu'à obtenir 0, compter les soustractions)
- Afficher le résultat
Indices :
- Stocker les trois nombres en mémoire
- Les additionner un par un
- Pour diviser par 3, utiliser une boucle qui soustrait 3 et compte le nombre de soustractions
Correction — Défi 5
La division par 3 est simulée par soustractions successives : on soustrait 3 à la somme en comptant chaque opération jusqu'à ce que le résultat devienne négatif.
INP
STA nb1
INP
STA nb2
INP
STA nb3
LDA nb1 # Calculer la somme
ADD nb2
ADD nb3
STA somme
LDA zero
STA moy
boucle LDA somme # Tester si somme - 3 >= 0
SUB trois
BRP suite # Si oui, continuer la division
LDA moy # Sinon, afficher le quotient
OUT
HLT
suite STA somme # somme = somme - 3
LDA moy
ADD un # moy = moy + 1
STA moy
BRA boucle
nb1 DAT
nb2 DAT
nb3 DAT
somme DAT
moy DAT
zero DAT 0
un DAT 1
trois DAT 3
Niveau 2 : Sélection (Structures conditionnelles)
Défi 6 : Maximum de deux nombres
Objectif : Demander deux nombres à l'utilisateur et afficher le plus grand des deux.
Programme attendu :
- Lire deux nombres (A et B)
- Calculer A - B
- Si le résultat est positif ou nul : afficher A
- Sinon : afficher B
Astuce : Utiliser SUB puis BRP pour tester quel nombre est le plus grand.
Correction — Défi 6
Défi 7 : Test de positivité
Objectif : Demander un nombre à l'utilisateur. Afficher 1 s'il est positif ou nul, afficher 0 s'il est négatif.
Programme attendu :
- Lire un nombre
- Tester s'il est positif (≥ 0)
- Afficher 1 ou 0 selon le cas
Correction — Défi 7
Défi 8 : Maximum de trois nombres
Objectif : Demander trois nombres à l'utilisateur et afficher le plus grand des trois.
Programme attendu :
- Lire trois nombres (A, B, C)
- Comparer A et B → garder le max dans une variable
- Comparer ce max avec C
- Afficher le résultat final
Indice léger
Vous savez déjà comparer deux nombres, c'est le défi 6. N'essayez pas de comparer les trois d'un coup : servez-vous deux fois de ce que vous savez faire.
Indice précis
Traitez le problème en deux temps. Premier temps, comparez A et B et rangez le plus grand des deux dans une case, disons max. Second temps, comparez le contenu de max avec C, exactement comme au défi 6, et rangez à nouveau le vainqueur dans max. Il ne reste plus qu'à l'afficher.
Le piège est de vouloir afficher dans chaque branche. Ne le faites qu'une seule fois, à la fin : la comparaison décide, elle n'affiche pas.
Correction — Défi 8
Niveau 3 : Itération (Boucles)
Défi 9 : Compte à rebours
Objectif : Afficher les nombres de 10 à 1 (compte à rebours).
Programme attendu :
- Initialiser un compteur à 10
- Afficher le compteur
- Décrémenter le compteur (soustraire 1)
- Répéter tant que le compteur n'est pas à 0
Concept clé : Utilisation d'une boucle avec un test de fin (BRZ).
Indice léger
Une boucle en langage machine, c'est un saut en arrière. Il vous faut donc repérer l'adresse à laquelle revenir, et décider à quel moment ne plus y revenir.
Indice précis
Le corps de la boucle tient en trois gestes : charger le compteur, l'afficher, lui soustraire 1. Ensuite seulement viennent les deux décisions.
D'abord, rangez le compteur avant de tester, sinon vous testerez autre chose que ce que vous croyez. Ensuite, BRZ saute vers la sortie si l'accumulateur vaut zéro, et un BRA inconditionnel ramène au début du corps sinon. Attention à l'ordre de ces deux instructions : le BRZ doit venir avant le BRA, sans quoi on ne sort jamais.
Correction — Défi 9
Défi 10 : Compteur croissant
Objectif : Afficher les nombres de 1 à 10.
Programme attendu :
- Initialiser un compteur à 1
- Afficher le compteur
- Incrémenter le compteur (ajouter 1)
- Répéter jusqu'à 10
Correction — Défi 10
Défi 11 : Table de multiplication
Objectif : Demander un nombre N à l'utilisateur, puis afficher sa table de multiplication de 1 à 10.
Exemple : Si l'utilisateur entre 7, afficher : 7, 14, 21, 28, 35, 42, 49, 56, 63, 70
Programme attendu :
- Lire N
- Initialiser un compteur à 1 et un résultat à 0
- Boucle :
- Ajouter N au résultat
- Afficher le résultat
- Incrémenter le compteur
- Répéter jusqu'à 10
Instructions à utiliser : INP, OUT, LDA, STA, ADD, SUB, BRZ, BRA, HLT, DAT
Concept clé : La multiplication est réalisée par additions successives.
Correction — Défi 11
Défi 12 : Somme des N premiers entiers
Objectif : Demander un nombre N à l'utilisateur et afficher la somme 1 + 2 + 3 + ... + N.
Exemple : Si l'utilisateur entre 5, afficher 15 (car 1+2+3+4+5 = 15)
Programme attendu :
- Lire N
- Initialiser une somme à 0
- Initialiser un compteur à N
- Boucle :
- Ajouter le compteur à la somme
- Décrémenter le compteur
- Répéter tant que le compteur n'est pas à 0
- Afficher la somme
Concept clé : Utilisation d'un accumulateur et d'une boucle décrémentale.
Indice léger
C'est le défi 9 avec une opération en plus : au lieu de simplement afficher le compteur, vous l'accumulez dans une seconde case avant de le décrémenter.
Indice précis
Vous manipulez maintenant deux variables, somme et compteur, et un seul accumulateur pour les deux. Chaque fois que vous voulez travailler sur l'une, il faut la charger, et la ranger avant de toucher à l'autre. C'est la principale source d'erreur de ce défi.
L'ordre qui fonctionne : charger somme, y ajouter compteur, ranger somme ; puis charger compteur, lui soustraire 1, ranger compteur ; puis tester s'il vaut zéro. N'affichez qu'à la sortie de la boucle.
Correction — Défi 12
Conseils pour réussir
1. Observer avant de coder
- Lancez le simulateur en mode pas à pas (step-by-step)
- Observez comment le compteur ordinal (PC) évolue
- Suivez le parcours des données sur les bus
- Identifiez quels registres sont modifiés à chaque étape
2. Planifier votre algorithme
Avant d'écrire le code LMC : 1. Écrivez l'algorithme en pseudo-code ou en Python 2. Identifiez les variables nécessaires 3. Déterminez les structures de contrôle (boucles, conditions)
3. Tester régulièrement
- Testez avec des valeurs simples d'abord (ex : 1, 2, 3)
- Vérifiez les cas limites (ex : 0, nombres négatifs)
- Utilisez la console du simulateur pour suivre l'exécution
4. Déboguer efficacement
Si votre programme ne fonctionne pas :
- Vérifiez que chaque instruction utilise la bonne adresse mémoire
- Assurez-vous que les labels sont correctement définis
- Vérifiez que vous n'avez pas oublié HLT à la fin
- Observez les valeurs dans les registres à chaque étape
Pour aller plus loin
Une fois les 12 défis réussis, vous pouvez essayer :
- Multiplication de deux nombres : A × B par additions successives
- Division euclidienne : Quotient et reste de A ÷ B par soustractions successives
- Suite de Fibonacci : Afficher les N premiers termes
- Factorielle : Calculer N!
- Recherche du minimum : Parmi une série de nombres entrés par l'utilisateur
Ressources
- Simulateur LMC : https://www.101computing.net/lmc/
- Simulateur alternatif (Peter Higginson) : https://peterhigginson.co.uk/lmc/
- Tutoriels détaillés : https://teachcomputerscience.com/lmc/
- Exercices avancés : https://github.com/Mbyrne28/Little-Man-Computer
Sources : - 101 Computing - Little Man Computer Mini Challenges - Teach Computer Science - LMC Resources - Wikipedia - Little Man Computer - Programme NSI - Bulletin officiel spécial n°1 du 22 janvier 2019