<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="http://grafi.jp/">
  <id>http://grafi.jp/</id>
  <title>grafi.jp</title>
  <updated>2025-06-29T20:20:29Z</updated>
  <link rel="alternate" href="http://grafi.jp/" type="text/html"/>
  <link rel="self" href="http://grafi.jp/feed.xml" type="application/atom+xml"/>
  <author>
    <name>grafi</name>
    <uri>http://grafi.jp/</uri>
  </author>
  <entry>
    <id>tag:grafi.jp,2021-03-08:/pages/rx6800-colour</id>
    <title type="html">新しい AMD の GPU で色がおかしくなる問題</title>
    <published>2021-03-08T15:10:00Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/rx6800-colour" type="text/html"/>
    <content type="html">&lt;p&gt;Radeon RX 6800 で Linux 動かして画面がちょっと変なのをしばらく放置してたんだけど、改めて調べてみると YCbCr でディスプレイに送ってたせいでレンジがおかしくなってたぽい、あと変換時に誤差も出てたかも。&lt;/p&gt;

&lt;p&gt;https://gitlab.freedesktop.org/drm/amd/-/issues/476&lt;/p&gt;

&lt;p&gt;ドライバに雑なパッチ当てれば直るのは直った。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2021-03-01:/pages/threes-shogi</id>
    <title type="html">Threes</title>
    <published>2021-03-01T03:37:47Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/threes-shogi" type="text/html"/>
    <content type="html">&lt;p&gt;Threes というパズルゲームがある。 &lt;a href="http://asherv.com/threes/threemails/#letter"&gt;2048 という模倣のほうが有名になってしまった&lt;/a&gt; ゲームである。ピースを合わせて大きな 3 × 2 ^ n を作ることが目標。6144 はかなりの高スコアで、12288 を作ると &lt;a href="https://www.theverge.com/tldr/2017/6/20/15836462/threes-mobile-puzzle-ios-android-end-high-score-12288-how"&gt;“beat Threes”&lt;/a&gt; とされる。&lt;/p&gt;

&lt;p&gt;引っ越し前後の家具の配置といった作業が一段落したのを機に、断続的にやっていたこのゲームを再開した。引きこもって過ごす今年の正月休みににやることとして、6144 を作れるまでがんばろうと決めた。&lt;/p&gt;

&lt;p&gt;この記事は敗北の表明である。すなわち、わたしは 6144 を作ることができなかった。&lt;/p&gt;

&lt;p&gt;
  &lt;img src="threes-shogi_res/threes-ss.png" alt="alt=&amp;quot;Threes&amp;quot;,height=760,width=360" /&gt;
&lt;/p&gt;

&lt;h2 id="section"&gt;発達・愛着&lt;/h2&gt;

&lt;p&gt;わたしはパズルゲームなどにのめり込みやすい性質をしている。自閉症スペクトラム障害の傾向を持つ人は多かれ少なかれ同じ性質を持つと思われる。しかしのめり込んでいると生活不能になる。実際のところ気が済むまでやれば飽きるので、気が済むまでやれればいいのだが、いつになれば気が済むのか分からないのは困る。結果として身につけた処世術は「適当な目標を決めて、それを達成するまでやり続ける」である。目標を達成するまで一週間なり音信不通になっても、一週間で済むならよいという考えである。&lt;/p&gt;

&lt;p&gt;いつもの処世術を適用すべく、6144 という目標を決定した。その地点で 3072 + 1536 までは達成したのでいけるだろうと思ったのだが、3072 + 1536 + 768 まで達成するのが限度であった。実際のところ、16 マスという狭いプレイエリアにさらに 384 を詰めることにはより大きな技術と幸運を必要とする。もう少しだと思わせて実は先が長いという構造は、いわゆるコンプガチャと通底しており邪悪にも思われる。ゲームデザインとして意図したことではなさそうだが、少し失敗か。&lt;/p&gt;

&lt;p&gt;ここまで読めばおわかりだが、目標が達成できないといつまで経っても生活できないという、致命的な欠点がこの処世術にはある。現に正月休みを過ぎても 6144 を作れずにいて労働に支障が出ていた。それでは困るということで目標を修正すればよいのだが、「自分への約束」たる目標値を修正することは中々容易なことではなく、自分を納得させるための相当な理由付けなりを必要とする。&lt;/p&gt;

&lt;p&gt;ずっと粘ってればそのうち 6144 を作れる気もしていたが、しかし将来的なことも考慮するならばセルフコントロールを改善すべきである。その一つの方法として、文章に昇華させることはできないかと思いついた。&lt;/p&gt;

&lt;p&gt;その試みは完全に成功に成功で、この文章を書き終える前のとっくに Threes をやり続ける気というものをなくしていた。これは一つの収穫で、素直にめでたいことだと喜んでいる。&lt;/p&gt;

&lt;p&gt;冷静になってみると、なぜ恣意的に決めた数値にこだわるのだろう。誰かに「よくがんばったね、十分だよ」と言ってもらえればそれで済むのではないかとも思う。孤独であるのがよくないのだろうか。アルコール依存については孤独が極めて大きな要因だとも効く。愛着（attachment）がぶっ壊れてるんだろうかとも思う。 &lt;a href="https://www.kobunsha.com/shelf/book/isbn/9784334036430"&gt;入門的な和書&lt;/a&gt; や &lt;a href="https://en.wikipedia.org/wiki/Attachment_theory"&gt;英語版 Wikipedia 記事&lt;/a&gt; を読むのは疑似科学かと半信半疑ではあるものの楽しい。自分は主に不安型であるだろうと感じつつ、回避型の要素も否めない。ただし回避については、コミュニケーションの齟齬で互いに傷付かないかという合理的な不安というふうに、自分の中では論理で説明できるように感じている。だからこそ説明不能なものとして不安的な要素を自覚しやすいのだろうか？&lt;/p&gt;

&lt;h2 id="section-1"&gt;将棋・逸脱&lt;/h2&gt;

&lt;p&gt;ここ数年 &lt;a href="https://www.shogi.or.jp/lp/mr201704/"&gt;将棋連盟のモバイル中継&lt;/a&gt; で将棋観戦を楽しんでいる。観戦を始めたときは駒の動かし方と、美濃囲い・四間飛車・矢倉囲い・棒銀の名前くらいしか知らない程度だったが、解説の助けなどもあり、一つ一つの駒の動きに合理性があることの美しさや、難解な終盤のスリルを楽しんでいる。始めに観戦したのが先手藤井聡太七段（当時）後手広瀬章人八段の、挑戦者決定戦となる2019年王将リーグ戦だったのは非常な幸運だったと言える。名局賞特別賞にも選ばれた一局で、矢倉のジリジリした序盤からの激しい攻め合い、終盤戦での逆転に次ぐ逆転、そして最終盤のドラマと、全くの素人にも凄さが伝わってくる濃密な一局であった。&lt;/p&gt;

&lt;p&gt;将棋ウォーズなどを始めて自分で指したいとも思いつつ、時間を無限に溶かしてしまうのが怖くて手が出せなかったりしている今日この頃。&lt;/p&gt;

&lt;p&gt;大晦日にはニコ生で『大晦日将棋ライバルズ』を視聴し、改めて棋士の集中力に恐れ入り、見習いたいと感じていた。Threes で好スコアを出せないのも、集中力が足らずに構想立てや読みを省いて感覚でやってしまうところに原因があると考えている。仕事ではプログラミングの速度も課題である。集中方法と言えば &lt;a href="https://softether.hatenadiary.org/entry/20070326/p://softether.hatenadiary.org/entry/20070326/p2"&gt;登さんの記事&lt;/a&gt; を思い出す。「論理的思考」をどこまで行うかのバランスは人や状況によって変わりそうではあるが、没我的な集中状態を持続させることが肝要なことは確かだろう。わたしはまだまだ精進が必要である。&lt;/p&gt;

&lt;p&gt;プロ棋士なんて「ゲーム廃人」そのものではないかとふと思ったことがあるが、そんなことはない。まずもって、将棋によって生計を立てられる。社会生活に支障がないなら依存症とは呼ばない。さらに対局時間に出席することは当然必要で、スポンサーを伴ったプロとしては様々な作法やファンサービスも求められる。歴史の発明だろうか、一つのゲームが人生の全てになってしまう依存的な振る舞いを一歩手前で止めるブレーキが備わっているように感じられる。少なくとも十分に適応的だとは言えるだろう。&lt;/p&gt;

&lt;p&gt;十分に適応的であるならば精神的に真に健康と言えるだろうかと考えてみて、わたしは YES と応えたい。より狭い範囲を真に健康と定義するなら、人間について何らかのモデルが必要となる。近代が大量に必要とした工場労働者や軍人、あるいは近世における農民がその例だろう。そこから外れた人たちは、たとえそれなりに幸せに生きていても真に健康とは言えない。権力者から見ればその通りだったのかもしれない。&lt;/p&gt;

&lt;p&gt;しかし、現代はより複雑な時代である。素朴であるが強力な反論だ。対しては、ではまた単純な時代になったらどうする？ という問いかけが浮かんでくる。わたし個人としては「そんな時代にはしない」というのが本命の回答となる。これからも情報科学技術が世の中を大きく変えるだろうが、画一化された人間を求める方向に向かわないよう微力でも尽くしたい。一方で、大穴の回答としては「遺伝子操作で人類を変えれば済む」というのもある。いや、遺伝子操作技術が進歩したときにどうなるかはわからない。たとえばものすごく賢いヒトを作るのか、電子計算機の下働きとして適切なヒトを作るのか。尊厳を守るための枠組みを作るとして、人類が合意できる「尊厳」とはなんだろう。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2020-05-25:/pages/2020</id>
    <title type="html">2020</title>
    <published>2020-05-25T04:46:33Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/2020" type="text/html"/>
    <content type="html">&lt;p&gt;2020 は 101 の倍数です。新年明けましておめでとうございます、と思っているともう半年経ってました。時間は流れる。&lt;/p&gt;

&lt;h2 id="section"&gt;近況&lt;/h2&gt;

&lt;p&gt;なんとか修士課程を修了して、各方面にご迷惑おかけしながら博士課程には進まないことになり（@各方面 ごめんなさい）、データ分析企業で深層学習を用いたプロダクトを作ることになって、しばらくしてから転職しました。今の職場では、独自開発の深層学習用プロセッサ向けにコンパイラやランタイムといった諸々の開発をやっています。わりと良いタイミングで応募することができたので、すんなり転職が決まったのかなと思います。人並みに忙しいことは忙しいのですが、物質的・心理的にすこし余裕ができたのは嬉しいです。&lt;/p&gt;

&lt;p&gt;ここ数ヶ月は、COVID-19 の流行により引きこもり生活を送っています。世の中どうなるのか本当わからないですが、できることをやるしかないですね。&lt;/p&gt;

&lt;h2 id="section-1"&gt;人生&lt;/h2&gt;

&lt;p&gt;人生むずかしいですね。今はバリバリ開発やってる（と思ってる）のですが、そんなにスタミナ溢れる人間でないので、いつまで続けられるのやら。ほとんど本読んだり映画観たりできてなくて、純粋に技術的な面以外では過去の蓄えをすりつぶしていそうで少し怖かったりもします。これは職場がどうこうでなく、自分のコンテキストスイッチがポンコツだったり、疲れっぽかったりするだけなのですが……。うまい具合にやっていきたいです。&lt;/p&gt;

&lt;p&gt;最近はなにか真に意味のある知識を人類に残さねばならないみたいな観念が薄れてきていて、なんらかの形で少し貢献できるくらいでいいかという気持ちになっています。これは進歩なのか老化なのかわかりません。あるいは、小学生のときはふと死ぬのが怖いと思うこともよくありましたが、高校くらいになるとそういうことも減ってました。そういう類の、適応的な老化とでも呼ぶべきものなのでしょうか。受け容れるしかないでしょうね。&lt;/p&gt;

&lt;p&gt;ずっと感覚がわからないのが、計画的な人生みたいな概念です。人生なんて風に吹かれる落ち葉みたいなもので、ただし落ち葉には自我があって小さなモーターを備えていて、あるいはそう思い込んでいて、少し自分の運命を操作することができますが、その結果を予測することなんてできようか。別に大きな社会の変動に振り回されることを気にしてるわけではなくて、むしろ自分の周りの小さな変動です。これまでの経験からして、出会う人や組織そして出会いのタイミングなどによって、人生を予測不能なものにするには十分な程度に自分の考え方までも大きく変わるように感じています。世間という大きな正則化項があんまり効いていないのか、元気があるかないかで100倍くらい火力が変動する人間だからか、まあそういう性質が表れているのでしょう。&lt;/p&gt;

&lt;p&gt;独り身をやっていると意味不明な方向に突っ走って自爆しそうで、将来的にパートナーが居ればなあと思うようなことが増えています。ただ、恋人・パートナーは単なる自分の精神安定剤ではなくお互い win-win であることが最低限の前提であり、他の誰かではなく自分のような破綻した人間といてもいいことなんてあるだろうかと思ってしまいます。その割にマッチングアプリ的なのも本当に嫌で、出会いの偶然性を大切にしろ！ 恋のトキメキはないのか！ という心情を拭えません。というか相手に求める条件みたいな概念がまるでピンと来なくて、好きな人のためなら物理法則の範囲内でいくらでも頑張れるし生産性100倍になるとか思っちゃう……。いわゆる就活を全くやらずに済んで、◯活と呼ばれるものをしたくないという無意味なプライドを得てしまっただけかもですね。&lt;/p&gt;

&lt;p&gt;博士進学したいとぼんやり思うこともありつつ、精神的に不調になって各方面に迷惑かけるだけになるのが怖くて当面は考えられない……。本当に滅茶苦茶だった修士課程のときと比べればもう少しはマシにやれる自信はあるものの、まだちょっとねえ。&lt;/p&gt;

&lt;h2 id="section-2"&gt;インターネットと肉体&lt;/h2&gt;

&lt;p&gt;どうしてインターネットはつらい場所になってしまったのでしょう、とくに twitter ですよ。特定の属性に向けたほとんどの批判めいた言葉は、まるで批判として成立しておらず&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;別にそんなことを言っている人はいない&lt;/li&gt;
  &lt;li&gt;一部の過激な人にしか当てはまらない&lt;/li&gt;
  &lt;li&gt;単なる揚げ足取り&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;という程度になってると感じます。「批判めいた」とすら呼べない明白な罵詈雑言はさらに多数です。Twitter で議論ができるなんて過剰な期待をし過ぎというのはまた適切な指摘に思いますけど、うーん。&lt;/p&gt;

&lt;p&gt;それと、「党派性」に対する否定的な反応を多く見る気がすることも気にかかります。一人では政治的に無力だから党派を組むわけでして、党派性が力に繋がるのならそれは必ずしも思考停止と呼ぶべきものではないと考えています。&lt;/p&gt;

&lt;p&gt;とはいえ、とくに感染症の拡がるこの世において、インターネットという技術はトータルとしてプラスの役割を果たしているとも信じています。インターネットを諦めない。&lt;/p&gt;

&lt;p&gt;今の情勢ニューノーマルだのがもてはやされますが、ちょっと懐疑的なところもあります。リモートでのコミュニケーションも悪いものではないですが、人と人の対面のコミュニケーションで行われていた（それこそ飛沫といった）物質の交換がないことを無視していいのかわかりません。体表の化学物質は多くの生物において社会的行動をもたらす決定的なメカニズムであり、高次の情報処理が発達したヒトにおいても一定の役割を果たしているのでないかと思ってしまいます。本質的に人間は肉塊であるとも感じていて、プログラマに有りがちな「身体捨てて意識だけの存在になりたい」という発想もピンと来なかったりします。まあ、だからどうこうと主張があるわけではないです。&lt;/p&gt;

&lt;h2 id="section-3"&gt;計算機&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/grafi_tt/status/994432078899957760"&gt;速い・安全・抽象的！ がモットー&lt;/a&gt; です。いやはや。&lt;/p&gt;

&lt;p&gt;深層学習バブルは COVID-19 がトドメとなって終わるとしても、深層学習の有用性は確かでしょう。これまでも深層学習は東京の土地くらいには価値があると話していました。90年代のバブル崩壊以上に東京の土地の価値が怪しくなってる現状からすると、どうも不吉なことを言ってしまっていたかもしれないですが……。それはそれとして、エンジニアリングの観点からみて深層学習がチャレンジングで面白い対象であることは確かです。これまでのワークロードと色々な部分で性質が違っていてうまく既存のパラダイムに載らず、様々な部分を新たに作る必要性が生じています。さらにそれでお金を稼ぐことができるので、世界中でハードウェアやソフトウェアの開発競争が起きているのは当然に思います。ちょっと過当競争すぎて効率を損なってる気はしないでもないですが。&lt;/p&gt;

&lt;p&gt;さて、深層学習手法は学習結果の再現性がないとか言われますが、そんなのはエンジニアリングのやる気が足りないだけだろうと常々感じています。ハードウェアが変わる場合は最適な数値計算の順序が変わってしまって確かに難しいのですが、同じハードウェアなら完璧に計算結果を再現すべきで、ハードウェアや並列度が変わった場合でもデータセットや正則化手法で用いるランダムサンプリングは再現しろと常々思っています。 &lt;a href="https://github.com/grafi-tt/multfly"&gt;multfly&lt;/a&gt; および &lt;a href="https://github.com/grafi-tt/melty2"&gt;melty2&lt;/a&gt; の counter-based pseudo random number generator を作ってみたのもそういう動機からで……、ちょっと放置してしまってますが。再現性が取れていることはもちろんアカデミックに有意義ですし、実務的にも学習が発散した場合などに原因を特定するのが簡単になるという大きなメリットがあります。&lt;/p&gt;

&lt;p&gt;学習の再現性というのは、モデルの固定化を意味するものではありません。機械学習モデルを用いた人間の評価が社会的偏見を固定化させ得ることはいまや問題視されていますが、このメタレベルでのモデルの固定化とでも言うべき現象は、評価関数を始めとしたモデルの設計の問題です。ある一つのモデルがなんらかの隠れたバイアスを有しているために同じ「AI」の特徴量の気まぐれによって誰かが不利益を被り続けるという、より字義通りのモデルの固定化については、別のシードを使って再学習するなどの非決定性を持たせれば基本的には解消可能と思われます。そう、それぞれの人間もまた、いかに賢い人であろうとも理不尽なバイアスを持っているのです。ある人間に低く評価されたなら他の人間を当たってみることができるように、他の「AI」を当たることができればよいのでしょう。そうすることが可能な形で機械学習モデルが運用されることを願っています。&lt;/p&gt;

&lt;p&gt;今の仕事では低レイヤ寄りの最適化などもやっているのですが、ハードウェアの都合が面倒くさいといった感覚はそんなにないです（非本質的な部分は面倒に感じることもありますが。）とりあえず、電子を無駄に動かすような回路を作ると無駄にエネルギーや製造コストがかかるという制約からは逃れられないと思っていて、ハードウェアはそういう物理法則にしたがって設計されているわけですので。計算機科学は物理法則と論理の橋渡しをする学問である、という自己流の定義がしっくりくるこの頃です。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2016-08-21:/pages/qemu-kvm-vga-scsi-pass-thru</id>
    <title type="html">QEMU-KVMでGPUと光学ドライブをパススルーしてWindowsゲストを快適に走らせる</title>
    <published>2016-08-21T07:07:41Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/qemu-kvm-vga-scsi-pass-thru" type="text/html"/>
    <content type="html">&lt;p&gt;基本的にLinuxデスクトップ環境で過ごしているが、WindowsでBlu-rayを再生したいこともある。
この要求を満たす環境の構成としては&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Windowsの下でLinuxを仮想マシンのゲストとして動かす&lt;/li&gt;
  &lt;li&gt;デュアルブート&lt;/li&gt;
  &lt;li&gt;物理的に二台動かす&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;といった選択肢が考えられますが、1はLinux側で使えるリソースが減るのが気に入らず、2は面倒くさい、3はハードウェアと場所と電気が必要と、それぞれ大きなデメリットがあります。&lt;/p&gt;

&lt;p&gt;このような難点を解消することはできないか。実はディスクリートGPUが挿さったマシンにおいては、PCIパススルーを行うことで、Linuxの下で仮想マシンのゲストとして動くWindowsから直接GPUにアクセスさせることができます。Linuxの方ではCPU内蔵のGPU（あるいは別のディスクリートGPU）を使います。SCSIパススルーを行うことで、WindowsからBlu-rayの読み込みなどもできます。こうすれば全ての難点はクリアされ、実際かなり快適に過ごすことが可能となりました。&lt;/p&gt;

&lt;p&gt;始めは取っつきにくく、実際数日がかりの試行錯誤になりましたが、なんとなくわかってしまえばシンプルです。むしろこんなにすっきりしていて正常に動作する足回りが開発されていることがすごいなあと感じます。&lt;/p&gt;

&lt;h2 id="section"&gt;必要なハードウェア&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;（Intelの場合）VT-xとVT-dをサポートしたチップセット・CPU&lt;/li&gt;
  &lt;li&gt;UEFI（GOP）をサポートするVGA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VT-dはちょっと前までローエンドや倍率ロックフリーのCPUだとサポートされてなかったので注意が必要です。他はすごく古くなければ問題なさそうです。&lt;/p&gt;

&lt;p&gt;このあたりの機能がない場合、色々無理をしないとGPUのパススルーはできないです。技術的な詳細を追っていないので不正確かとは思いますがわたしの理解を書いておきます。&lt;/p&gt;

&lt;p&gt;VT-dはIntelによるIOMMUの仕様です。IOMMUは、MMUがプロセスがアクセスする仮想メモリアドレスを物理メモリアドレスにマップするのと同様に、PCIデバイスがDMAする先を物理メモリアドレスにマップします。これによって、PCIデバイスが仮想マシンの下にある物理アドレスに正しくDMAできるようになると同時に、メモリ保護を実現できます。また、IOMMUはPCIデバイスが発生させる割り込みをVMに送信する機能も提供しています。&lt;/p&gt;

&lt;p&gt;QEMUはVFIOというLinuxの機構を通じてPCIパススルーを行います。VFIOとはPCIデバイスに対応するioctlで操作できるファイルディスクリプタをユーザー空間に公開することで、ユーザー空間からPCIデバイスをフルに操作できるようにする機構です。ユーザー空間からDMAリクエストを行ったときに好き勝手なメモリアクセスをしないようIOMMUが使われます。QEMUはVFIOファイルディスクリプタをPCIデバイスとして仮想マシンに見せるわけです。&lt;/p&gt;

&lt;p&gt;しかしGPUは普通のPCIデバイスみたいに単純ではありません。OSが起動する前に画面に何か描いてる地点でそれは明らかなのですが、特にBIOSで起動する場合はVGA BIOSというレガシーなABIを用いることとなり、システム全体にわたって固定されたアドレスを使ってデバイスとやり取りすることになります。なので複数のVGAを使う場合VGA BIOSをがんばって切り替える必要が生じてきて、さらにVGA BIOS領域にVFIO fdを介した変換される前のMMIOアドレスが見えてしまうのをなんとかしないといけません。このためパッチが必要になったりします。&lt;/p&gt;

&lt;p&gt;一方でUEFIではそういったアドレス空間に関する問題はなく、OS起動前の画面表示はGOPというプロトコルで行っています。なのでより安全にパススルーができることになります。&lt;/p&gt;

&lt;p&gt;参考&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.kernel.org/doc/Documentation/vfio.txt"&gt;Linuxカーネルソース添付のvfio.txt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://vfio.blogspot.jp/"&gt;VFIO tips and tricks&lt;/a&gt; このAlexさんがLinuxカーネルのこの辺を色々開発してるらしい。&lt;a href="https://lkml.org/lkml/2014/1/20/453"&gt;IntelチップセットでのIOMMUグループのQuirk&lt;/a&gt;もこの人のおかげ。&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.linux-kvm.org/images/e/ed/Kvm-forum-2013-VFIO-VGA.pdf"&gt;VGA Assignment Using VFIO&lt;/a&gt; Alexさんのスライド&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.uefi.org/sites/default/files/resources/UPFS11_P4_UEFI_GOP_AMD.pdf"&gt;Replacing VGA, GOP implementation for UEFI&lt;/a&gt; AMDの人のスライド&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://syuu1228.github.io/howto_implement_hypervisor/"&gt;ハイパーバイザの作り方&lt;/a&gt; syuuさん&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/PCI_configuration_space"&gt;PCI configuration space - Wikipedia, the free encyclopedia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="section-1"&gt;その他有ったほうがいいハードウェア&lt;/h2&gt;

&lt;p&gt;要するにこれは二台のマシンを動かすのと大体同じような構成です。
よって以下のものは有ったほうがいいです。&lt;/p&gt;

&lt;h3 id="section-2"&gt;ディスプレイ関連&lt;/h3&gt;

&lt;p&gt;ホストとゲストが別々に画面出力を行うことになるので、それぞれをディスプレイに接続する必要があります。このために&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;複数の入力端子があるディスプレイ&lt;/li&gt;
  &lt;li&gt;複数枚のディスプレイ&lt;/li&gt;
  &lt;li&gt;ディスプレイ切替器&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;のいずれかが必要となります。&lt;/p&gt;

&lt;h3 id="section-3"&gt;キーボード・ポインティングデバイス関連&lt;/h3&gt;

&lt;p&gt;ゲストは仮想スクリーンに描画するのではなく全く独自に画面出力をしているのですから、カーソルをゲストのスクリーンの上に持っていくとゲストを操作できるというような、空気を読んだ挙動はできません。なので、ホストとゲストの双方に、別々に入力機器をつなぐ必要があります。&lt;/p&gt;

&lt;p&gt;具体的には&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;複数のUSBコントローラの一部をゲストに渡した上で、USB切替器を使って入力機器を接続するUSBポートを切り替える&lt;/li&gt;
  &lt;li&gt;入力機器一式を二つ用意して、片方をゲストで使う&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;のいずれかが考えられます。後者は力技ですが単純で、特定のUSBデバイスをゲストに渡してやるだけです。前者では、一部のUSBコントローラのPCIデバイスを丸ごとPCIパススルーしてやり、切替器を使うことでホスト・ゲストそれぞれが制御するUSBコントローラに対応するポートにUSBデバイスを繋ぎ替えます。&lt;/p&gt;

&lt;p&gt;わたしはUSBオーディオインターフェースの切り替えも行いたい都合で&lt;a href="https://www.amazon.co.jp/gp/product/B000RHH590"&gt;サンワサプライの2x2スイッチ&lt;/a&gt;を使いました。また自分が使っているキーボード（HHKB）にはUSBハブがついているので、そこにトラックボールをぶら下げることにしました。外部電源を取っているおかげで無理がないからか、以前使っていたスイッチよりもキーボードが安定して認識されていて好調です。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;           +----------+
ポート1----|          |----USBオーディオIF
           | スイッチ |
ポート2----|          |----キーボード（HHKB）----トラックボール
           +----------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;複数のUSBコントローラを用意するには、PCIeやPCIでUSBポートを増設すればいいです。一部のポートだけがUSB3.0であるようなチップセットではUSB3.0のコントローラが内部的に分かれています。なのでわたしのMBでは、USBポートの数や片方ではUSB3.0が使えなくなることを気にしなければ、増設の必要はありませんでした。（PCIeスロットが埋まっていることに気づかずPCIe機器を買ったり、その後PCI機器を買って&lt;a href="http://vfio.blogspot.jp/2015/05/vfio-gpu-how-to-series-part-1-hardware.html"&gt;PCI-PCIeブリッジによる割り込みの問題で使えなかったり&lt;/a&gt;と、無駄足を踏みましたが。）&lt;/p&gt;

&lt;p&gt;理論的にはハードウェアに依らなくとも、特定のキーボードショートカットやコマンドを実行したときに適当なUSBデバイスをゲストにアタッチ・デタッチさせるよう、ホスト・ゲストの環境をそれぞれ設定すれば、USBデバイスの切り替えは可能です。ゲスト側からのQEMUの操作には&lt;a href="http://wiki.qemu.org/Features/QAPI/GuestAgent"&gt;GuestAgent&lt;/a&gt;が使えます。しかし確実に動くよう設定するのは中々大変そうです。&lt;/p&gt;

&lt;h2 id="pciiommu"&gt;PCIデバイス・IOMMUグループの確認&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF"&gt;PCI passthrough via OVMF - ArchWiki&lt;/a&gt;を参考にやりました。&lt;/p&gt;

&lt;p&gt;わたしのマシンは&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;MB&lt;/dt&gt;&lt;dd&gt;ASUS P8H77-M&lt;/dd&gt;
&lt;dt&gt;CPU&lt;/dt&gt;&lt;dd&gt;Core i5-3550 (IvyBridge)&lt;/dd&gt;
&lt;dt&gt;GPU&lt;/dt&gt;&lt;dd&gt;GTX750Ti&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;です。ArchWikiにあるように&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ for iommu_group in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d); do echo "IOMMU group $(basename "$iommu_group")"; for device in $(ls -1 "$iommu_group"/devices/); do echo -n $'\t'; lspci -nns "$device"; done; done
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;を実行すると、&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;IOMMU group 0
        00:00.0 Host bridge [0600]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor DRAM Controller [8086:0150] (rev 09)
IOMMU group 1
        00:01.0 PCI bridge [0604]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port [8086:0151] (rev 09)
        01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM107 [GeForce GTX 750 Ti] [10de:1380] (rev a2)
        01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:0fbc] (rev a1)
IOMMU group 2
        00:02.0 VGA compatible controller [0300]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller [8086:0152] (rev 09)
IOMMU group 3
        00:14.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller [8086:1e31] (rev 04)
IOMMU group 4
        00:16.0 Communication controller [0780]: Intel Corporation 7 Series/C210 Series Chipset Family MEI Controller #1 [8086:1e3a] (rev 04)
IOMMU group 5
        00:1a.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 [8086:1e2d] (rev 04)
IOMMU group 6
        00:1b.0 Audio device [0403]: Intel Corporation 7 Series/C210 Series Chipset Family High Definition Audio Controller [8086:1e20] (rev 04)
IOMMU group 7
        00:1c.0 PCI bridge [0604]: Intel Corporation 7 Series/C210 Series Chipset Family PCI Express Root Port 1 [8086:1e10] (rev c4)
IOMMU group 8
        00:1c.4 PCI bridge [0604]: Intel Corporation 7 Series/C210 Series Chipset Family PCI Express Root Port 5 [8086:1e18] (rev c4)
IOMMU group 9
        00:1c.5 PCI bridge [0604]: Intel Corporation 82801 PCI Bridge [8086:244e] (rev c4)
        04:00.0 PCI bridge [0604]: ASMedia Technology Inc. ASM1083/1085 PCIe to PCI Bridge [1b21:1080] (rev 03)
        05:00.0 USB controller [0c03]: VIA Technologies, Inc. VT82xx/62xx UHCI USB 1.1 Controller [1106:3038] (rev 62)
        05:00.1 USB controller [0c03]: VIA Technologies, Inc. VT82xx/62xx UHCI USB 1.1 Controller [1106:3038] (rev 62)
        05:00.2 USB controller [0c03]: VIA Technologies, Inc. USB 2.0 [1106:3104] (rev 65)
IOMMU group 10
        00:1d.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 [8086:1e26] (rev 04)
IOMMU group 11
        00:1f.0 ISA bridge [0601]: Intel Corporation H77 Express Chipset LPC Controller [8086:1e4a] (rev 04)
        00:1f.2 SATA controller [0106]: Intel Corporation 7 Series/C210 Series Chipset Family 6-port SATA Controller [AHCI mode] [8086:1e02] (rev 04)
        00:1f.3 SMBus [0c05]: Intel Corporation 7 Series/C210 Series Chipset Family SMBus Controller [8086:1e22] (rev 04)
IOMMU group 12
        02:00.0 Multimedia controller [0480]: Altera Corporation Device [1172:4c15] (rev 01)
IOMMU group 13
        03:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 09)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;となっています。GPUはIOMMU group 1です。USBは、結局使ってないもののPCIでUSB2.0ポートを増設してしまっていたり、背面ポートと前面用のポートが別のコントローラにぶら下がってたりして見にくいですが、IOMMU group 10とIOMMU group 5をゲストに渡します。&lt;/p&gt;

&lt;h2 id="linux"&gt;ホストのLinuxの設定&lt;/h2&gt;

&lt;p&gt;わたしの環境は&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;カーネルを自分でビルド&lt;/li&gt;
  &lt;li&gt;initramfsは使わない&lt;/li&gt;
  &lt;li&gt;systemdで起動&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;というものです。ディストリビューションはGentoo Linuxですが、ディストリビューション依存の設定は特に行っていません。&lt;/p&gt;

&lt;h3 id="section-4"&gt;カーネルコンフィグ・モジュール読み込み&lt;/h3&gt;

&lt;p&gt;QEMU-KVMに必要なオプションは&lt;a href="https://wiki.gentoo.org/wiki/QEMU"&gt;QEMU - Gentoo Wiki&lt;/a&gt;に書いてます。PCIパススルーに関係するコンフィグは&lt;a href="https://wiki.installgentoo.com/index.php/PCI_passthrough"&gt;PCI passthrough - InstallGentoo Wiki&lt;/a&gt;を参考に&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CONFIG_INTEL_IOMMU y&lt;/li&gt;
  &lt;li&gt;CONFIG_IRQ_REMAP y&lt;/li&gt;
  &lt;li&gt;CONFIG_VFIO m&lt;/li&gt;
  &lt;li&gt;CONFIG_VFIO_PCI m&lt;/li&gt;
  &lt;li&gt;CONFIG_VFIO_PCI_VGA y&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;とします（Intel CPUの場合）。&lt;/p&gt;

&lt;p&gt;さらに&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CONFIG_INTEL_IOMMU_DEFAULT_ON&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;も有効にすることで起動時のカーネルオプションが不要となります。&lt;/p&gt;

&lt;p&gt;vfio-pciモジュール読み込み、モジュールへのオプション指定、VFIO fdのパーミッション設定を行います。&lt;/p&gt;

&lt;p&gt;
  &lt;code&gt;/etc/modules-load.d/pci-thru.conf&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;vfio-pci
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;code&gt;/etc/modprobe.d/pci-thru.conf&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;options vfio-pci ids=10de:1380,10de:0fbc,8086:1e26,8086:1e2d
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;code&gt;/etc/udev/rules.d/10-vfio.rules&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SUBSYSTEM=="vfio", OWNER="root", GROUP="kvm"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;そして、vfio-pciモジュールが指定されたPCIデバイスを先に制御下に置くことができるよう、パススルーするデバイスに対応するモジュールをカーネル組み込みから外します。わたしの場合は&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CONFIG_SND_HDA_INTEL&lt;/li&gt;
  &lt;li&gt;CONFIG_USB_XHCI_HCD&lt;/li&gt;
  &lt;li&gt;CONFIG_USB_EHCI_HCD&lt;/li&gt;
  &lt;li&gt;CONFIG_USB_UHCI_HCD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;をモジュールにすることとなります。またNVidiaのグラフィックドライバは、オープンソース・プロプライエタリなもの両方とも消しました。&lt;/p&gt;

&lt;p&gt;こういうアドホックなカーネルコンフィグをしなくても、オプションを適当に渡すとか後からモジュールをunbindするとかすれば大丈夫なようです（&lt;a href="https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF"&gt;PCI passthrough via OVMF - ArchWiki&lt;/a&gt;など参考）。&lt;/p&gt;

&lt;h3 id="section-5"&gt;ネットワーク周り&lt;/h3&gt;

&lt;p&gt;仮想マシンをLANに公開したかったので、ブリッジの下にTAPインターフェースをぶら下げることにします。TAPインターフェースの説明は&lt;a href="https://www.kernel.org/doc/Documentation/networking/tuntap.txt"&gt;Linuxカーネルソース添付のtuntap.txt&lt;/a&gt;など。&lt;/p&gt;

&lt;p&gt;まずブリッジを作って物理NICを入れて、ブリッジインターフェースにIPアドレスを割り当てます。&lt;/p&gt;

&lt;p&gt;
  &lt;code&gt;/etc/systemd/network/00-bridge.netdev&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[NetDev]
Name=br0
Kind=bridge
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;code&gt;/etc/systemd/network/10-eth-bridge.network&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[Match]
Name=eth0

[Network]
Bridge=br0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;code&gt;/etc/systemd/network/50-bridge-static.network&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[Match]
Name=br0

[Network]
Address=192.168.1.40/24
Gateway=192.168.1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;QEMUのWikiには、&lt;a href="http://wiki.qemu.org/Features-Done/HelperNetworking"&gt;適当なオプションを付けてQEMUを実行したら、non-rootユーザーからでも自動でTAPインターフェースを作ってブリッジに入れることができる&lt;/a&gt;と書いていますが、&lt;a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=766664#15"&gt;Debianではセキュリティを懸念してqemu-bridge-helperのsetuidを外しているのでrootでしか使えない&lt;/a&gt;ようで、Gentooでもsetuidは外れていました。あんまりrootで起動したくなかったので、自分でkvmグループからアクセスできるTAPインターフェースを作っておきます。&lt;/p&gt;

&lt;p&gt;
  &lt;code&gt;/etc/systemd/network/00-tap.network&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[NetDev]
Name=tap0
Kind=tap
User=root
Group=kvm
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
  &lt;code&gt;/etc/systemd/network/10-tap-bridge.network&lt;/code&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[Match]
Name=tap0

[Network]
Bridge=br0
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="qemu"&gt;QEMUの起動&lt;/h3&gt;

&lt;p&gt;QEMUのオプションは正直なところアレでした。短いけど汎用性のない古いオプションと、より汎用的な新しいオプションがあります。暗黙に色んなことが設定されて、それを上書きしたり、取り消したりするオプションが色々あります。こういう指定をするときにこう書くというパターンが確立されてるわけでもなさそうで、人によってバラバラです。ユーザーガイドに載っていないことも結構あります。直接起動するよりlibvirtを使うのがいいのかもしれません。&lt;/p&gt;

&lt;p&gt;ともあれ、わたしの起動スクリプトは以下です。&lt;/p&gt;

&lt;div class="language-sh highlighter-rouge"&gt;
  &lt;div class="highlight"&gt;
    &lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="c"&gt;## to add the optical drive&lt;/span&gt;
&lt;span class="c"&gt;# device_add scsi-block,bus=scsi0.0,drive=sr0dr,id=sr0&lt;/span&gt;
&lt;span class="c"&gt;## to remove the optical drive&lt;/span&gt;
&lt;span class="c"&gt;# device_del sr0&lt;/span&gt;

qemu-system-x86_64 &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-nographic&lt;/span&gt; &lt;span class="nt"&gt;-nodefaults&lt;/span&gt; &lt;span class="nt"&gt;-monitor&lt;/span&gt; stdio &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-rtc&lt;/span&gt; &lt;span class="nv"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localtime &lt;span class="nt"&gt;-enable-kvm&lt;/span&gt; &lt;span class="nt"&gt;-cpu&lt;/span&gt; host,kvm&lt;span class="o"&gt;=&lt;/span&gt;off &lt;span class="nt"&gt;-smp&lt;/span&gt; 3 &lt;span class="nt"&gt;-m&lt;/span&gt; 4096 &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/edk2/Build/OvmfX64/DEBUG_GCC49/FV/OVMF.fd"&lt;/span&gt;,readonly,if&lt;span class="o"&gt;=&lt;/span&gt;pflash &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sdb,format&lt;span class="o"&gt;=&lt;/span&gt;raw,cache&lt;span class="o"&gt;=&lt;/span&gt;none,if&lt;span class="o"&gt;=&lt;/span&gt;virtio &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-device&lt;/span&gt; virtio-scsi-pci,id&lt;span class="o"&gt;=&lt;/span&gt;scsi0 &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-drive&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/sr0,format&lt;span class="o"&gt;=&lt;/span&gt;raw,cache&lt;span class="o"&gt;=&lt;/span&gt;none,if&lt;span class="o"&gt;=&lt;/span&gt;none,id&lt;span class="o"&gt;=&lt;/span&gt;sr0dr &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-vga&lt;/span&gt; none &lt;span class="nt"&gt;-device&lt;/span&gt; vfio-pci,host&lt;span class="o"&gt;=&lt;/span&gt;01:00.0,x-vga&lt;span class="o"&gt;=&lt;/span&gt;on &lt;span class="nt"&gt;-device&lt;/span&gt; vfio-pci,host&lt;span class="o"&gt;=&lt;/span&gt;01:00.1 &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-device&lt;/span&gt; vfio-pci,host&lt;span class="o"&gt;=&lt;/span&gt;00:1a.0 &lt;span class="nt"&gt;-device&lt;/span&gt; vfio-pci,host&lt;span class="o"&gt;=&lt;/span&gt;00:1d.0 &lt;span class="se"&gt;\&lt;/span&gt;
	&lt;span class="nt"&gt;-netdev&lt;/span&gt; tap,id&lt;span class="o"&gt;=&lt;/span&gt;vmnic,ifname&lt;span class="o"&gt;=&lt;/span&gt;tap0,script&lt;span class="o"&gt;=&lt;/span&gt;no,downscript&lt;span class="o"&gt;=&lt;/span&gt;no &lt;span class="nt"&gt;-device&lt;/span&gt; virtio-net,netdev&lt;span class="o"&gt;=&lt;/span&gt;vmnic
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;code&gt;-drive file=/dev/sdb,format=raw,cache=none&lt;/code&gt; という指定は、&lt;code&gt;/dev/sdb&lt;/code&gt; として認識されているSSD一枚を丸ごと仮想マシンに割り当てるための設定です。
光学ドライブ関係は&lt;a href="#scsi-thru"&gt;後で&lt;/a&gt;書きます。&lt;/p&gt;

&lt;h3 id="windows"&gt;Windowsのインストール&lt;/h3&gt;

&lt;p&gt;WindowsにはvirtioドライバがないのでRedHatが署名したドライバを入れる必要があったり、Windows 10へのアップグレードが上手くいかなかったりします。&lt;a href="https://wiki.archlinux.org/index.php/QEMU#Preparing_a_Windows_guest"&gt;QEMU - ArchWiki: Preparing a Windows guest&lt;/a&gt;に書いてます。&lt;/p&gt;

&lt;h3 id="scsiscsi-thru"&gt;
  &lt;a href="#scsi-thru"&gt;SCSIパススルー&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;virtioでHDDや光学ディスクドライブを半仮想化する方法として、半仮想化されたブロックデバイスをゲストに見せるvirtio-blkと、半仮想化されたSCSIコントローラをゲストに見せるvirtio-scsiがあります。SCSIパススルーに使うのは後者です。&lt;code&gt;/dev/sdX&lt;/code&gt; とか &lt;code&gt;/dev/srX&lt;/code&gt; とかをファイル名として指定してやると、自動的にSCSIコマンドのパススルーが行われます。&lt;/p&gt;

&lt;p&gt;しかしメディアが入っていない光学ドライブを指定して起動できなかったりと、メディアの出し入れ周りが完全にはならないようです。なのでQEMUのホットプラグ機能を用いて、&lt;code&gt;device_add&lt;/code&gt; コマンドと &lt;code&gt;device_del&lt;/code&gt; コマンドでデバイス自体を付けたり外したりすることで動かしました。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2016-05-21:/pages/dc1</id>
    <title type="html">近況・DC1</title>
    <published>2016-05-21T22:45:36Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/dc1" type="text/html"/>
    <content type="html">&lt;p&gt;ここしばらく、論文やら、学振DC1（博士課程生が生活費と研究費をもらえる制度）の申請書やらを書いていて、疲れました。金くれ。
具体的な申請書を上げたりはしませんが、知ってる人になら、言ってくれれば多分見せます。&lt;/p&gt;

&lt;p&gt;だいたい申請書を書くのに三週間近くかかりました。
なんとなく埋めるのは割とすぐでしたが、あれこれとやっていると専攻内の締切の一日後まで割とかかりっきりになってしまったという感じです。
熱い戦いを振り返ってみますが、他の人の参考になるかはわからないです。&lt;/p&gt;

&lt;h2 id="section"&gt;申請書を書く上でつらかったこと&lt;/h2&gt;
&lt;p&gt;筋を立てるつらさが3割、枠に収めるつらさが7割でした。
既存研究を調べるのにも時間は使いましたが、楽しかったのでつらくはなかったです。&lt;/p&gt;

&lt;p&gt;筋を立てるというのは、まず第一に研究計画に軸線を立てて目標をはっきり定めるということです。
なんとなくやりたい研究はあるものの、なんとなくやりたいと書くだけでは当然ダメです。
始めから筋がはっきりしている人もいるでしょうけど、わたしの場合は意識的に筋を通す必要がありました。
それからこれまでの研究の背景なんかも、そうやって通した筋に沿うように書くことになります。
もちろん研究内容はやったことを素直に書けばいいのですが、どの問題意識を重点的に書くべきかなどは、これからの計画によって変わってくるかと思います。&lt;/p&gt;

&lt;p&gt;後は枠です。
書きたいことを書いたら枠はさっさと埋まってしまいました。
これを、内容を取捨し、言い回しを取っかえ引っかえして、またパッと見の印象があまりと黒々と詰まりすぎないように、削っていくことになります。
図表もギリギリまで調整することになって、ことはミリメートル以下を争います。
PDFファイルを画面に表示すると線をピクセルにフィットさせてレンダリングされるので微妙な配置がわからなくて、高解像度ディスプレイがあると便利なのにと心底から思いました。
この作業を締切前日まで行ったのが、つらさの3.5割でした。残りの3.5割は後にでてきます。&lt;/p&gt;

&lt;h2 id="section-1"&gt;散歩&lt;/h2&gt;
&lt;p&gt;六義園を散歩しました。
小高く築かれた丘から、緑の狭間にさっと水辺に架かる橋が見はるかせたのは圧巻でした。
よくも計算して造られているなあと、申請書もこう計算して書かれるべきであると、書類に追われる身には感じられました。
それから、なんかそのへんの道端にいるのよりも、鳩が綺麗な気がするんですよね。
食べてるものが違うのかもしれないですし、気のせいかもしれないですが。
この鳩のように、美しいところに居られる美しい存在であれたらと思いがよぎりました。
だけど、きっとそう在れるのはほんのひと握り。&lt;/p&gt;

&lt;h2 id="section-2"&gt;炎上&lt;/h2&gt;
&lt;p&gt;申請書が一通り完成した締切前日の夕方に、フォントサイズが規定よりも小さくなっていたことが発覚しました。
原因は、ドキュメントクラスとして元々jarticleを使うようになっていたのを(lt)jsarticleを使うように変更したことです。
どうもプリアンブルにあったフォントサイズ指定が効かなくなっていたようです。
とりあえず、疲れたので寝るとメールを送ってふて寝をしました。&lt;/p&gt;

&lt;p&gt;あくる締切当日に、フォントサイズを上げるように設定を行いました。
幸いにも行間はそれなりに空いていたので、行幅を変えずにフォントサイズを上げることはできます。
とにかく早く終わらせることを優先して、フォントサイズ指定が効かない原因を調べないままfontspecのscaleオプションでごまかしました。
やってみると、ほぼあらゆる段落が一行ずつ伸びて悲惨なことになっています。&lt;/p&gt;

&lt;p&gt;それからは、事務室に一日遅れるとお詫びを入れた上で、ひたすらにあらゆる段落を縮めました。
言い回しを変えたり、内容を減らしたり、別の段落に内容を移動させたり、段落をマージしたり、まあ色々としました。
これが最後の一日に降りかかってきた、つらさの3.5割です。
おかげで深夜4時半くらいには全体が完成して、昼に起き出してから目が覚めた頭で見返して修正し、なんとか締切翌日には提出することができました。&lt;/p&gt;

&lt;h2 id="section-3"&gt;その他申請書の内容について&lt;/h2&gt;
&lt;p&gt;基本的な戦術としては、「こいつは凡百な研究をしているわけではないっぽい、これを落としてはいけない」、と思わせる圧倒力を狙いました。
ちょっと高密に書いたので、読む側としては大変かもしれないと少し申し訳なくはあります。
ただ、それだけを理由として落とされることはないかなあと。
漢字のひらき具合などは学振の書類と同じくらいを意識しましたが、別に申請内容の言葉は書類のメタな言葉とは違うので、あとからするとそんな意識はいらなかったなと思っています。&lt;/p&gt;

&lt;p&gt;DC1・DC2で書かないといけない自己評価は、どんな人材が求められていることは意識しつつも、わりかし正直に思っていることを書きました。
小説家でもない凡庸には、正直に思っていなければパワーのある文が出てこないもので、そういうパワーは投げつけてもいいかなあと。
まあ、自分の良いっぽいところを見てゴーマンなことを書くことにはなります。
あとは一般的なこととして、逐一あざとく主張には理由をつけるということも意識しました。&lt;/p&gt;

&lt;h2 id="section-4"&gt;締切を終えての感想&lt;/h2&gt;
&lt;p&gt;この前の論文の締切よりは体力的には全然マシでしたが、精神的にはきびしいタイプの締切でした。
やりたくないなあという思いが強いです。&lt;/p&gt;

&lt;p&gt;特に最後の炎上のようなものは、それ自体は鎮火できたのでもういいのですが、どうやってこれから防げばいいのやらと思うとむずかしいです。
自分としては当たり前のように使いなれた文書クラスに設定しただけで、そこに大きな問題があるとは全く考えていませんでした。
当然同じミスは今後しないでしょうが、どうしたって本質的に同じような見落としを自分一人でなくせるとは考えにくいです。
わたしの作業を随時みてくれる人がだれか居ればそれで済むのですが、そんなことを好き好んでするような人もいないですし。
どれくらいの出力を求められるような生活するかは考えたほうがよくて、とくに自分は各能力の差がはげしいので、上側に合わせすぎないようにすべきでないかとも思った次第です。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2015-06-30:/pages/natsu</id>
    <title type="html">natsu</title>
    <published>2015-06-30T16:38:27Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/natsu" type="text/html"/>
    <content type="html">&lt;p&gt;また夏が通りがかる。スローモーションの縄跳びが足をすくうように。ぼくは跳ぶ必要がない、なぜならずっと浮いているから。ぼくは悲しい。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2015-03-10:/pages/varphi</id>
    <title type="html">φ</title>
    <published>2015-03-10T18:46:50Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/varphi" type="text/html"/>
    <content type="html">&lt;p&gt;
  &lt;img src="varphi_res/varphi.jpg" alt="alt=&amp;quot;\varphi&amp;quot;" /&gt;
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2015-03-10:/pages/shrine-tabata-sta</id>
    <title type="html">Shrine（JR東日本 田端駅）</title>
    <published>2015-03-10T18:42:53Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/shrine-tabata-sta" type="text/html"/>
    <content type="html">&lt;p&gt;
  &lt;img src="shrine-tabata-sta_res/shrine-tabata-sta.jpg" alt="alt=&amp;quot;&amp;#x767A;&amp;#x5149;&amp;#x3059;&amp;#x308B;&amp;#x9244;&amp;#x306E;&amp;#x9CE5;&amp;#x5C45;&amp;quot;" /&gt;
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2015-03-07:/pages/ELECOM-WDC-433SU2M-Linux-x64</id>
    <title type="html">x86_64 Linux上でELECOM WDC-433SU2Mを用いて802.11acな通信を実現する</title>
    <published>2015-03-07T13:41:50Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/ELECOM-WDC-433SU2M-Linux-x64" type="text/html"/>
    <content type="html">&lt;p&gt;追記：カーネルのバージョンは3.18.0で試しました。 &lt;a href="http://nosada.hatenablog.com/entry/2014/06/10/003913"&gt;3.18系では動作するものの3.19.1ではコンパイルが通らないようです。コメント欄参照。&lt;/a&gt; &lt;a href="http://nosada.hatenablog.com/"&gt;id:nosada&lt;/a&gt; さん、ありがとうございます。&lt;/p&gt;

&lt;p&gt;バイト先のオフィスがフロアのEthernetケーブルをなくしてWi-Fiメインにすることになったので、Wi-Fiでそこそこ高速に安定した通信を行う必要があり試した結果です。Macbook ProにGentoo Linuxを入れて使っているのですが、これまでは基本的に有線LANで運用していました。Macbook内臓のBroadcomのWi-Fiチップのドライバが、プロプライエタリなものは不安定でオープンソースのものは遅かったので。&lt;/p&gt;

&lt;p&gt;さて、WDC-433SU2Mが使っているチップはRalinkという会社のもので、この会社は今はMediaTekという会社に買収されています。MediaTekはLinux向けのドライバのソースを公開しているので、そのドライバを適当にデバイスIDなど書き換えた上で使えばよさそうです。既に、 &lt;a href="http://nosada.hatenablog.com/entry/2014/05/31/184741"&gt;Elecom WDC-433SU2Mで802.11acな通信を実現したかった - テクニカルプア&lt;/a&gt; および &lt;a href="http://nosada.hatenablog.com/entry/2014/06/10/003913"&gt;Elecom WDC-433SU2Mで802.11acな通信を実現したのかわからないけどとりあえず動いた - テクニカルプア&lt;/a&gt; に手順などが記載されています。&lt;/p&gt;

&lt;p&gt;ただし、そこで二つ問題があります。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;ドライバのソースが64bit対応されていない&lt;/li&gt;
  &lt;li&gt;802.11acに対応する設定方法がドキュメントに記載されていない&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上でリンクした記事においても、この問題でハマっていました。&lt;/p&gt;

&lt;p&gt;64bit対応に関しては、幸いにも &lt;a href="https://bitbucket.org/sanrath/mediatek_mt7610u_sta_driver_linux-64bit"&gt;有志によって64bit対応されたドライバ&lt;/a&gt; がGitリポジトリとして公開されているので、そちらを用いました。自分が用いたコミットはbe2e5d4です。&lt;/p&gt;

&lt;p&gt;また、ソースコードを見たところ実際には802.11acに対応しているようで、ソースコードから推測した以下の設定を行いました。&lt;/p&gt;

&lt;p&gt;具体的には、64bit対応されたドライバに対して以下のパッチを当てました。&lt;/p&gt;

&lt;div class="language-patch highlighter-rouge"&gt;
  &lt;div class="highlight"&gt;
    &lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/Makefile b/Makefile
index 25d87aa..f1e8fa5 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/Makefile
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/Makefile
&lt;/span&gt;&lt;span class="p"&gt;@@ -14,7 +14,7 @@&lt;/span&gt; endif
 # rt8592(for rt85592), mt7650e, mt7630e, mt7610e, mt7650u, mt7630u, mt7610u
 
 ifeq ($(CHIPSET),)
&lt;span class="gd"&gt;-CHIPSET = mt7610u
&lt;/span&gt;&lt;span class="gi"&gt;+CHIPSET = mt7650u mt7630u mt7610u
&lt;/span&gt; endif
 
 MODULE = $(word 1, $(CHIPSET))
&lt;span class="p"&gt;@@ -196,9 +196,10 @@&lt;/span&gt; endif
 
 ifeq ($(PLATFORM),PC)
 # Linux 2.6
&lt;span class="gd"&gt;-LINUX_SRC = /lib/modules/$(shell uname -r)/build
&lt;/span&gt;&lt;span class="gi"&gt;+#LINUX_SRC = /lib/modules/$(shell uname -r)/build
&lt;/span&gt; # Linux 2.4 Change to your local setting
 #LINUX_SRC = /usr/src/linux-2.4
&lt;span class="gi"&gt;+LINUX_SRC = /usr/src/linux-$(shell uname -r)
&lt;/span&gt; LINUX_SRC_MODULE = /lib/modules/$(shell uname -r)/kernel/drivers/net/wireless/
 CROSS_COMPILE = 
 endif
&lt;span class="gh"&gt;diff --git a/common/rtusb_dev_id.c b/common/rtusb_dev_id.c
index 061362a..fb7bf4d 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/common/rtusb_dev_id.c
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/common/rtusb_dev_id.c
&lt;/span&gt;&lt;span class="p"&gt;@@ -38,6 +38,7 @@&lt;/span&gt; USB_DEVICE_ID rtusb_dev_id[] = {
 #ifdef MT76x0
 	{USB_DEVICE(0x148F,0x7610)}, /* MT7610U */
 	{USB_DEVICE(0x13B1,0x003E)}, /* MT7610U */
&lt;span class="gi"&gt;+	{USB_DEVICE(0x7392,0xb711)}, /* WDC-433SU2M */
&lt;/span&gt; 	{USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7630, 0xff, 0x2, 0xff)}, /* MT7630U */
 	{USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7650, 0xff, 0x2, 0xff)}, /* MT7650U */
 #endif
&lt;span class="gh"&gt;diff --git a/conf/RT2870STA.dat b/conf/RT2870STA.dat
index 0240bd5..172df59 100644
&lt;/span&gt;&lt;span class="gd"&gt;--- a/conf/RT2870STA.dat
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/conf/RT2870STA.dat
&lt;/span&gt;&lt;span class="p"&gt;@@ -1,12 +1,12 @@&lt;/span&gt;
 #The word of "Default" must not be removed
 Default
&lt;span class="gd"&gt;-CountryRegion=5
-CountryRegionABand=7
-CountryCode=
&lt;/span&gt;&lt;span class="gi"&gt;+CountryRegion=1
+CountryRegionABand=1
+CountryCode=JP
&lt;/span&gt; ChannelGeography=1
&lt;span class="gd"&gt;-SSID=11n-AP
&lt;/span&gt;&lt;span class="gi"&gt;+SSID=
&lt;/span&gt; NetworkType=Infra
&lt;span class="gd"&gt;-WirelessMode=8
&lt;/span&gt;&lt;span class="gi"&gt;+WirelessMode=14
&lt;/span&gt; EfuseBufferMode=0
 Channel=0
 BeaconPeriod=100
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;802.11acに対応するための設定は、RT2870STA.datでのWirelessMode=14の部分です。同ファイルにおけるCountry周りの設定は日本で使うことが許されている周波数帯を指定するものです。MakefileにおけるLINUX_SRCの設定はGentoo Linux依存のものなので、環境によっては必要ありません。&lt;/p&gt;

&lt;p&gt;この上で、makeしてmake installすれば上手く動作しました。スピードテストの結果802.11acで動作しているであろうことが確認できました。また、しばらく使った感じだと、どうも三日に一回くらい落ちてしまう（抜いて挿し直させば復活する）のですが、それ以外は安定して動いているようです。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2015-01-07:/pages/kobe150104</id>
    <title type="html">神戸 150104</title>
    <published>2015-01-07T19:09:01Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/kobe150104" type="text/html"/>
    <content type="html">&lt;p&gt;
  &lt;img src="kobe150104_res/kobe-suberidai.jpg" alt="alt=&amp;quot;&amp;#x591C;&amp;#x306E;&amp;#x516C;&amp;#x5712;&amp;#x306B;&amp;#x3042;&amp;#x308B;&amp;#x6ED1;&amp;#x308A;&amp;#x53F0;&amp;quot;" /&gt;
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-10-30:/pages/kissing-number</id>
    <title type="html">二次元の場合の接吻数問題を算数で</title>
    <published>2014-10-30T02:18:38Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/kissing-number" type="text/html"/>
    <content type="html">&lt;p&gt;接吻数問題（Kissing Number Problem）と呼ばれる問題があるそうだ。Wikipediaでは「（n 次元）接吻数問題（せっぷんすうもんだい、kissing number problem）とは『n次元の単位球の周りに単位球を重ならず触れ合うように並べるとき、最大何個並べることができるか』という問題である。その個数のことを接吻数という。」と述べられている。二次元の場合は、もちろん円の周りを6つの円で囲うのが解であるから、接吻数は6である。&lt;/p&gt;

&lt;p&gt;この二次元の場合の接吻数問題を中学入試程度の算数の問題にできないかとこの前考えていた。算数の問題であるから、三角関数や三平方の定理を使ってはいけない。考えてみた結果、なんとかできそうだった。&lt;/p&gt;

&lt;p&gt;誘導なしというのはちょっと厳しい気がしたので、以下のような小問に分割する。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;半径2cmの円を1つ描き，その円に接するように半径2cmの円を6つ，それぞれ重ならないように（接してもよい）描け．&lt;/li&gt;
  &lt;li&gt;任意の⊿ABCについて∠B&amp;lt;∠CならばAB&amp;gt;ACを示せ．&lt;/li&gt;
  &lt;li&gt;⊿ABC，⊿A’B’C’がAB=AC=A’B’=A’C’を満たすとする．∠A&amp;lt;∠A’ならばBC&amp;lt;B’C’を示せ．&lt;/li&gt;
  &lt;li&gt;1つの半径2cmの円に接するように，それぞれ重ならない半径2cmの円を7つ以上描けないことを示せ．&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;1.は単なる作図である。半径2cmと4cmの同心円を描いて、半径4cmの円上に頂点を持つように一辺4cmの正六角形を取って、正六角形の各頂点を中心とする半径2cmの円を書けばよい。1.をもって接吻数が6以上であることが示されたとする。&lt;/p&gt;

&lt;p&gt;2.を解くためには以下のように補助線BDを引けばよい。AD=ACが成りたつことからAB&amp;gt;ACである。&lt;/p&gt;

&lt;p&gt;
  &lt;img src="kissing-number_res/fig1.svg" alt="alt=&amp;quot;fig1&amp;quot;,height=400,width=400" /&gt;
&lt;/p&gt;

&lt;p&gt;3.は以下のような図において△CBB’について2.の結果を適用すればよい。&lt;/p&gt;

&lt;p&gt;
  &lt;img src="kissing-number_res/fig2.svg" alt="alt=&amp;quot;fig2&amp;quot;,height=400,width=400" /&gt;
&lt;/p&gt;

&lt;p&gt;4.は、ある円を取り囲む円を7つ以上描いたときに必ずどれか2つの円が重なることを示せばよい。このように円を描いたとすると、外側に描いた円の中心は、真ん中のある円の半径4cmの同心円上に載っているはずである。この同心円は、7つの頂点によって7つの扇型に分割されることとなる。もし7つの扇型の中心角が全て60°以上ならば和が360°を超えてしまうので、ある扇型について中心角は60°未満。この扇形の弦の長さは、3.の結果より中心角が60°の場合の弦の長さよりも短い。中心角が60°の場合は弦の長さは4cmであるから、弦は4cm未満ということになる。すなわち、2つの円の中心の距離が4cm未満ということとなり、このとき二つの円は重なってしまう。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-08-07:/pages/lualatexja-proportional</id>
    <title type="html">LuaLaTex-jaでプロポーショナルかなを使う</title>
    <published>2014-08-07T02:54:24Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/lualatexja-proportional" type="text/html"/>
    <content type="html">&lt;p&gt;ごたくを並べる前に、プロポーショナルかなを使う組版例を以下に示す。プロポーショナルかなを用いたのが上側、普通のかなを用いたのが下側である。&lt;/p&gt;

&lt;p&gt;
  &lt;img src=":lualatexja-proportional_res/proportional_thumb.png" alt="&amp;quot;LuaLaTex-ja&amp;#x3067;&amp;#x3042;&amp;#x3063;&amp;#x3068;&amp;#x9A5A;&amp;#x304D;&amp;#x306E;&amp;#x30D7;&amp;#x30ED;&amp;#x30DD;&amp;#x30FC;&amp;#x30B7;&amp;#x30E7;&amp;#x30CA;&amp;#x30EB;&amp;#x304B;&amp;#x306A;&amp;#x7D44;&amp;#x7248;&amp;quot;,link=&amp;quot;lualatexja-proportional_res/proportional.pdf&amp;quot;" /&gt;
&lt;/p&gt;

&lt;div class="language-tex highlighter-rouge"&gt;
  &lt;div class="highlight"&gt;
    &lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;\documentclass&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;ltjsarticle&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\usepackage&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;metalogo&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;% for \LuaLaTeX command&lt;/span&gt;
&lt;span class="k"&gt;\usepackage&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;luatexja-fontspec&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;\newopentypefeature&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;PKana&lt;span class="p"&gt;}{&lt;/span&gt;On&lt;span class="p"&gt;}{&lt;/span&gt;pkna&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c"&gt;% "PKana" and "On" can be arbitrary string&lt;/span&gt;
&lt;span class="k"&gt;\setmainjfont&lt;/span&gt;[
    JFM=prop,PKana=On,Kerning=On,
    BoldFont=&lt;span class="p"&gt;{&lt;/span&gt;YuMincho-DemiBold&lt;span class="p"&gt;}&lt;/span&gt;,
    ItalicFont=&lt;span class="p"&gt;{&lt;/span&gt;YuMincho-Medium&lt;span class="p"&gt;}&lt;/span&gt;,
    BoldItalicFont=&lt;span class="p"&gt;{&lt;/span&gt;YuMincho-DemiBold&lt;span class="p"&gt;}&lt;/span&gt;
]&lt;span class="p"&gt;{&lt;/span&gt;YuMincho-Medium&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;\begin{document}&lt;/span&gt;
&lt;span class="k"&gt;\LuaLaTeX&lt;/span&gt; で、あっと驚きのプロポーショナルかな組版。

&lt;span class="k"&gt;\jfontspec&lt;/span&gt;&lt;span class="na"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;YuMincho-Medium&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;\LuaLaTeX&lt;/span&gt; で、あっと驚きのプロポーショナルかな組版。
&lt;span class="nt"&gt;\end{document}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;好き嫌いはあるかもしれないが、プロポーショナルかなの側では、まず明らかに「っ」の横幅が小さくなっているほか、「き」が浮いている感じがなくなり「プロポーショナル」というカタカナ語のまとまりもよくなっている。&lt;/p&gt;

&lt;p&gt;’’’&lt;/p&gt;

&lt;p&gt;以下、どのようなことを行っていることを説明する。ただ、TeXにもOpenTypeにもさほど詳しくないのでいいかげんなことを書いているかもしれない（OpenTypeについては http://kanji-database.sourceforge.net/fonts/opentype.html の記載、およびそのページからリンクされている一次資料が、大いに参考になる）。&lt;/p&gt;

&lt;p&gt;まず背景として、 &lt;a href="http://sourceforge.jp/projects/luatex-ja/"&gt;LuaTeX-ja&lt;/a&gt; というpTeXに代わる日本語TeX環境を開発するプロジェクトの存在がある。LuaTeXという新しいTeXのエンジンをベースにし、Luaスクリプトによって和文組版を実現するというものである。LuaLaTex-jaにおいては、LuaTeXの持つOpenTypeやUnicodeのネイティブサポートを始めとするモダンな機能をそのまま日本語TeXで用いることができる。&lt;/p&gt;

&lt;p&gt;日本語TeX環境において、和文グリフの大きさなど（メトリクス）は、JFMと呼ばれるファイルに指定されている（なおLuaTeX-jaではJFMはLuaスクリプトである）。LuaTeX-jaの標準では和文グリフの横幅をTeXの側で固定にしているJFMファイルが使われるのだが、当然このままではプロポーショナル幅のフォントを使ったところで意味がなくなってしまうので、「フォントに指定された横幅を使う」という設定になっているJFMファイルを参照するようにしないといけない。なお、このことはLuaTeX-jaのドキュメントにも記載されている。&lt;/p&gt;

&lt;p&gt;しかし、それだけではプロポーショナルかなは使えない。游明朝体で普通にかなを使った場合に参照されるグリフは、固定幅になるよう設定されているかなグリフであるからだ。おそらく、プロポーショナルかなが使える他のOpenType書体でも同様である。フォントファイルの中に存在するプロポーショナルかなのグリフを参照するためには、“pkna”という機能（feature tag）を使いたいと指定した上で、グリフ（のCID）を別のグリフ（のCID）に置き換えるテーブル（GSUBテーブル）を引かなければいけない。技術的には縦組用かなと横組用かなの切り替えと同じである。LuaTeXはOpenTypeのfeatureの指定に対応しており、LuaTeX-jaからも使えるようになっている。&lt;/p&gt;

&lt;p&gt;ついでに、ペアカーニング機能も有効としたい。ペアカーニング機能は、特定の文字が並んだときに横幅を調整する機能である。欧文では一般的で、たとえば“AW”は横幅が詰められる。こちらも、GSUBテーブルで設定するというわけではないのだが、おおむね同様にOpenTypeの“kern”というfeatureを指定することで対応できる。&lt;/p&gt;

&lt;p&gt;さて、ここまではplain TeXの話である。(Lua)LaTeXで使う上ではfontspecの枠組みの中でプロポーショナルかなを使えるようにしたいところである。fontspecではOpenTypeのfeatureを直接指定する代わりにあらかじめ定義されたオプションをfontspecに与えるようになっている。kernに相当するオプションはKerningなのだが、pknaに相当するオプションは現状定義されていので、こちらは自分でオプションを定義してやる必要がある。すると残りはJFMである。和文フォントの指定のためには素のfontspecではなくLuaLaTeX-jaが提供するluatexja-fontspecを用いることとなる。luatexja-fontspecは、実はJFMをオプションとして指定できるようになっている。&lt;/p&gt;

&lt;p&gt;ここまでの内容を全部TeXで書くと、上のLuaLaTeX-jaのソースとなる。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-06-10:/pages/slow-fib</id>
    <title type="html">指数時間かかるけれども空間消費量がほぼ定数（厳密にはO(n)）のフィボナッチ数計算</title>
    <published>2014-06-10T07:18:09Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/slow-fib" type="text/html"/>
    <content type="html">&lt;p&gt;再帰による実装ではスタックに途中結果を保持することで木構造を葉から根に辿るような順序で加算するが、そうではなく加算の順序をスケジュールして1ずつ加算するようにすれば可能。ステートを保持するためのスタックのようなものはどうしても必要になるが、計算結果を保持する必要は無く1bitしか取らずに済む。&lt;/p&gt;

&lt;div class="language-scheme highlighter-rouge"&gt;
  &lt;div class="highlight"&gt;
    &lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib-naive&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib-naive&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib-naive&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib-scheduled&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;define&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="nv"&gt;prev&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;cond&lt;/span&gt;
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;even?&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;quotient&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;quotient&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;prev&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;even?&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;quotient&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;quotient&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;prev&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;display&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib-naive&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;newline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;display&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fib-scheduled&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;newline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-06-10:/pages/cabbage-no-shinseikatsu</id>
    <title type="html">キャベツの新生活 有吉玉青</title>
    <published>2014-06-10T06:35:46Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/cabbage-no-shinseikatsu" type="text/html"/>
    <content type="html">&lt;p&gt;偶然立ち寄った新橋の古書祭りで文庫を眺めていたら、タイトルが面白いので手にとってしまった本。カバーも綺麗で良いですね。読んでみるとかなりの当たりでした。&lt;/p&gt;

&lt;p&gt;どうして生きているのか。自分は何者なのか。そんな問いかけに高尚な自己実現だなんて題目を振りかざすのではなく、ただ生活を通じて自分自身の過去から何かを見出そうとする姿勢が見られます。真っさらなデザイナーズマンションで家具を買おうとするも、さてここからどんな部屋にだってできるのだと思うと、何も決められない。椅子を買おうとインテリアショップを巡ってみて、どれもこれもしっくり来ない。そんな情けないようなおかしいような話に、自分をどこにも定位できないという難問が重ね合わされる。個人的にはなかなかに好きです。&lt;/p&gt;

&lt;p&gt;ただ異性愛絶対という感があるのがどうしても引っかかったけれど、そこは本質ではないと思って読めば十分に楽しく読めました。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-05-27:/pages/coq-first</id>
    <title type="html">Coqに入門</title>
    <published>2014-05-27T00:26:20Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/coq-first" type="text/html"/>
    <content type="html">&lt;p&gt;前からやりたいと思っていたCoqを初めてみる。心が沈んで何もする気がしなかったのだけれど、夜の12時くらいに何となくCoqを書き出してみると、久しぶりに味わうような高揚感があり気がつくと朝に。自分の単純さがちょっとおかしくなる。&lt;/p&gt;

&lt;p&gt;入門となる資料としては、主に &lt;a href="http://www.cis.upenn.edu/~bcpierce/sf/"&gt;Software Foundations&lt;/a&gt; を参考にしたのだけれど、どうも古いバージョンに基づいた記述なのか、そのままじゃ動かないところがあった。&lt;/p&gt;

&lt;p&gt;Software Foundationsに載っているExerciseを一つ一つやるのも面倒くさかったので、Proof By Inductionの &lt;a href="http://www.cis.upenn.edu/~bcpierce/sf/Induction.html#lab48"&gt;Advanced Exercise&lt;/a&gt; として載っていた、SuccとZeroによる自然数の表現と二進数としての表現の間の変換が正しいことの証明を行ってみることに。二進表現の一番上の桁に無駄に0が入ってしまわないように正規化しないと同じ自然数に複数の二進表現が対応してしまう。Exerciseでは列表現を二進表現にしてまた列表現に戻して元の表現になることだけを示せば良いのでこのことは問題にならないが、さらに正規化されているなら二進表現を列表現にしてまた二進表現にして元の表現が帰ることを確かめる証明も自分で行った。&lt;/p&gt;

&lt;p&gt;とりあえず証明のコード。試行錯誤で書いてみたが、全然綺麗に書けていない。CoqIDEを使うと仮定の中身を示してくれるので仮定の名前を適当にしたまま証明が書けてしまうが、後から読み返すと読みづらい。あと、途中まで簡約した上でrewriteすれば済むところを、rewriteの対象となるtermおよびrewriteに用いるequationの両方をsimplしてからrewriteしているところがあるのだけど、途中まで簡約するのはどうするのだろうか、もしくはこういうのはsimplしてしまうのが一般的なのだろうか？&lt;/p&gt;

&lt;p&gt;話がそれるけれど、GNU Source-highlightはCoqに対応していないのね……。Camlのシンタックスハイライト扱いにしてお茶を濁したけれど、Pygmentを使ってみるのも良いのかもしれない。&lt;/p&gt;

&lt;div class="language-ocaml highlighter-rouge"&gt;
  &lt;div class="highlight"&gt;
    &lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nc"&gt;Inductive&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nc"&gt;Eb&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Sb&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Fixpoint&lt;/span&gt; &lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt;
  &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Eb&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Sb&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Fixpoint&lt;/span&gt; &lt;span class="n"&gt;succ_bin&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt;
  &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Eb&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Sb&lt;/span&gt; &lt;span class="nc"&gt;Eb&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Sb&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Sb&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succ_bin&lt;/span&gt; &lt;span class="n"&gt;b'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Fixpoint&lt;/span&gt; &lt;span class="n"&gt;nat_to_bin&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt;
  &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Eb&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;succ_bin&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nat_to_bin&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Lemma&lt;/span&gt; &lt;span class="n"&gt;plus_n_Sm&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nat&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;intros&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;induction&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;IHn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="nn"&gt;Qed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Lemma&lt;/span&gt; &lt;span class="n"&gt;homo_succ&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;succ_bin&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;intros&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;induction&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nat&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;intros&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;induction&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;plus_n_Sm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;IHb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;H&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="nn"&gt;Qed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Theorem&lt;/span&gt; &lt;span class="n"&gt;id_nat_bin_nat&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nat&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nat_to_bin&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;intros&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;induction&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;homo_succ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;IHn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="nn"&gt;Qed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Inductive&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Prop&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;regular_se&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Sb&lt;/span&gt; &lt;span class="nc"&gt;Eb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;regular_zind&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;regular_sind&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Sb&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Lemma&lt;/span&gt; &lt;span class="n"&gt;homo_double_z&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;nat&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nat_to_bin&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Eb&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;S&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nat_to_bin&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;destruct&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;induction&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="n"&gt;plus_n_Sm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;simpl&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;IHn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="nn"&gt;IHn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="nn"&gt;Qed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Lemma&lt;/span&gt; &lt;span class="n"&gt;regular_z&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Eb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;intros&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;destruct&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;simpl&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;destruct&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;induction&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

      &lt;span class="n"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;simpl&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;destruct&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nc"&gt;IHb&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nn"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="nn"&gt;Qed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nc"&gt;Theorem&lt;/span&gt; &lt;span class="n"&gt;id_bin_nat_bin&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;forall&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regular_bin&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;nat_to_bin&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;intros&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;intros&lt;/span&gt; &lt;span class="nn"&gt;H&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="n"&gt;induction&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;destruct&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

      &lt;span class="n"&gt;pose&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nc"&gt;IHb&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="n"&gt;homo_double_z&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; 
      &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;unfold&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;intros&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;regular_z&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;exact&lt;/span&gt; &lt;span class="nn"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;case_eq&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;intros&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;unfold&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nc"&gt;H2&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;intuition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
          &lt;span class="n"&gt;intros&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nn"&gt;H3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

      &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nc"&gt;IHb&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="n"&gt;homo_double_z&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;simpl&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

    &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
      &lt;span class="n"&gt;destruct&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

        &lt;span class="n"&gt;intros&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="n"&gt;homo_double_z&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;case_eq&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bin_to_nat&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Zb&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
          &lt;span class="n"&gt;intros&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="n"&gt;regular_z&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;inversion&lt;/span&gt; &lt;span class="nn"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;exact&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
          &lt;span class="n"&gt;intros&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="nn"&gt;H2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nc"&gt;IHb&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;

        &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nc"&gt;IHb&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="n"&gt;homo_double_z&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;simpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="n"&gt;simpl&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;rewrite&lt;/span&gt; &lt;span class="nn"&gt;H1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;reflexivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
  &lt;span class="nn"&gt;Qed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-05-03:/pages/cold-boot-attack</id>
    <title type="html">cold boot attack、耐タンパー性の極北</title>
    <published>2014-05-03T18:52:16Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/cold-boot-attack" type="text/html"/>
    <content type="html">&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Cold_boot_attack"&gt;cold boot attack&lt;/a&gt; という攻撃手法は、DRAM（いわゆる計算機の「メモリ」）は電源が切れてすぐにはデータは消えない（温度によるが数秒から数分）ということを逆手にとって、DRAMを物理的に冷却した上で、電源断→起動を高速に行うもしくはDRAMを外して別の機械から読み出すというものである。&lt;/p&gt;

&lt;p&gt;たとえばBitLockerなどでラップトップマシンのストレージを暗号化した上で、ログインが必要になるようロックしておいたとしても、ディスクを暗号化するための鍵は（多くの場合）メインメモリ上にある。なので、この間にマシンを盗まれてしまうと、 cold boot attack によってディスクを暗号化する鍵が読み出され、ディスクの中身を奪われる危険性がある。TPMを利用したところで、結局のところ鍵はメモリ上に保持されるのだから同じことだ。特に現在ではスマートフォンにおける危険が大きい。&lt;/p&gt;

&lt;p&gt;対策としては、暗号化するための鍵をメモリ上に持たないようにするしかない。上のようなケースでは、ロックを解除するときに入力するパスワードでディスクを暗号化するようにすれば良い。たとえば、マシンをサスペンド（ACPI S3）にするのではなく休止状態（ACPI S4）にすれば、安全ということになる。Androidでも画面をロックする度に内部ストレージをunmountすれば安全になるわけで、実際に &lt;a href="http://www.ccsl.carleton.ca/~dbarrera/files/spsm13-skillen.pdf"&gt;DeadBolt&lt;/a&gt; という実験的な実装が存在する。&lt;/p&gt;

&lt;p&gt;しかし、この方法は利便性という面から見ると完全に腐っている。ロックを解除する度に、（ブルートフォースを防ぐために十分に複雑である必要のある）暗号化キーを入力するというのは面倒極まりない。ロック画面で入力するパスワードは短くした上で、数回誤った入力が行われたら電源を落とし、そこで暗号化キーを要求するという方がよほど使いやすい。&lt;/p&gt;

&lt;p&gt;あるいは、別の問題として、サスペンドしていない稼働中のマシンをひったくられるという局面に際しては全く無力であることも挙げられる。ただ、このような攻撃はCPUのレジスタ上の暗号化キーを保持することで対処可能であり &lt;a href="http://en.wikipedia.org/wiki/TRESOR"&gt;TRESOR&lt;/a&gt; というLinuxカーネルなどのパッチなどの実装が存在する。しかし、デバッグ用のレジスタを使うなどの工夫はしているもののやはり暗号化キーにレジスタをいくつか専有されるのは他のアプリケーションにとって邪魔であり、また暗号処理を必然的にCPUの汎用レジスタ上で行うことになるため、空間消費の多いアルゴリズムは実行できず、そうでなくとも時間と空間のトレードオフによる性能の劣化は起こりうる。&lt;/p&gt;

&lt;p&gt;さて、これらを踏まえた上で、安全性と利便性を両立するためにどのような方法があるだろうか？結局のところ求められているのは、物理的にマシンを奪われて何をされたところで、中身を読み出されることの無い記憶装置だ。TPMがそうだと言われるかもしれないが、あれは周辺機器の構成やRAMに読み込まれるプログラムの正しさを検証するのに役立つものの、プログラムを実行するハードウェア自体の耐タンパー性を高めるようにはできていない（脱線するが、Trusted Computing Groupの提供しているTPMなどに関するドキュメントを色々読んでいたもののやたらと分かりづらくて弱った）。また、TPMは容量が小さく遅い。暗号化のような処理をパフォーマンスの問題無く遂行するには、この記憶装置はキャッシュメモリのようにCPUに組み込まれるしか無いだろう。十分な耐タンパー性は物理的に大変なのかもしれないが、少なくともダイサイズに関しては最近のCPUが数MBのキャッシュや特定用途の命令（のための演算器）を平気で持つことを考えると問題無いレベルであろう。そういえばCellはCPUによるデータ保護を提供していたような気がする（調べ直す気力が無かった）。&lt;/p&gt;

&lt;p&gt;さらに、フラッシュメモリのような不揮発性の記憶が、耐タンパー性のあるモジュールとしてCPU内に提供され、また現在TPMによって行なえるようなプログラムの検証が行われるとしよう。ロック画面で何回か短いパスワードの入力を間違えると長い暗号化キーの入力を要求するようにしようと上に書いたが、不揮発性の記憶を提供することで、これを電源断の後の通常のブート時にも行えるようになる。要はディスクを暗号化するキーおよび、パスワードを間違えた回数を不揮発性の記憶に保持すればいい（BitLockerのようにディスクを暗号化するキー（を暗号化するキー）をTPMに保持しても良いのだが）。この不揮発性の記憶がCPUに組み込まれていないと、たとえば信号線に細工して物理的に特定のアドレスへの書き込みを無効化することでパスワードの入力を間違えた回数を記憶させないようにする攻撃が可能になってしまうだろう。&lt;/p&gt;

&lt;p&gt;そこまでするならTPMもCPUに組み込んでしまえば良いのではないかという話になる。外部の配線を介して繋ぐと何でも遅く危険になるし、貧乏臭いデバイスはプログラマにとっても使いづらい。やはりCPUというのは計算機にとって約束された聖域である。国家機関からの圧力などによってCPUにバックドアを仕込まれる危険はもちろんあるが、そもそもCPUにバックドアがあったら全てのプログラムが処理する情報が筒抜けなわけで、今更何が変わるということもない。CPUは信用するしかないというわけだ。&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;モバイル端末の普及によって、物理的なコントロールが奪われても計算機を守り抜かねばならなくなっているのは間違いない。分解しようとすると爆発する時限爆発のように、時にはフェイルデッドも必要なのだろうか。ただ、これは本当に実体のあるモノを守りぬかねばならないというのとは訳が違うと思う。それは、一箇所を完璧に守りぬくことができれば、後は暗号化を適切に施すことによって、そうでない場所を保護することができるということだ。ここに計算機の勝ち目がある。まだまだリアルワールドより安全だ。&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;さて、CPUの製造者に全てを委ねるというのは良いのだろうか。GNU的には &lt;a href="http://en.wikipedia.org/wiki/LEON"&gt;LEON&lt;/a&gt; のようなオープンソース（さらにLEONはGPLライセンス）のCPUを使うのが正しいのかもしれない。ただ、オープンソースで提供されるのはCPUの回路記述であり、誰でもASICを作れるわけではないし、FPGAを使うにしてもFPGAにバックドアが無いことも論理合成ソフトウェアにバックドアが無いことも保障されない。&lt;/p&gt;

&lt;p&gt;そもそも、ソフトウェアは誰にでも複製可能な存在であるが、優れたハードウェアを製造出来るのは限られた製造者だけだ。およそ工業製品と呼ばれるものは、製造のための装置に金がかかるもので、その装置を苦労して手に入れたものが大量に生産するものだ。もちろんさほど複雑な初期投資を必要としなくても作ることのできる工業製品も存在するが、悪いことに最近のCPUやFPGAは初期投資が極端にかかる類の工業製品だ。&lt;/p&gt;

&lt;p&gt;確かに、性能の極めて低い半導体製品であれば、個人が作れるとは言わないがもっと小さい規模の組織でも作れるかもしれない。しかし、そんな性能の低い計算機を誰も求めていない。さらには、電力に対して性能の低い計算機を使うことはエネルギー問題の観点からみると罪ですらある。&lt;/p&gt;

&lt;p&gt;このジレンマはどうにもしようがないが、個人的には諦めとともに楽観するような気分である。国家と言えども神ではない。CPUに仕掛けたバックドアを経由して個人を監視するほど暇も技術も有るとは限らない。計算機づくりは国際的な仕事（アメリカに集中しているのは否めないが、いつまでも続くとは限らない）であるからして、一つの国家が全てを支配していられるというわけでもない。そもそも一つ国家からして一筋縄な存在で無い。仮に個人を監視する仕掛けが存在したとしても、少し工夫すればしばらくの間は撒くことができるかもしれない。支配者にとって善良な者であれば気にしないことにすれば初めから困らないし、あるいは支配者にとって善良で無いものは昔からある程度世を忍んで暮らしていたのだから何も変わらないとも言えるのだ。&lt;/p&gt;

&lt;p&gt;ちょっと話は外れるが、CPUにバックドアを仕掛けるなんて圧倒的な火力で攻めるという米軍のドクトリンであるかのような正攻法に思いを巡らせたくなる気持ちはあるものの、中国製製品の仕業である &lt;a href="http://security.slashdot.jp/story/13/10/30/0623241"&gt;無線LAN経由でウイルス攻撃を行なうアイロンが発見される&lt;/a&gt; なんてのも面白く、実はこれからの脅威かもしれないとも思われる。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-04-11:/pages/rot13-simd</id>
    <title type="html">SSE2などを使ったROT13の高速な実装</title>
    <published>2014-04-11T17:01:18Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/rot13-simd" type="text/html"/>
    <content type="html">&lt;p&gt;&lt;a href="http://ja.wikipedia.org/wiki/ROT13"&gt;ROT13&lt;/a&gt;と呼ばれる、アルファベットを13文字離れた文字に置き換える操作を行うプログラムを、SSE2を中心としたx86_64のSIMDによって高速化しました。結果としてテーブル引きによる実装と比べて4倍程度速くなりました。&lt;/p&gt;

&lt;p&gt;ソースコードは &lt;a href="https://github.com/grafi-tt/rot13-simd"&gt;https://github.com/grafi-tt/rot13-simd&lt;/a&gt; で公開しています。&lt;/p&gt;

&lt;p&gt;基本的な発想は、何文字だけずらすかを比較演算の結果を元にして算出した上で元の文字に足し合わせるというものです。&lt;/p&gt;

&lt;p&gt;大まかには、&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;各文字を0xDFでマスクして、小文字を大文字にする。&lt;/li&gt;
  &lt;li&gt;各文字を’A’-1、’M’、’Z’と比較する。比較結果は、-1あるいは0として得られる。&lt;/li&gt;
  &lt;li&gt;それを元に、「足す数」 / 13 + 1を算出する（or演算を上手く用いて命令数を削っている）。「足す数」は負になり得るが、ここで算出する数は必ず0以上。&lt;/li&gt;
  &lt;li&gt;その数に13をかける。8bit単位のSIMD乗算はできないが、変な繰り上がりがないので16bit単位や32bit単位で乗算しても問題は無い。このためにさっき0以上にする必要があった。&lt;/li&gt;
  &lt;li&gt;元の文字から13を引く。&lt;/li&gt;
  &lt;li&gt;4.と5.の結果を足し合わせる。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;という流れで行います。&lt;/p&gt;

&lt;p&gt;具体的な式を考えます。&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dA := if c &amp;gt; 'A' - 1 then -1 else 0
dM := if c &amp;gt; 'M' then -1 else 0
dZ := if c &amp;gt; 'Z' then -1 else 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;とすると、ずらす文字数は &lt;code&gt;(- dA + 2dM - dZ) × 13&lt;/code&gt; となります。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;2dM + 1&lt;/code&gt; は、 &lt;code&gt;dM | 1&lt;/code&gt; で算出できます。これから &lt;code&gt;dA + dZ&lt;/code&gt; を引けば、3.のステップが行えます。&lt;/p&gt;

&lt;p&gt;実は乗算を使わなくても、&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;j = (dM - dA) × 13
k = (dM - dZ) × 13
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;としたときに、 &lt;code&gt;dM - dA&lt;/code&gt; および &lt;code&gt;dM - dZ&lt;/code&gt; は 0 か -1 にしかならないことから &lt;code&gt;-j = (dM - dA) | 13 、 -k = (dM - dZ) | 13&lt;/code&gt; として算出できるので、ここから &lt;code&gt;j + k&lt;/code&gt; を求めることで「足す数」をいきなり求めることができます。&lt;/p&gt;

&lt;p&gt;しかしこうすると、依存関係が伸びてスケジューリングが悪くなる関係なのか、微妙に遅くなってしまいました（SSE4.1のblendを上手く使えばひょっとしたら速くなるかも）。&lt;/p&gt;

&lt;p&gt;両端の処理もmaskmovを用いてSIMDで行いました。maskの生成は結構大変だったけど何とかなりました（説明は省きます）。&lt;/p&gt;

&lt;p&gt;ただ、maskmovがかなり遅くて短い文字列に対してはかなり（アンロールした実装と比べて10倍近く）遅くなります。両端はテーブル引きするようにすれば、テーブルがL1キャッシュに載っている限り速くはなりますが、なんか中途半端にテーブルを使うのは負けた気がします。maskmovを使わずに文字列の範囲外には元と同じ文字を書き込むようにすれば一気に速くなるし、ページ境界を跨ぐことは無いので多分セグメンテーションフォルトは起きないような気がするのですが、文字列を読み込んだ直後に他のスレッドからその部分の文字が書き換えられた場合にデータが壊れてしまいます。別にスレッドセーフじゃないといけないとかは思わないのですが、範囲外の文字まで安全じゃないというのは気持ち悪いです。atomicな加算を使えないかとも思いましたがやっぱりアトミックにメモリを操作するのは遅かったです。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-04-10:/pages/cpuex</id>
    <title type="html">CPU実験おしまい</title>
    <published>2014-04-10T05:26:06Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/cpuex" type="text/html"/>
    <content type="html">&lt;p&gt;単位も来たので、CPU実験が完全に終了しました。約27億命令、44.8秒でした。&lt;/p&gt;

&lt;p&gt;わたしのコアは &lt;a href="https://github.com/grafi-tt/Maizul"&gt;https://github.com/grafi-tt/Maizul&lt;/a&gt; で公開しています。&lt;/p&gt;

&lt;h2 id="section"&gt;流れ&lt;/h2&gt;

&lt;h3 id="section-1"&gt;10月前半&lt;/h3&gt;
&lt;p&gt;コンパイラ係になるつもりでいたけど、じゃんけんで負けてしまい、何となくコア係になってしまう。何をすればいいのか分からないので、試験勉強がてら図書館で借りて少しだけ読んでいたヘネパタ4th editionを買って、まずはひたすら読んでいた。&lt;/p&gt;

&lt;p&gt;その後、いきなりパイプラインアーキテクチャを作るという方針でコアの実装を始める。途中まで実装が進んだあたりで命令セットの設計を完全にやり直したりも。&lt;/p&gt;

&lt;h3 id="section-2"&gt;10月後半&lt;/h3&gt;
&lt;p&gt;コアのテストに必要なので機械語のシミュレータを書く。&lt;/p&gt;

&lt;p&gt;SRAMが動かず何度も地下に泊まっては未明の本郷を徘徊しながら悩んだ末に、ついに論理的には初めから正しくてxst（論理合成プログラム、コンパイラのよなもの）のオプションを変更すると動くということを突き止める。これで機械語を手書きしたフィボナッチ数列を計算するプログラムが動作する。&lt;/p&gt;

&lt;p&gt;その後、アセンブラを一応動く状態に持っていく。&lt;/p&gt;

&lt;h3 id="section-3"&gt;11月前半&lt;/h3&gt;
&lt;p&gt;アセンブラとコンパイラを概ね完成させる。&lt;/p&gt;

&lt;p&gt;MinCamlのライブラリ関数をアセンブラでひたすら書いたり、FPUの実装やテストなどを行ったり。&lt;/p&gt;

&lt;p&gt;このあたりで見えてきた命令セットの微妙なミスを並行して修正する。&lt;/p&gt;

&lt;h3 id="section-4"&gt;11月後半&lt;/h3&gt;
&lt;p&gt;まずは残ったFPUを実装。マンデルブロ集合をプロットするプログラム（MinCamlに付属）が動く。&lt;/p&gt;

&lt;p&gt;コアの実装が解読できなくなってきてこのまま完動させる自信が無かったので、behavioralにデータパスを書き直す。ひたすらコアのデバッグを行い、MinCaml付属のmin-rt.mlが動作する。&lt;/p&gt;

&lt;p&gt;そのあとレイトレ向けにコンパイラを修正し、無事11月中に完動。13erでは一番早かった。&lt;/p&gt;

&lt;h3 id="section-5"&gt;12月〜2月前半&lt;/h3&gt;
&lt;p&gt;しばらくはお茶を濁すように形ばかり作業をしていたが、次第に何も進捗がなくなり進捗発表に行かなくなる。わたしが引きこもっているうちに他の班員が進捗を語っているかもしれないと思っていたが、どうやらそうでもなく一定期間班が消えていたらしい。&lt;/p&gt;

&lt;p&gt;とりあえず冬休みに分岐予測だけは実装した。パイプライン実装だと分岐予測の実装はすぐにできると言われるし、実際簡単だと思っていたが、レイテンシの調整が複雑で相当手間取った。データパスの変更が必要だったこともあるけど、今から思うと実装方針が悪かったかもしれない（後述）。&lt;/p&gt;

&lt;p&gt;あとは、余興でイーサネットを行うことにする。必要な資材を買い集める。&lt;/p&gt;

&lt;h3 id="section-6"&gt;2月後半〜進捗発表&lt;/h3&gt;
&lt;p&gt;これまで逆数および平方根は加算と乗算を使ってアセンブラで実装して動かしていたが、VHDLによる実装が出来たとFPU係から報告を受ける。試してみるとほぼそのままで問題なく動く。チームプレイってこういうものなのかとしみじみ喜ぶ。&lt;/p&gt;

&lt;p&gt;試しにクロックを上げてみると、少しFPU周りのパイプラインを調節すれば110MHzで安定した。121MHzは動かずあきらめる。&lt;/p&gt;

&lt;p&gt;コンパイラ演習で壊れているスケジューリングを実装していたので、動くように直して取り込む。分岐予測も壊れていたので、一応直す。（ただしこのあたりは本当に直っているかあやしい）&lt;/p&gt;

&lt;p&gt;また、min-rt.mlの初期化ルーチンの改変は許されているので、実質的にグローバル変数として確保されている配列をアセンブラに移して、MinCamlの上でクロージャが作られないようにしておいた（無論グローバル変数の検出をコンパイラで行うのが本当は正しい）。進捗発表直前に地下でコンパイラ係と二人で作業して何とか間に合わせた。&lt;/p&gt;

&lt;p&gt;イーサネットキットは必死こいてハンダ付けしたが、ハンダ付けが完了したあたりで力尽きた。FPGAからの制御方法は一応考えたのだけど……。&lt;/p&gt;

&lt;h2 id="section-7"&gt;感想&lt;/h2&gt;
&lt;p&gt;CPU実験ではチームプレイを学べるという噂がありますが、わたしに限って言えばあまり学べなかった気がします（反省点があるという意味や向き不向きが分かったという意味で全く学べなかったとは言いませんが）。それよりも、がんばればこのくらい大きなものがこれくらいの期間で実装できるんだなという感覚が学べたように思います。&lt;/p&gt;

&lt;p&gt;12erが11月中にほとんど動いていたという話がプレッシャーになって、かなり無理して11月中の完動にこぎつけたところはあります。やる気を喪失したのはその反動もあるとは思いますが、ではどうすればよかったのかと言われると分かりません。祭りのような、それを行うことに何らかの権威的なお墨付きが与えられた上でチームで行う活動に対して、傍から見ているとあんまり関わりたくないと感じるものの、いざ自分がコミットしてみると結構快楽を感じる、そういう性格をしているように思います（もっともこれは多くの人に当てはまる性格かもしれない）。コミットする際に感じるのはあくまで自分の中で閉じた快楽であって、周りの人と心を通わせてた上で何かをすることを楽しいと感じているのかというとそうでは無いような気がします。別にそれ自体が必ずしも悪いことでは無いのですが、ちょっと嫌な面かもしれません。&lt;/p&gt;

&lt;p&gt;あとは、わたしはライブラリ関数やテスト用のプログラムをコンパイラが安定してからもMinCamlで書かず全てアセンブラで書いていたのですが、それはやはり自分が設計および実装に携わったことによる慣れや思い入れがあったからのような気がします。そう考えると、自分でコンパイラをフルスクラッチしていれば、MinCaml（を拡張した言語）をもっと書く気になっていたかもしれません。&lt;/p&gt;

&lt;p&gt;ご指導頂いたTAや12erの方々に感謝します。班員の方々には勝手に動きすぎたことをやや申し訳なく思うとともに感謝します。13erのみなさん、特に技術面や精神面で多大な支えとなって頂いた &lt;a href="https://twitter.com/nemunemu3desu"&gt;@nemunemu3desu&lt;/a&gt; に感謝します。またこの文脈で適切かは分からないですが &lt;a href="https://twitter.com/alpicola"&gt;@alpicola&lt;/a&gt; には限りなく感謝します。&lt;/p&gt;

&lt;h2 id="section-8"&gt;アドバイス&lt;/h2&gt;
&lt;p&gt;取り立てて速く動かしたわけではなく何かすごいものを作ったわけでもないのに色々と書くのはおこがましいのですが、まあ思い当たるところを書いておきます。&lt;/p&gt;

&lt;h3 id="section-9"&gt;コア&lt;/h3&gt;
&lt;p&gt;はじめに断っておきますが、2命令以上の同時発行やアウトオブオーダーに関しては分かりません。他の人を当たってください。&lt;/p&gt;

&lt;p&gt;また、ここに書いてあることはいかにもRISCくさいですが、いっそCISCに振りきれるのも楽しいかもしれません。&lt;/p&gt;

&lt;h4 id="hdl"&gt;HDLの書き方&lt;/h4&gt;
&lt;p&gt;process文はクロックの立ち上がりでレジスタに転送するためだけに用いて、基本的にsignalのみでデータフロー的に書くのが良いという噂をIS周辺で耳にしました。確かにsignalのみを使ってプログラムするのは、VHDLの複雑さと係わらずに済むという意味で分かりやすく、ハードウェアのモデルと近いので論理合成の結果に問題が出にくいのかもしれないとは思います。&lt;/p&gt;

&lt;p&gt;しかし、VHDLはデータフロー的なモデリングを行うためだけの言語ではありません。xstはif文やループくらい組み合わせ回路に展開できるし論理圧縮もやってくれます。実際、Web上のHDLプログラミングに関するリソースにも、データフロー的にVHDLを書くことを推奨するような記述は全く見当たりません。signalはコンポーネント間の接続やクロックをまたいで保持する情報などに用いて、ロジックはbehavioralに書けば良いのではないのでしょうか。&lt;/p&gt;

&lt;p&gt;といってもやみくもに書こうとすると良い書き方が分からずかなり苦しみました。 &lt;a href="https://twitter.com/hiyuh"&gt;@hiyuh&lt;/a&gt; さんからtwitterで教えた頂いた &lt;a href="http://www.gaisler.com/doc/vhdl2proc.pdf"&gt;A strucutured VHDL design method&lt;/a&gt; （&lt;a href="http://www.gaisler.com/doc/structdes.pdf"&gt;スライド&lt;/a&gt;）という論文で説明されている、twoprocというデザインパターンが極めて有効な指針でした。&lt;/p&gt;

&lt;h4 id="section-10"&gt;分岐予測&lt;/h4&gt;
&lt;p&gt;まず、「分岐するかどうかを予測する」方法と「アドレスを予測する」方法があります。後者だと例外の実装がちょっと簡単になり、関数のリターンアドレスの予測も統一できます。前者だと多分回路は少なくて済みます。どっちが良いかはよく知らないですが。&lt;/p&gt;

&lt;p&gt;どちらにせよ、「分岐予測の失敗」に対処する必要があります。そのために分岐予測の結果をしばらくの間保持しておくことになるのですが、fetchフェーズあたりの分岐予測ユニットの中で保持する形で書くよりも、executionフェーズあたりの実際の分岐を決めるユニットまで命令と一緒に流す方が、ストールなどの処理が明らかに簡単なはずです。わたしはここで完全にハマりました。&lt;/p&gt;

&lt;h4 id="gprfpr"&gt;GPR/FPRの分離&lt;/h4&gt;
&lt;p&gt;データパス周りでの配線遅延を減らすには、データを必要以上にあっちこっちに流さないようにすることが（多分）大事です。とりあえずGPR（汎用レジスタ）とFPR（浮動小数点数レジスタ）は分けた方が賢明らしいです。&lt;/p&gt;

&lt;p&gt;さて、わたしのコアでは、ALUとFPUはそれぞれ整数レジスタおよび浮動小数点レジスタのみに書き込むようにはしていましたが、ALUの入力として浮動小数点数を使ってもよく、FPUの入力として整数を使ってもよいような実装となっていました。こうすることで、たしかにFPR/GPR間の移動や浮動小数点数の比較やitofが自然に実装できるようになります。しかし、ALUとFPUの重い命令同士が（例え重い命令ではねじれた入力を必要としなくとも）フォワーディングによってつながってしまうことになり、そのままクリティカルパスとなってしまっていました。ALUの入力は整数のみFPUの入力は浮動小数点数のみにした方がよかったかもしれません（試していないので本当に正しいかは不明。またこの場合は本当に重たい処理が存在しているわけではないので、xstのregiser balancingを有効にすればひょっとしたら解消するかもしれない）。こうすると、GPR/FPR間の移動などは特殊な命令とすることになります。&lt;/p&gt;

&lt;h3 id="fpu"&gt;FPU&lt;/h3&gt;
&lt;p&gt;基本的にみな「神資料」に従うので没個性なパートです。また、FPUのサイクルを全ての命令で固定するなら3サイクルよりも縮めるのはおそらく相当厳しいので、逆に3サイクルで動かすにはオーバーキルな最適化を余裕がある命令に対して行う必要もあまり無いことになってしまいます。&lt;/p&gt;

&lt;p&gt;が、実行サイクルを可変にするなら最適化の余地は存在します。まず、許される範囲で丸めを適当にすれば速くなるかもしれません。加算のレイテンシを根本的に縮めるのに有効そうなのは、 &lt;a href="http://news.mynavi.jp/column/architecture/098/"&gt;2パス加算器&lt;/a&gt; です。 &lt;a href="http://booksite.elsevier.com/9780123838728/references.php"&gt;ヘネパタのAppendix.J&lt;/a&gt; には、加算器の数を節約しつつ一回の加算で済ませる方法の記載があります。わたしの &lt;a href="https://github.com/grafi-tt/Maizul/blob/master/src/Unit/FPU/FAdd.vhd"&gt;faddの実装&lt;/a&gt; は、多分ヘネパタに記載の実装になっているので参考になるかもしれません（ハードウェア実験の際に自力で考えた工夫がたまたま一致していた）。わたしの &lt;a href="https://github.com/grafi-tt/Maizul/blob/master/src/Unit/FPU/"&gt;FPU&lt;/a&gt; は全体的にある程度速度を意識しているので、ひょっとしたら参考になるかもしれません。&lt;/p&gt;

&lt;p&gt;加算と乗算は最近接偶数丸めをきちんと行う実装があったほうが、三角関数や除算のソフトウェア実装の精度が出るはずなので好ましいかなと思います。あとは、WikipediaやIEEE754の仕様書を参考にしつつ、0の符号の扱いなどに気を付けましょう。&lt;/p&gt;

&lt;h3 id="section-11"&gt;コンパイラ&lt;/h3&gt;
&lt;p&gt;MinCamlを改造してレイトレを動かすだけなら、基本的に雑用です。出力部を書き換えて、倍精度浮動小数点数を扱うため8byteにしているところを単精度で良いので4byteに書き換えて、ひたすらライブラリを書けば、大体動くはずです。その後の最適化はほとんどやっていないので分かりません。個人的にはMinCamlベースで改善していくよりも、余裕とやる気があるならば、最低限MinCamlベースで動かしたところできりあげて、フルスクラッチしたコンパイラで最適化するなり言語を拡張して遊ぶなりするのが楽しそうです。&lt;/p&gt;

&lt;p&gt;スケジューリングだけやりましたが、MinCamlのバックエンドのデータ構造のハンドリングで苦労し、またOCamlの標準ライブラリが貧相で苦労しました。早めに基本ブロック単位の処理などがしやすいようバックエンドに手を入れておくとか、Janeのライブラリを使ってみるとか、すればいいのかなとは感じました。&lt;/p&gt;

&lt;h3 id="section-12"&gt;シミュレータ&lt;/h3&gt;
&lt;p&gt;シミュレータで一番大切なことは、とにかく確実に命令を動かしてくれること。速度とかデバッグ機能とか、そんなことよりも走らせた結果に嘘が無いことが大切です。&lt;/p&gt;

&lt;p&gt;それなりに速く動くようにするなら、まあスクリプト言語で実装するのは止めたほうがよさそうです。大人しく配列を使ってレジスタやメモリを表現すれば、関数型言語で実装してもおそらく速度的な問題は無さそうに思えます。OCamlで実装するなら64bitマシンでないとunboxedなintが31bitしかなくて遅いと語り継がれているようです。&lt;/p&gt;

&lt;p&gt;まじめに作るなら、機械語を解釈する部分をCで実装してフロントエンド部を他の言語で作るのが最善かなあと個人的には考えます（高速な高級言語で全部実装するのもアリでしょうが）。たとえばちゃんとデバッグできるようにするなら機械語をアセンブラに変換して出力する機能くらいはまず欲しいですが、それすらCで実装するのは苦痛です。また、一番重要な箇所をCで実装することには「誰でも読み書きできる」というメリットがあります。あんまりかっこよくはないやり方ですが、シミュレータの内部状態はグローバル変数として保持するようにして、「次のブレークポイントあるいはシミュレーション終了まで実行する」関数をCで実装してexternした上でフロントエンドから呼び出しするのが、比較的やりやすいでしょうか（自信は無い）。&lt;/p&gt;

&lt;p&gt;Cの実装に関しては、命令デコードのために &lt;a href="http://d.hatena.ne.jp/nyanp/20110728/p1"&gt;2進数リテラルもどき&lt;/a&gt; を使うのが便利です。コンパイラの拡張やC++14で2進リテラルが使えますが、環境依存はあんまりよろしくないです。あとは、math.hやstdint.hやinttypes.hは役立ちます（むしろFPUのソフトウェア実装で活躍しますが）。C99は正義。&lt;/p&gt;

&lt;p&gt;サイクルアキュムレートシミュレータ（きちんと理解していないけど、多分コアのパイプライン状態までシミュレートするシミュレータ）は、有るに越したことはないと思いますが、下手するとコアをもう一つ作るようなものになってしまうので大変かなとは思います。コアと実装が完全に一致しているかどうかを確かめるのも困難な気がします。「コアの設計としようとしているものが正しいかどうか検証するのによさそう」という話は聞きましたし、それはその通りだとは思いますが、先に書いた理由や、論理的には間違っていない設計でもFPGAでの実装として筋が悪いことはあるという理由から、効果のほどはやや疑問です。ただ、コア係とシミュレータ係の相性が良ければやってみる価値はあると感じます。&lt;/p&gt;

&lt;h3 id="section-13"&gt;アセンブラ&lt;/h3&gt;
&lt;p&gt;スクリプト言語でちゃらっと実装してしまって動くもののような気もしますが。&lt;/p&gt;

&lt;p&gt;代数的データ型がある言語でアセンブラを実装することを考えます。この場合、全ての命令を同じ型にして、コンストラクタで命令を区別するのが自然です。さて、各命令が引数として受け取るのは、GPRやFPRや即値やラベルのてんでバラバラな組み合わせです。こうした状況で、各命令を表すデータが正しい引数を持つということを型レベルで保証するのには、OCamlの多相バリアントが便利でした（もっともこの程度なら、各命令ごとに別々の型を用意してインターフェースやType Classで処理しても良さそう）。&lt;/p&gt;

&lt;p&gt;型安全に実装しようとすると、命令を表す文字列をコンストラクタの名前に持ち上げるための&lt;a href=""&gt;ボイラープレート&lt;/a&gt;が大量に出来てしまいます。Template Haskellなどでボイラープレートを自動生成するとか、Camlp4などでアセンブラのコードを直接読み込んでしまうとかすれば、ボイラープレートは無くせるかもしれません。&lt;/p&gt;

&lt;h3 id="section-14"&gt;夢&lt;/h3&gt;

&lt;h4 id="mhz"&gt;200MHz&lt;/h4&gt;
&lt;p&gt;SRAMを半分の速度で動かせば理論的には可能ですよね。&lt;/p&gt;

&lt;h4 id="section-15"&gt;ハードウェアレイトレ&lt;/h4&gt;
&lt;p&gt;min-rt.mlをそのままFPGAで実装すればすごく速そうです。実際FPGAで特定のアプリケーションを実装して高いスループットを得たという論文は見つかります。おそらく深いパイプラインが肝です。&lt;/p&gt;

&lt;h4 id="linux"&gt;Linux動作&lt;/h4&gt;
&lt;p&gt;Linux動作のためにやるべきことを考えるのが最終レポート課題（の一つ）でした。&lt;/p&gt;

&lt;p&gt;独自アーキテクチャにGCCとLinuxカーネルをポーティングするとか、x86_64を実装してやるとか、まあ面白いのですがLinuxがサポートするシンプルなアーキテクチャ（たとえばMIPS R3000）ベースにするのが無難そうです。当たり前ですがノイマン型（命令とデータをともにSRAMに入れて、BlockRAMはキャッシュとして用いる）になりますし、TLBも必要です。あとは、RS-232C/SDカードをコアから操作できるようにして（デバイスのレジスタを適当なアドレスにマッピング）、特定の組み込みデバイスをターゲットにした既存のドライバのソースコードを参考にしつつドライバを書けば、なんとかできないことはないかもしれません。&lt;/p&gt;

&lt;h4 id="section-16"&gt;インターネット&lt;/h4&gt;
&lt;p&gt;わたしが &lt;a href="http://www.l-and-f.co.jp/seihin/LF/LF-A1C.htm"&gt;LF-A1&lt;/a&gt; というAX88796搭載のキットを半田付けはしました（下手くそだけど）。チップをコントロールするレジスタおよび送受信バッファを命令レベルから操作できるようコントローラを書けば、理論的には動くはずです。プロトコルスタックを書けば理論的にはインターネットができるはずです。デバイスドライバを書くくらいのレイヤーで扱えるので、物理層を直で触るのに比べるとかなりソフトウェアっぽいです。&lt;/p&gt;

&lt;p&gt;チップのレジスタへのデータの読み書きは、普通のRAMのようにしつつ、データシートを参考に適当なクロックだけ待ってやればできると思います。チップからの割り込みは、割り込み信号をFPGA上のレジスタへのAsynchronous Resetにして、コアのクロックでそのレジスタを監視すれば扱えると思います。受信バッファのデータはチップ側のクロックでDMA転送されますが、これは非同期の読み書きに対応しているXilinxのBlockRAMを使ったキューを介することで、おそらくコアのクロックで読み出せるようにできます。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-01-19:/pages/picopico</id>
    <title type="html">ピコピコ</title>
    <published>2014-01-19T23:29:27Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/picopico" type="text/html"/>
    <content type="html">&lt;p&gt;試験勉強から逃避して、冗談でも書きます。&lt;/p&gt;

&lt;p&gt;友人が優秀な英作文の話をtwitterでしていた。自分はろくな英語も書けないし、読む方も英語ネイティブで無いプログラマのいい加減な英語ばかり読んでいて、これはいけない少しまともな英語を眺めて心を改めるかと guardian.co.uk を開いた。そうすると、 &lt;a href="http://www.theguardian.com/technology/gamesblog/2014/jan/17/tetris-ps4-xbox-one-playstation-ubisoft"&gt;UbisoftがテトリスのXbox One版とPS4版を出すというニュース&lt;/a&gt; が目に入った。テトリスに熱中した経験は誰もが有る。また、どんな計算機にもテトリスは移植される。それは言語や文化を超えていて、限りなく純粋なインタラクティブ体験。テトリスはまるで、人間の脳に直接アクセスして、脳にとってネイティブなマシン語で働きかけているかのようだ。そんな感じで記事は締めくくられていた。&lt;/p&gt;

&lt;p&gt;久しぶりにテトリスでもやってみようかと思った。ブラウザで動くテトリスなんてごまんと有るとは思うが、とりあえず tetris.com からリンクの貼ってあった &lt;a href="http://www.freetetris.org/game.php"&gt;http://www.freetetris.org/game.php&lt;/a&gt; をやってみることにした。結構楽しい。確かに熱中した。（ただし、 &lt;a href="http://www.twitchtetris.com/"&gt;http://www.twitchtetris.com/&lt;/a&gt; の方がモダンで良いと思う。）&lt;/p&gt;

&lt;p&gt;さて、他の（個人的には）快楽を感じる単純なパズルゲームとして、 &lt;a href="http://www.mod.go.jp/gsdf/fan/amusement/game/order.html"&gt;整理整頓 自衛官&lt;/a&gt; が挙げられる。この二つのゲームはどう違うのだろうか。&lt;/p&gt;

&lt;p&gt;テトリスは、決まったペースでテトリミノが落ちてきて、粛々と処理し続けることを要求される。言うなればライン工で、テトリスをしている間はテトリスのことを考え続ける。そこで訪れる忘我状態は思索を許さない。テトリスには様々なクローンがあり、ゲームバランスがそれぞれ異なれど、ゲームデザインの根本的な部分が人を惹きつける。一つ一つ振りかかるテトリミノを処理するという部分は同一であり、テトリミノを並べることに惹きつけられた脳は、身体の一部と化した単調な作業に溶かされていく。予定調和的な、あるべきディストピアの姿とも言える。&lt;/p&gt;

&lt;p&gt;整理整頓自衛官は、やりながら様々なことを考える。好意を寄せる人のこと、友人のこと、将来のこと。粛々とした歩みは無いが、しかし一方で乱数は理不尽だ。調子が良いときはサクサクと盤面を整えておけるのだが、やがて乱数の暴力を浴びせかけられてしどけなく乱れ、はち切れてしまう。このゲームは、ゲームバランスだけで面白さが成立しているように感じられる。たまたま危ういバランスの上に成立しているだけの世界。心は揺れる。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <id>tag:grafi.jp,2014-01-14:/pages/lua-reflection</id>
    <title type="html">Lua 5.2のデバッグライブラリを用いたリフレクション</title>
    <published>2014-01-14T15:29:12Z</published>
    <updated>2025-06-29T20:20:29Z</updated>
    <link rel="alternate" href="http://grafi.jp/pages/lua-reflection" type="text/html"/>
    <content type="html">&lt;p&gt;Luaは殆どのオブジェクトが自由に上書き可能なテーブルであるためかなり柔軟なメタプログラミングが可能な言語であるが、言語のセマンティクスの内側からはローカル変数自体を触ることができない。しかし、例えばRubyの文字列展開のようなものをプリプロセッサを使わずに実装しようとすると、どうしてもスタックフレーム中にあるローカル変数にアクセスしたくなる。printf使えば済むとか、LISPのマクロやTemplate Haskellなどによる実装の方が好ましいとか、思わなくもないが、まあとにかくLuaで何とかしたいこともある。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;debug.hoge&lt;/code&gt; でアクセス可能なデバッグライブラリの機能を使うと、何とかすることが可能であった。割と整理された関数が提供されているものの、デバッグ向けのライブラリであるためにインタプリタの実装に近い部分のモデルに従った機能が提供されており、何をするものか少し想像が付きづらかった。公式のドキュメントでは、一度分かってしまうまでは分からない類の解説がなされており、わたしは始め読んでいて何を言っているのか分からなかった。&lt;/p&gt;

&lt;p&gt;ここでは、Lua 5.2のデバッグライブラリを用いた変数周りのリフレクションについて、背景に有りそうだと感じられる概念を含めて書いておく。Lua 5.1とは多分微妙に違う。なおスレッドやコルーチン周りについては（わたしが知らないので）完全にスルーする。&lt;/p&gt;

&lt;h2 id="lua-52"&gt;Lua 5.2における環境とは&lt;/h2&gt;
&lt;p&gt;まず、Luaのドキュメントを読んでいてenvironmentという言葉が出てくるが、これはSchemeインタプリタにおけるenvironmentとは全く違うので注意である。分かってしまえば大したことはないが、わたしはここで激しくつまづいた。Luaのローカル変数は、Schemeと同じくレキシカルスコープに従っている。Schemeでは、レキシカルスコープに従った変数名と変数の対応付け、つまりLuaで言うところのローカル変数のマッピングをenvironmentと呼ぶが、Luaにおいては_ENVという名前のテーブルをenvironmentと呼び、これはむしろグローバル変数のマッピングとしての役割を果たす。&lt;/p&gt;

&lt;p&gt;Luaにはローカル変数とグローバル変数があることを思い出そう。ローカル変数のスコープは単なるレキシカルスコープである。一方、グローバル変数 &lt;code&gt;hoge&lt;/code&gt; へのアクセスは &lt;code&gt;_ENV.hoge&lt;/code&gt; へのアクセスとして扱われる。 &lt;code&gt;_ENV&lt;/code&gt; は、単なるローカル変数としてアクセス可能なテーブルであり、トップレベルで暗黙に定義されているとみなして良い。よって、グローバル変数は、同じローカル変数 &lt;code&gt;_ENV&lt;/code&gt; が見える範囲内をスコープとすることになる。&lt;/p&gt;

&lt;p&gt;以下の例がこの挙動を示している：&lt;/p&gt;

&lt;div class="language-lua highlighter-rouge"&gt;
  &lt;div class="highlight"&gt;
    &lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;myprint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"a"&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"b"&lt;/span&gt;
&lt;span class="n"&gt;myprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- prints "a"&lt;/span&gt;
&lt;span class="n"&gt;myprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- prints "b"&lt;/span&gt;
&lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;_ENV&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aaa"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;myprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- prints "aaa"&lt;/span&gt;
    &lt;span class="n"&gt;myprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- prints "nil"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;myprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- prints "a"&lt;/span&gt;
&lt;span class="n"&gt;myprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;-- prints "b"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;単一のソースコードで普通にプログラムを書く際には、ローカル変数だけで大体片がつくのでグローバル変数の概念はさして有用でもない。ただ、他のコードをrequireしたりevalしたりする際に大域的に見える関数や変数が定義される場所としてenvironemntは重要であり、また実際には単一のスクリプトを実行する際にも &lt;code&gt;print&lt;/code&gt; のようなグローバル関数がenvironmentの上に定義されているということになっている。&lt;/p&gt;

&lt;p&gt;Schemeでは、この際に「Schemeにおける」environmentを受け渡す。Schemeにおけるenvironmentの普通のS式での表現は自明では無く、environmentは組み込み関数によって取得可能であるが特殊なプリミティブとして扱われる（R5RSではこんな感じだった気がするがちょっと自信無い。またR6RSやR7RSでは違うのかもしれない）。一方、Luaにおいてはテーブルがプリミティブとして存在するのだから、フラットなテーブルを受け渡すと都合が良い。そしてこのテーブルがenvironmentと呼ばれると考えられる。&lt;/p&gt;

&lt;h2 id="section"&gt;リフレクションに使えそうな関数は何をしている&lt;/h2&gt;
&lt;p&gt;単なる再帰によるインタプリタなり、VMなり、コンパイルされた機械語の実行なり、どのような実行形式においても変数を保持しておくためのデータ構造は必要である。概念的なレベルで良いのでこのデータ構造を考えると、Luaのデバッグライブラリの機能はすんなりと腑に落ちる。&lt;/p&gt;

&lt;p&gt;関数が定義するローカル変数は、各変数ごとにスタックフレーム中でのオフセットを表す数値が割り当てられ、関数が呼び出された際のスタックフレームに保持される。また、関数を実行する際に外側のブロックで定義されているローカル変数にアクセスすることを考えると、現在実行している関数が外側のブロックから抜け出していないなら、スタックを字句的なネストから決まる数だけ上に辿ってアクセスすれば済む。一方、局所関数の定義がブロックの外側に抜け出すならば、変数が保持されていたスタックフレームは存在しないので、クロージャ変換を行い自由変数を捕獲しておくことになる。&lt;/p&gt;

&lt;p&gt;デバッグライブラリは、まさにこのスタックフレームやクロージャに対して、何らかの操作を行う関数群を定義している。&lt;/p&gt;

&lt;h3 id="debuggetlocalthread-level-local--debugsetlocalthread-level-local-value"&gt;
  &lt;code&gt;debug.getlocal([thread, ]level, local) / debug.setlocal([thread, ]level, local, value)&lt;/code&gt;
&lt;/h3&gt;
&lt;p&gt;スタックをlevelだけ上に辿った場所にある、local番目のローカル変数を操作する。なおgetlocalは変数の名前と値を組にして返す（これを使って、特定の名前を持つローカル変数を探すことができる）。ここで、末尾呼び出し最適化が為されるとスタックフレームが消えるので場合によっては注意が必要。カッコの有無によって末尾呼び出し最適化が変化するということも起こる。&lt;/p&gt;

&lt;div class="language-lua highlighter-rouge"&gt;
  &lt;div class="highlight"&gt;
    &lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;としてf,g,hを定義すると、g内でのfの呼び出しは末尾呼び出しの最適化の対象となり、h内でのfの呼び出しは末尾呼び出しの最適化にならない（C LuaでもLuaJでも同様の挙動だったが、これがバージョンごとに変化することの無い挙動なのかは不明）。&lt;/p&gt;

&lt;h3 id="debuggetupvaluef-n--debugsetupvaluef-n-value"&gt;
  &lt;code&gt;debug.getupvalue(f, n) / debug.setupvalue(f, n, value)&lt;/code&gt;
&lt;/h3&gt;
&lt;p&gt;クロージャfに捕獲されたn番目の自由変数を操作する。普通の変数代入と同じように動作する。&lt;/p&gt;

&lt;h3 id="debugupvalueidf-n--debugupvaluejoinf1-n1-f2-n2"&gt;
  &lt;code&gt;debug.upvalueid(f, n) / debug.upvaluejoin(f1, n1, f2, n2)&lt;/code&gt;
&lt;/h3&gt;
&lt;p&gt;Luaでは変数に再代入することが可能であり、またクロージャに捕獲された自由変数への再代入は、同じ変数を捕獲している別のクロージャにも影響する。よって、一般的に参照を介して自由変数を保持していると言える。&lt;/p&gt;

&lt;p&gt;upvalueidは、クロージャfに捕獲されたn番目の自由変数を保持する参照を一意に区別する識別子を返す。upvaluejoinは、f1内のn1番目の自由変数を保持する参照を、f2内のn2番目の自由変数を保持する参照と同じものに置き換える。ここで行うのは単なる変数への代入ではなく、参照自体の置き換えである。&lt;/p&gt;
</content>
  </entry>
</feed>

