;***** TMS1121_Simulator.asm **********************************************
;
;	ＴＩ社 TMS1121 デジタルタイマー・シミュレータ
;
;	Copyright (C) 2019   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2019/05/18  by M.Yamamoto )
;	coding:  Ver. 1.00   2019/07/24  初期バージョン
;	update:  
;
;******************************************************* PicAsm 0247 ******

;	Device: PIC16F886	Clock: 8MHz (Internal OSC)

;	PIC16F886 のピンと用途

;	  (1) MCLR: マスター・クリア入力	(28) RB7: R6 出力
;	  (2) RA0: R7 出力			(27) RB6: R5 出力
;	  (3) RA1: R8 出力			(26) RB5: R4 出力
;	  (4) RA2: R9 出力			(25) RB4: R3 出力
;	  (5) RA3: R10 出力			(24) RB3: R2 出力
;	  (6) RA4: K1 入力			(23) RB2: R1 出力
;	  (7) RA5: K2 入力			(22) RB1: R0 出力
;	  (8) VSS: 電源 GND			(21) RB0: K8 入力
;	  (9) RA7: EXT JPスイッチ 入力		(20) VDD: 電源 +5V DC
;	 (10) RA6: K3 入力			(19) VSS: 電源 GND
;	 (11) RC0: O0 出力 			(18) RC7: O7 出力
;	 (12) RC1: O1 出力 			(17) RC6: O6 出力
;	 (13) RC2: O2 出力 			(16) RC5: O5 出力
;	 (14) RC3: O3 出力 			(15) RC4: O4 出力

;
; ＜ 拡張機能について ＞
;
;　本シミュレーションプログラムを作って行く過程で、オリジナル TMS1121 にはないが、こんな機能があるといいのに
;　とか、こうしたらもっと便利になるのにとか、私が感じた機能をプログラムに盛り込むことにした。しかし、それはオ
;　リジナル TMS1121 から逸脱をすることにもなるので、これらの追加や変更の機能は拡張機能として、スイッチ操作に
;　よって有効／無効を自由に切り替えることが可能なように考慮をした。
;
;　その切り替えスイッチが、回路図に示す EXT ジャンパースイッチで、PIC16F886 のポート（RA7）が１つ余っていたの
;　でそれに割り当ててみた。
;
;　拡張機能としては、現在、次の３つの機能がある。
;
; １．コロン [COL] LED のブリンク表示
;
;　本機の時計の表示は "時"、"分" の４桁表示のため、刻々と変化をして行く "秒" の様子が、見ている者に伝わってこ
;　ない。―というわけでもないが、私の遊び心的な気持ちも手伝って、"時"、"分" の区切りの [COL] LED の表示を動か
;　してみたが、頭で考えていたのとは異なって、どうやらこの試みは失敗のようであった。 
;
;　0.5 秒間を "点"、次の 0.5 秒間を "滅" の１秒周期で、ブリンク表示をさせたが、人それぞれ感じ方は違うとは思う
;　が、私には、[COL] LED の表示が動くのを見ていて、何か煩わしく感じられた。
;
;　そこで、EXT ジャンパースイッチで拡張機能を選択したときに、必ずブリンク表示をしてしまうのも困るので、回路図
;　に示すように新たに NOR/BLK ジャンパースイッチを設けて、好みによってノーマル表示（点灯し切り）／ブリンク表
;　示（点滅）が選択できるようにした。
;
;　ただし、EXT ジャンパースイッチが OFF のときに NOR/BLK ジャンパースイッチを BLK にすると、 [COL] LED は消灯
;　してしまうので注意が必要である。
;
; ２．時計機能の 24 時間表示
;
;　私はこれまでに、他のページで紹介をしている "７セグメントＬＥＤ表示時計" を、初めて PIC によって作製をして
;　以来、他にも PIC を使用した数多くのデジタル時計を作製してきた。 そして、それらの数多くのデジタル時計で共通
;　していることは、どれもすべてが 12 時間表示／24 時間表示 のどちらにも対応をさせていることである。
;
;　したがって、オリジナルの TMS1121 は 12 時間表示専用のデジタル時計であるが、本機ではシミュレーションプログ
;　ラムを作成する当初から、24 時間表示にも対応をさせることを考えていた。 そして、それを拡張機能という形で盛り
;　込むことにした。これならば、決して TMS1121 から逸脱をすることにはならないと思う。
;
;　時計としての計時（カウント）方法を、TMS1121 ではどのように行っているのか分からないが、本シミュレーションプ
;　ログラムでは、ＬＥＤ表示が 12 時間表示でも、内部的には 24 時間表示で計時（カウント）をさせている。その方が
;　タイマー機能を実現させるためにも都合が良いからである。そして、ＬＥＤに表示をさせるときに 24 時間表示から、
;　12 時間表示に変換をしているだけなのである。言うまでもなく 24 時間表示をさせるときには、変換の必要はないの
;　で単純にそのままをＬＥＤに表示をさせている。
;
;　したがって、ＬＥＤ表示を 24 時間表示に変更をするためには、まず EXT ジャンパースイッチを ON にした上で、12H
;　/24H タクトスイッチを操作する。このタクトスイッチは、12 時間表示にするか 24 時間表示にするかを、押す度に切
;　り替えまる。
;
;　ここで、話は少し変わるが 12 時間表示専用の TMS1121 では、時計機能に対する時刻の変更設定やタイマーの設定（
;　定時プログラム）では、当然だが、そこで扱っている入力情報の指定には、AM/PM 別を含めた曜日、時分を 12 時間表
;　示形式で行っている。
;
;　これに対して本機では、拡張機能が OFF のときと 同機能が ON でも 12 時間表示のときには、同様に 12 時間表示形
;　式で入力情報の指定を行うが、拡張機能が ON で 24 時間表示のときには、AM/PM 別を含めない 24 時間表示形式で入
;　力情報の指定を行うのが正道とは思うが、ユーザの紛らわしさを避けるために、現在は、すべての場合において 12 時
;　間表示形式を採用している。（将来的には変更をするかもしれない。）
;
;　ここで、入力情報の指定を行うときの、12 時間表示形式と 24 時間表示形式の違いを再確認しておくと、前者では AM
;　/PM 別、時間指定は 1 ～ 12 であり、後者では時間指定は 0 ～ 23 であって AM/PM 別の指定はない。
;
; ３．MEM CLRの機能改善
;
;　オリジナルの TMS1121 では、タイマー用メモリの内容消去をするのに３つの方法があるが、その内の曜日別消去、ス
;　イッチ別消去については、自分の意志でもってメモリ内容を消去するわけだから問題はないと思う。これに対して全消
;　去の場合には、自分の意志のときはもちろん問題はないが、誤操作のときには取り返しがつかなくなる。
;
;　ここで一番問題なのは、MCLR キーの単独操作（たった１回の押下）でメモリ内容のすべてが消去されてしまう、とい
;　うことにある。誤操作というのは往々にしてあり得ることで、できればこれを避けたいものである。そこで、これに対
;　処をしたのがここで述べる改善策である。
;
;　自分の意志で全消去を行うという場面はそうそうあるわけではないから、単独操作ではなく MCLR キーを５回の連続操
;　作（５回連続で押下）で全消去を行うように改めた。２、３回というのはやはり誤操作であり得ると思うので、５回に
;　した。それほどの手間にはならないものと思う。なお、５回未満の場合には無視をする。
;
;　また、メモリ内容の全消去の操作をすることによって、私がもう一つ困ると思うことは、現在、どれかのスイッチ（複
;　数個を含む）が ON 動作をしていた場合に、それらのすべてのスイッチが OFF 状態にされてしまう、ということであ
;　る。TMS1121 の仕様なのかもしれないが私に言わせれば、いらぬお節介で余計なことをするな ―と言いたい。
;
;　しかし、これを逆手にとって（そうなることを意識して）、ON 動作のスイッチを OFF 状態にすることを目的として用
;　いることはできなくなるが、MCLR キーを５回の連続操作で全消去を行っても、現在 ON 動作をしているスイッチとは
;　無関係になるように改めた。 
;
;　ON 動作のスイッチを OFF 状態にするには、ダイレクト・コントロール（直接制御）で行えば良いと思う。 ただし、
;　複数個の ON 動作をしているすべてのスイッチを、一気に OFF 状態にすることはできない。
;
; ４．
;
;　----------------------------------------------------------------
;
;　なお、上述の拡張機能も含めて本シミュレーションプログラムの解説を、次に示す私のホームページ上で行っているの
;　で、このプログラムを理解する上での一助として欲しい。
;
;	ＵＲＬ： http://xyama.sakura.ne.jp/hp/TMS1121_Simulator.html#program
;

;==========================================================================

	list		p=pic16f886		;デバイス情報
	include		p16f886.inc		;インクルードファイル
	errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションの設定
;==========================================================================

	__config _CONFIG1, _INTOSCIO & _WDT_OFF & _PWRTE_ON & _MCLRE_ON & _IESO_OFF & _FCMEN_OFF & _LVP_OFF
	__config _CONFIG2, _WRT_OFF

;==========================================================================
;		定数、変数の定義とレジスタ割付け
;==========================================================================

#define 	ver_no	"1.00"

		radix	dec

tm0_h_val	equ	256 - 250	;ハードタイマー０カウント値（割り込み周期）(4/8Mz*16*250=2msec)
tm0_s_val	equ	25		;ソフトタイマー０カウント値                (2msec*25=50msec)

seg7_0		equ     b'00111111'	;-gfedcba Pattern 0
seg7_1		equ     b'00000110'	;         Pattern 1
seg7_2		equ     b'01011011'	;         Pattern 2
seg7_3		equ     b'01001111'	;         Pattern 3
seg7_4		equ     b'01100110'	;         Pattern 4
seg7_5		equ     b'01101101'	;         Pattern 5
seg7_6		equ     b'01111101'	;         Pattern 6
seg7_7		equ     b'00000111'	;         Pattern 7
seg7_8		equ     b'01111111'	;         Pattern 8
seg7_9		equ     b'01101111'	;         Pattern 9
seg7_off	equ     b'00000000'	;         LED off

		cblock  h'20'
tm0_s_cnt				;ソフトタイマー０カウンタ
f_const					;50/60Hz 定数を設定
init_flg				;bit7: 電源"ON" + CLKキー"ON" 以前の制御フラグ
					;bit0: AM/PM 点滅制御
sec1_cnt				;１秒カウンタ
week_cnt				;WEEK カウンタ
bcd_hh					;時_BCD カウンタ
bcd_mm					;分_BCD カウンタ
bcd_ss					;秒_BCD カウンタ
temp_week				;仮の WEEK カウンタ
temp_hh					;仮の 時_BCD カウンタ
temp_mm					;仮の 分_BCD カウンタ
ox_mode					;MODE LED セグメント出力
ox_week					;WEEK LED セグメント出力
ox_sw					;SW LED セグメント出力
rx_sw					;RX SW リレー出力の指定
fmmwwwss				;タイマー制御バイト
tmon_flg				;bit0: タイマー監視フラグ ... interrupt(bcd_ssmmhh_inc) で設定、time_monitor で解除
mode_flg				;bit0: キー入力モードフラグ
					;bit0=0: 時刻表示モード, bit0=1: キー入力表示モード
					;bit1: X,SW 処理済みフラグ、(追加フラグ)
					;bit2: 定時プログラムフラグ、(追加フラグ)
					;bit5-4: AM/PM の退避用ワーク
itv_flg					;bit0: インターバルフラグ
sw_stat					;スイッチの入力状態を一時保存
keycode					;bit7: キー入力受付済み表示フラグ ... key_scan で設定、interrupt で解除
					;bit6: キーコード別処理済みフラグ ... key_proc で設定、interrupt で解除
					;bit4-0: (0-19): キーコード, (20): 拡張機能時12H/24Hキー, (21): キー入力なし表示
wkcode					;キーコードワーク
err_flg					;bit0: 入力エラーフラグ
ext_flg					;bit7: 拡張機能フラグ
					;bit4: COL LED 点滅制御
					;bit3: 時間表示フラグ（0:12H / 1:24H）
					;bit2-0: MCLR カウンタ
dsp_cnt					;bit7: X,WEEK / X,SW 処理済みフラグ
					;bit6: LED 表示消灯フラグ、0: 表示 / 1: 消灯
					;bit5: タイマー用メモリ検索終了フラグ
					;bit4-0: 表示カウンタ
lp_cnt					;ループカウンタ
gen_wk					;ワーク
wt_cnt					;ウェイト用ループカウンタ
		endc

		cblock	h'70'
s_save					;STATUS レジスタの退避用
p_save					;PCLATH レジスタの退避用
w_save					;W レジスタの退避用
		endc

		cblock	h'a0'		;(バンク 1)
m_fmmwwwss				;タイマー制御バイト
m_week_cnt				;WEEK カウンタ
m_bcd_hh				;時_BCD カウンタ
m_bcd_mm				;分_BCD カウンタ
m_lp_cnt				;メモリスキャン用ループカウンタ
m_dsp_cnt				;表示カウンタ
m_gen_wk				;ワーク
timer_mem				;タイマー用メモリの先頭
;	     (3 * 20 = 60 byte 使用)
		endc

;==========================================================================
;		タイマー用メモリの構成
;==========================================================================

; １メモリ単位 ... (タイマー制御バイト)、(時_BCD カウンタバイト)、(分_BCD カウンタバイト)

; (タイマー制御バイト) ／ fmmwwwss ／ m_fmmwwwss

;		fmmw.wwss	fmmw.wwss	fmmw.wwss	fmmw.wwss
;		:		 ::		   : ::		       ::
;		0  メモリ無効	 00  OFF	   0 00  EDAY	       01  SW1
;		1  メモリ有効	 01  ON		   0 01  SUN	       10  SW2
;				 10  SLP OFF	   0 10  MON	       11  SW3
;				 11  SLP ON	   0 11  TUE	       00  SW4
;						   1 00  WED
;						   1 01  THU
;						   1 10  FRI
;						   1 11  SAT

; (時_BCD カウンタバイト)

;		chhh.hhhh		chhh.hhhh	chhh.hhhh
;		:			 :::		     ::::
;		1 メモリ自動消去有効	 十時(0～2)	     時(0～9)

; (分_BCD カウンタバイト)

;					mmmm.mmmm	mmmm.mmmm
;					::::		     ::::
;					十分(0～5)	     分(0～9)

;==========================================================================
;		プログラム開始
;==========================================================================

		org	0		;リセットベクタ
		goto	start
		org	4		;割り込みベクタ
		goto	interrupt

;==========================================================================
;		W に指定された 0～9 の数字を 表示パターンに変換
;	（PCL を操作する場合はプログラムを配置する位置に配慮すること）
;==========================================================================

ptn_set
		addwf	PCL,F		;プログラム・カウンタに加算

		retlw	seg7_0		;0
		retlw	seg7_1		;1
		retlw	seg7_2		;2
		retlw	seg7_3		;3
		retlw	seg7_4		;4
		retlw	seg7_5		;5
		retlw	seg7_6		;6
		retlw	seg7_7		;7
		retlw	seg7_8		;8
		retlw	seg7_9		;9
		retlw	seg7_off	;a

		retlw	b'00000010'	;b（以下デバッグ用）
		retlw	b'00000100'	;c
		retlw	b'00001000'	;d
		retlw	b'00010000'	;e
		retlw	b'00100000'	;f

;==========================================================================
;		初期化処理
;==========================================================================

start
		bcf	STATUS,RP1	;バンク 0
		bcf	STATUS,RP0
		clrf	PORTA
		clrf	PORTB
		clrf	PORTC
		clrf	ADCON0		;ADCON0 の設定, A/D 未使用

		bsf	STATUS,RP0	;バンク 1
		bsf	STATUS,RP1	;;バンク 3  ** PIC16F886 のとき必要 **
		clrf	ANSEL		;; すべてデジタルポート指定
		clrf	ANSELH		;;
		bcf	STATUS,RP1	;;バンク 1

		movlw	b'01110101'	;IRCF=111: 内部クロック周波数選択=8MHz
					;OSTS=0: 内部クロック
					;HTS=1: HFINTOSCステータスビット
					;SCS=1: システムクロック選択=内部クロック
		movwf	OSCCON

		movlw	b'11110000'	;RA7-4: 入力, RA3-0: 出力
		movwf	TRISA
		movlw	b'00000001'	;RB7-1: 出力, RB0: 入力
		movwf	TRISB
		clrf	TRISC		;RC7-0: 出力

		movlw	b'11000011'	;PBPU=1: プルアップ抵抗を使用しない
					;INTEDG=1: RB0/INTピンの立ち上がりで割り込み
					;T0CS=0: 内部クロックを使用
					;T0SE=0: タイマーカウントアップエッジ指定 = 立ち上がり
					;PSA=0: プリスケーラをタイマー０に使用
					;PS2-PS0=011: プリスケーラのスケール値 = 1:16
		movwf	OPTION_REG

		bcf	STATUS,RP0	;バンク 0
		movlw	h'00'		;bit7(GIE)=0: 全割り込み禁止,
					;bit5(T0IE)=0: タイマー０割り込み禁止,
					;bit4(INTE)=0: 外部割り込み(RB0/INT)禁止
		movwf	INTCON

		; 周波数切り替えジャンパの検出と定数設定

		clrf	PORTB
		bsf	PORTB,7		;R6(KBg) = ON
		nop
		movlw	50		;50Hz
		btfsc	PORTA,6		;K3(KB3), 切り替えジャンパ = ON か？
		movlw	60		;Yes. 60Hz
		movwf	f_const		;50/60Hz 定数を設定

		; AM/PM LED の点滅制御

		movwf	sec1_cnt	;点滅周期
		bcf	STATUS,C
		rrf	sec1_cnt,F	;1/2
		rrf	sec1_cnt,F	;1/4 秒にする

		bsf	INTCON,INTE	;bit4(INTE)=1: 外部割り込み(RB0/INT)許可
		bsf	INTCON,GIE	;bit7(GIE)=1: 全割り込み許可

		movlw	h'80'
		movwf	init_flg	;電源"ON" + CLKキー"ON" 以前の制御開始

start01		clrf	PORTB
		bsf	PORTB,1		;R0(MODE) = ON

		btfss	init_flg,0	;AM  か？
		bsf	PORTC,1		;Yes. O1(B) = ON, AM LED 点灯

		btfsc	init_flg,0	;PM か？
		bsf	PORTC,0		;Yes. O0(A) = ON, PM LED 点灯

		call	wait300us	;１桁の表示時間
		clrf	PORTC

		clrf	PORTB
		bsf	PORTB,6		;R5(KBf) = ON
		nop
		btfss	PORTA,6		;K3(KB3), CLK キー = ON か？
		goto	start01		;No

		clrf	PORTB
		clrf	init_flg	;電源"ON" + CLKキー"ON" 以前の制御終了

		movf	f_const,W	;50/60Hz 定数を設定
		movwf	sec1_cnt

		; 各変数の初期設定

		movlw	h'12'
		movwf	bcd_hh		;時_BCD カウンタの初期設定 = 12時
		clrf	bcd_mm		;分_BCD カウンタの初期設定 = 00分
		clrf	bcd_ss		;秒_BCD カウンタの初期設定 = 00秒
		movlw	1
		movwf	week_cnt	;WEEK カウンタの初期設定 = 1:SUN
		movwf	ox_week		;WEEK セグメント出力の初期設定 = SUN
		clrf	rx_sw		;RX SW リレー出力の初期設定
		clrf	mode_flg	;キー入力モードフラグの初期設定
		clrf	tmon_flg	;タイマー監視フラグの初期設定
		clrf	keycode		;キーコードの初期設定
		clrf	itv_flg		;インターバルフラグの初期設定
		clrf	err_flg		;入力エラーフラグの初期設定
		clrf	ext_flg		;拡張機能フラグの初期設定

		bsf	STATUS,RP0	;バンク 1
		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	3 * 20
		movwf	m_lp_cnt	;ループカウンタ

start02		clrf	INDF		;タイマー用メモリの初期設定
		incf	FSR,F		;間接アドレス +1 更新

		decfsz	m_lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	start02		;No

		bcf	STATUS,RP0	;バンク 0

		bsf	keycode,6	;キーコード別処理済みフラグ = ON
		movlw	tm0_h_val	;ハードタイマー０カウント値を
		movwf	TMR0		;TMR0 に設定
		movlw	tm0_s_val * 10	;ソフトタイマー０カウント値 * 10 = 500 mS を
		movwf	tm0_s_cnt	;ソフトタイマー０カウンタに設定
		bsf	INTCON,T0IE	;bit5(T0IE)=1: タイマー０割り込み許可

;	　　　（誤動作を避けるため、これ以降 500 mS 間はキー入力の受付を禁止にする）

;==========================================================================
;		メイン・ルーチン
;==========================================================================

; mode_flg: キー入力モードフラグ  bit0=0: 通常の時刻表示モード, bit0=1: キー入力中の表示モード

main
		btfsc	mode_flg,0	;キー入力モードフラグ = ON か？
		goto	main01		;Yes

		clrf	ox_sw		;SW セグメント出力の初期設定
		clrf	ox_mode		;MODE セグメント出力の初期設定
		movf	week_cnt,W	;WEEK カウンタ
		call	ox_week_out_x	;WEEK カウンタ値から OX 出力へ変換
		movf	bcd_hh,W
		movwf	temp_hh		;仮の 時_BCD カウンタ
		movf	bcd_mm,W
		movwf	temp_mm		;仮の 分_BCD カウンタ
		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		btfss	ext_flg,3	;Yes. 時間表示フラグ = ON か？ （0:12H / 1:24H）
		call	cnv_24to12	;No.  24時間表示を12時間表示に変換

main01		movlw	h'c0'
		andwf	keycode,F	;キーコードの初期設定

;-------------- R0(MODE) 桁の処理

		movlw	b'00000010'	;RX 桁出力位置 = R0
		movwf	PORTB		;R0(MODE) = ON

		movf	ox_mode,W
		movwf	PORTC		;OX(MODE) セグメント出力
		call	wait300us	;１桁の表示時間

		call	key_scan	;押されたキーコードを取得

		movlw	seg7_off
		movwf	PORTC		;OX(MODE) セグメント出力 = OFF

;-------------- R1(1st) 桁の処理

		movlw	b'00000100'	;RX 桁出力位置 = R1
		movwf	PORTB		;R1(1st) = ON

		movf	temp_mm,W
		andlw	h'0f'
		call	ptn_set		;表示パターンに変換

		btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	main02		;No

		btfsc	ext_flg,4	;COL LED 点滅制御 = ON か？
		iorlw	h'80'		;Yes. COL(上) LED 点灯

main02		movwf	PORTC		;OX(1st) セグメント出力
		call	wait300us	;１桁の表示時間

		call	key_scan	;押されたキーコードを取得

		movlw	seg7_off
		movwf	PORTC		;OX(1st) セグメント出力 = OFF

;-------------- R2(2nd) 桁の処理

		movlw	b'00001000'	;RX 桁出力位置 = R2
		movwf	PORTB		;R2(2nd) = ON

		swapf	temp_mm,W
		andlw	h'0f'
		call	ptn_set		;表示パターンに変換

		btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	main03		;No

		btfsc	ext_flg,4	;COL LED 点滅制御 = ON か？
		iorlw	h'80'		;Yes. COL(下) LED 点灯

main03		movwf	PORTC		;OX(2nd) セグメント出力
		call	wait300us	;１桁の表示時間

		call	key_scan	;押されたキーコードを取得

		movlw	seg7_off
		movwf	PORTC		;OX(2nd) セグメント出力 = OFF

;-------------- R3(3rd) 桁の処理

		movlw	b'00010000'	;RX 桁出力位置 = R3
		movwf	PORTB		;R3(3rd) = ON

		movf	temp_hh,W
		andlw	h'0f'
		call	ptn_set		;表示パターンに変換
		movwf	PORTC		;OX(3rd) セグメント出力
		call	wait300us	;１桁の表示時間

		call	key_scan	;押されたキーコードを取得

		movlw	seg7_off
		movwf	PORTC		;OX(3rd) セグメント出力 = OFF

;-------------- R4(4th) 桁の処理

		movlw	b'00100000'	;RX 桁出力位置 = R4
		movwf	PORTB		;R4(4th) = ON

		swapf	temp_hh,W
		andlw	h'0f'
		btfss	STATUS,Z	;0 か？
		goto	main04		;No

		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		btfss	ext_flg,3	;Yes. 時間表示フラグ（0:12H / 1:24H） = ON か？
		movlw	h'0a'		;No.  ゼロサプレス

main04		call	ptn_set		;表示パターンに変換
		movwf	PORTC		;OX(4th) セグメント出力
		call	wait300us	;１桁の表示時間

		call	key_scan	;押されたキーコードを取得

		movlw	seg7_off
		movwf	PORTC		;OX(4th) セグメント出力 = OFF

;-------------- R5(WEEK) 桁の処理

		movlw	b'01000000'	;RX 桁出力位置 = R5
		movwf	PORTB		;R5(WEEK) = ON

		movf	ox_week,W
		movwf	PORTC		;OX(WEEK) セグメント出力
		call	wait300us	;１桁の表示時間

		call	key_scan	;押されたキーコードを取得

		movlw	seg7_off
		movwf	PORTC		;OX(WEEK) セグメント出力 = OFF

;-------------- R6(SW) 桁の処理

		movlw	b'10000000'	;RX 桁出力位置 = R6
		movwf	PORTB		;R6(SW) = ON

		movf	ox_sw,W
		movwf	PORTC		;OX(SW) セグメント出力
		call	wait300us	;１桁の表示時間

		call	key_scan	;押されたキーコードを取得

		movlw	seg7_off
		movwf	PORTC		;OX(SW) セグメント出力 = OFF
		clrf	PORTB

;-------------- キー入力の監視とその処理

; keycode:	bit7:	キー入力受付済み表示フラグ ... key_scan で設定、interrupt で解除（キー ON  検出から  50 mS 後）
;		bit6:	キーコード別処理済みフラグ ... key_proc で設定、interrupt で解除（キー OFF 検出から 150 mS 後）
;		bit4-0:	(0-19): キーコード, (20): 拡張機能時12H/24Hキー, (21): キー入力なし表示

		movf	keycode,W
		andlw	h'c0'
		btfsc	STATUS,Z	;キー入力がある か？
		goto	main06		;No. ない

		btfsc	keycode,6	;コード別の処理 = 未 か？
		goto	main05		;No. 済み

		call	key_processing	;押されたキーコード別の処理
		goto	main06

main05		btfsc	keycode,7	;bit7=0 解除された か？
		goto	main06		;No. 解除前

		movf	keycode,W
		andlw	h'1f'
		sublw	21		;21: キー入力なし表示
		btfss	STATUS,Z	;キー入力がない か？
		goto	main06		;No. ある

		movf	tm0_s_cnt,W
		btfss	STATUS,Z	;タイマー０割り込みを監視中 か？
		goto	main06		;Yes

		; チャタリング(OFF)吸収の処理

		movlw	tm0_h_val	;ハードタイマー０カウント値を
		movwf	TMR0		;TMR0 に設定
		movlw	tm0_s_val * 3	;ソフトタイマー０カウント値 * 3 = 150 mS を
		movwf	tm0_s_cnt	;ソフトタイマー０カウンタに設定
		bsf	INTCON,T0IE	;bit5(T0IE)=1: タイマー０割り込み許可

;-------------- タイマーの監視とその処理

; tmon_flg:	bit0:	タイマー監視フラグ ... interrupt(bcd_ssmmhh_inc) で設定、time_monitor で解除

main06		btfsc	tmon_flg,0	;タイマー監視フラグ = ON か？
		call	time_monitor	;Yes

		goto	main

;==========================================================================
;		押されたキーコードを取得
;==========================================================================

; keycode:	bit7:	キー入力受付済み表示フラグ ... key_scan で設定、interrupt で解除
;		bit6:	キーコード別処理済みフラグ ... key_proc で設定、interrupt で解除
;		bit4-0:	(0-19): キーコード, (20): 拡張機能時12H/24Hキー, (21): キー入力なし表示

key_scan
		btfsc	keycode,7	;キー入力受付済み か？
		goto	kscan04		;Yes

		movf	PORTA,W		;キー入力
		andlw	h'f0'
		movwf	sw_stat		;スイッチの入力状態を一時保存

		; 拡張機能のチェック

		btfsc	sw_stat,7	;EXT JPスイッチ（このスイッチだけ逆論理）= OFF か？
		bcf	ext_flg,7	;Yes. bit7: 拡張機能フラグ = OFF
		btfss	sw_stat,7	;EXT JPスイッチ（このスイッチだけ逆論理）= ON か？
		bsf	ext_flg,7	;Yes. bit7: 拡張機能フラグ = ON

		; K1(KB1) から K3(KB3) をチェック

		btfsc	sw_stat,4	;K1(KB1) = ON か？
		goto	kscan03		;Yes

		movlw	7
		addwf	keycode,F	;keycode + 7
		btfsc	sw_stat,5	;K2(KB2) = ON か？
		goto	kscan03		;Yes

		movlw	7
		addwf	keycode,F	;keycode + 7
		btfsc	sw_stat,6	;K3(KB3) = ON か？
		goto	kscan02		;Yes

		; K1(KB1) から K3(KB3) のすべて OFF

		movlw	h'1f'
		andwf	keycode,W
		sublw	20
		btfsc	STATUS,Z	;keycode(bit4-0) = 20 か？
		goto	kscan01		;Yes

		movlw	13
		subwf	keycode,F	;keycode - 13
		goto	kscan04

kscan01		incf	keycode,F	;keycode(bit4-0) = 21: キー入力なし表示
		goto	kscan04

		; K3(KB3) が ON

kscan02		movlw	h'1f'
		andwf	keycode,W
		sublw	20
		btfss	STATUS,Z	;keycode(bit4-0) = 20 か？
		goto	kscan03		;No

		btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	kscan01		;No. 無視

		; K1(KB1) から K3(KB3) のどれか ON

kscan03		btfsc	keycode,6	;キーコード別処理済み か？
		goto	kscan04		;Yes

		bsf	keycode,7	;キー入力受付済み表示

		; チャタリング(ON)吸収の処理

		movlw	tm0_h_val	;ハードタイマー０カウント値を
		movwf	TMR0		;TMR0 に設定
		movlw	tm0_s_val	;ソフトタイマー０カウント値を
		movwf	tm0_s_cnt	;ソフトタイマー０カウンタに設定
		bsf	INTCON,T0IE	;bit5(T0IE)=1: タイマー０割り込み許可

kscan04		return

;==========================================================================
;		押されたキーコード別の処理
;==========================================================================

; keycode:	bit4-0:	(0-19): キーコード, (20): 拡張機能時12H/24Hキー, (21): キー入力なし表示

key_processing
		movf	keycode,W
		andlw	h'1f'
		movwf	wkcode		;キーコードだけを取り出す

		btfsc	err_flg,0	;入力エラーフラグ = ON か？
		goto	kproc000	;Yes

		btfsc	mode_flg,0	;キー入力モードフラグ = ON か？
		goto	kproc00		;Yes

		bsf	mode_flg,0	;キー入力モードフラグ = ON

kproc000	call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		clrf	fmmwwwss	;タイマー制御バイトの初期設定
		clrf	dsp_cnt		;表示カウンタの初期設定
		clrf	err_flg		;入力エラーフラグの初期設定

;----------------------------------------------------------------

kproc00		movlw	10
		subwf	wkcode,W
		btfsc	STATUS,C	;wkcode < 10 か？
		goto	kproc10		;No

		;; 数字キー (0 ～ 9) の処理
		; --------------------------

		btfss	fmmwwwss,7	;f bit = 1 (有効)  か？
		goto	kproc00a	;No

		call	clr_all_disp	;Yes. LED をすべて(コロンを除く)消灯
		bcf	fmmwwwss,7	;f bit = 0					;;

		btfss	mode_flg,2	;定時プログラムフラグ = ON か？、(追加フラグ)	;;
		goto	kproc00a	;No

		swapf	mode_flg,W
		andlw	h'03'
		movwf	ox_mode		;AM/PM を復帰

kproc00a	movlw	4		;左に 4 ビットシフト
		movwf	lp_cnt

kproc00b	bcf	STATUS,C
		rlf	temp_mm,F
		rlf	temp_hh,F
		decfsz	lp_cnt,F	;lp_cnt - 1 = 0 か？
		goto	kproc00b	;No

		movf	wkcode,W	;キーコードを
		iorwf	temp_mm,F	;分桁に加える

		movf	temp_hh,W
		andlw	h'f0'
		btfsc	STATUS,Z	;十時桁 = 0 か？
		goto	kproc00c	;Yes

		sublw	h'a0'
		btfss	STATUS,Z	;十時桁 = h'a' か？
		goto	kproc00g	;No
		goto	kproc00d	;Yes

kproc00c	movlw	h'a0'
		iorwf	temp_hh,F	;十時桁を h'a' に置き換える

kproc00d	movf	temp_hh,W
		andlw	h'0f'
		btfsc	STATUS,Z	;時桁 = 0 か？
		goto	kproc00e	;Yes

		sublw	h'0a'
		btfss	STATUS,Z	;時桁 = h'a' か？
		goto	kproc00g	;No
		goto	kproc00f	;Yes

kproc00e	movlw	h'0a'
		iorwf	temp_hh,F	;時桁を h'a' に置き換える

kproc00f	movf	temp_mm,W
		andlw	h'f0'
		btfss	STATUS,Z	;十分桁 = 0 か？
		goto	kproc00g	;No

		movlw	h'a0'
		iorwf	temp_mm,F	;十分桁を h'a' に置き換える

kproc00g	goto	kproczz

;----------------------------------------------------------------

kproc10		movlw	12
		subwf	wkcode,W
		btfsc	STATUS,C	;wkcode < 12 か？
		goto	kproc12		;No

		;; AM キー (10) ／ PM キー (11) の処理
		; -------------------------------------

		btfsc	fmmwwwss,7	;f bit = 1 (有効)  か？
		call	clr_all_disp	;Yes. LED をすべて(コロンを除く)消灯

		clrf	ox_mode
		btfss	wkcode,0	;AM キー(10) か？
		bsf	ox_mode,1	;Yes. O1(AM) = ON

		btfsc	wkcode,0	;PM キー(11) か？
		bsf	ox_mode,0	;Yes. O0(PM) = ON

		movlw	h'0f'
		andwf	mode_flg,F	;上位 4 ビットをクリア
		swapf	ox_mode,W
		iorwf	mode_flg,F	;AM/PM を退避
		goto	kproczz

;----------------------------------------------------------------

kproc12		movlw	14
		subwf	wkcode,W
		btfsc	STATUS,C	;wkcode < 14 か？
		goto	kproc14		;No

		;; WEEK キー (12) ／ SW キー (13) の処理
		; ---------------------------------------

;	X, WEEK,WEEK, ... WEEK,WEEK, ... WEEK,WEEK, .............. WEEK,WEEK, ... WEEK,WEEK, ... WEEK,WEEK, ...
;	:   :    :         :    :         :    :                    :    :         :    :         :    :
;	X WEEKX メモリ   WEEKX メモリ   WEEKX メモリ ............ WEEKX メモリ   WEEKX 全消灯   WEEKX メモリ
;	        1 表示         2 表示         3 表示                    n 表示                        1 表示

;	X,  SW,  SW,  ...  SW,  SW,  ...  SW,  SW,  ..............  SW,  SW,  ...  SW,  SW,  ...  SW,  SW,  ...
;	:   :    :         :    :         :    :                    :    :         :    :         :    :
;	X  SWX  メモリ    SWX  メモリ    SWX  メモリ ............  SWX  メモリ    SWX  全消灯    SWX  メモリ
;	        1 表示         2 表示         3 表示                    n 表示                        1 表示

;		fmmw.wwss	fmmw.wwss
;		   : ::		       ::
;		   0 00  EDAY	       01  SW1
;		   0 01  SUN	       10  SW2
;		   0 10  MON	       11  SW3
;		   0 11  TUE	       00  SW4
;		   1 00  WED
;		   1 01  THU
;		   1 10  FRI
;		   1 11  SAT

; dsp_cnt:	bit7: X,WEEK / X,SW 処理済みフラグ
;		bit6: LED 表示消灯フラグ、0: 表示 / 1: 消灯
;		bit5: タイマー用メモリ検索終了フラグ
;		bit4-0: 表示カウンタ

		movf	dsp_cnt,W
		btfss	STATUS,Z	;フラグと表示カウンタ = 0 か？
		goto	kproc12c	;No

		movf	temp_mm,W
		andlw	h'0f'
		movwf	gen_wk		;ワーク
		sublw	h'0a'
		btfsc	STATUS,Z	;temp_mm(bit3-0) = h'a' か？
		goto	kproc12e	;Yes						;;

		btfsc	wkcode,0	;WEEK キー(12) か？
		goto	kproc12a	;No. SW キー(13)

		; WEEK 番号（曜日）の取り込み（X,WEEK の処理）

		movlw	7 + 1
		subwf	gen_wk,W
		btfsc	STATUS,C	;temp_mm < 7 + 1 か？
		goto	kproc12g	;No. 無視(error)

		movf	gen_wk,W
		call	ox_week_out_x	;WEEK カウンタ値から OX 出力へ変換

		movlw	h'e3'
		andwf	fmmwwwss,F	;www 位置をクリア
		rlf	gen_wk,F
		rlf	gen_wk,W	;左に 2 ビットシフト
		andlw	h'1c'
		iorwf	fmmwwwss,F	;www 位置に加える
		goto	kproc12b

		; SW 番号の取り込み（X,SW の処理）

kproc12a	clrf	ox_week		;(TMS1121 original)
		movlw	4 + 1
		subwf	gen_wk,W
		btfsc	STATUS,C	;temp_mm < 4 + 1 か？
		goto	kproc12g	;No. 無視(error)

		movf	gen_wk,W
		call	ox_sw_out_x	;SW カウンタ値から OX 出力へ変換

		movlw	h'e0'		;h'fc'						;;
		andwf	fmmwwwss,F	;www,ss 位置をクリア
		movf	gen_wk,W
		andlw	h'03'		;下位 2 ビットを取り出し
		iorwf	fmmwwwss,F	;ss 位置に加える
		bsf	mode_flg,1	;X,SW 処理済みフラグ = ON、(追加フラグ)		;;

kproc12b	bsf	dsp_cnt,7	;X,WEEK / X,SW 処理済みフラグ = ON
		call	clr_numeric	;数字 LED を消灯
		goto	kproc12g

		; タイマー用メモリ内容の読み出し（(X),WEEK,WEEK ／ (X),SW,SW の処理）

kproc12c	btfss	dsp_cnt,5	;タイマー用メモリ検索終了フラグ = ON か？
		goto	kproc12d	;No

		movlw	h'80'
		andwf	dsp_cnt,F	;X,WEEK / X,SW 処理済みフラグ = ON を残す
		goto	kproc12f

kproc12d	btfsc	dsp_cnt,6	;LED 表示消灯フラグ = ON か？
		goto	kproc12f	;Yes

kproc12e	call	read_memory	;タイマー用メモリ内容の読み出し
		bsf	dsp_cnt,6	;LED 表示消灯フラグ = ON
		goto	kproc12g

kproc12f	call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		btfss	wkcode,0	;WEEK キー(12) か？
		call	ox_week_out	;Yes. WEEK カウンタ値から OX 出力へ変換
		btfsc	wkcode,0	;SW キー(13) か？
		call	ox_sw_out	;Yes. SW カウンタ値から OX 出力へ変換
		bcf	dsp_cnt,6	;LED 表示消灯フラグ = OFF

kproc12g	goto	kproczz

;----------------------------------------------------------------

kproc14		movlw	17
		subwf	wkcode,W
		btfsc	STATUS,C	;wkcode < 17 か？
		goto	kproc17		;No

		;; ON キー (14) ／ OFF キー (15) ／ SLP キー (16) の処理
		; -------------------------------------------------------

;		SW	AM/PM	WEEK	分桁
;		Ｘ	 ―	 ―	 ―	ERROR'9999'
;		○	 Ｘ	 ○	 ―	ERROR'9999'
;		○	 ○	 Ｘ	 ―	ERROR'9999'
;		○	 Ｘ	 Ｘ	 Ｘ	ダイレクト・コントロール （直接制御）
;		○	 Ｘ	 Ｘ	 ○	インターバル・タイマー （間隔プログラム）
;		○	 ○	 ○	 Ｘ	ダイレクト・コントロール （直接制御）..... (TMS1121 original)
;		○	 ○	 ○	 ○	タイマー （定時プログラム）

;		fmmw.wwss
;		 ::
;		 00  OFF
;		 01  ON
;		 10  SLP OFF
;		 11  SLP ON

	;;	movf	ox_sw,W
	;;	btfsc	STATUS,Z	;X,SW の指定済み か？
		btfss	mode_flg,1	;X,SW 処理済みフラグ = ON か？、(追加フラグ)
		goto	kproc99		;No. ERROR'9999'

		btfsc	wkcode,4	;SLP キー(16) か？
		goto	kproc14a	;Yes

		btfss	wkcode,0	;ON キー(14) か？
		bsf	ox_mode,5	;Yes. O5(ON) = ON
		btfsc	wkcode,0	;OFF キー(15) か？
		bsf	ox_mode,6	;Yes. O6(OFF) = ON
		movlw	h'9f'
		andwf	fmmwwwss,F	;mm bit をクリア
		btfss	wkcode,0	;ON キー(14) か？
		bsf	fmmwwwss,5	;Yes. mm bit = b'01'
		goto	kproc14b

kproc14a	bsf	ox_mode,7	;O7(SLP) = ON
		movlw	h'60'
		iorwf	fmmwwwss,F	;mm bit = b'11'

kproc14b	movf	ox_mode,W
		andlw	h'03'
		btfsc	STATUS,Z	;AM/PM の指定済み か？
		goto	kproc14c	;No

		movf	ox_week,W
		btfss	STATUS,Z	;X,WEEK の指定済み か？
		goto	kproc14g	;Yes. タイマー （定時プログラム）へ

		btfss	mode_flg,2	;定時プログラムフラグ = ON か？、(追加フラグ)	;;
		goto	kproc99		;No. ERROR'9999'

		call	ox_sw_out	;OX SW 出力へ変換
		call	ox_week_out	;OX WEEK 出力へ変換
		goto	kproc14g	;タイマー （定時プログラム）へ

kproc14c	movf	ox_week,W
		btfss	STATUS,Z	;X,WEEK の指定済み か？
		goto	kproc99		;Yes. ERROR'9999'

		movf	temp_mm,W	;分桁の指定
		andlw	h'0f'
		sublw	h'0a'
		btfsc	STATUS,Z	;分桁 = h'a' か？
		goto	kproc14d	;Yes. ダイレクト・コントロール （直接制御）へ

		call	ox_sw_out	;OX SW 出力へ変換
		goto	kproc14f	;インターバル・タイマー （間隔プログラム）へ

kproc14d	movf	ox_sw,W					;;
		btfsc	STATUS,Z	;X,SW の指定済み か？	;;
		goto	kproc99		;No. ERROR'9999'	;;

		btfsc	wkcode,4	;SLP キー(16) か？
		goto	kproc14e	;Yes

		; ON キー(14) ／ OFF キー(15) のダイレクト・コントロール （直接制御）

		movf	ox_sw,W
		btfss	wkcode,0	;ON キー(14) か？
		iorwf	PORTA,F		;Yes. リレーを ON

		xorlw	h'ff'
		btfsc	wkcode,0	;OFF キー(15) か？
		andwf	PORTA,F		;Yes. リレーを OFF

	;;	clrf	mode_flg	;キー入力モードフラグ = OFF
		bcf	mode_flg,0	;キー入力モードフラグ = OFF
		goto	kproc14h

		; SLP キー(16) のダイレクト・コントロール （直接制御）

kproc14e	movlw	1		;1 時間後のスリープタイマ時間
		movwf	temp_hh
		clrf	temp_mm
		call	interval_time	;インターバル時間の計算（24時間表示に変換）
		bcf	fmmwwwss,5	;mm bit = b'10' = (SLP + OFF)

		bsf	temp_hh,7	;メモリ自動消去フラグ = ON
		call	write_memory	;タイマー用メモリへの書き込み
		btfsc	STATUS,C	;C フラグ = 1 か？
		goto	kproc88		;Yes. ERROR'8888'、メモリオーバーエラー

		bcf	temp_hh,7	;メモリ自動消去フラグ = OFF
		call	cnv_24to12	;24時間表示を12時間表示に変換
		call	ox_week_out	;WEEK カウンタ値から OX 出力へ変換
		bcf	ox_mode,7	;O7(SLP) = OFF
		bsf	ox_mode,6	;O6(OFF) = ON

		movf	ox_sw,W
		iorwf	PORTA,F		;リレーを ON
		goto	kproc14h

		; インターバル・タイマー （間隔プログラム）

kproc14f	bsf	itv_flg,0	;インターバルフラグ = ON
		call	time_check	;入力された数字（時刻）の有効性チェック
		btfsc	STATUS,C	;エラー か？
		goto	kproc99		;Yes. ERROR'9999'

		call	interval_time	;インターバル時間の計算（24時間表示に変換）
		bsf	temp_hh,7	;メモリ自動消去フラグ = ON
		call	write_memory	;タイマー用メモリへの書き込み
		btfsc	STATUS,C	;C フラグ = 1 か？
		goto	kproc88		;Yes. ERROR'8888'、メモリオーバーエラー

		bcf	temp_hh,7	;メモリ自動消去フラグ = OFF
		call	cnv_24to12	;24時間表示を12時間表示に変換
		call	ox_week_out	;WEEK カウンタ値から OX 出力へ変換
		goto	kproc14h

		; タイマー （定時プログラム）

kproc14g	bcf	itv_flg,0	;インターバルフラグ = OFF
		call	time_check	;入力された数字（時刻）の有効性チェック
		btfsc	STATUS,C	;エラー か？
		goto	kproc99		;Yes. ERROR'9999'

		btfsc	STATUS,Z	;分桁 = h'a' か？
		goto	kproc14d	;Yes. (TMS1121 original)

		movf	temp_hh,W	;仮の 時_BCD カウンタ
		movwf	gen_wk		;ワークに退避
		call	cnv_12to24	;12時間表示を24時間表示に変換
		call	write_memory	;タイマー用メモリへの書き込み
		btfsc	STATUS,C	;C フラグ = 1 か？
		goto	kproc88		;Yes. ERROR'8888'、メモリオーバーエラー

		movf	gen_wk,W	;ワークから復帰
		movwf	temp_hh		;仮の 時_BCD カウンタ
		bsf	mode_flg,2	;定時プログラムフラグ = ON、(追加フラグ)	;;

kproc14h	goto	kproczz

;----------------------------------------------------------------

kproc17	;	movlw	17
	;	subwf	wkcode,W
		btfss	STATUS,Z	;wkcode = 17 か？
		goto	kproc18		;No

		;; CLR キー (17) の処理
		; ----------------------

		bcf	mode_flg,1	;X,SW 処理済みフラグ = OFF、(追加フラグ)	;;
		bcf	mode_flg,2	;定時プログラムフラグ = OFF、(追加フラグ)	;;
		clrf	fmmwwwss	;タイマー制御バイトの初期設定
		call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		goto	kproczz

;----------------------------------------------------------------

kproc18		movlw	19
		subwf	wkcode,W
		btfsc	STATUS,C	;wkcode < 19 か？
		goto	kproc19		;No

		;; MCLR キー (18) の処理
		; -----------------------

		movlw	h'03'
		movf	ox_sw,F
		btfss	STATUS,Z	;X,SW の処理済み か？
		goto	kproc18a	;Yes

		movlw	h'1c'
		movf	ox_week,F
		btfsc	STATUS,Z	;X,WEEK の処理済み か？
		goto	kproc18d	;No

		; X,SW,MCLR ／ X,WEEK,MCLR の処理

kproc18a	bsf	STATUS,RP0	;バンク 1
		movwf	m_gen_wk	;ワーク
		bcf	STATUS,RP0	;バンク 0
		movf	fmmwwwss,W	;タイマー制御バイト
		bsf	STATUS,RP0	;バンク 1
		movwf	m_fmmwwwss

		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	m_lp_cnt	;ループカウンタ

kproc18b	btfss	INDF,7		;(タイマー制御バイト) の f bit = 1 (有効) か？
		goto	kproc18c	;No

		movf	m_fmmwwwss,W
		andwf	m_gen_wk,W	;ss / www bit を取り出し
		xorwf	INDF,W		;比較する
		andwf	m_gen_wk,W
		btfsc	STATUS,Z	;ss / www bit は等しい か？
		clrf	INDF		;Yes. 消去

kproc18c	movlw	3
		addwf	FSR,F		;間接アドレス +3 更新
		decfsz	m_lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	kproc18b	;No

		bcf	STATUS,RP0	;バンク 0
		goto	kproc18g

		; MCLR の処理（全消去）

kproc18d	btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	kproc18e	;No

		incf	ext_flg,F	;bit2-0: MCLR カウンタ +1 更新
		movf	ext_flg,W
		andlw	h'07'
		sublw	5		;連続で 5 回
		btfss	STATUS,Z	;MCLR カウンタ = 5 か？
		goto	kproc18h	;No

		movlw	h'f8'
		andwf	ext_flg,F	;MCLR カウンタをクリア

kproc18e	bsf	STATUS,RP0	;バンク 1
		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	3 * 20
		movwf	m_lp_cnt	;ループカウンタ

kproc18f	clrf	INDF		;消去
		incf	FSR,F		;間接アドレス +1 更新
		decfsz	m_lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	kproc18f	;No

		bcf	STATUS,RP0	;バンク 0
		btfss	ext_flg,7	;拡張機能フラグ = ON か？
		clrf	PORTA		;No. （リレー）制御用出力ポートの初期設定

kproc18g	clrf	mode_flg	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,0	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,1	;X,SW 処理済みフラグ = OFF、(追加フラグ) (反 TMS1121 original)

kproc18h	goto	kproc19a

;----------------------------------------------------------------

kproc19	;	movlw	19
	;	subwf	wkcode,W
		btfss	STATUS,Z	;wkcode = 19 か？
		goto	kproc20		;No

		;; CLK キー (19) の処理
		; ----------------------

		btfsc	fmmwwwss,7	;f bit = 1 (有効)  か？
		goto	kproc19a	;Yes

		movf	ox_week,W	;WEEK セグメント出力
		btfsc	STATUS,Z	;指定されている か？
		goto	kproc19a	;No

		movf	ox_mode,W	;MODE セグメント出力
		andlw	h'03'
		btfsc	STATUS,Z	;AM/PM が指定されている か？
		goto	kproc19a	;No

		; 入力された数字（時刻）の有効性チェック

		clrf	itv_flg		;インターバルフラグ = OFF
		call	time_check	;有効性チェック
		btfsc	STATUS,C	;エラー か？
		goto	kproc99		;Yes. ERROR'9999'

		btfsc	STATUS,Z	;分桁 = h'a' か？
		goto	kproc19a	;Yes

		; 新しい曜日、時刻に設定変更

		rrf	fmmwwwss,F	;www bit を右に 2 ビットシフト
		rrf	fmmwwwss,W
		andlw	h'07'		;www bit を取り出す
		btfsc	STATUS,Z	;www bit = 0: EDAY か？
	;;	goto	kproc99		;Yes. ERROR'9999'
		movlw	1		;Yes. (TMS1121 original)

		movwf	week_cnt	;新 WEEK を設定
		call	cnv_12to24	;12時間表示を24時間表示に変換
		movf	temp_hh,W
		movwf	bcd_hh		;時_BCD カウンタの更新
		movf	temp_mm,W
		movwf	bcd_mm		;分_BCD カウンタの更新

kproc19a	clrf	ox_week
		clrf	mode_flg	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,0	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,1	;X,SW 処理済みフラグ = OFF、(追加フラグ) (反 TMS1121 original)
		goto	kproczz

;----------------------------------------------------------------

		;; 12H/24H キー (20) の処理 (拡張機能)
		; -------------------------------------

kproc20		movlw	8
		xorwf	ext_flg,F	;bit3: 時間表示フラグ（0:12H / 1:24H）を更新
	;;	clrf	mode_flg	;キー入力モードフラグ = OFF
		bcf	mode_flg,0	;キー入力モードフラグ = OFF
		goto	kproczz

;----------------------------------------------------------------

		;; エラー表示 (ERROR'8888')

kproc88		movlw	h'88'
		goto	$ + 2

		;; エラー表示 (ERROR'9999')

kproc99		movlw	h'99'

		movwf	temp_mm
		movwf	temp_hh
		clrf	ox_mode		;MODE セグメント出力の初期設定
		clrf	ox_week		;WEEK セグメント出力の初期設定
		clrf	ox_sw		;SW セグメント出力の初期設定
		bsf	err_flg,0	;入力エラーフラグ = ON

;----------------------------------------------------------------

		; 後処理

kproczz		movlw	12
		subwf	wkcode,W
		btfsc	STATUS,Z	;wkcode = 12: WEEK キー か？
		goto	kprocz1		;Yes

		movlw	13
		subwf	wkcode,W
		btfss	STATUS,Z	;wkcode = 13: SW キー か？
		clrf	dsp_cnt		;No. 表示カウンタの初期設定

kprocz1		movlw	18
		subwf	wkcode,W
		movlw	h'f8'
		btfss	STATUS,Z	;wkcode = 18: MCLR キー か？
		andwf	ext_flg,F	;No. MCLR カウンタをクリア

		bsf	keycode,6	;キーコード別処理済みフラグ = ON
		return

;==========================================================================
;==========================================================================

		; WEEK カウンタ値から OX WEEK 出力へ変換

ox_week_out
		movf	fmmwwwss,W
		movwf	lp_cnt		;ワーク
		rrf	lp_cnt,F	;www bit を右に 2 ビットシフト
		rrf	lp_cnt,W
		andlw	h'07'		;www bit = 0 か？

ox_week_out_x
		btfsc	STATUS,Z
		goto	oxwk02		;Yes

		movwf	lp_cnt		;ループカウンタ
		movlw	h'01'
		movwf	ox_week		;WEEK セグメント出力の初期値

oxwk01		decf	lp_cnt,F
		btfsc	STATUS,Z	;lp_cnt - 1 = 0 か？
		goto	oxwk03		;Yes

		bcf	STATUS,C
		rlf	ox_week,F	;WEEK セグメント出力を左に 1 ビットシフト
		goto	oxwk01

oxwk02		movlw	h'7f'
		movwf	ox_week		;EDAY をセット

oxwk03		return

;==========================================================================

		; SW カウンタ値から OX SW 出力へ変換

ox_sw_out
		movf	fmmwwwss,W
		andlw	h'03'

ox_sw_out_x
		btfsc	STATUS,Z	;ss bit = 0 か？
		movlw	4		;Yes

		movwf	lp_cnt		;ループカウンタ
		movlw	h'01'
		movwf	ox_sw		;SW セグメント出力の初期値

oxsw01		decf	lp_cnt,F
		btfsc	STATUS,Z	;lp_cnt - 1 = 0 か？
		goto	oxsw02		;Yes

		bcf	STATUS,C
		rlf	ox_sw,F		;SW セグメント出力を左に 1 ビットシフト
		goto	oxsw01

oxsw02		return

;==========================================================================

		; ON/OFF/SLP を OX MODE 出力へ変換

;		fmmw.wwss		  →	ox_mode: 7654.3210
;		 ::		    (LED)		 :::    ::
;		 00  OFF	...  OFF		 :::    ::. PM
;		 01  ON		...  ON			 :::    :.. AM
;		 10  SLP OFF	...  OFF		 :::. ON
;		 11  SLP ON	...  SLP		 ::.. OFF
;							 :... SLP

ox_mode_out
		movlw	h'03'
		andwf	ox_mode,F	;ON/OFF/SLP をクリア
		movlw	b'01000000'	;bit6: OFF LED
		btfss	fmmwwwss,5	;ON か？
		goto	oxmod01		;No. OFF,SLP(OFF)

		movlw	b'00100000'	;bit5: ON LED
		btfss	fmmwwwss,6	;SLP(ON) か？
		goto	oxmod01		;No. ON
					;Yes. SLP(ON)
		movlw	b'10000000'	;bit7: SLP LED

oxmod01		iorwf	ox_mode,F
		return

;==========================================================================

		; LED をすべて(コロンを除く)消灯
clr_all_disp
		clrf	ox_mode		;MODE セグメント出力の初期設定
		clrf	ox_week		;WEEK セグメント出力の初期設定
		clrf	ox_sw		;SW セグメント出力の初期設定

		; 数字 LED を消灯
clr_numeric
		movlw	h'aa'		;初期設定
		movwf	temp_mm		;仮の 分_BCD カウンタの初期設定
		movwf	temp_hh		;仮の 時_BCD カウンタの初期設定
		return

;==========================================================================
;		入力された数字（時刻）の有効性チェック
;==========================================================================

; 出力フラグ:	Z=0, C=0: OK
;		Z=?, C=1: ERR
;		Z=1, C=0: 分桁 temp_mm(bit3-0) = h'a'

time_check
		movf	temp_hh,W
		andlw	h'f0'
		sublw	h'a0'
		btfss	STATUS,Z	;十時桁 = h'a' か？
		goto	timck01		;No

		movlw	h'0f'
		andwf	temp_hh,F	;十時桁 = 0 に置き換える

		movf	temp_hh,W
	;	andlw	h'0f'
		sublw	h'0a'
		btfss	STATUS,Z	;時桁 = h'a' か？
		goto	timck01		;No

		movlw	h'12'
		btfsc	itv_flg,0	;インターバルフラグ = ON か？
		movlw	h'00'		;Yes
		movwf	temp_hh		;temp_hh = h'12' / h'00' に置き換える

timck01		movlw	h'13'
		btfsc	itv_flg,0	;インターバルフラグ = ON か？
		movlw	h'12'		;Yes
		subwf	temp_hh,W
		btfsc	STATUS,C	;temp_hh < h'13' / h'12' か？
		goto	timck03		;No. ERROR'9999'

		movf	temp_mm,W
		andlw	h'f0'
		sublw	h'a0'
		btfss	STATUS,Z	;十分桁 = h'a' か？
		goto	timck02		;No

		movlw	h'0f'
		andwf	temp_mm,F	;十分桁 = 0 に置き換える

		movf	temp_mm,W
	;	andlw	h'0f'
		sublw	h'0a'
		btfsc	STATUS,Z	;分桁 = h'a' か？
		goto	timck03		;Yes

timck02		movlw	h'60'
		subwf	temp_mm,W
	;	btfsc	STATUS,C	;temp_mm < h'60' か？
	;	goto	timck03		;No. ERROR'9999'

timck03		return

;==========================================================================
;		24時間表示を12時間表示に変換
;==========================================================================

;(24H) 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 
;(12H) 12 01 02 03 04 05 06 07 08 09 10 11 12 01 02 03 04 05 06 07 08 09 10 11
;      am am am am am am am am am am am am pm pm pm pm pm pm pm pm pm pm pm pm
;                                          -----------------------------------
;     +12                                 -12
;    ( 12 ef f0 f1 f2 f3 f4 f5 f6 f7 fe ff 00 01 02 03 04 05 06 07 0e 0f 10 11 )

cnv_24to12
		movf	temp_hh,W
		btfss	STATUS,Z	;仮の 時_BCD カウンタ = h'00' か？
		goto	cnv01		;No

		movlw	h'12'
		movwf	temp_hh		;仮の 時_BCD カウンタ temp_hh = h'12'
		goto	cnv02

cnv01		movlw	h'12'
		subwf	temp_hh,W
		btfsc	STATUS,C	;仮の時_BCD カウンタ < h'12' か？
		goto	cnv03		;No

cnv02		bsf	ox_mode,1	;O1(AM) = ON
		goto	cnv05

cnv03		btfsc	STATUS,Z	;仮の時_BCD カウンタ = h'12' か？
		goto	cnv04		;Yes

		movwf	temp_hh		;仮の時_BCD カウンタ temp_hh = temp_hh - 12
		movlw	h'0e'
		subwf	temp_hh,W
		btfss	STATUS,C	;仮の時_BCD カウンタ >= h'0e' か？
		goto	cnv04		;No

		movlw	h'10'
		subwf	temp_hh,W
		btfsc	STATUS,C	;仮の時_BCD カウンタ < h'10' か？
		goto	cnv04		;No

		movlw	h'06'
		subwf	temp_hh,F	;補正

cnv04		bsf	ox_mode,0	;O0(PM) = ON

cnv05		return

;==========================================================================
;		12時間表示を24時間表示に変換
;==========================================================================

cnv_12to24
		movf	temp_hh,W
		sublw	h'12'
		btfsc	STATUS,Z	;仮の 時_BCD カウンタ = h'12' か？
		clrf	temp_hh		;Yes

		btfss	ox_mode,0	;O0(PM) = ON か？
		goto	cnv11		;No

		movlw	h'12'
		addwf	temp_hh,F	;仮の時_BCD カウンタ temp_hh = temp_hh + 12

		movlw	h'19' + 1
		subwf	temp_hh,W
		btfss	STATUS,C	;仮の時_BCD カウンタ < h'19' + 1 か？
		goto	cnv11		;Yes

		movlw	h'22'
		subwf	temp_hh,W
		btfsc	STATUS,C	;仮の時_BCD カウンタ =< h'22' か？
		goto	cnv11		;No

		movlw	h'06'
		addwf	temp_hh,F	;補正

cnv11		return

;==========================================================================
;		インターバル時間の計算（24時間表示に変換）
;==========================================================================

interval_time
		; 本日の曜日（www bit）

		movlw	h'e3'
		andwf	fmmwwwss,F	;www bit をクリア
		movf	week_cnt,W	;WEEK カウンタ（本日）
		movwf	gen_wk		;ワーク
		rlf	gen_wk,F
		rlf	gen_wk,W	;左に 2 ビットシフト
		andlw	h'1c'
		iorwf	fmmwwwss,F	;www 位置に加える

		; 分の計算

		movf	bcd_mm,W
		addwf	temp_mm,F	;仮の 分_BCD カウンタ
		movf	temp_mm,W
		andlw	h'0f'		;下位4ビット
		sublw	h'09'		;9 - W
		movlw	h'06'
		btfss	STATUS,C	;下位4ビット > 9 か？
		addwf	temp_mm,F	;Yes. 下位4ビット = +6, (上位4ビット = +1)

		movf	temp_mm,W
		sublw	h'59'		;h'59' - W
		btfsc	STATUS,C	;仮の 分_BCD カウンタ > h'59' か？
		goto	itval01		;No. OK

		movlw	h'60'
		subwf	temp_mm,F	;仮の 分_BCD カウンタ - h'60'
		incf	temp_hh,F	;仮の 時_BCD カウンタ +1

		; 時の計算

itval01		movf	bcd_hh,W
		addwf	temp_hh,F	;仮の 時_BCD カウンタ
		movf	temp_hh,W
		andlw	h'0f'		;下位4ビット
		sublw	h'09'		;9 - W
		movlw	h'06'
		btfss	STATUS,C	;下位4ビット > 9 か？
		addwf	temp_hh,F	;Yes. 下位4ビット = +6, (上位4ビット = +1)

		movf	temp_hh,W
		sublw	h'23'		;h'23' - W
		btfsc	STATUS,C	;仮の 時_BCD カウンタ > h'23' か？
		goto	itval03		;No. OK

		movlw	h'24'
		subwf	temp_hh,F	;仮の 時_BCD カウンタ - h'24'

		; 曜日の更新

		movf	fmmwwwss,W
		andlw	h'1c'		;www bit
		addlw	h'04'		;www bit + 1
		andlw	h'1c'		;www bit
		btfsc	STATUS,Z	;www bit = 8 か？
		goto	itval02		;Yes

		movlw	h'04'
		addwf	m_fmmwwwss,F	;www bit + 1
		goto	itval03

itval02		movlw	h'e3'
		andwf	fmmwwwss,F	;www bit をクリア
		bsf	fmmwwwss,2	;www bit = 1

itval03		return

;==========================================================================
;	(X),WEEK,WEEK ／ (X),SW,SW 時のタイマー用メモリの読み出し
;==========================================================================

read_memory
		movf	fmmwwwss,W	;タイマー制御バイト
		bsf	STATUS,RP0	;バンク 1
		movwf	m_fmmwwwss
		bcf	STATUS,RP0	;バンク 0
		movf	dsp_cnt,W	;表示カウンタ
		andlw	h'1f'
		bsf	STATUS,RP0	;バンク 1
		movwf	m_dsp_cnt
		bcf	STATUS,RP0	;バンク 0
		movf	wkcode,W	;キーコードワーク
		bsf	STATUS,RP0	;バンク 1
		movwf	m_gen_wk	;ワーク

		; タイマー用メモリの検索

		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	m_lp_cnt	;ループカウンタ

rdmem01		btfss	INDF,7		;fmmwwwss の f bit = 1 (有効) か？
		goto	rdmem04		;No

		movf	m_fmmwwwss,W
		btfsc	m_gen_wk,0	;WEEK キー(12) か？
		goto	rdmem02		;No. SW キー(13)

		andlw	h'1c'		;www bit を取り出し
		xorwf	INDF,W		;比較する
		andlw	h'1c'
		goto	rdmem03

rdmem02		andlw	h'03'		;ss bit を取り出し
		xorwf	INDF,W		;比較する
		andlw	h'03'

rdmem03		btfss	STATUS,Z	;www / ss bit は等しい か？
		goto	rdmem04		;No

		movf	m_dsp_cnt,W
		btfsc	STATUS,Z	;表示カウンタ = 0 か？
		goto	rdmem05		;Yes

		decf	m_dsp_cnt,F	;表示カウンタ - 1

rdmem04		movlw	3
		addwf	FSR,F		;間接アドレス +3 更新
		decfsz	m_lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	rdmem01		;No

		bcf	STATUS,RP0	;バンク 0
		bsf	dsp_cnt,5	;タイマー用メモリ検索終了フラグ = ON
		call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		goto	rdmem06

		; タイマー用メモリの読み出しと内容表示

rdmem05		movf	INDF,W		;
		bcf	STATUS,RP0	;バンク 0
		movwf	fmmwwwss	;タイマー制御バイト
		bsf	STATUS,RP0	;バンク 1
		incf	FSR,F		;間接アドレス +1 更新
		movf	INDF,W		;
		bcf	STATUS,RP0	;バンク 0
		andlw	h'7f'		;メモリ自動消去フラグ = OFF
		movwf	temp_hh		;時_BCD カウンタ
		bsf	STATUS,RP0	;バンク 1
		incf	FSR,F		;間接アドレス +1 更新
		movf	INDF,W		;
		bcf	STATUS,RP0	;バンク 0
		movwf	temp_mm		;分_BCD カウンタ
		incf	dsp_cnt,F	;表示カウンタの更新

		clrf	ox_mode
		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		btfss	ext_flg,3	;Yes. 時間表示フラグ = ON か？ （0:12H / 1:24H）
		call	cnv_24to12	;No. 24時間表示を12時間表示に変換
		call	ox_week_out	;WEEK カウンタ値から OX 出力へ変換
		call	ox_sw_out	;SW カウンタ値から OX 出力へ変換
		call	ox_mode_out	;ON/OFF/SLP を OX 出力へ変換

rdmem06		return

;==========================================================================
;		タイマー用メモリへの書き込み
;==========================================================================

write_memory
		bsf	STATUS,RP0	;バンク 1
		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	m_lp_cnt	;ループカウンタ

wrmem01		btfss	INDF,7		;fmmwwwss の f bit = 1 (有効) か？
		goto	wrmem02		;No. 空き

		movlw	3
		addwf	FSR,F		;間接アドレス +3 更新
		decfsz	m_lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	wrmem01		;No

		bsf	STATUS,C	;C フラグ = 1、メモリオーバーエラー表示
		goto	wrmem03		;ERROR'8888'

wrmem02		bcf	STATUS,RP0	;バンク 0
		bsf	fmmwwwss,7	;f bit = 1 (有効) にする
		movf	fmmwwwss,W
		bsf	STATUS,RP0	;バンク 1
		movwf	INDF		;(タイマー制御バイト) へ書き込み
		incf	FSR,F		;間接アドレス +1 更新

		bcf	STATUS,RP0	;バンク 0
		movf	temp_hh,W
		bsf	STATUS,RP0	;バンク 1
		movwf	INDF		;(時_BCD カウンタバイト) へ書き込み
		incf	FSR,F		;間接アドレス +1 更新

		bcf	STATUS,RP0	;バンク 0
		movf	temp_mm,W
		bsf	STATUS,RP0	;バンク 1
		movwf	INDF		;(分_BCD カウンタバイト) へ書き込み

		bcf	STATUS,C	;C フラグ = 0、書き込み済み

wrmem03		bcf	STATUS,RP0	;バンク 0
		return

;==========================================================================
;		タイマー用メモリの構成
;==========================================================================

; １メモリ単位 ... (タイマー制御バイト)、(時_BCD カウンタバイト)、(分_BCD カウンタバイト)

; (タイマー制御バイト) ／ fmmwwwss ／ m_fmmwwwss

;		fmmw.wwss	fmmw.wwss	fmmw.wwss	fmmw.wwss
;		:		 ::		   : ::		       ::
;		0  メモリ無効	 00  OFF	   0 00  EDAY	       01  SW1
;		1  メモリ有効	 01  ON		   0 01  SUN	       10  SW2
;				 10  SLP OFF	   0 10  MON	       11  SW3
;				 11  SLP ON	   0 11  TUE	       00  SW4
;						   1 00  WED
;						   1 01  THU
;						   1 10  FRI
;						   1 11  SAT

; (時_BCD カウンタバイト)

;		chhh.hhhh		chhh.hhhh	chhh.hhhh
;		:			 :::		     ::::
;		1 メモリ自動消去有効	 十時(0～2)	     時(0～9)

; (分_BCD カウンタバイト)

;					mmmm.mmmm	mmmm.mmmm
;					::::		     ::::
;					十分(0～5)	     分(0～9)

;==========================================================================
;		タイマーの監視とその処理
;==========================================================================

time_monitor
		movf	week_cnt,W	;WEEK カウンタ
		bsf	STATUS,RP0	;バンク 1
		movwf	m_week_cnt
		bcf	STATUS,RP0	;バンク 0
		movf	bcd_hh,W	;時_BCD カウンタ
		bsf	STATUS,RP0	;バンク 1
		movwf	m_bcd_hh
		bcf	STATUS,RP0	;バンク 0
		movf	bcd_mm,W	;分_BCD カウンタ
		bsf	STATUS,RP0	;バンク 1
		movwf	m_bcd_mm

		bcf	STATUS,C
		rlf	m_week_cnt,F	;WEEK カウンタ
		rlf	m_week_cnt,F	;左に 2 ビットシフト

		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	m_lp_cnt	;ループカウンタ

tmon01		btfss	INDF,7		;fmmwwwss の f bit = 1 (メモリ有効) か？
		goto	tmon10		;No

		movf	INDF,W
		andlw	h'1c'		;www bit を取り出す
		btfsc	STATUS,Z	;www bit = 0: EDAY か？
		goto	tmon02		;Yes

		xorwf	m_week_cnt,W
		btfss	STATUS,Z	;WEEK カウンタは等しいか？
		goto	tmon10		;No

tmon02		movf	INDF,W
		movwf	m_fmmwwwss	;fmmwwwss を一旦退避

		incf	FSR,F		;間接アドレス +1 更新、(時_BCD カウンタバイト)
		movf	INDF,W
		andlw	h'7f'		;メモリ自動消去フラグを削除
		subwf	m_bcd_hh,W
		btfss	STATUS,Z	;時_BCD カウンタは等しいか？
		goto	tmon11		;No

		incf	FSR,F		;間接アドレス +1 更新、(分_BCD カウンタバイト)
		movf	INDF,W
		subwf	m_bcd_mm,W
		btfss	STATUS,Z	;分_BCD カウンタは等しいか？
		goto	tmon12		;No

		; WEEK, 時, 分が等しいときの出力（リレー）制御

		movf	m_fmmwwwss,W	;fmmwwwss を復帰

		bcf	STATUS,RP0	;バンク 0
		movwf	gen_wk		;タイマー制御バイトをワークへ

		andlw	h'03'		;ss bit を取り出す
		movwf	lp_cnt
		btfsc	STATUS,Z
		bsf	lp_cnt,2	;0 のときは 4 にする

		movlw	h'01'
		movwf	rx_sw		;RX(SW) 出力の初期値

tmon03		decf	lp_cnt,F
		btfsc	STATUS,Z	;lp_cnt - 1 = 0 か？
		goto	tmon04		;Yes

		bcf	STATUS,C
		rlf	rx_sw,F		;RX(SW) 出力を左に 1 ビットシフト
		goto	tmon03

tmon04		movf	rx_sw,W
		btfsc	gen_wk,5	;mm bit = x1: ON 出力 か？
		iorwf	PORTA,F		;Yes. リレーを ON

		xorlw	h'ff'
		btfss	gen_wk,5	;mm bit = x0: OFF 出力 か？
		andwf	PORTA,F		;Yes. リレーを OFF

		; メモリの自動消去

		bsf	STATUS,RP0	;バンク 1
		decf	FSR,F		;間接アドレス -1 更新、(時_BCD カウンタバイト)
		btfss	INDF,7		;メモリ自動消去フラグ = 1 か？
		goto	tmon06		;No

		btfss	m_fmmwwwss,6	;mm bit = 1x: SLP か？
		goto	tmon05		;No

		btfsc	m_fmmwwwss,5	;mm bit = 10: OFF か？
		goto	tmon07		;No

tmon05		decf	FSR,F		;間接アドレス -1 更新、(タイマー制御バイト)
	;;	bcf	INDF,7		;f bit = 0
		clrf	INDF		;メモリの消去
		goto	tmon10		;No

		; SLP のときのメモリ内容変更

tmon06		btfss	m_fmmwwwss,6	;mm bit = 1x: SLP か？
		goto	tmon11		;No

tmon07		decf	FSR,F		;間接アドレス -1 更新、(タイマー制御バイト)
		movlw	h'20'
		xorwf	INDF,F		;ON/OFF ビットを反転

		incf	FSR,F		;間接アドレス +1 更新、(時_BCD カウンタバイト)
		btfsc	m_fmmwwwss,5	;変更前の mm bit = 10: OFF 出力 か？
		goto	tmon08		;No. ON 出力

		; ON 出力時間に変更（メモリ自動消去フラグ = 1 のものはない）
		call	dec_bcd		;時_BCD カウンタバイト - 1
		movlw	h'f9'		;h'00' - h'01' - h'06'
		subwf	INDF,W
		btfss	STATUS,Z	;時_BCD カウンタ = h'f9' か？
		goto	tmon11		;No

		movlw	h'23'
		movwf	INDF		;時_BCD カウンタ = h'23' 設定

		movlw	h'1c'
		andwf	m_fmmwwwss,F
		btfsc	STATUS,Z	;www bit = 0: EDAY か？
		goto	tmon11		;Yes

		movlw	h'04'
		subwf	m_fmmwwwss,F	;www bit を - 1
		btfss	STATUS,Z	;www bit = 0 か？
		goto	tmon09		;No

		movlw	h'1c'
		movwf	m_fmmwwwss	;www bit = 7 にする
		goto	tmon09

		; OFF 出力時間に変更
tmon08		movf	INDF,W
		movwf	m_gen_wk	;時_BCD カウンタバイトを一旦退避
		bcf	INDF,7		;メモリ自動消去フラグ = 0
		call	inc_bcd		;時_BCD カウンタバイト + 1
		movlw	h'24'
		subwf	INDF,W
		btfsc	STATUS,C	;時 BCD カウンタ < h'24' か？
		clrf	INDF		;No. 時 BCD カウンタのクリア
		btfsc	m_gen_wk,7	;メモリ自動消去フラグ = 1 か？
		bsf	INDF,7		;Yes. メモリ自動消去フラグ = 1
		movlw	h'7f'
		andwf	INDF,W
		btfss	STATUS,Z	;時_BCD カウンタ = 0 か？
		goto	tmon11		;No

		movlw	h'1c'
		andwf	m_fmmwwwss,F
		btfsc	STATUS,Z	;www bit = 0: EDAY か？
		goto	tmon11		;Yes

		movlw	h'04'
		addwf	m_fmmwwwss,F	;www bit を + 1
		btfss	m_fmmwwwss,5	;www bit = 8 か？
		goto	tmon09		;No

		movlw	h'04'
		movwf	m_fmmwwwss	;www bit = 1 にする

		; WEEK を変更
tmon09		decf	FSR,F		;間接アドレス -1 更新、(タイマー制御バイト)
		movlw	h'e3'
		andwf	INDF,F		;www bit をクリア
		movwf	m_fmmwwwss	;www bit
		iorwf	INDF,F		;新しい www bit に更新

tmon10		incf	FSR,F		;(時_BCD カウンタバイト)

tmon11		incf	FSR,F		;(分_BCD カウンタバイト)

tmon12		incf	FSR,F		;(次の タイマー制御バイト)
		decfsz	m_lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	tmon01		;No

		bcf	STATUS,RP0	;バンク 0
		bcf	tmon_flg,0	;タイマー監視フラグ = OFF
		return

;--------------------------------------------------------------------------

;		BCD インクリメント

inc_bcd
		incf	INDF,F		;BCD カウンタ +1 更新
		movf	INDF,W
		andlw	h'0f'		;下位4ビット
		sublw	h'0a'
		btfss	STATUS,Z	;下位4ビット = d'10' か？
		return			;No

		movlw	h'06'
		addwf	INDF,F		;下位4ビット = 0, 上位4ビット = +1
		return

;--------------------------------------------------------------------------

;		BCD デクリメント

dec_bcd
		movf	INDF,W
		andlw	h'0f'		;下位4ビット
		btfsc	STATUS,Z	;下位4ビット <> h'00' か？
		goto	dec01		;No

		decf	INDF,F		;-1 更新
		return

dec01		decf	INDF,F		;-1 更新
		movlw	h'06'
		subwf	INDF,F		;下位4ビット = 9
		return

;==========================================================================
;		ウェイト・ルーチン（１桁の表示時間）
;==========================================================================

wait300us
		movlw	200		;1（クロック 8MHz 時）
		movwf	wt_cnt		;1
wt01		decfsz	wt_cnt,F	;1,2
		goto	wt01		;2,0	1+1+(1+2)*199+(2+0)=601

		return			;2	601+2=603 ... 603/8000000*4 S = 301.5 μS

;==========================================================================
;		割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		swapf	STATUS,W
		clrf	STATUS
		movwf	s_save		;STATUS レジスタの保存
		movf	PCLATH,W
		movwf	p_save		;PCLATH レジスタの保存
		clrf	PCLATH

		btfsc	INTCON,INTF	;外部割り込み(RB0/INT) か？
		goto	rb0_int		;Yes

		btfsc	INTCON,T0IF	;タイマー０割り込み か？
		goto	t0_int		;Yes
		goto	int_end		;No

		; 外部(RB0/INT)割り込み

rb0_int		bcf	INTCON,INTF	;外部割り込み(RB0/INT)解除

		decfsz	sec1_cnt,F	;１秒カウンタ - 1 = 0 か？
		goto	r0int01		;No

		; sec1_cnt = 0
		movf	f_const,W	;50/60Hz 定数を設定
		movwf	sec1_cnt

		btfss	init_flg,7	;電源"ON" + CLKキー"ON" 以前 か？
		goto	r0int02		;No

		bcf	STATUS,C	;AM/PM LED の点滅周期
		rrf	sec1_cnt,F	;1/2
		rrf	sec1_cnt,F	;1/4 (0.25秒)にする

		movlw	h'01'
		xorwf	init_flg,F	;bit0: AM/PM LED 点滅制御
		goto	int_end

		; sec1_cnt > 0
r0int01		btfsc	init_flg,7	;電源"ON" + CLKキー"ON" 以前 か？
		goto	int_end		;Yes

		bcf	STATUS,C	;COL LED の点滅周期
		rrf	f_const,W	;1/2 (0.5秒)にする
		subwf	sec1_cnt,W
		btfss	STATUS,Z	;１秒カウンタ = f_const / 2 か？
		goto	int_end		;No
		goto	r0int03		;Yes

r0int02		call	bcd_ssmmhh_inc	;時分秒_BCD カウンタのインクリメント

r0int03		btfss	ext_flg,7	;拡張機能 = ON か？
		goto	int_end		;No

		movlw	h'10'
		xorwf	ext_flg,F	;bit4: COL LED 点滅制御
		goto	int_end

		; タイマー０割り込み処理（割り込み周期 = 4/8Mz*16*250=2msec）

t0_int		bcf	INTCON,T0IF	;タイマー０割込みフラグをクリア
		movlw	tm0_h_val	;ハードタイマー０カウント値を
		movwf	TMR0		;TMR0 に設定

		decfsz	tm0_s_cnt,F	;ソフトタイマー０カウンタ - 1 = 0 か？
		goto	int_end		;No

		bcf	INTCON,T0IE	;タイマー０割り込みを禁止

		btfss	keycode,7	;キー入力受付済み表示フラグ = ON か？
		goto	t0int01		;No

		bcf	keycode,7	;Yes. キー入力受付済み表示解除 ... キーON から 50 mS 後
		goto	int_end

t0int01		bcf	keycode,6	;キーコード別処理済み解除 ... キーOFF から 150 mS 後
;		goto	int_end

		; 割り込み処理の終了

int_end		movf	p_save,W
		movwf	PCLATH		;PCLATH レジスタの復帰
		swapf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie			;割り込みからの復帰	

;--------------------------------------------------------------------------
;	  秒、分、時_BCD カウンタと WEEK カウンタのインクリメント
;--------------------------------------------------------------------------

bcd_ssmmhh_inc
		; 秒_BCD カウンタのインクリメント

		movlw	bcd_ss		;秒_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'60'
		subwf	bcd_ss,W
		btfss	STATUS,C	;秒_BCD カウンタ >= h'60' か？
		goto	smhinc02	;No

		clrf	bcd_ss		;秒_BCD カウンタのクリア
		bsf	tmon_flg,0	;タイマー監視フラグ = ON

		; 分_BCD カウンタのインクリメント

		movlw	bcd_mm		;分_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'60'
		subwf	bcd_mm,W
		btfss	STATUS,C	;分_BCD カウンタ >= h'60' か？
		goto	smhinc02	;No

		clrf	bcd_mm		;分_BCD カウンタのクリア

		; 時_BCD カウンタのインクリメント

		movlw	bcd_hh		;時_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'24'
		subwf	bcd_hh,W
		btfss	STATUS,C	;時_BCD カウンタ >= h'24' か？
		goto	smhinc02	;No

		clrf	bcd_hh		;時_BCD カウンタのクリア

		; WEEK カウンタのインクリメント

		incf	week_cnt,F	;WEEK カウンタ + 1
		movlw	7 + 1
		subwf	week_cnt,W
		btfss	STATUS,C	;WEEK カウンタ < 7 + 1 か？
		goto	smhinc01	;Yes

		movlw	1
		movwf	week_cnt	;WEEK カウンタの初期設定 = 1:SUN

smhinc01	btfsc	mode_flg,0	;キー入力モードフラグ = ON か？
		goto	smhinc02	;Yes

		bcf	STATUS,C
		rlf	ox_week,F	;WEEK セグメント出力を左に 1 ビットシフト
		btfsc	STATUS,C	;
		rlf	ox_week,F	;SUN (初期値)

smhinc02	return

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

eep_st		de	"Copyright (C) 2019 by M.Yamamoto"

;==========================================================================

		end			;プログラムの終了
