如何在 VHDL 中指定“无关”信号?

电器工程 视频文件 合成 优化
2022-01-10 22:43:26

在逻辑设计课程中,我们都知道可以最小化逻辑函数,例如使用卡诺图或Quine-McCluskey 算法我们还了解到,“不关心”值增加了最小化的潜力。

例如拿一个寄存器文件。信号为时, write_addressandwrite_data信号并不重要因此,应该为它们分配一个“无关”值,以允许在驱动这些信号的逻辑中进行更多优化(即不在寄存器文件本身中)。write_enable'0'

为了让综合工具有更多空间进行可能的优化,在 VHDL 中指定此类“无关”值的正确方法是什么?


到目前为止,我发现了以下可能合适的东西。但我不太确定每种方法的优缺点是什么:

  • 只是不分配信号。这似乎可以工作。但是我发现当你想定义某种类型的“什么都不做常量”时它不起作用record,因为需要完全指定记录常量(至少 Modelsim 告诉我)。
  • std_logic_1164包定义了'-' -- Don't carestd_ulogic这看起来像是明确“不在乎”的语义正确选择,但我从未见过它在任何地方使用过(除了在不相关的 VHDL-2008case?结构中)。
  • Modelsim 使用该值'X'来显示未定义的信号。但是我不确定综合工具是否将显式'X'-assign 理解为“不关心”。

这是一个过于简化的代码片段,用于澄清,我在其中初始化了无关信号'-'

如您所见,信号control.reg_write_address可以有 3 个不同的值"----"instruction(11 downto 8);instruction(3 downto 0);'-'现在,如果被解释为“不关心”,我希望这将被合成到一个 2 输入多路复用器。(others => '0')如果我用代替初始化信号'-',该工具将不得不生成一个 3 输入多路复用器。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package mytypes is
    type control_signals_t is record
        write_enable  : std_logic;
        write_address : std_ulogic_vector(3 downto 0);
        read_address  : std_ulogic_vector(3 downto 0);
    end record;

    -- All members of this constant must be fully specified.
    -- So it's not possible to simply not assign a value.
    constant CONTROL_NOP : control_signals_t := (
        write_enable  => '0',
        write_address => (others => '-'),
        read_address  => (others => '-')
    );
end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library cfx;
use cfx.mytypes.all;

entity control_unit is
    port(
        instruction : in  std_ulogic_vector(15 downto 0);
        write_data  : out std_ulogic_vector(15 downto 0);
        ctrl        : out control_signals_t
    );
end entity;

architecture rtl of control_unit is
begin
    decode_instruction : process(instruction) is
    begin
        -- Set sensible default values that do nothing.
        -- Especially all "write_enable" signals should be '0'.
        -- Everything else is mostly irrelevant (don't care).
        ctrl       <= CONTROL_NOP;
        write_data <= (others => '-');

        if instruction(15 downto 12) = "1100" then
            -- Load 8 bit of data into the register file
            ctrl.write_enable  <= '1';
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
            ctrl.write_address <= instruction(11 downto 8);
        elsif instruction(15 downto 8) = "11111001" then
            -- Load 4 bit of data into the register file
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
            ctrl.write_address <= instruction(3 downto 0);
        elsif instruction(15 downto 8) = "10110101" then
            -- Read from the register file. Don't use the write signals at all.
            ctrl.read_address <= instruction(3 downto 0);
        end if;
    end process;
end architecture;
2个回答

我将把它留给 LRM 专家提供更详细的答案,但简而言之,您的方法应该是有效的 - 我使用最新版本的 Quartus 进行了快速测试,它'-'的处理方式与预期一样 - 生成的逻辑减少了当输出默认为'-''X'顺便说一句,也可以)时,正如预期的那样。有关您列出的方法的更多信息:

  • 当然,如果您不想要锁存器,则不分配信号并不是您的示例的真正选择。如果它是一个时钟过程,你会稍微好一点,但你仍然会在你可能不需要它们的地方获得启用。也许我在这里错过了你的意图。

  • '-',如前所述,出于语义和实际原因,可能是最佳选择。

  • 取决于您所说的“未定义”是什么意思。'X'在技​​术上是“未知的”。'U'用于未初始化的信号,ModelSim 将其显示"X"为十六进制表示。'X'不过,正如我上面提到的,它似乎确实有效。

另一种选择是自己进行优化并从显式测试中删除一个案例:

if instruction(15 downto 8) = "11111001" then
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
else
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
end if;

不过,这有很大的缺点(主要与代码清晰度有关),我可能会选择更理想的解决方案。

顺便说一句,'-'也通常与 一起使用std_match(),我会考虑将其用于您的解码,例如:

if std_match(instruction(15 downto 8), "1100----") then

虽然在这一点上,你可能最好只使用case?.

简而言之:它是合法的 VHDL,通常由综合工具支持。

然而,很少看到它被使用。我真的不知道为什么。在我看来,您的代码是一个很好的例子,说明何时使用它是有意义的。

然而,有一个缺点需要注意:在综合时,驱动输出的函数可能会在综合运行之间有所不同。这使得合成的确定性降低。如果(错误地)使用了被定义为无关的输出,这会使错误更难被发现。

工具支持

至少以下工具将接受无关紧要并利用优化的可能性:

  • Xilinx(参考:“XST 用户指南”)
  • Altera(参考:“推荐的 HDL 编码风格”)
  • Synplify(参考:“Synplify 参考手册”)

'-'Xilinx和Altera 将把'X'它们视为不关心,Synplify 将把这些'U''W'(弱)视为不关心。