【问题标题】:VHDL Simulation Error on Outputs输出上的 VHDL 仿真错误
【发布时间】:2016-05-06 15:45:40
【问题描述】:

我正在尝试为 quartus II 中的 2 个模块做一个握手协议。首先,我使用了一个简单的 IF-ELSE 架构来做到这一点并且它可以工作,现在我正在尝试将这种 IF-ELSE 架构调整到状态机。电路的工作原理基本上是这样的:PRODUCER 模块向 CONSUMER 模块发送一个 4 位信号,CONSUMER 模块等待来自 PRODUCER 的 REQ 信号,当他的 REQ 信号为“1”时,需要一个“RDY”LED激活后,当用户拧紧 de RCV 按钮时,来自 CONSUMER 的 de 输出会在 4 个 LED 上显示从 PRODUCER 接收到的 4 位数据,并通过输出调用 ACK 向生产者发送确认信号。 PRODUCER 模块的状态机工作正常,但是当我模拟 CONSUMER 状态机时,输出不起作用。

在生产者和消费者模块的两个代码下方:

制作人:

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;

消费者:

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) 输出 上的生产者-消费者状态机出错:

2) 使用状态机架构和使用 IF-ELSE 架构的消费者模块模拟使用生产者:

3) 连接两个模块的BDF文件:

如果需要PRODUCER模块的架构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*****

将电路更改为具有时钟和复位入口的同步模式。 现在模拟工作了,但 LED 和输出始终保持相同的值...

新架构

消费者:

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;

制作人:

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 中两个模块的时钟和复位信号相同。 现在模拟是这样的:

现在输出的结果是 XXXX 值,这两个模块的逻辑似乎是正确的。

【问题讨论】:

  • 当您使用矢量波形文件 (VWF) 进行仿真时,Quartus-II 实际上会仿真合成网表的行为,如my answer here 中所述。合成器报告有关statenext_state(两个状态机)和o_DOUT(消费者)的锁存器的警告。只要这些警告持续存在,综合网表的行为就可能与 VHDL 描述不同。在担心模拟结果之前,您必须先修复警告。您真的要将当前的state 保存在闩锁中吗?
  • Martin,我试图做这个异步,但是如果锁存器出现问题我会做这个同步,我只需要使用时钟信号,但我真的不知道在哪里我将使用消费者和生产者模块的全局时钟信号将状态机放入代码中。我怎样才能做到这一点?感谢关注!
  • 我试图用两个状态机重现你的模拟,但在发出锁存器警告后合成器总是崩溃。要使两个单元同步,您必须将 p_state_reg 进程替换为 pastebin.com/aarkTqxJ 。现在需要两个组件中的另外两个输入i_clocki_reset,并且此输入必须连接到顶层的相同CLOCKRESET 信号。在 VWF 文件中,您必须在 CLOCK 上应用时钟波形,并在 RESET 上应用至少一个时钟周期的高脉冲。
  • 马丁,我已经按照你之前说的那样改变了电路。现在模拟正常,但输出信号始终保持 XXXX 值,我删除了之前用于执行状态的两个信号,现在我只使用了 1 个信号,我已经编辑了代码给你看。
  • 我上面评论中的代码模板是错误的。我已经在我的回答中修复了它。

标签: vhdl simulator state-machine quartus


【解决方案1】:

在 Altera FPGA 上,使用查找表 (LUT) 和逻辑元件 (LE) 内的组合反馈路径来实现锁存器。这种锁存器的状态在对 FPGA 进行编程后是未定义的。使用矢量波形文件 (VWF) 对合成网表的仿真将其显示为“X”。在您的原始代码中,合成器报告有关statenext_state(两个状态机)和o_DOUT(消费者)的锁存器的警告。因此,RDY_PRODUCERRDY_CONSUMER 等依赖于(未知)状态的信号也将是未知的(正如您所观察到的)。


使用锁存器的异步设计是可能的,但前提是 逻辑没有时序风险。 Altera 的实际要求 FPGA 在 Altera Quartus-II / Quartus Prime 手册中进行了描述, 第 1 卷,推荐的 HDL 编码风格、寄存器和锁存器编码 指导方针。

如果您的设计包含锁存器,则编译报告将 表示它们是否没有时序危害。该信息位于 分析与综合部分 -> 优化结果 -> 注册 统计信息 -> 用户指定和推断的锁存器。

Altera 和我建议改用同步设计。我有 已经在 cmets 中给出了一个代码模板,但它是 错误的。 (对不起!))您已在您的更新代码中使用它 问题,但必须再次更改为:

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 &lt;= '1') 已启用 (i_SND = '1')。

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

  3. 生产者等待确认,然后完成 之后请求 (o_REQ &lt;= '0')。

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

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

生产者的实现现在将是:

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 在第三个事务开始时被禁用 演示数据输出和确认的延迟。

模拟输出现在将是:

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

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

【讨论】:

  • 谢谢,现在可以正常工作了,用异步电路做这个真的很复杂,谢谢大家的解释!
猜你喜欢
  • 2015-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多