HELP Contents
このPML仮想コンピューターにはマウス、キーボード、仮想モニタ、それとタイマーがつながっていますが、この章ではこれらの機器を操作するためのI/Oポートの仕様を説明します。
ちなみにポート割り振りや入出力する値の仕様は、そのコンピューターや外部機器の設計者が好きに決めていい項目です。このPMLコンピューターは筆者がでっち上げた物なので、この入出力ポートの仕様もこの世に実際に存在するものではありません。だからこれを覚えたところで、何の役にも立ちません。I/Oポートを使って外部入出力機器を操作する例とでも考えておいて下さい。
実際のコンピューターでは外部入出力機器はI/Oポート以外でも操作されます。詳しくは7章の[補足:もう少し突っ込んだハードウェアの話]を見てみて下さい。
仮想モニタとはPMLエミュレータが起動したときに現れる真っ白なウインドウで、PML仮想コンピュータで何か画面表示を行いたい場合は、この画面に出力することになります。
仮想モニタは皆さんが通常使っているモニタと違って文字しか出せないという仕様になっています。
モニタ画面は以下のように48行×64桁のマス目に分割されていて、各マス(これを以後セルと呼びます)に以下のような通し番号が付いています。このセルに1つの文字を表示することができるので、このモニタは1行64文字で48行が表示できることになります。
行\桁 | 0 | 1 | 2 | 3 | 4 | … | 59 | 60 | 61 | 62 | 63 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 | … | 59 | 60 | 61 | 62 | 63 |
1 | 64 | 65 | 66 | 67 | 68 | … | 123 | 124 | 125 | 126 | 127 |
2 | 128 | 129 | 130 | 131 | 132 | … | 187 | 188 | 189 | 190 | 191 |
3 | 192 | 193 | 194 | 195 | 196 | … | 251 | 252 | 253 | 254 | 255 |
4 | 256 | 257 | 258 | 259 | 260 | … | 315 | 316 | 317 | 318 | 319 |
5 | 320 | 321 | 322 | 323 | 324 | … | 379 | 380 | 381 | 382 | 383 |
… | … | … | … | … | … | … | … | … | … | … | … |
42 | 2688 | 2689 | 2690 | 2691 | 2692 | … | 2747 | 2748 | 2749 | 2750 | 2751 |
43 | 2752 | 2753 | 2754 | 2755 | 2756 | … | 2811 | 2812 | 2813 | 2814 | 2815 |
44 | 2816 | 2817 | 2818 | 2819 | 2820 | … | 2875 | 2876 | 2877 | 2878 | 2879 |
45 | 2880 | 2881 | 2882 | 2883 | 2884 | … | 2939 | 2940 | 2941 | 2942 | 2943 |
46 | 2944 | 2945 | 2946 | 2947 | 2948 | … | 3003 | 3004 | 3005 | 3006 | 3007 |
47 | 3008 | 3009 | 3010 | 3011 | 3012 | … | 3067 | 3068 | 3069 | 3070 | 3071 |
―――ここからは少し余談になりますが、こういうモニターをキャラクターディスプレイといって、コンピューターの草創期にはごく普通の存在でした。でもそういう時代でもモニターに文字を出すにはこのモニタの仕様のようにI/Oポートに出力するのではなく、VRAMという仕組みが使われました。
これはメインメモリの一部を直接モニタが読み出せるようにしておいて、コンピュータの方はその領域に表示したい情報を書いておいて、一定時間ごとにモニタはCPUを介さずにそこを読み取って画面に表示するという仕組みです。
その理由はいろいろありますが、まず最大の理由がI/Oポートへのデータ入出力がすごく遅いということが挙げられます―――実はこのPML仮想コンピュータのI/Oポートは少々インチキで、INもしくはOUT命令を発したら即座に結果が戻ってきます。
ところが実際の機器の場合そういうことはあり得ません。なぜなら本物のCPUの場合、メモリアクセスでさえもすごく遅いのでCPU内にレジスタという機構を備えているということを本書内でもちょっと説明しました。ところが外部入出力機器の遅さはそれどころではないのです。外部機器は一般にコンピューターの外側にケーブルでつながっていて、機器が反応する速度もまったくまちまちです。
だからIN命令を使う際にはほぼ確実に「データを寄こせ!」と指示してから実際にデータが来るまで、CPU的には永劫とでもいうべき時間を待っていなければなりません。またOUT命令を出してからその機器が実際にその命令を反映するのも同様です。
すなわちこの偽モニタのようにI/Oポートのみで画面描画制御するととんでもなく非効率なことになってしまうのです。そこで考え出されたのがVRAMという仕組みだったわけです。
ではなんでPML仮想コンピュータでVRAMを使ってないかというと―――(以下省略されました)
このモニタを操作するためには以下のポートが使われます。
PORT | IN | OUT | 備考 |
---|---|---|---|
10h | なし | モニタのクリア | 値はShiftJisコード |
11h | セルの値を取得 | セルの値を設定して描画 | 値はShiftJisコード |
12h | カーソル表示状態の取得 | カーソル表示状態の設定 | 0でOff,0以外でOn |
13h | 描画モード取得 | 描画モード設定 | 0:カーソルと描画位置は独立 1:描画位置にカーソルを移動 2:カーソル位置に描画位置を移動 |
14h | なし | ハードウェアスクロールを行う | 値を±47で指定する |
15h | フレームカウント | フレームカウント初期化 | 現在のフレームカウントを取得・設定する |
20h | 指定されているセル番号の取得 | セル番号の指定 | 値は0〜3,071 |
21h | 指定されているセル行の取得 | セル行の指定 | 値は0〜47 |
22h | 指定されているセル桁の取得 | セル桁の指定 | 値は0〜63 |
23h | 文字色(赤)の値取得 | 文字色(赤)の設定 | 値は0〜255 |
24h | 文字色(緑)の値取得 | 文字色(緑)の設定 | 値は0〜255 |
25h | 文字色(青)の値取得 | 文字色(青)の設定 | 値は0〜255 |
26h | セル背景色(赤)の値取得 | セル背景色(赤)の設定 | 値は0〜255 |
27h | セル背景色(緑)の値取得 | セル背景色(緑)の設定 | 値は0〜255 |
28h | セル背景色(青)の値取得 | セル背景色(青)の設定 | 値は0〜255 |
29h | 文字方向の取得 | 文字描画方向の設定 | 値は0,1,2,3でそれぞれ上向き、右向き、下向き、左向き。それ以上の値の場合、4で割った余りが文字方向になる。 |
30h | カーソル位置のセル番号の取得 | カーソル位置のセル番号の指定 | 値は0〜3,071 |
31h | カーソル行の取得 | カーソル行の指定 | 値は0〜47 |
32h | カーソル桁の取得 | カーソル桁の指定 | 値は0〜63 |
ポート10hに出力を行うと指定された文字、文字色、背景色、文字の向きで画面を埋め尽くします。文字番号を0にしておけばこれは画面消去と同じです。
OUT #10h #41h ;'A'という文字で画面を埋め尽くす
モニタに文字を表示するためには以下のように出力します。
<セル番号で場所を指定する場合>
OUT #20h セル番号 OUT #11h 表示する文字コード
<画面の行・桁で場所を指定する場合>
OUT #21h 表示行 OUT #22h 表示桁 OUT #11h 表示する文字コード
以下は66番のセルに"A"という文字を表示させる例です。
<セル番号で場所を指定する場合>
OUT #20h #66 ;66番のセル(画面2行3桁目)を指定 OUT #11h #41h ;'A'という文字(文字コード41h)を書き込む OUT #11h #42h ;'B'という文字(文字コード41h)を書き込む OUT #11h #43h ;'C'という文字(文字コード41h)を書き込む
<画面の行・桁で場所を指定する場合>
OUT #21h #1 ;画面2行目を指定 OUT #22h #2 ;画面3桁目を指定 OUT #11h #41h ;'A'という文字(文字コード41h)を書き込む OUT #11h #42h ;'B'という文字(文字コード41h)を書き込む OUT #11h #43h ;'C'という文字(文字コード41h)を書き込む
#11hポートから入力を行うと、現在の描画位置のセルに現在どんな文字が書かれているか知ることができます。
<66番のセルにどんな文字が書かれているか調べる例>
OUT #10h #66 ;66番のセル(画面2行3桁目)を指定 IN X #11h ;66番のセルに書かれている文字コードがX番地に保管される
文字の色やセルの背景色を変えたい場合は、ポート23h〜28hを使います。
例えば文字の色を赤、すなわちRGBが(255,0,0)にしたければ、
OUT #23h #255 ;文字の赤の輝度を指定 OUT #24h #0 ;文字の緑の輝度を指定 OUT #25h #0 ;文字の青の輝度を指定 OUT #11h #41h ;'A'という文字(文字コード41h)を書き込む
といったように指定します。上の例だとAという文字が赤色で表示されます。
この場合も23h〜25hポートに値を設定しただけでは色は変わらず、11hに値を出力したとき初めて色が変わります。
文字の背景色を変更するには26h〜28hのポートを使用します。
OUT #26h #255 ;背景色の赤の輝度を指定 OUT #26h #0 ;背景色の緑の輝度を指定 OUT #28h #0 ;背景色の青の輝度を指定 OUT #11h #41h ;'A'という文字(文字コード41h)を書き込む
文字の表示方向を変えるにはポート29hを使います。
OUT #29h #2 ;文字の向きを下向きにする OUT #11h #41h ;'A'という文字(文字コード41h)を書き込む
疑似モニタにはテキストカーソル(キャレット)を表示する機能があります。これはあるセルが点滅するようにしたもので文字入力の際のガイドとして使われます。
カーソルを表示したり、今表示されているかどうかを取得するにはポート12hを使用します。
OUT #12h #1 ;カーソルを表示する
カーソルの場所を設定するにはポート30h〜32hを使用します。
<セル番号で指定する場合>
OUT #30h #66 ;66番のセル(画面2行3桁目)を指定
<画面の行・桁で場所を指定する場合>
OUT #31h #2 ;カーソル行を2行目に設定 OUT #32h #3 ;カーソル桁を3桁目を設定
カーソルは一般的に文字の入力位置を指定するために表示されますが、プログラムの都合によっては文字の表示位置とカーソル位置が連動してもらったら困る場合もあります。
そこでカーソルと文字描画位置については以下の描画モードが設定できます。
OUT #13h 描画モード
描画モードには以下の意味があります。
描画モード | その意味 |
---|---|
0 | カーソル位置と描画位置は独立です。 |
1 | 描画位置に自動的にカーソルが移動します。 |
2 | カーソル位置に自動的に描画位置が移動します。 |
ポート14hを利用することで画面をスクロールさせることができます。
OUT #14h #1 ;画面を上に1行スクロールさせる
ポート15hを読むと、現在のモニタのフレームカウントが取得できます。
疑似モニタはPCのグラフィック能力にも依存しますが、1秒間に約20回画面を書き換えます。アニメーションなどを行いたい場合、この描画フレームと処理を同期したいことがありますが、そういった場合にこのポートを使います。
OUT #15h 0 ;フレームカウントを初期化する IN X #15h ;X番地にフレームカウントを読み込む
INで読み込むとフレームカウントを初期化してから現在何フレームが描画されたかの値が返ってきます。そこで例えば以下のようなコードを書くことで、フレームに同期した処理を行うことができます。
OUT #15h #0 ;フレームカウントを初期化する >L: IN X #15h ;フレームカウントを読んで JPT >L X ;0だったらループする ...続きの処理
キーボードの状態を取得するには以下のポートを使います。
PORT | IN | OUT | 返り値 |
---|---|---|---|
100h | キーコード00h〜0Fhの状態取得 | なし | 下位ビットより00h〜0Fhのキー状態 |
101h | キーコード10h〜1Fhの状態取得 | なし | 下位ビットより10h〜1Fhのキー状態 |
102h | キーコード20h〜2Fhの状態取得 | なし | 下位ビットより20h〜2Fhのキー状態 |
103h | キーコード30h〜3Fhの状態取得 | なし | 下位ビットより30h〜3Fhのキー状態 |
104h | キーコード40h〜4Fhの状態取得 | なし | 下位ビットより40h〜4Fhのキー状態 |
105h | キーコード50h〜5Fhの状態取得 | なし | 下位ビットより50h〜5Fhのキー状態 |
106h | キーコード60h〜6Fhの状態取得 | なし | 下位ビットより60h〜6Fhのキー状態 |
107h | キーコード70h〜7Fhの状態取得 | なし | 下位ビットより70h〜7Fhのキー状態 |
108h | キーコード80h〜8Fhの状態取得 | なし | 下位ビットより80h〜8Fhのキー状態 |
109h | キーコード90h〜9Fhの状態取得 | なし | 下位ビットより90h〜9Fhのキー状態 |
10Ah | キーコードA0h〜AFhの状態取得 | なし | 下位ビットよりA0h〜AFhのキー状態 |
10Bh | キーコードB0h〜BFhの状態取得 | なし | 下位ビットよりB0h〜BFhのキー状態 |
10Ch | キーコードC0h〜CFhの状態取得 | なし | 下位ビットよりC0h〜CFhのキー状態 |
10Dh | キーコードD0h〜DFhの状態取得 | なし | 下位ビットよりD0h〜DFhのキー状態 |
10Eh | キーコードE0h〜EFhの状態取得 | なし | 下位ビットよりE0h〜EFhのキー状態 |
10Fh | キーコードF0h〜FFhの状態取得 | なし | 下位ビットよりF0h〜FFhのキー状態 |
110h | 設定されたキーコードのキー状態 | キーコードの設定 | 読込時は0か1,書込時は0〜255 |
キーボードの情報を得るためのポートはやたらたくさんありますが、まず通常の利用では110hポートを使います。このポートは調べたいキーのキーコードを出力してから読み込むと、そのキーが今押されていれば1、押されていなければ0が返ります。
OUT #110h #20h ;スペースキーのキーコードを送る IN X #110h ;X番地にキーの状態が返る
このポートを利用した場合、二つのキーが同時押しされているかどうかは分かりません。そこで複数のキーが同時押しされているかどうかを調べたい場合は以下のように面倒なことにはなりますが、10xhのポートを使用します。
IN X #101h ;X番地にキーコード10h〜1Fhまでのキー情報がセットされる。
こうやって読んだXには以下のようにキーコードに対応するビットに値が設定されます。
ビット | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
キーコード | 1F | 1E | 1D | 1C | 1B | 1A | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 |
例えば得られたデータが3hだったとします。するとこの値は二進数で表すと 0000000000000011 となりますが、これは第0ビットと第1ビットが1になっていて、それに対応するキー10hはシフトキー、11hはコントロールキーなので、要するにコントロールキーとシフトキーが同時に押されていることを示します。
キーボードのキーをコンピュータが区別できるように割り振られた値をキーコードといいます。PML仮想コンピュータでは以下のキーコードが使えます。
コード | キー名称 | コード | キー名称 | コード | キー名称 | コード | キー名称 |
---|---|---|---|---|---|---|---|
08h | Backspace | 37h | 7 | 57h | W | 76h | F7 |
09h | Tab | 38h | 8 | 58h | X | 77h | F8 |
0Dh | Enter | 39h | 9 | 59h | Y | 78h | F9 |
10h | Shift | 41h | A | 5Ah | Z | 7Ah | F11 |
11h | Ctrl | 42h | B | 60h | Num 0 | 7Bh | F12 |
1Bh | Esc | 43h | C | 61h | Num 1 | BAh | : |
20h | Space | 44h | D | 62h | Num 2 | BBh | ; |
21h | Pageup | 45h | E | 63h | Num 3 | BCh | , |
22h | Pagedown | 46h | F | 64h | Num 4 | BDh | - |
23h | End | 47h | G | 65h | Num 5 | BEh | . |
24h | Home | 48h | H | 66h | Num 6 | BFh | / |
25h | Left | 49h | I | 67h | Num 7 | C0h | @ |
26h | Up | 4Ah | J | 68h | Num 8 | DBh | [ |
27h | Right | 4Bh | K | 69h | Num 9 | DCh | \ |
28h | Down | 4Ch | L | 6Ah | Num * | DDh | ] |
2Ch | Printscreen | 4Dh | M | 6Bh | Num + | DEh | ^ |
2Dh | Insert | 4Eh | N | 6Dh | Num - | ||
2Eh | Delete | 4Fh | O | 6Eh | Num . | ||
30h | 0 | 50h | P | 6Fh | Num / | ||
31h | 1 | 51h | Q | 70h | F1 | ||
32h | 2 | 52h | R | 71h | F2 | ||
33h | 3 | 53h | S | 72h | F3 | ||
34h | 4 | 54h | T | 73h | F4 | ||
35h | 5 | 55h | U | 74h | F5 | ||
36h | 6 | 56h | V | 75h | F6 |
マウスの情報を取得するには以下のポートを使います。
PORT | IN | OUT | 備考 |
---|---|---|---|
200h | マウスボタン状態取得 | なし | 値は0〜3 |
201h | マウス位置取得 | なし | 値は0〜3,071 |
202h | マウス行位置取得 | なし | 値は0〜47 |
203h | マウス桁位置取得 | なし | 値は0〜63 |
以下の例のようにポート200hを読み込むことで、現在のマウスボタンの状態を取得できます。
IN X #200h ;X番地に現在のマウスの状態を読み込む
読まれた状態の値は以下の意味を持っています。
値 | 2進法の値 | 意味 |
---|---|---|
0 | 000 | 押されていない |
1 | 001 | 左ボタンが押されている |
2 | 010 | 右ボタンが押されている |
3 | 011 | 左ボタンと右ボタンが押されている |
4 | 100 | 中央ボタンが押されている |
5 | 101 | 中央ボタンと左ボタンが押されている |
6 | 110 | 中央ボタンと右ボタンが押されている |
7 | 111 | すべてのボタンが押されている |
以下のように201hポートを読むことで、現在マウスカーソルがあるモニタのセル番号を取得できます。
IN C #201 ;C番地にマウスカーソルのあるセル番号を得る
また以下のように202hポートと203hポートを読むことでマウス位置の行、桁を取得できます。
IN Y #202 ;Y番地にマウスカーソルのある行番号を得る IN X #203 ;X番地にマウスカーソルのある桁番号を得る
ポート300hにはタイマーがつながっていて以下のように使用します。
PORT | IN | OUT | 備考 |
---|---|---|---|
300h | タイマー取得 | タイマー設定 | 値は0〜65535 |
これはストップウォッチのようなもので、使うにはまずポート300hに1以上の値を設定します。
続いてポート300hを読むと設定してから経過した時間が取得できます。
時間の単位は“ミリ秒*設定時にセットした値”となります。
例えば以下のように10と設定すると10ミリ秒単位の値が戻ってきます。
OUT #300h #10 ;10ms単位のタイマー設定 IN X #300h ;タイマーの値を取得する