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 上综合此设计时我有几个问题。
- 这算不算是我的计数器的良好设计,因为我在 VHDL 方面的经验还不多。
- 在我设计的进一步逻辑中使用比较单元时是否有任何未定义的状态?正如我所见,只要 counter_value 更新,就会计算 compare_match 。
- 当 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 个时钟周期的延迟,但它会改善您的整体时序。
希望这些建议能对您有所帮助,并(至少部分)解决您的疑虑。
继续编码:)
我创建了以下具有比较匹配功能的计数器:
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 上综合此设计时我有几个问题。
- 这算不算是我的计数器的良好设计,因为我在 VHDL 方面的经验还不多。
- 在我设计的进一步逻辑中使用比较单元时是否有任何未定义的状态?正如我所见,只要 counter_value 更新,就会计算 compare_match 。
- 当 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 个时钟周期的延迟,但它会改善您的整体时序。
希望这些建议能对您有所帮助,并(至少部分)解决您的疑虑。 继续编码:)