Math operations on time values - verilog

I need to divide two delay parameter values which are in ps. The result has to be an integer value. I have tried the code below, but the result is incorrect. N, a parameter which I need at compile/elaboration time, needs to be calculated to 60. Link on edaplayground.
module test #(parameter delay=3000ps, unitDelay = 50ps, integer N=$ceil(delay/unitDelay))
(input logic L, output logic R);
initial begin
$display ("delay=%d, unitDelay=%d, N=%d", delay, unitDelay, N);
$display ("delay=%t, unitDelay=%t, N=%d", delay, unitDelay, N);
end
endmodule

The problem is your global timescale is 1ns, so unitDelay will be 0. So you either need to make your timescale 1ps, or change your parameter types to real

Related

How to prevent inferred latch and latch unsafe behavior in Verilog?

I am having trouble with a specific part of my program, here in the always block:
module compare_block (clk, reset_n, result, led);
parameter data_width = 8; //width of data input including sign bit
parameter size = 1024;
input clk, reset_n;
input [(data_width+2):0] result; //from filter -- DOUBLE CHECK WIDTH
logic [(data_width):0] data_from_rom; //precalculated 1 Hz sine wave
logic [10:0] addr_to_rom;
output reg led;
reg [(data_width + 2):0] ans_sig [size-1:0];
integer i, iii, jj, j, ii;
reg ans_sig_done, filt_sig_done, comp_sig_done;
reg [(data_width+2):0] sum;
reg [data_width:0] max_val, error_val;
initial max_val='b000000000;
...
always #* begin
sum = 0;
if (ans_sig_done) begin
for (j=4; j<(size-1); j=j+2) begin
sum = sum + ans_sig[j];
if (ans_sig[j] > max_val) begin
max_val = ans_sig[j];
end else begin
max_val = max_val;
end//else
end //for
end//if
end//always
...
endmodule
Essentially, ans_sig is an array, 1024 bytes long that I want to sum into one number (sum) and eventual (not here) take the average of. While I am traversing the ans_sig array, I also want to identify the maximum value within the array (max_val), which is what the nested if-statement is doing. However I get the following severe warnings when I'm compiling in Quartus:
"Inferred latch for "max_val[8]" at compare_block.sv"
"13012 Latch compare_block:compare|max_val[8] has unsafe behavior"
"13013 Ports D and ENA on the latch are fed by the same signal compare_block: compare|LessThan473~synth" (for max_val[8])
I get all of these errors for max_val [0] through max_val [8].
this code represents a null-statement and actually signifies a latch rather than eliminating it:
end else begin
max_val = max_val; <<< null statement
It does not make much sense in using such statement unless you want to show that this has a latch behavior.
You initialized the max_val only once in the initial block. There for the latch behavior is an expected one: you keep max_val between multiple invocations of the sum for loop.
If this is not the case, and you need to re-calculate the max_val every time, you should initialize it in the always block same way as you do sum.
always #* begin
sum = 0;
max_val = 0;
if (ans_sig_done) begin
for (j=4; j<(size-1); j=j+2) begin
sum = sum + ans_sig[j];
if (ans_sig[j] > max_val) begin
max_val = ans_sig[j];
end
end//else
end //for
end//if
end//always
this way you will get rid of the latch.
If this module is for simulation purposes, perhaps you don't need to care about the warnings (I'm not pretty sure. Correct me if I'm wrong). However if it's for implementation, you'll need to use sequential logic to generate sum and max_val with ans_sig_done being the enable signal. You have 1024 11-bit long data, don't ever think about doing such a calculation with zero time consumption. Let's talk about the warnings you got. Since the always block is combinational, what do you expect when ans_sig_done is false. Combinational logic with missing branches results in latch behavior. By the way, you have a sum with the same bit width as each data inside the ans_sig array which will lead to potential data loss during calculation, and a max_val with even narrower bit width.

Comparing two numbers without comparison operators in verilog

Two 8-bit inputs are fed to the comparator, and if first one is greater than second, they are supposed to be subtracted, else they are supposed to be added. But, > and < operators aren't supposed to be used to compare them.
So, I have written my logic as:
input[7:0] in1,in2;
output select;
assign select=(in1-in2)?0:1;
It is always subtracting, unless difference equals 0. If I use division, 0 cannot be an input or my program can crash. Any suggestions on how to solve this problem?
Thanks a lot for your time.
Remember that the leftmost bit of a negative number is aways 1. So you can use it to check the sign of the difference.
input[7:0] in1,in2;
output select;
wire [7:0] difference = in1-in2;
wire sign_of_difference = difference[7];
assign select = sign_of_difference? 0:1;

I can't understand the result of this $random(seed) code

module random;
reg [31:0] addr;
integer seed;
initial begin
seed = 5;
$monitor("%t->%d", $time, addr);
#30 $stop;
end
always #5 addr = $random(seed);
endmodule
In this code, if I declare seed with integer, the seed value changes every #5. But, if I declare seed with reg[3:0], the seed value is 5 continuously. I can't understand why this is happening.
Your code generates a very small sample size (5). You should generate more random numbers. When I did so, I saw more than one value with reg [3:0] seed;. Change #30 to #300, for example.
When I use reg [31:0] seed;, I get the same type of distribution as when I use integer. I don't see any explanation of this behavior in the IEEE Std 1800-2012 for $random, but section 20.15.2 "Distribution functions" mentions:
For each system function, the seed argument is an inout argument; that
is, a value is passed to the function, and a different value is
returned. The system functions shall always return the same value
given the same seed.
You should see seed changing on every call.
$monitor("addr=%d seed=%d", addr, seed);
I strongly recommend that you start using $urandom instead of $random. It makes it easy to control the seed from the command line without having to recompile, and you get better random stability as well.
The seed to $random is supposed to be at least a 32-bit integer (Although it is not explained in the LRM, the code for $random is in the append). A 32-bit seed does not mean you will get 2**32-1 random numbers. As you shorten the width of the seed, you shorten the number of random numbers that it takes to repeat the cycle of random numbers. By the time you get down to 4 bits, the probability that the cycle for a particular seed goes to 1 is pretty high.

Synthesis error on a CASE statement in Verilog

I m new in Verilog and I would like to know your opinion about an error I get when trying to synthesize the part of my code cited below:
input [31:0] A;
reg [31:0] X,Y;
reg [15:0] width;
input action;
always#*
begin
width= A [31:16];
if (action==1)
begin
case (width)
16'b0: X=0;
default:
begin
for (i=32; i>=width+1 ; i=i-1)
X[i]=0;
for (i=width; i>=0; i=i-1)
X[i]=1;
end
endcase
Y=X >> 1;
end
end
I m using Cadence synthesis tool and the error that i get is in this part of my code saying :
Index 'X[-1]' is not within the valid range of the declaration [31:0]
which i don't understand because even if width=0 i have a special case that should not involve the for loop. i also tried increasing the limits to width +2,width +1 and then shift the quantity X by 2 ..but also got the same error.
Thank you in advance!
I don't see how i could be -1, but it is possible for it to be greater than 31 which is out of range. There are couple of synthesis issues:
i=32 is already out of range for X[31:0]. Its MSB is 31.
i will go out of range when width > 31. width is a 16-bit unsigned value, meaning its maximum value is 65535 (i.e. 216-1) and its minimum is 0.
Synthesis requires loops to static unroll. This means the number of loops must be constant. Variables such as width cannot be in the loops condition.
A synthesis-able for loop will look as follows:
for (i=31; i>=0; i=i-1)
X[i] = (width>=i);
I'm assuming the width= A [31:16]; above the always block is a copy past typo as it is illegal syntax. I'm also assuming there are no additional assignments on width, X, Y, or i outside of the always block. Otherwise there are additional errors.
It's unclear exactly why you're hitting the -1 condition, but it looks like you are trying to create a mask of width "width", which would be more easily accomplished as:
always #*
begin
X = ((1 << width[4:0]) - 1)
end
Edit: Added width specifier to shift, this may reduce synthesis area

Verilog Assignment nth iteration

I have the following code:
always # (clk) begin
for (1=0,i<150, i++) begin
abc[i] = xyz[i];
end
end
Question: If I want to get value of abc[8] (set of 8th iteration with the assign statement), how can I do that?
I did like below:
reg [31:0] abc;
wire [31:0] jkl;
always # (clk) begin
for (1=0,i<150, i++) begin
abc[i] = xyz[i];
end
end
assign jkl = abc[8];
$display ("value is 0x%x\n", jkl);
I have an error, can you please suggest me something?
Seems like you have misunderstanding of how for loops work in Verilog. In Verilog, you are defining hardware which operates in parallel at all times. The for loop is just a handy way to express something. You should not think of it as iterating.
What your expression means is something like this:
Assign abc[i] from xyz[i] for all values of i from 0 to 149, on every clock cycle
If you really want to iterate, you need to create a counter which increments on each cycles and use that instead of a for loop.
Now, you are probably getting error messages due to some of your other errors:
You cannot put a $display outside of a sequential code block. That is, it needs to be inside an always or forever block or similar.
You are assigning jkl (a 32-bit value) from abc[8] which is a single bit
You are assigning abc[0] to abc[149] in the for loop, but abc is only 32-bits wide

Resources