Les systèmes numériques prennent une place de plus en plus importante dans notre vie quotidienne. De la machine à café jusqu’au satellite en passant par le téléphone portable ou la télévision, tous ces systèmes intègrent des puces renfermant dans seulement quelques millimètres carré de silicium une complexité étonnante. Les ASIC (Application Specific Integrated Circuit) sont des circuits intégrés dédiés exclusivement à un type d’application. Les circuits de ce type permettent d’atteindre les meilleurs rapports coût (taille), performance et consommation, mais leur comportement est totalement figé. Afin de supporter des modifications de spécification de l’application ou pour permettre d’exécuter une gamme d’application plus vaste, les circuits intègrent de plus en plus de processeurs programmables. Avec ces circuits, une simple modification du programme suffit pour tenir compte des évolutions. En contrepartie, les processeurs programmables sont plus complexes que les circuits dédiés puisqu’une partie significative de la logique est consacrée au stockage et au contrôle pour l’exécution des programmes. Les systèmes à base de processeurs programmables sont généralement décomposés en deux grandes classes : les systèmes généraux et les systèmes embarqués. Les systèmes généraux sont constitués à partir de processeurs standards et correspondent par exemple aux ordinateurs personnels de type PC. Les processeurs spécialisés, contrairement aux processeurs généraux, sont conçus pour exécuter efficacement les programmes pour lesquels ils sont prévus, et peuvent avoir des performances dégradées pour d’autres. Dotés d’unités de calcul adaptées, de chemins de données optimisés et d’un jeu d’instructions spécialisé, ces processeurs permettent d’atteindre d’excellents compromis performance, surface et consommation.
En 1997, seulement 2% des quelques deux milliards de microprocesseurs vendus dans le monde étaient destinés aux systèmes généraux, les 98% restants sont intégrés dans des systèmes embarqués. Un système embarqué peut être défini par les caractéristiques [Cam96] suivantes:
➤ Il est dédié à une application particulière.
➤ Il doit respecter des contraintes temps-réel souvent strictes et réagir à des événements externes.
➤ Son fonctionnement correct est essentiel en raison de l’impact sur l’environnement extérieur.
Les systèmes embarqués réalisent typiquement deux types de traitement : les applications de contrôle et les applications de traitement du signal. Parmi les processeurs spécialisés, les DSP (Digital Signal Processor) sont voués aux calculs intensifs inhérents aux applications de traitement du signal alors que les microcontrôleurs sont conçus pour exécuter efficacement des programmes de contrôle. Le marché des DSP programmables est en pleine croissance puisque le nombre de processeurs de ce type vendu dans le monde est passé de 132,7 millions en 1995 à 440,3 millions en 1998 , pour atteindre selon les prévisions le milliard d’unités en 2001. Ces dernières années, de nouveaux types de processeurs ultra spécialisés sont apparus, les ASIP (Application Specific Instruction set Processor). Dans [Mar95c], P. Marwedel situe les ASIP entre les ASIC et les processeurs spécialisés comme les DSP. Les ASIP ciblent en effet, non plus un domaine d’application (comme les DSP), mais en général moins d’un dizaine de programmes très spécifiques.
Les difficultés liées à la programmation de processeurs DSP
Les difficultés liées aux processeurs spécialisés programmables touchent à leur conception et à leur programmation. Dans ce document nous nous intéressons plus particulièrement aux problèmes des systèmes embarqués à base de DSP et à leur difficulté de programmation. De tels systèmes se caractérisent en effet par des contraintes de temps et de taille du code très fortes et font une part de plus en plus importante au logiciel par rapport au matériel. Actuellement, 60% du temps de développement de tels systèmes est consacré au codage logiciel.
Historiquement, le codage d’une application sur un processeur DSP s’effectuait manuellement. Tout d’abord, les constructeurs ont le plus souvent négligé l’investissement nécessaire au développement de compilateurs efficaces au profit de la conception même du circuit. Ce manque d’investissement s’explique par les faibles volumes des DSP qui ne justifiaient pas encore l’effort de conception d’un compilateur efficace. La complexité réduite des applications comme des architectures DSP permettait de plus une programmation en assembleur relativement aisée sur la base de fonctions de bibliothèques optimisées.
Mais la baisse du prix du matériel et les possibilités d’intégration que procurent les technologies sous microniques (actuellement 0,15 micron), permettent de concevoir des circuits contenant jusqu’à plusieurs millions de transistors par millimètre carré. Tirant profit de ces progrès, les constructeurs proposent des processeurs sans cesse plus performants pouvant exécuter plusieurs centaines de millions d’opérations par seconde. Les processeurs embarqués sont ainsi capables d’exécuter des applications de traitement du signal de plus en plus complexes. Mais cette puissance s’accompagne également d’un accroissement de la complexité de l’architecture cible [Pau97]. En conséquence, si pour les DSP du début des années 90 il est relativement aisé d’écrire du code assembleur tirant au maximum profit de l’architecture, ceci est beaucoup plus difficile avec les architectures parallèles récentes de type dual-MAC ou VLIW. Ces dernières possèdent en effet des contraintes liées au nombre élevé d’étages de pipeline (delay slot) ou encore des restrictions sur les chemins de données qui rendent considérablement plus complexes leur programmation.
Les coûts de développement élevés associés au codage manuel d’applications sur DSP et la pression sans cesse plus forte du « time-to-market » rendent cette situation de plus en plus inacceptable pour les entreprises et militent en faveur d’une approche de haut niveau basée sur l’utilisation de compilateurs [Woo98][Man99]. La situation a ainsi brusquement évoluée ces dernières années donnant aux compilateurs une place de plus en plus prépondérante dans le choix d’un DSP [Gal97]. Outre ces raisons, une telle approche augmente également la portabilité, la facilité de maintenance et le déboguage du code. Cette prise de conscience est générale dans le monde industriel. D’ailleurs Texas Instruments avec le processeur C6x[Tur97] ou Lucent avec le Sabre[Bod97] ont d’ores et déjà demandé à leurs utilisateurs d’abandonner l’assembleur au profit du langage C. L’utilisation d’un compilateur est indispensable pour ces deux processeurs en raison de leur complexité architecturale, donc de leur difficulté de programmation. Pour les processeurs à usage général, l’approche de haut niveau est courante puisque les compilateurs sont en général efficaces. Cela ne justifie pas pour autant leur utilisation dans des systèmes embarqués à base d’algorithmes de traitement du signal car leurs performances (nombre de cycles et taille de la mémoire programme) pour ce type d’applications sont souvent insuffisantes. Les DSP ont été conçu pour répondre aux contraintes fortes des systèmes embarqués, mais paradoxalement, leur haut degré de spécialisation en font des cibles particulièrement délicates pour la génération de code optimisé.
Les problèmes de génération de code efficace pour DSP suscitent un intérêt, certes récent, mais croissant de la part des industriels comme de la communauté scientifique [Ara95a][Gal97][Cra97]. L’inefficacité des compilateurs C actuels pour DSP oblige en effet tout ou partie de l’application à être codée en assembleur. Cela reste malheureusement le plus souvent la seule solution envisageable pour respecter les fortes contraintes de coût, de performance et de consommation. Or le codage et l’optimisation d’un code assembleur est un travail long et fastidieux. Pour l’application G.728 [Rec94] (codeur/décodeur de parole) par exemple, l’implémentation d’une solution valide et optimisée sur le processeur OakDSPCore a demandé cinq mois de travail. De plus, pour tirer le meilleur profit des performances d’un DSP, il est souvent nécessaire d’avoir une bonne connaissance de l’architecture du processeur (afin d’utiliser de manière efficace le jeu d’instructions) mais aussi de l’application cible.
Le besoin de nouveaux outils
La réduction du temps de développement d’un code assembleur optimisé pour DSP passe par une approche de plus haut niveau. Il s’agit en effet d’utiliser plus systématiquement le compilateur afin d’écrire le moins possible de code assembleur. Or, si les compilateurs pour DSP sont globalement inefficaces, nous savons également qu’il est possible d’améliorer de manière significative les performances du code assembleur généré en modifiant le code C d’origine pour le compilateur cible (i.e. l’architecture cible). Les modifications peuvent être effectuées naïvement sur la totalité du code C. Cependant, pour les applications de traitement du signal les parties critiques en temps d’exécution représentent généralement une faible partie de la taille totale du code. Ce sont typiquement les instructions appartenant à des boucles imbriquées. Partant de ce constat, le travail d’optimisation doit évidemment s’effectuer prioritairement sur ces parties critiques afin d’éviter de perdre inutilement du temps sur des parties de code ayant peu d’influence sur les performances globales de l’application.
En l’absence d’outil adapté, la localisation de ces parties critiques s’effectue généralement par une simulation du code assembleur généré par le compilateur. Malheureusement, le principal inconvénient de cette approche est les temps de simulation très longs Il faut en effet compter plusieurs heures voire plusieurs jours de simulation pour une application complète avec une séquence de test représentative (plusieurs secondes de paroles dans le cas d’un algorithme de compression comme G.728).
CHAPITRE 1 – INTRODUCTION |