SystemVerilog Array of Bits to Int Casting - verilog

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

Related

Casting from int to parameterized-width logic

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;

How to use Arithmetic expression in Enum in system verilog?

`define REG_WIDTH 48
`define FIELD_WIDTH 32
typedef enum bit [`REG_WIDTH-1:0]
{
BIN_MIN = 'h0,
BIN_MID = BIN_MIN + `REG_WIDTH'(((1<<`FIELD_WIDTH)+2)/3),
BIN_MAX = BIN_MID + `REG_WIDTH'(((1<<`FIELD_WIDTH)+2)/3),
}reg_cover;
In the above code I am getting compilation error of enum duplicate because BIN_MID is also taking value '48{0}. But when I do $display for "BIN_MIN + `REG_WIDTH'(((1<<`FIELD_WIDTH)+2)/3)" , I don't get zero.
Since I have typecast each enum field by 48 , why I am getting zero ? I am new to system verilog.
Typically, integer constants like 1 are treated as 32-bit values (SystemVerilog LRM specifies them to be at least 32 bits but most simulators/synthesis tools use exactly 32 bits). As such, since you are preforming a shift of 32 first, you are shifting out the one completely and left with 0 during compilation (32'd1<<32 is zero). By extending the size of the integer constant first to 48 bits, you will not lose the value due to the shift:
`define REG_WIDTH 48
`define FIELD_WIDTH 32
typedef enum bit [`REG_WIDTH-1:0] {
BIN_MIN = 'h0,
BIN_MID = BIN_MIN + (((`REG_WIDTH'(1))<<`FIELD_WIDTH)+2)/3,
BIN_MAX = BIN_MID + (((`REG_WIDTH'(1))<<`FIELD_WIDTH)+2)/3
} reg_cover;
As to why when put in a $display prints a non-zero value, I'm not sure. Some simulators I tried did print non-zero values, others printed 0. There's might be some differences in compile-time optimizations and how they run the code, but casting first is the best thing to do.

Shifter output is always 0 when using concatenation and case

I have the following code:
module shifter(
input[7:0] in,
input[1:0] amt,
output logic[7:0] out
);
always_comb case(amt)
2'h0: out = in;
2'h1: out = {{in[6:0]}, 0};
2'h2: out = {{in[5:0]}, 0, 0};
2'h3: out = {{in[4:0]}, 0, 0, 0};
default: out = in;
endcase
endmodule
It describes a simple shifter which takes in the amount of shifts through the amt input. The problem is that no matter what the value of amt is (except 0), out is always 0 as seen on this waveform from a test:
Am I concatenating wrong? Examples I've seen online are similar to this, however.
Try constraining the size of the 0 to 1'b0 in 2'h1: out = {{in[6:0]}, 0};. What happens is that you are assigning a concatenation of in[6:0] and 32-bit (default width) 0, so only LSBs of the 0 goes to the out.
Also, default is redundant since you've described all the possible cases for amt.
The code you wrote is illegal according to the IEEE 1800-2017 LRM section 11.4.12 Concatenation operators:
Unsized constant numbers shall not be allowed in concatenations. This
is because the size of each operand in the concatenation is needed to
calculate the complete size of the concatenation
The tool you are using has a bug and did not catch this error, which is very difficult to find on your own.

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.

Declaring an array of constant with Verilog

first i want to apologize for my ignorance,this question may be stupid for many of you..but i am a newbie in the domain of Hw dev
I am trying to turn a software function into a hardware accelerator...
in the C code we use an array of integer to calculate a certain value as shown here
uint k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
as you see here am gonna use it to calculate t1
$ t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
however am not certain how to declare this array without using registers, i have a verilog file in whitch it uses localparam to declare a constant. so i wonder could i use it with this vector as below ?
localparam [31:0] k[63:0] =
{0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
Yes you can. However, 0x is not verilog syntax, use 32'h (or just 'h if you want it less strongly typed) instead.
localparam logic [31:0] k[63:0] =
{
32'h428a2f98,32'h71374491,32'hb5c0fbcf,32'he9b5dba5,32'h3956c25b,32'h59f111f1,32'h923f82a4,32'hab1c5ed5,
32'hd807aa98,32'h12835b01,32'h243185be,32'h550c7dc3,32'h72be5d74,32'h80deb1fe,32'h9bdc06a7,32'hc19bf174,
32'he49b69c1,32'hefbe4786,32'h0fc19dc6,32'h240ca1cc,32'h2de92c6f,32'h4a7484aa,32'h5cb0a9dc,32'h76f988da,
32'h983e5152,32'ha831c66d,32'hb00327c8,32'hbf597fc7,32'hc6e00bf3,32'hd5a79147,32'h06ca6351,32'h14292967,
32'h27b70a85,32'h2e1b2138,32'h4d2c6dfc,32'h53380d13,32'h650a7354,32'h766a0abb,32'h81c2c92e,32'h92722c85,
32'ha2bfe8a1,32'ha81a664b,32'hc24b8b70,32'hc76c51a3,32'hd192e819,32'hd6990624,32'hf40e3585,32'h106aa070,
32'h19a4c116,32'h1e376c08,32'h2748774c,32'h34b0bcb5,32'h391c0cb3,32'h4ed8aa4a,32'h5b9cca4f,32'h682e6ff3,
32'h748f82ee,32'h78a5636f,32'h84c87814,32'h8cc70208,32'h90befffa,32'ha4506ceb,32'hbef9a3f7,32'hc67178f2
};
You might be better off going with an integer type rather than localparam. Logic types are 4-state, which is more expensive on the simulator and since you are using it as a constant value (I assume), you should be fine with integer.
integer k[64] = {
32'h428a2f98,32'h71374491,32'hb5c0fbcf,32'he9b5dba5,32'h3956c25b,32'h59f111f1,32'h923f82a4,32'hab1c5ed5,
32'hd807aa98,32'h12835b01,32'h243185be,32'h550c7dc3,32'h72be5d74,32'h80deb1fe,32'h9bdc06a7,32'hc19bf174,
32'he49b69c1,32'hefbe4786,32'h0fc19dc6,32'h240ca1cc,32'h2de92c6f,32'h4a7484aa,32'h5cb0a9dc,32'h76f988da,
32'h983e5152,32'ha831c66d,32'hb00327c8,32'hbf597fc7,32'hc6e00bf3,32'hd5a79147,32'h06ca6351,32'h14292967,
32'h27b70a85,32'h2e1b2138,32'h4d2c6dfc,32'h53380d13,32'h650a7354,32'h766a0abb,32'h81c2c92e,32'h92722c85,
32'ha2bfe8a1,32'ha81a664b,32'hc24b8b70,32'hc76c51a3,32'hd192e819,32'hd6990624,32'hf40e3585,32'h106aa070,
32'h19a4c116,32'h1e376c08,32'h2748774c,32'h34b0bcb5,32'h391c0cb3,32'h4ed8aa4a,32'h5b9cca4f,32'h682e6ff3,
32'h748f82ee,32'h78a5636f,32'h84c87814,32'h8cc70208,32'h90befffa,32'ha4506ceb,32'hbef9a3f7,32'hc67178f2
};

Resources