ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 1 - Spécification des circuits logiques avec AHDL Seconde partie : exercices et utilisation V oici un ensemble d’exercices à traiter avec AHDL. Il semble difficile de les traiter tous en une séance unique, il est demandé d’en résoudre un ou plus … selon le temps disponible. On peut également en proposer d’autres (la faisabilité et l’intérêt sont à discuter). Il faut donc choisir un exercice, poser le problème, préparer une solution originale, puis la spécifier en AHDL et valider par simulation avec l’environnement MaxPlusII d’Altera. L’objectif est de réaliser un microprojet, chercher les informations sur AHDL nécessaires pour résoudre le problème choisi et y apporter une solution personnelle, découvrir fonctionnalités et limites de l’outil proposé ... Exercices suggérés: 1. Construire un additionneur sur 16 bits (cf. subdesign addit donné en annexe): A(16 bits)+B(16 bits)+CY(retenue) R(16bits)+ CY1(retenue suivante) Puis, on le modifiera pour en faire un additionneur soustracteur 16 bits commandé par un bit nommé sgnop (sgnop= 0 addition, sgnop=1 soustraction) avec le code en complément à 2. On peut utiliser la propriété : a XOR 1 = NON a et a xor 0 = a, pour complémenter à 1 et incrémenter avec l’entrée CY pour passer uu complément à 2. Autre amélioration, le résultat est donné dans le format valeur absolue plus signe (signe = 1 pour négatif, 0 pour positif). Comment créer un bit de débordement OVF ? A A C B B B 1 Cy Cy1 C |C| signe Cy Cy1 sgnop=1 sgnop=0 2. Construire le séquenceur pasapas.tdf de la commande biphase des 4 enroulements ou phases d’un moteur pas à pas. On peut s’inspirer de stepper.tdf tiré des exemples ahdl. On souhaite alimenter les quatre phases selon la séquence suivante : alimenter phase3 seule, puis phase3 et phase2 simultanément, ensuite phase2, puis phase2 et phase1, etc ... pour faire tourner le moteur dans un sens en utilisant tour à tour les huit positions d’équilibre du rotor à chaque front montant de l’horloge clk: phases[3..0]= 1000,1100,0100,0110,0010,0011,0001,1001,1000 … On ajoute deux entrées binaires direct et inverse fixant chacune un sens de rotation du moteur ainsi qu’un signal reset qui ramène le rotor à la position initiale (valeur 1000). D’autre part, on utilise un compteur/décompteur pour tenir à jour la position actuelle du rotor en comptant les fronts de clk dans un sens de rotation et en décomptant dans l’autre sens ; le signal reset remet ce compteur à zéro. AB CD A Phase1 B 1000 1100 C D 0110 0010 ... ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 2 - 3. Détecteur de sens de rotation detect.tdf (cf. le principe utilisé pour les déplacements des souris). On dispose de deux entrées binaires A = Xclock, B = Xdata issues d’un codeur incrémental (disque gravé ou troué .. ouvrir sa souris) qui tourne quand on déplace la souris. Dans le sens gauche droite, on observe que A passe à 1, puis B passe à 1, puis A passe à 0, puis B etc... alors que B précède A dans le sens droite gauche. A partir de ces deux entrées et de l’horloge clk plus rapide (4 MHz) pour échantillonner A et B, construire un automate doté de 8 états à définir s0 , s1 ... s7 , et la sortie binaire sens qui donne le sens du déplacement actuel selon la séquence observée sur A et B. Ajouter l’information de l’amplitude du déplacement en comptabilisant les impulsions sur A ou B. disque A et B, sens 1 A codeur B instants d’échantillonnage temps A et B sens 2 Annexes : Exemple d’additionneur série 8 bits : analyser et simuler cet exemple dans un premier temps, puis modifier pour en faire un soustracteur commandé par la valeur sgnop constant NUMBIT=8; SUBDESIGN addit ( a[NUMBIT..1], b[NUMBIT..1], cin : INPUT; c[NUMBIT..1], cout : output; ) VARIABLE sum[NUMBIT..1], carryout[(NUMBIT+1)..1]: NODE; BEGIN carryout[1]=cin ; FOR i IN 1 TO NUMBIT GENERATE sum[i]= a[i] $ b[i] $ carryout[i]; % full adder % % $ est le ou exclusif, # est le ou et & le et % carryout[i+1]=a[i] & b[i] # carryout[i] & (a[i] $ b[i]); end generate; cout = carryout[NUMBIT+1]; c[]=sum[]; END; ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 3 Lors de l’addition, on visualise les résultats transitoires sur les diagrammes temporels. Utiliser l’opérateur + de ahdl, soit a[]+b[] au lieu de addit mène à un comportement semblable. Exemple de création de séquenceur, machine à nombre d’états fini (voir également simple.tdf pour une autre syntaxe) SUBDESIGN stepper ( clk, reset : INPUT; ccw, cw : INPUT; phase[3..0] : OUTPUT; ) VARIABLE ss: MACHINE OF BITS (phase[3..0]) WITH STATES ( s0 = B"0001", s1 = B"0010", s2 = B"0100", s3 = B"1000"); BEGIN ss.clk = clk; ss.reset = reset; % reinitialisation de la machine TABLE ss, ccw, cw => ss; s0, 1, x => s3; s0, x, 1 => s1; s1, 1, x => s0; s1, x, 1 => s2; s2, 1, x => s1; s2, x, 1 => s3; s3, 1, x => s2; s3, x, 1 => s0; END TABLE; END; Les instructions suivantes extraient valeur absolue et signe (1 pour <0, 0 pour >0) d’une entrée Ca2[N..0] : variable valabs[N..0] : node ; signe=Ca2[N] ; if signe then valabs[]= (Ca2[ ] $ VCC)+1 ; else valabs[ ]= Ca2[ ] ; end if ; (a,b,c,d,e,f) définit un groupe de bits en ahdl, à partir de sous groupes a, b,c, … de même que a[7..4] équivaut au groupe (a7, a6, a5, a4). L’overflow OVF peut être défini ainsi à partir des de s a , sb , s r signes des opérandes et du résultat, et de sgnop qui indique l’opération réalisée : OVF sgnop(sa sb * sr * sa * sb sr ) sgnop * (sa sb sr * s a * sb * sr ) ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 4 comparateur 16 bits if a[ ]== b[ ] then aeqb= VCC ; elsif a[ ]>b[ ] then agtb = VCC ; elsif a[ ]<b[ ] then altb = VCC ; end if ; Quand la fonction logique synthétisée est trop importante, le compilateur ahdl demande l’autorisation d’ajouter de la place, et de choisir des circuits logiques programmables EPLD plus grands, cocher la case « Add extra devices as needed ». Pour changer le format d’affichage des groupes binaires dans les diagrammes temporels, il faut détruire le groupe « Ungroup », choisir un format Hexa, Décimal, Binaire, etc … et refaire le groupe « Enter group » Attention au comptage en code Gray, ou code binaire réfléchi, le code des diagrammes de Karnaugh où le nombres successifs varient d’un bit seulement. Il donne des comportements bizarres, tels que « 2+2=5 » ! ! ! Les subdesigns ahdl ne sont pas des programmes exécutant des instructions en séquence, ce sont des spécifications textuelles de connexions de signaux logiques, la plupart du temps, l’ordre des instructions n’a pas d’importance, puisqu’il ne correspond pas à une cohérence de calcul. De plus, une instruction du type a = a +b sera refusée, parce qu’il s’agit de relier un signal a à une valeur différente a+b (court circuit). Enfin, on préfèrera a= VCC pour mettre a au niveau logique un. Suggestion d’autres exercices (non exhaustif …) Comment créer un décodeur BCD 7 segments nommé BCD.tdf dans un projet BCD ? Utiliser ce composant pour afficher 1999. Créer la fonction Valse.tdf qui convertit le format Valeur Absolue + signe en format complément à deux sur 8 bits : Entrée VA+Signe , sortie Cà2, Créer la fonction inverse : entrée Cà2, sortie VA+Signe. Obtenir un comparateur 16 bits comp16.tdf à partir de comparateurs 4 bits à retrouver dans les bibliothèques de MAXPLUSII : les entrées sont A(16 bits) et B(16 bits) et les 3 sorties binaires sont notées AgtB, AltB et AeqB. Proposer une autre méthode plus simple. Comment construire un compteur synchrone modulo 2000 dans ctr2000.tdf ? et un compteur décompteur commandé par une variable logique updown ? Réaliser dans distrib.tdf les équations du distributeur de boissons E , M , C , R f ( e, m, c, p ) Réaliser une logique de décodage adressant un périphérique P1 (signal CS1=1) si R/W=1 et ALE=1 et un second périphérique P2 (signal de validation CS2=1) si ALE=1 et R/W=0. Constituer un registre à décalage 8 bits shiftr.tdf fonctionnant en mode Parallel Input Serial Output PISO. Utiliser une ALU (Arithmetic and Logic Unit) pour effectuer diverses opérations sur deux opérandes A et B contenus dans des registres 8 bits. Peut on piloter l’Universal Asynchronous Receiver Transmitter UART inclus dans l’environnement ? Sur l’entrée RxD, on lit successivement Startbit, B0, B1, ... B7, Stopbit. Le circuit mémorise les Bi dans un registre à décalage, qui est lu quand il est plein. C’est la conversion parallèle série SIPO. La conversion inverse est réalisée sur la sortie TxD ? On prendra 19200 bauds. Peut on réaliser multiplieur binaire par additions et décalages (ou par un autre moyen) ? ... ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 5 - constant NUMBIT=16; SUBDESIGN addsub ( sgnop, clk, a[NUMBIT..1], b[NUMBIT..1], cin : INPUT; c[NUMBIT..1], cout, sgnout : output; ) VARIABLE sum[NUMBIT..1], carryout[(NUMBIT+1)..1]: NODE; BEGIN carryout[1]=cin # sgnop; FOR i IN 1 TO NUMBIT GENERATE sum[i]= a[i] $ (b[i] $ sgnop) $ carryout[i]; % full adder % -- $ est le ou exclusif, # est le ou et & le et carryout[i+1]=a[i] & (b[i] $ sgnop) # carryout[i] & (a[i] $ (b[i] $ sgnop)); end generate; cout = carryout[NUMBIT+1]; sgnout = sum[NUMBIT]; if !sgnout then c[]=sum[]; else c[]= (sum[] $ VCC)+1; end if; END; -------------------------------------------------------------------------------------------------------------constant NBITS= 15; SUBDESIGN pasapas ( clk, reset : INPUT; direct, inverse : INPUT; A,B,C,D, : OUTPUT; ) position[NBITS..0] VARIABLE pos[NBITS..0]: DFF; ss: MACHINE OF BITS (A,B,C,D) WITH STATES ( s0 = B"1000", s1 = B"1100", s2 = B"0100", s3 = B"0101", s4 = B"0001", s5 = B"0011", s6 = B"0010", s7 = B"1010"); BEGIN ss.clk = clk; ss.reset = reset; ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 6 pos[].clk=clk; pos[].clrn = !reset; if direct then pos[].d=pos[] +1; elsif inverse then pos[].d=pos[]-1; end if; position[]=pos[]; TABLE ss, direct, inverse => ss; %-----------------------------------------------% s0, 1, x => s7; s0, x, 1 => s1; s1, 1, x => s0; s1, x, 1 => s2; s2, 1, x => s1; s2, x, 1 => s3; s3, 1, x => s2; s3, x, 1 => s4; s4, 1, x => s3; s4, x, 1 => s5; s5, 1, x => s4; s5, x, 1 => s6; s6, 1, x => s5; s6, x, 1 => s7; s7, 1, x => s6; s7, x, 1 => s0; END TABLE; END; ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 7 - subdesign detect( clk : input; reset : input; a,b : input; s : output;) variable ss: machine with states (s0,s1,s2,s3,s4,s5,s6,s7); begin ss.clk = clk; ss.reset= reset; table ss, a, b => s, ss; %------------------------------------% s0, 0, 1 => 0, s1; s0, 1, 0 => 1, s6; s0, 1, 1 => 0, s0; s0, 0, 0 => 0, s0; s1, 1, 1 => 0, s3; s1, 0, 0 => 1, s4; s1, 1, 0 => 0, s1; s1, 0, 0 => 0, s1; s2, 1, 1 => 1, s7; s2, 0, 0 => 0, s0; s2, 1, 0 => 0, s2; s2, 0, 1 => 0, s2; s3, 1, 0 => 0, s2; ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 8 s3, 0, 1 => 1, s5; s3, 1, 1 => 0, s3; s3, 0, 0 => 0, s3; s4, 0, 1 => 0, s1; s4, 1, 0 => 1, s6; s4, 1, 1 => 1, s4; s4, 0, 0 => 1, s4; s5, 1, 1 => 0, s3; s5, 0, 0 => 1, s4; s5, 1, 0 => 1, s5; s5, 0, 1 => 1, s5; s6, 1, 1 => 1, s7; s6, 0, 0 => 0, s0; s6, 1, 0 => 1, s6; s6, 0, 1 => 1, s6; s7, 0, 1 => 1, s5; s7, 1, 0 => 0, s2; s7, 1, 1 => 1, s7; s7, 0, 0 => 1, s7; end table; end; ------------------------------------------------------------subdesign detect2 % seconde version de detect utilisant case% ( clk : input; reset : input; a,b : input; s : output;) variable seq: machine of bits (s) with states (s0,s1,s2,s3,s4,s5,s6,s7); begin seq.clk = clk; seq.reset= reset; case seq is when s0 => if !a&b then seq=s1; elsif a&!b then seq=s6; end if; when s1 => if a&b then seq=s3; elsif !a&!b then seq=s4; end if; when s2 => if a&b then seq=s7; elsif !a&!b then seq=s0; end if; when s3 => ESSI1 – Spécification des circuits logiques avec AHDL (Jean-Paul Stromboni, 1999) Page - 9 if a&!b then seq=s2; elsif !a&b then seq=s5; end if; when s4 => if !a&b then seq=s1; elsif a&!b then seq=s6; end if; when s5 => if a&b then seq=s3; elsif !a&!b then seq=s4; end if; when s6 => if a&b then seq=s7; elsif !a&!b then seq=s0; end if; when s7 => if !a&b then seq=s5; elsif a&!b then seq=s2; end if; end case; end;