#ifndef __HAL_UART_H__
#define __HAL_UART_H__
/*****************************************************************************
filename : hal_uart.h
模擬UART(C-Machine)モジュール

 (C) Copyright 2002-2023 佐々木芳


Windowsのシミュレーション環境上で動作するアプリケーションプログラムのコンパイル時には以下のマクロ定義が必要
	_CMTOY

以下の順番にインクルードする。
#include "hal.h"
#include "hal_uart.h"
#include "itron.h"
*****************************************************************************/


/*UART タイプ*/
typedef enum{
	UART_UNDEF		= -1,
	UART_DEFAULT	= 0,		//簡易シリアル,割り込みなし
	UART_TERM		= 1,		//TCP/IPコンソール端末
	UART_16550		= 16550,	//16550
}UART_TYPE;

/*16550 割り込み許可レジスタ (IER R/W) */
enum tagIER{
	IE16_RECV_READY		= 0x01,		/*受信データレディ割り込み設定*/
	IE16_SEND_EMPTY		= 0x02,		/*送信レジスタ空割り込み設定*/
	IE16_LINE_CHANGED	= 0x04,		/*ラインステータス割り込み設定*/
	IE16_MODEM_CHANGED	= 0x08,		/*モデムステータス割り込み設定*/
};
/*16550 割り込み認識レジスタ (IIR R)*/
enum tagIIR{
	II16_INT_NONE			= 0x01,	/*１で割込み要求なし、０で割込み要求あり*/
	II16_IID				= 0x0e,	/*割込み要因*/
	II16_IID_LINE			= 0x06,	/*優先度1 ライン状態*/
	II16_IID_RECV_READY		= 0x04,	/*優先度2 受信データあり*/
	II16_IID_TIMEOUT		= 0x0c,	/*優先度2 受信タイムアウト(FIFO mode only)*/
	II16_IID_SEND_EMPTY		= 0x02,	/*優先度3 送信FIFOが空*/
	II16_IID_MODEM			= 0x00,	/*優先度4 モデム状態*/
};
/*16550 FIFO制御レジスタ (FCR W) */
enum tagFCR{
	FC16_FIFO_ENABLE		= 0x01,		/*1でFIFOを使用*/
	FC16_RCVR_RESET			= 0x02,		/*受信FIFOリセット*/
	FC16_XMIT_RESET			= 0x04,		/*送信FIFOリセット*/
	FC16_RECV_TRIGGER		= 0xc0,		/*受信FIFO内の割り込みがかかる受信バイト数*/
	FC16_RECV_TRIGGER_1		= 0x00,
	FC16_RECV_TRIGGER_4		= 0x40,
	FC16_RECV_TRIGGER_8		= 0x80,
	FC16_RECV_TRIGGER_14	= 0xc0,
};
/*16550 ライン制御レジスタ (LCR R/W) */
enum tagLCR{
	LC16_WORD_LENGTH1	= 0x01,
	LC16_WORD_LENGTH2	= 0x02,
	LC16_STOP_BITS		= 0x04,
	LC16_PARITY_ENABLE	= 0x08,
	LC16_EVEN_PARITY	= 0x10,
	LC16_STICK_PARITY	= 0x20,
	LC16_SEND_BREAK		= 0x40,		/**/
	LC16_DLAB			= 0x80,		/**/
};
/*16550 モデム制御レジスタ (MCR R/W) */
enum tagMCR{
	MC16_DTR			= 0x01,		/*出力：ER信号*/
	MC16_RTS			= 0x02,		/*出力：RS信号*/
	MC16_OUT1			= 0x04,		/*出力：例：モデムリセット(DOS/V機）、	CI*/
	MC16_OUT2			= 0x08,		/*出力：例：割り込み許可(DOS/V機）、	CD*/
	MC16_LOOP			= 0x10,		/*ループバック*/
	MC16_AFE			= 0x20,		/*Autoflow Control Enable（TL16C550）*/
};
/*16550 ラインステータスレジスタ (LSR R) */
/*bit1-bit4はエラー状態ビット*/
enum tagLSR{
	LS16_RECV_READY		= 0x01,		/*受信データレディ（受信バッファまたは受信FIFOにデータあり） */
	LS16_BUFFER_OVERRUN	= 0x02,		/*オーバーランエラー発生 */
	LS16_PARITY_ERROR	= 0x04,		/*パリティエラー発生*/
	LS16_FRAMING_ERROR	= 0x08,		/*フレーミングエラー発生 */
	LS16_BREAK_SIGNAL	= 0x10,		/*break信号検出（break表示） */
	LS16_SEND_READY		= 0x20,		/*送信バッファまたは送信FIFOは空*/
	LS16_SEND_EMPTY		= 0x40,		/*送信バッファまたは送信FIFOとシフトレジスタは空 */
	LS16_FIFO_ERROR		= 0x80,		/*受信FIFO内にパリティエラー、フレーミングエラー、break表示があることを示す*/
	LS16_LINE_ERROR		= (LS16_BUFFER_OVERRUN | LS16_PARITY_ERROR | LS16_FRAMING_ERROR | LS16_BREAK_SIGNAL),
	LS16_RESET			= (LS16_SEND_READY | LS16_SEND_EMPTY)
};
/*16550 モデムステータスレジスタ (MSR R/W) */
enum tagMSR{
	MS16_CTS_CHANGED	= 0x01,		/*CTS入力が変化*/
	MS16_DSR_CHANGED	= 0x02,		/*DSR入力が変化*/
	MS16_RI_CHANGED		= 0x04,		/*RI入力が変化*/
	MS16_DCD_CHANGED	= 0x08,		/*DCD入力が変化*/
	MS16_CTS_ON			= 0x10,		/*CTSの入力レベル*/
	MS16_DSR_ON			= 0x20,		/*DSRの入力レベル*/
	MS16_RI_ON			= 0x40,		/*RIの入力レベル*/
	MS16_DCD_ON			= 0x80,		/*DCDの入力レベル*/
};

/*16550 Scratch Register (SCR R/W) */

/***************************************************************************************/

/*16550をモデムに使用した場合
モデム信号制御レジスタのOUT1,OUT2を以下のように使うと仮定。
	OUT1	＝	CI	モデムが呼び出し信号を受信しているかどうかをDTEに示す
	OUT2	＝	CD	モデムがキャリア（信号）を受信中であるかどうかをDTEに示す
DTEのDTRが16550のDSRにつながっていると仮定（DSRでDTEの電源ON/OFFを検出する）
	DTEの電源がONするとDTR ON、電源OFFでDTR OFFとなる。
*/

#ifdef _CMTOY
/*Windowsシミュレーション環境*/

/*レジスタ操作マクロ*/
#define IE16550(c)			hal16550ReadIER((c))
#define IID16550(c)			hal16550ReadIID((c))
#define LSTAT16550(c)		hal16550ReadLSR((c))
#define MSTAT16550(c)		hal16550ReadMSR((c))
#define READ16550(c)		hal16550ReadDATA((c))
#define WRITE16550(c,d)		hal16550WriteDATA((c),(d))
#define WRITE_LCR(c,d)		hal16550WriteLCR((c),(d))
#define WRITE_IER(c,d)		hal16550WriteIER((c),(d))
#define WRITE_MCR(c,d)		hal16550WriteMCR((c),(d))
#define WRITE_FCR(c,d)		hal16550WriteFCR((c),(d))
/*モデム信号制御*/
#define SET_DTR16550(c)		hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))|MC16_DTR))
#define CLEAR_DTR16550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))&(~MC16_DTR)))
#define SET_RTS16550(c)		hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))|MC16_RTS))
#define CLEAR_RTS16550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))&(~MC16_RTS)))
#define SET_OUT116550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))|MC16_OUT1))
#define CLEAR_OUT116550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))&(~MC16_OUT1)))
#define SET_OUT216550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))|MC16_OUT2))
#define CLEAR_OUT216550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))&(~MC16_OUT2)))
#define SET_LOOPBACK16550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))|MC16_LOOP))
#define CLEAR_LOOPBACK16550(c)	hal16550WriteMCR((c),(BYTE)(hal16550ReadMCR((c))&(~MC16_LOOP)))
/*割込み制御*/
#define ENA_RX16550(c)		hal16550WriteIER((c),(BYTE)(hal16550ReadIER((c))|IE16_RECV_READY))
#define DIS_RX16550(c)		hal16550WriteIER((c),(BYTE)(hal16550ReadIER((c))&(~IE16_RECV_READY)))
#define ENA_TX16550(c)		hal16550WriteIER((c),(BYTE)(hal16550ReadIER((c))|IE16_SEND_EMPTY))
#define DIS_TX16550(c)		hal16550WriteIER((c),(BYTE)(hal16550ReadIER((c))&(~IE16_SEND_EMPTY)))
/*Break信号制御*/
#define SET_BREAK16550(c)	hal16550WriteLCR((c),(BYTE)(hal16550ReadLCR((c))|LC16_SEND_BREAK))
#define CLEAR_BREAK16550(c)	hal16550WriteLCR((c),(BYTE)(hal16550ReadLCR((c))&(~LC16_SEND_BREAK)))

#else
/*実機*/

#if 0
/*以下はMCC68Kの例*/
#pragma asm
#include "device.inc"
	SECTION code,,C
#pragma endasm

#define IE16550			asm(unsigned char, " MOVE.W IE16,D0		;READ IE")
#define IID16550		asm(unsigned char, " MOVE.W IID16,D0	;READ IID")
#define STAT16550		asm(unsigned char, " MOVE.W LSTAT16,D0	;READ LINE STATUS")
#define MSTAT16550		asm(unsigned char, " MOVE.W MSTAT16,D0	;READ MODEM STATUS")
#define READ16550		asm(unsigned char, " MOVE.W DATA16,D0	;READ DATA")
#define WRITE16550		asm(unsigned char, " MOVE.W D0,DATA16	;WRITE DATA")
/*DTEのモデム信号制御*/
#define SET_DTR16550	asm(unsigned char, " ORI.W	#01H,MCNTR16	;set DTR")
#define CLEAR_DTR16550	asm(unsigned char, " ANDI.W	#0FEH,MCNTR16	;clear DTR")
#define SET_RTS16550	asm(unsigned char, " ORI.W	#02H,MCNTR16	;set RTS")
#define CLEAR_RTS16550	asm(unsigned char, " ANDI.W	#0FDH,MCNTR16	;clear RTS")
#define SET_CI16550		asm(unsigned char, " ORI.W	#04H,MCNTR16	;set out1 for CI")
#define CLEAR_CI16550	asm(unsigned char, " ANDI.W	#0FBH,MCNTR16	;clear out1 for CI")
#define SET_CD16550		asm(unsigned char, " ORI.W	#08H,MCNTR16	;set out2 for CD")
#define CLEAR_CD16550	asm(unsigned char, " ANDI.W	#0F7H,MCNTR16	;clear out2 for CD")
/*DTEの割込み制御*/
#define ENA_RX16550		asm(unsigned char, " ORI.W	#01H,IE16	;enable RX ready")
#define DIS_RX16550		asm(unsigned char, " ANDI.W	#0FEH,IE16	;disable RX ready")
#define ENA_TX16550		asm(unsigned char, " ORI.W	#02H,IE16	;ENABLE TX READY")
#define DIS_TX16550		asm(unsigned char, " ANDI.W	#0FDH,IE16	;DISABLE TX READY")
#endif	//0

#endif/*_CMTOY*/

#endif	//__HAL_UART_H__