I've written a code for matrx multiplication in Verilog.
module multiply3x3(i1,i2,i3,i4,i5,i6,i7,i8,i9,j1,j2,j3,j4,j5,j6,j7,j8,j9,prod);
output reg [31:0]prod;
wire [7:0]resultant[3:0][3:0];
wire [7:0]a[3:0][3:0];
wire [7:0]b[3:0][3:0];
genvar i,j,k;
generate
for (i = 0; i <= 2; i=i+1) begin:i_
for (j = 0; j <= 2; j=j+1) begin:j_
assign resultant[i][j] = 8'd0;
for (k = 0; k <= 2; k=k+1) begin:k_
assign resultant[i][j] = resultant[i][j] + a[i][k] * b[k][j];
end
end
end
endgenerate
endmodule
initial begin
#100 prod = {resultant[0][0],resultant[0][1],resultant[0][2],resultant[1][0],resultant[1][1],resultant[1][2],resultant[2][0],resultant[2][1],resultant[2][2]};
end
This is where the multiplication happens, but i cannot get the output for this.
What am I doing wrong?
consider a,b declared properly.
Accumulation (a = a + p) doesn't work with wires. The type wire is supposed to model a physical wire.
You'll have to declare the variable resultant as a reg. The reg type, in Verilog, can in some cases be treated like a variable in other programming languages.
Also, you can't use the assign statement on a wire or reg multiple times (like you've done in line 78 and 80 of https://pastebin.com/txrcwUBd). You should use always (and not generate) blocks to perform such things.
Corrected Verilog:
reg [7:0] resultant[3:0][3:0];
int i, j, k;
always #(*)
for(i=0; i<3; i=i+1)
for(j=0; j<3; j=j+1) begin
resultant[i][j] = 8'd0;
for(k=0; k<3; k=k+1)
resultant[i][j] = resultant[i][j] + (a[i][k]*b[k][j]);
end
Related
I made a design for a divider, but the result is wrong.
module div(x,y,quotient,remainder);
parameter M=4;
parameter N=4;
input [M-1:0] x;
input [N-1:0] y;
output [N-1:0] quotient;
output [M-1:0] remainder;
wire [M-1:0] rem_carry;
wire sum[M-1:0][N-1:0];
wire carry[M-1:0][N-1:0];
genvar i, j;
generate for(i=N-1; i>=0; i=i-1) begin:
unsigned_divider
if(i==N-1)
for(j=0; j<M; j=j+1) begin: first_row
if(j==0)
assign {carry[j][i],sum[j][i]}=y[i]+!x[j]+1;
assign {carry[j][i],sum[j][i]}=!x[j]+carry[j-1][i];
end
else
for(j=0; j<M;j=j+1) begin:rest_rows
if(j==0)
assign{carry[j][i],sum[j][i]}=y[i]+(x[j]^carry[M-1][i+1])+carry[M-1][i+1];
else
assign {carry[j][i],sum[j][i]}=sum[j-1][i+1]+(x[j]^carry[M-1][i+1])+carry[j-1][i];
end
end endgenerate
generate for(i=0; i<N; i=i+1)
begin:product_quotient
assign quotient[i]=carry[M-1][i];
end endgenerate
generate for(j=0;j<M;j=j+1)
begin:remainder_adjust
if(j==0)
assign{rem_carry[j],remainder[j]} = sum[j][0]+(sum[M-1][0]&x[j]);
else
assign{rem_carry[j],remainder[j]} =sum[j][0]+(sum[M-1][0]&x[j])+rem_carry[j-1];
end endgenerate
endmodule
and testbench simulation code
module tb_div();
parameter M = 4; // default divisor width
parameter N = 4; // default dividend width
reg [M-1:0] x;
reg [N-1:0] y;
wire[N-1:0] quotient;
wire[M-1:0] remainder;
wire[M-1:0] rem_carry;
div U0(.x(x), .y(y), .quotient(quotient), .remainder(remainder));
initial begin
x = 0; y = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
x=4'b0001;y=4'b0000;
#300 x=4'b0100;y=4'b0011;
#300 x=4'b1101;y=4'b1010;
#300 x=4'b1110;y=4'b1001;
#300 x=4'b1111;y=4'b1010;
end
endmodule
But, quotient, remainder, rem_carry is not value.
How to change the code? I think testbench is the problem.
The X values on quotient and remainder are due to contention on carry and sum in the design. Change:
assign {carry[j][i],sum[j][i]}=!x[j]+carry[j-1][i];
to:
else assign {carry[j][i],sum[j][i]}=!x[j]+carry[j-1][i];
The missing else caused carry to be simultaneously driven by 2 assign statements. The same goes for sum. My simulators gave me a "part-select index out of declared bounds" compile warning on that line. Proper indentation would have made it easier to catch this bug.
You get Z on the rem_carry signal in the testbench because the signal is undriven. You need to add an output port to the div module and make the proper connection in the testbench.
I am getting this error in VCS synthesizer. I have tried everything but it doesn't make sense to me.
it says VectorY[0], VectorY[1], VectorY[2], VectorY[3], or a directly connected net, is driven by more than one source, and at least one source is a constant net. (ELAB-368)
module control (clk, start, S1S2mux, newDist, CompStart, PEready, VectorX, VectorY, addressR, addressS1, addressS2,completed);
input clk;
input start;
output reg [15:0] S1S2mux;
output reg [15:0] newDist;
output CompStart;
output reg [15:0] PEready;
output reg [3:0] VectorX,VectorY;
output reg [7:0] AddressR;
output reg [9:0] AddressS1,AddressS2;
reg [12:0] count;
output reg completed;
integer i;
assign CompStart = start;
always #(posedge clk) begin
if(start==0) begin
count<= 12'b0;
completed<=0;
newDist<=0;
PEready<=0;
VectorX<=0;
VectorY<=0;
end
else if (completed==0)
count <= count+1'b1;
end
always #(count) begin
for (i = 0; i < 15; i = i+1)
begin
newDist [i] = (count [7:0] == i);
PEready [i] = (newDist [i] && !(count < 8'd256));
S1S2mux [i] = (count [3:0] > i);
end
addressR = count [7:0];
addressS1 = (count[11:8] + count[7:4] >> 4)*5'd32 + count [3:0];
addressS2 = (count[11:8] + count[7:4] >> 4)*4'd16 + count [3:0];
VectorX = count[3:0] - 4'd7;
VectorY = count[11:8] >> 4 - 4'd7;
completed = (count == 4'd16 * (8'd256 + 1));
end
endmodule
You can probably do like this...in systemverilog
create another logic variable
logic [3:0] VectorY_next;
and then in the sequential block, do ..
always_ff begin
if(start==0) begin
count<= 12'b0;
completed<=0;
newDist<=0;
PEready<=0;
VectorX<=0;
VectorY<=0;
end
else if (completed==0) begin
count <= count+1'b1;
VectorY <= VectorY_next;
end
end
And in the combinational block, you can write ...
always_comb begin
VectorY_next = VectorY;
for (i = 0; i < 15; i = i+1)
begin
.....
VectorY_next = count[11:8] >> 4 - 4'd7;
completed = (count == 4'd16 * (8'd256 + 1));
end
endmodule
And probably do the same for other ports too.To run using systemverilog, just use -sv option in the command line.
I am writing code for 8*4 RAM in Verilog. For each binary cell of memory, I am using an SR flip-flop. Initially, each cell is assigned 1'bx. The logic seems to be correct, but the output isn't. It is probably because statements are not getting executed concurrently. Can anyone suggest how can I get the task SRFlipFlop to get executed concurrently with other statements?
module memory(addr, read_data, rw, write_data, clk);
// read_data is the data read
// rw specifies read or write operation. 1 for read and 0 for write
// write data is the data to be written
// addr is the address to be written or read
task SRFlipFlop;
input d,r,s,clk; // d is the value initially stored
output q;
begin
case({s,r})
{1'b0,1'b0}: q<=d;
{1'b0,1'b1}: q<=1'b0;
{1'b1,1'b0}: q<=1'b1;
{1'b1,1'b1}: q<=1'bx;
endcase
end
endtask
task decoder; // a 3 to 8 line decoder
input [2:0] A;
input E;
output [7:0] D;
if (!E)
D <= 16'b0000000000000000;
else
begin
case (A)
3'b000 : D <= 8'b00000001;
3'b001 : D <= 8'b00000010;
3'b010 : D <= 8'b00000100;
3'b011 : D <= 8'b00001000;
3'b100 : D <= 8'b00010000;
3'b101 : D <= 8'b00100000;
3'b110 : D <= 8'b01000000;
3'b111 : D <= 8'b10000000;
endcase
end
endtask
output reg [3:0] read_data;
input [3:0] write_data;
input [2:0] addr;
input rw, clk;
reg [3:0] memory [7:0];
reg [3:0] r [7:0];
reg [3:0] s [7:0];
reg [3:0] intermediate;
reg [3:0] select [7:0];
reg [7:0] out;
reg [7:0] out1;
integer i,j,k,l;
initial
begin
for (i = 0; i <= 7; i=i+1)
begin
for (j = 0; j <= 3; j=j+1)
begin
memory[i][j] = 1'bx;
r[i][j] = 1'b0;
s[i][j] = 1'b0;
select[i][j] = 1'b0;
end
end
end
always #(posedge clk)
begin
decoder(addr, 1'b1, out);
for (i = 0; i <= 7; i=i+1)
begin
if (out[i] == 1'b1)
begin
for (j = 0; j <= 3; j=j+1)
begin
select[i][j] <= 1'b1;
s[i][j] <= write_data[j] & !rw & select[i][j];
r[i][j] <= !write_data[j] & !rw & select[i][j];
SRFlipFlop(memory[i][j],r[i][j],s[i][j],clk,intermediate);
memory[i][j] <= intermediate;
read_data[j] <= memory[i][j];
end
end
end
end
endmodule
Your code style is very software-oriented. Personally I like to know how my code will look as a circuit, so instead of using nested for loops and tasks I will use modules and generate-loops to create my circuits.
I have not been able to make your code work, but I suspect that the error is in the fact that s and r are not reset to zero on every iteration.
I have created a functioning design here:
http://www.edaplayground.com/x/Guc
Instead of using the initial block to initialize values I have added an asynchronous reset.
The SRFF-task has been converted to a module. A RAMblock module instantiates four SRFF-modules. 8 RAMblocks are instantiated in the memory module.
I have converted your packed(reg [] a []) arrays into unpacked arrays(reg [][] a) to be able to perform bitwise operations on several bits without for-loops.
If you have questions about the code, feel free to message me.
Edit: Perhaps the most important thing to note in this design is that I separate the sequential circuitry from the combinatorial. This way it is much easier to control what should be updated on the posedge of clk and what should just be a combinatorial reaction to the changes performed at the posedge.
I am trying to reduce a vector to a sum of all it elements. Is there an easy way to do this in verilog?
Similar to the systemverilog .sum method.
Thanks
My combinational solution for this problem:
//example array
parameter cells = 8;
reg [7:0]array[cells-1:0] = {1,2,3,4,5,1,1,1};
//###############################################
genvar i;
wire [7:0] summation_steps [cells-2 : 0];//container for all sumation steps
generate
assign summation_steps[0] = array[0] + array[1];//for less cost starts witch first sum (not array[0])
for(i=0; i<cells-2; i=i+1) begin
assign summation_steps[i+1] = summation_steps[i] + array[i+2];
end
endgenerate
wire [7:0] result;
assign result = summation_steps[cells-2];
Verilog doesn't have any built-in array methods like SV. Therefore, a for-loop can be used to perform the desired functionality. Example:
parameter N = 64;
integer i;
reg [7:0] array [0:N-1]
reg [N+6:0] sum; // enough bits to handle overflow
always #*
begin
sum = {(N+7){1'b0}}; // all zero
for(i = 0; i < N; i=i+1)
sum = sum + array[i];
end
In critiquing the other answers delivered here, there are some comments to make.
The first important thing is to provide space for the sum to be accumulated. statements such as the following, in RTL, won't do that:
sum = sum + array[i]
because each of the unique nets created on the Right Hand Side (RHS) of the expression are all being assigned back to the same signal called "sum", leading to ambiguity in which of the unique nets is actually the driver (called a multiple driver hazard). To compound the problem, this statement also creates a combinational loop issue because sum is used combinationally to drive itself - not good. What would be good would be if something different could be used as the load and as the driver on each successive iteration of the loop....
Back to the argument though, in the above situation, the signal will be driven to an unknown value by most simulator tools (because: which driver should it pick? so assume none of them are right, or all of them are right - unknown!!). That is if it manages to get through the compiler at all (which is unlikely, and it doesn't at least in Cadence IEV).
The right way to do it would be to set up the following. Say you were summing bytes:
parameter NUM_BYTES = 4;
reg [7:0] array_of_bytes [NUM_BYTES-1:0];
reg [8+$clog2(NUM_BYTES):0] sum [NUM_BYTES-1:1];
always #* begin
for (int i=1; i<NUM_BYTES; i+=1) begin
if (i == 1) begin
sum[i] = array_of_bytes[i] + array_of_bytes[i-1];
end
else begin
sum[i] = sum[i-1] + array_of_bytes[i];
end
end
end
// The accumulated value is indexed at sum[NUM_BYTES-1]
Here is a module that works for arbitrarily sized arrays and does not require extra storage:
module arrsum(input clk,
input rst,
input go,
output reg [7:0] cnt,
input wire [7:0] buf_,
input wire [7:0] n,
output reg [7:0] sum);
always #(posedge clk, posedge rst) begin
if (rst) begin
cnt <= 0;
sum <= 0;
end else begin
if (cnt == 0) begin
if (go == 1) begin
cnt <= n;
sum <= 0;
end
end else begin
cnt <= cnt - 1;
sum <= sum + buf_;
end
end
end
endmodule
module arrsum_tb();
localparam N = 6;
reg clk = 0, rst = 0, go = 0;
wire [7:0] cnt;
reg [7:0] buf_, n;
wire [7:0] sum;
reg [7:0] arr[9:0];
integer i;
arrsum dut(clk, rst, go, cnt, buf_, n, sum);
initial begin
$display("time clk rst sum cnt");
$monitor("%4g %b %b %d %d",
$time, clk, rst, sum, cnt);
arr[0] = 5;
arr[1] = 6;
arr[2] = 7;
arr[3] = 10;
arr[4] = 2;
arr[5] = 2;
#5 clk = !clk;
#5 rst = 1;
#5 rst = 0;
#5 clk = !clk;
go = 1;
n = N;
#5 clk = !clk;
#5 clk = !clk;
for (i = 0; i < N; i++) begin
buf_ = arr[i];
#5 clk = !clk;
#5 clk = !clk;
go = 0;
end
#5 clk = !clk;
$finish;
end
endmodule
I designed it for 8-bit numbers but it can easily be adapted for other kinds of numbers too.
I have written a piece of code that will return a quotient and a reminder, based on numbers that i provide and some other data that i used to shift the numbers in place.
The problem I have now is that i cannot keep a good track of my quotient if I test more values one after another.
I need a way to initialize my cat register, so that I no longer get residual values from previous computations.
Here is the code I was talking about:
module divide(
input [7:0] a, b,
input [3:0] counter, msb,
output reg [7:0] q,
output reg [7:0] r
);
always #(*) begin
for(i = 0; i < counter + 1 ; i = i+1) begin
sum = s_a + s_b; //previously calculated values
if(sum[8-msb] == 1) begin
assign s_a = s_a;
assign s_b = s_b >>> 1;
cat[counter - i] = 1'b0;
end
else begin
assign s_a = sum;
assign s_b = s_b >>> 1;
cat[counter - i] = 1'b1;
end
assign r = s_a;
assign q = cat;
end
end
endmodule
Note: I have declared all the registers that are in this code, but for some purpose I cannot declare them here.
You do not use assign inside always or initial blocks.
The assignments to cat are combinatorial therefore it is not a flip-flop, ie has no reset. The fact that it is a reg type has nothing to do with the hardware but a simulator optimisation.
I would have written it as (no functional alterations made):
module divide#(
parameter DATA_W = 8
)(
input [7:0] a, b,
input [3:0] counter, msb,
output reg [7:0] q,
output reg [7:0] r
);
//Definitions
reg [DATA_W-1:0] sum;
reg [DATA_W-1:0] s_a;
reg [DATA_W-1:0] s_b;
integer i;
always #* begin
for(i = 0; i < (counter + 1); i = i+1) begin
sum = s_a + s_b; //previously calculated values
if(sum[8-msb] == 1'b1) begin
s_a = s_a;
s_b = s_b >>> 1;
cat[counter - i] = 1'b0;
end
else begin
s_a = sum;
s_b = s_b >>> 1;
cat[counter - i] = 1'b1;
end
r = s_a;
q = cat;
end
end
endmodule
You have the following line:
sum = s_a + s_b; //previously calculated values
You have not included any flip-flops here, unless you have implied latches which are really to be avoided, there is no memory or state involved. i.e. there are no previously calculated values.
Instead of a combinatorial block you likely want to add a flip-flop and take multiple clock cycles to calculate the result.
instead of an always #* try:
always #(posedge clk or negedge rst_n) begin
if (~rst_n) begin
s_a <= 'b0; //Reset Value
end
else begin
s_a <= next value; //Normal logic
end
end