FSM 2 进程 VHDL
FSM 2 process VHDL
我试图为我的项目的控制单元的 FSM 写下 VHDL 代码。我选择了 2 进程方式,一个进程用于状态寄存器,另一个进程用于下一个状态和输出逻辑。无论如何,我在设置解决方案时遇到了一些问题,因为某些信号会发出合成锁存器警告(我知道它们为什么会出现)。我找到的唯一解决方案(没有对状态寄存器和输出逻辑使用一个进程,也没有再添加 3 个状态)是在管理状态逻辑的进程中添加一些输出逻辑。
令人惊讶的是,它确实有效,但这在概念上是否正确?我的意思是,用一些输出逻辑弄脏状态寄存器进程的代码是否正确,或者我是否打破了 2 进程模式?
这是我的工作代码和 "latch-free warning" 控制单元。无论如何,闩锁涉及信号 sel_mode
,因为我不知道如何在状态 IDLE 的其他分支中指定类似 "keep the previous value of "sel_mode 的东西(没有闩锁警告)。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity control_unit is
Port ( clock : in STD_LOGIC;
reset_n_in : in STD_LOGIC;
primo_operando : in STD_LOGIC;
secondo_operando : in STD_LOGIC;
add_sub : in STD_LOGIC;
ov : in STD_LOGIC;
subtract_in : in STD_LOGIC;
led_ov : out STD_LOGIC;
reset_n_out : out STD_LOGIC;
subtract_out : out STD_LOGIC;
en_w_primo_op : out STD_LOGIC;
en_w_secondo_op : out STD_LOGIC;
en_w_risultato : out STD_LOGIC;
sel_mode : out STD_LOGIC_VECTOR(1 downto 0)
);
end control_unit;
architecture Behavioral of control_unit is
type state is (IDLE, PRIMO_OP, SECONDO_OP, RISULTATO);
signal curr, nxt : state := IDLE;
begin
change_state : process(clock, reset_n_in)
begin
if reset_n_in = '0' then
curr <= IDLE;
-- in the following lines I mix the state register logic with output logic
elsif rising_edge(clock) then
if curr = PRIMO_OP then
sel_mode <= "10";
elsif curr = SECONDO_OP then
sel_mode <= "01";
elsif curr = RISULTATO then
sel_mode <= "00";
end if;
curr <= nxt;
end if;
end process;
fsm: process(curr, reset_n_in, primo_operando, secondo_operando, add_sub)
begin
if reset_n_in = '0' then
reset_n_out <= '0';
else
reset_n_out <= '1';
end if;
en_w_primo_op <= '0';
en_w_secondo_op <= '0';
en_w_risultato <= '0';
case curr is
when IDLE =>
if primo_operando = '1' then
-- sel_mode <= "10";
nxt <= PRIMO_OP;
elsif secondo_operando = '1' then
-- sel_mode <= "01";
nxt <= SECONDO_OP;
elsif add_sub = '1' then
-- sel_mode <= "00";
nxt <= RISULTATO;
else
nxt <= IDLE;
-- how to specify keep sel_mode to the previous value??
end if;
when PRIMO_OP =>
-- sel_mode <= "10";
en_w_primo_op <= '1';
nxt <= IDLE;
when SECONDO_OP =>
-- sel_mode <= "01";
en_w_secondo_op <= '1';
nxt <= IDLE;
when RISULTATO =>
-- sel_mode <= "00";
en_w_risultato <= '1';
nxt <= IDLE;
end case;
end process;
led_ov <= ov;
subtract_out <= subtract_in;
end Behavioral;
已添加:
With much surprise it works but is this conceptually correct? I mean, is it correct to dirty the code of the state register process with some output logic or am I breaking the 2 process pattern?
您的设计状态始终由设计中的所有个寄存器组成,而不仅仅是设计中的curr
个寄存器。你可以这样想:
FSM 的(部分)状态由 curr
定义。这是使用双进程形式描述的。
您发布的代码中的寄存器 sel_mode
是数据路径寄存器,因此定义了数据路径部分的状态。您已经使用单进程形式对其进行了描述。使用双进程形式的替代解决方案,我将在下面描述。
Anyway the latch involved the signal "sel_mode" as I don't know how to specify in the else branch of the state IDLE something like "keep the previous value of "sel_mode"(without having the latch warning).
为了防止锁存器的推断,你必须将sel_mode的当前值保存到一个时钟边沿触发的寄存器中,并在你想要输出前一个值时分配寄存器值。由于寄存器代表的是之前的值,所以我称之为sel_mode_prev
。寄存器的分配与一些复位逻辑一起发生在时钟进程中:
change_state : process(clock, reset_n_in)
begin
if reset_n_in = '0' then
curr <= IDLE;
sel_mode_prev <= "00"; -- or some other value
elsif rising_edge(clock) then
curr <= nxt;
sel_mode_prev <= sel_mode_i; -- save current value
end if;
end process;
输出sel_mode
在组合部分赋值。但是,由于您无法读取上面 sel_mode_prev
赋值中的输出值,您必须将 sel_mode
的所需值赋给一个中间值,我称之为 sel_mode_i
。组合过程fsm
然后分配这个信号。输出 sel_mode <= sel_mode_i;
的分配与其他输出分配一起在流程下方组合完成。
这里是完整的修改后的架构,带有注释:
architecture Behavioral of control_unit is
type state is (IDLE, PRIMO_OP, SECONDO_OP, RISULTATO);
signal curr, nxt : state := IDLE;
signal sel_mode_i : std_logic_vector(1 downto 0); -- internal version of output
signal sel_mode_prev : std_logic_vector(1 downto 0); -- previous version of sel_mode
begin
change_state : process(clock, reset_n_in)
begin
if reset_n_in = '0' then
curr <= IDLE;
sel_mode_prev <= "00"; -- or some other value
elsif rising_edge(clock) then
curr <= nxt;
sel_mode_prev <= sel_mode_i; -- save current value
end if;
end process;
fsm: process(curr, reset_n_in, primo_operando, secondo_operando, add_sub,
sel_mode_prev) -- also add sel_mode_prev here
begin
if reset_n_in = '0' then
reset_n_out <= '0';
else
reset_n_out <= '1';
end if;
en_w_primo_op <= '0';
en_w_secondo_op <= '0';
en_w_risultato <= '0';
case curr is
when IDLE =>
if primo_operando = '1' then
sel_mode_i <= "10"; -- assign internal signal
nxt <= PRIMO_OP;
elsif secondo_operando = '1' then
sel_mode_i <= "01"; -- assign internal signal
nxt <= SECONDO_OP;
elsif add_sub = '1' then
sel_mode_i <= "00"; -- assign internal signal
nxt <= RISULTATO;
else
sel_mode_i <= sel_mode_prev; -- output old value at default
nxt <= IDLE;
end if;
when PRIMO_OP =>
sel_mode_i <= "10"; -- assign internal signal
en_w_primo_op <= '1';
nxt <= IDLE;
when SECONDO_OP =>
sel_mode_i <= "01"; -- assign internal signal
en_w_secondo_op <= '1';
nxt <= IDLE;
when RISULTATO =>
sel_mode_i <= "00"; -- assign internal signal
en_w_risultato <= '1';
nxt <= IDLE;
end case;
end process;
sel_mode <= sel_mode_i; -- assign internal signal to output
led_ov <= ov;
subtract_out <= subtract_in;
end Behavioral;
我试图为我的项目的控制单元的 FSM 写下 VHDL 代码。我选择了 2 进程方式,一个进程用于状态寄存器,另一个进程用于下一个状态和输出逻辑。无论如何,我在设置解决方案时遇到了一些问题,因为某些信号会发出合成锁存器警告(我知道它们为什么会出现)。我找到的唯一解决方案(没有对状态寄存器和输出逻辑使用一个进程,也没有再添加 3 个状态)是在管理状态逻辑的进程中添加一些输出逻辑。
令人惊讶的是,它确实有效,但这在概念上是否正确?我的意思是,用一些输出逻辑弄脏状态寄存器进程的代码是否正确,或者我是否打破了 2 进程模式?
这是我的工作代码和 "latch-free warning" 控制单元。无论如何,闩锁涉及信号 sel_mode
,因为我不知道如何在状态 IDLE 的其他分支中指定类似 "keep the previous value of "sel_mode 的东西(没有闩锁警告)。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity control_unit is
Port ( clock : in STD_LOGIC;
reset_n_in : in STD_LOGIC;
primo_operando : in STD_LOGIC;
secondo_operando : in STD_LOGIC;
add_sub : in STD_LOGIC;
ov : in STD_LOGIC;
subtract_in : in STD_LOGIC;
led_ov : out STD_LOGIC;
reset_n_out : out STD_LOGIC;
subtract_out : out STD_LOGIC;
en_w_primo_op : out STD_LOGIC;
en_w_secondo_op : out STD_LOGIC;
en_w_risultato : out STD_LOGIC;
sel_mode : out STD_LOGIC_VECTOR(1 downto 0)
);
end control_unit;
architecture Behavioral of control_unit is
type state is (IDLE, PRIMO_OP, SECONDO_OP, RISULTATO);
signal curr, nxt : state := IDLE;
begin
change_state : process(clock, reset_n_in)
begin
if reset_n_in = '0' then
curr <= IDLE;
-- in the following lines I mix the state register logic with output logic
elsif rising_edge(clock) then
if curr = PRIMO_OP then
sel_mode <= "10";
elsif curr = SECONDO_OP then
sel_mode <= "01";
elsif curr = RISULTATO then
sel_mode <= "00";
end if;
curr <= nxt;
end if;
end process;
fsm: process(curr, reset_n_in, primo_operando, secondo_operando, add_sub)
begin
if reset_n_in = '0' then
reset_n_out <= '0';
else
reset_n_out <= '1';
end if;
en_w_primo_op <= '0';
en_w_secondo_op <= '0';
en_w_risultato <= '0';
case curr is
when IDLE =>
if primo_operando = '1' then
-- sel_mode <= "10";
nxt <= PRIMO_OP;
elsif secondo_operando = '1' then
-- sel_mode <= "01";
nxt <= SECONDO_OP;
elsif add_sub = '1' then
-- sel_mode <= "00";
nxt <= RISULTATO;
else
nxt <= IDLE;
-- how to specify keep sel_mode to the previous value??
end if;
when PRIMO_OP =>
-- sel_mode <= "10";
en_w_primo_op <= '1';
nxt <= IDLE;
when SECONDO_OP =>
-- sel_mode <= "01";
en_w_secondo_op <= '1';
nxt <= IDLE;
when RISULTATO =>
-- sel_mode <= "00";
en_w_risultato <= '1';
nxt <= IDLE;
end case;
end process;
led_ov <= ov;
subtract_out <= subtract_in;
end Behavioral;
已添加:
With much surprise it works but is this conceptually correct? I mean, is it correct to dirty the code of the state register process with some output logic or am I breaking the 2 process pattern?
您的设计状态始终由设计中的所有个寄存器组成,而不仅仅是设计中的curr
个寄存器。你可以这样想:
FSM 的(部分)状态由
curr
定义。这是使用双进程形式描述的。您发布的代码中的寄存器
sel_mode
是数据路径寄存器,因此定义了数据路径部分的状态。您已经使用单进程形式对其进行了描述。使用双进程形式的替代解决方案,我将在下面描述。
Anyway the latch involved the signal "sel_mode" as I don't know how to specify in the else branch of the state IDLE something like "keep the previous value of "sel_mode"(without having the latch warning).
为了防止锁存器的推断,你必须将sel_mode的当前值保存到一个时钟边沿触发的寄存器中,并在你想要输出前一个值时分配寄存器值。由于寄存器代表的是之前的值,所以我称之为sel_mode_prev
。寄存器的分配与一些复位逻辑一起发生在时钟进程中:
change_state : process(clock, reset_n_in)
begin
if reset_n_in = '0' then
curr <= IDLE;
sel_mode_prev <= "00"; -- or some other value
elsif rising_edge(clock) then
curr <= nxt;
sel_mode_prev <= sel_mode_i; -- save current value
end if;
end process;
输出sel_mode
在组合部分赋值。但是,由于您无法读取上面 sel_mode_prev
赋值中的输出值,您必须将 sel_mode
的所需值赋给一个中间值,我称之为 sel_mode_i
。组合过程fsm
然后分配这个信号。输出 sel_mode <= sel_mode_i;
的分配与其他输出分配一起在流程下方组合完成。
这里是完整的修改后的架构,带有注释:
architecture Behavioral of control_unit is
type state is (IDLE, PRIMO_OP, SECONDO_OP, RISULTATO);
signal curr, nxt : state := IDLE;
signal sel_mode_i : std_logic_vector(1 downto 0); -- internal version of output
signal sel_mode_prev : std_logic_vector(1 downto 0); -- previous version of sel_mode
begin
change_state : process(clock, reset_n_in)
begin
if reset_n_in = '0' then
curr <= IDLE;
sel_mode_prev <= "00"; -- or some other value
elsif rising_edge(clock) then
curr <= nxt;
sel_mode_prev <= sel_mode_i; -- save current value
end if;
end process;
fsm: process(curr, reset_n_in, primo_operando, secondo_operando, add_sub,
sel_mode_prev) -- also add sel_mode_prev here
begin
if reset_n_in = '0' then
reset_n_out <= '0';
else
reset_n_out <= '1';
end if;
en_w_primo_op <= '0';
en_w_secondo_op <= '0';
en_w_risultato <= '0';
case curr is
when IDLE =>
if primo_operando = '1' then
sel_mode_i <= "10"; -- assign internal signal
nxt <= PRIMO_OP;
elsif secondo_operando = '1' then
sel_mode_i <= "01"; -- assign internal signal
nxt <= SECONDO_OP;
elsif add_sub = '1' then
sel_mode_i <= "00"; -- assign internal signal
nxt <= RISULTATO;
else
sel_mode_i <= sel_mode_prev; -- output old value at default
nxt <= IDLE;
end if;
when PRIMO_OP =>
sel_mode_i <= "10"; -- assign internal signal
en_w_primo_op <= '1';
nxt <= IDLE;
when SECONDO_OP =>
sel_mode_i <= "01"; -- assign internal signal
en_w_secondo_op <= '1';
nxt <= IDLE;
when RISULTATO =>
sel_mode_i <= "00"; -- assign internal signal
en_w_risultato <= '1';
nxt <= IDLE;
end case;
end process;
sel_mode <= sel_mode_i; -- assign internal signal to output
led_ov <= ov;
subtract_out <= subtract_in;
end Behavioral;