--------------------------------------------------------------------------- -- (c) 2019 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_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; use ieee.std_logic_misc.all; LIBRARY work; ENTITY switch_pal_ntsc IS GENERIC ( CLOCKS : integer :=1; SYNC_ON : integer -- Which clock to send reset_n_out on and pll enable ); PORT ( RECONFIG_CLK : IN STD_LOGIC; -- A clock from another PLL RESET_N : IN STD_LOGIC; PAL : IN STD_LOGIC; SWITCH_ENA : in STD_LOGIC; INPUT_CLK : IN STD_LOGIC; PLL_CLKS : OUT STD_LOGIC_VECTOR(CLOCKS-1 downto 0); RESET_N_OUT : OUT STD_LOGIC ); END switch_pal_ntsc; ARCHITECTURE vhdl OF switch_pal_ntsc IS -- pal/ntsc switches signal pll_reconfig_areset : std_logic; signal pll_reconfig_configupdate : std_logic; signal pll_reconfig_scanclk : std_logic; signal pll_reconfig_scanclkena : std_logic; signal pll_reconfig_scandata : std_logic; signal pll_reconfig_scandataout : std_logic; signal pll_reconfig_scandone : std_logic; signal pll_reconfig_busy : std_logic; signal pll_reconfig_rom_address : std_logic_vector(7 downto 0); signal pll_reconfig_rom_q : std_logic; signal q_reconfig_pal : std_logic_vector(7 downto 0); signal q_reconfig_ntsc : std_logic_vector(7 downto 0); signal pll_reconfig_write_rom_ena : std_logic; signal pll_reconfig_write_from_rom : std_logic; signal pll_reconfig_write_from_rom_next : std_logic; signal pll_pause_counter_reg : std_logic_vector(29 downto 0); signal pll_pause_counter_next : std_logic_vector(29 downto 0); signal pll_enable_reg : std_logic; signal pll_enable_next : std_logic; signal pll_enable_reg_sync : std_logic; signal pll_state_reg : std_logic_vector(3 downto 0); signal pll_state_next : std_logic_vector(3 downto 0); constant PLL_STATE_WAIT : std_logic_vector(3 downto 0) := "0000"; constant PLL_STATE_WAIT_RECONF_ROM : std_logic_vector(3 downto 0) := "0001"; constant PLL_STATE_RECONF_ROM : std_logic_vector(3 downto 0) := "0010"; constant PLL_STATE_DISABLE : std_logic_vector(3 downto 0) := "0011"; constant PLL_STATE_DISABLE_WAIT1 : std_logic_vector(3 downto 0) := "0100"; constant PLL_STATE_DISABLE_WAIT2 : std_logic_vector(3 downto 0) := "0101"; constant PLL_STATE_DISABLE_WAIT3 : std_logic_vector(3 downto 0) := "0110"; constant PLL_STATE_DISABLE_WAIT4 : std_logic_vector(3 downto 0) := "0111"; constant PLL_STATE_RECONFIG1 : std_logic_vector(3 downto 0) := "1000"; constant PLL_STATE_RECONFIG1_WAIT_CONFIG : std_logic_vector(3 downto 0) := "1001"; constant PLL_STATE_RECONFIG1_WAIT_LOCK : std_logic_vector(3 downto 0) := "1010"; constant PLL_STATE_PAUSE1 : std_logic_vector(3 downto 0) := "1011"; signal pll_trigger_reconfig : std_logic; signal pll_upstream_reset : std_logic; signal pll_upstream_reset_pal : std_logic; signal pll_upstream_reset_ntsc : std_logic; signal pll_downstream_reset : std_logic; signal reset_n_next : std_logic; signal reset_n_reg : std_logic; signal reset_n_reg_sync : std_logic; signal CLK_PLL1 : std_logic; signal PLL_LOCKED1 : std_logic; signal PLL_LOCKED : std_logic; signal CLK_RAW : std_logic_vector(5 downto 0); signal pal_fpga_sync : std_logic; signal reconfig_to_pal_reg : std_logic; signal reconfig_to_pal_next : std_logic; BEGIN generic_pll : entity work.pll_pal PORT MAP(inclk0 => INPUT_CLK, c0 => CLK_PLL1, locked => PLL_LOCKED1, areset => pll_reconfig_areset, -- from reconfig configupdate => pll_reconfig_configupdate, scanclk => pll_reconfig_scanclk, scanclkena => pll_reconfig_scanclkena, scandata => pll_reconfig_scandata, -- back to reconfig scandataout => pll_reconfig_scandataout, scandone => pll_reconfig_scandone ); generic_pll2 : entity work.pll_downstream_pal PORT MAP(inclk0 => CLK_PLL1, c0 => CLK_RAW(0), c1 => CLK_RAW(1), c2 => CLK_RAW(2), c3 => CLK_RAW(3), --c4 => CLK_RAW(4), areset => pll_downstream_reset, locked => PLL_LOCKED ); generic_pll1_reconfig : entity work.video_pll_reconfig PORT MAP ( busy => pll_reconfig_busy, clock => RECONFIG_CLK, counter_param => (OTHERS => '0'), counter_type => (OTHERS => '0'), data_in => (OTHERS => '0'), read_param => '0', write_param => '0', --data_out : OUT STD_LOGIC_VECTOR (8 DOWNTO 0); pll_areset => pll_reconfig_areset, pll_areset_in => pll_upstream_reset, pll_configupdate => pll_reconfig_configupdate, pll_scanclk => pll_reconfig_scanclk, pll_scanclkena => pll_reconfig_scanclkena, pll_scandata => pll_reconfig_scandata, pll_scandataout => pll_reconfig_scandataout, pll_scandone => pll_reconfig_scandone, reset_rom_address => '0', rom_address_out => pll_reconfig_rom_address, rom_data_in => pll_reconfig_rom_q, write_from_rom => pll_reconfig_write_from_rom, write_rom_ena => pll_reconfig_write_rom_ena, reconfig => pll_trigger_reconfig, reset => not(RESET_N) ); pll_rom_pal : entity work.pal_rom port map( address => pll_reconfig_rom_address, clock => RECONFIG_CLK, rden => pll_reconfig_write_rom_ena, q => q_reconfig_pal ); pll_rom_ntsc : entity work.ntsc_rom port map( address => pll_reconfig_rom_address, clock => RECONFIG_CLK, rden => pll_reconfig_write_rom_ena, q => q_reconfig_ntsc ); pll_reconfig_rom_q <= q_reconfig_pal(0) when reconfig_to_pal_reg = '1' else q_reconfig_ntsc(0); process(RECONFIG_CLK,RESET_N) begin if (RESET_N='0') then pll_state_reg <= PLL_STATE_WAIT; pll_pause_counter_reg<= (others=>'0'); pll_enable_reg<='0'; pll_reconfig_write_from_rom <= '0'; reset_n_reg <= '0'; reconfig_to_pal_reg <= '1'; elsif (RECONFIG_CLK'event and RECONFIG_CLK='1') then pll_state_reg <= pll_state_next; pll_pause_counter_reg <= pll_pause_counter_next; pll_enable_reg <= pll_enable_next; pll_reconfig_write_from_rom <= pll_reconfig_write_from_rom_next; reset_n_reg <= reset_n_next; reconfig_to_pal_reg <= reconfig_to_pal_next; end if; end process; pal_synchronizer : entity work.synchronizer port map (clk=>RECONFIG_CLK, raw=>pal, sync=>pal_fpga_sync); process (pll_state_reg, pal_fpga_sync, pll_pause_counter_reg,pll_enable_reg, PLL_LOCKED1, PLL_LOCKED, pll_reconfig_busy,reconfig_to_pal_reg) begin pll_reconfig_write_from_rom_next <= '0'; pll_state_next <= pll_state_reg; reset_n_next <= '1'; reconfig_to_pal_next <= reconfig_to_pal_reg; pll_pause_counter_next <= std_logic_vector(unsigned(pll_pause_counter_reg)+1); pll_trigger_reconfig <= '0'; pll_downstream_reset <= '0'; pll_upstream_reset <= '0'; pll_enable_next <= pll_enable_reg; case pll_state_reg is when PLL_STATE_WAIT => pll_enable_next <= '1'; if SWITCH_ENA = '1' then reset_n_next <= PLL_LOCKED; if (not(pal_fpga_sync = reconfig_to_pal_reg) and PLL_LOCKED='1' and PLL_LOCKED1='1') then reconfig_to_pal_next <= pal_fpga_sync; pll_state_next <= PLL_STATE_WAIT_RECONF_ROM; pll_reconfig_write_from_rom_next <= '1'; end if; end if; when PLL_STATE_WAIT_RECONF_ROM => pll_state_next <= PLL_STATE_RECONF_ROM; when PLL_STATE_RECONF_ROM => if (pll_reconfig_busy = '0') then pll_state_next <= PLL_STATE_DISABLE; pll_pause_counter_next <= (others=>'0'); end if; when PLL_STATE_DISABLE => if (pll_pause_counter_reg(16)='1') then pll_enable_next <= '0'; pll_state_next <= PLL_STATE_DISABLE_WAIT1; end if; -- Wait for pll_enable_next to make through synchronizer when PLL_STATE_DISABLE_WAIT1 => pll_state_next <= PLL_STATE_DISABLE_WAIT2; when PLL_STATE_DISABLE_WAIT2 => pll_state_next <= PLL_STATE_DISABLE_WAIT3; when PLL_STATE_DISABLE_WAIT3 => pll_state_next <= PLL_STATE_DISABLE_WAIT4; when PLL_STATE_DISABLE_WAIT4 => pll_state_next <= PLL_STATE_RECONFIG1; -- Set params for upstream pll and reset downstream pll when PLL_STATE_RECONFIG1 => pll_trigger_reconfig <= '1'; pll_downstream_reset <= '1'; pll_state_next <= PLL_STATE_RECONFIG1_WAIT_CONFIG; when PLL_STATE_RECONFIG1_WAIT_CONFIG => --pll_downstream_reset <= '1'; if (pll_reconfig_busy = '0') then pll_state_next <= PLL_STATE_RECONFIG1_WAIT_LOCK; end if; when PLL_STATE_RECONFIG1_WAIT_LOCK => --pll_downstream_reset <= '1'; if (PLL_LOCKED1 = '1') then pll_state_next <= PLL_STATE_PAUSE1; pll_pause_counter_next <= (others=>'0'); --pll_downstream_reset <= '0'; end if; when PLL_STATE_PAUSE1 => if (pll_pause_counter_reg(16)='1') then pll_state_next <= PLL_STATE_WAIT; end if; when others => pll_state_next <= PLL_STATE_WAIT; end case; end process; reset_n_out <= reset_n_reg_sync; reset_synchronizer : entity work.synchronizer port map (clk=>CLK_RAW(SYNC_ON), raw=>reset_n_reg, sync=>reset_n_reg_sync); pll_enable_synchronizer : entity work.synchronizer port map (clk=>CLK_RAW(SYNC_ON), raw=>pll_enable_reg, sync=>pll_enable_reg_sync); GEN_CLKCTRL: for I in 0 to (CLOCKS-1) generate CLKCTRLX : entity work.clkctrl port map ( inclk => CLK_RAW(I), ena => pll_enable_reg_sync, outclk => PLL_CLKS(I) ); end generate GEN_CLKCTRL; end vhdl;