Prise en main de l`environnement de développement VisualDSP++

publicité
Architecture Avancée
Université de Cergy-Pontoise
Prise en main de l’environnement
de développement VisualDSP++
I.Préambule
a.Introduction
Un Digital Signal Processor ou DSP en anglais, soit « processeur de signal numérique », est un
composant électronique optimisé pour ces types de calculs. Son application principale est le
traitement du signal numérique (filtrage, extraction de signaux, etc.),
Les DSP sont utilisés dans la plupart des applications embarquées : on les trouve dans les modems
(dont modem RTC, modem ADSL, etc., mais aussi dans les téléphones mobiles). Ils sont
également utilisés dans des systèmes vidéo, les chaînes de traitement de son, partout où l'on reçoit
un signal complexe que l'on doit modifier à l'aide du filtrage.
L’objectif de la prochaine série de TPs est de se familiariser avec la programmation de telles
architectures. Après avoir pris en main l’environnement de développement et l’utilisation du
simulateur intégré du jeu d’instruction du processeur SHARC 32 bits : ADSP-21061, nous
passerons à une implantation embarquée d’applications DSP sur la carte EZ-Kit Lite sur laquelle
se trouve ce processeur.
L’objectif global des séances sera donc d’une part de comprendre les particularités de
l’architecture d’un DSP et d’autre part d’appréhender de manière pratique l’utilisation
d’algorithmes de traitement du signal audio.
b.Objectifs du TP
Pour la séance actuelle les objectifs sont les suivants :
• Savoir développer une application C et assembleur sous l’environnement VisualDSP++
• Savoir analyser et profiler une application de traitement du signal.
• Avoir la maîtrise de l’outil pour passer à la prochaine séance à la réalisation d’une
application embarquée temps réel.
Avant de commencer regarder le schéma de l’annexe C.
II.Exo1 - Exemple de programme C
Créer un répertoire de travail dans lequel vous aurez un dossier par exercice.
a.Lancement de VisualDSP++
Pour lancer l’environnement de développement, aller dans le Menu
’Démarrer/Programmes/VisualDSP’. Ouvrer ensuite un nouveau projet par le menu
‘Project/New…’.
La fenêtre d’options du projet s’ouvre, vous devez la configurer.
Le volet ‘Project’ définit les outils utilisés : compilateur, assembleur, linker, chargeur ainsi que le
processeur cible de votre application. Vous n’avez ici qu’à préciser le processeur cible : l’ADSP21061.
Les autres volets permettent de paramétrer les options de compilation, assemblage …
Visiter ces différents volets, puis faites OK.
A la question voulez-vous inclure les fonctions du noyau (kernel) de VisualDSP++, répondez
NON.
Architecture Avancée
Université de Cergy-Pontoise
b.Compilation et exécution du projet
Vous aller maintenant insérer au projet le code d’une application simple déjà développée en
partie : dotprodc. Pour cela, aller dans ‘Project/Add to project …/Files’ et ajouter les fichiers
dotprod.c, dotprod_main.c et dotprodc.ldf.
• Vous trouverez ces fichiers sur la page web habituelle.
Un fichier LDF est un fichier descripteur de l’édition de liens.
Compiler le programme (menu Project).
A l’issue de la compilation vous vérifierez que dans le répertoire debug de votre projet les fichiers
objets (.doj) et le fichier exécutable (.dxe) ont bien été générés.
Exécuter maintenant le projet (menu Debug si elle n’est pas lancée automatiquement). La fenêtre
‘Dissambly’ fournit une vision du code assembleur désassemblé à partir du fichier exécutable.
Un point d’arrêt a été placé dans le code C, retrouver sur quelle instruction en faisant de
l’exécution pas à pas. Continuer l’exécution pas à pas jusqu’à la fonction a_dot_b et visualiser
l’effet du pipeline sur le saut de fin de boucle.
Faites un restart, puis relancer l’exécution (run).
Si vous lancer à nouveau ‘run’ pour continuer l’exécution après le breakpoint l’exécution semble
ne pas terminer. Pour l’arrêter aller dans ‘Debug/Halt’.
En effet, la mémoire continue bien après la dernière instruction du code. Quelle est cette
instruction ? Pourquoi l’exécution boucle-t-elle dessus ?
Pour palier à ce problème de confort de manipulation du programme, ajouter un breakpoint à la
fin du programme. Pour cela, utiliser le menu ‘Settings/Breakpoint…’. Pour ajouter un point
d’arrêt supplémentaire, on peut soit donner son adresse, visible dans la fenêtre Disassembly, soit
aller chercher le symbole dans la table (…des symboles) accessible par le bouton browse, puis sur
Add.
Relancer l’exécution après avoir réinitialiser l’exécution avec ‘Debug/Restart’.
Un autre moyen de constater l’évolution du programme est de faire du pas à pas avec ‘Debug/Step
Into’ (F11).
Vous savez maintenant compiler, et exécuter (au besoin pas à pas) un programme.
Regarder maintenant le code que vous avez exécuter pour comprendre sa fonctionnalité.
c.Profiling de l’application
Nous allons maintenant profiler ce programme pour déterminer quelle partie devrait être optimisée
(en assembleur). Nous allons récupérer les informations :
• Pourcentage de temps d’exécution par fonction
• Nombre de cycles d’exécution
• Nombre d’instructions exécutées
• Nombre d’accès mémoire
Premièrement sélectionner l’analyse statistique par le menu Tools/Statistical Profiling/enable.
Aller dans le menu View/Debug Windows/Statistical results pour lancer la fenêtre correspondante.
Relancer l’exécution et identifier les sections critiques. Double cliquer sur la première ligne pour
visualiser le code responsable de ce temps d’exécution.
Sélectionner maintenant ‘Tools/Profile…/enable profile’ pour une analyse plus précise.
Puis Tools/Profile…/Profile…/Add/RemoveRange pour sélectionner la portion à analyser.
Vous choisirez d’analyser la function a_dot_c (du label a_dot_c à a_dot_c_end).
Architecture Avancée
Université de Cergy-Pontoise
Une fois le range placé, aller dans View/Debug option/Profile pour afficher la fenêtre
correspondante. Relancer l’exécution.
Vous pouvez ajouter le profiling des 2 autres fonctions en ajoutant un label de fin de fonction à
chacune, en recompilant et en relançant l’analyse.
Noter les résultats de profile obtenus nous en aurons besoin par la suite.
Au vue des résultats, nous allons réécrire la fonction a_dot_c en assembleur…
Femer le projet par Project/Close
III.Exo2 - Exemple de code joint C-assembleur
Créer un nouveau projet en incluant les fichiers de l’exo 2.
a.Modification du source
Actuellement la fonction main fait appel à la version C de la fonction a_dot_c. Modifier le code
pour qu’elle appelle la version assembleur _a_dot_c_asm.
Compiler. Que ce passe-t-il ? Pourquoi le code de version assembleur n’est elle pas trouvée ?
b.Modification du fichier LDF
Ouvrer le fichier dotprodasm.ldf en édition. Il est structuré en 3 parties :
• L’organisation mémoire de la cible en commentaires
• L’affectation des segments dans cette organisation
• La correspondance entre sections et segments
Remplacer l’affectation de l’objet dotprod.doj à la mémoire pour obtenir le code suivant :
block1_program_code
{
INPUT_SECTIONS( dotprod.doj(seg_pmco)
dotprod_func.doj(pm_code1)
dotprod_func.doj(pm_code2)
dotprod_func.doj(pm_code3))
} >b1_code
Compiler et exécuter le programme modifié.
c.Vérification
Configurer à nouveau le débugger pour profiler la nouvelle version de la fonction. Vous utiliserez le
range : _a_dot_c_asm …_a_dot_c_asm_end.
Comparer les résultats au profiling précédent et notamment aux résultats de la fonction a_dot_b
écrite en C et qui prenait les même temps de calcul que la version C de a_dot_c.
La programmation en assembleur a 2 avantages sur le C. Premièrement, les instructions
assembleurs sont optimisées pour le processeur. Le jeu d’instruction supporte le multi fonctions,
opérations parallèles exécutables en 1 seul cycle.
Deuxièmement en programmant en assembleur le code représente uniquement la fonction
suffisante. En C, la sauvegarde et la restauration de contexte un ensemble générique de registres
donc plus important. De plus le code C ajoute à la compilation un environnement d’exécution
amenant un surcoût d’instructions.
Visualiser le code assembleur, essayer d’identifier la correspondance avec le code C.
Fermer le projet et les fenêtres l’accompagnant.
Architecture Avancée
Université de Cergy-Pontoise
IV.Exo 3 - Visualiser les données
Nous allons maintenant utiliser une application de convolution sur un buffer de données
enregistrées et utiliser les outils graphiques de VisualDSP++ pour visualiser le résultat.
Créer un nouveau projet et insérer le fichier convolution.c
Aller dans View/Debug/Plot/New… qui permet de configurer les tracés graphiques.
• Ajouter la donnée ‘Table’ qui se trouve dans la mémoire de données (DM).
• C’est une courbe du type ‘line plot’
• Préciser l’adresse d’implantation mémoire en retrouvant le symbole dans la table accessible
avec le bouton Browse.
• Pour remplir le champ count, retrouver la taille du tableau dans le code C.
• Stride représente l’incrément entre éléments. Comme le tableau est contigu en mémoire, sa
valeur est 1.
• Enfin le tableau est de type float.
• N’oubliez pas de cliquer sur Add.
Répétez ces étapes pour afficher les données Input, impulse et Output.
Mettant en correspondance les affichages et le code C pour comprendre les calculs réalisées par
cette application. Vous utiliserez pour cela les fonctions
• ‘float in main window’,
• zoom en désignant une zone avec la souris
• data cursor, puis avancer sur la courbe avec les flèches droite/gauche du clavier, ou changer
de courbe avec les flèches haut/bas.
Quel type d’information contient :
• la table
• le tableau Input
• le tableau Impulse
• le tableau Output ?
Fermer le projet, c’est fini !!
Architecture Avancée
Université de Cergy-Pontoise
V.Annexe :
a.Procédure de sauvegarde/retour de fonction
En assembleur la responsabilité de créer une zone de pile et de sauvegarder les registres qui vont
être utilisés en début de fonction et de les replacer en fin de fonction sont celles de la fonction
appelée.
En générant le code d’un appel de fonction, le compilateur insère la procédure suivante pour créer
la pile :
• Load le registre R2 avec le frame pointer (I6)
• Place le frame pointer (I6) égal au stack pointer (I7)
• Utilise le branchement retardé pour donner le contrôle à la fonction
• Place le registre r2 sur la run-time stack durant le premier ‘delay slot’
• Place le registre PC sur la run-time stack durant le 2e
Vous pouvez utiliser la macro entry de la bibliothèque <asm_sprt.h> pour réaliser ce travail, et à
l’inverse la macro exit() pour dépiler le contexte.
b.Règles d’utilisation des registres
Architecture Avancée
Université de Cergy-Pontoise
c.Processus de développement et de conception
Téléchargement