/* * ext2sim.c -- * * Program to flatten hierarchical .ext files and produce * a .sim file, suitable for use as input to simulators * such as esim and crystal. * * Flattens the tree rooted at file.ext, reading in additional .ext * files as specified by "use" lines in file.ext. The output is left * in file.sim, unless '-o esSimFile' is specified, in which case the * output is left in 'esSimFile'. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[] = "$Header: /ufs/repository/magic/ext2sim/ext2sim-6.4.5/ext2sim.c,v 1.1.1.1 2000/03/29 18:34:58 rajit Exp $"; #endif #include #include #include #include "magic.h" #include "paths.h" #include "geometry.h" #include "hash.h" #include "utils.h" #include "pathvisit.h" #include "extflat.h" #include "runstats.h" /* Forward declarations */ int mainArgs(); int capVisit(), fetVisit(), nodeVisit(), resistVisit(); /* Options specific to ext2sim */ bool esFetNodesOnly = FALSE; bool esNoAlias = FALSE; bool esNoAttrs = FALSE; bool esNoLabel = FALSE; char esDefaultOut[FNSIZE], esDefaultAlias[FNSIZE], esDefaultLabel[FNSIZE]; char *esOutName = esDefaultOut, *esAliasName = esDefaultAlias; char *esLabelName = esDefaultLabel; FILE *esSimF = NULL; FILE *esAliasF = NULL; FILE *esLabF = NULL; /* * ---------------------------------------------------------------------------- * * main -- * * Top level of ext2sim. * * ---------------------------------------------------------------------------- */ main(argc, argv) char *argv[]; { int flatFlags; char *inName; FILE *f; /* Process command line arguments */ EFInit(); inName = EFArgs(argc, argv, mainArgs, (ClientData) NULL); if (inName == NULL) exit (1); /* * Initializations specific to this program. * Make output, alias, and label names be of the form * inName.suffix if they weren't explicitly specified, * where suffix is .sim, .al, or .nodes. */ if (esOutName == esDefaultOut) (void) sprintf(esDefaultOut, "%s.sim", inName); if (esAliasName == esDefaultAlias) (void) sprintf(esDefaultAlias, "%s.al", inName); if (esLabelName == esDefaultLabel) (void) sprintf(esDefaultLabel, "%s.nodes", inName); if ((esSimF = fopen(esOutName, "w")) == NULL) { perror(esOutName); exit (1); } if (!esNoAlias && (esAliasF = fopen(esAliasName, "w")) == NULL) { perror(esAliasName); exit (1); } if (!esNoLabel && (esLabF = fopen(esLabelName, "w")) == NULL) { perror(esLabelName); exit (1); } /* Read the hierarchical description of the input circuit */ EFReadFile(inName); (void) fprintf(esSimF, "| units: %d tech: %s\n", EFScale, EFTech); /* Convert the hierarchical description to a flat one */ flatFlags = EF_FLATNODES; if (EFCapThreshold < INFINITE_THRESHOLD) flatFlags |= EF_FLATCAPS; if (EFResistThreshold < INFINITE_THRESHOLD) flatFlags |= EF_FLATRESISTS; EFFlatBuild(inName, flatFlags); EFVisitFets(fetVisit, (ClientData) NULL); if (flatFlags & EF_FLATCAPS) EFVisitCaps(capVisit, (ClientData) NULL); EFVisitResists(resistVisit, (ClientData) NULL); EFVisitNodes(nodeVisit, (ClientData) NULL); #ifdef free_all_mem EFFlatDone(); EFDone(); #endif printf("Memory used: %s\n", RunStats(RS_MEM, NULL, NULL)); exit (0); } /* * ---------------------------------------------------------------------------- * * mainArgs -- * * Process those arguments that are specific to ext2sim. * Assumes that *pargv[0][0] is '-', indicating a flag * argument. * * Results: * None. * * Side effects: * After processing an argument, updates *pargc and *pargv * to point to after the argument. * * May initialize various global variables based on the * arguments given to us. * * Exits in the event of an improper argument. * * ---------------------------------------------------------------------------- */ Void mainArgs(pargc, pargv) int *pargc; char ***pargv; { char **argv = *pargv, *cp; int argc = *pargc; switch (argv[0][1]) { case 'A': esNoAlias = TRUE; break; case 'B': esNoAttrs = TRUE; break; case 'F': esFetNodesOnly = TRUE; break; case 'L': esNoLabel = TRUE; break; case 'a': if ((esAliasName = ArgStr(&argc, &argv, "filename")) == NULL) goto usage; break; case 'l': if ((esLabelName = ArgStr(&argc, &argv, "filename")) == NULL) goto usage; break; case 'o': if ((esOutName = ArgStr(&argc, &argv, "filename")) == NULL) goto usage; break; default: (void) fprintf(stderr, "Unrecognized flag: %s\n", argv[0]); goto usage; } *pargv = argv; *pargc = argc; return; usage: (void) fprintf(stderr, "\ Usage: ext2sim [-a aliasfile] [-A] [-B] [-l labelfile] [-L]\n\ [-o simfile] file\n\ or else see options to extcheck(1)\n"); exit (1); } #define NDiffResClass 0 #define PDiffResClass 1 typedef struct { HierName *lastPrefix; unsigned short PDone:1,NDone:1 ; } fetClient ; fetClient *mkFetClient() { register fetClient *fc; fc = ( fetClient *) mallocMagic(sizeof(fetClient)); fc->PDone = fc->NDone = 0; fc->lastPrefix = ( HierName * ) NULL ; return fc ; } short NDiffDone(fc) fetClient *fc; { return fc->NDone; } short PDiffDone(fc) fetClient *fc; { return fc->PDone; } /* * ---------------------------------------------------------------------------- * * fetVisit -- * * Procedure to output a single fet to the .sim file. * Called by EFVisitFets(). * * Results: * Returns 0 always. * * Side effects: * Writes to the file esSimF. * * Format of a .sim fet line: * * type gate source drain l w x y g= s= d= * * where * type is a name identifying this type of transistor * gate, source, and drain are the nodes to which these three * terminals connect * l, w are the length and width of the channel * x, y are the x, y coordinates of a point within the channel. * g=, s=, d= are the (optional) attributes; if present, each * is followed by a comma-separated list of attributes. * * ---------------------------------------------------------------------------- */ int fetVisit(fet, hierName, trans, l, w) Fet *fet; /* Fet being output */ HierName *hierName; /* Hierarchical path down to this fet */ Transform *trans; /* Coordinate transform for output */ int l, w; { FetTerm *gate, *source, *drain ; EFNode *subsNode ; int scale; Rect r; /* If no terminals, can't do much of anything */ if (fet->fet_nterm < 2) return 0; /* If only two terminals, connect the source to the drain */ gate = &fet->fet_terms[0]; source = drain = &fet->fet_terms[1]; if (fet->fet_nterm >= 3) drain = &fet->fet_terms[2]; subsNode = fet->fet_subsnode; /* Kludge for .sim: transistor types can only be one character */ (void) fprintf(esSimF, "%c", EFFetTypes[fet->fet_type][0]); /* Output gate, source, and drain node names */ fetOutNode(hierName, gate->fterm_node->efnode_name->efnn_hier, esSimF); fetOutNode(hierName, source->fterm_node->efnode_name->efnn_hier, esSimF); fetOutNode(hierName, drain->fterm_node->efnode_name->efnn_hier, esSimF); /* * Scale L and W appropriately by the same amount as distance * values in the transform. The transform will have a scale * different from 1 only in the case when the scale factors of * some of the .ext files differed, making it necessary to scale * all dimensions explicitly instead of having a single scale * factor at the beginning of the .sim file. */ GeoTransRect(trans, &fet->fet_rect, &r); scale = GeoScale(trans); (void) fprintf(esSimF, " %d %d %d %d", l*scale, w*scale, r.r_xbot, r.r_ybot); /* Attributes, if present and areas and perimeters for gate,source The substrate is output as the last gate atribute */ if (!esNoAttrs) { char type = EFFetTypes[fet->fet_type][0]; (void) fprintf(esSimF, " g="); if (gate->fterm_attrs) (void) fprintf(esSimF, "%s,", gate->fterm_attrs); fetOutSubs(hierName, subsNode->efnode_name->efnn_hier,esSimF); (void) fprintf(esSimF, " s="); if (source->fterm_attrs) (void) fprintf(esSimF, "%s,", source->fterm_attrs); processNode(source,hierName,type,'s'); (void) fprintf(esSimF, " d="); if (drain->fterm_attrs) (void) fprintf(esSimF, "%s,", drain->fterm_attrs); processNode(drain,hierName,type,'d'); } (void) fprintf(esSimF, "\n"); return 0; } Void processNode(node, hierName, type, srcDrn ) FetTerm *node; HierName *hierName; char type, srcDrn; { fetClient *fc ; /* init the structure if needed */ if ( node->fterm_node->efnode_client == (ClientData) NULL ) node->fterm_node->efnode_client = (ClientData) mkFetClient(); fc = (fetClient *)node->fterm_node->efnode_client; if ( fc->lastPrefix != hierName ) { fc->lastPrefix = hierName ; fc->PDone = fc->NDone = 0; } if ( type == 'n' && !fc->NDone ) { fprintf(esSimF, "A_%d,P_%d ", node->fterm_node->efnode_pa[NDiffResClass].pa_area, node->fterm_node->efnode_pa[NDiffResClass].pa_perim); fc->NDone = 1; } else if ( type == 'p' && !fc->PDone ) { fprintf(esSimF, "A_%d,P_%d ", node->fterm_node->efnode_pa[PDiffResClass].pa_area, node->fterm_node->efnode_pa[PDiffResClass].pa_perim); fc->PDone = 1; } else fprintf(esSimF,"A_0,P_0 "); } /* * ---------------------------------------------------------------------------- * * fetOutNode -- * * Output the name of the node whose hierarchical prefix down to this * point is 'prefix' and whose name from the end of suffix down to the * leaves is 'suffix', just as in the arguments to EFHNConcat(). * * Sets the efnode_client field of the node found in the global name * table to esFetNodesOnly. * * Results: * None. * * Side effects: * Writes to the file 'outf'. * Sets the efnode_client field as described above. * * ---------------------------------------------------------------------------- */ Void fetOutNode(prefix, suffix, outf) HierName *prefix; HierName *suffix; FILE *outf; { HashEntry *he; EFNodeName *nn; /* char pre[100],suf[100]; strcpy(pre , EFHNToStr(prefix)); strcpy(suf , EFHNToStr(suffix)); fprintf(stderr,"Called outnode w/ %s %s\n", pre, suf); */ he = EFHNConcatLook(prefix, suffix, "output"); if (he == NULL) { (void) fprintf(outf, " GND"); return; } /* Canonical name */ nn = (EFNodeName *) HashGetValue(he); (void) putc(' ', outf); EFHNOut(nn->efnn_node->efnode_name->efnn_hier, outf); nn->efnn_node->efnode_client = (ClientData) esFetNodesOnly; } /* A total kludge but it works */ Void fetOutSubs(prefix, suffix, outf) HierName *prefix; HierName *suffix; FILE *outf; { HashEntry *he; EFNodeName *nn; char *name, *suf ; suf = EFHNToStr(suffix); fprintf(outf, "S_"); if ( strcmp(suf, "Vdd!") == 0 || strcmp(suf, "Gnd!")==0 ) fprintf(outf, "%s", suf); else { he = EFHNConcatLook(prefix, suffix, "substrate"); if (he == NULL) { /* char pre[100], suf1[100]; strcpy(pre , EFHNToStr(prefix)); strcpy(suf1 , EFHNToStr(suffix)); fprintf(stderr,"Called outnode w/ %s %s na=%s\n", pre, suf1,name); */ (void) fprintf(outf, "errGnd!"); return; } /* Canonical name */ nn = (EFNodeName *) HashGetValue(he); EFHNOut(nn->efnn_node->efnode_name->efnn_hier, outf); nn->efnn_node->efnode_client = (ClientData) esFetNodesOnly; } } /* * ---------------------------------------------------------------------------- * * capVisit -- * * Procedure to output a single capacitor to the .sim file. * Called by EFVisitCaps(). * * Results: * Returns 0 always. * * Side effects: * Writes to the file esSimF. * * Format of a .sim cap line: * * C node1 node2 cap * * where * node1, node2 are the terminals of the capacitor * cap is the capacitance in femtofarads (NOT attofarads). * * ---------------------------------------------------------------------------- */ int capVisit(hierName1, hierName2, cap) HierName *hierName1; HierName *hierName2; int cap; { cap = (cap + 500) / 1000; if (cap <= EFCapThreshold) return 0; (void) fprintf(esSimF, "C "); EFHNOut(hierName1, esSimF); (void) fprintf(esSimF, " "); EFHNOut(hierName2, esSimF); (void) fprintf(esSimF, " %d\n", cap); return 0; } /* * ---------------------------------------------------------------------------- * * resistVisit -- * * Procedure to output a single resistor to the .sim file. * Called by EFVisitResists(). * * Results: * Returns 0 always. * * Side effects: * Writes to the file esSimF. * * Format of a .sim resistor line: * * r node1 node2 res * * where * node1, node2 are the terminals of the resistor * res is the resistance in ohms (NOT milliohms) * * * ---------------------------------------------------------------------------- */ int resistVisit(hierName1, hierName2, res) HierName *hierName1; HierName *hierName2; int res; { res = (res+ 500)/1000; (void) fprintf(esSimF, "r "); EFHNOut(hierName1, esSimF); (void) fprintf(esSimF, " "); EFHNOut(hierName2, esSimF); (void) fprintf(esSimF, " %d\n", res); return 0; } /* * ---------------------------------------------------------------------------- * * nodeVisit -- * * Procedure to output a single node to the .sim file, along with * its aliases to the .al file and its location to the .nodes file. * Called by EFVisitNodes(). * * Results: * Returns 0 always. * * Side effects: * Writes to the files esSimF, esAliasF, and esLabF. * * ---------------------------------------------------------------------------- */ int nodeVisit(node, res, cap) register EFNode *node; int res, cap; { register EFNodeName *nn; HierName *hierName; bool isGlob; char *fmt; EFAttr *ap; register fetClient *fc; if (esFetNodesOnly && node->efnode_client == (ClientData) 0) return 0; hierName = (HierName *) node->efnode_name->efnn_hier; cap = (cap + 500) / 1000; res = (res + 500) / 1000; if (cap > EFCapThreshold) { (void) fprintf(esSimF, "C "); EFHNOut(hierName, esSimF); (void) fprintf(esSimF, " GND %d\n", cap); } if (res > EFResistThreshold) { (void) fprintf(esSimF, "R "); EFHNOut(hierName, esSimF); (void) fprintf(esSimF, " %d\n", res); } if (node->efnode_attrs && !esNoAttrs) { (void) fprintf(esSimF, "A "); EFHNOut(hierName, esSimF); for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next) { (void) fprintf(esSimF, fmt, ap->efa_text); fmt = ",%s"; } putc('\n', esSimF); } if (esAliasF) { isGlob = EFHNIsGlob(hierName); for (nn = node->efnode_name->efnn_next; nn; nn = nn->efnn_next) { if (isGlob && EFHNIsGlob(nn->efnn_hier)) continue; (void) fprintf(esAliasF, "= "); EFHNOut(hierName, esAliasF); (void) fprintf(esAliasF, " "); EFHNOut(nn->efnn_hier, esAliasF); (void) fprintf(esAliasF, "\n"); } } if (esLabF) { (void) fprintf(esLabF, "94 "); EFHNOut(hierName, esLabF); (void) fprintf(esLabF, " %d %d %s;\n", node->efnode_loc.r_xbot, node->efnode_loc.r_ybot, EFLayerNames[node->efnode_type]); } return 0; }