带有计数器的无符号加法不起作用

时间:2015-08-27 19:51:11

标签: vhdl modelsim

我正在构建一个计数器来计算输入通道的上升沿。我已将设计简化为包括两个状态onetwo,其中计数已完成。出于某种原因,每当我尝试向counter_reg添加1,或者尝试为其分配任何数字时,信号在ModelSim中变为红色,并带有X.下面提供了信号发生的代码和图片。

我已经包含了IEEE.NUMERIC_STD.ALL,所以我应该能够进行无符号加法。我不确定counter_reg有什么问题。我在柜台上做错了什么?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity photon_counter is
    Port ( clk,reset : in STD_LOGIC;
           arm,shifter,channel : in STD_LOGIC;
           start : in STD_LOGIC);
end photon_counter;

architecture fsm_arch of photon_counter is
type state_type is (idle,zero,one);
type array_type is array (1 downto 0) of UNSIGNED (15 downto 0);
signal state_reg,state_next : state_type;
signal arm_prev,shifter_prev,channel_prev : STD_LOGIC;
signal counter : array_type;
signal counter_reg,counter_next : UNSIGNED (15 downto 0);
begin
--------------------------------------
--State Register
--------------------------------------
process(clk,reset)
begin
if reset='1' then
    state_reg <= zero;
    counter_reg <= (others => '0');
    counter <= (others => (others => '0'));
elsif rising_edge(clk) then
    state_reg <= state_next;
    counter_reg <= counter_next;
    arm_prev <= arm;
    shifter_prev <= shifter;
    channel_prev <= channel;
end if;
end process;
--------------------------------------
--Next-State Logic/Output Logic
--------------------------------------
process(clk,reset,state_reg,start,counter_reg,shifter_prev,shifter,arm,channel_prev,channel)
begin
--default actions
    state_next <= state_reg;
    counter_next <= counter_reg;
    counter_reg <= counter_reg;
    case state_reg is
        when idle =>
            counter_reg <= (others => '0');
            counter <= (others => (others => '0'));
            if start = '1' then
                state_next <= zero;
            end if;
        when zero =>
            if (shifter = '1') and (shifter_prev = '0') then
                state_next <= one;
                counter(0) <= counter_reg;
            end if;
            if (channel = '1') and (channel_prev = '0') then
                counter_next <= counter_reg + 1;
            end if;
        when one =>
            if arm = '1' then
                state_next <= zero;
                counter(1) <= counter_reg;
            end if;
            if (channel = '1') and (channel_prev = '0') then
                counter_reg <= counter_reg + 1;
            end if;
    end case;
end process;
end fsm_arch;

如下所示,counter_regcounter_next以值0开始,直到我尝试向counter_next添加1。当channel_prev上升时,counter_regcounter_next都会变为X(错误)并变为红色。

ModelSim Waveform

1 个答案:

答案 0 :(得分:1)

您的counter_reg信号分配在两个不同的进程中。这就是我们所谓的“多驱动”情况。它通常是不受欢迎的,就像任何短路一样,因为当两个过程不同意分配事物的价值时会变得非常糟糕。

解决方案:从单一过程中驱动您的计数器。

更多关于这一点:如果这很糟糕,为什么在编译或启动模拟时没有出错?因为大多数人不了解或不关心VHDL中的未解析/已解决类型。默认情况下,VHDL类型为未解析。这意味着,如果您尝试从多个进程中驱动此类型的信号,您将在编译或精化时出现错误,基本上说“如果您的进程不同意,我无法决定分配什么值,这是禁止的”。这是一个非常好的功能,因为这种意外短路会产生严重后果。您可以尝试使用unsigned(已解决的)计数器替换natural(已解决)的计数器来查看错误:

signal counter_reg,counter_next : natural 0 to 2**16 - 1;

调整其余代码,看看编译时会发生什么。

有时,很少,从多个进程(高阻抗共享总线,双向RAM数据总线......)驱动信号非常有用。因此VHDL允许定义一个分辨率函数来计算几个结果值驱动程序。此函数可用于定义未解析父类型的已解析子类型。如果您能找到ieee.std_logic_1164的源代码,您将看到未解析的9值std_ulogic类型(未解析的u)的声明,解析函数和声明已解决的子类型std_logic(请参阅?no u)。

但是当使用已解决的类型时,必须自己负责不要创建短路。没有编译器错误,没有安全带。当您的一个驱动过程驱动一个强值('0'或'1')时,所有其他驱动过程必须驱动一个弱值('Z'表示高阻抗)。否则,您将得到未知的结果值,如您所见,由Modelsim以红色表示。

不幸的是,大多数人并不真正知道U代表的std_Ulogic代表什么。因此,为了简化起见,他们始终使用std_logic而不是使用的内容:std_ulogic。此外,逻辑合成器的供应商也在朝着同一个方向努力,因为他们经常支持std_logic(当他们不仅仅强迫你使用它时)。标准化ieee.numeric_std包的人也这样做:他们将unsignedsigned类型声明为已解析类型(如果事实,它们与std_logic_vector具有相同的声明) 。这与夜间驾驶全速,佩戴太阳镜,没有灯光以及没有系安全带的情况一样令人遗憾。

最后,有人意识到这是多么不幸,当前版本的ieee.numeric_std现在也声明了UNRESOLVED_UNSIGNED(别名为U_UNSIGNED)和UNRESOLVED_SIGNED(别名为U_SIGNED)。唉,这有点太晚了,大多数设计师永远不会改变他们现有的代码或习惯,我想知道如果第一选择有所不同,可以避免多少错误。

我的建议:

    如果您不打算拥有多个物理驱动程序,手动避免短路等,
  • 永远不会从多个进程中驱动信号,等等,
  • 如果您不需要,
  • 永远不会使用已解析的类型,因此如果您不小心创建了多个驱动器情况,这些工具会引发错误,
  • 在您的情况下,
  • 从单个进程中驱动counter_reg,将其声明为U_UNSIGNEDNATURAL,并将所有其他信号声明为STD_ULOGIC,而不是{{1 }}。