Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
assign r = (c1) ? a :
(с2) ? b :
....
Стиль описания конечного автомата как образ мышления
Во-первых, как я понимаю код автора содержит генерацию латчей, что не очень хорошо, и даже плохо
По крайней мере, на VHDL это так
Во-вторых, множественны параллельные процессы необходимы для более сложных алгоритмов. Например, в примере с памятью, события от модуля памяти могут приходить в другом clock domain, что требует дополнительных процессов для синхронизации доменов.
В-третьих, можно заметить что описанная FSM всегда синхронизированна по clk, что не оптимально по скорости.
Рекомендую обратиться к коду примеров Xilinx что бы «ужаснуться» от количеству процессов даже в простом коде ;)
Писать автомат в 2 always блоках или в 3 — вопрос чисто философский
порождает на выходе FSM лишние и, самое главное, никому не нужные триггеры.До тех пор пока выход автомата не зашел на какой-либо асинхронный сброс или подобное…
В Вашей задачи получился большой автомат только из-за того, что неправильно разделена задача.
Нет, если мы говорим не про формальное разделение на блоки, а про функциональное. Третий always блок для формирования регистрового, а не комбинационного выхода. И это не философия.
До тех пор пока выход автомата не зашел на какой-либо асинхронный сброс или подобное…
Я бы не называл данный автомат в 7 состояний большим, но интересно было бы посмотреть вашу реализацию. Пока мне не очевидно как предлагаемое Вами разбиение сделает работу более наглядной.
" alt=«image»/>
" alt=«image»/>library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity CMD_CTRL is
generic
(
READ_SETUP : natural := 5;
READ_PULSE : natural := 3;
READ_HOLD : natural := 1;
WRITE_SETUP : natural := 5;
WRITE_PULSE : natural := 3;
WRITE_HOLD : natural := 1
);
port
(
clk : in std_logic;
reset : in std_logic;
w_strb : in std_logic;
r_strb : in std_logic;
s_waddress : in std_logic_vector(7 downto 0);
s_raddress : in std_logic_vector(7 downto 0);
s_data_to : in std_logic_vector(7 downto 0);
s_data_from : out std_logic_vector(7 downto 0);
done : out std_logic;
--------------------- Интерфейс с контроллером задержек ----------------------
delay_done : in std_logic;
delay_start : out std_logic;
delay_data : out natural range 0 to 7;
--------------------- Интерфейс с памятью ----------------------
m_data_to : out std_logic_vector(7 downto 0);
m_data_from : in std_logic_vector(7 downto 0);
m_address : out std_logic_vector(7 downto 0);
cs_n : out std_logic;
oe_n : out std_logic;
we : out std_logic
);
end entity;
architecture rtl of CMD_CTRL is
type state_type is
(
IDLE, -- Состояние записи данных в 0 буфер
PREPARE_READ, -- Состояние записи данных в 1 буфер
READ,
END_READ,
PREPARE_WRITE,
WRITE,
END_WRITE
);
signal pres_state, next_state : state_type := IDLE;
attribute syn_encoding : string; -- атрибуты синтеза
attribute syn_encoding of state_type : type is "safe"; -- создать машину состойний, выходящую из ошибочных состояний
signal addr_latch : std_logic_vector(7 downto 0) := (others => '0');
signal data_latch : std_logic_vector(7 downto 0) := (others => '0');
signal read_ena : std_logic;
signal dellay_cnt : unsigned(5 downto 0) := (others => '0');
signal dellay : std_logic_vector(2 downto 0);
begin
--======================================================
-- Смена состояний автомата на вычесленное состояние
--======================================================
next_state_proc : process(clk, reset)
begin
if (reset = '1') then
pres_state <= IDLE;
elsif (rising_edge(clk)) then
pres_state <= next_state;
end if;
end process;
--======================================================
-- Процес вычесления следующего состояния автомата
--======================================================
next_state_logic : process(all)
begin
case pres_state is
when IDLE =>
next_state <= IDLE;
if (w_strb = '1') then
next_state <= PREPARE_WRITE;
end if;
if (r_strb = '1') then
next_state <= PREPARE_READ;
end if;
--====================================================================================================
when PREPARE_READ =>
next_state <= PREPARE_READ;
if (delay_done = '1') then
next_state <= READ;
end if;
--====================================================================================================
when READ =>
next_state <= READ;
if (delay_done = '1') then
next_state <= END_READ;
end if;
--====================================================================================================
when END_READ =>
next_state <= END_READ;
if (delay_done = '1') then
next_state <= IDLE;
end if;
--====================================================================================================
when PREPARE_WRITE =>
next_state <= PREPARE_WRITE;
if (delay_done = '1') then
next_state <= WRITE;
end if;
--====================================================================================================
when WRITE =>
next_state <= WRITE;
if (delay_done = '1') then
next_state <= END_WRITE;
end if;
--====================================================================================================
when END_WRITE =>
next_state <= END_WRITE;
if (delay_done = '1') then
next_state <= IDLE;
end if;
when others => null;
end case;
end process;
--======================================================
-- Процесс выходных данных
--======================================================
output_data_logic : process(all)
begin
cs_n <= '1';
oe_n <= '1';
we <= '0';
m_address <= (others => '-');
done <= '0';
read_ena <= '0';
delay_start <= '0';
dellay <= (others => '-');
case pres_state is
when IDLE =>
cs_n <= '1';
oe_n <= '1';
we <= '0';
if (w_strb = '1') then
delay_start <= '1';
dellay <= std_logic_vector(to_unsigned(WRITE_SETUP,3));
end if;
if (r_strb = '1') then
delay_start <= '1';
dellay <= std_logic_vector(to_unsigned(READ_SETUP,3));
end if;
--====================================================================================================
when PREPARE_READ =>
cs_n <= '0';
oe_n <= '1';
we <= '0';
m_address <= addr_latch;
if (delay_done = '1') then
delay_start <= '1';
end if;
dellay <= std_logic_vector(to_unsigned(READ_PULSE,3));
--====================================================================================================
when READ =>
cs_n <= '0';
oe_n <= '0';
we <= '0';
if (delay_done = '1') then
read_ena <= '1';
delay_start <= '1';
end if;
m_address <= addr_latch;
dellay <= std_logic_vector(to_unsigned(READ_HOLD,3));
--====================================================================================================
when END_READ =>
cs_n <= '0';
oe_n <= '1';
we <= '0';
if (delay_done = '1') then
done <= '1';
delay_start <= '1';
end if;
m_address <= addr_latch;
--====================================================================================================
when PREPARE_WRITE =>
cs_n <= '0';
oe_n <= '1';
we <= '0';
m_address <= addr_latch;
if (delay_done = '1') then
delay_start <= '1';
end if;
dellay <= std_logic_vector(to_unsigned(WRITE_PULSE,3));
--====================================================================================================
when WRITE =>
cs_n <= '0';
oe_n <= '1';
we <= '1';
m_address <= addr_latch;
if (delay_done = '1') then
delay_start <= '1';
end if;
dellay <= std_logic_vector(to_unsigned(WRITE_HOLD,3));
--====================================================================================================
when END_WRITE =>
cs_n <= '0';
oe_n <= '1';
we <= '0';
if (delay_done = '1') then
done <= '1';
delay_start <= '1';
end if;
m_address <= addr_latch;
when others => null;
end case;
end process;
m_data_to <= data_latch;
delay_data <= to_integer(unsigned(dellay));
--======================================================
-- Защелкивание данных и адреса в регистры
--======================================================
addr_and_data_latch : process(clk, reset)
begin
if (rising_edge(clk)) then
if (w_strb = '1') then
addr_latch <= s_waddress;
data_latch <= s_data_to;
end if;
if (r_strb = '1') then
addr_latch <= s_raddress;
end if;
end if;
end process;
--======================================================
-- Чтение данных из памяти
--======================================================
read_data_from_memory : process(clk, reset)
begin
if (rising_edge(clk)) then
if (read_ena = '1') then
s_data_from <= m_data_from;
end if;
end if;
end process;
end architecture;
Если асинхронный сброс сделан правильно, то никаких проблем в схеме наблюдаться не должно. Если есть проблемы- значит сброс выполнен неверно!
На скорую руку сделал проект, как я его вижу.
Не понимаю как можно сделать правильно:) Комбинаторная схема во время переключения входных сигналов имеет полное право генерировать «иголки», которые вызовут сброс.
Все тоже самое верно и для комбинаторных выходов. Комбинаторные сигналы безопасно идут только внутри домена синхронных схем, как только вы их выдали наружу или в домен с другим клоком, вы потенциально породили проблемы. Если не сейчас, так завтра.
Комбинаторные сигналы безопасно идут только внутри домена синхронных схем
Конечно же при условии применения reset_bridge, который синхронно снимает сигнал сброса с домена схемы. Я поэтому и говорил, что сброс должен быть заведен правильно
Абсолютно те-же иголки формируются при синхронном переключении состояний автомата.
...
//-----------------------------------------------
assign next_cnt = cnt + 1'b1;
always @(posedge clk)
cnt <= next_cnt;
//-----------------------------------------------
assign out_a = (cnt != 0) ? 1'b1 : 1'b0;
always @(posedge clk)
out_s <= (next_cnt != 0) ? 1'b1 : 1'b0;
...
А вот это неверное утверждение.
Но когда мы говорим о FPGA мы подразумеваем концепцию синхронного проектирования
то кто мешал отдельно этот сигнал пропустить через триггер
FPGA для программиста, конечные автоматы (verilog)