pysv icon indicating copy to clipboard operation
pysv copied to clipboard

IntArray error

Open 1152995039 opened this issue 1 year ago • 14 comments

Hi,

I use IntArray as funtion parameter in python side and compile passed. But a error occurs when I simulate by vcs:

Error-[DPI-ASSERT] Assertion failure in DPI call Assertion failure in DPI function/task call: dimension 0 query is not supported. (svSize) Please check the parameter passing in a DPI function/task call

And I find that the svSize is used in c file, which generated by compile_lib:

py::memoryview to_buffer(const svOpenArrayHandle array_handle) {
    ssize_t element_size = sizeof(int32_t);
    void *base_ptr = nullptr;
    std::vector<ssize_t> sizes = {};
    std::vector<ssize_t> strides = {};

    // we try to query the underlying representation
    base_ptr = svGetArrayPtr(array_handle);
    if (!base_ptr) {
        throw std::runtime_error("Array type does not have native C representation");
    }
    auto dim = svDimensions(array_handle);
    for (auto i = 0; i < dim; i++) {
        auto s = svSize(array_handle, i);
        sizes.emplace_back(s);
    }

    // assumes row major ordering
    ssize_t stride = element_size;
    strides = std::vector<ssize_t>(dim, element_size);
    for (int i = 0; i < dim - 1; i++) {
        stride *= sizes[i];
        strides[i] = stride;
    }
    return py::memoryview::from_buffer(
        base_ptr,                                 /* Pointer to buffer */
        element_size,                             /* Size of one scalar */
        py::format_descriptor<int32_t>::value, /* Python struct-style format descriptor */
        sizes,                                    /* Buffer dimensions */
        strides                                   /* Strides (in bytes) for each index */
    );
}

Maybe this (dim in for loop begins from 0 ) causes the error?

1152995039 avatar Jan 04 '24 12:01 1152995039

Can you show me the code where you call the DPI function? Especially the array definition.

Kuree avatar Jan 04 '24 18:01 Kuree

Can you show me the code where you call the DPI function? Especially the array definition.

Ok, in python side:

class Img2colVerificationTools:
    @sv()
    def __init__(self):
        self.fea = None
        self.fea_2d = None
        self.counter = 0
    @sv(fea_array=DataType.IntArray)
    def get_fea(self, fea_array):
        self.fea = np.array(fea_array).reshape(3,8,8)
        self.fea_2d = self.fea.reshape(-1,4)
        
    @sv(return_type=Reference(a=DataType.UInt, b=DataType.UInt, c=DataType.UInt,d=DataType.UInt))
    def gen_stimulus(self):
        out = self.fea_2d[self.counter,:]
        self.counter += 1
        return out

In sv side:

class fea_transaction;
    rand int fea[][][];
    int fea_queue[$];
    constraint c_fea{
        $size(fea) == 3;
        foreach(fea[i]){
            $size(fea[i]) == 8;
        }
        foreach(fea[i,j]){
            $size(fea[i][j]) == 8;
        }
        foreach(fea[i,j,k]){
            fea[i][j][k] >= 0;
            fea[i][j][k] < 256;
        }
    }

    function void flatten();
        foreach(fea[i,j,k]) begin
            fea_queue.push_back(fea[i][j][k]);
        end
    endfunction
endclass
module top_tb;

    fea_transaction  fea_tr;
    initial begin
        int a,b,c,d, cycle;
        Img2colVerificationTools m_gen=new();
        fea_tr = new();
        fea_tr.randomize();
        fea_tr.flatten();
        m_gen.get_fea(fea_tr.fea_queue);
        
        cycle = 48;
        for(int i=0;i<cycle;i++) begin
            m_gen.gen_stimulus(a,b,c,d);
            $display("%d th cycle: a is %d",i+1,a);
            $display("%d th cycle: b is %d",i+1,b);
            $display("%d th cycle: c is %d",i+1,c);
            $display("%d th cycle: d is %d",i+1,d);
        end
        
        pysv_finalize();
    end
endmodule

1152995039 avatar Jan 05 '24 02:01 1152995039

int fea_queue[$]; defines a queue. SystemVerilog LRM does not specify how it can be translated to a DPI interface type. It should work once you convert it to an open/dynamic array.

Kuree avatar Jan 05 '24 16:01 Kuree

int fea_queue[$]; defines a queue. SystemVerilog LRM does not specify how it can be translated to a DPI interface type. It should work once you convert it to an open/dynamic array.

Thanks, the queue can not be used here. But the same error occurs when I use dynamic array or static array:

class fea_transaction;
    rand int fea[][][];
    int fea_queue[$];
    int fea_darray[];
    int fea_sarray[3*8*8];
    constraint c_fea{
        $size(fea) == 3;
        foreach(fea[i]){
            $size(fea[i]) == 8;
        }
        foreach(fea[i,j]){
            $size(fea[i][j]) == 8;
        }
        foreach(fea[i,j,k]){
            fea[i][j][k] >= 0;
            fea[i][j][k] < 256;
        }
    }

    function void flatten();
        foreach(fea[i,j,k]) begin
            fea_queue.push_back(fea[i][j][k]);
        end
        fea_darray = fea_queue;
        fea_sarray = fea_queue;
    endfunction
endclass
module top_tb;

    fea_transaction  fea_tr;
    initial begin
        int a,b,c,d, cycle;
        Img2colVerificationTools m_gen=new();
        fea_tr = new();
        fea_tr.randomize();
        fea_tr.flatten();
        m_gen.get_fea(fea_tr.fea_sarray);
        
        cycle = 48;
        for(int i=0;i<cycle;i++) begin
            m_gen.gen_stimulus(a,b,c,d);
            $display("%d th cycle: a is %d",i+1,a);
            $display("%d th cycle: b is %d",i+1,b);
            $display("%d th cycle: c is %d",i+1,c);
            $display("%d th cycle: d is %d",i+1,d);
        end
        
        pysv_finalize();
    end
endmodule

And i still think the reason of this error is usage of svSize function in c file. The similar error occurs when I take another experiment that I try to use svLow(h,0) function to get the lower bound of the first dimension of the array passed from sv to c:

Error-[DPI-ASSERT] Assertion failure in DPI call Source info: ./test_c.sv:35 Assertion failure in DPI function/task call: dimension 0 query is not supported. (svLow) Please check the parameter passing in a DPI function/task call.

Maybe the dimension parameter of these functions(likes svLow,svHigh,svSize) should start from 1 rather than 0?

In addition, i want to know what the code looks like if i pass a 3d array to python from sv. Here i was going to pass an array(3x8x8) to python. If i know how to do, i will do not use flatten in sv and reshape in python.

1152995039 avatar Jan 06 '24 09:01 1152995039

Maybe the dimension parameter of these functions(likes svLow,svHigh,svSize) should start from 1 rather than 0?

That's a good point. I will double check the spec. In the meantime, can you try to modify the generated C++ code and see if it works?

In addition, i want to know what the code looks like if i pass a 3d array to python from sv. Here i was going to pass an array(3x8x8) to python. If i know how to do, i will do not use flatten in sv and reshape in python.

Once the bug is fixed, the C++ you posted should produce a 3d Python array to the binding, at least that's the intention. I haven't extensively tested it thought.

Kuree avatar Jan 07 '24 04:01 Kuree

That's a good point. I will double check the spec. In the meantime, can you try to modify the generated C++ code and see if it works?

Only modifying the generated c++ code doesn't work, and maybe the shared library need to be recompiled. But i do not know how to recompile due to dependency issues.

Once the bug is fixed, the C++ you posted should produce a 3d Python array to the binding, at least that's the intention. I haven't extensively tested it thought.

Actually, I want to know what the code looks like in python side, and just using IntArray as parameter type maybe can't generate sv binding as: import "DPI-C" void function sv_fun(input int data[][][]); just generate: import "DPI-C" void function sv_fun(input int data[]); I don't know if my understanding is correct.

1152995039 avatar Jan 07 '24 05:01 1152995039

Ok, i modify the code in pysv package installed and it works. The code modified is in file snippets/buffer_impl.cc:

    auto dim = svDimensions(array_handle);
    for (auto i = 1; i < dim + 1; i++) {
        auto s = svSize(array_handle, i);
        sizes.emplace_back(s);
    }
    // assumes row major ordering
    ssize_t stride = element_size;
    strides = std::vector<ssize_t>(dim, element_size);
    for (int i = 0; i < dim; i++) {
        stride *= sizes[i];
        strides[i] = stride;
    }

But the 3x8x8 array data is not correct. The data printed in sv is:

'{126, 99, 120, 153, 229, 203, 121, 53, 202, 178, 172, 25, 106, 179, 187, 133, 55, 41, 168, 119, 200, 132, 47, 146, 215, 42, 70, 22, 118, 58, 60, 201, 7, 185, 65, 42, 201, 144, 100, 97, 233, 82, 227, 232, 255, 104, 176, 39, 70, 122, 94, 29, 154, 240, 54, 127, 185, 160, 23, 6, 36, 237, 230, 115, 232, 31, 95, 24, 68, 170, 197, 31, 31, 162, 168, 38, 97, 58, 241, 206, 27, 203, 7, 63, 39, 105, 172, 200, 229, 59, 71, 46, 182, 161, 68, 37, 195, 239, 198, 81, 99, 227, 100, 96, 188, 39, 173, 235, 61, 146, 242, 196, 136, 150, 39, 13, 52, 210, 206, 208, 165, 0, 205, 208, 9, 199, 63, 221, 193, 29, 40, 29, 1, 124, 146, 173, 101, 204, 108, 244, 149, 233, 220, 38, 29, 137, 182, 251, 53, 137, 189, 242, 241, 206, 254, 7, 247, 76, 132, 193, 192, 45, 96, 83, 216, 158, 156, 109, 126, 13, 40, 36, 180, 149, 46, 67, 132, 81, 223, 103, 168, 116, 209, 178, 191, 229, 71, 157, 9, 56, 84, 229}

The data printed in python is:

126,0,0,0,0,0,0,0,0,0,1272250368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65535,0,0,0,0,0,0,0,0,0,0,0,0,0,0,355991751,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1146307414,543515759,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1272067408,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

Maybe the code in to_buffer function is not correct?

1152995039 avatar Jan 07 '24 14:01 1152995039

Actually, I want to know what the code looks like in python side, and just using IntArray as parameter type maybe can't generate sv binding as: import "DPI-C" void function sv_fun(input int data[][][]); just generate: import "DPI-C" void function sv_fun(input int data[]); I don't know if my understanding is correct.

You're right about this. The type info is not properly encoded and thus only 1D array is generated. I have some ideas on how to add type annotation on the multi-d array. and I will work on that next.

Maybe the code in to_buffer function is not correct?

It might be. I only tested the code with Verilator (the one I have access to on my laptop) and using 0 seems to work without crashing. I will investigate more.

Thanks again for finding the issues.

Kuree avatar Jan 07 '24 20:01 Kuree

Looking forward to improvements in future

1152995039 avatar Jan 08 '24 05:01 1152995039

Should be fixed in the latest commit/release. Please reopen this issue if it doesn't work for you (I only tested it with Verilator). Example usage for a 3D array:

DataType.IntArray[3]

Kuree avatar Jan 20 '24 22:01 Kuree

Should be fixed in the latest commit/release. Please reopen this issue if it doesn't work for you (I only tested it with Verilator). Example usage for a 3D array:

DataType.IntArray[3]

Emmm, maybe i have not access to reopen this issue.

A new problem is the static multi-dimensional array defined can't be passed to function in sv binding(maybe it doesn't has the conception of multi-dimensional dynamic array). As follows:

Incompatible complex type usage in task or function call. The following expression is incompatible with the formal parameter of the function. The type of the actual is 'int$[0:2][0:7][0:7]', while the type of the formal is 'int$[][][]'. Expression: data Source info: m_gen.get_fea(data)

If i define a multi-dimensional dynamic array (maybe called open array, likes data[][][]) and pass it to function in sv binding, a new error occurs:

Incompatible complex type usage in task or function call. The following expression is incompatible with the formal parameter of the function. The type of the actual is 'int$[][][]', while the type of the formal is 'int$[:][:][:]'. Expression: fea_array Source info: gen::Img2colVerificationTools_get_fea(this.pysv_ptr, fea_array)

Finally, after i modify parameter type to static array in sv binding function and define a static array to pass it, everything works. the example code is:

// my array
int data[3][8][8];
Img2colVerificationTools m_gen=new();
m_gen.get_fea(data);

//import c functoin,  dosn't modify
 import "DPI-C" function void Img2colVerificationTools_get_fea(input chandle self,
                                                              input int fea_array[][][]);

//modify to static array
class Img2colVerificationTools extends PySVObject;
......
  function void get_fea(input int fea_array[3][8][8]);
    Img2colVerificationTools_get_fea(pysv_ptr, fea_array);
  endfunction
endclass

1152995039 avatar Jan 21 '24 09:01 1152995039

What simulator are you using? I tested the open array DPI interface with all big three simulators (VCS, Xcelium, and Questa), and Verilator. They all work with static-sized array. See the EDA playground example here: https://www.edaplayground.com/x/jrga

module dpi_tb;
  import "DPI-C" context function void test_array(input int array[][]);
  
  int value[2][4];
  
  initial
  begin
    test_array(value);
  end
  
endmodule
#include <stdio.h>
#include <iostream>
#include <svdpi.h>

using namespace std;

extern "C" {
  void test_array(svOpenArrayHandle array) {
     printf("works\n"); 
  }
}

Kuree avatar Jan 21 '24 17:01 Kuree

What simulator are you using? I tested the open array DPI interface with all big three simulators (VCS, Xcelium, and Questa), and Verilator. They all work with static-sized array. See the EDA playground example here: https://www.edaplayground.com/x/jrga

module dpi_tb;
  import "DPI-C" context function void test_array(input int array[][]);
  
  int value[2][4];
  
  initial
  begin
    test_array(value);
  end
  
endmodule
#include <stdio.h>
#include <iostream>
#include <svdpi.h>

using namespace std;

extern "C" {
  void test_array(svOpenArrayHandle array) {
     printf("works\n"); 
  }
}

I use the vcs to run. And i mean that static-sized array actually works, but error occurs in systemverilog binding. When a class is used in python, c++ file uses many static functions to map this class and systemverilog binding wraps these static functions into a sv class. Finally, we call this sv class for using as like calling python class.

A this class example in sv binding generated is:

class Img2colVerificationTools extends PySVObject;
  function new();
    pysv_ptr = Img2colVerificationTools_pysv_init();
  endfunction

  function void get_fea(input int fea_array[][][]);
    Img2colVerificationTools_get_fea(pysv_ptr, fea_array);
  endfunction
endclass

As like the above code, the formal parameter of get_fea function is fea_array[][][] so that i can not call this function by passing a static-sized array unless i modify fea_array[][][] to fea_array[3][8][8](the same as the size of static-sized array passed). If i directly call the Img2colVerificationTools_get_fea by passing a static-sized array, it will not a problem. It is the class wrapper that is causing the error.

1152995039 avatar Jan 22 '24 06:01 1152995039

As like the above code, the formal parameter of get_fea function is fea_array[][][] so that i can not call this function by passing a static-sized array unless i modify fea_array[][][] to fea_array[3][8][8](the same as the size of static-sized array passed). If i directly call the Img2colVerificationTools_get_fea by passing a static-sized array, it will not a problem. It is the class wrapper that is causing the error.

Got it. Thanks for the explanation. I am able to reproduce the error. I didn't realize that the class method is causing the issue. I don't know a quick workaround at the moment so unfortunately you have to use top-level functions instead of a python class. I will see if there is any workaround.

Reopen this issue for tracking.

Kuree avatar Jan 22 '24 06:01 Kuree