verilogsystem-verilogvivado

Vivado behavioral simulation results differ on different PCs, but synthesis results are the same


I have implemented a BCD converter on which I worked from two different PCs:

As an IDE, I used Vivado 2024.2 for both computers and a Basys3 development board for implementation.

Upon running a behavioral simulation on the BCD (same code for both PCs), on the computer, whatever I do, the output stays at X, but on the laptop the output changes correctly, according to the implemented design. For both PCs, from synthesis onward, the results are the same and the program works correctly after generating the bitstream and loading the program onto the board.

For completeness sake, I will also include the code of the design:

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
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
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
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

Why does this happen? Is it a problem between the two differing operating systems, but, if so, why does it only affect simulation and not synthesis?


Solution

  • If you also have Verilog code for the testbench, you should show that code as well.

    Depending on how you run your simulation, I see how the Binary2BCDTranscoder convOut output could remain unknown (X).

    You did not reset this output signal. You declared it as a reg type, which means it is initialized in simulation as x. The output will remain at x until you satisfy the if condition below:

    always @(posedge clk) begin
    
        if(state==CONV_CHK & convDone) convOut <= inner_out;
    
    end
    

    I created a simple testbench to run a simulation, and I always see the output as x:

    module tb;
        parameter INPUT_SIZE    = 12;
        parameter OUTPUT_DIGITS = 4;
        bit clk;
        bit convStart;
        bit [INPUT_SIZE-1:0] data;
        bit rst;
        wire convDone;
        wire [4*OUTPUT_DIGITS-1:0] convOut;
    
    Binary2BCDTranscoder dut (
        .clk        (clk),
        .convStart  (convStart),
        .data       (data),
        .rst        (rst),
        .convDone   (convDone),
        .convOut    (convOut)
    );
    
    always #5 clk++;
    
    initial begin
        $dumpvars;
        repeat (2) @(posedge clk);
        rst <= 1;
        repeat (2) @(posedge clk);
        convStart <= 1;
        repeat (1) @(posedge clk);
        convStart <= 0;
        #500 $finish;
    end
    endmodule
    

    If I use your reset signal to reset the output, I see the output become known (0):

    always @(posedge clk) begin
        if (!rst) convOut <= 0;
        else if (state==CONV_CHK & convDone) convOut <= inner_out;
    end
    

    Now that you have added the testbench code to the question, this confirms my results above. You could reset the convOut signal as described above to eliminate the x.