Почему бы не двухпроцессный конечный автомат в VHDL?
Когда я научился выражать конечные автоматы в VHDL, это было с двухпроцессорной архитектурой. Один процесс обрабатывает сигналы синхронизации / сброса, а другой - комбинаторную логику обновления состояния и вывода. Пример ниже.
Я видел критику этого стиля (см. Комментарии и ответ на этот вопрос, например), но никогда подробно. Я хотел бы знать, есть ли объективные причины этого.
Есть технические причины, чтобы избежать этого стиля? Синтезатор Xilinx, похоже, определяет его как конечный автомат (вы можете увидеть его в выходных данных и проверить переходы), но борются ли другие с ним или генерируют реализации низкого качества?
Разве это не идиоматический VHDL? Не забудьте избегать основанных на мнении ответов; если это не идиоматично, есть ли широко используемый учебный ресурс или справочник, который использует другой стиль? Идиоматические стили могут также существовать, потому что, например. Есть классы ошибок, которые легко уловить с правильным стилем, или потому что структура кода может лучше выразить проблемную область, или по другим причинам.
(Обратите внимание, что я не прошу определения или демонстрации различных стилей, я хочу знать, есть ли объективные причины, чтобы специально избегать двухпроцессной реализации.)
пример
Некоторые примеры можно найти в свободном диапазоне VHDL (p89). Вот супер простой пример:
library ieee;
use ieee.std_logic_1164.all;
-- Moore state machine that transitions from IDLE to WAITING, WAITING
-- to READY, and then READY back to WAITING each time the input is
-- detected as on.
entity fsm is
port(
clk : in std_logic;
rst : in std_logic;
input : in std_logic;
output : out std_logic
);
end entity fsm;
architecture fsm_arc of fsm is
type state is (idle, waiting, ready);
signal prev_state, next_state : state;
begin
-- Synchronous/reset process: update state on clock edge and handle
-- reset action.
sync_proc: process(clk, rst)
begin
if (rst = '1') then
prev_state <= idle;
elsif (rising_edge(clk)) then
prev_state <= next_state;
end if;
end process sync_proc;
-- Combinatorial process: compute next state and output.
comb_proc: process(prev_state, input)
begin
case prev_state is
when idle =>
output <= '0';
if input = '1' then
next_state <= waiting;
else
next_state <= idle;
end if;
when waiting =>
output <= '1';
if input = '1' then
next_state <= ready;
else
next_state <= waiting;
end if;
when ready =>
output <= '0';
if input = '1' then
next_state <= waiting;
else
next_state <= ready;
end if;
end case;
end process comb_proc;
end fsm_arc;
(Обратите внимание, что сейчас у меня нет доступа к синтезатору, поэтому в нем могут быть некоторые ошибки.)
3 ответа
Я всегда рекомендую конечные автоматы с одним процессом, потому что он позволяет избежать двух основных ошибок, которые чрезвычайно распространены среди начинающих:
- Пропущенные элементы в списке чувствительности комбинационного процесса приводят к неправильной работе симуляции. Это даже работает в лаборатории, так как большинство синтезаторов не заботятся о списке чувствительности.
- Использование одного из комбинационных результатов в качестве входных данных вместо зарегистрированной версии, что приводит к разлоченным циклам или просто длинным путям / пропущенным состояниям.
Менее важно, что комбинационный процесс снижает эффективность моделирования.
Менее объективно, я нахожу их легче читать и поддерживать; они требуют меньше котла, и мне не нужно синхронизировать список чувствительности с логикой.
Единственные две объективные причины, которые я вижу, касаются читабельности и эффективности моделирования в случае конечных автоматов Мура (где первичные выходы зависят только от текущего состояния, а не от первичных входов).
Удобочитаемость: если вы объединяете вместе результаты одного процесса и вычисления следующего состояния, это может быть более трудным для чтения / понимания / обслуживания, чем с отдельными комбинаторными процессами для отдельных задач.
Эффективность моделирования: в решении с 2 процессами ваш комбинаторный процесс будет запускаться при каждом изменении первичного входа и / или текущего состояния. Это имеет смысл для части процесса, которая вычисляет следующее состояние, но не для части, которая вычисляет выходные данные. Последнее срабатывает только при изменении текущего состояния.
Подробное описание этого приведено в исх. [1] ниже. Сначала автоматы делятся на 3 категории (в первый раз это делается), затем каждая из них тщательно изучается с множеством полных примеров. Точный ответ на ваш вопрос вы можете найти на страницах 107-115 для конечных автоматов категории 1 (обычные); на страницах 185-190 для машин категории 2 (по времени); и на страницах 245-248 для конечных автоматов категории 3 (рекурсивные). Шаблоны подробно описаны для версии Мура и Мили в каждой из трех категорий.
[1] В. Педрони, Конечные автоматы в аппаратном обеспечении: теория и проектирование (с VHDL и SystemVerilog), MIT Press, декабрь 2013 г.