一个Vivado仿真问题的debug

我最近在看Synopsys的MPHY仿真代码,想以此为参考写个能实现PWM-G1功能的MPHY,并应用于ProFPGA原型验证平台。我从中抽取了一部分代码,用Vivado自带的仿真器进行仿真,然后就遇到了一个莫名其妙的问题,谨以此文作为debug记录。

一、原始问题

涉及到的相关代码如下:

  1. 第一张图是我从MPHY仿真代码里copy的一个task,用于对MPHY进行参数配置;
  2. 第二张图是我要配置的MPHY参数;
  3. 第三张图是选取的一个出问题的参数模块例化;
  4. 第四张图是这个参数模块的实现,非常简单。

就是这么简单的几行代码,却意外出问题了,仿真波形如下图所示,可以看到参数没有配置成功。

我真的是百思不得其解,就用了一个下午进行debug。

二、问题简化

由于原始问题的仿真工程比较大,仿真时间比较长,debug起来就很费劲。于是我就把问题的关键部分抽取出来,做了简化,写了如下的一段仿真代码:

复制代码
// *****************************************************************************
// *                                                                           *
// * Vivado simulation.                                                        *
// *                                                                           *
// * Author:  ZhengWei                                                         *
// * Date  :  2024/02/06                                                       *
// *****************************************************************************
                                                                                 
`timescale 1ns / 1ps 
                                                                                 
module tb;                      
                                                                                 
    // Clock ans reset ports of the module
    reg                     sys_clk                     ;
    reg                     sys_rst                     ;
                                                         
    // Tx config interface ports
    reg     [7:0]           tx_attrid                   ;
    reg     [7:0]           tx_attrwrval                ;
    reg                     tx_attrwrn                  ;
    reg                     tx_configenable             ;
    wire                    write_en                    ;
    wire                    cfg_sel                     ;
    reg     [7:0]           dataout                     ;    
                                                                                     
                                                                                     
//------------------------------------------------------------------------------------
    parameter   SYSCLK_FREQ         = 38.4             	; 
                                                         
    initial sys_clk = 1'b0;
    initial forever
    begin
        #(1000.0/(2*SYSCLK_FREQ));
        sys_clk <= ~sys_clk;
    end
                                                                                                 
                                                                                                 
    task automatic write_shadow_cfg(input [7:0] attrid, input [7:0] attrwrval);
    begin    
            tx_attrid    = 8'h00;
            tx_attrwrval = 8'h00;	    
                                 
        @(posedge sys_clk) begin	
            tx_configenable <= 1'b0     ;
            tx_attrwrn      <= 1'b0     ;
            tx_attrid       <= attrid   ;
            tx_attrwrval    <= attrwrval;
        end        
        @(posedge sys_clk) begin	
            tx_configenable <= 1'b1     ;
            tx_attrwrn      <= 1'b1     ;
            tx_attrid       <= attrid   ;
            tx_attrwrval    <= attrwrval;
        end
        @(posedge sys_clk) begin
            tx_configenable <= 1'b0 ;
            tx_attrwrn      <= 1'b0 ;
            tx_attrid       <= 8'h00;
            tx_attrwrval    <= 8'h00;	
        end
    end
    endtask
                                              
                                              
    initial begin
        tx_configenable  = 1'b0 ;
        tx_attrwrn       = 1'b0 ;
        tx_attrid        = 8'h00;
        tx_attrwrval     = 8'h00;
                                 
        sys_rst = 1'b1  ;
        #100
        sys_rst = 1'b0  ;
                                                     
        #200;                                             
        write_shadow_cfg(8'h2d, 8'h20);
                                               
        #200;
        write_shadow_cfg(8'h2d, 8'h25);
        write_shadow_cfg(8'h2d, 8'h30);
                                                     
        # 500           ;
        $stop           ;
    end
                                                         
                                                         
    assign  write_en =  tx_configenable && tx_attrwrn;
    assign  cfg_sel  = (tx_attrid == 8'h2d);
                                                         
    always @(posedge sys_clk or posedge sys_rst) begin
        if (sys_rst)
            dataout <= 8'h00;
        else if(write_en && cfg_sel) 
            dataout <= tx_attrwrval;
        else 
            dataout <= dataout;
    end
                                                         
                                                           
endmodule

三、问题定位

按如上代码进行仿真,复现了问题,波形如下图所示:

  1. 先写了个20,结果是20,正确;
  2. 再写了个25,但结果是0,错误;
  3. 最后写了个30,结果是30,正确。

其实,我一开始只写了个20,发现结果是正确的。我还想了很久,为啥原始仿真工程是错误的呢?

后面就连着写了25和30,才发现先写的25结果是错的,后写的30结果是对的。

特别注意:写20后面加了delay,但25和30中间没有加delay。

四、问题解决

虽然这结果也很让人费解,但不加delay就有问题,不由得让我怀疑下面这两句有问题:

把这两句注释掉,重新仿真,结果正确,波形图如下:

五、进一步分析

按我的理解,这两句也就只是在task开始时给信号赋个初始值而已,为啥就会导致结果变成0了呢?还是不能理解!为了理解这个结果0是怎么来的,让问题能变得再清晰点,改成如下:

重新仿真后的波形图如下所示:

我们能在波形里看到ff,但却是更加莫名其妙了。隐隐感觉这可能与阻塞赋值和非阻塞赋值有关,虽然还是不能理解,但改成如下进行仿真:

重新仿真后的波形图如下所示,可以看到结果是正确的:

六、总结与疑问

以前读书时,只记住了"组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值",然后就是教科书里的几个加delay的例子,感觉还都能理解。

也看了下面这个例子,感觉和我当前的这个例子还是有区别的。

modelsim和vivado仿真不一致------噩梦debug - 代码先锋网

再看了下面这个链接,感觉还是没有特别理解为啥我这个例子里用阻塞赋值会是这样的结果。

verilog中阻塞和非阻塞的区别_verilog阻塞和非阻塞的区别-CSDN博客

时间和精力有限,这个问题先暂时这样了,如果有大佬路过可以赐教下,不胜感激!

相关推荐
我爱C编程1 小时前
基于FPGA的16QAM软解调+卷积编码Viterbi译码通信系统,包含帧同步,信道,误码统计,可设置SNR
fpga开发·16qam·软解调·帧同步·卷积编码·viterbi译码
南棱笑笑生1 小时前
20250726让荣品的PRO-RK3566开发板使用TF卡启动
fpga开发
水果里面有苹果9 小时前
1-FPGA的LUT理解
fpga开发
千宇宙航1 天前
闲庭信步使用图像验证平台加速FPGA的开发:第二十七课——图像腐蚀的FPGA实现
图像处理·计算机视觉·fpga开发·图像腐蚀
小白到大佬1 天前
High Speed SelectIO Wizard ip使用记录
fpga开发·lvds·高速接口
嵌入式-老费1 天前
再谈fpga开发(fpga开发的几个特点)
fpga开发
范纹杉想快点毕业2 天前
基于C语言的Zynq SOC FPGA嵌入式裸机设计和开发教程
c语言·开发语言·数据库·嵌入式硬件·qt·fpga开发·嵌入式实时数据库
YONYON-R&D2 天前
LAYOUT 什么时候需要等长布线?
嵌入式硬件·fpga开发
我不是程序猿儿2 天前
【Servo】裸机还是RTOS驱动架构如何选?
驱动开发·fpga开发·架构·伺服驱动器·伺服
乌恩大侠2 天前
USRP X440
fpga开发