Decode name of packed struct member based on bit position - system-verilog

I have a register map which is generated with a script. The output of the module is one huge packed struct. This is normally not a problem, but when I lint my code I get warnings like this:
*W,UNCONO (./module_name.v,158):: 'reg[1415]' is not connected.
So I can see that one of my register bits isn't getting used, which is bad, but which one is it? How do I map the bit position in the packed struct back to the named struct member?
To clarify I am looking for a function of some sort that will take a bit position as input and returns the struct member name as an output.

In a packed struct, the bits are numbered right to left, 0 to N-1. So, if you have
typedef struct packed {
logic sign;
logic [7:0] exponent;
logic [22:0] mantissa;
} Float32;
Float32 F;
then
assert (F.sign === F[31]);
assert (F.exponent === F[30:23]);
assert (F.mantissa === F[22:0]);

Related

How to initialize unpacked array of unpacked union of unpacked structs?

What is the legal method of initializing this?
module tb();
typedef struct {
logic [3:0] A;
} a_t;
typedef struct {
logic [7:0] B;
} b_t;
typedef union {
a_t a;
b_t b;
} a_b_t;
a_b_t a_b [8];
initial begin
a_b <= '{default: '{default: 0}};
end
endmodule
xrun gives this error:
xmelab: *E,APBLHS (./tmp.sv,14|23): Assignment pattern - LHS must be an array or structure [SystemVerilog].
I've tried a variety of other ways, and I can't quite get this right. I'm working around it right now by initializing each entry separately with 2 lines of initialization.
As the error message state, assignment patterns only work with struct and arrays, not unions. You would need to use a foreach loop to assign each union member.
initial
foreach (a_b[i]) begin
a_b[i].a <= '{default:0};
a_b[i].b <= '{default:0};
end
Note that unless you are using the DPI for C compatibility, unpacked unions have little usefulness in SystemVerilog. Use packed unions instead.

What is meant by this SystemVerilog typedef enum statement?

typedef enum logic [1:0] {S0, S1, S2} statetype;
Does this statement mean that any variable declared as 'statetype' can only take three values, 2'b00, 2'b01, and 2'b10? If so, what happens if I assign the said variable with the value 2'b11?
The IEEE Std 1800-2017, section 6.19.3 Type checking, states:
Enumerated types are strongly typed; thus, a variable of type enum
cannot be directly assigned a value that lies outside the enumeration
set unless an explicit cast is used or unless the enum variable is a
member of a union. This is a powerful type-checking aid, which
prevents users from accidentally assigning nonexistent values to
variables of an enumerated type. The enumeration values can still be
used as constants in expressions, and the results can be assigned to
any variable of a compatible integral type.
Enumerated variables are type-checked in assignments, arguments, and
relational operators.
What I observe in practice is that some simulators issue a compile warning while others issue a compile error. You can see what happens on multiple simulators on edaplayground (if you sign up for a free account there).
For example, with VCS, the following code:
module tb;
typedef enum logic [1:0] {S0, S1, S2} statetype;
statetype s;
initial begin
s = S0;
$display("n=%s,s=%0d,", s.name(), s);
s = 3;
$display("n=%s,s=%0d,", s.name(), s);
end
endmodule
issues this warning:
Warning-[ENUMASSIGN] Illegal assignment to enum variable
tb.v, 16
tb, "s = 3;"
Only expressions of the enum type can be assigned to an enum variable.
The type int is incompatible with the enum 'statetype'
Expression: 3
Use the static cast operator to convert the expression to enum type.
but, it still runs the simulation and prints:
n=S0,s=0
n=,s=3
I believe the question should be rephrased to say that what is this is happening in our test-bench and how to avoid it. This will gives us more cleaner and bug free code.
efficient code to avoid the confusion:
typedef enum logic [1:0] {S0, S1, S2} statetype;
module top();
statetype st_e;
initial begin
for(int val=0;val<4; val++) begin
// casting for avoid confusion and gotchas
if (!$cast(st_e,val)) begin
$error("Casting not possible -> statetype:%0s and val:%0d",st_e,val);
end else begin
$display("statetype:%0s and val:%0d",st_e,val);
end
end
end
endmodule: top
This code is already there in edaplayground feel free to try it and update it. This could be replace with the sv macro for more efficiency. Please let me know I will provide the example for macros.
Output will be:
# run -all
# statetype:S0 and val:0
# statetype:S1 and val:1
# statetype:S2 and val:2
# ** Error: Casting not possible -> statetype:S2 and val:3
# Time: 0 ns Scope: top File: testbench.sv Line: 14
# exit

Parameterizing the Bit Widths of fields in a packed struct so that modules can infer bit width if used in port map

Also discussed at:
https://verificationacademy.com/forums/systemverilog/parameterizing-bit-widths-fields-packed-struct-so-modules-can-infer-bit-width-if-used-port-map-virtual-interface-interface-compile-time-configured-struct-bit-width
https://forums.xilinx.com/t5/Synthesis/Parameterizing-the-Bit-Widths-of-fields-in-a-packed-struct-so/td-p/1191678
I am having trouble accomplishing my intent in SystemVerilog trying to use the latest language features to make my code more elegant and less verbose. For synthesis**
I would like to accomplish the following:
be able to parameterize the bit widths of fields in a packed struct that I want to define ... I have attempted to accomplish this using a parameterized interface construct
I would like for modules with that parameterized interface as an INPUT to the module to be able to infer the bit width of a field inside that packed struct defined inside the interface
I have been mostly successful in past experiments but I have run into an issue.
Please see the following simple interface definition:
interface MyInterface #(int DATA_W, ADDR_W) () ;
typedef struct packed
{ logic valid
; logic [ADDR_W-1:0] addr
; logic [DATA_W-1:0] data
; } SimpleStruct;
SimpleStruct bus;
logic ready;
modport SNK (input bus, output ready);
modport SRC (output bus, input ready);
endinterface
It is easy enough to instantiate an interface and use it at the input of a simple module in my Top module for this example:
module TopTest
( input wire Clock
, input wire Reset
, input wire [31:0] In
, output wire dummyOut
) ;
MyInterface # ( 32, 3 ) my_interface ();
assign my_interface.bus.data = In ;
assign my_interface.bus.addr = 3'h3 ;
InnerTest inst_mod_inner_test
( .Clock( Clock )
, .Reset( Reset )
, .Sink( my_interface )
) ;
assign dummyOut = my_interface.ready ;
endmodule
The problem that I am running into is that I do not want to parameterize the actual module with field bit widths, because I believe that at compile time the bit widths of the fields should be already established and accessible. This seems to not be the case, and I am wondering if there is anything I can do to accomplish inferring the bit width of the packed struct in the interface (remember that is the case because I want it parameterized, I know it is easy to get $bits of a field of a struct that is not defined in an interface but instead defined in a package or module)
module InnerTest
( input wire Clock
, input wire Reset
, MyInterface.SNK Sink
) ;
localparam BIT_WIDTH_SINK_DATA = $bits( Sink.bus.data ) // this line errors out b/c sink is 'virtual'
RAM # ( .DATA_WIDTH( BIT_WIDTH_SINK_DATA ) ) ram ( ... // etc
... other code to drive output ready of interface ...
endmodule
There are many reasons why a designer would want to make a module "parameterizable" and I have taken that approach in the past, but I am very interested in not duplicating information. If I were to take the easy approach, I would simply parameterize my inner test module so that I provided it DATA_WIDTH, but I would then have two numbers to update and a lot of parameters that I feel I do not need. I think it would be most elegant if I could simply infer characteristics of the parameterized struct somehow. The information I am looking for is truly known at compile time in my opinion. I just can't seem to access it, or this is another shortfall of SystemVerilog.
Follow up Q, in Simulation
The workaround mentioned by Dave was very useful when using QuestaSim, but now running into different issue in QuestaSim:
parameter reference "sink.bus.data" through interface port "sink" is not valid when the actual interface in the instance is an arrayed instance element or below a generate construct
What is the workaround for this, I don't understand why simply being in a generate statement would impact things way downstream. In this case i use a generate statement to choose between different FIFO implementations, a few layers above the line of code where the error happens.
typedef sink.bus.data questasim_workaround;
localparam width = $bits(questasim_workaround);
Follow Up Experiment
I have experimented with passing in type instead of restricting myself to passing in DATA_W.
interface MyInterface #(int ADDR_W, type DATA_TYPE) () ;
typedef struct packed
{ logic valid
; logic [ADDR_W-1:0] addr
; DATA_TYPE data
; } SimpleStruct;
SimpleStruct bus;
logic ready;
modport SNK (input bus, output ready);
modport SRC (output bus, input ready);
endinterface
This allows for more flexibility. I have observed that Vivado Simulator and Synthesis tools can handle an example like this without issue.
module SomeModule
( MyInterface myInt
blah...
);
localparam SOMETHING = $bits(myInt.DATA_TYPE);
// or equivalently
localparam SOMETHING_ELSE = $bits(myInt.data);
// or even this, for needs of a internal signal for pipelined processing steps
MyInterface # ($bits(myInt.addr), myInt.DATA_TYPE) internal_0 () ;
In place of this in QUestaSim we have had to implement Dave's work around:
module SomeModule
( MyInterface myInt
blah...
);
// this gets less elegant :/
typedef myInt.data questasim_workaround_data;
typedef myInt.addr questasim_workaround_addr;
localparam SOMETHING = $bits(questasim_workaround_data);
// or equivalently
localparam SOMETHING_ELSE = $bits(questasim_workaround_data);
// or even this, for needs of a internal signal for pipelined processing steps
MyInterface # ($bits(questasim_workaround_addr), questasim_workaround_data) internal_0 () ;
The current SystemVerilog BNF does not allow any dotted "." names in a parameter initialization. But you can get around this by using a typedef instead
interface MyInterface #(int DATA_W=0, ADDR_W=0) () ;
typedef logic [DATA_W-1:0] data_t;
...
endinterface
module InnerTest
( input wire Clock
, input wire Reset
, MyInterface.SNK Sink
) ;
typedef Sink.data_t data_t;
localparam BIT_WIDTH_SINK_DATA = $bits( data_t );
...
endmodule
Whenever you see an error that is unexpected in Vivado around "[Synth 8-27] scoped/hierarchical type name not supported" ... check to see if the instantiation port map matches all the names of the actual module definitions portmap. That was the issue in Vivado only with this code. The spelling didn't match and instead of a "[Synth 8-448] named port connection 'clkkkk' does not exist" I got a "[Synth 8-27] scoped/hierarchical type name not supported" error
As explained in: https://forums.xilinx.com/t5/Synthesis/Parameterizing-the-Bit-Widths-of-fields-in-a-packed-struct-so/td-p/1191678

Converting a 2D array into 3D array in systemverilog

I have an 2 D dynamic array as
logic [511:0] array[];
I wan to convert it into a 3 D dynamic array defined as
logic [32][16]M[];
eg.
array[0]= 1110110000111000...512 bits....
M[0][0]= 1110110000111000...32 bits....
M[0][1]= next 32 bits....
and so on.
Can some please suggest how to accomplish this task.Did I declare my 3D array properly.I know dynamic array can only be defined in unpacked array. Can I define array as
logic [31:0] M[16][]; ?
Any suggestion or correction would be helpful.
Based on the example you gave it seems as if you want a dynamic array of an unpacked array of 16 32-bit packed words. That would be:
logic [31:0] M[16][];
You can use a bit-stream cast to assign one type shape to another type shape as long as the number of bits in the source can be fit into an exact match number of bits into the target. You need a typedef identifier for the target type (and it's a good practice to use typedefs in general when declaring variables).
typedef [31:0] my_3d_t[16][];
my_3d_t M;
M = my_3d_t'(array);
That does the assignment as
M[0][0][31:0] = array[0][511:480];
M[0][1][31:0] = array[0][479:448];
...
M[0][15][31:0] = array[0][31:0];
M[1][0][31:0] = array[1][511:480];
...

preserving bit widths in enum in system verilog

How do i preserve bit widths in Enum ?
For example in following code :-
typedef enum bit[2:0] {
b1=2'b10,
b2=3'b100
}b;
{// regular stuff module, initial begin etc..
b a1,a2;
a1=b1;
a2=b2;
$display("b=%0d %b",$bits(a1),a1); **// prints 3, 010**
$display("b=%0d %b",$bits(a2),a2); **// prints 3, 100**
}
How can I get to first statement printing
prints 2, 10
I also tried following :-
typedef enum {
w1=2,
w2=3
}w;
w wa1,wa2;
int len,len2;
bit [3:0] bb;
{
bb=a1;
len=w1;
$display("b=%0d %b",$bits(bb[len:0]),wa1);
enter code here
bb=a2; len=w2;
$display("b=%0d %b",$bits(bb[len:0]),wa2);
}
which has compile issue.
Any other technique to preserve bit widths of variables/enums is also welcome.
--------------Edit after original question was posted-----------------
A simpler way to put this question is..
Lets say I have bit[31:0] a;
I need to achieve functionality as follows:-
function bit[] get(bit[31:0] a, int size)
return a[(size-1):0];
thanks,
I don't think you can do what you want in an enum.
When you write typedef enum [2:0] {...} b; you are defining a type called b whose width is 3. All values of this type will (necessarily) have width 3. A good way to think about this might be to consider a module that is going to take a b as an input, e.g.,
module mymod(input b myB, output o);
...
endmodule
How wide should myB be? It needs to be wide enough for mymod to accept any argument of type b. For instance, you would like to be able to pass this module either b1 or b2 and have it work. But the module's input can't be changing its size dynamically as your simulation/hardware runs.
If you just want to have some named values that have independent widths, you might try using localparam, e.g., you can write:
localparam b1 = 2'b10;
localparam b2 = 3'b100;
But you'll still run into a similar issue when you try to assign these to your variables a1 and a2. At that point, it's just a matter of how wide a1 and a2 are.
Well, if you insist in using an enum you can achieve this implicitly:
$display("b=%0d %0b", $clog2(a1+1), a1); **// prints 2, 10**
$display("b=%0d %0b", $clog2(a2+1), a2); **// prints 3, 100**