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

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

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

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

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


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 的特殊性:它不消耗时间,用于在同一时钟沿组合多个信号条件,等价于逻辑与,但在序列中表达更简洁。


✅ 总结一句话

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

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

相关推荐
狂奔蜗牛(bradley)1 小时前
拒绝SOEM黑盒!死磕EtherCAT主站:ARM+FPGA架构、DC同步与状态机修复等,50+篇实战开发文档全公开
arm开发·fpga开发·架构
XMAIPC_Robot4 小时前
CODESYS 实时控制 + RK182X 大模型算力扩展|RK3576 工业边缘控制器设计
人工智能·fpga开发·机器人·rk3588+fpga
女神下凡6 小时前
芯参谋(31):SPI NOR Flash 电路设计指南
arm开发·单片机·嵌入式硬件·fpga开发·设计规范
学习FPGA的电气小兴兴9 小时前
基于FPGA的CORDIC旋转模式实现sin和cos运算_采用EGo1板卡上板验证【FPGA数字信号处理第5讲】
fpga开发·信号处理·数字信号处理·verilog·cordic·ego1·fpga设计入门与提高
博览鸿蒙6 天前
FPGA开发使用的语言
fpga开发·fpga
明德扬7 天前
机器人多摄像头如何做FPGA多路视频聚合?
学习·fpga开发·fpga
JoYER_cc7 天前
FPGA 调试实录:LED 闪烁程序从踩坑到仿真验证的完整经验总结
fpga开发
啄缘之间7 天前
1.【SVA】什么是SVA?
经验分享·学习·测试用例·verilog·sva
ktd0077 天前
复旦微开发环境搭建流程备忘录
fpga开发
ERROR:997 天前
陈工,试试Agent开发FPGA
fpga开发