---------------------------------------------------------------------------------------------------
-- MODULE_UART_8_bit.VHD
-- (C) 2025 JAPAN LOGIC DESIGN 日本ロジック設計
-- No unauthorized reproduction or AI training allowed.
-- Unauthorized reproduction prohibited.
---------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------
-- Ver : Date		: Description
-- 0.1 : 2025.05.21	: 1st Version
-- 0.2 : 2025.11.09	: 通信開始後、すぐに次の設定ができるよう
--     : 			: パリティ指定を通信スタート時にラッチしておく。送信データは既にラッチ済み。
-- 0.3 : 2026.01.01	: クロック信号を汎用性のある信号名に変更
--     : 			: クロック分周比を、固定からパラメーター指定に変更
--     : 			: 送信開始信号名=>TX_SEND_STARTに変更
--     : 			: bitクロック分周回路を 16bit 化
--     : 			: TX_SEND_START は 1-CLOCK に変更
---------------------------------------------------------------------------------------------------
-- 解説:
--	UART 送受信ロジック。
--	スタートbit:1、データbit:8(LSBファースト)、ストップbit:1、パリティbit:偶数／奇数
--	ボーレート: CLOCK_DIV_VALUEによる
--
--	送信手順
--		送信BUSY(TX_BUSY) でないことを確認する。BUSYなら解除まで待つ。
--		送信レジスタ(TX_DATA_IN)にデータを設定し、
--		送信開始信号(TX_SEND_START) = '1' で送信を開始する。 (1-CLOCK)
--		送信中は、TX_BUSY='1' となる。
--
--	受信手順
--		シリアルデータを受信すると、受信レジスタ(RX_DATA)にデータを格納し、
--		受信終了信号(RX_RECIEVE_END)を 1-CLOCK 分(20MHz)だけ '1' にする。
--		また、受信中は RX_BUSY='1' となる。
---------------------------------------------------------------------------------------------------


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

-- エンティティ宣言 -------------------------------------------------------------------------------

entity MODULE_UART_8_bit is
port (
	-- システム
	nRESET				: in	std_logic;						-- 外部 RESETIN 入力(負論理)
	CLK_IN				: in	std_logic;						-- クロック	20MHz
	-- 分周比
	CLOCK_DIV_VALUE		: in	std_logic_vector(15 downto 0);	-- クロック分周比: (例) 20MHz/100Kbps/2 = 100d
	-- UART信号
	UART_RX				: in	std_logic;
	UART_TX				: out	std_logic;
	-- 送信
	TX_DATA_IN			: in	std_logic_vector(7 downto 0);	-- 送信データ
	TX_PARITY_ODD_EVEN	: in	std_logic;						-- パリティ 0:偶数、1:奇数
	TX_SEND_START		: in	std_logic;						-- 動作開始信号 1-CLOCK
	TX_BUSY				: out	std_logic;						-- 送信処理中は '1'、送信終了後 '0'
	TX_SEND_END			: out	std_logic;						-- 送信終了信号 (1-CLOCK)
	-- 受信
	RX_DATA				: out	std_logic_vector(7 downto 0);	-- 受信データ
	RX_PARITY_ODD_EVEN	: out	std_logic;						-- 受信データから計算したパリティの値 0:偶数、1:奇数
	RX_PARITY_bit		: out	std_logic;						-- 受信したパリティビットの値
	RX_BUSY				: out	std_logic;						-- 受信処理中は '1'、受信終了後 '0'
	RX_RECIEVE_END		: out	std_logic						-- 受信終了信号 (1-CLOCK)
);
end MODULE_UART_8_bit;

architecture rtl of MODULE_UART_8_bit is ----------------------------------------------------------

-- 固定値定義 -------------------------------------------------------------------------------------

-- 信号定義 ---------------------------------------------------------------------------------------
	signal TX_CLK_DIV_C			: std_logic_vector(15 downto 0);
	signal TX_BIT_CLK			: std_logic;
	signal UART_TX_f			: std_logic;
	signal TX_ACTION_STOP		: std_logic;
	signal TX_TIMING_PARITY		: std_logic;
	signal TX_TIMING_SHIFT		: std_logic;
	signal TX_TIMING_SEND		: std_logic;
	signal TX_PARITY_ODD_EVEN_d	: std_logic;

	signal TX_ACTION_F			: std_logic;
	signal TX_BIT_COUNTER		: std_logic_vector(7 downto 0);
	signal TX_DATA_SHIFT		: std_logic_vector(7 downto 0);

	signal TX_PARITY_bit		: std_logic;

	signal UART_RX_d1			: std_logic;
	signal UART_RX_d2			: std_logic;
	signal UART_RX_d3			: std_logic;

	signal RX_BIT_CLK			: std_logic;
	signal RX_ACTION_START		: std_logic;
	signal RX_ACTION_STOP		: std_logic;
	signal RX_TIMING_SHIFT		: std_logic;

	signal RX_DATA_LATCH		: std_logic;
	signal RX_CLK_DIV_C			: std_logic_vector(15 downto 0);
	signal RX_BIT_COUNTER		: std_logic_vector(7 downto 0);
	signal RX_ACTION_F			: std_logic;
	signal RX_DATA_SHIFT_f		: std_logic_vector(7 downto 0);

	signal RX_PARITY_bit_f		: std_logic;
	signal RX_PARITY_bit_f2		: std_logic;
	signal RX_DATA_f			: std_logic_vector(7 downto 0);
	signal RX_DATA_f2			: std_logic_vector(7 downto 0);
	signal RX_PARITY_CALC		: std_logic;
	signal RX_PARITY_ODD_EVEN_f	: std_logic;

-- 使用モジュール宣言 -----------------------------------------------------------------------------

begin ---------------------------------------------------------------------------------------------

-- ロジック本体(RX) -------------------------------------------------------------------------------

	---------------------------------------------
	-- RX 入力データ同期化
	---------------------------------------------
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			if ( nRESET = '0' ) then
				UART_RX_d1	<= '0';
				UART_RX_d2	<= '0';
				UART_RX_d3	<= '0';
			else
				UART_RX_d1	<= UART_RX;
				UART_RX_d2	<= UART_RX_d1;
				UART_RX_d3	<= UART_RX_d2;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX 分周カウンター
	---------------------------------------------
	RX_BIT_CLK	<= '1' when ( RX_CLK_DIV_C(15 downto 0) = CLOCK_DIV_VALUE ) else '0';
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_CLK_DIV_C(15 downto 0)	<= (others => '0');
			elsif ( RX_ACTION_F = '0' ) then
				RX_CLK_DIV_C(15 downto 0)	<= (others => '0');
			-- END
			elsif ( RX_BIT_CLK = '1' )  then
				RX_CLK_DIV_C(15 downto 0)	<= (others => '0');
			-- UP
			else
				RX_CLK_DIV_C(15 downto 0)	<= RX_CLK_DIV_C(15 downto 0) + 1 ;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX ビットカウンター
	---------------------------------------------
	-- 受信タイミングの分解能を上げるため、
	-- 非動作中(スタートbit検出前)は、カウンターをRESETしておく。
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_BIT_COUNTER(7 downto 0)	<= (others => '0');
			elsif ( RX_ACTION_F = '0' ) then
				RX_BIT_COUNTER(7 downto 0)	<= (others => '0');
			-- UP
			elsif ( RX_CLK_DIV_C(15 downto 0) = CLOCK_DIV_VALUE )  then
				RX_BIT_COUNTER(7 downto 0)	<= RX_BIT_COUNTER(7 downto 0) + 1 ;
			-- KEEP
			else
				RX_BIT_COUNTER(7 downto 0)	<= RX_BIT_COUNTER(7 downto 0);
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX UART 動作フラグ
	---------------------------------------------
	RX_ACTION_START	<= '1' when	(	( RX_ACTION_F = '0' )							-- 停止中
								and	( UART_RX_d3 = '1' ) and ( UART_RX_d2 = '0' ))	-- 立下り
							else '0';
	RX_ACTION_STOP	<= '1' when	(	( RX_ACTION_F = '1' )							-- 動作中
								and	( RX_BIT_COUNTER(7 downto 0) = X"14" ))
							else '0';
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_ACTION_F			<= '0';
				RX_RECIEVE_END		<= '0';
			-- 動作開始
			elsif ( RX_ACTION_START = '1' ) then
				RX_ACTION_F		<= '1';			-- ON
				RX_RECIEVE_END	<= '0';			-- 受信フラグ
			-- 動作終了
			elsif ( RX_ACTION_STOP = '1' ) then
				RX_ACTION_F		<= '0';			-- OFF
				RX_RECIEVE_END	<= '1';			-- 受信フラグ:ON
			else
				RX_ACTION_F		<= RX_ACTION_F;	-- KEEP
				RX_RECIEVE_END	<= '0';			-- 受信フラグ
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX データシフト
	---------------------------------------------
	-- ビットタイミング(RX_BIT_COUNTER:偶数)
	RX_TIMING_SHIFT	<= '1' when (( RX_BIT_CLK = '1' ) and ( RX_BIT_COUNTER(0) = '0' )) else '0';
	-- RX データシフト
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_DATA_SHIFT_f(7 downto 0)	<= (others => '0');
			-- 受信(右)シフトタイミング
			elsif ( RX_TIMING_SHIFT = '1' ) then
				-- KEEP
				if ( RX_BIT_COUNTER(7 downto 0) = X"14" ) then
					RX_DATA_SHIFT_f(7 downto 0)	<=RX_DATA_SHIFT_f(7 downto 0);
				-- シフト
				else
					RX_DATA_SHIFT_f(7 downto 0) <= UART_RX_d3 & RX_DATA_SHIFT_f(7 downto 1);
				end if;
			else
				-- KEEP
				RX_DATA_SHIFT_f(7 downto 0) <= RX_DATA_SHIFT_f(7 downto 0);
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX シフトデータラッチ
	---------------------------------------------
	-- ビットタイミング
	RX_DATA_LATCH	<= '1' when (( RX_BIT_CLK = '1' ) and ( RX_BIT_COUNTER(7 downto 0) = X"11" )) else '0';
	-- RX シフトデータラッチ
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_DATA_f(7 downto 0)	<= (others => '0');
			elsif ( RX_DATA_LATCH = '1' ) then
				RX_DATA_f(7 downto 0)	<= RX_DATA_SHIFT_f(7 downto 0);
			end if;
		end if;
	end process;
	-- 受信パリティラッチ
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_PARITY_bit_f		<= '0';
			-- ビットタイミング
			elsif (( RX_TIMING_SHIFT = '1' ) and ( RX_BIT_COUNTER(7 downto 0) = X"12" )) then
				RX_PARITY_bit_f	<= UART_RX_d3;
			-- KEEP
			else
				RX_PARITY_bit_f	<= RX_PARITY_bit_f;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- パリティ計算
	---------------------------------------------
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_PARITY_CALC		<= '0';
			-- ビットタイミング
			elsif ( RX_TIMING_SHIFT = '1' ) then
				-- スタートビットでクリア
				if ( RX_BIT_COUNTER(7 downto 0) = X"00" ) then
					RX_PARITY_CALC	<= '0';
				-- パリティタイミング以降では維持
				elsif ( RX_BIT_COUNTER(7 downto 0) = X"14" ) then
					RX_PARITY_CALC	<= RX_PARITY_CALC;
				elsif ( RX_BIT_COUNTER(7 downto 0) = X"16" ) then
					RX_PARITY_CALC	<= RX_PARITY_CALC;
				-- パリティ計算
				else
					RX_PARITY_CALC	<= RX_PARITY_CALC xor UART_RX_d3;
				end if;
			-- KEEP
			else
				RX_PARITY_CALC	<= RX_PARITY_CALC;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- 受信出力
	---------------------------------------------
	-- RX_ACTION_STOP のタイミングで、一斉ラッチしておく
	process ( CLK_IN ) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_PARITY_ODD_EVEN_f	<= '0';
				RX_PARITY_bit_f2		<= '0';
				RX_DATA_f2(7 downto 0)	<= (others => '0');
			-- ラッチ
			elsif ( RX_ACTION_STOP = '1' ) then
				RX_PARITY_ODD_EVEN_f	<= RX_PARITY_CALC;
				RX_PARITY_bit_f2		<= RX_PARITY_bit_f;
				RX_DATA_f2(7 downto 0)	<= RX_DATA_f(7 downto 0);
			-- KEEP
			else
				RX_PARITY_ODD_EVEN_f	<= RX_PARITY_ODD_EVEN_f;
				RX_PARITY_bit_f2		<= RX_PARITY_bit_f2;
				RX_DATA_f2(7 downto 0)	<= RX_DATA_f2(7 downto 0);
			end if;
		end if;
	end process;

-- ロジック本体(TX) -------------------------------------------------------------------------------

	---------------------------------------------
	-- TX 分周カウンター
	---------------------------------------------
	TX_BIT_CLK	<= '1' when ( TX_CLK_DIV_C(15 downto 0) = CLOCK_DIV_VALUE ) else '0';
	process ( CLK_IN) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_CLK_DIV_C(15 downto 0)	<= (others => '0');
			elsif ( TX_ACTION_F = '0' ) then
				TX_CLK_DIV_C(15 downto 0)	<= (others => '0');
			-- END
			elsif ( TX_BIT_CLK = '1' )  then
				TX_CLK_DIV_C(15 downto 0)	<= (others => '0');
			-- UP
			else
				TX_CLK_DIV_C(15 downto 0)	<= TX_CLK_DIV_C(15 downto 0) + 1 ;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- TX ビットカウンター
	---------------------------------------------
	process ( CLK_IN) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_BIT_COUNTER(7 downto 0)	<= (others => '0');
			elsif ( TX_ACTION_F = '0' ) then
				TX_BIT_COUNTER(7 downto 0)	<= (others => '0');
			-- UP
			elsif ( TX_BIT_CLK = '1' )  then
				TX_BIT_COUNTER(7 downto 0)	<= TX_BIT_COUNTER(7 downto 0) + 1 ;
			-- KEEP
			else
				TX_BIT_COUNTER(7 downto 0)	<= TX_BIT_COUNTER(7 downto 0);
			end if;
		end if;
	end process;

	---------------------------------------------
	-- TX UART 動作フラグ
	---------------------------------------------
	-- TX UART 動作フラグ
	TX_ACTION_STOP	<=	'1' when (( TX_ACTION_F = '1' ) and ( TX_BIT_COUNTER(7 downto 0) = X"18" ))	else '0';
	process ( CLK_IN) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_ACTION_F		<= '0';
				TX_SEND_END		<= '0';
			-- 動作開始
			elsif (( TX_ACTION_F = '0' ) and ( TX_SEND_START = '1' )) then
				TX_ACTION_F		<= '1';
				TX_SEND_END		<= '0';
			-- 動作終了: STOPの次のカウント
			elsif ( TX_ACTION_STOP = '1' ) then
				TX_ACTION_F		<= '0';
				TX_SEND_END		<= '1';			-- 送信済みフラグ 1-CLOCK
			-- KEEP
			else
				TX_ACTION_F		<=	TX_ACTION_F;
				TX_SEND_END		<= '0';
			end if;
		end if;
	end process;

	---------------------------------------------
	-- パリティ計算
	---------------------------------------------
	-- ビットタイミング(TX_BIT_COUNTER:偶数)
	TX_TIMING_PARITY	<= '1' when (( TX_BIT_CLK = '1' ) and ( TX_BIT_COUNTER(0) = '0' ))	else '0';
	-- パリティ計算
	process ( CLK_IN) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_PARITY_bit		<= '0';
			-- ビットタイミング
			elsif ( TX_TIMING_PARITY = '1' ) then
				-- スタートビットでクリア
				if ( TX_BIT_COUNTER(7 downto 0) = X"00" ) then
					TX_PARITY_bit	<= '0';
				-- パリティタイミング以降では維持
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"12" ) then
					TX_PARITY_bit	<= TX_PARITY_bit;
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"14" ) then
					TX_PARITY_bit	<= TX_PARITY_bit;
				-- パリティ計算
				else
					TX_PARITY_bit	<= TX_PARITY_bit xor TX_DATA_SHIFT(0);
				end if;
			--KEEP
			else
				TX_PARITY_bit	<= TX_PARITY_bit;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- TX データシフト
	---------------------------------------------
	-- ビットタイミング(TX_BIT_COUNTER:奇数)
	TX_TIMING_SHIFT	<= '1' when (( TX_BIT_CLK = '1' ) and ( TX_BIT_COUNTER(0) = '1' ))	else '0';
	-- TX データシフト
	process ( CLK_IN) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_DATA_SHIFT(7 downto 0)	<= (others => '0');
			-- 送信データラッチ
			elsif ( TX_SEND_START = '1' ) then
				TX_DATA_SHIFT(7 downto 0)	<= TX_DATA_IN(7 downto 0);
			-- 送信(右)シフトタイミング
			elsif ( TX_TIMING_SHIFT = '1' ) then
				if ( TX_BIT_COUNTER(7 downto 0) = X"01" ) then
					TX_DATA_SHIFT(7 downto 0) <= TX_DATA_SHIFT(7 downto 0);	-- KEEP
				-- シフト
				else
					TX_DATA_SHIFT(7 downto 0) <= '1' & TX_DATA_SHIFT(7 downto 1);
				end if;
			else
				-- KEEP
				TX_DATA_SHIFT(7 downto 0) <= TX_DATA_SHIFT(7 downto 0);		-- KEEP
			end if;
		end if;
	end process;

	---------------------------------------------
	-- パリティ指定、ラッチ
	---------------------------------------------
	-- TX データシフト
	process ( CLK_IN) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_PARITY_ODD_EVEN_d	<= '0';
			-- 送信パリティラッチ
			elsif ( TX_SEND_START = '1' ) then
				TX_PARITY_ODD_EVEN_d	<= TX_PARITY_ODD_EVEN;
			-- KEEP
			else
				TX_PARITY_ODD_EVEN_d	<= TX_PARITY_ODD_EVEN_d;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- 送信データ
	---------------------------------------------
	-- ビットタイミング(TX_BIT_COUNTER:奇数)
	TX_TIMING_SEND	<= '1' when (( TX_BIT_CLK = '1' ) and ( TX_BIT_COUNTER(0) = '1' ))	else '0';
	-- 送信データ
	process ( CLK_IN) begin
		if ( CLK_IN'event and CLK_IN = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				UART_TX_f	<= '1';			-- H
			-- ビットタイミング(TX_BIT_COUNTER:奇数)
			elsif ( TX_TIMING_SEND = '1' ) then
				-- START出力
				if ( TX_BIT_COUNTER(7 downto 0) = X"01" ) then
					UART_TX_f	<= '0';
				-- パリティ出力
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"13" ) then
					UART_TX_f	<= TX_PARITY_bit xor TX_PARITY_ODD_EVEN_d;	-- パリティ偶数/奇数
				-- STOP出力
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"15" ) then
					UART_TX_f	<= '1';
				-- 送信終了後
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"17" ) then
					UART_TX_f	<= '1';
				-- データ送信タイミング
				else
					UART_TX_f	<= TX_DATA_SHIFT(0);
				end if;
			-- KEEP
			else
				UART_TX_f	<= UART_TX_f;
			end if;
		end if;
	end process;

-- 出力 -------------------------------------------------------------------------------------------
	-- 送信
	UART_TX				<= UART_TX_f;
	TX_BUSY				<= TX_ACTION_F;
	-- 受信
	RX_DATA(7 downto 0)	<= RX_DATA_f2(7 downto 0);
	RX_PARITY_bit		<= RX_PARITY_bit_f2;
	RX_PARITY_ODD_EVEN	<= RX_PARITY_ODD_EVEN_f;
	RX_BUSY				<= RX_ACTION_F;

-- END --------------------------------------------------------------------------------------------
-- (C) 2025 JAPAN LOGIC DESIGN 日本ロジック設計
-- No unauthorized reproduction or AI training allowed.
-- Unauthorized reproduction prohibited.
end RTL;

