How to do matrix multiplication in Verilog? - 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];

Related

Signed and Unsigned Multiplication Problem in Verilog

I have been working on approximate multiplication recently and I want to write a Verilog code for dynamic segment multiplication (DSM) . It suggest that you find the first index in you number which has a value of 1 and then take other 3 indexes next to it to form a 4 bit number that represent an 8 bit number then you should multiply these 4 bit numbers instead of 8 bits then some shifts to have the final result it helps a lot on hardware actually.. but my problem is about multiplication of these segments because sometimes they should be considered signed and some time unsigned I have the last 3 lines of my code: (a and b are input 8 bit numbers) and m1 and m2 are segments I wrote m,m2 as reg signed [3:0] and a and b as input signed [7:0]
Here is my code:
assign out = ({a[7],b[7]}==2'b11)||({a[7],b[7]}==2'b00) ? ($unsigned(m1)*$unsigned(m2)) << (shift_m1+shift_m2) : 16'dz;
assign out = ({a[7],b[7]}==2'b01) ? ($signed({1'b0,m1})*$signed(m2)) << (shift_m1+shift_m2) : 16'dz;
assign out = ({a[7],b[7]}==2'b10) ? ($signed(m1)*$signed({1'b0,m2})) << (shift_m1+shift_m2) : 16'dz;
But in simulation Verilog always considers segments as unsigned and does unsigned multiplication even though I noted signed or unsigned mark...
Can anyone help? I read all of the questions about this problem in stackoverflow and other places but still cannot solve this issue...
The rules for non-self determined operands say that if one operand is unsigned, the result is unsigned. 16'dz is unsigned.
The conditional operator i ? j : k has the condition operand i self-determined, but the two selections j and k are in a context based on the assignment or expression it is a part of. The shift operator i << j has the shift amount operand j self-determined.
All of the context rules are explained in section 11.6.1 Rules for expression bit lengths in the IEEE 1800-2017 SystemVerilog LRM.
You can get your desired result by using the signed literal 16'sdz.
However the logic you wrote may not be synthesizable for certain technologies that do not allow using a z state inside your device. The correct and more readable way is using a case statement:
alway #(*) case({a[7],b[7]})
2'b00,
2'b11: out = $unsigned(m1)*$unsigned(m2) << shift_m1+shift_m2;
2'b01: out = $signed({1'b0,m1})*m2 << shift_m1+shift_m2;
2'b10: out = m1*$signed({1'b0,m2}) << shift_m1+shift_m2;
endcase

Unexpected result of Not operator in assignment

I have two 8-bit inputs A and B,
input [7:0] A,B;
and a 9-bit output F,
output reg [8:0] F;
A and B are combined and assigned to F like this:
F <= ~(A^B);
If A is equal to 8'hFF, and B is equal to 8'hF0, why does F become 9'h1F0 and not 9'h0F0?
Why is the output 9'h1F0 and not 9'h0F0?
You defined F as 9 bits wide. Thus the compiler will expand the right-hand-side arguments to 9 bits before doing any operations.
As both A and B are unsigned they become resp
A = 9'h0FF, B=9'h0F0. EXOR gives 9'h00F. Ones complement then gives 9'h1F0.
Beware that the width expansion does not happen if you put the expression between {}:
F2 = {~(A^B)};
F2 will be 9'h0F0;
Because sections 11.8.2 Steps for evaluating an expression and 11.8.3 Steps for evaluating an assignment of the IEEE 1800-2017 LRM effectively say that the operands get extended first to match the size of the result before any operation is performed.

System Verilog using mask

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.

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
);

Verilog reg assignment to part of another reg

I am using Verilog with modelSim and I get the following errors when I try to assign reg variables to different parts of another reg variable:
** Error: Range width must be greater than zero.
** Error: Range width must be constant expression.
here is the relevant code:
integer f; //zd, qd, R and Q are regs
always # * begin
f = 52 - zd;
R = qd[f +:0];
Q = qd[63 -:f+1];
end
I want R to include qd (from 0 to f) and Q to be (the rest) qd (from f+1 to 63). How to do it? Thanks.
What you are trying to do is not legal in verilog 2001.
As your warning says, Range width must be constant expression, i.e. you cannot have variable length part selects.
You can have fixed length part select that varies the starting point (i.e. select 8 bits starting from f), but the syntax for that is this:
vector_name[starting_bit_number +: part_select_width]
vector_name[starting_bit_number -: part_select_width]
In hardware the size of a bus must be a fixed size, you cannot change the number of wires in silicon based on the contents of a register :)

Resources