| 1 | {{{ |
| 2 | #!html |
| 3 | <h1>TP2: Déploiement de l'application MJPEG sur une architecture SoC monoprocesseur </h1> |
| 4 | }}} |
| 5 | [[PageOutline]] |
| 6 | |
| 7 | |
| 8 | = 0. Objectif = |
| 9 | |
| 10 | La première partie de ce TP vise à montrer comment décrire - avec DSX - |
| 11 | une architecture matérielle de système intégré sur puce, en utilisant les |
| 12 | composants matériels de la bibliothèque SoCLib. On rappelle que la |
| 13 | bibliothèque SoCLib contient un ensemble modèles de simulation de composants |
| 14 | matériels (IP cores), décrits en langage SystemC. L'intérêt d'utiliser DSX |
| 15 | (plutôt que de décrire directement l'architecture en langage SystemC), |
| 16 | est qu'il permet de décrire facilement des architectures génériques |
| 17 | (nombre variable de processeurs ou de bancs mémoire par exemple). |
| 18 | |
| 19 | La seconde partie du TP vous permettra d'utiliser DSX pour décrire et |
| 20 | contrôler précisément le déploiement de l'application logicielle !SplitMsg |
| 21 | (TCG décrit avec DSX), sur l'architecture matérielle décrite dans la première |
| 22 | partie. On validera ce déploiement en simulant l'exécution d>u code binaire |
| 23 | de l'application logicielle (généré par DSX) sur le modèle SystemC de |
| 24 | l'architecture matérielle (également généré par DSX). |
| 25 | |
| 26 | La troisième partie du TP vous permettra d'atteindre notre véritable but, qui est |
| 27 | de de déployer l'application MJPEG du TP1 sur l'architecture de SoC monoprocesseur |
| 28 | décrite dans la première partie, en contrôlant précisément le placement des tâches sur |
| 29 | les processeurs ou coprocesseurs, et le placement des tampons de communication |
| 30 | sur les bancs mémoire embarqués. |
| 31 | |
| 32 | = 1. Description de l'architecture matérielle = |
| 33 | |
| 34 | On se limitera dans ce TP à une architecture ne contenant qu'un seul processeur |
| 35 | programmable de type MIPS R3000. Cette architecture matérielle est |
| 36 | appelée 'VgmnNoirqMono'. |
| 37 | |
| 38 | [[Image(VgmnNoirqMono:vgmn_noirq_mono.png, align=right)]] |
| 39 | |
| 40 | * Elle est organisée autour d'un micro-réseau générique à interface VCI (composant VGMN). |
| 41 | Ce composant est générique en ce sens qu'il accepte un nombre quelconque d'inititiateurs |
| 42 | VCI, et un nombre quelconque de cibles VCI, ainsi qu'un paramètre définissant |
| 43 | la latence du réseau: nombre minimal de cycles pour une traversée du réseau |
| 44 | "one-way". |
| 45 | * Elle comporte un contrôleur de verrous (composant LOCKS), utilisé pour protéger |
| 46 | l'accès aux canaux de communication MWMR. |
| 47 | * Elle comporte deux contrôleurs mémoire RAM0 et RAM1 |
| 48 | * Elle comporte un contrôleur de terminal TTY. |
| 49 | |
| 50 | '''Attention''': les deux coprocesseurs matériels d'entrée/sortie TG et RAMDAC, ne doivent |
| 51 | pas être décrits dans l'architecture !VgmnNoirqMono. Ces deux coprocesseurs, ainsi que |
| 52 | les deux contrôleurs MWMR leur permettant d'accéder aux canaux MWMR ne sont utilisés |
| 53 | que par l'application MJPEG, et pas par l'application !SplitMsg. Ils seront |
| 54 | automatiquement générés dans la phase de "déploiement" de l'application MJPEG, |
| 55 | lorsqu'on précisera que les tâches `tg` et `ramdac` du TCG sont implémentés comme des |
| 56 | composants matériels. |
| 57 | |
| 58 | Commencez par créer un répertoire de travail TP2. |
| 59 | Pour faciliter la réutilisation, l'architecture matérielle est généralement décrite |
| 60 | dans un fichier séparé. Créez, dans le répertoire TP2, le fichier `vgmn_noirq_mono.py`. |
| 61 | VgmnNoirqMono contient une descrition incomplète que vous |
| 62 | devez compléter, en consultant la documentation SoclibComponents qui définit les |
| 63 | paramètres des différents composants de la bibliothèque SoCLib. |
| 64 | |
| 65 | [[Image(MjpegCourse:q.gif)]] Q1: '''''Quelle est la syntaxe utilisée par DSX pour exprimer |
| 66 | que le port P,,0,, du composant matériel C,,0,, est connecté au port P,,1,, du composant matériel C,,1,,?''''' |
| 67 | |
| 68 | Une fois la description de la plateforme complète, nous pouvons la tester en générant |
| 69 | une netlist SystemC décrivant la ''top-cell''. Créez un fichier contenant: |
| 70 | {{{ |
| 71 | #!/usr/bin/env python |
| 72 | |
| 73 | from vgmn_noirq_mono import VgmnNoirqMono |
| 74 | |
| 75 | archi = VgmnNoirqMono() |
| 76 | |
| 77 | archi.generate(Caba()) |
| 78 | }}} |
| 79 | * Rendez ce nouveau fichier de description exécutable, lancez-le. Ne réalisez pas la compilation |
| 80 | de la plateforme résultante: nous n'avons pas encore de logiciel à exécuter dedans. |
| 81 | |
| 82 | Si tout se passe bien, vous devriez avoir un nouveau répertoire `caba` dans le répertoire courant. |
| 83 | La description SystemC de la ''top-cell'' est dans `caba/top.h.new`. DSX alloue automatiquement des adresses aux |
| 84 | segments mémoire pour lesquels les adresses de base ne sont pas imposées par l'utilisateur. |
| 85 | [[BR]] |
| 86 | [[Image(MjpegCourse:q.gif)]] Q2: '''''Visualisez le fichier de "top-cell" pour déterminer les adresses |
| 87 | et les tailles des 6 segments de l'espace adressable définis dans cette application.''''' |
| 88 | |
| 89 | = 2. Déploiement de l'application SplitMsg = |
| 90 | |
| 91 | On va commencer par déployer l'application !SplitMsg, qui ne comporte que deux tâches et un canal |
| 92 | sur notre architecture de SoC monoprocesseur. |
| 93 | * Créez dans le répertoire TP2 un sous-répertoire 'splitmsg' (Important!) |
| 94 | * Recopiez dans ce répertoire la description DSX de l'application !SplitMsg du TP1. |
| 95 | * Modifiez cette description DSX en ajoutant après la description du TGG l'instanciation de l'architecture matérielle !VgmnNoirqMono. |
| 96 | |
| 97 | {{{ |
| 98 | ######################################################### |
| 99 | # Section B : Hardware architecture |
| 100 | # |
| 101 | # The file containing the architecture definition |
| 102 | # must be included, and the path to the directory |
| 103 | # containing this file must be defined |
| 104 | ######################################################### |
| 105 | |
| 106 | from soclib import * |
| 107 | |
| 108 | import sys |
| 109 | sys.path.append("..") |
| 110 | |
| 111 | from vgmn_noirq_mono import VgmnNoirqMono |
| 112 | |
| 113 | archi = VgmnNoirqMono() |
| 114 | |
| 115 | }}} |
| 116 | |
| 117 | * Définissez le mapping de l'application !SplitMsg sur l'architecture !VgmnNoirqMono. |
| 118 | Vous devez consulter la page DsxMapping pour plus d'informations. |
| 119 | |
| 120 | Dans cette section, un objet `Mapper` doit être créé. |
| 121 | Supposons qu'on crée une variable `mapper`, l'architecture matérielle doit |
| 122 | être référencée à travers mapper.hard.''nom'' pour accéder aux composants |
| 123 | créés par self.''nom'' dans la description de la plateforme. |
| 124 | De même les objets logiciels doivent être accédés à travers mapper.tcg['nom']. |
| 125 | Il va falloir placer toutes les tâches, tous les canaux de communication, |
| 126 | tous les objets logiciels associés aux processeurs et enfin les objets globaux du système. |
| 127 | |
| 128 | {{{ |
| 129 | ######################################################### |
| 130 | # Section C : Mapping |
| 131 | # |
| 132 | ######################################################### |
| 133 | |
| 134 | mapper = Mapper(archi, tcg) |
| 135 | |
| 136 | # mapping the "prod0" and "cons0" tasks |
| 137 | |
| 138 | mapper.map("prod0", |
| 139 | run = mapper.hard.processor, |
| 140 | stack = mapper.hard.cram0, |
| 141 | desc = mapper.hard.cram0, |
| 142 | status = mapper.hard.uram0, |
| 143 | code = mapper.hard.cram0) |
| 144 | |
| 145 | mapper.map("cons0", |
| 146 | run = mapper.hard.processor, |
| 147 | stack = mapper.hard.cram0, |
| 148 | desc = mapper.hard.cram0, |
| 149 | status = mapper.hard.uram0, |
| 150 | code = mapper.hard.cram0) |
| 151 | |
| 152 | # mapping the MWMR channel |
| 153 | |
| 154 | mapper.map( "fifo", |
| 155 | lock = mapper.hard.locks, |
| 156 | status = mapper.hard.cram1, |
| 157 | desc = mapper.hard.cram1) |
| 158 | |
| 159 | # mapping the software objects associated to a processor |
| 160 | |
| 161 | mapper.map("processor", |
| 162 | desc = mapper.hard.cram0, |
| 163 | priv = mapper.hard.cram0, |
| 164 | status = mapper.hard.uram0) |
| 165 | |
| 166 | # mapping the software objects used by the embedded OS |
| 167 | |
| 168 | mapper.map(mapper.tcg, |
| 169 | desc = mapper.hard.cram1, |
| 170 | shared = mapper.hard.uram1, |
| 171 | code = mapper.hard.cram1) |
| 172 | }}} |
| 173 | |
| 174 | * La dernière étape consiste à générer le code |
| 175 | |
| 176 | {{{ |
| 177 | ###################################################### |
| 178 | # Section D : Code generation |
| 179 | ###################################################### |
| 180 | |
| 181 | # Embedded software linked with the Mutek/S OS |
| 182 | # SystemC simulator for the hardware architecture at Cycle Accurate/Bit Accurate abstraction level |
| 183 | |
| 184 | muteks = MutekS() |
| 185 | simulator = Caba() |
| 186 | mapper.generate( muteks, simulator ) |
| 187 | |
| 188 | # The software application for a POSX workstation can still be generated |
| 189 | |
| 190 | posix = Posix() |
| 191 | tcg.generate(posix) |
| 192 | |
| 193 | # Global Makefile generation |
| 194 | TopMakefile( muteks, simulator, posix ) |
| 195 | }}} |
| 196 | |
| 197 | |
| 198 | [[Image(MjpegCourse:q.gif)]] Q3: '''''Quels objets logiciels doit-on placer dans |
| 199 | l'espace addressable pour une tâche ? pour un canal mwmr ? pour un processeur ?''''' |
| 200 | |
| 201 | * Relancez l'exécution de la description DSX de votre application |
| 202 | {{{ |
| 203 | $ ./SplitMsg.py |
| 204 | }}} |
| 205 | * Générez le code binaire et le modèle SystemC de l'architecture matérielle. |
| 206 | {{{ |
| 207 | $ make |
| 208 | }}} |
| 209 | |
| 210 | Une fois la compilation effectuée, visualisez le fichier de "top cell" généré par DSX spécifiquement pour |
| 211 | ce déploiement. Il se situe dans muteks/caba/top.h. Déterminez les adresses |
| 212 | et les tailles des 6 segments de l'espace adressable définis dans cette application.[[BR]] |
| 213 | [[Image(MjpegCourse:q.gif)]] Q4: '''''En quoi diffèrent-ils de ces mêmes segments |
| 214 | vus à la question 2 ?''''' |
| 215 | |
| 216 | * Executez l'application logicielle sur la station de travail |
| 217 | {{{ |
| 218 | $ ./exe.posix |
| 219 | }}} |
| 220 | * Simulez l'exécution de l'application logicielle sur le modèle SystemC du SoC |
| 221 | {{{ |
| 222 | $ ./exe.muteks_caba |
| 223 | }}} |
| 224 | |
| 225 | [[Image(MjpegCourse:q.gif)]] Q5: '''''Qu'observez-vous ? En quoi est-ce différent de ce |
| 226 | qui se passe dans la version pour station de travail ?''''' |
| 227 | |
| 228 | = 3. Déploiement de l'application MJPEG = |
| 229 | |
| 230 | L'application MJPEG est différente de l'application !SplitMsg car elle utilise deux |
| 231 | périphériques d'entrée/sortie spécialisés : |
| 232 | * le coprocesseur ''Tg'': un composant matériel qui récupère le flux binaire MJPEG |
| 233 | (en analysant un signal radio-fréquence par exemple), effectue la conversion |
| 234 | analogique/numérique et écrit le résultat dans un canal MWMR |
| 235 | * le coprocesseur ''Ramdac'': un composant matériel qui lit une image décompressée |
| 236 | dans un canal MWMR et génère le signal video pour affichage sur l'écran. |
| 237 | |
| 238 | Pour pouvoir déployer ces deux tâches sous forme de coprocesseurs matériels, il faut |
| 239 | prévenir DSX qu'il existe des coprocesseurs implémentant ces tâches. Nous allons donc |
| 240 | modifier les déclarations des modèles de tâches en conséquence. |
| 241 | |
| 242 | Retournez dans le répertoire mjpeg du TP1, et exécutez la commande {{{make mrproper}}} |
| 243 | qui détruit tous les fichiers générés par les différentes compilations effectuées. |
| 244 | Ce ménage est indispensable pour vous éviter de dépasser votre quota d'espace |
| 245 | disque. Recopiez ce répertoire `mjpeg` nettoyé dans votre répertoire TP2. |
| 246 | |
| 247 | Dans la description DSX de l'application MJPEG, modifiez la définition des modèles de tâches |
| 248 | `tg` et `ramdac` pour introduire leurs implémentations matérielles. |
| 249 | Comme ces deux implémentations sont définies dans soclib, la directive |
| 250 | {{{from soclib import *}}} doit être présente avant la description des tâches dans |
| 251 | votre fichier de description. |
| 252 | * Pour la tâche `tg`, ajoutez un deuxième élément dans la liste des implémentations disponibles: |
| 253 | {{{ |
| 254 | tg = TaskModel( 'tg', |
| 255 | outfifos = [ 'output' ], |
| 256 | impl = [ SwTask( 'tg', |
| 257 | stack_size = 1024, |
| 258 | sources = [ 'src/tg.c' ], |
| 259 | defines = [ 'FILE_NAME' ] ), |
| 260 | HwTask( Tg ) |
| 261 | ] ) |
| 262 | }}} |
| 263 | * De même, pour la tâche `ramdac`, ajoutez l'implémentation suivante: |
| 264 | {{{ |
| 265 | HwTask( Ramdac ) |
| 266 | }}} |
| 267 | |
| 268 | * En vous inspirant de ce qui a été fait pour déployer !SplitMsg, déployez l'application MJPEG |
| 269 | sur la plateforme. |
| 270 | * Les coprocesseurs `tg` et `ramdac` sont spécifiques, ils doivent |
| 271 | faire l'objet d'un déploiement non pas en tant que tâches logicielles sur un processeur, mais |
| 272 | en tant que coprocesseurs rattachés par un contrôleur MWMR à un interconnect VCI. Le déploiement |
| 273 | valide pour `tg` est par exemple: |
| 274 | {{{ |
| 275 | mapper.map( 'tg0', |
| 276 | vci = mapper.hard.vgmn ) |
| 277 | }}} |
| 278 | * De même déployez `ramdac` sur la plateforme. |
| 279 | * Relancez la description, recompilez, lancez la simulation. Ajoutez le flag `-e` sur la ligne de commande |
| 280 | pour que la simulation ne soit pas limitée au premier million de cycles. |
| 281 | {{{ |
| 282 | $ ./description |
| 283 | $ make |
| 284 | $ ./exe.muteks_caba -e |
| 285 | }}} |
| 286 | |
| 287 | L'avion fait le "tour" en 25 images. Vous avez un compteur de cycles sur le terminal qui contient le simulateur. |
| 288 | [[BR]] |
| 289 | [[Image(MjpegCourse:q.gif)]] Q6: '''''Combien faut-il de cycles, approximativement, pour décompresser 25 images ?''''' |
| 290 | |
| 291 | [[Image(MjpegCourse:q.gif)]] Q7: '''''Supposant un SoC cadencé à 200MHz, combien d'images sont affichées en une seconde ?''''' |
| 292 | |
| 293 | = 4. Influence du système d'exploitation embarqué = |
| 294 | |
| 295 | L'environnement DSX permet actuellement d'utiliser deux systèmes d'exploitation embarqués. |
| 296 | |
| 297 | * Mutek/S, un micro-noyau "statique" , très performant, mais ne fournissant pas la compatibilité POSIX. En particulier, il ne permet pas la création dynamique de tâches au moment de l'exécution. |
| 298 | * Mutek/D, un micro-noyau fournissant aux applications l'API des threads POSIX (y compris la création dynamique de tâches). |
| 299 | |
| 300 | Modifiez la description DSX de l'application MJPEG, pour utiliser l'OS Mutek/D. La section D devient: |
| 301 | {{{ |
| 302 | muteks = MutekS() |
| 303 | simulator_s = Caba() |
| 304 | mapper.generate( muteks, simulator_s ) |
| 305 | |
| 306 | mutekd = MutekD() |
| 307 | simulator_d = Caba() |
| 308 | mapper.generate( mutekd, simulator_d ) |
| 309 | |
| 310 | posix = Posix() |
| 311 | tcg.generate(posix) |
| 312 | |
| 313 | TopMakefile( muteks, simulator_s, mutekd, simulator_d, posix ) |
| 314 | }}} |
| 315 | |
| 316 | Il faut définir deux simulateurs différents (simulator_s et simulator_d) suivant qu'on utilise MUTEK/S ou MUTEK/D, |
| 317 | car DSX calcule automatiquement la capacité des deux bancs mémoire physique en fonction des la taille des différents |
| 318 | objets logiciels à ranger en mémoire. Le code généré pour MUTEK/S étant beaucoup plus compact, on a des mémoires |
| 319 | plus petites dans le cas de MUTEK/S. |
| 320 | |
| 321 | (Notez le changement dans la `TopMakefile`) |
| 322 | |
| 323 | * Relancez la description, recompilez, lancez la simulation du SoC avec Mutek/D |
| 324 | (attention, il y a deux simulateurs avec des noms différents) |
| 325 | {{{ |
| 326 | $ ./description |
| 327 | $ make |
| 328 | $ ./exe.mutekd_caba -e |
| 329 | }}} |
| 330 | |
| 331 | [[Image(MjpegCourse:q.gif)]] Q8: '''''Combien de cyles faut-il pour décompresser 25 images avec MUTEK/D? Comment expliquer ce résultat?''''' |
| 332 | |
| 333 | [[Image(MjpegCourse:q.gif)]] Q9: '''''En consultant la description SystemC de l'architecture matérielle générée par DSX, déterminez la capacité mémoire des deux bancs mémoire RAM0 et RAM1 suivant qu'on utilise MUTEK/S ou MUTEK/D.''''' |
| 334 | |
| 335 | = 5. Compte-rendu = |
| 336 | |
| 337 | Vous rendrez une archive dans le même format que la semaine précédente, nommée `binome0_binome1.tar.gz`, contenant exactement les fichiers: |
| 338 | {{{ |
| 339 | tp2/ |
| 340 | tp2/rapport.pdf |
| 341 | tp2/vgmn_noirq_mono.py |
| 342 | tp2/splitmsg/ |
| 343 | tp2/splitmsg/producer.c |
| 344 | tp2/splitmsg/consumer.c |
| 345 | tp2/splitmsg/splitmsg.py |
| 346 | tp2/mjpeg/mjpeg.py |
| 347 | tp2/mjpeg/src/ |
| 348 | tp2/mjpeg/src/iqzz.c |
| 349 | tp2/mjpeg/src/libu.c |
| 350 | }}} |
| 351 | |
| 352 | * Les fichiers `splitmsg.py` et `mjpeg.py` seront complets, avec vos descriptions de tâches et le mapping. |
| 353 | Pour mjpeg, il y aura les directives de génération de code pour Mutek/S et Mutek/D. |
| 354 | * Le répertoire `mjpeg/src` contiendra uniquement les implémentation de vos deux tâches libu et iqzz |
| 355 | (éventuellement mises à jour par rapport à la semaine dernière) vous ayant servi à exécuter les tests de ce TP. |
| 356 | * Le rapport sera court (une table des matières pour dire que tout est sur la même page est superflue), répondant aux questions |
| 357 | posées dans le texte, nommé `tp2/rapport.pdf`. |
| 358 | |
| 359 | Vous livrerez cette archive avant mardi 20 fevrier 2007, 18h00 à [MailAsim:nipo Nicolas Pouillon]. |