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