;***** TMS1121_SimulatorII.asm ********************************************
;
;	ＴＩ社 TMS1121 デジタルタイマー・シミュレータ
;
;	Copyright (C) 2019-2021   by M.Yamamoto. All rights reserved.
;
;     ( coding:  Ver. 0.00   2019/05/18  by M.Yamamoto )
;	coding:  Ver. 1.00   2019/07/24  初期バージョン
;	update:  Ver. 1.10   2019/08/21  拡張機能の追加II、他修正等
;	update:  Ver. 1.20   2019/08/28  拡張機能 MCLR の機能改善
;	update:  Ver. 1.21   2020/05/03  スタックの消費量を改善
;	update:  Ver. 1.30   2020/07/24  拡張（カレンダー）機能の追加
;	update:  Ver. 1.31   2021/05/17  バンクアクセスの改善
;
;******************************************************* PicAsm 0247 ******

;	Device: PIC16F886	Clock: 8MHz (Internal OSC)

;	PIC16F886 のピンと用途
;	----------------------

;	以下のように、ハードウエアとともに (1),(9) ピンの用途を変更した (Ver.1.10にて変更)

;	(1) MCLR: マスター・クリア入力 → RE3: EXT JPスイッチ 入力
;	(9) RA7: EXT JPスイッチ 入力   → RA7: アラーム音 出力

;	  (1) RE3: EXT JPスイッチ 入力		(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: アラーム音 出力		(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 の表示が動くのを見ていて、何か煩わしく感じられた。
;　※１秒間を "点"、次の１秒間を "滅" の２秒周期に変更をした。（Ver. 1.30）
;
;　そこで、EXT ジャンパースイッチで拡張機能を選択したときに、必ずブリンク表示をしてしまうのも困るので、回路図
;　に示すように新たに NOR/BLK ジャンパースイッチを設けて、好みによってノーマル表示（点灯し切り）／ブリンク表
;　示（点滅）が選択できるようにした。
;
;　ただし、EXT ジャンパースイッチが OFF のときに NOR/BLK ジャンパースイッチを BLK にすると、 [COL] LED は消灯
;　してしまうので注意が必要である。
;　※ジャンパースイッチを BLK にしたときも点灯するように変更をした。（Ver. 1.30）
;　※"シミュレータ II"では NOR/BLK ジャンパースイッチが不要となり削除した。
;
; ２．時計機能の 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 状態にすることはできない。
;
; ３－２．MEM CLR の機能改善に機能追加
;
;　MCLR キーを５回の連続操作で 全消去を行っても、見かけ上、何の反応も現れないため、本当にタイマー用メモリの内
;　容が全消去できたのかどうか、心配になることがある。そのために次の４項で述べる方法で、実際にそれを確認する必
;　要がある。
;
;　そこで、間違いなく全消去ができたことを示すために、MCLR キーを操作した直後に見かけ上の反応を現すことにした。
;　その反応方法として、４桁の７セグ LED を点滅して見せる。初めの 2.1 mS x 128 = 268.8 mS 間は４桁すべてに数字
;　"0" を点灯、次の 268.8 mS 間は４桁すべてを滅灯、の点滅表示を５回繰り返す、というものである。	
;
;　ここで 2.1 mS というのは メインルーチン１周期全体の処理時間であり、128 は１周期の繰り返し回数でプログラム
;　を簡単にするためにとった値である。
;
;　なお、この７セグ LED の点滅表示は、メモリ内容の全消去のときだけでなく、スイッチ別消去、および曜日別消去の
;　ときにも、同様に表示をするようにした。
;
; ４．タイマー用メモリから読み出し方法の追加
;
;　TMS1121 では タイマー用メモリから読み出し の項で、メモリに書き込まれているタイマー情報を読み出して、その内
;　容を各ＬＥＤに表示する機能があり、その指示方法には、曜日別表示とスイッチ別表示の２つの方法があることを述べ
;　た。私がこれまで TMS1121、および本シミュレータをいろいろ操作をしていて、この２つの方法以外に無条件で、記憶
;　されている すべての内容を表示 する機能があると、より便利になるとずっと思っていた。そこで、それを拡張機能と
;　して実現させてみることにした。
;
;　その場合の指示方法にはスイッチ別表示形式 (X), SW, SW で行い、スイッチ番号 X の指定には、スイッチとして有り
;　得ない番号 9 を割り当てた。
;
;　キースイッチを 9, SW と押すと、通常のスイッチ別指定とは異なっていることを示すために、SW1 ～ SW4 のすべての
;　LED を点灯させる。そして、それ以降のキー操作はスイッチ別指定の場合とまったく同様に行う。また、メモリ内容の
;　LED 表示の方法は、曜日別やスイッチ別はなく 記憶されている順（無差別）に表示される。
;
; ５．ON 動作（複数個を含む）のスイッチをすべて OFF にする
;
;　３の MEM CLRの機能改善の項末で述べた、"ダイレクト・コントロール（直接制御）では、複数個の ON 動作をしてい
;　るすべてのスイッチを、一気に OFF 状態にすることはできない" 件についてだが、 やはり、そのような機能があれば
;　便利になると思い直し、メモリ内容の全消去の機能とは切り離した、全スイッチを OFF 状態にする 機能を設けた。
;
;　その場合の指示方法には、ダイレクト・コントロール （直接制御）形式で行い、スイッチ番号 X の指定には、前項と
;　同様にスイッチとして有り得ない番号 9 を割り当てた。
;
;　前項と同様に キースイッチを 9, SW と押すと、通常のスイッチ別指定とは異なっていることを示すために、 SW1 ～ 
;　SW4 のすべての LED を点灯させる。その後、OFF キーを押すとそのときに動作をしているスイッチのすべてが OFF 状
;　態になり、LED表示は現在の時刻表示に戻る。
;
;　ここまで機能を拡張してくると、逆に全スイッチをすべて ON 状態にする機能も考えられ、実際に実現することは容易
;　だが、そこまで機能を拡張することは止めにしておいた。
;
; ６．アラーム音（ブザー音）の出力
;
;　オリジナルの TMS1121 のままでアラーム音を出力させることの不都合さは、私のホームページ "088. ＴＩ TMS1121 
;　デジタルタイマー II" の 回路図の下の説明 で述べた通りだが、その不都合な点を改善するための方法を拡張機能に
;　盛り込むことにした。また、各リレーの ON / OFF 時のアラーム音だけでなく、毎時の時報も併せて出力するように拡
;　張をした。
;
;　アラーム音を出力する拡張機能を実現するためには、簡単なハードウエアの改造が必要で、1 ピン、および 9 ピンに
;　与えられたそれぞれの役目の変更を行う。まず、1 ピンについては、従来 MCLR 端子として使用していたのを入力ポー
;　トに変更をして、ここに 9 ピンで使用をしていた EXT ジャンパスイッチの引っ越しをする。
;
;　次に、入力ポートであった 9 ピンを出力ポートに変更をして、ここにアラーム音を出力するための圧電スピーカ（ブ
;　ザー）を接続する。このように回りくどいことを行っているのは、MCLR 端子であった 1 ピンをポートに機能変更をす
;　るのに、1 ピンは入力ポート専用で出力ポートには変更をすることができないためである。
;
;　アラーム音の種類として、現在、４種類を用意している。これらのアラーム音の出力ルーチンは、 メインルーチンの
;　１周期の終了直前の部分に実行をするように追加挿入した。
;　※カレンダー機能の追加で "ピッ"、"ピポッ"、"ブッブッ" ブザー音の３種類を追加した。（Ver. 1.30）
;
;　このアラーム音の内、リレー ON 時の "ピポッピポッ" 音と、リレー OFF 時の "ブッブー" 音は、タイマーの監視と
;　その処理サブルーチン（ time_monitor ）内でフラグが設定される。また、時報予報音の "プッ" 音と、時報正報音の
;　"ポッ～～ン" 音は、割り込み処理ルーチン（ interrupt ）内から呼ばれる 秒、分、時_BCD カウンタと WEEK カウン
;　タのインクリメントサブルーチン（ bcd_ssmmhh_inc ）内でフラグが設定される。
;
;　もし、これらのフラグが複数 ON になった場合には、若番ビットのフラグのみが優先され他のフラグは無視をされる。
;
;　なお、これらのアラーム音が出力されている時間（最小 100 mS ～ 最大 1000 mS の間）中は、それぞれのアラーム音
;　出力サブルーチン内の各ウェイトルーチンのために、設定されたウェイト時間が経過するまで、プログラムの進行が次
;　には進まなくなるので、したがって、LED のダイナミック点灯が途切れてその間は（短時間だが）表示がされなくなる。
;
;　言うまでもないことかもしれないが、４種類のアラーム音の内、例えば時報予報音の "プッ" 音というのは、毎時の時
;　報、すなわち "プッ"、"プッ"、"プッ"、"ポッ～～ン" の内の１つの "プッ" で、本来は 440 Hz の正弦波を 100 m
;　秒間 出力するものだが、ここではプログラムを簡単にするために疑似的に矩形波で代用をしている。（というよりも、
;　正弦波を作り出すなんてことは私にはできない。）
;
; ７．カレンダー機能の追加（Ver. 1.30）
;
;　ハードウエアを "シミュレータ II" として一新したのを機に、新たにカレンダー機能を追加した。
;　年月日の自動表示モード、任意表示モード、および設定モードの３つの機能を設けた。
; （詳細はホームページの操作方法を参照のこと：http://xyama.sakura.ne.jp/hp/TMS1121_SimulatorII.html#calendar）
;
;　７－１．年月日の自動表示モード
;　　毎時 00 分 10 秒からの 18 秒間をカレンダーの自動表示モードに割り当てて、年月日を自動的に表示する。
;　　その 18 秒間は、[PM] LED が ブリンク表示をして、カレンダーの自動表示モード中であることを示す。
;
;　７－２．年月日の任意表示モード
;　　自動表示には関係なく、任意のときにキー操作をすることによって、いつでも年月日を表示させることができる。
;　　9 キーと、WEEK キーを操作するごとに、"年" と "月"、"日" を交互に表示する。
;　　任意表示モードを終了させるまで、[PM] LED がブリンク表示をして、カレンダーの表示モード中であることを示す。
;
;　７－３．年月日の設定モード
;　　キー操作をすることによって、年月日（曜日も含めて）が自由に設定変更ができるように機能追加。
;　　ただし、曜日は年月日によって一意的に決まるものであるため、曜日の直接指定はできない。
;　　設定モードを終了させるまで、[AM] LED がブリンク表示をして、カレンダーの設定モード中であることを示す。
;
; ８．拡張機能が有効時の時刻の設定（Ver. 1.30）
;
; 　カレンダー機能を追加したことによって、拡張機能が有効時には、従来の曜日を含めた時刻の設定方法では、矛盾が
; 　起きてしまう。それを回避するために、拡張機能が有効時には、曜日を含めない時刻の設定方法が行えるように変更
; 　を加えた。
;
;　----------------------------------------------------------------
;
;　なお、上述の拡張機能も含めて本シミュレーションプログラムの解説を、次に示す私のホームページ上で行っているの
;　で、このプログラムを理解する上での一助として欲しい。
;
;	ＵＲＬ： http://xyama.sakura.ne.jp/hp/TMS1121_Simulator.html#program
;	ＵＲＬ： http://xyama.sakura.ne.jp/hp/TMS1121_SimulatorII.html#program
;

;==========================================================================

	list		p=pic16f886		;デバイス情報
	include		p16f886.inc		;インクルードファイル
	errorlevel	-302			;Eliminate bank warning

;==========================================================================
;		コンフィギュレーションの設定
;==========================================================================

	__config _CONFIG1, _INTOSCIO & _WDT_OFF & _PWRTE_ON & _MCLRE_OFF & _IESO_OFF & _FCMEN_OFF & _LVP_OFF
	__config _CONFIG2, _WRT_OFF

;==========================================================================
;		定数、変数の定義とレジスタ割付け
;==========================================================================

#define 	ver_no	"1.31"

		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

buzzer		equ	7		;RA7: アラーム音 出力
f_rah		equ	65536 - 1136	;ラ (880.00 Hz)
f_doh		equ	65536 - 1911	;ド (523.26 Hz)  at 8MHz
f_ra		equ	65536 - 2273	;ラ (440.00 Hz)
f_so		equ	65536 - 2551	;ソ (392.00 Hz)
f_mi		equ	65536 - 3034	;ミ (329.63 Hz)
f_do		equ	65536 - 3822	;ド (261.63 Hz)
f_do_		equ	65536 - 7644	;ド (130.82 Hz)
po_tim		equ	100		;音長(ms)
pi_tim		equ	100		;音長
bu_tim		equ	100		;音長
buu_tim		equ	250		;音長

		cblock  h'20'
tm0_s_cnt				;ソフトタイマー０カウンタ
f_const					;50/60Hz 定数を設定
init_flg				;bit7: 電源"ON" + CLKキー"ON" 以前の制御フラグ
;					;bit0: AM/PM 点滅制御
sec1_cnt				;１秒カウンタ
week_cnt				;WEEK カウンタ
week_cnt2				;WEEK カウンタ（拡張時）
bcd_yh					;年(上位2桁)_BCD カウンタ
bcd_yl					;年(下位2桁)_BCD カウンタ
bcd_nn					;月_BCD カウンタ
bcd_dd					;日_BCD カウンタ
bcd_hh					;時_BCD カウンタ
bcd_mm					;分_BCD カウンタ
bcd_ss					;秒_BCD カウンタ
temp_yh					;仮の 年(上位2桁)_BCD カウンタ
temp_yl					;仮の 年(下位2桁)_BCD カウンタ
temp_nn					;仮の 月_BCD カウンタ
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				;モードフラグ
;					; bit5-4: AM/PM の退避用ワーク
;					; bit2: 定時プログラムフラグ、(追加フラグ)
;					; bit1: X,SW 処理済みフラグ、(追加フラグ)
; _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _	; bit0: キー入力モードフラグ、0: 時刻表示モード, 1: キー入力表示モード
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: 拡張機能フラグ
;					; bit6: MCLR 表示フラグ
;					; bit5: 9,SW 表示フラグ
;					; bit4: COL LED 点滅（ブリンク）制御
;					; bit3: 時間表示フラグ（0:12H / 1:24H）
; _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _	; bit2-0: MCLR カウンタ
mcl_cnt					;MCLR 表示カウンタ
dsp_cnt					;
;					; bit7: X,WEEK / X,SW 処理済みフラグ
;					; bit6: LED 表示消灯フラグ、0: 表示 / 1: 消灯
;					; bit5: タイマー用メモリ検索終了フラグ
; _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _	; bit4-0: 表示カウンタ
lp_cnt					;ループカウンタ
work1					;ワーク
work2					;ワーク
wt1cnt					;ウェイト用ループカウンタ
wt2cnt					;ウェイト用ループカウンタ
wt3cnt					;ウェイト用ループカウンタ
const_high				;音階用分周定数 high の保存
const_low				;音階用分周定数 low の保存
alm_flg					;アラームフラグ
;					; bit6: 年月日の設定ＮＧフラグ
;					; bit5: 年月日の設定ＯＫフラグ
;					; bit4: 年の入力ＯＫフラグ
;					; bit3: 時報正報音フラグ
;					; bit2: 時報予報音フラグ
;					; bit1: リレー OFF フラグ
; _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _	; bit0: リレー ON フラグ

cale_flg				;拡張機能: カレンダー（年月日）フラグ
;					; bit5: カレンダー（年月日）入力フラグ
;					; bit4: COL(下) LED 制御フラグ、0:滅灯,年表示指示／1:点灯,月日表示指示
;					; bit3: 設定や表示の対象フラグ、0:年(上位下位)／1:月日 
;					; bit2: カレンダー（年月日）モード時の AM/PM LED 点滅（ブリンク）制御
;					; bit1: カレンダー（年月日）の表示モードフラグ
; _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _	; bit0: カレンダー（年月日）の設定モードフラグ
uru_flag				;平年／閏年判定フラグ: bit0=0:平年／1:閏年
cur_yh					;年(上位2桁)(変) BCD カウンタ
cur_yl					;年(下位2桁)(変) BCD カウンタ
cur_nn					;月(変) BCD カウンタ
cur_dd					;日(変) BCD カウンタ
cur_week				;週位置カウンタ（曜日 1～7）
xxx_yh					;ワーク
		endc

		cblock	h'80' - 4
w_save					;W レジスタの退避用
s_save					;STATUS レジスタの退避用
p_save					;PCLATH レジスタの退避用
f_save					;FSR レジスタの退避用
		endc

		cblock	h'a0'		;(バンク 1)
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)

;==========================================================================
;		マクロ命令定義
;==========================================================================

;		Sound_M マクロ

Sound_M		macro	@scale,@time
		movlw	high @scale	;出力音階
		movwf	const_high
		movlw	low @scale
		movwf	const_low
		movlw	@time		;出力時間(ms)
		call	buzzer_control	;ブザー音出力コントロール
		endm

;==========================================================================
;		プログラム開始
;==========================================================================

		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'01110000'	;RA6-4: 入力, RA7,RA3-0: 出力
		movwf	TRISA
		movlw	b'00000001'	;RB7-1: 出力, RB0: 入力
		movwf	TRISB
		clrf	TRISC		;RC7-0: 出力
		movlw	b'00001000'	;RE3: 入力
		movwf	TRISE

		movlw	b'11000011'	;PBPU=1: プルアップ抵抗を使用しない
					;INTEDG=1: RB0/INTピンの立ち上がりで割り込み
					;T0CS=0: 内部クロックを使用
					;T0SE=0: タイマーカウントアップエッジ指定 = 立ち上がり
					;PSA=0: プリスケーラをタイマー０に使用
					;PS2-PS0=011: プリスケーラのスケール値 = 1:16
		movwf	OPTION_REG

		bcf	PIE1,TMR1IE	;TMR1IE: タイマー１割り込みを禁止
		bcf	STATUS,RP0	;バンク 0
		movlw	h'00'		;bit7(GIE)=0: 全割り込み禁止,
					;bit5(T0IE)=0: タイマー０割り込み禁止,
					;bit4(INTE)=0: 外部割り込み(RB0/INT)禁止
		movwf	INTCON

		movlw	b'00000001'	;bit7-6: 未使用
					;bit5-4=00: プリスケーラのスケール値 1:1
					;bit3=0: 専用の発振器を使う場合に指定
					;bit2=0: 外部入力クロック指定時に有効
					;bit1=0: 内部クロックを使う
					;bit0=1: タイマー１を動作
		movwf	T1CON		;T1CON に設定

		; 周波数切り替えジャンパの検出と定数設定

		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,PEIE	;PEIE: 周辺機器割り込みを許可
		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	wait_300us	;１桁の表示時間
		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'20'
		movwf	bcd_yh		;年(上位2桁)_BCD カウンタの初期設定 = 20
		movwf	bcd_yl		;年(下位2桁)_BCD カウンタの初期設定 = 20年
		movlw	h'07'
		movwf	bcd_nn		;月_BCD カウンタの初期設定 = 07月
		movlw	h'26'
		movwf	bcd_dd		;日_BCD カウンタの初期設定 = 26日 (SUN)
		clrf	cale_flg	;カレンダー（年月日）フラグの初期設定

		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

		call	day_week	;該当日（2020年07月26日）の曜日を取得 = 1:日曜日
		movf	cur_week,W
		movwf	week_cnt2	;WEEK カウンタ（拡張時）の設定

		clrf	rx_sw		;RX SW リレー出力の初期設定
		clrf	mode_flg	;キー入力モードフラグの初期設定
		clrf	tmon_flg	;タイマー監視フラグの初期設定
		clrf	keycode		;キーコードの初期設定
		clrf	itv_flg		;インターバルフラグの初期設定
		clrf	err_flg		;入力エラーフラグの初期設定
		clrf	ext_flg		;拡張機能フラグの初期設定
		clrf	alm_flg		;アラームフラグの初期設定

		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	3 * 20
		movwf	lp_cnt		;ループカウンタ

start02		clrf	INDF		;タイマー用メモリの初期設定
		incf	FSR,F		;間接アドレス +1 更新
		decfsz	lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	start02		;No

		btfss	PORTE,3		;EXT JPスイッチ（このスイッチだけ逆論理）= ON か？
		bsf	ext_flg,7	;Yes. bit7: 拡張機能フラグ = ON

		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	main_03		;Yes

		clrf	ox_sw		;SW セグメント出力の初期設定
		clrf	ox_mode		;MODE セグメント出力の初期設定
		movf	week_cnt,W	;WEEK カウンタ
		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		movf	week_cnt2,W	;Yes. WEEK カウンタ（拡張時）
		call	ox_week_out_x	;WEEK カウンタ値から OX 出力へ変換

		btfsc	cale_flg,1	;カレンダー（年月日）の表示モード = ON か？
		goto	main_01		;Yes

		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時間表示に変換
		goto	main_03

main_01		btfsc	cale_flg,4	;COL(下) LED 制御フラグ = 1:点灯、月(上位2桁) + 日(下位2桁) 表示指示 か？
		goto	main_02		;Yes

		movf	bcd_yh,W	;年(上位2桁)_BCD カウンタ
		movwf	temp_hh		;仮の 時_BCD カウンタ
		movf	bcd_yl,W	;年(下位2桁)_BCD カウンタ
		movwf	temp_mm		;仮の 分_BCD カウンタ
		goto	main_03

main_02		movf	bcd_nn,W	;月_BCD カウンタ
		movwf	temp_hh		;仮の 時_BCD カウンタ
		movf	bcd_dd,W	;日_BCD カウンタ
		movwf	temp_mm		;仮の 分_BCD カウンタ

main_03		movlw	h'c0'
		andwf	keycode,F	;キーコードの初期設定

;-------------- R0(MODE) 桁の処理

		movlw	b'00000010'	;RX 桁出力位置 = R0
		movwf	PORTB		;R0(MODE) = ON

		movlw	h'01'		;PM LED
		btfsc	cale_flg,1	;カレンダー（年月日）の表示モード = ON か？
		goto	main_mod01	;Yes

		movlw	h'02'		;AM LED
		btfsc	cale_flg,0	;カレンダー（年月日）の設定モード = ON か？
		goto	main_mod01	;Yes

		movf	ox_mode,W
		goto	main_mod02

main_mod01	btfss	cale_flg,2	;カレンダー（年月日）モード時の AM/PM LED 点滅（ブリンク）制御 = ON か？
		clrw			;No

main_mod02	movwf	PORTC		;OX(MODE) セグメント出力
		call	wait_300us	;１桁の表示時間

		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	cale_flg,5	;カレンダー（年月日）入力フラグ = ON か？
		goto	main_1st01	;No

		btfss	cale_flg,2	;カレンダー（年月日）モード時の AM/PM LED 点滅（ブリンク）制御 = ON か？
		goto	main_1st03	;No
		goto	main_1st02	;Yes

main_1st01	btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	main_1st02	;No

		btfsc	ext_flg,4	;COL LED 点滅制御 = ON か？

main_1st02	iorlw	h'80'		;Yes. COL(上) LED 点灯

main_1st03	movwf	PORTC		;OX(1st) セグメント出力
		call	wait_300us	;１桁の表示時間

		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	main_2nd01	;No

		btfsc	cale_flg,4	;COL(下) LED 制御フラグ = 0:滅灯／1:点灯 か？
		goto	main_2nd01	;1:点灯

		btfsc	ext_flg,4	;COL LED 点滅（ブリンク）制御 = ON か？

main_2nd01	iorlw	h'80'		;Yes. COL(下) LED 点灯

		movwf	PORTC		;OX(2nd) セグメント出力
		call	wait_300us	;１桁の表示時間

		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	wait_300us	;１桁の表示時間

		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	main_4th01	;No

		btfsc	cale_flg,1	;カレンダー（年月日）の表示モード = ON か？
		goto	main_4th01	;Yes. 常に４桁表示

		btfsc	cale_flg,0	;カレンダー（年月日）の設定モード = ON か？
		goto	main_4th01	;Yes. 常に４桁表示

		btfsc	ext_flg,6	;MCLR 表示フラグ = ON か？
		goto	main_4th01	;Yes

		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		btfss	ext_flg,3	;Yes. 時間表示フラグ（0:12H / 1:24H） = ON か？
		movlw	h'0a'		;No.  ゼロサプレス

main_4th01	call	ptn_set		;表示パターンに変換
		movwf	PORTC		;OX(4th) セグメント出力
		call	wait_300us	;１桁の表示時間

		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	wait_300us	;１桁の表示時間

		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	wait_300us	;１桁の表示時間

		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	main_key02	;No. ない

		btfsc	keycode,6	;コード別の処理 = 未 か？
		goto	main_key01	;No. 済み

		call	key_processing	;押されたキーコード別の処理
		goto	main_key02

main_key01	btfsc	keycode,7	;bit7=0 解除された か？
		goto	main_key02	;No. 解除前

		movf	keycode,W
		andlw	h'1f'
		sublw	21		;21: キー入力なし表示
		btfss	STATUS,Z	;キー入力がない か？
		goto	main_key02	;No. ある

		movf	tm0_s_cnt,W
		btfss	STATUS,Z	;タイマー０割り込みを監視中 か？
		goto	main_key02	;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: タイマー０割り込み許可

main_key02	;goto	main_mon01

;-------------- タイマーの監視とその処理

; tmon_flg:	bit0:	タイマー監視フラグ ... interrupt(bcd_ssmmhh_inc) で設定、time_monitor で解除

main_mon01	btfsc	tmon_flg,0	;タイマー監視フラグ = ON か？
		call	time_monitor	;Yes

;-------------- MCLR 処理の LED 表示（拡張機能）

		btfss	ext_flg,6	;MCLR 表示フラグ = ON か？
		goto	main_mcr01	;No

		incf	mcl_cnt,F	;MCLR 表示カウンタ + 1
		movlw	h'00'		;"０"表示
		btfsc	mcl_cnt,7	;カウンタのビット 7 = ON か？	(2.1 x 128 = 268.8 mS)
		movlw	h'aa'		;Yes. ブランク表示
		movwf	temp_hh		;仮の 時_BCD カウンタ
		movwf	temp_mm		;仮の 分_BCD カウンタ
		movf	mcl_cnt,W
		btfss	STATUS,Z	;MCLR 表示カウンタ = 0 (初期値) か？
		goto	main_mcr01	;No

		decf	ext_flg,F	;MCLR カウンタ - 1
		movlw	h'07'
		andwf	ext_flg,W
		btfss	STATUS,Z	;MCLR カウンタ = 0 か？
		goto	main_mcr01	;No

		bcf	ext_flg,6	;MCLR 表示フラグ = OFF
		clrf	mode_flg	;キー入力モードフラグ = OFF

main_mcr01	;goto	main_alm01

;-------------- アラームフラグの監視とアラーム音出力（拡張機能）

; alm_flg: アラームフラグ
;		　　┌─────────  key_processing(kproc12) で設定
;		　　│　　 ┌────── bcd_ssmmhh_inc で設定	
;		　　│　　 │　┌──── time_monitor で設定
;		　┌─┐　┌┐┌┐
;		０ｘｘｘ．ｘｘｘｘ
;		　│││　││││
;		　│││　│││└─── リレー ON フラグ	;"ピポッピポッ"
;		　│││　││└──── リレー OFF フラグ	;"ブッブー"
;		　│││　│└───── 時報予報音フラグ	;"プッ"
;		　│││　└────── 時報正報音フラグ	;"ポッ～～ン"
;		　││└──────── 年の入力ＯＫフラグ	;"ピッ"
;		　│└───────── 年月日の設定ＯＫフラグ	;"ピポッ"
;		　└────────── 年月日の設定ＮＧフラグ	;"ブッブッ"

main_alm01	btfsc	INTCON,T0IE	;タイマー０割り込み許可中 か？
		goto	main_alm09	;Yes. （チャタリング吸収中を除く）

		movf	alm_flg,W
		btfsc	STATUS,Z	;アラームフラグのどれか = ON か？
		goto	main_alm09	;No

		btfss	alm_flg,6	;年月日の設定ＮＧフラグ = ON か？
		goto	main_alm02	;No

		call	buzzer_bu	;"ブッ" ブザー音出力 (230 mS)
		call	wait_30ms
		call	buzzer_bu	;"ブッ" ブザー音出力
		clrf	keycode		;キーコードフラグをクリア
		goto	main_alm08

main_alm02	btfss	alm_flg,5	;年月日の設定ＯＫフラグ = ON か？
		goto	main_alm03	;No

		call	buzzer_pipo	;"ピポッ" ブザー音出力 (230 mS)
		clrf	keycode		;キーコードフラグをクリア
		goto	main_alm08

main_alm03	btfss	alm_flg,4	;年の入力ＯＫフラグ = ON か？
		goto	main_alm04	;No

		call	buzzer_pi	;"ピッ" ブザー音出力 (100 mS)
		clrf	keycode		;キーコードフラグをクリア
		goto	main_alm08

main_alm04	btfss	alm_flg,0	;リレー ON フラグ = ON か？
		goto	main_alm05	;No

		call	buzzer_pipo2	;"ピポッピポッ" ブザー音出力 (490 mS)
		goto	main_alm08

main_alm05	btfss	alm_flg,1	;リレー OFF フラグ = ON か？
		goto	main_alm06	;No

		call	buzzer_bubuu	;"ブッブー" ブザー音出力 (450 mS)
		goto	main_alm08

main_alm06	btfss	alm_flg,2	;時報予報音フラグ = ON か？
		goto	main_alm07	;No

		call	buzzer_pu	;"プッ" ブザー音出力 (100 mS)
		goto	main_alm08

main_alm07	btfss	alm_flg,3	;時報正報音フラグ = ON か？
		goto	main_alm08	;No

		call	buzzer_poon	;"ポッ～～ン" ブザー音出力 (1000 mS)
	;	goto	main_alm08

main_alm08	clrf	alm_flg		;アラームフラグをクリア

main_alm09	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	PORTE,3		;EXT JPスイッチ（このスイッチだけ逆論理）= OFF か？
		bcf	ext_flg,7	;Yes. bit7: 拡張機能フラグ = OFF
		btfss	PORTE,3		;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) の処理
		; --------------------------

		btfsc	cale_flg,1	;カレンダー（年月日）の表示モードフラグ = ON か？
		goto	kproc00h	;Yes

		btfss	cale_flg,0	;カレンダー（年月日）の設定モードフラグ = ON か？
		goto	kproc00a	;No

		btfss	cale_flg,5	;カレンダー（年月日）入力フラグ = ON か？
		goto	kproc00h	;No
		goto	kproc00b	;Yes

kproc00a	btfss	fmmwwwss,7	;f bit = 1 (有効)  か？
		goto	kproc00b	;No

		call	clr_all_disp	;Yes. LED をすべて(コロンを除く)消灯
		bcf	fmmwwwss,7	;f bit = 0					;;

		btfss	mode_flg,2	;定時プログラムフラグ = ON か？、(追加フラグ)	;;
		goto	kproc00b	;No

		swapf	mode_flg,W
		andlw	h'03'
		movwf	ox_mode		;AM/PM を復帰

kproc00b	movlw	4		;左に 4 ビットシフト
		movwf	lp_cnt

kproc00c	bcf	STATUS,C
		rlf	temp_mm,F
		rlf	temp_hh,F
		decfsz	lp_cnt,F	;lp_cnt - 1 = 0 か？
		goto	kproc00c	;No

		movf	wkcode,W	;キーコードを
		iorwf	temp_mm,F	;分桁に加える

		btfsc	cale_flg,5	;カレンダー（年月日）入力フラグ = ON か？
		goto	kproc00h	;Yes

		movf	temp_hh,W
		andlw	h'f0'
		btfsc	STATUS,Z	;十時桁 = 0 か？
		goto	kproc00d	;Yes

		sublw	h'a0'
		btfss	STATUS,Z	;十時桁 = h'a' か？
		goto	kproc00h	;No
		goto	kproc00e	;Yes

kproc00d	movlw	h'a0'
		iorwf	temp_hh,F	;十時桁を h'a' に置き換える

kproc00e	movf	temp_hh,W
		andlw	h'0f'
		btfsc	STATUS,Z	;時桁 = 0 か？
		goto	kproc00f	;Yes

		sublw	h'0a'
		btfss	STATUS,Z	;時桁 = h'a' か？
		goto	kproc00h	;No
		goto	kproc00g	;Yes

kproc00f	movlw	h'0a'
		iorwf	temp_hh,F	;時桁を h'a' に置き換える

kproc00g	movf	temp_mm,W
		andlw	h'f0'
		btfss	STATUS,Z	;十分桁 = 0 か？
		goto	kproc00h	;No

		movlw	h'a0'
		iorwf	temp_mm,F	;十分桁を h'a' に置き換える

kproc00h	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

		movlw	h'03'
		andwf	cale_flg,W
		btfss	STATUS,Z	;カレンダー（年月日）設定 or 表示モード か？
		goto	kproc12cc	;Yes

; dsp_cnt:	bit7: X,WEEK / X,SW 処理済みフラグ
;		bit6: LED 表示消灯フラグ、0: 表示 / 1: 消灯
;		bit5: タイマー用メモリ検索終了フラグ
;		bit4-0: 表示カウンタ

		movf	dsp_cnt,W
		btfss	STATUS,Z	;フラグと表示カウンタ = 0 か？
		goto	kproc12f	;No

		movf	temp_mm,W
		andlw	h'0f'
		movwf	work1		;ワーク
		sublw	h'0a'
		btfsc	STATUS,Z	;temp_mm(bit3-0) = h'a' か？
		goto	kproc12h	;Yes						;;

		btfsc	wkcode,0	;WEEK キー(12) か？
		goto	kproc12b	;No. SW キー(13)

		; WEEK 番号（曜日）の取り込み（X,WEEK の処理）

		movlw	7 + 1
		subwf	work1,W
		btfss	STATUS,C	;temp_mm < 7 + 1 か？
		goto	kproc12a	;Yes

		btfss	ext_flg,7	;拡張機能 = ON か？
		goto	kproc12l	;No. 無視(error)

		movlw	9
		subwf	work1,W
		btfss	STATUS,Z	;temp_mm = 9 か？
		goto	kproc12l	;No. 無視(error)
		goto	kproc12ca	;Yes. カレンダー機能（追加機能）へ

kproc12a	movf	work1,W
		call	ox_week_out_x	;WEEK カウンタ値から OX 出力へ変換

		movlw	h'e3'
		andwf	fmmwwwss,F	;www 位置をクリア
		rlf	work1,F
		rlf	work1,W	;左に 2 ビットシフト
		andlw	h'1c'
		iorwf	fmmwwwss,F	;www 位置に加える
		goto	kproc12e

		; SW 番号の取り込み（X,SW の処理）

kproc12b	clrf	ox_week		;(TMS1121 original)
		movlw	4 + 1
		subwf	work1,W
		btfss	STATUS,C	;temp_mm < 4 + 1 か？
		goto	kproc12c	;Yes

		btfss	ext_flg,7	;拡張機能 = ON か？
		goto	kproc12l	;No. 無視(error)

		movlw	9
		subwf	work1,W
		btfss	STATUS,Z	;temp_mm = 9 か？
		goto	kproc12l	;No. 無視(error)

		bsf	ext_flg,5	;9,SW 表示フラグ = ON
		movlw	h'0f'
		movwf	ox_sw		;9,SW 表示
		goto	kproc12d

kproc12c	movf	work1,W
		call	ox_sw_out_x	;SW カウンタ値から OX 出力へ変換

		movlw	h'e0'		;h'fc'						;;
		andwf	fmmwwwss,F	;www,ss 位置をクリア
		movf	work1,W
		andlw	h'03'		;下位 2 ビットを取り出し
		iorwf	fmmwwwss,F	;ss 位置に加える

kproc12d	bsf	mode_flg,1	;X,SW 処理済みフラグ = ON、(追加フラグ)	

kproc12e	bsf	dsp_cnt,7	;X,WEEK / X,SW 処理済みフラグ = ON
		call	clr_numeric	;数字 LED を消灯
		goto	kproc12l

		; タイマー用メモリ内容の読み出し（(X),WEEK,WEEK ／ (X),SW,SW の処理）

kproc12f	btfss	dsp_cnt,5	;タイマー用メモリ検索終了フラグ = ON か？
		goto	kproc12g	;No

		movlw	h'80'
		andwf	dsp_cnt,F	;X,WEEK / X,SW 処理済みフラグ = ON を残す
		goto	kproc12i

kproc12g	btfsc	dsp_cnt,6	;LED 表示消灯フラグ = ON か？
		goto	kproc12i	;Yes

kproc12h	call	read_memory	;タイマー用メモリ内容の読み出し
		bsf	dsp_cnt,6	;LED 表示消灯フラグ = ON
		goto	kproc12l

kproc12i	call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		btfss	wkcode,0	;WEEK キー(12) か？
		call	ox_week_out	;Yes. WEEK カウンタ値から OX 出力へ変換
		btfss	wkcode,0	;SW キー(13) か？
		goto	kproc12k	;No

		btfss	ext_flg,5	;9,SW 表示フラグ = ON か？
		goto	kproc12j	;No

		movlw	h'0f'
		movwf	ox_sw		;9,SW 表示
		goto	kproc12k

kproc12j	call	ox_sw_out	;Yes. SW カウンタ値から OX 出力へ変換

kproc12k	bcf	dsp_cnt,6	;LED 表示消灯フラグ = OFF

kproc12l	goto	kproczz

		; カレンダー機能（年月日の設定と表示）の追加 ... (Ver. 1.30)

;               9, WEEK, ...... WEEK, ...... WEEK, ...... ・・・・・ WEEK, ...... WEEK, ...... (CLK)
;		         PM_LED
;	                ブリンク      [YYYY]       [MMDD]                  [YYYY]       [MMDD]

;      9, 9, 9, 9, WEEK, ...... WEEK, ...... WEEK, ...... WEEK, ...... WEEK, ...... (CLK)
;		         AM_LED
;	                ブリンク      [YYYY]       [YYYY]       [MMDD]       [MMDD]
;	                             表示&入力    変更表示     表示&入力    変更表示

kproc12ca	movf	temp_mm,W
		sublw	h'a9'
		btfss	STATUS,Z	;temp_mm = h'a9' か？
		goto	kproc12cb	;No

		call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		bsf	cale_flg,1	;カレンダー（年月日）の表示モードフラグ = ON
		goto	kproc12cm

kproc12cb	movf	temp_mm,W
		sublw	h'99'
		btfss	STATUS,Z	;temp_mm = h'99' か？
		goto	kproc12cm	;No. 無視(error)

		movf	temp_hh,W
		sublw	h'99'
		btfss	STATUS,Z	;temp_hh = h'99' か？
		goto	kproc12cm	;No. 無視(error)

		call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		bsf	cale_flg,0	;カレンダー（年月日）の設定モードフラグ = ON
		goto	kproc12cm

; cale_flg:	拡張機能: カレンダー（年月日）フラグ
;		bit5: カレンダー（年月日）入力フラグ
;		bit4: COL(下) LED 制御フラグ、0:滅灯,年表示指示／1:点灯,月日表示指示
;		bit3: 設定や表示の対象フラグ、0:年(上位下位)／1:月日 
;		bit2: カレンダー（年月日）モード時の AM/PM LED 点滅（ブリンク）制御
;		bit1: カレンダー（年月日）の表示モードフラグ
;		bit0: カレンダー（年月日）の設定モードフラグ

		; カレンダー（年月日）の表示モード、設定モード時の 現在年月日を表示

kproc12cc	btfsc	cale_flg,5	;カレンダー（年月日）入力フラグ = ON か？
		goto	kproc12cg	;Yes

		btfsc	cale_flg,3	;設定や表示の対象フラグ、0:年(上位下位)／1:月日 か？
		goto	kproc12cd	;1:月日

		; 現在の年を表示
		movf	bcd_yh,W	;年(上位2桁)_BCD カウンタ
		movwf	temp_hh
		movf	bcd_yl,W	;年(下位2桁)_BCD カウンタ
		movwf	temp_mm
		bcf	cale_flg,4	;COL(下) LED 制御フラグ、0:滅灯
		goto	kproc12ce

		; 現在の月日を表示
kproc12cd	movf	bcd_nn,W	;月_BCD カウンタ
		movwf	temp_hh
		movf	bcd_dd,W	;日_BCD カウンタ
		movwf	temp_mm
		bsf	cale_flg,4	;COL(下) LED 制御フラグ、1:点灯

kproc12ce	btfsc	cale_flg,0	;カレンダー（年月日）の設定モードフラグ = ON か？
		goto	kproc12cf	;Yes

		movlw	h'08'
		xorwf	cale_flg,F	;bit3: 設定や表示の対象フラグの更新
		goto	kproc12cm

kproc12cf	bsf	cale_flg,5	;カレンダー（年月日）入力フラグ = ON
		goto	kproc12cm

		; カレンダー（年月日）の設定モード時の 年月日入力

kproc12cg	btfsc	cale_flg,3	;設定や表示の対象フラグ、0:年(上位下位)／1:月日 か？
		goto	kproc12ch	;1:月日

		; 年入力のチェック
		movf	temp_hh,W
		iorwf	temp_mm,W
		btfsc	STATUS,Z	;temp_hh = temp_mm = h'00' か？
		goto	kproc12ck	;Yes. (error)

		movf	temp_hh,W
		movwf	temp_yh		;仮の 年(上位2桁)_BCD カウンタ
		movf	temp_mm,W
		movwf	temp_yl		;仮の 年(下位2桁)_BCD カウンタ
		bsf	alm_flg,4	;年の入力ＯＫフラグのセット
		goto	kproc12cl

		; 月日入力のチェック
kproc12ch	movf	temp_hh,W
		btfsc	STATUS,Z	;月_BCD カウンタ temp_hh = h'00' か？
		goto	kproc12ck	;Yes. (error)

		movlw	h'12' + 1
		subwf	temp_hh,W
		btfsc	STATUS,C	;月_BCD カウンタ temp_hh < h'12' + 1 か？
		goto	kproc12ck	;No. (error)

		movf	temp_mm,W
		btfsc	STATUS,Z	;日_BCD カウンタ temp_mm = h'00' か？
		goto	kproc12ck	;Yes. (error)

		bcf	INTCON,GIE	;bit7(GIE)=1: 全割り込み禁止
		movf	temp_yh,W
		movwf	work1
		movf	bcd_yh,W	;年(上位2桁)_BCD カウンタ
		movwf	temp_yh		;退避
		movf	work1,W
		movwf	bcd_yh

		movf	temp_yl,W
		movwf	work1
		movf	bcd_yl,W	;年(下位2桁)_BCD カウンタ
		movwf	temp_yl		;退避
		movf	work1,W
		movwf	bcd_yl

		movf	bcd_nn,W	;月_BCD カウンタ
		movwf	temp_nn		;退避
		movf	temp_hh,W
		movwf	bcd_nn
		call	month_days	;各月の日数計算
		bsf	INTCON,GIE	;bit7(GIE)=1: 全割り込み許可

		subwf	temp_mm,W
		btfsc	STATUS,Z	;日_BCD カウンタ temp_mm = 各月の最終日 か？
		goto	kproc12ci	;Yes

		btfsc	STATUS,C	;temp_mm < 各月の最終日 か？
		goto	kproc12cj	;No. (error)

		; 曜日を取得
kproc12ci	bcf	INTCON,GIE	;bit7(GIE)=1: 全割り込み禁止
		movf	temp_mm,W
		movwf	bcd_dd		;日_BCD カウンタの更新

		call	day_week	;該当日の曜日を取得
		movf	cur_week,W
		movwf	week_cnt2	;WEEK カウンタ（拡張時）の更新
		bsf	INTCON,GIE	;bit7(GIE)=1: 全割り込み許可

		bsf	alm_flg,5	;年月日の設定ＯＫフラグのセット
		goto	kproc12cl

		; 入力エラー
kproc12cj	movf	temp_yh,W
		movwf	bcd_yh		;年(上位2桁)_BCD カウンタの復帰
		movf	temp_yl,W
		movwf	bcd_yl		;年(下位2桁)_BCD カウンタの復帰
		movf	temp_nn,W
		movwf	bcd_nn		;月_BCD カウンタの復帰

kproc12ck	bsf	alm_flg,6	;年月日の設定ＮＧフラグのセット
		goto	kproc12cm

kproc12cl	movlw	h'08'
		xorwf	cale_flg,F	;bit3: 設定や表示の対象フラグの更新
		bcf	cale_flg,5	;カレンダー（年月日）入力フラグ = OFF

kproc12cm	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'

		btfss	ext_flg,5	;9,SW 表示フラグ = ON か？
		goto	kproc14a	;No

		btfsc	wkcode,0	;OFF キー(15) か？
		goto	kproc14f	;Yes
		goto	kproc99		;No. ERROR'9999'

kproc14a	btfsc	wkcode,4	;SLP キー(16) か？
		goto	kproc14b	;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	kproc14c

kproc14b	bsf	ox_mode,7	;O7(SLP) = ON
		movlw	h'60'
		iorwf	fmmwwwss,F	;mm bit = b'11'

kproc14c	movf	ox_mode,W
		andlw	h'03'
		btfsc	STATUS,Z	;AM/PM の指定済み か？
		goto	kproc14d	;No

		movf	ox_week,W
		btfss	STATUS,Z	;X,WEEK の指定済み か？
		goto	kproc14i	;Yes. タイマー （定時プログラム）へ

		btfss	mode_flg,2	;定時プログラムフラグ = ON か？、(追加フラグ)	;;
		goto	kproc99		;No. ERROR'9999'

		call	ox_sw_out	;OX SW 出力へ変換
		call	ox_week_out	;OX WEEK 出力へ変換
		goto	kproc14i	;タイマー （定時プログラム）へ

kproc14d	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	kproc14e	;Yes. ダイレクト・コントロール （直接制御）へ

		call	ox_sw_out	;OX SW 出力へ変換
		goto	kproc14h	;インターバル・タイマー （間隔プログラム）へ

kproc14e	movf	ox_sw,W					;;
		btfsc	STATUS,Z	;X,SW の指定済み か？	;;
		goto	kproc99		;No. ERROR'9999'	;;

		btfsc	wkcode,4	;SLP キー(16) か？
		goto	kproc14g	;Yes

		; ON キー(14) ／ OFF キー(15) のダイレクト・コントロール （直接制御）

kproc14f	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	kproc14j

		; SLP キー(16) のダイレクト・コントロール （直接制御）

kproc14g	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	kproc14j

		; インターバル・タイマー （間隔プログラム）

kproc14h	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	kproc14j

		; タイマー （定時プログラム）

kproc14i	bcf	itv_flg,0	;インターバルフラグ = OFF
		call	time_check	;入力された数字（時刻）の有効性チェック
		btfsc	STATUS,C	;エラー か？
		goto	kproc99		;Yes. ERROR'9999'

		btfsc	STATUS,Z	;分桁 = h'a' か？
		goto	kproc14e	;Yes. (TMS1121 original)

		movf	temp_hh,W	;仮の 時_BCD カウンタ
		movwf	work1		;ワークに退避
		call	cnv_12to24	;12時間表示を24時間表示に変換
		call	write_memory	;タイマー用メモリへの書き込み
		btfsc	STATUS,C	;C フラグ = 1 か？
		goto	kproc88		;Yes. ERROR'8888'、メモリオーバーエラー

		movf	work1,W	;ワークから復帰
		movwf	temp_hh		;仮の 時_BCD カウンタ
		bsf	mode_flg,2	;定時プログラムフラグ = ON、(追加フラグ)	;;

kproc14j	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) の処理
		; -----------------------

		btfss	ext_flg,5	;9,SW 表示フラグ = ON か？
		goto	kproc18a	;No

		bcf	ext_flg,5	;9,SW 表示フラグ = OFF
		goto	kproc18i

kproc18a	movlw	h'03'
		movf	ox_sw,F
		btfss	STATUS,Z	;X,SW の処理済み か？
		goto	kproc18b	;Yes

		movlw	h'1c'
		movf	ox_week,F
		btfsc	STATUS,Z	;X,WEEK の処理済み か？
		goto	kproc18e	;No

		; X,SW,MCLR ／ X,WEEK,MCLR の処理

kproc18b	movwf	work1		;ワーク
		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	lp_cnt		;ループカウンタ

kproc18c	btfss	INDF,7		;(タイマー制御バイト) の f bit = 1 (有効) か？
		goto	kproc18d	;No

		movf	fmmwwwss,W
		andwf	work1,W		;ss / www bit を取り出し
		xorwf	INDF,W		;比較する
		andwf	work1,W
		btfsc	STATUS,Z	;ss / www bit は等しい か？
		clrf	INDF		;Yes. 消去

kproc18d	movlw	3
		addwf	FSR,F		;間接アドレス +3 更新
		decfsz	lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	kproc18c	;No
		goto	kproc18h

		; MCLR の処理（全消去）

kproc18e	btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	kproc18f	;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	kproc18j	;No

		movlw	h'f8'
		andwf	ext_flg,F	;MCLR カウンタをクリア

kproc18f	movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	3 * 20
		movwf	lp_cnt		;ループカウンタ

kproc18g	clrf	INDF		;消去
		incf	FSR,F		;間接アドレス +1 更新
		decfsz	lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	kproc18g	;No

		btfss	ext_flg,7	;拡張機能フラグ = ON か？
		clrf	PORTA		;No. （リレー）制御用出力ポートの初期設定

kproc18h	btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	kproc18i	;No

		bsf	ext_flg,6	;MCLR 表示フラグ = ON
		movlw	5
		iorwf	ext_flg,F	;MCLR カウンタの初期設定
		clrf	mcl_cnt		;MCLR 表示カウンタの初期設定
		goto	kproc18j

kproc18i	clrf	mode_flg	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,0	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,1	;X,SW 処理済みフラグ = OFF、(追加フラグ) (反 TMS1121 original)

kproc18j	goto	kproczz

;----------------------------------------------------------------

kproc19	;	movlw	19
	;	subwf	wkcode,W
		btfss	STATUS,Z	;wkcode = 19 か？
		goto	kproc20		;No

		;; CLK キー (19) の処理
		; ----------------------

		btfsc	fmmwwwss,7	;f bit = 1 (有効)  か？
		goto	kproc19d	;Yes

		btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	kproc19a	;No

		movf	ox_week,W	;WEEK セグメント出力
		btfsc	STATUS,Z	;指定されている か？
		goto	kproc19b	;No
		goto	kproc19d	;Yes. Error

kproc19a	movf	ox_week,W	;WEEK セグメント出力
		btfsc	STATUS,Z	;指定されている か？
		goto	kproc19d	;No. Error

kproc19b	movf	ox_mode,W	;MODE セグメント出力
		andlw	h'03'
		btfsc	STATUS,Z	;AM/PM が指定されている か？
		goto	kproc19d	;No. Error

		; 入力された数字（時刻）の有効性チェック

		clrf	itv_flg		;インターバルフラグ = OFF
		call	time_check	;有効性チェック
		btfsc	STATUS,C	;エラー か？
		goto	kproc99		;Yes. ERROR'9999'

		btfsc	STATUS,Z	;分桁 = h'a' か？
		goto	kproc19d	;Yes

		; 新しい曜日、時刻に設定変更

		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		goto	kproc19c	;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 を設定

kproc19c	call	cnv_12to24	;12時間表示を24時間表示に変換
		movf	temp_hh,W
		movwf	bcd_hh		;時_BCD カウンタの更新
		movf	temp_mm,W
		movwf	bcd_mm		;分_BCD カウンタの更新
		clrf	bcd_ss		;秒_BCD カウンタの更新

		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		bsf	alm_flg,5	;Yes. 年月日の設定ＯＫフラグ（兼用）= ON

kproc19d	clrf	ox_week
		clrf	mode_flg	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,0	;キー入力モードフラグ = OFF
	;;	bcf	mode_flg,1	;X,SW 処理済みフラグ = OFF、(追加フラグ) (反 TMS1121 original)
		clrf	cale_flg	;拡張機能: カレンダー（年月日）フラグ = OFF
		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
		btfsc	STATUS,Z	;wkcode = 13: SW キー か？
		goto	kprocz1		;Yes

		clrf	dsp_cnt		;表示カウンタの初期設定
		btfss	ext_flg,5	;9,SW 表示フラグ（拡張機能）= ON か？
		goto	kprocz1		;No

		bcf	ext_flg,5	;9,SW 表示フラグ（拡張機能）= OFF
		clrf	ox_sw

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 カウンタ
		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		movf	week_cnt2,W	;Yes. WEEK カウンタ（拡張時）
		movwf	work1		;ワーク
		rlf	work1,F
		rlf	work1,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	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	dsp_cnt,W	;表示カウンタ
		andlw	h'1f'
		movwf	work2

		movlw	h'00'
		btfsc	ext_flg,5	;9,SW 表示フラグ = ON か？
		movlw	h'80'		;Yes
		iorwf	wkcode,W	;キーコードワーク
		movwf	work1		;ワーク

		; タイマー用メモリの検索

		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	lp_cnt		;ループカウンタ

rdmem01		btfss	INDF,7		;fmmwwwss の f bit = 1 (有効) か？
		goto	rdmem05		;No

		btfsc	work1,7		;9,SW 表示フラグ = ON か？
		goto	rdmem04		;Yes

		movf	fmmwwwss,W
		btfsc	work1,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	rdmem05		;No

rdmem04		movf	work2,W
		btfsc	STATUS,Z	;表示カウンタ = 0 か？
		goto	rdmem06		;Yes

		decf	work2,F		;表示カウンタ - 1

rdmem05		movlw	3
		addwf	FSR,F		;間接アドレス +3 更新
		decfsz	lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	rdmem01		;No

		bsf	dsp_cnt,5	;タイマー用メモリ検索終了フラグ = ON
		call	clr_all_disp	;LED をすべて(コロンを除く)消灯
		goto	rdmem07

		; タイマー用メモリの読み出しと内容表示

rdmem06		movf	INDF,W		;
		movwf	fmmwwwss	;タイマー制御バイト
		incf	FSR,F		;間接アドレス +1 更新
		movf	INDF,W		;
		andlw	h'7f'		;メモリ自動消去フラグ = OFF
		movwf	temp_hh		;時_BCD カウンタ
		incf	FSR,F		;間接アドレス +1 更新
		movf	INDF,W		;
		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 出力へ変換

rdmem07		return

;==========================================================================
;		タイマー用メモリへの書き込み
;==========================================================================

write_memory
		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	lp_cnt		;ループカウンタ

wrmem01		btfss	INDF,7		;fmmwwwss の f bit = 1 (有効) か？
		goto	wrmem02		;No. 空き

		movlw	3
		addwf	FSR,F		;間接アドレス +3 更新
		decfsz	lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	wrmem01		;No

		bsf	STATUS,C	;C フラグ = 1、メモリオーバーエラー表示
		goto	wrmem03		;ERROR'8888'

wrmem02		bsf	fmmwwwss,7	;f bit = 1 (有効) にする
		movf	fmmwwwss,W
		movwf	INDF		;(タイマー制御バイト) へ書き込み
		incf	FSR,F		;間接アドレス +1 更新

		movf	temp_hh,W
		movwf	INDF		;(時_BCD カウンタバイト) へ書き込み
		incf	FSR,F		;間接アドレス +1 更新

		movf	temp_mm,W
		movwf	INDF		;(分_BCD カウンタバイト) へ書き込み

		bcf	STATUS,C	;C フラグ = 0、書き込み済み

wrmem03		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 カウンタ
		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		movf	week_cnt2,W	;Yes. WEEK カウンタ（拡張時）
		movwf	cur_week	;ワーク
		bcf	STATUS,C
		rlf	cur_week,F	;WEEK カウンタ
		rlf	cur_week,F	;左に 2 ビットシフト

		movlw	timer_mem	;タイマー用メモリの先頭アドレス
		movwf	FSR
		movlw	20
		movwf	lp_cnt		;ループカウンタ

tmon01		btfss	INDF,7		;fmmwwwss の f bit = 1 (メモリ有効) か？
		goto	tmon11		;No

		movf	INDF,W
		andlw	h'1c'		;www bit を取り出す
		btfsc	STATUS,Z	;www bit = 0: EDAY か？
		goto	tmon02		;Yes

		xorwf	cur_week,W
		btfss	STATUS,Z	;WEEK カウンタは等しいか？
		goto	tmon11		;No

tmon02		movf	INDF,W
		movwf	fmmwwwss	;fmmwwwss を一旦退避

		incf	FSR,F		;間接アドレス +1 更新、(時_BCD カウンタバイト)
		movf	INDF,W
		andlw	h'7f'		;メモリ自動消去フラグを削除
		subwf	bcd_hh,W
		btfss	STATUS,Z	;時_BCD カウンタは等しいか？
		goto	tmon12		;No

		incf	FSR,F		;間接アドレス +1 更新、(分_BCD カウンタバイト)
		movf	INDF,W
		subwf	bcd_mm,W
		btfss	STATUS,Z	;分_BCD カウンタは等しいか？
		goto	tmon13		;No

		; WEEK, 時, 分が等しいときの出力（リレー）制御

		movf	fmmwwwss,W	;fmmwwwss を復帰
		andlw	h'03'		;ss bit を取り出す
		movwf	work2		;ループカウンタ
		btfsc	STATUS,Z
		bsf	work2,2		;0 のときは 4 にする

		movlw	h'01'
		movwf	rx_sw		;RX(SW) 出力の初期値

tmon03		decf	work2,F
		btfsc	STATUS,Z	;ループカウンタ work2 - 1 = 0 か？
		goto	tmon04		;Yes

		bcf	STATUS,C
		rlf	rx_sw,F		;RX(SW) 出力を左に 1 ビットシフト
		goto	tmon03

tmon04		movf	rx_sw,W
		btfsc	fmmwwwss,5	;mm bit = x1: ON 出力 か？
		iorwf	PORTA,F		;Yes. リレーを ON

		xorlw	h'ff'
		btfss	fmmwwwss,5	;mm bit = x0: OFF 出力 か？
		andwf	PORTA,F		;Yes. リレーを OFF

		; アラームフラグの設定

		btfss	ext_flg,7	;拡張機能フラグ = ON か？
		goto	tmon05		;No

		btfsc	fmmwwwss,5	;mm bit = x1: ON 出力 か？
		bsf	alm_flg,0	;Yes. リレー ON フラグのセット
		btfss	fmmwwwss,5	;mm bit = x0: OFF 出力 か？
		bsf	alm_flg,1	;Yes. リレー OFF フラグのセット

		; メモリの自動消去

tmon05		decf	FSR,F		;間接アドレス -1 更新、(時_BCD カウンタバイト)
		btfss	INDF,7		;メモリ自動消去フラグ = 1 か？
		goto	tmon07		;No

		btfss	fmmwwwss,6	;mm bit = 1x: SLP か？
		goto	tmon06		;No

		btfsc	fmmwwwss,5	;mm bit = 10: OFF か？
		goto	tmon08		;No

tmon06		decf	FSR,F		;間接アドレス -1 更新、(タイマー制御バイト)
	;;	bcf	INDF,7		;f bit = 0
		clrf	INDF		;メモリの消去
		goto	tmon11		;No

		; SLP のときのメモリ内容変更

tmon07		btfss	fmmwwwss,6	;mm bit = 1x: SLP か？
		goto	tmon12		;No

tmon08		decf	FSR,F		;間接アドレス -1 更新、(タイマー制御バイト)
		movlw	h'20'
		xorwf	INDF,F		;ON/OFF ビットを反転

		incf	FSR,F		;間接アドレス +1 更新、(時_BCD カウンタバイト)
		btfsc	fmmwwwss,5	;変更前の mm bit = 10: OFF 出力 か？
		goto	tmon09		;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	tmon12		;No

		movlw	h'23'
		movwf	INDF		;時_BCD カウンタ = h'23' 設定

		movlw	h'1c'
		andwf	fmmwwwss,F
		btfsc	STATUS,Z	;www bit = 0: EDAY か？
		goto	tmon12		;Yes

		movlw	h'04'
		subwf	fmmwwwss,F	;www bit を - 1
		btfss	STATUS,Z	;www bit = 0 か？
		goto	tmon10		;No

		movlw	h'1c'
		movwf	fmmwwwss	;www bit = 7 にする
		goto	tmon10

		; OFF 出力時間に変更
tmon09		movf	INDF,W
		movwf	work1		;時_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	work1,7		;メモリ自動消去フラグ = 1 か？
		bsf	INDF,7		;Yes. メモリ自動消去フラグ = 1
		movlw	h'7f'
		andwf	INDF,W
		btfss	STATUS,Z	;時_BCD カウンタ = 0 か？
		goto	tmon12		;No

		movlw	h'1c'
		andwf	fmmwwwss,F
		btfsc	STATUS,Z	;www bit = 0: EDAY か？
		goto	tmon12		;Yes

		movlw	h'04'
		addwf	fmmwwwss,F	;www bit を + 1
		btfss	fmmwwwss,5	;www bit = 8 か？
		goto	tmon10		;No

		movlw	h'04'
		movwf	fmmwwwss	;www bit = 1 にする

		; WEEK を変更
tmon10		decf	FSR,F		;間接アドレス -1 更新、(タイマー制御バイト)
		movlw	h'e3'
		andwf	INDF,F		;www bit をクリア
		movf	fmmwwwss,W	;www bit
		iorwf	INDF,F		;新しい www bit に更新

tmon11		incf	FSR,F		;(時_BCD カウンタバイト)

tmon12		incf	FSR,F		;(分_BCD カウンタバイト)

tmon13		incf	FSR,F		;(次の タイマー制御バイト)
		decfsz	lp_cnt,F	;ループカウンタ - 1 = 0 か？
		goto	tmon01		;No

		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

;==========================================================================
;		アラーム（ブザー）音出力ルーチン
;==========================================================================

		; 時報予報音 "プッ" ブザー音出力 (100 mS)
buzzer_pu
		Sound_M		f_ra, d'100'
		return

		; 時報正報音 "ポッ～～ン" ブザー音出力 (1000 mS)
buzzer_poon
		call	buzzer_po_1_4
		call	buzzer_po_1_4
		call	buzzer_po_1_4

		; "ポッ～～ン" 1/4 ブザー音出力
buzzer_po_1_4
		Sound_M		f_rah, d'250'
		return

		; "ピッ" ブザー音出力
buzzer_pi
		Sound_M		f_so, pi_tim
		return

		; "ポッ" ブザー音出力
buzzer_po
		Sound_M		f_doh, po_tim
		return

		; "ピポッピポッ" ブザー音出力 (490 mS)
buzzer_pipo2
		call	buzzer_pipo	;"ピポッ" ブザー音出力
		call	wait_30ms

		; "ピポッ" ブザー音出力 (230 mS)
buzzer_pipo
	;;	call	buzzer_pi	;"ピッ" ブザー音出力
		Sound_M	f_so, pi_tim	;"ピッ" ブザー音出力（スタックの消費を抑えるため）
		call	wait_30ms
	;;	call	buzzer_po	;"ポッ" ブザー音出力
		Sound_M	f_doh, po_tim	;"ポッ" ブザー音出力（スタックの消費を抑えるため）
		return

		; "ブッ" ブザー音出力
buzzer_bu
		Sound_M		f_do_, bu_tim
		return

		; "ブー" ブザー音出力
buzzer_buu
		Sound_M		f_do_, buu_tim
		return	

		; "ブッブー" ブザー音出力 (450 mS)
buzzer_bubuu
		call	buzzer_bu	;"ブッ" ブザー音出力
		call	wait_100ms
		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

;==========================================================================
;		ウェイト・ルーチン (at 8 MHz)
;==========================================================================

		; 100μ秒 ウェイトルーチン
wait_100us
		movlw	39		;1
		movwf	wt1cnt		;1
wait01		goto	$+1		;2
		decfsz	wt1cnt,F	;1,2
		goto	wait01		;2,0	1+1+(2+1+2)*38+(2+2+0)=196
;		goto	$+1		;2
		return			;2	196+2=198
					;       198/8MHz*4 = 99 μS = 100 μS = 0.1 mS

		; 300μ秒 ウェイトルーチン
wait_300us
		movlw	3		;1
		goto	wait02		;2

		; 1m 秒 ウェイトルーチン
wait_1ms
		movlw	10		;1
wait02		movwf	wt2cnt		;1
wait03		call	wait_100us	;2	2+198=200
		decfsz	wt2cnt,F	;1,2
		goto	wait03		;2,0	1+1+(200+1+2)*9+(200+2+0)=2031
		return			;2	2031+2=2033
					;       2033/8MHz*4 = 1.0165 mS = 1 mS

		; 30m 秒 ウェイトルーチン
wait_30ms
		movlw	30
		goto	wait_xxms

		; 100m 秒 ウェイトルーチン
wait_100ms
		movlw	100
		goto	wait_xxms

		; 250m 秒 ウェイトルーチン
wait_250ms
		movlw	250

		; xx m 秒（ 1m 秒 x W ）ウェイトルーチン
wait_xxms
		movwf	wt2cnt		;1

w1m01		movlw	221		;1
		movwf	wt1cnt		;1

w1m02		goto	$ + 1		;2
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt1cnt,F	;1,2
		goto	w1m02		;2,0	(2+2+2+1+2)*220+(2+2+2+2+0)=1988

		nop			;1
		goto	$ + 1		;2
		goto	$ + 1		;2
		decfsz	wt2cnt,F	;1,2
		goto	w1m01		;2,0	(1+1+1988+1+2+2+1+2)*(W-1)+(1+1+1988+1+2+2+2+0)=1998*W-1

		return			;2	1+(1998*W-1)+2=1998*W+2
					;Total	(1998*W+2)/8MHz*4 = (999*W + 1) μS

;==========================================================================
;		割り込み処理
;==========================================================================

interrupt
		; レジスタの保存

		movwf	w_save		;W レジスタの保存
		swapf	STATUS,W
		clrf	STATUS
		movwf	s_save		;STATUS レジスタの保存
		movf	FSR,W
		movwf	f_save		;FSR レジスタの保存
		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

		btfsc	PIR1,TMR1IF	;タイマー１割り込み か？
		goto	t1_int		;Yes
		goto	int_end		;(Illegal interrupt)

		; 外部(RB0/INT)割り込み処理

rb0_int		bcf	INTCON,INTF	;外部割り込み(RB0/INT)解除

		decf	sec1_cnt,F
		btfsc	STATUS,Z	;１秒カウンタ - 1 = 0 か？
		goto	r0int01		;Yes

		; sec1_cnt > 0
		btfsc	init_flg,7	;電源"ON" + CLKキー"ON" 以前 か？
		goto	int_end		;Yes

		movlw	h'03'
		andwf	cale_flg,W
		btfsc	STATUS,Z	;カレンダー（年月日）設定 or 表示モード か？
		goto	int_end		;No

		bcf	STATUS,C	;AM/PM 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

		; sec1_cnt = 0
r0int01		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

r0int02	   ;;	call	bcd_smhdny_inc	;秒分時日月年_BCD カウンタのインクリメント
		goto	bcd_smhdny_inc	;（スタックの消費を抑えるため）
r0int02g
		btfss	ext_flg,7	;拡張機能 = ON か？
		goto	int_end		;No

		movlw	h'03'
		andwf	cale_flg,W
		btfss	STATUS,Z	;カレンダー（年月日）設定 or 表示モード か？
		goto	r0int03		;Yes

		movlw	h'10'
		xorwf	ext_flg,F	;bit4: COL LED 点滅（ブリンク）制御
		goto	int_end

r0int03		bcf	ext_flg,4	;bit4: COL LED 常時滅灯
		movlw	h'04'
		xorwf	cale_flg,F	;bit2: AM/PM 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

		; タイマー１割り込み処理

t1_int		bcf	PIR1,TMR1IF	;タイマー１割込みフラグをクリア

		movf	const_high,W	;音階用分周定数 high を
		movwf	TMR1H		;TMR1H に設定
		movf	const_low,W	;音階用分周定数 low を
		movwf	TMR1L		;TMR1L に設定

		movlw	1 << buzzer	;対象ビットをセット
		xorwf	PORTA,F		;出力をビット反転
;		goto	int_end

		; 割り込み処理の終了

int_end		movf	p_save,W
		movwf	PCLATH		;PCLATH レジスタの復帰
		movf	f_save,W
		movwf	FSR		;FSR レジスタの復帰
		swapf	s_save,W
		movwf	STATUS		;STATUS レジスタの復帰
		swapf	w_save,F
		swapf	w_save,W	;W レジスタの復帰

		retfie			;割り込みからの復帰	

;--------------------------------------------------------------------------
;   秒、分、時、日、月、年_BCD カウンタと WEEK カウンタのインクリメント
;--------------------------------------------------------------------------

; call:		inc_bcd, month_days, day_week, ox_week_out_x

bcd_smhdny_inc
		; 秒_BCD カウンタのインクリメント

		movlw	bcd_ss		;秒_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCDインクリメント
		movlw	h'60'
		subwf	bcd_ss,W
		btfsc	STATUS,C	;秒_BCD カウンタ >= h'60' か？
		goto	smhinc06	;Yes

		btfss	ext_flg,7	;拡張機能 = ON か？
		goto	smhinc10	;No

		; カレンダー（年月日）フラグのセット

		movf	bcd_mm,W
		btfss	STATUS,Z	;分_BCD カウンタ = h'00' か？
		goto	smhinc05	;No

		movlw	h'10'
		subwf	bcd_ss,W
		btfsc	STATUS,Z	;秒_BCD カウンタ = h'10' か？
		goto	smhinc01	;Yes

		movlw	h'13'
		subwf	bcd_ss,W
		btfsc	STATUS,Z	;秒_BCD カウンタ = h'13' か？
		goto	smhinc03	;Yes

		movlw	h'16'
		subwf	bcd_ss,W
		btfsc	STATUS,Z	;秒_BCD カウンタ = h'16' か？
		goto	smhinc02	;Yes

		movlw	h'19'
		subwf	bcd_ss,W
		btfsc	STATUS,Z	;秒_BCD カウンタ = h'19' か？
		goto	smhinc03	;Yes

		movlw	h'22'
		subwf	bcd_ss,W
		btfsc	STATUS,Z	;秒_BCD カウンタ = h'22' か？
		goto	smhinc02	;Yes

		movlw	h'25'
		subwf	bcd_ss,W
		btfsc	STATUS,Z	;秒_BCD カウンタ = h'25' か？
		goto	smhinc03	;Yes

		movlw	h'28'
		subwf	bcd_ss,W
		btfsc	STATUS,Z	;秒_BCD カウンタ = h'28' か？
		goto	smhinc04	;Yes
		goto	smhinc05

smhinc01	bsf	cale_flg,1	;カレンダー（年月日）の表示モードフラグ = ON

smhinc02	bcf	cale_flg,4	;COL(下) LED 制御フラグ = 0:滅灯、年(上位2桁) + 年(下位2桁) 表示指示
		goto	smhinc05

smhinc03	bsf	cale_flg,4	;COL(下) LED 制御フラグ = 1:点灯、月(上位2桁) + 日(下位2桁) 表示指示
		goto	smhinc05

smhinc04	bcf	cale_flg,1	;カレンダー（年月日）の表示モードフラグ = OFF
		bcf	cale_flg,4	;COL(下) LED 制御フラグ、0:滅灯

		; 時報予報音フラグ (440Hz) のセット、"プッ"

smhinc05	movlw	h'59'
		subwf	bcd_mm,W	;分_BCD カウンタ
		btfss	STATUS,Z	;bcd_mm = h'59' か？
		goto	smhinc10	;No

		movlw	h'57'
		subwf	bcd_ss,W	;秒_BCD カウンタ
		btfsc	STATUS,C	;bcd_ss >= h'57' か？
		bsf	alm_flg,2	;Yes. 時報予報音フラグ (440Hz) のセット
		goto	smhinc10

smhinc06	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	smhinc10	;No

		clrf	bcd_mm		;分_BCD カウンタのクリア

		; 時報正報音フラグ (880Hz) のセット、"ポッ～～ン"

		btfsc	ext_flg,7	;拡張機能 = ON か？
		bsf	alm_flg,3	;Yes. 時報正報音フラグ (880Hz) のセット

		; 時_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	smhinc10	;No

		clrf	bcd_hh		;時_BCD カウンタのクリア

		; 日_BCD カウンタのインクリメント

		call	month_days	;各月の日数計算
		subwf	bcd_dd,W
		btfsc	STATUS,Z	;日_BCD カウンタ = 各月の最終日 か？
		goto	smhinc07	;Yes

		movlw	bcd_dd		;日_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント
		goto	smhinc08

smhinc07	movlw	h'01'
		movwf	bcd_dd		;日_BCD カウンタ = h'01' 設定

		; 月_BCD カウンタのインクリメント

		movlw	bcd_nn		;月_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'13'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月_BCD カウンタ = h'13' か？
		goto	smhinc08	;No

		movlw	h'01'
		movwf	bcd_nn		;月_BCD カウンタ = h'01' 設定

		; 年(下位2桁)_BCD カウンタのインクリメント

		movlw	bcd_yl		;年(下位2桁)_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'a0'
		subwf	bcd_yl,W
		btfss	STATUS,Z	;年(下位2桁)_BCD カウンタ = 'a0' か？
		goto	smhinc08	;No

		clrf	bcd_yl		;年(下位2桁)_BCD カウンタ = h'00' 設定

		; 年(上位2桁)_BCD カウンタのインクリメント

		movlw	bcd_yh		;年(上位2桁)_BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'a0'
		subwf	bcd_yh,W
		btfss	STATUS,Z	;年(上位2桁)_BCD カウンタ = 'a0' か？
		goto	smhinc08	;No

		clrf	bcd_yh		;年(上位2桁)_BCD カウンタ = h'00' 設定
		movlw	h'01'
		movwf	bcd_yl		;9999 → (0000) → 0001

		; WEEK カウンタのインクリメント

		; （オリジナルのとき用）
smhinc08	incf	week_cnt,F	;WEEK カウンタ + 1
		movlw	7 + 1
		subwf	week_cnt,W
		btfss	STATUS,C	;WEEK カウンタ < 7 + 1 か？
		goto	smhinc09	;Yes

		movlw	1
		movwf	week_cnt	;WEEK カウンタの初期設定 = 1:SUN

		; （拡張機能のとき用）
smhinc09	call	day_week	;該当日の曜日を取得
		movf	cur_week,W
		movwf	week_cnt2	;WEEK カウンタ（拡張時）の更新

		btfsc	mode_flg,0	;キー入力モードフラグ = ON か？
		goto	smhinc10	;Yes

		movf	week_cnt,W	;WEEK カウンタ
		btfsc	ext_flg,7	;拡張機能フラグ = ON か？
		movf	week_cnt2,W	;Yes. WEEK カウンタ（拡張時）
		call	ox_week_out_x	;WEEK カウンタ値から OX WEEK 出力へ変換

smhinc10   ;;	return
		goto	r0int02g	;（スタックの消費を抑えるため）

;==========================================================================
;	拡張（カレンダー）機能に必要なサブルーチン ... (Ver. 1.30 追加)
;==========================================================================

; ＜参考＞　スタックの消費改善

;  改善前
;  　   　(main) → (key_processing) → (buzzer_pipo) → (buzzer_pi) → (buzzer_control) → (wait_xxms)
; 　　           (1)                 (2)              (3)...xx       (4)                 (5)

;     　　→ (interrupt) → (bcd_smhdny_inc) → (month_days) → (uruu_check) → (bcd2_to_binary)
;     　　(6)            (7)...xx            (8)             (9)...暴走     (10)

;  改善後
;  　   　(main) → (key_processing) → (buzzer_pipo) → (buzzer_control) → (wait_xxms)
;  　　          (1)                 (2)              (3)                 (4)

;  　   　→ (interrupt) → (month_days) → (uruu_check)
;  　   　(5)            (6)             (7)

;--------------------------------------------------------------------------
;		各月の日数計算
;--------------------------------------------------------------------------

; 入力:		bcd_yh, bcd_yl, bcd_nn
; 出力:		W_reg
; ワーク:	cur_yh, cur_yl
; call:		uruu_check

month_days
		movlw	h'02'
		subwf	bcd_nn,W
		btfss	STATUS,Z	;月 BCD カウンタ = h'02' か？
		goto	mday01		;No

		movf	bcd_yl,W	;年(下位2桁) BCD カウンタ
		movwf	cur_yl
		movf	bcd_yh,W	;年(上位2桁) BCD カウンタ
		movwf	cur_yh
		call	uruu_check	;平年／閏年の判定

		movlw	h'28'		;平年 2月
		btfsc	uru_flag,0	;閏年 か？
		movlw	h'29'		;Yes. 閏年 2月
		goto	mday03

mday01		movlw	h'04'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'04' か？
		goto	mday02		;Yes

		movlw	h'06'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'06' か？
		goto	mday02		;Yes

		movlw	h'09'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'09' か？
		goto	mday02		;Yes

		movlw	h'11'
		subwf	bcd_nn,W
		btfsc	STATUS,Z	;月 BCD カウンタ = h'11' か？
		goto	mday02		;Yes

		movlw	h'31'		;h'01', h'03', h'05', h'07', h'08', h'10', h'12'
		goto	mday03

mday02		movlw	h'30'		;h'04', h'06', h'09', h'11'

mday03		return

;--------------------------------------------------------------------------
;		該当日の曜日を取得
;--------------------------------------------------------------------------

; 入力:		bcd_yh: 年(上位2桁)_BCD カウンタ, bcd_yl: 年(下位2桁)_BCD カウンタ,
;		bcd_nn: 月_BCD カウンタ, bcd_dd: 日_BCD カウンタ

; 出力:		cur_week: ( 0:日, 1:月, 2:火, 3:水, 4:木, 5:金, 6:土 )
;  (+1して出力)	cur_week: ( 1:日, 2:月, 3:火, 4:水, 5:木, 6:金, 7:土 )

; ワーク:	cur_yh, cur_yl, xxx_yh
; call:		bcd2_to_binary, uruu_check, inc_bcd, month_day2

day_week
		movlw	h'01'
		movwf	cur_yl		;西暦元年 = '0001' とする
		clrf	cur_yh		;

		movlw	h'01'
		movwf	cur_week	;初期設定 (西暦元年1月1日 = 月曜日 とする)

		; 年の変換 (400年後毎の同月同日は同じ曜日)

		movf	bcd_yh,W	;年(上位2桁)_BCD カウンタ
		call	bcd2_to_binary	;バイナリ変換
		movwf	xxx_yh		;
					;
dweek01		movlw	4		;
		subwf	xxx_yh,W	;
		btfss	STATUS,C	;xxx_yh < 4 か？
		goto	dweek03		;Yes
					;
		btfss	STATUS,Z	;xxx_yh = 4 か？
		goto	dweek02		;No
					;
		movf	bcd_yl,W	;
		btfsc	STATUS,Z	;bcd_yl = 0 か？
		goto	dweek03		;Yes
					;
dweek02		movlw	4		;
		subwf	xxx_yh,F	;
		goto	dweek01		;

		; 年の計算

dweek03		movf	bcd_yl,W	;年(下位2桁)_BCD カウンタ
		subwf	cur_yl,W
		btfss	STATUS,Z	;cur_yl = bcd_yl か？
		goto	dweek04		;No

		movf	xxx_yh,W	;xxx_yh =< 4 (400年以下に変換)
		subwf	cur_yh,W
		btfsc	STATUS,Z	;cur_yh = xxx_yh か？
		goto	dweek05		;Yes

dweek04		movlw	365 % 7		;365 % 7 = 365 - 7 * 52 = 1
		addwf	cur_week,F
		call	uruu_check	;平年／閏年の判定
		btfsc	uru_flag,0	;平年 か？
		incf	cur_week,F	;No. 閏年

		movlw	7
		subwf	cur_week,W
		btfsc	STATUS,C	;cur_week < 7 か？
		movwf	cur_week	;No

		movlw	cur_yl		;年(下位2桁)(変) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント

		movlw	h'a0'
		subwf	cur_yl,W
		btfss	STATUS,Z	;年(下位2桁)(変) BCD カウンタ = h'a0' か？
		goto	dweek03		;No

		clrf	cur_yl		;年(下位2桁)(変) BCD カウンタ = h'00' 設定

		movlw	cur_yh		;年(上位2桁)(変) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント
		goto	dweek03

		; 月の計算

dweek05		movlw	h'01'
		movwf	cur_nn		;月(変) BCD カウンタ

dweek06		movf	bcd_nn,W	;月_BCD カウンタ
		subwf	cur_nn,W
		btfsc	STATUS,Z	;cur_nn = bcd_nn か？
		goto	dweek08		;Yes

		movf	cur_nn,W
		call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
		movwf	work1		;退避
		call	month_day2	;月データのテーブル読み出し	;;;;;
		addwf	cur_week,F
		movlw	h'02'
		subwf	cur_nn,W
		btfss	STATUS,Z	;cur_nn = 2 か？
		goto	dweek07		;No

		call	uruu_check	;平年／閏年の判定
		btfsc	uru_flag,0	;平年 か？
		incf	cur_week,F	;No. 閏年

dweek07		movlw	7
		subwf	cur_week,W
		btfsc	STATUS,C	;cur_week < 7 か？
		movwf	cur_week	;No

		movlw	cur_nn		;月(変) BCD カウンタの番地
		movwf	FSR		;間接アドレスに設定
		call	inc_bcd		;BCD インクリメント
		goto	dweek06

		; 日の計算

dweek08		movf	bcd_dd,W	;日_BCD カウンタ
		call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
		addwf	cur_week,F
		decf	cur_week,F	;-1（当日分）

dweek09		movlw	7
		subwf	cur_week,W
		btfss	STATUS,C	;cur_week < 7 か？
		goto	dweek10		;Yes

		movwf	cur_week	;No
		goto	dweek09

dweek10		incf	cur_week,F	;0～6 → 1～7 に変換
		return

;--------------------------------------------------------------------------
;		月データのテーブル読み出し
;--------------------------------------------------------------------------

; 入力:		work1 ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 )
; 出力:		W_reg

#ifdef comment
month_day2
;		movlw	high day_tbl	;月データの high アドレス
;		movwf	PCLATH
;		decf	work1,W
;		addlw	low day_tbl	;月データの low アドレス
;		movwf	PCL

;;		decf	work1,W
;;		addwf	PCL,F		;プログラム・カウンタに加算

day_tbl		retlw	31 % 7		; 1:  31 % 7 = 3
		retlw	28 % 7		; 2:  28 % 7 = 0
		retlw	31 % 7		; 3:  31 % 7 = 3
		retlw	30 % 7		; 4:  30 % 7 = 2
		retlw	31 % 7		; 5:  31 % 7 = 3
		retlw	30 % 7		; 6:  30 % 7 = 2
		retlw	31 % 7		; 7:  31 % 7 = 3
		retlw	31 % 7		; 8:  31 % 7 = 3
		retlw	30 % 7		; 9:  30 % 7 = 2
		retlw	31 % 7		;10:  31 % 7 = 3
		retlw	30 % 7		;11:  30 % 7 = 2
;		retlw	31 % 7		;12:  31 % 7 = 3  (使用しない)
#endif

month_day2
		decf	work1,F
		btfsc	STATUS,Z	;work1 =  1 か？
		goto	mday21		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  2 か？
		goto	mday22		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  3 か？
		goto	mday21		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  4 か？
		goto	mday23		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  5 か？
		goto	mday21		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  6 か？
		goto	mday23		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  7 か？
		goto	mday21		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  8 か？
		goto	mday21		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 =  9 か？
		goto	mday23		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 = 10 か？
		goto	mday21		;Yes

		decf	work1,F
		btfsc	STATUS,Z	;work1 = 11 か？
		goto	mday23		;Yes

mday21		movlw	31 % 7
		goto	mday24

mday22		movlw	28 % 7
		goto	mday24

mday23		movlw	30 % 7

mday24		return

;--------------------------------------------------------------------------
;		平年／閏年の判定
;--------------------------------------------------------------------------

; 入力:		cur_yh: 年(上位2桁)_BCD カウンタ, cur_yl: 年(下位2桁)_BCD カウンタ
; 出力:		uru_flag: ( 0:平年, 1:閏年 )
; ワーク:	work1, work2
; call:		なし

uruu_check
		clrf	uru_flag	;平年に設定

		movf	cur_yl,W	;年(下位2桁)(変) BCD カウンタ
	;;;	call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
	;;-----begin-----（スタックを消費させないため）
		movwf	work1		;退避
		swapf	work1,W		;上位4ビット(10位)を BCD からバイナリ変換
		andlw	h'0f'
		movwf	work2
		bcf	STATUS,C
		rlf	work2,F		;2倍
		rlf	work2,F		;4倍
		addwf	work2,F		;5倍
		rlf	work2,F		;10倍

		movf	work1,W		;下位4ビット(単位)
		andlw	h'0f'
		addwf	work2,W		;10位 + 単位 = W レジスタ
	;;-----end-----
		andlw	h'03'		;下位2ビット
		btfss	STATUS,Z	;下位2ビット = b'00' か？
		goto	uru02		;No. 平年 ... 4で割れない

		movf	cur_yl,W
		btfss	STATUS,Z	;年(下位2桁)(変) BCD カウンタ = h'00' か？
		goto	uru01		;No. 閏年 ... 100で割れない

		movf	cur_yh,W	;年(上位2桁)(変) BCD カウンタ
	;;;	call	bcd2_to_binary	;BCD (2桁) からバイナリ変換
	;;-----begin-----
		movwf	work1		;退避
		swapf	work1,W		;上位4ビット(10位)を BCD からバイナリ変換
		andlw	h'0f'
		movwf	work2
		bcf	STATUS,C
		rlf	work2,F		;2倍
		rlf	work2,F		;4倍
		addwf	work2,F		;5倍
		rlf	work2,F		;10倍

		movf	work1,W		;下位4ビット(単位)
		andlw	h'0f'
		addwf	work2,W		;10位 + 単位 = W レジスタ
	;;-----end-----
		andlw	h'03'		;下位2ビット
		btfss	STATUS,Z	;下位2ビット = b'00' か？
		goto	uru02		;No. 平年 ... 400で割れない

uru01		bsf	uru_flag,0	;閏年に設定

uru02		return

;--------------------------------------------------------------------------
;		BCD (2桁) からバイナリ変換
;--------------------------------------------------------------------------

; 入力:		W_reg
; 出力:		W_reg
; ワーク:	work1, work2

bcd2_to_binary
		movwf	work1		;退避
		swapf	work1,W		;上位4ビット(10位)を BCD からバイナリ変換
		andlw	h'0f'
		movwf	work2
		bcf	STATUS,C
		rlf	work2,F		;2倍
		rlf	work2,F		;4倍
		addwf	work2,F		;5倍
		rlf	work2,F		;10倍

		movf	work1,W		;下位4ビット(単位)
		andlw	h'0f'
		addwf	work2,W		;10位 + 単位 = W レジスタ
		return

;==========================================================================
;		EEPROM エリア
;==========================================================================

		org	h'2100'

eep_st		de	"Copyright (C) 2019-2021 by M.Yamamoto"

;==========================================================================

		end			;プログラムの終了
