カテゴリー別アーカイブ: Apple II

8 ビットコンピュータ用シリアルサーバの構成

「シリアルサーバ」というのは今考えた言葉で、世間で通用する用語ではありません。どういう意味かというと、8 ビットレトロコンピュータに装備されている最低限の通信機能を利用して最近のハイエンドマイコンボード(Raspberry Pi、ESP32 等)ないし PC へ接続し、端末接続のみならず様々なサービス、例えばディスクエミュレーションやネットワーク機能などをレトロコンピュータに提供しようというアイディアです(注 1)。

レトロコンピュータ界隈ではこのアイディアに基づいて次のデバイスが発表されています。

レトロパソコンは数多く存在するのでこれ以外にも同様のデバイスがあるかもしれませんが、私が多少なりとも調べてみたことがあるのは上記二つだけです(注 2)。

ポイントは、レトロコンピュータ側は処理能力の限界上あまり複雑なプロトコルを喋れないということです。AppleTalk などの汎用ネットワークプロトコルは 16/32 ビットプロセッサの時代になってようやくサポートされました(注 3)。

そういう理由で、シリアルサーバでは接続相手のレトロコンピュータがなるべく少ないオーバーヘッドでサービス呼び出し処理を行えるように配慮されています。レトロコンピュータに搭載されている既存のモニタプログラムにはそのような機能がないので、専用のクライアントソフトウェア(ドライバ)を新たに書く必要があります。なお文字端末機能をシリアルサーバに載せる場合は基本的に 1 文字送受信を 1 パケットに対応させるため、元の回線速度の数分の 1 程度に遅くなることは避けられません。

***

と、ここまでさも全容を知っているかのように説明してきましたが、実のところ各システムの細部について十分理解できていません。そこで本稿では Apple2Pi のソースを読み、どのような構成になっているのかを調べていこうと思います。要は学習ノートです。あわよくば自分でも同様のサーバやクライアントプログラムを書こうという考えです。

Apple2Pi ソースコード

Apple2Pi ソースコードは Github で公開されています。docs ディレクトリに格納されているドキュメントを参照したところ、システム構成について簡単な説明がみつかりました。さしあたって次のソースコードが参考になりそうです。

  • src/a2pid.c: Raspberry Pi 上で実行されるデーモン(サーバプログラム)
  • src/a2lib.c、src/a2pidcmd.c、src/a2term.c: Linux 側から a2pid を利用するためのライブラリとクライアントプログラム群。
  • client/BUILD/a2pi.s: Apple II(ProDOS)側から a2pid を利用するための、シリアル回線経由のクライアントプログラム。マウス・ジョイスティックイベントをサポートしているため単純な文字入出力処理に比べると結構複雑になる。

注意することは、Apple2pi では Apple II の入出力ストリームを Linux のデバイスに接続するだけではなく、Apple II のキーボードとジョイスティックないしマウスを Linux の入力デバイスとして利用するという、いわば双方向のサービスが提供されている点です。今回想定している目的では後者の機能に深入りする必要がないので、興味のない部分はなるべく読み飛ばすようにします。

src/a2pid.c

シリアルサーバのサービスを提供するコードです。とりあえず main() から読んで概要を把握します。と思ったらファイルの半分超、約 550 行が main() 内のコードでした。くじけず読んでいくと次のような流れがわかります。

  • ポート 6551 で TCP ソケットをオープン(#653-)
  • Apple II に接続されたシリアル回線もソケット管理に含める(#676)
  • Apple II とサーバのコンソール入出力、ブロックデータ転送、仮想ディスクファイルの読み書き、IIe/IIc のマウスイベントなどの情報を通信する(#682-)

いったんソケットがオープンされると a2pid は TCP ソケットのクライアントおよびシリアル回線を監視し(#691 select())、パケットを受信するとコマンドを解釈して適切な応答を返すか関連するクライアントに転送します。a2pid プログラムの実行中はこのパケット処理ループから脱出しません。

なおソケット通信でやり取りされるデータはパケットと称されますが、パケット管理のためのフィールドは必要最低限に抑えられています。Apple II シリアル回線上での通信の場合パケット長は最小 3 バイトで、1 バイト目は必ずコマンド値です。主要なコマンドについて、将来流用できそうなものを中心として以下のように読んでいきます。

a. afd(Apple II シリアル回線)でやり取りされるコマンド

  • 0x80 sync:Apple II からの同期チェック。Apple II への応答(ack)は 0x81。
  • 0x82 a2d keybd:Apple II から送られるキーボードイベント。2 バイト目がモディファイアコード、3 バイト目がキーコード。
  • (マウス関連は割愛)
  • 0x90 ack read bytes, 0x92 ack write bytes: Apple II と a2pid 間のバイナリデータ転送
  • 0x96 send input char:Apple II へキーボード入力文字を送信する。Apple II からの ack コマンドは 0x97
  • 0x98 get output char:Apple II から文字出力を受信して印字担当クライアントへ転送する。
  • 0xa0、0xa2 drive 1/2 status call:ドライブ 1、ドライブ 2 のステータスを Apple II へ送信する。
  • 0xa4、0xa6 dirve 1/2 read call:ドライブ 1、ドライブ 2 の指定ブロックを読み出して Apple II へブロック転送(512 バイト)する。その後結果コード 1 バイトを Apple II へ送信する。
  • 0xa8、0xaa drive 1/2 write call:Apple II からのブロック転送(512 バイト)をドライブ 1、ドライブ 2 の指定ブロック位置へ書き込む。その後結果コード 1 バイトを Apple II へ送り返す。

b. srvfd(Linux TCP ソケット)でやり取りされるコマンド

Linux 上のクライアントプログラムと通信します。TCP ソケットなので a2pid が走っているマシンとは別のマシンでもクライアントを実行できます。

  • 0x90 read bytes:Apple II のメモリ内容を読み出す。addreq() を用いて転送リクエストをキューに追加する。
  • 0x92 write bytes:Apple II へデータを書き込む。addreq() を用いて転送リクエストをキューに追加する。
  • 0x94, 0x9a call:指定されたアドレスの Apple II ルーチンを実行する
  • 0x96 send input char:Apple II のキーボード入力へ 1 文字送る
  • 0x98 get output char:Apple II の 1 文字印字を取得する
  • 0xc0 reconnect vdrvs:仮想ドライブを再起動する(仮想ドライブファイルのクローズと再オープン)
  • 0xc2 disconnect vdrvs:仮想ドライブを閉じる
  • 0xff close:クライアントをクローズする

***

a2pid.c には仮想ドライブファイル読み書きのためのインターフェイス(vdrvopen(), vdrvclose(), vdrvread(), vdrvwrite() 等)が用意されています。ここは少し詳しく関数単位で見ていきます。

int vdrvopen(char *path)

Apple2Pi の仮想ドライブ 1/2 をオープンします。仮想ドライブのディスクイメージファイル名は “A2VD1.PO” および “A2VD2.PO” で固定ですが、これらのファイルがあるディレクトリパスは引数 path で指定できます。双方のファイルのオープンに失敗すると 0 を返し、それ以外の場合は 0 以外の値を返します。

void vdrvclose(void)

Apple2Pi の仮想ドライブ 1/2 をクローズします。

int vdrvtime(int afd)

ProDOS 形式の日付時刻データ(4 バイト)をファイルディスクリプタ afd に書き込みます。現在使用されていません。

int vdrvstat(int afd, int drive)

ドライブ drive に割り当てられているディスクイメージファイルのブロック数(=ファイルサイズ/512、2 バイト値)をファイルディスクリプタ afd へ書き出します。

int vdrvread(int afd, int drive, int block)

仮想ドライブ drive に対応するディスクイメージファイルのブロック番号 block の位置から 512 バイト(ProDOS 1 ブロック分のデータ)を読み出して、ファイルディスクリプタ afd へ書き出します。成功すると 0、失敗すると 0x27 を返します。

int vdrvwrite(int afd, int drive, int block)

ファイルディスクリプタ afd から 512 バイト(ProDOS 1 ブロック分のデータ)を読み取り、仮想ドライブ drive のブロック番号 block へ書き込みます。 完了後 fsync() で Linux ファイルシステムへの書き込みを確定します。成功すると 0 を返します。ファイルシステムへの書き込みに失敗すると 0x27 を、それ以外の失敗では 0x28 を返します。

***

Apple2Pi には vdrv* 系の読み書きインターフェイスとは別に Linux ファイルシステムから ProDOS ボリュームを操作するための fusea2pi.c も含まれますが、この部分は今回は読みません。

a2pid.c 以外のソースは簡単に眺めるだけに止めます。

src/a2lib.c

Linux クライアントから a2pid への接続と通信を扱うライブラリです。ソケットのオープン/クローズ、データブロック送受信、Apple II 内ルーチン(ProDOS システムコール等)の呼び出しが行なえます。

src/a2term.c

Linux コンソールを Apple II の入出力に接続するためのプログラムです。以下のコマンドを送受信します。

  • 0x96 を送信: Apple II へのキーボード入力送信。
  • 0x98 を受信:Apple II からの印字リクエスト。MSBをマスクする、改行文字を変更するなどの変換を行ってから Linux 端末上に表示する。
  • 0x9E を受信:キーボード入力を Apple II が受信したことの確認応答。a2term から送信した文字と一致しなかった場合はエラーとみなし、再同期はせずそのまま a2term 終了。

src/a2setvd, src/a2pidcmd.c

a2pidcmd は a2pid 経由で Apple II シリアル回線へ任意のコマンドパケットを送信し、応答として返される ack 値を受信します。なお Apple II が受け取った 1 バイト(かならず偶数値)のコマンドに対して返す ack 値は、コマンド値+1(奇数値)となります。

a2setvd は仮想ドライブにディスクイメージファイルを割り当てるスクリプトです。a2picmd を経由して a2pid へコマンド 0xc0(マウント)、0xc2(アンマウント)を送ります。アンマウント→イメージファイルを再リンク→マウントの順に実行することで指定のファイルを割り当てます。

利用する機能

以上、Apple2Pi のコードをかなり恣意的に拾い読みしてきました。ピックアップした内容を押さえることで次の処理が可能になります。

  1. シリアル回線を経由した文字の送受信
  2. シリアル回線を経由したディスクイメージファイルへのブロック単位の読み書き

つまり単一のシリアル回線を利用してコンソールとディスクエミュレータの 2 つの機能を実行できます。今後この機能を実装していきます。

注:

  1. 1980 年代の ASCII 誌で「Planet」という汎用パソコン間ネットワークのシステムが紹介されていました。京大 KMC のプロジェクトだったと思います。シリアル回線経由かどうかはわかりません。
  2. 2023 年 6 月時点で Raspberry Pi Pico ベースの 8 ビットサーバといえるシステムが複数発表されています。Raspberry Pi Pico には高速 PIO 機能があり、レトロマシンとの接続は必ずしもシリアルに限定する必要はありません。PIO は 1〜4 MHz クロックの 8 ビットシステムバスに接続するのにぴったりだな、と考えていたら RP2040 データシートそのものに用途例として “8080 and 6800 parallel bus” と書いてありました。
  3. 実際のところ Apple IIe 用の AppleTalk アダプタが発売されていたようです(参考)。また 1990 年代に入ってから Ethernet カードなども発売されていました。

自作 ASCII キーボードを Apple II Plus に接続する

ここしばらく作成している ASCII キーボード LMD-3420 の基本機能は 7 ビット ASCII キーコードをパラレル出力することです。またこれとは別に、キー押し下げイベントを信号立ち上げ(または立ち下げ)として表す 1 ビットの Strobe 出力があります。

Lmbda-3420 キーボード。ALPS AKB-3420(ほぼ)互換

このようなキーボードをコンピュータに接続する場合、CPU からは 7 ビット ASCII コードは通常の I/O ポート入力として読み出せばいいのですが、Strobe 信号は立ち上がりでフラグがセットされるフリップフロップとして保持し、CPU から任意の時点で読みに行けるようにしておく機構が必要です。また、ASCII コードを読み出したときにフラグが自動的にクリアされると便利です。Λ-1 コンピュータでは MC6821 PIA の CA 入力を使用することでキーボードからの Strobe 出力に即した設定が可能です。ASCII コードの 7 ビット出力は PIA の 8 ビットポート PA に接続します[注 1]。

実は Apple II のキーボードインターフェイスも全く同じ構成です[注 2]。違いは ASCII コードが負論理(Λ-1)か、正論理(Apple II)かという点だけです。したがって LMD-3420 のファームウェア(qmk_firmware のカスタムコード)で ASCII コードのビット反転操作を無効にすれば Apple II へ接続できます [注 3]。

Apple II のキーボード端子は 16 ピンの IC ソケットで、下図のピン配列になっています。これにあわせて LMD-3420 キーボード基板にも同様の配列の 16 ピンソケットを用意しました。上の画像でいうと基板上端の右寄りのソケット(ケーブルが取り付けられていない)です。

※ 実際には 1/16 ピン側が Apple II 基板手前となる(出典:
http://www.1000bit.it/support/manuali/apple/R023PINOUTS.TXT)

Apple II キーボード端子と LMD-3420 キーボードを 16 pin DIP 端子のフラットケーブルで接続します。DIP ソケット対応のコネクタ端子は最近あまり見かけませんが、当時はそれなりに使われていました。

DIP ソケットのフラットケーブル

このケーブルは DigiKey で注文するとワンオフで受注生産してくれます。特に高価なものではありません。

キーボードケースとキーキャップ

これまで LMD-3420 キーボードは基板むき出しの状態で使用していましたが、完成を目指してケースと下部構造を追加します。下部構造として、適切な傾斜のついた桁構造で基板とスイッチプレートを下から支持します。左右に 2 本と、中央に小さな桁を 3 個組み合わせた構造を使用しています。左右の 2 本はケース上面の左右端を支える構造にもなります。これらの桁構造は自宅の 3 D プリンタで出力しました。インサートナットを取り付けてねじ止めが容易になるようにします。

桁構造部品の 3D デザイン

また ABS 板を切り出してキーボード底板を作りました。ここへ 3 本の桁構造をねじ止めします。ねじのうち 5 本はゴム足を取り付けるためにも利用します。

キーキャップは SA プロファイルの Aifei 製 Fishing 互換セットに変更しました。LMD-3420 キーボードは一部キー配列が変則的なので既製品のキーキャップセットでは形状・キーレジェンドが完全に適合するものが見つからない部分もありますが、今回使用したキーキャップセットでは少なくともサイズと行が合致するキーキャップがひと通り揃っています。

唯一不足するのは 8u のスペースバーです。こんな長いスペースバーを現代のキーキャップセットに期待するほうが間違っているので、あきらめて自作することにしました。ところが、スタビライザも 8u サイズのものは簡単に見つかりません。そこで 7u スタビライザが使えるように自作スペースバーのスタビライザ用ステムの位置をずらしました。スイッチプレート上のスタビライザ取り付け穴も 7u 相当の形状で設置しています。

スペースバーの 3D デザイン。スタビライザ取り付け位置は 7u 相当

このキーボードの上にケースを取り付けます。ケースは長方形の板からキースイッチ部分の穴をくり抜き、前部・後部を折り曲げた形状になっています。上面は桁構造で決まる斜面に沿って前傾しています。オリジナルの AKB-3420 ケースは金属板を折り曲げ加工しているのだと思いますが、実物を触ったことがないのでよくわかりません。今回は加工後の形状のケース部品を、8u スペースバー部品とともに 3D プリントサービスへ発注しました。ケースには 128×32 ドットの小型 OLED ディスプレイと Raspberry Pi Pico の USB コネクタ部分を外に出すための穴を開けてあります。

ケースの 3D デザイン

ケースのサイズは 36cm x 18cm で主要部分の厚さは 2mm です。サイズに比べて厚みが足りないようで、発注先 JLCPCB の 3D プリント部門から「細い部分でひずみが出るかも」というデザインレビュー警告が来ましたが「とりあえずこのままプリントしてください」と回答しました。到着した実物を確認すると案の定、ケース手前の一番細い部分が若干歪んでおりキーボードスペースバーと干渉しかねない形状になっています。ヒートガンで温風を当てつつ手で逆方向へ曲げることで問題ない程度まで修正しました。

ケース(ひずみ修正済み)と 8u スペースバーを取り付けた状態

レジン製のケースは乳白色の地味な色合いなので、この上にステッカー式のカスタム印刷デザインシートを貼付しました。以前 Λ-1 のフロントパネルに貼ったものと同じ製品です。色もフロントパネルに合わせてあります。

貼付け前のデザインシート。これは同時注文した色違い版
デザインシートを貼ったケース。OLED と USB コネクタの部分に 3D プリント製のカバーを追加しています

Apple II plus キーボード端子に接続

Apple II plus 純正キーボードは小文字入力モードがなくデフォルトで英大文字が入力されます [注 4]。また一部の記号キーが足りず Shift-P で ‘@’、Shift-N で ‘^’、Shift-M で ‘]’ を入力するようになっています。LMD-3420 キーボードではこれらの記号にもそれぞれ ANSI のキーが割り当てられているので、Shift-英文字キーによる記号入力機能は割愛しました。

前述のフラットケーブルで LMD-3420 と Apple II plus キーボードコネクタを接続し、電源投入して問題なく入力できることを確認しました。

なお上の画像では LMD-3420 キーボードが Apple II の幅より大きく見えますがこれは遠近法による錯覚で、実際には LMD-3420 も Apple II ケースも横幅はほぼ同じで 14 インチ(36 センチ)内外です。

ファームウェアの設定を変えると Λ-1 に対応

[1] 8 ビット幅の PIA A ポートに 7 ビット ASCII パラレル信号を接続するので、MSB 1 ビットが余ります。Λ-1 および Chick-Bug の設計ではこの MSB に VDG の書き込み禁止 FS 信号を入力しています。ということは、画面書き換え処理を行うたびに CA1 のキーボードストローブがクリアされるという動作になります。どうやらこれは意図的な設計らしく、Λ-1 システムでは画面書き換えが完了するまで次の文字は入力できないという挙動になります。

[2] オリジナル Apple II と Apple II plus の本体基板だけがパラレルキーボードインターフェイス対応のコネクタを備えています。Apple IIe 以降ではエンコード回路も本体基板に内蔵されるため、キーボードコネクタはもっとピン数の多いものになっています。

[3] ただし実際には左矢印キーの扱いなど一部例外的な処理があるので、キーコードマッピング自体も変更してあります。

[4] 後期リビジョンの Apple II plus では小文字入力も可能です。

ナーシャ・ジベリ氏インタビュー(1998/2017)

古くからのビデオゲーム愛好家の方々は「ナーシャ・ジベリ(Nasir Gebelli)」という名前を記憶されていることでしょう。Apple II アクションゲームの中でもひときわ高度なプログラミングテクニックを駆使したタイトルのいくつかに「BY: NASIR」というクレジットが掲げられていました。ジベリ氏はまた、FC 版「ファイナルファンタジー」シリーズ(I~III)および SFC「聖剣伝説 2」のプログラマとしても知られています。

「Doom」「Quake」シリーズの開発者で FPS というジャンルを世に広めたゲームデザイナー、ジョン・ロメロ氏も Apple II ゲームが自らのキャリアのルーツであるという方のひとりです。ロメロ氏はジベリ氏の熱烈なファンであると同時に Apple II ゲームと関連資料の収集・保存を進められており、活動の一環として過去に 2 回ジベリ氏へのインタビューを行っています。インタビューの内容は動画とポッドキャストで公開されており、他では表に出る機会の少ないジベリ氏についての貴重な資料です。

ロメロ氏は 1998 年にジベリ氏を自社キャンパスに招いてインタビューを行っており、これを収録したものが最初のリンクの YouTube / Vimeo 動画です。約 20 分の動画ですが FF シリーズ開発の経緯について比較的詳細に語られており、当時のスクウェアの開発体制をうかがい知ることができます。

後者は 2017 年頃に行われた 4 時間に及ぶインタビューをポッドキャスト 3 回に分けて収録したものです。ちなみに FF シリーズ開発当時の話は主に Part 2(Episode 4)で聞けます。なおこのポッドキャスト「Apple Time Warp」には他の Apple II デベロッパへのインタビューも収録されており、Episode 3〜Episode 5 がジベリ氏のインタビュー回です(注 1)。

6502 プログラミングに際してジベリ氏は Apple II 標準ミニアセンブラ以外の開発ツールを使わず、コード中のアドレスもラベルなしで管理していたそうです。(FF シリーズ開発当時)赤坂のマンションに籠もってコーディングに没頭していたらいつの間にか 40 時間過ぎていた、プリンタやダンプリストも使わずコードのすべてを頭の中に入れて開発していた等々、噂に違わぬスーパープログラマぶりを示すエピソードがご本人の口から聞けます。そのかわり一つのプログラムの開発期間は最長でも 2ヶ月で、それ以上時間が経つと記憶を維持できなかったとのこと。

2017 年のポッドキャストのほうは長尺なぶん話が脱線することも多く、FF2 開発の追い込みで日本から出張してきたスクウェアのスタッフ(注 2)を地元サクラメントのステーキハウスに連れて行った話なども出てきますがそれはそれで興味深いエピソードです。

注:

1: 「Apple Time Warp」は基本的に音声ポッドキャストですが、ジベリ氏インタビュー回を含む最初の数エピソードにはチャプターが切ってあり話の内容に合わせてサムネイルが関連画像に切り替わります。この画像が結構アノテーション的に参考になります。

2: ビザ手続きの都合でジベリ氏が帰国しスクウェアのスタッフがサクラメントのホテル(Residence Inn on Howe Ave., Sacramento)に詰めて開発していた時期について、ロメロ氏が「FF2 に続けて FF3 の開発もサクラメントで?」と聞くとジベリ氏が「スクウェアのチームはプログラムが完成したら日本に戻りましたよ。というかサクラメントでやったのが FF3 じゃなかった?」ロメロ氏「FF2 だと思いますよ、何年のことかわかれば調べがつくのですが…」というくだりがあり、ジベリ氏の帰国のタイミングが「2」開発時なのか「3」開発時なのかは未確定のまま別の話題に移りました。ネット上の他の記述を見てもまちまちです。こういった前後関係についてはロメロ氏のほうが詳しく調査されていて信頼度も高いのですが(ジベリ氏曰く「僕よりも僕のゲームに詳しいね」)インタビュー内ではロメロ氏も断言されていないので判断しかねるところです。当時スクウェアに在籍されていた方々ならおそらくご存知かと思われます。

Apple II Z80 カードの制作

ALLPCB で小型基板を月 1 回無料で作成できると聞き、早速ユーザ登録を行いました。まず試しに、先日作成した Apple II 拡張カードの KiCAD テンプレートを利用して Z80 SoftCard 互換基板を作ることにしました。

オリジナル版 Z80 カード(1980 年製 MS Softcard)はカード幅が約 14 cm なので無料 PCB のサイズでは作れませんが、TTL をすべて SOIC パッケージに変更すると 9.5cm x 8cm に収まります(高さ 8cm は Apple II 筐体サイズによる上限)。

[注:後で調べたところ ALLPCB の無料基板枠は幅 15 cm まで可能なようです。]

回路はオリジナル版のほぼ丸写しなのでことさら公開するようなプロジェクトではありませんが、制作を通じて回路構成を理解したり各部信号のタイミングを調べて CPU カード一般の設計手法を学習しようと思います。

Gerber ファイルアップロード後、一週間も待たずに PCB が到着しました。これで DHL 配送も無料と言うのだからなんだか狐に摘まれた気分です。もとより採算度外視のプロモーションなのでしょうが、配送費のような外部コストまで負担するのはすごいですね。品質も他社に劣らないものだったので次は有料で発注しようと思います。

組み立て前の基板チェックで若干の配線ミス(~DMAOUT と DMAOUT の取り違え)が判明しデバッグが必要になりましたが、それ以外は大きな問題もなく最初の電源投入で動作、私にしては珍しく順調に進みました。Apple CP/M 56K による起動を確認しました。

回路構成については SoftCard 付属ドキュメント「Software and Hardware Details」に概要が解説されています。次の各ブロックから構成されます。

  • クロック生成(U1, U4, U9, U12, Q1)
  • データバスバッファ(U3, U6, U9, U13, U15)
  • アドレスバスバッファ(U3, U14, U16, U17)
  • アドレス変換および設定切替(U7, U8, U11, U12, DIP-SW)
  • CPU 切替・リセット(U1, U2, U3, U5, U6)
  • 割込設定(U2, DIP-SW)

各種タイミングを測定しました。SoftCard で特徴的なのは Z80 クロック(下図の D10)の 2 サイクルに一度ストレッチが入る点です。これによって Apple II 本体(RAM)との同期を取っています。


D0: (A2) PH2, D1: (A2) 7M, D2: (A2) R/~W, D3: (A2) RDY, D4: (A2) ~DMA, D5: ~RD, D6: ~WR, D7: ~BUSAK, D8: ~WAIT, D9: ~RFSH, D10: CLK, D11: (A2) ~IOSEL

ただこの測定では目的を絞らずやたらチャンネルを増やしており、あまり賢いやり方ではなかったようです。チャンネルによってはグリッチが出たり信号を受け取れなかったりするケースがありました。

最後に、例によって ASCIIART ベンチを取ります。

Apple IIe + SoftCardZ80A 2.045MHzMBasic (BASIC-80 Rev. 5.2) / Apple II CP/M 56K Ver. 2.20B9’20”

Apple II リモート開発環境:VSCode Remote Development

前回の投稿で Apple II Pi をセットアップし、Apple II 実機と Raspberry Pi の間の橋渡しができました。最後に以下の作業を行って開発環境を整備します。

  1. Raspberry Pi に各種開発ツールをインストールする
  2. Mac から Raspberry Pi へ VSCode Remote Development 接続を行う
  3. サンプルコードのダウンロードと実行

これにより、普段使用している Mac デスクトップ環境で Apple II ソフトウェアの開発が行なえます。

Raspberry Pi 上の開発環境設定

開発ツールとして git、CC65、AppleCommander を Raspberry Pi にインストールします。

git 環境の整備

インストール

sudo apt-get install git

git ユーザ名の設定と github への ssh 接続

基本的な流れは Mac/Win 上での設定と同じです。

CC65 のインストールと設定

CC65 は 6502 用 C クロスコンパイラ・クロスアセンブラです。Apple II 用のメモリマップが使用できます。パッケージをインストールすることも可能ですが、ここではソースからビルドします。

git clone https://github.com/cc65/cc65.git
cd cc65; make
sudo make install

インストール先は次のとおりです。

コマンド:       /usr/local/bin/*65
ライブラリ等:/usr/local/share/cc65/

ビルドツールとして CMake, Ninja をインストールします。

sudo apt-get install cmake ninja-build

CMake と Ninja の CC65 向け設定として cc65-toolchain-example を利用します。後述するサンプルリポジトリに組み込むのでここではインストールしません。

AppleCommander

AppleCommander は Apple II 用ディスクイメージ操作ツールです。CC65 で作成したバイナリを Apple II ディスクイメージに書き込むために使用します。

AppleCommander のインストール手順は次のとおりです。

  1. AppleCommander リリースページから最新の ‘AppleCommander-ac-1.x.y.jar’ ファイルをダウンロードします。
  2. 次の要領でインストールします。
sudo apt-get install openjdk-11-jdk
sudo cp AppleCommander-ac-1.6.0.jar /usr/local/bin
cd /usr/local/bin; sudo ln -s ./AppleCommander-ac-1.6.0.jar ./ac.jar
sudo vi ./ac.sh
[以下の内容を入力]
#!/bin/sh
java -jar /usr/local/bin/ac.jar $*
[:wq で vi 終了]
sudo chmod 755 ./ac.sh

コマンドラインツール ‘ac.sh’ が使用できるようになります。

VSCode Remote Development のセットアップ

以上の作業により必要なツールを Raspberry Pi 上にインストールしました。しかしこの Raspberry Pi は基本的に ssh 接続の文字端末からしかアクセスできないので、開発環境として使うには若干非効率です。VNC 接続を設定して Raspberry Pi デスクトップを使用してもいいのですが、ここでは VSCode Remote Development を利用することにします。この方法だと普段使用している Mac/PC の操作性そのままで作業が行えて快適です。

以下の手順で Mac から VSCode Remote Development が使用できるようになります。PC でも基本的な流れは同様です。なお、Mac から Raspberry Pi への ssh パスフレーズ接続は前回の投稿で説明した手順で設定済みであるものとします。

下記の操作はすべて Mac 上で行います。

  1. Mac 上の VSCode はインストール済みであるとします。
  2. VSCode 機能拡張 ‘Remote Development’(ベンダー:Microsoft)をインストールします。
  3. VSCode 画面の左端ナビゲーションバーに追加された ‘Remote Explorer’ アイコンをクリックします。
  4. Remote Explorer パネルが表示されます。前回の投稿で設定した ~/.ssh/config ファイル内のエントリが ‘ssh targets’ の下にリストされています。
  5. 登録済みエントリの一つ ‘rpi’ にカーソルを乗せ、右に表示される +🗂 をクリックします。
  6. config ファイルの設定に従って Raspberry Pi への接続が開始されます。最初に ssh パスフレーズの入力が求められます。その後 VS Code Remote Development のダウンロードが始まります。初回接続時はダウンロードにしばらく時間がかかります。
  7. ダウンロードが終了すると VSCode の新規ウィンドウが開きます。左下に ‘SSH rpi’ と表示され、このウィンドウが Raspberry Pi 上の Remote Development 画面であることが示されます。

Remote Development 参考記事

Remote Development 画面では次のいずれかの方法で開発を開始できます。

  • シェルコンソールを開いて新規ディレクトリを作り、その中で ‘git init’ を実行する
  • シェルコンソールで ‘git clone’ を実行してプロジェクトを取得する

いずれの場合も VSCode Remote Development ウィンドウ上でプロジェクトディレクトリを開いてコーディングを始めます。

リモート開発環境の構成

以上で Apple II リモート開発環境がひと通り設定できました。開発環境の構成は下図のとおりです(前々回投稿の図を再掲)。

サンプルコードのダウンロードと実行

この環境で動くサンプルコードを 2 種類作りました。

これらのリポジトリはビルド設定用に cc65-toolchain-example をサブモジュールとして含みます。 git clone コマンドでリポジトリをクローンした後、リポジトリ内で次のコマンドを実行してサブモジュールをロードします。

git submodule update -i

2 つのリポジトリのディレクトリ構造は共通です。トップディレクトリにある runall.sh を実行すると、3 個のソースディレクトリ(Applesoft Basic、C、アセンブリ)について以下の処理を繰り返します。

  • 各 src ディレクトリの build.sh を実行して以下を処理
    • C とアセンブラについては CMake + Ninja でビルド実行
    • Basic、C、アセンブラそれぞれのプログラムを含むディスクイメージを作成
  • ディスクイメージをマウント
  • Apple II コンソールからプログラム実行コマンド(RUN、BRUN)を送出

今後はこのサンプルリポジトリをテンプレートとして使用する予定です。

Apple II リモート開発環境:Apple II Pi のインストールと設定

Apple II Pi(David Schmenk 氏作)はその名の通り Apple II と Raspberry Pi を組み合わせたシステムで、次の各要素から構成されます。

  • Apple II Pi カード(簡易シリアル通信カード)
  • Raspberry Pi
  • a2pi(ProDOS 常駐ソフトウェア)
  • a2pid(Raspberry Pi OS サービス)と付随ツール群(a2term、a2mon など)

次の機能が提供されます。

  • ブロックデバイス仮想ドライブ x2
  • Apple II リモートコンソール
  • 簡易マシン語モニタ
  • Fuse ドライバによるファイル共有
  • ジョイスティック読出し

詳細は Apple II Pi 公式マニュアルに記載されています。

本稿では Apple II リモート開発環境の構築を目的として、Apple II Pi のインストールと設定を行う手順について説明します。

ハードウェア(Apple II Pi カード + Raspberry Pi)

Apple II Pi カードハードウェアの頒布は終了しているので、プロジェクトリポジトリで公開されている回路図をもとに自作します。次のいずれかの方法で作成できます。

  • Apple II 拡張カードユニバーサル基板上に手配線で作成する
  • Apple II 拡張カードプリント基板を設計する

私はどちらの方法も試しましたが、6551 ACIA + 74LS04 + 若干の CR というシンプルな構成なので作成はそれほど難しくありません。

オリジナル版 Apple II Pi カードは Raspberry Pi の電源を Apple II から取得する設計になっていますが、私の作った Apple II Pi カードでは GPIO コネクタの +5V ラインを Apple II 電源に接続しません。Raspberry Pi は世代を重ねるごとに消費電力が増えており、製造後数十年を経た Apple II の電源ユニットにとって負担となる恐れがあるためです。かわりに通常通り Raspberry Pi の micro USB 端子から電源を取るようにしています。

Raspberry Pi モデルの選択と接続方法

使用する Raspberry Pi モデルは 3B+、3A+ あたりが適切でしょう。VSCode Remote Development を使う場合、Zero W では処理が重くなるかもしれません。今回は 3A+ を使いました。

外部の PC からヘッドレスでアクセスするために Raspberry Pi の Wifi 接続を使用しますが、Apple IIe ケースのシールド加工が Wifi の電波をブロックしてしまうという問題があります。Apple IIe の上蓋を常時開けたまま運用すれば通信に支障はありませんが、上蓋を閉じて使用する場合は何らかの対策が必要になります。有線 LAN を使用する、USB 延長ケーブルの先に WiFi ドングルを接続する、Apple II Pi カードの代わりに Super Serial Card を使用するなどの方法が考えられます。

下の画像は自作 Apple II Pi カードと Raspberry Pi 3A+ を GPIO コネクタで接続し、Apple IIe のスロット 2 に挿した様子です。Raspberry Pi の電源ケーブルは外部の USB 電源ユニットに接続されています。電源ケーブルのコネクタは Apple II 基板との干渉を防ぐため直角形状のものを使用します。micro USB の直角コネクタは右向き、左向きの区別がありますがどちらでも取り回し可能です。

これ以外に、Raspberry Pi の記憶媒体として SD カードが必要になります。

Apple II Pi ソフトウェアのインストール

以上でハードウェアは揃ったので、ソフトウェアのインストールと設定を行います。

以下数節で次の作業を行います。

  • Raspberry Pi OS Lite のインストールとヘッドレス設定
  • ssh 公開鍵/秘密鍵の設定
  • Apple II Pi ソフトウェアのインストール
  • systemd 対応
  • 動作確認
  • 追加設定(a2pid のパッチ)

Raspberry Pi OS Lite のインストールとヘッドレス設定

最初に Raspberry Pi OS をインストール、設定します。以前の投稿で PiTrex をセットアップした際の手順と同様です。

  1. SD カードを Mac(あるいは Linux/Win PC)に接続します。
  2. Raspberry Pi Imager を Mac にインストールして実行します。
  3. Raspberry Pi Imager ウィンドウの「Operating System」をクリックして「Raspberry Pi OS (other)」を選択、さらに「Raspberry Pi OS Lite (32-bit)」を選択します。インストール先として SD カードを指定し、 Raspberry Pi OS Lite をインストールします。
  4. SD カードをいったんアンマウントしてから Mac に再接続します。カード内の boot パーティションがマウントされます。Mac の場合は /Volumes/boot ディレクトリにマウントされます。
  5. boot/wpa_supplicant.conf ファイルを新規作成してテキストエディタで編集し、Wifi 接続先のパラメータを指定します。詳細はこの記事にわかりやすく説明されています。
  6. 空の boot/ssh ファイルを作成します。

以上を完了したら SD カードを Mac からアンマウントして Raspberry Pi にセットします。この時点では Raspberry Pi を Apple II Pi カードに接続せず、単独で電源投入します。Wifi + ssh 経由でログインしたらデフォルトユーザ pi のパスワード変更、新規ユーザの追加、raspi-config を使った追加設定(ホスト名変更など)を好みに応じて行います。

SSH 公開鍵/秘密鍵の設定

Mac やその他 PC から Raspberry Pi へ ssh パスフレーズ接続できるように公開鍵/秘密鍵を設定します。Mac での手順はこの記事で詳細に説明されています。Mac 以外の環境での設定方法も検索すれば多く見つかります。パスフレーズは空にせず適切な複雑度の文字列を設定します。

以降の接続を容易にするために、Mac の ~/.ssh/config に以下の要領でエントリを追加します。

Host rpi
        HostName raspberrypi.local
        User pi
        Port 22
        IdentityFile ~/.ssh/rpi

HostName(Raspberry Pi マシンのホスト名)と IdentityFile(秘密鍵ファイル名)は現状に合わせて変更します。

以後は ‘ssh rpi’ とタイプしてパスフレーズを入力するだけで Raspberry Pi に ssh 接続できます。パスフレーズと ssh config 設定は後で VSCode Remote Development へ接続する際にも使用します。

Apple II Pi ソフトウェアのインストール

Apple II Pi 公式マニュアルの記述通り、次の 2 行のコマンドを実行して Apple II Pi ソフトウェアをインストールします。

wget schmenk.is-a-geek.com/tarfiles/a2pi_armhf.deb
sudo dpkg -i a2pi_armhf.deb

インストール後 Raspberry Pi を再起動します。

/usr/share/a2pi/A2PI-1.6.PO ファイルを使って Apple II の起動ディスクを作成します。

またインストールしたソフトウェアとは別に、公式リポジトリからソースコードを Raspberry Pi にクローンしておきます(その前に git コマンドを インストールします)。

sudo apt-get install git
git clone https://github.com/dschmenk/apple2pi.git

systemd 対応

Raspbian / Raspberry Pi OS は systemd 以前と移行後でシステム起動時のサービス設定手順が変わっています。2021 年時点で、上記の方法でダウンロードできる Apple II Pi インストールパッケージ(タイムスタンプ 2017 年 8 月の a2pi_armhf.deb)は systemd に対応しているようですが、念のため設定を再確認します。

まず、Raspberry Pi の UART0(GPIO14, GPIO15)を Apple II Pi との通信専用にするため UART0 の login: セッションを無効にします。

  1. sudo raspi-config コマンドを起動し「3 Interface Options」→「F6 Serial Port」を選択
  2. 「Would you like a login shell to be accessible over serial?」に対して「No」を選択
  3. 「Would you like the serial port hardware to be enabled?」に対して「Yes」を選択
  4. raspi-config の終了時に再起動を求められるのでそれに従います。

次に、/lib/systemd/system/a2pi.service ファイルがインストールされていることを確認します。a2pi.service ファイルが存在し、以下の内容になっていることを確認します。

[Unit]
Description=Apple II Pi Daemon
After=network.target

[Service]
Type=idle
Environment="HOME=/root"
EnvironmentFile=-/etc/default/a2pi
ExecStart=/sbin/a2pid $A2PID_OPTS
Restart=on-failure

注:タイムスタンプ 2017 年 8 月の a2pi_armhf.deb を使ってインストールした場合、このファイルに問題はないようです。

注 2(2023/04):Raspberry Pi OS(32bit, 2.21.2023, Kernel 5.15)では上記の a2pi.service ファイルでは起動せず、EnvironmentFile 行の ‘-‘ を削除すると a2pid が正常に動作する場合があります。ただしサービスがすべて展開されるかどうかは未確認です。

このファイルにより、Raspberry Pi 起動時に a2pid が自動的に起動します。

ここまでの設定を終えた Raspberry Pi は Apple II Pi に接続しないで長時間(1 日程度)放置すると a2pid からのシステムログでファイルシステムが溢れるため、不要な期間はシャットダウンしておく必要があります。この問題への対策は後述します。

動作確認

以上で必須のソフトウェア設定は終わったので Apple II Pi を起動して動作を確認します。

  1. Apple II Pi カードと Raspberry Pi の GPIO ピンを接続します。ピン位置がずれないよう注意します。
  2. Raspberry Pi の USB micro 端子に電源ケーブルを接続します。
  3. Apple II Pi カードを Apple IIe のスロット 2 に挿します。他のスロットも使用できますがその場合は以降の説明中のスロット番号を適宜読み替えます。
  4. Raspberry Pi の電源ケーブルを電源に接続します。Raspberry Pi の起動が始まります。
  5. /usr/share/a2pi/A2PI-1.6.PO ファイルから作成したディスクで Apple IIe を起動します。

Apple II 起動ビープ音の後 Apple II 画面に接続待機メッセージが表示されます。初回接続時のみ Apple II Pi のスロット番号の入力を求められます(スロット番号 2 を入力)。その後 Apple II Pi の接続に成功するともう一度ビープ音がなります。

Apple II 画面に下の画像の内容が表示されれば接続完了です。

この時点で Apple II のキーボードを叩いても画面には反映されません。一方、Mac や PC から Raspberry Pi に ssh ログインしたターミナル画面で a2term コマンドを起動すると Apple II コンソールに接続されます。この状態で ProDOS や AppleSoft Basic のコマンドが入力できます。下図のように a2term セッションを開始して ‘CATALOG,S2,D1’ コマンドの応答が得られれば、Apple II Pi の基本的な動作を確認したことになります。

※ エミュレータではなく Apple II 実機とのセッションです

トラブルシューティング

具体的な解決法は提供できませんが、問題を特定するためのヒントをいくつか説明します。

  • Apple II 電源投入後、起動が正常に進めば Apple II ビープが 2 回鳴ってから上掲 Apple II 画面のメッセージが表示されます。2 つ目のビープが鳴らない場合は Apple II Pi への接続に失敗しています。画面左上のプログレスインジケータ(回転する棒)がいつまでも表示されていることもあります。
  • 起動と接続のシーケンスが正常に完了しない場合は、Raspberry Pi の /var/log/syslog および /var/log/daemon.log から ‘a2pi’ を含む行を抽出、確認します。
  • これらのログファイルに ‘a2pid: Unknown Event’ というメッセージが複数並んでいる場合は 2 つの可能性があります。
    1. Rasberry Pi がシリアル回線(UART0)にログインセッションを送信している
    2. Apple II Pi カードが正常に動作していない、あるいは Apple II の電源が落ちている

‘Unknown Event’ メッセージが多発する問題が発生する場合は、「systemd 対応」の節で説明した方法で UART0 の login: セッションを止めます。Apple II 電源オフ時に ‘Unknown Event’ メッセージが多発するのは既知の問題で、次節で対策を説明します。

a2pid.c へのパッチ

Apple II の電源をオフにした状態で Apple II Pi ソフトウェアをインストールした Raspberry Pi だけをオンにしていると syslog に ‘Unknown Event’ というメッセージが繰り返し書き込まれます。放置すると約 1 日で 32GB の SD カードを溢れさせてしまい以後の動作に支障をきたします。

もともとの Apple II Pi 設計では Raspberry Pi の電源を Apple II から取っていたので、Raspberry Pi の電源だけがオンになる状況は極めてまれでした。本稿では Apple II 電源ユニット保護の観点から Raspberry Pi を別電源に接続しているので、問題の状況が起きやすくなっています。今後の投稿で触れる予定ですが、VSCode でプログラミングする際はあえて Apple II の電源を落としたまま Raspberry Pi 上でコーディングを続けるということも考えられます。

そこでこの ‘Unknown Event’ メッセージを抑制するために、a2pid のソースコードにパッチを当てます。以下の手順を実施します。

  1. まだ行っていなければ Raspberry Pi 上に Apple II Pi ソースコードリポジトリをクローンします。
    git clone https://github.com/dschmenk/apple2pi.git
  2. ソースファイルディレクトリに移動します。
    cd apple2pi/src
  3. この gist(公式 Apple II Pi リポジトリとは無関係の私製のもの)の内容を ‘a2pid.c.patch’ ファイルに保存します。
    cat > a2pid.c.patch
    (コピー内容をペーストして ctrl-D でファイルを閉じる)
  4. パッチを a2pid.c に適用します。
    cp a2pid.c a2pid.c.bak
    patch < a2pid.c.patch
  5. 新しい a2pid をコンパイル、インストールします。
    make a2pid
    chmod a+x a2pid
    sudo cp a2pid /sbin/

注意:

  • 手順が煩雑に感じられる場合はパッチを当てる必要はないでしょう。このパッチを当てない場合は、Raspberry Pi 単体で電源オンにする機会を極力減らします。
  • 将来の Apple II Pi リリースで a2pid.c ソースコードに変更があった場合、このパッチは通用しなくなります。

まとめ

以上の手順で Apple II Pi が動くようになります。ただし、これはあくまで PC/Mac から Apple II プログラミングを行うという目的に合わせた必要最低限の設定手順です。

作者 David Schmenk 氏の YouTube デモを観ると、Apple II Pi には次のような用途もあるようです。

  • Apple IIe のキーボードとジョイスティック(またはマウス)を使用して Raspberry Pi OS デスクトップや Apple IIGS エミュレータ gsport を操作する
  • Fuse ドライバ経由で Raspberry Pi 上のファイルを Apple II 上にコピーする

今後 Apple II Pi ハードウェアの新バージョンも予定されているようです。作者 YouTube チャンネルの 2021 年 4 月の動画で新バージョンのプロトタイプについて触れられています。更新情報は Facebook ページに投稿されています。

次の投稿では VSCode Remote Development を Mac から実行する手順を説明します。

参考

Apple II リモート開発環境の構築

Apple II の開発環境といっても、昨今では実機を使わずにクロスアセンブラとエミュレータを使ってモダン OS 上で作業することが多いようです。しかし下記のような自作ハードウェア(拡張カード)の対応ソフトウェアを開発する場合は、エミュレータ上で完結するわけにはいきません。

基本的にはモダン OS(Win/Mac/Linux)上でコーディングを進めつつ、ビルド毎にバイナリを Apple II 実機に送って実行、テストを繰り返す作業が必要です。モダン OS と Apple II 実機を往復する一連の操作がスムーズに行えるハイブリッドな環境が求められますが、この際に役立つツールが Apple II Pi(David Schmenk 氏作)です。

Apple II Pi は Apple II と Raspberry Pi をシリアル回線で接続して双方の機能を融合するシステムで、シリアルインターフェイスまわりのハードウェアと Apple II / Raspberry Pi 双方のソフトウェアで構成されます。ハイブリッドな Apple II 開発環境の構築という観点からは、Apple II Pi 仮想ストレージを使ったファイルのやり取りが中心的な機能となります。また Apple II コンソールを Linux 端末から操作する機能(a2term)も便利です。

この投稿では Apple II Pi を中心にして VSCode エディタなども利用し、モダン OS(ここでは Mac を使用)から Raspberry Pi と Apple II を操作することで Apple II のリモート開発環境を構築する方法を検討します。なおターゲットの実機には Apple IIe / ProDOS を使用します。

リモート開発環境の基本構成

開発環境の全体構成を下図に示します。

Raspberry Pi の構成

上図に示したように多くのツールが Raspberry Pi 上に配置されます。主なツールについて以下に説明します。

Apple II Pi は シリアル通信カード、Apple IIe 側の a2pi ソフトウェア、Raspberry Pi 側の a2pid ソフトウェアおよび個別のコマンドツールから構成され、2 つのシステムを連携するいくつかのサービスを提供します。

Apple II Pi が提供する最も重要なサービスが仮想ドライブです。Raspberry Pi 上に保存されるディスクイメージファイルに基づき、Apple IIe から見ると Apple II Pi カードが刺さっているスロットに 2 つのブロックデバイスが現れます。

a2term も a2pid が提供するサービス(を利用したアプリケーション)です。a2term は Raspberry Pi 上で実行される通信ソフトウェアですが、接続先は Apple IIe の ProDOS コンソールであり ProDOS や Applesoft Basic のセッションが Raspberry Pi 端末上で利用できます。

CC65/CA65 は 6502 用 C コンパイラ / アセンブラです。開発は主にこれらの言語を使って行います。なお Applesoft Basic も開発用言語として使用できます。

AppleCommander ツールは仮想ドライブボリュームの実体である Raspberry Pi 上の *.po ディスクイメージファイルに対して、Basic プログラムや CC65/CA65 で作成した Apple II 実行ファイルを読み書きするために使います。

Apple IIe の構成

Apple IIe は Apple II Pi 専用の ProDOS ディスク A2PI-1.7.PO から起動します。このディスクは通常通り S6, D1 から読み込んで ProDOS を起動しますが、その際に a2pi ソフトウェアを ProDOS システムに常駐させます。

a2pi ソフトウェアは Apple II Pi カードのシリアル通信を管理すると同時に、Apple II Pi カードが刺さっているカードスロット(例えばスロット #2)上で D1、D2 の 2 つの仮想フロッピードライブをエミュレートします。またコンソールやジョイスティックの状態もシリアル通信経由で Raspberry Pi へ送ります。

PC(Win/Mac/Linux)の構成

Mac(または他の適当な Win/Linux PC)は必須ではありませんが、Raspberry Pi との間を SSH 接続して VSCode Remote Development を実行することにより PC のデスクトップ環境で Apple II プログラミングが行なえます。a2term を VSCode Remote Development 内の端末パネルで起動すれば、Apple II ProDOS コンソールを PC 画面上に持ってくることもできます。Mac 上の VSCode からプロジェクトを編集、実行している様子が本稿冒頭の画面です。

リモート開発環境での操作

プログラムの作成・実行の手順はおおむね次のようになります。各手順は Raspberry Pi に対する操作です。

  1. C(CC65)、アセンブラ(CA65)、Applesoft Basic を使って Apple II プログラムを記述します。Basic プログラムはテキストファイルとして記述できます。
  2. CC65/CA65 ソースコードを Apple II 用実行バイナリファイルにコンパイル(アセンブル)します。バイナリファイルは Raspberry Pi のファイルシステム上に保存されます。
  3. AppleCommander ツールを使ってバイナリファイルを *.po ディスクイメージに書き込みます。Basic ソーステキストファイルを Basic トークン形式に変換して書き込むことも可能です。
  4. 作成した *.po ディスクイメージファイルを a2pid の仮想ドライブとしてマウントします。作成したプログラムが Apple IIe からアクセスできるようになります。
  5. a2term を使って Apple IIe 上で RUN ないし BRUN コマンドを実行します。

サンプルプログラムの実行

上記の操作手順をみれば想像がつくと思いますが、Makefile やシェルスクリプトなどを組み合わせれば一連の過程をほぼ完全に自動化できます。ターゲット環境の選択(実機か、エミュレータか)など複雑な操作を行おうとすると多少工夫が必要になりますが、少なくともビルドと実行を繰り返す作業は比較的容易に自動化、省力化できます。次の動画では 3 種類の言語による HelloWorld プログラムをビルドし、Apple IIe 実機に送って実行する操作を Makefile とシェルスクリプトを使って自動化しています。

本稿では個々のツールの設定詳細に触れませんでした。今後個別に検討しようと思います。

Beneath Apple DOS and Beneath Apple ProDOS 2020

表題の本を Lulu から購入しました。1981 年刊の “Beneath Apple DOS”、1984 年刊 “Beneath Apple ProDOS” の 2 冊の Apple II 解説本を合本にしたもので、なんと今年(2020)の 9 月に刊行されています。Lulu はオンデマンド出版なので損益分岐点は低いとはいえ、Apple II のレトロコンピューティング人口が相当見込まれているものと想像します。表紙イラストのコンピュータは Apple II というより iMac っぽい?

気になっていた ReadPulse の模式図(Figure 3.3)は修正されていない模様。これは比較的誤解を招きやすい部分だと思います。

実際の ReadPulse 周期は 4us(上図の “msec” は誤植)で、図中で “CLOCK BITS” と呼ばれている要素は存在しません。

こういった誤植的なものも含め、歴史の一部ということでしょうか。

しかしこれは重箱の隅的な話で、本書により Apple DOS/ProDOS について網羅的に学べることには違いありません。本書の内容は DOS データ構造やそれを操作するシステムプログラミングの解説に重心が置かれています。ハードウェアレベルでの詳細について知るには、“Understanding the Apple II” という別の本をあわせて参照するのがいいと思います。

Booti Card(1)Apple IIe で使う

Booti_open

2 月に注文した Booti Card が 5 月になってようやく到着しました。Covid-19 ロックダウンの影響で製造・流通ともに遅れ、2/13 注文の品が到着したのは 5/2 です。しかし世界的な混乱の中、中国(PCB 製造)-> オーストラリア(設計・組立)-> コロラド(CT6502)-> カリフォルニア(私の住所)という長旅を経てきたので仕方ないところです。

Booti Card は Apple II シリーズ用の USB メモリストレージデバイスです。Apple IIe のスロット 7 に挿すとそのまま ProDOS ブートデバイスとして機能します。ブロックモードと Smartport モードで動作しますが、ゆくゆくは Apple III 上で運用したいので当面ブロックモードを中心に機能を確認します。

Booti_slot7

まずこちらのデモにも出てくる Total Replay 2MG イメージを試します。.2MG イメージを USB メモリにコピーして起動、コンフィギュレーション画面を立ち上げて .2MG イメージをドライブ 1 として指定します。

Booti_config

システム起動すると “Apple ][” スプラッシュ画面から 1 秒で Total Replay の起動画面が出ます。これは速い。ソリッドステート化の効果に加え、ドライバが相当最適化されているのではないでしょうか。

Booti_trply

次は昨年リリースされた ProDOS 2.5a8 を試します。開発元サイトでダウンロードできるイメージの拡張子は *.dsk なのですが、これでは起動しませんでした。AppleCommander を使って空の *.po イメージファイルを作り、そこへ ProDOS2.5a8 に含まれる全ファイルをコピーすると動きました。(変換ツールもあるそうです。後から知りました。)

ProDOS 2.5 はフロッピー起動だと 8 秒程度要するところ、Booti Card では約 2 秒でロードされます。これくらいだと体感では電源投入後即 ProDOS が使用可能になる感じです。

Booti_Bitsy

その他の機能として、Booti Card は ADTPro の仮想ドライブ VSDrive もサポートします。つまり起動ディスクに VSDrive プログラムを入れなくても、SSC シリアルポート経由で ADTPro ホストマシンが接続されていれば VDrive1/VDrive2 ボリュームが認識され、Booti Card スロット上のドライブとして指定できます。上に示したコンフィギュレーション画面では ADTPro が提供するボリューム(VDSSC2.VD1/VDSSC2.VD2)が認識されています。将来的には A2Cloud と組み合わせて使えないかと考えています。

Apple IIe 上での Booti Card の動作確認(ブロックモードのみ)はこれくらいにしておきます。次は Apple III での運用を検討します。

6502 と 6800 の減算時キャリーフラグの挙動の違い

わかる方はタイトルを見ただけでピンとくるでしょうし、この 2 つのプロセッサを使っていなかった方にとっては「何それ?」な話です。私はここしばらく 6502 と 6800 のアセンブラを並行して使っていたにもかかわらず、先日までぼんやりとしか把握していませんでした。

キャリーフラグと減算命令 SBC(SuBtract with Carry)に関する話題です。

2 バイト長以上の値同士で減算を行う場合、6502 や 6800 では 1 バイトずつ計算していきます。最下位バイト同士はただ引き算をすればいいのですが、2 桁目から上は下位バイトの減算結果で「繰り下がり=借り」が発生しているかどうかを考慮する必要があります。小学校で習う 10 進引き算の筆算と同じ手順です。この「借り」の有無込みで減算を行う命令が SBC 命令です。ニモニックは 6502 と 6800 で共通です。

この SBC 減算処理の際に、直前の演算(下位バイトの減算)で借りが発生したかどうかを表すキャリーフラグ値の意味が 6502 と 6800 では逆になるのです。

そんな基本的な仕様が逆だなんて? でもそうなんです。次のようになっています。

  • 借りが発生しているとき:6502 ではキャリーフラグが ‘0’、6800 ではキャリーフラグが ‘1’
  • 借りが発生していないとき:6502 ではキャリーフラグが ‘1’、6800 ではキャリーフラグが ‘0’

実際に確かめてみましょう。次の計算を行うプログラムをこれら 2 つのプロセッサで実行します。

計算内容 A

  1. アキュムレータに $10 を代入
  2. キャリーフラグを 0 にする
  3. SBC 命令でゼロをアキュムレータから引く。つまり $10 -(キャリー=0)- 0

計算内容 B

  1. アキュムレータに $10 を代入
  2. キャリーフラグを 1 にする
  3. SBC 命令でゼロをアキュムレータから引く。つまり $10 -(キャリー=1)- 0

6502 の計算は、Apple II のミニアセンブラとディスアセンブラを使用してプログラムを作成し、モニタコマンドで実行しました。6800 の計算は、Motorola アセンブラ as0 でアセンブルした内容を SBC6800 上で実行し、Mikbug の swi ルーチンを使って結果を表示しました。

計算内容 A:$10 -(キャリー=0)- 0

6502:

(アセンブルリストと実行結果)

a2-clc-sbc

6800:

(アセンブルリスト)

m68-clc-sbc0-src

(実行結果)

m68-clc-sbc0-res

  • 6502 の結果 : $0F -> 1 引かれている
    • 「キャリー=0」にすると直前の演算で「借り」があるとみなされる
  • 6800 の結果:$10 -> 変化なし
    • 「キャリー=0」にすると直前の演算で「借り」がないとみなされる

計算内容 B:$10 -(キャリー=1)- 0

6502:

(アセンブルリストと実行結果)

a2-sec-sbc0

6800:

(アセンブルリスト)

m68-sec-sbc0-src

(実行結果)m68-sec-sbc0-res

  • 6502 の結果 : $10 -> 変化なし
    • 「キャリー=1」にすると直前の演算で「借り」がないとみなされる
  • 6800 の結果:$0F -> 1 引かれている
    • 「キャリー=1」にすると直前の演算で「借り」があるとみなされる

確かに、6502 と 6800 では逆の挙動になります。

この結果を踏まえ、今度は「計算後に借りが発生する」減算を実行してキャリーフラグの変化を見てみます。

計算内容 C

  1. アキュムレータに 0 を代入
  2. キャリーフラグを「借りなし」の状態にする。つまり 6502 ではキャリー=1、6800 ではキャリー=0 にする
  3. SBC 命令でアキュムレータから 1 を引く

6502:

(アセンブルリストと実行結果)

a2-sec-sbc1

6800:

(アセンブルリスト)

m68-clc-sbc1-src

(実行結果)m68-clc-sbc1-res

  • 6502 の結果 :
    • アキュムレータ:$FF
    • キャリー(PSR—上記プログラムでは X に保存—の LSB): 0 に変化
    • つまり借り発生(キャリー=0)が記録される
  • 6800 の結果 :
    • アキュムレータ:$FF
    • キャリー(CCR の LSB): 1 に変化
    • つまり借り発生(キャリー=1)が記録される

と、この計算でもキャリーフラグの内容は 6502 と 6800 で逆の動きを見せることがわかります。

***

「基礎となる考え方は共通なのに、アーキテクチャの都合で仕様が逆になる」というのは、エンディアン問題に通じるところがあります。

6800 の挙動のほうが直感的にわかりやすい気もしますが、一方で、私が昔 6502 アセンブラについて読んだ解説では

「減算のとき C フラグはボローフラグとして機能する。ボローフラグの表現は(加算時の)キャリーフラグとは逆で、0 が “ボローあり”、1 が “ボローなし”」

という内容だったと記憶しています。これはこれで筋の通った説明です(実際には、減算時にプロセッサ内部処理で必要になる 2 の補数計算の短縮が目的のようです)。

この挙動のため、6502 で借りを含まない減算を行う時は、SBC 命令の実行前に必ず SEC 命令でキャリーをセットするように、と教えられます。また Compare 系の命令(CMP、CPX、CPY)でも、キャリーフラグに保存される比較結果はボローフラグ的な挙動になるため、注意が必要です。

当時そんなふうに習って以来、最近になるまでアセンブラに触れていなかったので、キャリーとボローの関係はどのプロセッサでもこういうものだ、と長年思い込んでいました。先ほど 6502、6800 双方でコードを実行して違いを確認し、ちょっとした衝撃を受けた次第です。

注:こちらのページ(この種の話題について事典のように詳しい)に、整理された解説があります:
http://www.st.rim.or.jp/~nkomatsu/miscproc/MCS6502.html
注 2:キャリーとボローの扱いについては ARM が 6502 と同じ流儀のようです:
https://en.wikipedia.org/wiki/Carry_flag