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


✅ 总结一句话

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

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

相关推荐
404是NotFound呀6 小时前
[FPGA] Ubuntu 22.04 安装 Vivado 2023.1 和 PetaLinux 踩坑记录
linux·ubuntu·fpga开发
liuluyang5308 小时前
SV中if与iff区别与用法
fpga开发·sv
高速上的乌龟9 小时前
Lattice LFCPNX-100 HSB+Fpga开发详解:2.2 Marvell MV-Q3244 Phy的Podl电路详解
单片机·嵌入式硬件·fpga开发·软件工程
zlinear数据采集卡13 小时前
深入底层:从SAR ADC原理到模拟前端设计,解析高精度数据采集卡的硬件架构
c语言·前端·嵌入式硬件·fpga开发·自动化·硬件架构
夜幕下的灯火14 小时前
基于 FPGA 的 SD 卡音频播放与电子琴系统
fpga开发·毕业设计·课程设计·fpga·altera
weiweiliulu14 小时前
FPGA和MATLAB仿真测试常会用的语句
fpga开发
FPGA_小田老师1 天前
PCIe XDMA数据传输:三种工作模式详解(ARM发起 → FPGA自主)
fpga开发·pcie·xdma·c2h·fpga触发传输
GateWorld2 天前
LCD显示技术完全指南:原理·制造·驱动·FPGA实现之驱动四
fpga开发·lcd显示·fpga点亮屏幕·minilvds·fpga点屏
喵喵苗2 天前
【Vivado2024.2】纯PL端128×128 Sobel边缘检测IP封装 | 单AXI4-Stream接口设计与仿真验证
人工智能·fpga开发