How to make this expressions dynamic? - system-verilog

I'm trying to make the following expression dynamic with respect to size:
localparam MAX_ALLOWED_RD = 32'b1 << WIDTH_min;
The problem here is that if WIDTH_min becomes 32, the param becomes 0. What I'm trying to replace 32`b1 with something similar to "sizeof (WIDTH_min)"
How do I write this in SystemVerilog?
I have tried the following but get "'A_SIZE' is not a constant"
logic [WIDTH_min : 0] A_SIZE = 'b1;
localparam MAX_ALLOWED_RD = A_SIZE << WIDTH_min ;

The problem here is that the localparam is, by default, an integer, so its width is 32 bit [31:0].
So when you do this assignment:
localparam MAX_ALLOWED_RD = 32'b1 << WIDTH_min;
you would need 33 bits to assign that.
You could solve this by using the width as parameter:
localparam WIDTH_min = 33;
localparam [WIDTH_min:0] MAX_ALLOWED_RD = 32'b1 << WIDTH_min;
A_SIZE must be a parameter or localparam, not logic array.

I was able to achieve it by doing the following:
localparam [WIDTH_min : 0] WIDTH_min_size = '1;
localparam MAX_ALLOWED_RD = WIDTH_min_size << ID_WIDTH_min ;
(I probably should have framed the question better.)

Related

How do I vary the lower index of a variable assignment?

I want to make an assignment to a variable with a variable lower index. This is what I want to do:
int i;
logic [63:0] data;
i = someCalculatedNumber;
data[63:(i*8)] = 'h0;
I know this won't compile. What is the best method to make this assignment?
If you are looking to zero-out the LSBs, then this should do it for you
data &= '1 << i*8;
or more readable
data = data & ('1 << i*8);
And if that's not exactly what you need, you can still use '1 << i*8 or its complement as a mask to select the portion of data you want to modify.
One way is to use a for loop:
module tb;
int i;
logic [63:0] data;
initial begin
data = '1;
$displayh(data);
i = 7;
for (int j=63; j>=(i*8); j--) data[j] = 0;
$displayh(data);
i = 2;
for (int j=63; j>=(i*8); j--) data[j] = 0;
$displayh(data);
end
endmodule
Output:
ffffffffffffffff
00ffffffffffffff
000000000000ffff
You can wrap the code in a function.

System Verilog Generate - Unable to access local busses in previous loops using $size

enter image description here
I am trying to implement a OR tree using specific cell type CKOR2 in stages.
The stage is in a generate loop. I need to access the previous loops output bus width in the current loop to determine the width and define the output bus of the current stage.
I get errors on the line using $size
module test ( A, o );
parameter WIDTH = 9 ;
input [WIDTH-1:0] A;
output o;
localparam NUM_OR_STAGES = $clog2(WIDTH) ;
genvar i;
for (i=0; i < NUM_OR_STAGES; i=i+1) begin: OR
localparam j=i-1;
if ( i == 0 ) begin
localparam width = WIDTH;
wire [WIDTH-1:0] stgout;
assign stgout = A;
end
else begin
localparam width = $size( OR[i-1].stgout ) ;
localparam width_div2 = width/2;
localparam offset = ( width % 2);
wire [width_div2-1:0] stgo;
wire [width_div2+offset-1:0] stgout;
CKOR2 u_ckor[width_div2-1:0] ( .o(stgo), .i0(OR[i-1].stgout[width-1:width-width_div2]), .i1(OR[i-1].stgout[width-width_div2-1:width-2*width_div2]));
if ( offset )
assign stgout = { stgo,OR[i-1].stgout[0] };
else
assign stgout = stgo;
end
end
assign o = OR[NUM_OR_STAGES -1].stgout;
endmodule
Your problem is stgout[0] is declared inside an unnamed begin/end block, and you can't access it from outside the block. This is also a problem for the CKOR2 port connections. Naming the blocks would not solve your problem because you would have to switch between referencing the i==0 branch when i is 1, and the other branch when i!=1. Better to move the declarations outside the if/else branches. I didn't test the math, but this should get you close:
module test ( A, o );
parameter WIDTH = 9 ;
input [WIDTH-1:0] A;
output o;
localparam NUM_OR_STAGES = $clog2(WIDTH) ;
genvar i;
for (i=0; i < NUM_OR_STAGES; i=i+1) begin: OR
localparam width = WIDTH*2/(i+1);
localparam width_div2 = width/2;
localparam offset = ( width % 2);
wire [width_div2+offset-1:0] stgout;
if ( i == 0 ) begin
assign stgout = A;
end else begin
wire [width_div2-1:0] stgo;
CKOR2 u_ckor[width_div2-1:0] ( .o(stgo), .i0(OR[i-1].stgout[width-1:width-width_div2]), .i1(OR[i-1].stgout[width-width_div2-1:width-2*width_div2]));
if ( offset )
assign stgout = { stgo,OR[i-1].stgout[0] };
else
assign stgout = stgo;
end
end
assign o = OR[NUM_OR_STAGES -1].stgout;
endmodule

Parameterize parameters?

I would like to parameterize localparam parameters.
My module definition:
module native #(
parameter SIM_ONLY = 0,
parameter FREQ = 500
)(
...
);
I have lots of instantiations using the same localparam parameter A.
if (FREQ == 550) begin
localparam A = 987;
end else begin
localparam A = 122;
end
AA #(
.A_VALUE (A),
) AA_inst (
...
);
But that isn't allowed in the specification, is there a different proper way to do it?
/!\ The A value is a magic number, not something that can be calculated from FREQ.
I've tried:
if (FREQ == 550) begin
shortreal A = 987;
end else begin
shortreal A = 122;
end
but I get The expression for a parameter actual associated with the parameter name... must be constant.
Use the conditional operator ?:
localparam A = (FREQ==550) 987 : 122;
You can also put more complicated expressions into a constant function
localparam A = some_function(FREQ);
function int some_function(int F);
case(F)
550: return 987;
123: return 456;
default: return 122;
endcase
endfunction

CRC-32 algorithm from HDL to software

I implemented a Galois Linear-Feedback Shift-Regiser in Verilog (and also in MATLAB, mainly to emulate the HDL design). It's been working great, and as of know I use MATLAB to calculate CRC-32 fields, and then include them in my HDL simulations to verify a data packet has arrived correctly (padding data with CRC-32), which produces good results.
The thing is I want to be able to calculate the CRC-32 I've implemented in software, because I'll be using a Raspberry Pi to input data through GPIO in my FPGA, and I haven't been able to do so. I've tried this online calculator, using the same parameters, but never get to yield the same result.
This is the MATLAB code I use to calculate my CRC-32:
N = 74*16;
data = [round(rand(1,N)) zeros(1,32)];
lfsr = ones(1,32);
next_lfsr = zeros(1,32);
for i = 1:length(data)
next_lfsr(1) = lfsr(2);
next_lfsr(2) = lfsr(3);
next_lfsr(3) = lfsr(4);
next_lfsr(4) = lfsr(5);
next_lfsr(5) = lfsr(6);
next_lfsr(6) = xor(lfsr(7),lfsr(1));
next_lfsr(7) = lfsr(8);
next_lfsr(8) = lfsr(9);
next_lfsr(9) = xor(lfsr(10),lfsr(1));
next_lfsr(10) = xor(lfsr(11),lfsr(1));
next_lfsr(11) = lfsr(12);
next_lfsr(12) = lfsr(13);
next_lfsr(13) = lfsr(14);
next_lfsr(14) = lfsr(15);
next_lfsr(15) = lfsr(16);
next_lfsr(16) = xor(lfsr(17), lfsr(1));
next_lfsr(17) = lfsr(18);
next_lfsr(18) = lfsr(19);
next_lfsr(19) = lfsr(20);
next_lfsr(20) = xor(lfsr(21),lfsr(1));
next_lfsr(21) = xor(lfsr(22),lfsr(1));
next_lfsr(22) = xor(lfsr(23),lfsr(1));
next_lfsr(23) = lfsr(24);
next_lfsr(24) = xor(lfsr(25), lfsr(1));
next_lfsr(25) = xor(lfsr(26), lfsr(1));
next_lfsr(26) = lfsr(27);
next_lfsr(27) = xor(lfsr(28), lfsr(1));
next_lfsr(28) = xor(lfsr(29), lfsr(1));
next_lfsr(29) = lfsr(30);
next_lfsr(30) = xor(lfsr(31), lfsr(1));
next_lfsr(31) = xor(lfsr(32), lfsr(1));
next_lfsr(32) = xor(data2(i), lfsr(1));
lfsr = next_lfsr;
end
crc32 = lfsr;
See I use a 32-zeroes padding to calculate the CRC-32 in the first place (whatever's left in the LFSR at the end is my CRC-32, and if I do the same replacing the zeroes with this CRC-32, my LFSR becomes empty at the end too, which means the verification passed).
The polynomial I'm using is the standard for CRC-32: 04C11DB7. See also that the order seems to be reversed, but that's just because it's mirrored to have the input in the MSB. The results of using this representation and a mirrored one are the same when the input is the same, only the result will be also mirrored.
Any ideas would be of great help.
Thanks in advance
Your CRC is not a CRC. The last 32 bits fed in don't actually participate in the calculation, other than being exclusive-or'ed into the result. That is, if you replace the last 32 bits of data with zeros, do your calculation, and then exclusive-or the last 32 bits of data with the resulting "crc32", then you will get the same result.
So you will never get it to match another CRC calculation, since it isn't a CRC.
This code in C replicates your function, where the data bits come from the series of n bytes at p, least significant bit first, and the result is a 32-bit value:
unsigned long notacrc(void const *p, unsigned n) {
unsigned char const *dat = p;
unsigned long reg = 0xffffffff;
while (n) {
for (unsigned k = 0; k < 8; k++)
reg = reg & 1 ? (reg >> 1) ^ 0xedb88320 : reg >> 1;
reg ^= (unsigned long)*dat++ << 24;
n--;
}
return reg;
}
You can immediately see that the last byte of data is simply exclusive-or'ed with the final register value. Less obvious is that the last four bytes are just exclusive-or'ed. This exactly equivalent version makes that evident:
unsigned long notacrc_xor(void const *p, unsigned n) {
unsigned char const *dat = p;
// initial register values
unsigned long const init[] = {
0xffffffff, 0x2dfd1072, 0xbe26ed00, 0x00be26ed, 0xdebb20e3};
unsigned xor = n > 3 ? 4 : n; // number of bytes merely xor'ed
unsigned long reg = init[xor];
while (n > xor) {
reg ^= *dat++;
for (unsigned k = 0; k < 8; k++)
reg = reg & 1 ? (reg >> 1) ^ 0xedb88320 : reg >> 1;
n--;
}
switch (n) {
case 4:
reg ^= *dat++;
case 3:
reg ^= (unsigned long)*dat++ << 8;
case 2:
reg ^= (unsigned long)*dat++ << 16;
case 1:
reg ^= (unsigned long)*dat++ << 24;
}
return reg;
}
There you can see that the last four bytes of the message, or all of the message if it is three or fewer bytes, is exclusive-or'ed with the final register value at the end.
An actual CRC must use all of the input data bits in determining when to exclusive-or the polynomial with the register. The inner part of that last function is what a CRC implementation looks like (though more efficient versions make use of pre-computed tables to process a byte or more at a time). Here is a function that computes an actual CRC:
unsigned long crc32_jam(void const *p, unsigned n) {
unsigned char const *dat = p;
unsigned long reg = 0xffffffff;
while (n) {
reg ^= *dat++;
for (unsigned k = 0; k < 8; k++)
reg = reg & 1 ? (reg >> 1) ^ 0xedb88320 : reg >> 1;
n--;
}
return reg;
}
That one is called crc32_jam because it implements a particular CRC called "JAMCRC". That CRC is the closest to what you attempted to implement.
If you want to use a real CRC, you will need to update your Verilog implementation.

What does this line of code do? Const uint32_t goodguys = 0x1 << 0

Can someone tell me what is being done here:
Const uint32_t goodguys = 0x1 << 0
I'm assuming it is c++ and it is assigning a tag to a group but I have never seen this done. I am a self taught objective c guy and this just looks very foreign to me.
Well, if there are more lines that look like this that follow the one that you posted, then they could be bitmasks.
For example, if you have the following:
const uint32_t bit_0 = 0x1 << 0;
const uint32_t bit_1 = 0x1 << 1;
const uint32_t bit_2 = 0x1 << 2;
...
then you could use use the bitwise & operator with bit_0, bit_1, bit_2, ... and another number in order to see which bits in that other number are turned on.
const uint32_t num = 5;
...
bool bit_0_on = (num & bit_0) != 0;
bool bit_1_on = (num & bit_1) != 0;
bool bit_2_on = (num & bit_2) != 0;
...
So your 0x1 is simply a way to designate that goodguys is a bitmask, because the hexadecimal 0x designator shows that the author of the code is thinking specifically about bits, instead of decimal digits. And then the << 0 is used to change exactly what the bitmask is masking (you just change the 0 to a 1, 2, etc.).
Although base 10 is a normal way to write numbers in a program, sometimes you want to express the number in octal base or hex base. To write numbers in octal, precede the value with a 0. Thus, 023, really means 19 in base 10. To write numbers in hex, precede the value with a 0x or 0X. Thus, 0x23, really means 35 in base 10.
So
goodguys = 0x1;
really means the same as
goodguys = 1;
The bitwise shift operators shift their first operand left (<<) or right (>>) by the number of positions the second operand specifies. Look at the following two statements
goodguys = 0x1;
goodguys << 2;
The first statement is the same as goodguys = 1;
The second statement says that we should shift the bits to the left by 2 positions. So we end up with
goodguys = 0x100
which is the same as goodguys = 4;
Now you can express the two statements
goodguys = 0x1;
goodguys << 2;
as a single statement
goodguys = 0x1 << 2;
which is similar to what you have. But if you are unfamiliar with hex notation and bitwise shift operators it will look intimidating.
When const is used with a variable, it uses the following syntax:
const variable-name = value;
In this case, the const modifier allows you to assign an initial value to a variable that cannot later be changed by the program. For Instance
const int POWER_UPS = 4;
will assign 4 to variable POWER_UPS. But if you later try to overwrite this value like
POWER_UPS = 8;
you will get a compilation error.
Finally the uint32_t means 32-bit unsigned int type. You will use it when you want to make sure that your variable is 32 bits long and nothing else.