Странности синтеза при работе с FPGA

На сегодняшний день существует два наиболее распространённых языка описания аппаратуры: Verilog/SystemVerilog и VHDL. Сами языки описания аппаратуры являются достаточно универсальными средствами, но всегда ли это так? И от чего может зависеть «не универсальность» языка описания аппаратуры?

Идея написания данной статьи возникла при синтезе одного проекта в разных средах разработки, в результате чего были получены отличные друг от друга результаты. Так как исходный модуль является достаточно объёмным, то для демонстрации полученных результатов был написан тестовый модуль меньшего объёма, но синтез которого вызывал те же предупреждения/ошибки. В качестве тестового модуля был использован 4-х битный регистр с асинхронным сбросом, а в качестве сред разработки были выбраны Libero SoC 18.1, Quartus Prime 17.1, Vivado 2017.4.1.

Сначала представлен вариант описания такого модуля на языке Verilog, текст которого воспринимается выбранными средами разработки верно:

module test1
( 
    input               clk,
    input               arst,
    input       [3:0]   data,
    output reg  [3:0]   q
);

always @( posedge clk or negedge arst ) begin
    if ( ~ arst ) begin
        q <= 4'h0 ;
    end
    else begin
        q <= data ;
    end
end

endmodule

В результате осуществления синтеза данного модуля были получены следующие схемы:

  1. Libero SoC v11.8

    test1 Libero SoC

  2. Quartus Prime 17.1

    test1 Quartus Prime

  3. Vivado 2017.4.1

    test1 Vivado


На всех синтезируемых схемах для test1 были использованы D-триггеры либо с инверсным входом сброса (Quartus Prime), либо с добавлением инвертора (VERIFIC_INV в случае Libero SoC и LUT1 в случае Vivado).

Будет ли отличаться синтезируемая схема, если изменить проверку состояния асинхронного сброса? Для этого необходимо изменить текст модуля test1 на описание модуля test2:

module test2
( 
    input               clk,
    input               arst,
    input       [3:0]   data,
    output reg  [3:0]   q
);

always @(posedge clk or negedge arst) begin
    if (arst) begin
        q<=data;    
    end
    else begin
        q<=4'h0;
    end
end

endmodule

Можно предположить, что синтез модуля test2 не должен отличаться от синтеза модуля test1, так как логики описания обоих модулей не противоречат друг другу. Однако, синтез модуля test2 привёл к следующим результатам:

  1. Libero SoC v11.8
    Синтез схемы осуществился, однако в сообщениях появилось следующее предупреждение «Edge and condition mismatch (CG136)». Данное предупреждение означает несоответствие списка чувствительности и проверки условия сброса. Однако, синтезируемая схема не отличается от модуля test1.

    test2 Libero SoC

  2. Quartus Prime 17.1

    Синтез схемы не осуществился с ошибкой:

    «Error (10200): Verilog HDL Conditional Statement error at test2.v(10): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct». Текст ошибки схож с предупреждением, выданным Libero SoC.
  3. Vivado 2017.4.1

    Синтез схемы осуществился с предупреждением:

    «[Synth 8-5788] Register q_reg in module test is has both Set and reset with same priority. This may cause simulation mismatches. Consider rewriting code ["/home/vlasovdv0111/project_1/project_1.srcs/sources_1/new/test2.v":10]». Также, как и в средах Libero SoC и Quartus Prime было выдано схожее предупреждение. Кроме этого в предупреждении было сказано о возможном несоответствии итогов моделирования и работы в «железе», вследствие этого предложено переписать код модуля.

    test2 Vivado


После описания модулей test1 и test2 появилась идея проверить, что будет, если выполнить синтез следующего кода:

module test3
( 
    input               clk,
    input               arst,
    input       [3:0]   data,
    output reg  [3:0]   q
);

always @(posedge clk or negedge arst) begin
    if (arst) begin
        q<=4'h0;
    end
    else begin
        q<=data;    
    end
end

endmodule

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

Результаты синтеза оказались следующие:

  1. Libero SoC v11.8

    Синтез схемы не осуществился с ошибкой: «Logic for q[3:0] does not match a standard flip-flop (CL123)», тем самым отказавшись производить синтез схемы, сославшись на отсутствие необходимого для синтеза типа триггеров.
  2. Quartus Prime 17.1

    Синтез схемы не осуществился со следующей ошибкой: «Error (10200): Verilog HDL Conditional Statement error at test3.v(9): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct». Текст данной ошибки не отличается от текста ошибки для модуля test2.
  3. Vivado 2017.4.1

    Синтез схемы осуществился без ошибок:

    test3 Vivado


Однако, что будет если описать модуль, в котором список чувствительности не противоречит проверке условия сброса, но при этом сброс триггеров происходит в момент неактивного состоянии линии сброса, как и в случае описания модуля test3. Описание такого модуля test4 следующее:

module test4
( 
    input               clk,
    input               arst,
    input       [3:0]   data,
    output reg  [3:0]   q
);

always @( posedge clk or negedge arst ) begin
    if ( ~ arst ) begin
        q <= data ;
    end
    else begin
        q <= 4'h0 ;
    end
end

endmodule

При синтезе были получены следующие результаты:

  1. Libero SoC v11.8

    Синтез схемы осуществился с предупреждением:

    «Found signal identified as System clock which controls 4 sequential elements including q_1[3]. Using this clock, which has no specified timing constraint, can adversely impact design performance. (MT532)».

    test4 Libero SoC

  2. Quartus Prime 17.1

    В результате синтеза схемы были получены предупреждения:

    «Warning (13004): Presettable and clearable registers converted to equivalent circuits with latches. Registers power-up to an undefined state, and DEVCLRn places the registers in an undefined state.
    Warning (13310): Register "q[0]~reg0" is converted into an equivalent circuit using register "q[0]~reg0_emulated" and latch "q[0]~1"
    Warning (13310): Register "q[1]~reg0" is converted into an equivalent circuit using register "q[1]~reg0_emulated" and latch "q[1]~1"
    Warning (13310): Register "q[2]~reg0" is converted into an equivalent circuit using register "q[2]~reg0_emulated" and latch "q[2]~1"
    Warning (13310): Register "q[3]~reg0" is converted into an equivalent circuit using register "q[3]~reg0_emulated" and latch "q[3]~1"»

    Все вышеописанные предупреждения соответствуют тому, что вместо триггеров были использованы защёлки.

    test4 Quartus Prime

  3. Vivado 2017.4.1

    Синтез схемы осуществился с одним предупреждением:

    «[Synth 8-5788] Register q_reg in module test is has both Set and reset with same priority. This may cause simulation mismatches. Consider rewriting code ["/home/vlasovdv0111/project_1/project_1.srcs/sources_1/new/test.v":11]». Текст данной ошибки полностью повторяет текст ошибки для модуля test2.

    test4 Vivado


Из всех описанных экспериментов можно сделать следующие выводы:

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

Похожие публикации

Комментарии 28
    +2
    Думаю, то, что САПР порой не совсем корректно синтезирует описание на собственном опыте убедился любой серьёзный разработчик)
    Это знаете, когда переходили с совсем низкоуровнего описания схем на HDL возникали резонные вопросы типа «САПР там насинтезирует непойми чего — как это потом работать будет»? Но прошло лет 20 и Verilog/VHDL заняли место прошлого низкоуровневневого собирания схем и теперь те же вопросы возникают относительно той же Vivado HLS, где код пишется на Си, а САПР уже сам выполняет трансляцию в HDL описание. Там порой такие чудеса синтезятся ;) Но, например, низкоскоростные фильтры делать всяко проще, чем Verilog/VHDL разрабатывать, а потом отлаживать.

    а также анализировать списки предупреждений и ошибок, возникающих на каждом этапе построения проекта

    Это, конечно, правильно. Но одно дело, анализировать предупреждения САПР на модуль из 18 строк и совсем другое — когда у тебя только один топ уровень «разлёгся» строк этак тысячи на две, а если посчитать ещё код вложенных модулей, то совсем цифра немалая получится. В таких проектах предупреждений может быть легко до тысячи и не факт, что стоит тратить время на их подробный анализ. Хотя сам по себе список просматривать безусловно стоит и что-то подмечать.

    Я предпочитаю VHDL как более жёсткий и не позволящий выстрелить себе в ногу. Например, в VHDL Check syntax никогда не пропустит присвоение сигналов разной разрядности или несоответствие типов. Ну и в VHDL есть такая штука как типы данных, используя которые можно гибко оперировать матрицами.
      0
      С VHDL к сожалению знаком слабо, только по одному курсу лабораторных работ, однако за то короткое время понял, что он является более строгим языком описания аппаратуры. Этой статьёй хотел обратить внимание новичков, которые только вступают на путь разработки на ПЛИС, на то, что необходимо анализировать ошибки и предупреждения возникающие при разработке. Это также связано с тем, что проведя курс лабораторных работ по описанию аппаратуры на языке Verilog понял, что не все студенты обращают внимание на ошибки и предупреждения, хотя в них обычно и написано, что конкретно не так в дизайне. И конечно согласен, что нет смысла анализировать все предупреждения досконально, но заострять внимание на определённых всё же стоит)
      +8
      для правильного описания аппаратуры необходимо знать синтаксис языка ...

      Неужели? :)
        +3
        для правильного описания аппаратуры необходимо знать синтаксис языка ...


        А ещё нужно знать стандарты конкретно для Verilog стандарт по синтезу есть: Std 1364.1-2002.

        К сожалению вот по SystemVerilog подобного нет, что приводит к некоторым косякам.
          +1
          По поводу примеров: 1 и 4 соответствуют стандарту, 2 и 3 нет. Разница в синтезе 4 это уже приколы самого синтезатора, но по идее работать скорее всего будут одинаково.
            +1
            Тест4 возможно технически соответствует стандарту, но установка неконстантных значений в триггер по асинхронному сигналу — верный путь к приключениям.
          +3
          Можно предположить, что синтез модуля test2 не должен отличаться от синтеза модуля test1, так как логики описания обоих модулей не противоречат друг другу.

          Вы правда думаете, что проверка и низкого и высокого уровня сигнала arst по negedge-фронту этого сигнала — это одно и то же?
          ограничениями которого являются возможности самих сред разработки

          Ограничением является форма глобуса, на который вы пытаетесь натягивать сову. А форма эта не от среды разработки зависит, а от возможностей примитивов конкретного FPGA.
            +3
            P.S. Не используйте асинхронный сброс в FPGA, если не знаете точно, как его готовить. Сколько новичков набили себе шишки на этом — и не передать.
              +3
              Я бы сказал даже не так: не используйте асинхронные схемы в FPGA, если в этом нет острой необходимости. Порой деваться просто некуда и такие штуки приходится применять, тогда надо понимать времянку работы своей схемы и в случае какой-то критичности всегда лучше «повесить» на «асинхронные сигналы» временные ограничения, чтобы потом долго и упорно днями напролёт не выяснять почему эта часть схемы начала глючить после переразводки проекта из-за изменений совсем в другой его части ;)
                +2
                Всё это, что вы (безусловно правильно) написали, как раз я и подразумевал в своём комментарии. Только мне было немного лень вдаваться в подробности. :)
                На самом деле, удручает непонимание многими того факта, что HDL предоставляет существенно больше возможностей, чем FPGA. Особенно verilog, где столько замечательных способов незаметно выстрелить себе в ногу и понять это уже после того, как нога отвалилась из-за гангрены. А потом, когда нога отвалилась, появляются статьи про ограничения сред разработки и плохие синтезаторы.
                Хотя то, что во Vivado не ругается на test3 — это таки косяк синтезатора, на мой взгляд.
                  +1
                  Да мне кажется в некоторой степени даже бесполезно новичков предупреждать об опасностях асинхронной логики или, допустим, пробросе сигналов (особенно шины со стробом) между тактовыми доменами. Это надо самому налететь пару раз, на своей шкуре ощутить коварность этих ситуаций.

                  Я не так давно искал ошибку в проекте, который начал ни с того, ни с сего подглючивать на определённых режимах. ПЛИС уже забит под завязку и начала сказываться времянка, в одном месте был некорректный переход по тактам — вот вам и привет проблеме. Цифровой подмодуль без проблем работал лет этак с пять (!), считался надёжным и проверенным — ну кто мог на него подумать? Подобные проблемы обычно процентов на 75% обычно локализуются аналитически, если у тебя хорошее погружение в проект. В противном случае приходится долго и нудно пользоваться отладчиком — тогда может уйти и несколько дней и пара недель… всего лишь из-за того, что кто-то накосячил с тактовыми переходами ;)
                    +1
                    Ничего бесполезного нет.
                    CDC — один из фундаментальных вопросов в разработке под FPGA.
                    Поэтому правильные техники CDC должны рассматриваться на ранних стадиях обучения FPGA-разработчика.
                    И при адекватном объяснении ментором этих вещей «ощущать коверность на своей шкуре» вообще не придётся :)
                +1
                При разработке ASIC (нет, не про блокчейны), в которых асинхронный сброс/установка является как раз нормой, и прототипировании кода в FPGA переделывать весь код с асинхронного сброса на синхронный обычно не только сложно и бесполезно, но и невозможно ввиду логики работы схемы.
              +4

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



              Конкретно эти ссылки только для примера. Но статья про то, какие есть в этих рекомендациях различия, почему они есть и самое главное — выводы о том, как писать HDL код так, чтобы он удовлетворял и тем и другим рекомендациям была бы намного более полезной, чем выводы:


              для правильного описания аппаратуры необходимо знать синтаксис языка
                +3
                Это мне напомнило код, который иногда мне попадает в руки из проектов коллег, которые писали его еще в 90х — начале 2000х. Там иногда волосы встают дыбом и думаешь как вообще компиляторы тех лет такое хавали и как это уже по 20 лет работает в аппаратуре. Там и тактовые сигналы из асинхронной логики и по 10 разных assign для одного и того же сигнала в модуле, или деленный тактовый сигнал который потом через and и or асинхронно формирует что-то там… Вывод — без знания стандартов и coding style нефига там делать.
                  +2
                  Я бы рекомендовал автору
                  1) Учить verilog либо перейти на VHDL — там /немножко/ меньше шансов отстрелить себе ногу
                  2) Запустить моделирование и убедиться, что test1 и test2 как бы совсем разные устройства, что синтез и показал.
                  3) Посетить electronix.ru в качестве тематического форума
                    +4
                    Моделирование как раз такие говорит, что это одно и то же устройство. С точки зрения стандарта языка Verilog там ошибок нет, а вот с точки зрения синтезируемого подмножества языка Verilog ошибка есть… Так что просто учить verilog тут не поможет…
                    Результаты моделирования до синтеза кому интересно:

                      +1
                      Согласен. Не вчитался в код. Воспользуюсь своим же первым советом — пойду дальше учить верилог, чтобы эффективнее стрелять себе в ногу ;-)
                        0
                        На самом деле, как уже написали выше, в первую очередь следует понять одну простую истину: Verilog и VHDL создавались для моделирования аппаратуры, но не для её создания. Это потом умные люди придумали, что с помощью этих языков можно синтезировать схемы, изначально подобный функционал в них не закладывался, отсюда и некоторые косяки синтеза, особенно когда человек не понимает физики процесса.
                          +4
                          Надо понять простую истину — есть стандарты.
                          И если их нарушать, то будут проблемы.
                          Автору выше уже советовали посмотреть в стандарт IEEE 1364.1-2002, который описывает синтезируемое подмножество языка Verilog.
                          Нужно посмотреть на раздел
                          5.2.2.1 Edge-sensitive storage device modeling with asynchronous set-reset (стр. 9)
                          И сравнитить то, что написано там, с модулем test2.
                        +1
                        Моделирование как раз такие говорит, что это одно и то же устройство.

                        А вы дёрнете сбросом по положительному фронту, а не по отрицательному…
                      +1
                      Вскрытие показало, что чукча умер от вскрытия
                      Да, действительно, если написать код неправильно, то можно получить неожиданный результат. Это и называется Undefined behaviour ;)

                      В Verilog проблема с тем, что полностью корректно описать триггер с асинхронным сбросом невозможно, т.к. в таком элементе сброс работает по уровню, а не по фронту, а в always-блоке можно задавать только либо фронты, либо уровни. Впрочем, и в VHDL это не сильно лучше — список чувствительности в process при моделировании работает только по уровням (что очевидно), хотя в самом тексте и более явно указывается проверка по уровню или проверка по фронту (
                      clk'event and clk = '1'
                      или альяс
                      rising_edge(clk)
                      ). С этой точки зрения и существуют нормативы написания корректно синтезируемых конструкций, указанные в комментариях выше.

                      В SystemVerilog, к слову, есть некоторые расширения (always_ff, always_comb, always_latch), позволяющие организовать дополнительный статический анализ кода и избежать множества ошибок, допустимых в чистом Verilog.
                        0
                        Добрый день
                        Радостно видеть на хабре статьи по ПЛИС тематике, хотелось бы чтобы побольше эту тему как говорится «раскрывали» 
                        Теперь по теме: поправьте меня если я ошибаюсь но мне кажется что результаты Quartus и Libero это и правда результат synthesis. Что же до Vivado то там уже мы видим более продвинутый этап. На схеме видно компоненты BUFG (да и LUTы видно) а это уже реальные компоненты чипа. Получается что хотя бы частично произведен mapping. Так что все же результаты сравнивать (как мне кажется) не совсем корректно.
                        Немного на счёт выводов статьи.
                        1) язык Verilog является универсальным языком описания аппаратуры, ограничениями которого являются возможности самих сред разработки.
                        Мне кажется, что язык ограничен не столько средой разработки сколько строением чипа под который компилируется код. Среда разработки обычно поддерживает последнюю (или почти последнюю версию языка). Дело в том, что нужно очень хорошо понимать какую аппаратуру с помощью этого языка описывают. Ведь от того, что на Verilog описан неведомый компонент (о чём вым пытается намекнуть например Quartus) он не прибавится на реальном чипе.

                        2) для правильного описания аппаратуры необходимо знать синтаксис языка, а также анализировать списки предупреждений и ошибок, возникающих на каждом этапе построения проекта.
                        Мне кажется, что кроме знания синтаксиса очень важно знать и понимать, каков будет резальтат имплементации на чипе той или иной языковой конструкции. Более того, результат будет иногда разительно отличатся если взять один и тот же код и прогнать их на Quartus и Vivado, например. Да, и в том и в другом случае мы получим идентично работающие блоки. Но иногда один или другой компилятор «сожрет» по той или иной причине намного больше или что куда хуже – не те ресурсы.
                          0
                          Добрый день.
                          По поводу:
                          Теперь по теме: поправьте меня если я ошибаюсь но мне кажется что результаты Quartus и Libero это и правда результат synthesis. Что же до Vivado то там уже мы видим более продвинутый этап.

                          Как в Quartus и Libero SoC так и в Vivado были взяты для рассмотрения одинаковые этапы синтеза, но видимо в Vivado изначально было принято так отображать синтезируемую схему (Если не так, то надеюсь меня поправят).
                          На счёт замечаний по поводу выводов статьи, они будут исправлены, возможно как и остальной текст. И да кроме знания синтаксиса языка также необходимо знать основы цифровой схемотехники, стандарт используемого языка, и много чего ещё. При переносе одного проекта от одной среды разработки к другой также может возникнуть ряд сложностей, например, среда Quartus не поддерживает тип real, хотя Libero SoC и Vivado, насколько я помню, правильно их интерпретируют. Помимо этого все среды разработки позволяют выбирать стандарты языка используемого для дизайна.
                            +3
                            Мне кажется, в примере test2 вы себе таки сами стреляете в ногу.
                            В Verilog не 2 возможных значения входа (0 и 1), а четыре: 0, 1, z, x.
                            Условие вида if(~arst) транслируется в if(arst==0), то есть, определённое состояние. А вот ветка else для if(arst) превращается в if(arst==0 || arst==z || arst==x), чего достаточно, чтобы сбить с толку большинство синтезаторов самим фактом, что можно что-то проверять по условию вида arst==x. В результате это условие просто выкидывается из проверки, но с предупреждением, что так нельзя, или же оно вообще может начать делать что-то запредельно неожиданное. Я бы такое не пропускал вообще, но нельзя от программы требовать того же, что от человека, по уровню интеллекта.

                            В программировании есть аналогичная ситуация с плавающими числами: if(a==b) нельзя превратить в if(!(a!=b)), потому что есть случай несравнимости чисел (хотя одно из них равно NaN), при котором a==b и a!=b оба ложны.

                            С test3 более очевидно, что проверять на 1 после отрицательного фронта нелогично.
                              0
                              Добрый день, да я с вами полностью согласен, но дело в том, что эта статья писалась с целью того, как ненужно описывать аппаратуру и что необходимо следить за тем, что происходит в проекте (ошибки, предупреждения и много чего ещё). Кроме этого в статье не отражены результаты симуляции, которые стоит добавить впоследствии.
                              Изначально я описал аппаратуру согласно описанию test2, который успешно синтезировался и работал на SmartFusion2, однако при попытке перенести его на Cyclone IV возникли проблемы, которые я впоследствии понял. Модули test3 и test4 я проверил чисто из интереса, а именно как их вообще могут воспринять выбранные среды разработки.
                              И собственно этой статьей я хотел обратить внимание начинающих разработчиков FPGA на то, что необходимо придерживаться стандартов языков, а также понимать что такое FPGA и из чего она состоит. Через некоторое время я постараюсь переписать выводы статьи.
                              0
                              С verilog не знаком, больше по vhdl, ко второму пункту бы добавил, что для выбранной среды и выбранной технологии/семейства неплохо изучить набор template-ов и правил inferring-a (для Vivado и то и другое прописано). То, что вы отметили, на мой взгляд, не совсем касается универсальности синтеза или языка, а больше относится к возможностям распознавания аппаратных идиом (не знаю как точнее по-русски назвать «inferring»).
                                +1
                                Здравствуйте. Действительно достаточно интересная статья с несколькими нюансами. Как указано пользователем Wilderwein очень важно понимать на каком чипе ведется разработка. По моей памяти, к примеру, Spartan 6 нивкакую не хотел адекватно реагировать на синхронный set, при том что aset и arst синтезировал отлично (там большой вопрос в строении LUT). И то же касается всех остальных чипов. Они только для студента и системного инженера «полностью программируемые». По факту же для разработки нужно понимать как разрабатывать на чипе и чем больше уровень понимания, тем выше профессионализм разработчика.
                                По указанным примерам. Я проектирую на VHDL, но попытка сбросить по положительному фронту if (arst) begin при списке чувствительности отрицательного фронте negedge arst вызывает конфуз даже у схемотехника. Что говорить об синтезаторе. Из чего следует, что как миним перед проектированием следует ознакомится с соответствующим кодстайлом и не использовать «придуманные» конструкции либо быть готовым к «абракрадабре» после синтеза.
                                з.ы. На картинках Vivado указаны уже синтезированные конструкции от чего ненужные буферы и т.п. Для просмотра схематика достаточно вызвать Elaborated Design — и проще, и не требует пересинтезировать каждый раз.

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

                                Самое читаемое