Ошибка синтеза Vivado HLS

В настоящее время я пытаюсь сделать какой-то проект на Vivado HLS. Однако во время синтеза я получил ошибку, как показано в заголовке. Однако появляется эта ошибка:

ошибка:** недопустимые операнды для двоичного выражения ("double" и "datau32" (он же "ap_axiu‹32, 2, 5, 6>"))) imgOut= (0,2126*Imgin[coord] + 0,7152*Imgin[coord+1 ] + 0,0722*Изображение[координата+2])

Это мой код HLS:

#include "core.h"

void imgreading(hls::stream<datau32> &inStream, datau32 Imgin[imagesize])
{
    for(int i=0;i<imagesize;i++)
    {
        Imgin[i]=(datau32)inStream.read();
    }
}

void resize_half(hls::stream<datau32> &inStream, hls::stream<datau32> &outStream)
{
#pragma HLS INTERFACE axis port=inStream
#pragma HLS INTERFACE axis port=outStream
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS
    datau32 Imgin[imagesize];
    imgreading (inStream,Imgin);
    datau32 imgOut;
    int coord=0;


#pragma HLS DATAFLOW
    for (int a=0; a<240; a++) {
        for(int b=0; b<320; b++){
#pragma HLS PIPELINE II=1
            coord=6*(a*640+b);
            imgOut=  (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2]) ;
            datau32 dataOutSideChannel;
            dataOutSideChannel.data = imgOut;
            outStream.write (dataOutSideChannel);
        }
    }
}

person Ong Sie SIong    schedule 10.05.2018    source источник


Ответы (1)


Инструмент жалуется, что не может работать с бинарными операторами в imgOut= (0.2126*Imgin[coord] + 0.7152*Imgin[coord+1] + 0.0722*Imgin[coord+2]). Бинарные операторы — это операторы с двумя операндами, здесь * и +. Как указано в сообщении об ошибке, datau32 относится к типу ap_axiu<32, 2, 5, 6>. Imgin и imgOut имеют datau32 в качестве базового типа. Следовательно, сообщение, по-видимому, относится к умножению Imgin[...] на константы с плавающей запятой (0.2126 и т. д.)

В любом случае, ap_axiu используется для объявления шин AXI. Это структура следующего формата (см. стр. 110 UG902 для Vivado HLS 2017.1.):

template<int D,int U,int TI,int TD>
struct ap_axiu{
  ap_uint<D> data;
  ap_uint<D/8> keep;
  ap_uint<D/8> strb;
  ap_uint<U> user;
  ap_uint<1> last;
  ap_uint<TI> id;
  ap_uint<TD> dest;
};

Итак, что вы пытаетесь сделать, это умножить константу с плавающей запятой на структуру. Это не разрешено в C++.

Если вы намеревались использовать шину AXI, вам придется использовать поле data структуры для передачи данных. Результатом умножения целочисленного поля data на double является другое double. double имеет ширину 64 бита, так что вам придется справляться и с этим несоответствием. Вы можете использовать константы типа float, что, вероятно, является достаточной точностью. Или вы можете сделать шину AXI шире. Или вы можете уменьшить точность после вычисления, приведя к float. Или вы можете использовать 2 цикла шины для передачи одного элемента. Обратите внимание, что если вы хотите преобразовать double или float в целое число, вам придется использовать reinterpret_cast, чтобы избежать потери точности. Обратите внимание, что вам также придется присвоить значения всем другим полям структуры ap_axiu. Обратите внимание, что вам также придется присвоить значения всем другим полям структуры ap_axiu (keep, strb и т. д.).

Более простой способ использовать шину AXI — объявить inStream и outStream массивами, например ap_uint<32> inStream[320*240]. Квитирование (TREADY и TVALID) выполняется автоматически. Если вам нужен так называемый сайд-канал (остальные сигналы вроде TLAST или TUSER), вы не можете использовать этот метод. Это может иметь место, например, если вы хотите передавать пакеты данных вместо непрерывного потока (можно сделать с помощью TLAST) или если размер ваших данных не кратен размеру шины, так что вам нужно разрешение байта сигнал (TKEEP).

Я также могу представить, что вы никогда не собирались использовать шину AXI. Существуют такие типы, как ap_uint и ap_fixed, которые можно использовать для передачи данных по обычной шине.

Наконец, я хочу подчеркнуть, что вы всегда должны сначала отлаживать свой код в программном обеспечении. Есть много ошибок, которые трудно решить, основываясь только на результатах синтеза. Некоторые сообщения, как правило, указывают людям неправильное направление. Я рекомендую вам сначала отлаживать свой код, используя функциональность моделирования C. Кроме того, вы можете скомпилировать код вне Vivado HLS с помощью обычного компилятора C, такого как gcc. Я также рекомендую использовать средство проверки памяти, такое как valgrind, чтобы убедиться, что ваш код не записывает за пределы массива и т. д. Инструмент не всегда находит эти проблемы, но приводит к непригодности оборудования.

Я думаю, что это решение, которое вы ищете:

void resize_half(ap_uint<32> inAXI[640 * 480 * 3], ap_uint<32> outAXI[320 * 240])
{
#pragma HLS INTERFACE axis port=inAXI
#pragma HLS INTERFACE axis port=outAXI
#pragma HLS INTERFACE s_axilite port=return bundle=CRTL_BUS

#pragma HLS dataflow
  hls::stream<ap_uint<32> > Stream[3];
  for (int i = 0; i < 480; i++)
    for (int j = 0; j < 640; j++)
      for (int k = 0; k < 3; k++)
      {
#pragma HLS PIPELINE II=1
        ap_uint<32> value = inAXI[3 * (640 * i + j) + k];
        if (i % 2 == 0 && j % 2 == 0)
          Stream[k].write(value);
      }

  for (int a = 0; a < 240; a++)
  {
    for (int b = 0; b < 320; b++)
    {
#pragma HLS PIPELINE II=1
      ap_uint<32> x = Stream[0].read();
      ap_uint<32> y = Stream[1].read();
      ap_uint<32> z = Stream[2].read();
      outAXI[320 * a + b] = 0.2126 * x + 0.7152 * y + 0.0722 * z;
    }
  }
}
person Gyzuh    schedule 11.05.2018
comment
Спасибо за предложение. Я изменил строку кода на Imgin.data, и теперь она работает. Кроме того, я объявляю плавающую точку с помощью ap_fixed. Вы хотите использовать hls::stream‹ap_uint‹32›› inStream[640*480]? - person Ong Sie SIong; 11.05.2018
comment
Большинство моих предложений — это разные способы достижения одной и той же цели, поэтому реализовать их все одновременно, вероятно, не получится. Если вы используете Imgin.data, вы также должны установить другие поля. Использование hls::stream<ap_uint<32>> inStream[640*480] не имеет смысла. Таким образом, вы объявляете потоки 640*480. В сочетании с интерфейсом axis я предлагаю вам использовать ap_uint<32> inStream[640*480] и отказаться от структуры ap_axiu. - person Gyzuh; 11.05.2018
comment
Я понял, что вы имеете в виду, еще один вопрос: я думал, что должен использовать потоковый интерфейс, если я хочу использовать DMA в Vivado IP Integrator позже? - person Ong Sie SIong; 11.05.2018
comment
Вы можете использовать массив или hls::stream и установить его как интерфейс axis, но не оба одновременно. В любом случае, изучив ваш код более внимательно, я заметил, что вы пытаетесь преобразовать изображение с понижением частоты. По сути, вы пропускаете образцы, на что инструмент легко жалуется. Чтобы немного помочь вам, я сделал реализацию, которая синтезирует, и я считаю, что она должна работать, но я признаю, что не проверял ее должным образом. Я поставил это в конце своего ответа. - person Gyzuh; 11.05.2018
comment
На самом деле я пытаюсь одновременно изменить размер и преобразовать оттенки серого для входного изображения 640 * 480. На выходе будет изображение в градациях серого 320*240. Спасибо за код. Я попробую. - person Ong Sie SIong; 11.05.2018