SV中#和##的区别与用法

在 SystemVerilog 中,### 都是用于延迟 的操作符,但它们的使用场景延迟基准完全不同:

  • #仿真时间延迟 ,用于过程块(initial / always)中,让执行等待一段指定的绝对时间 (由时间单位 timescaletimeunit 决定)。

  • ##时钟周期延迟 ,专门用于断言(SVA,SystemVerilog Assertions) 的序列中,表示等待指定数量的时钟边沿 (通常为时钟的 posedgenegedge)。

下面详细解释并给出示例。


1️⃣ # 延时操作符

语法

复制代码
#<delay>;            // 延迟 <delay> 个时间单位
#(<expression>);     // 延迟由表达式计算出的时间

特点

  • 只能在 过程块 (initial, always, task, function) 中使用。

  • 延迟量可以是常数表达式(表达式结果须为整数或实数)。

  • 时间单位由 timescale 或模块内的 timeunit / timeprecision 指定。

  • 仿真器执行到 #delay 时会挂起当前进程,直到时间前进指定的量后恢复。

示例

复制代码
`timescale 1ns/1ps

module delay_demo;
    logic sig;

    initial begin
        $display("[%0t] start", $time);
        sig = 0;
        #10;                          // 延迟 10 ns
        sig = 1;
        $display("[%0t] after 10ns", $time);
        
        #(5.3);                       // 延迟 5.3 ns(需 timeprecision 支持)
        sig = 0;
        $display("[%0t] after 5.3ns", $time);
        
        // 也可以用表达式
        int d = 20;
        #(d) $display("[%0t] after 20ns", $time);
    end
endmodule

输出示例:

复制代码
[0] start
[10] after 10ns
[15.3] after 5.3ns
[35.3] after 20ns

2️⃣ ## 周期延迟操作符(SVA)

语法

复制代码
##n                // 延迟 n 个时钟周期(n 为正整数或 0)
##[m:n]            // 延迟范围 m 到 n 个时钟周期
##[m:$]            // 从 m 到无穷

特点

  • 只能在断言序列 (sequence) 中使用,不能出现在普通的 initial / always 过程块中(除非作为 assert property 的一部分)。

  • 延迟的基准是时钟 ,由序列中定义的 @(posedge clk)@(negedge clk) 决定。

  • ##1 表示下一个时钟沿,##0 表示当前时钟沿(用于组合)。

  • 可以用于设计并发断言assert property)。

示例

复制代码
module sva_demo;
    logic clk, a, b, c;
    
    // 生成时钟
    initial clk = 0;
    always #5 clk = ~clk;
    
    // 简单序列:在 a 为高的时钟沿之后 2 个时钟周期,b 必须为高
    property p1;
        @(posedge clk) a |=> ##2 b;
    endproperty
    assert property (p1) else $error("Property failed");
    
    // 序列中使用 ##0 表示同一时钟沿的组合(a 和 b 在同一时钟沿同时为高)
    property p2;
        @(posedge clk) a ##0 b;
    endproperty
    assert property (p2) else $error("a and b not both high");
    
    // 使用范围:在 a 为高后的 1~3 个时钟周期内,c 必须为高
    property p3;
        @(posedge clk) a |-> ##[1:3] c;
    endproperty
    assert property (p3) else $error("c not high within 1-3 cycles");
endmodule

注意

  • ## 不能用于过程延时,比如 ##10; 写在 initial 里会报语法错误。

  • 在普通代码中如果需要等待指定数量的时钟周期 ,通常使用 repeat@(posedge clk) 组合,而不是 ##。例如:

    复制代码
    // 等待 5 个时钟上升沿
    repeat(5) @(posedge clk);

3️⃣ 区别总结表

特性 # (仿真延时) ## (周期延迟)
适用领域 过程块(initial/always/task/function) 断言序列(SVA sequence / property
延迟基准 仿真绝对时间(ns/ps等) 时钟周期数(基于指定的时钟边沿)
是否受时钟影响 是,依赖于时钟的变化
时间单位 timescale / timeunit 定义的时间单位 无单位,仅是周期计数
是否可综合 通常不可综合(仅仿真) 断言本身用于验证,不综合为硬件,但可配合形式工具
常见写法 #10;#(5ns)#(delay_expr) ##2##[1:3]##[0:$]

4️⃣ 常见误区澄清

  • 不能在断言外使用 ##:以下代码是错误的

    复制代码
    initial begin
        ##5;   // 编译错误!## 只能用于 sequence/property
    end
  • # 不能用于周期计数 :若想等待 5 个时钟周期,用 #(5*周期时间) 不健壮,因为时钟频率可能改变。正确做法是用 repeat + @(posedge clk)

  • ##0 的特殊性:它不消耗时间,用于在同一时钟沿组合多个信号条件,等价于逻辑与,但在序列中表达更简洁。


✅ 总结一句话

# 是仿真时间延迟,用于过程块等待绝对时间;## 是断言中的时钟周期延迟,用于序列中等待指定数量的时钟边沿。

切记不能混用场景,否则会导致语法错误或仿真行为异常。

相关推荐
Rambo.xia13 小时前
接口协议避坑 · 第5篇:多器件级联时序踩坑实录
fpga开发
紫霄芯语19 小时前
观察者模式在FPGA中断系统的实战重构
观察者模式·fpga开发·重构
ARM+FPGA+AI工业主板定制专家1 天前
国产化RK3576+FPGA架构|晶圆传输机器人高速定位+AI瑕疵检测一体化方案
fpga开发·架构·机器人·嵌入式·fpga·工控·机器人运控
Eloudy2 天前
FPGA (QSFP28 + CMAC US+ RoCEv2) 与 Ubuntu22 + Mellanox 网卡直连分析
fpga开发
szxinmai主板定制专家2 天前
RK3568+FPGA高速并行采集|半导体探针测试设备多通道同步数据采集系统设计
人工智能·嵌入式硬件·计算机视觉·fpga开发
ARM|X86+FPGA工业主板厂家3 天前
RK3588+FPGA+EtherCAT异构架构解析|工业场景如何同时保住AI算力与微秒级运动实时性
人工智能·fpga开发·架构
zlinear数据采集卡3 天前
从“脏信号”到“纳伏级纯净”:硬核拆解DABL7606的多级抗混叠滤波与24位过采样算法
arm开发·科技·嵌入式硬件·fpga开发·开源
尤老师FPGA4 天前
HDMI数据的接收发送实验(二十)
fpga开发
千寻xun4 天前
三、实战篇-NVME SSD控制之FPGA实现(一)
fpga开发·nvme ssd·nvme协议
XMAIPC_Robot4 天前
软硬协同实时控制|RK3588业务调度+FPGA硬件时序,ethercat实现半导体设备微秒级响应(125us)
linux·arm开发·人工智能·fpga开发