我是一名在读学生,正在寻找有关 VHDL 的知识。我知道VHDL是一种并发语言。我了解到您可以使用流程语句按顺序更新信号。我目前正在做一个项目。我有一个 Digilent 16 键键盘,已连接到我的 DE10-Lite FPGA。我创建了一个解码器,可以确定按下键盘上的哪个按钮(0-F)并输出相应的四位值(例如 4 =“0100”)。我还有一个按钮按下标志,按下按钮时该标志处于高电平状态。这个代表我按下的数字的四位值然后被驱动到另一个组件,我在其中尝试顺序更新不同的四位信号。基本上,当按下按钮(BP_in)时,我希望解码器(Dec_in)中的值代表 Num0。如果再次按下按钮,我希望解码器中的新值成为 Num0 的新值,并将 Num0 的旧值转移到另一个信号 Num1 。如果再次按下按钮,我想要 Num0 <= Dec_in, Num1 <= Num0, Num2 <= Num1. I want this cycle to continue thereafter so that each time a new input from the keypad is pressed, the numbers update sequentially. Unfortunately, when I've attempted to do this I continue to run into the same problem where the values are updated all at once causing Num0, Num1, and Num2 to all equal whatever the dec_in input is.
我尝试创建一个有限状态机,它只更新每个状态中的单个信号,但出现了同样的问题。 这是我想要工作的简单代码:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity NumShift is
port( Dec_in : in std_logic_vector(3 downto 0);
BP_in : in std_logic;
Num0 : buffer std_logic_vector(3 downto 0);
Num1 : buffer std_logic_vector(3 downto 0);
Num2 : buffer std_logic_vector(3 downto 0));
end entity NumShift;
architecture Behavioral of NumShift is
begin
process (BP_in)
begin
if (BP_in = '1') then
Num2 <= Num1;
Num1 <= Num0;
Num0 <= dec_in;
end if;
end process;
end architecture Behavioral;
让我们从代码中最明显的问题开始: 你期望它像记忆一样工作,但这不是记忆。它是一系列传播值的 MUX。请参阅下面的快照
那些复用器的行为就像锁存器(事实上,我自己甚至称它们为锁存器)。您出现此行为的原因是因为您没有在流程中分配 if 语句的所有可能分支。当您在 VHDL 进程内使用条件时,必须为该条件语句的所有可能条件分配一个值,并且在进程内用作输入的任何值都应添加到敏感度列表中。否则,您会遇到闩锁或不良行为。要解决问题,让我们看一下您的流程:
process (BP_in)
begin
if (BP_in = '1') then
Num2 <= Num1;
Num1 <= Num0;
Num0 <= dec_in;
end if;
end process;
让我们从最明显的问题开始。您的敏感度列表缺少很多信号: 在这里,仅当
BP_in
发生变化时才会触发该过程。 BP_in
的任何转换都会触发 if
条件。这意味着对进程内任何其他输入信号的任何更改都不会触发它,并且输出也不会发生更改。据我了解,您希望 dec_in
的值在发生变化时也被存储。您的进程没有表现出这种行为。因此,您必须将 dec_in
添加到敏感度列表中。此外,您使用 Num0
和 Num1
作为输入,因此这两个应添加到敏感度列表中。
我们需要解决的第二个问题是
if
条件:您只检查条件的一个可能的分支,即当BP_in = '1'
时,但是当BP_in = '0'
时会发生什么?我假设您不希望更改这些值。因此,您需要为 BP_in = '0'
时的条件分配值。有两种方法可以完成此操作:
首先是在
else
条件中添加 if
语句:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity NumShift is
...
end entity NumShift;
architecture Behavioral of NumShift is
begin
process (BP_in, Dec_in, Num2, Num1, Num0)
begin
if (BP_in = '1') then
Num2 <= Num1;
Num1 <= Num0;
Num0 <= dec_in;
else
Num2 <= Num2;
Num1 <= Num1;
Num0 <= Num0;
end if;
end process;
end architecture Behavioral;
其次是在
if
条件之前分配“默认”值:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity NumShift is
...
end entity NumShift;
architecture Behavioral of NumShift is
begin
process (BP_in, Dec_in, Num2, Num1, Num0)
begin
Num2 <= Num2;
Num1 <= Num1;
Num0 <= Num0;
if (BP_in = '1') then
Num2 <= Num1;
Num1 <= Num0;
Num0 <= dec_in;
end if;
end process;
end architecture Behavioral;
请注意,我将
Num2
添加到了敏感度列表中,因为我们在 BP_in = '0'
时使用它。此外,即使进行了这些关键的更改,MUX 的行为仍然像锁存器一样。这应该可以解决您的值未正确更新的问题。这仍然会生成上面的快照。
但是,我们仍然需要解决手头的一个更大的问题:这个电路完全是组合的。您说您希望按顺序更新这些值。这意味着您的设计需要内存。为此,您必须使用寄存器来存储值。这将包括在您的设计中添加一个时钟端口,以启用时钟边沿触发的时序逻辑。即使进行了上述修复,我也不确定您的设计是否稳健,并且您可能会发现一些问题。我建议您考虑使用移位寄存器或串联的三个不同寄存器来实现您期望的目标。
此外,我会做一些不同的事情来使这段代码更加健壮。我在下面添加了我的编辑和评论
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity NumShift is
port(
Dec_in : in std_logic_vector(3 downto 0);
BP_in : in std_logic;
Num0 : buffer std_logic_vector(3 downto 0);
Num1 : buffer std_logic_vector(3 downto 0);
Num2 : buffer std_logic_vector(3 downto 0)
);
end entity NumShift;
architecture Behavioral of NumShift is
-- use signals to carry the values from the process to output ports.
signal Num0_v : std_logic_vector(3 downto 0);
signal Num1_v : std_logic_vector(3 downto 0);
signal Num2_v : std_logic_vector(3 downto 0);
begin
process (BP_in, Dec_in, Num2_v, Num1_v, Num0_v)
begin
if (BP_in = '1') then
Num2_v <= Num1_v;
Num1_v <= Num0_v;
Num0_v <= dec_in;
else
-- This is a simple if statement so an else statement is sufficient.
Num2_v <= Num2_v;
Num1_v <= Num1_v;
Num0_v <= Num0_v;
end if;
end process;
-- always assign output ports concurently
Num2 <= Num2_v;
Num1 <= Num1_v;
Num0 <= Num0_v;
end architecture Behavioral;