Verilog : Can't understand the resulting simulation (delay, blocking/non blocking) - delay

I'm studying the Verilog language (I have already worked with VHDL) and I don't understand the simulation of this following code :
module exam2011;
integer a,b,c,d;
always
begin
c = #1 a;
#2 b=a;
d = a;
end
initial
begin
a = 0; b = 0; c = 0; d = 0;
#1 a=1;
#2 a=2;
#2 a=3;
#2 a=4;
#2 a=5;
end
initial $monitor($time, “a=%d, b=%d, c=%d, d=%d”,a,b,c,d);
endmodule
The result :
# 0a= 0, b= 0, c= 0, d= 0
# 1a= 1, b= 0, c= x, d= 0
# 3a= 2, b= 1, c= x, d= 1
# 4a= 2, b= 1, c= 1, d= 1
# 5a= 3, b= 1, c= 1, d= 1
# 6a= 3, b= 3, c= 1, d= 3
# 7a= 4, b= 3, c= 3, d= 3
# 9a= 5, b= 5, c= 3, d= 5
# 10a= 5, b= 5, c= 5, d= 5
First, I don't know if I think in the good way : when we change the value of "a" AND the value of "b" and "d" (which are "a") at the same time, how are theses changes performed ?
Also, I don't really understand how to interpret the delay command # after the assignment "=".
Thanks for your help.

Output always depends upon the simulator. 'always' and 'initial' statements are executed in parallel. Even though it looks parallel to us, its is executed in sequence by simulator in the same time stamp.
After all the events in the current time stamp are done, simulator will increment the time stamp. In your code, it looks like 'always' statement is executed before 'initial' statement. Let me try to explain bit clearly.
c = #1 a;
this statement is equivalent to
temp = a; //sample the value of 'a'
#1; // Wait for 1 unit of time
c = temp; //assign the sampled value to 'c'
since 'always' statement enters 1st to simulator queue, it samples value of 'a' which is 'x' and stores it in temporary variable at 0th time. Then it enters 'initial' statement and assigns 0 to 'a','b','c' and 'd'. After #1 time unit, sampled value of 'a' which is 'x' is assigned to 'c' in 'always' statement.
#2 b = a;
this statement is equivalent to
#2 //Wait for 2 time unit
b = a //sample the value of 'a' and assign to b
After 3 time unit, since 'always' block is in top of the simulator queue, value of 'a' will still be '1' and it gets assigned to 'c'. After this 'initial' statement is executed and value of '2' is assigned to 'a'. Rest of the output, behaves in the same fashion. Hope this helps.

As I said earlier, Output depends on the simulator. I think for the time stamp #9, 'initial' block went 1st to the simulator queue. So it updated the 'a' to 5. In the same time stamp 'always' block is executed after 'initial' block. So 'c' and 'd' are assigned with updated value of 'a' which is '5'.
Since the time stamp is still #9, this value of 'a' which is '5' is sampled and gets stored in temporary variable. This is later assigned to 'c' at time stamp #10. Hope this make sense.
So this is not a good way of coding. This results in ambiguous results. In order to illustrate this ambiguous result, I can given an example. Consider following codes.
always#(posedge clk)
begin
cnt = cnt+1;
end
always#(posedge clk)
begin
A = cnt;
end
If the initial value of 'cnt' is 40, what is the value of 'A' in next clock cycle. See, now the output depends on the simulator. It depends on which 'always' block goes 1st to the simulator queue. If the 1st 'always' block is executed 1st, 'A' value is '41' else it is '40'. This can be removed by using non-blocking statements "<=".
always#(posedge clk)
begin
cnt <= cnt+1;
end
always#(posedge clk)
begin
A <= cnt;
end
Now 'A' will be 40 irrespective of simulator. Hope this helps.

Related

Diference in bit selection in Verilog

I have a code similar to the following
module testModule(
input Clk,
input [2:0] Counter,
output [1:0] OutVar1,
output [1:0] OutVar2
);
localparam logic [7:0] mask = 8'h50;
// CODE 1
always_ff #(posedge Clk) begin
case (mask[{Counter[1:0], 1'b0} +: 2])
2'h0 : OutVar1 <= 2'h0;
2'h1 : OutVar1 <= 2'h1;
2'h2 : OutVar1 <= 2'h2;
2'h3 : OutVar1 <= 2'h3;
default: OutVar1 <= 2'hX;
endcase
end
// CODE 2
always_ff #(posedge Clk) begin
case (mask[(Counter[1:0]<<1) +: 2])
2'h0 : OutVar2 <= 2'h0;
2'h1 : OutVar2 <= 2'h1;
2'h2 : OutVar2 <= 2'h2;
2'h3 : OutVar2 <= 2'h3;
default: OutVar2 <= 2'hX;
endcase
end
endmodule
Counter is a input that goes 0, 2, 4, 6, 0, 2, 4, etc.
And I expected CODE 1 and CODE 2 to behave the same but when counter is 2 and 6 (counter[1:0] is 2) I hit the case 2'h1 in CODE 1 (correct) and 2'h0 in CODE 2 (wrong).
I have not checked yet what is the behaviour if counter goes 0, 1, ..., 7, 0, 1, etc.
I do not have a testbed because this code is part of a large project. I saw the problem after simulation and seeing the waves.
What am I missing?
I suspect you're missing that only 2 bits are used to calculate the answer in "CODE 2", because it is a so-called self-determined expression. So, Verilog takes the expression:
counter[1:0]<<1
and needs to decide how many bits to use for the answer. This is what it does: it looks at how many bits there are on the left hand side of the shift operator (2) and uses that to put the result in. How could it do anything else? The number of bits on the right hand side (32) is basically irrelevant (unless you think Verilog should use 2^31-1 bits for the result!). So, you get an overflow - the left hand side of the result of the shift is truncated.
See this answer here.

How do I use combinational logic while using posedge?

I am a beginner at Verilog and I am trying to get logic to occur every positive clock edge. However, within this same block, I need combinational logic as I am using a for-loop and changing the value of a register within the for-loop. Currently, the value of this register always shows up as X. Is there a way to get this logic processed within a sequential block? Thanks!
Code:
output reg count;
// ...
always #(posedge clock) begin
integer row;
integer col;
count <= 0;
for (col = 0; col < 4; col = col + 1) begin
if (col == 1)
count <= count + 1;
if (count == 1) begin
//other logic that does not occur because count value = x
end
end
end
Non-blocking assignment works does not assign values immediately to the 'count'. Instead they postpone the assignment till the end of the simulation tick. So, in your case:
initially the value of the count is x.
in your always block count <= 0 will set it to zero some time in the future, but for now it is still x;
in your loop you say count <= count + 1. But the count is still 'x' and count + 1 is also x. You asked it to assign x to the count some time in the future, but after you asked it to assign '0'. So, it will become 'x' at the end of the simulation tick. As a result it will always be 'x'.
your if (count == 1) which will never be true, because count is still 'x'.
The usual way to initialize your count is to have a reset signal, for example
always #(posedge clk) begin
if (reset)
count <= 0;
else
for(...)
if (col == 1)
count <= count + 1;
end
you can add your if (count == 1) inside the always block, but remember the rule of the non-blocking assignments, count will become '1' one clock cycle later in this case. Depending on your requirements you might be able to move it into a separate always block.
always #*
if (count == 1) do something
else do something else

Clean way to truncate result of addition or subtraction

When I do addition or subtraction in Verilog, some compilers emit warning.
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
// warning example
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 11 to match size of target (10) File: xxx.sv Line: xxx
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 32 to match size of target (10) File: xxx.sv Line: xxx
I want to find clean way to remove these warnings. I tried two methods:
// method 1
b <= (a + 1)[9 : 0];
// method 2
logic [10 : 0] d;
d <= a + 1;
b <= d[9 : 0];
I thought the first method would compile, but it was invalid syntax in verilog.
Second method works, but it is too verbose and dirty.
Is there any other clean ways?
From IEEE Std 1364-2001.
Page 73:
Table 29—Bit lengths resulting from self-determined expressions:
Unsized constant number = Same as integer
Page 45:
NOTE Implementations may limit the maximum size of an integer variable, but they shall at least be 32 bits.
So the warnings you see come from trying to operate one unsized numeric constant (32 bits at least) with a sized variable (10 bits), so the synthesizer warns about the result may overflow.
So, just make sure all your operands have the same size:
Instead of:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
Do:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 10'd1;
c <= a - 10'd1;
end
1 id a 32-bit value. As a result the width of the expression is 32.
The way around is to use a sized value of '1', i.e.
b <= a + 1'b1;
c <= b - 1'b1;
This can potentially give you an 11-bit result. Carryon bit will be lost. At this point you can do some other tricks. I guess this is the most common one. Use a carry on bit.
logic con;
logic[9:0] a,b;
...
{con, a} <= b + 1'b1;
You can use a temp variable, as in your example.
In general, verilog standard does allow free truncation or extension of operand widths and no warning is required. Definitely in this case you can ignore the warning or turn it off. I have not seen simulators which would warn about it. Just certain rule in linting tools.
Use curley concatination braces
b <= {a + 1}[9 : 0];
or change the constant size (which defaults to 32-bits)
b <= a + 10'd1;

How to dynamically change value assigned to a vector register

I am a newbie to verilog coding. In my problem statement, I will get number of entries in a sorted table from another module and based on number of entries I need to decide where should I start my binary search
(e.g. Let num_entries be 15, then start index should be 8). Code snippet is given below:
srch_addr <= {{(TBL_AW-msb_loc(num_entries)-1){1'b0}},2'b10, {(msb_loc(num_entries)-1){1'b0}}};
//function to find out MSB 1
integer LOC;
function [3:0] msb_loc;
input [TBL_AW:0] num_entries;
reg found;
//input start;
begin
//if(start = 1)
//begin
found = 1'b0;
msb_loc = 3'b000;
for (LOC=TBL_AW; LOC> 0; LOC=LOC-1)
begin
if((num_entries[LOC] == 1) && !found)
begin
msb_loc = LOC;
found = 1'b1; //TO exit the loop
end
end
//end
end
endfunction
Compiler gives me this error "Illegal operand for constant expression". What can be done to resolve this error?
The replicator 'count' value must be a non-zero, non-X and non-Z constant expression.
{(TBL_AW-msb_loc(num_entries)-1){1'b0}}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not a constant.
To get the 'halfway' address you can just the standard mathematical way: divided and round upwards. In this case add one and divide by two:
srch_addr <= (msb_loc(num_entries)+1)>>1;
Coming back to your formula. This part just makes zeros: {(TBL_AW-msb_loc(num_entries)-1){1'b0}} You don't need that.
This part 2'b10, {(msb_loc(num_entries)-1){1'b0}} actually shifts 2'b10 left by "(msb_loc(num_entries)-1)" positions.
This does the same but then without syntax errors:
srch_addr <= 1'b1 << msb_loc(num_entries);
What I can see it does NOT give you the half-way address.
Further:
Your integer LOC; should be inside your function as a local variable.

Verilog - generate weighted random numbers

I am trying to generate random single bits and this is simple as long as you want a normal randomization:
wire R;
assign R = $random % 2;
What I am looking for is a sort of weighted probability like:
wire R;
assign R = 60%(0) || 40%(1);
Forgive me if it is not conform to standard Verilog code, it is just to give an idea of what I want.
Can anyone help me out?
Thank you
The SystemVerilog solution has a distribution method within randomize called dist. Weights are assigned by value_or_range := weight or value_or_range :/ distributed_weight. This exert from the IEEE Std 1800-2012 § 18.5.4 page 476 gives a clear example:
When weights are applied to ranges, they can be applied to each value in the range, or they can be applied to the range as a whole. For example:
x dist { [100:102] := 1, 200 := 2, 300 := 5}
means x is equal to 100, 101, 102, 200, or 300 with a weighted ratio of 1-1-1-2-5, and
x dist { [100:102] :/ 1, 200 := 2, 300 := 5}
means x is equal to one of 100, 101, 102, 200, or 300 with a weighted ratio of
1/3-1/3-1/3-2-5.
dist is used in randomization so it needs to be mare of a randomize() with (or a class constraint). randomize returns a success bit, therefore it should be in called within an assert, void'(), or the RHS of an assignment.
In your we can set the weight of 0 to 6 and the weight of 1 to 4, creating a total weight of 10 with a 60/40 distribution. Example:
reg R;
initial begin
assert( randomize(R) with { R dist { 0 := 6, 1 := 4 }; } );
end
From more about dist see IEEE Std 1800-2012 § 18.5.4 "Distribution".
Create a random integer then based on Value return 1 or 0; NB you may want to seed your random number, for repeatability use the same seed. This way when a test fails it can be debugged.
$urandom works a little different to $random it doe not update the seed value so should only be seeded the first time it is called in a thread (always block). It is also thread safe, each always block works independently.
initial begin
$urandom(seed);
$urandom;
$urandom;
end
integer temp;
reg r ;
always # ... begin
temp = $urandom; //Range: +2_147_483_647 -2_147_483_648
// weighting; 0 would be 50:50
// real weighting is (0.1 + 0.5), 0.5 inherent from positive number.
r = (temp > (2_147_483_647*0.1);
end
NB: the random functions are not synthesizable and should only be used for testbenches. if you want a random number for synthesis check out this Question
For Verilog you can always so something like:
integer R;
R = ($dist_uniform(0,100) < 60) : $dist_uniform(0,5) : $dist_uniform(6,10)
and this in SystemVerilog would be the same as:
std::randomize(R) with {R dist {[0:5] :/60, [6:10] :/ 40} ;};
You could also do this procedural code:
randcase
60: R = 1;
40: R = 0;
endcase
Following Code Will Generate Random Variable as Per Your Requirement :
program top;
class Packet;
rand reg R;
constraint percentage {R dist {1:=60,0:=40};};
function void display;
$display("Random Reg : %0d",this.R);
endfunction
endclass
Packet P;
initial
begin
P = new;
repeat(10)
begin
P.randomize();
P.display;
end
end
endprogram
It seems not so hard at verilog.
reg [7:0] R;
reg rand_bit;
R = $random();
if (R < 76)
rand_bit = 1'b0;
else
rand_bit = 1'b1;
Here I assume that $random is pretty uniform. I think it should work :)
Something like:
wire R;
if ($random[7:0]>(40*255/100))
assign R = 1'b0;
else
assign R = 1'b1;
I'm assuming that the algorithm that $random uses produces numbers that are equally random whatever bits you take from it.

Resources