Update at Fri Feb 9 12:38:17 EST 2018 by tim
[xcircuit.git] / spiceparser / netlist_lib.c
blobfb8fbf827ba7dcd60f4cc8e60ff6a88bfca56293
1 /********************
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
20 ******************/
21 /* netlist_lib.c, routines for building a library of netlists
22 Conrad Ziesler
27 /* the goal here is to be able to read/write a file composed of segments
28 each segment has a header describing
30 1. reference name
31 2. equation parameters to iterate through
32 3. logic function
33 4. output ports, output tokens
34 5. input ports, input tokens
35 6. spice format netlist block to be parsed by netlist_spice
37 we then maintain this library of each version of each gate
39 in addition we would like to procedurally add gates to our library.
40 (ie. automatically generate library from templates)
44 #include <stdio.h>
45 #include <ctype.h>
46 #include <math.h>
47 #include "debug.h"
48 #include "netlist_lib.h"
49 #include "netlist_dev.h"
51 int __debug_nlib__=1;
53 #ifndef STRIP_DEBUGGING
54 #define D(level,a) do { if(__debug_nlib__>(level)) a; } while(0)
55 #else
56 #define D(level,a)
57 #endif
61 /* add a new param, to a db */
62 int nlib_add_pm(nlib_t *nlib, int dbindex, char *str, float min, float max, int qty)
64 nlibpm_t template;
65 nlibdb_t *db;
66 int index;
67 template.min=min;
68 template.max=max;
69 template.qty=qty;
70 db=list_data(&(nlib->db),dbindex);
71 if(db==NULL)assert(0);
72 if(str!=NULL)
73 template.index=eqnl_find(&(db->nl->eqnl),str);
74 else template.index=-1;
76 if(template.index<0)
77 { fprintf(stderr,"couldn't find parameter %s used in netlist, assuming ignoring\n",str); return -1; }
79 index=list_add(&(db->params),&template);
80 return index;
83 /* add a new io definition to a db */
84 int nlib_add_io(nlib_t *nlib, int dbindex, nlibiol_t *io, int tokens, int nodes, int dig, char **names)
86 int index,ni;
87 int i;
88 nlibio_t *p,template;
89 nlibdb_t *db;
90 db=list_data(&(nlib->db),dbindex);
91 assert(db!=NULL);
93 memset(&template,0,sizeof(template));
94 index=list_add(&(io->iol),&template);
95 p=list_data(&(io->iol),index);
97 assert((nodes<NLIBIO_MAXNODES) && "Compile time node limit exceeded, change and recompile");
99 io->qtokens= (io->qtokens>0)?io->qtokens*tokens : tokens;
100 p->tokens=tokens;
101 p->qnodes=nodes;
102 p->digitize=dig;
103 for(i=0;i<nodes;i++)
105 ni=names_check(db->nl->names,names[i]);
106 if(ni<0)
108 fprintf(stderr,"NLIB: could not find i/o node %s in circuit\n",names[i]);
109 assert(0);
111 p->nodes[i]=ni;
113 return index;
117 static void nlib_init_io(nlibiol_t *io)
119 io->qtokens=0;
120 list_init(&(io->iol),sizeof(nlibio_t),LIST_UNITMODE);
124 int nlib_db_netlist(nlib_t *nlib, int index, netlist_t *nl)
126 nlibdb_t *db;
127 db=list_data(&(nlib->db),index);
128 assert(db!=NULL);
129 db->nl=nl;
130 return index;
135 /* makes a new db */
136 int nlib_new_db(nlib_t *nlib, char *str)
138 int index;
139 nlibdb_t template,*db;
141 memset(&template,0,sizeof(template));
142 index=list_add(&(nlib->db),&template);
143 names_add(nlib->dbref,index,str);
144 db=list_data(&(nlib->db),index);
145 list_init(&(db->params),sizeof(nlibpm_t),LIST_DEFMODE);
146 nlib_init_io(&(db->in));
147 nlib_init_io(&(db->out));
148 list_init(&(db->refnodes),sizeof(nlibrefnode_t),LIST_UNITMODE);
149 return index;
153 nlibfref_t nlib_func_lookup(nlib_t *nlib, char *str)
155 nlibfref_t f;
156 f.index=names_check(nlib->funcnames,str);
157 return f;
160 /* fixme: should look up name of function in nlib->functions and
161 use that index
163 int nlib_db_func(nlib_t *nlib, int index, char *str)
165 nlibdb_t *db;
166 db=list_data(&(nlib->db),index);
167 assert(db!=NULL);
168 db->map=nlib_func_lookup(nlib,str);
169 return 0;
172 /* makes empty function of specified variables */
173 nlibfunc_t *nlib_new_func(nlib_t *nlib, char *str, int qin, int qout,int p_delay, int p_offset, int p_cycle)
175 int l;
176 nlibfunc_t *fp;
177 fp=malloc((l=sizeof(nlibfunc_t)+(sizeof(int)*qin)));
178 assert(fp!=NULL);
179 memset(fp,0,l);
180 fp->qin=qin;
181 fp->qout=qout;
182 fp->p_delay=p_delay;
183 fp->p_offset=p_offset;
184 fp->p_cycle=p_cycle;
185 l=list_add(&(nlib->funcs),&fp);
186 names_add(nlib->funcnames,l,str);
187 return fp;
189 /* specify one mapping */
190 void nlib_func_addmap(nlib_t *nlib, nlibfunc_t *fp, int in, int out)
192 assert(in<fp->qin);
193 assert(out<fp->qout);
194 assert(in>=0);
195 assert(out>=0);
196 fp->map[in]=out;
201 /* inits a nlib, call before any action on nlib */
202 int nlib_init(nlib_t *nlib)
204 list_init(&(nlib->db),sizeof(nlibdb_t),LIST_DEFMODE);
205 nlib->dbref=names_new();
206 list_init(&(nlib->iodefs),sizeof(nlibiodef_t), LIST_DEFMODE);
207 eqnl_init(&(nlib->eqnl));
208 list_init(&(nlib->funcs), sizeof(nlibfunc_t *), LIST_DEFMODE); /* list of pointers */
209 list_init(&(nlib->flatdb), sizeof(nlibflatdb_t), LIST_DEFMODE);
210 nlib->funcnames=names_new();
211 nlib->qvref=0;
212 nlib->vref=names_new();
213 nlib->flags=NULL;
214 nlib->eqn_mem=eqn_mem_new();
215 return 0;
218 void nlib_release_flatdb(nlib_t *nlib)
220 int i;
221 nlibflatdb_t *fdbp;
222 list_iterate(&(nlib->flatdb),i,fdbp)
224 list_empty(&(fdbp->uservals));
225 if(fdbp->pvals!=NULL)free(fdbp->pvals);
226 fdbp->pvals=NULL;
228 list_empty(&(nlib->flatdb));
229 bitlist_free(nlib->flags);
230 nlib->flags=NULL;
233 void nlib_release_io(nlib_t *nlib, nlibiol_t *io)
235 list_empty(&(io->iol));
238 void nlib_release_db(nlib_t *nlib)
240 int i;
241 nlibdb_t *dbp;
243 list_iterate(&(nlib->db),i,dbp)
245 if(dbp->pvals!=NULL)free(dbp->pvals);
246 dbp->pvals=NULL;
247 list_empty(&(dbp->refnodes));
248 list_empty(&(dbp->params));
249 nlib_release_io(nlib,&(dbp->in));
250 nlib_release_io(nlib,&(dbp->out));
251 netlist_free(dbp->nl);
252 dbp->nl=NULL;
254 list_empty(&(nlib->db));
255 names_free(nlib->dbref);
256 nlib->dbref=NULL;
259 void nlib_release_funcs(nlib_t *nlib)
261 int i;
262 void **p;
263 names_free(nlib->funcnames);
264 nlib->funcnames=NULL;
265 list_iterate(&(nlib->funcs),i,p)
267 if((*p)!=NULL)
268 free((*p));
270 list_empty(&(nlib->funcs));
273 void nlib_release_refs(nlib_t *nlib)
275 names_free(nlib->vref);
276 nlib->vref=NULL;
277 nlib->qvref=0;
280 void nlib_release_iodefs(nlib_t *nlib)
282 int i;
283 nlibiodef_t *p;
284 list_iterate(&(nlib->iodefs),i,p)
286 if(p->encoding!=NULL)free(p->encoding);
287 p->encoding=NULL;
289 list_empty(&(nlib->iodefs));
292 /* frees all data in nlib */
293 void nlib_release(nlib_t *nlib)
295 nlib_release_flatdb(nlib);
296 nlib_release_db(nlib);
297 nlib_release_refs(nlib);
298 nlib_release_funcs(nlib);
299 eqnl_free(&(nlib->eqnl));
300 nlib_release_iodefs(nlib);
301 eqn_mem_free(nlib->eqn_mem);
302 nlib->eqn_mem=NULL;
307 /* post processing of db structure */
308 int nlib_db_fixup(nlib_t *nlib, nlibdb_t *db)
310 int i,q,j;
311 nlibpm_t *p;
312 nlibrefnode_t *rnp;
313 int l=list_qty(&(db->params));
314 db->pvals=malloc((sizeof(float)*l));
315 memset(db->pvals,0,sizeof(float)*l);
316 list_shrink(&(db->params));
317 list_shrink(&(db->refnodes));
319 list_iterate(&(db->params),i,p)
321 if(0)fprintf(stderr,"nlib_db_fixup: trying to define eqn: %i->%s (%p)\n",p->index,eqnl_lookup(&(db->nl->eqnl),p->index),db->pvals+i);
322 eqnl_define(&(db->nl->eqnl),p->index,db->pvals+i);
324 q=eqnl_qty(&(db->nl->eqnl));
326 /* setup equations in our reference nodes */
327 list_iterate(&(db->refnodes),i,rnp)
329 for(j=0;j<RTqty;j++)
330 eqnl_depend(&(nlib->eqnl), rnp->skew[j]);
333 return 0;
337 /* step through library,
338 (in terms of param qty's, in order)
339 substitute in, and call client process function
340 for each instance of each cell
342 void nlib_process(nlib_process_t *user, int screened)
344 int i,j,k,lib_index;
345 nlib_t *nlib=user->nlib;
346 nlibdb_t *dbp;
347 nlibpm_t *dbpm;
348 int li[64]; /* max 64 parameters */
349 int lq[64];
350 int qp=0;
352 assert(nlib!=NULL);
353 memset(li,0,sizeof(li));
354 memset(lq,0,sizeof(lq));
355 lib_index=0;
356 list_iterate(&(nlib->db),i,dbp)
358 qp=0;
359 list_iterate(&(dbp->params),j,dbpm)
361 lq[j]=dbpm->qty;
362 li[j]=0;
363 dbp->pvals[j]= dbpm->min;
364 qp++;
365 if(qp>=64)assert(0);
367 k=0;
368 fprintf(stderr,"\n\nstarting db index %i\n",i);
369 while(1)
371 if(0)
373 fprintf(stderr,"iteration:");
374 for(j=0;j<qp;j++)
375 fprintf(stderr," (%i,%i)",li[j]+1,lq[j]);
376 fprintf(stderr,"\n");
379 if(nlib_isdisabled(nlib,lib_index)!=1)
381 /* eval each parameters */
382 for(j=0;j<qp;j++)
384 dbpm=list_data(&(dbp->params),j);
386 dbp->pvals[j]=dbpm->min+
387 li[j]*(dbpm->max-dbpm->min)/dbpm->qty;
389 if(0)fprintf(stderr,"setting %i (%p) val[%i]=%g\n",j,dbp->pvals+j,dbpm->index,dbp->pvals[j]);
392 user->nl=dbp->nl;
393 user->lib_index=lib_index;
394 user->db_index=i;
395 user->process(user);
397 lib_index++;
398 /* increment loop */
399 for(j=0;j<qp;j++)
400 if(li[j]<(lq[j]-1))
402 li[j]++;
403 for(j--;j>=0;j--) /* roll over rest of indices */
404 li[j]=0;
405 break;
407 if(j==qp)break;
414 static void nlib_fixup_process(nlib_process_t *user)
416 int *ip=user->user;
417 ip[0]++;
420 void nlib_fixup(nlib_t *nlib)
422 int count=0;
423 nlib_process_t pr;
425 eqnl_autodepend(&(nlib->eqnl));
426 eqnl_evaldep(&(nlib->eqnl));
427 if(nlib->flags!=NULL) /* in case we were called multiple times */
428 bitlist_free(nlib->flags);
429 nlib->flags=NULL;
430 if(0)
432 pr.user=&count;
433 pr.nlib=nlib;
434 pr.process=nlib_fixup_process;
435 nlib_process(&pr,0);
436 nlib->flags=bitlist_new(count+1);
440 /* this does the dirty work of updating configurable db netlists from flat db */
441 void nlib_doflat(nlib_t *nlib, int index)
443 nlibflatdb_t *fdb;
444 nlibdb_t *db;
445 assert(nlib!=NULL);
446 fdb=list_data(&(nlib->flatdb),index);
447 assert(fdb!=NULL);
448 db=list_data(&(nlib->db),fdb->db_index);
449 assert(db!=NULL);
450 if(fdb->pvals!=NULL)
451 memcpy(db->pvals,fdb->pvals,sizeof(float)*fdb->qvals);
452 else
453 assert(fdb->qvals==0);
456 /* call this from user process for each gate we want to keep */
457 void *nlib_flat(nlib_process_t *user, int s_uservals, int q_uservals)
459 nlib_t *nlib;
460 nlibdb_t *db;
461 int index;
462 nlibflatdb_t *fdb;
464 assert(user!=NULL);
465 nlib=user->nlib;
466 assert(nlib!=NULL);
467 index=list_nextz(&(nlib->flatdb));
468 fdb=list_data(&(nlib->flatdb),index);
469 fdb->lib_index=user->lib_index;
470 fdb->db_index=user->db_index;
471 db=list_data(&(nlib->db),fdb->db_index);
472 assert(db!=NULL);
473 fdb->qvals=list_qty(&(db->params));
475 list_init(&(fdb->uservals),s_uservals,LIST_UNITMODE);
476 list_hint(&(fdb->uservals),q_uservals);
478 if(fdb->qvals>0)
480 fdb->pvals=malloc(sizeof(float)*fdb->qvals);
481 assert(fdb->pvals!=NULL);
482 memcpy(fdb->pvals,db->pvals,sizeof(float)*fdb->qvals);
484 else fdb->pvals=NULL;
486 return list_block_next(&(fdb->uservals),q_uservals);
490 void nlib_disable(nlib_t *nlib, int index)
492 if(nlib->flags!=NULL)
493 bitlist_set(nlib->flags,index);
496 int nlib_isdisabled(nlib_t *nlib, int index)
498 if(nlib->flags!=NULL)
499 return bitlist_test(nlib->flags,index);
500 return -1;
504 static void nlib_o_spice_subckt_(nlib_t *nlib, int db_index, int lib_index, void * of_fp)
506 FILE *of=of_fp;
507 nlibdb_t *dbp;
508 nlibrefnode_t *rnp;
509 nlibio_t *iop;
510 int i,j;
511 int z_index=1;
512 int n_start=1;
514 dbp=list_data(&(nlib->db),db_index);
515 assert(dbp!=NULL);
516 fprintf(of,"\n.subckt sc%i", lib_index);
518 /* reference nodes */
519 list_iterate(&(dbp->refnodes),i,rnp)
520 fprintf(of," rn%i",rnp->vrefi);
522 /* input nodes */
523 list_iterate(&(dbp->in.iol),i,iop)
524 for(j=0;j<iop->qnodes;j++)
525 fprintf(of," %i",iop->nodes[j]+n_start);
527 /* output nodes */
528 list_iterate(&(dbp->out.iol),i,iop)
529 for(j=0;j<iop->qnodes;j++)
530 fprintf(of," on%i_%i",i,j);
532 fprintf(of,"\n");
534 /* call netlist_o_spice to output subckt netlist */
535 netlist_o_spice(of, dbp->nl, n_start);
537 /* add additional circuitry for output buffers */
538 list_iterate(&(dbp->out.iol),i,iop)
539 for(j=0;j<iop->qnodes;j++)
540 fprintf(of,"Ez%i on%i_%i 0 VCVS PWL(1) %i 0 -10v,-10v 10v,10v\n",z_index++,i,j, iop->nodes[j]+n_start);
542 /* add aditional circuitry for delay and rc of references */
544 list_iterate(&(dbp->refnodes),i,rnp)
546 float f[4]={0.0, 0.0, 0.0, 0.0 };
547 int ud[4];
548 assert(RTqty<=3);
549 for(j=0;j<RTqty;j++)
551 ud[j]=(eqn_is_undefined(rnp->skew[j])!=0);
552 f[j]=eqnl_eval(&(nlib->eqnl),rnp->skew[j]);
555 if( ud[RTdelay] && ud[RTrseries] )
556 fprintf(of,"rz%i rn%i %i 1e-3\n", z_index++,rnp->vrefi,rnp->devnodei+n_start);
558 else if (!ud[RTdelay] && ud[RTrseries])
559 fprintf(of,"Ez%i %i 0 VCVS DELAY rn%i 0 TD=%g SCALE=1\n",
560 z_index++, rnp->devnodei+n_start, rnp->vrefi, f[RTdelay]
563 else if ( ud[RTdelay] && !ud[RTrseries])
564 fprintf(of,"rz%i rn%i %i %g\n",z_index++, rnp->vrefi, rnp->devnodei+n_start, f[RTrseries]);
566 else
568 fprintf(of,"dz%i rn%i rn%ia %g\nrz%i rn%ia %i %g\n",
569 z_index, rnp->vrefi, rnp->vrefi, f[RTdelay],
570 z_index+1, rnp->vrefi, rnp->devnodei+n_start, f[RTrseries]
572 z_index+=2;
574 if(!ud[RTcshunt])
575 fprintf(of,"cz%i %i 0 %g\n",z_index++,rnp->devnodei+n_start, f[RTcshunt] );
577 fprintf(of,".ends sc%i\n",lib_index);
582 void nlib_o_spice_refs(nlib_t *nlib, void * of_fp)
584 FILE *of=of_fp;
585 int i;
586 char *p;
587 for(i=0;(p=names_lookup(nlib->vref,i))!=NULL;i++)
589 fprintf(of,"*nref %s\n",p);
594 static void nlib_o_spice_subckt_process(nlib_process_t *user)
595 { nlib_o_spice_subckt_(user->nlib,user->db_index,user->lib_index, user->user); }
597 void nlib_o_spice_subckts(nlib_t *nlib, void * of_fp)
599 FILE *of=of_fp;
600 /* if we built a flat db, use it */
601 if(list_qty(&(nlib->flatdb))>0)
603 int i,j;
604 nlibflatdb_t *fdb;
605 float *dp;
607 list_iterate(&(nlib->flatdb),i,fdb)
609 /* print header with some usefull info */
610 fprintf(of,"****** index=%i db_index=%i lib_index=%i ***",
611 i,fdb->db_index,fdb->lib_index
613 list_iterate(&(fdb->uservals),j,dp)
614 fprintf(of,"%s%g",((j%5)==0)?"\n*** ":" ",*dp);
615 fprintf(of,"\n");
617 nlib_doflat(nlib,i); /* update the netlist */
618 nlib_o_spice_subckt_(nlib,fdb->db_index,fdb->lib_index, of);
621 else
623 nlib_process_t proc;
624 proc.nlib=nlib;
625 proc.user=of;
626 proc.process=nlib_o_spice_subckt_process;
627 nlib_process(&proc,1);
635 /************ TOFIX: NEED to add multiple input nodes
636 probably the easiest is to pass a list ptr of i_nodes
638 tree.c needs some helper function in netlist_lib.c which gives the number of inputs
639 a given gate needs, so it can figure out it's proper wiring topology.
640 perhaps we should allocate the list of input nodes within the flatdb structure
641 and then tree would only have to pass *which* node to change in the list?
642 or at the very least, tree.c won't have to allocate a bunch of random lists and keep them
643 current.
645 ************/
650 /* output spice style subckt call, mapping i_node and o_node */
651 void nlib_o_spice_call(nlib_t *nlib, int index, int i_node, int o_node, int *skt, void * of_fp)
653 FILE *of=of_fp;
654 nlibflatdb_t *fdb;
655 nlibdb_t *db;
656 nlibio_t *iop;
657 nlibrefnode_t *rnp;
658 int i,j;
659 char tmp[64];
661 assert(nlib!=NULL);
662 fdb=list_data(&(nlib->flatdb),index);
663 assert(fdb!=NULL);
664 db=list_data(&(nlib->db),fdb->db_index);
665 assert(db!=NULL);
667 fprintf(of,"X%i ",(*skt)++);
669 /* reference nodes */
670 list_iterate(&(db->refnodes),i,rnp)
671 fprintf(of," %s",names_lookup(nlib->vref,rnp->vrefi));
673 if(i_node==-1)sprintf(tmp,"root");
674 else sprintf(tmp,"n%i",i_node);
676 /* input nodes, for multi-input gate, tie inputs together */
677 list_iterate(&(db->in.iol),i,iop)
678 for(j=0;j<iop->qnodes;j++)
679 fprintf(of," %s_%i",tmp,j);
681 /* output nodes, for multi-output gate, tie outputs together */
682 list_iterate(&(db->out.iol),i,iop)
683 for(j=0;j<iop->qnodes;j++)
684 fprintf(of," n%i_%i",o_node,j);
686 fprintf(of," sc%i",fdb->lib_index);
687 fprintf(of,"\n");
688 fprintf(of,"*nlib %i %i %i %i\n",i_node,o_node,fdb->db_index,index);
691 void nlib_iface_release(nlib_iface_t *iface)
693 list_empty(&(iface->icalls));
694 list_empty(&(iface->frefs));
697 void nlib_iface_init(nlib_iface_t *iface, nlib_t *nlib)
699 memset(iface->ref_map,0,sizeof(iface->ref_map));
700 list_init(&(iface->icalls),sizeof(nlib_icall_t),LIST_DEFMODE);
701 list_init(&(iface->frefs),sizeof(nlib_ifref_t),LIST_DEFMODE);
702 iface->nlib=nlib;
703 iface->phase=0;
706 nlib_ifref_t *nlib_iface_getref(nlib_iface_t *iface, int id)
708 nlib_ifref_t *rp;
709 assert(id<NLIBref_max);
710 assert(id>=0);
711 rp=list_data(&(iface->frefs),iface->ref_map[id]);
712 assert(rp!=NULL);
713 return rp;
716 static int nlib_digitize(float *vals[], int digitize, int tokens[], nlib_iface_t *iface)
718 int i;
719 int token=-1;
720 float dv;
721 float vdd,vss;
723 switch(digitize)
725 case 0: /* default */
726 assert(0);
727 break;
728 case 1: /* delta v */
729 assert(vals[0]!=NULL);
730 assert(vals[1]!=NULL);
731 dv=(*vals[0])-(*vals[1]);
732 if(dv>(1e-3))token=1;
733 if(dv<(-1e-3)) token=0;
734 break;
735 case 2: /* cmos */
736 assert(vals[0]!=NULL);
737 dv=*vals[0];
738 vss=nlib_iface_getref(iface,NLIBref_vss)->val[0];
739 vdd=nlib_iface_getref(iface,NLIBref_vdd)->val[0];
740 if((2*dv)>(vdd-vss)) token=1;
741 else token=0;
742 break;
743 default:
744 assert(0);
745 break;
748 /* update tokens[phases] current phase is always tokens[0].. */
749 if(tokens!=NULL)
751 for(i=(NLIB_MAXPHASES-1);i>=1;i--)
752 tokens[i]=tokens[i-1];
753 tokens[0]=token;
755 return token;
758 int nlib_func_compute(nlibfunc_t *map, int input)
760 assert(map!=NULL);
761 if(input<0)return -1;
762 assert(input<map->qin);
763 return map->map[input];
767 int nlib_icall_digitize(nlib_iface_t *iface, int calli, int phase)
769 nlib_icall_t *cd;
770 nlibdb_t *dp;
771 nlibfunc_t *fp,**fpp;
773 cd=list_data(&(iface->icalls),calli);
774 assert(cd!=NULL);
775 dp=list_data(&(iface->nlib->db),cd->dbi);
776 assert(dp!=NULL);
777 fpp=list_data(&(iface->nlib->funcs),dp->map.index);
778 assert(fpp!=NULL);
779 fp=*fpp;
780 assert(fp!=NULL);
782 nlib_digitize(cd->in, cd->idigitize, cd->itokens, iface);
783 nlib_digitize(cd->out, cd->odigitize, cd->otokens, iface);
785 if(phase> (fp->p_delay+fp->p_offset)) /* wait at least this long before checking valididy */
786 if( (phase%fp->p_cycle)== (fp->p_delay%fp->p_cycle) ) /* are we on the correct phase */
788 cd->ctoken=nlib_func_compute(fp,cd->itokens[(fp->p_offset%fp->p_delay)]);
789 if(cd->ctoken!=cd->otokens[0]) cd->err++;
790 else cd->ver++;
792 return cd->err;
795 void nlib_iface_phase(nlib_iface_t *iface)
797 int i;
798 nlib_icall_t *cp;
799 iface->phase++;
801 list_iterate(&(iface->icalls),i,cp)
802 nlib_icall_digitize(iface,i,iface->phase);
805 int nlib_iface_do_call(nlib_iface_t *iface, int in, int on, int dbi, int fdbi)
807 nlib_t *nlib=iface->nlib;
808 nlibdb_t *db;
809 char nn[64],*nnp;
810 int j;
811 nlib_icall_t *cd;
812 nlibio_t *iop;
813 int z;
815 db=list_data(&(nlib->db),dbi);
816 if(db==NULL)return 0;
818 z=list_qty(&(iface->icalls));
819 cd=list_next(&(iface->icalls));
820 cd->dbi=dbi;
821 cd->flatdbi=fdbi;
822 cd->err=0;
823 cd->ver=0;
824 for(j=0;j<NLIBIO_MAXNODES;j++)
826 cd->in[j]=NULL;
827 cd->out[j]=NULL;
829 for(j=0;j<NLIB_MAXPHASES;j++)
830 cd->itokens[j]=cd->otokens[j]=-1;
832 cd->ctoken=-1;
833 cd->inode=in;
834 cd->onode=on;
836 /*** lookup input nodes from tracefile interface *****/
838 if(in>-1)
839 sprintf(nn,"n%i_",in);
840 else sprintf(nn,"root_");
842 nnp=nn+strlen(nn);
844 iop=list_data(&(db->in.iol),0); /* only handle inverters right now */
845 assert(iop!=NULL);
846 for(j=0;j<iop->qnodes;j++)
848 sprintf(nnp,"%i",j);
849 cd->in[j]=iface->lookup_node_f(iface->user, nn);
850 if(cd->in[j]==NULL)
851 fprintf(stderr,"ERROR: did not find trace node %s\n",nn);
853 cd->idigitize=iop->digitize;
855 /*** lookup output nodes from tracefile interface ****/
857 sprintf(nn,"n%i_",on);
858 nnp=nn+strlen(nn);
860 iop=list_data(&(db->out.iol),0); /* only handle inverters right now */
861 assert(iop!=NULL);
862 for(j=0;j<iop->qnodes;j++)
864 sprintf(nnp,"%i",j);
865 cd->out[j]=iface->lookup_node_f(iface->user, nn);
866 if(cd->out[j]==NULL)
867 fprintf(stderr,"ERROR: did not find trace node %s\n",nn);
869 cd->odigitize=iop->digitize;
871 return z;
874 int nlib_i_spice_calls(nlib_iface_t *iface, void * cktf_fp)
876 FILE *cktf=cktf_fp;
877 int dbi,fdbi;
878 int in,on;
879 char line[4096];
880 int q=0;
881 int i;
882 nlib_ifref_t ifref;
884 memset(line,0,sizeof(line));
885 while(!feof(cktf))
887 line[0]=0;
888 line[1]=0;
889 line[sizeof(line)-1]=0;
890 line[sizeof(line)-2]=0;
891 fgets(line,sizeof(line-2),cktf);
892 i=strlen(line)-1;
893 while(i>=0) { if(isspace(line[i])) line[i]=0; else break; i--; }
895 if( ( line[0]=='*') && (line[1]=='n') && (line[2]=='l') && (line[3]=='i') && (line[4]=='b') )
897 dbi=-1;
898 fdbi=-1;
899 in=-2;
900 on=-2;
901 sscanf(line+5," %i %i %i %i",&in,&on,&dbi,&fdbi);
902 if(fdbi==-1)continue;
903 q+=nlib_iface_do_call(iface,in,on,dbi,fdbi);
904 continue;
907 if( (line[0]=='*') && (line[1]=='n') && (line[2]=='r') && (line[3]=='e') && (line[4]=='f'))
909 if(line[5]!=' ')continue;
910 memset(&ifref,0,sizeof(ifref));
912 for(i=6;line[i]!=0;i++)
914 if(isspace(line[i]))break;
915 ifref.name[i-6]=line[i];
918 for(i=0;i<NLIB_MAXPHASES;i++) ifref.vals[i]=0.0;
919 ifref.val=iface->lookup_node_f(iface->user,ifref.name);
920 dbi=list_add(&(iface->frefs),&ifref);
921 /* this is all just a big consistancy check */
922 fdbi=names_check(iface->nlib->vref,ifref.name);
923 if(dbi!=fdbi)
925 fprintf(stderr,"FATAL ERROR: this database file does not seem to match given tracefile\n");
926 exit(0);
929 continue;
932 return q;
936 /* saving and restoring the flat db
938 these are non human readable formatted files because i am lazy
939 note: architecture float format and endianess dependence in user parameters
942 static char nlib_flatdb_ver[]="NLIB_FLATDB_a";
944 int nlib_flatdb_write(nlib_t *nlib, void * file)
946 nlibflatdb_t *p;
947 int i,j,q;
948 unsigned char *c;
949 fprintf(file,"%s %i\n",nlib_flatdb_ver,list_qty(&(nlib->flatdb)));
950 list_iterate(&(nlib->flatdb),i,p)
952 q=list_sizeof(&(p->uservals))*list_qty(&(p->uservals));
953 c=list_data(&(p->uservals),0);
954 fprintf(file,"lib %i db %i qvals %i user %i %i\n",p->lib_index,p->db_index,p->qvals,
955 list_sizeof(&(p->uservals)),list_qty(&(p->uservals))
957 for(j=0;j<p->qvals;j++)
958 fprintf(file,"%e%c",p->pvals[j],(j==(p->qvals-1))?'\n':' ');
959 for(j=0;j<q;j++)
961 fprintf(file,"%i%c",(int)c[j],(j==(q-1))?'\n':' ');
962 if(0)fprintf(stderr,"%i ",c[j]);
965 fprintf(file,"NLIB_FLATDB_END\n");
966 return i;
970 int nlib_flatdb_read(nlib_t *nlib, void * file_fp)
972 FILE *file=file_fp;
973 nlib_process_t up;
974 nlibflatdb_t *p;
975 int i,j,q,qty,p_qvals,ua,ub,index;
976 unsigned char *c;
977 char line[4096],*lp;
978 line[0]=0;
979 line[sizeof(line)-1]=0;
980 fgets(line,sizeof(line)-2,file);
981 if(memcmp(line,nlib_flatdb_ver,strlen(nlib_flatdb_ver))!=0)return -1;
982 qty=atoi(line+sizeof(nlib_flatdb_ver));
983 if(qty==0)return -2;
984 list_hint(&(nlib->flatdb),qty);
985 i=0;
986 while(!feof(file))
988 if(i==qty)break;
989 line[0]=0;
990 fgets(line,sizeof(line)-2,file);
991 memset(&up,0,sizeof(up));
992 up.nlib=nlib;
993 up.lib_index=-1;
994 up.db_index=-1;
995 p_qvals=-1;
996 ua=0;
997 ub=0;
998 if(sscanf(line,"lib %i db %i qvals %i user %i %i",&up.lib_index,&up.db_index,&p_qvals,&ua,&ub)!=5)
999 { assert(0); continue; }
1000 index=list_qty(&(nlib->flatdb));
1001 c=nlib_flat(&up,ua,ub);
1002 p=list_data(&(nlib->flatdb),index);
1003 assert(p!=NULL);
1004 assert(p_qvals==p->qvals);
1005 line[0]=0;
1006 fgets(line,sizeof(line)-2,file);
1007 for(lp=line,j=0;j<p->qvals;j++)
1009 float f=0.0;
1010 while(isspace(lp[0]))lp++;
1011 if(sscanf(lp,"%f",&f)!=1)assert(0);
1012 while(!isspace(lp[0]))lp++;
1013 p->pvals[j]=f;
1015 assert(c!=NULL);
1016 q=ua*ub;
1017 line[0]=0;
1018 fgets(line,sizeof(line)-2,file);
1020 for(lp=line,j=0;j<q;j++)
1022 unsigned x=0;
1023 while(isspace(lp[0]))lp++;
1024 if(sscanf(lp,"%i",&x)!=1)assert(0);
1025 while(!isspace(lp[0]))lp++;
1026 c[j]=x;
1027 if(0)fprintf(stderr,"%i ",c[j]);
1029 i++;
1031 return i;
1034 /* parse a library file format
1036 .netlist = name
1037 .reference=ref_name name=spice_name delay=time rseries=res cshunt=cap
1038 .reference= ...
1039 .input=encoding spice_name[0] .... spice_name_[qnodes-1]
1040 .input=encoding ...
1041 .output spice_nam.....
1042 .output ...
1043 .param=spice_name .min=xxx .max=xxx .qtysteps=xxx
1044 .param ..
1045 .function=fname
1046 .end_netlist
1048 .encoding=encodingname .wires=number .tokens=number .digitize=methodname
1050 .digital=functionname
1051 0=0 1=0 0011=.. ... input_token = output_token
1052 .end_digital
1055 .spice
1057 # spice netlist format
1059 .end_section # end of spice netlist
1064 static tokenmap_t nlib_tokens[]=NLIB_TOKENS;
1066 /* assume nlib aready initted, this adds to it */
1067 int nlib_parse(nlib_t *nlib, scanner_t *scan)
1069 netlist_t *nl=NULL;
1070 int db_index=-1;
1071 deck_t *db_deck=NULL, *digital_deck=NULL;
1072 nlibiodef_t encoding_default;
1073 nlibfunc_t *digital_func=NULL;
1074 deck_t *dplast=NULL;
1075 scanner_def_t defs;
1077 assert(nlib->eqn_mem!=NULL);
1078 eqn_mem_push(nlib->eqn_mem);
1080 defs=*scanner_def_spice();
1081 strcpy(defs.line_stop,".end_nlib");
1082 encoding_default.encoding="dual_rail";
1083 encoding_default.wires=2;
1084 encoding_default.tokens=2;
1085 encoding_default.digitize=0;
1086 scanner_sect_new(scan,&defs,nlib_tokens);
1087 while(scanner_parse_line(scan))
1089 card_t *cp=NULL;
1090 int flag=0;
1092 if(scan->sectp!=NULL)
1093 if(scan->sectp->dp!=NULL)
1094 if((cp=scan->sectp->dp->card)!=NULL)
1095 flag++;
1096 if(flag&&(scan->sectp->dp!=dplast))
1098 dplast=scan->sectp->dp;
1099 scan->errdeck=dplast;
1100 scan->errcard=dplast->card;
1101 if(0)scanner_debug_all(scan,stderr);
1102 switch(cp->token)
1105 case Knlib_digital:
1106 if(cp->val!=NULL)
1108 card_t *p;
1109 int z;
1110 int qtyin=-1, qtyout=-1, p_delay=-1, p_offset=-1, p_cycle=-1;
1111 for(p=cp->next;p!=NULL;p=p->next)
1113 if(p->val!=NULL)
1115 z=atoi(p->val);
1116 switch(p->token)
1118 case Knlib_qtyin:
1119 qtyin=z;
1120 break;
1121 case Knlib_qtyout:
1122 qtyout=z;
1123 break;
1124 case Knlib_p_delay:
1125 p_delay=z;
1126 break;
1127 case Knlib_p_offset:
1128 p_offset=z;
1129 break;
1130 case Knlib_p_cycle:
1131 p_cycle=z;
1132 break;
1133 default:
1134 scan->errcard=p;
1135 scan->errdeck=dplast;
1136 parse_warn(scan,"unknown word in function definition %s\n",p->val);
1141 if((qtyin!=-1) && (qtyout!=-1) && (p_delay!=-1) && (p_offset!=-1) && (p_cycle!=-1))
1143 digital_deck=scan->sectp->dp;
1144 digital_func=nlib_new_func(nlib,cp->val, qtyin, qtyout, p_delay,p_offset,p_cycle);
1145 break;
1148 parse_error(scan,"mangled function definition");
1149 break;
1151 case Knlib_end_digital:
1152 if((digital_deck!=NULL) && (digital_func!=NULL))
1154 deck_t *dp;
1155 for(dp=digital_deck->next;dp!=NULL;dp=dp->next)
1157 card_t *p;
1158 if(dp==scan->sectp->dp)break;
1159 for(p=dp->card;p!=NULL;p=p->next)
1161 unsigned int a=0,b=0;
1162 char *sp=p->str;
1163 scan->errcard=p;
1164 scan->errdeck=dp;
1165 if(sp!=NULL)
1167 a=parse_binary(&sp);
1168 sp=p->val;
1169 if(sp!=NULL)
1171 b=parse_binary(&sp);
1172 nlib_func_addmap(nlib, digital_func, a, b);
1174 else parse_warn(scan,"ignoring mangled mapping %s=%s\n",cp->str,cp->val);
1176 else parse_warn(scan,"ignoring mangled mapping %s=%s\n",cp->str,cp->val);
1180 else
1181 parse_error(scan,"mangled function definition");
1182 digital_deck=NULL;
1183 digital_func=NULL;
1184 break;
1186 case Knlib_encoding: /* io def */
1187 if(cp->val!=NULL)
1189 int tokens=0, wires=0, h_tokens=0, h_wires=0;
1190 char *digitize=NULL;
1191 card_t *p;
1192 for(p=cp->next;p!=NULL;p=p->next)
1194 D(20,fprintf(stderr,"encoding: %s=[%s]\n",p->str,p->val));
1195 if(p->val!=NULL)
1197 switch(p->token)
1199 case Knlib_wires:
1200 wires=atoi(p->val);
1201 h_wires++;
1202 break;
1203 case Knlib_tokens:
1204 tokens=atoi(p->val);
1205 h_tokens++;
1206 break;
1207 case Knlib_digitize:
1208 digitize=p->val;
1209 break;
1213 if( h_tokens && h_wires && (digitize!=NULL) )
1215 int index;
1216 nlibiodef_t *iop;
1217 index=list_add(&(nlib->iodefs),&encoding_default);
1218 iop=list_data(&(nlib->iodefs),index);
1219 iop->encoding=strdup(cp->val);
1221 if(strcmp(digitize,"deltav")==0)
1222 iop->digitize=1;
1223 else if(strcmp(digitize,"cmos")==0)
1224 iop->digitize=2;
1225 else
1226 iop->digitize=0;
1228 iop->tokens=tokens;
1229 iop->wires=wires;
1230 D(20,fprintf(stderr,"adding encoding %s, %i %i\n",cp->val,tokens,wires));
1231 break;
1235 parse_error(scan,"mangled encoding line ");
1236 break;
1238 case Knlib_define:
1239 if(cp->val==NULL)
1241 card_t *p;
1242 for(p=cp->next;p!=NULL;p=p->next)
1244 if(p->val!=NULL)
1246 eqnl_add(&(nlib->eqnl),eqn_parse(p->val),p->str);
1250 break;
1252 case Knlib_netlist:
1253 if(cp->val!=NULL)
1255 db_index=nlib_new_db(nlib,cp->val);
1256 db_deck=scan->sectp->dp; /* store location in deck where netlist occured */
1258 else
1259 parse_error(scan,".netlist=name expected");
1260 break;
1262 case Knlib_spice:
1263 if(db_index>=0)
1265 nl=netlist_devnew(netlist_parse_input(scan,"spice",NULL));
1266 assert(nl!=NULL);
1268 if(1)netlist_release(nl); /* release spice parse structures */
1269 /* why does it crash with this ???? */
1271 else
1272 parse_error(scan,".spice section must be preceded by .netlist section");
1273 break;
1275 case Knlib_end_netlist:
1276 if(db_index<0)
1277 parse_error(scan,".end netlist without .netlist");
1278 else
1280 deck_t *dp;
1281 card_t *cp;
1282 nlibdb_t *dbp;
1283 nlib_db_netlist(nlib,db_index,nl);
1284 dbp=list_data(&(nlib->db),db_index);
1285 nl=NULL;
1286 for(dp=db_deck;dp!=NULL;dp=dp->next) /* walk through from db_deck to here */
1288 if(dp->card==NULL)continue;
1289 cp=dp->card;
1290 scan->errdeck=dp;
1291 scan->errcard=cp;
1293 switch(cp->token)
1295 case Knlib_param:
1296 if(cp->val!=NULL)
1298 card_t *p;
1299 float min=0,max=0,qty=0,v;
1300 int h_min=0, h_max=0, h_qty=0;
1302 for(p=cp->next;p!=NULL;p=p->next)
1304 if(p->val!=NULL)
1306 v=parse_float(p->val);
1307 switch(p->token)
1309 case Knlib_min:
1310 min=v; h_min++;
1311 break;
1312 case Knlib_max:
1313 max=v; h_max++;
1314 break;
1315 case Knlib_qty:
1316 qty=v; h_qty++;
1317 break;
1321 if(h_min&&h_max&&h_qty)
1323 nlib_add_pm(nlib,db_index, cp->val, min, max, floorf(qty));
1324 break;
1327 scan->errdeck=dp;
1328 scan->errcard=dp->card;
1329 parse_error(scan,"mangled param statement\n");
1330 break;
1332 case Knlib_input:
1333 case Knlib_output:
1334 if(cp->val!=NULL)
1336 card_t *p;
1337 char *names[64]; /* max limit */
1338 int i,qnames=0;
1339 nlibiodef_t *iop;
1340 int tokens=0, wires=0, digital=0, h_stuff=0;
1342 for(i=0,p=cp->next;(p!=NULL)&&(i<64);p=p->next,i++)
1343 names[i]=p->str;
1345 qnames=i;
1346 list_iterate(&(nlib->iodefs),i,iop)
1348 if(strcmp(cp->val,iop->encoding)==0)
1350 tokens=iop->tokens;
1351 wires=iop->wires;
1352 digital=iop->digitize;
1353 h_stuff=1;
1354 if(0)fprintf(stderr,"got stuff %s %i %i \n",cp->val,wires,qnames);
1358 if(h_stuff && (wires==qnames)&& (dbp!=NULL) )
1361 if(cp->token==Knlib_input)
1362 nlib_add_io(nlib,db_index,&(dbp->in),tokens,wires,digital,names);
1363 if(cp->token==Knlib_output)
1364 nlib_add_io(nlib,db_index,&(dbp->out),tokens,wires,digital,names);
1365 break;
1368 scan->errdeck=dp;
1369 scan->errcard=dp->card;
1370 parse_error(scan,"mangled input/output statement \n");
1371 break;
1372 case Knlib_function:
1373 if(cp->val!=NULL)
1375 nlib_db_func(nlib,db_index,cp->val);
1376 break;
1378 parse_error(scan,"mangled function line \n");
1379 break;
1381 case Knlib_reference:
1382 if(cp->val!=NULL)
1384 card_t *p;
1385 char *str_name=NULL;
1386 eqn_t cshunt,rseries,delay;
1387 int h_cshunt=0, h_rseries=0, h_delay=0;
1388 int nl_index=-1, top_index=-1;
1390 for(p=cp->next;p!=NULL;p=p->next)
1392 if(p->val!=NULL)
1393 switch(p->token)
1395 case Knlib_name:
1396 str_name=p->val;
1397 break;
1398 case Knlib_cshunt:
1399 cshunt=eqn_parse(p->val);
1400 h_cshunt++;
1401 break;
1402 case Knlib_rseries:
1403 rseries=eqn_parse(p->val);
1404 h_rseries++;
1405 break;
1406 case Knlib_delay:
1407 delay=eqn_parse(p->val);
1408 h_delay++;
1409 break;
1410 default:
1411 scan->errdeck=dp;
1412 scan->errcard=p;
1413 parse_warn(scan,"reference: unknown word %s\n",cp->str);
1416 if(str_name!=NULL)
1417 nl_index=netlist_findnode(dbp->nl,str_name);
1419 if(nl_index>=0)
1421 nlibrefnode_t rn;
1422 int l;
1424 top_index=names_check(nlib->vref,cp->val);
1425 if(top_index<0)
1427 top_index=nlib->qvref;
1428 names_add(nlib->vref,top_index,cp->val);
1429 nlib->qvref++;
1432 for(l=0;l<MAXSKEW_PARAMS;l++)
1433 rn.skew[l]=eqn_empty();
1435 rn.vrefi=top_index;
1436 rn.devnodei=nl_index;
1437 if(h_delay)
1438 rn.skew[RTdelay]=delay;
1439 if(h_rseries)
1440 rn.skew[RTrseries]=rseries;
1441 if(h_cshunt)
1442 rn.skew[RTcshunt]=cshunt;
1444 list_add(&(dbp->refnodes),&rn);
1445 break;
1447 else { parse_warn(scan,"reference netlist node %s not found, ignoring\n",str_name); break; }
1449 parse_error(scan,"mangled reference line cp=%s val=%s\n",cp->str,cp->val);
1450 break;
1451 case Knlib_netlist:
1452 break;
1453 case Knlib_spice:
1454 break;
1455 case Knlib_end_netlist:
1456 break;
1457 default:
1458 scan->errdeck=dp;
1459 scan->errcard=cp;
1460 parse_warn(scan,"ignoring unknown card %s\n",cp->str);
1461 break;
1464 if(dbp!=NULL)
1465 nlib_db_fixup(nlib,dbp);
1466 else assert(0);
1467 dbp=NULL;
1468 db_index=-1;
1469 break;
1476 /* check memory after parse */ free(malloc(32));
1477 nlib_fixup(nlib);
1478 if(eqn_mem_pop()!=nlib->eqn_mem)assert(0);
1479 return list_qty(&(nlib->db));