Concatenation of RAM bits in Verilog - 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.

Related

Initialize and increment a genvar variable inside nested for loop of system verilog

I'm trying to write a synthesizable code in .sv to meet my requirements, but got stuck at the very end without a solution;
I've an incoming wire which is 99 bit wide and 10 (MAX) deep
I need to feed this to a module and get its output which is 99 bit
the output needs to be assigned to an array (99 bit wide ) from 0 .. max
I can't paste the snippet, but this is what I've coded:
--
param MAX = 10;
param TOT_INST = 45 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0]
genvar x,y,z ;
generate
for (x = 0, z=0; x<=MAX-1; x=x+1, z=z+1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
some_module mod_inst ( .in1(inwire[x]), .in2(inwire[y]), .y(outwire[z]) );
end
end
endgenerate
--
The expectation is to get outwire[0] to be an output of inwire[0] and inwire[1], outwire[1] to be a function of inwire[0], inwire[1] etc. So, it becomes necessary to increment the index of outwire.
I used another genvar z for this purpose (to increment from 0 to 44). But, it looks like the SV doesn't support multiple genvar variables to be incremented? im getting compilation error at the for loop itself.
Is there any way to achieve what i need? I really appreciate you taking time to go through this question. Any insight would be really helpful.
Thanks
Jr.
I understand your intent. It seems you are trying to use comma expressions, but they wont work here.
Also, it seems that the genvar can only be assigned in the initialization and increment of the for loop, otherwise it would be easy to increment them on the innermost loop.
Since you must have unique drivers to the outwires, and the number of entries you declared (45) matches the number of instances you will create I assume you simply want them to be set incrementally.
What I would do is to calculate the number of iterations algebraically and create a local parameter. If you can't see how, review triangular numbers.
parameter MAX = 10;
// Generalizing your TOT_INST
parameter TOT_INST = MAX * (MAX - 1) / 2 ;
wire [98:0] inwire [MAX-1:0] ;
wire [98:0] outwire [TOT_INST-1:0];
genvar x,y;
generate
for (x = 0; x <= MAX-1; x = x + 1 )
begin : gen1
for (y = x + 1; y<=MAX-1; y=y+1)
begin : gen2
localparam z = TOT_INST - ((MAX - x - 2) * (MAX - x - 1)) / 2 + y - MAX;
initial begin
$display("%d %d %d", x, y, z);
end
end
end
endgenerate
The formula would be simpler if we used the x in the inner loop.

Verilog: Using reg As Counters For for-loops

In a module:
reg a, b;
integer i, j;
initial
begin
for (a = 0; a < 2; a = a + 1)
//some code
end
The textbook says it would be incorrect to get rid of integers i and j and use reg a and b directly as loop counters. Hint: reg variables have a fixed size and, hence, they wrap.
What does that mean? Doesn't integer have a fixed size as well? And what's wrapping?
A reg is either single bit, or multiple bit if you define it as an array. An integer, on the other hand is 32 bits. So if you have a loop, it is more convenient to use an integer variable that doesn't overflow as the loop advances.
In your example, you set a < 2, so with a single bit reg the loop never terminates.
Moreover integers are singed values.

Setting multiple values in a vector to a single value

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

Verilog - generate weighted random numbers

I am trying to generate random single bits and this is simple as long as you want a normal randomization:
wire R;
assign R = $random % 2;
What I am looking for is a sort of weighted probability like:
wire R;
assign R = 60%(0) || 40%(1);
Forgive me if it is not conform to standard Verilog code, it is just to give an idea of what I want.
Can anyone help me out?
Thank you
The SystemVerilog solution has a distribution method within randomize called dist. Weights are assigned by value_or_range := weight or value_or_range :/ distributed_weight. This exert from the IEEE Std 1800-2012 § 18.5.4 page 476 gives a clear example:
When weights are applied to ranges, they can be applied to each value in the range, or they can be applied to the range as a whole. For example:
x dist { [100:102] := 1, 200 := 2, 300 := 5}
means x is equal to 100, 101, 102, 200, or 300 with a weighted ratio of 1-1-1-2-5, and
x dist { [100:102] :/ 1, 200 := 2, 300 := 5}
means x is equal to one of 100, 101, 102, 200, or 300 with a weighted ratio of
1/3-1/3-1/3-2-5.
dist is used in randomization so it needs to be mare of a randomize() with (or a class constraint). randomize returns a success bit, therefore it should be in called within an assert, void'(), or the RHS of an assignment.
In your we can set the weight of 0 to 6 and the weight of 1 to 4, creating a total weight of 10 with a 60/40 distribution. Example:
reg R;
initial begin
assert( randomize(R) with { R dist { 0 := 6, 1 := 4 }; } );
end
From more about dist see IEEE Std 1800-2012 § 18.5.4 "Distribution".
Create a random integer then based on Value return 1 or 0; NB you may want to seed your random number, for repeatability use the same seed. This way when a test fails it can be debugged.
$urandom works a little different to $random it doe not update the seed value so should only be seeded the first time it is called in a thread (always block). It is also thread safe, each always block works independently.
initial begin
$urandom(seed);
$urandom;
$urandom;
end
integer temp;
reg r ;
always # ... begin
temp = $urandom; //Range: +2_147_483_647 -2_147_483_648
// weighting; 0 would be 50:50
// real weighting is (0.1 + 0.5), 0.5 inherent from positive number.
r = (temp > (2_147_483_647*0.1);
end
NB: the random functions are not synthesizable and should only be used for testbenches. if you want a random number for synthesis check out this Question
For Verilog you can always so something like:
integer R;
R = ($dist_uniform(0,100) < 60) : $dist_uniform(0,5) : $dist_uniform(6,10)
and this in SystemVerilog would be the same as:
std::randomize(R) with {R dist {[0:5] :/60, [6:10] :/ 40} ;};
You could also do this procedural code:
randcase
60: R = 1;
40: R = 0;
endcase
Following Code Will Generate Random Variable as Per Your Requirement :
program top;
class Packet;
rand reg R;
constraint percentage {R dist {1:=60,0:=40};};
function void display;
$display("Random Reg : %0d",this.R);
endfunction
endclass
Packet P;
initial
begin
P = new;
repeat(10)
begin
P.randomize();
P.display;
end
end
endprogram
It seems not so hard at verilog.
reg [7:0] R;
reg rand_bit;
R = $random();
if (R < 76)
rand_bit = 1'b0;
else
rand_bit = 1'b1;
Here I assume that $random is pretty uniform. I think it should work :)
Something like:
wire R;
if ($random[7:0]>(40*255/100))
assign R = 1'b0;
else
assign R = 1'b1;
I'm assuming that the algorithm that $random uses produces numbers that are equally random whatever bits you take from it.

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