これは、問題を解決する一般的な分数 M/D クロック分周器の設計です。これは数年前に自分用に書いたものです。ターゲットにしているデバイスによっては、bit の代わりに std_logic を使用したい場合があります。
基本的な考え方は、アキュムレータを使用して分数クロック フェーズを追跡することです。これは、ダイレクト デジタル シンセサイザー (DDS) を実装する方法と非常に似ていますが、クロックについてのみ考慮する必要があります。
楽しみ!=)
これを使用する方法が明確でない場合、 のように 39 の乗数と 50 の除数に使用するパラメーター100 * 39/100 = 78
なので、必要なオペランド幅は 6 です ( のため2**6 = 64
)。これは入力クロック レートの半分以上であるため、同期ロジックは出力クロック信号を生成できないため、このブロックのそのレートでの唯一の有効な出力はクロック イネーブルになることに注意してください。
また、考えられる除数の最悪のケースは、任意の 1 サイクルで 33%/66% のデューティ サイクルであることに注意してください。乗数と除数の特定の選択はより良いかもしれませんが(伝えるには数学を行う必要があります)、合理的な除算を使用するアルゴリズムでは、一般的に最悪の場合よりも良くなることはありません。このブロックの出力を実際のハードウェア PLL または DLL でクリーンアップして、位相ノイズをフィルター処理し、デューティ サイクルを目標範囲に収めることができます。
-- Copyright © 2010 Wesley J. Landaker <wjl@icecavern.net>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
library ieee;
use ieee.numeric_bit.all;
-- Clock Divider
-- =============
--
-- Fractionally divides the input clock using simultaneous frequency
-- multiplication and division.
--
-- Outputs both a clock enable and a balanced duty-cycle clock. The clock's
-- duty-cycle is as always close to 50% as possible, worst case is 33%/66%.
--
-- Details
-- =======
--
-- Given:
--
-- Fi = input frequency Hz
-- M = multiplier
-- D = divisor
-- Fo = output frequency Hz
--
-- Where:
--
-- M ≤ D
--
-- Then:
--
-- ⎧ M
-- ⎪ Fi·— if M <= D
-- Fo = ⎨ D
-- ⎪
-- ⎩ undefined if M > D
--
--
-- If (M/D) is greater than 0.5, only the clock enable is valid.
-- If (M/D) is greater than 1.0, both outputs are invalid.
entity Clock_Divider is
generic (
operand_width : positive
);
port (
clock : in bit;
reset : in bit;
multiplier : in unsigned(operand_width-1 downto 0);
divisor : in unsigned(operand_width-1 downto 0);
out_enable : buffer bit;
out_clock : buffer bit
);
end entity;
architecture any of Clock_Divider is
signal enable_2x : bit;
begin
-- Divide the clock by accumulating phase using the mulitplier and
-- subtracting when we pass the divisor value.
proc_enable : process is
variable phase : unsigned(operand_width downto 0);
begin
wait until rising_edge(clock);
phase := phase + multiplier;
if phase >= divisor then
phase := phase - divisor;
out_enable <= '1';
else
out_enable <= '0';
end if;
if reset = '1' then
phase := (others => '0');
out_enable <= '0';
end if;
end process;
proc_enable : process is
variable phase : unsigned(operand_width downto 0);
begin
wait until rising_edge(clock);
phase := phase + (multiplier & '0');
if phase >= divisor then
phase := phase - divisor;
enable_2x <= '1';
else
enable_2x <= '0';
end if;
if reset = '1' then
phase := (others => '0');
enable_2x <= '0';
end if;
end process;
proc_out_clock : process is
begin
wait until rising_edge(clock);
if enable_2x = '1' then
out_clock <= not out_clock;
end if;
end process;
end architecture;