Casting from int to parameterized-width logic - verilog

Given the parameters
parameter int eC,
parameter int cntW = ...
I have the following assignment:
logic [cntW-1:0] count;
logic [cntW-1:0] front;
logic [cntW-1:0] back;
assign count = condition ? front : back+eC+1 - front;
where back+eC+1 - front is promoted to a 32 bit int, which is wider than cntW.
How can I explicitly cast int to the variable width cntW to suppress the warning that comes from the implicit conversion?
The warning is
Continuous assignment width mismatch
5 bits (lhs) versus 32 bits (rhs).
Source info: assign count = ((back >= front) ? (back - front) : (((back +
eC) + 1) - front));

First of all, the bare number 1 is implicitly a 32-bit signed decimal value. Operands in arithmetic expression get extended to the width of the largest operand before applying the operators. You can use 1'b1 which is an explicit 1-bit value. Also declare eC with the same width as the other variables
typedef logic [cntW-1:0] cnt_t;
parameter cnt_t eC;
cnt_t count;
cnt_t front;
cnt_t back;
assign count = condition ? front : back+eC+1'b1 - front;
Another thing you do is use a cast
assign count = condition ? front : cntW'(back+eC+1) - front;

Related

SystemVerilog Array of Bits to Int Casting

I have the following SystemVerilog variable:
bit [5:0] my_bits = 6'h3E; // my_bits == 6'd62
I want to take the bit-wise inverse of it and then get that result into an int variable, treating the underlying bits as unsigned, so first I did this:
bit [5:0] my_bits_inv = ~my_bits; // my_bits_inv = 6'b00_0001
int my_int = int'(my_bits_inv); // my_int = 1
That gave me what I wanted. However, if I combine the inversion and casting into a single step, I get -63:
int my_int2 = int'(~my_bits); // my_int2 = -63 ???
Presumably it is treating my_bits as 32 bits, then taking the inverse of that to give int'(~32'h0000_003E) = int'(32'hFFFF_FFC1) = -63.
Can someone explain why this happens? Does it have to do with self-determination rules?
Your diagnosis is correct. This is explained in IEEE Std 1800-2017, section 11.6.1 Rules for expression bit lengths. In your case, casting with int' expands my_bits to match the width of int (32) before the bitwise inversion.
Consider also:
$displayb(~my_bits);
$displayb(int'(~my_bits));
Outputs:
000001
11111111111111111111111111000001

How do I generate parameters dependent onf previous parameters in systemverilog

I recently switched from VHDL to SystemVerilog and I am converting some of my codes. I want to generate an array of local parameters based on 3 parameters SZ,L,max.
module test #(
parameter int SZ = 1024,
parameter int L = 35,
parameter int MAX = 4
)()
//...
localparam int n[MAX:0] = ;//...
for(genvar i = 0; i < max; i++) begin: gg
//n[i] and n[i+1] will be used here
//There is a second generate loop here that uses n[i+1] and therefore n[i+1] has to be parameter.
end
I tried using a function to generate localparams but I get an error that element assignment in function is not constant. I never had this issue in VHDL.
The only other option I can think of is to create the params inside the for generate but how would I reference the initial value? Is there any other solution?
The simulator I am using is Verilator but I also want the design to work in Xilinx Vivado.
Edit: I do not want to generate the parameters from an external script because I lose the ability to use Vivado's ability to run multiple synthesis/implementation in the same project with different parameters. That was what I used to do in VHDL.
You can use a function to initialize a parameter, you just have to have the output of the entire array as the result of the function. To do that, you need a typedef
typedef int array_type[MAX:0];
function array_type f();
f[0]=SZ;
for(int i=0;i<MAX;i++)
f[i+1]=f[i]-((2*i)+1)*L)/2;
endfunction
localparam array_type n = f();
I got it working by using packed array of 32-bits. Verilator doesn't support unpacked int with constants. Packed int is also not supported so I had to change the type to pack of 32-bits.
typedef [MAX:0][31:0] array_type;
function array_type f();
f[0]=SZ;
for(int i=0;i<MAX;i++)
f[i+1]=f[i]-((2*i)+1)*L)/2;
endfunction
localparam array_type n = f();

JPEG Huffman "DECODE" Procedure

The JPEG standard defines the DECODE procedure like below. I'm confused about a few parts.
CODE > MAXCODE(I), if this is true then it enters in a loop and apply left shift (<<) to code. AFAIK, if we apply left shift on non-zero number, the number will be larger then previous. In this figure it applies SLL (shift left logical operation), would't CODE always be greater than MAXCODE?
Probably I coundn't read the figure correctly
What does + NEXTBIT mean? For instance if CODE bits are 10101 and NEXTBIT is 00000001 then will result be 101011 (like string appending), am I right?
Does HUFFVAL list is same as defined in DHT marker (Vi,j values). Do I need to build extra lookup table or something? Because it seems the procedure used that list directly
Thanks for clarifications
EDIT:
My DECODE code (C):
uint8_t
jpg_decode(ImScan * __restrict scan,
ImHuffTbl * __restrict huff) {
int32_t i, j, code;
i = 1;
code = jpg_nextbit(scan);
/* TODO: infinite loop ? */
while (code > huff->maxcode[i]) {
i++;
code = (code << 1) | jpg_nextbit(scan);
}
j = huff->valptr[i];
j = code + huff->delta[i]; /* delta = j - mincode[i] */
return huff->huffval[j];
}
It's not MAXCODE, it's MAXCODE(I), which is a different value each time I is incremented.
+NEXTBIT means literally adding the next bit from the input, which is a 0 or a 1. (NEXTBIT is not 00000001. It is only one bit.)
Once you've found the length of the current code, you get the Vi,j indexing into HUFFVAL decoding table.

How to do explicit resize?

Is there a way to do explict resize to LEN of an expression?
The reason I want this, is to make the code explicitly describe the intention, and also to avoid the warnings for implicit resize that some tools generate.
The code below works in some tools, but fails in other:
localparam EXPR = 12;
localparam LEN = 7;
assign res = LEN'(EXPR);
Based on reading the Verilog-2001 standard, it looks like lengty by LEN'... can only be used for literals, e.g. 7'd12, and not for general expressions.
So, is there a way to do explicit resize of general expressions in Verilog-2001?
The syntax you are looking for is already in SystemVerilog. You need to make sure you turn it on or use the proper .sv file extension so your tools recognize it.
assign res = LEN'(EXPR);
However, there is no way to dynamically calculate the length of a type - it needs to be a constant expression.
But you can dynamically apply a mask that truncates your value to desired length
assign res = EXPR & ((64'b10<<LEN)-1);
How about
localparam LEN = 7;
localparam [LEN-1:0] EXPR = 12;
assign res = EXPR;
or if you need to use EXPR for some other purpose
localparam LEN = 7;
localparam [LEN-1:0] EXPR7 = 12;
localparam EXPR = 12;
assign res = EXPR7
System Verilog has a $bits() system call. It returns the number of bits required for an expression. Thus:
wire [11:0] res;
$bits(res) // <= will return 12
You have to check if you simulator/compiler supports it. Also I don't know if you can use it as:
$bits(res)'d7
The only thing I should warn off is not to sacrifice your code readability to suppress superfluous warnings. Good readability prevents more errors than anything else.
I have a [systemverilog] macro I use for resizing:
// Drive a signal with a constant, automatically resize constant to signal value
`define assign_const(SIGNAL,VALUE) assign SIGNAL = ($bits(SIGNAL))'(VALUE)
The ($bits(SIGNAL))'(VALUE) is the critical part. It uses $bits to determine the signal length and recasts the value accordingly.

C++ size_t and double type calculation

I am not familiar with C++ and current face a problem about size_t calculation with double type.
I provide a part of source code as below. The variable "storage" is define as double and "pos" as size_t type. How come they can be calculate together? I review the value of "pos and it shows value like 0, 1, 2 and so on. Moreover, in the case of double* result = storage + pos, it shows 108 + 2 comes out the result x 117.
Further, sometimes 108 + 0 comes out the result x zero. what the condition lead to the result?
How do I know the exact value of size_t before the calculation?
Any advice & suggestion is appreciated.
double* getPosValue(size_t pos, IdentifierType *idRule, unsigned int *errorNumber, bool *found)
{
double * storage = *from other function with value 108*
double* result = storage + pos;
uint16_t* stat = status + pos; }
The size of a variable (or type) can be obtained with:
sizeof(variableNameOrTypeName)
If you're after the address of a given array element such as variableName[42], it's simply:
&(variableName[42])
with no explicit mucking about with pointers.
If you want to manipulate the actual double value when you only have a pointer to it, you need to dereference the pointer. For example:
double xyzzy = 108.0; // this is the VALUE.
double *pXyzzy = &xyzzy; // this is a POINTER to it.
double plugh = *pXyzzy + 12.0;
The final line above gets the value from the pointer (*pXyzzy) and adds twelve to that, before storing it into another variable named plugh.
You should be very wary of things like:
double * storage = 108;
That creates a pointer to a double with the address of 108. In no way does it create an actual double with the value 108. Dereferencing that pointer is likely to lead to, shall we say, interesting results :-)

Resources