Вывести открытый массив как формальный аргумент в DPI-C
У меня есть C-код (модель предиктора), который может генерировать массив переменной длины в качестве результата. До вызова кода C неизвестно, каков размер этого массива, и существует некоторая степень рандомизации (моделирование шума).
Мне нужно вызвать эту модель предиктора C из SystemVerilog и получить обратно массив выходных результатов.
Как новичок в DPI-C, я столкнулся с 3 ограничениями:
- Массив результатов на стороне SV должен быть выделен до вызова кода C. Поскольку я не знаю, каким будет размер, у меня есть шанс перераспределить или перераспределить.
- Я не могу передать открытый массив из C -> SV в функцию экспорта.
- Функция экспорта не может использоваться для методов класса (!)
Чтобы обойти это, я создал хакерское жонглирование между двумя интерфейсами и глобальными переменными / задачами.
Я опубликовал свое решение, и оно отлично работает, но я хотел бы знать, есть ли у кого-нибудь более элегантное решение, чем это. Особенно мне не нравится использовать глобальные переменные.
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];
}