VHDL Vivado的行为仿真returns unknown(红X)over output赋值操作
VHDL Vivado's behavioral simulation returns unknown (red X) over output assignment operation
我写了这个简单的流程。它应该累加 ((b-a)/n)*yi 项,其中 yi 是每个时钟周期更新的输入,然后输出总和的结果。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Integrator is
Port ( a : in STD_LOGIC_VECTOR(7 downto 0);
b : in STD_LOGIC_VECTOR(7 downto 0);
n : in STD_LOGIC_VECTOR(7 downto 0);
yi : in STD_LOGIC_VECTOR (15 downto 0);
start : in std_logic;
clk : in std_logic;
output : out signed (15 downto 0);
done : out STD_LOGIC);
end Integrator;
architecture Integrator_arch of Integrator is
signal do : std_logic;
signal i : unsigned(7 downto 0);
signal tmp1, tmp2, tmp3, res : signed(15 downto 0);
begin
process(clk)
begin
if(clk'event and clk='1') then
if(start='1') then
do <= '1';
i <= (others=>'0');
done <= '0';
res <= (others=>'0');
elsif(do='1' and done='0') then
if(i=unsigned(n)) then
output <= res;
do <= '0';
done <= '1';
else
tmp1 <= resize(signed(b)-signed(a),16);
tmp2 <= resize(tmp1/signed(n),16);
tmp3 <= resize(tmp2*signed(yi),16);
res <= res + tmp3;
i <= i+1;
end if;
end if;
end if;
end process;
end Integrator_arch;
这是测试平台:
architecture Behavioral of Integrator_Testbench is
signal start : std_logic;
signal clk, done : std_logic;
signal yi : std_logic_vector(15 downto 0);
signal O : signed(15 downto 0);
begin
uut: entity work.integrator(integrator_arch)
port map(a=>"11111110", b=>"00000010", n=>"00000100", yi=>yi
,start=>start, clk=>clk, done=>done, output=>O);
process
begin
clk<='0';
start<='1';
wait for 200ns;
clk<='1';
wait for 200ns;
start<='0';
clk<='0';
yi<=x"0003";
wait for 200ns;
clk<='1';
yi<=x"0003";
wait for 200ns;
clk<='0';
yi<=x"0001";
wait for 200ns;
clk<='1';
yi<=x"0001";
wait for 200ns;
clk<='0';
yi<=x"0000";
wait for 200ns;
clk<='1';
yi<=x"0000";
wait for 200ns;
clk<='0';
yi<=x"0002";
wait for 200ns;
clk<='1';
yi<=x"0002";
wait for 200ns;
clk<='0';
yi<=x"0000";
wait for 200ns;
clk<='1';
yi<=x"0000";
wait for 200ns;
clk<='0';
yi<=x"0000";
wait for 200ns;
clk<='1';
yi<=x"0000";
wait for 200ns;
end process;
end Behavioral;
但这就是问题所在,当我 运行 进行行为模拟时,输出总是报告为未知(红色 X)。更奇怪的是它 运行 在调试会话中完全正常,并且通过 运行 逐行调试会话我能够得到正确的输出,即 x"0006" !!!
找问题找了两个小时后,我终于决定问了。特别是因为它 运行 完全没问题,并在逐行调试中输出正确的结果,所以我不知道为什么模拟一直在运行。
非常感谢您的宝贵时间。
通过更多的尝试和错误找到了我自己的答案
一行numeric_std
表达式的结果似乎需要一个时钟周期才能稳定下来,所以当我试图通过写
使其更具可读性时
tmp1 <= resize(signed(b)-signed(a),16);
tmp2 <= resize(tmp1/signed(n),16);
tmp3 <= resize(tmp2*signed(yi),16);
res <= res + tmp3;
需要 4 个时钟周期才能稳定下来,在这 4 个时钟周期完成之前,端口设置为未知。
所以我将所有这些行缩短为一行
res <= res + resize((resize(b-a,16)/signed(n))*yi,16);
现在结果在 1 个时钟周期内就为我准备好了。
您的启动信号应该持续更长的时间。在仿真开始时,tmp1、tmp2、tmp3 未初始化,需要 3 个时钟周期才能正确计算出 tmp3 值(因为您在时钟进程中使用了 <= 信号分配)。如果在仿真开始时,您的启动信号仅被断言一个周期,则在其解除断言后的循环中,res 会累积一个仍未初始化的 tmp3 值,因此会给出一个未知的 res。
解决方案:
- 一开始,断言再开始3个周期,
- 或声明时初始化tmp1、tmp2、tmp3
- 或者在start = 1的时候和res一起初始化
您可以更改 tmp1、tmp2、tmp3 变量的代码。时钟进程中的信号表现得像管道。这只是它是行为代码还是可综合代码,是否满足时序约束的问题。 VHDL是一种描述语言;从功能的角度来看,没有一个好的答案。
我写了这个简单的流程。它应该累加 ((b-a)/n)*yi 项,其中 yi 是每个时钟周期更新的输入,然后输出总和的结果。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity Integrator is
Port ( a : in STD_LOGIC_VECTOR(7 downto 0);
b : in STD_LOGIC_VECTOR(7 downto 0);
n : in STD_LOGIC_VECTOR(7 downto 0);
yi : in STD_LOGIC_VECTOR (15 downto 0);
start : in std_logic;
clk : in std_logic;
output : out signed (15 downto 0);
done : out STD_LOGIC);
end Integrator;
architecture Integrator_arch of Integrator is
signal do : std_logic;
signal i : unsigned(7 downto 0);
signal tmp1, tmp2, tmp3, res : signed(15 downto 0);
begin
process(clk)
begin
if(clk'event and clk='1') then
if(start='1') then
do <= '1';
i <= (others=>'0');
done <= '0';
res <= (others=>'0');
elsif(do='1' and done='0') then
if(i=unsigned(n)) then
output <= res;
do <= '0';
done <= '1';
else
tmp1 <= resize(signed(b)-signed(a),16);
tmp2 <= resize(tmp1/signed(n),16);
tmp3 <= resize(tmp2*signed(yi),16);
res <= res + tmp3;
i <= i+1;
end if;
end if;
end if;
end process;
end Integrator_arch;
这是测试平台:
architecture Behavioral of Integrator_Testbench is
signal start : std_logic;
signal clk, done : std_logic;
signal yi : std_logic_vector(15 downto 0);
signal O : signed(15 downto 0);
begin
uut: entity work.integrator(integrator_arch)
port map(a=>"11111110", b=>"00000010", n=>"00000100", yi=>yi
,start=>start, clk=>clk, done=>done, output=>O);
process
begin
clk<='0';
start<='1';
wait for 200ns;
clk<='1';
wait for 200ns;
start<='0';
clk<='0';
yi<=x"0003";
wait for 200ns;
clk<='1';
yi<=x"0003";
wait for 200ns;
clk<='0';
yi<=x"0001";
wait for 200ns;
clk<='1';
yi<=x"0001";
wait for 200ns;
clk<='0';
yi<=x"0000";
wait for 200ns;
clk<='1';
yi<=x"0000";
wait for 200ns;
clk<='0';
yi<=x"0002";
wait for 200ns;
clk<='1';
yi<=x"0002";
wait for 200ns;
clk<='0';
yi<=x"0000";
wait for 200ns;
clk<='1';
yi<=x"0000";
wait for 200ns;
clk<='0';
yi<=x"0000";
wait for 200ns;
clk<='1';
yi<=x"0000";
wait for 200ns;
end process;
end Behavioral;
但这就是问题所在,当我 运行 进行行为模拟时,输出总是报告为未知(红色 X)。更奇怪的是它 运行 在调试会话中完全正常,并且通过 运行 逐行调试会话我能够得到正确的输出,即 x"0006" !!!
找问题找了两个小时后,我终于决定问了。特别是因为它 运行 完全没问题,并在逐行调试中输出正确的结果,所以我不知道为什么模拟一直在运行。
非常感谢您的宝贵时间。
通过更多的尝试和错误找到了我自己的答案
一行numeric_std
表达式的结果似乎需要一个时钟周期才能稳定下来,所以当我试图通过写
tmp1 <= resize(signed(b)-signed(a),16);
tmp2 <= resize(tmp1/signed(n),16);
tmp3 <= resize(tmp2*signed(yi),16);
res <= res + tmp3;
需要 4 个时钟周期才能稳定下来,在这 4 个时钟周期完成之前,端口设置为未知。 所以我将所有这些行缩短为一行
res <= res + resize((resize(b-a,16)/signed(n))*yi,16);
现在结果在 1 个时钟周期内就为我准备好了。
您的启动信号应该持续更长的时间。在仿真开始时,tmp1、tmp2、tmp3 未初始化,需要 3 个时钟周期才能正确计算出 tmp3 值(因为您在时钟进程中使用了 <= 信号分配)。如果在仿真开始时,您的启动信号仅被断言一个周期,则在其解除断言后的循环中,res 会累积一个仍未初始化的 tmp3 值,因此会给出一个未知的 res。
解决方案:
- 一开始,断言再开始3个周期,
- 或声明时初始化tmp1、tmp2、tmp3
- 或者在start = 1的时候和res一起初始化
您可以更改 tmp1、tmp2、tmp3 变量的代码。时钟进程中的信号表现得像管道。这只是它是行为代码还是可综合代码,是否满足时序约束的问题。 VHDL是一种描述语言;从功能的角度来看,没有一个好的答案。