我已经为时钟分频器制作了一个代码,其好处是可以将电路板上的50mHz转换为100 Hz,并使用以下代码:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity clock_divider is
port (
clk_50Mhz : in std_logic;
reset : in std_logic;
clk_100Hz : out std_logic
);
end clock_divider;
architecture Behavioral of clock_divider is
signal counter : unsigned(23 downto 0);
--signal clk_2Hz_i : std_logic;
signal clk_100Hz_i : std_logic;
begin
gen_clk : process (clk_50Mhz, reset)
begin
if reset = '1' then
clk_100Hz_i <= '0';
counter <= (others => '0');
elsif rising_edge(clk_50Mhz) then -- rising clock edge
if counter = X"2625A0" then -- 2500000 in hex
counter <= (others => '0');
clk_100Hz_i <= not clk_100Hz_i;
else
counter <= counter + "1";
end if;
end if;
end process gen_clk;
clk_100Hz <= clk_100Hz_i;
end Behavioral;`
但是有什么好的解决方案可以在Modelsim中模拟这段代码,看它是否有效?我试过了,但我没有得到任何好的解决方案。
答案 0 :(得分:1)
为了模拟长延迟,有一种方法可以加速模拟以获得更快的结果。这可以通过顶级布尔泛型来完成,您可以检查它以确定实际延迟常数和较小的一个用于模拟。
模拟100Hz时钟并不是特别具有挑战性。单个100Hz周期内仅有1e6个时钟事件。您可以通过进程检查输出上连续边缘之间的延迟是否在某个误差范围内约为5ms来进一步自动化验证。
constant CLOCK_FREQ : integer := 50e6; -- 50 MHz
constant TARGET_FREQ : integer := 100; -- 100 Hz
...
constant MAX_ERROR : delay_length := 10 ns;
constant EXPECTED_HALF_PERIOD : delay_length := 1 sec / TARGET_FREQ / 2;
assert abs(clk_100Hz'last_event - EXPECTED_HALF_PERIOD) <= MAX_ERROR
report "100Hz clock has wrong period"
severity error;
然后你不必费心在波形窗口中测量边缘。请注意,需要在第一个生成的100Hz边沿禁止该断言,以避免在模拟开始时出现错误错误。
一般情况下,如果可能的话,最好避免在代码中使用幻数。解释性注释虽然有用但可能与实际代码不同步。无需手动将计数转换为十六进制。只需使用约束为0到250000-1(而不是2500000)的integer
类型的计数器,让仿真/综合对实现细节进行排序。
在这种情况下,您有一个模糊的错误,因为您已计算出错误的常量值。您只需要一个18位计数器,因此使用unsigned
手动构建的实现也会浪费位。最后,对于简单的计数器,向下计数到零是优选的,因为在一些目标体系结构(一个大的NOR门)中,与0进行比较会更便宜。
constant DELAY_CYCLES : integer := CLOCK_FREQ / TARGET_FREQ / 2 - 1;
signal counter : integer range 0 to DELAY_CYCLES;
if reset = '1' then
counter <= DELAY_CYCLES;
elsif rising_edge(clk_50Mhz) then
if counter = 0 then
counter <= DELAY_CYCLES;
else
counter <= counter - 1;
end if;
end if;
现在,如果您需要将系统更改为生成80 Hz或120 Hz,则只需要对TARGET_FREQ
进行简单明显的常量更改,而无需知道如何重新计算不透明的十六进制值。其他所有内容都会自动调整而无需进一步努力。