#!/usr/bin/tclsh #extend TK package require Tk #sysEnableTk #add font property option add *Dialog.msg.font {Times 12} # ----- User define ------ #script path set script_home "/home/ds11/Laker_tcl/LVS_script" #lvs command file initial path set lvs_init_dir "./" #netlist file initial path set netlist_init_dir "./" #set initial GDS direction set initialdir "./" # ----- sub define ------ #reset File_name2 #set File_name2 "" #reset Top_cell2 #set Top_cell2 "" # ----- main ----- #laker run direction set RUN_PATH [exec "pwd"] #command file and script file direction set run_lvs_script "${script_home}/run_lvs.csh" #gets library and cell name set cv [lakerGetWndCellViewId] set cur_LibName [dbGet -obj $cv -attr LibName] set cur_CellName [dbGet -obj $cv -attr CellName] #sets the GDSII file name like the top cell name. #set tmp_CellName "tmp_cell" #set cur_LibName ${tmp_CellName}.db_tmp #set cur_CellName ${tmp_CellName} # -----GUI----- # #create toplevel and title toplevel .t1 wm title .t1 "Run LVS" #create frame for top #set t1_f1 [frame .t1.f1 -borderwidth 10] frame .t1.f1 -borderwidth 10 # Create the buttons button .t1.f1.b_get_netlist -text "Get Netlist" -command {get_netlist_file} button .t1.f1.b_get_netlist_cell -text "Get Netlist Cell" -command {get_netlist_cell} button .t1.f1.b_lvl_file -text "Get LVS file" -command get_lvs_file button .t1.f1.b_run_lvs -text "Run LVS" -command Run button .t1.f1.b_view_result -text "View result" -command do_dis button .t1.f1.b_quit -text "Quit" -command do_rm #button .t1.f1.b_clean_message -text "Clean message" -command do_clear # Create a labeled and entry for GDS (for top frame1) label .t1.f1.l_gdsname -wraplength 4i -justify left -text "Library Name:" entry .t1.f1.e_gdsname -width 60 -relief sunken -textvariable cur_LibName -background white label .t1.f1.l_gdscell -wraplength 4i -justify left -text "Cell Name:" entry .t1.f1.e_gdscell -width 8 -relief sunken -textvariable cur_CellName -background white # Create a labeled and entry for netlist (for top frame1) label .t1.f1.l_netlistname -wraplength 4i -justify left -text "Netlist File:" entry .t1.f1.e_netlistname -width 60 -relief sunken -textvariable netlist_path -background white label .t1.f1.l_netlistcell -wraplength 4i -justify left -text "Netlist Cell:" entry .t1.f1.e_netlistcell -width 8 -relief sunken -textvariable netlist_cell -background white # Create a labeled and entry for lvl command file (for top frame1) label .t1.f1.l_lvl_file -wraplength 4i -justify left -text "lvs command file:" entry .t1.f1.e_lvl_file -width 60 -relief sunken -textvariable lvs_file_path -background white #Create radiobutton for lvs connect setting frame .t1.rdb_frame label .t1.f1.l_connect_op -wraplength 4i -justify left -text "Connect option:" radiobutton .t1.rdb_frame.rdb_1 -text "Don`t connect nets by name" -variable connect_op -value "1" radiobutton .t1.rdb_frame.rdb_2 -text "Connect all nets by name" -variable connect_op -value "2" .t1.rdb_frame.rdb_1 select #palece widget (label entry file1) to $w.topframe grid .t1.f1.l_gdsname -in .t1.f1 -row 0 -column 0 -sticky e grid .t1.f1.e_gdsname -in .t1.f1 -row 0 -column 1 -sticky ew grid .t1.f1.l_gdscell -in .t1.f1 -row 1 -column 0 -sticky e grid .t1.f1.e_gdscell -in .t1.f1 -row 1 -column 1 -sticky ew #palece widget (label entry file2) to $w.topframe grid .t1.f1.l_netlistname -in .t1.f1 -row 2 -column 0 -sticky e grid .t1.f1.e_netlistname -in .t1.f1 -row 2 -column 1 -sticky ew grid .t1.f1.l_netlistcell -in .t1.f1 -row 3 -column 0 -sticky e grid .t1.f1.e_netlistcell -in .t1.f1 -row 3 -column 1 -sticky ew #palece widget (label entry lvl file) to $w.topframe grid .t1.f1.l_lvl_file -in .t1.f1 -row 4 -column 0 -sticky ew grid .t1.f1.e_lvl_file -in .t1.f1 -row 4 -column 1 -sticky ew grid .t1.f1.b_lvl_file -in .t1.f1 -row 4 -column 2 -sticky ew #palece widget (button) to $w.topframe grid .t1.f1.b_get_netlist -in .t1.f1 -row 2 -column 2 -sticky ew grid .t1.f1.b_get_netlist_cell -in .t1.f1 -row 3 -column 2 -sticky ew #place connect option grid .t1.f1.l_connect_op -in .t1.f1 -row 5 -column 0 -sticky ew grid .t1.rdb_frame.rdb_1 -in .t1.rdb_frame -row 0 -column 0 -sticky ew grid .t1.rdb_frame.rdb_2 -in .t1.rdb_frame -row 0 -column 1 -sticky ew grid .t1.rdb_frame -in .t1.f1 -row 5 -column 1 -sticky ew #place run button grid .t1.f1.b_run_lvs -in .t1.f1 -row 6 -column 0 -sticky ew grid .t1.f1.b_view_result -in .t1.f1 -row 6 -column 1 -sticky ew grid .t1.f1.b_quit -in .t1.f1 -row 6 -column 2 -sticky ew #create logarea frame frame .t1.f2 #create logarea text .t1.f2.t_log -width 50 -height 40 -borderwidth 2 -relief raised -setgrid true -yscrollcommand {.t1.f2.scroll set} scrollbar .t1.f2.scroll -command {.t1.f2.t_log yview} #grid .t1.f2.t_log -in .t1.f2 -row 0 -column 0 #grid .t1.f2.scroll -in .t1.f2 -row 0 -column 1 -sticky ns pack .t1.f2.t_log -side left -fill both -expand true pack .t1.f2.scroll -side right -fill y #pack top floorplan pack .t1.f1 -side top pack .t1.f2 -side top -fill both -expand true proc Run {} { global lvs_file_path cur_LibName cur_CellName netlist_path netlist_cell connect_op run_lvs_script input .t1.f2.t_log delete 1.0 100000.0 if {$lvs_file_path != "" && \ $cur_LibName != "" && \ $cur_CellName != "" && \ $netlist_path != "" && \ $netlist_cell != "" && \ $connect_op != ""} { if {[file exists "./tmp_lvs"]} { set w_lvs_deck_file [open "./tmp_lvs/lvs_deck.cal" w] } else { exec mkdir tmp_lvs set w_lvs_deck_file [open "./tmp_lvs/lvs_deck.cal" w] } set cv [lakerGetWndCellViewId] set cur_exec_path [exec pwd] #sets the GDSII file name like the top cell name. set EXPR_FileName "$cur_exec_path/tmp_lvs/$cur_CellName.db_tmp" #invokes the laker export command lakerExportStream -file $EXPR_FileName -lib $cur_LibName -topCell $cur_CellName -case Preserve -label Preserve -maxVerti 1024 -mergeRefLib 1 -OutAbsCell Off -SmashMcell ExpCont -IoLayerMapMode Map #write lvs deck file set date [clock format [clock seconds] -format "%Y-%m-%d %H:%M"] puts $w_lvs_deck_file "\/\/\n\/\/ Rule file generated on $date by run_lvs TCL" puts $w_lvs_deck_file "\/\/ ***Please DO NOT MODIFY THIS FILE***" puts $w_lvs_deck_file "\/\/\n\n" puts $w_lvs_deck_file "LAYOUT PATH \"$EXPR_FileName\"" puts $w_lvs_deck_file "LAYOUT PRIMARY \"$cur_CellName\"" puts $w_lvs_deck_file "LAYOUT SYSTEM GDSII\n" puts $w_lvs_deck_file "SOURCE PATH \"$netlist_path\"" puts $w_lvs_deck_file "SOURCE PRIMARY \"$netlist_cell\"" puts $w_lvs_deck_file "SOURCE SYSTEM SPICE\n\nMASK SVDB DIRECTORY \"svdb\" QUERY" puts $w_lvs_deck_file "LVS REPORT \"lvs.report\"\nVIRTUAL CONNECT COLON YES" if {$connect_op == "1"} { puts $w_lvs_deck_file "\/\/VIRTUAL CONNECT NAME ?" } else { puts $w_lvs_deck_file "VIRTUAL CONNECT NAME ?" } puts $w_lvs_deck_file "DRC ICSTATION YES\n" puts $w_lvs_deck_file "INCLUDE \"$lvs_file_path\"" close $w_lvs_deck_file #open "|" input :run with pipeline and redirect to input variable #catch {open "|./tmp_lvs/lvs_deck.cal "} input] if [catch {open "|calibre -lvs -hier ./tmp_lvs/lvs_deck.cal | tee ./tmp_lvs/run.log"} input] { .t1.f2.t_log insert end $input\n } else { #fileevent $input readable Log => if $input can readable then exec fileevent $input readable { if [eof $input] { Stop } else { gets $input line .t1.f2.t_log insert end $line\n .t1.f2.t_log see end\n } } .t1.f2.t_log insert end "$lvs_file_path\n" .t1.f1.b_run_lvs config -text Stop -command Stop } } else { lakerMsgForm -name Informaiton -text "please check input data" } } proc Stop {} { global input catch {close $input} .t1.f1.b_run_lvs config -text "Run LVS" -command Run #$but config -state normal -command Run } proc get_netlist_file {} { global netlist_path .t1.f2.t_log netlist_init_dir # Type names Extension(s) Mac File Type(s) # #--------------------------------------------------------- set types { {"All files" {*}} } set file [tk_getOpenFile -filetypes $types -initialdir $netlist_init_dir -title "Open LVS file"] set netlist_init_dir [file dirname $file] if {$file != ""} { .t1.f2.t_log delete 1.0 100000.0 set netlist_path $file } } proc get_netlist_cell {} { global netlist_path netlist_cell .t1.f1.b_get_netlist_cell configure -state disable catch {set netlist_cells [exec cat $netlist_path | grep -i "^.subckt" | awk "{print \$2}"]} if {[info exists netlist_cells]} { set netlist_cells_list [split $netlist_cells "\n"] #puts $netlist_cells_list toplevel .t2 wm title .t2 "Select netlist cell" frame .t2.f1 listbox .t2.sel_cell -selectmode single -width 30 -height 15 -yscrollcommand ".t2.sel_cell_sr_y set" -xscrollcommand ".t2.sel_cell_sr_x set" foreach cell $netlist_cells_list { .t2.sel_cell insert end $cell } scrollbar .t2.sel_cell_sr_y -command ".t2.sel_cell yview" -orient v scrollbar .t2.sel_cell_sr_x -command ".t2.sel_cell xview" -orient h frame .t2.f2 button .t2.b_cancel -text "cancel" -command { destroy .t2 ; .t1.f1.b_get_netlist_cell configure -state normal} button .t2.b_ok -text "ok" -command { if {[.t2.sel_cell curselection] == {}} {tk_messageBox -title "exit" -message "No cell selected."} else {set netlist_cell [.t2.sel_cell get [.t2.sel_cell curselection]]} ; destroy .t2 ;.t1.f1.b_get_netlist_cell configure -state normal} #pack .t2.sel_cell -side top -fill x #pack .t2.b_ok -side left #pack .t2.b_cancel -side right grid .t2.sel_cell -in .t2.f1 -row 0 -column 0 -sticky ew grid .t2.sel_cell_sr_y -in .t2.f1 -row 0 -column 1 -sticky ns grid .t2.sel_cell_sr_x -in .t2.f1 -row 1 -column 0 -sticky ew grid .t2.b_ok -in .t2.f2 -row 0 -column 0 grid .t2.b_cancel -in .t2.f2 -row 0 -column 1 pack .t2.f1 -side top -fill x pack .t2.f2 -side right wm geometry .t2 +700+600 } elseif {[file exists $netlist_path] == 0} { tk_messageBox -title "exit" -message "The netlist file path does not exist." } else { tk_messageBox -title "exit" -message "The netlist does not include any cells, please check the netlist file." } wm protocol .t2 WM_DELETE_WINDOW { destroy .t2 .t1.f1.b_get_netlist_cell configure -state normal } } proc get_lvs_file {} { global initialdir lvs_file_path .t1.f2.t_log lvs_init_dir # Type names Extension(s) Mac File Type(s) # #--------------------------------------------------------- set types { {"cal files" {.cal .CAL} } {"All files" {*}} } set file [tk_getOpenFile -filetypes $types -initialdir $lvs_init_dir -title "Open LVS file"] set lvs_init_dir [file dirname $file] if {$file != ""} { .t1.f2.t_log delete 1.0 100000.0 set lvs_file_path $file } } proc do_rm {} { if {[tk_messageBox -title "exit" -message "tmp_lvs folder will be removed, Really Quit?" -type yesno] == "yes"} { exec rm -rf tmp_lvs tmp_drc tmp_ag cell_list layer_list name_list #destroy .t1 destroy .t1 } } wm protocol .t1 WM_DELETE_WINDOW { if {[tk_messageBox -title "exit" -message "tmp_lvs folder will be removed, Really Quit?" -type yesno] == "yes"} { exec rm -rf tmp_lvs tmp_drc tmp_ag cell_list layer_list name_list #destroy .t1 destroy .t1 } } #specify window size:50X50 and location shift +500 +100 #wm geometry .t1 50x50+500+100 wm geometry .t1 +500+300 #wm title .t1 "TOP LEVEL" #raise .t1
Write, Run & Share TCL code online using OneCompiler's TCL online compiler for free. It's one of the robust, feature-rich online compilers for TCL language, running the latest TCL version 8.6. Getting started with the OneCompiler's TCL editor is easy and fast. The editor shows sample boilerplate code when you choose language as TCL and start coding.
OneCompiler's TCL online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample TCL program which takes name as input and prints hello message with your name.
set name [gets stdin]
puts "Hello $name"
Tool Command Language(TCL) is a general purpose scripting language which is commonly used for GUIs and for testing. Everything is by default string in TCL. It was created by John Osterhout in 1989.
Variable is a identifier which is used to hold the value. set
is used to create variables.
set name onecompiler
When ever you want to perform a set of operations based on a condition IF-ELSE is used.
if(conditional-expression) {
#code
} else {
#code
}
You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.
Switch is an alternative to If-Else-If ladder.
switch(conditional-expression) {
value1 {
# code
}
value1 {
# code
}
...
default {
# code
}
For loop is used to iterate a set of statements based on a condition.
for{start}{test}{next}{
# code
}
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while(condition) {
# code
}
Array is a collection of similar data which is stored in continuous memory addresses. Array values can be fetched using index. Index starts from 0 to size-1.
set ArrayName(Index) value
Procedure is a sub-routine which contains set of statements. Uusually procedures are required when multiple calls are made to same set of statements. Procedures increases re-usuability and modularity.
proc procedureName {arguments} {
# code
}