CP/M v2.23

English

概要

現在の主流オペレーティングシステムはマイクロコンピューターでは Linux と Windows ですが、かつてはすべて Digital Research が CP/M(Control Program/Monitor)を作成したことから始まりました。CP/M はマイクロコンピューター向けの最初の本格的なオペレーティングシステムの一つで、様々なハードウェアをまたいでアプリケーションを実行するための共通手段を提供しました。CP/M が動作するマシンは何千ものプログラムにアクセスでき、こうして Sharp MZ80A に CP/M を動かすという探求が始まりました。

Sharp MZ80A 向けの CP/M バージョンは Micro Technology によって作成されましたが、80 桁スクリーンがないため、アップグレードなしではあまり役に立ちませんでした。調査したところ、Kuma などのサードパーティが 80 桁アップグレードを開発し、後に SUC から入手できるようになりましたが、MZ80A の CP/M は 2020 年時点では多くの記事で言及されているものの、実際に入手するのは非常に困難でした。original.sharpmz.org などの優れたサイトは 80K/80B/800 バージョンを提供していますが、MZ80A 向けは提供していません。

80 桁カラーアップグレードボードと Rom Filing System を開発した主な目的は、MZ80A で CP/M を実現することでした。FPGA ベースのハードウェアエミュレータープロジェクトでは様々な桁数の出力、カラー、グラフィックスに対応する変更を簡単に追加できますが、ヴィンテージマシンへの変更を最小限に抑えた実際のオリジナルハードウェアで行うことは、より大きな挑戦であり、1983 年にこのマシンを初めて手にして以来の個人的な願望でもありました。過去のアップグレードのほとんどはオリジナル PCB へのカットやリンクが必要ですが、私は特にそれをしたくありませんでした。Sharp が作ったままのオリジナルハードウェアを保ちたいのです!オリジナル PCB への私の唯一の変更は、チップ(IC8 74LS165 ビデオシフトレジスター)をソケット化することで、これは使用中に故障して交換が必要になった場合でも簡単に行え、マシンは 100% オリジナルの状態に保たれ、元の工場出荷状態に簡単に戻せます。

こうして CP/M を動作させようとしましたが、ネット上に大量の情報があっても簡単な作業ではありませんでした。まず、MZ80A 向けの Micro Technology 版 CP/M の入手が非常に困難だったため、MZ80K と MZ80B バージョンに頼ることにしました。次に、MZ80A が反転データを読み取るように設計されているという奇妙なディスクフォーマットの問題に直面しました。長い話を短くすると、独自の ROM ベース版 CBIOS を作成し、CP/M v2.23 の BDOS+CCP と組み合わせることにしました。このセクションではその作業の詳細を説明します。

CP/M ブートプロセス

CP/M の起動は 2 つのフェーズで行われます:

  1. オリジナルの AFI フロッピーディスク制御ソフトウェアを使用して反転ブートセクターを読み込み、0x0000 に制御コード 0x02 + “IPLPRO” が含まれていることを確認し、カプセル化されたブートローダーに制御を渡す
  2. 0x9C00 から始まる CCP、BDOS、CBIOS を読み込む。CBIOS が制御を引き継ぎ、異なるディスクフォーマットを適用して異なる FDC コントローラーロジックを使用する(データを再反転する)。
このため、MZ80A AFI ROM(リポジトリで入手可能)を逆アセンブルして、何をしているかを理解しました。最初の読み込みでは、ディスクが MZ80A でブート可能かどうかを確認します。MZ80K では、ブート可能ディスクのマーカー(フォーマットが大きく異なりデータを反転しないという点以外に)は最初のセクターの先頭バイトに 01 + IPLPRO でした。MZ80B では 03 + IPLPRO でした。

MZ80A 版の CP/M を持っていなかったため、MZ80K バージョンを読み込もうとしましたが、非反転データのため MZ80K ブートディスクを MZ80A フォーマットに変換する必要がありました。変換後に CP/M を起動しようとしましたが、ディスクコントローラーなどの非互換性がありました。その後 Micro Technologies の CP/M の MZ80B と MZ800 バージョンを調べましたが、これらも異なるディスクフォーマットを使用しており、最終的にはカスタム CP/M を構築して独自の CBIOS を作成するのが最善のアプローチだと判断しました。

CBIOS

CP/M は 3 つの独立したモジュールで構成されています:CCP(Console Command Processor)、BDOS(Basic Disk Operating System)、CBIOS(Custom Basic Input Output System)。一般的に CCP + BDOS は標準的で、CBIOS は基盤となるハードウェアに合わせてカスタマイズされます。

3 つのコンポーネントはすべてフロッピーディスクからブートストラップされ、メモリ(MZ80K/A では 0x9C00)に読み込まれ、制御が CBIOS に渡され、CBIOS がマシンをセットアップしてから CCP に制御を渡します。通常の動作条件下では、読み込まれたアプリケーションは BDOS を呼び出して、コンソールへの書き込み、キー入力の取得、ディスクアクセスなどのサービスを明確に定義された API から利用しますが、BDOS サービスが不要な場合は CBIOS を直接呼び出してその API を使用し、CCP+BDOS の RAM を使用して追加のプログラムスペースを確保することができます。アプリケーションが完了すると、ベクター 0x0000 にジャンプして CCP+BDOS の再読み込みを含むウォームスタートが開始されます。

CP/M は自己修正/組み込み変数を使用するため ROM への格納には適していませんが、CBIOS については話が別です。CBIOS を ROM に配置して RAM を増やすことが可能で、ページ ROM バンクを持つ Rom Filing System にアクセスできることもあり、私はこの方法を採用しました。

CBIOS を作成するには、以下の API メソッドを提供する必要があります:

API メソッド 説明
BOOT コールドスタート。CCP を呼び出す前にすべてのハードウェアを初期化する。
WBOOT ウォームスタート。ハードウェアの変更を元に戻してから CCP を呼び出す前に CCP+BDOS を再読み込みする。
CONST コンソールステータス。キーボードのキー入力が待機中かどうかを確認する。
CONIN コンソール入力。キーボードからキーを取得し、利用可能でない場合は待機する。
CONOUT コンソール出力。画面に文字を出力する。
LIST リストデバイス出力。リストデバイス(例:プリンター)に文字を出力する。
PUNCH パンチデバイス出力。パンチデバイス(70年代にはパンチテープやカードが使われていた)に文字を出力する。
READER リーダー入力。リーダーデバイス(例:紙テープ)から文字を入力する。
HOME 現在選択されているディスクのヘッドをトラック 0 に移動する。
SELDSK ディスクを選択/有効化する。
SETTRK 次の読み書き操作のディスクトラックを設定する。
SETSEC 次の読み書き操作の選択されたトラック上のディスクセクターを設定する。
SETDMA データが読み書きされる場所のディスクメモリアドレスを設定する。
READ ディスクセクターを読み取る。
WRITE ディスクセクターに書き込む。
LISTST リストデバイスステータス。リストデバイスが新しい文字を受け入れる準備ができているかを確認する。
SECTRN セクター変換。特定のハードウェアへの適応やディスクサブシステムの応答性向上のための論理から物理セクターへの変換。
単純な要件のように見えますが、MZ80A のようなマシンには独自の BIOS がなく、CP/M 動作時に ROM のファームウェアが 0xC000 に移動されるため使用できないことを考慮する必要があります。また、フロッピー制御ファームウェアは非常に基本的で、ディスクのブートストラップのみを扱います。

CP/M が提供する基本的な文字入出力メカニズムの上に必要なさらなる要件として、ほとんどのアプリケーションは高度な画面とキーボード機能を提供するスマートターミナルが CP/M マシンの前にあることを期待しています。これは通常 DEC VT52 や VT100 などのターミナルの形式です。MZ80A は独自の画面とキーボードを持っているため、このスマート機能を作成する必要があります。

CBIOS を作成するには、以下のファームウェアサブモジュールをコーディングする必要があります:

サブモジュール 説明
基本画面 I/O 画面に文字を配置する、画面をクリアするなどの低レベル機能。
高度な画面 I/O 表示出力の位置決め、画面の一部のクリア、太字などの特別属性のインテリジェンス。
キーボード I/O キーコードをスキャンして返し、必要に応じて ASCII にマッピングする。
ディスク I/O 複数のディスクセクターを読み書きする機能を提供する。
以前に Sharp SA-1510 モニターを逆アセンブルしていたため、基本的な画面とキーボード機能を提供するための良い出発点がありました。フロッピーディスク AFI ファームウェアの逆アセンブルから、フロッピーディスクの読み取りに必要なコードの洞察が得られ、特に欠点も明らかになりました。MZ80A は 2MHz コンピューターで、ディスク入出力ストリームを処理するだけの速度がなく、FDC のデータリクエスト/レディ信号に基づいて ROM バンクをページするハードウェアに依存しています。したがって、FDC コンポーネントには大幅な作業が必要でした。高度な画面 I/O については ANSI 標準を使用することにし、Ewen McNeill の Amstrad CPC ターミナルエミュレーターを採用しました。当初は ANSI パーサーを単純に抽出して組み込めると思っていましたが、これは大量の作業になりました。最も簡単に見えるオプションが最も難しい場合があります!

すべての機能はスペースを必要とし、以下のように割り当てられています:

ROM アドレス 説明
4K MROM(0x0000 - 0x0FFF から再配置されたモニター ROM) 0xC000 - 0xCFFF CBIOS(CP/M API、初期化ルーチン、ROM ディスクコントローラールーチン、割り込みルーチン)を提供。
2K ページ ROM 0xE800 - 0xEFFF、バンク 8 基本的なサウンドとメロディー、RTC、キーボードとヘルパー機能。
2K ページ ROM 0xE800 - 0xEFFF、バンク 9 画面 I/O と ANSI ターミナルパーサー。
2K ページ ROM 0xE800 - 0xEFFF、バンク 10 SD カードコントローラー機能。
2K ページ ROM 0xE800 - 0xEFFF、バンク 11 フロッピーディスクコントローラー機能。

CP/M ディスクドライブ

この CP/M と Custom BIOS の実装は 3 つの異なるディスクドライブコントローラーを使用し、そのうちのいくつかは常に存在するとは限らないため、ドライブはコールドブート中に CP/M 内で動的に作成されます。

ドライブの順序は以下の表に示されています:

ROM ドライブ # 存在 0 1 2 存在 0 1 2
ROM ドライブ n/a   A A,B n/a   A A,B
フロッピーディスク あり A,B B,C C,D なし      
SD カード あり C,D,E,F D,E,F E,F,G あり A,B,C,D,E B,C,D,E C,D,E,F
SD カード なし       あり      
ドライブ数の制限は CP/M(最大 16 ドライブ)と、リポジトリの CPM_Definitions.asm ファイル内の変数 'CSVALVEND - CSVALVMEM' で管理されるドライブに割り当てられた RAM の量によって決まります。ドライブの割り当ては動的で、割り当てるメモリが多いほど利用可能なドライブが増えます。SD カードには数百の 16MB SD ディスクドライブを含めることができるため、問題は純粋に使用目的に割り当てられた RAM です。

機能

標準的な BIOS 機能に加えて、以下の機能が CBIOS に追加されています。

  • 50mS 精度のリアルタイムクロック
  • バッファと自動リピートを持つ割り込み駆動キーボード
  • 通常、Caps Lock、Shift Lock の 3 モードキーロック
  • ANSI ターミナル機能
  • 1.44M、720K、320K サイズの再ターゲット可能なフロッピーディスクドライブ
  • 240K サイズの再ターゲット可能な ROM ドライブ(設定で変更可能)
  • 再ターゲット可能な SD カード 16MB ハードディスク
  • SHIFT+GRAPH+BREAK でモニターに終了

CP/M のビルド

CP/M のビルドは、Z80 アセンブリ言語ソースをマシンコードバイナリにアセンブルし、ブートディスクを作成することを含みます。この実装の場合は、ROM ベースの CBIOS と ROM に格納された MZF フォーマットのブータブルアプリケーションを作成します。

これを実現するにはいくつかのツールが必要で、現時点ではかなり手動のプロセスです。

パス

読みやすくするため、以下の短縮名はこの章の対応するパスを指しています。

短縮名  
[<ABS PATH>] このリポジトリがシステムに展開されたパス。
<software> [<ABS PATH>]/MZ80A_RFS/software
<roms> [<ABS PATH>]/MZ80A_RFS/software/roms
<CPM> [<ABS PATH>]/MZ80A_RFS/software/CPM
<tools> [<ABS PATH>]/MZ80A_RFS/software/tools
<MZF> [<ABS PATH>]/MZ80A_RFS/software/MZF
<MZB> [<ABS PATH>]/MZ80A_RFS/software/MZB

ツール

すべての開発は Linux、特に Debian/Ubuntu で行われています。Windows は RAM のフラッシュと GUI 版の CP/M ツールの使用に利用していますが、Windows での RFS のビルドには時間を割いていません。いずれ必要なツールがすべてインストールされた Docker イメージを作成する予定ですが、それまでの間、Z80 コードのアセンブル、C プログラムの作成、CP/M ソフトウェアと CP/M ディスクイメージの操作のために以下のツールを入手してインストールする必要があります。

Z80 Glass Assembler - アセンブリファイルをマシンコードに変換する Z80 アセンブラー。
samdisk - マルチ OS コマンドライン低レベルディスク操作ツール。
cpmtools - マルチ OS コマンドライン CP/M ディスク操作ツール。
CPMToolsGUI - Windows ベースの GUI CP/M ディスク操作ツール。
z88dk - Z80 CPU 向けの優れた C 開発キット。
sdcc - Z80 をターゲットの一つとする別の優れた Small Device C コンパイラー。z88dk はこのツールの Z80 向け強化版をパッケージ内に提供しています。

ソフトウェア

ソフトウェアイメージのビルドは、リポジトリをクローンし、提供されているシェルスクリプトとバイナリをいくつか実行することで行えます。

スクリプト 説明
assemble_cpm.sh CPM バイナリ、RFS 経由で読み込むための CPM MZF フォーマットアプリケーション、CPM ROM ドライブ 0 と 1 をビルドするシェルスクリプト
assemble_rfs.sh Rom Filing System ROM イメージをビルドする bash スクリプト。
assemble_roms.sh SA-1510 モニター ROM などの標準 MZ80A ROM をすべてビルドする bash スクリプト。
make_roms.sh 512KByte フラッシュ RAM にプログラミングするのに適した RFS ROM をビルドする bash スクリプト。
make_cpmdisks.sh SD カードまたは ROM ドライブのロー形式イメージと CPC Extended Disk Format の CP/M ディスクセットをビルドする bash スクリプト。
make_sdcard.sh RFS イメージといくつかの CPM ディスクドライブを組み合わせた SD カードイメージを作成する bash スクリプト。
mzftool.pl MZF イメージを作成/抽出/操作する Perl スクリプト。
processMZFfiles.sh MZF プログラムのセットを Rom Filing System ROM での使用に適したセクター化イメージに変換する bash スクリプト。
sdtool src/tools リポジトリで作成されたバイナリ。RFS SD カードイメージを構築しディレクトリを作成して MZF/バイナリアプリケーションをドライブイメージに追加します。

CP/M システムは 4 つの部分でビルドされます:

1. CCP、BDOS、CBIOS スタブを含む cpm22.bin。
2. プライマリソースが 4K ROM と 4 つのバンク化された 2K ROM にあるバンク化された CBIOS。
3. 任意の CP/M ドライブ文字に割り当てられる最大 2 つ(現在)の読み取り専用 CP/M ROM ドライブ。
4. バイナリを Rom Filing System に直接追加するのに適したセクター化 MZF イメージへの変換。

上記のすべては assemble_cpm.sh bash スクリプトにエンコードされており、以下のように実行できます:

cd <software>
tools/assemble_cpm.sh

CPM を使用するには、2×512KByte フラッシュ RAM にプログラミングできるモニター ROM と USERROM イメージを作成する必要があります:

cd <software>
tools/assemble_cpm.sh
tools/assemble_rfs.sh
tools/assemble_roms.sh
tools/make_cpmdisks.sh
tools/make_roms.sh
tools/make_sdcard.sh

ディスクフォーマット

わかったことですが、CP/M ディスクフォーマットは数百もあり、Sharp シリーズだけでもマシンごとに 2〜3 種類実装されています。この CP/M 実装に使用するフォーマットを決定するにあたり、既存のフォーマットを調べ、1.44MB、720K の 3.5” フロッピーの標準フォーマットと ROM ベースの 240K ROM ドライブを使用することにしました。

使用しているフォーマットは以下の diskdefs 定義を使用して cpmtools で操作できます:

   diskdef MZ80A-A
     seclen 256
     tracks 40
     sectrk 32
     blocksize 2048
     maxdir 64
     skew 0
     boottrk 1
     os 2.2
   end

   diskdef MZ80A-1440
     seclen 512
     tracks 80
     sectrk 36
     blocksize 2048
     maxdir 128
     skew 0
     boottrk 0
     os 2.2
   end

   diskdef MZ80A-720
     seclen 256
     tracks 80
     sectrk 36
     blocksize 2048
     maxdir 128
     skew 0
     boottrk 0
     os 2.2
   end

   diskdef mz80a-rfs
     seclen 128
     tracks 15
     sectrk 128
     blocksize 1024
     maxdir 32
     skew 0
     boottrk 0
     os 2.2
   end

   diskdef MZ80A-SDC16M
     seclen 512
     tracks 1024
     sectrk 32
     blocksize 8192
     maxdir 512
     skew 0
     boottrk 0
     os 2.2
   end

MZ80A CP/M ディスクの抽出

Sharp MZ-80A はフロッピーディスクデータを反転フォーマットで保存します。samdisk で EDSK を RAW に変換し、Python でバイト反転を行い、CPMTools で読み取ります。
  samdisk copy <MZ80A DISK NAME>.DSK <MZ80A DISK NAME>.RAW --cyls=40 --head=2 --sectors=16 --size=256
  python3 -c "import sys; sys.stdout.buffer.write(bytes(~b & 0xFF for b in open('<MZ80A DISK NAME>.RAW','rb').read()))" > <MZ80A DISK NAME>_normal.RAW
  cpmls -f MZ80A-A <MZ80A DISK NAME>_normal.RAW
  cpmcp -f MZ80A-A <MZ80A DISK NAME>_normal.RAW 0:*.* /output/directory/

MZ80K CP/M ディスクの抽出

Sharp MZ-80K は標準(非反転)データを使用します。バイト反転は不要です。
  samdisk copy <MZ80K DISK NAME>.DSK <MZ80K DISK NAME>.RAW --cyls=40 --head=1 --sectors=18 --size=128
  cpmls -f mz80k <MZ80K DISK NAME>.RAW
  cpmcp -f mz80k <MZ80K DISK NAME>.RAW 0:*.* /output/directory/

MZ80B CP/M ディスクの抽出

Sharp MZ-80B は MZ-80A と同様に反転フォーマットを使用します。
  samdisk copy <MZ80B DISK NAME>.DSK <MZ80B DISK NAME>.RAW --cyls=40 --head=2 --sectors=18 --size=256
  python3 -c "import sys; sys.stdout.buffer.write(bytes(~b & 0xFF for b in open('<MZ80B DISK NAME>.RAW','rb').read()))" > <MZ80B DISK NAME>_normal.RAW
  cpmls -f mz80b <MZ80B DISK NAME>_normal.RAW
  cpmcp -f mz80b <MZ80B DISK NAME>_normal.RAW 0:*.* /output/directory/

MZ800 CP/M ディスクの抽出

MZ800 シリーズはブートトラックに反転データ、CP/M トラックに標準データを使用する混合フォーマットです。データを抽出して他のフォーマットにコピーすることをお勧めします。
  samdisk copy <MZ800 DISK NAME>.DSK <MZ800 DISK NAME>.RAW --cyls=40 --head=2 --sectors=8 --size=256
   mv <MZ800 DISK NAME>.RAW workingfile.raw
   > total
   dd if=workingfile.raw of=total count=8192 bs=1
   for i in $(seq 8192 8192 327680); do
     dd if=workingfile.raw of=blob skip=$i bs=1 count=4096
     cat blob >> total
     echo $i
   done
   for i in $(seq 12288 8192 327680); do
     dd if=workingfile.raw of=blob skip=$i bs=1 count=4096
     cat blob >> total
     echo $i
   done
   mv total <MZ800 DISK NAME>.RAW

CP/M アーカイブ

CP/M アーカイブは Gitea から削除しました。必要な場合はzip ファイルをダウンロードしてリポジトリの <repo>/software ディレクトリに解凍してください。

cd <software>
tools/make_cpmdisks.sh

ディスクはディレクトリ <CPM>/1M44/DSK に作成されます。

このスクリプトはアーカイブの組み合わせを使用して 16MB SD カードドライブイメージもビルドします。

開発者ガイド

Sharp MZ 上の CP/M の内部アーキテクチャの理解、CBIOS の変更、新しいディスクフォーマットの追加、ソースからのビルドについては、包括的なCP/M 開発者ガイドをご覧ください。CCP/BDOS/CBIOS のレイヤリング、RFS と TZFS 両プラットフォームのメモリマップ、ディスクパラメータブロック、ANSI ターミナルエミュレータ、ストレージコントローラ、ビルドシステム、CI/CD パイプラインを網羅しています。