【问题标题】:Issue with Synchronous Sequential Circuit using Flip Flop D使用触发器 D 的同步时序电路问题
【发布时间】:2018-05-14 00:06:49
【问题描述】:

现在我正在做一个关于在下降沿使用 D 触发器的项目,其中 x 和 y 是输入,z 是输出。

只有当 x 和 y 都为 0 并且它们在前一个时钟周期中都为 0 并且仅在时钟的下降沿发生转换时,电路才会给出 z ='1'。

变量 a 和 b 将代表状态 Q0(a) 和 Q1(b)。

Mealy 机有 Q0 和 Q1 两种状态,转换如下:

Q0

xyz

0 0 1

0 1 x

1 0 0 --> 进入下一个状态(Q1)

1 1 x

第一季度

xyz

0 0 0 --> 仅在这一次进入下一个状态 (Q0) z='0'

0 1 x

1 0 x

1 1 0 --> 保持当前状态(Q1)

问题是当从 Q1 转换到 Q0 时,z 仍然是“1”而不是“0”。

对于我如何才能绕过这种快速过渡有什么建议吗?

这是目前为止的代码:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Mealys is
  Port (
    inicio: in std_logic;
    clk: in std_logic;
    x: in std_logic;
    y: in std_logic;
    z: out std_logic;
    a: out  std_logic;
    b: out std_logic
  );
end Mealys;

architecture behavior of Mealys is

  type nombres_estados is (Q0, Q1);
  signal estado: nombres_estados;
  signal entrada_aux: std_logic_vector (1 downto 0);

begin

  entrada_aux <= x & y;

  FF_D: process (clk)
  begin
    if (inicio = '1') then
      estado <= Q0;
    elsif falling_edge(clk) then
      case estado is
        when Q0 =>
          case entrada_aux is
            when "00" => estado<=Q0;
            when "10" => estado<=Q1;
            when others => estado<=Q0;
          end case;
        when Q1 =>
          case entrada_aux is
            when "00" => estado<=Q0;
            when "11" => estado<=Q1;
            when others => estado<=Q1;
          end case;
        when others => estado<=Q0;
      end case;
    end if;
  end process;

  next_decode: process(estado, entrada_aux)
  begin
    case (estado) is
      when Q0 =>
        a <= '1';
        b <= '0';
        if entrada_aux <= "00" then
          z<='1';
        elsif entrada_aux <= "10" then
          z<='0';
        end if;
      when Q1 =>
        a <= '0';
        b <= '1';
        if entrada_aux <= "00" then
          z<='0';
        elsif entrada_aux <= "11" then
          z<='0';
        end if;
    end case;
  end process;

end behavior;

这是状态图

感谢您的宝贵时间。

【问题讨论】:

    标签: vhdl state-machine vivado flip-flop


    【解决方案1】:

    我假设您正在学习 VHDL,您从 VHDL 子集开始进行综合,最终目标是综合您的设计。

    您的设计包含两个过程:同步过程和组合过程。两者都是伪造的合成。

    1. 您的同步进程未正确处理重置。如果您的重置是异步的(即在断言时立即考虑),它应该在敏感度列表中:

      process(clk, inicio)
      begin
        if inicio = '1' then
          <initialize things>
        elsif falling_edge(clk) then
          <do things>
        end if;
      end process;
      

      如果它是同步的(仅在时钟下降沿考虑),它不应该在敏感列表中,但你的进程的重置部分应该在时钟边沿测试的范围内:

      process(clk)
      begin
        if falling_edge(clk) then
          if inicio = '1' then
            <initialize things>
          else
            <do things>
          end if;
        end if;
      end process;
      
    2. 您的组合过程有 3 个输出:abz。它们在流程的任何执行过程中都必须被赋予一个值。这就是组合的含义:每次输入发生变化时,信号都会传播,所有输出最终都会得到一个新值。 new 值可以与前一个值相同,但这一定是偶然的,而不是因为尚未分配输出。否则,这对合成器意味着:“保留先前的值”,这通常会导致推断锁存器来存储先前的值……这不是您在真正的组合过程中想要的。在你的过程中,当estadoentrada_aux 改变时,ab 被分配,但并不总是z(我让你明白为什么)。

      在这个过程中还有一个问题:相等测试运算符是=,而不是&lt;=,后者是小于或等于测试运算符。请注意,您的代码甚至不应该按原样编译。

      提出此流程的固定版本并不容易,因为您的规范并非 100% 明确。这些x 在转换表中是什么意思?例如,如果我们处于状态Q0 并且xy0111z 会发生什么?如果答案是“z 不会改变”,那么它的计算必须涉及一个内存元素,并且您必须在同步过程中对此进行描述。否则,如果它意味着“z 取任何值”(我们不在乎),那么您必须在编码之前自行决定并将其添加到您的组合过程中(例如使用 else声明)。

      我假设这意味着“z 不会改变”。因此,您需要一个存储元件(一个 D 触发器)来存储先前的值。添加另一个信号 (previous_z) 并在您的同步过程中分配它:

      signal previous_z: std_logic:
      ...
      process(clk, inicio)
      begin
        if inicio = '1' then
          previous_z <= '0';
          <initialize other things>
        elsif falling_edge(clk) then
          previous_z <= z;
          <do other things>
        end if;
      end process;
      

      这里有一个潜在的问题,因为我们正在读取 z 的值,这是您的实体的输出端口。在 2008 年之前的 VHDL 版本中,这是被禁止的。如果您使用的是 2008 之前版本的 VHDL,您必须声明另一个内部信号 (local_z),您可以读取和分配它,在任何地方使用它,并将其分配给输出 z,例如在并发信号分配中(在任何进程之外):

      signal previous_z: std_logic:
      signal local_z: std_logic:
      ...
      process(clk, inicio)
      begin
        if inicio = '1' then
          previous_z <= '0';
          <initialize other things>
        elsif falling_edge(clk) then
          previous_z <= local_z;
          <do other things>
        end if;
      end process;
      
      z <= local_z;
      

      现在,您可以在组合过程中使用此previous_z 信号来计算local_z(或VHDL 2008 中的z):

      next_decode: process(estado, entrada_aux, previous_z)
      begin
        case estado is
          when Q0 =>
            a <= '1';
            b <= '0';
            if entrada_aux = "00" then
              local_z <= '1';
            elsif entrada_aux = "10" then
              local_z <= '0';
            else
              local_z <= previous_z;
            end if;
          when Q1 =>
            a <= '0';
            b <= '1';
            if entrada_aux = "00" then
              local_z <= '0';
            elsif entrada_aux = "11" then
              local_z <= '0';
            else
              local_z <= previous_z;
            end if;
        end case;
      end process;
      

      请注意,previous_z 必须添加到敏感度列表中。您现在看到进程的local_z 输出总是如何分配的吗?

      还有一个更好的选择,即在流程开始时无条件地为每个输出分配一个默认值,并仅在需要时更改此值:

      next_decode: process(estado, entrada_aux, previous_z)
      begin
        a <= '0':
        b <= '0';
        local_z <= previous_z;
        case estado is
          when Q0 =>
            a <= '1';
            if entrada_aux = "00" then
              local_z <= '1';
            elsif entrada_aux = "10" then
              local_z <= '0';
            end if;
          when Q1 =>
            b <= '1';
            if entrada_aux = "00" then
              local_z <= '0';
            elsif entrada_aux = "11" then
              local_z <= '0';
            end if;
        end case;
      end process;
      

      这是可行的,因为在组合过程中,当一个信号被多次分配时,获胜是最后一次分配。而且这种编码风格有一个很好的特性:你不能忘记分配一个输出。

      还有另一个不错的选择:并发信号分配(在任何进程之外):

      a <= '1' when estado = Q0 else '0';
      b <= '1' when estado = Q1 else '0';
      local_z <= '1' when estado = Q0 and entrada_aux = "00" else
                 '0' when estado = Q0 and entrada_aux = "10" else
                 '0' when estado = Q1 and entrada_aux = "00" else
                 '0' when estado = Q1 and entrada_aux = "11" else
                 previous_z;
      

      当逻辑足够简单时,并发信号分配甚至可能比其他两个选项更好,因为无需担心灵敏度列表并始终分配输出。可能是非常好的点,至少对于初学者来说。

    最后一句话:您使用 std_logic 解析类型没有任何充分的理由。这是不幸的并且容易出错。您应该改用 std_ulogic,它的未解析父类型(u 表示 Unresolved)。但这超出了您的问题范围。

    【讨论】:

      猜你喜欢
      • 2019-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多