为什么这不可合成? (在NOT(时钟边缘)下不保持其值)

时间:2017-07-29 18:02:13

标签: events process vhdl clock synthesis

我是一名软件工程师(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;?

我很想解释如何解决这个问题(不改变结构),并解释我试图要求合成器做什么以及为什么合成器无法实现目标。

3 个答案:

答案 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;