From 590bf8b6ecf71e18725ac1f4da23adac44f176d9 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Wed, 12 Apr 2023 18:28:19 +0200 Subject: [PATCH] add instance based "schematic=..." attribute. This allows multiple instances of the same symbol to have different implementations. --- src/actions.c | 81 ++++++++++++++++++++++++++++++++++++++++--- src/netlist.c | 2 +- src/psprint.c | 2 +- src/spice_netlist.c | 13 ++++--- src/tedax_netlist.c | 2 +- src/token.c | 35 ++++++++++--------- src/verilog_netlist.c | 4 ++- src/vhdl_netlist.c | 10 ++++-- src/xschem.h | 4 ++- 9 files changed, 121 insertions(+), 32 deletions(-) diff --git a/src/actions.c b/src/actions.c index ddd394c4..6ba7aed1 100644 --- a/src/actions.c +++ b/src/actions.c @@ -1144,7 +1144,7 @@ void schematic_in_new_window(int new_process) "primitive" ) ) return; - get_sch_from_sym(filename, xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym); + get_sch_from_sym(filename, xctx->inst[xctx->sel_array[0].n].ptr+ xctx->sym, xctx->sel_array[0].n); if(!check_loaded(filename, win_path)) { if(new_process) new_xschem_process(filename, 0); else new_schematic("create", NULL, filename); @@ -1179,19 +1179,85 @@ void launcher(void) } } -void get_sch_from_sym(char *filename, xSymbol *sym) +const char *get_sym_name(int inst, int ext) +{ + const char *sym, *sch; + + sch = get_tok_value(xctx->inst[inst].prop_ptr, "schematic", 0); + if(xctx->tok_size) { /* token exists */ + if(ext) sym = get_cell_w_ext(add_ext(rel_sym_path(sch), ".sym"), 0); + else sym = skip_dir(add_ext(rel_sym_path(sch), ".sym")); + } + else if(ext) { + sym = get_cell_w_ext(xctx->inst[inst].name, 0); + } else { + sym = skip_dir(xctx->inst[inst].name); + } + return sym; +} + + +/* what = 1: start + what = 0 : end +*/ +void get_additional_symbols(int what) +{ + int i; + static int num_syms; /* no context switch between start and end so it is safe */ + Int_hashentry *found; + Int_hashtable sym_table = {NULL, 0}; + int_hash_init(&sym_table, HASHSIZE); + + + if(what == 1) { /* start */ + num_syms = xctx->symbols; + for(i = 0; i < xctx->symbols; ++i) { + int_hash_lookup(&sym_table, xctx->sym[i].name, i, XINSERT); + } + /* handle instances with "schematic=..." attribute (polymorphic symbols) */ + for(i=0;iinstances; ++i) { + const char *sch = get_tok_value(xctx->inst[i].prop_ptr,"schematic",0); + if(xctx->tok_size) { /* token exists */ + const char *sym = add_ext(rel_sym_path(sch), ".sym"); + int j; + found = int_hash_lookup(&sym_table, sym, 0, XLOOKUP); + if(!found) { + j = xctx->symbols; + int_hash_lookup(&sym_table, sym, j, XINSERT); + dbg(1, "get_additional_symbols(): adding symbol %s\n", sym); + check_symbol_storage(); + copy_symbol(&xctx->sym[j], xctx->inst[i].ptr + xctx->sym); + my_strdup(_ALLOC_ID_, &xctx->sym[j].name, sym); + xctx->symbols++; + } else { + j = found->value; + } + } + } + int_hash_free(&sym_table); + } else { /* end */ + for(i = xctx->symbols - 1; i >= num_syms; --i) { + remove_symbol(i); + } + xctx->symbols = num_syms; + } +} + +void get_sch_from_sym(char *filename, xSymbol *sym, int inst) { char *sch = NULL; char *str_tmp = NULL; char *ptr; int web_url = 0; + struct stat buf; /* get sch/sym name from parent schematic downloaded from web */ if( strstr(xctx->current_dirname, "http://") == xctx->current_dirname || strstr(xctx->current_dirname, "https://") == xctx->current_dirname) { web_url = 1; } - my_strdup2(_ALLOC_ID_, &str_tmp, get_tok_value(sym->prop_ptr, "schematic", 2)); + if(inst >= 0) my_strdup(_ALLOC_ID_, &str_tmp, get_tok_value(xctx->inst[inst].prop_ptr, "schematic", 2)); + if(!str_tmp) my_strdup2(_ALLOC_ID_, &str_tmp, get_tok_value(sym->prop_ptr, "schematic", 2)); if(str_tmp[0]) { /* @symname in schematic attribute will be replaced with symbol name */ if( (ptr = strstr(str_tmp, "@symname"))) { @@ -1218,7 +1284,12 @@ void get_sch_from_sym(char *filename, xSymbol *sym) } else { /* for schematics referenced from web symbols do not build absolute path */ if(web_url) my_strncpy(filename, add_ext(sym->name, ".sch"), PATH_MAX); - else my_strncpy(filename, add_ext(abs_sym_path(sym->name, ""), ".sch"), PATH_MAX); + else { + if(!stat(abs_sym_path(sym->name, ""), &buf)) /* symbol exists. pretend schematic exists too ... */ + my_strncpy(filename, add_ext(abs_sym_path(sym->name, ""), ".sch"), PATH_MAX); + else /* ... symbol does not exist (instances with schematic=... attr) so can not pretend that */ + my_strncpy(filename, abs_sym_path(sym->name, ".sch"), PATH_MAX); + } } } @@ -1343,7 +1414,7 @@ int descend_schematic(int instnumber) hilight_child_pins(); unselect_all(1); - get_sch_from_sym(filename, xctx->inst[n].ptr+ xctx->sym); + get_sch_from_sym(filename, xctx->inst[n].ptr+ xctx->sym, n); dbg(1, "descend_schematic(): filename=%s\n", filename); /* we are descending from a parent schematic downloaded from the web */ remove_symbols(); diff --git a/src/netlist.c b/src/netlist.c index a4abd0d8..51277665 100644 --- a/src/netlist.c +++ b/src/netlist.c @@ -1253,7 +1253,7 @@ int sym_vs_sch_pins() { if( xctx->sym[i].type && !strcmp(xctx->sym[i].type,"subcircuit")) { rects = xctx->sym[i].rects[PINLAYER]; - get_sch_from_sym(filename, xctx->sym + i); + get_sch_from_sym(filename, xctx->sym + i, -1); if(!stat(filename, &buf)) { fd = fopen(filename, "r"); pin_cnt = 0; diff --git a/src/psprint.c b/src/psprint.c index f9c7d2a5..205c8ac5 100644 --- a/src/psprint.c +++ b/src/psprint.c @@ -825,7 +825,7 @@ static void ps_draw_symbol(int n,int layer, int what, short tmp_flip, short rot, "/Subtype /Link " "/ANN pdfmark\n", x1, y1, x2, y2, - add_ext(skip_dir(xctx->inst[n].name), ".sch")); + add_ext(get_sym_name(n, 0), ".sch")); } } } diff --git a/src/spice_netlist.c b/src/spice_netlist.c index e594c9fc..6a4c7d6c 100644 --- a/src/spice_netlist.c +++ b/src/spice_netlist.c @@ -72,6 +72,7 @@ void hier_psprint(char **res, int what) /* netlister driver */ xctx->sch_path_hash[xctx->currsch+1] = 0; xctx->currsch++; subckt_name=NULL; + get_additional_symbols(1); for(i=0;isymbols; ++i) { int flag; @@ -87,7 +88,7 @@ void hier_psprint(char **res, int what) /* netlister driver */ if (str_hash_lookup(&subckt_table, subckt_name, "", XLOOKUP)==NULL) { str_hash_lookup(&subckt_table, subckt_name, "", XINSERT); - get_sch_from_sym(filename, xctx->sym + i); + get_sch_from_sym(filename, xctx->sym + i, -1); if(!stat(filename, &buf)) { /* for printing we go down to bottom regardless of spice_stop attribute */ load_schematic(1,filename, 0, 1); @@ -104,6 +105,7 @@ void hier_psprint(char **res, int what) /* netlister driver */ } } } + get_additional_symbols(0); my_free(_ALLOC_ID_, &abs_path); str_hash_free(&subckt_table); my_free(_ALLOC_ID_, &subckt_name); @@ -268,6 +270,7 @@ int global_spice_netlist(int global) /* netlister driver */ } else { my_snprintf(cellname, S(cellname), "%s.spice", skip_dir(xctx->sch[xctx->currsch])); } + first = 0; for(i=0;iinstances; ++i) /* print netlist_commands of top level cell with 'place=header' property */ { @@ -399,6 +402,7 @@ int global_spice_netlist(int global) /* netlister driver */ dbg(1, "global_spice_netlist(): last defined symbol=%d\n",xctx->symbols); subckt_name=NULL; + get_additional_symbols(1); for(i=0;isymbols; ++i) { if( strcmp(get_tok_value(xctx->sym[i].prop_ptr,"spice_ignore",0),"true")==0 ) continue; @@ -420,8 +424,9 @@ int global_spice_netlist(int global) /* netlister driver */ err |= spice_block_netlist(fd, i); } } - my_free(_ALLOC_ID_, &abs_path); } + my_free(_ALLOC_ID_, &abs_path); + get_additional_symbols(0); str_hash_free(&subckt_table); my_free(_ALLOC_ID_, &subckt_name); /*clear_drawing(); */ @@ -533,8 +538,8 @@ int spice_block_netlist(FILE *fd, int i) spice_stop=1; else spice_stop=0; - get_sch_from_sym(filename, xctx->sym + i); - + get_sch_from_sym(filename, xctx->sym + i, -1); + dbg(1, "spice_block_netlist(): filename=%s\n", filename); if(split_f) { my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d", tclgetvar("netlist_dir"), skip_dir(xctx->sym[i].name), getpid()); diff --git a/src/tedax_netlist.c b/src/tedax_netlist.c index c29b2fe1..da8c76f7 100644 --- a/src/tedax_netlist.c +++ b/src/tedax_netlist.c @@ -86,7 +86,7 @@ static int tedax_block_netlist(FILE *fd, int i) tedax_stop=1; else tedax_stop=0; - get_sch_from_sym(filename, xctx->sym + i); + get_sch_from_sym(filename, xctx->sym + i, -1); fprintf(fd, "\n# expanding symbol: %s # of pins=%d\n", xctx->sym[i].name,xctx->sym[i].rects[PINLAYER] ); diff --git a/src/token.c b/src/token.c index 895d91bf..eea7fbf0 100644 --- a/src/token.c +++ b/src/token.c @@ -787,11 +787,11 @@ static void print_vhdl_primitive(FILE *fd, int inst) /* netlist primitives, 200 else if(strcmp(token,"@symname")==0) /* of course symname must not be present */ /* in hash table */ { - fprintf( fd, "%s",skip_dir(xctx->inst[inst].name) ); + fputs(get_sym_name(inst, 0), fd); } else if (strcmp(token,"@symname_ext")==0) { - fputs(get_cell_w_ext(xctx->inst[inst].name, 0), fd); + fputs(get_sym_name(inst, 1), fd); } else if(strcmp(token,"@schname_ext")==0) /* of course schname must not be present */ /* in hash table */ @@ -1061,6 +1061,7 @@ const char *get_trailing_path(const char *str, int no_of_dir, int skip_ext) size_t ext_pos, dir_pos; int n_ext, n_dir, c, i; + if(str == NULL) return NULL; my_strncpy(s, str, S(s)); len = strlen(s); @@ -1161,9 +1162,9 @@ void print_vhdl_element(FILE *fd, int inst) /* print instance name and subckt */ dbg(2, "print_vhdl_element(): printing inst name & subcircuit name\n"); if( (lab = expandlabel(name, &tmp)) != NULL) - fprintf(fd, "%d %s : %s\n", tmp, lab, skip_dir(xctx->inst[inst].name) ); + fprintf(fd, "%d %s : %s\n", tmp, lab, get_sym_name(inst, 0) ); else /* name in some strange format, probably an error */ - fprintf(fd, "1 %s : %s\n", name, skip_dir(xctx->inst[inst].name) ); + fprintf(fd, "1 %s : %s\n", name, get_sym_name(inst, 0) ); dbg(2, "print_vhdl_element(): printing generics passed as properties\n"); @@ -1795,7 +1796,7 @@ int print_spice_element(FILE *fd, int inst) } else if (strcmp(token,"@symname")==0) /* of course symname must not be present in attributes */ { - const char *s = skip_dir(xctx->inst[inst].name); + const char *s = get_sym_name(inst, 0); tmp = strlen(s) +100 ; /* always make room for some extra chars * so 1-char writes to result do not need reallocs */ STR_ALLOC(&result, tmp + result_pos, &size); @@ -1804,7 +1805,7 @@ int print_spice_element(FILE *fd, int inst) } else if (strcmp(token,"@symname_ext")==0) /* of course symname must not be present in attributes */ { - const char *s = get_cell_w_ext(xctx->inst[inst].name, 0); + const char *s = get_sym_name(inst, 1); tmp = strlen(s) +100 ; /* always make room for some extra chars * so 1-char writes to result do not need reallocs */ STR_ALLOC(&result, tmp + result_pos, &size); @@ -2025,7 +2026,7 @@ void print_tedax_element(FILE *fd, int inst) int n; Int_hashtable table={NULL, 0}; subcircuit = 1; - fprintf(fd, "__subcircuit__ %s %s\n", skip_dir(xctx->inst[inst].name), xctx->inst[inst].instname); + fprintf(fd, "__subcircuit__ %s %s\n", get_sym_name(inst, 0), xctx->inst[inst].instname); int_hash_init(&table, 37); for(i=0;iinst[inst].name),fd); + fputs(get_sym_name(inst, 0), fd); } else if (strcmp(token,"@symname_ext")==0) { - fputs(get_cell_w_ext(xctx->inst[inst].name, 0), fd); + fputs(get_sym_name(inst, 1), fd); } else if(strcmp(token,"@schname_ext")==0) /* of course schname must not be present */ /* in hash table */ @@ -2401,11 +2402,11 @@ static void print_verilog_primitive(FILE *fd, int inst) /* netlist switch level else if(strcmp(token,"@symname")==0) /* of course symname must not be present */ /* in hash table */ { - fprintf( fd, "%s",skip_dir(xctx->inst[inst]. name) ); + fputs(get_sym_name(inst, 0), fd); } else if (strcmp(token,"@symname_ext")==0) { - fputs(get_cell_w_ext(xctx->inst[inst].name, 0), fd); + fputs(get_sym_name(inst, 1), fd); } else if(strcmp(token,"@schname_ext")==0) /* of course schname must not be present */ /* in hash table */ @@ -2547,9 +2548,9 @@ void print_verilog_element(FILE *fd, int inst) get_tok_value((xctx->inst[inst].ptr + xctx->sym)->prop_ptr, "verilogprefix", 0)); if(verilogprefix) { my_strdup(_ALLOC_ID_, &symname, verilogprefix); - my_strcat(_ALLOC_ID_, &symname, skip_dir(xctx->inst[inst].name)); + my_strcat(_ALLOC_ID_, &symname, get_sym_name(inst, 0)); } else { - my_strdup(_ALLOC_ID_, &symname, skip_dir(xctx->inst[inst].name)); + my_strdup(_ALLOC_ID_, &symname, get_sym_name(inst, 0)); } my_free(_ALLOC_ID_, &verilogprefix); my_strdup(_ALLOC_ID_, &template, (xctx->inst[inst].ptr + xctx->sym)->templ); @@ -2903,7 +2904,8 @@ const char *translate(int inst, const char* s) memcpy(result+result_pos,xctx->inst[inst].instname, tmp+1); result_pos+=tmp; } else if(strcmp(token,"@symname")==0) { - tmp_sym_name=xctx->inst[inst].name ? get_cell(xctx->inst[inst].name, 0) : ""; + tmp_sym_name = get_sym_name(inst, 0); + tmp_sym_name=tmp_sym_name ? tmp_sym_name : ""; tmp=strlen(tmp_sym_name); STR_ALLOC(&result, tmp + result_pos, &size); memcpy(result+result_pos,tmp_sym_name, tmp+1); @@ -2915,7 +2917,8 @@ const char *translate(int inst, const char* s) memcpy(result+result_pos, path, tmp+1); result_pos+=tmp; } else if(strcmp(token,"@symname_ext")==0) { - tmp_sym_name=xctx->inst[inst].name ? get_cell_w_ext(xctx->inst[inst].name, 0) : ""; + tmp_sym_name = get_sym_name(inst, 1); + tmp_sym_name=tmp_sym_name ? tmp_sym_name : ""; tmp=strlen(tmp_sym_name); STR_ALLOC(&result, tmp + result_pos, &size); memcpy(result+result_pos,tmp_sym_name, tmp+1); @@ -3009,7 +3012,7 @@ const char *translate(int inst, const char* s) my_free(_ALLOC_ID_, &pin_num_or_name); } else if(strcmp(token,"@sch_last_modified")==0) { - get_sch_from_sym(file_name, xctx->inst[inst].ptr + xctx->sym); + get_sch_from_sym(file_name, xctx->inst[inst].ptr + xctx->sym, inst); if(!stat(file_name , &time_buf)) { tm=localtime(&(time_buf.st_mtime) ); tmp=strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", tm); diff --git a/src/verilog_netlist.c b/src/verilog_netlist.c index 9c22abe2..2420b4ea 100644 --- a/src/verilog_netlist.c +++ b/src/verilog_netlist.c @@ -351,6 +351,7 @@ int global_verilog_netlist(int global) /* netlister driver */ dbg(2, "global_verilog_netlist(): last defined symbol=%d\n",xctx->symbols); subckt_name=NULL; + get_additional_symbols(1); for(i=0;isymbols; ++i) { if( strcmp(get_tok_value(xctx->sym[i].prop_ptr,"verilog_ignore",0),"true")==0 ) continue; @@ -372,6 +373,7 @@ int global_verilog_netlist(int global) /* netlister driver */ } } my_free(_ALLOC_ID_, &abs_path); + get_additional_symbols(0); str_hash_free(&subckt_table); my_free(_ALLOC_ID_, &subckt_name); my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch])); @@ -437,7 +439,7 @@ int verilog_block_netlist(FILE *fd, int i) verilog_stop=1; else verilog_stop=0; - get_sch_from_sym(filename, xctx->sym + i); + get_sch_from_sym(filename, xctx->sym + i, -1); if(split_f) { my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d", diff --git a/src/vhdl_netlist.c b/src/vhdl_netlist.c index adb70d0c..f77fd445 100644 --- a/src/vhdl_netlist.c +++ b/src/vhdl_netlist.c @@ -336,6 +336,7 @@ int global_vhdl_netlist(int global) /* netlister driver */ dbg(1, "global_vhdl_netlist(): printing top level used components\n"); /* print all components */ subckt_name=NULL; + get_additional_symbols(1); for(j=0;jsymbols; ++j) { if( strcmp(get_tok_value(xctx->sym[j].prop_ptr,"vhdl_primitive",0),"true")==0 ) continue; @@ -388,6 +389,7 @@ int global_vhdl_netlist(int global) /* netlister driver */ } my_free(_ALLOC_ID_, &abs_path); } + get_additional_symbols(0); str_hash_free(&subckt_table); my_free(_ALLOC_ID_, &subckt_name); @@ -448,6 +450,7 @@ int global_vhdl_netlist(int global) /* netlister driver */ dbg(2, "global_vhdl_netlist(): last defined symbol=%d\n",xctx->symbols); subckt_name=NULL; + get_additional_symbols(1); for(i=0;isymbols; ++i) { if( strcmp(get_tok_value(xctx->sym[i].prop_ptr,"vhdl_ignore",0),"true")==0 ) continue; @@ -468,8 +471,9 @@ int global_vhdl_netlist(int global) /* netlister driver */ err |= vhdl_block_netlist(fd, i); } } - my_free(_ALLOC_ID_, &abs_path); } + my_free(_ALLOC_ID_, &abs_path); + get_additional_symbols(0); str_hash_free(&subckt_table); my_free(_ALLOC_ID_, &subckt_name); my_strncpy(xctx->sch[xctx->currsch] , "", S(xctx->sch[xctx->currsch])); @@ -530,7 +534,7 @@ int vhdl_block_netlist(FILE *fd, int i) vhdl_stop=1; else vhdl_stop=0; - get_sch_from_sym(filename, xctx->sym + i); + get_sch_from_sym(filename, xctx->sym + i, -1); if(split_f) { my_snprintf(netl_filename, S(netl_filename), "%s/.%s_%d", @@ -635,6 +639,7 @@ int vhdl_block_netlist(FILE *fd, int i) dbg(1, "vhdl_block_netlist(): used components\n"); /* print all components */ if(!vhdl_stop) { + get_additional_symbols(1); for(j=0;jsymbols; ++j) { if( strcmp(get_tok_value(xctx->sym[j].prop_ptr,"vhdl_primitive",0),"true")==0 ) continue; @@ -692,6 +697,7 @@ int vhdl_block_netlist(FILE *fd, int i) fprintf(fd, "end component ;\n\n"); } } /* for(j...) */ + get_additional_symbols(0); } /* if(!vhdl_stop) */ my_free(_ALLOC_ID_, &abs_path); dbg(1, "vhdl_block_netlist(): netlisting %s\n", skip_dir( xctx->sch[xctx->currsch])); diff --git a/src/xschem.h b/src/xschem.h index 1965648e..be9d3135 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1299,7 +1299,9 @@ extern void load_ascii_string(char **ptr, FILE *fd); extern char *read_line(FILE *fp, int dbg_level); extern void read_record(int firstchar, FILE *fp, int dbg_level); extern void create_sch_from_sym(void); -extern void get_sch_from_sym(char *filename, xSymbol *sym); +extern void get_sch_from_sym(char *filename, xSymbol *sym, int inst); +extern const char *get_sym_name(int inst, int ext); +extern void get_additional_symbols(int what); extern int descend_schematic(int instnumber); extern void go_back(int confirm); extern void view_unzoom(double z);