Initial iterator for generate for-loop - for-loop

In a generate loop, you often need to connect the first iteration of wires to your inputs (or some unique set of wires) before the array stuff kicks in. Pasted below is a snippet from my parameterizable OR-Reduce module (my assignment requires structural verilog, so oOUt = |adjA is not legal).
for(i=0; i<depth; i=i+1) begin : lvl
localparam iWidth = p2Width>>i;
localparam oWidth = iWidth>>1;
wire [oWidth-1:0] tmp;
if(i==0) begin
or2$ reduce [oWidth-1:0]
(tmp, adjA[iWidth/2-1:0], adjA[iWidth-1:iWidth/2]);
end else begin
or2$ reduce [oWidth-1:0]
(tmp, lvl[i-1].tmp[iWidth/2-1:0], lvl[i-1].tmp[iWidth-1: iWidth/2]);
end
end
I have to put this nasty if-statement to catch the first iteration and connect it to the inputs. The problem is that I can't just change the initial i value to 1 and declare a lvl[0].tmp outside of the for-loop. Here's what I think would look nicer if it were legal.
wire [p2Width-1] lvl[0].tmp;
or2$ reduce [oWidth-1:0]
(lvl[0].tmp, adjA[iWidth/2-1:0], adjA[iWidth-1:iWidth/2]);
for(i=1; i<depth; i=i+1) begin : lvl
localparam iWidth = p2Width>>i;
localparam oWidth = iWidth>>1;
wire [oWidth-1:0] tmp;
or2$ reduce [oWidth-1:0]
(tmp, lvl[i-1].tmp[iWidth/2-1:0], lvl[i-1].tmp[iWidth-1: iWidth/2]);
end
Is there a way to clean up my generate loop?

You can declare your input array to be one entry wider than required. I find this often results in more readable code:
logic [N_LEVELS:0] block_inputs; // Last entry not used, optimised away
logic [N_LEVELS-1:0] block_outputs;
// Start of pipeline
assign block_inputs[0] = stage1_input;
genvar i;
generate
for (i=0; i<N_LEVELS; i++) begin: levels
some_block i_some_block (
.data (block_inputs[i]),
.result (block_outputs[i])
);
assign block_inputs[i+1] = block_outputs[i];
end
endgenerate
assign final_result = block_outputs[N_LEVELS-1];

Related

Implementing a for loop in systemverilog

I want to generate an automated input stimulus for my DUT. This input is going to different modules at the same time and working on this data. I want my input to be generated in an increasing manner. Like 0000,0001,0010,0011...1111
I tried using a for loop but it only uses the last data from the loop and works on that.
always_comb begin
for (i=0, i<16; i=i+1)
begin
data <= i;
end
end
When I give inputs individually like,
data = 8'd1;
#2;
data = 8'd2;
#2;
It works smoothly with all input values specified.
always_comb cannot have delays. At least per the IEEE1800 standard.
You can do something like this:
bit [3:0] data; // bit so the initial value is 0, not x
bit clk;
always #1 clk++; // or some other clock model
always_ff #(posedge clk) begin
data <= data+1;
end
or something like this:
logic [3:0] data;
initial begin
for (i=0, i<16; i=i+1) begin
data = i;
#2;
end
end
Or some other similar code with time delay.

Verilog: what does begin followed by colon and a variable mean

What does data_mux mean here? Is it just a name for the block?
if ((PORT_CONFIG == "32") && (P0 == 1'b1))
begin : data_mux
...
end
These are block names. Especially useful with generate blocks. For example you can define a generate block such as
genvar i;
generate (for i = 0; i<10; i++)
begin : structures
reg my_reg;
// ...
.. other block descriptions
// ...
end
endgenerate
Then you can access the block elements later like
structures[3].my_reg <= 1'b1;
Yes, it is just the name for the begin/end block. Refer to the free IEEE Std 1800-2012 (section 9.3.4 Block names). In most cases the block label is optional.

Error in verilog, coding for CSHM Filter using generate statement

module CSHM #(parameter data_width=8,order=4)
(y,in,clk,reset_n);
wire [data_width-1:0]coeff[0:order-1];
output reg signed [2*data_width-1:0]y;
input clk,reset_n;
input signed[data_width-1:0]in;
integer i;
wire [15:0] product1,product2,product3,product4,product5,product6,product7,product8;
wire signed[3:0]lsboutputcoeff;
wire signed[7:4]msboutputcoeff;
wire signed[2:0]lsbcount,msbcount;
wire signed[2:0]lsbselect,msbselect;
wire signed[2*data_width-1:0]muxoutput,shiftoutlsb,shiftoutmsb;
wire [3:0] lsbcoeff;
wire [7:4] msbcoeff;
//reg [7:0] this_coeff;
wire [2:0]inputshift;
wire signed[15:0]muxout;
wire signed[15:0]leftshiftone,leftshifttwo,leftshiftthree;
wire [15:0]outputshift;
bankofprecomputers b1(.product1(product1),.product2(product2),.product3(product3),.product4(product4),.product5(product5),.product6(product6),.product7(product7),.product8(product8),.in(in));
genvar count;
generate
assign coeff[0]= 8'd1;
assign coeff[1]= 8'd2;
assign coeff[2]= 8'd3;
assign coeff[3]= 8'd4;
for(count = 0; count < order ; count = count+1)
begin : gen_loop
assign lsbcoeff = coeff[count][3:0];
assign msbcoeff = coeff[count][7:4];
shifter s1(.lsboutputcoeff(lsboutputcoeff),.msboutputcoeff(msboutputcoeff),.lsbselect(lsbselect),.msbselect(msbselect),.lsbcount(lsbcount),.msbcount(msbcount),.lsbcoeff(lsbcoeff),.msbcoeff(msbcoeff));
end
endgenerate
mux8_1msb m1(.muxoutput(muxoutput),.msbselect(msbselect),.product1(product1),.product2(product2),.product3(product3),.product4(product4),.product5(product5),.product6(product6),.product7(product7),.product8(product8));
mux8_1LSB m2(.muxoutput(muxoutput),.lsbselect(lsbselect),.product1(product1),.product2(product2),.product3(product3),.product4(product4),.product5(product5),.product6(product6),.product7(product7),.product8(product8));
inverse_shifter is1(.shiftoutmsb(shiftoutmsb),.muxoutput(muxoutput),.msbcount(msbcount));
inverse_shifter_LSB is2 (.shiftoutlsb(shiftoutlsb),.muxoutput(muxoutput),.lsbcount(lsbcount));
always#(negedge clk)
begin
y = shiftoutmsb+shiftoutlsb;
end
endmodule
When im trying to synthesis , im getting error as
Multi-source in Unit on signal lsbcoeff3; this signal is
connected to multiple drivers.
Multi-source in Unit on signal lsbcoeff0; this signal is
connected to multiple drivers.
If im wrong anywhere , please guide me
lsbcoeff and msbcoeff are shared across the static-unrolled generate loops, therefore you have parallel assignments onto these nets. To resolve the issue, you need to make the nets unique for each loop. This can be done two different ways.
Array the nets:
wire signed [2:0] lsbcount [0:order-1];
wire signed [2:0] msbcount [0:order-1]
for(count = 0; count < order ; count = count+1) begin : gen_loop
assign lsbcoeff[count] = coeff[count][3:0];
assign msbcoeff[count] = coeff[count][7:4];
...
Localize the nets by declaring them inside the generate loop: Note: with this aproach, the nets will not be accessible outside its loop scope.
for(count = 0; count < order ; count = count+1) begin : gen_loop
wire signed [2:0] lsbcoeff = coeff[count][3:0];
wire signed [2:0] msbcoeff = coeff[count][7:4];
...
end
// lsbcoeff and msbcoeff cannot be accessed outside of the loop
The for loop is more or less like same lines repeated n number of times.
for(count = 0; count < order ; count = count+1)
begin : gen_loop
assign lsbcoeff = coeff[count][3:0];
assign msbcoeff = coeff[count][7:4];
....
So #Suguresh, your original code is having the issue.
As correctly pointed by Greg, you need to correct this. For your code, the solution 1 looks more apt. Can you change the code and post updated again to re-check ?

how to index a reg or memory in for-loop by for-variable?

I have a problem with the code below. The code is synthesized in ISE 14.2.
input [1:8176] m_d_in;
reg [1:511] m_d [1:16];
integer i;
always # (*)
begin
for (i=0; i<16; i=i+1)
begin
m_d[i+1] = m_d_in[ 1+511*i : 511+511*i];
end
end
after synthesizing, this error shows up:
HDL Compiler:1660_<'Address of CodeName.v> <'Line of Error>: procedural assignment to a non-register i is not permitted, left-hand side should be reg/integer/time/genvar
the line of Error refer to this:
m_d[i+1] = m_d_in[ 1+511*i : 511+511*i];
i also have tested using the:
reg [4:0] i;
and
genvar i;
instead of:
integer i;
and got exactly the same error I wrote above!
I know there is a solution by using a case instead of the code above, but in its not the right solution for me.
Thanks a lot.
Since you are range is consistent, Indexing vectors and arrays with +: is also possible:
always #* begin
for (i=0; i<16; i=i+1)
m_d[i+1] = m_d_in[511*i+1 +: 511];
end
The indexed part select (+:/-:) and generate block (from Morgan's answer) were introduced in IEEE std 1364-2001. Any modern simulator and synthesizer will support them.
If you use wire instead of reg then a single assign line can be wrapped up in a generate.
module tb(
input [1:8176] m_d_in
);
wire [1:511] m_d [1:16];
genvar i;
generate
for (i=0; i<16; i=i+1) begin
assign m_d[i+1] = m_d_in[ 1+511*i : 511+511*i];
end
endgenerate
endmodule
To keep the reg and use generates you would need to do:
module tb(
input [1:8176] m_d_in
);
reg[1:511] m_d [1:16];
genvar i;
generate
for (i=0; i<16; i=i+1) begin
always #* begin
m_d[i+1] = m_d_in[ 1+511*i : 511+511*i];
end
end
endgenerate
endmodule

How to randomize contents of a very large memory?

I need to randomize a large memory. All of the data is contained inside of latch modules -- 1 per bit.
How do I fix the following?
// Quick mock up of the memory, which I can't change
`define WIDTH 64*144
module latch(
output reg Q);
endmodule
module memory;
wire [`WIDTH-1:0] latchData;
latch latch[`WIDTH-1:0] (.Q(latchData[`WIDTH-1:0]));
endmodule
// My testbench, which I can change
module test;
reg [31:0] index;
memory memory();
initial begin
$display("Initial data: %0d", memory.latchData);
injectRandomData();
$display("Randomized data: %0d", memory.latchData);
end
task injectRandomData();
// Using for loop does not work
//for (index=0; index < `WIDTH; index = index+1) begin
// memory.latch[index].Q = $urandom;
//end
// Doing it this way seems terrible
memory.latch[0].Q = $urandom;
memory.latch[1].Q = $urandom;
memory.latch[2].Q = $urandom;
// ... a bunch more to go; don't wait up
endtask
endmodule
Code on EDA Playground: http://www.edaplayground.com/s/4/235
Quick and dirty solution:
task injectRandomData();
->do_InjectRandomData;
#0; // gen always block a change to finish;
endtask
event do_InjectRandomData;
genvar index;
generate
for(index = 0; index < `WIDTH; index = index +1) begin : gen_loop
always #(do_InjectRandomData) begin : set_rand
memory.latch[index].Q = $urandom;
end
end
endgenerate
Code on EDA Playground: http://www.edaplayground.com/s/6/236
You cannot dynamically index an array of instances. Two ways to fix this:
Do you really need to model a memory at such a low level? Change the memory model to an RTL description. It will be much better for performance anyways.
Use a generate block with a for-loop around the initial block instead of a for-loop inside the initial block. If you need to do this at some time other than time 0 you can use an event to trigger it.
genvar index;
event injectRandomData;
for (index=0; index &lt `WIDTH; index++) begin
always #injectRandomData
memory.latch[index].Q = $urandom;
end

Resources