FUZIXをビルドしてみよう

 FUZIXというプロジェクトをご存じでしょうか。Linuxのバージョンが2.2〜2.4の時代にメンテナーとして有名だったAlan Cox氏による、主に8bitのパソコンで動かすUNIXライクな環境です。もちろんRaspberry PiみたいなGUI環境を想像したらガッカリするとは思いますが、それでもCP/Mとも違うもっと高度なOSの出現にはワクワクさせられます。

 そもそもはDoug Braun氏によるUZI(Unix: Z80 Implementation)というプロジェクトが発端でした。明らかに無茶な試みなんですが惹かれるものがあったのでしょうね、Braun氏自身の手によるUZI280(当時の次世代Z80であるZ280用)の他にも、H. Bower氏によるUZI180(HD64180/Z80180用)や、MSX用に移植されたUZIX(本家/日本語)、さらにそれをシャープMZ-800に移植したuMZixと、なかなかの広がりを見せています。

 そこに現れたのがCox氏によるFUZIXです。名称に含まれるZの文字はZ80のZだったはずなのですが、対象を6502や6809・68000・ARMに広げるなどマルチプラットフォームという顔を持つようになりました。GitHubでの公開によりコントリビューターも増えてきて、さらにはCox氏の経歴を考えれば将来はすごいシステムに化けるのではなかろうかと淡い期待を抱かずにはいられません。

 2014年秋の第一報以来私もずっと気になっていたのですが、ふとその気になって一通りビルドだけは試してみることにしました。参考にしたのは「Running Alan Cox’s Fuzix OS on a Z80 emulator」というブログ記事で、仮想環境で動かせるようCP/Mシミュレータを流用したものです。ただこのブログ記事は2年以上前のもので、やってみるといろいろと不具合がありましたので順番に解決していく必要がありました(当時は必要でも今は不要なものもありましたが)。そんなわけで、備忘録を兼ねて2017年4月現在のビルド方法についてメモしていこうと思います。

環境

 Ubuntu16.04を使用しました。Windows環境でも不可能ではないと思いますが、Cygwinその他「ちょっと変わった環境」でトラブルになるのも面倒だったので、素直にLinuxにて試すことにしました。

 ビルドにあたって以下のパッケージが必要です。

SDCCのインストール

 FUZIXがZ80用にCソースをコンパイルする前提となっているSDCCを導入します。10年ほど前でしたか使ってみた個人的な印象では、ループ変数の演算がちょっと複雑になるとコードが出力されなかったりあまり良い思い出がなかったりしたのですが、今はC99やC11も受け付けられるモダンなコンパイラに変貌しているようです。

 ブログ記事では必要な機能を使うためにスナップショット版をインストールしていましたが、現在のFUZIXのソースではさらに機能が必要になっていますので、素直にstable版(3.6.0)をダウンロードしておきます。

>tar xjvf sdcc-src-3.6.0.tar.bz2
>cd sdcc-3.6.0
>./configure --prefix=/usr --disable-pic14-port --disable-pic16-port
>make
>sudo make install

 PIC14やPIC16以外にdisableにしておくアーキテクチャがあってもいいとは思いますが…。

z80packのインストール

 CP/Mシミュレータを含むz80packを導入します。最新バージョンは1.34にまで上がってますが、若干仕様が変わっているようで画面が乱れたりすることから、ブログ記事と同様の1.24版を利用します。

>wget http://www.autometer.de/unix4fun/z80pack/ftp/z80pack-1.24.tgz
>tar xzvf z80pack-1.24.tgz
>cd z80pack-1.24/cpmsim/srcsim
>make -f Makefile.linux
>cd ../srctools
>make

ユーティリティのコンパイル

 いよいよ本題のFUZIXのビルドです。まずはユーティリティをコンパイルします。後で起動ディスクを作る際に利用されるプログラムが含まれています。

>git clone https://github.com/EtchedPixels/FUZIX.git
>cd FUZIX/Standalone
>make

カーネルのコンパイル

 カーネルをコンパイルします。プラットフォームに合わせた修正が必要です。

>cd ../Kernel
>(Makefileとdevtty.cを編集)
>make

 Makefileですが、開いてみるとターゲットを定義する行がコメントアウトされた上で多数並んでいるのがわかると思います。これを必要な行だけが有効になるようにするわけです。

FUZIX/Kernel/Makefile
export TARGET = coco2cart
 ↓
#export TARGET = coco2cart
FUZIX/Kernel/Makefile
#export TARGET = z80pack
 ↓
export TARGET = z80pack

 もうひとつ、FUZIX/Kernel/dev/z80pack/devtty.cを編集します。tty_writeready関数の戻り値の型がおかしいのを修正するわけです。

FUZIX/Kernel/dev/z80pack/devtty.c
char tty_writeready(uint8_t minor)
 ↓
ttyready_t tty_writeready(uint8_t minor)

 これでエラーなくコンパイルできるはずです。

クロス開発用ツールのコンパイル

 まだ(ずっと?)FUZIXではセルフコンパイルができませんので、アプリ開発のためにはクロス開発環境を整える必要があります。SDCCをUNIXライクな環境に合わせるためのラッパーとしてfccというものが用意されており、これをコンパイルします。

>cd ../Library
>make
>sudo make install

 これで/optとそれ以下のディレクトリが作成され、/opt/fcc/binと/opt/fcc/includeに必要なファイルが転送されます。

ライブラリのコンパイル

 今度はライブラリです。

>cd libs
>(Makefileを編集)
>make
>sudo make install

 ライブラリはfccでコンパイルする必要があるのですが、今さっきインストールしたばっかりでPATHにも追加してませんから、コンパイルに失敗するのは明白です。ということで手っ取り早くMakefileを変更することにします。

FUZIX/Library/libs/Makefile
CC = fcc
 ↓
CC = /opt/fcc/bin/fcc

 これでクロス開発環境が整いました。

ディスクイメージの作成

 コマンド類をコンパイルして、CP/Mシミュレータで動作させるためのディスクイメージを作成します。もちろん必要に応じてfccが使われるのですが、Makefileでは/opt/fcc以下にインストールされたものではなく先ほどコンパイルしたバイナリが指定されています。ブログ記事ではインストールを手動で行うしかなかったみたいなので、その当時のものがまだ残ってるんですかね?

>cd ../Applications/util
>make

 コンパイルができたら、イメージ作成のスクリプトを走らせます。ちゃんと走れば瞬く間に必要なディスクイメージが出来上がるのですが、スクリプトに問題があって少々編集が必要です。

>cd ../../Kernel/platform-z80pack
>(createdrivesを編集)
>./createdrives

 まず、現状のプロジェクトには含まれていないプログラムが含まれていますので、それをリストから削除します。

FUZIX/Kernel/platform-z80pack/createdrives
DISK2BINS="banner basename bd cal chgrp chmod chown cksum cmp cut date dd decomp16 dirname dosread du echo ed false fgrep fsck grep head id init ll logname man mkfs mkfifo more mv od pagesize passwd patchcpm printenv prtroot pwd sleep sort stty sum su sync tee tail touch tr true umount uniq uud uue wc which who whoami write xargs sed yes"
 ↓
DISK2BINS="banner basename bd cal chgrp chmod chown cksum cmp cut date dd decomp16 dirname dosread du echo ed false fgrep fsck grep head id init ll logname man mkfs mkfifo more mv od pagesize passwd printenv prtroot pwd sleep sort stty sum su sync tee tail touch tr true umount uniq uud uue wc which who whoami write xargs sed yes"

わかりにくいですが…patchcpmというのがなくなってるのです。いつの間に消えたんでしょうね?

 次に、$UCPとあるディスクイメージを編集する行の"&> /dev/null"を消します。複数行ありますが、全てこんな感じで。

FUZIX/Kernel/platform-z80pack/createdrives
$UCP $DISK1 "mkdir $DIR" &> /dev/null
 ↓
$UCP $DISK1 "mkdir $DIR"

メッセージやエラーをnullに吐き出して表示を静かにさせたいのでしょうが、スクリプトの実行結果を見るとエラーが出たり出なかったり、メッセージが出たり出なかったりで、出来上がってディスクイメージの内容もボロボロでした。デバッグがしたくて"&> /dev/null"を消したのですが、なんとそれだけで正常に動作するようになり…。「よくわからないが、こうしたら動いた」という気持ち悪い結果になったのですが、まぁ動けば正義か、と…。

FUZIXを動かす!

 いよいよFUZIXを起動させます。先ほど作成したディスクイメージを所定のディレクトリにコピーして、シミュレータを実行するのです。

>cp drivea.cpm drivei.cpm ~/z80pack-1.24/cpmsim/disks
>cd ~/z80pack-1.24/cpmsim
>./cpmsim

 先ほど作成したディスクイメージというのは、drivea.cpmがカーネルの入った起動ドライブでフロッピーディスクのイメージ、drivei.cpmが/usrなどの収められたハードディスクのイメージだそうです。起動するとこんな画面になります。

bootdevというプロンプトには0と入力します。するとinitが実行され、シングルユーザーモードかな? コマンドプロンプトが出てきます。/usrをマウントしてちょっと使ってみたのがこちら。

 ssh#というプロンプトは、secure shellじゃなくてsimple shellらしいですね。あとinittabがないと言われてますが一般的な/etc/inittabを探しに行っており、適切に記述したinittabを用意したらもう少し環境が良くなるんじゃないかと思います(runlevelが変わるとか)。

 そろそろ察しが付いてきた頃かと思いますが、CP/Mシミュレータと言いつつ、CP/Mのファンクションコールを仮想的に実装するのではなく素のZ80マシンのシミュレータを動かしているだけなんですね。だからCP/Mではないシステムを起動させることができるわけで…やろうと思えばS-OSだって搭載可能なのでしょう。

 しかしアレですね…CP/MシミュレータなのにRAMが480KBもあるんだ…ああ、CP/M3にも対応するシミュレータだからか…。

ソフトウェアの開発

 何も手をつけていませんのでほとんど当てずっぽうですが、FUZIX用アプリケーションは基本的にクロス開発で、SDCCではなくfccを用いることになります。/opt/fcc/binをPATHに加えておけばいいんでしょうね。

 問題は出来上がったプログラムをFUZIXにて使えるようにする、具体的にはディスクイメージに書き込む方法です。そのためにucpというユーティリティが用意されていて、先ほどもディスクイメージを作る際スクリプトから呼び出されていました。使い方は

ucp ディスクイメージのファイル コマンド

で、コマンドの指定に空白が含まれる場合はダブルクォーテーションでくくり、複数の処理はセミコロンで区切ることで指定できます。またパイプでつなげば複数行にわたってコマンドを記述することができます(その場合はucpに対してコマンドを書かない)。どんなコマンドが使えるかはucpのソースを見て下さい。プログラムやデータをディスクイメージに書き込むにはbgetコマンドを使えばいいようです(FUZIX/Kernel/platfome-z80pack/createdrivesを見て下さい)。

ポーティングについて

 シミュレータで動かしてるだけじゃなくて、やはり扱い慣れたレトロPCで動かしたいと思いますよね。FUZIX/Kernelを見ると多くのCPUと多くのプラットフォームに対してポーティングされているらしいことがわかります。ここら辺をあちこち見比べながら移植の方針を考えることになるのでしょう。

 例えばz80packとmsx1を比べてみても、同じZ80ではあってもメモリマップに差異があって、しかもZ80用のはリロケータブルではないそうなので、プログラムをバイナリの状態では融通できないことになります。あくまでソース互換ということにして、CPUが違うマシンに移植したのと同然であると割り切った方がいいのでしょうね。むしろこれは移植を「やりたいようにやる」ってことで構わないのだと考えることにしましょう。

 ではぼちぼカーネルを眺めてみるか…。

戻る