2. TRACE32脚本语言基础
TRACE32 的 PRACTICE 脚本是调试自动化的核心载体。它不像 C 语言那样需要编译,而是由 TRACE32 的脚本解释器逐行执行,因此非常适合在调试会话中快速构建可复用的测试序列、寄存器检查、内存扫描和批量命令封装。理解 PRACTICE 的语法、变量、运算符、流程控制以及它与 CMM 命令的交互方式,是写出可靠自动化脚本的前提。
脚本结构与基本语法
PRACTICE 脚本通常以 .cmm 为扩展名,由若干行命令组成。每行可以是一条 CMM 命令,也可以是一条 PRACTICE 语句。脚本中大小写不敏感,但为了可读性,建议命令使用大写、变量使用小写。注释使用 // 或 ;,块注释使用 /* ... */。一个最简单的脚本如下:
// 初始化并读取内核寄存器
SYStem.Up
Register.Set PC 0x8000_0000
PRINT "PC = " Register(PC)
其中 SYStem.Up 和 Register.Set 是 CMM 命令,PRINT 是 PRACTICE 的输出语句。PRACTICE 脚本的执行是顺序的,遇到错误默认会中止,除非使用 ON ERROR 或 GOTO 进行错误处理。
变量与数据类型
PRACTICE 的变量不需要显式声明类型,赋值即创建。变量名以字母开头,可包含字母、数字和下划线。常见的数据类型包括:
- 整数:默认 64 位有符号整数,支持十进制、十六进制(
0x)、二进制(0b)和字符常量。 - 浮点数:带小数点的数值,用于计算频率、电压等物理量。
- 字符串:用双引号括起,支持转义字符,常用于拼接命令和输出信息。
- 布尔值:PRACTICE 没有独立布尔类型,通常用 0 表示假、非 0 表示真。
变量赋值示例:
base = 0x8000_0000
offset = 0x100
addr = base + offset
name = "core0"
PRINT "addr = " FORMAT("%08X", addr)
PRACTICE 还支持数组和结构体。数组用 DIM 声明,例如 DIM buf[16] 创建一个 16 元素的数组。结构体则通过 STRUCT 定义,适合组织寄存器组或测试参数。
运算符与表达式
PRACTICE 支持常见的算术、关系和逻辑运算符。算术运算符包括 +、-、*、/、%,以及位运算符 &、|、^、~、<<、>>。关系运算符有 ==、!=、<、>、<=、>=,逻辑运算符为 &&、||、!。表达式可以混合使用,优先级与 C 语言类似。
一个典型的位操作示例:读取状态寄存器,判断第 3 位是否置位:
status = Register(STATUS)
if (status & 0x08) != 0
(
PRINT "Bit3 is set"
)
else
(
PRINT "Bit3 is clear"
)
流程控制
PRACTICE 提供 IF/ELSE、WHILE、REPEAT、FOR 和 GOTO 等流程控制结构。注意 PRACTICE 的块使用圆括号 ( ... ) 而不是花括号,这是初学者最容易出错的地方。
IF 语句用于条件分支,WHILE 在条件为真时循环,REPEAT 至少执行一次直到条件满足,FOR 则适合已知次数的循环。例如,批量读取 8 个连续寄存器的值:
i = 0
while i < 8
(
value = Register(i * 4)
PRINT "Reg[" i "] = " FORMAT("%08X", value)
i = i + 1
)
如果需要在循环中提前退出,可以使用 BREAK;跳过本次循环剩余部分则用 CONTINUE。对于复杂的跳转逻辑,GOTO 配合标签仍然有效,但建议优先使用结构化控制语句,以保持脚本可读性。
与 CMM 命令的交互方式
PRACTICE 脚本与 CMM 命令的交互是双向的:脚本可以调用 CMM 命令,CMM 命令也可以读取脚本变量。最常见的交互方式有三种:
- 直接调用:在脚本中直接写 CMM 命令,如
Data.Set、Register.Set、Go等。 - 函数式调用:使用
Register()、Data.Long()、Address()等函数读取目标状态,返回值可直接赋给变量。 - 参数传递:通过
&前缀将脚本变量传递给 CMM 命令,例如Data.Set &addr %Long 0x12345678。
下面是一个综合示例,演示如何用脚本控制一次内存写入并回读验证:
addr = 0x8000_1000
expected = 0xDEADBEEF
Data.Set &addr %Long expected
actual = Data.Long(addr)
if actual == expected
(
PRINT "Write/Read OK"
)
else
(
PRINT "Mismatch: " FORMAT("%08X", actual)
)
需要注意的是,CMM 命令中的地址和数值通常以十六进制解析,而脚本变量在传递时由 PRACTICE 解释器负责转换。使用 FORMAT() 可以控制输出格式,ADDRESS() 可以获取符号地址,Register() 可以读取寄存器值。这些函数让脚本能够动态适应不同的调试目标。
LOCAL 声明局部变量,减少命名冲突。
脚本执行与调试
在 TRACE32 中执行脚本有三种常用方式:在命令行输入 DO script.cmm、通过 AREA 窗口加载、或在 PRACTICE 对话框中运行。脚本执行过程中,可以使用 PRINT 输出中间变量,也可以使用 Break 命令暂停执行。如果脚本出错,TRACE32 会显示错误行号和错误信息,常见的错误包括括号不匹配、变量未定义、CMM 命令参数类型错误等。
下面这张图展示了 PRACTICE 脚本从编写到执行的完整数据流,以及脚本变量与 CMM 命令之间的交互关系:
从图中可以看出,PRACTICE 脚本负责逻辑组织和变量管理,CMM 命令负责与调试目标交互,两者通过参数传递和函数返回值形成闭环。掌握这个交互模型后,就可以把重复的寄存器检查、内存扫描、批量测试封装成脚本,显著提升调试效率。
SYStem.Up 之前执行 Register.Set 会失败。建议在脚本开头加入状态检查,如 IF !STATE.RUN() PRINT "Target not running",避免因目标状态异常导致脚本中断。
最后,建议把常用操作封装成带参数的 PRACTICE 函数。PRACTICE 支持 ENTRY 和 RETURN 定义子程序,参数通过 & 传递。这样可以把“读寄存器—比较—打印”这样的逻辑复用多次,让脚本更接近工程化的调试工具,而不是一次性命令堆叠。