Université Pierre & Marie Curie (PARIS VI)
LIP6 - Département ASIM
Spécifications de DpGen
version 0.2
Le 11 mai 2000
Les technologies à deux niveaux de métaux avaient conduit à deux gabarits de cellules différents pour les chemins de données et les parties de contrôle. D'une part les cellules précaractérisées pour les parties de contrôle routées en utilisant des canaux. D'autre part les cellules de type « chemins de données » bien adaptées aux flux de données vectorisés.
L'avènement des technologies à plus de deux niveaux de métaux rend obsolète cette organisation. Désormais toutes les cellules ont un gabarit unique et sont connectées avec le même routeur (Silicon Ensemble sous Cadence, ou OCR sous Alliance).
Il découle de cette unification deux conséquences importantes :
La principale vue générée est la net-list au niveau portes logiques.
On appelle DpGen l'ensemble des générateurs d'opérateurs vectorisés. DpGen hérite à la fois de caractéristiques de FpGen et de caractéristiques de GenOptim. Il génère des net-list routables par un outil standart, mais il s'appuie sur des cellules spécifques pour certains opérateurs. On vise donc toujours une portabilité au niveau du layout symbolique.
Puique DpGen manipule des netlists de cellules de même granularité et au même gabarit que GenLib, FpGen n'a plus lieu d'exiter en tant que language de description spécifique. DpGen est donc une extention de GenLib. Cette extention fournit un ensemble de macro-cellules paramétrables utilisables soit pour construire un chemin de données, soit pour utiliser un ou plusieurs opérateurs vectorisés dans une net-list de granularité portes. Le principal paramètre structurel est la largeur N du vecteur de bits.
Un autre obectif de DpGen est de pouvoir offrir à un outil de synthèse une API en C lui permettant de manipuler des opérateurs complexes (évolution possible de BOP, SCMAP, VASY).
La principale particularité de FpGen était de fusionner la génération des modèles et leur instantiation. Dans DpGen, on revient à une approche classique en deux étapes.
Exemple :
FpGen : DP_AND2("mux_Nbits", N, ...); DpGen : GENLIB_MACRO(DPGEN_MUX2, "modele_mux2_Nbits", N, ...); GENLIB_LOINS("modele_mux2_Nbits", "mon_mux2", ...);
La fonction GENLIB_MACRO(), est l'interface (unique) de tous les générateurs de DpGen. C'est donc une fonction d'aiguillage vers les différents générateurs disponibles. Son premier paramètre définit le type du générateur appelé, les autres paramètres définissent le nom de modèle de l'opérateur généré, les vues demandées et enfin les différents paramètres structurels, spécifques à chaque générateur.
La fonction GENLIB_MACRO() peut être appelée n'importe ou dans un programme GenLib. Un générateur peut faire appel à des fonctions GenLib. La fonction GENLIB_MACRO() sauvegarde les variables globales WORK_LOFIG et WORK_PHFIG en entrée, et les restitue en sortie, ce qui permet une utilisation récursive de GENLIB_MACRO().
Si le générateur le permet, la fonction GENLIB_MACRO() peut générer un placement optionnel pour les opérateurs réguliers. Il s'agit d'un fichier «.ap» de l'opérateur instanciant les cellules de base, sans routage et sans connecteurs. Ces fichiers peuvent être utilisés pour placer explicitement les opérateurs d'un chemin de données les uns par rapport aux autres grâce aux fonctions GENLIB_PLACE_RIGHT() et GENLIB_PLACE_LEFT().
FpGen produisait deux vues :
Les opérateurs de DpGen sont construits à partir de cellules de SxLib où Dp_SxLib (cellules spéciales pour chemin de données). Toutes ces cellules disposent d'un modèle comportemental (et d'une caractérisation électrique). La connectique interne aux opérateurs est donc être réalisée par le routeur générique.
Dans le cas d'un chemin de données contenant de nombreux opérateurs, on fournit au routeur une net-list hiérarchique. Les niveaux hierarchiques correspondant aux opérateurs ou groupes d'opérateurs sont supprimés par le routeur avant routage. Le placement est lui aussi hiérarchique, mais il est optionnel.
Bien que la vue comportementale d'un opérateur ne soit plus nécéssaire, puisque toutes les cellules feuilles ont leur modèle comportemental, un générateur DpGen peut fournir une vue comportementale, à des fins vérification.
En résumé DpGen produira :
La fonction GENLIB_MACRO() est l'interface unique permettant d'appeler tous les générateurs de DpGen. Tous les générateurs n'ayant pas les mêmes paramètres, c'est une fonction à nombre d'arguments variables.
Prototype C de GENLIB_MACRO :
void GENLIB_MACRO(long function, /* obligatoire. */ char *modelName, /* obligatoire. */ long flags, /* obligatoire. */ long N, /* obligatoire. */ long drive, /* optionnel. */ long regNumber, /* optionnel. */ char *constVal /* optionnel. */ );
On distingue deux types d'arguments :
Les arguments systématiquement présents :
Le premier argument : long function, spécifie le type du générateur appelé. Par example DPGEN_MUX2 pour générer un multiplexeur à deux entrées.
Le second argument : char *modelName, spécifie le nom de modèle. Par example : "modele_mux2_32bits".
Le troisième argument : long flags, une combinaison des «flags» suivants :
Le quatrième argument : long N, largeur du vecteur de bits.
Les arguments optionnels :
long drive : La puissance de sortie de l'opérateur.
long regNumber : Nombre de registres.
char *constVal : Une chaine de caractères représentant une constante, par example "0xFFFF0000".
GENLIB_MACRO(DPGEN_INV, char *modelName, /* ex: "model_inv_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1, 2, 4 ou 8. */ GENLIB_LOINS("model_inv_32", "instance1_inv_32", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
GENLIB_MACRO(DPGEN_BUFF, char *modelName, /* ex: "model_buff_32" */ long flags, long N, /* ex: 32. */ long drive); /* 2, 4 ou 8. */ GENLIB_LOINS("model_Buff_32", "instance1_buff_32", "i0[31:0]", "q[31:0"], "vdd", "vss", NULL);
NAND2 : nq <= not(i0 and i1)
GENLIB_MACRO(DPGEN_NAND2, char *modelName, /* ex: "model_nand2_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_nand2_32", "instance1_nand2_32", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
NAND3 : nq <= not(i0 and i1 and i2)
GENLIB_MACRO(DPGEN_NAND3, char *modelName, /* ex: "model_nand3_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_nand3_32", "instance1_nand3_32", "i2[31:0]", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
NAND4 : nq <= not(i0 and i1 and i2 and i3)
GENLIB_MACRO(DPGEN_NAND4, char *modelName, /* ex: "model_nand4_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_nand4_32", "instance1_nand4_32", "i3[31:0]", "i2[31:0]", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
GENLIB_MACRO(DPGEN_AND2, char *modelName, /* ex: "model_and2_32" */ long flags, long N, /* ex: 32. */ long drive); /* 2 ou 4. */ GENLIB_LOINS("model_and2_32", "instance1_and2_32", "i1[31:0]", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
AND3 : q <= i0 and i1 and i3
GENLIB_MACRO(DPGEN_AND3, char *modelName, /* ex: "model_and3_32" */ long flags, long N, /* ex: 32. */ long drive); /* 2 ou 4. */ GENLIB_LOINS("model_and3_32", "instance1_and3_32", "i2[31:0]", "i1[31:0]", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
AND4 : q <= i0 and i1 and i3 and i4
GENLIB_MACRO(DPGEN_AND4, char *modelName, /* ex: "model_and4_32" */ long flags, long N, /* ex: 32. */ long drive); /* 2 ou 4. */ GENLIB_LOINS("model_and4_32", "instance1_and4_32", "i3[31:0]", "i2[31:0]", "i1[31:0]", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
GENLIB_MACRO(DPGEN_NOR2, char *modelName, /* ex: "model_nor2_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_nor2_32", "instance1_nor2_32", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
NOR3 : nq <= not(i0 or i1 or i3)
GENLIB_MACRO(DPGEN_NOR3, char *modelName, /* ex: "model_nor3_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_nor3_32", "instance1_nor3_32", "i2[31:0]", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
NOR4 : nq <= not(i0 or i1 or i3 or i4)
GENLIB_MACRO(DPGEN_NOR4, char *modelName, /* ex: "model_nor4_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_nor4_32", "instance1_nor4_32", "i3[31:0]", "i2[31:0]", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
GENLIB_MACRO(DPGEN_OR2, char *modelName, /* ex: "model_or2_32" */ long flags, long N, /* ex: 32. */ long drive); /* 2 ou 4. */ GENLIB_LOINS("model_or2_32", "instance1_or2_32", "i1[31:0]", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
GENLIB_MACRO(DPGEN_OR3, char *modelName, /* ex: "model_or3_32" */ long flags, long N, /* ex: 32. */ long drive); /* 2 ou 4. */ GENLIB_LOINS("model_or3_32", "instance1_or3_32", "i1[31:0]", "i0[31:0]", "i2[31:0]", "q[31:0]", "vdd", "vss", NULL);
OR4 : q <= i0 or i1 or i3 or i4
GENLIB_MACRO(DPGEN_OR4, char *modelName, /* ex: "model_or4_32" */ long flags, long N, /* ex: 32. */ long drive); /* 2 ou 4. */ GENLIB_LOINS("model_or4_32", "instance1_or4_32", "i3[31:0]", "i2[31:0]", "i1[31:0]", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
XNOR2 : nq <= not(i0 xor i1)
GENLIB_MACRO(DPGEN_XNOR2, char *modelName, /* ex: "model_xnor2_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_xnor2_32", "instance1_xnor2_32", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
GENLIB_MACRO(DPGEN_XOR2, char *modelName, /* ex: "model_xor2_32" */ long flags, long N, /* ex: 32. */ long drive); /* 1 ou 4. */ GENLIB_LOINS("model_xor2_32", "instance1_xor2_32", "i1[31:0]", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
nq <= WITH cmd SELECT not i0 WHEN '0', not i1 WHEN '1';
GENLIB_MACRO(DPGEN_NMUX2, char *modelName, /* ex: "model_nmux2_32" */ long flags, long N); /* ex: 32. */ GENLIB_LOINS("model_nmux2_32", "instance1_nmux2_32", "cmd", "i1[31:0]", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
q <= WITH cmd SELECT i0 WHEN '0', i1 WHEN '1';
GENLIB_MACRO(DPGEN_MUX2, char *modelName, /* ex: "model_mux2_32" */ long flags, long N, /* ex: 32. */ long Drive); /* 2 ou 4 */ GENLIB_LOINS("model_mux2_32", "instance1_mux2_32", "cmd", "i1[31:0]", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
nts:BLOCK(cmd = '1') BEGIN nq <= GUARDED not(i0); END
GENLIB_MACRO(DPGEN_NBUSE, char *modelName, /* ex: "model_nbuse_32" */ long flags, long N); /* ex: 32. */ GENLIB_LOINS("model_nbuse_32", "instance1_nbuse_32", "cmd", "i0[31:0]", "nq[31:0]", "vdd", "vss", NULL);
ts:BLOCK(cmd = '1') BEGIN q <= GUARDED i0; END
GENLIB_MACRO(DPGEN_BUSE, char *modelName, /* ex: "model_buse_32" */ long flags, long N, /* ex: 32. */ long Drive); /* 4 ou 8 */ GENLIB_LOINS("model_buse_32", "instance1_buse_32", "cmd", "i0[31:0]", "q[31:0"], "vdd", "vss", NULL);
nq <= WITH cmd SELECT not(i0) WHEN '0', not(i0 and X"0000FFFF") WHEN '1';
GENLIB_MACRO(DPGEN_NAND2MASK, char *modelName, /* ex: "model_nand2Mask0000FFFF_32" */ long flags, long N, /* ex: 32. */ char *constVal); /* ex: "0x0000FFFF" */ GENLIB_LOINS("model_nand2Mask0000FFFF_32", "instance1_nand2mask0000FFFF_32", "cmd", "i0[31:0]", "nq[31:0"], "vdd", "vss", NULL);
nq <= WITH cmd SELECT not(i0) WHEN '0', not(i0 or X"0000FFFF") WHEN '1';
GENLIB_MACRO(DPGEN_NOR2MASK, char *modelName, /* ex: "model_nor2Mask0000FFFF_32" */ long flags, long N, /* ex: 32. */ char *constVal); /* ex: "0x0000FFFF" */ GENLIB_LOINS("model_nor2Mask0000FFFF_32", "instance1_nor2mask0000FFFF_32", "cmd", "i0[31:0]", "nq[31:0"], "vdd", "vss", NULL);
nq <= WITH cmd SELECT not(i0) WHEN '0', not(i0 xor X"0000FFFF") WHEN '1';
GENLIB_MACRO(DPGEN_XNOR2MASK, char *modelName, /* ex: "model_nxor2Mask0000FFFF_32" */ long flags, long N, /* ex: 32. */ char *constVal); /* ex: "0x0000FFFF" */ GENLIB_LOINS("model_nxor2Mask0000FFFF_32", "instance1_nxor2mask0000FFFF_32", "cmd", "i0[31:0]", "nq[31:0"], "vdd", "vss", NULL);
Additionneur/soustracteur signé. Connecteurs (6) :
add_sub = '1' : soustraction, addition sinon.
c32 : la carry sortante (i.e. carry[N]). En mode non signé c'est l'overflow.
c31 : carry[N-1]. On calculera l'overflow (mode signé) en effectuant carry xor overflow.
GENLIB_MACRO(DPGEN_ADSB2F, char *modelName, /* ex: "model_adsb2f_32" */ long flags, long N); /* ex: 32. */ GENLIB_LOINS( "model_adsb2f_32", "instance1_adsb2f_32", "add_sub", /* 0: add, 1: substract. */ "c32", /* carry[N] (ex: "carry[32]"). */ "c31", /* carry[N-1] (ex: "carry[31]"). */ "i0[31:0]", "i1[31:0]", "q[31:0"], /* operands and results. */ "vdd", "vss", NULL);
Le shifter possède 4 connecteurs : (une commande et trois données)
op[1:0] : le type du décalage à effectuer.
op[0] = '1' décalage à droite, à gauche
sinon.
op[1] = '1' extention de signe dans le cas
d'un décalage à droite (arithmétique).
shamt[Y:0] : la valeur du décalage. la largeur de ce bus est égale à log2(N) - 1 où N est la largeur du bus.
i0[N-1:0] : la valeur à décaler.
q[N-1:0] : le résulat du décalage.
Remarque : dans FpGen le shifter était capable d'effectuer des rotations, on ne retient pas cette possibilité dans DpGen.
GENLIB_MACRO(DPGEN_SHIFT, char *modelName, /* ex: "model_shift_32" */ long flags, long N); /* ex: 32. */ GENLIB_LOINS("model_shift_32", "instance1_shift_32", "op[1:0]", "shamt[4:0]", "i0[31:0]", "q[31:0"], "vdd", "vss", NULL);
NUL : q <= '1' WHEN (i0 = X"00000000") ELSE '0'
GENLIB_MACRO(DPGEN_NUL, char *modelName, /* ex: "model_nul_32" */ long flags, long N); /* ex: 32. */ GENLIB_LOINS("model_nul_32", "instance1_nul_32", "i0[31:0]", "flag_nul", "vdd", "vss", NULL);
GENLIB_MACRO(DPGEN_CONST, char *modelName, /* ex: "model_constFFFF0000_32" */ long flags, long N, /* ex: 32. */ char *constVal); /* ex: "0xFFFF0000" */ GENLIB_LOINS("model_constFFFF0000_32", "instance1_constFFFF0000_32", "q[31:0]", "vdd", "vss", NULL);
q <= WITH sel0 SELECT contsVal0 WHEN B"0", constVal1 WHEN B"1";
GENLIB_MACRO(DPGEN_ROM2, char *modelName, /* ex: "model_rom2_set_1" */ long flags, long N, /* ex: 4. */ char *constVal0, /* ex: "0b1010" */ char *constVal1); /* ex: "0b1100" */ GENLIB_LOINS("model_rom2_set_1", "instance1_rom2_set_1", "q[3:0]", "vdd", "vss", NULL);
q <= WITH sel1 & sel0 SELECT contsVal0 WHEN B"00", contsVal1 WHEN B"01", contsVal2 WHEN B"10", constVal3 WHEN B"11";
GENLIB_MACRO(DPGEN_ROM4, char *modelName, /* ex: "model_rom4_set_1" */ long flags, long N, /* ex: 15. */ char *constVal0, /* ex: "0xFF00" */ char *constVal1, /* ex: "0xCCCC" */ char *constVal2, /* ex: "0xF0F0" */ char *constVal3); /* ex: "0xAAAA" */ GENLIB_LOINS("model_rom4_set_1", "instance1_rom4_set_1", "q[15:0]", "vdd", "vss", NULL);
Banc de registre à une écriture et une lecture sans décodeur. RF1R0 est identique a RF1 a ceci près que le registre R0 est collé a zero (si on l'écrit on ne change pas sa valeur, et en lecture on a toujours zéro). Connecteurs : (7)
ckok : le signal d'horloge (monophasé).
sel : sélectionne le bus d'écriture :
sel = '0' écrit le bus datain0
sel = '1' écrit le bus datain1
selr[regNumber-1:0] : l'adresse de lecture décodée (i.e. autant de bits que de registres).
selw[regNumber-1:0] : l'adresse d'écriture décodée (i.e. autant de bits que de registres).
datain0[N-1:0] : le premier bus d'écriture.
datain1[N-1:0] : le second bus d'écriture.
dataout[N-1:0] : le bus de lecture.
GENLIB_MACRO(DPGEN_RF1, char *modelName, /* ex: "model_rf1x8_32" */ long flags, long N, /* ex: 32 */ long regNumber); /* ex: 8 */ GENLIB_LOINS("model_rf1x8_32", "instance1_rf1x8_32", "ckok", "sel", "selr[7:0]", "selw[7:0]", "datain0[31:0]", "datain1[31:0]", "dataout[31:0]", "vdd", "vss", NULL);
Banc de registre à une écriture et une lecture avec décodeur. RF1DR0 est identique a RF1D a ceci près que le registre R0 est collé a zero (si on l'écrit on ne change pas sa valeur, et en lecture on a toujours zéro). Connecteurs : (9)
ck : le signal d'horloge (monophasé).
sel : sélectionne le bus d'écriture :
sel = '0' écrit le bus datain0
sel = '1' écrit le bus datain1
wen : autorisation d'écriture (actif a '1').
ren : autorisation de lecture (actif a '1').
adr[log2(regNumber)-1:0] : l'adresse de lecture encodée.
adw[log2(regNumber)-1:0] : l'adresse d'écriture encodée.
datain0[N-1:0] : le premier bus d'écriture.
datain1[N-1:0] : le second bus d'écriture.
dataout[N-1:0] : le bus de lecture.
GENLIB_MACRO(DPGEN_RF1D, char *modelName, /* ex: "model_rf1dx8_32" */ long flags, long N, /* ex: 32 */ long regNumber); /* ex: 8 */ GENLIB_LOINS("model_rf1dx8_32", "instance1_rf1dx8_32", "ck", "sel", "wen", "ren", "adr[2:0]", "adw[2:0]", "datain0[31:0]", "datain1[31:0]", "dataout[31:0]", "vdd", "vss", NULL);
Registre simple avec write enable. Connecteurs : (4)
ck : le signal d'horloge (monophasé).
wen : autorisation en écriture (actif à l'état haut).
i0[N-1:0] : le bus d'écriture.
q[N-1:0] : le bus de lecture.
GENLIB_MACRO(DPGEN_DFF, char *modelName, /* ex: "model_dff_32" */ long flags, long N); /* ex: 32 */ GENLIB_LOINS("model_dff_32", "instance1_dff_32", "wen", "ck", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
Registre simple avec write enable et scan-path. Connecteurs : (6)
Remarque : l'entrée du scan-path est i0[0] et la sortie q[31]
ck : le signal d'horloge (monophasé).
scan : mise en mode scan-path (actif à l'état haut).
wen : autorisation en écriture (actif à l'état haut).
scin : entrée du scan-path (q[N-1]) est la sortie.
i0[N-1:0] : le bus d'écriture.
q[N-1:0] : le bus de lecture.
GENLIB_MACRO(DPGEN_DFFT, char *modelName, /* ex: "model_dfft_32" */ long flags, long N); /* ex: 32 */ GENLIB_LOINS("model_dfft_32", "instance1_dfft_32", "scan", "scin", "wen", "ck", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
Registre simple avec write enable. Connecteurs : (4)
ck : le signal d'horloge (monophasé).
wen : autorisation en écriture (actif à l'état haut).
i0[N-1:0] : le bus d'écriture.
q[N-1:0] : le bus de lecture.
GENLIB_MACRO(DPGEN_SFF, char *modelName, /* ex: "model_sff_32" */ long flags, long N); /* ex: 32 */ GENLIB_LOINS("model_sff_32", "instance1_sff_32", "wen", "ck", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);
Registre simple avec write enable et scan-path. Connecteurs : (6)
Remarque : l'entrée du scan-path est i0[0] et la sortie q[31]
ck : le signal d'horloge (monophasé).
scan : mise en mode scan-path (actif à l'état haut).
wen : autorisation en écriture (actif à l'état haut).
scin : entrée du scan-path (q[N-1]) est la sortie.
i0[N-1:0] : le bus d'écriture.
q[N-1:0] : le bus de lecture.
GENLIB_MACRO(DPGEN_SFFT, char *modelName, /* ex: "model_sfft_32" */ long flags, long N); /* ex: 32 */ GENLIB_LOINS("model_sfft_32", "instance1_sfft_32", "scan", "scin", "wen", "ck", "i0[31:0]", "q[31:0]", "vdd", "vss", NULL);