6253 lines
222 KiB
Tcl
6253 lines
222 KiB
Tcl
#
|
|
# File: xschem.tcl
|
|
#
|
|
# This file is part of XSCHEM,
|
|
# a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
|
|
# simulation.
|
|
# Copyright (C) 1998-2022 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"
|
|
label .inutile_line.l1 -text $txtlabel
|
|
entry .inutile_line.e1 -width 60
|
|
.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 <Return> {
|
|
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
|
|
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
|
|
wm title $w "(IN)UTILE ALIAS FILE: $filename"
|
|
wm iconname $w "ALIAS"
|
|
|
|
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 -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
|
|
wm title $w "(IN)UTILE ALIAS FILE"
|
|
wm iconname $w "ALIAS"
|
|
|
|
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 -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
|
|
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 {}}} {
|
|
global XSCHEM_SHAREDIR retval netlist_dir
|
|
|
|
toplevel .inutile
|
|
wm title .inutile "(IN)UTILE (Stefan Schippers, sschippe)"
|
|
wm iconname .inutile "(IN)UTILE"
|
|
set utile_path $XSCHEM_SHAREDIR/utile
|
|
if { ![string compare $filename ""] } then {
|
|
wm withdraw .inutile
|
|
tk_messageBox -type ok -message "Please give a file name as argument"
|
|
exit
|
|
}
|
|
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 -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}\] {}\]} {
|
|
template .inutile.text $utile_path/template.stimuli}"
|
|
label .inutile.buttons.timelab -text "time:"
|
|
entry .inutile.buttons.time -width 11
|
|
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]
|
|
}
|
|
}
|
|
}
|
|
|
|
### 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
|
|
}
|
|
}
|
|
|
|
###
|
|
### Tk procedures
|
|
###
|
|
# execute service function
|
|
proc execute_fileevent {id} {
|
|
global execute
|
|
append execute(data,$id) [read $execute(pipe,$id) 1024]
|
|
if {[eof $execute(pipe,$id)]} {
|
|
fileevent $execute(pipe,$id) readable ""
|
|
if { $execute(status,$id) } {
|
|
# setting pipe to blocking before closing allows to see if pipeline failed
|
|
# do not ask status for processes that close stdout/stderr, as eof might
|
|
# occur before process ends and following close blocks until process terminates.
|
|
fconfigure $execute(pipe,$id) -blocking 1
|
|
set status 0
|
|
if { [ info tclversion] > 8.4} {
|
|
set catch_return [eval catch [list {close $execute(pipe,$id)} err options] ]
|
|
} else {
|
|
set catch_return [eval catch [list {close $execute(pipe,$id)} err] ]
|
|
}
|
|
if {$catch_return} {
|
|
if {[info tclversion] > 8.4} {
|
|
set details [dict get $options -errorcode]
|
|
if {[lindex $details 0] eq "CHILDSTATUS"} {
|
|
set status [lindex $details 2]
|
|
viewdata "Failed: $execute(cmd,$id)\nstderr:\n$err\ndata:\n$execute(data,$id)"
|
|
} else {
|
|
set status 1
|
|
if {$execute(status,$id) } {
|
|
viewdata "Completed: $execute(cmd,$id)\nstderr:\n$err\ndata:\n$execute(data,$id)"
|
|
}
|
|
}
|
|
} else {
|
|
set status 1
|
|
if {$execute(status,$id) } {
|
|
viewdata "Completed: $execute(cmd,$id)\nstderr:\n$err\ndata:\n$execute(data,$id)"
|
|
}
|
|
}
|
|
}
|
|
if {$status == 0} {
|
|
if {$execute(status,$id) } {
|
|
viewdata "Completed: $execute(cmd,$id)\ndata:\n$execute(data,$id)"
|
|
}
|
|
}
|
|
} else {
|
|
# nonblocking close always succeed
|
|
close $execute(pipe,$id)
|
|
}
|
|
if {[info exists execute(callback,$id)] && $execute(callback,$id) ne {}} {
|
|
uplevel #0 "eval $execute(callback,$id)"
|
|
unset execute(callback,$id)
|
|
}
|
|
unset execute(pipe,$id)
|
|
unset execute(data,$id)
|
|
unset execute(status,$id)
|
|
unset execute(cmd,$id)
|
|
}
|
|
}
|
|
|
|
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.
|
|
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)
|
|
}
|
|
if { [catch {open "|$args" r} 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(data,$id) ""
|
|
fconfigure $pipe -blocking 0
|
|
fileevent $pipe readable "execute_fileevent $id"
|
|
return $id
|
|
}
|
|
|
|
#### Scrollable frame
|
|
proc scrollyview {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 "scrollyview $container" ;# scrollyview 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 number to engineering form
|
|
proc to_eng {i} {
|
|
set suffix {}
|
|
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. if expression has errors or does not evaluate return expression as is
|
|
proc ev {s} {
|
|
if {![catch {expr $s} res]} {
|
|
return [format %.4g $res]
|
|
} else {
|
|
return $s
|
|
}
|
|
}
|
|
proc netlist {source_file show netlist_file} {
|
|
global XSCHEM_SHAREDIR flat_netlist netlist_dir
|
|
global verilog_2001 debug_var OS verilog_bitblast
|
|
|
|
simuldir
|
|
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
|
|
if { [regexp -nocase {\.pdf$} $dest] } {
|
|
set pdffile [file rootname $filename].pdf
|
|
# puts "---> $to_pdf $filename $pdffile"
|
|
set cmd "exec $to_pdf \$filename \$pdffile"
|
|
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 {
|
|
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
|
|
|
|
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 0 $topwin}
|
|
if { [info exists has_x] } {setup_recent_menu 1 $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 { {in_new_window 0} { topwin {} } } {
|
|
global recentfile
|
|
# puts "setup recent menu in_new_window=$in_new_window"
|
|
if {$in_new_window} {
|
|
$topwin.menubar.file.menu.recent_new_window delete 0 9
|
|
} else {
|
|
$topwin.menubar.file.menu.recent delete 0 9
|
|
}
|
|
set i 0
|
|
if { [info exists recentfile] } {
|
|
foreach i $recentfile {
|
|
if {$in_new_window} {
|
|
$topwin.menubar.file.menu.recent_new_window add command \
|
|
-command "xschem load_new_window {$i}" \
|
|
-label [file tail $i]
|
|
} else {
|
|
$topwin.menubar.file.menu.recent add command \
|
|
-command "xschem load {$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} {
|
|
global path graph_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.
|
|
set skip 0
|
|
while { $skip < $graph_raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
set n [string tolower $n]
|
|
set prefix [string range $n 0 0]
|
|
#puts "ngspice::get_current: path=$path n=$n"
|
|
set n $path$n
|
|
if { ![sim_is_xyce] } {
|
|
if {$path ne {} } {
|
|
set n $prefix.$n
|
|
}
|
|
if { ![regexp $prefix {[ve]}] } {
|
|
set n @$n
|
|
}
|
|
}
|
|
set n i($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} {
|
|
global path graph_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.
|
|
set skip 0
|
|
while { $skip < $graph_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} {
|
|
global path graph_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.
|
|
set skip 0
|
|
while { $skip < $graph_raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
set n [string tolower $n]
|
|
# puts "ngspice::get_voltage: path=$path n=$n"
|
|
set node $path$n
|
|
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 ngspice::get_node {n} {
|
|
global path graph_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.
|
|
set skip 0
|
|
while { $skip < $graph_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
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
# 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 {[string is list $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 {[string is list $s] } {
|
|
return $s
|
|
} else {
|
|
return [split $s]
|
|
}
|
|
}
|
|
|
|
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}
|
|
set_ne sim(spice,0,fg) 0
|
|
set_ne sim(spice,0,st) 0
|
|
|
|
set_ne sim(spice,1,cmd) {ngspice -b -r "$n.raw" -o "$n.out" "$N"}
|
|
set sim(spice,1,name) {Ngspice batch}
|
|
set_ne sim(spice,1,fg) 0
|
|
set_ne sim(spice,1,st) 1
|
|
|
|
set_ne sim(spice,2,cmd) "Xyce \"\$N\"\n# Add -r \"\$n.raw\" if you want all variables saved"
|
|
set sim(spice,2,name) {Xyce batch}
|
|
set_ne sim(spice,2,fg) 0
|
|
set_ne sim(spice,2,st) 1
|
|
|
|
set_ne sim(spice,3,cmd) {mpirun /path/to/parallel/Xyce "$N"}
|
|
set sim(spice,3,name) {Xyce parallel batch}
|
|
set_ne sim(spice,3,fg) 0
|
|
set_ne sim(spice,3,st) 1
|
|
|
|
# number of configured spice simulators, and default one
|
|
set_ne sim(spice,n) 4
|
|
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) {Ngpice 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
|
|
|
|
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
|
|
|
|
### verilog
|
|
set_ne sim(verilog,0,cmd) {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
|
|
# number of configured verilog simulators, and default one
|
|
set_ne sim(verilog,n) 1
|
|
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 700x340
|
|
frame .sim.topf
|
|
set scrollframe [sframe .sim.topf]
|
|
frame ${scrollframe}.top
|
|
frame ${scrollframe}.center
|
|
frame .sim.bottom
|
|
pack ${scrollframe}.top -fill x
|
|
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 -bg $bg($toggle)
|
|
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 -bg $bg($toggle)
|
|
radiobutton ${scrollframe}.center.$tool.r.$i.radio -bg $bg($toggle) \
|
|
-variable sim($tool,default) -value $i
|
|
text ${scrollframe}.center.$tool.r.$i.cmd -width 20 -height 3 -wrap none -bg $bg($toggle)
|
|
${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) -bg $bg($toggle)
|
|
checkbutton ${scrollframe}.center.$tool.r.$i.st -text Status -variable sim($tool,$i,st) -bg $bg($toggle)
|
|
|
|
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.
|
|
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.
|
|
Any changes made in the command or tool name entries will be saved in
|
|
~/.xschem/simrc when 'Save Configuration to file' button is pressed.
|
|
If 'Accept 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 {Save Configuration to file} -command "simconf_saveconf $scrollframe"
|
|
button .sim.bottom.reset -text {Reset to default} -command {
|
|
simconf_reset
|
|
}
|
|
button .sim.bottom.close -text {Accept 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 <Configure> {scrollyview .sim.topf}
|
|
bind .sim <Configure> {
|
|
set simconf_default_geometry [wm geometry .sim]
|
|
}
|
|
bind .sim <ButtonPress-4> { scrollyview .sim.topf scroll -0.2}
|
|
bind .sim <ButtonPress-5> { scrollyview .sim.topf scroll 0.2}
|
|
scrollyview .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)
|
|
}
|
|
|
|
proc bespice_getdata {sock} {
|
|
global bespice_server_getdata
|
|
if {[eof $sock] || [catch {gets $sock bespice_server_getdata(line,$sock)}]} {
|
|
close $sock
|
|
puts "Close $bespice_server_getdata(addr,$sock)"
|
|
unset bespice_server_getdata(addr,$sock)
|
|
unset bespice_server_getdata(line,$sock)
|
|
unset bespice_server_getdata(sock)
|
|
} 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
|
|
if {[eof $sock] || [catch {gets $sock xschem_server_getdata(line,$sock)}]} {
|
|
close $sock
|
|
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)
|
|
} else {
|
|
puts "tcp--> $xschem_server_getdata(line,$sock)"
|
|
# xschem command must be executed at global scope...
|
|
uplevel #0 [list catch $xschem_server_getdata(line,$sock) xschem_server_getdata(res,$sock)]
|
|
puts $sock "$xschem_server_getdata(res,$sock)"
|
|
}
|
|
}
|
|
|
|
proc bespice_server {sock addr port} {
|
|
global bespice_server_getdata
|
|
if { ![info exists bespice_server_getdata(sock)] } {
|
|
puts "Accept $sock from $addr port $port"
|
|
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]
|
|
}
|
|
}
|
|
|
|
|
|
proc xschem_server {sock addr port} {
|
|
global xschem_server_getdata
|
|
puts "Accept $sock from $addr port $port"
|
|
fconfigure $sock -buffering line
|
|
set xschem_server_getdata(addr,$sock) [list $addr $port]
|
|
fileevent $sock readable [list xschem_getdata $sock]
|
|
}
|
|
|
|
## 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
|
|
# 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 {} {
|
|
if { [file exists [abs_sym_path devices/lab_pin.sym]] } {
|
|
return {devices/lab_pin.sym}
|
|
}
|
|
return {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
|
|
}
|
|
|
|
proc simulate {{callback {}}} {
|
|
## $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)
|
|
## $S : schematic name full path (/home/schippes/.xschem/xschem_library/opamp.sch)
|
|
## $d : netlist directory
|
|
|
|
global netlist_dir terminal sim
|
|
global execute XSCHEM_SHAREDIR has_x OS
|
|
|
|
simuldir
|
|
set_sim_defaults
|
|
set netlist_type [xschem get netlist_type]
|
|
if { [select_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 $sim($tool,$def,cmd)]
|
|
if {$OS == "Windows"} {
|
|
# $cmd cannot be surrounded by {} as exec will change forward slash to backward slash
|
|
if { $callback ne {} } {
|
|
uplevel #0 "eval cd $netlist_dir; $callback"
|
|
}
|
|
#eval exec {cmd /V /C "cd $netlist_dir&&$cmd}
|
|
eval exec $cmd &
|
|
return -1 ;# no execute ID on windows
|
|
} else {
|
|
set execute(callback) $callback
|
|
set id [$fg $st sh -c "cd $netlist_dir; $cmd"]
|
|
puts "Simulation started: execution ID: $id"
|
|
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
|
|
|
|
if { [info exists gaw_fd] } { return 1; }
|
|
simuldir
|
|
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
|
|
}
|
|
chan configure $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
|
|
|
|
simuldir
|
|
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
|
|
}
|
|
chan configure $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 {} {
|
|
## $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)
|
|
## $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
|
|
|
|
simuldir
|
|
set netlist_type [xschem get netlist_type]
|
|
set_sim_defaults
|
|
if { [select_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 $sim($tool,$def,cmd)]
|
|
$fg $st sh -c "cd $netlist_dir; $cmd"
|
|
}
|
|
}
|
|
# ============================================================
|
|
|
|
|
|
|
|
|
|
# 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 colors graph_sel_wave
|
|
global graph_schname
|
|
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 getprop rect 2 $graph_selected node]
|
|
# 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 rect 2 $graph_selected color $col fast
|
|
xschem draw_graph $graph_selected
|
|
toplevel .graphdialog
|
|
frame .graphdialog.f
|
|
button .graphdialog.ok -text OK -command {destroy .graphdialog}
|
|
button .graphdialog.cancel -text Cancel -command {destroy .graphdialog}
|
|
for {set i 4} {$i < 22} {incr i} {
|
|
radiobutton .graphdialog.f.r$i -value $i -bg [lindex $colors $i] \
|
|
-variable graph_sel_color -command {graph_change_wave_color $graph_sel_wave }
|
|
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} ....
|
|
proc graph_add_nodes_from_list {nodelist} {
|
|
global graph_bus graph_selected graph_schname
|
|
set sel {}
|
|
if {$graph_bus} {
|
|
set sep ,
|
|
} else {
|
|
set sep \n
|
|
}
|
|
|
|
if { [winfo exists .graphdialog] } {
|
|
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 rect 2 $graph_selected color $col fastundo
|
|
graph_update_nodelist
|
|
regsub -all {\\?(["\\])} $node {\\\1} node_quoted ;#"4vim
|
|
xschem setprop rect 2 $graph_selected node $node_quoted fast
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
} else {
|
|
set graph_bus 0
|
|
set nn {}
|
|
set cc {}
|
|
foreach {n c} $nodelist {
|
|
if { $nn ne {}} {append nn \n}
|
|
if { $cc ne {}} {append cc " "}
|
|
append nn $n
|
|
append cc $c
|
|
}
|
|
|
|
set nnn [xschem getprop rect 2 [xschem get graph_lastsel] node]
|
|
set ccc [xschem getprop rect 2 [xschem get graph_lastsel] color]
|
|
if { $nnn ne {}} {append nnn "\n"}
|
|
if { $ccc ne {}} {append ccc " "}
|
|
append nnn $nn
|
|
append ccc $cc
|
|
regsub -all {\\?(["\\])} $nnn {\\\1} node_quoted ;#"4vim
|
|
xschem setprop rect 2 [xschem get graph_lastsel] color $ccc fastundo
|
|
xschem setprop rect 2 [xschem get graph_lastsel] node $node_quoted fast
|
|
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]
|
|
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
|
|
}
|
|
|
|
# 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 tag [.graphdialog.center.right.text1 tag names insert]
|
|
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 rect 2 $graph_selected color $col fast
|
|
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 rect 2 $graph_selected color $col fast
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
|
|
# tag nodes in text widget with assigned colors
|
|
proc graph_update_nodelist {} {
|
|
global graph_selected colors graph_sel_color graph_schname
|
|
if { [xschem get schname] ne $graph_schname } return
|
|
# delete old tags
|
|
eval .graphdialog.center.right.text1 tag delete [ .graphdialog.center.right.text1 tag names]
|
|
# tagging nodes in text widget:
|
|
set col [xschem getprop rect 2 $graph_selected color]
|
|
set col [string trim $col " \n"]
|
|
|
|
set regx {(?:(tcleval\()?"[^"]+"\)?)|(?:(tcleval\()?[^\n \t]+\)?)}
|
|
set txt [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}]
|
|
set tt {}
|
|
set cc {}
|
|
set start 0
|
|
while {[regexp -indices -start $start $regx $txt idx]} {
|
|
lappend tt [lindex $idx 0]
|
|
set start [expr {[lindex $idx 1] + 1}]
|
|
lappend cc $start
|
|
}
|
|
|
|
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 $colors $col_idx]
|
|
.graphdialog.center.right.text1 tag add t$n "1.0 + $t chars" "1.0 + $c chars"
|
|
.graphdialog.center.right.text1 tag configure t$n -background $b -selectbackground grey40
|
|
incr n
|
|
}
|
|
# remove excess colors
|
|
set col [lrange $col 0 [expr {$n - 1}]]
|
|
## for debug
|
|
# if { [llength $col] != [llength [tolist [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}]]] } {
|
|
# puts "PROBLEMS: colors and nodes of different length"
|
|
# }
|
|
} else {
|
|
set col {}
|
|
}
|
|
xschem setprop rect 2 $graph_selected color $col fast
|
|
}
|
|
|
|
proc fill_graph_listbox {} {
|
|
set retval [.graphdialog.top.search get]
|
|
set retval [graph_get_signal_list [xschem raw_query list] $retval]
|
|
.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 update_graph_node {node} {
|
|
global graph_selected
|
|
graph_update_nodelist
|
|
regsub -all {\\?(["\\])} $node {\\\1} node_quoted ;#"4vim
|
|
xschem setprop rect 2 $graph_selected node $node_quoted fast
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
proc 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
|
|
}
|
|
xschem setprop rect 2 $graph_selected $div $divis
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
|
|
proc graph_edit_properties {n} {
|
|
global graph_bus graph_sort graph_digital graph_selected colors graph_sel_color
|
|
global graph_unlocked graph_schname graph_logx graph_logy
|
|
|
|
xschem push_undo
|
|
set geom {}
|
|
if { [winfo exists .graphdialog]} {
|
|
set geom [winfo geometry .graphdialog]
|
|
}
|
|
catch {destroy .graphdialog}
|
|
toplevel .graphdialog -width 1 -height 1
|
|
update idletasks
|
|
if {$geom ne {}} { wm geometry .graphdialog $geom}
|
|
|
|
set graph_selected $n
|
|
set graph_schname [xschem get schname]
|
|
set_ne graph_sel_color 4
|
|
set_ne graph_sort 0
|
|
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_digital 0
|
|
if {[xschem getprop rect 2 $n digital] == 1} {set graph_digital 1}
|
|
if {[regexp {unlocked} [xschem getprop rect 2 $n flags]]} {
|
|
set graph_unlocked 1
|
|
} else {
|
|
set graph_unlocked 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.lab1 -text {Signal list}
|
|
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.lab1 .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
|
|
label .graphdialog.center.right.lab1 -text {Signals in graph}
|
|
text .graphdialog.center.right.text1 -wrap none -width 50 -height 5 -bg grey70 -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.lab1
|
|
grid .graphdialog.center.right.text1 - .graphdialog.center.right.yscroll -sticky nsew
|
|
grid .graphdialog.center.right.xscroll - -sticky nsew
|
|
grid rowconfig .graphdialog.center.right 0 -weight 0
|
|
grid rowconfig .graphdialog.center.right 1 -weight 1 -minsize 3c
|
|
grid columnconfig .graphdialog.center.right 0 -weight 1
|
|
grid columnconfig .graphdialog.center.right 1 -weight 1
|
|
|
|
# bottom frame
|
|
button .graphdialog.bottom.cancel -text Cancel -command {
|
|
destroy .graphdialog
|
|
set graph_selected {}
|
|
set graph_schname {}
|
|
}
|
|
button .graphdialog.bottom.ok -text OK -command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
|
|
update_graph_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
xschem setprop rect 2 $graph_selected x1 [.graphdialog.top3.xmin get] fast
|
|
xschem setprop rect 2 $graph_selected x2 [.graphdialog.top3.xmax get] fast
|
|
xschem setprop rect 2 $graph_selected y1 [.graphdialog.top3.min get] fast
|
|
xschem setprop rect 2 $graph_selected y2 [.graphdialog.top3.max get] fast
|
|
|
|
if {$graph_unlocked} {
|
|
xschem setprop rect 2 $graph_selected flags {graph,unlocked} fast
|
|
} else {
|
|
xschem setprop rect 2 $graph_selected flags {graph} fast
|
|
}
|
|
destroy .graphdialog
|
|
set graph_selected {}
|
|
set graph_schname {}
|
|
} else {
|
|
destroy .graphdialog
|
|
set graph_selected {}
|
|
set graph_schname {}
|
|
}
|
|
}
|
|
button .graphdialog.bottom.apply -text Apply -command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
|
|
update_graph_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
xschem setprop rect 2 $graph_selected x1 [.graphdialog.top3.xmin get] fast
|
|
xschem setprop rect 2 $graph_selected x2 [.graphdialog.top3.xmax get] fast
|
|
xschem setprop rect 2 $graph_selected y1 [.graphdialog.top3.min get] fast
|
|
xschem setprop rect 2 $graph_selected y2 [.graphdialog.top3.max get] fast
|
|
if {$graph_unlocked} {
|
|
xschem setprop rect 2 $graph_selected flags {graph,unlocked} fast
|
|
} else {
|
|
xschem setprop rect 2 $graph_selected flags {graph} fast
|
|
}
|
|
}
|
|
}
|
|
|
|
# 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 < 22} {incr i} {
|
|
radiobutton .graphdialog.bottom.r$i -value $i -bg [lindex $colors $i] \
|
|
-variable graph_sel_color -command graph_change_wave_color
|
|
pack .graphdialog.bottom.r$i -side left
|
|
}
|
|
|
|
# top2 frame
|
|
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 {
|
|
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 {
|
|
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
|
|
bind .graphdialog.top2.divx <KeyRelease> {
|
|
update_div $graph_selected divx
|
|
}
|
|
|
|
label .graphdialog.top2.labdivy -text { Y div.}
|
|
entry .graphdialog.top2.divy -width 2
|
|
bind .graphdialog.top2.divy <KeyRelease> {
|
|
update_div $graph_selected divy
|
|
}
|
|
|
|
label .graphdialog.top2.labsubdivx -text { X subdiv.}
|
|
entry .graphdialog.top2.subdivx -width 2
|
|
bind .graphdialog.top2.subdivx <KeyRelease> {
|
|
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
|
|
bind .graphdialog.top2.subdivy <KeyRelease> {
|
|
xschem setprop rect 2 $graph_selected subdivy [.graphdialog.top2.subdivy get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top2.labdset -text { Dataset}
|
|
entry .graphdialog.top2.dset -width 4
|
|
bind .graphdialog.top2.dset <KeyRelease> {
|
|
xschem setprop rect 2 $graph_selected dataset [.graphdialog.top2.dset get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
.graphdialog.top2.dset insert 0 [xschem getprop rect 2 $graph_selected dataset]
|
|
|
|
label .graphdialog.top2.labsweep -text { Sweep}
|
|
entry .graphdialog.top2.sweep -width 10
|
|
bind .graphdialog.top2.sweep <KeyRelease> {
|
|
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
|
|
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 \
|
|
.graphdialog.top2.labdset .graphdialog.top2.dset \
|
|
.graphdialog.top2.labsweep .graphdialog.top2.sweep -side left
|
|
|
|
# top frame
|
|
label .graphdialog.top.labsearch -text Search:
|
|
entry .graphdialog.top.search -width 10
|
|
checkbutton .graphdialog.top.bus -text Bus -padx 2 -variable graph_bus
|
|
checkbutton .graphdialog.top.incr -text {Incr. sort} -variable graph_sort -indicatoron 1 \
|
|
-command fill_graph_listbox
|
|
checkbutton .graphdialog.top.unlocked -text {Unlocked X axis} -variable graph_unlocked
|
|
checkbutton .graphdialog.top.dig -text {Digital} -variable graph_digital -indicatoron 1 \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
xschem setprop rect 2 $graph_selected digital $graph_digital fast
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
|
|
label .graphdialog.top3.xlabmin -text { X min:}
|
|
entry .graphdialog.top3.xmin -width 7
|
|
bind .graphdialog.top3.xmin <KeyRelease> {
|
|
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
|
|
bind .graphdialog.top3.xmax <KeyRelease> {
|
|
xschem setprop rect 2 $graph_selected x2 [.graphdialog.top3.xmax get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
|
|
label .graphdialog.top3.labmin -text { Y min:}
|
|
entry .graphdialog.top3.min -width 7
|
|
bind .graphdialog.top3.min <KeyRelease> {
|
|
xschem setprop rect 2 $graph_selected y1 [.graphdialog.top3.min get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
label .graphdialog.top3.labmax -text { Y max:}
|
|
entry .graphdialog.top3.max -width 7
|
|
bind .graphdialog.top3.max <KeyRelease> {
|
|
xschem setprop rect 2 $graph_selected y2 [.graphdialog.top3.max get]
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
|
|
button .graphdialog.top.clear -text Clear -padx 2 -command {
|
|
.graphdialog.top.search delete 0 end
|
|
fill_graph_listbox
|
|
}
|
|
pack .graphdialog.top.labsearch .graphdialog.top.search -side left
|
|
pack .graphdialog.top.clear -side left
|
|
pack .graphdialog.top.incr -side left
|
|
pack .graphdialog.top.bus -side left
|
|
pack .graphdialog.top.dig -side left
|
|
pack .graphdialog.top.unlocked -side left
|
|
.graphdialog.top3.min insert 0 [xschem getprop rect 2 $graph_selected y1]
|
|
.graphdialog.top3.max 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]
|
|
|
|
# top3 frame
|
|
set graph_logx [xschem getprop rect 2 $graph_selected logx]
|
|
set graph_logy [xschem getprop rect 2 $graph_selected logy]
|
|
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 scale} -variable graph_logx \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
xschem setprop rect 2 $graph_selected logx $graph_logx fast
|
|
if { $graph_logx eq 1} {
|
|
xschem setprop rect 2 $graph_selected subdivx 8 fast
|
|
.graphdialog.top2.subdivx delete 0 end
|
|
.graphdialog.top2.subdivx insert 0 8
|
|
} else {
|
|
xschem setprop rect 2 $graph_selected subdivx 4 fast
|
|
.graphdialog.top2.subdivx delete 0 end
|
|
.graphdialog.top2.subdivx insert 0 4
|
|
}
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
|
|
checkbutton .graphdialog.top3.logy -text {Log Y scale} -variable graph_logy \
|
|
-command {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
xschem setprop rect 2 $graph_selected logy $graph_logy fast
|
|
if { $graph_logy eq 1} {
|
|
xschem setprop rect 2 $graph_selected subdivy 8 fast
|
|
.graphdialog.top2.subdivy delete 0 end
|
|
.graphdialog.top2.subdivy insert 0 8
|
|
} else {
|
|
xschem setprop rect 2 $graph_selected subdivy 4 fast
|
|
.graphdialog.top2.subdivy delete 0 end
|
|
.graphdialog.top2.subdivy insert 0 4
|
|
}
|
|
xschem draw_graph $graph_selected
|
|
}
|
|
}
|
|
pack .graphdialog.top3.logx .graphdialog.top3.logy -side left
|
|
pack .graphdialog.top3.xlabmin .graphdialog.top3.xmin .graphdialog.top3.xlabmax .graphdialog.top3.xmax -side left
|
|
pack .graphdialog.top3.labmin .graphdialog.top3.min .graphdialog.top3.labmax .graphdialog.top3.max -side left
|
|
# binding
|
|
bind .graphdialog.top.search <KeyRelease> {
|
|
fill_graph_listbox
|
|
}
|
|
bind .graphdialog.center.left.list1 <Double-Button-1> {
|
|
graph_add_nodes
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
update_graph_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
}
|
|
}
|
|
|
|
bind .graphdialog.center.right.text1 <KeyRelease> {
|
|
if { [xschem get schname] eq $graph_schname } {
|
|
update_graph_node [string trim [.graphdialog.center.right.text1 get 1.0 {end - 1 chars}] " \n"]
|
|
}
|
|
}
|
|
bind .graphdialog <Control-Return> {
|
|
.graphdialog.bottom.ok invoke
|
|
}
|
|
bind .graphdialog <Escape> {
|
|
.graphdialog.bottom.cancel invoke
|
|
}
|
|
wm protocol .graphdialog WM_DELETE_WINDOW {
|
|
.graphdialog.bottom.cancel invoke
|
|
}
|
|
|
|
# fill data in left listbox
|
|
eval .graphdialog.center.left.list1 insert 0 [graph_get_signal_list [xschem raw_query list] {}]
|
|
|
|
# fill data in right textbox
|
|
set plotted_nodes [xschem getprop rect 2 $n node]
|
|
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
|
|
}
|
|
|
|
proc graph_show_measure {{action show}} {
|
|
global measure_id measure_text
|
|
|
|
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 -bg {}
|
|
label .measure.lab -text $measure_text -bg 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}]
|
|
}]
|
|
}
|
|
|
|
proc get_shell { curpath } {
|
|
global netlist_dir debug_var
|
|
global terminal
|
|
|
|
simuldir
|
|
execute 0 sh -c "cd $curpath && $terminal"
|
|
}
|
|
|
|
proc edit_netlist {netlist } {
|
|
global netlist_dir debug_var
|
|
global editor terminal OS
|
|
|
|
simuldir
|
|
set netlist_type [xschem get netlist_type]
|
|
|
|
if { [regexp vim $editor] } { set ftype "-c \":set filetype=$netlist_type\"" } else { set ftype {} }
|
|
if { [select_netlist_dir 0] ne "" } {
|
|
if {$OS == "Windows"} {
|
|
set cmd "$editor \"$netlist_dir/${netlist}\""
|
|
eval exec $cmd &
|
|
} else {
|
|
execute 0 sh -c "cd $netlist_dir && $editor $ftype \"${netlist}\""
|
|
}
|
|
}
|
|
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
|
|
}
|
|
|
|
proc is_xschem_file {f} {
|
|
set a [catch {open "$f" r} fd]
|
|
set ret 0
|
|
set score 0
|
|
set instances 0
|
|
if {$a} {
|
|
puts stderr "Can not open file $f"
|
|
} else {
|
|
fconfigure $fd -translation binary
|
|
while { [gets $fd line] >=0 } {
|
|
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
|
|
}
|
|
}
|
|
if { $score > 4 } { set ret 1} ;# Heuristic decision :-)
|
|
if { $ret } {
|
|
if { $instances} {
|
|
set ret SCHEMATIC
|
|
} else {
|
|
set ret SYMBOL
|
|
}
|
|
}
|
|
close $fd
|
|
}
|
|
# puts "score=$score"
|
|
return $ret
|
|
}
|
|
|
|
|
|
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) [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 {} {
|
|
variable c_t
|
|
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 -width 7 -state disabled -disabledforeground black \
|
|
-background grey60 -highlightthickness 0 -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) -width 7
|
|
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) "xschem abort_operation; myload_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 Recent component toolbar
|
|
|
|
proc myload_set_colors1 {} {
|
|
global myload_files1 dircolor
|
|
for {set i 0} { $i< [.load.l.paneleft.list index end] } { incr i} {
|
|
set name "[lindex $myload_files1 $i]"
|
|
.load.l.paneleft.list itemconfigure $i -foreground black -selectforeground black
|
|
foreach j [array names dircolor] {
|
|
set pattern $j
|
|
set color $dircolor($j)
|
|
if { [regexp $pattern $name] } {
|
|
.load.l.paneleft.list itemconfigure $i -foreground $color -selectforeground $color
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc myload_set_colors2 {} {
|
|
global myload_index1 myload_files2 dircolor
|
|
set dir1 [abs_sym_path [.load.l.paneleft.list get $myload_index1]]
|
|
for {set i 0} { $i< [.load.l.paneright.list index end] } { incr i} {
|
|
set name "$dir1/[lindex $myload_files2 $i]"
|
|
if {[ file isdirectory $name]} {
|
|
.load.l.paneright.list itemconfigure $i -foreground blue
|
|
foreach j [array names dircolor] {
|
|
set pattern $j
|
|
set color $dircolor($j)
|
|
if { [regexp $pattern $name] } {
|
|
.load.l.paneright.list itemconfigure $i -foreground $color -selectforeground $color
|
|
}
|
|
}
|
|
|
|
} else {
|
|
.load.l.paneright.list itemconfigure $i -foreground black
|
|
}
|
|
}
|
|
}
|
|
|
|
proc myload_set_home {dir} {
|
|
global pathlist myload_files1 myload_index1
|
|
|
|
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 myload_files1 $pathlist
|
|
update
|
|
myload_set_colors1
|
|
.load.l.paneleft.list xview moveto 1
|
|
set myload_index1 $i
|
|
.load.l.paneleft.list selection set $myload_index1
|
|
} else {
|
|
set myload_files1 [list $dir]
|
|
update
|
|
myload_set_colors1
|
|
.load.l.paneleft.list xview moveto 1
|
|
set myload_index1 0
|
|
.load.l.paneleft.list selection set 0
|
|
}
|
|
}
|
|
|
|
proc setglob {dir} {
|
|
global globfilter myload_files2
|
|
set myload_files2 [lsort [glob -nocomplain -directory $dir -tails -type d .* *]]
|
|
if { $globfilter eq {*}} {
|
|
set myload_files2 ${myload_files2}\ [lsort [glob -nocomplain -directory $dir -tails -type {f} .* $globfilter]]
|
|
} else {
|
|
set myload_files2 ${myload_files2}\ [lsort [glob -nocomplain -directory $dir -tails -type {f} $globfilter]]
|
|
}
|
|
}
|
|
|
|
proc load_file_dialog_mkdir {dir} {
|
|
global myload_dir1
|
|
if { $dir ne {} } {
|
|
file mkdir "${myload_dir1}/$dir"
|
|
setglob ${myload_dir1}
|
|
myload_set_colors2
|
|
}
|
|
}
|
|
proc load_file_dialog_up {dir} {
|
|
global myload_dir1
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
.load.l.paneright.draw configure -background white
|
|
set d [file dirname $dir]
|
|
if { [file isdirectory $d]} {
|
|
myload_set_home $d
|
|
setglob $d
|
|
myload_set_colors2
|
|
set myload_dir1 $d
|
|
}
|
|
}
|
|
|
|
|
|
proc myload_getresult {loadfile confirm_overwrt} {
|
|
global myload_dir1 myload_retval myload_ext
|
|
|
|
if { $myload_retval ne {}} {
|
|
if {![file exists "$myload_dir1/$myload_retval"] } {
|
|
return "$myload_dir1/$myload_retval"
|
|
}
|
|
if { $loadfile == 0 } {
|
|
if {[file exists "$myload_dir1/$myload_retval"]} {
|
|
if {$confirm_overwrt == 1 } {
|
|
set answer [tk_messageBox -message "Overwrite $myload_dir1/${myload_retval}?" \
|
|
-icon warning -parent [xschem get topwindow] -type okcancel]
|
|
} else {
|
|
set answer ok
|
|
}
|
|
if {$answer eq {ok}} {
|
|
return "$myload_dir1/$myload_retval"
|
|
} else {
|
|
return {}
|
|
}
|
|
}
|
|
}
|
|
set myload_type [is_xschem_file "$myload_dir1/$myload_retval"]
|
|
if { $myload_type eq {0} } {
|
|
set answer [
|
|
tk_messageBox -message "$myload_dir1/$myload_retval does not seem to be an xschem file...\nContinue?" \
|
|
-icon warning -parent [xschem get topwindow] -type yesno]
|
|
if { $answer eq "no"} {
|
|
set myload_retval {}
|
|
return {}
|
|
} else {
|
|
return "$myload_dir1/$myload_retval"
|
|
}
|
|
} elseif { $myload_type ne {SYMBOL} && ($myload_ext eq {*.sym}) } {
|
|
set answer [
|
|
tk_messageBox -message "$myload_dir1/$myload_retval does not seem to be a SYMBOL file...\nContinue?" \
|
|
-icon warning -parent [xschem get topwindow] -type yesno]
|
|
if { $answer eq "no"} {
|
|
set myload_retval {}
|
|
return {}
|
|
} else {
|
|
return "$myload_dir1/$myload_retval"
|
|
}
|
|
} else {
|
|
return "$myload_dir1/$myload_retval"
|
|
}
|
|
} else {
|
|
return {}
|
|
}
|
|
}
|
|
|
|
proc myload_display_preview {f} {
|
|
set myload_type [is_xschem_file $f]
|
|
if { $myload_type ne {0} } {
|
|
### update
|
|
if { [winfo exists .load] } {
|
|
.load.l.paneright.draw configure -background {}
|
|
xschem preview_window draw .load.l.paneright.draw "$f"
|
|
bind .load.l.paneright.draw <Expose> [subst {xschem preview_window draw .load.l.paneright.draw "$f"}]
|
|
|
|
}
|
|
} else {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
.load.l.paneright.draw configure -background white
|
|
}
|
|
}
|
|
|
|
# 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 myload_index1 myload_files2 myload_files1 myload_retval myload_dir1 pathlist OS
|
|
global myload_default_geometry myload_sash_pos myload_yview tcl_version globfilter myload_dir2
|
|
global save_initialfile myload_loadfile myload_ext
|
|
|
|
if { [winfo exists .load] } {
|
|
.load.buttons_bot.cancel invoke
|
|
}
|
|
set myload_loadfile $loadfile
|
|
set myload_ext $ext
|
|
set globfilter $ext
|
|
set save_initialfile $initialf
|
|
set myload_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
|
|
set_ne myload_index1 0
|
|
if { ![info exists myload_files1]} {
|
|
set myload_files1 $pathlist
|
|
set myload_index1 0
|
|
}
|
|
set_ne myload_files2 {}
|
|
panedwindow .load.l -orient horizontal -height 8c
|
|
if { $loadfile == 2} {frame .load.l.recent}
|
|
frame .load.l.paneleft
|
|
eval [subst {listbox .load.l.paneleft.list -listvariable myload_files1 -width 20 -height 12 \
|
|
-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
|
|
}
|
|
myload_set_colors1
|
|
scrollbar .load.l.paneleft.yscroll -command ".load.l.paneleft.list yview"
|
|
scrollbar .load.l.paneleft.xscroll -command ".load.l.paneleft.list xview" -orient horiz
|
|
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
|
|
bind .load.l.paneleft.list <<ListboxSelect>> {
|
|
# bind .load.l.paneright.draw <Expose> {}
|
|
# .load.l.paneright.draw configure -background white
|
|
set myload_sel [.load.l.paneleft.list curselection]
|
|
if { $myload_sel ne {} } {
|
|
set myload_dir1 [abs_sym_path [.load.l.paneleft.list get $myload_sel]]
|
|
set myload_index1 $myload_sel
|
|
set globfilter $myload_ext
|
|
if {$save_initialfile eq {}} {.load.buttons_bot.entry delete 0 end}
|
|
setglob $myload_dir1
|
|
myload_set_colors2
|
|
}
|
|
}
|
|
frame .load.l.paneright
|
|
frame .load.l.paneright.draw -background white -height 3.8c
|
|
listbox .load.l.paneright.list -listvariable myload_files2 -width 20 -height 12\
|
|
-yscrollcommand ".load.l.paneright.yscroll set" -selectmode browse \
|
|
-xscrollcommand ".load.l.paneright.xscroll set" -exportselection 0
|
|
scrollbar .load.l.paneright.yscroll -command ".load.l.paneright.list yview"
|
|
scrollbar .load.l.paneright.xscroll -command ".load.l.paneright.list xview" -orient horiz
|
|
pack .load.l.paneright.draw -side bottom -anchor s -fill x
|
|
pack .load.l.paneright.yscroll -side right -fill y
|
|
pack .load.l.paneright.xscroll -side bottom -fill x
|
|
pack .load.l.paneright.list -side bottom -fill both -expand true
|
|
|
|
if { $loadfile == 2} {
|
|
.load.l add .load.l.recent -minsize 30
|
|
c_toolbar::display
|
|
}
|
|
.load.l add .load.l.paneleft -minsize 40
|
|
.load.l add .load.l.paneright -minsize 40
|
|
# .load.l paneconfigure .load.l.paneleft -stretch always
|
|
# .load.l paneconfigure .load.l.paneright -stretch always
|
|
frame .load.buttons
|
|
frame .load.buttons_bot
|
|
button .load.buttons_bot.ok -width 5 -text OK -command {
|
|
set myload_retval [.load.buttons_bot.entry get]
|
|
destroy .load
|
|
xschem preview_window destroy {} {}
|
|
set initdir "$myload_dir1"
|
|
}
|
|
button .load.buttons_bot.cancel -width 5 -text Cancel -command {
|
|
set myload_retval {}
|
|
destroy .load
|
|
if {$myload_loadfile == 2} {xschem abort_operation}
|
|
xschem preview_window destroy {} {}
|
|
set initdir "$myload_dir1"
|
|
}
|
|
button .load.buttons.home -width 5 -text {Home} -command {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
.load.l.paneright.draw configure -background white
|
|
set myload_files1 $pathlist
|
|
update
|
|
myload_set_colors1
|
|
.load.l.paneleft.list xview moveto 1
|
|
set myload_index1 0
|
|
set myload_dir1 [abs_sym_path [.load.l.paneleft.list get $myload_index1]]
|
|
setglob $myload_dir1
|
|
myload_set_colors2
|
|
.load.l.paneleft.list selection clear 0 end
|
|
.load.l.paneright.list selection clear 0 end
|
|
.load.l.paneleft.list selection set $myload_index1
|
|
}
|
|
label .load.buttons_bot.label -text { File/Search:}
|
|
entry .load.buttons_bot.entry
|
|
if { $save_initialfile ne {} } {
|
|
.load.buttons_bot.entry insert 0 $save_initialfile
|
|
}
|
|
bind .load.buttons_bot.entry <KeyRelease> {
|
|
if {$save_initialfile eq {} } {
|
|
set globfilter *[.load.buttons_bot.entry get]*
|
|
if { $globfilter eq {**} } { set globfilter * }
|
|
setglob $myload_dir1
|
|
}
|
|
}
|
|
radiobutton .load.buttons_bot.all -text All -variable globfilter -value {*} \
|
|
-command { setglob $myload_dir1 }
|
|
radiobutton .load.buttons_bot.sym -text .sym -variable globfilter -value {*.sym} \
|
|
-command { setglob $myload_dir1 }
|
|
radiobutton .load.buttons_bot.sch -text .sch -variable globfilter -value {*.sch} \
|
|
-command { setglob $myload_dir1 }
|
|
button .load.buttons.up -width 5 -text Up -command {load_file_dialog_up $myload_dir1}
|
|
label .load.buttons.mkdirlab -text { New dir: } -fg blue
|
|
entry .load.buttons.newdir -width 16
|
|
button .load.buttons.mkdir -width 5 -text Create -fg blue -command {
|
|
load_file_dialog_mkdir [.load.buttons.newdir get]
|
|
}
|
|
button .load.buttons.rmdir -width 5 -text Delete -fg blue -command {
|
|
if { [.load.buttons.newdir get] ne {} } {
|
|
file delete "${myload_dir1}/[.load.buttons.newdir get]"
|
|
setglob ${myload_dir1}
|
|
myload_set_colors2
|
|
}
|
|
}
|
|
button .load.buttons.pwd -text {Current dir} -command {load_file_dialog_up [xschem get schname]}
|
|
pack .load.buttons.home .load.buttons.up .load.buttons.pwd -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.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 myload_default_geometry]} {
|
|
wm geometry .load "${myload_default_geometry}"
|
|
}
|
|
myload_set_home $initdir
|
|
if { $loadfile != 2} {
|
|
bind .load <Return> {
|
|
set myload_retval [.load.buttons_bot.entry get]
|
|
if {$myload_retval ne {} } {
|
|
destroy .load
|
|
xschem preview_window destroy {} {}
|
|
set initdir "$myload_dir1"
|
|
}
|
|
}
|
|
bind .load.l.paneright.list <Double-Button-1> {
|
|
set myload_retval [.load.buttons_bot.entry get]
|
|
if {$myload_retval ne {} &&
|
|
![file isdirectory "$myload_dir1/[.load.l.paneright.list get $myload_sel]"]} {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
destroy .load
|
|
xschem preview_window destroy {} {}
|
|
set initdir "$myload_dir1"
|
|
}
|
|
}
|
|
}
|
|
bind .load <Escape> {
|
|
set myload_retval {}
|
|
destroy .load
|
|
if {$myload_loadfile == 2} {xschem abort_operation}
|
|
xschem preview_window destroy {} {}
|
|
set initdir "$myload_dir1"
|
|
}
|
|
|
|
### update
|
|
if { [ info exists myload_sash_pos] } {
|
|
eval .load.l sash mark 0 [.load.l sash coord 0]
|
|
eval .load.l sash dragto 0 [subst $myload_sash_pos]
|
|
}
|
|
### update
|
|
.load.l.paneleft.list xview moveto 1
|
|
bind .load <Configure> {
|
|
set myload_sash_pos [.load.l sash coord 0]
|
|
set myload_default_geometry [wm geometry .load]
|
|
.load.l.paneleft.list xview moveto 1
|
|
# regsub {\+.*} $myload_default_geometry {} myload_default_geometry
|
|
}
|
|
|
|
bind .load.l.paneright.yscroll <Motion> {
|
|
set myload_yview [.load.l.paneright.list yview]
|
|
}
|
|
|
|
xschem preview_window create .load.l.paneright.draw {}
|
|
set myload_dir1 [abs_sym_path [.load.l.paneleft.list get $myload_index1]]
|
|
setglob $myload_dir1
|
|
myload_set_colors2
|
|
|
|
bind .load.l.paneright.list <ButtonPress> {
|
|
set myload_yview [.load.l.paneright.list yview]
|
|
}
|
|
bind .load.l.paneright.list <<ListboxSelect>> {
|
|
set myload_yview [.load.l.paneright.list yview]
|
|
set myload_sel [.load.l.paneright.list curselection]
|
|
if { $myload_sel ne {} } {
|
|
set myload_dir1 [abs_sym_path [.load.l.paneleft.list get $myload_index1]]
|
|
set myload_dir2 [.load.l.paneright.list get $myload_sel]
|
|
if {$myload_dir2 eq {..}} {
|
|
set myload_d [file dirname $myload_dir1]
|
|
} elseif { $myload_dir2 eq {.} } {
|
|
set myload_d $myload_dir1
|
|
} else {
|
|
if {$OS == "Windows"} {
|
|
if {[regexp {^[A-Za-z]\:/$} $myload_dir1]} {
|
|
set myload_d "$myload_dir1$myload_dir2"
|
|
} else {
|
|
set myload_d "$myload_dir1/$myload_dir2"
|
|
}
|
|
} else {
|
|
if {$myload_dir1 eq "/"} {
|
|
set myload_d "$myload_dir1$myload_dir2"
|
|
} else {
|
|
set myload_d "$myload_dir1/$myload_dir2"
|
|
}
|
|
}
|
|
}
|
|
if { [file isdirectory $myload_d]} {
|
|
bind .load.l.paneright.draw <Expose> {}
|
|
.load.l.paneright.draw configure -background white
|
|
myload_set_home $myload_d
|
|
setglob $myload_d
|
|
myload_set_colors2
|
|
set myload_dir1 $myload_d
|
|
# .load.buttons_bot.entry delete 0 end
|
|
} else {
|
|
.load.buttons_bot.entry delete 0 end
|
|
.load.buttons_bot.entry insert 0 $myload_dir2
|
|
myload_display_preview $myload_dir1/$myload_dir2
|
|
# puts "xschem preview_window draw .load.l.paneright.draw \"$myload_dir1/$myload_dir2\""
|
|
}
|
|
}
|
|
if {$myload_loadfile == 2} {
|
|
set myload_retval [.load.buttons_bot.entry get]
|
|
set r [myload_getresult 2 0]
|
|
# puts "r=$r myload_dir1=$myload_dir1 myload_dir2=$myload_dir2"
|
|
xschem abort_operation
|
|
if {$r ne {}} {
|
|
xschem place_symbol "$myload_dir1/$myload_dir2"
|
|
}
|
|
}
|
|
};# bind .load.l.paneright.list <<ListboxSelect>>
|
|
if { [ info exists myload_yview]} {
|
|
.load.l.paneright.list yview moveto [lindex $myload_yview 0]
|
|
}
|
|
if {$loadfile != 2} {
|
|
tkwait window .load
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
return [myload_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_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]
|
|
if { [file exists [abs_sym_path devices/ipin.sym]] } {
|
|
set indirect 1
|
|
} else {
|
|
set indirect 0
|
|
}
|
|
# viewdata $retval
|
|
set pcnt 0
|
|
set y 0
|
|
set fd [open $USER_CONF_DIR/.clipboard.sch "w"]
|
|
foreach i $lines {
|
|
if {$indirect} {
|
|
puts $fd "C \{[rel_sym_path devices/[lindex $i 1].sym]\} 0 [set y [expr {$y-20}]] \
|
|
0 0 \{ name=p[incr pcnt] lab=[lindex $i 0] \}"
|
|
} else {
|
|
puts $fd "C \{[rel_sym_path [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
|
|
|
|
if { [file exists [abs_sym_path devices/ipin.sym]] } {
|
|
set indirect 1
|
|
} else {
|
|
set indirect 0
|
|
}
|
|
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 {
|
|
if {$indirect} {
|
|
puts $fd "C \{devices/lab_pin.sym\} 0 [set y [expr {$y+20}]] \
|
|
0 0 \{ name=p[incr pcnt] verilog_type=wire lab=[lindex $i 0] \}"
|
|
} else {
|
|
puts $fd "C \{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
|
|
|
|
if { [file exists [abs_sym_path devices/ipin.sym]] } {
|
|
set indirect 1
|
|
} else {
|
|
set indirect 0
|
|
}
|
|
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 {
|
|
if {$indirect} {
|
|
puts $fd "C \{devices/lab_pin.sym\} 0 [set y [expr {$y+20}]] \
|
|
0 0 \{ name=p[incr pcnt] verilog_type=reg lab=i[lindex $i 0] \}"
|
|
} else {
|
|
puts $fd "C \{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} {
|
|
global XSCHEM_SHAREDIR symbol_width
|
|
set name [abs_sym_path $name ]
|
|
# 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 {}
|
|
}
|
|
|
|
# create simulation dir 'simulation/' under current schematic directory
|
|
proc simuldir {} {
|
|
global netlist_dir local_netlist_dir
|
|
if { $local_netlist_dir == 1 } {
|
|
set simdir [xschem get current_dirname]/simulation
|
|
file mkdir $simdir
|
|
set netlist_dir $simdir
|
|
return $netlist_dir
|
|
}
|
|
return {}
|
|
}
|
|
|
|
#
|
|
# force==0: force creation of $netlist_dir (if not empty)
|
|
# if netlist_dir empty and no dir given prompt user
|
|
# else set netlist_dir to dir
|
|
#
|
|
# force==1: if no dir given prompt user
|
|
# else set netlist_dir to dir
|
|
#
|
|
proc select_netlist_dir { force {dir {} }} {
|
|
global netlist_dir env OS
|
|
|
|
if { ( $force == 0 ) && ( $netlist_dir ne {} ) } {
|
|
if {![file exist $netlist_dir]} {
|
|
file mkdir $netlist_dir
|
|
}
|
|
regsub {^~/} $netlist_dir ${env(HOME)}/ netlist_dir
|
|
return $netlist_dir
|
|
}
|
|
if { $dir eq {} } {
|
|
if { $netlist_dir ne {} } {
|
|
set initdir $netlist_dir
|
|
} else {
|
|
if {$OS == "Windows"} {
|
|
set initdir $env(windir)
|
|
} else {
|
|
set initdir [pwd]
|
|
}
|
|
}
|
|
# 20140409 do not change netlist_dir if user Cancels action
|
|
set new_dir [tk_chooseDirectory -initialdir $initdir \
|
|
-parent [xschem get topwindow] -title {Select netlist DIR} -mustexist false]
|
|
} else {
|
|
set new_dir $dir
|
|
}
|
|
|
|
if {$new_dir ne {} } {
|
|
if {![file exist $new_dir]} {
|
|
file mkdir $new_dir
|
|
}
|
|
set netlist_dir $new_dir
|
|
}
|
|
regsub {^~/} $netlist_dir ${env(HOME)}/ netlist_dir
|
|
return $netlist_dir
|
|
}
|
|
|
|
|
|
proc enter_text {textlabel {preserve_disabled disabled}} {
|
|
global retval rcode has_cairo preserve_unchanged_attrs wm_fix
|
|
set rcode {}
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Enter text}
|
|
|
|
set X [expr {[winfo pointerx .dialog] - 30}]
|
|
set Y [expr {[winfo pointery .dialog] - 25}]
|
|
|
|
# 20100203
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
wm geometry .dialog "+$X+$Y"
|
|
frame .dialog.f1
|
|
label .dialog.f1.txtlab -text $textlabel
|
|
text .dialog.txt -width 100 -height 4
|
|
.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.lab
|
|
frame .dialog.edit.entries
|
|
pack .dialog.edit.lab -side left
|
|
pack .dialog.edit.entries -side left -fill x -expand yes
|
|
pack .dialog.edit -side top -fill x
|
|
if {$has_cairo } {
|
|
entry .dialog.edit.entries.hsize -relief sunken -textvariable vsize -width 20
|
|
} else {
|
|
entry .dialog.edit.entries.hsize -relief sunken -textvariable hsize -width 20
|
|
}
|
|
entry .dialog.edit.entries.vsize -relief sunken -textvariable vsize -width 20
|
|
entry .dialog.edit.entries.props -relief sunken -textvariable props -width 20
|
|
pack .dialog.edit.entries.hsize .dialog.edit.entries.vsize \
|
|
.dialog.edit.entries.props -side top -fill x -expand yes
|
|
label .dialog.edit.lab.hlab -text "hsize:"
|
|
label .dialog.edit.lab.vlab -text "vsize:"
|
|
label .dialog.edit.lab.proplab -text "props:"
|
|
pack .dialog.edit.lab.hlab .dialog.edit.lab.vlab \
|
|
.dialog.edit.lab.proplab -side top
|
|
frame .dialog.buttons
|
|
button .dialog.buttons.ok -text "OK" -command \
|
|
{
|
|
set retval [.dialog.txt get 1.0 {end - 1 chars}]
|
|
if {$has_cairo} {
|
|
set hsize $vsize
|
|
}
|
|
set rcode {ok}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.buttons.cancel -text "Cancel" -command \
|
|
{
|
|
set retval {}
|
|
set 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 <Escape> {
|
|
if ![string compare $retval [.dialog.txt get 1.0 {end - 1 chars}]] {
|
|
.dialog.buttons.cancel invoke
|
|
}
|
|
}
|
|
bind .dialog <Control-Return> {.dialog.buttons.ok invoke}
|
|
#grab set .dialog
|
|
tkwait window .dialog
|
|
return $retval
|
|
}
|
|
|
|
# evaluate a tcl command from GUI
|
|
proc tclcmd {} {
|
|
global tclcmd_txt
|
|
if {[winfo exists .tclcmd]} {
|
|
destroy .tclcmd
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .tclcmd -class dialog
|
|
label .tclcmd.txtlab -text {Enter TCL expression:}
|
|
label .tclcmd.result -text {Result:}
|
|
text .tclcmd.t -width 100 -height 8
|
|
text .tclcmd.r -width 100 -height 6 -yscrollcommand ".tclcmd.yscroll set"
|
|
scrollbar .tclcmd.yscroll -command ".tclcmd.r yview"
|
|
.tclcmd.t insert 1.0 $tclcmd_txt
|
|
|
|
frame .tclcmd.b
|
|
button .tclcmd.b.close -text Close -command {
|
|
set tclcmd_txt [.tclcmd.t get 1.0 end]
|
|
destroy .tclcmd
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
button .tclcmd.b.ok -text Evaluate -command {
|
|
set tclcmd_txt [.tclcmd.t get 1.0 end]
|
|
set res [eval $tclcmd_txt]
|
|
.tclcmd.r delete 1.0 end
|
|
.tclcmd.r insert 1.0 $res
|
|
}
|
|
pack .tclcmd.txtlab -side top -fill x
|
|
pack .tclcmd.t -side top -fill both -expand yes
|
|
pack .tclcmd.result -side top -fill x
|
|
pack .tclcmd.b -side bottom -fill x
|
|
pack .tclcmd.yscroll -side right -fill y
|
|
pack .tclcmd.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
|
|
}
|
|
|
|
proc select_layers {} {
|
|
global dark_colorscheme colors enable_layer
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .sl -class dialog
|
|
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 $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
|
|
}
|
|
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}
|
|
checkbutton .dim.bg -text {Dim background} -variable enable_dim_bg
|
|
# xschem color_dim <scale value> 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}]
|
|
}
|
|
|
|
proc about {} {
|
|
if [winfo exists .about] {
|
|
bind .about.link <Button-1> {}
|
|
bind .about.link2 <Button-1> {}
|
|
destroy .about
|
|
}
|
|
toplevel .about -class dialog
|
|
wm title .about {About XSCHEM}
|
|
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
|
|
label .about.copyright -text "\n Copyright 1998-2022 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.descr
|
|
pack .about.copyright
|
|
pack .about.close
|
|
bind .about.link <Button-1> { execute 0 xdg-open http://repo.hu/projects/xschem}
|
|
bind .about.link2 <Button-1> { execute 0 xdg-open https://github.com/StefanSchippers/xschem}
|
|
bind .about.link3 <Button-1> { execute 0 xdg-open http://repo.hu/projects/xschem/index.html}
|
|
}
|
|
|
|
proc property_search {} {
|
|
global search_value search_found
|
|
global search_exact
|
|
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}
|
|
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
|
|
.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
|
|
.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]
|
|
} else {
|
|
set search_found [xschem searchmenu regex $search_select $custom_token $search_value]
|
|
}
|
|
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
|
|
if {$OS == "Windows"} {
|
|
set search_exact 1
|
|
checkbutton .dialog.but.sub -text Exact_search -variable search_exact -state disable
|
|
} else {
|
|
checkbutton .dialog.but.sub -text Exact_search -variable search_exact
|
|
}
|
|
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.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 <Escape> {.dialog.but.cancel invoke}
|
|
bind .dialog <Return> {.dialog.but.ok invoke}
|
|
bind .dialog <Control-Return> {.dialog.but.ok 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(<script>) m=@m"
|
|
# NOTE: spaces and quotes in <script> must be escaped
|
|
# symname and instname are predefined variables in the <script> context
|
|
# they can be used together with TCL xschem command to query instance or symbol
|
|
# attributes.
|
|
#
|
|
proc tclpropeval {s instname symname} {
|
|
# puts "tclpropeval: $s $instname $symname"
|
|
global env debug_var
|
|
if {$debug_var <=-1} {puts "tclpropeval: $s"}
|
|
regsub {^@tcleval\(} $s {} s
|
|
regsub {\)([ \t\n]*)$} $s {\1} s
|
|
if { [catch {eval $s} res] } {
|
|
if { $debug_var<=-1 } { puts "tclpropeval warning: $res"}
|
|
set res ?\n
|
|
}
|
|
return $res
|
|
}
|
|
|
|
# this hook is called in translate() if whole string is contained in a tcleval(...) construct
|
|
proc tclpropeval2 {s} {
|
|
global debug_var env path graph_raw_level
|
|
|
|
set netlist_type [xschem get netlist_type]
|
|
# puts "tclpropeval2: s=|$s|"
|
|
if {$debug_var <=-1} {puts "tclpropeval2: $s"}
|
|
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.
|
|
set skip 0
|
|
while { $skip < $graph_raw_level } {
|
|
regsub {^[^.]*\.} $path {} path
|
|
incr skip
|
|
}
|
|
|
|
if { $netlist_type eq {spice} } {
|
|
# this is necessary if spiceprefix is being used in netlists
|
|
regsub {^([^xX])} $path {x\1} path
|
|
while { [regsub {\.([^xX])} $path {.x\1} path] } {}
|
|
}
|
|
|
|
## no more necessary, ':' are converted to '.' when reading raw file */
|
|
# if { [sim_is_xyce]} {
|
|
# regsub -all {\.} [string toupper $path] {:} path
|
|
# }
|
|
|
|
if { $debug_var<=-1 } { puts "---> path=$path" }
|
|
regsub {^tcleval\(} $s {} s
|
|
regsub {\)([ \n\t]*)$} $s {\1} s
|
|
# puts "tclpropeval2: s=|$s|"
|
|
# puts "tclpropeval2: subst $s=|[subst $s]|"
|
|
if { [catch {uplevel #0 "subst \{$s\}"} res] } {
|
|
if { $debug_var<=-1 } { puts "tclpropeval2 warning: $res"}
|
|
set res ?\n
|
|
}
|
|
# puts "tclpropeval2: res=|$res|"
|
|
return $res
|
|
}
|
|
|
|
proc attach_labels_to_inst {} {
|
|
global use_lab_wire use_label_prefix custom_label_prefix rcode do_all_inst rotated_text
|
|
|
|
set rcode {}
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Add labels to instances}
|
|
|
|
# 20100408
|
|
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 "Prefix"
|
|
entry .dialog.custom.e -width 32
|
|
.dialog.custom.e insert 0 $custom_label_prefix
|
|
pack .dialog.custom.e .dialog.custom.l -side right
|
|
|
|
|
|
frame .dialog.but
|
|
button .dialog.but.ok -text OK -command {
|
|
set custom_label_prefix [.dialog.custom.e get]
|
|
#### put command here
|
|
set rcode yes
|
|
destroy .dialog
|
|
}
|
|
button .dialog.but.cancel -text Cancel -command { set rcode {}; destroy .dialog }
|
|
checkbutton .dialog.but.wire -text {use wire labels} -variable use_lab_wire
|
|
checkbutton .dialog.but.do_all -text {Do all} -variable do_all_inst
|
|
label .dialog.but.rot -text {Rotated Text}
|
|
entry .dialog.but.rotated -textvariable rotated_text -width 2
|
|
checkbutton .dialog.but.prefix -text {use prefix} -variable use_label_prefix
|
|
pack .dialog.but.ok -anchor w -side left
|
|
pack .dialog.but.prefix -side left
|
|
pack .dialog.but.wire -side left
|
|
pack .dialog.but.do_all -side left
|
|
pack .dialog.but.rotated -side left
|
|
pack .dialog.but.rot -side left
|
|
pack .dialog.but.cancel -anchor e
|
|
|
|
pack .dialog.custom -anchor e
|
|
pack .dialog.but -expand yes -fill x
|
|
|
|
focus .dialog
|
|
bind .dialog <Escape> {.dialog.but.cancel invoke}
|
|
bind .dialog <Return> {.dialog.but.ok invoke}
|
|
bind .dialog <Control-Return> {.dialog.but.ok invoke}
|
|
grab set .dialog
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return {}
|
|
}
|
|
|
|
proc ask_save { {ask {save file?}} {cancel 1}} {
|
|
global rcode wm_fix
|
|
set rcode {}
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Ask Save}
|
|
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
|
|
wm geometry .dialog "+$X+$Y"
|
|
label .dialog.l1 -text $ask
|
|
frame .dialog.f1
|
|
button .dialog.f1.b1 -text {Yes} -command\
|
|
{
|
|
set rcode {yes}
|
|
destroy .dialog
|
|
}
|
|
if {$cancel} {
|
|
button .dialog.f1.b2 -text {Cancel} -command\
|
|
{
|
|
set rcode {}
|
|
destroy .dialog
|
|
}
|
|
}
|
|
button .dialog.f1.b3 -text {No} -command\
|
|
{
|
|
set rcode {no}
|
|
destroy .dialog
|
|
}
|
|
pack .dialog.l1 .dialog.f1 -side top -fill x
|
|
pack .dialog.f1.b1 -side left -fill x -expand yes
|
|
if { $cancel} {
|
|
pack .dialog.f1.b2 -side left -fill x -expand yes
|
|
}
|
|
pack .dialog.f1.b3 -side left -fill x -expand yes
|
|
if {$cancel} {
|
|
bind .dialog <Escape> {.dialog.f1.b2 invoke}
|
|
}
|
|
# needed, otherwise problems when descending with double clixk 23012004
|
|
tkwait visibility .dialog
|
|
grab set .dialog
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $rcode
|
|
}
|
|
|
|
|
|
proc edit_vi_prop {txtlabel} {
|
|
global XSCHEM_TMP_DIR retval symbol prev_symbol rcode debug_var editor
|
|
global user_wants_copy_cell
|
|
|
|
set netlist_type [xschem get netlist_type]
|
|
set user_wants_copy_cell 0
|
|
set rcode {}
|
|
set filename .xschem_edit_file.[pid]
|
|
if ![string compare $netlist_type "vhdl"] { set suffix vhd } else { set suffix v }
|
|
set filename $filename.$suffix
|
|
write_data $retval $XSCHEM_TMP_DIR/$filename
|
|
# since $editor can be an executable with options (gvim -f) I *need* to use eval
|
|
eval execute_wait 0 $editor $XSCHEM_TMP_DIR/$filename ;# 20161119
|
|
if {$debug_var<=-1} {puts "edit_vi_prop{}:\n--------\nretval=$retval\n---------\n"}
|
|
if {$debug_var<=-1} {puts "edit_vi_prop{}:\n--------\nsymbol=$symbol\n---------\n"}
|
|
set tmp [read_data $XSCHEM_TMP_DIR/$filename]
|
|
file delete $XSCHEM_TMP_DIR/$filename
|
|
if {$debug_var<=-1} {puts "edit_vi_prop{}:\n--------\n$tmp\n---------\n"}
|
|
if [string compare $tmp $retval] {
|
|
set retval $tmp
|
|
if {$debug_var<=-1} {puts "modified"}
|
|
set rcode ok
|
|
return $rcode
|
|
} else {
|
|
set rcode {}
|
|
return $rcode
|
|
}
|
|
}
|
|
|
|
proc edit_vi_netlist_prop {txtlabel} {
|
|
global XSCHEM_TMP_DIR retval rcode debug_var editor
|
|
global user_wants_copy_cell
|
|
|
|
set netlist_type [xschem get netlist_type]
|
|
set user_wants_copy_cell 0
|
|
set filename .xschem_edit_file.[pid]
|
|
if ![string compare $netlist_type "vhdl"] { set suffix vhd } else { set suffix v }
|
|
set filename $filename.$suffix
|
|
regsub -all {\\?"} $retval {"} retval
|
|
regsub -all {\\?\\} $retval {\\} retval
|
|
write_data $retval $XSCHEM_TMP_DIR/$filename
|
|
if { [regexp vim $editor] } { set ftype "\{-c :set filetype=$netlist_type\}" } else { set ftype {} }
|
|
# since $editor can be an executable with options (gvim -f) I *need* to use eval
|
|
eval execute_wait 0 $editor $ftype $XSCHEM_TMP_DIR/$filename
|
|
if {$debug_var <= -1} {puts "edit_vi_prop{}:\n--------\n$retval\n---------\n"}
|
|
set tmp [read_data $XSCHEM_TMP_DIR/$filename]
|
|
file delete $XSCHEM_TMP_DIR/$filename
|
|
if {$debug_var <= -1} {puts "edit_vi_prop{}:\n--------\n$tmp\n---------\n"}
|
|
if [string compare $tmp $retval] {
|
|
set retval $tmp
|
|
regsub -all {(["\\])} $retval {\\\1} retval ;#" editor is confused by the previous quote
|
|
set retval \"${retval}\"
|
|
if {$debug_var <= -1} {puts "modified"}
|
|
set rcode ok
|
|
return $rcode
|
|
} else {
|
|
set rcode {}
|
|
return $rcode
|
|
}
|
|
}
|
|
proc reset_colors {ask} {
|
|
global colors dark_colors light_colors dark_colorscheme USER_CONF_DIR svg_colors ps_colors
|
|
global light_colors_save dark_colors_save
|
|
|
|
if {$ask} {
|
|
set answer [tk_messageBox -message "Warning: delete 'colors' configuration file?" \
|
|
-icon warning -parent [xschem get topwindow] -type okcancel]
|
|
if {$answer ne {ok}} { return }
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
set light_colors $light_colors_save
|
|
set dark_colors $dark_colors_save
|
|
if { $dark_colorscheme == 1 } {
|
|
set colors $dark_colors
|
|
} else {
|
|
set colors $light_colors
|
|
}
|
|
regsub -all {"} $light_colors {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
regsub -all {"} $colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
file delete ${USER_CONF_DIR}/colors
|
|
xschem build_colors
|
|
xschem redraw
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
|
|
proc change_color {} {
|
|
global colors dark_colors light_colors dark_colorscheme cadlayers USER_CONF_DIR svg_colors ps_colors
|
|
|
|
set n [xschem get rectcolor]
|
|
if { $n < 0 || $n >=$cadlayers} return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
if { $dark_colorscheme == 1 } {
|
|
set c $dark_colors
|
|
} else {
|
|
set c $light_colors
|
|
}
|
|
set initial_color [lindex $c $n]
|
|
set value [tk_chooseColor -initialcolor $initial_color]
|
|
if {[string compare $value {}] } {
|
|
set cc [lreplace $c $n $n $value]
|
|
set colors $cc
|
|
if { $dark_colorscheme == 1 } {
|
|
set dark_colors $cc
|
|
} else {
|
|
set light_colors $cc
|
|
regsub -all {"} $cc {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
}
|
|
regsub -all {"} $colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
|
|
xschem build_colors
|
|
xschem redraw
|
|
set savedata "#### THIS FILE IS AUTOMATICALLY GENERATED BY XSCHEM, DO NOT EDIT.\n"
|
|
append savedata "set cadlayers $cadlayers\n"
|
|
append savedata "set light_colors {$light_colors}\n"
|
|
append savedata "set dark_colors {$dark_colors}\n"
|
|
write_data $savedata ${USER_CONF_DIR}/colors
|
|
}
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
}
|
|
|
|
proc edit_prop {txtlabel} {
|
|
global edit_prop_size infowindow_text selected_tok edit_symbol_prop_new_sel edit_prop_pos
|
|
global prev_symbol retval symbol rcode no_change_attrs preserve_unchanged_attrs copy_cell debug_var
|
|
global user_wants_copy_cell editprop_sympath retval_orig old_selected_tok
|
|
set user_wants_copy_cell 0
|
|
set rcode {}
|
|
set retval_orig $retval
|
|
if {$debug_var <= -1} {puts " edit_prop{}: retval=$retval"}
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Edit Properties}
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
|
|
# 20160325 change and remember widget size
|
|
bind .dialog <Configure> {
|
|
# puts [wm geometry .dialog]
|
|
if { $edit_symbol_prop_new_sel != 1 } {
|
|
set edit_prop_size [wm geometry .dialog]
|
|
set edit_prop_pos $edit_prop_size
|
|
regsub {\+.*} $edit_prop_size {} edit_prop_size
|
|
regsub {[^+]*\+} $edit_prop_pos {+} edit_prop_pos
|
|
}
|
|
}
|
|
wm geometry .dialog "${edit_prop_size}+$X+$Y"
|
|
set prev_symbol $symbol
|
|
set editprop_sympath [file dirname [abs_sym_path $symbol]]
|
|
frame .dialog.f4
|
|
label .dialog.f4.l1 -text $txtlabel
|
|
label .dialog.f4.path -text "Path:"
|
|
entry .dialog.f4.e1 -textvariable editprop_sympath -width 0 -state readonly
|
|
text .dialog.e1 -yscrollcommand ".dialog.yscroll set" -setgrid 1 \
|
|
-xscrollcommand ".dialog.xscroll set" -wrap none
|
|
.dialog.e1 delete 1.0 end
|
|
.dialog.e1 insert 1.0 $retval
|
|
scrollbar .dialog.yscroll -command ".dialog.e1 yview"
|
|
scrollbar .dialog.xscroll -command ".dialog.e1 xview" -orient horiz
|
|
frame .dialog.f1
|
|
frame .dialog.f2
|
|
label .dialog.f1.l2 -text "Symbol"
|
|
entry .dialog.f1.e2 -width 30
|
|
.dialog.f1.e2 insert 0 $symbol
|
|
button .dialog.f1.b5 -text "Browse" -command {
|
|
set r [tk_getOpenFile -parent .dialog -initialdir $INITIALINSTDIR ]
|
|
if {$r ne {} } {
|
|
.dialog.f1.e2 delete 0 end
|
|
.dialog.f1.e2 insert 0 $r
|
|
}
|
|
raise .dialog .drw
|
|
}
|
|
button .dialog.f1.b1 -text "OK" -command {
|
|
set retval [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
if { $selected_tok ne {<ALL>} } {
|
|
regsub -all {(["\\])} $retval {\\\1} retval ;#" editor is confused by the previous quote
|
|
set retval \"${retval}\"
|
|
set retval [xschem subst_tok $retval_orig $selected_tok $retval]
|
|
set selected_tok {<ALL>}
|
|
}
|
|
set symbol [.dialog.f1.e2 get]
|
|
set abssymbol [abs_sym_path $symbol]
|
|
set rcode {ok}
|
|
set user_wants_copy_cell $copy_cell
|
|
set prev_symbol [abs_sym_path $prev_symbol]
|
|
if { ($abssymbol ne $prev_symbol) && $copy_cell } {
|
|
if { ![regexp {^/} $symbol] && ![regexp {^[a-zA-Z]:} $symbol] } {
|
|
set symlist [file split $symbol]
|
|
set symlen [llength $symlist]
|
|
set abssymbol "[path_head $prev_symbol $symlen]/$symbol"
|
|
}
|
|
# puts "$abssymbol $prev_symbol"
|
|
if { [file exists "[file rootname $prev_symbol].sch"] } {
|
|
if { ! [file exists "[file rootname ${abssymbol}].sch"] } {
|
|
file copy "[file rootname $prev_symbol].sch" "[file rootname $abssymbol].sch"
|
|
# puts "file copy [file rootname $prev_symbol].sch [file rootname $abssymbol].sch"
|
|
}
|
|
}
|
|
if { [file exists "$prev_symbol"] } {
|
|
if { ! [file exists "$abssymbol"] } {
|
|
file copy "$prev_symbol" "$abssymbol"
|
|
# puts "file copy [file rootname $prev_symbol].sym [file rootname $abssymbol].sym"
|
|
}
|
|
}
|
|
}
|
|
#puts "symbol: $symbol , prev_symbol: $prev_symbol"
|
|
set copy_cell 0 ;# 20120919
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f1.b2 -text "Cancel" -command {
|
|
set rcode {}
|
|
set edit_symbol_prop_new_sel {}
|
|
destroy .dialog
|
|
}
|
|
wm protocol .dialog WM_DELETE_WINDOW {
|
|
set rcode {}
|
|
set edit_symbol_prop_new_sel {}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f1.b3 -text "Load" -command {
|
|
global INITIALPROPDIR
|
|
set a [tk_getOpenFile -parent .dialog -initialdir $INITIALPROPDIR ]
|
|
if [string compare $a ""] {
|
|
set INITIALPROPDIR [file dirname $a]
|
|
read_data_window .dialog.e1 $a
|
|
}
|
|
}
|
|
button .dialog.f1.b4 -text "Del" -command {
|
|
.dialog.e1 delete 1.0 end
|
|
}
|
|
checkbutton .dialog.f2.r1 -text "No change properties" -variable no_change_attrs -state normal
|
|
checkbutton .dialog.f2.r2 -text "Preserve unchanged props" -variable preserve_unchanged_attrs -state normal
|
|
checkbutton .dialog.f2.r3 -text "Copy cell" -variable copy_cell -state normal
|
|
set tok_list "<ALL> [list_tokens $retval]"
|
|
set selected_tok {<ALL>}
|
|
set old_selected_tok {<ALL>}
|
|
label .dialog.f2.r4 -text { Edit Attr:}
|
|
if { [ info tclversion] > 8.4} {
|
|
ttk::combobox .dialog.f2.r5 -values $tok_list -textvariable selected_tok -width 14
|
|
}
|
|
pack .dialog.f1.l2 .dialog.f1.e2 .dialog.f1.b1 .dialog.f1.b2 .dialog.f1.b3 \
|
|
.dialog.f1.b4 .dialog.f1.b5 -side left -expand 1
|
|
pack .dialog.f4 -side top -anchor nw
|
|
#pack .dialog.f4.path .dialog.f4.e1 .dialog.f4.l1 -side left -fill x
|
|
pack .dialog.f4.path -side left
|
|
pack .dialog.f4.e1 -side left
|
|
pack .dialog.f1 .dialog.f2 -side top -fill x
|
|
pack .dialog.f2.r1 -side left
|
|
pack .dialog.f2.r2 -side left
|
|
pack .dialog.f2.r3 -side left
|
|
pack .dialog.f2.r4 -side left
|
|
if { [ info tclversion] > 8.4 } { pack .dialog.f2.r5 -side left }
|
|
pack .dialog.yscroll -side right -fill y
|
|
pack .dialog.xscroll -side bottom -fill x
|
|
pack .dialog.e1 -fill both -expand yes
|
|
bind .dialog <Control-Return> {.dialog.f1.b1 invoke}
|
|
bind .dialog <Escape> {
|
|
if { ![string compare $retval [.dialog.e1 get 1.0 {end - 1 chars}]] && \
|
|
![string compare $symbol [ .dialog.f1.e2 get]] } {
|
|
.dialog.f1.b2 invoke
|
|
}
|
|
}
|
|
if { [ info tclversion] > 8.4} {
|
|
bind .dialog.f2.r5 <<ComboboxSelected>> {
|
|
if {$old_selected_tok ne $selected_tok} {
|
|
if { $old_selected_tok eq {<ALL>} } {
|
|
set retval_orig [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set retval [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
regsub -all {(["\\])} $retval {\\\1} retval ;#" editor is confused by the previous quote
|
|
set retval \"${retval}\"
|
|
set retval_orig [xschem subst_tok $retval_orig $old_selected_tok $retval]
|
|
}
|
|
}
|
|
if {$selected_tok eq {<ALL>} } {
|
|
set retval $retval_orig
|
|
} else {
|
|
set retval [xschem get_tok $retval_orig $selected_tok 2]
|
|
# regsub -all {\\?"} $retval {"} retval
|
|
}
|
|
.dialog.e1 delete 1.0 end
|
|
.dialog.e1 insert 1.0 $retval
|
|
set old_selected_tok $selected_tok
|
|
}
|
|
|
|
bind .dialog.f2.r5 <KeyRelease> {
|
|
set selected_tok [.dialog.f2.r5 get]
|
|
if { $old_selected_tok eq {<ALL>}} {
|
|
set retval_orig [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set retval [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
if {$retval ne {}} {
|
|
regsub -all {(["\\])} $retval {\\\1} retval ;#" editor is confused by the previous quote
|
|
set retval \"${retval}\"
|
|
set retval_orig [xschem subst_tok $retval_orig $old_selected_tok $retval]
|
|
}
|
|
}
|
|
if {$selected_tok eq {<ALL>} } {
|
|
set retval $retval_orig
|
|
} else {
|
|
set retval [xschem get_tok $retval_orig $selected_tok 2]
|
|
# regsub -all {\\?"} $retval {"} retval
|
|
}
|
|
.dialog.e1 delete 1.0 end
|
|
.dialog.e1 insert 1.0 $retval
|
|
set old_selected_tok $selected_tok
|
|
}
|
|
}
|
|
if {$edit_symbol_prop_new_sel == 1} {
|
|
wm geometry .dialog $edit_prop_pos
|
|
}
|
|
set edit_symbol_prop_new_sel 0
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $rcode
|
|
}
|
|
|
|
proc read_data_nonewline {f} {
|
|
set fid [open $f "r"]
|
|
set data [read -nonewline $fid]
|
|
close $fid
|
|
return $data
|
|
}
|
|
|
|
proc read_data {f} {
|
|
set fid [open $f "r"]
|
|
set data [read $fid]
|
|
close $fid
|
|
return $data
|
|
}
|
|
|
|
proc read_data_window {w f} {
|
|
set fid [open $f "r"]
|
|
set t [read $fid]
|
|
# $w delete 0.0 end
|
|
## 20171103 insert text at cursor position instead of at beginning (insert index tag)
|
|
$w insert insert $t
|
|
close $fid
|
|
}
|
|
|
|
proc write_data {data f} {
|
|
set fid [open $f "w"]
|
|
puts -nonewline $fid $data
|
|
close $fid
|
|
return {}
|
|
}
|
|
|
|
proc text_line {txtlabel clear {preserve_disabled disabled} } {
|
|
global text_line_default_geometry preserve_unchanged_attrs wm_fix
|
|
global retval rcode debug_var selected_tok retval_orig old_selected_tok
|
|
set retval_orig $retval
|
|
if $clear==1 then {set retval ""}
|
|
if {$debug_var <= -1} {puts " text_line{}: clear=$clear"}
|
|
if {$debug_var <= -1} {puts " text_line{}: retval=$retval"}
|
|
set rcode {}
|
|
if { [winfo exists .dialog] } return
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Text input}
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
|
|
set tok_list "<ALL> [list_tokens $retval]"
|
|
set selected_tok {<ALL>}
|
|
set old_selected_tok {<ALL>}
|
|
bind .dialog <Configure> {
|
|
# puts [wm geometry .dialog]
|
|
set text_line_default_geometry [wm geometry .dialog]
|
|
regsub {\+.*} $text_line_default_geometry {} text_line_default_geometry
|
|
}
|
|
|
|
# 20100203
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
wm geometry .dialog "${text_line_default_geometry}+$X+$Y"
|
|
|
|
frame .dialog.f0
|
|
frame .dialog.f1
|
|
label .dialog.f0.l1 -text $txtlabel
|
|
text .dialog.e1 -relief sunken -bd 2 -yscrollcommand ".dialog.yscroll set" -setgrid 1 \
|
|
-xscrollcommand ".dialog.xscroll set" -wrap none -width 90 -height 40
|
|
scrollbar .dialog.yscroll -command ".dialog.e1 yview"
|
|
scrollbar .dialog.xscroll -command ".dialog.e1 xview" -orient horiz
|
|
.dialog.e1 delete 1.0 end
|
|
.dialog.e1 insert 1.0 $retval
|
|
button .dialog.f1.b1 -text "OK" -command \
|
|
{
|
|
set retval [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
if { $selected_tok ne {<ALL>} } {
|
|
regsub -all {(["\\])} $retval {\\\1} retval ;#" editor is confused by the previous quote
|
|
set retval \"${retval}\"
|
|
set retval [xschem subst_tok $retval_orig $selected_tok $retval]
|
|
set selected_tok {<ALL>}
|
|
}
|
|
destroy .dialog
|
|
set rcode {ok}
|
|
}
|
|
button .dialog.f1.b2 -text "Cancel" -command \
|
|
{
|
|
set retval [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
set rcode {}
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f1.b3 -text "Load" -command \
|
|
{
|
|
global INITIALPROPDIR
|
|
set a [tk_getOpenFile -parent .dialog -initialdir $INITIALPROPDIR ]
|
|
if [string compare $a ""] {
|
|
set INITIALPROPDIR [file dirname $a]
|
|
read_data_window .dialog.e1 $a
|
|
}
|
|
}
|
|
button .dialog.f1.b4 -text "Del" -command \
|
|
{
|
|
.dialog.e1 delete 1.0 end
|
|
}
|
|
label .dialog.f1.r4 -text { Edit Attr:}
|
|
if { [ info tclversion] > 8.4} {
|
|
ttk::combobox .dialog.f1.r5 -values $tok_list -textvariable selected_tok -width 14
|
|
}
|
|
checkbutton .dialog.f0.l2 -text "preserve unchanged props" -variable preserve_unchanged_attrs \
|
|
-state $preserve_disabled
|
|
pack .dialog.f0 -fill x
|
|
pack .dialog.f0.l2 -side left
|
|
pack .dialog.f0.l1 -side left -expand yes
|
|
pack .dialog.f1 -fill x
|
|
pack .dialog.f1.b1 -side left -fill x -expand yes
|
|
pack .dialog.f1.b2 -side left -fill x -expand yes
|
|
pack .dialog.f1.b3 -side left -fill x -expand yes
|
|
pack .dialog.f1.b4 -side left -fill x -expand yes
|
|
pack .dialog.f1.r4 -side left
|
|
if { [ info tclversion] > 8.4} {pack .dialog.f1.r5 -side left}
|
|
|
|
|
|
pack .dialog.yscroll -side right -fill y
|
|
pack .dialog.xscroll -side bottom -fill x
|
|
pack .dialog.e1 -expand yes -fill both
|
|
bind .dialog <Escape> {
|
|
if ![string compare $retval [.dialog.e1 get 1.0 {end - 1 chars}]] {
|
|
.dialog.f1.b2 invoke
|
|
}
|
|
}
|
|
|
|
if { [ info tclversion] > 8.4} {
|
|
bind .dialog.f1.r5 <<ComboboxSelected>> {
|
|
if {$old_selected_tok ne $selected_tok} {
|
|
if { $old_selected_tok eq {<ALL>} } {
|
|
set retval_orig [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set retval [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
regsub -all {(["\\])} $retval {\\\1} retval ;#" editor is confused by the previous quote
|
|
set retval \"${retval}\"
|
|
set retval_orig [xschem subst_tok $retval_orig $old_selected_tok $retval]
|
|
}
|
|
}
|
|
if {$selected_tok eq {<ALL>} } {
|
|
set retval $retval_orig
|
|
} else {
|
|
set retval [xschem get_tok $retval_orig $selected_tok 2]
|
|
# regsub -all {\\?"} $retval {"} retval
|
|
}
|
|
.dialog.e1 delete 1.0 end
|
|
.dialog.e1 insert 1.0 $retval
|
|
set old_selected_tok $selected_tok
|
|
}
|
|
|
|
bind .dialog.f1.r5 <KeyRelease> {
|
|
set selected_tok [.dialog.f1.r5 get]
|
|
if { $old_selected_tok eq {<ALL>}} {
|
|
set retval_orig [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
} else {
|
|
set retval [.dialog.e1 get 1.0 {end - 1 chars}]
|
|
if {$retval ne {}} {
|
|
regsub -all {(["\\])} $retval {\\\1} retval ;#" editor is confused by the previous quote
|
|
set retval \"${retval}\"
|
|
set retval_orig [xschem subst_tok $retval_orig $old_selected_tok $retval]
|
|
}
|
|
}
|
|
if {$selected_tok eq {<ALL>} } {
|
|
set retval $retval_orig
|
|
} else {
|
|
set retval [xschem get_tok $retval_orig $selected_tok 2]
|
|
# regsub -all {\\?"} $retval {"} retval
|
|
}
|
|
.dialog.e1 delete 1.0 end
|
|
.dialog.e1 insert 1.0 $retval
|
|
set old_selected_tok $selected_tok
|
|
}
|
|
}
|
|
bind .dialog <Control-Return> {.dialog.f1.b1 invoke}
|
|
#tkwait visibility .dialog
|
|
#grab set .dialog
|
|
#focus .dialog.e1
|
|
set rcode {}
|
|
tkwait window .dialog
|
|
return $rcode
|
|
}
|
|
|
|
proc alert_ {txtlabel {position +200+300} {nowait {0}}} {
|
|
global has_x
|
|
if {![info exists has_x] } {return}
|
|
toplevel .alert -class Dialog
|
|
wm title .alert {Alert}
|
|
set X [expr {[winfo pointerx .alert] - 60}]
|
|
set Y [expr {[winfo pointery .alert] - 60}]
|
|
if { [string compare $position ""] != 0 } {
|
|
wm geometry .alert $position
|
|
} else {
|
|
wm geometry .alert "+$X+$Y"
|
|
}
|
|
label .alert.l1 -text $txtlabel -wraplength 700
|
|
button .alert.b1 -text "OK" -command \
|
|
{
|
|
destroy .alert
|
|
}
|
|
pack .alert.l1 -side top -fill x
|
|
pack .alert.b1 -side top -fill x
|
|
tkwait visibility .alert
|
|
grab set .alert
|
|
focus .alert.b1
|
|
bind .alert <Return> { destroy .alert }
|
|
bind .alert <Escape> { destroy .alert }
|
|
bind .alert <Visibility> {
|
|
if { [winfo exists .alert] && [winfo ismapped .alert] && [winfo ismapped .] && [wm stackorder .alert isbelow . ]} {
|
|
if { [winfo exists .drw] } {
|
|
raise .alert .drw
|
|
} else {
|
|
raise .alert
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if {!$nowait} {tkwait window .alert}
|
|
return {}
|
|
}
|
|
|
|
proc show_infotext {} {
|
|
global has_x infowindow_text
|
|
if {[info exists has_x]} {
|
|
wm deiconify .infotext
|
|
} else {
|
|
puts stderr $infowindow_text
|
|
}
|
|
}
|
|
|
|
proc infowindow {} {
|
|
global infowindow_text
|
|
|
|
set infotxt $infowindow_text
|
|
if { $infowindow_text ne {}} {append infotxt \n}
|
|
set z {.infotext}
|
|
if ![string compare $infotxt ""] {
|
|
if [winfo exists $z] {
|
|
$z.f1.text delete 1.0 end
|
|
}
|
|
}
|
|
if ![winfo exists $z] {
|
|
toplevel $z
|
|
wm title $z {Info window}
|
|
wm geometry $z 90x24+0+400
|
|
wm iconname $z {Info window}
|
|
wm withdraw $z
|
|
wm protocol .infotext WM_DELETE_WINDOW "wm withdraw $z; set show_infowindow 0"
|
|
# button $z.dismiss -text Dismiss -command "destroy $z"
|
|
frame $z.f1
|
|
frame $z.f2
|
|
text $z.f1.text -relief sunken -bd 2 -yscrollcommand "$z.f1.yscroll set" -setgrid 1 \
|
|
-height 6 -width 50 -xscrollcommand "$z.f1.xscroll set" -wrap none
|
|
scrollbar $z.f1.yscroll -command "$z.f1.text yview" -orient v
|
|
scrollbar $z.f1.xscroll -command "$z.f1.text xview" -orient h
|
|
grid $z.f1.text - $z.f1.yscroll -sticky nsew
|
|
grid $z.f1.xscroll - -sticky ew
|
|
# grid $z.dismiss - -
|
|
grid rowconfig $z.f1 0 -weight 1
|
|
grid columnconfig $z.f1 0 -weight 1
|
|
pack $z.f1 -fill both -expand yes
|
|
button $z.f2.dismiss -text Dismiss -command "wm withdraw $z; set show_infowindow 0"
|
|
pack $z.f2.dismiss
|
|
pack $z.f2 -fill x
|
|
bind $z <Escape> "wm withdraw $z; set show_infowindow 0"
|
|
}
|
|
$z.f1.text insert end $infotxt
|
|
$z.f1.text see end
|
|
return {}
|
|
}
|
|
|
|
proc textwindow {filename {ro {}}} {
|
|
global textwindow_wcounter
|
|
global textwindow_w
|
|
# set textwindow_w .win$textwindow_wcounter
|
|
# catch {destroy $textwindow_w}
|
|
set textwindow_wcounter [expr {$textwindow_wcounter+1}]
|
|
set textwindow_w .win$textwindow_wcounter
|
|
|
|
|
|
global textwindow_filename
|
|
global textwindow_fileid
|
|
set textwindow_filename $filename
|
|
toplevel $textwindow_w
|
|
wm title $textwindow_w $filename
|
|
wm iconname $textwindow_w $filename
|
|
frame $textwindow_w.buttons
|
|
pack $textwindow_w.buttons -side bottom -fill x -pady 2m
|
|
button $textwindow_w.buttons.dismiss -text Dismiss -command "destroy $textwindow_w"
|
|
pack $textwindow_w.buttons.dismiss -side left -expand 1
|
|
if { $ro eq {} } {
|
|
button $textwindow_w.buttons.save -text "Save" -command \
|
|
{
|
|
set textwindow_fileid [open $textwindow_filename "w"]
|
|
puts -nonewline $textwindow_fileid [$textwindow_w.text get 1.0 {end - 1 chars}]
|
|
close $textwindow_fileid
|
|
destroy $textwindow_w
|
|
}
|
|
pack $textwindow_w.buttons.save -side left -expand 1
|
|
}
|
|
|
|
text $textwindow_w.text -relief sunken -bd 2 -yscrollcommand "$textwindow_w.yscroll set" -setgrid 1 \
|
|
-xscrollcommand "$textwindow_w.xscroll set" -wrap none -height 30
|
|
scrollbar $textwindow_w.yscroll -command "$textwindow_w.text yview"
|
|
scrollbar $textwindow_w.xscroll -command "$textwindow_w.text xview" -orient horiz
|
|
pack $textwindow_w.yscroll -side right -fill y
|
|
pack $textwindow_w.text -expand yes -fill both
|
|
pack $textwindow_w.xscroll -side bottom -fill x
|
|
bind $textwindow_w <Escape> "$textwindow_w.buttons.dismiss invoke"
|
|
set textwindow_fileid [open $filename "r"]
|
|
|
|
# 20171103 insert at insertion cursor(insert tag) instead of 0.0
|
|
$textwindow_w.text insert insert [read $textwindow_fileid]
|
|
close $textwindow_fileid
|
|
return {}
|
|
}
|
|
|
|
proc viewdata {data {ro {}}} {
|
|
global viewdata_wcounter rcode viewdata_filename
|
|
global viewdata_w OS viewdata_fileid env
|
|
# set viewdata_w .view$viewdata_wcounter
|
|
# catch {destroy $viewdata_w}
|
|
set viewdata_wcounter [expr {$viewdata_wcounter+1}]
|
|
set viewdata_w .view$viewdata_wcounter
|
|
set rcode {}
|
|
toplevel $viewdata_w
|
|
wm title $viewdata_w {View data}
|
|
frame $viewdata_w.buttons
|
|
pack $viewdata_w.buttons -side bottom -fill x -pady 2m
|
|
|
|
button $viewdata_w.buttons.dismiss -text Dismiss -command "destroy $viewdata_w"
|
|
pack $viewdata_w.buttons.dismiss -side left -expand 1
|
|
|
|
if { $ro eq {} } {
|
|
button $viewdata_w.buttons.saveas -text {Save As} -command {
|
|
if {$OS == "Windows"} {
|
|
set viewdata_filename [tk_getSaveFile -initialdir $env(windir) ]
|
|
} else {
|
|
set viewdata_filename [tk_getSaveFile -initialdir [pwd] ]
|
|
}
|
|
if { $viewdata_filename != "" } {
|
|
set viewdata_fileid [open $viewdata_filename "w"]
|
|
puts -nonewline $viewdata_fileid [$viewdata_w.text get 1.0 {end - 1 chars}]
|
|
close $viewdata_fileid
|
|
}
|
|
}
|
|
pack $viewdata_w.buttons.saveas -side left -expand 1
|
|
}
|
|
|
|
text $viewdata_w.text -relief sunken -bd 2 -yscrollcommand "$viewdata_w.yscroll set" -setgrid 1 \
|
|
-xscrollcommand "$viewdata_w.xscroll set" -wrap none -height 30
|
|
scrollbar $viewdata_w.yscroll -command "$viewdata_w.text yview"
|
|
scrollbar $viewdata_w.xscroll -command "$viewdata_w.text xview" -orient horiz
|
|
pack $viewdata_w.yscroll -side right -fill y
|
|
pack $viewdata_w.text -expand yes -fill both
|
|
pack $viewdata_w.xscroll -side bottom -fill x
|
|
# 20171103 insert at insertion cursor(insert tag) instead of 0.0
|
|
$viewdata_w.text insert insert $data
|
|
return $rcode
|
|
}
|
|
|
|
# given an absolute path of a symbol/schematic remove the path prefix
|
|
# if file is in a library directory (a $pathlist dir)
|
|
proc rel_sym_path {symbol} {
|
|
global pathlist
|
|
|
|
set curr_dirname [xschem get current_dirname]
|
|
set name {}
|
|
foreach path_elem $pathlist {
|
|
if { ![string compare $path_elem .] && [info exist curr_dirname]} {
|
|
set path_elem $curr_dirname
|
|
}
|
|
set pl [string length $path_elem]
|
|
if { [string equal -length $pl $path_elem $symbol] } {
|
|
set name [string range $symbol [expr {$pl+1}] end]
|
|
break
|
|
}
|
|
}
|
|
if {$name eq {} } {
|
|
# no known lib, so return full path
|
|
set name ${symbol}
|
|
}
|
|
return $name
|
|
}
|
|
|
|
## given a library/symbol return its absolute path
|
|
proc abs_sym_path {fname {ext {} } } {
|
|
global pathlist OS
|
|
|
|
set curr_dirname [xschem get current_dirname]
|
|
## empty: do nothing
|
|
if {$fname eq {} } return {}
|
|
## add extension for 1.0 file format compatibility
|
|
if { $ext ne {} } {
|
|
set fname [file rootname $fname]$ext
|
|
}
|
|
if {$OS eq "Windows"} {
|
|
## absolute path: return as is
|
|
if { [regexp {^[A-Za-z]\:/} $fname ] } {
|
|
return "$fname"
|
|
}
|
|
} else {
|
|
## absolute path: return as is
|
|
if { [regexp {^/} $fname] } {
|
|
return "$fname"
|
|
}
|
|
}
|
|
## replace all runs of multiple / with single / in fname
|
|
regsub -all {/+} $fname {/} fname
|
|
## replace all '/./' with '/'
|
|
while {[regsub {/\./} $fname {/} fname]} {}
|
|
## transform a/b/../c to a/c or a/b/c/.. to a/b
|
|
while {[regsub {([^/]*\.*[^./]+[^/]*)/\.\./?} $fname {} fname] } {}
|
|
## remove trailing '/' or '/.'
|
|
while {[regsub {/\.?$} $fname {} fname]} {}
|
|
## 'found' set to 1 if fname begins with './' or '../'
|
|
set found 0
|
|
## remove any leading './'
|
|
while {[regsub {^\./} $fname {} fname]} {set found 1}
|
|
## if previous operation left fname empty set to '.'
|
|
if { $fname eq {} } { set fname . }
|
|
## if fname is just "." return $curr_dirname
|
|
if {[regexp {^\.$} $fname] } { return "$curr_dirname" }
|
|
set tmpdirname $curr_dirname
|
|
set tmpfname $fname
|
|
## if tmpfname begins with '../' remove this prefix and remove one path component from tmpdirname
|
|
while { [regsub {^\.\./} $tmpfname {} tmpfname] } {
|
|
set found 1
|
|
set tmpdirname [file dirname $tmpdirname]
|
|
}
|
|
## if tmpfname reducced to '..' return dirname of tmpdirname
|
|
if { $tmpfname eq {..}} { return "[file dirname $tmpdirname]" }
|
|
## if given file begins with './' or '../' and dir or file exists relative to curr_dirname
|
|
## just return it.
|
|
if {$found } {
|
|
set tmpfname "${tmpdirname}/$tmpfname"
|
|
if { [file exists "$tmpfname"] } { return "$tmpfname" }
|
|
## if file does not exists but directory does return anyway
|
|
if { [file exists [file dirname "$tmpfname"]] } { return "$tmpfname" }
|
|
}
|
|
## if fname is present in one of the pathlist paths get the absolute path
|
|
set name {}
|
|
foreach path_elem $pathlist {
|
|
## in xschem a . in pathlist means the directory of currently loaded schematic/symbol
|
|
if { ![string compare $path_elem .] && [info exist curr_dirname]} {
|
|
set path_elem $curr_dirname
|
|
}
|
|
set fullpath "$path_elem/$fname"
|
|
if { [file exists $fullpath] } {
|
|
set name $fullpath
|
|
break
|
|
}
|
|
}
|
|
## nothing found -> use current schematic directory
|
|
if {$name eq {} } {
|
|
set name "$curr_dirname/$fname"
|
|
}
|
|
return "$name"
|
|
}
|
|
|
|
proc add_ext {fname ext} {
|
|
return [file rootname $fname]$ext
|
|
}
|
|
|
|
proc input_line {txt {cmd {}} {preset {}} {w 12}} {
|
|
global input_line_cmd input_line_data wm_fix
|
|
set input_line_data {}
|
|
if { [winfo exists .dialog] } return
|
|
xschem set semaphore [expr {[xschem get semaphore] +1}]
|
|
toplevel .dialog -class Dialog
|
|
wm title .dialog {Input number}
|
|
set X [expr {[winfo pointerx .dialog] - 60}]
|
|
set Y [expr {[winfo pointery .dialog] - 35}]
|
|
# 20100203
|
|
if { $wm_fix } { tkwait visibility .dialog }
|
|
wm geometry .dialog "+$X+$Y"
|
|
set input_line_cmd $cmd
|
|
frame .dialog.f1
|
|
label .dialog.f1.l -text $txt
|
|
entry .dialog.f1.e -width $w
|
|
.dialog.f1.e insert 0 $preset
|
|
.dialog.f1.e selection range 0 end
|
|
|
|
pack .dialog.f1.l .dialog.f1.e -side left
|
|
frame .dialog.f2
|
|
button .dialog.f2.ok -text OK -command {
|
|
if {$input_line_cmd ne {}} {
|
|
eval [subst -nocommands {$input_line_cmd [.dialog.f1.e get]}]
|
|
}
|
|
set input_line_data [.dialog.f1.e get]
|
|
destroy .dialog
|
|
}
|
|
button .dialog.f2.cancel -text Cancel -command { destroy .dialog }
|
|
pack .dialog.f2.ok -anchor w -side left
|
|
pack .dialog.f2.cancel -anchor e
|
|
pack .dialog.f1
|
|
pack .dialog.f2 -expand yes -fill x
|
|
bind .dialog <Escape> {.dialog.f2.cancel invoke}
|
|
bind .dialog <Return> {.dialog.f2.ok invoke}
|
|
grab set .dialog
|
|
focus .dialog.f1.e
|
|
tkwait window .dialog
|
|
xschem set semaphore [expr {[xschem get semaphore] -1}]
|
|
return $input_line_data
|
|
}
|
|
|
|
proc launcher {launcher_var {launcher_program {} } } {
|
|
# env, XSCHEM_SHAREDIR and netlist_dir not used directly but useful in paths passed thru launcher_var
|
|
global launcher_default_program env XSCHEM_SHAREDIR netlist_dir
|
|
|
|
if { ![string compare $launcher_program {}] } { set launcher_program $launcher_default_program}
|
|
eval exec [subst $launcher_program] {[subst $launcher_var]} &
|
|
}
|
|
|
|
proc reconfigure_layers_button { { topwin {} } } {
|
|
global colors dark_colorscheme
|
|
set c [xschem get rectcolor]
|
|
$topwin.menubar.layers configure -background [lindex $colors $c]
|
|
if { $dark_colorscheme == 1 && $c == 0} {
|
|
$topwin.menubar.layers configure -foreground white
|
|
} else {
|
|
$topwin.menubar.layers configure -foreground black
|
|
}
|
|
}
|
|
|
|
proc reconfigure_layers_menu { {topwin {} } } {
|
|
global colors dark_colorscheme
|
|
set j 0
|
|
foreach i $colors {
|
|
set ind_bg white
|
|
if { $j == [xschem get backlayer] } {
|
|
if { $dark_colorscheme == 1 } {
|
|
set layfg white
|
|
} else {
|
|
set layfg black
|
|
}
|
|
} else {
|
|
if { $dark_colorscheme == 1 } {
|
|
set layfg black
|
|
} else {
|
|
set layfg white
|
|
}
|
|
}
|
|
$topwin.menubar.layers.menu entryconfigure $j -activebackground $i \
|
|
-background $i -foreground $layfg -activeforeground $layfg
|
|
incr j
|
|
}
|
|
reconfigure_layers_button $topwin
|
|
}
|
|
|
|
proc get_file_path {ff} {
|
|
global env OS
|
|
# Absolute path ? return as is.
|
|
# Linux Windows
|
|
if { [regexp {^/} $ff] || [regexp {^[a-zA-Z]:} $ff] } { return $ff }
|
|
if {$OS == "Windows"} {
|
|
set mylist [split $env(PATH) \;]
|
|
} else {
|
|
set mylist [split $env(PATH) :]
|
|
}
|
|
foreach i $mylist {
|
|
set ii $i/$ff
|
|
if { [file exists $ii]} {return $ii}
|
|
}
|
|
# nothing found, return $ff as is and hope for the best :-)
|
|
return $ff
|
|
}
|
|
|
|
#
|
|
# Balloon help system, from https://wiki.tcl-lang.org/page/balloon+help
|
|
#
|
|
proc balloon {w help {pos 1}} {
|
|
bind $w <Any-Enter> "after 1000 [list balloon_show %W [list $help] $pos]"
|
|
bind $w <Any-Leave> "destroy %W.balloon"
|
|
}
|
|
|
|
### pos:
|
|
## 0: set balloon close to mouse
|
|
## 1: set balloon below related widget
|
|
proc balloon_show {w arg pos} {
|
|
if {[eval winfo containing [winfo pointerxy .]]!=$w} {return}
|
|
set top $w.balloon
|
|
catch {destroy $top}
|
|
toplevel $top -bd 1 -bg black
|
|
wm overrideredirect $top 1
|
|
if {[string equal [tk windowingsystem] aqua]} {
|
|
::tk::unsupported::MacWindowStyle style $top help none
|
|
}
|
|
pack [message $top.txt -aspect 10000 -bg lightyellow \
|
|
-font fixed -text $arg]
|
|
if { $pos } {
|
|
set wmx [winfo rootx $w]
|
|
set wmy [expr {[winfo rooty $w]+[winfo height $w]}]
|
|
} else {
|
|
set wmx [expr [winfo pointerx $w] + 20]
|
|
set wmy [winfo pointery $w]
|
|
}
|
|
wm geometry $top [winfo reqwidth $top.txt]x[winfo reqheight $top.txt]+$wmx+$wmy
|
|
raise $top
|
|
}
|
|
|
|
proc context_menu { } {
|
|
global retval
|
|
|
|
set retval 0
|
|
if {[info tclversion] >= 8.5} {
|
|
set font {Sans 8 bold}
|
|
} else {
|
|
set font fixed
|
|
}
|
|
set selection [expr {[xschem get lastsel] eq {1}}]
|
|
toplevel .ctxmenu
|
|
wm overrideredirect .ctxmenu 1
|
|
set x [expr {[winfo pointerx .ctxmenu] - 10}]
|
|
set y [expr {[winfo pointery .ctxmenu] - 10}]
|
|
if { !$selection} {
|
|
button .ctxmenu.b9 -text {Open most recent} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuRecent -compound left \
|
|
-font [subst $font] -command {set retval 9; destroy .ctxmenu}
|
|
}
|
|
button .ctxmenu.b10 -text {Edit attributes} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuEdit -compound left \
|
|
-font [subst $font] -command {set retval 10; destroy .ctxmenu}
|
|
button .ctxmenu.b11 -text {Edit attr in editor} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuEdit -compound left \
|
|
-font [subst $font] -command {set retval 11; destroy .ctxmenu}
|
|
if {$selection} {
|
|
button .ctxmenu.b12 -text {Descend schematic} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuDown -compound left \
|
|
-font [subst $font] -command {set retval 12; destroy .ctxmenu}
|
|
button .ctxmenu.b13 -text {Descend symbol} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuDownSym -compound left \
|
|
-font [subst $font] -command {set retval 13; destroy .ctxmenu}
|
|
button .ctxmenu.b18 -text {Delete selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuDelete -compound left \
|
|
-font [subst $font] -command {set retval 18; destroy .ctxmenu}
|
|
button .ctxmenu.b7 -text {Cut selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuCut -compound left \
|
|
-font [subst $font] -command {set retval 7; destroy .ctxmenu}
|
|
button .ctxmenu.b15 -text {Copy selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuCopy -compound left \
|
|
-font [subst $font] -command {set retval 15; destroy .ctxmenu}
|
|
button .ctxmenu.b16 -text {Move selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuMove -compound left \
|
|
-font [subst $font] -command {set retval 16; destroy .ctxmenu}
|
|
button .ctxmenu.b17 -text {Duplicate selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuDuplicate -compound left \
|
|
-font [subst $font] -command {set retval 17; destroy .ctxmenu}
|
|
}
|
|
if {!$selection} {
|
|
button .ctxmenu.b14 -text {Go to upper level} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuUp -compound left \
|
|
-font [subst $font] -command {set retval 14; destroy .ctxmenu}
|
|
button .ctxmenu.b1 -text {Insert symbol} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuSymbol -compound left \
|
|
-font [subst $font] -command {set retval 1; destroy .ctxmenu}
|
|
button .ctxmenu.b2 -text {Insert wire} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuWire -compound left \
|
|
-font [subst $font] -command {set retval 2; destroy .ctxmenu}
|
|
button .ctxmenu.b3 -text {Insert line} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuLine -compound left \
|
|
-font [subst $font] -command {set retval 3; destroy .ctxmenu}
|
|
button .ctxmenu.b4 -text {Insert box} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuBox -compound left \
|
|
-font [subst $font] -command {set retval 4; destroy .ctxmenu}
|
|
button .ctxmenu.b5 -text {Insert polygon} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuPoly -compound left \
|
|
-font [subst $font] -command {set retval 5; destroy .ctxmenu}
|
|
button .ctxmenu.b19 -text {Insert arc} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuArc -compound left \
|
|
-font [subst $font] -command {set retval 19; destroy .ctxmenu}
|
|
button .ctxmenu.b20 -text {Insert circle} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuCircle -compound left \
|
|
-font [subst $font] -command {set retval 20; destroy .ctxmenu}
|
|
button .ctxmenu.b6 -text {Insert text} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuText -compound left \
|
|
-font [subst $font] -command {set retval 6; destroy .ctxmenu}
|
|
button .ctxmenu.b8 -text {Paste selection} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuPaste -compound left \
|
|
-font [subst $font] -command {set retval 8; destroy .ctxmenu}
|
|
}
|
|
button .ctxmenu.b21 -text {Abort command} -padx 3 -pady 0 -anchor w -activebackground grey50 \
|
|
-highlightthickness 0 -image CtxmenuAbort -compound left \
|
|
-font [subst $font] -command {set retval 21; destroy .ctxmenu}
|
|
|
|
pack .ctxmenu.b21 -fill x -expand true
|
|
if {!$selection} {
|
|
pack .ctxmenu.b9 -fill x -expand true
|
|
}
|
|
pack .ctxmenu.b10 .ctxmenu.b11 -fill x -expand true
|
|
if {$selection} {
|
|
pack .ctxmenu.b12 .ctxmenu.b13 .ctxmenu.b18 -fill x -expand true
|
|
}
|
|
if {!$selection} {
|
|
pack .ctxmenu.b14 -fill x -expand true
|
|
pack .ctxmenu.b1 .ctxmenu.b2 .ctxmenu.b3 .ctxmenu.b4 .ctxmenu.b5 -fill x -expand true
|
|
pack .ctxmenu.b19 .ctxmenu.b20 .ctxmenu.b6 -fill x -expand true
|
|
}
|
|
if {$selection} {
|
|
pack .ctxmenu.b7 -fill x -expand true
|
|
pack .ctxmenu.b15 .ctxmenu.b16 .ctxmenu.b17 -fill x -expand true
|
|
}
|
|
if {!$selection} {
|
|
pack .ctxmenu.b8 -fill x -expand true
|
|
}
|
|
wm geometry .ctxmenu "+$x+$y"
|
|
update
|
|
# if window has been destroyed (by mouse pointer exiting) do nothing
|
|
if { ![winfo exists .ctxmenu] } { return 0 }
|
|
|
|
set wx [winfo width .ctxmenu]
|
|
set wy [winfo height .ctxmenu]
|
|
set sx [winfo screenwidth .]
|
|
set sy [winfo screenheight .]
|
|
if { $y + $wy > $sy } {
|
|
set y [expr {$y - ( $y + $wy - $sy )} ]
|
|
}
|
|
if { $x + $wx > $sx } {
|
|
set x [expr {$x - ( $x + $wx - $sx )} ]
|
|
}
|
|
wm geometry .ctxmenu "+$x+$y";# move away from screen edges
|
|
bind .ctxmenu <Leave> {if { {%W} eq {.ctxmenu} } {destroy .ctxmenu}}
|
|
tkwait window .ctxmenu
|
|
return $retval
|
|
}
|
|
|
|
#
|
|
# toolbar: Public variables that we allow to be overridden
|
|
# Code contributed by Neil Johnson (github: nejohnson)
|
|
#
|
|
proc setup_toolbar {} {
|
|
global toolbar_visible toolbar_horiz toolbar_list XSCHEM_SHAREDIR
|
|
set_ne toolbar_visible 0
|
|
set_ne toolbar_horiz 1
|
|
set_ne toolbar_list {
|
|
FileOpen
|
|
FileSave
|
|
FileReload
|
|
---
|
|
EditUndo
|
|
EditRedo
|
|
EditCut
|
|
EditCopy
|
|
EditPaste
|
|
EditDelete
|
|
---
|
|
EditDuplicate
|
|
EditMove
|
|
---
|
|
EditPushSch
|
|
EditPushSym
|
|
EditPop
|
|
---
|
|
ViewRedraw
|
|
ViewToggleColors
|
|
---
|
|
ToolInsertSymbol
|
|
ToolInsertText
|
|
ToolInsertWire
|
|
ToolInsertLine
|
|
ToolInsertRect
|
|
ToolInsertPolygon
|
|
ToolInsertArc
|
|
ToolInsertCircle
|
|
---
|
|
ToolSearch
|
|
---
|
|
ToolJoinTrim
|
|
ToolBreak
|
|
}
|
|
#
|
|
# Pull in the toolbar graphics resources
|
|
#
|
|
source $XSCHEM_SHAREDIR/resources.tcl
|
|
#
|
|
# Separation bar counter
|
|
#
|
|
}
|
|
|
|
#
|
|
# Create a tool button which may be displayed
|
|
#
|
|
proc toolbar_add {name cmd { help "" } {topwin {} } } {
|
|
if {![winfo exists $topwin.toolbar]} {
|
|
frame $topwin.toolbar -relief raised -bd 0 -bg white
|
|
}
|
|
button $topwin.toolbar.b$name -image img$name -relief flat -bd 0 -bg white -fg white -height 24 \
|
|
-padx 0 -pady 0 -highlightthickness 0 -command $cmd
|
|
if { $help == "" } { balloon $topwin.toolbar.b$name $name } else { balloon $topwin.toolbar.b$name $help }
|
|
}
|
|
|
|
#
|
|
# Show the toolbar in horizontal or vertical position, parsing the toolbar list and
|
|
# adding any separators as needed.
|
|
#
|
|
proc toolbar_show { { topwin {} } } {
|
|
global toolbar_horiz toolbar_list toolbar_visible tabbed_interface
|
|
|
|
# puts "toolbar_show: $topwin"
|
|
set toolbar_visible 1
|
|
if {![winfo exists $topwin.toolbar]} {
|
|
frame $topwin.toolbar -relief raised -bd 0 -bg white
|
|
}
|
|
if {[winfo ismapped $topwin.toolbar]} {return}
|
|
if { $toolbar_horiz } {
|
|
if {$tabbed_interface} {
|
|
pack $topwin.toolbar -fill x -before $topwin.tabs
|
|
} else {
|
|
pack $topwin.toolbar -fill x -before $topwin.drw
|
|
}
|
|
} else {
|
|
pack $topwin.toolbar -side left -fill y -before $topwin.drw
|
|
}
|
|
set pos "top"
|
|
if { $toolbar_horiz } { set pos "left" }
|
|
set tlist [ winfo children $topwin.toolbar ]
|
|
set toolbar_sepn 0
|
|
foreach b $toolbar_list {
|
|
if { $b == "---" } {
|
|
if { $toolbar_horiz } {
|
|
frame $topwin.toolbar.sep$toolbar_sepn -bg lightgrey -width 2
|
|
pack $topwin.toolbar.sep$toolbar_sepn -side $pos -padx 1 -pady 0 -fill y
|
|
} else {
|
|
frame $topwin.toolbar.sep$toolbar_sepn -bg lightgrey -height 2
|
|
pack $topwin.toolbar.sep$toolbar_sepn -side $pos -padx 0 -pady 1 -fill x
|
|
}
|
|
incr toolbar_sepn
|
|
} else {
|
|
if { [ lsearch -exact $tlist "$topwin.toolbar.b$b" ] != -1 } {
|
|
pack $topwin.toolbar.b$b -side $pos
|
|
} else {
|
|
puts "Error: unknown toolbar item \"$b\""
|
|
}
|
|
}
|
|
}
|
|
set pos "bottom"
|
|
if { $toolbar_horiz } { set pos "right" }
|
|
foreach b { Waves Simulate Netlist } {
|
|
pack $topwin.toolbar.b$b -side $pos
|
|
}
|
|
}
|
|
|
|
#
|
|
# Hide the toolbar, unpack the buttons, and remove any separators
|
|
#
|
|
proc toolbar_hide { { topwin {} } } {
|
|
global toolbar_visible
|
|
set toolbar_visible 0
|
|
if {![winfo exists $topwin.toolbar]} {return}
|
|
if {![winfo ismapped $topwin.toolbar]} {return}
|
|
set tlist [ winfo children $topwin.toolbar ]
|
|
foreach b $tlist {
|
|
pack forget $b
|
|
if { [ string match "$topwin.toolbar.sep*" $b ] == 1 } {
|
|
destroy $b
|
|
}
|
|
}
|
|
pack forget $topwin.toolbar
|
|
set toolbar_visible 0
|
|
}
|
|
|
|
proc pack_tabs {} {
|
|
global toolbar_horiz
|
|
if {[winfo exists .toolbar] && [winfo ismapped .toolbar] } {
|
|
if { $toolbar_horiz == 1 } {
|
|
pack .tabs -fill x -side top -after .toolbar
|
|
} else {
|
|
pack .tabs -fill x -side top -before .toolbar
|
|
}
|
|
} else {
|
|
pack .tabs -fill x -side top -before .drw
|
|
}
|
|
}
|
|
|
|
proc setup_tabbed_interface {} {
|
|
global tabbed_interface toolbar_horiz
|
|
|
|
if { $tabbed_interface } {
|
|
if { ![winfo exists .tabs] } {
|
|
frame .tabs
|
|
button .tabs.x0 -padx 2 -pady 0 -anchor nw -text Main -command "xschem new_schematic switch_tab .drw"
|
|
bind .tabs.x0 <ButtonPress> {swap_tabs %X %Y press}
|
|
bind .tabs.x0 <ButtonRelease> {swap_tabs %X %Y release}
|
|
button .tabs.add -padx 0 -pady 0 -text { + } -command "xschem new_schematic create"
|
|
pack .tabs.x0 .tabs.add -side left
|
|
pack_tabs
|
|
}
|
|
} else {
|
|
destroy .tabs
|
|
}
|
|
if {$tabbed_interface} {
|
|
.menubar.file.menu entryconfigure {Open recent in new window} -state disabled
|
|
.menubar.file.menu entryconfigure {Open new window} -state disabled
|
|
set_tab_names
|
|
} else {
|
|
.menubar.file.menu entryconfigure {Open recent in new window} -state normal
|
|
.menubar.file.menu entryconfigure {Open new window} -state normal
|
|
}
|
|
# update tabbed window close (X) function
|
|
if {$tabbed_interface} {
|
|
wm protocol . WM_DELETE_WINDOW {
|
|
if { [xschem get current_win_path] eq {.drw} } {
|
|
xschem exit
|
|
} else {
|
|
xschem new_schematic destroy [xschem get current_win_path] {}
|
|
}
|
|
}
|
|
# restore non tabbed window close function for main window
|
|
} else {
|
|
wm protocol . WM_DELETE_WINDOW {
|
|
set old [xschem get current_win_path]
|
|
save_ctx $old
|
|
restore_ctx .drw
|
|
housekeeping_ctx
|
|
xschem new_schematic switch_win .drw
|
|
xschem exit
|
|
# did not exit (user cancel) ... switch back
|
|
restore_ctx $old
|
|
housekeeping_ctx
|
|
xschem new_schematic switch_win $old
|
|
}
|
|
}
|
|
}
|
|
|
|
proc delete_tab {path} {
|
|
regsub {\.drw$} $path {} path
|
|
destroy .tabs$path
|
|
}
|
|
|
|
# button press on a tab, drag onto another tab, release button --> swap
|
|
proc swap_tabs {x y what} {
|
|
if {$what eq {press} } {
|
|
# puts "From: [winfo containing $x $y]"
|
|
set tctx::source_swap_tab [winfo containing $x $y]
|
|
} else {
|
|
# puts "To: [winfo containing $x $y]"
|
|
set tctx::dest_swap_tab [winfo containing $x $y]
|
|
if {[info exists tctx::source_swap_tab] && [info exists tctx::dest_swap_tab]} {
|
|
set cond1 [regexp {\.tabs\.x} $tctx::source_swap_tab]
|
|
set cond2 [regexp {\.tabs\.x} $tctx::dest_swap_tab]
|
|
set cond3 [expr { $tctx::source_swap_tab ne $tctx::dest_swap_tab }]
|
|
if { $cond1 && $cond2 && $cond3} {
|
|
# puts "ok for swapping ctx"
|
|
set tablist [pack slaves .tabs]
|
|
set sourceidx [lsearch -exact $tablist $tctx::source_swap_tab]
|
|
set destidx [lsearch -exact $tablist $tctx::dest_swap_tab]
|
|
incr sourceidx
|
|
incr destidx
|
|
set following_source_tab [lindex $tablist $sourceidx]
|
|
set following_dest_tab [lindex $tablist $destidx]
|
|
# puts " $tablist --> $following_source_tab $following_dest_tab"
|
|
pack $tctx::source_swap_tab -side left -before $following_dest_tab
|
|
pack $tctx::dest_swap_tab -side left -before $following_source_tab
|
|
}
|
|
set tctx::source_swap_tab {}
|
|
set tctx::dest_swap_tab {}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc prev_tab {} {
|
|
global tabbed_interface
|
|
if { !$tabbed_interface} { return}
|
|
set currwin [xschem get current_win_path]
|
|
regsub {\.drw} $currwin {} tabname
|
|
if {$tabname eq {}} { set tabname .x0}
|
|
regsub {\.x} $tabname {} number
|
|
set next_tab $number
|
|
set highest -10000000
|
|
set xcoord [winfo rootx .tabs$tabname]
|
|
for {set i 0} {$i < $tctx::max_new_windows} { incr i} {
|
|
if { $i == $number} { continue}
|
|
if { [winfo exists .tabs.x$i] } {
|
|
set tab_coord [winfo rootx .tabs.x$i]
|
|
if {$tab_coord < $xcoord && $tab_coord > $highest} {
|
|
set next_tab $i
|
|
set highest $tab_coord
|
|
}
|
|
}
|
|
}
|
|
.tabs.x$next_tab invoke
|
|
}
|
|
|
|
proc next_tab {} {
|
|
global tabbed_interface
|
|
if { !$tabbed_interface} {return}
|
|
set currwin [xschem get current_win_path]
|
|
regsub {\.drw} $currwin {} tabname
|
|
if {$tabname eq {}} { set tabname .x0}
|
|
regsub {\.x} $tabname {} number
|
|
set next_tab $number
|
|
set lowest 10000000
|
|
set xcoord [winfo rootx .tabs$tabname]
|
|
for {set i 0} {$i < $tctx::max_new_windows} { incr i} {
|
|
if { $i == $number} { continue}
|
|
if { [winfo exists .tabs.x$i] } {
|
|
set tab_coord [winfo rootx .tabs.x$i]
|
|
if {$tab_coord > $xcoord && $tab_coord < $lowest} {
|
|
set next_tab $i
|
|
set lowest $tab_coord
|
|
}
|
|
}
|
|
}
|
|
.tabs.x$next_tab invoke
|
|
}
|
|
|
|
proc set_tab_names {{mod {}}} {
|
|
global tabbed_interface has_x
|
|
|
|
if {[info exists has_x] && $tabbed_interface } {
|
|
set currwin [xschem get current_win_path]
|
|
regsub {\.drw} $currwin {} tabname
|
|
if {$tabname eq {}} { set tabname .x0}
|
|
.tabs$tabname configure -text [file tail [xschem get schname]]$mod -bg Palegreen
|
|
if {$tabname eq {.x0}} {
|
|
.tabs$tabname configure -fg red
|
|
}
|
|
for { set i 0} { $i < $tctx::max_new_windows} { incr i} {
|
|
if { [winfo exists .tabs.x$i] && ($tabname ne ".x$i")} {
|
|
.tabs.x$i configure -bg $tctx::tab_bg
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc raise_dialog {parent window_path } {
|
|
global myload_loadfile
|
|
foreach i ".dialog .graphdialog .load" {
|
|
if {[info exists myload_loadfile ] && $myload_loadfile == 2 && $i eq {.load} } {
|
|
continue
|
|
}
|
|
if {[winfo exists $i] && [winfo ismapped $i] && [winfo ismapped $parent] &&
|
|
[wm stackorder $i isbelow $parent ]} {
|
|
raise $i $window_path
|
|
}
|
|
}
|
|
}
|
|
|
|
proc set_old_tk_fonts {} {
|
|
if {[info tclversion] <= 8.4} {
|
|
set myfont {-*-helvetica-*-r-*-*-12-*-*-*-*-*-*-*}
|
|
set mymonofont fixed
|
|
option add *Button*font $myfont startupFile
|
|
option add *Menubutton*font $myfont startupFile
|
|
option add *Menu*font $myfont startupFile
|
|
option add *Listbox*font $myfont startupFile
|
|
option add *Entry*font $mymonofont startupFile
|
|
option add *Text*font $mymonofont startupFile
|
|
option add *Label*font $myfont startupFile
|
|
}
|
|
}
|
|
|
|
proc every {interval script} {
|
|
uplevel #0 $script
|
|
after $interval [list every $interval $script]
|
|
}
|
|
|
|
## tcl context switching global namespace
|
|
namespace eval tctx {
|
|
variable tctx
|
|
variable i
|
|
variable global_list
|
|
variable global_array_list
|
|
variable dialog_list
|
|
variable tab_bg
|
|
variable max_new_windows
|
|
variable source_swap_tab
|
|
variable dest_swap_tab
|
|
}
|
|
|
|
## list of dialogs: when open do not perform context switching
|
|
## do not include .infotext as it is always open (in withdrawn mode)
|
|
set tctx::dialog_list { .ctxmenu .alert .sim .dialog .tclcmd .sl .dim }
|
|
|
|
proc no_open_dialogs {} {
|
|
set res 1
|
|
foreach tctx::i $tctx::dialog_list {
|
|
if { [winfo exists $tctx::i] } {
|
|
# puts "$tctx::i dialog open"
|
|
set res 0
|
|
}
|
|
}
|
|
return $res
|
|
}
|
|
|
|
## list of globals to save/restore on context switching
|
|
## EXCEPTIONS, not to be saved/restored:
|
|
## "textwindow_wcounter" should be kept unique as it is the number of open textwindows
|
|
## "viewdata_wcounter" should be kept unique as it is the number of open viewdatas
|
|
## "measure_id" should be kept unique since we allow only one measure tooltip in graphs
|
|
## "tabbed_interface"
|
|
## "case_insensitive" case insensitive symbol lookup (on case insensitive filesystems only!)
|
|
## "dark_colors_save"
|
|
## "light_colors_save" restore default colors
|
|
## "menu_debug_var" there is only a global debug mode
|
|
## "debug_var" there is only a global debug mode
|
|
## "xschem_server_getdata" only one tcp listener per process
|
|
## "bespice_server_getdata" only one tcp listener per process
|
|
|
|
set tctx::global_list {
|
|
auto_hilight autofocus_mainwindow autotrim_wires bespice_listen_port big_grid_points bus_replacement_char
|
|
cadgrid cadlayers cadsnap cairo_font_name
|
|
change_lw color_ps colors connect_by_kissing constrained_move copy_cell custom_label_prefix custom_token dark_colors
|
|
dark_colorscheme dim_bg dim_value disable_unique_names do_all_inst draw_grid draw_window
|
|
edit_prop_pos edit_prop_size editprop_sympath edit_symbol_prop_new_sel enable_dim_bg enable_stretch
|
|
en_hilight_conn_inst filetmp flat_netlist fullscreen gaw_fd gaw_tcp_address globfilter
|
|
graph_bus graph_digital graph_logx graph_logy graph_raw_level
|
|
graph_sel_color graph_schname graph_selected graph_sel_wave graph_sort
|
|
graph_unlocked hide_empty_graphs hide_symbols hsize
|
|
incr_hilight infowindow_text INITIALINSTDIR INITIALLOADDIR INITIALPROPDIR INITIALTEXTDIR
|
|
input_line_cmd input_line_data launcher_default_program light_colors line_width
|
|
live_cursor2_backannotate local_netlist_dir measure_text
|
|
myload_d myload_default_geometry myload_dir1 myload_dir2 myload_dir2
|
|
myload_ext myload_files1 myload_files2 myload_index1 myload_loadfile
|
|
myload_retval myload_sash_pos myload_sel myload_type myload_yview netlist_dir netlist_show
|
|
netlist_type no_change_attrs noprint_libs old_selected_tok
|
|
only_probes path pathlist persistent_command preserve_unchanged_attrs prev_symbol ps_colors rainbow_colors
|
|
rawfile_loaded rcode recentfile replace_key retval retval_orig rotated_text save_initialfile search_exact
|
|
search_found search_schematic search_select search_value selected_tok show_hidden_texts show_infowindow
|
|
show_pin_net_names simconf_default_geometry simconf_vpos simulate_bg
|
|
spiceprefix split_files svg_colors svg_font_name symbol symbol_width sym_txt tclcmd_txt tclstop
|
|
text_line_default_geometry textwindow_fileid textwindow_filename textwindow_w tmp_bus_char
|
|
toolbar_horiz toolbar_list toolbar_visible top_subckt transparent_svg undo_type
|
|
use_label_prefix use_lab_wire user_wants_copy_cell verilog_2001 verilog_bitblast
|
|
viewdata_fileid viewdata_filename viewdata_w vsize xschem_libs xschem_listen_port
|
|
}
|
|
|
|
## list of global arrays to save/restore on context switching
|
|
## will be saved as tctx::.drw_dircolor, tctx::.x1.drw_dircolor and so on
|
|
## EXCEPTIONS, not to be saved/restored:
|
|
## execute
|
|
set tctx::global_array_list {
|
|
dircolor sim enable_layer
|
|
}
|
|
|
|
proc delete_ctx {context} {
|
|
global has_x
|
|
if {![info exists has_x]} {return}
|
|
set tctx::tctx $context
|
|
uplevel #0 {
|
|
# puts "delete_ctx $tctx::tctx"
|
|
array unset $tctx::tctx
|
|
foreach tctx::i $tctx::global_array_list {
|
|
if { [array exists ${tctx::tctx}_$tctx::i] } {
|
|
array unset ${tctx::tctx}_$tctx::i
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc restore_ctx {context} {
|
|
global has_x
|
|
if {![info exists has_x]} {return}
|
|
# puts "restoring tcl context $context : semaphore=[xschem get semaphore]"
|
|
set tctx::tctx $context
|
|
array unset ::sim
|
|
uplevel #0 {
|
|
if { [ array exists tctx::$tctx::tctx ] } {
|
|
# puts "restore_ctx tctx::$tctx::tctx"
|
|
## Cleanup these vars to avoid side effects from previous ctx
|
|
unset -nocomplain gaw_fd
|
|
foreach tctx::i $tctx::global_list {
|
|
if { [info exists [subst tctx::$tctx::tctx]($tctx::i)] } {
|
|
# puts "restoring: $tctx::i"
|
|
set $tctx::i [set [subst tctx::$tctx::tctx]($tctx::i)]
|
|
}
|
|
}
|
|
}
|
|
foreach tctx::i $tctx::global_array_list {
|
|
if { [array exists tctx::${tctx::tctx}_$tctx::i] } {
|
|
array set $tctx::i [array get [subst tctx::${tctx::tctx}_$tctx::i]]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc save_ctx {context} {
|
|
global has_x
|
|
if {![info exists has_x]} {return}
|
|
# puts "saving tcl context $context : semaphore=[xschem get semaphore]"
|
|
set tctx::tctx $context
|
|
uplevel #0 {
|
|
# puts "save_ctx $tctx::tctx"
|
|
foreach tctx::i $tctx::global_list {
|
|
if { [info exists $tctx::i] } {
|
|
# puts "saving: $tctx::i"
|
|
set [subst tctx::$tctx::tctx]($tctx::i) [set $tctx::i]
|
|
}
|
|
}
|
|
foreach tctx::i $tctx::global_array_list {
|
|
if { [array exists $tctx::i] } {
|
|
array set [subst tctx::${tctx::tctx}_$tctx::i] [array get $tctx::i]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc housekeeping_ctx {} {
|
|
global has_x simulate_bg show_hidden_texts case_insensitive draw_window hide_symbols
|
|
if {![info exists has_x]} {return}
|
|
uplevel #0 {
|
|
}
|
|
# puts "housekeeping_ctx, path: [xschem get current_win_path]"
|
|
xschem set hide_symbols $hide_symbols
|
|
xschem set draw_window $draw_window
|
|
xschem case_insensitive $case_insensitive
|
|
if {![info exists tctx::[xschem get current_win_path]_simulate]} {
|
|
[xschem get top_path].menubar.simulate configure -bg $simulate_bg
|
|
} else {
|
|
[xschem get top_path].menubar.simulate configure -bg red
|
|
}
|
|
}
|
|
|
|
proc simulate_button {button_path} {
|
|
global simulate_bg
|
|
if { ![info exists tctx::[xschem get current_win_path]_simulate] } {
|
|
set tctx::[xschem get current_win_path]_simulate 1
|
|
$button_path configure -bg red
|
|
simulate "clear_simulate_button $button_path tctx::[xschem get current_win_path]_simulate"
|
|
}
|
|
|
|
}
|
|
|
|
proc clear_simulate_button {button_path simvar} {
|
|
global simulate_bg
|
|
if { "tctx::[xschem get current_win_path]_simulate" eq $simvar } {
|
|
$button_path configure -bg $simulate_bg
|
|
}
|
|
unset $simvar
|
|
}
|
|
|
|
proc set_bindings {topwin} {
|
|
global env has_x OS autofocus_mainwindow
|
|
###
|
|
### Tk event handling
|
|
###
|
|
|
|
# puts "set_binding: topwin=$topwin"
|
|
if {($OS== "Windows" || [string length [lindex [array get env DISPLAY] 1] ] > 0 ) && [info exists has_x]} {
|
|
set parent [winfo toplevel $topwin]
|
|
|
|
bind $parent <Expose> [list raise_dialog $parent $topwin]
|
|
bind $parent <Visibility> [list raise_dialog $parent $topwin]
|
|
bind $parent <FocusIn> [list raise_dialog $parent $topwin]
|
|
# send non-existent event just to force change schematic window context.
|
|
bind $parent <Enter> "
|
|
if { {$parent} eq {.}} {
|
|
if { {%W} eq {$parent}} {
|
|
# send a fake event just to force context switching in callback()
|
|
xschem callback .drw -55 0 0 0 0 0 0
|
|
}
|
|
} else {
|
|
if { {%W} eq {$parent}} {
|
|
# send a fake event just to force context switching in callback()
|
|
xschem callback $parent.drw -55 0 0 0 0 0 0
|
|
}
|
|
}
|
|
"
|
|
bind $topwin <Leave> "graph_show_measure stop"
|
|
bind $topwin <Expose> "xschem callback %W %T %x %y 0 %w %h %s"
|
|
bind $topwin <Double-Button-1> "xschem callback %W -3 %x %y 0 %b 0 %s"
|
|
bind $topwin <Double-Button-2> "xschem callback %W -3 %x %y 0 %b 0 %s"
|
|
bind $topwin <Double-Button-3> "xschem callback %W -3 %x %y 0 %b 0 %s"
|
|
bind $topwin <Configure> "xschem callback %W %T %x %y 0 %w %h 0"
|
|
bind $topwin <ButtonPress> "xschem callback %W %T %x %y 0 %b 0 %s"
|
|
bind $topwin <ButtonRelease> "xschem callback %W %T %x %y 0 %b 0 %s"
|
|
bind $topwin <KeyPress> "xschem callback %W %T %x %y %N 0 0 %s"
|
|
bind $topwin <KeyRelease> "xschem callback %W %T %x %y %N 0 0 %s"
|
|
if {$autofocus_mainwindow} {
|
|
bind $topwin <Motion> "focus $topwin; xschem callback %W %T %x %y 0 0 0 %s"
|
|
bind $topwin <Enter> "destroy .ctxmenu; focus $topwin; xschem callback %W %T %x %y 0 0 0 0"
|
|
} else {
|
|
bind $topwin <Motion> "xschem callback %W %T %x %y 0 0 0 %s"
|
|
bind $topwin <Enter> "destroy .ctxmenu; xschem callback %W %T %x %y 0 0 0 0"
|
|
}
|
|
bind $topwin <Unmap> " wm withdraw .infotext; set show_infowindow 0 "
|
|
bind $topwin "?" {textwindow "${XSCHEM_SHAREDIR}/xschem.help"}
|
|
|
|
# on Windows Alt key mask is reported as 131072 (1<<17) so build masks manually with values passed from C code
|
|
if {$OS == "Windows" } {
|
|
bind $topwin <Alt-KeyPress> {xschem callback %W %T %x %y %N 0 0 [expr {$Mod1Mask}]}
|
|
bind $topwin <Control-Alt-KeyPress> {xschem callback %W %T %x %y %N 0 0 [expr {$ControlMask + $Mod1Mask}]}
|
|
bind $topwin <Shift-Alt-KeyPress> {xschem callback %W %T %x %y %N 0 0 [expr {$ShiftMask + $Mod1Mask}]}
|
|
bind $topwin <MouseWheel> {
|
|
if {%D<0} {
|
|
xschem callback %W 4 %x %y 0 5 0 %s
|
|
} else {
|
|
xschem callback %W 4 %x %y 0 4 0 %s
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
## this function sets up all tk windows and binds X events. It is executed by xinit.c after completing
|
|
## all X initialization. This avoids race conditions.
|
|
## In previous flow xschem.tcl was setting up windows and events before X initialization was completed by xinit.c.
|
|
## this could lead to crashes on some (may be slow) systems due to Configure/Expose events being delivered
|
|
## before xschem being ready to handle them.
|
|
proc pack_widgets { { topwin {} } } {
|
|
global env has_x OS tabbed_interface toolbar_visible toolbar_horiz
|
|
# puts "pack_widgets: $topwin"
|
|
if {($OS== "Windows" || [string length [lindex [array get env DISPLAY] 1] ] > 0 ) && [info exists has_x]} {
|
|
pack $topwin.statusbar.2 -side left
|
|
pack $topwin.statusbar.3 -side left
|
|
pack $topwin.statusbar.4 -side left
|
|
pack $topwin.statusbar.5 -side left
|
|
pack $topwin.statusbar.6 -side left
|
|
pack $topwin.statusbar.7 -side left
|
|
pack $topwin.statusbar.8 -side left
|
|
pack $topwin.statusbar.1 -side left -fill x
|
|
pack $topwin.menubar -side top -fill x
|
|
pack $topwin.statusbar -side bottom -fill x
|
|
pack $topwin.drw -side right -fill both -expand true
|
|
setup_tabbed_interface
|
|
if {$toolbar_visible} {toolbar_show $topwin}
|
|
|
|
bind $topwin.statusbar.5 <Leave> \
|
|
"focus $topwin.drw; set cadgrid \[$topwin.statusbar.5 get\]; xschem set cadgrid \$cadgrid"
|
|
bind $topwin.statusbar.3 <Leave> \
|
|
"focus $topwin.drw; set cadsnap \[$topwin.statusbar.3 get\]; xschem set cadsnap \$cadsnap"
|
|
}
|
|
if {$topwin ne {}} {
|
|
$topwin.menubar.view.menu entryconfigure {Tabbed interface} -state disabled
|
|
}
|
|
}
|
|
|
|
# if undo_type == disk save undo to disk
|
|
# if undo_type == memory keep undo in memory
|
|
# In memory undo is faster but in case of crashes nothing can be recovered
|
|
# On disk undo is slower but can be used to recover state just before a crash
|
|
proc switch_undo {} {
|
|
global undo_type
|
|
if { $undo_type eq {memory} } {
|
|
set res [tk_messageBox -type yesno -parent [xschem get topwindow] \
|
|
-message {Ok to keep undo in memory? Undo will be reset.\
|
|
Memory undo is faster but in case of crashes nothing can be recovered.}]
|
|
if {$res eq {yes} } {
|
|
xschem undo_type $undo_type
|
|
} else {
|
|
set undo_type disk
|
|
}
|
|
} else { ;# disk
|
|
set res [tk_messageBox -type yesno -parent [xschem get topwindow] \
|
|
-message {Ok to save undo on disk? Undo will be reset.\
|
|
Disk undo is slower but in case of crashes previous state can be recovered.}]
|
|
if {$res eq {yes} } {
|
|
xschem undo_type $undo_type
|
|
} else {
|
|
set undo_type memory
|
|
}
|
|
}
|
|
}
|
|
|
|
proc build_widgets { {topwin {} } } {
|
|
global XSCHEM_SHAREDIR tabbed_interface simulate_bg
|
|
global colors recentfile color_ps transparent_svg menu_debug_var enable_stretch
|
|
global netlist_show flat_netlist split_files tmp_bus_char
|
|
global draw_grid big_grid_points sym_txt change_lw incr_hilight symbol_width
|
|
global cadgrid draw_window show_pin_net_names toolbar_visible hide_symbols undo_type
|
|
global disable_unique_names persistent_command autotrim_wires en_hilight_conn_inst
|
|
global local_netlist_dir editor netlist_type netlist_dir spiceprefix initial_geometry
|
|
set mbg {}
|
|
set bbg {-highlightthickness 0}
|
|
if { $topwin ne {}} {
|
|
set mbg {-bg gray50}
|
|
set bbg {-bg gray50 -highlightthickness 0}
|
|
}
|
|
eval frame $topwin.menubar -relief raised -bd 2 $mbg
|
|
eval menubutton $topwin.menubar.file -text "File" -menu $topwin.menubar.file.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.file.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.edit -text "Edit" -menu $topwin.menubar.edit.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.edit.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.option -text "Options" -menu $topwin.menubar.option.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.option.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.view -text "View" -menu $topwin.menubar.view.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.view.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.prop -text "Properties" -menu $topwin.menubar.prop.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.prop.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.layers -text "Layers" -menu $topwin.menubar.layers.menu \
|
|
-padx 3 -pady 0 -background [lindex $colors 4]
|
|
menu $topwin.menubar.layers.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.tools -text "Tools" -menu $topwin.menubar.tools.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.tools.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.sym -text "Symbol" -menu $topwin.menubar.sym.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.sym.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.hilight -text "Highlight" -menu $topwin.menubar.hilight.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.hilight.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.simulation -text "Simulation" -menu $topwin.menubar.simulation.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.simulation.menu -tearoff 0
|
|
eval menubutton $topwin.menubar.help -text "Help" -menu $topwin.menubar.help.menu \
|
|
-padx 3 -pady 0 $mbg
|
|
menu $topwin.menubar.help.menu -tearoff 0
|
|
$topwin.menubar.help.menu add command -label "Help" -command "textwindow \"${XSCHEM_SHAREDIR}/xschem.help\" ro" \
|
|
-accelerator {?}
|
|
$topwin.menubar.help.menu add command -label "Keys" -command "textwindow \"${XSCHEM_SHAREDIR}/keys.help\" ro"
|
|
$topwin.menubar.help.menu add command -label "About XSCHEM" -command "about"
|
|
|
|
$topwin.menubar.file.menu add command -label "New Schematic" -accelerator Ctrl+N\
|
|
-command {
|
|
xschem clear SCHEMATIC
|
|
}
|
|
# toolbar_add FileNew {xschem clear SCHEMATIC} "New Schematic" $topwin
|
|
$topwin.menubar.file.menu add command -label "New Symbol" -accelerator Ctrl+Shift+N \
|
|
-command {
|
|
xschem clear SYMBOL
|
|
}
|
|
# toolbar_add FileNewSym {xschem clear SYMBOL} "New Symbol" $topwin
|
|
$topwin.menubar.file.menu add command -label "New empty Schematic window" -accelerator {Alt+N} \
|
|
-command {
|
|
xschem new_window
|
|
}
|
|
$topwin.menubar.file.menu add command -label "New empty Symbol window" -accelerator {Alt+Shift+N} \
|
|
-command {
|
|
xschem new_symbol_window
|
|
}
|
|
$topwin.menubar.file.menu add command -label "Component browser" -accelerator {Shift-Ins, Ctrl-I} \
|
|
-command {
|
|
load_file_dialog {Insert symbol} *.sym INITIALINSTDIR 2
|
|
}
|
|
$topwin.menubar.file.menu add command -label "Open" -command "xschem load" -accelerator {Ctrl+O}
|
|
$topwin.menubar.file.menu add cascade -label "Open recent" -menu $topwin.menubar.file.menu.recent
|
|
$topwin.menubar.file.menu add cascade -label {Open recent in new window} \
|
|
-menu $topwin.menubar.file.menu.recent_new_window
|
|
menu $topwin.menubar.file.menu.recent_new_window -tearoff 0
|
|
menu $topwin.menubar.file.menu.recent -tearoff 0
|
|
setup_recent_menu 0 $topwin
|
|
setup_recent_menu 1 $topwin
|
|
$topwin.menubar.file.menu add command -label {Open new window} -command "xschem load_new_window"
|
|
if {$tabbed_interface} {
|
|
$topwin.menubar.file.menu entryconfigure {Open new window} -state disabled
|
|
$topwin.menubar.file.menu entryconfigure {Open recent in new window} -state disabled
|
|
}
|
|
toolbar_add FileOpen "xschem load" "Open File" $topwin
|
|
$topwin.menubar.file.menu add command -label "Delete files" -command "xschem delete_files" -accelerator {Shift-D}
|
|
|
|
$topwin.menubar.file.menu add command -label "Open Most Recent" \
|
|
-command {xschem load [lindex "$recentfile" 0]} -accelerator {Ctrl+Shift+O}
|
|
$topwin.menubar.file.menu add command -label "Save" -command "xschem save" -accelerator {Ctrl+S}
|
|
toolbar_add FileSave "xschem save" "Save File" $topwin
|
|
$topwin.menubar.file.menu add command -label "Merge" -command "xschem merge" -accelerator {Shift+B}
|
|
# toolbar_add FileMerge "xschem merge" "Merge File" $topwin
|
|
$topwin.menubar.file.menu add command -label "Reload" -accelerator {Alt+S} \
|
|
-command {
|
|
if { [string compare [tk_messageBox -type okcancel -parent [xschem get topwindow] \
|
|
-message {Are you sure you want to reload?}] ok]==0 } {
|
|
xschem reload
|
|
}
|
|
}
|
|
toolbar_add FileReload {
|
|
if { [string compare [tk_messageBox -type okcancel -parent [xschem get topwindow] \
|
|
-message {Are you sure you want to reload?}] ok]==0 } {
|
|
xschem reload
|
|
}
|
|
} "Reload File" $topwin
|
|
$topwin.menubar.file.menu add command -label "Save as" -command "xschem saveas" -accelerator {Ctrl+Shift+S}
|
|
$topwin.menubar.file.menu add command -label "Save as symbol" \
|
|
-command "xschem saveas {} SYMBOL" -accelerator {Ctrl+Alt+S}
|
|
# added svg, png 20171022
|
|
$topwin.menubar.file.menu add command -label "PDF/PS Export" -command "xschem print pdf" -accelerator {*}
|
|
$topwin.menubar.file.menu add command -label "Hierarchical PDF/PS Export" -command "xschem hier_psprint"
|
|
$topwin.menubar.file.menu add command -label "PNG Export" -command "xschem print png" -accelerator {Ctrl+*}
|
|
$topwin.menubar.file.menu add command -label "SVG Export" -command "xschem print svg" -accelerator {Alt+*}
|
|
$topwin.menubar.file.menu add separator
|
|
$topwin.menubar.file.menu add command -label "Exit" -accelerator {Ctrl+Q} -command {
|
|
if {[xschem get current_win_path] eq {.drw} } {
|
|
xschem exit
|
|
} else {
|
|
xschem new_schematic destroy [xschem get current_win_path] {}
|
|
}
|
|
}
|
|
$topwin.menubar.option.menu add checkbutton -label "Color Postscript/SVG" -variable color_ps \
|
|
-command {
|
|
if { $color_ps==1 } {xschem set color_ps 1} else { xschem set color_ps 0}
|
|
}
|
|
$topwin.menubar.option.menu add checkbutton -label "Transparent SVG background" -variable transparent_svg
|
|
$topwin.menubar.option.menu add checkbutton -label "Debug mode" -variable menu_debug_var \
|
|
-command {
|
|
if { $menu_debug_var==1 } {xschem debug 1} else { xschem debug 0}
|
|
}
|
|
$topwin.menubar.option.menu add checkbutton -label "Undo buffer on Disk" -variable undo_type \
|
|
-onvalue disk -offvalue memory -command {switch_undo}
|
|
$topwin.menubar.option.menu add checkbutton -label "Enable stretch" -variable enable_stretch \
|
|
-accelerator Y
|
|
$topwin.menubar.option.menu add checkbutton -label "Show netlist win" -variable netlist_show \
|
|
-accelerator {Shift+A}
|
|
$topwin.menubar.option.menu add checkbutton -label "Flat netlist" -variable flat_netlist \
|
|
-accelerator : \
|
|
-command {
|
|
if { $flat_netlist==1 } {xschem set flat_netlist 1} else { xschem set flat_netlist 0}
|
|
}
|
|
$topwin.menubar.option.menu add checkbutton -label "Split netlist" -variable split_files \
|
|
-accelerator {}
|
|
$topwin.menubar.option.menu add command -label "Replace \[ and \] for buses in SPICE netlist" \
|
|
-command {
|
|
input_line "Enter two characters to replace default bus \[\] delimiters:" "set tmp_bus_char"
|
|
if { [info exists tmp_bus_char] && [string length $tmp_bus_char] >=2} {
|
|
set bus_replacement_char $tmp_bus_char
|
|
}
|
|
}
|
|
$topwin.menubar.option.menu add checkbutton -label "Verilog 2001 netlist variant" -variable verilog_2001
|
|
$topwin.menubar.option.menu add checkbutton \
|
|
-label "Group bus slices in Verilog instances" -variable verilog_bitblast
|
|
$topwin.menubar.option.menu add checkbutton -label "Draw grid" -variable draw_grid \
|
|
-accelerator {%} \
|
|
-command {
|
|
xschem redraw
|
|
}
|
|
$topwin.menubar.option.menu add command -label "Half Snap Threshold" -accelerator G -command {
|
|
xschem set cadsnap [expr {[xschem get cadsnap] / 2.0} ]
|
|
}
|
|
$topwin.menubar.option.menu add command -label "Double Snap Threshold" -accelerator Shift-G -command {
|
|
xschem set cadsnap [expr {[xschem get cadsnap] * 2.0} ]
|
|
}
|
|
$topwin.menubar.option.menu add checkbutton -label "Variable grid point size" -variable big_grid_points \
|
|
-command { xschem redraw }
|
|
$topwin.menubar.option.menu add command -label "Set symbol width" \
|
|
-command {
|
|
input_line "Enter Symbol width ($symbol_width)" "set symbol_width" $symbol_width
|
|
}
|
|
$topwin.menubar.option.menu add checkbutton -label "Show net names on symbol pins" -variable show_pin_net_names \
|
|
-command {
|
|
xschem show_pin_net_names
|
|
xschem redraw
|
|
}
|
|
$topwin.menubar.option.menu add separator
|
|
$topwin.menubar.option.menu add radiobutton -label "Spice netlist" -variable netlist_type -value spice \
|
|
-accelerator {Shift+V} \
|
|
-command "xschem set netlist_type spice"
|
|
$topwin.menubar.option.menu add radiobutton -label "VHDL netlist" -variable netlist_type -value vhdl \
|
|
-accelerator {Shift+V} \
|
|
-command "xschem set netlist_type vhdl"
|
|
$topwin.menubar.option.menu add radiobutton -label "Verilog netlist" -variable netlist_type -value verilog \
|
|
-accelerator {Shift+V} \
|
|
-command "xschem set netlist_type verilog"
|
|
$topwin.menubar.option.menu add radiobutton -label "tEDAx netlist" -variable netlist_type -value tedax \
|
|
-accelerator {Shift+V} \
|
|
-command "xschem set netlist_type tedax"
|
|
$topwin.menubar.option.menu add radiobutton -label "Symbol global attrs" -variable netlist_type -value symbol \
|
|
-accelerator {Shift+V} \
|
|
-command "xschem set netlist_type symbol"
|
|
$topwin.menubar.edit.menu add command -label "Undo" -command "xschem undo; xschem redraw" -accelerator U
|
|
toolbar_add EditUndo "xschem undo; xschem redraw" "Undo" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Redo" -command "xschem redo; xschem redraw" -accelerator {Shift+U}
|
|
toolbar_add EditRedo "xschem redo; xschem redraw" "Redo" $topwin
|
|
toolbar_add EditCut "xschem cut" "Cut" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Copy" -command "xschem copy" -accelerator Ctrl+C
|
|
toolbar_add EditCopy "xschem copy" "Copy" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Cut" -command "xschem cut" -accelerator Ctrl+X
|
|
$topwin.menubar.edit.menu add command -label "Paste" -command "xschem paste" -accelerator Ctrl+V
|
|
toolbar_add EditPaste "xschem paste" "Paste" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Delete" -command "xschem delete" -accelerator Del
|
|
toolbar_add EditDelete "xschem delete" "Delete" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Select all" -command "xschem select_all" -accelerator Ctrl+A
|
|
$topwin.menubar.edit.menu add command -label "Edit schematic in new window/tab" \
|
|
-command "xschem schematic_in_new_window" -accelerator Alt+E
|
|
$topwin.menubar.edit.menu add command -label "Edit symbol in new window/tab" \
|
|
-command "xschem symbol_in_new_window" -accelerator Alt+I
|
|
$topwin.menubar.edit.menu add command -label "Duplicate objects" -command "xschem copy_objects" -accelerator C
|
|
toolbar_add EditDuplicate "xschem copy_objects" "Duplicate objects" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Move objects" -command "xschem move_objects" -accelerator M
|
|
toolbar_add EditMove "xschem move_objects" "Move objects" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Flip selected objects" -command "xschem flip" -accelerator {Alt-F}
|
|
$topwin.menubar.edit.menu add command -label "Rotate selected objects" -command "xschem rotate" -accelerator {Alt-R}
|
|
$topwin.menubar.edit.menu add radiobutton -label "Unconstrained move" -variable constrained_move \
|
|
-value 0 -command {xschem set constrained_move 0}
|
|
$topwin.menubar.edit.menu add radiobutton -label "Constrained Horizontal move" -variable constrained_move \
|
|
-value 1 -accelerator H -command {xschem set constrained_move 1}
|
|
$topwin.menubar.edit.menu add radiobutton -label "Constrained Vertical move" -variable constrained_move \
|
|
-value 2 -accelerator V -command {xschem set constrained_move 2}
|
|
$topwin.menubar.edit.menu add checkbutton -label "Add wire when separating pins" -variable connect_by_kissing
|
|
$topwin.menubar.edit.menu add command -label "Push schematic" -command "xschem descend" -accelerator E
|
|
toolbar_add EditPushSch "xschem descend" "Push schematic" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Push symbol" -command "xschem descend_symbol" -accelerator I
|
|
toolbar_add EditPushSym "xschem descend_symbol" "Push symbol" $topwin
|
|
$topwin.menubar.edit.menu add command -label "Pop" -command "xschem go_back" -accelerator Ctrl+E
|
|
toolbar_add EditPop "xschem go_back" "Pop" $topwin
|
|
eval button $topwin.menubar.waves -text "Waves" -activebackground red -takefocus 0 \
|
|
-padx 2 -pady 0 -command waves $bbg
|
|
eval button $topwin.menubar.simulate -text "Simulate" -activebackground red -takefocus 0 \
|
|
-padx 2 -pady 0 -command \{simulate_button $topwin.menubar.simulate\} $bbg
|
|
set simulate_bg [$topwin.menubar.simulate cget -bg]
|
|
eval button $topwin.menubar.netlist -text "Netlist" -activebackground red -takefocus 0 \
|
|
-padx 2 -pady 0 -command \{xschem netlist\} $bbg
|
|
# create $topwin.menubar.layers.menu
|
|
create_layers_menu $topwin
|
|
$topwin.menubar.view.menu add checkbutton -label "Show ERC Info window" -variable show_infowindow \
|
|
-command {
|
|
if { $show_infowindow != 0 } {wm deiconify .infotext
|
|
} else {wm withdraw .infotext}
|
|
}
|
|
$topwin.menubar.view.menu add command -label "Redraw" -command "xschem redraw" -accelerator Esc
|
|
toolbar_add ViewRedraw "xschem redraw" "Redraw" $topwin
|
|
$topwin.menubar.view.menu add command -label "Fullscreen" \
|
|
-accelerator "\\" -command "
|
|
if {\$fullscreen == 1} {set fullscreen 2} ;# avoid hiding menu in true fullscreen
|
|
xschem fullscreen $topwin.drw
|
|
"
|
|
$topwin.menubar.view.menu add command -label "Zoom Full" -command "xschem zoom_full" -accelerator F
|
|
$topwin.menubar.view.menu add command -label "Zoom In" -command "xschem zoom_in" -accelerator Shift+Z
|
|
# toolbar_add ViewZoomIn "xschem zoom_in" "Zoom In" $topwin
|
|
$topwin.menubar.view.menu add command -label "Zoom Out" -command "xschem zoom_out" -accelerator Ctrl+Z
|
|
# toolbar_add ViewZoomOut "xschem zoom_out" "Zoom Out" $topwin
|
|
$topwin.menubar.view.menu add command -label "Zoom box" -command "xschem zoom_box" -accelerator Z
|
|
# toolbar_add ViewZoomBox "xschem zoom_box" "Zoom Box" $topwin
|
|
$topwin.menubar.view.menu add command -label "Set snap value" \
|
|
-command {
|
|
input_line "Enter snap value ( default: [xschem get cadsnap_default] current: [xschem get cadsnap])" \
|
|
"xschem set cadsnap" [xschem get cadsnap]
|
|
}
|
|
$topwin.menubar.view.menu add command -label "Set grid spacing" \
|
|
-command {
|
|
input_line "Enter grid spacing (float):" "xschem set cadgrid" $cadgrid
|
|
}
|
|
$topwin.menubar.view.menu add checkbutton -label "View only Probes" -variable only_probes \
|
|
-accelerator {5} \
|
|
-command { xschem only_probes }
|
|
$topwin.menubar.view.menu add command -label "Toggle colorscheme" -accelerator {Shift+O} -command {
|
|
xschem toggle_colorscheme
|
|
xschem build_colors 1
|
|
xschem redraw
|
|
}
|
|
toolbar_add ViewToggleColors {
|
|
xschem toggle_colorscheme
|
|
xschem build_colors 1
|
|
xschem redraw
|
|
} "Toggle Color Scheme" $topwin
|
|
$topwin.menubar.view.menu add command -label "Dim colors" -accelerator {} -command {
|
|
color_dim
|
|
}
|
|
$topwin.menubar.view.menu add command -label "Visible layers" -accelerator {} -command {
|
|
select_layers
|
|
xschem redraw
|
|
}
|
|
$topwin.menubar.view.menu add checkbutton -label "Show hidden texts" -variable show_hidden_texts \
|
|
-command {xschem redraw}
|
|
$topwin.menubar.view.menu add command -label "Change current layer color" -accelerator {} -command {
|
|
change_color
|
|
}
|
|
$topwin.menubar.view.menu add command -label "Reset all colors to default" \
|
|
-accelerator {} -command {
|
|
reset_colors 1
|
|
}
|
|
$topwin.menubar.view.menu add checkbutton -label "No XCopyArea drawing model" -variable draw_window \
|
|
-accelerator {Ctrl+$} \
|
|
-command {
|
|
if { $draw_window == 1} { xschem set draw_window 1} else { xschem set draw_window 0}
|
|
}
|
|
$topwin.menubar.view.menu add checkbutton -label "Symbol text" -variable sym_txt \
|
|
-accelerator {Ctrl+B} -command { xschem set sym_txt $sym_txt; xschem redraw }
|
|
$topwin.menubar.view.menu add checkbutton -label "Toggle variable line width" -variable change_lw \
|
|
-accelerator {_}
|
|
$topwin.menubar.view.menu add command -label "Set line width" \
|
|
-command {
|
|
input_line "Enter linewidth (float):" "xschem line_width"
|
|
}
|
|
$topwin.menubar.view.menu add checkbutton -label "Show Toolbar" -variable toolbar_visible \
|
|
-command "
|
|
if { \$toolbar_visible } \" toolbar_show $topwin\" else \"toolbar_hide $topwin\"
|
|
"
|
|
$topwin.menubar.view.menu add checkbutton -label "Horizontal Toolbar" -variable toolbar_horiz \
|
|
-command "
|
|
if { \$toolbar_visible } \" toolbar_hide $topwin; toolbar_show $topwin \"
|
|
"
|
|
$topwin.menubar.view.menu add checkbutton -label "Tabbed interface" -variable tabbed_interface \
|
|
-command setup_tabbed_interface
|
|
$topwin.menubar.prop.menu add command -label "Edit" -command "xschem edit_prop" -accelerator Q
|
|
$topwin.menubar.prop.menu add command -label "Edit with editor" -command "xschem edit_vi_prop" -accelerator Shift+Q
|
|
$topwin.menubar.prop.menu add command -label "View" -command "xschem view_prop" -accelerator Ctrl+Shift+Q
|
|
$topwin.menubar.prop.menu add command -background red -label "Edit file (danger!)" \
|
|
-command "xschem edit_file" -accelerator Alt+Q
|
|
$topwin.menubar.sym.menu add radiobutton -label "Show Symbols" \
|
|
-variable hide_symbols -value 0 \
|
|
-command {xschem set hide_symbols $hide_symbols; xschem redraw} -accelerator Alt+B
|
|
$topwin.menubar.sym.menu add radiobutton -label "Show instance Bounding boxes for subcircuit symbols" \
|
|
-variable hide_symbols -value 1 \
|
|
-command {xschem set hide_symbols $hide_symbols; xschem redraw} -accelerator Alt+B
|
|
$topwin.menubar.sym.menu add radiobutton -label "Show instance Bounding boxes for all symbols" \
|
|
-variable hide_symbols -value 2 \
|
|
-command {xschem set hide_symbols $hide_symbols; xschem redraw} -accelerator Alt+B
|
|
$topwin.menubar.sym.menu add command -label "Make symbol from schematic" -command "xschem make_symbol" -accelerator A
|
|
$topwin.menubar.sym.menu add command -label "Make schematic from symbol" -command "xschem make_sch" -accelerator Ctrl+L
|
|
$topwin.menubar.sym.menu add command -label "Make schematic and symbol from selected components" \
|
|
-command "xschem make_sch_from_sel" -accelerator Ctrl+Shift+H
|
|
$topwin.menubar.sym.menu add command -label "Attach net labels to component instance" \
|
|
-command "xschem attach_labels" -accelerator Shift+H
|
|
$topwin.menubar.sym.menu add command -label "Create symbol pins from selected schematic pins" \
|
|
-command "schpins_to_sympins" -accelerator Alt+H
|
|
$topwin.menubar.sym.menu add command -label "Place symbol pin" \
|
|
-command "xschem add_symbol_pin" -accelerator Alt+P
|
|
$topwin.menubar.sym.menu add command -label "Print list of highlight nets" \
|
|
-command "xschem print_hilight_net 1" -accelerator J
|
|
$topwin.menubar.sym.menu add command -label "Print list of highlight nets, with buses expanded" \
|
|
-command "xschem print_hilight_net 3" -accelerator Alt-Ctrl-J
|
|
$topwin.menubar.sym.menu add command -label "Create labels from highlight nets" \
|
|
-command "xschem print_hilight_net 4" -accelerator Alt-J
|
|
$topwin.menubar.sym.menu add command -label "Create labels from highlight nets with 'i' prefix" \
|
|
-command "xschem print_hilight_net 2" -accelerator Alt-Shift-J
|
|
$topwin.menubar.sym.menu add command -label "Create pins from highlight nets" \
|
|
-command "xschem print_hilight_net 0" -accelerator Ctrl-J
|
|
$topwin.menubar.sym.menu add checkbutton \
|
|
-label "Search all search-paths for schematic associated to symbol" -variable search_schematic
|
|
$topwin.menubar.sym.menu add checkbutton -label "Allow duplicated instance names (refdes)" \
|
|
-variable disable_unique_names
|
|
$topwin.menubar.tools.menu add checkbutton -label "Remember last command" -variable persistent_command
|
|
$topwin.menubar.tools.menu add command -label "Insert symbol" -command "xschem place_symbol" -accelerator {Ins, Shift-I}
|
|
toolbar_add ToolInsertSymbol "xschem place_symbol" "Insert Symbol" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert wire label" -command "xschem net_label 1" -accelerator {Alt-L}
|
|
$topwin.menubar.tools.menu add command -label "Insert wire label 2" -command "xschem net_label 0" \
|
|
-accelerator {Alt-Shift-L}
|
|
$topwin.menubar.tools.menu add command -label "Insert text" -command "xschem place_text" -accelerator T
|
|
toolbar_add ToolInsertText "xschem place_text" "Insert Text" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert wire" -command "xschem wire" -accelerator W
|
|
toolbar_add ToolInsertWire "xschem wire" "Insert Wire" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert snap wire" -command "xschem snap_wire" -accelerator Shift+W
|
|
$topwin.menubar.tools.menu add command -label "Insert line" -command "xschem line" -accelerator L
|
|
toolbar_add ToolInsertLine "xschem line" "Insert Line" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert rect" -command "xschem rect" -accelerator R
|
|
toolbar_add ToolInsertRect "xschem rect" "Insert Rectangle" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert polygon" -command "xschem polygon" -accelerator Ctrl+W
|
|
toolbar_add ToolInsertPolygon "xschem polygon" "Insert Polygon" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert arc" -command "xschem arc" -accelerator Shift+C
|
|
toolbar_add ToolInsertArc "xschem arc" "Insert Arc" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert circle" -command "xschem circle" -accelerator Ctrl+Shift+C
|
|
toolbar_add ToolInsertCircle "xschem circle" "Insert Circle" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Insert PNG image" -command "xschem add_png"
|
|
$topwin.menubar.tools.menu add command -label "Search" -accelerator Ctrl+F -command property_search
|
|
toolbar_add ToolSearch property_search "Search" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Align to Grid" -accelerator Alt+U -command "xschem align"
|
|
$topwin.menubar.tools.menu add command -label "Execute TCL command" -command "tclcmd"
|
|
$topwin.menubar.tools.menu add command -label "Join/Trim wires" \
|
|
-command "xschem trim_wires" -accelerator {&}
|
|
toolbar_add ToolJoinTrim "xschem trim_wires" "Join/Trim Wires" $topwin
|
|
$topwin.menubar.tools.menu add command -label "Break wires at selected instance pins" \
|
|
-command "xschem break_wires" -accelerator {!}
|
|
toolbar_add ToolBreak "xschem break_wires" "Break wires at selected\ninstance pin intersections" $topwin
|
|
$topwin.menubar.tools.menu add checkbutton -label "Auto Join/Trim Wires" -variable autotrim_wires \
|
|
-command {
|
|
if {$autotrim_wires == 1} {
|
|
xschem trim_wires
|
|
xschem redraw
|
|
}
|
|
}
|
|
$topwin.menubar.tools.menu add command -label "Select all connected wires/labels/pins" \
|
|
-accelerator {Shift-Right Butt.} \
|
|
-command { xschem connected_nets}
|
|
$topwin.menubar.tools.menu add command -label "Select conn. wires, stop at junctions" \
|
|
-accelerator {Ctrl-Righ Butt.} -command { xschem connected_nets 1 }
|
|
|
|
$topwin.menubar.hilight.menu add command \
|
|
-label {Set schematic to compare and compare with} \
|
|
-command "xschem compare_schematics"
|
|
$topwin.menubar.hilight.menu add command \
|
|
-label {Compare schematics} \
|
|
-command "xschem compare_schematics {}" \
|
|
-accelerator {Alt-X}
|
|
$topwin.menubar.hilight.menu add command \
|
|
-label {Highlight net-pin name mismatches on selected instances} \
|
|
-command "xschem net_pin_mismatch" \
|
|
-accelerator {Shift-X}
|
|
$topwin.menubar.hilight.menu add command -label {Highlight duplicate instance names} \
|
|
-command "xschem check_unique_names 0" -accelerator {#}
|
|
$topwin.menubar.hilight.menu add command -label {Rename duplicate instance names} \
|
|
-command "xschem check_unique_names 1" -accelerator {Ctrl+#}
|
|
$topwin.menubar.hilight.menu add command -label {Select overlapped instances} \
|
|
-command "xschem warning_overlapped_symbols 1; xschem redraw" -accelerator {}
|
|
$topwin.menubar.hilight.menu add command -label {Propagate Highlight selected net/pins} \
|
|
-command "xschem hilight drill" -accelerator {Ctrl+Shift+K}
|
|
$topwin.menubar.hilight.menu add checkbutton -label "Increment Hilight Color" -variable incr_hilight
|
|
$topwin.menubar.hilight.menu add command -label {Highlight selected net/pins} \
|
|
-command "xschem hilight" -accelerator K
|
|
$topwin.menubar.hilight.menu add command -label {Send selected net/pins to Viewer} \
|
|
-command "xschem send_to_viewer" -accelerator Alt+G
|
|
$topwin.menubar.hilight.menu add command -label {Select hilight nets / pins} \
|
|
-command "xschem select_hilight_net" \
|
|
-accelerator Alt+K
|
|
$topwin.menubar.hilight.menu add command -label {Un-highlight all net/pins} \
|
|
-command "xschem unhilight_all" -accelerator Shift+K
|
|
$topwin.menubar.hilight.menu add command -label {Un-highlight selected net/pins} \
|
|
-command "xschem unhilight" -accelerator Ctrl+K
|
|
# 20160413
|
|
$topwin.menubar.hilight.menu add checkbutton -label {Auto-highlight net/pins} -variable auto_hilight
|
|
$topwin.menubar.hilight.menu add checkbutton -label {Enable highlight connected instances} \
|
|
-variable en_hilight_conn_inst
|
|
|
|
$topwin.menubar.simulation.menu add command -label "Set netlist Dir" \
|
|
-command {
|
|
select_netlist_dir 1
|
|
}
|
|
$topwin.menubar.simulation.menu add command -label "Set top level netlist name" \
|
|
-command {
|
|
input_line {Set netlist file name} {xschem set netlist_name} [xschem get netlist_name] 40
|
|
}
|
|
$topwin.menubar.simulation.menu add checkbutton -label "Use 'simulation' dir under current schematic dir" \
|
|
-variable local_netlist_dir \
|
|
-command { if {$local_netlist_dir == 0 } { select_netlist_dir 1 } else { simuldir} }
|
|
$topwin.menubar.simulation.menu add command -label {Configure simulators and tools} -command {simconf}
|
|
$topwin.menubar.simulation.menu add command -label {Utile Stimuli Editor (GUI)} -command {
|
|
simuldir
|
|
inutile [xschem get current_dirname]/stimuli.[file rootname [file tail [xschem get schname]]]
|
|
}
|
|
$topwin.menubar.simulation.menu add command -label {Utile Stimuli Translate} -command {
|
|
simuldir
|
|
inutile_translate [xschem get current_dirname]/stimuli.[file rootname [file tail [xschem get schname]]]
|
|
}
|
|
$topwin.menubar.simulation.menu add command -label {Shell [simulation path]} -command {
|
|
if { [select_netlist_dir 0] ne "" } {
|
|
get_shell $netlist_dir
|
|
}
|
|
}
|
|
$topwin.menubar.simulation.menu add command -label {Edit Netlist} \
|
|
-command {edit_netlist [xschem get netlist_name fallback]}
|
|
$topwin.menubar.simulation.menu add command -label {Send highlighted nets to viewer} \
|
|
-command {xschem create_plot_cmd} -accelerator Shift+J
|
|
$topwin.menubar.simulation.menu add checkbutton -label "Hide graphs if no spice data loaded" \
|
|
-variable hide_empty_graphs -command {xschem redraw}
|
|
$topwin.menubar.simulation.menu add checkbutton -variable rawfile_loaded \
|
|
-label {Load/Unload spice .raw file} -command {
|
|
xschem raw_read $netlist_dir/[file tail [file rootname [xschem get current_name]]].raw
|
|
}
|
|
$topwin.menubar.simulation.menu add command -label {Add waveform graph} -command {xschem add_graph}
|
|
$topwin.menubar.simulation.menu add checkbutton -label "Live annotate probes with 'b' cursor" \
|
|
-variable live_cursor2_backannotate
|
|
$topwin.menubar.simulation.menu add command -label "Annotate Operating Point into schematic" \
|
|
-command {set show_hidden_texts 1; xschem annotate_op}
|
|
$topwin.menubar.simulation.menu add separator
|
|
$topwin.menubar.simulation.menu add checkbutton -label "LVS netlist: Top level is a .subckt" -variable top_subckt
|
|
$topwin.menubar.simulation.menu add checkbutton -label "Use 'spiceprefix' attribute" -variable spiceprefix \
|
|
-command {xschem save; xschem reload}
|
|
|
|
toolbar_add Netlist { xschem netlist } "Create netlist" $topwin
|
|
toolbar_add Simulate "simulate_button $topwin.menubar.simulate" "Run simulation" $topwin
|
|
toolbar_add Waves { waves } "View results" $topwin
|
|
|
|
pack $topwin.menubar.file -side left
|
|
pack $topwin.menubar.edit -side left
|
|
pack $topwin.menubar.option -side left
|
|
pack $topwin.menubar.view -side left
|
|
pack $topwin.menubar.prop -side left
|
|
pack $topwin.menubar.layers -side left
|
|
pack $topwin.menubar.tools -side left
|
|
pack $topwin.menubar.sym -side left
|
|
pack $topwin.menubar.hilight -side left
|
|
pack $topwin.menubar.simulation -side left
|
|
pack $topwin.menubar.help -side right
|
|
pack $topwin.menubar.waves -side right
|
|
pack $topwin.menubar.simulate -side right
|
|
pack $topwin.menubar.netlist -side right
|
|
# used to check status of Simulate button later. This variable is constant, never changed
|
|
frame $topwin.drw -background {} -takefocus 1
|
|
|
|
focus $topwin.drw
|
|
if { $topwin == {} } {set rootwin .} else { set rootwin $topwin}
|
|
wm title $rootwin "xschem - "
|
|
wm iconname $rootwin "xschem - "
|
|
$rootwin configure -background {}
|
|
wm geometry $rootwin $initial_geometry
|
|
#wm maxsize . 1600 1200
|
|
if {$tabbed_interface && $rootwin eq {.}} {
|
|
wm protocol $rootwin WM_DELETE_WINDOW {
|
|
if { [xschem get current_win_path] eq {.drw} } {
|
|
xschem exit
|
|
} else {
|
|
xschem new_schematic destroy [xschem get current_win_path] {}
|
|
}
|
|
}
|
|
} elseif { $rootwin == {.}} {
|
|
wm protocol $rootwin WM_DELETE_WINDOW {
|
|
set old [xschem get current_win_path]
|
|
save_ctx $old
|
|
restore_ctx .drw
|
|
housekeeping_ctx
|
|
xschem new_schematic switch_win .drw
|
|
xschem exit
|
|
# did not exit ... switch back
|
|
restore_ctx $old
|
|
housekeeping_ctx
|
|
xschem new_schematic switch_win $old
|
|
}
|
|
} else {
|
|
wm protocol $rootwin WM_DELETE_WINDOW "xschem new_schematic destroy $topwin.drw {}"
|
|
}
|
|
|
|
frame $topwin.statusbar
|
|
label $topwin.statusbar.1 -text "STATUS BAR 1"
|
|
label $topwin.statusbar.2 -text "SNAP:"
|
|
entry $topwin.statusbar.3 -relief sunken -bg white \
|
|
-width 10 -foreground black -takefocus 0
|
|
label $topwin.statusbar.4 -text "GRID:"
|
|
entry $topwin.statusbar.5 -relief sunken -bg white \
|
|
-width 10 -foreground black -takefocus 0
|
|
label $topwin.statusbar.6 -text "NETLIST MODE:"
|
|
label $topwin.statusbar.7 -relief sunken -bg white \
|
|
-width 8
|
|
label $topwin.statusbar.8 -activebackground red -text {}
|
|
}
|
|
|
|
proc set_paths {} {
|
|
global XSCHEM_LIBRARY_PATH env pathlist OS
|
|
set pathlist {}
|
|
if { [info exists XSCHEM_LIBRARY_PATH] } {
|
|
if {$OS == "Windows"} {
|
|
set pathlist_orig [split $XSCHEM_LIBRARY_PATH \;]
|
|
} else {
|
|
set pathlist_orig [split $XSCHEM_LIBRARY_PATH :]
|
|
}
|
|
foreach i $pathlist_orig {
|
|
regsub {^~} $i $env(HOME) i
|
|
if { ![string compare $i .] } {
|
|
lappend pathlist $i
|
|
} elseif { [ regexp {\.\.\/} $i] } {
|
|
lappend pathlist [file normalize $i]
|
|
} elseif { [ file exists $i] } {
|
|
lappend pathlist $i
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
proc print_help_and_exit {} {
|
|
global XSCHEM_SHAREDIR
|
|
if { [xschem get help ]} {
|
|
set fd [open "${XSCHEM_SHAREDIR}/xschem.help" r]
|
|
set helpfile [read $fd]
|
|
puts $helpfile
|
|
close $fd
|
|
exit
|
|
}
|
|
}
|
|
|
|
proc set_missing_colors_to_black {} {
|
|
global enable_layer cadlayers svg_colors ps_colors light_colors dark_colors
|
|
## pad missing colors with black
|
|
for {set i 0} { $i<$cadlayers } { incr i} {
|
|
set_ne enable_layer($i) 1
|
|
foreach j { svg_colors ps_colors light_colors dark_colors } {
|
|
if { ![string compare [lindex [set $j] $i] {} ] } {
|
|
if { ![string compare $j {ps_colors} ] || ![string compare $j {svg_colors} ]} {
|
|
lappend $j {0x000000}
|
|
} else {
|
|
lappend $j {#000000}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
foreach i {svg_colors ps_colors light_colors dark_colors} {
|
|
if { [llength [set $i]] > $cadlayers} {
|
|
set $i [lrange [set $i] 0 [expr {$cadlayers -1}]]
|
|
}
|
|
}
|
|
}
|
|
|
|
proc set_initial_dirs {} {
|
|
global INITIALLOADDIR INITIALINSTDIR INITIALPROPDIR pathlist
|
|
set INITIALLOADDIR {}
|
|
set INITIALINSTDIR {}
|
|
set INITIALPROPDIR {}
|
|
foreach i $pathlist {
|
|
if { [file exists $i] } {
|
|
set INITIALLOADDIR $i
|
|
set INITIALINSTDIR $i
|
|
set INITIALPROPDIR $i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
proc create_layers_menu { {topwin {} } } {
|
|
global dark_colorscheme colors
|
|
if { $dark_colorscheme == 1 } { set txt_color black} else { set txt_color white}
|
|
set j 0
|
|
foreach i $colors {
|
|
## 20121121
|
|
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] } { ;# 20161206
|
|
set laylab [format %2d $j]-TEXT
|
|
set layfg $txt_color
|
|
} elseif { $j == [xschem get backlayer] } { ;# 20161206
|
|
set laylab [format %2d $j]-BG
|
|
if { $dark_colorscheme == 1 } {
|
|
set layfg white
|
|
} else {
|
|
set layfg black
|
|
}
|
|
} elseif { $j == [xschem get gridlayer] } { ;# 20161206
|
|
set laylab [format %2d $j]-GRID
|
|
set layfg $txt_color
|
|
} else {
|
|
set laylab "[format %2d $j] "
|
|
set layfg $txt_color
|
|
}
|
|
$topwin.menubar.layers.menu add command -label $laylab -activeforeground $layfg \
|
|
-foreground $layfg -background $i -activebackground $i \
|
|
-command "xschem set rectcolor $j; reconfigure_layers_button $topwin"
|
|
if { [expr {$j%10}] == 0 } { $topwin.menubar.layers.menu entryconfigure $j -columnbreak 1 }
|
|
incr j
|
|
}
|
|
}
|
|
|
|
proc set_replace_key_binding {} {
|
|
global replace_key
|
|
if {[array exists replace_key]} {
|
|
foreach i [array names replace_key] {
|
|
key_binding "$i" "$replace_key($i)"
|
|
}
|
|
}
|
|
}
|
|
|
|
proc source_user_tcl_files {} {
|
|
global tcl_files
|
|
foreach i $tcl_files {
|
|
uplevel #0 "source $i"
|
|
}
|
|
}
|
|
|
|
proc setup_tcp_xschem {} {
|
|
global xschem_listen_port xschem_server_getdata
|
|
if { [info exists xschem_listen_port] && ($xschem_listen_port ne {}) } {
|
|
if {[catch {socket -server xschem_server $xschem_listen_port} err]} {
|
|
puts "setup_tcp_xschem: problems listening to TCP port: $xschem_listen_port"
|
|
puts $err
|
|
return 0
|
|
} else {
|
|
set xschem_server_getdata(server) $err
|
|
}
|
|
}
|
|
return 1
|
|
}
|
|
|
|
proc setup_tcp_bespice {} {
|
|
global bespice_listen_port bespice_server_getdata
|
|
if { [info exists bespice_listen_port] && ($bespice_listen_port ne {}) } {
|
|
if {[catch {socket -server bespice_server $bespice_listen_port} err]} {
|
|
puts "setup_tcp_bespice: problems listening to TCP port: $bespice_listen_port"
|
|
puts $err
|
|
return 0
|
|
} else {
|
|
set bespice_server_getdata(server) $err
|
|
}
|
|
}
|
|
return 1
|
|
}
|
|
|
|
###
|
|
### MAIN PROGRAM
|
|
###
|
|
set OS [lindex $tcl_platform(os) 0]
|
|
set env(LC_ALL) C
|
|
|
|
# tcl variable XSCHEM_LIBRARY_PATH should already be set in xschemrc
|
|
set_paths
|
|
print_help_and_exit
|
|
|
|
# focus the schematic window if mouse goes over it, even if a dialog box is displayed,
|
|
# without needing to click. This allows to move/zoom/pan the schematic while editing attributes.
|
|
set_ne autofocus_mainwindow 1
|
|
if {$OS == "Windows"} {
|
|
set_ne XSCHEM_TMP_DIR [xschem get temp_dir]
|
|
} else {
|
|
set_ne XSCHEM_TMP_DIR {/tmp}
|
|
}
|
|
|
|
# used in C code
|
|
set_ne xschem_libs {}
|
|
set_ne noprint_libs {}
|
|
set_ne debug_var 0
|
|
# used to activate debug from menu
|
|
set_ne menu_debug_var 0
|
|
set textwindow_wcounter 1
|
|
set viewdata_wcounter 1
|
|
set retval ""
|
|
set prev_symbol ""
|
|
set symbol ""
|
|
|
|
# 20100204 flag to enable fix for dialog box positioning, issues with some wm
|
|
set wm_fix 0
|
|
|
|
# 20171010
|
|
set tclcmd_txt {}
|
|
|
|
###
|
|
### user preferences: set default values
|
|
###
|
|
|
|
if { ![info exists dircolor] } {
|
|
set_ne dircolor(/share/xschem/) red
|
|
set_ne dircolor(/share/doc/xschem/) {#338844}
|
|
}
|
|
|
|
set_ne globfilter {*}
|
|
## list of tcl procedures to load at end of xschem.tcl
|
|
set_ne tcl_files {}
|
|
set_ne netlist_dir "$USER_CONF_DIR/simulations"
|
|
# this global exists only for netlist_type radiobuttons, don't use, use [xschem] subcommand to get/set values
|
|
# it is also used in xschemrc to set initial netlist type.
|
|
set_ne netlist_type spice
|
|
set_ne local_netlist_dir 0 ;# if set use <sch_dir>/simulation for netlist and sims
|
|
set_ne bus_replacement_char {} ;# use {<>} to replace [] with <> in bussed signals
|
|
set_ne top_subckt 0
|
|
set_ne hide_empty_graphs 0 ;# if set to 1 waveform boxes will be hidden if no raw file loaded
|
|
set_ne spiceprefix 1
|
|
set_ne verilog_2001 1
|
|
set_ne verilog_bitblast 0
|
|
set_ne search_schematic 0
|
|
set_ne split_files 0
|
|
set_ne flat_netlist 0
|
|
set_ne netlist_show 0
|
|
set_ne color_ps 1
|
|
set_ne transparent_svg 0
|
|
set_ne only_probes 0 ; # 20110112
|
|
set_ne fullscreen 0
|
|
set_ne unzoom_nodrift 0
|
|
set_ne change_lw 1
|
|
set_ne line_width 0
|
|
set_ne live_cursor2_backannotate 0
|
|
set_ne draw_window 0
|
|
set_ne show_hidden_texts 0
|
|
set_ne incr_hilight 1
|
|
set_ne enable_stretch 0
|
|
set_ne constrained_move 0
|
|
set_ne connect_by_kissing 0
|
|
set_ne draw_grid 1
|
|
set_ne big_grid_points 0
|
|
set_ne persistent_command 0
|
|
set_ne autotrim_wires 0
|
|
set_ne disable_unique_names 0
|
|
set_ne sym_txt 1
|
|
set_ne show_infowindow 0
|
|
set_ne symbol_width 150
|
|
set_ne editor {gvim -f}
|
|
set_ne rainbow_colors 0
|
|
set_ne initial_geometry {900x600}
|
|
set_ne edit_symbol_prop_new_sel {}
|
|
set_ne launcher_default_program {xdg-open}
|
|
set_ne auto_hilight 0
|
|
set_ne en_hilight_conn_inst 0
|
|
## xpm to png conversion
|
|
set_ne to_png {gm convert}
|
|
## ps to pdf conversion
|
|
set_ne to_pdf {ps2pdf}
|
|
|
|
# selected graph user is editing attributes with graph GUI
|
|
set_ne graph_bus 0
|
|
set_ne graph_logx 0
|
|
set_ne graph_logy 0
|
|
set_ne graph_selected {}
|
|
set_ne graph_schname {}
|
|
set_ne graph_raw_level -1 ;# hierarchy level where raw file has been loaded
|
|
# user clicked this wave
|
|
set_ne graph_sel_wave {}
|
|
# flag to force simulation stop (Esc key pressed)
|
|
set_ne tclstop 0
|
|
## undo_type: disk or memory
|
|
set_ne undo_type disk
|
|
|
|
## show tab bar (tabbed interface)
|
|
set_ne tabbed_interface 0
|
|
## case insensitive symbol lookup (on case insensitive filesystems only!)
|
|
set_ne case_insensitive 0
|
|
|
|
## remember edit_prop widget size
|
|
set_ne edit_prop_size 80x12
|
|
set_ne text_line_default_geometry 80x12
|
|
set_ne terminal xterm
|
|
|
|
# xschem tcp port number (listen to port and execute commands from there if set)
|
|
# set a port number in xschemrc if you want accept remote connections.
|
|
set_ne xschem_listen_port {}
|
|
|
|
# server for bespice waveform connection (listen to port and send commands to bespice if set)
|
|
# set a port number in xschemrc if you want xschem to be able to cross-probe to bespice
|
|
set_ne bespice_listen_port {}
|
|
|
|
# hide instance details (show only bbox)
|
|
set_ne hide_symbols 0
|
|
# show net names if symbol has attributes like @#n:net_name (where n = pin number or pin name)
|
|
# and net_name=true global attribute set on symbol or instance.
|
|
set_ne show_pin_net_names 0
|
|
# gaw tcp {host port}
|
|
set_ne gaw_tcp_address {localhost 2020}
|
|
|
|
## cairo stuff 20171112
|
|
set_ne cairo_font_scale 1.0
|
|
set_ne nocairo_font_xscale .85
|
|
set_ne nocairo_font_yscale .88
|
|
set_ne cairo_font_line_spacing 1.0
|
|
set_ne cairo_vert_correct 0
|
|
set_ne nocairo_vert_correct 0
|
|
|
|
# Arial, Monospace Sans-Serif; default font to use if unspecified in text elements
|
|
set_ne cairo_font_name {Sans-Serif}
|
|
set_ne svg_font_name {Sans-Serif}
|
|
|
|
# has_cairo set by c program if cairo enabled
|
|
set has_cairo 0
|
|
set rotated_text {} ;#20171208
|
|
set_ne dark_colorscheme 1
|
|
set_ne enable_dim_bg 0
|
|
set_ne dim_bg 0.0
|
|
set_ne dim_value 0.0
|
|
##### set colors
|
|
if {!$rainbow_colors} {
|
|
set_ne cadlayers 22
|
|
## 20171113
|
|
set_ne light_colors {
|
|
"#ffffff" "#0044ee" "#aaaaaa" "#222222" "#229900"
|
|
"#bb2200" "#00ccee" "#ff0000" "#888800" "#00aaaa"
|
|
"#880088" "#00ff00" "#0000cc" "#666600" "#557755"
|
|
"#aa2222" "#7ccc40" "#00ffcc" "#ce0097" "#d2d46b"
|
|
"#ef6158" "#fdb200"}
|
|
set_ne dark_colors {
|
|
"#000000" "#00ccee" "#3f3f3f" "#cccccc" "#88dd00"
|
|
"#bb2200" "#00ccee" "#ff0000" "#ffff00" "#ffffff"
|
|
"#ff00ff" "#00ff00" "#0044dd" "#aaaa00" "#aaccaa"
|
|
"#ff7777" "#bfff81" "#00ffcc" "#ce0097" "#d2d46b"
|
|
"#ef6158" "#fdb200"}
|
|
} else {
|
|
# rainbow colors for bitmapping
|
|
# skip if colors defined in ~/.xschem 20121110
|
|
set_ne cadlayers 35
|
|
#20171113
|
|
set_ne light_colors {
|
|
"#000000" "#00ccee" "#aaaaaa" "#ffffff" "#88dd00"
|
|
"#bb2200" "#0000e0" "#2000e0" "#4000e0" "#6000e0"
|
|
"#8000e0" "#a000e0" "#c000e0" "#e000e0" "#e000c0"
|
|
"#e000a0" "#e00080" "#e00060" "#e00040" "#e00020"
|
|
"#e00000" "#e02000" "#e04000" "#e06000" "#e08000"
|
|
"#e0a000" "#e0c000" "#e0e000" "#e0e020" "#e0e040"
|
|
"#e0e060" "#e0e080" "#e0e0a0" "#e0e0c0" "#e0e0e0"
|
|
}
|
|
set_ne dark_colors {
|
|
"#000000" "#00ccee" "#3f3f3f" "#ffffff" "#88dd00"
|
|
"#bb2200" "#0000e0" "#2000e0" "#4000e0" "#6000e0"
|
|
"#8000e0" "#a000e0" "#c000e0" "#e000e0" "#e000c0"
|
|
"#e000a0" "#e00080" "#e00060" "#e00040" "#e00020"
|
|
"#e00000" "#e02000" "#e04000" "#e06000" "#e08000"
|
|
"#e0a000" "#e0c000" "#e0e000" "#e0e020" "#e0e040"
|
|
"#e0e060" "#e0e080" "#e0e0a0" "#e0e0c0" "#e0e0e0"
|
|
}
|
|
}
|
|
|
|
# for svg and pdf draw 20121108
|
|
regsub -all {"} $dark_colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
regsub -all {"} $light_colors {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
set_missing_colors_to_black
|
|
# read-only vars to store defaults (so we can switch to default colors)
|
|
set dark_colors_save $dark_colors
|
|
set light_colors_save $light_colors
|
|
|
|
set_ne colors $dark_colors
|
|
##### end set colors
|
|
|
|
|
|
# 20111005 added missing initialization of globals...
|
|
set_ne no_change_attrs 0
|
|
set_ne preserve_unchanged_attrs 0
|
|
set search_select 0
|
|
|
|
# 20111106 these vars are overwritten by caller with mktemp file names
|
|
if {$OS == "Windows"} {
|
|
set filetmp $env(windir)/.tmp2
|
|
} else {
|
|
set filetmp [pwd]/.tmp2
|
|
}
|
|
|
|
set rawfile_loaded 0
|
|
|
|
# flag bound to a checkbutton in symbol editprop form
|
|
# if set cell is copied when renaming it
|
|
set_ne copy_cell 0
|
|
|
|
load_recent_file
|
|
# schematic to preload in new windows 20090708
|
|
set_ne XSCHEM_START_WINDOW {}
|
|
|
|
# set INITIALLOADDIR INITIALINSTDIR INITIALPROPDIR as initial locations in load file dialog box
|
|
set_initial_dirs
|
|
|
|
set custom_token {lab}
|
|
set search_value {}
|
|
set search_exact 0
|
|
|
|
# 20171005
|
|
set custom_label_prefix {}
|
|
|
|
###
|
|
### build Tk widgets
|
|
###
|
|
if { ( $OS== "Windows" || [string length [lindex [array get env DISPLAY] 1] ] > 0 ) && [info exists has_x]} {
|
|
setup_toolbar
|
|
# for hyperlink in about dialog
|
|
eval font create Underline-Font [ font actual TkDefaultFont ]
|
|
font configure Underline-Font -underline true -size 24
|
|
. configure -cursor left_ptr
|
|
set_old_tk_fonts ;# for xschem compiled with old tcl-tk libs
|
|
if { [info exists tk_scaling] } {tk scaling $tk_scaling} ;# useful for 4k displays (set bigger widgets)
|
|
set infowindow_text {}
|
|
infowindow
|
|
|
|
build_widgets {}
|
|
|
|
##
|
|
## packing top windows (pack instructions) and event binding (bind instructions) done in proc pack_widgets
|
|
## executed by xinit.c after finalizing X initialization. This avoid potential race conditions
|
|
## like Configure or Expose events being generated before xschem being ready to handle them.
|
|
##
|
|
|
|
# allow user to modify key bindings
|
|
set_replace_key_binding
|
|
|
|
update
|
|
xschem windowid . ;# set icon for window
|
|
} ;# end if {[exists has_x]}
|
|
|
|
# read custom colors
|
|
if { [file exists ${USER_CONF_DIR}/colors] } {
|
|
source ${USER_CONF_DIR}/colors
|
|
}
|
|
|
|
if { [llength $dark_colors] < $cadlayers || [llength $light_colors] < $cadlayers } {
|
|
puts stderr { Warning: wrong number of configured layers in light_colors or dark_colors variables.}
|
|
}
|
|
if { $dark_colorscheme == 1} {
|
|
set colors $dark_colors
|
|
} else {
|
|
set colors $light_colors
|
|
}
|
|
regsub -all {"} $light_colors {} ps_colors
|
|
regsub -all {#} $ps_colors {0x} ps_colors
|
|
regsub -all {"} $colors {} svg_colors
|
|
regsub -all {#} $svg_colors {0x} svg_colors
|
|
|
|
if { $show_infowindow } { wm deiconify .infotext }
|
|
|
|
# xschem listen and bespice listen
|
|
setup_tcp_xschem
|
|
setup_tcp_bespice
|
|
|