1 //----------------------------------------------------------------
2 // vlog2Def
3 //----------------------------------------------------------------
4 // Convert from verilog netlist to a pre-placement DEF file
5 //----------------------------------------------------------------
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <unistd.h>	/* for getopt() */
11 #include <math.h>	/* For sqrt() and ceil() */
12 
13 #include "hash.h"
14 #include "readverilog.h"
15 #include "readlef.h"
16 
17 int write_output(struct cellrec *, int hasmacros, float aspect, float density,
18 		int units, GATE coresite, char *outname);
19 void helpmessage(FILE *outf);
20 
21 /* Linked list for nets */
22 
23 typedef struct _linkedNet *linkedNetPtr;
24 
25 typedef struct _linkedNet {
26     char *instname;
27     char *pinname;
28     linkedNetPtr next;
29 } linkedNet;
30 
31 /* Hash table of LEF macros */
32 struct hashtable LEFhash;
33 
34 /*--------------------------------------------------------------*/
35 
main(int argc,char * argv[])36 int main (int argc, char *argv[])
37 {
38     int i, result = 0, hasmacros = FALSE;
39     int units = 100;
40     float aspect = 1.0;
41     float density = 1.0;
42     struct cellrec *topcell;
43     GATE coresite = NULL;
44     char *defoutname = NULL;
45 
46     InitializeHashTable(&LEFhash, SMALLHASHSIZE);
47 
48     while ((i = getopt(argc, argv, "hHl:a:d:u:o:")) != EOF) {
49         switch (i) {
50 	    case 'h':
51 	    case 'H':
52 		helpmessage(stdout);
53 		return 0;
54 	    case 'l':
55 		result = LefRead(optarg);	/* Can be called multiple times */
56 		if (result == 0) {
57 		    helpmessage(stderr);
58 		    return 1;
59 		}
60 		break;
61 	    case 'o':
62 		defoutname = strdup(optarg);
63 		break;
64 	    case 'a':
65 		if (sscanf(optarg, "%f", &aspect) != 1) {
66 		    fprintf(stderr, "Could not read aspect value from \"-a %s\"\n",
67 				optarg);
68 		    helpmessage(stderr);
69 		    return 1;
70 		}
71 		break;
72 	    case 'd':
73 		if (sscanf(optarg, "%f", &density) != 1) {
74 		    fprintf(stderr, "Could not read density value from \"-d %s\"\n",
75 				optarg);
76 		    helpmessage(stderr);
77 		    return 1;
78 		}
79 		if (density < 0.0 || density > 1.0) {
80 		    fprintf(stderr, "Illegal density value \"-d %s\"\n", optarg);
81 		    helpmessage(stderr);
82 		    return 1;
83 		}
84 		break;
85 	    case 'u':
86 		if (sscanf(optarg, "%d", &units) != 1) {
87 		    fprintf(stderr, "Could not read units value from \"-u %s\"\n",
88 				optarg);
89 		    helpmessage(stderr);
90 		    return 1;
91 		}
92 		break;
93 	    default:
94 		fprintf(stderr, "Bad option switch \"%c\"\n", (char)i);
95 		helpmessage(stderr);
96 		return 1;
97    	}
98     }
99 
100     if (optind >= argc) {
101 	fprintf(stderr, "Couldn't find a filename as input\n");
102 	helpmessage(stderr);
103 	return 1;
104     }
105 
106     /* If any LEF files were read, hash the GateInfo list */
107     if (GateInfo != NULL) {
108 	GATE gate;
109 	for (gate = GateInfo; gate; gate = gate->next) {
110 	    HashPtrInstall(gate->gatename, gate, &LEFhash);
111 	    if (!strncmp(gate->gatename, "site_", 5))
112 		if (gate->gateclass == MACRO_CLASS_CORE)
113 		    coresite = gate;
114 	}
115 	hasmacros = TRUE;
116     }
117 
118     topcell = ReadVerilog(argv[optind]);
119     result = write_output(topcell, hasmacros, aspect, density,
120 		units, coresite, defoutname);
121     return result;
122 }
123 
124 /*--------------------------------------------------------------*/
125 /* output_nets:							*/
126 /* Recursion callback function for each item in Nodehash	*/
127 /*--------------------------------------------------------------*/
128 
output_nets(struct hashlist * p,void * cptr)129 struct nlist *output_nets(struct hashlist *p, void *cptr)
130 {
131     struct netrec *net;
132     char *sptr = NULL;
133     FILE *outf = (FILE *)cptr;
134     linkedNetPtr nlink, nsrch;
135 
136     nlink = (linkedNetPtr)(p->ptr);
137 
138     // Verilog backslash-escaped names are decidedly not SPICE
139     // compatible, so replace the mandatory trailing space character
140     // with another backslash.
141 
142     if (*p->name == '\\') {
143 	sptr = strchr(p->name, ' ');
144 	if (sptr != NULL) *sptr = '\\';
145     }
146 
147     fprintf(outf, "- %s\n", p->name);
148 
149     for (nsrch = nlink; nsrch; nsrch = nsrch->next) {
150 	fprintf(outf, "  ( %s %s )", nsrch->instname, nsrch->pinname);
151 	if (nsrch->next == NULL)
152 	    fprintf(outf, " ;");
153 	fprintf(outf, "\n");
154     }
155 
156     if (sptr != NULL) *sptr = ' ';
157     return NULL;
158 }
159 
160 /*--------------------------------------------------------------*/
161 /* port_output_specs						*/
162 /*								*/
163 /* Write information to an entry in the DEF PINS section	*/
164 /*--------------------------------------------------------------*/
165 
port_output_specs(FILE * outfptr,struct portrec * port,LefList * routelayer,int units)166 void port_output_specs(FILE *outfptr, struct portrec *port,
167 	    LefList *routelayer, int units)
168 {
169     char *layername;
170     int x, y, ll, ur, w, hw;
171     LefList pinlayer;
172 
173     /* This string array much match the port definitions in readverilog.h */
174     static char *portdirs[] = {"", "INPUT", "OUTPUT", "INOUT"};
175 
176     x = y = 0;	    /* To be done (need constraints?) */
177 
178     /* To be done:  Layer depends on position and orientation */
179     pinlayer = routelayer[2];
180 
181     layername = pinlayer->lefName;
182     w = (int)(0.5 + pinlayer->info.route.width * (float)units);
183     hw = w >> 1;
184     ll = -hw;
185     ur = w - hw;
186 
187     if (port->direction > PORT_NONE)
188 	fprintf(outfptr, "\n  + DIRECTION %s", portdirs[port->direction]);
189     fprintf(outfptr, "\n  + LAYER %s ( %d %d ) ( %d %d )", layername,
190 		ll, ll, ur, ur);
191     fprintf(outfptr, "\n  + PLACED ( %d %d ) N ;\n", x, y);
192 }
193 
194 /*--------------------------------------------------------------*/
195 /* write_output							*/
196 /*								*/
197 /*         ARGS: 						*/
198 /*      RETURNS: 1 to OS					*/
199 /* SIDE EFFECTS: 						*/
200 /*--------------------------------------------------------------*/
201 
write_output(struct cellrec * topcell,int hasmacros,float aspect,float density,int units,GATE coresite,char * outname)202 int write_output(struct cellrec *topcell, int hasmacros, float aspect,
203 	float density, int units, GATE coresite, char *outname)
204 {
205     FILE *outfptr = stdout;
206     int ncomp, npin, nnet, start, end, i, result = 0;
207     int totalwidth, totalheight, rowwidth, rowheight, numrows;
208     int sitewidth, siteheight, numsites;
209     char portnet[512];
210 
211     struct netrec *net;
212     struct portrec *port;
213     struct instance *inst;
214 
215     struct hashtable Nodehash;
216 
217     /* Static string "PIN" for ports */
218     static char pinname[] = "PIN";
219 
220     linkedNetPtr nlink, nsrch;
221     LefList slef;
222     LefList routelayer[3];
223 
224     if (topcell == NULL) {
225 	fprintf(stderr, "No top-level cell data;  cannot continue.\n");
226 	return 1;
227     }
228 
229     /* Open the output file (unless name is NULL, in which case use stdout) */
230     if (outname != NULL) {
231 	outfptr = fopen(outname, "w");
232 	if (outfptr == NULL) {
233 	    fprintf(stderr, "Error:  Cannot open file %s for writing.\n", outname);
234 	    return 1;
235 	}
236     }
237 
238     /* Hash the nets */
239 
240     InitializeHashTable(&Nodehash, LARGEHASHSIZE);
241     nnet = 0;
242     for (port = topcell->portlist; port; port = port->next) {
243 	if ((net = BusHashLookup(port->name, &topcell->nets)) != NULL) {
244 	    start = net->start;
245 	    end = net->end;
246 	}
247 	else start = end = -1;
248 
249 	if (start > end) {
250 	    int tmp;
251 	    tmp = start;
252 	    start = end;
253 	    end = tmp;
254 	}
255 	for (i = start; i <= end; i++) {
256 	    nlink = (linkedNetPtr)malloc(sizeof(linkedNet));
257 	    nlink->instname = pinname;
258 
259 	    if (start == -1)
260 		nlink->pinname = port->name;
261 	    else {
262 		sprintf(portnet, "%s[%d]", port->name, i);
263 		nlink->pinname = strdup(portnet);
264 	    }
265 	    nlink->next = NULL;
266 	    if ((nsrch = HashLookup(nlink->pinname, &Nodehash)) != NULL) {
267 		while (nsrch->next) nsrch = nsrch->next;
268 		nsrch->next = nlink;
269 	    }
270 	    else {
271 		HashPtrInstall(nlink->pinname, nlink, &Nodehash);
272 		nnet++;
273 	    }
274 	}
275     }
276     totalwidth = 0;
277     for (inst = topcell->instlist; inst; inst = inst->next) {
278 	int j;
279 	GATE gate;
280 	gate = HashLookup(inst->cellname, &LEFhash);
281 
282 	for (port = inst->portlist; port; port = port->next) {
283 
284 	    char *netsptr;
285 
286 	    /* Code for handling vectors mostly copied from vlog2Cel.c. */
287 	    /* Note, however, that this program is given a synthesized	*/
288 	    /* netlist and there are no instance arrays.  If that is	*/
289 	    /* ever not true, then this code needs to be expanded to	*/
290 	    /* include handling of instance arrays.			*/
291 
292 	    /* Determine and handle the four cases of a port and a net	*/
293 	    /* being an array or a single signal.			*/
294 
295 	    int is_port_bus = FALSE;
296 	    int is_net_bus = FALSE;
297 
298             /* Verilog backslash-escaped names have spaces that     */
299             /* break pretty much every other format, so replace     */
300             /* the space with the (much more sensible) second       */
301             /* backslash.  This can be detected and changed         */
302             /* back by programs converting the syntax back into     */
303             /* verilog.                                             */
304 
305 	    netsptr = port->net;
306 	    if (*port->net == '\\') {
307 	        netsptr = strchr(port->net, ' ');
308 	        if (netsptr != NULL) *netsptr = '\\';
309 	    }
310 
311             /* Find the port name in the gate pin list */
312             for (j = 0; j < gate->nodes; j++) {
313                 if (!strcmp(port->name, gate->node[j])) break;
314             }
315             if (j == gate->nodes) {
316                 /* Is this a bus? */
317                 for (j = 0; j < gate->nodes; j++) {
318                     char *delim = strrchr(gate->node[j], '[');
319                     if (delim != NULL) {
320                         *delim = '\0';
321                         if (!strcmp(port->name, gate->node[j]))
322                             is_port_bus = TRUE;
323                         *delim = '[';
324                         if (is_port_bus) break;
325                     }
326                 }
327             }
328 
329             /* Check if the net itself is an array */
330             net = HashLookup(port->net, &topcell->nets);
331             if (net && (net->start != -1)) {
332                 char *sptr, *dptr, *cptr;
333 
334                 is_net_bus = TRUE;
335 
336                 /* However, if net name is a 1-bit bus subnet, then */
337                 /* it is not considered to be a bus.  Note that     */
338                 /* brackets inside a verilog backslash-escaped name */
339                 /* are not array indicators.                        */
340 
341                 dptr = strchr(netsptr, '[');
342                 if (dptr) {
343                     cptr = strchr(dptr + 1, ':');
344                     if (!cptr) {
345                         is_net_bus = FALSE;
346                     }
347                 }
348             }
349 	    else if (!net && port->net[0] == '{') {
350 		/* net is a signal bundle */
351 		is_net_bus = TRUE;
352 	    }
353 
354             if (j == gate->nodes) {
355                 fprintf(stderr, "Error:  Pin \"%s\" not found in LEF macro \"%s\"!\n",
356                         port->name, gate->gatename);
357             }
358             else if (is_net_bus == FALSE) {
359 
360 		nlink = (linkedNetPtr)malloc(sizeof(linkedNet));
361 		nlink->instname = inst->instname;
362 		nlink->pinname = port->name;
363 		nlink->next = NULL;
364 
365 		if ((nsrch = HashLookup(port->net, &Nodehash)) != NULL) {
366 		    while (nsrch->next) nsrch = nsrch->next;
367 		    nsrch->next = nlink;
368 		}
369 		else {
370 		    HashPtrInstall(port->net, nlink, &Nodehash);
371 		    nnet++;
372 		}
373 	    }
374             else {  // is_net_bus == TRUE
375 
376 		char *apin, *anet, *dptr, *cptr;
377 		int a, pidx, armax, armin;
378 
379 		armax = armin = 0;
380 		for (j = 0; j < gate->nodes; j++) {
381 		    char *delim, *sptr;
382 
383 		    sptr = gate->node[j];
384 		    if (*sptr == '\\') sptr = strchr(sptr, ' ');
385 		    if (sptr == NULL) sptr = gate->node[j];
386 		    delim = strrchr(sptr, '[');
387 		    if (delim != NULL) {
388 			*delim = '\0';
389 			if (!strcmp(port->name, gate->node[j])) {
390 			    if (sscanf(delim + 1, "%d", &pidx) == 1) {
391 				if (pidx > armax) armax = pidx;
392 				if (pidx < armin) armin = pidx;
393 			    }
394 			}
395 			*delim = '[';
396 		    }
397 		}
398 
399 		/* To do:  Need to check if array is high-to-low or low-to-high */
400 		/* Presently assuming arrays are always defined high-to-low	*/
401 
402 		apin = (char *)malloc(strlen(port->name) + 15);
403 		for (a = armax; a >= armin; a--) {
404 		    if (is_port_bus)
405 			sprintf(apin, "%s[%d]", port->name, a);
406 		    else
407 			sprintf(apin, "%s", port->name);
408 
409 		    /* If net is not delimited by {...} then it is also	*/
410 		    /* an array.  Otherwise, find the nth element in	*/
411 		    /* the brace-enclosed set.				*/
412 
413 		    /* To do: if any component of the array is a vector	*/
414 		    /* then we need to count bits in that vector.	*/
415 
416 		    if (*port->net == '{') {
417 			int aidx;
418 			char *sptr, ssave;
419 			char *pptr = port->net + 1;
420 			for (aidx = 0; aidx < (armax - a); aidx++) {
421 			    sptr = pptr;
422 			    while (*sptr != ',' && *sptr != '}') sptr++;
423 			    pptr = sptr + 1;
424 			}
425 			sptr = pptr;
426 			if (*sptr != '\0') {
427 			    while (*sptr != ',' && *sptr != '}') sptr++;
428 			    ssave = *sptr;
429 			    *sptr = '\0';
430 			    anet = (char *)malloc(strlen(pptr) + 1);
431 			    sprintf(anet, "%s", pptr);
432 			    *sptr = ssave;
433 			}
434 			else {
435 			    anet = NULL;	/* Must handle this error! */
436 			}
437 		    }
438 		    else if (((dptr = strrchr(netsptr, '[')) != NULL) &&
439 				((cptr = strrchr(netsptr, ':')) != NULL)) {
440 			int fhigh, flow, fidx;
441 			sscanf(dptr + 1, "%d", &fhigh);
442 			sscanf(cptr + 1, "%d", &flow);
443 			if (fhigh > flow) fidx = fhigh - (armax - a);
444 			else fidx = flow + (armax - a);
445 			anet = (char *)malloc(strlen(port->net) + 15);
446 			*dptr = '\0';
447 			sprintf(anet, "%s[%d]", port->net, fidx);
448 			*dptr = '[';
449 		    }
450 		    else {
451 			anet = (char *)malloc(strlen(port->net) + 15);
452 			sprintf(anet, "%s[%d]", port->net, a);
453 		    }
454 
455 		    /* Find the corresponding port bit */
456 		    for (j = 0; j < gate->nodes; j++) {
457 			if (anet == NULL) break;
458 			if (!strcmp(apin, gate->node[j])) {
459 
460 			    nlink = (linkedNetPtr)malloc(sizeof(linkedNet));
461 			    nlink->instname = inst->instname;
462 			    nlink->pinname = gate->node[j];
463 			    nlink->next = NULL;
464 
465 			    if ((nsrch = HashLookup(anet, &Nodehash)) != NULL) {
466 				while (nsrch->next) nsrch = nsrch->next;
467 				nsrch->next = nlink;
468 			    }
469 			    else {
470 				HashPtrInstall(anet, nlink, &Nodehash);
471 				nnet++;
472 			    }
473 			    break;
474 			}
475 		    }
476 		    free(anet);
477 		    if (j == gate->nodes) {
478 			fprintf(stderr, "Error:  Failed to find port %s in cell %s"
479 				    " port list!\n", port->name, inst->cellname);
480 		    }
481 		}
482 		free(apin);
483 	    }
484 	}
485 
486 	if (hasmacros) {
487 	    if (gate) {
488 		/* Make sure this is a core cell */
489 		if (gate->gateclass == MACRO_CLASS_CORE) {
490 		    totalwidth += (int)(gate->width * (float)units);
491 		    rowheight = (int)(gate->height * (float)units);
492 		}
493 		/* To do:  Handle non-core cell records */
494 		/* (specifically PAD and BLOCK).	*/
495 	    }
496 	}
497     }
498 
499     /* For pin placement, find the 2nd and 3rd route layer LEF names.	*/
500     /* NOTE:  This only ensures that the output is valid LEF;  it does	*/
501     /* not do anything about applying pin constraints.			*/
502 
503     for (i = 0; i < 3; i++)
504 	routelayer[i] = (LefList)NULL;
505 
506     for (slef = LefInfo; slef; slef = slef->next)
507         if (slef->lefClass == CLASS_ROUTE)
508 	    if ((slef->type < 3) && (slef->type >= 0))
509 		routelayer[slef->type] = slef;
510 
511     /* Write output DEF header */
512     fprintf(outfptr, "VERSION 5.6 ;\n");
513     /* fprintf(outfptr, "NAMESCASESENSITIVE ON  ;\n"); */
514     fprintf(outfptr, "DIVIDERCHAR \"/\" ;\n");
515     fprintf(outfptr, "BUSBITCHARS \"[]\" ;\n");
516     fprintf(outfptr, "DESIGN %s ;\n", topcell->name);
517     fprintf(outfptr, "UNITS DISTANCE MICRONS %d ;\n", units);
518     fprintf(outfptr, "\n");
519 
520     /* Calculate pre-placement die area, rows, and tracks, and output the same,	*/
521     /* depending on what has been read in from LEF files.			*/
522 
523     if (hasmacros) {
524 	/* NOTE:  Use a prorated density that is slightly lower than the target	*/
525 	/* or else the placement can fail due to fewer sites available then	*/
526 	/* cell area to place, after accounting for density.			*/
527 
528 	int efftotalwidth = (int)ceilf((float)totalwidth / (density * 0.95));
529 
530 	numrows = (int)ceilf(sqrtf(efftotalwidth / (aspect * rowheight)));
531 	rowwidth = (int)ceilf(efftotalwidth / numrows);
532 	totalheight = (int)ceilf(rowheight * numrows);
533 	sitewidth = (int)ceilf(coresite->width * units);
534 	siteheight = (int)ceilf(coresite->height * units);
535 
536 	/* Diagnostic */
537 	fprintf(stdout, "Diagnostic:\n");
538 	fprintf(stdout, "Total width of all cells = %gum\n", (float)totalwidth / (float)units);
539 	fprintf(stdout, "Effective total width after density planning = %gum\n", (float)efftotalwidth / (float)units);
540 	fprintf(stdout, "Site size = (%gum, %gum)\n", (float)sitewidth / (float)units, siteheight / (float)units);
541 	fprintf(stdout, "Row height = %gum\n", (float)rowheight / (float)units);
542 	fprintf(stdout, "Row width = %gum\n", (float)rowwidth / (float)units);
543 	fprintf(stdout, "Total height = %gum\n", (float)totalheight / (float)units);
544 
545 	/* To do: compute additional area for pins */
546 
547 	fprintf(outfptr, "DIEAREA ( 0 0 ) ( %d %d ) ;\n", rowwidth, totalheight);
548 	fprintf(outfptr, "\n");
549 
550         /* Compute site placement and generate ROW statements */
551 
552 	numsites = (int)ceilf((float)rowwidth / (float)sitewidth);
553 	for (i = 0; i < numrows; i++) {
554 	    fprintf(outfptr, "ROW ROW_%d %s 0 %d %c DO %d BY 1 STEP %d 0 ;\n",
555 			i + 1, coresite->gatename + 5, i * siteheight,
556 			((i % 2) == 0) ? 'N' : 'S', numsites, sitewidth);
557 	}
558 	fprintf(outfptr, "\n");
559     }
560 
561     /* Write components in the order of the input file */
562 
563     ncomp = 0;
564     for (inst = topcell->instlist; inst; inst = inst->next) {
565 	ncomp++;
566         if (inst->arraystart != -1) {
567 	    int arrayw = inst->arraystart - inst->arrayend;
568 	    ncomp += (arrayw < 0) ? -arrayw : arrayw;
569 	}
570     }
571     fprintf(outfptr, "COMPONENTS %d ;\n", ncomp);
572 
573     for (inst = topcell->instlist; inst; inst = inst->next) {
574 	if (inst->arraystart != -1) {
575 	    int ahigh, alow, j;
576 	    if (inst->arraystart > inst->arrayend) {
577 		ahigh = inst->arraystart;
578 		alow = inst->arrayend;
579 	    }
580 	    else {
581 		ahigh = inst->arrayend;
582 		alow = inst->arraystart;
583 	    }
584 	    for (j = ahigh; j >= alow; j--) {
585 		fprintf(outfptr, "- %s[%d] %s ;\n", inst->instname, j, inst->cellname);
586 	    }
587 	}
588 	else
589 	    fprintf(outfptr, "- %s %s ;\n", inst->instname, inst->cellname);
590     }
591     fprintf(outfptr, "END COMPONENTS\n\n");
592 
593     npin = 0;
594     for (port = topcell->portlist; port; port = port->next) {
595 	if ((net = BusHashLookup(port->name, &topcell->nets)) != NULL) {
596 	    int btot = net->start - net->end;
597 	    if (btot < 0) btot = -btot;
598 	    npin += btot + 1;
599 	}
600 	else
601 	    npin++;
602     }
603     fprintf(outfptr, "PINS %d ;\n", npin);
604 
605     for (port = topcell->portlist; port; port = port->next) {
606 	if ((net = BusHashLookup(port->name, &topcell->nets)) != NULL) {
607 	    if (net->start == -1) {
608 		fprintf(outfptr, "- %s + NET %s", port->name, port->name);
609 		port_output_specs(outfptr, port, routelayer, units);
610 	    }
611 	    else if (net->start > net->end) {
612 		for (i = net->start; i >= net->end; i--) {
613 		    fprintf(outfptr, "- %s[%d] + NET %s[%d]", port->name, i,
614 				port->name, i);
615 		    port_output_specs(outfptr, port, routelayer, units);
616 		}
617 	    }
618 	    else {
619 		for (i = net->start; i <= net->end; i++) {
620 		    fprintf(outfptr, "- %s[%d] + NET %s[%d]", port->name, i,
621 				port->name, i);
622 		    port_output_specs(outfptr, port, routelayer, units);
623 		}
624 	    }
625 	}
626 	else {
627 	    fprintf(outfptr, "- %s + NET %s", port->name, port->name);
628 	    port_output_specs(outfptr, port, routelayer, units);
629 	}
630     }
631 
632     fprintf(outfptr, "END PINS\n\n");
633 
634     fprintf(outfptr, "NETS %d ;\n", nnet);
635     RecurseHashTablePointer(&Nodehash, output_nets, outfptr);
636     fprintf(outfptr, "END NETS\n\n");
637 
638     /* End the design */
639     fprintf(outfptr, "END DESIGN\n");
640 
641     if (outname != NULL) fclose(outfptr);
642 
643     fflush(stdout);
644     return result;
645 
646 } /* write_output */
647 
648 /*--------------------------------------------------------------*/
649 /* C helpmessage - tell user how to use the program		*/
650 /*								*/
651 /*         ARGS: 						*/
652 /*      RETURNS: 1 to OS					*/
653 /* SIDE EFFECTS: 						*/
654 /*--------------------------------------------------------------*/
655 
helpmessage(FILE * outf)656 void helpmessage(FILE *outf)
657 {
658     fprintf(outf,"vlog2Def <netlist>\n");
659     fprintf(outf,"\n");
660     fprintf(outf,"vlog2Def converts a verilog netlist to a pre-placement DEF file.\n");
661     fprintf(outf,"\n");
662     fprintf(outf,"options:\n");
663     fprintf(outf,"\n");
664     fprintf(outf,"   -h          Print this message\n");
665     fprintf(outf,"   -o <path>   Set output filename (otherwise output is on stdout).\n");
666     fprintf(outf,"   -l <path>   Read LEF file from <path> (may be called multiple"
667 			" times)\n");
668     fprintf(outf,"   -a <value>	 Set aspect ratio to <value> (default 1.0)\n");
669     fprintf(outf,"   -d <value>	 Set density to <value> (default 1.0)\n");
670     fprintf(outf,"   -u <value>  Set units-per-micron to <value) (default 100)\n");
671 
672 } /* helpmessage() */
673 
674