8086のセグメントレジスタはなぜ16bitの幅を持っているのですか？


これを読んでいると、以下の文がありました。

<https://ja.wikipedia.org/wiki/Intel_8086>

>
> 演算用のアドレスレジスタのほかに、セグメントレジスタという、アドレス変換のための16ビットのレジスタを持っていることである。実際にCPUがアクセスするアドレスは、16ビット幅のレジスタによって指定された64KBのアドレスに、さらに16ビット幅のセグメントレジスタの値を16倍（左に4ビットシフト）して加算したアドレスとするため、1MBのメモリ空間を利用できた。

これは、

セグメントレジスタ：0x0000  
アドレスレジスタ：0x00ff  
と、  
セグメントレジスタ：0x000f  
アドレスレジスタ：0x000f

は同じ場所を示すということでしょうか。  
そうだとして、なんのためにそのような仕様にしたのでしょうか。  
メモリ空間を64KBから1MBに増やすことが目的なら、セグメントレジスタの幅を4bitにすればいいのではないのでしょうか。そうすれば、セグメントレジスタ＋アドレスレジスタで20bit、つまり1MBを表現できるわけですし。




「なぜ」の回答は @y_waiwai さんの通り 16bit CPU だから。わざわざ 4bit レジスタなんてものを用意すると `PUSH` /
`POP` 等で困ってしまいます。

もう一つ理由を挙げるなら物理アドレスの表記方法が複数あるほうがソフトウエアの実装に便利だから。

物理アドレス [0x1EEE8, 0x2345F] の範囲のデータを、物理アドレス 0x4FF08 からにコピーしたいという場合

  * セグメントレジスタが 4bit の場合  
セグメントレジスタの値を、コピー元で１回、コピー先で１回、違うタイミングで変更する必要がある。セグメントレジスタを更新するとオフセットは計算しなおし。

  * セグメントレジスタが 16bit の場合  
コピー元として [0x1EEE:0x0008-0x1EEE:0x457F] コピー先を [0x4FF0:0x0008-]
に正規化してから開始すると途中でセグメントレジスタを更新しなくてよい。オフセットだけで処理可能

処理開始時に正規化すると１オブジェクトの処理中にセグメントレジスタを更新しなくてよいというのはソフトウエア実装側としては楽できます（＝高速）。逆に言うと
8086 では１オブジェクトの大きさがメモリ上 64KiB を超過すると、処理中に必ずセグメントレジスタの更新が必要で超絶遅くなります。

セグメントレジスタが 4bit なマイコンとしては Renesas RL シリーズなんかがそうですね。 8086 ユーザーを取り込むべくレジスタ名として
`CS` / `ES` なんて名前が付けてありますが実装は全く異なるです。小規模用途向けマイコンだから 64KiB
を超えるようなデータを扱うことはまれという設計思想でそうなっています。

