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

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.

Related

Multi dimensional array value assignment in verilog

The verilog below code as you see uses a multi-dimensional register array for storing the data.
parameter DSIZE = 8;
parameter ASIZE = 4;
input [DSIZE-1:0] wdata;
input wclk,wen;
reg [ASIZE:0] wptr;
parameter MEMDEPTH = 1<<ASIZE;
reg [DSIZE-1:0] ex_mem [0:MEMDEPTH-1];
always #(posedge wclk)
if (wen)
ex_mem[wptr[ASIZE-1:0]] <= wdata;
I do not properly understand what happens in the last assignment statement in which ex_mem is assigned the value in wdata. What does the part in the brackets (wptr[ASIZE-1:0]) associated with ex_mem return and to what location of ex_mem does wdata get stored into?
In the code, ex_mem is a memory that has 16 (MEMDEPTH) slots. Each slot has 8 (DSIZE) bits. 16 slots can be addressed by 4 (ASIZE) bits, but wptr is a 5-bit signal for some reason, so its most significant bit (MSB) is not used for addressing the memory.
ex_mem[wptr[ASIZE-1:0]] <= wdata;
Since wptr[ASIZE-1:0] is a 4-bit signal (for ASIZE=4), the assignment above may write to a slot between ex_mem[0] and ex_mem[15].
'wptr' is just a one-dimensional register.
So, first of all verilog extracts an index to ex_mem from the 'wptr' thing. It uses this range to do so: ASIZE-1:0.
If ASIZE is 4, as in your example, it can sample values from 0 to 15 from there. For example,
reg [4:0] wptr = 0x1B;
wptr[3:0] will give you 'B' (11).
Now this index value will be applied to the ex_mem array to write your data.

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;

Unsigned reg subtraction in Verilog

I have some troubles with unsigned reg subtraction in Verilog.
The following Verilog code is designed for a 4-bit ALU :
module p2(in_1,in_2,s,out);
input [3:0]in_1,in_2;
input [1:0]s;
output [4:0]out;
reg [4:0]out;
parameter ADD=2'b00;
parameter SUBTRACT=2'b01;
parameter AND=2'b10;
parameter OR=2'b11;
always #(in_1,in_2,s)
begin
case (s)
ADD: out=in_1+in_2;
SUBTRACT: out=in_1-in_2;
AND: out={1'b0,(in_1&in_2)};
OR: out={1'b0,(in_1|in_2)};
endcase
end
endmodule
Problem1:
For the case in_1=4'b0000,in_2=4'b0001,s=2'b01
I think in_1-in_2 should be: 0000-0001=0000+(1110+1)=1111
So 1111 should be zero-extended(due to unsigned subtraction) to 01111,
then is assigned to out=5'b01111
However,the correct result show that out=5'b11111
Why?
Problem2:
For the case in_1=4'b0001,in_2=4'b0001,s=2'b01
I think in_1-in_2 should be: 0001-0001=0001+(1110+1)=10000
Then it is assigned to out=5'b10000
However,the correct result show that out=5'b00000
Why?
For physical hardware, a register contains only the binary data, signed unsigned are of just a matter of human interpretations.
Here, in your case, it is a matter of Expression width evaluation. Referring to SystemVerilog LRM 1800-2012, section 11.6:
The number of bits of an expression is determined by the operands and the context.
SystemVerilog uses the bit length of the operands to determine how many bits to use while evaluating an expression.
The bit length rules are given in 11.6.1. In the case of the addition operator, the bit length of the
largest operand, including the left-hand side of an assignment, shall be used.
The number of bits of an expression (known as the size of the expression) shall be determined by the
operands involved in the expression and the context in which the expression is given.
Referring to example given in LRM:
logic [15:0] a, b; // 16-bit variable
logic [15:0] sumA;
logic [16:0] sumB; // 17-bit variable
sumA = a + b; // expression evaluates using 16 bits
sumB = a + b; // expression evaluates using 17 bits
The mistake you are making here is calculating 2's complement for 4-bits and expecting a 5-bit output. While the language uses maximum bit length in an expression to do the same.
Here, out is a 5-bit register. So the 2's complement of minuend is taken for five bits. That is, 2's complement of 4'b0001 is 5'b11111. Adding this to an extension of 4'b0000 as 5'b00000, we get 5'b11111. Henceforth your first problem's result.
Similar, comments applies for your Problem-2, Adding 5'b11111 to 5'b00001 results in 5'b00000.
For more information about signed subtraction, refer to this, this and this links.

How range overflow affects the simulation and synthesis?

module dut ( a,b_out,array,c);
input [2:0] a;
input [3:0] array;
input c;
output reg b_out;
always#( a or c or array) begin
if(c)
b_out = 1'b0;
else
b_out = array[a];
end
endmodule
There is a possible range overflow in the above RTL, how it exactly affects the simulation and synthesis?
When a > 3 and !c then b_out will be undef in simulation because an out-of bounds access to a vector returns undef (i.e. 1'bx). See 5.2.1 in IEEE Std 1364-2005:
A part-select of any type that addresses a range of bits that are
completely out of the address bounds of the net, reg, integer, time
variable, or parameter or a part-select that is x or z shall yield the
value x when read and shall have no effect on the data stored when
written. Part-selects that are partially out of range shall, when
read, return x for the bits that are out of range and shall, when
written, only affect the bits that are in range.
In synthesis this don't care will be transformed into whatever the synthesis tool deems the most efficient. Very likely that means that only the bottom two bits of a are used in array[a], i.e. it is identical to array[a[1:0]]. But there is no guarantee for that whatsoever and it would be equally correct to create a circuit that for example always returns 1 or 0 when a[2] is high.

Math operations on time values

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

Resources