From 294a10bd5a0a7cd9586cb558c43eba521afaa015 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 2 Jan 2025 22:38:40 +0100 Subject: [PATCH 1/8] go_back(): if a write of modified schematic is requested before going up but write fails (for example due to permission issues) then issue a warning and go ahead anyway. Previously xschem got stuck in the lower hierarchy with no way to escape. If xschem load is done with `noundoreset` option do not change some context data (xctx->currsch, xctx->sch_path, xctx->portmap, xctx->sch_inst_number, ...). Various fixes/enhancements in cellview and traversal procedures. --- src/actions.c | 5 +- src/save.c | 2 - src/scheduler.c | 16 +++-- src/xschem.tcl | 179 ++++++++++++++++++++++++++---------------------- 4 files changed, 111 insertions(+), 91 deletions(-) diff --git a/src/actions.c b/src/actions.c index 6323c2a2..7621ee7c 100644 --- a/src/actions.c +++ b/src/actions.c @@ -2403,7 +2403,10 @@ void go_back(int confirm, int set_title) /* 20171006 add confirm */ save_ok = save_schematic(xctx->sch[xctx->currsch]); } } - if(save_ok==0) return; + if(save_ok==0) { + fprintf(errfp, "go_back(): file opening for write failed! %s \n", xctx->current_name); + tclvareval("alert_ {file opening for write failed! ", xctx->current_name, "} {}", NULL); + } unselect_all(1); if(!tclgetboolvar("keep_symbols")) remove_symbols(); from_embedded_sym=0; diff --git a/src/save.c b/src/save.c index 145fa283..04b416db 100644 --- a/src/save.c +++ b/src/save.c @@ -3456,7 +3456,6 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler my_strdup2(_ALLOC_ID_, &xctx->sch[xctx->currsch], name); /* local relative reference */ my_strncpy(xctx->current_name, rel_sym_path(name), S(xctx->current_name)); - /* local filename specified but coming (push, pop) from web object ... */ } else if(is_from_web(xctx->current_dirname) && xschem_web_dirname[0]) { /* ... but not local file from web download --> reset current_dirname */ @@ -3468,7 +3467,6 @@ int load_schematic(int load_symbols, const char *fname, int reset_undo, int aler my_snprintf(msg, S(msg), "get_directory {%s}", fname); my_strncpy(xctx->current_dirname, tcleval(msg), S(xctx->current_dirname)); } - /* local file name */ my_strdup2(_ALLOC_ID_, &xctx->sch[xctx->currsch], fname); /* local relative reference */ diff --git a/src/scheduler.c b/src/scheduler.c index 51af0134..a6ce89de 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -2829,7 +2829,7 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg unselect_all(1); /* no implicit undo: if needed do it before loading */ /* if(!undo_reset) xctx->push_undo(); */ - xctx->currsch = 0; + if(undo_reset) xctx->currsch = 0; remove_symbols(); if(!nofullzoom) { xctx->zoom=CADINITIALZOOM; @@ -2840,12 +2840,14 @@ int xschem(ClientData clientdata, Tcl_Interp *interp, int argc, const char * arg dbg(1, "scheduler: undo_reset=%d\n", undo_reset); ret = load_schematic(load_symbols, f, undo_reset, !force); dbg(1, "xschem load: ret=%d\n", ret); - tclvareval("update_recent_file {", f, "}", NULL); - my_strdup(_ALLOC_ID_, &xctx->sch_path[xctx->currsch], "."); - if(xctx->portmap[xctx->currsch].table) str_hash_free(&xctx->portmap[xctx->currsch]); - str_hash_init(&xctx->portmap[xctx->currsch], HASHSIZE); - xctx->sch_path_hash[xctx->currsch] = 0; - xctx->sch_inst_number[xctx->currsch] = 1; + if(undo_reset) { + tclvareval("update_recent_file {", f, "}", NULL); + my_strdup(_ALLOC_ID_, &xctx->sch_path[xctx->currsch], "."); + if(xctx->portmap[xctx->currsch].table) str_hash_free(&xctx->portmap[xctx->currsch]); + str_hash_init(&xctx->portmap[xctx->currsch], HASHSIZE); + xctx->sch_path_hash[xctx->currsch] = 0; + xctx->sch_inst_number[xctx->currsch] = 1; + } if(nofullzoom) { if(!nodraw) draw(); } else zoom_full(1, 0, 1 + 2 * tclgetboolvar("zoom_full_center"), 0.97); diff --git a/src/xschem.tcl b/src/xschem.tcl index ee642283..be857143 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -1759,8 +1759,27 @@ proc simconf_add {tool} { incr sim($tool,n) } + +############ cellview # this proc prints symbol bindings (default binding or "schematic" attr in symbol) # of all symbols used in current and sub schematics. +proc cellview_setlabels {w sch} { + if {[$w get] ne $sch} { + if { [file exists [abs_sym_path [$w get]]] } { + $w configure -bg PaleGreen + } else { + # puts "$sch --- [$sf.f$i.s get]" + $w configure -bg red + } + } else { + if { [file exists [abs_sym_path [$w get]]] } { + $w configure -bg [option get . background {}] + } else { + $w configure -bg red + } + } +} + proc cellview {} { global keep_symbols @@ -1804,38 +1823,25 @@ proc cellview {} { if {![file exists $abs_sch]} { $sf.f$i.s configure -bg red } elseif {$default_sch ne $sch} { - $sf.f$i.s configure -bg green + $sf.f$i.s configure -bg PaleGreen } + } else { + $sf.f$i.s configure -fg red } balloon $sf.f$i.s $abs_sch - button $sf.f$i.b -text Open -padx 4 -borderwidth 1 -pady 0 -font $font \ + button $sf.f$i.b -text Sch -padx 4 -borderwidth 1 -pady 0 -font $font \ -command " - if { {$spice_sym_def} eq {}} { + if { [list $spice_sym_def] eq {}} { xschem load_new_window \[$sf.f$i.s get\] } else { - viewdata {$spice_sym_def} + editdata [list $spice_sym_def] {Symbol spice_sym_def attribute} }" if {$spice_sym_def eq {}} { $sf.f$i.s insert 0 $sch } else { - $sf.f$i.s insert 0 {<>} + $sf.f$i.s insert 0 {defined in symbol spice_sym_def} } - bind $sf.f$i.s " - if {\[$sf.f$i.s get\] ne {$sch}} { - if { \[file exists \[abs_sym_path \[$sf.f$i.s get\]\]\] } { - $sf.f$i.s configure -bg green - } else { - puts \"$sch --- \[$sf.f$i.s get\]\" - $sf.f$i.s configure -bg red - } - } else { - if { \[file exists \[abs_sym_path \[$sf.f$i.s get\]\]\] } { - $sf.f$i.s configure -bg [option get . background {}] - } else { - $sf.f$i.s configure -bg red - } - } - " + bind $sf.f$i.s "cellview_setlabels %W [list $sch]" pack $sf.f$i.l $sf.f$i.s -side left -fill x -expand 1 pack $sf.f$i.b -side left } @@ -1850,47 +1856,58 @@ proc cellview {} { set maxsize [expr {[winfo height ${sf}] + [winfo height .cv.top] + [winfo height .cv.bottom]}] wm maxsize .cv 9999 $maxsize bind .cv.center.f {sframeyview .cv.center} - bind .cv { sframeyview .cv.center scroll -0.2} - bind .cv { sframeyview .cv.center scroll 0.2} + bind .cv { sframeyview .cv.center scroll -0.1} + bind .cv { sframeyview .cv.center scroll 0.1} + bind .cv {destroy .cv} xschem reload_symbols ;# purge all symbols used in below hierarchies } - - +############ /cellview ############ traversal -proc traversal_update_schematic {w parent_sch instname default_sch} { - if {$parent_sch eq {}} {return} - puts "traversal_update_schematic: $w $parent_sch $instname--> [$w get]" - set current [xschem get current_name] - xschem load $parent_sch noundoreset nodraw - set sch [xschem getprop instance $instname schematic] - if { $sch ne [$w get]} { - if { [$w get] eq $default_sch} { - xschem setprop instance $instname schematic fast ;# remove schematic attr on instance - } else { - xschem setprop instance $instname schematic [$w get] fast ;# set schematic attr on instance - } - xschem set_modify 1 - xschem save - } - xschem load $current noundoreset nodraw -} - proc traversal_setlabels {w parent_sch sch instname default_sch inst_spice_sym_def sym_spice_sym_def} { global traversal_cnt - set sf .cv.center.f.scrl - puts "traversal_setlabels $w $parent_sch $sch $instname" - traversal_update_schematic $w $parent_sch $instname $default_sch + set sf .trav.center.f.scrl + # puts "traversal_setlabels $w $parent_sch $sch $instname" + + # update schematic + if {$parent_sch ne {}} { + set current [xschem get current_name] + puts "traversal_update_schematic: $w parent: $parent_sch $instname def: $default_sch $sch --> [$w get]" + if { $sch ne [$w get] } { + puts "update attr" + xschem load $parent_sch noundoreset nodraw + set sch [xschem getprop instance $instname schematic] + if { $sch ne [$w get]} { + if { [$w get] eq $default_sch} { + xschem setprop instance $instname schematic fast ;# remove schematic attr on instance + } else { + xschem setprop instance $instname schematic [$w get] fast ;# set schematic attr on instance + } + xschem set_modify 1 + xschem save + set sch [$w get] + puts "sch set to: $sch" + } + xschem load $current noundoreset nodraw + + bind $w " + traversal_setlabels $w [list $parent_sch] [list $sch] [list $instname] [list $default_sch] \ + [list $inst_spice_sym_def] [list $sym_spice_sym_def] + " + } + } + # /update schematic + if {[$w get] ne $default_sch} { if { $sym_spice_sym_def ne {}} { - $w configure -fg green + $w configure -fg PaleGreen $w configure -bg [option get . background {}] } elseif {$inst_spice_sym_def ne {}} { $w configure -fg red $w configure -bg [option get . background {}] } elseif { [file exists [abs_sym_path [$w get]]] } { $w configure -fg [option get . foreground {}] - $w configure -bg green + $w configure -bg PaleGreen } else { $w configure -fg [option get . foreground {}] $w configure -bg red @@ -1920,37 +1937,37 @@ proc traversal {{only_subckts 0} {all_hierarchy 1}} { set font fixed } - toplevel .cv - wm geometry .cv 1200x400 + toplevel .trav + wm geometry .trav 1200x400 - frame .cv.top - label .cv.top.inst -text {INSTANCE} -width 25 -bg grey60 -anchor w -padx 4 -font $font - label .cv.top.sym -text {SYMBOL} -width 30 -bg grey60 -anchor w -padx 4 -font $font - label .cv.top.sch -text SCHEMATIC -width 45 -bg grey60 -anchor w -padx 4 -font $font - label .cv.top.pad -text { } -bg grey60 -font $font - pack .cv.top.inst -side left -fill x -expand 1 - pack .cv.top.sym .cv.top.sch -side left -fill x - pack .cv.top.pad -side left -fill x - frame .cv.center - set sf [sframe .cv.center] + frame .trav.top + label .trav.top.inst -text {INSTANCE} -width 25 -bg grey60 -anchor w -padx 4 -font $font + label .trav.top.sym -text {SYMBOL} -width 30 -bg grey60 -anchor w -padx 4 -font $font + label .trav.top.sch -text SCHEMATIC -width 45 -bg grey60 -anchor w -padx 4 -font $font + label .trav.top.pad -text { } -bg grey60 -font $font + pack .trav.top.inst -side left -fill x -expand 1 + pack .trav.top.sym .trav.top.sch -side left -fill x + pack .trav.top.pad -side left -fill x + frame .trav.center + set sf [sframe .trav.center] hier_traversal 0 $only_subckts $all_hierarchy xschem set no_draw 0 xschem set no_undo 0 set keep_symbols $save_keep - frame .cv.bottom - label .cv.bottom.status -text {STATUS LINE} - pack .cv.bottom.status -fill x -expand yes - pack .cv.top -side top -fill x -expand no - pack .cv.center -side top -fill both -expand yes - pack .cv.bottom -side top -fill x -expand no - sframeyview .cv.center place - set maxsize [expr {[winfo height ${sf}] + [winfo height .cv.top] + [winfo height .cv.bottom]}] - wm maxsize .cv 9999 $maxsize - bind .cv.center.f {sframeyview .cv.center} - bind .cv { sframeyview .cv.center scroll -0.1} - bind .cv { sframeyview .cv.center scroll 0.1} - bind .cv {destroy .cv} + frame .trav.bottom + label .trav.bottom.status -text {STATUS LINE} + pack .trav.bottom.status -fill x -expand yes + pack .trav.top -side top -fill x -expand no + pack .trav.center -side top -fill both -expand yes + pack .trav.bottom -side top -fill x -expand no + sframeyview .trav.center place + set maxsize [expr {[winfo height ${sf}] + [winfo height .trav.top] + [winfo height .trav.bottom]}] + wm maxsize .trav 9999 $maxsize + bind .trav.center.f {sframeyview .trav.center} + bind .trav { sframeyview .trav.center scroll -0.1} + bind .trav { sframeyview .trav.center scroll 0.1} + bind .trav {destroy .trav} } # recursive procedure @@ -1963,7 +1980,7 @@ proc hier_traversal {{level 0} {only_subckts 0} {all_hierarchy 1}} { } set parent_sch [xschem get current_name] # puts $parent_sch - set sf .cv.center.f.scrl + set sf .trav.center.f.scrl set done_print 0 set schpath [xschem get sch_path] set instances [xschem get instances] @@ -2017,17 +2034,17 @@ proc hier_traversal {{level 0} {only_subckts 0} {all_hierarchy 1}} { " button $sf.f$traversal_cnt.bsch -text {Sch} -padx 4 -borderwidth 1 -pady 0 -font $font \ -command " - if { {$sym_spice_sym_def} eq {} && {$inst_spice_sym_def} eq {}} { + if { [list $sym_spice_sym_def] eq {} && [list $inst_spice_sym_def] eq {}} { xschem load_new_window \[$sf.f$traversal_cnt.s get\] - } elseif {{$sym_spice_sym_def} ne {}} { - editdata {$sym_spice_sym_def} {Symbol spice_sym_def attribute} + } elseif {[list $sym_spice_sym_def] ne {}} { + editdata [list $sym_spice_sym_def] {Symbol spice_sym_def attribute} } else { - editdata {$inst_spice_sym_def} {Instance spice_sym_def attribute} + editdata [list $inst_spice_sym_def] {Instance spice_sym_def attribute} }" if { $sym_spice_sym_def eq {} && $inst_spice_sym_def eq {}} { bind $sf.f$traversal_cnt.s " - traversal_setlabels %W {$parent_sch} $sch_tail {$instname} {$default_sch} \ - {$inst_spice_sym_def} {$sym_spice_sym_def} + traversal_setlabels %W [list $parent_sch] [list $sch_tail] [list $instname] [list $default_sch] \ + [list $inst_spice_sym_def] [list $sym_spice_sym_def] " } traversal_setlabels $sf.f$traversal_cnt.s {} $sch_tail $instname $default_sch \ @@ -7656,7 +7673,7 @@ proc set_sim_netlist_waves_buttons {} { if {![info exists $netlist_var] || [set $netlist_var] eq $simulate_bg} { $top_path.menubar entryconfigure Netlist -background $simulate_bg } else { - $top_path.menubar entryconfigure -background [set $netlist_var] + $top_path.menubar entryconfigure Netlist -background [set $netlist_var] } if {![info exists $sim_var] || [set $sim_var] eq $simulate_bg} { From e77cc334f467c3512d8b91e7e72b7b8cf777c353 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 3 Jan 2025 00:49:54 +0100 Subject: [PATCH 2/8] has_included_subcircuit() and proc has_included_subcircuit: compare and reorder only ports with associated symbol pin. do not consider `extra` ports assigned via attributes --- src/token.c | 5 +++-- src/xschem.tcl | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/token.c b/src/token.c index 18c8454e..8a9bb0b7 100644 --- a/src/token.c +++ b/src/token.c @@ -1848,6 +1848,7 @@ static int has_included_subcircuit(int inst, int symbol, char **result) char *symname = NULL; char *templ = NULL; char *symname_attr = NULL; + int no_of_pins = (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; 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)); @@ -1866,7 +1867,7 @@ static int has_included_subcircuit(int inst, int symbol, char **result) dbg(1, "has_included_subcircuit(): symname=%s\n", symname); strtolower(symname); tclvareval("has_included_subcircuit {", get_cell(symname, 0), "} {", - translated_sym_def, "}", NULL); + translated_sym_def, "} ", my_itoa(no_of_pins), NULL); my_free(_ALLOC_ID_, &templ); my_free(_ALLOC_ID_, &symname_attr); if(tclresult()[0]) { @@ -1875,7 +1876,7 @@ static int has_included_subcircuit(int inst, int symbol, char **result) char *subckt_pinlist_ptr; char *subckt_pinlist = NULL; char *tmp_result = NULL; - int i, no_of_pins = (xctx->inst[inst].ptr + xctx->sym)->rects[PINLAYER]; + int i; int symbol_pins = 0; int instance_pins = 0; Str_hashentry *entry; diff --git a/src/xschem.tcl b/src/xschem.tcl index be857143..4ecd9dd8 100644 --- a/src/xschem.tcl +++ b/src/xschem.tcl @@ -813,7 +813,7 @@ proc tabulate {text {sep ",\t "}} { # get pin ordering from included subcircuit # return empty string if not found. -proc has_included_subcircuit {symname spice_sym_def} { +proc has_included_subcircuit {symname spice_sym_def no_of_pins} { global has_x set include_found 0 regsub -all {\n\+} $spice_sym_def { } spice_sym_def @@ -853,6 +853,13 @@ proc has_included_subcircuit {symname spice_sym_def} { } else { set last [expr {$last -1}] } + # if spice_sym_def has more ports than symbol (no_of_pins) assume these are extra ports + # assigned via attributes ('extra' symbol attribute, usually power rails), these extra + # ports are not returned as @pinlist and correspondence with symbol format string + # is not checked. user must ensure these additional ports are in the right order. + if { $last >= $no_of_pins + 1 } { + set last [expr {$no_of_pins + 1}] + } set pinlist [lrange $line 2 $last] break } @@ -1766,7 +1773,7 @@ proc simconf_add {tool} { proc cellview_setlabels {w sch} { if {[$w get] ne $sch} { if { [file exists [abs_sym_path [$w get]]] } { - $w configure -bg PaleGreen + $w configure -bg green } else { # puts "$sch --- [$sf.f$i.s get]" $w configure -bg red @@ -1823,7 +1830,7 @@ proc cellview {} { if {![file exists $abs_sch]} { $sf.f$i.s configure -bg red } elseif {$default_sch ne $sch} { - $sf.f$i.s configure -bg PaleGreen + $sf.f$i.s configure -bg green } } else { $sf.f$i.s configure -fg red @@ -1900,14 +1907,14 @@ proc traversal_setlabels {w parent_sch sch instname default_sch inst_spice_sym_d if {[$w get] ne $default_sch} { if { $sym_spice_sym_def ne {}} { - $w configure -fg PaleGreen + $w configure -fg green $w configure -bg [option get . background {}] } elseif {$inst_spice_sym_def ne {}} { $w configure -fg red $w configure -bg [option get . background {}] } elseif { [file exists [abs_sym_path [$w get]]] } { $w configure -fg [option get . foreground {}] - $w configure -bg PaleGreen + $w configure -bg green } else { $w configure -fg [option get . foreground {}] $w configure -bg red From 0af6155b5b969db50dd4f734d2e949d96330cd10 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Fri, 3 Jan 2025 11:43:00 +0100 Subject: [PATCH 3/8] add scripts.html manual page --- doc/xschem_man/scripts.html | 96 ++++++++++++++++++++++++++++++++++ doc/xschem_man/simulation.html | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 doc/xschem_man/scripts.html diff --git a/doc/xschem_man/scripts.html b/doc/xschem_man/scripts.html new file mode 100644 index 00000000..531dba39 --- /dev/null +++ b/doc/xschem_man/scripts.html @@ -0,0 +1,96 @@ + + + +SCRIPTS + + + + + + + +
+ + +UP + + +

XSCHEM SCRIPTS


+ +

+ Xschem is a tcl interpreter and as such TCL scripts and commands can be executed. + Xschem adds its own extension commands, mostly with the xschem TCL command. + See this manual page. + The same procedure as tcl is used to load and execute a script: +

     source /path/to/script.tcl
+

+

+ there are various ways to run a script in xschem: +

+
    +
  1. + On the xschem command prompt: +

    source myscript.tcl

    +
  2. + +
  3. + In the xschemrc you may set the tcl_files tcl variable with a list of files + to read in and execute after xschem is started: +

    set tcl_files {/path/to/file1.tcl  /path/to/file2.tcl}

    +
  4. + +
  5. + the postinit_commands variable in xschemrc can be filled with tcl code , + it is executed when starting xschem: +

    set postinit_commands {
    +  puts hello
    +  puts world
    +}
    +    

    +
  6. + +
  7. + On the unix shell command line with --tcl (this code is executed after reading xschemrc, + this is usually done to override xschemrc settings: +

    xschem --tcl 'set intuitive_interface 0'

    +
  8. + +
  9. + On the unix shell command line with --preinit. Same as --tcl, + but the commands are executed + at the very beginning of xschem startup, before reading xschemrc. + Usually done to change some internal variables for testing +

    xschem --preinit 'some_weird_tcl_code'

    +
  10. + +
  11. + On the unix shell command line with --command. + The specified tcl code is executed after complete startup so all extended + xschem commands are available: +

    +xschem solar_panel.sch --command 'simulate'  #there are other ways to do this, just an example
    +    

    +
  12. + +
  13. + + On the unix shell command line with --script. Specify a file to source, + it will be executed after complete startup. +

    xschem --script myscript.tcl

    +
  14. + +
+ + +
+
+ + +