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. 现象核心原因
核心是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
相关产品推荐
相关产品推荐

