我试图写下我项目控制单元的FSM的VHDL代码。我选择了2个进程方式,一个进程用于状态寄存器,另一个进程用于下一个状态和输出逻辑。无论如何,我在设置解决方案时遇到一些问题,因为有些信号会给出综合锁定警告(我知道它们出现的原因)。我发现的唯一解决方案(不使用单个进程用于状态寄存器和输出逻辑,也不添加3个状态)是在管理状态逻辑的过程中添加一些输出逻辑。
令人惊讶的是它有效,但这在概念上是否正确?我的意思是,用一些输出逻辑弄脏状态寄存器进程的代码是正确的还是我打破了2进程模式?
这是我工作的代码和“无闩锁警告”控制单元。无论如何,锁存器涉及信号sel_mode
,因为我不知道如何在状态IDLE的else分支中指定类似“保留前一个值”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;
答案 0 :(得分:3)
<强>加强>:
令人惊讶的是它有效,但这在概念上是否正确?我的意思是,用一些输出逻辑弄脏状态寄存器进程的代码是正确的还是我打破了2进程模式?
您的设计状态始终由您设计中的所有寄存器组成,而不仅仅是您设计中的寄存器curr
。你可以这样想:
FSM的(部分)状态由curr
定义。这是使用双流程形式描述的。
发布代码中的寄存器sel_mode
是数据路径寄存器,因此定义了数据路径部分的状态。您已使用单进程表单对其进行了描述。使用双流程形式的替代解决方案,我将在下面描述。
无论如何,锁存器涉及信号“sel_mode”,因为我不知道如何在状态IDLE的else分支中指定类似“保留前一个值”sel_mode“(没有锁存警告)。
为了防止锁存器的推断,必须将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;