8080エミュレータを作ってCP/M-80を動かす(その4)

CP/M

前回までの作業でCP/M-80とCP/M-80アプリを動かせるようになったのですが、キー入力周りで若干問題があります。また、CP/M-80用のスクリーンエディタとして有名な「WordMaster」は、そのままの状態ではうまく動きません。今回は、キー入力に関する問題の解消と、WordMasterの改造に取り組みます。

キー入力の問題を解消

前回までに作成したCP/M-80起動用プログラム「startcpm.c」には問題があります。例えば、CP/M-80に付属する「ED」というラインエディタでは、テキスト入力用のモード(インサートモード)からコマンドモードに移動するのに、Ctrl+zというキー入力を用います。しかし現状のstartcpm.cでは、Ctrl+zを入力すると(通常のLinuxプログラムと同様に)SIGTSTPシグナルが送られてプロセスが停止してしまいます。また、WordMasterでは、カーソルの上下左右の移動にCtrl+e、Ctrl+x、Ctrl+s、Ctrl+dというキー入力を用いますが、現状のstartcpm.cでは、Ctrl+sを入力すると端末への出力が停止してしまいます。

Backspaceキーに関する問題もあります。GNOME TerminalなどのLinuxの端末エミュレータでは、デフォルトでBackspaceキーに「ASCII DEL」(コード「0x7F」)が割り当てられています。しかし、CP/M-80は、同キーに「Ctrl+h」(コード「0x08」)が割り当てられることを想定しています。そのため、期待通りの動作になりません。

これらの問題を解消するには、startcpm.cのbios()関数にある、文字入力用のBIOSコールの処理部分を次のように書き換えます。

    case 0xFFE0:
      tcgetattr(0,&save_settings);
      settings = save_settings;
      settings.c_lflag &= ~(ECHO|ICANON|ISIG);
      settings.c_cc[VTIME] = 0;
      settings.c_cc[VMIN] = 1;
      settings.c_cc[VSTOP] = 0;
      settings.c_cc[VSTART] = 0;
      settings.c_cc[VSUSP] = 0;
      tcsetattr(0, TCSANOW, &settings);
      c = getchar();
      tcsetattr(0, TCSANOW, &save_settings);
      if (c == 0x0A) {
        c = 0x0D;
      }
      if (c == 0x10) {
        exit(0);
      }
      if (c == 0x7F) {
        c = 0x08;
      }
      regA = (c & 0x7F);
      break;

この書き換えでは、端末に設定するフラグから「ISIG」を取り除いています。ISIGは、「INTR」「QUIT」「SUSP」「DSUSP」を示す文字入力があった際に、対応するシグナルを発生させるためのフラグです。また、端末の出力を停止する「VSTOP」と、再開する「VSTART」、SIGTSTPシグナルを送信する「VSUSP」の二つの処理に対応付けた文字をクリアするコードも追加しています。これにより、Ctrl+zとCtrl+q、Ctrl+sの入力をCP/M(またはCP/Mアプリ)側で処理できるようになります。

さらに、WordMasterでは、Ctrl+oも編集用のキー入力として用います。そのため、プログラム終了用のキー入力を、Ctrl+o(コード「0x0F」)からCtrl+p(コード「0x10」)に変更しています。CP/M-80 2.2においてCtrl+pは、コンソール出力をプリンタにもエコーするかどうかを切り替えるのに用いられます。しかし、今回作成したBIOSはプリンタ出力に対応していませんので、終了用のキーとして使っても問題ないでしょう。

Backspaceキーの問題については、単純に「0x7F」の入力があった場合にそれを「0x08」に置き換えるコードで対処しています。

変更後、EDを使ってテキストを編集できることを確認してください。なお、「CBIOS.ASM」の入手に用いたアーカイブファイル「cpm2-plm.zip」に含まれる「ED.COM」は高速化の改造を施されたもので、そのままでは正常に動作しません。「ED1.COM」の方がオリジナル版なので、それをリネームして使いましょう。「CPM.SYS」の入手に用いたアーカイブファイル「cpm22-b.zip」に含まれるED.COMはオリジナル版なので、そのまま使えます。

WordMasterを改造する

キー入力の問題は解決できましたが、WordMasterはまだ利用できません。WordMasterが利用する端末制御シーケンスが、Linuxの端末エミュレータなどで使われているANSI/VT100互換の端末制御シーケンスと異なるからです。

問題を解決する方法の一つが、WordMasterにパッチを当ててANSI/VT100互換の端末制御シーケンスに対応させることです。パッチの当て方はさまざまな場所で解説されていますが、ここでは、「CP/M Word-Master patch for vt100 up to 255 columns.」で紹介されている方法でパッチを当てます。

まず、WordMasterを入手します。http://www.retroarchive.org/cpm/text/text.htm から「Wrdmastr.zip」ファイルをダウンロードし、その中にある「WM.COM」をCP/Mのディスクにコピーします。続いて、前述のリンク先から「WM3.HEX」というパッチファイルをダウンロードします。また、http://www.s100computers.com/Software%20Folder/Assembler%20Collection/ZSID,%20SID%20&%20DDT.zip などをダウンロードして、デバッガの「SID.COM」を入手してください。これらのファイルも、CP/Mのディスクにコピーします。

準備を終えたら、CP/M-80を起動して次のコマンドを実行します。

A>SID WM.COM
CP/M 3 SID - Version 3.0
NEXT MSZE  PC  END
2700 2700 0100 C8FF
#Rwm3.hex
NEXT MSZE  PC  END
29DF 29DF 0100 C8FF
#Wwm3vt100.com
0052h record(s) written.
#g0

A>

作成された「WM3VT100.COM」が、ANSI/VT100互換の端末制御シーケンスに対応したWordMasterの実行ファイルです。テキストファイルを編集して確かめてください。

CP/M-80の画面をグリーンディスプレイ風にする

レトロ感を出すために、画面をグリーンディスプレイ風にしてみましょう。startcpm.cファイルのmain()関数にある、CP/Mの起動メッセージを出力している部分の前に、次のコードを挿入します。printf文で出力しているのは、文字を太字にして、文字色を緑にするエスケープシーケンスです。

  printf("\x1b[1;32m");

さらに、プログラム終了時に文字色を標準色(白)に戻せるように、bios()関数内のプログラム終了処理部分を次のように書き換えます。

      if (c == 0x10) {
        printf("\x1b[0;39m\n");
        exit(0);
      }

書き換え後、CP/M-80を起動して操作している様子を次に示します。なかなか良い感じではないでしょうか。

なお、カーソルの色は変えていません。「\e]12;green\a」といったエスケープシーケンスを使えば、端末によってはカーソルの色も変えられるのですが、筆者がリモートアクセスに使っているTera Termでは効かないのでそのままにしています。

グリーンディスプレイ風にしたCP/M-80の画面

コメント

タイトルとURLをコピーしました