Changes between Version 104 and Version 105 of Archi-1-TP9


Ignore:
Timestamp:
Dec 11, 2020, 11:37:03 AM (4 years ago)
Author:
meunier
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP9

    v104 v105  
    7979'''''''''''''''
    8080* L'espace d'adressage du MIPS est l'ensemble des adresses que peut former le MIPS.
    81 * Les adresses sont sur 32 bits qui désignent chacune un octet, il y a donc 2^32^ octets.
     81* Les adresses sont sur 32 bits et désignent chacune un octet, il y a donc 2^32^ octets.
    8282* On accède à l'espace d'adressage avec les instructions load/store (`lw`, `lh`, `lb`, `lhu`, `lbu`, `sw`, `sh`, `sb`).
    8383* Non, les mémoires sont des composants contenant des cases de mémoire adressable. Les mémoires sont placées (on dit aussi « ''mappées'' » dans l'espace d'adressage).
     
    107107'''''''''''''''
    108108}}}
    109 1. Le contrôleur de `TTY` peut contrôler de 1 à 4 terminaux. Chaque terminal dispose d'un ensemble de 4 registres (on appelle ça une carte de registres, ou en anglais une ``register map``). Ces ensembles de 4 registres sont placés à des adresses contiguës. S'il y a 2 terminaux (`TTY0` et `TTY1`), A quelle adresse est le registre `TTY_READ` de `TTY1` ?
     1091. Le contrôleur de `TTY` peut contrôler de 1 à 4 terminaux. Chaque terminal dispose d'un ensemble de 4 registres (on appelle ça une carte de registres, ou en anglais une ``register map``). Ces ensembles de 4 registres sont placés à des adresses contiguës. S'il y a 2 terminaux (`TTY0` et `TTY1`), à quelle adresse est le registre `TTY_READ` de `TTY1` ?
    110110{{{#!protected ------------------------------------------------------------------------------------
    111111'''''''''''''''
     
    136136ori   $4, $4, 0x0000   // cette instruction ne sert a rien puisqu on ajoute 0, mais je la mets pour le cas general
    137137ori   $5, $0, 'x'
    138 sb    $5, 0($4)         // Notez que l'immédiat 0 devant ($4) n est pas obligatoire mais on s'obligera à le mettre
     138sb    $5, 0($4)        // Notez que l'immédiat 0 devant ($4) n est pas obligatoire mais on s'obligera à le mettre
    139139}}}
    140140'''''''''''''''
     
    158158la    $4, __tty_regs_map
    159159li    $5, 'x'
    160 sb    $5, ($4)
    161 }}}
    162 '''''''''''''''
    163 }}}
    164 1. En assembleur pour sauter à une adresse de manière inconditionnelle, on utilise les instructions `j label` et `jr $r`. Ces instructions permettent dd'effeectuer un saut à n'importe quelle adresse ?
     160sb    $5, 0($4)
     161}}}
     162'''''''''''''''
     163}}}
     1641. En assembleur pour sauter à une adresse de manière inconditionnelle, on utilise les instructions `j label` et `jr $r`. Ces instructions permettent-elles d'effectuer un saut à n'importe quelle adresse ?
    165165{{{#!protected ------------------------------------------------------------------------------------
    166166'''''''''''''''
    167167*
    168   - `j label` malgré sa forme assembleur effectue un saut relativement au `PC` puisque le `label` n'est pas entièrement encodé dans l'instruction binaire (cf. cours sur les sauts). Cette instruction réalise : `PC ← PC&0xF0000000 + (label<<2)&0x0FFFFFFF)`. Les 4 bits de poids forts du `PC` sont conservés, le saut est bien relatif au PC.
     168  - `j label` malgré sa forme assembleur effectue un saut relativement au `PC` puisque le `label` n'est pas entièrement encodé dans l'instruction binaire (cf. cours sur les sauts). Cette instruction réalise : `PC ← (PC & 0xF0000000) | (ZeroExtend(label, 32) << 2)`. Les 4 bits de poids forts du `PC` sont conservés, le saut est bien relatif au PC.
    169169  - A l'inverse, `jr $r` effectue un saut absolu puisque cette instruction réalise `PC ← $r`
    170170 Autrement dit, si l’on veut aller exécuter du code n'importe où en mémoire, il faut utiliser `jr`.
     
    179179{{{#!asm
    180180 .section .mytext,"ax"
    181  add $4,$5,$6
     181 addu $4,$5,$6
    182182}}}
    183183'''''''''''''''
     
    200200
    201201print:
    202     lb      $8, 0($4)                    // get current char
    203     sb      $8, 0($5)                    // send the current char to the tty
    204     addiu   $4, $4, 1                    // point to the next char
    205     bne     $8, $0, print                // check that it is not null, if ok it must be printed
     202    lb      $8, 0($4)                   // get current char
     203    sb      $8, 0($5)                   // send the current char to the tty
     204    addiu   $4, $4, 1                   // point to the next char
     205    bne     $8, $0, print               // check that it is not null, if ok it must be printed
    206206}}}
    207207'''''''''''''''
    208208}}}
    209 1. En regardant, le dessin de l'espace d'adressage du prototype **almo1**, à quelle adresse devra être initialisé le pointeur de pile pour le kernel. Rappelez pourquoi c'est indispensable de le définir avant d'appeler une fonction C et écrivez le code qui fait l'initialisation, en supposant que l'adresse du pointeur de pile vaut celle que représente le nom `__kdata_end`
     2091. En regardant le dessin de l'espace d'adressage du prototype **almo1**, dites à quelle adresse devra être initialisé le pointeur de pile pour le kernel. Rappelez pourquoi c'est indispensable de le définir avant d'appeler une fonction C et écrivez le code qui fait l'initialisation, en supposant que l'adresse du pointeur de pile vaut celle que représente le nom `__kdata_end`
    210210{{{#!protected ------------------------------------------------------------------------------------
    211211'''''''''''''''
     
    236236{{{#!protected ------------------------------------------------------------------------------------
    237237'''''''''''''''
    238 * Les déclarations `extern` permettent d'informer que le compilateur qu'une variable ou qu'une fonction existe et est définie ailleurs. Le compilateur connaît ainsi le type de la variable ou du prototype des fonctions, il sait donc comment les utiliser. En C, par défaut, les variables et les fonctions ddoivent être déclarées / leur existence et type doit être connus avant leur utilisation.
     238* Les déclarations `extern` permettent d'informer que le compilateur qu'une variable ou qu'une fonction existe et est définie ailleurs. Le compilateur connaît ainsi le type de la variable ou du prototype des fonctions, il sait donc comment les utiliser. En C, par défaut, les variables et les fonctions doivent être déclarées / leur existence et type doit être connus avant leur utilisation.
    239239* Il n'y a pas de déclaration `extern` en assembleur parce que ce n'est pas un langage typé. Pour l'assembleur, un label c'est juste une adresse donc un nombre.
    240240'''''''''''''''
    241241}}}
    242 1. Comment déclarer un tableau de structures en variable globale ? La structure est nommée `test_s`, elle a deux champs `int` nommés `a` et `b`. Le tableau est nommé `tab` a 2 cases.
     2421. Comment déclarer un tableau de structures en variable globale ? La structure est nommée `test_s`, elle a deux champs `int` nommés `a` et `b`. Le tableau est nommé `tab` et a 2 cases.
    243243{{{#!protected ------------------------------------------------------------------------------------
    244244'''''''''''''''
     
    327327  - Appel de l'éditeur de lien pour produire l'exécutable `bin.x` en assemblant tous les fichiers objets `.o`, en les plaçant dans l'espace d'adressage et résolvant les liens entre eux (quand un `.o` utilise une fonction ou une variable définie dans un autre `.o`).
    328328* `objdump -D file.o > file.o.s` ou `objdump -D bin.x > bin.x.s`
    329   - Appel du désassembleur prend les fichiers binaires (`.o` ou `.x`) pour retrouver le code produit par le compilateur à des fins de debug ou de curiosité.
     329  - Appel du désassembleur qui prend les fichiers binaires (`.o` ou `.x`) pour retrouver le code produit par le compilateur à des fins de debug ou de curiosité.
    330330
    331331**Questions**
     
    358358}}}
    359359
    360 1. Le fichier commence par la déclaration des variables donnant des informations sur les adresses et les tailles des régions de mémoire. Ces symboles n'ont pas de type et ils sont visibles de tous les programmes C, il faut juste leur donner un type pour que le compilateur puisse les exploiter, c'est ce que nous avons fait pour `extern volatile struct tty_s __tty_regs_map[NTTYS]`. En regardant, dans le dessin de la représentation de l'espace d'adressage, complétez les lignes de déclaration des variables pour la région `kdata_region`
     3601. Le fichier commence par la déclaration des variables donnant des informations sur les adresses et les tailles des régions de mémoire. Ces symboles n'ont pas de type et ils sont visibles de tous les programmes C, il faut juste leur donner un type pour que le compilateur puisse les exploiter, c'est ce que nous avons fait pour `extern volatile struct tty_s __tty_regs_map[NTTYS]`. En regardant dans le dessin de la représentation de l'espace d'adressage, complétez les lignes de déclaration des variables pour la région `kdata_region`
    361361{{{#!protected ------------------------------------------------------------------------------------
    362362'''''''''''''''
     
    367367'''''''''''''''
    368368}}}
    369 1. Le fichier contient ensuite la déclaration des régions (dans `MEMORY{...}`) qui vont être remplies par les sections trouvées dans les fichiers objets.  Comment modifiez cette partie (la zone `[... question 2 ...]`) pour ajouter les lignes correspondant à la déclaration de la région `kdata_region` ?
     3691. Le fichier contient ensuite la déclaration des régions (dans `MEMORY{...}`) qui vont être remplies par les sections trouvées dans les fichiers objets.  Comment modifier cette partie (la zone `[... question 2 ...]`) pour ajouter les lignes correspondant à la déclaration de la région `kdata_region` ?
    370370{{{#!protected ------------------------------------------------------------------------------------
    371371'''''''''''''''
     
    386386}}}
    387387 
    388 Nous allons systématiquement utiliser des Makefiles pour la compilation du code, mais aussi pour lancer le simulateur du prototype **almo1**. Pour cette première séance, les Makefiles ne permettent pas de faire des recompilations partielles de fichiers. Les Makefiles sont utilisés pour agréger toutes les actions que nous voulons faire sur les fichiers, c'est-à-dire : compiler, exécuter avec ou sans trace, nettoyer le répertoire. Nous avons recopiez partiellement le premier Makefile pour montrer sa forme et poser quelques questions, auxquels vous savez certainement répondre.
     388Nous allons systématiquement utiliser des Makefiles pour la compilation du code, mais aussi pour lancer le simulateur du prototype **almo1**. Pour cette première séance, les Makefiles ne permettent pas de faire des recompilations partielles de fichiers. Les Makefiles sont utilisés pour agréger toutes les actions que nous voulons faire sur les fichiers, c'est-à-dire : compiler, exécuter avec ou sans trace, nettoyer le répertoire. Nous avons recopié partiellement le premier Makefile pour montrer sa forme et poser quelques questions, auxquels vous savez certainement répondre.
    389389{{{#!make
    390390# Tools and parameters definitions
     
    441441'''''''''''''''
    442442* La variable `CFLAGS` est utilisée par `gcc`, il y a ici toutes les options indispensables pour compiler mais il en existe beaucoup, ce qui fait des tonnes de combinaison d'options !
    443 * `-DNTTYS=$(NTTY)` permet de définir et donner une valeur à une macro (ici définition `NTTYS` avec la valeur `$(NNTY)` comme le fait un `#define` dans un fichierC . Cette commande éviter donc d'ouvrir les codes pour les changer.
     443* `-DNTTYS=$(NTTY)` permet de définir et donner une valeur à une macro (ici définition `NTTYS` avec la valeur `$(NNTY)` comme le fait un `#define` dans un fichier C. Cette commande éviter donc d'ouvrir les codes pour les changer.
    444444'''''''''''''''
    445445}}}