无法使用简单的比特序列识别器电路(FSM)

时间:2017-01-05 11:14:34

标签: vhdl hardware boolean-logic state-machine circuit

这是我正在参加的硬件课程的简单练习。我们需要使用Altera Quartus II和ModelSim来测试实现;我之前从未使用过的工具,所以我可能会遗漏一些东西,而我的解释却缺乏。

该电路有3个输入(数据,时钟和复位)和2个输出(锁定,错误)。本练习中使用的序列为10001

该问题要求设计一个能识别一系列位的电路。输入正确的序列后,您将被授予访问权限(电路进入" UNLOCK"状态;锁定输出为0)。否则,如果您在任何时候输入错误的位,则会触发警报并且您应该保留在“错误”中。状态,直到电路手动复位。

"锁定"总是1,除非它到达" UNLOCK"州。 "错误"总是0,除非它到达"错误"州。

电路应该始终在" RESET"州。一旦它进入" UNLOCK"状态,只要提供的位是1,它就会保持在那里,或者转到" RESET"如果遇到0。

这是我制定的状态图:

enter image description here

欢迎任何帮助或想法!

事实证明,我的实现背后的几乎所有逻辑都是正确的,问题是在触发器上使用CLRN时的误解以及其中一个分配中的拼写错误。因此,大多数图像被删除以摆脱杂乱。

- 编辑1

使用以下代码(应该是正确的),波形不符合预期(至少lock不是)

LIBRARY ieee;
USE ieee.std_logic_1164.all; 

entity dlock is 
    port
    (
        DATA  :  IN   STD_LOGIC;
        RESET :  IN   STD_LOGIC;
        CLOCK :  IN   STD_LOGIC;
        LOCK  :  OUT  STD_LOGIC;
        ALARM :  OUT  STD_LOGIC
    );
end dlock;

architecture bdf_type of dlock is 

type STATE_type is (S_RESET, S1, S2, S3, S4, UNLOCK, S_ALARM);
signal state : STATE_type := S_RESET;

begin

process (clock) is
begin
  if (rising_edge(clock)) then
    -- `reset` always puts us back in the reset state
    if (RESET = '1') then
      state <= S_RESET;
    else
      case state is
        when S_RESET =>
          -- Reset; lock active and alarm off
          LOCK  <= '1';
          ALARM <= '0';
          if (DATA = '1') then
            -- Correct bit, proceed to next state
            state <= S1;
          else
            -- Incorrect bit; ALARM
            state <= S_ALARM;
          end if;
        when S1 => 
          if (DATA = '0') then
            state <= S2;
          else
            state <= S_ALARM;
          end if;
        when S2 => 
          if (DATA = '0') then
            state <= S3;
          else
            state <= S_ALARM;
          end if;
        when S3 => 
          if (DATA = '0') then
            state <= S4;
          else
            state <= S_ALARM;
          end if;
        when S4 => 
          if (DATA = '1') then
            state <= UNLOCK;
          else
            state <= S_ALARM;
          end if;
        when UNLOCK =>
          -- Lock inactive!
          LOCK <= '0';
          if (data = '0') then
            state <= S_RESET;
          else
            state <= UNLOCK;
          end if;
        when S_ALARM =>
          -- Alarm active in ALARM state
          ALARM <= '1';
      end case;
    end if;
  end if;
end process;
end bdf_type;

2 个答案:

答案 0 :(得分:1)

  1. 您的重置(在VHDL中编写)处于低电平状态。这意味着您大部分时间都在重置电路。您的数据模式看起来像您认为您的重置处于高效状态。

  2. 在我发布的波形图像中,您的错误信号表现正常。每次退出复位一个周期时,数据都为0,这会将您发送到错误状态。当然,这只会持续一个周期,因为你会立即重置。

  3. 这些只是毛刺,如果你放大你会看到幻像解锁发生了0次(或非常小的时间段,取决于你的门模型)。这是组合逻辑的输出不用于计时数据的一个原因。通过触发器传递值将消除毛刺。

  4. 编辑: 此外,您的状态分配表和状态输出表彼此不一致。一个列出Q downto Q2的{​​{1}}值和Q0Q0的其他列表,但都将Q2状态列为{ {1}}。这不会导致unlocked状态出现问题,因为"110"会向前和向后读取相同内容。

    EDIT2: 至于避免故障......故障是组合逻辑的本质。

    你可以直接从翻牌中获得Error而不会增加延迟,因为输入到“锁定”的翻牌是由解锁状态的相同前提条件决定的(即"111"并使用{{ 1}}。

    你可以通过将状态机机器编码转换为单热或混合单热来避免锁定是多个状态位的函数(其中存在锁定/错误状态的专用位,因为它们驱动输出位,但其他5个状态使用3个共享状态位。)

    想象一下像这样的状态表:

    locked

    locked_d = not((state=s4 or state=locked) and data=1)位是locked_qQ4 Q3 Q2 Q1 Q0 State 0 1 0 0 0 Reset 0 1 0 0 1 S1 0 1 0 1 0 S2 0 1 0 1 1 S3 0 1 1 0 0 S4 0 0 X X X Unlock 1 1 X X X Error 1 0 X X X X 0 1 1 0 1 X 0 1 1 1 X X 位是Q4

    也就是说,避免毛刺通常并不重要,因为当D输入或时钟使能时,它们在顺序逻辑中使用时不会引起问题。

答案 1 :(得分:1)

我会说你用你的方法让你的生活变得更加困难。您根本不需要这些DQ信号,只需在问题开头的优秀图表中完全按照您所见的状态编码状态机。我没有编写完整的代码,但是这应该显示导致最小的,易于阅读的结果的基本方法:

type STATE_type is (S_RESET, S1, UNLOCK, ERROR);
signal state : STATE_type := S_RESET;

...

process (clock) is
begin
  if (rising_edge(clock)) then
    -- `reset` always puts us back in the reset state
    if (reset = '1') then
      state <= S_RESET;
    else
      case state is
        when S_RESET =>
          -- Reset; lock active and alarm off
          lock <= '1';
          alarm <= '0';
          if (data = '1') then
            -- Correct bit, proceed to next state
            state <= S1;
          else
            -- Incorrect bit; error
            state <= ERROR;
          end if;
        when S1 => 
          if (data = '0') then
            state <= UNLOCK;
          else
            state <= ERROR;
          end if;
        when UNLOCK =>
          -- Lock inactive!
          lock <= '0';
          if (data = '0') then
            state <= RESET;
          end if;
        when ERROR =>
          -- Alarm active in error state
          alarm <= '1';
      end case;
    end if;
  end if;
end process;

您应该可以轻松地将其他状态S2添加到此处。

如果在lock置位后需要alarmreset更改状态,则应该实现异步复位,而不是上面示例中的同步复位:< / p>

  if (reset = '1') then
    state <= S_RESET;
    alarm <= '0';
    lock <= '1';
  elsif (rising_edge(clock)) then
    case state is
      -- `when` statements
    end case;
  end if;

以这种方式编写它的另一个好处是,您可以轻松地使所需的模式保持不变:

constant PATTERN : std_logic_vector(0 to 4) := "10001";

然后,各种状态下的数据比较如下:

when S_RESET =>
  if (data = PATTERN(0)) then

...

when S1 =>
  if (data = PATTERN(1)) then

等。然后,您可以通过简单的单行更改来更改所需的模式。