when doing spice netlist, if a symbol has the spice_sym_def attribute set and is using @pinlist in format string for port order, get the port order from the subckt given in spice_sym_def, either directly or through a .include line
This commit is contained in:
parent
0f7785d588
commit
d2c6566030
166
src/token.c
166
src/token.c
|
|
@ -1812,17 +1812,57 @@ void print_tedax_subckt(FILE *fd, int symbol)
|
|||
}
|
||||
}
|
||||
|
||||
static int has_included_subcircuit(int symbol, char **result)
|
||||
/* This function is used to generate the @pinlist replacement getting port order
|
||||
* from the spice_sym_def attribute (either directly or by loading the provided .include file),
|
||||
* checking with the corresponding symbol pin name and getting the net name attached to it.
|
||||
* Any name mismatch is reported and in this case the function does nothing. The default xschem
|
||||
* symbol port ordering will be used. */
|
||||
static int has_included_subcircuit(int inst, int symbol, char **result)
|
||||
{
|
||||
|
||||
char *spice_sym_def = NULL;
|
||||
int ret = 0;
|
||||
|
||||
my_strdup2(_ALLOC_ID_, &spice_sym_def, get_tok_value(xctx->sym[symbol].prop_ptr, "spice_sym_def", 0));
|
||||
if(xctx->tok_size) {
|
||||
tclvareval("has_included_subcircuit {", spice_sym_def, "}", NULL);
|
||||
my_mstrcat(_ALLOC_ID_, result, tclresult(), NULL);
|
||||
ret = 1;
|
||||
if(tclresult()[0]) {
|
||||
char *pinlist = NULL;
|
||||
char *pin, *save;
|
||||
char *pinlist_ptr;
|
||||
const char *net;
|
||||
int i, no_of_pins = (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER], multip;
|
||||
int symbol_pins = 0;
|
||||
int instance_pins = 0;
|
||||
|
||||
my_strdup2(_ALLOC_ID_, &pinlist, tclresult());
|
||||
dbg(1, "included subcircuit: pinlist=%s\n", pinlist);
|
||||
pinlist_ptr = pinlist;
|
||||
while( (pin = my_strtok_r(pinlist_ptr, " ", "", 0, &save)) ) {
|
||||
instance_pins++;
|
||||
for(i = 0;i < no_of_pins; ++i) {
|
||||
char *prop = (xctx->inst[inst].ptr + xctx->sym)->rect[PINLAYER][i].prop_ptr;
|
||||
int spice_ignore = !strboolcmp(get_tok_value(prop, "spice_ignore", 0), "true");
|
||||
const char *name = get_tok_value(prop, "name", 0);
|
||||
|
||||
if(!spice_ignore) {
|
||||
if(!strcmp(pin, name)) {
|
||||
symbol_pins++;
|
||||
net = net_name(inst, i, &multip, 0, 1);
|
||||
my_mstrcat(_ALLOC_ID_, result, "?", my_itoa(multip), " ", net, " ", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
pinlist_ptr = NULL;
|
||||
}
|
||||
if(instance_pins == symbol_pins) ret = 1;
|
||||
else {
|
||||
dbg(0, "has_included_subcircuit(): symbol and .subckt pins do not match. Discard .subckt port order\n");
|
||||
if(has_x)
|
||||
tcleval("alert_ {has_included_subcircuit(): "
|
||||
"symbol and .subckt pins do not match. Discard .subckt port order}");
|
||||
}
|
||||
my_free(_ALLOC_ID_, &pinlist);
|
||||
}
|
||||
}
|
||||
my_free(_ALLOC_ID_, &spice_sym_def);
|
||||
return ret;
|
||||
|
|
@ -1988,7 +2028,6 @@ void print_spice_subckt_nodes(FILE *fd, int symbol)
|
|||
int print_spice_element(FILE *fd, int inst)
|
||||
{
|
||||
int i=0, multip, itmp;
|
||||
size_t tmp;
|
||||
const char *str_ptr=NULL;
|
||||
register int c, state=TOK_BEGIN, space;
|
||||
char *template=NULL,*format=NULL, *s, *name=NULL, *token=NULL;
|
||||
|
|
@ -1999,7 +2038,6 @@ int print_spice_element(FILE *fd, int inst)
|
|||
int escape=0;
|
||||
int no_of_pins=0;
|
||||
char *result = NULL;
|
||||
size_t result_pos = 0;
|
||||
size_t size = 0;
|
||||
char *spiceprefixtag = NULL;
|
||||
const char *fmt_attr = NULL;
|
||||
|
|
@ -2038,7 +2076,6 @@ int print_spice_element(FILE *fd, int inst)
|
|||
while(1)
|
||||
{
|
||||
/* always make room for some characters so the single char writes to result do not need reallocs */
|
||||
STR_ALLOC(&result, 100 + result_pos, &size);
|
||||
c=*s++;
|
||||
if(c=='\\') {
|
||||
escape=1;
|
||||
|
|
@ -2104,10 +2141,8 @@ int print_spice_element(FILE *fd, int inst)
|
|||
if(!token_exists && token[0] =='%') {
|
||||
|
||||
|
||||
tmp = strlen(token + 1) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", token + 1);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", token + 1); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, token + 1, NULL);
|
||||
/* fputs(token + 1, fd); */
|
||||
} else if (value && value[0]!='\0') {
|
||||
/* instance names (name) and node labels (lab) go thru the expandlabel function. */
|
||||
|
|
@ -2115,73 +2150,57 @@ int print_spice_element(FILE *fd, int inst)
|
|||
|
||||
if (!(strcmp(token+1,"name") && strcmp(token+1,"lab")) /* expand name/labels */
|
||||
&& ((lab = expandlabel(value, &itmp)) != NULL)) {
|
||||
tmp = strlen(lab) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", lab);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", lab); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, lab, NULL);
|
||||
/* fputs(lab,fd); */
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
tmp = strlen(value) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", value);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", value); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, value, NULL);
|
||||
/* fputs(value,fd); */
|
||||
}
|
||||
}
|
||||
else if (strcmp(token,"@path")==0) /* of course symname must not be present in attributes */
|
||||
{
|
||||
const char *s = xctx->sch_path[xctx->currsch] + 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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", s);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", s); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, s, NULL);
|
||||
/* fputs(s,fd); */
|
||||
}
|
||||
else if(strcmp(token,"@symref")==0)
|
||||
{
|
||||
const char *s = get_sym_name(inst, 9999, 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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", s);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", s); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, s, NULL);
|
||||
}
|
||||
else if (strcmp(token,"@symname")==0) /* of course symname must not be present in attributes */
|
||||
{
|
||||
const char *s = sanitize(translate(inst, get_sym_name(inst, 0, 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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", s);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", s); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, s, NULL);
|
||||
/* fputs(s,fd); */
|
||||
}
|
||||
else if (strcmp(token,"@symname_ext")==0) /* of course symname must not be present in attributes */
|
||||
{
|
||||
const char *s = sanitize(translate(inst, get_sym_name(inst, 0, 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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", s);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", s); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, s, NULL);
|
||||
/* fputs(s,fd); */
|
||||
}
|
||||
else if(strcmp(token,"@topschname")==0) /* of course topschname must not be present in attributes */
|
||||
{
|
||||
const char *topsch;
|
||||
topsch = get_trailing_path(xctx->sch[0], 0, 1);
|
||||
tmp = strlen(topsch) + 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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", topsch);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", topsch); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, topsch, NULL);
|
||||
}
|
||||
else if(strcmp(token,"@schname_ext")==0) /* of course schname must not be present in attributes */
|
||||
{
|
||||
tmp = strlen(xctx->current_name) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", xctx->current_name);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", xctx->current_name); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, xctx->current_name, NULL);
|
||||
/* fputs(xctx->current_name, fd); */
|
||||
}
|
||||
else if(strcmp(token,"@savecurrent")==0)
|
||||
|
|
@ -2191,23 +2210,20 @@ int print_spice_element(FILE *fd, int inst)
|
|||
const char *sc = get_tok_value(xctx->inst[inst].prop_ptr, "savecurrent", 0);
|
||||
if(!sc[0]) sc = get_tok_value(template, "savecurrent", 0);
|
||||
if(!strboolcmp(sc , "true")) {
|
||||
tmp = strlen(instname) + 25;
|
||||
STR_ALLOC(&result, tmp + result_pos, &size);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "\n.save I( ?1 %s )", instname);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "\n.save I( ?1 %s )", instname); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, "\n.save I( ?1 ", instname, " )", NULL);
|
||||
}
|
||||
}
|
||||
else if(strcmp(token,"@schname")==0) /* of course schname must not be present in attributes */
|
||||
{
|
||||
const char *schname = get_cell(xctx->current_name, 0);
|
||||
tmp = strlen(schname) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", schname);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", schname); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, schname, NULL);
|
||||
}
|
||||
else if(strcmp(token,"@pinlist")==0) /* of course pinlist must not be present in attributes */
|
||||
/* print multiplicity */
|
||||
{ /* and node number: m1 n1 m2 n2 .... */
|
||||
if(1 || !has_included_subcircuit(xctx->inst[inst].ptr, &result)) {
|
||||
if(!has_included_subcircuit(inst, xctx->inst[inst].ptr, &result)) {
|
||||
Int_hashtable table = {NULL, 0};
|
||||
int_hash_init(&table, 37);
|
||||
for(i=0;i<no_of_pins; ++i)
|
||||
|
|
@ -2219,10 +2235,8 @@ int print_spice_element(FILE *fd, int inst)
|
|||
if(!int_hash_lookup(&table, name, 1, XINSERT_NOREPLACE)) {
|
||||
str_ptr = net_name(inst, i, &multip, 0, 1);
|
||||
|
||||
tmp = strlen(str_ptr) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2236,10 +2250,8 @@ int print_spice_element(FILE *fd, int inst)
|
|||
if(strboolcmp(get_tok_value(prop,"spice_ignore",0), "true")) {
|
||||
str_ptr = net_name(inst,i, &multip, 0, 1);
|
||||
|
||||
tmp = strlen(str_ptr) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -2290,9 +2302,8 @@ int print_spice_element(FILE *fd, int inst)
|
|||
}
|
||||
my_free(_ALLOC_ID_, &tmpstr);
|
||||
}
|
||||
tmp=strlen(value) + 100;
|
||||
STR_ALLOC(&result, tmp + result_pos, &size);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", value);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", value); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, value, NULL);
|
||||
my_free(_ALLOC_ID_, &pin_attr_value);
|
||||
}
|
||||
else if(n>=0 && n < (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]) {
|
||||
|
|
@ -2302,10 +2313,8 @@ int print_spice_element(FILE *fd, int inst)
|
|||
if(strboolcmp(si, "true")) {
|
||||
str_ptr = net_name(inst,n, &multip, 0, 1);
|
||||
|
||||
tmp = strlen(str_ptr) +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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL);
|
||||
}
|
||||
}
|
||||
my_free(_ALLOC_ID_, &pin_attr);
|
||||
|
|
@ -2322,29 +2331,40 @@ int print_spice_element(FILE *fd, int inst)
|
|||
dbg(1, "print_spice_element(): tclpropeval {%s} {%s} {%s}", token, name, xctx->inst[inst].name);
|
||||
res = tcleval(tclcmd);
|
||||
|
||||
tmp = strlen(res) + 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);
|
||||
result_pos += my_snprintf(result + result_pos, tmp, "%s", res);
|
||||
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", res); */
|
||||
my_mstrcat(_ALLOC_ID_, &result, res, NULL);
|
||||
/* fprintf(fd, "%s", tclresult()); */
|
||||
my_free(_ALLOC_ID_, &tclcmd);
|
||||
} /* /20171029 */
|
||||
|
||||
|
||||
if(c != '%' && c != '@' && c!='\0' ) {
|
||||
result_pos += my_snprintf(result + result_pos, 2, "%c", c); /* no realloc needed */
|
||||
char str[2];
|
||||
str[0] = (unsigned char) c;
|
||||
str[1] = '\0';
|
||||
|
||||
/* result_pos += my_snprintf(result + result_pos, 2, "%c", c); */ /* no realloc needed */
|
||||
my_mstrcat(_ALLOC_ID_, &result, str, NULL);
|
||||
/* fputc(c,fd); */
|
||||
}
|
||||
if(c == '@' || c == '%' ) s--;
|
||||
state=TOK_BEGIN;
|
||||
}
|
||||
else if(state==TOK_BEGIN && c!='\0') {
|
||||
result_pos += my_snprintf(result + result_pos, 2, "%c", c); /* no realloc needed */
|
||||
char str[2];
|
||||
str[0] = (unsigned char) c;
|
||||
str[1] = '\0';
|
||||
/* result_pos += my_snprintf(result + result_pos, 2, "%c", c); */ /* no realloc needed */
|
||||
my_mstrcat(_ALLOC_ID_, &result, str, NULL);
|
||||
/* fputc(c,fd); */
|
||||
}
|
||||
if(c=='\0')
|
||||
{
|
||||
result_pos += my_snprintf(result + result_pos, 2, "%c", '\n'); /* no realloc needed */
|
||||
char str[2];
|
||||
str[0] = '\n';
|
||||
str[1] = '\0';
|
||||
/* result_pos += my_snprintf(result + result_pos, 2, "%c", '\n'); */ /* no realloc needed */
|
||||
my_mstrcat(_ALLOC_ID_, &result, str, NULL);
|
||||
/* fputc('\n',fd); */
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -654,12 +654,48 @@ proc ev0 {args} {
|
|||
}
|
||||
}
|
||||
|
||||
# get pin ordering from included subcircuit
|
||||
# return empty string if not found.
|
||||
proc has_included_subcircuit {spice_sym_def} {
|
||||
global has_x
|
||||
# puts "has_included_subcircuit: spice_sym_def=$spice_sym_def"
|
||||
regsub -all {\n\+} $spice_sym_def { } spice_sym_def
|
||||
set pinlist {}
|
||||
# .include? get the file ...
|
||||
if {[regexp -nocase {^\.include } $spice_sym_def]} {
|
||||
set filename [lindex $spice_sym_def 1]
|
||||
# puts "filename=$filename"
|
||||
set res [catch {open $filename r} fd]
|
||||
if { $res } {
|
||||
puts "has_included_subcircuit: error opening file $filename: $fd"
|
||||
if { [info exists has_x] } {alert_ "has_included_subcircuit: error opening file $filename: $fd"}
|
||||
return $pinlist
|
||||
}
|
||||
set spice_sym_def [read -nonewline $fd]
|
||||
close $fd
|
||||
regsub -all {\n\+} $spice_sym_def { } spice_sym_def
|
||||
}
|
||||
return "---- $filename ----"
|
||||
# ... or use the attribute value as *the* subcircuit
|
||||
|
||||
# split lines
|
||||
set spice_sym_def [split $spice_sym_def \n]
|
||||
foreach line $spice_sym_def {
|
||||
# het 1st line with a .subckt. This is our subcircuit definition, get the pin order
|
||||
if {[string tolower [lindex $line 0]] eq {.subckt} } {
|
||||
regsub -all { *= *} $line {=} line
|
||||
# pin list ends where parameter assignment begins (param=value)
|
||||
set last [lsearch -regexp [string tolower $line] {=|param:}]
|
||||
if {$last == -1} {
|
||||
set last [expr {[llength $line] -1}]
|
||||
} else {
|
||||
set last [expr {$last -1}]
|
||||
}
|
||||
set pinlist [lrange $line 2 $last]
|
||||
break
|
||||
}
|
||||
}
|
||||
# return pinlist as found in the .subckt line or empty string if not found
|
||||
return $pinlist
|
||||
}
|
||||
|
||||
# should not be called directly by user
|
||||
|
|
|
|||
|
|
@ -22,8 +22,15 @@ v {xschem version=3.4.5 file_version=1.2
|
|||
G {}
|
||||
K {type=subcircuit
|
||||
xformat="@name @pinlist @symname"
|
||||
|
||||
format="@name @@GND @@TRIG @@OUT @@RESETB @@CTRL @@THRES @@DIS @@VCC @symname"
|
||||
spice_sym_def=".include model_test_ne555.txt"
|
||||
|
||||
desc="Following format string will get port order from
|
||||
included .subckt file. In this case will fail because
|
||||
.subckt uses different node names"
|
||||
xformat="@name @pinlist @symname"
|
||||
|
||||
spice_sym_def="tcleval(.include $netlist_dir/model_test_ne555.txt)"
|
||||
template="name=x1"
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue