Часовые делители бывают разных вкусов.
Если вы смотрите на высокоскоростные часы, например, при использовании памяти с двойной скоростью передачи данных (DDR), вы действительно хотите использовать диспетчер часов FPGA. Например. Xilinx Digital Clock Manager (DCM) . Они обеспечивают очень стабильный, синхронизированный по фронту тактовый выход.
Для часов с более низкой скоростью вы можете использовать предложенный вами делитель. Тем не менее, они также бывают разных вкусов. Если коэффициент деления является целым числом, вы можете использовать простой счетчик, как вы делаете. Для этого следующего примера делитель тактовых импульсов всегда делит входную частоту на 2 (например, 50 МГц -> 25 МГц), а затем дополнительно делит на установленное соотношение (например, 25/3 = 8 1/3 МГц)
library ieee;
use ieee.std_logic_1164.all;
entity simp_clk_div is
generic(
half_clk_div_ratio : positive);
port(
input_clk : in std_logic;
output_clk : out std_logic);
end entity;
architecture rtl of simp_clk_div is
constant clk_div_cnt : natural := half_clk_div_ratio - 1;
signal cnt : natural := clk_div_cnt;
signal output_clk_i : std_logic := '0';
begin
divide : process(input_clk) begin
if rising_edge(input_clk) then
if cnt = 0 then
cnt <= clk_div_cnt;
output_clk_i <= not output_clk_i;
else
cnt <= cnt - 1;
end if;
end if;
end process;
output_clk <= output_clk_i;
end architecture;
entity simp_clk_div_tb is end entity;
library ieee;
architecture behavior of simp_clk_div_tb is
use ieee.std_logic_1164.all;
signal input_clk, output_clk : std_logic;
begin
DUT : entity work.simp_clk_div
generic map(
clk_div_ratio => 3)
port map(
input_clk => input_clk,
output_clk => output_clk);
clk_stim : process begin
input_clk <= '0', '1' after 1 ns;
wait for 2 ns;
if (now > 200 ns) then wait; end if;
end process;
end architecture;
Если вы хотите больше свободы, например преобразовать 50 МГц в 3 МГц, вы можете использовать дробный тактовый делитель. Однако этот компонент требует гораздо больше ресурсов. Кроме того, на выходе синхроимпульсов много дрожания в виде синхроимпульсов неравной длины. Но это обычно не большая проблема с низкоскоростными часами.
library ieee;
use ieee.std_logic_1164.all;
entity frac_clk_div is
generic(
input_freq : positive;
output_freq : positive);
port(
input_clk : in std_logic;
output_clk : out std_logic);
end entity;
architecture rtl of frac_clk_div is
constant cnt_sub : positive := output_freq*2;
signal cnt : natural := input_freq;
signal output_clk_i : std_logic := '0';
begin
divide : process(input_clk) begin
if rising_edge(input_clk) then
if cnt < cnt_sub then
cnt <= input_freq - (cnt_sub - cnt);
output_clk_i <= not output_clk_i;
else
cnt <= cnt - cnt_sub;
end if;
end if;
end process;
output_clk <= output_clk_i;
end architecture;
entity frac_clk_div_tb is end entity;
library ieee;
architecture behavior of frac_clk_div_tb is
use ieee.std_logic_1164.all;
signal input_clk, output_clk : std_logic;
begin
DUT : entity work.frac_clk_div
generic map(
input_freq => 50_000_000,
output_freq => 3_000_000)
port map(
input_clk => input_clk,
output_clk => output_clk);
clk_stim : process begin
input_clk <= '0', '1' after 1 ns;
wait for 2 ns;
if (now > 200 ns) then wait; end if;
end process;
end architecture;