我有一个FSM,它有效。然而,合成器抱怨存在“acc_x”,“acc_y”和“data_out”的锁存器,我理解为什么以及为什么它是坏的。但是,我不知道如何重写FSM,因此状态部分会进入时钟进程。任何想法从哪里开始?以下是FSM的代码:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity storage is
port
(
clk_in : in std_logic;
reset : in std_logic;
element_in : in std_logic;
data_in : in signed(11 downto 0);
addr : in unsigned(9 downto 0);
add : in std_logic; -- add = '1' means add to RAM
-- add = '0' means write to RAM
dump : in std_logic;
element_out : out std_logic;
data_out : out signed(31 downto 0)
);
end storage;
architecture rtl of storage is
component bram is
port
(
clk : in std_logic;
we : in std_logic;
en : in std_logic;
addr : in unsigned(9 downto 0);
di : in signed(31 downto 0);
do : out signed(31 downto 0)
);
end component bram;
type state is (st_startwait, st_add, st_write);
signal current_state : state := st_startwait;
signal next_state : state := st_startwait;
signal we : std_logic;
signal en : std_logic;
signal di : signed(31 downto 0);
signal do : signed(31 downto 0);
signal acc_x : signed(31 downto 0);
signal acc_y : signed(31 downto 0);
begin
ram : bram port map
(
clk => clk_in,
we => we,
en => en,
addr => addr,
di => di,
do => do
);
process(clk_in)
begin
if rising_edge(clk_in) then
if (reset = '1') then
current_state <= st_startwait;
else
current_state <= next_state;
end if;
end if;
end process;
process(current_state, element_in, add, dump, data_in, do, acc_x, acc_y)
begin
element_out <= '0';
en <= '1';
we <= '0';
di <= (others => '0');
case current_state is
when st_startwait =>
if (element_in = '1') then
acc_x <= resize(data_in, acc_x'length);
next_state <= st_add;
else
next_state <= st_startwait;
end if;
when st_add =>
if (add = '1') then
acc_y <= acc_x + do;
else
acc_y <= acc_x;
end if;
next_state <= st_write;
when st_write =>
if (dump = '1') then
data_out <= acc_y;
element_out <= '1';
else
di <= acc_y;
we <= '1';
end if;
next_state <= st_startwait;
end case;
end process;
end rtl;
答案 0 :(得分:2)
这是个人偏好,但我认为这里的大多数人都会同意我这一点......不要使用两个进程来控制你的状态机。在我看来,整个previous_state next_state事情是完全垃圾。这真的很令人困惑,它往往会产生闩锁 - 惊喜 - 你发现了这一点。尝试使用单个时钟进程重写您的状态机,只使用一个状态机信号。
这是我尝试重写你的状态机。请注意,我不确定下面的功能对您有用。模拟它以确保它的行为符合您的预期。例如,信号en始终与'1'相关联,不确定是否需要...
process (clk_in)
begin
if rising_edge(clk_in) then
element_out <= '0';
en <= '1'; -- this is set to 1 always?
we <= '0';
di <= (others => '0');
case state is
when st_startwait =>
if (element_in = '1') then
acc_x <= resize(data_in, acc_x'length);
state <= st_add;
end if;
when st_add =>
if (add = '1') then
acc_y <= acc_x + do;
else
acc_y <= acc_x;
end if;
state <= st_write;
when st_write =>
if (dump = '1') then
data_out <= acc_y;
element_out <= '1';
else
di <= acc_y;
we <= '1';
end if;
state <= st_startwait;
end case;
end if;
end process;
答案 1 :(得分:0)
显然,你需要补充(时钟控制)寄存器(D触发器)。
你需要问问自己“如果FSM处于(假设)状态st_add,会对acc_x发生什么?”。你的答案是“我不想在这种状态下修改acc_x”。所以:使用时钟寄存器(例如用于状态的寄存器)来明确地写入它;您可以使用这些补充寄存器来增加时钟进程。做到处都是。这是规则。否则,合成器将推断透明锁存器以记忆acc_x的先前值:但是这些透明锁存器违反了同步设计原则。它们在结构上意味着你设计中的组合环,这很糟糕。
换句话说:问问自己什么是组合,寄存器在哪里?如果您有记录,请明确编码。不要在同一过程中分配和读取组合信号。
答案 2 :(得分:0)
推断锁存器的原因是最后一个进程中的情况 不能以敏感信号的所有可能组合驱动所有信号。 因此,该过程可以在不改变某些输出数据的情况下完成 过程的信号值。以这种方式保持输出是操作 因此,锁存器的锁存器由合成工具推断。
此锁存仅适用于acc_x
,acc_y
和data_out
,因为所有其他
在过程开始时,信号被分配一个默认值。
你可以通过驱动最后3个信号的默认值来解决这个问题
该过程的开始,例如'X'
所有位允许合成
自由:
data_out <= (others => 'X');
acc_x <= (others => 'X');
acc_y <= (others => 'X');
或者,您可以确保所有输出都在所有分支中驱动
在这种情况下,您还应该在案例中添加when others =>
分支。
我建议您使用默认值分配给所有信号,因为这样 更容易编写和维护,而不必跟踪分配 案件所有分支中的所有驱动信号。