----------------------------------------------------------------------------------
-- マルツ電子株式会社
--
-- 　　　　【MFPGA-BASE】　　FPGAトレーニング用学習ベースボード 
-- 
-- 　　　　　　機能検証用　サンプルコード
--
-- 設計言語	: VHDL言語
-- FPGA名	: 米国ザイリンクス社　XC3S250E-VQ100
-- 設計日	: 2009年2月14日
-- 提供日	: 2009年4月10日
-- バージョン	: 1.0.0
--
----------------------------------------------------------------------------------

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

entity Module_TxBlock is
	generic (
		TxCLK_rate		: integer := (10000000 / 9600)				-- Base clock = 10.000MHz.
																	--		TxSpeed is setted to 9600 bps
	);
	port(
		SysCLK_in		: in	std_logic ;							-- System clock
		SysRST_in		: in	std_logic ;							-- System reset
		
		TxDataWen_i		: in	std_logic ;							-- Transmit data write strobe
		TxData_i		: in	std_logic_vector(7 downto 0) ;		-- Transmit 8bits data

		TxD_o			: out	std_logic ;							-- TxD port
		TxRdy_o			: out	std_logic							-- Transmitter ready flag
	);
end Module_TxBlock ;

architecture Behavioral of Module_TxBlock is

--******** Declare Internal registers ********--
	constant	tPD				: time := 1 ns ;
	signal		BitCount		: std_logic_vector(3 downto 0) ;	-- Maximum 15bit
	signal		TxDataBuf		: std_logic_vector(7 downto 0) ;	-- Data store buffer.
	signal		TxShiftReg		: std_logic_vector(9 downto 0) ;	-- Shift register.( Start bit + Data bits + Stop bit )
	signal		Hld_TxCLK		: std_logic_vector(1 downto 0) ;	-- Clock syncronize
	signal		Hld_TxWrENB		: std_logic_vector(1 downto 0) ;	-- Clock syncronize
	
--******** Declare Status flag ********--
 	signal		TxReady			: std_logic ;						-- Internal TxREADY flag.
 	signal		edge_TxCLK		: std_logic ;						-- Clock edge of TxCLK
 	signal		edge_TxWrENB	: std_logic ;						-- WrENB edge
	signal		TxShiftEnable	: std_logic ;						-- TxD shift enable flag.
	signal		TxShiftProgress	: std_logic ;						-- Shift operation inprogress.
	
	signal		reg_TxD_out		: std_logic ;						-- Internal register.
	signal		reg_TxRdy_o		: std_logic ;						-- Internal register.
	
--******** Declare Clock divider for Tx ********--
component Module_Freq_div is
	port (
	--**** System signals **** --
		SysCLK_in			: in	std_logic ;				-- 10.000MHz oscillator
		SysRST_in			: in	std_logic ;
		
		DIV_rate			: in	std_logic_vector(23 downto 0) ;
		
		SysOSC_out			: out	std_logic
	) ;
end component ;

	signal	Divider_rate	: std_logic_vector(23 downto 0) ;
	signal	TxCLK			:	std_logic ;								-- Tx clock

begin

--*****************************************************************************************--
--**** Timing generator ****--
u_TxCLKgen : Module_Freq_div
	port map (
	--**** System signals **** --
		SysCLK_in	=> SysCLK_in ,				-- 10.000MHz oscillator
		SysRST_in	=> SysRST_in ,
		
		DIV_rate	=> Divider_rate ,
		
		SysOSC_out	=> TxCLK
	) ;
	-- Set divide parameter which is calcurated from baud rate.	
		Divider_rate	<= conv_std_logic_vector( TxCLK_rate , 24 ) ;

--*****************************************************************************************--
--**** UART-Tx function ****--

	edge_TxCLK		<= '1' when ( Hld_TxCLK = "01" )	else '0' after tPD ;	-- get 1 clock width of txSysCLK
	edge_TxWrENB	<= '1' when ( Hld_TxWrENB = "01" )	else '0' after tPD ;	-- get 1 clock width of txSysCLK
	
Data_hold : process ( SysCLK_in, SysRST_in )
begin
	if ( SysRST_in = '1' ) then
		TxDataBuf		<= (others => '0');
		Hld_TxCLK		<= "00";
		Hld_TxWrENB		<= "00";
		TxShiftEnable	<= '0' ;
		reg_TxRdy_o		<= '0' ;
	elsif ( SysCLK_in'event and SysCLK_in = '1' ) then
		Hld_TxCLK		<= Hld_TxCLK(0) & TxCLK;				-- Input synchronize for edge detect.
		Hld_TxWrENB		<= Hld_TxWrENB(0) & TxDataWen_i ;		-- Input synchronize for edge detect.

		reg_TxRdy_o		<= TxReady ;							-- Clock syncronize output of TxREADY. ( 1clock delay )
		
		if ( edge_TxCLK = '1' and BitCount = "0000" ) then
			TxShiftEnable	<= '0' ;
		else
			if ( edge_TxCLK = '0' and edge_TxWrENB = '1' and TxReady = '1' ) then
				TxShiftEnable	<= '1' ;
			end if ;
		end if ;
		
		if ( edge_TxCLK = '0' and edge_TxWrENB = '1' and TxReady = '1' ) then
			TxDataBuf	<= TxData_i ;
		end if ;
	end if ;
end process ;

TxD_Equ : process ( SysCLK_in, SysRST_in )
begin
	if ( SysRST_in = '1' ) then 
		reg_TxD_out		<= '1';
		TxReady			<= '1';
		BitCount		<= "1010" ;
		TxShiftReg		<= ( others => '0' );
		TxShiftProgress	<= '0' ;
	elsif ( SysCLK_in'event and SysCLK_in = '1' ) then
	--**** Transmit preparation phase **** --
		if ( edge_TxCLK = '0' and TxShiftProgress = '0' ) then		-- Stay IDLE state.
			BitCount		<= "1010" ;					-- 10bit
			TxReady			<= '1';						-- Set TxREADY flag.
			TxShiftReg		<= '1' & TxDataBuf & '0' ;	-- Stopbit + Data + StartBit
			reg_TxD_out		<= '1';
		end if ;
	--**** Transmit inprogress phase **** --
		if ( edge_TxCLK = '1' and TxShiftEnable = '1' ) then
			if ( BitCount /= "0000" ) then
				BitCount	<= BitCount - 1 ;
				TxReady		<= '0';						-- Clear TxREADY flag.
				TxShiftReg	<= '1' & TxShiftreg(9 downto 1) ;
				reg_TxD_out	<= TxShiftreg(0) ;			-- Put shift data. LSB first.
			end if ;
		end if;
		
		if ( edge_TxCLK = '1' and TxShiftEnable = '1' ) then
			if ( BitCount = "0000" ) then
				TxShiftProgress <= '0' ;					-- Reset internal flag.
			else
				TxShiftProgress <= '1' ;					-- Set internal flag.
			end if ;
		end if ;
	end if;
end process;

--**** Signal output ****--
	TxD_o	<= reg_TxD_out		after tPD ;
	TxRdy_o	<= reg_TxRdy_o		after tPD ;
	
end Behavioral;

