一个Vivado仿真问题的debug

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

一、原始问题

涉及到的相关代码如下:

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

一个Vivado仿真问题的debug_第1张图片

一个Vivado仿真问题的debug_第2张图片

一个Vivado仿真问题的debug_第3张图片

一个Vivado仿真问题的debug_第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

三、问题定位

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

一个Vivado仿真问题的debug_第5张图片

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

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

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

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

四、问题解决

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

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

一个Vivado仿真问题的debug_第6张图片

五、进一步分析

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

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

一个Vivado仿真问题的debug_第7张图片

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

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

一个Vivado仿真问题的debug_第8张图片

六、总结与疑问

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

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

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

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

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

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

你可能感兴趣的:(FPGA调试总结,vivado,fpga开发,vivado)