当前位置: 首页 > article >正文

【IC验证】verilog及systemverilog特殊特性的分析

verilog及systemverilog特殊特性的分析

  • 1.概述
  • 2.赋值延迟
    • (0)总结
    • (1)情况一:initial中进行阻塞赋值和非阻塞赋值(不延迟)
      • a代码
      • b 电路图
      • c 结果
    • (2)时钟
      • a 代码
      • b 电路图
      • c 结果
    • (3)always过程块实现时序逻辑(延迟)
      • a 代码
      • b 电路图
      • c 结果
    • (4)always过程块实现组合逻辑(延迟)
      • a 代码
      • b 电路图
      • c 结果
    • (5)assign连续赋值语句实现组合逻辑(延迟)
      • a 代码
      • b 电路图
      • c 结果
    • (6)接口中的时钟(延迟)
      • a 代码
      • b 电路图
      • c 结果
    • (7)触发事件(延迟)
      • a代码
      • b 电路图
      • c 结果
  • 3.仿真软件的采样时刻
    • (1)在过程块中:时钟触发沿和数据改变沿同时刻
      • a代码
      • b结果
    • (2)在clocking block中:时钟触发沿和数据改变沿同时刻(完全一致)
      • a代码
      • b结果
  • 4.并行块代码的执行
    • 1.代码的执行时间(按照仿真结果总结出的,不具有理论依据)
  • 5.对模块中成员的调用
    • (1)问题
    • (2)例子(以模块为例)
  • 6.模块和类的静态与动态

1.概述

本文主要汇总分析verilog及systemverilog学习过程中出现的特殊问题;

2.赋值延迟

(0)总结

always过程块实现时序逻辑和组合逻辑和连续赋值语句赋值要消耗仿真时间;
接口内部的时钟,会比外部提供的时钟,存在延迟;
触发事件,@xxx,存在延迟;

(1)情况一:initial中进行阻塞赋值和非阻塞赋值(不延迟)

a代码

module test_tb;
    reg [3:0]   data1;
    reg [3:0]   data2;
    initial begin
        data1 = 0;
        data2 <= 0;
        #5;
        data1 = 1;
        data2 <= 1;
    end
endmodule

b 电路图

initial过程块不可综合;

c 结果

结论:initial过程块中直接赋值不消耗时间;
在这里插入图片描述

(2)时钟

a 代码

module test_tb;
	reg clk;
    initial begin
        clk = 1'b0;
    end
    always#(10) clk = !clk;
endmodule

b 电路图

延时语句不可综合;

c 结果

结论:时钟赋值不消耗时间;
在这里插入图片描述

(3)always过程块实现时序逻辑(延迟)

a 代码

module test_tb;
	parameter T =20;
    reg clk;
    reg rst_n;
    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        #(T);
        rst_n = 1'b1;
    end
    always#(T/2) clk = !clk;
    reg [3:0] cnt1;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            cnt1 <= 'd0;
        else
            cnt1 <= cnt1+1'b1;
    end
endmodule

b 电路图

在这里插入图片描述

c 结果

结论:综合出寄存器,赋值需要消耗时间;
在这里插入图片描述

(4)always过程块实现组合逻辑(延迟)

a 代码

module test_tb;
	parameter T =20;
    reg clk;
    reg rst_n;
    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        #(T);
        rst_n = 1'b1;
    end
    always#(T/2) clk = !clk;
    reg [3:0] cnt1;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            cnt1 <= 'd0;
        else
            cnt1 <= cnt1+1'b1;
    end
    reg [3:0] cnt2;
    always@(*)begin
        cnt2 = cnt1;
    end
endmodule

b 电路图

在这里插入图片描述

c 结果

结论:综合出数据线,赋值需要消耗时间
在这里插入图片描述

(5)assign连续赋值语句实现组合逻辑(延迟)

a 代码

module test_tb;
	parameter T =20;
    reg clk;
    reg rst_n;
    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        #(T);
        rst_n = 1'b1;
    end
    always#(T/2) clk = !clk;
    reg [3:0] cnt1;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            cnt1 <= 'd0;
        else
            cnt1 <= cnt1+1'b1;
    end
    wire [3:0] cnt2;
    assign cnt2 = (cnt1 == 1)?1'b1:1'b0;

endmodule


b 电路图

在这里插入图片描述

c 结果

结论:综合出组合逻辑电路,赋值需要消耗时间
在这里插入图片描述

(6)接口中的时钟(延迟)

a 代码

interface my_if(input bit clk);
    bit [7:0] sig1;
    bit [7:0] sig2;
    clocking cb@(posedge clk);
        input sig1;
        output sig2;
    endclocking 
endinterface 
module test_blocking1_test;
    reg clk;
    my_if mif(clk);
    initial begin
        clk = 0;
    end
    always#3 clk = !clk;

endmodule

b 电路图

不可综合语句;

c 结果

结论:
接口中的时钟跳变,会比顶层时钟跳变,延迟;

(7)触发事件(延迟)

a代码

module test_tb;
    parameter T = 20;
    reg clk;
    reg rst_n;
    reg cnt;
    initial begin
        clk = 0;
        rst_n = 0;
        cnt = 0;
        #(T);
        rst_n = 1;
        #(T);
        @(posedge clk);
        cnt = 1;
    end
    always#(T/2) clk = !clk;

endmodule

b 电路图

不可综合语句;

c 结果

在这里插入图片描述

3.仿真软件的采样时刻

(1)在过程块中:时钟触发沿和数据改变沿同时刻

a代码

说明:时钟clk1T/2倍数处改变,输入数据in1 也在T/2倍数处改变;

module test_tb;
    parameter T = 20;
    reg             clk1;
    reg     [3:0]   in1;
    reg             rst_n;
    initial begin
        clk1 = 1'b0;
        rst_n = 1'b0;
        in1  = 'd0;
        #(T);
        rst_n = 1'b1;
    end
    always#(T/2) in1 = in1 + 1'b1;
    always#(T/2) clk1 = !clk1;
    reg [3:0] data_out1;
    always@(posedge clk1 or negedge rst_n)begin
        if(!rst_n)
            data_out1 <= 'd0;
        else 
            data_out1 <= in1;
    end

endmodule

b结果

questasim:
结论:仿真器采样为数据跳变沿右侧的值;
在这里插入图片描述
vcs(DVE):
结论:仿真器采样为数据跳变沿右侧的值;
在这里插入图片描述
vcs(verdi):
结论:仿真器采样为数据跳变沿右侧的值;
在这里插入图片描述

(2)在clocking block中:时钟触发沿和数据改变沿同时刻(完全一致)

a代码

在这里插入图片描述

b结果

questasim:
结论:仿真器采样为采样时刻左侧的值;
在这里插入图片描述
vcs(DVE):
结论:仿真器采样为采样时刻右侧的值;
在这里插入图片描述

vcs(verdi):
结论:仿真器采样为采样时刻右侧的值;
在这里插入图片描述

说明:时钟clk13倍数处改变,输入数据sig1 第二次变化在时钟跳变沿处改变;


为什么两种clk翻转时刻不同???

4.并行块代码的执行

1.代码的执行时间(按照仿真结果总结出的,不具有理论依据)

(1)在verilog实现的硬件电路中,同一时刻不同过程块中的并行语句,是并行执行;
(2)在verilog和systemverilog仿真时,同一时刻同一过程块中的串行语句,是串行执行;
见例子1中,“aaa”、“bbb”、“ccc”的打印语句,是同一过程块中的串行语句,是串行执行;
(3)在verilog和systemverilog仿真时,同一时刻不同过程块中的并行语句,是串行执行;
见例子1中“aaa”、“bbb”、“ccc”三个打印语句和"eee"打印语句,是不同过程块中的并行语句,所以会串行执行;
(因为“aaa”、“bbb”、“ccc”打印语句过程块在前,优先打印)
(4)在verilog和systemverilog仿真时,部分语句会消耗一个很小的时刻的;
如:“#”
见例子2中,两过程块均延时1个时间单位,然后分别打印aaaccc,所以结果aaa在前、ccc在后;
而在第一个过程块中通过执行两次**#1表示延迟两个时间单位,第二个过程块通过执行一次#2同样表示延迟两个时间单位。但是过程块1用了两次#会消耗两个很小的时刻,过程块2只用了1次#只会消耗1个很小的时刻,所以会先打印ddd再打印bbb**
(5)例子
例子1

module test_ft_tb;
    initial begin
        $display("aaa");
        $display("bbb");
	$display("ccc");
        #10;
        $display("ddd");
    end
    initial begin
	$display("eee");
        #10;
        $display("fff");
    end
endmodule

结果:
在这里插入图片描述
例子2

module test_ft_tb;
    initial begin
        #1;
        $display("aaa");
	#1;
	#1;
        $display("bbb");
    end
    initial begin
        #1;
        $display("ccc");
	#2;
	$display("ddd");
    end
endmodule

结果:
在这里插入图片描述

5.对模块中成员的调用

(1)问题

systemverilog中,在一个区域中,声明了一个类(或模块),那么在这个区域中就可以调用这个类(或模块)中的成员(变量和方法);

(2)例子(以模块为例)

代码:

module add_module;
    int data_arr [$];
    task automatic get_data(input int data_in);
        data_arr.push_back(data_in);
    endtask 
    task automatic add_data(output int add_re);
        foreach(data_arr[i])begin
            add_re = add_re + data_arr[i];
        end
    endtask
endmodule
module test_ft_tb1;
   add_module u1();
   initial begin
        int re;
        u1.get_data(1);
        u1.get_data(2);
        u1.get_data(3);
        $display("data_arr = %p",u1.data_arr);
        u1.add_data(re);
        $display("result is %0d",re);
   end
endmodule

结果:
在这里插入图片描述

6.模块和类的静态与动态

模块是静态的,创建于编译时刻;
类是动态的,创建于实例化时刻。


http://www.kler.cn/a/458455.html

相关文章:

  • Xilinx DCI技术
  • OpenGL变换矩阵和输入控制
  • word怎么添加链接,点击直接到参考文献
  • 【YOLO算法改进】ALSS-YOLO:无人机热红外图像|野生动物小目标检测
  • Android 系统 `android.app.Fragment` 类的深度定制与常见问题解析
  • mybatis 使用@Insert插入操作后返回自增id
  • uniapp-vue3(下)
  • Direct Preference Optimization: Your Language Model is Secretly a Reward Model
  • MIT实验笔记冲刺3:页表操作(理论部分)
  • 解锁ChatGPT潜力:打造属于你的AI助手
  • 基于Springboot的高校办公室行政事务管理系统【附源码】
  • Linux 的信号机制
  • 使用C#生成一张1G大小的空白图片
  • Django REST framework 源码剖析-路由详解(Routers)
  • Docker 开启远程端口访问2375
  • Java的责任链模式在项目中的使用
  • 如何优化求职简历从模板选择到面试准备
  • LeetCode 203:根据值删除节点
  • HDLBits训练6
  • Java爬虫实战:获取亚马逊商品详情
  • 五.Springboot通过AOP实现API接口的签名验证
  • Go IO之文件处理,TCPUDP讲解
  • CF2043b-B. Digits
  • ASP.NET Core Web API Hangfire
  • C# OpenCV机器视觉:漫水填充
  • 春招快速准备和是否考研建议