add instance based "schematic=..." attribute. This allows multiple instances of the same symbol to have different implementations.

This commit is contained in:
stefan schippers 2023-04-12 18:28:19 +02:00
parent 5b3b3d0662
commit 590bf8b6ec
9 changed files with 121 additions and 32 deletions

View File

@ -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;i<xctx->instances; ++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();

View File

@ -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;

View File

@ -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"));
}
}
}

View File

@ -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;i<xctx->symbols; ++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;i<xctx->instances; ++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;i<xctx->symbols; ++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());

View File

@ -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] );

View File

@ -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;i<no_of_pins; ++i) {
my_strdup2(_ALLOC_ID_, &net, net_name(inst,i, &net_mult, 0, 1));
@ -2162,11 +2163,11 @@ void print_tedax_element(FILE *fd, int inst)
else if(strcmp(token,"@symname")==0) /* of course symname must not be present */
/* in hash table */
{
fputs(skip_dir(xctx->inst[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);

View File

@ -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;i<xctx->symbols; ++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",

View File

@ -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;j<xctx->symbols; ++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;i<xctx->symbols; ++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;j<xctx->symbols; ++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]));

View File

@ -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);