System Verilog : wire input for bits part indexing - arrays

I have the following code:
module rotate
(
input wire [5:0] index,// tells how many bits to rotate
input [31:0] a,
output [31:0] b
);
I want to implement this assign statement for left rotate:
assign b = {a[32-index-1 : 0], a[31: 32-index] ;
..
..
..
endmodule
The above assignment will not work since wire/logic signals are evaluated during simulation time. I am not able to use parameters.
I tried converting wire to integer and then do assignment, still its not working.
int i1 = index ;
assign assign b[i1] = a[i1] ; // this worked
assign b[i1-1 : 0] = a[i1-1 : 0] ; //not worked
I implemented using for loop inside always_comb but I want a simpler method like concatenation operation etc.
Please help with a suitable way.

I want to do a rotate operation using the concatenation operator and the rotate count will be specified by an input.
You were very close, especially with using two concatenated a's. All you have to do is use the +: operator:
wire [63:0] a_twice = {a,a};
assign b = a_twice[ index +: 32];
The +: operator gives you the bits from index to index+31:
3322222222221111111111 3322222222221111111111
1098765432109876543210987654321010987654321098765432109876543210
<------------- +32 ----------> index=21

Related

Concatenation of two arrays with specific range in one array in SystemVerilog

I was trying to store two specific spans of an array inside another array, but I get an error.
What I want to do:
I have [8-1:0]A as module input, and I wanna store :
logic [8-1:0]temp = {A[4:7],A[0:3]};
but, when I simulate my module in test bench, I get an error in modelSim:
error: Range of part-select into 'A' is reversed.
Ways I tried:
Convert logic to wire,
Use assign
I think the idea is problematic.
example :
A = 8'b11000101 -> I want temp to be -> temp=8'b00111010
->explain:
A[0]=1,A[1]=0,A[2]=1,A[3]=0,A[4]=0,A[5]=0,A[6]=1,A[7]=1.
A[4..7]=4'b0011,A[0..3]=4'b1010
`timescale 1ns/1ns
module examp(input [7:0]A,output [7:0]O);
logic [7:0]temp = {A[4:7],A[0:3]};
// I wanna temp be 8'b00111010.
assign O = temp;
endmodule
`timescale 1ns/1ns
module examp_tb();
logic [7:0]aa=8'b11000101;
wire [7:0]ww;
examp MUX_TB(.A(aa),.O(ww));
initial begin
#200 aa=8'b01100111;
#200 $stop;
end
endmodule
Note : In the example above, I have a compile error, but in the main question, I have simulation error.
The streaming operator can be used to reverse a group of bits. So you could do:
logic [8-1:0]temp = { {<<{A[7:4]}} , {<<{A[3:0]}} };
The streaming operator also takes a slice argument, which is used to preserve a grouping of bits before performing the bit reversal. The problem with what you want is you are trying to reverse the bits within the slice. You can accomplish this by nesting the streaming operators. This approach with be more useful when dealing with larger vectors
logic [7:0] temp1 = {<<{A}}; // A[0:7]
logic [7:0] temp2 = {<<4{temp1}}; // A[4:7],A[03];
or in a single line
logic [7:0] temp = {<<4{ {<<{A}} }};
One way to swap bits within a nibble is to use a function:
module examp (input [7:0] A, output [7:0] O);
assign O = {swap_nib(A[7:4]), swap_nib(A[3:0])};
function logic [3:0] swap_nib (logic [3:0] in);
swap_nib[3] = in[0];
swap_nib[2] = in[1];
swap_nib[1] = in[2];
swap_nib[0] = in[3];
endfunction
endmodule

Shifting array to left or right OCaml

I'm having some trouble around arrays in OCaml.
Namely, I want to just shift the elements to the right or left based on a value I pass.
Example: # let a = [|1;2;3;4;5|], # shift_array a 7;;- : int array array = [|4;5;1;2;3|]
I wrote the following code but I keep getting a syntax error where the second array is formed.
let shift_array arr x =
let size = Array.length arr in
let sec_arr = Array.make size 0 in
for i = 0 to size - 1 do
if i < x
then (sec_arr.(size - x + 1) <- arr.(i))
else (sec_arr.(i-x) <- arr.(i))
done;;
I'm just not 100% sure how to print out the new array.
EDIT: fixed it by adding in to the second and third line.
The problem now is that the function has type int array -> int -> unit and the one I'm trying to get is 'a array -> int -> 'a array. Is there some way to work around that ?
It should be let size = Array.length arr in, notice the in, which you're missing.
The let expression in OCaml has the form let <var> = <expr> in <body> and should not be (but commonly is) confused with the let definition that can occur only on the top-level (as an element of a module), which has form let <name> = <body>.
In your example, you have both, the top-level definition, let shift_array = <body> and two let expressions (though, you have used the wrong syntax for them.
EDIT:
Since OP edited the post, here is the corresponding edit.
You function doesn't return anything, it creates a new array, does the cycle, but doesn't return anything but the unit value (which is the value to which the for cycle evaluates). So you have to add one more line, that will contain the expression, to which the whole function will evaluate. Hint the sequencing operator ; is what you need, when you have expression x;y;z the computer evaluates x, then y, and finally z and the value of the whole expression of x;y;z is the value of z.

Systemverilog localparam array with configurable size

I want to create and define a localparam array in SystemVerilog. The size of the array should be configurable, and the value of each localparam array cell calculated based on its location. Essentially this code:
localparam [7:0] [ADDR_BITS-1:0] ADDR_OFFSET = '{
7*PAGE_SIZE,
6*PAGE_SIZE,
5*PAGE_SIZE,
4*PAGE_SIZE,
3*PAGE_SIZE,
2*PAGE_SIZE,
1*PAGE_SIZE,
0
};
but where the first '7' is replaced with a parameter, and where the parameter initialization is extended to the generic case. So I need a way to loop from 0 to (N-1) and set ADDR_OFFSET(loop) = loop*PAGE_SIZE.
The "obvious" option in SystemVerilog would be generate, but I read that placing a parameter definition inside a generate block generates a new local parameter relative to the hierarchical scope within the generate block (source).
Any suggestions?
For background reference: I need to calculate an actual address based on a base address and a number. The calculation is simple:
real_address = base_address + number*PAGE_SIZE
However, I don't want to have the "*" in my code since I am afraid the synt tool will generate a multiplier, that it will then try to simplify since PAGE_SIZE is a constant value. I am guessing that this can lead to more logic than if I try to do all calculations when generating the localparam array, since this for sure will not give any multiplier in logic.
So with the above localparam definition, I perform the desired address calculation like this:
function [ADDR_BITS-1:0] addr_calc;
input [ADDR_BITS-1:0] base_addr;
input [NBITS-1:0] num;
addr_calc = base_addr + ADDR_OFFSET[num];
endfunction
I think perhaps I found a solution. Wouldn't I essentially accomplish the same by not defining a localparam array, but rather performing the address calculation inside a loop? Since systemverilog sees the loop variable as "constant" (when it comes to generating logic) that seems to accomplish the same? Like this (inside the function I wrote above):
for (int loop1 = 0; loop1 < MAXNUM ; loop1++) begin
if (num == loop1) begin
addr_offset = CSP_PAGE_SIZE*loop1;
end
addr_calc = base_addr + addr_offset;
end
You can set your localparam with the return value of a function.
localparam bit [7:0] [ADDR_BITS-1:0] ADDR_OFFSET = ADDR_CALC();
function bit [7:0] [ADDR_BITS-1:0] ADDR_CALC();
for(int ii=0;ii<$size(ADDR_CALC,1); ii++)
ADDR_CALC[ii] = ii * PAGE_SIZE;
endfunction

how to check in matlab if a 3D array has at least one non zero element?

I tried to check if a 3D array is not all zeros using the next code:
notAll_n0_GreaterThan_ni=1;
while notAll_n0_GreaterThan_ni
notAll_n0_GreaterThan_ni=0;
mask=(n0<ni);
numDimensions=ndims(mask);
for dim_ind=1:numDimensions
if any(mask,dim_ind)
notAll_n0_GreaterThan_ni=1;
break;
end
end
if notAll_n0_GreaterThan_ni
n0(mask)=n0(mask)+1;
end
end
It seems I have error in the code because at the end I get for example: n_0(11,3,69)=21 while ni(11,3,69)=21.1556.
I can't find the error. I'll appreciate if someone shows me where I'm wrong and also if there is a simpler way to check existence of nonzero elements in a 3D array.
Let x denote an n-dimensional array. To check if it contains at least one non-zero element, just use
any(x(:))
For example:
>> x = zeros(2,3,4);
>> any(x(:))
ans =
0
>> x(1,2,2) = 5;
>> any(x(:))
ans =
1
Other, more exotic possibilities include:
sum(abs(x(:)))>0
and
nnz(x)>0
This is what you looking for
B = any(your_Array_name_here(:) ==0); no need for loops
the (:) turns the elements of your_Array into a single column vector, so you can use this type of statement on an array of any size
I 've tested this and it works
A = rand(3,7,5) * 5;
B = any(A(:) ==0);

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