tab が変だけど…


;
; X68000のキーボードを
; AT互換機のPS/2ポートにつなぐのです
;
;                                      2001/11/26 作成
;                                      2001/11/27 更新
;
; 秋月アセンブラ(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
LCD_E		equ		0	; RA0 - LCD E
LCD_RS		equ		1	; RA1 - LCD RS
X68_READY	equ		2	; RA2 - X68 KY READY
;						  RA3 - 未使用 (入力に設定し、GNDへ接続)
;						  RA4 - 未使用 (入力に設定し、GNDへ接続)

; PORT B
PS2_CLK		equ		0	; RB0 - PS/2 CLK  (外部にプルアップ抵抗をつける 2kくらい?)
PS2_DATA	equ		1	; RB1 - PS/2 DATA (外部にプルアップ抵抗をつける 2kくらい?)
X68_RxD		equ		2	; RB2 - X68 KY RxD
X68_TxD		equ		3	; RB3 - X68 KY TxD
LCD_DB4		equ		4	; RB4 - LCD DB4
LCD_DB5		equ		5	; RB5 - LCD DB5
LCD_DB6		equ		6	; RB6 - LCD DB6
LCD_DB7		equ		7	; RB7 - LCD DB7

;	LCDの余ったピンの処理
;	LCD DB0  - GND
;	LCD DB1  - GND
;	LCD DB2  - GND
;	LCD DB3  - GND
;	LCD R/~W - GND 常時ライト


	.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		250	; ms 単位のウェイト用定数
							; CONST_WAIT_MS = (動作クロック[MHz]/4)*100

CONST_WAIT_US	equ		8	; 10μs 単位のウェイト用定数
							; CONST_WAIT_US = 10/(1/動作クロック[MHz]*4*3)

CONST_COMSPEED	equ		130	; シリアル通信用割り込み間隔
							; CONST_COMSPEED = 255 - (osc[Hz] / bps / 32)+5?

; -----------------------------------------------------------------------------

;	変数を宣言
		org		0ch
temp1				ds		1
status_led			ds		1	; ステータスLED状態保持
SCRLK				equ		1
NUMLK				equ		2
CAPSLK				equ		3
lastdata			ds		1	; PS/2ポートに前回送出したデータ
lcd_temp1			ds		1	; LCD表示で使う変数
lcd_temp2			ds		1	; LCD表示で使う変数
lcd_temp3			ds		1	; LCD表示で使う変数
lcd_temp4			ds		1	; LCD表示で使う変数
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	PORTB,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	PORTB,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	PORTB,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	PORTB,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		PORTB,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		PORTB,X68_TxD			;送信バッファのbit0が0なら0を送信
		goto	intx68tmode1_8end
intx68tmode1_8_1
		bsf		PORTB,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		PORTB,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
;******************************************************************************
;		goto	ps2init

		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	11111000b	; w=11111000b
		;		   ||||+----- LCD_E			out
		;		   |||+------ LCD_RS		out
		;		   ||+------- X68_READY		out
		;		   |+-------- RA3 - 未使用	in
		;		   +--------- RA4 - 未使用	in
		movwf	TRISA		; 設定レジスタに書き込み

;	ポートB
		movlw	00000100b	;
		;		|||||||+----- PC_DATA		out
		;		||||||+------ PC_CLK		out
		;		|||||+------- X68_RxD		in
		;		||||+-------- X68_TxD		out
		;		|||+--------- LCD_DB4		out
		;		||+---------- LCD_DB5		out
		;		|+----------- LCD_DB6		out
		;		+------------ LCD_DB7		out
		movwf	TRISB		; 設定レジスタに書き込み

		bcf		STATUS,RP0	; bank0

;	X68キーボードデータ送出禁止
		bcf		PORTA,X68_READY

;	通信ポートを1にしておく
		movlw	11111111b
		movwf	PORTB

;	変数の初期化

		clrf	int_x68rmode
		clrf	int_x68rcount
		clrf	int_x68tcount
		clrf	int_x68tmode
		clrf	com_status


;	LCDの初期化

		movlw	15
		call	wait			; 15ms 待つ

		bcf		PORTA,LCD_RS	;  RS DB7 DB6 DB5 DB4
		movlw	00110000b		;  0   0   0   1   1
		call	lcd_write4

		movlw	5
		call	wait			; 5ms 待つ

		movlw	00110000b
		call	lcd_write4

		movlw	1
		call	wait			; 1ms 待つ

		movlw	00110000b
		call	lcd_write4

		movlw	00100000b		;  DB7 DB6 DB5 DB4
		call	lcd_write4		;   0   0   1   0
								; 4ビットモードに設定

		movlw	00101000b		; 4bit, 1/16duty, 5x7
		call	lcd_write

		movlw	00000001b		; 表示クリア
		call	lcd_write

		movlw	2				; クリアには少し時間がかかるので
		call	wait			; 2ms 待つ

		movlw	00000110b		; エントリーモードセット
		call	lcd_write		; (カーソルの進み方の設定)

		movlw	00001110b		; 表示オン/オフコントロール
		call	lcd_write		; 表示オン, カーソル表示あり, ブリンクなし


;	割り込み許可

		movlw	10100000b
		movwf	INTCON			; TMR0割り込み許可





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;	PS/2 キーボードとしての初期化処理

ps2init
		movlw	11111111b
		movwf	PORTB
		movlw	100
		call	wait
ps2init1
		btfss	PORTB,PS2_CLK	; CLKがHになるまで待つ
		goto	ps2init1

ps2init2
		btfss	PORTB,PS2_DATA
		goto	main			; DATA がLなら受信処理

		movlw	0aah
		call	ps2transmit		; セルフテストOK送信
		btfsc	com_status,ps2break
		goto	ps2init1		; 送信が中断されたらもう一回


; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
main
;	X68キーボードデータ送出許可
		bsf		PORTA,X68_READY

;	ホストコマンドの処理
hostcommand
		call	ps2receive
		btfss	com_status,ps2rxdvalid
		goto	main_keyin				; 受信しなければキー入力処理

; -----------------------------------------------------------------------------
set_status_led
		movlw	0edh
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	echo
		movlw	0fah
		call	ps2transmit					; ACK
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	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
set_scancode1
		call	ps2receive
		btfss	com_status,ps2rxdvalid
		goto	set_scancode1
		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
set_repeatrate1
		call	ps2receive
		btfss	com_status,ps2rxdvalid
		goto	set_repeatrate1

;***************************************

		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	0f5h
		subwf	ps2rxd,0
		btfss	STATUS,Z
		goto	reset
resend1
		movf	lastdata,0
		call	ps2transmit					; resend
		goto	main_keyin

; -----------------------------------------------------------------------------
reset
		movlw	0f5h
		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			; データを受信しなければ何もしない

		bcf		INTCON,GIE		; 割り込み禁止

								; 割り込み処理内でテーブル処理を
								; 行っているので、
								; PCLATH を書き換えている間に割り込みが入ると
								; まずいので、割り込み禁止にする
		movlw	003h
		movwf	PCLATH

		movlw	01111111b
		andwf	x68rxd,0
		call	table
		movwf	temp1

		movlw	000h
		movwf	PCLATH

		movf	temp1,0
		call	disp_h

		movf	temp1,1
		btfsc	STATUS,Z		; テーブルから00hが帰ってきた(キー未割り当て)
		goto	main_keyin_end	; なら、なにもしない

		btfsc	temp1,7
		goto	exkey

;	通常キー
		btfsc	x68rxd,7
		goto	release
;	押された
		movf	temp1,0
		call	ps2transmit
		goto	main_keyin_end
release
;	離された
		movlw	0f0h
		call	ps2transmit
		movf	temp1,0
		call	ps2transmit
		goto	main_keyin_end

exkey
;	拡張キー
		btfsc	x68rxd,7
		goto	exkey_release
;	押された
		movlw	0e0h
		call	ps2transmit
		movf	temp1,0
		call	ps2transmit
		goto	main_keyin_end

exkey_release
;	離された
		movlw	0e0h
		call	ps2transmit
		movlw	0f0h
		call	ps2transmit
		movf	temp1,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
		movlw	11111111b
		movwf	PORTB

;	スタートビットの取り込み
ps2receive_startbit
		btfsc	PORTB,PS2_DATA		; スタートビットが見つからなければ
		return						; 終了
		bsf		com_status,ps2rxdfound
		bsf		com_status,ps2break
		movlw	1
		movwf	ps2parity			;パリティ計算用変数を初期化
		movlw	8
		movwf	ps2count			; count=8

;	8ビット分データを取り込む
ps2receive_data
		call	ps2clk				; クロックを出す
		movlw	11111111b
		movwf	PORTB
		rrf		ps2rxd,1
		btfsc	PORTB,PS2_DATA		; データを取り込む
		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_CLK		; ホストがCLKをLにしてきたら
		return						; 処理中断
		decfsz	ps2count,1	; count-1
		goto	ps2receive_data

;	パリティビットの取り込み
ps2receive_parity
		call	ps2clk				; クロックを出す
		movlw	11111111b
		movwf	PORTB
		btfss	PORTB,PS2_CLK		; ホストがCLKをLにしてきたら
		return						; 処理中断
		movlw	00000001b
		andwf	ps2parity,1			; ps2parity のbit0のみ取り出し
		btfsc	PORTB,PS2_DATA
		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	ps2clk				; クロックを出す
		movlw	11111111b
		movwf	PORTB
		btfss	PORTB,PS2_CLK		; ホストがCLKをLにしてきたら
		return						; 処理中断
		bcf		com_status,ps2break
		btfss	PORTB,PS2_DATA		; ストップビットと思われるところが
		goto	ps2receive_end		; 0だったらエラー
;	受信終了
		bsf		com_status,ps2rxdvalid	; データ有効フラグをセット
		call	ps2clk				; クロックを出す
		movlw	11111101b
		movwf	PORTB				; データラインをLにする
ps2receive_perror
		call	ps2clk				; クロックを出す
		movlw	11111111b
		movwf	PORTB				; データラインをHにする

ps2receive_end
		btfsc	PORTB,PS2_DATA
		goto	ps2receive_return	; データラインがHなら終了処理
		call	ps2clk				; データラインがLならHになるまで
		movlw	11111111b			; クロックを出す
		movwf	PORTB
		goto	ps2receive_end

ps2receive_return
		btfsc	com_status,ps2rxdvalid
		return						; 正常受信なら終了
ps2receive_resend
;	受信エラーの為、再送要求
		btfss	PORTB,PS2_CLK	; CLKがLならHになるまで待つ
		goto	ps2receive_resend
		btfss	PORTB,PS2_DATA
		goto	ps2receive		; DATA がLなら再度受信処理
		movlw	0feh
		call	ps2transmit		; Resend コマンド発行
		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

		movlw	11111111b
		movwf	PORTB
		btfss	PORTB,PS2_CLK		; CLKがLなら
		goto	ps2transmit			; Hになるまで待つ
		btfss	PORTB,PS2_DATA		; DATAがLなら、なにもしない
		return						; 戻り先で受信処理を行って欲しい

ps2transmit_startbit
		movlw	11111101b
		movwf	PORTB				; スタートビットをセット
;		bcf		PORTB,PS2_DATA		; スタートビットをセット
		call	ps2clk				; クロックを出す
		btfss	PORTB,PS2_CLK		; ホストがCLKをLにしてきたら
		return						; 処理中断

ps2transmit_data
		btfsc	ps2txd,0			; データをセット
		goto	ps2transmit_data1
ps2transmit_data0
		bcf		PORTB,PS2_DATA
		goto	ps2transmit_wait1
ps2transmit_data1
		bsf		PORTB,PS2_DATA
		incf	ps2parity,1			; parity+1
ps2transmit_wait1
		call	ps2clk				; クロックを出す
		btfss	PORTB,PS2_CLK		; ホストがCLKをLにしてきたら
		return						; 処理中断
		rrf		ps2txd,1			; 右シフト
		decfsz	ps2count,1	; count-1
		goto	ps2transmit_data

ps2transmit_parity
		btfsc	ps2parity,0			; パリティをセット
		goto	ps2transmit_parity1
ps2transmit_parity0
		bcf		PORTB,PS2_DATA
		goto	ps2transmit_wait2
ps2transmit_parity1
		bsf		PORTB,PS2_DATA
ps2transmit_wait2
		call	ps2clk				; クロックを出す
		btfss	PORTB,PS2_CLK		; ホストがCLKをLにしてきたら
		return						; 処理中断

ps2transmit_stopbit
		bsf		PORTB,PS2_DATA		; ストップビットをセット
		call	ps2clk				; クロックを出す
		btfss	PORTB,PS2_CLK		; ホストがCLKをLにしてきたら
		return						; 処理中断

;	送信おしまい
ps2transmit_end
		movlw	11111111b
		movwf	PORTB
		bcf		com_status,ps2break
		return




ps2clk
		movlw	7
		call	waitus
;		movlw	11111110b
;		movwf	PORTB			; CLK をLにする
		bcf		PORTB,PS2_CLK
		movlw	7
		call	waitus
;		movlw	11111111b
;		movwf	PORTB			; CLK をHにする
		bsf		PORTB,PS2_CLK
		return



; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------

; wレジスタの内容を16進表記で表示する


; 例
;	1:	movlw		0ah		; w=0ah
;	2:	call	disp_h
; と実行するとLCDに
;	+----------------+
;	|0A_             |
;	|                |
;	+----------------+ と表示する

disp_h
		clrf	lcd_temp4		; lcd_temp5=0
		movwf	lcd_temp3		; lcd_temp3=w

		bsf		PORTA,LCD_RS	; RS を 1

disp_h_loop
		swapf	lcd_temp3,0

		andlw	00001111b
		movwf	lcd_temp1		; lcd_temp1=w

		addlw	6				; w=w+6
		btfsc	STATUS,DC		; 0fhを超えた(w=9以下)
		goto	disp_h_1

;	0〜9の時
		movlw	030h			; w=030h
		addwf	lcd_temp1,0		; w=w+lcd_temp1
		call	lcd_write
		goto disp_h_2

;	a〜hの時
disp_h_1
		movlw	037h			; w=037h
		addwf	lcd_temp1,0		; w=w+lcd_temp1
		call	lcd_write

disp_h_2
		btfsc	lcd_temp4,0		; lcd_temp4のbit0が 0以外ならreturn
		return					;

		decf	lcd_temp4,1		; lcd_temp4=lcd_temp4-1 (0-1=0ffh)
		swapf	lcd_temp3,1
		goto	disp_h_loop





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------

;	LCDへの書き込み
;	wレジスタの内容をLCDに書き込む


lcd_write
		movwf	lcd_temp1	; lcd_temp1=w
		call	lcd_write4	; 上位4ビットの書き込み

		swapf	lcd_temp1,0	; lcd_temp1 の上位4ビットと下位4ビットを入れ替えて
							; wレジスタに代入
		call	lcd_write4	; 下位4ビットの書き込み

		return


;
;	書き込みサブルーチンのサブルーチン
;	wレジスタの上位4ビットだけを書き込む

;	ポートBの下位4ビットは変化しない

lcd_write4
		andlw	11110000b	; w=w&11110000b
		movwf	lcd_temp2	; 書き込むデータの上位4ビットのみを退避

		movf	PORTB,0		; w=PORTB
		andlw	00001111b	; w=w&00001111b
							; ポートBの下位4ビットのみを取り出し

		iorwf	lcd_temp2,0	; w=w|lcd_temp2
		movwf	PORTB		; ボートBの下位4ビットとデータの上位4ビットを
							; 合成してポートBに出力

		bsf		PORTA,LCD_E	; 書き込み
		nop
		bcf		PORTA,LCD_E

		movlw	1
		call	wait		; 少し待つ

		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





; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;	キーコード変換テーブル
;	PS2のキーコードが複数バイトあって、どう処理しようか困った
;	とりあえず、拡張キーは bit7 を 1 にしてみる方針でやってみる

;	キーの割り当てを変えたい場合は、このテーブルを書き換えてね


		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	0FDh		; 38h  [ROLL UP]
		retlw	0FAh		; 39h  [ROLL DOWN]
		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	055h		; 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	049h		; 50h  [,] (10key)
		retlw	071h		; 51h  [.] (10key)
		retlw	000h		; 52h  [記号入力]
		retlw	000h		; 53h  [登録]
		retlw	000h		; 54h  [HELP]
		retlw	000h		; 55h  [XF1]
		retlw	000h		; 56h  [XF2]
		retlw	000h		; 57h  [XF3]
		retlw	000h		; 58h  [XF4]
		retlw	000h		; 59h  [XF5]
		retlw	078h		; 5Ah  [かな]           -  [F11]
		retlw	007h		; 5Bh  [ローマ字]       -  [F12]
		retlw	000h		; 5Ch  [カナ入力]
		retlw	058h		; 5Dh  [CAPS]
		retlw	0F0h		; 5Eh  [INS]
		retlw	000h		; 5Fh  [ひらがな]
		retlw	000h		; 60h  [全角]
		retlw	000h		; 61h  [BREAK]
		retlw	000h		; 62h  [COPY]
		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	012h		; 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


webmaster@kyoutan.jpn.org

('A`)