| 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 = |