Bit slicing with variable width in SystemVerilog - system-verilog

I am trying to access certain sections of an array using the +: operator however getting the infamous [variable] is not a constant error. The only problem is, the width I would like the get from the array is changing as well.
This is the loop I have:
logic [N-1:0] a;
logic [2**N-2:0] b;
for (i = 0; i < N; i++)
a[i] = b[(2**i)-1 +: 2**i] == {(2**i){1'b1}};
In other words, if N = 4, I want this loop to do this:
a[0] = b[0:0] == 1'b1;
a[1] = b[2:1] == 2'b11;
a[2] = b[6:3] == 4'b1111;
a[3] = b[14:7] == 8'b11111111;
Logically, I'm pretty certain that the loop I provided works however SystemVerilog doesn't allow non-constants to be used for setting the width (after the a:).
How can I utilize the +: operator when my starting index and width are both dependent on a non-constant variable? or is there another way of doing this considering that N can be a large number.
Thanks!
EDIT:
This can be done with shifts, here is a working code:
for (i = 0; i < N; i++)
a[i] <= ((b >> (2**i)-1) << ((2**N) - (2**i) - 1)) ==
{(2**N-1){1'b1}} << ((2**N) - (2**i) - 1);

You cannot use +: with variable widths. It is actually just a short-hand for shifts and masks. For example, something like the following should work in your case:
logic [N-1:0] a;
logic [2**N-2:0] b;
always_comb begin
for (int i = 0; i < N; i++) begin
logic [2**N-2:0] tmpb, tmp1;
tmpb = b >> ((2**i)+1);
tmp1 = ((2**N)'(1) << (2**i)) - 1;
a[i] = (tmpb & tmp1) == 0;
end
end
you just need to figure out exact numbers of shifts and widths.

You can use a combination of '+:` operator with a mask
parameter N = 8; localparam N2 = 2**(N-1);
logic [N-1:0] a;
logic [2**N-1:0] b;
initial begin
b ={8'b000001,4'b1111,2'b01,1'b1};
for (int i = 0; i < N; i++)
a[i] = (b[(2**i)-1 +: N2] | ~N2'((1 << 2**i)- 1)) == '1;
$displayb(a,,b);
end

You can use +: provided that the right hand side is a constant or genvar.
logic [N-1:0] a;
logic [2**N-2:0] b;
for (genvar i = 0; i < N; i++) begin : gen_a
assign a[i] = b[(2**i)-1 +: 2**i] == {(2**i){1'b1}};
end
Note that this for-loop is a generate-for-loop which is not within a procedural block (ie begin-end)

Related

system verilog: for loop index variable issue

`timescale 1ns / 1ps
module param_right_shifter
# (parameter N = 3)
(
input logic [$clog2(N)-1:0] a, // input
input logic [N-1:0] amt, // shift bits
output logic [$clog2(N)-1:0] y // output
);
logic [$clog2(N)-1:0][N:0] s;
logic [$clog2(N)-1:0] placeholder = a;
localparam bit_num = $clog2(N)-1;
always_comb
begin
for(int i = 0; i < N; i++)
begin
if (i == 0)
begin
s[i] = amt[i] ? {placeholder[i], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
else
begin
s[i] = amt[i] ? {placeholder[$clog2(N)-1:0], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
end
end
endmodule
I am having an issue with referencing the 'i' variable. It says that 'range must be bounded by constant expressions'. I am unsure of how to resolve.
Try below. I am assuming N is will have a constant value throughout the simulation.
Please note that placeholder is driven by all bits of s so here placeholder will settle to s[N-1].
genvar i;
generate
for(i = 0; i < N; i++)
begin
if (i == 0)
begin
always_comb
begin
s[i] = amt[i] ? {placeholder[i], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
end
else
begin
always_comb
begin
s[i] = amt[i] ? {placeholder[$clog2(N)-1:0], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
end
end
endgenerate

How to generate a synthesizable pseudo random generator from 1 to 52 System Verilog

Could someone explain how to create a pseudo number generator that has a range of 1 to 51 and can have its value placed within something like the for loop. This has to be in System Verilog and synthesizable. I have read about some CRC and LFSRs but was not quite sure how to modify them to fit it within the specified values I needed (1-52) and how to fit it within a for loop as most examples took up an entire module.
Thank you for your time.
initial begin
for(int i = 0; i < 52; i++) begin
int j = // insert PSEUDO RANDOM NUM GEN 0 to 51
if(array[j] == 0)begin
i = i-1;
continue;
end
else
array2[i] = array[j];
array[j] = 0;
end
end
(array and array2 both have 52 values of bit size 4)
I don't know what is your application, but what you could do is to generate numbers in the modular ring mod 53 (53 is a prime number). Since you did not mention any other requirement I will take the simplest generator I could imagine, that can be performed without multiplications and will generate numbers, 1 <= n < 52.
function [5:0] next_item(input logic [5:0] v);
if(v < 26) begin
next_item = (v << 1); // 2 * v % 53 = 2 * v
end
else if(v > 26) begin
// (2 * v) % 53 = (2 * v - 52 - 1) % 53 = 2 * (v - 26) - 1
next_item = (((v - 26) << 2) - 1);
end
else begin
// v = 26, you want to exclude 2 * v % 53 = 52, so we skip it
// by applying the next item again, and it will be
next_item = 51;
end
endfunction
And you could use it like this
parameter SEED = 20; // any number 1 <= N < 52 you like
initial begin
int j = SEED;
for(int i = 0; i < 52; i++) begin
if(array[j-1] == 0)begin
i = i-1;
continue;
end
else begin
array2[i] = array[k];
end
j = next_item(j);
end

How to cope with the error of the following piece of system verilog code?

schematic
I would like to write system verilog code to implement this schematic (using 3 2:4 decoder and 64 3-input and gate to achieve a 6:64 decoder), and the following is my piece of code:
module Ex4( input logic [5:0] D,
output logic [63:0] y
);
genvar i;
genvar j;
genvar k;
integer n = 0;
logic [3:0] y1, y2, y3;
dec2 d1(D[1:0], y1);
dec2 d2(D[3:2], y2);
dec2 d3(D[5:4], y3);
generate
begin
for(i = 0; i < 3; i = i + 1) begin:flp1
for (j = 0; j < 3; j = j + 1) begin:flp2
for(k = 0; k < 3; k = k + 1) begin:flp3
and3_new a_n(y1[i], y2[j], y3[k], y[n]);
n=n+1; // error message comes from this line
end
end
end
end
endgenerate
endmodule
Note: "dec2" and "and3_new" are two modules written in advance with no problems
However, I got the following error during compilation, can anybody give me some hint? Thank you.
Error (10170): Verilog HDL syntax error at Ex4.sv(22) near text: "=";
expecting ".", or "(". Check for and fix any syntax errors that appear
immediately before or at the specified keyword. The Intel FPGA
Knowledge Database contains many articles with specific details on
how to resolve this error. Visit the Knowledge Database at
https://www.altera.com/support/support-resources/knowledge-
base/search.html and search for this specific error message number.
You can't put a procedural assignment statement in that position. Instead of [n], use [i*16+j*4+k]. You can also do
module Ex4( input logic [5:0] D,
output logic [63:0] y
);
logic [3:0] y1, y2, y3;
dec2 d1(D[1:0], y1);
dec2 d2(D[3:2], y2);
dec2 d3(D[5:4], y3);
for(genvar i = 0; i < 4; i++) begin:flp1
for (genvar j = 0; j < 4; j++) begin:flp2
for(genvar k = 0; k < 4; k = k + 1) begin:flp3
parameter n = i*16+j*4+k;
and3_new a_n(y1[i], y2[j], y3[k], y[n]);
end :flp3
end : flp2
end : flp1
endmodule

where is cula "culaSgesv" answer for X?

I just downloaded Cula and I want to use it's implemented functions for solving system of linear equation I looked into Examples Directory and I saw below code but it's very confusing when they want to obtain X solution of A*X=B they just copy B in X and since A is identity diagonal matrix so the answer IS, "B" and in this line of code nothing happens
status = culaSgesv(N, NRHS, A, N, IPIV, X, N);
(changing X to B didn't help!)
would you please tell me whats going on? Please tell me how can I get the answer "X" from this?
if anyone need any further information please just tell me.
#ifdef CULA_PREMIUM
void culaDoubleExample()
{
#ifdef NDEBUG
int N = 4096;
#else
int N = 780;
#endif
int NRHS = 1;
int i;
culaStatus status;
culaDouble* A = NULL;
culaDouble* B = NULL;
culaDouble* X = NULL;
culaInt* IPIV = NULL;
culaDouble one = 1.0;
culaDouble thresh = 1e-6;
culaDouble diff;
printf("-------------------\n");
printf(" DGESV\n");
printf("-------------------\n");
printf("Allocating Matrices\n");
A = (culaDouble*)malloc(N*N*sizeof(culaDouble));
B = (culaDouble*)malloc(N*sizeof(culaDouble));
X = (culaDouble*)malloc(N*sizeof(culaDouble));
IPIV = (culaInt*)malloc(N*sizeof(culaInt));
if(!A || !B || !IPIV)
exit(EXIT_FAILURE);
printf("Initializing CULA\n");
status = culaInitialize();
checkStatus(status);
// Set A to the identity matrix
memset(A, 0, N*N*sizeof(culaDouble));
for(i = 0; i < N; ++i)
A[i*N+i] = one;
// Set B to a random matrix (see note at top)
for(i = 0; i < N; ++i)
B[i] = (culaDouble)rand();
memcpy(X, B, N*sizeof(culaDouble));
memset(IPIV, 0, N*sizeof(culaInt));
printf("Calling culaDgesv\n");
DWORD dw1 = GetTickCount();
status = culaDgesv(N, NRHS, A, N, IPIV, X, N);
DWORD dw2 = GetTickCount();
cout<<"Time difference is "<<(dw2-dw1)<<" milliSeconds"<<endl;
if(status == culaInsufficientComputeCapability)
{
printf("No Double precision support available, skipping example\n");
free(A);
free(B);
free(IPIV);
culaShutdown();
return;
}
checkStatus(status);
printf("Verifying Result\n");
for(i = 0; i < N; ++i)
{
diff = X[i] - B[i];
if(diff < 0.0)
diff = -diff;
if(diff > thresh)
printf("Result check failed: i=%d X[i]=%f B[i]=%f", i, X[i], B[i]);
}
printf("Shutting down CULA\n\n");
culaShutdown();
free(A);
free(B);
free(IPIV);
}
You mention Sgesv but the sample code you have shown is for Dgesv. Nevertheless, the answer is the same.
According to the Netlib LAPACK reference, the B matrix of RHS vectors is passed to the function as the 6th parameter:
[in,out] B
B is DOUBLE PRECISION array, dimension (LDB,NRHS)
On entry, the N-by-NRHS matrix of right hand side matrix B.
On exit, if INFO = 0, the N-by-NRHS solution matrix X.
And the X matrix is returned in the same parameter location. So B when passed to the function contains the NxNRHS right-hand-side vectors, and the same parameter returns the X result.
In the code you have shown, they are actually passing a variable called X and after the result is returned (in the same variable X) they are comparing it against a variable named B which is perhaps confusing, but the concept is the same.
Since the A matrix in the example is the identity matrix, the correct solution of Ax = b is x=b
For the general case, you should pass your B matrix of RHS vectors in the 6th parameter location. Upon completion of the function, the result (X) will be returned in the same parameter.

loop unrolling for matrix multiplication

I need to make a good implementation for matrix multiplication better than the naive method
here is the methods i used :
1- removed false dependencies which made the performance a lot better
2- used a recursive approach
and then there is something i need to try loop unrolling. The thing is each time i used it , it makes the performance worst i can't find an explanation for it
i need help here is the code
for (i = 0; i < M; i++)
for (j = 0; j < N; j++) {
double sum = 0;
#pragma unroll(5)
for (k = 0; k < K; k++)
{
sum += A[i + k*LDA] * B[k + j*LDB];
}
C[i + j*LDC] = sum ;
}