l'applet xLogicCircuits2

(see english version)

L'appliquette liée à cette page vous permettra de simuler des circuits logiques décrits au niveau structurel. Il s'agit d'un outil interactif d'initiation à la logique combinatoire et séquentielle. Seul l'aspect comportement "logique" est simulé, pas le comportement électrique réel (en particulier, les temps de propagation sont unitaires, la logique n'a que 2 états et il n'y a aucun rebond sur les entrées). L'appliquette xLogicCircuits fait originellement partie d'une collection d'applets écrite par  David Eck et pouvant être utilisées avec son livre d'introduction aux ordinateurs : The Most Complex Machine. (Mais elles peuvent être utilisées indépendamment de ce livre.). Pour obtenir la liste des autres appliquettes et pour des fiches d'exercices les mettant en oeuvre, voir  la page index de David Eck.

L'appliquette xLogicCircuits a été "enrichie" par Jean Conter afin de pouvoir créer des circuits plus complexes. Une ouverture vers un langage de description structurel, le langage MDL, est également proposée. La description qui suit correspond à la version "enrichie" de xLogicCircuits (appelée xLogicCircuits2).

Aujourd'hui,  xLogicCircuits2 permet de disposer de 9 composants de base : 5 portes (dont un multiplexeur), 3 bascules et une mini-mémoire de 16 bits. Ces composants peuvent être mis en oeuvre immédiatement : par exemple, vous pouvez prendre le circuit XOR3, lui associer 3 entrées et une sortie (la définition d'une porte Ou Exclusif (XOR) est telle que la sortie vaut '1' si et seulement si un nombre impair d'entrées sont à '1' (les autres étant à '0'). Pour que le circuit soit opérationnel, il faut simplement cocher la case "Power" en bas de l'appliquette. Dans ce mode, tout clic sur une entrée permet de changer son état.

Grâce au compilateur du langage MDL,  un circuit  conçu avec xLogicCircuits2 pourra être synthétisé très facilement sur un FPGA réel (en utilisant les environnements intégrés ISE WebPack ou Quartus II Web Edition) et vous pourrez donc vite découvrir le charme et la puissance de l'émulation (par rapport à la simulation).
Pour le fonctionnement de base, lire le document de David Eck adapté par Ph. Tixier. Pour les nouveautés, quelques détails figurent sur cette page après l'appliquette.
xLogicCircuits2 peut également être lancée dans sa propre fenêtre (ce qui permet de la déplacer et de la redimensionner) en cliquant sur le bouton suivant : (Désolé, votre navigateur ne gère pas Java!)


(Java not available.)


Créer des circuits logiques en quelques clics

Vous pouvez construire un circuit en glissant/déposant des items (composant ou entrée ou sortie) pris dans le tiroir à composants (partie gauche de l'appliquette) puis en interconnectant ces items. Il faut au minimum une entrée et une sortie pour chaque circuit. Chaque connexion doit être établie en partant de la source du signal et en allant vers une entrée de l'item de destination. Pour rendre la disposition des fils plus 'lisible', il est également possible de placer des Plots (Pin en anglais, Tack en américain) : cela se fait en double-cliquant sur le fil. Le Plot ainsi tracé peut alors être déplacé à la souris (bouton droit). A la différence de la version originale de David, les segments encadrés par des Plots constituent désormais une équipotentielle : le temps de traversée d'un Plot est donc nul. Les connexions peuvent être faites même quand le bouton "Power" est actif.
Bien entendu, une fois un circuit créé, il peut être "iconisé" et  utilisé comme brique de base dans un circuit plus complexe : cette modularité est fondamentale car elle permet une vraie description hiérarchique et rationnelle.


Nouvelles fonctionnalités (xLogicCircuits2)

Des tampons à sortie haute-impédance, un OU exclusif, un multiplexeur à 2 entrées, trois bascules (D, T et JK) ainsi qu'une mémoire de 16 bits ont été ajoutés aux items de base. Un signe + situé en haut à droite de chaque case d'item permet de choisir parmi différentes versions (avatars) de chaque item. Ainsi, pour le ET logique, on dispose maintenant de 4 versions de ET à 2 entrées et de 4 versions de ET à 3 entrées (on obtient ainsi un NI (NOR) à 2 entrées et un NI à 3 entrées).

Pour le OU exclusif (XOR), il n'y a que 4 avatars : XOR2, XNOR2, XOR3 et XNOR3 (NB: XNOR(A,B,C) = XOR(/A,B,C) )

Pour le Multiplexeur, les 3 entrées (2 données et une sélection) sont inversibles

Pour les Bascules (FF), il est possible d'inverser la première entrée (resp. D, T et J), de choisir le front d'horloge ainsi que la polarité de la mise à zéro asynchrone. Pour les bascules D et T, il est également possible de disposer d'une entrée de validation inversible.

Pour la Mémoire, il n'y a que 2 versions : RAM (16 bits, lecture asynchrone, écriture synchrone avec Wclk et WE) et ROM (16 bits, lecture asynchrone). C'est ce dernier composant qui permet d'implémenter la fonctionnalité de 'porte universelle', mais celle-ci reste cependant limitée à 4 entrées maximum. Il est également possible d'engendrer une ROM à partir d'une RAM dont on a défini le contenu dynamiquement : il suffit de ne plus raccorder les 3 entrées Data, Wclk et WE puis de sauver.

Au total, les 9 items de base ainsi que leurs avatars sont représentés sur le schéma suivant :

Avatars

Un support minimal du langage MDL a été introduit. En particulier, les signaux sont nommés (et peuvent être renommés en double-cliquant sur l'item source à condition d'être hors mode "Power"). Les noms des signaux d'interface (entrées et sorties) apparaissent sur le schéma et en facilitent l'interprétation. La version actuelle de xLogicCircuits2 est loin d'être parfaite ( cf . bogues et limitations connues) mais permet néanmoins de tester rapidement des idées de conception logique.

Les boutons "Save" et "Load" permettent de travailler avec des fichiers (cependant cela n'est pas possible à priori car le système de sécurité associé aux applets ne l'autorise pas par défaut : il faudra donc utiliser policytool pour donner un droit d'accès aux fichiers en lecture et/ou en écriture ou bien lancer xLogicCircuits2 en tant qu'application). Par contre, il sera toujours possible d'obtenir un équivalent MDL du circuit en appuyant sur le bouton "MDL" : la sortie se fait alors dans la console Java (il faut configurer le navigateur pour permettre l'affichage de celle-ci)  ou bien sur le terminal si l'applet xLogic2 a été lancée par appletviewer. Un copier/coller permet alors de sauver ce texte (à suffixer en .MDL) dans le répertoire choisi. Le fichier MDL obtenu par cette seconde méthode est plus compact car il supprime tous les Plots (ce qui n'a aucun impact sur la fonctionalité) alors que le fichier MDL figurant en fin de fichier xLogic tient compte des Plots (ce qui préserve la présentation graphique). Dans tous les cas, avant de sauver un circuit, pensez à mettre à jour le nom de celui-ci dans la fenêtre "Title".
La version actuelle des fichiers est transitoire : elle conserve (avec de légères modifications) la structure originelle : elle ajoute cependant des informations du langage MDL ; le fichier produit gagne alors en lisibilité.Cependant, l'applet ne prend pas (encore) en charge un circuit directement décrit en MDL : il faut pour cela utiliser le compilateur MDLC qui fabrique un fichier .xlg lisible par l'applet.


Le programme de démonstration (sampLFSR)

Le circuit sampLFSR ci-dessus est un exemple de circuit simple en apparence : à partir de 4 bascules et sans aucune logique additionnelle, il permet de cycler sur 15 états (soit un de moins que le maximum possible) : il s'agit d'un registre à décalage à rétroaction linéaire (LFSR de type Fibonacci) bâti comme un compteur de Johnson dont on aurait remplacé la bascule /D de tête par une bascule /T.
Pour faire marcher cet exemple, il suffit d'activer le bouton "Power".
Attention, si cela va trop vite, choisissez une vitesse "Moderate" ou bien "Slow" afin de suivre plus confortablement l'évolution des états.
NB: prenez garde d'éviter l'état où toutes les bascules sont à 1 : c'est l'état collé (stuck state) dont on ne sort que par une remise à zéro forcée (entrées de RAZ asynchrone ou bien mise hors tension momentanée).


Introduction à la description structurelle

La description structurelle est une description proche du matériel qui, bien conduite, permet de tirer le maximum de celui-ci. C'est un peu l'équivalent de la programmation en langage d'assemblage pour le logiciel. Habituellement, cette approche est réservée aux connaisseurs et en particulier à ceux qui développent des bibliothèques de primitives que d'autres pourront utiliser sans difficulté. En ce sens, c'est une démarche ascendante (Bottom-up design) dans laquelle on élabore des briques de base que l'on assemblera ultérieurement. A contrario, une démarche descendante (Top-down design) sera utilisée dans une description comportementale : l'implémentation étant alors traitée en bout de chaîne. La démarche comportementale, fondamentale pour le travail en équipe sur de gros projet, fait souvent peu de cas du matériel cible (par volonté ou par ignorance).
La démarche structurelle, qui part du matériel, ne doit cependant pas être réservée aux spécialistes : grâce à des outils simples (voire simplistes), dont xLogicCircuits2, il sera possible d'en apprécier les bénéfices. Une fois les bases maîtrisées, il sera toujours loisible d'utiliser des outils plus puissants qui modélisent plus finement la réalité. Une connaissance préalable de la logique combinatoire et séquentielle ainsi que celle de la syntaxe MDL sera cependant nécessaire.

Commençons par un exemple classique : un additionneur série. Il s'agit d'un circuit séquentiel basé sur un additionneur complet et une bascule D. Voyons d'abord les différentes façons de décrire un additionneur complet au niveau structurel. Trois solutions pour l'additionneur complet sont regroupées sur l'applet suivante :


(Java not available.)


 

Première approche (premier circuit en haut de l'applet ADDERS): on dispose d'un matériel permettant de réaliser directement toute fonction combinatoire de 3 signaux (par exemple au moyen d'une Look Up Table, ce qui sera réalisé avec l'item ROM sous xLogicCircuits2)
dans ce cas, on utilise 2 portes logiques : une pour la retenue R et une pour la somme S (NB: pour la somme, on pourrait aussi écrire : S=A@B@C). Ci-dessous, le texte MDL de droite équivaut  au schéma de gauche : l'ensemble des deux représentations sera désigné par le terme 'Schéma-Texte' . Les informations de position (;P=x,y) et de valeur (;V=0 ou 1 ou ?) ne sont pas nécessaires : elles permettent simplement de définir respectivement le positionnement graphique des items (portes, bascules, modules) sur le schéma ainsi que les valeurs initiales des signaux (ce qui permet d'imposer un état de départ pour un circuit séquentiel). Les étiquettes (MARQUES) pour R et S sont également facultatives : elles visualisent le nom et la valeur d'un signal.

ADDER

Seconde approche (circuit du milieu) : supposons maintenant que le matériel disponible n'autorise que des fonctions logiques de 2 signaux. Dans ce cas, grâce à l'associativité des opérateurs ET, OU inclusif et OU exclusif, on décomposera le circuits en 7 portes, ce qui s'écrira par exemple :

ADDER1

Enfin (circuit du bas), supposons que l'on dispose, en plus des fonctions logiques de 2 signaux, de la fonction Multiplexeur à deux voies (qui est donc un opérateur à 3 entrées). Dans ce cas, le circuit final peut être considérablement simplifié : la retenue R est obtenue directement en sortie du multiplexeur car, si X=0, cela signifie que A et B sont identiques et que, par conséquent, si A=1 (on pourrait aussi prendre B) alors R doit valoir 1. De même, si X=1, cela signifie que A et B sont différents et que par conséquent C=1 entraîne R=1. Un outil de synthèse automatique aura probablement du mal à trouver une optimisation de ce genre.

ADDER2

Cette dernière description est particulièrement bien adaptée pour être implantée sur un FPGA basé sur des multiplexeurs comme le vénérable XC6216 (successeur du CAL1024 d'Algotronix) : dans ce FPGA, chaque cellule peut abriter une fonction logique de 2 signaux (ou de 3 signaux dans le cas d'un multiplexeur) et une bascule D. Chaque cellule est reliée à chacune de ses 4 voisines directes par deux liens unidirectionnels (un lien d'entrée et un lien de sortie). Voici un exemple de placement et de routage du circuit précédent sur 3 cellules du FPGA XC6216 : veuillez noter la correspondance quasi parfaite entre la description graphique (circuit en bas de l'applet ADDERS et schéma MDL ci-dessus) et l'implémentation dans le FPGA! (l'origine des coordonnées est cependant différente). Vous noterez également certaines inversions (figurées par de petits cercles) à la frontière des cellules : ces inversions sont dues à un choix d'implémentation pour les traversées directes (routage de cellule) mais sont gérées automatiquement par le compilateur (notez le XOR X devenu XNOR pour tenir compte de l'inversion de routage sur le chemin de A). La description MDL ci-dessous impose le placement de X, R et S respectivement dans les cellules (0,0), (0,1) et (1,0) : le compilateur fait le reste (routage notamment) et engendre un fichier CAL (le fichier bitstream du XC6216, représenté à droite ) qui à son tour permet de configurer le FPGA conformément à la figure de gauche.

ADDCAL

Bien entendu, la description structurelle illustrée ci-dessus ne prend tout son sens que lorsque l'on maîtrise totalement la synthèse dans le FPGA, c'est-à-dire quand on contrôle la production du bitstream (il s'agit du fichier de configuration du FPGA), ce qui n'est possible qu'avec très peu de FPGA. Le XC6216 fait partie des FPGA à bitstream ouvert (public) et c'est pourquoi nous l'utiliserons intensivement dans nos expérimentations. Bien que ce circuit ne soit plus disponible commercialement, vous pourrez néanmoins vous en servir, grâce à la magie d'internet (pour savoir comment, voir ici).

Dernière étape : l'additionneur série. Il est réalisé en ajoutant une bascule D qui mémorise la retenue de l'addition précédente des deux entrées A et B. On 'économise' une sortie (R devient un signal local) mais on doit ajouter deux entrées : un signal d'horloge (GCLK) et un signal pour la mise à zéro initiale de la bascule (GCLR). Dans le cas du XC6216, la bascule D peut être placée dans la même cellule que le multiplexeur (x=0,y=1): on obtient alors le circuit représenté  ci-dessous (version a). En fait le circuit effectivement visualisé par l'applicatif Calview sera celui représenté au niveau inférieur ( représentation synthétique), circuit dont la description structurelle en MDL serait la version b. Cela indique simplement que les 2 descriptions MDL a et b, structurellement différentes, sont fonctionnellement équivalentes.

SERADDALL

Représentation graphique synthétique: en principe, la description structurelle permet de conserver une implantation parfaitement conforme à celle prévue. Cependant, quelques dérogations sont parfois utiles : ainsi une bascule T peut être réalisée en associant une porte XOR à une bascule D (c'est notamment le cas avec le XC6216 dans lequel d'ailleurs le XOR est lui-même implémenté avec des multiplexeurs) : doit t'on conserver une représentation graphique proche de l'implémentation ou bien utilise-t'on une représentation plus  'fonctionnelle' ? Nous avons choisi cette seconde solution, car plus synthétique donc plus lisible, tout en sachant qu'une seule cellule logique étant impliquée, les caractéristiques temporelles seront parfaitement déterminées. Cet 'aménagement' ne concerne que l'aspect graphique, la description MDL, par contre, respectant scrupuleusement la structure. Les versions  MDL a et b ci-dessus de l'additionneur série sont donc bien différentes (et donneront d'ailleurs des implémentations différentes si on utilise des outils de synthèse automatiques) mais, dans le cas particulier d'un ciblage sur XC6216 par le compilateur MDLC, fourniront exactement la même implémentation (le même fichier CAL) : la représentation graphique effective sera alors la représentation la plus synthétique, c'est à dire la version graphique b.  

      Dernier exemple : un registre additionneur : dans ce cas, ce n'est pas la retenue que l'on mémorise (cas de l'additionneur série) mais la somme. Nous avons vu que le circuit de retenue pouvait être réalisé avec un simple multiplexeur. La description d'un registre additionneur pourra donc se faire de la façon suivante:

ADDREGD ADDREGD

Si l'on choisit la solution de gauche, nous constatons que la bascule de sortie peut être remplacée par une bascule T, comme suit :

ADDREGT

Nous pouvons donc aisément implanter cette 'tranche' dans trois cellules horizontales du FPGA et instancier ces tranches autant de fois que nécessaire. Pour un registre additionneur 6 bits, nous obtiendrons le circuit suivant (avec la description générique MAC correspondante):

RADDER6T


 

Conclusion

Si l'on dispose d'outils adaptés, il est encore possible de pratiquer la synthèse fonctionnelle, comme au 'bon vieux temps'. Il s'agit d'une approche basée sur l'expérience permettant de tirer le maximum du matériel. Cette approche concrête tend à disparaître au profit d'outils de synthèse automatiques qui, à mon avis, déqualifient à terme leurs utilisateurs. Il y a bien sûr de bonnes raisons, y compris techniques, à cette évolution. Une des bonnes raisons, liée à l'exploitation massive des FPGAs, est que le temps de propagation dans les connexions (les fils) n'est plus du tout négligeable (il peut parfois même être supérieur!) face à celui passé dans les fonctions (les cellules logiques) : ceci altère bien entendu le raisonnement en terme de synthèse fonctionnelle. Ce handicap est, toute proportion gardée, similaire à celui rencontré par les programmeurs en langage d'assemblage sur des architectures RISC : tous ces NOP à insérer aux endroits stratégiques ressemblent un peu aux délais de connexion et gâchent sensiblement la lisibilité du programme et le plaisir du programmeur. Pour les FPGA c'est un peu semblable : doit-on garder un niveau sémantique élevé (grosse granularité resp. CISC) ou bien réduire le niveau sémantique (granularité fine resp. RISC) pour faciliter le travail des compilateurs et outils de synthèse ? Mon opinion est faite depuis longtemps : simplifier l'écriture d'un compilateur ou d'un outil de synthèse ne concerne que des milliers de personnes alors que simplifier l'écriture d'une application (ce qui impliquerait des compilateurs plus complexes...) concerne des millions de personnes! Les langages et les compilateurs étant ce qu'ils sont, nous sommes malheureusement condamnés à utiliser des outils imparfaits. MDLC (le compilateur du langage MDL) n'échappe pas à la règle : il est parfois pointilleux, parfois trop permissif !... Malgré tout, la possibilité de décrire au niveau structurel permet de mieux maîtriser ce que l'on engendre et, en particulier, de relancer des études sur les circuits séquentiels asynchrones, peu aidés par les outils logiciels et matériels disponibles d'aujourd'hui, et pourtant porteurs d'avenir.
    J'espère que la mise en ligne d'outils de conception simples permettra de susciter de nouvelles vocations en favorisant l'imagination et la créativité plutôt que le suivisme fondé sur la copie directe de solutions souvent inadaptées. 


Jean Conter (conter@enseeiht.fr),January 2006