|
---------------------------------------------------------------------------
|
|
-- (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;
|
|
|
|
INPUT_CLK : IN STD_LOGIC;
|
|
PLL_CLKS : OUT STD_LOGIC_VECTOR(CLOCKS-1 downto 0);
|
|
|
|
RESET_N_OUT : OUT STD_LOGIC;
|
|
|
|
PLL_RECONFIG_DONE : 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_areset_pal : std_logic;
|
|
signal pll_reconfig_configupdate_pal : std_logic;
|
|
signal pll_reconfig_scanclk_pal : std_logic;
|
|
signal pll_reconfig_scanclkena_pal : std_logic;
|
|
signal pll_reconfig_scandata_pal : std_logic;
|
|
signal pll_reconfig_scandataout_pal : std_logic;
|
|
signal pll_reconfig_scandone_pal : std_logic;
|
|
signal pll_reconfig_busy_pal : std_logic;
|
|
|
|
signal pll_reconfig_areset_ntsc : std_logic;
|
|
signal pll_reconfig_configupdate_ntsc : std_logic;
|
|
signal pll_reconfig_scanclk_ntsc : std_logic;
|
|
signal pll_reconfig_scanclkena_ntsc : std_logic;
|
|
signal pll_reconfig_scandata_ntsc : std_logic;
|
|
signal pll_reconfig_scandataout_ntsc : std_logic;
|
|
signal pll_reconfig_scandone_ntsc : std_logic;
|
|
signal pll_reconfig_busy_ntsc : 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_DISABLE : std_logic_vector(3 downto 0) := "0001";
|
|
constant PLL_STATE_DISABLE_WAIT1 : std_logic_vector(3 downto 0) := "0010";
|
|
constant PLL_STATE_DISABLE_WAIT2 : std_logic_vector(3 downto 0) := "0011";
|
|
constant PLL_STATE_DISABLE_WAIT3 : std_logic_vector(3 downto 0) := "0100";
|
|
constant PLL_STATE_DISABLE_WAIT4 : std_logic_vector(3 downto 0) := "0101";
|
|
constant PLL_STATE_RECONFIG1 : std_logic_vector(3 downto 0) := "0110";
|
|
constant PLL_STATE_RECONFIG1_WAIT_CONFIG : std_logic_vector(3 downto 0) := "0111";
|
|
constant PLL_STATE_RECONFIG1_WAIT_LOCK : std_logic_vector(3 downto 0) := "1000";
|
|
constant PLL_STATE_PAUSE1 : std_logic_vector(3 downto 0) := "1001";
|
|
|
|
signal pll_trigger_reconfig : std_logic;
|
|
signal pll_trigger_reconfig_downstream : 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;
|
|
|
|
signal pll_enable_reg_sync_reg : std_logic;
|
|
|
|
BEGIN
|
|
|
|
generic_pll : entity work.pal_pll
|
|
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
|
|
);
|
|
|
|
process(reconfig_to_pal_reg,
|
|
pll_reconfig_scanclk_pal, pll_reconfig_scanclkena_pal, pll_reconfig_busy_pal, pll_reconfig_areset_pal,pll_reconfig_scandata_pal,pll_reconfig_configupdate_pal,
|
|
pll_reconfig_scanclk_ntsc, pll_reconfig_scanclkena_ntsc, pll_reconfig_busy_ntsc, pll_reconfig_areset_ntsc,pll_reconfig_scandata_ntsc,pll_reconfig_configupdate_ntsc,
|
|
pll_upstream_reset,pll_reconfig_scandone,pll_reconfig_scandataout
|
|
)
|
|
begin
|
|
pll_upstream_reset_pal<= '0';
|
|
pll_upstream_reset_ntsc <= '0';
|
|
pll_reconfig_scandone_pal <= '0';
|
|
pll_reconfig_scandone_ntsc <= '0';
|
|
pll_reconfig_scandataout_pal <= '0';
|
|
pll_reconfig_scandataout_ntsc <= '0';
|
|
|
|
if (reconfig_to_pal_reg='1') then
|
|
pll_reconfig_scanclk<=pll_reconfig_scanclk_pal;
|
|
pll_reconfig_scanclkena<=pll_reconfig_scanclkena_pal;
|
|
pll_reconfig_scandata<= pll_reconfig_scandata_pal;
|
|
pll_reconfig_busy <= pll_reconfig_busy_pal;
|
|
pll_reconfig_areset <= pll_reconfig_areset_pal;
|
|
pll_reconfig_configupdate <= pll_reconfig_configupdate_pal;
|
|
|
|
pll_upstream_reset_pal <= pll_upstream_reset;
|
|
pll_reconfig_scandone_pal <= pll_reconfig_scandone;
|
|
pll_reconfig_scandataout_pal <= pll_reconfig_scandataout;
|
|
else
|
|
pll_reconfig_scanclk<=pll_reconfig_scanclk_ntsc;
|
|
pll_reconfig_scanclkena<=pll_reconfig_scanclkena_ntsc;
|
|
pll_reconfig_scandata<= pll_reconfig_scandata_ntsc;
|
|
pll_reconfig_busy <= pll_reconfig_busy_ntsc;
|
|
pll_reconfig_areset <= pll_reconfig_areset_ntsc;
|
|
pll_reconfig_configupdate <= pll_reconfig_configupdate_ntsc;
|
|
|
|
pll_upstream_reset_ntsc <= pll_upstream_reset;
|
|
pll_reconfig_scandone_ntsc <= pll_reconfig_scandone;
|
|
pll_reconfig_scandataout_ntsc <= pll_reconfig_scandataout;
|
|
end if;
|
|
end process;
|
|
|
|
generic_pll1_reconfig : entity work.video_pll_reconfig
|
|
PORT MAP
|
|
(
|
|
busy => pll_reconfig_busy_ntsc,
|
|
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_ntsc,
|
|
pll_areset_in => pll_upstream_reset_ntsc,
|
|
pll_configupdate => pll_reconfig_configupdate_ntsc,
|
|
pll_scanclk => pll_reconfig_scanclk_ntsc,
|
|
pll_scanclkena => pll_reconfig_scanclkena_ntsc,
|
|
pll_scandata => pll_reconfig_scandata_ntsc,
|
|
pll_scandataout => pll_reconfig_scandataout,
|
|
pll_scandone => pll_reconfig_scandone,
|
|
|
|
reconfig => pll_trigger_reconfig,
|
|
reset => not(RESET_N)
|
|
);
|
|
|
|
generic_pll1_reconfig_pal : entity work.video_pll_reconfig_pal
|
|
PORT MAP
|
|
(
|
|
busy => pll_reconfig_busy_pal,
|
|
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_pal,
|
|
pll_areset_in => pll_upstream_reset_pal,
|
|
pll_configupdate => pll_reconfig_configupdate_pal,
|
|
pll_scanclk => pll_reconfig_scanclk_pal,
|
|
pll_scanclkena => pll_reconfig_scanclkena_pal,
|
|
pll_scandata => pll_reconfig_scandata_pal,
|
|
pll_scandataout => pll_reconfig_scandataout,
|
|
pll_scandone => pll_reconfig_scandone,
|
|
|
|
reconfig => pll_trigger_reconfig,
|
|
reset => not(RESET_N)
|
|
);
|
|
|
|
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';
|
|
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;
|
|
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_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_trigger_reconfig_downstream <= '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';
|
|
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_DISABLE;
|
|
pll_enable_next <= '0';
|
|
end if;
|
|
|
|
|
|
-- Wait for pll_enable_next to make through synchronizer
|
|
when PLL_STATE_DISABLE =>
|
|
pll_state_next <= PLL_STATE_DISABLE_WAIT1;
|
|
|
|
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(24)='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);
|
|
|
|
|
|
pll_reconfig_done <= '1' when pll_enable_reg_sync_reg='0' and pll_enable_reg_sync='1' else '0';
|
|
|
|
process(CLK_RAW)
|
|
begin
|
|
if (CLK_RAW(SYNC_ON)'event and CLK_RAW(SYNC_ON)='1') then
|
|
pll_enable_reg_sync_reg <= pll_enable_reg_sync;
|
|
end if;
|
|
end process;
|
|
|
|
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;
|
|
|