----------------------------------------------------------------------------------
-- Company:        www.mlab.cz
-- Based on code written by MIHO.
-- 
-- Design Name:    S3AN01A
-- Project Name:   PulseGen
-- Target Devices: XC3S50AN-4
-- Tool versions:  ISE 13.3
-- Description:    Sample of Pulse Generator at S3AN01A MLAB board.
--
-- Dependencies:   External PS/2 Keyboard has to be connected.
--
-- Version:  $Id: PulseGen.vhd 2534 2012-09-02 13:40:37Z kakl $
--
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use WORK.PS2_pkg.ALL;

library UNISIM;
use UNISIM.vcomponents.all;

entity PulseGen is
	generic (
		--	Top Value for 100MHz Clock Counter
		MAXCOUNT:	integer	:=	30_000_000;
		MUXCOUNT:	integer	:=	100_000				--	LED Display Multiplex Clock Divider
	);
	port (
		-- Main Clock
		CLK100MHz:	in		std_logic;

		-- Mode Signals (usualy not used)
		M:				in		std_logic_vector(2 downto 0);
		VS:			in		std_logic_vector(2 downto 0);

		-- Dipswitch Inputs
		DIPSW:		in		std_logic_vector(7 downto 0);

		-- Push Buttons
		PB:			in		std_logic_vector(3 downto 0);

		-- LED Bar Outputs
		LED:			out	std_logic_vector(7 downto 0);

		--	LED Display (8 digit with 7 segments and ddecimal point)
		LD_A_n:		out	std_logic;
		LD_B_n:		out	std_logic;
		LD_C_n:		out	std_logic;
		LD_D_n:		out	std_logic;
		LD_E_n:		out	std_logic;
		LD_F_n:		out	std_logic;
		LD_G_n:		out	std_logic;
		LD_DP_n:		out	std_logic;
		LD_0_n:		out	std_logic;
		LD_1_n:		out	std_logic;
		LD_2_n:		out	std_logic;
		LD_3_n:		out	std_logic;
		LD_4_n:		out	std_logic;
		LD_5_n:		out	std_logic;
		LD_6_n:		out	std_logic;
		LD_7_n:		out	std_logic;

		--	VGA Video Out Port
		VGA_R:		out	std_logic_vector(1 downto 0);
		VGA_G:		out	std_logic_vector(1 downto 0);
		VGA_B:		out	std_logic_vector(1 downto 0);
		VGA_VS:		out	std_logic;
		VGA_HS:		out	std_logic;

		-- Bank 1 Pins - Inputs for this Test
		B:				inout		std_logic_vector(24 downto 0);
		
		-- PS/2 Bidirectional Port (open collector, J31 and J32)
--		PS2_CLK1:	inout	std_logic;
--		PS2_DATA1:	inout	std_logic;
		PS2_CLK2:	inout	std_logic;
		PS2_DATA2:	inout	std_logic;

		--	Diferencial Signals on 4 pin header (J7)
		DIF1P:		inout	std_logic;
		DIF1N:		inout	std_logic;
		DIF2P:		inout	std_logic;
		DIF2N:		inout	std_logic;
		

		--	I2C Signals (on connector J30)
		I2C_SCL:		inout	std_logic;
		I2C_SDA:		inout	std_logic;

		--	Diferencial Signals on SATA like connectors (not SATA capable, J28 and J29)
		SD1AP:		inout	std_logic;
		SD1AN:		inout	std_logic;
		SD1BP:		inout	std_logic;
		SD1BN:		inout	std_logic;
		SD2AP:		inout	std_logic;
		SD2AN:		inout	std_logic;
		SD2BP:		inout	std_logic;
		SD2BN:		inout	std_logic;

		--	Analog In Out
	   ANA_OUTD:	out	std_logic;
		ANA_REFD:	out	std_logic;
		ANA_IND:		in		std_logic;

		--	SPI Memory Interface
		SPI_CS_n:	inout	std_logic;
		SPI_DO:		inout	std_logic;
		SPI_DI:		inout	std_logic;
		SPI_CLK:		inout	std_logic;
		SPI_WP_n:	inout	std_logic
	);
end entity PulseGen;


architecture PulseGen_a of PulseGen is

function to_bcd ( bin : std_logic_vector(7 downto 0) ) return std_logic_vector is
variable i : integer:=0;
variable mybcd : std_logic_vector(11 downto 0) := (others => '0');
variable bint : std_logic_vector(7 downto 0) := bin;
begin
	for i in 0 to 7 loop  -- repeating 8 times.
		mybcd(11 downto 1) := mybcd(10 downto 0);  --shifting the bits.
		mybcd(0) := bint(7);
		bint(7 downto 1) := bint(6 downto 0);
		bint(0) :='0';


		if(i < 7 and mybcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
		mybcd(3 downto 0) := std_logic_vector(unsigned(mybcd(3 downto 0)) + 3);
		end if;

		if(i < 7 and mybcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
		mybcd(7 downto 4) := std_logic_vector(unsigned(mybcd(7 downto 4)) + 3);
		end if;

		if(i < 7 and mybcd(11 downto 8) > "0100") then  --add 3 if BCD digit is greater than 4.
		mybcd(11 downto 8) := std_logic_vector(unsigned(mybcd(11 downto 8)) + 3);
		end if;
	end loop;
	
	return mybcd;
end to_bcd;


-- O1: ____|^^^^^^^|______
-- O2: _________|^^|______
--           t1  t2    
-- t1/t2 is from 0 to 2000 ns; repeating frequency is cca 1,6 kHz

	signal T1: 		unsigned(15 downto 0)	:=	X"000a"; -- Time t1 to Impuls at O2
	signal T2: 		unsigned(15 downto 0)	:=	X"0001"; -- Duration t2 of impuls at O2
	signal CT0:		unsigned(15 downto 0) := X"0000";	-- Timer
	signal O1:	std_logic := '0';	-- Output 1
	signal O2:	std_logic := '0'; -- Output 2
	signal CTburst:		unsigned(15 downto 0) := X"0000";	-- Pulse counter
	
	-- LED Demo Signals
	--	----------------

	signal Counter:		unsigned(31 downto 0)	:= X"00000000";	--	Main Counter (binary)
	signal Bar:				unsigned(7 downto 0)		:=	X"00";			--	Counter for Bar output (binary)

	signal FastBlink:		std_logic;											--	Signal mask for half intensity LED output (several kHz)

	--	LED Display
	--	-----------

	signal Number:			std_logic_vector(32 downto 0);				--	LED Display Input
	signal MuxCounter:	unsigned(31 downto 0)	:=	(others => '0');	--	LED Multiplex - Multiplex Clock Divider
	signal Enable:			std_logic;
	signal Digits:			std_logic_vector(7 downto 0)	:=	X"01";	--	LED Multiplex - Digit Counter - LED Digit Output
	signal Segments:		std_logic_vector(0 to 7);						--	LED Segment Output
	signal Code:			std_logic_vector(3 downto 0);					--	BCD to 7 Segment Decoder Output

	--	PS/2 Port
	-- ---------

	--	Interface Signals
	signal PS2_Code:		std_logic_vector(7 downto 0);					--	Key Scan Code
	signal PS2_Attribs:	std_logic_vector(7 downto 0);					--	State of Shifts for Scan Code
	signal PS2_Valid:		boolean;												--	Valid Data (synchronous with Main Clock)
	signal PS2_Shifts:	std_logic_vector(9 downto 0);					--	Immediate (life) State of Shifts for Scan Code

	--	Result
	signal PS2_Result:	std_logic_vector(15 downto 0);				--	Result (memory)

--	signal Key:				std_logic_vector(7 downto 0);					-- Cislo na klavese
	
	-- VGA Demo Signals
	--	----------------

	signal CLK:				std_logic;											--	Main Clock - global distribution network
	signal CLKVGAi:		std_logic;											--	DCM Clock Out (40MHz Pixel Clock) - internal connection from DCM to BUFG
	signal CLKVGA:			std_logic;											--	DCM Clock Out (40MHz Pixel Clock) - global distribution network
	signal VGA_Blank:		boolean;												--	Blank
	signal VGA_Hsync:		boolean;												--	Horisontal Synchronisation
	signal VGA_Vsync:		boolean;												--	Vertical Synchronisation

	signal VCounter:		unsigned(9 downto 0)		:=	"0000000000";	--	Vertical Counter
	signal HCounter:		unsigned(10 downto 0)	:=	"00000000000";	--	Horisontal Counter

	signal PinState:		std_logic;											-- For IB1 Port Test
	signal Red:				std_logic_vector(1 downto 0);
	signal Green:			std_logic_vector(1 downto 0);
	signal Blue:			std_logic_vector(1 downto 0);

	--	ADDA
	signal ADDA_DataIn:	std_logic_vector(7 downto 0);

begin

	--	Basic LED Blinking Test
	--	=======================

	-- LED Bar Counter
	process (CLK100MHz)
	begin
		if rising_edge(CLK100MHz) then
			if Counter < MAXCOUNT-1 then
				Counter <= Counter + 1;
			else
				Counter <= (others => '0');
				Bar <= Bar + 1;
			end if;
		end if;
	end process;

   LED <= std_logic_vector(Bar); --	LED Bar Connected to Counter

	FastBlink <= Counter(13) and Counter(14) and Counter(15) and Counter(16);	--	1/16 intensity

	--	LED Display (multiplexed)
	--	=========================

	--	Connect LED Display Output Ports (negative outputs)
	LD_A_n	<=	not (Segments(0) and Enable);
	LD_B_n	<=	not (Segments(1) and Enable);
	LD_C_n	<=	not (Segments(2) and Enable);
	LD_D_n	<=	not (Segments(3) and Enable);
	LD_E_n	<=	not (Segments(4) and Enable);
	LD_F_n	<=	not (Segments(5) and Enable);
	LD_G_n	<=	not (Segments(6) and Enable);
	LD_DP_n	<=	not (Segments(7) and Enable);

	LD_0_n	<=	not Digits(0);
	LD_1_n	<=	not Digits(1);
	LD_2_n	<=	not Digits(2);
	LD_3_n	<=	not Digits(3);
	LD_4_n	<=	not Digits(4);
	LD_5_n	<=	not Digits(5);
	LD_6_n	<=	not Digits(6);
	LD_7_n	<=	not Digits(7);

	--	Time Multiplex
	process (CLK100MHz)
	begin
		if rising_edge(CLK100MHz) then
			if MuxCounter < MUXCOUNT-1 then
				MuxCounter <= MuxCounter + 1;
			else
				MuxCounter <= (others => '0');
				Digits(7 downto 0) <= Digits(6 downto 0) & Digits(7);	--	Rotate Left
				Enable <= '0';
			end if;
			if MuxCounter > (MUXCOUNT-4) then
				Enable <= '1';
			end if;
		end if;
	end process;

	--	BCD to 7 Segmet Decoder
	--	 --     A
	--	|  |  F   B
	--	 --     G
	--	|  |  E   C
	--	 --     D   H
	--              ABCDEFGH
	Segments		<=	"11111100"	when	Code="0000"	else	--	Digit 0
						"01100000"	when	Code="0001"	else	--	Digit 1
						"11011010"	when	Code="0010"	else	--	Digit 2
						"11110010"	when	Code="0011"	else	--	Digit 3
						"01100110"	when	Code="0100"	else	--	Digit 4
						"10110110"	when	Code="0101"	else	--	Digit 5
						"10111110"	when	Code="0110"	else	--	Digit 6
						"11100000"	when	Code="0111"	else	--	Digit 7
						"11111110"	when	Code="1000"	else	--	Digit 8
						"11110110"	when	Code="1001"	else	--	Digit 9
						"11101110"	when	Code="1010"	else	--	Digit A
						"00111110"	when	Code="1011"	else	--	Digit b
						"10011100"	when	Code="1100"	else	--	Digit C
						"01111010"	when	Code="1101"	else	--	Digit d
						"10011110"	when	Code="1110"	else	--	Digit E
						"10001110"	when	Code="1111"	else	--	Digit F
						"00000000";

	Code 			<=	Number( 3 downto  0)	when	Digits="00000001"	else
						Number( 7 downto  4)	when	Digits="00000010"	else
						Number(11 downto  8)	when	Digits="00000100"	else
						Number(15 downto 12)	when	Digits="00001000"	else
						Number(19 downto 16)	when	Digits="00010000"	else
						Number(23 downto 20)	when	Digits="00100000"	else
						Number(27 downto 24)	when	Digits="01000000"	else
						Number(31 downto 28)	when	Digits="10000000"	else
						"0000";

--	Key		<=	"00000000"	when	PS2_Result(7 downto 0)=X"70"	else	--	Digit 0
--				   "00000001"	when	PS2_Result(7 downto 0)=X"69"	else	--	Digit 1
--				   "00000010"	when	PS2_Result(7 downto 0)=X"72"	else	--	Digit 2
--					"11111111";
						
--  Number(31 downto 28) <= Key(3 downto 0);

--	Number( 7 downto  0) <=	std_logic_vector(BAR);
--	Number(31 downto 24)	<=	DIPSW;

	--	PS/2 Port
	--	=========

	--	Instantiate PS/2 Keyboard Interface Handler
	PS2_Keyboard: PS2 generic map(
		CLKFREQ		=>	100_000_000
	)
	port map(
		-- Main Clock
		Clk			=>	CLK100MHz,

		-- PS/2 Port
		PS2_Clk		=>	PS2_CLK2,
		PS2_Data		=>	PS2_DATA2,

		-- Result - valid when PS2_Valid
		PS2_Code		=>	PS2_Code,
		PS2_Attribs	=>	PS2_Attribs,
		PS2_Valid	=>	PS2_Valid,

		--	Immediate State of Shifts
		PS2_Shifts	=>	PS2_Shifts
	);	--	PS2

	process (CLK100MHz)
	begin
		if rising_edge(CLK100MHz) then
			if PS2_Valid and PS2_Attribs(7)='0' then
				--	Valid Scan Code with no Break Attribute
				PS2_Result( 7 downto 0)	<=	PS2_Code;
				PS2_Result(15 downto 8)	<=	PS2_Attribs;
			end if;
			
			if PS2_Valid and PS2_Attribs(7)='0' then
			   if PS2_Code = X"74" and T1<2000 then T1<=T1+1; end if;
			   if PS2_Code = X"6b" and T1>0 then T1<=T1-1; end if;
			   if PS2_Code = X"75" and T2<200 then T2<=T2+1; end if;
			   if PS2_Code = X"72" and T2>0 then T2<=T2-1; end if;
				CT0<=X"0000";
				O1<='0';
				O2<='0';
				CTburst<=X"0000";
			end if;

			if PB(0)='1' then
				T1<=X"0000";
				T2<=X"0000";
			end if;
	
			if DIPSW(0)='1' then
				if CT0>X"F000" then
					CT0<=X"0000";
				else
					CT0<=CT0+1;
				end if;
			else
				if CT0>X"0200" then
					CT0<=X"0000";
				else
					CT0<=CT0+1;
				end if;			
			end if;
			
			if CTburst>2000 then
				CTburst<=X"0000";
			end if;

			if (CTburst<1000) or (DIPSW(1)='0') then
				if CT0=X"0000" then
					O1<='1';
				end if;
				
				if CT0=T1+X"0000" then
					O2<='1';
				end if;
			end if;
			
			if CT0=T2+T1+X"0000" then
				O1<='0';
				O2<='0';
				CTburst<=CTburst+1;
			end if;
			
		end if;
		
	end process;

	--	Display Result on LED
	Number(3  downto 0)  <= (others=>'0');
	Number(15 downto 4)  <= to_bcd(std_logic_vector(T2));
	Number(19 downto 16) <=	(others=>'0');
	Number(31 downto 20) <=	to_bcd(std_logic_vector(T1));
	

	--	Test Diferencial In/Outs
	-- ========================

	--	Output Signal on SATA Connector
	SD1AP			<=	Bar(0);
	SD1AN			<=	Bar(1);
	SD1BP			<=	Bar(2);
	SD1BN			<=	Bar(3);

	--	Input Here via SATA Cable
	SD2AP			<=	'Z';
	SD2AN			<=	'Z';
	SD2BP			<=	'Z';
	SD2BN			<=	'Z';

	--	Copy SATA Connector Input to 4 pin header (J7) - Connect these signals to B port input to visualize them
	-- !!!!!!!!!!!! Pulse Generator Outputs !!!!!!!!!!!!!!!!!!!!!
	DIF1P			<=	O1; 
	B(0)			<= O1;
	DIF1N			<=	not O1; 
	B(1)			<=	not O1;
	DIF2P			<=	O2;
	B(2)			<= O2;
	DIF2N			<=	not O2;
	B(3)			<=	not O2;
	
	VGA_R(0)		<=	O1; 
	VGA_R(1)		<=	O2; 

	--	Unused Signals
	--	==============

	--	I2C Signals (on connector J30)
	I2C_SCL		<=	'Z';
	I2C_SDA		<=	'Z';

	--	SPI Memory Interface
	SPI_CS_n		<=	'Z';
	SPI_DO		<=	'Z';
	SPI_DI		<=	'Z';
	SPI_CLK		<=	'Z';
	SPI_WP_n		<=	'Z';

   ANA_OUTD	<= 'Z';
	ANA_REFD <= 'Z';

	VGA_R	<= "ZZ";
	VGA_G	<= "ZZ";
	VGA_B	<= "ZZ";
	VGA_VS	<= 'Z';
	VGA_HS	<= 'Z';

end architecture PulseGen_a;
