TCL使用

TCL语言入门

1、TCL解释器运用规则把命令分成一个个独立的单词,同时进行必要的置换。

TCL置换分为以下三类。
变量置换 $
命令置换 []
反斜杠置换
而{} 则会将花括号内部的所有字符都解释称普通字符,不会进行置换
# 表示注释

2、变量、数组、列表

变量

定义变量: set 变量名 变量值
使用变量: $变量名

#普通情况下
set a "snow"
puts $a
#若向实现输出 snow_1,怎样操作?
#此时需要利用{}限定$的解释范围
puts ${a}_1 
#若利用puts $a_1 则会让$解释a_1,但是$a_1没有定义,所以会报错

数组

数组:TCL中数组可以存储很多值,通过元素名来进行检索。类似于某件事物(数组名)几种不同属性(元素名),每一种属性有其独立的值。
定义数组: set 数组名 (元素名) 值
数组取值:puts $数组名(元素名)
获取数组元素个数: array size 数组名
获取数组元素名: array names 数组名

(System32) 11 % set cell_1(ref_name) "bufferx2"
bufferx2
(System32) 12 % set cell_1(full_name) "top/cell_1"
top/cell_1
(System32) 13 % set cell_1(pins) "A B C"
A B C
(System32) 14 % puts $cell_1(ref_name)
bufferx2
(System32) 20 % array size cell_1
3
(System32) 21 % array names cell_1
ref_name pins full_name

列表

列表式标量的有序集合
定义列表: set 列表名 {元素1 元素2 元素3 ......}
列表取值: $列表名

(System32) 31 % set ivt_list {ivtx1 ivtx2 ivtx3}
ivtx1 ivtx2 ivtx3
(System32) 32 % puts $ivt_list
ivtx1 ivtx2 ivtx3
(System32) 33 % 

列表合并,注意,合并之后并未自动生成新列表,若想再次引用,可以利用set 创建新列表,如下的my_list

(System32) 34 % set list1 {bufx1 bufx2 bufx3}
bufx1 bufx2 bufx3
(System32) 35 % set list2 {bufx4 bufx5 bufx6}
bufx4 bufx5 bufx6
(System32) 36 % set list3 {bufx7 bufx8 bufx9}
bufx7 bufx8 bufx9
(System32) 37 % concat $list1 $list2 $list3
bufx1 bufx2 bufx3 bufx4 bufx5 bufx6 bufx7 bufx8 bufx9
#列表合并后利用set生成新列表
(System32) 42 % set my_list [concat $list1 $list2 $list3]
bufx1 bufx2 bufx3 bufx4 bufx5 bufx6 bufx7 bufx8 bufx9
(System32) 43 % puts $my_list
bufx1 bufx2 bufx3 bufx4 bufx5 bufx6 bufx7 bufx8 bufx9
#返回列表中元素个数
(System32) 44 % llength $list1
3
#返回列表中的第2个元素(从0开始计数)
(System32) 45 % set list1 {bufx1 bufx2 bufx3}
bufx1 bufx2 bufx3
(System32) 46 % lindex $list1 2
bufx3
#返回列表中的最后一个元素(一种方法是可以通过查询列表最后一个元素的索引,然后通过lindex找到最后一个元素)
(System32) 51 % lindex $list1 [expr [llength $list1]-1]
f
#在列表尾加入新元素(只能增加一个元素)
(System32) 52 % set a {1 2 3}
1 2 3
(System32) 53 % lappend a 4
1 2 3 4
(System32) 54 % puts $a
1 2 3 4
#直接在数组末尾增加新数组,后一个数组会被视为一个元素,此时类似于二维列表,可以通过先引用到列表b位置,然后再找到4
(System32) 60 % set a {1 2 3}
1 2 3
(System32) 61 % set b {4 5}
4 5
(System32) 62 % lappend a $b
1 2 3 {4 5}
#如何引用4?
(System32) 64 % lindex [lindex [lappend a $b] 3] 0
4
(System32) 65 % 

lsort列表指令

使用: lsort 开关 列表
功能: lsort作用在于将列表按照一定规则排序
开关: 默认按照ASCII码进行排序
-real 按照浮点数大小排序
-unique 删除重复元素

(System32) 65 % set list1 {c d a f b}
c d a f b
(System32) 66 % lsort $list1
a b c d f
(System32) 67 % set list2 {-2  3.1 5 0}
-2  3.1 5 0
(System32) 68 % lsort -real $list2
-2 0 3.1 5
(System32) 69 % set list3 {1 1 2 2 3 3}
1 1 2 2 3 3
(System32) 70 % lsort -unique $list3
1 2 3
(System32) 71 % 

运算

语法格式: expr 运算表达式
功能: 将运算表达式求值
tips: 如果想要进行浮点运算,需要将其中任意一个数值,写成浮点形式(有小数点),否则会出现5/2=2的情况(即可以用5.0/2=2.5得到正确结果)
数值运算
a+b
a-b
a*b
a/b

(System32) 71 % expr 3+4
7
(System32) 72 % 

逻辑运算
a<=b
a>=b
a==b
a!=b

3 控制流

条件指令 if

语法格式: if{判断条件} {
脚本语句
} elseif{判断条件} {
脚本语句
} else {
脚本语句
}
注意,上例中脚本语句的'{'一定要写在上一行,因为如果不这样,TCL解释器会认为命令在换行符处已结束,下一行会被当成新的命令,从而导致错误,同时注意空格的保持

(System32) 7 % if {$a > $b} {
> puts $a
> } else {
> puts $b
> }
3
(System32) 8 % 

循环指令foreach

语法格式: foreach 变量 列表 循环主体
语法功能: 从第0个元素开始,每次按顺序取得列表的一个元素,将其赋值给变量,然后执行循环主体一次,直到列表最后一个元素

(System32) 9 % foreach i $list1 {
> puts $i
> }
1
2
3
(System32) 10 % 

循环控制指令break

语法格式: break
语法功能: 结束整个循环过程,并从循环跳出

(System32) 10 % set list1 {1 2 3}
1 2 3
(System32) 11 % foreach i $list1 {
> if {$i==2} {
> break
> }
> puts $i
> }
1
(System32) 12 % 

循环控制指令continue

语法格式: continue
语法功能: 仅结束本次循环

(System32) 15 % set list1 {3 2 1}
3 2 1
(System32) 16 % foreach i $list1 {
if {$i==2} {
continue
}
puts $i
}
3
1
(System32) 17 % 

循环控制指令while

语法格式: while 判断语句 循环主体
语法功能: 如果判断语句成立(返回值非0),就运行脚本,直到不满足判断条件停止循环,此时while命令中断并返回一个空字符串。

(System32) 17 % set i 3
3
(System32) 18 % while {$i >0} {
> puts $i
> incr i -1; #set i [expr $i -1]
> }
3
2
1
(System32) 19 % 
#其中上述代码中#后的事注释

循环控制指令for

语法格式: for 初始化参数 判断语句 重新初始化参数 循环主体
语法功能: 如果判断语句返回值非0就进入循环,行循环主体后,再重新初始化参数。然后再次进行判断,直到判断语句返回值为0,循环结束。

(System32) 20 % for {set i 3} {$i>0} {incr i -1} {
> puts $i
> }
3
2
1
(System32) 21 % 

4 过程函数

过程函数proc

语法格式: proc 函数名 参数列表 函数主体
语法功能:类似于C语言中的函数。即用户自定义的功能,方便多次调用。

(System32) 23 % proc add {a b} {
> set num [expr $a + $b]
> return $num
> }
(System32) 24 % add 3 4
7
(System32) 25 % 

过程函数中的全局变量和局部变量

全局变量:在所有过程之外定义的变量。
局部变量:对于在过程中定义的变量,因为它们只能在过程中被访问,并且当过程退出时会被自动删除。
指令global,可以在过程内部引用全部变量

#在proc内部使用gloabal引用全局变量
(System32) 25 % set a 1
1
(System32) 26 % proc sample {x} {
> global a
> set a [expr $a +1]
> return [expr $a + $x]
> }
(System32) 27 % sample 3
5
(System32) 28 % puts $a
2
(System32) 29 % 

#没有在proc内部使用global引用全局变量导致出错
(System32) 31 % set a 1
1
(System32) 32 % proc sample {x} {
set a [expr $a +1]
return [expr $a + $x]
}
(System32) 33 % sample 3
can't read "a": no such variable
(System32) 34 % 

5 正则匹配

定义:正则表达式是一种特殊的字符串模式,用来去匹配符合规则的字符串。
\w : 匹配一个字母、数字、下划线
\d : 匹配一个数字

  • :匹配0次或者多次
  • : 匹配一次或者多次
    ? :匹配零次或者一次
    \s : 匹配空格
    . : 匹配任意一个字符
    ^ : 字符串开头(这是一个锚位,用来指示字符串当中的开头和结尾的位置,使我们能够匹配到正确的字符)
    $ : 字符串结尾(这是一个锚位,用来指示字符串当中的开头和结尾的位置,使我们能够匹配到正确的字符)

正则匹配指令regexp

语法格式: regexp ? switches ? exp string ? matchVar? ?subMatchVar subMatchVar ... ?
语法功能: 在字符串中使用正则表达式匹配

  • switches:
    -nocase将字符串中的大写都当成小写看待。
  • exp正则表达式
  • string用来进行匹配的字符串
  • matchstring表示用正则表示式匹配的所有字符串
  • sub1表示正则表达式中的第一个子表达式匹配的字符串
  • sub2表示正则表达式中的第二个子表达式匹配的字符串
#匹配字符串"abc456"
(System32) 34 % regexp {\w+\d+} "abc456"
1
#匹配以数字开头且以数字结尾的字符串
(System32) 35 % regexp {^\d.*\w$} "1 dfsal 1"
1
(System32) 36 % 

捕获变量()

语法功能:通过()可以捕获字符串

#通过正则匹配得到total结果= 30 years old
#通过()捕获了age结果=30
(System32) 36 % regexp {\s(\d+).*} "Snow is 30 years old" total age
1
(System32) 37 % puts $total
 30 years old
(System32) 38 % puts $age
30
#通过()捕获了多个值
(System32) 39 % regexp {^(\w+)\s\w+\s(\d+).*} "Snow is 30 years old" total name age
1
(System32) 40 % puts $total
Snow is 30 years old
(System32) 41 % puts $name
Snow
(System32) 42 % puts $age
30
(System32) 43 % 

6 文本处理

常用语法
open
gets
close

  • open
    语法格式: open 文件 打开方式 (打开方式:r代表读模式,w代表写模式)
    语法功能: 打开文件
  • gets
    语法格式: gets fileid 变量名
    语法功能: gets读fileld标识的文件的下一行,并把该行赋给变量,并返回该行的字符数(文件尾返回 -1)
  • close
    语法格式: close fileid
    语法功能: 关闭文件
#读取文件
(Desktop) 52 % set INPUTFILE [open file.txt r]
file1a75e298e40
(Desktop) 53 % while {[gets $INPUTFILE line] >=0 } {
> puts "$line"
> }
a
b
c
(Desktop) 55 % close $INPUTFILE
#写入文件并且读取
(Desktop) 60 % set OUTPUTFILE [open file.txt w]
file1a75e283270
(Desktop) 61 % puts $OUTPUTFILE "hello world"
(Desktop) 62 % close $OUTPUTFILE
(Desktop) 63 % set INPUTFILE [open file.txt r]
file1a75e2d62d0
(Desktop) 64 % while {[gets $INPUTFILE line] >=0 } {
> puts "$line"
> }
hello world
(Desktop) 65 % close $INPUTFILE

例子

有文本如下:

#dc.log
Slack=-0.051
Slack=-0.234
Slack=-0.311
Slack=-0.056
Slack=-0.434

利用tcl提取所有Slack之和
tcl脚本如下

set sum 0
set INFILE [open "dc.log" r]
while {[gets $INFILE line] >= 0} {
    if {[regexp {^Slack\s+=\s+(-?\d+\.?\d+)} $line match slack]} {
        set sum [expr $sum + $slack]  ;
    }
}
close $INFILE

#测试结果
(Desktop) 40 % while {[gets $INFILE line] >= 0} {
>     if {[regexp {^Slack\s+=\s+(-?\d+\.?\d+)} $line match slack]} {
>         set sum [expr $sum + $slack]  ;
>     }
> }
(Desktop) 41 % close $INFILE
(Desktop) 42 % puts $sum
-1.086
(Desktop) 43 % 
#正则匹配查找
regexp {([0-9]+)\s([a-z]+)}  "there is 100 apples" total num word
# 1
echo $num
# 100
echo $total
# 100 apples

#正则匹配替换
#regsub switchs matching_pattern string replace_string final_string
regsub there "The live there lives" their x
# 1
echo $x
# The live their lives

Synopsys TCL 语言入门

Part-1:TCL 语言

1 DC中常用的TCL指令

  • get_ports portsName
    功能: 返回design中对应的ports object
  • get_cells cellsName
    功能:返回design中对应的cell的instance name object
  • note:什么是reference?instance?
    例如:
    module ADDER();
    .....
    endmodule
    module test();
    ADDER u_ADDER();
    endmodule
    其中ADDER是一个reference,u_ADDER是一个instance
top模块



//**************************************************************************
// *** 名称 : asFIFO.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2020年6月
// *** 描述 : 异步FIFO,读写位宽相同,默认写先读后
//**************************************************************************
module asFIFO
//========================< 参数 >==========================================
#(
parameter DATA_W            = 8                 ,   //数据位宽
parameter ADDR_W            = 4                     //地址位宽
)
//========================< 端口 >==========================================
(
input                       rst_n               ,   //复位
//FIFO写 ----------------------------------------
input                       wr_clk              ,   //写时钟
input                       wr_en               ,   //写使能
input       [DATA_W-1:0]    wr_data             ,   //写数据
output                      wr_full             ,   //写满
//FIFO读 ----------------------------------------
input                       rd_clk              ,   //读时钟
input                       rd_en               ,   //读使能
output  reg [DATA_W-1:0]    rd_data             ,   //读数据
output                      rd_empty                //读空
);
//========================< 信号 >==========================================
reg     [ADDR_W  :0]        wr_addr_ptr         ;   //写指针,多1位
reg     [ADDR_W  :0]        rd_addr_ptr         ;   //读指针,多1位
wire    [ADDR_W  :0]        wr_addr_gray        ;   //写地址_格雷码
reg     [ADDR_W  :0]        wr_addr_gray_r      ;   //写地址打拍
reg     [ADDR_W  :0]        wr_addr_gray_rr     ;   //写地址打拍
wire    [ADDR_W  :0]        rd_addr_gray        ;   //读地址_格雷码
reg     [ADDR_W  :0]        rd_addr_gray_r      ;   //读地址打拍
reg     [ADDR_W  :0]        rd_addr_gray_rr     ;   //读地址打拍
//-----------------------------------------------
wire    [ADDR_W-1:0]        wr_addr             ;   //写地址
wire    [ADDR_W-1:0]        rd_addr             ;   //读地址
reg     [DATA_W-1:0]        ram[2**ADDR_W-1:0]  ;   //ram,地址位宽4,共16个
//==========================================================================
//==    地址指针
//==========================================================================
always @(posedge wr_clk or negedge rst_n) begin
    if(!rst_n) begin
        wr_addr_ptr <= 0;
    end
    else if(wr_en & (!wr_full)) begin
        wr_addr_ptr <= wr_addr_ptr + 1;
    end
end

always @(posedge rd_clk or negedge rst_n) begin
    if(!rst_n) begin
        rd_addr_ptr <= 0;
    end
    else if(rd_en & (!rd_empty)) begin
        rd_addr_ptr <= rd_addr_ptr + 1;
    end
end
//==========================================================================
//==    空满信号
//==========================================================================
//-- 格雷码转换
//---------------------------------------------------
assign wr_addr_gray = (wr_addr_ptr>>1) ^ wr_addr_ptr;
assign rd_addr_gray = (rd_addr_ptr>>1) ^ rd_addr_ptr;

//-- 跨时钟域,打两拍
//---------------------------------------------------
always @(posedge wr_clk) begin
    rd_addr_gray_r  <= rd_addr_gray;
    rd_addr_gray_rr <= rd_addr_gray_r;
end

always @(posedge rd_clk) begin
    wr_addr_gray_r  <= wr_addr_gray;
    wr_addr_gray_rr <= wr_addr_gray_r;
end

//-- 写满标志:高2位不同,其余位相同
//---------------------------------------------------
assign wr_full  = (wr_addr_gray == ({~rd_addr_gray_rr[ADDR_W-:2],rd_addr_gray_rr[ADDR_W-2:0]}));

//-- 读空标志:读写地址相同
//---------------------------------------------------
assign rd_empty = (rd_addr_gray == wr_addr_gray_rr);
//==========================================================================
//==    ram读写
//==========================================================================
//-- 读写地址
//---------------------------------------------------
assign wr_addr = wr_addr_ptr[ADDR_W-1:0];
assign rd_addr = rd_addr_ptr[ADDR_W-1:0];

//-- 写数据
//---------------------------------------------------
integer i;
always @(posedge wr_clk or negedge rst_n) begin
    if(!rst_n) begin
        for(i=0; i<2**ADDR_W; i=i+1)
            ram[i] <= 0;
    end
    else if(wr_en & (!wr_full)) begin
            ram[wr_addr] <= wr_data;
    end  
end

//-- 读数据
//---------------------------------------------------
always @(posedge rd_clk or negedge rst_n) begin
    if(!rst_n) begin
        rd_data <= 0;
    end
    else if(rd_en & (!rd_empty)) begin
        rd_data <= ram[rd_addr];
    end
end

wire flag;
adder u_adder(
.clk(wr_clk),
.rst_n(rst_n),
.flag(flag)
);
endmodule
sub模块
module adder(
input   clk,
input   rst_n,
output  reg flag
);
//************************< 代码 >******************************************
always@(posedge clk or negedge rst_n)begin
    if(rst_n == 1'b0)begin
        flag <= 1'b0;
    end else begin
        flag <= 1'b1; 
    end
end
endmodule
  • 原理图如下:

####查找是否有wr_clk的port在design中
design_vision> get_ports wr_clk
{wr_clk}
#####查找是否有AAA的port
design_vision> get_ports AAA
Warning: Can't find port 'AAA' in design 'asFIFO'. (UID-95)
#####查找所有port
design_vision> get_ports *
{wr_data[7] wr_data[6] wr_data[5] wr_data[4] wr_data[3] wr_data[2] wr_data[1] wr_data[0] rd_data[7] rd_data[6] rd_data[5] rd_data[4] rd_data[3] rd_data[2] rd_data[1] rd_data[0] rst_n wr_clk wr_en wr_full rd_clk rd_en rd_empty}
#####查找以wr_开头的port
design_vision> get_ports wr_*
{wr_data[7] wr_data[6] wr_data[5] wr_data[4] wr_data[3] wr_data[2] wr_data[1] wr_data[0] wr_clk wr_en wr_full}
#####查找design中有无u_adder 的cell
design_vision> get_cells u_adder
{u_adder}
posted @ 2023-09-10 01:49  就很胖  阅读(408)  评论(0编辑  收藏  举报