Skip to content

Activité : Little Man Computer (LMC)

Rappel d'ouverture (5 minutes, cours fermé)

  1. Une instruction machine se décompose en deux parties. Lesquelles, et à quoi sert chacune ?
  2. Dans une machine où une instruction s'écrit sur trois chiffres, combien de chiffres reste-t-il pour désigner une adresse ?
  3. Pourquoi le processeur n'a-t-il pas besoin de savoir que 007 était une donnée ?
Corrigé
  1. Le code opération (quelle opération effectuer) et l'opérande (sur quelle donnée ou quelle adresse travailler).
  2. Deux, le premier chiffre étant pris par le code opération. On peut donc adresser 100 cases, de 00 à 99.
  3. 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 :

  1. Le PC (compteur ordinal) commence à 0
  2. L'instruction INP est chargée depuis la mémoire
  3. Le PC s'incrémente automatiquement
  4. L'instruction est décodée puis exécutée
  5. 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

Correction — Défi 1
        INP       # Lire l'entrée → ACC
        OUT       # Afficher ACC
        HLT       # Fin

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
        INP       # Lire le premier nombre → ACC
        STA nb1   # Stocker dans nb1
        INP       # Lire le deuxième nombre → ACC
        STA nb2   # Stocker dans nb2
        LDA nb1   # Charger nb1
        OUT       # Afficher nb1
        LDA nb2   # Charger nb2
        OUT       # Afficher nb2
        HLT
nb1     DAT
nb2     DAT

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
        INP       # Lire le premier nombre → ACC
        STA nb1   # Stocker dans nb1
        INP       # Lire le deuxième nombre → ACC
        ADD nb1   # ACC = ACC + nb1
        OUT       # Afficher la somme
        HLT
nb1     DAT

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
        INP       # Lire le premier nombre → ACC
        STA nb1   # Stocker dans nb1
        INP       # Lire le deuxième nombre → ACC
        STA nb2   # Stocker dans nb2
        LDA nb1   # Charger nb1 dans ACC
        SUB nb2   # ACC = nb1 - nb2
        OUT       # Afficher le résultat
        HLT
nb1     DAT
nb2     DAT

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
        INP
        STA a
        INP
        STA b
        LDA a
        SUB b
        BRP affA    # Si A - B >= 0, afficher A
        LDA b       # Sinon afficher B
        OUT
        HLT
affA    LDA a
        OUT
        HLT
a       DAT
b       DAT

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
        INP
        BRP positif # Si ACC >= 0, sauter à "positif"
        LDA zero    # Sinon charger 0
        OUT
        HLT
positif LDA un      # Charger 1
        OUT
        HLT
zero    DAT 0
un      DAT 1

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
        INP
        STA a
        INP
        STA b
        INP
        STA c
        LDA a
        SUB b
        BRP aGb     # Si A >= B, max = A
        LDA b       # Sinon max = B
        STA max
        BRA cmpC
aGb     LDA a
        STA max
cmpC    LDA max
        SUB c
        BRP fin     # Si max >= C, max est déjà bon
        LDA c       # Sinon max = C
        STA max
fin     LDA max
        OUT
        HLT
a       DAT
b       DAT
c       DAT
max     DAT

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
        LDA dix
        STA cpt
boucle  LDA cpt
        OUT         # Afficher le compteur
        SUB un
        STA cpt
        BRZ fin     # Si cpt = 0, terminer
        BRA boucle
fin     HLT
cpt     DAT
dix     DAT 10
un      DAT 1

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
        LDA un
        STA cpt
boucle  LDA cpt
        OUT         # Afficher le compteur
        SUB dix
        BRZ fin     # Si cpt = 10, terminer
        LDA cpt
        ADD un
        STA cpt
        BRA boucle
fin     HLT
cpt     DAT
un      DAT 1
dix     DAT 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
        INP
        STA n
        LDA zero
        STA res
        LDA un
        STA cpt
boucle  LDA res
        ADD n       # res = res + N
        STA res
        OUT         # Afficher res (= N × cpt)
        LDA cpt
        SUB dix
        BRZ fin     # Si cpt = 10, terminer
        LDA cpt
        ADD un
        STA cpt
        BRA boucle
fin     HLT
n       DAT
res     DAT
cpt     DAT
zero    DAT 0
un      DAT 1
dix     DAT 10

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
        INP
        STA cpt     # cpt = N (on décompte de N à 1)
        LDA zero
        STA somme
boucle  LDA somme
        ADD cpt     # somme = somme + cpt
        STA somme
        LDA cpt
        SUB un
        STA cpt
        BRZ fin     # Si cpt = 0, terminer
        BRA boucle
fin     LDA somme
        OUT
        HLT
cpt     DAT
somme   DAT
zero    DAT 0
un      DAT 1

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


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