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.