----------------------------------------------------------------------------------
-- Company: University of Connecticut
-- Engineer: Igor Senderovich
-- 
-- Create Date:    19:47:05 08/16/2009 
-- Design Name: 
-- Module Name:    SerialOut - Behavioral 
-- Description:    Shifts out parallel input into a properly-conditioned
--		   RS-232 serial out.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

library FPGA_BasicComp;
use FPGA_BasicComp.BasicComp.all;

entity SerialOut is
    Port ( Clk : in  STD_LOGIC;
           Rst : in  STD_LOGIC;
	   En : in STD_LOGIC;
           D : in  STD_LOGIC_VECTOR (7 downto 0);
           Q : out  STD_LOGIC;
	   Done : out STD_LOGIC;
	   db : out STD_LOGIC);
end SerialOut;

architecture Behavioral of SerialOut is

	signal ClkCnt : STD_LOGIC_VECTOR (4 downto 0);
	signal SerCnt : STD_LOGIC_VECTOR (3 downto 0);
	signal serClk : STD_LOGIC;
	signal reg : STD_LOGIC_VECTOR (7 downto 0);
	signal LastBit : STD_LOGIC;

begin
	
	r1: Reg8bit port map (Clk, Rst, En, D, reg);

	--produce serial clock ~115200 Hz using the 5MHz clock
	Gen_serClk : process (Clk, Rst) begin
		if Rst = '1' then
			ClkCnt <= "00000"; serClk <= '0';
		else
			if rising_edge(Clk) then
				if ClkCnt = "10101" then 
					ClkCnt <= "00000";
					serClk <= not serClk;
				else
					ClkCnt <= ClkCnt + "00001";
				end if;
			else
				ClkCnt <= ClkCnt;
			end if;
		end if;
	end process;


	ShiftClk : process (serClk, Rst, En, SerCnt)
	begin
		if Rst='1' then
			SerCnt <= "0000";
		else
			if En='1' then
				SerCnt <= "1011";
			else
				if rising_edge(serClk) then
					SerCnt <= SerCnt - ("000" & (SerCnt(0) or SerCnt(1) or SerCnt(2) or SerCnt(3)));
				end if;
			
				case SerCnt is 
					when "0000" =>	Q <= '0';	-- idleness
					when "0001" =>	Q <= '0'; 	-- stop bit
					when "0010" =>	Q <= not reg(7); 
					when "0011" =>	Q <= not reg(6);
					when "0100" =>	Q <= not reg(5);
					when "0101" =>	Q <= not reg(4);
					when "0110" =>	Q <= not reg(3);
					when "0111" =>	Q <= not reg(2);
					when "1000" =>	Q <= not reg(1);
					when "1001" =>	Q <= not reg(0);
					when "1010" =>	Q <= '1';
					when others => Q <= '0';
				end case;
			end if;
		end if;
	end process;

	LastBit <= '1' when SerCnt="0001" else '0';
	db <= serClk;
	u1: pulser port map (Clk, LastBit, Done);
	
end Behavioral;


--------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

library FPGA_BasicComp;
use FPGA_BasicComp.BasicComp.all;

entity SerialOutFIFO is
    Port ( Clk : in  STD_LOGIC;
           Rst : in  STD_LOGIC;
	   Go  : in STD_LOGIC;
           D : in  STD_LOGIC_VECTOR (7 downto 0);
           Q : out  STD_LOGIC;
	   --Done : out STD_LOGIC;
	   db : out STD_LOGIC
	 );
end SerialOutFIFO;

architecture Behavioral of SerialOutFIFO is

	component Reg256x8bit_wPrim is
    	   Port ( Clk : in  STD_LOGIC;
           	  Rst : in  STD_LOGIC;
           	  Wr : in  STD_LOGIC;
           	  Addri : in  STD_LOGIC_VECTOR (7 downto 0);
           	  Addro : in  STD_LOGIC_VECTOR (7 downto 0);
           	  D : in  STD_LOGIC_VECTOR (7 downto 0);
           	  Q : out  STD_LOGIC_VECTOR (7 downto 0)
		);
	end component;

	component Reg64x8bit_wPrim is
    	   Port ( Clk : in  STD_LOGIC;
           	  Rst : in  STD_LOGIC;
           	  Wr : in  STD_LOGIC;
           	  Addri : in  STD_LOGIC_VECTOR (5 downto 0);
           	  Addro : in  STD_LOGIC_VECTOR (5 downto 0);
           	  D : in  STD_LOGIC_VECTOR (7 downto 0);
           	  Q : out  STD_LOGIC_VECTOR (7 downto 0)
		);
	end component;

	component Reg16x8bit is
    	   Port ( Clk : in  STD_LOGIC;
           	  Rst : in  STD_LOGIC;
           	  Wr : in  STD_LOGIC;
           	  Addri : in  STD_LOGIC_VECTOR (3 downto 0);
           	  Addro : in  STD_LOGIC_VECTOR (3 downto 0);
           	  D : in  STD_LOGIC_VECTOR (7 downto 0);
           	  Q : out  STD_LOGIC_VECTOR (7 downto 0)
		);
	end component;

	signal reg : STD_LOGIC_VECTOR (7 downto 0);
	signal Ai, Ao, Queue : STD_LOGIC_VECTOR (5 downto 0);
	signal PulseStat : STD_LOGIC_VECTOR (1 downto 0);
	signal QueueEmpty, ser_En, ser_En_Permit, ser_En_delayed : STD_LOGIC;
	signal ser_Done, ser_Done_delayed, Go_delayed : STD_LOGIC;
	constant zero : STD_LOGIC_VECTOR (5 downto 0) := "000000";
	constant one : STD_LOGIC_VECTOR (5 downto 0) := "000001";
begin
	
	r1: Reg64x8bit_wPrim port map (Clk, Rst, Go, Ai, Ao, D, reg);
	--r1: Reg16x8bit port map (Clk, Rst, Go, Ai, Ao, D, reg);
	--reg <= Ao & Ai;
	u0: SerialOut port map (Clk, Rst, ser_En, reg, Q, ser_Done,db);

	u1: c_delay port map (Clk, Go, Go_delayed);
	ser_En_Permit <= Go when QueueEmpty='1' else ser_Done_delayed;
	u2: c_delay port map (Clk, ser_En_Permit, ser_En);
	u3: c_delay port map (Clk, ser_Done, ser_Done_delayed);
	u4: c_delay port map (Clk, ser_En, ser_En_delayed);

	PulseStat <= Go & ser_Done;
	
	OutputPipe: process (Clk, Rst, Go, ser_En) begin
		if Rst='1' then
			Ai <= zero; Ao <= zero;
			Queue <= zero; --QueueEmpty <= '0';
		else
			if falling_edge(Clk) and Go_delayed='1' then
				Ai <= Ai + one;
			end if;
			if falling_edge(Clk) and ser_En_delayed='1' then
				Ao <= Ao + one;
			end if;
			
			if falling_edge(Clk) then
				case PulseStat is  -- i.e. Go & ser_Done
					when "10" => Queue <= Queue + one;
					when "01" => Queue <= Queue - one;
					when others => Queue <= Queue;
				end case;
			end if;
		end if;
	end process;
	QueueEmpty <= '1' when Queue=zero else '0';
							 
end Behavioral;
