;===============================================================================
;
;	PS/2キーボードプロトコルコンバージョンアダプタ(PPCA)
;
;		Author		: K.Takahashi(tokoya)
;		Version		: 1.00
;		Last Update	: 2000/11/17
;		Target		: AT90S2313 -> ATtiny2313
;		Comment		: 外部クロック8MHz使用 -> ATtiny2313内蔵OSC使用(8MHz)
;
;	2000/09/19	: 初版
;	2000/10/24	: トランスレートモード追加
;	2000/11/06	: キーボードへのコマンド送信機能追加
;	2000/11/15	: 変換テーブルの構造を変更
;	2000/11/16	: ホストからキーボードへコマンド送信する機能を追加
;	2000/11/17	: 拡張トランスレートモードを追加
;	2008/01/22	: ホスト通信速度変更(115200,8N1)およびそれに伴う内蔵RC調整(7.4MHz)
;	2008/01/23	: トランスレートモードでctrl+A〜Z(0x01-0x1A)対応
;	2008/01/23	: KBポートにマウスモード追加
;	2008/01/25	: キャラクタLCD(2行モノ専用)対応追加
;	2009/09/23	: 遅いキャラクタLCD対応(初期化などのwaitを2-3倍程度に増加)
;
;===============================================================================
;Command list
;
;S	スキャンコードモードに切替
;
;T	トランスレートモードに切替（デフォルト）
;
;X	拡張トランスレートモードに切替
;
;V	ファームウェアバージョンを返す
;
;R	キーボードリセット
;
;L	LEDの状態を取得
;	　bit0 - Scroll Lock
;	　bit1 - Num Lock
;	　bit2 - Caps lock
;	　以上のビット状態に0x30を加えた値が返ってきます。
;	　従ってアダプタからの戻り値は'0'〜'7'までの文字となります。
;
;E	LED状態設定
;	　このコマンドに続けて送信した1バイトの、下位3ビットをLEDの状態として設定します。
;	　bit0 - Scroll Lock
;	　bit1 - Num Lock
;	　bit2 - Caps lock
;	　スキャンコードモードで動作している時は、このコマンドでLED状態を設定しても、キーコードは変わりません。
;	　トランスレート、拡張トランスレートモードの場合は、LED状態の設定によってキーコードが変化します。
;
;K	キー状態取得
;	　Ctrl、Shift、Altの状態が、2バイトのコードとして返ってきます。
;		最初のバイト
;		　bit0 - 左Ctrl
;		　bit1 - 左Shift
;		　bit2 - 左Alt
;		次のバイト
;		　bit0 - 右Ctrl
;		　bit1 - 右Shift
;		　bit2 - 右Alt
;	　以上のビット状態に0x30を加えた値が返ってきます。
;	　従ってアダプタからの戻り値は'0'〜'7'までの文字となります。
;
;1	1バイトコマンド送信
;	　キーボードに1バイトコマンドを送信します。
;	　このコマンドに続けて送信した1バイトのデータをそのままキーボードに送信します。
;	　デバッグ用に付けたもので、特殊なことをやろうとしない限りは使う必要は無いでしょう。
;
;2	2バイトコマンド送信
;	　キーボードに2バイトコマンドを送信します。
;	　このコマンドに続けて送信した2バイトのデータをそのままキーボードに送信します。
;	　これもデバッグ用に付けたものです。
;
;===============================================================================
;Extended command list
;
;M	PS/2デバイスにイネーブルコマンド(F4)を発行してスキャンコードモードに切替える
;	　PS/2マウスの情報取り込みに使える
;
;U	LCDリセット
;
;P	このコマンドに続けて送信した1バイトをLCDにデータとして書き込む
;
;Q	このコマンドに続けて送信した1バイトをLCDにコマンドとして書き込む;
;
;===============================================================================

.include "2313def.inc"
.include "CodeTbl.inc"

.def	lcd_send	= r8				; LCDヘの送信データ
.def	lcd_dat		= r9				; LCDのワーク
.def	lcd_sta		= r10				; LCDのステータス
.def	lcd_cnt		= r11				; LCDのタイムアウトカウンタ

.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	LCD_TX_DAT	= 4
.equ	LCD_TX_CMD	= 5
.equ	LCD_TX_INIT	= 6


.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

; port-D(LCD ctrl)
.equ	LCD_E		= 6
.equ	LCD_RW		= 5
.equ	LCD_RS  	= 3

.equ	lcd_busy 	= 7


.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	LCD_OUT_CMD	= 4
.equ	LCD_EXE_CMD	= 5

.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

.equ	OSCCAL	= 0x31

.CSEG
.ORG	$0
		rjmp	RESET
		rjmp	EXT_INT0			; キーボード割り込み
		rjmp	DUMMY
		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
	
;		in	tp_main,OSCCAL			; Internal OSC calibration
;		subi tp_main,10				; 8MHz x 0.92(@OSCCAL=$77)= 7.375MHz
;		out	OSCCAL,tp_main

		ldi	tp_main,0b01101011		; ポートＤのPD4,PD2を入力に設定
		out	DDRD,tp_main
		clr	tp_main					; プルアップ無し
		out	PORTD,tp_main			; (LCD_E,RW,RS=L)

		ldi	tp_main,(1<<ISC01)		; 立ち下がりで割り込み発生
		out	MCUCR,tp_main

		ldi	tp_main,0b10011000		; 送受信許可、受信割り込み許可
		out	UCR,tp_main
		ldi	tp_main,12			; クロック8MHz時のUBRR値(38400bps)
;		ldi	tp_main,3			; クロック7.37MHz時のUBRR値(115200bps)
		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					; 割り込み許可

		rjmp MAIN_LCD_INIT			; LCD初期化


;---------------------------------------
;	メインループ
;---------------------------------------
MAIN:
		cbr	fg_txrx,(1<<RXC_WAIT)		; 受信完了通知フラグをクリア
		clr	rx_code
MAIN_RX_0:
		sbrc	fg_txrx,LCD_TX_INIT		; LCD_INIT送信要求フラグが立っている？
		rjmp	MAIN_LCD_INIT
		sbrc	fg_txrx,LCD_TX_CMD		; LCD_CMD送信要求フラグが立っている？
		rjmp	MAIN_LCD_TX_CMD
		sbrc	fg_txrx,LCD_TX_DAT		; LCD_DAT送信要求フラグが立っている？
		rjmp	MAIN_LCD_TX_DAT
		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				

MAIN_LCD_TX_CMD:
		cbr	fg_txrx,(1<<LCD_TX_CMD)		; 送信要求フラグをクリア
		mov	tp_main,lcd_send
		rcall LCD_CMD
		rjmp	MAIN				
MAIN_LCD_TX_DAT:
		cbr	fg_txrx,(1<<LCD_TX_DAT)		; 送信要求フラグをクリア
		mov	tp_main,lcd_send
		rcall LCD_OUT
		rjmp	MAIN				
MAIN_LCD_INIT:
		cbr	fg_txrx,(1<<LCD_TX_INIT)	; 送信要求フラグをクリア
		rcall LCD_INIT
		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
		swap	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

; ctrl+A-Z
		mov	tp_main,key_stat
		andi	tp_main,(1<<L_CTRL)+(1<<R_CTRL)	; CTRLが押されている？
		breq	TRANSLATE_M_CTRL_9
		cpi	tp_send,'A'
		brlo	TRANSLATE_M_CTRL_9	; 'A'より小さい場合はスキップ
		cpi	tp_send,'z'+1
		brsh	TRANSLATE_M_CTRL_9	; 'z'より大きい場合はスキップ
		cpi	tp_send,'Z'+1
		brlo	TRANSLATE_M_CTRL_0	; 'Z'以下ならctrlコードに
		cpi	tp_send,'a'
		brsh	TRANSLATE_M_CTRL_0	; 'a'以上ならctrlコードに
		rjmp	TRANSLATE_M_9
TRANSLATE_M_CTRL_0:
		andi	tp_send,0x1f
TRANSLATE_M_CTRL_9:

	;
	; 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:
	;
	; 特殊キー処理
	;
	;	付加コードE0付きの'?'は，'/'(10key)に置き換える
	;	CTRLが押されている時のScrollLockはPauseに置き換える
	;
		cpi	tp_send,'?'			; is '?'?
		brne	TRANSLATE_M_A_NXT
		sbrc	fg_key,E0_FLAG
		ldi	tp_send,'/'			; change to '/'
		rjmp	TRANSLATE_M_A3

TRANSLATE_M_A_NXT:
	;	付加コード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:
;		mov	tp_main,tp_send		; キャラクタLCDへ出力
;		rcall	LCD_OUT
		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:
;		mov	tp_main,tp_send		; キャラクタLCDへ出力
;		rcall	LCD_OUT
		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

;---------------------------------------
;	キーボード割り込み
;---------------------------------------
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					; 割り込みから戻る

;---------------------------------------
;	シリアル受信割り込み
;---------------------------------------
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_M
;		rcall	LCD_CLEAR
		ldi	tp_send,'P'
		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
		ldi	tp_send,'P'
		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
		ldi	tp_send,'C'
		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
		ldi	tp_send,'A'
		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
		ldi	tp_send,'+'
		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
;		ldi	tp_send,'V'
;		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
;		ldi	tp_send,'1'
;		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
;		ldi	tp_send,'.'
;		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
;		ldi	tp_send,'0'
;		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
;		ldi	tp_send,'1'
;		rcall	SEND
;		mov		tp_main,tp_send
;		rcall	LCD_OUT
		rjmp	UART_RXC_EXIT
	
UART_RXC_SKIP_M:
		cpi	tp_int,'M'			; マウスモード
		brne	UART_RXC_SKIP_0
		ldi	fg_mode,'S'
		ldi	tp_main,0xf4
		sbr	fg_txrx,(1<<TX_REQUEST)
		mov	tx_cmd,tp_main
		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_SKIP_7
		sbr	fg_cmd,(1<<X2BYTE_CMD_F)
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_7:
		cpi	tp_int,'P'			; LCD_OUTコマンド
		brne	UART_RXC_SKIP_8
		sbr	fg_cmd,(1<<LCD_OUT_CMD)
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_8:
		cpi	tp_int,'Q'			; LCD_CMDコマンド
		brne	UART_RXC_SKIP_9
		sbr	fg_cmd,(1<<LCD_EXE_CMD)
		rjmp	UART_RXC_EXIT

UART_RXC_SKIP_9:
		cpi	tp_int,'U'			; LCD_INITコマンド
		brne	UART_RXC_EXIT
		sbr	fg_txrx,(1<<LCD_TX_INIT)
		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_CMD_3
		mov	tx_cmd,tp_int
		sbr	fg_cmd,(1<<X2BYTE_CMD_S)
		rjmp	UART_RXC_EXIT

UART_RXC_CMD_3:
		sbrs	fg_cmd,LCD_OUT_CMD
		rjmp	UART_RXC_CMD_4
		mov	lcd_send,tp_int
		sbr	fg_txrx,(1<<LCD_TX_DAT)
		clr	fg_cmd
		rjmp	UART_RXC_EXIT

UART_RXC_CMD_4:
		sbrs	fg_cmd,LCD_EXE_CMD
		rjmp	UART_RXC_CMD_5
		mov	lcd_send,tp_int
		sbr	fg_txrx,(1<<LCD_TX_CMD)
		clr	fg_cmd
UART_RXC_CMD_5:
		rjmp	UART_RXC_EXIT

UART_RXC_EXIT:
		pop	tp_main
		pop	tp_int
		pop	r0				; SREGレジスタを復帰する
		out	SREG,r0
		reti					; 割り込みから戻る


;---------------------------------------
;	CLKの立ち下がりを待つ
;---------------------------------------
CLK_HIGHLOW:
		sbis	PIND,KB_CLK
		rjmp	CLK_HIGHLOW
CLK_HIGHLOW_0:
		sbic	PIND,KB_CLK
		rjmp	CLK_HIGHLOW_0
		ret

;---------------------------------------
;	LCDのステータス入力
;---------------------------------------
LCD_STATUS:
		clr	lcd_sta					; ポートＢを入力に設定
		out	DDRB,lcd_sta
		cbi	PORTD,LCD_RS			; LCD_RSをLに設定(ステータス入力)
		sbi	PORTD,LCD_RW			; LCD_RWをHに設定
		sbi	PORTD,LCD_E				; LCD_EをHに設定
		nop
		in	lcd_sta,PINB			; データを読取る
		cbi	PORTD,LCD_E				; LCD_EをLに設定
		mov	tp_main,lcd_sta
		ret

LCD_WAIT:
		ldi	tp_main,0x40
		mov	lcd_cnt,tp_main
LCD_LOOP:
		rcall LCD_STATUS
		andi tp_main,(1<<lcd_busy)
		breq LCD_EXIT
		dec  lcd_cnt
		brne LCD_LOOP
LCD_EXIT:
		ret

;---------------------------------------
;	LCDへコマンド出力
;---------------------------------------
LCD_CMD:
		mov	lcd_dat,tp_main
		rcall LCD_WAIT
LCD_CMD_NOWAIT:
		cbi	PORTD,LCD_RS			; LCD_RSをLに設定(コマンド出力)
		cbi	PORTD,LCD_RW			; LCD_RWをLに設定
		out	PORTB,lcd_dat			; データを設定する
		clr	lcd_sta					; ポートＢを出力に設定
		com	lcd_sta
		out	DDRB,lcd_sta
		out	PORTB,lcd_dat			; データを設定する
		sbi	PORTD,LCD_E				; LCD_EをHに設定
		nop
		cbi	PORTD,LCD_E				; LCD_EをLに設定
		ret

;---------------------------------------
;	LCDへデータ出力
;---------------------------------------
LCD_OUT:
		mov	lcd_dat,tp_main
		rcall LCD_WAIT
		sbi	PORTD,LCD_RS			; LCD_RSをHに設定(データ出力)
		cbi	PORTD,LCD_RW			; LCD_RWをLに設定
		out	PORTB,lcd_dat			; データを設定する
		clr	lcd_sta					; ポートＢを出力に設定
		com	lcd_sta
		out	DDRB,lcd_sta
		out	PORTB,lcd_dat			; データを設定する
		sbi	PORTD,LCD_E				; LCD_EをHに設定
		nop
		cbi	PORTD,LCD_E				; LCD_EをLに設定
		ret

;---------------------------------------
;	LCDからデータ入力
;---------------------------------------
LCD_IN:
		rcall LCD_WAIT
		clr	lcd_sta					; ポートＢを入力に設定
		out	DDRB,lcd_sta
		sbi	PORTD,LCD_RS			; LCD_RSをHに設定(データ入力)
		sbi	PORTD,LCD_RW			; LCD_RWをHに設定
		sbi	PORTD,LCD_E				; LCD_EをHに設定
		nop
		in	tp_main,PINB			; データを読取る
		mov lcd_dat,tp_main
		cbi	PORTD,LCD_E				; LCD_EをLに設定
		ret

;---------------------------------------
;	LCD初期化
;---------------------------------------
LCD_INIT:
;	rcall WAIT15ms
	rcall WAIT25ms
	rcall WAIT25ms

	ldi	tp_main,0x30 ; // set 8bits mode and 1/16duty 5x7char mode
	mov	lcd_dat,tp_main
	rcall LCD_CMD_NOWAIT

;	rcall WAIT5ms
	rcall WAIT15ms

	ldi	tp_main,0x30 ; // set 8bits mode and 1/16duty 5x7char mode
	mov	lcd_dat,tp_main
	rcall LCD_CMD_NOWAIT

;	rcall WAIT100us
	rcall WAIT1ms

	ldi	tp_main,0x30 ; // set 8bits mode and 1/16duty 5x7char mode
	mov	lcd_dat,tp_main
	rcall LCD_CMD_NOWAIT

;	rcall WAIT100us
	rcall WAIT1ms

	ldi	tp_main,0x38 ; // set 8bits mode and 1/16duty 5x7char mode
	mov	lcd_dat,tp_main
	rcall LCD_CMD_NOWAIT

	ldi	tp_main,0x08 ; // disable display
	rcall LCD_CMD

;	rcall WAIT5ms
	rcall WAIT15ms


LCD_CLEAR:
	ldi	tp_main,0x01 ; // clear display memory
	rcall LCD_CMD

	ldi	tp_main,0x06 ; // set entry mode
	rcall LCD_CMD

	ldi	tp_main,0x02 ; // set cursor to home position
	rcall LCD_CMD

	ldi	tp_main,0x0c ; // display enable
	rcall LCD_CMD

;	rcall WAIT5ms
	rcall WAIT15ms

	ldi	tp_main,0x0c ; // display enable
	rcall LCD_CMD

;	ldi	tp_main,0x1f ; // set cursor to display
;	rcall LCD_CMD

	ret

WAIT25ms:
	ldi	tp_main,250
	mov	lcd_cnt,tp_main
	rjmp WAIT_loop1

WAIT15ms:
	ldi	tp_main,150
	mov	lcd_cnt,tp_main
	rjmp WAIT_loop1

WAIT5ms:
	ldi	tp_main,50
	mov	lcd_cnt,tp_main
	rjmp WAIT_loop1

WAIT1ms:
	ldi	tp_main,10
	mov	lcd_cnt,tp_main
	rjmp WAIT_loop1

WAIT100us:
	ldi	tp_main,1
	mov	lcd_cnt,tp_main
WAIT_loop1:
	ldi tp_main,200
WAIT_loop2:
	nop					; 1
	dec tp_main			; 1
	brne WAIT_loop2		; 2/1
	dec lcd_cnt			; 1
	brne WAIT_loop1		; 2/1
	ret

WAIT:		;wait 25us
	clr lcd_cnt
	com lcd_cnt
	clc
	ror lcd_cnt
	clc
	ror lcd_cnt
WAITloop:
	dec lcd_cnt
	brne WAITloop
	ret
