1

我在 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% 的代码覆盖率。我发现了两个问题:

  1. 由于枚举被所有选择完全覆盖,因此不需要覆盖其他情况。但是这个分支是不可访问的......为什么 QuestaSim 期望覆盖这个分支?

  2. QuestaSim 显示了我的示例 FSM 的错误状态图。该图包含状态的自边:RUNNINGFINISH。这些边缘不存在,也不能被覆盖。
    如果我删除默认分配fsm_ns <= fsm_cs;并在 IDLE 状态下添加一个 else 分支,我将获得完全覆盖。

    if req = '1' then
      fsm_ns <= RUNNING;
    else
      fsm_ns <= IDLE;
    end if;
    

    为什么状态图显示假边,为什么我不能使用默认分配?

我可以接受第 1 项,但第 2 项是个问题。如果我以这种风格编写我的 FSM,我会复制很多不需要的代码,并且大多数合成器将无法识别 FSM 模式!所以我将失去 FSM 优化和综合检查。

4

2 回答 2

2

一些观察,再次使用 ghdl。

注释掉rdy端口后,ghdl 再次报告 100% 的覆盖率。

具有讽刺意味的是,nullin “others”子句获得了 20 次点击……这是可疑的。由于它是流程中的最后一条活动线,我相信任何唤醒流程但不执行任何操作的事件都会记录在这里。

在收集这 20 个命中null;后添加的 A证实了这一点 - 但该案例仍未记录为覆盖漏洞(尽管没有命中)。我的假设是,因为没有生成代码,所以没有被跟踪。向分支添加一个无害但可跟踪的操作现在会产生一个覆盖漏洞(令人讨厌的是,当删除之后会收到虚假命中。end caseothersnullfsm_ns <= IDLE;when othersnullend case

概括 :

  • 值得测试活动语句的效果作为跟踪覆盖率的钩子when others,以及null之后end case,以便“进程结束”代码不会错误地记录在最后一个案例臂上
  • ghdl 需要在这两个领域进行一些整理,也许可以翻译null为“nop”来挂钩覆盖范围。

在此处输入图像描述

抱歉,我无法在这里阐明 Modelsim 的行为。

但是,存在但无法访问的代码 - “死代码” - 被视为代表高完整性实践中的设计错误,因此我认为 Modelsim 突出显示它是正确的,而 ghdl 在没有突出显示的情况下是不正确的。

这与安全状态机设计问题有些相关,其中 SEU(可能来自宇宙射线)破坏了状态寄存器。请注意,如果 的成员少于 2**n STATES,则会出现“其他”状态,并且通过null操作,如果该 SM 达到该状态,它将锁定在那里。(但是,删除“others”子句并不能纠正这一点,综合工具可能会断定“others”子句无法访问并删除它。安全 SM 设计是另一个主题)

于 2017-02-07T00:40:52.770 回答
1
  1. 正如预期的那样,当其他人显示为未覆盖时。您可以通过以下方式排除它:

    -- coverage off
    when others => null;
    -- coverage on
    

    我在每个案例陈述中都这样做,而其他案例不能被击中。

  2. 即使没有 else 分支,我也能获得 100% 的状态覆盖率。状态中的if条件IDLE具有 100% 的分支覆盖率,即使没有 else 分支(Active: 4, True Hits: 1, AllFalse: 3)。对于 100% FSM 覆盖,您应该排除复位信号的隐含变化,或者您必须在每个 FSM 状态下拉复位。-nofsmresettrans您可以在编译时使用 swith 排除重置状态更改。

我使用 Modelsim DE 10.5c 和 10.6 以及 Questa 10.6 得到了相同的行为。

顺便说一句:如果 FSM 的某些部分位于依赖于泛型的生成块内,我将无法获得 FSM 覆盖,因此我不得不对生成的内容进行评论,并且只保留其中一个重置过程。我认为这是 Modelsim/Questa 的限制,它不能识别生成块内的 FSM,但我不是。该帮助还暗示使用泛型的 FSM 未得到认可。也许就是这里的情况。

于 2017-02-07T12:36:17.580 回答