;
; X68000のキーボードを
; AT互換機のPS/2ポートにつなぐのです
; キー入力に関してはほぼ完成版。ホストコマンドをたびたび取りこぼす
;                                      2001/11/28 作成
;                                      2001/11/30 一応完成
;
; 秋月アセンブラ(PA.EXE)用



;              ----__----
;       RA2 1-|*         |-18 RA1
;       RA3 2-|          |-17 RA0
; RA4 TOCKI 3-|          |-16 OSC1 CLKIN
;     /MCLR 4-|          |-15 OSC2 CLKOUT
;       Vss 5-| PIC16C84 |-14 Vdd
;   RB0 INT 6-|          |-13 RB7
;       RB1 7-|          |-12 RB6
;       RB2 8-|          |-11 RB5
;       RB3 9-|          |-10 RB4
;              ----------

;	I/Oポートの割り当て
; PORT A
X68_RxD		equ		0	; RA0 - X68 KY RxD
X68_TxD		equ		1	; RA1 - X68 KY TxD
X68_READY	equ		2	; RA2 - X68 KY READY
;						  RA3 - 未使用
;						  RA4 - 未使用

; PORT B
PS2_CLKOUT	equ		0	; RB0 - PS/2 CLK
PS2_CLKIN	equ		1	; RB1 - PS/2 CLK
PS2_DATAOUT	equ		2	; RB2 - PS/2 DATA
PS2_DATAIN	equ		3	; RB3 - PS/2 DATA
;						; RB4 - 未使用
;						; RB5 - 未使用
;						; RB6 - 未使用
;						; RB7 - 未使用
; ----------------------------------------------------------------------------
;
;  回路図
;
;                        PS/2コネクタ
;
; +5V   -----------+---- +5V
;                  |
;                  = C1
;                  |-
; GND   -----------+---- GND
;
;
;     +--------+
;     |     Vdd|----+-- +5V
;     |        |    |
;     |PIC16C84|    = C2
;     |        |    |
;     |     Vss|----+-- GND
;     |        |
;     |        |       C3
;     |    OSC1|----+--||-- GND
;     |        |    |
;     |        |    = X'tal1
;     |        |    |
;     |    OSC2|----+--||-- GND
;     |        |       C3
;     |        |
;     |   /MCLR|---R4-- +5V
;     +--------+
;
;
;
;
;                 +5V
;                  |
;                  R1
;                  |
; RB1 CLKIN   --R2-+---- PS/2 CLK
;                  |
; RB0 CLKOUT  --R3-K TR1
;                  |
;                 GND
;
;                 +5V
;                  |
;                  R1
;                  |
; RB3 DATAIN  --R2-+---- PS/2 CLK
;                  |
; RB2 DATAOUT --R3-K TR1
;                  |
;                 GND
; R1    4.7k
; R2    330
; R3    12k
; R4    1k
; C1    47u
; C2    0.1u
; C3    22p
; TR1   2SC1815
;
;
;                      X68キーボードコネクタ
;
; +5V       -------------- VCC2 1pin
; GND       -------------- GND  7pin
;
; RA0 RxD   -------------- TxD 3pin
;
; RA1 TxD   -------------- RxD 4pin
;
; RA2 READY -------------- T0  5pin
;



; ----------------------------------------------------------------------------

	.16c84				; デバイスの設定（省略できません）
	.osc	HS			; 発振タイプの設定
	.wdt	off			; ウォッチドックタイマの有効・無効の設定
	.pwrt	on			; パワーアップタイマの有効・無効の設定
	.protect	off		; プロテクトの設定

; -----------------------------------------------------------------------------

;	システムレジスタにラベル付け

TMR0		equ		01h		; タイマ(BANK0)
PCL			equ		02h		; プログラムカウンタの下位8ビット(BANK0)

STATUS		equ		03h		; ステータスレジスタ(BANK0)
C			equ		0		; STATUS,C   キャリーフラグ
DC			equ		1		; STATUS,DC  DCフラグ
Z			equ		2		; STATUS,Z   ゼロフラグ
PD			equ		3		; STATUS,PD  パワーダウンフラグ
TO			equ		4		; STATUS,TO  タイムアウトフラグ
RP0			equ		5		; STATUS,RP0 RAMのバンク切り替え

PORTA		equ		05h		; I/OポートA(BANK0)
PORTB		equ		06h		; I/OポートB(BANK0)

PCLATH		equ		0ah		; プログラムカウンタの上位

INTCON		equ		0bh		; 割り込み制御レジスタ(BANK0)
RBIF		equ		0		; RB<4:7>ポートチェンジ割り込みフラグ
INTF		equ		1		; INT(RA4)割り込みフラグ
T0IF		equ		2		; TMR0オーバーフロー割り込みフラグ
RBIE		equ		3		; RBIF割り込み許可
INTE		equ		4		; INTF割り込み許可
T0IE		equ		5		; TMR0割り込み許可
EEIE		equ		6		; データEEPROM書き込み終了割り込み許可
GIE			equ		7		; 全体割り込み許可

OPTION		equ		01h		; オプションレジスタ(BANK1)
RBPU		equ		7		; OPTION,RBPU ポートBのプルアップ 0:行う 1:行わない

TRISA		equ		05h		; ポートA出力/入力設定 0:出力 1:入力(BANK1)
TRISB		equ		06h		; ポートB出力/入力設定 0:出力 1:入力(BANK1)

;	定数のセット
;	PICの動作クロックに応じて書き換えてください

CONST_WAIT_MS	equ		200	; ms 単位のウェイト用定数
							; CONST_WAIT_MS = (動作クロック[MHz]/4)*100

CONST_WAIT_US	equ		6	; 10μs 単位のウェイト用定数
							; CONST_WAIT_US = 10/(1/動作クロック[MHz]*4*3)

CONST_COMSPEED	equ		155	; シリアル通信用割り込み間隔
							; CONST_COMSPEED = 255-(動作クロック[Hz]/bps/32)+4(くらい)

; -----------------------------------------------------------------------------

;	変数を宣言
		org		0ch
keycode				ds		1   ; キーコードの一時保存
prtsc				ds		1   ; Print Screen キーのリピート処理用カウンタ
status_led			ds		1	; ステータスLED状態保持
SCRLK				equ		1
NUMLK				equ		2
CAPSLK				equ		3
lastdata			ds		1	; PS/2ポートに前回送出したデータ
wait_count1			ds		1	; ウェイトルーチンで使うカウンタ
wait_count2			ds		1	; ウェイトルーチンで使うカウンタ
int_w				ds		1	; 割り込み処理でのレジスタ退避用
int_status			ds		1	; 割り込み処理でのレジスタ退避用
x68txd				ds		1	; 送信バッファ
x68rxd				ds		1	; 受信バッファ
int_x68rmode		ds		1	; 受信処理内部状態
int_x68rcount		ds		1	; 受信割り込みカウンタ
int_x68tmode		ds		1	; 送信処理内部状態
int_x68tcount		ds		1	; 送信割り込みカウンタ
ps2txd				ds		1	; 送信バッファ
ps2rxd				ds		1	; 受信バッファ
ps2parity			ds		1	; パリティ計算用
ps2count			ds		1	; カウンタ
com_status			ds		1	; 通信ステータスフラグ
x68receiving		equ		0	; com_status,x68receiving		受信中
x68transmitrq		equ		1	; com_status,x68transmitrq		送信要求
x68rxdvalid			equ		2	; com_status,x68rxdvalid		受信データ有効
ps2rxdvalid			equ		3	; com_status,ps2rxdvalid	受信データ有効
ps2rxdfound			equ		4	; com_status,ps2rxdfound	データを見つけた
ps2break			equ		5	; com_status,ps2break		通信中断

; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------

;	リセットベクタ

		org		000h

		goto	start





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------

;	割り込みベクタ

		org		004h



interrupt

		movwf	int_w					; wレジスタを退避
		movf	STATUS,0
		movwf	int_status				; ステータスレジスタを退避
		movlw	CONST_COMSPEED
		movwf	TMR0					; TMR0プリセット





; -----------------------------------------------------------------------------

; x68キーボードとの通信処理
; 2400bps,8ビット,ストップビット1,パリティなし

; 受信すると x68rxd にデータが入り
; キーレディ信号 PORTA,X68_READY を 0
; データ有効フラグ com_status,x68rxdvalid を 1 にセットする

; 受信処理中は 受信処理中フラグ com_status,x68receiving が 1 になる

; プログラムで受信データを引き受けたら、
; キーレディ信号 PORTA,X68_READY を 1
; にすることで、次のデータの受信を行う
; (PORTA,X68_READY を 1 にしなければ、キーボードが次のデータを送信してこない)



;	受信処理

		movf	int_x68rmode,0			; 内部状態に応じて分岐
		addwf	PCL,1					; PCL=PCL+int_x68rmode
		goto	int_x68rmode0			; スタートビット検出処理
		goto	int_x68rmode1			; 本当にスタートビット？
		goto	int_x68rmode2_9			; データの受信1
		goto	int_x68rmode2_9			; データの受信2
		goto	int_x68rmode2_9			; データの受信3
		goto	int_x68rmode2_9			; データの受信4
		goto	int_x68rmode2_9			; データの受信5
		goto	int_x68rmode2_9			; データの受信6
		goto	int_x68rmode2_9			; データの受信7
		goto	int_x68rmode2_9			; データの受信8
		goto	int_x68rmode10			; 受信処理終わり


int_x68rmode0
		btfsc	PORTA,X68_RxD
		goto	int_x68rbreak			; スタートビットを確認せず 中断

;	X68_RxDが0 スタートビットがきた
		bsf		com_status,x68receiving	; 受信中フラグセット
		movlw	2
		movwf	int_x68rcount			; int_x68rcount=2
		incf	int_x68rmode,1			; int_x68rmode=int_x68rmode+1=1
		goto	int_x68rend


int_x68rmode1
		btfsc	PORTA,X68_RxD
		goto	int_x68rbreak			; スタートビットを確認せず 中断

;	スタートビットを確認した
		decf	int_x68rcount,1			; int_x68rcount=int_x68rcount-1
		btfss	STATUS,Z
		goto	int_x68rend				; int_x68rcountがゼロでなければ終了

;	3回続けてスタートビットを確認したので受信処理に入る
		movlw	4
		movwf	int_x68rcount			; int_x68rcount=4
		incf	int_x68rmode,1			; int_x68rmode=int_x68rmode+1=2
		bcf		com_status,x68rxdvalid	; 受信データ有効フラグクリア
		clrf	x68rxd					; 受信バッファクリア
		goto	int_x68rend


int_x68rmode2_9
		decf	int_x68rcount,1			; int_x68rcount=int_x68rcount-1
		btfss	STATUS,Z
		goto	int_x68rend				; int_x68rcountがゼロでなければ終了
;	実際の受信 (割り込みが4回発生するごとに1回実行される)
		rrf		x68rxd,1				; 受信バッファを右シフト
		btfsc	PORTA,X68_RxD
		bsf		x68rxd,7				; RxDが1なら受信バッファのbit7をセット
		movlw	4
		movwf	int_x68rcount			; int_x68rcount=4
		incf	int_x68rmode,1			; int_x68rmode=int_x68rmode+1
		goto	int_x68rend


int_x68rmode10
		decf	int_x68rcount,1			; int_x68rcount=int_x68rcount-1
		btfss	STATUS,Z
		goto	int_x68rend				; int_x68rcountがゼロでなければ終了

		btfss	PORTA,X68_RxD
		goto	int_x68rbreak			; ストップビットを確認せず 中断

;	受信正常終了
		bcf		PORTA,X68_READY			; 
		bsf		com_status,x68rxdvalid	; 受信データ有効フラグセット

;	受信異常終了
int_x68rbreak
		bcf		com_status,x68receiving	; 受信中処理フラグクリア
		clrf	int_x68rmode
		clrf	int_x68rcount

int_x68rend



; -----------------------------------------------------------------------------

;	送信処理
; x68txd にデータをセットして
; 送信要求フラグ com_status,x68transmitrq を 1 にすると
; 送信が開始される

; 送信が終了すると com_status,x68transmitrq が 0 になる

; 送信を開始する前に com_status,x68transmitrq が 0 であることを確認する必要あり



		movf	int_x68tmode,0			; 内部状態に応じて分岐
		addwf	PCL,1					; PCL=PCL+int_x68tmode
		goto	int_x68tmode0			; スタートビットを送信
		goto	int_x68tmode1_8			; 1ビット目を送信
		goto	int_x68tmode1_8			; 2ビット目を送信
		goto	int_x68tmode1_8			; 3ビット目を送信
		goto	int_x68tmode1_8			; 4ビット目を送信
		goto	int_x68tmode1_8			; 5ビット目を送信
		goto	int_x68tmode1_8			; 6ビット目を送信
		goto	int_x68tmode1_8			; 7ビット目を送信
		goto	int_x68tmode1_8			; 8ビット目を送信
		goto	int_x68tmode9			; ストップビットを送信
		goto	int_x68tmode10			; 送信おわり


int_x68tmode0
		btfss	com_status,x68transmitrq
		goto	int_x68tend				; 送信要求フラグが0なら終了

		movlw	4
		movwf	int_x68tcount			; int_x68tcount=4
		incf	int_x68tmode,1			; int_x68tmode=int_x68tmode+1=1
		bcf		PORTA,X68_TxD			; スタートビット(0)を送信
		goto	int_x68tend


int_x68tmode1_8
		decf	int_x68tcount,1			; int_x68tcount=int_x68tcount-1
		btfss	STATUS,Z
		goto	int_x68tend				; int_x68rcountがゼロでなければ終了

;	受信バッファの下位ビットから順に送信する
		btfsc	x68txd,0
		goto	intx68tmode1_8_1
intx68tmode1_8_0
		bcf		PORTA,X68_TxD			;送信バッファのbit0が0なら0を送信
		goto	intx68tmode1_8end
intx68tmode1_8_1
		bsf		PORTA,X68_TxD			;送信バッファのbit0が1なら1を送信

intx68tmode1_8end
		rrf		x68txd,1				;送信バッファを右シフト
		movlw	4
		movwf	int_x68tcount			; int_x68tcount=4
		incf	int_x68tmode,1			; int_x68tmode=int_x68tmode+1
		goto	int_x68tend


int_x68tmode9
		decf	int_x68tcount,1			; int_x68tcount=int_x68tcount-1
		btfss	STATUS,Z
		goto	int_x68tend				; int_x68rcountがゼロでなければ終了

		bsf		PORTA,X68_TxD			; ストップビット(1)を送信
		movlw	4
		movwf	int_x68tcount			; int_x68tcount=4
		incf	int_x68tmode,1			; int_x68tmode=int_x68tmode+1
		goto	int_x68tend


int_x68tmode10
		decf	int_x68tcount,1			; int_x68tcount=int_x68tcount-1
		btfss	STATUS,Z
		goto	int_x68tend				; int_x68rcountがゼロでなければ終了

		clrf	int_x68tcount
		clrf	int_x68tmode
		bcf		com_status,x68transmitrq	; 送信が終わりましたの印

int_x68tend



; -----------------------------------------------------------------------------

;	割り込み処理の終了

int_return
		bcf		INTCON,T0IF				; TMR0オーバーフロー割り込みフラグをクリア
		movf	int_status,0
		movwf	STATUS					; ステータスレジスタを元に戻す
		movf	int_w,0					; wレジスタを元に戻す

;		goto	interrupt

		retfie							; 割り込みを許可してリターン





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------

;	初期設定いろいろ

start

		bsf		STATUS,RP0	; bank1

		movlw	11000000b			; プリスケーラを使用、分周比1:2
		;		|||||||+----- PS0		-+
		;		||||||+------ PS1		 +- プリスケーラ分周比
		;		|||||+------- PS2		-+
		;		||||+-------- PSA		プリスケーラ設定		0:TMR0	1:WDT
		;		|||+--------- RTE		TMR0信号のエッジ		0:↑	1:↓
		;		||+---------- RTS		TMR0信号のソース		0:内部	1:外部
		;		|+----------- INTEDG	INT 割り込みのエッジ	0:↓	1:↑
		;		+------------ /RBPU		ポートBのプルアップ		0:行う	1:行わない
		movwf	OPTION

;	I/Oポートの設定
;	ポートA
		movlw	11100001b
		;		   ||||+----- X68 KY RxD	in
		;		   |||+------ X68 KY TxD	out
		;		   ||+------- X68_READY		out
		;		   |+-------- RA3 - 未使用	in
		;		   +--------- RA4 - 未使用	in
		movwf	TRISA		; 設定レジスタに書き込み

;	ポートB
		movlw	00001010b
		;		|||||||+----- PS/2 CLKOUT	out
		;		||||||+------ PS/2 CLKIN	in
		;		|||||+------- PS/2 DATAOUT	out
		;		||||+-------- PS/2 DATAIN	in
		;		|||+--------- RB4 - 未使用	out
		;		||+---------- RB5 - 未使用	out
		;		|+----------- RB6 - 未使用	out
		;		+------------ RB7 - 未使用	out
		movwf	TRISB		; 設定レジスタに書き込み

		bcf		STATUS,RP0	; bank0

;	通信ポートの初期化

		bcf		PORTA,X68_READY
;		bsf		PORTA,X68_RxD
		bsf		PORTA,X68_TxD
		bcf		PORTB,PS2_CLKOUT
;		bsf		PORTB,PS2_CLKIN
		bcf		PORTB,PS2_DATAOUT
;		bsf		PORTB,PS2_DATAIN

;	変数の初期化

		clrf	int_x68rmode
		clrf	int_x68rcount
		clrf	int_x68tcount
		clrf	int_x68tmode
		clrf	com_status


;	割り込み許可

		movlw	10100000b
		movwf	INTCON			; TMR0割り込み許可





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;	PS/2 キーボードとしての初期化処理

ps2init
		movlw	255
		call	wait

ps2init1
		btfsc	com_status,x68transmitrq	; キーボードへ送信処理中なら
		goto	ps2init1					; 終わるまで待つ
		movlw	10000000b
		movwf	x68txd
		bsf		com_status,x68transmitrq	; LED全点灯

		movlw	250
		call	wait
		movlw	250
		call	wait

		btfss	PORTB,PS2_DATAIN
		goto	main			; DATA がLなら受信処理

		movlw	0aah
		call	ps2transmit		; セルフテストOK送信
;		btfsc	com_status,ps2break
;		goto	ps2init			; 送信が中断されたらもう一回

ps2init5
		btfsc	com_status,x68transmitrq	; キーボードへ送信処理中なら
		goto	ps2init5					; 終わるまで待つ
		movlw	11111111b
		movwf	x68txd
		bsf		com_status,x68transmitrq	; LED全消灯





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
main
;	X68キーボードデータ送出許可
		bsf		PORTA,X68_READY

;	ホストコマンドの処理
hostcommand
		call	ps2receive
		btfss	com_status,ps2rxdvalid
		goto	main_keyin				; 受信しなければキー入力処理

		movlw	100
		call	waitus					; 重要


; -----------------------------------------------------------------------------
set_status_led
		movlw	0edh
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	echo
		movlw	0fah
		call	ps2transmit					; ACK

		movlw	100
		call	waitus

set_status_led_1
		call	ps2receive
		btfss	com_status,ps2rxdvalid
		goto	set_status_led_1

		movlw	11111111b
		movwf	status_led
		btfsc	ps2rxd,0
		bcf		status_led,SCRLK
		btfsc	ps2rxd,1
		bcf		status_led,NUMLK
		btfsc	ps2rxd,2
		bcf		status_led,CAPSLK

set_status_led_2
		btfsc	com_status,x68transmitrq	; キーボードへ送信処理中なら
		goto	set_status_led_2			; 終わるまで待つ
		movf	status_led,0
		movwf	x68txd
		bsf		com_status,x68transmitrq	; LEDの状態をキーボードへ送信

		movlw	50
		call	waitus

		movlw	0fah
		call	ps2transmit					; ACK
		goto	main_keyin

; -----------------------------------------------------------------------------
echo
		movlw	0eeh
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	set_scancode
echo_1
		movlw	0eeh
		call	ps2transmit
		goto	main_keyin

; -----------------------------------------------------------------------------
set_scancode
		movlw	0f0h
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	set_repeatrate
		movlw	0fah
		call	ps2transmit					; ACK

		movlw	100
		call	waitus

set_scancode1
		call	ps2receive
		btfss	com_status,ps2rxdvalid
		goto	set_scancode1

		movlw	100
		call	waitus

		movlw	002h
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	set_scancode2

		movlw	0fah
		call	ps2transmit					; ACK
		goto	main_keyin

set_scancode2
		movlw	002h						; スキャンコードは
		call	ps2transmit					; 02のみ対応なので02と返す
		goto	main_keyin

; -----------------------------------------------------------------------------
set_repeatrate
		movlw	0f3h
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	keyboard_enable
		movlw	0fah
		call	ps2transmit					; ACK

		movlw	100
		call	waitus

set_repeatrate1
		call	ps2receive
		btfss	com_status,ps2rxdvalid
		goto	set_repeatrate1

;***************************************

		movlw	100
		call	waitus

		movlw	0fah
		call	ps2transmit					; ACK
		goto	main_keyin

; -----------------------------------------------------------------------------
keyboard_enable
		movlw	0f4h
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	keyboard_disable
		movlw	0fah
		call	ps2transmit					; ACK
keyboard_enable1
;***************************************
		goto	main_keyin

; -----------------------------------------------------------------------------
keyboard_disable
		movlw	0f5h
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	resend
		movlw	0fah
		call	ps2transmit					; ACK
keyboard_disable1
;***************************************
		goto	main_keyin

; -----------------------------------------------------------------------------
resend
		movlw	0feh
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	reset
resend1
		movf	lastdata,0
		call	ps2transmit					; resend
		goto	main_keyin

; -----------------------------------------------------------------------------
reset
		movlw	0ffh
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	unknown_command
		movlw	0fah
		call	ps2transmit					; ACK
reset1
		goto	ps2init						; リセット

; -----------------------------------------------------------------------------
unknown_command
;	解らないコマンドがきたらどうしよう？
;	とりあえず ACK でも返しとけ！
		movlw	0fah
		call	ps2transmit					; ACK



; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
main_keyin
		btfsc	PORTA,X68_READY	; キーボードから
		goto	main			; データを受信しなければ何もしない
main_keyin1
		btfsc	com_status,x68transmitrq	; キーボードへ送信処理中なら
		goto	main_keyin1					; 終わるまで待つ

		bcf		INTCON,GIE		; 割り込み禁止

								; 割り込み処理内でテーブル処理を
								; 行っているので、
								; PCLATH を書き換えている間に割り込みが入ると
								; まずいので、割り込み禁止にする

		movlw	003h
		movwf	PCLATH

		movlw	01111111b
		andwf	x68rxd,0
		call	table
		movwf	keycode

; -----------------------------------------------------------------------------
		movlw	000h
		movwf	PCLATH

		movf	keycode,1
		btfsc	STATUS,Z		; テーブルから00hが帰ってきた（キー未割り当て）
		goto	main_keyin_end	; なら、なにもしない

; -----------------------------------------------------------------------------
;	[Print Screen] キーの処理
printscreen
		movlw	0feh
		subwf	keycode,0
		btfss	STATUS,Z
		goto	pause

		btfsc	x68rxd,7
		goto	printscreen_release

;	押された
printscreen_press
		movf	prtsc,1
		btfsc	STATUS,Z				; １回目のみ E0 12 E0 7C を送信
		goto	printscreen_press2		; ２回目から E0 7C を送信
		decf	prtsc,1

		movlw	0e0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	012h
		call	ps2transmit
		movlw	50
		call	waitus

printscreen_press2
		movlw	0e0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	07ch
		call	ps2transmit
		goto	main_keyin_end

;	離された
printscreen_release
		movlw	0e0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	0f0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	07ch
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	0e0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	0f0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	012h
		call	ps2transmit
		goto	main_keyin_end

; -----------------------------------------------------------------------------
;	[Pause] キーの処理
pause
		movlw	0ffh
		subwf	keycode,0
		btfss	STATUS,Z
		goto	main_keyin2

		btfsc	x68rxd,7
		goto	pause_release

;	押された
pause_press
		movlw	0e1h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	014h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	077h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	0e1h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	0f0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	014h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	0f0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	077h
		call	ps2transmit
		goto	main_keyin_end

;	離された
pause_release
		;	なにもしない
		goto	main_keyin_end

; -----------------------------------------------------------------------------
;	そのほか普通のキーの処理
main_keyin2
		btfsc	keycode,7		; 通常キーか拡張キーかを bit7 で判断
		goto	exkey

;	通常キー
normaliy
		btfsc	x68rxd,7
		goto	release
;	押された
press
		movf	keycode,0
		call	ps2transmit
		goto	main_keyin_end
;	離された
release
		movlw	0f0h
		call	ps2transmit
		movlw	50
		call	waitus

		movf	keycode,0
		call	ps2transmit
		goto	main_keyin_end

; -----------------------------------------------------------------------------
;	拡張キー
exkey
		movlw	01111111b
		andwf	keycode,1

		btfsc	x68rxd,7
		goto	exkey_release
;	押された
		movlw	0e0h
		call	ps2transmit
		movlw	50
		call	waitus

		movf	keycode,0
		call	ps2transmit
		goto	main_keyin_end

;	離された
exkey_release
		movlw	0e0h
		call	ps2transmit
		movlw	50
		call	waitus

		movlw	0f0h
		call	ps2transmit
		movlw	50
		call	waitus

		movf	keycode,0
		call	ps2transmit
		goto	main_keyin_end

main_keyin_end
		bsf		INTCON,GIE		; 割り込み許可
		goto	main





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;	PS/2
;	受信処理
;	受信すべきデータがを見つけたら com_status,ps2rxdfound をセット
;	受信がホストに中断されると com_status,ps2break フラグを1にして戻ります
;	正常に受信すると com_status,ps2rxdvalid セットし
;	ps2rxd に受信データをいれて帰ってくる

;	エラー(com_status,ps2rxdvalid が 0)の場合
;	com_status,ps2rxdfound が 0 なら受信すべきデータが無かった。
;	1 なら 受信動作を行ったが、パリティエラーかフレーミングエラーが発生した


ps2receive
		bcf		com_status,ps2rxdvalid	; データ有効フラグをクリア
		bcf		com_status,ps2rxdfound
		bcf		com_status,ps2break

;	スタートビットの取り込み
ps2receive_startbit
		btfsc	PORTB,PS2_DATAIN	; スタートビットが見つからなければ
		return						; 終了
		bsf		com_status,ps2rxdfound
		bsf		com_status,ps2break
		movlw	1
		movwf	ps2parity			;パリティ計算用変数を初期化
		movlw	8
		movwf	ps2count			; count=8

;	8ビット分データを取り込む
ps2receive_data
		call	ps2clkr				; クロックを出す
		rrf		ps2rxd,1
		btfsc	PORTB,PS2_DATAIN	; データを取り込む
		goto	ps2receive_b1
ps2receive_b0
		bcf		ps2rxd,7
		goto	ps2receive_data_end
ps2receive_b1
		bsf		ps2rxd,7
		incf	ps2parity,1			; parity+1
ps2receive_data_end
		btfss	PORTB,PS2_CLKIN		; ホストがCLKをLにしてきたら
		return						; 処理中断
		decfsz	ps2count,1	; count-1
		goto	ps2receive_data

;	パリティビットの取り込み
ps2receive_parity
		call	ps2clkr				; クロックを出す
		btfss	PORTB,PS2_CLKIN		; ホストがCLKをLにしてきたら
		return						; 処理中断
		movlw	00000001b
		andwf	ps2parity,1			; ps2parity のbit0のみ取り出し
		btfsc	PORTB,PS2_DATAIN
		goto	ps2receive_parity1
ps2receive_parity0
		movf	ps2parity,1
		btfss	STATUS,Z
		goto	ps2receive_perror	; パリティエラー
		goto	ps2receive_parity_end
ps2receive_parity1
		movf	ps2parity,1
		btfsc	STATUS,Z
		goto	ps2receive_perror	; パリティエラー
ps2receive_parity_end

;	ストップビットの取り込み
ps2receive_stopbit
		call	ps2clkr				; クロックを出す
		bcf		com_status,ps2break
		btfss	PORTB,PS2_DATAIN	; ストップビットと思われるところが
		goto	ps2receive_end		; 0だったらエラー
;	受信終了
		bsf		com_status,ps2rxdvalid	; データ有効フラグをセット
		bsf		PORTB,PS2_DATAOUT	; データラインをLにする
		call	ps2clkr				; クロックを出す
ps2receive_perror
		bcf		PORTB,PS2_DATAOUT	; データラインをHにする
		call	ps2clkr				; クロックを出す

ps2receive_end
		btfsc	PORTB,PS2_DATAIN
		goto	ps2receive_return	; データラインがHなら終了処理
		call	ps2clkr				; データラインがLならHになるまで
		goto	ps2receive_end		; クロックを出す

ps2receive_return
		btfsc	com_status,ps2rxdvalid
		return						; 正常受信なら終了

ps2receive_resend
;	受信エラーの為、再送要求
		btfss	PORTB,PS2_CLKIN		; CLKがLならHになるまで待つ
		goto	ps2receive_resend
ps2receive_resend1
		movlw	50
		call	waitus

		btfss	PORTB,PS2_DATAIN
		goto	ps2receive			; DATA がLなら再度受信処理
		movlw	0feh
		call	ps2transmit			; Resend コマンド発行
		btfsc	com_status,ps2break
		goto	ps2receive_resend1	; 送信が中断されたらもう一回

		movlw	50
		call	waitus
		return





;-----------------------------------------------------------------------------
;	送信処理
;	wレジスタにデータを入れてコールすると
;	PS/2キーボードへ向けて送信する
;	送信がホストに中断されると com_status,ps2break フラグを1にして戻ります

ps2transmit
		movwf	ps2txd
		movwf	lastdata
		bsf		com_status,ps2break
		movlw	1
		movwf	ps2parity	;パリティ計算用変数を初期化
		movlw	8
		movwf	ps2count	; count=8

		btfss	PORTB,PS2_CLKIN		; CLKがLなら
		goto	ps2transmit			; Hになるまで待つ
		btfss	PORTB,PS2_DATAIN	; DATAがLなら、なにもしない
		return						; 戻り先で受信処理を行って欲しい

ps2transmit_startbit
		bsf		PORTB,PS2_DATAOUT	; スタートビットをセット
		call	ps2clk				; クロックを出す
		btfss	PORTB,PS2_CLKIN		; ホストがCLKをLにしてきたら
		goto	ps2transmit_break	; 処理中断

ps2transmit_data
		btfsc	ps2txd,0			; データをセット
		goto	ps2transmit_data1
ps2transmit_data0
		bsf		PORTB,PS2_DATAOUT
		goto	ps2transmit_wait1
ps2transmit_data1
		bcf		PORTB,PS2_DATAOUT
		incf	ps2parity,1			; parity+1
ps2transmit_wait1
		call	ps2clk				; クロックを出す
		btfss	PORTB,PS2_CLKIN		; ホストがCLKをLにしてきたら
		goto	ps2transmit_break	; 処理中断
		rrf		ps2txd,1			; 右シフト
		decfsz	ps2count,1	; count-1
		goto	ps2transmit_data

ps2transmit_parity
		btfsc	ps2parity,0			; パリティをセット
		goto	ps2transmit_parity1
ps2transmit_parity0
		bsf		PORTB,PS2_DATAOUT
		goto	ps2transmit_wait2
ps2transmit_parity1
		bcf		PORTB,PS2_DATAOUT
ps2transmit_wait2
		call	ps2clk				; クロックを出す
		btfss	PORTB,PS2_CLKIN		; ホストがCLKをLにしてきたら
		goto	ps2transmit_break	; 処理中断

ps2transmit_stopbit
		bcf		PORTB,PS2_DATAOUT	; ストップビットをセット
		call	ps2clk				; クロックを出す

;	送信おしまい
ps2transmit_end
		bcf		com_status,ps2break
ps2transmit_break
		bcf		PORTB,PS2_DATAOUT
		return




ps2clk
		movlw	2
		call	waitus
		bsf		PORTB,PS2_CLKOUT
		movlw	1
		call	waitus
		bcf		PORTB,PS2_CLKOUT
		movlw	1
		call	waitus
		return

ps2clkr
		movlw	2
		call	waitus
		bsf		PORTB,PS2_CLKOUT
		movlw	1
		call	waitus
		bcf		PORTB,PS2_CLKOUT
		movlw	1
		call	waitus
		return





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------

;	wレジスタの値に応じて ms 単位のウェイトを入れる

;	使用変数
;		wait_count1,wait_count2

;	例、約2ms待つ
;	1:	movlw	2
;	2:	call	wait

;	メモ
;	使用クロックに応じて、定数 CONST_WAIT_MS を定義してください

;	CONST_WAIT_MS = (動作クロック[MHz]/4)*100

;	例、8Mhz時
;	CONST_WAIT_MS	equ	200

wait
		movwf	wait_count1		; wait_count1=w
wait_loop1
			movlw	CONST_WAIT_MS
			movwf	wait_count2		; wait_count2=CONST_WAIT_MS
wait_loop2
				nop
				nop
				nop
				nop
				nop
				nop
				nop
				decfsz	wait_count2,1	; wait_count2=wait_count2-1
				goto	wait_loop2		; if wait_count2!=0 goto wait_loop2
			decfsz	wait_count1,1	; wait_count1=wait_count1-1
			goto	wait_loop1		; if wait_count1!=0 goto wait_loop1
		return					; else return





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------

;	wレジスタの値に応じて 10マイクロ秒 単位のウェイトを入れる

;	使用変数
;		wait_count1,wait_count2

;	例、約20μs待つ
;	1:	movlw	2
;	2:	call	waitus

;	メモ
;	使用クロックに応じて、定数 CONST_WAIT_US を定義してください

;	CONST_WAIT_US = 10/(1/動作クロック[MHz]*4*3)

;	例、8Mhz時
;	CONST_WAIT_US	equ	7

waitus
		movwf	wait_count1		; wait_count1=w
waitus_loop1
			movlw	CONST_WAIT_US
			movwf	wait_count2		; wait_count2=CONST_WAIT_US
waitus_loop2
				decfsz	wait_count2,1	; wait_count2=wait_count2-1
				goto	waitus_loop2		; if wait_count2!=0 goto waitus_loop2
			decfsz	wait_count1,1	; wait_count1=wait_count1-1
			goto	waitus_loop1		; if wait_count1!=0 goto waitus_loop1
		return					; else return





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;	キーコード変換テーブル

;	キーの割り当てを変えたい場合は、このテーブルを書き換えてね


		org		300h
table
		addwf	PCL,1
		retlw	000h		; 00h
		retlw	076h		; 01h  [ESC]
		retlw	016h		; 02h  [1]
		retlw	01Eh		; 03h  [2]
		retlw	026h		; 04h  [3]
		retlw	025h		; 05h  [4]
		retlw	02Eh		; 06h  [5]
		retlw	036h		; 07h  [6]
		retlw	03Dh		; 08h  [7]
		retlw	03Eh		; 09h  [8]
		retlw	046h		; 0Ah  [9]
		retlw	045h		; 0Bh  [0]
		retlw	04Eh		; 0Ch  [-]
		retlw	055h		; 0Dh  [^]
		retlw	06Ah		; 0Eh  [\]
		retlw	066h		; 0Fh  [BS]
		retlw	00Dh		; 10h  [TAB]
		retlw	015h		; 11h  [Q]
		retlw	01Dh		; 12h  [W]
		retlw	024h		; 13h  [E]
		retlw	02Dh		; 14h  [R]
		retlw	02Ch		; 15h  [T]
		retlw	035h		; 16h  [Y]
		retlw	03Ch		; 17h  [U]
		retlw	043h		; 18h  [I]
		retlw	044h		; 19h  [O]
		retlw	04Dh		; 1Ah  [P]
		retlw	054h		; 1Bh  [@]
		retlw	05Bh		; 1Ch  [[]
		retlw	05Ah		; 1Dh  [RETURN]
		retlw	01Ch		; 1Eh  [A]
		retlw	01Bh		; 1Fh  [S]
		retlw	023h		; 20h  [D]
		retlw	02Bh		; 21h  [F]
		retlw	034h		; 22h  [G]
		retlw	033h		; 23h  [H]
		retlw	03Bh		; 24h  [J]
		retlw	042h		; 25h  [K]
		retlw	04Bh		; 26h  [L]
		retlw	04Ch		; 27h  [;]
		retlw	052h		; 28h  [:]
		retlw	05Dh		; 29h  []]
		retlw	01Ah		; 2Ah  [Z]
		retlw	022h		; 2Bh  [X]
		retlw	021h		; 2Ch  [C]
		retlw	02Ah		; 2Dh  [V]
		retlw	032h		; 2Eh  [B]
		retlw	031h		; 2Fh  [N]
		retlw	03Ah		; 30h  [M]
		retlw	041h		; 31h  [,]
		retlw	049h		; 32h  [.]
		retlw	04Ah		; 33h  [/]
		retlw	051h		; 34h  [ろ]
		retlw	029h		; 35h  [SPACE]
		retlw	0ECh		; 36h  [HOME]
		retlw	0F1h		; 37h  [DEL]
		retlw	0FAh		; 38h  [ROLL UP]        -  [Page Doun]
		retlw	0FDh		; 39h  [ROLL DOWN]      -  [Page Up]
		retlw	0E9h		; 3Ah  [UNDO]           -  [END]
		retlw	0EBh		; 3Bh  [←]
		retlw	0F5h		; 3Ch  [↑]
		retlw	0F4h		; 3Dh  [→]
		retlw	0F2h		; 3Eh  [↓]
		retlw	077h		; 3Fh  [CLR]            -  [NUM LOCK]
		retlw	0CAh		; 40h  [/] (10key)
		retlw	07Ch		; 41h  [*] (10key)
		retlw	07Bh		; 42h  [-] (10key)
		retlw	06Ch		; 43h  [7] (10key)
		retlw	075h		; 44h  [8] (10key)
		retlw	07Dh		; 45h  [9] (10key)
		retlw	079h		; 46h  [+] (10key)
		retlw	06Bh		; 47h  [4] (10key)
		retlw	073h		; 48h  [5] (10key)
		retlw	074h		; 49h  [6] (10key)
		retlw	04Eh		; 4Ah  [=] (10key)
		retlw	069h		; 4Bh  [1] (10key)
		retlw	072h		; 4Ch  [2] (10key)
		retlw	07Ah		; 4Dh  [3] (10key)
		retlw	0DAh		; 4Eh  [ENTER] (10key)
		retlw	070h		; 4Fh  [0] (10key)
		retlw	041h		; 50h  [,] (10key)
		retlw	071h		; 51h  [.] (10key)
		retlw	067h		; 52h  [記号入力]       -  [無変換]
		retlw	07Eh		; 53h  [登録]           -  [ScroolLocK]
		retlw	000h		; 54h  [HELP]
		retlw	09Fh		; 55h  [XF1]            -  [ミ田]
		retlw	011h		; 56h  [XF2]            -  [Alt]
		retlw	064h		; 57h  [XF3]            -  [変換]
		retlw	091h		; 58h  [XF4]            -  [Alt]
		retlw	0AFh		; 59h  [XF5]            -  [(メニュー)]
		retlw	078h		; 5Ah  [かな]           -  [F11]
		retlw	007h		; 5Bh  [ローマ字]       -  [F12]
		retlw	000h		; 5Ch  [コード入力]
		retlw	058h		; 5Dh  [CAPS]
		retlw	0F0h		; 5Eh  [INS]
		retlw	013h		; 5Fh  [ひらがな]
		retlw	00Eh		; 60h  [全角]
		retlw	0FFh		; 61h  [BREAK]          -  [Pause]
		retlw	0FEh		; 62h  [COPY]           -  [PrintScreen]
		retlw	005h		; 63h  [F1]
		retlw	006h		; 64h  [F2]
		retlw	004h		; 65h  [F3]
		retlw	00Ch		; 66h  [F4]
		retlw	003h		; 67h  [F5]
		retlw	00Bh		; 68h  [F6]
		retlw	083h		; 69h  [F7]
		retlw	00Ah		; 6Ah  [F8]
		retlw	001h		; 6Bh  [F9]
		retlw	009h		; 6Ch  [F10]
		retlw	000h		; 6Dh
		retlw	000h		; 6Eh
		retlw	000h		; 6Fh
		retlw	059h		; 70h  [SHIFT]
		retlw	014h		; 71h  [CTRL]
		retlw	000h		; 72h  [OPT.1]
		retlw	000h		; 73h  [OPT.2]
		retlw	000h		; 74h
		retlw	000h		; 75h
		retlw	000h		; 76h
		retlw	000h		; 77h
		retlw	000h		; 78h
		retlw	000h		; 79h
		retlw	000h		; 7Ah
		retlw	000h		; 7Bh
		retlw	000h		; 7Ch
		retlw	000h		; 7Dh
		retlw	000h		; 7Eh
		retlw	000h		; 7Fh
