4 布尔表达式与HDL信号引用

4.1 问题背景

PSL属性中的核心逻辑原子是布尔表达式。无论是描述“当条件成立时得到响应”的蕴含属性,还是约束“不允许出现某状态”的拒绝属性,最终都要落在具体的信号引用与布尔运算上。实际验证中,大量初学错误并不来自属性时态逻辑本身,而是来自信号引用方式不准确:向量位序写反、位选择方向错误、整向量直接当布尔量使用、跨模块路径缺失、运算符优先级歧义等。

本章学习目标:

  • 掌握信号、向量、位选择、位切片在PSL中的正确引用方式;
  • 理解布尔表达式在PSL时钟采样上下文中的求值语义;
  • 写出无歧义、可综合、可验证的信号引用表达式。

4.2 核心概念

信号(Signal):PSL中直接引用的HDL线网或寄存器量,通常为单比特标量,如 rst_n、hsel。标量信号可以被 PSL 直接当作布尔量使用,但工程上建议显式写成 (rst_n == 1'b1),使验证语义更清晰。

向量(Vector):多位宽总线量,如 haddr[31:0]、data[7:0]。向量不能直接作为布尔量参与 &&、|| 运算,必须通过比较运算或位选择将其转化为单比特值。

位选择与切片(Bit Select / Slice):从向量中取出单比特或连续子段。Verilog 风格为 bus[i]、bus[msb:lsb];VHDL 风格为 bus(i)、bus(msb downto lsb)。PSL 遵循 HDL 原生的位选择规则。

表达式运算符:PSL 布尔表达式支持逻辑非 !、逻辑与 &&、逻辑或 ||、关系比较 ==、!=、<、<=、>=、> 等。运算符优先级与 C/Verilog 基本一致,但复杂表达式必须加括号。

下图展示了从HDL信号引用到PSL求值上下文的核心路径:

HDL信号引用 标量/向量 位选择与切片 [msb:lsb] 运算符组合 ! && || == 布尔表达式 最终真值 PSL求值上下文 时钟边沿采样 时钟边界与 HDL 采样语义决定布尔表达式的最终求值结果

4.3 原理机制:布尔表达式在 PSL 中的求值上下文

PSL 中的布尔表达式不是在仿真器任意时刻连续求值的组合逻辑,而是在时钟边界上采样后得到的确定真值。求值上下文由三部分决定:

  • 时钟约束:表达式在 default clock 指定的边沿计算,例如 posedge clk;
  • 采样语义:时钟边沿触发时,所有信号值取采样值,禁止组合竞争依赖;
  • 不确定状态:形式验证中,X/Z 不参与真值判断,而是按未知态处理。

重要区别:RTL 中的 if (bus) 依赖 Verilog 的“非 0 即真”规则;PSL 布尔表达式则建议显式使用比较运算符,避免向量隐式转换带来歧义。

// 不推荐:向量隐式转布尔
assert always (bus) -> p;

// 推荐:显式比较
assert always (bus != 3'b000) -> p;

4.4 编写无歧义布尔表达式的流程步骤

  1. 定位信号层次:确认信号在 PSL unit 或 HDL 设计层次中可见,必要时使用 hdlpath 完整路径;
  2. 确认类型与位宽:区分标量/向量,记录位宽及位序声明;
  3. 选择位选择或切片:对于总线信号,按需取出特定位或子段,保证索引方向与声明一致;
  4. 选择运算符:使用逻辑运算符、关系运算符,将子表达式组合为单比特结果;
  5. 加括号明确优先级:不依赖记忆中的优先级,为每个子表达式加括号;
  6. 绑定时钟与采样上下文:检查 default clock 是否覆盖当前属性;
  7. 语义检查:在验证工具中运行语法与静态检查,确认表达式无类型错误。

4.5 案例说明:AHB 桥接场景下的信号引用

假设一个 AHB-APB 桥接器,DUT 接口声明片段如下:

module ahb_apb_bridge (
  input wire        hclk,
  input wire        hresetn,
  input wire        hsel,
  input wire        hwrite,
  input wire [2:0]  hsize,
  input wire [31:0] haddr
);

PSL 属性要求:当主设备发起 4 字节或 8 字节写传输时,地址必须按传输宽度对齐。

unit psl_ahb_example {
  default clock = (posedge hclk);
  default disable iff (hresetn == 1'b0);

  // 规则1:4字节传输时,地址低2位必须为 0
  aligned_4byte: assert always 
    (hsel && hwrite && (hsize == 3'b010)) 
    -> (haddr[1:0] == 2'b00);

  // 规则2:8字节传输时,地址低3位必须为 0
  aligned_8byte: assert always 
    (hsel && hwrite && (hsize == 3'b011)) 
    -> (haddr[2:0] == 3'b000);
}

案例要点:

  • hsel && hwrite 使用逻辑与,两个标量信号组合为传输有效条件;
  • hsize == 3'b010 通过比较将向量转化为布尔结果;
  • haddr[1:0] 与 haddr[2:0] 的切片方向与 Verilog 声明完全一致。

4.6 信号引用形式速查表

表达式形式 HDL/PSL 作用 使用建议 常见错误
sig 标量信号作为布尔量 建议显式写 sig == 1'b1 隐式使用标量真值产生歧义
bus 整个向量 不能直接作为布尔量,须比较或位选择 把向量当布尔量参与逻辑运算
bus[3] 取第 3 位 可用于布尔子表达式 位序方向写反
bus[7:4] 取连续 4 位切片 切片方向与声明一致 写成 [4:7]
bus[addr +: 8] Verilog-2001+ 递增切片 动态索引时使用 在 VHDL 中不可用
bus(7 downto 4) VHDL 切片 VHDL 工程使用,保持位序 与 Verilog 风格混淆

4.7 误区提醒

  • 误区 1:位选择方向写反。信号声明为 data[7:0] 时,data[0:3] 非法或语义错误。PSL 严格遵守 HDL 声明位序。
  • 误区 2:把位运算符当作逻辑运算符。在 PSL 序列中 & 代表重叠(overlap)操作,而非逻辑与。布尔表达式应使用 &&、||、!。
  • 误区 3:忽略运算符优先级。例如 a && b || c != d 会被解析为 (a && b) || (c != d),而不是按阅读直觉从左到右。务必加括号。
  • 误区 4:向量整体直接作真值。assert always (bus) 在 Verilog 语义下可能合法,但 PSL 形式验证不推荐,应改为 bus != 0。
  • 误区 5:忘记绑定 default clock。没有时钟边界的布尔表达式在属性中无法确定采样时刻。

4.8 实践清单

写信号引用表达式前的 8 项检查:

  • 信号是否在当前 PSL unit 或 HDL 层次可见;
  • 向量位宽与位序是否和声明一致;
  • 位选择、切片索引是否在有效范围内;
  • 向量是否通过比较运算转化为布尔值;
  • 复杂表达式是否已用括号显式分组;
  • 当前属性是否已被 default clock 覆盖;
  • 是否避免使用位运算符 &、| 作逻辑运算;
  • 是否在验证工具中完成了静态语义检查。

工程建议:评审 PS 属性时,将信号引用部分单独列出,与 RTL 信号声明逐一比对。对位选择、切片和跨模块路径的审查要优先于逻辑运算符审查,因为这类错误定位成本最高。