过程评估次数过多
Process evaluated too many times
我有一个简单的设计,我从 RS-232 端口读取传入字节,然后 "parse" 它们。
我试图将其分为 2 个过程:
第一个从串行端口接收位并尝试将它们成帧 - 如果成功,它将结果分配给类型为 unsigned(7 downto 0)
的名为 next_byte
的信号:
-- simplified version
rxbits := serial_rx & rxbits(...);
if (rxbits contain a frame) then:
next_byte <= ....;
rxbits := (others => '1');
end if;
第二个敏感度列表中有 next_byte
;它将 ascii '0'
/'1'
转换为位值。我假设它会在分配 next_byte
时进行评估:
-- simplified version
num <= num(...) & ascii_to_bit(next_byte);
当 next_byte
更改时,过程 2 似乎被评估了太多次:
- 如果我将
'1'
发送到FPGA,num
立即变为所有'1'
s(我稍后将其显示在七段* 4显示器上,所以我可以看到).
- 如果我发送
'0'
,num
立即更改为所有 '0'
。
为什么会这样?是什么事件导致它被评估这么多次?也许它不是 "simple" 信号(即不是 std_logic
)?
顺便说一句,运行在 Xilinx ISE 的 ISim 中使用它不会重现这些结果 - 在发送 '1'
后,num
按预期更新。
此外,如果我删除第二个进程,并简单地将第一个修改为:
-- simplified version
-- next_byte is a variable this time
rxbits := serial_rx & rxbits(...);
if (rxbits contain a frame) then:
next_byte := ....;
num <= num(...) & ascii_to_bit(next_byte);
rxbits := (others => '1');
end if;
一切正常如预期...
编辑: 我将代码稍微修改为 sum 接收到的数字的值(即 '1'
添加1
到 num
,'5'
添加 5
...)。如果我 运行 使用这两个进程,显示(显示 num
)将永远闪烁(-> 进程 2 被称为 无限期 ...);如果我 运行 它使用 1 个进程,它工作得很好。
编辑 2: 最小,但重现了问题:
signal a: unsigned(7 downto 0) := (others => '0');
signal num: unsigned(13 downto 0) := (others => '0');
...
process1: process(clk)
variable counter: unsigned(31 downto 0) := (others => '0');
begin
if rising_edge(clk) then
counter := counter + 1;
if counter(23 downto 0) = 0 then
a <= counter(31 downto 24);
end if;
end if;
end process;
process2: process(a)
begin
num <= num + a;
end process;
num
的显示永远闪烁。
但是这里:
signal num: unsigned(13 downto 0) := (others => '0');
...
process1: process(clk)
variable counter: unsigned(31 downto 0) := (others => '0');
begin
if rising_edge(clk) then
counter := counter + 1;
if counter(23 downto 0) = 0 then
num <= num + counter(31 downto 24);
end if;
end if;
end process;
效果很好,num
的显示如您所料增加。
您的问题是您希望在综合后观察敏感度列表。敏感度列表严格用于模拟。
简化后,模拟器的工作假设是它们只需要在某些输入发生变化时重新评估流程。回到指定 VHDL 时,计算哪些信号触发过程中有意义的变化的计算能力并不容易获得。因此,语言创建者诉诸于告诉模拟工具哪些信号发生变化以手动重新评估过程。
你的问题是你的灵敏度列表中缺少一个信号:num
process2: process(a)
begin
num <= num + a;
end process;
您希望仅在更改时对其进行评估。但是,硬件不能那样工作!在硬件中,这只是一个带有正反馈回路的加法器,因此它会一直继续加 a。要在您的测试台中查看正确的行为,请将 num
添加到敏感度列表,因为如果您仔细观察,您会发现 num
也在您的进程中被读取。
process2: process(a, num)
begin
num <= num + a;
end process;
您现在将在模拟工具中看到正确的行为,并且可能会收到一条消息,表明您超出了每步的最大评估次数。
想想看:
t = 0: num is 00, a is 00, num + a is also zero
t = 1: a changes to 01 due to your UART receiving '1'
num is 000, a is 01, num + a = 001
num is 001, a is 01, num + a = 002
num is 002, a is 01, num + a = 003
num is 003, a is 01, num + a = 004
num is 004, a is 01, num + a = 005
num is 005, a is 01, num + a = 006
num is 006, a is 01, num + a = 007
num is 007, a is 01, num + a = 008
num is 008, a is 01, num + a = 009
...
num is 255, a is 01, num + a = 000
num is 000, a is 01, num + a = 001
...
t = 2: simulator will never reach this point in time
如您所见,显示一直在闪烁,因为 num 处于不断递增的状态。
你也发现了,解决这个问题的方法是让你的加法器同步。添加一个 valid
信号,该信号仅在一个时钟周期内有效,以指示从 UART 到达的新字符。只有在断言 valid
时才将 a
添加到 num
。
但在更改设计中的任何内容之前,您应该查看综合工具的输出。您的综合工具可能会指示 a) 错误的灵敏度列表和 b) 设计中的组合回路。
您必须学会阅读综合工具的输出,并了解哪些警告实际上只是警告,哪些警告表明您的设计存在致命缺陷。
我有一个简单的设计,我从 RS-232 端口读取传入字节,然后 "parse" 它们。
我试图将其分为 2 个过程:
第一个从串行端口接收位并尝试将它们成帧 - 如果成功,它将结果分配给类型为
unsigned(7 downto 0)
的名为next_byte
的信号:-- simplified version rxbits := serial_rx & rxbits(...); if (rxbits contain a frame) then: next_byte <= ....; rxbits := (others => '1'); end if;
第二个敏感度列表中有
next_byte
;它将 ascii'0'
/'1'
转换为位值。我假设它会在分配next_byte
时进行评估:-- simplified version num <= num(...) & ascii_to_bit(next_byte);
当 next_byte
更改时,过程 2 似乎被评估了太多次:
- 如果我将
'1'
发送到FPGA,num
立即变为所有'1'
s(我稍后将其显示在七段* 4显示器上,所以我可以看到). - 如果我发送
'0'
,num
立即更改为所有'0'
。
为什么会这样?是什么事件导致它被评估这么多次?也许它不是 "simple" 信号(即不是 std_logic
)?
顺便说一句,运行在 Xilinx ISE 的 ISim 中使用它不会重现这些结果 - 在发送 '1'
后,num
按预期更新。
此外,如果我删除第二个进程,并简单地将第一个修改为:
-- simplified version
-- next_byte is a variable this time
rxbits := serial_rx & rxbits(...);
if (rxbits contain a frame) then:
next_byte := ....;
num <= num(...) & ascii_to_bit(next_byte);
rxbits := (others => '1');
end if;
一切正常如预期...
编辑: 我将代码稍微修改为 sum 接收到的数字的值(即 '1'
添加1
到 num
,'5'
添加 5
...)。如果我 运行 使用这两个进程,显示(显示 num
)将永远闪烁(-> 进程 2 被称为 无限期 ...);如果我 运行 它使用 1 个进程,它工作得很好。
编辑 2: 最小,但重现了问题:
signal a: unsigned(7 downto 0) := (others => '0');
signal num: unsigned(13 downto 0) := (others => '0');
...
process1: process(clk)
variable counter: unsigned(31 downto 0) := (others => '0');
begin
if rising_edge(clk) then
counter := counter + 1;
if counter(23 downto 0) = 0 then
a <= counter(31 downto 24);
end if;
end if;
end process;
process2: process(a)
begin
num <= num + a;
end process;
num
的显示永远闪烁。
但是这里:
signal num: unsigned(13 downto 0) := (others => '0');
...
process1: process(clk)
variable counter: unsigned(31 downto 0) := (others => '0');
begin
if rising_edge(clk) then
counter := counter + 1;
if counter(23 downto 0) = 0 then
num <= num + counter(31 downto 24);
end if;
end if;
end process;
效果很好,num
的显示如您所料增加。
您的问题是您希望在综合后观察敏感度列表。敏感度列表严格用于模拟。
简化后,模拟器的工作假设是它们只需要在某些输入发生变化时重新评估流程。回到指定 VHDL 时,计算哪些信号触发过程中有意义的变化的计算能力并不容易获得。因此,语言创建者诉诸于告诉模拟工具哪些信号发生变化以手动重新评估过程。
你的问题是你的灵敏度列表中缺少一个信号:num
process2: process(a)
begin
num <= num + a;
end process;
您希望仅在更改时对其进行评估。但是,硬件不能那样工作!在硬件中,这只是一个带有正反馈回路的加法器,因此它会一直继续加 a。要在您的测试台中查看正确的行为,请将 num
添加到敏感度列表,因为如果您仔细观察,您会发现 num
也在您的进程中被读取。
process2: process(a, num)
begin
num <= num + a;
end process;
您现在将在模拟工具中看到正确的行为,并且可能会收到一条消息,表明您超出了每步的最大评估次数。
想想看:
t = 0: num is 00, a is 00, num + a is also zero
t = 1: a changes to 01 due to your UART receiving '1'
num is 000, a is 01, num + a = 001
num is 001, a is 01, num + a = 002
num is 002, a is 01, num + a = 003
num is 003, a is 01, num + a = 004
num is 004, a is 01, num + a = 005
num is 005, a is 01, num + a = 006
num is 006, a is 01, num + a = 007
num is 007, a is 01, num + a = 008
num is 008, a is 01, num + a = 009
...
num is 255, a is 01, num + a = 000
num is 000, a is 01, num + a = 001
...
t = 2: simulator will never reach this point in time
如您所见,显示一直在闪烁,因为 num 处于不断递增的状态。
你也发现了,解决这个问题的方法是让你的加法器同步。添加一个 valid
信号,该信号仅在一个时钟周期内有效,以指示从 UART 到达的新字符。只有在断言 valid
时才将 a
添加到 num
。
但在更改设计中的任何内容之前,您应该查看综合工具的输出。您的综合工具可能会指示 a) 错误的灵敏度列表和 b) 设计中的组合回路。
您必须学会阅读综合工具的输出,并了解哪些警告实际上只是警告,哪些警告表明您的设计存在致命缺陷。