Search code examples
verilogvpi

How to get dimensions of a verilog vector port using PLI routines?


How can I fetch the dimensions of a vector port using the vpi PLI routines? For example, for the vector port declaration "output [2:1] out;", how can I get the left dimension as 2 and right dimension as 1? I tried using vpiRange property but it seems that vpiRange property is not supported for Ports. Thanks! Putting the code here for clarity.

vpiHandle lowconn = vpi_handle(vpiLowConn, portH);   
int dim = 0;
int ldim[10];
int rdim[10];

vpiHandle range_itr = vpi_iterate(vpiRange, lowconn );

vpiHandle range;
while ((range = vpi_scan(range_itr))) {
  ldim[dim] = vpi_get(vpiLeftRange, range);
  rdim[dim] = vpi_get(vpiRightRange, range);
  dim++;
}
int size = vpi_get(vpiSize, portH);
cout << endl << vpi_get_str(vpiName, portH) << " size = " << size << " LeftRange = " << vpi_get(vpiLeftRange, lowconn ) << " RightRange = " << vpi_get(vpiRightRange, lowconn );
for ( int i = 0; i < dim; i++ ) {
  cout << vpi_get_str(vpiName, portH) << " = " << ldim[i] << ":" << rdim[i];
}

I am getting -1 from vpi_get(vpiLeft/RightRange) as well as in ldim and rdim. Is there anything erroneos with my code?


Solution

  • Your problem is that both vpiLeftRange and vpiRightRange return vpiHandle, not the value. When you instantiate a module. They could be constant expressions, or variable index expressions (for highcon). so, you can try to get values for them. Here is an example which works for vcs.

    the verilog module looks like this:

    module pvpi (pa, pb);
       input wire [3:0] pa;
       input wire [7:6] pb;
    
       child child_inst(.a(pa), .b(pb));
       initial $report_ports;
    endmodule 
    
    module child(input [4:1] a, input [1:2] b);
    endmodule // child
    

    c-code is here

    #include "vpi_user.h"
    
    static int getExprValue(vpiHandle conn, int r) {
        vpiHandle expr = vpi_handle(r, conn);
    
        s_vpi_value val = {vpiIntVal};
        vpi_get_value(expr, &val);
        return val.value.integer;
    }
    
    void report_ports() {
        vpiHandle moduleInst = vpi_handle_by_name("pvpi.child_inst", 0);
        vpiHandle ports = vpi_iterate(vpiPort, moduleInst);
        vpiHandle port;
    
        vpi_printf("%s %s\n", vpi_get_str(vpiDefName, moduleInst), vpi_get_str(vpiFullName, moduleInst));
    
        while ((port = vpi_scan(ports))) {
    
            vpiHandle highConn = vpi_handle(vpiHighConn, port);
            vpiHandle lowConn = vpi_handle(vpiLowConn, port);
    
            vpi_printf("   %d %s [%d:%d]/[%d:%d]\n", vpi_get(vpiDirection, port),  vpi_get_str(vpiFullName, port),
                       getExprValue(highConn, vpiLeftRange), getExprValue(highConn, vpiRightRange),
                       getExprValue(lowConn, vpiLeftRange), getExprValue(lowConn, vpiRightRange)); 
    
        }
    }
    

    here is the result

    child pvpi.child_inst
       1 pvpi.child_inst.a [3:0]/[3:0]
       1 pvpi.child_inst.b [7:6]/[1:2]
    

    This should work for simple constant expressions with parameters and literals.