;===============================================================================
;
;	PS/2キーボードプロトコルコンバージョンアダプタ(PPCA)
;
;		Author		: K.Takahashi(tokoya)
;		Version		: 1.00
;		Last Update	: 2000/11/17
;		Target		: AT90S2313
;		Comment		: 外部クロック8MHz使用
;
;	2000/09/19	: 初版
;	2000/10/24	: トランスレートモード追加
;	2000/11/06	: キーボードへのコマンド送信機能追加
;	2000/11/15	: 変換テーブルの構造を変更
;	2000/11/16	: ホストからキーボードへコマンド送信する機能を追加
;	2000/11/17	: 拡張トランスレートモードを追加
;
;===============================================================================

.include "2313def.inc"
.include "CodeTbl.inc"

.def	tx_cmd		= r12				; キーボードへの送信コマンド
.def	tx_opt		= r13				; キーボードへの送信オプション
.def	rx_code		= r14				; キーボードからの受信コード
.def	tx_code		= r15				; キーボードへの送信コード

.def	tp_main		= r16				; メインワーク
.def	tp_int		= r17				; 割り込み内使用ワーク
.def	tp_send		= r18				; ホストへの送信キャラクタ
.def	i0_code		= r19
.def	i0_count	= r20
.def	pt_count	= r21				; パリティカウント
.def	tx_count	= r22
.def	fg_mode		= r23				; S - SCANCODE
							; T - TRANSLATE
							; X - EXTEND TRANSLATE
.def	fg_key		= r24				; bit0 - key_up
							; bit1 - key_shift
							; bit2 - edge_flag
							; bit3 - e0_flag
							; bit4 - e1_flag
.def	fg_txrx		= r25				; bit0 - tx_request
							; bit1 - tx_option
							; bit2 - rx_busy
							; bit3 - rx_wait
.def	key_stat	= r26				; bit0 - left_ctrl
							; bit1 - left_shift
							; bit2 - left_alt
							; bit3 - right_ctrl
							; bit4 - right_shift
							; bit5 - right_alt
.def	led_stat	= r27				; bit0 - Scroll Lock
							; bit1 - Num Lock
							; bir2 = Caps Lock
.def	fg_cmd		= r28				; bit0 - 1Byte Command
							; bit1 - 2Byte Command(First)
							; bit2 - 2Byte Command(Second)
							; bit3 - LED Set

.equ	ASCII_MODE	= 0

.equ	KEY_UP		= 0
.equ	KEY_SHIFT	= 1
.equ	EDGE_FLAG	= 2
.equ	E0_FLAG		= 3
.equ	E1_FLAG		= 4

.equ	TX_REQUEST	= 0
.equ	TX_OPTION	= 1
.equ	RXC_WAIT	= 2
.equ	RX_BUSY		= 3

.equ	L_CTRL		= 0
.equ	L_SHIFT		= 1
.equ	L_ALT		= 2
.equ	R_CTRL		= 3
.equ	R_SHIFT		= 4
.equ	R_ALT		= 5

.equ	KB_CLK		= 2
.equ	KB_DATA		= 4

.equ	SCROLL_LOCK	= 0
.equ	NUM_LOCK	= 1
.equ	CAPS_LOCK	= 2

.equ	X1BYTE_CMD	= 0
.equ	X2BYTE_CMD_F	= 1
.equ	X2BYTE_CMD_S	= 2
.equ	LED_SET		= 3

.equ	MAKE_L_CTRL	= 0x90
.equ	MAKE_L_SHIFT	= 0x91
.equ	MAKE_L_ALT	= 0x92
.equ	MAKE_R_CTRL	= 0x93
.equ	MAKE_R_SHIFT	= 0x94
.equ	MAKE_R_ALT	= 0x95
.equ	BREAK_L_CTRL	= 0x96
.equ	BREAK_L_SHIFT	= 0x97
.equ	BREAK_L_ALT	= 0x98
.equ	BREAK_R_CTRL	= 0x99
.equ	BREAK_R_SHIFT	= 0x9A
.equ	BREAK_R_ALT	= 0x9B

.CSEG
.ORG	$0
		rjmp	RESET
		rjmp	EXT_INT0			; キーボード割り込み
		rjmp	EXT_INT1			; マウス割り込み
		rjmp	DUMMY
		rjmp	DUMMY
		rjmp	DUMMY
		rjmp	DUMMY
		rjmp	UART_RXC			; シリアル受信割り込み
		rjmp	DUMMY
		rjmp	DUMMY
		rjmp	DUMMY

DUMMY:
		reti

;---------------------------------------
;	初期化
;---------------------------------------
RESET:
		ldi	tp_main,low(RAMEND)		; スタックポインタ設定
		out	SPL,tp_main
	
		ldi	tp_main,0b11111111		; ポートＢを出力に設定(デバッグ用)
		out	DDRB,tp_main

		ldi	tp_main,0b01000011		; ポートＤのPD5～PD2を入力に設定
		out	DDRD,tp_main
		ldi	tp_main,0b00000000		; プルアップ無し
		out	PORTD,tp_main

		ldi	tp_main,(1<<ISC01)		; 立ち下がりで割り込み発生
		out	MCUCR,tp_main

		ldi	tp_main,0b10011000		; 送受信許可、受信割り込み許可
		out	UCR,tp_main
		ldi	tp_main,12			; クロック8MHz時のUBRR値(38400bps)
		out	UBRR,tp_main

		clr	i0_code				; ワークレジスタ初期化
		ldi	i0_count,11
		ldi	fg_mode,'T'			; トランスレートモード
		clr	fg_key
		clr	fg_txrx
		clr	key_stat
		clr	led_stat
		clr	fg_cmd

		ldi	tp_main,(1<<INT0)		; INT0割り込み許可
		out	GIMSK,tp_main
		sei					; 割り込み許可

;---------------------------------------
;	メインループ
;---------------------------------------
MAIN:
		cbr	fg_txrx,(1<<RXC_WAIT)		; 受信完了通知フラグをクリア
		clr	rx_code
MAIN_RX_0:
		sbrc	fg_txrx,TX_REQUEST		; 送信要求フラグが立っている？
		rjmp	MAIN_RX_1
		sbrs	fg_txrx,RXC_WAIT		; 受信完了フラグが立っていたら受信完了
		rjmp	MAIN_RX_0
		rjmp	MAIN_RX_2
MAIN_RX_1:
		sbrc	fg_txrx,RX_BUSY			; 受信途中なら完了まで待つ
		brne	MAIN_RX_0
		rjmp	MAIN_TX
MAIN_RX_2:
	;
	; ホストへキーコード送信
	;
		mov	tp_send,rx_code
		cpi	fg_mode,'T'			; トランスレートモード？
		breq	MAIN_RX_3
		cpi	fg_mode,'X'			; 拡張トランスレートモード？
		breq	MAIN_RX_3
		rcall	SEND				; スキャンコードをそのまま送出
		rjmp	MAIN
MAIN_RX_3:
		rcall	TRANSLATE			; コード変換してから送出
		rjmp	MAIN	

MAIN_TX:
	;
	; キーボードへコマンド送信
	;
		mov	tx_code,tx_cmd
		rcall	SEND_TO_KB			; キーボードにコマンド送信
		rcall	RX_WAIT				; ACK受信
		sbrs	fg_txrx,TX_OPTION
		rjmp	MAIN_TX_0
		mov	tx_code,tx_opt
		rcall	SEND_TO_KB			; キーボードにオプション送信
		rcall	RX_WAIT				; ACK受信
MAIN_TX_0:
		cbr	fg_txrx,(1<<TX_REQUEST)		; 送信要求フラグをクリア
		cbr	fg_txrx,(1<<TX_OPTION)		; オプション送信フラグをクリア
		rjmp	MAIN				

;---------------------------------------
;	受信待ち
;---------------------------------------
RX_WAIT:
		cbr	fg_txrx,(1<<RXC_WAIT)		; 受信完了通知フラグをクリア
		clr	rx_code
RX_WAIT_0:
		sbrs	fg_txrx,RXC_WAIT		; 受信完了フラグが立っていたら受信完了
		rjmp	RX_WAIT_0
		ret

;---------------------------------------
;	送信
;---------------------------------------
SEND:
		sbis	USR,UDRE			; 送信終了まで待つ
		rjmp	SEND
		out	UDR,tp_send
		ret

;---------------------------------------
;	16進数値の送信(デバッグ用)
;---------------------------------------
SEND_HEX:
		push	tp_send
		lsr	tp_send
		lsr	tp_send
		lsr	tp_send
		lsr	tp_send
		ori	tp_send,0x30
		cpi	tp_send,0x3A
		brlo	SEND_HEX_0
		ldi	tp_main,0x07
		add	tp_send,tp_main
SEND_HEX_0:
		sbis	USR,UDRE			; 送信終了まで待つ
		rjmp	SEND_HEX_0
		out	UDR,tp_send
		pop	tp_send
		andi	tp_send,0x0F
		ori	tp_send,0x30
		cpi	tp_send,0x3A
		brlo	SEND_HEX_1
		ldi	tp_main,0x07
		add	tp_send,tp_main
SEND_HEX_1:
		sbis	USR,UDRE			; 送信終了まで待つ
		rjmp	SEND_HEX_1
		out	UDR,tp_send
		ret	

;---------------------------------------
;	コード変換
;---------------------------------------
TRANSLATE:
		sbrc	fg_key,KEY_UP
		rjmp	TRANSLATE_B_0
	;
	; 付加コードチェック
	;
		cpi	tp_send,0xE0			; 付加コード？
		brne	TRANSLATE_M_00
		sbr	fg_key,(1<<E0_FLAG)		; 付加コード有りフラグを立てる
		rjmp	TRANSLATE_EXIT
TRANSLATE_M_00:
		cpi	tp_send,0xE1			; 付加コード？
		brne	TRANSLATE_M_0
		sbr	fg_key,(1<<E1_FLAG)		; 付加コード有りフラグを立てる
		rjmp	TRANSLATE_EXIT
TRANSLATE_M_0:
		cpi	tp_send,0xF0			; ブレークコード？
		brne	TRANSLATE_M_1
		sbr	fg_key,(1<<KEY_UP)
		rjmp	TRANSLATE_EXIT
	;
	; キーが押された時の処理
	;
TRANSLATE_M_1:
		cpi	tp_send,0x14			; CTRL
		brne	TRANSLATE_M_3
		sbrc	fg_key,E0_FLAG
		rjmp	TRANSLATE_M_2
		sbrc	fg_key,E1_FLAG			; E1の時は無視
		rjmp	TRANSLATE_EXIT
		sbrc	key_stat,L_CTRL			; 既に押されている？
		rjmp	TRANSLATE_EXIT
		sbr	key_stat,(1<<L_CTRL)
		ldi	tp_send,MAKE_L_CTRL
		rjmp	TRANSLATE_M_A
TRANSLATE_M_2:
		sbrc	key_stat,R_CTRL			; 既に押されている？
		rjmp	TRANSLATE_EXIT
		sbr	key_stat,(1<<R_CTRL)
		ldi	tp_send,MAKE_R_CTRL
		rjmp	TRANSLATE_M_A
		
TRANSLATE_M_3:
		cpi	tp_send,0x11			; ALT
		brne	TRANSLATE_M_5
		sbrc	fg_key,E0_FLAG
		rjmp	TRANSLATE_M_4
		sbrc	key_stat,L_ALT			; 既に押されている？
		rjmp	TRANSLATE_EXIT
		sbr	key_stat,(1<<L_ALT)
		ldi	tp_send,MAKE_L_ALT
		rjmp	TRANSLATE_M_A
TRANSLATE_M_4:
		sbrc	key_stat,R_ALT			; 既に押されている？
		rjmp	TRANSLATE_EXIT
		sbr	key_stat,(1<<R_ALT)
		ldi	tp_send,MAKE_R_ALT
		rjmp	TRANSLATE_M_A
		
TRANSLATE_M_5:
		cpi	tp_send,0x12			; L-SHIFT
		brne	TRANSLATE_M_6
		sbrc	key_stat,L_SHIFT		; 既に押されている？
		rjmp	TRANSLATE_EXIT
		sbr	key_stat,(1<<L_SHIFT)
		ldi	tp_send,MAKE_L_SHIFT
		rjmp	TRANSLATE_M_A
TRANSLATE_M_6:
		cpi	tp_send,0x59			; R-SHIFT
		brne	TRANSLATE_M_7
		sbrc	key_stat,R_SHIFT		; 既に押されている？
		rjmp	TRANSLATE_EXIT
		sbr	key_stat,(1<<R_SHIFT)
		ldi	tp_send,MAKE_R_SHIFT
		rjmp	TRANSLATE_M_A

TRANSLATE_M_7:
	;
	; テーブルを引いて変換
	;
		ldi	ZH,high(transtbl)		; 変換テーブル
		ldi	ZL,low(transtbl)
		add	ZL,tp_send
		clr	tp_send
		adc	ZH,tp_send
		clc
		rol	ZL
		rol	ZH
		mov	tp_main,key_stat
		andi	tp_main,(1<<L_SHIFT)+(1<<R_SHIFT)	; SHIFTが押されている？
		brne	TRANSLATE_M_8
		sbrs	fg_key,E0_FLAG			; 付加コード有り？
		rjmp	TRANSLATE_M_9
TRANSLATE_M_8:
		ori	ZL,0x01				; 上位バイトアクセス
TRANSLATE_M_9:
		lpm
		mov	tp_send,r0
	;
	; Num Lock処理
	;
		cpi	tp_send,0xB0			; 10Key数値?
		brlo	TRANSLATE_M_A
		cpi	tp_send,0xBA
		brsh	TRANSLATE_M_A
		sbrs	led_stat,NUM_LOCK		; Num Lock状態?
		rjmp	TRANSLATE_M_90
		andi	tp_send,0x0F			; B0-B9→30-39(数字)
		ori	tp_send,0x30
		rjmp	TRANSLATE_M_A
TRANSLATE_M_90:
		andi	tp_send,0x0F			; B0-B9→A0-A9(カーソル移動キー)
		ori	tp_send,0xA0
		cpi	tp_send,0xA5			; 10key数値の'5'に対するカーソル移動キーは無い
		brne	TRANSLATE_M_A
		ldi	tp_send,0x00	
TRANSLATE_M_A:
	;
	; 特殊キー処理
	;
	;	付加コードE1付きのNumLockはPauseに置き換える
	;	CTRLが押されている時のScrollLockはPauseに置き換える
	;
		cpi	tp_send,0xD1			; Num Lock?
		brne	TRANSLATE_M_A0
		sbrc	fg_key,E1_FLAG
		ldi	tp_send,0xAA			; Pauseのコードに置き換え
		rjmp	TRANSLATE_M_A1
TRANSLATE_M_A0:
		cpi	tp_send,0xD0			; Scroll Lock?
		brne	TRANSLATE_M_A1
		mov	tp_main,key_stat
		andi	tp_main,(1<<L_CTRL)+(1<<R_CTRL)	; CTRLが押されている？
		breq	TRANSLATE_M_A1
		ldi	tp_send,0xAA			; Pauseのコードに置き換え
TRANSLATE_M_A1:
	;
	; Caps Lock処理
	;
		sbrs	led_stat,CAPS_LOCK		; Caps Lock状態?
		rjmp	TRANSLATE_M_A3
		cpi	tp_send,'A'			; 英大文字?
		brlo	TRANSLATE_M_A2
		cpi	tp_send,'Z'+1
		brsh	TRANSLATE_M_A2
		ori	tp_send,0x20			; 英小文字に変換
		rjmp	TRANSLATE_M_A3
TRANSLATE_M_A2:
		cpi	tp_send,'a'			; 英小文字?
		brlo	TRANSLATE_M_A3
		cpi	tp_send,'z'+1
		brsh	TRANSLATE_M_A3
		andi	tp_send,0xDF			; 英大文字に変換
TRANSLATE_M_A3:
	;
	; ホストに送信
	;
		cpi	tp_send,0x00			; コード0x00は送信しない
		breq	TRANSLATE_M_B
		cpi	fg_mode,'X'			; 拡張トランスレートモード？
		breq	TRANSLATE_M_A4
		cpi	tp_send,0x80			; コード0x80以上は送信しない
		brsh	TRANSLATE_M_A5
TRANSLATE_M_A4:
		rcall	SEND
TRANSLATE_M_A5:
	;
	; Scroll Lock/Num Lock/Caps LockキーはLEDのON/OFF処理を行う
	;
		cpi	tp_send,0xD0
		brlo	TRANSLATE_M_B
		cpi	tp_send,0xD3
		brsh	TRANSLATE_M_B
		rcall	SET_LED				; LEDのON/OFF
TRANSLATE_M_B:
		cbr	fg_key,(1<<E0_FLAG)
		cbr	fg_key,(1<<E1_FLAG)
		rjmp	TRANSLATE_EXIT

	;
	; キーが離された時の処理
	;
TRANSLATE_B_0:
		sbrs	fg_key,E1_FLAG			; Pause/Break
		rjmp	TRANSLATE_B_00
		cpi	tp_send,0x77
		brne	TRANSLATE_EXIT
		rjmp	TRANSLATE_B_B
TRANSLATE_B_00:
		cpi	tp_send,0x14			; CTRL
		brne	TRANSLATE_B_3
		sbrc	fg_key,E0_FLAG
		rjmp	TRANSLATE_B_2
		sbrc	fg_key,E1_FLAG			; E1の時は無視
		rjmp	TRANSLATE_EXIT
		cbr	key_stat,(1<<L_CTRL)
		ldi	tp_send,BREAK_L_CTRL
		rjmp	TRANSLATE_B_A
TRANSLATE_B_2:
		cbr	key_stat,(1<<R_CTRL)
		ldi	tp_send,BREAK_R_CTRL
		rjmp	TRANSLATE_B_A
		
TRANSLATE_B_3:
		cpi	tp_send,0x11			; ALT
		brne	TRANSLATE_B_5
		sbrc	fg_key,E0_FLAG
		rjmp	TRANSLATE_B_4
		cbr	key_stat,(1<<L_ALT)
		ldi	tp_send,BREAK_L_ALT
		rjmp	TRANSLATE_B_A
TRANSLATE_B_4:
		cbr	key_stat,(1<<R_ALT)
		ldi	tp_send,BREAK_R_ALT
		rjmp	TRANSLATE_B_A
		
TRANSLATE_B_5:
		cpi	tp_send,0x12			; L-SHIFT
		brne	TRANSLATE_B_6
		cbr	key_stat,(1<<L_SHIFT)
		ldi	tp_send,BREAK_L_SHIFT
		rjmp	TRANSLATE_B_A
TRANSLATE_B_6:
		cpi	tp_send,0x59			; R-SHIFT
		brne	TRANSLATE_B_7
		cbr	key_stat,(1<<R_SHIFT)
		ldi	tp_send,BREAK_R_SHIFT
		rjmp	TRANSLATE_B_A

TRANSLATE_B_7:
		rjmp	TRANSLATE_B_B
		
TRANSLATE_B_A:
	;
	; ホストに送信
	;
		cpi	fg_mode,'X'			; 拡張トランスレートモード？
		breq	TRANSLATE_B_A1
		cpi	tp_send,0x80			; コード0x80以上は送信しない
		brsh	TRANSLATE_B_B
TRANSLATE_B_A1:
		rcall	SEND
TRANSLATE_B_B:
		cbr	fg_key,(1<<KEY_UP)
		cbr	fg_key,(1<<E0_FLAG)
		cbr	fg_key,(1<<E1_FLAG)
		rjmp	TRANSLATE_EXIT
	
TRANSLATE_EXIT:
		ret

;---------------------------------------
;	LEDのON/OFF
;---------------------------------------
SET_LED:
		cpi	tp_send,0xD0			; Scroll Lock
		brne	SET_LED_0
		ldi	tp_main,(1<<SCROLL_LOCK)
		rjmp	SET_LED_2
SET_LED_0:
		cpi	tp_send,0xD1			; Num Lock
		brne	SET_LED_1
		ldi	tp_main,(1<<NUM_LOCK)
		rjmp	SET_LED_2
SET_LED_1:
		cpi	tp_send,0xD2			; Caps Lock
		brne	SET_LED_3
		ldi	tp_main,(1<<CAPS_LOCK)
SET_LED_2:
		eor	led_stat,tp_main
		sbr	fg_txrx,(1<<TX_REQUEST)
		sbr	fg_txrx,(1<<TX_OPTION)
		ldi	tp_main,0xED
		mov	tx_cmd,tp_main
		mov	tx_opt,led_stat
SET_LED_3:
		ret		

;---------------------------------------
;	キーボードへコマンド送信
;---------------------------------------
SEND_TO_KB:
		cli					; 割り込み禁止

		cbi	PORTD,KB_CLK			; CLKポート出力をLに設定
		cbi	PORTD,KB_DATA			; DATAポート出力をLに設定
		sbi	DDRD,KB_CLK			; ポートＤのPD2(KB_CLK)を出力に設定(L出力)

		ldi	tp_main,128			; 64μSec待ち(0.125μSecx4x128=64μSec)
SEND_TO_KB_0:
		nop
		dec	tp_main
		brne	SEND_TO_KB_0

		sbi	DDRD,KB_DATA			; ポートＤのPD4(KB_DATA)を出力に設定(L出力)(スタートビット)
		cbi	DDRD,KB_CLK			; ポートＤのPD2(KB_CLK)を入力に設定

		ldi	tx_count,8
		clr	pt_count
		rcall	CLK_HIGHLOW			; CLKの立ち下がりを待つ

SEND_TO_KB_1:
		ror	tx_code				; 1ビット右シフト
		brcs	SEND_TO_KB_2
		sbi	DDRD,KB_DATA			; L出力
		rjmp	SEND_TO_KB_3
SEND_TO_KB_2:
		cbi	DDRD,KB_DATA			; H出力(プルアップでHになる)
		inc	pt_count			; パリティカウント
SEND_TO_KB_3:
		rcall	CLK_HIGHLOW			; CLKの立ち下がりを待つ
		dec	tx_count
		brne	SEND_TO_KB_1

		sbrc	pt_count,0			; 偶数？
		rjmp	SEND_TO_KB_4
		cbi	DDRD,KB_DATA			; L出力(パリティビット)
		rjmp	SEND_TO_KB_5
SEND_TO_KB_4:		
		sbi	DDRD,KB_DATA			; H出力(パリティビット)
SEND_TO_KB_5:						
		rcall	CLK_HIGHLOW			; CLKの立ち下がりを待つ
		cbi	DDRD,KB_DATA			; H出力(ストップビット)

		rcall	CLK_HIGHLOW			; CLKの立ち下がりを待つ
		sbis	PIND,KB_DATA			; ACK?
		rjmp	SEND_TO_KB_6
		
		ldi	tp_main,0xFF
		mov	tx_code,tp_main			; リセットコマンド
		rjmp	SEND_TO_KB		

SEND_TO_KB_6:
		sbis	PIND,KB_CLK			; ラインがアイドル状態になるまで待つ
		rjmp	SEND_TO_KB_6

		clr	i0_code				; ワークレジスタ初期化
		ldi	i0_count,11
		clr	fg_key

		sei
		ret

;---------------------------------------
;	CLKの立ち下がりを待つ
;---------------------------------------
CLK_HIGHLOW:
		sbis	PIND,KB_CLK
		rjmp	CLK_HIGHLOW
CLK_HIGHLOW_0:
		sbic	PIND,KB_CLK
		rjmp	CLK_HIGHLOW_0
		ret

;---------------------------------------
;	キーボード割り込み
;---------------------------------------
EXT_INT0:
		in	r0,SREG				; SREGレジスタを待避する
		push	r0
		push	tp_int

		sbr	fg_txrx,(1<<RX_BUSY)		; 受信処理中フラグを立てる

		sbrc	fg_key,EDGE_FLAG		; 立ち上がりの割り込み？
		rjmp	EXT_INT0_1

		cpi	i0_count,11			; パリティ、スタートビット、ストップビットは除く
		brsh	EXT_INT0_0
		cpi	i0_count,3
		brlo	EXT_INT0_0
		lsr	i0_code
		sbic	PIND,PD4
		ori	i0_code,0x80

EXT_INT0_0:
		ldi	tp_int,(1<<ISC01)+(1<<ISC00)	; 立ち上がりでの割り込み発生に設定
		out	MCUCR,tp_int
		sbr	fg_key,(1<<EDGE_FLAG)		; フラグセット
		rjmp	EXT_INT0_EXIT

EXT_INT0_1:
		ldi	tp_int,(1<<ISC01)		; 立ち下がりでの割り込み発生に設定
		out	MCUCR,tp_int
		cbr	fg_key,(1<<EDGE_FLAG)		; フラグクリア
		dec	i0_count			; 全ビット受信？
		brne	EXT_INT0_EXIT

		mov	rx_code,i0_code			; 受信コード
		clr	i0_code
		ldi	i0_count,11
		sbr	fg_txrx,(1<<RXC_WAIT)		; 受信完了通知フラグを立てる
		cbr	fg_txrx,(1<<RX_BUSY)		; 受信処理中フラグをクリア

EXT_INT0_EXIT:	
		pop	tp_int
		pop	r0				; SREGレジスタを復帰する
		out	SREG,r0
		reti					; 割り込みから戻る

;---------------------------------------
;	マウス割り込み
;---------------------------------------
EXT_INT1:
		in	r0,SREG				; SREGレジスタを待避する
		push	r0

		pop	r0				; SREGレジスタを復帰する
		out	SREG,r0
		reti					; 割り込みから戻る

;---------------------------------------
;	シリアル受信割り込み
;---------------------------------------
UART_RXC:
		in	r0,SREG				; SREGレジスタを待避する
		push	r0
		push	tp_int
		push	tp_main

		in	tp_int,UDR
		tst	fg_cmd
		breq	UART_RXC_SKIP_00
		rjmp	UART_RXC_CMD

UART_RXC_SKIP_00:
		cpi	tp_int,'V'			; バージョン情報
		brne	UART_RXC_SKIP_0
		ldi	tp_send,'P'
		rcall	SEND
		ldi	tp_send,'P'
		rcall	SEND
		ldi	tp_send,'C'
		rcall	SEND
		ldi	tp_send,'A'
		rcall	SEND
		ldi	tp_send,' '
		rcall	SEND
		ldi	tp_send,'V'
		rcall	SEND
		ldi	tp_send,'1'
		rcall	SEND
		ldi	tp_send,'.'
		rcall	SEND
		ldi	tp_send,'0'
		rcall	SEND
		ldi	tp_send,'0'
		rcall	SEND
		rjmp	UART_RXC_EXIT
	
UART_RXC_SKIP_0:
		cpi	tp_int,'S'			; スキャンコードモード
		brne	UART_RXC_SKIP_1
		ldi	fg_mode,'S'
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_1:
		cpi	tp_int,'T'			; トランスレートモード
		brne	UART_RXC_SKIP_11
		ldi	fg_mode,'T'
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_11:
		cpi	tp_int,'X'			; 拡張トランスレートモード
		brne	UART_RXC_SKIP_2
		ldi	fg_mode,'X'
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_2:
		cpi	tp_int,'L'			; LED状態取得
		brne	UART_RXC_SKIP_21
		mov	tp_send,led_stat
		ori	tp_send,0x30
		rcall	SEND
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_21:
		cpi	tp_int,'K'			; キー状態取得
		brne	UART_RXC_SKIP_3
		mov	tp_send,key_stat
		andi	tp_send,0x07
		ori	tp_send,0x30
		rcall	SEND
		mov	tp_send,key_stat
		lsr	tp_send
		lsr	tp_send
		lsr	tp_send
		andi	tp_send,0x07
		ori	tp_send,0x30
		rcall	SEND
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_3:
		cpi	tp_int,'R'			; キーボードリセット
		brne	UART_RXC_SKIP_4
		sbr	fg_txrx,(1<<TX_REQUEST)
		ldi	tp_main,0xFF
		mov	tx_cmd,tp_main
		clr	key_stat			; キー状態クリア
		clr	led_stat			; LED状態クリア
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_4:
		cpi	tp_int,'E'			; LED状態設定
		brne	UART_RXC_SKIP_5
		sbr	fg_cmd,(1<<LED_SET)
		rjmp	UART_RXC_EXIT
		
UART_RXC_SKIP_5:
		cpi	tp_int,'1'			; 1Byteコマンド
		brne	UART_RXC_SKIP_6
		sbr	fg_cmd,(1<<X1BYTE_CMD)
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_6:
		cpi	tp_int,'2'			; 2Byteコマンド
		brne	UART_RXC_EXIT
		sbr	fg_cmd,(1<<X2BYTE_CMD_F)
		rjmp	UART_RXC_EXIT

UART_RXC_CMD:
		sbrs	fg_cmd,LED_SET
		rjmp	UART_RXC_CMD_0
		sbr	fg_txrx,(1<<TX_REQUEST)
		sbr	fg_txrx,(1<<TX_OPTION)
		ldi	tp_main,0xED
		mov	tx_cmd,tp_main
		andi	tp_int,0x07
		mov	tx_opt,tp_int
		clr	fg_cmd
		rjmp	UART_RXC_EXIT
		
UART_RXC_CMD_0:
		sbrs	fg_cmd,X1BYTE_CMD
		rjmp	UART_RXC_CMD_1
		sbr	fg_txrx,(1<<TX_REQUEST)
		mov	tx_cmd,tp_int
		clr	fg_cmd
		rjmp	UART_RXC_EXIT

UART_RXC_CMD_1:
		sbrs	fg_cmd,X2BYTE_CMD_S
		rjmp	UART_RXC_CMD_2
		sbr	fg_txrx,(1<<TX_REQUEST)
		sbr	fg_txrx,(1<<TX_OPTION)
		mov	tx_opt,tp_int
		clr	fg_cmd
		rjmp	UART_RXC_EXIT

UART_RXC_CMD_2:
		sbrs	fg_cmd,X2BYTE_CMD_F
		rjmp	UART_RXC_EXIT
		mov	tx_cmd,tp_int
		sbr	fg_cmd,(1<<X2BYTE_CMD_S)
		rjmp	UART_RXC_EXIT

UART_RXC_EXIT:
		pop	tp_main
		pop	tp_int
		pop	r0				; SREGレジスタを復帰する
		out	SREG,r0
		reti					; 割り込みから戻る
