Array search for 1s and 0s - arrays

I want to traverse a logic vector of 32 bits and find the indices which have value of 1 and 0 and store them in two separate arrays.
I will know through a input which will tell number of ones in the array.
The indices array will be two dimensional.
Also I want this to be implemented using combo logic and synthesizable.
I am not able to think of any logic without latch being inferred.
logic [31:0] data ; // Array to be traversed
logic [31:0] [ONES_NUM-1:0] one_index;// One's indices in array
logic [31:0] [32-ONES_NUM-1:0] zero_index;//Zeros indices in array
always #(*)
while(j < ONES_NUM)
while ( i < 32)
if(data[i]==1) begin
one_index[j][31:0] = i;
j++;
i++;
end
else
i++; //Here prob is no else statement so latch inferred.
Similar always#(*) for zero index as well.
Also I have doubts whether while loop is synthesizable.
Kindly help with the logic.

logic [31:0] data ;
logic [31:0][(ONES_NUM-1):0] one_index; // One's indices in array
logic [31:0][(32-ONES_NUM-1):0] zero_index; // Zeros indices in array
bit clk;
int j,k;
always#(posedge clk)
for(i=0;i<32;i++)
begin
if(data[i]==1)
begin
one_index[j]=i;
j++;
end
else
begin
zero_index[k]=i;
k++;
end
end
You have to use a clock to avoid latches.
you can refer to this link https://www.edaplayground.com/x/kZ6 for better understanding.

Related

for(i=i-1;i>=0;i++) How does this line works?

I read a code to convert decimal to binary. In that, after calculating and storing the binary number in an array in reverse, there was a for loop to print the array in reverse.
It goes like,
for(i=i-1;i>=0;i++)
printf("%d",b[i]);
Can anyone explain me how does the initialization part works?
In your case we should certainly have i-- instead of i++.
Just consider the below structure of for loops:
for (init ;condition; step)
The init state will be consider just one time at the beginning, each time condition checks and if it satisfies it will go to the block and at the end step will execute. Then we can rewrite the given loop as below:
i = i-1;
while ( i >= 0 ) {
printf("%d",b[i]);
i--;
}
Then in your case if we have i is equal length of b array, then your code will print all elements in the b in reverse order.

VHDL: Is it possible to concurrently shift array elements?

I would like to crearte own implementation of insertion sort for learning purposes.
As you may now, one of the steps reqiure shifting array elements to right by 1. The main difficulty here that the range of this operation has to be dynamic.
so if sort_reg is array from 0 to array_length, I need to acheive sort_reg(n)<=sort_reg(n-1), sort_reg(n-1)<=sort_reg(n-2) ... sort_reg(n-i+1)<=sort_reg(n-i); (n-m)>=i>=1, where m starting array index of the range, which would be shifted right by 1 from range ( m to n-1) to (m+1 to n).
The question is if it is possible to acheive this in one step, and then how?
Yes, it is possible in one step. You must store the element in registers and than assign the new value for all array elements at the same rising edge.
Let's make a simple example with just two signals a and b of type std_logic. Then this process would swap both elements at the rising edge of the clock:
process(clock)
begin
if rising_edge(clock) then
a <= b;
b <= a;
end if;
end process;
This works, because the signals get there new values after the process has finished. Thus, in the assignment of b the old value of a (before the rising clock edge) is assigned.
Let's continue with your example.
You didn't specify an specific array, so I take this one:
type array_type is array(0 to SIZE-1) of std_logic_vector(7 downto 0);
signal sort_reg : array_type;
Then the process can be written using a for loop.
EDIT: Within each iteration step, anif statement can be used to check if an element should be actually shifted. The signals n and m should be of type unsigned (prefered), or integer with range 0 to SIZE-1.
EDIT 2: Example changed to rotation as indicated in comments.
-- value to insert in case of rotation
value_to_insert <= sort_reg(to_integer(n)); -- to_integer required if type of 'n' is unsigned
process(clock)
begin
if rising_edge(clock) then
-- This loop is unrolled by the synthesis tool.
for i in SIZE-1 downto 1 loop
-- shift elements [n-1:m] to [n:m+1]
if (i <= n) and (i >= m+1) then
sort_reg(i) <= sort_reg(i-1);
end if;
-- insert new value
if i = m then
sort_reg(i) <= value_to_insert;
end if;
end loop;
-- insert into position zero
if m = 0 then
sort_reg(0) <= value_to_insert;
end if;
end if;
end process;
How about this;
sort_reg <= sort_reg(1 to sort_reg'high) & sort_reg(0);
I'm assuming sort_reg is a signal defined as;
signal sort_reg : some_array_type(0 to N);
In this case sort_reg'high is an attribute that is equal to N.
In vhdl & is used as concatenation operators. It joins two vector/arrays together to form a single vector/array.
Above example shifts only by 1 item. If you want to shift by M, you can use something like this;
sort_reg <= sort_reg(M to sort_reg'high) & sort_reg(0 to M-1);
Note that if you want to shift a signal (not assign it to a different signal) you should do it in a process as described by Martin.

Comparing input signal with array values

As I wrote in my previous post Synthesizable array of XY values
I wanted to create an array in Verilog to store x, y values of a given function.
Now I want to compare an input with x values of this array. If the value is within a specific region I want to save the index of this region and perform an addition with y with the same index. The result goes to the output. The code compiles just fine but its not synthesizes any circuit. The idea later is to use this array to perform linear interpolation and determinate the value of y for a given value of x that its not inside the array. The code is the following. I save the save value for x and y for each index.
module memc (inp,outp,clk,reset);
input[2:0] inp;
input clk, reset;
output[2:0] outp;
reg[2:0] outp;
wire [2:0] test;
reg [5:0] mem[2:0];
always #(posedge clk)
if (reset == 1'b1) begin
mem[0] <= {3'b000, 3'b000};//y0,x0
mem[1] <= {3'b001, 3'b001};//y1,x1
mem[2] <= {3'b010, 3'b010};//y2,x2
end
assign test ={inp<mem[0][2:0],inp<mem[1][2:0],inp<mem[2][2:0]}; //create a test vector by comparing inp with xo,x1,x2
always #(test)
case (test)
3'b1xx: outp=mem[0][2:0]+mem[0][5:3];//if 0<inp<x1
3'b0xx: outp=mem[1][2:0]+mem[1][5:3];//if x1<inp<x2
3'b00x: outp=mem[2][2:0]+mem[2][5:3];//if x2<inp<x3
default: outp=3'b00;
endcase
endmodule
Firstly, all three of your if conditions are the same (inp > mem[0][2:0]). I'm assuming you want
always #(*)
begin
if (inp > mem[0][2:0] ) //index 0
begin
index = 0;
end
else if (inp > mem[1][2:0] ) // index 1
begin
index = 1;
end
else if(inp > mem[2][2:0] ) // index 2
begin
index = 2;
end
end
Secondly, if you are using a large array (hard to be exact on the size), the latency from inp -> outp will get quite long, and you may get timing violations, depending on your clock speed. In that case, you'd be better off building a very simple FSM, and checking one or two entries per clock cycle instead. Just something to keep in mind moving forward.

Assigning entire array in verilog

I am trying to copy a 2d array into another like so:
reg [11:0] input_matrix [0:array_width - 1] [0:array_height - 1];
reg [11:0] output_matrix [0:array_width - 1] [0:array_height - 1];
always #(posedge clk)
begin
if(<some condition>)
output_matrix <= input_matrix;
end
So, we have two 2D arrays of 12-bit values. I'd like to copy one into the other.
This doesn't seem to be possible. Does anyone know the correct way to do this? Or, if not, explain why it's not possible? I can't see any reason why this assignment wouldn't be able to synthesize.
For loops generally don't synthesize well, for obvious reasons. However, is this one of the cases that a for loop can be used, because the loop is statically defined?
for loops are synthesizable. This is the case were it is perfectly fine as it can be statically unrolled.
The inner loop may not be necessary but I find some version of synthesis tools struggled with memory (array) assignments, they worked but renamed the buses badly which can cause issues with ECO's.
reg [11:0] input_matrix [0:array_width - 1] [0:array_height - 1];
reg [11:0] output_matrix [0:array_width - 1] [0:array_height - 1];
integer i;
integer j;
always #(posedge clk) begin
if(<some condition>) begin
for (i=0; i<array_width; i=i+1 ) begin
for (j=0; j<array_height; j=j+1 ) begin
output_matrix[i][j] <= input_matrix[i][j];
end
end
end
end
The code as you wrote it is synthesizable. See section 2.5.2 in this paper:
http://www.lcdm-eng.com/papers/snug13_SNUG-SV-2013_Synthesizable-SystemVerilog_paper.pdf

Verilog Parallel Check and Assignment Across Dissimilar Sized Shift Registers

I'm looking to perform the cross-correlation* operation using an FPGA.
The secific part that I am currently struggling with is the multiplication piece. I want to multiply each 8-bit element of a nx8 shift register that uses excess or offset representation** against a nx1 shift register where I treat 0s as a -1 for the purposes of multiplication.
Now if I was doing that for a single element, I might do something like this for the operation:
input [7:0] dataIn;
input refIn;
output [7:0] dataOut;
wire [7:0] dataOut;
wire [7:0] invertedData;
assign invertedData = 8'd0 - dataIn;
assign dataOut <= refIn ? dataIn : invertedData;
What I'm wondering is how do I scale this to 4, 8, n elements?
My first though was to use a for loop like this:
for(loop=0; loop < n; loop = loop+1)
begin
assign invertedData[loop*8+7:loop*8] = 8'd0 - dataIn[loop*8+7:n*8];
assign dataOut[loop*8+7:loop*8] <= refIn[loop] ? dataIn[loop*8+7:loop*8] : invertedData[loop*8+7:loop*8];
end
This doesn't compile, but that's more or less the idea, and I can't seem to find the right syntax to do what I want.
https://en.wikipedia.org/wiki/Cross-correlation
** http://www.cs.auckland.ac.nz/~patrice/210-2006/210%20LN04_2.pdf
for(loop=0; loop < n; loop = loop+1)
begin
assign invertedData[n*8+7:n*8] = 8'd0 - dataIn[n*8+7:n*8];
assign dataOut[n*8+7:n*8] <= refIn[n] ? dataIn[n*8+7:n*8] : invertedData[n*8+7:n*8];
end
There's a few issues with this, but I think you can make this work.
You can't have 'assign' statements in a for loop. A for loop is meant to be used inside a begin/end block, so you need to change invertedData/dataOut from wire type to reg type, and remove the assign statements.
You generally can't have variable part-selects, unless you use the special constant-width selection operator (verilog-2001 support required). That would look like this: dataIn[n*8 +:8], which means: select 8 bits starting from n*8.
I don't know about your algorithm, but it looks like loop/n are backwards in your statement. You should be incrementing n, not loop variable (or else all statements will be operating on the same part-select).
So considering those points I believe this should compile for you:
always #* begin
for(n=0; n< max_loops ; n=n+1)
begin
invertedData[n*8 +:8] = 8'd0 - dataIn[n*8 +:8];
dataOut[n*8 +:8] <= refIn[n] ? dataIn[n*8 +:8] : invertedData[n*8 +:8];
end
end

Resources