СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА

в 2:44, , рубрики: fpga, shift register, Verilog, vhdl, ПЛИС, синтез

Сдвиговый регистр – это одна из наиболее часто применяемых конструкций в проектах на ПЛИС. Сегодня мы уделим внимание тому, как можно и нужно писать VHDL и Verilog код для сдвиговых регистров, но при этом, чтобы синтезатор понял, что мы хотим реализовать сдвиговый регистр из нескольких триггеров или же задействовать для его реализации специальные ресурсы, такие как SRL регистры.

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

Введение

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

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

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

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 1

Как и следует из названия, сдвиговый регистр что-то сдвигает, а именно входящие данные.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 2

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

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

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 3

Сдвиговые регистры могут иметь различный функционал, в зависимости от решаемой вами задачи. Они могут :

  • Иметь управляющие сигналы, такие как сброс и сигнал разрешения тактовой частоты clock enable

  • Иметь вход загрузки данных для сдвига – то есть выступать в качестве серилайзера

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 4
  • Иметь разрешающий сигнал параллельной выгрузки данных – то есть выступать в качестве десерилайзера

  • Иметь отводы от некоторых триггеров – таки образом строятся генераторы псевдослучайных последовательностей

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 5
  • Иметь отводы и управляющий мультиплексор для создания динамической линии задержки

  • Выход сдвигового регистра может быть соединен с входом сдвигового регистра – таким образом можно циклически прокручивать заранее записанные данные по кругу.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 6

Кстати, такой прием мы использовали на одном из наших стримов по реализации интерфейса SPI на ПЛИС для работы с АЦП, ссылка на этот стрим

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 7

Несколько слов о применении сдвиговых регистров. Наиболее часто их применяют:

  • для задержки сигналов на определенное количество тактов, причем величина задержки может быть как фиксированной, так и переменной величиной

  • для построения генераторов псевдослучайных последовательностей

  • для реализации серилайзеров и десерилайзеров

  • для проигрывания зацикленных данных

  • для реализации регистра барабанного сдвига – barrel shifter, применяемого, например, для сложения и вычитания чисел с плавающей точкой, где он производит нормализацию мантисс

  • для реализации счетчиков и тд.

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

Перед тем как мы начнем, сделаю небольшое отступление. Надо помнить, что не все ПЛИС имеют сдвиговый регистр как аппаратный специально выделенный ресурс. Чтобы понять, есть ли он в вашей ПЛИС или нет нужно обратиться к документации на выбранную микросхему и посмотреть наличие SRL или Shift Register примитива в архитектуре. В наших примерах мы будем использовать микросхемы 7-ой серии для Xilinx и Cyclone V для Intel/Altera

 

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 8

Перейдем к практике

Описать сдвиговый регистр на VHDL или Verilog достаточно просто.

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

Для VHDL
library ieee;
use ieee.std_logic_1164.all;

entity srl_1_vhdl is
    port ( 
        id      : in std_logic;
        iclk    : in std_logic;
        oq      : out std_logic);
end srl_1_vhdl;

architecture rtl of srl_1_vhdl is

    signal dff0, dff1, dff2, dff3, dff4 : std_logic := '0';

begin
    
    srl_1 : process (iclk) begin
        if rising_edge(iclk) then
            dff0 <= id;
            dff1 <= dff0;
            dff2 <= dff1;
            dff3 <= dff2;
            dff4 <= dff3;
        end if;
    end process srl_1;
    
    oq <= dff4;
    
end rtl;

Для Verilog
module srl_1_verilog(
    input id,
    input iclk,
    output oq
    );
    
    reg dff0, dff1, dff2, dff3, dff4 = 1'b0;
    
    always @(posedge iclk) begin
      dff0 <= id;
      dff1 <= dff0;
      dff2 <= dff1;
      dff3 <= dff2;
      dff4 <= dff3;
    end
    assign oq = dff4;
endmodule

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

для VHDL
library ieee;
use ieee.std_logic_1164.all;

entity srl_2_vhdl is
    port ( 
        id      : in std_logic;
        iclk    : in std_logic;
        oq      : out std_logic);
end srl_2_vhdl;

architecture rtl of srl_2_vhdl is

    signal dff : std_logic_vector( 4 downto 0 ) := (others => '0');

begin
    
    srl_2 : process (iclk) begin
        if rising_edge(iclk) then
            dff <= dff(3 downto 0) & id;
        end if;
    end process srl_2;
    
    oq <= dff(4);
    
end rtl;

и для Verilog
module srl_2_verilog(
    input id,
    input iclk,
    output oq
    );
     
   reg [4:0] dff = 5'b00000;
    always @(posedge iclk) begin
      dff <= {dff[3:0], id};
    end
    
    assign oq = dff[4];
    
endmodule

Или вот так, используя цикл for на языке VHDL

на языке VHDL
library ieee;
use ieee.std_logic_1164.all;

entity srl_3_vhdl is
    port ( 
        id      : in std_logic;
        iclk    : in std_logic;
        oq      : out std_logic);
end srl_3_vhdl;

architecture rtl of srl_3_vhdl is

    signal dff : std_logic_vector( 4 downto 0 ) := (others => '0');

begin
    
    srl_3 : process (iclk) begin
        if rising_edge(iclk) then
            dff(0) <= id;
            for i in 0 to 3 loop
                dff(i + 1) <= dff(i);
            end loop;           
        end if;
    end process srl_3;
    
    oq <= dff(4);
    
end rtl;

на Verilog
module srl_3_verilog(
    input id,
    input iclk,
    output oq
  );

  reg [4:0] dff = 5'b00000;
  integer i;

  always @(posedge iclk)
  begin
    dff[0] <= id;
    for (i = 0; i < 4; i=i+1)
    begin
      dff[i + 1] <= dff[i]
       end
     end

     assign oq = dff[4];

endmodule

Здесь как говорится на вкус и цвет. Если вы хотите дополнить проект своими вариантами реализации и описания сдвиговых регистров, делайте пул реквесты в гит репозиторий,  или же оставляйте ваш код в комментариях.

Я привел по три варианта реализации, но суть от этого не меняется.

Нам важно понять, каким образом мы можем управлять синтезатором, чтобы получить либо цепочку из отдельных триггеров, либо специально выделенный аппаратный ресурс. Нам нужно найти такие инструменты и средства либо языка описания аппаратуры VHDL или Verilog либо настройки синтеза в самих средах проектирования, таких как Quartus или Vivado, которые помогли бы нам решить поставленную задачу.

Атрибуты в языках описания аппаратуры

Мы начнем со средств языков описания аппаратуры VHDL и Verilog. Влиять напрямую на синтез мы можем с помощью специальной языковой конструкции, которая называется атрибут. Атрибуты есть как в VHDL так и в Verilog. Синтаксис атрибутов следующий

 Для VHDL он задается с помощью объявления атрибута, имени или идентификатора атрибута и типа атрибута. Затем записывается то, к чему атрибут присваивается: entity | architec.| procedure | function | package и тд и затем значение атрибута.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 9

На практике это выглядит примерно вот так,

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 10

здесь атрибут CASCADE_HEIGHT применяется к сигналу ram, а значение атрибута равно 4.

Для языка Verilog атрибут задается непосредственно перед объявлением чего-либо, и записывается внутри специальной конструкции из скобочек и звездочек.  Тот же атрибут CASCADE_HEIGHT на языке Verilog задается следующим образом

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 11

Следует обратить внимание на тот факт, что разные среды проектирования поддерживают разные атрибуты. Атрибуты могут выполнять одну и ту же задачу, но при этом иметь разные названия и значения. Например, приведенный ранее атрибут CASCADE_HEIGHT есть в Vivado, но отсутствует в Quartus.

Где же искать список поддерживаемых атрибутов?

О том, какие атрибуты поддерживает среда проектирования нужно смотреть в документации.

Если вы используете среду Xilinx Vivado, то ваш основной помощник это User Guide 901 или гайд по синтезу. В этом гайде собрано много интересных и полезных советов и правил. Обязательно с ним познакомьтесь, если еще не сделали этого.

Если же вы используете среду Intel Quartus, том пригодится Quartus II Handbook. В конце статьи вы найдете необходимые ссылки.

 Ну что, давайте опробуем атрибуты на практике: для VHDL и Verilog, для Vivado и Quartus

Практика использования атрибутов

Для демонстрации мы будем использовать параметризированный вариант кода описания сдвигового регистра. Мы задами длину задержки или длину цепочки параметром SRL_LENGTH.

 Мы рассмотрим две реализации: VHDL+Vivado и Verilog+Quartus. Однако исходники будут доступны и для связки VERILOG+Vivado и VHDL+Quatus. Каких-то принципиальных отличий вы не найдете, поскольку синтаксис атрибутов одинаковый, а отличаются они лишь в части названия атрибута и его значения. К тому же я оставил ссылки на дополнительную литературу в конце статьи, и вы всегда сможете самостоятельно пополнить свой багаж знаний и попрактиковаться.

 Начнем с VHDL и Vivado.

Код для параметризированного варианта для языка VHDL без атрибута будет выглядеть следующим образом.

VHDL
library ieee;
use ieee.std_logic_1164.all;

entity srl_4_vhdl is
    generic (
        SRL_LENGTH : natural := 32
    );
    port ( 
        id      : in std_logic;
        iclk    : in std_logic;
        oq      : out std_logic);
end srl_4_vhdl;

architecture rtl of srl_4_vhdl is

    signal dff : std_logic_vector( SRL_LENGTH - 1 downto 0 ) := (others => '0');

begin
    
    srl_4 : process (iclk) begin
        if rising_edge(iclk) then
            dff(0) <= id;
            for i in 0 to SRL_LENGTH - 2 loop
                dff(i + 1) <= dff(i);
            end loop;           
        end if;
    end process srl_4;
    
    oq <= dff(SRL_LENGTH - 1);
    
end rtl;

 Давайте выполним синтез в вивадо и посмотрим на результат.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 12

Как мы видим, получилась длинная цепочка, содержащая 32 триггера.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 13

Теперь обратимся к UG901 и добавим атрибут SHREG_EXTRACT.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 14

Данный атрибут позволит среде проектирования обнаружить цепочку регистров и реализовать ее как аппаратный ресурс. Добавим этот атрибут в наш код

VHDL
library ieee;
use ieee.std_logic_1164.all;

entity srl_5_vhdl_attr is
    generic (
        SRL_LENGTH : natural := 32
    );
    port ( 
        id      : in std_logic;
        iclk    : in std_logic;
        oq      : out std_logic);
end srl_5_vhdl_attr;

architecture rtl of srl_5_vhdl_attr is

    signal dff : std_logic_vector( SRL_LENGTH - 1 downto 0 ) := (others => '0');
    
    attribute shreg_extract : string;
    attribute shreg_extract of dff : signal is "yes";
    
begin
    
    srl_5 : process (iclk) begin
        if rising_edge(iclk) then
            dff(0) <= id;
            for i in 0 to SRL_LENGTH - 2 loop
                dff(i + 1) <= dff(i);
            end loop;           
        end if;
    end process srl_5;
    
    oq <= dff(SRL_LENGTH - 1);
    
end rtl;

После синтеза мы увидим, что регистры с 1 по 30 были объединены в один аппаратный блок. То есть вместо 32 триггеров у нас теперь всего 2 триггера с номерами 0 и 31 и один аппаратный сдвиговый регистр.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 15

Вы наверняка зададите вопрос: «Почему остались регистры 0 и 31? Почему они не были объединены с остальными 30-ю триггерами? ведь ресурс SLR32 может обеспечить задержку на 32 такта».

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 16

Ответ тут кроется в настройках по умолчанию. Если вы проявите чуть больший интерес к UG901, то сможете найти атрибут SRL_STYLE, который отвечает за окончательный вид сдвиговых регистров. Данный атрибут имеет 6 доступных значений или 6 вариантов реализации.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 17

Давайте попробуем добавить еще 1 атрибут в наш код. Это будет атрибут SRL_STYLE со значением srl

VHDL
library ieee;
use ieee.std_logic_1164.all;

entity srl_6_vhdl_attr_2 is
    generic (
        SRL_LENGTH : natural := 32
    );
    port ( 
        id      : in std_logic;
        iclk    : in std_logic;
        oq      : out std_logic);
end srl_6_vhdl_attr_2;

architecture rtl of srl_6_vhdl_attr_2 is

    signal dff : std_logic_vector( SRL_LENGTH - 1 downto 0 ) := (others => '0');
    
    attribute shreg_extract : string;
    attribute shreg_extract of dff : signal is "yes";
    
    attribute srl_style : string;
    attribute srl_style of dff : signal is "srl";
    
begin
    
    srl_6 : process (iclk) begin
        if rising_edge(iclk) then
            dff(0) <= id;
            for i in 0 to SRL_LENGTH - 2 loop
                dff(i + 1) <= dff(i);
            end loop;           
        end if;
    end process srl_6;
    
    oq <= dff(SRL_LENGTH - 1);
    
end rtl;

и посмотрим, что получится.

 Как видите, все наши триггеры были упакованы в один сдвиговый регистр.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 18

Чудеса, не так ли. Всего пара строк кода и мы сэкономили кучу ресурсов. Поиграйтесь с кодом, задайте разную длину сдвиговому регистру и поменяйте значения атрибутов. Посмотрите и сравните результаты. Посмотрите, что произойдет, если длина цепочки будет больше 32-х. Ну а мы движемся далее и на очереди у нас код на Verilog для пользователей Quartus

 Для экспериментов с Intel взят кристалл серии Cyclone V, в котором реализация аппаратного сдвигового регистра сделана на блочной памяти. Однако, тут есть нюанс. Согласно документации преобразование из цепочки триггеров в аппаратный блок делается только при длине цепочки более 64:

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 19

но поскольку у нас с вами имеется параметризированный верилог код для сдвигового регистра:

Verilog
module srl_4_verilog(
    input id,
    input iclk,
    output oq
    );
   
    parameter SRL_LENGTH = 128;
   
    reg [SRL_LENGTH-1:0] dff;
   
    integer i;
    
    always @(posedge iclk) begin
   
      dff[0] <= id;
    
      for (i = 0; i < SRL_LENGTH-1; i = i+1) begin
        dff[i + 1] <= dff[i];
      end
    
    end
    
    assign oq = dff[SRL_LENGTH-1];
    
endmodule

то мы просто изменим длину с 32 на 128 и запустим синтез.

 Как мы видим, что по умолчанию имплементируется цепочка триггеров.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 20

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

 Давайте теперь попробуем применить атрибут для упаковки нашей цепочки аппаратный примитив, который для Cyclone V делается на блочной памяти. Чтобы это осуществить мы воспользуемся атрибутом altera_attribute со значением «-name AUTO_SHIFT_REGISTER_RECOGNITION ON»

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 21

Данный атрибут мы пропишем перед объявлением нашего вектора reg_dff.

 Код будет выглядеть следующим образом.

Verilog
module srl_5_verilog_attr(
    input id,
    input iclk,
    output oq
    );
    parameter SRL_LENGTH = 128;
    
   (* altera_attribute = "-name AUTO_SHIFT_REGISTER_RECOGNITION ON" *)reg [SRL_LENGTH-1:0] dff;
    
   integer i;
    
    always @(posedge iclk) begin
      dff[0] <= id;
      for (i = 0; i < SRL_LENGTH-1; i = i+1) begin
        dff[i + 1] <= dff[i];
      end
    end
    
    assign oq = dff[SRL_LENGTH-1];
    
endmodule

 Запустим синтез и посмотрим результат.

 Как видим, часть нашей цепочки была упакована в блочную память.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 22

Итак, первый эксперимент оказался вполне удачным, и мы смогли достичь поставленной цели по упаковке цепочки триггеров в аппаратный ресурс c помощью атрибутов в языке VHDL и Verilog. Ссылка на описания атрибутов для Vivado и Quartus вы найдете в конце статьи.

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

 Управление настройками синтеза

И начнем мы с Xilinx Vivado.

Как я и говорил, што бы атрибуты корректно отработали, пришлось пойти на хитрость. А она в свою очередь заключалась в том, что я специально отключал глобальные настройки синтезатора в Vivado и Quartus, отвечающие за обнаружение и упаковку сдвиговых регистров. В Vivado за это отвечают несколько опций в настройках синтеза: это -no_srlextract и shreg_min_size.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 23

Кстати, работа по оптимизации может также вестись и на этапе имплементации. Подробнее познакомиться с опциями по оптимизации проекта во время синтеза и имплементации вы можете в руководстве UG835 Tcl Command Reference Guide. Опции по работе со сдвиговыми регистрами вы сможете найти по ключевому слову shift register.

Запретить обнаружение цепочки триггеров мы можем с помощью опции -no_srlextract, установив напротив нее галочку

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 24

В этом случае мы получим обычную цепочку из 32-ти двух триггеров.

Сняв галочку с опции -no_srlextract мы скажем Vivado, што разрешаем обнаружение и упаковку цепочек триггеров в аппаратные ресурсы, и после синтеза получим вполне ожидаемый результат в виде двух триггеров и SRL32 ресурса.

 Втора опция shreg_min_size указывает при какой минимальной длине цепочки триггеров производить упаковку в аппаратный ресурс.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 25

Если мы измени значение на 33, то увидим, как вивадо после синтеза вновь возвращает на цепочку из 32-х триггеров.

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

 Переходим в Quartus

В квартус для управления упаковкой сдвиговых регистров имеется 3 атрибута. Управляя комбинацией этих настроек мы можем запретить или разрешить обнаружение и упаковку, комбинировать и объединять несколько сдвиговых регистров для экономии ресурсов.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 26

Предлагаю вам самостоятельно поиграться с настройками и посмотреть, как их комбинации влияют на ваши проекты.

Сброс ломает всё

Поскольку мы работаем с аппаратными ресурсами, мы не всегда можем писать так как нам хочется и во многих случаях мы ограничены заготовленным функционалом аппаратного блока. Наиболее частая ситуация, которая не позволяет нам упаковать цепочки регистров в аппаратный ресурс возникает из-за банального сброса. Выполнение операции сброса не стоит путать с начальной инициализацией при объявлении переменной или сигнала. Инициализация в отличие от сброса не влияет на возможность упаковки цепочки триггеров в аппаратный ресурс. Поэтому при разработке поведенческих описаний, обязательно ознакомьтесь с шаблоном описания аппаратного ресурса. Такие шаблоны приводятся в документации – в UG901 для Vivado и Handbook для Quartus. Также в Vivado есть отдельная возможность вставки шаблонных описаний – вкладка называется language templates

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 27

Давайте добавим сброс к нашему VHDL модулю с атрибутами и посмотрим, к каким последствиям это приведет.

Код перед вами, ни чего сложного, обычный сброс.

VHDL
library ieee;
use ieee.std_logic_1164.all;

entity srl_7_vhdl_reset is
    generic (
        SRL_LENGTH : natural := 128
    );
    port ( 
        id      : in std_logic;
        iclk    : in std_logic;
        ireset  : in std_logic;
        oq      : out std_logic);
end srl_7_vhdl_reset;

architecture rtl of srl_7_vhdl_reset is
    signal dff : std_logic_vector( SRL_LENGTH - 1 downto 0 ) := (others => '0');
    
    attribute shreg_extract : string;
    attribute shreg_extract of dff : signal is "yes";
    attribute srl_style : string;
    attribute srl_style of dff : signal is "srl";
    
begin
    
    srl_7 : process (iclk) begin
        if rising_edge(iclk) then
            if ireset = '1' then
                dff <= (others => '0');
            else
                dff(0) <= id;
                for i in 0 to SRL_LENGTH - 2 loop
                    dff(i + 1) <= dff(i);
                end loop;
            end if;         
        end if;
    end process srl_7;
    
    oq <= dff(SRL_LENGTH - 1);
    
end rtl;

Запустим синтез и проверим результат.

 Как вы можете наблюдать, даже при установленных атрибутах и настройках синтеза мы получили не аппаратный блок, а цепочку регистров  

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 28

и если вы обратитесь к руководству UG474 или UG953, то увидите, что примитив SRL не имеет входа сброса, поэтому Vivado и не может упаковать наш код в примитив SRL32.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 29

Установив значение при сбросе не в 0 а в 1, мы получим такой же результат. Движемся далее

Давайте посмотрим как на ввод сигнала сброса отреагирует Quartus

Дополним наш код сигналом сброса.

Verilog
module srl_7_verilog_reset(
    input id,
    input iclk,
   input ireset,
    output oq
    );
    parameter SRL_LENGTH = 128;
    
   (* altera_attribute = "-name AUTO_SHIFT_REGISTER_RECOGNITION ON" *)reg [SRL_LENGTH-1:0] dff;
    
   integer i;
    
    always @(posedge iclk or posedge ireset) begin
      if (ireset) begin
      dff <= {SRL_LENGTH{1'b1}};
    end else begin
      dff[0] <= id;
      for (i = 0; i < SRL_LENGTH-1; i = i+1) begin
        dff[i + 1] <= dff[i];
      end
    end
    end
    
    assign oq = dff[SRL_LENGTH-1];
    
endmodule

 Для начала посмотрим, что будет если мы будем по сигналу сброса обнулять наш сдвиговый регистр

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

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 30

Давайте попробуем теперь заменить очистку регистра при сбросе на установку всех элементов в 1.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 31

И тут мы получили опять цепочку триггеров, что несколько странно.

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 32

 Если вы знаете, чем объясняется такое различие, напишите об этом комментариях.

Любопытно, что при реализации сдвигового регистра со сбросом на языке VHDL мы получим идентичные результаты – цепочку триггеров для обоих случаев.

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

Практические кейсы

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

 Случай 1. Когда вы пытаетесь реализовать что-то более сложное, чем моргание светодиодом на достаточно высоких частотах, ну скажем 150-300 МГц, вы непременно столкнетесь с проблемой сведения таймингов. И как правило для того чтобы их сводить, вам придется оптимизировать ваш код и добавлять триггеры. Это вполне нормальная практика.

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

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

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 33

Ставь палец вверх, если у тебя такое было на практике.

 Решить проблему можно простым введением атрибутов, с которыми мы сегодня познакомились и запретить упаковку цепочки триггеров в аппаратный ресурс

Случай 2. Часто в проектах мы сталкиваемся с пересечением тактовых доменов или необходимостью пересинхронизации асинхронных сигналов.

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

СДВИГОВЫЙ РЕГИСТР ИЛИ ТО, О ЧЕМ НЕ РАССКАЖУТ В СТАТЬЯХ ДЛЯ НАЧИНАЮЩИХ :: АТРИБУТЫ СИНТЕЗА - 34

Помимо введения триггеров, на цепи, их соединяющие надо дополнительно наложить специальные временные ограничения, типа false_path, max_delay и тд. Нередко и для самих триггеров надо прописать специальный атрибут, например ASYNC_REG в случае Xilinx

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

Подведем итоги

 Разработка на ПЛИС не ограничивается написанием кода. Да, когда проект простой, можно следовать принципу «чик-чик и в продакшн», но на практике так лучше не поступать. Сложные проекты требуют от разработчика знаний не только языка проектирования, но и знаний архитектуры ПЛИС, настроек среды, в частности синтезатора, возможностей аппаратных ресурсов и много много другого. Сегодня, используя атрибуты для управления синтезатором, мы только приоткрыли дверь в мир проектирования на ПЛИС. Впереди еще много новых тем, про которые не принято говорить в статьях для начинающих.

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

Поддержите автора вашим царским лайком и оставьте в комментариях идеи для новых статей.

 До встречи в следующей статье из серии «Практическое проектирование на ПЛИС или то о чем не принято говорить в статьях для начинающих»

Источники

  1. Для пользователей Xilinx Vivado

    1. UG901 Vivado Design Suite Synthesis Guide https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_2/ug901-vivado-synthesis.pdf

    2. Vivado Design SuiteTcl Command Reference Guide https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_2/ug835-vivado-tcl-commands.pdf

    3. Vivado Design Suite 7 Series FPGA and Zynq-7000 SoC Libraries Guide https://www.xilinx.com/support/documentation/sw_manuals/xilinx2020_2/ug953-vivado-7series-libraries.pdf

  2. Для пользователей Intel Quartus II

    1. Intel Quartus Prime Software User Guides https://www.intel.com/content/www/us/en/programmable/products/design-software/fpga-design/quartus-prime/user-guides.html

    2. Verilog HDL Synthesis Attributes and Directives https://www.intel.com/content/www/us/en/programmable/quartushelp/17.0/hdl/vlog/vlog_file_dir.htm

    3. Quartus II Handbook Volume 1: Design and Synthesis https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/hb/qts/qts_qii5v1.pdf 

  3. Git репозиторий с исходниками https://github.com/FPGA-Systems/fpga_inside

  4. Ссылка на стрим с 4 вариантами реализации SPI на сдвиговом регистре, конечном автомате, счетчике, памяти

    1. ПЛИС и АЦП :: 1000 и 1 способ реализации SPI :: Часть 2 https://youtu.be/qVFO6D9Hj94 

    2. Интерфейсы :: SPI :: Часть 1:: Общие сведения https://youtu.be/s7kpZYsXM68?list=PLWMg96mLREOd-7U9LxkfNy1PgSiX1Moyj

    3. Интерфейсы :: SPI :: Часть 2 :: Варианты реализации https://youtu.be/pGYkpPjy1Oc?list=PLWMg96mLREOd-7U9LxkfNy1PgSiX1Moyj

  5. Статья в видеоформате

 PS: еще можно почитать народный FPGA журнал FSM, доступный бесплатно вот по этой ссылке https://fpga-systems.ru/fsm и для которого мы все еще ищем авторов :)

Автор: KeisN13

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js