4

我正在上一门关于嵌入式系统设计的课程,我的一个同学已经上了另一门课程,声称另一门课程的讲师不会让他们实现这样的状态机:

architecture behavioral of sm is
    type state_t is (s1, s2, s3);
    signal state : state_t;
begin
    oneproc: process(Rst, Clk)
    begin
        if (Rst = '1') then
            -- Reset
        elsif (rising_edge(Clk)) then
            case state is
                when s1 =>
                    if (input = '1') then
                        state <= s2;
                    else
                        state <= s1;
                    end if;
                    ...
                    ...
                    ...

            end case;
        end if;
    end process;
end architecture;

但他们不得不这样做:

architecture behavioral of sm is
    type state_t is (s1, s2, s3);
    signal state, next_state : state_t;
begin
    syncproc: process(Rst, Clk)
    begin
        if (Rst = '1') then
            --Reset
        elsif (rising_edge(Clk)) then
            state   <= next_state;
        end if;
    end process;

    combproc: process(state)
    begin
        case state is
            when s1 =>
                if (input = '1') then
                    next_state <= s2;
                else
                    next_state <= s1;
                end if;
                ...
                ...
                ...

        end case;
    end process;
end architecture;

对我来说,非常缺乏经验,第一种方法看起来更简单,因为一切都是计时的,并且引入闩锁的风险更小(不是?)。

我的同学不能给我任何理由说明他的讲师为什么不让他们使用其他方式来实现它,所以我试图找出每种方式的优缺点。他们中的任何一个在行业中是首选吗?为什么我要避免其中一个?

4

5 回答 5

6

单一流程形式更简单、更短。仅此一项就减少了它包含错误的机会。

然而,它还消除了困扰对方组合过程的“不完整的敏感性列表”问题,这应该使它成为明显的赢家,无论其他任何考虑。

然而,有太多的文本和教程提出相反的建议,没有适当地证明该建议的合理性,或者(至少在一种情况下我找不到 atm)在单一过程形式中引入了一个愚蠢的错误并拒绝了整个想法,理由是那个错误。

唯一(AFAIK)单进程形式做得不好的是非时钟输出。无论如何,这些都是(IMO)糟糕的做法,因为它们在最好的时候可能是比赛,并且只有在你真的必须时才能通过单独的组合过程来处理该输出。

我猜这背后有一些实际的原因;可能是 1990 年代中期的综合工具,它无法可靠地处理单一流程形式,并使其成为讲师从中学习的原始文档。就像那些爆破的非标准std_logic_arith库一样。于是这个神话就流传了下来……

如果他们看到可以通过现代综合工具传递的内容,那些相同的讲师可能会很适合:整数、枚举、记录类型、循环、函数和更新信号的过程(Xilinx ISE 现在可以很好地处理这些。某些版本的 Synplicity 有问题函数,但接受带有 Out 参数的相同过程)。

另一个评论:我更if Rst = '1' then喜欢if (Rst = '1') then。它看起来不像线路噪声(或 C)。

于 2013-10-19T11:26:41.050 回答
4

我同意布赖恩的观点。一个进程状态机的唯一问题是您不能有非时钟输出,如果您需要输入到输出的延迟为 0,这是一个问题。否则,单一流程模型有助于最大限度地减少错误,因为它清楚地将输出与状态相关联。

我在学校被教过两种流程模型,但发现一个流程模型是工业界普遍接受的。我相信在学校使用两个过程模型的原因是它让学生了解组合逻辑相对于寄存器的位置如何根据代码的编写方式(IMO 在开始时非常重要)以及它的含义而发生变化为他们的设计。然而,简单地强迫您使用没有解释的两个流程模型并不能做到这一点。

于 2013-10-19T19:23:36.270 回答
2

第一种方法看起来更简单,因为所有东西都有时钟,并且引入闩锁的风险较小(不是?)。

是的,第一种所有东西都计时的方法没有机会引入锁存器。它可能会引入人字拖,但这很好。

第二种方法可以引入真正的异步锁存器,即使在最好的情况下,我使用的后端 FPGA 工具也不能很好地处理它,并且在某些架构中根本不支持,所以必须在门外构建或查找表。

此外,如果您在第二个过程中弄错了灵敏度列表,您的模拟可能会与您的合成结果不同!这是因为合成器(出于我已经放弃尝试理解的原因)将敏感度列表视为填充了您读取的所有信号(在此过程中完全忽略了 VHDL 语言规范),而模拟器将完全按照您的要求进行操作说。

于 2013-10-23T11:42:42.200 回答
1

啊。我个人讨厌双进程状态机。他可能是个老家伙,这是 20 年前最可靠的方法。这些工具了解您的方式,我个人更喜欢这种方法。

于 2013-10-19T16:24:12.470 回答
0

你同学说的完全正确。这里的问题是你的问题不完整。你同事的代码比你的更好的原因是人们通常在同一个过程中定义输出值和下一个状态值,如下所示(这和你自己的代码一样,只是在它上面添加了输出值,这会导致“错误”代码):

 elsif (rising_edge(clk)) then
    case state is
        when s1 =>
            --define outputs:
            outp1 <= ...;
            outp2 <= ...;
            ...
            --define next state:
            if (input = '1') then
               state <= s2;
            else
               state <= s1;
             end if;
          when s2 =>
             ...
          ...
        end case;
    end if;

回想一下,在 FSM 中,输出是由组合逻辑部分产生的,因此它是无记忆的。然而,在上面的代码中,输出值被注册,这不是 FSM 必须产生的。实际上,注册输出是 FSM 外部的逐案决策(例如,可以注册输出以消除故障,这是一个特殊的计划决策,而不是强制情况,如上面的代码中所示) .

于 2013-10-24T13:55:52.823 回答