Changes between Version 154 and Version 155 of Archi-1-TP9


Ignore:
Timestamp:
Nov 21, 2021, 11:59:04 AM (3 years ago)
Author:
franck
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP9

    v154 v155  
    143143{{{#!protected ------------------------------------------------------------------------------------
    144144''
    145 Cours 9 / slide 10
    146 
     145Cours 9 / slide 10\\\\
    147146Ce qu'il faut bien comprendre, c'est que l'adresse du registre TTY_WRITE est l'adresse d'une __sortie du SoC__, ce n'est pas une mémoire à proprement parler. Il est d'ailleurs interdit de lire à cette adresse. Pour écrire un message à l'écran, il faut écrire tous les caractères du message à cette adresse (0xD0200000). En principe, entre chaque écriture, il faut attendre un peu que le caractère précédent soit parti, parce que le débit du port de sortie matériel (USB par exemple) est beaucoup plus lent que ce que peut faire le processeur. Dans notre cas, c'est un simulateur de SoC et les caractères sont envoyés vers un terminal sans délai. Dans ce cas, il n'est pas nécessaire d'attendre.
    148147{{{#!asm
     
    169168{{{#!protected ------------------------------------------------------------------------------------
    170169''
    171 Cours 9 / slide 19
    172 
     170Cours 9 / slide 19\\\\
    173171Il suffit de remplacer les instructions `lui` et `ori` par `la` et `li`.
    174172{{{#!asm
     
    195193{{{#!protected ------------------------------------------------------------------------------------
    196194''
    197 Cours 9 / slide 19
    198 
     195Cours 9 / slide 19\\\\
    199196Pour répondre, il faut avoir compris l'explication donnée dans la question. L'intérêt de cette question est de revenir sur la notion de section. Une section est un segment d'adresses ayant un but spécifique. On définit des segments d'adresses pour le code, pour les données (il y a d'ailleurs plusieurs types de sections en fonction du type de données). Ces segments sont placés dans l'espace d'adressage par l'éditeur de liens (`ld`) et la manière dont ils sont placés est définie dans un fichier donné en paramètre de l'éditeur de lien, ce fichier de description de placement est le `ldscript`).
    200197{{{#!as
     
    207204{{{#!protected ------------------------------------------------------------------------------------
    208205''
    209 Cours 9 / slide 19
    210 
     206Cours 9 / slide 19\\\\
    211207Ce qu'il faut comprendre, c'est que les comportements du `C` et de l'assembleur sont inversés vis-à-vis des labels. Dans un fichier `.c`, quand on définit un label (une fonction ou variable), ce label est par défaut `extern`, c'est-à-dire qu'il est utilisable dans un autre fichier `.c`. Si on veut que le label ne soit utilisable que dans le fichier dans lequel il est défini, il faut utiliser le mot clé `static` lors de sa déclaration. En assembleur, c'est l'inverse, les labels sont par défaut `static`, c'est-à-dire utilisable uniquement dans le fichier où ils sont définis. Si on veut qu'ils soient utilisables dans les autres fichiers, il faut le dire avec la directive `.globl`.
    212208* `globl` signifie `glob`al `l`abel. Cette directive permet de dire que le `label` est visible en dehors de son fichier de définition. Ainsi il est utilisable dans les autres fichiers assembleur ou les autres fichier C du programme.
     
    285281{{{#!protected ------------------------------------------------------------------------------------
    286282''
    287 Cours 9 / slides 18 et 58
    288 
     283Cours 9 / slides 18 et 58\\\\
    289284Ce sont toujours des connaissances connues en principe, mais comme c'est utilisé dans le code, ce n'est pas inutile d'en parler rapidement.
    290285* Avec `#include "file.h"`, le préprocesseur recherche le fichier dans le répertoire local.
     
    296291{{{#!protected ------------------------------------------------------------------------------------
    297292''
    298 Cours 9 / slides 9 et 58
    299 
     293Cours 9 / slides 9 et 58\\\\
    300294Cette déclaration est présente à plusieurs endroits dans le code. Elle permet de définir des valeurs de paramètres par défaut, s'ils ne sont pas déjà définis ailleurs, soit plus haut dans le code, ou dans un fichier inclu, ou encore passé en paramètre du compilateur par l'option `-D`.
    301295* En utilisant, une directive `#ifndef` :
     
    310304{{{#!protected ------------------------------------------------------------------------------------
    311305''
    312 Cours 9 / slides 9 et 58
    313 
     306Cours 9 / slides 9 et 58\\\\
    314307C'est un usage de ce qui a été vu dans la question précédente. C'est utilisé dans tous les fichiers .h (sauf oubli).
    315308* En utilisant ce que nous venons de voir dans la question précédente : on peut définir une macro instruction différente au début de chaque fichier `.h` (en utilisant le nom du fichier comme nom de macro pour éviter les collisions de nom). On peut alors tester l'existence de cette macro comme condition d'inclusion du fichier.
     
    338331{{{#!protected ------------------------------------------------------------------------------------
    339332''
    340 Cours 9 / slide 10
    341 
     333Cours 9 / slide 10\\\\
    342334En principe, cela ne devrait pas poser de difficulté, mais cela nécessite d'avoir compris comment fonctionne le TTY et de savoir écrire une fonction en C. Pour aider, au cas où, on peut donner la description de ce qui est attendu:\\Tant que le registre `status` est à 0 alors attendre, puis lire le registre `read`.\\Notez que cela nécessite de savoir accéder aux champs d'une structure.
    343335{{{#!c
     
    3523441. Savez-vous à quoi sert le mot clé `volatile` ? Nous n'en avons pas parlé en cours, mais c'est nécessaire pour les adresses des registres de périphérique, une idée ... ?
    353345{{{#!protected ------------------------------------------------------------------------------------
    354 '''''''''''''''
     346''
     347Ce n'est pas dit dans le cours, mais c'est un concept important. Quand le programme doit aller chercher une donnée dans la mémoire puis faire plusieurs calculs dessus, le compilateur optimise en réservant un registre du processeur pour cette variable afin de ne pas être obligé d'aller lire la mémoire à chaque fois. Mais, il y a des cas où ce comportement n'est pas souhaitable (il est même interdit). C'est le cas pour les données qui se trouvent dans les registres de périphériques. Ces données peuvent être changées par le périphérique sans que le processeur le sache, de sorte qu'une valeur lue par le processeur à l'instant `t` n'est plus la même (dans le registre du périphérique) à l'instant `t+1`. Le compilateur ne doit pas optimiser, il doit aller chercher la donnée en mémoire à chaque fois que le programme le demande.
    355348* `volatile` permet de dire à `gcc` que la variable en mémoire peut changer à tout moment, elle est volatile. Ainsi quand le programme demande de lire une variable `volatile` le compilateur doit toujours aller la lire en mémoire. Il ne doit jamais chercher à optimiser en utilisant un registre afin de réduire le nombre de lecture mémoire (load). De même, quand le programme écrit dans une variable `volatile`, cela doit toujours provoquer une écriture dans la mémoire (store).
    356349* Ainsi, les registres de périphériques doivent toujours être impérativement lus ou écrits à chaque fois que le programme le demande, parce que c'est justement ces lectures et ces écritures qui commandent le périphérique.
    357 '''''''''''''''
     350''
    358351}}}
    359352