Quantcast
Channel: 熱血挑戦者のブログ
Viewing all 107 articles
Browse latest View live

CPU実験と東大理情のカリキュラム

$
0
0

15erの熱血です。この記事では東大理情のカリキュラムが(CPU実験から見ると)良くできていると思った話を軽く書きます。僕が個人的に続けてきた講義感想録の続きでもあります。

どちらかと言うとISの方はもう充分ご存知の内容だと思います。想定読者層は進振り前の前期教養1,2年生です。

最終更新: 2015/Dec/02




東大理情(IS)のカリキュラムがどういう風になっているかは、たとえば学科紹介パンフレットの図を見ると分かります。この図では各講義の連続性が分かりやすく表示されているのですが、正直僕はこの連続性がいかに具体的なものであるかを学部2年夏の進振り前にあまり分かっていませんでした。だからCPU実験をやりながら感じたカリキュラムの一貫性について書きます。

CPU実験では単にFPGA上にCPUを作るだけでなく、OCamlというプログラミング言語のsubsetであるところのmin-caml言語の自作アーキテクチャ向けコンパイラを作ったり、三角関数などの数値計算を要する関数を自前実装したり、自作アーキテクチャのシミュレータを作ったり、I/Oまわりやアセンブラなどを更に作ったりと、色々とすることがあります。大体4人くらいの班でこれらのジョブを各人に割り振って(コア係、コンパイラ係、シミュレータ係、FPu係)、自前アーキテクチャを作ることになります。

そんなことを今すぐ「やれ」と言われてもできないので、ISのカリキュラムでは段階的にこれらの技術を学べます。




2年後期には「ハードウェア構成法」という講義があります。先生が変わっていなければこれは小林先生の講義だと思います。なかなかディープな講義です。そして、3年生になってから「今受けたい」と言う人も多いほど、前提知識が少ない人には苦しい講義だとも思います。ISのハードウェア系の講義だと一番物理層・物性に近いことを習った講義でもありました。

また2年後期には「計算機システム」という、コンピュータの物理的な仕組みからアプリケーションレイヤーでの仕組みまで、コンピュータがどのように動いているのかを網羅的に扱う講義もあります。こちらも前提知識が少ない人には多少苦しい講義になりますが、逆に言うとここで叩きこまれておくと後が楽です。

この「ハードウェア構成法」と「計算機システム」は、そのまま3年前期の「ハードウェア実験」と「計算機構成法」という講義に内容が直結しています。

「ハードウェア実験」は実際にデジタル素子を使った電気回路実験から始まります。これは電気回路の特性を知るための前準備みたいなもので、本番はその後のFPGA実習にあります。FPGAとは自分でデジタル回路をプログラムできる電気回路のことで、HDL(ハードウェア記述言語)と呼ばれるプログラミング言語で仕様を決定し、そこからデジタル回路を合成してFPGAに書き込むことで回路を作り、その特性を調べるといった実験が可能になります。「ハードウェア実験」ではFPGAを使って、いくつかのデジタル回路を作ることになります。ここで作る回路はそのままCPU実験の基本となるような回路ばかりです。つまりこの講義はCPU実験に直結していると言えます。

「計算機構成法」では「計算機システム」では深堀されなかったCPUの仕組みについて詳細に語られます。ぶっちゃけるとカリキュラム的にはこの講義が無いとCPUを作るのは厳しいでしょう。というわけでこの講義もCPU実験に直結します。自習したい人はいわゆる「パタヘネ」「ヘネパタ」という本があるにはあります。この講義を担当なさっているhrk先生がもうすぐご退官予定のため、もしかすると後数年でこの講義の性質が変わるのかもしれません。でもそんなこと言うとCPU実験そのものの存続さえ危ぶまれてしまうので特に考えないこととします。


2年後期には他にも「アルゴリズムとデータ構造」という名が体を表す講義があります。アルゴリズムとはコンピュータで計算をするための一種の決まりきったやり方のことです。そしてデータ構造とは、計算するためのアルゴリズムを簡単にするための技法と言ってもさほど間違いではないでしょう。この講義で習うこれらの概念はソフトウェア的な意味での情報科学全ての基礎になっていると言っても過言ではありません。そういう意味で、この講義は3年後期の「連続系アルゴリズム」に弱く接続しています。

3年後期の「連続系アルゴリズム」ではいわゆる「数値計算」と呼ばれる分野を網羅的に扱います。浮動小数点数計算の誤差についての議論から始まって、数値微分・数値積分や補完多項式などの話題があります。僕ははじめこの講義はCPU実験に関係ないと思っていたのですが、関係あります。CPU実験でレイトレするために数値計算が必要なのです。FPU係の人やコンパイラ係の人(ライブラリを書く人)は特に関係するでしょう。


コンパイラ係がコンパイラを書くための知識は、2年後期「形式言語理論」、3年前期「言語処理系論」および「関数・論理型プログラミング実験」の知識が使われます。抽象的な意味での(形式的、数学的な意味での)「言語」を扱う「形式言語理論」の知識の一部が「言語処理系論」で必要になります。「言語処理系論」では人間が書いたプログラムのソースコードをコンパイラが扱いやすい形にする字句解析・構文解析の知識から始まり、それらを元に機械語を生成するための様々な手法について学びます。実際に「関数・論理型プログラミング実験」の方ではインタプリタを作ったりもします。これらの知識と、CPU実験(コンパイラ実験)で習う手法を元にコンパイラを書くことになります。

「言語処理系論」の話をしたのでついでに話しておくと、コンパイラの最適化技術は「言語処理系論」で習うものでは少し足りないので、それらをある意味補ってくれているのが3年前期「離散数学」「離散数学演習」であったり3年後期の「計算量理論」「計算量演習」であったりすると考えることもできます。「離散数学」で習うグラフ理論の基礎や線形計画問題の扱い方は最適化のための手法として有効です。コンパイラで扱う問題にはNP困難な問題が結構あるので、「計算量理論」で習う近似アルゴリズムの話も多少関係してくる所でしょう。


ここまでシミュレータについて触れてきませんでしたが、じゃあシミュレータ係は楽なの?と言われると、一概にはそうも言えません。CPUのシミュレータを書くためにはそもそもそのアーキテクチャの仕様についての理解が必要なので、ハードウェアの知識が必要です。またCPU実験で使うレイトレーシングのプログラムは普通に動かしてもそれなりに時間がかかるものなので、シミュレータの高速化には開発速度を高めるという充分な意味があります。高速化のためには2年後期「システムプログラミング実験」で習うような手法や、そもそも一般の実験で必要とされるようなプログラミング技術を持っているべきでしょう。また、Out of Orderという実装をコア係がする場合は、CPUの1クロックごとのシミュレーションをするCycle Accurateなシミュレータがあると便利なのですが、この実装はコアを1つ実装するのと同じくらい大変です。




ISの講義はここで紹介した以外にも存在します。それらの講義はCPU実験と直接的な関わりは無いかもしれません。でもたとえば14erの方々の中には自作アーキテクチャの上にOSを実装した班があったりと、余興の方にそういった知識は用いることができます。自前計算機を作るんですから何でもできますね。

というわけで、以上ISのカリキュラムを追いながら、どういった知識がCPU実験で必要で、活用されているのかを書きました。ISに来ようか迷っている方や、ISじゃないけどCPU実験をしてみたい方の参考になれば幸いです。

.ocamlinit

$
0
0
CPU実験 Advent Calendar 2015の記事です。今回は短い。

最終更新: 2015/Dec/06

コンパイラのデバッグに役立つかもしれないOCaml情報なのですが.ocamlinitが便利です。

カレントディレクトリもしくはホームディレクトリに.ocamlinitがある場合、ocamlコマンドでOCamlトップレベルが立ち上がる際に.ocamlinitの中身が読み込まれます。

なので、.ocamlinitの中で#loadや#use、#mod_use、#load_recなどをするようにしておくと、新しい最適化用関数をデバッグするときにとても便利です。一時的によく使うデバッグ用関数とかを.ocamlinitでletしておくのも便利です。

より詳しい話は http://caml.inria.fr/pub/docs/manual-ocaml/toplevel.htmlなんかを参考にどうぞ。日本語マニュアルはちょっと古いことと、英語版マニュアルを見るときも最新ページでないページを見ている可能性があるので更新日時に注意してください。

-initオプションで.ocamlinit以外のファイルをロードすることも可能です。また細かいことですが僕がひっかかったので書いておくと、トップレベルを立ち上げる意味でocamlコマンドを使うのではなく、スクリプトモード(ocamlコマンドの引数に.mlファイルを与えてトップレベルで実行させて結果を出力させるモード)でocamlコマンドを使うとどうも.ocamlinitや-initが効いていないっぽい(OCaml 4.02.3時点)ので注意です(仕様なのかバグなのか不明)。

デバッグするときに-initオプションだとかocamlmktopだとか試したのですが、僕的には.ocamlinitが一番使いやすかったので紹介しました。ではー。

CPU実験: ライブラリのバグを晒す

$
0
0

僕はコンパイラ係をしています。コンパイラ係関係の仕事の1つとして「ライブラリを書く」というものがあります。具体的に言うと、I/O系の命令や三角関数などの関数を、アセンブリやmin-caml言語などで書くことになります。

この記事では、僕がコンパイラを書くにあたって遭遇したライブラリのバグについて書きつつ、1stコンパイラのデバッグにかけた期間のラスト1週間がどんな感じだったのか書きます。多少記憶が前後しているかもしれませんがそこらへんはご愛嬌ということで。

最終更新: 2015/Dec/08




☆ライブラリがすべからくバグっていた

僕はライブラリ関数をアセンブリで書いたのですが、眠たい眠たい言いながら睡眠前にちょっとずつ書いていたのが悪かったのでした。至る所buggyなライブラリは「コンパイラはちゃんとraytracerをコンパイルできているし、出力されたアセンブリも合法に見えるし、シミュレータ上でも正常に終了して画像を出力するのに、何かがおかしい」という状況を生み出しました。

市民、睡眠は義務です。眠たいときは寝ましょう。

もうどのライブラリがどのようにバグっていたのかはいちいち覚えていませんが、それぞれのライブラリ関数がどのような出力を吐くのか調べるために適当な入力のもとでグラフを書いた画像が残っていたので、これを貼ってお茶を濁します。

はじめにバグっていることが発覚したライブラリはcosでした(11月9日)。

イメージ 1


どうみてもcosのグラフですね。間違いない。

多少手を加えると下のグラフのようになりました。タイトルがsinとなっていますがcosです。

イメージ 2


このとき調子に載って同時にatanをプロットしたら痛い目に遭いました。

イメージ 3


まあこれはすぐに直りました。




☆画像だなあ

11月10日にmandelbrotが動いたので、そのままの勢いでraytracerを動かしました。

イメージ 8


綺麗なtron.ppmですね。




☆三角関数だけじゃなかった

floorもバグっていました(11月10日)。floorは何も考えずに実装しているとバグを生むので注意してください。

イメージ 4


床関数(穴だらけ)。

このあたりのコンパイラデバッグ期間はつらかったです。ライブラリに限らず無限にバグが生まれていて悲しかった。しかもその9割は僕の不注意による非本質的な、typoなどのバグだったのでしょんぼり。

コアが既に完成していて、実機でも先ほどのレイトレース画像と同じ世紀末的画像が出力されることが再現されていたので、焦りがありました。

11月13日、floor, i2f, f2iなどのライブラリ関数がきちんと動くようになりました。




☆三角関数ふたたび

このあたりからFPU係の人がデバッグを手伝ってくれるようになりました(11月14日)。cos/sinの誤差を全数調査したところ、さっきのグラフではうまくいっているように見えるものの、実は無茶苦茶誤差っていることが分かりました。

イメージ 5


なんか角が生えていますね。誤差だけ表示してみましょう。

イメージ 6


グラフだと分かりにくいのですが、pi/4周期で誤差が大きくなっています。cosの実装上どこが誤差を生んでいるかはすぐに分かったので後はひたすら自分の書いたバグアセンブリを読みました。




☆うごいた

ライブラリを直して、CPU実験のレギュレーションを満たしていることを全て確認してもまだ動きませんでした。emit.mlを何回も読み直しました。バグを見つけてコミットしました。

そうしたら動きました(11月16日)。

イメージ 7


最後に見つけたコンパイラのバグは、1箇所だけ浮動小数点数レジスタ移動命令fmovのsourceレジスタとdestinationレジスタの向きが逆になっているというものでした。

同じ日に実機でも完動しdiffは0で狭義完動となりました。

おしまい。




教訓: 眠いときは寝る。ISAを100回読む。

CPU実験の浮動小数点数演算について

$
0
0

読者層として3年の夏休み頃のIS 16erを想定して書かれています。

この記事では、CPU実験で動かすことになるraytracer/min-rt.mlの中で必要な浮動小数点数周りの演算についての軽い解説を行います。解説しなくてもその内分かるかとは思いますが、一応記録のためです。

以下の記事では2015年度のCPU実験のルールを元にした記述がたくさんあります。ルールが変わっているかもしれないので注意してください。

最終更新日: 2015年12月11日




浮動小数点数演算について見る前に、IEEE 754 単精度浮動小数点数について復習します。

IEEE 754 単精度浮動小数点数は、32bitで実数を近似的に表現するための規格で、符号部1bit, 指数部8bit, 仮数部23bitからなります。

指数部は127を0とするオフセット付きの表現になっており、また、仮数部はけち表現(1.xxx...のxxx...しか保存しない表現)をすることによって1bit節約されています。

単精度で表現できる通常の実数(正規化数)の他に、±inf, NaN, 非正規化数があります。また0には2種類(+0と-0)あります。

ここらへんについて怪しい方は是非今の内に"Wikipedia - IEEE 754"生の規格(東大内だとpdfで落とせます)を読んでおいてください。以下では上の知識は既知とします。




「浮動小数点数演算」と言いましたがこれは曖昧で、実際に実装するときには「ハードウェア実装する浮動小数点数演算」「コンパイラのライブラリ関数としてソフトウェア実装する浮動小数点数演算」「min-caml言語として実装する浮動小数点数演算」の3種類があります。これらの演算をFPU係やコンパイラ係が実装することになります。

どこまでの演算をどの分類にするかは、班のISA(命令セットアーキテクチャ)やコンパイラ・ライブラリの仕様によります。どのような設計にするとより高速にレイトレーシングが実行できるか、などを目標にこれらを定めることになります。

この記事の目標は、必要な演算について適当な解説をして、1st アーキテクチャの設計前になるべくクリアなイメージを持ってもらうことにあります。

では、どのような演算が必要になるのか列挙していきます。




加算命令faddと乗算命令fmulは、全ての班が1st アーキテクチャでハードウェア実装することになるでしょう。おそらくハードウェア実験でfaddの実装はしたことになっているでしょう。まだしていない人はFPU係として実装することになります。faddの実装にはハードウェア構成法の方の小林先生の著書である『ディジタル・ハードウェア設計の基礎と実践』が多いに参考になるでしょう。地下に数冊あるので是非読んでみて下さい。faddのC実装がちゃんとできているかどうかは綿密にチェックしましょう。14erのb-inaryさんが作られたverify.cが参考になるかもしれません(14er wiki/ハードウェア実験にあります)。ただし安全のためにはもっと標本数を増やすべきです。faddが実装できればfmulの実装は容易にできるでしょう。2004年に書かれた神FPU資料のfmul実装は古いです。16erの皆さんが扱う基盤がリニューアルされたものなら、他の部分の記述も古いものになってしまっているかもしれないので注意が必要です。

faddのC実装はある程度真面目に作っておく必要があります。というのも、CPU実験の狭義完動条件が「シミュレータの出力と実機の出力のdiffが0」なので、シミュレータに組み込まれたfaddの実装が雑だとVHDL実装とのdiffが出てしまいます。

NaNや非正規化数などにどこまで対応するかどうかは、CPU実験のレギュレーションやraytracer/min-rt.mlの中で行われる演算と相談しながら行うことになります。レイトレーシングに満足せずもっと豊富なことをしたいのであれば実装しても良いでしょう。はじめは面倒くさいし実装していなくていいんじゃないかあと思います。実際にレイトレでNaNや非正規化数が現れるのかどうかは、コンパイラ、アセンブラ、シミュレータ完成後にシミュレータで確認することはできます。本当にCPU実験のレギュレーションかちかちで作るのであれば、丸めの計算をroundingをnearest evenなどといったものでなくもっとサボることもできるらしいのですが、僕は実際に実装していないので分かりません。速さを求めるのであれば神FPU資料なども参考に研究することになります。ただしfaddの誤差をサボると三角関数などのソフトウェア実装した関数で誤差が大きくなって困ることになるかもしれないので加減が必要です。

VHDL実装をパイプライン方式で行ったとして、66MHzでfaddが3 clock、fmulが2 clockで終わればとりあえずは大丈夫です。ただしその内クロックを上げることになるので、それに対応することになるでしょう。また、うまく丸め計算をサボるともう少し高速化することもできるようです。13er grafiさんの記事には2パス加算器の話が載っています(ヘネパタにアイディアが載っているらしい。こちらも参考になる)。




加算命令と乗算命令があるなら減算命令fsubと除算命令fdivも欲しくなる所ですが、もしISAをなるべく小さくしたいのであればこれらはとりあえず必要ありません。代わりに正負反転命令fnegと逆数命令finvが必要です。

fnegの実装は簡単です。finvの実装はNewton-Raphson法を用いるか、線形近似の値を保存しておくテーブルを用意しておいて、テーブル引きを使って値を求める方法の2種類に分かれます(他の方法もあるのかもしれませんが知りません)。

Newton-Raphson法で実装する場合"Wikipedia:en - Division algorithm"が参考になります。テーブル引きで実装する場合は神FPU資料が参考になるでしょう。finvには大体2 clockかかります。ただし分散RAMを使って1 clockで終わらせる実装も発見されていて、こちらはハードウェア資源との相談になります。

テーブル引きの誤差を減らす方法はよく知りません。FPU係の誰かが記事にしてくれるかも?




コンパイラとしてmin-camlをそのまま使うなら、浮動小数点関係の中間表現としてあらかじめ存在するものはFMov, FNeg, FAdd, FSub, FMul, FDiv, LdF, StF, IfFEq, IfFLEの10個です。楽をするなら1stではこの10個さえできればOKです。FSubはfaddとfnegで表現できます。fdivは実はx/yをx * (1/y)と最適化するのは正しくない(たとえばx=y=0)のですが、CPU実験のレギュレーション的にはOKなので大丈夫です。

僕の班の場合、1stが完動した後にシミュレータを使ってraytracer/min-rt.mlでの色んな命令の出現頻度を測った所fsubが結構多かったので2ndではfsubを命令セットに加えることにしました。fdivは今の所入れていません。ここらへんは各班で色々画策して決めることになるかと思います。

LdF, StFはGPR/FPR(整数レジスタと浮動小数点数レジスタ)を分けている班は用意する必要のある命令です。分けていない班は中間表現ごと消して大丈夫(なはず)。面白命令入れたい班の人はx87の定数ロード命令などいかがでしょうか(速くなるかどうかは知りません)。役に立たなさそうな面白命令として、上位/下位n bitだけが即値オペランドで指定できる浮動小数点数ロード命令とか(無いところは0埋め)。

fmovはGPR/FPR分けてる班なら有ると思うのでOKかと思います。ちなみに凄い細かい話をすると"fmov x to y"を"y = fadd 0.0 x"で実装するのは間違いです。xが-0.0のときを考えて下さい。

浮動小数点数によるブランチ命令は最低限equalとless than (もしくはless than or equal to)があれば大丈夫です。いや待てよ、本当に最小の命令セットにするならequalも不要ですね(ニッコリ)。コンパイラに優しいのはeq, neq, lt, leq全部あるパターンかな?




平方根命令fsqrtの計算はfinvと同じくNewton-Raphson法かテーブル引きを使うでしょう。ここらへんからハードウェア実装するかソフトウェア実装するかが分かれてくると思います。

面白命令として、高速に平方根の逆数を求めるfast InvSqrtというのが知られています。特にfsqrtをソフトウェア実装している場合「平方根の逆数を求めてから乗除算に使う」という方法で高速化の可能性があります。計算には有名なマジックナンバーがあるので参考になるかも。ただし誤差がちゃんとレギュレーションを満たすように注意してください。1 iterationでは満たさないと思います。




三角関数のsin/cosは入力xの値によって誤差が大きくなるので、適当に誤差の小さい区間に帰着させてあとはマクローリン展開(をちょっと弄ったもの)によって計算するという方法が神FPU資料に載っています。また、15erには自力で色々試してみている人もいたようです。

sin/cosは1stではソフトウェア実装の人が多かった印象です。レイトレーシングではそんなに呼ばれない[要出典]ということもありハードウェア実装のメリットがそんなに無い班も多いです。自分たちの班のISAと相談することになります。

sin/cosが出来上がったら誤差をulpでちゃんと表示してあげることをオススメします(参考)。もしかすると、たとえばsinでx=nπの周辺において誤差が大きくなっているかもしれませんが、実はそれはCPU実験のレギュレーション内です。しっかりレギュレーションを確認すると、定数cというとても1に近い数が設定されていることに気づきます。このcの意味に気づけば、cを含んだ意味でcos/sinがレギュレーションを満たしていることを全数探索できます。

あ、そうそう、連続系アルゴリズムの講義で習うかとは思いますが、級数の計算はHorner法でやると良いです。

tanもレイトレの中で使われていますが、raytracer/min-rt.mlの中身でtan = sin/cosと定義されてしまっています。ただしCPU実験のレギュレーションにより、勝手に別のものに置き換えても良いことになっています。

atanもsin/cos同様にマクローリン展開で計算できます。僕はほとんど神FPU資料に従ってしまったのであまり詳しいことは分かりません……。




浮動小数点数と整数の変換命令としてint_of_float(ftoi, f2i)とfloat_of_int(itof, i2f)があります。神FPU資料には8388608を使った実装法が載っていますが、他の実装として、GPR/FPRが分かれていないなら指数部を読んで適当にシフトしてあげるというのもあります。ちなみにCPU実験のレギュレーションに沿ったint_of_floatとOCamlのPervasives.int_of_floatは微妙に違うので注意してください。

int_of_floatには、爆速で終わる実装が発見されています(ただしISA的な注意が必要)。詳しくはこちらを: (1) / (2) / (3) / (4)

似た命令にffloorがあります。ffloorは神FPU資料を見て何も考えずに作ると間違えるので注意してください。「床関数をミスるとレイトレの床がバグる」という超有用な金言があるので、床がバグったらいの一番にffloorを疑って下さい。

int_of_float, float_of_int, ffloorはソフトウェア実装するかハードウェア実装するかの選択で悩むことになるかもしれません。呼び出し回数や1回の呼び出しでの消費クロック数などを考えながら選択することになるでしょう。




raytracer/min-rt.ml特有の命令として、fless, fispos, fisneg, fiszero, fhalf, fsqr, fnegがあります。これらはminiMLRuntime.mlに定義されています。

これらはCPU実験のレギュレーションによりある程度弄くることができます。min-caml言語として実装してインライン展開しても良いですし、たとえばfhalfはGPR/FPRの区別が無いアーキテクチャの場合はfmulしなくても単に指数部を弄るだけで実装できます。ここらへんは小細工です。




FPRを使うライブラリ命令は実はもう1つあって、それがread_floatです。これはRS232Cから送られてきたASCIIの小数を32bit floatに変換してレジスタに格納する命令です。別にread_intも作ると思うのでそれをそのまま拡張すると作ることができます。小数点が無かったりすることもあるので注意してください。ASCIIの1文字は8bitなので、8bit単位で読み書きする命令があると便利です。レギュレーションが変わっていなければ審判サーバーとの通信過程で1byteだけのデータを送信する箇所があるので、I/Oがいつも32bit単位だと思っていると失敗すると思います。

また、審判サーバーが変わっていないのなら、更に32bitのバイナリを読んでその内容をそのままFPRに格納する命令が必要なはずです(そしてこれはすぐ実装できます)。




以下は瑣末な点です。

誤差を測る: 浮動小数点数まわりの演算を実装するときは、誤差がちゃんとレギュレーションを満たすことを確認した方が良いでしょう。そこまで細かくなくても、グラフの概形が合っていることを見るだけでも何かバグってないか見ることができます。1引数の関数は全数検査が現実的な時間でできるのでやってみるといいかもしれません。15erはシミュレータ経由でデータを出させてグラフプロットする人が多かったようですが、14erには実機で直接検査していた方もいたようです。

また、x87との誤差を見るときは注意が必要です。C言語でやるなら、全ての表現がfloatになっていないと、途中でdoubleの計算になってからfloatにキャストされるのは結果が違うかもしれません。math.hの関数を使うときも、たとえばsinの代わりにsinfを使うべきでしょう。また、もう無いと思いますがx64ではなくてx86でやるときは、うまくコンパイルしないと浮動小数点数演算の際に一度80bitに拡張されてから計算されてしまうので誤差がでます(参考1参考2)。また、OCamlは倍精度です。ついでに言うとOCamlの整数型は1bit無いです(GCに使われている。ビット幅をフルに使うにはnativeintを用いる)。

シミュレータで数える: どの命令が要りそうか判断するために、どの命令が何回実行されたかカウントするのは便利でした。関数呼び出しの回数を測るのはシミュレータの組み方によっては難しいかもしれませんが、うちはたまたま標準だとnopが1回も実行されないので、回数を数えたいところにnopを手で挿入してやりました。

ISAについて考える: どこまでハードウェア実装してどこからソフトウェア実装するかは結構悩みどころかもしれません。でもたとえば"Computer Organization and Design"には「ぶっちゃけISAはそこまで関係ない」と書かれていたりもします。ISAに神経質になりすぎるよりコアの設計やコンパイラの最適化を考えた方がよっぽど速度に寄与するのかもしれません。また、数年前までは神FPU資料に結構頼っていたと思われるFPU実装も、そこまで単純なものには見えなくなってきました。

いくつかの実装については、14er wiki/CPU実験のSUPERHACKERのCPU実験/Yebiや神FPU資料が参考になります。浮動小数点数演算周りの話は、班の全係が関係して色々考えられる面白い部分だと個人的に思っているので、是非色々試して面白実装してみてください(面白いのができたら、是非教えてください!)。

WiiリモコンをScratch 2.0で使う

$
0
0
この記事では、Wiiリモコン(Wiimote)をBluetoothでパソコンに接続し、cwiidというソフトウェアを介してキーボードやマウスと対応づけることでScratchで使うことを解説します。

以下は、Ubuntu 14.04 LTSで動作確認しました。確認していませんが他のLinux環境でも同様に可能だと思います。Windows環境でも、ここで用いるソフトと同様のことができるソフトを使えば可能です(最後にリンクします)。Mac OS環境ではよく知りません。

最終更新日: 2016/02/07




まず、WiiリモコンをパソコンにBluetooth接続できるか確認します。

パソコンにBluetoothがついていない場合、Bluetooth USBアダプタを使用すると良いです。僕のパソコンには標準でついていたので使用していません。

イメージ 1


Ubuntu側でBluetoothの待ち受けをした後、Wiiリモコンの.椒織鵑鉢▲椒織鵑鯑瓜,靴垢襪、電池の横にある赤いSYNCボタンを押すことでBluetoothの登録をします。

後は待っていれば自動的に成功します。とはいえ繋がるだけなのでこのままでは何もできません。電池がもったいないので一旦接続をオフにします。後で面倒くさいので、Ubuntu側で認識できることが分かれば[Bluetoothの設定]からデバイスを削除しておいても良いかもしれません。




今回はBluetooth接続したWiiリモコンをジョイスティックとして使うために、CWiiDというソフトを使います。


libcwiid1が共通ライブラリ、lswmがWiiリモコンのアドレスを出力するソフト、wmguiがGUIでWiiリモコンの接続を確認するソフト、wminputが今回メインで使う、Wiiリモコンの入力をマウスやキーボード入力にマップするソフトです。

まずはインストールします。とりあえず使うだけならaptのパッケージで大丈夫です。pullされていない拡張機能を試したい方はgithubからcloneしてコンパイルする必要があります(後述)。

$ sudo apt-get install libcwiid1 lswm wmgui wminput

更にマウスを動かす機能を使うために、カーネルにuinputモジュールをロードしておきます。

$ sudo modprobe uinput

この操作はUbuntuを再起動するたびに必要になるはずです。かわりに/etc/modulesに直接書き込んでおく方法もあります。

$ gksudo gedit /etc/modules
$ cat /etc/modules
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

lp
uinput
$

さてそれでは、動くかどうかwmguiで確かめてみます。

$ wmgui

起動したら、メニューバーから[File]->[Connect]を押したあと、Wiiリモコンを待ち受け状態にして(+△泙燭SYNC)、[OK]を押すとWiiリモコンが認識されます。

イメージ 2


この画面の上で、きちんとWiiリモコンの入力が認識されているか確認できます。標準ではボタン入力だけチェックされていますが、メニューバーの[Settings]で選択することによって、加速度センサー、赤外線、ヌンチャク、クラシックコントローラの入力を受け取ることができるようになります。また、[Controls]から選択することによってWiiリモコンのLEDを光らせたり、Wiiリモコンをバイブさせたりすることができます。




動作確認ができたら、今度はwminputを使ってみます。wminputはWiiリモコンの入力をマウスの移動やクリック、キーボード入力などに変換できるソフトです。

$ lswm
Put Wiimotes in discoverable mode now (press 1+2)...
00:1F:32:95:EF:B0                   # このアドレスはWiiリモコンによって違うはずです
$ sudo wminput 00:1F:32:95:EF:B0

まずlswmを使ってWiiリモコン固有のアドレスを取得しておきます。これは必須ではないですが、こうしておくとwminputを使うときに接続開始を速くできます。

そしてwminputにこのアドレスを渡して動かします。デフォルトの設定では、Wiiリモコンを傾けるとマウスが動き、Aボタンで左クリック、Bボタンで右クリック、A+Bで中クリック、十字キーが矢印キーなどに対応させています。

このキーマップはコンフィグファイルを使って変更することができます。wminputの-cオプションを使うとできます。コンフィグファイルのサンプルは/usr/local/lib/cwiid/wminput/などにあります。

$ sudo wminput -c ir_ptr

みたいにすると使えます。詳しくはwminputのREADMEを読んで下さい。

赤外線センサも上みたいにコンフィグを変更することで使用できます。Wiiに付属のセンサーバーを起動してもいいですが、CWiiDのREADMEによると、赤外線LED、ろうそく、白熱電球などで代用できるようです。センサーバーからはたくさん赤外線が出ていますが、基本的には左右2つあればよいらしく、もっと言うと1つでも大丈夫だそうです。(まだ試していません)

またCWiiDにはプラグインの機能があります。マウス移動の機能はデフォルトで入っているプラグインを使って実装されています。プラグインはC/Pythonで書くことができるのでユーザーがいくつか自作プラグインを開発してpull reqを送っています。完成しているがmergeされていないものも多いですが、GitHubのレポジトリを確認しつつ自分でmergeしてコンパイルしてやると使うことができます。Wiiリモコンの傾きを捻りだと思ってキーボード入力にするScrewdriverとか便利じゃないですかね? 自分でプラグインを書くこともできるので自由度高そうです。

aptで配布されているパッケージはちょっと古くて、ソースコードからコンパイルするとwmguiでモーションプラスの値を取れるようになっていたりします。

ソースコードからコンパイルすることについては、こっちの記事を参考にしてください。

これ以上の詳細はCWiiDのコミュニティページや、wminputのREADMEを参照してください。




wminputのデフォルト設定を使ってWiiリモコンを接続したとして、Wiiリモコンで遊べるサンプルゲームを作ってみました。


多少他の人に遊んでもらった感想です:

・このゲームの操作にはボタンは要らないので、変な所でボタン操作を要求しない方が良さそう
・傾ける動作と赤外線でポイントする動作だと、子どもには後者の方が直感的っぽい?
・マウスカーソルをわざと大きくして画面から離れてプレイできるようにしないとあんまりWiiっぽくない
・ブラウザを全画面表示(F11)にした上でScratchも大画面モードでプレイした方がそれっぽい
・普通のマウス入力はオフにしておかないと、結局そっちの方に流れる(これはゲーム設計が悪い; Wiiリモコンだからこそできるゲームにすべき)




※ Windows使いの方向けの補足 ※

CWiiDはLinux用です。Windowsでするならもっと簡単に、一般のBluetoothジョイスティックを入力として扱うソフトウェアがあるのでそれが使えます。

この記事が詳しく解説されています。ソフトウェアとしてGlovePIEやWeyを紹介されていて、同様の方法でWiiリモコンだけでなく「太鼓の達人 for Wii」のタタコンなどが使用できることが示されています。「Wiimote software」などで調べると色々出てきますね。

(2016年1月20日16時現在、GlovePIEの公式ホームページはハックされてしまっているように見えます。復旧まで下手にアクセスしない方が良さそうです)

また、Scratch 1.4のときみたいにプラグインとしてWiiリモコンを使いたいという欲求もあるでしょう。たとえばWiiリモコンの加速度センサーの値をそのままScratchで使いたくなるときもあります。

Scratch 2.0では拡張機能をScratchXとして実装しようとしている(?)ので、ScratchXを使用するならこれを実現することができます。たとえばiiConnect2ScratchというのがBluetooth接続方法から、オリジナルソフトウェアの使い方、Scratchでのサンプルプロジェクトまでの流れが全部分かりやすく説明されていて良いと思いました。特にこのユーザーガイドは分かりやすかったです。iiConnect2ScratchではWiiリモコンだけでなくWiiFitボードも使えるようです。面白そう。




参考


ScratchXについて、開発者向けにはここが詳しいです
ScratchX - GitHub

CWiiDの他にXWiimoteというのもあります。こちらの方が設計が良く使いやすいと言っていた人もいるけれどまだ僕は試していません。
XWiimote - Ponyhof

CWiiDをUbuntu 14.04にインストールする

$
0
0
CWiiDをUbuntu 14.04 LTSでコンパイルして、wmgui, lswm, wminputを使えるようにする。

Scratchで使いたかったという話の流れですがこの記事にScratchは出てきません。あと、単に使うだけならapt-get installできます。

最終更新日: 2016/01/21




1. git clone

オリジナルのレポジトリはabstrakraft/cwiidなのだが、これの開発は2010年から止まっている。開発者のabstrakraftは「もっと良いAPIとしてWiiリモコン用のカーネルドライバができたのでcwiidを開発する必要が無くなった」と言っている

そこでこのissueを参考にしつつ、たとえばmzimmerman/cwiidというforkをgit cloneすると良いと思う。オリジナルに寄せられたpull-reqをいくつか取り入れていたりするブランチなのでわざわざ自分でmergeしなくて済む。

以下mzimmerman/cwiidかオリジナルをgit cloneしたとして話す。




2. 事前に必要なものをインストール

目ぼしいところだとpython2.xやlibbluetooth-dev(bluez-libs)が必要です。僕の環境ではpython2.7で動作確認しました。

$ sudo apt-get install bison flex libgtk2.0-dev autotools-dev automake libbluetooth-dev

フランス語のこのサイトによると、以下のものが必要らしい(環境はLinux Mint 12)が、本当かなあ。pythonのバージョンを見る限り情報が古そうな気もする。

$ sudo apt-get install bison flex libbluetooth-dev libgtk2.0-dev python-dev libtool automake1.10 autoconf quilt patchutils python-all-dev cdbs lesstif2 poppler-data
$ sudo apt-get install autogen automake gcc bluetooth libbluetooth3-dev libgtk2.0-dev pkg-config python2.6-dev flex bison git-core libbluetooth-dev python-pygame python-tk

あと、wminputを動かすためにカーネルにuinputモジュールを入れておく必要がある。これについて詳しいことは、wminputのREADMEを参照。

$ sudo modprobe uinput  # 再起動のたびに実行




3. makeしてインストール

コンフィグしてmakeする。

オリジナルのレポジトリからgit cloneしたなら、Makefileにバグがあるので修正する必要がある。wmdemo/Makefile.inの11行目を以下のように追記修正。

LDLIBS += -lcwiid -lbluetooth

そしてmake

$ cd cwiid
$ aclocal
$ autoconf
$ ./configure --with-cwiid-config-dir=/etc/cwiid/
$ make
$ sudo make install

configureが「wmdemo.oに未定義のシンボルstr2baがあんねん」みたいなエラーで止まった場合は上の修正を忘れている。wmdemo/Makefile.inを修正し、make cleanした後に上の動作をもう一度すると良い。




4. 確認

wmgui, lswm, wminputが動くか確認してみる。またはwmdemoを動かしてみても良い。

$ which wmgui
/usr/local/bin/wmgui
$ wmgui

僕の環境+オリジナルのcwiidでは、オリジナルのWiiリモコン、Wiiリモコン+ヌンチャク、Wiiリモコン+モーションプラスがちゃんと認識できた。クラシックコントローラは持っていないので分からない。また、Wiiリモコン+モーションプラス+ヌンチャクだと上手く認識できなかった。また、wmgui起動中にヌンチャクとモーションプラスを切り替えてもプラグアンドプレイ的な認識をしてくれなかった。

mzimmerman/cwiidでも同じような認識だった。ただこっちにはさらにguitarというのが増えていた。"Guitar Hero"や"Rock Band"というゲームで使用されているコレのことだろうか。持っていないので確認できなかった。

lswmとwminputも普通に動いた。mzimmerman/cwiidならsudoは要らないようだ。

$ lswm
Put Wiimotes in discoverable mode now (press 1+2)...
00:1F:32:95:EF:B0                   # このアドレスはWiiリモコンによって違うはず
$ wminput                           # オリジナルならsudo wminputじゃないと駄目な気がする

もし"ImportError: No module named cwiid"というpythonのエラーっぽいもので止まったら、以下のことをすると良いだろう。僕はこれで動いた。

a. PYTHONPATHにpython2.X/site-packagesを追加する。

$ export $PYTHONPATH="/usr/local/lib/python2.7/site-packages"

元からPYTHONPATHに何か入っている方は上書きして消さないように注意。このスクリプトは.bashrcなどに書いておくと便利。ちゃんとパスが通ったかどうかは、たとえばsys.pathを見ると確認できる。

$ python2.7>>> import sys>>> sys.path

それでも止まるときは、他のモジュールが干渉しているかもしれない。僕はstraceして変なところから呼んでないか調べた。

$ sudo strace wminput 2> log
$ emacs log

b. sudo wminputがうまくいかないとき、これはsudoだとPYTHONPATHが使われないことに起因している。sudoersのenv_keepにPYTHONPATHを追加すると動く。このStackOverflowや、このブログを参考にした。

sudoersは不用意に弄ると死ぬので気をつける。/etc/sudoers.d/やvisudoを使うと安全?

c. ディストリビューションによっては、/usr/local/libを見に行かないこともあるらしい(Ubuntu 14.04だと大丈夫だった)。cwiidのREADMEに解決策が出ているので参考にすると良いかもしれない。また、./configureに-libdirを指定しないといけないディストリビューションもあるらしい。こちらを参照




5. キーコンフィグやプラグイン

wminputは-cオプションを使うとキーコンフィグファイルを変更できる。/etc/cwiid/wminput/や/usr/local/etc/cwiid/wminput/にサンプルのコンフィグファイルがいくつかあるので、たとえば

$ ls /usr/local/etc/cwiid/wminput/  # オリジナル版の場合
acc_led  buttons  gamepad  neverball        nunchuk_stick2btn
acc_ptr  default  ir_ptr   nunchuk_acc_ptr
$ sudo wminput -c ir_ptr

とするとir_ptrを使用できる。コンフィグファイルの文法についてはwminputのREADME参照。

自分でプラグインを書くこともできる。他のプラグインを参考にしながらCで書いてmakeし直すとできるはず。




6. その他

やってるとCWiiDのインストール/アンインストールを繰り返すことがある。そのときは

$ cd cwiid
$ sudo make uninstall && sudo make uninstall_config
$ sudo make clean

すると綺麗に諸々削除してくれる。make cleanまで必要なのかどうか知らないが、不安なのでとりあえずしている。make uninstallについてはcwiidのREADMEに書いてあった。

ちゃんとmake uninstallできていることは

$ sudo updatedb
$ locate cwiid

とかすると分かる。

TOP PAGE

Viewing all 107 articles
Browse latest View live