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"
}