H.D.L optimisé pour la conception des PLD (CPLD - SPLD)
Introduit par DATA I/O, se compose de parties déclaratives et de parties "exécutables", mais comparé par exemple au C++, le résultat de la compilation d'un "programme" HDL sera une solution "hardware" avec une cible "circuit" et non un programme exécutable.
ABEL permet la spécification d'équations, tables de vérité (truth tables), machines d'états (state diagrams), ou toute combinaison des trois. Il est possible de ne pas scpécifier le circuit ("device") final, voire de ne pas donner d'affectations pour les broches d'entrée/sortie. Le format de sortie des fichiers produits par le compilateur permet l'interfacage avec des produits de CAO électronique (dans notre cas il s'agira des outils Xilinx) ainsi que les standard JEDEC pour les programmateurs de PLD ainsi que les programmateurs de PROM. Dans son expression la plus simple, la description est de type RTL (Register Transfer language) i.e. que l'on définit une sortie par une variation de ses signaux d'entrée. ABEL permet d'écrire des structures indépendanters du choix technologique final, qui sera fait après simulation et optimisation (avec généralement une aide par les outils de CAO).
Les rectrictions suivantes s'appliquent :
a - z (alphabet minuscule)
A - Z (alphabet majuscule)
0 - 9 (chiffres)
<espace>
<tabulation>
! @ # $ ? + & * ( )- _ = +
[ { } ] ; : ` " ` ~ \ | , < > . / ^ %
Les règles sont les suivantes :
DECLARATIONS IF STATE_DIAGRAM DEVICE IN (obs) TEST_VECTORS ELSE ISTYPE THEN ENABLE (obs) LIBRARY TITLE END MACRO TRACE ENDCASE MODULE TRUTH_TABLE ENDWITH NODE WHEN FUSES OPTIONS WITH EQUATIONS PIN FLAG (obs) PROPERTY
Système de numération : ABEL supporte le binaire (2), l'octal (8), le decimal (10), l'hexadecimal. Le système par défaut est le décimal (10) et il peut être changé par la déclaration @RADIX. Examples :
56 decimal 56
^h56 hexadecimal 56 (valeur décimale 86)
^b1001 binaire 1001 (valeur décimale 9)
^o56 octal 56 (valeur décimale 46)
^h0E hexadecimal 0E (valeur décimale 14)
Vrai (valeur logique 1) et faux (valeur logique 0) sont représentés comme des nombres entiers 32 bits, vrai = -1 (tous les bits à 1) et faux =0 (tous les bits à 0).
.C. Entrée "clockée" (transition bas-haut-bas)
.K. Entrée "clockée"input (transition haut-bas-haut )
.U. Front montant (transition bas-haut )
.D. Front descendant
.F. Entrée ou sortie "flottante"
.P. Pré-charge de registre
.SVn. n = 2 .. 9. Force l'entrée à un "supervoltage" de 2 à 9V.
.X. Etat indifférent
.Z. Etat "tristate"
Suites de caractères ASCII , avec espaces, encadrés par apostrophes (` `). Les chaînes de caractères sont utilisées dans TITLE, MODULE et OPTIONS, et dans les instructions, broche, noeuds interne (node) et déclaration d'attributs.
`Hello this is a string!'
`Punctuation? is even allowed !!'
`It\'s easy to use ABEL'
`He\\she can use backslashes in a string'
Constantes, noms de signaux sont utilisés dans les expressions. Les expressions combinent, comparent ou effectuent des opérations sur leurs opérandes pour produire un résultat. Les opérations sont indiquées par des opérateurs.
Il y a quatre types de base d'opérateurs pour ABEL-HDL : logique, arithmétique, relationnel, et affectation.
Opérateurs logiques (Logical Operators) :
| ! | !A | NOT: Complément à 1 |
| & | A & B | AND |
| # | A # B | OR |
| $ | A $ B | XOR: exclusive OR |
| !$ | A !& B | XNOR exclusive NOR |
Opérateurs Arithmétiques (Arithmetic Operators) :
- -A Complément à 2 (négation) - A - B Soustraction + A + B Addition
* A*B Multiplication
/ A/B Division entière non signée
% A%B Reste de la division
<< A<<B Décalage de A gauche de B bits
>> A>>B Décalage de A droite de B bits
Opérateurs relationnels (Relational Operators) :
== A == B Egalité
!= A != B Différent
< A < B Inférieur
<= A <= B Inférieur ou égal
> A > B Supérieur
>= A >= B Supérieur ou égal
Opérateurs d'affectation (Assignment Operators) :
Une équation affecte la valeur d'une expression à un signal de sortie. Il y a 4 opérateurs d'affectation, 2 pour le combinatoire et 2 pour les sorties à registre. Les affectations combinatoires arrivent sans délai après l'évaluation de l'expression, les affectations de type "registre" sont efectuées au prochain coup d'horloge actif associé au registre.
= ON(1) Affectation combinatoire ou equation détaillée
?= DC(X) Affectation combinatoire ou equation détaillée
:= ON(1) Affectation de sortie de registre
?:= DC(X) Affectationd de registre
Priorité des opérateurs :
possibilité d'utilisation des parenthèses pour changer l'ordre d'évaluation, pour la même priorité l'évaluation se fait de gauche à droite dans l'ordre d'écriture..
Un ensemble est une collection de signaux et de constantes, et on peut les référencer avec un seul identificateur. Dans d'autres langages, les "sets" sont appelés des "bus". Les éléments d'un ensemble sont écrits entre crochets ([]) et séparés par des virgules, il speuvent aussi être séparés par l'indicateur d'ordre '..'.
bus_address =[A8, A7, A6, A5, A4, A3, A2, A1, A0]
ou
bus_address =[A8..A0]
Multiplication, division, reste, décalage ne sont pas autorisées sur les ensembles.
!bus_address= [!A8, !A7, ......., !A0]
-bus_adress=!bus_address + 1
bus_address.OE=[A8.OE,.....,A0.OE]
bus_address == BK si égalité de tous les bits
bus_address != BK si au moins un des bits est différent de l'autre
Ce sont des sections de texte encadrés par des parenthèses. Ils sont utilisés dans les équations, machines d'états, macros et directives, le texte concerné peut tenir sur une ligne ou sur plusieurs et l'on peut imbriquer un bloc dans un autre bloc.
{ this is a block }
{this is also a block, and it
spans more than one line.}
{ A = B # C;
D = [0, 1] + [l, 0];
}
Un commentaire commence par " et se termine par ".
"You can use comments to write observation in your program."
Les paramètres formels n'ont de valeur que dans les macros. Dans les modules ou directives, ils pointent le paramètre sur lequel est appliqué l'opération. Dans le corps d'une macro, avant le paramètre formel, on écrit un point d'interrogation, et ils sont séparés par des espaces.
EXP MACRO (a, b, c, d)
{?a & ?b # ?c & ?d};
`This was the macro declaration'
`The call of the defined macro:'
F = EXP (x, y, z, w);
`The evaluation of the macro will be:'
F= x & y # z & w;
Les directives donnent des options qui contrôlent le contenu ou le traitement d'un fichier source.
@ALTERNATE (Alternate operator Set)
@ALTERNATE valide les opérateurs altenatifs :
| Standard | Alternate | Description |
|---|---|---|
| ! | / | NOT |
| & | * | AND |
| # | + | OR |
| $ | :+: | XOR |
| !$ | :*: | XNOR |
@STANDARD (Standard operator Set):
@STANDARD repositionne les opérateurs standard ABEL.
@CONST (Constant Declaration) hors de la section de déclaration normale
Syntaxe:
@CONST identifier = expression;
Exemple:
@CONST OK = 1;
@DCSET (Don't Care Set)
@DCSET permet l'optimisation des fonctions partiellement définies (supprime les attributs `dc', `neg' et `pos').
@ONSET neutralise @DCSET.
@IF
@IF inclut ou exclut des sections de code source par rapport à la valeur d'une expression.
Syntaxe:
@IF expression {block}
Exemple:
@IF (A>B) {C = D # E}
@INCLUDE
@INCLUDE inclut un fichier ABEL
Syntaxe : @INCLUDE `file_name.abl`
Exemple:
@INCLUDE `macros.abl`
@INCLUDE `C:\\ABEL\\INCLUDE\\CONVERT.ABL`
@PAGE
@PAGE Saut de page
@RADIX (Default Base Numbering Directive)
@RADIX change la base par défaut.
Syntaxe:
@ RADIX expression
Example:
A = 10; `A is 10 (decimally)'
@RADIX 2;
A = 10; ` A vaut 2 (decimal)
@RADIX 10000; `base passe à 16''
A = 10; ` A vaut 16 (decimal)'
@RADIX 0A; `restaure à 10'
A = 10; `A vaut 10 (decimal) de nouveau
@REPEAT
@REPEAT répète un bloc du nombre de fois donné dans l'expression (peut être un entier).
Syntaxe :
@REPEAT expression { block };
ABEL a aussi une multitude d'autres directives listées ci-dessous.
@EXPR (Expression Directive)
@IFB (If Blank Directive)
@IFDEF (If Defined Directive)
@IFIDEN (If Identical Directive)
@IFNB (If Not Blank Directive)
@IFNDEF (If Not Defined Directive)
@IFNIDEN (If Not Identical Directive)
La figure suivante donne un exemple de fichier ABEL.

La description fonctionnelle est définie dans le "module".
Un module comprend les sections suivantes :
Un en-tête (Header)
Une partie Declarations
Une partie Description logique (Equations)
Des vecteurs de test éventuels (Test_Vectors)
Une indication de fin pour le module (End)
Les règles suivantes s'appliquent à la structure du module :
Généralement cela consiste en :
La description est fonctionnelle et/ou structurellle. Tous les éléments utilisés doivent avoir été précédemment déclarés.
Les différents éléments suivants permmettent de faire la description :
Ne sont quasiment plus utilisés (On préfère la simulation)
Termine le module et va de pair avec l'instruction MODULE.
The MODULE statment defines the beginning of an HDL program and must be paired with END statment that defines the functional description end.
The Header Section can consist of the following elements:
MODULE name (The identifier is the beginning of module statement (required))
OPTIONS (Optional element that can influence the run of the program)
TITLE `string' (Optional element that it is written in the header of JEDEC file)
The order of the identifiers must be the order presented
Chaque module doit avoir au moins une section de déclarations. Le "device" est déclaré de la manière suivante :
device_identifier DEVICE real_device;
Cette déclaration est optionnelle, elle associe un module effectivement avec une cible matérielle (défini par real_device, du type P22V10, P16L8, etc...), Le "device_identifier" doit correspondre à un nom de fichier valide car ce sera celui du fichier JEDEC auquel on éjoutera l'extension .JED. Le ";" est obligatoire.
nom_de_module DEVICE;
Exemples:
D1 device `P22V10' ;
module UART; "Xilinx™ XEPLD design"
UART device;
Il y a plusieurs types de déclaration :
ATTRIBUTE CONSTANT LIBRARY MACRO NODE PIN
PIN et NODE permettent de déclarer les signaux du module, et optionnellement d'associer les numéros de broche du circuit. Cette étape peut être faite en dernier lors du "mapping" final sur une architecture. Les attributs sont affectés au signaux (PIN/NODE) par l'intermédiaire de la déclaration ISTYPE. Les extensions (.NOM_EXTENSION) permettent de décrire plus précisément les signaux.
Declarations des "Pin" et "Node"
[!] pin_id [,[!] pin_id. . .] PIN (pin# [, pin#]] [ISTYPE ` attributes']
[!] node_id [[!] node_id. .] NODE [node# [, node#]] [ISTYPE `attributes']
avec pin# et node# numéros de broche du circuit, et attributes une chaîne de caractères qui spécifie des attributs pour les circuits avec possibilité de programmation (majoritairement pour les sorties).
Attributs pour les signaux :
signal_name, [signal_name] ISTYPE `attr'
Attributs génériques ou "indépendant de l'architecture" (Architecture Independent)
`com' , Signal combinatoire
`reg' , Elément mémoire, (bascule), peut être combiné avec 'invert' ou 'buffer' pour préciser le type de sortie.
`neg' , Le signal (entrée ou sortie) est inversé (logique négative pour optimisation), affectation à 1 pour logique non attribuée.
`pos' , Le signal (entrée ou sortie) n'est pas inversé (logique positive), affectation à 0 pour logique non attribuée.
Attributs "dépendants de l'architecture" (Architecture dependent)
`buffer' , Pas d'inverseur entre la fonction de sortie (éventuellement Flip-Flop) et la broche de sortie.
`invert' , Un inverseur entre la fonction de sortie (éventuellement Flip-Flop) et la broche de sortie.
`reg_D' , Une bascule D (D-type flip-flop). Implique une description détaillée (voir plus loin), si l'on spécifie 'invert' ou 'buffer', le compilateur transforme l'équation := (et .FB) en expressions avec .D et .Q.
`reg_T', Une bascule bi-stable (T-type flip-flop). Implique une description détaillée (voir plus loin).
`reg_SR' , Bascule SR (SR-type flip-flop). Implique une description détaillée (voir plus loin).
`reg_JK' , Bascule JK (JK-type flip-flop). Implique une description détaillée (voir plus loin).
`reg_G' , élément mémoire(D-type flip-flop avec validation de clock). Implique une description détaillée (voir plus loin).
`xor' , L'architecture cible contient une porte XOR.
ISTYPE permet de définir des attributs lorsque l'on ne spécifie pas de "device" ni de numéro de broche, cependant il est préférable de les spécifier même quand les numéros de broche pour un "device" sont donnés de manière à permettre une lecture claire du fichier.
Syntaxe :
identifier [, identifier]. .= expression [, expression]. . ;
Une constante correspond à un identificateur qui garde la même valeur dans le module. On fait l'affectation de gauche à droite.
Les extensions permettent de donner des préisions par rapport au comportement du circuit.
Syntaxe:
signal_name.EXT
Les extensions peuvent être indépendantes de l'architecture ou spécifiques à une architecture. On définit l'utilisation des extensions spécifiques comme correspondant à une syntaxe détaillée (detailed) et les extensions indépendantes comme correspondant à une syntaxe broche-à-broche (pin to pin).
Extensions indépendantes de l'Architecture (Architecture independent):
.CLK Entrée d'Horloge pour bascule
.OE "Output enable"
.PIN "Pin feedback", Retour vers le réseau de la broche (PIN)
.FB "Register feedback", Retour vers le réseau de la sortie du registre
Architecture specific dot extensions:
.D Dans la partie droite d'une équation, .D est le "feedback" combinatoire de l'entrée D de la bascule. Dans la partie gauche d'une équation, c'est l'entrée D de la bascule.
.J Entrée J d'une bascule JK.
.K Entrée K d'une bascule JK.
.R Entrée Rd'une bascule RS.
.S Entrée S d'une bascule RS.
.T Entrée T d'une bascule T.
.Q Sortie de la bascule
.PR Preset du Registre (synchrone ou asynchrone)
.RE Reset du registre (synchrone ou asynchrone)
.ACLR Reset Asynchrone du registre
.ASET Preset Asynchrone du registre
.CLR Reset synchrone du registre
.SET Preset synchrone du registre
.AR Reset Asynchrone du registre
.AP Preset Asynchrone du registre
.SR Reset Synchrone du registre
.SP Preset synchrone du registre
.LE Active bas, validation de latch
.LH Active haut, validation de Latch
.CE Entrée de validation d'horloge
.OE Validation de la sortie (Output Enable)
.COM "Feedback" combinatoire de l'entrée de la bascule, utilisé pour faire la distinction éventuelle entre la broche (.PIN) et le réseau logique interne (.COM).
La logique combinatoire peut être décrite avec des équations booléennes,des tables de vérité. Les instructions suivantes peuvent être utilisées :
[WHEN condition THEN] equation;
[ELSE equation];
Exemple:
EQUATIONS
@ALTERNATE
A = B + C + /D;
ADDR = AB + 5;
WHEN X THEN A =B; ELSE A = C;
Syntaxe des tables de vérité :
TRUTH_TABLE ([input_signals] -> [output_signals])
[input_values] -> [output_values];
[input_values] -> [output_values];
...
Exemple: Décodeur BCD -> 7 segments
-------------------------------------------------------------
"HEX-to-seven-segment decoder
MODULE bcd7seg
Declarations
D3,D2,D1,D0,ENA pin;
A,B,C,D,E,F,G pin istype 'com';
BCD=[D3,D2,D1,D0];
LED=[A,B,C,D,E,F,G];
ON,OFF=0,1;
L,H,X,Z=0,1,.X.,.Z.;
EQUATIONS
LED.OE= !ENA;
truth_table ( BCD -> [G,F,E,D,C,B,A])
0 -> [OFF,ON,ON,ON,ON,ON,ON] ;
1 -> [OFF,OFF,OFF,OFF,ON,ON,OFF];
2 -> [ON,OFF,ON,ON,OFF,ON,ON];
3 -> [ON,OFF,OFF,ON,ON,ON,ON];
4 -> [ON,ON,OFF,OFF,ON,ON,OFF];
5 -> [ON,ON,OFF,ON,ON,OFF,ON];
6 -> [ON,ON,ON,ON,ON,OFF,ON];
7 -> [OFF,OFF,OFF,OFF,ON,ON,ON];
8 -> [ON,ON,ON,ON,ON,ON,ON];
9 -> [ON,ON,OFF,ON,ON,ON,ON];
end;
---------------------------------------------------------------------------------
Cette description peut se faire par équations logiques booléennes, diagrammes d'états et tables.
Equations Logiques Booléennes
La syntaxe est la même que pour la logique combinatoire, mais on utilise l'opérateur ":=" à la place de l'opérateur "=". L'expression est affectée après le coup d'horloge actif.
EQUATIONS
Q := (A + B) * /RST;
COUNT := COUNT + 1;
Tables de vérité
La syntaxe est la même, mais on utilise l'opérateur ":>" dans la table.
Syntaxe:
TRUTH_TABLE ([IN_SIGNALS] :> [REG_SIGNALS] -> [OUTPUTS]
[IN_VALUES] :> [REG_VALUES] -> [OUT_VALUES;]
[IN_VALUES] :> [REG_VALUES] -> [OUT_VALUES;]
[IN_VALUES] :> [REG_VALUES] -> [OUT_VALUES;]
[...];
Considérations de Conception
Comme nous l'avons dit précédemment, il y a deux types de description pour les éléments à mémoire : "pin to pin" ou "detailed".
Considérons l'équation suivante :
sortie := !sortie # Preset;
Le terme sortie à gauche avec ":="
implique un registre, le terme !sortie à droite correspond à
quoi?
- la sortie du registre ?
- la sortie du combinatoire alimentant le registre ?
- la sortie de la broche de sortie (I/O) ?
Il n'y a d'autre part pas d'indication du type de registre.
L'écriture suivante :
sortie.CLK = clock;
sortie := !sortie.FB # Preset;
est plus précise. C'est une description dite "PIN TO PIN".
L'écriture en version "detailed" revient à écrire :
sortie.CLK = clock;
sortie.D = !sortie.Q # Preset; mais il n'y a pas
d'information sur la sortie (I/O). On peut donc avoir un
focntionnement différent selon que l'on ait un circuit avec
sortie inversé (P16R4 par exemple) ou un circuit avec sortie
normale. Il est donc préférable de mettre un attribut
supplémentaire, l'attribut "buffer" (pas d'inversion
entre la sortie de la bascule et la sortie associée) ou son
complément "invert" est nécessaire ,
soit une déclaration :
sortie PIN ISTYPE 'buffer';
Il est intéressant de "visualiser" la "macrocellule" équivalente pour le mode "detrailed" :

Il faut noter sur la figure ci-dessus que l'identificateur BASC.Q n'est pas forcément le même que BASC (notamment si le fusible commande l'inversion en sortie).
Le "PIN to PIN" estv plus comportemental et correspond à la macro-cellule suivante (pas de Reset ou de Preset dans ce cas) :

Récapitulons donc l'écriture de notre module :
En "Pin to Pin" (Module 1):
module pin_to_pin
sortie PIN ISTYPE 'reg';
Clock, Preset PIN;
Equations;
Sortie.clk = Clock;
sortie := !sortie.FB # Preset;
En "detailed" (Module 2) :
module detail
sortie PIN ISTYPE 'reg_D, buffer';
Clock,Preset PIN
Equations;
Sortie.clk = Clock;
Sortie.D = !Sortie.Q # Preset
Le module 1 peut normalement s'implanter dans n'importe quel type de PLD. Le module D ne peut avoir pour cible que les circuits avec bascule D et sortie non-inverseuse. Pour l'implémenter dans un circuit avec sortie inversé, il faut écrire :
(Module 3)
module detail_inv
sortie PIN ISTYPE 'reg_D, invert';
Clock,Preset PIN
Equations;
Sortie.clk = Clock;
!Sortie.D = Sortie.Q # Preset; "(Changement de l'équation
à cause du type de sortie)"
Ceci démontre que le mieux est de faire une description "Pin to Pin" pour ne pas avoir à modifier la decsription en fonction du type de cible, par contre on n'a pas de Preset et Reset (asynchrone), et si l'on en met un, on aura une restriction à certains types de circuits. Par exemple :
(Module 4)
module avec_preset
sortie PIN ISTYPE 'reg, buffer';
Clock,Preset PIN
Equations;
Sortie.clk = Clock;
Sortie.AP = Preset;
sortie := !Sortie.FB;
.AP pour le Preset est associé à la bascule interne, donc il ne faut pas que le circuit soit à sortie inverrsée entre la bascule et la broche, d'où la nécessité d'indisuer le "buffer" pour être sur que cela fonctionnera correctement.
Si l'on met un attribut "invert", il faudra que le Preset soit connecté sur le Resset Asynchrone pour avoir effectivement un Preset (voir Module 5) :
(Module 5)
module avec_preset_inv
sortie PIN ISTYPE 'reg, invert';
Clock,Preset PIN
Equations;
Sortie.clk = Clock;
Sortie.AR = Preset;
sortie := !Sortie.FB;
Terminons par l'exemple d'un compteur synchrone par 5 (Q2 Q1 Q0) = ( 000 001 010 011 100 ), pour lequel les équations sont :
D0 = /QO AND /Q2; D1 = (QO AND /Q1) OR (/Q0 AND Q1) = Q0 XOR Q1; D2 = Q0 AND Q1;
(Module 7 : Compteur synchrone en description PIN TO PIN)
module csync_pin_to_pin
csync device 'P16R4'
Clock, reset PIN 1,2 ;
Q0, Q1, Q2 PIN 15,16,17 ISTYPE 'reg';
QREG = [Q2,Q1,Q0];
Equations;
QREG.CLK = Clock;
Q0 := (!Q0.FB & !Q2.FB) & !reset;
Q1 := (Q0.FB $ Q1.FB) & !reset;
Q2 := (Q0.FB & Q1.FB) & !reset;
END;
(Module 8 : Compteur synchrone en description DETAILED)
module csync_detailed
csyncd device 'P16R4'
Clock, reset PIN 1,2 ;
Q0, Q1, Q2 PIN 15,16,17 ISTYPE 'reg_D,invert';
QREG = [Q2,Q1,Q0];
Equations;
QREG.CLK = Clock;
!Q0.D = (Q0.Q & Q2.Q) & !reset;
!Q1.D = (!Q0.Q $ !Q1.Q) & !reset;
!Q2.D = (!Q0.Q & !Q1.Q) & !reset;
END;