| | 60 | |
| | 61 | Il existe deux méthode méthodes permettant de charger le code binaire dans les mémoires embarquées sur la puce: |
| | 62 | * Le code peut être stocké dans des mémoires mortes (ROM). le contenu de ces mémoires est défini lors de la fabrication |
| | 63 | 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 |
| | 64 | que pour le code de boot. |
| | 65 | * Le code est stocké dans des mémoires inscriptibles (SRAM), qui sont chargées lors de la mise sous tension du système |
| | 66 | à partir d'un périphérique de stockage externe (cela peut être une ROM externe, une mémoire flash, ou un autre dispositif de |
| | 67 | stockage. On peut même imaginer qu'on utilise une liaison sans fil pour télécharger du code applicatif disponible |
| | 68 | sur un serveur distant. Cette approache est généralement utilisée pour le code applicatif, mais également |
| | 69 | pour le système d'exploitation embarqué. Le code qui exécute ce chargement de code s'appelle un ''bootloader''. |
| | 70 | |
| | 71 | La phase de chargement du code applicatif et du système d'exploitation est exécutée à chaque mise sous tension. Elle peut être |
| | 72 | très longue (plusieurs millions de cycles). Un fois que le ''bootloader'' a été validé cette phase de chargement n'apporte plus beaucoup |
| | 73 | d'information, quand on souhaite mettre au point une application logicielle sur une architecture matérielle modélisée avec SoCLib. |
| | 74 | |
| | 75 | La plate-forme SoCLib fournit donc un service permettant d'initialiser directement les mémoires embarquées à partir du code contenu |
| | 76 | 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 |
| | 77 | est réalisée avant le démarrage de la simulation par le constructeur des composants modélisant des mémoires embarquées |
| | 78 | (ROM ou RAM). Le constructeur du composant ''!VciSimpleRam'' possède un argument ''loader'' qui lui permet d'accéder au |
| | 79 | contenu du fichier ELF contenant le code binaire. Le constructeur possédant un autre argument lui permettant d'accéder |
| | 80 | à la MappingTable, il peut déterminer quels segments de la RAM (ou de la ROM) doivent être initialisés. |
| 125 | | Il faut compléter le fichier ''tp3_mono_top.cpp'', pour définir la segmentation |
| 126 | | de l'espace adressable, définir les arguments des constructeurs et les valeurs des |
| 127 | | paramètres template des différents composants matériels instanciés. |
| 128 | | |
| 129 | | Cette architecture nécessite la définition de 6 segments: |
| 130 | | * '''seg_lcd''' est le segment associé au coprocesseur LCD. On prendra pour adresse de base la valeur 0xD0000000. La longueur de 16 octets correspond aux quatre registres adressables de ce composant. |
| 131 | | * '''seg_tty''' est le segment associé au contrôleur de terinaux TTY. On prendra pour adresse de base la valeur 0xC0000000, et pour longueur 64 octets, ce qui permet d'adresser jusqu'à 4 terminaux indépendants (consulter la spécification fonctionnelle du composant VciMultiTty). |
| 132 | | * '''seg_reset''' est le segment contenant contient 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 4Koctets. |
| 133 | | * '''seg_giet''' est le segment contenant le code du Gestionnaire d'Interruptions, Exceptions, et Trappes (GIET). Il est assigné à la RAM. L'adresse de base 0x80000000 est imposée par la spécification du processeur MIPS32. On choisira une capacité de stockage de 4 Koctets. |
| 134 | | * '''seg_code''' est le segment contenant le code de l'application logicielle embarquée. Il est assigné à la RAM. On choisira pour adresse de base la valeur 0x00400000, et une capacité de stockage de 16 Koctets. |
| 135 | | * '''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. |
| 136 | | |
| 137 | | == 5.3 Génération du logiciel embarqué == |
| 138 | | |
| 139 | | == 5.4 Compilation et génération du simulateur == |
| 140 | | |
| 141 | | Il faut ensuite compiler les différents fichiers pour générer le simulateur. |
| 142 | | On va utiliser la même méthode que dans le TP1, mais il y a une difficulté supplémentaire, à cause |
| 143 | | du paramètre template `vci_param` des composants `VciLcdMaster`, `VciLcdCoprocessor`. |
| 144 | | Dans un contexte de compilation séparée, il est nécessaire de définir explicitement la valeur de ce paramètre |
| 145 | | dans chacun des fichiers source avant de lancer la génération du fichier objet associé. |
| 146 | | Pour cela, il faut rajouter la ligne suivante à la fin des fichiers `vci_lcd_master.cpp` et `vci_lcd_coprocessor.cpp` : |
| | 152 | Comme dans le TP2, il faut modifier tous les fichiers des composants qui possèdent des paramètres templates pour définir |
| | 153 | les valeurs de ces paramètres templates. Il faut ajouter à la fin de chaque fichier une ligne du type : |
| 148 | | template class VciLcdMaster<soclib::caba::VciParams<4, 8, 32, 1, 1, 1, 12, 1, 1, 1> >; |
| 149 | | }}} |
| 150 | | (pensez à changer le nom de la classe pour `vci_lcd_coprocessor.cpp`. |
| 151 | | |
| 152 | | Ceci étant fait, écrivez le Makefile permettant la génération du fichier exécutable `simple_simulator.x`. |
| 153 | | N'oubliez pas d'inclure dans la liste des fichiers objets les fichiers `mapping_table.o`, `segment.o`, `address_decoding_table.o`, |
| 154 | | `address_masking_table.o` (en plus des fichiers objet correspondant aux deux composants matériels |
| 155 | | |
| 156 | | Le lancement du simulateur doit vous fournir la même trace d'exécution que celle que obtenue dans le TP1, puisque |
| 157 | | les calculs effectués sont les mêmes (seul le protocole de communication a changé. |
| 158 | | |
| 159 | | == 5.5 Architecture multi-maitres == |
| 160 | | |
| 161 | | L' architecture interne du composant `VciVgsb` est décrite dans la figure ci-dessous. |
| 162 | | Le `bus` des commandes VCI, et le `bus` des réponses VCI sont modélisés par des multiplexeurs. Ces multiplexeurs sont |
| 163 | | commandés par un automate à trois états qui réalise une priorité tournante entre les initiateurs. |
| 164 | | Comme vous pouvez le constater sur le schéma, ce composant se comporte comme un automate de Mealy, |
| 165 | | puisque - une fois le bus alloué à un initiateur - les signaux de sortie dépendent combinatorement des signaux d'entrée. |
| 166 | | La latence minimale d'une transaction rafale de N mots VCI est de (N+1) cycles, dans le cas où la cible répond immédiatement. |
| 167 | | Du point de vue latence et bande passante, ce composant se comporte comme le PIbus. |
| 168 | | |
| 169 | | [[Image(soclib_tp2_bus.png)]] |
| 170 | | |
| 171 | | En vous inspirant du fichier `tp2_simple_top.cpp` de la question précédente, écrivez le fichier `tp2_multi_top.cpp`, |
| 172 | | qui décrit l'architecture à 7 composants décrite au début de ce TP. Vous ferez en sorte que le maitre (i) communique |
| 173 | | avec le coprocesseur (i). N'oubliez pas de définir 3 segments différents pour les trois coprocesseurs. |
| 174 | | |
| 175 | | Il faut également ajouter à la fin du fichier `vci_vgsb.cpp` la ligne permettant de définir la valeur du paramètre template |
| 176 | | `vci_param` : |
| 177 | | {{{ |
| 178 | | template class VciVgsb<soclib::caba::VciParams<4, 8, 32, 1, 1, 1, 12, 1, 1, 1> >; |
| | 155 | template class VciLcdCoprocessor<soclib::caba::VciParams<4, 8, 32, 1, 1, 1, 12, 1, 1, 1> >; |
| 187 | | = 6 Compte-rendu = |
| | 160 | Il faut compléter le fichier ''tp3_top.cpp'', pour définir complêtement la MappingTable, |
| | 161 | définir les arguments des constructeurs et les valeurs des paramètres template des différents composants matériels instanciés, |
| | 162 | et définir le cheminom permettant au ''loader'' d'accéder au fichier ELF. |
| | 163 | |
| | 164 | == 4.5 Compilation et génération du simulateur == |
| | 165 | |
| | 166 | Complêtez le Makefile qui vous est fourni dans le répertoire TP3, pour définir l'ensemble de tous les fichiers |
| | 167 | objet utilisés pour construire le simulateur ''tp3_mono_simulator.x''. |
| | 168 | |
| | 169 | Lancez la compilation, puis exécutez la simulation. |
| | 170 | |
| | 171 | == 4.6 Modification du logiciel embarqué == |
| | 172 | |
| | 173 | Il est maintenant possible de modifier le logiciel embarqué (fichier ''main.c''), sans modifier l'architecture matérielle (fichier ''tp3_top.cpp''). |
| | 174 | L'application logicielle ''hello world'' n'utilisait pas le coprocesseur LCD. |
| | 175 | Modifiez le fichier ''main.c'', pour que les programme C exécute une boucle infinie dans laquelle on effectue successivement |
| | 176 | les opérations six opérations suivantes : |
| | 177 | |
| | 178 | .1 affichage du numéro de cycle et du numéro d'itération. |
| | 179 | .1 génération aléatoire de deux variables OPA et OPB de type ''int''. |
| | 180 | .1 écriture de OPA dans le registre ''r_opa'' du coprocesseur LCD. |
| | 181 | .1 écriture de OPB dans le registre ''r_opb'' du coprocesseur LCD. |
| | 182 | .1 écriture dans le pseudo-registre ''r_start'' du coprocesseur LCD, pour démarrer la simulation. |
| | 183 | .1 lecture dans le registre ''r_res'' du coprocesseur LCD pour récupérer le résultat. |
| | 184 | .1 affichage du numéro d'itération, du numéro de cycle, des valeurs des opérandes et du résultat sur le TTY. |
| | 185 | |
| | 186 | Pour afficher sur le terminal, on utilisera évidemment la fonction ''printf()''. |
| | 187 | Pour obtenir le numéro de cycle, on utilisera la fonction... |
| | 188 | Pour la génération aléatoire, on utilisera la fonction ''rand()''. |
| | 189 | Pour les accès au coprocesseur LCD on utilisera les fonctions... |
| | 190 | |
| | 191 | Le code de ces fonctions est défini dans le fichier... |
| | 192 | |
| | 193 | = 5 Compte-rendu = |