diff --git a/doc/xschem_man/commands.html b/doc/xschem_man/commands.html index d6a9da20..0a4f589e 100644 --- a/doc/xschem_man/commands.html +++ b/doc/xschem_man/commands.html @@ -156,7 +156,9 @@ ctrl 'c' Save to clipboard shift 'C' Start arc placement shift+ctrl 'C' Start circle placement alt 'C' Toggle dim/brite background with rest of layers -shift 'D' Delete files +ctrl 'd' Delete files +- 'd' Unselect selected object under the mouse pointer +shift 'D' Unselect selected objects by area ctrl 'e' Back to parent schematic - 'e' Descend to schematic alt 'e' Edit selected schematic in a new window diff --git a/src/Makefile.in b/src/Makefile.in index 4eec5b71..ec2d23ef 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -5,7 +5,7 @@ put /local/src { select.c font.c editprop.c save.c paste.c token.c psprint.c node_hash.c hilight.c options.c vhdl_netlist.c svgdraw.c spice_netlist.c tedax_netlist.c verilog_netlist.c parselabel.c expandlabel.c - in_memory_undo.c cairo_jpg.c + eval_expr.c in_memory_undo.c cairo_jpg.c } # list all files that need to be installed in "$(XSHAREDIR)" @@ -49,12 +49,15 @@ parselabel.c: parselabel.l expandlabel.h expandlabel.c expandlabel.h: expandlabel.y bison -d -o expandlabel.c expandlabel.y +eval_expr.c: eval_expr.y + bison -o eval_expr.c eval_expr.y + parselabel.o: expandlabel.h $(OBJ): xschem.h ../config.h Makefile clean: FORCE - rm -rf rawtovcd xschem *.o expandlabel.[ch] parselabel.c + rm -rf rawtovcd xschem *.o eval_expr.c expandlabel.[ch] parselabel.c # Explicit rule for each object: @] diff --git a/src/actions.c b/src/actions.c index 7bcc6d42..59afb731 100644 --- a/src/actions.c +++ b/src/actions.c @@ -1482,7 +1482,7 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot tcleval("load_file_dialog {Choose symbol} *.\\{sym,tcl\\} INITIALINSTDIR"); my_strncpy(name1, tclresult(), S(name1)); } else { - my_strncpy(name1, symbol_name, S(name1)); + my_strncpy(name1, trim_chars(symbol_name, " \t\n"), S(name1)); } dbg(1, "place_symbol(): 1: name1=%s first_call=%d\n",name1, first_call); @@ -1495,7 +1495,9 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot tclvareval("is_xschem_file {", name1, "}", NULL); if(!strcmp(tclresult(), "GENERATOR")) { - my_snprintf(name, S(name), "%s()", name1); + size_t len = strlen(name1); + if( name1[len - 1] != ')') my_snprintf(name, S(name), "%s()", name1); + else my_strncpy(name, name1, S(name)); } else { my_strncpy(name, name1, S(name)); } @@ -1983,34 +1985,34 @@ void get_additional_symbols(int what) char *default_schematic = NULL; char *sch = NULL; char symbol_base_sch[PATH_MAX] = ""; + size_t schematic_token_found = 0; if(xctx->inst[i].ptr < 0) continue; + dbg(1, "get_additional_symbols(): inst=%d (%s) sch=%s\n",i, xctx->inst[i].name, sch); /* copy instance based *_sym_def attributes to symbol */ my_strdup(_ALLOC_ID_, &spice_sym_def, get_tok_value(xctx->inst[i].prop_ptr,"spice_sym_def",6)); my_strdup(_ALLOC_ID_, &verilog_sym_def, get_tok_value(xctx->inst[i].prop_ptr,"verilog_sym_def",4)); my_strdup(_ALLOC_ID_, &vhdl_sym_def, get_tok_value(xctx->inst[i].prop_ptr,"vhdl_sym_def",4)); - dbg(1, "schematic=%s\n", get_tok_value(xctx->inst[i].prop_ptr,"schematic",6)); + dbg(1, "get_additional_symbols(): schematic=%s\n", get_tok_value(xctx->inst[i].prop_ptr,"schematic",6)); /* resolve schematic=generator.tcl( @n ) where n=11 is defined in instance attrs */ - my_strdup2(_ALLOC_ID_, &sch, - translate3(get_tok_value(xctx->inst[i].prop_ptr,"schematic", 6), 1, - xctx->inst[i].prop_ptr, NULL, NULL)); - dbg(1, "sch=%s\n", sch); + my_strdup2(_ALLOC_ID_, &sch, get_tok_value(xctx->inst[i].prop_ptr,"schematic", 6)); + schematic_token_found = xctx->tok_size; + my_strdup2(_ALLOC_ID_, &sch, translate3(sch, 1, xctx->inst[i].prop_ptr, NULL, NULL, NULL)); + dbg(1, "get_additional_symbols(): sch=%s tok_size= %ld\n", sch, xctx->tok_size); my_strdup2(_ALLOC_ID_, &sch, tcl_hook2( str_replace(sch, "@symname", get_cell(xctx->inst[i].name, 0), '\\', -1))); - dbg(1, "get_additional_symbols(): inst=%d sch=%s\n",i, sch); /* schematic does not exist */ if(sch[0] && stat(abs_sym_path(sch, ""), &buf)) { 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"); dbg(1, "using: %s\n", symbol_base_sch); } - if(xctx->tok_size && sch[0]) { /* "schematic" token exists and a schematic is specified */ + if(schematic_token_found && sch[0]) { /* "schematic" token exists and a schematic is specified */ int j; char *sym = NULL; - char *templ = NULL; char *symname_attr = NULL; int ignore_schematic = 0; xSymbol *symptr = xctx->inst[i].ptr + xctx->sym; @@ -2030,15 +2032,13 @@ void get_additional_symbols(int what) my_strdup2(_ALLOC_ID_, &sym, add_ext(rel_sym_path(sch), ".sym")); } - my_strdup2(_ALLOC_ID_, &templ, get_tok_value(symptr->prop_ptr, "template", 0)); my_mstrcat(_ALLOC_ID_, &symname_attr, "symname=", get_cell(sym, 0), NULL); my_mstrcat(_ALLOC_ID_, &symname_attr, " symref=", get_sym_name(i, 9999, 1, 1), NULL); my_strdup(_ALLOC_ID_, &spice_sym_def, translate3(spice_sym_def, 1, xctx->inst[i].prop_ptr, - templ, - symname_attr)); + symptr->templ, + symname_attr, NULL)); dbg(1, "get_additional_symbols(): spice_sym_def=%s\n", spice_sym_def); - my_free(_ALLOC_ID_, &templ); my_free(_ALLOC_ID_, &symname_attr); /* if instance symbol has default_schematic set to ignore copy the symbol anyway, since * the base symbol will not be netlisted by *_block_netlist() */ @@ -2131,7 +2131,7 @@ void get_sch_from_sym(char *filename, xSymbol *sym, int inst, int fallback) /* resolve schematic=generator.tcl( @n ) where n=11 is defined in instance attrs */ if(inst >=0 ) { my_strdup(_ALLOC_ID_, &str_tmp, translate3(get_tok_value(xctx->inst[inst].prop_ptr,"schematic", 6), - 1, xctx->inst[inst].prop_ptr, NULL, NULL)); + 1, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); } if(!str_tmp) my_strdup2(_ALLOC_ID_, &str_tmp, get_tok_value(sym->prop_ptr, "schematic", 6)); if(str_tmp[0]) { /* schematic attribute in symbol or instance was given */ @@ -2395,8 +2395,7 @@ int descend_schematic(int instnumber, int fallback, int alert, int set_title) my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch].prop_ptr, xctx->inst[n].prop_ptr); - my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch].templ, - get_tok_value(xctx->sym[xctx->inst[n].ptr].prop_ptr, "template", 0)); + my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch].templ, xctx->sym[xctx->inst[n].ptr].templ); dbg(1,"descend_schematic(): inst_number=%d\n", inst_number); my_strcat(_ALLOC_ID_, &xctx->sch_path[xctx->currsch+1], find_nth(str, ",", "", 0, inst_number)); @@ -2593,6 +2592,7 @@ void calc_drawing_bbox(xRect *boundbox, int selected) #endif char *estr = NULL; + xctx->show_hidden_texts = tclgetboolvar("show_hidden_texts"); boundbox->x1=-100; boundbox->x2=100; boundbox->y1=-100; @@ -2689,6 +2689,8 @@ void calc_drawing_bbox(xRect *boundbox, int selected) int no_of_lines; double longest_line; if(selected == 1 && !xctx->text[i].sel) continue; + + if(!xctx->show_hidden_texts && xctx->text[i].flags & (HIDE_TEXT | HIDE_TEXT_INSTANTIATED)) continue; #if HAS_CAIRO==1 customfont = set_text_custom_font(&xctx->text[i]); #endif @@ -2843,6 +2845,7 @@ void set_viewport_size(int w, int h, double lw) void save_restore_zoom(int save, Zoom_info *zi) { if(save) { + dbg(1, "save_restore_zoom: save width= %d, height=%d\n", xctx->xrect[0].width, xctx->xrect[0].height); zi->savew = xctx->xrect[0].width; zi->saveh = xctx->xrect[0].height; zi->savelw = xctx->lw; @@ -2854,6 +2857,7 @@ void save_restore_zoom(int save, Zoom_info *zi) xctx->xrect[0].y = 0; xctx->xrect[0].width = (unsigned short)zi->savew; xctx->xrect[0].height = (unsigned short)zi->saveh; + dbg(1, "save_restore_zoom: restore width= %d, height=%d\n", xctx->xrect[0].width, xctx->xrect[0].height); xctx->areax2 = zi->savew+2*INT_WIDTH(zi->savelw); xctx->areay2 = zi->saveh+2*INT_WIDTH(zi->savelw); xctx->areax1 = -2*INT_WIDTH(zi->savelw); diff --git a/src/callback.c b/src/callback.c index 056e3062..45e95cec 100644 --- a/src/callback.c +++ b/src/callback.c @@ -441,10 +441,6 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int /* determine if mouse pointer is below xaxis or left of yaxis in some graph */ setup_graph_data(i, 0, gr); - - - - /* check if user clicked on a wave label -> draw wave in bold */ if(event == ButtonPress && button == Button3 && edit_wave_attributes(2, i, gr)) { @@ -908,7 +904,10 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int } /* loop: after having operated on the master graph do the others */ for(i=0; i< xctx->rects[GRIDLAYER]; ++i) { + int same_sim_type = 0; + char *curr_sim_type = NULL; r = &xctx->rect[GRIDLAYER][i]; + my_strdup2(_ALLOC_ID_, &curr_sim_type, get_tok_value(r->prop_ptr, "sim_type", 0)); need_redraw = 0; if( !(r->flags & 1) ) continue; /* 1: graph; 3: graph_unlocked */ gr->gx1 = gr->master_gx1; @@ -918,6 +917,12 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int if(gr->dataset >= 0 /* && gr->dataset < xctx->raw->datasets */) dataset =gr->dataset; else dataset = -1; + if(!strcmp(curr_sim_type, + get_tok_value(xctx->rect[GRIDLAYER][xctx->graph_master].prop_ptr, "sim_type", 0))) { + same_sim_type = 1; + } + my_free(_ALLOC_ID_, &curr_sim_type); + if(event == MotionNotify && (state & Button1Mask) && !xctx->graph_bottom && !(xctx->graph_flags & (16 | 32 | 512 | 1024))) { double delta; @@ -955,7 +960,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int delta = gr->gw; delta_threshold = 0.01; /* selected or locked or master */ - if( r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if( r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { dbg(1, "moving waves: %d\n", i); if(fabs(xctx->mx_double_save - xctx->mousex_snap) > fabs(gr->cx * delta) * delta_threshold) { xx1 = gr->gx1 + (xctx->mx_double_save - xctx->mousex_snap) / gr->cx; @@ -994,7 +999,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int /* horizontal move of waveforms with mouse wheel */ else { /* selected or locked or master */ - if( r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if( r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { delta = gr->gw; delta_threshold = 0.05; xx1 = gr->gx1 - delta * delta_threshold; @@ -1031,7 +1036,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int /* horizontal move of waveforms with mouse wheel */ else { /* selected or locked or master */ - if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { delta = gr->gw; delta_threshold = 0.05; xx1 = gr->gx1 + delta * delta_threshold; @@ -1072,7 +1077,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int } } else { /* selected or locked or master */ - if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { double var = 0.2 * gr->gw; xx2 = gr->gx2 + var * (1 - zoom_m); xx1 = gr->gx1 - var * zoom_m; @@ -1111,7 +1116,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int } } else { /* selected or locked or master */ - if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { double var = 0.2 * gr->gw; xx2 = gr->gx2 - var * (1 - zoom_m); xx1 = gr->gx1 + var * zoom_m; @@ -1190,13 +1195,15 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int need_redraw = 1; } } else { - delta = gr->gw; - delta_threshold = 0.05; - xx1 = gr->gx1 - delta * delta_threshold; - xx2 = gr->gx2 - delta * delta_threshold; - my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); - my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); - need_redraw = 1; + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + delta = gr->gw; + delta_threshold = 0.05; + xx1 = gr->gx1 - delta * delta_threshold; + xx2 = gr->gx2 - delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } } } else if(event == KeyPress && key == XK_Right) { @@ -1215,13 +1222,15 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int need_redraw = 1; } } else { - delta = gr->gw; - delta_threshold = 0.05; - xx1 = gr->gx1 + delta * delta_threshold; - xx2 = gr->gx2 + delta * delta_threshold; - my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); - my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); - need_redraw = 1; + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { + delta = gr->gw; + delta_threshold = 0.05; + xx1 = gr->gx1 + delta * delta_threshold; + xx2 = gr->gx2 + delta * delta_threshold; + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); + my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x2", dtoa(xx2))); + need_redraw = 1; + } } } else if(event == KeyPress && key == XK_Down) { @@ -1258,7 +1267,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int } /* graph_master */ } else { /* not graph_left, full X zoom*/ /* selected or locked or master */ - if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { need_redraw = graph_fullxzoom(i, gr, dataset); } } @@ -1268,7 +1277,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int else if(event == MotionNotify && (state & Button1Mask) && xctx->graph_bottom ) { if(xctx->raw && xctx->raw->values) { /* selected or locked or master */ - if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { /* xx1 and xx2 calculated for master graph above */ my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "x1", dtoa(xx1))); @@ -1288,7 +1297,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int else if(button == Button3 && (xctx->ui_state & GRAPHPAN) && !xctx->graph_left && !xctx->graph_top) { /* selected or locked or master */ - if(r->sel || !(r->flags & 2) || i == xctx->graph_master) { + if(r->sel || (same_sim_type && !(r->flags & 2)) || i == xctx->graph_master) { if(xctx->mx_double_save != xctx->mousex_snap) { clear_graphpan_at_end = 1; @@ -1686,6 +1695,16 @@ static int end_place_move_copy_zoom() return 0; } +static void unselect_at_mouse_pos(int mx, int my) +{ + xctx->last_command = 0; + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex_snap; + xctx->my_double_save=xctx->mousey_snap; + select_object(xctx->mousex, xctx->mousey, 0, 0, NULL); + rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ +} + void snapped_wire(double c_snap) { double x, y; @@ -1706,11 +1725,22 @@ void snapped_wire(double c_snap) } } -static int check_menu_start_commands(double c_snap) +static int check_menu_start_commands(double c_snap, int mx, int my) { dbg(1, "check_menu_start_commands(): ui_state=%x, ui_state2=%x last_command=%d\n", xctx->ui_state, xctx->ui_state2, xctx->last_command); + if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTDESEL) ) { + if(xctx->ui_state & DESEL_CLICK) { + unselect_at_mouse_pos(mx, my); + } else { /* unselect by area */ + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + xctx->ui_state |= DESEL_AREA; + } + return 1; + } if((xctx->ui_state & MENUSTART) && (xctx->ui_state2 & MENUSTARTWIRECUT)) { break_wires_at_point(xctx->mousex_snap, xctx->mousey_snap, 1); return 1; @@ -2274,7 +2304,7 @@ static void end_shape_point_edit(double c_snap) } #if defined(__unix__) && HAS_CAIRO==1 -static int grabscreen(const char *winpath, int event, int mx, int my, KeySym key, +static int grabscreen(const char *win_path, int event, int mx, int my, KeySym key, int button, int aux, int state) { static int grab_state = 0; @@ -2401,8 +2431,8 @@ static int grabscreen(const char *winpath, int event, int mx, int my, KeySym key /* main window callback */ /* mx and my are set to the mouse coord. relative to window */ -/* winpath: set to .drw or sub windows .x1.drw, .x2.drw, ... */ -int callback(const char *winpath, int event, int mx, int my, KeySym key, +/* win_path: set to .drw or sub windows .x1.drw, .x2.drw, ... */ +int callback(const char *win_path, int event, int mx, int my, KeySym key, int button, int aux, int state) { char str[PATH_MAX + 100]; @@ -2431,9 +2461,9 @@ int rstate; /* (reduced state, without ShiftMask) */ * on such events */ if(fix_mouse_coord) { if(event == KeyPress || event == KeyRelease) { - tclvareval("getmousex ", winpath, NULL); + tclvareval("getmousex ", win_path, NULL); mx = atoi(tclresult()); - tclvareval("getmousey ", winpath, NULL); + tclvareval("getmousey ", win_path, NULL); my = atoi(tclresult()); dbg(1, "mx = %d my=%d\n", mx, my); } @@ -2474,21 +2504,21 @@ int rstate; /* (reduced state, without ShiftMask) */ #if 0 /* exclude Motion and Expose events */ if(event!=6 /* && event!=12 */) { - dbg(0, "callback(): state=%d event=%d, winpath=%s, old_winpath=%s, semaphore=%d\n", - state, event, winpath, old_winpath, xctx->semaphore+1); + dbg(0, "callback(): state=%d event=%d, win_path=%s, old_win_path=%s, semaphore=%d\n", + state, event, win_path, old_win_path, xctx->semaphore+1); } #endif /* Schematic window context switch */ redraw_only =0; - if(strcmp(old_winpath, winpath) ) { + if(strcmp(old_win_path, win_path) ) { if( xctx->semaphore >= 1 || event == Expose) { - dbg(1, "callback(): semaphore >=2 (or Expose) switching window context: %s --> %s\n", old_winpath, winpath); + dbg(1, "callback(): semaphore >=2 (or Expose) switching window context: %s --> %s\n", old_win_path, win_path); redraw_only = 1; - new_schematic("switch_no_tcl_ctx", winpath, "", 1); + new_schematic("switch_no_tcl_ctx", win_path, "", 1); } else { - dbg(1, "callback(): switching window context: %s --> %s, semaphore=%d\n", old_winpath, winpath, xctx->semaphore); - new_schematic("switch", winpath, "", 1); + dbg(1, "callback(): switching window context: %s --> %s, semaphore=%d\n", old_win_path, win_path, xctx->semaphore); + new_schematic("switch", win_path, "", 1); } tclvareval("housekeeping_ctx", NULL); } @@ -2533,7 +2563,7 @@ int rstate; /* (reduced state, without ShiftMask) */ #if defined(__unix__) && HAS_CAIRO==1 if(xctx->ui_state & GRABSCREEN) { - grabscreen(winpath, event, mx, my, key, button, aux, state); + grabscreen(win_path, event, mx, my, key, button, aux, state); } else #endif switch(event) @@ -2577,7 +2607,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; case Expose: - dbg(1, "callback: Expose, winpath=%s, %dx%d+%d+%d\n", winpath, button, aux, mx, my); + dbg(1, "callback: Expose, win_path=%s, %dx%d+%d+%d\n", win_path, button, aux, mx, my); MyXCopyArea(display, xctx->save_pixmap, xctx->window, xctx->gc[0], mx,my,button,aux,mx,my); { XRectangle xr[1]; @@ -2639,7 +2669,7 @@ int rstate; /* (reduced state, without ShiftMask) */ /* determine direction of a rectangle selection (or unselection with ALT key) */ if(xctx->ui_state & STARTSELECT && !(xctx->ui_state & (PLACE_SYMBOL | STARTPAN | PLACE_TEXT)) ) { /* Unselect by area : determine direction */ - if( (state & Button1Mask) && SET_MODMASK) { + if( ((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) { if(mx >= xctx->mx_save) xctx->nl_dir = 0; else xctx->nl_dir = 1; select_rect(enable_stretch, RUBBER,0); @@ -2692,12 +2722,13 @@ int rstate; /* (reduced state, without ShiftMask) */ } } /* Unselect by area */ - if((state & Button1Mask) && (SET_MODMASK) && !(state & ShiftMask) && - !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && + if( (((state & Button1Mask) && SET_MODMASK) || (xctx->ui_state & DESEL_AREA)) && + !(state & ShiftMask) && + !(xctx->ui_state & STARTPAN) && + !xctx->shape_point_selected && + !(xctx->ui_state & STARTSELECT) && !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT))) { /* unselect area */ - if( !(xctx->ui_state & STARTSELECT)) { - select_rect(enable_stretch, START,0); - } + select_rect(enable_stretch, START,0); } /* Select by area. Shift pressed */ else if((state&Button1Mask) && (state & ShiftMask) && !(xctx->ui_state & STARTWIRE) && @@ -3081,10 +3112,10 @@ int rstate; /* (reduced state, without ShiftMask) */ tclvareval("xschem set rectcolor ", n, NULL); if(has_x) { - if(!strcmp(winpath, ".drw")) { + if(!strcmp(win_path, ".drw")) { tclvareval("reconfigure_layers_button {}", NULL); } else { - tclvareval("reconfigure_layers_button [winfo parent ", winpath, "]", NULL); + tclvareval("reconfigure_layers_button [winfo parent ", win_path, "]", NULL); } } dbg(1, "callback(): new color: %d\n",xctx->color_index[xctx->rectcolor]); @@ -3826,8 +3857,8 @@ int rstate; /* (reduced state, without ShiftMask) */ if(key=='\\' && state==0) /* fullscreen */ { - dbg(1, "callback(): toggle fullscreen, winpath=%s\n", winpath); - toggle_fullscreen(winpath); + dbg(1, "callback(): toggle fullscreen, win_path=%s\n", win_path); + toggle_fullscreen(win_path); break; } if(key=='f' && EQUAL_MODMASK) /* flip objects around their anchor points 20171208 */ @@ -3988,43 +4019,8 @@ int rstate; /* (reduced state, without ShiftMask) */ } if(key=='n' && rstate==0) /* hierarchical netlist */ { - int err = 0; - yyparse_error = 0; if(xctx->semaphore >= 2) break; - unselect_all(1); - if(set_netlist_dir(0, NULL)) { - dbg(1, "callback(): -------------\n"); - if(xctx->netlist_type == CAD_SPICE_NETLIST) - err = global_spice_netlist(1, 1); - else if(xctx->netlist_type == CAD_VHDL_NETLIST) - err = global_vhdl_netlist(1, 1); - else if(xctx->netlist_type == CAD_VERILOG_NETLIST) - err = global_verilog_netlist(1, 1); - else if(xctx->netlist_type == CAD_TEDAX_NETLIST) - err = global_tedax_netlist(1, 1); - else - tcleval("tk_messageBox -type ok -parent [xschem get topwindow] " - "-message {Please Set netlisting mode (Options menu)}"); - - dbg(1, "callback(): -------------\n"); - } - else { - if(has_x) tcleval("alert_ {Can not write into the netlist directory. Please check} {}"); - else dbg(0, "Can not write into the netlist directory. Please check"); - err = 1; - } - if(err) { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background red", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist red", NULL); - } - - } else { - if(has_x) { - tclvareval(xctx->top_path, ".menubar entryconfigure Netlist -background Green", NULL); - tclvareval("set tctx::", xctx->current_win_path, "_netlist Green", NULL); - } - } + tcleval("xschem netlist -erc"); break; } if(key=='N' && rstate == 0) /* current level only netlist */ @@ -4153,7 +4149,33 @@ int rstate; /* (reduced state, without ShiftMask) */ draw(); break; } - if(key=='D' && rstate == 0) /* delete files */ + if(key=='d' && rstate == 0) /* unselect object under the mouse */ + { + if(infix_interface) { + unselect_at_mouse_pos(mx, my); + } else { + xctx->ui_state |= (MENUSTART | DESEL_CLICK); + xctx->ui_state2 = MENUSTARTDESEL; + } + break; + } + if(key=='D' && rstate == 0) /* unselect by area */ + { + if( !(xctx->ui_state & STARTPAN) && !xctx->shape_point_selected && + !(xctx->ui_state & (PLACE_SYMBOL | PLACE_TEXT)) && !(xctx->ui_state & STARTSELECT)) { + if(infix_interface) { + xctx->mx_save = mx; xctx->my_save = my; + xctx->mx_double_save=xctx->mousex; + xctx->my_double_save=xctx->mousey; + xctx->ui_state |= DESEL_AREA; + } else { + xctx->ui_state |= MENUSTART; + xctx->ui_state2 = MENUSTARTDESEL; + } + } + break; + } + if(key=='d' && rstate == ControlMask) /* delete files */ { if(xctx->semaphore >= 2) break; delete_files(); @@ -4294,12 +4316,7 @@ int rstate; /* (reduced state, without ShiftMask) */ } /* Alt - Button1 click to unselect */ else if(button==Button1 && (SET_MODMASK) ) { - xctx->last_command = 0; - xctx->mx_save = mx; xctx->my_save = my; - xctx->mx_double_save=xctx->mousex_snap; - xctx->my_double_save=xctx->mousey_snap; - select_object(xctx->mousex, xctx->mousey, 0, 0, NULL); - rebuild_selected_array(); /* sets or clears xctx->ui_state SELECTION flag */ + unselect_at_mouse_pos(mx, my); } /* Middle button press (Button2) will pan the schematic. */ @@ -4350,7 +4367,7 @@ int rstate; /* (reduced state, without ShiftMask) */ break; } /* handle all object insertions started from Tools/Edit menu */ - if(check_menu_start_commands(c_snap)) break; + if(check_menu_start_commands(c_snap, mx, my)) break; /* complete the pending STARTWIRE, STARTRECT, STARTZOOM, STARTCOPY ... operations */ if(end_place_move_copy_zoom()) break; @@ -4488,6 +4505,7 @@ int rstate; /* (reduced state, without ShiftMask) */ waves_callback(event, mx, my, key, button, aux, state); break; } + xctx->ui_state &= ~DESEL_CLICK; dbg(1, "release: shape_point_selected=%d\n", xctx->shape_point_selected); /* bring up context menu if no pending operation */ if(state == Button3Mask && xctx->semaphore <2) { @@ -4563,6 +4581,7 @@ int rstate; /* (reduced state, without ShiftMask) */ select_rect(enable_stretch, END,-1); } } + xctx->ui_state &= ~DESEL_AREA; rebuild_selected_array(); my_snprintf(str, S(str), "mouse = %.16g %.16g - selected: %d path: %s", xctx->mousex_snap, xctx->mousey_snap, xctx->lastsel, xctx->sch_path[xctx->currsch] ); @@ -4621,13 +4640,13 @@ int rstate; /* (reduced state, without ShiftMask) */ if(xctx->semaphore > 0) xctx->semaphore--; if(redraw_only) { xctx->semaphore--; /* decrement articially incremented semaphore (see above) */ - dbg(1, "callback(): semaphore >=2 restoring window context: %s <-- %s\n", old_winpath, winpath); - if(old_winpath[0]) new_schematic("switch_no_tcl_ctx", old_winpath, "", 1); + dbg(1, "callback(): semaphore >=2 restoring window context: %s <-- %s\n", old_win_path, win_path); + if(old_win_path[0]) new_schematic("switch_no_tcl_ctx", old_win_path, "", 1); } else - if(strcmp(old_winpath, winpath)) { - if(old_winpath[0]) dbg(1, "callback(): reset old_winpath: %s <- %s\n", old_winpath, winpath); - my_strncpy(old_winpath, winpath, S(old_winpath)); + if(strcmp(old_win_path, win_path)) { + if(old_win_path[0]) dbg(1, "callback(): reset old_win_path: %s <- %s\n", old_win_path, win_path); + my_strncpy(old_win_path, win_path, S(old_win_path)); } return 0; } diff --git a/src/draw.c b/src/draw.c index b6c5fe6e..b7c057dc 100644 --- a/src/draw.c +++ b/src/draw.c @@ -736,7 +736,7 @@ void draw_symbol(int what,int c, int n,int layer,short tmp_flip, short rot, dbg(1, "draw_symbol(): drawing string: str=%s prop=%s\n", txtptr, text.prop_ptr ? text.prop_ptr : ""); my_strdup2(_ALLOC_ID_, &txtptr, translate3(txtptr, 1, xctx->inst[n].prop_ptr, - xctx->sym[xctx->inst[n].ptr].templ, NULL )); + xctx->sym[xctx->inst[n].ptr].templ, NULL, NULL)); dbg(1, "draw_symbol(): after translate3: str=%s\n", txtptr); draw_string(textlayer, what, txtptr, (text.rot + ( (flip && (text.rot & 1) ) ? rot+2 : rot) ) & 0x3, @@ -906,7 +906,7 @@ void draw_temp_symbol(int what, GC gc, int n,int layer,short tmp_flip, short rot my_strdup2(_ALLOC_ID_, &txtptr, translate(n, text.txt_ptr)); /* do another round of substitutions if some @var are found, but if not found leave @var as is */ my_strdup2(_ALLOC_ID_, &txtptr, translate3(txtptr, 1, xctx->inst[n].prop_ptr, - xctx->sym[xctx->inst[n].ptr].templ, NULL )); + xctx->sym[xctx->inst[n].ptr].templ, NULL, NULL)); dbg(1, "draw_temp_symbol(): after translate3: str=%s\n", txtptr); if(txtptr[0]) draw_temp_string(gc, what, txtptr, (text.rot + ( (flip && (text.rot & 1) ) ? rot+2 : rot) ) & 0x3, @@ -2543,7 +2543,7 @@ int graph_fullyzoom(xRect *r, Graph_ctx *gr, int graph_dataset) if(gr->logx) xx = mylog10(gv[p]); else xx = gv[p]; if(p == ofs) xx0 = gv0[p]; - wrap = (cnt > 1 && gv0[p] == xx0); + wrap = !strcmp(xctx->raw->sim_type, "dc") && cnt > 1 && gv0[p] == xx0; if(wrap) { sweepvar_wrap++; cnt = 0; @@ -3568,7 +3568,7 @@ int calc_custom_data_yrange(int sweep_idx, const char *express, Graph_ctx *gr) xx = gv[p]; if(p == ofs) xx0 = gv0[p]; - wrap = ( cnt > 1 && gv0[p] == xx0); + wrap = !strcmp(xctx->raw->sim_type, "dc") && cnt > 1 && gv0[p] == xx0; if(first != -1) { /* there is something to plot ... */ if(xx > end || xx < start || /* ... and we ran out of graph area ... */ wrap) { /* ... or sweep variable changed direction */ @@ -3713,7 +3713,7 @@ int find_closest_wave(int i, Graph_ctx *gr) if(gr->logy) yy = mylog10(gvy[p]); else yy = gvy[p]; if(p == ofs) xx0 = gv0[p]; - wrap = (cnt > 1 && gv0[p] == xx0); + wrap = !strcmp(xctx->raw->sim_type, "dc") && cnt > 1 && gv0[p] == xx0; if(first != -1) { if(xx > end || xx < start || wrap) { dbg(1, "find_closest_wave(): last=%d\n", last); @@ -4026,7 +4026,6 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct) /* optimization: skip unwanted datasets, if no dc no need to detect sweep variable wraps */ if(dataset >= 0 && strcmp(xctx->raw->sim_type, "dc") && dataset != sweepvar_wrap) goto done; - for(p = ofs ; p < ofs_end; p++) { double xxprevious, xxfollowing; @@ -4038,7 +4037,7 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct) * are simulated and thos no equality test can be done, and any "approx equal" test si going * to do unexpected things (liek in simulations with very dense steps) */ if(p == ofs) xx0 = gv0[p]; /* gv[p];*/ - wrap = cnt > 1 && gv0[p] == xx0; + wrap = !strcmp(xctx->raw->sim_type, "dc") && cnt > 1 && gv0[p] == xx0; #if 1 /* plot one point before start and one point after end so * waves will extend to whole graph area even if there are few points * but NOT if we are about to wrap (missing 1st/last point in 2-var dc sweeps) */ @@ -4778,7 +4777,7 @@ void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2, cairo_surface_t *png_sfc; int save, save_draw_window, save_draw_grid, rwi, rhi; size_t olength; - const double max_size = 3000.0; + const double max_size = 2500.0; if(!has_x) return; @@ -4793,9 +4792,9 @@ void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2, rw = fabs(rx2 -rx1); rh = fabs(ry2 - ry1); scale = 3.0; - if(rw > rh && rw > max_size) { + if(rw > rh && rw * scale > max_size) { scale = max_size / rw; - } else if(rh > max_size) { + } else if(rh * scale > max_size) { scale = max_size / rh; } rwi = (int) (rw * scale + 1.0); @@ -4851,7 +4850,7 @@ void svg_embedded_graph(FILE *fd, xRect *r, double rx1, double ry1, double rx2, xctx->do_copy_area=save; tclsetboolvar("draw_grid", save_draw_grid); save_restore_zoom(0, &zi); - resetwin(1, 1, 1, xctx->xrect[0].width, xctx->xrect[0].height); + resetwin(1, 1, 1, 0, 0); h = fabs(y2 - y1); w = fabs(x2 - x1); @@ -4883,7 +4882,6 @@ void draw(void) #endif dbg(1, "draw()\n"); - if(!xctx || xctx->no_draw) return; cs = tclgetdoublevar("cadsnap"); diff --git a/src/editprop.c b/src/editprop.c index f40a65a4..44a5d8e0 100644 --- a/src/editprop.c +++ b/src/editprop.c @@ -1475,7 +1475,7 @@ int drc_check(int i) my_strdup(_ALLOC_ID_, &drc, get_tok_value(xctx->sym[xctx->inst[j].ptr].prop_ptr, "drc", 2)); if(drc) { my_strdup(_ALLOC_ID_, &res, translate3(drc, 1, - xctx->inst[j].prop_ptr, xctx->sym[xctx->inst[j].ptr].templ, NULL)); + xctx->inst[j].prop_ptr, xctx->sym[xctx->inst[j].ptr].templ, NULL, NULL)); dbg(1, "drc_check(): res = |%s|, drc=|%s|\n", res, drc); if(res) { const char *result; diff --git a/src/eval_expr.y b/src/eval_expr.y new file mode 100644 index 00000000..ba954f26 --- /dev/null +++ b/src/eval_expr.y @@ -0,0 +1,277 @@ +%{ +#include +#include /* For math functions, cos(), sin(), etc. */ +#include +#include +#include +#include +#include "xschem.h" + +static const char *str, *strptr; +static char *ret = NULL; + +static int dbglev = 1; + +/* Data type for links in the chain of functions. */ +struct symrec +{ + char *name; /* name of symbol */ + double (*fnctptr)(); /* value of a FNCT */ + struct symrec *next; /* link field */ +}; + +typedef struct symrec symrec; + +/* The symbol table: a chain of `struct symrec'. */ +symrec *sym_table = (symrec *)0; + +static symrec *getsym(char *sym_name); +static symrec *putsym(char *sym_name); +static int kklex(); +static void kkerror(char *s); +static double toint(double x); +static void get_expr(double x); +static void get_char(int c); + +struct fn +{ + char *fname; + double (*fnct)(); +}; +static int lex_state = 0; +struct fn fn_array[] + = { + {"int" , toint}, + {"sin" , sin}, + {"cos" , cos}, + {"asin", asin}, + {"acos", acos}, + {"atan", atan}, + {"log" , log10}, + {"ln" , log}, + {"exp" , exp}, + {"sqrt", sqrt}, + {0 , 0} + }; +%} + +%define api.prefix {kk} +%union { +int c; +double val; /* For returning numbers. */ +symrec *tptr; /* For returning symbol-table pointers */ +} + +%token STREND 0 +%token CHAR +%token EXPR /* expr( */ +%token NUM /* Simple double precision number */ +%token FNCT /* Variable and Function */ +%type exp +%right '=' +%left '-' '+' +%left '*' '/' '%' +%left NEG /* Negation--unary minus */ +%right '^' /* Exponentiation */ + +/* Grammar follows */ +%% +input: + | input line +; + +line: + CHAR {get_char($1);} + | EXPR exp ')' {get_expr($2);lex_state = 0;} + | EXPR '\'' exp '\'' ')' {get_expr($3);lex_state = 0;} + | EXPR exp error +; + +exp: NUM {$$ = $1;} + | FNCT '(' exp ')' {$$ = $1 ? (*($1->fnctptr))($3) : 0.0;} + | exp '+' exp {$$ = $1 + $3; } + | exp '-' exp {$$ = $1 - $3;} + | exp '*' exp {$$ = $1 * $3;} + | exp '%' exp {$$ = (int)$1 % (int)$3;} + | exp '/' exp {$$ = $1 / $3;} + | '-' exp %prec NEG {$$ = -$2;} + | exp '^' exp {$$ = pow ($1, $3);} + | '(' exp ')' {$$ = $2;} +; +/* End of grammar */ +%% + +static void get_char(int c) +{ + char s[2]; + dbg(dbglev, "get_char: %c |%s|\n", c, str); + s[0] = (char)c; + s[1] = '\0'; + my_mstrcat(_ALLOC_ID_, &ret, s, NULL); + strptr = str; +} + +static void get_expr(double x) +{ + char xx[100]; + dbg(dbglev,"get_expr(): x=%g\n", x); + my_snprintf(xx, S(xx), "%.15g", x); + my_mstrcat(_ALLOC_ID_, &ret, xx, NULL); + strptr = str; +} + +static double toint(double x) +{ + if(x < 0.0) return ceil(x); + return floor(x); +} + +/* ad=expr(3*xa) pd=expr(2*(3+xa)) --> ad=3*xa pd=2*(3+xa) */ +static void remove_expr(char *s) +{ + char *ptr = s; + int plev = 0; + while(*ptr) { + if(strstr(ptr, "expr(") == ptr) { + ptr += 5; + plev++; + } + if(*ptr == '(') plev++; + if(*ptr == ')') { + plev--; + if(plev == 0) ptr++; + if(!ptr) break; + } + *s = *ptr; + ptr++; + s++; + } + *s = *ptr; +} + + +static void kkerror(char *s) /* Called by kkparse on error */ +{ + char *ss = NULL; + dbg(dbglev, "error: |%s|\n\n |%s|\n", s, str ? str : ""); + my_strdup2(_ALLOC_ID_, &ss, strptr); + remove_expr(ss); + my_mstrcat(_ALLOC_ID_, &ret, ss, NULL); + my_free(_ALLOC_ID_, &ss); + lex_state = 0; +} + +static symrec *getsym(char *sym_name) +{ + symrec *ptr; + for (ptr = sym_table; ptr; ptr = ptr->next) + if (strcmp (ptr->name,sym_name) == 0) return ptr; + return NULL; +} + +symrec * putsym (char *sym_name) +{ + symrec *ptr; + ptr = (symrec *) my_malloc(_ALLOC_ID_, sizeof (symrec)); + ptr->name = (char *) my_malloc(_ALLOC_ID_, strlen (sym_name) + 1); + strcpy (ptr->name,sym_name); + ptr->next = (struct symrec *)sym_table; + sym_table = ptr; + return ptr; +} + +void eval_expr_init_table(void) /* puts arithmetic functions in table. */ +{ + int i; + symrec *ptr; + for (i = 0; fn_array[i].fname != 0; i++) + { + ptr = putsym (fn_array[i].fname); + ptr->fnctptr = fn_array[i].fnct; + } +} + +void eval_expr_clear_table(void) +{ + symrec *ptr; + for (ptr = sym_table; ptr; ptr = ptr->next) { + symrec *tmp = ptr; + my_free(_ALLOC_ID_, &(tmp->name)); + my_free(_ALLOC_ID_, &tmp); + } +} + +static int kklex() +{ + int c; + + if(!str) { return 0; } + if(strstr(str, "expr(") == str) { + lex_state = 1; + str += 5; + dbg(dbglev, "lex(): EXPR\n"); + return EXPR; + } + if(!lex_state) { + c = *str++; + if(c) { + kklval.c = c; + dbg(dbglev, "lex(): CHAR; %c\n", c); + return CHAR; + } else { + dbg(dbglev, "lex(): STREND\n"); + return STREND; + } + } + /* Ignore whitespace, get first nonwhite character. */ + while ((c = *str++) == ' ' || c == '\t' || c == '\n'); + if (c == 0) { + str = NULL; + return 0; + } + /* Char starts a number => parse the number. */ + if (c == '.' || isdigit (c)) + { + char s[100] =""; + int rd = 0; + str--; + + sscanf(str, "%99[.0-9a-zA-Z_]%n", s, &rd); + kklval.val = atof_spice(s); + str += rd; + dbg(dbglev, "lex(): NUM: %s\n", s); + return NUM; + } + /* Char starts an identifier => read the name. */ + if(isalpha(c)) { + symrec *s; + int length = 40; /* max length of function names */ + char symbuf[41]; + int i = 0; + /* Initially make the buffer int enough + * for a 40-character symbol name. */ + do + { + symbuf[i++] = (char) c; /* Add this character to the buffer.*/ + c = *str++; /* Get another character.*/ + } + while (c != 0 && isalnum(c) && i < length); + str--; + symbuf[i] = '\0'; + s = getsym (symbuf); + kklval.tptr = s; + dbg(dbglev, "ylex: FNCT=%s\n", symbuf); + return FNCT; + } + /* Any other character is a token by itself. */ + return c; +} + +char *eval_expr(const char *s) +{ + lex_state = 0; + if(ret) my_free(_ALLOC_ID_, &ret); + strptr = str = s; + kkparse(); + return ret; +} diff --git a/src/globals.c b/src/globals.c index 36c2984a..7a270d4d 100644 --- a/src/globals.c +++ b/src/globals.c @@ -186,7 +186,7 @@ int yyparse_error = 0; char *xschem_executable=NULL; Tcl_Interp *interp = NULL; double *character[256]; /* array or per-char coordinates of xschem internal vector font */ -char old_winpath[PATH_MAX] = ".drw"; /* previously switched window, used in callback() */ +char old_win_path[PATH_MAX] = ".drw"; /* previously switched window, used in callback() */ #ifndef __unix__ char win_temp_dir[PATH_MAX]=""; const char fopen_read_mode[] = "rb"; diff --git a/src/keys.help b/src/keys.help index cc2db919..a73197bf 100644 --- a/src/keys.help +++ b/src/keys.help @@ -96,7 +96,9 @@ ctrl 'c' Save to clipboard shift 'C' Start arc placement shift+ctrl 'C' Start circle placement alt 'C' Toggle dim/brite background with rest of layers -shift 'D' Delete files +ctrl 'd' Delete files +- 'd' Unselect selected object under the mouse pointer +shift 'D' Unselect selected objects by area ctrl 'e' Back to parent schematic - 'e' Descend to schematic alt 'e' Edit selected schematic in a new window diff --git a/src/psprint.c b/src/psprint.c index 6ea4281a..295ed1ed 100644 --- a/src/psprint.c +++ b/src/psprint.c @@ -257,7 +257,7 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl double rw, rh, scale; cairo_surface_t* png_sfc; int save, save_draw_window, save_draw_grid, rwi, rhi; - const double max_size = 3000.0; + const double max_size = 2500.0; int d_c; unsigned char* jpgData = NULL; size_t fileSize = 0; @@ -292,15 +292,16 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl rw = fabs(rx2 - rx1); rh = fabs(ry2 - ry1); scale = 3.0; - if (rw > rh && rw > max_size) { + if (rw > rh && rw * scale > max_size) { scale = max_size / rw; } - else if (rh > max_size) { + else if (rh * scale > max_size) { scale = max_size / rh; } rwi = (int)(rw * scale + 1.0); rhi = (int)(rh * scale + 1.0); dbg(1, "graph size: %dx%d\n", rwi, rhi); + dbg(1, "ps_embedded_graph: saving zoom\n"); save_restore_zoom(1, &zi); set_viewport_size(rwi, rhi, xctx->lw); @@ -353,8 +354,9 @@ static int ps_embedded_graph(xRect* r, double rx1, double ry1, double rx2, doubl cairo_surface_destroy(png_sfc); xctx->draw_pixmap = 1; tclsetboolvar("draw_grid", save_draw_grid); + dbg(1, "ps_embedded_graph: restoring zoom\n"); save_restore_zoom(0, &zi); - resetwin(1, 1, 1, xctx->xrect[0].width, xctx->xrect[0].height); + resetwin(1, 1, 1, 0, 0); change_linewidth(xctx->lw); tclsetboolvar("dark_colorscheme", d_c); build_colors(0, 0); @@ -1178,8 +1180,8 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) fprintf(errfp, "ps_draw(): can not create tmpfile %s\n", *psfile); return; } + setbuf(fd, NULL); /*To prevent buffer errors, still investigating cause. */ } - setbuf(fd, NULL); /*To prevent buffer errors, still investigating cause. */ ps_colors=my_calloc(_ALLOC_ID_, cadlayers, sizeof(Ps_color)); if(ps_colors==NULL){ fprintf(errfp, "create_ps(): calloc error\n"); @@ -1190,78 +1192,83 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) old_grid=tclgetboolvar("draw_grid"); tclsetvar("draw_grid", "0"); - /* xschem window aspect ratio decides if portrait or landscape */ - boundbox.x1 = xctx->areax1; - boundbox.x2 = xctx->areax2; - boundbox.y1 = xctx->areay1; - boundbox.y2 = xctx->areay2; - dx=boundbox.x2-boundbox.x1; - dy=boundbox.y2-boundbox.y1; - - /* xschem drawing bbox decides if portrait or landscape */ - if(fullzoom == 1) { - calc_drawing_bbox(&boundbox, 0); - dx=boundbox.x2-boundbox.x1; - dy=boundbox.y2-boundbox.y1; - } - if(dx >= dy) { - landscape = 1; - } else { - landscape = 0; - } - dbg(1, "dx=%g, dy=%g\n", dx, dy); - if(fullzoom == 1) { - /* save size and zoom factor */ - save_restore_zoom(1, &zi); - /* this zoom only done to reset lw */ - zoom_full(0, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); - /* adjust aspect ratio to paper size */ - if(landscape) - xctx->xrect[0].height = (short unsigned int) (xctx->xrect[0].width * pagey / pagex); - else - xctx->xrect[0].width = (short unsigned int) (xctx->xrect[0].height * pagey / pagex); - dbg(1, "xrect.width=%d, xrect.height=%d\n", xctx->xrect[0].width, xctx->xrect[0].height); - xctx->areax1 = -2*INT_WIDTH(xctx->lw); - xctx->areay1 = -2*INT_WIDTH(xctx->lw); - xctx->areax2 = xctx->xrect[0].width+2*INT_WIDTH(xctx->lw); - xctx->areay2 = xctx->xrect[0].height+2*INT_WIDTH(xctx->lw); - xctx->areaw = xctx->areax2-xctx->areax1; - xctx->areah = xctx->areay2 - xctx->areay1; - dbg(1, "dx=%g, dy=%g\n", dx, dy); - /* fit schematic into adjusted size */ - zoom_full(0, 0, 0 + 2 * tclgetboolvar("zoom_full_center"), 0.97); + if(!(what & 4)) { + /* xschem window aspect ratio decides if portrait or landscape */ boundbox.x1 = xctx->areax1; boundbox.x2 = xctx->areax2; boundbox.y1 = xctx->areay1; boundbox.y2 = xctx->areay2; dx=boundbox.x2-boundbox.x1; dy=boundbox.y2-boundbox.y1; - } - - if(!landscape) { /* decide paper orientation for best schematic fit */ - double tmp; - tmp = pagex; - pagex = pagey; - pagey = tmp; - } - if(fullzoom == 2) { /* set media size to bbox */ - double sc; - my_strncpy(papername, "bbox", S(papername)); - pagex = xctx->xrect[0].width; - pagey = xctx->xrect[0].height; - if(pagex > pagey) { - sc = 842. / pagex; - pagex = my_round(pagex * sc); - pagey = my_round(pagey * sc); - } else { - sc = 842. / pagey; - pagex = my_round(pagex * sc); - pagey = my_round(pagey * sc); + + /* xschem drawing bbox decides if portrait or landscape */ + if(fullzoom == 1) { + calc_drawing_bbox(&boundbox, 0); + dx=boundbox.x2-boundbox.x1; + dy=boundbox.y2-boundbox.y1; } - margin = 0.0; - } + if(dx >= dy) { + landscape = 1; + } else { + landscape = 0; + } + dbg(1, "dx=%g, dy=%g\n", dx, dy); + + + if(fullzoom == 1) { + /* save size and zoom factor */ + dbg(1, "create_ps: saving zoom\n"); + save_restore_zoom(1, &zi); + /* this zoom only done to reset lw */ + zoom_full(0, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); + /* adjust aspect ratio to paper size */ + if(landscape) + xctx->xrect[0].height = (short unsigned int) (xctx->xrect[0].width * pagey / pagex); + else + xctx->xrect[0].width = (short unsigned int) (xctx->xrect[0].height * pagey / pagex); + dbg(1, "xrect.width=%d, xrect.height=%d\n", xctx->xrect[0].width, xctx->xrect[0].height); + xctx->areax1 = -2*INT_WIDTH(xctx->lw); + xctx->areay1 = -2*INT_WIDTH(xctx->lw); + xctx->areax2 = xctx->xrect[0].width+2*INT_WIDTH(xctx->lw); + xctx->areay2 = xctx->xrect[0].height+2*INT_WIDTH(xctx->lw); + xctx->areaw = xctx->areax2-xctx->areax1; + xctx->areah = xctx->areay2 - xctx->areay1; + dbg(1, "dx=%g, dy=%g\n", dx, dy); + /* fit schematic into adjusted size */ + zoom_full(0, 0, 0 + 2 * tclgetboolvar("zoom_full_center"), 0.97); + boundbox.x1 = xctx->areax1; + boundbox.x2 = xctx->areax2; + boundbox.y1 = xctx->areay1; + boundbox.y2 = xctx->areay2; + dx=boundbox.x2-boundbox.x1; + dy=boundbox.y2-boundbox.y1; + } + + if(!landscape) { /* decide paper orientation for best schematic fit */ + double tmp; + tmp = pagex; + pagex = pagey; + pagey = tmp; + } + if(fullzoom == 2) { /* set media size to bbox */ + double sc; + my_strncpy(papername, "bbox", S(papername)); + pagex = xctx->xrect[0].width; + pagey = xctx->xrect[0].height; + if(pagex > pagey) { + sc = 842. / pagex; + pagex = my_round(pagex * sc); + pagey = my_round(pagey * sc); + } else { + sc = 842. / pagey; + pagex = my_round(pagex * sc); + pagey = my_round(pagey * sc); + } + margin = 0.0; + } + } /* if(!(what & 4)) */ if(what & 1) {/* prolog */ dbg(1, "ps_draw(): bbox: x1=%g y1=%g x2=%g y2=%g\n", boundbox.x1, boundbox.y1, boundbox.x2, boundbox.y2); @@ -1334,7 +1341,6 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) fprintf(fd, "%%%%EndProlog\n"); } - if(what & 2) { /* page */ ++numpages; @@ -1491,7 +1497,7 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) dbg(1, "ps_draw(): INT_WIDTH(lw)=%d plotfile=%s\n",INT_WIDTH(xctx->lw), xctx->plotfile); fprintf(fd, "showpage\n\n"); - } + } /* if(what & 2) */ if(what & 4) { /* trailer */ fprintf(fd, "%%%%trailer\n"); fprintf(fd, "%%%%Pages: %d\n", numpages); @@ -1509,10 +1515,10 @@ void create_ps(char **psfile, int what, int fullzoom, int eps) /* restore original size and zoom factor */ - if(fullzoom == 1) { + if(!(what & 4) && fullzoom == 1) { + dbg(1, "create_ps: restoring zoom\n"); save_restore_zoom(0, &zi); } - } int ps_draw(int what, int fullzoom, int eps) diff --git a/src/save.c b/src/save.c index c088b816..05638341 100644 --- a/src/save.c +++ b/src/save.c @@ -3446,6 +3446,7 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler { FILE *fd; char name[PATH_MAX]; + char *ffname = NULL; /*copy of fname so I can change it */ char msg[PATH_MAX+100]; struct stat buf; int i, ret = 1; /* success */ @@ -3454,24 +3455,31 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler xctx->prep_net_structs=0; xctx->prep_hash_inst=0; xctx->prep_hash_wires=0; + my_strdup2(_ALLOC_ID_, &ffname, trim_chars(fname, " \t\n")); if(reset_undo) { xctx->clear_undo(); xctx->prev_set_modify = -1; /* will force set_modify(0) to set window title */ } else xctx->prev_set_modify = 0; /* will prevent set_modify(0) from setting window title */ - if(fname && fname[0]) { + if(ffname && ffname[0]) { int generator = 0; - if(is_generator(fname)) generator = 1; - my_strncpy(name, fname, S(name)); - dbg(1, "load_schematic(): fname=%s\n", fname); + /* if ffname is a generator add () at end of filename if not already present */ + tclvareval("is_xschem_file {", ffname, "}", NULL); + if(!strcmp(tclresult(), "GENERATOR")) { + size_t len = strlen(ffname); + if( ffname[len - 1] != ')') my_strcat(_ALLOC_ID_, &ffname, "()"); + } + if(is_generator(ffname)) generator = 1; + my_strncpy(name, ffname, S(name)); + dbg(1, "load_schematic(): name=%s generator=%d\n", name, generator); /* remote web object specified */ - if(is_from_web(fname) && xschem_web_dirname[0]) { + if(is_from_web(ffname) && xschem_web_dirname[0]) { /* download into ${XSCHEM_TMP_DIR}/xschem_web */ - tclvareval("download_url {", fname, "}", NULL); + tclvareval("download_url {", ffname, "}", NULL); /* build local file name of downloaded object */ - my_snprintf(name, S(name), "%s/%s", xschem_web_dirname, get_cell_w_ext(fname, 0)); + my_snprintf(name, S(name), "%s/%s", xschem_web_dirname, get_cell_w_ext(ffname, 0)); /* build current_dirname by stripping off last filename from url */ - my_snprintf(msg, S(msg), "get_directory {%s}", fname); + my_snprintf(msg, S(msg), "get_directory {%s}", ffname); my_strncpy(xctx->current_dirname, tcleval(msg), S(xctx->current_dirname)); /* local file name */ my_strdup2(_ALLOC_ID_, &xctx->sch[xctx->currsch], name); @@ -3482,29 +3490,32 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler /* ... but not local file from web download --> reset current_dirname */ char sympath[PATH_MAX]; my_snprintf(sympath, S(sympath), "%s", xschem_web_dirname); - /* fname does not begin with $XSCHEM_TMP_DIR/xschem_web and fname does not exist */ + /* ffname does not begin with $XSCHEM_TMP_DIR/xschem_web and ffname does not exist */ - if(strstr(fname, sympath) != fname /* && stat(fname, &buf)*/) { - my_snprintf(msg, S(msg), "get_directory {%s}", fname); + if(strstr(ffname, sympath) != ffname /* && stat(ffname, &buf)*/) { + my_snprintf(msg, S(msg), "get_directory {%s}", ffname); my_strncpy(xctx->current_dirname, tcleval(msg), S(xctx->current_dirname)); } /* local file name */ - my_strdup2(_ALLOC_ID_, &xctx->sch[xctx->currsch], fname); + my_strdup2(_ALLOC_ID_, &xctx->sch[xctx->currsch], ffname); /* local relative reference */ - my_strncpy(xctx->current_name, rel_sym_path(fname), S(xctx->current_name)); + my_strncpy(xctx->current_name, rel_sym_path(ffname), S(xctx->current_name)); } else { /* local file specified and not coming from web url */ /* build current_dirname by stripping off last filename from url */ - my_snprintf(msg, S(msg), "get_directory {%s}", fname); + my_snprintf(msg, S(msg), "get_directory {%s}", ffname); my_strncpy(xctx->current_dirname, tcleval(msg), S(xctx->current_dirname)); /* local file name */ - my_strdup2(_ALLOC_ID_, &xctx->sch[xctx->currsch], fname); + my_strdup2(_ALLOC_ID_, &xctx->sch[xctx->currsch], ffname); /* local relative reference */ - my_strncpy(xctx->current_name, rel_sym_path(fname), S(xctx->current_name)); + my_strncpy(xctx->current_name, rel_sym_path(ffname), S(xctx->current_name)); } - dbg(1, "load_schematic(): opening file for loading:%s, fname=%s\n", name, fname); + dbg(1, "load_schematic(): opening file for loading:%s, ffname=%s\n", name, ffname); dbg(1, "load_schematic(): sch[currsch]=%s\n", xctx->sch[xctx->currsch]); - if(!name[0]) return 0; /* empty filename */ + if(!name[0]) { + my_free(_ALLOC_ID_, &ffname); + return 0; /* empty filename */ + } if(reset_undo) { if(!stat(name, &buf)) { /* file exists */ xctx->time_last_modify = buf.st_mtime; @@ -3515,7 +3526,7 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler } else {xctx->time_last_modify = 0;} /* undefined */ if(generator) { char *cmd; - cmd = get_generator_command(fname); + cmd = get_generator_command(ffname); if(cmd) { fd = popen(cmd, "r"); my_free(_ALLOC_ID_, &cmd); @@ -3526,9 +3537,9 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler size_t len; ret = 0; if(alert) { - fprintf(errfp, "load_schematic(): unable to open file: %s, fname=%s\n", name, fname ); + fprintf(errfp, "load_schematic(): unable to open file: %s, ffname=%s\n", name, ffname ); if(has_x) { - my_snprintf(msg, S(msg), "update; alert_ {Unable to open file: %s}", fname); + my_snprintf(msg, S(msg), "update; alert_ {Unable to open file: %s}", ffname); tcleval(msg); } } @@ -3567,7 +3578,7 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler } } dbg(1, "load_schematic(): %s, returning\n", xctx->sch[xctx->currsch]); - } else { /* fname == NULL or empty */ + } else { /* ffname == NULL or empty */ /* if(reset_undo) xctx->time_last_modify = time(NULL); */ /* no file given, set mtime to current time */ if(reset_undo) xctx->time_last_modify = 0; /* no file given, set mtime to 0 (undefined) */ clear_drawing(); @@ -3602,6 +3613,7 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler set_netlist_dir(2, NULL); drc_check(-1); } + my_free(_ALLOC_ID_, &ffname); return ret; } @@ -5140,7 +5152,7 @@ int descend_symbol(void) my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch].prop_ptr, xctx->inst[n].prop_ptr); my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch].templ, - get_tok_value(xctx->sym[xctx->inst[n].ptr].prop_ptr, "template", 0)); + xctx->sym[xctx->inst[n].ptr].templ); if(!xctx->inst[n].embed) /* use -1 to keep track we are descending into symbol from instance with no embed attr diff --git a/src/scheduler.c b/src/scheduler.c index 22322d33..b5611a46 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -431,7 +431,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg else { cmd_found = 0;} break; case 'c': /*----------------------------------------------*/ - /* callback winpath event mx my key button aux state + /* callback win_path event mx my key button aux state * Invoke the callback event dispatcher with a software event */ if(!strcmp(argv[1], "callback") ) { @@ -1008,6 +1008,16 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg } } + + /* eval_expr str + * debug function: evaluate arithmetic expression in str */ + else if(!strcmp(argv[1], "eval_expr")) + { + if(argc > 2) { + Tcl_SetResult(interp, eval_expr(argv[2]), TCL_VOLATILE); + } + } + /* exit [exit_code] [closewindow] [force] * Exit the program, ask for confirm if current file modified. * if exit_code is given exit with its value, otherwise use 0 exit code @@ -2732,7 +2742,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg my_free(_ALLOC_ID_, &pins); } - /* is_symgen symbol + /* is_generator symbol * tell if 'symbol' is a generator (symbol(param1,param2,...) */ else if(!strcmp(argv[1], "is_generator")) { @@ -3367,6 +3377,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg } } tclsetvar("show_infowindow_after_netlist", saveshow); + tcleval("eval_netlist_postprocess"); set_netlist_dir(1, savedir); if(done_netlist) { if(messages) { @@ -3394,22 +3405,22 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg Tcl_ResetResult(interp); } - /* new_schematic create|destroy|destroy_all|switch winpath file [draw] + /* new_schematic create|destroy|destroy_all|switch win_path file [draw] * Open/destroy a new tab or window * create: create new empty window or with 'file' loaded if 'file' given. - * The winpath must be given (even {} is ok). - * non empty winpath ({1}) will avoid warnings if opening the + * The win_path must be given (even {} is ok). + * non empty win_path ({1}) will avoid warnings if opening the * same file multiple times. - * destroy: destroy tab/window identified by winpath. Example: + * destroy: destroy tab/window identified by win_path. Example: * xschem new_schematic destroy .x1.drw * destroy_all: close all tabs/additional windows * if the 'force'argument is given do not issue a warning if modified * tabs are about to be closed. - * switch: switch context to specified 'winpath' window or specified schematic name + * switch: switch context to specified 'win_path' window or specified schematic name * If 'draw' is given and set to 0 do not redraw after switching tab * (only tab i/f) - * Main window/tab has winpath set to .drw, - * Additional windows/tabs have winpath set to .x1.drw, .x2.drw and so on... + * Main window/tab has win_path set to .drw, + * Additional windows/tabs have win_path set to .x1.drw, .x2.drw and so on... */ else if(!strcmp(argv[1], "new_schematic")) { @@ -3613,7 +3624,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg xctx->ui_state2 = MENUSTARTPOLYGON; } - /* preview_window create|draw|destroy|close [winpath] [file] + /* preview_window create|draw|destroy|close [win_path] [file] * destroy: will delete preview schematic data and destroy container window * close: same as destroy but leave the container window. * Used in fileselector to show a schematic preview. @@ -5749,7 +5760,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg /* switch [window_path |schematic_name] * Switch context to indicated window path or schematic name * returns 0 if switch was successfull or 1 in case of errors - * (no tabs/windows present or no matching winpath / schematic name + * (no tabs/windows present or no matching win_path / schematic name * found). */ else if(!strcmp(argv[1], "switch")) @@ -5773,7 +5784,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg char n[100]; if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;} if(argc > 2 && !strcmp(argv[2], "derived_symbols")) derived_symbols = 1; - else if(argc > 2 && argv[2][0]) { + else if(argc > 2 && argv[2][0] && isonlydigit(argv[2])) { one_symbol = 1; i = get_symbol(argv[2]); if(i >=0) Tcl_AppendResult(interp, my_itoa(i), " {", xctx->sym[i].name, "}", NULL); @@ -6057,9 +6068,9 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg int eat_escapes = 0; if(!xctx) {Tcl_SetResult(interp, not_avail, TCL_STATIC); return TCL_ERROR;} if(argc > 3) eat_escapes = atoi(argv[3]); - if(argc > 6) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], eat_escapes, argv[4], argv[5], argv[6])); - else if(argc > 5) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], eat_escapes, argv[4], argv[5], NULL)); - else if(argc > 4) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], eat_escapes, argv[4], NULL, NULL)); + if(argc > 6) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], eat_escapes, argv[4], argv[5], argv[6], NULL)); + else if(argc > 5) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], eat_escapes, argv[4], argv[5], NULL, NULL)); + else if(argc > 4) my_strdup2(_ALLOC_ID_, &s, translate3(argv[2], eat_escapes, argv[4], NULL, NULL, NULL)); else { Tcl_SetResult(interp, "xschem translate3: missing arguments", TCL_STATIC); return TCL_ERROR; diff --git a/src/spice_netlist.c b/src/spice_netlist.c index 911289d1..c341895a 100644 --- a/src/spice_netlist.c +++ b/src/spice_netlist.c @@ -133,9 +133,9 @@ void hier_psprint(char **res, int what) /* netlister driver */ xctx->prev_set_modify = save_prev_mod; my_strncpy(xctx->current_name, rel_sym_path(xctx->sch[xctx->currsch]), S(xctx->current_name)); xctx->do_copy_area = save; - if(what & 1) ps_draw(4, 1, 0); /* trailer */ zoom_full(0, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); draw(); + if(what & 1) ps_draw(4, 1, 0); /* trailer */ } static char *model_name_result = NULL; /* safe even with multiple schematics */ @@ -455,11 +455,13 @@ int global_spice_netlist(int global, int alert) /* netlister driver */ if(lvs_ignore && (xctx->sym[i].flags & LVS_IGNORE)) continue; if(!xctx->sym[i].type) continue; /* store parent symbol template attr (before descending into it) and parent instance prop_ptr + * into xctx->hier_attr[0].templ and xctx->hier_attr[0.prop_ptr, * to resolve subschematic instances with model=@modp in format string, * modp will be first looked up in instance prop_ptr string, and if not found * in parent symbol template string */ my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].templ, tcl_hook2(xctx->sym[i].templ)); + /* only additional symbols (created with instance schematic=... attr) will have this attribute */ my_strdup(_ALLOC_ID_, &xctx->hier_attr[xctx->currsch - 1].prop_ptr, tcl_hook2(xctx->sym[i].parent_prop_ptr)); my_strdup(_ALLOC_ID_, &abs_path, abs_sym_path(xctx->sym[i].name, "")); @@ -641,14 +643,9 @@ int spice_block_netlist(FILE *fd, int i, int alert) my_strdup(_ALLOC_ID_, &sym_def, get_tok_value(xctx->sym[i].prop_ptr,"spice_sym_def",0)); if(sym_def) { char *symname_attr = NULL; - char *templ = NULL; const char *translated_sym_def; - my_strdup2(_ALLOC_ID_, &templ, get_tok_value(xctx->sym[i].prop_ptr, "template", 0)); my_mstrcat(_ALLOC_ID_, &symname_attr, "symname=", get_cell(name, 0), NULL); - translated_sym_def = translate3(sym_def, 1, "", - templ, - symname_attr); - my_free(_ALLOC_ID_, &templ); + translated_sym_def = translate3(sym_def, 1, xctx->sym[i].templ, symname_attr, NULL, NULL); my_free(_ALLOC_ID_, &symname_attr); fprintf(fd, "%s\n", translated_sym_def); my_free(_ALLOC_ID_, &sym_def); diff --git a/src/token.c b/src/token.c index e8e3d855..4a067718 100644 --- a/src/token.c +++ b/src/token.c @@ -1174,9 +1174,18 @@ static void print_vhdl_primitive(FILE *fd, int inst) /* netlist primitives, 200 if(c=='\0') { - if(result && strstr(result, "tcleval(")== result) { + /* 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); - my_strdup(_ALLOC_ID_, &result, translate(inst, 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); @@ -1207,7 +1216,7 @@ const char *subst_token(const char *s, const char *tok, const char *new_val) size_t token_pos=0, result_pos=0, result_save_pos = 0, tmp; int quote=0; int done_subst=0; - int escape=0, matched_tok=0; + int escape=0, matched_tok=0, removed_tok = 0; char *new_val_copy = NULL; size_t new_val_len; @@ -1290,6 +1299,7 @@ const char *subst_token(const char *s, const char *tok, const char *new_val) } else { /* remove token (and value if any) */ result_pos = result_save_pos; done_subst = 1; + removed_tok = 1; } } result_save_pos = result_pos; @@ -1326,11 +1336,13 @@ const char *subst_token(const char *s, const char *tok, const char *new_val) } else { /* remove token (and value if any) */ result_pos = result_save_pos; done_subst = 1; + removed_tok = 1; } } state=TOK_VALUE; } else if( state == TOK_VALUE && space && !quote && !escape) { state=TOK_BEGIN; + if(matched_tok && removed_tok && (c == '\n' || c == ' ') ) continue; } /* state actions */ if(state == TOK_BEGIN) { @@ -1856,7 +1868,6 @@ static int has_included_subcircuit(int inst, int symbol, char **result) if(xctx->tok_size) { char *symname = NULL; - char *templ = NULL; char *symname_attr = NULL; int no_of_pins = (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; int i; @@ -1865,7 +1876,6 @@ static int has_included_subcircuit(int inst, int symbol, char **result) Str_hashentry *entry; Str_hashtable table = {NULL, 0}; - my_strdup2(_ALLOC_ID_, &templ, get_tok_value(xctx->sym[symbol].prop_ptr, "template", 0)); my_strdup2(_ALLOC_ID_, &symname, get_tok_value(xctx->inst[inst].prop_ptr, "schematic", 0)); if(!symname[0]) { my_strdup2(_ALLOC_ID_, &symname, get_tok_value(xctx->sym[symbol].prop_ptr, "schematic", 0)); @@ -1876,8 +1886,8 @@ static int has_included_subcircuit(int inst, int symbol, char **result) my_mstrcat(_ALLOC_ID_, &symname_attr, "symname=", get_cell(symname, 0), NULL); my_mstrcat(_ALLOC_ID_, &symname_attr, " symref=", get_sym_name(inst, 9999, 1, 1), NULL); translated_sym_def = translate3(spice_sym_def, 1, xctx->inst[inst].prop_ptr, - templ, - symname_attr); + xctx->sym[symbol].templ, + symname_attr, NULL); dbg(1, "has_included_subcircuit(): translated_sym_def=%s\n", translated_sym_def); dbg(1, "has_included_subcircuit(): symname=%s\n", symname); @@ -1915,7 +1925,6 @@ static int has_included_subcircuit(int inst, int symbol, char **result) tclvareval("has_included_subcircuit {", get_cell(symname, 0), "} {", translated_sym_def, "} ", my_itoa(exp_no_of_pins), NULL); - my_free(_ALLOC_ID_, &templ); my_free(_ALLOC_ID_, &symname_attr); if(tclresult()[0]) { /* a valid spice_sym_def netlist was found */ char *subckt_pin, *pin_save; @@ -2203,103 +2212,30 @@ int print_spice_element(FILE *fd, int inst) token[token_pos]='\0'; token_pos=0; - /* if spiceprefix==0 and token == @spiceprefix then set empty value */ - if (!tclgetboolvar("spiceprefix") && !strcmp(token, "@spiceprefix")) { - value=NULL; - } else { - size_t tok_val_len; - size_t tok_size; - dbg(1, "print_spice_element(): token: |%s|\n", token); - my_strdup2(_ALLOC_ID_, &val, get_tok_value(xctx->inst[inst].prop_ptr, token+1, 0)); - tok_size = xctx->tok_size; - value = val; - if(strchr(value, '@')) { - /* Symbol format string contains model=@modp, - * resolve @modp looking in instance attributes ... */ - char *parent_prop_ptr = NULL; - char *parent_templ = NULL; - - if(xctx->currsch > 0) { - /* ... also look up modp also in **parent** instance prop_ptr and symbol template attribute */ - parent_prop_ptr = xctx->hier_attr[xctx->currsch - 1].prop_ptr; - parent_templ = xctx->hier_attr[xctx->currsch - 1].templ; - } - dbg(1, "print_spice_element(): before translate3(): value=%s\n", value); - value = translate3(val, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, parent_templ); - dbg(1, "print_spice_element(): after translate3(): value=%s\n", value); - } - tok_val_len = strlen(value); - 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; - } - xctx->tok_size = tok_size; - /* xctx->tok_size==0 indicates that token(+1) does not exist in instance attributes */ - - if (!xctx->tok_size) value=get_tok_value(template, token+1, 0); - token_exists = xctx->tok_size; - - if(!strcmp("@savecurrent", token)) { - token_exists = 0; /* processed later */ - value = NULL; - } - } - 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); */ - } else if (value && value[0]!='\0') { - /* instance names (name) and node labels (lab) go thru the expandlabel function. */ - /*if something else must be parsed, put an if here! */ - - if (!(strcmp(token+1,"name") && strcmp(token+1,"lab")) /* expand name/labels */ - && ((lab = expandlabel(value, &itmp)) != NULL)) { - /* result_pos += my_snprintf(result + result_pos, tmp, "%s", lab); */ - my_mstrcat(_ALLOC_ID_, &result, lab, NULL); - /* fputs(lab,fd); */ - - - - } else { - - /* result_pos += my_snprintf(result + result_pos, tmp, "%s", value); */ - my_mstrcat(_ALLOC_ID_, &result, value, NULL); - /* fputs(value,fd); */ - } - } - else if(strcmp(token,"@symref")==0) + if(strcmp(token,"@symref")==0) { const char *s = get_sym_name(inst, 9999, 1, 0); - /* 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, 0))); - /* 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_ext must not be present in attributes */ { const char *s = sanitize(translate(inst, get_sym_name(inst, 0, 1, 0))); - /* 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); - /* 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 */ { - /* 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) { @@ -2308,14 +2244,12 @@ 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")) { - /* 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); - /* 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 */ @@ -2333,7 +2267,6 @@ 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); - /* result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr); */ my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL); } } @@ -2348,7 +2281,6 @@ 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); - /* 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; @@ -2400,7 +2332,6 @@ int print_spice_element(FILE *fd, int inst) } my_free(_ALLOC_ID_, &tmpstr); } - /* result_pos += my_snprintf(result + result_pos, tmp, "%s", value); */ my_mstrcat(_ALLOC_ID_, &result, value, NULL); my_free(_ALLOC_ID_, &pin_attr_value); } @@ -2411,7 +2342,6 @@ int print_spice_element(FILE *fd, int inst) if(strboolcmp(si, "true")) { str_ptr = net_name(inst,n, &multip, 0, 1); - /* result_pos += my_snprintf(result + result_pos, tmp, "?%d %s ", multip, str_ptr); */ my_mstrcat(_ALLOC_ID_, &result, "?", my_itoa(multip), " ", str_ptr, " ", NULL); } } @@ -2429,42 +2359,134 @@ 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); - /* 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 spiceprefix==0 and token == @spiceprefix then set empty value */ + else if (!tclgetboolvar("spiceprefix") && !strcmp(token, "@spiceprefix")) { + value=NULL; + /* else tcl var spiceprefix is enabled */ + } + else { + /* here a @token in format string will be replaced by value in instance prop_ptr + * or symbol template */ + size_t tok_val_len; + char *parent_prop_ptr = NULL; + char *parent_templ = NULL; + if(xctx->currsch > 0) { + parent_prop_ptr = xctx->hier_attr[xctx->currsch - 1].prop_ptr; + parent_templ = xctx->hier_attr[xctx->currsch - 1].templ; + } + dbg(1, "print_spice_element(): token: |%s|\n", token); + + /* consider this scenario: + * instance of passgate.sym: W_N=5 L_N=0.2 W_P=10 L_P=0.3 m=1 + * instance based schematic (schematic=mypippo attr) will have also modeln=pippon + * passgate.sym: + * format="@name @pinlist @symname W_N=@W_N L_N=@L_N W_P=@W_P L_P=@L_P m=@m" + * template=" ... modeln=nfet_01v8 modelp=pfet_01v8 m=1" + * passgate.sch: + * instance of nmos.sym: L=L_N W=W_N nf=1 m=1 model=@modeln + * nmos.sym: + * format="@name @pinlist @model L=@L W=@W nf=@nf + * + ad=@ad as=@as pd=@pd .... m=@m + * template="name=M1 W=1 L=0.15 m=1 + * ad=\"expr('int((@nf + 1)/2) * @W / @nf * 0.29')\" + * ..." + * model=nfet_01v8 + */ + my_strdup2(_ALLOC_ID_, &val, + translate3(token, 2, xctx->inst[inst].prop_ptr, parent_prop_ptr, template, NULL)); + /* nmos instance format string: @model --> @modeln */ + dbg(1, "print_spice_element(): 1st round: val: |%s|\n", val); + if(strchr(val, '@')) { + if(parent_prop_ptr) { + my_strdup2(_ALLOC_ID_, &val, + translate3(val, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, parent_templ, NULL)); + /* instance based passgate.sym placement, nmos instance format string: @modeln --> pippon */ + /* ad="expr('int((@nf + 1)/2) * @W / @nf * 0.29')" --> ad="expr('int((1 + 1)/2) * W_N / 1 * 0.29')" */ + if(strchr(val, '@')) { + my_strdup2(_ALLOC_ID_, &val, + translate3(val, 0, xctx->inst[inst].prop_ptr, parent_prop_ptr, parent_templ, NULL)); + /* ad="expr('int((1 + 1)/2) * W_N / 1 * 0.29')" --> ad="expr('int((1 + 1)/2) * 5 / 1 * 0.29')" */ + } + } else { + my_strdup2(_ALLOC_ID_, &val, + translate3(val, 0, xctx->inst[inst].prop_ptr, NULL, NULL, NULL)); + dbg(1, "print_spice_element(): 2nd round: val: |%s|\n", val); + /* normal passgate.sym placement, nmos instance format string: + ad="expr('int((@nf + 1)/2) * @W / @nf * 0.29')" --> ad="expr('int((1 + 1)/2) * W_N/ 1 * 0.29')" */ + if(strchr(val, '@')) { + my_strdup2(_ALLOC_ID_, &val, + translate3(val, 0, xctx->inst[inst].prop_ptr, parent_templ, NULL, NULL)); + dbg(1, "print_spice_element(): 3nd round: val: |%s|\n", val); + /* normal passgate.sym placement, nmos instance format string: + * @modeln --> nfet_01v8 */ + } + } + 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); + 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]) { + my_realloc(_ALLOC_ID_, &spiceprefixtag, tok_val_len+22); + my_snprintf(spiceprefixtag, tok_val_len+22, "**** spice_prefix %s\n", value); + value = spiceprefixtag; + } + + if(strstr(value, "expr(") ) { + value = eval_expr(value); + } + /* token=%xxxx and xxxx is not defined in prop_ptr or template: return xxxx */ + if(!token_exists && token[0] =='%') { + my_mstrcat(_ALLOC_ID_, &result, token + 1, NULL); + } + /* And finally set the value of token into result string */ + else if (value && value[0]!='\0') { + /* instance names (name) and node labels (lab) go thru the expandlabel function. */ + /*if something else must be parsed, put an if here! */ + if (!(strcmp(token+1,"name") && strcmp(token+1,"lab")) /* expand name/labels */ + && ((lab = expandlabel(value, &itmp)) != NULL)) { + my_mstrcat(_ALLOC_ID_, &result, lab, NULL); + } else { + my_mstrcat(_ALLOC_ID_, &result, value, NULL); + } + } + } /* else */ + + /* append token separator to output result ... */ if(c != '%' && c != '@' && c!='\0' ) { 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); */ } + /* ... unless it is the start of another token, so push back to input string */ if(c == '@' || c == '%' ) s--; state=TOK_BEGIN; my_free(_ALLOC_ID_, &val); - } + } /* else if (state==TOK_SEP) */ + else if(state==TOK_BEGIN && c!='\0') { 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') { 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; } } /* while(1) */ @@ -2472,40 +2494,20 @@ int print_spice_element(FILE *fd, int inst) /* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions * can be calculated */ - - /* do one level of substitutions to resolve @params and equations*/ - if(result && strstr(result, "tcleval(")== result) { - dbg(1, "print_spice_element(): before translate() result=%s\n", result); - my_strdup(_ALLOC_ID_, &result, translate(inst, result)); - dbg(1, "print_spice_element(): after translate() result=%s\n", result); + if(result) { + my_strdup(_ALLOC_ID_, &result, tcl_hook2(result)); + } + if(strstr(result, "expr(") ) { + result = eval_expr(result); } - - - /* can't remember what the f**k this is supposed to do. - why eval( and not tcleval( ? - disable until some regression pops out - */ - #if 0 - * /* do a second round of substitutions, but without calling tcl */ - * if(result && strstr(result, "eval(") == result) { - * char *c = strrchr(result, ')'); - * if(c) while(1) { /* shift following characters back 1 char */ - * *c = (char)c[1]; - * c++; - * if(!*c) break; - * } - * my_strdup2(_ALLOC_ID_, &result, translate(inst, result+5)); - * } - #endif - - if(result) fprintf(fd, "%s", result); + dbg(1, "print_spice_element(): returning |%s|\n", result); my_free(_ALLOC_ID_, &template); my_free(_ALLOC_ID_, &format); my_free(_ALLOC_ID_, &name); my_free(_ALLOC_ID_, &token); my_free(_ALLOC_ID_, &result); - my_free(_ALLOC_ID_, &spiceprefixtag); + if(spiceprefixtag) my_free(_ALLOC_ID_, &spiceprefixtag); /* my_free(_ALLOC_ID_, &translatedvalue); */ return 1; } @@ -3107,10 +3109,18 @@ static void print_verilog_primitive(FILE *fd, int inst) /* netlist switch level } if(c=='\0') { - /* do one level of substitutions to resolve @params and equations*/ - if(result && strstr(result, "tcleval(")== result) { + /* do one level of substitutions to resolve remaining @params and/or tcl expr/code */ + if(result) { dbg(1, "print_verilog_primitive(): before translate() result=%s\n", result); - my_strdup(_ALLOC_ID_, &result, translate(inst, 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_verilog_primitive(): after translate() result=%s\n", result); } if(result) fprintf(fd, "%s", result); @@ -3738,772 +3748,775 @@ const char *spice_get_node(const char *token) /* if s==NULL return emty string */ const char *translate(int inst, const char* s) { - static regex_t *get_sp_cur = NULL; - static const char *empty=""; - static char *translated_tok = NULL; - static char *result=NULL; /* safe to keep even with multiple schematics */ - size_t size=0; - size_t tmp; - register int c, state=TOK_BEGIN, space; - char *token=NULL; - const char *tmp_sym_name; - size_t sizetok=0; - size_t result_pos=0, token_pos=0; - struct stat time_buf; - struct tm *tm; - char file_name[PATH_MAX]; - const char *value; - int escape=0, engineering = 0; - char date[200]; - int sp_prefix; - int level; - Lcc *lcc; - char *value1 = NULL; - int sim_is_xyce; - char *instname = NULL; - - if(!s && inst == -1) { - if(result) my_free(_ALLOC_ID_, &result); - if(translated_tok) my_free(_ALLOC_ID_, &translated_tok); - if(get_sp_cur) { - regfree(get_sp_cur); - get_sp_cur = NULL; - } - } - - if(!s || !xctx || !xctx->inst) { - return empty; - } - - if(!get_sp_cur) { - get_sp_cur = my_malloc(_ALLOC_ID_, sizeof(regex_t)); - /* @spice_get_current_param(...) or @spice_get_modelparam_param(...) */ - /* @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); - } - - sp_prefix = tclgetboolvar("spiceprefix"); - - if(inst >= xctx->instances) { - dbg(0, "translate(): instance number out of bounds: %d\n", inst); - return empty; - } - /* if spice_get_* token not processed by tcl use enginering notation (2m, 3u, ...) */ - if(!(strstr(s, "tcleval(") == s)) engineering = 1; - instname = (inst >=0 && xctx->inst[inst].instname) ? xctx->inst[inst].instname : ""; - sim_is_xyce = tcleval("sim_is_xyce")[0] == '1' ? 1 : 0; - level = xctx->currsch; - lcc = xctx->hier_attr; - size=CADCHUNKALLOC; - my_realloc(_ALLOC_ID_, &result,size); - result[0]='\0'; - - dbg(1, "translate(): substituting props in <%s>, instance <%s>\n", s ? s : "" , instname); - - while(1) - { - - c=*s++; - if(c=='\\') { - escape=1; - c=*s++; /* do not remove: breaks translation of format strings in netlists (escaping %) */ + static regex_t *get_sp_cur = NULL; + static const char *empty=""; + static char *result=NULL; /* safe to keep even with multiple schematics */ + size_t size=0; + size_t tmp; + register int c, state=TOK_BEGIN, space; + char *token=NULL; + const char *tmp_sym_name; + size_t sizetok=0; + size_t result_pos=0, token_pos=0; + struct stat time_buf; + struct tm *tm; + char file_name[PATH_MAX]; + const char *value; + int escape=0, engineering = 0; + char date[200]; + int sp_prefix; + int level; + Lcc *lcc; + char *value1 = NULL; + int sim_is_xyce; + char *instname = NULL; + + if(!s && inst == -1) { + if(result) my_free(_ALLOC_ID_, &result); + if(get_sp_cur) { + regfree(get_sp_cur); + get_sp_cur = NULL; + } } - 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(&result, result_pos, &size); - STR_ALLOC(&token, token_pos, &sizetok); - if(state==TOK_TOKEN) token[token_pos++]=(char)c; - else if(state==TOK_SEP) + + if(!s || !xctx || !xctx->inst) { + return empty; + } + + if(!get_sp_cur) { + get_sp_cur = my_malloc(_ALLOC_ID_, sizeof(regex_t)); + /* @spice_get_current_param(...) or @spice_get_modelparam_param(...) */ + /* @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); + } + + sp_prefix = tclgetboolvar("spiceprefix"); + + if(inst >= xctx->instances) { + dbg(0, "translate(): instance number out of bounds: %d\n", inst); + return empty; + } + /* if spice_get_* token not processed by tcl use enginering notation (2m, 3u, ...) */ + if(!(strstr(s, "tcleval(") == s)) engineering = 1; + instname = (inst >=0 && xctx->inst[inst].instname) ? xctx->inst[inst].instname : ""; + sim_is_xyce = tcleval("sim_is_xyce")[0] == '1' ? 1 : 0; + level = xctx->currsch; + lcc = xctx->hier_attr; + size=CADCHUNKALLOC; + my_realloc(_ALLOC_ID_, &result,size); + result[0]='\0'; + + dbg(1, "translate(): substituting props in <%s>, instance <%s>\n", s ? s : "" , instname); + + while(1) { - token[token_pos]='\0'; - if(!strcmp(token, "@name")) { - tmp = strlen(instname); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, instname, tmp+1); - result_pos+=tmp; - } else if(inst >= 0 && strcmp(token,"@symref")==0) { - tmp_sym_name = get_sym_name(inst, 9999, 1, 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); - result_pos+=tmp; - } else if(inst >= 0 && strcmp(token,"@symname")==0) { - tmp_sym_name = get_sym_name(inst, 0, 0, 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); - result_pos+=tmp; - } else if(strcmp(token,"@path")==0) { - const char *path = xctx->sch_path[xctx->currsch] + 1; - int start_level = sch_waves_loaded(), skip = 0; - if(start_level == -1) start_level = 0; - - /* skip path components that are above the level where raw file was loaded */ - while(*path && skip < start_level) { - if(*path == '.') skip++; - ++path; + c=*s++; + if(c=='\\') { + escape=1; + c=*s++; /* do not remove: breaks translation of format strings in netlists (escaping %) */ } - - tmp=strlen(path); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, path, tmp+1); - result_pos+=tmp; - } else if(inst >= 0 && strcmp(token,"@symname_ext")==0) { - tmp_sym_name = get_sym_name(inst, 0, 1, 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); - result_pos+=tmp; - /* recognize single pins 15112003 */ - } else if(inst >= 0 && token[0]=='@' && token[1]=='@' && xctx->inst[inst].ptr >= 0) { - int i, multip; - int no_of_pins= (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; - prepare_netlist_structs(0); - for(i=0;iinst[inst].ptr + xctx->sym)->rect[PINLAYER][i].prop_ptr; - if (!strcmp( get_tok_value(prop,"name",0), token+2)) { - if(strboolcmp(get_tok_value(prop,"spice_ignore",0), "true")) { - const char *str_ptr = net_name(inst,i, &multip, 0, 0); - tmp = strlen(str_ptr) +100 ; - STR_ALLOC(&result, tmp + result_pos, &size); - result_pos += my_snprintf(result + result_pos, tmp, "%s", str_ptr); - } - break; - } - } - } else if(inst >= 0 && token[0]=='@' && token[1]=='#') { - value = get_pin_attr(token, inst, engineering); - if(value) { - tmp=strlen(value); + 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(&result, result_pos, &size); + STR_ALLOC(&token, token_pos, &sizetok); + if(state==TOK_TOKEN) token[token_pos++]=(char)c; + else if(state==TOK_SEP) + { + token[token_pos]='\0'; + if(!strcmp(token, "@name")) { + tmp = strlen(instname); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, instname, tmp+1); + result_pos+=tmp; + } else if(inst >= 0 && strcmp(token,"@symref")==0) { + tmp_sym_name = get_sym_name(inst, 9999, 1, 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, value, tmp+1); + memcpy(result+result_pos,tmp_sym_name, tmp+1); result_pos+=tmp; - my_free(_ALLOC_ID_, &value); - } - } else if(inst >= 0 && strcmp(token,"@sch_last_modified")==0 && xctx->inst[inst].ptr >= 0) { - - get_sch_from_sym(file_name, xctx->inst[inst].ptr + xctx->sym, inst, 0); - if(!stat(file_name , &time_buf)) { - tm=localtime(&(time_buf.st_mtime) ); - tmp=strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", tm); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, date, tmp+1); - result_pos+=tmp; - } - } else if(inst >= 0 && strcmp(token,"@sym_last_modified")==0) { - my_strncpy(file_name, abs_sym_path(tcl_hook2(xctx->inst[inst].name), ""), S(file_name)); - if(!stat(file_name , &time_buf)) { - tm=localtime(&(time_buf.st_mtime) ); - tmp=strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", tm); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, date, tmp+1); - result_pos+=tmp; - } - } else if(strcmp(token,"@time_last_modified")==0) { - my_strncpy(file_name, abs_sym_path(xctx->sch[xctx->currsch], ""), S(file_name)); - if(!stat(file_name , &time_buf)) { - tm=localtime(&(time_buf.st_mtime) ); - tmp=strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", tm); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, date, tmp+1); - result_pos+=tmp; - } - } else if(strcmp(token,"@schname_ext")==0) { - /* tmp=strlen(xctx->sch[xctx->currsch]);*/ - tmp = strlen(xctx->current_name); - STR_ALLOC(&result, tmp + result_pos, &size); - /* memcpy(result+result_pos,xctx->sch[xctx->currsch], tmp+1); */ - memcpy(result+result_pos, xctx->current_name, tmp+1); - result_pos+=tmp; - } else if(strcmp(token,"@schname")==0) { - const char *schname = get_cell(xctx->current_name, 0); - tmp = strlen(schname); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, schname, tmp+1); - result_pos+=tmp; - } else if(strcmp(token,"@topschname")==0) { - const char *topsch; - topsch = get_trailing_path(xctx->sch[0], 0, 1); - tmp = strlen(topsch); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, topsch, tmp+1); - result_pos+=tmp; - } else if(inst >= 0 && strcmp(token,"@prop_ptr")==0 && xctx->inst[inst].prop_ptr) { - tmp=strlen(xctx->inst[inst].prop_ptr); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos,xctx->inst[inst].prop_ptr, tmp+1); - result_pos+=tmp; - } - else if(inst >= 0 && strcmp(token,"@spice_get_voltage")==0 && xctx->inst[inst].ptr >= 0) - { - int start_level; /* hierarchy level where waves were loaded */ - int live = tclgetboolvar("live_cursor2_backannotate"); - if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { - int multip; - int no_of_pins= (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; - if(no_of_pins == 1) { - char *fqnet = NULL; - const char *path = xctx->sch_path[xctx->currsch] + 1; - char *net = NULL; - size_t len; - int idx; - double val = 0.0; - const char *valstr; - if(path) { - prepare_netlist_structs(0); - if(xctx->inst[inst].lab) { - my_strdup2(_ALLOC_ID_, &net, expandlabel(xctx->inst[inst].lab, &multip)); - } - if(net == NULL || net[0] == '\0') { - my_strdup2(_ALLOC_ID_, &net, net_name(inst, 0, &multip, 0, 0)); - } - if(multip == 1 && net && net[0]) { - char *rn; - dbg(1, "translate() @spice_get_voltage: inst=%s\n", instname); - dbg(1, " net=%s\n", net); - rn = resolved_net(net); - if(rn) { - my_strdup2(_ALLOC_ID_, &fqnet, rn); - if(rn) my_free(_ALLOC_ID_, &rn); - strtolower(fqnet); - dbg(1, "translate() @spice_get_voltage: fqnet=%s start_level=%d\n", fqnet, start_level); - idx = get_raw_index(fqnet, NULL); - if(idx >= 0) { - val = xctx->raw->cursor_b_val[idx]; - } - if(!strcmp(fqnet, "0") || !my_strcasecmp(fqnet, "GND")) { - valstr = "0.0"; - xctx->tok_size = 3; - len = 3; - } else if(idx < 0) { - valstr = "-"; - xctx->tok_size = 5; - len = 5; - } else { - valstr = engineering ? dtoa_eng(val) : dtoa(val); - len = xctx->tok_size; - } - if(len) { - STR_ALLOC(&result, len + result_pos, &size); - memcpy(result+result_pos, valstr, len+1); - result_pos += len; - } - dbg(1, "inst %d, net=%s, fqnet=%s idx=%d valstr=%s\n", inst, net, fqnet, idx, valstr); - if(fqnet) my_free(_ALLOC_ID_, &fqnet); - } - } - if(net) my_free(_ALLOC_ID_, &net); - } + } else if(inst >= 0 && strcmp(token,"@symname")==0) { + tmp_sym_name = get_sym_name(inst, 0, 0, 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); + result_pos+=tmp; + } else if(strcmp(token,"@path")==0) { + const char *path = xctx->sch_path[xctx->currsch] + 1; + int start_level = sch_waves_loaded(), skip = 0; + if(start_level == -1) start_level = 0; + + /* skip path components that are above the level where raw file was loaded */ + while(*path && skip < start_level) { + if(*path == '.') skip++; + ++path; } - } - } - - /* copy as is: processed by spice_get_node() later - * the format is "some_text@spice_get_node some_additional_text" - * Examples: - * Id=@spice_get_node i(\@m.@path@spiceprefix@name\.msky130_fd_pr__@model\[id]) - * will translate to: - * Id=6.6177u - * Id=@spice_get_node i(\@m.@path@spiceprefix@name\.msky130_fd_pr__@model\[id]) A - * will translate to: - * Id=6.6177uA - * note the required separator spaces around the spice node. Spaces are used here as - * separators since spice nodes don't allow spaces. - * escapes are used for 2 reasons: - * mark a @ as a literal character instead of a the start of a @var token to be substituted - * mark the end of a @var, like for example @var\iable. In this case @var will - * be substituted by xschem instead of @variable - * - * caveats: only one @spice_get_node is allowed in a string - */ - else if(strcmp(token,"@spice_get_node")==0 ) - { - STR_ALLOC(&result, 15 + result_pos, &size); - memcpy(result+result_pos, token, 16); - result_pos += 15; - } - else if(strncmp(token,"@spice_get_voltage(", 19)==0 ) - { - int start_level; /* hierarchy level where waves were loaded */ - int live = tclgetboolvar("live_cursor2_backannotate"); - dbg(1, "--> %s\n", token); - if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { - char *fqnet = NULL; - const char *path = xctx->sch_path[xctx->currsch] + 1; - char *net = NULL; - char *global_net; - size_t len; - int idx, n, multip; - double val = 0.0; - const char *valstr; - tmp = strlen(token) + 1; - if(path) { - int skip = 0; - /* skip path components that are above the level where raw file was loaded */ - while(*path && skip < start_level) { - if(*path == '.') skip++; - ++path; - } - net = my_malloc(_ALLOC_ID_, tmp); - n = sscanf(token + 19, "%[^)]", net); - expandlabel(net, &multip); - if(n == 1 && multip == 1) { - len = strlen(path) + strlen(instname) + strlen(net) + 2; - dbg(1, "net=%s\n", net); - fqnet = my_malloc(_ALLOC_ID_, len); - - - global_net = strrchr(net, '.'); - if(global_net == NULL) global_net = net; - else global_net++; - - if(inst < 0 || record_global_node(3, NULL, global_net)) { - strtolower(net); - my_snprintf(fqnet, len, "%s", global_net); - } else { - strtolower(net); - my_snprintf(fqnet, len, "%s%s.%s", path, instname, net); - } - strtolower(fqnet); - dbg(1, "translate(): inst=%d, net=%s, fqnet=%s start_level=%d\n", inst, net, fqnet, start_level); - idx = get_raw_index(fqnet, NULL); - if(idx >= 0) { - val = xctx->raw->cursor_b_val[idx]; - } - if(!strcmp(fqnet, "0") || !my_strcasecmp(fqnet, "GND")) { - valstr = "0.0"; - xctx->tok_size = 3; - len = 3; - } else if(idx < 0) { - valstr = "-"; - xctx->tok_size = 1; - len = 1; - } else { - /* always use engineering as these tokens are generated from single - * @spice_get_voltage patterns */ - valstr = dtoa_eng(val); - len = xctx->tok_size; - } - if(len) { - STR_ALLOC(&result, len + result_pos, &size); - memcpy(result+result_pos, valstr, len+1); - result_pos += len; - } - dbg(1, "instname %s, net=%s, fqnet=%s idx=%d valstr=%s\n", instname, net, fqnet, idx, valstr); - my_free(_ALLOC_ID_, &fqnet); - } - my_free(_ALLOC_ID_, &net); - } - } - } - /* @spice_get_current(...) or @spice_get_current_param(...) - * @spice_get_modelparam(...) or @spice_get_modelparam_param(...) - * @spice_get_modelvoltage(...) or @spice_get_modelvoltage_param(...) - * - * Only @spice_get_current(...) and @spice_get_current_param(...) are processed - * the other types are ignored */ - else if(!regexec(get_sp_cur, token, 0 , NULL, 0) ) - { - int start_level; /* hierarchy level where waves were loaded */ - int live = tclgetboolvar("live_cursor2_backannotate"); - if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { - char *fqdev = NULL; - const char *path = xctx->sch_path[xctx->currsch] + 1; - char *dev = NULL, *param = NULL; - size_t len; - int idx, n = 0; - double val = 0.0; - const char *valstr; - tmp = strlen(token) + 1; - if(path) { - int skip = 0; - /* skip path components that are above the level where raw file was loaded */ - while(*path && skip < start_level) { - if(*path == '.') skip++; - ++path; - } - dev = my_malloc(_ALLOC_ID_, tmp); - dbg(1, "%s\n", token); - if(!strncmp(token, "@spice_get_current(", 19)) { - n = sscanf(token + 19, "%[^)]", dev); - } else { - param = my_malloc(_ALLOC_ID_, tmp); - n = sscanf(token, "@spice_get_current_%s(%[^)]", param, dev); - if(n < 2) { - my_free(_ALLOC_ID_, ¶m); - n = sscanf(token, "@spice_get_current[^(](%[^)]", dev); - } - } - if(n >= 1) { - strtolower(dev); - len = strlen(path) + strlen(instname) + - strlen(dev) + 21; /* some extra chars for i(..) wrapper */ - dbg(1, "dev=%s\n", dev); - fqdev = my_malloc(_ALLOC_ID_, len); - if(!sim_is_xyce) { - int prefix, vsource; - char *prefix_ptr = strrchr(dev, '.'); /* last '.' in dev */ - if(prefix_ptr) prefix = prefix_ptr[1]; /* character after last '.' */ - else prefix=dev[0]; - dbg(1, "prefix=%c, path=%s\n", prefix, path); - vsource = (prefix == 'v') || (prefix == 'e'); - if(vsource) { - my_snprintf(fqdev, len, "i(%c.%s%s.%s)", prefix, path, instname, dev); - } else if(prefix == 'q') { - my_snprintf(fqdev, len, "i(@%c.%s%s.%s[%s])", prefix, path, instname, dev, param ? param : "ic"); - } else if(prefix == 'd' || prefix == 'm') { - my_snprintf(fqdev, len, "i(@%c.%s%s.%s[%s])", prefix, path, instname, dev, param ? param : "id"); - } else if(prefix == 'i') { - my_snprintf(fqdev, len, "i(@%c.%s%s.%s[current])", prefix, path, instname, dev); - } else { - my_snprintf(fqdev, len, "i(@%c.%s%s.%s[i])", prefix, path, instname, dev); - } - } else { - my_snprintf(fqdev, len, "i(%s%s.%s)", path, instname, dev); - } - strtolower(fqdev); - dbg(1, "fqdev=%s\n", fqdev); - idx = get_raw_index(fqdev, NULL); - if(idx >= 0) { - val = xctx->raw->cursor_b_val[idx]; - } - if(idx < 0) { - valstr = "-"; - xctx->tok_size = 1; - len = 1; - } else { - /* always use engineering as these tokens are generated from single - * @spice_get_voltage patterns */ - valstr = dtoa_eng(val); - len = xctx->tok_size; - } - if(len) { - STR_ALLOC(&result, len + result_pos, &size); - memcpy(result+result_pos, valstr, len+1); - result_pos += len; - } - dbg(1, "instname %s, dev=%s, fqdev=%s idx=%d valstr=%s\n", instname, dev, fqdev, idx, valstr); - my_free(_ALLOC_ID_, &fqdev); - } /* if(n == 1) */ - if(param) my_free(_ALLOC_ID_, ¶m); - my_free(_ALLOC_ID_, &dev); - } /* if(path) */ - } /* if((start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) */ - } - else if(inst >= 0 && strcmp(token,"@spice_get_diff_voltage")==0 && xctx->inst[inst].ptr >= 0) - { - int start_level; /* hierarchy level where waves were loaded */ - int live = tclgetboolvar("live_cursor2_backannotate"); - if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { - int multip; - int no_of_pins= (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; - if(no_of_pins == 2) { - char *fqnet1 = NULL, *fqnet2 = NULL; - const char *path = xctx->sch_path[xctx->currsch] + 1; - const char *net1, *net2; - size_t len; - int idx1, idx2; - double val = 0.0, val1 = 0.0, val2 = 0.0; - const char *valstr; - if(path) { - int gnd1 = 0, gnd2 = 0; - int skip = 0; - /* skip path components that are above the level where raw file was loaded */ - while(*path && skip < start_level) { - if(*path == '.') skip++; - ++path; - } - prepare_netlist_structs(0); - net1 = net_name(inst, 0, &multip, 0, 0); - len = strlen(path) + strlen(net1) + 1; - dbg(1, "net1=%s\n", net1); - fqnet1 = my_malloc(_ALLOC_ID_, len); - my_snprintf(fqnet1, len, "%s%s", path, net1); - strtolower(fqnet1); - net2 = net_name(inst, 1, &multip, 0, 0); - len = strlen(path) + strlen(net2) + 1; - dbg(1, "net2=%s\n", net2); - fqnet2 = my_malloc(_ALLOC_ID_, len); - my_snprintf(fqnet2, len, "%s%s", path, net2); - strtolower(fqnet2); - dbg(1, "translate(): fqnet1=%s start_level=%d\n", fqnet1, start_level); - dbg(1, "translate(): fqnet2=%s start_level=%d\n", fqnet2, start_level); - if(!strcmp(fqnet1, "0") || !my_strcasecmp(fqnet1, "GND")) gnd1 = 1; - if(!strcmp(fqnet2, "0") || !my_strcasecmp(fqnet2, "GND")) gnd2 = 1; - idx1 = get_raw_index(fqnet1, NULL); - idx2 = get_raw_index(fqnet2, NULL); - if( (!gnd1 && idx1 < 0) || (!gnd2 && idx2 < 0) ) { - valstr = "-"; - xctx->tok_size = 1; - len = 1; - } else { - double val1 = gnd1 ? 0.0 : xctx->raw->cursor_b_val[idx1]; - double val2 = gnd2 ? 0.0 : xctx->raw->cursor_b_val[idx2]; - val = val1 - val2; - valstr = engineering ? dtoa_eng(val) : dtoa(val); - len = xctx->tok_size; - } - if(len) { - STR_ALLOC(&result, len + result_pos, &size); - memcpy(result+result_pos, valstr, len+1); - result_pos += len; - } - dbg(1, "inst %d, fqnet1=%s fqnet2=%s idx1=%d idx2=%d, val1=%g val2=%g valstr=%s\n", - inst, fqnet1, fqnet2, idx1, idx2, val1, val2, valstr); - my_free(_ALLOC_ID_, &fqnet1); - my_free(_ALLOC_ID_, &fqnet2); - } - } - } - } - else if( - strncmp(token,"@spice_get_current", 18)==0 || - strncmp(token,"@spice_get_modelparam", 21)==0 || - strncmp(token,"@spice_get_modelvoltage", 23)==0 - ) - { - int start_level; /* hierarchy level where waves were loaded */ - int live = tclgetboolvar("live_cursor2_backannotate"); - if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { - char *fqdev = NULL; - const char *path = xctx->sch_path[xctx->currsch] + 1; - char *dev = NULL, *param = NULL; - int modelparam = 0; /* 0: current, 1: modelparam, 2: modelvoltage */ - size_t len; - int idx; - int error = 0; - double val = 0.0; - const char *valstr; - if(path) { - int skip = 0; - /* skip path components that are above the level where raw file was loaded */ - while(*path && skip < start_level) { - if(*path == '.') skip++; - ++path; - } - /* token contans _param after @spice_get_current or @spice_get_modelparam - * or @spice_get_modelvoltage */ - if(strcmp(token, "@spice_get_current") && - strcmp(token, "@spice_get_modelparam") && - strcmp(token, "@spice_get_modelvoltage")) { - int n = 0; - param = my_malloc(_ALLOC_ID_, strlen(token) + 1); - n = sscanf(token, "@spice_get_current_%s", param); - if(n == 0) { - n = sscanf(token, "@spice_get_modelparam_%s", param); - modelparam = 1; - } - if(n == 0) { - n = sscanf(token, "@spice_get_modelvoltage_%s", param); - modelparam = 2; - } - if(n == 0) { - my_free(_ALLOC_ID_, ¶m); - error = 1; - } - } - if(!error) { - char *iprefix = modelparam == 0 ? "i(" : modelparam == 1 ? "" : "v("; - char *ipostfix = modelparam == 1 ? "" : ")"; - int prefix; - my_strdup2(_ALLOC_ID_, &dev, instname); - strtolower(dev); - prefix=dev[0]; - len = strlen(path) + strlen(dev) + 40; /* some extra chars for i(..) wrapper */ - dbg(1, "token=%s, dev=%s param=%s\n", token, dev, param ? param : ""); - fqdev = my_malloc(_ALLOC_ID_, len); - if(!sim_is_xyce) { - int vsource = (prefix == 'v') || (prefix == 'e'); - if(path[0]) { - if(vsource) { - my_snprintf(fqdev, len, "i(%c.%s%s)", prefix, path, dev); - } else if(prefix=='q') { - my_snprintf(fqdev, len, "%s@%c.%s%s[%s]%s", - iprefix, prefix, path, dev, param ? param : "ic", ipostfix); - } else if(prefix=='d' || prefix == 'm') { - my_snprintf(fqdev, len, "%s@%c.%s%s[%s]%s", - iprefix, prefix, path, dev, param ? param : "id", ipostfix); - } else if(prefix=='i') { - my_snprintf(fqdev, len, "i(@%c.%s%s[current])", prefix, path, dev); - } else { - my_snprintf(fqdev, len, "i(@%c.%s%s[i])", prefix, path, dev); - } - } else { - if(vsource) { - my_snprintf(fqdev, len, "i(%s)", dev); - } else if(prefix == 'q') { - my_snprintf(fqdev, len, "%s@%s[%s]%s", iprefix, dev, param ? param : "ic", ipostfix); - } else if(prefix == 'd' || prefix == 'm') { - my_snprintf(fqdev, len, "%s@%s[%s]%s", iprefix, dev, param ? param : "id", ipostfix); - } else if(prefix == 'i') { - my_snprintf(fqdev, len, "i(@%s[current])", dev); - } else { - my_snprintf(fqdev, len, "i(@%s[i])", dev); - } - } - } else { - my_snprintf(fqdev, len, "i(%s%s)", path, dev); - } - if(param) my_free(_ALLOC_ID_, ¶m); - dbg(1, "fqdev=%s\n", fqdev); - strtolower(fqdev); - idx = get_raw_index(fqdev, NULL); - if(idx >= 0) { - val = xctx->raw->cursor_b_val[idx]; - } - /* special handling for resistors that are converted to b sources: - * i(@r.x4.r1[i]) --> i(@b.x4.br1[i]) - */ - if(idx < 0 && !strncmp(fqdev, "i(@r", 4)) { - if(path[0]) { - my_snprintf(fqdev, len, "i(@b.%sb%s[i])", path, dev); - } else { - my_snprintf(fqdev, len, "i(@b%s[i])", dev); - } - dbg(1, "fqdev=%s\n", fqdev); - idx = get_raw_index(fqdev, NULL); - if(idx >= 0) { - val = xctx->raw->cursor_b_val[idx]; - } - } - if(idx < 0) { - valstr = "-"; - xctx->tok_size = 1; - len = 1; - } else { - valstr = engineering ? dtoa_eng(val) : dtoa(val); - len = xctx->tok_size; - } - if(len) { - STR_ALLOC(&result, len + result_pos, &size); - memcpy(result+result_pos, valstr, len+1); - result_pos += len; - } - dbg(1, "instname %s, dev=%s, fqdev=%s idx=%d valstr=%s\n", instname, dev, fqdev, idx, valstr); - my_free(_ALLOC_ID_, &fqdev); - my_free(_ALLOC_ID_, &dev); - } /* if(!error) */ - } /* if(path) */ - } /* (live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) */ - } - else if(strcmp(token,"@schvhdlprop")==0 && xctx->schvhdlprop) - { - tmp=strlen(xctx->schvhdlprop); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos,xctx->schvhdlprop, tmp+1); - result_pos+=tmp; - } - - else if(strcmp(token,"@schprop")==0 && xctx->schprop) - { - tmp=strlen(xctx->schprop); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos,xctx->schprop, tmp+1); - result_pos+=tmp; - } - /* /20100217 */ - - else if(strcmp(token,"@schsymbolprop")==0 && xctx->schsymbolprop) - { - tmp=strlen(xctx->schsymbolprop); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos,xctx->schsymbolprop, tmp+1); - result_pos+=tmp; - } - else if(strcmp(token,"@schtedaxprop")==0 && xctx->schtedaxprop) - { - tmp=strlen(xctx->schtedaxprop); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos,xctx->schtedaxprop, tmp+1); - result_pos+=tmp; - } - /* /20100217 */ - - else if(strcmp(token,"@schverilogprop")==0 && xctx->schverilogprop) - { - tmp=strlen(xctx->schverilogprop); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos,xctx->schverilogprop, tmp+1); - result_pos+=tmp; - /* if spiceprefix==0 and token == @spiceprefix then set empty value */ - } else if(!sp_prefix && !strcmp(token, "@spiceprefix")) { - /* add nothing */ - } else if(inst >= 0) { - value = get_tok_value(xctx->inst[inst].prop_ptr, token+1, 0); - if(!xctx->tok_size && xctx->inst[inst].ptr >= 0) { - value=get_tok_value(xctx->sym[xctx->inst[inst].ptr].templ, token+1, 0); - } - if(!xctx->tok_size) { /* above lines did not find a value for token */ - if(token[0] =='%') { - /* no definition found -> subst with token without leading % */ - tmp=token_pos -1 ; /* we need token_pos -1 chars, ( strlen(token+1) ) , excluding leading '%' */ + + tmp=strlen(path); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, path, tmp+1); + result_pos+=tmp; + } else if(inst >= 0 && strcmp(token,"@symname_ext")==0) { + tmp_sym_name = get_sym_name(inst, 0, 1, 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); + result_pos+=tmp; + /* recognize single pins 15112003 */ + } else if(inst >= 0 && token[0]=='@' && token[1]=='@' && xctx->inst[inst].ptr >= 0) { + int i, multip; + int no_of_pins= (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; + prepare_netlist_structs(0); + for(i=0;iinst[inst].ptr + xctx->sym)->rect[PINLAYER][i].prop_ptr; + if (!strcmp( get_tok_value(prop,"name",0), token+2)) { + if(strboolcmp(get_tok_value(prop,"spice_ignore",0), "true")) { + const char *str_ptr = net_name(inst,i, &multip, 0, 0); + tmp = strlen(str_ptr) +100 ; + STR_ALLOC(&result, tmp + result_pos, &size); + result_pos += my_snprintf(result + result_pos, tmp, "%s", str_ptr); + } + break; + } + } + } else if(inst >= 0 && token[0]=='@' && token[1]=='#') { + value = get_pin_attr(token, inst, engineering); + if(value) { + tmp=strlen(value); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, value, tmp+1); + result_pos+=tmp; + my_free(_ALLOC_ID_, &value); + } + } else if(inst >= 0 && strcmp(token,"@sch_last_modified")==0 && xctx->inst[inst].ptr >= 0) { + + get_sch_from_sym(file_name, xctx->inst[inst].ptr + xctx->sym, inst, 0); + if(!stat(file_name , &time_buf)) { + tm=localtime(&(time_buf.st_mtime) ); + tmp=strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", tm); STR_ALLOC(&result, tmp + result_pos, &size); - /* dbg(2, "translate(): token=%s, token_pos = %d\n", token, token_pos); */ - memcpy(result+result_pos, token + 1, tmp+1); + memcpy(result+result_pos, date, tmp+1); result_pos+=tmp; } - } else { - int i = level; - my_strdup2(_ALLOC_ID_, &value1, value); - /* recursive substitution of value using parent level prop_ptr attributes */ - while(i > 0) { - char *v = value1; - const char *tok; - if(v && v[0] == '@') v++; - tok = get_tok_value(lcc[i-1].prop_ptr, v, 0); - if(xctx->tok_size && tok[0]) { - dbg(1, "tok=%s\n", tok); - my_strdup2(_ALLOC_ID_, &value1, tok); - } else { - tok = get_tok_value(lcc[i-1].templ, v, 0); - if(xctx->tok_size && tok[0]) { - dbg(1, "from parent template: tok=%s\n", tok); - my_strdup2(_ALLOC_ID_, &value1, tok); - } - } - dbg(1, "2 translate(): lcc[%d].prop_ptr=%s, value1=%s\n", i-1, lcc[i-1].prop_ptr, value1); - i--; + } else if(inst >= 0 && strcmp(token,"@sym_last_modified")==0) { + my_strncpy(file_name, abs_sym_path(tcl_hook2(xctx->inst[inst].name), ""), S(file_name)); + if(!stat(file_name , &time_buf)) { + tm=localtime(&(time_buf.st_mtime) ); + tmp=strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", tm); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, date, tmp+1); + result_pos+=tmp; } - tmp=strlen(value1); - STR_ALLOC(&result, tmp + result_pos, &size); - memcpy(result+result_pos, value1, tmp+1); - result_pos+=tmp; - my_free(_ALLOC_ID_, &value1); - } - } - token_pos = 0; - if(c == '@' || c == '%') s--; - else result[result_pos++]=(char)c; - state=TOK_BEGIN; - } /* else if(state==TOK_SEP) */ - else if(state==TOK_BEGIN) result[result_pos++]=(char)c; - if(c=='\0') - { - result[result_pos]='\0'; - break; + } else if(strcmp(token,"@time_last_modified")==0) { + my_strncpy(file_name, abs_sym_path(xctx->sch[xctx->currsch], ""), S(file_name)); + if(!stat(file_name , &time_buf)) { + tm=localtime(&(time_buf.st_mtime) ); + tmp=strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", tm); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, date, tmp+1); + result_pos+=tmp; + } + } else if(strcmp(token,"@schname_ext")==0) { + /* tmp=strlen(xctx->sch[xctx->currsch]);*/ + tmp = strlen(xctx->current_name); + STR_ALLOC(&result, tmp + result_pos, &size); + /* memcpy(result+result_pos,xctx->sch[xctx->currsch], tmp+1); */ + memcpy(result+result_pos, xctx->current_name, tmp+1); + result_pos+=tmp; + } else if(strcmp(token,"@schname")==0) { + const char *schname = get_cell(xctx->current_name, 0); + tmp = strlen(schname); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, schname, tmp+1); + result_pos+=tmp; + } else if(strcmp(token,"@topschname")==0) { + const char *topsch; + topsch = get_trailing_path(xctx->sch[0], 0, 1); + tmp = strlen(topsch); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, topsch, tmp+1); + result_pos+=tmp; + } else if(inst >= 0 && strcmp(token,"@prop_ptr")==0 && xctx->inst[inst].prop_ptr) { + tmp=strlen(xctx->inst[inst].prop_ptr); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos,xctx->inst[inst].prop_ptr, tmp+1); + result_pos+=tmp; + } + else if(inst >= 0 && strcmp(token,"@spice_get_voltage")==0 && xctx->inst[inst].ptr >= 0) + { + int start_level; /* hierarchy level where waves were loaded */ + int live = tclgetboolvar("live_cursor2_backannotate"); + if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { + int multip; + int no_of_pins= (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; + if(no_of_pins == 1) { + char *fqnet = NULL; + const char *path = xctx->sch_path[xctx->currsch] + 1; + char *net = NULL; + size_t len; + int idx; + double val = 0.0; + const char *valstr; + if(path) { + prepare_netlist_structs(0); + if(xctx->inst[inst].lab) { + my_strdup2(_ALLOC_ID_, &net, expandlabel(xctx->inst[inst].lab, &multip)); + } + if(net == NULL || net[0] == '\0') { + my_strdup2(_ALLOC_ID_, &net, net_name(inst, 0, &multip, 0, 0)); + } + if(multip == 1 && net && net[0]) { + char *rn; + dbg(1, "translate() @spice_get_voltage: inst=%s\n", instname); + dbg(1, " net=%s\n", net); + rn = resolved_net(net); + if(rn) { + my_strdup2(_ALLOC_ID_, &fqnet, rn); + if(rn) my_free(_ALLOC_ID_, &rn); + strtolower(fqnet); + dbg(1, "translate() @spice_get_voltage: fqnet=%s start_level=%d\n", fqnet, start_level); + idx = get_raw_index(fqnet, NULL); + if(idx >= 0) { + val = xctx->raw->cursor_b_val[idx]; + } + if(!strcmp(fqnet, "0") || !my_strcasecmp(fqnet, "GND")) { + valstr = "0.0"; + xctx->tok_size = 3; + len = 3; + } else if(idx < 0) { + valstr = "-"; + xctx->tok_size = 5; + len = 5; + } else { + valstr = engineering ? dtoa_eng(val) : dtoa(val); + len = xctx->tok_size; + } + if(len) { + STR_ALLOC(&result, len + result_pos, &size); + memcpy(result+result_pos, valstr, len+1); + result_pos += len; + } + dbg(1, "inst %d, net=%s, fqnet=%s idx=%d valstr=%s\n", inst, net, fqnet, idx, valstr); + if(fqnet) my_free(_ALLOC_ID_, &fqnet); + } + } + if(net) my_free(_ALLOC_ID_, &net); + } + } + } + } + + /* copy as is: processed by spice_get_node() later + * the format is "some_text@spice_get_node some_additional_text" + * Examples: + * Id=@spice_get_node i(\@m.@path@spiceprefix@name\.msky130_fd_pr__@model\[id]) + * will translate to: + * Id=6.6177u + * Id=@spice_get_node i(\@m.@path@spiceprefix@name\.msky130_fd_pr__@model\[id]) A + * will translate to: + * Id=6.6177uA + * note the required separator spaces around the spice node. Spaces are used here as + * separators since spice nodes don't allow spaces. + * escapes are used for 2 reasons: + * mark a @ as a literal character instead of a the start of a @var token to be substituted + * mark the end of a @var, like for example @var\iable. In this case @var will + * be substituted by xschem instead of @variable + * + * caveats: only one @spice_get_node is allowed in a string + */ + else if(strcmp(token,"@spice_get_node")==0 ) + { + STR_ALLOC(&result, 15 + result_pos, &size); + memcpy(result+result_pos, token, 16); + result_pos += 15; + } + else if(strncmp(token,"@spice_get_voltage(", 19)==0 ) + { + int start_level; /* hierarchy level where waves were loaded */ + int live = tclgetboolvar("live_cursor2_backannotate"); + dbg(1, "--> %s\n", token); + if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { + char *fqnet = NULL; + const char *path = xctx->sch_path[xctx->currsch] + 1; + char *net = NULL; + char *global_net; + size_t len; + int idx, n, multip; + double val = 0.0; + const char *valstr; + tmp = strlen(token) + 1; + if(path) { + int skip = 0; + /* skip path components that are above the level where raw file was loaded */ + while(*path && skip < start_level) { + if(*path == '.') skip++; + ++path; + } + net = my_malloc(_ALLOC_ID_, tmp); + n = sscanf(token + 19, "%[^)]", net); + expandlabel(net, &multip); + if(n == 1 && multip == 1) { + len = strlen(path) + strlen(instname) + strlen(net) + 2; + dbg(1, "net=%s\n", net); + fqnet = my_malloc(_ALLOC_ID_, len); + + + global_net = strrchr(net, '.'); + if(global_net == NULL) global_net = net; + else global_net++; + + if(inst < 0 || record_global_node(3, NULL, global_net)) { + strtolower(net); + my_snprintf(fqnet, len, "%s", global_net); + } else { + strtolower(net); + my_snprintf(fqnet, len, "%s%s.%s", path, instname, net); + } + strtolower(fqnet); + dbg(1, "translate(): inst=%d, net=%s, fqnet=%s start_level=%d\n", inst, net, fqnet, start_level); + idx = get_raw_index(fqnet, NULL); + if(idx >= 0) { + val = xctx->raw->cursor_b_val[idx]; + } + if(!strcmp(fqnet, "0") || !my_strcasecmp(fqnet, "GND")) { + valstr = "0.0"; + xctx->tok_size = 3; + len = 3; + } else if(idx < 0) { + valstr = "-"; + xctx->tok_size = 1; + len = 1; + } else { + /* always use engineering as these tokens are generated from single + * @spice_get_voltage patterns */ + valstr = dtoa_eng(val); + len = xctx->tok_size; + } + if(len) { + STR_ALLOC(&result, len + result_pos, &size); + memcpy(result+result_pos, valstr, len+1); + result_pos += len; + } + dbg(1, "instname %s, net=%s, fqnet=%s idx=%d valstr=%s\n", instname, net, fqnet, idx, valstr); + my_free(_ALLOC_ID_, &fqnet); + } + my_free(_ALLOC_ID_, &net); + } + } + } + /* @spice_get_current(...) or @spice_get_current_param(...) + * @spice_get_modelparam(...) or @spice_get_modelparam_param(...) + * @spice_get_modelvoltage(...) or @spice_get_modelvoltage_param(...) + * + * Only @spice_get_current(...) and @spice_get_current_param(...) are processed + * the other types are ignored */ + else if(!regexec(get_sp_cur, token, 0 , NULL, 0) ) + { + int start_level; /* hierarchy level where waves were loaded */ + int live = tclgetboolvar("live_cursor2_backannotate"); + if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { + char *fqdev = NULL; + const char *path = xctx->sch_path[xctx->currsch] + 1; + char *dev = NULL, *param = NULL; + size_t len; + int idx, n = 0; + double val = 0.0; + const char *valstr; + tmp = strlen(token) + 1; + if(path) { + int skip = 0; + /* skip path components that are above the level where raw file was loaded */ + while(*path && skip < start_level) { + if(*path == '.') skip++; + ++path; + } + dev = my_malloc(_ALLOC_ID_, tmp); + dbg(1, "%s\n", token); + if(!strncmp(token, "@spice_get_current(", 19)) { + n = sscanf(token + 19, "%[^)]", dev); + } else { + param = my_malloc(_ALLOC_ID_, tmp); + n = sscanf(token, "@spice_get_current_%s(%[^)]", param, dev); + if(n < 2) { + my_free(_ALLOC_ID_, ¶m); + n = sscanf(token, "@spice_get_current[^(](%[^)]", dev); + } + } + if(n >= 1) { + strtolower(dev); + len = strlen(path) + strlen(instname) + + strlen(dev) + 21; /* some extra chars for i(..) wrapper */ + dbg(1, "dev=%s\n", dev); + fqdev = my_malloc(_ALLOC_ID_, len); + if(!sim_is_xyce) { + int prefix, vsource; + char *prefix_ptr = strrchr(dev, '.'); /* last '.' in dev */ + if(prefix_ptr) prefix = prefix_ptr[1]; /* character after last '.' */ + else prefix=dev[0]; + dbg(1, "prefix=%c, path=%s\n", prefix, path); + vsource = (prefix == 'v') || (prefix == 'e'); + if(vsource) { + my_snprintf(fqdev, len, "i(%c.%s%s.%s)", prefix, path, instname, dev); + } else if(prefix == 'q') { + my_snprintf(fqdev, len, "i(@%c.%s%s.%s[%s])", prefix, path, instname, dev, param ? param : "ic"); + } else if(prefix == 'd' || prefix == 'm') { + my_snprintf(fqdev, len, "i(@%c.%s%s.%s[%s])", prefix, path, instname, dev, param ? param : "id"); + } else if(prefix == 'i') { + my_snprintf(fqdev, len, "i(@%c.%s%s.%s[current])", prefix, path, instname, dev); + } else { + my_snprintf(fqdev, len, "i(@%c.%s%s.%s[i])", prefix, path, instname, dev); + } + } else { + my_snprintf(fqdev, len, "i(%s%s.%s)", path, instname, dev); + } + strtolower(fqdev); + dbg(1, "fqdev=%s\n", fqdev); + idx = get_raw_index(fqdev, NULL); + if(idx >= 0) { + val = xctx->raw->cursor_b_val[idx]; + } + if(idx < 0) { + valstr = "-"; + xctx->tok_size = 1; + len = 1; + } else { + /* always use engineering as these tokens are generated from single + * @spice_get_voltage patterns */ + valstr = dtoa_eng(val); + len = xctx->tok_size; + } + if(len) { + STR_ALLOC(&result, len + result_pos, &size); + memcpy(result+result_pos, valstr, len+1); + result_pos += len; + } + dbg(1, "instname %s, dev=%s, fqdev=%s idx=%d valstr=%s\n", instname, dev, fqdev, idx, valstr); + my_free(_ALLOC_ID_, &fqdev); + } /* if(n == 1) */ + if(param) my_free(_ALLOC_ID_, ¶m); + my_free(_ALLOC_ID_, &dev); + } /* if(path) */ + } /* if((start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) */ + } + else if(inst >= 0 && strcmp(token,"@spice_get_diff_voltage")==0 && xctx->inst[inst].ptr >= 0) + { + int start_level; /* hierarchy level where waves were loaded */ + int live = tclgetboolvar("live_cursor2_backannotate"); + if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { + int multip; + int no_of_pins= (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; + if(no_of_pins == 2) { + char *fqnet1 = NULL, *fqnet2 = NULL; + const char *path = xctx->sch_path[xctx->currsch] + 1; + const char *net1, *net2; + size_t len; + int idx1, idx2; + double val = 0.0, val1 = 0.0, val2 = 0.0; + const char *valstr; + if(path) { + int gnd1 = 0, gnd2 = 0; + int skip = 0; + /* skip path components that are above the level where raw file was loaded */ + while(*path && skip < start_level) { + if(*path == '.') skip++; + ++path; + } + prepare_netlist_structs(0); + net1 = net_name(inst, 0, &multip, 0, 0); + len = strlen(path) + strlen(net1) + 1; + dbg(1, "net1=%s\n", net1); + fqnet1 = my_malloc(_ALLOC_ID_, len); + my_snprintf(fqnet1, len, "%s%s", path, net1); + strtolower(fqnet1); + net2 = net_name(inst, 1, &multip, 0, 0); + len = strlen(path) + strlen(net2) + 1; + dbg(1, "net2=%s\n", net2); + fqnet2 = my_malloc(_ALLOC_ID_, len); + my_snprintf(fqnet2, len, "%s%s", path, net2); + strtolower(fqnet2); + dbg(1, "translate(): fqnet1=%s start_level=%d\n", fqnet1, start_level); + dbg(1, "translate(): fqnet2=%s start_level=%d\n", fqnet2, start_level); + if(!strcmp(fqnet1, "0") || !my_strcasecmp(fqnet1, "GND")) gnd1 = 1; + if(!strcmp(fqnet2, "0") || !my_strcasecmp(fqnet2, "GND")) gnd2 = 1; + idx1 = get_raw_index(fqnet1, NULL); + idx2 = get_raw_index(fqnet2, NULL); + if( (!gnd1 && idx1 < 0) || (!gnd2 && idx2 < 0) ) { + valstr = "-"; + xctx->tok_size = 1; + len = 1; + } else { + double val1 = gnd1 ? 0.0 : xctx->raw->cursor_b_val[idx1]; + double val2 = gnd2 ? 0.0 : xctx->raw->cursor_b_val[idx2]; + val = val1 - val2; + valstr = engineering ? dtoa_eng(val) : dtoa(val); + len = xctx->tok_size; + } + if(len) { + STR_ALLOC(&result, len + result_pos, &size); + memcpy(result+result_pos, valstr, len+1); + result_pos += len; + } + dbg(1, "inst %d, fqnet1=%s fqnet2=%s idx1=%d idx2=%d, val1=%g val2=%g valstr=%s\n", + inst, fqnet1, fqnet2, idx1, idx2, val1, val2, valstr); + my_free(_ALLOC_ID_, &fqnet1); + my_free(_ALLOC_ID_, &fqnet2); + } + } + } + } + else if( + strncmp(token,"@spice_get_current", 18)==0 || + strncmp(token,"@spice_get_modelparam", 21)==0 || + strncmp(token,"@spice_get_modelvoltage", 23)==0 + ) + { + int start_level; /* hierarchy level where waves were loaded */ + int live = tclgetboolvar("live_cursor2_backannotate"); + if(live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) { + char *fqdev = NULL; + const char *path = xctx->sch_path[xctx->currsch] + 1; + char *dev = NULL, *param = NULL; + int modelparam = 0; /* 0: current, 1: modelparam, 2: modelvoltage */ + size_t len; + int idx; + int error = 0; + double val = 0.0; + const char *valstr; + if(path) { + int skip = 0; + /* skip path components that are above the level where raw file was loaded */ + while(*path && skip < start_level) { + if(*path == '.') skip++; + ++path; + } + /* token contans _param after @spice_get_current or @spice_get_modelparam + * or @spice_get_modelvoltage */ + if(strcmp(token, "@spice_get_current") && + strcmp(token, "@spice_get_modelparam") && + strcmp(token, "@spice_get_modelvoltage")) { + int n = 0; + param = my_malloc(_ALLOC_ID_, strlen(token) + 1); + n = sscanf(token, "@spice_get_current_%s", param); + if(n == 0) { + n = sscanf(token, "@spice_get_modelparam_%s", param); + modelparam = 1; + } + if(n == 0) { + n = sscanf(token, "@spice_get_modelvoltage_%s", param); + modelparam = 2; + } + if(n == 0) { + my_free(_ALLOC_ID_, ¶m); + error = 1; + } + } + if(!error) { + char *iprefix = modelparam == 0 ? "i(" : modelparam == 1 ? "" : "v("; + char *ipostfix = modelparam == 1 ? "" : ")"; + int prefix; + my_strdup2(_ALLOC_ID_, &dev, instname); + strtolower(dev); + prefix=dev[0]; + len = strlen(path) + strlen(dev) + 40; /* some extra chars for i(..) wrapper */ + dbg(1, "token=%s, dev=%s param=%s\n", token, dev, param ? param : ""); + fqdev = my_malloc(_ALLOC_ID_, len); + if(!sim_is_xyce) { + int vsource = (prefix == 'v') || (prefix == 'e'); + if(path[0]) { + if(vsource) { + my_snprintf(fqdev, len, "i(%c.%s%s)", prefix, path, dev); + } else if(prefix=='q') { + my_snprintf(fqdev, len, "%s@%c.%s%s[%s]%s", + iprefix, prefix, path, dev, param ? param : "ic", ipostfix); + } else if(prefix=='d' || prefix == 'm') { + my_snprintf(fqdev, len, "%s@%c.%s%s[%s]%s", + iprefix, prefix, path, dev, param ? param : "id", ipostfix); + } else if(prefix=='i') { + my_snprintf(fqdev, len, "i(@%c.%s%s[current])", prefix, path, dev); + } else { + my_snprintf(fqdev, len, "i(@%c.%s%s[i])", prefix, path, dev); + } + } else { + if(vsource) { + my_snprintf(fqdev, len, "i(%s)", dev); + } else if(prefix == 'q') { + my_snprintf(fqdev, len, "%s@%s[%s]%s", iprefix, dev, param ? param : "ic", ipostfix); + } else if(prefix == 'd' || prefix == 'm') { + my_snprintf(fqdev, len, "%s@%s[%s]%s", iprefix, dev, param ? param : "id", ipostfix); + } else if(prefix == 'i') { + my_snprintf(fqdev, len, "i(@%s[current])", dev); + } else { + my_snprintf(fqdev, len, "i(@%s[i])", dev); + } + } + } else { + my_snprintf(fqdev, len, "i(%s%s)", path, dev); + } + if(param) my_free(_ALLOC_ID_, ¶m); + dbg(1, "fqdev=%s\n", fqdev); + strtolower(fqdev); + idx = get_raw_index(fqdev, NULL); + if(idx >= 0) { + val = xctx->raw->cursor_b_val[idx]; + } + /* special handling for resistors that are converted to b sources: + * i(@r.x4.r1[i]) --> i(@b.x4.br1[i]) + */ + if(idx < 0 && !strncmp(fqdev, "i(@r", 4)) { + if(path[0]) { + my_snprintf(fqdev, len, "i(@b.%sb%s[i])", path, dev); + } else { + my_snprintf(fqdev, len, "i(@b%s[i])", dev); + } + dbg(1, "fqdev=%s\n", fqdev); + idx = get_raw_index(fqdev, NULL); + if(idx >= 0) { + val = xctx->raw->cursor_b_val[idx]; + } + } + if(idx < 0) { + valstr = "-"; + xctx->tok_size = 1; + len = 1; + } else { + valstr = engineering ? dtoa_eng(val) : dtoa(val); + len = xctx->tok_size; + } + if(len) { + STR_ALLOC(&result, len + result_pos, &size); + memcpy(result+result_pos, valstr, len+1); + result_pos += len; + } + dbg(1, "instname %s, dev=%s, fqdev=%s idx=%d valstr=%s\n", instname, dev, fqdev, idx, valstr); + my_free(_ALLOC_ID_, &fqdev); + my_free(_ALLOC_ID_, &dev); + } /* if(!error) */ + } /* if(path) */ + } /* (live && (start_level = sch_waves_loaded()) >= 0 && xctx->raw->annot_p>=0) */ + } + else if(strcmp(token,"@schvhdlprop")==0 && xctx->schvhdlprop) + { + tmp=strlen(xctx->schvhdlprop); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos,xctx->schvhdlprop, tmp+1); + result_pos+=tmp; + } + + else if(strcmp(token,"@schprop")==0 && xctx->schprop) + { + tmp=strlen(xctx->schprop); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos,xctx->schprop, tmp+1); + result_pos+=tmp; + } + /* /20100217 */ + + else if(strcmp(token,"@schsymbolprop")==0 && xctx->schsymbolprop) + { + tmp=strlen(xctx->schsymbolprop); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos,xctx->schsymbolprop, tmp+1); + result_pos+=tmp; + } + else if(strcmp(token,"@schtedaxprop")==0 && xctx->schtedaxprop) + { + tmp=strlen(xctx->schtedaxprop); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos,xctx->schtedaxprop, tmp+1); + result_pos+=tmp; + } + /* /20100217 */ + + else if(strcmp(token,"@schverilogprop")==0 && xctx->schverilogprop) + { + tmp=strlen(xctx->schverilogprop); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos,xctx->schverilogprop, tmp+1); + result_pos+=tmp; + /* if spiceprefix==0 and token == @spiceprefix then set empty value */ + } else if(!sp_prefix && !strcmp(token, "@spiceprefix")) { + /* add nothing */ + } else if(inst >= 0) { + value = get_tok_value(xctx->inst[inst].prop_ptr, token+1, 0); + if(!xctx->tok_size && xctx->inst[inst].ptr >= 0) { + value=get_tok_value(xctx->sym[xctx->inst[inst].ptr].templ, token+1, 0); + } + if(!xctx->tok_size) { /* above lines did not find a value for token */ + if(token[0] =='%') { + /* no definition found -> subst with token without leading % */ + tmp=token_pos -1 ; /* we need token_pos -1 chars, ( strlen(token+1) ) , excluding leading '%' */ + STR_ALLOC(&result, tmp + result_pos, &size); + /* dbg(2, "translate(): token=%s, token_pos = %d\n", token, token_pos); */ + memcpy(result+result_pos, token + 1, tmp+1); + result_pos+=tmp; + } + } else { + int i = level; + my_strdup2(_ALLOC_ID_, &value1, value); + /* recursive substitution of value using parent level prop_ptr attributes */ + while(i > 0) { + char *v = value1; + const char *tok; + if(v && v[0] == '@') v++; + tok = get_tok_value(lcc[i-1].prop_ptr, v, 0); + if(xctx->tok_size && tok[0]) { + dbg(1, "tok=%s\n", tok); + my_strdup2(_ALLOC_ID_, &value1, tok); + } else { + tok = get_tok_value(lcc[i-1].templ, v, 0); + if(xctx->tok_size && tok[0]) { + dbg(1, "from parent template: tok=%s\n", tok); + my_strdup2(_ALLOC_ID_, &value1, tok); + } + } + dbg(1, "2 translate(): lcc[%d].prop_ptr=%s, value1=%s\n", i-1, lcc[i-1].prop_ptr, value1); + i--; + } + tmp=strlen(value1); + STR_ALLOC(&result, tmp + result_pos, &size); + memcpy(result+result_pos, value1, tmp+1); + result_pos+=tmp; + my_free(_ALLOC_ID_, &value1); + } + } + token_pos = 0; + if(c == '@' || c == '%') s--; + else result[result_pos++]=(char)c; + state=TOK_BEGIN; + } /* else if(state==TOK_SEP) */ + else if(state==TOK_BEGIN) result[result_pos++]=(char)c; + if(c=='\0') + { + result[result_pos]='\0'; + break; + } + } /* while(1) */ + dbg(2, "translate(): returning %s\n", result); + my_free(_ALLOC_ID_, &token); + /* resolve spice_get_node patterns. + * if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions + * can be calculated */ + my_strdup2(_ALLOC_ID_, &result, spice_get_node(tcl_hook2(result))); + + if(strstr(result, "expr(")) { + dbg(1, "translate(): expr():%s\n", result); + my_strdup2(_ALLOC_ID_, &result, eval_expr( + translate3(result, 1, xctx->inst[inst].prop_ptr, xctx->sym[xctx->inst[inst].ptr].templ, + NULL, NULL))); } - } /* while(1) */ - dbg(2, "translate(): 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, spice_get_node(tcl_hook2(result))); - - return translated_tok; + return result; } const char *translate2(Lcc *lcc, int level, char* s) @@ -4643,12 +4656,19 @@ const char *translate2(Lcc *lcc, int level, char* s) -/* 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, int eat_escapes, const char *s1, const char *s2, const char *s3) +/* 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 + * eat_escapes: + * bit0 == 0 --> keep escapes + * == 1 --> remove escapes + * bit1 == 0 --> return unchanged token if no value found in s* strings + * == 1 --> return empty token if no definition found in s* strings + */ +const char *translate3(const char *s, int eat_escapes, const char *s1, + const char *s2, const char *s3, const char *s4) { static const char *empty=""; static char *translated_tok = NULL; @@ -4658,60 +4678,70 @@ const char *translate3(const char *s, int eat_escapes, const char *s1, const cha size_t sizetok=0; size_t token_pos=0; const char *value; - int escape=0; - char *value1 = NULL; + int i, escape=0; + size_t found_value = 0; const char *escape_pos = NULL; - + const char *sptr[5]; /* 1...4 used */ 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); + xctx->tok_size = 0; + dbg(1, "---\ntranslate3():\n s=%s\n s1=%s\n s2=%s\n s3=%s\n s4=%s\n---\n", s, s1, s2, s3, s4); my_strdup2(_ALLOC_ID_, &result, ""); - + sptr[1] = s1; sptr[2] = s2; sptr[3] = s3; sptr[4] = s4; while(1) { c=*s; - if(c=='\\') { escape=1; escape_pos = s; - if(eat_escapes) { s++; c=*s; } + if(eat_escapes & 1) { s++; c=*s; } } - space=SPACE(c); - if( state==TOK_BEGIN && (c=='@' || c=='%' ) && !escape ) state=TOK_TOKEN; /* 20161210 escape */ + if( state==TOK_BEGIN && (c=='@' || c=='%' ) && !escape ) state=TOK_TOKEN; else if(state==TOK_TOKEN && token_pos > 1 && ( ( (space || c == '%' || c == '@') && !escape ) || ( (!space && c != '%' && c != '@') && escape ) ) ) state=TOK_SEP; - if( s > escape_pos ) escape = 0; - s++; - STR_ALLOC(&token, token_pos, &sizetok); if(state==TOK_TOKEN) token[token_pos++]=(char)c; else if(state==TOK_SEP) { + found_value = 0; token[token_pos]='\0'; dbg(1, "translate3(): token=|%s|\n", token); - value = get_tok_value(s1, token+1, 0); - if(!xctx->tok_size && s2) { - value=get_tok_value(s2, token+1, 0); + value = NULL; + + for(i = 1; i <= 4; i++) { + if(!found_value && sptr[i]) { + value=get_tok_value(sptr[i], token+1, 0); + dbg(1, "translate3(): i=%d, value=%s\n", i, value); + if(xctx->tok_size) found_value = xctx->tok_size; + } + else if( sptr[i]) { + char *v = NULL; + const char *newval; + my_strdup2(_ALLOC_ID_, &v, value); + newval = get_tok_value(sptr[i], v, 0); + if(xctx->tok_size) { + value = newval; + } + my_free(_ALLOC_ID_, &v); + } } - 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); + + if(!found_value) { /* above lines did not find a value for token */ + if((eat_escapes & 2) == 0) { + /* 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); + my_strcat(_ALLOC_ID_, &result, value); } token_pos = 0; if(c == '@' || c == '%') s--; /* these token separators are also identifiers for next token: push them back */ @@ -4730,7 +4760,6 @@ const char *translate3(const char *s, int eat_escapes, const char *s1, const cha my_strcat(_ALLOC_ID_, &result, ch); } if(c=='\0') { - /* my_strcat(_ALLOC_ID_, &result, ""); */ break; } } /* while(1) */ @@ -4741,6 +4770,7 @@ const char *translate3(const char *s, int eat_escapes, const char *s1, const cha * can be calculated */ dbg(1, "translate3(): result=|%s|\n", result); my_strdup2(_ALLOC_ID_, &translated_tok, tcl_hook2(result)); + xctx->tok_size = found_value; return translated_tok; } diff --git a/src/xinit.c b/src/xinit.c index 9ad21557..5e1a83f3 100644 --- a/src/xinit.c +++ b/src/xinit.c @@ -187,7 +187,7 @@ static int window_state (Display *disp, Window win, char *arg) {/*{{{*/ /* ----------------------------------------------------------------------- */ /* used to set icon */ -void windowid(const char *winpath) +void windowid(const char *win_path) { #ifdef __unix__ int i; @@ -200,11 +200,11 @@ void windowid(const char *winpath) Window *framewin_child_ptr; unsigned int framewindow_nchildren; - dbg(1, "windowid(): winpath=%s\n", winpath); + dbg(1, "windowid(): win_path=%s\n", win_path); framewindow_nchildren =0; mainwindow=Tk_MainWindow(interp); display = Tk_Display(mainwindow); - tclvareval("winfo id ", winpath, NULL); + tclvareval("winfo id ", win_path, NULL); sscanf(tclresult(), "0x%x", (unsigned int *) &ww); framewin = ww; XQueryTree(display, framewin, &rootwindow, &parent_of_topwindow, &framewin_child_ptr, &framewindow_nchildren); @@ -949,12 +949,13 @@ static void xwin_exit(void) list_tokens(NULL, 0); /* clear static data in function */ translate(-1, NULL); /* clear static data in function */ translate2(NULL, 0, NULL); /* clear static data in function */ - translate3(NULL, 0, NULL, NULL, NULL); /* clear static data in function */ + translate3(NULL, 0, NULL, NULL, NULL, NULL); /* clear static data in function */ subst_token(NULL, NULL, NULL); /* clear static data in function */ find_nth(NULL, "", "", 0, 0); /* clear static data in function */ trim_chars(NULL, ""); /* clear static data in function */ tcl_hook2(NULL); /* clear static data in function */ save_ascii_string(NULL, NULL, 0); /* clear static data in function */ + eval_expr_clear_table(); /* clear expression parser data */ dbg(1, "xwin_exit(): removing font\n"); for(i=0;i<127; ++i) my_free(_ALLOC_ID_, &character[i]); dbg(1, "xwin_exit(): closed display\n"); @@ -1445,7 +1446,7 @@ void swap_windows(int dr) new_schematic("switch", wp_j, "", 0); resetwin(1, 1, 1, 0, 0); - my_snprintf(old_winpath, S(old_winpath), ""); + my_snprintf(old_win_path, S(old_win_path), ""); if(dr) draw(); } } @@ -1655,6 +1656,7 @@ static void create_new_window(int *window_count, const char *noconfirm, const ch load_schematic(1, fname, 1, confirm); if(dr) zoom_full(1, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); /* draw */ tclvareval("set_bindings ", window_path[n], NULL); + tclvareval("set_replace_key_binding ", window_path[n], NULL); tclvareval("save_ctx ", window_path[n], NULL); /* restore previous context, * because the Expose event after new window creation does a context switch prev win -> new win @@ -2186,6 +2188,8 @@ void resetwin(int create_pixmap, int clear_pixmap, int force, int w, int h) #else XWindowAttributes wattr; #endif + dbg(1, "resetwin(): create=%d, clear=%d, force=%d, w=%d, h=%d\n", + create_pixmap, clear_pixmap, force, w, h); if(w && h) { width = w; height = h; @@ -2310,6 +2314,7 @@ int Tcl_AppInit(Tcl_Interp *inter) #ifdef __unix__ const char* home_buff; #endif + eval_expr_init_table(); /* get PWD and HOME */ if(!getcwd(pwd_dir, PATH_MAX)) { fprintf(errfp, "Tcl_AppInit(): getcwd() failed\n"); diff --git a/src/xschem.h b/src/xschem.h index 8dad9125..59802adf 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -229,7 +229,9 @@ extern char win_temp_dir[PATH_MAX]; #define START_SYMPIN 16384U #define GRAPHPAN 32768U /* bit 15 */ #define MENUSTART 65536U /* bit 16 */ -#define GRABSCREEN 131072 /* bit 17 */ +#define GRABSCREEN 131072U /* bit 17 */ +#define DESEL_CLICK 262144U /* bit 18 */ +#define DESEL_AREA 524288U /* bit 19 */ #define SELECTED 1U /* used in the .sel field for selected objs. */ #define SELECTED1 2U /* first point selected... */ @@ -238,6 +240,7 @@ extern char win_temp_dir[PATH_MAX]; #define SELECTED4 16U /* sub states encoded in global ui_state2 to reduce ui_state bits usage */ +/* also used when infix_interface=0 */ #define MENUSTARTWIRE 1U /* start wire invoked from menu */ #define MENUSTARTLINE 2U /* start line invoked from menu */ #define MENUSTARTRECT 4U /* start rect invoked from menu */ @@ -250,6 +253,7 @@ extern char win_temp_dir[PATH_MAX]; #define MENUSTARTWIRECUT 512U #define MENUSTARTWIRECUT2 1024U /* do not align cut point to snap */ #define MENUSTARTCOPY 2048U +#define MENUSTARTDESEL 4096U #define WIRE 1 /* types of defined objects */ #define xRECT 2 @@ -1215,7 +1219,7 @@ extern int yyparse_error; extern char *xschem_executable; extern Tcl_Interp *interp; extern double *character[256]; -extern char old_winpath[PATH_MAX]; /* previously switched window, used in callback() */ +extern char old_win_path[PATH_MAX]; /* previously switched window, used in callback() */ extern const char fopen_read_mode[]; /* "r" on unix, "rb" on windows */ /*********** Cmdline options (used at xinit, and then not used anymore) ***********/ @@ -1399,7 +1403,7 @@ extern void draw_crosshair(int what, int state); extern void draw_snap_cursor(int what); extern void backannotate_at_cursor_b_pos(xRect *r, Graph_ctx *gr); /* extern void snapped_wire(double c_snap); */ -extern int callback(const char *winpath, int event, int mx, int my, KeySym key, +extern int callback(const char *win_path, int event, int mx, int my, KeySym key, int button, int aux, int state); extern void resetwin(int create_pixmap, int clear_pixmap, int force, int w, int h); extern Selected find_closest_obj(double mx,double my, int override_lock); @@ -1609,7 +1613,8 @@ extern int isonlydigit(const char *s); extern const char *spice_get_node(const char *token); 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, int eat_escapes, const char *s1, const char *s2, const char *s3); +extern const char *translate3(const char* s, int eat_escapes, const char *s1, + const char *s2, const char *s3, const char *s4); 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); @@ -1675,6 +1680,9 @@ extern void check_box_storage(int c); extern void check_arc_storage(int c); extern void check_line_storage(int c); extern void check_polygon_storage(int c); +extern void eval_expr_init_table(void); +extern void eval_expr_clear_table(void); +extern char *eval_expr(const char *s); extern const char *expandlabel(const char *s, int *m); extern void parse(const char *s); extern void clear_expandlabel_data(void); @@ -1741,7 +1749,7 @@ extern void print_hilight_net(int show); extern void list_hilights(int all); extern void change_layer(); extern void launcher(); -extern void windowid(const char *winpath); +extern void windowid(const char *win_path); extern int preview_window(const char *what, const char *tk_win_path, const char *fname); extern int new_schematic(const char *what, const char *win_path, const char *fname, int dr); extern void toggle_fullscreen(const char *topwin); diff --git a/src/xschem.tcl b/src/xschem.tcl index 5c12cffb..6b7c26bb 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -1005,7 +1005,7 @@ proc convert_to_png {filename dest} { # Alt-Key-c # ButtonPress-4 # -proc key_binding { s d { topwin {} } } { +proc key_binding { s d { win_path {.drw} } } { regsub {.*-} $d {} key @@ -1039,14 +1039,14 @@ proc key_binding { s d { topwin {} } } { if { [regexp ButtonPress-3 $d] } { set state [expr {$state +0x400}] } # puts "$state $key <${s}>" if {[regexp ButtonPress- $d]} { - bind $topwin.drw "<${s}>" "xschem callback %W %T %x %y 0 $key 0 $state" + bind $win_path "<${s}>" "xschem callback %W %T %x %y 0 $key 0 $state" } else { if {![string compare $d {} ] } { # puts "bind .drw <${s}> {}" - bind $topwin.drw "<${s}>" {} + bind $win_path "<${s}>" {} } else { # puts "bind .drw <${s}> xschem callback %W %T %x %y $keysym 0 0 $state" - bind $topwin.drw "<${s}>" "xschem callback %W %T %x %y $keysym 0 0 $state" + bind $win_path "<${s}>" "xschem callback %W %T %x %y $keysym 0 0 $state" } } @@ -1771,7 +1771,7 @@ proc simconf_add {tool} { # proc cellview prints symbol bindings (default binding or "schematic" attr in symbol) # of all symbols used in current and sub schematics. proc cellview_setlabels {w symbol derived_symbol} { - global dark_gui_colorscheme + global dark_gui_colorscheme netlist_type if {$dark_gui_colorscheme} { set instfg orange1 set symfg SeaGreen1 @@ -1783,6 +1783,7 @@ proc cellview_setlabels {w symbol derived_symbol} { set symbg SeaGreen1 set missingbg IndianRed1 } + set save_netlist_type [xschem get netlist_type] set current [xschem get current_name] set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2] set abs_sch [xschem get_sch_from_sym -1 $symbol] @@ -1799,6 +1800,8 @@ proc cellview_setlabels {w symbol derived_symbol} { if { $sym_spice_sym_def eq {}} { if { ![file exists [abs_sym_path [$w get]]] } { $w configure -bg $missingbg + } elseif {$new_sch ne $default_sch } { + $w configure -bg $symbg } } puts =============== @@ -1816,6 +1819,8 @@ proc cellview_setlabels {w symbol derived_symbol} { xschem save fast xschem remove_symbols ;# purge all symbols to force a reload from disk xschem load -keep_symbols -nodraw -noundoreset $current + set netlist_type $save_netlist_type + xschem set netlist_type $netlist_type xschem netlist -keep_symbols -noalert;# traverse the hierarchy and retain all encountered symbols puts "get netlist" } @@ -1826,6 +1831,8 @@ proc cellview_setlabels {w symbol derived_symbol} { } proc cellview_edit_item {symbol w} { + global netlist_type + set save_netlist_type [xschem get netlist_type] set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2] if {[xschem is_generator [$w get]]} { set f [$w get] @@ -1834,7 +1841,6 @@ proc cellview_edit_item {symbol w} { } elseif { $sym_spice_sym_def eq {}} { xschem load_new_window [$w get] } else { - puts $symbol set current [xschem get current_name] set old_sym_def [xschem getprop symbol $symbol spice_sym_def 2] set new_sym_def [editdata $sym_spice_sym_def {Symbol spice_sym_def attribute}] @@ -1847,6 +1853,8 @@ proc cellview_edit_item {symbol w} { xschem save fast puts "$symbol: updated spice_sym_def attribute" xschem load -keep_symbols -nodraw -noundoreset $current + set netlist_type $save_netlist_type + xschem set netlist_type $netlist_type xschem reload_symbols ;# update in-memory symbol data } } @@ -1863,8 +1871,10 @@ proc cellview_edit_sym {w} { xschem load_new_window $sym } -proc cellview { {derived_symbols {}} {upd 0} } { - global keep_symbols nolist_libs dark_gui_colorscheme +proc cellview { {derived_symbols {}} {upd 0}} { + global keep_symbols nolist_libs dark_gui_colorscheme netlist_type + + set save_netlist_type [xschem get netlist_type] if {$dark_gui_colorscheme} { set instfg orange1 @@ -1884,6 +1894,8 @@ proc cellview { {derived_symbols {}} {upd 0} } { } if {!$upd} { + set netlist_type $save_netlist_type + xschem set netlist_type $netlist_type xschem reload_symbols ;# purge unused symbols xschem netlist -keep_symbols -noalert;# traverse the hierarchy and retain all encountered symbols puts "get netlist" @@ -1906,15 +1918,17 @@ proc cellview { {derived_symbols {}} {upd 0} } { } set syms [join [lsort -index 1 [xschem symbols $derived_symbols]]] + # puts "syms=$syms" foreach {i symbol} $syms { if { [catch {set base_name [xschem symbol_base_name $symbol]}] } { set base_name $symbol } + # puts "i=$i, symbol=$symbol" set derived_symbol 0 if {$base_name ne {}} { set derived_symbol 1 } - if { [catch {set abs_sch [xschem get_sch_from_sym -1 $symbol]} ]} { + if { [catch {xschem get_sch_from_sym -1 $symbol} abs_sch ]} { set abs_sch [abs_sym_path [add_ext $symbol .sch]] } if {$derived_symbol} { @@ -1931,6 +1945,9 @@ proc cellview { {derived_symbols {}} {upd 0} } { } if {$skip} { continue } set sym_sch [rel_sym_path $abs_sch] + if {[catch {xschem getprop symbol $symbol type} type]} { + puts "error: $symbol not found: $type" + } set type [xschem getprop symbol $symbol type] set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2] if {$type eq {subcircuit}} { @@ -1986,7 +2003,7 @@ proc cellview { {derived_symbols {}} {upd 0} } { if {$upd} {return} frame .cv.bottom - button .cv.bottom.update -text Update -command "cellview $derived_symbols 1" + button .cv.bottom.update -text Update -command "cellview [list $derived_symbols] 1" pack .cv.bottom.update -side left label .cv.bottom.status -text {STATUS LINE} pack .cv.bottom.status -fill x -expand yes @@ -2006,9 +2023,10 @@ proc cellview { {derived_symbols {}} {upd 0} } { ############ traversal proc traversal_setlabels {w parent_sch instname inst_sch sym_sch default_sch inst_spice_sym_def sym_spice_sym_def} { - global traversal dark_gui_colorscheme + global traversal dark_gui_colorscheme netlist_type set sf .trav.center.f.scrl + set save_netlist_type [xschem get netlist_type] # puts "traversal_setlabels: $w parent: |$parent_sch| inst: $instname def: $sym_sch $inst_sch --> [$w get]" # update schematic if {$parent_sch ne {}} { @@ -2026,6 +2044,8 @@ proc traversal_setlabels {w parent_sch instname inst_sch sym_sch default_sch set inst_sch [$w get] # puts "inst_sch set to: $inst_sch" xschem load -undoreset -nodraw $current + set netlist_type $save_netlist_type + xschem set netlist_type $netlist_type } } # /update schematic @@ -2955,6 +2975,14 @@ proc touches {sel tag} { return $res } +proc set_graph_default_colors {} { + global graph_selected graph_schname + if { [xschem get schname] ne $graph_schname } return + xschem setprop -fast rect 2 $graph_selected color "4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21" + graph_update_nodelist + xschem draw_graph $graph_selected +} + # change color of selected wave in text widget and redraw graph # OR # change color attribute of wave given as parameter, redraw graph @@ -3346,13 +3374,13 @@ proc graph_edit_properties {n} { grid columnconfig .graphdialog.center.right 5 -weight 0 # bottom frame - button .graphdialog.bottom.cancel -text Cancel -command { + button .graphdialog.bottom.cancel -padx 1 -borderwidth 1 -pady 0 -text Cancel -command { set graph_dialog_default_geometry [winfo geometry .graphdialog] destroy .graphdialog set graph_selected {} set graph_schname {} } - button .graphdialog.bottom.ok -text OK -command { + button .graphdialog.bottom.ok -padx 1 -borderwidth 1 -pady 0 -text OK -command { if { [xschem get schname] eq $graph_schname } { graph_push_undo graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"] @@ -3367,7 +3395,7 @@ proc graph_edit_properties {n} { set graph_selected {} set graph_schname {} } - button .graphdialog.bottom.apply -text Apply -command { + button .graphdialog.bottom.apply -padx 1 -borderwidth 1 -pady 0 -text Apply -command { if { [xschem get schname] eq $graph_schname } { graph_push_undo graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"] @@ -3384,9 +3412,16 @@ proc graph_edit_properties {n} { pack .graphdialog.bottom.apply -side left pack .graphdialog.bottom.cancel -side left - for {set i 4} {$i < $cadlayers} {incr i} { - radiobutton .graphdialog.bottom.r$i -value $i -background [lindex $tctx::colors $i] \ - -variable graph_sel_color -command graph_change_wave_color -selectcolor white -foreground black + for {set i 4} {$i <= $cadlayers} {incr i} { + if {$i == $cadlayers } { + button .graphdialog.bottom.r$i -padx 1 -borderwidth 1 -pady 0 \ + -command "set_graph_default_colors" \ + -text {AUTO SET} + } else { + radiobutton .graphdialog.bottom.r$i -value $i -background [lindex $tctx::colors $i] \ + -variable graph_sel_color -command graph_change_wave_color \ + -selectcolor white -foreground black + } pack .graphdialog.bottom.r$i -side left } @@ -3872,6 +3907,7 @@ proc open_sub_schematic {{inst {}} {inst_number 0}} { proc is_xschem_file {f} { + regsub {\(.*} $f {} f ;# remove trailing generator args (gen.tcl(....)) if any if { ![file exists $f] } { return 0 } elseif { [file isdirectory $f] } { return 0 } set a [catch {open "$f" r} fd] @@ -4246,7 +4282,7 @@ proc file_dialog_place_symbol {} { proc file_dialog_display_preview {f} { set type [is_xschem_file $f] - if { $type ne {0} && $type ne {GENERATOR} } { + if { $type ne {0} } { if { [winfo exists .load] } { .load.l.paneright.draw configure -background {} xschem preview_window draw .load.l.paneright.draw "$f" @@ -7831,33 +7867,33 @@ proc housekeeping_ctx {} { } # callback that resets simulate button color at end of simulation -proc set_simulate_button {top_path winpath} { +proc set_simulate_button {top_path win_path} { global simulate_bg execute has_x if {![info exists has_x]} return set current_win [xschem get current_win_path] - set simvar tctx::${winpath}_simulate + set simvar tctx::${win_path}_simulate set sim_button $top_path.menubar # puts "current_win=|$current_win|" # puts "simvar=|$simvar|" - # puts "winpath=|$winpath|" + # puts "win_path=|$win_path|" # puts "top_path=|$top_path|" # puts "sim_button=|$sim_button|" # puts "execute(exitcode,last)=|$execute(exitcode,last)|" if {![info exists execute(exitcode,last)]} { - if { $current_win eq $winpath} { + if { $current_win eq $win_path} { $sim_button entryconfigure Simulate -background $simulate_bg } set $simvar $simulate_bg } elseif { $execute(exitcode,last) == 0} { - if { $current_win eq $winpath} { + if { $current_win eq $win_path} { $sim_button entryconfigure Simulate -background Green } set $simvar Green } else { - if { $current_win eq $winpath} { + if { $current_win eq $win_path} { $sim_button entryconfigure Simulate -background red } set $simvar red @@ -8900,11 +8936,11 @@ proc create_layers_menu { {topwin {} } } { } } -proc set_replace_key_binding {} { +proc set_replace_key_binding { {win_path {.drw}}} { global replace_key if {[array exists replace_key]} { foreach i [array names replace_key] { - key_binding "$i" "$replace_key($i)" + key_binding "$i" "$replace_key($i)" $win_path } } } @@ -8925,6 +8961,15 @@ proc eval_postinit_commands {} { } } +proc eval_netlist_postprocess {} { + global netlist_postprocess + if {[info exists netlist_postprocess]} { + if {[catch {uplevel #0 $netlist_postprocess} res]} { + puts "executing $netlist_postprocess:\n\n$res" + } + } +} + proc setup_tcp_xschem { {port_number {}} } { global xschem_listen_port xschem_server_getdata diff --git a/src/xschemrc b/src/xschemrc index dfec3dfc..092298dd 100644 --- a/src/xschemrc +++ b/src/xschemrc @@ -545,7 +545,10 @@ # } # } - +########################################################################### +#### TCL COMMANDS TO BE EXECUTED AFTER GENERATING NETLIST +########################################################################### +# set netlist_postprocess {textfile $netlist_dir/[xschem get netlist_name fallback]} ########################################################################### #### WEB URL DOWNLOAD HELPER APPLICATION diff --git a/xschem_library/devices/simulator_commands.sym b/xschem_library/devices/simulator_commands.sym index ee2879f3..4e227033 100644 --- a/xschem_library/devices/simulator_commands.sym +++ b/xschem_library/devices/simulator_commands.sym @@ -1,4 +1,4 @@ -v {xschem version=3.4.5 file_version=1.2 +v {xschem version=3.4.6 file_version=1.2 * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit @@ -31,7 +31,7 @@ value=\\" format="tcleval( [if \{[catch \{sim_is_@simulator \} retval] \} \{ return \{\} \} elseif \{$retval\} \{ return \{ -\\\\@value +@value \} \} else \{ return \{\} \} ])" diff --git a/xschem_library/devices/simulator_commands_shown.sym b/xschem_library/devices/simulator_commands_shown.sym index 52556243..080eb041 100644 --- a/xschem_library/devices/simulator_commands_shown.sym +++ b/xschem_library/devices/simulator_commands_shown.sym @@ -1,4 +1,4 @@ -v {xschem version=3.4.5 file_version=1.2 +v {xschem version=3.4.6 file_version=1.2 * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit @@ -31,7 +31,7 @@ value=\\" format="tcleval( [if \{[catch \{sim_is_@simulator \} retval] \} \{ return \{\} \} elseif \{$retval\} \{ return \{ -\\\\@value +@value \} \} else \{ return \{\} \} ])"} diff --git a/xschem_library/rom8k/lvnand2.sym b/xschem_library/rom8k/lvnand2.sym index 2fa69bb9..805f94a1 100644 --- a/xschem_library/rom8k/lvnand2.sym +++ b/xschem_library/rom8k/lvnand2.sym @@ -1,4 +1,4 @@ -v {xschem version=3.4.4 file_version=1.2 +v {xschem version=3.4.6 file_version=1.2 * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit @@ -31,7 +31,8 @@ template="name=x1 m=1 + VCCPIN=VCC VSSPIN=VSS" extra="VCCPIN VSSPIN" generic_type="m=integer wna=real lna=real wpa=real lpa=real wnb=real lnb=real wpb=real lpb=real VCCPIN=string VSSPIN=string" -verilog_stop=true} +verilog_stop=true +} V {} S {} E {} diff --git a/xschem_library/rom8k/lvnor2.sym b/xschem_library/rom8k/lvnor2.sym index 28cea362..95672ee9 100644 --- a/xschem_library/rom8k/lvnor2.sym +++ b/xschem_library/rom8k/lvnor2.sym @@ -1,4 +1,4 @@ -v {xschem version=3.4.4 file_version=1.2 +v {xschem version=3.4.6 file_version=1.2 * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit @@ -19,7 +19,8 @@ v {xschem version=3.4.4 file_version=1.2 * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } -G {type=subcircuit +G {} +K {type=subcircuit vhdl_stop=true verilog_stop=true format="@name @pinlist @VCCPIN @VSSPIN @symname wna=@wna lna=@lna wpa=@wpa lpa=@lpa wnb=@wnb lnb=@lnb wpb=@wpb lpb=@lpb m=@m" diff --git a/xschem_library/rom8k/lvnot.sym b/xschem_library/rom8k/lvnot.sym index 59321d63..2f4980f0 100644 --- a/xschem_library/rom8k/lvnot.sym +++ b/xschem_library/rom8k/lvnot.sym @@ -1,4 +1,4 @@ -v {xschem version=3.4.4 file_version=1.2 +v {xschem version=3.4.6 file_version=1.2 * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit @@ -30,7 +30,8 @@ template="name=x1 m=1 + VCCPIN=VCC VSSPIN=VSS" extra="VCCPIN VSSPIN" generic_type="m=integer wn=real lln=real wp=real lp=real VCCPIN=string VSSPIN=string" -verilog_stop=true} +verilog_stop=true +} V {} S {} E {} diff --git a/xschem_library/rom8k/rom2_predec1.sym b/xschem_library/rom8k/rom2_predec1.sym index 630760ce..524d5cc4 100644 --- a/xschem_library/rom8k/rom2_predec1.sym +++ b/xschem_library/rom8k/rom2_predec1.sym @@ -1,4 +1,4 @@ -v {xschem version=3.4.4 file_version=1.2 +v {xschem version=3.4.6 file_version=1.2 * * This file is part of XSCHEM, * a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit @@ -19,7 +19,8 @@ v {xschem version=3.4.4 file_version=1.2 * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA } -G {type=subcircuit +G {} +K {type=subcircuit format="@name @pinlist @symname" template="name=x1" }