--------------------------------------------------------------------------- -- (c) 2020 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; USE IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.STD_LOGIC_MISC.all; LIBRARY work; ENTITY clockgen IS PORT ( CLK : IN STD_LOGIC; RESET_N : IN STD_LOGIC; PAL : IN STD_LOGIC; PHI2 : IN STD_LOGIC; -- enable cycle in clk domain... MHZ1 : OUT STD_LOGIC; -- C64 method, 1% error MHZ2 : OUT STD_LOGIC -- 2x C64 method, 1% error ); END clockgen; -- C64 output --PAL: XL: 2*4.43361875/5, C64: 2*4.43361875/9 -> i.e. C64/XL = 5/9 -> 2x is 10/9 --NTSC: XL: (315/88)/2, C64: 2*(315/88)/7 -> i.e. C64/XL = 4/7 -> 2x i 8/7 ARCHITECTURE vhdl OF clockgen IS signal cycle_count_next : unsigned(3 downto 0); signal cycle_count_reg : unsigned(3 downto 0); signal clk_count_next : unsigned(8 downto 0); signal clk_count_reg : unsigned(8 downto 0); signal err_next : signed(13 downto 0); signal err_reg : signed(13 downto 0); signal state_next : std_logic_vector(1 downto 0); signal state_reg : std_logic_vector(1 downto 0); constant state_sync : std_logic_vector(1 downto 0) := "00"; constant state_count : std_logic_vector(1 downto 0) := "01"; constant state_genbegin : std_logic_vector(1 downto 0) := "10"; constant state_gen : std_logic_vector(1 downto 0) := "11"; signal everyother_next : std_logic; signal everyother_reg : std_logic; BEGIN process(clk,reset_n) begin if (reset_n='0') then cycle_count_reg <= (others=>'0'); clk_count_reg <= (others=>'0'); err_reg <= (others=>'0'); state_reg <= state_sync; everyother_reg <= '0'; elsif (clk'event and clk='1') then cycle_count_reg <= cycle_count_next; clk_count_reg <= clk_count_next; err_reg <= err_next; state_reg <= state_next; everyother_reg <= everyother_next; end if; end process; process(clk_count_reg,cycle_count_reg,pal,phi2,state_reg,err_reg,everyother_reg) variable threshold : unsigned(3 downto 0); variable adj1 : unsigned(17 downto 0); variable adj : signed(13 downto 0); -- 8.6 fixed point variable trig : std_logic; variable cycle_inc : std_logic; variable clk_inc : std_logic; variable thresh_match : std_logic; variable multby : unsigned(8 downto 0); begin cycle_count_next <= cycle_count_reg; clk_count_next <= clk_count_reg; state_next <= state_reg; err_next <= err_reg; everyother_next <= everyother_reg; trig := '0'; cycle_inc := '0'; clk_inc := '0'; mhz1 <= '0'; mhz2 <= '0'; if (pal='1') then multby := to_unsigned(51,9); else multby := to_unsigned(64,9); end if; adj1:= multby * clk_count_reg; adj:= signed(adj1(16 downto 3)) - to_signed(64,14); --threshold: = "0111"; ntsc --threshold: = "1001"; pal threshold(0) := '1'; threshold(1) := not(pal); threshold(2) := not(pal); threshold(3) := pal; thresh_match := '0'; if (cycle_count_reg=threshold) then thresh_match := '1'; end if; err_next(13 downto 0) <= err_reg(13 downto 0) + to_signed(64,14); case state_reg is when state_sync => if (phi2='1') then state_next <= state_count; end if; when state_count => clk_inc := '1'; if (phi2='1') then cycle_inc := '1'; end if; if (thresh_match='1') then state_next <= state_gen; clk_inc := '0'; end if; when state_genbegin => if (phi2='1') then cycle_count_next <= (others=>'0'); state_next <= state_gen; err_next <= -adj; trig := '1'; end if; when state_gen => -- threshold here is other size -1, which happens to match! if (err_reg(13) = '0') then err_next <= err_reg - adj; trig := '1'; cycle_inc := '1'; end if; if (thresh_match='1') then state_next <= state_genbegin; end if; when others=> state_next <= state_sync; end case; if (cycle_inc='1') then cycle_count_next <= cycle_count_reg+1; end if; if (clk_inc='1') then clk_count_next <= clk_count_reg + 1; end if; if (trig='1') then mhz2 <= '1'; everyother_next <= not(everyother_reg); mhz1 <= everyother_reg; end if; end process; --enable_psg_div2 : entity work.syncreset_enable_divider -- generic map (COUNT=>29,RESETCOUNT=>6) -- 28-22 -- port map(clk=>clk,syncreset=>'0',reset_n=>reset_n,enable_in=>'1',enable_out=>mhz2); -- --enable_psg_div1 : entity work.syncreset_enable_divider -- generic map (COUNT=>58,RESETCOUNT=>6) -- 28-22 -- port map(clk=>clk,syncreset=>'0',reset_n=>reset_n,enable_in=>'1',enable_out=>mhz1); end vhdl;