Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"<signal> is not a constant" error in if-statement

Tags:

verilog

I am trying to write a simple module to output a 14-bit number based on the value of four input signals. My attempt is shown below.

module select_size(
    input a,
    input b,
    input c,
    input d,
    output [13:0] size
);

    if (a) begin
        assign size = 14'h2222;
    end
    else begin
        if (b) begin
            assign size = 14'h1111;
        end
        else begin
            if (c) begin
                assign size = 14'h0777;
            end
            else begin
                assign size = 14'h0333;
            end
        end
    end

endmodule

Upon compilation, I receive the following error:

ERROR:HDLCompiler:44 - Line 67: c is not a constant

I don't understand why that particular if-statement isn't working if the other two preceding it are. I have tried changing the condition to

if (c == 1) begin

but to no avail.

Does anybody know how to solve this error? Thank you!

like image 211
tomocafe Avatar asked Aug 06 '12 21:08

tomocafe


2 Answers

Two problems:

1) You need to put if statements inside an always block.

If you use verilog-2001, you can use

always @*
   if ....
   end
end

Otherwise specify all the inputs in the sensitivity list:

always @(a or b or c or d)
   if ....
   end
end


2) Constant assignments are not allowed inside if statements.

Remove the assign keyword from any statements inside the if block:

if (a) begin
    size = 14'h2222;
end

You will also have to declare size as a reg type.

However my preference would be to rewrite the entire module with conditional operator, I find it much preferrable to read. This following module achieves the same result:

module select_size(
    input a,
    input b,
    input c,
    input d,
    output [13:0] size
);

    assign size = a ? 14'h2222 :
                  b ? 14'h1111 :
                  c ? 14'h0777 : 
                      14'h0333 ;

endmodule
like image 88
Tim Avatar answered Nov 19 '22 15:11

Tim


As @Tim has already answered, using reg types inside always blocks or wire with assign.

@Tim has also described the nested ternary assignments, while in the example are written very well, they are generally seen as bad practice. They imply a very long combinatorial path and can be hard to maintain. The combinatorial path may be optimised by synthesis which should imply a mux with optimised selection logic.

Easier to maintain code will have a lower cost of ownership, and as long as it does not lead to a larger synthesised design it is normally preferred.

My implementation would be to use a casez, (? are don't cares). I find the precedence of each value easier to see/debug.

module select_size(
  input a,
  input b,
  input c,
  input d,
  output logic [13:0] size //logic (SystemVerilog) or reg type
);

always @* begin
  casez ({a,b,c})
    3'b1?? : size = 14'h2222 ;
    3'b01? : size = 14'h1111 ;
    3'b001 : size = 14'h0777 ;
    3'b000 : size = 14'h0333 ;
    default: size = 'bx      ;
  endcase
end

endmodule
like image 1
Morgan Avatar answered Nov 19 '22 13:11

Morgan