Я использую высокоскоростные часы (из внутреннего ФАПЧ) и пытаюсь разделить их, чтобы сгенерировать 2 тактовых импульса с разным коэффициентом заполнения и фазой. Код работает правильно, если я пошаговый ввод часов. По мере увеличения частоты фаза и нагрузка вторичного выхода (iDM_out в образце кода) повреждаются. На некоторых частотах рабочий цикл вторичного выхода будет правильным. На других частотах рабочий цикл может доходить до 90 или 199%. То же самое с фазовым соотношением (DMDelay). Мне показались некоторые статьи о необходимости тактовых буферов, поэтому я пробовал несколько типов BUFF, CLKBUF и CLKINT на выходе, и это, кажется, усугубляет ситуацию. У кого-нибудь есть идеи о том, что может быть причиной этого состояния?
use work.A208_pckgs.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity DutyPhaseMod is
port (
rst : in std_logic;
GLA : in std_logic; -- GLA is 36x faster than target frequency
EXDuty : in std_logic_vector(4 downto 0); -- the number of GLA clock cycles for the EX duty cycle
DMDuty : in std_logic_vector(4 downto 0); -- the number of GLA clock cycles for the DM duty cycle
DMDelay : in std_logic_vector(4 downto 0); -- the number of GLA clock cycles for the DM phase delay
EX_out : out std_logic;
DM_out : out std_logic
);
end entity;
architecture behavioral of DutyPhaseMod is
signal iGLA : std_logic;
signal iFREQlen : integer range 0 to 35;
begin
process (rst, GLA)
variable iEX_out : std_logic;
variable iDM_out : std_logic;
variable iEXctr : natural range 0 to 35;
variable iDMctr : natural range 0 to 35;
begin
iFREQlen <= 35; -- number of clock cycles
if rst = '1' then -- reset the counters on reset signal
iEXctr := 0;
iDMctr := 0;
elsif rising_edge(GLA) then
if iEXctr <= unsigned(EXDuty) then -- first part of EX the duty cycle
iEX_out := '1';
iEXctr := iEXctr + 1;
elsif iEXctr < iFREQlen then -- second part of EX duty cycle
iEX_out := '0';
iEXctr := iEXctr + 1;
else -- set for the start of the next cycle
iEX_out := '1';
iEXctr := 0;
end if;
if iEXctr = unsigned(DMDelay) then -- reset for DM phase offset
iDMctr := 0;
elsif iDMctr <= unsigned(DMDuty) then -- first part of the DM duty cycle
iDM_out := '1';
iDMctr := iDMctr + 1;
elsif iDMctr <= iFREQlen - 1 then -- second part of the DM duty cycle
iDM_out := '0';
iDMctr := iDMctr + 1;
else -- set for the start of the next cycle
iDM_out := '1';
end if;
EX_out <= iEX_out;
DM_out <= iDM_out;
end if;
end process;
end behavioral;