以下のような技術的興味から、PC-8001エミュレータをクライアントサーバーモデルで実装してみました。

(1) WebGLとAjaxで、サーバーから受け取ったデータを描画して60fps出せるか。
(2) キー入力から画面描画までのレイテンシはどれくらいか。
(3) AWS(Amazon Web Services)を使ってみたいが、手頃な題材はないか。

幸い、PC-8001のVRAMはわずか3000バイトしかなく、60fpsで全部送っても180kB/s、差分だけ送るなどすれば十分実現性があると考えました。
初めはVRAMデータは毎回全部転送、キー入力なしで作りました。
まずクライアント側です。
サーバーからのデータはヘッダにwidthコマンドの結果を入れておき、初期化時と変更があった場合だけ頂点座標を作ります。
あとは毎回、VRAMの内容からテキストアトリビュートの処理をしながら頂点カラー、テクスチャ座標を生成し、シェーダーで描画します。
次にサーバー側です。
DVD-Video/DVD-VRの動画ファイルをクリップ単位で観るでは、Apacheモジュールを作りましたが、今回はCGIにします。
Z80エミュレータのCocoa8001のソースを切り出して、クライアントに画面情報を送る機能を追加すれば出来上がりです。
とりあえずローカルサーバーで試すとちゃんとN-BASICが起動しました。
Safari上に出ているN-BASICのプロンプトを見てちょっとにんまり。
キー入力の処理をクライアントとサーバーに追加して、転送データを差分だけに変更して出来上がりです。

さて、いよいよAWSに持っていきます。
まずAWSのアカウントを取得しました。クレジットカード番号と着信できる電話番号が必要です。
次にEC2 Management Consoleでt2.microインスタンスを作ります。
このとき、右上のタブでTokyoリージョンを選んでおきます。
最初に作ったときラグがひどいので、そういえばリージョンを選んでないということに気づきました(Oregonになってました)。
OSはAmazon Linuxを選び、セキュリティ設定でSSHをMy IP(現在アクセスしているIPアドレスからのみ受け入れ)にし、HTTPを開ける以外はデフォルトで作りました。
インスタンスを起動したら、
local$ ssh -i pemファイル ec2-user@グローバルIP
のようにしてログイン、
$ sudo yum install httpd24
でApache2.4をインストール、
/etc/httpd/conf/httpd.confのAddHandler cgi-script .cgiのコメントを外してから
$ sudo service httpd start
で起動します。次回以降はインスタンススタート時に起動するように
$ sudo chkconfig httpd on
しておきます。
local$ scp -i pemファイル pc8001server.tar.bz2 ec2-user@グローバルIP:~
のようにファイルを送り、
$ cd /var/www
$ sudo chown ec2-user.ec2-user cgi-bin www
$ tar xvfj ~/pc8001server.tar.bz2
とします。
アーカイブにはROMイメージが含まれません。別途入手し、pc8001.romという名前でcgi-binディレクトリに配置してください。
準備ができたら、ブラウザでグローバルIPにアクセスすればインデックスページが出ます。
そこからプログラムなしかサンプルプログラム実行か選ぶと、ブラウザ上でPC-8001が再現されます。
サンプルプログラムは私が30年前(!)にナムコのラリーXにインスパイア(笑)されて作ったオールマシン語(懐かしい当時の表現)のゲームです。
cmtファイルも読めるので、お持ちの方は試してみてください。

ところで、ローカルサーバーでは大丈夫だったのにAWSで出た不具合がありました。
しばらく走らせると画面が崩れるのです。
TCPだしデータ化けは考えにくいです。
調べた結果、CGIで明示的にfflush()した場合以外に、途中でクライアントに送信されることがあるためと分かりました。 考えてみれば当たり前のことです。
そこで、データがどこで中断しても大丈夫なようにクライアントを書き換え、安定しました。

download(pc8001server.tar.bz2)

download(pc8001server_src.tar.bz2)

OS XではSafari,Chrome,FireFoxを試し、どれも大丈夫でした。
WindowsではIE,Chrome,FireFoxを試し、IE以外は大丈夫でした。

実装してみた結果、例えばモニタ(mon)のメモリダンプ画面では60fps程度出ることがわかりました。
キー入力から画面反映までも、東京のサーバーなら気になるラグはありませんでした。

WebSocket版

download(html.tar.bz2)

download(pc8001server_ws.tar.bz2)

同じ機能を、libwebsocketsを使って実現しました。
まず準備として、AWSにlibwebsocketsをビルドするのに必要なものをインストールします。
$ sudo yum install zlib-devel openssl-devel cmake
次に、http://git.libwebsockets.org/cgi-bin/cgit/libwebsockets/からlibwebsockets-1.5-chrome47-firefox41.tar.gzを落としてきて、
展開した中のREADME.build.mdを読んでビルド、インストールします。
デフォルトでは/usr/local/下にインストールされるので、共有ライブラリをリンクできるように
$ sudo ldconfig /usr/local/lib
しておきます。
最後にpc8001server_ws.tar.bz2を展開し、
$ make
$ sudo make install
することで/usr/local/bin/にインストールされます。pc8001.romを同じディレクトリに配置します。
html.tar.bz2は展開して/var/www/下に配置します。
あと、/etc/rc.d/rc.localの最後に
(cd /usr/local/bin/; ./pc8001server &)
と書いて、起動時に実行されるようにします。


さて、ソースだけでなく、サーバーを公開しようと思ったのですが、一つ問題があります。
AWSの無料時間は750時間(2015年3月現在)で、常時稼働では1ヶ月ほどで終わってしまいます。
無料サーバーを探してみましたが、PerlなどではなくC++で、クライアントが接続している間じゅう走り続けるようなCGIが使えるところは見つかりませんでした。
そこで、このページからリクエストしたときにインスタンスを起動する仕組みを作りました。
このサイトはCGIが使えないので、別途無料サーバーに飛んで、そこでリクエスト状態を保持します。
それを毎分ポーリングし、リクエストが来ていたらAWSコマンドラインインターフェースを使ってインスタンスを起動します。
起動したら10分で停止、その後しばらくは起動しないようにしておくことで、無料時間をすぐに使い果たすことがないようにしました。
この処理は常時走らせるので、電気代がほとんどかからないRaspberry Piでやっています。

下のリンクをクリックして1〜2分待つと、PC-8001サーバーにつながります。10分間使えますのでお試しください。
すぐにつながった場合はすでに誰かが起動しているので10分経たずに切れます。

PC-8001エミュレーションサーバーを試してみる(外部のサーバーに飛びます)公開を終了しました

サンプルプログラムのキー操作:
デモ中にreturnキーを押し続けるとスタート、テンキーの2468が方向、スペースがスモッグです。
キーが効かない場合はフォーカスが外れているので一度画面部分をクリックしてください。