使用触发器D的同步时序电路问题

时间:2017-11-30 06:20:12

标签: vhdl state-machine vivado flip-flop

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

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

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

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

  

Q0

     

x y z

     

0 0 1

     

0 1 x

     

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

     

1 1 x

     

Q1

     

x y z

     

0 0 0 - >仅在此时z ='0'

进入下一状态(Q0)      

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;

这是状态图 enter image description here

谢谢你的时间。

1 个答案:

答案 0 :(得分: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(我让您了解原因)。

    此过程还有另一个问题:等于测试运算符是=,而不是<=,它是较小或相等的测试运算符。请注意,您的代码甚至不应该按原样编译。

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

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

    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; 的值,它是您实体的输出端口。在2008年以前的VHDL版本中,这是被禁止的。如果您使用的是2008年之前的VHDL版本,则必须声明另一个可以读取和分配的内部信号(z),在任何地方使用它,并将其分配给输出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(或VHDL 2008中的local_z):

    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;
    

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

  3. 最后一句话:您没有任何充分理由使用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 已解决)。但这超出了你的问题范围。