8086

**Intel 8086**（亦稱之為 **iAPX 86**）是由英特爾公司於 1976 年初開始設計，1978 年年中發表的 Intel 第一款 16 位元微處理器。隨後於 1979 年，又推出了 Intel 8088，它在晶片的外部連接椎使用 8 位元資料匯流排（允許使用更廉價和更少積體電路）的支援，成為 8086 的一個低成本的簡化產品，並用在 IBM PC 的原始設計中的處理器（包括廣為人所知的 IBM PC XT）中而被人知曉。

8086 是 Intel 最成功的處理器系列 x86 架構的開端。

## 歷史

### 背景

1972 年，Intel 發表了 8008 微處理器 —— 世界上第一款 8 位元微處理器。 8008 微處理器有 18 個引腳，其中位址匯流排使用了 14 個引腳，並且與 8 位元資料匯流排復用引腳。指令集源自是 Datapoint 公司為電腦的 CRT - 鍵盤終端設計的但相當通用的指令集。當時英特爾還是一家生產 DRAM 為主業的公司，缺乏這方面的技術儲備。

1974 年，Intel 發表了 8080 微處理器， 被公認是第一款真正可用的微處理器。8080 的晶片封裝採用 40 個引腳，其中 8 個資料匯流排引腳、16 個位址匯流排引腳都是專用的，因此資料匯流排與位址匯流排可以並列工作。8080 的擴充後的指令集在原始碼級別上向前相容 8008 指令集。

1975 年，Intel 發表了第三款 8 位元微處理器 ——8085。採用了新的製造工藝，簡化了輸入電壓引腳的數量。同一時期還有 Motorola 6800（1974）、Microchip PIC16X（1975）、MOS Technology 6502（1975）、Zilog Z80（1976）及 Motorola 6809（1978）等 8 位元微處理器。在 8 位元微處理器市場競爭中 Z80 最為成功。

### 第一種 x86 設計

8086 專案起始於 1976 年 5 月，是英特爾公司當時更為看重的 16 位元的 iAPX 432 微處理器的備份專案。8086 一方面要與 Motorola, Zilog, National Semiconductor 等公司的 16 位元、32 位元微處理器競爭市佔率，另一方面也是對 Zilog Z80 在 8 位元位微處理器市場上的成功的回擊。由於採用了與 8085 微處理器近似的微體系結構與物理實現工藝製程，8086 專案進展相當快。

8086 微處理器被設計為在組譯源程式上向前相容 8008, 8080, 8085 等微處理器。指令集與編程模式是基於 8080 微處理器，但指令集做了擴充以完全支援 16 位元運算。

新增加的指令包括：完全支援有符號整數、段基址 + 偏移量定址、類似於 Z80 的自重複操作、直接支援巢狀的 ALGOL 類語言如 Pascal 或 PL/M、微碼實現的乘法除法指令、以及更好支援與協處理器（8087 或 8089）和多處理器系統的匯流排結構。

第一版的指令集與高層的體系結構的設計僅用了 3 個月。 在沒有 CAD 工具的時代，4 名工程師與 12 名布線繪圖員平行工作， 用了 2 年多的時間才把 8086 的高層設計實現為可執行測試的產品。這在當時算是很快的研發速度。

8086 是隨機邏輯與微碼的混合實現，使用了大約 20,000 個電晶體（算上所有的 ROM 與可程式化邏輯陣列為 29,000 個電晶體）。晶片面積為 33 mm²，製程為 3.2 μm.

8086 體系結構由 Stephen P. Morse 設計，並在最後定案時得到 Bruce Ravenel（8087 體系結構設計者）的幫助。邏輯設計者是以 Jim McKevitt 與 John Bayliss 為首的硬體開發工程師團隊。專案經理 William Pohlman。迄今 8086 的指令集仍然是個人電腦與伺服器的基本指令集。

## 細節

### 匯流排與操作

所有的內部暫存器、內部及外部資料匯流排都是 16 位元寬，因此是完全的 16 位元微處理器。20 位外部位址匯流排，因此**物理定址空間**為 1MiB (即 220 = 1,048,576). 由於內部暫存器都是 16 位元，對 1M 位址空間定址時採取了段定址方式。8086 的封裝採用 40 引腳的雙列直插（dual in-line），資料匯流排與位址匯流排復用了前 16 個引腳。16 位元的 I/O 位址，因此獨立的 I/O 定址空間為 64KiB 的**虛擬定址空間** (即 216 = 65,536). 由於 8086 內部的位址暫存器是 16 位寬，因而最大線性定址空間為 64 KiB. 使用超過 64 KiB 記憶體空間的程式設計時，需要調整段暫存器（segment registers）。直到 32 位元的 80386 出現之前，8086 的這種段定址相當不便.

8086 晶片封裝的 8 個控制引腳在 _min_ 或 _max_ 下有不同功能。"min" 模式是使用單處理器的小型電腦系統，"max" 模式是使用多處理器的中到大型電腦系統。

### 暫存器與指令

8086 有 8 個 16 位元的暫存器，包括棧暫存器 SP 與 BP，但不包括指令暫存器 IP、控制暫存器 FLAGS 以及四個段暫存器。AX, BX, CX, DX, 這四個暫存器可以按照位元組存取；但 BP, SI, DI, SP, 這四個位址暫存器只能按照 16 位元寬存取。

8086 以 8080 和 8085（它與 8080 有組譯語言上的原始碼相容性）的設計為基礎，擁有類似的暫存器集合，但是擴充為 16 位元。匯流排介面單元（Bus Interface Unit）透過 6 位元組預存（prefetch）的貯列（queue）將指令送給執行單元（Execution Unit），所以取指令和執行是同步的－一種管線的原始形式（8086 指令長度變化從 1 到 6 位元組）。

8086 有四個完全一樣的 16 位元暫存器，但也能夠當作八個 8 位元暫存器來存取；以及四個 16 位元索引暫存器（包含堆疊索引）。資料暫存器通常由指令隱含地使用，針對暫存值需要複雜的暫存器組態。它提供 64K 8 位元的輸出輸入（或 32K 16 位元）埠，以及固定的向量中斷。大部分的指令只能夠存取一個記憶體位址，所以其中一個運算子必須是一個暫存器。運算結果會儲存在運算子中的一個。

8086 有 4 個記憶體區段（segment）暫存器，可以通過索引暫存器來設定。區段暫存器可以讓 CPU 一種當時是全新的方式存取多達 1MB 之記憶體。在現今有區段的處理器中，8086 把區段暫存器左移 4 位元然後把它加上去定址。這通常被認為是一個不太好的設計，因為這麼做會讓各區段有重疊。儘管這樣對於組譯語言而言會顯得有用 —— 因為可以充分控制區段，但同時卻使高階語言中的指標（像是 C 程式語言）使用變得困難。它降低了指標的高效率，且有可能產生兩個指向同一個地方的指標擁有不同的位址。更壞的是，這種方式產生要讓記憶體擴充到大於 1MB 的困難。而 80286 的定址方式改變讓記憶體擴充較有效率。

由於 8 位元機（如 Intel 8008）時代沿襲下來的緊湊編碼，大多數指令雖然有兩個源運算元（operands）及一個輸出結果，但單條指令至多使用兩個位址，因此運算結果被存入一個源運算元中。且最多只能有一個記憶體運算元，另外的運算元是暫存器或立即數。記憶體運算元也可以用於儲存指令的輸出結果。8 位元微處理器的指令集不能把輸出結果直接儲存在記憶體運算元中，因此 8086 指令集的如此設計大大提高了代碼密度（code density）。

相比與 8080 或 8085，8086 有更強的暫存器通用性，但比起典型的小型電腦來說仍有很大不如。8086 的某些指令隱式使用某些暫存器。比起更為規則的 16- 或 32 - 位處理器如 PDP-11, VAX, 68000, 等等，8086 的暫存器分配特性使得編譯器的工作更為複雜；另一方面，比起半現代化的但廣為使用的 8 位元微處理器如 6502, 6809, 或 8085, 編譯器生成代碼就容易太多了.

8086 有 64 KiB 的字寬為 8 位元的（或 32K 個寬度為 16 位元的）I/O 定址空間.

棧的長度最大為 64 KB（一個段） ，8086 硬體支援棧頂由高位址向低位址生長。入棧、彈棧的資料單元長度為 2 位元組。棧頂位置由暫存器的組合 SS:SP 給出.

共有 256 個中斷，包括硬體中斷與軟中斷。中斷可以巢狀，使用棧來儲存中斷返回位址。

8086 增加了一些 8080 與 8085 所沒有的新指令，用於更好地支援 Pascal 與 PL/M 的進階程式設計特性；如 **push** _mem-op_, **ret** _size_, (其它一些指令如 **push** _immed_ and **enter**, 在隨後的 80186, 80286, and 80386 中陸續增加.)

### 標誌暫存器

8086 有一個 16 位元寬的標誌暫存器 FLAGS. 其中 9 個位元是被使用的，另外 7 個位元保留未用。具體是：進位標誌 CF、奇偶標誌 PF、輔助標誌 AF、為零標誌 ZF、符號標誌 SF、追蹤標誌 TF、中斷允許標誌 IF、方向標誌 DF、溢位標誌 OF。

### 記憶體分段

在 Intel 的 8 位元、16 位元處理器中，由於暫存器的寬度為 8 或 16 位元，而位址匯流排的寬度一般是要大於暫存器的寬度，所以為了能存取整個位址空間，需要採取特殊的定址計算 —— 分段定址。從 80386 開始的 32 位元微處理器，位址匯流排寬度也是 32 位元，可以視作扁平（flat）位址空間，不再需要分段定址。

8086 的分段定址，是指一個實體位址由**段位址**（segment selector）與**偏移量**（offset）兩部分組成，長度各是 16 位元。其中段位址左移 4 位元（即乘以 16）與偏移量相加即為實體位址。例如，06EFh:1234h，表示段位址為 06EFh, 偏移量為 1234h, 實體位址為 06EF0h + 1234h = 08124h。在計算實體位址時如果發生上溢位，8086 處理器捨棄進位。例如，FFFFh：0010h 所對應的實體位址為 00000h.

一個 20 位的實體位址對應著 4096 個不同的 "段位址：偏移量" 的組合。這是因為，偏移量的最低 4 位元對應於實體位址的最低四位，而偏移量的高 12 位元共有 4096 個取值。

段位址所對應的實體位址的粒度是 16 位元組（=24），稱之為 paragraph。

段位址確定後，偏移量的取值最多為 64KiB（=65536），這就是分段定址的最大的線性位址空間。實際上在 8086 處理器上，作業系統分配的線性位址空間可以是不大於 64KiB 的任意數量。程式可以自由存取整個實體記憶體空間，作業系統沒有任何權限限制或監管（supervision）。

8086 處理器有 20 根位址匯流排引腳（pins），因此實體記憶體空間最大為 220=1MiB=1,048,576 位元組。這還包括了 IO 記憶體。因此使用 8086 處理器的電腦的主記憶體的容量少於 1MiB，最常見的主記憶體容量是 640KiB。

由於 X86 指令集的向下相容原則，計算實體位址時，段位址左移 4 位元被所有後繼支援真實模式的 X86 處理器所繼承。80286 是使用 24 位元寬位址匯流排的 16 位元微處理器，如果要在整個 224=16MiB 物理儲存空間定址，就必須採用其它方式，即保護模式定址，這時 16 位元的段位址是指向**段描述符**表（segment descriptors table）的一個包含 24 位元基位址的條目，基位址加上 16 位元偏移量即為 24 位元的實體位址。

在 8086 上執行的編譯器，一般支援兩種 C 語言的指標：近指標（near）與遠指標（far）。近指標是 16 位元的位址偏移值，隱式與程式的代碼段位址或資料段位址結合使用以確定實體位址。遠指標是 32 位元的「段位址：偏置量」成對出現，用以確定 20 位的實體位址。某些編譯器支援「巨指標」（huge），類似於遠指標。但巨指標的位址運算是線性 20 位；而遠指標的位址運算在 16 位元偏移值溢位時不影響段位址部分，因此遠指標的線性部分是 16 位元。

為了避免對大量的指標、資料結構、函式指出是「近」還是「遠」，編譯器提供了記憶體模式（memory model）給出了預設的記憶體存取方式：

* 微模式 _tiny_ 資料段代碼段共享不超過 64K 記憶體空間，編譯為.com 可執行檔；
* 小模式 _small_ 資料段、代碼段各用最多 64K 記憶體共空間；
* 緊湊模式 _compact_ 資料段 > 64K；
* 中模式 _medium_ 代碼段 > 64K；
* 大模式 _large_ 代碼段資料段都 > 64K；
* 巨模式 _huge_ 單個陣列 > 64K。

預編譯庫對不同的記憶體模式要分別編譯為相應版本。

#### 移植老的程式

8 位元機上的程式可以不考慮段位址直接以.com 可執行檔以「微模式」在 8086 上執行。這是當時 8086 與 MS-DOS 作為新平台取得市場成功的關鍵原因 —— 大量已存的 CP/M 應用程式能很快得到利用。

### 實例代碼

以下 8086/8088 組譯原始碼是將給定大小的資料塊從一個位置拷貝到另一個位置的叫做 `_memcpy` 的子程式。每次拷貝一個位元組，資料移動和迴圈邏輯採用 16 位元操作。

上面的代碼使用 BP（基指標）暫存器建立一個呼叫影格（包含子程式執行過程中的所有參數和局部變數的棧的區域）。這種呼叫約定支援可重入和遞迴代碼，大多數類 ALGOL 語言上世紀 50 年代後期就已採用這種約定。ES 段暫存器儲存在堆疊上，並用 DS 段暫存器中的值替換，於是指令 `MOV` `AL` 會在相同的源資料段和目的資料段之間操作。在返回前，子程式恢復了 ES 暫存器以前的值。

上面的子程式是一種比較麻煩的拷貝成塊資料的方法。若源資料區域和目的資料區域都是處於單個 65,536 位元組的段中（上述程式的要求），使用 8086 的塊 `MOV` 指令更有優勢。上面的迴圈部分可以替換為：

這種方法每次可以拷貝一個字。`REP` 指令使下面的 `MOVSW` 重複直至 CX=0，重複之時自動遞增 SI 和 DI。另外，`MOVSB` 或 `MOVSD` 指令可以用來一次拷貝單個位元組或雙字。大多數組譯器在 `REP` 指令用在 `MOVSW` 之前為 `REP MOVSW` 的情況下都會正確組譯。

如果被中斷，這個程式也能正確執行，因為程式計數器會繼續指向 `REP` 指令，知道塊拷貝已經結束。拷貝會在中斷服務程式將控制恢復的時候繼續。

### 效能

外部匯流排作為資料與位址的復用，降低了 CPU 的效能。取 16 位元或 8 位元資料需要 4 個時鐘周期。指令的長度為 1-6 個位元組，取指令與執行是並行完成的。CPU 內的匯流排介面單元把取到的指令儲存在 6 位元組的預取佇列中。

* EA = 計算有效位址的時間，5 到 12 周期.
* 用時為最好的情形，依賴於預取狀態，指令對齊，及其它因素.

8086 涉及記憶體存取的指令，包括跳轉（jump）指令需要比 8080 與 8085 更多的時間，原因在於：

* 取指令與執行指令是鬆散耦合，對於跳轉與亂數據存取沒有特殊措施，效率較低.
* 沒有專門的位址計算部件，只能用主 ALU，雖然有專用的_段位址_ + _偏移位址_的加法器
* 外部位址匯流排與資料匯流排是多工復用，與 8 位元處理器相比要多用 33~50% 的匯流排周期

8086 的後繼處理器的記憶體存取效能大大增強了。80186 與 80286 有專門的位址計算硬體，節約了很多時間周期。80286 的外部位址匯流排與資料匯流排是分開各自專用的。

### 浮點

8086/8088 可以連接上專用的數學協處理器以增加浮點計算效能。標準的數學協處理是 Intel 8087，執行 80 位元浮點數運算。

## 使用 8086 的微電腦

第一個以 8086 為基礎的商業微電腦是 Mycron2000。

IBM Displaywriter 文字處理機也使用 8086。在大部分顯要的所有微處理器中，IBM PC 使用了更窄的記憶體總線版本的 8086，也就是 Intel 8088。
8086CPU 結構上的一個重要特點是分為二大部分，即總線介面單元 BIU 和執行單元 EU，其中 BIU 負責外部資訊交換，EU 負責指令執行，二者合理分工、並行工作，工作效率比此前的 CPU 明顯提高，常稱之為流水線結構。

## 硬體模式

8086 和 8088 支援兩種硬體模式：最大模式和最小模式。最大模式是用在大型應用中的多重處理，並且也是支援 8087 處理器的必需。該模式通常硬體化在電路中，不能由軟體改變。具體來說，#33 引腳（MN/MX）是連載高電壓還是接地決定了模式。改變引腳 #33 的狀態就改變了其他特定引腳的功能，這些引腳中大多數是 CPU 處理（局部）匯流排的。IBM PC 和 PC/XT 使用工作在最大模式的 Intel 8088，讓 CPU 與 PC 或 PC/XT 主機板上安裝在數學協同處理器插口的可選 8087 協同處理器。（PC 和 PC/XT 可能因為其他原因而要求用最大模式，比如要支援 DMA 控制器。）

## 外設

* Intel 8237：直接記憶體存取（DMA）控制器
* Intel 8251：USART
* Intel 8253：可程式化間隔定時器
* Intel 8255：可程式化序外圍介面
* Intel 8259：可程式化中斷控制器
* Intel 8279：鍵盤 / 顯示控制器
* Intel 8282/8283：8 位元鎖存器
* Intel 8284：時鐘發生器
* Intel 8286/8287：雙向 8 位元驅動
* Intel 8288：匯流排控制器
* Intel 8289：匯流排仲裁器

## 紀念

2018 年 6 月 8 日，英特爾在官網上開啟了限量抽獎活動，獎品為 i7-8086k，限量生產 8086 個。

## 注釋

## 參考文獻

## 外部連結

* Intel 8086/8088 images and descriptions at cpu-collection.de （頁面存檔備份，存於網際網路檔案館）
* 8086 visual microprocessor emulator（頁面存檔備份，存於網際網路檔案館）

 

_Article based on Intel 8086 at FOLDOC（頁面存檔備份，存於網際網路檔案館），used with permission._