TCL腳本語(yǔ)言
Tcl(Tool Command Language)是一種很通用的腳本語(yǔ)言,它幾乎在所有的平臺(tái)上都可以解釋運(yùn)行,而且VIVADO也提供了TCL命令行。最近發(fā)現(xiàn)TCL腳本貌似比GUI下操作VIVADO效率高一些,方便一些。而且最近跟著官網(wǎng)文檔做SDSOC的flatform,發(fā)現(xiàn)xilinx官網(wǎng)的文檔里都是用TCL命令來(lái)完成操作,于是決心學(xué)習(xí)一下TCL的語(yǔ)法。
應(yīng)用程序(如VIVADO)使用Tcl作為它的命令語(yǔ)言的好處:
1 Tcl提供了標(biāo)準(zhǔn)語(yǔ)法,一旦用戶掌握了Tcl就可以很容易的發(fā)布命令給基于Tcl的程序。
2 Tcl實(shí)現(xiàn)了很多的功能,使你的工作變得很方便。
命令格式
一條Tcl的命令串包含了多條命令時(shí),用換行符或分號(hào)來(lái)隔開
而每一條命令包含了一個(gè)域的集合,域使用空白分開的,第一個(gè)域是一個(gè)命令的名字,其它的是作為參數(shù)來(lái)傳給它
數(shù)據(jù)類型
Tcl只支持一種數(shù)據(jù)結(jié)構(gòu):字符串。所有的命令、命令里的所有的參數(shù)、命令的結(jié)果、變量全部都是都是字符串。
簡(jiǎn)單實(shí)例:
set i 123
將123這個(gè)字符串賦值給i變量
unset i
清除變量
set i hi
將hi這個(gè)字符串賦值給i變量
set i “hi hello”
hi hello中有空格,所以加引號(hào)
set i 123;#開始注釋
注意注釋前,要先用分號(hào),把命令結(jié)束掉,或者換行注釋
基本語(yǔ)法和基礎(chǔ)命令
在VIVADO中的TCL命令行里,學(xué)習(xí)這些基本語(yǔ)法
(Windows下 –》 開始 –》 所有程序 –》 Xilinx Design Tools –》 Vivado xxx –》 Vivado xxx Tcl Shell)
1》使用$符號(hào)引用變量
其中puts是打印命令
2》使用[]將命令返回值,作為新命令的參數(shù)
set j 232命令會(huì)返回值232
新命令就成了 set i 232
這里稍微復(fù)雜一點(diǎn)點(diǎn)的例子:
set i a[set j b][set k c]
最后的結(jié)果就是:j=b ; k=c ; i=abc
3》數(shù)組
數(shù)組不需要聲明,直接賦值即可,也不必按照順序來(lái):
set i(1) 123 ; set i(16) hi
當(dāng)然也支持任意維數(shù)的數(shù)組:
set i(1,2,3) hi
引用的時(shí)候直接$i(1,2,3)即可
· parray命令
可以打印出一個(gè)數(shù)組的全部信息:
· array命令
命令格式:array option arrayName
option 是 操作選項(xiàng),有如下可選:
name : 返回?cái)?shù)組的所有元素的名稱
size : 返回?cái)?shù)組的長(zhǎng)度
startsearch : 初始化一次遍歷,返回一個(gè)遍歷標(biāo)識(shí)符(searchId),這個(gè)searchId在下面用到,(是可以多個(gè)遍歷同時(shí)進(jìn)行的)
下面的命令格式為:array option arrayName searchId
-》nextelement : 返回?cái)?shù)組中下一個(gè)元素,如果沒(méi)有返回空
-》anymore : 如果接下來(lái)還有元素,返回1,否則返回0
-》donesearch : 結(jié)束遍歷
4》字符串命令
· string命令
命令格式:string option string1 string2
option 是 操作選項(xiàng),有如下可選:
compare : 按照字母的排序方式比較,string1 《,=,》string2,分別返回-1,0,1
match : 判斷string1和string2是否匹配
first : 檢索string2中第一次出現(xiàn)string1的位置,如果沒(méi)有出現(xiàn)string1則返回-1
last : 和first相反
trim : 從string1中刪除開頭和結(jié)尾的,string2的字符
命令格式:string option string
tolower : 返回string中的所有字符被轉(zhuǎn)換為小寫字符后的新字符串
toupper : 返回string中的所有字符串轉(zhuǎn)換為大寫后的字符串
trimleft : ,去除string左空白,類似的還有trimright
length : 返回string1的長(zhǎng)度
range :
string range abcdef 1 2,返回輸出結(jié)果為bc
· append命令
字符串追加,可以無(wú)限拼接
set i a
append i b c d
puts $i
i變量的值就成了 abcd,注意append i b c d命令,而不是append $i b c d
· split命令
命令格式:split 字符串 分割符,將字符串轉(zhuǎn)換為列表
5》數(shù)字操作
tcl中只有string類型的變量,所以當(dāng)進(jìn)行數(shù)字運(yùn)算的時(shí)候,需要用到incr和expr操作命令
· incr命令
a變量自加-3:incr a -3
a變量自加1 : incr a
· expr命令
類似C語(yǔ)言中的算術(shù)操作符有(在Tcl 中的邏輯:真為1,假為0):
!、* 、/、 %、+、-、《《、 》》 、《 、》 、《= 、》= 、== 、!=、& 、^ 、|、&&、 || 、x ? y : z
除此之外,expr還能夠識(shí)別一些函數(shù)及其返回值:
abs(x) 、round(x) 、sin(x)、cos(x) 等
使用方法:expr 表達(dá)式
6》list列表
類似python中的列表,比如:{abc {def {jkl ccc}}}是一個(gè)有兩個(gè)元素的列表 abc和{def {jkl ccc}},Tcl中對(duì)list的命令有:
(首先set l {abc {def {jkl ccc}}},下面實(shí)例中將對(duì)這個(gè)l列表進(jìn)行操作)
需要注意的是:大部分命令都是對(duì)$l進(jìn)行處理,也把就是l的內(nèi)容字符串取出來(lái),再處理,并不會(huì)對(duì)l列表的內(nèi)容造成影響
需要注意的是lappend命令,lappend $l abcd是無(wú)效的,必須lappend l abcd才能實(shí)現(xiàn)列表內(nèi)容的更新,而且是直接更改列表的內(nèi)容
7》proc自定義函數(shù)
proc:
proc hello {str} {
puts hello:$str
}
需要注意的是,如果不能一行寫完,那建議按照如下格式來(lái)定義(主要是要將“{”放到第一行的末尾):
第一行: proc+(空格)+函數(shù)名+(空格)+{參數(shù)}+(空格)+{
中間行: 邏輯運(yùn)算
最后行: }
全局變量global:
用于將過(guò)程中的局部變量變成外界可操作的全局變量
proc hello {} {
global x
set x hi
set i hello}
上述代碼,執(zhí)行結(jié)果:
return命令:
proc hello {} {return world}
set i [hello]
return命令沒(méi)啥好說(shuō)的,上述代碼的結(jié)果是,將i變量賦值為world字符串
8》流控制
if 流控制
這個(gè)同樣建議按照格式來(lái):
第一行: if+(空格)+{表達(dá)式}+(空格)+{
中間行: 邏輯運(yùn)算
第N行: }+(空格)+else+(空格)+{
中間行: 邏輯運(yùn)算
最后行: }
switch流控制
例子如下,一目了然:
switch 2 {
1 {puts 111}
2 {puts 222}
3 {puts 333}
default {puts xxx}
}
case流控制
case abcd in a {puts 111} *bc* {puts 333} default {puts xxx}
上述程序?qū)ψ址產(chǎn)bcd進(jìn)行判斷:
條件一 : 字符串為a
條件二 : 不管字符串的前后字符是啥,只要中間有bc子字符串即可
條件三 : default
9》循環(huán)控制
foreach循環(huán):
假如想要將0,3,2,1按照順序分別放到上述switch的判決條件(列表)里,輸出四個(gè)結(jié)果,那就需要這個(gè)foreach了:
foreach i {0 3 2 1} {
switch $i {
1 {puts 111}
2 {puts 222}
3 {puts 333}
default {puts xxx}
}
}
for循環(huán):
TCL的for循環(huán)也是很類似C語(yǔ)言的:
for {set i 0} {$i 《 10} {incr i} {
puts $i
}
初始化i=0,范圍 i《10 ,循環(huán)i=i+1
while循環(huán):
set i 10
while {$i!=5} {
puts $i
incr i -1
}
運(yùn)行的結(jié)果,自己就可以想象了
10》字符串轉(zhuǎn)為命令
eval命令:
set a set ; set b i ; set c hello ; eval $a $b $c
上述代碼就等效于:set i hello
eval將字符串的內(nèi)容,作為命令,執(zhí)行
11》打印輸出
之前的那個(gè)puts命令也是可以打印到命令行,但是,也只是能打印出來(lái)而已,而這個(gè)format類似于C中的sprintf(用于格式化輸出):
format命令:
format可以這樣用:
format “%s %d” hello 666
set i [format “%s %d” hello 666]
scan命令:
說(shuō)到format,剛好一起把scan說(shuō)了,這兩個(gè)命令可以看做是相反的一對(duì), 前者組合成字符串,后者把字符串拆分后賦值給變量
scan 12.34.56.78 %d.%d.%d.%d a b c d
將12.34.56.78拆分,并分別賦值給a b c d四個(gè)變量,命令返回賦值成功的變量的個(gè)數(shù)
puts命令:
puts當(dāng)然也可以打印到文件中
set f [open test.txt w]
puts -nonewline $f “hello\n”
puts $f “world”
close $f
puts -nonewline $f “hello\n”表示的是強(qiáng)制不換行打印,否則自動(dòng)追加一個(gè)換行符
文件系統(tǒng)
基本常用操作:
gets –》 一次讀一行文件
puts –》 寫入文件
open –》 打開文件
close –》 關(guān)閉文件
flush –》 刷新緩沖區(qū)
cd命令
和shell中的cd一樣
pwd命令
用于查看當(dāng)前所在的目錄
open命令
打開文件,返回文件描述符
命令格式:open 文件名 模式,支持6種模式,和其他編程語(yǔ)言中的文件IO,也是很相似的,模式如下:
r 模式: 打開只讀文件(文件必須存在)
r+ 模式: 打開可讀寫文件[r+和a+模式可以類比]
w 模式: 打開只寫文件,若文件存在則清空內(nèi)容;若文件不存在則創(chuàng)建文件。
a 模式: 以追加方式打開只寫文件,若文件不存在,則創(chuàng)建;如果文件存在,則會(huì)在文件內(nèi)容最后面追加寫入的數(shù)據(jù)
xxxx
理論上說(shuō)open |文件名 模式,在文件名前加個(gè)“|”符號(hào),可以以管道的模式打開文件,但是測(cè)試一直沒(méi)有成功,之后用到的話再回來(lái)解決吧
xxxx
read命令
set f [open test.txt r]
read $f 6
close $f
可以使用eof命令,判斷文件是否讀完了,eof $f,讀完返回1,否則返回0
上述代碼直接從文件中讀6個(gè)字節(jié);如果想把文件內(nèi)容全部讀出,則直接read $f;如果想一行一行讀則使用gets命令:gets $f
source命令
命令格式:source $f
從對(duì)應(yīng)的文件中讀出內(nèi)容,并傳給Tcl解釋執(zhí)行
tell命令
返回文件的指針位置,命令格式:tell $f
file命令
命令格式:file option name
option操作選項(xiàng)較多,就直接列個(gè)表了,表示如下:
除此之外,file 的 stat 狀態(tài)操作選項(xiàng):
命令格式:file stat name k,結(jié)果存在數(shù)組k里
glob命令
1)查看當(dāng)前目錄下的文件(類似shell中的ls)
glob *
2)查看當(dāng)前目錄下特定后綴的文件
glob *.txt *.tcl
3)查看當(dāng)前目錄下的txt、txl、tcl和tct文件:
glob {*t[xc][tl]}
4)查看當(dāng)前目錄下的子目錄里查看txt、txl、tcl和tct文件:
用“\”分割路徑,格式為:glob {{目錄1,目錄2等}\\*.后綴}
5)-type選擇查看類型:
命令格式:glob -type {類型1 類型2 等} 目標(biāo)目錄
類型有:
類型 含義
b 塊設(shè)備
c 字符設(shè)備
d 代表目錄
f 文件
l 代表符號(hào)鏈接
p 代表命名管道
s 代表套接字
r 讀
w 寫
x 可執(zhí)行
seek命令
用于調(diào)整文件指針
命令seek $f 2,文件指針定位到序號(hào)為2,現(xiàn)在有一個(gè)文件名為s1.txt,內(nèi)容為hello字符串,那么,設(shè)計(jì)一個(gè)程序?qū)崿F(xiàn)從第三個(gè)字符串開始讀文件內(nèi)容:
info命令獲取信息
假如創(chuàng)建了一個(gè)過(guò)程:proc hello { a b c } {puts hi}
執(zhí)行命令:info args hello,則返回a b c,參數(shù)列表
執(zhí)行命令:info body hello,則返回puts hi,函數(shù)體
info procs,返回所有的過(guò)程的列表
info procs hello,如果存在hello過(guò)程則返回hello字符串,不存在則不返回
info commands,則列出解釋器支持的所有命令
info commands create_ip,create_ip是vivado支持的tcl命令,所以這個(gè)info返回的值是create_ip,如果不支持該命令的話,則不返回值
info exists kkk,判斷kkk變量是否存在
info vars,返回當(dāng)前變量名的列表
info vars i,如果存在該i變量則返回i字符串,不存在則不返回
info globals,返回全局變量的列表
info globals env,如果存在該env全局變量則返回env,不存在則不返回
info locals,返回local變量列表
info locals i,如果存在該i局部變量則返回i,不存在則不返回
info hostname,返回主機(jī)名
info cmdcount,則返回當(dāng)前解釋器已經(jīng)執(zhí)行的命令個(gè)數(shù)
info tclversion,返回解釋器版本號(hào)
info level,返回當(dāng)前的在棧中的絕對(duì)位置
info level 1,如果加了參數(shù)數(shù)字,則返回該層的命令和參數(shù)
注:uplevel命令(連接參數(shù))
既然說(shuō)了level那就把uplevel命令說(shuō)了,level值為0代表頂層,level代表在棧中的絕對(duì)位置,過(guò)程調(diào)用的時(shí)候,一層比一層的level值高1,被調(diào)用的過(guò)程中若想在上一層的環(huán)境中執(zhí)行操作,那么就需要uplevel命令了
proc hello {} { uplevel set a “helloworld” }
set a hi ; hello ; puts $a
注:upvar命令(連接變量)
既然說(shuō)了uplevel那就把upvar命令也說(shuō)了吧,其類似于uplevel命令,但是其側(cè)重的是在不同層之間連接單一變量
proc hello {a} {upvar $a x ; set x helloworld}
set i hi ; hello i ; puts $i
系統(tǒng)異常、系統(tǒng)監(jiān)視
catch命令
用于阻止因錯(cuò)誤而導(dǎo)致的中斷執(zhí)行,類似python中的異常,執(zhí)行成功返回0,否則返回1
unknown命令
我將這個(gè)指令歸為異常指令
使用方法:首先定義一個(gè)unknown過(guò)程,這個(gè)過(guò)程的參數(shù)為cwd(命令)和args(參數(shù))
proc unknown {cwd args} {
puts commend:$cwd
puts args:$args
}
這樣的話,當(dāng)有未知命令或者打錯(cuò)了代碼的話,就可以通過(guò)unknown過(guò)程,控制錯(cuò)誤
time命令
time “set i 10”,該命令將計(jì)算執(zhí)行的時(shí)間
trace命令
監(jiān)視變量的存儲(chǔ)的命令,感覺暫時(shí)用不到,需要用到的時(shí)候再看
命名空間namespace
命名空間是命令和變量的集合,通過(guò)命名空間的封裝,來(lái)保證他們不會(huì)影響其它命名空間的變量和命令
設(shè)置新命名空間
首先定義兩個(gè)hello過(guò)程,其中一個(gè)在hlf命名空間內(nèi),然后測(cè)試
namespace eval hlf {pro hello {} {puts hello_hlf}}
pro hello {} {puts hello_all}
設(shè)置新變量
直接通過(guò)set hlf::i 888,就可以對(duì)hlf空間的i進(jìn)行設(shè)置
刪除命名空間
命令:namespace delete hlf
不同命名空間共享變量和過(guò)程
通過(guò)export和import命令,完成一個(gè)命名空間導(dǎo)出過(guò)程,另一個(gè)命名空間將其導(dǎo)入,完成過(guò)程共享
對(duì)命名空間的變量進(jìn)行設(shè)置或訪問(wèn)
variable命令,以例子說(shuō)明:
namespace eval hlf {
variable i 5
proc next {} {variable i;return [incr i]}
proc reset {} {variable i;set i 0}
}
目前的理解就是可以在同一命名空間內(nèi)的不同過(guò)程中傳遞變量,也就不深究了
到此為止算是對(duì)TCL的基本使用有了一個(gè)大致的理解,里面還有很多具體的函數(shù)和函數(shù)選項(xiàng)沒(méi)有涉及到,如果之后用的到的話再做補(bǔ)充吧,但是我覺得,應(yīng)對(duì)VIVADO的TCL的語(yǔ)法,這些基礎(chǔ)語(yǔ)法應(yīng)該足夠了的,接下來(lái)就是對(duì)VIVADO自帶的TCL的庫(kù)里的函數(shù),進(jìn)行一個(gè)了解了
之后遇到不懂的命令,就直接輸入命令 -help,就可以看到一堆幫助了
評(píng)論