H.TIMI割込みの話:その2
noteのダッシュボードをみると過去記事のH.TIMIの話にけっこう人気があるみたいです。
前回記事ではサウンドドライバの話まで踏み込んでしまっているので、H.TIMI単体としての使い方がぼやけてしまったかもしれません。
そのため、今回はH.TIMIの話に限定してサンプルを作成しました。
コメントをばりばり書いてますので、前回記事のサンプルコードよりかはみやすくなっている(はず)です。
このサンプルではメイン処理をH.TIMIのタイミングで呼び出し、1秒ごとに画面を書き換えるだけのサンプルになっています。
一応、全コードもここに掲載しておきますね。
ORG $D000
;
; BIOS SUBROUTINE
; BIOSサブルーチンの定義
;
SETWRT:equ $0053
FILVRM:equ $0056
CHGMOD:equ $005F
ERAFNK:equ $00CC
; Work area addresses.
; ワークエリアアドレスの定義
LINWID:equ $F3AF ; WIDTH
RG0SAV:equ $F3DF ; VDP#0 Register
FORCLR:equ $F3E9 ; Fore ground color
BAKCLR:EQU $F3EA ; Back ground color
BDRCLR:equ $F3EB ; Border color
; =================
; H.TIMI hook address
; =================
H_TIMI:equ $FD9F ; H.TIMI hook address
;===========================
; Variables
; 変数定義
;===========================
VBLANK_WAIT_FLG:equ $E000
TIMER_COUNTER:equ $E001
H_TIMI_BACKUP:equ $E002
DISP_CHAR_TYPE:equ $E007
; Main procedure.
; メイン処理
MAIN:
xor a
ld (TIMER_COUNTER), a
ld (DISP_CHAR_TYPE), a
; Initialize screen
; 画面の初期化
ld a, $0F
ld (FORCLR), a
ld a, $01
ld (BAKCLR), a
ld (BDRCLR), a
;SCREEN1,2
ld a,(RG0SAV+1)
or 2
ld (RG0SAV+1),a
ld a, 1 ; SCREEN MODE = 1
call CHGMOD
ld a, 32 ;WIDTH=32
ld (LINWID), a
; Disable FUNCTION KEY DISPLAY.
call ERAFNK
;=============================
; Initialize H.TIMI Handler
; H.TIMIのHOOK処理を変更する
;=============================
ld (VBLANK_WAIT_FLG), a
call INIT_H_TIMI_HANDLER
;==================================
; Wait for H_TIMI(VBLANK) and call your procedure
; each time VBLANK.
; H_TIMI(VBLANK)を待ち
; VBLANKのつど、自分の処理を呼び出す
;==================================
H_TIMI_HOOK_LOOP:
;
; Set one to VBLANK_WAIT_FLG
; VBLANK_WAIT_FLGに1をセットする
;
; The value of this variable is updated to 0 by the
; H_TIMI_HANDLER process when H.TIMI is hooked.
; 変数の値はH_TIMI_HANDLER処理にて0に更新される
;
ld a, 1
ld (VBLANK_WAIT_FLG), a
;=============================
; Jump to the REDRAW_SCREEN procedure.
; Return to VBLAN_WAIT when REDRAW_SCREEN
; process is finished.
; Rewriting this process to a process of
; your choice will cause H.TIMI to call your process.
;
; REDRAW_SCREEN処理にジャンプする
; REDRAW_SCREEN処理が終わったらVBLAN_WAITに
; 戻る
; この処理を自分の好きな処理に書き換えることで
; H.TIMIに自分の処理が呼ばれるようになる
;=============================
jp REDRAW_SCREEN
VBLANK_WAIT:
; Wait the VBLANK
; Wait for the value of VBLANK_FLG
; to be updated to 0 by the occurrence of
; the next VBLANK.
; VBLANKを待つ
; 次のVBLANKのタイミングにて
; VBLANK_FLGが0に更新されるのを待つ
ld a, (VBLANK_WAIT_FLG)
or a
jr nz,VBLANK_WAIT
; Goto H_TIMI_HOOK_LOOP
; H_TIMI_HOOK_LOOPにジャンプする
jp H_TIMI_HOOK_LOOP
;================================
; Initialized H.TIMI Interrupt routine
; H.TIMI割り込み時に呼ばれる処理を初期化する
;================================
INIT_H_TIMI_HANDLER:
push af
push bc
push de
push hl
di ; Disable Interrupt.
; Backup H.TIMI original procedure
; もともと存在していたH.TIMI処理を退避する
ld hl, H_TIMI
ld de, H_TIMI_BACKUP
ld bc, 5
ldir
; Override the H.TIMI procedure
; H.TIMI処理処理を書き換える
ld a, $C3
ld hl, H_TIMI_HANDLER
ld (H_TIMI + 0), a
ld (H_TIMI + 1), hl
ei ; Enable Interrupt.
pop hl
pop de
pop bc
pop af
ret
;=================================
; This programs own H.TIMI hook process.
; At the end of this process, it jumps to the
; original H.TIMI process.
; この処理は独自のH.TIMI処理となる
; この処理の終了後に本来のH.TIMI処理を呼び出す
;=================================
H_TIMI_HANDLER:
; Decrement VBLANK_WAIT_FLG variable.
; most every 1/60 second.
; 1/60秒ごとにVBLANK_WAIT_FLGの内容をチェックし
; 0であれば本来のH.TIMI処理を呼び出す
;
ld a, (VBLANK_WAIT_FLG)
or a
;
; Call original H.TIMI hook procedure.
; most every 1/60 second.
; 本来のH.TIMI処理を呼び出す
;
jr z, H_TIMI_HANDLER_GO_BACKUPPROC
; Set zero to VBLANK_WAIT_FLG variable.
; VBLANK_WAIT_FLGの値をゼロにする
dec a
ld (VBLANK_WAIT_FLG), a
H_TIMI_HANDLER_GO_BACKUPPROC:
; Submit the original H.TIMI procedure.
; H_TIMI_BACKUPに戻る
jp H_TIMI_BACKUP
;
; Redraw screen.
; Draw the screen most every second.
;
; This process uses the H.TIMI function to count up the
; variable TIMER_COUNTER every 1/60 second, and
; rewrites the screen when the value of
; TIMER_COUNTER reaches 59.
;
; 1秒ごとに画面を書き換える
; この処理はH.TIMIのつど呼び出される
; この処理ではTIMER_COUNTERの値をインクリメントし
; 値が59になったタイミングで画面を更新する
;
REDRAW_SCREEN:
; Count up the TIMER_COUNTER variable.
; TIMER_COUNTER between 0 to 59.
; TIMER_COUNTER変数をカウントアップする
; TIMER_COUNTERの値は0から59とする
ld a, (TIMER_COUNTER)
cp 59
jp nz, REDRAW_SCREEN_COUNTUP_END
ld a, (DISP_CHAR_TYPE)
cp $20
jp z, REDRAW_SCREEN_ASTERISK
ld a, $20
ld (DISP_CHAR_TYPE), a
jp REDRAW_SCREEN_DISPLAY
REDRAW_SCREEN_ASTERISK:
ld a, $2A
ld (DISP_CHAR_TYPE), a
REDRAW_SCREEN_DISPLAY:
; Fill Screen charcters.
; character is '*' or brank.
; 画面を文字(*もしくはブランク)で埋めつくす
call SETWRT
ld hl, $1800
ld bc, 768
ld a, (DISP_CHAR_TYPE)
call FILVRM
; TIMER_COUNTER initialized.
; 画面更新後はTIMER_COUNTERを初期化する
xor a
ld (TIMER_COUNTER), a
jp REDRAW_SCREEN_END
REDRAW_SCREEN_COUNTUP_END:
; Count up the timer.
; TIMER_COUNTERをインクリメントする
inc a
ld (TIMER_COUNTER), a
REDRAW_SCREEN_END:
; Return to VBLANK_WAIT and wait for next H.TIMI
; VBLANK_WAITに戻り次のH.TIMIを待つ
jp VBLANK_WAIT
コメントで ==== で囲われている箇所が重要(筆者として伝えたいポイント)になってます。
では、また!!ノシ
いいなと思ったら応援しよう!
セーラー服が似合うおじさんです。猫好き、酒好き、ガジェット好き、楽しいことならなんでも好き。そんな「好き」をつらつらと書き留めていきます。