我是一名软件工程师(JAVA / C ++),而不是电气工程师,因此您可以想象VHDL对我来说完全混乱,因为我不知道合成器在幕后尝试做什么。而且它告诉我它无法综合我认为非常简单的架构。 (实际上它是我为几个实体做的,所以我怀疑我误解了一些基本概念并在多个地方重复了架构错误。)
为什么这不合成...... (ERROR - 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;
(是的,我完全清楚该过程的&#34;逻辑&#34;可以替换为 ack&lt; = data_request;但我的vhdl源实际上比这复杂得多 但我把它提炼到抛出错误的最简单的子集。请不要建议用不同的结构/并发声明替换该过程。)
基本上,当data_request线转换为高电平时,应将ack输出驱动为高电平;在下降沿,它应该改为驱动低。 (并且在每种情况下我都希望改变一大堆其他内容,因此我需要进程而不是并发语句,ack将其更改为仅向顶级实体发出请求已完成的信号。)< / p>
什么是&#34;没有保持其价值&#34;?什么&#34;时钟&#34;是在谈论&#34; NOT(时钟边缘)&#34;?
我很想解释如何解决这个问题(不改变结构),并解释我试图要求合成器做什么以及为什么合成器无法实现目标。
答案 0 :(得分:1)
VHDL只是一种编程语言,实际上很多结构都是可能的。但是,您想为设备编程VHDL(FPGA?)。这意味着您必须根据特定规则对其进行编程。
为了能够检测到边缘,您必须在两个时刻观察到一个值:a之前和之后。因此,您必须在代码中引入时间概念。 &#34;信号x是&#39; 0&#39;在t-1,是&#39; 1&#39;在t。&#34;
在大多数可编程设备中,时钟概念在时钟时间中是未知的。作为程序员,你必须介绍它。在大多数数字电路中,你会使用一个具有特定频率的振荡器,大多数被称为“时钟”。
数字逻辑还有其他问题,那就是延迟。通过逻辑,电力不会以无限速度传播。因此,您必须考虑到不同的旅行路径的延迟。这使得设计异步逻辑变得非常困难。或者,您可以将值存储在特定位置的内存元素中以修复计时问题,称为同步逻辑。这些元素通常是寄存器。
为什么我要解释这个,是为了激发为您的特定要求在您的设计中引入时钟的原因。您需要记住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综合工具都会接受。如果你没有,你需要写一整个过程。
答案 1 :(得分:1)
问题是您的信号ack
仅在上升沿和下降沿设置。综合将尝试使您的组件在现实世界中工作,具有物理限制。换句话说,你必须管理没有事件的情况。
在您的情况下,您只需在else
中添加if
语句,如下所示:
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
。
作为提示,我建议您每次执行else
块时始终有if
语句,因为在现实世界中的电路中,您总是需要默认行为。
答案 2 :(得分:0)
与软件编译器相反,合成硬件通常不是逐字逐句完成的。相反,分析整个代码块以找到常见的构造,例如有限状态机。在您的情况下,大多数综合工具将识别一个过程,如
process (...)
begin
if rising_edge(clk) then
-- code here
end if;
end process;
也就是说,只需一个检查上升沿。您的代码可能会出现问题,因为您使用相同的if语句检查上升沿和下降沿。
使代码工作可以像使用两个if语句一样简单。但是,正如user1155120指出的那样,两条边上的触发可能不适用于所有目标(FPGA)。模拟没有这个限制。
您还可以尝试添加一个单独的时钟信号,该信号将在上升沿触发某段代码。然后,此代码检查data_request
信号。
或者(但这取决于您拥有的其他代码),您可以检查data_request
的级别而不是边缘,例如。
if data_request = '1' then
-- rising edge code
else
-- falling edge code
end if;