2022年应该是我计划深入研究fpga编程的一年。 25 年来我确实没有做过任何类似的事情(当时我做了一些 GAL 逻辑)。 因此,无论出于何种意图和目的,就 HDL 内容而言,您可以将这篇文章视为新手的帖子。
我想做的事情其实很简单 - 一个带有进位和借位的简单加法器以及相应的测试台。
-- add1.vhdl
library IEEE;
use IEEE.std_logic_1164.all;
entity add1 is
port (
borrow : in std_ulogic;
a : in std_ulogic;
b : in std_ulogic;
o : out std_ulogic;
carry : out std_ulogic;
err : out std_ulogic);
end add1;
architecture add1arch of add1 is
begin
process
variable inputs : std_ulogic_vector(2 downto 0);
begin
inputs := borrow & a & b;
err <= '0';
case inputs is
when "000" =>
o <= '0';
carry <= '0';
when "100" =>
o <= '1';
carry <= '0';
when "010" =>
o <= '1';
carry <= '0';
when "001" =>
o <= '1';
carry <= '0';
when "011" =>
o <= '0';
carry <= '1';
when "110" =>
o <= '0';
carry <= '0';
when "101" =>
o <= '0';
carry <= '0';
when "111" =>
o <= '1';
carry <= '1';
when others =>
o <= '0';
carry <= '0';
err <= '1';
end case;
end process;
end architecture;
测试台是这样的:
-- add1_tb.vhdl
library IEEE;
use IEEE.std_logic_1164.all;
entity add1_tb is
end add1_tb;
architecture test of add1_tb is
component add1
port (
borrow : in std_ulogic;
a : in std_ulogic;
b : in std_ulogic;
o : out std_ulogic;
carry : out std_ulogic;
err : out std_ulogic);
end component;
signal borrow, a, b, o, carry, err : std_ulogic;
signal inputs : std_ulogic_vector(2 downto 0);
begin
adder: add1 port map
(borrow => borrow,
a => a,
b => b,
o => o,
carry => carry,
err => err);
process
begin
inputs <= borrow & a & b;
inputs <= "XXX";
wait for 1 ns;
inputs <= "000";
wait for 1 ns;
inputs <= "001";
wait for 1 ns;
inputs <= "010";
wait for 1 ns;
inputs <= "011";
wait for 1 ns;
inputs <= "100";
wait for 1 ns;
inputs <= "101";
wait for 1 ns;
inputs <= "110";
wait for 1 ns;
inputs <= "111";
wait for 1 ns;
assert false report "done.";
wait;
end process;
end architecture;
使用
ghdl --版本
GHDL 1.0.0 (Debian 1.0.0+dfsg-3) [Dunoon 版]
使用 GNAT 版本编译:10.2.1 20210110
mcode 代码生成器
由特里斯坦·金戈尔德撰写。
版权所有 (C) 2003 - 2021 特里斯坦·金戈尔德。
GHDL 是免费软件,受 GNU 通用公共许可证保护。 没有
保修单;甚至不是为了适销性或特定用途的适用性。
在 Debian bullseye 64 位机器上。
构建:
ghdl——干净
ghdl -a add1.vhdl
ghdl -a add1_tb.vhdl
ghdl -e add1_tb
ghdl -r add1_tb --vcd=add1.vcd
最后一个命令永远不会终止,当我在一段时间后使用 control-c 时,
add1.vcd
文件为空。
现在的问题将帮助我确定我的 vhdl 代码中是否存在工具链问题或错误:
有人发现我的代码有什么问题吗? (我知道它很笨拙,但由于我没有收到错误或警告,我认为它在语法上是正确的。)
事实证明,关于“敏感度列表”的建议(我必须先查找,这意味着什么......)可以轻松解决我的问题
显然,设计运行时“模拟”流程的方式取决于一些“触发器”来使“状态机”继续进行。这可以是等待,或者 - 正如我现在了解到的 - 更改“敏感度列表”中包含的信号(这是编程术语中进程的一种参数列表)。
所以,为了解决我的小问题,我所要做的就是......
-- add1.vhdl
-- ...
architecture add1arch of add1 is
begin
process (borrow, a, b) -- list signals in sensitivity list to avoid hangs!
至于测试台中的另一个问题,我试图为我的输入信号找到更好的表示法(
"001" instead of "borrow <= 0; a <= 0; b <= 1;"
),我必须做出以下更改:
-- add1_tb.vhdl
-- ...
signal inputs : std_ulogic_vector(2 downto 0);
signal o, carry, err : std_ulogic;
alias borrow : std_ulogic is inputs(0);
alias a : std_ulogic is inputs(1);
alias b : std_ulogic is inputs(2);
-- ...
现在它的行为符合预期,我可以看到 gtkwave 输出。 唯一的缺点是,gtkwave 不提供显示别名值,所以我现在只能使用输入向量。
是的,敏感度列表是你的问题。虽然实际电路并不真正需要它们,但模拟器需要它们知道何时需要重新评估过程。
如果您没有敏感度列表,则不会评估任何内容,模拟器将永远等待永远不会发生的事件。
这很奇怪、令人困惑且容易出错。我了解敏感度列表,但前几天我花了 6 个小时,因为我忘记将一个敏感度列表放入敏感度列表中,而且当模拟中事情根本没有发生时,我感到很困惑。
但实际上,这可能是使模拟易于处理的唯一方法。通过灵敏度列表,您可以限制模拟器需要查看以进行评估的信号数量,从而获得更合理的模拟性能。
也许知道敏感度列表的用途可能有助于记住?