/* File: netlist.c * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit * simulation. * Copyright (C) 1998-2024 Stefan Frederik Schippers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "xschem.h" static int for_netlist = 0; static int netlist_lvs_ignore = 0; static void instdelete(int n, int x, int y) { Instentry *saveptr, **prevptr, *ptr; prevptr = &xctx->inst_spatial_table[x][y]; ptr = *prevptr; while(ptr) { if(ptr->n == n) { saveptr = ptr->next; my_free(_ALLOC_ID_, &ptr); *prevptr = saveptr; return; } prevptr = &ptr->next; ptr = *prevptr; } } static void instinsert(int n, int x, int y) { Instentry *ptr, *newptr; ptr=xctx->inst_spatial_table[x][y]; newptr=my_malloc(_ALLOC_ID_, sizeof(Instentry)); newptr->next=ptr; newptr->n=n; xctx->inst_spatial_table[x][y]=newptr; dbg(2, "instinsert(): inserting object %d at %d,%d\n",n,x,y); } static Instentry *delinstentry(Instentry *t) { Instentry *tmp; while( t ) { tmp = t->next; my_free(_ALLOC_ID_, &t); t = tmp; } return NULL; } void del_inst_table(void) { int i,j; for(i=0;iinst_spatial_table[i][j] = delinstentry(xctx->inst_spatial_table[i][j]); xctx->prep_hash_inst=0; dbg(1, "del_inst_table(): cleared object hash table\n"); } /* what: * 0, XINSERT : add to hash * 1, XDELETE : remove from hash */ void hash_inst(int what, int n) /* 20171203 insert object bbox in spatial hash table */ { int tmpi,tmpj, counti,countj,i,j; double tmpd; double x1, y1, x2, y2; int x1a, x2a, y1a, y2a; x1=xctx->inst[n].x1; x2=xctx->inst[n].x2; y1=xctx->inst[n].y1; y2=xctx->inst[n].y2; /* ordered bbox */ if( x2 < x1) { tmpd=x2;x2=x1;x1=tmpd;} if( y2 < y1) { tmpd=y2;y2=y1;y1=tmpd;} /* calculate square 4 1st bbox point of object[k] */ x1a=(int)floor(x1/BOXSIZE); y1a=(int)floor(y1/BOXSIZE); /* calculate square 4 2nd bbox point of object[k] */ x2a=(int)floor(x2/BOXSIZE); y2a=(int)floor(y2/BOXSIZE); /*loop thru all squares that intersect bbox of object[k] */ counti=0; for(i=x1a; i<=x2a && counti < NBOXES; ++i) { ++counti; tmpi=i%NBOXES; if(tmpi<0) tmpi+=NBOXES; countj=0; for(j=y1a; j<=y2a && countj < NBOXES; ++j) { ++countj; tmpj=j%NBOXES; if(tmpj<0) tmpj+=NBOXES; /* insert object_ptr[n] in region [tmpi, tmpj] */ if(what == XINSERT) instinsert(n, tmpi, tmpj); else instdelete(n, tmpi, tmpj); } } } void hash_instances(void) /* 20171203 insert object bbox in spatial hash table */ { int n; if(xctx->prep_hash_inst) return; del_inst_table(); for(n=0; ninstances; ++n) { hash_inst(XINSERT, n); } xctx->prep_hash_inst=1; } /* START HASH ALL OBJECTS */ static Objectentry *delobjectentry(Objectentry *t) { Objectentry *tmp; while( t ) { tmp = t->next; my_free(_ALLOC_ID_, &t); t = tmp; } return NULL; } void del_object_table(void) { int i,j; for(i=0;iobject_spatial_table[i][j] = delobjectentry(xctx->object_spatial_table[i][j]); xctx->prep_hash_object=0; xctx->n_hash_objects = 0; dbg(1, "del_object_table(): cleared object hash table\n"); } static void objectdelete(int type, int n, int c, int x, int y) { Objectentry *saveptr, **prevptr, *ptr; prevptr = &xctx->object_spatial_table[x][y]; ptr = *prevptr; while(ptr) { if(ptr->n == n && ptr->type == type && ptr->c == c ) { saveptr = ptr->next; my_free(_ALLOC_ID_, &ptr); *prevptr = saveptr; return; } prevptr = &ptr->next; ptr = *prevptr; } } static void objectinsert(int type, int n, int c, int x, int y) { Objectentry *ptr, *newptr; ptr=xctx->object_spatial_table[x][y]; newptr=my_malloc(_ALLOC_ID_, sizeof(Instentry)); newptr->next=ptr; newptr->type=type; newptr->n=n; newptr->c=c; xctx->object_spatial_table[x][y]=newptr; dbg(2, "objectnsert(): inserting object %d %d %d at %d,%d\n",type, n, c, x, y); } /* what: * 0, XINSERT : add to hash * 1, XDELETE : remove from hash */ void hash_object(int what, int type, int n, int c) { int tmpi,tmpj, counti,countj,i,j; double tmpd; double x1, y1, x2, y2; int x1a, x2a, y1a, y2a; int skip = 0; char *estr = NULL; switch(type) { case ELEMENT: x1=xctx->inst[n].x1; x2=xctx->inst[n].x2; y1=xctx->inst[n].y1; y2=xctx->inst[n].y2; break; case xRECT: x1 = xctx->rect[c][n].x1; y1 = xctx->rect[c][n].y1; x2 = xctx->rect[c][n].x2; y2 = xctx->rect[c][n].y2; break; case WIRE: x1 = xctx->wire[n].x1; y1 = xctx->wire[n].y1; x2 = xctx->wire[n].x2; y2 = xctx->wire[n].y2; break; case LINE: x1 = xctx->line[c][n].x1; y1 = xctx->line[c][n].y1; x2 = xctx->line[c][n].x2; y2 = xctx->line[c][n].y2; break; case POLYGON: polygon_bbox(xctx->poly[c][n].x, xctx->poly[c][n].y, xctx->poly[c][n].points, &x1, &y1, &x2, &y2); break; case ARC: arc_bbox(xctx->arc[c][n].x, xctx->arc[c][n].y, xctx->arc[c][n].r, xctx->arc[c][n].a, xctx->arc[c][n].b, &x1, &y1, &x2, &y2); break; case xTEXT: estr = my_expand(get_text_floater(n), tclgetintvar("tabstop")); text_bbox(estr, xctx->text[n].xscale, xctx->text[n].yscale, xctx->text[n].rot, xctx->text[n].flip, xctx->text[n].hcenter, xctx->text[n].vcenter, xctx->text[n].x0, xctx->text[n].y0, &x1,&y1, &x2,&y2, &tmpi, &tmpd); my_free(_ALLOC_ID_, &estr); break; default: skip = 1; x1 = 0.0; y1 = 0.0; x2 = 0.0; y2 = 0.0; break; } if(skip) return; xctx->n_hash_objects++; /* total number of objects in spatial hash table */ /* ordered bbox */ if( x2 < x1) { tmpd=x2;x2=x1;x1=tmpd;} if( y2 < y1) { tmpd=y2;y2=y1;y1=tmpd;} /* calculate square 4 1st bbox point of object[k] */ x1a=(int)floor(x1/BOXSIZE); y1a=(int)floor(y1/BOXSIZE); /* calculate square 4 2nd bbox point of object[k] */ x2a=(int)floor(x2/BOXSIZE); y2a=(int)floor(y2/BOXSIZE); /*loop thru all squares that intersect bbox of object[k] */ counti=0; for(i=x1a; i<=x2a && counti < NBOXES; ++i) { ++counti; tmpi=i%NBOXES; if(tmpi<0) tmpi+=NBOXES; countj=0; for(j=y1a; j<=y2a && countj < NBOXES; ++j) { ++countj; tmpj=j%NBOXES; if(tmpj<0) tmpj+=NBOXES; /* insert object_ptr[n] in region [tmpi, tmpj] */ if(what == XINSERT) objectinsert(type, n, c, tmpi, tmpj); else objectdelete(type, n, c, tmpi, tmpj); } } } void hash_objects(void) /* 20171203 insert object bbox in spatial hash table */ { int n, c; if(xctx->prep_hash_object) return; del_object_table(); for(n=0; ninstances; ++n) { hash_object(XINSERT, ELEMENT, n, 0); } for(n=0; nwires; ++n) { hash_object(XINSERT, WIRE, n, 0); } for(n=0; ntexts; ++n) { hash_object(XINSERT, xTEXT, n, 0); } for(c=0;crects[c]; n++) { hash_object(XINSERT, xRECT, n, c); } for(n=0; nlines[c]; n++) { hash_object(XINSERT, LINE, n, c); } for(n=0; narcs[c]; n++) { hash_object(XINSERT, ARC, n, c); } for(n=0; npolygons[c]; n++) { hash_object(XINSERT, POLYGON, n, c); } } xctx->prep_hash_object=1; } /* END HASH ALL OBJECTS */ static void instpindelete(int n,int pin, int x, int y) { Instpinentry *saveptr, **prevptr, *ptr; prevptr = &xctx->instpin_spatial_table[x][y]; ptr = *prevptr; while(ptr) { if(ptr->n == n && ptr->pin == pin) { saveptr = ptr->next; my_free(_ALLOC_ID_, &ptr); *prevptr = saveptr; return; } prevptr = &ptr->next; ptr = *prevptr; } } /* --pin coordinates-- -square coord- */ static void instpininsert(int n,int pin, double x0, double y0, int x, int y) { Instpinentry *ptr, *newptr; ptr=xctx->instpin_spatial_table[x][y]; newptr=my_malloc(_ALLOC_ID_, sizeof(Instpinentry)); newptr->next=ptr; newptr->n=n; newptr->x0=x0; newptr->y0=y0; newptr->pin=pin; xctx->instpin_spatial_table[x][y]=newptr; dbg(2, "instpininsert(): inserting inst %d at %d,%d\n",n,x,y); } static Instpinentry *delinstpinentry(Instpinentry *t) { Instpinentry *tmp; while(t) { tmp = t->next; my_free(_ALLOC_ID_, &t); t = tmp; } return NULL; } static void del_inst_pin_table(void) { int i,j; for(i=0;iinstpin_spatial_table[i][j] = delinstpinentry(xctx->instpin_spatial_table[i][j]); } static void wiredelete(int n, int x, int y) { Wireentry *saveptr, **prevptr, *ptr; prevptr = &xctx->wire_spatial_table[x][y]; ptr = *prevptr; while(ptr) { if(ptr->n == n) { saveptr = ptr->next; my_free(_ALLOC_ID_, &ptr); *prevptr = saveptr; return; } prevptr = &ptr->next; ptr = *prevptr; } } static void wireinsert(int n, int x, int y) { Wireentry *ptr, *newptr; ptr=xctx->wire_spatial_table[x][y]; newptr=my_malloc(_ALLOC_ID_, sizeof(Wireentry)); newptr->next=ptr; newptr->n=n; xctx->wire_spatial_table[x][y]=newptr; dbg(2, "wireinsert(): inserting wire %d at %d,%d\n",n,x,y); } static Wireentry *delwireentry(Wireentry *t) { Wireentry *tmp; while( t ) { tmp = t->next; my_free(_ALLOC_ID_, &t); t = tmp; } return NULL; } void del_wire_table(void) { int i,j; for(i=0;iwire_spatial_table[i][j] = delwireentry(xctx->wire_spatial_table[i][j]); xctx->prep_hash_wires=0; } void get_square(double x, double y, int *xx, int *yy) { int xa, xb, ya, yb; xa=(int)floor(x/BOXSIZE) ; xb=xa % NBOXES; if(xb<0) xb+=NBOXES; ya=(int)floor(y/BOXSIZE) ; yb=ya % NBOXES; if(yb<0) yb+=NBOXES; *xx=xb; *yy=yb; } /* what: * 0, XINSERT : add to hash * 1, XDELETE : remove from hash * * inst pin */ static int hash_inst_pin(int what, int i, int j) { int err = 0; xRect *rct; char *prop_ptr; double x0, y0, rx1, ry1; short rot, flip; int sqx, sqy; int rects; rects=(xctx->inst[i].ptr+ xctx->sym)->rects[PINLAYER] ; if(j>=rects) /* generic pins */ { rct=(xctx->inst[i].ptr+ xctx->sym)->rect[GENERICLAYER]; x0=(rct[j-rects].x1+rct[j-rects].x2)/2; y0=(rct[j-rects].y1+rct[j-rects].y2)/2; prop_ptr = rct[j-rects].prop_ptr; } else { rct=(xctx->inst[i].ptr+ xctx->sym)->rect[PINLAYER]; x0=(rct[j].x1+rct[j].x2)/2; y0=(rct[j].y1+rct[j].y2)/2; prop_ptr = rct[j].prop_ptr; } if(xctx->netlist_count && for_netlist && jinst[i].instname, xctx->inst[i].name, j, prop_ptr ? prop_ptr : ""); statusmsg(str,2); err |= 1; xctx->inst[i].color = -PINLAYER; xctx->hilight_nets=1; } rot=xctx->inst[i].rot; flip=xctx->inst[i].flip; ROTATION(rot, flip, 0.0,0.0,x0,y0,rx1,ry1); x0=xctx->inst[i].x0+rx1; y0=xctx->inst[i].y0+ry1; get_square(x0, y0, &sqx, &sqy); if( what == XINSERT ) instpininsert(i, j, x0, y0, sqx, sqy); else instpindelete(i, j, sqx, sqy); return err; } /* what: * 0, XINSERT : add to hash * 1, XDELETE : remove from hash */ void hash_wire(int what, int n, int incremental) { int tmpi,tmpj, counti,countj,i,j; double tmpd; double x1, y1, x2, y2; int x1a, x2a, y1a, y2a; Wireentry *wptr; xWire * const wire = xctx->wire; dbg(1, "hash_wire(): what=%d n=%d incremental=%d\n", what, n, incremental); wire[n].end1 = wire[n].end2=-1; x1=wire[n].x1; x2=wire[n].x2; y1=wire[n].y1; y2=wire[n].y2; /* ordered bbox */ if( x2 < x1) { tmpd=x2;x2=x1;x1=tmpd;} if( y2 < y1) { tmpd=y2;y2=y1;y1=tmpd;} /* calculate square 4 1st bbox point of wire[k] */ x1a=(int)floor(x1/BOXSIZE) ; y1a=(int)floor(y1/BOXSIZE) ; /* calculate square 4 2nd bbox point of wire[k] */ x2a=(int)floor(x2/BOXSIZE); y2a=(int)floor(y2/BOXSIZE); /*loop thru all squares that intersect bbox of wire[k] */ counti=0; for(i=x1a; i<=x2a && counti < NBOXES; ++i) { ++counti; tmpi=i%NBOXES; if(tmpi<0) tmpi+=NBOXES; countj=0; for(j=y1a; j<=y2a && countj < NBOXES; ++j) { ++countj; tmpj=j%NBOXES; if(tmpj<0) tmpj+=NBOXES; /* insert wire[n] in region [tmpi, tmpj] */ if(what==XINSERT) wireinsert(n, tmpi, tmpj); else wiredelete(n, tmpi, tmpj); /* reset ends of all wires that *could* touch wire[n] */ if(incremental) for(wptr = xctx->wire_spatial_table[tmpi][tmpj] ; wptr ; wptr = wptr->next) { wire[wptr->n].end1 = wire[wptr->n].end2 = -1; } } } } void hash_wires(void) { int n; if(xctx->prep_hash_wires) return; del_wire_table(); for(n=0; nwires; ++n) hash_wire(XINSERT, n, 0); xctx->prep_hash_wires=1; } /* return 0 if library path of s matches any lib name in tcl variable $xschem_libs */ /* what: * 1: netlist exclude pattern * 2: hierarchical print exclude pattern * 4: hierarchical cell listing exclude pattern */ int check_lib(int what, const char *s) { int range,i, found; char str[PATH_MAX + 512]; /* overflow safe 20161122 */ found=0; if(what & 1) tcleval("llength $xschem_libs"); if(what & 2) tcleval("llength $noprint_libs"); if(what & 4) tcleval("llength $nolist_libs"); range = atoi(tclresult()); dbg(1, "check_lib(): s=%s, range=%d\n", s, range); for(i=0;i %s\n", str, tclresult()); my_snprintf(str, S(str), "regexp {%s} {%s}", tclresult(), s); dbg(1, "check_lib(): str=%s\n", str); tcleval(str); if( tclresult()[0] == '1') found=1; } if(found) return 0; else return 1; } void netlist_options(int i) { const char * str; str = get_tok_value(xctx->inst[i].prop_ptr, "bus_replacement_char", 0); if(str[0] && str[1] && strlen(str) ==2) { bus_char[0] = str[0]; bus_char[1] = str[1]; /* tclsetvar("bus_replacement_char", str); */ } /* fprintf(errfp, "netlist_options(): bus_char=%s\n", str); */ str = get_tok_value(xctx->inst[i].prop_ptr, "lvs_ignore", 0); if(str[0]) { /* fprintf(errfp, "netlist_options(): prop_ptr=%s\n", xctx->inst[i].prop_ptr); */ if(!strboolcmp(str, "true")) tclsetintvar("lvs_ignore", 1); else tclsetintvar("lvs_ignore", 0); } str = get_tok_value(xctx->inst[i].prop_ptr, "lvs_netlist", 0); if(str[0]) { /* fprintf(errfp, "netlist_options(): prop_ptr=%s\n", xctx->inst[i].prop_ptr); */ if(!strboolcmp(str, "true")) tclsetintvar("lvs_netlist", 1); else tclsetintvar("lvs_netlist", 0); } str = get_tok_value(xctx->inst[i].prop_ptr, "top_is_subckt", 0); if(str[0]) { /* fprintf(errfp, "netlist_options(): prop_ptr=%s\n", xctx->inst[i].prop_ptr); */ if(!strboolcmp(str, "true")) tclsetintvar("top_is_subckt", 1); else tclsetintvar("top_is_subckt", 0); } str = get_tok_value(xctx->inst[i].prop_ptr, "spiceprefix", 0); if(str[0]) { /* fprintf(errfp, "netlist_options(): prop_ptr=%s\n", xctx->inst[i].prop_ptr); */ if(!strboolcmp(str, "false")) tclsetvar("spiceprefix", "0"); else tclsetvar("spiceprefix", "1"); } str = get_tok_value(xctx->inst[i].prop_ptr, "hiersep", 0); if(str[0]) { my_snprintf(xctx->hiersep, S(xctx->hiersep), "%s", str); } } void set_tcl_netlist_type(void) { if(xctx->netlist_type == CAD_SPICE_NETLIST) { tclsetvar("netlist_type", "spice"); } else if(xctx->netlist_type == CAD_VERILOG_NETLIST) { tclsetvar("netlist_type", "verilog"); } else if(xctx->netlist_type == CAD_VHDL_NETLIST) { tclsetvar("netlist_type", "vhdl"); } else if(xctx->netlist_type == CAD_TEDAX_NETLIST) { tclsetvar("netlist_type", "tedax"); } else if(xctx->netlist_type == CAD_SYMBOL_ATTRS) { tclsetvar("netlist_type", "symbol"); } else { tclsetvar("netlist_type", "unknown"); } } /* used only for debug */ #if 0 static void print_wires(void) { int i,j; Wireentry *ptr; for(i=0;iwire_spatial_table[i][j]; while(ptr) { dbg(1, "print_wires(): %6d\n", ptr->n); ptr=ptr->next; } dbg(1, "print_wires(): \n"); } } ptr=xctx->wire_spatial_table[0][1]; while(ptr) { select_wire(ptr->n,SELECTED, 1); rebuild_selected_array(); ptr=ptr->next; } draw(); } #endif /* store list of global nodes (global=1 set in symbol props) to be printed in netlist 28032003 */ /* what: */ /* 0: print list of global nodes and delete list */ /* 1: add entry */ /* 2: delete list only, no print */ /* 3: look if node is a global */ int record_global_node(int what, FILE *fp, const char *node) { int i; if( what == 1 || what == 3) { if(!node) return 0; if(!strcmp(node, "0")) return 1; for(i = 0;i < xctx->max_globals; ++i) { if( !strcmp(node, xctx->globals[i] )) return 1; /* node is a global */ } if(what == 3) return 0; /* node is not a global */ if(xctx->max_globals >= xctx->size_globals) { xctx->size_globals+=CADCHUNKALLOC; my_realloc(_ALLOC_ID_, &xctx->globals, xctx->size_globals*sizeof(char *) ); } xctx->globals[xctx->max_globals]=NULL; my_strdup(_ALLOC_ID_, &xctx->globals[xctx->max_globals], node); xctx->max_globals++; } else if(what == 0) { for(i = 0;i < xctx->max_globals; ++i) { if(xctx->netlist_type == CAD_SPICE_NETLIST) fprintf(fp, ".GLOBAL %s\n", xctx->globals[i]); if(xctx->netlist_type == CAD_TEDAX_NETLIST) fprintf(fp, "__GLOBAL__ %s\n", xctx->globals[i]); } } else if(what == 2) { for(i=0;imax_globals; ++i) { my_free(_ALLOC_ID_, &xctx->globals[i]); } my_free(_ALLOC_ID_, &xctx->globals); xctx->size_globals = xctx->max_globals=0; } return 0; } void get_inst_pin_coord(int i, int j, double *x, double *y) { xRect *rct; int rects, rot, flip; double x0, y0, rx1, ry1; xInstance * const inst = xctx->inst; rects = (inst[i].ptr+ xctx->sym)->rects[PINLAYER]; if(j < rects) { rct=(inst[i].ptr+ xctx->sym)->rect[PINLAYER]; x0=(rct[j].x1+rct[j].x2)/2; y0=(rct[j].y1+rct[j].y2)/2; rot=inst[i].rot; flip=inst[i].flip; ROTATION(rot, flip, 0.0,0.0,x0,y0,rx1,ry1); *x=inst[i].x0+rx1; *y=inst[i].y0+ry1; } else { *x = 0; *y = 0; } } /* what==0 -> initialize */ /* what==1 -> get new node name, net## */ /* what==2 -> update multiplicity */ /* what==3 -> get node multiplicity */ int get_unnamed_node(int what, int mult,int node) { dbg(2, "get_unnamed_node(): what=%d mult=%d node=%d\n", what, mult, node); if(what==0) { /* initialize unnamed node data structures */ xctx->new_node=0; my_free(_ALLOC_ID_, &xctx->node_mult); xctx->node_mult_size=0; return 0; } else if(what==1) { /* get a new unique unnamed node */ char tmp_str[30]; do { ++xctx->new_node; my_snprintf(tmp_str, S(tmp_str), "net%d", xctx->new_node); /* JL avoid autonamed nets clash with user defined 'net#' names */ } while (bus_node_hash_lookup(tmp_str, "", XLOOKUP, 0, "", "", "", "")!=NULL); if(xctx->new_node >= xctx->node_mult_size) { /* enlarge array and zero it */ int oldsize = xctx->node_mult_size; xctx->node_mult_size = xctx->new_node + CADCHUNKALLOC; my_realloc(_ALLOC_ID_, &xctx->node_mult, sizeof(xctx->node_mult[0]) * xctx->node_mult_size ); memset(xctx->node_mult + oldsize, 0, (xctx->node_mult_size - oldsize) * sizeof(xctx->node_mult[0])); } xctx->node_mult[xctx->new_node]=mult; return xctx->new_node; } else if(what==2) { /* update node multiplicity if given mult is lower */ if(xctx->node_mult[node]==0) xctx->node_mult[node]=mult; else if(mult < xctx->node_mult[node]) xctx->node_mult[node]=mult; return 0; } else { /* what=3 , return node multiplicity */ dbg(2, "get_unnamed_node(): returning mult=%d\n", xctx->node_mult[node]); return xctx->node_mult[node]; } } static void name_generics() { xRect *rct; double x0, y0; short rot = 0; short flip = 0; int sqx, sqy; double rx1,ry1; Instpinentry *iptr; int i,j, rects, generic_rects; char *type=NULL; char *sig_type=NULL; xInstance * const inst = xctx->inst; int const instances = xctx->instances; /* name generic pins from attached labels */ dbg(2, "name_generics(): naming generics from attached labels\n"); if(for_netlist) for (i=0;isym)->type); if(type && !IS_LABEL_OR_PIN(type) ) { if((generic_rects = (inst[i].ptr+ xctx->sym)->rects[GENERICLAYER]) > 0) { rects = (inst[i].ptr+ xctx->sym)->rects[PINLAYER]; for (j=rects;jsym)->rect[GENERICLAYER]; x0=(rct[j-rects].x1+rct[j-rects].x2)/2; y0=(rct[j-rects].y1+rct[j-rects].y2)/2; rot=inst[i].rot; flip=inst[i].flip; ROTATION(rot, flip, 0.0,0.0,x0,y0,rx1,ry1); x0=inst[i].x0+rx1; y0=inst[i].y0+ry1; get_square(x0, y0, &sqx, &sqy); for(iptr=xctx->instpin_spatial_table[sqx][sqy]; iptr; iptr = iptr ->next) { int p = iptr->pin; int n = iptr->n; if(n == i) continue; if(!inst[n].node) continue; if((iptr->x0==x0) && (iptr->y0==y0)) { if((inst[n].ptr+ xctx->sym)->type && inst[n].node[p] != NULL && !strcmp((inst[n].ptr+ xctx->sym)->type, "label")) { dbg(2, "name_generics(): naming generic %s\n", inst[n].node[p]); my_strdup(_ALLOC_ID_, &inst[i].node[j], get_tok_value(inst[n].prop_ptr,"value",0) ); if(!for_netlist) { my_strdup(_ALLOC_ID_, &sig_type,""); bus_node_hash_lookup(inst[n].node[p],"", XINSERT, 1, sig_type,"", "",""); } else { my_strdup(_ALLOC_ID_, &sig_type, get_tok_value(xctx->sym[inst[i].ptr].rect[GENERICLAYER][j-rects].prop_ptr, "sig_type", 0)); /* insert generic label in hash table as a port so it will not */ /* be declared as a signal in the vhdl netlist. this is a workaround */ /* that should be fixed 25092001 */ bus_node_hash_lookup(inst[n].node[p], get_tok_value(xctx->sym[inst[i].ptr].rect[GENERICLAYER][j-rects].prop_ptr, "dir",0), XINSERT, 1, sig_type,"", "",""); } } /* end if(inst[iptr->n].node[iptr->pin] != NULL) */ } /* end if( (iptr->x0==x0) && (iptr->y0==y0) ) */ } /* end for(iptr=xctx->instpin_spatial_table[sqx][sqy]; iptr; iptr = iptr ->next) */ } /* end for(j=0;j0) */ } /* end if(type not a label nor pin)... */ } /* end for(i...) */ if(type) my_free(_ALLOC_ID_, &type); } static int signal_short( const char *tag, const char *n1, const char *n2) { int err = 0; char str[2048]; if( xctx->netlist_count && n1 && n2 && strcmp( n1, n2) ) { err |= 1; my_snprintf(str, S(str), "Error: %s shorted: %s - %s", tag, n1, n2); dbg(1, "signal_short(): signal_short: shorted: %s - %s", n1, n2); statusmsg(str,2); if(!xctx->netlist_count) { bus_hilight_hash_lookup(n1, xctx->hilight_color, XINSERT); if(tclgetboolvar("incr_hilight")) incr_hilight_color(); bus_hilight_hash_lookup(n2, xctx->hilight_color, XINSERT); if(tclgetboolvar("incr_hilight")) incr_hilight_color(); } } return err; } static void set_inst_node(int i, int j, const char *node) { xInstance * const inst = xctx->inst; int inst_mult; xRect *rect = (inst[i].ptr + xctx->sym)->rect[PINLAYER]; int skip; if(!inst[i].node) return; dbg(1, "set_inst_node(): inst %s pin %d <-- %s\n", inst[i].instname, j, node); expandlabel(inst[i].instname, &inst_mult); my_strdup(_ALLOC_ID_, &inst[i].node[j], node); skip = skip_instance(i, 1, netlist_lvs_ignore); if(!for_netlist || skip) { bus_node_hash_lookup(inst[i].node[j],"", XINSERT, 0,"","","",""); } else { const char *dir = get_tok_value(rect[j].prop_ptr, "dir",0); bus_node_hash_lookup(inst[i].node[j], dir, XINSERT, 0,"","","",""); } if(node && node[0] == '#') { /* update multilicity of unnamed node */ int pin_mult; expandlabel(get_tok_value(rect[j].prop_ptr, "name", 0), &pin_mult); get_unnamed_node(2, pin_mult * inst_mult, atoi((inst[i].node[j]) + 4)); } } static int instcheck(int n, int p); static int name_attached_inst_to_net(int k, int sqx, int sqy) { int err = 0; xInstance * const inst = xctx->inst; xWire * const wire = xctx->wire; Instpinentry *iptr; for(iptr = xctx->instpin_spatial_table[sqx][sqy]; iptr; iptr = iptr->next) { int n = iptr->n; int p = iptr->pin; double x0 = iptr->x0; double y0 = iptr->y0; int rects=(inst[n].ptr+ xctx->sym)->rects[PINLAYER]; if(p >= rects) continue; /* generic pins are handled in name_generics() */ if(!inst[n].node) continue; if(touch(wire[k].x1, wire[k].y1, wire[k].x2, wire[k].y2, x0, y0)) { if(!inst[n].node[p]) { dbg(1, "name_attached_inst_to_net(): inst %s, pin %d <-- %s\n", inst[n].instname, p, wire[k].node ? wire[k].node : ""); set_inst_node(n, p, wire[k].node); err |= instcheck(n, p); } else { if(for_netlist>0) err |= signal_short("net to named instance pin", wire[k].node, inst[n].node[p]); } } } return err; } static int wirecheck(int k) /* recursive routine */ { int err = 0; int tmpi, tmpj, counti, countj, i, j, touches, x1a, x2a, y1a, y2a; double x1, y1, x2, y2; Wireentry *wptr; xWire * const wire = xctx->wire; x1 = wire[k].x1; y1 = wire[k].y1; x2 = wire[k].x2; y2 = wire[k].y2; /* ordered bbox */ RECTORDER(x1, y1, x2, y2); /* calculate square 4 1st bbox point of wire[k] */ x1a = (int)floor(x1 / BOXSIZE); y1a = (int)floor(y1 / BOXSIZE); /* calculate square 4 2nd bbox point of wire[k] */ x2a = (int)floor(x2 / BOXSIZE); y2a = (int)floor(y2 / BOXSIZE); /*loop thru all squares that intersect bbox of wire[k] */ counti = 0; for(i = x1a; i <= x2a && counti < NBOXES; ++i) { ++counti; tmpi = i % NBOXES; if(tmpi < 0) tmpi += NBOXES; countj = 0; for(j = y1a; j <= y2a && countj < NBOXES; ++j) { ++countj; tmpj = j % NBOXES; if(tmpj < 0) tmpj += NBOXES; /*check if wire[k] touches wires in square [tmpi, tmpj] */ for(wptr = xctx->wire_spatial_table[tmpi][tmpj]; wptr; wptr = wptr->next) { int n = wptr->n; if(n == k) { /* itself */ err |= name_attached_inst_to_net(k, tmpi, tmpj); continue; } touches = touch(wire[k].x1, wire[k].y1, wire[k].x2, wire[k].y2, wire[n].x1, wire[n].y1) || touch(wire[k].x1, wire[k].y1, wire[k].x2, wire[k].y2, wire[n].x2, wire[n].y2) || touch(wire[n].x1, wire[n].y1, wire[n].x2, wire[n].y2, wire[k].x1, wire[k].y1) || touch(wire[n].x1, wire[n].y1, wire[n].x2, wire[n].y2, wire[k].x2, wire[k].y2); if( touches ) { if(!wire[n].node) { my_strdup(_ALLOC_ID_, &wire[n].node, wire[k].node); my_strdup(_ALLOC_ID_, &wire[n].prop_ptr, subst_token(wire[n].prop_ptr, "lab", wire[n].node)); err |= name_attached_inst_to_net(n, tmpi, tmpj); err |= wirecheck(n); /* recursive check */ } else { if(for_netlist>0) err |= signal_short("Net to net", wire[n].node, wire[k].node); } } } } } return err; } static int name_attached_nets(double x0, double y0, int sqx, int sqy, const char *node) { int err = 0; xWire * const wire = xctx->wire; Wireentry *wptr; for(wptr = xctx->wire_spatial_table[sqx][sqy]; wptr; wptr = wptr->next) { int n = wptr->n; if(touch(wire[n].x1, wire[n].y1, wire[n].x2, wire[n].y2, x0,y0)) { if(!wire[n].node) { my_strdup(_ALLOC_ID_, &wire[n].node, node); my_strdup(_ALLOC_ID_, &wire[n].prop_ptr, subst_token(wire[n].prop_ptr, "lab", wire[n].node)); err |= wirecheck(n); } else { if(for_netlist>0) err |= signal_short("Net", wire[n].node, node); } } } return err; } static int name_attached_inst(int i, double x0, double y0, int sqx, int sqy, const char *node) { int err = 0; xInstance * const inst = xctx->inst; Instpinentry *iptr; for(iptr = xctx->instpin_spatial_table[sqx][sqy]; iptr; iptr = iptr->next) { int n = iptr->n; int p = iptr->pin; int rects=(inst[n].ptr+ xctx->sym)->rects[PINLAYER]; if(i == n) continue; /* itself -> skip */ if(p >= rects) continue; /* generic pins are handled in name_generics() */ if(!inst[n].node) continue; if(iptr->x0 == x0 && iptr->y0 == y0 ) { if(!inst[n].node[p]) { set_inst_node(n, p, node); err |= instcheck(n, p); } else { if(for_netlist>0) err |= signal_short("Instance pin", inst[n].node[p], node); } } } return err; } int shorted_instance(int i, int lvs_ignore) { xInstance * const inst = xctx->inst; xSymbol * const sym = xctx->sym; int shorted = 0; if(inst[i].ptr < 0) shorted = 0; else if(lvs_ignore) { if((inst[i].flags & LVS_IGNORE_SHORT) || (sym[inst[i].ptr].flags & LVS_IGNORE_SHORT) ) shorted = 1; } else if(xctx->netlist_type == CAD_SPICE_NETLIST) { if((inst[i].flags & SPICE_SHORT) || (sym[inst[i].ptr].flags & SPICE_SHORT) ) shorted = 1; } else if(xctx->netlist_type == CAD_VERILOG_NETLIST) { if((inst[i].flags & VERILOG_SHORT) || (sym[inst[i].ptr].flags & VERILOG_SHORT) ) shorted = 1; } else if(xctx->netlist_type == CAD_VHDL_NETLIST) { if((inst[i].flags & VHDL_SHORT) || (sym[inst[i].ptr].flags & VHDL_SHORT) ) shorted = 1; } else if(xctx->netlist_type == CAD_TEDAX_NETLIST) if((inst[i].flags & TEDAX_SHORT) || (sym[inst[i].ptr].flags & TEDAX_SHORT) ) shorted = 1; return shorted; } static int skip_instance2(int i, int lvs_ignore, int mask) { int skip = 0; if(xctx->inst[i].flags & mask) skip = 1; else if(xctx->sym[xctx->inst[i].ptr].flags & mask) skip = 1; else if(lvs_ignore && (xctx->inst[i].flags & LVS_IGNORE)) skip = 1; else if(lvs_ignore && (xctx->sym[xctx->inst[i].ptr].flags & LVS_IGNORE)) skip = 1; return skip; } int skip_instance(int i, int skip_short, int lvs_ignore) { int skip = 0; if(xctx->inst[i].ptr < 0) skip = 1; else if(xctx->netlist_type == CAD_SPICE_NETLIST) skip = skip_instance2(i, lvs_ignore, (skip_short ? SPICE_SHORT : 0) | SPICE_IGNORE); else if(xctx->netlist_type == CAD_VERILOG_NETLIST) skip = skip_instance2(i, lvs_ignore, (skip_short ? VERILOG_SHORT : 0) | VERILOG_IGNORE); else if(xctx->netlist_type == CAD_VHDL_NETLIST) skip = skip_instance2(i, lvs_ignore, (skip_short ? VHDL_SHORT : 0) | VHDL_IGNORE); else if(xctx->netlist_type == CAD_TEDAX_NETLIST) skip = skip_instance2(i, lvs_ignore, (skip_short ? TEDAX_SHORT : 0) | TEDAX_IGNORE); else skip = 0; dbg(1, "skip_instance(): instance %d skip=%d\n", i, skip); return skip; } /* what: * Determine if given "ninst" instance has pass-through pins * 0: initialize * 1: query * 2: cleanup */ static int find_pass_through_symbols(int what, int ninst) { int i, j, k; xInstance * const inst = xctx->inst; int const instances = xctx->instances; Int_hashtable table = {NULL, 0}; static int *pt_symbol = NULL; /* pass-through symbols, symbols with duplicated ports */ int *symtable = NULL; if(what == 0 ) { /* initialize */ pt_symbol = my_calloc(_ALLOC_ID_, xctx->symbols, sizeof(int)); symtable = my_calloc(_ALLOC_ID_, xctx->symbols, sizeof(int)); for(i = 0; i < instances; ++i) { k = inst[i].ptr; if( k < 0 || symtable[k] ) continue; symtable[k] =1; int_hash_init(&table, 37); for(j = 0; j < xctx->sym[k].rects[PINLAYER]; ++j) { const char *pin_name = get_tok_value(xctx->sym[k].rect[PINLAYER][j].prop_ptr, "name", 0); if(int_hash_lookup(&table, pin_name, j, XINSERT_NOREPLACE)) { dbg(1, " pass thru symbol found\n"); pt_symbol[k] = 1; } } int_hash_free(&table); if(pt_symbol[k]) dbg(1, "duplicated pins: %s\n", xctx->sym[k].name); } my_free(_ALLOC_ID_, &symtable); } else if(what ==1) { /* query */ k = inst[ninst].ptr; if(k >=0 && pt_symbol[k]) return 1; return 0; } else if(what ==2) { /* cleanup */ my_free(_ALLOC_ID_, &pt_symbol); } return -1; } /* * Given an instance pin (inst n, pin p) propagate electrical information through * other pins with identical "name" attribute (pass-through symbols) */ static int instcheck(int n, int p) { int err = 0; xInstance * const inst = xctx->inst; xSymbol * const sym = xctx->sym; int j, sqx, sqy; double x0, y0; int rects = xctx->sym[inst[n].ptr].rects[PINLAYER]; int bus_tap = !strcmp(xctx->sym[inst[n].ptr].type, "bus_tap"); int k = inst[n].ptr; int shorted_inst = shorted_instance(n, netlist_lvs_ignore); if(!inst[n].node) return 0; if( xctx->netlist_type == CAD_VERILOG_NETLIST && ((inst[n].flags & VERILOG_IGNORE) || (k >= 0 && (sym[k].flags & VERILOG_IGNORE))) ) return 0; if( xctx->netlist_type == CAD_SPICE_NETLIST && ((inst[n].flags & SPICE_IGNORE) || (k >= 0 && (sym[k].flags & SPICE_IGNORE))) ) return 0; if( xctx->netlist_type == CAD_VHDL_NETLIST && ((inst[n].flags & VHDL_IGNORE) || (k >= 0 &&(sym[k].flags & VHDL_IGNORE))) ) return 0; if( xctx->netlist_type == CAD_TEDAX_NETLIST && ((inst[n].flags & TEDAX_IGNORE) || (k >= 0 && (sym[k].flags & TEDAX_IGNORE))) ) return 0; if( netlist_lvs_ignore && ((inst[n].flags & LVS_IGNORE_OPEN) || (k >= 0 && (sym[k].flags & LVS_IGNORE_OPEN))) ) return 0; /* process bus taps : type = bus_tap * node 1 connects to bus (DATA[15:0]) , node 0 is the tap ([2:0]) */ if(rects > 1 && bus_tap && p == 1) { char *node_base_name = NULL; const char *tap; if(inst[n].node && inst[n].node[0] && inst[n].node[0][0] == '#') { my_free(_ALLOC_ID_, &inst[n].node[0]); /* bus tap forces net name on pin 0 (the tap) */ } /* delete any previously set unnamed net */ if(!inst[n].node[0]) { /* still unnamed */ /* tap = get_tok_value(inst[n].prop_ptr, "lab", 0); */ tap = inst[n].lab; /* Check if this is a bus slice and must be appended to bus base name */ if(tap[0] == '[' || isonlydigit(tap)) { /* find bus basename, from beginning or first character after ',' and ' ' */ char *nptr = strchr(inst[n].node[p], '['); if(nptr) { while(nptr > inst[n].node[p]) { nptr--; if(*nptr == ',') { while(*(++nptr) ==' '); break; } } } else { nptr = inst[n].node[p]; } node_base_name = my_malloc(_ALLOC_ID_, strlen(inst[n].node[p]) + 1); sscanf(nptr, "%[^[]", node_base_name); my_strcat(_ALLOC_ID_, &node_base_name, tap); } else { my_strdup2(_ALLOC_ID_, &node_base_name, tap); } set_inst_node(n, 0, node_base_name); get_inst_pin_coord(n, 0, &x0, &y0); get_square(x0, y0, &sqx, &sqy); err |= name_attached_nets(x0, y0, sqx, sqy, inst[n].node[0]); err |= name_attached_inst(n, x0, y0, sqx, sqy, inst[n].node[0]); } else { if(for_netlist>0) err |= signal_short("Bus tap", inst[n].node[p], inst[n].node[0]); } dbg(1, "instcheck: bus tap node: p=%d, %s, tap=%s\n", p, inst[n].node[p], inst[n].node[0]); my_free(_ALLOC_ID_, &node_base_name); } /* should process only symbols with pass-through pins */ else if(shorted_inst || find_pass_through_symbols(1, n)) { int k = inst[n].ptr; char *pin_name = NULL; my_strdup(_ALLOC_ID_, &pin_name, get_tok_value(xctx->sym[k].rect[PINLAYER][p].prop_ptr, "name", 0)); if(p >= rects) return 1; for(j = 0; j < rects; ++j) { const char *other_pin; if(j == p) continue; if(shorted_inst) { other_pin = get_tok_value(xctx->sym[k].rect[PINLAYER][p].prop_ptr, "name", 0); } else { other_pin = get_tok_value(xctx->sym[k].rect[PINLAYER][j].prop_ptr, "name", 0); } if(!strcmp(other_pin, pin_name)) { dbg(1, "instcheck: inst %s pin %s(%d) <--> pin %s(%d)\n", inst[n].instname, pin_name, p, other_pin, j); dbg(1, "instcheck: node: %s\n", inst[n].node[p]); if(!inst[n].node[j]) { set_inst_node(n, j, inst[n].node[p]); get_inst_pin_coord(n, j, &x0, &y0); get_square(x0, y0, &sqx, &sqy); err |= name_attached_nets(x0, y0, sqx, sqy, inst[n].node[j]); err |= name_attached_inst(n, x0, y0, sqx, sqy, inst[n].node[j]); } else { if(for_netlist>0) err |= signal_short("Pass_through symbol", inst[n].node[p], inst[n].node[j]); } } } my_free(_ALLOC_ID_, &pin_name); } return err; } /* starting from labels, ipins, opins, iopins propagate electrical * nodes to attached nets and instances */ static int name_nodes_of_pins_labels_and_propagate() { int err = 0; int i, sqx, sqy; double x0, y0; int port; char *dir=NULL; char *type=NULL; char *sig_type=NULL; char *verilog_type=NULL; char *value=NULL; char *class=NULL; char *global_node=NULL; int print_erc; xInstance * const inst = xctx->inst; int const instances = xctx->instances; static int startlevel = 0; /* safe to keep even with multiple schematic windows, netlist is not interruptable */ if(xctx->netlist_count == 0 ) startlevel = xctx->currsch; dbg(2, "name_nodes_of_pins_labels_and_propagate(): naming pins from attrs\n"); /* print_erc is 1 the first time prepare_netlist_structs() is called on top level while * doing the netlist, when netlist of sub blocks is completed and toplevel is reloaded * a second prepare_netlist_structs() is called to name unnamed nets, in this second call * print_erc must be set to 0 to avoid double erc printing */ print_erc = (xctx->netlist_count == 0 || startlevel < xctx->currsch) && for_netlist; for (i=0;isym)->type); if(print_erc && (!inst[i].instname || !inst[i].instname[0]) && !get_tok_value(xctx->sym[inst[i].ptr].templ, "name", 0)[0] ) { char str[2048]; if( type && /* list of devices that do not have a name= in template attribute */ strcmp(type, "package") && strcmp(type, "port_attributes") && strcmp(type, "architecture") && strcmp(type, "arch_declarations") && strcmp(type, "attributes") && strcmp(type, "netlist_options") && strcmp(type, "use")) { my_snprintf(str, S(str), "Warning: instance: %s (%s): no name attribute set", inst[i].instname, inst[i].name); statusmsg(str,2); inst[i].color = -PINLAYER; xctx->hilight_nets=1; } } if(print_erc && (!type || !type[0]) ) { char str[2048]; my_snprintf(str, S(str), "Warning: Symbol: %s: no type attribute set", inst[i].name); statusmsg(str,2); inst[i].color = -PINLAYER; xctx->hilight_nets=1; } if(type && inst[i].node && IS_LABEL_OR_PIN(type) ) { /* instance must have a pin! */ #if 0 if(for_netlist) { /* 20150918 skip labels / pins if ignore property specified on instance */ if( xctx->netlist_type == CAD_VERILOG_NETLIST && (inst[i].flags & VERILOG_IGNORE)) continue; if( xctx->netlist_type == CAD_SPICE_NETLIST && (inst[i].flags & SPICE_IGNORE)) continue; if( xctx->netlist_type == CAD_VHDL_NETLIST && (inst[i].flags & VHDL_IGNORE)) continue; if( xctx->netlist_type == CAD_TEDAX_NETLIST && (inst[i].flags & TEDAX_IGNORE)) continue; if( netlist_lvs_ignore && (inst[i].flags & LVS_IGNORE_OPEN)) continue; } #endif port=0; my_strdup2(_ALLOC_ID_, &dir, ""); if(strcmp(type,"label")) { /* instance is a port (not a label) */ port=1; /* 20071204 only define a dir property if instance is not a label */ if(for_netlist) my_strdup2(_ALLOC_ID_, &dir, get_tok_value(xctx->sym[inst[i].ptr].rect[PINLAYER][0].prop_ptr, "dir",0)); } else { /* handle global nodes (global=1 set as symbol property) 28032003 */ my_strdup(_ALLOC_ID_, &global_node,get_tok_value(inst[i].prop_ptr,"global",0)); if(!xctx->tok_size) { my_strdup(_ALLOC_ID_, &global_node,get_tok_value(xctx->sym[inst[i].ptr].prop_ptr,"global",0)); } /*20071204 if instance is a label dont define a dir property for more precise erc checking */ } /* obtain ipin/opin/label signal type (default: std_logic) */ if(for_netlist) { my_strdup(_ALLOC_ID_, &sig_type,get_tok_value(inst[i].prop_ptr,"sig_type",0)); my_strdup(_ALLOC_ID_, &verilog_type,get_tok_value(inst[i].prop_ptr,"verilog_type",0)); my_strdup(_ALLOC_ID_, &value,get_tok_value(inst[i].prop_ptr,"value",0)); my_strdup(_ALLOC_ID_, &class,get_tok_value(inst[i].prop_ptr,"class",0)); } my_strdup(_ALLOC_ID_, &inst[i].node[0], inst[i].lab); if(!(inst[i].node[0])) { my_strdup(_ALLOC_ID_, &inst[i].node[0], get_tok_value(xctx->sym[inst[i].ptr].templ, "lab",0)); dbg(1, "name_nodes_of_pins_labels_and_propagate(): no lab attr on instance, pick from symbol: %s\n", inst[i].node[0]); } /* handle global nodes (global=1 set as symbol property) 28032003 */ if(!strcmp(type,"label") && global_node && !strboolcmp(global_node, "true")) { dbg(1, "name_nodes_of_pins_labels_and_propagate(): global node: %s\n",inst[i].node[0]); record_global_node(1,NULL, inst[i].node[0]); } /* do not count multiple labels/pins with same name */ bus_node_hash_lookup(inst[i].node[0], /* insert node in hash table */ dir, XINSERT, port, sig_type, verilog_type, value, class); get_inst_pin_coord(i, 0, &x0, &y0); get_square(x0, y0, &sqx, &sqy); /* name nets that touch ioin opin alias instances */ err |= name_attached_nets(x0, y0, sqx, sqy, inst[i].node[0]); /* name instances that touch ioin opin alias instances */ err |= name_attached_inst(i, x0, y0, sqx, sqy, inst[i].node[0]); } /* if(type && ... */ } /* for(i=0;iwire[i].node, tmp_str); my_strdup(_ALLOC_ID_, &xctx->wire[i].prop_ptr, subst_token(xctx->wire[i].prop_ptr, "lab", tmp_str)); /* insert unnamed wire name in hash table */ bus_node_hash_lookup(tmp_str, "", XINSERT, 0,"","","",""); err |= wirecheck(i); return err; } static int name_unlabeled_nets() { int err = 0; int i; /* name nets that do not touch ipin opin alias instances */ dbg(2, "name_unlabeled_nets(): naming nets that dont touch labels\n"); for (i = 0; i < xctx->wires; ++i) { if(xctx->wire[i].node == NULL) { err |= set_unnamed_net(i); } } return err; } static int set_unnamed_inst(int i, int j) { int err = 0; char tmp_str[30]; xInstance * const inst = xctx->inst; int sqx, sqy; double x0, y0; my_snprintf(tmp_str, S(tmp_str), "#net%d", get_unnamed_node(1,0,0)); dbg(1, "set_unnamed_inst(): inst %s pin %d, net %s\n", inst[i].instname, j, tmp_str); set_inst_node(i, j, tmp_str); get_inst_pin_coord(i, j, &x0, &y0); get_square(x0, y0, &sqx, &sqy); if(inst[i].node && inst[i].node[j]) err |= name_attached_inst(i, x0, y0, sqx, sqy, inst[i].node[j]); return err; } static int name_unlabeled_instances() { int err = 0; int i, j; xInstance * const inst = xctx->inst; int const instances = xctx->instances; int rects; /* name nets that do not touch ipin opin alias instances */ #if 0 /* does not work */ int all_unconn; for (i = 0; i < instances; ++i) { if(!inst[i].node) continue; if(skip_instance(i, 0, netlist_lvs_ignore)) continue; if(inst[i].ptr != -1) { rects=(inst[i].ptr+ xctx->sym)->rects[PINLAYER]; all_unconn = 0; for(j = 0; j < rects; ++j) { if(inst[i].node[j] == NULL) { all_unconn++; } } if(rects > 0 && all_unconn == rects && for_netlist > 0 && xctx->netlist_count > 0) { char str[2048]; my_snprintf(str, S(str), "Error: %s all pins disconnected,", inst[i].instname); statusmsg(str,2); xctx->inst[i].color = -PINLAYER; xctx->hilight_nets=1; } } } #endif dbg(2, "name_unlabeled_instances(): naming nets that dont touch labels\n"); for (i = 0; i < instances; ++i) { if(!inst[i].node) continue; if(skip_instance(i, 0, netlist_lvs_ignore)) continue; if(inst[i].ptr != -1) { rects=(inst[i].ptr+ xctx->sym)->rects[PINLAYER]; for(j = 0; j < rects; ++j) { if(inst[i].node[j] == NULL) { err |= set_unnamed_inst(i, j); } } } } return err; } static int reset_node_data_and_rehash() { int err = 0; int i,j, rects; xInstance * const inst = xctx->inst; int const instances = xctx->instances; /* reset wire & inst node labels */ dbg(2, "reset_node_data_and_rehash(): rehashing wires and instance pins in spatial hash table\n"); hash_wires(); for (i=0;isym)->rects[PINLAYER] + (inst[i].ptr+ xctx->sym)->rects[GENERICLAYER]; if(rects > 0) { inst[i].node = my_malloc(_ALLOC_ID_, sizeof(char *) * rects); for (j=0;j0 && xctx->prep_net_structs) return 0; else if(!for_netlist && xctx->prep_hi_structs) return 0; dbg(1, "prepare_netlist_structs(): extraction: %s\n", xctx->sch[xctx->currsch]); reset_caches(); /* update cached flags: necessary if some tcleval() is used for cached attrs */ set_modify(-2); /* to reset floater cached values */ /* delete instance pins spatial hash, wires spatial hash, node_hash, wires and inst nodes.*/ if(for_netlist) { my_snprintf(nn, S(nn), "-----------%s", xctx->sch[xctx->currsch]); statusmsg(nn,2); } delete_netlist_structs(); free_simdata(); /* invalidate simulation cache */ err |= reset_node_data_and_rehash(); get_unnamed_node(0,0,0); /*initializes node multiplicity data struct */ find_pass_through_symbols(0, 0); /* initialize data struct to quickly find pass-through syms */ err |= name_nodes_of_pins_labels_and_propagate(); err |= name_unlabeled_nets(); err |= name_unlabeled_instances(); name_generics(); /* name_non_label_inst_pins(); */ find_pass_through_symbols(2, 0); /* cleanup data */ rebuild_selected_array(); if(for_netlist>0) { xctx->prep_net_structs=1; xctx->prep_hi_structs=1; } else xctx->prep_hi_structs=1; dbg(1, "prepare_netlist_structs(): returning\n"); /* avoid below call: it in turn calls prepare_netlist_structs(), too many side effects */ /* propagate_hilights(1, 0, XINSERT_NOREPLACE);*/ return err; } void delete_inst_node(int i) { int j, rects; if( xctx->inst[i].ptr == -1 || !xctx->inst[i].node) return; rects = (xctx->inst[i].ptr+ xctx->sym)->rects[PINLAYER] + (xctx->inst[i].ptr+ xctx->sym)->rects[GENERICLAYER]; if( rects > 0 ) { for(j=0;j< rects ; ++j) my_free(_ALLOC_ID_, &xctx->inst[i].node[j]); my_free(_ALLOC_ID_, &xctx->inst[i].node ); } } void delete_netlist_structs(void) { int i; /* erase node data structures */ dbg(1, "delete_netlist_structs(): begin erasing\n"); for(i=0;iinstances; ++i) { delete_inst_node(i); } for(i=0;iwires; ++i) { my_free(_ALLOC_ID_, &xctx->wire[i].node); } /* erase inst and wire topological hash tables */ del_inst_pin_table(); node_hash_free(); dbg(1, "delete_netlist_structs(): end erasing\n"); xctx->prep_net_structs=0; xctx->prep_hi_structs=0; } int warning_overlapped_symbols(int sel) { int err = 0; int i; Int_hashtable table = {NULL, 0}; Int_hashentry *found; char str[2048]; char s[512]; int_hash_init(&table, HASHSIZE); for(i = 0; i < xctx->instances; ++i) { dbg(1, "instance:%s: %s\n", xctx->inst[i].instname, xctx->inst[i].name); my_snprintf(s, S(s), "%g %g %g %g", xctx->inst[i].xx1, xctx->inst[i].yy1, xctx->inst[i].xx2, xctx->inst[i].yy2); dbg(1, " bbox: %g %g %g %g\n", xctx->inst[i].xx1, xctx->inst[i].yy1, xctx->inst[i].xx2, xctx->inst[i].yy2); dbg(1, " s=%s\n", s); found = int_hash_lookup(&table, s, i, XINSERT_NOREPLACE); if(found) { if(sel == 0) { xctx->inst[i].color = -PINLAYER; xctx->hilight_nets=1; } else { xctx->inst[i].sel = SELECTED; set_first_sel(ELEMENT, i, 0); xctx->need_reb_sel_arr = 1; } my_snprintf(str, S(str), "Error: overlapped instance found: %s(%s) -> %s\n", xctx->inst[i].instname, xctx->inst[i].name, xctx->inst[found->value].instname); statusmsg(str,2); err |= 1; } } int_hash_free(&table); if(sel && xctx->need_reb_sel_arr) rebuild_selected_array(); return err; } /* all: -1: check all symbols, otherwise check only indicated symbol */ int sym_vs_sch_pins(int all) { int err = 0; char **lab_array =NULL; int lab_array_size = 0; int i, j, k, symbol, pin_cnt=0, pin_match, mult; struct stat buf; char name[PATH_MAX]; char *type = NULL; char *tmp = NULL; char *lab=NULL; char *pin_name=NULL; char *pin_dir=NULL; double tmpd; FILE *fd; int tmpi; short tmps; int endfile; char tag[1]; char filename[PATH_MAX]; char f_version[100]; int start = 0; int end = xctx->symbols; int n_syms = xctx->symbols; if(all >= 0 && all < xctx->symbols) { start = all; end = all + 1; } for(i = start; i < end; ++i) { if( xctx->sym[i].type && !strcmp(xctx->sym[i].type,"subcircuit")) { int rects = xctx->sym[i].rects[PINLAYER]; /* Determine if symbol has pass-through pins (pins with identical name) * if any is found do not check with schematic */ Int_hashtable pin_table = {NULL, 0}; int p; int unique_pins = 0; int_hash_init(&pin_table, HASHSIZE); for(p = 0; p < rects; p++) { const char *pname = get_tok_value(xctx->sym[i].rect[PINLAYER][p].prop_ptr, "name", 0); if(!int_hash_lookup(&pin_table, pname, i, XINSERT_NOREPLACE)) { unique_pins++; } } dbg(1, "%s: rects=%d, unique_pins=%d\n", xctx->sym[i].name, rects, unique_pins); int_hash_free(&pin_table); /* pass through symbols, duplicated pins: do not check with schematic */ if(rects > unique_pins) continue; get_sch_from_sym(filename, xctx->sym + i, -1, 0); if(!stat(filename, &buf)) { fd = fopen(filename, "r"); pin_cnt = 0; endfile = 0; f_version[0] = '\0'; while(!endfile) { if(fscanf(fd," %c",tag)==EOF) break; switch(tag[0]) { case 'v': load_ascii_string(&tmp, fd); my_snprintf(f_version, S(f_version), "%s", get_tok_value(tmp, "file_version", 0)); break; case 'E': case 'S': case 'V': case 'K': case 'G': load_ascii_string(&tmp, fd); break; case '#': read_line(fd, 1); break; case 'F': /* extension for future symbol floater labels */ read_line(fd, 1); break; case 'L': case 'B': if(fscanf(fd, "%d",&tmpi)< 1) { fprintf(errfp,"sym_vs_sch_pins(): WARNING: missing fields for LINE/BOX object, ignoring\n"); read_line(fd, 0); break; } case 'N': if(fscanf(fd, "%lf %lf %lf %lf ",&tmpd, &tmpd, &tmpd, &tmpd) < 4) { fprintf(errfp,"sym_vs_sch_pins(): WARNING: missing fields for LINE/BOX object, ignoring\n"); read_line(fd, 0); break; } load_ascii_string(&tmp, fd); break; case 'P': if(fscanf(fd, "%d %d",&tmpi, &tmpi)<2) { fprintf(errfp,"sym_vs_sch_pins(): WARNING: missing fields for POLYGON object, ignoring.\n"); read_line(fd, 0); break; } for(j=0;jsym[symbol].type); if(type && IS_PIN(type)) { my_strdup(_ALLOC_ID_, &lab, expandlabel(get_tok_value(tmp, "lab", 0), &mult)); if(pin_cnt >= lab_array_size) { lab_array_size += CADCHUNKALLOC; my_realloc(_ALLOC_ID_, &lab_array, lab_array_size * sizeof(char *)); } lab_array[pin_cnt] = NULL; my_strdup(_ALLOC_ID_, &(lab_array[pin_cnt]), lab); pin_cnt++; pin_match = 0; for(j=0; j < rects; ++j) { my_strdup(_ALLOC_ID_, &pin_name, expandlabel(get_tok_value(xctx->sym[i].rect[PINLAYER][j].prop_ptr, "name", 0), &mult)); my_strdup(_ALLOC_ID_, &pin_dir, get_tok_value(xctx->sym[i].rect[PINLAYER][j].prop_ptr, "dir", 0)); if( pin_name && !strcmp(pin_name, lab)) { if(!pin_dir) { char str[2048]; my_snprintf(str, S(str), "Error: Symbol %s: No direction given for pin %s", xctx->sym[i].name, lab); statusmsg(str,2); my_snprintf(str, S(str), " %s <--> ???", type); statusmsg(str,2); err |= 1; } else if(!( ( !strcmp(type, "ipin") && !strcmp(pin_dir, "in") ) || ( !strcmp(type, "opin") && !strcmp(pin_dir, "out") ) || ( !strcmp(type, "iopin") && !strcmp(pin_dir, "inout") ) ) ) { char str[2048]; my_snprintf(str, S(str), "Error: Symbol %s: Unmatched subcircuit schematic pin direction: %s", xctx->sym[i].name, lab); statusmsg(str,2); my_snprintf(str, S(str), " %s <--> %s", type, pin_dir); statusmsg(str,2); err |= 1; for(j = 0; j < xctx->instances; ++j) { if(!xctx->x_strcmp(get_sym_name(j, 9999, 1, 0), xctx->sym[i].name)) { xctx->inst[j].color = -PINLAYER; xctx->hilight_nets=1; } } } pin_match++; break; } } if(!pin_match) { char str[2048]; /* fprintf(errfp, " unmatched sch / sym pin: %s\n", lab); */ my_snprintf(str, S(str), "Error: Symbol %s: schematic pin: %s not in symbol", xctx->sym[i].name, lab); statusmsg(str,2); err |= 1; for(j = 0; j < xctx->instances; ++j) { dbg(1, "inst.name=%s, sym.name=%s\n", tcl_hook2(xctx->inst[j].name), xctx->sym[i].name); if(!xctx->x_strcmp(get_sym_name(j, 9999, 1, 0), xctx->sym[i].name)) { xctx->inst[j].color = -PINLAYER; xctx->hilight_nets=1; } } } } break; case '[': load_sym_def(name, fd); break; case ']': read_line(fd, 0); endfile=1; break; default: if( tag[0] == '{' ) ungetc(tag[0], fd); read_record(tag[0], fd, 0); break; } read_line(fd, 0); /* discard any remaining characters till (but not including) newline */ if(!f_version[0]) { my_snprintf(f_version, S(f_version), "1.0"); dbg(1, "sym_vs_sch_pins(): no file_version, assuming file_version=%s\n", f_version); } } /* while(!endfile) */ fclose(fd); if(pin_cnt != rects) { char str[2048]; my_snprintf(str, S(str), "Error: Symbol %s has %d pins, its schematic has %d pins", xctx->sym[i].name, rects, pin_cnt); statusmsg(str,2); err |= 1; for(j = 0; j < xctx->instances; ++j) { if(!xctx->x_strcmp(get_sym_name(j, 9999, 1, 0), xctx->sym[i].name)) { xctx->inst[j].color = -PINLAYER; xctx->hilight_nets=1; } } } for(j=0; j < rects; ++j) { my_strdup(_ALLOC_ID_, &pin_name, expandlabel(get_tok_value(xctx->sym[i].rect[PINLAYER][j].prop_ptr, "name", 0), &mult)); pin_match = 0; for(k=0; ksym[i].name, pin_name ? pin_name : ""); statusmsg(str,2); err |= 1; for(k = 0; k < xctx->instances; ++k) { if(!xctx->x_strcmp(get_sym_name(k, 9999, 1, 0), xctx->sym[i].name)) { xctx->inst[k].color = -PINLAYER; xctx->hilight_nets=1; } } } } } if(lab_array_size) { for(k=0;ksymbols > n_syms) remove_symbol(xctx->symbols - 1); return err; }