---------------------------------------------------------------------------------------------------
-- SIM_MODULE_UART_8_bit.VHD
-- (C) 2025 JAPAN LOGIC DESIGN 日本ロジック設計
---------------------------------------------------------------------------------------------------

-- <<<<<   No unauthorized reproduction or AI training allowed.   >>>>>

---------------------------------------------------------------------------------------------------
-- Ver : Date		: Description
-- 0.1 : 2025.05.21	: 1st Version
-- 0.2 : 2025.11.06	: 信号名変更
---------------------------------------------------------------------------------------------------
-- 解説:
--	UART動作テスト用のシミュレーションモデル
--	中身は [SIM_MODULE_UART_8_bit.VHD] と同じ
---------------------------------------------------------------------------------------------------


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


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

entity SIM_MODULE_UART_8_bit is

Generic (
	CLOCK_DIV_VALUE :	integer := 100-1	-- クロック分周比 : 20MHz/100Kbps/2 = 100d
);
port (
	-- システム
	nRESET					: in	std_logic;						-- 外部 RESETIN 入力(負論理)
	CLK20M					: in	std_logic;						-- クロック	20MHz
	-- 送信
	SIM_TX_DATA_IN			: in	std_logic_vector(7 downto 0);	-- 送信データ
	SIM_TX_DATA_SET			: in	std_logic;						-- 動作開始信号
	SIM_TX_BUSY				: out	std_logic;						-- 送信処理中は '1'、送信終了後 '0'
	SIM_UART_TX				: out	std_logic;
	SIM_TX_PARITY_ODD_EVEN	: in	std_logic;						-- パリティ 0:偶数、1:奇数
	-- 受信
	SIM_UART_RX				: in	std_logic;
	SIM_RX_DATA				: out	std_logic_vector(7 downto 0);	-- 受信データ
	SIM_RX_PARITY_bit		: out	std_logic;						-- 受信したパリティビット
	SIM_RX_PARITY_ODD_EVEN	: out	std_logic;						-- 受信パリティ 0:偶数、1:奇数
	SIM_RX_BUSY				: out	std_logic;						-- 受信処理中は '1'、受信終了後 '0'
	SIM_RX_RECIEVE_END		: out	std_logic						-- 受信終了信号 (1-CLOCK)
);
end SIM_MODULE_UART_8_bit;


architecture rtl of SIM_MODULE_UART_8_bit is ------------------------------------------------------


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


-- 信号定義 ---------------------------------------------------------------------------------------
	signal TX_CLK_DIV_C				: std_logic_vector(7 downto 0);
	signal TX_BIT_CLK				: std_logic;
	signal SIM_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 SIM_TX_DATA_SET_d		: std_logic;
	signal SIM_TX_DATA_SET_UP		: 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 SIM_UART_RX_d1			: std_logic;
	signal SIM_UART_RX_d2			: std_logic;
	signal SIM_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 SIM_RX_DATA_LATCH		: std_logic;
	signal RX_CLK_DIV_C				: std_logic_vector(7 downto 0);
	signal RX_BIT_COUNTER			: std_logic_vector(7 downto 0);
	signal RX_ACTION_F				: std_logic;
	signal SIM_RX_DATA_SHIFT_f		: std_logic_vector(7 downto 0);

	signal SIM_RX_PARITY_bit_f		: std_logic;
	signal SIM_RX_PARITY_bit_f2		: std_logic;
	signal SIM_RX_DATA_f			: std_logic_vector(7 downto 0);
	signal SIM_RX_DATA_f2			: std_logic_vector(7 downto 0);
	signal RX_PARITY_CALC			: std_logic;
	signal SIM_RX_PARITY_ODD_EVEN_f	: std_logic;


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


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


-- ロジック本体 -----------------------------------------------------------------------------------

	---------------------------------------------
	-- TX 分周カウンター
	---------------------------------------------

	TX_BIT_CLK	<= '1' when ( TX_CLK_DIV_C(7 downto 0) = CLOCK_DIV_VALUE ) else '0';

	process ( CLK20M) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_CLK_DIV_C(7 downto 0)	<= (others => '0');
			elsif ( TX_ACTION_F = '0' ) then
				TX_CLK_DIV_C(7 downto 0)	<= (others => '0');
			-- END
			elsif ( TX_BIT_CLK = '1' )  then
				TX_CLK_DIV_C(7 downto 0)	<= (others => '0');
			-- UP
			else
				TX_CLK_DIV_C(7 downto 0)	<= TX_CLK_DIV_C(7 downto 0) + 1 ;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- TX ビットカウンター
	---------------------------------------------
	process ( CLK20M) begin
		if ( CLK20M'event and CLK20M = '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 動作フラグ
	---------------------------------------------
	--
	-- SIM_TX_DATA_SET = '1' で動作開始
	-- 

	-- 立上り検出
	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			if ( nRESET = '0' ) then
				SIM_TX_DATA_SET_d	<= '0';
			else
				SIM_TX_DATA_SET_d	<= SIM_TX_DATA_SET;
 			end if;
		end if;
	end process;

	SIM_TX_DATA_SET_UP	<= '1' when (( SIM_TX_DATA_SET_d = '0' ) and ( SIM_TX_DATA_SET = '1' )) else '0';

	-- TX UART 動作フラグ
	TX_ACTION_STOP	<=	'1' when (( TX_ACTION_F = '1' ) and ( TX_BIT_COUNTER(7 downto 0) = X"18" ))
						else '0';

	process ( CLK20M) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_ACTION_F		<= '0';
			-- 動作開始
			elsif (( TX_ACTION_F = '0' ) and ( SIM_TX_DATA_SET_UP = '1' )) then
				TX_ACTION_F	<= '1';
			-- 動作終了: STOPの次のカウント
			elsif ( TX_ACTION_STOP = '1' ) then
				TX_ACTION_F	<= '0';
			-- KEEP
			else
				TX_ACTION_F	<=	TX_ACTION_F;
			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 ( CLK20M) begin
		if ( CLK20M'event and CLK20M = '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 ( CLK20M) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				TX_DATA_SHIFT(7 downto 0)	<= (others => '0');
			-- 送信データラッチ
			elsif ( SIM_TX_DATA_SET_UP = '1' ) then
				TX_DATA_SHIFT(7 downto 0)	<= SIM_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_BIT_COUNTER:奇数)
	TX_TIMING_SEND	<= '1' when (( TX_BIT_CLK = '1' ) and ( TX_BIT_COUNTER(0) = '1' ))
						else '0';

	-- 送信データ
	process ( CLK20M) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				SIM_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
					SIM_UART_TX_f	<= '0';
				-- パリティ出力
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"13" ) then
					SIM_UART_TX_f	<= TX_PARITY_bit xor SIM_TX_PARITY_ODD_EVEN;	-- パリティ偶数/奇数
				-- STOP出力
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"15" ) then
					SIM_UART_TX_f	<= '1';
				-- 送信終了後
				elsif ( TX_BIT_COUNTER(7 downto 0) = X"17" ) then
					SIM_UART_TX_f	<= '1';
				-- データ送信タイミング
				else
					SIM_UART_TX_f	<= TX_DATA_SHIFT(0);
				end if;
			-- KEEP
			else
				SIM_UART_TX_f	<= SIM_UART_TX_f;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX 入力データ同期化
	---------------------------------------------
	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			if ( nRESET = '0' ) then
				SIM_UART_RX_d1	<= '0';
				SIM_UART_RX_d2	<= '0';
				SIM_UART_RX_d3	<= '0';
			else
				SIM_UART_RX_d1	<= SIM_UART_RX;
				SIM_UART_RX_d2	<= SIM_UART_RX_d1;
				SIM_UART_RX_d3	<= SIM_UART_RX_d2;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX 分周カウンター
	---------------------------------------------

	RX_BIT_CLK	<= '1' when ( RX_CLK_DIV_C(7 downto 0) = CLOCK_DIV_VALUE ) else '0';

	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_CLK_DIV_C(7 downto 0)	<= (others => '0');
			elsif ( RX_ACTION_F = '0' ) then
				RX_CLK_DIV_C(7 downto 0)	<= (others => '0');
			-- END
			elsif ( RX_BIT_CLK = '1' )  then
				RX_CLK_DIV_C(7 downto 0)	<= (others => '0');
			-- UP
			else
				RX_CLK_DIV_C(7 downto 0)	<= RX_CLK_DIV_C(7 downto 0) + 1 ;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX ビットカウンター
	---------------------------------------------
	--
	-- 受信タイミングの分解能を上げるため、
	-- 非動作中(スタートbit検出前)は、カウンターをRESETしておく。
	--
	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '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(7 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	( SIM_UART_RX_d3 = '1' ) and ( SIM_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 ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				RX_ACTION_F			<= '0';
				SIM_RX_RECIEVE_END		<= '0';
			-- 動作開始
			elsif ( RX_ACTION_START = '1' ) then
				RX_ACTION_F		<= '1';				-- ON
				SIM_RX_RECIEVE_END	<= '0';			-- 受信フラグ
			-- 動作終了
			elsif ( RX_ACTION_STOP = '1' ) then
				RX_ACTION_F		<= '0';				-- OFF
				SIM_RX_RECIEVE_END	<= '1';			-- 受信フラグ:ON
			else
				RX_ACTION_F		<= RX_ACTION_F;		-- KEEP
				SIM_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 ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				SIM_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
					SIM_RX_DATA_SHIFT_f(7 downto 0)	<=SIM_RX_DATA_SHIFT_f(7 downto 0);
				-- シフト
				else
					SIM_RX_DATA_SHIFT_f(7 downto 0) <= SIM_UART_RX_d3 & SIM_RX_DATA_SHIFT_f(7 downto 1);
				end if;
			else
				-- KEEP
				SIM_RX_DATA_SHIFT_f(7 downto 0) <= SIM_RX_DATA_SHIFT_f(7 downto 0);
			end if;
		end if;
	end process;

	---------------------------------------------
	-- RX シフトデータラッチ
	---------------------------------------------

	-- ビットタイミング
	SIM_RX_DATA_LATCH	<= '1' when (( RX_BIT_CLK = '1' ) and ( RX_BIT_COUNTER(7 downto 0) = X"11" ))
						else '0';

	-- RX シフトデータラッチ
	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				SIM_RX_DATA_f(7 downto 0)	<= (others => '0');
			elsif ( SIM_RX_DATA_LATCH = '1' ) then
				SIM_RX_DATA_f(7 downto 0)	<= SIM_RX_DATA_SHIFT_f(7 downto 0);
			end if;
		end if;
	end process;

	-- 受信パリティラッチ
	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				SIM_RX_PARITY_bit_f		<= '0';
			-- ビットタイミング
			elsif (( RX_TIMING_SHIFT = '1' ) and ( RX_BIT_COUNTER(7 downto 0) = X"12" )) then
				SIM_RX_PARITY_bit_f	<= SIM_UART_RX_d3;
			-- KEEP
			else
				SIM_RX_PARITY_bit_f	<= SIM_RX_PARITY_bit_f;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- パリティ計算
	---------------------------------------------

	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '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 SIM_UART_RX_d3;
				end if;
			-- KEEP
			else
				RX_PARITY_CALC	<= RX_PARITY_CALC;
			end if;
		end if;
	end process;

	---------------------------------------------
	-- 受信出力
	---------------------------------------------
	--
	-- RX_ACTION_STOP のタイミングで、一斉ラッチしておく
	--

	process ( CLK20M ) begin
		if ( CLK20M'event and CLK20M = '1' ) then	-- '
			-- RESET
			if ( nRESET = '0' ) then
				SIM_RX_PARITY_ODD_EVEN_f	<= '0';
				SIM_RX_PARITY_bit_f2		<= '0';
				SIM_RX_DATA_f2(7 downto 0)	<= (others => '0');
			-- ラッチ
			elsif ( RX_ACTION_STOP = '1' ) then
				SIM_RX_PARITY_ODD_EVEN_f	<= RX_PARITY_CALC;
				SIM_RX_PARITY_bit_f2		<= SIM_RX_PARITY_bit_f;
				SIM_RX_DATA_f2(7 downto 0)	<= SIM_RX_DATA_f(7 downto 0);
			-- KEEP
			else
				SIM_RX_PARITY_ODD_EVEN_f	<= SIM_RX_PARITY_ODD_EVEN_f;
				SIM_RX_PARITY_bit_f2		<= SIM_RX_PARITY_bit_f2;
				SIM_RX_DATA_f2(7 downto 0)	<= SIM_RX_DATA_f2(7 downto 0);
			end if;
		end if;
	end process;


-- 出力 -------------------------------------------------------------------------------------------
	-- 送信
	SIM_UART_TX				<= SIM_UART_TX_f;
	SIM_TX_BUSY				<= TX_ACTION_F;
	-- 受信
	SIM_RX_DATA(7 downto 0)	<= SIM_RX_DATA_f2(7 downto 0);
	SIM_RX_PARITY_bit		<= SIM_RX_PARITY_bit_f2;
	SIM_RX_PARITY_ODD_EVEN	<= SIM_RX_PARITY_ODD_EVEN_f;
	SIM_RX_BUSY				<= RX_ACTION_F;


-- END --------------------------------------------------------------------------------------------
-- Copyright 2025 JAPAN LOGIC DESIGN 日本ロジック設計
end RTL;

