Function to return a struct with an unconstrained field

I have a struct with an unconstrained field and would like a function to return a value whose type is that struct, and where the unconstrained field is constrained by the size of the function input. I know how to do this in VHDL and was hoping there’s a System Verilog equivalent. Here’s my (very unsuccessful) first attempt at this:


typedef struct {
  bit Vec [];
  bit Parity;
} MyRec_t;

function automatic MyRec_t CreateMyRec (input Val []);
  MyRec_t Rec;
  Rec.Vec = new(Val.size()+4);
  Rec.Vec = {4'hF,Val};
  Rec.Parity = ^ Rec.Vec;
  return Rec;
endfunction

In reply to craigc40:

There is no direct equivalent of VHDL’s unconstrained vector type in SystemVerilog.

For the code in your example, you need to treat Rec.Vec as an unpacked array.

function automatic MyRec_t CreateMyRec (input Val []);
  MyRec_t Rec;
  Rec.Vec = {>>{4'hF,Val}}; // streaming operator
  Rec.Parity = Rec.Vec.xor(); // array reduction method
  return Rec;
endfunction

In reply to dave_59:

Thank you Dave. This is a very elegant solution. Do you have any reason to believe I would run into trouble with synthesis support using your solution? And would you have recommended I take a different approach (such as using a parameterized class)?

In reply to craigc40:

Synthesis tools do not support variables with a dynamic array type. You would need to wrap this in a parameterized class.

module top;
  virtual class myRec #(int WIDTH);
    typedef  bit [WIDTH-1:0] Vec_t;
    typedef struct {
      Vec_t Vec;
       bit Parity;
    } myRec_t;
    static function myRec_t Create (input Vec_t Val);
      myRec_t Rec;
      Rec.Vec = {4'hF,Val};
      Rec.Parity = ^ Rec.Vec;
      return Rec;
    endfunction
  endclass
  
  bit [3:0] v1 = 4'b1010;
  bit [7:0] v2 = 8'b10101;
  typedef myRec#($bits(v1)) v1_t;
  typedef myRec#($bits(v2)) v2_t;
  v1_t::myRec_t res1;
  v2_t::myRec_t res2;

  initial begin
    res1 = v1_t::Create(v1);
    res2 = v2_t::Create(v2);
    $displayb("res1: %p", res1);
    $displayb("res2: %p", res2);
  end
endmodule