一、写在前面

一个数字芯片工程师核心竞争力是什么?不同的工程师可能给出不同的答复,有些人可能提到硬件描述语言,有些人可能会提到对于特定算法和协议的理解,有些人或许会提到对于软硬件的结合划分,作者想说,这些说法,其实对也不对,硬件描述语言,翻来覆去无非是always和assign这几个语句的反复使用,而一些基础的协议算法深究起来其实也并不复杂,于作者而言,在常规的技能以外,有两项额外的技能颇为重要,其中之一便为sdc/STA的分析能力,它的重要之处在于作为桥梁建立了前端和后端的连接,虽然对于DE工程师而言,初版交付的sdc往往不甚准确,也没有办法通过这份sdc生成一份无误的timing report,但sdc的内容体现却是完完整整的将时序约束从行为级的描述映射到了gate level这样一个真实的电路层次上面。
写此专栏,一为学习记录,二为交流分享,以犒粉丝读者。

1.1 快速导航链接·

静态时序分析简明教程(一)绪论
静态时序分析简明教程(二)基础知识:建立保持时间,违例修复,时序分析路径
静态时序分析简明教程(三)备战秋招,如何看懂一个陌生的timing report
静态时序分析简明教程(四)时钟常约束
静态时序分析简明教程(五)生成时钟
静态时序分析简明教程(六)时钟组与其他时钟特性
静态时序分析简明教程(七)端口延迟
静态时序分析简明教程(八)虚假路径
静态时序分析简明教程(九)多周期路径


二、Tcl基础知识

SDC的约束基于Tcl语言。通过使SDC扩展到Tcl,基于工具的命令可以和原生Tcl的结构,如变量,表达式,语句和子程序相混合,实现更为强大的功能,因此,作为SDC约束的提供方,对Tcl命令的理解,本身也是IC技能中颇为重要的一个方面。

Tcl是由加州大学伯克利分校开发的常用脚本语言,它是一种解释语言,每条语句被以此解析并立即执行, 在Tcl脚本遇到第一个错误的时候就会立刻停止。

Tcl脚本遵循一些基本的语义,总结起来是以下四点

  1. 每条Tcl以换行符或分号结束;
  2. 如果一条语句跨越多行,然后再下一行继续执行,需要在行尾加反斜杠
  3. 双引号和大括号括住的包括多个单词的字符串被认定为单元
  4. #开头的语句是注释

给出两个简单的例子,帮助读者们快速get以上四条的含义

三、Tcl的语言结构

Tcl的语言结构可以区分为以下几种

  1. 变量
  2. 列表
  3. 表达式与运算符
  4. 控制流语句
  5. 过程

接下来我们将逐一讲解其含义

3.1 Tcl变量

Tcl变量是ASCII字符串,变量使用set命令来分配(Example1),如果要对变量求值,需要使用“$“符号(Example2),因为”$“的特殊含义,因此假如想要打印这个变量,需要”\$",多一个“\”符号(Example3)

3.2 Tcl表达式与运算符

Tcl中使用expr命令来对表达式求值

两条expr命令将返回相同的值,但是Tcl建议表达式使用大括号,这有助于程序更快地执行。
下面的表格将列出Tcl所支持的运算符

3.3 Tcl的控制流语句

Tcl的控制流语句由以下种类的结构组成
1.列表遍历
2.决策
3.循环
4.子程序

3.3.1 列表遍历

Tcl提供了foreach结构来遍历列表,案例如下

# 创建一个包含元素的列表
set my_list {apple banana orange}

# 使用 foreach 命令遍历列表
foreach item $my_list {
    # 输出当前列表元素
    puts "Item: $item"
}

它会有如下的输出结果

Item: apple
Item: banana
Item: orange

3.3.2 决策

Tcl提供if-else if-else的结构来提供决策能力,举例如下:

# 假设有一个变量 age 表示年龄
set age 25

# 使用 if-else if-else 结构进行决策
if {$age < 18} {
    puts "未成年人"
} elseif {$age >= 18 && $age < 60} {
    puts "成年人"
} else {
    puts "老年人"
}

其输出的结果如下:

成年人

3.3.3 Tcl循环

当程序想在一个条件下循环和终止时,可以使用Tcl提供的for和while语句,它还提供了两个额外的结构,break和continue,其中break用提提前结束循环,而continue用于停止执行当前代码的循环,并重新评估当前循环的代码。
for语句的循环举例如下:

# 使用 for 循环输出数字从15
for {set i 1} {$i <= 5} {incr i} {
    puts $i
}

运行上面的代码会产生如下的输出

1
2
3
4
5

while语句的循环举例如下:

# 使用 while 循环计算数字的阶乘
set num 5
set factorial 1
while {$num > 0} {
    set factorial [expr $factorial * $num]
    incr num -1
}
puts "5的阶乘是: $factorial"

它会产生如下的输出结果

5的阶乘是: 120

break语句的举例如下

# 使用 while 循环打印数字,直到遇到数字 4 时终止循环
set i 1
while {$i <= 10} {
    puts $i
    if {$i == 4} {
        break  ;# 当 i 等于 4 时终止循环
    }
    incr i
}

在这个示例中,我们使用 while 循环打印数字从 1 到 10。然而,当 i 的值等于 4 时,我们使用 break 语句提前终止了循环的执行,因此循环只会打印数字 1 到 3。以上的代码将会输出如下的结果

1
2
3
4

3.3.4 Tcl过程

在Tcl中,过程可以通过 proc 命令定义,用于封装一系列命令,形成一个可重复使用的代码块,以下是一个例子

# 定义一个计算两个数之和的过程
proc add_numbers {num1 num2} {
    set sum [expr $num1 + $num2]
    return $sum
}

# 调用定义的过程来计算和
set result [add_numbers 10 20]
puts "计算结果是: $result"

其结果输出如下:

计算结果是: 30

3.4 其他Tcl命令

以下是一些常用的Tcl命令

3.4.1 open/close

文件句柄,用来打开和关闭文件

#以写模式打开文件"file.txt"
set fhandle [open "file.txt" w] 
#关闭文件句柄
close $fhandle

3.4.2 gets/puts

获取字符串或打印字符串,举例如下:

# 提示用户输入姓名
puts "请输入您的姓名:"
# 使用 gets 命令读取用户输入的一行数据
gets stdin name

# 提示用户输入年龄
puts "请输入您的年龄:"
# 使用 gets 命令读取用户输入的一行数据
gets stdin age

# 使用 puts 命令输出用户输入的信息
puts "您的姓名是:$name"
puts "您的年龄是:$age"

在这个示例中,我们首先使用 puts 命令提示用户输入姓名,并使用 gets 命令从标准输入读取用户输入的姓名。然后,我们再次使用 puts 命令提示用户输入年龄,并使用 gets 命令从标准输入读取用户输入的年龄。最后,我们使用 puts 命令将用户输入的姓名和年龄输出到标准输出。
运行上述代码将会产生类似于以下的交互过程:

请输入您的姓名:
John Smith
请输入您的年龄:
28
您的姓名是:John Smith
您的年龄是:28

3.4.3 catch

在Tcl中,catch 命令用于捕获可能引发异常的代码块,并在发生异常时进行处理。以下是一个使用 catch 命令的示例

# 尝试将一个非数字字符串转换为整数
set input "abc"
catch {
    set number [expr $input]
} result

# 检查是否捕获到异常
if {[catch "set number [expr $input]" result]} {
    puts "捕获到异常:$result"
} else {
    puts "转换结果为:$number"
}

在这个示例中,我们首先尝试将字符串 “abc” 转换为整数,这是不合法的操作,会引发异常。我们使用 catch 命令来捕获可能发生的异常,并将异常信息存储在变量 result 中。然后,我们检查是否捕获到异常,如果捕获到异常,则输出异常信息;否则,输出转换结果。
运行上述代码将会输出:

捕获到异常:expected integer but got "abc"

3.4.4 info

从Tcl解释器获取信息所使用的命令

3.4.5 source

在 Tcl 编程语言中,source 命令用于在当前脚本中执行另一个 Tcl 脚本文件。通过使用 source 命令,可以将另一个脚本文件中的代码嵌入到当前脚本中执行,从而实现模块化和代码重用。

3.4.6 incr

在 Tcl 编程语言中,incr 是一个内置命令,用于增加变量的值。它可以用于增加整数变量或双精度浮点数变量的值。

# 增加整数变量的值
set count 5
incr count   ;# 将 count 增加 1
puts "增加后的值是: $count"

# 增加整数变量的值,并指定增量
set value 10
incr value 2   ;# 将 value 增加 2
puts "增加后的值是: $value"

# 增加双精度浮点数变量的值
set total 3.5
incr total 1.2   ;# 将 total 增加 1.2
puts "增加后的值是: $total"

上面的代码会输出如下的结果

增加后的值是: 6
增加后的值是: 12
增加后的值是: 4.7

3.4.7 exit

exit 是一个内置命令,用于终止当前脚本的执行,并退出 Tcl 解释器。您可以使用 exit 命令来在特定条件下终止脚本的执行,或在脚本执行完毕后退出解释器。

四、总结

本文中,我们总结了Tcl语句的相关使用方法,提供了大量的案例来讲解:Tcl的变量、表达式、运算符列表遍历、决策、循环、Tcl过程,其中还会涉及到额外的语句如open/close、gets/puts、catch、info、source、incr、exit。

08-21 06:22