Changes between Version 154 and Version 155 of Archi-1-TP9
- Timestamp:
- Nov 21, 2021, 11:59:04 AM (3 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Archi-1-TP9
v154 v155 143 143 {{{#!protected ------------------------------------------------------------------------------------ 144 144 '' 145 Cours 9 / slide 10 146 145 Cours 9 / slide 10\\\\ 147 146 Ce 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. 148 147 {{{#!asm … … 169 168 {{{#!protected ------------------------------------------------------------------------------------ 170 169 '' 171 Cours 9 / slide 19 172 170 Cours 9 / slide 19\\\\ 173 171 Il suffit de remplacer les instructions `lui` et `ori` par `la` et `li`. 174 172 {{{#!asm … … 195 193 {{{#!protected ------------------------------------------------------------------------------------ 196 194 '' 197 Cours 9 / slide 19 198 195 Cours 9 / slide 19\\\\ 199 196 Pour 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`). 200 197 {{{#!as … … 207 204 {{{#!protected ------------------------------------------------------------------------------------ 208 205 '' 209 Cours 9 / slide 19 210 206 Cours 9 / slide 19\\\\ 211 207 Ce 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`. 212 208 * `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. … … 285 281 {{{#!protected ------------------------------------------------------------------------------------ 286 282 '' 287 Cours 9 / slides 18 et 58 288 283 Cours 9 / slides 18 et 58\\\\ 289 284 Ce sont toujours des connaissances connues en principe, mais comme c'est utilisé dans le code, ce n'est pas inutile d'en parler rapidement. 290 285 * Avec `#include "file.h"`, le préprocesseur recherche le fichier dans le répertoire local. … … 296 291 {{{#!protected ------------------------------------------------------------------------------------ 297 292 '' 298 Cours 9 / slides 9 et 58 299 293 Cours 9 / slides 9 et 58\\\\ 300 294 Cette 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`. 301 295 * En utilisant, une directive `#ifndef` : … … 310 304 {{{#!protected ------------------------------------------------------------------------------------ 311 305 '' 312 Cours 9 / slides 9 et 58 313 306 Cours 9 / slides 9 et 58\\\\ 314 307 C'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). 315 308 * 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. … … 338 331 {{{#!protected ------------------------------------------------------------------------------------ 339 332 '' 340 Cours 9 / slide 10 341 333 Cours 9 / slide 10\\\\ 342 334 En 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. 343 335 {{{#!c … … 352 344 1. 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 ... ? 353 345 {{{#!protected ------------------------------------------------------------------------------------ 354 ''''''''''''''' 346 '' 347 Ce 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. 355 348 * `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). 356 349 * 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 '' 358 351 }}} 359 352