1. 程式人生 > >VIVADO 之 TCL指令碼工具 (基本語法)

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型別的變數,所以當進行數字運算的時候,需要用到increxpr操作命令

· 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