作者:白櫟旸
tcl腳本在芯片設計中用于modelsim do腳本的編寫,數字設計軟件的自動化都需要tcl。
閱讀以下文檔時,大家可以一邊讀,一邊打開modelsim,在命令行上進行輸入,命令行可以運行tcl程序。
以下介紹中順便介紹modelsim的命令,請不要把它與tcl的語法混淆。
(1)注釋方法,同shell一樣用#,但注釋和代碼是分行寫的,不能寫在一行。
(2)變量定義和賦值:tcl將所有值當做字符,所以“set x 10”中的10是字符,而不被理解為真正的10。對比其他語言,perl是自動匹配,即編譯器自動判斷是數字還是字符,C語言是用戶告訴編譯器是int還是char。
【字符賦值】:set x 10,或 set x $a
在tcl中,變量 a 被賦值后,在后面的程序中出現 a,說明是變量 a,后面的程序出現 $a, 只表示一個具體的字符或數字,跟 a 沒有一點關系。
像tcl這種默認字符的處理方式給處理字符帶來方便,但數學計算卻并不方便,下面介紹如何將字符變成數字:
【數字賦值】:使用 expr 命令,如:set y [expr 10+100],則y的值就是110,注意:110仍然是個字符。
在賦值、數學計算中,都使用[],而不是傳統的(),如:[expr [expr 1+2]*3]。所以最 好不用tcl進行數學運算,只用它處理字符和文件,數學運算非它所長。
【變量運算】:set y [expr $x+100],y的值仍然是110.
如果一個變量叫 abc = 10,則 set y [expr $abc+100],y是110,說明 $abc 被當作一個
整體處理了。如果怕不保險,可以用 ${abc},即 set y [expr ${abc}+100],這和perl的
用法是一樣的。
(3)顯示變量的值:"puts 文件句柄 $x",或者"puts $x"(默認文件句柄為stdout),或者直接 "set x",會顯示 $x 的值。
(4)取消變量: unset x y z,注銷了 x y z 三個變量。
(5)追加變量值:
set x 10
append x abc, 則 x 的值是10abc
(6)關鍵字、關鍵字符:當變量賦值時,有些字符在tcl語法中有特殊含義,如果需要將其當作一般字符賦值,請進行字符轉義,
例1: [ ,請使用 \[ 標識,set x \[,則 x =[
例2: set x \[2],則 x = [2],注意,]前面沒有\
以下列出關鍵字符:
\空格 ———— 空格
\[ ———— [
\$ ———— $
\n ———— 換行
\t ———— 制表符
\r ———— 回車
\x48 ———— 0x48對應的ASC碼字符
\756 ———— 0756(八進制)對應的ASC碼字符
此外,可以使用""或{},如:set x "1 2 3",x = "1 2 3",
""的用法: 編譯器仍然編譯""里面的內容,如:set x "$y",則 x = y的值;“[express]”也會被編譯。
{}的用法: 編譯器不編譯{}中的任何內容,如:set y {\n},則 y = \n.{}其實是定義數組的方式,看后面
(7)數組(集合):雖然人們管它叫 list,但我看就是個廣義數組,類似matlab中cell的數據結構。以下是數組的概念和操作:
【定義數組】:set x {1 2 3},等同于 set x [list 1 2 3],前者比較容易寫。
【數組嵌套】:set x 1 2 3 {3 4 5}
【合并數組】:set $z [concatlist $x $y]
【從數組中取一個元素】:lindex $x 2,從$x中取從0開始第2個元素。
【數組的長度】:llength $x
【插入數組元素】:linsert $x 3 $y,在原數組$x的3位置插入一個新數組$y,序號3位置可以使用end表示最后一個。
【替換數組元素】:lreplace $x 1 3 5 7,將原數組$x的第1~3位置元素替換為5和7。
【截取數組】:lrange $x 1 3,截取原數組$x的第1~3位置的一段。
【尾部追加數組元素】:lappend x 1 3 4,在原數組x的后面加入元素1 3 4。注意:該命令與上面的數組命令不同。上面的數組命令只產生一個新的數組,原數組x不變,而本命令會改變原數組x本身。因此我們不寫成“lappend $x 1 3 4”,而應該寫成“lappend x 1 3 4”。
【在數組元素中查找】:lsearch $x 33,在數組 $x 中查找33,找到后返回序號,未找到返回-1。搜索命令可以加控制選項:-exact(完全匹配,不支持通配符*等),-glob(支持通配符的查找),-regexp(正則表達式)。如下:lsearch -regexp $x .*3.+。
【數組排序】:lsort 選項 $x,如果不寫選項,默認按ASC碼順序排列。其他選項有:
-integer:整數排列,2不會拍到10后面
-real:按浮點數排列
-increasing:ASC碼升序排列
-decreasing:ASC碼降序排列
【將string拆成數組】:split "abc" {},將字符串abc拆成數組a b c,{}是拆分的依據,即把每個字符都拆開。也可以用其他依據,如:split "a:b:c" :,結果還是 a b c
【將數組變成string】:join {1 2 3} :,結果是一個字符串1:2:3
(8)條件判斷:tcl編譯器是早期編譯器,比較“弱智”,對“換行符”、“空格”等都敏感。“換行符”用來標識一行命令結束(類似C語言中的;),“空格”用來劃分命令和參數。因此,在tcl復雜語言結構中,使用“換行”和“空格”一定要注意。
if {條件1} { //注意“空格”和“換行”的位置。條件、結果都用{},不用()。
結果1
} elseif {條件2} {
結果2
} else {
結果3
}
switch 選項 $x {
a - // - 表示“a情況 ~ b情況”
b {結果1}
c {結果2}
default {結果3}
}
switch的選項有:-exact(準確匹配),-glob(整體匹配),-regexp(regular expression正則表達式匹配)
(9)循環結構: tcl循環支持 break 和 continue .
while {條件} {
循環體
}
for {條件} {
循環體
}
foreach i $a { //$a 是個數組
循環體
}
foreach 還可以多變量賦值,如下:
foreach i {1 2 3} j {4 5 6} {
循環體
}
(10)動態命令:set x "expr 3+2",eval $x,顯示為5。
(11)自定義函數:在tcl中也可以寫函數,供腳本調用。函數定義方法如下:
proc 函數名 參數列表 {函數功能塊},例如:proc add {x y} {expr $x+$y},寫完后,調用時寫add 1 3,執行結果為4。支持return。
在函數外定義的變量,如果要在函數中使用,并繼承原來的值,需要在“函數功能塊”中用:global x進 行聲明。
可以給函數的參數定義默認值:proc add {{x 1} {y 2}} {expr $x+$y}。
可以讓函數攜帶非固定數量的參數,關鍵詞是args,例如: proc add {args} {......},args是作為列 表使用的,而非單獨一個元素。
(12)字符串操作:tcl數字處理是繁瑣的,而對字符串操作是它的強項,因為tcl主要用于命令行中對文件名、目錄名、路徑等字符串進行操作。
【格式化字符串】:在C語言和perl中,我們使用sprintf來格式化字符串,或輸出到屏幕上,或輸出到另一個字符串變量中。在tcl中,完成相同功能的命令叫format,例如:format "%s is %d" $x $y,使用時把C語言中的逗號改成空格,沒有括號,就是tcl的表達方式。
【字符串匹配】:使用perl語言的話,用模式匹配符 =~ 進行正則表達式匹配超容易,在tcl中稍麻煩一些,使用命令:regexp,格式為:
regexp {pattern} string,
如果pattern匹配string,則返回1,否則返回0. 例如:regexp {abc} baiabc001,abc在baiabc001中出現,匹配成功,返回1。
匹配命令regexp也可以像perl一樣從string中截取變量的值,賦給變量,例如:
regexp {(.).+([0-1]+)} "baiguangyu001" x y z,則x匹配整個baiguangyu001,y匹配第一個b,z匹配最后一個1。
打開選項-indices可以返回匹配的位置,如regexp -indices {(.).+([0-1]+)} "baiguangyu001" x y z,x的值是{0 12},表示匹配整個字符串,y的值是{0 0},表示從第一個字符開始,到第一個字符結束。z的值是{12 12},從第12個字符開始,又從第12個字符結束。
【字符串替換】:regexp是字符串匹配,相當于perl中的m//,而regsub是字符串替換,相當于perl中的s//。
格式為:regsub option pattern string substr whole_str_aft
用pattern在string中匹配,匹配上以后,用substr替代匹配部分,替換后的整個string存在whole_str_aft里。
在option處可以加選項,相當于perl中的m//igx之類的。具體選項有:-nocase:不區分大小寫//i,-all就是//g.
【字符串比較】:string compare [-nocase] [-length 10] str1 str2,
比較str1和str2,如果有length 10,就是只比較前10個字符。返回值:-1(小于),0(等于),1(大于)
【字符串比較】:string equal [-nocase] [-length 10] str1 str2,返回值:1(等于),0(不等于)。
【字符串長度】:string length str,返回str的長度。
【字符串大小寫互轉】:string tolower str,將str變小寫。
string toupper str,將str變大寫。
(13)文件訪問:對于tcl來說,一個重點是字符串,另一個重點就是文件操作。
【打開文件】:set x [open $filename r],同perl中的:open x,"<$filename";同C語言的:x=fopen(filename,"r"); r是讀,w是寫,a是追加,r+是讀寫。
【關閉文件】:close $x
【逐行讀取文件】:關鍵命令gets,while {gets $x line},把x句柄的每一行賦給line變量。類似perl中的:while($line = <$x>),但perl更簡單。
【寫文件】:“puts 文件句柄 內容”
【3種特殊的文件句柄】:stdin,stdout,stderr。
【刷新緩沖區】:有時候內容顯示不出來,就用flush命令,“flush 句柄”。
【文件指針跳躍】:“seek 句柄 偏移 坐標原點”,坐標原點只有3種:start,current,end
【獲知文件指針】:“tell 句柄”,“eof 句柄”說明文件是否已經讀完
(14)目錄文件管理:
【查找文件或目錄名】:glob name1 name2 ....,用來查找當前工作目錄中是否有name文件,name的格式不是模式匹配的,所以需要文件名的全稱,也支持通配符,但不支持正則表達式。通配符有*,集合符有[ab](表示ab中的一個字符),{a1,a2}類似[ab]但是個組集合。如果怕報錯,寫一個-nocomplain,即便沒找到,也只返回空。例如:
glob -nocomplain {abc,a123}/*hd.[co],可以匹配abc/1hd.c,a123/Ahd.o等。
【顯示文件的訪問時間】:file atime name,atime就是access time(訪問時間),返回一個很莫名其妙的時間。
【顯示文件的修改時間】:file mtime name,mtime就是manipulate time(操作時間).
【顯示文件大小】:file size name,單位是字節。
【顯示文件類型】:file type name,類型有:file,directory,characterspecial(字符設備),blockspecial(塊設備),fifo,link,socket.
【拷貝文件】:file copy [-force] source target
【刪除文件或目錄】:file delete [-force] name
【獲知文件路徑】:file dirname name
【獲知文件是否可執行】:file executable name
【獲知文件或目錄是否存在】:file exists name
【獲知文件擴展名】:file extension name
【獲知文件名是否是目錄名】:file isdirectory name
【獲知文件是否是個軟連接】:file lstat name,lstat就是link state
【新建目錄】:file mkdir dirname1 dirname2
【文件改名】:file rename [-force] source target,類似linux的mv命令,可以用于剪切和粘貼。
(15)在tcl中調用perl腳本:
tcl的功能有限,很多復雜處理還需要用perl實現較快,以下是tcl調用perl的方法:
set x [exec perl abc.pl],其中abc.pl是被調用的perl腳本的文件名。
如果abc.pl的內容為:
$a = 4; $b = 3; $c = $a+$b; print $c;
則 x 被賦值為 7.