|
---------------------------------------------------------------------------
|
|
-- (c) 2018 mark watson
|
|
-- I am happy for anyone to use this for non-commercial use.
|
|
-- If my vhdl files are used commercially or otherwise sold,
|
|
-- please contact me for explicit permission at scrameta (gmail).
|
|
-- This applies for source and binary form and derived works.
|
|
---------------------------------------------------------------------------
|
|
LIBRARY ieee;
|
|
USE ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
ENTITY phi_mult IS
|
|
PORT
|
|
(
|
|
clkin : IN STD_LOGIC; -- 55 to 116MHz
|
|
phi2 : IN STD_LOGIC; -- about 1.8MHz
|
|
clkout : OUT STD_LOGIC -- about 6x phi2, in sync with phi2!
|
|
);
|
|
END phi_mult;
|
|
|
|
ARCHITECTURE vhdl OF phi_mult IS
|
|
signal measure_next : std_logic_vector(5 downto 0); -- we do not know osc frequency, measure how many cycles in 1 cycle
|
|
signal measure_reg : std_logic_vector(5 downto 0);
|
|
|
|
signal target_next : std_logic_vector(3 downto 0); -- this is 1/6 of the cycle length, flip our output every time
|
|
signal target_reg : std_logic_vector(3 downto 0);
|
|
|
|
signal counter_next : std_logic_vector(3 downto 0);
|
|
signal counter_reg : std_logic_vector(3 downto 0);
|
|
|
|
signal output_next : std_logic;
|
|
signal output_reg : std_logic;
|
|
|
|
signal phi2_next : std_logic;
|
|
signal phi2_reg : std_logic;
|
|
|
|
signal phi2_sync : std_logic;
|
|
|
|
signal flip : std_logic;
|
|
begin
|
|
phi2_next <= phi2_sync;
|
|
process(clkin)
|
|
begin
|
|
if (clkin'event and clkin='1') then
|
|
phi2_reg <= phi2_next;
|
|
measure_reg <= measure_next;
|
|
target_reg <= target_next;
|
|
counter_reg <= counter_next;
|
|
output_reg <= output_next;
|
|
end if;
|
|
end process;
|
|
|
|
sync_clk : entity work.synchronizer
|
|
port map
|
|
(
|
|
CLK => clkin,
|
|
RAW => phi2,
|
|
SYNC => phi2_sync
|
|
);
|
|
|
|
process(phi2_reg, phi2_sync,measure_reg,target_reg,counter_reg)
|
|
variable sum : std_logic_vector(10 downto 0);
|
|
begin
|
|
measure_next <= std_logic_vector(unsigned(measure_reg) + 1);
|
|
target_next <= target_reg;
|
|
counter_next <= std_logic_vector(unsigned(counter_reg) +1);
|
|
flip <= '0';
|
|
|
|
if (phi2_sync = '1' and phi2_reg = '0') then
|
|
measure_next <= "000000";
|
|
|
|
-- *21/128 to get 1/6
|
|
-- 10101 is 20...
|
|
sum := std_logic_vector(unsigned("00000"&measure_reg)+unsigned("000"&measure_reg&"00")+unsigned("0"&measure_reg&"0000"));
|
|
target_next <= sum(10 downto 7);
|
|
counter_next <= "0011";
|
|
end if;
|
|
|
|
if (counter_reg=target_reg) then
|
|
counter_next <= (others=>'0');
|
|
flip <= '1';
|
|
end if;
|
|
end process;
|
|
|
|
process(phi2_reg, phi2_sync, flip, output_reg)
|
|
begin
|
|
output_next <= output_reg;
|
|
|
|
if (phi2_sync = '1' and phi2_reg = '0') then
|
|
output_next <= '1'; -- put in sync (should already be one...)
|
|
end if;
|
|
|
|
if (flip='1') then
|
|
output_next <= not(output_reg); -- next!
|
|
end if;
|
|
end process;
|
|
|
|
CLKOUT <= output_reg;
|
|
|
|
end vhdl;
|
|
|
|
|