输出上的 VHDL 仿真错误
VHDL Simulation Error on Outputs
我正在尝试为 quartus II 中的 2 个模块执行握手协议。首先,我使用一个简单的 IF-ELSE 架构来执行此操作并且它有效,现在我正在尝试将 IF-ELSE 的此架构调整为状态机。电路基本上是这样工作的:PRODUCER 模块向 CONSUMER 模块发送一个 4 位信号,CONSUMER 模块等待来自 PRODUCER 的 REQ 信号,当 REQ 信号为“1”时,"RDY" led 需要要被激活,当用户拧紧 de RCV 按钮时,消费者的 de 输出会在 4 个 LED 上显示从生产者接收到的 4 位数据,并通过输出调用 ACK 向生产者发送确认信号。
来自 PRODUCER 模块的状态机工作正常,但是当我模拟 CONSUMER 状态机时,输出不起作用。
下面来自 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;
我用了三种状态来做consumer的状态机:
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中两个模块的Clock和Reset信号相同。
现在模拟是这样的:
现在输出的是XXXX值,两个模块的逻辑似乎是正确的。
在 Altera FPGA 上,锁存器是使用查找 table (LUT) 和逻辑元件 (LE) 内的组合反馈路径实现的。在对 FPGA 编程后,这种锁存器的状态是不确定的。使用矢量波形文件 (VWF) 对合成网表进行的仿真将其显示为“X”。在您的原始代码中,合成器报告有关 state
和 next_state
(两个状态机)和 o_DOUT
(消费者)锁存器的警告。因此,依赖于(未知)状态的 RDY_PRODUCER
和 RDY_CONSUMER
等信号也将是未知的(如您所观察到的)。
使用锁存器的异步设计是可能的,但前提是
逻辑没有时序风险。 Altera 的实际需求
FPGA 在 Altera Quartus-II / Quartus Prime 手册中有描述,
第 1 卷,推荐的 HDL 编码风格,寄存器和锁存器编码
准则。
如果您的设计包含锁存器,那么编译报告将
表示它们是否没有时间风险。该信息位于
分析与综合部分 -> 优化结果 -> 注册
统计 -> 用户指定和推断的锁存器。
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
因为它正在等待确认。但是,消费者是
在回复之前先等待请求
承认。因此,状态机处于死锁状态。
生产者-消费者方案将按如下方式工作:
生产者发出新的请求(o_REQ <= '1'
)如果发送是
启用(i_SND = '1'
)。
消费者等待请求,如果启用接收则保存传入的数据(i_RCV = '1'
)。消费者随后回复确认 (o_ACK <= '1'
)
生产者等待确认,然后完成
之后请求 (o_REQ <= '0'
)。
消费者也完成确认(o_ACK <= '0'
)
1 个时钟周期后或请求完成后。
继续第 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;
我已经使用了您波形的输入,但需要进行一些更改:
RCV
和 SND
必须在开始时为低电平否则复位
需要。
时钟频率必须是 2 倍,因此,输入应 而不是
在时钟的上升沿附近变化。
RCV
在第三个事务开始时被禁用
演示数据输出和应答的延迟。
模拟输出现在将是:
我的波形还包括两者之间的 REQ
和 ACK
信号
用于演示握手的状态机(名为 DEBUG_REQ 和
DEBUG_ACK 这里)。
信号o_DOUT
在两个状态机中的赋值仍然描述
闩锁。根据编译报告,Quartus可以实现
他们没有时间上的危险。但是,最好实施它们
作为同步寄存器也是如此。我将把它留作练习。
我正在尝试为 quartus II 中的 2 个模块执行握手协议。首先,我使用一个简单的 IF-ELSE 架构来执行此操作并且它有效,现在我正在尝试将 IF-ELSE 的此架构调整为状态机。电路基本上是这样工作的:PRODUCER 模块向 CONSUMER 模块发送一个 4 位信号,CONSUMER 模块等待来自 PRODUCER 的 REQ 信号,当 REQ 信号为“1”时,"RDY" led 需要要被激活,当用户拧紧 de RCV 按钮时,消费者的 de 输出会在 4 个 LED 上显示从生产者接收到的 4 位数据,并通过输出调用 ACK 向生产者发送确认信号。 来自 PRODUCER 模块的状态机工作正常,但是当我模拟 CONSUMER 状态机时,输出不起作用。
下面来自 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;
我用了三种状态来做consumer的状态机:
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中两个模块的Clock和Reset信号相同。 现在模拟是这样的:
现在输出的是XXXX值,两个模块的逻辑似乎是正确的。
在 Altera FPGA 上,锁存器是使用查找 table (LUT) 和逻辑元件 (LE) 内的组合反馈路径实现的。在对 FPGA 编程后,这种锁存器的状态是不确定的。使用矢量波形文件 (VWF) 对合成网表进行的仿真将其显示为“X”。在您的原始代码中,合成器报告有关 state
和 next_state
(两个状态机)和 o_DOUT
(消费者)锁存器的警告。因此,依赖于(未知)状态的 RDY_PRODUCER
和 RDY_CONSUMER
等信号也将是未知的(如您所观察到的)。
使用锁存器的异步设计是可能的,但前提是 逻辑没有时序风险。 Altera 的实际需求 FPGA 在 Altera Quartus-II / Quartus Prime 手册中有描述, 第 1 卷,推荐的 HDL 编码风格,寄存器和锁存器编码 准则。
如果您的设计包含锁存器,那么编译报告将 表示它们是否没有时间风险。该信息位于 分析与综合部分 -> 优化结果 -> 注册 统计 -> 用户指定和推断的锁存器。
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
因为它正在等待确认。但是,消费者是
在回复之前先等待请求
承认。因此,状态机处于死锁状态。
生产者-消费者方案将按如下方式工作:
生产者发出新的请求(
o_REQ <= '1'
)如果发送是 启用(i_SND = '1'
)。消费者等待请求,如果启用接收则保存传入的数据(
i_RCV = '1'
)。消费者随后回复确认 (o_ACK <= '1'
)生产者等待确认,然后完成 之后请求 (
o_REQ <= '0'
)。消费者也完成确认(
o_ACK <= '0'
) 1 个时钟周期后或请求完成后。继续第 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;
我已经使用了您波形的输入,但需要进行一些更改:
RCV
和SND
必须在开始时为低电平否则复位 需要。时钟频率必须是 2 倍,因此,输入应 而不是 在时钟的上升沿附近变化。
RCV
在第三个事务开始时被禁用 演示数据输出和应答的延迟。
模拟输出现在将是:
我的波形还包括两者之间的 REQ
和 ACK
信号
用于演示握手的状态机(名为 DEBUG_REQ 和
DEBUG_ACK 这里)。
信号o_DOUT
在两个状态机中的赋值仍然描述
闩锁。根据编译报告,Quartus可以实现
他们没有时间上的危险。但是,最好实施它们
作为同步寄存器也是如此。我将把它留作练习。