SVA学习之路(1)— SystemVerilog Assertion简介与实战

SVA学习之路(1)--- SystemVerilog Assertion简介与实战

一、前言

在数字电路设计验证中,传统的验证方法往往需要编写大量的测试向量和复杂的测试环境。然而,随着设计复杂度的增加,这些方法变得越来越低效。SystemVerilog Assertion(SVA)作为一种声明式验证方法,正成为硬件验证工程师的必备技能。

SVA允许你在设计中直接嵌入属性描述,实时监控设计行为,及早发现错误,大大提高验证效率和设计质量。

SVA是SystemVerilog语言的一部分,专门用于描述设计行为的时序属性。它不改变设计功能,而是作为"监控器"嵌入到设计中,检查设计是否按照预期行为运行。

二、立即断言(Immediate Assertions)

立即断言在当前仿真时刻立即检查条件是否成立,不依赖时钟,类似于if语句中的条件检查,语法简单,适合检查组合逻辑或单周期信号。​

编写代码文件tb.sv如下所示

systemverilog 复制代码
module tb;
    reg a,b;

    initial begin
        a = 0; b = 0;

        #10ns; a = 1;
        assert(a&b);

        #10ns; b = 1;
        assert(a&b);
        
        #10ns; a = 0;
        assert(a&b);
    end

    initial begin
        $timeformat(-9, 2, "ns", 10);
        $fsdbDumpfile("test.fsdb");
        $fsdbDumpvars(0, tb);
        $fsdbDumpSVA(0, tb);
        #100ns;
        $finish(2);
    end

endmodule

编写运行makefile文件如下所示:

bash 复制代码
all: comp sim

comp:
	vcs -full64 -kdb -sverilog -debug_access+all -timescale=1ns/1ps tb.sv

sim:
	./simv

verdi:
	verdi tb.sv -ssf test.fsdb &

运行日志如下,可以看到打印了两次失败

使用verdi查看如下所示,在波形上可以看到两次失败的示意箭头

三、并发断言(Concurrent Assertions)

并发断言是基于时钟边沿检测时序逻辑的行为。它在仿真过程中持续检测监控信号的时序关系。

区别即时断言和并发断言的关键词是"property",编写代码文件tb.sv如下所示

systemverilog 复制代码
module tb;
    reg a,b;
    reg clk;

    assert property(
        @(posedge clk) a&b==1'b1
    );

    initial begin
        clk <= 1'b0;
        forever #2ns clk <= ~clk;
    end

    initial begin
        a = 0; b = 0;
        #10ns; a = 1;
        #10ns; b = 1;
        #10ns; a = 0;
    end

    initial begin
        $timeformat(-9, 2, "ns", 10);
        $fsdbDumpfile("test.fsdb");
        $fsdbDumpvars(0, tb);
        $fsdbDumpSVA(0, tb);
        #100ns;
        $finish(2);
    end

endmodule

运行日志如下,可以看到打印了多次失败

使用verdi查看如下所示,在波形上可以看到多次失败的示意箭头

如果想要查看成功的示意箭头,添加运行时选项如下所示:

powershell 复制代码
	./simv +fsdb+sva_success

重新查看波形如下所示,可以看到成功的示意箭头

四、时钟检测

编写如下代码检测时钟信号clk,频率为10MHz,占空比为50%。

verilog 复制代码
module tb;
    reg clk;
    reg rst_n;

    // Clock genrate
    initial begin
        clk = 1'b0;
        forever begin
            #50 clk = 1'b1;
            #50 clk = 1'b0;
        end
    end

    // Reset genrate
    initial begin
        rst_n <= 1'b0;
        repeat(10) @(posedge clk);
        rst_n <= 1'b1;
    end

    // ==================== SVA ====================
    // Check 10MHz, period for 100ns
    property clk_period_check;
        realtime rise_time, current_period;
        @(posedge clk)
        disable iff (!rst_n)
        (1, rise_time = $realtime)
        ##1 (clk === 1'b0, current_period = $realtime - rise_time)
        ##0 (current_period) inside {[99900ps:100100ps]};
    endproperty
    
    // Check 50% duty
    property clk_duty_cycle_check;
        realtime rise_time, duty_time;
        @(posedge clk)
        disable iff (!rst_n)
        (1, rise_time = $realtime) |->
        @(negedge clk) (clk === 1'b1, duty_time = $realtime - rise_time)
        ##0 (duty_time) inside {[49900ps:50100ps]};
    endproperty
    
    check_clk_period : assert property (clk_period_check) 
        else $error("Clock period error! Expected 100ns");

    check_clk_duty_cycle : assert property (clk_duty_cycle_check)
        else $error("High level duty cycle error! Expected 50ns");

    initial begin
        $timeformat(-9, 2, "ns", 10);
        $fsdbDumpfile("test.fsdb");
        $fsdbDumpvars(0, tb);
        $fsdbDumpSVA(0, tb);
        #100us;
        $finish(2);
    end

endmodule
相关推荐
charlie1145141911 小时前
嵌入式现代C++教程: 构造函数优化:初始化列表 vs 成员赋值
开发语言·c++·笔记·学习·嵌入式·现代c++
IT=>小脑虎1 小时前
C++零基础衔接进阶知识点【详解版】
开发语言·c++·学习
#眼镜&2 小时前
嵌入式学习之路2
学习
码农小韩2 小时前
基于Linux的C++学习——指针
linux·开发语言·c++·学习·算法
微露清风2 小时前
系统性学习C++-第十九讲-unordered_map 和 unordered_set 的使用
开发语言·c++·学习
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [fs]seq_file
linux·笔记·学习
行业探路者3 小时前
二维码标签是什么?主要有线上生成二维码和文件生成二维码功能吗?
学习·音视频·语音识别·二维码·设备巡检
li星野3 小时前
OpenCV4X学习—核心模块Core
人工智能·opencv·学习
@zulnger3 小时前
python 学习笔记(多线程和多进程)
笔记·python·学习
凉、介3 小时前
SylixOS 中的 Unix Socket
服务器·c语言·笔记·学习·嵌入式·sylixos