为什么递增 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 和类似信号,如果有必要,请重写以将这些进程合并为一个进程。
如果您需要将多个输出连接在一起,有两种方法可以成功工作,但我认为这不是正确的方法。
- 线或输出(或线与)。在 Wired-OR 方案中,信号被
ADR <= (others -> 'L');
之类的分配永久拉低,并且每个输出驱动 'Z'
为低或 '1'
为高可以覆盖。这是可行的,因为多个输出可以同时安全地驱动信号。
- 三态输出,通过仲裁确保任何时候只有一个进程驱动输出。其他人都将
'Z'
或 (others => 'Z')
驱动到同一信号上,以表示它们处于非活动状态。
的回答是正确的。我只想在你的例子中解释。在时间 0,reset
和 stim_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;
我正在尝试用 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 和类似信号,如果有必要,请重写以将这些进程合并为一个进程。
如果您需要将多个输出连接在一起,有两种方法可以成功工作,但我认为这不是正确的方法。
- 线或输出(或线与)。在 Wired-OR 方案中,信号被
ADR <= (others -> 'L');
之类的分配永久拉低,并且每个输出驱动'Z'
为低或'1'
为高可以覆盖。这是可行的,因为多个输出可以同时安全地驱动信号。 - 三态输出,通过仲裁确保任何时候只有一个进程驱动输出。其他人都将
'Z'
或(others => 'Z')
驱动到同一信号上,以表示它们处于非活动状态。
reset
和 stim_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;