VHDL 无法驱动负载引脚

VHDL Cannot Drive Load pins

使用第一段代码时,我遇到了这个错误,我的一堆信号没有驱动引脚。我很确定这是因为在第一个代码片段中,第一个 if 语句从未到达。为什么会这样?在第二个片段中,我修改了代码,我所有的问题都得到了解决。我出于直觉的冲动进行了更改,我不知道为什么会解决所有问题。有人能解释一下合成器是如何产生电路的吗?

第一个片段:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity DataReg is
    generic(N: integer := 8);
    port(DIN: in std_logic_vector(N - 1 downto 0);
    DOUT: out std_logic_vector(N - 1 downto 0);
    CLK: in std_logic;
    ENABLE: in std_logic;
    RESET: in std_logic);
end DataReg;

architecture Behavioral of DataReg is
begin
    process(CLK, ENABLE)    
    begin
        if rising_edge(CLK) and ENABLE = '1' then
            DOUT <= DIN;
        end if;

        if rising_edge(CLK) and RESET = '1' then
            DOUT <= (others => '0');
        end if;
    end process;
end Behavioral;

第二个片段:(固定代码)

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity DataReg is
    generic(N: integer := 8);
    port(DIN: in std_logic_vector(N - 1 downto 0);
    DOUT: out std_logic_vector(N - 1 downto 0);
    CLK: in std_logic;
    ENABLE: in std_logic
    RESET: in std_logic);
end DataReg;

architecture Behavioral of DataReg is
begin
    process(CLK, ENABLE)    
    begin
        if rising_edge(CLK) then
            if ENABLE = '1' then
                DOUT <= DIN;
            elsif RESET = '1' then
                DOUT <= (others => '0');
            end if;
        end if;
    end process;
end Behavioral;

因为 HDL 代码必须能够表示现有的硬件。因此,当您编写 RTL(寄存器传输级)代码时,您必须坚持某些结构。连你写的第二个代码都不对。

我无法解释所有规则,但基本上,要使用边沿(上升沿或下降沿),您只能有一个信号。不是 OR-es 或 And-es 等:
if rising_edge(CLK) then

在这样的时钟部分中,您的过程可以有一个或两个以上的灵敏度信号。在某些异常情况下,通常会出现异步复位,也会出现异步设置。对于那些工作,你必须将条件 放在时钟 之前。因此你的代码是错误的。您的 ENABLE 和 RESET 仅在有时钟沿时才会被查看。因此,将 ENABLE 放入敏感列表是多余的。你不妨把它留下来。

此外,ENABLE if 在 RESET 之前。因此,如果 ENABLE 为高电平,您的 RESET 将被忽略。可能不是你想要的!

时钟部分的代码非常标准,我经常复制我手头的模板。 (我一直使用异步低电平有效复位)

process(clk, reset_n) 
begin
    if (reset_n='0') then

    elsif rising_edge(clk) then

    end if; -- reset/clocked
end process;

首先,您提供的两段代码在模拟器中甚至不等价,因为当 ENABLERESET 都在时钟边沿 1 时,第一个片段导致 DOUT 成为 00000000 而在第二个片段中它的计算结果为 DIN.

我的印象是Xilinx Vivado在综合过程中忽略了敏感性列表(process后括号中的部分)。我认为它们是模拟工具无法推断应监视哪些变量以确定何时应更新变量的时代的遗物。我不知道其他综合工具用它们做什么。

无论如何,您在敏感度列表中指定了 ENABLE,这意味着您希望在 ENABLE 更改值时评估流程语句。除非发生时钟上升沿,否则所有 if 语句的计算结果都是假的。因此,灵敏度列表中单独CLK就足以进行模拟。

综上所述,您应该将代码限制为综合工具供应商明确推荐的格式。综合工具只能实现您可以用 VHDL 编写的所有内容的一个子集。对于 Vivado,您可以在 synthesis manual 中找到建议的代码结构(这个适用于 Vivado 2017.3)。在第 71 页,您会看到他们推荐以下形式的人字拖:

process(clk) is
begin
    if rising_edge(clk) then
        if clr = '1' then
            dout <= "00000000";
        elsif ce = '1' then
            dout <= d_in;
        end if;
    end if;
end process;

当然,您可以根据需要重命名变量。在第 69 页,您还将看到 Xilinx 建议使用同步实现(将所有内容放在 rising_edge if 语句中)而不是异步实现。手册中还有更多内容,例如关于如何编写移位寄存器或 RAM,如果您想编写要用 Vivado 综合的代码,您应该熟悉这些内容。其他供应商有带有推荐代码的类似文档。