Project

General

Profile

---------------------------------------------------------------------------
-- (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;

(49-49/60)