Merge branch 'StefanSchippers:master' into master

This commit is contained in:
Chayan Deb 2025-01-10 17:08:28 +05:30 committed by GitHub
commit 48b561b72c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 684 additions and 548 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="Xschem" Language="1033" Version="3.4.6" Manufacturer="Xschem" UpgradeCode="0deb9c17-cbbd-491c-be3e-24446b27ccd5">
<Product Id="*" Name="Xschem" Language="1033" Version="3.4.6.1" Manufacturer="Xschem" UpgradeCode="0deb9c17-cbbd-491c-be3e-24446b27ccd5">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<WixVariable Id="WixUILicenseRtf"
Value="License.rtf" />
@ -151,9 +151,6 @@
<Component Id="CMPNGSPICEBACKANNOTATE">
<File Id="NGSPICEBACKANNOTATE" KeyPath="yes" Source="../../src/ngspice_backannotate.tcl" />
</Component>
<Component Id="CMPTRAVERSAL">
<File Id="TRAVERSAL" KeyPath="yes" Source="../../src/traversal.tcl" />
</Component>
<Component Id="CMPORDERLABELSAWK">
<File Id="ORDERLABELSAWK" KeyPath="yes" Source="../../src/order_labels.awk" />
</Component>
@ -361,7 +358,6 @@
<ComponentRef Id="CMPMAKESYMAWK" />
<ComponentRef Id="CMPMAKESYMLCCAWK" />
<ComponentRef Id="CMPNGSPICEBACKANNOTATE" />
<ComponentRef Id="CMPTRAVERSAL" />
<ComponentRef Id="CMPMAKEVHDLFROMSPICEAWK" />
<ComponentRef Id="CMPNETLISTCOMPACTORAWK" />
<ComponentRef Id="CMPORDERLABELSAWK" />

View File

@ -5880,6 +5880,9 @@
<Component Id="cmp5B62A7CAE8EECF932F98EB403B5CDD29" Guid="{E3CBD1A0-81FA-4B30-BCC4-3350FC0F7A14}">
<File Id="fil1CACDA915CAC17ACE7F7A3B476C083FF" KeyPath="yes" Source="$(var.docSrcDir)\xschem_man\run_xschem.html" />
</Component>
<Component Id="cmp814223FC22DFF7462DCE79B3829E6FBF" Guid="{3FE54B70-5CDE-4759-B1FB-EE3ECA812574}">
<File Id="fil5DD06C43623DA708411D23E907EEEA81" KeyPath="yes" Source="$(var.docSrcDir)\xschem_man\scripts.html" />
</Component>
<Component Id="cmp9540E3F9B5835A06B30F0AE43A00BDCA" Guid="{4634F2B8-39C0-4F07-A2C5-89AB39A928C5}">
<File Id="fil2934B2FC856C8A8D86E4B92EF92AD1B9" KeyPath="yes" Source="$(var.docSrcDir)\xschem_man\simulation.html" />
</Component>
@ -8370,6 +8373,7 @@
<ComponentRef Id="cmp9B3A7686BB046FC570A7F71F4AD981E3" />
<ComponentRef Id="cmp87920616631BEEA016176533E5C41578" />
<ComponentRef Id="cmp5B62A7CAE8EECF932F98EB403B5CDD29" />
<ComponentRef Id="cmp814223FC22DFF7462DCE79B3829E6FBF" />
<ComponentRef Id="cmp9540E3F9B5835A06B30F0AE43A00BDCA" />
<ComponentRef Id="cmp5DB828CEC70D5904EB1C1A5DC881F321" />
<ComponentRef Id="cmp6506097EF307EF163BD976300B67E723" />

File diff suppressed because it is too large Load Diff

View File

@ -1342,6 +1342,8 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
if x0, y0 not given use mouse coordinates </pre>
<li><kbd> rotate_in_place</kbd></li><pre>
Rotate selected objects around their 0,0 coordinate point </pre>
<li><kbd> round_to_n_digits i n</kbd></li><pre>
round number 'i' to 'n' digits </pre>
<li><kbd> save [fast]</kbd></li><pre>
Save schematic if modified. Does not ask confirmation!
if 'fast' is given it is passed to save_schematic() to avoid
@ -1506,7 +1508,7 @@ C {verilog_timescale.sym} 1050 -100 0 0 {name=s1 timestep="1ns" precision="1ns"
<li><kbd> snap_wire</kbd></li><pre>
Start a GUI start snapped wire placement (click to start a
wire to closest pin/net endpoint) </pre>
<li><kbd> str_replace str rep with [escape]</kbd></li><pre>
<li><kbd> str_replace str rep with [escape] [count]</kbd></li><pre>
replace 'rep' with 'with' in string 'str'
if rep not preceeded by an 'escape' character </pre>
<li><kbd> subst_tok str tok newval</kbd></li><pre>

View File

@ -1482,7 +1482,7 @@ int place_symbol(int pos, const char *symbol_name, double x, double y, short rot
/* remove tcleval( given in file selector, if any ... */
if(strstr(name1, "tcleval(")) {
tclev = 1;
my_snprintf(name1, S(name1), "%s", str_replace(name1, "tcleval(", "", 0));
my_snprintf(name1, S(name1), "%s", str_replace(name1, "tcleval(", "", 0, -1));
}
dbg(1, "place_symbol(): 2: name1=%s\n",name1);
@ -1788,7 +1788,7 @@ const char *get_sym_name(int inst, int ndir, int ext, int abs_path)
/* instance based symbol selection */
sch = tcl_hook2(str_replace(get_tok_value(xctx->inst[inst].prop_ptr,"schematic", 2), "@symname",
get_cell(xctx->inst[inst].name, 0), '\\'));
get_cell(xctx->inst[inst].name, 0), '\\', -1));
if(xctx->tok_size) { /* token exists */
if(abs_path)
@ -1965,9 +1965,17 @@ void get_additional_symbols(int what)
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",2));
/* 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",2), 1,
xctx->inst[i].prop_ptr, NULL, NULL));
dbg(1, "sch=%s\n", sch);
my_strdup2(_ALLOC_ID_, &sch, tcl_hook2(
str_replace( get_tok_value(xctx->inst[i].prop_ptr,"schematic",2), "@symname",
get_cell(xctx->inst[i].name, 0), '\\')));
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)) {
@ -1982,6 +1990,7 @@ void get_additional_symbols(int what)
char *symname_attr = NULL;
int ignore_schematic = 0;
xSymbol *symptr = xctx->inst[i].ptr + xctx->sym;
my_strdup2(_ALLOC_ID_, &default_schematic, get_tok_value(symptr->prop_ptr,"default_schematic",0));
ignore_schematic = !strcmp(default_schematic, "ignore");
@ -2081,12 +2090,17 @@ void get_sch_from_sym(char *filename, xSymbol *sym, int inst, int fallback)
}
dbg(1, "get_sch_from_sym(): current_dirname= %s\n", xctx->current_dirname);
dbg(1, "get_sch_from_sym(): symbol %s inst=%d web_url=%d\n", sym->name, inst, web_url);
if(inst >= 0) my_strdup(_ALLOC_ID_, &str_tmp, get_tok_value(xctx->inst[inst].prop_ptr, "schematic", 2));
if(inst >= 0) {
/* resolve schematic=generator.tcl( @n ) where n=11 is defined in instance attrs */
my_strdup2(_ALLOC_ID_, &str_tmp,
translate3(get_tok_value(xctx->inst[inst].prop_ptr,"schematic",2), 1,
xctx->inst[inst].prop_ptr, NULL, NULL));
}
if(!str_tmp) my_strdup2(_ALLOC_ID_, &str_tmp, get_tok_value(sym->prop_ptr, "schematic", 2));
if(str_tmp[0]) { /* schematic attribute in symbol or instance was given */
/* @symname in schematic attribute will be replaced with symbol name */
my_strdup2(_ALLOC_ID_, &sch, tcl_hook2(str_replace(str_tmp, "@symname",
get_cell(sym->name, 0), '\\')));
get_cell(sym->name, 0), '\\', -1)));
if(is_generator(sch)) { /* generator: return as is */
my_strncpy(filename, sch, PATH_MAX);
is_gen = 1;

View File

@ -497,41 +497,12 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
need_redraw_master = 1;
}
/* move cursor1 */
/* set cursor position from master graph x-axis */
else if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 16 )) {
double c;
c = G_X(xctx->mousex);
if(gr->logx) c = pow(10, c);
if(r->flags & 4) { /* private_cursor */
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(c)));
} else {
xctx->graph_cursor1_x = c;
}
need_all_redraw = 1;
}
/* move cursor2 */
/* set cursor position from master graph x-axis */
else if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 32 )) {
double c;
int floaters = there_are_floaters();
c = G_X(xctx->mousex);
if(gr->logx) c = pow(10, c);
if(r->flags & 4) { /* private_cursor */
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(c)));
} else {
xctx->graph_cursor2_x = c;
}
if(tclgetboolvar("live_cursor2_backannotate")) {
backannotate_at_cursor_b_pos(r, gr);
if(floaters) set_modify(-2); /* update floater caches to reflect actual backannotation */
need_fullredraw = 1;
} else {
need_all_redraw = 1;
}
}
if(xctx->ui_state & GRAPHPAN) goto finish; /* After GRAPHPAN only need to check Motion events for cursors */
if(xctx->mousey_snap < W_Y(gr->gy2)) {
xctx->graph_top = 1;
@ -576,7 +547,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
if(r->flags & 4) { /* private_cursor */
const char *s = get_tok_value(r->prop_ptr, "cursor1_x", 0);
if(s[0]) {
cursor1 = atof(s);
cursor1 = atof_eng(s);
} else {
cursor1 = xctx->graph_cursor1_x;
}
@ -595,7 +566,7 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
if(r->flags & 4) { /* private_cursor */
const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0);
if(s[0]) {
cursor2 = atof_spice(s);
cursor2 = atof_eng(s);
} else {
cursor2 = xctx->graph_cursor2_x;
}
@ -613,59 +584,91 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
else if(event == ButtonPress && button == Button3) {
/* Numerically set cursor position */
if(xctx->graph_flags & 2) {
double cursor1;
double logcursor, cursor;
if(r->flags & 4) { /* private_cursor */
const char *s = get_tok_value(r->prop_ptr, "cursor1_x", 0);
if(s[0]) {
cursor1 = atof_spice(s);
cursor = atof_spice(s);
} else {
cursor1 = xctx->graph_cursor1_x;
cursor = xctx->graph_cursor1_x;
}
} else {
cursor1 = xctx->graph_cursor1_x;
cursor = xctx->graph_cursor1_x;
}
logcursor = cursor;
if(gr->logx ) {
cursor1 = mylog10(cursor1);
logcursor = mylog10(cursor);
}
if(fabs(xctx->mousex - W_X(cursor1)) < 10) {
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor1), NULL);
cursor1 = atof_spice(tclresult());
if(fabs(xctx->mousex - W_X(logcursor)) < 10) {
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL);
cursor = atof_eng(tclresult());
if(r->flags & 4) {
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(cursor1)));
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(cursor)));
} else {
xctx->graph_cursor1_x = cursor1;
xctx->graph_cursor1_x = cursor;
}
event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */
}
need_all_redraw = 1;
}
/* Numerically set cursor position *** DO NOT PUT AN `else if` BELOW *** */
if(xctx->graph_flags & 4) {
double logcursor, cursor;
if(r->flags & 4) { /* private_cursor */
const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0);
if(s[0]) {
cursor = atof_spice(s);
} else {
cursor = xctx->graph_cursor2_x;
}
} else {
cursor = xctx->graph_cursor2_x;
}
logcursor = cursor;
if(gr->logx) {
logcursor = mylog10(cursor);
}
if(fabs(xctx->mousex - W_X(logcursor)) < 10) {
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL);
cursor = atof_eng(tclresult());
if(r->flags & 4) {
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(cursor)));
} else {
xctx->graph_cursor2_x = cursor;
}
event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */
}
need_fullredraw = 1;
}
/* Numerically set cursor position */
if(xctx->graph_flags & 4) {
double cursor2;
if(r->flags & 4) { /* private_cursor */
const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0);
if(s[0]) {
cursor2 = atof_spice(s);
} else {
cursor2 = xctx->graph_cursor2_x;
}
} else {
cursor2 = xctx->graph_cursor2_x;
/* Numerically set hcursor position *** DO NOT PUT AN `else if` BELOW *** */
if(xctx->graph_flags & 128) {
double logcursor, cursor;
logcursor = cursor = gr->hcursor1_y;
if(gr->logy ) {
logcursor = mylog10(cursor);
}
if(gr->logx) {
cursor2 = mylog10(cursor2);
}
if(fabs(xctx->mousex - W_X(cursor2)) < 10) {
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor2), NULL);
cursor2 = atof_spice(tclresult());
if(r->flags & 4) {
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(cursor2)));
} else {
xctx->graph_cursor2_x = cursor2;
}
if(fabs(xctx->mousey - W_Y(logcursor)) < 10) {
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL);
cursor = atof_eng(tclresult());
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor1_y", dtoa(cursor)));
event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */
}
need_fullredraw = 1;
need_redraw_master = 1;
}
/* Numerically set hcursor position *** DO NOT PUT AN `else if` BELOW *** */
if(xctx->graph_flags & 256) {
double logcursor, cursor;
logcursor = cursor = gr->hcursor2_y;
if(gr->logy ) {
logcursor = mylog10(cursor);
}
if(fabs(xctx->mousey - W_Y(logcursor)) < 10) {
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL);
cursor = atof_eng(tclresult());
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor2_y", dtoa(cursor)));
event = 0; button = 0; /* avoid further processing ButtonPress that might set GRAPHPAN */
}
need_redraw_master = 1;
}
}
else if(event == -3 && button == Button1) {
@ -914,38 +917,54 @@ static int waves_callback(int event, int mx, int my, KeySym key, int button, int
}
}
}
else if(event == ButtonPress && button == Button3) {
/* Numerically set hcursor position */
if(xctx->graph_flags & 128) {
double cursor;
cursor = gr->hcursor1_y;
if(gr->logy ) {
cursor = mylog10(cursor);
/* move cursor1 */
/* set cursor position from master graph x-axis */
else if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 16 )) {
double c;
/* selected or locked or master */
if( r->sel || !(r->flags & 2) || i == xctx->graph_master) {
c = G_X(xctx->mousex);
if(gr->logx) c = pow(10, c);
if(r->flags & 4) { /* private_cursor */
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor1_x", dtoa(c)));
} else {
xctx->graph_cursor1_x = c;
}
if(fabs(xctx->mousey - W_Y(cursor)) < 10) {
xctx->ui_state &= ~GRAPHPAN; /* we are setting a cursor so clear GRAPHPAN set before */
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL);
cursor = atof_spice(tclresult());
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor1_y", dtoa(cursor)));
}
need_redraw = 1;
}
/* Numerically set hcursor position */
if(xctx->graph_flags & 256) {
double cursor;
cursor = gr->hcursor2_y;
if(gr->logy ) {
cursor = mylog10(cursor);
}
if(fabs(xctx->mousey - W_Y(cursor)) < 10) {
xctx->ui_state &= ~GRAPHPAN; /* we are setting a cursor so clear GRAPHPAN set before */
tclvareval("input_line {Pos:} {} ", dtoa_eng(cursor), NULL);
cursor = atof_spice(tclresult());
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "hcursor2_y", dtoa(cursor)));
}
need_redraw = 1;
need_all_redraw = 1;
}
}
/* move cursor2 */
/* set cursor position from master graph x-axis */
else if(event == MotionNotify && (state & Button1Mask) && (xctx->graph_flags & 32 )) {
double c;
int floaters = there_are_floaters();
/* selected or locked or master */
if( r->sel || !(r->flags & 2) || i == xctx->graph_master) {
c = G_X(xctx->mousex);
if(gr->logx) c = pow(10, c);
if(r->flags & 4) { /* private_cursor */
my_strdup(_ALLOC_ID_, &r->prop_ptr, subst_token(r->prop_ptr, "cursor2_x", dtoa(c)));
} else {
xctx->graph_cursor2_x = c;
}
if(tclgetboolvar("live_cursor2_backannotate")) {
backannotate_at_cursor_b_pos(r, gr);
if(floaters) set_modify(-2); /* update floater caches to reflect actual backannotation */
need_fullredraw = 1;
} else {
need_all_redraw = 1;
}
}
}
else if(event == ButtonPress && button == Button5 && !(state & ShiftMask)) {
double delta;
/* vertical move of waveforms with mouse wheel */

View File

@ -2915,21 +2915,21 @@ void setup_graph_data(int i, int skip, Graph_ctx *gr)
gr->hcursor1_y = gr->hcursor2_y = 0.0;
val = get_tok_value(r->prop_ptr,"hcursor1_y", 0);
if(val[0]) {
gr->hcursor1_y = atof_spice(val);
gr->hcursor1_y = atof_eng(val);
xctx->graph_flags |= 128;
}
val = get_tok_value(r->prop_ptr,"hcursor2_y", 0);
if(val[0]) {
gr->hcursor2_y = atof_spice(val);
gr->hcursor2_y = atof_eng(val);
xctx->graph_flags |= 256;
}
if(!skip) {
gr->gx1 = 0;
gr->gx2 = 1e-6;
val = get_tok_value(r->prop_ptr,"x1", 0);
if(val[0]) gr->gx1 = atof_spice(val);
if(val[0]) gr->gx1 = atof_eng(val);
val = get_tok_value(r->prop_ptr,"x2", 0);
if(val[0]) gr->gx2 = atof_spice(val);
if(val[0]) gr->gx2 = atof_eng(val);
if(gr->gx1 == gr->gx2) gr->gx2 += 1e-6;
gr->gw = gr->gx2 - gr->gx1;
}
@ -3012,17 +3012,17 @@ void setup_graph_data(int i, int skip, Graph_ctx *gr)
val = get_tok_value(r->prop_ptr,"logy", 0);
if(val[0] == '1') gr->logy = 1;
val = get_tok_value(r->prop_ptr,"y1", 0);
if(val[0]) gr->gy1 = atof_spice(val);
if(val[0]) gr->gy1 = atof_eng(val);
val = get_tok_value(r->prop_ptr,"y2", 0);
if(val[0]) gr->gy2 = atof_spice(val);
if(val[0]) gr->gy2 = atof_eng(val);
if(gr->gy1 == gr->gy2) gr->gy2 += 1.0;
val = get_tok_value(r->prop_ptr,"digital", 0);
if(val[0]) gr->digital = atoi(val);
if(gr->digital) {
val = get_tok_value(r->prop_ptr,"ypos1", 0);
if(val[0]) gr->ypos1 = atof_spice(val);
if(val[0]) gr->ypos1 = atof_eng(val);
val = get_tok_value(r->prop_ptr,"ypos2", 0);
if(val[0]) gr->ypos2 = atof_spice(val);
if(val[0]) gr->ypos2 = atof_eng(val);
if(gr->ypos2 == gr->ypos1) gr->ypos2 += 1.0;
}
gr->posh = gr->ypos2 - gr->ypos1;
@ -3057,6 +3057,7 @@ void setup_graph_data(int i, int skip, Graph_ctx *gr)
gr->digtxtsizelab = 0.000900 * fabs( gr->h / gr->posh * gr->gh );
else
gr->digtxtsizelab = 0.001200 * fabs( gr->h / gr->posh * gr->gh );
gr->txtsizelab *= gr->magx;
/* x axis, y axis text sizes */
gr->txtsizey = gr->h / gr->divy * 0.0095;
@ -3783,7 +3784,7 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
if(r->flags & 4) { /* private_cursor */
const char *s = get_tok_value(r->prop_ptr, "cursor1_x", 0);
if(s[0]) {
cursor1 = atof_spice(s);
cursor1 = atof_eng(s);
} else {
cursor1 = xctx->graph_cursor1_x;
}
@ -3794,7 +3795,7 @@ void draw_graph(int i, const int flags, Graph_ctx *gr, void *ct)
if(r->flags & 4) { /* private_cursor */
const char *s = get_tok_value(r->prop_ptr, "cursor2_x", 0);
if(s[0]) {
cursor2 = atof_spice(s);
cursor2 = atof_eng(s);
} else {
cursor2 = xctx->graph_cursor2_x;
}

View File

@ -554,20 +554,20 @@ char *dtoa_eng(double i)
size_t n;
int suffix = 0;
double absi = fabs(i);
if (absi == 0.0) { suffix = 0;}
else if(absi < 1e-23) { i = 0; suffix = 0;}
else if(absi >=1e12) { i /= 1e12; suffix = 'T';}
else if(absi >=1e9) { i /= 1e9 ; suffix = 'G';}
else if(absi >=1e6) { i /= 1e6 ; suffix = 'M';}
else if(absi >=1e3) { i /= 1e3 ; suffix = 'k';}
else if(absi >=0.1) { suffix = 0;}
else if(absi >=1e-3) { i *= 1e3 ; suffix = 'm';}
else if(absi >=1e-6) { i *= 1e6 ; suffix = 'u';}
else if(absi >=1e-9) { i *= 1e9 ; suffix = 'n';}
else if(absi >=1e-12) { i *= 1e12; suffix = 'p';}
else if(absi >=1e-15) { i *= 1e15; suffix = 'f';}
else { i *= 1e18; suffix = 'a';}
dbg(1, "dtoa_eng(): i=%.17g, absi=%.17g\n", i, absi);
if (absi == 0.0) { suffix = 0 ;}
else if(absi < 0.999999e-23) { i = 0.0 ; suffix = 0 ;}
else if(absi > 0.999999e12) { i /= 1e12; suffix = 'T';}
else if(absi > 0.999999e9) { i /= 1e9 ; suffix = 'G';}
else if(absi > 0.999999e6) { i /= 1e6 ; suffix = 'M';}
else if(absi > 0.999999e3) { i /= 1e3 ; suffix = 'k';}
else if(absi > 0.999999e-1) { suffix = 0; }
else if(absi > 0.999999e-3) { i *= 1e3 ; suffix = 'm';}
else if(absi > 0.999999e-6) { i *= 1e6 ; suffix = 'u';}
else if(absi > 0.999999e-9) { i *= 1e9 ; suffix = 'n';}
else if(absi > 0.999999e-12) { i *= 1e12; suffix = 'p';}
else if(absi > 0.999999e-15) { i *= 1e15; suffix = 'f';}
else { i *= 1e18; suffix = 'a';}
if(suffix) {
n = my_snprintf(s, S(s), "%.5g%c", i, suffix);
} else {
@ -1481,7 +1481,7 @@ int drc_check(int i)
const char *result;
const char *replace_res;
replace_res = str_replace(res, "@symname", xctx->sym[xctx->inst[j].ptr].name, '\\');
replace_res = str_replace(res, "@symname", xctx->sym[xctx->inst[j].ptr].name, '\\', -1);
result = tcleval(replace_res);
if(result && result[0]) {
ret = 1;
@ -1799,8 +1799,10 @@ void change_elem_order(int n)
if(modified) set_modify(1);
}
}
/* replace substring 'rep' in 'str' with 'with', if 'rep' not preceeded by an 'escape' char */
char *str_replace(const char *str, const char *rep, const char *with, int escape)
/* replace substring 'rep' in 'str' with 'with', if 'rep' not preceeded by an 'escape' char
* 'count' indicates the number of replacements to do or all if -1
*/
char *str_replace(const char *str, const char *rep, const char *with, int escape, int count)
{
static char *result = NULL;
static size_t size=0;
@ -1809,6 +1811,7 @@ char *str_replace(const char *str, const char *rep, const char *with, int escape
size_t with_len;
const char *s = str;
int cond;
int replacements = 0;
if(s==NULL || rep == NULL || with == NULL || rep[0] == '\0') {
my_free(_ALLOC_ID_, &result);
@ -1825,11 +1828,14 @@ char *str_replace(const char *str, const char *rep, const char *with, int escape
while(*s) {
STR_ALLOC(&result, result_pos + with_len + 1, &size);
cond = ((s == str) || ((*(s - 1) != escape))) && (!strncmp(s, rep, rep_len));
cond = (count == -1 || replacements < count) &&
((s == str) || ((*(s - 1) != escape))) &&
(!strncmp(s, rep, rep_len));
if(cond) {
my_strncpy(result + result_pos, with, with_len + 1);
result_pos += with_len;
s += rep_len;
replacements++;
} else {
result[result_pos++] = *s++;
}

View File

@ -4589,6 +4589,17 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
Tcl_ResetResult(interp);
}
/* round_to_n_digits i n
* round number 'i' to 'n' digits */
else if(!strcmp(argv[1], "round_to_n_digits"))
{
double r;
if(argc > 3) {
r = round_to_n_digits(atof(argv[2]), atoi(argv[3]));
Tcl_SetResult(interp, dtoa(r), TCL_VOLATILE);
}
}
else { cmd_found = 0;}
break;
case 's': /*----------------------------------------------*/
@ -5538,15 +5549,16 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg
xctx->ui_state2 = MENUSTARTSNAPWIRE;
}
/* str_replace str rep with [escape]
/* str_replace str rep with [escape] [count]
* replace 'rep' with 'with' in string 'str'
* if rep not preceeded by an 'escape' character */
else if(!strcmp(argv[1], "str_replace"))
{
int escape = 0;
int escape = 0, count = -1;
if(argc > 5) escape = argv[5][0];
if(argc > 6) count = atoi(argv[6]);
if(argc > 4) {
Tcl_AppendResult(interp, str_replace(argv[2], argv[3], argv[4], escape), NULL);
Tcl_AppendResult(interp, str_replace(argv[2], argv[3], argv[4], escape, count), NULL);
} else {
Tcl_SetResult(interp, "Missing arguments", TCL_STATIC);
return TCL_ERROR;

View File

@ -67,7 +67,7 @@ const char *tcl_hook2(const char *cmd)
return empty;
}
if(strstr(cmd, "tcleval(") == cmd) {
unescaped_res = str_replace(cmd, "\\}", "}", 0);
unescaped_res = str_replace(cmd, "\\}", "}", 0, -1);
tclvareval("tclpropeval2 {", unescaped_res, "}" , NULL);
my_strdup2(_ALLOC_ID_, &result, tclresult());
/* dbg(0, "tcl_hook2: return: %s\n", result);*/
@ -1972,7 +1972,7 @@ void print_spice_subckt_nodes(FILE *fd, int symbol)
/* can not do this, since @symname is used as a token later in format parser */
/* my_strdup(_ALLOC_ID_, &format1,
* str_replace(format1, "@symname", get_cell(xctx->sym[symbol].name, 0), '\\')); */
* str_replace(format1, "@symname", get_cell(xctx->sym[symbol].name, 0), '\\', -1)); */
if(format1 && strstr(format1, "tcleval(") == format1) {
tclres = tcl_hook2(format1);
@ -3645,6 +3645,57 @@ static char *get_pin_attr(const char *token, int inst, int engineering)
return value;
}
const char *spice_get_node(const char *token)
{
const char *pos;
if((pos = strstr(token, "@spice_get_node "))) {
char *node = NULL;
char *token2 = NULL;
int idx;
char sp;
int n;
size_t len;
double val = 0.0;
const char *valstr;
const char *s;
dbg(1, "token=%s\n", token);
node = my_malloc(_ALLOC_ID_, strlen(token) + 1);
n = sscanf(pos, "%*[^ ] %[^ ]%c", node, &sp);
len = strlen(node);
dbg(1, "node=%s, n=%d, sp=|%c|\n", node, n, sp);
idx = get_raw_index(node, NULL);
if(idx >= 0) {
val = xctx->raw->cursor_b_val[idx];
}
if(!strcmp(node, "0") || !my_strcasecmp(node, "GND")) {
valstr = "0.0";
} else if(idx < 0) {
valstr = "-";
} else {
/* always use engineering as these tokens are generated from single
* @spice_get_node(...) patterns */
valstr = dtoa_eng(val);
}
dbg(1, "valstr=%s\n", valstr);
my_strdup2(_ALLOC_ID_, &token2, str_replace(token, "@spice_get_node ", "", 0, 1));
dbg(1, "token2=%s\n", token2);
if(n == 2 && sp == ' ') {
node[len] = ' ';
node[len + 1] = '\0';
}
s = str_replace(token2, node, valstr, 0, 1);
dbg(1, "s=%s\n", s);
my_free(_ALLOC_ID_, &token2);
my_free(_ALLOC_ID_, &node);
return s;
} else {
return token;
}
}
/* 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 */
/* if s==NULL return emty string */
@ -3902,6 +3953,31 @@ const char *translate(int inst, const char* s)
}
}
}
/* copy as is: processed by spice_get_node() later
* the format is "some_text@spice_get_node <spice_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 */
@ -3914,7 +3990,7 @@ const char *translate(int inst, const char* s)
char *global_net;
size_t len;
int idx, n, multip;
double val;
double val = 0.0;
const char *valstr;
tmp = strlen(token) + 1;
if(path) {
@ -3956,8 +4032,8 @@ const char *translate(int inst, const char* s)
len = 3;
} else if(idx < 0) {
valstr = "-";
xctx->tok_size = 5;
len = 5;
xctx->tok_size = 1;
len = 1;
} else {
/* always use engineering as these tokens are generated from single
* @spice_get_voltage patterns */
@ -3986,7 +4062,7 @@ const char *translate(int inst, const char* s)
char *dev = NULL;
size_t len;
int idx, n;
double val;
double val = 0.0;
const char *valstr;
tmp = strlen(token) + 1;
if(path) {
@ -4029,9 +4105,9 @@ const char *translate(int inst, const char* s)
val = xctx->raw->cursor_b_val[idx];
}
if(idx < 0) {
valstr = "undef";
xctx->tok_size = 5;
len = 5;
valstr = "-";
xctx->tok_size = 1;
len = 1;
} else {
/* always use engineering as these tokens are generated from single
* @spice_get_voltage patterns */
@ -4093,9 +4169,9 @@ const char *translate(int inst, const char* s)
idx1 = get_raw_index(fqnet1, NULL);
idx2 = get_raw_index(fqnet2, NULL);
if( (!gnd1 && idx1 < 0) || (!gnd2 && idx2 < 0) ) {
valstr = "";
xctx->tok_size = 0;
len = 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];
@ -4126,7 +4202,7 @@ const char *translate(int inst, const char* s)
char *dev = NULL;
size_t len;
int idx;
double val;
double val = 0.0;
const char *valstr;
if(path) {
int skip = 0;
@ -4166,9 +4242,9 @@ const char *translate(int inst, const char* s)
val = xctx->raw->cursor_b_val[idx];
}
if(idx < 0) {
valstr = "";
xctx->tok_size = 0;
len = 0;
valstr = "-";
xctx->tok_size = 1;
len = 1;
} else {
valstr = engineering ? dtoa_eng(val) : dtoa(val);
len = xctx->tok_size;
@ -4286,7 +4362,8 @@ const char *translate(int inst, const char* s)
/* if result is like: 'tcleval(some_string)' pass it thru tcl evaluation so expressions
* can be calculated */
my_strdup2(_ALLOC_ID_, &translated_tok, tcl_hook2(result));
my_strdup2(_ALLOC_ID_, &translated_tok, spice_get_node(tcl_hook2(result)));
return translated_tok;
}

View File

@ -715,7 +715,7 @@ static void delete_schematic_data(int delete_pixmap)
/* delete instances, wires, lines, rects, arcs, polys, texts, hash_inst, hash_wire,
* inst & wire .node fields, instance name hash */
remove_symbols();
str_replace(NULL, NULL, NULL, 0);
str_replace(NULL, NULL, NULL, 0, -1);
escape_chars(NULL, "");
sanitize(NULL);
is_generator(NULL);

View File

@ -1601,6 +1601,7 @@ extern Ptr_hashentry *ptr_hash_lookup(Ptr_hashtable *hashtable,
extern char *trim_chars(const char *str, const char *sep);
extern char *find_nth(const char *str, const char *sep, const char *quote, int keep_quote, int n);
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);
@ -1728,7 +1729,7 @@ extern int drc_check(int i);
extern void change_elem_order(int n);
extern int is_generator(const char *name);
extern char *str_chars_replace(const char *str, const char *replace_set, const char with);
extern char *str_replace(const char *str, const char *rep, const char *with, int escape);
extern char *str_replace(const char *str, const char *rep, const char *with, int escape, int count);
extern char *escape_chars(const char *source, const char *charset);
extern int set_different_token(char **s,const char *new, const char *old);
extern void print_hilight_net(int show);