Procédures, pile et langages de haut niveau
CentraleSupélec
2025-11-02
| Code | Nom | Mots | Description |
|---|---|---|---|
| 0x0c00 | END | 1 | Fin du programme |
| 0x1000 | LDAi | 2 | Charge la valeur de l’opérande dans le registre A. [A:=opérande] |
| 0x1400 | LDAd | 2 | Charge la valeur dans la RAM pointée par l’opérande dans le registre A. [A:=Mem[opérande]]. |
| 0x1c00 | STA | 2 | Sauvegarde en mémoire la valeur du registre A à l’adresse donnée par l’opérande. [Mem[opérande]:= A] |
| 0x2000 | LDBi | 2 | Charge la valeur de l’opérande dans le registre B. [B:=opérande] |
| 0x2400 | LDBd | 2 | Charge la valeur dans la RAM pointée par l’opérande dans le registre B. [B:=Mem[opérande]]. |
| 0x2c00 | STB | 2 | Sauvegarde en mémoire la valeur du registre B à l’adresse donnée par l’opérande. [Mem[opérande]:= B] |
| 0x3000 | ADDA | 1 | Ajoute le contenu des registres A et B et mémorise le résultat dans le registre A. [A:=A+B] |
| 0x3400 | ADDB | 1 | Ajoute le contenu des registres A et B et mémorise le résultat dans le registre B. [B:=A+B] |
| 0x3800 | SUBA | 1 | Soustrait le contenu des registres A et B et mémorise le résultat dans le registre A. [A:=A-B] |
| 0x3c00 | SUBB | 1 | Soustrait le contenu des registres A et B et mémorise le résultat dans le registre B. [B:=A-B] |
| 0x4000 | MULA | 1 | Multiplie le contenu des registres A et B et mémorise le résultat dans le registre A. [A:=AxB] |
| 0x4400 | MULB | 1 | Multiplie le contenu des registres A et B et mémorise le résultat dans le registre B. [B:=AxB] |
| 0x4800 | DIVA | 1 | Divise le contenu du registre A par deux et mémorise le résultat dans A. [A:=A/2] |
| 0x5000 | ANDA | 1 | Calcule un ET logique entre le contenu des registres A et B et mémorise le résultat dans A. [A:=A&B] |
| 0x5400 | ANDB | 1 | Calcule un ET logique entre le contenu des registres A et B et mémorise le résultat dans B. [B:=A&B] |
| 0x5800 | ORA | 1 | Calcule un OU logique entre le contenu des registres A et B et mémorise le résultat dans A. [A:=A|B] |
| 0x5c00 | ORB | 1 | Calcule un OU logique entre le contenu des registres A et B et mémorise le résultat dans B. [B:=A|B] |
| 0x6000 | NOTA | 1 | Mémorise dans A la négation de A. [A:=!A] |
| 0x6400 | NOTB | 1 | Mémorise dans B la négation de B. [B:=!B] |
| 0x7000 | JMP | 2 | Saute inconditionnellement à l’adresse donnée par l’opérande. [PC:=operande] |
| 0x7400 | JZA | 2 | Saute à l’adresse donnée par l’opérande si le contenu du registre A est nul. [PC:=operande si A=0] |
| 0x7800 | JZB | 2 | Saute à l’adresse donnée par l’opérande si le contenu du registre B est nul. [PC := operande si B=0] |
Séquenceur
Programme
La notre
Beaucoup d’architectures :
https://en.wikipedia.org/wiki/List_of_instruction_sets
Du Intel 8086(1978) jusqu’au Intel Core i7 (2015)
Note
Intel 64 and IA-32 Architectures Software Developer Manuals
https://software.intel.com/en-us/articles/intel-sdm
Carry Flag (CF), Sign Flag (SF), Zero Flag (ZF),
Beaucoup d’instructions : 1.300 mnémoniques, plusieurs modes d’adressages, ..
Documentation des instructions https://cdrdv2.intel.com/v1/dl/getContent/671110.
Acorn RISC Machine architecture (1980) jusqu’au ARMv8.3-A (2016)
Note
http://infocenter.arm.com/help/index.jsp
Voir l’intervention de ST Micro.
Calculer la suite de Syracuse
\[\forall n \in \mathbb{N}^*, u_{n+1} = \begin{cases} u_n/2 & \mbox{si } u_n \mbox{ est pair}\\ 3u_{n+1}+1 & \mbox{ sinon} \end{cases}\] \[u_0 = 127 ; u_{n} = ?\]
⇔
Code machine
1000 007f 1c00 0024 1c00 1000 1400 0024 2000 0001 5000 7400 001b 1400 0024 2000 0003 4000 2000 0001 3000 1c00 0024 1c00 1000 7000 0006 1400 0024 4800 1c00 0024 1c00 1000 7000 0006
si si, je vous assure. Donc, c’est dur et long.
Calculer la suite de Syracuse
\[\forall n \in \mathbb{N}^*, u_{n+1} = \begin{cases} u_n/2 & \mbox{si } u_n \mbox{ est pair}\\ 3u_{n+1}+1 & \mbox{ sinon} \end{cases}\] \[u_0 = 127 ; u_{n} = ?\]
⇔
Code machine
[LDAi 007f STA 0024 STA 1000] [LDAd 0024 LDBi 0001 ANDA JZA 001b] [LDAd 0024 LDBi 0003 MULA LDBi 0001 ADDA STA 0024 STA 1000 JMP 0006] [LDAd 0024 DIVA STA 0024 STA 1000 JMP 0006]
Les procédures (ou fonctions)
Définition : succession d’opérations à exécuter pour accomplir une tâche déterminée [Larousse]
Exemple de Syracuse en Python:
Nous avons donc \(4\) problèmes à résoudre :
Dans notre architecture, on va répondre à ces \(3\) dernières questions en utilisant une structure particulière : la pile
Une pile en mémoire
Spécifications
Instructions particulières
→ Machines à états (b0, b4, b8, bc)?
Spécifications
Instructions particulières
Attention, il faut penser à l’ajout de l’adresse de retour lorsqu’on indexe la pile (e.g. PEEK, POKE).
et le résultat au fait? La pile !
Le programme appelant
Programme appelé
Programme appelant
Attention!
Dans cette version d’architecture, les accès PEEK, POKE sont relatifs au sommet de pile !
Autre possibilité : registre Base Pointer (BP) / Frame Pointer (FP)
Pour restaurer le registre SP, on pourrait aussi utiliser BP/FP
Les procédures permettent
mais avec un petit surcoût à l’exécution (parfois inévitable)
La pile permet
Problème
Calculer le nombre de déplacement minimum nécessaires : \[h(n) = \begin{cases} 1 & \mbox{si } n=1 \\ 2h(n-1) + 1 & \mbox{sinon} \end{cases}\] \(h(4) = ?\)
Exercice : Définir le code assembleur pour calculer \(h(4)\).
Exécutons (à 8 Hz) et regardons le contenu de la pile pour visualiser les contextes.
La pile pourrait “déborder” \(\rightarrow StackOverflow\)
Au fait ..
Comment passer de la formalisation du problème à un algorithme efficace permettant de le résoudre ??
Cours SDA (1A - S06): Structures de Données et Algorithmes
Cours C++ (1A - S06): Programmation C++, structures de données, etc…
Cours Génie logiciel (2A - S07): Etude des méthodes et bonnes pratiques pour le développement logiciel
Souhaits
8000 0FFF
1000 0001
2000 0002
⋮
LDSPi 0x0FFF
LDAi 0x0001
LDBi 0x0002
⋮
Assembleur : programme traduisant langage d’assemblage → code machine.
Abus : programme assembleur = programme en langage d’assemblage
Spécifications
Les variables et les étiquettes ne doivent pas être interprétables en hexadécimal.
La boucle tant que
En pseudo-code
tant que i ≠ 0 faire
res ← res + i
i ← i - 1
fin tant que
La boucle for est équivalente à la boucle tant que
for ⇔ while
pour (i = 0 ; i < N ; i = i + 1) faire
res ← res + i
fin pour
⇔
i ← 0
tant que i < N faire
res ← res + i
i ← i + 1
fin tant que
for ⇔ while
pour (init; condition ; incrément) faire
action
fin pour
init
tant que condition faire
action
incrément
fin tant que
Les tests conditionnels :
Pseudo-code
si x ≠ 0 alors
x ← 1
fin si
x ← x + 1
Pseudo-code
si x == 10 alors
x ← 0
sinon
x ← x + 1
fin si
Exercice : Assembler le programme
u ← 127
tant que vrai faire
u ← next(u)
print(u)
fin tant que
fonction next(u)
si u pair alors
retourner u/2
sinon
retourner 3*u + 1
fin si
fin fonction
Compteur d’emplacement, table des symboles, variables globals; cf syr.asm
Démo : python assemble.py
Mais pourquoi ?
Assembleur
LDAd b; LDBd c; ADDA; STA a)Langage de haut niveau
Langage interprété
Un programme (interpréteur) interprète “à la volée” le code source
Ex : Python/ python
python main.py
⇒ Machine virtuelle python
Références :
Représentation intermédiaire
Ex : register transfer language, gimple, generic, three adress code, single static assignment, control flow graph, …
Example de représentation : Three Address Code
x := y op zx:= op yx := ygoto L; If x relop y goto Lparam x1,.. call p, return yRéférences :
En C++ :
Représentation 3-Address Code
x = 3;
_t1 = 2 + 7;
y = _t1 + x;
z = 2 * y;
_t2 = x < y;
IfZ _t2 Goto _L0;
_t3 = x / 2;
_t4 = y / 3;
z = _t3 + _t4
Goto _L1
_L0: _t5 = x * y;
z = _t5 + z;
_L1:
Note
Application répétée de quelques règles de simplification
jusqu’à ce que plus aucune des règles ne soit applicable
Représentation intermédiaire ⇒ Code machine
Références :

Produced with quarto
Comment faire pour simplifier la programmation ?
Ne plus écrire en code machine1
2000 0002
3000
LDBi 2
ADDA
b=2
a=a+b
et bien sûr comment faire la conversion vers le langage machine