;***** StaticRamCk1-4bit.asm **********************************************
;
;	簡易 S-RAM チェッカー (1 bit／4 bit)
;
;	Copyright (C) 2010   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2010/08/12  by M.Yamamoto )
;	coding:  Ver. 1.00   2010/08/15  初期バージョン
;	update:  Ver. 1.01   2010/08/22  LCD 更新時間変更の機能追加
;	update:  Ver. 1.02   2010/08/23  /CS,OD S-RAM アクセス方法の変更
;	bugfix:  Ver. x.xx
;
;******************************************************* PicAsm 0224 ******

;	Device: PIC16F877A	Clock: 20MHz (セラロック)

#ifdef comment

 <機能概要>

・本装置は、昔懐かしいレガシーなデバイスの、１ビット幅のスタティックＲＡＭ（種類：２１０２、
　４０４４）と、４ビット幅のスタティックＲＡＭ（種類：５１０１、２１１４）のメモリチェックを
　行なうのを目的とする。
・本装置は、電源スイッチをオンすると、"ピポッ" と起動ブザー音を出力後、液晶（ＬＣＤ）にスタート
　メッセージとして、次の文字列が約３秒間表示される。また同時に、BUSY(黄)、OK(緑)、NG(赤)の各 
　LED を、約１.５秒間細かく交互に点滅させて、点灯チェックも行う。
		"StaticRamChecker"
		" (1 bit / 4 bit)"
・その後、次のメッセージに切り替わって約１.５秒間表示され、その後には無表示が約１.５秒間続く。
		"     ver.x.xx   "
		"  by m.yamamoto "
・やがて無表示の後、次のような SRAM タイプの選択メッセージが表示され、初期値として 2102 が選択
　されて、その文字列先頭の "2" の位置がブリンク表示されている。また同時に、"ピポッ" とブザー音
　を出力してユーザに選択の注意を喚起する。
		"Type?_ 2102 4044"
		"       5101 2114"
・これはユーザからのスイッチの入力待ちの状態を表し、←（LEFT）／ →（RIGHT）スイッチの操作によ
　って、自由に SRAM タイプの選択を行なうことができる。すなわちこのスイッチ操作によって "ポッ" 
　というブザー音とともにブリンク位置が移動し、今ブリンクしている文字列の SRAM タイプが選択され
　ていることになる。
・ SRAM タイプを選択したなら、次に ENTER スイッチを押下することによりその選択が決定され、次のチ
　ェックのスタート促進メッセージが表示される。この時にもユーザの注意を喚起するため、"ピポッ" と
　ブザー音を出力する。
		"<xxxx>  Start?_ "		; xxxx 位置に選択された RAM タイプが入る
		"                "
・そしてその後、ENTER スイッチが押下されればそのまま SRAM チェックがスタートすることになるが、
　もしここで何らかの理由により SRAM タイプの選択を変更したい場合には、BREAK スイッチを押下する
　ことによってチェックスタートされることなく、再び SRAM タイプの選択メッセージの表示に戻ること
　ができる。
・そのまま ENTER スイッチが押下されると、いよいよ SRAM チェックがスタートし "ピポッ" と開始ブザ
　ー音とともに、まず次のようなチェック進行メッセージが表示される。
		"<xxxx>   Er:0000"
		"A:     W:   R:  "
・一方、メモリチェックがスタートされると上記のチェック進行メッセージが表示され、A: はアドレスを、
　W: は書き込みデータを、R: は読み出しデータをそれぞれ表し、":" の後にその内容が表示されてチェ
　ックの進行にしたがって刻々と変化をして行く。これらはすべて１６進数で表示され、通常は A:xxxx、
　W:xx、R:xx の形式で表示される。また、Er: は１６進数４桁表示でそのときまでに起こったエラー数を
　表示する。
・また、SRAM をチェックするのに４つの方法が用意されており、それぞれ SELECT 1, 0 スイッチ（SW5: 
　DIP スイッチの内の真中、SW4: 右端）の設定で、自由に選択が可能である。ただし、１ビット幅の SRAM 
　（種類：2102、4044）では３つの方法のみが用意。
・この SRAM のチェックの進行中にエラーが多発したような場合で、もうこれ以上チェックを続行させて
　も無駄と判断した場合には、BREAK スイッチを押下することによって、いつでもチェックを中断し終了
　させることも可能である。ただし、エラーが起こってなくても BREAK スイッチを押下すれば、やはりチ
　ェックは中断終了してしまうのでそのスイッチの扱いには十分注意を要する。
・一方、次のチェックのスタート促進メッセージが表示されているときに、PAUSE (←（LEFT）スイッチと
　兼用) スイッチを押しながら ENTER スイッチを押下した場合には、エラー発生時にポーズ動作を行なう。
　すなわち、エラーが発生した場合には、その時点での A: アドレス、W: 書き込みデータ、R:読み出しデ
　ータの内容、および Er: エラー数が表示された状態で、一時的にチェックの進行が中断される。このと
　き、結果 NG(赤LED) が点灯するとともに "ブー" というブザー音も出力してエラー表示を行ない、ポー
　ズ状態に入ったことをユーザに知らせる。
		"<xxxx>  Start?_ "		; xxxx 位置に選択された RAM タイプが入る
		"                "
・したがって、そのときの液晶（ＬＣＤ）に表示されている内容を確認した後、CONTINUE (→（RIGHT）ス
　イッチと兼用) スイッチを押下すると、結果 NG(赤LED) が消灯してこのポーズ状態から抜けチェックが
　続行される。この CONTINUE スイッチで続行しても、再度エラーが発生すれば再びポーズ状態に移行す
　ることになる。また、続行を中断したい場合には BREAK スイッチを押下すれば、やはりチェックは中断
　し終了処理に移行する。
・上記のように４つのチェック方法の相違によって、チェックから終了処理に至るまでの過程は違うもの
　の、やがてプログラミングされた予定の処理に終了を迎えた場合、または上記のように BREAK スイッチ
　によって強制的に中断終了させた場合に、終了処理に移行する。
・終了処理では、まず SRAM チェックの総合結果を LED の表示とブザー音の出力でユーザに知らせる。エ
　ラーがなく正常に終了した場合（ BREAK 終了も含む）には、結果 OK(緑LED) が点灯して同時に "ポッ
　ポッポッポッ" というブザー音を出力して正常終了をユーザに知らせる。また、エラーが１件以上あっ
　て終了した場合には、結果 NG(赤LED) が点灯して同時に "ブッブー" というブザー音を出力してエラー
　終了をユーザに知らせる。
・これでとりあえず１つの SRAM のチェックが終了したことになるが、続いて他の同タイプの SRAM のチ
　ェックを行ないたい場合には、ここで ENTER スイッチを押下すれば、再び以下のスタート促進メッセー
　ジが表示されるとともに、"ピポッ" とブザー音を出力してユーザの注意を喚起する。したがって、他の
　SRAM に交換して新たにチェックを行なう。
		"<xxxx>  Start?_ "		; xxxx 位置に選択された RAM タイプが入る
		"                "
・また、他のタイプの SRAM のチェックを行ないたい場合には、上記のスタート促進メッセージが表示さ
　れているときに BREAK スイッチを押下すれば、再び SRAM タイプの選択メッセージの表示に戻ることが
　できる。

（機能追加）
・通常のチェック進行メッセージの表示では、あまりにも早過ぎてどのようなことが行なわれているのか
　普通は追随できない。しかしエラーが起こっている場合などでは、おおよそのことが目視で知りたい場
　合がある。そこでそれが可能なように機能を追加した。
・ENTER スイッチを押下しながら POWER スイッチをＯＮした場合には、液晶（ＬＣＤ）に表示するチェッ
　ク進行メッセージの更新時間を遅延表示することが可能となる。
・デフォルトでは 500mS が設定されているが、進行メッセージが表示されているチェック中に、←（LEFT）
　／ →（RIGHT）スイッチの１回の操作によって、100mS 単位でその更新時間の変更が可能で、←（LEFT）
　スイッチでは －（マイナス）方向に、→（RIGHT）スイッチでは ＋（プラス）方向に働く。
・またその遅延変更の範囲は、最小 100mS から最大 1500mS までの１５段階の設定が可能であり、その段
　階値を次のように１行目の X の位置に液晶（ＬＣＤ）表示する。
		"<xxxx> X Er:0000"
		"A:xxxx W:xx R:xx"

#endif

;==========================================================================

;	PIC16F877A のピンと用途

;	 (1) MCLR:マスター・クリア入力		(40) RB7: A7 出力, A11 出力
;	 (2) RA0: ENTER スイッチ入力		(39) RB6: A6 出力, A10 出力
;	 (3) RA1: LEFT← / PAUSE スイッチ入力　	(38) RB5: A5 出力, A9  出力
;	 (4) RA2: RIGHT→ / CONTI スイッチ入力	(37) RB4: A4 出力, A8  出力
;	 (5) RA3: BREAK スイッチ入力		(36) RB3: A3 出力, D3 入出力
;	 (6) RA4: SELECT_0 スイッチ入力		(35) RB2: A2 出力, D2 入出力
;	 (7) RA5: SELECT_1 スイッチ入力		(34) RB1: A1 出力, D1 入出力
;　	 (8) RE0: ブザー音出力			(33) RB0: A0 出力, D0 入出力
;	 (9) RE1: OK LED 出力			(32) VDD: 電源 +5V DC
;	(10) RE2: NG LED 出力			(31) VSS: 電源 GND
;	(11) VDD: 電源 +5V DC			(30) RD7: LCD DB7 信号 入出力制御
;	(12) VSS: 電源 GND			(29) RD6: LCD DB6 信号 入出力制御
;	(13) OSC1:オシレータ水晶入力		(28) RD5: LCD DB5 信号 入出力制御
;	(14) OSC2:オシレータ水晶入力		(27) RD4: LCD DB4 信号 入出力制御
;	(15) RC0: 2102 タイプ CS 出力		(26) RC7: DO 入力
;	(16) RC1: 4044 タイプ CS 出力		(25) RC6: DI 出力
;	(17) RC2: 5101 タイプ CS 出力		(24) RC5: 74HC574(アドレス)  CK出力
;	(18) RC3: 2114 タイプ CS 出力		(23) RC4: OD, R/W 信号 出力
;	(19) RD0: LCD E   信号 出力制御		(22) RD3: BUSY LED 出力
;	(20) RD1: LCD R/W 信号 出力制御		(21) RD2: LCD RS 信号 出力制御

;==========================================================================

	list		p=pic16f877a	;デバイス情報
	include		p16f877a.inc	;インクルードファイル
	errorlevel	-302		;Eliminate bank warning

	__config	_CP_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC

;==========================================================================
;		変数の定義とレジスタ割付け
;==========================================================================

#define 	ver_no	"1.02"

;#define		_ddram_read		;LCD DDRAM 読み込みを使う場合
;#define		_table_conv		;テーブル変換を使用する場合

		radix	dec

SW		equ	PORTA		;各スイッチ入力ポート
TRIS_SW		equ	TRISA		;各スイッチ入力ポートの入出力切り替え
SRAM		equ	PORTB		;SRAM アドレスデータ用ポート
TRIS_RAM	equ	TRISB		;SRAM 用ポートの入出力切り替え
CONT		equ	PORTC		;コントロール用ポート
TRIS_CNT	equ	TRISC		;コントロール用ポートの入出力切り替え
LCD		equ	PORTD		;LCD 制御用ポート
TRIS_LCD	equ	TRISD		;LCD 制御用ポートの入出力切り替え
LED		equ	PORTE		;LED 制御用ポート
TRIS_LED	equ	TRISE		;LED 制御用ポートの入出力切り替え

_swE		equ	0		;ENTER スイッチ
_swL		equ	1		;LEFT  ← スイッチ
_swR		equ	2		;RIGHT → スイッチ
_swB		equ	3		;BREAK スイッチ
_sw0		equ	4		;SELECT_0 スイッチ
_sw1		equ	5		;SELECT_1 スイッチ

ram2102		equ	h'01'		;SRAM /CS: 2102タイプ チップセレクト
ram4044		equ	h'02'		;SRAM /CS: 4044タイプ チップセレクト
ram5101		equ	h'04'		;SRAM /CS: 5101タイプ チップセレクト
ram2114		equ	h'08'		;SRAM /CS: 2114タイプ チップセレクト
ramRW		equ	4	;h'10'	;SRAM /RW: リードライト制御
ffCK		equ	5	;h'20'	;74HC574(下位アドレス)フリップフロップ用 CK
ramOD		equ	6	;h'40'	;SRAM  OD: 
ramDI		equ	6	;h'40'	;SRAM  DI: 1 bit 用 データ入力
ramDO		equ	7	;h'80'	;SRAM  DO: 1 bit 用 データ出力

_E		equ	0		;LCD E:   動作起動信号
_RW		equ	1		;LCD R/W: 読み出し／書き込み選択信号
_RS		equ	2		;LCD RS:  レジスタ選択信号

_BF		equ	7		;LCD ビジーフラグ

_OK		equ	1		;結果 OK(緑LED)
_NG		equ	2		;結果 NG(赤LED)
_BUSY		equ	3		;ビジー BUSY(黄LED)

buh		equ	high (65536 - 9555)	;ド (261.63 Hz)
bul		equ	low  (65536 - 9555)	;
pih		equ	high (65536 - 6377)	;ソ (392.00 Hz)
pil		equ	low  (65536 - 6377)	;
poh		equ	high (65536 - 4777)	;ド (523.26 Hz)
pol		equ	low  (65536 - 4777)	;

buulcnt		equ	250		;音長
bulcnt		equ	70		;音長
pilcnt		equ	70		;音長
polcnt		equ	70		;音長

		cblock  h'20'
lcdtmp					;LCD への入出力データの一時保存
ledcnt					;LED 点灯チェック用ループカウンタ
ramtyp					;選択 SRAM タイプ
rt_save					;選択 SRAM タイプの保存用
sel_sw					;SELECT_0,1 スイッチの内容(正論理に変換後)

ddram_ad				;DDRAM のアドレスを保存
ddram_wk				;DDRAM のアドレスを保存
ram_idx					;文字列の保存エリアのインデックス
ram_type	;(00)			;選択 SRAM タイプ文字列の保存エリア
		;(01)
		;(02)
		;(03)
		endc

		cblock  ram_type + 4
addr_high				;読み出すデータの high アドレス
addr_low				;読み出すデータの low アドレス

const_high				;音階用分周定数 high の保存
const_low				;音階用分周定数 low の保存

wt1cnt					;ウェイト用ループカウンタ
wt2cnt					;ウェイト用ループカウンタ
wt3cnt					;ウェイト用ループカウンタ
wt4cnt					;ウェイト用ループカウンタ

ram_addr_h				;SRAM の high アドレス
ram_addr_l				;SRAM の low アドレス
ram_data_i				;SRAM の 入力(読み出し)データ
ram_data_o				;SRAM の 出力(書き込み)データ
ram_data_w				;SRAM の 出力(書き込み)データ
ram_cont				;SRAM の コントロール出力
ram_err_h				;エラー数の high 値
ram_err_l				;エラー数の low  値
error_flg				;エラーフラグ
pause_flg				;ポーズフラグ
break_flg				;ブレイクフラグ
adend_flg				;更新終了フラグ
wait_flg				;LCD 更新時間変更フラグ
wt_count				;LCD 更新時間カウンタ

max_addr_h				;SRAM アドレス MAX値の high
max_addr_l				;SRAM アドレス MAX値の low

rd1cnt					;SRAM 種類別テーブルの読み出し用ループカウンタ
rd2cnt					;SRAM 種類別テーブルの読み出し用ループカウンタ

cnvtmp					;変換データの一時保存
hextmp					;変換データの一時保存
		endc

		cblock	h'70'
w_save					;W レジスタの保存用（割り込み処理で使用）
s_save					;STATUS レジスタの保存用（割り込み処理で使用）
		endc

;==========================================================================
;		マクロ命令定義
;==========================================================================

;		LCD メッセージデータ１／２行表示マクロ

;		@x=1: １行表示, @x=2: ２行表示

Disp_Lcd	macro	@com,@msg,@x
		movlw	@com
		call	lcd_cmd		;LCD へコマンドを出力
		movlw	high @msg	;メッセージデータの先頭アドレスの high アドレス
		movwf	addr_high	;
		movlw	low @msg	;メッセージデータの先頭アドレスの low アドレス
		movwf	addr_low	;
		call	lcd_disp	;メッセージデータ１行目表示
	#if 	@x == 1
	#else
		movlw	b'11000000'	;２行目先頭にアドレスセット
		call	lcd_cmd		;LCD へコマンドを出力
		call	lcd_disp	;メッセージデータ２行目表示
	#endif
		endm

;==========================================================================
;		プログラム開始
;==========================================================================

		org	0		;リセットベクタ
		goto	init
		org	4		;割り込みベクタ
		goto	interrupt

;==========================================================================
;		初期化処理
;==========================================================================

		; PIC16F877A 初期設定
init
		bcf	STATUS,RP1	;バンク 0
		bcf	STATUS,RP0
		clrf	ADCON0		;ADCON0 の設定, A/D 未使用

;		bcf	STATUS,RP1	;バンク 1
		bsf	STATUS,RP0
		movlw	h'06'		;ポートA, E を ディジタルモード
		movwf	ADCON1		;ADCON1 の設定

		movlw	b'00111111'	;RA5-0: 入力
		movwf	TRIS_SW		;設定
		clrf	TRIS_RAM	;RB7-0: 出力 の設定
		movlw	b'10000000'	;RC7: 入力, RC6-0: 出力
		movwf	TRIS_CNT	;設定
		clrf	TRIS_LCD	;RD7-0: 出力 の設定
		clrf	TRIS_LED	;RE2-0: 出力 の設定

		movlw	h'80'		;プルアップ抵抗を使用しない
		movwf	OPTION_REG	;OPTION_REG の設定

		bcf	PIE1,TMR1IE	;タイマー１割り込みを禁止

;		bcf	STATUS,RP1	;バンク 0
		bcf	STATUS,RP0
		movlw	b'00000001'	;bit7-6: 未使用
					;bit5-4=00: プリスケーラのスケール値 1:1
					;bit3=0: 専用の発振器を使う場合に指定
					;bit2=0: 外部入力クロック指定時に有効
					;bit1=0: 内部クロックを使う
					;bit0=1: タイマー１を動作
		movwf	T1CON		;T1CON に設定

		clrf	SRAM		;アドレスデータ用ポート
		clrf	CONT		;コントロール用ポート
		bsf	CONT,ffCK	;bit5=1
		nop
		bcf	CONT,ffCK	;bit5=0
		clrf	LCD		;LCD 制御用ポート
		clrf	LED		;LED, 圧電ブザー 制御用ポート

		movlw	5		;規定値(500mS)
		movwf	wt_count	;LCD 更新時間カウンタの設定
		clrf	wait_flg	;LCD 更新時間変更フラグの初期設定
		btfss	SW,_swE		;ENTER スイッチ = ON か？
		bsf	wait_flg,0	;Yes, LCD 更新時間変更フラグの設定

		; SC1602BS-B(LCD) 初期設定, スタートメッセージの表示

		call	lcd_init	;LCD の初期設定

		Disp_Lcd	b'00001100',start_msg,2	;表示ON

;			 0123456789ABCDEF

;			"StaticRamChecker",0
;			" (1 bit / 4 bit)",0

		; ブザー音出力チェック

		bsf	INTCON,PEIE	;PEIE 周辺機器割り込みを許可
		bsf	INTCON,GIE	;GIE 全割り込み許可

		call	buzzer_pipo	;"ピポッ" ブザー音出力

		; BUSY(黄), OK(緑), NG(赤) LED 点灯／消灯チェック

		movlw	5
		movwf	ledcnt		;ループカウンタ

ledck		bsf	LCD,_BUSY	;ビジー BUSY(黄LED) 点灯
		call	wait_100ms	;100m 秒 ウェイト
		bcf	LCD,_BUSY	;ビジー BUSY(黄LED) 消灯

		bsf	LED,_OK		;結果 OK(緑LED) 点灯
		call	wait_100ms	;100m 秒 ウェイト
		bcf	LED,_OK		;結果 OK(緑LED) 消灯

		bsf	LED,_NG		;結果 NG(赤LED) 点灯
		call	wait_100ms	;100m 秒 ウェイト
		bcf	LED,_NG		;結果 NG(赤LED) 消灯

		decfsz	ledcnt,F	;ループカウンタ - 1 = 0 か？
		goto	ledck		;No

		call	wait_1500ms	;1.5 秒 ウェイトルーチン

		Disp_Lcd	b'00000001',start_msg2,2	;表示クリア

;			 0123456789ABCDEF

;			"    ver.x.xx    ",0
;			"  by m.yamamoto ",0

		call	wait_1500ms	;1.5 秒 ウェイトルーチン

		movlw	h'01'		;表示クリア
		call	lcd_cmd		;LCD へコマンドを出力

		call	wait_1500ms	;1.5 秒 ウェイトルーチン

;		btfsc	SW,_swE		;ENTER スイッチ = ON か？
;		goto	$ - 1		;No

;==========================================================================
;		メイン・ルーチン
;==========================================================================

main
		call	wait_500ms	;チャタリングを吸収

		; SRAM タイプ選択メッセージの表示

		Disp_Lcd	b'00000001',type_msg,2	;表示クリア

;			 0123456789ABCDEF

;			"Type?_ 2102 4044",0
;			"       5101 2114",0

		; SRAM タイプの選択 (LCD ブリンク位置決め)

		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	wait_500ms
		clrf	ramtyp		;選択 SRAM タイプの初期設定

		movlw	b'00001101'	;表示オン／オフコントロール
		call	lcd_cmd		;D=1: 表示オン, C=0: カーソル非表示, B=1: ブリンク

main01		movf	ramtyp,W	;選択 SRAM タイプを W へロード
		call	blink_tbl_read	;ブリンク位置テーブル読み込み
		movwf	ddram_ad	;DDRAM のアドレスを保存
		iorlw	h'80'		;DDRAM のアドレス(ブリンク位置)をセット
		call	lcd_cmd		;LCD へコマンドを出力

		btfss	SW,_swE		;ENTER スイッチ = ON か？
		goto	main02		;Yes

		btfss	SW,_swL		;←(LEFT)スイッチ = ON か？
		call	left_switch	;Yes

		btfss	SW,_swR		;→(RIGHT)スイッチ = ON か？
		call	right_switch	;Yes
		goto	main01

main02		call	wait_500ms	;ENTER スイッチのチャタリングを吸収

#ifdef		_ddram_read		;( 選択文字列を LCD DDRAM から取得する場合 )

		; 選択 SRAM タイプ文字列の取得

		movf	ramtyp,W	;選択 SRAM タイプを W へロード
		call	blink_tbl_read	;ブリンク位置テーブル読み込み
		iorlw	h'80'		;DDRAM のアドレスをセット
		call	lcd_cmd		;LCD へコマンドを出力

		clrf	ram_idx		;文字列の保存エリアのインデックス = 0 を設定

main03		movlw	ram_type	;保存エリアの先頭アドレス
		addwf	ram_idx,W	;保存エリアのインデックス値 + 保存エリアの先頭アドレス
		movwf	FSR		;FSR に設定

		call	lcd_data_rd	;LCD からデータを入力
		movwf	INDF		;読み出しデータを保存エリアに書き込む
		incf	ram_idx,F	;保存エリアのインデックスの更新

		movlw	4
		subwf	ram_idx,W
		btfss	STATUS,Z	;読み出しデータ = 終了 か？
		goto	main03		;No

		; 選択 SRAM タイプの表示

main0x		movlw	b'00000001'	;表示クリア
		call	lcd_cmd		;LCD へコマンドを出力

		movlw	"<"
		call	lcd_data	;LCD へデータを１文字出力

		clrf	ram_idx		;文字列の保存エリアのインデックス = 0 を設定

main04		movlw	ram_type	;保存エリアの先頭アドレス
		addwf	ram_idx,W	;保存エリアのインデックス値 + 保存エリアの先頭アドレス
		movwf	FSR		;FSR に設定

		movf	INDF,W		;保存エリアから読み出す
		call	lcd_data	;LCD へデータを１文字出力
		incf	ram_idx,F	;保存エリアのインデックスの更新

		movlw	4
		subwf	ram_idx,W
		btfss	STATUS,Z	;読み出しデータ = 終了 か？
		goto	main04		;No

#else					;( 選択文字列をメッセージテーブルから取得する場合 )

main0x		movlw	b'00000001'	;表示クリア
		call	lcd_cmd		;LCD へコマンドを出力

		movlw	"<"
		call	lcd_data	;LCD へデータを１文字出力

		movlw	high type_msg	;メッセージデータの先頭アドレスの high アドレス
		movwf	addr_high	;
		movlw	low type_msg	;メッセージデータの先頭アドレスの low アドレス
		movwf	addr_low	;

		movf	ddram_ad,W	;DDRAM のアドレスを
		movwf	ddram_wk	;ワークへ

		btfss	ddram_wk,6	;ブリンク位置 ddram_wk >= h'40' か？
		goto	main03		;No

		movlw	b'10111111'	;
		andwf	ddram_wk,F	;ddram_wk - h'40'

		movlw	high type_msg2	;メッセージデータの先頭アドレスの high アドレス
		movwf	addr_high	;
		movlw	low type_msg2	;メッセージデータの先頭アドレスの low アドレス
		movwf	addr_low	;

;			 0123456789ABCDEF

;			"Type?_ 2102 4044",0
;			"       5101 2114",0

main03		clrf	ram_idx		;選択 SRAM タイプ名の取得用ループカウンタ = 0 を設定

main04		incf	addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;読み出すデータの high アドレスの更新

		decfsz	ddram_wk,F
		goto	main04

main05		call	tbl_read	;テーブルデータの読み出し
		bcf	PCLATH,3	;ページ 0 に戻す
		bcf	PCLATH,4
		call	lcd_data	;LCD へデータを１文字出力

		incf	addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;読み出すデータの high アドレスの更新

		incf	ram_idx,F	;保存エリアのインデックスの更新
		movlw	4
		subwf	ram_idx,W
		btfss	STATUS,Z	;読み出しデータ = 終了 か？
		goto	main05		;No
#endif

		movlw	">"
		call	lcd_data	;LCD へデータを１文字出力

		; チェックスタート促進メッセージの表示

		movlw	b'00001101'	;表示オン／オフコントロール
		call	lcd_cmd		;D=1: 表示オン, C=0: カーソル非表示, B=1: ブリンク

		Disp_Lcd	b'10001000',ckst_msg,1	;DDRAM = '08' アドレスセット

;			 0123456789ABCDEF

;		0x	 <xxxx>  "Start?_",0

		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	wait_500ms

main06		btfss	SW,_swB		;BREAK スイッチ = ON か？
		goto	main		;Yes

		btfsc	SW,_swE		;ENTER スイッチ = ON か？
		goto	main06		;No

		clrf	pause_flg	;ポーズフラグのクリア

		call	buzzer_pipo	;"ピポッ" ブザー音出力
		btfss	SW,_swL		;PAUSE(LEFT←) スイッチ = ON か？
		incf	pause_flg,F	;Yes, ポーズフラグのセット

		goto	chk_start	;SRAM チェック開始

;==========================================================================

		; ブリンク位置テーブル読み込み
blink_tbl_read
		addlw	low blink_tbl	;テーブルデータの先頭アドレスの low アドレス
		movwf	addr_low	;
		movlw	high blink_tbl	;テーブルデータの先頭アドレスの high アドレス
		btfsc	STATUS,C	;オーバーフローした場合は
		addlw	1
		movwf	addr_high	;

		call	tbl_read
		bcf	PCLATH,3	;ページ 0 に戻す
		bcf	PCLATH,4
		return

		; ブリンク位置テーブル
blink_tbl
		;	0     1     2     3
		dt	h'07',h'0c',h'47',h'4c'
blink_tbl_end

;			 0123456789ABCDEF

;			"Type?_ 2102 4044",0
;			"       5101 2114",0

;==========================================================================
;		SRAM チェック開始
;==========================================================================

#ifdef comment

		SELECT_1,0 スイッチの内容別 チェックパタンの概要

	(1) sel_sw = b'00' の場合

		for ADDRESS = 0 to max
			for W_DATA = 0 to 1(1 bit 幅) or '0f'(4 bit 幅)
				(write)
				(read)
				if R_DATA = W_DATA then
					OK
				else
					NG
				endif
			next
		next

	(2) sel_sw = b'01' の場合

		for W_DATA = 0 to 1(1 bit 幅) or '0f'(4 bit 幅)
			for ADDRESS = 0 to max
				(write)
			next
			for ADDRESS = 0 to max
				(read)
				if R_DATA = W_DATA then
					OK
				else
					NG
				endif
			next
		next

	(3) sel_sw = b'10' の場合

		for wk = 0 to 1(1 bit 幅) or '0f'(4 bit 幅)
			W_DATA = wk
			for ADDRESS = 0 to max
				(write)
				W_DATA = W_DATA + 1
			next
			W_DATA = wk
			for ADDRESS = 0 to max
				(read)
				if R_DATA = W_DATA then
					OK
				else
					NG
				endif
				W_DATA = W_DATA + 1
			next
		next

	(4) sel_sw = b'11' の場合（4 bit 幅のみ）

		for ADDRESS = 0 to max
			for W_DATA = '01','02','04','08','00','0f','05','0a'
				(write)
				(read)
				if R_DATA = W_DATA then
					OK
				else
					NG
				endif
			next
		next

#endif

;==========================================================================

chk_start
		; チェックパタンの選択チェック

		swapf	SW,W		;上下入れ替えて各スイッチ入力ポートの読み出し
		andlw	b'00000011'	;SELECT_0,1 スイッチを取り出し
		xorlw	b'00000011'	;正論理に変換して
		movwf	sel_sw		;保存

		movlw	2
		subwf	ramtyp,W	;
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		goto	chk00		;Yes

		movlw	3
		subwf	sel_sw,W
		btfss	STATUS,Z	;sel_sw = b'11' か？
		goto	chk00		;No

		call	wait_500ms
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		goto	main06

		; SRAM チェック進行メッセージ(固定文字部分)の表示

chk00		movlw	b'00001100'	;表示オン／オフコントロール
		call	lcd_cmd		;D=1: 表示オン, C=0: カーソル非表示, B=0: 非ブリンク

		Disp_Lcd	b'10001000',check_msg,2	;DDRAM = '08' アドレスセット

;			 0123456789ABCDEF

;		0x	        " Er:0000",0
;		4x	"A:     W:   R:  ",0

		bsf	LCD,_BUSY	;ビジー BUSY(黄LED) 点灯

		; SRAM 種類別 CS pin, アドレス MAX テーブルの読み出し

		call	ram_tbl_read	;ram_cont, max_addr_h, max_addr_l へ設定

		; SRAM チップセレクト(CS)と初期設定

;		movf	ram_cont,W	;SRAM 種類別 CS pin		;(Ver.1.02で変更)
;		movwf	CONT		;コントロール用ポートの設定	;(Ver.1.02で変更)
		clrf	CONT		;コントロール用ポートの設定

		movlw	2
		subwf	ramtyp,W	;
		btfss	STATUS,Z	;選択 SRAM タイプ = 2 か？
		goto	chk0a		;No

		bsf	CONT,ramOD	;5101のとき、OD の設定 OFF

chk0a		clrf	ram_err_h	;エラー数の high 値の初期設定
		clrf	ram_err_l	;エラー数の low  値の初期設定
		clrf	error_flg	;エラーフラグの初期設定

	;;;;;;; チェックパタン '00' の場合

		movf	sel_sw,W
		btfss	STATUS,Z	;sel_sw = b'00' か？
		goto	chk03		;No

		clrf	ram_addr_h	;SRAM の high アドレスの初期設定	
		clrf	ram_addr_l	;SRAM の low  アドレスの初期設定

chk01		call	addr_lcd_ram	;SRAM アドレス(xxxx) の LCD 制御と SRAM への 出力制御

		clrf	ram_data_o	;SRAM の 出力データの初期設定

chk02		call	wdata_lcd_ram	;SRAM 書き込みデータ(xx) の LCD 制御と SRAM への 出力制御

		call	rdata_lcd_ram	;SRAM 読み出しデータ(xx) の SRAM への 入力制御と LCD 制御

		call	err_lcd_pause	;エラー時の LCD 制御と ポーズ動作
		btfsc	break_flg,0	;ブレイクフラグ = ON か？
		goto	chk20		;Yes

		btfss	SW,_swB		;BREAK スイッチ = ON か？
		goto	chk20		;Yes

		incf	ram_data_o,F	;SRAM の 出力データの更新

		movlw	2
		subwf	ramtyp,W	;
		movlw	h'02'
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		movlw	h'10'		;Yes
		subwf	ram_data_o,W	;
		btfss	STATUS,Z	;出力データの更新 = 終了 か？
		goto	chk02		;No

		call	ram_addr_inc	;SRAM の アドレスの更新
		movf	adend_flg,F
		btfsc	STATUS,Z	;更新終了フラグ = ON か？
		goto	chk01		;No
		goto	chk20

	;;;;;;; チェックパタン '01' の場合

chk03		movlw	1
		subwf	sel_sw,W
		btfss	STATUS,Z	;sel_sw = b'01' か？
		goto	chk07		;No

		clrf	ram_data_o	;SRAM の 出力データの初期設定

chk04		clrf	ram_addr_h	;SRAM の high アドレスの初期設定	
		clrf	ram_addr_l	;SRAM の low  アドレスの初期設定

chk05		call	addr_lcd_ram	;SRAM アドレス(xxxx) の LCD 制御と SRAM への 出力制御

		call	wdata_lcd_ram	;SRAM 書き込みデータ(xx) の LCD 制御と SRAM への 出力制御

		call	ram_addr_inc	;SRAM の アドレスの更新
		movf	adend_flg,F
		btfsc	STATUS,Z	;更新終了フラグ = ON か？
		goto	chk05		;No

		clrf	ram_addr_h	;SRAM の high アドレスの初期設定	
		clrf	ram_addr_l	;SRAM の low  アドレスの初期設定

chk06		call	addr_lcd_ram	;SRAM アドレス(xxxx) の LCD 制御と SRAM への 出力制御

		call	rdata_lcd_ram	;SRAM 読み出しデータ(xx) の SRAM への 入力制御と LCD 制御

		call	err_lcd_pause	;エラー時の LCD 制御と ポーズ動作
		btfsc	break_flg,0	;ブレイクフラグ = ON か？
		goto	chk20		;Yes

		btfss	SW,_swB		;BREAK スイッチ = ON か？
		goto	chk20		;Yes

		call	ram_addr_inc	;SRAM の アドレスの更新
		movf	adend_flg,F
		btfsc	STATUS,Z	;更新終了フラグ = ON か？
		goto	chk06		;No

		incf	ram_data_o,F	;SRAM の 出力データの更新

		movlw	2
		subwf	ramtyp,W	;
		movlw	h'02'
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		movlw	h'10'		;Yes
		subwf	ram_data_o,W	;
		btfss	STATUS,Z	;出力データの更新 = 終了 か？
		goto	chk04		;No
		goto	chk20

	;;;;;;; チェックパタン '10' の場合

chk07		movlw	2
		subwf	sel_sw,W
		btfss	STATUS,Z	;sel_sw = b'10' か？
		goto	chk13		;No

		clrf	ram_data_w	;SRAM の 出力データの初期設定

chk08		clrf	ram_addr_h	;SRAM の high アドレスの初期設定	
		clrf	ram_addr_l	;SRAM の low  アドレスの初期設定

		movf	ram_data_w,W
		movwf	ram_data_o

chk09		call	addr_lcd_ram	;SRAM アドレス(xxxx) の LCD 制御と SRAM への 出力制御

		call	wdata_lcd_ram	;SRAM 書き込みデータ(xx) の LCD 制御と SRAM への 出力制御

		call	ram_addr_inc	;SRAM の アドレスの更新
		movf	adend_flg,F
		btfss	STATUS,Z	;更新終了フラグ = ON か？
		goto	chk10		;Yes

		incf	ram_data_o,F	;SRAM の 出力データの更新

		movlw	2
		subwf	ramtyp,W	;
		movlw	h'02'
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		movlw	h'10'		;Yes
		subwf	ram_data_o,W	;
		btfsc	STATUS,Z	;出力データの更新 = 最終値 か？
		clrf	ram_data_o	;Yes
		goto	chk09

chk10		clrf	ram_addr_h	;SRAM の high アドレスの初期設定	
		clrf	ram_addr_l	;SRAM の low  アドレスの初期設定

		movf	ram_data_w,W
		movwf	ram_data_o

chk11		call	addr_lcd_ram	;SRAM アドレス(xxxx) の LCD 制御と SRAM への 出力制御

		call	rdata_lcd_ram	;SRAM 読み出しデータ(xx) の SRAM への 入力制御と LCD 制御

		call	err_lcd_pause	;エラー時の LCD 制御と ポーズ動作
		btfsc	break_flg,0	;ブレイクフラグ = ON か？
		goto	chk20		;Yes

		btfss	SW,_swB		;BREAK スイッチ = ON か？
		goto	chk20		;Yes

		call	ram_addr_inc	;SRAM の アドレスの更新
		movf	adend_flg,F
		btfss	STATUS,Z	;更新終了フラグ = ON か？
		goto	chk12		;Yes

		incf	ram_data_o,F	;SRAM の 出力データの更新

		movlw	2
		subwf	ramtyp,W	;
		movlw	h'02'
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		movlw	h'10'		;Yes
		subwf	ram_data_o,W	;
		btfsc	STATUS,Z	;出力データの更新 = 最終値 か？
		clrf	ram_data_o	;Yes
		goto	chk11

chk12		incf	ram_data_w,F	;SRAM の 出力データの更新

		movlw	2
		subwf	ramtyp,W	;
		movlw	h'02'
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		movlw	h'10'		;Yes
		subwf	ram_data_w,W	;
		btfss	STATUS,Z	;出力データの更新 = 終了 か？
		goto	chk08		;No
		goto	chk20

	;;;;;;; チェックパタン '11' の場合

ptn_tbl		dt	h'01',h'02',h'04',h'08'
		dt	h'00',h'0f',h'05',h'0a'

chk13		clrf	ram_addr_h	;SRAM の high アドレスの初期設定	
		clrf	ram_addr_l	;SRAM の low  アドレスの初期設定

chk14		call	addr_lcd_ram	;SRAM アドレス(xxxx) の LCD 制御と SRAM への 出力制御

		movlw	high ptn_tbl	;パタンテーブルの先頭アドレスの high アドレス
		movwf	addr_high	;
		movlw	low ptn_tbl	;パタンテーブルの先頭アドレスの low アドレス
		movwf	addr_low	;

chk15		call	tbl_read	;テーブルデータの読み出し

		bcf	PCLATH,3	;ページ 0 に戻す
		bcf	PCLATH,4
		incf	addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;読み出すデータの high アドレスの更新

		movwf	ram_data_o	;SRAM の 出力データの設定

		call	wdata_lcd_ram	;SRAM 書き込みデータ(xx) の LCD 制御と SRAM への 出力制御

		call	rdata_lcd_ram	;SRAM 読み出しデータ(xx) の SRAM への 入力制御と LCD 制御

		call	err_lcd_pause	;エラー時の LCD 制御と ポーズ動作
		btfsc	break_flg,0	;ブレイクフラグ = ON か？
		goto	chk20		;Yes

		btfss	SW,_swB		;BREAK スイッチ = ON か？
		goto	chk20		;Yes

		movlw	h'0a'
		subwf	ram_data_o,W
		btfss	STATUS,Z	;SRAM の 出力データ = 終了'0a' か？
		goto	chk15		;No

		call	ram_addr_inc	;SRAM の アドレスの更新
		movf	adend_flg,F
		btfsc	STATUS,Z	;更新終了フラグ = ON か？
		goto	chk14		;No

	;;;;;;; SRAM チェックの総合結果 (LED の表示とブザー音出力)

chk20		movf	error_flg,F	
		btfsc	STATUS,Z	;エラー数 = 0 か？
		goto	chk21		;Yes

		bsf	LED,_NG		;結果 NG(赤LED)
		call	buzzer_bubuu	;"ブッブー" ブザー音出力
		goto	chk22

chk21		bsf	LED,_OK		;結果 OK(緑LED)
		call	buzzer_po4	;"ポッポッポッポッ" ブザー音出力

chk22		clrf	SRAM		;アドレス／データ用ポート
		clrf	CONT		;コントロール用ポート
		bsf	CONT,ffCK	;bit5=1
		nop
		bcf	CONT,ffCK	;bit5=0
		bcf	LCD,_BUSY	;ビジー BUSY(黄LED) 消灯

		btfsc	SW,_swE		;ENTER スイッチ = ON か？
		goto	$ - 1		;No

		clrf	LED		;LED, 圧電ブザー 制御用ポート
		goto	main0x

;==========================================================================

	;;;;;;; SRAM アドレス(xxxx) の LCD 制御と SRAM への 出力制御

addr_lcd_ram
		; SRAM アドレス(xxxx) の LCD 表示

		movlw	b'11000010'	;DDRAM = '42' アドレスセット
		call	lcd_cmd		;LCD へコマンドを出力
		movf	ram_addr_h,W	;SRAM の high アドレス
		call	lcd_hex_out	;１バイト変換 (BIN → HEX 文字) ２文字 LCD 表示
		movf	ram_addr_l,W	;SRAM の low アドレス
		call	lcd_hex_out	;１バイト変換 (BIN → HEX 文字) ２文字 LCD 表示

		; SRAM アドレス(xxxx) の 出力設定

		movf	ram_addr_l,W	;SRAM の low アドレス
		movwf	SRAM		;PIC のアドレス／データ用ポートに出力
		nop
		bsf	CONT,ffCK	;Flip-Flop CK
		nop
		bcf	CONT,ffCK

		movlw	h'0f'
		andwf	SRAM,F
		swapf	ram_addr_h,W	;SRAM の high アドレス
		iorwf	SRAM,F		;PIC のアドレス／データ用ポートに出力
		return

	;;;;;;; SRAM 書き込みデータ(xx) の LCD 制御と SRAM への 出力制御

wdata_lcd_ram
		; SRAM 書き込みデータ(xx) の LCD 表示

		movlw	b'11001001'	;DDRAM = '49' アドレスセット
		call	lcd_cmd		;LCD へコマンドを出力
		movf	ram_data_o,W	;SRAM の 出力データ
		call	lcd_hex_out	;１バイト変換 (BIN → HEX 文字) ２文字 LCD 表示

		; SRAM 書き込みデータ(xx) の 出力設定

		movlw	2
		subwf	ramtyp,W	;
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		goto	wdata01		;Yes
	
		bcf	CONT,ramDI
		movf	ram_data_o,W	;SRAM の 出力データ
		btfss	STATUS,Z	;出力データ > 0 か？
		bsf	CONT,ramDI	;Yes
		goto	wdata02

wdata01		movlw	h'f0'
		andwf	SRAM,F
		movf	ram_data_o,W	;SRAM の 出力データ
		iorwf	SRAM,F		;PIC のアドレス／データ用ポートに出力
		nop

wdata02		movf	ram_cont,W	;SRAM 種類別 CS pin
		iorwf	CONT,F		;/CS:チップセレクト ON
		nop
		nop

		bsf	CONT,ramRW	;/RW:リードライト制御
		nop
		nop
		nop
		bcf	CONT,ramRW	;

		nop
		movlw	h'f0'
		andwf	CONT,F		;/CS:チップセレクト OFF
		return

	;;;;;;; SRAM 読み出しデータ(xx) の SRAM への 入力制御と LCD 制御

rdata_lcd_ram
		; SRAM 読み出しデータ(xx) の 入力設定

		movlw	2
		subwf	ramtyp,W	;
		btfsc	STATUS,C	;選択 SRAM タイプ >= 2 か？
		goto	rdata01		;Yes

		; 1 bit 幅（2102, 4044）のとき

		movf	ram_cont,W	;SRAM 種類別 CS pin
		iorwf	CONT,F		;/CS:チップセレクト ON
		nop

		clrf	ram_data_i	;SRAM の 入力データ
		btfsc	CONT,ramDO	;入力データ = 1 か？
		incf	ram_data_i,F	;Yes
		goto	rdata04

		; 4 bit 幅（5101, 2114）のとき

rdata01		bcf	STATUS,RP1	;バンク 1
		bsf	STATUS,RP0
		movlw	b'00001111'
		movwf	TRIS_RAM	;RB3-0: 入力 の設定
;		bcf	STATUS,RP1	;バンク 0
		bcf	STATUS,RP0

		swapf	ram_addr_h,W	;;再度 SRAM の high アドレスを
		movwf	SRAM		;;PIC のアドレス／データ用ポートに出力

		movf	ram_cont,W	;SRAM 種類別 CS pin
		iorwf	CONT,F		;/CS:チップセレクト ON

		movlw	2
		subwf	ramtyp,W	;
		btfss	STATUS,Z	;選択 SRAM タイプ = 2 か？
		goto	rdata02		;No

		bcf	CONT,ramOD	;5101のとき、OD の設定 ON

rdata02		movf	SRAM,W		;SRAM データの読み出し
		andlw	h'0f'
		movwf	ram_data_i	;SRAM の 入力データ

		movlw	2
		subwf	ramtyp,W	;
		btfss	STATUS,Z	;選択 SRAM タイプ = 2 か？
		goto	rdata03		;No

		bsf	CONT,ramOD	;5101のとき、OD の設定 OFF

;		bcf	STATUS,RP1	;バンク 1
rdata03		bsf	STATUS,RP0
		clrf	TRIS_RAM	;RB7-0: 出力 の設定
;		bcf	STATUS,RP1	;バンク 0
		bcf	STATUS,RP0

rdata04		movlw	h'f0'
		andwf	CONT,F		;/CS:チップセレクト OFF

		; SRAM 読み出しデータ(xx) の LCD 表示

		movlw	b'11001110'	;DDRAM = '4E' アドレスセット
		call	lcd_cmd		;LCD へコマンドを出力
		movf	ram_data_i,W	;SRAM の 入力データ
		call	lcd_hex_out	;１バイト変換 (BIN → HEX 文字) ２文字 LCD 表示
		return

	;;;;;;; エラー時の LCD 制御と ポーズ動作

err_lcd_pause
		clrf	break_flg	;ブレイクフラグのクリア

		; LCD 更新時間の変更

		movf	wait_flg,F
		btfsc	STATUS,Z	;wait_flg = 0 か？
		goto	pause00		;Yes

		movf	wt_count,W
		call	wait04		;wait_100ms
;		movwf	wt4cnt
;		call	wait_100ms
;		decfsz	wt4cnt,F
;		goto	$ - 2

		btfsc	SW,_swL		;←(LEFT)スイッチ = ON か？
		goto	$ + 4		;No

		decf	wt_count,F	;-1 更新
		btfsc	STATUS,Z	;0 か？
		incf	wt_count,F	;Yes

		movf	wt_count,W
		btfsc	SW,_swR		;→(RIGHT)スイッチ = ON か？
		goto	$ + 4		;No

		addlw	1		;+1 更新
		btfss	STATUS,DC	;下位４ビットがオーバーフロー か？
		movwf	wt_count	;No

		movlw	b'10000111'	;DDRAM = '07' アドレスセット
		call	lcd_cmd		;LCD へコマンドを出力

		movf	wt_count,W
		call	hex_conv	;下位４ビットの変換
		call	lcd_data	;LCD へデータを１文字出力

		; エラー数の LCD 表示

pause00		movf	ram_data_i,W	;SRAM の 入力データ
		subwf	ram_data_o,W
		btfsc	STATUS,Z	;等しい か？
		goto	pause03		;Yes

		incf	ram_err_l,F	;エラー数の low  値の更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	ram_err_h,F	;エラー数の high 値の更新
		bsf	error_flg,0	;エラーフラグの設定	

		movlw	b'10001100'	;DDRAM = '0C' アドレスセット
		call	lcd_cmd		;LCD へコマンドを出力
		movf	ram_err_h,W	;エラー数の high 値
		call	lcd_hex_out	;１バイト変換 (BIN → HEX 文字) ２文字 LCD 表示
		movf	ram_err_l,W	;エラー数の low  値
		call	lcd_hex_out	;１バイト変換 (BIN → HEX 文字) ２文字 LCD 表示

		; ポーズ動作をする場合

		movf	pause_flg,F
		btfsc	STATUS,Z	;ポーズフラグ = ON か？
		goto	pause03		;No

		bsf	LED,_NG		;結果 NG(赤LED) 点灯
		call	buzzer_buu	;"ブー" ブザー音出力

pause01		btfsc	SW,_swB		;BREAK スイッチ = ON か？
		goto	pause02		;No

		bsf	break_flg,0	;ブレイクフラグのセット
		goto	pause03

pause02		btfsc	SW,_swR		;CONTI(RIGHT→) スイッチ = ON か？
		goto	pause01		;No

		bcf	LED,_NG		;結果 NG(赤LED) 消灯
		call	wait_500ms	;CONTI スイッチのチャタリングを吸収

pause03		return

	;;;;;;; SRAM の アドレスの更新

ram_addr_inc
		clrf	adend_flg	;更新終了フラグのクリア

		movf	max_addr_l,W	;SRAM アドレス MAX値の low
		subwf	ram_addr_l,W	;SRAM の low アドレス
		btfss	STATUS,Z	;等しい か？
		goto	adinc01		;No

		movf	max_addr_h,W	;SRAM アドレス MAX値の high
		subwf	ram_addr_h,W	;SRAM の high アドレス
		btfss	STATUS,Z	;等しい か？
		goto	adinc01		;No

		bsf	adend_flg,0	;更新終了フラグのセット
		goto	adinc02

adinc01		incf	ram_addr_l,F	;SRAM の low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	ram_addr_h,F	;SRAM の high アドレスの更新

adinc02		return

;==========================================================================

		; １バイト変換 (BIN → HEX 文字) ２文字 LCD 出力
lcd_hex_out
		movwf	cnvtmp		;変換データの一時保存
		swapf	cnvtmp,W
		andlw	h'0f'
		call	hex_conv	;上位４ビットの変換
		call	lcd_data	;LCD へデータを１文字出力

		movlw	h'0f'
		andwf	cnvtmp,W
		call	hex_conv	;下位４ビットの変換
		call	lcd_data	;LCD へデータを１文字出力
		return

		; ４ビット変換 (BIN → HEX 文字)
hex_conv

#ifndef		_table_conv		;( テーブル変換を使用しない場合 )

		movwf	hextmp
		sublw	h'0a'
		btfsc	STATUS,Z	;
		goto	cnv01		;W = h'0a' 

		btfss	STATUS,C	;
		goto	cnv01		;W > h'0a' 

		movlw	h'30'		;0 ～ 9
		goto	cnv02

cnv01		movlw	h'40' - 9	;A ～ F

cnv02		addwf	hextmp,W
		return

#else					;( テーブル変換を使用する場合 )

		addwf	PCL,F
		dt	"0","1","2","3","4","5","6","7"
		dt	"8","9","A","B","C","D","E","F"
#endif

;==========================================================================
;		LCD（ SC1602BS-B の場合 ）表示用 各種メッセージ等
;==========================================================================

		; スタートメッセージ

start_msg	dt	"StaticRamChecker",0
		;	 0123456789ABCDEF
		dt	" (1 bit / 4 bit)",0

start_msg2
		dt	"    ver.",ver_no,"    ",0
		dt	"  by m.yamamoto ",0

		; SRAM タイプ選択メッセージ

type_msg	dt	"Type?_ 2102 4044",0
		;	 0123456789ABCDEF
type_msg2	dt	"       5101 2114",0

		; SRAM チェックスタート促進メッセージ

ckst_msg	dt	        "Start?_",0
		;	 0123456789ABCDEF

		; SRAM チェック進行メッセージ

check_msg	dt	        " Er:0000",0
		;	 0123456789ABCDEF
		dt	"A:     W:   R:  ",0

;		dt	"<xxxx>   Er:xxxx",0
;		dt	"A:xxxx W:xx R:xx",0

;==========================================================================
;		←(LEFT) 左スイッチの処理
;==========================================================================

left_switch
		movlw	30		;チャッタリング吸収1
		call	wait_xxms	;wait 30ms
		btfsc	SW,_swL		;入力(LEFT ←)スイッチ = ON か？
		goto	lefsw01		;No

		call	buzzer_po	;"ポッ" ブザー音出力
		movlw	150		;チャッタリング吸収2
		call	wait_xxms	;wait 100ms

		decf	ramtyp,F	;選択 SRAM タイプ -1
		incf	ramtyp,W
		btfss	STATUS,Z	;(ramtyp < 0) か？
		goto	lefsw01		;No

		movlw	blink_tbl_end - blink_tbl - 1
		movwf	ramtyp		;選択 SRAM タイプの初期設定

lefsw01		return

;==========================================================================
;		→(RIGHT) 右スイッチの処理
;==========================================================================

right_switch
		movlw	30		;チャッタリング吸収1
		call	wait_xxms	;wait 30ms
		btfsc	SW,_swR		;入力(RIGHT →)スイッチ = ON か？
		goto	rigsw01		;No

		call	buzzer_po	;"ポッ" ブザー音出力
		movlw	150		;チャッタリング吸収2
		call	wait_xxms	;wait 100ms

		incf	ramtyp,F	;選択 SRAM タイプ +1
		movlw	blink_tbl_end - blink_tbl
		subwf	ramtyp,W
		btfss	STATUS,Z	;(ramtyp = テーブルデータ数) か？
		goto	rigsw01		;No

		clrf	ramtyp		;選択 SRAM タイプの初期設定

rigsw01		return

;==========================================================================
;		SRAM 種類別 CS pin, アドレス MAX テーブルの読み出し
;==========================================================================

ram_tbl_read
		movlw	high ram_tbl	;テーブルデータの先頭アドレスの high アドレス
		movwf	addr_high	;
		movlw	low ram_tbl	;テーブルデータの先頭アドレスの low アドレス
		movwf	addr_low	;

		movf	ramtyp,W	;選択 SRAM タイプ値を
		movwf	rd1cnt		;rd1cnt にセット

tblrd01		movf	rd1cnt,F
		btfsc	STATUS,Z	;rd1cnt = 0 か？
		goto	tblrd03		;Yes

		movlw	3
		movwf	rd2cnt		;rd2cnt = 3 をセット

tblrd02		incf	addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;読み出すデータの high アドレスの更新

		decfsz	rd2cnt,F	;rd2cnt - 1 = 0 か？
		goto	tblrd02		;No

		decf	rd1cnt,F	;rd1cnt - 1
		goto	tblrd01

tblrd03		call	tbl_read	;テーブルデータの１文字読み出し
		bcf	PCLATH,3	;ページ 0 に戻す
		bcf	PCLATH,4
		movwf	ram_cont	;;SRAM の コントロールバッファへ設定
		incf	addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;読み出すデータの high アドレスの更新

		call	tbl_read	;テーブルデータの１文字読み出し
		bcf	PCLATH,3	;ページ 0 に戻す
		bcf	PCLATH,4
		movwf	max_addr_h	;;SRAM アドレス MAX値の high へ設定
		incf	addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;読み出すデータの high アドレスの更新

		call	tbl_read	;テーブルデータの１文字読み出し
		bcf	PCLATH,3	;ページ 0 に戻す
		bcf	PCLATH,4
		movwf	max_addr_l	;;SRAM アドレス MAX値の low へ設定
		return

		; SRAM 種類別 CS pin, アドレス MAX テーブル
ram_tbl
		dt	ram2102, h'03',h'ff'	;0: 2102 SRAM (1 bit×1024)
		dt	ram4044, h'0f',h'ff'	;1: 4044 SRAM (1 bit×4096)
		dt	ram5101, h'00',h'ff'	;2: 5101 SRAM (4 bit× 256)
		dt	ram2114, h'03',h'ff'	;3: 2114 SRAM (4 bit×1024)

;==========================================================================
;		LCD 制御サブルーチン
;==========================================================================

		; LCD へコマンドを出力
lcd_cmd
		bcf	LCD,_RS		;RS = 0  (コマンドモードに設定)
		goto	lcd01

		; LCD へデータを出力
lcd_data
		bsf	LCD,_RS		;RS = 1  (データモードに設定)
		nop

lcd01		bcf	LCD,_RW		;R/W = 0 (書き込みモードに設定)
		call	lcd_out		;上位４ビットを転送

		swapf	lcdtmp,W	;一時保存データの上位下位入れ替え
		call	lcd_out		;下位４ビットを転送

		call	lcd_busy	;LCD ビジーチェック
		return

		; ４ビット一回の送出
lcd_out
		movwf	lcdtmp		;コマンド／データを一時保存
		movlw	h'0f'		;下位４ビットの
		andwf	LCD,F		;コントロールポートの内容を残し
		movlw	h'f0'		;上位４ビットデータ
		andwf	lcdtmp,W	;を取り出して
		iorwf	LCD,F		;コントロールとＯＲ

		bsf	LCD,_E		;E = 1   (動作起動信号の設定：Hでストローブ)
		nop			;E のパルス幅を220ns以上確保するため
		bcf	LCD,_E		;E = 0   (動作起動信号の設定：Lに戻す)
		return

		; LCD ビジーチェック
lcd_busy
		bsf	STATUS,RP0	;バンク 1
		movlw	b'11110000'	;上位４ビットを入力ポート
		iorwf	TRIS_LCD,F
		bcf	STATUS,RP0	;バンク 0
		bcf	LCD,_RS		;RS = 0  (コマンドモードに設定)
		nop
		bsf	LCD,_RW		;R/W = 1 (読み込みモードに設定)

lcd_busy01	bsf	LCD,_E		;E = 1   (動作起動信号の設定：Hでストローブ)
		movf	LCD,W		;DDRAM からのデータ（上位４ビット）の読み出し
		bcf	LCD,_E		;E = 0   (動作起動信号の設定：Lに戻す)
;		andlw	h'f0'		;上位４ビット
		movwf	lcdtmp		;読み込みデータを一時保存
;		swapf	lcdtmp,F	;下位４ビットに移動

		bsf	LCD,_E		;E = 1   (動作起動信号の設定：Hでストローブ)
		movf	LCD,W		;DDRAM からのデータ（下位４ビット）の読み出し
		bcf	LCD,_E		;E = 0   (動作起動信号の設定：Lに戻す)
;		andlw	h'f0'		;上位４ビット
;		iorwf	lcdtmp,F	;上位４ビット + 下位４ビット
;		swapf	lcdtmp,F	;上位４ビットと下位４ビットを入れ替え
		btfsc	lcdtmp,_BF	;ビジーフラグのチェック (読み込みデータの７ビット目)
		goto	lcd_busy01	;_BF=0 になるまでループ

		bcf	LCD,_RW		;R/W = 0  (書き込みモードに設定)
		bsf	STATUS,RP0	;バンク 1
		movlw	b'11110000'	;上位４ビットを出力ポートに戻す
		xorwf	TRIS_LCD,F
		bcf	STATUS,RP0	;バンク 0
		return

		; LCD 初期設定
lcd_init
		bcf	LCD,_RW		;R/W = 0 (書き込みモードに設定)
		nop
		bcf	LCD,_RS		;RS = 0  (コマンドモードに設定)
		nop
		bcf	LCD,_E		;E = 0   (動作起動信号の設定)

		movlw	15
		call	wait_xxms	;wait 15ms （15ms以上を確保）
		movlw	b'00110000'	;ファンクションセット(8bitモードに設定)
		call	lcd_out		;上位４ビットを転送

		movlw	5
		call	wait_xxms	;wait 5ms （4.1ms以上を確保）
		movlw	b'00110000'	;ファンクションセット(8bitモードに設定) 
		call	lcd_out		;上位４ビットを転送

		call	wait_100us
		movlw	b'00110000'	;ファンクションセット(8bitモードに設定)
		call	lcd_out		;上位４ビットを転送

		call	wait_100us
		movlw	b'00100000'	;ファンクションセット(4bitモードに設定)
		call	lcd_out		;上位４ビットを転送

		call	wait_100us	;ここから 4bitモード
		movlw	b'00101000'	;ファンクションセット
		call	lcd_cmd		;DL=0: 4bit, N=1: 2行, F=0: 5x7ドット

		movlw	b'00001000'	;表示オン／オフコントロール
		call	lcd_cmd		;D=0: 表示オフ, C=0: カーソル非表示, B=0: 非ブリンク

		movlw	b'00000001'	;表示クリア
		call	lcd_cmd		;

		movlw	b'00000110'	;エントリーモードセット 
		call	lcd_cmd		;I/D=1: アドレスを+1しカーソルは右移動，S=0: 非シフト
		return

		; LCD からデータを入力

;<使用例>	movlw	h'80'		;読み出す DDRAM のアドレスをセット
;		call	lcd_cmd		;LCD へコマンドを出力
;		  :
;		call	lcd_data_rd	;LCD からデータを入力

lcd_data_rd
		bsf	STATUS,RP0	;バンク 1
		movlw	b'11110000'	;上位４ビットを入力ポート
		iorwf	TRIS_LCD,F
		bcf	STATUS,RP0	;バンク 0
		bsf	LCD,_RS		;RS = 1  (データモードに設定)
		nop
		bsf	LCD,_RW		;R/W = 1 (読み込みモードに設定)

		bsf	LCD,_E		;E = 1   (動作起動信号の設定：Hでストローブ)
		movf	LCD,W		;DDRAM からのデータ（上位４ビット）の読み出し
		bcf	LCD,_E		;E = 0   (動作起動信号の設定：Lに戻す)
		andlw	h'f0'		;上位４ビット
		movwf	lcdtmp		;読み込みデータを一時保存
		swapf	lcdtmp,F	;下位４ビットに移動

		bsf	LCD,_E		;E = 1   (動作起動信号の設定：Hでストローブ)
		movf	LCD,W		;DDRAM からのデータ（下位４ビット）の読み出し
		bcf	LCD,_E		;E = 0   (動作起動信号の設定：Lに戻す)
		andlw	h'f0'		;上位４ビット
		iorwf	lcdtmp,F	;上位４ビット + 下位４ビット
		swapf	lcdtmp,F	;上位４ビットと下位４ビットを入れ替え

		bcf	LCD,_RW		;R/W = 0  (書き込みモードに設定)
		bsf	STATUS,RP0	;バンク 1
		movlw	b'11110000'	;上位４ビットを出力ポートに戻す
		xorwf	TRIS_LCD,F
		bcf	STATUS,RP0	;バンク 0

		call	wait_100us
		movf	lcdtmp,W	;読み出しデータを W に移動
		return

		; LCD １行メッセージ表示

;<使用例>	movlw	h'80'		;表示位置の DDRAM のアドレスをセット
;		call	lcd_cmd		;LCD へコマンドを出力
;		movlw	high st_msg	;メッセージデータの先頭アドレスの high アドレス
;		movwf	addr_high	;
;		movlw	low st_msg	;メッセージデータの先頭アドレスの low アドレス
;		movwf	addr_low	;
;		call	lcd_disp	;メッセージデータ１行表示
;		  :
;st_msg		dt	"StaticRamChecker",0

lcd_disp
		call	tbl_read	;テーブルデータの読み出し
		bcf	PCLATH,3	;ページ 0 に戻す
		bcf	PCLATH,4
		incf	addr_low,F	;読み出すデータの low アドレスの更新
		btfsc	STATUS,Z	;オーバーフローした場合は
		incf	addr_high,F	;読み出すデータの high アドレスの更新
		addlw	0
		btfsc	STATUS,Z	;h'00' か？
		return			;yes

		call	lcd_data	;LCD へデータを１文字出力
		goto	lcd_disp

		; テーブルデータの１文字読み出し
tbl_read
		movf	addr_high,W	;読み出すデータの high アドレス
		movwf	PCLATH
		movf	addr_low,W	;読み出すデータの low アドレス
		movwf	PCL

;==========================================================================
;		ブザー音出力ルーチン
;==========================================================================

		; "ブー" ブザー音出力
buzzer_buu
		movlw	buh
		movwf	const_high	;音階用分周定数 high を設定
		movlw	bul
		movwf	const_low	;音階用分周定数 low を設定
		movlw	buulcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ブッ" ブザー音出力
buzzer_bu
		movlw	buh
		movwf	const_high	;音階用分周定数 high を設定
		movlw	bul
		movwf	const_low	;音階用分周定数 low を設定
		movlw	bulcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ピッ" ブザー音出力
buzzer_pi
		movlw	pih
		movwf	const_high	;音階用分周定数 high を設定
		movlw	pil
		movwf	const_low	;音階用分周定数 low を設定
		movlw	pilcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ポッ" ブザー音出力
buzzer_po
		movlw	poh
		movwf	const_high	;音階用分周定数 high を設定
		movlw	pol
		movwf	const_low	;音階用分周定数 low を設定
		movlw	polcnt		;音長（ループカウンタ）
		goto	buzzer_control

		; "ピポッ" ブザー音出力
buzzer_pipo
		call	buzzer_pi	;"ピッ" ブザー音出力
		movlw	30
		call	wait_xxms
		call	buzzer_po	;"ポッ" ブザー音出力
		return

		; "ポッポッポッポッ" ブザー音出力
buzzer_po4
		movlw	4
		movwf	wt4cnt
po4		call	buzzer_po	;"ポッ" ブザー音出力
		movlw	30
		call	wait_xxms
		decfsz	wt4cnt,F
		goto	po4
		return

		; "ブッブー" ブザー音出力
buzzer_bubuu
		call	buzzer_bu	;"ブッ" ブザー音出力
		movlw	70
		call	wait_xxms
		call	buzzer_buu	;"ブー" ブザー音出力
		return

		; ブザー音出力コントロール

buzzer_control
		bsf	STATUS,RP0	;バンク 1
		bsf	PIE1,TMR1IE	;タイマー１割り込みを許可
		bcf	STATUS,RP0	;バンク 0

		call	wait_xxms	;入力 W: 音長（ループカウンタ）

		bsf	STATUS,RP0	;バンク 1
		bcf	PIE1,TMR1IE	;タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		return

;==========================================================================
;		ウェイト・ルーチン (20 MHz)
;==========================================================================

		; 100μ秒 ウェイトルーチン
wait_100us
		movlw	99		;1
		movwf	wt1cnt		;1
wait01		goto	$+1		;2
		decfsz	wt1cnt,F	;1,2
		goto	wait01		;2,0	1+1+(2+1+2)*98+(2+2+0)=496
;		goto	$+1		;2
		return			;2	496+2=498
					;       498/20MHz*4 = 99.6 μS = 100 μS = 0.1 mS

		; 1m 秒 ウェイトルーチン
wait_1ms
		movlw	10		;1
		movwf	wt2cnt		;1
wait02		call	wait_100us	;2	2+498=500
		decfsz	wt2cnt,F	;1,2
		goto	wait02		;2,0	1+1+(500+1+2)*9+(500+2+0)=5031
		return			;2	5031+2=5033
					;       5033/20MHz*4 = 1.0066 mS = 1 mS

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100

		; xx m 秒 ウェイトルーチン
wait_xxms
		movwf	wt3cnt		;1
wait03		call	wait_1ms	;2	2+5033=5035
		decfsz	wt3cnt,F	;1,2
		goto	wait03		;2,0	1+(5035+1+2)*(xx-1)+(5035+2+0)=5038*(xx)
		return			;2	5038*(xx)+2
					;

		; 500m 秒 ウェイトルーチン
wait_500ms
		movlw	5
		goto	wait04

		; 1.5 秒 ウェイトルーチン
wait_1500ms
		movlw	15
wait04		movwf	wt4cnt

wait05		call	wait_100ms
		decfsz	wt4cnt,F
		goto	wait05
		return

;==========================================================================
;		タイマー割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		movf	STATUS,W
		movwf	s_save		;STATUS レジスタの保存

		bcf	STATUS,RP0	;バンク 0
		bcf	STATUS,RP1
		btfss	PIR1,TMR1IF	;タイマ１オーバフロー か？
;		goto	init		;No. Reset(Illegal interrupt)
		goto	int01

		; タイマー１割り込み処理

		movf	const_high,W	;音階用分周定数 high を
		movwf	TMR1H		;TMR1H に設定
		movf	const_low,W	;音階用分周定数 low を
		movwf	TMR1L		;TMR1L に設定

		movlw	b'00000001'	;RE0: ブザー音出力, 対象ビットをセット
		xorwf	PORTE,F		;出力をビット反転

		bcf	PIR1,TMR1IF	;タイマ１オーバフロー解除

		; レジスタの復帰

int01		movf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie			;割り込みからの復帰

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

eep_st		de	"Copyright (C) 2010 by M.Yamamoto"

;==========================================================================

		end			;プログラムの終了
