Search code examples
verilogfpgavivadogtkwave

Verilog garbage input does not result in garbage output


I am writing a simple Control Unit in verilog. It goes something like this.

module controlUnit(
    output reg  wreg,
    input  wire [5:0] op, func
);
    // wreg sub-handles. Beware: wreg is 0 if any of these s high
    wire isBranch = (op[5:3] == 3'b0) & (|op[2:0]); 
    wire isStrWrd = op == 6'b101011;
    wire isJumpReg = (op == 6'd0) & (func == 6'b001000);

    // wreg handle
    always @(*) begin
        if(isBranch | isStrWrd | isJumpReg) 
            wreg <= op == 6'b000011;
        else
            wreg <= 1'b1;
    end
endmodule

module testbench;
    integer i;
    wire out;
    reg [11:0] in;

    controlUnit CU0(
        .wreg(out),
        .op(in[11:6]), .func(in[5:0])
    );

    initial begin
        $dumpfile("test.vcd");
        $dumpvars(0, testbench);

        #4 in = 0;
        for(i=0; i<1024; i=i+1) begin
            #1 in = i;
        end
        #1 in = 10'hXX;    // Garbage input here
        #1000;
    end
endmodule

However in simulation, the wreg signal is a solid logical HIGH when the input becomes garbage. I have seen this behaviour with iverilog-10/GTKwave and Vivado 2019.1. Following is the waveform: Garbage as input, but logic HIGH as output.

So, why?


Solution

  • You only set 10 of your 12 input bits to x; the 2 MSBs are 0. You should set all of your input signals to x. This is probably unrelated to your problem, but I think it is what you intended. Change:

        #1 in = 10'hXX;    // Garbage input here
    

    to:

        #1 in = {12{1'bx}};    // Garbage input here
    

    When the signals in if(isBranch | isStrWrd | isJumpReg) are x, the if is false, and the else is executed, which sets wreg to 1 (wreg <= 1'b1), not x. This answers the question of why the Verilog simulator assigns wreg to 1 when all the inputs are x. This is the way the simulator is designed to work.


    Using the ternary operator equivalent code will set wreg to x when the inputs are x:

    always @(*) begin
        wreg = (isBranch | isStrWrd | isJumpReg) ? (op == 6'b000011) : 1'b1;
    end
    

    Note that using a blocking assignment (=) is recommended for combinational logic.