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


11

在逻辑设计课程中,我们都了解到可以最小化逻辑功能,例如通过使用卡诺图或Quine-McCluskey算法。我们还了解到“ Do n't Care”值增加了最小化的可能性。

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

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


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

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

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

正如你所看到的,信号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;

您能详细说明您要与write_addressand 做些write_data什么吗?您希望进行什么优化?
fru1tbat

我希望这个例子可以使我想要实现的目标更加清楚。
Fritz

Answers:


9

我将它留给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?


6

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

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

但是,有一个缺点是应该意识到的:在综合过程中,涉及无关紧要的输出驱动功能可能在综合运行之间有所不同。这使综合的确定性降低。如果使用了定义为无关的输出(错误),这会使错误更难发现。

工具支援

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

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

Xilinx和Altera将把'-'并且'X'作为不在乎,Synplify的将治疗那些并进一步'U''W'(弱)作为不在乎。


1
我有另一个缺点的应用。该代码可用于仿真,但不能用于FPGA,因为我的代码如下所示:if signal = '1' then a; else b; end if;。不幸的是,signal不是10-。因此,在仿真else中执行了分支,但在硬件中-结果是a 1,因此执行了真正的分支……
Fritz

是的,我在通过仿真时也遇到了类似的错误,但是在我的情况下,最'U'常见的是在仿真开始时就使用了s,它们导致了某些else代码块的执行。如果可以使条件以某种方式传播'U's(这与并发布尔表达式的行为类似)将是很棒的。
卡尔

在发现该错误之后,我确保总是写类似的东西if signal = '1' then output <= '1'; elsif signal='0' then output <= '0'; else output <= '-'; end if;。我在所有寄存器和存储器中添加了以下内容:assert not is_X(write_enable) report "we=" & str(A_write_enable) severity ERROR;if write_enable = '1' then assert not is_X(write_addr) report "write_addr=str(write_addr) severity ERROR; end if;。再加上相同的write_data。总之,这应该捕获几乎所有这些错误。
Fritz

那是一种方式,但是那对我来说太冗长了。我希望在VHDL语言中有这种可能性。
卡尔,

1
是的,VHDL有点冗长,但这只是VHDL方式。:D另一方面,它也是非常显式的,并且在我的背后并没有做“黑魔法”,我觉得这挺不错的(参见Python Zen:“显式优于隐式”)。
Fritz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.