3
\$\begingroup\$

Here is the problem: Verilog code and testbench for detecting the range of the input given number. If input number is between 12 to 49 then output is '1' else '0'. Range should be easily programmable.

I'm using EDA playground, cadence xcelium 20.09 simulator and EP wave is also present. Is it the appropriate code for the question asked? and also-

Does Verilog read integers normally? for example if I'm inputting a binary number then I should mention the number of bits and then the binary bit like 4b'0011. I directly inputted 12 in the if loop, so it automatically detects that it is an integer?

Here is the link: https://www.edaplayground.com/x/7sQM

Design

module range_detect(y,x);
  input [9:0]x;
  output reg y;
  always @(x)
    begin
      if(x>=12 && x<=49)
        begin
        y=1;
          $display("Input: %d lies between 12 and 49",x);
        end
      else
        begin
        y=0;
          $display("Input: %d does not lie between 12 and 49",x);
        end
    end
endmodule

Testbench

module testbench;
  reg [9:0]in;
  wire out;
  range_detect rd(out,in);
  initial
    begin
      $dumpfile("dump.vcd");
      $dumpvars(1,testbench);
      in=12;
      #2 in=11;
      #2 in=51;
      #2 in=34;
      #2 in=61;
      #2 in=19;
      #2 in=18;
      #2 $stop;
    end
endmodule
\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

Verilog is flexible with how it interprets integers. It interprets 5 and 4'b0101 as the same numeric value. Yes, it interprets 12 as an integer in the if statement.

Your code simulates properly on edaplayground, and you have done a good job of separating the design code from the testbench. Here are some specific recommendations.

If you want your design code to be synthesizable, it would be best to move the $display statements into the testbench. This requires you to replicate the logic in the testbench as well, but this is necessary when you create a testbench checker anyway.

For debugging purposes, it is helpful to display the simulation time as well: $time.

Also for debugging, it is better to dump signals throughout the hierarchy. Currently, you just dump the testbench signals. If you call $dumpvars without arguments, you will also get the design variables dumped to your VCD file.

An alternate approach to driving specific values to your input (12, 11, 51, etc.) is to drive random values in a repeat loop. This allows you to easily change the number of values you drive and the range. The code {$random} % 60 below returns a value in the range 0-59.

Your rd instance uses connections-by-position, which is fine for a small number of ports (2), like you have. But, it is preferable to use connections-by-name to make the code more readable and to help prevent connection errors. For example: .x (in)

In your design, it is preferable to use ANSI style port declarations to cut down on duplicate port names.

It is preferable to use an implicit sensitivity list always @* because it automatically triggers the block when the appropriate signals change. This avoids a common Verilog problem where people forget to add or remove signals from the list when they change the code body.

To make the range programmable, one common way to do it is to use parameters. They can be declared in both the design and the testbench. For example, you can use MIN and MAX instead of 12 and 49 (all caps is a convention). It is also helpful to add comments describing the legal values for the parameters.

Here is an alternate way to code everything:

module range_detect (
    input [9:0] x,
    output reg y
);

parameter MIN = 12;
parameter MAX = 49;

always @* begin
    if ((x>=MIN) && (x<=MAX)) begin
        y = 1;
    end else begin
        y = 0;
    end
end
endmodule


module testbench;
    reg [9:0] in;
    wire out;

    // MIN must be smaller than MAX.
    // MAX must be smaller than 1024.
    parameter MIN = 12;
    parameter MAX = 49;

    range_detect #(
        .MIN (MIN),
        .MAX (MAX)
    )
    rd (
        .x  (in),
        .y  (out)
    );

    always @* begin
        if ((in>=MIN) && (in<=MAX)) begin
            $display($time, "  Input: %0d lies between %0d and %0d", in, MIN, MAX);
        end else begin
            $display($time, "  Input: %0d does not lie between %0d and %0d", in, MIN, MAX);
        end
    end

    initial begin
        $dumpfile("dump.vcd");
        $dumpvars;
        repeat (10) #2 in = {$random} % 60;
        #2;
    end
endmodule

You can simply change the parameter values in the testbench and they will propagate into the design.


I use 4-space indentation because I think it is easier to see the different levels of your code's logic.

I add parentheses around terms like (x>=MIN) so that I never have to think about which operators have higher precedence, and it also helps me visually parse the code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.