エンディアンについて (ビット編)

たけおか

初出: 2010/NOV/01
Update:2010/NOV/03 エンディアンとしての呼び方を削除
Update:2010/NOV/06 TI9900追加
Update:2022/NOV/03 Adaに関する情報を更新



0. はじめに

エンディアンというのは、ワード(語)や、ビットの並び方の呼び名である。
ビットの場合、ビット・ナンバリング(ビットの番号づけ)ともいう。

1. ビットのエンディアン

ビットのエンディアン、ビット・ナンバリング(ビットの番号づけ)ともいう ものの話をしよう。

80x86 は、ビットの名前が最下位ビットからついている。
つまり、最右ビット(最下位ビット(LSB)) が、bit 0 だ。

古いMacオタクの大好きな PowerPC は、ビットの名前が最上位(最左(MSB))から ついている。最上位ビットが bit 0 だ。

LSB 0 ビット・ナンバリング
x86, VAX, ARM, MIPS, 680x0, SPARC
MSB 0 ビット・ナンバリング
PowerPC,PA-RISC, S/390(メインフレーム)
ビット・ナンバリング



さて、ここに古代Macオタクと、1980年代 UNIXワークステーション好きが、 超絶大好きな 68020,68030 というモトローラ(今では、フリースケール)のCPUがある。

68020は、68000の32bit強化版で、68000の命令はすべてそのまま実行できる。
68000は、32bitアーキテクチャの16bit実装ということで、偉そうにしていた。
(が、実は作った人は、そんなに頭が良くない)

68000は、ワードはモトローラ伝統のビッグ・エンディアン。
そして、ビットの名前は最下位(最右)ビットがbit0。

例えば 68000 から備わっている BTST(ビットテスト)命令は、

   BTST.L #0,D0
 
で、bit0すなわち 最右ビット(LSB)をテストする。

だがしかし、68020で新設の BFTST命令では、

  BFTST D0{0:1}
 
は、最上位(最左)ビット(MSB)をテストする。

最下位(最右)ビット(LSB)をテストするには、
  BFTST D0{31:1}
 
としなければならない。
これは、ビットの名前付けを、 68020では、PowerPCと同様に変更したということだ。

なぜこんなことになったのか?

それは、ビットの拡張性の問題だ。

2. ビット拡張性と、ビットのエンディアン


ワードのエンディアンのページ には、 結局、「ワード拡張性がいいのは、リトル・エンディアンだ」と書いていたはずだ。

ビットは、ワード・エンディアンとは独立に拡張性がある。
しかし、それにしても、めちゃくちゃにやってはいけない。

そうしなければ拡張性が無い。(下図参照)


LSB 0 ビット・ナンバリングは、
ワード・リトル・エンディアンである方向に拡張される
MSB 0 ビット・ナンバリングは、
ワード・ビッグ・エンディアンである方向に拡張される
ビット・エンディアンと、ビット拡張される方向


68000は、ワードがビッグ・エンディアンなのに、 LSB 0 ビット・ナンバリングにしたので、 本当に32bit 以上にしたとき、破綻した。
(拡張された部分の名前付けがうまくできなかった)

そして、仕方がないので、ビットの名前付けを逆(MSB 0 ビット・ナンバリング)に 修正した。
古い68000命令は、古いまま残して。

3. ビットのエンディアンとハードウェア

ビット・ナンバリングは、ビットマップ・ディスプレイを作るときにも影響した。

80x86で作った機械は、ハードウェア屋さんも何も考えずに素直に作っておけ ば、CPUが32bit化したときも、なにも考えずにそのままソフトウェアも全てつかえた。

68000は、メモリ空間がリニアで、ハードウェア屋さんも好きだった。
とくに、高解像度なグラフィック端末は、リニアなメモリ空間を必要としたので、 68000で、グラフィック端末を作った会社も多かった。

しかし、16bit機である68000で、32bit以上のメモリ配置を考えず、 68000のbit0(LSB) から表示した機械は、 それを32bit 化したとき、ソフトウェアは、32bit ワードを半分に切って、 入れ替えるとかいう、あほらしい手間が生じた。
(通常、ビットマップ・ディスプレイのハードウェアは、 bit0から表示するように設計する。
というか、ビット・シリアルなハードウェアは、LSBから出力するようにするのが、 ハードウェア設計の通常のやり方である)

なぜなら、ビットの拡張性が無く、16bit づつ切れていたからだ。
(だから、32bitアクセスすると16bit単位で上下が入れ替わる)

68000系を使った機械でも、頭のいい人が設計したハードウェアは、 68000のbit15(MSB: PowerPCのbit0)から表示していたので、 32bit化したときも問題なかった。
しかし、68000の機械語命令のビット名前の付け方から通常 想像される点の位置と、 実際に点の表示される位置が違うので、ソフトウェア屋は混乱した。

4. 各CPUのビット・エンディアン

IBMは、ものがわかっているので、ワード・ビッグ・エンディアンである 伝統のメインフレーム S/390 (大昔の370シリーズ)も、 Power(PowerPCは、Powerのマイコン版)も、 MSB 0ビット・ナンバリングで作っている。

MIPSは、SGIを始めとする多くのUNIX系マシンで ワード・ビッグ・エンディアンで使われている。
だが、LSB 0 ビット・ナンバリングであり、 それは本来、ワード・リトル用である。

MIPSをビッグ・エンディアンで使った会社のほとんどは、 680x0のマシンの後継として MIPS使用マシンを出したので仕方ない。

DECは、MIPSをワード・リトルで使っていた。DECは伝統的に リトル・エンディアンの会社だから当然。
DECは、LSB 0ナンバリングの会社である。

SPARCは、基本がワード・ビッグ・エンディアンなのに、LSB 0ビット・ ナンバリングであった…

日立もワード・ビッグ・エンディアンの会社であるが、 SH-3, SH-4も、LSB 0 ビット・ナンバリングだった。
そもそも8bit時代に6800(六千八百)のセカンド・ソース作りとかやってたからだな…

6800, 6809は、モトローラの8bit。どちらも、ワードはビッグ・エンディアンだが、 LSB 0 ビット・ナンバリング。

6502は、ハードウェアは6800に似せてあるが、ワード(主にアドレス情報)は リトル・エンディアン。
LSB 0ビット・ナンバリング。正解。

8080, Z80,80x86は、ワード・リトル・エンディアンで、 LSB 0ビット・ナンバリング。正解。

というか、8bit CPUで、MSB 0ビット・ナンバリングのCPUって、 メジャーなものには、なかった気がする…

古い16bit CPUである TI社の9900は、ワード・ビッグ・エンディアンで、 MSB 0 ビット・ナンバリング。正解。



5. おしまい

通常、ハードウェアは、LSBから出力するので、その点でも、 LSB 0 ビット・ナンバリングが良い。

そして、LSB 0 ビット・ナンバリングを使用すると、拡張性を自然にしようとすると、 自ずとワード・リトル・エンディアンになる。

やはり、リトル・エンディアンを使う方が、正しいと思えるのだが。

MSB 0 ビット・ナンバリングで、グラフィックスのプログラムを書いてみれば、 ちょっと混乱するよ。慣れれば平気だけど。
LSB 0ビット・ナンバリングで、グラフィックスのドットがMSBから表示される (68000系機械)の方が、もっとプログラマは混乱するかも知れない。
SGIとかのメジャーなグラフィック・マシンも、これなんだけど。
(だから、慣れている人は多い気がする)

ビット操作が、ワードで閉じてて、拡張を絶対にしないなら、 ビット・エンディアンは関係ないとも言える。

だが…
Ada95言語では、 record定義の中で、データのビット・エンディアンを指定できる。 この文書は、前半では本稿と同様の議論が、書かれている。
/*無くなった (^^; →
だが、 英語版Wikipediaの Bit numberingの項には、 Ada言語では、ビット・エンディアンが見えている、と出ている。*/

ちなみに、verilogなどのハードウェア記述言語では、ビットのオーダリングを個々に指定できるのはフツーである。


参考
英語版Wikipedia Bit numbering


68000と68020で新設された命令の違いは↓がよくわかる
M68000ファミリのビットフィールド命令, 鎌田 誠

ワードのエンディアンについて
たけおかのホーム・ページ