You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vivado行为仿真跨PC结果不一致但综合结果一致问题咨询

问题描述

我在两台不同配置的电脑上实现了一款BCD转换器:

  • 台式机:AMD Ryzen 7 3700X 8核处理器、GeForce RTX 2070 SUPER、32GB内存,系统为Windows 10
  • 笔记本:Intel i7-1165G7处理器、32GB内存,系统为Windows 11 PRO

两台设备均使用Vivado 2024.2作为开发环境,目标开发板为Basys3。
运行BCD转换器的行为仿真时(代码完全相同),台式机的输出始终为X,而笔记本的输出符合设计预期。但从综合阶段开始,两台设备的结果完全一致,生成比特流并烧录到开发板后程序运行正常。

完整设计代码如下:

counter模块

module counter #(parameter SIZE = 4) (
        input clk,
        input rst,
        input en,
        output reg [SIZE-1:0] out
    );
    
    always @(posedge clk, negedge rst) begin
    
        if(!rst)
            out <= 0;
        else
            if (en) out <= out + 1;
    
    end
    
endmodule

loadRegister模块

module loadRegister #(DATA_SIZE = 1, REG_SIZE = 2) (
        input clk,
        input rst,
        input [DATA_SIZE-1:0] Din,
        input Sin,
        input [REG_SIZE - 1 : 0] cellAdr,
        input serialLoad,
        input parallelLoad,
        output reg [DATA_SIZE * (2 ** REG_SIZE) - 1 : 0] data
    );
    
    always @(posedge clk) begin
    
        if(!rst) data <= 0;
        
        else if(parallelLoad) begin
        
            data[DATA_SIZE*cellAdr+:DATA_SIZE] <= Din;
        
        end
        
        else if(serialLoad) begin
        
            data <= {data[DATA_SIZE * (2 ** REG_SIZE) - 2 : 0],Sin};
        
        end
        
        else begin
        
            data <= data;
        
        end
    
    end
    
endmodule

Binary2BCDTranscoder模块

module Binary2BCDTranscoder #(parameter INPUT_SIZE = 12, parameter OUTPUT_DIGITS = 4, parameter ICNTR_SIZE = 4, parameter JCNTR_SIZE = 2) (
        input clk,
        input rst,
        input convStart,
        input [INPUT_SIZE-1:0] data,
        output reg convDone,
        output reg [4 * OUTPUT_DIGITS - 1:0] convOut 
    );
    
    localparam WAIT = 2'b00;
    localparam CONV_CHK = 2'b01;
    localparam FINISHED = 2'b11;
    
    reg iRst, jRst, iEn, jEn;
    wire [ICNTR_SIZE-1:0] i;
    wire [JCNTR_SIZE-1:0] j;
    
    reg [1:0] state, next_state;
    reg [INPUT_SIZE-1:0] inner_in;
    
    reg loadRegRst;
    reg [3:0] loadRegDin;
    reg loadRegSin;
    reg loadRegSerial, loadRegParallel;
    reg [1:0] loadRegCellAdr;
    
    wire [4 * OUTPUT_DIGITS - 1:0] inner_out;
    
    always @(posedge clk) begin
    
        if(!rst) state <= WAIT;
        
        else state <= next_state;
    
    end
    
    always @(posedge clk) begin
    
        if(!rst) inner_in <= 0;
    
        else if(state==WAIT) inner_in <= data;
        
    end
    
    always @(posedge clk) begin
    
        if(state==CONV_CHK & convDone) convOut <= inner_out;
    
    end
    
    counter #(.SIZE(ICNTR_SIZE)) iCounter (
        .clk(clk),
        .rst(iRst),
        .en(iEn),
        .out(i)
    );
    
    counter #(.SIZE(JCNTR_SIZE)) jCounter (
        .clk(clk),
        .rst(jRst),
        .en(jEn),
        .out(j)
    );
    
    loadRegister #(.DATA_SIZE(4),.REG_SIZE(2)) innerOutReg (
        .clk(clk),
        .rst(loadRegRst),
        .Din(loadRegDin),
        .Sin(loadRegSin),
        .serialLoad(loadRegSerial),
        .parallelLoad(loadRegParallel),
        .cellAdr(loadRegCellAdr),
        .data(inner_out)
    );
        
    always @(*) begin
    
        case(state)
        
            WAIT: begin
            
                convDone = 0;
                iRst = 0;
                iEn = 0;
                jRst = 0;
                jEn = 0;
                next_state = convStart ? CONV_CHK : WAIT;
            
            end
            
            CONV_CHK: begin
                
                if(i == INPUT_SIZE) begin
                    convDone = 1;
                    next_state = FINISHED;
                    iRst = 0;
                    jRst = 0;
                    iEn = 0;
                    jEn = 0;
                end
                
                else if(j == OUTPUT_DIGITS-1) begin
                    next_state = CONV_CHK;
                    convDone = 0;
                    iRst = 1;
                    jRst = 0;
                    iEn = 1;
                    jEn = 0;
                end
                
                else begin
                    next_state = CONV_CHK;
                    convDone = 0;
                    iRst = 1;
                    jRst = 1;
                    iEn = 0;
                    jEn = 1;
                end
            
            end
            
            FINISHED: begin
            
                next_state = WAIT;
                convDone = 1;
                iRst = 0;
                iEn = 0;
                jRst = 0;
                jEn = 0;
                
            end
            
            default: begin
                next_state = WAIT;
                convDone = 0;
                iRst = 0;
                iEn = 0;
                jRst = 0;
                jEn = 0;
            end
        
        endcase
    
    end
    
    always @(*) begin
    
        case(state)
        
            WAIT: begin
                loadRegRst = 0;
                loadRegDin = 0;
                loadRegSin = 0;
                loadRegParallel = 0;
                loadRegSerial = 0;
                loadRegCellAdr = 0;
            end
            
            CONV_CHK: begin
            
                loadRegRst = 1;
            
                if (iEn) begin
                    loadRegDin = 0;
                    loadRegSin = inner_in[INPUT_SIZE-1-i];
                    loadRegParallel = 0;
                    loadRegSerial = 1;
                    loadRegCellAdr = 0;
                end
                
                else if (jEn) begin
                    
                    if(inner_out[4*j+:4] >= 5) begin
                    
                        loadRegDin = inner_out[4*j+:4] + 3;
                        loadRegSin = 0;
                        loadRegParallel = 1;
                        loadRegSerial = 0;
                        loadRegCellAdr = j; 
                    
                    end
                    
                    else begin
                    
                        loadRegDin = 0;
                        loadRegSin = 0;
                        loadRegParallel = 0;
                        loadRegSerial = 0;
                        loadRegCellAdr = 0;
                    
                    end
                    
                end
                
                else begin
                    loadRegDin = 0;
                    loadRegSin = 0;
                    loadRegParallel = 0;
                    loadRegSerial = 0;
                    loadRegCellAdr = 0;
                end
            
            end
            
            FINISHED: begin
            
                loadRegRst = 1;
                loadRegDin = 0;
                loadRegSin = 0;
                loadRegParallel = 0;
                loadRegSerial = 0;
                loadRegCellAdr = 0;
            
            end
            
            default: begin
            
                loadRegRst = 0;
                loadRegDin = 0;
                loadRegSin = 0;
                loadRegParallel = 0;
                loadRegSerial = 0;
                loadRegCellAdr = 0;
            
            end
        
        endcase
    
    end
    
endmodule

Bin2BCDTest测试模块

module Bin2BCDTest();

reg clk, rst, convStart;
reg [11:0] data;

wire convDone;
wire [15:0] convOut;
    
Binary2BCDTranscoder #(.INPUT_SIZE(12),.OUTPUT_DIGITS(4),.ICNTR_SIZE(4),.JCNTR_SIZE(2)) dut (
    .clk(clk),
    .rst(rst),
    .convStart(convStart),
    .data(data),
    .convDone(convDone),
    .convOut(convOut)
);

initial begin
    clk = 0;
    forever #5 clk = !clk;
end

initial begin 
    rst = 0;
    convStart = 0;
    
    #10 rst = 1;
    
    #10 data = 1023;
    #10 convStart = 1;
    #20 convStart = 0;
    
    #1000;
    
    #10 data = 512;
    #10 convStart = 1;
    #20 convStart = 0;
    
    #1000;
    
    #10 data = 3683;
    #10 convStart = 1;
    #20 convStart = 0;
    
    #1000;
    
    #10 data = 4091;
    #10 convStart = 1;
    #20 convStart = 0;
    
    #1000;
    
    #10 data = 4090;
    #10 convStart = 1;
    #20 convStart = 0;
    
    #1000;
    $stop;
end

endmodule

疑问

  1. 该现象的原因是什么?
  2. 是否与操作系统差异有关?
  3. 为何仅影响行为仿真而不影响综合流程?

问题分析与解答

1. 现象核心原因

核心是Vivado行为仿真器在不同CPU架构下的未初始化信号处理差异,结合代码中的复位逻辑问题:

  • loadRegister采用同步复位(仅在时钟上升沿响应复位),但测试用例中仅在#10时刻给出一次异步复位信号,且Binary2BCDTranscoder的WAIT状态将loadRegRst设为0,导致loadRegister的data信号在仿真初期未被正确初始化,始终保持X。
  • AMD与Intel CPU的架构差异导致Vivado仿真器的事件调度顺序不同:Intel平台仿真器可能对未初始化信号做了隐式补0处理,而AMD平台严格遵循Verilog标准,未初始化的X信号持续传播,最终导致输出全为X。

2. 与操作系统的关系

直接关联不大,但存在间接影响:Windows 10和Windows 11的系统调度、CPU亲和性设置可能放大不同CPU架构下的仿真事件调度差异,但本质原因是CPU架构导致的仿真器行为差异,而非操作系统本身。

3. 仅影响行为仿真的原因

行为仿真与综合/实现的目标和规则完全不同:

  • 行为仿真:严格遵循Verilog语言标准,模拟代码的逻辑行为细节,包括未初始化信号传播、事件调度顺序等,不同平台的仿真器对这些细节的处理可能存在差异,导致结果不同。
  • 综合流程:只关注可综合逻辑,会自动忽略未初始化信号这类仿真特有的问题——综合工具会为寄存器添加默认初始化(如复位时置0),且硬件实现中不存在X状态,所有信号都会被物理电路驱动为明确的高低电平,因此综合后两台设备结果一致,烧录到开发板可正常运行。

修复建议

将loadRegister的同步复位改为异步复位,确保信号能被正确初始化:

always @(posedge clk, negedge rst) begin  // 修改为异步复位
    if(!rst) data <= 0;
    else if(parallelLoad) begin
        data[DATA_SIZE*cellAdr+:DATA_SIZE] <= Din;
    end
    else if(serialLoad) begin
        data <= {data[DATA_SIZE * (2 ** REG_SIZE) - 2 : 0],Sin};
    end
    else begin
        data <= data;
    end
end

内容的提问来源于stack exchange,提问作者Florinlego

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:40:55