【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

コマンドライン版インタプリタ

id:n7shi:20110408で開発したSilverlight版のPDP-11インタプリタですが、ブラウザから出してコマンドラインで動かなければ、実用には厳しいと感じました。そのためC++で書き直して、Win32とPOSIXに対応しました。Win32はMinGWPOSIXは Interix 3.5, NetBSD 5.1, FreeBSD 8.1-R での動作を確認しています。他のOSでは多少の修正が必要になるかもしれません。

Lions' Commentary on UNIX 読書会 Part 006 に間に合わせようと突貫で開発したため、一部のシステムコールしかサポートしていません。現段階ではUNIX V6カーネルのビルドが可能です。

インストール方法

最初にインタプリタ本体(v6run)をビルドします。ソースをMercurialでcloneするか、ダウンロードページの Tags & snapshots から 0.2-20110412 を選択してください。(Uploaded files については後で説明します)

ソースを展開して make install としてください(WindowsではMinGW Shellを使用)。デフォルトでは /usr/local/bin にインストールされますが、変更するにはMakefileのPREFIXを書き換えてください。

$ hg clone https://bitbucket.org/7shi/v6run
$ cd v6run
$ make install

BSD系のOSではgmakeを使用してください。

V6バイナリの配置

v6runはPDP-11の命令をインタプリタで実行して、UNIX V6のシステムコールをネイティブのシステムコールに変換するだけのプログラムです。そのため何か作業するには別途V6のバイナリが必要となります。

開発環境一式をダウンロードページの Uploaded files で配布しています。

  • v6root-20110412.tar.xz

これをMakefileのV6ROOTで指定したパスに展開します。デフォルトでは /usr/local/v6root です。

$ tar xvJf v6root-20110412.tar.xz -C /usr/local

※tarがxzに未対応の場合、gtarを使用してください。

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

動作確認

簡単なプログラムで動作確認を行います。

次のソースを作成してください。simhの外での作業ですから、edを使う必要はありません。任意のエディタを使用可能です。

hello.c
main()
{
    printf("hello\n");
}

コンパイルして動作を確認します。

$ v6cc hello.c
$ v6run a.out
hello

a.outがPDP-11バイナリであることを確認します。

$ file a.out
a.out: PDP-11 executable

【注】Windowsでは、改行コードがCR+LFのままだと以下のようにエラーとなります。LFをサポートしたエディタを使用してください。

$ v6cc hello.c
1: Unknown character
2: Unknown character
3: Unknown character
4: Unknown character

オプション

デバッグ用にトレース機能が利用できます。引数なしでコマンドを起動するとオプションが表示されます。

$ v6run
usage: v6run [-r V6ROOT] [-v/-s] cmd [args ...]
    -v: verbose mode (output syscall and disassemble)
    -s: syscall mode (output syscall)

すべての命令を逆アセンブルしながら動作を確認するには -v オプションを使用します。

$ v6run -v a.out
0000,0000,0000,0000,0000,0000,sp=fff6,pc=0000: setd
0000,0000,0000,0000,0000,0000,sp=fff6,pc=0002: mov sp, r0
fff6,0000,0000,0000,0000,0000,sp=fff6,pc=0004: mov (r0), -(sp)
fff6,0000,0000,0000,0000,0000,sp=fff4,pc=0006: tst (r0)+
(以下略)

システムコールだけを表示するには -s オプションを使用します。

$ v6run -s a.out
0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys indir; 02a8
0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys write; 02c0; 0001
h0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys indir; 02a8
0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys write; 02c0; 0001
e0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys indir; 02a8
0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys write; 02c0; 0001
l0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys indir; 02a8
0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys write; 02c0; 0001
l0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys indir; 02a8
0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys write; 02c0; 0001
o0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys indir; 02a8
0001,0000,0000,0000,ffea,ff5a,sp=ff58,pc=022a: sys write; 02c0; 0001

0000,ffea,0000,0000,0000,fff0,sp=fff0,pc=0252: sys exit

上の例で表示がずれている部分があるのは、writeシステムコールによって文字が表示されているためです。このようにprintf()では一文字ずつ表示していることが分かります。

カーネルのビルド

カーネルをビルドしてみます。オリジナルのV6ではビルド用にrunというシェルスクリプトが用意されていますが、これは現在のシェルスクリプトとは少し仕様が異なるため、そのままでは使用することができません。

そのためMakefileを追加したソース一式を用意しました。ダウンロードページの Uploaded files で配布しています。Makefileを追加した以外の変更はありません。ソースはオリジナルのままです。

  • v6sys-20110411.tar.xz

これを展開してビルドします。

$ tar xvJf v6sys-20110411.tar.xz
$ cd v6sys-20110411
$ make

※tarがxzに未対応の場合、gtarを使用してください。

成功すれば、以下の3つのカーネルが生成されます。それぞれコンフィグが異なるカーネルです。

  • hpunix
  • rkunix
  • rpunix

どのようにコマンドを呼び出しているかはMakefileを参照してください。もともとあったシェルスクリプト(run)を直訳したもののため、Makefileとしては格好悪いスタイルです。気持ち悪い方は各自修正してみてください。