System Verilog using mask - verilog

I can't get the meaning of this code.
I know VHDL and need system verilog. I do not know the meaning of bits [num] = '{4, 4}) or (output logic [width-1:0] mask [num]);
please explain me
module works
#(parameter int num = 4,
parameter int width = 8,
parameter int bits [num] = '{4, 4})
(output logic [width-1:0] mask [num]);

A module is like a VHDL entity, so we have a block called works:
module works
A parameter is like a VHDL generic. Instead of saying generic, in SystemVerilog we just say #. So, we have a block with three parameters (generics), an int (32-bit signed integer like a VHDL integer) with a default value of 4:
#(parameter int num = 4,
an int with a default value of 8:
parameter int width = 8,
and an array of ints of size equal to the value of the parameter num, which will be numbered 0 to num-1:
parameter int bits [num] = '{4, 4})
'{4,4} is an assignment pattern and is the (rough) equivalent of a VHDL aggregate. So, this code is trying to initialise two of the values of this array to to integer 4. The trouble is this code is probably illegal. The array bits can be of any size (depending on the value of the parameter num) and this array is what is called an unpacked array. In SystemVerilog (and in Verilog), both the size and shape of assignments to packed arrays must match (just like in VHDL). This size of either side of this assignment will not match unless the value of num is 2. If you want to initialise all the elements of an unpacked array to the same thing, you can use a key (rather like VHDL others):
parameter int bits [num] = '{default:4})
https://www.edaplayground.com/x/5w8y
This is a port:
(output logic [width-1:0] mask [num]);
whose size is defined by the two parameters, width and num. The output is an array of num (a so-called unpacked dimension) of words of width width (a so-called packed dimension). logic is a type. Variables of type logic can take one of four values: 0, 1, X or Z.

output logic [width-1:0] mask [num]
[width-1:0] mask is a vector of width bits. With a width of 8 this would be an 8-bit vecor: [7:0] mask.
The vector is followed by [num] means it is an array of 'num' vectors. The total is a two-dimensional array of width x num bits.
That syntax is verry common and you will see it often.
I had to look for the '{4,4} pattern (I could not find it in my little System Verilog booklet) and as Matthew says it is an assignment of values to an array. So, my initial interpretation was wrong.
The problem with the existing code is that my Verilog simulator throws an error message when using the default values. num is 4 and '{4,4} has only two elements. This upon start-up I get an error:
ERROR: [VRFC 10-666] expression has 2 elements; expected 4 [...
If I set num to 2 #(.num(2)) the simulator is happy.

Related

Verilog parameters with parametric width

It isn't hard to agree that parametrized module design is a good practice and data width is a good starting point.
I have been defining constants 0 and 1 of required bus or operand widths for years. That to avoid compiler warnings and to explicitly communicate the intention. Typically using something like:
parameter WIDTH = 16;
// ...
parameter ZERO = {WIDTH{1'b0}}; // all zeroes
parameter UNO = {{WIDTH-1{1'b0}}, 1'b1}; // all zeroes except LSB
This is all fine until I want to define an arbitrary constant with given parametrized WIDTH.
I certainly can write a constant with fixed width - but that's not what I want:
parameter FULL = 16'd57;
However, analogous construct using the parametric WIDTH fails with syntax error:
parameter LEVEL = WIDTH'd57; // <== *ERROR*
What is the proper syntax - if there is one?
This was a problem in Verilog because the RHS of a parameter assignment was used as the self-determined width of the parameter. SystemVerilog addressed this by allowing you to specify a datatype as part of a parameter declaration
parameter WIDTH = 16;
// ...
parameter bit [WIDTH-1:0] ZERO = '0; // all zeroes
parameter bit [WIDTH-1:0] UNO = 1; // all zeroes except LSB
parameter bit [WIDTH-1:0] LEVEL = 57;
The datatype does not change when overriding.
Another way is using a sizing cast
parameter LEVEL = WIDTH'(56);
But if you do it this way and override the parameter, the datatype becomes the width of the overriding value's type.

How to do matrix multiplication in Verilog?

I am trying to multiply 1x3 * 3X64 matrix, here since each value in matrix is decimal number so for each value I have taken 4 bits that is 4x64 bits in total accessing 4bits of each row at a time.
I tried to generalize it.
The matrix is of form 1x3 [2,4,3] &
3*64(64 decimal value in each row)
row 1[111111111111111111111111111111(64)]
row 2[11111111(8)22222222(8).....88888888(8)]
row 3[1234567812345678..................12345678]
The code which I tried
always#(h1,h2,h3)
begin
z1 =((w0[3:0]*h1[3:0])+(w1[3:0]*h2[3:0])+(w2[3:0]*h3[3:0]));
z2=((w0[3:0]*h1[7:4])+(w1[3:0]*h2[7:4])+(w2[3:0]*h3[7:4]));
.
.
.
.
.
z64=((w0[3:0]*h1[255:252])+(w1[3:0]*h2[255:252])+(w2[3:0]*h3[255:252]));
end
endmodule
I need generalized form of this..
Error that I have got:
ERROR:HDLCompilers:110 - "mat.v" line 36 Least significant bit operand
in part-select of vector wire 'h1' is illegal
for(i=3;i<255;i=i+4)
begin
for(j=0;j<255;j=j+4)
begin
z[i:j]=((w0[3:0]*(h1[i:j]))+(w1[3:0]*h2[i:j])+(w2[0]*h3[i:j]));
end
A part select in Verilog must have constant bounds. h1[i:j] is illegal. h1[i +: 4] is legal and means the same as the illegal h1[i:(i+3)]. (And h1[i+3 -: 4] means the same as the illegal h1[(i+3):i]).
However, wouldn't your problem not be better solved by using two dimensional arrays? eg:
reg [3:0] h1 [0:63];

How to implement an n-bit adder whose input vectors are represented in octal?

I'm somewhat stumped on this problem:
"Write a verilog module for full addition of n-bit integers. Let the parameter, the number of bits, equal 3. Call this module from a test bench, and in the test bench specify the numbers to be added in the arrays. Assign octal values to the X and Y arrays. The carryin is 0."
And yes, this is homework.
I was able to write the module for the n-bit adder:
module addern(carryin, X, Y, S, carryout, overflow);
parameter n = 3;
input carryin;
input [n-1:0] X, Y;
output reg [n-1:0] S;
output reg carryout, overflow;
always #(X,Y, carryin)
begin
{carryout, S} = X + Y + carryin;
overflow = (X[n-1] & Y[n-1] & ~S[n-1]) | (~X[n-1] & ~Y[n-1] & S[n-1]);
end
endmodule
I understand this component of the problem. However, I'm not sure how to implement the octal number addition. Is there a way in verilog to indicate that the arrays are holding octal values, rather than binary?
Is there anything like a typecast in verilog? For instance, input (octal) [n-1:0] X, Y, and do something likewise in the test bench.
Any constructive input is appreciated.
I'm pretty sure I'm in the same class as you. I think what you need to do is create a hierarchical Verilog module and then assign your values there. That would be your testbench. for example if you want to make X you write input [n-1:0] X = 3'o013, or maybe it's X = 9'o013 if Oli is correct. you don't change n, but it's kind of like BCD where they are in groups and you have a certain amount of bits you can represent before it overflows.
To help solve the problem thik about the question:
Q) How are numbers stored in digital hardware?
A) Binary, in digital logic we can only represent 2 values 1 and 0, but with this we can represent Integer, fixed point or floating point numbers.
Therefore digital numbers are base 2 (two possible values), while being able to represent any number. Other bases such as Octal (base 8) hex (base 16) and decimal (base 10) exist but these are just way of representing numbers, similar to the way binary just represents a number.
A decimal 1, is represented by 1 n all the bases, and when stored as binary they are all the same. An example of some values in verilog and there binary equivalents.
Octal Decimal Hex Binary
3'O7 => 3'd7 => 3'h7 => 3'b111
6'O10 => 6'd8 => 6'h8 => 6'b001000
Octal, Decimal and Hex in verilog are just representations of a binary format, a way of viewing the data. Since the low level electronics has no way of representing any thing other than 0 and 1.
The interesting thing about Octal and Hex is that they have a power of 2 values so they use an exact number of bits so an 9'O123 is the same as treating each Octal place separately and concatenating them together, 9'O123 == {3'O1, 3'O2, 3'O3}. This is also true for hexadecimal values but not decimal (base 10) values, as 10 is not a power of 2 and does not fully occupy the number space.
This does allow 'Octal' ports to be created, which are just 3 bit binary ports:
module octal_concat (
input [2:0] octal_2,
input [2:0] octal_1,
input [2:0] octal_0,
output [8:0] concat
);
assign concat = {octal_2, octal_1, octal_0};
endmodule
octal_concat octal_concat_0 (
.octal_2(3'O1),
.octal_1(3'O2),
.octal_0(3'O3),
.concat() //Drives 9'O123 which is also 9'b001_010_011
);

Eliminating unused bits: creating synthesisable multidimensional arrays of with different dimensions

This is a follow-on question from How can I iteratively create buses of parameterized size to connect modules also iteratively created?. The answer is too complex to answer in a comment and the solution may be helpful for other SOs. This question is following the self-answer format. Addition answer are encouraged.
The following code works and uses a bi-directional array.
module Multiplier #(parameter M = 4, parameter N = 4)(
input [M-1:0] A, //Input A, size M
input [N-1:0] B, //Input B, size N
output [M+N-1:0] P ); //Output P (product), size M+N
wire [M+N-1:0] PP [N-1:0]; // Partial Product array
assign PP[0] = { {N{1'b0}} , { A & {M{B[0]}} } }; // Pad upper bits with 0s
assign P = PP[N-1]; // Product
genvar i;
generate
for (i=1; i < N; i=i+1)
begin: addPartialProduct
wire [M+i-1:0] gA,gB,gS; wire Cout;
assign gA = { A & {M{B[i]}} , {i{1'b0}} };
assign gB = PP[i-1][M+i-1:0];
assign PP[i] = { {(N-i){1'b0}}, Cout, gS}; // Pad upper bits with 0s
RippleCarryAdder#(M+i) adder( .A(gA), .B(gB), .S(gS), .Cin(1'b0), .* );
end
endgenerate
endmodule
Some of the bits are never used, such as PP[0][M+N-1:M+1]. A synthesizer will usually remove these bits during optimization and possibly give a warning. Some synthesizers are not advance enough to do this correctly. To resolve this, the designer must implement extra logic. In this example the parameter for all the RippleCarryAdder's would be set to M+N. The extra logic wastes area and potently degrades performance.
How can the unused bits be safely eliminated? Can multidimensional arrays with different dimensions be used? Will the end code be readable and debug-able?
Can multidimensional arrays with different dimensions be used?
Short answer, NO.
Verilog does not support unique sized multidimensional arrays. SystemVerilog does support dynamic arrays however these cannot be connected to module ports and cannot be synthesized.
Embedded code (such as Perl's EP3, Ruby's eRuby/ruby_it, Python's prepro, etc.) can generate custom denominational arrays and code iterations, but the parameters must be hard coded before compile. The final value of any parameter of a given instance is discoverer during compile time, well after the embedded script is ran. The parameter must be treated as a global constant, therefore Multiplier#(4,4) and Multiplier#(8,8) cannot exist in the same project unless to teach the script how to extract the full hierarchy and parameters of the project. (Good luck coding and maintaining that).
How can the unused bits be safely eliminated?
If the synthesizer is not advance enough to exclude unused bits on its own, then the bits can be optimized by flattening the multidimensional array into a one-dimensional array with intelligent part-select. The trick is finding the equation which can be achieved by following these steps:
Find the pattern of the lsb index for each part part select:
Assume M is 4, the lsb for each part-select are 0, 5, 11, 18, 26, 35, .... Plug this pattern into WolframAlpha to find the equation a(n) = (n-1)*(n+8)/2.
Repeat with M equal to 3 for the pattern 0, 4, 9, 15, ... to get equation a(n)=(n-1)*(n+6)/2
Repeat again with M equal to 5 for the pattern 0, 6, 13, 21, 30, ... to get equation a(n)=(n-1)*(n+10)/2.
Since the relation of M and N is linear (i.e. multiple; no exponential, logarithmic, etc.), only two equations are needed to create a variable parameter M equation. For non-linear equations more data-point equations are recommended. In this case note that for M=3,4,5 the pattern (n+6),(n+8),(n+10), therefore the generic equation can be derived to: lsb(n)=(n-1)*(n+2*M)/2
Fine the pattern of the msb index for each part select:
Use the same process of as finding the lsb (ends up being msb(n)=(n**2+(M*2+1)*n-2)/2). Or define the msb in terms of lsb: msb(n)=lsb(n+1)-1
IEEE std 1364-2001 (Verilog 2001) introduced macros with arguments and indexed part-select; see § 19.3.1 '`define' and § 4.2.1 'Vector bit-select and part-select addressing' respectively. Or see IEEE std 1800-2012 § 22.5.1 '`define' and § 11.5.1 'Vector bit-select and part-select addressing' respectively. This answer assumes that these features are supported by the SO's simulator and synthesizer since the generate keyword was also introduced in IEEE std 1364-2001, see § 12.1.3 'Generated instantiation' (and IEEE std 1800-2012 § 27. 'Generate constructs'). For tools that are not fully support IEEE std 1364-2001, see `ifdef examples provided here.
Since the functions to calculate the part-select ranges are frequently used, use `define macros with arguments. This will help prevent copy/paste bugs. The extra sets of () in the macro definitions are to insure proper order of operations. It is also a good idea to `undef the macros at the end of the module definition, preventing the global space from getting polluted. With the flattened array it may become challenging to debug. By defining pass-through connections within the generate block's for-loop the signal can become readable and can be probed in waveform.
module Multiplier #(parameter M = 4, parameter N = 4)(
input [M-1:0] A, //Input A, size M
input [N-1:0] B, //Input B, size N
output [M+N-1:0] P ); //Output P (product), size M+N
// global space macros
`define calc_pp_lsb(n) (((n)-1)*((n)+2*M)/2)
`define calc_pp_msb(n) (`calc_pp_lsb(n+1)-1)
`define calc_pp_range(n) `calc_pp_lsb(n) +: (M+n)
wire [`calc_pp_msb(N):0] PP; // Partial Product
assign PP[`calc_pp_range(1)] = { 1'b0 , { A & {M{B[0]}} } };
assign P = PP[`calc_pp_range(N)]; // Product
genvar i;
generate
for (i=1; i < N; i=i+1)
begin: addPartialProduct
wire [M+i-1:0] gA,gB,gS; wire Cout;
assign gA = PP[`calc_pp_range(i)];
assign gB = { A & {M{B[i]}} , {i{1'b0}} };
assign PP[`calc_pp_range(i+1)] = {Cout,gS};
RippleCarryAdder#(M+i) adder( .A(gA), .B(gB), .S(gS), .Cin (1'b0), .* );
end
endgenerate
// Cleanup global space
`undef calc_pp_range
`undef calc_pp_msb
`undef calc_pp_lsb
endmodule
Working example with side-by-side and test bench: http://www.edaplayground.com/s/6/591
Will the end code be readable and debug-able?
Yes, for anyone who has already learned how to properly use the generate construct. The generate block's for-loop defines local wires which are confined to scope of the loop index. gA form loop-0 and gA from loop-1 are unique signals and cannot interact with each other. The local signals can be probed in waveform which is great for debugging.

How to define and initialize a vector containing only ones in Verilog?

If I want to declare a 128 bit vector of all ones, which one of these methods is always correct?
wire [127:0] mywire;
assign mywire = 128'b1;
assign mywire = {128{1'b1}};
assign mywire = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
As a quick simulation would prove, assign mywire = 128'b1; does not assign all bits of mywire to 1. Only bit 0 is assigned 1.
Both of the following always assign all 128 bits to 1:
assign mywire = {128{1'b1}};
assign mywire = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
One advantage of the 1st line is that it is more easily scalable to widths greater than and less than 128.
With SystemVerilog, the following syntax also always assigns all 128 bits to 1:
assign mywire = '1;
I would use the following statement instead:
assign mywire = ~0;
in a simple expression like this, the width on the left-hand side of the assignment sets the width for the expression on the right hand side. So 0, which is a 32 bit constant, is first extended to the full 128 bit of mywire, then all the bits are flipped and the resulting all-ones vector is assigned.
I'd prefer this version because it does not require you to specify the width of mywire anywhere in the assignment.

Resources