VIVADO 之 TCL指令碼工具 (基本語法)
TCL指令碼語言
注:TCL在VIVADO中的具體使用將寫在VIVADO 之 TCL指令碼工具 [下]
中,本文只有TCL語法
Tcl(Tool Command Language)是一種很通用的指令碼語言,它幾乎在所有的平臺上都可以解釋執行,而且VIVADO也提供了TCL命令列。最近發現TCL指令碼貌似比GUI下操作VIVADO效率高一些,方便一些。而且最近跟著官網文件做SDSOC的flatform,發現xilinx官網的文件裡都是用TCL命令來完成操作,於是決心學習一下TCL的語法。
應用程式(如VIVADO)使用Tcl作為它的命令語言的好處:
1 Tcl提供了標準語法,一旦使用者掌握了Tcl就可以很容易的釋出命令給基於Tcl的程式。
2 Tcl實現了很多的功能,使你的工作變得很方便。
3 TCl可作為程式間通訊的介面。
命令格式
一條Tcl的命令串包含了多條命令時,用換行符或分號來隔開
而每一條命令包含了一個域的集合,域使用空白分開的,第一個域是一個命令的名字,其它的是作為引數來傳給它
資料型別
Tcl只支援一種資料結構:字串。所有的命令、命令裡的所有的引數、命令的結果、變數全部都是都是字串。
簡單例項:
-
set i 123
將123這個字串賦值給i變數 -
unset i
清除變數 -
set i hi
將hi這個字串賦值給i變數 -
set i "hi hello"
hi hello中有空格,所以加引號 -
set i 123;#開始註釋
注意註釋前,要先用分號,把命令結束掉,或者換行註釋
基本語法和基礎命令
在VIVADO中的TCL命令列裡,學習這些基本語法
(Windows下 –> 開始 –> 所有程式 –> Xilinx Design Tools –> Vivado xxx –> Vivado xxx Tcl Shell)
1>使用$符號引用變數
其中puts是列印命令
2>使用[]將命令返回值,作為新命令的引數
set j 232
命令會返回值232
新命令就成了 set i 232
這裡稍微複雜一點點的例子: set i a[set j b][set k c]
最後的結果就是:j=b ; k=c ; i=abc
3>陣列
陣列不需要宣告,直接賦值即可,也不必按照順序來: set i(1) 123 ; set i(16) hi
當然也支援任意維數的陣列: set i(1,2,3) hi
引用的時候直接$i(1,2,3)
即可
· parray命令
可以打印出一個數組的全部資訊:
· array命令
命令格式:array option arrayName
option 是 操作選項,有如下可選:
name : 返回陣列的所有元素的名稱
size : 返回陣列的長度
startsearch : 初始化一次遍歷,返回一個遍歷識別符號(searchId),這個searchId在下面用到,(是可以多個遍歷同時進行的)
下面的命令格式為:array option arrayName searchId
->nextelement : 返回陣列中下一個元素,如果沒有返回空
->anymore : 如果接下來還有元素,返回1,否則返回0
->donesearch : 結束遍歷
4>字串命令
· string命令
命令格式:string option string1 string2
option 是 操作選項,有如下可選:
compare : 按照字母的排序方式比較,string1 <,=,>string2,分別返回-1,0,1
match : 判斷string1和string2是否匹配
first : 檢索string2中第一次出現string1的位置,如果沒有出現string1則返回-1
last : 和first相反
trim : 從string1中刪除開頭和結尾的,string2的字元
命令格式:string option string
tolower : 返回string中的所有字元被轉換為小寫字元後的新字串
toupper : 返回string中的所有字串轉換為大寫後的字串
trimleft : ,去除string左空白,類似的還有trimright
length : 返回string1的長度
range :
string range abcdef 1 2
,返回輸出結果為bc
· append命令
字串追加,可以無限拼接
<span style="color:#000000"><code>set <span style="color:#4f4f4f">i</span> a
append <span style="color:#4f4f4f">i</span> b c d
puts $<span style="color:#4f4f4f">i</span></code></span>
- 1
- 2
- 3
i變數的值就成了 abcd,注意append i b c d
命令,而不是append $i b c d
· split命令
命令格式:split 字串 分割符
,將字串轉換為列表
5>數字操作
tcl中只有string型別的變數,所以當進行數字運算的時候,需要用到incr和expr操作命令
· incr命令
a變數自加-3:incr a -3
a變數自加1 : incr a
· expr命令
類似C語言中的算術操作符有(在Tcl 中的邏輯:真為1,假為0):
!、* 、/、 %、+、-、<<、 >> 、< 、> 、<= 、>= 、== 、!=、& 、^ 、|、&&、 || 、x ? y : z
除此之外,expr還能夠識別一些函式及其返回值:
abs(x) 、round(x) 、sin(x)、cos(x) 等
使用方法:expr 表示式
6>list列表
類似python中的列表,比如:{abc {def {jkl ccc}}}是一個有兩個元素的列表 abc和{def {jkl ccc}},Tcl中對list的命令有:
(首先set l {abc {def {jkl ccc}}}
,下面例項中將對這個l
列表進行操作)
命令 | 命令格式 | 功能 | 例項 |
---|---|---|---|
concat | concat 列表1 列表2 等 |
列表拼接 | |
list | list 列表1 列表2 等 |
同上 | |
lindex | lindex 列表 索引 |
索引列表 | |
lrange | lrange列表 索引1 索引2 |
索引列表的一部分 | |
llength | llength 列表 |
返回長度 | |
linsert | linsert 列表 索引 物件 |
列表新增元素 | |
lreplace | lreplace 列表 索引1 索引2 物件 |
把列表對應位置的元素替換 | |
lsearch | lsearch (-mode) 列表 物件 |
在列表中搜索元素的位置(可以加具體mode) | |
lsort | lsort (-mode) 列表 |
列表中元素排序(可以加具體mode) | |
join | join 列表 (連線符) |
將列表中的元素連線成字串 | |
lappend | lappend 列表 物件 |
向列表追加元素(需要注意如下) |
需要注意的是:大部分命令都是對$l
進行處理,也把就是l
的內容字串取出來,再處理,並不會對l
列表的內容造成影響
需要注意的是lappend
命令,lappend $l abcd
是無效的,必須lappend l abcd
才能實現列表內容的更新,而且是直接更改列表的內容
7>proc自定義函式
proc:
<span style="color:#000000"><code>proc hello {<span style="color:#000088">str</span>} {
puts hello:$<span style="color:#000088">str</span>
}</code></span>
- 1
- 2
- 3
需要注意的是,如果不能一行寫完,那建議按照如下格式來定義(主要是要將“{”放到第一行的末尾):
第一行: proc+(空格)+函式名+(空格)+{引數}+(空格)+{
中間行: 邏輯運算
最後行: }
全域性變數global:
用於將過程中的區域性變數變成外界可操作的全域性變數
<span style="color:#000000"><code>proc hello {} {
<span style="color:#4f4f4f">global</span> x
<span style="color:#4f4f4f">set</span> x hi
<span style="color:#4f4f4f">set</span> i hello}</code></span>
- 1
- 2
- 3
- 4
上述程式碼,執行結果:
return命令:
<span style="color:#000000"><code> proc hello {} {return world}
set <span style="color:#4f4f4f">i</span> [hello]</code></span>
- 1
- 2
return命令沒啥好說的,上述程式碼的結果是,將i變數賦值為world字串
8>流控制
-
if 流控制
這個同樣建議按照格式來:
第一行: if+(空格)+{表示式}+(空格)+{
中間行: 邏輯運算
第N行: }+(空格)+else+(空格)+{
中間行: 邏輯運算
最後行: } -
switch流控制
例子如下,一目瞭然:
<span style="color:#000000"><code><span style="color:#000088">switch</span> <span style="color:#006666">2</span> {
<span style="color:#006666">1</span> {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">111</span>}
<span style="color:#006666">2</span> {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">222</span>}
<span style="color:#006666">3</span> {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">333</span>}
<span style="color:#000088">default</span> {<span style="color:#4f4f4f">puts</span> xxx}
} </code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- case流控制
<span style="color:#000000"><code><span style="color:#000088">case</span> abcd in a {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">111</span>} *bc* {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">333</span>} <span style="color:#000088">default</span> {<span style="color:#4f4f4f">puts</span> xxx} </code></span>
- 1
上述程式對字串abcd進行判斷:
條件一 : 字串為a
條件二 : 不管字串的前後字元是啥,只要中間有bc子字串即可
條件三 : default
9>迴圈控制
- foreach迴圈:
假如想要將0,3,2,1按照順序分別放到上述switch的判決條件(列表)裡,輸出四個結果,那就需要這個foreach了:
<span style="color:#000000"><code>foreach i {<span style="color:#006666">0</span> <span style="color:#006666">3</span> <span style="color:#006666">2</span> <span style="color:#006666">1</span>} {
<span style="color:#000088">switch</span> $i {
<span style="color:#006666">1</span> {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">111</span>}
<span style="color:#006666">2</span> {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">222</span>}
<span style="color:#006666">3</span> {<span style="color:#4f4f4f">puts</span> <span style="color:#006666">333</span>}
<span style="color:#000088">default</span> {<span style="color:#4f4f4f">puts</span> xxx}
}
} </code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- for迴圈:
TCL的for迴圈也是很類似C語言的:
<span style="color:#000000"><code><span style="color:#000088">for</span> {set i <span style="color:#006666">0</span>} {$i < <span style="color:#006666">10</span>} {incr i} {
puts $i
}</code></span>
- 1
- 2
- 3
初始化i=0,範圍 i<10 ,迴圈i=i+1
- while迴圈:
<span style="color:#000000"><code><span style="color:#000088">set</span> i <span style="color:#006666">10</span>
<span style="color:#000088">while</span> {<span style="color:#009900">$i</span>!=<span style="color:#006666">5</span>} {
puts <span style="color:#009900">$i</span>
incr i -<span style="color:#006666">1</span>
}</code></span>
- 1
- 2
- 3
- 4
- 5
執行的結果,自己就可以想象了
10>字串轉為命令
eval命令: set a set ; set b i ; set c hello ; eval $a $b $c
上述程式碼就等效於:set i hello
eval將字串的內容,作為命令,執行
11>列印輸出
之前的那個puts命令也是可以列印到命令列,但是,也只是能打印出來而已,而這個format類似於C中的sprintf(用於格式化輸出):
format命令:
format可以這樣用:
<span style="color:#000000"><code><span style="color:#000088">format</span> <span style="color:#009900">"<span style="color:#4f4f4f">%s</span> <span style="color:#4f4f4f">%d</span>"</span> hello <span style="color:#006666">666</span>
set i [<span style="color:#000088">format</span> <span style="color:#009900">"<span style="color:#4f4f4f">%s</span> <span style="color:#4f4f4f">%d</span>"</span> hello <span style="color:#006666">666</span>]</code></span>
- 1
- 2
scan命令:
說到format,剛好一起把scan說了,這兩個命令可以看做是相反的一對, 前者組合成字串,後者把字串拆分後賦值給變數 scan 12.34.56.78 %d.%d.%d.%d a b c d
將12.34.56.78拆分,並分別賦值給a b c d四個變數,命令返回賦值成功的變數的個數
puts命令:
puts當然也可以列印到檔案中
<span style="color:#000000"><code>set f [<span style="color:#000088">open</span> test.txt w]
puts -nonewline <span style="color:#4f4f4f">$f</span> <span style="color:#009900">"hello\n"</span>
puts <span style="color:#4f4f4f">$f</span> <span style="color:#009900">"world"</span>
<span style="color:#000088">close</span> <span style="color:#4f4f4f">$f</span></code></span>
- 1
- 2
- 3
- 4
puts -nonewline $f "hello\n"
表示的是強制不換行列印,否則自動追加一個換行符
檔案系統
基本常用操作:
gets –> 一次讀一行檔案
puts –> 寫入檔案
open –> 開啟檔案
close –> 關閉檔案
flush –> 重新整理緩衝區
cd命令
和shell中的cd一樣
pwd命令
用於檢視當前所在的目錄
open命令
開啟檔案,返回檔案描述符
命令格式:open 檔名 模式
,支援6種模式,和其他程式語言中的檔案IO,也是很相似的,模式如下:
r 模式: 開啟只讀檔案(檔案必須存在)
r+ 模式: 開啟可讀寫檔案[r+和a+模式可以類比]
w 模式: 開啟只寫檔案,若檔案存在則清空內容;若檔案不存在則建立檔案。
a 模式: 以追加方式開啟只寫檔案,若檔案不存在,則建立;如果檔案存在,則會在檔案內容最後面追加寫入的資料
xxxx
理論上說open |檔名 模式
,在檔名前加個“|”符號,可以以管道的模式開啟檔案,但是測試一直沒有成功,之後用到的話再回來解決吧
xxxx
read命令
<span style="color:#000000"><code>set f [<span style="color:#000088">open</span> test.txt r]
<span style="color:#000088">read</span> <span style="color:#4f4f4f">$f</span> <span style="color:#006666">6</span>
<span style="color:#000088">close</span> <span style="color:#4f4f4f">$f</span></code></span>
- 1
- 2
- 3
可以使用eof命令,判斷檔案是否讀完了,eof $f
,讀完返回1,否則返回0
上述程式碼直接從檔案中讀6個位元組;如果想把檔案內容全部讀出,則直接read $f
;如果想一行一行讀則使用gets命令:gets $f
source命令
命令格式:source $f
從對應的檔案中讀出內容,並傳給Tcl解釋執行
tell命令
返回檔案的指標位置,命令格式:tell $f
file命令
命令格式:file option name
option操作選項較多,就直接列個表了,表示如下:
option名稱 | 功能 |
---|---|
dirname | 返回最後一個“/”之前的部分(目錄部分) |
tail | 返回最後一個“/”以後的部分 |
executable | 返回檔案是否可被執行 |
mkdir | 在當前目錄下建立資料夾 |
owned | 判斷檔案是否屬於當前目錄 |
exists | 返回1 表示檔案存在,0 表示檔案不存在 |
extension | 返回檔案的副檔名 |
rootname | 返回去除副檔名後的name |
isdirectory | 判斷是否為目錄 |
isfile | 判斷是否為檔案 |
writable | 判斷檔案是否可寫 |
readable | 判斷檔案是否可讀 |
size | 返回檔案的大小 |
split | 把Windows格式的路徑拆分 |
join | 組合成標準路徑 |
normalize | 返回標準化路徑 |
nativename | 返回原生格式路徑 |
pathtype | 判斷路徑為相對路徑還是絕對路徑 |
type | 返回檔案型別(有file、directory、characterSpecial、blockSpecial、fifo、link、socket) |
delete | 刪除指定檔案,當需要強制刪除非空目錄時(命令格式:file delete -force 目錄名 ) |
copy | 複製檔案(命令格式:file copy 源 目標 ),同樣的-force可以強行覆蓋同名檔案(目標名衝突時) |
rename | 重新命名,同樣可以強制 |
除此之外,file 的 stat 狀態操作選項:
命令格式:file stat name k
,結果存在陣列k裡
glob命令
1)檢視當前目錄下的檔案(類似shell中的ls) glob *
2)檢視當前目錄下特定字尾的檔案 glob *.txt *.tcl
3)檢視當前目錄下的txt、txl、tcl和tct檔案: glob {*t[xc][tl]}
4)檢視當前目錄下的子目錄裡檢視txt、txl、tcl和tct檔案:
用“\”分割路徑,格式為:glob {{目錄1,目錄2等}\\*.字尾}
5)-type選擇檢視型別:
命令格式:glob -type {型別1 型別2 等} 目標目錄
型別有:
型別 | 含義 |
---|---|
b | 塊裝置 |
c | 字元裝置 |
d | 代表目錄 |
f | 檔案 |
l | 代表符號連結 |
p | 代表命名管道 |
s | 代表套接字 |
r | 讀 |
w | 寫 |
x | 可執行 |
seek命令
用於調整檔案指標
命令seek $f 2
,檔案指標定位到序號為2,現在有一個檔名為s1.txt,內容為hello字串,那麼,設計一個程式實現從第三個字串開始讀檔案內容:
info命令獲取資訊
假如建立了一個過程:proc hello { a b c } {puts hi}
執行命令:info args hello
,則返回a b c,引數列表
執行命令:info body hello
,則返回puts hi,函式體 info procs
,返回所有的過程的列表 info procs hello
,如果存在hello過程則返回hello字串,不存在則不返回
info commands
,則列出直譯器支援的所有命令 info commands create_ip
,create_ip是vivado支援的tcl命令,所以這個info返回的值是create_ip,如果不支援該命令的話,則不返回值
info exists kkk
,判斷kkk變數是否存在
info vars
,返回當前變數名的列表 info vars i
,如果存在該i變數則返回i字串,不存在則不返回
info globals
,返回全域性變數的列表 info globals env
,如果存在該env全域性變數則返回env,不存在則不返回
info locals
,返回local變數列表 info locals i
,如果存在該i區域性變數則返回i,不存在則不返回
info hostname
,返回主機名 info cmdcount
,則返回當前直譯器已經執行的命令個數 info tclversion
,返回直譯器版本號
info level
,返回當前的在棧中的絕對位置 info level 1
,如果加了引數數字,則返回該層的命令和引數
注:uplevel命令(連線引數)
既然說了level那就把uplevel命令說了,level值為0代表頂層,level代表在棧中的絕對位置,過程呼叫的時候,一層比一層的level值高1,被呼叫的過程中若想在上一層的環境中執行操作,那麼就需要uplevel命令了
<span style="color:#000000"><code>proc hello {} { uplevel <span style="color:#4f4f4f">set</span> a <span style="color:#009900">"helloworld"</span> }
<span style="color:#4f4f4f">set</span> a hi ; hello ; puts $a</code></span>
- 1
- 2
注:upvar命令(連線變數)
既然說了uplevel那就把upvar命令也說了吧,其類似於uplevel命令,但是其側重的是在不同層之間連線單一變數
<span style="color:#000000"><code>proc hello {a} {upvar $a x ; set x helloworld}
set <span style="color:#4f4f4f">i</span> hi ; hello <span style="color:#4f4f4f">i</span> ; puts $<span style="color:#4f4f4f">i</span></code></span>
- 1
- 2
系統異常、系統監視
catch命令
用於阻止因錯誤而導致的中斷執行,類似python中的異常,執行成功返回0,否則返回1
unknown命令
我將這個指令歸為異常指令
使用方法:首先定義一個unknown過程,這個過程的引數為cwd(命令)和args(引數)
<span style="color:#000000"><code><span style="color:#000088">proc</span> unknown {cwd args} {
puts commend:<span style="color:#4f4f4f">$cwd</span>
puts args:<span style="color:#4f4f4f">$args</span>
}</code></span>
- 1
- 2
- 3
- 4
這樣的話,當有未知命令或者打錯了程式碼的話,就可以通過unknown過程,控制錯誤
time命令 time "set i 10"
,該命令將計算執行的時間
trace命令
監視變數的儲存的命令,感覺暫時用不到,需要用到的時候再看
名稱空間namespace
名稱空間是命令和變數的集合,通過名稱空間的封裝,來保證他們不會影響其它名稱空間的變數和命令
設定新名稱空間
首先定義兩個hello過程,其中一個在hlf名稱空間內,然後測試
<span style="color:#000000"><code>namespace eval hlf {pro hello {} {puts hello_hlf}}
pro hello {} {puts hello_all}</code></span>
- 1
- 2
設定新變數
直接通過set hlf::i 888
,就可以對hlf空間的i進行設定
刪除名稱空間
命令:namespace delete hlf
不同名稱空間共享變數和過程
通過export和import命令,完成一個名稱空間匯出過程,另一個名稱空間將其匯入,完成過程共享
對名稱空間的變數進行設定或訪問
variable命令,以例子說明:
<span style="color:#000000"><code>namespace eval hlf {
<span style="color:#4f4f4f">variable</span> i <span style="color:#006666">5</span>
proc next {} {<span style="color:#4f4f4f">variable</span> i;<span style="color:#009900">return</span> [incr i]}
proc reset {} {<span style="color:#4f4f4f">variable</span> i;<span style="color:#4f4f4f">set</span> i <span style="color:#006666">0</span>}
}</code></span>
- 1
- 2
- 3
- 4
- 5
目前的理解就是可以在同一名稱空間內的不同過程中傳遞變數,也就不深究了
到此為止算是對TCL的基本使用有了一個大致的理解,裡面還有很多具體的函式和函式選項沒有涉及到,如果之後用的到的話再做補充吧,但是我覺得,應對VIVADO的TCL的語法,這些基礎語法應該足夠了的,接下來就是對VIVADO自帶的TCL的庫裡的函式,進行一個瞭解了
之後遇到不懂的命令,就直接輸入命令 -help
,就可以看到一堆幫助了
本文轉自: https://blog.csdn.net/long_fly/article/details/78897158