VHDL Quadrature Decoder: последовательная / комбинаторная логика
Я внедряю квадратурный декодер в VHDL и придумала два решения.
В методе 1 вся логика размещается в одном процессе, который чувствителен к такту и сбрасывается. На Spartan-3A используются четыре слайса, семь FF и четыре входных LUT.
Код 1
architecture Behavioral of quadr_decoder is
signal chan_a_curr : std_logic;
signal chan_a_prev : std_logic;
signal chan_b_curr : std_logic;
signal chan_b_prev : std_logic;
begin
process (n_reset, clk_in) begin
if (n_reset = '0') then
-- initialize internal signals
chan_a_curr <= '0';
chan_a_prev <= '0';
chan_b_curr <= '0';
chan_b_prev <= '0';
-- initialize outputs
count_evt <= '0';
count_dir <= '0';
error_evt <= '0';
elsif (clk_in'event and clk_in = '1') then
-- keep delayed inputs
chan_a_prev <= chan_a_curr;
chan_b_prev <= chan_b_curr;
-- read current inputs
chan_a_curr <= chan_a;
chan_b_curr <= chan_b;
-- detect a count event
count_evt <= ((chan_a_prev xor chan_a_curr) xor
(chan_b_prev xor chan_b_curr));
-- determine count direction
count_dir <= (chan_a_curr xor chan_b_prev xor
count_mode);
-- detect error conditions
error_evt <= ((chan_a_prev xor chan_a_curr) and
(chan_b_prev xor chan_b_curr));
end if;
end process;
end Behavioral;
Метод 2 разбивает логику на отдельные последовательные и комбинаторные процессы. Он использует два среза, четыре FF и четыре входных LUT.
Код 2
architecture Behavioral of quadr_decoder is
signal chan_a_curr : std_logic;
signal chan_a_prev : std_logic;
signal chan_b_curr : std_logic;
signal chan_b_prev : std_logic;
begin
process (n_reset, clk_in) begin
if (n_reset = '0') then
-- initialize internal signals
chan_a_curr <= '0';
chan_a_prev <= '0';
chan_b_curr <= '0';
chan_b_prev <= '0';
elsif (clk_in'event and clk_in = '1') then
-- keep delayed inputs
chan_a_prev <= chan_a_curr;
chan_b_prev <= chan_b_curr;
-- read current inputs
chan_a_curr <= chan_a;
chan_b_curr <= chan_b;
end if;
end process;
process (chan_a_prev, chan_a_curr, chan_b_prev, chan_b_curr) begin
-- detect a count event
count_evt <= ((chan_a_prev xor chan_a_curr) xor
(chan_b_prev xor chan_b_curr));
-- determine count direction
count_dir <= (chan_a_curr xor chan_b_prev xor count_mode);
-- detect error conditions
error_evt <= ((chan_a_prev xor chan_a_curr) and
(chan_b_prev xor chan_b_curr));
end process;
end Behavioral;
Когда я симулирую код (поведенческий), оба результата выглядят нормально. Но я не могу поверить, что оба метода одинаково действительны. Может ли кто-то пролить свет на то, какой метод следует отдать предпочтение другому?
1 ответ
Ваша версия кода 2 управляет выходами комбинаторно, тогда как версия кода 1 регистрирует выходы:
- count_evt
- count_dir
- error_evt
Это учитывает 3 дополнительных триггера (и так как у спартанца 3 есть 2 регистра по каждому срезу, это означает, что вам нужно 2 дополнительных среза).
Хотя логическая функция, выполняемая кодом, идентична, они не будут вести себя одинаково. Если / когда вы подключите выходы к входам другого блока, результат будет доступен на 1 цикл раньше для версии 2. Предполагая, что нижестоящий блок берет эти входы и применяет некоторую дополнительную логику, вы увидите, что версия 2 дает более длинные пути и, следовательно, достижимую частоту ниже.
В некоторых рекомендациях говорится, что вы должны, как правило, регистрировать выходы для блоков, чтобы улучшить синхронизацию. Иногда вы хотите иметь возможность объединить несколько блоков в комбинаторный режим, чтобы из всех рекомендаций всегда были некоторые исключения. Рекомендуется комментировать в декларации, если какие-либо выводы приводятся комбинаторно. Если вы чувствуете особую заинтересованность, вы можете сделать выходной регистр необязательным, используя generic.