VHDL 中具有比较匹配和负载的同步计数器

Synchronous counter in VHDL with compare match and load

我创建了以下具有比较匹配功能的计数器:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;

entity Counter is
    generic (
        N : natural := 24
    );

    port (
        -- Input counter clock
        clk                 : in std_logic := '0';
        -- Enable the counter
        enable              : in std_logic := '0';
        -- Preload value loaded when clk is rising and load is 1
        load_value          : in std_logic_vector((N-1) downto 0) := (others => '0');
        -- Set to 1 to load a value
        load                : in std_logic := '0';
        -- Compare match input is compared with the counter value
        compare_match_value : in std_logic_vector((N-1) downto 0) := (others => '0');
        -- Is 1 when compare_match_value = counter_value
        compare_match       : out std_logic := '0';
        output_value        : out std_logic_vector((N-1) downto 0) := (others => '0') 
    );
end Counter;

architecture Behavioral of Counter is
    signal counter_value      : unsigned((N - 1) downto 0) := to_unsigned(0, N);
begin
    output_value <= std_logic_vector(counter_value);

    process (clk) is 
    begin 
        if rising_edge(clk) then
            if enable = '1' then
                if load = '1' then
                    counter_value <= unsigned(load_value);
                else 
                    counter_value <= counter_value + 1;
                end if;
            else 
                if load = '1' then 
                    counter_value <= unsigned(load_value);
                end if;
            end if;
        end if;
    end process;

    process (counter_value) is
    begin 
        if unsigned(compare_match_value) = counter_value then 
            compare_match <= '1';
        else
            compare_match <= '0';
        end if;
    end process;
end Behavioral;

我的计数器的行为是与输入 clk 信号完全同步。始终可以禁用计数器,并且该值保持在当前计数值。可以使用负载和 load_value 信号分配负载值。每当加载信号为高并检测到上升沿时,计数器值就会更新为 load_value

另一个功能是比较单元,它在 compare_match 输出端输出高电平。仿真按预期工作,但在 spartan 3 fpga 上综合此设计时我有几个问题。

  1. 这算不算是我的计数器的良好设计,因为我在 VHDL 方面的经验还不多。
  2. 在我设计的进一步逻辑中使用比较单元时是否有任何未定义的状态?正如我所见,只要 counter_value 更新,就会计算 compare_match 。
  3. 当 N 使用较大的数字时,我需要考虑的延迟有什么特别之处吗?

总的来说,在我看来这是一个很好的描述。 但是,我想指出一些小事(这可能是我对您的第一个问题的一些回答)。

1) 因为,我现在看到您的计数器不包含任何重置(既不异步也不同步)。通常,您无法预测计数的起点(即使启动时可能全为“0”)。 在我看来,如果你能有一个复位信号,那将是一个更简洁的设计。 我还注意到,无论计数器是否启用,加载都会被激活。我对此没有评论,因为它可能是您设计的规范。也许您可以通过将 "if load" 部分移到 "if enable" 之外来压缩代码(即更改比较顺序)。 为了提高可读性(特别是当设计会更复杂时),我建议您标记过程。这将帮助您识别设计的不同部分。 如果你使用 emacs 的 VHDL 模式,你可以跳过很多额外的输入。它内置了模板,可以处理与编码相关的 "boring" 部分。 我还看到您的输入端口有默认值。在我看来,这不是一个很好的做法;它们会被合成器忽略,导致 IP 的行为可能与您预期的不同。一般而言,不要对外部信号做出假设(指定的部分)。 最后,我对比较部分有一个评论。 这适用于问题 1) 和 2)

1-2) 在比较过程中,您刚刚在敏感列表中列出了 counter_value。 这意味着当 counter_value 更改时,该进程将 被激活。 由于您将它与作为块输入的信号 (compare_match_value) 进行比较(因此它可以更改值),因此最好将它也包含在灵敏度列表中。否则,当您更改 compare_match_value 时,比较将不适用(即不会激活该过程)。 Linting 工具和合成器可能会抱怨它(发出警告,如不完整的敏感度列表)。事实上,最好在组合过程的列表中列出所有可能发生变化的信号。

关于比较本身,你描述的方式完全没问题,你不会有未发现的状态。基本上你已经指定了所有可能的条件,所以没有惊喜。

3) 关于您的第三个问题,由于您的目标是 FPGA,因此您可以 "relax" 了解它。 FPGA 具有用于快速算术运算的专用结构,并且(只要您不使用所有这些运算)合成器将使用它们来关闭时间。 同样在 ASIC 中,合成器可能 select 一个适当的算术结构来关闭时间。 如果想保险起见,可以在比较块的输出端加一个寄存器。这将防止创建长组合路径,尤其是当您的 IP 必须与其他块集成时。当然,这个额外的寄存器会增加 1 个时钟周期的延迟,但它会改善您的整体时序。

希望这些建议能对您有所帮助,并(至少部分)解决您的疑虑。 继续编码:)