Setting multiple values in a vector to a single value - verilog

Basically, what is the best practice for programmatically specifying fan-out in System Verilog?
module fanout
#(
parameter N = 4
)
(
input i,
output j [N-1:0]
);
always # (*) begin
for (int k = 0; k < N; k++) begin
j[k] = i;
end
end
endmodule
This allows the width of the output vector to be a parameter -- are there any issues with this? Will this synthesize okay?

You can use the replication operator. This allows you to replicate a value a fixed number of times and concatenate them.
Example (Note you need to change the output to a packed data type output [N-1:0] j:
module fanout
#(
parameter N = 4
)
(
input i,
output [N-1:0] j
);
assign j = {N{i}};
endmodule
Runnable example on EDA playground: http://www.edaplayground.com/x/9vn

You can use a default in an assignment pattern
module fanout
#(
parameter N = 4
)
(
input i,
output j[N]
);
assign j = '{default:i};
endmodule

Related

Error with localparam inside "for" loop on Verilog

parameter N = 4, FOO = { N { 4'd1 } };
//And then in the generate loop
genvar i;
for( i = 0; i < N; i = i + 1 )
begin : gen_loop
localparam THIS_FOO = FOO[ i * 4 +: 4 ];
end
wire [1:0] rr = THIS_FOO[1:0];
wire [1:0] rt = THIS_FOO[3:2];
I get this error but did not understand why?:
Line 344: <THIS_FOO> is not declared.
Line 345: <THIS_FOO> is not declared.
Module <TCL_vec> ignored due to previous errors.
Please tell me where I was wrong?
Your localparam is declared inside begin:gen_loop..end scope. Moreover your generate for loop created multiple versions of the block, with names
gen_loop[0]
gen_loop[1]
...
So you have multiple versions of the THIS_FOO as well.The way to access them is to use a cross-reference notation.
wire [1:0] rr = gen_loop[0].THIS_FOO[1:0];
wire [1:0] rt = gen_loop[1].THIS_FOO[3:2];
...
and yes, you have to know which iteration of the loop to access.
So, in your case it complained because you do not have THIS_FOO declared in the scope you wanted to access it.

Bit slicing in verilog

How can I write wdata[((8*j)+7) : (8*i)] = $random; in verilog programming language? , where i and j are reg type variable. Modelsim gives error for constant range variable. How could I write it in proper manner.
You should think from Hardware prospective for the solution.
Here is one solution. Hope that it will help you.
module temp(clk);
input clk;
reg i, j;
reg [23:0] register, select;
wire [23:0] temp;
initial
begin
i = 'd1;
j = 'd1;
end
generate
for(genvar i = 0; i<24; i++)
begin
assign temp[i] = select[i] ? $random : register[i];
end
endgenerate
always # (posedge clk)
begin
register <= temp;
end
always # *
begin
select = (32'hffff_ffff << ((j<<3)+8)) ^ (32'hffff_ffff << (i<<3));
end
endmodule
Use the array slicing construction. You can find more detailed explanation at Array slicing Q&A
bit [7:0] PA, PB;
int loc;
initial begin
loc = 3;
PA = PB; // Read/Write
PA[7:4] = 'hA; // Read/Write of a slice
PA[loc -:4] = PA[loc+1 +:4]; // Read/Write of a variable slice equivalent to PA[3:0] = PA[7:4];
end
Verilog 2001 Syntax
[M -: N] // negative offset from bit index M, N bit result
[M +: N] // positive offset from bit index M, N bit result

Concatenation of RAM bits in Verilog

First of all, I had a lot of difficulty phrasing the title of this question. So if you understand the problem I'm facing, and there is a better way to word it and the question has been answered before, I apologise, and please do point out to me how I can resolve this. Anyways, here's the relevant code snippet that I've truncated for clarity:
parameter RAM_DEPTH = 256;
reg ram [0:RAM_DEPTH-1]; //256 deep memory, 1-bit size per location
parameter NUM_INST = 64;
parameter N = 4;
genvar x;
generate for (x = 0; x < NUM_INST; x = x + 1) begin: xs
//instantiate a module here
//connect N bits to input port
//which N bits depends module number x
mod inst (
.in(ram[x*N : x*N + N - 1]) //the error is here
);
end endgenerate
The error is:
error: Array cannot be indexed by a range.
I understand that this is because ram is declared as reg ram [0:RAM_DEPTH-1] instead of reg [0:RAM_DEPTH-1] ram. But is there a way to automate concatenation of RAM bits based on the N parameter, i.e. instead of having to write .in({ram[x*N],ram[x*N+1],ram[x*N+2],ram[x*N+3]}), there's an automated range selection logic that concatenates the bits based on N. You can imagine that if, say, N = 256, I would have to write a very long concatenation operator, and also makes my module less parametric.
In this case, should I just be using reg [0:RAM_DEPTH-1] ram declaration, and re-write my module to support bit updates on a single register array instead?
Thanks.
The easiest solution I found was to do as you suggested and turn reg ram [0:RAM_DEPTH-1] into reg [0:RAM_DEPTH-1] ram. An alternative would be the following:
parameter RAM_DEPTH = 256;
parameter NUM_INST = 64;
parameter N = 4;
reg [RAM_DEPTH-1:0] ram; //256 deep memory, 1-bit size per location
reg [N-1:0] ramwires [NUM_INST-1:0];
genvar x;
integer y, z;
generate for (x = 0; x < NUM_INST; x = x + 1) begin: xs
mod inst (
.in(ramwires[x])
);
end endgenerate
always#(*)
for (y = 0; y<NUM_INST; y = y + 1) begin
for (z=0; z<N; z = z + 1) begin
ramwires[y][z] = ram[y*N+z];
end
end
This converts the 1D array into a 2D array, which is easily passed into the module, while still being parameterizable.

Calculating a parameter in a loop generate block

I have an array of parameters WIDTHS, and I need to calculate another parameter RIGHT based on some values in WIDTHS in a generate block. Is this possible? If not, is there an alternative way?
Here is an example of what I am trying to do. Suppose we have a predefined register module REG which has inputs d, q, we (write enable), CLK and _RESET. I would like to create a new module called GroupReg, which instantiates N instances of REG. Each instance has a different width (hence the WIDTH parameter array). The d, q, and we of each group are aggregated in arrays with the same name in GroupReg and need to be specified for each instance. Specifying we is easy (we[i]) since it is only one bit. However, specifying d and q with the correct LEFT and RIGHT values is where I have problem with since each group has a different width.
Looks like the only way to assign a value to a parameter is upon its definition, which prevents assigning a value to it in a generate loop.
module GroupReg(d, q, we, CLK, _RESET);
parameter N = 4; //Number of groups
//INDICES has to have N+1 members. Last member should be 0
parameter integer WIDTHS [N:0] = {40, 30, 20, 10, 0};
parameter integer DW_TOTAL = 128;
input logic [DW_TOTAL-1:0] d; // Data Input
input logic [N-1:0] we; // write enable
input logic CLK; // Clock Input
input logic _RESET; // Reset input (active low)
output logic [DW_TOTAL-1:0] q; // Q output
genvar i, j;
for (i=N-1 ; i>=0 ; i--) begin:REGISTERS
localparam WIDTH = WIDTHS[i];
localparam LEFT = RIGHT + WIDTHS[i];;
localparam RIGHT = 0;
for (j = 0 ; j<i ; j++) // <<----- Does not work
RIGHT = RIGHT + WIDTH[j];
REG #(
.DW (WIDTH),
)
reg_i
(
.d(d[LEFT:RIGHT]),
.q(q[LEFT:RIGHT]),
.we(we[i]),
.CLK(CLK),
._RESET(_RESET)
);
end : REGISTERS
endmodule
I tried using the sum() array reduction method on WIDTHS and it worked in Aldec Riviera PRO:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
parameter integer DW_TOTAL = WIDTHS.sum();
initial begin
$display("DW_TOTAL", DW_TOTAL);
end
endmodule
If you're lucky it's going to work in your simulator too.
I anyway don't really get what you're trying to do making N a parameter, seeing as how you're anyway hardcoding a fixed number of values for the widths.
This works in Modelsim:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
genvar i;
for (i=N-1 ; i>=0 ; i--) begin
localparam integer FOO[i:0] = WIDTHS[i:0];
//localparam RIGHT = FOO.sum();
initial begin
foreach (FOO[i])
$display("FOO[%0d] = %h", i, FOO[i]);
end
end
endmodule
The FOO parameter would only store the relevant entries from WIDTH for a specific loop iteration. If sum() would work, you'd be home free. The slicing syntax doesn't work in Riviera, however.
This is a typical example of vendors interpreting the standard differently, basically because it's not specific enough. Still, if you use a simulator from a different EDA company, try combining the two answers; maybe you're lucky and it works.

How to design a 64 x 64 bit array multiplier in Verilog?

I know how to design a 4x4 array multiplier , but if I follow the same logic , the coding becomes tedious.
4 x 4 - 16 partial products
64 x 64 - 4096 partial products.
Along with 8 full adders and 4 half adders, How many full adders and half adders do I need for 64 x 64 bit. How do I reduce the number of Partial products? Is there any simple way to solve this ?
Whenever tediously coding a repetitive pattern you should use a generate statement instead:
module array_multiplier(a, b, y);
parameter width = 8;
input [width-1:0] a, b;
output [width-1:0] y;
wire [width*width-1:0] partials;
genvar i;
assign partials[width-1 : 0] = a[0] ? b : 0;
generate for (i = 1; i < width; i = i+1) begin:gen
assign partials[width*(i+1)-1 : width*i] = (a[i] ? b << i : 0) +
partials[width*i-1 : width*(i-1)];
end endgenerate
assign y = partials[width*width-1 : width*(width-1)];
endmodule
I've verified this module using the following test-bench:
http://svn.clifford.at/handicraft/2013/array_multiplier/array_multiplier_tb.v
EDIT:
As #Debian has asked for a pipelined version - here it is. This time using a for loop in an always-region for the array part.
module array_multiplier_pipeline(clk, a, b, y);
parameter width = 8;
input clk;
input [width-1:0] a, b;
output [width-1:0] y;
reg [width-1:0] a_pipeline [0:width-2];
reg [width-1:0] b_pipeline [0:width-2];
reg [width-1:0] partials [0:width-1];
integer i;
always #(posedge clk) begin
a_pipeline[0] <= a;
b_pipeline[0] <= b;
for (i = 1; i < width-1; i = i+1) begin
a_pipeline[i] <= a_pipeline[i-1];
b_pipeline[i] <= b_pipeline[i-1];
end
partials[0] <= a[0] ? b : 0;
for (i = 1; i < width; i = i+1)
partials[i] <= (a_pipeline[i-1][i] ? b_pipeline[i-1] << i : 0) +
partials[i-1];
end
assign y = partials[width-1];
endmodule
Note that with many synthesis tools it's also possible to just add (width) register stages after the non-pipelined adder and let the tools register balancing pass do the pipelining.
[how to] reduce the number of partial products?
A method somewhat common used to be modified Booth encoding:
At the cost of more complicated addend selection, it at least almost halves their number.
In its simplest form, considering groups of three adjacent bits (overlapping by one) from one of the operands, say, b, and selecting 0, a, 2a, -2a or -a as an addend.
The code below generates only half of expected the output.
module arr_multi(a, b, y);
parameter w = 8;
input [w-1:0] a, b; // w-width
output [(2*w)-1:0] y; // p-partials
wire [(2*w*w)-1:0] p; //assign width as input bits multiplied by
output bits
genvar i;
assign p[(2*w)-1 : 0] = a[0] ? b : 0; //first output size bits
generate
for (i = 1; i < w; i = i+1)
begin
assign p[(w*(4+(2*(i-1))))-1 : (w*2)*i] = (a[i]?b<<i :0) + p[(w*(4+(2*
(i-2))))-1 :(w*2)*(i-1)];
end
endgenerate
assign y=p[(2*w*w)-1:(2*w)*(w-1)]; //taking last output size bits
endmodule

Resources