Search code examples
system-verilogsystem-verilog-dpi

Is it possible to use packed structs with DPI


Suppose I have a packed struct:

typedef struct packed {
   logic a;
   logic [7:0] b;
   bit  [7:0] c;
   logic [7:0] [31:0] d;
} my_struct;

And I want to pass it into a C function:

import "DPI" context function int my_dpi_function (input my_struct data);

How do I read values on C side?:

int my_dpi_function (void* data) 
{  
    ... ?

    return 0;
}

Solution

  • The type you need is defined in the svdpi.h header:

    svLogicVecVal
    

    So, you need something like:

    int my_dpi_function (svLogicVecVal* data) 
    {  
        ... 
        return 0;
    }
    

    svLogicVecVal is itself a struct. It has two fields - aval and bval (or sometimes, eg in Cadence, a and b). From svdpi.h:

    typedef struct t_vpi_vecval {
    #ifdef P1800_2005_VECVAL
        uint32_t a;
        uint32_t b;
    #else
        uint32_t aval;
        uint32_t bval;
    #endif
    } s_vpi_vecval, *p_vpi_vecval;
    #endif
    
    /* (a chunk of) packed logic array */
    typedef s_vpi_vecval svLogicVecVal;
    

    The aval and bval fields are encoded thus (the so-called "canonical representation"):

    bval aval | 4-state verilog value
    ----------|----------------------
      0    0  |   0
      0    1  |   1
      1    0  |   X
      1    1  |   Z
    

    So, you can access the aval and bval fields in your C. It turns out that for vectors wider than 32-bits, the most-significant 32-bit word is at the highest pointer address.


    https://www.edaplayground.com/x/2k33

    SV

    module test;
    
      typedef struct packed {
        logic a;
        logic [7:0] b;
        bit  [7:0] c;
        logic [7:0] [31:0] d;
      } my_struct;
    
      import "DPI-C" context function int my_dpi_function (logic [272:0] data);
    
      initial
        begin
          automatic my_struct data = '{1'b0,8'hAA,8'h55,256'h0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF};
          $display("%h",data);
          my_dpi_function (data);
        end
    
    endmodule
    

    C++

    #include <iostream>
    #include <iomanip>
    #include <svdpi.h>
    
    using namespace std;
    
    extern "C" int my_dpi_function (svLogicVecVal* data) {
        data+=8;
        cout << "# C++: ";
        for (int i=0; i<9; i++)
          cout << std::hex << std::setw(8) << std::setfill('0') << (data--)->aval;
        cout << "\n";
      return 0;
    }