Перейти к содержанию
    

Очередной мегаперл от квартуса

Наткнулся на очередной перл от квартуса. В этот раз 14.1.

Итак положим есть проект, в котором есть хитро сгенерированные таблицы :

module test_pipa (input logic iclk, input logic [3 : 0] addr, input logic [1 : 0] sel, output logic [7 : 0] odat);

  typedef int tab_t [4][16];

  tab_t tab;

  assign tab = get_tab(0);

  function automatic tab_t get_tab (input bit nul);
    get_tab = '{
      '{1, 43, 435, 21, 44, 976, 53, 4, 11, 143, 35, 121, 144, 76, 153, 14},
      '{5, 543, 35, 521, 544, 76, 553, 54, 511, 43, 535, 21, 44, 576, 53, 514},
      '{2, 243, 235,121, 544, 6, 3, 674, 611, 3143, 835, 3121, 1144, 976, 6153, 414},
      '{2, 293, 235,121, 599, 6, 3, 679, 611, 3193, 835, 3121, 1199, 976, 6153, 919}
      };
  endfunction

  typedef logic [7 :0] btab_t [4][16];

  btab_t btab;

  assign btab = get_btab(0);  // 5LC/5REG AriaV 
//assign btab = get_btab2(0); // 21LC/5REG (????)

  always_ff @(posedge iclk) begin
    odat <= btab[sel][addr];
  end

  function automatic btab_t get_btab (input bit nul);
    tab_t mtab;
    //
    mtab = get_tab(0);
    //
    for (int i = 0; i < 4; i++) begin
      for (int j = 0; j < 16; j++) begin
        get_btab[i][j] = (35 + 3*mtab[i][j] % 27) % 35;
      end
    end
  endfunction

  function automatic btab_t get_btab2 (input bit nul);
    for (int i = 0; i < 4; i++) begin
      for (int j = 0; j < 16; j++) begin
        get_btab2[i][j] = (35 + 3*tab[i][j] % 27) % 35;
      end
    end
  endfunction

endmodule

В зависимости от того какая функция используется get_btab/get_btap2 ресурс для 5 ой арии/сыклона отличается в 4 раза, можете проверить :) Причем во втором случае находиться кучка делителей, занимающих нулевой ресурс, но при этом сам модуль значительно толще.

 

Судя по всему есть там баг, с доступом к константным массивам находящимися выше по иерархии. Он считает их не константными и пихает под них логику, которая не используется. Эффект проверен начиная с 9.1. Будьте внимательны

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Интересно, если объявлять константы с const или localparam, баг тоже будет проявляться?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Интересно, если объявлять константы с const или localparam, баг тоже будет проявляться?

квалификатор const насколько я помню не поддерживается квартусами (до 9.1 точно).

с localparam ом возможны различные глюки : несмотря на то, что в стандарте четко оговорена последовательность анализа константных параметров, разные версии квартуса не всегда понимают это корректно, квеста тоже (причем тупо не инициализирует константы), поэтому на сигналах самый безопасный вариант.

 

ЗЫ. Имеются в виду параметры - одномерные и многомерные массивы. С числами проблем я не замечал (ну кроме квартуса 8.1)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

есть два типа оптимизации:

1) оптимизация внутри функций, имеющая все необходимые инструменты для всяких там loop unroll и прочих программизмов SV

2) оптимизация логики на основе анализа графа

 

внутри функции работает 1), до генерации логики, и если ему доступно значение чисел - есть локальная переменная в которую вы скопировали сигналы (а фактически скопировались константы), то оптимизация отрабатывает на ура.

в противном случае он видит глобальные сигналы, и не проверяя их (не положено!) генерит полную логику функции. и скармливает оптимизатору 2)

 

отсюда и разница.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

внутри функции работает 1), до генерации логики, и если ему доступно значение чисел - есть локальная переменная в которую вы скопировали сигналы (а фактически скопировались константы), то оптимизация отрабатывает на ура.

в противном случае он видит глобальные сигналы, и не проверяя их (не положено!) генерит полную логику функции. и скармливает оптимизатору 2)

 

отсюда и разница.

Логично, была такая версия. Но тогда непонятен вот такой момент. Меняем немного код :

  function automatic btab_t get_btab2 (input bit nul);
    for (int i = 0; i < 4; i++) begin
      for (int j = 0; j < 16; j++) begin
        //get_btab2[i][j] = (35 + 3*tab[i][j] % 27) % 35;
        get_btab2[i][j] = mod(35 + mod(3*tab[i][j], 27), 35);
      end
    end
  endfunction

  function automatic int mod (input int a, int base);
    int tmp;
    mod = a;
    for (int i = 0; i < 5; i++) begin // правда тут цифры 5 мало, т.к.  6153/27 = 227. Но для общности изложения пойдет. 
      if (mod >= base)
        mod = (mod - base);
      else
        break;
    end
  endfunction

И вуаля, то что доктор прописал. Но это похоже уже оптимизатор постарался. Дооптимизировал таки.

 

и до кучи, упростим задачу : сделаем матрицу параметров одномерной.

module test_popa (input logic iclk, input logic [3 : 0] addr, output logic [7 : 0] odat);

  typedef int tab_t [16];

  tab_t tab;

  assign tab = get_tab(0);

  function automatic tab_t get_tab (input bit nul);
    get_tab = '{5, 543, 35, 521, 544, 76, 553, 54, 511, 43, 535, 21, 44, 576, 53, 514};
  endfunction

  typedef logic [7 :0] btab_t [16];

  btab_t btab;

  assign btab = get_btab(0);  // 5LC/5REG
//assign btab = get_btab2(0); // 5LC/5REG 

  always_ff @(posedge iclk) begin
    odat <= btab[addr];
  end

  function automatic btab_t get_btab (input bit nul);
    tab_t mtab;
    //
    mtab = get_tab(0);
    //
    for (int j = 0; j < 16; j++) begin
      get_btab[j] = (35 + 3*mtab[j] % 27) % 35;
    end
  endfunction

  function automatic btab_t get_btab2 (input bit nul);
    for (int j = 0; j < 16; j++) begin
      get_btab2[j] = (35 + 3*tab[j] % 27) % 35;
    end
  endfunction

endmodule

результат одинаковый. т.е. идея с оптимизацией дюже избирательна :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в первом куске кода опять-таки есть момент копирования констант в момент вызова функции mod ( строчка mod = a;) т.е. оптимизатор 1) имеет значения констант, что позволяет иметь в момент сборки функции get_btab2 всё, чтобы сгенерировать минимальную логику.

 

а со вторым куском кода оптимизатор типа 2) лучше справился, просто из-за меньшего размера исходного графа перед оптимизацией.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в первом куске кода опять-таки есть момент копирования констант в момент вызова функции mod ( строчка mod = a;) т.е. оптимизатор 1) имеет значения констант

не соглашусь, это чисто верилоговская фенечка и

assign btab = get_btab3(tab);
...
  function automatic btab_t get_btab3 (input tab_t tab);
    tab_t mtab;
    mtab = tab;
    for (int i = 0; i < 4; i++) begin
      for (int j = 0; j < 16; j++) begin
        get_btab3[i][j] = (35 + 3*tab[i][j] % 27) % 35;
      end
    end
  endfunction

дает такой же попсовый результат

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

попсовый - это какой?

 

function automatic btab_t get_btab3 (input tab_t tab);

тут вы сами запретили копирование значений в тело функции, явно указав что на вход придут априори неизвестные сигналы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

попсовый - это какой?

ресурс в 4 раза больше.

 

тут вы сами запретили копирование значений в тело функции, явно указав что на вход придут априори неизвестные сигналы.

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

 

Резюмирую тему : способов передачи параметров в подобных примерах 2 : сгенерировать таблицу внутри функции или передать ее снаружи (через интерфейс функции или через глобальное пространство имен).

Примеры показывают что результат синтеза функции с передачей параметров зависит от размерности таблицы. Одномерные таблицы, пусть и большие прекрасно оптимизируются, многомерные (даже маленькие) оптимизируются из рук вон плохо. Сей момент надо теперь помнить при разработке как фичу.

 

Причем забавно, что когда смотришь на уровни элементов ПЛИСа, там тупо висят константы в лютах, но заведение этих констант в рабочую логику приводит к увеличению слоев логики и тактовая падает процентов на 20.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

а другого способа, если исключить генерацию таблицы внутри, нет

бинго.

 

логика синтезируется только для вызываемой функции самого верхнего уровня.

при этом синтезатор просматривает на всю глубину - т.е. при вызове функции "BBB" внутри функции "AAA" сначала производится получение выходного значения функции "BBB" без генерации логики для "BBB".

 

В этом способе синтезатор не может не видеть что на вход функции приходят константы.

ага, но только после синтеза соответствующей логики для функции.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...