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 /* netlist.c, generalized netlist functions
27 we try to store a netlist in a form which is as compact as possible, while being extensible
28 by clients, in addition to being general enough to handle all possible netlist input formats
30 the primary memory saving device is the termptr_t bitfield, where we make a complex
31 pointer which represents the type of node it points to.
33 also we statically allocate memory for the devices using list_t blocks.
34 and allocate extra space per device as defined by the client structure
43 #define __NETLIST_PRIVATE__
48 /* call these at entry and exit of all netlist functions that potentially modify equations */
49 void netlist_eqn_begin(netlist_t
*nl
)
51 assert(nl
->eqn_mem
!=NULL
);
52 eqn_mem_push(nl
->eqn_mem
);
55 void netlist_eqn_end(netlist_t
*nl
)
57 if(eqn_mem_pop()!=nl
->eqn_mem
)
62 /* some assumptions we make about bitfield encodings */
63 int netlist_machine(void)
65 assert(sizeof(termptr_t
)==sizeof(void*));
66 assert(sizeof(unsigned int) == sizeof(void*));
67 assert(sizeof(unsigned int) == 4 );
71 termptr_t
netlist_termptr_null_t(termptr_t from
)
77 termptr_t
netlist_termptr_null(void)
87 termptr_t
netlist_termptr_nonnull(termptr_t from
)
94 termptr_t
netlist_termptr(int dev
, int term
, int type
)
104 int netlist_termptr_devi(termptr_t t
)
107 int netlist_termptr_termi(termptr_t t
)
110 int netlist_termptr_devt(termptr_t t
)
113 termptr_t
netlist_termptr_deref(netlist_t
*nl
, termptr_t t
)
116 assert(t
.devt
<nl
->qe
);
118 assert(t
.termi
<nl
->e
[t
.devt
].qterms
);
119 assert(t
.nonnull
==1);
120 return NETLIST_TERM(nl
,t
.devt
,t
.devi
,t
.termi
);
123 int netlist_node_termptr(netlist_t
*nl
, termptr_t t
)
125 while(t
.devt
!=DEVT_NODE
)
126 t
=netlist_termptr_deref(nl
,t
);
131 int netlist_add_dev_(netlist_t
*nl
, int devt
, void *p
)
136 i
=list_add(&(nl
->e
[devt
].l
),p
);
140 int netlist_add_dev(netlist_t
*nl
, int devt
)
145 i
=list_nextz(&(nl
->e
[devt
].l
));
149 /* merge duplicate entities summing results
150 the user function tocompare returns a ptr to some static area
151 which is filled with data that should be sorted and matched to
153 the user function sum takes the indices of the two entities
154 and performs the equivilent of [a]=[a]+[b]
155 if sum returns 1 we remove item b
156 so sum should frees any private data associated with [b] on 1
159 void netlist_merge(netlistfunc_t
*nm
)
165 list_t
*entity
=&(nm
->entity
->l
);
168 if(nm
->tocompare
==NULL
)return;
169 if(nm
->sum
==NULL
)return;
170 if(nm
->qcmp
<=0)return;
171 buffer
=malloc(nm
->qcmp
);
172 assert(buffer
!=NULL
);
173 memset(buffer
,0,nm
->qcmp
);
175 md
=mergedup_alloc(list_qty(entity
),nm
->qcmp
);
177 list_iterate(entity
,i
,data
)
179 nm
->tocompare(nm
,i
,buffer
);
180 mergedup_fill(md
,buffer
,i
);
189 ib
=mergedup_visit(md
,0); /* get next same */
193 ia
=mergedup_visit(md
,1); /* get next different */
198 if(nm
->sum(nm
,ia
,ib
))
200 /* flag delete item */
201 mergedup_setbit(md
,ib
);
207 ia
=0; /* count number of remaining elements */
208 for(i
=0;i
<list_qty(entity
);i
++)
209 if(!mergedup_testbit(md
,i
))ia
++;
211 list_copyfrom(&newl
,entity
); /* setup new list */
212 list_hint(&newl
,ia
); /* pre-alloc data */
213 list_iterate(entity
,i
,data
) /* fill new list */
215 if(!mergedup_testbit(md
,i
))
216 list_add(&newl
,data
);
218 mergedup_free(md
); /* free mergedup */
219 list_empty(entity
); /* free old list data */
220 *entity
=newl
; /* copy over new pointers into old list */
224 /* distribute some attribute across entity
226 network of entities, connected via nodes.
227 some attribute associated with an entity terminal
228 first accumulate properties per node
229 then distribute to all entities connected to that node
231 ie: extract programs lump diffusion on one fet instead of distributing it as per width
235 void netlist_distribute(netlistfunc_t
*nm
)
238 netlist_t
*nl
=nm
->nl
;
239 list_t
*entity
=&(nm
->entity
->l
);
240 entity_t
*e
=nm
->entity
;
241 int qterm
=nm
->entity
->qterms
;
244 if(nm
->qproperties
<=0)return;
246 node_sums
=malloc(sizeof(float)*list_qty(&(nl
->e
[DEVT_NODE
].l
))*nm
->qproperties
);
247 assert(node_sums
!=NULL
);
249 for(i
=0;i
< (list_qty(&(nl
->e
[DEVT_NODE
].l
))*nm
->qproperties
);i
++)
252 list_iterate_(entity
,i
)
258 t
=NETLIST_E_TERM(e
,i
,j
);
259 node_data
=node_sums
+ (netlist_termptr_devi(t
)*nm
->qproperties
) ;
260 if(nm
->accumulate
!=NULL
)
261 nm
->accumulate(nm
,i
,j
,node_data
);
265 list_iterate_(entity
,i
)
271 t
=NETLIST_E_TERM(e
,i
,j
);
272 node_data
=node_sums
+ (netlist_termptr_devi(t
)*nm
->qproperties
) ;
273 if(nm
->distribute
!=NULL
)
274 nm
->distribute(nm
,i
,j
,node_data
);
282 /* fixup netlist node pointers
284 when we first build a netlist, we have a many to one relationship
285 for the entity terminals, ie. they all point to the associated node
287 we also want to be able to enumerate the list of entity terminals on
288 a given net, without going through all entities and comparing.
290 thus we have to fixup the netlist, making a linked list out of the terminal ptrs
292 so we can walk through all the terminals on a net.
293 also we put the actual node on the head of that list.
295 we call a user function for each terminal on the net (to store back pointer if necessary)
298 void netlist_fixup(netlistfunc_t
*nm
)
300 netlist_t
*nl
=nm
->nl
;
308 /* init tail ptrs, to point to the head ptr */
309 list_iterate(&(nl
->e
[DEVT_NODE
].l
),i
,np
)
312 NETLIST_TERM(nl
,DEVT_NODE
,i
,1)=t
=netlist_termptr(i
,0,DEVT_NODE
);
313 NETLIST_TERM(nl
,DEVT_NODE
,i
,0)=netlist_termptr_null_t(t
);
316 for(i
=0;i
<nl
->qe
;i
++)
318 qterms
=nl
->e
[i
].qterms
;
319 list_iterate(&(nl
->e
[i
].l
),j
,dp
)
321 for(k
=0;k
<qterms
;k
++)
324 t
=NETLIST_TERM(nl
,i
,j
,k
);
325 assert(t
.devt
==DEVT_NODE
);
326 nt
=NETLIST_TERM(nl
,t
.devt
,t
.devi
,1); /* tail ptr */
327 npn1
=NETLIST_TERM(nl
,t
.devt
,t
.devi
,1)=netlist_termptr(j
,k
,i
);
328 NETLIST_TERM(nl
,nt
.devt
,nt
.devi
,nt
.termi
)=npn1
; /* also links n[0] */
329 /* call user routine if not avail */
339 int netlist_findnode(netlist_t
*nl
, char *str
)
342 pindex
=names_check(nl
->names
,str
);
347 termptr_t
netlist_node(netlist_t
*nl
, char *str
, void *parent
)
351 if(0)fprintf(stderr
,"\nnode %s %p\n",str
,parent
);
352 pindex
=names_check(nl
->names
,str
);
355 pindex
=netlist_add_dev(nl
,DEVT_NODE
);
356 names_add(nl
->names
,pindex
,str
);
357 tp
=netlist_termptr(pindex
,0,DEVT_NODE
);
358 NETLIST_TERM(nl
,DEVT_NODE
,pindex
,0)=tp
;
359 NETLIST_TERM(nl
,DEVT_NODE
,pindex
,1)=tp
;
363 tp
=netlist_termptr(pindex
,0,DEVT_NODE
);
370 int netlist_newdev_fromnode(netlist_t
*nl
, int devt
, dev_input_t parent
, termptr_t n
[])
374 qv
=NETLIST_QVALS (nl
,devt
);
375 q
=NETLIST_QTERMS (nl
,devt
);
377 index
=netlist_add_dev(nl
,devt
);
378 NETLIST_PARENT(nl
,devt
,index
)=parent
;
381 NETLIST_TERM(nl
,devt
,index
,i
)=n
[i
];
384 NETLIST_VAL(nl
,devt
,index
,i
)=eqn_empty();
390 void netlist_init(netlist_t
*nl
)
393 entity_t e
=ENTITY_INVALID
;
395 for(i
=0;i
<TERMPTR_MAX_DEVT
;i
++)
398 nl
->names
=names_new();
400 nl
->eqn_mem
=eqn_mem_new();
402 eqnl_init(&(nl
->eqnl
));
406 int netlist_register_entity (netlist_t
*nl
, int id
, int qterms
, int qvals
, int qrest
, char *sym
, int othersize
)
410 if(nl
->qe
>=TERMPTR_MAX_DEVT
)
418 strncpy(ep
->sym
,sym
,8);
422 list_init(&(ep
->l
),NETLIST_OFFSET_OTHER((*ep
))+othersize
,LIST_DEFMODE
);
426 netlist_input_t
netlist_parse_input(scanner_t
*scan
, char *type
, netlist_param_t
*params
)
433 if(strcmp(type
,"spice")==0)
435 p
.spice
=spice_new(scan
);
437 if(strcmp(type
,"extract")==0)
439 /* p.ext=extract_new(scan); */
442 parse_error(scan
, "Netlist: can't parse input of type %s",type
);
448 void netlist_debug_input(void * dbg_fp
, netlist_input_t p
)
454 fprintf(dbg
, "can't debug netlist input, null ptr");
456 if(p
.generic
->magic
==SPICE_MAGIC
)
457 spice_debug(dbg
,p
.spice
);
459 else if(p
.generic
->magic
==EXTRACT_MAGIC
)
460 /* p.ext=extract_debug(dbg,p.extract) */ ;
464 void netlist_debug(void * dbg_fp
, netlist_t
*nl
)
466 netlist_debug_(dbg_fp
,nl
,0);
470 void netlist_debug_(void * dbg_fp
, netlist_t
*nl
, int eval
)
476 fprintf(dbg
,"can't debug netlist, null ptr");
480 if(0)fprintf(stderr
,"\n\nbegin evaldep \n\n");
481 eqnl_evaldep(&(nl
->eqnl
));
482 if(0)fprintf(stderr
,"\n\ndone evaldep \n\n");
485 fprintf(dbg
,"debugging netlist eval=%i, %p\n",eval
,nl
);
486 for(i
=0;i
<nl
->qe
;i
++)
493 fprintf(dbg
," e %i %s, qterm=%i qcount=%i l.q,m=%i,%i\n",
494 i
,e
->sym
,e
->qterms
,e
->qcount
,e
->l
.q
,e
->l
.m
496 list_iterate_(&(e
->l
),j
)
499 fprintf(dbg
,"%i: ",j
);
501 for(k
=0;k
<e
->qterms
;k
++)
503 termptr_t t
=NETLIST_E_TERM(e
,j
,k
);
504 fprintf(dbg
," [%i %s.%i]",t
.devi
,nl
->e
[t
.devt
].sym
,t
.termi
);
506 fprintf(dbg
,"=%s ",names_lookup(nl
->names
,j
));
510 v
=NETLIST_VALS(nl
,i
,j
);
511 for(k
=0;k
<e
->qvals
;k
++)
516 sprintf(buf
," %i",k
);
517 debug_eqn(dbg
,buf
,v
+k
);
523 f
=eqnl_eval(&(nl
->eqnl
),v
[k
]);
524 fprintf(dbg
," ev %g ",f
);
536 /* release input from netlist (free structures if possible)
537 after this call, all parent ptrs and input ptrs are set to null
539 void netlist_release(netlist_t
*nl
)
543 /* reset all the parent ptrs to null */
544 for(i
=0;i
<nl
->qe
;i
++)
546 list_iterate_(&(nl
->e
[i
].l
),j
)
547 NETLIST_PARENT(nl
,i
,j
).p
=NULL
;
550 /* call low level free function */
551 switch(nl
->input
.generic
->magic
)
554 spice_release(nl
->input
.spice
);
558 /* extract_release(nl->input.ext); */
566 /* this releases input if not already done
567 and then frees up the memory associated with the netlist
568 any additional client memory should already have been freed
571 void netlist_free(netlist_t
*nl
)
576 if(nl
->input
.p
!=NULL
)
579 for(i
=0;i
<TERMPTR_MAX_DEVT
;i
++)
580 list_empty(&(nl
->e
[i
].l
));
582 eqn_mem_free(nl
->eqn_mem
);
586 eqnl_free(&(nl
->eqnl
));
587 names_free(nl
->names
);
596 int netlist_print_nodep(netlist_t
*n
, netprint_t grp
, void * file_fp
, void *gn
, char *str
)
600 const char *err
="node_error";
604 fprintf(file
,"%s",str
);
606 index
=list_index(&(n
->e
[DEVT_NODE
].l
),gn
);
614 fprintf(file
,"%s",names_lookup(n
->names
,index
));
615 else fprintf(file
,err
);
619 fprintf(file
,"n%i",index
);
620 else fprintf(file
,err
);
622 fprintf(file
,"N_%p",gn
);
625 name
=names_lookup(n
->names
,index
);
628 fprintf(file
,"N%i_%s",index
,name
+i
);
633 fprintf(file
,"[Node %p %i %s]",gn
,index
,names_lookup(n
->names
,index
));
635 fprintf(file
,"[Node %p]",gn
);
641 void netlist_eval(netlist_t
*n
)
643 eqnl_evaldep(&(n
->eqnl
));
648 /* this is somewhat inefficient, please don't rely on it */
649 netlist_t
*netlist_copyisher(netlist_t
*in
, int extrasize
, int extrasizes
[])
656 nl
=malloc(sizeof(netlist_t
)+extrasize
);
660 for(i
=0;i
<in
->qe
;i
++)
665 index
=netlist_register_entity(nl
,ep
->id
,ep
->qterms
,ep
->qvals
,ep
->qother
,ep
->sym
,extrasizes
[i
]);
666 assert(sizeof(buffer
)> (extrasizes
[i
]+NETLIST_OFFSET_OTHER((*ep
))));
668 memset(buffer
,0,sizeof(buffer
));
669 sin
=list_sizeof(&(in
->e
[i
].l
));
670 list_hint(&(nl
->e
[index
].l
),sin
);
671 list_iterate(&(ep
->l
),j
,p
)
673 memcpy(buffer
,p
,sin
); /* yes, we copy twice. this is required, think about it */
674 list_add(&(nl
->e
[index
].l
),buffer
);
678 /* POTENTIAL MEMORY LEAK HERE */
679 nl
->names
=in
->names
; /* share name database */
680 nl
->eqnl
=in
->eqnl
; /* share eqnl database */
681 nl
->input
.p
=NULL
; /* flag this to null */