Initial version of donated sources by Avertec, 3.4p5.
[tas-yagle.git] / distrib / sources / yagle / yagle / yag_lofig.c
1 /****************************************************************************/
2 /* */
3 /* Chaine de CAO & VLSI Alliance */
4 /* */
5 /* Produit : YAGLE v3.50 */
6 /* Fichier : yag_lofig.c */
7 /* */
8 /* (c) copyright 1993 Laboratoire MASI equipe CAO & VLSI */
9 /* Tous droits reserves */
10 /* Support : e-mail alliance-support@asim.lip6.fr */
11 /* */
12 /* Auteur(s) : Marc LAURENTIN le : 27/01/1993 */
13 /* */
14 /* Modifie par : Anthony LESTER le : 20/11/1994 */
15 /* Modifie par : le : ../../.... */
16 /* Modifie par : le : ../../.... */
17 /* */
18 /****************************************************************************/
19
20 #include "yag_headers.h"
21
22 lofig_list *YAG_HEAD_MODEL = NULL;
23
24 static lofig_list *cnsmodToLomod __P((cone_list *ptcone, int index));
25 static int coneConnect __P((cone_list *ptcone));
26 static int coneIsEmpty __P((cone_list *ptcone));
27 static void saveVbeConeModel __P((cone_list *ptcone, int index));
28 static void prepConeExt __P((cone_list *ptcone));
29 static void restoreConeExt __P((cone_list *ptcone));
30 static void delOutconeForVst __P((cnsfig_list *ptcnsfig));
31 static void genCatal __P((lofig_list *headModel));
32 static void prepConeMemory __P((cone_list *ptcone));
33 static void restoreConeMemory __P((cone_list *ptcone));
34 static void addGlueCones __P((cnsfig_list *ptcnsfig));
35 static void removeGlueCones __P((cnsfig_list *ptcnsfig));
36 static void addCellInstances __P((lofig_list *ptlofig, cnsfig_list *ptcnsfig, long vddSigIndex, long vssSigIndex));
37 static lofig_list *cellToLomod __P((cell_list *ptcell));
38 static chain_list *labelEnum __P((char *root, long num));
39
40 /****************************************************************************
41 * function yagBuildLofig(); *
42 ****************************************************************************/
43 void
44 yagBuildLofig(ptcnsfig, ptlotrsfig)
45 cnsfig_list *ptcnsfig;
46 lofig_list *ptlotrsfig;
47 {
48 ht *funcTable;
49 ht *modelTable;
50 lofig_list *tabModel[200]; /* table des model:index donne par modelTable*/
51 edge_list *tabIncone[500];
52 lofig_list *ptlofig;
53 lofig_list *ptfig;
54 losig_list *ptsig;
55 locon_list *ptcon;
56 cone_list *ptcone, *ptxcone;
57 edge_list *ptedge;
58 cell_list *ptcell;
59 ptype_list *ptuser;
60 chain_list *signame = NULL;
61 chain_list *sigchain;
62 chain_list *ptchain;
63 char buf[YAGBUFSIZE];
64 char *model;
65 char *expr;
66 char *name;
67 long vddSigIndex;
68 long vssSigIndex;
69 long nbSig = 1;
70 int modelIdx = 1;
71 int nbModel, nbEdge;
72 int value, i;
73 int vddDone = FALSE;
74 int vssDone = FALSE;
75 short save_USE_FCF;
76 float capa;
77
78 /* disable global analysis of any cones built */
79 save_USE_FCF = YAG_CONTEXT->YAG_USE_FCF;
80 YAG_CONTEXT->YAG_USE_FCF = FALSE;
81
82 funcTable = addht(100); /* table des occurences de modeles (stat..)*/
83 modelTable = addht(100); /* correspondance model <-> index */
84
85 /*-----------------------------------------------------------------+
86 | On supprime iterativement les outcones qui pointe sur des cones |
87 | qui n'ont pas de sorties, ceci pour que la netlist structurelle |
88 | soit avalable par Asimut ou par SaX |
89 +----------------------------------------------------------------*/
90 delOutconeForVst(ptcnsfig);
91
92 /*--------------------------------------------------------+
93 | On associe a chaque cone son modele (char * ~= structrel|
94 | Si le model est nouveau , il est ajoute a la table de |
95 | hasch modelTable avec un index qui est incremente. |
96 | et le model logique MBK est cree |
97 | Le pointeur sur le model logique (MBK) est ajoute dans |
98 | un tableau de pointeur, dont l'index est celui precite |
99 | ON accedera donc au pointeur de model en cherchant |
100 | table[i] avec i = le res du hash sur l'expression du |
101 | modele |
102 | Enfin, le vbe du model est crache sur disque |
103 +--------------------------------------------------------*/
104
105 addGlueCones(ptcnsfig);
106
107 for(ptcone = ptcnsfig->CONE; ptcone != NULL; ptcone = ptcone->NEXT) {
108
109 if (ptcone->CELLS != NULL) {
110 for (ptchain = ptcone->CELLS; ptchain; ptchain = ptchain->NEXT) {
111 ptcell = (cell_list *)ptchain->DATA;
112 if ((ptcell->TYPE & ~CNS_UNKNOWN) >= 128 && ptcell->BEFIG == NULL) break;
113 }
114 if (ptchain == NULL) continue;
115 }
116 if ((ptcone->TYPE & CNS_POWER) != 0) continue;
117 if (ptcone->OUTCONE == NULL && (ptcone->TYPE & YAG_GLUECONE) == 0) continue;
118 if (coneIsEmpty(ptcone) == 0) continue;
119 if (coneConnect(ptcone) == 0) continue;
120
121 if ((ptcone->TYPE & CNS_EXT) == CNS_EXT) prepConeExt(ptcone);
122 if ((ptcone->TYPE & (CNS_MEMSYM|CNS_LATCH)) == CNS_MEMSYM)
123 prepConeMemory(ptcone);
124
125 yagMakeConeModel(ptcone);
126 ptuser = getptype(ptcone->USER, YAG_MODEL_PTYPE);
127 if (ptuser == NULL) continue;
128 expr = (char*)ptuser->DATA;
129 value = gethtitem(funcTable,expr);
130
131 if(value == EMPTYHT) { /* Nouveau model de cone */
132 addhtitem(funcTable, expr, 1);
133 addhtitem(modelTable, expr, modelIdx);
134 ptfig = cnsmodToLomod(ptcone, modelIdx);
135 savelofig(ptfig);
136 saveVbeConeModel(ptcone, modelIdx);
137 tabModel[modelIdx++] = ptfig;
138 }
139 else sethtitem(funcTable,expr,value+1);
140 }
141
142 /*-----------------------------------------------------+
143 | On cree la figure proprement dit |
144 +-----------------------------------------------------*/
145 sprintf(buf, "%s_yagh", ptcnsfig->NAME);
146 ptlofig = addlofig(namealloc(buf));
147
148 /*--------------------------------------------------+
149 | Signaux de la figure |
150 +--------------------------------------------------*/
151 for(ptcone = ptcnsfig->CONE; ptcone != NULL; ptcone = ptcone->NEXT) {
152 nbSig++;
153
154 if (ptcone->CELLS != NULL) {
155 for (ptchain = ptcone->CELLS; ptchain; ptchain = ptchain->NEXT) {
156 ptcell = (cell_list *)ptchain->DATA;
157 if ((ptcell->TYPE & ~CNS_UNKNOWN) >= 128 && ptcell->BEFIG == NULL) break;
158 }
159 if (ptchain == NULL && (ptcone->TYPE & YAG_CELLOUT) == 0) continue;
160 }
161 if (ptcone->OUTCONE == NULL && (ptcone->TYPE & YAG_GLUECONE) == 0) continue;
162 if ((ptcone->TYPE & CNS_POWER) == CNS_POWER) continue;
163 if (coneIsEmpty(ptcone) == 0) continue;
164
165 signame = addchain(NULL, (void *)ptcone->NAME);
166
167 if ((ptcone->TYPE & CNS_EXT) != 0)
168 ptsig = addlosig(ptlofig, ptcone->INDEX, signame, EXTERNAL);
169 else ptsig = addlosig(ptlofig, ptcone->INDEX, signame, INTERNAL);
170 addlorcnet(ptsig);
171 rcn_addcapa(ptsig, yagGetConeCapa(ptcone, ptlofig));
172 }
173
174 /*---------------------------------------------------------+
175 | Connecteurs externes: Ceux sur lequel un cone est monte |
176 | sont craches tels quel puisque un signal ( un cone) leur |
177 | associe. Pour les autres (fin de branche EXT sur lequel ,|
178 | il n'y a pas de cone -xor de connecteur=contre exemple-) |
179 |il faut |
180 | un signal supplementaire, dont on range l'index dans un |
181 | user MBK_SIG du connecteur |
182 +---------------------------------------------------------*/
183 for (ptcon = ptcnsfig->LOCON; ptcon != NULL; ptcon = ptcon->NEXT) {
184
185 if (ptcon->DIRECTION == 'X') continue; /* Transparence */
186
187 if (ptcon->DIRECTION == CNS_VDDC || ptcon->DIRECTION == CNS_VSSC) {
188 if (ptcon->DIRECTION == CNS_VDDC && !vddDone && !YAG_CONTEXT->YAG_NO_SUPPLY) {
189 vddSigIndex = nbSig;
190 if (YAG_CONTEXT->YAG_ONE_SUPPLY) {
191 vddDone = TRUE;
192 name = CNS_VDDNAME;
193 }
194 else name = ptcon->NAME;
195 ptsig = addlosig(ptlofig, nbSig, addchain(NULL, name), EXTERNAL);
196 addlorcnet(ptsig);
197 if (ptcon->SIG->PRCN != NULL) capa = rcn_getcapa(ptlotrsfig, ptcon->SIG);
198 else capa = 0.0;
199 rcn_addcapa(ptsig, capa);
200 addlocon(ptlofig, name, getlosig(ptlofig,vddSigIndex), 'I');
201 nbSig++;
202 }
203 else if (ptcon->DIRECTION == CNS_VSSC && !vssDone && !YAG_CONTEXT->YAG_NO_SUPPLY) {
204 vssSigIndex = nbSig;
205 if (YAG_CONTEXT->YAG_ONE_SUPPLY) {
206 vssDone = TRUE;
207 name = CNS_VSSNAME;
208 }
209 else name = ptcon->NAME;
210 ptsig = addlosig(ptlofig, nbSig, addchain(NULL, name), EXTERNAL);
211 addlorcnet(ptsig);
212 if (ptcon->SIG->PRCN != NULL) capa = rcn_getcapa(ptlotrsfig, ptcon->SIG);
213 else capa = 0.0;
214 rcn_addcapa(ptsig, capa);
215 addlocon(ptlofig, name, getlosig(ptlofig,vssSigIndex), 'I');
216 nbSig++;
217 }
218 continue;
219 }
220
221 ptuser = getptype(ptcon->USER, CNS_EXT);
222 /* connecteur sur lequel est monte un cone */
223
224 if (ptuser != NULL) {
225 ptcone = (cone_list*)ptuser->DATA;
226 if (coneIsEmpty(ptcone) != 0) /* si cone non vide */
227 addlocon(ptlofig, ptcon->NAME, getlosig(ptlofig, ptcone->INDEX), ptcon->DIRECTION);
228 else {
229 ptsig = addlosig(ptlofig, nbSig, addchain(NULL, (void*)ptcon->NAME), EXTERNAL);
230 addlorcnet(ptsig);
231 if (ptcon->SIG->PRCN != NULL) capa = rcn_getcapa(ptlotrsfig, ptcon->SIG);
232 else capa = 0.0;
233 rcn_addcapa(ptsig, capa);
234 addlocon(ptlofig, ptcon->NAME, getlosig(ptlofig, nbSig), ptcon->DIRECTION);
235 ptcon->USER = addptype(ptcon->USER, CNS_SIGNAL, (void*)nbSig);
236 nbSig++;
237 }
238 }
239 else { /* les autres */
240 ptsig = addlosig(ptlofig, nbSig, NULL, EXTERNAL);
241 addlorcnet(ptsig);
242 if (ptcon->SIG->PRCN != NULL) capa = rcn_getcapa(ptlotrsfig, ptcon->SIG);
243 else capa = 0.0;
244 rcn_addcapa(ptsig, capa);
245 addlocon(ptlofig, ptcon->NAME, getlosig(ptlofig, nbSig), ptcon->DIRECTION);
246 ptcon->USER = addptype(ptcon->USER, CNS_SIGNAL, (void*)nbSig);
247 nbSig++;
248 }
249 }
250
251 /*-----------------------------------------------------+
252 | On change temporairement l'index de tous les cones |
253 | VDD ou VSS. Leur index prend la valeur de l'index |
254 | du signal associe aux connecteurs ext d'alimentation |
255 +-----------------------------------------------------*/
256 for (ptcone = ptcnsfig->CONE; ptcone != NULL; ptcone = ptcone->NEXT) {
257 if((ptcone->TYPE & CNS_VDD) == CNS_VDD) {
258 ptcone->USER = addptype(ptcone->USER, YAG_OLDINDEX_PTYPE, (void*)ptcone->INDEX);
259 ptcone->INDEX = vddSigIndex;
260 }
261 else if ((ptcone->TYPE & CNS_VSS) == CNS_VSS) {
262 ptcone->USER = addptype(ptcone->USER, YAG_OLDINDEX_PTYPE, (void*)ptcone->INDEX);
263 ptcone->INDEX = vssSigIndex;
264 }
265 else continue;
266 }
267
268 /*----------------------------------------------------+
269 | on crache les instances |
270 +----------------------------------------------------*/
271 for (ptcone = ptcnsfig->CONE; ptcone != NULL; ptcone = ptcone->NEXT) {
272
273 if (ptcone->CELLS != NULL) {
274 for (ptchain = ptcone->CELLS; ptchain; ptchain = ptchain->NEXT) {
275 ptcell = (cell_list *)ptchain->DATA;
276 if ((ptcell->TYPE & ~CNS_UNKNOWN) >= 128 && ptcell->BEFIG == NULL) break;
277 }
278 if (ptchain == NULL) continue;
279 }
280 if (ptcone->OUTCONE == NULL && (ptcone->TYPE & YAG_GLUECONE) == 0) continue;
281 if (coneIsEmpty(ptcone) == 0) continue;
282 if (coneConnect(ptcone) == 0) continue;
283 if ((ptcone->TYPE & CNS_POWER) == CNS_POWER) continue;
284
285 ptuser = getptype(ptcone->USER, YAG_MODEL_PTYPE);
286
287 if (ptuser == NULL) {
288 yagBug(DBG_NO_CONEMODEL,"yagBuildLofig",ptcone->NAME,NULL,0);
289 }
290
291 /*------------------------------------------------------------------+
292 | On recupere le lomodele du cone a partir du model passe dans TsH |
293 +------------------------------------------------------------------*/
294 model = (char *)ptuser->DATA ;
295 nbModel = gethtitem(modelTable, model);
296 ptfig = tabModel[nbModel];
297
298 /*-------------------------------------------+
299 | On constitue un tableau ordonnee de incone |
300 +-------------------------------------------*/
301 nbEdge = 0;
302 for(ptedge = ptcone->INCONE; ptedge != NULL; ptedge = ptedge->NEXT) {
303 if((ptedge->TYPE & CNS_IGNORE) == CNS_IGNORE) continue ;
304 if((ptedge->TYPE & YAG_NOT_FUNCTIONAL) == YAG_NOT_FUNCTIONAL) continue ;
305 if((ptedge->TYPE & CNS_POWER) == CNS_POWER) continue ;
306 if((ptedge->TYPE & (CNS_BLEEDER|CNS_FEEDBACK)) != 0) continue ;
307
308 ptuser = getptype(ptedge->USER, YAG_WEIGHT_PTYPE);
309 i = (int)((long)ptuser->DATA);
310 tabIncone[i] = ptedge;
311 nbEdge++;
312 }
313
314 /*-----------------------------------------+
315 | On fabrique la chainlist des entrees |
316 +-----------------------------------------*/
317 sigchain = NULL;
318 for (i=1; i<=nbEdge; i++) {
319 ptedge = tabIncone[i];
320
321 if ((ptedge->TYPE & CNS_CONE) != 0) {
322 ptxcone = ptedge->UEDGE.CONE ;
323 sigchain = addchain(sigchain, (void*)getlosig(ptlofig, ptxcone->INDEX));
324 }
325 else { /* Entree de type Connecteur */
326 ptcon = ptedge->UEDGE.LOCON;
327 /*-----------------------------------------------------+
328 | Si un cone est monte sur le connecteur , ATTENTION , |
329 | C'est peut etre un cone vide |
330 +-----------------------------------------------------*/
331 if ((ptuser = getptype(ptcon->USER, CNS_EXT)) != NULL) {
332 ptxcone = (cone_list *)ptuser->DATA;
333
334 if (coneIsEmpty(ptxcone) != 0) { /* si cone non vide */
335 sigchain = addchain(sigchain, (void*)getlosig(ptlofig, ptxcone->INDEX));
336 }
337 else { /* si cone vide, le signal
338 qui y est attache n'a pas ete declare mais
339 un signal a ete creee pour le connecteur */
340 ptuser = getptype(ptcon->USER, CNS_SIGNAL);
341 sigchain=addchain(sigchain, (void*)getlosig(ptlofig,(long)ptuser->DATA));
342 }
343 }
344 else { /* Pas de cone monte sur le connecteur -> comme cone vide */
345 ptuser = getptype(ptcon->USER,CNS_SIGNAL);
346 sigchain=addchain(sigchain, (void*)getlosig(ptlofig,(long)ptuser->DATA));
347 }
348 }
349 }
350
351 /* ON RAJOUTE la SORTIE VDD et VSS puis on fait le ADDLOINS*/
352
353 {
354 char insname[YAGBUFSIZE];
355 sigchain = addchain(sigchain,(void*)getlosig(ptlofig,ptcone->INDEX));
356 sigchain = addchain(sigchain,(void*)getlosig(ptlofig,vddSigIndex));
357 sigchain = addchain(sigchain,(void*)getlosig(ptlofig,vssSigIndex));
358 sprintf(insname,"yagins_%s",yagVectorizeName(ptcone->NAME));
359 addloins(ptlofig,namealloc(insname),ptfig,sigchain);
360 }
361 }
362
363 addCellInstances(ptlofig, ptcnsfig, vddSigIndex, vssSigIndex);
364
365 /*----------------------------------------------------+
366 | On remet en place les index des cones alimentation |
367 | et les con EXT contenant un connecteur 'T' |
368 +----------------------------------------------------*/
369 for (ptcone = ptcnsfig->CONE; ptcone != NULL; ptcone = ptcone->NEXT) {
370 if ((ptcone->TYPE & CNS_POWER) == CNS_POWER) {
371 ptuser = getptype(ptcone->USER, YAG_OLDINDEX_PTYPE);
372 ptcone->INDEX = (long)ptuser->DATA;
373 ptcone->USER = delptype(ptcone->USER, YAG_OLDINDEX_PTYPE);
374 }
375 else if ((ptcone->TYPE & CNS_EXT) == CNS_EXT) {
376 restoreConeExt(ptcone);
377 }
378 else if ((ptcone->TYPE & (CNS_MEMSYM|CNS_LATCH)) == CNS_MEMSYM) {
379 restoreConeMemory(ptcone);
380 }
381 else continue;
382 }
383
384 removeGlueCones(ptcnsfig);
385
386 sortlocon(&ptlofig->LOCON);
387 genCatal(YAG_HEAD_MODEL);
388 lofigchain(ptlofig);
389 ptcnsfig->USER = addptype(ptcnsfig->USER, YAG_CONE_NETLIST_PTYPE, ptlofig);
390
391 YAG_CONTEXT->YAG_USE_FCF = save_USE_FCF;
392 }
393
394 /****************************************************************************
395 * function cnsmodToLomod(); *
396 ****************************************************************************/
397 /*--------------------------------------------------------------------------+
398 | Fabrique un lofig contenant essentiellement l'interface du cone |
399 +--------------------------------------------------------------------------*/
400 static lofig_list *
401 cnsmodToLomod(ptcone, index)
402 cone_list *ptcone;
403 int index;
404 {
405 lofig_list *ptfig;
406 edge_list *ptincone;
407 ptype_list *ptuser;
408 char figname[YAGBUFSIZE];
409 long poids;
410 long nbIn = 0;
411 int i = 0;
412
413 for(ptincone = ptcone->INCONE; ptincone != NULL; ptincone = ptincone->NEXT) {
414
415 if((ptincone->TYPE & CNS_IGNORE) == CNS_IGNORE) continue;
416 if((ptincone->TYPE & YAG_NOT_FUNCTIONAL) == YAG_NOT_FUNCTIONAL) continue;
417 if((ptincone->TYPE & CNS_POWER) == CNS_POWER) continue;
418 if((ptincone->TYPE & (CNS_BLEEDER|CNS_FEEDBACK)) != 0) continue;
419
420 ptuser = getptype(ptincone->USER,YAG_WEIGHT_PTYPE);
421 if(ptuser == NULL) {
422 yagBug(DBG_NO_INCONEUSER,"cnsmodToLomod",ptcone->NAME,"YAG_WEIGHT_PTYPE",0);
423 }
424 poids = (long)ptuser->DATA;
425
426 if (poids > nbIn) nbIn = poids;
427 }
428
429 sprintf(figname,"%s_model_%d", CNS_HEADCNSFIG->NAME, index);
430
431 YAG_HEAD_MODEL = addlomodel(YAG_HEAD_MODEL, namealloc(figname));
432 ptfig = YAG_HEAD_MODEL;
433
434 for(i=1; i<=nbIn; i++) addlosig(ptfig, i, (void*)NULL, EXTERNAL);
435
436 addlosig(ptfig, nbIn+1, (void *)NULL, EXTERNAL); /* f */
437 addlosig(ptfig, nbIn+2, (void *)NULL, EXTERNAL); /* vdd */
438 addlosig(ptfig, nbIn+3, (void *)NULL, EXTERNAL); /* vss */
439
440 for (i=1; i<=nbIn; i++) {
441 char buff[6];
442 sprintf(buff, "in%d", i);
443 addlocon(ptfig, namealloc(buff), getlosig(ptfig,i), 'I');
444 }
445
446 if((ptcone->TYPE & CNS_TRI) == CNS_TRI) addlocon(ptfig, namealloc("f"), getlosig(ptfig,nbIn+1), 'Z');
447 else addlocon(ptfig, namealloc("f"), getlosig(ptfig,nbIn+1), 'O');
448
449 addlocon(ptfig, namealloc("vdd"), getlosig(ptfig,nbIn+2), 'I');
450 addlocon(ptfig, namealloc("vss"), getlosig(ptfig,nbIn+3),'I');
451 return ptfig;
452 }
453
454 /****************************************************************************
455 * function coneConnect(); *
456 ****************************************************************************/
457 /*-------------------------------------------------------------------------+
458 | Retourne 0 si le cone est un cone connecteur ie il possede une branche |
459 | functionnelle unique qui est la branche maillon connecteur |
460 | -1 si le cone possede au moins une branche functionnele qui |
461 | n'est pas externe. |
462 +-------------------------------------------------------------------------*/
463 static int
464 coneConnect(ptcone)
465 cone_list *ptcone;
466 {
467 branch_list *ptbranch;
468 short coneconnect = 0;
469 short funcpath = 0;
470
471 if ((ptcone->TYPE & CNS_EXT) != CNS_EXT) return(-1);
472
473 if(ptcone->BREXT==NULL) return(-1);
474
475 for (ptbranch = ptcone->BRVDD; ptbranch; ptbranch = ptbranch->NEXT) {
476 if ((ptbranch->TYPE & CNS_NOT_FUNCTIONAL) == 0) funcpath++;
477 }
478 for (ptbranch = ptcone->BRVSS; ptbranch; ptbranch = ptbranch->NEXT) {
479 if ((ptbranch->TYPE & CNS_NOT_FUNCTIONAL) == 0) funcpath++;
480 }
481 for (ptbranch = ptcone->BREXT; ptbranch; ptbranch = ptbranch->NEXT) {
482 if (ptbranch->LINK->NEXT == NULL) coneconnect++;
483 else funcpath++;
484 }
485
486 if (funcpath != 0) return(-1);
487 else if (coneconnect == 1) return(0);
488 else {
489 yagBug(DBG_MULT_CON, "coneConnect", ptcone->NAME, NULL, 0);
490 }
491 return(0);
492 }
493
494 /****************************************************************************
495 * function coneIsEmpty(); *
496 ****************************************************************************/
497 static int
498 coneIsEmpty(ptcone)
499 cone_list *ptcone;
500 {
501 if ((ptcone->BRVDD == NULL)
502 && (ptcone->BRVSS == NULL)
503 && (ptcone->BREXT == NULL)
504 && (ptcone->BRGND == NULL)
505 && (ptcone->INCONE == NULL)
506 && (ptcone->OUTCONE == NULL))
507 return 0;
508 else return -1;
509 }
510
511 /****************************************************************************
512 * function vbeConeModel(); *
513 ****************************************************************************/
514 /*--------------------------------------------------------------------------+
515 | Sauvegarde sur disque le comportemental Vhdl d'un model de cone |
516 +-------------------------------------------------------------------------*/
517 static void
518 saveVbeConeModel(ptcone, index)
519 cone_list *ptcone;
520 int index;
521 {
522 befig_list *ptbefig;
523 edge_list *ptin;
524 cone_list *ptincone;
525 locon_list *ptcon;
526 ptype_list *ptuser;
527 biabl_list *biexpr;
528 chain_list *expr;
529 char figname[YAGBUFSIZE];
530 char newName[YAGBUFSIZE];
531 char *name;
532 long poids;
533
534 /*--------------------------------------------------------------+
535 | On renomme temporairement tous les cones ou les connecteurs |
536 | qui sont en entree du cone. On parcourt les incones dont on |
537 | connait le poids, et in renomme le cone/connect correspondant |
538 | par un ("in%s",poids) comme pour les instances |
539 | La sortie s'appellera invariablement 'f' |
540 +--------------------------------------------------------------*/
541 for (ptin = ptcone->INCONE; ptin != NULL; ptin = ptin->NEXT) {
542 if ((ptin->TYPE & CNS_IGNORE) == CNS_IGNORE) continue;
543 if ((ptin->TYPE & YAG_NOT_FUNCTIONAL) == YAG_NOT_FUNCTIONAL) continue;
544 if ((ptin->TYPE & CNS_POWER) == CNS_POWER) continue;
545 if ((ptin->TYPE & (CNS_BLEEDER|CNS_FEEDBACK)) != 0) continue;
546
547 if ((ptin->TYPE & CNS_CONE) != 0) {
548 ptincone = ptin->UEDGE.CONE;
549 ptincone->USER = addptype(ptincone->USER, YAG_OLDNAME_PTYPE, (void *)ptincone->NAME);
550 ptuser = getptype(ptin->USER, YAG_WEIGHT_PTYPE);
551 poids = (long)ptuser->DATA;
552 sprintf(newName, "in%ld", poids);
553 ptincone->NAME = namealloc(newName);
554 }
555 else {
556 ptcon = ptin->UEDGE.LOCON;
557 ptcon->USER = addptype(ptcon->USER, YAG_OLDNAME_PTYPE, (void *)ptcon->NAME);
558 ptuser = getptype(ptin->USER, YAG_WEIGHT_PTYPE);
559 poids = (long)ptuser->DATA;
560 sprintf(newName, "in%ld", poids);
561 ptcon->NAME = namealloc(newName);
562 }
563 }
564
565 /*-----------------------------------------------------+
566 | Ecriture du modele sur disque |
567 +-----------------------------------------------------*/
568
569 sprintf(figname, "%s_model_%d", CNS_HEADCNSFIG->NAME, index);
570 if ((ptbefig = yagMakeLatchBehaviour(ptcone, FALSE)) == NULL) {
571 ptbefig = beh_addbefig(NULL, figname);
572 for (ptin = ptcone->INCONE; ptin != NULL; ptin = ptin->NEXT) {
573 if ((ptin->TYPE & CNS_IGNORE) == CNS_IGNORE) continue;
574 if ((ptin->TYPE & YAG_NOT_FUNCTIONAL) == YAG_NOT_FUNCTIONAL) continue;
575 if ((ptin->TYPE & (CNS_BLEEDER|CNS_FEEDBACK)) != 0) continue;
576
577 if ((ptin->TYPE & (CNS_POWER|CNS_CONE)) != 0) {
578 name = ptin->UEDGE.CONE->NAME;
579 }
580 else name = ptin->UEDGE.LOCON->NAME;
581
582 ptbefig->BEPOR = beh_addbepor(ptbefig->BEPOR, name, 'I', 'B');
583 ptbefig->BERIN = beh_addberin(ptbefig->BERIN, name);
584 }
585
586 if ((ptcone->TYPE & CNS_LATCH) != 0 || (ptcone->TYPE & CNS_PRECHARGE) != 0) {
587 ptbefig->BEPOR = beh_addbepor(ptbefig->BEPOR, "f", 'O', 'B');
588 expr = createAtom("aux");
589 ptbefig->BEOUT = beh_addbeout(ptbefig->BEOUT, "f", expr, NULL, 0);
590 biexpr = yagMakeLatchExpr(ptcone);
591 ptbefig->BEREG = beh_addbereg(ptbefig->BEREG, "aux", biexpr, NULL,0);
592 }
593 else if ((ptcone->TYPE & CNS_TRI) == CNS_TRI) {
594 ptbefig->BEPOR = beh_addbepor(ptbefig->BEPOR, "f", 'Z', 'W');
595 biexpr = yagMakeTristateExpr(ptcone);
596 ptbefig->BEBUS = beh_addbebus(ptbefig->BEBUS, "f", biexpr, NULL, 'W',0);
597 }
598 else if ((ptcone->TYPE & CNS_CONFLICT) == CNS_CONFLICT) {
599 ptbefig->BEPOR = beh_addbepor(ptbefig->BEPOR, "f", 'Z', 'W');
600 biexpr = yagMakeTristateExpr(ptcone);
601 ptbefig->BEBUS = beh_addbebus(ptbefig->BEBUS, "f", biexpr, NULL, 'W',0);
602 }
603 else {
604 ptbefig->BEPOR = beh_addbepor(ptbefig->BEPOR, "f", 'O', 'B');
605 expr = yagMakeDualExpr(ptcone);
606 ptbefig->BEOUT = beh_addbeout(ptbefig->BEOUT, "f", expr, NULL, 0);
607 }
608
609 ptbefig->BEPOR = beh_addbepor(ptbefig->BEPOR, CNS_VDDNAME, 'I', 'B');
610 ptbefig->BEPOR = beh_addbepor(ptbefig->BEPOR, CNS_VSSNAME, 'I', 'B');
611 }
612 ptbefig->NAME = figname;
613 savebefig(ptbefig, 0);
614 beh_frebefig(ptbefig);
615
616 /*----------------------------------------------------------+
617 | On remet tous les noms en place |
618 +----------------------------------------------------------*/
619 for (ptin = ptcone->INCONE; ptin != NULL; ptin = ptin->NEXT) {
620 if ((ptin->TYPE & CNS_IGNORE) == CNS_IGNORE) continue;
621 if ((ptin->TYPE & YAG_NOT_FUNCTIONAL) == YAG_NOT_FUNCTIONAL) continue;
622 if ((ptin->TYPE & CNS_POWER) == CNS_POWER) continue;
623 if ((ptin->TYPE & (CNS_BLEEDER|CNS_FEEDBACK)) != 0) continue;
624
625 if ((ptin->TYPE & CNS_CONE) != 0) {
626 ptincone = ptin->UEDGE.CONE;
627 ptuser = getptype(ptincone->USER, YAG_OLDNAME_PTYPE);
628 ptincone->NAME = (char *)ptuser->DATA;
629 ptincone->USER = delptype(ptincone->USER, YAG_OLDNAME_PTYPE);
630 }
631 else {
632 ptcon = ptin->UEDGE.LOCON;
633 ptuser = getptype(ptcon->USER, YAG_OLDNAME_PTYPE);
634 ptcon->NAME = (char *)ptuser->DATA;
635 ptcon->USER = delptype(ptcon->USER, YAG_OLDNAME_PTYPE);
636 }
637 }
638 }
639
640 /****************************************************************************
641 * function prepConeExt(); *
642 ****************************************************************************/
643 /*--------------------------------------------------------------------------+
644 | sauvegarde puis supprime de la liste des branche, la branche qui contient|
645 | un conecteur T , des cone montes sur un connecteur T. L'entree contenant |
646 | le connecteur T est elle type IGNORE . Il va de soit que ces modif ne |
647 | doivent etre que temporaires |
648 +--------------------------------------------------------------------------*/
649 static void
650 prepConeExt(ptcone)
651 cone_list *ptcone;
652 {
653 ptype_list *ptuser;
654 locon_list *ptcon;
655 branch_list *ptbranch;
656 edge_list *ptincone;
657
658 ptuser = getptype(ptcone->USER, CNS_EXT);
659 ptcon = (locon_list *)((chain_list *)ptuser->DATA)->DATA;
660
661 if (ptcon->DIRECTION == 'I' || ptcon->DIRECTION == 'O') return;
662
663 for (ptbranch = ptcone->BREXT; ptbranch != NULL; ptbranch = ptbranch->NEXT) {
664 if (ptbranch->LINK->NEXT != NULL) continue;
665 ptbranch->TYPE |= CNS_IGNORE;
666 ptincone = yagGetEdge(ptcone->INCONE, ptbranch->LINK->ULINK.LOCON);
667 ptincone->TYPE |= CNS_IGNORE;
668 }
669 }
670
671 /****************************************************************************
672 * function restoreConeExt(); *
673 ****************************************************************************/
674 /*-------------------------------------------------------------------------+
675 | Remet en place la branche contenant le connecteur INOUT supprimee par la |
676 | function prepConeExt. |
677 +--------------------------------------------------------------------------*/
678 static void
679 restoreConeExt(ptcone)
680 cone_list *ptcone;
681 {
682 ptype_list *ptuser;
683 locon_list *ptcon;
684 branch_list *ptbranch;
685 edge_list *ptincone;
686
687 ptuser = getptype(ptcone->USER, CNS_EXT);
688 ptcon = (locon_list *)((chain_list *)ptuser->DATA)->DATA;
689
690 if (ptcon->DIRECTION == 'I' || ptcon->DIRECTION == 'O') return;
691
692 for (ptbranch = ptcone->BREXT; ptbranch != NULL; ptbranch = ptbranch->NEXT) {
693 if (ptbranch->LINK->NEXT != NULL) continue;
694 ptbranch->TYPE &= ~CNS_IGNORE;
695 ptincone = yagGetEdge(ptcone->INCONE, ptbranch->LINK->ULINK.LOCON);
696 ptincone->TYPE &= ~CNS_IGNORE;
697 }
698 }
699
700 /****************************************************************************
701 * function delOutConeForVst() *
702 ****************************************************************************/
703 /*------------------------------------------------------------------------+
704 | Suprime les outcone pointant sur des cones sans sorties. Fonction |
705 | iterative, puisque d'une passe a l'autre, les cones perdent des outcones|
706 +------------------------------------------------------------------------*/
707 static void
708 delOutconeForVst(ptcnsfig)
709 cnsfig_list *ptcnsfig;
710 {
711 short change = 0;
712 edge_list *ptin;
713 edge_list *ptout;
714 cone_list *ptincone;
715 cone_list *ptoutcone;
716 cone_list *ptcone;
717
718 while (change == 0) {
719
720 change = -1;
721
722 for (ptcone = ptcnsfig->CONE; ptcone != NULL; ptcone = ptcone->NEXT) {
723 if (ptcone->OUTCONE != NULL) continue;
724
725 for (ptin = ptcone->INCONE; ptin != NULL; ptin = ptin->NEXT) {
726 if ((ptin->TYPE & CNS_EXT) == CNS_EXT) continue;
727
728 ptincone = ptin->UEDGE.CONE;
729 for (ptout = ptincone->OUTCONE; ptout != NULL; ptout = ptout->NEXT) {
730 if ((ptout->TYPE & CNS_EXT) == CNS_EXT) continue;
731
732 ptoutcone = ptout->UEDGE.CONE;
733 if (ptoutcone == ptcone) {
734 ptincone->OUTCONE = deledge(ptincone->OUTCONE, ptout);
735 change = 0;
736 break;
737 }
738 }
739 }
740 }
741 }
742 }
743
744 /****************************************************************************
745 * function genCatal(); *
746 ****************************************************************************/
747 /*--------------------------------------------------------------------------+
748 | Genere le fichier CATAL contenant la liste des modeles suivi de ' C' |
749 +-------------------------------------------------------------------------*/
750 static void
751 genCatal(headModel)
752 lofig_list *headModel;
753 {
754 FILE *ptCatal;
755 lofig_list *ptlofig;
756
757 if ((ptCatal = mbkfopen(CATAL, NULL, WRITE_TEXT)) == NULL) {
758 avt_errmsg(YAG_ERRMSG, "006", AVT_ERROR, CATAL);
759 return;
760 }
761
762 for (ptlofig = headModel; ptlofig != NULL; ptlofig = ptlofig->NEXT)
763 fprintf(ptCatal, "%s C\n", ptlofig->NAME);
764
765 if (fclose(ptCatal) != 0)
766 avt_errmsg(YAG_ERRMSG, "007", AVT_ERROR, CATAL);
767 }
768
769 /****************************************************************************
770 * function prepConeMemory(); *
771 ****************************************************************************/
772 /*--------------------------------------------------------------------------+
773 | Cette function fait en sorte que le cone ressemble temporairement a un |
774 | inverseur |
775 +--------------------------------------------------------------------------*/
776 static void
777 prepConeMemory(ptcone)
778 cone_list *ptcone;
779 {
780 branch_list *ptbranch;
781 edge_list *ptin;
782
783 for (ptin = ptcone->INCONE; ptin != NULL; ptin = ptin->NEXT) {
784 if ((ptin->TYPE & CNS_LOOP) != CNS_LOOP) ptin->TYPE |= CNS_IGNORE;
785 }
786
787 /* ignore all branches of more than one link */
788 for (ptbranch = ptcone->BRVDD; ptbranch; ptbranch = ptbranch->NEXT) {
789 if (ptbranch->LINK->NEXT != NULL) {
790 ptbranch->TYPE |= CNS_IGNORE;
791 }
792 }
793 for (ptbranch = ptcone->BRVSS; ptbranch; ptbranch = ptbranch->NEXT) {
794 if (ptbranch->LINK->NEXT != NULL) {
795 ptbranch->TYPE |= CNS_IGNORE;
796 }
797 }
798 }
799
800 /****************************************************************************
801 * function restoreConeMemory(); *
802 ****************************************************************************/
803 static void
804 restoreConeMemory(ptcone)
805 cone_list *ptcone;
806 {
807 branch_list *ptbranch;
808 edge_list *ptin;
809
810 for (ptin = ptcone->INCONE; ptin != NULL; ptin = ptin->NEXT) {
811 if ((ptin->TYPE & CNS_LOOP) != CNS_LOOP) ptin->TYPE &= ~CNS_IGNORE;
812 }
813
814 for (ptbranch = ptcone->BRVDD; ptbranch; ptbranch = ptbranch->NEXT) {
815 if ((ptbranch->TYPE & CNS_IGNORE) == CNS_IGNORE) {
816 ptbranch->TYPE &= ~(CNS_IGNORE);
817 }
818 }
819 for (ptbranch = ptcone->BRVSS; ptbranch; ptbranch = ptbranch->NEXT) {
820 if ((ptbranch->TYPE & CNS_IGNORE) == CNS_IGNORE) {
821 ptbranch->TYPE &= ~(CNS_IGNORE);
822 }
823 }
824 }
825
826 /****************************************************************************
827 * function addGlueCones(); *
828 ****************************************************************************/
829 static void
830 addGlueCones(ptcnsfig)
831 cnsfig_list *ptcnsfig;
832 {
833 cone_list *ptcone;
834 cone_list *headgluecone;
835 ptype_list *ptuser;
836 long index;
837
838 ptuser = getptype(ptcnsfig->USER, YAG_GLUECONE_PTYPE);
839 if (ptuser != NULL) {
840 headgluecone = (cone_list *)ptuser->DATA;
841 for (ptcone = ptcnsfig->CONE; ptcone->NEXT; ptcone = ptcone->NEXT);
842 ptcone->NEXT = headgluecone;
843 index = ptcone->INDEX + 1;
844 for (ptcone = headgluecone; ptcone; ptcone = ptcone->NEXT) {
845 ptcone->INDEX = index++;
846 }
847 }
848 }
849
850 /****************************************************************************
851 * function removeGlueCones(); *
852 ****************************************************************************/
853 static void
854 removeGlueCones(ptcnsfig)
855 cnsfig_list *ptcnsfig;
856 {
857 cone_list *ptcone;
858 cone_list *headgluecone;
859 ptype_list *ptuser;
860
861 ptuser = getptype(ptcnsfig->USER, YAG_GLUECONE_PTYPE);
862 if (ptuser != NULL) {
863 headgluecone = (cone_list *)ptuser->DATA;
864 for (ptcone = ptcnsfig->CONE; ptcone->NEXT != headgluecone; ptcone = ptcone->NEXT);
865 ptcone->NEXT = NULL;
866 }
867 }
868
869 static void
870 addCellInstances(ptlofig, ptcnsfig, vddSigIndex, vssSigIndex)
871 lofig_list *ptlofig;
872 cnsfig_list *ptcnsfig;
873 long vddSigIndex;
874 long vssSigIndex;
875 {
876 cell_list *ptcell;
877 cone_list *ptcone;
878 lofig_list *ptmodel;
879 losig_list *ptsig;
880 chain_list *cellsiglist;
881 chain_list *sigchain;
882 chain_list *ptchain;
883 char insname[YAGBUFSIZE];
884 ht *modelTable;
885
886 modelTable = addht(20);
887 for (ptcell = ptcnsfig->CELL; ptcell; ptcell = ptcell->NEXT) {
888 if (ptcell->BEFIG == NULL && (ptcell->TYPE & ~CNS_UNKNOWN) >= 128) continue;
889 sigchain = NULL;
890 ptmodel = (lofig_list *)gethtitem(modelTable, (void *)ptcell->TYPE);
891 if (ptmodel == (lofig_list *)EMPTYHT) {
892 ptmodel = cellToLomod(ptcell);
893 addhtitem(modelTable, (void *)ptcell->TYPE, (long)ptmodel);
894 }
895 cellsiglist = (chain_list *)getptype(ptcell->USER, YAG_SIGLIST_PTYPE)->DATA;
896 for (ptchain = cellsiglist; ptchain; ptchain = ptchain->NEXT) {
897 ptsig = (losig_list *)ptchain->DATA;
898 ptcone = (cone_list *)getptype(ptsig->USER, YAG_CONE_PTYPE)->DATA;
899 sigchain = addchain(sigchain, getlosig(ptlofig, ptcone->INDEX));
900 }
901 sigchain = reverse(sigchain);
902 sigchain = addchain(sigchain, getlosig(ptlofig, vddSigIndex));
903 sigchain = addchain(sigchain, getlosig(ptlofig, vssSigIndex));
904 sprintf(insname, "yagins_%s", ptcell->BEFIG->NAME);
905 addloins(ptlofig, namealloc(insname), ptmodel, sigchain);
906 }
907 }
908
909 static lofig_list *
910 cellToLomod(ptcell)
911 cell_list *ptcell;
912 {
913 befig_list *ptbefig;
914 lofig_list *ptlofig;
915 bepor_list *ptbepor;
916 losig_list *ptlosig;
917 char figname[YAGBUFSIZE];
918 char direction;
919 long index = 1;
920 long numset, numreset;
921
922 switch (ptcell->TYPE & YAG_CELLMASK) {
923 case YAG_CELL_MS_SC:
924 sprintf(figname, "%s_ms_sc", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
925 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", NULL, NULL, NULL, "mem", "q", "qn", TRUE, NULL);
926 break;
927 case YAG_CELL_MSS_SC:
928 sprintf(figname, "%s_mss_sc", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
929 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", "s", NULL, NULL, "mem", "q", "qn", TRUE, NULL);
930 break;
931 case YAG_CELL_MSR_SC:
932 sprintf(figname, "%s_msr_sc", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
933 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", NULL, "r", NULL, "mem", "q", "qn", TRUE, NULL);
934 break;
935 case YAG_CELL_MSNR_SC:
936 sprintf(figname, "%s_msnr_sc", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
937 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", NULL, NULL, "nr", "mem", "q", "qn", TRUE, NULL);
938 break;
939 case YAG_CELL_MS_SC_RT:
940 sprintf(figname, "%s_ms_sc_rt", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
941 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", NULL, NULL, NULL, "mem", "q", "qn", FALSE, NULL);
942 break;
943 case YAG_CELL_MSS_SC_RT:
944 sprintf(figname, "%s_mss_sc_rt", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
945 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", "s", NULL, NULL, "mem", "q", "qn", FALSE, NULL);
946 break;
947 case YAG_CELL_MSR_SC_RT:
948 sprintf(figname, "%s_msr_sc_rt", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
949 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", NULL, "r", NULL, "mem", "q", "qn", FALSE, NULL);
950 break;
951 case YAG_CELL_MSNR_SC_RT:
952 sprintf(figname, "%s_msnr_sc_rt", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
953 ptbefig = yagBuildBefigMSSC(figname, NULL, NULL, "d", "ck", NULL, NULL, "nr", "mem", "q", "qn", FALSE, NULL);
954 break;
955 case YAG_CELL_MSDIFF:
956 sprintf(figname, "%s_msdiff", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
957 ptbefig = yagBuildBefigMSDIFF(figname, "d", "ck", "mem", "q", "qn", NULL);
958 break;
959 case YAG_CELL_FFT2:
960 sprintf(figname, "%s_fft2", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
961 ptbefig = yagBuildBefigFFT2(figname, NULL, NULL, "d", "cpn", "ld", "re", "mem", "q", "qn", NULL);
962 break;
963 case YAG_CELL_FD2R:
964 sprintf(figname, "%s_fd2r", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
965 ptbefig = yagBuildBefigFD2R(figname, NULL, NULL, "d", "cpn", "re", "mem", "q", "qn", NULL);
966 break;
967 case YAG_CELL_FD2S:
968 sprintf(figname, "%s_fd2s", YAG_CONTEXT->YAG_CURCNSFIG->NAME);
969 ptbefig = yagBuildBefigFD2S(figname, NULL, NULL, "d", "cpn", "re", "mem", "q", "qn", NULL);
970 break;
971 default:
972 if ((ptcell->TYPE & ~CNS_UNKNOWN) < 128) {
973 yagBug(DBG_ILL_CELLTYPE, "cellToLomod", NULL, NULL, 0);
974 }
975 else if ((ptbefig = fclGetBefig(ptcell->BEFIG->NAME)) == NULL) {
976 yagBug(DBG_ILL_CELLTYPE, "cellToLomod", NULL, NULL, 0);
977 }
978 strcpy(figname, ptbefig->NAME);
979 }
980 savebefig(ptbefig, 0);
981
982 YAG_HEAD_MODEL = addlomodel(YAG_HEAD_MODEL, namealloc(figname));
983 ptlofig = YAG_HEAD_MODEL;
984
985 for (ptbepor = ptbefig->BEPOR; ptbepor; ptbepor = ptbepor->NEXT) {
986 ptlosig = addlosig(ptlofig, index++, NULL, EXTERNAL);
987 switch (ptbepor->DIRECTION) {
988 case 'I': direction = IN; break;
989 case 'O': direction = OUT; break;
990 case 'Z': direction = TRISTATE; break;
991 case 'B': direction = INOUT; break;
992 case 'T': direction = TRANSCV; break;
993 }
994 addlocon(ptlofig, ptbepor->NAME, ptlosig, direction);
995 }
996 ptlofig->LOCON = (locon_list *)reverse((chain_list *)ptlofig->LOCON);
997
998 savelofig(ptlofig);
999 beh_frebefig(ptbefig);
1000
1001 return ptlofig;
1002 }
1003
1004 static chain_list *
1005 labelEnum(root, num)
1006 char *root;
1007 long num;
1008 {
1009 chain_list *labels = NULL;
1010 char buf[64];
1011 int i;
1012
1013 for (i=1; i<= num; i++) {
1014 sprintf(buf, "%s%d", root, i);
1015 labels = addchain(labels, namealloc(buf));
1016 }
1017 return labels;
1018 }