一个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博客

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

相关推荐
仲南音15 小时前
Xilinx FPGA——时钟IP核MMCM、PLL
fpga开发
I'm a winner1 天前
基于Xilinx FPGA的LVDS高速串行通信系统(三)--数据训练及握手机制【文末源码】
fpga开发
upper20201 天前
coremark移植坑之-nostartfiles -nostdlib参数
学习·fpga开发·coremark移植·riscv设计
Eloudy2 天前
Vivado 纯命令行构建 FPGA 项目教程
fpga开发
Rambo.xia2 天前
AXI跨时钟域与数据一致性——CDC FIFO深度不够、写后读冒险、多Master仲裁、乱序返回,出了Bug根本查不出来
fpga开发·bug
upper20202 天前
FPGA部署卷积神经网络识别MINST图片
fpga开发·卷积神经网络·minst·minst识别·部署神经网络·神经网络识别图片
你是我的解忧王子2 天前
嵌入式 ADC采样 原始数据分析上层(平均值 波动率 正态分布 线性补偿 系统误差)
fpga开发·数据挖掘·数据分析
9527华安3 天前
FPGA纯verilog代码ISP图像处理培训教程,基于IMX214,提供工程源码+视频教程+FPGA开发板
图像处理·fpga开发·isp·imx214·mipi
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(六)-读写NVME SSD硬盘数据
fpga开发·nvme·nvme ssd
千寻xun3 天前
二、实战篇-NVME SSD控制之ZYNQ实现(三)
fpga开发·nvme ssd·nvme协议