现在我正在开展一个关于在下降沿使用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;
谢谢你的时间。
答案 0 :(得分:1)
我假设你正在学习VHDL,你开始使用VHDL子集进行综合,最终目标是综合你的设计。
您的设计包括两个过程:同步一个和组合一个。两者都是合成的假。
您的同步过程无法正确处理重置。如果您的重置是异步的(即,在声明时立即考虑),它应该在敏感列表中:
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;
您的组合过程有3个输出:a
,b
和z
。在执行流程期间,必须为所有分配一个值。这就是组合的意思:每次输入改变时,信号传播,所有输出最终得到一个新值。 new 值可以与前一个值相同,但这必须是偶然的,而不是因为尚未分配输出。否则,它将对合成器意味着:“保留先前的值”,这通常会导致锁存器的推断以存储先前的值...不是您想要的真正的组合过程。在您的流程中,当estado
或entrada_aux
更改时,a
和b
已分配但不总是z
(我让您了解原因)。
此过程还有另一个问题:等于测试运算符是=
,而不是<=
,它是较小或相等的测试运算符。请注意,您的代码甚至不应该按原样编译。
提出此过程的固定版本并不容易,因为您的规范并非100%明确。这些x
在转换表中意味着什么?例如,z
如果我们处于州Q0
和xy
状态01
或11
会发生什么?如果答案是“ 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;
当逻辑足够简单时,并发信号分配甚至可能比其他两个选项更好,因为无需担心灵敏度列表并始终分配输出。可能非常好,至少对于初学者来说。
最后一句话:您没有任何充分理由使用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 已解决)。但这超出了你的问题范围。