1: 2005-07-21 (木) 15:48:05 |
現: 2024-01-06 (土) 22:39:13 |
| | | |
| | | |
- | | + | *16bit(8086)のセグメント [#qbded341] |
- | | + | |
- | | + | |
| セグメントとはなんじゃらほい? | | セグメントとはなんじゃらほい? |
| | | |
- | 8086CPUは、最大1MBのメモリをアクセスできる。 | + | 8086は16bitですね。内部には沢山のレジスタがありますが、ほぼどれも最大16bitです。 |
| | | |
- | (「アクセスできる」とは、逆に言えば、それ以上メモリ装置が搭載されていても、アクセスできないということ) | + | CPUがメモリにアクセスする場合、当然メモリの番地を指定しなくてはなりませんが、そのためのレジスタも16bitです。 |
| | | |
- | なぜ???? | + | ん?おかしいですね?。メモリの番地を指定するためのレジスタも16bit。(16進数で4桁です。)そうなると・・・ |
| | | |
- | メモリの指定には、必ず「番地」を指定しなければいけない。 | + | 0x0000〜0xffff |
| | | |
- | この番地の指定に使われるCPU内のレジスタが16bitしかないから。 | + | です。最大0xffffということは、十進数に直すと・・・65,535・・・え? ''最大''64KB??? |
| | | |
- | 16ビット= 0x0000 〜 0xFFFF まで。十進数に直すと0〜65535。 | + | そうです。CPUの素直な仕組みで考えると、16bitのCPUは、最大64KBしかメモリをアクセスすることができません。・・・しかし、8086は最大1MBを活用することができるのです。いったいどうやって??? |
- | つまり、65,535バイト。あれれれ? たった64KB????? | + | |
| | | |
- | 8086はたったこれだけのメモリしかアクセスできない!? | + | 8086CPUは大きなメモリ空間を64KBごとに区切り、各区切りを別の16bitのレジスタで指定することによって、事実上20bit(16進数で5桁)でメモリ番地を指定することができます。この64KBの区切りを''セグメント''と言います。 |
- | 「素」の理屈から言えばそうなる。これでは少なすぎるので、8086はちょっと変わった方式を採用している。 | + | |
| | | |
- | メモリアドレスを20ビットで表現できるようになっている。これなら、0x000000〜0xFFFFFF。つまり、16,777,215バイト。1MBとなる。 | + | メモリ番地を20ビットで表現。これなら、0x00000〜0xFFFFF。つまり、1,048,575バイト。1MBとなる。 |
| | | |
- | しかし、レジスタは16ビット。これでどうやって20ビットを表現するのか? | + | 具体的には、「セグメントアドレス」+「オフセット値」でアドレスを表現する。 |
- | | + | |
- | 「セグメントアドレス」+「オフセット値」でアドレスを表現する。 | + | |
| | | |
| セグメントアドレスもやはり16ビットでしか表現できない。で、それ+何番地ずれているかを表現する。 | | セグメントアドレスもやはり16ビットでしか表現できない。で、それ+何番地ずれているかを表現する。 |
| | | |
- | たとえば、物理的に0x112233番地のメモリにアクセスしたいとする。その場合、レジスタはみな16ビットではあるが、 | + | たとえば、物理的に0x21000番地のメモリにアクセスしたいとする。その場合、レジスタはみな16ビットではあるが、 |
- | | + | |
- | セグメントアドレス:1122 | + | |
- | オフセットアドレス:0033 | + | |
- | | + | |
- | これで表現する。 | + | |
| | | |
| + | セグメントアドレスに:0x2000 (セグメントベースという) |
| + | オフセットアドレスに:0x1000 (オフセット値という) |
| | | |
| + | とセットすると、 |
| | | |
| + | 0x2000x16 = 0x20000 |
| + | + |
| + | 0x1000 |
| + | -------------------- |
| + | 0x21000 |
| + | こう解釈して内部回路に信号を送り、0x21000番地のメモリにアクセスしてくれる。 |
| | | |
| + | 図にする・・・ |
| | | |
| + | 物理アドレス |
| + | 0x00000 ┌──────┐ |
| + | │セグメント │ |
| + | │ (64kb) │ ┌─── ここを読みたい! |
| + | 0x10000 ├──────┤ │ |
| + | │セグメント │ │ 0x21000とかの指定はできない。 |
| + | │ │ │ (だってレジスタが16bitだもん) |
| + | 0x20000 ├──────┤ │ |
| + | │セグメント │ │ そこで、セグメントレジスタにセグメント |
| + | │ │←─┘ のベース番地を指定する。(頭4桁だけ) |
| + | 0x30000 ├──────┤ |
| + | │セグメント │ 0x2000:0x1000 (セグメントベース:アドレス) |
| + | │ │ これで0x21000にアクセスしてくれる |
| + | 0x40000 ├──────┤ |
| + | : │セグメント │ |
| + | : : : |
| + | : : : |
| + | 0xE0000 ├──────┤ |
| + | │セグメント │ |
| + | │ │ |
| + | 0xF0000 ├──────┤ |
| + | │セグメント │ |
| + | │ │ |
| + | 0xFFFFF └──────┘ |
| + | (1MB) |
| | | |
| + | ※少々乱暴な考え方をすれば、この16bit(8086時)のセグメントはとても変則的で無茶な方法といえるかも。整合性や理屈で考えれば、16bitのまま無理に1MBを使えるようにするより、20bitのCPUを開発するというのが本当といえないか。(もちろんあくまでも後付のお評論家的な話ってことで。) |
| | | |
| | | |
| + | *32bit(i386)のセグメント [#p6116747] |
| + | セグメントは元来は、上記の通り16bitでなんとか1MBのメモリを使うための変則的手法だったが、32bitになると使用法や意味合い・存在意義が変化する。 |
| | | |
| + | 32bit状態になると、BXレジスタ(主にアドレスを指定する)も32bit化してEBXレジスタに変化する。32bitなのだから、0x00000000〜0xffffffffまで。すなわち4GBまで番地を直接指定できる。普通に考えればもうセグメントなど必要ではない。 |
| | | |
| + | しかし、32bit状態(i386)のCPUはマルチタスク(いくつものプログラムが平行して動作する)を意識している。そのため、この「セグメント」というメモリ分割管理の仕組みをうまく別の用途に転用することにしたようだ。 |
| | | |
| + | まず、GDTという、メモリ分割場所の表を用意する。この表はプログラム(主にOS)で設定する必要がある。GDT表はこんな感じになる。 |
| | | |
| + | |セグメント番号|セグメントの大きさ|セグメントの開始番地|セグメントの属性|h |
| + | |0|1MB|0x30000000|書き込み禁止| |
| + | |1|32MB|0xA0000000|OS専用| |
| + | |2|7MB|0x43880000|実行禁止| |
| + | |3|512KB|0xBA500000|OS専用,書き込み禁止| |
| + | |4|2MB|0x90000000|特になし| |
| + | |>|>|>|CENTER::| |
| + | |8,191|2MB|0xCF8600000|書き込み禁止| |
| + | ※逆に言えば、GDTを設定しておかないとセグメントが使えない |
| + | ~ |
| + | ~ |
| + | この状態で、セグメントレジスタに「4」を入れ、EBXレジスタに0x00001111を入れてアクセスしたとする。するとCPUは、 |
| + | --えーっと。セグメント番号は4かぁ。 |
| + | --じゃ、GDTの4番を見に行こう。ええと、開始番地は0x90000000だね。 |
| + | --大きさは2MBだから、EBXの値も問題ないね。 |
| + | --属性も特に問題はないか。 |
| + | --ええと、そうすると、0x90000000+0x00001111だから・・・ |
| + | --そうか。物理的な0x90001111番地にアクセスすればいいのか! |
| | | |
| + | と、こう判断して動作を実行する。 |
| | | |
| | | |
| + | 特にアプリケーションプログラムなどでは、作る段階では |
| | | |
| + | -とにかくこのプログラムは、0x00000000番地に読み込まれてスタートするのだ! |
| | | |
| + | という想定で作ればよい。OS側が適切にセグメントをセット&選択してくれるので、上記のような物理アドレスの位置をプログラムが意識しなくてもちゃんと動作してくれる。 |
| | | |
- | ここで登場するのが、「セグメント」という概念。 | |
| | | |
- | ''模式図的概念'' | |
- | 例えば、「電話番号」に置き換えて考えてみる。我々が住んでいる現世は沢山の家がある。しかし、電話番号にはある制約があって、一回に4桁までしか決められないとする。 | |
- | そうすると、電話番号は9999までしか作れない。日本でたった千件しか電話をもてない。 | |
- | これでは困る。そこで、「局番」というものを導入。局番には、「何処の県か?」という番号が振られている。だから、いままでは、2845という電話番号は、「日本全国の中の、2845番のお宅」という状態だったが、局番の導入によって、電話番号は、0012-2845という形になり、「北海道の2845番のお宅」「北九州のの2845番のお宅」という指定ができるようになり、電話番号をたくさん使えるようになった。 | |
| | | |
- | セグメントは、この「局番」に当たる。 | |
| | | |
| | | |