VHDL:将一个 std_logic_vector 分配给另一个会使“1”变为 'X'

VHDL: Assigning one std_logic_vector to another makes '1' turn to 'X'

我有一个莫名其妙的问题。作为缓冲过程的一部分,我将一个 std_logic_vector 分配给另一个,只需执行以下操作:

dataRegister <= dataRegisterBuf;

进程与时钟同步。完整过程请看这里:

--! This process buffers the data register synced to sclk when state is state_bufferingToSclk and sets registerReady when done
SclkDomainBuffering: process(sclk)
variable step: natural := 0;
begin
    if (rising_edge(sclk)) then
        if (state = state_bufferingToSclk) then
            if (step = 0) then
                dataRegister <= dataRegisterBuf;
                step := 1;
            elsif (step = 1) then
                registerReady <= '1';
                step := 2; 
            end if;
        else
            step := 0;
            registerReady <= '0';
        end if;
    end if;
end process SclkDomainBuffering;

问题是,当在 Modelsim 中对此进行仿真时,dataRegister 不采用 dataRegisterBuf 的值,而是向量中的每个“1”变为 'X'。因此,例如,如果 dataRegisterBuf 为“00010”,则 dataRegister 变为“000X0”。我一辈子都想不通为什么。这是一个显示它发生的模拟:http://i.imgur.com/znFgqKl.png

我已经遍历了整个代码,看不出有什么异常。在它发生时,上面代码中的第 84 行确实执行了,据我所知,这是执行的唯一与所讨论的两个寄存器有关的语句。

正如评论中的人所说,问题在于另一个进程正在驱动相同的数据寄存器。我不明白,即使其他进程只是在不同的状态下改变了寄存器的值,它仍然会在每个其他状态期间驱动信号。我通过将与该寄存器相关的所有内容移动到一个进程中解决了这个问题。

这是根据您的问题和评论创建的 Minimal Complete and Verifiable example

library ieee;
use ieee.std_logic_1164.all;

entity baffling_problem is
end entity;

architecture foo of baffling_problem is
    type state_type is (state_bufferingToClk, state_bufferingToSclk);
    signal state: state_type;  -- defaults to 'LEFT, state_bufferingToClk
    signal dataRegisterBuf:     std_logic_vector (31 downto 0) :=
                (1 | 2 => '1', others => '0');
    signal dataRegister:     std_logic_vector (31 downto 0) := (others => '0');
    signal registerReady:       std_logic;
    signal sclk:                std_logic := '1';
begin

    SclkDomainBuffering: process(sclk)
    variable step: natural := 0;
    begin
        if (rising_edge(sclk)) then
            if (state = state_bufferingToSclk) then
                if (step = 0) then
                    dataRegister <= dataRegisterBuf;
                    step := 1;
                elsif (step = 1) then
                    registerReady <= '1';
                    step := 2; 
                end if;
            else
                step := 0;
                registerReady <= '0';
            end if;
        end if;
    end process SclkDomainBuffering;
    SOMEOTHERPROCESS:
    process (state)
    begin
        if state = state_type'LEFT then  -- other than state_bufferingToSclk
            dataRegister <= (others => '0');
        end if;
    end process;
STIMULI:
    process
    begin
        wait for 20 ns;
        sclk <= '0';
        wait for 5 ns;
        sclk <= '1';
        wait for 0 ns;   -- state transitions in distinct delta cycle
        state <= state_bufferingToSclk;
        wait for 20 ns;
        sclk <= '0';
        wait for 5 ns;
        sclk <= '1';
        wait for 20 ns;
        wait;
    end process;

end architecture;

这给出了您描述的行为:

参见 IEEE 标准 1076-2008 14.7.3 信号值的传播,14.7.3.1 概述:

As simulation time advances, the transactions in the projected output waveform of a given driver (see 14.7.2) will each, in succession, become the value of the driver. When a driver acquires a new value in this way or as a result of a force or deposit scheduled for the driver, regardless of whether the new value is different from the previous value, that driver is said to be active during that simulation cycle. For the purposes of defining driver activity, a driver acquiring a value from a null transaction is assumed to have acquired a new value. A signal is said to be active during a given simulation cycle if
— One of its sources is active.
— One of its subelements is active.
— The signal is named in the formal part of an association element in a port association list and the corresponding actual is active.
— The signal is a subelement of a resolved signal and the resolved signal is active.
— A force, a deposit, or a release is scheduled for the signal.
— The signal is a subelement of another signal for which a force or a deposit is scheduled.

因此信号(dataReady(1) 和 dataReady(2) 处于活动状态,它们的源处于活动状态。

在 14.7.3.2 驱动值中找到了为什么它们的值是其驱动程序的解析值的解释,none 组成 dataReady 的信号是基本信号,请参阅第 3 f).

为什么您看到 dataReady 的值为“00000000000000000000000000000XX0”在 14.7.3.3 有效值中有描述。

VHDL 语言描述了如何模拟详细的设计模型以及描述语法和语义。详细的设计模型由在由信号互连的层次结构中描述的过程组成,信号具有历史而不仅仅是价值。在投影输出波形中安排信号更新(请参阅 10.5 信号分配语句)。

许多刚开始使用 VHDL 的用户将他们对其他语言行为的了解应用到 VHDL,一个例子是 if 语句中条件周围多余的(但不是禁止的)括号。其他语言的知识无法解决信号行为(由仿真周期驱动的仿真模型的架构决定。

您会注意到的一件事是进程 (11.3) 基于显式或隐式等待语句 (10.2) 暂停和恢复。

所有的并发语句细化为流程和/或流程和块语句(11.并发语句)。

子程序调用要么是表达式(函数,9.3.4),要么是语句(过程,10.7)。

任何计划处于活动状态的进程(那些与当前仿真时间匹配的投影输出波形,14.7.4 模型执行,14.7.3.4 信号更新)都没有更新信号值。

在多个进程中驱动的信号表示多个硬件集合。出现问题是因为您使用了已解析的数据类型,如果您使用了未解析的数据类型,则会出现详细说明错误(6.4.2.3 信号声明,第 8 段)。已解析的信号允许有多个驱动程序。

std_logic 元素的分辨率 table 可以在包 std_logic_1164 的包体中找到(参见脚注 15 附件 A 访问 VHDL 源文件的说明包包含在标准中)。分辨率 table 会将“0”和“1”解析为 'X'。

如果这一切听起来很复杂,您可以学习简单的经验法则来预防问题。

在这种情况下,经验法则是始终从单个进程驱动信号。