# # File: xschem.tcl # # This file is part of XSCHEM, # a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit # simulation. # Copyright (C) 1998-2024 Stefan Frederik Schippers # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ### INUTILE integration (spice stimuli generator from a higher level description language) proc inutile_line {txtlabel} { global retval toplevel .inutile_line -class Dialog set X [expr [winfo pointerx .inutile_line] - 60] set Y [expr [winfo pointery .inutile_line] - 35] wm geometry .inutile_line "+$X+$Y" wm transient .inutile_line [xschem get topwindow] label .inutile_line.l1 -text $txtlabel entry .inutile_line.e1 -width 60 entry_replace_selection .inutile_line.e1 .inutile_line.e1 delete 0 end .inutile_line.e1 insert 0 $retval button .inutile_line.b1 -text "OK" -command \ { set retval [.inutile_line.e1 get ] destroy .inutile_line } bind .inutile_line { set retval [.inutile_line.e1 get ] destroy .inutile_line } pack .inutile_line.l1 -side top -fill x pack .inutile_line.e1 -side top -fill both -expand yes pack .inutile_line.b1 -side top -fill x grab set .inutile_line focus .inutile_line.e1 tkwait window .inutile_line return $retval } proc inutile_write_data {w f} { set fid [open $f w] set t [$w get 0.0 {end - 1 chars}] puts -nonewline $fid $t close $fid } proc inutile_read_data {w f} { set fid [open $f r] set t [read $fid] $w delete 0.0 end $w insert 0.0 $t close $fid } proc inutile_template {w f} { set fid [open $f r] set t [read $fid] $w insert 0.0 $t close $fid } proc inutile_get_time {} { global netlist_dir regsub {/$} $netlist_dir {} netlist_dir set fileid [open "$netlist_dir/inutile.simulationtime" "RDONLY"] .inutile.buttons.time delete 0 end .inutile.buttons.time insert 0 [read -nonewline $fileid] close $fileid file delete "$netlist_dir/inutile.simulationtime" } proc inutile_alias_window {w filename} { catch {destroy $w} toplevel $w -class Dialog wm title $w "(IN)UTILE ALIAS FILE: $filename" wm iconname $w "ALIAS" # wm transient $w [xschem get topwindow] set fileid [open $filename "RDONLY CREAT"] set testo [read $fileid] close $fileid frame $w.buttons pack $w.buttons -side bottom -fill x -pady 2m text $w.text -undo 1 -relief sunken -bd 2 -yscrollcommand "$w.scroll set" -setgrid 1 \ -height 30 scrollbar $w.scroll -command "$w.text yview" button $w.buttons.dismiss -text Dismiss -command "destroy $w" button $w.buttons.save -text Save -command "inutile_write_data $w.text \"$filename\"" button $w.buttons.load -text Reload -command "inutile_read_data $w.text \"$filename\"" pack $w.buttons.dismiss $w.buttons.save $w.buttons.load -side left -expand 1 pack $w.scroll -side right -fill y pack $w.text -expand yes -fill both $w.text insert 0.0 $testo } proc inutile_help_window {w filename} { catch {destroy $w} toplevel $w -class Dialog wm title $w "(IN)UTILE ALIAS FILE" wm iconname $w "ALIAS" # wm transient $w [xschem get topwindow] frame $w.buttons pack $w.buttons -side bottom -fill x -pady 2m button $w.buttons.dismiss -text Dismiss -command "destroy $w" button $w.buttons.save -text Save -command "inutile_write_data $w.text \"$filename\"" pack $w.buttons.dismiss $w.buttons.save -side left -expand 1 text $w.text -undo 1 -relief sunken -bd 2 -yscrollcommand "$w.scroll set" -setgrid 1 \ -height 30 -width 90 scrollbar $w.scroll -command "$w.text yview" pack $w.scroll -side right -fill y pack $w.text -expand yes -fill both set fileid [open $filename "RDONLY CREAT"] $w.text insert 0.0 [read $fileid] close $fileid } proc inutile_translate {f} { global XSCHEM_SHAREDIR netlist_dir regsub {/$} $netlist_dir {} netlist_dir set p $XSCHEM_SHAREDIR/utile set savedir [pwd] cd $netlist_dir eval exec awk -f $p/preprocess.awk \"$f\" | awk -f $p/expand_alias.awk | awk -f $p/param.awk | awk -f $p/clock.awk | awk -f $p/stimuli.awk cd $savedir } proc inutile { {filename {}} {wait {}} } { global XSCHEM_SHAREDIR retval netlist_dir if {$wait ne {}} { xschem set semaphore [expr {[xschem get semaphore] +1}] } if { ![string compare $filename ""] } then { tk_messageBox -type ok -message "Please give a file name as argument" return } toplevel .inutile -class Dialog wm title .inutile "(IN)UTILE (Stefan Schippers, sschippe)" wm iconname .inutile "(IN)UTILE" # wm transient .inutile [xschem get topwindow] set utile_path $XSCHEM_SHAREDIR/utile set retval {} frame .inutile.buttons pack .inutile.buttons -side bottom -fill x -pady 2m button .inutile.buttons.translate -text Translate -command " inutile_write_data .inutile.text \"$filename\" inutile_translate \"$filename\" inutile_get_time" button .inutile.buttons.dismiss -text Dismiss -command "destroy .inutile" button .inutile.buttons.code -text "Help" -command "inutile_help_window .inutile.help $utile_path/utile.txt" text .inutile.text -undo 1 -relief sunken -bd 2 -yscrollcommand ".inutile.scroll set" -setgrid 1 -height 30 scrollbar .inutile.scroll -command {.inutile.text yview} button .inutile.buttons.save -text Save -command " set retval \"$filename\" set filename \[inutile_line {Filename}\] inutile_write_data .inutile.text \"$filename\"" button .inutile.buttons.load -text Reload -command " set retval \"$filename\" set filename \[inutile_line {Filename}\] inutile_read_data .inutile.text \"$filename\"" button .inutile.buttons.send -text "Template" -command " if { !\[string compare \[.inutile.text get 0.0 {end - 1 chars}\] {}\]} { inutile_template .inutile.text $utile_path/template.stimuli}" label .inutile.buttons.timelab -text "time:" entry .inutile.buttons.time -width 11 entry_replace_selection .inutile.buttons.time pack .inutile.buttons.dismiss .inutile.buttons.code \ .inutile.buttons.load .inutile.buttons.save .inutile.buttons.translate \ .inutile.buttons.send .inutile.buttons.timelab \ .inutile.buttons.time -side left -expand 1 pack .inutile.scroll -side right -fill y pack .inutile.text -expand yes -fill both if { [file exists $filename] } { set fileid [open $filename "RDONLY"] .inutile.text insert 0.0 [read $fileid] close $fileid } set tmp [.inutile.text index end] regsub {\..*$} $tmp {} lines for {set i 1} {$i <= $lines} {incr i} { set tmp [.inutile.text get $i.0 "$i.0 lineend"] if [regexp {^(include)|(\.include)} $tmp ] { inutile_alias_window .inutile.tw$i [lindex $tmp 1] } } if {$wait ne {}} { tkwait window .inutile xschem set semaphore [expr {[xschem get semaphore] -1}] } } ### End INUTILE integration ### for tclreadline: disable customcompleters proc completer { text start end line } { return {}} # set 'var' with '$val' if 'var' not existing proc set_ne { var val } { upvar #0 $var v if { ![info exists v ] } { set v $val } } # $execute(id) is an integer identifying the last running pipeline # set id $execute(id) to get the current subprocess id in variable 'id' # $execute(status,$id) contains the status argument as given in proc execute # $execute(pipe,$id) contains the channel descriptor to read or write as specified in status # $execute(data,$id) contains the stdout of the pipeline (output data) # $execute(cmd,$id) contains the pipeline command # $execute(win_path,$id) contains the xctx->current_win_path that started the command # $execute(exitcode,id) contains the exit code. This variable will not be deleted at the end # when subprocess ends all execute(...,$id) data is cleared (except execute(exitcode,id) # # The following post-mortem data is available for last finished process: # execute(cmd,last) : the command # execute(win_path,last): the xctx->current_win_path that started the last command # execute(data,last) : the data # execute(error,last) : the errors (stderr) # execute(status,last) : the status argument as was given when calling proc execute # execute(exitcode,last): exit code of last finished process # # execute service function proc execute_fileevent {id} { global execute OS has_x errorCode append execute(data,$id) [read $execute(pipe,$id) 1024] if { $OS != {Windows} } { set eof [eof $execute(pipe,$id)] # handle processes that close stdout. Read pipe will go into eof condition # but process is still running. Doing a close operation in blocking mode # will block execution until process exits. # In this situation we avoid setting pipe to blocking mode and do an # asynchronous close. We lose exit status and stderr though, but # avoid the program to freeze waiting for process to exit. set lastproc [lindex [pid $execute(pipe,$id)] end] set ps_status [exec ps -o state= -p $lastproc] set finished [regexp Z $ps_status] ;# if zombie consider process to be finished. if { $eof && !$finished} { after 2000 "execute_fileevent $id" fileevent $execute(pipe,$id) readable "" # puts "rescheduling $id" return } } else { set eof [eof $execute(pipe,$id)] set finished 1 } if {$eof} { set report [regexp {1} $execute(status,$id)] fileevent $execute(pipe,$id) readable "" # setting pipe to blocking before closing allows to get pipeline exit status # do not ask status for processes that close stdout/stderr, as eof might # occur before process ends and following close blocks until process terminates. if {$finished} {fconfigure $execute(pipe,$id) -blocking 1} set exit_status 0 set catch_return [eval catch [list {close $execute(pipe,$id)} err] ] # puts "catch_return=$catch_return" if {$catch_return} { # puts "errorCode=$errorCode" if {"NONE" == [lindex $errorCode 0]} { set exit_status 0 } elseif {"CHILDSTATUS" == [lindex $errorCode 0]} { set exit_status [lindex $errorCode 2] # puts "exit_status=$exit_status" } else { set exit_status $catch_return } if {$exit_status != 0} { if {$report} {viewdata "Failed: $execute(cmd,$id)\nstderr:\n$err\ndata:\n$execute(data,$id)"} } else { if {$report} {viewdata "Completed: $execute(cmd,$id)\nstderr:\n$err\ndata:\n$execute(data,$id)"} } } else { if {$report} {viewdata "Completed: $execute(cmd,$id)\ndata:\n$execute(data,$id)"} } set execute(exitcode,last) $exit_status set execute(exitcode,$id) $exit_status set execute(cmd,last) $execute(cmd,$id) set execute(win_path,last) $execute(win_path,$id) set execute(data,last) $execute(data,$id) if { ![info exists err] } { set err {} } set execute(error,last) $err set execute(status,last) $execute(status,$id) if { [info exists tctx::$execute(win_path,$id)_simulate_id] } { if { [set tctx::$execute(win_path,$id)_simulate_id] eq $id } { unset tctx::$execute(win_path,$id)_simulate_id } } if {[info exists execute(callback,$id)] && $execute(callback,$id) ne {}} { # puts $execute(callback,$id) # puts $execute(win_path,$id) eval uplevel #0 [list $execute(callback,$id)] } catch {unset execute(callback,$id)} if { ![info exists exit_status] } { set exit_status 0 } unset execute(pipe,$id) unset execute(data,$id) unset execute(status,$id) unset execute(cmd,$id) unset execute(win_path,$id) # apply a delay, process does not disappear immediately. if {[info exists has_x] && [winfo exists .processlist]} { after 250 {insert_running_cmds .processlist.f2.lb}} } } proc execute_wait {status args} { global execute set id [eval execute $status $args] if {$id == -1} { return -1 } xschem set semaphore [expr {[xschem get semaphore] +1}] vwait execute(pipe,$id) xschem set semaphore [expr {[xschem get semaphore] -1}] return $id } # equivalent to the 'exec' tcl function but keeps the event loop # responding, so widgets get updated properly # while waiting for process to end. # status: # rw open pipe in 'r+' (read write) mode instead of 'r' # line set line buffering mode of channel # none set no channel buffering. # 1 get status report at process end # 0 no status report # # These options can be combined as in '1rwline' of '1rnone' # proc execute {status args} { global execute has_x if {![info exists execute(id)]} { set execute(id) 0 } else { incr execute(id) } set id $execute(id) if { [info exists execute(callback)] } { set execute(callback,$id) $execute(callback) unset execute(callback) } set mode r if {[regexp {rw} $status]} { set mode r+ } if { [catch {open "|$args" $mode} err] } { puts stderr "Proc execute error: $err" if { [info exists has_x]} { tk_messageBox -message \ "Can not execute '$args': ensure it is available on the system. Error: $err" \ -icon error -parent [xschem get topwindow] -type ok } return -1 } else { set pipe $err } set execute(status,$id) $status set execute(pipe,$id) $pipe set execute(cmd,$id) $args set execute(win_path,$id) [xschem get current_win_path] set execute(data,$id) "" # Apply a delay to catch the new process. if {[info exists has_x] && [winfo exists .processlist]} { after 250 {insert_running_cmds .processlist.f2.lb}} fconfigure $pipe -blocking 0 if {[regexp {line} $status]} { fconfigure $pipe -buffering line } if {[regexp {none} $status]} { fconfigure $pipe -buffering none } fileevent $pipe readable "execute_fileevent $id" return $id } # kill selected sub-processes by looking up their command strings # into all running sub-processes, killing the matching ones # with the supplied 'sig'. proc kill_running_cmds {{lb {}} sig} { global execute if { [regexp {^[0-9]+$} $lb] && $lb >= 0 } { set id $lb if { [info exists execute(pipe,$id)] } { set pid [pid $execute(pipe,$id)] exec kill $sig $pid } else { return 0 } } else { set selected [$lb curselection] foreach idx $selected { set cmd1 [$lb get $idx] foreach {id pid cmd2} [get_running_cmds] { # puts "$cmd1\n$cmd2 \n$pid" if { $cmd1 eq $cmd2 } { exec kill $sig $pid break } } } after 250 insert_running_cmds $lb } # apply a delay, after a kill command process does not disappear # immediately. return 1 } # refresh list of running commands in dialog box proc insert_running_cmds {lb} { $lb delete 0 end foreach {id pid cmd} [get_running_cmds] { # puts "inserting $cmd" $lb insert end $cmd } } # periodically update status proc update_process_status {lb} { global execute has_x set exists 0 set selected [$lb curselection] if { ![info exists has_x]} {return} if { [winfo exists .pstat] } { set pos [lindex [.pstat.text yview] 1] if {$pos == 1} { if { $selected ne {} && [llength $selected] == 1} { .pstat.text delete 1.0 end set idx $selected set cmd1 [$lb get $idx] foreach {id pid cmd2} [get_running_cmds] { if { $cmd1 eq $cmd2 } { if {[catch { set t $execute(data,$id) } err]} { set t $err } .pstat.text insert 1.0 $t .pstat.text yview moveto 1 break } } } } after 1000 "update_process_status $lb" } else { after cancel "update_process_status $lb" } } # display stdout of selected sub-process proc view_process_status {lb} { global execute has_x set exists 0 if {![info exists has_x]} {return} if {[winfo exists .pstat] } { .pstat.text delete 1.0 end set exists 1 } set selected [$lb curselection] if {$selected ne {} && [llength $selected] == 1} { set idx $selected set cmd1 [$lb get $idx] foreach {id pid cmd2} [get_running_cmds] { if { $cmd1 eq $cmd2 } { if {[catch { set t $execute(data,$id) } err]} { set t $err } if {$exists == 0} { viewdata $t ro .pstat } else { .pstat.text insert 1.0 $t } .pstat.text yview moveto 1 break } } } after 1000 "update_process_status $lb" } # top level dialog displaying running sub-processes proc list_running_cmds {} { global has_x set top .processlist if {![info exists has_x]} {return} if {[winfo exists $top]} {return} toplevel $top -class Dialog # wm transient $top [xschem get topwindow] set frame1 $top.f1 set frame2 $top.f2 set frame3 $top.f3 frame $frame1 frame $frame2 frame $frame3 set lb $frame2.lb listbox $lb -width 70 -height 8 -selectmode extended \ -yscrollcommand "$frame2.yscroll set" \ -xscrollcommand "$frame2.xscroll set" scrollbar $frame2.yscroll -command "$lb yview" scrollbar $frame2.xscroll -orient horiz -command "$lb xview" pack $frame2.yscroll -side right -fill y pack $frame2.xscroll -side bottom -fill x pack $lb -side bottom -fill both -expand true bind $lb [list $frame3.b3 invoke] button $frame3.b1 -width 16 -text {Terminate selected} -command "kill_running_cmds $lb -15" \ -fg black -background yellow button $frame3.b2 -width 16 -text {Kill selected} -command "kill_running_cmds $lb -9" \ -fg black -background red button $frame3.b3 -width 16 -text {View status} -command "view_process_status $lb" \ -fg black -background PaleGreen button $frame3.b4 -width 16 -text {Dismiss} \ -fg black -background PaleGreen -command " if {\[winfo exists .pstat\]} { after cancel [list update_process_status $lb] destroy .pstat } destroy $top " pack $frame3.b1 $frame3.b2 $frame3.b3 $frame3.b4 -side left -fill x -expand 1 pack $frame1 -fill x -expand 0 pack $frame2 -fill both -expand 1 pack $frame3 -fill x -expand 0 insert_running_cmds $lb } # for each running sub-process return a list of three elements per process: # the integer id, the process PID, the command string. proc get_running_cmds {} { global execute set ret {} foreach i [array names execute *pipe*] { set id [lindex [split $i ,] 1] lappend ret $id [pid $execute($i)] $execute(cmd,$id) } return $ret } # pause for $del_ms milliseconds, keep event loop responsive proc delay {del_ms} { global delay_flag after $del_ms {set delay_flag 1} vwait delay_flag unset delay_flag } #### Scrollable frame proc sframeyview {container args} { global ${container}_vpos ;# global to remember scrollbar position set_ne ${container}_vpos 0 if {[lindex $args 0] eq {place}} { place ${container}.f.scrl -in $container.f -x 0 -y 0 -relwidth 1 update ;# without this vpos of scrollbar will not be remembered when reopening toplevel } set ht [winfo height $container.f] set hs [winfo height $container.f.scrl] set frac [expr {double($ht)/$hs}] if { [lindex $args 0] eq {scroll}} { ;# mouse wheel set ${container}_vpos [expr {[set ${container}_vpos] + [lindex $args 1] *(1.0/$frac)/5}] } elseif { [lindex $args 0] eq {moveto}} { ;# scrollbar slider set ${container}_vpos [lindex $args 1] } if { [set ${container}_vpos] < 0.0 } {set ${container}_vpos 0.0} if { [set ${container}_vpos] > 1.0 - $frac } {set ${container}_vpos [expr {1.0 - $frac}]} $container.vs set [set ${container}_vpos] [expr {[set ${container}_vpos] + $frac}] place $container.f.scrl -in $container.f -x 0 -y [expr {-$hs * [set ${container}_vpos]}] -relwidth 1.0 } # scrollable frame constructor proc sframe {container} { frame $container.f scrollbar $container.vs -command "sframeyview $container" ;# sframeyview moveto commands frame $container.f.scrl pack $container.f -expand yes -fill both -side left pack $container.vs -expand yes -fill y return $container.f.scrl } #### /Scrollable frame ## convert engineering form to number proc from_eng {i} { set str {} scan $i "%g%s" n str set str [string tolower $str] if { [regexp {^meg} $str] } { set str {meg} } else { set suffix [string index $str 0] } set mult [switch $suffix { a { expr {1e-18}} f { expr {1e-15}} p { expr {1e-12}} n { expr { 1e-9}} u { expr {1e-6}} m { expr {1e-3}} k { expr {1e3}} meg { expr {1e6}} g { expr {1e9}} t { expr {1e12}} default { expr {1.0}} }] return [expr {$n * $mult}] } ## convert number to engineering form proc to_eng {args} { set suffix {} set i [uplevel #0 expr [join $args]] set absi [expr {abs($i)}] if {$absi == 0.0} { set mult 1 ; set suffix {} } elseif {$absi >=1e12} { set mult 1e-12; set suffix T } elseif {$absi >=1e9} { set mult 1e-9 ; set suffix G } elseif {$absi >=1e6} { set mult 1e-6 ; set suffix M } elseif {$absi >=1e3} { set mult 1e-3 ; set suffix k } elseif {$absi >=0.1} { set mult 1 ; set suffix {} } elseif {$absi >=1e-3} { set mult 1e3 ; set suffix m } elseif {$absi >=1e-6} { set mult 1e6 ; set suffix u } elseif {$absi >=1e-9} { set mult 1e9 ; set suffix n } elseif {$absi >=1e-12} { set mult 1e12 ; set suffix p } elseif {$absi >=1e-15} { set mult 1e15 ; set suffix f } else { set mult 1e18 ; set suffix a} if {$suffix ne {}} { set i [expr {$i * $mult}] set s [format {%.5g%s} $i $suffix] } else { set s [format {%.5g} $i] } return $s } ## evaluate expression with 7 significant digits. ## if expression has errors or does not evaluate return expression as is proc ev7 {args} { set i [join $args] if {![catch {uplevel #0 expr $i} res]} { return [format %.7g $res] } else { # puts stderr "proc ev: $res" return $args } } ## evaluate expression. if expression has errors or does not evaluate return expression as is proc ev {args} { set i [join $args] if {![catch {uplevel #0 expr $i} res]} { return [format %.4g $res] } else { # puts stderr "proc ev: $res" return $args } } ## evaluate expression. if expression has errors or does not evaluate return 0 proc ev0 {args} { set i [join $args] if {![catch {uplevel #0 expr $i} res]} { return [format %.4g $res] } else { # puts stderr "proc ev0: $res" return 0 } } # return "$n * $indent" spaces proc spaces {n {indent 4}} { set n [expr {$n * $indent}] # return [format %${n}s {}] return [string repeat { } $n] } # wraps provided table formatted text into a nice looking bordered table # sep is the list of characters used as separators, default are { }, {,}, {\t} # if you want to tabulate data with spaces use only {,} as separator or any other character. proc tabulate {text {sep ",\t "}} { # define table characters set top {┌ ─ ┬ ┐} set row {│ { } │ │} set mid {├ ─ ┼ ┤} set head {╞ ═ ╪ ╡} set bot {└ ─ ┴ ┘} # used_sep (first character of sep) will be used as separator after text cleanup set used_sep [string range $sep 0 0] set sep "\[$sep\]" set maxcols 0 ;# max number of columns set nlines 0 ;# number of data lines set chopped_text {} set found_data 0 foreach line [split $text \n] { # skip completely empty lines if {[regexp {^$} $line]} { continue} # skip leading lines with no data (only separators) if {!$found_data && [regexp ^${sep}*\$ $line]} { continue } set found_data 1 # change separators to { } regsub -all $sep $line $used_sep line # transform resulting line into a proper list set line [split $line $used_sep] incr nlines set ncols 0 # calculate max field width and number of columns foreach field $line { incr ncols if {![info exists maxlen($ncols)]} {set maxlen($ncols) 0} if {$ncols > $maxcols} {set maxcols $ncols} set len [string length $field] if {$len > $maxlen($ncols)} { set maxlen($ncols) $len} } if { $chopped_text ne {}} {append chopped_text \n} append chopped_text $line } set table {} set l 0 foreach line [split $chopped_text \n] { incr l # top table border set rowsep {} if {$l == 1} { append rowsep [lindex $top 0] set c 0 for {set i 0} {$i < $maxcols} { incr i} { set field [lindex $line $i] incr c append rowsep [string repeat [lindex $top 1] $maxlen($c)] if { $c == $ncols} { append rowsep [lindex $top 3] } else { append rowsep [lindex $top 2] } } append table $rowsep \n } else { append table \n } set rowsep {} append table [lindex $row 0] if { $l == $nlines} { append rowsep [lindex $bot 0] } elseif {$l == 1} { append rowsep [lindex $head 0] } else { append rowsep [lindex $mid 0] } set c 0 for {set i 0} {$i < $maxcols} { incr i} { set field [lindex $line $i] incr c set pad [expr {$maxlen($c) - [string length $field]}] append table $field [string repeat { } $pad] if { $l == $nlines} { append rowsep [string repeat [lindex $bot 1] $maxlen($c)] } elseif {$l == 1} { append rowsep [string repeat [lindex $head 1] $maxlen($c)] } else { append rowsep [string repeat [lindex $mid 1] $maxlen($c)] } if { $c == $ncols} { append table [lindex $row 3] if { $l == $nlines} { append rowsep [lindex $bot 3] } elseif {$l == 1} { append rowsep [lindex $head 3] } else { append rowsep [lindex $mid 3] } } else { append table [lindex $row 2] if { $l == $nlines} { append rowsep [lindex $bot 2] } elseif { $l == 1} { append rowsep [lindex $head 2] } else { append rowsep [lindex $mid 2] } } } append table \n $rowsep } return $table } # get pin ordering from included subcircuit # return empty string if not found. 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 # puts "has_included_subcircuit: spice_sym_def=$spice_sym_def" set pinlist {} # .include? get the file ... if {[regexp -nocase {^[ \t\n]*\.include +} $spice_sym_def]} { regsub -nocase {^[ \t\n]*\.include +} $spice_sym_def {} filename regsub -all {^"|"$} $filename {} filename ;# remove double quotes at beginning and end regsub -all {^\n*|\n*$} $filename {} filename ;# remove newlines at beginning and end set filename [abs_sym_path $filename] # puts "filename=$filename" set res [catch {open $filename r} fd] if { $res } { puts "has_included_subcircuit: error opening file $filename: $fd" if { [info exists has_x] } {alert_ "has_included_subcircuit: error opening file $filename: $fd"} return $pinlist } set spice_sym_def [read -nonewline $fd] close $fd regsub -all {\n\+} $spice_sym_def { } spice_sym_def } # ... or use the attribute value as *the* subcircuit # split lines set spice_sym_def [split $spice_sym_def \n] foreach line $spice_sym_def { # get 1st line with a matching .subckt. This is our subcircuit definition, get the pin order if {[string tolower [lindex $line 0]] eq {.subckt} && [string tolower [lindex $line 1]] eq $symname} { set include_found 1 regsub -all { *= *} $line {=} line # pin list ends where parameter assignment begins (param=value) set last [lsearch -regexp [string tolower $line] {=|param:}] if {$last == -1} { set last [expr {[llength $line] -1}] } 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 } } # return pinlist as found in the .subckt line or empty string if not found if {!$include_found} { puts "has_included_subcircuit: $symname: no matching .subckt found in spice_sym_def. Ignore" if { [info exists has_x] } { alert_ "has_included_subcircuit: $symname: no matching .subckt found in spice_sym_def. Ignore" } } # puts $pinlist return [string tolower [join $pinlist]] } # should not be called directly by user # does netlist post processing, called from global_(spice|vhdl|verilog)_netlist() proc netlist {source_file show netlist_file} { global XSCHEM_SHAREDIR flat_netlist netlist_dir simulate_bg global verilog_2001 debug_var OS has_x verilog_bitblast regsub {/$} $netlist_dir {} netlist_dir # if waves are loaded turn Waves button to orange to indicate old waves are shown set win_path [xschem get current_win_path] set top_path [xschem get top_path] set waves_var tctx::${win_path}_waves if {[info exists has_x] && $waves_var ne $simulate_bg} { set $waves_var orange $top_path.menubar entryconfigure Waves -background orange } set netlist_type [xschem get netlist_type] if {$debug_var <= -1} { puts "netlist: source_file=$source_file, netlist_type=$netlist_type" } set dest $netlist_dir/$netlist_file if {$netlist_type eq {spice}} { if { [sim_is_xyce] } { set xyce {-xyce} } else { set xyce {} } set cmd ${XSCHEM_SHAREDIR}/spice.awk set brk ${XSCHEM_SHAREDIR}/break.awk set flatten ${XSCHEM_SHAREDIR}/flatten.awk if {$flat_netlist==0} { eval exec {awk -f $cmd -- $xyce $source_file | awk -f $brk > $dest} } else { eval exec {awk -f $cmd -- $xyce $source_file | awk -f $flatten | awk -f $brk > $dest} } if ![string compare $show "show"] { textwindow $dest } } if {$netlist_type eq {vhdl}} { set cmd $XSCHEM_SHAREDIR/vhdl.awk eval exec {awk -f $cmd $source_file > $dest} if ![string compare $show "show"] { textwindow $dest } } if {$netlist_type eq {tedax}} { set cmd1 $XSCHEM_SHAREDIR/tedax.awk set cmd2 $XSCHEM_SHAREDIR/flatten_tedax.awk if {[catch {eval exec {awk -f $cmd1 $source_file | awk -f $cmd2 > $dest} } err] } { puts stderr "tEDAx errors: $err" } if ![string compare $show "show"] { textwindow $dest } } if {$netlist_type eq {verilog}} { set cmd ${XSCHEM_SHAREDIR}/verilog.awk if { $verilog_bitblast == 1 } { eval exec {awk -f $cmd -- -bitblast $source_file > $dest} } else { eval exec {awk -f $cmd $source_file > $dest} } if { $verilog_2001==1 } { set cmd ${XSCHEM_SHAREDIR}/convert_to_verilog2001.awk set interm ${dest}[pid] eval exec {awk -f $cmd $dest > $interm} file rename -force $interm $dest } if ![string compare $show "show"] { textwindow "$dest" } } return {} } # 20161121 proc convert_to_pdf {filename dest} { global to_pdf OS execute if { [regexp -nocase {\.pdf$} $dest] } { set pdffile [file rootname $filename].pdf # puts "---> cmd=$to_pdf filename=$filename pdffile=$pdffile dest=$dest" if {$OS == "Windows"} { set cmd "exec $to_pdf \$pdffile \$filename" if { ![catch {eval $cmd} msg] } { file rename -force $pdffile $dest # ps2pdf succeeded, so remove original .ps file if { ![xschem get debug_var] } { file delete $filename } } else { puts stderr "problems converting postscript to pdf: $msg" } } else { ;# OS == unix eval execute_wait 0 $to_pdf [list $filename $pdffile] if {$execute(status,last) == 0} { file rename -force $pdffile $dest if { ![xschem get debug_var] } { file delete $filename } } } } else { file rename -force $filename $dest } } # 20161121 proc convert_to_png {filename dest} { global to_png debug_var OS # puts "---> $to_png $filename $dest" set cmd "exec $to_png \$filename png:\$dest" if {$OS == "Windows"} { set cmd "exec $to_png \$dest \$filename" } if { ![catch {eval $cmd} msg] } { # conversion succeeded, so remove original .xpm file if { ![xschem get debug_var] } { file delete $filename } } else { puts stderr "problems converting xpm to png: $msg" } } # always specify Shift- modifier for capital letters # see tk 'man keysyms' for key names # example format for s, d: Control-Alt-Key-asterisk # Control-Shift-Key-A # Alt-Key-c # ButtonPress-4 # proc key_binding { s d { topwin {} } } { regsub {.*-} $d {} key switch $key { Insert { set keysym 65379 } Escape { set keysym 65307 } Return { set keysym 65293 } Delete { set keysym 65535 } F1 { set keysym 65470 } F2 { set keysym 65471 } F3 { set keysym 65472 } F4 { set keysym 65473 } F5 { set keysym 65474 } F6 { set keysym 65475 } F7 { set keysym 65476 } F8 { set keysym 65477 } F9 { set keysym 65478 } F10 { set keysym 65479 } F11 { set keysym 65480 } F12 { set keysym 65481 } BackSpace { set keysym 65288 } default { set keysym [scan "$key" %c] } } set state 0 # not found any portable way to get modifier constants ... if { [regexp {(Mod1|Alt)-} $d] } { set state [expr {$state +8}] } if { [regexp Control- $d] } { set state [expr {$state +4}] } if { [regexp Shift- $d] } { set state [expr {$state +1}] } if { [regexp ButtonPress-1 $d] } { set state [expr {$state +0x100}] } if { [regexp ButtonPress-2 $d] } { set state [expr {$state +0x200}] } 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" } else { if {![string compare $d {} ] } { # puts "bind .drw <${s}> {}" bind $topwin.drw "<${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" } } } proc edit_file {filename} { global editor # since $editor can be an executable with options (gvim -f) I *need* to use eval eval execute 0 $editor $filename return {} } # ============================================================ # SIMULATION CONTROL # ============================================================ # ============================================================ # SIMCONF # ============================================================ ## $N : netlist file full path (/home/schippes/simulations/opamp.spice) ## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp) ## $s : schematic name (opamp) ## $d : netlist directory ## ## Other global vars: ## netlist_dir ## terminal ## netlist_type can be obtained with [xschem get netlist_type] proc save_sim_defaults {f} { global sim netlist_dir terminal regsub {/$} $netlist_dir {} netlist_dir set a [catch {open $f w} fd] if { $a } { puts "save_sim_defaults: error opening file $f: $fd" return } puts $fd {# set the list of tools known to xschem} puts $fd {# Note that no spaces are allowed around commas in array keys} puts $fd "set sim(tool_list) {$sim(tool_list)}" puts $fd {} foreach tool $sim(tool_list) { puts $fd "#Specify the number of configured $tool tools." puts $fd "set sim($tool,n) $sim($tool,n) ;# number of configured $tool tools" puts $fd "# Specify the default $tool tool to use (first=0)" puts $fd "set sim($tool,default) $sim($tool,default) ;# default $tool tool to launch" puts $fd {} for {set i 0} {$i < $sim($tool,n)} { incr i} { puts $fd "# specify tool command (cmd), name (name), if tool must run\ in foreground and if exit status must be reported" puts $fd "set sim($tool,$i,cmd) {$sim($tool,$i,cmd)}" puts $fd "set sim($tool,$i,name) {$sim($tool,$i,name)}" puts $fd "set sim($tool,$i,fg) $sim($tool,$i,fg)" puts $fd "set sim($tool,$i,st) $sim($tool,$i,st)" puts $fd {} } puts $fd {} } close $fd } proc load_recent_file {} { global USER_CONF_DIR recentfile has_x # recent files set recentfile {} if { [file exists $USER_CONF_DIR/recent_files] } { if {[catch { source $USER_CONF_DIR/recent_files } err] } { puts "Problems opening recent_files: $err" if {[info exists has_x]} { tk_messageBox -message "Problems opening recent_files: $err" \ -icon warning -parent . -type ok } } foreach i [info vars c_toolbar::c_t_*] { if {[set ${i}(w)] != $c_toolbar::c_t(w) || [set ${i}(n)] != $c_toolbar::c_t(n)} { array unset $i } } set hash $c_toolbar::c_t(hash) if { [info exists c_toolbar::c_t_$hash]} { array set c_toolbar::c_t [array get c_toolbar::c_t_$hash] } } } proc update_recent_file {f {topwin {} } } { global recentfile has_x # puts "update recent file, f=$f, topwin=$topwin" set old $recentfile set recentfile {} lappend recentfile $f foreach i $old { if {[abs_sym_path $i] ne [abs_sym_path $f]} { lappend recentfile [abs_sym_path $i] } } # tcl8.4 errors if using lreplace past the last element if { [llength $recentfile] > 10 } { set recentfile [lreplace $recentfile 10 end] } write_recent_file if { [info exists has_x] } {setup_recent_menu $topwin} } proc write_recent_file {} { global recentfile USER_CONF_DIR # puts "write recent file recentfile=$recentfile" set a [catch {open $USER_CONF_DIR/recent_files w} fd] if { $a } { puts "write_recent_file: error opening file $f: $fd" return } puts $fd "set recentfile {$recentfile}" if {[info exists c_toolbar::c_t]} { set hash $c_toolbar::c_t(hash) set c_toolbar::c_t(time) [clock seconds] array set c_toolbar::c_t_$hash [array get c_toolbar::c_t] foreach i [info vars c_toolbar::c_t_*] { ## old (~3 months) recent components will expire if { [info exists [subst $i](time)]} { if { [clock seconds] - [set [subst $i](time)] < 7500000} { puts $fd "array set $i {[array get $i]}" } # puts "Age: [expr {[clock seconds] - [set [subst $i](time)]}]" } } } close $fd } proc setup_recent_menu { { topwin {} } } { global recentfile $topwin.menubar.file.recent delete 0 9 set i 0 if { [info exists recentfile] } { foreach i $recentfile { $topwin.menubar.file.recent add command \ -command "xschem load -gui {$i}" \ -label [file tail $i] } } } ## ngspice:: raw file access functions namespace eval ngspice { # Create a variable inside the namespace variable ngspice_data variable op_point_read } proc ngspice::get_current {n} { set raw_level [xschem get raw_level] set path [string range [xschem get sch_path] 1 end] # skip hierarchy components above the level where raw file has been loaded. # node path names to look up in raw file begin from there. if { [xschem get currsch] < $raw_level} { return {}} set skip 0 while { $skip < $raw_level } { regsub {^[^.]*\.} $path {} path incr skip } set n [string tolower $n] set prefix $n # if xm1.rd is given get prefix (r) by removing path components (xm1.) regsub {.*\.} $prefix {} prefix set prefix [string range $prefix 0 0] # puts "ngspice::get_current: path=$path n=$n prefix=$prefix" set n $path$n set currname i if { ![sim_is_xyce] } { ;# ngspice if {$path ne {} } { set n $prefix.$n } if { ![regexp $prefix {[ve]}] } { set n @$n } set n i($n) } else { ;# xyce if { [regexp {\[i[bcedgsb]\]$} $n] } { regexp {\[(i[bcesdgb])\]$} $n curr1 currname if { $prefix == {d} } {set currname i} regsub {\[(i[bcesdgb])\]$} $n {} n } regsub {\[i\]} $n {} n set n $currname\($n\) } # puts "ngspice::get_current --> $n" set err [catch {set ngspice::ngspice_data($n)} res] if { $err } { set res {?} } # puts "$n --> $res" return $res } proc ngspice::get_diff_voltage {n m} { set raw_level [xschem get raw_level] set path [string range [xschem get sch_path] 1 end] if { [xschem get currsch] < $raw_level} { return {}} # skip hierarchy components above the level where raw file has been loaded. # node path names to look up in raw file begin from there. set skip 0 while { $skip < $raw_level } { regsub {^[^.]*\.} $path {} path incr skip } set n [string tolower $n] set m [string tolower $m] set nn $path$n set mm $path$m set errn [catch {set ngspice::ngspice_data($nn)} resn] if {$errn} { set nn v(${path}${n}) set errn [catch {set ngspice::ngspice_data($nn)} resn] } set errm [catch {set ngspice::ngspice_data($mm)} resm] if {$errm} { set mm v(${path}${m}) set errm [catch {set ngspice::ngspice_data($mm)} resm] } if { $errn || $errm} { set res {?} } return $res } proc ngspice::get_voltage {n} { set raw_level [xschem get raw_level] set path [string range [xschem get sch_path] 1 end] if { [xschem get currsch] < $raw_level} { return {}} # skip hierarchy components above the level where raw file has been loaded. # node path names to look up in raw file begin from there. set skip 0 while { $skip < $raw_level } { regsub {^[^.]*\.} $path {} path incr skip } set n [string tolower $n] # puts "ngspice::get_voltage: path=$path n=$n" set node $path$n # puts "ngspice::get_voltage: trying $node" set err [catch {set ngspice::ngspice_data($node)} res] if {$err} { set node v(${path}${n}) # puts "ngspice::get_voltage: trying $node" set err [catch {set ngspice::ngspice_data($node)} res] } if { $err } { set res {?} } return $res } proc update_schematic_header {} { global retval set retval [xschem get header_text] text_line {Header/License text:} 0 if { $tctx::rcode ne {}} { xschem set header_text $retval } } proc ngspice::get_node {n} { set raw_level [xschem get raw_level] set path [string range [xschem get sch_path] 1 end] if { [xschem get currsch] < $raw_level} { return {}} # skip hierarchy components above the level where raw file has been loaded. # node path names to look up in raw file begin from there. set skip 0 while { $skip < $raw_level } { regsub {^[^.]*\.} $path {} path incr skip } set n [string tolower $n] # n may contain $path, so substitute its value set n [ subst -nocommand $n ] set err [catch {set ngspice::ngspice_data($n)} res] if { $err } { set res {?} } return $res } ## end ngspice:: functions # test if currently set simulator is ngspice proc sim_is_ngspice {} { global sim set_sim_defaults if { [info exists sim(spice,default)] } { set idx $sim(spice,default) if { [regexp {ngspice} $sim(spice,$idx,cmd)] } { return 1 } } return 0 } # test if currently set simulator is Xyce proc sim_is_Xyce {} { return [sim_is_xyce] } proc sim_is_xyce {} { global sim set_sim_defaults if { [info exists sim(spice,default)] } { set idx $sim(spice,default) if { [regexp {[xX]yce} $sim(spice,$idx,cmd)] } { return 1 } } return 0 } # tests if file f exists. One level of global scope 'subst' is done on f # to expand global variables / commands catching errors. # example: # % set b {$env(HOME)/.bashrc} # $env(HOME)/.bashrc # % file_exists $b # 1 # % # % # % set b {$env(HOMExx)/.bashrc} # $env(HOMExx)/.bashrc # % file_exists $b # 0 # % proc file_exists {f} { set ret 0 set r [catch "uplevel #0 {subst $f}" res] if {$r == 0} { if {[file exists $res]} { set ret 1} } return $ret } # wrapper to "xschem list_tokens" comand to handle non list results # usually as a result of malformed input strings proc list_tokens {s} { set res [xschem list_tokens $s 0] if { [info tclversion] > 8.4 } { if { [string is list $res]} { return $res } else { return [split $res] } } else { if {![catch {llength $res}]} { return $res } else { return [split $res] } } } # generates a proper list, trimming multiple separators proc tolist {s} { set s [string trim $s] regsub -all {[\t\n ]+} $s { } s if { [info tclversion] > 8.4 } { if { [string is list $s]} { return $s } else { return [split $s] } } else { if {![catch {llength $s}]} { return $s } else { return [split $s] } } } # Initialize the tcl sim array variable (if not already set) # setting up simulator / wave viewer commands proc set_sim_defaults {{reset {}}} { global sim terminal USER_CONF_DIR has_x bespice_listen_port env OS if {$reset eq {reset} } { file delete ${USER_CONF_DIR}/simrc } if { $reset eq {} } { set failure 0 if { [info exists has_x] && [winfo exists .sim] } { foreach tool $sim(tool_list) { for {set i 0} {$i < $sim($tool,n)} { incr i} { set sim($tool,$i,cmd) [.sim.topf.f.scrl.center.$tool.r.$i.cmd get 1.0 {end - 1 chars}] } } } if { ![info exists sim] } { if { [file exists ${USER_CONF_DIR}/simrc] } { # get conf from simrc if { [catch {source ${USER_CONF_DIR}/simrc} err]} { puts "Problems opening simrc file: $err" if {[info exists has_x]} { tk_messageBox -message "Problems opening simrc file: $err" -icon warning \ -parent [xschem get topwindow] -type ok } set failure 1 } } } } if {( $reset eq {reset} ) || ![info exists sim] || $failure} { if {[info exists sim]} {unset sim} # no simrc, set a reasonable default set sim(tool_list) {spice spicewave verilog verilogwave vhdl vhdlwave} if {$OS == "Windows"} { set_ne sim(spice,0,cmd) {ngspice -i "$N" -a} } else { set_ne sim(spice,0,cmd) {$terminal -e {ngspice -i "$N" -a || sh}} } # can not use set_ne as variables bound to entry widgets always exist if widget exists set sim(spice,0,name) {Ngspice interactive} set_ne sim(spice,0,fg) 0 set_ne sim(spice,0,st) 0 set_ne sim(spice,1,cmd) {ngspice "$N" -a} set sim(spice,1,name) {Ngspice Control mode} set_ne sim(spice,1,fg) 0 set_ne sim(spice,1,st) 1 set_ne sim(spice,2,cmd) {ngspice -b -r "$n.raw" "$N"} set sim(spice,2,name) {Ngspice batch} set_ne sim(spice,2,fg) 0 set_ne sim(spice,2,st) 1 set_ne sim(spice,3,cmd) {Xyce "$N"} set sim(spice,3,name) {Xyce batch} set_ne sim(spice,3,fg) 0 set_ne sim(spice,3,st) 1 set_ne sim(spice,4,cmd) {mpirun /path/to/parallel/Xyce "$N"} set sim(spice,4,name) {Xyce parallel batch} set_ne sim(spice,4,fg) 0 set_ne sim(spice,4,st) 1 # number of configured spice simulators, and default one set_ne sim(spice,n) 5 set_ne sim(spice,default) 0 ### spice wave view set_ne sim(spicewave,0,cmd) {gaw "$n.raw" } set sim(spicewave,0,name) {Gaw viewer} set_ne sim(spicewave,0,fg) 0 set_ne sim(spicewave,0,st) 0 set_ne sim(spicewave,1,cmd) {$terminal -e ngspice} set sim(spicewave,1,name) {Ngspice Viewer} set_ne sim(spicewave,1,fg) 0 set_ne sim(spicewave,1,st) 0 set_ne sim(spicewave,2,cmd) {rawtovcd -v 1.5 "$n.raw" > "$n.vcd" && gtkwave "$n.vcd" "$n.sav" 2>/dev/null} set sim(spicewave,2,name) {Rawtovcd} set_ne sim(spicewave,2,fg) 0 set_ne sim(spicewave,2,st) 0 # A server communicating with bespice wave was set up in the function setup_tcp_bespice(). # This server is listening on port $bespice_listen_port. set_ne sim(spicewave,3,cmd) {$env(HOME)/analog_flavor_eval/bin/bspwave --socket localhost $bespice_listen_port "$n.raw" } set sim(spicewave,3,name) {Bespice wave} set_ne sim(spicewave,3,fg) 0 set_ne sim(spicewave,3,st) 0 # number of configured spice wave viewers, and default one set_ne sim(spicewave,n) 4 set_ne sim(spicewave,default) 0 ### icarus verilog set_ne sim(verilog,0,cmd) {sh -c "iverilog -o .verilog_object -g2012 '$N' && vvp .verilog_object"} set sim(verilog,0,name) {Icarus verilog} set_ne sim(verilog,0,fg) 0 set_ne sim(verilog,0,st) 1 ### verilator set_ne sim(verilog,1,cmd) {sh -c "verilator -Wno-fatal --binary --timing --cc --Mdir obj_$s -o $s '$N' --trace \ && ./obj_$s/$s"} set sim(verilog,1,name) {Verilator} set_ne sim(verilog,1,fg) 0 set_ne sim(verilog,1,st) 1 # number of configured verilog simulators, and default one set_ne sim(verilog,n) 2 set_ne sim(verilog,default) 0 ### verilog wave view set_ne sim(verilogwave,0,cmd) {gtkwave dumpfile.vcd "$N.sav" 2>/dev/null} set sim(verilogwave,0,name) {Gtkwave} set_ne sim(verilogwave,0,fg) 0 set_ne sim(verilogwave,0,st) 0 # number of configured verilog wave viewers, and default one set_ne sim(verilogwave,n) 1 set_ne sim(verilogwave,default) 0 ### vhdl set_ne sim(vhdl,0,cmd) {ghdl -c --ieee=synopsys -fexplicit "$N" -r "$s" "--wave=$n.ghw"} set sim(vhdl,0,name) {Ghdl} set_ne sim(vhdl,0,fg) 0 set_ne sim(vhdl,0,st) 1 # number of configured vhdl simulators, and default one set_ne sim(vhdl,n) 1 set_ne sim(vhdl,default) 0 ### vhdl wave view set_ne sim(vhdlwave,0,cmd) {gtkwave "$n.ghw" "$N.sav" 2>/dev/null} set sim(vhdlwave,0,name) {Gtkwave} set_ne sim(vhdlwave,0,fg) 0 set_ne sim(vhdlwave,0,st) 0 # number of configured vhdl wave viewers, and default one set_ne sim(vhdlwave,n) 1 set_ne sim(vhdlwave,default) 0 } } proc simconf_reset {} { global sim set answer [tk_messageBox -message "Warning: delete simulation configuration file and reset to default?" \ -icon warning -parent .sim -type okcancel] if { $answer eq {ok}} { set_sim_defaults reset foreach tool $sim(tool_list) { for {set i 0} { $i < $sim($tool,n)} {incr i} { .sim.topf.f.scrl.center.$tool.r.$i.cmd delete 1.0 end .sim.topf.f.scrl.center.$tool.r.$i.cmd insert 1.0 $sim($tool,$i,cmd) } } } } proc simconf_saveconf {scrollframe} { global sim USER_CONF_DIR foreach tool $sim(tool_list) { for {set i 0} { $i < $sim($tool,n)} {incr i} { set sim($tool,$i,cmd) [${scrollframe}.center.$tool.r.$i.cmd get 1.0 {end - 1 chars}] } } # destroy .sim # xschem set semaphore [expr {[xschem get semaphore] -1}] save_sim_defaults ${USER_CONF_DIR}/simrc # puts "saving simrc" } proc simconf {} { global sim USER_CONF_DIR simconf_default_geometry if {[winfo exists .sim]} { destroy .sim xschem set semaphore [expr {[xschem get semaphore] -1}] } xschem set semaphore [expr {[xschem get semaphore] +1}] set_sim_defaults toplevel .sim -class Dialog wm title .sim {Simulation Configuration} wm geometry .sim 790x370 # wm transient .sim [xschem get topwindow] frame .sim.topf set scrollframe [sframe .sim.topf] frame ${scrollframe}.center frame .sim.bottom pack ${scrollframe}.center -fill both -expand yes set bg(0) {#dddddd} set bg(1) {#aaaaaa} set toggle 0 foreach tool $sim(tool_list) { frame ${scrollframe}.center.$tool label ${scrollframe}.center.$tool.l -width 12 -text $tool -background $bg($toggle) -fg black frame ${scrollframe}.center.$tool.r pack ${scrollframe}.center.$tool -fill both -expand yes pack ${scrollframe}.center.$tool.l -fill y -side left pack ${scrollframe}.center.$tool.r -fill both -expand yes for {set i 0} { $i < $sim($tool,n)} {incr i} { frame ${scrollframe}.center.$tool.r.$i pack ${scrollframe}.center.$tool.r.$i -fill x -expand yes entry ${scrollframe}.center.$tool.r.$i.lab -textvariable sim($tool,$i,name) -width 18 \ -background $bg($toggle) -fg black entry_replace_selection ${scrollframe}.center.$tool.r.$i.lab radiobutton ${scrollframe}.center.$tool.r.$i.radio -background $bg($toggle) -fg black \ -selectcolor white -variable sim($tool,default) -value $i text ${scrollframe}.center.$tool.r.$i.cmd -undo 1 -width 20 -height 3 -wrap none -background $bg($toggle) -fg black ${scrollframe}.center.$tool.r.$i.cmd insert 1.0 $sim($tool,$i,cmd) checkbutton ${scrollframe}.center.$tool.r.$i.fg -text Fg -variable sim($tool,$i,fg) \ -selectcolor white -background $bg($toggle) -fg black checkbutton ${scrollframe}.center.$tool.r.$i.st -text Status -variable sim($tool,$i,st) \ -selectcolor white -background $bg($toggle) -fg black pack ${scrollframe}.center.$tool.r.$i.lab -side left -fill y pack ${scrollframe}.center.$tool.r.$i.radio -side left -fill y pack ${scrollframe}.center.$tool.r.$i.cmd -side left -fill x -expand yes pack ${scrollframe}.center.$tool.r.$i.fg -side left -fill y pack ${scrollframe}.center.$tool.r.$i.st -side left -fill y } incr toggle set toggle [expr {$toggle %2}] } button .sim.bottom.cancel -text Cancel -command { destroy .sim xschem set semaphore [expr {[xschem get semaphore] -1}] } button .sim.bottom.help -text Help -command { viewdata {In this dialog box you set the commands xschem uses to launch the various external tools. The commands go through a tcl 'subst' round to do TCL variable and command substitution, so you may use the TCL '{' and '}' characters for grouping arguments with spaces. Xschem has 3 main netlisting modes (spice, verilog, vhdl) and for each netlisting mode some simulators and some viewers can be defined. The following variables are defined and will get substituted by XSCHEM before sending commands to the shell: - N: complete filename of netlist for current netlisting mode (example: /home/schippes/.xschem/simulations/opamp.spice for spice) (example: /home/schippes/.xschem/simulations/opamp.v for verilog) - n: complete filename of netlist as above but without extension (example: /home/schippes/.xschem/simulations/opamp) - S: full pathname of schematic being used (example: /home/schippes/.xschem/xschem_library/opamp.sch) - s: name of schematic being used (example: opamp) - d: simulation directory (example: /home/schippes/.xschem/simulations) - terminal: terminal to be used for applications that need to be executed in terminal (example: $terminal -e ngspice -i "$N" -a) If for a given tool there are multiple rows then the radiobutton tells which one will be called by xschem. Variables should be used with the usual substitution character $: $n, $N, etc. Foreground (Fg) checkbutton tells xschem to wait for child process to finish. Status checkbutton tells xschem to report a status dialog (stdout, stderr, exit status) when process finishes. If 'Accept, Save and Close' is pressed then changes made in the dialog box entries will be saved in ~/.xschem/simrc, changes will be persistent. If 'Accept, no Save and Close' is pressed then the changes are kept in memory and dialog is closed without writing to a file, if xschem is restarted changes will be lost. If no ~/.xschem/simrc is present then a minimal default setup is presented. To reset to default use the corresponding button or just delete the ~/.xschem/simrc file manually. } ro } button .sim.bottom.ok -text {Accept, Save and Close} -command " set_sim_defaults simconf_saveconf $scrollframe destroy .sim xschem set semaphore [expr {[xschem get semaphore] -1}] " button .sim.bottom.reset -text {Reset to default} -command { simconf_reset } button .sim.bottom.close -text {Accept, no Save and Close} -command { set_sim_defaults destroy .sim xschem set semaphore [expr {[xschem get semaphore] -1}] } wm protocol .sim WM_DELETE_WINDOW { set_sim_defaults destroy .sim xschem set semaphore [expr {[xschem get semaphore] -1}] } pack .sim.bottom.cancel -side left -anchor w pack .sim.bottom.help -side left #foreach tool $sim(tool_list) { # button .sim.bottom.add${tool} -text +${tool} -command " # simconf_add $tool # destroy .sim # xschem set semaphore [expr {[xschem get semaphore] -1}] # save_sim_defaults ${USER_CONF_DIR}/simrc ## simconf # " # pack .sim.bottom.add${tool} -side left #} pack .sim.bottom.ok -side right -anchor e pack .sim.bottom.close -side right pack .sim.bottom.reset -side right pack .sim.topf -fill both -expand yes pack .sim.bottom -fill x if { [info exists simconf_default_geometry]} { wm geometry .sim "${simconf_default_geometry}" } bind .sim.topf.f {sframeyview .sim.topf} bind .sim { set simconf_default_geometry [wm geometry .sim] } bind .sim { sframeyview .sim.topf scroll -0.2} bind .sim { sframeyview .sim.topf scroll 0.2} sframeyview .sim.topf place set maxsize [expr {[winfo height ${scrollframe}] + [winfo height .sim.bottom]}] wm maxsize .sim 9999 $maxsize # tkwait window .sim } proc simconf_add {tool} { global sim set n $sim($tool,n) set sim($tool,$n,cmd) {} set sim($tool,$n,name) {} set sim($tool,$n,fg) 0 set sim($tool,$n,st) 0 incr sim($tool,n) } ############ cellview # 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 if {$dark_gui_colorscheme} { set instfg orange1 set symfg SeaGreen1 set symbg SeaGreen4 set missingbg IndianRed4 } else { set instfg orange4 set symfg SeaGreen4 set symbg SeaGreen1 set missingbg IndianRed1 } 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] set sym_sch [rel_sym_path $abs_sch] set default_sch [add_ext $symbol .sch] set new_sch [$w get] $w configure -fg [option get . foreground {}] $w configure -bg [option get . background {}] if { $derived_symbol} { $w configure -fg $instfg } elseif {$sym_spice_sym_def ne {} } { $w configure -fg $symfg } if { $sym_spice_sym_def eq {}} { if { ![file exists [abs_sym_path [$w get]]] } { $w configure -bg $missingbg } } puts =============== if {$sym_sch ne $new_sch && $sym_spice_sym_def eq {}} { puts "Changing schematic attribute in symbol" xschem load -keep_symbols -nodraw -noundoreset $symbol set oldprop [xschem get schsymbolprop] if { $new_sch eq $default_sch } { set newprop [xschem subst_tok $oldprop schematic {}] ;# delete schematic attr in symbol } else { set newprop [xschem subst_tok $oldprop schematic $new_sch] } xschem set schsymbolprop $newprop xschem set_modify 3 ;# set only modified flag to force a save, do not update window/tab titles xschem save fast xschem remove_symbols ;# purge all symbols to force a reload from disk xschem load -keep_symbols -nodraw -noundoreset $current xschem netlist -keep_symbols -noalert;# traverse the hierarchy and retain all encountered symbols puts "get netlist" } puts sym_sch=$sym_sch puts default_sch=$default_sch puts new_sch=$new_sch puts symbol=$symbol } proc cellview_edit_item {symbol w} { set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2] if {[xschem is_generator [$w get]]} { set f [$w get] regsub {\(.*} $f {} f textwindow [abs_sym_path $f] } 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}] if {$new_sym_def ne $old_sym_def} { xschem load -keep_symbols -nodraw -noundoreset $symbol set oldprop [xschem get schsymbolprop] set newprop [xschem subst_tok $oldprop spice_sym_def $new_sym_def] xschem set schsymbolprop $newprop xschem set_modify 3 ;# set only modified flag to force a save, do not update window/tab titles xschem save fast puts "$symbol: updated spice_sym_def attribute" xschem load -keep_symbols -nodraw -noundoreset $current xschem reload_symbols ;# update in-memory symbol data } } } proc cellview_edit_sym {w} { set sym [$w cget -text] set res [catch {xschem symbol_base_name $sym} base_name] if {$res == 0} { if {$base_name ne {}} { set sym $base_name } } xschem load_new_window $sym } proc cellview { {derived_symbols {}} {upd 0} } { global keep_symbols nolist_libs dark_gui_colorscheme if {$dark_gui_colorscheme} { set instfg orange1 set symfg SeaGreen1 set symbg SeaGreen4 set missingbg IndianRed4 } else { set instfg orange4 set symfg SeaGreen4 set symbg SeaGreen1 set missingbg IndianRed1 } if {[info tclversion] >= 8.5} { set font {TkDefaultFont 10 bold} ;# Monospace } else { set font fixed } if {!$upd} { xschem reload_symbols ;# purge unused symbols xschem netlist -keep_symbols -noalert;# traverse the hierarchy and retain all encountered symbols puts "get netlist" catch {destroy .cv} toplevel .cv wm geometry .cv 800x200 update raise .cv frame .cv.top 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 { } -width 4 -bg grey60 -font $font pack .cv.top.sym .cv.top.sch -side left -fill x -expand 1 pack .cv.top.pad -side left -fill x frame .cv.center set sf [sframe .cv.center] } else { set sf .cv.center.f.scrl } set syms [join [lsort -index 1 [xschem symbols $derived_symbols]]] foreach {i symbol} $syms { if { [catch {set base_name [xschem symbol_base_name $symbol]}] } { set base_name $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]} ]} { set abs_sch [abs_sym_path [add_ext $symbol .sch]] } if {$derived_symbol} { set abs_sym [abs_sym_path $base_name] } else { set abs_sym [abs_sym_path $symbol] } set skip 0 foreach j $nolist_libs { if {[regexp $j $abs_sym]} { set skip 1 break } } if {$skip} { continue } set sym_sch [rel_sym_path $abs_sch] set type [xschem getprop symbol $symbol type] set sym_spice_sym_def [xschem getprop symbol $symbol spice_sym_def 2] if {$type eq {subcircuit}} { if {!$upd} { frame $sf.f$i pack $sf.f$i -side top -fill x label $sf.f$i.l -text $symbol -width 30 -anchor w -padx 4 -borderwidth 1 \ -relief sunken -pady 1 -font $font if {$derived_symbol} { $sf.f$i.l configure -fg $instfg } # puts $sf.f$i.s entry $sf.f$i.s -width 45 -borderwidth 1 -relief sunken -font $font button $sf.f$i.sym -text Sym -padx 4 -borderwidth 1 -pady 0 -font $font \ -command "cellview_edit_sym $sf.f$i.l" button $sf.f$i.sch -text Sch -padx 4 -borderwidth 1 -pady 0 -font $font \ -command "cellview_edit_item $symbol $sf.f$i.s" if {$sym_spice_sym_def eq {}} { $sf.f$i.s insert 0 $sym_sch } else { if {$derived_symbol} { $sf.f$i.s insert 0 {defined in instance spice_sym_def} } else { $sf.f$i.s insert 0 {defined in symbol spice_sym_def} } } } if {[xschem is_generator [ $sf.f$i.s get]]} { set f [ $sf.f$i.s get] regsub {\(.*} $f {} f } elseif { $sym_spice_sym_def eq {}} { set f [abs_sym_path [$sf.f$i.s get]] } else { set ff [split $sym_spice_sym_def \n] if {[llength $ff] > 5} { set ff [lrange $ff 0 4] lappend ff ... } set f [join $ff \n] } balloon $sf.f$i.s $f cellview_setlabels $sf.f$i.s $symbol $derived_symbol if {!$upd} { pack $sf.f$i.l $sf.f$i.s -side left -fill x -expand 1 pack $sf.f$i.sch $sf.f$i.sym -side left } } } if {$upd} {return} frame .cv.bottom button .cv.bottom.update -text Update -command "cellview $derived_symbols 1" pack .cv.bottom.update -side left 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} } ############ /cellview ############ 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 set sf .trav.center.f.scrl # puts "traversal_setlabels: $w parent: |$parent_sch| inst: $instname def: $sym_sch $inst_sch --> [$w get]" # update schematic if {$parent_sch ne {}} { set current [xschem get current_name] if { $inst_sch ne [$w get] } { puts "update attr" xschem load -undoreset -nodraw $parent_sch if { [$w get] eq $sym_sch} { xschem setprop -fast instance $instname schematic ;# remove schematic attr on instance } else { xschem setprop -fast instance $instname schematic [$w get] ;# set schematic attr on instance } xschem set_modify 3 ;# set only modified flag to force a save, do not update window/tab titles xschem save fast set inst_sch [$w get] # puts "inst_sch set to: $inst_sch" xschem load -undoreset -nodraw $current } } # /update schematic if {$dark_gui_colorscheme} { set instfg orange1 set symfg SeaGreen1 set instbg orange4 set symbg SeaGreen4 set missingbg IndianRed4 } else { set instfg orange4 set symfg SeaGreen4 set instbg Orange1 set symbg SeaGreen1 set missingbg IndianRed1 } $w configure -fg [option get . foreground {}] $w configure -bg [option get . background {}] if { $sym_spice_sym_def ne {}} { $w configure -fg $symfg } elseif {$inst_spice_sym_def ne {}} { $w configure -fg $instfg } elseif { ![file exists [abs_sym_path [$w get]]] } { $w configure -bg $missingbg } else { if {[$w get] eq $default_sch} { # .... } elseif {[$w get] eq $sym_sch} { $w configure -bg $symbg } elseif {[$w get] eq $inst_sch} { $w configure -bg $instbg } } } # This proc traverses the hierarchy and prints all instances in design. proc traversal {{only_subckts 1} {all_hierarchy 1}} { global traversal keep_symbols set traversal(only_subckts) $only_subckts set traversal(all_hierarchy) $all_hierarchy set traversal(cnt) 0 set save_keep $keep_symbols set keep_symbols 1 xschem unselect_all xschem set no_draw 1 ;# disable screen update xschem set no_undo 1 ;# disable undo if {[info tclversion] >= 8.5} { set font {TkDefaultFont 10 bold} ;# Monospace } else { set font fixed } toplevel .trav 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 .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 " set traversal(geom) \[winfo geometry .trav\] destroy .trav " if {[info exists traversal(geom)]} { wm geometry .trav $traversal(geom) } else { wm geometry .trav 1200x400 } update set traversal(geom) [winfo geometry .trav] return {} } # recursive procedure proc hier_traversal {{level 0} {only_subckts 0} {all_hierarchy 1}} { global nolist_libs traversal retval if {[info tclversion] >= 8.5} { set font {TkDefaultFont 10 bold} ;# Monospace } else { set font fixed } set parent_sch [xschem get current_name] # puts $parent_sch set sf .trav.center.f.scrl set done_print 0 set schpath [xschem get sch_path] set instances [xschem get instances] set current_level [xschem get currsch] for {set i 0} { $i < $instances} { incr i} { set instname [xschem getprop instance $i name] set symbol [xschem getprop instance $i cell::name] set default_sch [add_ext $symbol .sch] set sym_sch [rel_sym_path [xschem get_sch_from_sym -1 $symbol]] set abs_symbol [abs_sym_path $symbol] set type [xschem getprop symbol $symbol type] set schematic [xschem get_sch_from_sym $i] set sch_exists [expr {[file exists $schematic] ? {} : {**missing**}}] set inst_sch [rel_sym_path $schematic] set sch_rootname [file tail [file rootname $inst_sch]] set inst_spice_sym_def [xschem getprop instance $i spice_sym_def] set sym_spice_sym_def [xschem getprop instance $i cell::spice_sym_def] if {$only_subckts && ($type ne {subcircuit})} { continue } set skip 0 foreach j $nolist_libs { if {[regexp $j $abs_symbol]} { set skip 1 break } } if {$skip} { continue } incr traversal(cnt) set cnt $traversal(cnt) # puts "building frame $sf.f$cnt" frame $sf.f$cnt pack $sf.f$cnt -side top -fill x label $sf.f$cnt.i -text "[spaces $level 2]$instname" \ -width 25 -anchor w -padx 4 -borderwidth 1 \ -relief sunken -pady 1 -font $font label $sf.f$cnt.l -text $symbol -width 30 -anchor w -padx 4 -borderwidth 1 \ -relief sunken -pady 1 -font $font entry $sf.f$cnt.s -width 45 -borderwidth 1 -relief sunken -font $font if {$type eq {subcircuit}} { if {$inst_spice_sym_def ne {}} { $sf.f$cnt.s insert 0 "$sch_rootname defined in instance spice_sym_def" } elseif {$sym_spice_sym_def ne {}} { $sf.f$cnt.s insert 0 "$sch_rootname defined in symbol spice_sym_def" } else { $sf.f$cnt.s insert 0 "$inst_sch" } } button $sf.f$cnt.bsym -text {Sym} -padx 4 -borderwidth 1 -pady 0 -font $font \ -command " xschem load_new_window \[$sf.f$cnt.l cget -text\] " button $sf.f$cnt.bsch -text {Sch} -padx 4 -borderwidth 1 -pady 0 -font $font \ -command " if { [list $sym_spice_sym_def] eq {} && [list $inst_spice_sym_def] eq {}} { xschem load_new_window \[$sf.f$cnt.s get\] } elseif {[list $sym_spice_sym_def] ne {}} { editdata [list $sym_spice_sym_def] {Symbol spice_sym_def attribute} } else { editdata [list $inst_spice_sym_def] {Instance spice_sym_def attribute} }" button $sf.f$cnt.upd -text Upd -padx 4 -borderwidth 1 -pady 0 -font $font \ -command " traversal_setlabels $sf.f$cnt.s [list $parent_sch] [list $instname] [list $inst_sch] \ [list $sym_sch] [list $default_sch] [list $inst_spice_sym_def] [list $sym_spice_sym_def] set traversal(geom) \[winfo geometry .trav\] destroy .trav traversal $traversal(only_subckts) $traversal(all_hierarchy) " traversal_setlabels $sf.f$cnt.s $parent_sch $instname $inst_sch $sym_sch \ $default_sch $inst_spice_sym_def $sym_spice_sym_def pack $sf.f$cnt.i -side left -fill x -expand 1 pack $sf.f$cnt.l $sf.f$cnt.s -side left -fill x pack $sf.f$cnt.bsym $sf.f$cnt.bsch $sf.f$cnt.upd -side left set done_print 1 if {$type eq {subcircuit} && $all_hierarchy} { xschem select instance $i fast nodraw set descended [xschem descend 1 6] if {$descended} { incr level set dp [hier_traversal $level $only_subckts 1] xschem go_back 1 incr level -1 } } } return $done_print } ############ /traversal proc bespice_getdata {sock} { global bespice_server_getdata if {[eof $sock] || [catch {gets $sock bespice_server_getdata(line,$sock)}]} { puts "Closing connection $sock to bespice : $bespice_server_getdata(addr,$sock)" unset bespice_server_getdata(addr,$sock) unset bespice_server_getdata(line,$sock) # we remove the closing socket from the list of clients set search_index [ lsearch $bespice_server_getdata(clients) $sock] # puts " search_index for $sock in $bespice_server_getdata(clients) ==> $search_index" if { $search_index >= 0 } { set bespice_server_getdata(clients) [ lreplace $bespice_server_getdata(clients) $search_index $search_index ] } set nb [ llength $bespice_server_getdata(clients) ] if { $nb == 0 } { # no more clients left => communication closed unset bespice_server_getdata(sock) } else { # we have another client connection => use this one set new_sock [lindex $bespice_server_getdata(clients) 0] puts "Communicating to bespice over socket $new_sock" set bespice_server_getdata(sock) [list $new_sock ] } close $sock # puts "Clients = $bespice_server_getdata(clients)" # set nb [ llength $bespice_server_getdata(clients) ] # puts "number of Clients = $nb" } else { puts "bespice --> $bespice_server_getdata(line,$sock)" set bespice_server_getdata(last) $bespice_server_getdata(line,$sock) } } proc xschem_getdata {sock} { global xschem_server_getdata tclcmd_puts debug_var while {1} { if {[gets $sock line] < 0} { break } else { append xschem_server_getdata(line,$sock) $line \n } } if {$debug_var<=-1} {puts "tcp<-- $xschem_server_getdata(line,$sock)"} # xschem command must be executed at global scope... redef_puts uplevel #0 [list catch $xschem_server_getdata(line,$sock) tclcmd_puts] rename puts {} rename ::tcl::puts puts if {$debug_var<=-1} {puts "tcp--> $tclcmd_puts"} set xschem_server_getdata(res,$sock) "$tclcmd_puts" puts -nonewline $sock "$xschem_server_getdata(res,$sock)" flush $sock close $sock ;# server closes if {$debug_var<=-1} {puts "Close $xschem_server_getdata(addr,$sock)"} unset xschem_server_getdata(addr,$sock) unset xschem_server_getdata(line,$sock) unset xschem_server_getdata(res,$sock) } # this function is called as soon as bespice wave connects to the communication server listening on $bespice_listen_port # it makes sure the communication over the socket connection is possible proc bespice_server {sock addr port} { global bespice_server_getdata if { ![info exists bespice_server_getdata(sock)] } { puts "Accepting bespice connection $sock from $addr port $port" set bespice_server_getdata(clients) [list $sock] } else { # we can' t handle more tha one socket at once # however we put this socket to a list in case the 1st socket is closed. # we can then use the 2nd socket puts "Can't handle bespice connection $sock from $addr port $port" lappend bespice_server_getdata(clients) [list $sock] } fconfigure $sock -buffering line set bespice_server_getdata(addr,$sock) [list $addr $port] set bespice_server_getdata(sock) [list $sock] fileevent $sock readable [list bespice_getdata $sock] # this informs bespice wave that it receives it's instructions from xschem. Some features will be adjusted for that. puts $bespice_server_getdata(sock) "set_customer_specialization xschem" # puts "Clients = $bespice_server_getdata(clients)" # set nb [ llength $bespice_server_getdata(clients) ] # puts "number of Clients = $nb" } proc xschem_server {sock addr port} { global xschem_server_getdata debug_var if {$debug_var<=-1} {puts "Accept $sock from $addr port $port"} fconfigure $sock -buffering line -blocking 0 set xschem_server_getdata(addr,$sock) [list $addr $port] set xschem_server_getdata(line,$sock) {} fileevent $sock readable [list xschem_getdata $sock] } proc list_hierarchy {} { set s [xschem list_hierarchy] set r {} foreach {a b} [lsort -decreasing -dictionary -index 0 -stride 2 $s] { append r $a { } $b \n } return $r } ## given a path (x1.x2.m4) descend into x1.x2 and return m4 whether m4 found or not proc descend_hierarchy {path {redraw 1}} { xschem set no_draw 1 # return to top level if not already there while { [xschem get currsch] } { xschem go_back } # recursively descend into sub-schematics while { [regexp {\.} $path] } { xschem unselect_all set inst $path regsub {\..*} $inst {} inst ;# take 1st path component: xlev1[3].xlev2.m3 -> xlev1[3] regsub {[^.]+\.} $path {} path ;# take remaining path: xlev1[3].xlev2.m3 -> xlev2.m3 xschem search exact 1 name $inst 1 # handle vector instances: xlev1[3:0] -> xlev1[3],xlev1[2],xlev1[1],xlev1[0] # descend into the right one set inst_list [split [lindex [xschem expandlabel [lindex [xschem selected_set] 0 ] ] 0] {,}] set instnum [expr {[lsearch -exact $inst_list $inst] + 1}] xschem descend $instnum } xschem set no_draw 0 if {$redraw} {xschem redraw} return $path } ## given a hierarchical instname name (x1.xamp.m1) go down in the hierarchy and ## select the specified instance (m1). ## this search assumes it is given from the top of hierarchy proc select_inst {fullinst {redraw 1 } } { xschem set no_draw 1 set inst [descend_hierarchy $fullinst 0] set res [xschem select instance $inst] # if nothing found return to top if {!$res} { while { [xschem get currsch] } { xschem go_back } } xschem set no_draw 0 if {$redraw} {xschem redraw} if {$res} {return $inst} else { return {} } } proc pin_label {} { return [rel_sym_path [find_file_first lab_pin.sym]] } ## given a hierarchical net name x1.xamp.netname go down in the hierarchy and ## highlight the specified net. ## this search assumes it is given from the top of hierarchy proc probe_net {fullnet {redraw 1} } { xschem set no_draw 1 set net [descend_hierarchy $fullnet 0] set res [xschem hilight_netname $net] if {$res==0 && [regexp {^net[0-9]+$} $net]} { set net \#$net set res [xschem hilight_netname $net] } if {!$res} { while { [xschem get currsch] } { xschem go_back } } xschem set no_draw 0 if {$redraw} {xschem redraw} if {$res} {return $net} else { return {} } } # backannotate newnet to be connected to specified hierarchical instance name and pin. # places a label close to the instance pin to be re-routed. # actual reconnect is human assisted! proc reroute_inst {fullinst pinattr pinval newnet} { if { [regexp {\.} $fullinst] } { set hier 1 } else { set hier 0 } set res [descend_hierarchy $fullinst 0] if {$res ne {} } { set coord [xschem instance_pin_coord $res $pinattr $pinval] if { $coord eq {} } { while { [xschem get currsch] } { xschem go_back } return 0 } set pinname [lindex $coord 0] set x [expr {[lindex $coord 1] - 10} ] set y [expr {[lindex $coord 2] - 10} ] set oldnet [xschem instance_net $res $pinname] regsub {.*\.} $newnet {} newnet if { $oldnet eq $newnet } { while { [xschem get currsch] } { xschem go_back } puts "Warning: netlist patch already done? " return 0 } xschem instance [pin_label] $x $y 0 0 [list name=l1 lab=$newnet] xschem hilight_netname $newnet xschem select instance $res xschem hilight_netname $oldnet if {$hier} { xschem save} ;# save so we can process other reroute_inst without beink asked to save. xschem redraw return 1 } return 0 } ## put $new net labels close to pins on all elements connected to $old proc reroute_net {old new} { xschem push_undo xschem set no_undo 1 xschem unhilight probe_net $old set old_nopath [regsub {.*\.} $old {}] set new_nopath [regsub {.*\.} $new {}] set devlist [xschem instances_to_net $old_nopath] foreach i $devlist { set instname [lindex $i 0] set x [expr {[lindex $i 2] - 10}] set y [expr {[lindex $i 3] - 10}] xschem instance [pin_label] $x $y 0 0 [list name=l1 lab=$new_nopath] xschem select instance $instname } xschem hilight_netname $new_nopath xschem set no_undo 0 } ## $N : netlist file full path (/home/schippes/simulations/opamp.spice) ## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp) ## $s : schematic name (opamp) or netlist_name if given ## $S : schematic name full path (/home/schippes/.xschem/xschem_library/opamp.sch) ## $d : netlist directory proc sim_cmd {cmd} { global netlist_dir terminal regsub {/$} $netlist_dir {} netlist_dir set tool [xschem get netlist_type] set d ${netlist_dir} set S [xschem get schname] set custom_netlist_file [xschem get netlist_name] if {$custom_netlist_file ne {}} { set s [file rootname $custom_netlist_file] } else { set s [file tail [file rootname $S]] } set n ${netlist_dir}/${s} if {$tool eq {verilog}} { set N ${n}.v } else { set N ${n}.${tool} } # puts "N=$N\nn=$n\ns=$s\nS=$S\nd=$d" return [subst $cmd] } # wrapper to proc simulate, if called from button. proc simulate_from_button {{callback {}}} { global simulate_bg set simvar tctx::[xschem get current_win_path]_simulate if {![info exists $simvar] || [set $simvar] ne {orange}} { simulate $callback } elseif {[info exists $simvar] && [set $simvar] eq {orange}} { set simulate_id tctx::[xschem get current_win_path]_simulate_id if { [info exists $simulate_id] } { set id [set $simulate_id] set res [kill_running_cmds $id -15] if { $res == 0} { # something went wrong. Forget about the process unset tctx::[xschem get current_win_path]_simulate_id set tctx::[xschem get current_win_path]_simulate $simulate_bg [xschem get top_path].menubar entryconfigure Simulate -background $simulate_bg } } } } ## $N : netlist file full path (/home/schippes/simulations/opamp.spice) ## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp) ## $s : schematic name (opamp) or netlist_name if given ## $S : schematic name full path (/home/schippes/.xschem/xschem_library/opamp.sch) ## $d : netlist directory proc simulate {{callback {}}} { global netlist_dir terminal sim env global execute XSCHEM_SHAREDIR has_x OS regsub {/$} $netlist_dir {} netlist_dir set_sim_defaults set netlist_type [xschem get netlist_type] if { [set_netlist_dir 0] ne {}} { set d ${netlist_dir} set tool $netlist_type set S [xschem get schname] set custom_netlist_file [xschem get netlist_name] if {$custom_netlist_file ne {}} { set s [file rootname $custom_netlist_file] } else { set s [file tail [file rootname $S]] } set n ${netlist_dir}/${s} if {$tool eq {verilog}} { set N ${n}.v } else { set N ${n}.${tool} } if { ![info exists sim($tool,default)] } { if { [info exists has_x] } {alert_ "Warning: simulator for $tool is not configured"} puts "Warning: simulator for $tool is not configured" return -1 } set def $sim($tool,default) set fg $sim($tool,$def,fg) set st $sim($tool,$def,st) if {$fg} { set fg {execute_wait} } else { set fg {execute} } set cmd [subst -nobackslashes $sim($tool,$def,cmd)] # window interface tabbed interface # ----------------------------------------- # top_path win_path top_path win_path # {} .drw {} .drw # .x1 .x1.drw {} .x1.drw # .x2 .x2.drw {} .x2.drw set execute(callback) " set_simulate_button [list [xschem get top_path] [xschem get current_win_path]] $callback " if {$fg eq {execute_wait}} {xschem set semaphore [expr {[xschem get semaphore] +1}]} set save [pwd] cd $netlist_dir # Note: Windows $cmd cannot be surrounded by {} as exec will change forward slash to backward slash set id [eval execute $st $cmd] ;# Start simulation process cd $save if {[info exists has_x] && $id >= 0 } { set tctx::[xschem get current_win_path]_simulate_id $id set button_path [xschem get top_path].menubar $button_path entryconfigure Simulate -background orange set tctx::[xschem get current_win_path]_simulate orange } puts "Simulation started: execution ID: $id" if {$fg eq {execute_wait}} { if {$id >= 0} { vwait execute(pipe,$id) } xschem set semaphore [expr {[xschem get semaphore] -1}] } return $id } else { return -1 } } proc gaw_echoline {} { global gaw_fd gets $gaw_fd line if {[eof $gaw_fd]} { puts "finishing connection from gaw" close $gaw_fd unset gaw_fd } else { # generate a variable event we can vwait for set gaw_fd $gaw_fd } puts "gaw -> $line" } proc setup_tcp_gaw {} { global gaw_fd gaw_tcp_address netlist_dir has_x regsub {/$} $netlist_dir {} netlist_dir if { [info exists gaw_fd] } { return 1; } set custom_netlist_file [xschem get netlist_name] if {$custom_netlist_file ne {}} { set s [file rootname $custom_netlist_file] } else { set s [file tail [file rootname [xschem get schname 0]]] } if { ![info exists gaw_fd] && [catch {eval socket $gaw_tcp_address} gaw_fd] } { puts "Problems opening socket to gaw on address $gaw_tcp_address" unset gaw_fd if {[info exists has_x]} { tk_messageBox -type ok -title {Tcp socket error} \ -message [concat "Problems opening socket to gaw on address $gaw_tcp_address. " \ "Ensure the following line is present uncommented in ~/.gaw/gawrc: up_listenPort = 2020." \ "If you recently closed gaw the port may be in a TIME_WAIT state for a minute or so ." \ "Close gaw, Wait a minute or two, then send waves to gaw again."] } return 0 } fconfigure $gaw_fd -blocking 1 -buffering line -encoding binary -translation binary fileevent $gaw_fd readable gaw_echoline puts $gaw_fd "table_set $s.raw" return 1 } proc gaw_cmd {cmd} { global gaw_fd gaw_tcp_address netlist_dir has_x regsub {/$} $netlist_dir {} netlist_dir if { ![info exists gaw_fd] && [catch {eval socket $gaw_tcp_address} gaw_fd] } { puts "Problems opening socket to gaw on address $gaw_tcp_address" unset gaw_fd if {[info exists has_x]} { tk_messageBox -type ok -title {Tcp socket error} \ -message [concat "Problems opening socket to gaw on address $gaw_tcp_address. " \ "If you recently closed gaw the port may be in a TIME_WAIT state for a minute or so ." \ "Close gaw, Wait a minute or two, then send waves to gaw again."] } return } fconfigure $gaw_fd -blocking 0 -buffering line -encoding binary -translation binary puts $gaw_fd "$cmd" set n [regexp -all \n $cmd] incr n puts "gaw command lines: $n" fileevent $gaw_fd readable gaw_echoline while { $n} { #timeout for abnormal deadlocks set wd [after 10000 set gaw_fd stalled] vwait gaw_fd if { $gaw_fd ne {stalled} } { after cancel $wd } else { puts "timeout waiting for gaw response.." break } incr n -1 } close $gaw_fd unset gaw_fd } proc waves {{type {}}} { ## $N : netlist file full path (/home/schippes/simulations/opamp.spice) ## $n : netlist file full path with extension chopped (/home/schippes/simulations/opamp) ## $s : schematic name (opamp) or netlist_name if given ## $S : schematic name full path (/home/schippes/.xschem/xschem_library/opamp.sch) ## $d : netlist directory global netlist_dir terminal sim XSCHEM_SHAREDIR has_x global bespice_listen_port env simulate_bg execute regsub {/$} $netlist_dir {} netlist_dir if {$type ne {external} } { load_raw $type return } set netlist_type [xschem get netlist_type] set_sim_defaults if { [set_netlist_dir 0] ne {}} { set d ${netlist_dir} set tool ${netlist_type} set S [xschem get schname] set custom_netlist_file [xschem get netlist_name] if {$custom_netlist_file ne {}} { set s [file rootname $custom_netlist_file] } else { set s [file tail [file rootname $S]] } set n ${netlist_dir}/${s} if {$tool eq {verilog}} { set N ${n}.v } else { set N ${n}.${tool} } set tool ${tool}wave if {![info exists sim($tool,default)] } { if { [info exists has_x] } {alert_ "Warning: viewer for $tool is not configured"} puts "Warning: viewer for $tool is not configured" return } set def $sim($tool,default) set fg $sim($tool,$def,fg) set st $sim($tool,$def,st) if {$fg} { set fg {execute_wait} } else { set fg {execute} } set cmd [subst -nobackslashes $sim($tool,$def,cmd)] set save [pwd] cd $netlist_dir set id [eval execute $st $cmd] cd $save if {$fg eq {execute_wait}} { if {$id >= 0} { xschem set semaphore [expr {[xschem get semaphore] +1}] vwait execute(pipe,$id) xschem set semaphore [expr {[xschem get semaphore] -1}] } } } } # ============================================================ proc graph_push_undo {} { global graph_change_done if {$graph_change_done == 0} { xschem push_undo set graph_change_done 1 } } # allow change color (via graph_change_wave_color) of double clicked wave proc graph_edit_wave {n n_wave} { global graph_sel_color graph_selected graph_sel_wave global graph_schname cadlayers if {[winfo exists .graphdialog]} {return} set graph_schname [xschem get schname] set_ne graph_sel_color 4 set graph_selected $n set graph_sel_wave $n_wave set col [xschem getprop rect 2 $graph_selected color] set node [xschem my_strtok_r [xschem getprop rect 2 $graph_selected node] \n \" 0] # add default colors if unspecified in col set i 0 foreach graph_node $node { if {[lindex $col $i] eq {}} { lappend col $graph_sel_color} incr i } # remove excess colors set col [lrange $col 0 [expr {$i - 1}]] set graph_sel_color [lindex $col $graph_sel_wave] xschem setprop -fast rect 2 $graph_selected color $col xschem draw_graph $graph_selected toplevel .graphdialog -class Dialog wm transient .graphdialog [xschem get topwindow] frame .graphdialog.f button .graphdialog.ok -text OK -command { destroy .graphdialog } button .graphdialog.cancel -text Cancel -command {destroy .graphdialog} for {set i 4} {$i < $cadlayers} {incr i} { radiobutton .graphdialog.f.r$i -value $i -background [lindex $tctx::colors $i] \ -variable graph_sel_color -command {graph_change_wave_color $graph_sel_wave } \ -selectcolor white -foreground black pack .graphdialog.f.r$i -side left -fill both -expand yes } grid .graphdialog.f - -sticky nsew grid .graphdialog.ok .graphdialog.cancel -sticky ew grid rowconfig .graphdialog 0 -weight 1 grid column .graphdialog 0 -weight 1 grid column .graphdialog 1 -weight 1 tkwait window .graphdialog set graph_schname {} } # get selected text from a text widget: # # .graphdialog.center.right.text1 get sel.first sel.last # # see if a selection is present: # .graphdialog.center.right.text1 tag ranges sel # # replace selected text: # .graphdialog.center.right.text1 replace sel.first sel.last BUS # # programmatically select text: # .graphdialog.center.right.text1 tag add sel 1.0 {end - 1 chars} # clear selection # .graphdialog.center.right.text1 tag remove sel 1.0 end # get position of cursor: # .graphdialog.center.right.text1 index insert # set cursor position: # .graphdialog.center.right.text1 mark set insert 2.18 # add nodes from provided list of {node color} .... # used in hilight_net() proc graph_add_nodes_from_list {nodelist} { global graph_bus graph_selected graph_schname has_x if {$graph_bus} { set sep , } else { set sep \n } if { [info exists has_x] && [winfo exists .graphdialog] } { set sel {} set current_node_list [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] set col [xschem getprop rect 2 $graph_selected color] if {[string length $current_node_list] > 0 && ![regexp "\n$" $current_node_list]} { .graphdialog.center.right.text1 insert end \n } set change_done 0 set first 0 foreach {i c} $nodelist { if {$sel ne {}} {append sel $sep} if {!$first || !$graph_bus } { regsub {\[.*} $i {} busname lappend col $c } append sel $i set change_done 1 set first 1 } if {$change_done && $graph_bus} { set sel "[string toupper $busname];${sel}\n" } else { set sel "${sel}\n" } if {$change_done} { .graphdialog.center.right.text1 insert end $sel if { [xschem get schname] eq $graph_schname } { set node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"] xschem setprop -fastundo rect 2 $graph_selected color $col graph_update_nodelist regsub -all {[\\"]} $node {\\&} node_quoted xschem setprop -fast rect 2 $graph_selected node $node_quoted xschem draw_graph $graph_selected } } } else { set sel {} set change_done 0 set first 0 set col [xschem getprop rect 2 [xschem get graph_lastsel] color] set nnn [xschem getprop rect 2 [xschem get graph_lastsel] node] foreach {i c} $nodelist { if {$sel ne {}} {append sel $sep} if {!$first || !$graph_bus } { regsub {\[.*} $i {} busname lappend col $c } append sel $i set change_done 1 set first 1 } if {$change_done && $graph_bus} { set sel "[string toupper $busname];${sel}\n" } else { set sel "${sel}\n" } if {$change_done} { xschem setprop -fastundo rect 2 [xschem get graph_lastsel] color $col if {[string length $nnn] > 0 && ![regexp "\n$" $nnn]} { append nnn "\n" } append nnn $sel regsub -all {[\\"]} $nnn {\\&} node_quoted xschem setprop -fast rect 2 [xschem get graph_lastsel] node $node_quoted xschem draw_graph [xschem get graph_lastsel] } } } # add nodes from left listbox proc graph_add_nodes {} { global graph_bus set sel_idx [.graphdialog.center.left.list1 curselection] set sel {} if {$graph_bus} { set sep , } else { set sep \n } set current_node_list [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] if {[string length $current_node_list] > 0 && ![regexp "\n$" $current_node_list]} { .graphdialog.center.right.text1 insert end \n } set change_done 0 foreach i $sel_idx { set c [.graphdialog.center.left.list1 get $i] # escape [ and ] characters. set c [regsub -all {([][])} $c {\\\1}] if { ![regexp "(^|\[ \t\n\])${c}($|\[ \t\n\])" $current_node_list]} { if {$sel ne {}} {append sel $sep} append sel [.graphdialog.center.left.list1 get $i] set change_done 1 } } if {$change_done && $graph_bus} { set sel "BUS_NAME;${sel}\n" } else { set sel "${sel}\n" } if {$change_done} { .graphdialog.center.right.text1 insert {insert lineend + 1 char} $sel } } proc graph_get_signal_list {siglist pattern } { global graph_sort set direction {-decreasing} if {$graph_sort} {set direction {-increasing}} set result {} set siglist [join [lsort $direction -dictionary $siglist] \n] # just check if pattern is a valid regexp set err [catch {regexp $pattern {12345}} res] if {$err} {set pattern {}} foreach i $siglist { regsub {^v\((.*)\)$} $i {\1} i if {[regexp $pattern $i] } { lappend result $i } } return $result } proc touches {sel tag} { set res 0 scan $sel {%d.%d %d.%d} sel_linestart sel_charstart sel_lineend sel_charend scan $tag {%d.%d %d.%d} tag_linestart tag_charstart tag_lineend tag_charend set selstart [expr {$sel_linestart * 1000000 + $sel_charstart}] set selend [expr {$sel_lineend * 1000000 + $sel_charend}] set tagstart [expr {$tag_linestart * 1000000 + $tag_charstart}] set tagend [expr {$tag_lineend * 1000000 + $tag_charend}] # puts "selstart: $selstart" # puts "selend: $selend" # puts "tagstart: $tagstart" # puts "tagend: $tagend" if { ($tagstart >= $selstart && $tagstart <= $selend) || ($tagend >= $selstart && $tagend <= $selend) || ($selstart >= $tagstart && $selstart <= $tagend) || ($selend >= $tagstart && $selend <= $tagend) } { set res 1 } # puts "touch: returning $res" return $res } # change color of selected wave in text widget and redraw graph # OR # change color attribute of wave given as parameter, redraw graph proc graph_change_wave_color {{wave {}}} { global graph_sel_color graph_selected graph_schname if { [xschem get schname] ne $graph_schname } return # get tag the cursor is on: if { $wave eq {}} { set sel_range [.graphdialog.center.right.text1 tag ranges sel] if {$sel_range ne {}} { # puts "sel_range --> $sel_range" foreach tag [.graphdialog.center.right.text1 tag names] { if {$tag eq {sel}} {continue} set tag_range [.graphdialog.center.right.text1 tag ranges $tag] # puts "$tag --> $tag_range" if { [touches $sel_range $tag_range]} { set index [string range $tag 1 end] set col [xschem getprop rect 2 $graph_selected color] set col [lreplace $col $index $index $graph_sel_color] xschem setprop -fast rect 2 $graph_selected color $col } } graph_update_nodelist xschem draw_graph $graph_selected } else { set tag [.graphdialog.center.right.text1 tag names insert] if { $tag eq {}} {set tag [.graphdialog.center.right.text1 tag names {insert - 1 char}]} if { [regexp {^t} $tag]} { set index [string range $tag 1 end] set col [xschem getprop rect 2 $graph_selected color] set col [lreplace $col $index $index $graph_sel_color] xschem setprop -fast rect 2 $graph_selected color $col graph_update_nodelist xschem draw_graph $graph_selected } } # wave to change provided as parameter } else { set col [xschem getprop rect 2 $graph_selected color] set col [lreplace $col $wave $wave $graph_sel_color] xschem setprop -fast rect 2 $graph_selected color $col xschem draw_graph $graph_selected } } # set txt [xschem getprop rect 2 $n node 2] # set txt [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] # return first and last indexes of nodes in txt proc graph_tag_nodes {txt} { global graph_selected graph_sel_color # delete old tags if { [winfo exists .graphdialog.center.right.text1] } { eval .graphdialog.center.right.text1 tag delete [ .graphdialog.center.right.text1 tag names] set col [xschem getprop rect 2 $graph_selected color] set col [string trim $col " \n"] } set start 0 if {[regexp {^tcleval\(} $txt]} { set start 8 regsub {\)[ \n]*$} $txt {} txt } set regx {("[^"]+")|([^\n]+)} set tt {} set cc {} while {[regexp -indices -start $start $regx $txt idxall]} { lappend tt [lindex $idxall 0] set ccc [lindex $idxall 1] lappend cc $ccc set start [expr {$ccc + 1}] } if { [winfo exists .graphdialog.center.right.text1] } { set n 0 if { $tt ne {} } { foreach t $tt c $cc { set col_idx [lindex $col $n] # add missing colors if {$col_idx eq {}} { set col_idx $graph_sel_color lappend col $graph_sel_color } set b [lindex $tctx::colors $col_idx] .graphdialog.center.right.text1 tag add t$n "1.0 + $t chars" "1.1 + $c chars" if { [info tclversion] > 8.4} { .graphdialog.center.right.text1 tag configure t$n -background $b -selectbackground grey40 } else { .graphdialog.center.right.text1 tag configure t$n -background $b } incr n } # remove excess colors set col [lrange $col 0 [expr {$n - 1}]] } else { set col {} } xschem setprop -fast rect 2 $graph_selected color $col } return [list $tt $cc] } # tag nodes in text widget with assigned colors proc graph_update_nodelist {} { global graph_selected graph_sel_color graph_schname if { [xschem get schname] ne $graph_schname } return # tagging nodes in text widget: set txt [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] graph_tag_nodes $txt } proc graph_fill_listbox {} { global graph_selected set pattern [.graphdialog.center.left.search get] set retval {} set autoload [uplevel #0 {subst [xschem getprop rect 2 $graph_selected autoload 2]}] set rawfile [xschem getprop rect 2 $graph_selected rawfile] if {$rawfile ne {}} { if {![catch {eval uplevel #0 {subst $rawfile}} res]} { set rawfile $res } } set sim_type [uplevel #0 {subst [xschem getprop rect 2 $graph_selected sim_type 2]}] if {$autoload ne {} && $autoload } { set autoload read} else {set autoload switch} # puts "graph_fill_listbox: $rawfile $sim_type" if {$rawfile ne {}} { if {$sim_type eq {table}} { set res [xschem raw table_read $rawfile $sim_type] } else { set res [xschem raw $autoload $rawfile $sim_type] } if {$res} { set retval [graph_get_signal_list [xschem raw_query list] $pattern] xschem raw switch_back } # puts "switch back" } elseif {[xschem raw loaded] != -1} { set retval [graph_get_signal_list [xschem raw_query list] $pattern] } .graphdialog.center.left.list1 delete 0 end eval .graphdialog.center.left.list1 insert 0 $retval } # called from event handlers (OK, KeyRelease, DoubleClick) in graph_edit_properties proc graph_update_node {node} { global graph_selected graph_update_nodelist # add a backslash before " and \ characters # note the double escaping for regsub replace string regsub -all {[\\"]} $node {\\&} node_quoted graph_push_undo xschem setprop -fast rect 2 $graph_selected node $node_quoted xschem draw_graph $graph_selected } proc graph_update_div {graph_selected div} { set divis [.graphdialog.top2.$div get] if {[regexp {^[0-9]+$} $divis] && $divis < 1} { set divis 1 .graphdialog.top2.$div delete 0 end .graphdialog.top2.$div insert 0 $divis } graph_push_undo xschem setprop rect 2 $graph_selected $div $divis xschem draw_graph $graph_selected } proc graph_set_linewidth {graph_sel} { global graph_linewidth_mult set custom_lw [.graphdialog.top.lwe get] if {[regexp {^[ \t]*$} $custom_lw]} { set custom_lw $graph_linewidth_mult } graph_push_undo if {$custom_lw != $graph_linewidth_mult} { xschem setprop rect 2 $graph_sel linewidth_mult $custom_lw } else { xschem setprop rect 2 $graph_sel linewidth_mult ;# delete attribute since it is default } } proc raw_is_loaded {rawfile type} { set loaded 0 set r [catch "uplevel #0 {subst $rawfile}" res] if {$r == 0} { set rawfile $res } else { return $loaded } set rawlist [lrange [xschem raw info] 2 end] foreach {n f t} $rawlist { if {$rawfile eq $f && $type eq $t} { set loaded 1 break } } return $loaded } proc set_rect_flags {graph_selected} { global graph_private_cursor graph_unlocked if {$graph_private_cursor} { set private_cursor {,private_cursor} } else { set private_cursor {} } if {$graph_unlocked} { set unlocked {,unlocked} } else { set unlocked {} } xschem setprop -fast rect 2 $graph_selected flags "graph$unlocked$private_cursor" } proc graphdialog_set_raw_props {} { global graph_selected xschem setprop -fast rect 2 $graph_selected rawfile [.graphdialog.center.right.rawentry get] xschem setprop -fast rect 2 $graph_selected sim_type [.graphdialog.center.right.list get] graph_fill_listbox } proc graph_edit_properties {n} { global graph_bus graph_sort graph_digital graph_selected graph_sel_color graph_legend global graph_unlocked graph_schname graph_logx graph_logy cadlayers graph_rainbow global graph_linewidth_mult graph_change_done has_x graph_dialog_default_geometry global graph_autoload graph_private_cursor if { ![info exists has_x]} {return} set graph_change_done 0 if { [winfo exists .graphdialog]} { set graph_dialog_default_geometry [winfo geometry .graphdialog] } catch {destroy .graphdialog} toplevel .graphdialog -class Dialog ;# -width 1 -height 1 wm withdraw .graphdialog wm transient .graphdialog [xschem get topwindow] update idletasks set graph_selected $n set graph_schname [xschem get schname] set_ne graph_sel_color 4 set_ne graph_sort 0 set graph_rainbow 0 if {[xschem getprop rect 2 $n rainbow] == 1} {set graph_rainbow 1} set graph_logx 0 if {[xschem getprop rect 2 $n logx] == 1} {set graph_logx 1} set graph_logy 0 if {[xschem getprop rect 2 $n logy] == 1} {set graph_logy 1} set graph_legend 1 if {[xschem getprop rect 2 $n legend] == 0} {set graph_legend 0} set graph_digital 0 if {[xschem getprop rect 2 $n digital] == 1} {set graph_digital 1} if {[regexp {private_cursor} [xschem getprop rect 2 $n flags]]} { set graph_private_cursor 1 } else { set graph_private_cursor 0 } if {[regexp {unlocked} [xschem getprop rect 2 $n flags]]} { set graph_unlocked 1 } else { set graph_unlocked 0 } set autoload [xschem getprop rect 2 $n autoload] if {$autoload ne {} && $autoload} { set graph_autoload 1 } else { set graph_autoload 0 } frame .graphdialog.top # another row of buttons frame .graphdialog.top2 frame .graphdialog.top3 panedwindow .graphdialog.center -orient horiz frame .graphdialog.bottom frame .graphdialog.center.left frame .graphdialog.center.right .graphdialog.center add .graphdialog.center.left .graphdialog.center.right pack .graphdialog.top -side top -fill x pack .graphdialog.top2 -side top -fill x pack .graphdialog.top3 -side top -fill x pack .graphdialog.center -side top -fill both -expand yes pack .graphdialog.bottom -side top -fill x # center-left frame label .graphdialog.center.left.labsearch -text Search: entry .graphdialog.center.left.search -width 10 entry_replace_selection .graphdialog.center.left.search button .graphdialog.center.left.add -text Add -command { graph_add_nodes; graph_update_nodelist } listbox .graphdialog.center.left.list1 -width 20 -height 5 -selectmode extended \ -yscrollcommand {.graphdialog.center.left.yscroll set} \ -xscrollcommand {.graphdialog.center.left.xscroll set} scrollbar .graphdialog.center.left.yscroll -command {.graphdialog.center.left.list1 yview} scrollbar .graphdialog.center.left.xscroll -orient horiz -command {.graphdialog.center.left.list1 xview} grid .graphdialog.center.left.labsearch .graphdialog.center.left.search .graphdialog.center.left.add grid .graphdialog.center.left.list1 - - .graphdialog.center.left.yscroll -sticky nsew grid .graphdialog.center.left.xscroll - - -sticky nsew grid rowconfig .graphdialog.center.left 0 -weight 0 grid rowconfig .graphdialog.center.left 1 -weight 1 -minsize 2c grid columnconfig .graphdialog.center.left 0 -weight 1 grid columnconfig .graphdialog.center.left 1 -weight 1 # center right frame checkbutton .graphdialog.center.right.autoload -text {Auto load} -variable graph_autoload \ -command { if {$graph_autoload} { xschem setprop -fast rect 2 $graph_selected autoload 1 } else { xschem setprop -fast rect 2 $graph_selected autoload 0 } } label .graphdialog.center.right.lab2 -text { Sim type:} if { [info tclversion] > 8.4} { ttk::combobox .graphdialog.center.right.list \ -values {dc ac tran op sp spectrum noise constants table} -width 9 } else { entry .graphdialog.center.right.list -width 4 entry_replace_selection .graphdialog.center.right.list } if { [info tclversion] > 8.4} { bind .graphdialog.center.right.list <> { xschem setprop -fast rect 2 $graph_selected sim_type [.graphdialog.center.right.list get] graph_fill_listbox } if { [xschem getprop rect 2 $graph_selected sim_type 2] ne {}} { .graphdialog.center.right.list set [xschem getprop rect 2 $graph_selected sim_type 2] } else { .graphdialog.center.right.list set {} } } else { .graphdialog.center.right.list delete 0 end if { [xschem getprop rect 2 $graph_selected sim_type 2] ne {}} { .graphdialog.center.right.list insert 0 [xschem getprop rect 2 $graph_selected sim_type 2] } else { .graphdialog.center.right.list insert 0 {} } } bind .graphdialog.center.right.list { xschem setprop -fast rect 2 $graph_selected sim_type [.graphdialog.center.right.list get] graph_fill_listbox } entry .graphdialog.center.right.rawentry -width 20 entry_replace_selection .graphdialog.center.right.rawentry button .graphdialog.center.right.rawbut -text {Raw file:} -command { regsub {/$} $netlist_dir {} netlist_dir .graphdialog.center.right.rawentry delete 0 end .graphdialog.center.right.rawentry insert 0 [string map [list $netlist_dir {$netlist_dir}] [select_raw]] graphdialog_set_raw_props } bind .graphdialog.center.right.rawentry graphdialog_set_raw_props bind .graphdialog.center.right.rawentry graphdialog_set_raw_props .graphdialog.center.right.rawentry insert 0 [xschem getprop rect 2 $graph_selected rawfile 2] .graphdialog.center.right.rawentry xview moveto 1 text .graphdialog.center.right.text1 -undo 1 -wrap none -width 50 -height 5 -background grey90 -fg black \ -insertbackground grey40 -exportselection 1 \ -yscrollcommand {.graphdialog.center.right.yscroll set} \ -xscrollcommand {.graphdialog.center.right.xscroll set} scrollbar .graphdialog.center.right.yscroll -command {.graphdialog.center.right.text1 yview} scrollbar .graphdialog.center.right.xscroll -orient horiz -command {.graphdialog.center.right.text1 xview} grid .graphdialog.center.right.autoload \ .graphdialog.center.right.lab2 .graphdialog.center.right.list \ .graphdialog.center.right.rawbut .graphdialog.center.right.rawentry - grid configure .graphdialog.center.right.rawentry -sticky ew grid .graphdialog.center.right.text1 - - - - .graphdialog.center.right.yscroll -sticky nsew grid .graphdialog.center.right.xscroll - - - - - -sticky ew grid rowconfig .graphdialog.center.right 0 -weight 0 grid rowconfig .graphdialog.center.right 1 -weight 1 -minsize 3c grid rowconfig .graphdialog.center.right 2 -weight 0 grid columnconfig .graphdialog.center.right 0 -weight 0 grid columnconfig .graphdialog.center.right 1 -weight 0 grid columnconfig .graphdialog.center.right 2 -weight 0 grid columnconfig .graphdialog.center.right 3 -weight 0 grid columnconfig .graphdialog.center.right 4 -weight 1 grid columnconfig .graphdialog.center.right 5 -weight 0 # bottom frame button .graphdialog.bottom.cancel -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 { 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"] xschem setprop -fast rect 2 $graph_selected x1 [.graphdialog.top3.xmin get] xschem setprop -fast rect 2 $graph_selected x2 [.graphdialog.top3.xmax get] xschem setprop -fast rect 2 $graph_selected y1 [.graphdialog.top3.ymin get] xschem setprop -fast rect 2 $graph_selected y2 [.graphdialog.top3.ymax get] set_rect_flags $graph_selected } set graph_dialog_default_geometry [winfo geometry .graphdialog] destroy .graphdialog set graph_selected {} set graph_schname {} } button .graphdialog.bottom.apply -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"] xschem setprop -fast rect 2 $graph_selected x1 [.graphdialog.top3.xmin get] xschem setprop -fast rect 2 $graph_selected x2 [.graphdialog.top3.xmax get] xschem setprop -fast rect 2 $graph_selected y1 [.graphdialog.top3.ymin get] xschem setprop -fast rect 2 $graph_selected y2 [.graphdialog.top3.ymax get] set_rect_flags $graph_selected } } # top packs pack .graphdialog.bottom.ok -side left 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 pack .graphdialog.bottom.r$i -side left } # top2 frame checkbutton .graphdialog.top.legend -text {Legend} -variable graph_legend -indicatoron 1 \ -command { if { [xschem get schname] eq $graph_schname } { graph_push_undo xschem setprop -fast rect 2 $graph_selected legend $graph_legend xschem draw_graph $graph_selected } } label .graphdialog.top2.labunitx -text {X units} spinbox .graphdialog.top2.unitx -values {f p n u m 1 k M G T} -width 2 \ -command { graph_push_undo xschem setprop rect 2 $graph_selected unitx [.graphdialog.top2.unitx get] xschem draw_graph $graph_selected } label .graphdialog.top2.labunity -text { Y units} spinbox .graphdialog.top2.unity -values {f p n u m 1 k M G T} -width 2 \ -command { graph_push_undo xschem setprop rect 2 $graph_selected unity [.graphdialog.top2.unity get] xschem draw_graph $graph_selected } label .graphdialog.top2.labdivx -text { X div.} entry .graphdialog.top2.divx -width 2 entry_replace_selection .graphdialog.top2.divx bind .graphdialog.top2.divx { graph_update_div $graph_selected divx } label .graphdialog.top2.labdivy -text { Y div.} entry .graphdialog.top2.divy -width 2 entry_replace_selection .graphdialog.top2.divy bind .graphdialog.top2.divy { graph_update_div $graph_selected divy } label .graphdialog.top2.labsubdivx -text { X subdiv.} entry .graphdialog.top2.subdivx -width 2 entry_replace_selection .graphdialog.top2.subdivx bind .graphdialog.top2.subdivx { graph_push_undo xschem setprop rect 2 $graph_selected subdivx [.graphdialog.top2.subdivx get] xschem draw_graph $graph_selected } label .graphdialog.top2.labsubdivy -text { Y subdiv.} entry .graphdialog.top2.subdivy -width 2 entry_replace_selection .graphdialog.top2.subdivy bind .graphdialog.top2.subdivy { graph_push_undo xschem setprop rect 2 $graph_selected subdivy [.graphdialog.top2.subdivy get] xschem draw_graph $graph_selected } label .graphdialog.top2.labsweep -text { Sweep} entry .graphdialog.top2.sweep -width 10 entry_replace_selection .graphdialog.top2.sweep label .graphdialog.top2.labmode -text {Mode} if { [info tclversion] > 8.4} { ttk::combobox .graphdialog.top2.mode -values {Line HistoV HistoH} -width 6 bind .graphdialog.top2.mode <> { graph_push_undo xschem setprop rect 2 $graph_selected mode [.graphdialog.top2.mode get] xschem draw_graph $graph_selected } } else { spinbox .graphdialog.top2.mode -values {Line HistoV HistoH} -width 6 \ -command { graph_push_undo xschem setprop rect 2 $graph_selected mode [.graphdialog.top2.mode get] xschem draw_graph $graph_selected } } # bind .graphdialog.top2.sweep { # graph_push_undo # xschem setprop rect 2 $graph_selected sweep [.graphdialog.top2.sweep get] # xschem draw_graph $graph_selected # } bind .graphdialog.top2.sweep { graph_push_undo xschem setprop rect 2 $graph_selected sweep [.graphdialog.top2.sweep get] xschem draw_graph $graph_selected } .graphdialog.top2.sweep insert 0 [xschem getprop rect 2 $graph_selected sweep] set graph_divx [xschem getprop rect 2 $graph_selected divx] if {$graph_divx eq {}} { set graph_divx 5} .graphdialog.top2.divx insert 0 $graph_divx set graph_divy [xschem getprop rect 2 $graph_selected divy] if {$graph_divy eq {}} { set graph_divy 5} .graphdialog.top2.divy insert 0 $graph_divy set graph_subdivx [xschem getprop rect 2 $graph_selected subdivx] if {$graph_subdivx eq {}} { set graph_subdivx 1} .graphdialog.top2.subdivx insert 0 $graph_subdivx set graph_subdivy [xschem getprop rect 2 $graph_selected subdivy] if {$graph_subdivy eq {}} { set graph_subdivy 1} .graphdialog.top2.subdivy insert 0 $graph_subdivy set graph_unitx [xschem getprop rect 2 $graph_selected unitx] if {$graph_unitx eq {}} { set graph_unitx 1} .graphdialog.top2.unitx set $graph_unitx set graph_unity [xschem getprop rect 2 $graph_selected unity] if {$graph_unity eq {}} { set graph_unity 1} .graphdialog.top2.unity set $graph_unity set graph_mode [xschem getprop rect 2 $graph_selected mode] if {$graph_mode eq {}} { set graph_mode Line} .graphdialog.top2.mode set $graph_mode pack .graphdialog.top2.labunitx .graphdialog.top2.unitx \ .graphdialog.top2.labunity .graphdialog.top2.unity -side left pack .graphdialog.top2.labdivx .graphdialog.top2.divx \ .graphdialog.top2.labdivy .graphdialog.top2.divy \ .graphdialog.top2.labsubdivx .graphdialog.top2.subdivx \ .graphdialog.top2.labsubdivy .graphdialog.top2.subdivy -side left pack .graphdialog.top2.labmode .graphdialog.top2.mode .graphdialog.top2.labsweep -side left pack .graphdialog.top2.sweep -side left -fill x -expand yes # top frame checkbutton .graphdialog.top.bus -text Bus -padx 2 -variable graph_bus checkbutton .graphdialog.top.incr -text {Incr. sort} -variable graph_sort -indicatoron 1 \ -command graph_fill_listbox checkbutton .graphdialog.top.rainbow -text {Rainbow col.} -variable graph_rainbow \ -command { if { [xschem get schname] eq $graph_schname } { graph_push_undo xschem setprop -fast rect 2 $graph_selected rainbow $graph_rainbow xschem draw_graph $graph_selected } } label .graphdialog.top.lw -text " Line width:" entry .graphdialog.top.lwe -width 4 entry_replace_selection .graphdialog.top.lwe bind .graphdialog.top.lwe { graph_set_linewidth $graph_selected xschem draw_graph $graph_selected } set custom_lw [xschem getprop rect 2 $n linewidth_mult] if {[regexp {^[ \t]*$} $custom_lw]} { .graphdialog.top.lwe insert 0 $graph_linewidth_mult } else { .graphdialog.top.lwe insert 0 $custom_lw } label .graphdialog.top.labdset -text { Dataset} entry .graphdialog.top.dset -width 4 entry_replace_selection .graphdialog.top.dset bind .graphdialog.top.dset { graph_push_undo xschem setprop rect 2 $graph_selected dataset [.graphdialog.top.dset get] xschem draw_graph $graph_selected } .graphdialog.top.dset insert 0 [xschem getprop rect 2 $graph_selected dataset] checkbutton .graphdialog.top.priv_curs -text {Priv. Cursor} -variable graph_private_cursor \ -command {set_rect_flags $graph_selected } checkbutton .graphdialog.top.unlocked -text {Unlock. X axis} -variable graph_unlocked \ -command {set_rect_flags $graph_selected } checkbutton .graphdialog.top.dig -text {Digital} -variable graph_digital -indicatoron 1 \ -command { if { [xschem get schname] eq $graph_schname } { graph_push_undo xschem setprop -fast rect 2 $graph_selected digital $graph_digital xschem draw_graph $graph_selected } } label .graphdialog.top3.xlabmin -text { X min:} entry .graphdialog.top3.xmin -width 7 entry_replace_selection .graphdialog.top3.xmin bind .graphdialog.top3.xmin { graph_push_undo xschem setprop rect 2 $graph_selected x1 [.graphdialog.top3.xmin get] xschem draw_graph $graph_selected } label .graphdialog.top3.xlabmax -text { X max:} entry .graphdialog.top3.xmax -width 7 entry_replace_selection .graphdialog.top3.xmax bind .graphdialog.top3.xmax { graph_push_undo xschem setprop rect 2 $graph_selected x2 [.graphdialog.top3.xmax get] xschem draw_graph $graph_selected } label .graphdialog.top3.ylabmin -text { Y min:} entry .graphdialog.top3.ymin -width 7 entry_replace_selection .graphdialog.top3.ymin bind .graphdialog.top3.ymin { graph_push_undo xschem setprop rect 2 $graph_selected y1 [.graphdialog.top3.ymin get] xschem draw_graph $graph_selected } label .graphdialog.top3.ylabmax -text { Y max:} entry .graphdialog.top3.ymax -width 7 entry_replace_selection .graphdialog.top3.ymax bind .graphdialog.top3.ymax { graph_push_undo xschem setprop rect 2 $graph_selected y2 [.graphdialog.top3.ymax get] xschem draw_graph $graph_selected } label .graphdialog.top3.xlabmag -text { X/Y lab mag:} entry .graphdialog.top3.xmag -width 4 entry_replace_selection .graphdialog.top3.xmag bind .graphdialog.top3.xmag { graph_push_undo xschem setprop rect 2 $graph_selected xlabmag [.graphdialog.top3.xmag get] xschem draw_graph $graph_selected } label .graphdialog.top3.ylabmag -text { } entry .graphdialog.top3.ymag -width 4 entry_replace_selection .graphdialog.top3.ymag bind .graphdialog.top3.ymag { graph_push_undo xschem setprop rect 2 $graph_selected ylabmag [.graphdialog.top3.ymag get] xschem draw_graph $graph_selected } pack .graphdialog.top.legend -side left pack .graphdialog.top.incr -side left pack .graphdialog.top.bus -side left pack .graphdialog.top.priv_curs -side left pack .graphdialog.top.dig -side left pack .graphdialog.top.unlocked -side left pack .graphdialog.top.rainbow -side left pack .graphdialog.top.lw -side left pack .graphdialog.top.lwe -side left pack .graphdialog.top.labdset -side left pack .graphdialog.top.dset -side left .graphdialog.top3.ymin insert 0 [xschem getprop rect 2 $graph_selected y1] .graphdialog.top3.ymax insert 0 [xschem getprop rect 2 $graph_selected y2] .graphdialog.top3.xmin insert 0 [xschem getprop rect 2 $graph_selected x1] .graphdialog.top3.xmax insert 0 [xschem getprop rect 2 $graph_selected x2] .graphdialog.top3.xmag insert 0 [xschem getprop rect 2 $graph_selected xlabmag] .graphdialog.top3.ymag insert 0 [xschem getprop rect 2 $graph_selected ylabmag] # top3 frame set graph_rainbow [xschem getprop rect 2 $graph_selected rainbow] set graph_logx [xschem getprop rect 2 $graph_selected logx] set graph_logy [xschem getprop rect 2 $graph_selected logy] if { $graph_rainbow eq {} } { set graph_rainbow 0 } if { $graph_logx eq {} } { set graph_logx 0 } if { $graph_logy eq {} } { set graph_logy 0 } checkbutton .graphdialog.top3.logx -padx 2 -text {Log X} -variable graph_logx \ -command { if { [xschem get schname] eq $graph_schname } { graph_push_undo xschem setprop -fast rect 2 $graph_selected logx $graph_logx if { $graph_logx eq 1} { graph_push_undo xschem setprop -fast rect 2 $graph_selected subdivx 8 .graphdialog.top2.subdivx delete 0 end .graphdialog.top2.subdivx insert 0 8 xschem setprop rect 2 $graph_selected fullxzoom xschem setprop rect 2 $graph_selected fullyzoom } else { graph_push_undo xschem setprop -fast rect 2 $graph_selected subdivx 4 .graphdialog.top2.subdivx delete 0 end .graphdialog.top2.subdivx insert 0 4 xschem setprop rect 2 $graph_selected fullxzoom xschem setprop rect 2 $graph_selected fullyzoom } xschem draw_graph $graph_selected } } checkbutton .graphdialog.top3.logy -text {Log Y} -variable graph_logy \ -command { if { [xschem get schname] eq $graph_schname } { graph_push_undo xschem setprop -fast rect 2 $graph_selected logy $graph_logy if { $graph_logy eq 1} { graph_push_undo xschem setprop -fast rect 2 $graph_selected subdivy 8 .graphdialog.top2.subdivy delete 0 end .graphdialog.top2.subdivy insert 0 8 xschem setprop rect 2 $graph_selected fullyzoom } else { graph_push_undo xschem setprop -fast rect 2 $graph_selected subdivy 4 .graphdialog.top2.subdivy delete 0 end .graphdialog.top2.subdivy insert 0 4 xschem setprop rect 2 $graph_selected fullyzoom } xschem draw_graph $graph_selected } } pack .graphdialog.top3.logx .graphdialog.top3.logy \ .graphdialog.top3.xlabmin .graphdialog.top3.xmin .graphdialog.top3.xlabmax .graphdialog.top3.xmax \ .graphdialog.top3.ylabmin .graphdialog.top3.ymin .graphdialog.top3.ylabmax .graphdialog.top3.ymax \ .graphdialog.top3.xlabmag .graphdialog.top3.xmag .graphdialog.top3.ylabmag .graphdialog.top3.ymag \ -fill x -expand yes -side left # binding bind .graphdialog.center.left.search { graph_fill_listbox } bind .graphdialog.center.left.list1 { graph_add_nodes if { [xschem get schname] eq $graph_schname } { graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"] } } bind .graphdialog.center.right.text1 { if { [xschem get schname] eq $graph_schname } { graph_update_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"] } } bind .graphdialog { .graphdialog.bottom.ok invoke } bind .graphdialog { .graphdialog.bottom.cancel invoke } wm protocol .graphdialog WM_DELETE_WINDOW { .graphdialog.bottom.cancel invoke } # fill data in left listbox graph_fill_listbox # fill data in right textbox set plotted_nodes [xschem getprop rect 2 $n node 2] if {[string length $plotted_nodes] > 0 && [string index $plotted_nodes end] ne "\n"} {append plotted_nodes \n} .graphdialog.center.right.text1 insert 1.0 $plotted_nodes graph_update_nodelist # add stuff in textbox at end of line + 1 char (after newline) # .graphdialog.center.right.text1 insert {insert lineend + 1 char} foo\n # tkwait window .graphdialog wm deiconify .graphdialog if {$graph_dialog_default_geometry ne {}} { wm geometry .graphdialog $graph_dialog_default_geometry} } proc graph_show_measure {{action show}} { global measure_id measure_text has_x if {![info exists has_x]} return; set_ne measure_text "y=\nx=" if { [info exists measure_id] } { after cancel $measure_id unset measure_id } destroy .measure if {$action eq {stop}} { return } set measure_id [after 400 { unset measure_id toplevel .measure -background {} label .measure.lab -text $measure_text -background black -fg yellow -justify left pack .measure.lab wm overrideredirect .measure 1 wm geometry .measure +[expr {[winfo pointerx .measure] +10}]+[expr {[winfo pointery .measure] -8}] }] } # launch a terminal shell, if 'curpath' is given set path to 'curpath' proc get_shell { {curpath {}} } { global netlist_dir debug_var global terminal regsub {/$} $netlist_dir {} netlist_dir set save [pwd] if { $curpath ne {} } { cd $curpath eval execute 0 $terminal } else { eval execute 0 $terminal } cd $save } proc edit_netlist {netlist } { global netlist_dir debug_var global editor terminal OS regsub {/$} $netlist_dir {} netlist_dir set netlist_type [xschem get netlist_type] if { [regexp vim $editor] } { set ftype "-c \":set filetype=$netlist_type\"" } else { set ftype {} } if { [set_netlist_dir 0] ne "" } { set save [pwd] cd $netlist_dir if {$OS == "Windows"} { set cmd "$editor \"${netlist}\"" eval exec $cmd & } else { eval execute 0 $editor $ftype \"${netlist}\" } cd $save } return {} } # 20180926 # global_initdir should be set to: # INITIALLOADDIR for load # INITIALINSTDIR for instance placement # ext: .sch or .sym or .sch.sym or .sym.sch # proc save_file_dialog { msg ext global_initdir {initialf {}} {overwrt 1} } { upvar #0 $global_initdir initdir set temp $initdir if { $initialf ne {}} { set initialdir [file dirname $initialf] set initialf [file tail $initialf] } else { set initialdir $initdir set initialf {} } set initdir $initialdir set r [load_file_dialog $msg $ext $global_initdir 0 $overwrt $initialf] set initdir $temp return $r } # opens indicated instance (or selected one) into a separate tab/window # keeping the hierarchy path, as it was descended into (as with 'e' key). proc open_sub_schematic {{inst {}} {inst_number 0}} { global search_schematic set rawfile {} set n_sel [xschem get lastsel] if { $inst eq {} && $n_sel == 0} { if {$search_schematic == 1} { set f [abs_sym_path [xschem get current_name] {.sch}] } else { set f [file rootname [xschem get schname]].sch } xschem new_schematic create {} $f return 1 } elseif { $inst eq {} && $n_sel == 1} { set inst [lindex [xschem selected_set] 0] xschem unselect_all } else { set instlist {} # get list of instances (instance names only) foreach {i s t} [xschem instance_list] {lappend instlist $i} # if provided $inst is not in the list return 0 if {[lsearch -exact $instlist $inst] == -1} {return 0} } # open a new top level in another window / tab if {[xschem raw loaded] >= 0} { set rawfile [xschem raw_query rawfile] set sim_type [xschem raw_query sim_type] } set res [xschem schematic_in_new_window force] # if successfull descend into indicated sub-schematic if {$res} { xschem new_schematic switch [xschem get last_created_window] if { $rawfile ne {}} { if {$sim_type eq {op}} { xschem annotate_op $rawfile } else { xschem raw_read $rawfile $sim_type } } xschem select instance $inst fast xschem descend return 1 } return 0 } proc is_xschem_file {f} { if { ![file exists $f] } { return 0 } elseif { [file isdirectory $f] } { return 0 } set a [catch {open "$f" r} fd] set ret 0 set score 0 set instances 0 set nline 0 set generator 0 if {$a} { puts stderr "Can not open file $f" } else { fconfigure $fd -translation binary while { [gets $fd line] >=0 } { # this is a script. not an xschem file if { $nline == 0 && [regexp {^#!} $line] } { #### too dangerous executing an arbitrary script... # close $fd # set fd [open "|$f"] set generator 1 # continue } if { [regexp {^[TKGVSE] \{} $line] } { incr score } if { [regexp {^[BL] +[0-9]+ +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +\{} $line] } {incr score} if { [regexp {^N +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +[-0-9.eE]+ +\{} $line] } {incr score} if { [regexp {^C +\{[^{}]+\} +[-0-9.eE]+ +[-0-9.eE]+ +[0-3]+ +[0-3]+ +\{} $line] } {incr instances; incr score} if { [regexp "^v\[ \t\]+\{xschem\[ \t\]+version\[ \t\]*=.*\[ \t\]+file_version\[ \t\]*=" $line] } { set ret 1 } incr nline } if { $score > 4 } { set ret 1} ;# Heuristic decision :-) if {$generator eq {1}} { set ret GENERATOR } elseif { $ret ne {0}} { if { $instances} { set ret SCHEMATIC } else { set ret SYMBOL } } close $fd } # puts "ret=$ret score=$score" return $ret } # "xschem hash_string" in scheduler.c is faster proc hash_string {s} { set hash 5381 set len [string length $s] for {set i 0} { $i < $len} { incr i} { set c [string index $s $i] set ascii [scan $c %c] set hash [expr {($hash + ($hash << 5) + $ascii)%4294967296} ] } return $hash } ## Recent component toolbar namespace eval c_toolbar { # Create a variable inside the namespace variable c_t variable i set c_t(w) .load.l.recent set c_t(hash) [xschem hash_string $::XSCHEM_LIBRARY_PATH] set c_t(n) 25 set c_t(top) 0 for {set i 0} {$i < $c_t(n)} {incr i} { set c_t($i,text) {} set c_t($i,command) {} set c_t($i,file) {} } proc cleanup {} { variable c_t if {![info exists c_t(n)]} return set j 0 set n $c_t(n) set top $c_t(top) set i $top while {1} { set f [abs_sym_path $c_t($i,file)] if { $c_t($i,text) eq {} } {break} if { $j } { set k [expr {$i - $j}] if {$k < 0 } { set k [expr {$k + $n}]} set c_t($k,text) $c_t($i,text) set c_t($k,command) $c_t($i,command) set c_t($k,file) $c_t($i,file) set c_t($i,text) {} set c_t($i,command) {} set c_t($i,file) {} } if {$f ne {} && ![file exists $f]} { incr j } elseif {[array names files -exact $f] ne {}} { incr j } set files($f) 1 set i [expr {($i + 1) % $n} ] if {$i == $top} break } } proc display {} { global has_x variable c_t if {![info exists has_x]} {return} if { [winfo exists $c_t(w)]} { set w $c_t(w) set n $c_t(n) cleanup destroy $w.title for {set i 0} {$i < $n} {incr i} { destroy $w.b$i } set i $c_t(top) button $w.title -text Recent -pady 0 -padx 0 -state disabled -disabledforeground black \ -background grey60 -borderwidth 0 -font {TkDefaultFont 12 bold} pack $w.title -side top -fill x while {1} { button $w.b$i -text $c_t($i,text) -pady 0 -padx 0 -command $c_t($i,command) -takefocus 0 pack $w.b$i -side top -fill x set i [expr {($i + 1) % $n}] if { $i == $c_t(top) } break } } } proc add {f} { variable c_t for {set i 0} {$i < $c_t(n)} {incr i} { if { $c_t($i,file) eq $f } { return 0} } set ret 0 set ret 1 set i [expr { ($c_t(top)-1) % $c_t(n) } ];# last element set c_t($i,file) $f set c_t($i,command) " set file_dialog_retval {} xschem abort_operation file_dialog_display_preview {$f} xschem place_symbol {$f} " set c_t($i,text) [file tail [file rootname $f]] set c_t(top) $i if {$ret} {write_recent_file} return $ret } } ## end c_toolbar namespace proc file_dialog_set_colors1 {} { global file_dialog_files1 dircolor for {set i 0} { $i< [.load.l.paneleft.list index end] } { incr i} { set maxlen 0 set name "[lindex $file_dialog_files1 $i]" .load.l.paneleft.list itemconfigure $i -foreground black -selectforeground black foreach j [array names dircolor] { set pattern $j set color $dircolor($j) set len [string length [regexp -inline $pattern $name]] if { $len > $maxlen } { .load.l.paneleft.list itemconfigure $i -foreground $color -selectforeground $color set maxlen $len } } } } proc file_dialog_set_colors2 {} { global file_dialog_index1 file_dialog_files2 dircolor file_dialog_files1 set dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]] for {set i 0} { $i< [.load.l.paneright.f.list index end] } { incr i} { set maxlen 0 set name "$dir1/[lindex $file_dialog_files2 $i]" if {[ file isdirectory $name]} { .load.l.paneright.f.list itemconfigure $i -foreground blue foreach j [array names dircolor] { set pattern $j set color $dircolor($j) set len [string length [regexp -inline $pattern $dir1]] # puts "len=$len\npattern=$pattern\nname=$name\n\n\n" if { $len > $maxlen } { .load.l.paneright.f.list itemconfigure $i -foreground $color -selectforeground $color set maxlen $len } } } else { .load.l.paneright.f.list itemconfigure $i -foreground black } } } proc file_dialog_set_names1 {} { global file_dialog_names1 file_dialog_files1 load_file_dialog_fullpath set file_dialog_names1 {} foreach i $file_dialog_files1 { if { $load_file_dialog_fullpath == 1} { set item $i } else { set item [get_cell $i 0] } lappend file_dialog_names1 $item } } proc file_dialog_set_home {dir} { global pathlist file_dialog_files1 file_dialog_index1 file_dialog_names1 set curr_dirname [xschem get current_dirname] .load.l.paneleft.list selection clear 0 end if { $dir eq {.}} { set dir $curr_dirname} # puts "set home: dir=$dir, pathlist=$pathlist" set pl {} foreach path_elem $pathlist { if { ![string compare $path_elem .]} { set path_elem $curr_dirname } lappend pl $path_elem } set i [lsearch -exact $pl $dir] if { $i>=0 } { set file_dialog_files1 $pathlist file_dialog_set_names1 update file_dialog_set_colors1 .load.l.paneleft.list xview moveto 1 set file_dialog_index1 $i .load.l.paneleft.list selection set $file_dialog_index1 } else { set file_dialog_files1 [list $dir] file_dialog_set_names1 update file_dialog_set_colors1 .load.l.paneleft.list xview moveto 1 set file_dialog_index1 0 .load.l.paneleft.list selection set 0 } } proc setglob {dir} { global file_dialog_globfilter file_dialog_files2 OS # puts "setglob: $dir, filter=$file_dialog_globfilter" set file_dialog_files2 [lsort [glob -nocomplain -directory $dir -tails -type d .* *]] if { $file_dialog_globfilter eq {*}} { set file_dialog_files2 ${file_dialog_files2}\ [lsort [ glob -nocomplain -directory $dir -tails -type {f} .* $file_dialog_globfilter]] } else { if {$OS == "Windows"} { regsub {:} $file_dialog_globfilter {\:} file_dialog_globfilter } if {![catch {glob -nocomplain -directory $dir -tails -type {f} $file_dialog_globfilter} res]} { set flist $res } else { set flist [glob -nocomplain -directory $dir -tails -type {f} {*}] } set file_dialog_files2 ${file_dialog_files2}\ [lsort $flist] } } proc load_file_dialog_mkdir {dir} { global file_dialog_dir1 has_x if { $dir ne {} } { if {[catch {file mkdir "${file_dialog_dir1}/$dir"} err]} { puts $err if {[info exists has_x]} { tk_messageBox -message "$err" -icon error -parent [xschem get topwindow] -type ok } } setglob ${file_dialog_dir1} file_dialog_set_colors2 } } proc load_file_dialog_up {dir} { global file_dialog_dir1 bind .load.l.paneright.draw {} bind .load.l.paneright.draw {} .load.l.paneright.draw configure -background white set d [file dirname $dir] if { [file isdirectory $d]} { file_dialog_set_home $d setglob $d file_dialog_set_colors2 set file_dialog_dir1 $d } } proc file_dialog_getresult {loadfile confirm_overwrt} { global file_dialog_dir1 file_dialog_retval file_dialog_ext has_x if { $file_dialog_retval ne {}} { if { [regexp {^https?://} $file_dialog_retval] } { set fname $file_dialog_retval } elseif { [regexp {^/} $file_dialog_retval]} { set fname $file_dialog_retval } else { regsub {/*$} $file_dialog_dir1 {/} file_dialog_dir1 set fname "${file_dialog_dir1}${file_dialog_retval}" } if {![file exists "$fname"] } { return "$fname" } if { $loadfile == 0 } { if {[file exists "$fname"]} { if {$confirm_overwrt == 1 } { set answer [alert_ "Overwrite $fname?" {} 0 1] } else { set answer 1 } if {$answer eq {1}} { return "$fname" } else { set file_dialog_retval {} return {} } } } set type [is_xschem_file "$fname"] if { $type eq {0} || $type eq {GENERATOR} } { if { $type eq {0} } { set answer [alert_ "$fname does not seem to be an xschem file...\nContinue?" {} 0 1] } else { ;# $type == GENERATOR set answer 1 } if { $answer eq {0}} { set file_dialog_retval {} return {} } else { ;# $answer == 1 if { $type eq {GENERATOR} } { return "${fname}" } # $type == 0 but $answer==1 so return selected filename return "$fname" } # $type == SYMBOL or SCHEMATIC } elseif { $type ne {SYMBOL} && ($file_dialog_ext eq {*.sym}) } { ;# SCHEMATIC set answer [ alert_ "$fname does not seem to be a SYMBOL file...\nContinue?" {} 0 1] if { $answer eq {0}} { set file_dialog_retval {} return {} } else { return "$fname" } } else { ;# SYMBOL return "$fname" } } else { return {} } } proc file_dialog_place_symbol {} { global file_dialog_retval set entry [.load.buttons_bot.entry get] # puts "entry=$entry" set file_dialog_retval $entry set sym [file_dialog_getresult 2 0] # puts "sym=$sym" xschem abort_operation if {$sym ne {}} { xschem place_symbol "$sym" } } proc file_dialog_display_preview {f} { set type [is_xschem_file $f] if { $type ne {0} && $type ne {GENERATOR} } { if { [winfo exists .load] } { .load.l.paneright.draw configure -background {} xschem preview_window draw .load.l.paneright.draw "$f" bind .load.l.paneright.draw [subst {xschem preview_window draw .load.l.paneright.draw "$f"}] bind .load.l.paneright.draw [subst {xschem preview_window draw .load.l.paneright.draw "$f"}] } } else { bind .load.l.paneright.draw {} bind .load.l.paneright.draw {} .load.l.paneright.draw configure -background white } } proc file_dialog_right_listboxselect {dirselect} { global file_dialog_yview file_dialog_dir1 file_dialog_dir2 file_dialog_retval file_dialog_sel global OS file_dialog_loadfile file_dialog_index1 file_dialog_files1 file_dialog_globfilter set file_dialog_yview [.load.l.paneright.f.list yview] set file_dialog_sel [.load.l.paneright.f.list curselection] if { $file_dialog_sel ne {} } { set curr_dir [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]] set curr_item [.load.l.paneright.f.list get $file_dialog_sel] if {$curr_item eq {..}} { set file_dialog_d [file dirname $curr_dir] } elseif {$curr_item eq {.} } { set file_dialog_d $curr_dir } else { if {$OS == "Windows"} { if {[regexp {^[A-Za-z]\:/$} $curr_dir]} { set file_dialog_d "$curr_dir$curr_item" } else { set file_dialog_d "$curr_dir/$curr_item" } } else { if {$curr_dir eq "/"} { set file_dialog_d "$curr_dir$curr_item" } else { set file_dialog_d "$curr_dir/$curr_item" } } } if { !$dirselect && [file isdirectory $file_dialog_d] } { .load.buttons_bot.entry delete 0 end set file_dialog_retval { } return } set file_dialog_dir1 $curr_dir set file_dialog_dir2 $curr_item if { [file isdirectory $file_dialog_d]} { bind .load.l.paneright.draw {} bind .load.l.paneright.draw {} .load.l.paneright.draw configure -background white file_dialog_set_home $file_dialog_d setglob $file_dialog_d file_dialog_set_colors2 set file_dialog_dir1 $file_dialog_d } else { .load.buttons_bot.entry delete 0 end .load.buttons_bot.entry insert 0 $file_dialog_dir2 file_dialog_display_preview $file_dialog_d # puts "xschem preview_window draw .load.l.paneright.draw \"$file_dialog_dir1/$file_dialog_dir2\"" } } if {$file_dialog_loadfile == 2} { # set to something different to any file to force a new placement in file_dialog_place_symbol set file_dialog_retval { } } } # global_initdir: name of global variable containing the initial directory # loadfile: set to 0 if calling for saving instead of loading a file # set to 2 for non blocking operation (symbol insertion) # confirm_overwrt: ask before overwriting an existing file # initialf: fill the file entry box with this name (used when saving) # proc load_file_dialog {{msg {}} {ext {}} {global_initdir {INITIALINSTDIR}} {loadfile {1}} {confirm_overwrt {1}} {initialf {}}} { global file_dialog_index1 file_dialog_files2 file_dialog_files1 file_dialog_retval file_dialog_dir1 pathlist OS global file_dialog_default_geometry file_dialog_sp0 file_dialog_sp1 file_dialog_v_sp0 file_dialog_yview global file_dialog_names1 tcl_version file_dialog_globfilter file_dialog_dir2 global file_dialog_save_initialfile file_dialog_loadfile file_dialog_ext if { [winfo exists .load] } { .load.buttons_bot.cancel invoke } set file_dialog_loadfile $loadfile if {$ext ne {}} {set file_dialog_ext $ext} set file_dialog_globfilter $file_dialog_ext set file_dialog_save_initialfile $initialf set file_dialog_retval {} upvar #0 $global_initdir initdir if { $loadfile != 2} {xschem set semaphore [expr {[xschem get semaphore] +1}]} toplevel .load -class Dialog wm title .load $msg # wm transient .load [xschem get topwindow] set_ne file_dialog_index1 0 if { ![info exists file_dialog_files1]} { set file_dialog_files1 $pathlist file_dialog_set_names1 update set file_dialog_index1 0 } set_ne file_dialog_files2 {} panedwindow .load.l -orient horizontal -height 8c if { $loadfile == 2} {frame .load.l.recent -takefocus 0} frame .load.l.paneleft -takefocus 0 -highlightcolor red -highlightthickness 2 -bg {grey90} eval [subst {listbox .load.l.paneleft.list -listvariable file_dialog_names1 -width 40 -height 12 \ -fg black -background {grey90} -highlightthickness 0 -relief flat -borderwidth 0 \ -yscrollcommand ".load.l.paneleft.yscroll set" -selectmode browse \ -xscrollcommand ".load.l.paneleft.xscroll set" -exportselection 0}] if { ![catch {.load.l.paneleft.list cget -justify}]} { .load.l.paneleft.list configure -justify right } file_dialog_set_colors1 scrollbar .load.l.paneleft.yscroll -command ".load.l.paneleft.list yview" -takefocus 0 scrollbar .load.l.paneleft.xscroll -command ".load.l.paneleft.list xview" -orient horiz -takefocus 0 pack .load.l.paneleft.yscroll -side right -fill y pack .load.l.paneleft.xscroll -side bottom -fill x pack .load.l.paneleft.list -fill both -expand true -padx 12 bind .load.l.paneleft.list <> { set file_dialog_sel [.load.l.paneleft.list curselection] if { $file_dialog_sel ne {} } { set file_dialog_dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_sel]] set file_dialog_index1 $file_dialog_sel set file_dialog_globfilter *[.load.buttons_bot.src get]* if { $file_dialog_globfilter eq {**} } { set file_dialog_globfilter * } setglob $file_dialog_dir1 file_dialog_set_colors2 } } panedwindow .load.l.paneright -orient vertical frame .load.l.paneright.f -takefocus 0 frame .load.l.paneright.draw -background white -height 3.8c -takefocus 0 .load.l.paneright add .load.l.paneright.f .load.l.paneright add .load.l.paneright.draw -minsize 150 if { ![catch {.load.l.paneright panecget .load.l.paneright.f -stretch}]} { set optnever {-stretch never} set optalways {-stretch always} } else { set optnever {} set optalways {} } eval .load.l.paneright paneconfigure .load.l.paneright.f $optnever eval .load.l.paneright paneconfigure .load.l.paneright.draw $optalways listbox .load.l.paneright.f.list -background {grey90} -listvariable file_dialog_files2 -width 20 -height 12\ -fg black -highlightcolor red -highlightthickness 2 \ -yscrollcommand ".load.l.paneright.f.yscroll set" -selectmode browse \ -xscrollcommand ".load.l.paneright.f.xscroll set" -exportselection 0 scrollbar .load.l.paneright.f.yscroll -command ".load.l.paneright.f.list yview" -takefocus 0 scrollbar .load.l.paneright.f.xscroll -command ".load.l.paneright.f.list xview" -orient horiz -takefocus 0 pack .load.l.paneright.f.yscroll -side right -fill y pack .load.l.paneright.f.xscroll -side bottom -fill x pack .load.l.paneright.f.list -side bottom -fill both -expand true if { $loadfile == 2} { .load.l add .load.l.recent c_toolbar::display } .load.l add .load.l.paneleft -minsize 40 .load.l add .load.l.paneright -minsize 150 eval .load.l paneconfigure .load.l.paneleft $optnever eval .load.l paneconfigure .load.l.paneright $optalways frame .load.buttons -takefocus 0 frame .load.buttons_bot -takefocus 0 button .load.buttons_bot.ok -width 5 -text OK -takefocus 0 -command " set file_dialog_retval \[.load.buttons_bot.entry get\] xschem preview_window destroy .load.l.paneright.draw {} destroy .load set $global_initdir \"\$file_dialog_dir1\" " button .load.buttons_bot.cancel -width 5 -text Cancel -takefocus 0 -command " set file_dialog_retval {} if {\$file_dialog_loadfile == 2} {xschem abort_operation} xschem preview_window destroy .load.l.paneright.draw {} destroy .load set $global_initdir \"\$file_dialog_dir1\" " wm protocol .load WM_DELETE_WINDOW {.load.buttons_bot.cancel invoke} button .load.buttons.home -width 5 -text {Home} -takefocus 0 -command { bind .load.l.paneright.draw {} bind .load.l.paneright.draw {} .load.l.paneright.draw configure -background white set file_dialog_files1 $pathlist file_dialog_set_names1 update file_dialog_set_colors1 .load.l.paneleft.list xview moveto 1 set file_dialog_index1 0 set file_dialog_dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]] setglob $file_dialog_dir1 file_dialog_set_colors2 .load.l.paneleft.list selection clear 0 end .load.l.paneright.f.list selection clear 0 end .load.l.paneleft.list selection set $file_dialog_index1 } label .load.buttons_bot.label -text { File:} entry .load.buttons_bot.entry -highlightcolor red -highlightthickness 2 entry_replace_selection .load.buttons_bot.entry label .load.buttons_bot.srclab -text { Search:} entry .load.buttons_bot.src -width 18 -highlightcolor red -highlightthickness 2 entry_replace_selection .load.buttons_bot.src .load.buttons_bot.src delete 0 end .load.buttons_bot.src insert 0 $file_dialog_globfilter if { $file_dialog_save_initialfile ne {} } { .load.buttons_bot.entry insert 0 $file_dialog_save_initialfile } bind .load.buttons_bot.src { if {$file_dialog_save_initialfile eq {} } { set file_dialog_globfilter *[.load.buttons_bot.src get]* if { $file_dialog_globfilter eq {**} } { set file_dialog_globfilter * } setglob $file_dialog_dir1 if {[.load.buttons_bot.entry get] ne {}} { .load.l.paneright.f.list yview moveto 1.0 } else { if { [info exists file_dialog_yview]} { .load.l.paneright.f.list yview moveto [lindex $file_dialog_yview 0] } } } # set to something different to any file to force a new placement in file_dialog_place_symbol set file_dialog_retval { } } bind .load.buttons_bot.entry { # set to something different to any file to force a new placement in file_dialog_place_symbol set file_dialog_retval { } } # radiobutton .load.buttons_bot.all -text All -variable file_dialog_globfilter -value {*} -takefocus 0 \ # -command { # set file_dialog_ext $file_dialog_globfilter # setglob $file_dialog_dir1 # .load.buttons_bot.src delete 0 end # .load.buttons_bot.src insert 0 $file_dialog_globfilter # } # radiobutton .load.buttons_bot.sym -text .sym -variable file_dialog_globfilter -value {*.sym} -takefocus 0 \ # -command { # set file_dialog_ext $file_dialog_globfilter # setglob $file_dialog_dir1 # .load.buttons_bot.src delete 0 end # .load.buttons_bot.src insert 0 $file_dialog_globfilter # } # radiobutton .load.buttons_bot.sch -text .sch -variable file_dialog_globfilter -value {*.sch} -takefocus 0 \ # -command { # set file_dialog_ext $file_dialog_globfilter # setglob $file_dialog_dir1 # .load.buttons_bot.src delete 0 end # .load.buttons_bot.src insert 0 $file_dialog_globfilter # } button .load.buttons.up -width 5 -text Up -command {load_file_dialog_up $file_dialog_dir1} -takefocus 0 label .load.buttons.mkdirlab -text { New dir: } entry .load.buttons.newdir -width 16 -takefocus 0 entry_replace_selection .load.buttons.newdir button .load.buttons.mkdir -width 5 -text Create -takefocus 0 -command { load_file_dialog_mkdir [.load.buttons.newdir get] } button .load.buttons.rmdir -width 5 -text Delete -takefocus 0 -command { if { [.load.buttons.newdir get] ne {} } { file delete "${file_dialog_dir1}/[.load.buttons.newdir get]" setglob ${file_dialog_dir1} file_dialog_set_colors2 } } button .load.buttons.pwd -text {Current dir} -takefocus 0 -command {load_file_dialog_up [xschem get schname]} checkbutton .load.buttons.path -text {Library paths} -variable load_file_dialog_fullpath -takefocus 0 \ -command { file_dialog_set_names1 update file_dialog_set_colors1 .load.l.paneleft.list xview moveto 1 } pack .load.buttons.home .load.buttons.up .load.buttons.pwd .load.buttons.path -side left pack .load.buttons.mkdirlab -side left pack .load.buttons.newdir -expand true -fill x -side left pack .load.buttons.rmdir .load.buttons.mkdir -side right # pack .load.buttons_bot.all .load.buttons_bot.sym .load.buttons_bot.sch -side left pack .load.buttons_bot.srclab -side left pack .load.buttons_bot.src -side left pack .load.buttons_bot.label -side left pack .load.buttons_bot.entry -side left -fill x -expand true pack .load.buttons_bot.cancel .load.buttons_bot.ok -side left pack .load.buttons_bot -side bottom -fill x pack .load.buttons -side bottom -fill x pack .load.l -expand true -fill both if { [info exists file_dialog_default_geometry]} { wm geometry .load "${file_dialog_default_geometry}" } file_dialog_set_home $initdir if { $loadfile != 2} { bind .load " set file_dialog_retval \[.load.buttons_bot.entry get\] if {\$file_dialog_retval ne {} && !\[file isdirectory \$file_dialog_retval\]} { bind .load.l.paneright.draw {} bind .load.l.paneright.draw {} xschem preview_window destroy .load.l.paneright.draw {} destroy .load set $global_initdir \"\$file_dialog_dir1\" } " bind .load.l.paneright.f.list " set file_dialog_retval \[.load.buttons_bot.entry get\] if {\$file_dialog_retval ne {} && !\[file isdirectory \$file_dialog_retval\]} { bind .load.l.paneright.draw {} bind .load.l.paneright.draw {} xschem preview_window destroy .load.l.paneright.draw {} destroy .load set $global_initdir \"\$file_dialog_dir1\" } " } bind .load " set file_dialog_retval {} if {\$file_dialog_loadfile == 2} {xschem abort_operation} xschem preview_window destroy .load.l.paneright.draw {} destroy .load set $global_initdir \"\$file_dialog_dir1\" " ### update if { [info exists file_dialog_v_sp0] } { eval .load.l.paneright sash mark 0 [.load.l.paneright sash coord 0] eval .load.l.paneright sash dragto 0 [subst {1 $file_dialog_v_sp0}] } if { [info exists file_dialog_sp0] } { if { $file_dialog_loadfile == 2} { eval .load.l sash mark 1 [.load.l sash coord 1] eval .load.l sash dragto 1 [subst {$file_dialog_sp0 1}] } else { eval .load.l sash mark 0 [.load.l sash coord 0] eval .load.l sash dragto 0 [subst {$file_dialog_sp0 1}] } } if { $file_dialog_loadfile == 2 && [info exists file_dialog_sp1] } { eval .load.l sash mark 0 [.load.l sash coord 0] eval .load.l sash dragto 0 [subst {$file_dialog_sp1 1}] } ### update .load.l.paneleft.list xview moveto 1 bind .load { set file_dialog_v_sp0 [lindex [.load.l.paneright sash coord 0] 1] if { $file_dialog_loadfile == 2} { set file_dialog_sp0 [lindex [.load.l sash coord 1] 0] } else { set file_dialog_sp0 [lindex [.load.l sash coord 0] 0] } if {$file_dialog_loadfile == 2} { set file_dialog_sp1 [lindex [.load.l sash coord 0] 0] } set file_dialog_default_geometry [wm geometry .load] .load.l.paneleft.list xview moveto 1 # regsub {\+.*} $file_dialog_default_geometry {} file_dialog_default_geometry } bind .load.l.paneright.f.yscroll { set file_dialog_yview [.load.l.paneright.f.list yview] } xschem preview_window create .load.l.paneright.draw {} set file_dialog_dir1 [abs_sym_path [lindex $file_dialog_files1 $file_dialog_index1]] setglob $file_dialog_dir1 file_dialog_set_colors2 if {$file_dialog_loadfile == 2} { bind .load { if { {%W} eq {.load} && $file_dialog_retval ne {} && [.load.buttons_bot.entry get] ne $file_dialog_retval} { file_dialog_place_symbol } } } bind .load.l.paneright.f.list { file_dialog_right_listboxselect 1 } bind .load.l.paneright.f.list { file_dialog_right_listboxselect 1 } bind .load.l.paneright.f.list { file_dialog_right_listboxselect 0 } bind .load.l.paneright.f.list { file_dialog_right_listboxselect 0 } # bind .load.l.paneright.f.list <> { # file_dialog_right_listboxselect # } if { [info exists file_dialog_yview]} { .load.l.paneright.f.list yview moveto [lindex $file_dialog_yview 0] } focus .load.buttons_bot.src .load.buttons_bot.src selection range 0 end if {$loadfile != 2} { tkwait window .load xschem set semaphore [expr {[xschem get semaphore] -1}] } return [file_dialog_getresult $loadfile $confirm_overwrt] } # get last n path components: example , n=1 --> /aaa/bbb/ccc/ddd.sch -> ccc/ddd.sch proc get_cell {s n } { set slist [file split $s] set l [llength $slist] if { $n >= $l } {set n [expr {$l - 1}]} set p {} for {set i [expr {$l-1-$n}]} {$i < $l} { incr i } { append p [lindex $slist $i] if {$i < $l - 1} { append p {/} } } return $p } # chop last n path components from s proc path_head {s n } { set slist [file split $s] set l [llength $slist] if { $n < 0 } { set n 0 } set p {} for {set i 0} {$i < [expr {$l - $n}]} { incr i } { append p [lindex $slist $i] if {$i < $l -$n- 1 && ([lindex $slist $i] ne {/})} { append p {/} } } return $p } proc delete_files { dir } { if { [info tclversion] >=8.4} { set x [tk_getOpenFile -title "DELETE FILES" -multiple 1 -initialdir [file dirname $dir] ] } else { set x [tk_getOpenFile -title "DELETE FILES" -initialdir [file dirname $dir] ] } foreach i $x { file delete $i } } proc create_user_xschemrc {} { global USER_CONF_DIR XSCHEM_SHAREDIR if {![file exists $USER_CONF_DIR/xschemrc]} { file copy $XSCHEM_SHAREDIR/xschemrc $USER_CONF_DIR/xschemrc puts stderr "copied system $XSCHEM_SHAREDIR/xschemrc to $USER_CONF_DIR/xschemrc" puts stderr "Please review the file and make your changes, then restart xschem" } else { puts stderr "$USER_CONF_DIR/xschemrc already exists, will not overwrite." } } proc create_pins {} { global env retval USER_CONF_DIR global filetmp set retval [ read_data_nonewline $filetmp ] regsub -all {<} $retval {[} retval regsub -all {>} $retval {]} retval set lines [split $retval \n] set dirprefix [file dirname [rel_sym_path [find_file_first ipin.sym]]] if {$dirprefix == {.}} { set dirprefix {}} else {append dirprefix {/}} # viewdata $retval set pcnt 0 set y 0 set fd [open $USER_CONF_DIR/.clipboard.sch w] foreach i $lines { puts $fd "C \{${dirprefix}[lindex $i 1].sym\} 0 [set y [expr {$y-20}]] \ 0 0 \{ name=p[incr pcnt] lab=[lindex $i 0] \}" } close $fd xschem merge $USER_CONF_DIR/.clipboard.sch } proc rectorder {x1 y1 x2 y2} { if {$x2 < $x1} {set tmp $x1; set x1 $x2; set x2 $tmp} if {$y2 < $y1} {set tmp $y1; set y1 $y2; set y2 $tmp} return [list $x1 $y1 $x2 $y2] } proc order {x1 y1 x2 y2} { if {$x2 < $x1} {set tmp $x1; set x1 $x2; set x2 $tmp; set tmp $y1; set y1 $y2; set y2 $tmp } elseif {$x2==$x1 && $y2<$y1} {set tmp $y1; set y1 $y2; set y2 $tmp} return [list $x1 $y1 $x2 $y2] } proc rotation {x0 y0 x y rot flip} { set tmp [expr {$flip? 2*$x0-$x : $x}] if {$rot==0} {set rx $tmp; set ry $y } if {$rot==1} {set rx [expr {$x0 - $y +$y0}]; set ry [expr {$y0+$tmp-$x0}]} if {$rot==2} {set rx [expr {2*$x0-$tmp}]; set ry [expr {2*$y0-$y}]} if {$rot==3} {set rx [expr {$x0+$y-$y0}]; set ry [expr {$y0-$tmp+$x0}]} return [list $rx $ry] } proc schpins_to_sympins {} { global env USER_CONF_DIR set pinhsize 2.5 set first 1 xschem copy set clipboard [read_data_nonewline $USER_CONF_DIR/.clipboard.sch] set lines [split $clipboard \n] set fd [open $USER_CONF_DIR/.clipboard.sch w] foreach i $lines { set ii [split [regexp -all -inline {\S+} $i]] if {[regexp {^C \{.*(i|o|io)pin} $i ]} { if {[regexp {ipin} [lindex $ii 1]]} { set dir in } if {[regexp {opin} [lindex $ii 1]]} { set dir out } if {[regexp {iopin} [lindex $ii 1]]} { set dir inout } set rot [lindex $ii 4] set flip [lindex $ii 5] while {1} { if { [regexp {lab=} $i] } { regsub {^.*lab=} $i {} lab regsub {[\} ].*} $lab {} lab } if { [regexp {\}} $i]} { break} } set x0 [lindex $ii 2] set y0 [lindex $ii 3] if {$first} { puts $fd "G {$x0 $y0 }" set first 0 } set pinx1 [expr {$x0-$pinhsize}] set pinx2 [expr {$x0+$pinhsize}] set piny1 [expr {$y0-$pinhsize}] set piny2 [expr {$y0+$pinhsize}] if {![string compare $dir "out"] || ![string compare $dir "inout"] } { set linex1 [expr {$x0-20}] set liney1 $y0 set linex2 $x0 set liney2 $y0 set textx0 [expr {$x0-25}] set texty0 [expr {$y0-4}] set textflip [expr {!$flip}] } else { set linex1 [expr {$x0+20}] set liney1 $y0 set linex2 $x0 set liney2 $y0 set textx0 [expr {$x0+25}] set texty0 [expr {$y0-4}] set textflip [expr {$flip}] } lassign [rotation $x0 $y0 $linex1 $liney1 $rot $flip] linex1 liney1 lassign [rotation $x0 $y0 $linex2 $liney2 $rot $flip] linex2 liney2 lassign [order $linex1 $liney1 $linex2 $liney2] linex1 liney1 linex2 liney2 lassign [rotation $x0 $y0 $textx0 $texty0 $rot $flip] textx0 texty0 puts $fd "B 5 $pinx1 $piny1 $pinx2 $piny2 \{name=$lab dir=$dir\}" puts $fd "L 4 $linex1 $liney1 $linex2 $liney2 \{\}" puts $fd "T \{$lab\} $textx0 $texty0 $rot $textflip 0.2 0.2 \{\}" } } close $fd xschem paste } proc add_lab_no_prefix {} { global env retval USER_CONF_DIR global filetmp set dirprefix [file dirname [rel_sym_path [find_file_first ipin.sym]]] if {$dirprefix == {.}} { set dirprefix {}} else {append dirprefix {/}} set retval [ read_data_nonewline $filetmp ] regsub -all {<} $retval {[} retval regsub -all {>} $retval {]} retval set lines [split $retval \n] # viewdata $retval set pcnt 0 set y 0 set fd [open $USER_CONF_DIR/.clipboard.sch w] foreach i $lines { puts $fd "C \{${dirprefix}lab_pin.sym\} 0 [set y [expr {$y+20}]] \ 0 0 \{ name=p[incr pcnt] verilog_type=wire lab=[lindex $i 0] \}" } close $fd xschem merge $USER_CONF_DIR/.clipboard.sch } proc add_lab_prefix {} { global env retval USER_CONF_DIR global filetmp set dirprefix [file dirname [rel_sym_path [find_file_first ipin.sym]]] if {$dirprefix == {.}} { set dirprefix {}} else {append dirprefix {/}} set retval [ read_data_nonewline $filetmp ] regsub -all {<} $retval {[} retval regsub -all {>} $retval {]} retval set lines [split $retval \n] # viewdata $retval set pcnt 0 set y 0 set fd [open $USER_CONF_DIR/.clipboard.sch w] foreach i $lines { puts $fd "C \{${dirprefix}lab_pin.sym\} 0 [set y [expr {$y+20}]] \ 0 0 \{ name=p[incr pcnt] verilog_type=reg lab=i[lindex $i 0] \}" } close $fd xschem merge $USER_CONF_DIR/.clipboard.sch } proc make_symbol {name {ask {no}} } { global XSCHEM_SHAREDIR symbol_width set name [abs_sym_path $name ] set symname [abs_sym_path $name .sym] if { $ask eq {no} && [file exists $symname] } { set answer [tk_messageBox -message "Warning: symbol $symname already exists. Overwrite?" \ -icon warning -parent [xschem get topwindow] -type okcancel] if {$answer ne {ok}} { return {}} } # puts "make_symbol{}, executing: ${XSCHEM_SHAREDIR}/make_sym.awk $symbol_width ${name}" eval exec {awk -f ${XSCHEM_SHAREDIR}/make_sym.awk $symbol_width $name} return {} } proc make_symbol_lcc {name} { global XSCHEM_SHAREDIR set name [abs_sym_path $name] # puts "make_symbol{}, executing: ${XSCHEM_SHAREDIR}/make_sym_lcc.awk ${name}" eval exec {awk -f ${XSCHEM_SHAREDIR}/make_sym_lcc.awk $name} return {} } # point netlist_dir to simulation dir 'simulation/' under current schematic directory proc simuldir {} { global netlist_dir local_netlist_dir has_x if { $local_netlist_dir == 1 } { set simdir [xschem get current_dirname]/simulation set netlist_dir $simdir regsub {/$} $netlist_dir {} netlist_dir return $netlist_dir } if { $local_netlist_dir == 2 } { set simdir [xschem get current_dirname]/simulation/[get_cell [xschem get current_name] 0] set netlist_dir $simdir regsub {/$} $netlist_dir {} netlist_dir return $netlist_dir } return {} } # # what==0: force creation of $netlist_dir (if netlist_dir variable not empty) # and return current setting. # # what==1: if no dir given prompt user # else set netlist_dir to dir # # what==2: just set netlist_dir according to local_netlist_dir setting # # Return current netlist directory # proc set_netlist_dir { what {dir {} }} { global netlist_dir env OS has_x local_netlist_dir USER_CONF_DIR #### set local-to-schematic-dir if local_netlist_dir tcl var is set simuldir regsub {/$} $netlist_dir {} netlist_dir if {$what == 2} { return $netlist_dir } #### what == 0 if {$what == 0} { if {$netlist_dir ne {}} { if {![file exist $netlist_dir]} { if {[catch {file mkdir "$netlist_dir"} err]} { puts stderr $err if {[info exists has_x]} { tk_messageBox -message "$err" -icon error -parent [xschem get topwindow] -type ok } } } } #### what == 1 } else { # if local_netlist_dir is set can not provide a dir, set dir to netlist_dir as set by proc simuldir if {$local_netlist_dir != 0} { set dir $netlist_dir } if { $dir eq {} } { # set to default simulations/ directory. if {$local_netlist_dir == 0 && $netlist_dir eq {}} { set initdir "$USER_CONF_DIR/simulations" } elseif {$local_netlist_dir == 0 } { set initdir $netlist_dir } elseif { $netlist_dir ne {} } { set initdir $netlist_dir } else { if {$OS == "Windows"} { set initdir $env(windir) } else { set initdir [pwd] } } # prompt user for a dir set new_dir [tk_chooseDirectory -initialdir $initdir \ -parent [xschem get topwindow] -title {Select netlist DIR} -mustexist false] } else { # use provided dir argument set new_dir $dir } # create new dir if not already existing if {$new_dir ne {} } { if {![file exist $new_dir]} { if {[catch {file mkdir "$new_dir"} err]} { puts stderr $err if {[info exists has_x]} { tk_messageBox -message "$err" -icon error -parent [xschem get topwindow] -type ok } } } set netlist_dir $new_dir } } ;# what == 1 regsub {^~/} $netlist_dir ${env(HOME)}/ netlist_dir regsub {/$} $netlist_dir {} netlist_dir # return $netlist_dir if valid and existing, else return empty string if {$netlist_dir ne {} && [file exists $netlist_dir]} { return $netlist_dir } return {} } proc enter_text {textlabel {preserve_disabled disabled}} { global retval has_cairo preserve_unchanged_attrs wm_fix props enter_text_default_geometry global text_tabs_setting tabstop set tctx::rcode {} toplevel .dialog -class Dialog wm title .dialog {Enter text} wm transient .dialog [xschem get topwindow] set X [expr {[winfo pointerx .dialog] - 30}] set Y [expr {[winfo pointery .dialog] - 25}] bind .dialog { # puts [wm geometry .dialog] set enter_text_default_geometry [wm geometry .dialog] regsub {\+.*} $enter_text_default_geometry {} enter_text_default_geometry } # 20100203 if { $wm_fix } { tkwait visibility .dialog } wm geometry .dialog "${enter_text_default_geometry}+$X+$Y" frame .dialog.f1 label .dialog.f1.txtlab -text $textlabel eval text .dialog.txt -undo 1 -width 120 -height 9 $text_tabs_setting .dialog.txt delete 1.0 end .dialog.txt insert 1.0 $retval checkbutton .dialog.f1.l1 -text "preserve unchanged props" -variable preserve_unchanged_attrs \ -state $preserve_disabled pack .dialog.f1 -side top -fill x ;# -expand yes pack .dialog.f1.l1 -side left pack .dialog.f1.txtlab -side left -expand yes -fill x pack .dialog.txt -side top -fill both -expand yes frame .dialog.edit frame .dialog.edit.hsize frame .dialog.edit.vsize frame .dialog.edit.props pack .dialog.edit.hsize -side bottom -expand yes -fill x pack .dialog.edit.vsize -side bottom -expand yes -fill x pack .dialog.edit.props -side bottom -expand yes -fill x pack .dialog.edit -side top -fill x if {$has_cairo } { entry .dialog.edit.hsize.hsize -relief sunken -textvariable tctx::vsize -width 20 entry_replace_selection .dialog.edit.hsize.hsize } else { entry .dialog.edit.hsize.hsize -relief sunken -textvariable tctx::hsize -width 20 entry_replace_selection .dialog.edit.hsize.hsize } entry .dialog.edit.vsize.vsize -relief sunken -textvariable tctx::vsize -width 20 entry_replace_selection .dialog.edit.vsize.vsize text .dialog.edit.props.props -undo 1 -width 70 -height 3 .dialog.edit.props.props insert 1.0 $props label .dialog.edit.hsize.hlab -text "hsize:" label .dialog.edit.vsize.vlab -text "vsize:" label .dialog.edit.props.proplab -text "props:" pack .dialog.edit.hsize.hlab -side left pack .dialog.edit.hsize.hsize -side left -fill x -expand yes pack .dialog.edit.vsize.vlab -side left pack .dialog.edit.vsize.vsize -side left -fill x -expand yes pack .dialog.edit.props.proplab -side left pack .dialog.edit.props.props -side left -fill x -expand yes frame .dialog.buttons button .dialog.buttons.ok -text "OK" -command \ { set props [.dialog.edit.props.props get 1.0 {end - 1 chars}] set retval [.dialog.txt get 1.0 {end - 1 chars}] if {$has_cairo} { set tctx::hsize $tctx::vsize } set tctx::rcode {ok} destroy .dialog } button .dialog.buttons.cancel -text "Cancel" -command \ { set retval {} set tctx::rcode {} destroy .dialog } button .dialog.buttons.b3 -text "Load" -command \ { global INITIALTEXTDIR if { ![info exists INITIALTEXTDIR] } { set INITIALTEXTDIR [xschem get current_dirname] } set a [tk_getOpenFile -parent .dialog -initialdir $INITIALTEXTDIR ] if [string compare $a ""] { set INITIALTEXTDIR [file dirname $a] read_data_window .dialog.txt $a } } button .dialog.buttons.b4 -text "Del" -command \ { .dialog.txt delete 1.0 end } pack .dialog.buttons.ok -side left -fill x -expand yes pack .dialog.buttons.cancel -side left -fill x -expand yes pack .dialog.buttons.b3 -side left -fill x -expand yes pack .dialog.buttons.b4 -side left -fill x -expand yes pack .dialog.buttons -side bottom -fill x bind .dialog { if ![string compare $retval [.dialog.txt get 1.0 {end - 1 chars}]] { .dialog.buttons.cancel invoke } } bind .dialog.txt {return_release %W; .dialog.buttons.ok invoke} #grab set .dialog tkwait window .dialog return $retval } # will redefine puts to output into tclcmd_puts proc redef_puts {} { global tclcmd_puts if ![llength [info command ::tcl::puts]] { rename puts ::tcl::puts proc puts args { set la [llength $args] if {$la<1 || $la>3} { error "usage: puts ?-nonewline? ?channel? string" } set nl \n if {[lindex $args 0]=="-nonewline"} { set nl "" set args [lrange $args 1 end] } if {[llength $args]==1} { set args [list stdout [join $args]] ;# (2) } foreach {channel s} $args break #set s [join $s] ;# (1) prevent braces at leading/tailing spaces if {$channel=="stdout" || $channel=="stderr"} { append tclcmd_puts $s$nl } else { set cmd ::tcl::puts if {$nl==""} {lappend cmd -nonewline} lappend cmd $channel $s eval $cmd } };# puts } } # return key release, used to remove last entered character # when binding close text-widget window to Shift-return or Control-return. proc return_release {window} { set curs [$window index insert] $window delete "$curs - 1 chars" $curs } proc tclcmd_ok_button {} { global tclcmd_txt tclcmd_puts set tclcmd_txt [.tclcmd.t get 1.0 end] redef_puts catch {uplevel #0 $tclcmd_txt} tclcmd_puts rename puts {} rename ::tcl::puts puts if {$tclcmd_puts != {} && [string index $tclcmd_puts end] != "\n"} { append tclcmd_puts "\n" } .tclcmd.r.r insert end $tclcmd_puts .tclcmd.r.r yview moveto 1 } # evaluate a tcl command from GUI proc tclcmd {} { global tclcmd_txt if {[winfo exists .tclcmd]} { destroy .tclcmd } toplevel .tclcmd -class Dialog # wm transient .tclcmd [xschem get topwindow] label .tclcmd.txtlab -text {Enter TCL expression. Shift-Return will evaluate} panedwindow .tclcmd.p -orient vert text .tclcmd.t -undo 1 -width 100 -height 3 frame .tclcmd.r text .tclcmd.r.r -undo 1 -width 100 -height 8 -yscrollcommand ".tclcmd.r.yscroll set" scrollbar .tclcmd.r.yscroll -command ".tclcmd.r.r yview" .tclcmd.p add .tclcmd.t .tclcmd.r .tclcmd.t insert 1.0 $tclcmd_txt frame .tclcmd.b button .tclcmd.b.clear -text Clear -command { .tclcmd.r.r delete 1.0 end } button .tclcmd.b.close -text Close -command { set tclcmd_txt [.tclcmd.t get 1.0 {end - 1 chars}] destroy .tclcmd } button .tclcmd.b.ok -text Evaluate -command {tclcmd_ok_button} # bind .tclcmd.t { .tclcmd.b.ok invoke } bind .tclcmd.t {return_release %W; .tclcmd.b.ok invoke } pack .tclcmd.txtlab -side top -fill x pack .tclcmd.b -side bottom -fill x pack .tclcmd.p -side top -fill both -expand yes pack .tclcmd.r.yscroll -side right -fill y pack .tclcmd.r.r -side top -fill both -expand yes pack .tclcmd.b.ok -side left -expand yes -fill x pack .tclcmd.b.close -side left -expand yes -fill x pack .tclcmd.b.clear -side left -expand yes -fill x } proc select_layers {} { global dark_colorscheme enable_layer # xschem set semaphore [expr {[xschem get semaphore] +1}] toplevel .sl -class Dialog wm transient .sl [xschem get topwindow] if { $dark_colorscheme == 1 } { set txt_color black } else { set txt_color white } set j 0 set f 0 frame .sl.f0 frame .sl.f1 pack .sl.f0 .sl.f1 -side top -fill x button .sl.f1.ok -text OK -command { destroy .sl} pack .sl.f1.ok -side left -expand yes -fill x frame .sl.f0.f$f pack .sl.f0.f$f -side left -fill y foreach i $tctx::colors { if { $dark_colorscheme == 1 } { set ind_bg white } else { set ind_bg black } if { $j == [xschem get pinlayer] } { set laylab [format %2d $j]-PIN set layfg $txt_color } elseif { $j == [xschem get wirelayer] } { set laylab [format %2d $j]-WIRE set layfg $txt_color } elseif { $j == [xschem get textlayer] } { set laylab [format %2d $j]-TEXT set layfg $txt_color } elseif { $j == [xschem get backlayer] } { set laylab [format %2d $j]-BG if { $dark_colorscheme == 1 } { set layfg white set ind_bg black } else { set layfg black set ind_bg white } } elseif { $j == [xschem get gridlayer] } { set laylab [format %2d $j]-GRID set layfg $txt_color } else { set laylab "[format %2d $j] " set layfg $txt_color } checkbutton .sl.f0.f$f.cb$j -text $laylab -variable enable_layer($j) -activeforeground $layfg \ -selectcolor $ind_bg -anchor w -foreground $layfg -background $i -activebackground $i \ -command { xschem enable_layers xschem redraw } pack .sl.f0.f$f.cb$j -side top -fill x incr j if { [expr {$j%10}] == 0 } { incr f frame .sl.f0.f$f pack .sl.f0.f$f -side left -fill y } } # tkwait window .sl # xschem set semaphore [expr {[xschem get semaphore] -1}] } proc color_dim {} { global dim_bg dim_value enable_dim_bg xschem set semaphore [expr {[xschem get semaphore] +1}] toplevel .dim -class Dialog wm title .dim {Dim colors} wm transient .dim [xschem get topwindow] checkbutton .dim.bg -text {Dim background} -variable enable_dim_bg # xschem color_dim sets also dim_value variable scale .dim.scale -digits 2 -label {Dim factor} -length 256 \ -showvalue 1 -command {xschem color_dim} -orient horizontal \ -from -5 -to 5 -resolution 0.1 button .dim.ok -text OK -command {destroy .dim} .dim.scale set $dim_value pack .dim.scale pack .dim.bg -side left pack .dim.ok -side right -anchor e tkwait window .dim xschem set semaphore [expr {[xschem get semaphore] -1}] } # show xschem about dialog proc about {} { global OS running_in_src_dir if [winfo exists .about] { bind .about.link {} bind .about.link2 {} destroy .about } toplevel .about -class Dialog wm title .about {About XSCHEM} wm transient .about [xschem get topwindow] label .about.xschem -text "XSCHEM V[xschem get version]" -font {Sans 24 bold} label .about.descr -text "Schematic editor / netlister for VHDL, Verilog, SPICE, tEDAx" button .about.link -text {http://repo.hu/projects/xschem} -font Underline-Font -fg blue -relief flat button .about.link2 -text {https://github.com/StefanSchippers/xschem} -font Underline-Font -fg blue -relief flat button .about.link3 -text {Online XSCHEM Manual} -font Underline-Font -fg blue -relief flat button .about.link4 -text {Local XSCHEM Manual} -font Underline-Font -fg blue -relief flat label .about.copyright -text "\n Copyright (C) 1998-2024 Stefan Schippers (stefan.schippers@gmail.com) \n This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\n" button .about.close -text Close -command {destroy .about} -font {Sans 18} pack .about.xschem pack .about.link pack .about.link2 pack .about.link3 pack .about.link4 pack .about.descr pack .about.copyright pack .about.close if {$OS == "Windows"} { bind .about.link {eval start http://repo.hu/projects/xschem} bind .about.link2 {eval start https://github.com/StefanSchippers/xschem} bind .about.link3 {eval start http://repo.hu/projects/xschem/index.html} bind .about.link4 { if {$running_in_src_dir} { eval start [pwd]/../doc/xschem_man/xschem_man.html } else { eval start $XSCHEM_SHAREDIR/../doc/xschem/xschem_man/xschem_man.html } } } else { bind .about.link {execute 0 xdg-open http://repo.hu/projects/xschem} bind .about.link2 {execute 0 xdg-open https://github.com/StefanSchippers/xschem} bind .about.link3 {execute 0 xdg-open http://repo.hu/projects/xschem/index.html} bind .about.link4 { if {$running_in_src_dir} { execute 0 xdg-open file://$XSCHEM_SHAREDIR/../doc/xschem_man/xschem_man.html } else { execute 0 xdg-open file://$XSCHEM_SHAREDIR/../doc/xschem/xschem_man/xschem_man.html } } } } proc property_search {} { global search_value search_found global search_exact search_case global search_select global custom_token OS set search_found 0 while { !$search_found} { if { [winfo exists .dialog] } return xschem set semaphore [expr {[xschem get semaphore] +1}] toplevel .dialog -class Dialog wm title .dialog {Search} wm transient .dialog [xschem get topwindow] if { ![info exists X] } { set X [expr {[winfo pointerx .dialog] - 60}] set Y [expr {[winfo pointery .dialog] - 35}] } wm geometry .dialog "+$X+$Y" frame .dialog.custom label .dialog.custom.l -text "Token" entry .dialog.custom.e -width 32 entry_replace_selection .dialog.custom.e .dialog.custom.e insert 0 $custom_token pack .dialog.custom.e .dialog.custom.l -side right frame .dialog.val label .dialog.val.l -text "Value" entry .dialog.val.e -width 32 entry_replace_selection .dialog.val.e .dialog.val.e insert 0 $search_value pack .dialog.val.e .dialog.val.l -side right frame .dialog.but button .dialog.but.ok -text OK -command { set search_value [.dialog.val.e get] set custom_token [.dialog.custom.e get] if {$debug_var<=-1} { puts stderr "|$custom_token|" } if { $search_exact==1 } { set search_found [xschem searchmenu exact $search_select $custom_token $search_value $search_case] } else { set search_found [xschem searchmenu regex $search_select $custom_token $search_value $search_case] } destroy .dialog } button .dialog.but.cancel -text Cancel -command { set search_found 1; destroy .dialog } # Window doesn't support regular expression, has to be exact match for now checkbutton .dialog.but.sub -text {Exact search} -variable search_exact checkbutton .dialog.but.case -text {Match case} -variable search_case radiobutton .dialog.but.nosel -text {Highlight} -variable search_select -value 0 radiobutton .dialog.but.sel -text {Select} -variable search_select -value 1 # 20171211 added unselect radiobutton .dialog.but.unsel -text {Unselect} -variable search_select -value -1 pack .dialog.but.ok -anchor w -side left pack .dialog.but.sub -side left pack .dialog.but.case -side left pack .dialog.but.nosel -side left pack .dialog.but.sel -side left pack .dialog.but.unsel -side left pack .dialog.but.cancel -anchor e pack .dialog.custom -anchor e pack .dialog.val -anchor e pack .dialog.but -expand yes -fill x focus .dialog bind .dialog {.dialog.but.cancel invoke} bind .dialog {.dialog.but.ok invoke} wm protocol .dialog WM_DELETE_WINDOW {.dialog.but.cancel invoke} # grab set .dialog tkwait window .dialog xschem set semaphore [expr {[xschem get semaphore] -1}] } return {} } #20171029 # allows to call TCL hooks from 'format' strings during netlisting # example of symbol spice format definition: # format="@name @pinlist @symname @tcleval(