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

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

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

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

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

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

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

СВ:

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

С:

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]);

}

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


person noobuntu    schedule 22.12.2017    source источник
comment
Каков диапазон X?   -  person meaning-matters    schedule 23.12.2017
comment
Это варьируется - может быть что-то между 2 ^ 1 и 2 ^ 32-1. Я использую структуру типа очереди для динамического увеличения и перераспределения памяти для моего массива.   -  person noobuntu    schedule 23.12.2017
comment
Ой, это действительно очень большой диапазон. Возможно, есть эвристика, с помощью которой вы можете найти верхнюю границу размера (с некоторым запасом)?   -  person meaning-matters    schedule 23.12.2017
comment
Верхняя граница может быть определена только во время выполнения путем рандомизации в предсказателе. Любое его ограничение ухудшит нашу производительность. Я использовал структуру очереди для динамического выделения/освобождения памяти в модели C, но трудно предсказать, какой будет верхняя граница.   -  person noobuntu    schedule 23.12.2017
comment
Разделите часть C на две отдельные функции. Первый генерирует данные и возвращает количество данных, второй копирует (и освобождает) сгенерированные данные в буфер, выделенный вызывающей стороной (SV). Да, вам нужно будет использовать глобальные переменные. Если вы хотите, чтобы в полете одновременно выполнялось более одной операции, вы можете использовать массив дескрипторов и первую функцию для захвата первого свободного; он возвращает индекс дескриптора. Затем дополнительная функция возвращает размер результата. Функция копирования всегда освобождает динамическую память C и уничтожает дескриптор. Будет ли это работать лучше?   -  person Nominal Animal    schedule 23.12.2017
comment
Да, я, по сути, сделал это. Функция allocate_mem выделяет буферное пространство в SV. set_item копирует его в это пространство. Мне нравится твоя идея с дескрипторами. Однако вопрос в том, есть ли способ передать открытый массив обратно в SV со стороны C, используя svOpenArrayHandle   -  person noobuntu    schedule 23.12.2017


Ответы (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];
}
person Tudor Timi    schedule 23.12.2017
comment
У меня изначально была такая же идея. Проблема в том, что моя модель C имеет рандомизацию со стохастически сгенерированным начальным числом. Таким образом, 2 вызова одной и той же модели C не гарантируют одинаковых результатов. (Если вам интересно, как я могу воспроизвести неудачные тестовые случаи, я выгружаю массив результатов в файл, который затем могу вернуть без вызова предиктора) - person noobuntu; 23.12.2017
comment
Затем вы можете сохранить результаты в глобальной переменной на языке C. Вы можете сделать переменные C уникальными для файла, в котором они объявлены (я забыл, как именно). @noobuntu Замените функцию get_num_elems(...) на allocate_elems_and_get_size(...), которая выделяет элементы в массиве C, к которому вы можете получить доступ из get_elems(svOpenArray) (только один аргумент - массив для их помещения). - person Tudor Timi; 23.12.2017
comment
Хотя это тонна копирования. - person Tudor Timi; 23.12.2017
comment
@noobuntu Если повторное копирование в SV непомерно дорого, вам лучше использовать дополнительный класс-оболочку вместо собственного массива SV. Получите chandle для глобального массива C и размер массива из C. Всякий раз, когда вы хотите получить доступ к элементу, вместо того, чтобы нарезать массив, вы можете вызвать функцию get(chandle array, int idx) для вашего объекта-оболочки, которая может быть посредником между вашим кодом и C. - person Tudor Timi; 23.12.2017