Вывести открытый массив как формальный аргумент в DPI-C

У меня есть C-код (модель предиктора), который может генерировать массив переменной длины в качестве результата. До вызова кода C неизвестно, каков размер этого массива, и существует некоторая степень рандомизации (моделирование шума).

Мне нужно вызвать эту модель предиктора C из SystemVerilog и получить обратно массив выходных результатов.

Как новичок в DPI-C, я столкнулся с 3 ограничениями:

  1. Массив результатов на стороне SV должен быть выделен до вызова кода C. Поскольку я не знаю, каким будет размер, у меня есть шанс перераспределить или перераспределить.
  2. Я не могу передать открытый массив из C -> SV в функцию экспорта.
  3. Функция экспорта не может использоваться для методов класса (!)

Чтобы обойти это, я создал хакерское жонглирование между двумя интерфейсами и глобальными переменными / задачами.

Я опубликовал свое решение, и оно отлично работает, но я хотел бы знать, есть ли у кого-нибудь более элегантное решение, чем это. Особенно мне не нравится использовать глобальные переменные.

SV:

export "DPI-C" function allocate_mem;
export "DPI-C" function set_item;
import "DPI-C" context function void predictForMe (input int noiseA, input int noiseB);

int result[];

function void allocate_mem(int size);
  result = new[size];
endfunction

function void set_item(int index, int item);
  result[index] = item;
endfunction

class my_class;
  // constructor etc etc - assume is valid

  // my_func
  function void my_func();
    int noiseA = 10; // hardcode to simplify example
    int noiseB = 20; // hardcode to simplify example

    // call imported function
    predictForMe( noiseA, noiseB );
  endfunction
endclass

C:

extern void allocate_mem(int size);
extern void set_item(int index, int item);

void predictForMe(int noiseA, int noiseB)
{
  // do some calcualation based on noiseA and noiseB
  // generates an answer_array with num elements = X

  allocate_mem(X);
  for(i = 0; i < X; i++) set_item(i, answer_array[i]);

}

Любые лучшие решения приветствуются.

1 ответ

Вы не можете передать открытый массив из кода C, потому что код C не знает, как распределить такую ​​структуру данных. Я предполагаю, что это потому, что было бы проблематично, если массив, выделенный в коде C, не соответствует типу массива на стороне SV. Например, представьте, что у вас есть массив фиксированного размера из 100 элементов, определенный на стороне SV, и вы пытаетесь передать ему массив из 10 элементов из C. Также, вероятно, трудно определить функцию на стороне C, которая может выделить структуру данных массива SV, Размер и расположение зависят не только от количества элементов, но и от типа элемента.

Впрочем, в качестве выходного аргумента можно передать уже выделенный массив. Вы должны знать, сколько элементов нужно предварительно выделить. Как подсказывает @NominaAnimal, вы должны передать количество элементов, которые вы получите от C, через отдельный вызов функции:

import "DPI-C" function int get_num_elems(args...);
import "DPI-C" function void get_elems(output int elems, args...);

class some_class;

  function void some_func();
    int result[]; // not a global variable
    result = new[get_num_elems(args...)];
    get_elems(result, args...);
  endfunction

endclass

На стороне C вы можете использовать svGetArrElemPtr1(...) получить указатель на каждый элемент переданного в result массив и обновить его соответственно. Вы можете сделать это, потому что тип int и представления идентичны на обоих языках:

void get_elems(svOpenArray elems, args...) {
  // compute elems based on 'args...'

  for (int i = 0; i < svSize(elems); i++)
    *(svGetArrElemPtr1(elems, i)) = ...[i];
}
Другие вопросы по тегам