Aller au contenu

Exercices - Architectures matérielles et systèmes d'exploitation


Modèle de Von Neumann

Exercice 1 - Les composants

a. Citer les quatre composants du modèle de Von Neumann.

b. Quel est le rôle de l'UAL ? De l'unité de commande ?

c. Quelle est la différence fondamentale entre la mémoire vive (RAM) et un disque dur (HDD) ?

d. Quel est le principe fondamental qui distingue le modèle de Von Neumann des machines précédentes ?

Solution

a. Les quatre composants sont : le processeur (CPU), la mémoire vive (RAM), les entrées/sorties et les bus.

b. L'UAL (Unité Arithmétique et Logique) effectue les calculs (addition, soustraction, comparaison) et les opérations logiques (ET, OU, NON). L'unité de commande lit les instructions en mémoire, les décode et coordonne leur exécution.

c. La RAM est une mémoire volatile (contenu perdu à l'extinction) mais rapide (accès en nanosecondes). Le disque dur est une mémoire non volatile (contenu conservé) mais lente (accès en millisecondes). La RAM sert pour le traitement en temps réel, le disque pour le stockage permanent.

d. Le principe fondamental est que le programme est stocké en mémoire au même titre que les données. Avant Von Neumann, il fallait recâbler physiquement la machine pour changer de programme.


Exercice 2 - Cycle d'exécution

a. Décrire les trois étapes du cycle d'exécution d'une instruction par le processeur.

b. Un processeur cadencé à 2,5 GHz effectue combien de cycles d'horloge par seconde ?

c. Quel registre contient l'adresse de la prochaine instruction à exécuter ? Quel registre contient l'instruction en cours de décodage ?

Solution

a. 1. Chargement (fetch) : le processeur lit en mémoire l'instruction à l'adresse contenue dans IP et la place dans IR. IP est incrémenté. 2. Décodage (decode) : l'unité de commande analyse l'instruction dans IR. 3. Exécution (execute) : l'UAL effectue l'opération demandée.

b. 2,5 GHz = 2,5 × 10⁹ = 2 500 000 000 cycles par seconde (2,5 milliards).

c. Le registre IP (Instruction Pointer) contient l'adresse de la prochaine instruction. Le registre IR (Instruction Register) contient l'instruction en cours de décodage.


Langage machine et assembleur

Exercice 3 - Instructions assembleur

Indiquer, pour chaque instruction, l'opération effectuée et l'état des registres/mémoire après exécution.

a. MOV R0, #15

b. ADD R1, R0, #3

c. STR R1, 200

d. LDR R2, 200

e. SUB R3, R2, R0

Solution

a. Place la valeur 15 dans R0. → R0 = 15

b. Additionne R0 (15) et la valeur immédiate 3, stocke le résultat dans R1. → R1 = 18

c. Stocke la valeur de R1 (18) en mémoire à l'adresse 200. → mémoire[200] = 18

d. Charge la valeur en mémoire à l'adresse 200 (18) dans R2. → R2 = 18

e. Soustrait R0 (15) de R2 (18), stocke le résultat dans R3. → R3 = 3

État final : R0 = 15, R1 = 18, R2 = 18, R3 = 3, mémoire[200] = 18.


Exercice 4 - Dérouler un programme assembleur

Dérouler le programme suivant et indiquer la valeur finale de R0 et de la mémoire à l'adresse 50.

    MOV R0, #10
    MOV R1, #4
    ADD R0, R0, R1
    SUB R0, R0, #2
    STR R0, 50
    LDR R2, 50
    ADD R0, R2, R2
    STR R0, 50
    HALT
Solution
Instruction R0 R1 R2 mém[50]
MOV R0, #10 10
MOV R1, #4 10 4
ADD R0, R0, R1 14 4
SUB R0, R0, #2 12 4
STR R0, 50 12 4 12
LDR R2, 50 12 4 12 12
ADD R0, R2, R2 24 4 12 12
STR R0, 50 24 4 12 24

Valeur finale : R0 = 24, mémoire[50] = 24.


Exercice 5 - Traduire Python en assembleur

Traduire les programmes Python suivants en assembleur (stocker les variables en mémoire aux adresses indiquées).

a. a = 7 et b = a + 5 (a à l'adresse 30, b à l'adresse 31)

b. Le programme avec condition :

x = 12    # adresse 40
if x > 10:
    x = x - 10
Solution

a.

MOV R0, #7
STR R0, 30       ; a = 7
LDR R0, 30
ADD R0, R0, #5
STR R0, 31       ; b = a + 5 = 12
HALT

b.

    MOV R0, #12
    STR R0, 40       ; x = 12
    LDR R0, 40
    CMP R0, #10      ; comparer x à 10
    BLT fin          ; si x < 10, sauter à fin (donc ne rien faire si x <= 10)
    BEQ fin          ; si x == 10, sauter à fin
    SUB R0, R0, #10  ; x = x - 10
    STR R0, 40
fin:
    HALT

Comme x = 12 > 10, les deux branchements ne sont pas pris, et on exécute x = x - 10 = 2.


Systèmes d'exploitation et ligne de commande

Exercice 6 - Navigation dans le système de fichiers

On se trouve dans le répertoire /home/alice/Documents.

a. Quelle commande permet d'afficher le répertoire courant ?

b. Quelle commande permet de lister le contenu du répertoire courant ?

c. Écrire la commande pour créer un répertoire NSI dans le répertoire courant.

d. Écrire la commande pour aller dans ce nouveau répertoire NSI.

e. Écrire la commande pour remonter au répertoire parent (Documents).

f. Écrire le chemin absolu du répertoire NSI.

Solution

a. pwd (affiche /home/alice/Documents)

b. ls

c. mkdir NSI

d. cd NSI

e. cd ..

f. /home/alice/Documents/NSI


Exercice 7 - Droits d'accès

a. Décoder les droits suivants : -rwxr-x---

b. Que signifie chmod 640 rapport.txt ? Détailler les droits pour chaque catégorie.

c. Écrire la commande chmod en notation symbolique pour retirer le droit d'écriture au groupe sur le fichier notes.txt.

d. Un fichier a les droits -rw-rw-r--. L'utilisateur bob (qui n'est ni le propriétaire ni dans le groupe) peut-il modifier ce fichier ? Le lire ?

Solution

a. - - : c'est un fichier (pas un répertoire) - rwx : le propriétaire peut lire, écrire et exécuter - r-x : le groupe peut lire et exécuter (pas écrire) - --- : les autres n'ont aucun droit

b. chmod 640 : - 6 = 4 + 2 = rw- : le propriétaire peut lire et écrire - 4 = r-- : le groupe peut seulement lire - 0 = --- : les autres n'ont aucun droit

c. chmod g-w notes.txt

d. Bob est dans la catégorie « autres » (derniers 3 caractères : r--). Il peut lire le fichier (droit r) mais ne peut pas le modifier (pas de droit w).


Réseaux

Exercice 8 - Adressage IP

a. L'adresse 192.168.1.25 avec le masque 255.255.255.0 : quelle est la partie réseau ? La partie machine ?

b. Deux machines avec les adresses 192.168.1.10 et 192.168.2.10 (masque 255.255.255.0) sont-elles sur le même réseau ?

c. Quelle est la particularité de l'adresse 127.0.0.1 ?

Solution

a. Partie réseau : 192.168.1 (les 3 premiers octets, car le masque est 255.255.255.0). Partie machine : .25 (le dernier octet).

b. Non, elles ne sont pas sur le même réseau. La première est sur le réseau 192.168.1.0 et la seconde sur le réseau 192.168.2.0. Pour communiquer, elles ont besoin d'un routeur.

c. 127.0.0.1 est l'adresse de bouclage (loopback), aussi appelée localhost. Elle désigne la machine elle-même. Elle est utilisée pour tester la connectivité réseau locale.


Exercice 9 - Protocole du bit alterné

Dérouler le protocole du bit alterné pour la transmission de 4 paquets (A, B, C, D) sachant que :

  • Le paquet B est perdu lors du premier envoi
  • L'accusé de réception du paquet C est perdu
Solution
Émetteur                              Récepteur

Envoi A (seq=0) ─────────────────────► Reçu A
◄───────────────────── ACK 0           

Envoi B (seq=1) ──────── ✗ (perdu)     
(timeout, pas d'ACK)
Envoi B (seq=1, retransmis) ─────────► Reçu B
◄───────────────────── ACK 1           

Envoi C (seq=0) ─────────────────────► Reçu C
◄────── ACK 0 ────── ✗ (perdu)         
(timeout, pas d'ACK)
Envoi C (seq=0, retransmis) ─────────► Doublon détecté (seq=0 déjà reçu)
◄───────────────────── ACK 0           (renvoie ACK 0 quand même)

Envoi D (seq=1) ─────────────────────► Reçu D
◄───────────────────── ACK 1           

Le récepteur détecte le doublon de C car il reçoit un paquet avec seq=0 alors qu'il attend seq=0 pour un nouveau paquet (mais il a déjà reçu le paquet avec seq=0 précédent). Il renvoie quand même l'accusé ACK 0.


Exercice 10 - Encapsulation

On envoie le message « Bonjour » depuis la machine A (192.168.1.10) vers la machine B (192.168.1.20) via HTTP.

a. Décrire les étapes d'encapsulation du message, couche par couche.

b. Quelles informations sont ajoutées par chaque couche ?

c. À la réception, dans quel ordre les en-têtes sont-ils retirés ?

Solution

a. Encapsulation couche par couche :

  1. Couche Application (HTTP) : le message « Bonjour » est intégré dans une requête HTTP
  2. Couche Transport (TCP) : ajout d'un en-tête TCP (ports source/destination, numéro de séquence)
  3. Couche Réseau (IP) : ajout d'un en-tête IP (adresses IP source 192.168.1.10 et destination 192.168.1.20)
  4. Couche Liaison (Ethernet) : ajout d'un en-tête Ethernet (adresses MAC source et destination)

b.

Couche Informations ajoutées
Application Type de requête HTTP, en-têtes HTTP
Transport Ports source et destination, numéro de séquence, drapeaux TCP
Réseau Adresses IP source et destination, TTL
Liaison Adresses MAC source et destination, type de protocole

c. À la réception, les en-têtes sont retirés dans l'ordre inverse : d'abord Ethernet (couche liaison), puis IP (couche réseau), puis TCP (couche transport), et enfin HTTP (couche application) pour retrouver le message « Bonjour ».



Activités


🧪 Activité 1 - Simulateur d'assembleur

Objectif

Écrire et exécuter des programmes en assembleur sur un simulateur pour comprendre le fonctionnement du processeur.

Étapes

a. Écrire un programme assembleur qui calcule la somme des entiers de 1 à 10 (résultat dans R0).

b. Dérouler les 3 premières itérations à la main (état des registres à chaque étape).

c. Vérifier que le résultat final est bien 55.

Correction
    MOV R0, #0       ; somme = 0
    MOV R1, #1       ; i = 1
boucle:
    CMP R1, #11      ; comparer i à 11
    BEQ fin          ; si i == 11, sortir
    ADD R0, R0, R1   ; somme = somme + i
    ADD R1, R1, #1   ; i = i + 1
    B boucle         ; retour au début
fin:
    HALT

Trois premières itérations :

Itération R1 (i) R0 (somme) avant R0 après
1 1 0 1
2 2 1 3
3 3 3 6

Résultat final : R0 = 1 + 2 + 3 + ... + 10 = 55.


🧪 Activité 2 - Exploration du système de fichiers

Objectif

Pratiquer les commandes de base du terminal Linux.

Étapes

a. Ouvrir un terminal. Afficher le répertoire courant, puis son contenu détaillé.

b. Créer l'arborescence suivante :

~/NSI/
├── Cours/
│   ├── chapitre1.txt
│   └── chapitre2.txt
├── Exercices/
│   └── tp1.py
└── Projets/

c. Copier chapitre1.txt dans le répertoire Projets.

d. Renommer chapitre2.txt en resume.txt.

e. Afficher les droits de tous les fichiers. Modifier les droits de tp1.py pour que seul le propriétaire puisse le lire, l'écrire et l'exécuter.

f. Supprimer le fichier copié dans Projets.

Correction
# a.
pwd
ls -l

# b.
mkdir -p ~/NSI/Cours ~/NSI/Exercices ~/NSI/Projets
touch ~/NSI/Cours/chapitre1.txt
touch ~/NSI/Cours/chapitre2.txt
touch ~/NSI/Exercices/tp1.py

# c.
cp ~/NSI/Cours/chapitre1.txt ~/NSI/Projets/

# d.
mv ~/NSI/Cours/chapitre2.txt ~/NSI/Cours/resume.txt

# e.
ls -l ~/NSI/Cours/ ~/NSI/Exercices/
chmod 700 ~/NSI/Exercices/tp1.py

# f.
rm ~/NSI/Projets/chapitre1.txt

🧪 Activité 3 - Simuler un réseau avec Filius

Objectif

Utiliser le logiciel Filius pour simuler un réseau local et observer le routage des paquets.

Étapes

a. Créer un réseau avec 3 ordinateurs (PC1, PC2, PC3) reliés à un switch. Configurer les adresses IP : 192.168.1.1, 192.168.1.2, 192.168.1.3 (masque 255.255.255.0).

b. Tester la connectivité avec ping entre PC1 et PC3.

c. Ajouter un second réseau (192.168.2.0/24) avec 2 ordinateurs et un switch. Relier les deux réseaux par un routeur.

d. Configurer les tables de routage et tester la communication entre les deux réseaux.

e. Installer un serveur Web sur un PC et y accéder depuis un autre.

Correction

Cette activité est pratique et se réalise dans Filius. Points clés :

a-b. Les 3 PC sur le même réseau (192.168.1.0/24) communiquent directement via le switch. ping 192.168.1.3 depuis PC1 doit réussir.

c. Le routeur a deux interfaces : une sur chaque réseau (ex : 192.168.1.254 et 192.168.2.254).

d. Sur chaque PC, la passerelle par défaut (gateway) doit pointer vers l'interface du routeur de son réseau : - PC du réseau 1 : passerelle = 192.168.1.254 - PC du réseau 2 : passerelle = 192.168.2.254

e. Installer le logiciel « Serveur Web » sur un PC, le démarrer, puis ouvrir un navigateur sur un autre PC et saisir l'adresse IP du serveur.


🎯 Projet final - Mini-ordinateur virtuel en Python

Objectif

Programmer un simulateur simplifié de processeur en Python qui lit et exécute des instructions assembleur.

Partie A - Structure

a. Créer un dictionnaire registres avec les clés "R0" à "R3" et "IP", toutes initialisées à 0.

b. Créer un tableau memoire de 256 éléments initialisés à 0.

Partie B - Instructions

c. Écrire une fonction executer(instruction) qui traite les instructions suivantes :

  • MOV Rd, #val : place val dans le registre Rd
  • ADD Rd, Rs, #val : Rd = Rs + val
  • ADD Rd, Rs, Rt : Rd = Rs + Rt
  • STR Rd, adr : memoire[adr] = registres[Rd]
  • LDR Rd, adr : registres[Rd] = memoire[adr]
  • HALT : arrête le programme

Partie C - Exécution

d. Écrire une fonction charger_programme(instructions) qui place une liste d'instructions en mémoire et exécute le programme instruction par instruction.

e. Tester avec le programme : MOV R0, #5, MOV R1, #3, ADD R2, R0, R1, STR R2, 100, HALT. Vérifier que memoire[100] vaut 8.

f. Ajouter un affichage de l'état des registres après chaque instruction.

Correction
def creer_processeur():
    registres = {"R0": 0, "R1": 0, "R2": 0, "R3": 0, "IP": 0}
    memoire = [0] * 256
    return registres, memoire

def analyser(instruction):
    parties = instruction.replace(",", "").split()
    return parties

def executer(instruction, registres, memoire):
    p = analyser(instruction)
    op = p[0]

    if op == "HALT":
        return False

    elif op == "MOV":
        rd = p[1]
        if p[2].startswith("#"):
            registres[rd] = int(p[2][1:])
        else:
            registres[rd] = registres[p[2]]

    elif op == "ADD":
        rd = p[1]
        rs = p[2]
        if p[3].startswith("#"):
            registres[rd] = registres[rs] + int(p[3][1:])
        else:
            registres[rd] = registres[rs] + registres[p[3]]

    elif op == "SUB":
        rd = p[1]
        rs = p[2]
        if p[3].startswith("#"):
            registres[rd] = registres[rs] - int(p[3][1:])
        else:
            registres[rd] = registres[rs] - registres[p[3]]

    elif op == "STR":
        rd = p[1]
        adr = int(p[2])
        memoire[adr] = registres[rd]

    elif op == "LDR":
        rd = p[1]
        adr = int(p[2])
        registres[rd] = memoire[adr]

    return True

def afficher_etat(registres):
    for nom, val in registres.items():
        if nom != "IP":
            print(f"  {nom} = {val}", end="")
    print()

def lancer(programme):
    registres, memoire = creer_processeur()
    for instruction in programme:
        print(f"  > {instruction}")
        continuer = executer(instruction, registres, memoire)
        afficher_etat(registres)
        if not continuer:
            break
    print(f"\nmemoire[100] = {memoire[100]}")
    return registres, memoire

# Test
programme = [
    "MOV R0, #5",
    "MOV R1, #3",
    "ADD R2, R0, R1",
    "STR R2, 100",
    "HALT"
]

lancer(programme)
# Résultat attendu : R0=5, R1=3, R2=8, memoire[100]=8