为什么这不可综合? (在 NOT(clock-edge) 下不保持其值)
Why is this not synthesizable? (does not hold its value under NOT(clock-edge))
我是一名软件工程师 (JAVA/C++) 而不是电气工程师,所以你可以想象 VHDL 对我来说非常混乱,因为我不知道合成器在背后试图做什么场景。它告诉我它无法合成我认为非常简单的架构。 (事实上它是为我拥有的几个实体做的,所以我怀疑我误解了一些基本概念并在多个地方重复了架构错误。)
为什么这个不能合成...
(错误 - controller.vhd(63):语句不可综合,因为它不
在 NOT(时钟边沿)条件下保持其值。 VHDL-1242
完成:错误代码 2)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY controller IS
PORT (
ack: out STD_LOGIC := '0';
data_request: in STD_LOGIC
);
END controller;
ARCHITECTURE logic OF controller IS
BEGIN
PROCESS (data_request)
BEGIN
if (rising_edge(data_request)) then
-- other logic will be added here
ack <= '1';
elsif (falling_edge(data_request)) then
-- other logic will be added here too
ack<='0';
end if;
END PROCESS;
END logic;
(是的,我完全知道进程的 "logic" 可以替换为
确认 <= data_request;但我的 vhdl 源实际上比这复杂得多
但我已将其提炼为引发错误的最简单子集。请不要建议用不同的 structure/concurrent 语句替换该过程。)
基本上,当 data_request 线转换为高电平时,ack 输出应被驱动为高电平;在下降沿,它应该变为低电平。 (在每种情况下,我还希望更改一大堆其他内容,因此我需要流程而不是并发语句,ack更改它只是为了向顶级实体发出请求已完成的信号。)
什么是"not holding its value"?当它说 "NOT(clock-edge)" 时,它在说什么 "clock"?
我很想解释如何解决这个问题(不改变结构),并解释我试图要求合成器做什么以及为什么合成器无法实现目标。
与软件编译器相反,硬件综合通常不是逐字进行的。相反,分析整个代码块以找到常见的结构,例如有限状态机。在您的情况下,大多数综合工具都会识别诸如
之类的过程
process (...)
begin
if rising_edge(clk) then
-- code here
end if;
end process;
也就是说,只用一个检查上升沿。您的代码可能会出现问题,因为您使用相同的 if 语句检查上升沿和下降沿。
要使您的代码正常工作,只需使用两个 if 语句即可。然而,正如 指出的那样,在两个边沿上触发可能不适用于所有目标 (FPGA)。模拟没有这个限制。
您也可以尝试添加一个单独的时钟信号,它会在上升沿触发一段特定的代码。此代码然后检查 data_request
信号。
或者(但这取决于您拥有的其他代码)您可以检查 data_request
的水平而不是边缘,例如
if data_request = '1' then
-- rising edge code
else
-- falling edge code
end if;
VHDL只是一种编程语言,其实可以有很多结构。但是,您想为设备(FPGA?)编写 VHDL。这意味着您必须根据特定规则对其进行编程。
为了能够检测边缘,您必须及时观察两个时刻的值:之前和之后。因此,您必须在代码中引入时间的概念。 "signal x was '0' at t-1 and is '1' at t."
时钟时间中的时间概念在大多数可编程设备中并不为人所知。作为程序员的你必须介绍它。在大多数数字电路中,您会为此使用具有特定频率的振荡器,通常被称为 'clock'.
数字逻辑还有一个问题,那就是延迟。电力不会以无限的速度通过逻辑。因此,您必须考虑通过不同行进路径的延迟。这使得设计异步逻辑变得非常困难。或者,您可以将值存储在特定位置的内存元素中以解决时序问题,这称为同步逻辑。这些元素通常是寄存器。
为什么我解释这个,是为了激发在您的设计中为您的特定要求引入时钟的原因。您需要记住 data_request
的先前状态才能观察到变化。
signal data_request_old : std_logic;
begin
data_request_old <= data_request when rising_edge(clk);
if data_request = '1' and data_request_old = '0' then
-- rising edge
end if;
if data_request = '0' and data_request_old = '1' then
-- falling edge
end if;
x_old <= x when rising_edge(clk)
会推断一个寄存器,延迟输入一个时钟周期。
p.s。我假设 data_request
已经与 clk
同步。否则你首先需要同步它。
p.s.2 我将 when rising_edge(clk);
编写为最小结构,大多数 FPGA 综合工具都可以接受。如果你的没有,你需要写一个完整的过程。
问题是您的信号 ack
仅设置在上升沿和下降沿。综合将尝试使您的组件在具有物理约束的现实世界中工作。换句话说,您必须管理没有事件的情况。
在您的情况下,您只需在 if
中添加 else
语句,如下所示:
architecture logic of controller is
signal ack_s : std_logic := '0';
begin
process(data_request)
begin
if (rising_edge(data_request)) then
-- other logic will be added here
ack_s <= '1';
elsif (falling_edge(data_request)) then
-- other logic will be added here too
ack_s <= '0';
else then
ack_s <= ack_s;
end if;
end process;
ack <= ack_s; -- You map the output on the internal signal
end architecture logic;
这样你的信号总是映射到一个值。如果您尝试绘制原理图,您就会明白这一点。此外,您必须使用 signal
,因为当 ack
是输出时,您不能使用 ack <= ack;
。
作为提示,我建议您每次执行 if
块时始终使用 else
语句,因为在现实世界中的电路中,您始终需要默认行为。
我是一名软件工程师 (JAVA/C++) 而不是电气工程师,所以你可以想象 VHDL 对我来说非常混乱,因为我不知道合成器在背后试图做什么场景。它告诉我它无法合成我认为非常简单的架构。 (事实上它是为我拥有的几个实体做的,所以我怀疑我误解了一些基本概念并在多个地方重复了架构错误。)
为什么这个不能合成... (错误 - controller.vhd(63):语句不可综合,因为它不 在 NOT(时钟边沿)条件下保持其值。 VHDL-1242 完成:错误代码 2)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY controller IS
PORT (
ack: out STD_LOGIC := '0';
data_request: in STD_LOGIC
);
END controller;
ARCHITECTURE logic OF controller IS
BEGIN
PROCESS (data_request)
BEGIN
if (rising_edge(data_request)) then
-- other logic will be added here
ack <= '1';
elsif (falling_edge(data_request)) then
-- other logic will be added here too
ack<='0';
end if;
END PROCESS;
END logic;
(是的,我完全知道进程的 "logic" 可以替换为 确认 <= data_request;但我的 vhdl 源实际上比这复杂得多 但我已将其提炼为引发错误的最简单子集。请不要建议用不同的 structure/concurrent 语句替换该过程。)
基本上,当 data_request 线转换为高电平时,ack 输出应被驱动为高电平;在下降沿,它应该变为低电平。 (在每种情况下,我还希望更改一大堆其他内容,因此我需要流程而不是并发语句,ack更改它只是为了向顶级实体发出请求已完成的信号。)
什么是"not holding its value"?当它说 "NOT(clock-edge)" 时,它在说什么 "clock"?
我很想解释如何解决这个问题(不改变结构),并解释我试图要求合成器做什么以及为什么合成器无法实现目标。
与软件编译器相反,硬件综合通常不是逐字进行的。相反,分析整个代码块以找到常见的结构,例如有限状态机。在您的情况下,大多数综合工具都会识别诸如
之类的过程process (...)
begin
if rising_edge(clk) then
-- code here
end if;
end process;
也就是说,只用一个检查上升沿。您的代码可能会出现问题,因为您使用相同的 if 语句检查上升沿和下降沿。
要使您的代码正常工作,只需使用两个 if 语句即可。然而,正如
您也可以尝试添加一个单独的时钟信号,它会在上升沿触发一段特定的代码。此代码然后检查 data_request
信号。
或者(但这取决于您拥有的其他代码)您可以检查 data_request
的水平而不是边缘,例如
if data_request = '1' then
-- rising edge code
else
-- falling edge code
end if;
VHDL只是一种编程语言,其实可以有很多结构。但是,您想为设备(FPGA?)编写 VHDL。这意味着您必须根据特定规则对其进行编程。
为了能够检测边缘,您必须及时观察两个时刻的值:之前和之后。因此,您必须在代码中引入时间的概念。 "signal x was '0' at t-1 and is '1' at t."
时钟时间中的时间概念在大多数可编程设备中并不为人所知。作为程序员的你必须介绍它。在大多数数字电路中,您会为此使用具有特定频率的振荡器,通常被称为 'clock'.
数字逻辑还有一个问题,那就是延迟。电力不会以无限的速度通过逻辑。因此,您必须考虑通过不同行进路径的延迟。这使得设计异步逻辑变得非常困难。或者,您可以将值存储在特定位置的内存元素中以解决时序问题,这称为同步逻辑。这些元素通常是寄存器。
为什么我解释这个,是为了激发在您的设计中为您的特定要求引入时钟的原因。您需要记住 data_request
的先前状态才能观察到变化。
signal data_request_old : std_logic;
begin
data_request_old <= data_request when rising_edge(clk);
if data_request = '1' and data_request_old = '0' then
-- rising edge
end if;
if data_request = '0' and data_request_old = '1' then
-- falling edge
end if;
x_old <= x when rising_edge(clk)
会推断一个寄存器,延迟输入一个时钟周期。
p.s。我假设 data_request
已经与 clk
同步。否则你首先需要同步它。
p.s.2 我将 when rising_edge(clk);
编写为最小结构,大多数 FPGA 综合工具都可以接受。如果你的没有,你需要写一个完整的过程。
问题是您的信号 ack
仅设置在上升沿和下降沿。综合将尝试使您的组件在具有物理约束的现实世界中工作。换句话说,您必须管理没有事件的情况。
在您的情况下,您只需在 if
中添加 else
语句,如下所示:
architecture logic of controller is
signal ack_s : std_logic := '0';
begin
process(data_request)
begin
if (rising_edge(data_request)) then
-- other logic will be added here
ack_s <= '1';
elsif (falling_edge(data_request)) then
-- other logic will be added here too
ack_s <= '0';
else then
ack_s <= ack_s;
end if;
end process;
ack <= ack_s; -- You map the output on the internal signal
end architecture logic;
这样你的信号总是映射到一个值。如果您尝试绘制原理图,您就会明白这一点。此外,您必须使用 signal
,因为当 ack
是输出时,您不能使用 ack <= ack;
。
作为提示,我建议您每次执行 if
块时始终使用 else
语句,因为在现实世界中的电路中,您始终需要默认行为。