VHDL coding guidelines

Это свод правил написания VHDL кода, скомпилированный на основании различных источников и личного опыта.

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

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

Базовые правила

Номер 1.1
Описание Используйте строчные буквы для всех ключевых слов языка программирования VHDL и для все типов данных
Пример
signal sig_name : std_logic; -- верно
SIGNAL sig_name : STD_LOGIC; -- неверно
Номер 1.2
Описание (объединено с 1.3)
Пример  
Номер 1.3
Описание Используйте прописные буквы только для имен constant и generic. Остальной код пишите строчными буквами
Пример
constant CONST_NAME : std_logic;          -- верно
constant const_name : std_logic;          -- неверно
variable var_name : integer range 0 to 9;          -- верно
signal Sig_Name1, SIG_NAME2, SigName3 : std_logic; -- неверно
Номер 1.4
Описание Создаваемые имена для signal, port, variable, constant, function (и так далее) должны быть значащими и понятными.
Пример

Для обозначения шины адреса RAM лучше использовать ram_addr, а не ra:

ram_addr : out std_logic_vector(7 downto 0); -- верно
ra : out std_logic_vector(7 downto 0);       -- неверно
Номер 1.5
Описание

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

Не допустимо: clk1, clk2, clk_3, clk_50mhz.

Допустимо: clk_interface, clk_spi, clk_high

Пример
clk_gen : in std_logic; -- верно
clk50 : in std_logic;   -- неверно
Номер 1.6
Описание Сигнал сброса, активный в логической единице (active-high), должен называться rst или иметь префикс rst_ . Сигнал сброса, активный в логическом нуле (active-low), должен называться rst_n или иметь префикс rst_ и постфикс _n.
Пример
rst : in std_logic;       -- верно
rst_spi_n : in std_logic; -- верно
reset : in std_logic;     -- неверно
nreset : in std_logic;    -- неверно
Номер 1.7
Описание Однобитные сигналы, активные в логическом нуле (active-low), должны содержать в названии постфикс _n .
Пример
enable_n : in std_logic; -- верно
Номер 1.8
Описание Используйте нисходящий порядок битов в многобитных signal, port, variable, constant.
Пример
signal data : std_logic_vector(7 downto 0); -- верно
signal data : std_logic_vector(0 to 7);     -- неверно
Номер 1.9
Описание При подключении компонентов через port map используйте одинаковые или похожие имена port и signal, которые к ним подключаются.
Пример
port map(
    clk => clk,           -- верно
    data => spi_data,     -- верно
    enable => spi_enable, -- верно
    busy => waiting       -- неверно
);
Номер 1.10
Описание Используйте тип данных std_logic[_vector] для port.
Пример
entity module is
    port (
        data1 : in std_logic;                    -- верно
        data2 : in std_logic_vector(3 downto 0); -- верно
        data3 : out unsigned(3 downto 0)         -- неверно
    );
end module;
Номер 1.11
Описание
Давайте следующие названия для architecture:
  • rtl или префикс rtl_ - RTL-типа архитектуры
  • sim или префикс sim_ - архитектура для симуляции
  • tb - архитектура testbench файла
Пример
architecture rtl of module is -- верно
architecture sim of module is -- верно
architecture tb of tb_file is -- верно
Номер 1.12
Описание

Каждый файл должен содержать заголовок в виде комментария. Весь текст должен быть написан на латинице.

В заголовке указывается следующая информация:
  • Названия файла (Filename)
  • Автор[ы] (Author)
  • Дата создания файла (Data)
  • Кратное описания (Annotation). Может быть
  • Версия (Version)
  • Дата последней модификации (Mod.Data)
Так же на усмотрение разработчика могут быть добавлены следующие поля:
  • Лицензию (License)
  • Почта для связи (E-mail)
  • Ссылка на репозиторий или сайт (Link)
  • Зависимости от других файлов (Dependency)
  • Детальное описание работы кода (Description)
  • Примечание (Note)
Пример

Обязательная часть заголовка:

-- Filename     : jr_module.vhd
-- Author       : John Rambo
-- Date         : 07.06.1972
-- Annotation   : This file is written by a fictional character in the Rambo series.
--                “They drew first blood”
-- Version      : 0.5
-- Mod.Data     : 11.02.1981

Дополнительная часть заголовка:

-- License      : GPL
-- E-mail       : john_rambo_72@gmail.com
-- Link         : www.john_ram6o_repo.xyz
-- Dependency   : dm_module.vhd
--                d_m_repo.com
--                david_morre11@gmail.com
-- Description: : .....................
-- Note         : .....................
Номер 1.13
Описание
Большинство специалистов сходятся во мнении, что комментарии должны объяснять намерения программиста, а не код; то, что можно выразить на языке программирования, не должно выноситься в комментарии [Wikipedia - Комментарии]
  • Для описания signal, port, variable, constant, type старайтесь размещать комментарий в той же строке
  • Для описания function, process, procedure и других многострочных структур размещайте комментарий строчкой выше.
  • Приветствуется комментирование групп из нескольких port или signal
Пример
---- верно:
signal flag_position : std_logic; -- '1' - HOME position; '0' - FINISH position

---- неверно:
signal flag_position : std_logic; -- flag of position

---- неверно:
-- '1' - HOME position; '0' - FINISH position
signal flag_position : std_logic;
---- верно:
-- Manager State Machine of IIC interface
process (clk)
begin

---- неверно:
process (clk) -- Manager State Machine of IIC interface
begin
---- верно
port (
    -- Individual reset signalsв
    reset_adc : out std_logic;
    reset_dac : out std_logic;
    reset_fir : out std_logic;
);
Номер 1.14
Описание
  • Каждое выражение VHDL должно находиться на отдельной строке.
  • Не группируйте объявления signal, port - пишите каждое на отдельной строке
Пример
a <= b and c;              -- верно
c <= d or e;               -- верно
a <= b and c; c <= d or e; -- неверно

signal a : std_logic;   -- верно
signal b : std_logic;   -- верно
signal a,b : std_logic; -- неверно
Номер 1.15
Описание
Объявляйте port в следующем порядке:
  • Входные порты:
    • Тактовые сигналы (clocks)
    • Сигналы сброса (resets)
    • Сигналы разрешения (enables)
    • Управляющие сигналы (control signals)
    • Порты адреса (address lines)
    • Порты данных (data lines)
  • Двунаправленные порты:
    • Тактовые сигналы (clocks)
    • Сигналы сброса (resets)
    • Сигналы разрешения (enables)
    • Управляющие сигналы (control signals)
    • Порты адреса (address lines)
    • Порты данных (data lines)
  • Выходные порты:
    • Тактовые сигналы (clocks)
    • Сигналы сброса (resets)
    • Сигналы разрешения (enables)
    • Управляющие сигналы (control signals)
    • Порты адреса (address lines)
    • Порты данных (data lines)

Допускается объединять крупные группы port для одного интерфейса. Такие группы размещаются после списка выходных портов, а порядок портов внутри определяется вышеизложенным правилом.

Пример

Верный пример:

entity module is
    port (
        clk : in std_logic;
        rst : in std_logic;

        en      : in std_logic;
        addr_in : in std_logic_vector(3 downto 0);
        data_in : in std_logic_vector(31 downto 0);

        data_val : out std_logic;
        addr_out : out std_logic_vector(3 downto 0);
        data_out : out std_logic_vector(31 downto 0);

        -- avalon streaming source
        avl_ready : in std_logic;
        avl_valid : out std_logic;
        avl_data  : out std_logic_vector(7 downto 0)
    );
end module;
Номер 1.16
Описание

При использовании port map используйте именную ассоциацию, а не позиционную.

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

Верный пример:

port map(
    clk => clk,
    data => spi_data,
    enable => spi_enable,
    busy => busy
);

Неверный пример:

port map(clk, spi_data, spi_enable, busy);
Номер 1.17
Описание Название entity должно совпадать с названием файла: entity_name .vhd
Пример None
Номер 1.18
Описание entity, architecture и configuration должны располагаться в одном VHDL-файле.
Пример None
Номер 1.19
Описание Создавайте function вместо многократного повторения одинакового кода. Делайте function максимально универсальными, чтобы упростить их повторное использование.
Пример None
Номер 1.20
Описание Каждый процесс должен содержать метку (label). Метки должны иметь постфикс _PROC
Пример
SYNC_PROC : process (clk, rst)
    -- ...
end process SYNC_PROC;
Номер 1.21
Описание
При инициализации экземпляра component используйте следующие правила:
  • в начале ставьте префикс i_
  • дублируйте название или сокращайте его, если оно чрезмерно длинное
  • добавляйте постфикс _number с номерами экземпляров компонентов тогда, когда их инициализируете больше одного
i_ component_name [_number]
Пример
i_fir_0 : fir
port map(
    -- ...
);

i_fir_1 : fir
port map(
    -- ...
);

Правила создания переносимого кода

Номер 2.1
Описание Используйте только типы данных из IEEE стандарта или типы и подтипы, которые основаны на IEEE стандарте.
Пример
subtype new_subtype is std_logic_vector(31 downto 0);
Номер 2.2
Описание
  • Используйте std_logic и std_logic_vector вместо std_ulogic и std_ulogic_vector соответственно.
  • Используйте std_logic и std_logic_vector вместо bit и bit_vector соответственно.
Пример None
Номер 2.3
Описание

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

Для однобитных '1' и '0' создание отдельных констант не обязательно.

Во многих случаях можно обойтись использованием предопределенных атрибутов языка VHDL (Predefined Attributes).

Пример
---- верно
constant DATA_WIDTH : integer := 8;
signal data_reg : std_logic_vector(DATA_WIDTH-1 downto 0);

---- верно
constant MAX_CNT_FREQ : integer := 2679;
-- ...
if (cnt_freq = MAX_CNT_FREQ) then
    -- ...
end if;

---- верно
if (flag_blink = '1') then
    -- ...
end if;

---- верно
signal data_reg : std_logic_vector(data_in'RANGE);

---- неверно
if (cnt_freq = 456626) then
    -- ...
end if;

Тактовые сигналы и сигналы сброса

Номер 3.1
Описание

Используйте для тактирования положительный фронт тактового сигнала (rising edge). Используйте отрицательный фронт тактового сигнала (falling edge) только при необходимость работы с удвоенной частотой.

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

Пример None
Номер 3.2
Описание Не используйте для тактирования тактовые сигналы, сгенерированные последовательностной логикой (gated clock).
Пример
subtype new_subtype is std_logic_vector(31 downto 0);