見出し画像

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

コメントで ==== で囲われている箇所が重要(筆者として伝えたいポイント)になってます。

では、また!!ノシ

セーラー服が似合うおじさんです。猫好き、酒好き、ガジェット好き、楽しいことならなんでも好き。そんな「好き」をつらつらと書き留めていきます。