#!/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 
by

Tool Command Language(TCL) online compiler

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.

Taking inputs (stdin)

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"

About TCL

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.

Syntax help

Variables

Variable is a identifier which is used to hold the value. set is used to create variables.

Examples

set name onecompiler

Loops

1. If-Else:

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.

2. Switch:

Switch is an alternative to If-Else-If ladder.

switch(conditional-expression) {    
value1 {     
 # code
}    
value1 {     
 # code
}    
...
default {
# code
} 

3. For:

For loop is used to iterate a set of statements based on a condition.

for{start}{test}{next}{  
  # code  
} 

4. While:

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 
}  

Arrays

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.

Syntax

set ArrayName(Index) value

Procedures

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.

Syntax

proc procedureName {arguments} {
   # code
}