2 This file is part of the software library CADLIB written by Conrad Ziesler
3 Copyright 2003, Conrad Ziesler, all rights reserved.
5 *************************
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* extract.c : optional magic .ext file input (bypassing ext2spice)
22 links to magic's extract library
23 .ext files have more/better info than what's in the spice file,
24 which gives us better debugging info, and integration with the layout
30 /* this is loosely based on magic's extcheck sample program,
31 and links to the magic libraries, so if you don't have them, undef USE_EXTRACT_FORMAT
33 the following copyright notice was from extcheck.c, which this code was based on
40 * *********************************************************************
41 * * Copyright (C) 1985, 1990 Regents of the University of California. *
42 * * Permission to use, copy, modify, and distribute this *
43 * * software and its documentation for any purpose and without *
44 * * fee is hereby granted, provided that the above copyright *
45 * * notice appear in all copies. The University of California *
46 * * makes no representations about the suitability of this *
47 * * software for any purpose. It is provided "as is" without *
48 * * express or implied warranty. Export of this software outside *
49 * * of the United States of America may require an export license. *
50 * *********************************************************************
65 #include "netlist_extract.h"
73 void *mymalloc(unsigned size
)
79 #define CHECK_EXTINIT(g) if(g!=NULL) if(g->input.generic->magic==EXTRACT_MAGIC) if(g->input.ext->did_EF_init_read)
81 #ifdef USE_EXTRACT_FORMAT
90 #include "include/magic.h"
91 #include "include/paths.h"
92 #include "include/geometry.h"
93 #include "include/hash.h"
94 #include "include/utils.h"
95 #include "include/pathvisit.h"
96 #include "include/extflat.h"
97 #include "include/runstats.h"
100 int GeoScale(Transform
*t
);
102 void EFReadFile(char *name
);
103 void EFFlatBuild(char *rootName
, int flags
);
104 void EFFlatDone(void);
106 int (*fetProc
)(Fet
*fet
, HierName
*hname
, Transform
*t
, int l
, int w
, ClientData data
),
111 int (*nodeProc
)(EFNode
*node
, int r
, double c
, ClientData cdata
),
115 bool EFHNIsGlob(HierName
*hname
);
116 char * EFHNToStr(HierName
*hierName
);
121 static int ecNumFets
;
122 static int ecNumCaps
;
123 static int ecNumResists
;
124 static int ecNumThreshCaps
;
125 static int ecNumThreshResists
;
126 static int ecNumNodes
;
127 static int ecNumGlobalNodes
;
128 static int ecNumNodeCaps
;
129 static int ecNumNodeResists
;
137 make a new extract_t container
138 first create fake argc, *argv[] using extract options from config file
141 #ifdef USE_EXTRACT_FORMAT
142 extract_t
*extract_new(char *rootname
)
146 assert(rootname
!=NULL
);
147 p
=mymalloc(sizeof(extract_t
)+(sizeof(char*)*(PARAMS
.extract_qty
+4)));
149 memset(p
,0,sizeof(extract_t
));
150 p
->root
=strdup(rootname
);
151 assert(p
->root
!=NULL
);
152 p
->extract_magic
=EXTRACT_MAGIC
;
153 p
->ext_argv
=(char **) (&p
[1]);
154 p
->ext_argv
[0]="ext2spice";
155 for(i
=1;i
< (PARAMS
.extract_qty
+1);i
++)
156 p
->ext_argv
[i
]=PARAMS
.extract_params
[i
-1];
157 p
->ext_argv
[i
]=p
->root
;
158 p
->ext_argv
[i
+1]=NULL
;
160 p
->did_EF_init_read
=0;
164 /* Process command line arguments */
166 p
->fname
= EFArgs(p
->ext_argc
, p
->ext_argv
, (int (*)()) NULL
, (ClientData
) NULL
);
167 if(p
->fname
==NULL
){ fprintf(stderr
,"ERROR: extract configuration error\n"); return NULL
; }
169 /* Read the hierarchical description of the input circuit */
170 EFReadFile(p
->fname
);
172 if(PARAMS
.extfix
!=NULL
) /* tag with extfix data (merge Gnd/Vdd GND/VDD) */
173 EFReadFile(PARAMS
.extfix
);
175 if (EFArgTech
) EFTech
= StrDup((char **) NULL
, EFArgTech
);
176 if (EFScale
==0) EFScale
= 1;
177 p
->did_EF_init_read
=1;
181 fprintf(stderr
,"EXT: %i layers defined\n",EFLayerNumNames
);
182 for(i
=0;i
<EFLayerNumNames
;i
++)
183 fprintf(stderr
,"EXT: layer %i=%s\n",i
,EFLayerNames
[i
]);
193 extract_t
*extract_new(char *rootname
)
201 #ifndef USE_EXTRACT_FORMAT
204 /****************** LINK TO MAGIC EXTFLAT LIBRARY ************/
210 void extract_finish(graph_t
*gr
)
216 fprintf(stderr
,"EXT: Memory used: %s\n", RunStats(RS_MEM
, NULL
, NULL
));
217 fprintf(stderr
,"EXT: %d fets\n", ecNumFets
);
218 fprintf(stderr
,"EXT: %d nodes (%d global, %d local)\n",
219 ecNumNodes
, ecNumGlobalNodes
, ecNumNodes
- ecNumGlobalNodes
);
220 fprintf(stderr
,"EXT: %d nodes above capacitance threshold\n", ecNumNodeCaps
);
221 fprintf(stderr
,"EXT: %d nodes above resistance threshold\n", ecNumNodeResists
);
222 fprintf(stderr
,"EXT: %d internodal capacitors (%d above threshold)\n",
223 ecNumCaps
, ecNumThreshCaps
);
224 fprintf(stderr
,"EXT: %d explicit resistors (%d above threshold)\n",
225 ecNumResists
, ecNumThreshResists
);
228 static int countfetVisit(Fet
*fet
, HierName
*hname
, Transform
*t
, int l
, int w
, ClientData data
)
230 fet
->fet_type
&=0x07f; /* clear our sneaky bit */
236 static int countnodeVisit(EFNode
*node
, int res
, double cap
, ClientData data
)
242 static EFNode
*GetNode(HierName
*prefix
,HierName
*suffix
)
246 he
= EFHNConcatLook(prefix
, suffix
, "output");
247 return(((EFNodeName
*) HashGetValue(he
))->efnn_node
);
251 void extract_setup_graph(graph_t
*gr
)
254 CHECK_EXTINIT(gr
)er
=0;
257 /* Convert the hierarchical description to a flat one */
258 EFFlatBuild(gr
->input
.ext
->fname
, EF_FLATNODES
| EF_FLATCAPS
| EF_FLATRESISTS
);
262 EFVisitFets(countfetVisit
, (void *) gr
);
263 EFVisitNodes(countnodeVisit
, (void *) gr
);
267 fprintf(stderr
,"EXT: setup %i fets %i nodes\n",gr
->mge
, gr
->mgn
);
273 static int buildnodeVisit(EFNode
*node
, int res
, double cap
, ClientData data
)
275 graph_t
*g
=(void *)data
;
284 cap = (cap + 500) / 1000;
285 res = (res + 500) / 1000;
290 assert(node
->efnode_name
!=NULL
);
291 str
=EFHNToStr(node
->efnode_name
->efnn_hier
);
294 if (EFHNIsGlob(node
->efnode_name
->efnn_hier
)) ecNumGlobalNodes
++;
296 pay
.flag
=PAYLOAD_node
;
297 pay
.data
=gn
=new_gn(g
);
298 node
->efnode_client
=(void *)gn
; /* store our node ptr in here so we don't have to compare strings */
299 hc
=add_hashtab(g
->names
,str
,pay
); /* add some string data for debugging, printing, etc memory hog*/
300 if(EFHNIsGlob(node
->efnode_name
->efnn_hier
))
303 gn
->special
=safestrdup(hc
->str
);
304 l
=strlen(gn
->special
);
305 if(gn
->special
[l
-1]=='!')gn
->special
[l
-1]=0;
307 else gn
->special
=NULL
;
312 gn
->cfixed
=cap
*1e-18; /* cap in attofarrads 1e-18 */
313 diff
[FTpfet
]=node
->efnode_pa
+1; /* resist class 1 from techfile is pdiff */
314 diff
[FTnfet
]=node
->efnode_pa
+0; /* resist class 0 from techfile is ndiff */
318 (PARAMS
.scale
* PARAMS
.scale
* diff
[i
]->pa_area
* PARAMS
.c_area_sd
[i
]) +
319 (PARAMS
.scale
* diff
[i
]->pa_perim
* PARAMS
.c_perim_sd
[i
])
324 The above code is very dependent on the magic techfile extract section,
325 namely, it assumes a specific resistance class ordering
326 and it assumes the extractor doesn't sum up diffusion and gate capacitance
332 static graph_t
*extract_Graph
;
334 static int buildfetVisit(Fet
*fet
, HierName
*hname
, Transform
*t
, int l
, int w
, ClientData data
)
337 FetTerm
*gate
, *source
, *drain
;
338 EFNode
/* *bnode,*/ *snode
, *dnode
, *gnode
;
341 graph_t
*gr
=extract_Graph
;
344 double sc
=PARAMS
.scale
; /* lamda in meters */
349 gate
= &fet
->fet_terms
[0];
350 source
= drain
= &fet
->fet_terms
[1];
351 if (fet
->fet_nterm
>= 3)
352 drain
= &fet
->fet_terms
[2];
354 gnode
= GetNode (hname
, gate
->fterm_node
->efnode_name
->efnn_hier
);
355 snode
= GetNode (hname
, source
->fterm_node
->efnode_name
->efnn_hier
);
356 dnode
= GetNode (hname
, drain
->fterm_node
->efnode_name
->efnn_hier
);
357 /*bnode = fetSubstrate(hname, fet->fet_subsnode->efnode_name->efnn_hier, fet->fet_type, NULL);*/
361 GeoTransRect(t
, &fet
->fet_rect
, &r
);
366 typ
=np_type((uchar
)ft
[0]);
371 ep
->flatref
.x
=r
.r_ll
.p_x
;
372 ep
->flatref
.xx
=r
.r_ur
.p_x
;
373 ep
->flatref
.y
=r
.r_ll
.p_y
;
374 ep
->flatref
.yy
=r
.r_ur
.p_y
;
376 ep
->WL
= (PARAMS
.gm_woverl
[ep
->type
]*(double)w
)/(double)l
;
377 ep
->Cg
= sc
*sc
*PARAMS
.c_area_gate
[ep
->type
]*((double)w
*scale
)*((double)l
*scale
);
378 ep
->Cs
=0; /* compute this from ? */
379 ep
->Cd
=0; /* same with this */
381 /* for above Cs,Cd: strategy, split the diffusion resistance classes between all fet s/d's connected
382 to the node, proportional to the total width of each device
383 this is better than the hspice version, where diffusion is lumped onto a single fet.
384 so one poor fet gets all the diffusion for resizing
385 we have to do this after we visit all the fets once, so node wtotals are updated correctly
388 ep
->parent
.vp
=(void *)fet
;
389 ep
->gn
[GE_G
]=(void *)(gnode
->efnode_client
);
390 ep
->gn
[GE_S
]=(void *)(snode
->efnode_client
);
391 ep
->gn
[GE_D
]=(void *)(dnode
->efnode_client
);
392 if(ep
->gn
[GE_S
] > ep
->gn
[GE_D
] ) /* put source/drain in cannonical order (source is lower node number) */
393 { void *tmp
=ep
->gn
[GE_S
]; ep
->gn
[GE_S
]=ep
->gn
[GE_D
]; ep
->gn
[GE_D
]=tmp
; }
394 ep
->gn
[GE_S
]->wtotal
+=(w
*scale
*sc
);
395 ep
->gn
[GE_D
]->wtotal
+=(w
*scale
*sc
);
400 static int capVisit(HierName *hn1, HierName *hn2, double cap)
403 cap = (cap + 500) / 1000;
404 if (cap > (double) EFCapThreshold) ecNumThreshCaps++;
408 static int resistVisit(HierName *hn1, HierName *hn2, int res)
411 res = (res + 500) / 1000;
412 if (res > EFResistThreshold) ecNumThreshResists++;
419 static int comparesorted(const void *a
, const void *b
)
421 const ge_t
*pa
=a
,*pb
=b
;
424 if(pa
==NULL
)return 1;
425 if(pb
==NULL
)return -1;
428 if(pa
->gn
[GE_G
] > pb
->gn
[GE_G
])return 1;
429 if(pa
->gn
[GE_G
] < pb
->gn
[GE_G
])return -1;
431 if( (pa
->gn
[GE_S
]==pb
->gn
[GE_S
]) )
433 if(pa
->gn
[GE_D
] > pb
->gn
[GE_D
] ) return 1;
434 else if(pa
->gn
[GE_D
] < pb
->gn
[GE_D
] ) return -1;
436 if( (pa
->gn
[GE_D
]==pb
->gn
[GE_D
]) )
438 if(pa
->gn
[GE_D
] > pb
->gn
[GE_D
] ) return 1;
439 else if(pa
->gn
[GE_D
] < pb
->gn
[GE_D
] ) return -1;
441 else if( (pa
->gn
[GE_S
]==pb
->gn
[GE_D
]) )
443 if(pa
->gn
[GE_D
] > pb
->gn
[GE_S
] ) return 1;
444 else if(pa
->gn
[GE_D
] < pb
->gn
[GE_S
] ) return -1;
446 else if( (pa
->gn
[GE_D
]==pb
->gn
[GE_S
]) )
448 if(pa
->gn
[GE_S
] > pb
->gn
[GE_D
] ) return 1;
449 else if(pa
->gn
[GE_S
] < pb
->gn
[GE_D
] ) return -1;
453 if(pa
->gn
[GE_S
] > pb
->gn
[GE_S
] ) return 1;
454 else if(pa
->gn
[GE_S
] < pb
->gn
[GE_S
] ) return -1;
461 static double compute_diffcap(gn_t
*np
, double w
, int type
)
465 if(ws
<=0.0)assert(0);
466 c
= np
->cdiff
[type
]*w
/ws
;
470 void extract_build_graph(graph_t
*gr
)
475 CHECK_EXTINIT(gr
)er
=0;
479 EFVisitNodes(buildnodeVisit
, (ClientData
) gr
);
480 EFVisitFets(buildfetVisit
, (ClientData
) gr
);
483 if (EFCapThreshold < INFINITE_THRESHOLD) EFVisitCaps(capVisit, (ClientData) NULL);
484 if (EFResistThreshold < INFINITE_THRESHOLD) EFVisitResists(resistVisit, (ClientData) NULL);
487 /* now we want to sort the edges to merge duplicate fets faster */
488 qsort(gr
->ge
,gr
->qge
,sizeof(ge_t
),comparesorted
);
490 /* mark and merge parallel transistors */
491 for(i
=0,j
=0,pep
=NULL
,ep
=gr
->ge
;i
<gr
->qge
;i
++)
495 if( (ep
->gn
[GE_G
]==pep
->gn
[GE_G
]) &&
496 (ep
->gn
[GE_S
]==pep
->gn
[GE_S
]) &&
497 (ep
->gn
[GE_D
]==pep
->gn
[GE_D
])
498 ) /* parallel fet, merge */
513 /* eliminate flagged transistors
514 wep moves forward for each new good transistor
515 ep moves forward for each transistor
518 for(j
=0,wep
=ep
=gr
->ge
,i
=0;i
<gr
->qge
;i
++)
520 if(!ep
->flag
) { if(wep
!=ep
) { *wep
=*ep
; } j
++; wep
++; }
527 /* now divvy up s/d diffusions between fets */
529 for(ep
=gr
->ge
,i
=0;i
<gr
->qge
;i
++)
533 ep
->Cs
=compute_diffcap(ep
->gn
[GE_S
],w
,ep
->type
);
534 ep
->Cd
=compute_diffcap(ep
->gn
[GE_D
],w
,ep
->type
);
544 #endif /* USE_EXTRACT_FORMAT */