为什么递增 std_logic_vector 会给出未知值?

Why does incrementing a std_logic_vector give unknown value?

我正在尝试用 VHDL 编写 I2C 总线主控器 - 并对其进行全面测试以确保其正常工作等。为此,我编写了模块和后续测试平台以在不同刺激下对其进行测试- 即在每个发送周期后更改地址和数据输入(忙变低时)。

为此,我首先尝试使用这个问题 here 中描述的技术来增加数据总线中的值并减少地址总线中的值。但是,当我这样做时,地址总线没有采用新值,而是采用了未初始化的值,并且赋值语句似乎没有执行。

然后我尝试使用中间整数信号,但是这产生了相同的结果,但这意味着地址和数据总线在第一个周期采用正确的值 - 但随后不递增而是采用未知状态!

最终我的问题是为什么会出现这些错误 - 我如何 fix/avoid 它们?

可以找到我的 I2C 主模块代码 here and the code for the I2CBus (testbench) can be found here。我可以提供的任何其他信息请直接说!

非常感谢,

大卫

-----使用中间信号的代码------

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY I2CBus IS
END I2CBus;

ARCHITECTURE behavior OF I2CBus IS
    COMPONENT IIC_Master
        PORT(
            CLOCK   : IN    std_logic;
            RESET_N : IN    std_logic;
            ENA     : IN    std_logic;
            ADR     : IN    std_logic_vector(6 downto 0);
            RW      : IN    std_logic;
            DAT_WR  : IN    std_logic_vector(7 downto 0);
            DAT_RD  : OUT   std_logic_vector(7 downto 0);
            BUSY    : OUT   std_logic;
            SCL     : INOUT std_logic;
            SDA     : INOUT std_logic;
            ACK_ERR : BUFFER std_logic
        );
    END COMPONENT;

    --Inputs
    signal CLOCK   : std_logic := '0';
    signal RESET_N : std_logic;         --active high
    signal ENA     : std_logic;         --active high
    signal ADR     : std_logic_vector(6 downto 0);
    signal RW      : std_logic;         --read high write low
    signal DAT_WR  : std_logic_vector(7 downto 0);

    --BiDirs
    signal SCL : std_logic;
    signal SDA : std_logic;

    --Outputs
    signal DAT_RD  : std_logic_vector(7 downto 0);
    signal BUSY    : std_logic;
    signal ACK_ERR : std_logic;

    -- Clock period definitions
    constant CLOCK_period : time := 5 ns;

    --Signals to vary
    signal address    : integer := 127;
    signal input_data : integer := 0;

BEGIN
    -- Instantiate the Unit Under Test (UUT)
    uut : IIC_Master PORT MAP(
            CLOCK   => CLOCK,
            RESET_N => RESET_N,
            ENA     => ENA,
            ADR     => ADR,
            RW      => RW,
            DAT_WR  => DAT_WR,
            DAT_RD  => DAT_RD,
            BUSY    => BUSY,
            SCL     => SCL,
            SDA     => SDA,
            ACK_ERR => ACK_ERR
        );

    -- Clock process definitions
    CLOCK_process : process
    begin
        CLOCK <= '0';
        wait for CLOCK_period / 2;
        CLOCK <= '1';
        wait for CLOCK_period / 2;
    end process;

    -- Reset process
    reset : process
    begin
        reset_n <= '0';
        ADR     <= "1111111";           --This doesn't seem to happen the first time?
        DAT_WR  <= "00000000";          --Nor does this?
        RW      <= '0';
        wait for 50 ns;
        reset_n <= '1';
        ENA     <= '1';

        wait;
    end process;

    stim_proc : process
    begin
        DAT_WR <= std_logic_vector(to_unsigned(input_data, 8));
        ADR    <= std_logic_vector(to_unsigned(address, 7));
        if input_data < 127 then
            address    <= address - 1;
            input_data <= input_data + 1;
            wait until BUSY = '0' and RESET_N = '1';
        elsif unsigned(DAT_WR) > 126 then
            wait;
        end if;
    end process;
end behavior;

------第一个刺激过程w/out 中间信号

stim_proc : process
begin
    if input_data < 127 then
        wait until BUSY = '0' and RESET_N = '1';
        ADR    <= std_logic_vector(unsigned(ADR) + 1);
        DAT_WR <= std_logic_vector(unsigned(DAT_WR) + 1);
    elsif unsigned(DAT_WR) > 126 then
        wait;
    end if;
end process;

使用中间信号的第二次模拟的结果

造成这种情况的常见原因是在几个不同的进程中对 ADR 等信号的多项分配进行了解析。在硬件方面。这相当于将几个不同 IC 的输出短路在一起。 (如果没有特别小心,它就无法工作,并且会破坏您的 IC)。

因此请检查您是否仅在一个进程中分配 ADR 和类似信号,如果有必要,请重写以将这些进程合并为一个进程。

如果您需要将多个输出连接在一起,有两种方法可以成功工作,但我认为这不是正确的方法。

  1. 线或输出(或线与)。在 Wired-OR 方案中,信号被 ADR <= (others -> 'L'); 之类的分配永久拉低,并且每个输出驱动 'Z' 为低或 '1' 为高可以覆盖。这是可行的,因为多个输出可以同时安全地驱动信号。
  2. 三态输出,通过仲裁确保任何时候只有一个进程驱动输出。其他人都将 'Z'(others => 'Z') 驱动到同一信号上,以表示它们处于非活动状态。

的回答是正确的。我只想在你的例子中解释。在时间 0,resetstim_proc 进程分配相同的值:

reset : process
begin
    ...
    ADR     <= "1111111";
    ...
 end process;

stim_proc : process
begin
    ADR    <= std_logic_vector(to_unsigned(address, 7)); -- with address = 127
    ...
end process;

因此,ADR 的结果是 "1111111"。但是在递减 address 之后(在中间版本的原始代码中),stim_proc 进程在重新开始后分配一个不同的值(与 reset 进程)。您会在波形中看到这一点。当地址得到126,即“1111110”时,只有ADR的最低位得到X,因为只有这一位与reset过程中分配的“1111111”不同。

解决方案 1

如果您只想初始化一个信号,请在信号声明处分配初始化值。 (我认为,根据您的 VHDL 注释,这就是您想要的。)即:

signal ADR     : std_logic_vector(6 downto 0)  := (others => '1');

解决方案 2

如果您(真的)只想在 reset 过程的前 50 ns 秒内分配 "1111111",那么您必须分配 (others => 'Z')(三态), (others => 'Z')(弱下拉)或(others => 'H')(弱上拉)在此过程之后允许stim_proc过程的"overriding",例如:

reset : process
begin
    ADR     <= "1111111";
    wait for 50 ns;
    ADR     <= (others => 'Z');
    wait;
 end process;