diff --git a/src/eval_expr.y b/src/eval_expr.y index ba954f26..26f8d21d 100644 --- a/src/eval_expr.y +++ b/src/eval_expr.y @@ -63,7 +63,7 @@ symrec *tptr; /* For returning symbol-table pointers */ } %token STREND 0 -%token CHAR +%token XCHAR %token EXPR /* expr( */ %token NUM /* Simple double precision number */ %token FNCT /* Variable and Function */ @@ -81,7 +81,7 @@ input: ; line: - CHAR {get_char($1);} + XCHAR {get_char($1);} | EXPR exp ')' {get_expr($2);lex_state = 0;} | EXPR '\'' exp '\'' ')' {get_expr($3);lex_state = 0;} | EXPR exp error @@ -216,8 +216,8 @@ static int kklex() c = *str++; if(c) { kklval.c = c; - dbg(dbglev, "lex(): CHAR; %c\n", c); - return CHAR; + dbg(dbglev, "lex(): XCHAR; %c\n", c); + return XCHAR; } else { dbg(dbglev, "lex(): STREND\n"); return STREND; diff --git a/src/token.c b/src/token.c index 4a067718..aa4d5da5 100644 --- a/src/token.c +++ b/src/token.c @@ -1174,26 +1174,34 @@ static void print_vhdl_primitive(FILE *fd, int inst) /* netlist primitives, 200 if(c=='\0') { - /* do one level of substitutions to resolve remaining @params and/or tcl expr/code */ - if(result) { - dbg(1, "print_vhdl_primitive(): before translate() result=%s\n", result); - if(!strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { - /* since netlist_commands often have @ characters in spice node save / plot commands, do - * not pass through translate, unless a tcleval(...) is present */ - if(strstr(result, "tcleval(")== result) { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); - } - } else { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); - } - dbg(1, "print_vhdl_primitive(): after translate() result=%s\n", result); - } - if(result) fprintf(fd, "%s", result); - fputc('\n',fd); - fprintf(fd, "---- end primitive\n"); - break ; + /* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions + * can be calculated. Before that do also a round of translation to remove remaining @params */ + if(result) { + dbg(1, "print_verilog_primitive(): before translate3() result=%s\n", result); + if(strchr(result, '@')) { + /* netlist_commands often have @ characters due to ngspice syntax. Do not translate */ + if(strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); + /* can not put template in above translate3: ------------------------------------^^^^ + * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 + * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ + if(strchr(result, '@')) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 2, template, NULL, NULL, NULL)); + } + } + } + my_strdup2(_ALLOC_ID_, &result, tcl_hook2(result)); /* tcl evaluation if tcleval(....) */ + if(strstr(result, "expr(") ) { + result = eval_expr(result); + } + dbg(1, "print_verilog_primitive(): after translate3() result=%s\n", result); + } + if(result) fprintf(fd, "%s", result); + fputc('\n',fd); + fprintf(fd, "---- end primitive\n"); + break ; } - } + } /* while(1) */ my_free(_ALLOC_ID_, &result); my_free(_ALLOC_ID_, &template); my_free(_ALLOC_ID_, &format); @@ -2398,7 +2406,13 @@ int print_spice_element(FILE *fd, int inst) * model=nfet_01v8 */ my_strdup2(_ALLOC_ID_, &val, - translate3(token, 2, xctx->inst[inst].prop_ptr, parent_prop_ptr, template, NULL)); + translate3(token, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, NULL, NULL)); + /* can not put template in above translate3: ---------------------------^^^^ + * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 + * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ + if(strchr(val, '@')) { + my_strdup2(_ALLOC_ID_, &val, translate3(val, 0, template, NULL, NULL, NULL)); + } /* nmos instance format string: @model --> @modeln */ dbg(1, "print_spice_element(): 1st round: val: |%s|\n", val); if(strchr(val, '@')) { @@ -2428,12 +2442,10 @@ int print_spice_element(FILE *fd, int inst) } dbg(1, "print_spice_element(): final: val: |%s|\n", val); } - value = val; - /* xctx->tok_size==0 (set in translate3()) indicates that token(+1) does not exist - * in instance attributes so try to get from symbol template */ - dbg(1, "print_spice_element(): val: %s\n", val); + /* still unresolved: set to empty */ + if(val[0] == '@') value = ""; + else value = val; token_exists = xctx->tok_size; - value = val; tok_val_len = strlen(value); /* @spiceprefix needs a special tag for postprocessing */ if(!strcmp(token, "@spiceprefix") && value[0]) { @@ -3109,26 +3121,35 @@ static void print_verilog_primitive(FILE *fd, int inst) /* netlist switch level } if(c=='\0') { - /* do one level of substitutions to resolve remaining @params and/or tcl expr/code */ + /* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions + * can be calculated. Before that do also a round of translation to remove remaining @params */ if(result) { - dbg(1, "print_verilog_primitive(): before translate() result=%s\n", result); - if(!strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { - /* since netlist_commands often have @ characters in spice node save / plot commands, do - * not pass through translate, unless a tcleval(...) is present */ - if(strstr(result, "tcleval(")== result) { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); + dbg(1, "print_verilog_primitive(): before translate3() result=%s\n", result); + if(strchr(result, '@')) { + /* netlist_commands often have @ characters due to ngspice syntax. Do not translate */ + if(strcmp(xctx->sym[xctx->inst[inst].ptr].type, "netlist_commands")) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); + /* can not put template in above translate3: ------------------------------------^^^^ + * if instance has VHI=VHI, format string has VHI=@VHI, and symbol template has VHI=3 + * we do not want token @VHI to resolve to 3, but stop at VHI as specified in instance */ + if(strchr(result, '@')) { + my_strdup2(_ALLOC_ID_, &result, translate3(result, 2, template, NULL, NULL, NULL)); + } + } - } else { - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); } - dbg(1, "print_verilog_primitive(): after translate() result=%s\n", result); + my_strdup2(_ALLOC_ID_, &result, tcl_hook2(result)); /* tcl evaluation if tcleval(....) */ + if(strstr(result, "expr(") ) { + result = eval_expr(result); + } + dbg(1, "print_verilog_primitive(): after translate3() result=%s\n", result); } if(result) fprintf(fd, "%s", result); fputc('\n',fd); fprintf(fd, "---- end primitive\n"); break ; } - } + } /* while(1) */ my_free(_ALLOC_ID_, &result); my_free(_ALLOC_ID_, &template); my_free(_ALLOC_ID_, &format); @@ -3789,7 +3810,7 @@ const char *translate(int inst, const char* s) /* @spice_get_current(...) or @spice_get_modelparam(...) */ /* @spice_get_modelvoltage(...) or @spice_get_modelvoltage_param(...) */ regcomp(get_sp_cur, - "^@spice_get_(current|modelparam|modelvoltage)(_[a-zA-Z][a-zA-Z0-9_]*)*\\(", REG_NOSUB | REG_EXTENDED); + "^@spice_get_(current|modelparam|modelvoltage)([_a-zA-Z][a-zA-Z0-9_]*)*\\(", REG_NOSUB | REG_EXTENDED); } sp_prefix = tclgetboolvar("spiceprefix"); diff --git a/src/xinit.c b/src/xinit.c index 5e1a83f3..a13674a5 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -1177,12 +1177,20 @@ static int source_tcl_file(char *s) if(Tcl_EvalFile(interp, s)==TCL_ERROR) { fprintf(errfp, "Tcl_AppInit() error: can not execute %s, please fix:\n", s); - fprintf(errfp, "Line No: %d\n", Tcl_GetErrorLine(interp)); fprintf(errfp, "%s", tclresult()); + #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6 + fprintf(errfp, "Line No: %d\n", Tcl_GetErrorLine(interp)); + #endif fprintf(errfp, "\n"); + #if TCL_MAJOR_VERSION >= 8 && TCL_MINOR_VERSION >=6 my_snprintf(tmp, S(tmp), "tk_messageBox -icon error -type ok -message \ {Tcl_AppInit() err 1: can not execute %s, please fix:\n%s\nLine No: %d\n}", s, tclresult(), Tcl_GetErrorLine(interp)); + #else + my_snprintf(tmp, S(tmp), "tk_messageBox -icon error -type ok -message \ + {Tcl_AppInit() err 1: can not execute %s, please fix:\n%s\n}", + s, tclresult()); + #endif if(has_x) { tcleval( "wm withdraw ."); tcleval( tmp); diff --git a/xschem_library/ngspice/diff_amp.sym b/xschem_library/ngspice/diff_amp.sym index 1d16a1d0..93676b81 100644 --- a/xschem_library/ngspice/diff_amp.sym +++ b/xschem_library/ngspice/diff_amp.sym @@ -21,21 +21,21 @@ v {xschem version=3.4.6 file_version=1.2 } G {} K {type=opamp_va -format="@name @@OUT @@IN1 @@IN2 @model" +format="@name @@OUT @@IN1 @@IN2 @model gain=@gain amplitude=@amplitude offset=@offset" -template="name=X1 model=diff_amp_cell" +template="name=X1 model=diff_amp_cell gain=40 amplitude=3 offset=1.5" device_model="tcleval( -.subckt diff_amp_cell OUT IN1 IN2 -N1 out in1 in2 diff_amp_model -.ends diff_amp_cell - -.model diff_amp_model diff_amp - .control * following line specifies the location for the .osdi file so ngspice can use it. pre_osdi $USER_CONF_DIR/xschem_library/diff_amp.osdi .endc + +.model diff_amp_model diff_amp $ gain=40 amplitude=3 offset=1.5 + +.subckt diff_amp_cell OUT IN1 IN2 gain=40 amplitude=3 offset=1.5 +N1 out in1 in2 diff_amp_model gain=gain amplitude=amplitude offset=offset +.ends diff_amp_cell )" } V {} diff --git a/xschem_library/ngspice/tb_diff_amp.sch b/xschem_library/ngspice/tb_diff_amp.sch index 3c0fc396..3d02e9a5 100644 --- a/xschem_library/ngspice/tb_diff_amp.sch +++ b/xschem_library/ngspice/tb_diff_amp.sch @@ -25,8 +25,8 @@ V {} S {} E {} B 2 840 -580 1640 -170 {flags=graph -y1=0 -y2=6 +y1=6.3e-14 +y2=5 ypos1=0 ypos2=2 divy=5 @@ -49,7 +49,7 @@ logy=0 } B 2 840 -990 1640 -580 {flags=graph y1=0 -y2=40 +y2=100 ypos1=0 ypos2=2 divy=5 @@ -68,10 +68,9 @@ unitx=1 logx=0 logy=0 } -P 4 5 140 -600 140 -880 710 -880 710 -600 140 -600 {} +P 4 5 30 -600 30 -880 740 -880 740 -600 30 -600 {} P 4 7 410 -600 410 -560 420 -560 410 -540 400 -560 410 -560 410 -600 {} T {// importing libs - `include "discipline.h" module diff_amp( @@ -79,17 +78,17 @@ module diff_amp( input electrical in1, input electrical in2); -parameter real gain = 40; // setting gain to 40 of the differential amplifier -parameter real vcc = 3; // swing from -vcc/2 to +vcc/2 -parameter real offset = 3;// added offset +(* desc="gain", units="", type="instance" *) parameter real gain = 40 from [-inf: inf]; +(* desc="amplitude", units="", type="instance" *) parameter real amplitude = 3 from [-inf: inf]; +(* desc="offset", units="", type="instance" *) parameter real offset = 1.5 from [-inf: inf]; analog begin - V(out) <+ offset / 2 + vcc / 2 * tanh( gain / vcc * 2 * V(in1, in2)); + V(out) <+ offset + amplitude / 2 * tanh( gain / amplitude * 2 * V(in1, in2)); end endmodule -} 150 -870 0 0 0.2 0.2 {font=monospace} +} 40 -870 0 0 0.2 0.2 {font=monospace} T {create a diff_amp.va file with following code and compile it into a .osdi file with openvaf.} 190 -940 0 0 0.4 0.4 {} N 180 -450 320 -450 {lab=B} @@ -100,7 +99,6 @@ N 180 -330 180 -290 {lab=0} N 80 -330 80 -290 {lab=0} N 80 -530 80 -390 {lab=A} N 180 -450 180 -390 {lab=B} -C {diff_amp.sym} 420 -490 0 0 {name=X1} C {lab_pin.sym} 640 -490 0 1 {name=p1 sig_type=std_logic lab=Z} C {lab_pin.sym} 80 -530 0 0 {name=p2 sig_type=std_logic lab=A} C {lab_pin.sym} 180 -450 0 0 {name=p3 sig_type=std_logic lab=B} @@ -118,7 +116,7 @@ C {code_shown.sym} 240 -320 0 0 {name=COMMANDS only_toplevel=false value=" set appendwrite remzerovec write tb_diff_amp.raw - quit 0 + * quit 0 .endc "} C {launcher.sym} 670 -120 0 0 {name=h5 @@ -130,3 +128,4 @@ C {launcher.sym} 670 -170 0 0 {name=h1 descr="OP annotate" tclcommand="xschem annotate_op" } +C {diff_amp.sym} 420 -490 0 0 {name=X1 model=diff_amp_cell gain=100 amplitude=5 offset=2.5}