【问题标题】:Why is this not synthesizable? (does not hold its value under NOT(clock-edge))为什么这个不能合成? (在 NOT(时钟边沿)下不保持其值)
【发布时间】:2017-07-29 18:02:13
【问题描述】:

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

(是的,我完全知道该过程的“逻辑”可以替换为 ack

基本上,当 data_request 线转换为高电平时,应将 ack 输出驱动为高电平;在下降沿,它应更改为低电平驱动。 (在每种情况下,我还希望更改一大堆其他内容,因此我需要进程而不是并发语句,ack 更改它只是为了向顶级实体发出请求已完成的信号。)

什么是“不保值”?当它说“NOT(clock-edge)”时,它在说什么“时钟”?

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

【问题讨论】:

  • 我可能已经找到了一些原因...阅读后我认为灵敏度过程中“X
  • 您的综合工具将具有时序逻辑的 HDL 指南,显示从 IEEE Std 1076.6-2004(已撤销)派生的可接受形式。这里的问题是您尝试将 data_request 的两个边缘用作双数据速率时钟,而如果支持 DDR,则仅适用于 iO 单元并且需要特殊调用(并使用两个触发器)。通常每个进程只支持一个时钟边沿。想想硬件描述语言。

标签: events process vhdl clock synthesis


【解决方案1】:

问题是您的信号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 &lt;= ack;。 作为提示,我建议您每次执行 if 块时始终使用 else 语句,因为在现实世界中的电路上,您总是需要默认行为。

【讨论】:

    【解决方案2】:

    VHDL只是一种编程语言,其实很多结构都是可以的。但是,您想为设备(FPGA?)编写 VHDL。这意味着您必须根据特定规则对其进行编程。

    为了能够检测到边缘,您必须在两个时刻观察一个值:之前和之后。因此,您必须在代码中引入时间的概念。 “信号 x 在 t-1 为‘0’,在 t 为‘1’。”

    时钟时间中的时间概念在大多数可编程设备中并不为人所知。您作为程序员必须介​​绍它。在大多数数字电路中,您会为此使用具有特定频率的振荡器,通常称为“时钟”。

    数字逻辑还有一个问题,那就是延迟。电力不会通过逻辑以无限的速度传播。因此,您必须考虑通过不同行进路径的延迟。这使得设计异步逻辑变得非常困难。或者,您可以将值存储在特定位置的内存元素中以解决时序问题,称为同步逻辑。这些元素通常是寄存器。

    我之所以解释这一点,是为了激发在您的设计中引入时钟以满足您的特定要求的原因。您需要记住 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 &lt;= x when rising_edge(clk) 将推断一个寄存器,将输入延迟一个时钟周期。

    附言我假设data_request 已经与clk 同步。否则你首先需要同步它。

    p.s.2 我将when rising_edge(clk); 写成一个最小的结构,大多数 FPGA 综合工具都可以接受。如果你没有,你需要写一个完整的过程。

    【讨论】:

    • 什么时候更新 data_request_old ?你在一个异步系统上..
    • @kingsjester 我不明白你的问题。你能改写一下吗?我不在任何系统上。
    • 组件是异步的,你什么时候更新data_request_old?我想这是data_request 的先前值,但在异步系统上,您无法在时钟边缘更新它。所以我想你在data_request 值改变时更新它,这意味着在data_request 的下降沿或上升沿,这正是你想要实现的......
    • @King'sjester 首先:我不想实现任何东西。我只是在帮助提出问题的人。其次,不确定提问者想要实现什么:同步还是异步。然后是内容:提问者从 Xilinx 综合工具报错。因此,他正在为 FPGA 进行综合。 FPGA 逻辑构建块由查找表 (LUT) - 寄存器对组成,旨在实现同步设计。在 FPGA 中设计异步通信非常困难,因为您必须手动设置所有时序路径以实现时序收敛。我建议不要这样做,除非你
    • @King'sjester ... 是一位非常有经验的设计师。您的建议:(使用信号的上升沿和下降沿)不在 FPGA 中合成。时钟进程process (clk) begin if rising_edge(clk) then 将推断出一个寄存器。如果您继续使用... elsif falling_edge(clk) then,该工具通常会失败。您可以继续使用... end if; if falling_edge(clk) then,它将实例化一个时钟在NOT clk 上的second 寄存器。但是如果两个语句/寄存器都驱动相同的信号,你会得到一个“多驱动错误”。异步设计是一个单独的专长。
    【解决方案3】:

    与软件编译器相反,硬件合成通常不是逐字进行的。相反,会分析整个代码块以找到常见的结构,例如有限状态机。在您的情况下,大多数综合工具会识别一个过程,例如

    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;
    

    【讨论】:

    • 此修复程序不会导致诸如 A=A+1 之类的“上升沿代码”出现问题,其中增量会失控吗?
    • 如果你确实有这样的语句,级别触发的代码不适合你。试试其他两个仍然是边缘触发的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-24
    • 1970-01-01
    • 2016-03-19
    相关资源
    最近更新 更多