メモリ、バイト、レジスタ
非常に基礎的な部分を説明します。
バイト
一般的なコンピュータのメモリの量を表す単位は 1 バイト(byte)です。1 バイトは下の表のように 8 ビット から成ります。1ビットとはコンピュータで扱うことのできる最小単位で 0 または 1 の 2つの状態を保持することができます。コンピュータの内部では電圧の高い/低いという状態で表現できるため、回路が簡単になるなどのメリットがあるため、中間の電圧を使ったりすることはありません。アナログという場合は中間の状態も扱う回路、デジタルというのは中間は無く飛び飛びの(この場合は0と1)値を使うものです。アナログテレビ、地上デジタルテレビのデジタル/アナログも同じ意味で使っています。このビットをすべての処理の最小単位とするため、コンピュータは2進数で処理を行うことになります。いくつかのビットを同時に扱うほうが便利なため、「8ビットを1バイトとする」と定義されているわけです。
バイト | 1 | |||||||
---|---|---|---|---|---|---|---|---|
ニブル | 1 | 0 | ||||||
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
メモリの内容 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 |
2進数と16進数
1ビットで2つの状態を表せますが、1バイト(8ビット)ではビットの組み合わせでいくつの状態を表わせるのでしょうか? 8ビットのすべての組み合わせを表にすると大きすぎるので、4ビットで試してみましょう。
10進 | 16進 | 2進 | |||
---|---|---|---|---|---|
3 | 2 | 1 | 0 | ||
0 | 0 | 0 | 0 | 0 | 0 |
1 | 1 | 0 | 0 | 0 | 1 |
2 | 2 | 0 | 0 | 1 | 0 |
3 | 3 | 0 | 0 | 1 | 1 |
4 | 4 | 0 | 1 | 0 | 0 |
5 | 5 | 0 | 1 | 0 | 1 |
6 | 6 | 0 | 1 | 1 | 0 |
7 | 7 | 0 | 1 | 1 | 1 |
8 | 8 | 1 | 0 | 0 | 0 |
9 | 9 | 1 | 0 | 0 | 1 |
10 | A | 1 | 0 | 1 | 0 |
11 | B | 1 | 0 | 1 | 1 |
12 | C | 1 | 1 | 0 | 0 |
13 | D | 1 | 1 | 0 | 1 |
14 | E | 1 | 1 | 1 | 0 |
15 | F | 1 | 1 | 1 | 1 |
1ビットで2種類、4ビットで16種類となりました。一般にNビットで 2 N 種類の組み合わせが表現できます。したがって、8ビットでは 2 8 で256になります。同じように16ビットで65536、32ビットで4294967296(約42億)、64ビットで18446744073709551616(約1844京)種類の組み合わせが表現できます。メモリの単位として8ビットを使いましたが、人が扱うには 256 種類の状態は区別するには多すぎます。そこで8ビットを4ビットずつの2つに分け 16x16 と考えることにします。最初の表で 4ビットの単位に「ニブル」という名前を付けています。最近はニブルという呼び方はまったくといっていいほど使いませんが、4ビットを1桁とする16進数はコンピュータでは10進数よりよく使います。0から16までを1桁とすると、数字が足りません。そこで「9」より大きい数字を「A」「B」「C」「D」「E」「F」とアルファベットの文字を使って 16 種類の数字とします。このように4ビットを1桁とする16進数 が 10 進数と近く、慣れが必要かもしれませんが、扱いやすいためよく使われます。また、大きな数を考える場合はキロ、メガ、ギガ、テラという単位が使われますが、 2 10 が1024になることを使うと、10ビット単位でキロ、メガという1000倍を基準にする数え方とほぼ一致します。
名前 | 記号 | 乗数 |
---|---|---|
キロ | K | 210 = 1,024 |
メガ | M | 220 = 1,048,576 |
ギガ | G | 230 = 1,073,741,824 |
テラ | T | 240 = 1,099,511,627,776 |
ペタ | P | 250 = 1,125,899,906,842,624 |
エクサ | E | 260 = 1,152,921,504,606,846,976 |
数が大きくなると1000を基準とする場合と1024を基準とする場合でズレが大きくなってきますが、メモリは1024を基準とし、ハードディスクやDVDなどの記憶媒体は1000を基準(大きく見える)にしている場合が多いのでちょっと注意が必要です。1024を基準にする場合はキビ(Ki)、メビ(Mi)、ギビ(Gi) という表し方もありますが、ほとんど普及していません。
2の補数
2進数で負の値を表す場合に使われる方法です。ある数αの32ビットの2の補数表現という場合、
α+β= 232
が成立するβになります。 この場合、232 は 33ビットの数値 (100000000000000000000000000000000) となっていることに注意してください。
ある数 α の N ビットの2の補数表現 β は以下の式で求めることができます。
β= 2N - α
1の補数 (one's complement) は単に各ビットを反転させたものですが、2 の補数 (two's complement) は 1 の補数 に 1 を加えたものとして求めることもできます。最上位ビットが 0 の場合は正、1 の場合は負として扱います。2 の補数表現を符号付表現とも呼びます。アセンブリ言語で「符号なし/符号付き」という表現は整数をすべて正として扱うか、2 の補数表現として扱うかをあらわしています。C の unsigned int と signed int と同じ意味です。 絶対値正負の整数の加算が正しい値(桁あふれは無視する)となり、また32ビット数を64ビットに拡張する場合でも、最上位ビットを拡張された分だけコピーするだけです。
下の表は4ビットの2進数とその1の補数、2の補数、4ビットの2の補数として10進表現したものです。2 の補数が 24 = 16 (10000) から減算したものと同じとなることが確認できます。
10進 | 2進 | 1 の補数 | 2 の補数 | 2の補数の 10進表現 |
---|---|---|---|---|
0 | 0000 | 1111 | 0000 | 0 |
1 | 0001 | 1110 | 1111 | -1 |
2 | 0010 | 1101 | 1110 | -2 |
3 | 0011 | 1100 | 1101 | -3 |
4 | 0100 | 1011 | 1100 | -4 |
5 | 0101 | 1010 | 1011 | -5 |
6 | 0110 | 1001 | 1010 | -6 |
7 | 0111 | 1000 | 1001 | -7 |
8 | 1000 | 0111 | 1000 | -8 |
9 | 1001 | 0110 | 0111 | 7 |
10 | 1010 | 0101 | 0110 | 6 |
11 | 1011 | 0100 | 0101 | 5 |
12 | 1100 | 0011 | 0100 | 4 |
13 | 1101 | 0010 | 0011 | 3 |
14 | 1110 | 0001 | 0010 | 2 |
15 | 1111 | 0000 | 0001 | 1 |
メモリ
メモリはプログラムやデータを格納するために使います。プログラム本体もプログラムが使用するデータも同じようにメモリに1バイト単位で格納されます。メモリには下の図のように1バイト単位で番地(アドレス)をつけます。0番地からメモリ全体に番地を振ります。特定のアドレスのメモリを指定するためにレジスタを使いますが、メモリ全体を指定できるだけの大きさが必要です。32bitのCPUの場合、レジスタも32ビットで、0から約40億までの番地を指定できます。これが使用できるメモリの量を制限します。したがって32bitのCPUのメモリ空間の上限は4GBということになります。64bit の CPU では理論的な上限は16エクサバイトという非常に大きなメモリ空間が可能となります。現在の実際のCPUでは 1テラバイト程度のメモリが上限となっています。64bitではメモリの上限は金額や物理的なサイズで制限されることになります。
メモリアドレス | メモリの内容 | |||||||
---|---|---|---|---|---|---|---|---|
16進数アドレス | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0000000000000000 | ||||||||
0000000000000001 | ||||||||
0000000000000002 | ||||||||
0000000000000003 | ||||||||
0000000000000004 | ||||||||
0000000000000005 | ||||||||
: : |
: : |
|||||||
FFFFFFFFFFFFFFF9 | ||||||||
FFFFFFFFFFFFFFFA | ||||||||
FFFFFFFFFFFFFFFB | ||||||||
FFFFFFFFFFFFFFFC | ||||||||
FFFFFFFFFFFFFFFD | ||||||||
FFFFFFFFFFFFFFFE | ||||||||
FFFFFFFFFFFFFFFF |
レジスタ
コンピュータの中でメモリはどのように使われるのでしょうか? 「メモリはプログラムやデータを格納するために使います。」と書きましたが、メモリの内容はメモリと同じように数値を格納できるレジスタにコピーされて計算したり、比較されたりといった処理が行われます。その結果をレジスタからメモリに格納することもできます。また、メモリ番地を指定するにもレジスタを使います。インストラクションポインタ(プログラムカウンタともいう)というレジスタは実行する命令が格納されているメモリアドレスを保持します。下の図は64ビットのレジスタを示します。レジスタは64ビットの数値(qword)だけではなく、8ビット(byte)、16ビット(word)、32ビット(dword)の数値をレジスタの一部分を使って扱うこともできます。 x86-64 のレジスタは次のページで詳しく紹介します。
byte 7 | byte 6 | byte 5 | byte 4 | byte 3 | byte 2 | byte 1 | byte 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
qword | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dword | dword | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
word | word | word | word | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
byte | byte | byte | byte | byte | byte | byte | byte |
x86-64の64bitモードのレジスタには32本の汎用レジスタとフラグレジスタ以外にも特殊命令用の多くの種類がありますが、OSを作る場合以外は必要ないでしょう。