I have a very complicated packed struct, C
, with nested packed structs, A
and B
, in SystemVerilog:
typedef struct packed {
logic [31:0] ex1;
logic [3:0] ex2;
} A;
typedef struct packed {
logic ex3;
A [7:0] ex4;
} B;
typedef struct packed {
logic ex5
A [5:0]ex6;
B ex7;
} C;
I need to send this struct via a DPI-C call and then access the different elements within the struct. Unfortunately the actual struct I'm working with is much more complicated than above and I'd like to achieve this without bit indexing into the array for every element. I have seen this post but my struct is so nested and complicated that just indexing would be largely infeasible.
So in the testbench.sv file, I have:
import "DPI-C" function void passC(input C c);
And then in the my-dpi.cc file, I want a way to simply save the svLogicVecVal into a C++ equivalent struct
struct A {
svLogicVecVal ex1; \\[31:0]
svLogicVecVal ex2; \\[3:0]
};
struct B {
svBit ex3;
A ex4[8];
};
struct C {
svBit ex5
A ex6[6];
B ex7;
};
extern "C" function void passC(svLogicVecVal* c){
C = c;
}
I know this is an extremely complicated issue so I would appreciate any advice on the best way to go about it. Unfortunately, I cannot change the SystemVerilog struct itself. I could try to convert it to C compatible types in SystemVerilog but I'd prefer to just go whatever the cleanest solution is. Thanks in advance.
I came up with an example which allows you to use vpi calls to traverse fields of the structure. It is pure vpi example involved from a dpi function. You can use something similar.
Here is verilog code
typedef struct packed {
logic [3:0] f1;
logic f2;
} s1_t;
typedef struct packed {
logic f3;
s1_t s1;
} s2_t;
import "DPI-C" function void xploreStruct(string instName, string varName);
module test;
s2_t s2 = '{1, '{2, 0}};
initial begin
xploreStruct("test", "s2");
end
endmodule // test
The function gets called with two args: module instance, and variable name. You can probably come up with a different scheme. You might need to use a pure vpi system function instead of dpi if you want to pass the variable itself. Anyway, 'C' code for this example:
#include "stdio.h"
#include "svdpi.h"
#include "sv_vpi_user.h"
static void xploreStructUnionMembers(vpiHandle var, int offset);
void xploreStruct(const char *instName, const char *varName){
vpiHandle module = vpi_handle_by_name(instName, 0);
vpiHandle tdVar = vpi_handle_by_name(varName, module);
printf("%s %s\n", vpi_get_str(vpiType, tdVar), vpi_get_str(vpiName, tdVar));
xploreStructUnionMembers(tdVar, 1);
}
static void xploreStructUnionMembers(vpiHandle var, int offset){
vpiHandle members = vpi_iterate(vpiMember, var);
vpiHandle member;
while (( member = vpi_scan(members) )) {
printf("%*s %s %s\n", offset*4, "", vpi_get_str(vpiType, member), vpi_get_str(vpiName, member));
int vType = vpi_get(vpiType, member);
if (vType == vpiStructVar || vType == vpiUnionVar) {
xploreStructUnionMembers(member, offset+1);
}
else {
s_vpi_value value = {vpiIntVal};
vpi_get_value(member, &value);
printf("%*s = %d\n", offset*4, " ", value.value.integer);
}
}
return;
}
and the output
vpiStructVar s2
vpiLogicVar f3
= 1
vpiStructVar s1
vpiLogicVar f1
= 2
vpiLogicVar f2
= 0
This worked with vcs.