今回は描画ルーチンの高速化について検証したいと思います。
【広告】※ テレワークでのボイスチャットやyoutubeのゲーム実況などに。
ほぼ同一条件で同じデータを描画しただけのサンプルです。データアドレスの .L0 は左詰、.L1 は右詰ですが、データとして大差はありません。実行するとこんな画面表示になります。※画面は抜粋
さて、実行速度の測定です。あまり知られていないと思うのですが、実は PC6001VW4 には実行からブレークポインタで停止するまでの処理時間を表示する機能があります。それが state 命令です。コンソール画面から state on とすると実行速度表示モードになります。
ということで、まずはアセンブルした結果の lst と sym を PC6001VW4 に読み込んでから、u 0x8000 として、正しくプログラムが読めている事を確認します。続いて b コマンドで HL レジスタに値を入れているラインにブレークポインタを貼っていきます。ブレークを貼り終わってから、もう一度 u コマンドを実行すると、ブレークが貼られたアドレスは赤文字になります。
r pc 0x8000 として開始アドレスを設定、state on の状態で g で実行します(本当は g 0x8000 とコマンド打ちたいw)。最初のサンプル描画直後で停止した状態を下記に示します。
実行速度は 2772 と出ました。Instruction とはマシンオペコード別のサイクル数です。それに M1wait とあるのは、命令をフェッチした際に発生するメモリウェイトです。この二つのステート数が加算されたのが実際の実行時間となります。なお、PC6001VW4 のステート表示は、実行時に発生した割り込み処理の実行時間も含まれています。そのため、割り込み処理時間がなるべく短くなるように、割り込み処理にはなるべく何もぶら下げないようにしておきます。それでも処理時間は加算されてしまうのですが、まあ、誤差範囲という事で…。
続いてサンプル2の pop データ取得描画での実行時間です。
実行時間は 1563 です。やっぱり速いですね!Z80 で 2バイトを一気に処理できる pop を駆使するとこんな速度が出たりするのです。では、お待ちかね(?)、サンプル3 プログラム書き換え描画の実行速度です。
実行時間は 1581 です。データの取得にスタックを使い、描画は LD (Adr), HL を使うという反則級のプログラムです…が、思ったほどは速くなっていません。ちらつきや色ズレが気になる時に使用すると良いかもですが、実測するとこんなもんなんですね💦
なお、このプログラム、実は PC-8801 だと劇的に高速化するんです。理由は同じアドレスに R,G,B と3回も描画するハードウェアの仕様に因ります。前半のプログラム書き換えでアドレスが決まったら、後はポート出力で R,G,B と切り替えて描画処理を合計3回通すだけで済むためです。PC-6001 だと L, H のアドレスが 0x2000 も離れているため、アドレス計算は都度し直さないといけないので、処理速度が速くならなかったというワケなんです。L と H をバンク切り替えとかで同じアドレスに持ってこれれば…とも思いましたが、残念ながら動きませんでした…。
ということで、上記プログラムより高速に描画する処理が作れたらご一報ください💦💦💦
上記プログラムを収めたサンプルを提示しておきますー
P6DrawTest.zip
※ アセンブルすると 32KB というどでかいバイナリが出来てしまいます。テストなのでご容赦を…
- 前回までの描画方法
普通に ldi を使って描画している、何の変哲も無いルーチンです。プログラムサイズは34バイトとなかなかに小さいです。このルーチンのメリットとしては、やはりサイズの小ささにあるかと思います。
GRPDraw2x12Sep1:: call VRMAddress ; HL 描画アドレス ex de, hl ; 描画を HL→DE の流れとする push de call .draw ; L 描画 pop de set 5, d ; DE 描画アドレスを H 側に .draw ld iyl, 11 .loop ldi ldi ld a, SCRWidth - 2 add a, e ld e, a jr nc, .chk inc d .chk dec iyl jr nz, .loop ldi ldi ret
- 普通に高速化した描画ルーチン
このルーチンのメリットは、最初のルーチンよりかなり高速化されたですね。デメリットとしては、プログラムサイズは 145バイトと、そこそこ大きくなってしまった事でしょうか。それでも高速化という意味では、この方法は採用したいところです。
GRPDraw2x12Sep2:: call VRMAddress ; HL 描画アドレス ex de, hl ld (WRK.Temp00), sp di ld sp, hl ex de, hl ld bc, SCRWidth - 1
REPT 12 LAST -1 pop de ; DE データを読み出す ld (hl), e inc hl ld (hl), d ; VRAMに書き出す add hl, bc ; 次のアドレスに ENDM ld bc, $2000 - SCRWidth * 11 - 1
add hl, bc ; アドレスを H に移動 ld bc, 40 - 1 REPT 12 LAST -1 pop de ; DE データを読み出す ld (hl), e inc hl ld (hl), d ; VRAMに書き出す add hl, bc ; 次のアドレスに ENDM ld sp, (WRK.Temp00) ei ret
【広告】
Logicool(ロジクール)
2019-12-12
- かなり異常な描画ルーチン
プログラムはさらに長く、総容量は212バイトもあります。しかも、残念ながらこの方法は ROMでは採用できません、なぜならプログラム書き換えが必要だからです。高速化以上にこのルーチンを使用するメリットが二つあります。ひとつは、描画し始めると一気に超高速で書き換えるので、たらつきちらつき色ズレといった異常表示状態が目立たないという事です。もう一つが割り込み禁止時間が短い事です。サウンドの揺らぎが少なくなるはずです。
GRPDraw2x12Sep3:: call VRMAddress ; HL 描画アドレス ; 描画アドスの初期化 ld bc, SCRWidth ld (.put00 + 1), hl add hl, bc ld (.put01 + 1), hl add hl, bc ld (.put02 + 1), hl add hl, bc ld (.put03 + 1), hl add hl, bc ld (.put04 + 1), hl add hl, bc ld (.put05 + 1), hl add hl, bc ld (.put06 + 1), hl add hl, bc ld (.put07 + 1), hl add hl, bc ld (.put08 + 1), hl add hl, bc ld (.put09 + 1), hl add hl, bc ld (.put0A + 1), hl add hl, bc ld (.put0B + 1), hl ld bc, $2000 - SCRWidth * 11 add hl, bc ld (.put10 + 1), hl
ld bc, SCRWidth
add hl, bc ld (.put11 + 1), hl add hl, bc ld (.put12 + 1), hl add hl, bc ld (.put13 + 1), hl add hl, bc ld (.put14 + 1), hl add hl, bc ld (.put15 + 1), hl add hl, bc ld (.put16 + 1), hl add hl, bc ld (.put17 + 1), hl add hl, bc ld (.put18 + 1), hl add hl, bc ld (.put19 + 1), hl add hl, bc ld (.put1A + 1), hl add hl, bc ld (.put1B + 1), hl ; 描画する ex de, hl ld (.stack + 1), sp di ld sp, hl pop hl .put00 ld ($0000), hl pop hl .put01 ld ($0000), hl pop hl .put02 ld ($0000), hl pop hl .put03 ld ($0000), hl pop hl .put04 ld ($0000), hl pop hl .put05 ld ($0000), hl pop hl .put06 ld ($0000), hl pop hl .put07 ld ($0000), hl pop hl .put08 ld ($0000), hl pop hl .put09 ld ($0000), hl pop hl .put0A ld ($0000), hl pop hl .put0B ld ($0000), hl pop hl .put10 ld ($0000), hl pop hl .put11 ld ($0000), hl pop hl .put12 ld ($0000), hl pop hl .put13 ld ($0000), hl pop hl .put14 ld ($0000), hl pop hl .put15 ld ($0000), hl pop hl .put16 ld ($0000), hl pop hl .put17 ld ($0000), hl pop hl .put18 ld ($0000), hl pop hl .put19 ld ($0000), hl pop hl .put1A ld ($0000), hl pop hl .put1B ld ($0000), hl .stack ld sp, $0000 ei ret
- 実行速度測定
org $8000 call InitSystem ld hl, 0 ld de, Bullet.L0 call GRPDraw2x12Sep1 ld hl, $0103 ld de, Bullet.L1 call GRPDraw2x12Sep2 ld hl, $0206 ld de, Bullet.L0 call GRPDraw2x12Sep3 jr $
ほぼ同一条件で同じデータを描画しただけのサンプルです。データアドレスの .L0 は左詰、.L1 は右詰ですが、データとして大差はありません。実行するとこんな画面表示になります。※画面は抜粋
さて、実行速度の測定です。あまり知られていないと思うのですが、実は PC6001VW4 には実行からブレークポインタで停止するまでの処理時間を表示する機能があります。それが state 命令です。コンソール画面から state on とすると実行速度表示モードになります。
ということで、まずはアセンブルした結果の lst と sym を PC6001VW4 に読み込んでから、u 0x8000 として、正しくプログラムが読めている事を確認します。続いて b コマンドで HL レジスタに値を入れているラインにブレークポインタを貼っていきます。ブレークを貼り終わってから、もう一度 u コマンドを実行すると、ブレークが貼られたアドレスは赤文字になります。
r pc 0x8000 として開始アドレスを設定、state on の状態で g で実行します(本当は g 0x8000 とコマンド打ちたいw)。最初のサンプル描画直後で停止した状態を下記に示します。
実行速度は 2772 と出ました。Instruction とはマシンオペコード別のサイクル数です。それに M1wait とあるのは、命令をフェッチした際に発生するメモリウェイトです。この二つのステート数が加算されたのが実際の実行時間となります。なお、PC6001VW4 のステート表示は、実行時に発生した割り込み処理の実行時間も含まれています。そのため、割り込み処理時間がなるべく短くなるように、割り込み処理にはなるべく何もぶら下げないようにしておきます。それでも処理時間は加算されてしまうのですが、まあ、誤差範囲という事で…。
続いてサンプル2の pop データ取得描画での実行時間です。
実行時間は 1563 です。やっぱり速いですね!Z80 で 2バイトを一気に処理できる pop を駆使するとこんな速度が出たりするのです。では、お待ちかね(?)、サンプル3 プログラム書き換え描画の実行速度です。
実行時間は 1581 です。データの取得にスタックを使い、描画は LD (Adr), HL を使うという反則級のプログラムです…が、思ったほどは速くなっていません。ちらつきや色ズレが気になる時に使用すると良いかもですが、実測するとこんなもんなんですね💦
なお、このプログラム、実は PC-8801 だと劇的に高速化するんです。理由は同じアドレスに R,G,B と3回も描画するハードウェアの仕様に因ります。前半のプログラム書き換えでアドレスが決まったら、後はポート出力で R,G,B と切り替えて描画処理を合計3回通すだけで済むためです。PC-6001 だと L, H のアドレスが 0x2000 も離れているため、アドレス計算は都度し直さないといけないので、処理速度が速くならなかったというワケなんです。L と H をバンク切り替えとかで同じアドレスに持ってこれれば…とも思いましたが、残念ながら動きませんでした…。
ということで、上記プログラムより高速に描画する処理が作れたらご一報ください💦💦💦
上記プログラムを収めたサンプルを提示しておきますー
P6DrawTest.zip
※ アセンブルすると 32KB というどでかいバイナリが出来てしまいます。テストなのでご容赦を…
【広告】
Logicool(ロジクール)
2020-08-27
※ どうせなら良いモノを、と言う事ならこちらをオススメ。没頭できます!
※ どうせなら良いモノを、と言う事ならこちらをオススメ。没頭できます!
コメント
コメント一覧 (2)
キャラ表示ルーチン、ちょっとだけ速いヤツです。
出典はここです。
http://000.la.coocan.jp/p6/hover.html
GRPDraw2x12Sep2::
call VRMAddress ; HL 描画アドレス
ex de, hl
ld (WRK.Temp00), sp
di
ld sp, hl
ex de, hl
ld bc, SCRWidth - $2000
REPT 12 LAST -1
pop de ; プレーン0データを読み出す
ld (hl), e
inc hl
ld (hl), d ; VRAMに書き出す
set 5,h
pop de ; プレーン1データを読み出す
ld (hl), e
dec hl
ld (hl), d ; VRAMに書き出す
add hl, bc ; 次のアドレスに
ENDM
ld sp, (WRK.Temp00)
ei
ret
差は、set の8+2サイクルと、add hl,bc の11+1サイクルです。( +1,+2 はm1でのウエイト分)
プログラムを全部、拡張カートリッジ上で動かすようにして、m1サイクルを0に設定すると、更に速く出来ます。
内藤時浩
がしました