wiki:SoclibCourseTp3

Version 55 (modified by alain, 13 years ago) (diff)

--

TP3 : Processeurs programmables

1 Objectif

L'objectif de ce troisième TP est d'introduire des processeurs programmables dans les architectures modélisées. Pour des raisons de flexibilité et de re-utilisation des plate-formes matérielles, les concepteurs de systèmes intégrés essaient de réaliser le plus grand nombre possible de fonctions en logiciel, en utilisant soit des processeurs GPP (General Purpose Processor), soit des processeurs DSP (Digital Signal Processor).

On utilise des processeurs RISC 32 bits, car ce type de processeur possède un très bon rapport (puissance de calcul) / (consommation énergétique).

On introduit également dans ce TP l'outil de compilation soclib-cc qui facilite la génération du simulateur.

2 Architecture matérielle cible

L'architecture matérielle modélisée dans ce TP comporte un seul processeur initiateur VCI et 4 cibles VCI :

  • xcache est un processeur Mips32 avec ses caches L1. On utilise le composant VciXcacheWrapper, qui est un contrôleur de cache à interface VCI.
  • rom est une mémoire non inscriptible à interface VCI contenant le code de boot. On utilise le composant VciSimpleRam.
  • ram est une mémoire inscriptible à interface VCI contenant le code et les données. On utilise également un composant VciSimpleRam.
  • tty est un périphérique adressable de type écran/clavier à interface VCI. On utilise le composant VciMultiTty.
  • gcd est le coprocesseur cible réalisant le calcul du PGCD déjà utilisé dans le TP2.
  • vgsb est le bus système déjà utilisé dans le TP2.

Les modèles de simulation des composants matériels instanciés dans cette architecture sont disponibles dans la bibliothèque SoCLib. Ils vous sont fournis, et vous n'aurez pas à les re-écrire vous-même.

Le composant VciXcacheWrapper peut être utilisé pour encapsuler différents processeur 32 bits. Le coeur du processeur est modélisé par un ISS (Instruction Set Simulator). Le type du proceseur instancié (MIP32, ARM, SPARCV8, PPC405, NIOS, MicroBlaze, etc.) est défini par un paramètre template du composant VciXcacheWrapper. Consultez la documentation ici.

Le composant VciSimpleRam est utilisé pour modéliser des mémoires inscriptibles embarquées (SRAM). On utilise le même composant pour modéliser des mémoires non inscriptibles (ROM). Ce composants peut contenir un ou plusieurs segments (correspondant à des tranches disjointes de l'espace addressable). Le composant analyse les bits de poids fort de l'adresse VCI pour déterminer le segment désigné. Les bancs de mémoire physique correspondant aux différents segments sont modélisés par des tableaux C++ dont la longueur est définie par les valeurs stockées dans la MappingTable. Consultez la documentation ici.

Enfin le composant VciMultiTty est un contrôleur de terminaux alpha-numériques. Ce composant peut contrôler de 1 à 256 terminaux (un terminal est une paire écran / clavier). Pratiquement, chaque terminal est modélisé par l'ouverture d'une fenêtre XTERM indépendante sur l'écran de la station de travail qui exécute la simulation. Chaque terminal possède 4 registres adressables pour la lecture ou l'écriture, et fonctionne en mode caractère: on ne peut lire ou écrire qu'un seul caractère par transaction. Consultez la documentation ici.

3 Génération et chargement du logiciel embarqué

Il existe plusieurs façons de définir et de générer le code binaire qui sera exécuté par le (ou les) processeur(s) du MPSoC. Si on part d'une application logicielle écrite en langage C, il faut utiliser un cross-compilateur spécifique pour le processeur choisi. Le résultat est un fichier binaire au format ELF. Le code binaire correspondant doit ensuite être chargé dans les mémoires embarquées du MPSoC. Il y a donc deux étapes bien distinctes pour la génération et le chargement.

3.1 Génération du code

Les composants de la bibliothèque SoCLib permettent de modéliser des architectures matérielles complexes, capables d'exécuter des systèmes d'exploitation généralistes (tels que LINUX ou NetBSD), ou des systèmes d'exploitation spécialisés pour MPSoC (tels que MutekH. Mais dans ce TP et les suivants, on se contentera d'un système d'exploitation minimal, constitué par un Gestionnaire d'Interruptions, Exceptions et Trappes (GIET). Cet OS minimal fournit quelques appels systèmes permettant aux programmes utilisateurs d'accéder aux périphériques, il traite les requêtes d'interruption vectorisées, et facilite le debug du logiciel embarqué en signalant les exceptions. Le code du GIET est écrit en C et en assembleur MIPS32.

Les processeurs disponibles dans SoCLib sont principalement des processeurs RISC, capables de démarrer une instruction à chaque cycle, grâce à leur structure pipe-line. Le processeur doit, à chaque instruction (donc à chaque cycle) lire l'instruction dans le cache, la décoder et l'exécuter. En cas de MISS, c'est le contrôleur du cache qui se charge de délencher une transaction VCI pour aller lire le code binaire chargé dans les mémoires embarquées.

Le code binaire doit donc être généré par un cross-compilateur spécifique pour le processeur Mips32. On utilise la chaîne de compilation GCC, pour compiler l'ensemble du logiciel embarqué (code applicatif et code système) et pour réaliser l'édition de liens entre le code applicatif écrit par vous, et le code système. Le résultat de cette compilation est un fichier au format ELF, contenant le code binaire exécutable par le processeur MIP32.

3.2 Chargement du code

Il existe deux méthodes permettant de charger le code binaire dans les mémoires embarquées sur la puce:

  1. Le code peut être stocké dans des mémoires mortes (ROM). Le contenu de ces mémoires est défini lors de la fabrication de la puce, et n'est plus modifiable. Cette approche est évidemment très peu flexible, et elle n'est généralement utilisée que pour le code de boot.
  2. Le code peut être stocké dans des mémoires inscriptibles (SRAM), qui sont chargées lors de la mise sous tension du système à partir d'un périphérique de stockage externe (cela peut être une EPROM externe, une mémoire flash, ou un autre dispositif de stockage. On peut même imaginer qu'on utilise une liaison sans fil pour télécharger du code applicatif disponible sur un serveur distant. Cette approche en deux temps est utilisée pour le code applicatif, mais également pour le système d'exploitation embarqué. C'est pourquoi on appelle souvent bootloader le code de boot qui effectue ce chargement.

La phase de chargement du système d'exploitation et du code applicatif est en pratique exécutée à chaque mise sous tension, ou chaque fois qu'on active le signal NRESET. Elle peut être très longue (plusieurs millions de cycles). Un fois que le bootloader a été validé, cette phase d'initialisation n'apporte plus beaucoup d'information, quand on souhaite mettre au point ou mesurer les performances d'une application logicielle sur une architecture matérielle modélisée avec SoCLib.

La plate-forme SoCLib fournit donc un service permettant d'initialiser directement les mémoires embarquées à partir du code contenu dans le fichier ELF. Cette initialisation n'est plus réalisée lors de l'exécution de la simulation (dans la phase de boot), elle est réalisée avant le démarrage de la simulation. En pratique, ce chargement est réalisé par le constructeur du composant VciSimpleRam, gràce à un argument loader` qui lui permet d'accéder au contenu du fichier ELF contenant le code binaire. Ce constructeur posséde un autre argument lui permettant d'accéder à la MappingTable. Il peut donc déterminer quels segments ont été affectés à la RAM (ou à la la ROM) et lesquels doivent être initialisés.

On économise ainsi plusieurs millions de cycles de simulation, et le code de boot peut être beaucoup plus court (le code de boot utilisé dans ce TP contient moins de 20 lignes d'assembleur).

4 Travail à réaliser

L'archive soclib_tp3.tgz contient différents fichiers dont vous aurez besoin pour ce TP. Créez un répertoire de travail spécifique TP3, recopiez l'archive dans ce répertoire TP3, et décompressez-la:

$ tar xzvf soclib_tp3.tgz

Outre les fichiers qui permettent de générer le simulateur de l'architecture matérielle, cette archive contient également un sous-répertoire soft qui est utilisé pour la génération du logiciel embarqué.

Pour cette architecture, il faut définir 9 segments dans l'espace adressable, dont 7 correspondent à de la mémoire, et 2 correspondent à 2 périphériques adressables :

  • seg_reset est le segment contenant le code de boot exécuté à la mise sous tension. Il est évidemment assigné à la ROM. L'adresse de base 0xBFC00000 est imposée par la spécification du processeur Mips32. On choisira une capacité de stockage de 4 Koctets.
  • seg_kcode est le segment contenant le code du système qui s'exécute en mode kernel. Il s'agit principalement du code du Gestionnaire d'Interruptions, Exceptions, et Trappes (GIET), du code des fonctions système, ainsi que du code des routines d'interruption (ISR, pour interrupt Service Routine). Ce segment est assigné à la RAM. L'adresse de base 0x80000000. On choisira une capacité de stockage de 64 Koctets.
  • seg_kdata est le segment contenant les données cachables du système d'exploitation. Il est assigné à la RAM. L'adresse de base est égale à 0x81000000. Sa capacité esr de 64Koctets.
  • seg_kunc est le segment contenant les données non cachables du système d'exploitation. Il est assigné à la RAM. L'adresse de base est égale à 0x82000000. Sa capacité esr de 64Koctets.
  • seg_code est le segment contenant le code de l'application logicielle embarquée, qui s'exécute en mode user. Il est assigné à la RAM. On choisira pour adresse de base la valeur 0x00400000, et une capacité de stockage de 64 Koctets.
  • seg_data est le segment contenant les données globales et la pile d'exécution de l'application logicielle embarquée. Il est assigné à la RAM. On choisira pour adresse de base la valeur 0x10000000, et une capacité de stockage de 64 Koctets.
  • seg_stack est le segment contenant la pile d'exécution de l'application logicielle embarquée. Il est assigné à la RAM. On choisira pour adresse de base la valeur 0x20000000, et une capacité de stockage de 64 Koctets.
  • seg_tty est le segment associé au contrôleur de terminaux TTY. On prendra pour adresse de base la valeur 0x90000000, et pour longueur 64 octets, ce qui permet d'adresser jusqu'à 4 terminaux indépendants.
  • seg_gcd est le segment associé au coprocesseur GCD. On prendra pour adresse de base la valeur 0x95000000. La longueur de 16 octets correspond aux quatre registres adressables de ce composant.

Remarquez que les 2 segments correspondant aux périphériques (seg_tty et seg_gcd), le segment contenant le code de boot, ainsi que les 3 segments utilisés par le système d'exploitation sont dans la zone protégée de l'espace adressable, qui n'est accessible que lorsque le processeur est en mode kernel (adresses supérieures à 0x80000000).

Les adresses de base sont utilisées à la fois par le matériel et par le logiciel embarqué. Elles doivent donc être définies à deux endroits :

  1. Pour le matériel, les addresses de base et les longueurs des segments doivent être définies dans le fichier tp3_top.cpp pour ëtre stockées dans la MappingTable. Elles sont utilisées dans la phase de configuration du matériel par les constructeurs des composants.
  2. Pour le logiciel, les adresses de base des segments doivent être définies dans le fichier soft/ldscript qui contient les directives pour l'éditeur de liens lors de la compilation du logiciel embarqué.

Par ailleurs le GIET peut supporter des architectures comportant plusieurs processeur, mais les structures de données utilisées par le système doivent être dimensionnées en fonction du nombre de composants matériels disponibles: nombre de processeurs, nombre de terminaux TTY. Ces paramètres doivent donc être définies dans le fichier tp"_top.cpp et dans le fichier soft/ldscript.

4.1 Compilation du logiciel embarqué

Le logiciel embarqué est défini dans deux types de fichiers.

Vous pouvez consulter le code source générique du système d'exploitation dans le répertoire

/users/cao/alain/ue_almo/soft/giet
  • le fichier giet.s est écrit en assembleur et contient le code du Gestionnaire d'Interruption, Exceptions et Trappes. Le GIET est l'unique point d'entrée dans le système d'exploitation. Ce code s'exécute en mode kernel, et se termine toujours par une instruction eret.
  • les fichier stdio.c et stdio.h sont écrits en C, et contiennent le code des appels systèmes permettant à un programme s'exécutant en mode user d'accéder aux périphériques.
  • les fichiers drivers.c et drivers.h sont écrits en C et contiennent le code des fonctions systèmes qui s'exécutent en mode kernel, qui accèdent effectivement aux périphériques ou aux registres protégés du processeur.
  • le fichier isr.s contient le code des routines de traitement des interruptions (Interrupt Service Routine).

Le répertoire soft de l'archive qui vous est fournie contient les fichiers spécifiques à l'application embarquée :

  • le fichier reset.s est écrit en assembleur et contient le code de boot qui est exécuté à la mise sous tension, ou lors de l'activation du signal NRESET. Ce code s'exécute en mode kernel, mais il est spécifique à chaque plate-forme matérielle, car il est chargé d'initialiser les périphériques présents dans l'architecture.
  • le fichier main.c est écrit en C et contient le code de l'application logicielle. IL peut évidemment utiliser les appels système définis dans le fichier stdio.c.
  • le fichier ldscript contient les directives pour l'éditeur de liens, et en particulier les adresses de base des différents segments, ainsi que certains paramètres de la plate-forme matérielle tels que le nombre de processeurs ou de terminaux TTY.
  • le fichier Makefile permet de lancer la génération du logiciel embarqué.

La génération du code binaire embarqué est totalement indépendante de la génération du simulateur de l'architecture matérielle. La chaîne de compilation croisée GCC fournit quatre outils:

  • mipsel-unknown-elf-gcc : compilateur, pour transformer un fichier source C (extension .c) en fichier assembleur pour MIPS32 (extension .s)
  • mipsel-unknown-elf-as : assembleur, pour transformer un fichier assembleur (extension .s) en fichier binaire objet (extension .o)
  • mipsel-unknown-elf-ld : éditeur de lien, pour résoudre les références croisées entre les fichiers objets et produire le fichier binaire exécutable
  • mipsel-unknown-elf-objdump : désassembleur, pour générer un fichier texte lisible à partir d'un fichier binaire.

Assurez-vous que votre PATH contient bien le chemin permettant d'accéder à ces 4 outils en exécutant la commande :

$ source /users/outil/soc/env_soclib.sh

Question : Editez le fichier reset.s, de façon à définir la taille du segment de pile. On choisira une taille de 64 Koctets. Quelles sont les autres initialisations réalisées par le code de boot ?

On rappelle que l'instruction eret de sortie du GIET modifie le registre protégé SR (registre 12 du coprocesseur système) pour que le processeur retourne dans le mode user et effectue un branchement à l'adresse contenue dans le registre protégé EPC (registre 14 du coprocesseur système).

Question : Ouvrez le fichier main.c. Que fait ce programme ? (La fonction tty_getc() est bloquante, et ne rend pas la main tant qu'un caractère n'a pas été saisi au clavier).

Question : Editez le fichier stdio.c contenu dans le répertoire /users/cao/alain/ue_almo/soft/giet. Quels sont les appels système qui permettent d'accéder à un terminal TTY ? Que trouve-t-on dans le code de ces appels système?

Question : Complétez le fichier ldscript pour définir les adresses de base des différents segments, ainsi que les paramètres NB_PROCS et NB_TTYS.

Lancez l'exécution du Makefile dans le répertoire soft. Deux fichiers bin.soft et bin.soft.txt doivent être créés : Le fichier bin.soft contient le code binaire au format ELF, et le fichier bin.soft.txt contient un version desassemblée (donc lisible) de ce code binaire.

Question : Editez le fichier bin.soft.txt. Combien d'instructions assembleur ont été générées pour le programme main? Dans quelle section est rangée la chaîne de caractère Hello world '' ?

4.2 Description de l'architecture matérielle

Pour ce qui concerne le matériel, faut commencer par compléter le fichier tp3_top.cpp qui vous est fourni:

  • Il faut enregister les 9 segments dans la MappingTable. Consultez la documentation de la MappingTable pour bien comprendre la signification des 4 arguments du constructeur de la MappingTable, ainsi que la signification des 5 arguments du constructeur d'un segment.
  • Il faut définir les arguments des constructeurs des composants matériels instanciés, ainsi que les valeurs de leurs paramètres template. Vous devez consulter la documentation des composants VciXcacheWrapper et VciSimpleRam pour comprendre la signification des arguments. On choisira des caches à correspondance directe (c'est à dire un seul niveau d'associativité), ayant une capacité totale de 4 Koctets et des lignes de caches d'une longueur de 16 octets.
  • Il faut définir l'argument du composant loader qui réalise le chargement du code binaire dans les mémoires ROM et RAM. Cet argument est une chaîne de caractères définissant le cheminom d'accès au fichier bin.soft.
  • Il faut enfin compléter la net-list en connectant les signaux du bus.

Question : Parmi les 9 segments utilisés dans cette l'architecture, lesquels doivent être non-cachables ?

Question : Quel est le nombre de bits de poids fort de l'adresse qui doivent être décodés par le contrôleur du bus pour déterminer la cible VCI désignée ? Cette information est un des arguments du constructeur de la MappingTable.

Question quels sont les bits d'adresse qui doivent être décodés par le contrôleur du cache, pour déterminer qu'une adresse appartient à un segment non-cachable, et doit être directement transmise à la mémoire ? Cette information est un autre argument du constructeur de la MappingTable?.

4.3 Génération du simulateur

Les composants matériels modélisées dans les TP1 et TP2 étaient très simples. Vous avez pu décrire vous-même les modèles de simulation de ces composants, et vous avez pu écrire à la main le Makefile permettant d'enchaîner la compilation des modules avant de compiler la top-cell.

Mais les composants instanciés ici (VciXcacheWrapper, VciSimpleRam, et VciMultiTty) sont des objets nettement plus complexes, qui utilisent eux-même un gransd nombre d'autres composants. Tous les fichiers sont accessibles sur le serveur SVN de SoCLib, qui fournit un service de gestion de versions et supporte le développement coopératif de la plate-forme.

Cependant l'exploitation de cette bibliothèque de modèles de simulation pose (au moins) deux problèmes :

  1. Il faut identifier et localiser tous les fichiers nécessaires pour générer le simulateur d'une architecture particulière. L' architecture très simple proposée ici nécessite la compilation d'une centaine de fichiers. D'une façon générale, l'identification des fichiers nécessaires à la compilation est un travail non négligeable,

et la construction du Makefile peut devenir assez pénible.

  1. Par ailleurs, la plupart des modèles ont des paramètres templates (puisque la plupart des composants ont des interfaces VCI, et que les largeurs des champs VCI sont définis par un paramètre template.

Pour chaque composant possédant un paramètre) template, il faut modifier le fichier .cpp pour préciser la valeur des paramètres template avant de lancer la compilation de ce composant (on dit qu'on instancie les template). Vous avez fait ce travail dans le TP2, et c'est un travail fastidieux dès que les architectures deviennent complexes.

La chaîne de compilation soclib-cc a pour but de résoudre ces deux problèmes dans le cas général, en automatisant la recherche des dépendances, l'instanciation des templates, et l'appel du compilateur. Pour permettre cette automatisation, tout composant logiciel de SoCLib est accompagné d'un fichier de metadata (fichier possédant le suffixe .sd) qui contient les informations suivantes:

  • le nom de la classe C++
  • les paramètres templates associés, avec leurs types et les valeurs par défaut (si applicable)
  • les chemins d'accès aux fichiers d'en-tête (.h) et d'implémentation (.cpp)
  • la liste des ports d'interface du composant
  • la liste des dépendances vers d'autres composants
  • les paramètres du constructeur, avec leurs types

Ce fichier est écrit en un langage ad-hoc (mais que Python peut parser nativement), et on trouvera ci-dessous, à titre d'exemple, le fichier vci_simple_ram.sd:

	
Module('caba:vci_simple_ram',
        classname = 'soclib::caba::VciSimpleRam',
	tmpl_parameters = [parameter.Module('vci_param',  default = 'caba:vci_param')],
        header_files = ['../source/include/vci_simple_ram.h',],
        implementation_files = ['../source/src/vci_simple_ram.cpp'],
        ports = [
	          Port('caba:vci_target', 'p_vci'),
                  Port('caba:bit_in', 'p_resetn', auto = 'resetn')      
                  Port('caba:clock_in', 'p_clk', auto = 'clock')
                  ],
        uses = [
                  Uses('caba:base_module'),
	          Uses('common:linked_access_buffer',
                             addr_t = parameter.StringExt('sc_dt::sc_uint<%d>', parameter.Reference('addr_size')),
                             id_t = parameter.StringExt('sc_dt::sc_uint<%d>', parameter.Reference('srcid_size'))),
                  Uses('common:loader'),
                  Uses('common:mapping_table',
                  ],
        instance_parameters = [
                  parameter.IntTab('ident'),
                  parameter.Module('mt', 'common:mapping_table', auto='env:mapping_table'),
                  parameter.Module('loader', 'common:loader', auto='env:loader'),
                  parameter.Int('latency')
                  ],
        extensions = [
                  'dsx:addressable=ident',
                  'dsx:get_ident=ident:p_vci',
                  'dsx:mapping_type=memory'],
)

Il faut par ailleurs définir les caractéristiques de la top-cell dans un fichier de directives pour soclib-cc. Ce fichier est habituellement suffixé par .desc, mais le nom n'est pas imposé. Ce fichier est également en langage parsable par Python, et contient : le nom de fichier de la top-cell SystemC, la liste des modèles des composants instanciés et les valeurs des paramètres template VCI. Vous trouverez ci-dessous, à titre d'exemple, le fichier tp3_top.desc décrivant l'architecture du TP3:

todo = Platform('caba', 'tp3_top.cpp',
            uses = [
                    Uses('caba:vci_xcache_wrapper', iss_t = 'common:mips32el'),
                    Uses('caba:vci_simple_ram'),
                    Uses('caba:vci_multi_tty'),
                    Uses('caba:vci_vgsb'),
                    Uses('caba:vci_gcd_coprocessor'),
                    Uses('common:mapping_table'),
                    Uses('common:elf_file_loader')],
            cell_size = 4,
            plen_size = 8,
            addr_size = 32,
            rerror_size = 1,
            clen_size = 1,
            rflag_size = 1,
            srcid_size = 12,
            pktid_size = 1,
            trdid_size = 1,
            wrplen_size = 1
)

Complétez le fichier tp3_top.cpp qui vous est fourni, puis lancez la compilation avec la commande:

$ soclib-cc -p tp3_top.desc -o simulator.x

L'exécutable simulator.x devrait être créé dans le répertoire de travail TP3.

4.4 Simulation

Lancez la simulation avec la commande :

$ ./simulator.x

En cas de problème lors de l'éxécution, vous pouvez relancer le simulateur en activant le mode DEBUG. Il faut ajouter les deux arguments suivants sur la ligne de commande

$ ./simulator.x -DEBUG 0 -NCYCLES 10000

Vous obtiendrez une trace d'exécution entre les cycles 0 et 10000, que vous pouvez rediriger vers un fichier.

Pour attirer votre attention sur des erreurs fréquentes, faites les essais suivants :

  1. Modifiez l'adresse de base du segment seg_gcd pour lui donner la valeur 0xB0000000 au lieu de 0x9000000. Relancez la compilation et la simulation. Expliquez les résultats obtenus.
  2. Déclarez les segments correspondant aux périphériques (seg_tty et seg_gcd) comme cachables. Relancez la compilation et la simulation. Expliquez les résultats obtenus.

4.5 Modification du logiciel embarqué

Puisque le logiciel embarqué est chargé dynamiquement dans la RAM et dans la ROM lors du lancement du simulateur, il est possible de modifier le logiciel embarqué (fichier bin.soft), sans modifier l'architecture matérielle et donc sans regénérer le fichier simulator.x.

On va donc maintenant écrire une application logicielle un peu plus complexe, qui utilise le coprocesseur GCD, simplement en modifiant le fichier main.c dans le répertoire soft, et en relançant la compilation et la génération du fichier bin.soft.

Modifiez le fichier main.c, pour que les programme C exécute une boucle infinie dans laquelle on effectue successivement les opérations suivantes :

  1. affichage du numéro de cycle et du numéro d'itération.
  2. génération aléatoire de deux variables OPA et OPB de type int.
  3. écriture de OPA dans le registre GCD_OPA du coprocesseur GCD.
  4. écriture de OPB dans le registre GCD_OPB du coprocesseur GCD.
  5. écriture dans le pseudo-registre GCD_START, pour démarrer le coprocesseur GCD.
  6. lecture du registre GCD_STATUS du coprocesseur GCD pour tester la fin du calcul.
  7. affichage du numéro d'itération, du numéro de cycle, des valeurs des opérandes et du résultat sur le TTY.

Pour afficher sur le terminal, on utilisera évidemment la fonction tty_printf(). Pour obtenir le numéro de cycle, on utilisera la fonction proctime(). Pour la génération aléatoire, on utilisera la fonction rand(). Pour les accès au coprocesseur GCD on utilisera les fonctions spécifiques au coprocesseur GCD.

Pour introduire un peu d'interactivité dans cet exercice, vous pouvez introduire dans la boucle un appel à la fonction tty_getc() qui lit un caractère au clavier, et bloque l'exécution du programme tant que le caractère n'est pas saisi. Le code de ces fonctions est défini dans le fichier stdio.c, et les prototypes sont définis dans le fichier stdio.h.

5 Compte-rendu

Il ne vous est pas demandé de compte-rendu pour ce TP, mais on vous demandera une démonstration de votre simulateur au début du TP de la semaine suivante...

Attachments (2)

Download all attachments as: .zip