bit指定について
(0)
- OSECPU-VMのrev2には、アセンブラにbitというよくわからないものが標準で出てくるようになりました。それについての説明です。
- 関連するページ:
(1)
- パソコン向けCPUの歴史を考えてみると、8ビットCPUから始まって、16ビット、32ビット、64ビット、と発展してきました。将来はどうなるのでしょうか。128ビットとか256ビットになるのでしょうか。
- こうしてみると、まるでビット数が増えることが技術の進歩のように思うかもしれません。実際64ビットのレジスタはかなり広い範囲の整数を扱うことができます。それまで32ビット演算で収まらなかった場合、複数の整数演算を組み合わせて64ビット計算をしてきたので、プログラムは単純化されて分かりやすくなり高速化されます。
- しかし一方で、デメリットもあります。たとえば1+2+3+...+9+10の計算をすることを考えてみた時に、こんな計算は8ビットどころか、6ビットもあれば十分な計算なのですが、それにもかかわらず64ビットのCPUはこれを64ビットで計算します。その分余計に電力を消費していますし、回路内のゲートも多くなって、高クロック化の妨げになっています。・・・100メートル先のお店に行くために、超高速飛行機を飛ばすようなものです。そんなの徒歩か自転車くらいで十分なのです。演算対象によって適切なビット数というものがあって、それより大きいのは結局は無駄なのです。だから一番大きなビット数に合わせてすべてを設計してしまうと、無駄の多いシステムになってしまいます。
- もし64ビット演算が時々しか必要ないのなら、結局は32ビットCPUが一番良いのかもしれません。いやそれどころか、もしかしたら16ビットCPUくらいが一番いいのかもしれません。
(2)
- もし全ての分野に共通な最適なビット数が分かれば話は単純です。たとえばそれは32ビットだとしましょう。それならOSECPU-VMは32ビットのVMとして設計してしまえばいいのです。これでOSECPU-VMは全ての分野に適合できるすばらしいVMになります。
- 最適なビット数がわからない以上は、この演算は○○ビットでやってください、とプログラム内に記述できるようにすることが一番いいと僕は考えました。そのためにすべての整数演算にbitという定数を記述する部分があります。
- VMは、もしCPUのアーキテクチャが16ビットで、それにもかかわらず32ビットの演算を要求されれば、多倍長演算アルゴリズムを使って32ビット演算をします。したがってプログラマは本当に必要なビット数を書けばいいのです。我慢して小さな数を書く必要はないですし、必要もないのに無駄に大きな数を書く必要もありません。これにより、16ビットや8ビットの組み込みCPUなどでも、無駄に32ビット演算のエミュレーションなどをする必要はなくなります。8ビット演算で十分な時は8ビット演算しかしないからです。逆にもし本当に必要なら遠慮なく256ビットでも4096ビットでも書くべきです。それをわざわざ多倍長演算する必要はありません。それはVMが自動でやってくれることだからです。
(3)
- 一方で、世界最小サイズを目指してコードを書きたい場合は、bit=32とすることをお勧めします。もちろんそれでは無駄な演算になってしまうこともあるでしょう。しかし32ビットはデフォルトになっているので、これをよく使うことはサイズの上では有利です。
- なぜ32ビットをデフォルトにしたかです。正直、多くのケースでは16ビットで十分だと感じてはいました。しかしゲームなどを作る際に、スコアなどは3万以上の数値を使いたいかもしれないと思いました。また、カラーコードでも24ビット以上がほしくなるのではないかと思いました。ということで、デフォルトは32ビットとしました。ちなみにAPIの引数では、16ビットしか要求しないものがかなりあります。
- 註:16ビットしか要求していない引数に対して32ビットで渡すことは何の問題もありません。上位ビットが無視されるだけです。
(4) 具体例
- (4-1) LIMM(16, R00, 0x123);
- R00レジスタに0x123が代入されます。この代入操作には16ビットかそれ以上で行われます。実行後のR00の精度は16ビットになります。
- (4-2) ADD(8, R01, R02, R03); // R01 = R02 + R03;
- 実行前の状態は次の通りだったとします。
レジスタ | データ | ビット |
R01 | 0x2 | 4 |
R02 | 0x1234 | 16 |
R03 | 0x56789a | 32 |
- 上記ADD命令を実行するとこうなります。
レジスタ | データ | ビット |
R01 | 0xce | 8 |
R02 | 0x1234 | 16 |
R03 | 0x56789a | 32 |
- [解説] この命令は8ビット以上の結果を要求しています。入力値であるR02とR03の両方とも、8ビット以上の精度を持っていたので、この演算は問題なく実行されて、結果がR01に格納されます。結果は無条件で上書きされるので、R01がそれまで4ビットの精度だったことは全く関係ありません。
- [Q] R02とR03の精度の最低値は16ビットなのだから、R01の精度は16ビットにできるのではないの?
- [A] その通りです。その気になれば0x8aceを結果として格納することはできます。しかし、VMやJITコンパイラによっては、高速化のために「要求された8ビット演算だけ」をやるかもしれません。そうするとやはり上位ビットは計算されていないので不定になります。したがってR01の精度は8ビットとして扱うべきです。
- なお、このADD命令の実行に当たっては、プリフィクス2F-0が必要です。そうでないと、中間結果568aceが8ビットを超えてしまっているので、「もしかして間違いではないですか?」と警告のためにセキュリティ例外になってしまいます。
こめんと欄
- LIMMではレジスタのbitの値は書き換えられ、ORなどの数値演算ではレジスタのbitは書き換えられない(同じかどうかチェックするだけ)だと思うのですが、ではCP命令のときは、値のみをコピーするのでしょうか?それとも、レジスタのbitも含めた全体をコピーするのでしょうか? -- hikarupsp 2014-06-08 (日) 15:42:21
- 他の例で言えば、まだ値の代入されたことのない未定義のレジスタ(bit==0)に数値をCPするには、先にLIMMやSBXを実行する必要があるのか、ということです。 -- hikarupsp 2014-06-08 (日) 15:45:28
- ORでr0に値を代入する時は確かOR命令の引数bitがr0のbitに適用されるはず。すなわち、SBXを実行する必要はない、ということ。ついでに言うと、r1とr2に関してもbitが等しいことは必須条件でなく、双方のbitがOR命令の引数bit以上あればOK。 -- ttwilb 2014-06-09 (月) 08:58:42
- ttwilbさん・Kさん、ありがとうございます。よくわかりました。本当は自分で実行して確かめてみるべきだったと思うのですが、Macで動作させるのに少し手こずってしまって…。 -- hikarupsp 2014-06-09 (月) 14:20:49