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