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

时间:2015-11-14 17:30:10

标签: vhdl simulation i2c xilinx-ise

我试图用VHDL编写I2C总线主控器 - 并对其进行全面测试以确保其正常工作等。在这样做的过程中,我已经编写了模块和随后的测试平台来测试它不同的刺激 - 即在每个发送周期后(即忙碌变低时)改变地址和数据输入。

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

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

最终我的问题是为什么会出现这些错误 - 我该如何修复/避免它们?

可以找到我的I2C主模块代码here,可以找到I2CBus(testbench)的代码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;

使用中间信号进行第二次模拟的结果 enter image description here

2 个答案:

答案 0 :(得分:3)

通常的原因是在几个不同的过程中解决了ADR等信号的多个分配。用硬件术语来说。这相当于将几个不同IC的输出短路。 (没有特别小心,它不会工作,并且会破坏你的IC)。

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

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

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

答案 1 :(得分:2)

Brian Drummond的回答是正确的。我只是用魔杖在你的例子中解释。在时间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

如果您(真的)只希望在"1111111"进程的前50 ns秒内分配reset,那么您必须分配(others => 'Z')(三态),{{之后在此过程中1}}(弱下拉)或(others => 'Z')(弱上拉)允许(others => 'H')过程“覆盖”,例如:

stim_proc