输出的VHDL仿真错误

时间:2016-05-06 15:45:41

标签: vhdl simulator state-machine quartus

我试图在quartus II中为2个模块做一个握手协议。首先,我使用简单的IF-ELSE架构来实现这一点并且它可以工作,现在我试图将这种IF-ELSE架构适应状态机。电路基本上如下工作:PRODUCER模块向CONSUMER模块发送4位信号,当REQ信号为' 1时,CONSUMER模块等待来自PRODUCER的REQ信号。 a" RDY"需要激活led,当用户收紧de RCV按钮时,来自消费者的输出显示4个LED上从PRODUCER接收的4位数据,并通过输出呼叫ACK向生产者发送确认信号。 来自PRODUCER模块的状态机它正常工作,但是当我模拟消费者状态机时,输出不起作用。

以下来自PRODUCER和CONSUMER模块的两个代码:

PRODUCER:

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;

ENTITY produtor IS
  GENERIC(W : NATURAL := 4);
  PORT (o_RDY   : OUT  BIT; 
        i_SND   : IN  BIT;
        i_DIN   : IN  STD_LOGIC_VECTOR(W-1 DOWNTO 0);
        o_DOUT  : OUT  STD_LOGIC_VECTOR(W-1 DOWNTO 0);
        o_REQ   : OUT BIT;
        i_ACK   : IN BIT);
END produtor;

ARCHITECTURE arch_1 OF produtor IS
TYPE state_type IS (s0, s1);
SIGNAL state_reg : state_type;
SIGNAL next_state: state_type;

BEGIN
p_state_reg: PROCESS(i_SND,i_DIN,i_ACK)
  BEGIN
    IF (i_ACK ='0') THEN
      state_reg <= s0;
    ELSIF (i_ACK ='1') THEN
      state_reg <= next_state;
    END IF;
  END PROCESS;


 p_next_state: PROCESS(state_reg,i_SND,i_ACK)
  BEGIN
    CASE (state_reg) IS
      WHEN s0 => IF (i_ACK = '1') THEN 
                   next_state <= s1;
                 ELSIF (i_ACK = '0') THEN 
                  next_state <= s0;
                 END IF;

      WHEN s1 => IF (i_SND ='1') THEN 
                   next_state <= s1;
                 ELSIF (i_SND='0') THEN
                   next_state <= s0;
                 END IF;
   WHEN OTHERS=> next_state <= s0;
   END CASE;
  END PROCESS;

o_DOUT <= i_DIN WHEN (state_reg = s1);
o_REQ <= '1' WHEN (state_reg = s1) ELSE '0';
o_RDY <= '0'  WHEN (state_reg = s1) ELSE '1';

END arch_1;

CONSUMER:

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;

ENTITY consumidor IS
  GENERIC(W : NATURAL := 4);
  PORT (o_RDY   : OUT  BIT;
        i_RCV   : IN  BIT;
        i_DIN   : IN  STD_LOGIC_VECTOR(W-1 DOWNTO 0); 
        o_DOUT  : OUT  STD_LOGIC_VECTOR(W-1 DOWNTO 0); 
        i_REQ   : IN BIT;  
        o_ACK   : OUT BIT);
END consumidor;

ARCHITECTURE arch_1 OF consumidor IS

TYPE state_type IS (s0, s1, s2);
SIGNAL state_reg : state_type;
SIGNAL next_state: state_type;

BEGIN
p_state_reg: PROCESS(i_RCV,i_REQ,i_DIN)
  BEGIN
    IF (i_REQ ='0') THEN
      state_reg <= s0;
    ELSIF (i_REQ ='1') THEN
      state_reg <= next_state;
    END IF;
  END PROCESS;


 p_next_state: PROCESS(state_reg,i_RCV,i_REQ,i_DIN)
  BEGIN
    CASE (state_reg) IS
      WHEN s0 => IF (i_REQ = '1') THEN 
                   next_state <= s1;
                 ELSIF (i_REQ = '0') THEN 
                  next_state <= s0;
                 END IF;
                 o_RDY <= '1';
                 o_ACK <= '0';
      WHEN s1 => IF (i_RCV ='1') THEN 
                   next_state <= s2;
                 ELSIF (i_RCV='0') THEN
                   next_state <= s0;
                 END IF;
                  o_RDY <= '0'; 
                 o_ACK <= '1';
      WHEN s2 =>  o_DOUT <= i_DIN;
                  o_ACK <= '0';
                  o_RDY <= '0';
                  next_state <= s0;



   WHEN OTHERS=> next_state <= s0;
   END CASE;
  END PROCESS;

--o_DOUT <= i_DIN WHEN (state_reg = s2);
--o_ACK <= '1' WHEN (state_reg = s1) ELSE '0';
--o_RDY <= '1'  WHEN (state_reg = s0) ELSE '0';
END arch_1;

我用三种状态来做消费者的状态机:

         s0 --> Ready to receive  
         s1 --> Waiting authorization to receive (authorization is send by the RCV input)
         s2 --> Receiving

*这两个模块通过电线连接BDF文件。

下面的CONSUMER模块的架构IF-ELSE:

ARCHITECTURE arch_1 OF consumidor IS

BEGIN
  PROCESS(i_RCV, i_DIN, i_REQ)
  BEGIN
    IF (i_REQ = '1') THEN
        o_RDY <= '1';
    ELSE
        o_RDY <= '0';
    END IF;
    IF (i_RCV = '1') THEN
        o_DOUT <= i_DIN;
        o_ACK <= '1';
    ELSE
        o_ACK <= '0';
    END IF;
  END PROCESS;
END arch_1;

错误如下图所示:

1)输出enter image description here上的生产者 - 消费者状态机出错:

2)仿真使用状态机架构和使用IF-ELSE架构的消费者模块与PRODUCER一起工作:

enter image description here

3)BDF文件包含两个模块:

enter image description here

如果需要生产者模块的IF-ELSE架构来解决这个问题,请在下面进行说明:

ARCHITECTURE arch_1 OF produtor IS
SIGNAL entrada : STD_LOGIC_VECTOR (W-1 DOWNTO 0);
BEGIN
  PROCESS(i_SND,i_DIN,i_ACK)
  BEGIN
    IF (i_ACK = '1') THEN
        o_RDY <= '1';
    ELSE
        o_RDY <= '0';
    END IF;
    IF (o_RDY = '1') THEN
       IF (i_DIN(0) = '1') THEN
          entrada(0) <= '1';
       END IF;
       IF (i_DIN(0) = '0') THEN
          entrada(0) <= '0';
       END IF;
       IF (i_DIN(1) = '1') THEN
          entrada(1) <= '1';
       END IF;
       IF (i_DIN(1) = '0') THEN
          entrada(1) <= '0';
       END IF;
       IF (i_DIN(2) = '1') THEN
          entrada(2) <= '1';
       END IF;
       IF (i_DIN(2) = '0') THEN
          entrada(2) <= '0';
       END IF;
       IF (i_DIN(3) = '1') THEN
          entrada(3) <= '1';
       END IF;
       IF (i_DIN(3) = '0') THEN
          entrada(3) <= '0';
       END IF;
       IF (i_SND = '1') THEN
          o_DOUT <= entrada;
          o_REQ <= '1';
          o_RDY <= '0';
       ELSE
          o_REQ <= '0';
          o_RDY <= '1';
       END IF;
    END IF;
  END PROCESS;
END arch_1;

我认为错误发生在消费者的状态机上,在执行此状态机后,模拟不再有效。

                            *****UPDATE*****

使用时钟和复位输入将电路更改为同步模式。 现在仿真工作但Leds和输出总是保持相同的值......

新架构

CONSUMER:

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;

ENTITY consumidor IS
  GENERIC(W : NATURAL := 4);
  PORT (o_RDY   : OUT  BIT;-- data input
        i_RST   : IN BIT;
        i_CLK   : IN STD_ULOGIC;
        i_RCV   : IN  BIT;-- data input
        i_DIN   : IN  STD_LOGIC_VECTOR(W-1 DOWNTO 0);  -- clock
        o_DOUT  : OUT  STD_LOGIC_VECTOR(W-1 DOWNTO 0);  -- clear
        i_REQ   : IN BIT;  -- enable
        o_ACK   : OUT BIT);-- data output
END consumidor;

ARCHITECTURE arch_1 OF consumidor IS

TYPE state_type IS (s0, s1, s2);
SIGNAL stateT : state_type;


BEGIN
PROCESS(i_CLK)
    BEGIN
        IF rising_edge(i_CLK) THEN
          IF (i_RST = '1') THEN
            CASE stateT IS
                WHEN s0 => IF (i_REQ = '0') THEN 
                                stateT <= s0;
                           ELSE
                                stateT <= s1;
                            END IF;
                WHEN s1 => IF (i_RCV = '1') THEN
                                stateT <= s2;
                           ELSE 
                                stateT <= s0;
                           END IF;
                WHEN s2 => stateT <= s0;
             END CASE;
           END IF;
        END IF;
END PROCESS;

o_DOUT <= i_DIN WHEN (stateT = s2);
o_ACK <= '1' WHEN (stateT = s1) ELSE '0';
o_RDY <= '1'  WHEN (stateT = s0) ELSE '0';

END arch_1;

PRODUCER:

LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;
use IEEE.std_logic_arith.ALL;

ENTITY produtor IS
  GENERIC(W : NATURAL := 4);
  PORT (
        i_RST   : IN BIT;
        i_ACK   : IN BIT;
        i_CLK   : IN STD_ULOGIC;
        i_SND   : IN  BIT;-- data input
        i_DIN   : IN  STD_LOGIC_VECTOR(W-1 DOWNTO 0);  -- clock
        o_DOUT  : OUT  STD_LOGIC_VECTOR(W-1 DOWNTO 0);  -- clear
        o_REQ   : OUT BIT;  -- enable
        o_RDY   : OUT  BIT);-- data output
END produtor;

ARCHITECTURE arch_1 OF produtor IS
TYPE state_type IS (s0, s1, s2);
SIGNAL stateT : state_type;

BEGIN
PROCESS(i_CLK)
    BEGIN
        IF rising_edge(i_CLK) THEN
          IF (i_RST = '1') THEN
            CASE stateT IS
                WHEN s0 => IF (i_ACK = '0') THEN 
                                stateT <= s0;
                           ELSE
                                stateT <= s1;
                            END IF;
                WHEN s1 => IF (i_SND = '1') THEN
                                stateT <= s2;
                           ELSE 
                                stateT <= s0;
                           END IF;
                WHEN s2 => stateT <= s0;
             END CASE;
           END IF;
        END IF;
END PROCESS;


o_DOUT <= i_DIN WHEN (stateT = s2);
o_REQ <= '1' WHEN (stateT = s1) ELSE '0';
o_RDY <= '1'  WHEN (stateT = s0) ELSE '0';

END arch_1;

BDF中的两个模块的时钟和复位信号相同。 现在模拟是这样的:

Simulation

现在输出的内容保持XXXX值,两个模块的逻辑似乎是正确的。

1 个答案:

答案 0 :(得分:1)

在Altera FPGA上,使用查找表(LUT)和逻辑单元(LE)内的组合反馈路径实现锁存器。在编程FPGA之后,这种锁存器的状态是不确定的。使用矢量波形文件(VWF)模拟合成网表将其显示为&#39; X&#39; es。在原始代码中,合成器会报告有关statenext_state(两个状态机)和o_DOUT(consumidor)的锁存器的警告。因此,依赖于(未知)状态的RDY_PRODUCERRDY_CONSUMER等信号也是未知的(如您所观察到的)。

使用锁存器的异步设计是可能的,但仅限于 逻辑没有时间危险。 Altera的实际要求 FPGA在Altera Quartus-II / Quartus Prime手册中有所描述, 第1卷,推荐的HDL编码样式,寄存器和锁存编码 准则。

如果您的设计包含锁存器,那么编译报告将会 表示他们是否没有时间危险。信息见于 分析&amp;合成 - &gt;优化结果 - &gt;寄存器 统计 - &gt;用户指定和推断的锁存器。

Altera和我建议使用同步设计。我有 已经在评论中给出了代码模板,但确实如此 错误。 (对不起!))你已经在你的更新代码中使用过了 问题,但必须在另一个时间改变:

PROCESS(i_CLK)
BEGIN
    IF rising_edge(i_CLK) THEN
      IF (i_RST = '1') THEN
        stateT <= s0;
      ELSE
        CASE stateT IS
        -- description of state machine here
        END CASE;
      END IF;
    END IF;
END PROCESS;

需要在启动期间声明重置i_RST 仅限FPGA,如果状态机可以立即切换状态。该 初始状态将始终由信号声明定义 stateT

但即使解决这个问题也无济于事。制片人一直待在这里 状态s0,因为它正在等待确认。但是,消费者是 在回复之前先等待请求 确认。因此,状态机处于死锁状态。

生产者 - 消费者计划将如下工作:

  1. 如果发送,生产者会发出新请求(o_REQ <= '1') 已启用(i_SND = '1')。

  2. 如果启用了接收(i_RCV = '1'),则消费者会等待请求,然后保存传入的数据。消费者随后回复确认(o_ACK <= '1'

  3. 制作人等待确认,然后完成了 之后请求(o_REQ <= '0')。

  4. 消费者也完成了确认(o_ACK <= '0') 在1个时钟周期之后或在请求完成之后。

  5. 继续步骤1.但是,您的波形表示新的 只有当i_SND为低时,才应由生产者发布交易 之间。这对于检测新数据DIN何时可用是必要的。

  6. 生产者的实施现在将是:

    ARCHITECTURE arch_1 OF produtor IS
      TYPE state_type IS (s0, s1, s2);
      SIGNAL stateT : state_type;
    BEGIN
      PROCESS(i_CLK)
      BEGIN
        IF rising_edge(i_CLK) THEN
          IF (i_RST = '1') THEN
            stateT <= s0;
          ELSE
            CASE stateT IS
              when s0 => if (i_SND = '1') then -- wait until sending enabled
                           stateT <= s1; -- issue new request
                         end if;
    
              when s1 => if (i_ACK = '1') then -- wait until acknowledge
                           stateT <= s2; -- finish request
                         end if;
    
              when s2 => if (i_ACK = '0') and (i_SND = '0') then
                           -- wait until acknowledge finished and `i_SND` low
                           -- before starting a new transaction.
                           stateT <= s0;
                         end if;
            END CASE;
          END IF;
        END IF;
      END PROCESS;
    
      o_DOUT <= i_DIN WHEN (stateT = s0); -- latch open when ready
      o_REQ <= '1' WHEN (stateT = s1) ELSE '0';
      o_RDY <= '1'  WHEN (stateT = s0) ELSE '0';
    END arch_1;
    

    并且消费者的实现(代码更新为仅在请求后发出信号):

    ARCHITECTURE arch_1 OF consumidor IS
      TYPE state_type IS (s0, s1, s2);
      SIGNAL stateT : state_type;
    BEGIN
      PROCESS(i_CLK)
      BEGIN
        IF rising_edge(i_CLK) THEN
          IF (i_RST = '1') THEN
            stateT <= s0;
          ELSE
            CASE stateT IS
              WHEN s0 => IF (i_REQ = '1') then -- wait until request
                           stateT <= s1; -- signal ready
                         END IF;
    
              when s1 => if (i_RCV = '1') then -- wait until receiving enabled
                           stateT <= s2; -- save data and acknowledge
                         end if;
    
              WHEN s2 => IF (i_REQ = '0') then -- wait until request finished
                           stateT <= s0; -- finish acknowledge
                         END IF;
            END CASE;
          END IF;
        END IF;
      END PROCESS;
    
      o_DOUT <= i_DIN WHEN (stateT = s2); -- latch open during acknowledge
      o_ACK <= '1'  WHEN (stateT = s2) ELSE '0';
      o_RDY <= '1'  WHEN (stateT = s1) ELSE '0';
    END arch_1;
    

    我使用了波形输入,但需要进行一些更改:

    • RCVSND必须在开头为低,否则重置为 需要的。

    • 时钟频率必须是2倍,因此输入 在时钟的上升沿附近变化。

    • RCV在第三个交易开始时被禁用 证明数据输出的延迟和确认。

    模拟输出现在为:

    simulation output with o_DOUT latch

    我的波形还包括两者之间的REQACK信号 状态机来演示握手(名为DEBUG_REQ和 DEBUG_ACK这里)。

    两个状态机中信号o_DOUT的分配仍然描述 锁存器。根据编译报告,Quartus可以实现 他们没有时间危险。但是,实施它们会更好 作为同步寄存器。我将把它留作练习。