8080な世界からCore 2の世界へ
アセンブリのレベルで見ると、本質はずっと変わっていないのですね。Mac OS X のアセンブラをちょっと触ってみた - IT戦記を読んで色々と思い出しました。
8080
私はZ80として知っているCPUです。いまでもZ80の拡張版がマイコンとして使われています。
A, B, C, D, E, H, Lの8bit汎用レジスタを持ちます。BC, DE, HLのようにレジスタを組み合わせて16bitアドレスを指定できますが、16bit演算はできません。メモリの読み書きや演算をするには必ずAレジスタを経由する必要があります。逆を言うと、A以外のレジスタを指定できる命令はかなり少ないです。例えば、2値の足し算をするにもBへの退避が必要です。
LD A, (0x0100) LD B, A LD A, (0x0101) ADD A, B LD (0x0102), A
(私はZ80のニーモニックしか知らないので、その表記にしてます)
フラグ、メモリ上のスタック、関数呼び出しのCALL/RET、入出力、割り込みに至るまで、今日のアーキテクチャと本質は同じです。十分に勉強する価値はあると思います。
8086
今日のx86アーキテクチャのもととなったCPUです。OSの違いがないとすれば、30年前にコンパイルしたコードがそのまま動きます。不思議ですよね。
AX, BX, CX, DXの16bit汎用レジスタを持ちます。AHと書いたら上位8bit、ALと書いたら下位8bitとして扱えます。命令のレジスタ制限もほとんどなくなり、自由度は大きく上がりました。
8bitと16bitの値を扱えるため、それらを区別するために新しい表記ができました。例えば、
MOV [BX], 0
と書くと、BXレジスタが指す先が8bitデータなのか16bitデータなのか分かりません。そこで、
MOV WORD PTR [BX], 0
と書けば16bitデータであることを明示できます。これは今日まで受け継がれており、DWORD PTR(32bit)、QWORD PTR(64bit)、DQWORD PTR(128bit)と書くようになっています。
8086を語る上で避けて通れないのがセグメンテーションです。メモリ空間をセグメントという単位に分割し、プログラムを置くセグメントとデータを置くセグメントを分離できるようになりました。実際には、16bitのレジスタを2つ組み合わせて20bitのメモリ空間を表現します。
セグメントレジスタ | A | 1 | 0 | 0 | |
---|---|---|---|---|---|
アドレスレジスタ | 4 | 5 | 6 | 7 | |
実際の物理アドレス | A | 5 | 5 | 6 | 7 |
↑24bitアドレスになっていたので20bitに訂正
まだセグメントの保護機能がなかったため、他のプログラムが使うセグメントを書き換えてしまう行儀の悪いプログラムがあればすぐに暴走してしまいます。セグメントの考え方は歴史として知っておいて損はないと思います。