Оптимизация параметров FPGA матриц за счет правильного HDL кодирования

    Первоисточник

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

    Если бы мы жили в идеальном мире, существующие инструменты синтеза логических схем могли бы толковать и эксплуатировать различные архитектуры программируемых пользователем вентильных матриц (FPGA) и их специальные функции без вмешательства разработчика. В реальном мире всё не так легко. Приложения, от которых требуется высокая производительность и плотность размещения логики, являются очень критичными к используемому разработчиком стилю кодирования. Для получения оптимальных результатов необходимо понимание архитектуры матриц FPGA, принципов работы инструментов синтеза схем и программного обеспечения конечной трассировки.

    Большинство устройств FPGA состоят не из множества малых элементарных ячеек, а из набора программируемых функциональных блоков (Programmable Functional Units, PFU), реализующих комбинационную логику на основе поисковых таблиц (LUT), и некоторого количества триггеров или регистров. Ниже приводится список некоторых особенностей матриц FPGA, без учёта которых могут возникнуть трудности при использовании стандартных инструментов синтеза:
    триггеры внутри блоков PFU совместно используют некоторые сигналы управления, например, сигналы синхронизации, разрешения синхронизации и сброса/установки. В архитектуре ORCA, например, возможно реализовать четыре триггера в одном функциональном блоке PFU при условии, что они имеют одинаковые вышеупомянутые сигналы. Большинство инструментов синтеза этого не понимает. Если проект был закодирован без учёта этого факта, то набор триггеров использовался бы неэффективно, что привело бы к значительному увеличению размера кристалла микросхемы;

    запоминающие элементы внутри матрицы FPGA могут быть реализованы на блоках PFU в её LUT части. Такой метод создания модулей ОЗУ или ПЗУ внутри FPGA позволяет сэкономить большое количество логических элементов и значительно улучшает быстродействие устройства. К сожалению, в HDL не имеется никакого способа реализовать модули памяти. Следовательно, инструменты синтеза не могут обнаружить их присутствие, чтобы затем использовать функцию табличного поиска матриц FPGA;

    реализация счётчиков и конечных автоматов также затруднена. Так как имеется большое количество различных видов этих схем, использование какой-либо определённой из них целиком определяется приложением. Выбор наиболее эффективного метода в значительной степени определяется знанием архитектуры устройства FPGA;

    иерархия проекта и разработка общей топологии кристалла для инструментов синтеза — задача также достаточно сложная;

    сигнал глобального сброса (Global Set Reset, GSR) представляет собой внутренне маршрутизируемый сигнал, который не потребляет никаких ресурсов маршрутизации микросхемы. В настоящее время реализовать эту функцию в языке VHDL принципиально невозможно. Следовательно, инструменты синтеза не могут использовать эту функцию, так как GSR компонент никак не описывается в коде HDL.

    Имеются три основных метода написания VHDL кода. Ниже они представлены в порядке возрастания эффективности:
    Общий код, который не привязан к архитектуре.
    Общий код, привязанный к архитектуре используемого устройства.
    HDL код с макроконкретизацией.

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

    Синхронная логика

    Триггеры и защёлки в большинстве устройств FPGA на основе поисковых таблиц могут быть сконфигурированы в синхронном режиме сброса/установки с использованием назначаемого разработ-чиком локального сигнала сброса (Local Set Reset, LSR). Для правильной реализации защёлки или триггера, инструмент синтеза должен найти в библиотеке соответствующий макрос. Этого не произойдет, если HDL код не будет содержать правильное описание элемента, а поэтому требование общего понимания архитектуры устройств FPGA надо считать обязательным.

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

    В каждом программируемом функциональном блоке (PFU) может быть реализовано несколько защёлок и/или триггеров, которые совместно используют некоторые из его входов. Чтобы получить максимальную эффективность использования площади кристалла, защёлки и триггеры должны быть сгруппированы по несколько штук, чтобы оптимально использовать объём блоков PFU.

    Если требуется синхронная работа триггера, то глобальный сигнал сброса (GSR) здесь не подойдет, так как он обеспечивает только асинхронный режим работы. Несмотря на это, он может быть использован совместно с сигналом локального сброса (LSR).

    Если код подразумевает использование стробированного сигнала разрешения синхронизации (Clock Enable, CE), инструмент синтеза имеет тенденцию дублировать разрешающую логику для каждого регистра проекта. Чтобы избежать этого, рекомендуется держать стробированные сигналы в отдельной процедуре, а затем подавать их на CE вход главного модуля.

    Чтобы реализовать правильный триггер, код HDL должен корректно описать его функционирование. Например, приведенный ниже листинг кода используется, чтобы реализовать двухбитовый регистр с уровнем синхронного сброса +VE, и уровнем +VE сигнала разрешения:


    DO <= D1 AND D2;
    SYNC_RST : Process (CLK, RST)
    begin
    if (CLK’event and CLK=’1’) then
    if (RST = ’1’) then
    DATA_OUT <= (others => ’0’);
    elsif (DO = ’1’) then
    DATA_OUT <= DATA_IN ;
    end if;
    end if;
    end process SYNC_RST;

    Обратите внимание, что здесь, чтобы корректно осуществить син-хронный сброс, оператор “if (RST = ’1’) then” должен быть введён внутри процедуры после оператора с CLK’event. А для того, чтобы связать “DO” с входом CE триггера, оператор “elsif (DO = ’1’) then” должен стоять после “if (RST = ’1’) then”.

    При использовании такого подхода надо быть очень бдительным, так как некоторые инструменты синтеза имеют ограничения в осуществлении режима синхронного сброса/установки. В итоге могут быть получены некоторые непредсказуемые результаты, которые, хотя они и будут правильны функционально, пагубно отразятся на быстродействии и объёме конечных схем. Сигнал DO связан с входом CE триггера только в случае, если HDL код реализован, как показано в предыдущем примере. К тому же, некоторые сигналы не предполагалось подавать на CE порт. Но известно, что они будут присутствовать, если разработчик не знает точно, какой алгоритм закончится CE связью. Рассмотрим:


    SYNC_RST : Process (CLK,RST)
    begin
    if (CLK’event and CLK=’1’) then
    if (D1 = ’0’ and DATA_IN = ’10’) then
    DATA_OUT(0) <= DATA_IN(0);
    elsif (D2 = ’0’ and DATA_IN = ’01’) then
    DATA_OUT(1) <= DATA_IN(1);
    end if;
    end if;
    end process SYNC_RST;

    Приведённый в этом листинге код произведет два триггера с двумя различными сигналами CE по двум причинам. Во-первых, в процедуре имеется несколько неопределённых состояний (например, состояние, когда D1 = ’1’ и DATA_IN = ’10’). Во-вторых, не все возможные выходы для определённых состояний были определены в каждом операторе “if”.

    Обе эти причины вынудят инструмент синтеза использовать порт CE триггера, чтобы сохранить их предыдущие состояния. В результате, эта схема потребует две программируемых логических ячейки (PLC) вместо одной. Чтобы избежать таких моментов, снижающих эффективность проектирования, при написании HDL кода пользуйтесь следующими правилами:
    всегда старайтесь группировать по четыре триггера под каждым оператором “if”;
    старайтесь определить все возможные состояния сигналов управления и статус выходов регистра для каждого из этих состояний.

    if (CLK’event and CLK=’1’) then
    if (D1 = ’0’) then
    DATA_OUT <= ’01’;
    elsif (D2 = ’0’) then
    DATA_OUT <= ’10’;
    else
    DATA_OUT <= DATA_IN;
    end if;
    end if;

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