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 /* spice.c: read hierachical spice deck composed of M and C and X
32 /* The following is copied from xcircuit.h */
34 #define Fprintf tcl_printf
35 #define Flush tcl_stdflush
37 #define Fprintf fprintf
42 int __debug_spice__
=2;
44 #ifndef STRIP_DEBUGGING
45 #define D(level,a) do { if(__debug_spice__>(level)) a; } while(0)
53 M0 6 3 1 1 NMOS W=1.025U L=0.350U AD=0.0 AS=0.0 PD=0.0 PS=0.0
54 M1 7 4 6 1 NMOS W=1.025U L=0.350U AD=0.0 AS=0.0 PD=0.0 PS=0.0
66 #define __NETLIST_SPICE_C__ 1
70 #include "netlist_dev.h"
75 #ifndef __NETLIST_SPICE_H__
76 #include "netlist_spice.h"
79 tokenmap_t spice_tokens
[]=SPICE_TOKENS
;
81 /******* Hashing Clients *******/
83 uint
paramclient_hash(int max
, void *data
, int size
)
85 return hash_strhash(max
, ((char *)data
)+sizeof(paramload_t
), size
-sizeof(paramload_t
));
89 int paramclient_cmp(int sizea
, void *a
, int sizeb
, void *b
)
93 if(sizea
> sizeb
) return 1;
94 if(sizea
< sizeb
) return -1;
95 return memcmp( ((char *) a
) + sizeof(paramload_t
), ((char *)b
) + sizeof(paramload_t
),sizeb
-sizeof(paramload_t
) );
98 static callparam_t
*new_callparam(char *str
, eqn_t eqn
)
101 pc
=malloc(sizeof(callparam_t
)+strlen(str
));
109 static paramclient_t
*add_param(hash_t
*h
, char *str
, eqn_t eqn
)
116 if(l
>(sizeof(data
)-sizeof(paramclient_t
)))
117 l
=sizeof(data
)-sizeof(paramclient_t
);
119 pc
->payload
.patch_call
=NULL
;
120 pc
->payload
.global_i
=-1;
121 memcpy(pc
->str
,str
,l
);
122 return hash_add(h
,pc
,l
+sizeof(paramload_t
));
125 uint
nodeclient_hash(int max
, void *data
, int size
)
127 return hash_strhash(max
, ((char *)data
)+sizeof(hashload_t
), size
-sizeof(hashload_t
));
130 int nodeclient_cmp(int sizea
, void *a
, int sizeb
, void *b
)
133 if(b
==NULL
)return -1;
134 if(sizea
> sizeb
) return 1;
135 if(sizea
< sizeb
) return -1;
136 return memcmp( ((char *) a
) + sizeof(hashload_t
), ((char *)b
) + sizeof(hashload_t
), sizea
-sizeof(hashload_t
) );
139 /* some helper functions for hash clients */
141 static nodeclient_t
*find_hashtab(hash_t
*tab
, uchar
*str
)
145 return hash_find(tab
,str
-sizeof(hashload_t
),sizeof(hashload_t
)+l
);
148 subckt_t
*spice_find_subckt(subckt_t
*parent
, char *name
)
151 tc
=find_hashtab(parent
->cktdir
,(uchar
*)name
);
152 return tc
->payload
.data
.subckt
;
156 list_t
spice_list_subckt(subckt_t
*parent
)
165 list_init(&foo
,sizeof(subckt_t
*),LIST_EXPMODE
);
166 if(parent
==NULL
)return foo
;
169 FORALL_HASH(tab
,i
,bp
)
172 ckt
=p
->payload
.data
.subckt
;
173 list_add (&foo
,&ckt
);
179 static nodeclient_t
*add_hashtab(hash_t
*tab
, uchar
*str
, hashload_t payload
)
184 static unsigned data
[16000];
185 nodeclient_t
*nd
=(void *)data
;
196 assert(l
< (16000-sizeof(nodeclient_t
)));
197 if(tab
->hashfunc
!=nodeclient_hash
)assert(0);
198 cp
=hash_add(tab
,nd
,(sizeof(hashload_t
)+l
));
199 D(20,Fprintf(stderr
,"add_hashtab(%p,%s,..) cp=%p \n",tab
,str
,cp
));
205 #define warning(d,c,s) do { scan->errdeck=d; scan->errcard=c; parse_warn(scan,s); } while(0)
206 #define error(d,c,s) do { scan->errdeck=d; scan->errcard=c; parse_error(scan,s); } while(0)
207 #define checkvalid(d,q) scanner_checkvalid(d,q)
209 static eqn_t
parseval(deck_t
*d
, card_t
*c
, uchar
*val
)
215 if(val
==NULL
)return eqn
;
217 for(ps
=val
;ps
[0]!=0;ps
++)
218 if(!isspace(ps
[0]))break;
220 if(ps
[0]=='\'') ps
++; /* hack */
229 /************************************************************************/
230 /******* PASS 2 : create subcircuit definitions (for forward ref) ****/
231 /******* and count devices (for memory alloc) ****/
232 /******* fill in all devices and nodes (except x subckt) ****/
233 /************************************************************************/
237 static void skip_subckt(deck_t
**thedeckpp
)
240 deck_t
*dp
=*thedeckpp
;
247 if(dp
->card
->token
==Kends
)i
--;
248 if(dp
->card
->token
==Ksubckt
)i
++;
256 static subckt_t
*new_subckt(deck_t
**thedeckpp
, subckt_t
*parent
, scanner_t
*scan
)
258 int i
, qtynodes
, qtyparams
, qtycallparams
, qtylparams
;
259 int qtym
, qtyc
, qtyx
, qtyr
, qtyl
, qtyv
, qtyi
;
260 int qtysubckt
, qtyglobal
;
263 deck_t
*dp
,*d
=*thedeckpp
,*dplast
=NULL
;
267 hashload_t payload
={ PAYLOAD_null
, {NULL
} };
276 if(!checkvalid(d
,2))error(d
,d
->card
,"invalid subckt definition");
277 name
=d
->card
->next
->str
;
280 for(cp
=d
->card
->next
->next
; cp
!=NULL
; cp
=cp
->next
)
282 if(cp
->val
==NULL
) qtynodes
++;
295 for(dp
=d
; dp
!=NULL
; dp
=dp
->next
)
299 if(dp
->card
==NULL
)continue;
301 if( (dp
->card
->token
==Ksubckt
) && (dp
!=d
))
302 { skip_subckt(&dp
); qtysubckt
++; continue; } /* consume .ends token */
305 if(dp
->card
==NULL
)continue;
307 if(dp
->card
->token
==Kend
)break;
308 if(dp
->card
->token
==Kends
)break;
312 { if(dp->card->token==Kends)break; }
313 else { if(dp->card->token==Kend)break; }
320 for(cp
=dp
->card
->next
;cp
!=NULL
;cp
=cp
->next
)
321 if(cp
->val
!=NULL
)qtycallparams
++;
331 if(dp
->card
->token
==Kparam
)
333 for(cp
=dp
->card
->next
;cp
!=NULL
;cp
=cp
->next
)
336 if(dp
->card
->token
==Kglobal
)
338 for(cp
=dp
->card
->next
;cp
!=NULL
;cp
=cp
->next
)
347 uchar *p,buf[64]=".END ";
348 D(50,Fprintf(stderr,"ignoring lack of .END token\n"));
349 assert(dplast!=NULL);
350 assert(dplast->next==NULL);
351 dp=dplast->next=new_deck();
354 dp->card=make_card(&p,PARSE_CASE_TOLOWER);
355 dp->card->token=Kend;
360 if(parent
==NULL
)error(d
,NULL
,"No .END found");
361 else error(d
,NULL
,"No .ENDS found");
365 D(10, Fprintf(stderr
,"Got %i subckts, %i x's %i m's %i c's %i r's "
366 "%i l %i v %i i's\n",
367 qtysubckt
, qtyx
, qtym
, qtyc
, qtyr
, qtyl
, qtyv
, qtyi
));
371 (sizeof(node_t
)*qtynodes
) +
381 scktp
=p
=malloc(size
+1024); /* 1024 is debug pad */
384 memset(scktp
,0,size
);
385 memset(((char *)scktp
)+size
,'a',1024);
386 p
= ((char *)p
+sizeof(subckt_t
));
389 scktp
->ndefn
=qtynodes
;
390 p
= ((char *)p
+(sizeof(node_t
)*qtynodes
));
394 p
= ((char *)p
+(sizeof(m_t
)*qtym
));
398 p
= ((char *)p
+(sizeof(c_t
)*qtyc
));
402 p
= ((char *)p
+(sizeof(r_t
)*qtyr
));
406 p
= ((char *)p
+(sizeof(l_t
)*qtyl
));
410 p
= ((char *)p
+(sizeof(v_t
)*qtyv
));
414 p
= ((char *)p
+(sizeof(i_t
)*qtyi
));
418 p
= ((char *)p
+(sizeof(x_t
)*qtyx
));
421 strcpy(scktp
->name
,name
);
422 p
= ((char *)p
+strlen(name
)+2);
427 scktp
->subckt_magic
=SUBCKT_MAGIC
;
428 assert((((char *)p
)-((char *)scktp
))==size
); /* sanity check */
430 /* estimate good size for hashtable */
431 scktp
->nodes
=hash_new((qtym
*3)+(qtyx
*4),nodeclient_hash
,nodeclient_cmp
);
434 scktp
->params
=hash_new(qtyparams
,paramclient_hash
,paramclient_cmp
);
435 scktp
->lparams
=hash_new(qtylparams
,paramclient_hash
,paramclient_cmp
);
436 scktp
->parent
=parent
;
437 scktp
->cktdir
=hash_new(qtysubckt
,nodeclient_hash
,nodeclient_cmp
);
438 scktp
->global
=hash_new(qtyglobal
,nodeclient_hash
,nodeclient_cmp
);
440 /* store defn nodes, and ptrs */
441 for(i
=0,cp
=d
->card
->next
->next
;cp
!=NULL
;cp
=cp
->next
)
443 if(cp
->val
==NULL
) /* skip params on line */
445 if(find_hashtab(scktp
->nodes
,cp
->str
)!=NULL
)
446 warning(d
,cp
,"duplicate node in subckt definition");
448 payload
.flag
=PAYLOAD_null
;
450 scktp
->defn
[i
]=add_hashtab(scktp
->nodes
,cp
->str
,payload
);
455 /* do subckt params (those on the .subckt line) */
457 for(cp
=d
->card
->next
->next
;cp
!=NULL
;cp
=cp
->next
)
459 if(cp
->val
!=NULL
) /* skip nodes on line */
460 add_param(scktp
->lparams
,cp
->str
,parseval(d
,cp
,cp
->val
));
465 /* reinitialize device counters */
474 for (dp
= d
; dp
!= NULL
; dp
= dp
->next
)
477 if (dp
->card
== NULL
) continue;
479 if ((dp
->card
->token
== Ksubckt
) && (dp
!= d
))
481 subckt_t
*child
=NULL
;
482 child
=new_subckt(&dp
,scktp
,scan
);
483 payload
.data
.subckt
=child
;
484 payload
.flag
=PAYLOAD_subckt
;
485 add_hashtab(scktp
->cktdir
,child
->name
,payload
);
489 if(dp
->card
==NULL
)continue;
491 { if(dp
->card
->token
==Kends
)break; }
492 else { if(dp
->card
->token
==Kend
)break; }
501 assert(qtyx
<scktp
->nx
);
502 xp
=&(scktp
->x
[qtyx
]);
508 if(!checkvalid(dp
,2))error(d
,NULL
,"invalid subckt call");
509 for(i
=0,last
=cp
=dp
->card
->next
;cp
!=NULL
;cp
=cp
->next
,i
++)
511 if(cp
->val
!=NULL
)break; last
=cp
;
516 for(k
=0;cp
!=NULL
;cp
=cp
->next
,k
++);
522 xp
->nodes
=malloc((sizeof(node_t
)*i
)+(sizeof(paramclient_t
*)*k
));
526 xp
->locals
=(void *)((char *)(xp
->nodes
))+(sizeof(node_t
)*(i
));
529 assert(xp
->nodes
!=NULL
);
531 payload
.flag
=PAYLOAD_null
;
534 for(i
=0,cp
=dp
->card
->next
;(cp
!=NULL
)&&(cp
!=last
);cp
=cp
->next
,i
++)
536 xp
->nodes
[i
]=add_hashtab(scktp
->nodes
,cp
->str
,payload
);
537 if(0)Fprintf(stderr
,"X:%s adding node %p cp->str=%s\n",dp
->card
->str
,xp
->nodes
[i
],cp
->str
);
541 for(k
=0,cp
=cp
->next
;(cp
!=NULL
);cp
=cp
->next
,k
++)
543 { xp
->locals
[k
]=new_callparam(cp
->str
,parseval(dp
,cp
,cp
->val
)); }
544 else xp
->locals
[k
]=NULL
;
548 if(a
=='m') /* Mident d g s b model L=val W=val other_params... */
551 if(!checkvalid(dp
,8))error(d
,NULL
,"invalid mosfet card");
552 mp
=&(scktp
->m
[qtym
]);
555 payload
.flag
=PAYLOAD_null
;
560 mp
->nodes
[i
]=add_hashtab(scktp
->nodes
,cp
->str
,payload
);
564 /* hope this is n or p */
565 if((cp
->str
[0]=='n')||(cp
->str
[0]=='p'))
570 for(p
=cp
->str
;p
[0]!=0;p
++)
571 if((p
[0]=='n')||(p
[0]=='p'))
576 Fprintf(stderr
,"Couldn't determine fet type from model name %s\n",cp
->str
);
583 mp
->l
=eqn_const(1); mp
->w
=eqn_const(1);
584 mp
->as
=eqn_const(-1); mp
->ad
=eqn_const(-1);
585 mp
->ps
=eqn_const(-1); mp
->pd
=eqn_const(-1);
587 for(i
=0;cp
!=NULL
;cp
=cp
->next
,i
++)
589 if( (cp
->str
[0]=='l') && (cp
->str
[1]==0)) mp
->l
=parseval(dp
,cp
,cp
->val
);
590 if( (cp
->str
[0]=='w') && (cp
->str
[1]==0)) mp
->w
=parseval(dp
,cp
,cp
->val
);
591 if( (cp
->str
[0]=='a') && (cp
->str
[1]=='s') && (cp
->str
[2]==0) )
592 mp
->as
=parseval(dp
,cp
,cp
->val
);
593 if( (cp
->str
[0]=='a') && (cp
->str
[1]=='d') && (cp
->str
[2]==0) )
594 mp
->ad
=parseval(dp
,cp
,cp
->val
);
595 if( (cp
->str
[0]=='p') && (cp
->str
[1]=='s') && (cp
->str
[2]==0) )
596 mp
->ps
=parseval(dp
,cp
,cp
->val
);
597 if( (cp
->str
[0]=='p') && (cp
->str
[1]=='d') && (cp
->str
[2]==0) )
598 mp
->pd
=parseval(dp
,cp
,cp
->val
);
602 if(a
=='c') /* Cident node0 node1 value */
604 if(!checkvalid(dp
,4))error(d
,NULL
,"invalid capacitor card");
606 payload
.flag
=PAYLOAD_null
;
608 scktp
->c
[qtyc
].nodes
[0]=add_hashtab(scktp
->nodes
,dp
->card
->next
->str
,payload
);
609 scktp
->c
[qtyc
].nodes
[1]=add_hashtab(scktp
->nodes
,dp
->card
->next
->next
->str
,payload
);
610 cp
=dp
->card
->next
->next
->next
;
611 scktp
->c
[qtyc
].deck
=dp
;
612 scktp
->c
[qtyc
].c
=parseval(dp
,cp
,cp
->str
);
613 scktp
->c
[qtyc
].rest
=cp
;
617 if (a
== 'r') /* Rident node0 node1 value */
619 if (!checkvalid(dp
,4))error(d
,NULL
,"invalid resistor card");
621 payload
.flag
=PAYLOAD_null
;
623 scktp
->r
[qtyr
].nodes
[0] =
624 add_hashtab(scktp
->nodes
,dp
->card
->next
->str
,payload
);
625 scktp
->r
[qtyr
].nodes
[1] =
626 add_hashtab(scktp
->nodes
,dp
->card
->next
->next
->str
, payload
);
627 cp
=dp
->card
->next
->next
->next
;
628 scktp
->r
[qtyr
].deck
=dp
;
629 scktp
->r
[qtyr
].r
=parseval(dp
,cp
,cp
->str
);
630 scktp
->r
[qtyr
].rest
=cp
;
634 /* To be done: AC, pulse, and PWL sources */
636 if (a
== 'v') /* Vident node0 node1 value */
638 if (!checkvalid(dp
,4))error(d
,NULL
,"invalid voltage source card");
640 payload
.flag
=PAYLOAD_null
;
642 scktp
->v
[qtyv
].nodes
[0] =
643 add_hashtab(scktp
->nodes
,dp
->card
->next
->str
,payload
);
644 scktp
->v
[qtyv
].nodes
[1] =
645 add_hashtab(scktp
->nodes
,dp
->card
->next
->next
->str
, payload
);
646 cp
=dp
->card
->next
->next
->next
;
647 scktp
->v
[qtyv
].deck
=dp
;
648 scktp
->v
[qtyv
].v
=parseval(dp
,cp
,cp
->str
);
649 scktp
->v
[qtyv
].rest
=cp
;
653 if (a
== 'i') /* Iident node0 node1 value */
655 if (!checkvalid(dp
,4))error(d
,NULL
,"invalid current source card");
657 payload
.flag
=PAYLOAD_null
;
659 scktp
->i
[qtyi
].nodes
[0] =
660 add_hashtab(scktp
->nodes
,dp
->card
->next
->str
,payload
);
661 scktp
->i
[qtyi
].nodes
[1] =
662 add_hashtab(scktp
->nodes
,dp
->card
->next
->next
->str
, payload
);
663 cp
=dp
->card
->next
->next
->next
;
664 scktp
->i
[qtyi
].deck
=dp
;
665 scktp
->i
[qtyi
].i
=parseval(dp
,cp
,cp
->str
);
666 scktp
->i
[qtyi
].rest
=cp
;
670 if (a
== 'l') /* Lident node0 node1 value */
672 if (!checkvalid(dp
,4))error(d
,NULL
,"invalid inductor card");
674 payload
.flag
=PAYLOAD_null
;
676 scktp
->l
[qtyl
].nodes
[0] =
677 add_hashtab(scktp
->nodes
,dp
->card
->next
->str
,payload
);
678 scktp
->l
[qtyl
].nodes
[1] =
679 add_hashtab(scktp
->nodes
,dp
->card
->next
->next
->str
,payload
);
680 cp
=dp
->card
->next
->next
->next
;
681 scktp
->l
[qtyl
].deck
=dp
;
682 scktp
->l
[qtyl
].l
=parseval(dp
,cp
,cp
->str
);
683 scktp
->l
[qtyl
].rest
=cp
;
687 if(dp
->card
->token
==Kparam
)
688 for(cp
=dp
->card
->next
;cp
!=NULL
;cp
=cp
->next
)
690 if(cp
->val
==NULL
)error(dp
,cp
,"couldn't find = in .param statement");
691 add_param(scktp
->params
,cp
->str
,parseval(dp
,cp
,cp
->val
));
692 D(10, Fprintf(stderr
, "spice: adding param %s to scktp->params=%p \n",
693 cp
->str
, scktp
->params
));
696 if(dp
->card
->token
==Kscale
)
698 if(dp
->card
->val
!=NULL
)
699 scktp
->scale
=parse_float(dp
->card
->val
);
700 else error(dp
,dp
->card
,"need a value for .scale ");
703 if(dp
->card
->token
==Kmult
)
705 if(dp
->card
->val
!=NULL
)
706 scktp
->mult
=parse_float(dp
->card
->val
);
707 else error(dp
,dp
->card
,"need a value for .scale ");
710 payload
.flag
=PAYLOAD_null
;
713 if(dp
->card
->token
==Kglobal
)
714 for(cp
=dp
->card
->next
;cp
!=NULL
;cp
=cp
->next
)
715 add_hashtab(scktp
->global
,cp
->str
,payload
);
717 if(dp
->next
==NULL
) *thedeckpp
=dp
; /* ignore lack of end token */
720 *thedeckpp
=dp
; /*dp->next;*/ /* skip .end token if present */
726 static void do_subckts(subckt_t
*ckt
, scanner_t
*scan
)
736 for(i
=0;i
<ckt
->nx
;i
++)
745 for(search
=ckt
;search
!=NULL
;search
=search
->parent
)
746 if( (hcp
=find_hashtab(search
->cktdir
,nm
)) != NULL
) break;
749 { Fprintf(stderr
,"subcircuit named [%s] not found in ckt [%s]\n",
752 assert(hcp
->payload
.flag
==PAYLOAD_subckt
);
753 xp
->xp
=hcp
->payload
.data
.subckt
;
754 assert(xp
->xp
!=NULL
);
755 do_subckts(xp
->xp
,scan
); /* recursion */
762 static subckt_t
*new_ckt(deck_t
*d
, scanner_t
*scan
)
765 subckt_t
*first
=NULL
;
769 topdeck
.line
.fileindex
=0;
771 topdeck
.card
=&(topcard
[0]);
772 topcard
[0].next
=&(topcard
[1]);
774 topcard
[0].token
=Ksubckt
;
775 strcpy(topcard
[0].str
,".su"); /* max 4 bytes */
777 topcard
[1].next
=NULL
;
778 topcard
[1].token
=Kother
;
780 strcpy(topcard
[1].str
,"TOP"); /* MAX 4 bytes */
784 first
=new_subckt(&dp
,NULL
,scan
);
785 first
->subckt_magic
=SUBCKT_MAGIC
;
786 do_subckts(first
,scan
);
791 static void debug_subckts(void * dbg
, subckt_t
*ckt
, int level
)
804 fprintf(dbg
,"%s subckt %s nm=%i nc=%i nr=%i nx=%i\n",pad
,ckt
->name
,ckt
->nm
,ckt
->nc
,ckt
->nr
,ckt
->nx
);
805 for(i
=0;i
<ckt
->nm
;i
++)
807 node_t
*n
=ckt
->m
[i
].nodes
;
808 fprintf(dbg
,"%s M %s %s %s %s\n%s +",pad
,
809 n
[0]->str
,n
[1]->str
,n
[2]->str
,n
[3]->str
,pad
);
810 debug_eqn(dbg
,"l",&(ckt
->m
[i
].l
));
811 debug_eqn(dbg
,"w",&(ckt
->m
[i
].w
));
812 debug_eqn(dbg
,"as",&(ckt
->m
[i
].as
));
813 debug_eqn(dbg
,"ad",&(ckt
->m
[i
].ad
));
814 debug_eqn(dbg
,"ps",&(ckt
->m
[i
].ps
));
815 debug_eqn(dbg
,"pd",&(ckt
->m
[i
].ps
));
819 for(i
=0;i
<ckt
->nc
;i
++)
821 node_t
*n
=ckt
->c
[i
].nodes
;
822 fprintf(dbg
,"%s C %s %s ",pad
,
823 n
[0]->str
,n
[1]->str
);
824 debug_eqn(dbg
,"c",&(ckt
->c
[i
].c
));
828 for(i
=0;i
<ckt
->nr
;i
++)
830 node_t
*n
=ckt
->r
[i
].nodes
;
831 fprintf(dbg
,"%s R %s %s ",pad
,
832 n
[0]->str
,n
[1]->str
);
833 debug_eqn(dbg
,"r",&(ckt
->r
[i
].r
));
838 for(i
=0;i
<ckt
->nx
;i
++)
840 fprintf(dbg
,"%s X %s : %p, %i nodes\n",pad
,ckt
->x
[i
].xp
->name
,ckt
->x
[i
].nodes
,ckt
->x
[i
].nn
);
841 debug_subckts(dbg
,ckt
->x
[i
].xp
,level
+1); /* recursion */
852 /**********************************************************************/
853 /***************** PASS 3: operations on heirarchy *******************/
854 /******************************-- flattening --- **********************/
859 /* a couple of different lookup functions for equations and parameters
860 with slightly different semantics
862 lookup_params is for TERMINAL equations that need multipliers
863 lookup_params_nomult is for equations in '.param' statements
864 lookup_parents_call_eqns is for equations in subckt calls
865 ie: Xdddd blah blah v='eqn blah' ...
868 static eqn_t
lookup_parents_call_eqns(stack_t
*s
, eqn_t
*ep
);
869 static eqn_t
lookup_params_nomult(stack_t
*s
, eqn_t
*ep
);
870 static eqn_t
lookup_params(stack_t
*s
, eqn_t
*ep
, float m
);
874 static void spice_recurse_subckts(spice_t
*spice
, subckt_t
*ckt
, stack_t
*parent
, void (*process
)(stack_t
*s
, int flag
, void *data
),void *data
)
882 if(parent
==NULL
) { s
.level
=0; s
.parent
=NULL
; s
.ckt
=ckt
; s
.call
=NULL
; s
.top
=&s
; }
883 else { s
.level
=parent
->level
+1; s
.parent
=parent
; s
.ckt
=ckt
; s
.call
=NULL
; s
.top
=s
.parent
->top
; }
887 for(i
=0;i
<ckt
->nx
;i
++)
888 { s
.call
=ckt
->x
+i
; spice_recurse_subckts(spice
,s
.call
->xp
,&s
,process
,data
); } /* recursion */
896 static char * do_name(stack_t
*s
, char *str
)
898 static char buf
[1024*63];
901 int l
,q
=0,sizebuf
=sizeof(buf
);
904 D(10,Fprintf(stderr
,"doname: [%s] ",str
));
915 for(sp
=s
;sp
!=NULL
;sp
=sp
->parent
)
917 if(sp
->call
==NULL
)continue;
918 assert(sp
->call
->deck
!=NULL
);
919 assert(sp
->call
->deck
->card
!=NULL
);
920 c
=sp
->call
->deck
->card
->str
;
928 D(10,Fprintf(stderr
,"(%s)\n",bp
));
937 static eqn_t
lookup_params(stack_t
*s
, eqn_t
*ep
, float m
)
946 static paramclient_t
* find_param_intable(hash_t
*h
, char *str
)
949 paramclient_t
*pc
,*tofind
;
950 /* note to self: this trickery is dependent on hash.c doing the right thing which it does */
951 tofind
=(void *)(str
-sizeof(paramload_t
));
954 D(30,Fprintf(stderr
,"looking for %s in table %p l=%i ",str
,h
,l
));
955 pc
=hash_find(h
,tofind
,sizeof(paramload_t
)+l
);
956 D(30,Fprintf(stderr
," hash_find=%p\n",pc
));
961 /* local (bottom) takes precedence over top (global) */
962 static paramclient_t
* find_param_bot(stack_t
*s
, char *str
)
965 paramclient_t
*r
=NULL
,*toret
=NULL
;
969 for(sp
=s
;sp
!=NULL
;sp
=sp
->parent
)
974 r
=find_param_intable(ckt
->lparams
,str
);
975 if(toret
==NULL
)toret
=r
;
976 r
=find_param_intable(ckt
->params
,str
);
977 if(toret
==NULL
)toret
=r
;
983 /* global (top) takes precidence over bottom (local) */
984 static paramclient_t
* find_param_top(stack_t
*s
, char *str
)
986 paramclient_t
*r
=NULL
,*toret
=NULL
;
990 for(sp
=s
;sp
!=NULL
;sp
=sp
->parent
)
995 r
=find_param_intable(ckt
->lparams
,str
);
997 r
=find_param_intable(ckt
->params
,str
);
1007 static eqn_litref_t
lookup_function(plookup_t
*user
, char *str
)
1009 paramlookup_t
*me
=user
->user
;
1011 eqn_litref_t index
=eqn_litref_INIT
;
1014 if(1)r
=find_param_bot(me
->sp
,str
);
1015 else r
=find_param_top(me
->sp
,str
);
1018 /* this is not a renameable local parameter */
1019 if(r
->payload
.patch_call
==NULL
)
1021 /* we want to use this parameter, but don't have a global entry yet */
1022 if(r
->payload
.global_i
<0)
1024 /* todo: lookup this param=equation now, in case it has dependencies */
1026 hname
=do_name(me
->sp
,str
);
1027 D(5,Fprintf(stderr
,"Lookup function: Adding eqn (%s) (%s)\n",str
,hname
));
1028 D(5,debug_eqn(stderr
,str
,&(r
->payload
.eqn
)));
1029 D(5,Fprintf(stderr
,"\n"));
1030 eq
=lookup_params_nomult(me
->sp
,&(r
->payload
.eqn
));
1031 r
->payload
.global_i
=eqnl_add(&(me
->nl
->eqnl
),eq
,hname
);
1033 index
=r
->payload
.global_i
;
1035 else /* we renamed this parameter, follow the indirection, make heir. name */
1036 { /* also note we probably want to call lookup params now
1037 using parent's context for subckt call
1039 D(50,Fprintf(stderr
,"Lookup rename: %s\n",str
));
1040 D(50,debug_eqn(stderr
," eqn ",&(r
->payload
.patch_call
->eqn
)));
1041 D(50,Fprintf(stderr
,"\n"));
1042 if(r
->payload
.global_i
<0)
1044 hname
=do_name(me
->sp
,str
);
1045 D(5,Fprintf(stderr
,"Lookup function rename: Adding eqn (%s) (%s)\n",str
,hname
));
1046 D(5,debug_eqn(stderr
," eqn ",&(r
->payload
.patch_call
->eqn
)));
1047 r
->payload
.global_i
=eqnl_add(&(me
->nl
->eqnl
),
1048 lookup_parents_call_eqns(me
->sp
, &(r
->payload
.patch_call
->eqn
)),
1051 index
=r
->payload
.global_i
;
1054 else /* an undefined reference, may be a sweep parameter, to be loaded from tracefile */
1056 index
=eqnl_find(&(me
->nl
->eqnl
),str
);
1059 D(3,Fprintf(stderr
,"Netlist_sp: assuming %s is global sweep parameter\n",str
));
1060 index
= eqnl_add(&(me
->nl
->eqnl
),eqn_undefined(),str
);
1062 else D(3,Fprintf(stderr
,"Netlist_sp: assume %s is a global parameter, not local\n",str
));
1068 static eqn_t
lookup_parents_call_eqns(stack_t
*s
, eqn_t
*ep
)
1080 plu
.lookup
=lookup_function
;
1082 D(10,debug_eqn(stderr
,"lookup parents:", &v
));
1083 D(10,Fprintf(stderr
,"\n"));
1084 r
=eqntok_depend(v
.eqn
,&plu
);
1085 if(r
)D(1,Fprintf(stderr
,"couldn't find a parameter in equation\n"));
1087 else D(1,Fprintf(stderr
,"lookup parents eqn called, but we are at the top level\n"));
1088 assert(s
->parent
!=NULL
);
1092 static eqn_t
lookup_params_nomult(stack_t
*s
, eqn_t
*ep
)
1101 plu
.lookup
=lookup_function
;
1106 r
=eqntok_depend(v
.eqn
,&plu
);
1108 if(r
)D(1,Fprintf(stderr
,"couldn't find a parameter in equation\n"));
1115 static eqn_t
lookup_params(stack_t
*s
, eqn_t
*ep
, float m
)
1124 plu
.lookup
=lookup_function
;
1126 v
=eqn_copy_m(*ep
,m
);
1129 r
=eqntok_depend(v
.eqn
,&plu
);
1131 if(r
)D(1,Fprintf(stderr
,"couldn't find a parameter in equation\n"));
1139 static void count_stuff(stack_t
*s
, int flag
, void *data
)
1143 nl
->e
[DEVT_FET
].qcount
+=s
->ckt
->nm
;
1144 nl
->e
[DEVT_CAP
].qcount
+=s
->ckt
->nc
;
1151 static void build_stuff(stack_t
*s
, int flag
, void *data
)
1157 hash_t
*h
,*globals
,*h1
;
1159 paramclient_t
*pc
,*findpc
;
1160 scanner_t
*scan
=s
->scan
;
1161 if(flag
)return; /* preorder */
1164 globals
=s
->top
->ckt
->global
;
1167 D(40,Fprintf(stderr
,"processing stack %p: s->top=%p s->parent=%p s->ckt=%p\n",s
,s
->top
,s
->parent
,s
->ckt
));
1169 /* first assign parent payloads to all the nodes in nodedir */
1172 call
=s
->parent
->call
;
1175 if(call
->nn
!=s
->ckt
->ndefn
)
1176 error(call
->deck
,call
->rest
,"Definition does not match use");
1178 q
=minimum(call
->nn
,s
->ckt
->ndefn
);
1182 assert(call
->nodes
[i
]!=NULL
);
1183 assert(call
->nodes
[i
]->payload
.flag
==PAYLOAD_gnptr
);
1184 s
->ckt
->defn
[i
]->payload
.data
=call
->nodes
[i
]->payload
.data
;
1185 s
->ckt
->defn
[i
]->payload
.flag
=PAYLOAD_parent
;
1189 /* lookup subckt call's and map to local params */
1192 hash_forall(h1
,i
,bp
) /* init patch ptrs to Null (so any previous invokation won't be used) */
1194 pc
=hash_bin2user(bp
); pc
->payload
.patch_call
=NULL
; pc
->payload
.global_i
=-1;
1195 D(30,Fprintf(stderr
,"considering hash table entry %i %s len=%i\n",i
,pc
->str
,bp
->size
-sizeof(paramload_t
)));
1198 /* for each param in the x call line, patch local param if found */
1199 for(i
=0;i
<call
->nl
;i
++)
1202 callp
=call
->locals
[i
];
1203 if(callp
==NULL
)continue;
1205 /* hackish hash_find: we pass a bogus object, who's string is at same location */
1206 findpc
=hash_find(h1
,callp
->str
-sizeof(paramload_t
),strlen(callp
->str
)+sizeof(paramload_t
)+1);
1208 if(findpc
!=NULL
) /* we link to this subckt eqn call */
1209 findpc
->payload
.patch_call
=callp
;
1211 D(2,Fprintf(stderr
,"subckt call, specified parameter [%s] not found\n",callp
->str
));
1213 D(5,Fprintf(stderr
,"patching call %s",callp
->str
));
1214 if(findpc
!=NULL
)D(5,debug_eqn(stderr
," orig ",&(findpc
->payload
.eqn
)));
1215 D(5,debug_eqn(stderr
," patch ",&(callp
->eqn
)));
1216 D(5,Fprintf(stderr
,"\n"));
1220 /* if parent is NULL, then we are top level, specially create/process global nodes first */
1223 assert(s
->top
->ckt
==s
->ckt
);
1225 FORALL_HASH(globals
,i
,bp
)
1228 n
=hash_bin2user(bp
);
1229 n
->payload
.flag
=PAYLOAD_gnptr
;
1230 /* note to self: must use terminal indices, because node table may be reallocated as it grows */
1231 flatname
=do_name(s
,n
->str
);
1232 n
->payload
.data
.t
=netlist_node(nl
,flatname
,(void*)n
);
1237 /* then assign new node payload to all the rest, doing global checks */
1242 n
=hash_bin2user(bp
);
1243 if((n
->payload
.flag
==PAYLOAD_gnptr
)||(n
->payload
.flag
==PAYLOAD_parent
)||(n
->payload
.flag
==PAYLOAD_null
))
1247 gbn
=find_hashtab(globals
,n
->str
); /* i hope this search is efficient */
1250 if(n
->payload
.flag
!=PAYLOAD_parent
)
1251 n
->payload
.data
=gbn
->payload
.data
;
1255 if(n
->payload
.flag
!=PAYLOAD_parent
)
1258 flatname
=do_name(s
,n
->str
);
1259 n
->payload
.data
.t
=netlist_node(nl
,flatname
,(void *)n
);
1262 n
->payload
.flag
=PAYLOAD_gnptr
; /* set both types to gnptr */
1266 /* now we have ptrs to every gn_t in this subckt reference, so we can process elements */
1268 for(i
=0;i
<s
->ckt
->nc
;i
++) /* FOR EACH capacitor */
1275 np
[j
]= s
->ckt
->c
[i
].nodes
[j
]->payload
.data
.t
;
1276 devinp
.spice_cap
=cp
=&(s
->ckt
->c
[i
]);
1277 dcp
=list_data(&(nl
->e
[DEVT_CAP
].l
),netlist_newdev_fromnode(nl
,DEVT_CAP
,devinp
,np
));
1278 dcp
->v
[DEVCAP_c
]=lookup_params(s
,&(cp
->c
),s
->ckt
->mult
);
1281 for(i
=0;i
<s
->ckt
->nm
;i
++) /* FOR EACH fet */
1287 int spiceorder
[4]={INDEX_SOURCE
, INDEX_DRAIN
, INDEX_GATE
, INDEX_BULK
};
1288 int netlistorder
[4]= {DEVFET_S
, DEVFET_D
, DEVFET_G
, DEVFET_B
};
1291 np
[netlistorder
[j
]]=s
->ckt
->m
[i
].nodes
[spiceorder
[j
]]->payload
.data
.t
;
1292 devinp
.spice_fet
=cp
=&(s
->ckt
->m
[i
]);
1293 dfp
=list_data(&(nl
->e
[DEVT_FET
].l
),netlist_newdev_fromnode(nl
,DEVT_FET
,devinp
,np
));
1295 for(j
=0;j
<DEVFET_V
;j
++)
1296 dfp
->v
[j
]=eqn_const(0);
1301 { dfp
->type
=DEVFET_pmos
; }
1304 { dfp
->type
=DEVFET_nmos
; }
1310 static int mosfet_i
=0;
1311 Fprintf(stderr
,"processing mosfet %i \n",++mosfet_i
);
1315 dfp
->v
[DEVFET_w
] =lookup_params(s
,&(cp
->w
),s
->ckt
->scale
);
1316 dfp
->v
[DEVFET_l
] =lookup_params(s
,&(cp
->l
),s
->ckt
->scale
);
1317 dfp
->v
[DEVFET_as
]=lookup_params(s
,&(cp
->as
),(s
->ckt
->scale
)*(s
->ckt
->scale
));
1318 dfp
->v
[DEVFET_ad
]=lookup_params(s
,&(cp
->ad
),(s
->ckt
->scale
)*(s
->ckt
->scale
));
1319 dfp
->v
[DEVFET_ps
]=lookup_params(s
,&(cp
->ps
),s
->ckt
->scale
);
1320 dfp
->v
[DEVFET_pd
]=lookup_params(s
,&(cp
->pd
),s
->ckt
->scale
);
1323 for(i
=0;i
<s
->ckt
->nx
;i
++) /* FOR EACH SUBCKT CALL */
1327 for(j
=0;j
<xp
->nl
;j
++)
1328 if(xp
->locals
[j
]!=NULL
)
1330 /* we copy the actual equation at use instantiation time
1331 via lookup_parent...
1341 return ; /* recurse on subckt calls */
1347 static void free_ckt(subckt_t
*ckt
)
1355 if(ckt
==NULL
)return;
1358 FORALL_HASH(tab
,i
,bp
)
1360 p
=hash_bin2user(bp
);
1361 tofree
=p
->payload
.data
.subckt
;
1362 p
->payload
.data
.subckt
=NULL
;
1366 for(i
=0;i
<ckt
->nx
;i
++)
1370 for(j
=0;j
<ckt
->x
[i
].nl
;j
++)
1371 if(ckt
->x
[i
].locals
[j
]!=NULL
)
1372 free(ckt
->x
[i
].locals
[j
]);
1374 if(ckt
->x
[i
].nodes
!=NULL
)
1375 free(ckt
->x
[i
].nodes
); /* this frees locals also (combined allocation) */
1377 /* note: equations have their own memory allocation system
1378 so NEVER free an eqntoken_t *
1381 hash_free(ckt
->cktdir
);
1382 hash_free(ckt
->nodes
);
1383 hash_free(ckt
->params
);
1384 hash_free(ckt
->lparams
);
1385 hash_free(ckt
->global
);
1391 void spice_count(netlist_t
*nl
)
1393 spice_t
*sp
=nl
->input
.spice
;
1395 spice_recurse_subckts(sp
,sp
->ckt
,NULL
,&count_stuff
,(void *)nl
);
1400 void spice_build(netlist_t
*nl
)
1402 spice_t
*sp
=nl
->input
.spice
;
1403 netlist_eqn_begin(nl
);
1404 spice_recurse_subckts(sp
,sp
->ckt
,NULL
,&build_stuff
,(void *)nl
);
1405 netlist_eqn_end(nl
);
1409 void spice_release(spice_t
*sp
)
1414 eqn_mem_free(sp
->eqn_mem
);
1419 spice_t
*spice_new(scanner_t
*scan
)
1422 p
=malloc(sizeof(spice_t
));
1424 memset(p
,0,sizeof(spice_t
));
1425 p
->spice_magic
=SPICE_MAGIC
;
1427 p
->eqn_mem
=eqn_mem_new();
1428 eqn_mem_push(p
->eqn_mem
);
1429 scanner_sect_new(p
->scan
,scanner_def_spice(),spice_tokens
);
1430 scanner_parse_all(p
->scan
);
1431 D(6,scanner_debug_all(p
->scan
,stderr
));
1432 p
->deck
=p
->scan
->sectp
->dhead
;
1433 scanner_sect_release(p
->scan
);
1436 { p
->ckt
=new_ckt(p
->deck
,p
->scan
); }
1437 else { p
->ckt
=NULL
; }
1439 if(eqn_mem_pop()!=p
->eqn_mem
)
1448 void spice_debug(void * dbg_fp
, spice_t
*sp
)
1451 fprintf(dbg
,"debugging output for spice circuit file \n");
1453 debug_subckts(dbg
,sp
->ckt
, 0);