2017-07-29 60 views
2

我是一名软件工程师(JAVA/C++),而不是电气工程师,所以你可以想象VHDL对我来说是彻底的困惑,因为我不知道什么是合成器正试图在幕后做。它告诉我,它无法综合我认为是一个非常简单的架构。 (实际上它是为我的几个实体做的,所以我怀疑我误解了一些基本概念,并在多个地方重复了架构错误。)这是为什么不能合成? (在NOT(时钟边沿)不保留它的值)

为什么不能合成... (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; 

(是的,我完全知道,该过程的“逻辑”可以由 ack < = data_request替代;但是我的vhdl源实际上比t更复杂他的 ,但我已经将其归结为引发错误的最简单的子集。请不要建议用不同的结构/并发语句替换进程。)

基本上,当data_request行转换为高电平时,ack输出应该被驱动为高电平;在下降的时候应该改变为低点。 (并且在每种情况下,我都希望其他一些东西也会发生变化,因此我需要该过程而不是并发语句,但更改它只是为了向顶层实体发出请求已完成的信号。)

什么是“不持有其价值”?什么“时钟”是指什么时候它说“不(时钟边缘)”?

我很想解释如何解决这个问题(不改变结构)以及我想要问合成器做什么以及为什么合成器无法完成目标的解释。

+0

我可能已经找出了一些原因,为什么...读取后,我认为在灵敏度过程中的“X <= Y”分配中的X输出由合成器实现,其中触发器附加到灵敏度事件上作为时钟我试图用两个触发器不支持的不同时钟源来驱动触发器。它是否正确?那么,如何根据两个不同的事件来改变输出,比如两种不同的方式? – user3059763

+1

您的综合工具将具有用于顺序逻辑的HDL指南,其中显示了从IEEE Std 1076.6-2004(撤回)派生的可接受形式。这里的问题是你试图使用data_request的两个边作为双数据速率时钟,而DDR如果支持,只能用于iO单元并需要特殊调用(并使用两个触发器)。通常每个进程只能支持一个时钟边沿。认为硬件描述语言。 – user1155120

回答

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; 
+0

这种修复方法是否会导致类似A = A + 1的“上升沿代码”的问题,其中增量会失去控制? – user3059763

+0

如果你确实有这样的语句,级别触发的代码不适合你。尝试另外两个仍然是边缘触发的建议。 – Mattenii

1

VHDL只是一种编程语言,实际上很多结构都是可能的。但是,您想要为器件编程VHDL(FPGA?)。这意味着你必须按照特定的规则进行编程。

为了能够检测到边缘,您必须在两个时间点观察一个值:a前后。因此你必须在你的代码中引入时间的概念。 “信号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 <= x when rising_edge(clk)将推断寄存器,延迟输入一个时钟周期。

p.s.我假设data_request已经与clk同步。否则你首先需要同步它。

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

+0

你什么时候更新data_request_old?你在一个异步系统上。 –

+0

@kingsjester我不明白你的问题。你可以重新说明吗?我不在任何系统上。 – JHBonarius

+0

组件是异步的,所以什么时候更新'data_request_old'?我想这是'data_request'的前一个值,但是在异步系统上,您无法在时钟边缘更新它。所以我想你会在'data_request'值发生变化时更新它,这意味着'data_request'的下降沿或者上升沿就是你正在实现的目标... –

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;。 作为提示,我建议您每次做if块时总是有一个else声明,因为在现实世界的电路中,您总是需要默认行为。

相关问题