How to write string values in Verilog testbench? - verilog

I am trying to write a Verilog test-bench where I have to write output of some registers. I want to write L instead of 0, and H instead of 1 e.g '100101' as g 'HLLHLH'. I know about writing binary, hex or decimal value, but I am not sure whether it can be done in Verilog or not?

Assuming you're not using SystemVerilog, you could write a task, eg:
task LHwrite (input integer bin, input integer length);
integer i;
for (i=length-1; i>=0; i=i-1)
$write("%s", "L"-(bin[i]*8'h4));
endtask
bin is the value you want to display (up to 32 bits); length is the number of bits you want to display. The task iterates over the input:
for (i=length-1; i>=0; i=i-1)
and then uses the $write system task (which is like $display but without a newline) to display the string you want. This is calculated based on the knowledge that the ASCII code for 'H' is 8'h48 and for 'L' is 8'h4C.
https://www.edaplayground.com/x/4Ewk
module M;
task LHwrite (input integer bin, input integer length);
integer i;
for (i=length-1; i>=0; i=i-1)
$write("%s", "L"-(bin[i]*8'h4));
endtask
initial
begin : test
reg [5:0] bin = 6'b100101;
LHwrite(bin, 6);
$write("\n");
end
endmodule

System verilog testbench is a programming language. You can do normal programming things in it. However, in this case you would need to create your resulting string bit by bit like in the following example:
program a;
bit [3:0] data = 4'b1100;
initial begin
string out;
$display("%b ==> ", data);
for (int i = 0; i < $bits(data); i++) begin
if ((data & ($bits(data)) == 0)
out = {"L", out};
else
out = {"H", out};
data >>= 1;
end
$display(" ==> %s", out);
end
endprogram
result:
1100 ==>
==> HHLL

Related

Writing a Verilog function to Locate the index of the first one on the right in the vector

I am Writing a Verilog function to Locate the index of the first one on the right in the vector.If the vector has no ones, the function should returns the value to the vector’s highest index + 1. Here is the code :
module m ();
parameter n = 3;
function integer Locate_one (input [n-1:0] a );
Locate_one ='dx;
for (integer i =n-1 ; i<=0 ; i=i-1)
begin
if(a[i] == 1'b1)
begin
Locate_one=i;
break;
end
end
if (Locate_one=='dx)
Locate_one=n;
endfunction
initial begin
reg [n-1:0] a = 3'b111;
integer result = Locate_one (a);
$display("output is %d ", result);
end
endmodule
Th questions are as follows :
How to break out of the function when we find the highest one ? I have used the keyword break, which is as I found online, is a valid SystemVerilog keyword not Verilog Keyword.
The strategy that I have used to know that there is no one in the vector is that I have initialized the return integer to X and then I have compared the variable to X at the end of the function. Is this a good way to do so or there is another better way to do this comparison ?
There are a number of problems with your code.
You cannot use the == to compare with x—it always returns false. you must use the === operator
You are initializing two static variables a and result and the order of initializations is not defined. They are not procedural statements. SystemVerilog has made implicitly static variable initializations inside procedural code illegal, and that is the only backward incompatibility with Verilog I can think of.
Your code has a lot of SystemVerilog constructs besides break
declaring a variable in a for loop
a function/task body without begin/end keywords.
You should not be using x values in your code. It's not synthesizable, and it makes debugging your code more difficult if you made a mistake.
Your loop condition was the opposite of what you needed.
You can use a disable statement to get functionality similar to a break if you want strict Verilog compatibility.
module m ();
parameter n = 5;
function integer Locate_one (input [n-1:0] a );
integer i;
begin : block
Locate_one = n;
for (i =n-1 ; i>=0 ; i=i-1)
begin
if(a[i] == 1'b1)
begin
Locate_one=i;
disable block;
end
end
end
endfunction
reg [n-1:0] a = 3'b111;
initial begin
integer result;
result = Locate_one (a);
$display("output is %d ", result);
end
endmodule
Here is the SystemVerilog code
module m ();
parameter n = 5;
function int Locate_one (input [n-1:0] a );
Locate_one = n;
for (int i =n-1 ; i>=0 ; i=i-1)
begin
if(a[i] == 1'b1)
begin
Locate_one=i;
break;
end
end
endfunction
logic [n-1:0] a = 3'b111;
int result;
initial begin
result = Locate_one (a);
$display("output is %d ", result);
end
endmodule
I would go with a temp variable inside the function block, indicating if the "1" has been found. It wasn't necessary to initialise the index variable with X's, this should do the work: (I believe this is for simulation purposes as there are no input/output ports)
module first_one ();
parameter n = 3;
reg [n-1:0] a;
function integer locate_one;
input [n-1:0] a;
integer i;
reg found_temp;
begin
found_temp = 0;
for (i=0; i<n; i=i+1) begin
if(a[i] == 1'b1 & ~found_temp) begin
locate_one = i;
found_temp = 1;
end
end
if(~found_temp)
locate_one = n;
end
endfunction
initial begin
a = 0;
$monitor("a = %b : index = %d", a, result);
#100 $finish;
end
wire [$clog2(n)-1:0] result = locate_one(a);
always
#1 a = $urandom;
endmodule
This can be tested with icarus verilog:
iverilog first_one.v -o first_one.tb
vvp first_one.tb

Writing a simple function to count number of ones in a vector

As a task for learning how to write functions in Verilog, I am trying to write a function that just counts the number of ones in a given vector:
module m ();
parameter n = 4;
function integer count_ones (input [n-1:0] a);
for (integer i = 0 ; i<n ; i=i+1)
begin
if (a[i] ==1'b1)begin
count_ones=count_ones+1;
end
end
endfunction
initial begin
reg [3:0] a = 4'b1;
integer result = count_ones (a);
$display("output is ", result);
end
endmodule
The result is displayed as x. So what is the error in this code ?
You declare count_ones as type integer, which is a 4-state type, and its default value is x. Also, count_ones=count_ones+1; keeps count_ones equal to x.
You should initialize count_ones inside the function.
function integer count_ones (input [n-1:0] a);
count_ones = 0;
Keep in mind that there is a built-in $countones system function. Refer to IEEE Std 1800-2017, section 20.9 Bit vector system functions.

Unexpected behaviour using the ternary operator (Verilog)

In the following Verilog module, I'd like to understand why the blocking assignment using concatenation doesn't give the same result as the 2 commented out blocking assignments.
When I run the program on the FPGA, it gives the expected result with the 2 blocking assignments (the leds blink), but not with the blocking assignment using concatenation (the leds stay off).
Bonus points for answers pointing to the Verilog specification explaining what is at play here!
/* Every second, the set of leds that are lit will change */
module blinky(
input clk,
output [3:0] led
);
reg [3:0] count = 0;
reg [27:0] i = 0;
localparam [27:0] nTicksPerSecond = 100000000;
assign led = {count[3],count[2],count[1],count[0]};
always # (posedge(clk)) begin
// This works:
//count = i==nTicksPerSecond ? (count + 1) : count;
//i = i==nTicksPerSecond ? 0 : i+1;
// But this doesn't:
{count,i} = i==nTicksPerSecond ?
{count+1, 28'b0 } :
{count , i+1};
end
endmodule
PS: I use Vivado 2018.2
The reason is because the widths of count+1 and i+1 are both 32 bits. An unsized number is 32 bits wide (1800-2017 LRM section 5.7.1) and the width of the addition operator is the size of the largest operand (LRM section 11.6.1). To make your code work, add a proper size to your numeric literals
{count,i} = i==nTicksPerSecond ?
{count+4'd1, 28'b0 } :
{count , i+28'd1};
A simpler way to write this code is
always # (posedge clk)
if (i== nTicksPerSecond)
begin
count <= count + 1;
i <= 0;
end
else
begin
i <= i + 1;
end

Bit slicing in verilog

How can I write wdata[((8*j)+7) : (8*i)] = $random; in verilog programming language? , where i and j are reg type variable. Modelsim gives error for constant range variable. How could I write it in proper manner.
You should think from Hardware prospective for the solution.
Here is one solution. Hope that it will help you.
module temp(clk);
input clk;
reg i, j;
reg [23:0] register, select;
wire [23:0] temp;
initial
begin
i = 'd1;
j = 'd1;
end
generate
for(genvar i = 0; i<24; i++)
begin
assign temp[i] = select[i] ? $random : register[i];
end
endgenerate
always # (posedge clk)
begin
register <= temp;
end
always # *
begin
select = (32'hffff_ffff << ((j<<3)+8)) ^ (32'hffff_ffff << (i<<3));
end
endmodule
Use the array slicing construction. You can find more detailed explanation at Array slicing Q&A
bit [7:0] PA, PB;
int loc;
initial begin
loc = 3;
PA = PB; // Read/Write
PA[7:4] = 'hA; // Read/Write of a slice
PA[loc -:4] = PA[loc+1 +:4]; // Read/Write of a variable slice equivalent to PA[3:0] = PA[7:4];
end
Verilog 2001 Syntax
[M -: N] // negative offset from bit index M, N bit result
[M +: N] // positive offset from bit index M, N bit result

systemverilog arithmetic operation returns negative value

I have a part of code of my design as follows.
parameter n=256;
input [n-1:0] x;
output y;
initial begin
x = 0;
if(0 >= unsigned'(x-9))
y = 1;
end
My expectation is, the unsigned subtraction operation should return decimal 247 but in actual it returns -9. Is anyone having better way of coding to achieve this?
My actual requirement is, even if I subtract a smaller value from larger, the value should rollover w.r.t. parameter width (As if 0-1 should yield 255). My question may be wrong but this requirement is necessary from my project.
247 and -9 are the same bit pattern so the arithmetic is correct. Signed vs unsigned is an interpretation of the bit pattern.
NB: 0-1 is only 255 with 8 bit numbers you have defined them as 256 bit numbers.
The following example should help clarify, We use $signed and $unsigned keywords which alters how the decimal representation is displayed but the underlying binary form does not change.
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
$display("%1d", x-9);
$display("%1b", x-9);
$display("");
$display("%1d", $unsigned(x-9) );
$display("%1b", $unsigned(x-9) );
$display("");
$display("%1d", $signed(x-9) );
$display("%1b", $signed(x-9) );
$display("");
$finish;
end
endmodule
Which Outputs:
4294967287
11111111111111111111111111110111
4294967287
11111111111111111111111111110111
-9
11111111111111111111111111110111
For your example you just need to use $unsigned:
module tb;
parameter n=8;
logic [n-1:0] x;
logic y;
initial begin
x = 0;
if(0 >= $unsigned(x-9)) begin
y = 1;
end
else begin
y = 0;
end
$display("y: %b", y);
$finish;
end
endmodule

Resources