svgdraw.c: avoid setting stroke-width to excessively small (invisible) values; print_spice_element(): in format string if @param is given and in instance atttributes param=value@tag do a round of resolution of @tag looking in instance attributes, then in parent symbol instance attributes (in case of per-instance implementation (schematic=... attr) and finally in parent symbol template string. Doc udpades

This commit is contained in:
stefan schippers 2024-02-16 16:44:33 +01:00
parent 7a589ef4fb
commit a176f99db5
11 changed files with 191 additions and 39 deletions

View File

@ -547,7 +547,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
<li><kbd> abort_operation</kbd></li><pre>
@ -1393,6 +1392,11 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
Translate string 'str' replacing @xxx tokens with values in instance 'n' attributes
Example: xschem translate vref {the voltage is @value}
the voltage is 1.8 </pre>
<li><kbd> translate3 str s1 [s2]</kbd></li><pre>
Translate string 'str' replacing @xxx tokens with values in string s1 or if
not found in string s2
Example: xschem translate3 {the voltage is @value} {name=x12} {name=x1 value=1.8}
the voltage is 1.8 </pre>
<li><kbd> trim_chars str sep</kbd></li><pre>
Remove leading and trailing chars matching any character in 'sep' from str </pre>
<li><kbd> trim_wires</kbd></li><pre>
@ -1506,6 +1510,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
</ul>

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -196,7 +196,66 @@ m1 y a VSSPIN VSSPIN yyn w=wn l=lln ad='wn *4.3u' as='wn *4.3u' pd='wn *2+8.6u'
duplicate the subcircuit, since model names can not be set as parameters.
</p>
<h3> Another example of spice models given as parameters</h3>
<p> Consider the following symbol instance:</p>
<img src="instance_based_implementation_08.png">
<p> with the following symbol definition</p>
<img src="instance_based_implementation_09.png">
<p> And the following schematic definition. Note the <kbd>model</kbd> syntax for the p-channel transistor
(the n-channel transistor has a similar <kbd>model=modn@modeltag</kbd> definition):</p>
<img src="instance_based_implementation_10.png">
<p> The following netlist will be produced</p>
<pre class="code">
...
...
x4 LDCP4_B LDCP vcc vss inv4 wn=8.4u lln=2.4u wp=20u lp=2.4u m=1
...
...
* expanding symbol: inv4.sym # of pins=2
** sym_path: /home/schippes/.xschem/xschem_library/test_parametric_model/inv4.sym
** sch_path: /home/schippes/.xschem/xschem_library/test_parametric_model/inv4.sch
.subckt inv4 y a VCCPIN VSSPIN wn=10u lln=1.2u wp=10u lp=1.2u
*.opin y
*.ipin a
m2 y a VCCPIN VCCPIN modp18 w=wp l=lp ad='wp *4.6u' as='wp *4.6u' pd='wp *2+9.2u' ps='wp *2+9.2u' m=1
m1 y a VSSPIN VSSPIN modn18 w=wn l=lln ad='wn *4.3u' as='wn *4.3u' pd='wn *2+8.6u' ps='wn *2+8.6u' m=1
.ends
...
...
</pre>
<p> You see the <kbd>@modeltag</kbd> will be substituted looking first in the mos transistor attributes
(but there is no definition there), then in the containing symbol attributes (and there is
a <kbd>modeltag=18</kbd> definition).</p>
<p> Now suppose you want to place another instance of <kbd>inv4.sym</kbd> but with a different modeltag:
Since we know that spice does not allow model names to be passed as parameters we need to specialize the
<kbd>inv4.sym</kbd> subcircuit to a new <kbd>inv_1.sym</kbd> subcircuit.
Therefore we give the attribute <kbd>schematic=inv4_1.sch</kbd>
to the second inv4 instance. We also set there a different modeltag: <kbd>modeltag=13</kbd></p>
<img src="instance_based_implementation_11.png">
<p> The netlist for this additional instance will be: </p>
<pre class="code">
...
...
x5 LDCP5_B LDCP vcc vss inv4_1 wn=8.4u lln=2.4u wp=20u lp=2.4u m=1
...
...
* expanding symbol: inv4_1.sym # of pins=2
** sym_path: /home/schippes/.xschem/xschem_library/test_parametric_model/inv4.sym
** sch_path: /home/schippes/.xschem/xschem_library/test_parametric_model/inv4.sch
.subckt inv4_1 y a VCCPIN VSSPIN wn=10u lln=1.2u wp=10u lp=1.2u
*.opin y
*.ipin a
m2 y a VCCPIN VCCPIN modp13 w=wp l=lp ad='wp *4.6u' as='wp *4.6u' pd='wp *2+9.2u' ps='wp *2+9.2u' m=1
m1 y a VSSPIN VSSPIN modn13 w=wn l=lln ad='wn *4.3u' as='wn *4.3u' pd='wn *2+8.6u' ps='wn *2+8.6u' m=1
.ends
...
...
</pre>
<p> This way it is possible from a single symbol (<kbd>inv4.sym</kbd> in the example) to netlist multiple instances of it
with different models, in the example using a <kbd>modeltag</kbd> variable.</p>
<!-- end of slide -->
<div class="filler"></div>
</div>

View File

@ -1887,7 +1887,7 @@ void get_additional_symbols(int what)
my_strdup2(_ALLOC_ID_, &sch, tcl_hook2(
str_replace( get_tok_value(xctx->inst[i].prop_ptr,"schematic",2), "@symname",
get_cell(xctx->inst[i].name, 0), '\\')));
dbg(1, "get_additional_symbols(): sch=%s\n", sch);
dbg(1, "get_additional_symbols(): inst=%d sch=%s\n",i, sch);
if(sch[0] && stat(abs_sym_path(sch, ""), &buf)) {/* schematic does not exist */
my_snprintf(symbol_base_sch, PATH_MAX, "%s.sch", get_cell(xctx->sym[xctx->inst[i].ptr].name, 9999));
dbg(1, "get_additional_symbols(): schematic not existing\n");

View File

@ -5265,6 +5265,27 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
}
}
/* translate3 str s1 [s2]
* Translate string 'str' replacing @xxx tokens with values in string s1 or if
* not found in string s2
* Example: xschem translate3 {the voltage is @value} {name=x12} {name=x1 value=1.8}
* the voltage is 1.8 */
else if(!strcmp(argv[1], "translate3") )
{
char *s = NULL;
if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;}
if(argc > 5) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], argv[3], argv[4], argv[5]));
if(argc > 4) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], argv[3], argv[4], NULL));
else if(argc > 3) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], argv[3], NULL, NULL));
else {
Tcl_SetResult(interp, "xschem translate3: missing arguments", TCL_STATIC);
return TCL_ERROR;
}
Tcl_ResetResult(interp);
Tcl_SetResult(interp, s, TCL_VOLATILE);
my_free(_ALLOC_ID_, &s);
}
/* trim_chars str sep
* Remove leading and trailing chars matching any character in 'sep' from str */
else if(!strcmp(argv[1], "trim_chars"))

View File

@ -39,7 +39,7 @@ static double svg_linew; /* current width of lines / rectangles */
static void svg_restore_lw(void)
{
svg_linew = xctx->lw*1.2;
svg_linew = (xctx->lw <= 0.01 ? 0.2 : xctx->lw) * 1.2;
}
static void svg_xdrawline(int layer, int bus, double x1, double y1, double x2, double y2, int dash)

View File

@ -2154,35 +2154,17 @@ int print_spice_element(FILE *fd, int inst)
my_strdup2(_ALLOC_ID_, &val, get_tok_value(xctx->inst[inst].prop_ptr, token+1, 0));
tok_size = xctx->tok_size;
value = val;
if(!strcmp(token + 1, "model") && strchr(value, '@')) {
value = translate(inst, val);
if(strchr(value, '@')) {
/* Symbol format string contains model=@modp,
* instance attributes does not contain a modp=xxx,
* look up modp in **parent** symbol template attribute */
dbg(1, "model: instance=%s ,val=%s, tok=%s, value=%s template=%s\n",
xctx->inst[inst].instname,
val, token, value, xctx->hier_attr[xctx->currsch - 1].templ);
if(value[0] == '\0') {
value=get_tok_value(xctx->hier_attr[xctx->currsch - 1].prop_ptr, val+1, 0);
}
if(value[0] == '\0') {
value=get_tok_value(xctx->hier_attr[xctx->currsch - 1].templ, val+1, 0);
}
}
else if(val[0] == '@' && !strpbrk(value + 1, "@ ")) {
/* value = translate(inst, val); */
value = get_tok_value(xctx->inst[inst].prop_ptr, val + 1, 0);
dbg(1, "val=%s, tok=%s, value=%s template=%s",
val, token, value, xctx->hier_attr[xctx->currsch - 1].templ);
if(value[0] == '\0') {
value=get_tok_value(xctx->hier_attr[xctx->currsch - 1].prop_ptr, val+1, 0);
}
if(value[0] == '\0') {
value=get_tok_value(xctx->hier_attr[xctx->currsch - 1].templ, val+1, 0);
}
* look up modp in **parent** instance prop_ptr and symbol template attribute */
value = translate3(val, xctx->inst[inst].prop_ptr,
xctx->hier_attr[xctx->currsch - 1].prop_ptr,
xctx->hier_attr[xctx->currsch - 1].templ);
}
tok_val_len = strlen(value);
if(!strcmp(token, "@spiceprefix")) {
if(!strcmp(token, "@spiceprefix") && value[0]) {
my_realloc(_ALLOC_ID_, &spiceprefixtag, tok_val_len+22);
my_snprintf(spiceprefixtag, tok_val_len+22, "**** spice_prefix %s\n", value);
value = spiceprefixtag;
@ -2197,18 +2179,8 @@ int print_spice_element(FILE *fd, int inst)
token_exists = 0; /* processed later */
value = NULL;
}
/*
if (!strncmp(value,"tcleval(", 8)) {
dbg(1, "print_spice_element(): value=%s\n", value);
my_strdup2(_ALLOC_ID_, &translatedvalue, value);
my_strdup2(_ALLOC_ID_, &translatedvalue, translate(inst, translatedvalue));
value = translatedvalue;
}
*/
}
if(!token_exists && token[0] =='%') {
/* result_pos += my_snprintf(result + result_pos, tmp, "%s", token + 1); */
my_mstrcat(_ALLOC_ID_, &result, token + 1, NULL);
/* fputs(token + 1, fd); */
@ -4339,3 +4311,97 @@ const char *translate2(Lcc *lcc, int level, char* s)
return result;
}
/* substitute given tokens in a string with their corresponding values */
/* ex.: name=@name w=@w l=@l ---> name=m112 w=3e-6 l=0.8e-6 */
/* using s1, s2, s3 in turn to resolve @tokens */
/* if no definition for @token is found return @token as is in s */
/* if s==NULL return emty string */
const char *translate3(const char *s, const char *s1, const char *s2, const char *s3)
{
static const char *empty="";
static char *translated_tok = NULL;
static char *result=NULL; /* safe to keep even with multiple schematics */
register int c, state=TOK_BEGIN, space;
char *token=NULL;
size_t sizetok=0;
size_t token_pos=0;
const char *value;
int escape=0;
char *value1 = NULL;
if(!s || !xctx) {
my_free(_ALLOC_ID_, &result);
my_free(_ALLOC_ID_, &translated_tok);
return empty;
}
dbg(2, "translate3():\n s=%s\n s1=%s\n s2=%s\n s3=%s\n", s, s1, s2, s3);
my_strdup2(_ALLOC_ID_, &result, "");
while(1) {
c=*s++;
if(c=='\\') {
escape=1;
c=*s++; /* do not remove: breaks translation of format strings in netlists (escaping %) */
}
else escape=0;
space=SPACE(c);
if( state==TOK_BEGIN && (c=='@' || c=='%' ) && !escape ) state=TOK_TOKEN; /* 20161210 escape */
else if(state==TOK_TOKEN && token_pos > 1 &&
(
( (space || c == '%' || c == '@') && !escape ) ||
( (!space && c != '%' && c != '@') && escape )
)
) state=TOK_SEP;
STR_ALLOC(&token, token_pos, &sizetok);
if(state==TOK_TOKEN) token[token_pos++]=(char)c;
else if(state==TOK_SEP) {
token[token_pos]='\0';
value = get_tok_value(s1, token+1, 0);
if(!xctx->tok_size && s2) {
value=get_tok_value(s2, token+1, 0);
}
if(!xctx->tok_size && s3) {
value=get_tok_value(s3, token+1, 0);
}
if(!xctx->tok_size) { /* above lines did not find a value for token */
/* no definition found -> keep token */
my_strcat(_ALLOC_ID_, &result, token);
} else {
my_strdup2(_ALLOC_ID_, &value1, value);
my_strcat(_ALLOC_ID_, &result, value1);
my_free(_ALLOC_ID_, &value1);
}
token_pos = 0;
if(c == '@' || c == '%') s--;
else {
char ch[2];
ch[0] = (char)c;
ch[1] = '\0';
my_strcat(_ALLOC_ID_, &result, ch);
}
state=TOK_BEGIN;
} /* else if(state==TOK_SEP) */
else if(state==TOK_BEGIN) {
char ch[2];
ch[0] = (char)c;
ch[1] = '\0';
my_strcat(_ALLOC_ID_, &result, ch);
}
if(c=='\0') {
my_strcat(_ALLOC_ID_, &result, "");
break;
}
} /* while(1) */
dbg(2, "translate3(): returning %s\n", result);
my_free(_ALLOC_ID_, &token);
/* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions
* can be calculated */
my_strdup2(_ALLOC_ID_, &translated_tok, tcl_hook2(result));
return translated_tok;
}

View File

@ -1557,6 +1557,7 @@ extern char *find_nth(const char *str, const char *sep, const char *quote, int k
extern int isonlydigit(const char *s);
extern const char *translate(int inst, const char* s);
extern const char* translate2(Lcc *lcc, int level, char* s);
extern const char *translate3(const char* s, const char *s1, const char *s2, const char *s3);
extern void print_tedax_element(FILE *fd, int inst);
extern int print_spice_element(FILE *fd, int inst);
extern void print_spice_subckt_nodes(FILE *fd, int symbol);