我在 VHDL 中有以下简单的 FSM 描述:
library ieee;
use ieee.std_logic_1164.all;
entity coverage1 is
port (
clk : in std_logic;
rst : in std_logic;
req : in std_logic;
ack : out std_logic
);
end entity coverage1;
architecture rtl of coverage1 is
type STATES is (IDLE, RUNNING, FINISH);
signal fsm_cs : STATES := IDLE;
signal fsm_ns : STATES;
begin
process (fsm_cs, req) is
begin
fsm_ns <= fsm_cs;
ack <= '0';
case fsm_cs is
when IDLE =>
if req = '1' then
fsm_ns <= RUNNING;
end if;
when RUNNING =>
fsm_ns <= FINISH;
when FINISH =>
ack <= '1';
fsm_ns <= IDLE;
when others =>
null;
end case;
end process;
process (clk) is
begin
if rising_edge(clk) then
if rst = '1' then
fsm_cs <= IDLE;
else
fsm_cs <= fsm_ns;
end if;
end if;
end process;
end architecture;
而这个测试台:
library ieee;
use ieee.std_logic_1164.all;
entity coverage1_tb is
end entity coverage1_tb;
architecture tb of coverage1_tb is
signal clk : std_logic := '1';
signal rst : std_logic;
signal req : std_logic;
signal ack : std_logic;
signal finished : boolean := false;
begin
coverage1_1: entity work.coverage1
port map (
clk => clk,
rst => rst,
req => req,
rdy => rdy,
ack => ack);
clk <= not clk after 5 ns when not finished else unaffected;
process
begin
rst <= '1';
wait until rising_edge(clk);
rst <= '0';
req <= '0';
wait until rising_edge(clk);
req <= '1';
wait until rising_edge(clk);
req <= '0';
wait until rising_edge(clk) and ack = '1';
wait until rising_edge(clk);
finished <= true;
wait;
end process;
end architecture tb;
FSM 在 ModelSim/QuestaSim 中没有达到 100% 的代码覆盖率。我发现了两个问题:
由于枚举被所有选择完全覆盖,因此不需要覆盖其他情况。但是这个分支是不可访问的......为什么 QuestaSim 期望覆盖这个分支?
QuestaSim 显示了我的示例 FSM 的错误状态图。该图包含状态的自边:
RUNNING
和FINISH
。这些边缘不存在,也不能被覆盖。
如果我删除默认分配fsm_ns <= fsm_cs;
并在 IDLE 状态下添加一个 else 分支,我将获得完全覆盖。if req = '1' then fsm_ns <= RUNNING; else fsm_ns <= IDLE; end if;
为什么状态图显示假边,为什么我不能使用默认分配?
我可以接受第 1 项,但第 2 项是个问题。如果我以这种风格编写我的 FSM,我会复制很多不需要的代码,并且大多数合成器将无法识别 FSM 模式!所以我将失去 FSM 优化和综合检查。