verilogencoderdigital

Unexpected output in verilog code for encoder


I have been trying to code encoder in Verilog. The code is compiling without error but the output are unexpected. The output is not changing with input. I am attaching the code and the pic of the output.

I have initialized out with value 0 in each module. But the value of out is not getting updated in the case statement. That's why the output is always zero.

I tried to check value of the variable 'in' in the modules using the $display keyword, but it isn't showing anything. I guess the input variable 'in' inside the encoder modules is not taking the input values from the test module. I don't know why is this happening.

module ENCODER_2_1(
    output reg out,
    input [1:0] in,
    input enable);

    initial begin
        out = 1'b0;
        if (enable) begin
            case (in)
                2'b00 : out = 1'b0;
                2'b10 : out = 1'b1;
                default : out = 8'b00000000;
            endcase
        end
    end

endmodule

module ENCODER_4_2(
    output reg [1:0] out,
    input [3:0] in,
    input enable);

    initial begin
        out = 2'b00;
        if (enable) begin
            case (in)
                4'b0000 : out = 2'b00;
                4'b0001 : out = 2'b01;
                4'b0010 : out = 2'b10;
                4'b0100 : out = 2'b11;
                default : out = 8'b00000000;
            endcase
        end
    end

endmodule

module ENCODER_8_3(
    output reg [2:0] out,
    input [7:0] in,
    input enable);

    initial begin
        out = 3'b000;
        if (enable) begin
            case (in)
                8'b00000000 : out = 3'b000;
                8'b00000001 : out = 3'b001;
                8'b00000010 : out = 3'b010;
                8'b00000100 : out = 3'b011;
                8'b00001000 : out = 3'b100;
                8'b00010000 : out = 3'b101;
                8'b00100000 : out = 3'b110;
                8'b01000000 : out = 3'b111;
                default : out = 8'b00000000;
            endcase
        end
    end

endmodule

module ENCODER_16_4(
    output reg [3:0] out,
    input [15:0] in,
    input enable);

    initial begin
        out = 4'b0000;
        if (enable) begin
            case (in)
                16'h0000 : out = 4'b0000;
                16'h0001 : out = 4'b0001;
                16'h0002 : out = 4'b0010;
                16'h0004 : out = 4'b0011;
                16'h0008 : out = 4'b0100;
                16'h0010 : out = 4'b0101;
                16'h0020 : out = 4'b0110;
                16'h0040 : out = 4'b0111;
                16'h0080 : out = 4'b1000;
                16'h0100 : out = 4'b1001;
                16'h0200 : out = 4'b1010;
                16'h0400 : out = 4'b1011;
                16'h0800 : out = 4'b1100;
                16'h1000 : out = 4'b1101;
                16'h2000 : out = 4'b1110;
                16'h4000 : out = 4'b1111;
                default : out = 8'b00000000;
            endcase
        end
    end

endmodule

//To run the test uncomment this block

module test();


    wire out1;
    wire [1:0] out2;
    wire [2:0] out3;
    wire [3:0] out4;

    reg [1:0] in2;
    reg [3:0] in4;
    reg [7:0] in8;
    reg [15:0] in16;

    reg enable;

    ENCODER_2_1 enc_2_1(out1, in2, enable);
    ENCODER_4_2 enc_4_2(out2, in4, enable);
    ENCODER_8_3 enc_8_3(out3, in8, enable);
    ENCODER_16_4 enc_16_4(out4, in16, enable);

    initial begin
        
        enable = 1;

        #1 $display("\n2:1 Encoder");
           $monitor("input = %b | output = %b",in2, out1);

           in2 = 2'b00;
        #1 in2 = 2'b10;

        #1 $display("\n4:2 Encoder");
           $monitor("input = %b | output = %b",in4, out2);

           in4 = 4'b0000;
        #1 in4 = 4'b0001;
        #1 in4 = 4'b0010;
        #1 in4 = 4'b0100;

        #1 $display("\n8:3 Encoder");
           $monitor("input = %b | output = %b",in8, out3);

           in8 = 8'b00000000;
        #1 in8 = 8'b00000001;
        #1 in8 = 8'b00000010;
        #1 in8 = 8'b00000100;
        #1 in8 = 8'b00001000;
        #1 in8 = 8'b00010000;
        #1 in8 = 8'b00100000;
        #1 in8 = 8'b01000000;

        #1 $display("\n16:4 Encoder");
           $monitor("input = %h | output = %b",in16, out4);

           in16 = 16'h0000;
        #1 in16 = 16'h0001;
        #1 in16 = 16'h0002;
        #1 in16 = 16'h0004;
        #1 in16 = 16'h0008;
        #1 in16 = 16'h0010;
        #1 in16 = 16'h0020;
        #1 in16 = 16'h0040;
        #1 in16 = 16'h0080;
        #1 in16 = 16'h0100;
        #1 in16 = 16'h0200;
        #1 in16 = 16'h0400;
        #1 in16 = 16'h0800;
        #1 in16 = 16'h1000;
        #1 in16 = 16'h2000;
        #1 in16 = 16'h4000;

    end 

endmodule

The output is given below:

Output

Why isn't the output changing?


Solution

  • In all your ENCODER modules, change:

    initial begin
    

    to:

    always @* begin
    

    The code in your ENCODER modules only executes once at time 0 because the code is in an initial block. You want the module outputs to be updated every time any input changes. This is accomplished with always @*.

    If you enable SystemVerilog features in your simulator, you could use

    always_comb begin
    

    I see the output changing:

    2:1 Encoder
    input = 00 | output = 0
    input = 10 | output = 1
    
    4:2 Encoder
    input = 0000 | output = 00
    input = 0001 | output = 01
    input = 0010 | output = 10
    input = 0100 | output = 11
    
    8:3 Encoder
    input = 00000000 | output = 000
    input = 00000001 | output = 001
    input = 00000010 | output = 010
    input = 00000100 | output = 011
    input = 00001000 | output = 100
    input = 00010000 | output = 101
    input = 00100000 | output = 110
    input = 01000000 | output = 111