CPUで「やりたい」ことを「できる」にかえる基本の12章 オンライン版
                                                      2010/12/09
                                     Copyright(C) by Y.Nakashima

0章 はじめに

本書は「Cでやりたいことをできるにかえる基本の12章」に引き続き,
これから,ハードウェア(特にプロセッサ)を使ってプログラムを高速に
動かしてみようという挑戦者を対象としている.

ハードウェアの学習には,おおまかに二つの方法がある.一つは論理ゲー
ト階層から積み上げて,徐々に複雑な回路を構成し,最後に実用的設計例
に取り組む方法,もう一つは,ソフトウェア階層から掘り下げて,OS階
層を経由し,ハードウェア構成の必然に至る方法である.歴史を順に辿り
基本技術を隅々まで正確に理解したい人には前者の方法,プログラムを使っ
た具体的な問題解決に興味がある人には後者の方法が適している.もちろ
ん,この二つの方法を併用することによって,さらに理解を深めることが
できる.

本書では後者を採用しており,簡単なソースプログラムをコンパイルして
実行する方法に始まり,機械語命令を経由して,ライブラリとシステムコー
ルの実現方法,各種シミュレータによるモデルの実現方法,さらに,実験
環境の構築を通じて実際にプログラムをハードウェア上で動作させるま
での過程を解説している.さらに,以上の過程から得られる各種パラメタ
をシミュレータにフィードバックして,より精密なシミュレーションを行
う手法についてまとめている.

なお,本書は一般のハードウェア入門書とは異なっている.C言語により
書かれたプログラムを機械語命令に変換し,一般的なハードウェアにより
走行させて一通りの経験を積む内容ではない.機械語命令をいかに「先進
的な機構により」高速実行するか,また,実験室レベルで実際に稼働させ
るかに主眼を置いているため,必ずしも世の中の常識や商用向けの一般的
手法に沿ったものではないことを断っておく.

----

§ Cプログラムでは手に負えない時

C言語によりプログラムを開発し市販のコンピュータで実行した結果,所
望の性能が得られない場合,どうすれば改良できるであろうか.性能指標
には速度,回路規模,消費電力,耐故障性などがあり,コンピュータを買
い替えたり,GPUのようなアクセラレータを追加搭載することにより,特
定の性能問題を解決できる場合もある.また,マルチコアプログラミング
のような高度な手法により解決できる場合もある.しかし,性能指標のう
ち速度と消費電力は一般にトレードオフの関係にあることから,両者を同
時に改善したい場合,誰かが作ってくれるのを待つか,自分で作るしかな
い.研究者/挑戦者は専ら後者を選択する人種なので,このような本をま
とめようという動機が生まれる.

----

§ 本書の使い方

最近では,大学などの教育現場においてFPGA設計環境が一通り揃っている
ことが期待できる.ただし,市販のFPGA設計環境の大部分は,作成したハー
ドウェア上で実用的なアプリケーションプログラムを動作させることが困
難である.主には,メモリやI/O性能の不足,さらにコア部分をLSI化した
場合の環境の不連続性による.これらの問題を解決するには,FPGA設計環
境を特注するしかないのが現状である.幸いなことに,当方にはこのよう
な環境が揃っているので,本書に沿って本当に実験したい人は,当大学院
に入学(入院?)することをお勧めする.:-)

----

1章 ユーザプログラムから機械語命令列へ

ソースプログラムが実行されるまでの手順を復習してみよう.以下のプロ
グラム(sample.c)を「vi」により作成したとする.

% vi sample.c

  main()
  {
    printf("Hello.\\n");
  }

実行するには,以下のようにCコンパイラを使って実行可能形式を生成し
なければならない.

% gcc -v sample.c -o sample
  …/cpp …	sample.c	…/cxxx.i
  …/cc1 …	…/cxxx.i -o	…/cxxx.s
  …/as  …	…/cxxx.s -o	…/cxxx.o
  …/ld  …	…/cxxx.o -o	sample

「Cでやりたいことをできるにかえる基本の12章」に記載したように,
4つのコマンドが順に呼び出されて順にファイルを生成する.cpp(プリ
プロセッサ)がsample.cからcxxx.iを生成し,cc1(コンパイラ本体)が
cxxx.sを生成し,as(アセンブラ)がcxxx.oを生成し,最後にld(リンカ)
がsample(ロードモジュール)を生成する.首尾よくsampleが生成された
ら,以下により実行することができる.

% ./sample
  Hello.

次にアセンブラについて見てみよう.アセンブラは,アセンブリ言語によ
り記述されたファイル(cxxx.s)を解釈して,バイナリ形式の機械語命令
ファイル(cxxx.o)を生成するプログラムである.最終的にsampleを実行
するCPUの種類によって,以下のようにアセンブリ言語が異なり,各々の
言語に対応したアセンブラを使用しなければならない.

Pentiumの場合
	main: pushl %ebp
	      movl  %esp,%ebp
	      pushl $.LC0
	      call  printf … この先はどうなっているのか?
	      leave
	      ret
	.LC0: .ascii "Hello.\\12\\0"

SPARCの場合
	main: save  %sp,-112,%sp
	      sethi %hi(.LLC0),%o0
	      call  printf,0 … この先はどうなっているのか?
	      or    %o0,%lo(.LLC0),%o0
	      ret
	      restore
	.LLC0:.asciz  "Hello\\n"

ところで,sample.cに記述したprintf関数が,そのまま"call printf"と
表現されていることに注意が必要である.最終的に画面に文字列が表示さ
れるまでには様々な処理が必要であるにもかかわらず,わずか1個の機械
語命令が生成されているに過ぎない.また,.LLC0は単なるラベルであり,
具体的なアドレスに対応付けられていない.このように,アセンブル直後
の機械語命令列は不完全である.

実体がない関数呼び出しや,アドレスの対応付がないラベルを完全な状態
に変換する作業はリンカが行う.また,一般ユーザにとってプログラムの
先頭はmainであるが,実際には,ベースレジスタやスタックポインタの初
期化等,mainを実行する前にやるべきことがいくつかあり,このためのス
タートアップファイル(crt0.o等)の接続もリンカが行う.この結果,
sampleの実行開始アドレスはmainの先頭ではなく,startというラベルが
付いたアドレスとなる.さらに,printfの実体を含む標準関数ライブラリ
(libc)や数値関数ライブラリ(libm)等,プログラムの実行に必要なラ
イブラリが結合されて,sampleは実行可能ファイルとなる.

さて,標準関数ライブラリに含まれるprintfの実体は,どこまでの機能を
含んでいるであろうか.最終的に,どこかで誰かが,物理的な装置の画面
に文字を表示しているはずであるが,実際には,OSを搭載しない簡素な組
み込み機器を除き,printfの実体は最終局面までの全命令列を含んではい
ない.これは,情報機器の複雑化とともに,複数のプログラムを同時に実
行する必要性が増し,有限の資源を複数のプログラムが秩序を保ちながら
使用する(たとえば1つの画面に文字を表示する)必要性が出てきたため
である.有限の資源を管理し,複数のプログラムに整然と使用させるため
には,あるレベルを超える機能をOSが一括して管理する必要がある.OSは
ユーザが勝手に物理資源を使わないようにユーザプログラムが参照できな
い領域に隠し,ユーザプログラムが物理資源を必要とする場合は,システ
ムコールと呼ぶ特殊な命令を使用させる.例えばprintf自体をシステムコー
ルとすることもできる.しかし,指定された書式に合わせて浮動小数点数
を文字列に変換するような処理は,ユーザプログラムレベルで可能である
し,printfのような複雑な処理をOS機能に含めてしまうと,OSが大きくな
り過ぎたり,ユーザレベルでの改変が困難になるなど弊害が多い.このた
め,一般に,最後にどうしてもI/O処理が必要になる段階以降をシステム
コールとして用意し,それまでの処理はユーザプログラムに含めるのが一
般的である.

----