カーソルの形状設定
PC-9801のカーソル
PC-9801のMS-DOS、つまりテキストV-RAM上のカーソルは、グラフィックコントローラーが都度割り込みをかけて点滅表示させています。
J-3100やDOS/VのDOSでは、カーソルはBIOSがソフト的に表示させています。J-3100ではBIOSがタイマー割り込みをかけて点滅表示をさせていますし、DOS/Vでは点滅はせずにV-RAMとXORを取って該当箇所を反転表示させています。したがって、J-3100やDOS/VではレジスタをセットしてBIOS割り込みをかけるだけでカーソルの形状を設定できます。
しかし、PC-9801ではグラフィックコントローラーがカーソルを表示させていますので、グラフィックコントローラーにコマンドを送信しなければなりません。
J-3100やDOS/VのDOSでは、カーソルはBIOSがソフト的に表示させています。J-3100ではBIOSがタイマー割り込みをかけて点滅表示をさせていますし、DOS/Vでは点滅はせずにV-RAMとXORを取って該当箇所を反転表示させています。したがって、J-3100やDOS/VではレジスタをセットしてBIOS割り込みをかけるだけでカーソルの形状を設定できます。
しかし、PC-9801ではグラフィックコントローラーがカーソルを表示させていますので、グラフィックコントローラーにコマンドを送信しなければなりません。
GDCコマンドの発行
グラフィックコントローラー(以下GDC)へコマンドを送信するためには、いくつか段取りが必要です。
GDCコはFIFOバッファにてコマンドをバッファリングしています。FIFOですので、最後のコマンドを最初に実行します。したがって、割り込み処理ルーチンが何かGDCにコマンドを送っている最中にGDCに何かコマンドを発行してしまうと、そちらが先に実行され、割り込み処理が行っていた処理が誤動作してしまうかもしれません。
そこで、GDCのFIFOバッファが空になるまで待ちます。具体的には、I/Oポート60Hのビット2を検査します。
60H GDCステータス(Read)
ビット2が1ならFIFO EMPTY、つまりFIFOバッファが空という事です。
しかし、ここで2つ問題があります。
①割り込み処理の問題
GDCにアクセスしているのは、なにもあなたの実行させているプログラムだけではありません。MS-DOS上ではさまざまな割り込み処理が動いており、途中で割り込み処理がGDCを使うかもしれません。そこで、GDCのEMPTYを検出する前に、割り込み禁止(CLI)しておく必要があります。
GDCコはFIFOバッファにてコマンドをバッファリングしています。FIFOですので、最後のコマンドを最初に実行します。したがって、割り込み処理ルーチンが何かGDCにコマンドを送っている最中にGDCに何かコマンドを発行してしまうと、そちらが先に実行され、割り込み処理が行っていた処理が誤動作してしまうかもしれません。
そこで、GDCのFIFOバッファが空になるまで待ちます。具体的には、I/Oポート60Hのビット2を検査します。
60H GDCステータス(Read)
ビット | 意味 |
---|---|
7 | LIGHT PEN DETECT |
6 | HORIZONTAL BANK |
5 | VERTICAL SYNC |
4 | DMA EXECUTE |
3 | DRAWING |
2 | FIFO EMPTY |
1 | FIFO FULL |
0 | DATA READY |
しかし、ここで2つ問題があります。
①割り込み処理の問題
GDCにアクセスしているのは、なにもあなたの実行させているプログラムだけではありません。MS-DOS上ではさまざまな割り込み処理が動いており、途中で割り込み処理がGDCを使うかもしれません。そこで、GDCのEMPTYを検出する前に、割り込み禁止(CLI)しておく必要があります。
②再チェックの間隔
もし、あなたが部下に仕事を頼みたいとします。しかし、部下はあなたよりさらに上司に頼まれた仕事を割り込みでしていました。そこで、あなたは部下に「今やってる仕事は終わったか?」と聞くでしょう。ところが、あまりに頻繁に「仕事終わったか?」と聞くと、その返事をするのに時間をとられてしまってかえって仕事が終わらなくなってしまいます。
これは私もよく経験した事で、トラブル発生時にせっかちなお客さんからもう1分おきぐらいに電話で「まだかまだか」と催促の電話がかかってしまい、その電話の対応のせいで仕事が全然進まなくなってしまいました。
同様に、60Hをチェックする間隔にある程度時間を空けないと、GDCがあなたへの要求に対して返事をするのに時間を取られてしまい、今やってる仕事が終わらなくなってしまいます。そこで、GDCのFIFOバッファが空でなかった時は、適当な待ち時間を入れてから再度60Hをチェックします。
待ち時間を入れるのに、普通はタイマー割り込みをかけるのですが、PC-9801ではこのタイマー割り込みが複雑で、GDCのFIFOバッファを読み出すためだけのウェイトであれば、PC-9801ではポート5FHに何らかの値を書き込むと0.6μ秒以上のウェイトが保証されているので、とりあえずこれをウェイトとして利用します。
もし、あなたが部下に仕事を頼みたいとします。しかし、部下はあなたよりさらに上司に頼まれた仕事を割り込みでしていました。そこで、あなたは部下に「今やってる仕事は終わったか?」と聞くでしょう。ところが、あまりに頻繁に「仕事終わったか?」と聞くと、その返事をするのに時間をとられてしまってかえって仕事が終わらなくなってしまいます。
これは私もよく経験した事で、トラブル発生時にせっかちなお客さんからもう1分おきぐらいに電話で「まだかまだか」と催促の電話がかかってしまい、その電話の対応のせいで仕事が全然進まなくなってしまいました。
同様に、60Hをチェックする間隔にある程度時間を空けないと、GDCがあなたへの要求に対して返事をするのに時間を取られてしまい、今やってる仕事が終わらなくなってしまいます。そこで、GDCのFIFOバッファが空でなかった時は、適当な待ち時間を入れてから再度60Hをチェックします。
待ち時間を入れるのに、普通はタイマー割り込みをかけるのですが、PC-9801ではこのタイマー割り込みが複雑で、GDCのFIFOバッファを読み出すためだけのウェイトであれば、PC-9801ではポート5FHに何らかの値を書き込むと0.6μ秒以上のウェイトが保証されているので、とりあえずこれをウェイトとして利用します。
;------- 0.6マイクロ秒以上のウェイト WAI = $ PUSH DX PUSH AX MOV DX,005FH MOV AX,0 OUT DX,AX POP AX POP DX RET
以上の事をまとめると、以下のロジックになります。


;----- FIFOバッファチェック CHKFIFO = $ PUSHF CLI IN AL,60H TEST AL,4 JZ RETRY JMP GDCSEND ;---- やり直し RETRY = $ POPF CALL WAI JMP CHKFIFO ;---- GDCコマンド送信 GDCSEND = $ (後述)
画面の行数の取得
GDCのカーソルの形状変更コマンド「4BH」は、カーソルの形状と共にテキスト1行あたりのドット数も設定しなければなりません。つまり「1行あたりのドット数は現状維持」っていうコマンドがないのです。
PC-9801はグラフィックスが640×400ドットでテキストは80×25ですので、1行あたりのドット数は400÷25で16ドットです。ところが、MS-DOSでは画面の行数を20行にする事もできるため、ワークエリアを参照して現在の画面モードが、20行なのか25行なのかを取得しなければなりません。
0000:0053CH
PC-9801はグラフィックスが640×400ドットでテキストは80×25ですので、1行あたりのドット数は400÷25で16ドットです。ところが、MS-DOSでは画面の行数を20行にする事もできるため、ワークエリアを参照して現在の画面モードが、20行なのか25行なのかを取得しなければなりません。
0000:0053CH
ビット | 意味 |
---|---|
0 | 0 画面の行数25 1 画面の行数20 |
カーソル形状の変更コマンド
ここまできて、ようやくGDCにコマンドを送れるようになります。
カーソルの形状変更コマンドは4BHですので、まず62Hに4BHを書きます。その後、60Hにパラメーターを出力します。これは3回に分けて8ビットずつ出力します。
1回目
1行のドット数はテキスト画面が80×25なら16-1で15、80x20なら20-1で19を指定します。なので、80×25でカーソルを表示させる場合は、
128 + (16-1) = 143 = 8FH
を指定します。1行のドット数の指定が大きすぎると下の方の行が画面からはみ出して見えなくなってしまいますし、1行のドット数が少なすぎるとテキストが重なって表示されてしまいます。

△1行のドット数を誤って少なく指定してしまった場合
2回目
3回目
カーソルの表示開始ライン、表示終了ラインを指定します、開始ライン>終了ラインの場合はカーソルが消えます。
ブリンクレートはカーソルの点滅の速さで5ビット(0~31)で指定しますが、色々変更してみましたがいくらやっても変わりませんでした。なので大きければ速くなるのか遅くなるのかわかりませんでした。とりあえずいつも12(01100B)ぐらいを指定しています。
I/Oポート | 意味 |
---|---|
60H | GDCコマンドパラメーター送信(ライト) |
62H | GDCコマンド送信(ライト) |
1回目
ビット | 意味 |
---|---|
7 | 0 カーソルを表示しない 1 カーソルを表示する |
6~5 | 未使用(常に0) |
4~0 | (1行あたりのドット数)-1 |
128 + (16-1) = 143 = 8FH
を指定します。1行のドット数の指定が大きすぎると下の方の行が画面からはみ出して見えなくなってしまいますし、1行のドット数が少なすぎるとテキストが重なって表示されてしまいます。

△1行のドット数を誤って少なく指定してしまった場合
2回目
ビット | 意味 |
---|---|
7~6 | ブリンクレートの下位2ビット |
5 | 0 ブリンクする 1 ブリンクしない |
4~0 | カーソル表示開始ライン(0~16または0~20) |
3回目
ビット | 意味 |
---|---|
7~3 | カーソル表示終了ライン(0~16または0~20) |
2~0 | ブリンクレートの上位3ビット |
カーソルの表示開始ライン、表示終了ラインを指定します、開始ライン>終了ラインの場合はカーソルが消えます。
ブリンクレートはカーソルの点滅の速さで5ビット(0~31)で指定しますが、色々変更してみましたがいくらやっても変わりませんでした。なので大きければ速くなるのか遅くなるのかわかりませんでした。とりあえずいつも12(01100B)ぐらいを指定しています。
;---- GDCコマンド送信 GDCSEND = $ MOV AL,4BH OUT 62H,AL MOV SI,OFFSET CURDATA MOV AL,[SI] OUT 60H,AL MOV AL,[SI+1] OUT 60H,AL MOV AL,[SI+2] OUT 60H,AL (省略) ;----- カーソルの形状データ CURDATA DB 8FH,0FH,7BH
エスケープシーケンスやBIOSを使う場合
このコマンドはカーソルの形状を設定するだけで、現在の形状を読み出す事ができません。したがって、エスケープシーケンスやBIOSで「カーソルを消す」「カーソルを出す」というコマンドを使った場合、カーソルが消える前の状態が復元されるわけではなく、カーソルはデフォルトの状態で復元されます。
エスケープシーケンス
カーソルを消す ESC [>5h
カーソルを出す ESC [>5l
BIOS INT18H
AH=12H カーソルを消す
AH=11H カーソルを出す
なので、エスケープシーケンスやBIOSを使ってカーソルを消したり出したりした後は、自前のルーチンでもう一度カーソルの形状を再設定する必要があります。
エスケープシーケンス
カーソルを消す ESC [>5h
カーソルを出す ESC [>5l
BIOS INT18H
AH=12H カーソルを消す
AH=11H カーソルを出す
なので、エスケープシーケンスやBIOSを使ってカーソルを消したり出したりした後は、自前のルーチンでもう一度カーソルの形状を再設定する必要があります。
終わりに
これと同じ事をJ-3100でやるなら、
;--------カーソルの形状設定 MOV CH,ES:[SI] MOV CL,ES:[SI+1] MOV AH,1 INT 10H
こんな感じになります。ここで、ES:[SI]にはカーソル表示開始行、ES:[SI+1]にはカーソル表示終了行が入ってるとします。J-3100では4行で済むことが、なんでこんなに長くなるのかというと、PC-9801はCPUにできる限り負担をかけないように、さまざまな外部コントローラーがついているためです。
結局、多くの外部コントローラーの存在は製造コストを跳ね上げ、プログラムを複雑化する要因となりました。また、PC-9821MATEシリーズが発売された頃には、CPUの急速な性能の向上により、外部コントローラではなくCPUが直接V-RAMを書き換えたほうがかえって高速になってしまいました。
1990年頃東芝から代理店向けに配布された販促用資料の1つに、「PC-9801はアンタッチャブル、それが私のフィロソフィ」というツッコミどころ満載の文書がありました。しかし、実際に国内で売れたのはPC-9801でした。(海外では圧倒的にT-3100でしたが) 結局、プログラミングのしやすさが必ずしも売り上げにつながるというわけではないようです。
結局、多くの外部コントローラーの存在は製造コストを跳ね上げ、プログラムを複雑化する要因となりました。また、PC-9821MATEシリーズが発売された頃には、CPUの急速な性能の向上により、外部コントローラではなくCPUが直接V-RAMを書き換えたほうがかえって高速になってしまいました。
1990年頃東芝から代理店向けに配布された販促用資料の1つに、「PC-9801はアンタッチャブル、それが私のフィロソフィ」というツッコミどころ満載の文書がありました。しかし、実際に国内で売れたのはPC-9801でした。(海外では圧倒的にT-3100でしたが) 結局、プログラミングのしやすさが必ずしも売り上げにつながるというわけではないようです。
参考文献
『PC‐9801スーパーテクニック』 1992年 小高輝真、清水和文、速水祐 著 アスキー
『J-3100解析ハンドブック』 1989年 土屋勝著 ナツメ社
『DOS/Vテクニカル・リファレンス・マニュアル』 1993年 芦達剛著 ソフトバンク
『PC‐9801スーパーテクニック』 1992年 小高輝真、清水和文、速水祐 著 アスキー
『J-3100解析ハンドブック』 1989年 土屋勝著 ナツメ社
『DOS/Vテクニカル・リファレンス・マニュアル』 1993年 芦達剛著 ソフトバンク

広告