6.PC-6001mk2/PC-6601 の特長
今回、動画再生を作成する時に使用した、PC-6001mk2/PC-6601 の特長です。
○ページ切り替え
P6系は、画面のページとして、複数のページを持つことが出来ます。そのため、Page2 を表示させたままで、その裏で Page3 に描画して、描画が完了したら Page3 を表示する、という事ができます。
この手法を使うと、描画している最中のちらつきが抑えられます。
○メモリ管理
PC-6001mk2/PC-6601 では、4000H 単位でどのメモリから読み出すか、どのメモリに書き込むかを設定できます。読み出しと書き込みを別にする事も出来ます。
今回はVRAM にデータをひたすら書き込む処理がありますが、この際、外部メモリ(外付けメモリ)から読み出して、内部メモリ(VRAM)に書き込む、という設定にしています。
○バスリクエストオフ
バスリクエストをオフにすると、画面の描画が止まります。正確に言うと、直前に入力したデータを表示し続けます。
これをうまく使うと、画面の一部を使わない場合、その部分をバスリクエストオフにする事によって、その間にCPUを働かせる事ができます。
7.実装
・PCM 音声出力のためには、一定のタイミングでPSG にデータを出力する必要がある。
・画面描画は、VRAM に高速で書き込むしかない。
・両方とも、CPU からしかコントロールできない。
このため、外部から出来ることは、CPU が走るプログラムを操作するしかありません。
で、今回行った実装方法です。
1)描画する範囲を160×150 にする。
PC-6001mk2/PC-6601 は、16色使えるのは 160×200 のモードです。この場合、画面の縦横比は4:3です。今回扱う動画は、ほとんどが16:9でしたので、 描画範囲を160×150 にしました。
160×150 にする事によって、描画するデータが減る、画面の一部をバスリクエストオフに出来る、という2つのメリットがあります。
2)CPU から出力される信号(M1、RD、WR、IORQ、MREQ など)を監視する。
信号の変化が止まっている時は、バスリクエストが出ていてCPU が止まっている事を示しています。そのため、画面描画をしているタイミングを検出する事ができます。
3)外部メモリの空間をアドレスフリーで使う。
これは、VRAM に出来るだけ高速にデータを格納するために行っています。
外部メモリ空間にメモリを配置しません。外部メモリを読み出した場合、アドレスを無視して、単に算出したデータ(プログラム)を返すようにします。さらに、メモリ管理で、書き込みを内部メモリ(VRAM)、読み出しを外部メモリに設定します。
上記の設定にした場合、CALL 文を実行すると、PC の値が内部メモリ(VRAM)に書き込まれます。1回のCALL 文で2バイト書き込めて、1バイト当たり 8.5 クロックとなって、高速で書き込む事ができます(多分、最速です)。
4)2)で検出した画面描画のタイミングを考慮しながら、プログラムをスケジューリングする。
これにより、PSG に一定の間隔でデータを出力する事ができます。さらに、1フレームの描画速度も管理する事ができるので、一石二鳥です。
以下が実際にスケジューリングした結果、CPU に出力されるプログラムです。アドレスは無視しているので、このタイミングの通りにCPU に出力されます。
出力されるプログラム(データ)は、以下の通りです。
・画面描画:CD XX XX (CALL XXXX )
・PCM出力:3E XX D3 A1 (LD A,XX / OUT (0A1H),A )
・バスリクエストON/OFF:3E 02(03) D3 93 (LD A,02H / OUT (93H),A )
・ページ切り替え:3E F4(F6) D3 B1 (LD A,0F4H / OUT (0B1H),A )
ページ切り替えは、1フレームの描画が終わった時のみです。
また、PCM出力は、15KHz サンプリングの1ch 使用時のものです。8KHz サンプリングの 2ch 使用の場合は、1ライン毎に(1)〜(4)を順番に繰り返して出力します。
(1) 11 XX XX (LD DE,XXXX )
(2) 7C ED 51 D3 A0 ED 59 (LD A,H / OUT (C),D / OUT (0A0H),A / OUT (C),E )
(3) 11 XX XX (LD DE,XXXX )
(4) 7D ED 59 D3 A0 ED 51 (LD A,L / OUT (C),E / OUT (0A0H),A / OUT (C),D )
これを実行する前に、レジスタの初期設定をしています。
LD C,0A1H
LD HL,0908H
本当は、1ラインで2ch 分の出力が出来ればいいんですが、14MHzで176clkしかない、1ラインの隙間に出力しているので、2ラインに分けています。
具体的なデータを出して説明しましたが、実際にやっている事は、7)実装の項目に書いている、スケジューリングをして、そのタイミングでプログラムを出力しているだけなんですね。そのため、システムとしては割りと単純になっています。
どっちかというと、SDカードからデータを読み出す事の方が、よっぽど複雑な事をしています。


同じアドレスに対しても読み書きを別にできますか?
> PC-6001mk2/PC-6601 は、16色使えるのは 160×200 のモードです。この場合、画面の縦横比は4:3です。今回扱う動画は、ほとんどが16:9でしたので、 描画範囲を160×150 にしました。
これって専用ディスプレイに表示した場合では?TV表示でも200ラインで4:3になりますか?
あ、左右も空くから4:3になるんですね
> 以下が実際にスケジューリングした結果、CPU に出力されるプログラムです。アドレスは無視しているので、このタイミングの通りにCPU に出力されます。
具体的に、各工程で何クロックかかりますか?CALLで2バイト毎よりLDIRでバースト転送が
速いかな?と思ったので。
PCM(PSG)とバスリクエストの間が空いていますが、これはCRTCが決めるタイミングとかで
ズラせませんか?
>>
>>同じアドレスに対しても読み書きを別にできますか?
可能です。
>>具体的に、各工程で何クロックかかりますか?CALLで2バイト毎よりLDIRでバースト転送が
速いかな?と思ったので。
画面描画の話ですよね?
CALL XXXX 、CALL XXXX 、・・・
なので、2バイト出力当たり17クロックです。
他のスタックポインタの初期値設定や、ページ切り替えなどは、1フレームに1回なので無視です。
>>PCM(PSG)とバスリクエストの間が空いていますが、これはCRTCが決めるタイミングとかで
ズラせませんか?
どれを指しているかよくわかりませんが...
CRTC が出力するタイミングは基本的には変更できません。
変更可能なのは、モード変更時と、バスリクエストON/OFF変更時のみです。
ぃぇ全部です。すべて命令実行時間、つまり
・PCM(PSG):LD A,XX (13clk) OUT (0A1H),A (11clk) = 24clk
・バスリクエストON/OFF:LD A,02H (13clk) OUT (93H),A (11clk) = 24clk
・ページ切り替え:LD A,0F4H (13clk) OUT (0B1H),A (11clk) = 24clk
・画面描画:CALL XXXX (17clk/2bytes)
となるワケですね。
> CALL XXXX 、CALL XXXX 、・・・
確かに、SPをVRAMにしてCALLすればその前のXXXX+3が(SP)に書き込まれますが、
SPは-2されるので後ろから降順に書き込むワケですか?
メモリリードとライトだけならLDIRのが速そうな気もしますが、その前の
LD HL,XXXX (20clk)
LD DE,XXXX (20clk)
LD BC,XXXX (20clk) 計60clk
LDIR(21/16clk/byte)
を考えると...HL(コピー元)はテキトーでも良いんでしたね。なら40+21clk/byteですか。
やっぱりダメですね。
> どれを指しているかよくわかりませんが...
PSGとバスリクエストとではなくPSGとON/OFFとの間でした。その間に描画があります
が、そこを詰めてバースト転送を、と思いましたが、そもそもLDIRのがCALLより時間が
かかるので意味ないですね
VRAMを外部にできるP6(とSR?)が羨ましくもなりますね
あまりいい加減な命令を与えると復帰した際の動作がどうなるか解りませんが、平気
ですか?
それとも、リセットからリセットまでの動作にするのでその前後の動作なんてドーでもイー
のでしょうか?
まぁ終わる際にまともな命令で元に戻してから復帰すればいいのですが。
組み込みやっているくせに何考えてんだろ?>自分
>>
>>ぃぇ全部です。すべて命令実行時間、つまり
>>・PCM(PSG):LD A,XX (13clk) OUT (0A1H),A (11clk) = 24clk
>>・バスリクエストON/OFF:LD A,02H (13clk) OUT (93H),A (11clk) = 24clk
>>・ページ切り替え:LD A,0F4H (13clk) OUT (0B1H),A (11clk) = 24clk
>>・画面描画:CALL XXXX (17clk/2bytes)
>>となるワケですね。
説明が分かりにくくなっている所ですね。ええと...
画面1フレーム(160×150ドット16色)を描画するためには、12000バイトをVRAMに書き込みます。
現状では、5フレーム分の時間(1/12秒)で、12000バイトをVRAMに書き込んでいます。
5フレーム分の時間(1/12秒)で掛かる総クロック数は以下の通りです。
・バスリクエストON/OFF:(7+11)clk × 2 × 5= 180clk
・ページ切り替え:(7+11)clk = 18clk
・画面描画:17clk × 6000 = 102000clk
この間(5フレーム間)、PCM出力は1ラインで常に出力していますので、
・PCM(PSG):(7+11)clk × 262 × 5 = 23580clk
>>> CALL XXXX 、CALL XXXX 、・・・
>>
>>確かに、SPをVRAMにしてCALLすればその前のXXXX+3が(SP)に書き込まれますが、
>>SPは-2されるので後ろから降順に書き込むワケですか?
そうです。
>>あまりいい加減な命令を与えると復帰した際の動作がどうなるか解りませんが、平気
ですか?
>>それとも、リセットからリセットまでの動作にするのでその前後の動作なんてドーでもイー
のでしょうか?
>>まぁ終わる際にまともな命令で元に戻してから復帰すればいいのですが。
>>
・描画/PCM出力のルーチンに飛ぶ前に、スタックポインタを待避させている。
・描画/PCM出力のルーチンでは、割り込みは禁止している
・各レジスタは破壊されてもいい。
・内部メモリは、VRAM以外には書き込まれない。
・描画/PCM出力のルーチンから戻る時には、固定のアドレスに戻る。
をしています。