I have a data of 1024 bit stored in A register.
reg [1023:0] A;
reg [7:0] B [0:127]
Now I want to convert it into 2 dimensional register B. How's it possible with minimum coding in Verilog?
In System Verilog a streaming operator could be used for this:
module top;
reg [1023:0] A;
reg [7:0] B [0:127];
always_comb begin
B = {>>{A}};
// this also works:
// {>>{B}} = A;
end
// testing
initial begin
for(int i = 0; i < 128; i++)
A[i*8 +: 8] = i;
#1 $finish;
end
always #* begin
$display("A: %3d %3d %3d", A[7:0], A[15:8], A[1023:1016]);
$display("B: %3d %3d %3d", B[127], B[126], B[0]);
end
endmodule
Just note, due to the B[0:127] declaration, index [0] is the most significant one and maps to A[1023:1016]. If you want an opposite mapping, declare B[127:0].
One way is to use a for loop:
module tb;
reg [1023:0] A;
reg [7:0] B [0:127];
always_comb begin
for (int i=0; i<128; i++) begin
B[i] = A[8*i +: 8];
end
end
endmodule
See also +:
Related
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
I have a problem with this
wire [7:0] table [0:999];
wire [8*1000-1:0] y;
assign y = {table[0], table[1], table[2], ...., table[999]}; // this line code is right, I don't want hard code
I want y is all 1000 values of table but I don't know how to assign all values in 1 line of code( or 2,3). code assign above is right but if there is 100000 values, do I have to type 100000 times?
You can use a for loop but your problem is the sensitivity list. Not all simulators allow two dimensional arrays as sensitivity argument.
wire [7:0] tbl [0:999];
reg [8*1000-1:0] y; // <<== Needs to be reg
integer i;
always #( tbl ) // <<== may give error/warning
for (i=0; i<1000; i=i+1)
y[i*8 +: 8] = tbl[i];
As long as you are using Verilog-2001 or higher, you can use:
wire [7:0] table [0:999];
reg [8*1000-1:0] y;
integer i;
always #* begin
for (i=0; i<1000; i=i+1) begin
y[ i*8 +: 8] = table[i];
end
end
See: Indexing vectors and arrays with +:
Verilog-95 solution is not as pretty and has more overhead:
wire [7:0] table [0:999];
reg [8*1000-1:0] y;
integer i;
always #( table ) begin
y = {8000{1'b0}};
for (i=999; i>=0; i=i-1) begin
y = {[8*999-1:0],table[i]};
end
end
If you can use SystemVerilog, it can be done in one step with bitsteaming
wire [7:0] table [1000];
wire [8*1000-1:0] y = {<<8{table}};
I'm newbie to a verilog.
I did a lot of research, and finally wrote this code, but it seems to not work.
Can anyone fix it for me?
module comparator();
reg[3:0] a, b;
wire[1:0] equal, lower, greater;
if (a<b) begin
equal = 0;
lower = 1;
greater = 0;
end
else if (a==b) begin
equal = 1;
lower = 0;
greater = 0;
end
else begin
equal = 0;
lower = 0;
greater = 1;
end;
initial begin
$monitor($time,
"a=%b, b=%b, greater=%b, equals=%b, lower=%b",
a, b, greater, equal, lower);
a=9; b=10;
#100 $display ("\n", $time, "\n");
end
endmodule
Behavioural procedures must be enclosed within an always block, like this:
Also, your module needs inputs and outputs. A more correct version would be like this:
module comparator (
input wire [3:0] a,
input wire [3:0] b,
output reg equal,
output reg lower,
output reg greater
);
always #* begin
if (a<b) begin
equal = 0;
lower = 1;
greater = 0;
end
else if (a==b) begin
equal = 1;
lower = 0;
greater = 0;
end
else begin
equal = 0;
lower = 0;
greater = 1;
end
end
endmodule
I suggest reading some tutorial about behavioral modelling with Verilog, because you missed a lot of points:
How to correctly define inputs and outputs in a module
What things can be wires and what things should be regs
The use of always #* to model combinational logic
And most important: how to write a test bench. Test benches are written as module with no inputs and outputs) that instantiates your UUT (unit under test), provides inputs, read outputs and check whether they are valid.
module testcomp;
reg [3:0] a, b;
wire eq, lw, gr;
comparator uut (
.a(a),
.b(b),
.equal(eq),
.lower(lw),
.greater(gr)
);
initial begin
a = 0;
repeat (16) begin
b = 0;
repeat (16) begin
#10;
$display ("TESTING %d and %d yields eq=%d lw=%d gr=%d", a, b, eq, lw, gr);
if (a==b && eq!=1'b1 && gr!=1'b0 && lw!=1'b0) begin
$display ("ERROR!");
$finish;
end
if (a>b && eq!=1'b0 && gr!=1'b1 && lw!=1'b0) begin
$display ("ERROR!");
$finish;
end
if (a<b && eq!=1'b1 && gr!=1'b0 && lw!=1'b1) begin
$display ("ERROR!");
$finish;
end
b = b + 1;
end
a = a + 1;
end
$display ("PASSED!");
$finish;
end
endmodule
You can play with this example at EDAPlayGround using this link:
http://www.edaplayground.com/x/CPq
Without always block:
module comparator (
input wire [3:0] a,
input wire [3:0] b,
output reg equal,
output reg lower,
output reg greater
);
assign equal = (a===b);
assign lower = (a<b)?1'b1:1'b0;
assign greater = (a>b)1'b1:1'b0;
end
Be careful, you need to consider 'X' and 'Z', use "===" instead of "=="
I am now doing reading input data from txt file and write the results into txt file.
However the results runs in the simulation works well but it fail to link back the the conv module which is o = a+b; the system able to read the values in x.txt and d.txt but cannot link it back to a and b. What is my mistake and how to correct it?
And from the same cases in i found out that the system cannot write out negative decimal value although it is change to "%d\n" in $fwrite. Any method to solve that? Should i use $dumpfile to get negative number as output??
Here is the content in d.txt
56
272
1
-62
75
Content in x.txt
562
2723
14
-620
751
Here is my module code:
module conv (input signed[15:0]a,b,
output signed[15:0] o);
assign o = a + b;
endmodule
My testbench code:
module conv_tb();
reg clk;
reg signed [15:0]a[4:0];
reg signed [15:0]b[4:0];
wire signed [15:0]o[4:0];
integer ai,bi,oo,i;
conv U1(.a(a),.b(b),.o(o));
initial begin
clk <= 1'b0;
forever
#1 clk = ~clk;
end
initial begin
ai = $fopen("x.txt","r");
bi = $fopen("d.txt","r");
oo = $fopen("o.txt","w");
#1;
for (i = 0; i<5; i=i+1)
a <= $fscanf(ai,"%d\n",x);
b <= $fscanf(bi,"%d\n",d);
#4;
$fwrite(oo,"%d\n",o);
end
$fclose(ai);
$fclose(bi);
$fclose(oo);
$finish;
end
endmodule
An example for writing signed number to a text file using fwrite :
module write_signed;
integer out_file;
initial begin
out_file = $fopen("out_file.txt","w");
$fwrite(out_file, "%d\n", 3);
$fwrite(out_file, "%d\n", 2);
$fwrite(out_file, "%d\n", 1);
$fwrite(out_file, "%d\n", 0);
$fwrite(out_file, "%d\n", -1);
$fwrite(out_file, "%d\n", -2);
$fclose(out_file);
end
endmodule
Which generates :
3
2
1
0
-1
-2
An alternative method to solve your issue is to use a hex value input as shown, convert all negative values to corresponding hex value in the text file explicitly is required
module conv ( input signed [15:0] a, b,
output signed [15:0] o);
assign o = a + b;
endmodule
module conv_tb();
reg signed [15:0] a,b,o;
conv u0(.a(a),.b(b),.o(o));
reg [15:0] Mem [0:4];
reg [15:0] Mem1 [0:4];
integer j,k,oo;
initial
begin
$readmemh("x.txt",Mem);
$readmemh("d.txt",Mem1);
oo = $fopen("o.txt","w");
end
initial begin
for (k=0; k<5; k=k+1) begin a= Mem[k]; end
for (j=0; j<5; j=j+1) begin b= Mem1[j]; $fwrite(oo,"%d\n",o); end
end
endmodule
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.