Brevet FR2978263A1 — publié le 20130125

La présente invention concerne le domaine de la conception automatique des systèmes numériques connu sous le nom de synthèse de haut niveau (high-level synthesis en anglais) ou synthèse comportementale (behavioural synthesis en anglais). La synthèse de haut niveau consiste à partir d'une description de haut niveau d'une application à lui appliquer une série de transformations automatiques pour générer une description qui puisse permettre la synthèse d'un composant matériel dédié à l'exécution de cette application. Ces applications sont vues sous la forme de systèmes qui intègrent des programmes informatiques au sens traditionnel du terme, c'est-à-dire ayant vocation à s'exécuter sur des processeurs génériques et des programmes ayant vocation à être synthétisés sous la forme d'assemblages de composants électroniques dédiés. Le système généré fonctionne de manière concurrente, c'est-à-dire qu'il y a une exécution simultanée de l'ensemble des processeurs et des composants générés. De plus, ces processeurs et ces composants échangent des données par le biais de synchronisations et/ou de protocoles de communication entre ces éléments. Les solutions actuelles de synthèse de haut niveau partent généralement d'une description séquentielle du système sous la forme d'un programme unique, typiquement écrit en langage C ou C++. Le parallélisme de l'application n'est pas décrit ou simplement sous la forme de simples directives de compilation (pragma en anglais) insérées dans le code par le programmeur pour désigner des parties de codes pouvant être exécutées en parallèle. Cette application est alors traduite sous la forme d'un graphe SSA (Static Single Assignment en anglais) de niveau assembleur où chaque variable n'est assignée qu'une seule fois. Ce graphe est ensuite transformé en un graphe de flot de contrôle et de données appelé CDFG (Control and Data Flow Graph en anglais). La partie contrôle du CDFG sert à exprimer les différents traitements au sein de l'application tandis que la partie données sert à effectuer des calculs de dépendance des données. Ces dépendances de données permettent d'exhiber le parallélisme fin pouvant être utilisé lors de l'implémentation de l'application. On peut alors traduire le CDFG sous la forme d'un ou plusieurs automates d'états finis ou FSM (Finite State Machine en anglais). Ces automates sont alors transcrits dans un langage de description matériel ou RTL (Register Transfer Language en anglais). Les langages les plus connus sont VHDL (VHSIC Hardware Description Language en anglais) et Verilog HDL. La description du système dans un de ces langages est directement synthétisable sous la forme d'un composant, typiquement un FPGA (Field-Programmable Gate Array en anglais) ou un ASIC (Application Specific Integrated Circuit en anglais). Du fait de la complexité de l'opération consistant à déduire le parallélisme fin du graphe de dépendance des données, il s'avère dans la pratique que la taille des applications que l'on peut ainsi synthétiser est limitée. Pour des applications plus grandes, il est nécessaire de les découper en modules de taille raisonnable pour les synthétiser séparément. D'autre part, cette opération est coûteuse en temps et génère une description dans le langage RTL choisi complexe et éloignée de la description initiale. Cette description est donc difficile à lire pour un humain et donc à adapter. L'invention vise à résoudre les problèmes précédents par un procédé de synthèse de haut niveau à partir d'une description du système dans un langage spécifique du domaine particulier ou DSL (Domain Specific Language en anglais). Ce DSL permet de décrire l'application sous la forme d'un réseau de processus communiquant. Il permet d'expliciter les ports de communications et donc le parallélisme de l'application. La synthèse implique la transformation de cette description en organigrammes particuliers puis en automates d'états finis. Ce procédé permet de se dispenser d'un calcul de dépendance des données. Le procédé décrit permet une synthèse rapide et donne un résultat lisible et facilement adaptable et portable par un humain. L'invention concerne un procédé de synthèse de haut niveau d'une application sous la forme d'un langage de description matérielle des transferts de registres qui comporte une étape de lecture d'une description de l'application sous la forme d'un réseau de processus communicants ; une étape de construction d'un organigramme de flot de contrôle pour chaque processus de l'application ainsi décrite ; une étape de construction d'un automate d'états finis pour chaque organigramme de flot de contrôle et une étape de traduction de chaque automate sous la forme d'un langage de description matérielle des transferts de registres. Selon un mode de réalisation particulier de l'invention, l'étape de lecture d'une description de l'application comprend une étape de lecture d'une déclaration des différents ports de communication pour chaque processus. Selon un mode de réalisation particulier de l'invention, l'étape de lecture d'une déclaration des différents ports de communication pour chaque processus, comprend la lecture du type du port, ce type pouvant être synchrone ou asynchrone. Selon un mode de réalisation particulier de l'invention, l'étape de lecture d'une description de l'application comprend une étape de lecture des communications entre les processus décrits sous la forme de primitives d'émission et de réception de messages sur les ports de communication. Selon un mode de réalisation particulier de l'invention, le procédé comporte en outre une étape de remplacement des primitives d'émission et de réception de 10 messages par des primitives de plus bas niveau. Selon un mode de réalisation particulier de l'invention, l'étape de création de l'organigramme de flot de contrôle crée un organigramme consistant en des boîtes correspondant à une séquence de traitement s'exécutant de manière atomique ; des décisions précisant le flot de contrôle en fonction du résultat de l'évaluation d'une 15 condition et des jonctions insérées en amont de toute boîte ou décision destination de plusieurs flots de contrôle ou pour séparer deux étapes de calcul intrinsèquement séquentielles. Selon un mode de réalisation particulier de l'invention, l'étape de création de l'automate d'états finis comprend une étape de création d'un état correspondant à 20 chaque jonction de l'organigramme ; une étape de création d'une transition d'un état vers un autre lorsqu'une boîte ou une décision pointe vers une nouvelle jonction et une étape de création d'un code associé à un état constitué des éléments se trouvant entre la jonction correspondant à cet état et la suivante. Selon un mode de réalisation particulier de l'invention, le procédé comporte une 25 étape de génération d'une horloge de fonctionnement distincte pour chacun des processus dudit réseau de processus communicants. Selon un mode de réalisation particulier de l'invention, le procédé comporte une étape de génération d'un traitement combinatoire du calcul impliquant une variable ne nécessitant pas de stockage des résultats intermédiaires dans un registre. 30 Selon un mode de réalisation particulier de l'invention, la dernière modification de la variable au sein de l'état est sauvegardée sous la forme d'un signal stocké dans un registre. Les caractéristiques de l'invention mentionnées ci-dessus, ainsi que d'autres, apparaîtront plus clairement à la lecture de la description suivante d'un exemple de réalisation, ladite description étant faite en relation avec les dessins joints, parmi lesquels : La Fig. 1 illustre un exemple de réseau de processus communicants. La Fig. 2 illustre le déroulement du procédé de synthèse dans l'exemple de 5 réalisation de l'invention. La Fig. 3 illustre un exemple d'organigramme de flot de contrôle généré. Le procédé prend en entrée une description de l'application à implémenter sous la forme d'un réseau de processus communicants. C'est une façon naturelle d'exprimer le parallélisme présent dans l'application. L'art antérieur utilise un 10 formalisme de description de l'application sous la forme d'un programme séquentiel, typiquement C ou C++. Le choix est fait ici de privilégier une expression du parallélisme à gros grains plutôt qu'une synthèse fine du parallélisme par une analyse du graphe de dépendance des données. L'obligation pour l'utilisateur de décrire son application en explicitant le parallélisme de cette manière se révèle à l'usage pas plus 15 contraignant que la découpe en module typiquement nécessaire dans l'art antérieur pour être capable de synthétiser des applications de grande taille. La Fig. 1 illustre un exemple de réseau de processus communicants. Dans cet exemple il y a trois processus 1.1, 1.2 et 1.3. Chacun de ces processus est exprimé sous la forme d'un programme séquentiel classique permettant d'exprimer le 20 traitement effectué par le processus. Les processus sont dotés de ports de communication leur permettant d'émettre et de recevoir des données sous la forme de messages. Certains de ces ports, par exemple les ports référencés 1.4 et 1.9, permettent un échange avec l'extérieur. Ce sont les entrées et les sorties de l'application. D'autres ports, 1.5, 1.6, 1.7 et 1.8 permettent un échange avec le port d'un autre processus. Le 25 couple de ports forme alors un canal de communication. Ces canaux de communication peuvent avantageusement prendre deux formes, une forme synchrone et une forme asynchrone. La forme synchrone est conforme au modèle CSP (Communicating Sequential Process en anglais). Elle correspond à un modèle de rendez-vous, le processus qui émet un message et le processus qui reçoit le 30 message doivent être présents au rendez-vous pour que l'échange ait lieu. Le premier arrivé est donc bloqué en attendant le second. Une fois que l'échange de message a eu lieu, les deux processus reprennent le cours de leur exécution. Le second modèle, connu sous le nom de modèle KPN (Kahn Process Network en anglais), correspond à un modèle où le canal de transmission est modélisé sous la forme d'une FIFO (First In First Out en anglais). Dans ce cas, un processus émetteur de message va écrire son message dans la FIFO, tandis que le processus receveur va lire cette FIFO. Il n'y aura donc de blocage uniquement lors d'une tentative de lecture sur une FIFO vide. Dans la pratique, les tailles de FIFO étant nécessairement limitées, il peut également se produire un blocage dans le cas d'une tentative d'écriture dans une FIFO pleine. L'application est décrite à l'aide d'un langage séquentiel particulier appelé DSL. Ce langage comprend un ensemble de déclarations pour les variables, les fonctions, les structures de données, les ports de communication et autres. Un port de communication est l'interface d'un canal de communication au sein d'un processus. Il comprend également des primitives d'émission et de réception de données sur ces ports appelées SEND et RECEIVE. Ces primitives peuvent être bloquantes ou non selon le mode de fonctionnement, synchrone ou asynchrone, du canal de transmission associé. Il comprend également une primitive d'assignation de variable et les expressions arithmétiques et logiques habituelles. Il comprend également des structures de contrôle telles qu'une boucle conditionnelle, boucle WHILE, et une boucle non conditionnelle, boucle FOR ainsi qu'une structure de test, structure IF ELSETF. Il comprend la possibilité d'effectuer un appel de fonction, primitive CALL. Une primitive d'attente permet d'attendre un nombre déterminé de cycles d'horloge, l'horloge étant définie implicitement comme l'horloge du circuit généré, primitive WATT. La Fig. 2 illustre le déroulement du procédé de synthèse dans l'exemple de réalisation de l'invention. On part d'une description de l'application dans le langage DSL décrit 25 précédemment. L'application est donc décrite sous la forme d'un réseau de processus communicants permettant d'exprimer le parallélisme intrinsèque. Une première étape 2.1 consiste à lire cette description en DSL de l'application. Ensuite, selon l'exemple de réalisation, intervient une étape préalable 2.2 qui consiste à expliciter certaines ruptures de séquence. L'homme du métier comprend 30 que cette étape n'est pas nécessaire dans tous les cas. Elle dépend de l'implémentation particulière des primitives de communication et d'accès mémoire. Elle peut également alternativement être intégrée dans l'étape suivante. Elle consiste à remplacer les primitives de communication, SEND et RECEIVE, ainsi que les accès mémoire, READ et WRITE, par des primitives de plus bas niveau. En particulier, les primitives d'accès au canal de transmission sont remplacées par une primitive REQ, pour request en anglais, en lecture ou en écriture, suivie d'une boucle d'attente d'un accusé de réception. Cette boucle est donc une boucle conditionnelle dont la condition est la réception d'un accusé de réception, primitive ACK. De même, une primitive de lecture mémoire READ est remplacée par une primitive READ_MEM suivie d'une primitive WAIT(1) pour satisfaire la condition de latence de l'accès mémoire et enfin d'une assignation à une variable du résultat de la lecture à l'aide de la primitive RESULT_MEM. Pour l'écriture en mémoire, on remplace la primitive WRITE par une primitive WRTTE_MEM suivie de la primitive WAIT(l). Dans ce cas, il n'y a pas de résultat. L'étape 2.3 consiste à partir de cette description en DSL, éventuellement modifiée par l'étape préliminaire, à construire un organigramme du flot de contrôle (flowchart en anglais) pour chaque processus de l'application. Cet organigramme exprime le contrôle et donc les traitements liés à chaque processus. Par contre, contrairement aux processus connus, il n'est jamais calculé de graphes de dépendance des données. Ces dépendances n'apparaissent donc pas dans l'organigramme calculé. En particulier, il n'est pas effectué de calcul d'un graphe SSA (Static Single Assignment en anglais) exprimant les dépendances des données à l'aide d'une transformation où les variables ne sont affectées qu'une seule fois. Cet organigramme du flot de contrôle comporte trois types d'éléments : des boîtes, des décisions et des jonctions. Une boîte, représentée par un rectangle, correspond à une séquence de traitement s'exécutant de manière atomique. Cette séquence est non interruptible et ne comporte pas de séquence de contrôle. Une décision, représentée par un losange, précise un flot de contrôle en fonction du résultat de l'évaluation de la condition qu'elle contient. Deux branches orientées sortent de la décision pour indiquer le chemin pris par le contrôle selon que l'évaluation de la condition est positive ou négative. L'exécution de l'organigramme précise que lorsque le flot de contrôle arrive sur une décision, le test est effectué et l'exécution se poursuit vers la branche concernée. Une jonction, représentée par un cercle, est insérée lorsque, sinon, plusieurs arcs aboutissent à une boîte ou une décision. Les arcs aboutissent alors à la jonction. Un arc unique sort de la jonction pour aboutir à la boîte ou à la décision. Les jonctions sont insérées pour rendre les chemins d'exécutions acycliques. Une jonction est donc insérée en amont de toute boîte ou décision destination de plusieurs flots de contrôle. Une jonction est également insérée lorsqu'un traitement intrinsèquement séquentiel apparaît. En effet, le code séparant deux jonctions est destiné à être exécuté dans le temps d'un pas d'horloge. Or certaines opérations, telles qu'un accès à une mémoire synchrone par exemple, nécessitent par nature un traitement sur plusieurs pas d'horloge. Dans ce cas, une jonction est insérée pour séparer les traitements séquentiels. La Fig. 3 illustre l'organigramme de flot de contrôle généré à partir de 10 l'exemple de programme source de la Fig. 4. Ce programme provoque l'assignation d'un tableau de 10 éléments avec le résultat d'une fonction `f'. C'est la première boucle. La seconde boucle correspond à l'émission des valeurs du tableau sur le port ol. Sur l'organigramme de la Fig. 3, on voit que l'on a une jonction SO qui permet 15 l'attente du démarrage du processus. Lorsque la variable `go' prend la valeur `true' on passe à la jonction SI. On initialise alors la variable i à 0 et l'on passe à la jonction S2. Il s'ensuit un test de sortie de boucle lorsque i est supérieur à 10. Tant que la valeur de i est inférieure ou égale à 10, on incrémente i et l'on effectue un appel de la fonction `f'. On passe alors à la jonction S3 pour attendre la fin d'exécution de `f'. Lorsque la 20 fonction `f' est terminée, on assigne la variable `t' via la variable temporaire tmp_0 avec le résultat de `f'. Cette valeur est ensuite mémorisée dans l'élément du tableau `tab' d'indice 'i'. Lorsque le tableau est entièrement rempli, on réinitialise `i' à 0 pour arriver à la jonction S5. On démarre alors une nouvelle boucle. Lors de cette nouvelle boucle, on 25 lit la valeur de l'élément de tableau d'indice `i' par une commande MEM_READ. Le résultat est assigné à la variable `t' via la variable temporaire `tmp_l'. Une boucle d'attente du résultat de l'émission est générée autour de la jonction S8. La jonction S7 est insérée pour tenir compte de l'aspect séquentiel obligatoire entre le lancement de l'opération de lecture mémoire « MEM_READ » et l'utilisation de la valeur lue par 30 l'instruction « MEM RESULT ». Une fois l'organigramme construit, on peut effectuer l'étape 2.4 consistant à construire l'automate d'états finis ou FSM correspondant à chaque organigramme créé. On doit donc établir les états de l'automate ainsi que les transitions entre les différents états. Une transition est constituée par un prédicat de transition, c'est-à-dire une expression booléenne dont l'évaluation conditionne la transition. Chaque état est éventuellement associé à une liste d'actions associée. Cette construction est effectuée par un parcours de l'organigramme. Les jonctions correspondent à un état de l'automate. Un état de démarrage est ajouté systématiquement, c'est l'état correspondant à la jonction SO de la Fig. 3. Il correspond à un état d'attente de lancement du processus. L'automate sort de cet état sur réception d'un signal `go' non présent dans la spécification fonctionnelle qui matérialise la possibilité de démarrage externe du processus. Avantageusement un signal similaire `clone' est généré pour indiquer la fin du traitement. Les transitions d'un état vers un autre sont établies lorsqu'une boîte ou une décision pointe vers une nouvelle jonction. Tous les éléments qui se trouvent entre deux jonctions sont automatiquement réécrits comme code associé à l'état de la première jonction. Ce code correspond à la liste d'actions associée à l'état. Ce code est alors sans boucle de répétition. Il peut comprendre un ensemble de primitives conditionnelles, primitive IF, imbriquées. Ces caractéristiques correspondent aux gabarits de synthèse d'un langage RTL tel que le VHDL par exemple. Les actions réalisées dans un état particulier associé à une jonction correspondent à l'ensemble des chemins d'exécution entre cette jonction et toute autre 20 jonction. Cette façon de construire l'automate et ses états conduit à un traitement avantageux de l'implémentation des variables du programme initial. Dans les techniques connues de synthèse, typiquement, chaque variable est implémentée dans un registre. Les états générés sont connus sous le nom de bloc basique (basic bloc en 25 anglais). Ces blocs basiques sont constitués d'instructions consécutives en mémoire avec un seul point d'entrée et un seul point de sortie. Ces blocs ne contiennent pas de branchements internes, tout branchement marque forcément une fin de bloc. Selon l'invention, le traitement combinatoire associé à un état de l'automate comprend l'ensemble des boîtes et branchements issus d'une jonction. Ce traitement 30 peut donc contenir des branchements, des tests et des calculs. Il vient donc que ces traitements sont plus complexes que les traitements associés à un bloc basique des méthodes connues. La conséquence est que lorsqu'une variable fait l'objet d'un traitement, la méthode connue va provoquer le stockage dans un registre de cette variable pour chaque calcul et donc de chaque résultat intermédiaire. Au contraire, notre procédé permet de générer un traitement combinatoire du calcul impliquant une variable ne nécessitant pas de stockage des résultats intermédiaires dans un registre. Une variable modifiée dans un même état de la machine s'incarne en une variable VHDL modifiée en combinatoire au sein de l'état. Avantageusement, la dernière modification de la variable au sein de l'état est sauvegardée sous la forme d'un signal stocké dans un registre. L'étape 2.5 permet alors de traduire l'automate ainsi créé dans le langage RTL choisi. Cette dernière étape est bien connue des procédés de synthèses de haut niveau de l'art antérieur. Le procédé décrit permet d'obtenir une synthèse de haut niveau rapide et dont le résultat, pour chacun des processus, conserve la structure du contrôle initialement présente dans la description en entrée du procédé, ce qui assure une grande lisibilité à l'utilisateur prenant connaissance des résultats du procédé. De ce fait, il est facile à un utilisateur de s'approprier le résultat de la synthèse pour le modifier et l'adapter en fonction de ses besoins. La synthèse est faite sans étape de lien (binding en anglais), cette étape vise traditionnellement à factoriser les composants matériels élémentaires tels que les multiplieurs ou les additionneurs. De ce fait, le résultat obtenu est moins optimisé. Toutefois, lorsque la performance est requise, les outils existent qui peuvent réaliser de manière postérieure sur le RTL généré cette étape de lien et de factorisation. Pour des raisons de rapidité et de simplicité de la synthèse et du résultat généré, il est donc avantageux de ne pas intégrer cette étape de lien au sein du procédé de synthèse. Avantageusement, on utilise la structure de la description initiale sous la forme d'un réseau de processus communiquant pour générer les horloges de fonctionnement des différents processus. En effet, chaque état de l'automate généré est conçu pour s'exécuter de manière simultanée lors d'un pas d'horloge. Le procédé de génération de l'automate conduit à générer des états dont le traitement combinatoire peut être relativement complexe. Ce traitement combinatoire doit être exécuté en un pas d'horloge. Il est donc évident que la durée de ce pas d'horloge ne peut être inférieure au temps nécessaire pour effectuer le traitement de l'état le plus complexe. Lorsque les différents processus communiquant possèdent un niveau de complexité dans les traitements hétérogènes, on pourra avantageusement générer une horloge de fonctionnement distincte pour chacun des processus du réseau de processus communicants en fonction de sa complexité. Ainsi, les processus dont les traitements sont simples pourront utiliser une horloge plus rapide que les processus mettant en oeuvre des traitements plus complexes. Les différents processus sont synchronisés ensuite par leurs communications. On atteint ainsi un meilleur rendement du matériel généré en fonction des contraintes de l'applicatif implémenté.5 REVENDICATIONS1/ Procédé de synthèse de haut niveau d'une application sous la forme d'un langage de description matérielle des transferts de registres caractérisé en ce qu'il 5 comporte exécutées par un dispositif de traitement de l'information : - une étape (2.1) de lecture d'une description de l'application sous la forme d'un réseau de processus communicants ; - une étape (2.3) de construction d'un organigramme de flot de contrôle pour chaque processus de l'application ainsi décrite ; 10 - une étape (2.4) de construction d'un automate d'états finis pour chaque organigramme de flot de contrôle ; - une étape (2.5) de traduction de chaque automate sous la forme d'un langage de description matérielle des transferts de registres. 15 2/ Procédé selon la revendication 1, caractérisé en ce que l'étape (2.1) de lecture d'une description de l'application comprend une étape de lecture d'une déclaration des différents ports de communication pour chaque processus. 3/ Procédé selon la revendication 2, caractérisé en ce que l'étape (2.1) de lecture 20 d'une déclaration des différents ports de communication pour chaque processus, comprend la lecture du type du port, ce type pouvant être synchrone ou asynchrone. 4/ Procédé selon la revendication 2, caractérisé en ce que l'étape (2.1) de lecture d'une description de l'application comprend une étape de lecture des communications 25 entre les processus décrits sous la forme de primitives d'émission et de réception de messages sur les ports de communication. 5/ Procédé selon la revendication 4, caractérisé en ce qu'il comporte en outre une étape (2.2) de remplacement des primitives d'émission et de réception de 30 messages par des primitives de plus bas niveau. 6/ Procédé selon l'une des revendications 1 à 5, caractérisé en ce que l'étape (2.3) de création de l'organigramme de flot de contrôle crée un organigramme consistant en :- boîtes correspondant à une séquence de traitement s'exécutant de manière atomique ; - décisions précisant le flot de contrôle en fonction du résultat de l'évaluation d'une condition ; - jonction insérée en amont de toute boîte ou décision destination de plusieurs flots de contrôle ou pour séparer deux étapes de calcul intrinsèquement séquentielles. 7/ Procédé selon l'une des revendications 1 à 6, caractérisé en ce que l'étape (2.4) de création de l'automate d'états finis comprend : - une étape de création d'un état correspondant à chaque jonction de l'organigramme ; - une étape de création d'une transition d'un état vers un autre lorsqu'une boîte ou une décision pointe vers une nouvelle jonction ; - une étape de création d'un code associé à un état constitué des éléments se 15 trouvant entre la jonction correspondant à cet état et la suivante. 8/ Procédé selon l'une des revendications 1 à 7, caractérisé en ce qu'il comporte une étape de génération d'une horloge de fonctionnement distincte pour chacun des processus dudit réseau de processus communicants. 9/ Procédé selon l'une des revendications 1 à 8, caractérisé en ce qu'il comporte une étape de génération d'un traitement combinatoire du calcul impliquant une variable ne nécessitant pas de stockage des résultats intermédiaires dans un registre. 25 10/ Procédé selon la revendication 9, caractérisé en ce que la dernière modification de la variable au sein de l'état est sauvegardée sous la forme d'un signal stocké dans un registre. 20