In Verilog, when using a for-loop within a sequential process, how can you increment the sequential variable? - for-loop

Here is a snippet of code, hopefully you are alright without the preamble:
always # (posedge clk)
begin
if(rst)
begin
i<=0;
j<=0;
end
else
begin
for(j = 0 ; j < 16 ; j = j+1)
begin
if(i<8)
begin
var[j] <= var_2[i];
i <= i+1;
end
end
end
end
Basically, I am wondering if the outer "for-loop" will erroneously increment the counter variable i, rather than simply calculating the 16 vars in parallel. If this is the case, should I cut the for-loop short so that the variable is incremented outside the for-loop?
Thanks!

You are making the code unnecessary complex.
If i<8 then these get executed:
var[j] <= var_2[i];
i <= i+1;
But the i is not incremented until after the clock edge.
As 'i' does not change the condition does not change and thus once true it stays true for all values of j.
Probably a better way of understanding this is to write the code as follows which has the exact same behavior:
always # (posedge clk)
begin
if(rst)
begin
i<=0;
j<=0;
end
else
begin
for (j = 0 ; j < 16 ; j = j+1)
begin
if(i<8)
var[j] <= var_2[i];
end
// i increment independent from the 'j' loop
if(i<8)
i <= i+1;
end
end

Related

Is it synthesizable, using integer variable for the for-loop within a generate block in a always block?

In the code below, the line: mem_reg[wr_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]][i*8 +: 8] <= wr_cmd_data[SEG_DATA_WIDTH*n+i*8 +: 8];
The index "i" is an integer type. It is being synthesized right??
I was under the impression that integer variables are only used for simulations in the initial procedural block
Also, the BRAM reg [SEG_DATA_WIDTH-1:0] mem_reg[2**INT_ADDR_WIDTH-1:0]; is being synthesized the number of times the genvar variable "n" loops in the for loop? The multiple generated BRAMs mem_reg will have the same names? And they cannot be accessed separately by name with something like: mem_reg[n] right?
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DMA parallel simple dual port RAM
*/
module dma_psdpram #
(
// RAM size
parameter SIZE = 4096,
// RAM segment count
parameter SEG_COUNT = 2,
// RAM segment data width
parameter SEG_DATA_WIDTH = 128,
// RAM segment byte enable width
parameter SEG_BE_WIDTH = SEG_DATA_WIDTH/8,
// RAM segment address width
parameter SEG_ADDR_WIDTH = $clog2(SIZE/(SEG_COUNT*SEG_BE_WIDTH)),
// Read data output pipeline stages
parameter PIPELINE = 2
)
(
input wire clk,
input wire rst,
/*
* Write port
*/
input wire [SEG_COUNT*SEG_BE_WIDTH-1:0] wr_cmd_be,
input wire [SEG_COUNT*SEG_ADDR_WIDTH-1:0] wr_cmd_addr,
input wire [SEG_COUNT*SEG_DATA_WIDTH-1:0] wr_cmd_data,
input wire [SEG_COUNT-1:0] wr_cmd_valid,
output wire [SEG_COUNT-1:0] wr_cmd_ready,
output wire [SEG_COUNT-1:0] wr_done,
/*
* Read port
*/
input wire [SEG_COUNT*SEG_ADDR_WIDTH-1:0] rd_cmd_addr,
input wire [SEG_COUNT-1:0] rd_cmd_valid,
output wire [SEG_COUNT-1:0] rd_cmd_ready,
output wire [SEG_COUNT*SEG_DATA_WIDTH-1:0] rd_resp_data,
output wire [SEG_COUNT-1:0] rd_resp_valid,
input wire [SEG_COUNT-1:0] rd_resp_ready
);
parameter INT_ADDR_WIDTH = $clog2(SIZE/(SEG_COUNT*SEG_BE_WIDTH));
// check configuration
initial begin
if (SEG_ADDR_WIDTH < INT_ADDR_WIDTH) begin
$error("Error: SEG_ADDR_WIDTH not sufficient for requested size (min %d for size %d) (instance %m)", INT_ADDR_WIDTH, SIZE);
$finish;
end
end
generate
genvar n;
for (n = 0; n < SEG_COUNT; n = n + 1) begin
(* ramstyle = "no_rw_check" *)
reg [SEG_DATA_WIDTH-1:0] mem_reg[2**INT_ADDR_WIDTH-1:0];
reg wr_done_reg = 1'b0;
reg [PIPELINE-1:0] rd_resp_valid_pipe_reg = 0;
reg [SEG_DATA_WIDTH-1:0] rd_resp_data_pipe_reg[PIPELINE-1:0];
integer i, j;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (i = 0; i < 2**INT_ADDR_WIDTH; i = i + 2**(INT_ADDR_WIDTH/2)) begin
for (j = i; j < i + 2**(INT_ADDR_WIDTH/2); j = j + 1) begin
mem_reg[j] = 0;
end
end
for (i = 0; i < PIPELINE; i = i + 1) begin
rd_resp_data_pipe_reg[i] = 0;
end
end
always #(posedge clk) begin
wr_done_reg <= 1'b0;
for (i = 0; i < SEG_BE_WIDTH; i = i + 1) begin
if (wr_cmd_valid[n] && wr_cmd_be[n*SEG_BE_WIDTH+i]) begin
mem_reg[wr_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]][i*8 +: 8] <= wr_cmd_data[SEG_DATA_WIDTH*n+i*8 +: 8];
wr_done_reg <= 1'b1;
end
end
if (rst) begin
wr_done_reg <= 1'b0;
end
end
assign wr_cmd_ready[n] = 1'b1;
assign wr_done[n] = wr_done_reg;
always #(posedge clk) begin
if (rd_resp_ready[n]) begin
rd_resp_valid_pipe_reg[PIPELINE-1] <= 1'b0;
end
for (j = PIPELINE-1; j > 0; j = j - 1) begin
if (rd_resp_ready[n] || ((~rd_resp_valid_pipe_reg) >> j)) begin
rd_resp_valid_pipe_reg[j] <= rd_resp_valid_pipe_reg[j-1];
rd_resp_data_pipe_reg[j] <= rd_resp_data_pipe_reg[j-1];
rd_resp_valid_pipe_reg[j-1] <= 1'b0;
end
end
if (rd_cmd_valid[n] && rd_cmd_ready[n]) begin
rd_resp_valid_pipe_reg[0] <= 1'b1;
rd_resp_data_pipe_reg[0] <= mem_reg[rd_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]];
end
if (rst) begin
rd_resp_valid_pipe_reg <= 0;
end
end
assign rd_cmd_ready[n] = rd_resp_ready[n] || ~rd_resp_valid_pipe_reg;
assign rd_resp_valid[n] = rd_resp_valid_pipe_reg[PIPELINE-1];
assign rd_resp_data[SEG_DATA_WIDTH*n +: SEG_DATA_WIDTH] = rd_resp_data_pipe_reg[PIPELINE-1];
end
endgenerate
endmodule
`resetall
try to use named blocks:
for (n = 0; n < SEG_COUNT; n = n + 1) begin : blkname
reg [SEG_DATA_WIDTH-1:0] mem_reg [2**INT_ADDR_WIDTH-1:0];
end
And access as:
assign x = blkname[i].mem_reg[j];

VHDL - looping through an array

I wanted to loop through an array elements and later output them.
I don't think that the for loop is correct.
Could someone help with this, please ?
enter image description here
In VHDL, a for loop is a shorthand notation for creating parallel paths of logic.
In your example, the loop becomes a shift-by-1 index mapping assignment:
r_array(1) <= myArray1(0);
r_array(2) <= myArray1(1);
r_array(3) <= myArray1(2);
r_array(4) <= myArray1(3);
r_array(5) <= myArray1(4);
r_array(6) <= myArray1(5);
r_array(7) <= myArray1(6);
Since r_array is scalar type integer type and not a vector, this won't work as is.
Try using r_array as an index counter, then on each rising edge clock the next index of myArray will be assigned and our array index counter will increment by 1 (or wrap over back 0).
if rising_edge(i_CE1Hz) then
if r_array <= 7 then
r_array <= r_array + 1;
else
r_array <= 0;
end if;
o_element <= myArray(r_array); -- new output signal
end if;

Finding the maximum value of an array in log2 time in Verilog?

I have designed a 'sorter' that finds the maximum value of its input, which is 16 31-bit words. In simulation, it works, but I am not sure if it will work in hardware (as it doesn't seem to be working on the FPGA as planned). Can someone please let me know if this will work? I am trying to save on resources, that is why I am trying to reuse the same register. Thank you...
module para_sort(clk, ready, array_in, out_max)
input clk, ready;
input [16*31-1:0] array_in;
output reg [30:0] out_max;
reg [30:0] temp_reg [0:15]
integer i, j;
always # (posedge clk)
begin
if(ready)
begin
for(j=0; j<16; j=j+1)
begin
temp_reg[j] <= array_in[31*(j+1)-1 -: 31];
end
i<=0;
done<=0;
end
else
begin
if(i<4)
begin
for(j=0; j<16; j=j+1)
if(temp_reg[j+1] > temp_reg[j]
temp_reg[((j+2)>>1)-1] <= temp_reg[j+1]
else
temp_reg[((j+2)>>1)-1] <= temp_reg[j]
i<=i+1;
end
end
if(i == 4)
begin
out_max <= temp_reg[0];
done <=1;
i <= i + 1;
end
if(i == 5)
done <=0;
end
endmodule
Sorry for the long code. If you have any questions about the code, please let me know.
Before answering the question, I assume that you do not have any problem with code syntax and semantics, and the module is part of the design so that you do not have problem with number of I/O pins, as it seems to be the case.
First of all, the algorithm that has been used in this posted code is incorrect. Maybe you meant something different, but this one is incorrect. The following code worked for me:
//The same code as you posted, but slight changes are made
//Maybe you have tried compiling this code and missed some points while posting
module para_sort(clk, ready, array_in, out_max, done);
input clk, ready;
input [16*31-1:0] array_in;
output reg [30:0] out_max;
output reg done;
reg [30:0] temp_reg [0:16];
integer i, j;
always # (posedge clk)
begin
if(ready)
begin
for(j=0; j<16; j=j+1)
begin
temp_reg[j] <= array_in[31*(j+1)-1 -: 31];
end
i<=0;
done<=0;
end
else
begin
if(i<4)
begin
for(j=0; j<16; j=j+2)
begin
if(temp_reg[j+1] > temp_reg[j])
temp_reg[((j+2)>>1)-1] <= temp_reg[j+1];
else
temp_reg[((j+2)>>1)-1] <= temp_reg[j];
end // end of the for loop
i<=i+1;
end
end
if(i == 4)
begin
out_max <= temp_reg[0];
done <=1;
i <= i + 1;
end
if(i == 5)
done <=0;
end
endmodule
If the above code does not solve the problem, then:
The problem might be with timing. In Quartus Prime software, there are netlist viewer tools (The same is true for Vivado). When you check the generated circuit, you can see paths with many combinational blocks and feedback (caused mostly by the second for loop). If the second for loop does not have enough time to complete execution in a single clock, you will loose synchronization and the results will be unpredictable.
So,
Try the above code first
If the code does not solve your problem, then try FSM (with case and if - else - if statements ) even the code becomes longer or looks uglier (not user friendly), it is more FPGA hardware friendly.

PLSQL - How does this Prime number code work?

DECLARE
i number(3);
j number(3);
BEGIN
i := 2;
LOOP
j:= 2;
LOOP
exit WHEN ((mod(i, j) = 0) or (j = i));
j := j +1;
END LOOP;
IF (j = i ) THEN
dbms_output.put_line(i || ' is prime');
END IF;
i := i + 1;
exit WHEN i = 50;
END LOOP;
END;
The code works properly. I tried to figure out how it works and ended up having 4 as a prime number, which isn't. If you could help me understand how this nested loop works, I'd be very thankful.
Thank you.
The code is looking for all the prime numbers up to 50. The outer loop is just checking each value of i from 2 to 50 to see if that integer is prime.
For each value of i, it tries to divide that integer by every other integer one by one, starting from 2. If i is divisible by j with no remainder (mod is zero) then it is not prime; unless it is only divisible by itself (j=1).
It exits that inner loop as soon as it finds a value of j which divides into i, or it reaches i itself.
It then needs a further check to see which of those conditions actually caused it to exit; and thus whether or not it is actually prime.
You could do the same thing with slightly clearer (IMHO) logic:
BEGIN
<<OUTER>>
FOR i IN 2..50 LOOP
FOR j IN 2..i-1 LOOP
IF (mod(i, j) = 0) THEN
CONTINUE OUTER;
END IF;
END LOOP;
dbms_output.put_line(i || ' is prime');
END LOOP;
END;
/
Lets rewrite it so its a bit simpler:
BEGIN
<<outer_loop>>
FOR value IN 2 .. 50 LOOP
FOR divisor IN 2 .. value - 1 LOOP
CONTINUE outer_loop WHEN MOD( value, divisor ) = 0;
END LOOP;
DBMS_OUTPUT.PUT_LINE( value || ' is prime' );
END LOOP;
END;
/
All it is doing is, in the outer loop going through the number 2 .. 50 and in the inner loop is checking whether there is a number that divides exactly into that value; if there is then continue the outer loop and if there is not then output that the number is prime.
Your code is effectively the same code but it is complicated by not using FOR .. IN .. loops
If I understand your question.
When i = 4 and j = 2 then condition ((mod(i, j) = 0) or (j = i)) leads to the exit from inner loop, but condition (j = i ) is false and program doesn't go to line dbms_output.put_line(i || ' is prime');

how to count leading 0 in vector

back:while (sub1_mantissa(52)='0') loop
sub1_mantissa := sub1_mantissa(51 downto 0) & '0';
count := count + "000000000001";
end loop back;
hi .i want to count leading zeros in vector...like if my result is 0001 so it will show 3 zeros..so my counter will be increment by 3..and when i will get the first 1 in msb then my loop will stop...
i m using the above code..but it is not working...counter value it takes is too large like 1100111...i am not getting where is d problem...guys plz help me...n reply soon
I would use a for loop to count this, something like this:
variable zero_count : natural := 0;
for i in sub1_mantissa'range loop
if sub1_mantissa(i) = '0' then
zero_count := zero_count + 1;
else
exit;
end if;
end loop;
NOTE: this will only count the leading zeros if sub1_mantissa is declared using DOWNTO notation.

Resources