How to create an array to store integers in a testbench? - verilog

I'm going through all my Verilog modules and creating good testbenches for them. I already finished the larger project, but I want to get better at writing testbenches as well as upload the testbenches to the project repository.
I have the following code for a testbench that tests a module I have. This module takes a 16-bit input, trims it down to 10 bits (data input from an accelerometer, only 10 bits are used but the input is 16 bits for consistency), then converts the 10 bit signed number into decimal by outputting the number of ones, tens, hundreds, and thousands.
This is the code I have for the testbench (Note: Decimal_Data represents the "usable" 10 bits of data):
module Binary_to_Decimal_TB();
reg [15:0] Accel_Data = 16'd0;
wire [3:0] ones;
wire [3:0] tens;
wire [3:0] hundreds;
wire [3:0] thousands;
wire negative;
wire [9:0] Decimal_Data;
integer i;
integer j = 0;
Binary_to_Decimal BtD(.Accel_Data(Accel_Data), .Decimal_Data(Decimal_Data),
.ones(ones), .tens(tens), .hundreds(hundreds), .thousands(thousands), .negative(negative));
initial
begin
for (i = 0; i < 2047; i = i + 1)
begin
Accel_Data = i;
#2;
if (Decimal_Data < 512)
begin
if (((ones * 1) + (tens * 10) + (hundreds * 100) + (thousands * 1000)) != 4 * Decimal_Data)
j = j + 1;
end
else if (Decimal_Data == 512)
begin
if (((ones * 1) + (tens * 10) + (hundreds * 100) + (thousands * 1000)) != 0)
j = j + 1;
end
else
begin
if (((ones * 1) + (tens * 10) + (hundreds * 100) + (thousands * 1000)) != 2048 - (4 * (Decimal_Data - 512)))
j = j + 1;
end
end
$display("Conversion mismatches:", j);
$finish;
end
endmodule
It works as it should, and I get zero mismatches between the numbers represented by the converted data, and the original 2's complement 10-bit number.
However, I want to write it so that if there were an error, it would save the binary number where there is a mismatch between the input and output. In C++, I'd create an array, and dynamically allocate it with the binary numbers where a mismatch is detected (since we don't know how many mismatches there would be if the design were faulty).
More clearly, right now I can see how many mismatch errors occur. I want to implement a way to see where the errors occur
I know I'd write to the array in the conditional where I increment j, but I don't know how to create an array that's used for this purpose in Verilog.
Also, I've heard SystemVerilog is better for verification, so maybe there's something in SystemVerilog that I could use to accomplish this? I haven't really looked into SystemVerilog, but I do want to learn it.

In SystemVerilog you can create a queue, which is dynamic, to store the mismatched results.
logic [15:0] mismatches [$];
...
if (Decimal_Data < 512)
begin
if (((ones * 1) + (tens * 10) + (hundreds * 100) + (thousands * 1000)) !== 4 * Decimal_Data) begin
j = j + 1;
mismatches.push_back(Accel_Data);
end
end
...
$display("Conversion mismatches:", j);
foreach (mismatches[i]) $display(mismatches[i]);
$finish;
Refer to IEEE Std 1800-2017, section 7.10 Queues.
Since you are comparing 4-state values, you should use the case inequality operator (!==), as I have shown above. Furthermore, since you are comparing your DUT outputs to each other, you should also check if there are x or z values using $isunknown.
Also, there is common code in your testbench which can be combined. This is especially important as you add more checking code. For example:
logic [15:0] mismatches [$];
integer expect_data;
initial
begin
for (i = 0; i < 2047; i = i + 1)
begin
Accel_Data = i;
#2;
if (Decimal_Data < 512)
begin
expect_data = 4 * Decimal_Data;
end
else if (Decimal_Data == 512)
begin
expect_data = 0;
end
else
begin
expect_data = 2048 - (4 * (Decimal_Data - 512));
end
if (((ones * 1) + (tens * 10) + (hundreds * 100) + (thousands * 1000)) !== expect_data) begin
j = j + 1;
mismatches.push_back(Accel_Data);
end
end
$display("Conversion mismatches:", j);
foreach (mismatches[i]) $display(mismatches[i]);
$finish;
end
endmodule

Out of curiosity, why not print the mismatches when they occur? No need to store them and print them out later since it is all non-synthesized code. Example:
logic [15:0] mismatches [$];
...
if (Decimal_Data < 512)
begin
if (((ones * 1) + (tens * 10) + (hundreds * 100) + (thousands * 1000)) !== 4 * Decimal_Data) begin
j = j + 1;
$display("ERROR: Mistmatch (expected=%d) (actual=%d) #%t", 4*Decimal_data, ones+(tens*10)+(hundreds*100)+(thousands*1000), $time);
end
end
...
$display("Conversion mismatches:", j);
$finish;

Related

how to declare integer variable in verilog to keep track of a value to be used in multiple for loops?

so I have this assignment to make a generic Wallace tree multiplier in Verilog, I wrote the code but didn't test it yet. my problem is in the 2nd stage where I am supposed to bypass some wires which couldn't fit in the current stage into the next stage and the results of the current stages are passed to next stage, so I made a simple for loop to that operation:
/*the logic in this module*/
generate
for(i = 0; i < size/3; i = i + 1)
begin
integer k = 0;
for(j = i; j < size-3; j = j + 3)
begin
CSAlike #(2 * size) parallelAdder(intermediateWires[k][i+1], intermediateWires[k+1][i+1], intermediateWires[j][i], intermediateWires[j+1][i], intermediateWires[j+2][i]);
k = k + 2;
end
/*assign the wires from this stage who couldn't fit into the current stage (0 or 1 or 2 wires)*/
for(l = size-(size%3); l < size; l = l + 1)
begin
assign intermediateWires[k][i+1] = intermediateWires[l][i];
k = k + 1;
end
end
endgenerate
well , ModelSim give me this error :
vlog -work work -stats=none {D:/PROJECTS/third year/first term/VLSI/mini project 2/codes (before synthesis)/verilog codes/multiplierTree.v}
Model Technology ModelSim - Intel FPGA Edition vlog 2020.1 Compiler 2020.02 Feb 28 2020
-- Compiling module multiplierTree
** Warning: D:/PROJECTS/third year/first term/VLSI/mini project 2/codes (before synthesis)/verilog codes/multiplierTree.v(17): (vlog-2417) Multiple packed dimensions are not allowed.
-- Compiling module multiplyAllBits
** Warning: D:/PROJECTS/third year/first term/VLSI/mini project 2/codes (before synthesis)/verilog codes/multiplierTree.v(46): (vlog-2417) Multiple packed dimensions are not allowed.
-- Compiling module addIntermedaiteWires
** Warning: D:/PROJECTS/third year/first term/VLSI/mini project 2/codes (before synthesis)/verilog codes/multiplierTree.v(61): (vlog-2417) Multiple packed dimensions are not allowed.
** Warning: D:/PROJECTS/third year/first term/VLSI/mini project 2/codes (before synthesis)/verilog codes/multiplierTree.v(67): (vlog-2417) Multiple packed dimensions are not allowed.
** Error: (vlog-13069) D:/PROJECTS/third year/first term/VLSI/mini project 2/codes (before synthesis)/verilog codes/multiplierTree.v(92): near "=": syntax error, unexpected '='.
** Error: D:/PROJECTS/third year/first term/VLSI/mini project 2/codes (before synthesis)/verilog codes/multiplierTree.v(92): (vlog-13205) Syntax error found in the scope following 'k'. Is there a missing '::'?
and this is the full code:
/*resources :
https://www.youtube.com/watch?v=4-l_PGPog9o
https://www.youtube.com/watch?v=lcPIMvI57dM
*/
module multiplierTree #(parameter size = 32) (Res, OVF, A, B, clk);
/*the inputs to be multiplies*/
input [size-1:0] A, B;
input clk;
reg [size-1:0] A_in, B_in;
/*the outputs from the multiplier*/
output reg [(size-1)*2:0] Res;
output wire OVF; // overflow flag
/*intermediate wires for clean code*/
wire [size-1:0][(size-1)*2:0] wiresMultiplied;
wire [(size-1)*2:0] secondStage_Res, secondStage_carry, totalRes;
/*calling necessary modules*/
multiplyAllBits #(size) firstStage(wiresMultiplied, A_in, B_in);
addIntermedaiteWires #(size) secondStage(secondStage_Res, secondStage_carry, wiresMultiplied);
addResWithCarry #(2 * size) thirdStage(totalRes, secondStage_Res, secondStage_carry);
/*important assigns*/
assign OVF = Res[(size-1)*2] ^ A[size-1] & Res[(size-1)*2] ^ B[size-1] ;
/*the logic of the module*/
always#(posedge clk)
begin
A_in <= A;
B_in <= B;
Res <= totalRes;
end
endmodule
/*this is the first stage in the wallace tree*/
module multiplyAllBits #(parameter size = 32) (wiresMultiplied, A, B);
/*inputs to 1st stage of wallace tree*/
input wire [size-1:0] A, B;
/*outputs from the 1st stage*/
output wire [size-1:0][(size-1)*2:0] wiresMultiplied;
/*the actual logic in the circuit*/
genvar i, j;
generate
for(i = 0; i < size; i = i + 1)
assign wiresMultiplied[i] = ({size{B[i]}} & A) << i;
endgenerate
endmodule
/*this is the second stage in wallace tree*/
module addIntermedaiteWires #(parameter size = 32) (Res, carry, wiresMultiplied);
/*inputs coming from the 1st stage*/
input wire [size-1:0][(size-1)*2:0] wiresMultiplied;
/*outputs from 2nd stage*/
output wire [(size-1)*2:0] Res, carry;
/*intermediate wires for clean code*/
wire [size+1:0][size+1:0][(size-1)*2:0] intermediateWires;
genvar i, j, l;
/*important assigns*/
generate
for(i = 0; i < size; i = i + 1)
begin
assign intermediateWires[i][0] = wiresMultiplied[i];
end
endgenerate
/*getting the results*/
assign Res = intermediateWires[size+1][size+1];
assign calling = intermediateWires[size+1][size+1];
/*the logic in this module*/
generate
for(i = 0; i < size/3; i = i + 1)
begin
integer k = 0;
for(j = i; j < size-3; j = j + 3)
begin
CSAlike #(2 * size) parallelAdder(intermediateWires[k][i+1], intermediateWires[k+1][i+1], intermediateWires[j][i], intermediateWires[j+1][i], intermediateWires[j+2][i]);
k = k + 2;
end
/*assign the wires from this stage who couldn't fit into the current stage (0 or 1 or 2 wires)*/
for(l = size-(size%3); l < size; l = l + 1)
begin
assign intermediateWires[k][i+1] = intermediateWires[l][i];
k = k + 1;
end
end
endgenerate
endmodule
/*this is CSA look like to add parallely*/
module CSAlike #(parameter size = 32) (result, carry, A, B, C);
/*list of the inputs*/
input wire [size-1:0] A, B, C;
/*outputs*/
output wire [size-1:0] result, carry;
/*temp genvar*/
genvar i;
/*actual logic of parallel adders*/
for(i = 0; i < size; i = i + 1)
begin
FA fa(A[i], B[i], C[i], result[i], carry[i]);
end
endmodule
module addResWithCarry #(parameter size = 32) (Res_out, Res_in, carry_in);
/*list of the inputs*/
input wire [size-1:0] Res_in, carry_in;
/*outputs*/
output wire [size-1:0] Res_out;
/*using normar adder (verilog adder (adder plus))*/
assign Res_out = Res_in + carry_in;
endmodule
as it tells me that writing
k = k + 2;
is wrong inside the generate loop, but I don't know why, also it gave me some warnings telling me that writing
wire [size-1:0][(size-1)*2:0] wiresMultiplied;
has something wrong with it but IDK what's wrony with my code.
it tells me that writing
k = k + 2;
is wrong inside the generate loop, but I don't know why
It is a syntax error to make that assignment where you do in the code. It is an error for the same reason as this extreme simplification of your code is an error:
module dut;
integer k = 0;
k = k + 2;
endmodule
The integer declaration line is legal, but the other assignment line is illegal because it looks like you are trying to make a procedural assignment outside of a procedural block (like an always block).
When debugging problems with generate loops, it's always helps to "unroll" the loop and start writing out the code the long way. These loops are advanced syntax constructs and are tricky to use. Especially nested loops. Especially for students who are just starting to learn Verilog.

Why I'm keep getting error in the output signal?

I write a simple Verilog code for calculating inner product between 2 vectors. I don't understand why, but I get an error in the module's output - red signal. There is probably some problem with the result variable.
Does anyone know what I'm missing?
The code -
`resetall
`timescale 1ns/10ps
`include "../hdl/params.v"
module ZCalculationParllel(features_vec, weights_vec, bias, predict);
// Feature vector in size of |NUMBER_OF_PIXELS| * |PIXEL_PRECISION|
input [(`NUMBER_OF_PIXELS * `PIXEL_PRECISION) - 1 : 0] features_vec;
// Weights vector in size of |NUMBER_OF_PIXELS| * |WEIGHT_BIAS_PRECISION|
input [(`NUMBER_OF_PIXELS * `WEIGHT_BIAS_PRECISION) - 1 : 0] weights_vec;
// Bias vector in size |WEIGHT_BIAS_PRECISION|
input [`WEIGHT_BIAS_PRECISION - 1 : 0] bias;
// The output value for prediction
//output predict; in case we want return one bit represent prediction
output [(2 * `PIXEL_PRECISION + $bits(`NUMBER_OF_PIXELS)) - 1 : 0] predict;
// Accomulator array for saving the multiplication result before the adders
wire [`PIXEL_PRECISION_PLUS_WEIGHT_BIAS_PRECISION - 1 : 0] multiplications [0 : `NUMBER_OF_PIXELS - 1];
wire [(2 * `PIXEL_PRECISION + $bits(`NUMBER_OF_PIXELS)) - 1 : 0] result;
genvar k;
generate
for (k = 0; k < `NUMBER_OF_PIXELS; k = k + 1)
begin: elementMul
assign multiplications[k] = features_vec[(k + 1) * `PIXEL_PRECISION - 1 -: `PIXEL_PRECISION] * weights_vec[(k + 1) * `WEIGHT_BIAS_PRECISION - 1 -: `WEIGHT_BIAS_PRECISION];
end
endgenerate
assign result = 2;
genvar i;
generate
for (i = 0; i < `NUMBER_OF_PIXELS; i = i + 1)
begin: elementAdd
assign result = result + multiplications[i];
end
endgenerate
assign predict = result;
endmodule
The test -
`resetall
`timescale 1ns/10ps
`include "../hdl/ZCalculationParllel.v"
`include "../hdl/params.v"
module ZCalculationParllel_tb ;
reg [(`NUMBER_OF_PIXELS * `PIXEL_PRECISION) - 1 : 0] features;
reg [(`NUMBER_OF_PIXELS * `WEIGHT_BIAS_PRECISION) - 1 : 0] weights;
reg [`WEIGHT_BIAS_PRECISION - 1 : 0] b;
wire [(2 * `PIXEL_PRECISION + $bits(`NUMBER_OF_PIXELS)) - 1 : 0] ans;
ZCalculationParllel z (
.features_vec(features),
.weights_vec(weights),
.bias(b),
.predict(ans)
);
initial
begin
b = 8'b00000010;
features[7:0] = 8'b00000010;
features[15:8] = 8'b00000001;
features[24:16] = 8'b00000010;
weights[7:0] = 8'b00000010;
weights[15:8] = 8'b00000001;
weights[24:16] = 8'b00000010;
end
endmodule
assign are applied concurrency, not sequentially. Xs will result if any of the assignments are conflicting.
Replace your result related code with something like the following:
reg [(2 * `PIXEL_PRECISION + $bits(`NUMBER_OF_PIXELS)) - 1 : 0] result;
integer i;
always #* begin
result = 2;
for (i = 0; i < `NUMBER_OF_PIXELS; i = i + 1) begin
result = result + multiplications[i];
end
end

Most significant bit operand in part-select of vector wire is illegal

I want to make a parameterized FIR filter in verilog on xilinix. This is my code:
module FIRFilter(xInput, clock, reset, filterCoeff, yOutput);
parameter inputBits = 8, lengthOfFilter = 4, coeffBitLength = 8, lengthOfCoeff = lengthOfFilter + 1, outputBitWdth = 2 * inputBits;
input [(coeffBitLength * lengthOfCoeff) - 1 : 0] filterCoeff;
input clock, reset;
input [inputBits - 1 : 0] xInput;
reg [outputBitWdth - 1 : 0] addWires [lengthOfFilter - 1 : 0];
output reg [outputBitWdth - 1 : 0] yOutput;
reg [inputBits - 1 : 0] registers [lengthOfFilter - 1 : 0];
integer i, j;
always # (posedge clock, posedge reset)
begin
if(reset)
begin
for(i = 0; i < lengthOfFilter; i = i + 1)
begin
registers[i] <= 0;
end
end
else
begin
registers[0] <= xInput;
for(i = 1; i < lengthOfFilter; i = i + 1)
begin
registers[i] <= registers[i - 1];
end
end
end
always # (posedge clock)
begin
addWires[0] = filterCoeff[(lengthOfFilter * coeffBitLength) - 1 : (lengthOfFilter - 1) * coeffBitLength] * xInput;
for(j = 1; j < lengthOfFilter; j = j + 1)
begin
addWires[j] = (filterCoeff[((j + 1) * coeffBitLength) - 1 : j * coeffBitLength] * registers[j - 1]) + addWires[j - 1];
end
yOutput = (filterCoeff[coeffBitLength - 1 : 0] * registers[lengthOfFilter - 1]) + addWires[lengthOfFilter - 1];
end
endmodule
But I keep getting this error
ERROR:HDLCompilers:109 - "FIRFilter.v" line 33 Most significant bit operand in part-select of vector wire 'filterCoeff' is illegal
ERROR:HDLCompilers:110 - "FIRFilter.v" line 33 Least significant bit operand in part-select of vector wire 'filterCoeff' is illegal
ERROR:HDLCompilers:45 - "FIRFilter.v" line 33 Illegal right hand side of blocking assignment
I searched online for the solution but haven't got any satisfactory answer.
Can someone help me with the this?
Verilog does not allow part selects signal[msb:lsb] where msb and lsb are not constants. You can use another construct called an indexed part select where you specify a constant width, but a variable offset signal[offset+:width]
addWires[0] = filterCoeff[(lengthOfFilter * coeffBitLength) +:coeffBitLength] * xInput;

Verilog error : A reference to a wire or reg is not allowed in a constant expression

I'm new to Verilog and I would really appreciate it if someone could help me out with this error:
output reg [0:image_width][image_height:0] result
....
integer i, j, imageX, imageY, x, y, kernelX, kernelY;
....
#(negedge ACLK)
for(x = 0; x < image_width; x++) begin
for(y = 0; y < image_height; y++)
begin
//multiply every value of the filter with corresponding image pixel
for(kernelX = 0; kernelX < kernel_width; kernelX++) begin
for(kernelY = 0; kernelY < kernel_height; kernelY++)
begin
imageX = (x - kernel_width / 2 + kernelX + image_width) % image_width;
imageY = (y - kernel_height / 2 + kernelY + image_height) % image_height;
// ignore input samples which are out of bound
if( imageY >= 0 && imageY < image_height && imageX >= 0 && imageX < image_width )
//ERROR HERE!!!
result[x][y] += image[imageX][imageY] * kernel[kernelX][kernelY];
end
end
end
end
end
The error I get is:
error: A reference to a wire or reg ('x') is not allowed in a constant expression.
error: Array index expressions must be constant here.
error: A reference to a wire or reg ('imageX') is not allowed in a constant expression.
error: Array index expressions must be constant here.
error: A reference to a wire or reg ('kernelX') is not allowed in a constant expression.
error: Array index expressions must be constant here.
Could somebody tell me what I'm doing wrong? Thank you!
This line is the problem:
result[x][y] += image[imageX][imageY] * kernel[kernelX][kernelY];
Indexing into arrays is only allowed for constant expressions. You are not allowed to use variables in vector indexes. Remember that you're working with an HDL: you're dictating physical connections in hardware. Having a variable in the index implies the ability to dynamically rewire the circuit. This SO question has some rough workarounds that may work for you. However, you should really try to refactor your algorithm to avoid the need to use the variable indexing in the first place.
By the way, you should be using non-blocking assignments instead of the blocking assignments you currently have. Your code is in a clocked block, so blocking combinational logic should be avoided:
imageX <= (x - kernel_width / 2 + kernelX + image_width) % image_width;
imageY <= (y - kernel_height / 2 + kernelY + image_height) % image_height;
// ignore input samples which are out of bound
if( imageY >= 0 && imageY < image_height && imageX >= 0 && imageX < image_width )
result[x][y] <= result[x][y] + image[imageX][imageY] * kernel[kernelX][kernelY];
#(negedge ACLK);
^
I'm pretty sure that semicolon doesn't belong there. As written, the for loops are all outside the always block.
Additionally, your image array currently only has one bit per pixel. Is this intentional? Whether it is or not, I would recommend that you reconsider this architecture; filtering an image of any significant size in a single clock cycle is not going to synthesize very well.

Verilog, generic adder tree

So, I'm trying to write an adder tree in verilog. The generic part of it is that it has a configurable number of elements to add and a configurable word size. However, I'm encountering problem after problem and I'm starting to question that this is the right way to solve my problem. (I will be using it in a larger project.) It is definately possible to just hard code the adder tree, alhough that will take alot of text.
So, I though I'd check with you stack overflowers on what you think about it. Is this "the way to do it"? I'm open for suggestions on different approaches too.
I can also mention that I'm quite new to verilog.
In case anyone is interested, here's my current non-working code: (I'm not expecting you to solve the problems; I'm just showing it for convenience.)
module adderTree(
input clk,
input [`WORDSIZE * `BANKSIZE - 1 : 0] terms_flat,
output [`WORDSIZE - 1 : 0] sum
);
genvar i, j;
reg [`WORDSIZE - 1 : 0] pipeline [2 * `BANKSIZE - 1 : 0]; // Pipeline array
reg clkPl = 0; // Pipeline clock
assign sum = pipeline[0];
// Pack flat terms
generate
for (i = `BANKSIZE; i < 2 * `BANKSIZE; i = i + 1) begin
always # (posedge clk) begin
pipeline[i] <= terms_flat[i * `WORDSIZE +: `WORDSIZE];
clkPl = 1;
end
end
endgenerate
// Add terms logarithmically
generate
for (i = 0; i < $clog2(`BANKSIZE); i = i + 1) begin
for (j = 0; j < 2 ** i; j = j + 1) begin
always # (posedge clkPl) begin
pipeline[i * (2 ** i) + j] <= pipeline[i * 2 * (2 ** i) + 2 * j] + pipeline[i * 2 * (2 ** i) + 2 * j + 1];
end
end
end
endgenerate
endmodule
Here are a few comments you might find useful:
CLOCKING
It is generally good to have as few clocks as possible in your design (preferably just one).
In this particular case it appears you are trying generating a new clock clkPl, but this does not work because it will never return to 0. (The "reg clkPl=0;" will reset it to 0 at time 0, then it is set permanently to 1 in "clkPl = 1;".)
You can fix this by simply replacing
always # (posedge clkPl)
with
always # (posedge clk)
ASSIGNMENTS
It is good form to only use blocking assignments in combinatorial blocks, and non-blocking in clocked blocks. You are mixing both blocking and non-blocking assignments in your "Pack flat terms" section.
As you don't need clkPl you can simply delete the line with the blocking assignment ("clkPl = 1;")
TREE STRUCTURE
Your double for loop:
for (i = 0; i < $clog2(`BANKSIZE); i = i + 1) begin
for (j = 0; j < 2 ** i; j = j + 1) begin
always # (posedge clkPl) begin
pipeline[i * (2 ** i) + j] <= pipeline[i * 2 * (2 ** i) + 2 * j] + pipeline[i * 2 * (2 ** i) + 2 * j + 1];
end
end
end
looks like it will access incorrect elements.
e.g. for BANKSIZE = 28, **i will count up to 7, at which point "pipeline[i * (2 ** i) + j]"="pipeline[7*2**7+j]"="pipeline[896+j] which will be out of bounds for the array. (The array has 2*BANKSIZE=512 elements in it.)
I think you actually want this structure:
assign sum = pipeline[1];
for (i = 1; i < `BANKSIZE; i = i + 1) begin
always # (posedge clk) begin
pipeline[i] <= pipeline[i*2] + pipeline[i*2 + 1];
end
end
LOWER LATENCY
Note that most verilog tools are very good at synthesising adds of multiple elements so you may want to consider combining more terms at each level of the hierarchy.
(Adding more terms costs less than someone might expect because the tools can use optimisations such as carry save adders to reduce the gate delay.)

Resources