第一章 6809を動かしてみよう
専門的すぎますが、とりあえず備忘録ですね。
NEO MANHATTANの開発は、最初から「OS-9とCP/Mを統合した巨大なシステムを作ろう」と始まったわけではなかった。
もっと単純な興味からだった。
『Windowsの上で、6809のプログラムを動かしてみたい。』
そこが出発点だった。
FM-7、FM-8、FM-11。
1980年代の富士通製パーソナルコンピュータには、Motorola 6809が使われていた。6809は8ビットCPUに分類されるが、その設計思想は当時としてはかなり洗練されていた。
究極の8ビットCPUなどと、ASCII誌で宣伝されていたが、大学1年の私には、なにが凄いのか分からなかった。友人が日立のベーシックマスターレベル3を買って、色々自慢していたが、高額すぎて私には買えないのである。
PC-8001はかなり普及していたが、いまいちであった。インターフェース誌の記事を読み、コピーしたりしていた。
MC6809はZ80と違いアセンブラーがきれいだった。
A、B二つの8ビットアキュムレータがあるが、2つ合わせると16ビットのDレジスタになる。
X、Y二本のインデックスレジスタ、そしてUレジスタとSレジスターという、スタックが2つ使える。まあこれは、1つだけで済むのではと思ったが、インデックスレジスターとして使えるから、便利だろうとしか思えなかったが、Uレジスターの裏業でスピードアップに貢献した。
PCもあり、DPレジスタを使えれば、任意の256バイト単位のアドレスが、短縮された高速にアクセス出来るDPアドレスと使えるのだ。
このように、6800系の改良と言うか、延長線上にあるといっても、ミニコンのCPU張りの事が出来そうなCPUだったのである。
しかし、当時の私には、そんなことはどうでも良かったのである。
友人が、OS-9との組み合わせると、VAX-11並みだと言って興奮していたが、そんなことは関係なかった。
私は1980年日本橋の関東電子のお店で、家庭用TVアダプターと一緒にFM-8を予約した。そして、入荷したときは本当に嬉しく、重いデザイン箱をかかえて、うちに帰ったものであった。
モニターはシャープの14インチカラーTVだったが、色がにじんでひどかったので、白黒TVにつないでいた。
BASICプログラムは、簡単な技術計算のプログラムがかけたので、書いてみて、感動したものである。
サイン波のプログラムを書いたりして、楽しんだ。
そういうなつかしい思い出がある。
FM-7などのエミュレーターは既にあるので、2000年頃に古い5インチフロッピーやFM77AVで使っていた、3.5インチフロッピーなどはいくつか吸い出して、ハードディスクにあり、それなりに使えるのだが、他人の作ったプログラムには、どうしてもなじめない物があった。
自前の6809エミュレーターで好きかってしたいのである。幸いFM-11シミュレーターはMIYAZAKI氏が作ったものがあり、これはソースをいじって色々改造したこともあるので、これを参考に6809コードを読んで実行するプログラムを作りたくなった。
《 1 CPUを作る》
幸い、マイクロソフトの開発環境は無料配布である。これで、古いスタイルのCなら私も書けるのである。C++でMIYAZAKI氏は書いているが、これはよくわからんのである。
というわけで、古いスタイルのANSI-Cで書こうと開始した。
エミュレータの仕事は、ある意味では単純である。
メモリから命令を一つ読む。
命令を解釈する。
レジスタを変更する。
必要ならメモリを読み書きする。
そして次の命令へ進む。
たとえば、
$86 $01
なら、
LDA #$01
である。
Aレジスタへ1を入れる。
それだけなら簡単だ。
しかし6809には、数多くの命令とアドレッシングモードがある。同じLDAでも、
LDA #$01
LDA <$20
LDA $1000
LDA ,X
LDA 5,X
LDA [10,X]
では意味がまったく違う。
とりわけ6809のインデックスアドレッシングは強力で、そのぶんエミュレータ側の実装は複雑になる。
5ビットオフセット。
8ビットオフセット。
16ビットオフセット。
Aレジスタオフセット。
Bレジスタオフセット。
Dレジスタオフセット。
オートインクリメント。
オートデクリメント。
プログラムカウンター相対。
そして、間接指定というのがある。
一つひとつを実装していかなければならない。
このあたりは、FM-8でディスアセンブラを作った経験があるので、
1バイト読み出し、
ざーっと
switch(op){
case 0x12:return 1; /* NOP */
case 0x13:return 1; /* SYNC treated as NOP in minimal environment */
case 0x16:{short r=(short)fetch16(cpu);cpu->pc=(unsigned short)(cpu->pc+r);return 1;}
}
こんな感じで書いていく。
でディスアセンブラとの違いは、レジスターのレジスタ値をかえたり、配列で用意した、メモリが書き換わる。
そしてCCレジスタのビットをいじり、プログラムカウンターを進める。
例えば、プログラムカウンターの内容をSPレジスタが指し示すところにしまって、スタックであるSPを2減らし、オペランドの内容から求められた結果をPCプログラムカウンタに入れる。これがサブルーチンジャンプである。
プログラムカウンタにスタックの指し示す内容を戻し、スタックポインタを二上げると、リターンである。
この雑なコード列が、次第に「プログラムの動作」に見えてくる。
小人さんがレジスタ棚の内容を移したりしてる姿が思い浮かぶ。これはCPUエミュレータ開発の面白い瞬間である。
そして、CPUという建物の内部で小人さんが棚の中をいじっている感じが、あるところを越えると、CPUが小人になり、別の誰かが書いた数十年前のプログラムが動き始める。プログラムの動きが小人さんたちの働きに見える。
ある程度動いたところで、現代の究極の助っ人登場である。
ANSICに詳しい、という性格付けをした、CHATGpT君である。これにコードを送り検証して貰う。
動作範囲限定のCPUで、未だ未実装というところが大量にあるのだが、実装部分については検査が出来た。ついでに大量の提案を頂く。
動く範囲のテスト用コードを配列に入れて、実行。上手く動いているようだ。
GPT君が改良したがっているので、改良して貰う。あっという間に未実装部分の大半が出来てしまった。生成AIは凄い。
《 2 止めなければ見えない》
プログラムが動き始めると、次の問題が起きた。
『何をしているのか分からない。』
スコープ範囲が小さな、単純なテストプログラムならよい。頭の中で十分わかる。
しかし実際の6809プログラムを動かそうとすると、数百、数千、あるいはそれ以上の命令が実行される。
どこで間違ったのか。フラグの立て方を忘れたのかな。
どこで予想と違う分岐をしたのか。
どの命令でレジスタが壊れたのか。
画面だけを眺めていても分からない。
そこで必要になったのが、デバッガだった。
最初は簡単だった。
コード$3FというSWIを置く。オペコードを読んで、$3Fを読み出したら、
レジスタを表示して停止する。いわゆるブレークポイントだ。
どの6809デバッガでも、SWIを使っている。
プログラムカウンターを見る。前後のメモリの内容を見る。
これだけでもずいぶん違う。プログラムの途中へSWIを埋め込み、
「ここまでは来た」
「ここから先がおかしい」
と調べていくのだ。
昔のマシンでモニタプログラムを使っていた経験が生きるが、マシンコード表をいちいち見るのはめんどくさい。
停止した場所のアドレス表示やSWIが格納したレジスタ一の表だけでは足りない。
『今、どんな命令の上で止まっているのか。』
それを知りたくなる。というわけで、
《 3 逆アセンブラを載せよう》
ということになった。元々ディスアセンブラ的な解釈機構で作っていたから、コメント欄にオペランドが書いてある、今読んでいるところのニーモニックを表示するのは簡単な改造で出来る。こうしてCPUエミュレーターに、逆アセンブラ表示が加わった。
つまり、メモリ上の、
$8E $20 $00
を、
LDX #$2000
と表示する。
$BD $E8 $34
なら、
JSR $E834
と表示する。
分かりやすい、実行速度は遅くはなるが、これはメリットの方が大きい。
また、プログラムカウンターが示す周辺を逆アセンブルすれば、
xxxx LDX #$2000
xxxx LDA ,X+
xxxx BEQ xxxx
xxxx JSR xxxx
などと処理の流れが見える。ついでにレジスタの変化も見たいからと、レジスタ内容の表示を横に入れる。
このレジスタ値と命令列を同時に見れば、プログラムが何をしようとしているのか推測できる。ついでにCCフラグもばらして見えるようにする。
単なる6809エミュレータから、6809用のトレーサーへと、遅くはなるが進化した。
この逆アセンブラは後に、後々、OS-9プログラムやManhattan関連モジュールを追いかけるための「目」になるのである。
《 4 6809ではない命令》
予想されていたことだが、手元にあるOS9の古いプログラムを調べ始めると、妙な命令に出会うことがある。
6809の命令表にはない。実装していない。大抵はバグでデータを読んでいるのだが、しかし、明らかにコードとして存在しているものもある。未定義命令。
原因の一つが、6309だった。私のFMシリーズは63C09に換装してあるので、この機械語命令もとおるのだ。
日立HD63C09は、6809との高い互換性を持ちながら、追加レジスタや追加命令を備えたCPUである。3MHZ以上で動作するので、FM-11ではサブCPUを4MHz化した人も多数いた。私の場合場合は3MHzにしたが。FM77AVなどはクロックアップが出来なかったので、そのままであるが、プリフェッチをONにすると、1.5倍程度速くなった。
と言うわけで、私の持っている当時のソフトウェアには、6309の命令を利用しているものも存在した。
そうなると、単に、
Unsupported opcode
と出して停止するだけでは不十分になる。
「これは壊れたコードなのか?」
「未実装の6809命令なのか?」
「6309命令なのか?」
を区別したくなる。
どうせなら6309命令も動けば良いのだ。
すぐに完全な6309エミュレーションを実装するわけではない。大体公式マニュアルもない、今は無きUNOさんが書いた記事がOH!FMに載っているだけである。
しかし、
「ここには6809以外の命令がある」
と分かるだけでも、解析の意味は大きく違う。
NEO MANHATTANの開発には、後々までこの考え方が繰り返し現れる。
未知のものに遭遇したとき、無理に処理を続けるのではなく、
「何が起きたのかを見えるようにする」ことが重要だった。
《 5 SWI2 はシステムコール 》
そして、ある命令の存在が、開発の方向を大きく変える。
『SWI2』
6809には、SWIのほかにSWI2、SWI3というソフトウェア割り込み命令がある。普通の6809プログラムを動かすだけなら、ひとまず後回しにすることもできる。だがOS-9では違った。SWI2は、OS-9のシステムコールを呼び出すために使われる。
たとえばプログラム中に、
SWI2
FCB F$xxxx
のような命令列があれば、それはOS-9カーネルへの要求である。
ファイルを開く。
プロセスを作る。
メモリを確保する。
時刻を読む。
デバイスへアクセスする。
OS-9プログラムは、SWI2を通じてOSのサービスを受ける。
つまり、SWI2をただの停止命令か、それとも、
『OS-9のシステムコールとして実装するのか。』
ということである。
この選択で、エミュレータの未来はまったく違うものになる。
もしSWI2を実装し、内容を吟味すれば、OS-9用に書かれたプログラムを、Windows上で直接動かせるかもしれない。単なるCPUエミュレーションではない。
OS-9のプログラム環境そのものを再現できる可能性がある。
幸い、マニュアルも解説書も沢山有る。
よし。OS9のシステムコールをとりあえず実装すれば便利かな?ということである。
《6 OS-9という世界》
OS-9は、単純なディスクOSではない。マイクロウエア社がBasic09を作ったとき、専用のOSとして、当時のUNIXを手本に作ったOSである。
プリエンプティブ・マルチタスクで動くことを前提としてつくっており、64KB以下のLevel1と64KB以上使えるLevel2がある。FM-11はLevel2を意識して作られたマシンだ。
UNIX的な構造で、標準入力、標準出力、標準エラー出力があり、構造的には
UNIX以上の改良が成されている。
このOSシステムはパソコンにウイルスを作ろうする人間が存在しなかった時代に、性善説的にモジュール化されている。
モジュールはリビジョンなどで管理され、この数値の大きいものが使われる。つまり後で上書き差し替え可能なのである。
秀和のOS9関連の解説書や、富士通のマニュアルを引っ張り出し、久しぶりに読んでみた。
この、OS-9プログラムを動かすということは、単にSWI2の命令を処理すればよいという話ではなかった。このSWI2の向こう側には、一つのこのOS世界が存在しているのだ。しかしその時点では、まだ全容は見えていなかった。
OS9をそのまま動かすなら、既にあるパソコン用のエミュレーターで十分なのだ。
こっちの、システムコールは、CPUエミュレータに付いた形で、6809コードのものを利用しないことにした。つまり、SWI2を見つけたら、そこでWindows側のプログラムが介入し、必要な結果を返すのである。
まず試しにコンソール関係のシステムコールを実装してみた。
次にもう一つ。恐る恐るOS9用のプログラムを動かすと、これが少し先まで進む。すると、また別の必要なシステムコールが現れる。それを実装する。さらに進む。それの繰り返しである。
今度はファイルアクセスが必要になる。ではOS-9のRBFを読まなければならない。
プログラムが端末へ文字を出そうとする。端末処理が必要になる。
別のプログラムを起動しようとする。モジュール管理が必要になる。
一つ扉を開けるたびに、その向こうに次の部屋が現れた。
この時点では、まだ気づいていなかったが、その先に無限の世界が開けていた。
RBF /Term モジュールディレクトリ シェル。
大変だ!これはもう知力体力の弱った老体には手には負えない、助っ人が必要である。ChatGPT君に任せることにした。
現在のソースコードを貼り付け、目的をチャットで入れる。GPT君ネットを検索してなかなか凄いことにGitHubなどを調査対象に調べまくってくれるのである。
そのうちに改良した差し替えのソースコードを提示してくれた。古いANSI-Cのソースであったが、それに合わせて書いてくれている。一気に完成度が上がった。
そして、Z80も動かそうねということで、マンハッタンシステムを入れようと言うことになった。
Z80のシミュレーターも今度は面倒なので初めからGPT君につくってもらって、FM11に準じた数バイトのマンハッタンのハードのエミュレーションを入れてもらい、OS9の古いイメージから、マンハッタンシステム関連のソフトをいれると、Helloが動くではないか!!
Welcome to Manhattan
が出たときにはもう完成かと喜んだ。
CP/M関係はもとのマンハッタンのソフトがあるので、そのまま使おうと決めた。CP/MのツールはFM-8で使っていたし、FM-11でも使っていた。
《 7 マンハッタンって》
FM-11には、かつてManhattan Systemという環境があった。Forksという会社が作ったものだ。
FM-11にアプリカードというZ80Bの載った専用カードが必要だが、OS9上でCP/Mのソフトを統合的に使おうというシステムである。
まあ、FM-11には純正のZ80カードもあるのだが、これは切り替えて使わなければならないし、ハードはあまりよく分からない。
しかし、このシステムは、CP/Mプログラムから発生する要求をOS-9側へ渡し、OS-9のサービスとして処理する。そうして、CP/MプログラムをOS9のファイル管理システムで扱えるようにするのである。
これは、私が惚れ込んで、会社で買ってFM7/X1/PC88の三機種同時開発を実現させた便利システムである。
pOS9:シェードOS9
pCPM: シェードCP/M
ApIf:アプリケーションインターフェース
ApDv: アプリケーションデバイス
Foster2:CP/M起動用のDiceコマンドを作ってくれるソフト
云々...
マニュアルや解説書がばっちり手元にあり、紹介記事も全部取ってある。
それらを再び実現できるのではないか。これらは残念ながら、件のFM-11シミュレーターでは動かない。
もし私の6809エミュレータがOS-9プログラムを実行できるなら、そしてZ80エミュレータも組み込めるなら、このManhattanの仕組みを、Windows上で再構築できるのではないか。
さらに、FM-11実機をそのまま再現するだけでなく、現代の環境だからこそできる拡張を加えられるのではないか。
複数ウインドウ。Windowsファイルとの交換。デバッグ機能。仮想ディスク。
複数CPU。より柔軟なモジュール管理。
当時のハードウェア制約から解放された、新しいManhattan。当時は1枚78000円もしたものが、4枚フル実装できる。
そして、CP/M的なものはこの上で実現できるとすれば、CP/M68KやCP/M86も手元にあるので、同等に実現可能だ。ここで初めて、6809エミュレータの先にあるものが、ぼんやりと巨大な形を持ち始める。それに、ChatGPT君の実力も既に確かめ、なかなか使えることもわかった。
《 8 ネオマンハッタンと呼ぼう》
最初はテストプログラムだった。次に6809エミュレータになった。デバッガが付き、逆アセンブラが付き、SWI2の実装からOS-9用のプログラムを動かせることが分かった。Z80のエミュレーターをFM-11の標準では無く、Manhattan System形式で入れると、すぐに動いてしまった。
もう単なるCPUエミュレータプログラムとは呼べない。
昔のManhattanが持っていた、
『異なるCPUと異なるOSを、一つの環境の中で協調させる』
という思想を受け継ぐ。別個のエミュレーターが別々に使われるのではなく、統合された上で、新しい機能が加わった、便利な謎のPCエミュレーション実行環境である。
このプログラムには、いみじくもChatGPT君が仮に名付けた。
『NEO MANHATTAN』
新しいマンハッタン。Welcome というプログラムを走らせると、911で倒壊した世界貿易センタービルを含むデザインの絵が描かれるのである。
もっとも、その名前が示すほどの機能は、まだ何も完成していなかった。
6809は動く。いくつかのプログラムも動く。デバッガもある。しかしOS-9は、まだ入口に立っただけだった。SWI2の向こうには、巨大な世界がある。
そして、その世界へ入るためには、
「OS-9とは何か」
を、もう一度最初から理解しなければならなかった。そして、ChatGPT君に説明しなければならないのだ。
---
その最初の壁が、システムコールだった。先に書いたが、いろいろ買ってあった、解説書を紐解き、当時生半可で理解していた知識を再確認する。
40年の年月と経験が当時には分からなかったことを教えてくれていた。
命令としてのSWI2を実装するだけでは足りない。
レジスタに何を渡すのか。
エラーはどう返るのか。
プロセスはどう管理されるのか。
パス番号とは何か。
OS-9のプログラムは、OSに何を期待しているのか。
NEO MANHATTANはここから、CPUエミュレータではなく、
『OSを実装する側』
へ踏み込んでいくことになる。
次に作るものは、もう決まっていた。
『SWI2を、システムコールを本当に動かす。』
ことである。
次章 『 第二章 SWI2――OS-9への入口 』へ続く。
Uレジスターはスタックス操作でいっぺんに複数のレジスターのロードセーブとレジスタ自体のインクリメントデクリメントが出来るので、余っていたら以下のようなことをしました。
*
* hput(x,y,buf,flg)
*
* 01 23 45 67 89 ab
* U PC x y adr flg
*
* ttl hput
hput:
pshs u,y
ldb 9,s ;read Y position
lda #80
mul ;
addd 6,s ;x*2+y adr
addd 6,s ; vram address at Dreg
std 6,s ;
ldy #$fc81 ;put address
ldu 10,s ;pattern adress
lbsr shalt ;reserve all register
lda 13,s
anda #7
sta ,y+ ;$fc81
ldd 6,s
std ,y++
cmpu INIFLG,PCR
beq hput2
stu INIFLG,PCR
ldb #4
pshs b
hput1 pulu d,x ;Hi-speed Copy 87/03/11
std ,y
stx 2,y
pulu d,x
std 4,y
stx 6,y
pulu d,x
std 8,y
stx 10,y
leay 12,y
dec ,s
bne hput1
leas 1,s
hput2 lbsr sready
puls y,u,pc
*
*




