Initial version of donated sources by Avertec, 3.4p5.
[tas-yagle.git] / distrib / sources / tas / stb / stb_drive.c
1 /****************************************************************************/
2 /* */
3 /* Chaine de CAO & VLSI AVERTEC */
4 /* */
5 /* Produit : STB Version 1.00 */
6 /* Fichier : stb_drive.c */
7 /* */
8 /* (c) copyright 2000 AVERTEC */
9 /* Tous droits reserves */
10 /* */
11 /* Auteur(s) : Karim DIOURY */
12 /* Anthony LESTER */
13 /* */
14 /****************************************************************************/
15
16 #include STB_H
17 #include AVT_H
18
19 #include "stb_util.h"
20 #include "stb_error.h"
21 #include "stb_transfer.h"
22 #include "stb_drive.h"
23 #include "stb_directives.h"
24
25 /*****************************************************************************
26 * static function declarations *
27 *****************************************************************************/
28
29 static void stb_writesig __P((FILE *ptfile, stbfig_list *ptstbfig, ttvsig_list *ptttvsig, int format));
30 static void stb_writeintervals __P((FILE *ptfile, stbpair_list *ptheadstbpair, int format));
31 static void stb_writeintervals_split(FILE *ptfile, stbfig_list *sb, stbnode *node, int hz, char phase);
32
33 /*****************************************************************************
34 * fonction stb_savestbfig() *
35 *****************************************************************************/
36
37
38
39 static void stb_driveconfig(FILE *ptfile, inffig_list *ifl)
40 {
41 int i;
42
43 fprintf(ptfile, "Conditions\nBegin\n");
44 for (i=0; i<(signed)sto_cfg_size; i++)
45 {
46 if (sto_cfg[i].type=='b' && V_BOOL_TAB[sto_cfg[i].idx].SET)
47 fprintf(ptfile, " %s = \"%s\";\n", V_BOOL_TAB[sto_cfg[i].idx].VAR, V_BOOL_TAB[sto_cfg[i].idx].VALUE?"yes":"no");
48 else if (sto_cfg[i].type=='s' && V_STR_TAB[sto_cfg[i].idx].SET && V_STR_TAB[sto_cfg[i].idx].VALUE!=NULL)
49 fprintf(ptfile, " %s = \"%s\";\n", V_STR_TAB[sto_cfg[i].idx].VAR, V_STR_TAB[sto_cfg[i].idx].VALUE);
50 else if (sto_cfg[i].type=='i' && V_INT_TAB[sto_cfg[i].idx].SET)
51 fprintf(ptfile, " %s = \"%d\";\n", V_INT_TAB[sto_cfg[i].idx].VAR, V_INT_TAB[sto_cfg[i].idx].VALUE);
52 }
53 fprintf(ptfile, " key_fp_bp = \"%x\";\n", stb_getfalsepathkey(ifl));
54 fprintf(ptfile, " key_mc = \"%x\";\n", stb_getmulticyclekey(ifl));
55 fprintf(ptfile, " key_d = \"%x\";\n", stb_getdirectivekey(ifl));
56 fprintf(ptfile, " key_dm = \"%x\";\n", stb_getdelaymarginkey(ifl));
57 fprintf(ptfile, " key_nc = \"%x\";\n", stb_getnocheckkey(ifl));
58 fprintf(ptfile, " key_nf_nr = \"%x\";\n", stb_getlistsectionkey(ifl, INF_NORISING)*3+stb_getlistsectionkey(ifl, INF_NOFALLING));
59 fprintf(ptfile, " key_fs = \"%x\";\n", stb_getfalseslackkey(ifl));
60 fprintf(ptfile, " key_proba = \"%x\";\n",stb_getswitchingprobakey(ifl));
61 fprintf(ptfile, " key_uncertainty = \"%x\";\n", stb_getclockuncertaintykey(ifl));
62
63 fprintf(ptfile, "End;\n\n");
64 }
65
66 static void
67 stb_writesetuphold(FILE *ptfile, ttvsig_list *ptttvsig, char *signame)
68 {
69 stbnode *nodeu, *noded;
70 noded=stb_getstbnode(ptttvsig->NODE);
71 nodeu=stb_getstbnode(ptttvsig->NODE+1);
72 if (nodeu->SETUP!=STB_NO_TIME || nodeu->HOLD!=STB_NO_TIME
73 || noded->SETUP!=STB_NO_TIME || noded->HOLD!=STB_NO_TIME)
74 {
75 fprintf(ptfile, " \"%s\" :", signame);
76 fprintf(ptfile, " ( %s %s ) ", noded->SETUP==STB_NO_TIME?"-":stb_drvtime(noded->SETUP), noded->HOLD==STB_NO_TIME?"-":stb_drvtime(noded->HOLD));
77 fprintf(ptfile, " ( %s %s );\n", nodeu->SETUP==STB_NO_TIME?"-":stb_drvtime(nodeu->SETUP), nodeu->HOLD==STB_NO_TIME?"-":stb_drvtime(nodeu->HOLD));
78 }
79 }
80
81 static void
82 stb_writeflags(FILE *ptfile, ttvsig_list *ptttvsig, char *signame)
83 {
84 stbnode *nodeu, *noded;
85 noded=stb_getstbnode(ptttvsig->NODE);
86 nodeu=stb_getstbnode(ptttvsig->NODE+1);
87 if ((nodeu->FLAG & STB_NODE_STABCORRECT)!=0
88 || (noded->FLAG & STB_NODE_STABCORRECT)!=0)
89 {
90 fprintf(ptfile, " \"%s\" :", signame);
91 fprintf(ptfile, " \"%s\"", (noded->FLAG & STB_NODE_STABCORRECT)!=0?"S":"");
92 fprintf(ptfile, " \"%s\";\n", (nodeu->FLAG & STB_NODE_STABCORRECT)!=0?"S":"");
93 }
94 }
95
96 int
97 stb_savestbfig(ptstbfig, mode, format, suffix)
98 stbfig_list *ptstbfig;
99 int mode, format, suffix;
100 {
101 FILE *stbout;
102 ttvsig_list *ptttvsig;
103 ttvevent_list *ptevent;
104 stbnode *ptstbnode;
105 stbck *ptstbck;
106 chain_list *ptchain;
107 ptype_list *pt;
108 char namebuf[1024];
109 char suffixbuf[4];
110 char state;
111 int conditioned = FALSE;
112 int internals = FALSE;
113 int memories = FALSE, invert, ideal, virt;
114 stb_propagated_clock_to_clock *spctc;
115 ttv_directive *sd;
116 inffig_list *ifl;
117
118 if (suffix == STB_SUFFIX_STO) {
119 strcpy(suffixbuf, "sto");
120 }
121 else if (suffix == STB_SUFFIX_STB) {
122 strcpy(suffixbuf, "stb");
123 }
124 else {
125 stb_error(ERR_UNKNOWN_SUFFIX, NULL, 0, STB_FATAL);
126 }
127
128 if ((stbout = mbkfopen(ptstbfig->FIG->INFO->FIGNAME, suffixbuf, WRITE_TEXT)) == NULL) {
129 stb_error(ERR_CANNOT_OPEN, NULL, 0, STB_FATAL);
130 }
131
132 /* General Header */
133
134 avt_printExecInfo(stbout, "#","","");
135
136 fprintf(stbout, "NAME \"%s\";\n", ptstbfig->FIG->INFO->FIGNAME);
137 fprintf(stbout, "SETUPTIME %s;\n", stb_drvtime(ptstbfig->SETUP));
138 fprintf(stbout, "HOLDTIME %s;\n", stb_drvtime(ptstbfig->HOLD));
139 fprintf(stbout, "\n");
140
141
142 stb_driveconfig(stbout, getloadedinffig(ptstbfig->FIG->INFO->FIGNAME));
143
144 /* Clock Connectors */
145
146 if (ptstbfig->CLOCK != NULL) {
147 fprintf(stbout, "CLOCK CONNECTORS\n");
148 fprintf(stbout, "BEGIN\n");
149
150 for (ptchain = ptstbfig->CLOCK; ptchain; ptchain = ptchain->NEXT) {
151 ptttvsig = (ttvsig_list *)ptchain->DATA;
152 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
153 ptstbnode = stb_getstbnode(ptttvsig->NODE);
154 if ((pt=getptype(ptttvsig->USER, STB_IS_CLOCK))!=NULL)
155 spctc=(stb_propagated_clock_to_clock *)pt->DATA;
156 else
157 spctc=NULL;
158
159 if (spctc!=NULL) ptstbck=&spctc->original_waveform;
160 else ptstbck = ptstbnode->CK;
161
162 if (getptype(ptttvsig->USER, STB_INVERTED_CLOCK)) invert=1;
163 else invert=0;
164 if (getptype(ptttvsig->USER, STB_IDEAL_CLOCK)) ideal=1;
165 else ideal=0;
166 if (getptype(ptttvsig->USER, STB_VIRTUAL_CLOCK)) virt=1;
167 else virt=0;
168
169 fprintf(stbout, " %s%s%s \"%s\":\n", virt?"VIRTUAL ":"",ideal?"IDEAL ":"", invert?"! ":"", namebuf);
170 fprintf(stbout, " %s (%s:%s);\n", !invert?"UP":"DOWN", stb_drvtime(ptstbck->SUPMIN), stb_drvtime(ptstbck->SUPMAX));
171 fprintf(stbout, " %s (%s:%s);\n", !invert?"DOWN":"UP", stb_drvtime(ptstbck->SDNMIN), stb_drvtime(ptstbck->SDNMAX));
172 fprintf(stbout, " PERIOD %s;\n", stb_drvtime(ptstbck->PERIOD));
173
174 if (spctc!=NULL && spctc->master!=NULL)
175 {
176 fprintf(stbout, " CLOCK \"%s\" %s %s;\n", spctc->master, (spctc->edges & 2)!=0?"UP":"DOWN", (spctc->edges & 1)!=0?"UP":"DOWN");
177 }
178 }
179
180 fprintf(stbout, "END;\n");
181 fprintf(stbout, "\n");
182 }
183
184 fprintf(stbout, "ClockLatencies\nBegin\n");
185 for (ptchain = ptstbfig->CLOCK; ptchain; ptchain = ptchain->NEXT) {
186 long a, b, c, d;
187 ptttvsig = (ttvsig_list *)ptchain->DATA;
188 if ((pt=getptype(ptttvsig->USER, STB_IS_CLOCK))!=NULL)
189 {
190 spctc=(stb_propagated_clock_to_clock *)pt->DATA;
191 if (getptype(ptttvsig->USER, STB_INVERTED_CLOCK))
192 {
193 a=spctc->latencies.SDNMIN; b=spctc->latencies.SDNMAX; c=spctc->latencies.SUPMIN; d=spctc->latencies.SUPMAX;
194 }
195 else
196 {
197 a=spctc->latencies.SUPMIN; b=spctc->latencies.SUPMAX; c=spctc->latencies.SDNMIN; d=spctc->latencies.SDNMAX;
198 }
199 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
200 fprintf(stbout, " \"%s\" : %s %s", namebuf, stb_drvtime(a), stb_drvtime(b));
201 fprintf(stbout, " %s %s;\n", stb_drvtime(c), stb_drvtime(d));
202 }
203 }
204 fprintf(stbout, "End;\n\n");
205
206
207
208 /* equivalent clock group */
209 if ((pt=getptype(ptstbfig->USER, STB_EQUIVALENT))!=NULL)
210 {
211 int num;
212 chain_list *cl;
213 fprintf(stbout, "Equivalent Clock Groups\n");
214 fprintf(stbout, "Begin\n");
215 for (ptchain =(chain_list *)pt->DATA, num=1; ptchain!=NULL; ptchain=ptchain->NEXT, num++)
216 {
217 fprintf(stbout, " Group%d:", num);
218 for (cl=ptchain->DATA; cl!=NULL; cl=cl->NEXT)
219 {
220 ptttvsig=(ttvsig_list *)cl->DATA;
221 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
222 fprintf(stbout, " \"%s\"%s", namebuf, cl->NEXT!=NULL?",":";");
223 }
224 fprintf(stbout, "\n");
225 }
226 fprintf(stbout, "End;\n\n");
227 }
228
229 /* asynchronous clock group */
230 if ((pt=getptype(ptstbfig->USER, STB_DOMAIN))!=NULL)
231 {
232 int num;
233 chain_list *cl;
234 fprintf(stbout, "Asynchronous Clock Groups\n");
235 fprintf(stbout, "Begin\n");
236 for (ptchain =(chain_list *)pt->DATA, num=1; ptchain!=NULL; ptchain=ptchain->NEXT, num++)
237 {
238 fprintf(stbout, " Group%d:", num);
239 for (cl=ptchain->DATA; cl!=NULL; cl=cl->NEXT)
240 {
241 ptttvsig=(ttvsig_list *)cl->DATA;
242 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
243 fprintf(stbout, " \"%s\"%s", namebuf, cl->NEXT!=NULL?",":";");
244 }
245 fprintf(stbout, "\n");
246 }
247 fprintf(stbout, "End;\n\n");
248 }
249
250 if ((ifl=getloadedinffig(ptstbfig->FIG->INFO->FIGNAME))!=NULL)
251 {
252 infDriveStbSpecSection (stbout, ifl, INF_SPECIN, "Specify Input Connectors");
253 infDriveStbSpecSection (stbout, ifl, INF_SPECOUT, "Verify Output Connectors");
254 }
255
256 /* Conditioned Command States */
257
258 if (ptstbfig->COMMAND != NULL) {
259
260 for (ptchain = ptstbfig->COMMAND; ptchain; ptchain = ptchain->NEXT) {
261 ptttvsig = (ttvsig_list *)ptchain->DATA;
262 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
263 ptstbnode = stb_getstbnode(ptttvsig->NODE);
264 ptstbck = ptstbnode->CK;
265 state = ptstbck->VERIF & (STB_UP|STB_DN);
266 if (state != 0) {
267 if (conditioned == FALSE) {
268 conditioned = TRUE;
269 fprintf(stbout, "CONDITIONED COMMAND STATES\n");
270 fprintf(stbout, "BEGIN\n");
271 }
272 if (state == STB_UP) fprintf(stbout, " \"%s\": UP;\n", namebuf);
273 else fprintf(stbout, " \"%s\": DOWN;\n", namebuf);
274 }
275 }
276
277 if (conditioned == TRUE) {
278 fprintf(stbout, "END;\n");
279 fprintf(stbout, "\n");
280 }
281 }
282
283 /* Stability of Input Connectors */
284
285 fprintf(stbout, "INPUT CONNECTORS STABILITY\n");
286 fprintf(stbout, "BEGIN\n");
287
288 for (ptchain = ptstbfig->CONNECTOR; ptchain; ptchain = ptchain->NEXT) {
289 ptttvsig = (ttvsig_list *)ptchain->DATA;
290 if ((ptttvsig->TYPE & TTV_SIG_CI) != TTV_SIG_CI || (ptttvsig->TYPE & TTV_SIG_CB) == TTV_SIG_CB) continue;
291 if (stb_getstbnode(ptttvsig->NODE)->CK != NULL) {
292 if (stb_getstbnode(ptttvsig->NODE)->CK->TYPE == STB_TYPE_CLOCK)
293 continue;
294 }
295 stb_writesig(stbout, ptstbfig, ptttvsig, format);
296 }
297
298 fprintf(stbout, "END;\n");
299 fprintf(stbout, "\n");
300
301 /* Stability of Output Connectors */
302
303 fprintf(stbout, "OUTPUT CONNECTORS STABILITY\n");
304 fprintf(stbout, "BEGIN\n");
305
306 for (ptchain = ptstbfig->CONNECTOR; ptchain; ptchain = ptchain->NEXT) {
307 ptttvsig = (ttvsig_list *)ptchain->DATA;
308 if ((ptttvsig->TYPE & TTV_SIG_CO) != TTV_SIG_CO) continue;
309 stb_writesig(stbout, ptstbfig, ptttvsig, format);
310 }
311
312 fprintf(stbout, "END;\n");
313 fprintf(stbout, "\n");
314
315 /* Stability of Memory nodes */
316
317 if (mode == STB_DRIVE_INTERNALS) {
318
319 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT) {
320 ptevent = (ttvevent_list *)ptchain->DATA;
321 ptttvsig = ptevent->ROOT;
322 if ((ptttvsig->TYPE & TTV_SIG_MARQUE) == TTV_SIG_MARQUE) continue;
323 if ((ptttvsig->TYPE & TTV_SIG_L) != TTV_SIG_L) continue;
324 if (memories == FALSE) {
325 memories = TRUE;
326 fprintf(stbout, "MEMORY NODES STABILITY\n");
327 fprintf(stbout, "BEGIN\n");
328 }
329 ptttvsig->TYPE |= TTV_SIG_MARQUE;
330 stb_writesig(stbout, ptstbfig, ptttvsig, format);
331 }
332
333 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT) {
334 ptevent = (ttvevent_list *)ptchain->DATA;
335 ptttvsig = ptevent->ROOT;
336 ptttvsig->TYPE &= ~(TTV_SIG_MARQUE);
337 }
338
339 if (memories == TRUE) {
340 fprintf(stbout, "END;\n");
341 fprintf(stbout, "\n");
342 }
343 }
344
345 /* Stability of Internal nodes */
346
347 if (mode == STB_DRIVE_INTERNALS) {
348
349 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT) {
350 ptevent = (ttvevent_list *)ptchain->DATA;
351 ptttvsig = ptevent->ROOT;
352 if ((ptttvsig->TYPE & TTV_SIG_MARQUE) == TTV_SIG_MARQUE) continue;
353 if ((ptttvsig->TYPE & TTV_SIG_C) == TTV_SIG_C) continue;
354 if ((ptttvsig->TYPE & TTV_SIG_L) == TTV_SIG_L) continue;
355 if (internals == FALSE) {
356 internals = TRUE;
357 fprintf(stbout, "INTERNAL NODES STABILITY\n");
358 fprintf(stbout, "BEGIN\n");
359 }
360 ptttvsig->TYPE |= TTV_SIG_MARQUE;
361 stb_writesig(stbout, ptstbfig, ptttvsig, format);
362 }
363
364 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT) {
365 ptevent = (ttvevent_list *)ptchain->DATA;
366 ptttvsig = ptevent->ROOT;
367 ptttvsig->TYPE &= ~(TTV_SIG_MARQUE);
368 }
369
370 if (internals == TRUE) {
371 fprintf(stbout, "END;\n");
372 fprintf(stbout, "\n");
373 }
374 }
375
376 fprintf(stbout, "SetupHold\n");
377 fprintf(stbout, "Begin\n");
378
379 fprintf(stbout, "# <signal name> : ( <fallsetup> <fallhold> ) ( <risesetup> <risehold> ) ;\n");
380 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT) {
381 ptevent = (ttvevent_list *)ptchain->DATA;
382 ptttvsig = ptevent->ROOT;
383 if ((ptttvsig->TYPE & TTV_SIG_MARQUE) == TTV_SIG_MARQUE) continue;
384 ptttvsig->TYPE |= TTV_SIG_MARQUE;
385 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
386 stb_writesetuphold(stbout, ptttvsig, namebuf);
387 }
388 fprintf(stbout, "End;\n");
389 fprintf(stbout, "\n");
390
391
392 fprintf(stbout, "StabFlags\n");
393 fprintf(stbout, "Begin\n");
394 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT) {
395 ptevent = (ttvevent_list *)ptchain->DATA;
396 ptttvsig = ptevent->ROOT;
397 if ((ptttvsig->TYPE & TTV_SIG_MARQUE) != TTV_SIG_MARQUE) continue;
398 ptttvsig->TYPE &= ~TTV_SIG_MARQUE;
399 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
400 stb_writeflags(stbout, ptttvsig, namebuf);
401 }
402 fprintf(stbout, "End;\n");
403 fprintf(stbout, "\n");
404
405 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT) {
406 ptevent = (ttvevent_list *)ptchain->DATA;
407 ptttvsig = ptevent->ROOT;
408 ptttvsig->TYPE &= ~TTV_SIG_MARQUE;
409 }
410
411 /* fprintf (stbout, "Directives\nBegin\n");
412 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT)
413 {
414 ptevent = (ttvevent_list *)ptchain->DATA;
415 ptttvsig = ptevent->ROOT;
416 if ((ptttvsig->TYPE & TTV_SIG_MARQUE) == TTV_SIG_MARQUE) continue;
417 ptttvsig->TYPE |= TTV_SIG_MARQUE;
418 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
419 if ((sd=stb_get_directive(ptttvsig))!=NULL)
420 {
421 while (sd!=NULL)
422 {
423 if (sd->filter) fprintf (stbout, " FILTER: "); else fprintf (stbout, " CHECK: ");
424
425 if (sd->target1_dir & INF_DIRECTIVE_CLOCK) fprintf (stbout, "CLOCK ");
426 fprintf (stbout, "\"%s\" ", namebuf);
427
428 if (sd->target1_dir & INF_DIRECTIVE_UP) fprintf(stbout, "Up ");
429 else if (sd->target1_dir & INF_DIRECTIVE_DOWN) fprintf(stbout, "Down ");
430 else if (sd->target1_dir & INF_DIRECTIVE_RISING) fprintf(stbout, "Rising ");
431 else if (sd->target1_dir & INF_DIRECTIVE_FALLING) fprintf(stbout, "Falling ");
432
433 if (sd->operation & INF_DIRECTIVE_BEFORE) fprintf(stbout, "Before ");
434 else if (sd->operation & INF_DIRECTIVE_AFTER) fprintf(stbout, "After ");
435 else fprintf(stbout, "With ");
436
437 if (sd->target2!=NULL)
438 {
439 char namebuf2[1024];
440 ttv_getsigname(ptstbfig->FIG, namebuf2, sd->target2);
441 if (sd->target2_dir & INF_DIRECTIVE_CLOCK) fprintf(stbout, "Clock ");
442 fprintf(stbout, "\"%s\" ", namebuf2);
443 if (sd->target2_dir & INF_DIRECTIVE_UP) fprintf(stbout, "Up ");
444 else if (sd->target2_dir & INF_DIRECTIVE_DOWN) fprintf(stbout, "Down ");
445 else if (sd->target2_dir & INF_DIRECTIVE_RISING) fprintf(stbout, "Rising ");
446 else if (sd->target2_dir & INF_DIRECTIVE_FALLING) fprintf(stbout, "Falling ");
447
448 if (sd->margin!=0) fprintf(stbout, "Margin %.1f", sd->margin/TTV_UNIT);
449 }
450 fprintf(stbout,";\n");
451 sd=sd->next;
452 }
453 }
454 }
455
456 for (ptchain = ptstbfig->NODE; ptchain; ptchain = ptchain->NEXT)
457 {
458 ptevent = (ttvevent_list *)ptchain->DATA;
459 ptttvsig = ptevent->ROOT;
460 ptttvsig->TYPE &= ~TTV_SIG_MARQUE;
461 }
462 fprintf(stbout, "End;\n");
463 fprintf(stbout, "\n");
464 */
465
466 if (fclose(stbout)) {
467 stb_error(ERR_CANNOT_CLOSE, NULL, 0, STB_FATAL);
468 }
469
470 return 0;
471 }
472
473 /*****************************************************************************
474 * fonction stb_writesig() *
475 *****************************************************************************/
476 static void
477 stb_writesig(ptfile, ptstbfig, ptttvsig, format)
478 FILE *ptfile;
479 stbfig_list *ptstbfig;
480 ttvsig_list *ptttvsig;
481 int format;
482 {
483 stbnode *ptstbnode_up;
484 stbnode *ptstbnode_dn;
485 char namebuf[1024];
486 char phasebuf[1024];
487 char active_edge;
488 int i;
489
490 ptstbnode_dn = stb_getstbnode(ptttvsig->NODE);
491 ptstbnode_up = stb_getstbnode(ptttvsig->NODE+1);
492 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
493 for (i = 0; i < ptstbfig->PHASENUMBER; i++) {
494 /* add source phase */
495 strcpy(phasebuf, " FROM \"");
496 if (stb_getclock(ptstbfig, i, phasebuf+7, &active_edge, NULL) == NULL) {
497 if (i == 0) {/* combinatorial */
498 phasebuf[0] = 0;
499 }
500 else
501 {
502 stb_error(ERR_UNKNOWN_CLOCK, namebuf, i, STB_NONFATAL/*STB_FATAL*/);
503 continue;
504 }
505 }
506 else {
507 strcat(phasebuf, "\"");
508 if (active_edge == STB_SLOPE_DN) {
509 strcat(phasebuf, " FALLING");
510 }
511 else strcat(phasebuf, " RISING");
512 }
513
514 /* write intervals for hz precharge/evaluate */
515 if (ptstbnode_dn != NULL) {
516 if (ptstbnode_dn->STBHZ != NULL) {
517 if (ptstbnode_dn->STBHZ[i] != NULL) {
518 if (ptstbnode_dn->CK->TYPE == STB_TYPE_PRECHARGE) {
519 fprintf(ptfile, " \"%s\" FALLING%s WITHOUT PRECHARGE:\n", namebuf, phasebuf);
520 stb_writeintervals(ptfile, ptstbnode_dn->STBHZ[i], format);
521 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_dn, 1, i);
522 }
523 else if (ptstbnode_dn->CK->TYPE == STB_TYPE_EVAL) {
524 fprintf(ptfile, " \"%s\" FALLING%s WITHOUT EVALUATE:\n", namebuf, phasebuf);
525 stb_writeintervals(ptfile, ptstbnode_dn->STBHZ[i], format);
526 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_dn, 1, i);
527 }
528 }
529 }
530 }
531 if (ptstbnode_up != NULL) {
532 if (ptstbnode_up->STBHZ != NULL) {
533 if (ptstbnode_up->STBHZ[i] != NULL) {
534 if (ptstbnode_up->CK->TYPE == STB_TYPE_PRECHARGE) {
535 fprintf(ptfile, " \"%s\" RISING%s WITHOUT PRECHARGE:\n", namebuf, phasebuf);
536 stb_writeintervals(ptfile, ptstbnode_up->STBHZ[i], format);
537 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_up, 1, i);
538 }
539 else if (ptstbnode_up->CK->TYPE == STB_TYPE_EVAL) {
540 fprintf(ptfile, " \"%s\" RISING%s WITHOUT EVALUATE:\n", namebuf, phasebuf);
541 stb_writeintervals(ptfile, ptstbnode_up->STBHZ[i], format);
542 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_up, 1, i);
543 }
544 }
545 }
546 }
547
548 /* write intervals for the current phase */
549 if (ptstbnode_up != NULL && ptstbnode_dn != NULL) {
550 if (stb_compstbpairlist(ptstbnode_dn->STBTAB[i], ptstbnode_up->STBTAB[i]) == TRUE) {
551 if (ptstbnode_dn->STBTAB[i] != NULL) {
552 fprintf(ptfile, " \"%s\"%s:\n", namebuf, phasebuf);
553 stb_writeintervals(ptfile, ptstbnode_dn->STBTAB[i], format);
554 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_dn, 0, i);
555 }
556 }
557 else {
558 if (ptstbnode_dn->STBTAB[i] != NULL) {
559 fprintf(ptfile, " \"%s\" FALLING%s:\n", namebuf, phasebuf);
560 stb_writeintervals(ptfile, ptstbnode_dn->STBTAB[i], format);
561 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_dn, 0, i);
562 }
563 if (ptstbnode_up->STBTAB[i] != NULL) {
564 fprintf(ptfile, " \"%s\" RISING%s:\n", namebuf, phasebuf);
565 stb_writeintervals(ptfile, ptstbnode_up->STBTAB[i], format);
566 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_up, 0, i);
567 }
568 }
569 }
570 else if (ptstbnode_up != NULL) {
571 if (ptstbnode_up->STBTAB[i] != NULL) {
572 fprintf(ptfile, " \"%s\" RISING%s:\n", namebuf, phasebuf);
573 stb_writeintervals(ptfile, ptstbnode_up->STBTAB[i], format);
574 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_up, 0, i);
575 }
576 }
577 else if (ptstbnode_dn != NULL) {
578 if (ptstbnode_dn->STBTAB[i] != NULL) {
579 fprintf(ptfile, " \"%s\" FALLING%s:\n", namebuf, phasebuf);
580 stb_writeintervals(ptfile, ptstbnode_dn->STBTAB[i], format);
581 stb_writeintervals_split(ptfile, ptstbfig, ptstbnode_dn, 0, i);
582 }
583 }
584 }
585 }
586
587 /*****************************************************************************
588 * fonction stb_writeintervals() *
589 *****************************************************************************/
590
591 static void
592 stb_writeintervals_split(FILE *ptfile, stbfig_list *sb, stbnode *node, int hz, char phase)
593 {
594 stbpair_list *ptstbpair, *pair;
595 stbpair_list *STBTAB[256];
596 stbpair_list *STBHZ[256];
597 int i;
598 stbck *ck;
599 char buf[1024];
600
601 if (node->CK==NULL || node->CK->NEXT==NULL) return;
602
603 for (ck=node->CK; ck!=NULL; ck=ck->NEXT)
604 {
605 if (ck->CKINDEX==phase)
606 {
607 for (i=0; i<node->NBINDEX; i++)
608 {
609 STBHZ[i]=NULL, STBTAB[i]=NULL;
610 }
611 stb_transferstbline (sb, node->EVENT, node , STBTAB, STBHZ, 0, 1, NULL, ck, 1, (node->FLAG & STB_NODE_STABCORRECT)!=0?STB_TRANSFERT_CORRECTION:0) ;
612 pair = stb_globalstbtab (!hz?STBTAB:STBHZ, node->NBINDEX);
613 stb_freestbtabpair(STBHZ, node->NBINDEX);
614 stb_freestbtabpair(STBTAB, node->NBINDEX);
615
616 if (pair!=NULL)
617 {
618 if (ck->CMD==NULL) fprintf(ptfile, "#no cmd:");
619 else fprintf(ptfile, "#cmd %s (%c):", ttv_getsigname(sb->FIG,buf,ck->CMD->ROOT), (ck->CMD->TYPE & TTV_NODE_UP)?'R':'F');
620 for (ptstbpair = pair; ptstbpair; ptstbpair = ptstbpair->NEXT)
621 fprintf(ptfile, " %s-%s", stb_drvtime(ptstbpair->D), stb_drvtime(ptstbpair->U));
622 fprintf(ptfile, "\n");
623 }
624 stb_freestbpair(pair);
625 }
626 }
627 }
628 static void
629 stb_writeintervals(ptfile, ptheadstbpair, format)
630 FILE *ptfile;
631 stbpair_list *ptheadstbpair;
632 int format;
633 {
634 stbpair_list *ptstbpair;
635
636 if (format == STB_SEPARATE_INTERVALS) {
637 for (ptstbpair = ptheadstbpair; ptstbpair; ptstbpair = ptstbpair->NEXT) {
638 fprintf(ptfile, " UNSTABLE %s;\n", stb_drvtime(ptstbpair->D));
639 fprintf(ptfile, " STABLE %s;\n", stb_drvtime(ptstbpair->U));
640 }
641 }
642 else {
643 fprintf(ptfile, " UNSTABLE");
644 for (ptstbpair = ptheadstbpair; ptstbpair; ptstbpair = ptstbpair->NEXT) {
645 fprintf(ptfile, " %s%s", stb_drvtime(ptstbpair->D), ptstbpair->NEXT?" ":"");
646 }
647 fprintf(ptfile, ";\n");
648 fprintf(ptfile, " STABLE ");
649 for (ptstbpair = ptheadstbpair; ptstbpair; ptstbpair = ptstbpair->NEXT) {
650 fprintf(ptfile, " %s%s", stb_drvtime(ptstbpair->U), ptstbpair->NEXT?" ":"");
651 }
652 fprintf(ptfile, ";\n");
653 }
654 }
655
656 /*****************************************************************************
657 * fonction stb_drvsigerr() *
658 *****************************************************************************/
659 void stb_drvsigerr(file,ptstbfig,ptsig)
660 FILE *file ;
661 stbfig_list *ptstbfig;
662 ttvsig_list *ptsig ;
663 {
664 stbdebug_list *debug ;
665 stbdebug_list *deb ;
666 char namebuf[1024], buf[1024];
667
668 debug = stb_debugstberror(ptstbfig,ptsig,(long)0, 0);
669
670 for(deb = debug ; deb ; deb = deb->NEXT) {
671 if (deb->START_CMD_EVENT!=NULL)
672 sprintf(buf, " CMD '%s' (%c)", ttv_getsigname(ptstbfig->FIG,namebuf,deb->START_CMD_EVENT->ROOT), (deb->START_CMD_EVENT->TYPE & TTV_NODE_UP)?'R':'F');
673 else
674 strcpy(buf,"");
675 fprintf(file, "\tERROR FROM '%s'%s:",ttv_getsigname(ptstbfig->FIG,namebuf,deb->SIG1), buf);
676 if (deb->SETUP != STB_NO_TIME) {
677 fprintf(file, " SETUP=%s", stb_drvtime(deb->SETUP));
678 }
679 if (deb->HOLD != STB_NO_TIME) {
680 fprintf(file, " HOLD=%s", stb_drvtime(deb->HOLD));
681 }
682 fprintf(file, "\n");
683 }
684 stb_freestbdebuglist(debug) ;
685 }
686
687 /*****************************************************************************
688 * fonction stb_drvreport() *
689 *****************************************************************************/
690 int stb_getdatalag(ttvfig_list *ttvfig, ttvevent_list *latch, double *time)
691 {
692 stbfig_list *stbfig ;
693 long datamin ;
694 long datamax=0, dmax ;
695 char phase ;
696 stbck *ck;
697 stbnode *node;
698
699 *time=-1;
700 if((((latch->ROOT->TYPE & TTV_SIG_LL) != TTV_SIG_LL) &&
701 ((latch->ROOT->TYPE & TTV_SIG_R) != TTV_SIG_R)))
702 return(0) ;
703
704 if (ttv_testsigflag(latch->ROOT, TTV_SIG_FLAGS_DONTCROSS))
705 return 0;
706
707 if((stbfig = stb_getstbfig(ttvfig)) == NULL)
708 return(0) ;
709
710 stb_geteventphase(stbfig,latch,&phase,NULL,NULL,1,1) ;
711
712 if(phase == STB_NO_INDEX)
713 {
714 *time=-2;
715 return(1) ;
716 }
717
718 node = stb_getstbnode (latch);
719 if (node!=NULL)
720 {
721 for (ck=node->CK; ck!=NULL; ck=ck->NEXT)
722 {
723 if (stb_IsClockCK(node->EVENT, ck)) continue;
724 stb_getstbdelta(stbfig, latch, &datamin, &dmax, ck->CMD);
725 if (dmax>datamax) datamax=dmax;
726 }
727 }
728 *time=(datamax/TTV_UNIT)*1e-12;
729 if(datamax <= 0)
730 {
731 *time=-1;
732 return(0) ;
733 }
734
735 return(1) ;
736 }
737
738 void stb_drvreport(stbfig,file,type,slope,name,setup,hold,ck,lag,node)
739 stbfig_list *stbfig ;
740 FILE *file ;
741 char *type ;
742 char *slope ;
743 char *name ;
744 long setup ;
745 long hold ;
746 stbck *ck;
747 double lag;
748 ttvevent_list *node;
749
750 {
751 char upmin[32];
752 char upmax[32];
753 char dnmin[32];
754 char dnmax[32];
755 char nameclock[1024];
756 char namecmd[1024];
757 char edge ;
758 char *up, *down;
759 int invert;
760
761 if ((setup != STB_NO_TIME) || (hold != STB_NO_TIME)) {
762 fprintf(file, "%s '%s' %s:", type, name, slope);
763 if (setup != STB_NO_TIME) {
764 fprintf(file, " SETUP=%s", stb_drvtime(setup));
765 }
766 if (hold != STB_NO_TIME) {
767 fprintf(file, " HOLD=%s", stb_drvtime(hold));
768 }
769 if (lag!=-3)
770 {
771 if (lag==-2)
772 fprintf(file, " TRANSPARENT=ALWAYS");
773 else if (lag!=-1)
774 fprintf(file, " TRANSPARENT=%s", stb_drvtime(mbk_long_round(lag*TTV_UNIT*1e12)));
775 else
776 fprintf(file, " NOT-TRANSPARENT");
777 }
778
779 fprintf(file, "\n");
780 for(; ck ; ck = ck->NEXT) {
781 if (stb_IsClockCK(node, ck)) continue;
782 if (ck->CMD!=NULL && stbfig!=NULL && !stb_cmd_can_generate_event(stbfig, node, ck->CMD)) continue;
783 if(ck->CKINDEX != STB_NO_INDEX) {
784 if(stb_getclock(stbfig,ck->CKINDEX,nameclock,&edge, ck) == NULL)
785 *nameclock='\0' ;
786 }
787 else *nameclock='\0' ;
788 if(ck->CMD != NULL) {
789 ttv_getsigname(stbfig->FIG,namecmd,ck->CMD->ROOT) ;
790 }
791 else *namecmd='\0' ;
792 if (ck->SUPMIN == STB_NO_TIME) strcpy(upmin, "NO_TIME");
793 else sprintf(upmin, "%s", stb_drvtime(ck->SUPMIN));
794 if (ck->SUPMAX == STB_NO_TIME) strcpy(upmax, "NO_TIME");
795 else sprintf(upmax, "%s", stb_drvtime(ck->SUPMAX));
796 if (ck->SDNMIN == STB_NO_TIME) strcpy(dnmin, "NO_TIME");
797 else sprintf(dnmin, "%s", stb_drvtime(ck->SDNMIN));
798 if (ck->SDNMAX == STB_NO_TIME) strcpy(dnmax, "NO_TIME");
799 else sprintf(dnmax, "%s", stb_drvtime(ck->SDNMAX));
800 fprintf(file, "\tCLOCK: ");
801 if(*nameclock != '\0')
802 {
803 if (STB_OPEN_LATCH_PHASE == 'N')
804 fprintf(file, "%s(%s) ",nameclock,(edge == STB_SLOPE_DN)?"DOWN":"UP");
805 else
806 fprintf(file, "%s(%s) ",nameclock,(edge != STB_SLOPE_DN)?"DOWN":"UP");
807 }
808 up="UP", down="DN";
809 if(*namecmd != '\0')
810 {
811 stb_getgoodclock_and_status(stbfig, ck, ck->CMD, node, &invert);
812
813 if(invert)
814 {
815 up="DN"; down="UP";
816 }
817 fprintf(file, "COMMAND : %s(%s) ",namecmd, (ck->CMD->TYPE & TTV_NODE_UP)==TTV_NODE_UP?"DOWN":"UP");
818 }
819 fprintf(file, "%sMIN=%s, %sMAX=%s, %sMIN=%s, %sMAX=%s\n",up, upmin,up, upmax,down,dnmin,down,dnmax);
820 }
821 }
822 }
823
824 /*****************************************************************************
825 * fonction stb_report() *
826 *****************************************************************************/
827
828 void
829 stb_report(stbfig_list *ptstbfig, char *filename)
830 {
831 FILE *stbrep;
832 ttvsig_list *ptttvsig;
833 stbnode *ptstbnode_up;
834 stbnode *ptstbnode_dn;
835 chain_list *ptchain;
836 char namebuf[1024];
837 double lag;
838
839 stbrep = mbkfopen(filename==NULL?ptstbfig->FIG->INFO->FIGNAME:filename, filename==NULL?"str":NULL, WRITE_TEXT);
840 if (stbrep== NULL) {
841 stb_error(ERR_CANNOT_OPEN, NULL, 0, STB_FATAL);
842 }
843
844 sprintf(namebuf,"Stability report : %s.str\n",filename==NULL?ptstbfig->FIG->INFO->FIGNAME:filename);
845 avt_printExecInfo(stbrep, "#", namebuf, "");
846
847 fprintf(stbrep, "NUMBER OF PHASES: %d\n", (int)ptstbfig->PHASENUMBER);
848 for (ptchain = ptstbfig->CLOCK; ptchain; ptchain = ptchain->NEXT) {
849 ptttvsig = (ttvsig_list *)ptchain->DATA;
850 ptstbnode_up = stb_getstbnode(ptttvsig->NODE);
851 ptstbnode_dn = stb_getstbnode(ptttvsig->NODE+1);
852 fprintf(stbrep, "CLOCK %s :", ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig));
853 if (ptstbnode_up->CK->CKINDEX != STB_NO_INDEX)
854 fprintf(stbrep, " FALLING(%d)", ptstbnode_up->CK->CKINDEX) ;
855 if (ptstbnode_dn->CK->CKINDEX != STB_NO_INDEX)
856 fprintf(stbrep, " RISING(%d)", ptstbnode_dn->CK->CKINDEX) ;
857 fprintf(stbrep, "\n") ;
858 }
859
860 fprintf(stbrep, "STABLE: ");
861 if (ptstbfig->STABILITYFLAG == STB_STABLE) {
862 fprintf(stbrep, "YES\n\n");
863 }
864 else fprintf(stbrep, "NO\n\n");
865
866 lag=-3;
867 for (ptchain = ptstbfig->CONNECTOR; ptchain; ptchain = ptchain->NEXT) {
868 ptttvsig = (ttvsig_list *)ptchain->DATA;
869 if ((ptttvsig->TYPE & TTV_SIG_CO) != TTV_SIG_CO) continue;
870 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
871 ptstbnode_dn = stb_getstbnode(ptttvsig->NODE);
872 stb_drvreport(ptstbfig,stbrep, "OUTPUT", "FALLING", namebuf, ptstbnode_dn->SETUP, ptstbnode_dn->HOLD, NULL, lag, ptttvsig->NODE);
873 ptstbnode_up = stb_getstbnode(ptttvsig->NODE+1);
874 stb_drvreport(ptstbfig,stbrep, "OUTPUT", "RISING", namebuf, ptstbnode_up->SETUP, ptstbnode_up->HOLD, NULL, lag, ptttvsig->NODE+1);
875 if((ptstbnode_up->SETUP <= (long)0) || (ptstbnode_up->HOLD <= (long)0)||
876 (ptstbnode_dn->SETUP <= (long)0) || (ptstbnode_dn->HOLD <= (long)0))
877 stb_drvsigerr(stbrep,ptstbfig,ptttvsig) ;
878 }
879
880 lag=-3;
881 for (ptchain = ptstbfig->MEMORY; ptchain; ptchain = ptchain->NEXT) {
882 ptttvsig = (ttvsig_list *)ptchain->DATA;
883 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
884 ptstbnode_dn = stb_getstbnode(ptttvsig->NODE);
885 stb_getdatalag(ptstbfig->FIG, ptttvsig->NODE, &lag);
886 stb_drvreport(ptstbfig,stbrep, "MEMORY", "FALLING", namebuf, ptstbnode_dn->SETUP, ptstbnode_dn->HOLD, ptstbnode_dn->CK, lag, ptttvsig->NODE);
887 ptstbnode_up = stb_getstbnode(ptttvsig->NODE+1);
888 stb_getdatalag(ptstbfig->FIG, ptttvsig->NODE+1, &lag);
889 stb_drvreport(ptstbfig,stbrep, "MEMORY", "RISING", namebuf, ptstbnode_up->SETUP, ptstbnode_up->HOLD, ptstbnode_up->CK, lag, ptttvsig->NODE+1);
890 if((ptstbnode_up->SETUP <= (long)0) || (ptstbnode_up->HOLD <= (long)0)||
891 (ptstbnode_dn->SETUP <= (long)0) || (ptstbnode_dn->HOLD <= (long)0))
892 stb_drvsigerr(stbrep,ptstbfig,ptttvsig) ;
893 }
894
895 lag=-3;
896 for (ptchain = ptstbfig->COMMAND; ptchain; ptchain = ptchain->NEXT) {
897 ptttvsig = (ttvsig_list *)ptchain->DATA;
898 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
899 ptstbnode_dn = stb_getstbnode(ptttvsig->NODE);
900 stb_drvreport(ptstbfig,stbrep, "COMMAND", "FALLING", namebuf, ptstbnode_dn->SETUP, ptstbnode_dn->HOLD, ptstbnode_dn->CK, lag, ptttvsig->NODE);
901 ptstbnode_up = stb_getstbnode(ptttvsig->NODE+1);
902 stb_drvreport(ptstbfig,stbrep, "COMMAND", "RISING", namebuf, ptstbnode_up->SETUP, ptstbnode_up->HOLD, ptstbnode_up->CK, lag, ptttvsig->NODE+1);
903 if((ptstbnode_up->SETUP <= (long)0) || (ptstbnode_up->HOLD <= (long)0)||
904 (ptstbnode_dn->SETUP <= (long)0) || (ptstbnode_dn->HOLD <= (long)0))
905 stb_drvsigerr(stbrep,ptstbfig,ptttvsig) ;
906 }
907
908 lag=-3;
909 for (ptchain = ptstbfig->PRECHARGE; ptchain; ptchain = ptchain->NEXT) {
910 ptttvsig = (ttvsig_list *)ptchain->DATA;
911 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
912 ptstbnode_dn = stb_getstbnode(ptttvsig->NODE);
913 stb_getdatalag(ptstbfig->FIG, ptttvsig->NODE, &lag);
914 stb_drvreport(ptstbfig,stbrep, "PRECHARGE", "FALLING", namebuf, ptstbnode_dn->SETUP, ptstbnode_dn->HOLD, ptstbnode_dn->CK, lag, ptttvsig->NODE);
915 ptstbnode_up = stb_getstbnode(ptttvsig->NODE+1);
916 stb_getdatalag(ptstbfig->FIG, ptttvsig->NODE+1, &lag);
917 stb_drvreport(ptstbfig,stbrep, "PRECHARGE", "RISING", namebuf, ptstbnode_up->SETUP, ptstbnode_up->HOLD, ptstbnode_up->CK, lag, ptttvsig->NODE+1);
918 if((ptstbnode_up->SETUP <= (long)0) || (ptstbnode_up->HOLD <= (long)0)||
919 (ptstbnode_dn->SETUP <= (long)0) || (ptstbnode_dn->HOLD <= (long)0))
920 stb_drvsigerr(stbrep,ptstbfig,ptttvsig) ;
921 }
922
923 lag=-3;
924 for (ptchain = ptstbfig->BREAK; ptchain; ptchain = ptchain->NEXT) {
925 ptttvsig = (ttvsig_list *)ptchain->DATA;
926 ttv_getsigname(ptstbfig->FIG, namebuf, ptttvsig);
927 ptstbnode_dn = stb_getstbnode(ptttvsig->NODE);
928 stb_drvreport(ptstbfig,stbrep, "BREAK", "FALLING", namebuf, ptstbnode_dn->SETUP, ptstbnode_dn->HOLD, ptstbnode_dn->CK, lag, ptttvsig->NODE);
929 ptstbnode_up = stb_getstbnode(ptttvsig->NODE+1);
930 stb_drvreport(ptstbfig,stbrep, "BREAK", "RISING", namebuf, ptstbnode_up->SETUP, ptstbnode_up->HOLD, ptstbnode_up->CK, lag, ptttvsig->NODE+1);
931 if((ptstbnode_up->SETUP <= (long)0) || (ptstbnode_up->HOLD <= (long)0)||
932 (ptstbnode_dn->SETUP <= (long)0) || (ptstbnode_dn->HOLD <= (long)0))
933 stb_drvsigerr(stbrep,ptstbfig,ptttvsig) ;
934 }
935
936 if (fclose(stbrep)) {
937 stb_error(ERR_CANNOT_CLOSE, NULL, 0, STB_FATAL);
938 }
939 }
940
941 char* stb_drvtime( long time )
942 {
943 static int n=0;
944 static char buffer[4][64];
945
946 n++;
947 if( n==4 )
948 n=0;
949 sprintf( buffer[n], "%.1f", (double)time / TTV_UNIT );
950
951 return buffer[n] ;
952 }