diff --git a/doc/xschem_man/developer_info.html b/doc/xschem_man/developer_info.html index 454e918f..3fdea1c7 100644 --- a/doc/xschem_man/developer_info.html +++ b/doc/xschem_man/developer_info.html @@ -547,7 +547,6 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns" -
  • abort_operation
  • @@ -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 
    +
  • 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 
  • trim_chars str sep
  •     Remove leading and trailing chars matching any character in 'sep' from str 
  • trim_wires
  • @@ -1506,6 +1510,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
     
     
     
    +
     
     
      
    diff --git a/doc/xschem_man/instance_based_implementation_08.png b/doc/xschem_man/instance_based_implementation_08.png
    new file mode 100644
    index 00000000..4c70553b
    Binary files /dev/null and b/doc/xschem_man/instance_based_implementation_08.png differ
    diff --git a/doc/xschem_man/instance_based_implementation_09.png b/doc/xschem_man/instance_based_implementation_09.png
    new file mode 100644
    index 00000000..b44c183b
    Binary files /dev/null and b/doc/xschem_man/instance_based_implementation_09.png differ
    diff --git a/doc/xschem_man/instance_based_implementation_10.png b/doc/xschem_man/instance_based_implementation_10.png
    new file mode 100644
    index 00000000..e7963b5b
    Binary files /dev/null and b/doc/xschem_man/instance_based_implementation_10.png differ
    diff --git a/doc/xschem_man/instance_based_implementation_11.png b/doc/xschem_man/instance_based_implementation_11.png
    new file mode 100644
    index 00000000..ae7d39e7
    Binary files /dev/null and b/doc/xschem_man/instance_based_implementation_11.png differ
    diff --git a/doc/xschem_man/tutorial_instance_based_implementation.html b/doc/xschem_man/tutorial_instance_based_implementation.html
    index f6a27a70..f5b9b561 100644
    --- a/doc/xschem_man/tutorial_instance_based_implementation.html
    +++ b/doc/xschem_man/tutorial_instance_based_implementation.html
    @@ -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.
      

    - +

    Another example of spice models given as parameters

    + +

    Consider the following symbol instance:

    + +

    with the following symbol definition

    + +

    And the following schematic definition. Note the model syntax for the p-channel transistor + (the n-channel transistor has a similar model=modn@modeltag definition):

    + +

    The following netlist will be produced

    +
    +...
    +...
    +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
    +...
    +...
    + 
    +

    You see the @modeltag 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 modeltag=18 definition).

    +

    Now suppose you want to place another instance of inv4.sym 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 + inv4.sym subcircuit to a new inv_1.sym subcircuit. + Therefore we give the attribute schematic=inv4_1.sch + to the second inv4 instance. We also set there a different modeltag: modeltag=13

    + +

    The netlist for this additional instance will be:

    +
    +...
    +...
    +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
    +...
    +...
    + 
    +

    This way it is possible from a single symbol (inv4.sym in the example) to netlist multiple instances of it + with different models, in the example using a modeltag variable.

    + +
    diff --git a/src/actions.c b/src/actions.c index 24c23ff8..5e8b748f 100644 --- a/src/actions.c +++ b/src/actions.c @@ -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"); diff --git a/src/scheduler.c b/src/scheduler.c index 139201b8..6ccd9e78 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -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")) diff --git a/src/svgdraw.c b/src/svgdraw.c index 9f04979f..6513661f 100644 --- a/src/svgdraw.c +++ b/src/svgdraw.c @@ -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) diff --git a/src/token.c b/src/token.c index a7c9b09c..e794bdcf 100644 --- a/src/token.c +++ b/src/token.c @@ -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; +} + diff --git a/src/xschem.h b/src/xschem.h index 06301905..0cd8accb 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -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);