
【組込みシステム編】第5回 組込みシステム
こんにちは、南角 です。
前回書いたように、浮動小数点数に関して、まだround や 符号、 メモリ上の形式などの話などが残っていますので、今回はまず符号の話から始めたいと思います。
皆さんご存じのとおり、多くのCPUでは、符合有りの整数において負数を表現する場合、2の補数を用いています。
2の補数に関する正確な定義はともかくとして、私は実用上はその値の正の整数と足すと0となる数が2の補数表現におけるマイナス表現だと考えています。
例えば整数が16ビットの場合、10進数の5は2進数では 0000 0000 0000 0101 となり、
1111 1111 1111 1011 と加えると 1 0000 0000 0000 0000 となり、オーバーフローを無視すると
0000 0000 0000 0000 と10進数でいうと0になります。
そこで 1111 1111 1111 1011 が-5 というわけです。
ここでMSB (Most Significant Bit - 最上位ビット)が符号ビットだと説明される方もおられますが、それは違うと思います。
確かにMSBを見れば、その数が正か負かは判断できますが、MSBで符号を決めているわけではありません。
もしMSBで符号を決めているのであれば、16ビットの2進数でいうと 1000 0000 0000 0000が-0となり、2の補数では+0と-0が存在することになりますがそうではありません。
1000 0000 0000 0000は10進数でいうと-32768、負数のもっとも小さな数になります。
しかし浮動小数点における仮数部の表現は、MSBは本当に符号ビットです。
ですから浮動小数点においては+0.0と−0.0が存在します。
ちなみに浮動小数点における指数部の負数の表現形式は、指数部にゲタ(バイアス)を加えて常に正の値で表したものとしています。たとえば指数部が8ビットであれば、常に127を加えて正の数(0と255は特殊な意味で用いるため1から254)となるようにしています。
以上の意味では、浮動小数点表現における仮数部も指数部も符号なし2進数ということになります。
なお、浮動小数点の広く採用されている規格であるIEEE 754においては、4倍精度という128ビット(16バイト)のものも存在して、この形式では仮数部も112ビットあるようなので、long longの値を格納した場合の精度落ちも発生しないと思いますが、まだ私は使用したことがないため、これ以上は何とも言えません。
ところで、私が浮動小数点プロセッサ(FPU)というものを最初に使用したのは、確か入社2、3年の頃で、インテルのi8087でした。
当時はi8086のコンパイラを使用していましたが、むろん当初はコンパイラのサポートはなく、Cから呼び出せる関数をアセンブラで作成しました。
80ビットのレジスタFP0からFP7がありましたが、これがスタック構造だったため、コメント部分に、命令ごとにスタック上のデータ位置を記述したことを覚えています。
FPUを最初に使用したのはi8086+i8087で、はじめはCから呼び出せる関数をアセンブラで作成して演算時間を短くするのに利用していました。
やがて新しい機種を開発することになり、その機種ではさらなる性能、機能の向上のためMC68020+MC68881を使用することになりました。
MC68881というのがFPUです。
i8087はi8086と同時に命令をフェッチしており、命令によってi8086の命令なのかi8087の命令なのかが区別されており、それぞれが自分の命令を実行する方式でした。
それに対してMC68881はいわば演算用デバイスで、必要に応じてMC68020から呼び出される方式だったと思います。
当時のFPUはいわば贅沢品で、C言語におけるdoubleが8バイト(64ビット)であるにも関わらず、
内部的にはi8087で10バイト(80ビット)、MC68881で12バイト(96ビット)のレジスタを持ち演算を行っています。
RISCなどでは内部的にも8バイト(64ビット)のレジスタしか持たず、浮動小数点演算を行う場合も多く、その結果、ソースコードが同じであっても、PCなどで行うシミュレータと実機での動作が異なる場合もあることは、以前もお伝えした通りです。
またPCなどを使う場合に注意することは、内部的には10バイトのデータをメモリに保存する時は、途中に2バイトの詰め物(padding)をして12バイトになることです。
これはもちろん32ビットCPUなので、メモリアクセスの効率化(data alignment)のためだと思いますが、サイズを4の整数倍にするためだと思います。
現状のIntelの64ビットCPUだと効率化のために8の整数倍になるのでしょうか?
残念ながら手元に64ビット対応のコンパイラがないため確認できません。
すこし驚いたのは浮動小数点の値を整数化する時です。
確かfmoveだったと思いますが、MC68881にはFPU内部のレジスタを形式を指定してメモリに書き込むだけで、FPUの丸めモードにしたがって自動的に型変換してくれたため、丸めモードをroundにしておけば四捨五入だろうと考えていたところ、実は偶数への丸めだったことです。
浮動小数点の値を整数に変換する場合、最も近くの表現できる整数へ丸める。さらに0.5のように表現可能な2つの値の中間の値であったら、一番低い仮数ビットが0になるほうに丸めるという動作です。
これは世の中の四捨五入とは別の動作になります。たとえば1.5を丸めた場合2になります。これはいいのですが2.5を丸めた場合も2になります。
最初に使用したFPU(MC68881)対応コンパイラでは、doubleの変数をlongに(明示的にせよ、暗黙的にせよ)変換する場合に単にfmove命令を使用していました。
従来、FPUを使用せずソフトウェアで処理していた時は、四捨五入の動作をしていたものが、FPUに対応するバージョンに置き換えた時に微妙に計算結果が異なり、客先からクレームが来ました。
初期のころはコンパイラ屋さんもよくわかっていなかったようで、FPUのモードを利用した整数変換になっており、この問題が発生しました。
この時は対策として、Cからアセンブラに変換して、そのアセンブラのソースコードをきちんと四捨五入するアセンブラに置き換えるというツールを作成して、変換を行った後、アセンブルして機械語を生成するということを行いました。
何か昔話のようになってしまいましたが、言いたかったことは、コンパイラも100%信用してはいけないということです。
このようなこともあったため、今でも時に応じてCやC++のソースコードから生成されたアセンブラ、そしてアセンブラであってもそのまま機械語になるとは限らないため、実際に生成されたオブジェクトを逆アセンブルして、確認するということが習慣になっています。
それなりに長い間使われているコンパイラであれば、不具合も少ないとは思いますが、とはいえコンパイラもあくまでソフトウェアです。
最適化オプションや状況によっては不具合が残っていたかもしれません。
機械語で見ないとわからない不具合もあります、みなさんもアセンブラだからと言って敬遠せず、是非アセンブラも好きになってください。
アセンブラを知ることにより、使用しているCPUも、わかってくるはずです。
もう一つ言っておきたいことがあります。
CPUはハードウェア屋さんの領域だと思っていませんか?
私はCPUもソフトウェアだと思っています。
CPUの電気特性や信号のタイミング、接続などはハードウェア屋さんの領域だと思いますが、CPUの動作に関してはソフトウェア屋さんの仕事です。
むしろソフトウェア屋さんがハードウェア屋さんに教えてあげないといけません。
もうひとつ、当たり前ですが、ハードウェア屋さんとは仲良くしてください。
ハードウェア屋さんはハードウェア屋さんで、ソフトウェア屋に気を使って、自分の判断でソフトウェアに関係ないと思った場合にその情報を伝えてこない場合があります。
例えば、ある製品で製造中止に伴いEEPROMが変更になったことがありました。
EEPROM自体は変更になりましたが、ソフトウェアからみた、書き込み方法などその使用方法に変更がなかったため、特に変更の連絡はありませんでした。
おそらく書類や会議で「EEPROMが変更になったが、互換品なのでソフトウェアの変更は不要」くらいの連絡はあったと思います。しかしこちらも上記のような連絡があれば特に気にはしません。
しかし、実はEEPROMの特性に変更があり、書き込み速度がかなり遅くなっていました。
このEEPROMは製品の型番、パラメータなども保持しており、こちらは書き込み速度が遅くなっても大した問題はありません。
しかし、重要な用途があり、それは、電源断割り込みにより保持しておかなければならないデータを保存することでした。
もう少し詳しく説明しますと、製品の電源を切っても、一瞬で200Vや100Vが0になるわけではなく、電圧は徐々に低下します。そしてある電圧より低下した時に、電源低下割り込みを発生させ、ハードウェアが動作可能な電圧を保っている間に、保存データのEEPROMへの書き込みを行っていました。
これは時間との勝負であり、製品によってはコンデンサーなどを付加して、低下する時間を延ばしたりもしていました。
もうお分かりだと思いますが、EEPROMの変更により、電源断の時に、従来は書き込みが間に合っていたデータが、失われるようになりました。
これも一種のリアルタイム性であり、ハードウェアの変更により、処理が間に合わなくなった例です。
その他、温度によってデバイスの書き込み速度が遅くなるために生じる不具合など、ハードウェアとソフトウェアが一体となって成立する組み込みシステムならではのものだと思います。
使用される環境という意味では、紫外線の影響が大きい宇宙空間や、ノイズが激しいうえに、規制上?ハードウェア的なノイズ対策ができにくいパチンコ台などにも、一定周期でリセット信号を入れるなどの、独自の対策が必要だったりします。
デバイスに関しては、フラッシュメモリなどは書き込み回数の上限(寿命)もあり、今までちゃんと書き込めていたものが、ある時から書き込めなくなる場合もあります。
このような場合は、試験を行えば行うほど寿命を縮めてしまうというジレンマもあり、何かと難しいところもあります。
以上のように、組み込みシステムにおいては、実験室で正しく動作するソフトウェアを作成しておけばよいわけではなく、ハードウェア屋さんと一緒になって、(保障している条件内の)さまざまな環境で製品を動作させる必要があることを、忘れないでください。
次回は組込みシステム編の最終回です。
繰り返しますが、組込みシステムの最大の特徴は、現実世界の変化に対応して、制限時間以内に結果を返すことです。
現実世界の変化を知るためには、各種センサーを使用します。そしてセンサーが情報をCPUに伝える場合には割り込みを使用することが一般的です。
RTOSにとっても、タスクからRTOSに制御を移すために、定期的なタイマー割り込みを使用します。
このように、割り込みおよび割り込み処理が、組み込みシステムにとって重要な役目を果たします。
最終回は、この重要な割り込みに関してまとめたいと思います。
組込みシステム編 第5回 おわり
■著者プロフィール
南角 茂樹(なんかく しげき)
大阪電気通信大学 総合情報学部 メディアコンピュータシステム学科 准教授、同大学院総合情報学研究科(コンピュータサイエンス専攻)、エイシップ・ソリューションズ株式会社 研究顧問。
慶應義塾大学工学部数理工学科卒業後、大手電機会社を経て現職。組み込みシステムおよびリアルタイムOSを専門とし、著書、解説記事、発表・講演、登録特許等多数。
ページの先頭へ戻る »

