--
--  Counter Board Counter chip
--
--	***************************************************************
--  Revision history
--
--  Date		Rev	Eng				Description
--  --------	---	--------------	----------------------  
--	12/16/02	1	RY				Initial File
--  12/27/02	2	PMO				changed reset polarity
--  12/31/02	3	RY				OE does  not rely on C(7)
--	12/31/02	4	RY				added testpoint for output enable to pin 48
--	12/31/02	5	RY				commented out everything that was added, should be same as Rev 2
--	1/3/2002	7?	PMO				try to sync APD input, C(0) sync fixed problem
--	3/31/2003	11	RY				qualify reset for two consecutive clock edges
library IEEE;
use IEEE.std_logic_1164.all; 

entity Counter is
	port (	
		SYSCLK:			in STD_LOGIC;
		C:				in STD_LOGIC_VECTOR(7 downto 0);
		DCI:			in STD_LOGIC_VECTOR(2 downto 0);
		COUNT_SIGNAL:	in STD_LOGIC_VECTOR(4 downto 1);
		D:				out STD_LOGIC_VECTOR(15 downto 0);
-- debug
		OUTEN:			out STD_LOGIC;
-- end debug
		DCO:			out STD_LOGIC_VECTOR(3 downto 0)
		);
end Counter;

architecture Counter of Counter is 
--	signal TempCount:	STD_LOGIC_VECTOR(13 downto 0);
--	signal TempCount1:	STD_LOGIC_VECTOR(13 downto 0);
--	signal HighCountA:	STD_LOGIC_VECTOR(13 downto 0);
--	signal LowCountA:	STD_LOGIC_VECTOR(13 downto 0);
--	signal HighCountB:	STD_LOGIC_VECTOR(13 downto 0);
--	signal LowCountB:	STD_LOGIC_VECTOR(13 downto 0);
--	signal HighCountC:	STD_LOGIC_VECTOR(13 downto 0);
--	signal LowCountC:	STD_LOGIC_VECTOR(13 downto 0);
--	signal HighCountD:	STD_LOGIC_VECTOR(13 downto 0);
--	signal LowCountD:	STD_LOGIC_VECTOR(13 downto 0);
	signal TempCount:	STD_LOGIC_VECTOR(14 downto 0);
	signal TempCount1:	STD_LOGIC_VECTOR(14 downto 0);
	signal HighCountA:	STD_LOGIC_VECTOR(14 downto 0);
	signal LowCountA:	STD_LOGIC_VECTOR(14 downto 0);
	signal HighCountB:	STD_LOGIC_VECTOR(14 downto 0);
	signal LowCountB:	STD_LOGIC_VECTOR(14 downto 0);
	signal HighCountC:	STD_LOGIC_VECTOR(14 downto 0);
	signal LowCountC:	STD_LOGIC_VECTOR(14 downto 0);
	signal HighCountD:	STD_LOGIC_VECTOR(14 downto 0);
	signal LowCountD:	STD_LOGIC_VECTOR(14 downto 0);
	signal Pre_Out_En:	STD_LOGIC;
	signal Output_En:	STD_LOGIC;
	signal Phase_Not:	STD_LOGIC;
	signal Reset_Low:	STD_LOGIC;
	signal Reset_High:	STD_LOGIC;
	signal pulse_out1:	STD_LOGIC; --PMO
	signal sync_out1:	STD_LOGIC; --PMO
	signal pulse_out2:	STD_LOGIC; --PMO
	signal sync_out2:	STD_LOGIC; --PMO
	signal pulse_out3:	STD_LOGIC; --PMO
	signal sync_out3:	STD_LOGIC; --PMO
	signal pulse_out4:	STD_LOGIC; --PMO
	signal sync_out4:	STD_LOGIC; --PMO
	signal C0_sync:	STD_LOGIC; --PMO
	signal COUNT_SIG1:	STD_LOGIC; --PMO
	signal COUNT_SIG2:	STD_LOGIC; --PMO
	signal COUNT_SIG3:	STD_LOGIC; --PMO
	signal COUNT_SIG4:	STD_LOGIC; --PMO
	signal c6_sync:	STD_LOGIC; --PMO
	signal c6_buffer:	STD_LOGIC;	-- RY 3/31/03
	signal phase_not_buffer: STD_LOGIC;	-- RY 3/31/03
-- instantiate sync_Counter

component sync_Counter -- is
		port (	
			RESET:		in STD_LOGIC;
			COUNT_EN:	in STD_LOGIC;
			D_IN:	in STD_LOGIC;
			clk:	in STD_LOGIC;
--			COUNT_OUT:	out STD_LOGIC_VECTOR(13 downto 0)
			COUNT_OUT:	out STD_LOGIC_VECTOR(14 downto 0)
			);
	end component; --sync_Counter;

begin

	sync_phase : process  (SYSCLK)
	begin
	if (SYSCLK'event and SYSCLK = '1') then	
		C0_sync <= C(0);
		c6_sync <= C(6);
		c6_buffer <= c6_sync;
	end if;
	end process;

	Phase_Not	<= not(C0_sync);
	phase_not_buffer <= c6_buffer;
	Reset_High	<= c6_sync and Phase_Not and phase_not_buffer;
	Reset_Low	<= c6_sync and C0_sync and c6_buffer;
-- debug code 
DCO(3) <= Reset_High or Reset_Low;
-- debug code
--	Reset_High	<= C(6) and Phase_Not;
--	Reset_Low	<= C(6) and C0_sync; 
	-- create inverted phase, reset


	addr_decode : process 
	begin
			-- if upper address bits match DCI then output data
			if (C(5 downto 3) = DCI(2 downto 0)) then
				-- select which count to output
				case (C(2 downto 1)) is
					when "00" =>
						if C0_sync = '0' then 
							TempCount <= HighCountA;
						else
							TempCount <= LowCountA;
						end if;
					when "01" =>
						if C0_sync = '0' then 
							TempCount <= HighCountB;
						else
							TempCount <= LowCountB;
						end if;
					when "10" =>
						if C0_sync = '0' then 
							TempCount <= HighCountC;
						else
							TempCount <= LowCountC;
						end if;
					when "11" =>
						if C0_sync = '0' then 
							TempCount <= HighCountD;
						else
							TempCount <= LowCountD;
						end if;
					when others =>
				end case;
			end if;
	end process;	


	next_addr : process (DCI)
	begin
		case (DCI(2 downto 0)) is
			-- '000' next address '001'			
			when "000" => DCO(2 downto 0) <= "001";
			-- '001' next address '010'			
			when "001" => DCO(2 downto 0) <= "010";
			-- '010' next address '011'			
			when "010" => DCO(2 downto 0) <= "011";
			-- '011' next address '100'			
			when "011" => DCO(2 downto 0) <= "100";
			-- '100' next address '101'			
			when "100" => DCO(2 downto 0) <= "101";
			when others => DCO(2 downto 0) <= "000";
		end case;
	end process;

	-- First Counter
	counterhighA : sync_Counter
		port map(
			RESET		=> Reset_High,
			COUNT_EN	=> C0_sync, 
			D_IN	=> sync_out1,
			clk 	=> SYSCLK, 
			COUNT_OUT	=> HighCountA
			);
	counterlowA : sync_Counter
		port map(
			RESET		=> Reset_Low,
			COUNT_EN	=> Phase_Not,
			D_IN	=> sync_out1,
			clk 	=> SYSCLK, 
			COUNT_OUT	=> LowCountA
			);
	-- End First Counter

	-- Second Counter
	counterhighB : sync_Counter
		port map(
			RESET		=> Reset_High,
			COUNT_EN	=> C0_sync, 
			D_IN	=> sync_out2, 
			clk 	=> SYSCLK, 	
			COUNT_OUT	=> HighCountB
			);
	counterlowB : sync_Counter
		port map(
			RESET		=> Reset_Low,
			COUNT_EN	=> Phase_Not,
			D_IN	=> sync_out2,
			clk 	=> SYSCLK, 
			COUNT_OUT	=> LowCountB
			);
	-- End Second Counter

	-- Third Counter
	counterhighC : sync_Counter
		port map(
			RESET		=> Reset_High,
			COUNT_EN	=> C0_sync, 
			D_IN	=> sync_out3,
			clk 	=> SYSCLK, 
			COUNT_OUT	=> HighCountC
			);
	counterlowC : sync_Counter
		port map(
			RESET		=> Reset_Low,
			COUNT_EN	=> Phase_Not,
			D_IN	=> sync_out3,
			clk 	=> SYSCLK, 
			COUNT_OUT	=> LowCountC
			);
	-- End Third Counter

	-- Fourth Counter
	counterhighD : sync_Counter
		port map(
			RESET		=> Reset_High,
			COUNT_EN	=> C0_sync,
			D_IN	=> sync_out4,
			clk 	=> SYSCLK, 
			COUNT_OUT	=> HighCountD
			);
	counterlowD : sync_Counter
		port map(
			RESET		=> Reset_Low,
			COUNT_EN	=> Phase_Not,
			D_IN	=> sync_out4,
			clk 	=> SYSCLK, 
			COUNT_OUT	=> LowCountD
			);
	-- End Fourth Counter

-- APD sync
-- invert COUNT_SIGNAL# s 
	COUNT_SIG1 <= not COUNT_SIGNAL(1);
	COUNT_SIG2 <= not COUNT_SIGNAL(2);
	COUNT_SIG3 <= not COUNT_SIGNAL(3);
	COUNT_SIG4 <= not COUNT_SIGNAL(4);

--	pulse_APD1 : process (sysclk,COUNT_SIGNAL(1),sync_out1)
pulse_APD1 : process (sysclk,COUNT_SIG1,sync_out1)
	begin
if (COUNT_SIG1 = '1') then 
--		if (COUNT_SIGNAL(1) = '0') then 
			pulse_out1 <= '1';
		elsif (sync_out1 = '1') then 
			pulse_out1 <= '0';
		elsif (SYSCLK'event and SYSCLK ='1') then
			if (sync_out1 = '1') then
				pulse_out1 <= '0';
			end if;	
		end if;
	end process;
	
	sync1 : process (SYSCLK,pulse_out1)
	begin
		if (SYSCLK'event and SYSCLK ='1') then
			sync_out1 <= pulse_out1; 
		end if;
	end process;	


--	pulse_APD2 : process (SYSCLK,COUNT_SIGNAL(2),sync_out2)
pulse_APD2 : process (SYSCLK,COUNT_SIG2,sync_out2)
begin
if (COUNT_SIG2 = '1') then
--	if (COUNT_SIGNAL(2) = '0') then 
			pulse_out2 <= '1';
		elsif (sync_out2 = '1') then 
			pulse_out2 <= '0';
		elsif (SYSCLK'event and SYSCLK ='1') then
			if (sync_out2 = '1') then
				pulse_out2 <= '0';
			end if;	
		end if;
	end process;
	
	sync2 : process (SYSCLK,pulse_out2)
	begin
		if (SYSCLK'event and SYSCLK ='1') then
			sync_out2 <= pulse_out2; 
		end if;
	end process;


--	pulse_APD3 : process (SYSCLK,COUNT_SIGNAL(3),sync_out3)
pulse_APD3 : process (SYSCLK,COUNT_SIG3,sync_out3)
begin
if (COUNT_SIG3 = '1') then
--	if (COUNT_SIGNAL(3) = '0') then 
			pulse_out3 <= '1';
		elsif (sync_out3 = '1') then 
			pulse_out3 <= '0';
		elsif (SYSCLK'event and SYSCLK ='1') then
			if (sync_out3 = '1') then
				pulse_out3 <= '0';
			end if;	 
		end if;
	end process;
		
	sync3 : process (SYSCLK,pulse_out3)
	begin
		if (SYSCLK'event and SYSCLK ='1') then
			sync_out3 <= pulse_out3; 
		end if;
	end process;	


--	pulse_APD4 : process (SYSCLK,COUNT_SIGNAL(4),sync_out4)
	pulse_APD4 : process (SYSCLK,COUNT_SIG4,sync_out4)
	begin
if (COUNT_SIG4 = '1') then
--	if (COUNT_SIGNAL(4) = '0') then 
			pulse_out4 <= '1';
		elsif (sync_out4 = '1') then 
			pulse_out4 <= '0';
		elsif (SYSCLK'event and SYSCLK ='1') then
			if (sync_out4 = '1') then
				pulse_out4 <= '0';
			end if;	
		end if;
	end process;
	
	sync4 : process (SYSCLK,pulse_out4)
	begin
		if (SYSCLK'event and SYSCLK ='1') then
			sync_out4 <= pulse_out4; 
		end if;
	end process;

	-- Register TempCount to make it fit
	reg_count : process (SYSCLK)
	begin
		if (SYSCLK'event and SYSCLK ='1') then
			TempCount1 <= TempCount;
		end if;
	end process;
	
	-- If C[5:1] matches DCI[2:0] and Output_En = '1' drive outputs
	-- else set outputs to HighZ
--	D(13 downto 0) 	<= TempCount1(13 downto 0) when (DCI(2 downto 0) = C(5 downto 3)) else (others => 'Z');
--	D(15 downto 14) <= "00" when (DCI(2 downto 0) = C(5 downto 3)) else (others => 'Z');
D(14 downto 0) 	<= TempCount1(14 downto 0) when (DCI(2 downto 0) = C(5 downto 3)) else (others => 'Z');
D(15) <= '0' when (DCI(2 downto 0) = C(5 downto 3)) else ('Z');

OUTEN <= sync_out2;
-- debug
--	OUTEN <= '1' when (DCI(2 downto 0) = C(5 downto 3)) else '0';
-- end debug
end Counter;
