; Tab width = 4

;----------------------------------------------------------------------------
; ** 分・秒カウンタ (LCD表示, タイマ(T0)割り込み, サウンド使用サンプル) **
;
; ・プログラムスタートからの時間をカウントする(0〜99分59秒)
; ・1分ごとに音を鳴らす
;----------------------------------------------------------------------------
; 1.01 990208 SEGA Enterprises,LTD.
;----------------------------------------------------------------------------

chip	LC868700			; チップの種類をアセンブラに指定
world	external			; 外部メモリ用プログラム

public	main				; ghead.asm から参照されるシンボル
public	int_T0H				; ghead.asm から参照されるシンボル

extern	_game_end			; アプリケーション終了


; **** システム定数の定義 ***************************************************

							; OCR(発振制御レジスタ)設定値
osc_rc		equ 04dh		;	システムクロックに内蔵RC発振を指定
osc_xt		equ 0efh		;	システムクロックに水晶発振を指定


; *** データセグメント ******************************************************

		dseg				; データセグメント開始

r0:		ds		1			; 間接アドレッシングレジスタ r0
r1:		ds		1			; 間接アドレッシングレジスタ r1
r2:		ds		1			; 間接アドレッシングレジスタ r2
r3:		ds		1			; 間接アドレッシングレジスタ r3
		ds		12			; その他のレジスタ

work1:	ds		1			; 作業用(put2digitで使用)

second:	ds		1			; 秒カウンタ
minute:	ds		1			; 分カウンタ


; *** コードセグメント ******************************************************

		cseg				; コードセグメント開始
		
; *-------------------------------------------------------------------------*
; * ユーザープログラム														*
; * タイマ(T0)割り込みサンプル「分・秒カウンタ」							*
; *-------------------------------------------------------------------------*
main:
		mov		#0, second	; メモリ上のカウント値をリセットする
		mov		#0, minute	;

		call	cls			; LCDの消去
		call	T0Mode2Init	; タイマT0の初期化
		call	SndInit		; 音声出力の初期化
		
loop0:
							; **** minuteの数値をLCDに表示する ****
		mov		#0,c		;   水平座標
		mov		#1,b		;   垂直座標
		ld		minute		;   表示対象数値(分)
		call	put2digit	;   2桁数値表示
		
							; ****「:」をLCDに表示する ****
		mov		#2,c		;   水平座標
		mov		#1,b		;   垂直座標
		mov		#10,acc		;   キャラクタコード
		call	putch		;   1文字表示
	
							; **** secondの数値をLCDに表示する ****
		mov		#3,c		;   水平座標
		mov		#1,b		;   垂直座標
		ld		second		;   表示対象数値(秒)
		call	put2digit	;   2桁数値表示

							; ****「.」をLCDに表示する ****
		mov		#5,c		;  垂直座標
		mov		#1,b		;   垂直座標
		mov		#11,acc		;  キャラクタコード
		call	putch		;  1文字表示

							; **** 00秒〜01秒までブザーを鳴らす ****
		ld		second		; second値の読み込み
		bnz		next3		; second != 0 ならnext3
		call	Snd2Start	; second == 0 なら音発生
next3:						;
		ld		second		; second値の読み込み
		bnz		next4		; second != 1 ならnext4
		call	SndStop		; second == 1 なら音停止
next4:						;
		
		set1	pcon,0		; 次の割り込みまでHALT

							; ** [M](モード)ボタンチェック **
		ld		P3
		bn		acc,6,finish ; [M]ボタンが押されていたらアプリ終了

		jmp		loop0		; 繰り返し

finish:						; ** アプリケーション終了処理 **
		jmp		_game_end	; アプリケーション終了


; *-------------------------------------------------------------------------*
; * タイマ/カウンタT0 の初期化												*
; *   モード2(16bitカウンタ)で、1秒毎に割り込みをかける						*
; *-------------------------------------------------------------------------*
T0Mode2Init:
		mov		#255,T0PRR	; プリスケーラ値セット
							;   8bitプリスケーラなので
							;   周期 = (256-255)*0.000183 = 0.000183
		mov		#high(65536-5464),T0HR ; プリセット値(H)セット
		mov		#low(65536-5464),T0LR  ; プリセット値(L)セット
							;   プリスケーラとセットで
							;   0.000183 * 5464 = 0.999912 (≒1sec)
							;   1秒毎にオーバーフローが起こる
		mov		#0ffh,T0L	; 最初すぐにオーバーフローするようにする
		mov		#0ffh,T0H	;
		mov		#0e4h,T0CNT	; モード2 (16bitカウンタ)
							; T0Hオーバーフローで割り込みを発生させる
							; T0動作開始
		
		; 割り込みが許可されている必要がある (mov #80h,IE)
	
		ret					; T0Mode2Init終わり


T0HStop:					; *** T0Hタイマ停止 ***

		clr1	T0CNT,6		; T0Lカウント動作停止
		clr1	T0CNT,7		; T0Hカウント動作停止
		ret


; *-------------------------------------------------------------------------*
; * タイマT0H割り込みハンドラ												*
; *-------------------------------------------------------------------------*
int_T0H:					; *** T0H割り込みハンドラ ***
		push	acc

		inc		second		; 秒カウンタを進める
		ld		second		; 秒カウンタが..
		bne		#60,tinx1	; 60でなければtinx1へ
		mov		#0,second	; 60なら0にリセット
		inc		minute		; 分カウンタを進める

		ld		minute		; 分カウンタが..
		bne		#100,tinx1	; 100でなければtinx1へ
		mov		#0,minute	; 100ならば分カウンタを0にリセット
tinx1:	
		pop		acc

		clr1	T0CNT,3		; タイマ割り込み要因クリア
		clr1	T0CNT,1		;
		reti				; T0H割り込みハンドラ終わり


; *-------------------------------------------------------------------------*
; * 音声出力関係
; *-------------------------------------------------------------------------*
SndInit:					; *** 音声出力ハードの初期化 ***
		clr1	P1,7		; 音声出力ポートセット
	
		ret
		
Snd1Start:					; *** 約342Hz の発音開始 ***
		mov		#0f0h,T1LR	; 周期 = 100h-0f0h = 16
		mov		#0f8h,T1LC	; Lレベル幅 = 100h-0f8h = 8
		mov		#0D4h,T1CNT	; 音声出力開始
		
		ret

Snd2Start:					; *** 約781Hz の発音開始 ***
		mov		#0f9h,T1LR	; 周期 = 100h-0f9h = 7
		mov		#0fch,T1LC	; Lレベル幅 = 100h-0fch = 4
		mov		#0D4h,T1CNT	; 音声出力開始
		
		ret

SndStop:					; *** 発音停止 ***
		mov		#0,T1CNT	; 音声出力停止
		
		ret

		
; *-------------------------------------------------------------------------*
; * 2桁の数値を表示する														*
; * 入力 acc : 数値															*
; *        c : 文字水平位置												  	*
; *        b : 文字垂直位置												  	*
; *-------------------------------------------------------------------------*
put2digit:
		push	b			; 座標データを退避
		push	c			;
		st		c			; 10の位と1の位の値をそれぞれ計算
		xor		a			; ( acc = acc/10, work1 = acc mod 10 )
		mov		#10,b		;
		div					;
		ld		b			;
		st		work1		; 1の位の計算結果をwork0に保存
		ld		c			;
		pop		c			; 座標値を(c.b)に復帰
		pop		b			; 
		push	b			; また退避
		push	c			;
		call	putch		; 10の位を表示
		ld		work1			; 1の位の値を読み込み
		pop		c			; 座標値を(c,b)に復帰
		pop		b			; 
		inc		c			; 表示座標を右へ
		call	putch		; 1の位を表示

		ret					; put2digit終わり


; *-------------------------------------------------------------------------*
; * LCD表示イメージを消去する												*
; *-------------------------------------------------------------------------*
cls:
		push	OCR			; OCR値を退避
		mov		#osc_rc,OCR ; システムクロックを指定

		mov		#0,XBNK		; 表示用RAMのバンクアドレスを指定(BANK0)
		call	cls_s		; そのバンク内のデータをクリア

		mov		#1,XBNK		; 表示用RAMのバンクアドレスを指定(BANK1)
		call	cls_s		; そのバンク内のデータをクリア
		pop		OCR			; OCR値を復帰
		
		ret					; cls終わり
		
cls_s:						; *** 表示用RAM 1BANK分の消去 ***
		mov		#80h,r2		; 間接アドレッシングレジスタを表示用RAMの先頭に
		mov		#80h,b 		; ループカウンタbにループ数をセット
loop3:
		mov		#0,@r2		; アドレスをインクリメントしながら0を書き込む
		inc		r2			;
		dbnz	b,loop3		; bが0になるまで繰り返す
		
		ret					; cls_s終わり
		

; *-------------------------------------------------------------------------*
; * 指定位置に1キャラクタ表示する											*
; * 入力 acc : キャラクタコード												*
; *        c : 文字水平位置												  	*
; *        b : 文字垂直位置												  	*
; *-------------------------------------------------------------------------*
putch:
		push	XBNK
		push	acc
		call	locate		; 座標から表示RAMのアドレスを計算
		pop		acc
		call	put_chara	; 1キャラクタ表示する
		pop		XBNK
		
		ret					; putch終わり
		

locate:	; **** 表示位置指定から表示用RAMのアドレスを計算 ****
		; ** 入力 c: 水平位置(0〜5) b: 垂直位置(0〜3)
		; ** 出力 r2: RAMアドレス XBNK: 表示用RAMバンク

							; *** 表示用RAMバンクアドレスの判断 ***
		ld		b			; b>=2 のとき next1 へ
		sub		#2			;
		bn		PSW,7,next1	;
		
		mov		#00h,XBNK	; 表示用RAMのバンクアドレスを指定(BANK0)
		br		next2
next1:
		st		b
		mov		#01h,XBNK	; 表示用RAMのバンクアドレスを指定(BANK1)
next2:

							; *** 表示指定位置のRAMアドレス計算 ***
		ld		b			; b * 40h + c + 80h
		rol					;
		rol					;
		rol					;
		rol					;
		rol					;
		rol					;
		add		c			;
		add		#80h		;
		st		r2			; RAMアドレスをr2に格納
				
		ret					; locate終わり


put_chara:
		push	PSW			; PSW値を退避
		set1	PSW,1		; データRAMバンク1を選択

							; *** キャラクタデータアドレスの計算 ***
		rol					; (TRH,TRL) = acc*8 + fontdata
		rol					;
		rol					;	
		add		#low(fontdata)	;
		st		TRL				;
		mov		#0,acc			;
		addc	#high(fontdata)	;
		st		TRH			;

		push	OCR			; OCR値を退避
		mov		#osc_rc,OCR ; システムクロックを指定

		mov		#0,b		; キャラクタデータ読み出し用オフセット値
		mov		#4,c		; ループカウンタ
loop1:
		ld		b			; 1ライン目の表示データを読み出す
		ldc					;
		inc		b			; 読み出しデータのオフセットを +1
		st		@r2			; 表示データを表示用RAMに転送
		ld		r2			; 表示用RAMアドレス +6
		add		#6			;
		st		r2			;

		ld		b			; 2ライン目の表示データを読み出す
		ldc					;
		inc		b			; 読み出しデータのオフセットを +1
		st		@r2			; 表示データを表示用RAMに転送
		ld		r2			; 表示用RAMアドレス +10
		add		#10			;
		st		r2			;
		
		dec		c			; ループカウンタのデクリメント
		ld		c			; 
		bnz		loop1		; 8ライン分(4回)繰り返し
		
		pop		OCR			; OCR値を復帰
		pop		PSW			; PSW値を復帰

		ret					; put_chara終わり


; *-------------------------------------------------------------------------*
; * キャラクタのビットイメージデータ										*
; *-------------------------------------------------------------------------*
fontdata:
		db 07ch, 0e6h, 0c6h, 0c6h, 0c6h, 0ceh, 07ch, 000h	;0
		db 018h, 038h, 018h, 018h, 018h, 018h, 03ch, 000h	;1
		db 07ch, 0c6h, 0c6h, 00ch, 038h, 060h, 0feh, 000h	;2
		db 07ch, 0e6h, 006h, 01ch, 006h, 0e6h, 07ch, 000h	;3
		db 00ch, 01ch, 03ch, 06ch, 0cch, 0feh, 00ch, 000h	;4
		db 0feh, 0c0h, 0fch, 006h, 006h, 0c6h, 07ch, 000h	;5
		db 01ch, 030h, 060h, 0fch, 0c6h, 0c6h, 07ch, 000h	;6
		db 0feh, 0c6h, 004h, 00ch, 018h, 018h, 038h, 000h	;7
		db 07ch, 0c6h, 0c6h, 07ch, 0c6h, 0c6h, 07ch, 000h	;8
		db 07ch, 0c6h, 0c6h, 07eh, 006h, 00ch, 078h, 000h	;9
        
        db 000h, 030h, 030h, 000h, 000h, 030h, 030h, 000h	;:
        db 000h, 000h, 000h, 000h, 000h, 060h, 060h, 000h	;.

