Is below sort of generate loop is valid in system verilog.
genvar i,j;
for (i=0,j=5; i<5 && j<10; i++,j++) begin:M1
integer t;
initial begin
t = i*j;
end
endgenerate
Nope. I'm not even sure what the behavior of this code should be, or in what order they execute.
genvar i,j;
for (i = 0; i <5; i++) begin
for (j = 5; j < 10; j++) begin
$display("%d", i*j);
end
end
you don't need 'endgenerate' in the end.
You cannot do much with genvars in your example.
The following code mimics what you asked for, but it might not work with all simulators. It works with synopsys vcs but does not work with icarus.
module g;
genvar i;
for (i=0; i<5; i++) begin:M
if (i == 0) begin:B
parameter j = 5;
end
else begin:B
parameter j = g.M[i-1].B.j + 1;
end
integer t;
initial begin
t = i*B.j;
$display(i, B.j, t);
end
end // block: M
endmodule // g
the idea is to declare the parameter j inside the generate loop so that its value is an increment of the value declared in the previous iteration. You need to add a named block 'B' to declare conditionally.
Related
Im currently working on the Shift-Add Algorithm (32x32 bit Multiplication) in System Verilog. System Verilog cant find any error and my code is working correctly according to GTKwave. When I synthesize my circuit with yosys, Latches will be added. And that is the Problem. I dont want Latches in my Circuit. Heres my Code:
module multiplier(
input logic clk_i,
input logic rst_i,
input logic start_i,
input logic [31:0] a_i,
input logic [31:0] b_i,
output logic finished_o,
output logic [63:0] result_o
);
typedef enum logic [1:0] { STATE_A, STATE_B} state_t;
state_t state_p, state_n;
logic [63:0] fin_res;
logic [63:0] tmp;
logic rst_flag;
integer i;
always #(posedge clk_i or posedge rst_i) begin
if (rst_i == 1'b1) begin
state_p <= STATE_B;
end
else begin
state_p <= state_n;
end
end
always #(*)begin
state_n = state_p;
case (state_p)
STATE_A: if (start_i == 0) state_n = STATE_B;
STATE_B: if (start_i == 1) state_n = STATE_A;
default: state_n = state_p;
endcase
end
always #(*) begin
case (state_p)
STATE_A: begin
rst_flag = 1;
fin_res = 0;
finished_o = 0;
tmp = 0;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
default: begin
finished_o = 0;
result_o = 0;
end
endcase
end
endmodule
After spending 2 days only with debugging and not finding any mistake I would like to ask if u could help me. I am assigning every output (at least I think so). So where is my mistake? Is it the for loop? But what would be wrong with it? Thanks in advance for your help :)
Some useful Information for the Code-Snippet: start_i is the starting signal. If this is set to 1 the multiplication should be started. finished_o is the finish flag. If this is set to 1 the CPU will know that the computation is completed. a_i and b_i are the inputs which should be multiplied. result_o is the result of the multiplication which can be read when finished_o is set to 1.
According to yosys i get the following latches:
64 DLATCH_N
64 DLATCH_P
I think something may be wrong with fin_res in the for loop cause that logic variable is exactly 64 bits long as are the Latches
From the comment you have a bunch of variables which are not assigned in the second case statement causing synthesis to generate latches. To avoid it you need to assign all the vars in all branches of the case statement and conditional statements recursively.
However, if there is a default value you can assign to all of them, you can use a pattern similar to the one from the second always block, just assigning default values before the 'case' statement. This way you do not even need the default clause and you can get rid of it in the second always block as well.
always #(*) begin
// set default values
rst_flag = 0;
fin_res = 0;
finished_o = 0;
tmp = 0;
result_o = 0;
case (state_p)
STATE_A: begin
rst_flag = 1;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
// are you sure that you do not need a latch here?
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
// you do not need 'default' here.
endcase
end
My fixes will cause combinational behavior and should get rid of latches in synthesis, but it does not look like they will behave as you expected. It looks like you really need a latches here.
rst_flag must be a latch. You set it in STATE_A and use it in STATE_B. It has to keep the value between states. This is a latch behavior.
In STATE_B you change finished_o only if some of conditions met. What happens if the rst_flag and start_i are both 0. do you want finished_o to be 0 or the previous value? In the latter case you need a latch.
How about fin_res ? What do you want to do with it in other states? keep previous value (latch) or have a default value (no latch).
...
I am Writing a Verilog function to Locate the index of the first one on the right in the vector.If the vector has no ones, the function should returns the value to the vector’s highest index + 1. Here is the code :
module m ();
parameter n = 3;
function integer Locate_one (input [n-1:0] a );
Locate_one ='dx;
for (integer i =n-1 ; i<=0 ; i=i-1)
begin
if(a[i] == 1'b1)
begin
Locate_one=i;
break;
end
end
if (Locate_one=='dx)
Locate_one=n;
endfunction
initial begin
reg [n-1:0] a = 3'b111;
integer result = Locate_one (a);
$display("output is %d ", result);
end
endmodule
Th questions are as follows :
How to break out of the function when we find the highest one ? I have used the keyword break, which is as I found online, is a valid SystemVerilog keyword not Verilog Keyword.
The strategy that I have used to know that there is no one in the vector is that I have initialized the return integer to X and then I have compared the variable to X at the end of the function. Is this a good way to do so or there is another better way to do this comparison ?
There are a number of problems with your code.
You cannot use the == to compare with x—it always returns false. you must use the === operator
You are initializing two static variables a and result and the order of initializations is not defined. They are not procedural statements. SystemVerilog has made implicitly static variable initializations inside procedural code illegal, and that is the only backward incompatibility with Verilog I can think of.
Your code has a lot of SystemVerilog constructs besides break
declaring a variable in a for loop
a function/task body without begin/end keywords.
You should not be using x values in your code. It's not synthesizable, and it makes debugging your code more difficult if you made a mistake.
Your loop condition was the opposite of what you needed.
You can use a disable statement to get functionality similar to a break if you want strict Verilog compatibility.
module m ();
parameter n = 5;
function integer Locate_one (input [n-1:0] a );
integer i;
begin : block
Locate_one = n;
for (i =n-1 ; i>=0 ; i=i-1)
begin
if(a[i] == 1'b1)
begin
Locate_one=i;
disable block;
end
end
end
endfunction
reg [n-1:0] a = 3'b111;
initial begin
integer result;
result = Locate_one (a);
$display("output is %d ", result);
end
endmodule
Here is the SystemVerilog code
module m ();
parameter n = 5;
function int Locate_one (input [n-1:0] a );
Locate_one = n;
for (int i =n-1 ; i>=0 ; i=i-1)
begin
if(a[i] == 1'b1)
begin
Locate_one=i;
break;
end
end
endfunction
logic [n-1:0] a = 3'b111;
int result;
initial begin
result = Locate_one (a);
$display("output is %d ", result);
end
endmodule
I would go with a temp variable inside the function block, indicating if the "1" has been found. It wasn't necessary to initialise the index variable with X's, this should do the work: (I believe this is for simulation purposes as there are no input/output ports)
module first_one ();
parameter n = 3;
reg [n-1:0] a;
function integer locate_one;
input [n-1:0] a;
integer i;
reg found_temp;
begin
found_temp = 0;
for (i=0; i<n; i=i+1) begin
if(a[i] == 1'b1 & ~found_temp) begin
locate_one = i;
found_temp = 1;
end
end
if(~found_temp)
locate_one = n;
end
endfunction
initial begin
a = 0;
$monitor("a = %b : index = %d", a, result);
#100 $finish;
end
wire [$clog2(n)-1:0] result = locate_one(a);
always
#1 a = $urandom;
endmodule
This can be tested with icarus verilog:
iverilog first_one.v -o first_one.tb
vvp first_one.tb
I need to initialize arrays in generated instances via generate block in Verilog. I'm trying to use the syntax below, however, I get an error as
External reference foo[0].bar.array[0] remains unresolved.
in Xilinx ISE.
integer i, j;
initial begin
// initialization of arrays
for(i=0; i<(2**7); i=i+1) begin
valid_array[i] = 0;
for(j=0; j<N; j=j+1) begin
foo[j].bar.array[i] = 0;
end
end
end
This is my generate block:
genvar jj;
generate
for(jj = 0; jj < N; jj = jj + 1) begin : foo
Memory_v3
#(
.ADDRESS_WIDTH(INDEX),
.DATA_WIDTH(TAG)
) bar
(
.clock(clock),
.we(we),
.addr_a(addra),
.addr_b(addrb),
.din(din),
.dout(dout)
);
end
endgenerate
What is the correct way to do this?
the problem is that foo block gets resolved at compile time. So, the names like foo[0], foo[1] are pre-generated and are compile-time names, they not work with dynamic index resolution at run-time. Therefore foo[j] will not work.
the solution in this case is to use another generate block to initialize them. Something like the following.
generate
for(jj = 0; jj < N; jj = jj + 1) begin : foo_init
initial begin
// initialization of arrays
for(i=0; i<(2**7); i=i+1) begin
foo[jj].bar.array[i] = 0;
end
end
end
endgenerate
Same story is with array of instances.
FOO bar[3:0](); // array of instances
int i,j;
generate
for(jj = 0; jj < 4; jj = jj + 1) begin : foo_init
initial begin
for(i=0; i<(2**7); i=i+1) begin
bar[jj].array[i] = 0;
end
end
end
endgenerate
BTW, in system verilog you can avoid using generate/endgenerate pairs:
I'm trying to add a second level of nesting to my generate loop in the following code, but iverilog is throwing an error that the register j is unknown:
../crc.v:119: register ``j'' unknown in crc_tb.U_crc.loop[31].
So is it possible to use multiple genvars in verilog? It looks like j is being interpreted as a register.
Code snippet:
genvar i;
genvar j;
reg [DATA_WIDTH-1:0] temp;
generate
for(i = 0; i < CRC_WIDTH; i= i + 1)
begin : loop
always #(posedge clock or posedge reset)
begin
if (reset)
begin
crc_out[i+:1] = SEED[i+:1];
end
else if (init)
begin
crc_out[i+:1] = SEED[i+:1];
end
else if (data_enable)
begin
if (DEBUG)
$display("\n\nCRC OUT[%0d]\n***************************************************************************", i);
if (REVERSE)
begin
for (j = DATA_WIDTH-1; j >= 0; j = j - 1)
begin : reverse_loop
temp[DATA_WIDTH-1-j] = data[i][j];
end
crc_out[i+:1] <= prev(DATA_WIDTH-1,i,temp,crc_out);
end
else
begin
crc_out[i+:1] <= prev(DATA_WIDTH-1,i,data,crc_out);
end
end
end
end
endgenerate
You can nest multiple generate loops, but your inner generate loop is inside a procedural block of code - that is illegal. Perhapsj should just be a local variable instead of a genvar.
Consider the following function which I would like to parameterize. I have created some parameters to set a width of the input and a corresponding width parameter for the output.
parameter SELECT_WIDTH = 6;
parameter PRIENC_WIDTH = $clog2(SELECT_WIDTH+1);
function [PRIENC_WIDTH-1:0] prienc6;
input [SELECT_WIDTH-1:0] select;
reg [PRIENC_WIDTH-1:0] out;
begin
casex(select)
6'b000001: out = 3'b101; // Is it possible to parameterize the case statement with generate
6'b00001x: out = 3'b100;
6'b0001xx: out = 3'b011;
6'b001xxx: out = 3'b010;
6'b01xxxx: out = 3'b001;
6'b1xxxxx: out = 3'b000;
endcase
prienc6 = out ;
end
end function
Obviously, the casex statement cases will not expand as written.
So I tried the following, which didn't compile correctly indicating unexpected generate found.
function [PRIENC_WIDTH-1:0] prienc_n;
input [SELECT_WIDTH-1:0] select;
reg [PRIENC_WIDTH-1:0] out;
begin
genvar gv_j;
casex(select)
for (gv_j = 0; gv_j < SELECT_WIDTH; gv_j = gv_j + 1)
begin
{{(SELECT_WIDTH-1)-gv_j{1'b0}},1'b1,{gv_j{1'bx}}} : out = (SELECT_WIDTH-1)-gv_j;
end
endcase
prienc_n = out ;
end
end function
I have been able to get the correct behavior using parameterized if's, but it seems like I should be able to parameterize that casex statement. Any thoughts on how to do this? I guess what I will try next is to wrap the casex in the generate loop and create 6 casex statements, each with only one state.
Since you tagged this question with SystemVerilog, I'll show you how to do this without a case statement or generate
function logic [PRIENC_WIDTH-1:0] prienc_n(
input [SELECT_WIDTH-1:0] select);
for (int j = 0; j < SELECT_WIDTH; j++) begin
if (select[SELECT_WIDTH-1]) return j;
select <<=1;
end
// if no 1 found
return ('x); // you did not specify this case
endfunction
If you need to stay in Verilog, it will need an intermediate variable
function reg [PRIENC_WIDTH-1:0] prienc_n(
input [SELECT_WIDTH-1:0] select);
reg [PRIENC_WIDTH-1:0] out;
integer j;
begin
out = {PRIENC_WIDTH{1'bx}}; // what should be returned if no 1 found
for (j = 0; j < SELECT_WIDTH; j = j + 1) begin
if (select[SELECT_WIDTH-1]) begin
out = j;
select = 0;
end
select = select << 1;
end
prienc_n = out;
end
endfunction