## 14.7 與8086的不同
通常,80386會正確的執行ROM中為8086,8088,80186和80188設計的軟件。下面是一些8086和80386在執行過程中的一些細微區別。
1.指令時鐘計數。
大部分指令的執行過程,80386花費的時鐘要比8086/8088要少。
這主要影響到一下幾個方面:
+ I/O操作要求的延時。
+ 操作并口連接的80387過程中設定的延時。
2.DIV指令的除法異常觸發點。
80386的除法異常總是將CS:IP指向失敗的指令。8086/8088指向下一條指令。
3.未定義的8086/8088操作碼。
執行在8086/8088中未定義的操作碼將導致異常6或者執行80386中定義的新指令。
4.PUSH SP寫入值。
80386在執行PUSH SP時放入堆棧的值與8086/8088不同。80386把增加SP作為指令的一部分,在SP改變之前將其入棧;8086/8088在增加SP之后再將其入棧。如果入棧的值很重要,用下面的三條指令代替PUSH SP:
```
PUSH BP
MOV BP, SP
XCHG BP, [BP]
```
上面的代碼在80386中的執行結果和8086/8088中的PUSH SP。
5.超過31位的移位或循環移位。
80386將所有移位和循環移位操作計數的低位5位作為掩碼。這種用32取模的操作將計數值限制為最多31位,以此來限制在執行中的代碼被中斷的時間。
6.冗余前綴。
80386限制指令的最大長度為15個字節。突破這個限制的唯一方法是在指令的前面使用冗余前綴。超過長度限制的指令將導致異常13。8086/8088沒有指令長度限制。
7.操作數越過0或65536。
對于8086,試圖訪問的內存操作數的偏移值如果越過了65536(比如,MOV使用偏移值65536)或者0(比如,當SP=1時使用PUSH)將導致偏移值回繞到對65536取模后的值。80386在這種情況下將產生異常-13,如果使用了數據寄存器(比如,CS, DS, ES, FS或GS),-12,如果使用了堆棧寄存器(比如,SS)。
8.順序執行越過了偏移值65536。
對于8086,順序執行的指令越過了偏移值65536,處理器將取同一個段內的0地址處的下一條指令。這種情況下,80386將產生異常13。
9.某些指令禁止使用LOCK。
LOCK前綴以及相應的輸出信號應該只是用來阻止總線控制器在數據移動過程中被中斷。80386在使用XCHG指令和存儲器交互時總是聲明LOCK信號(即使沒有使用LOCK前綴)。LOCK應該只是用在更新存儲器的下列指令之前:BTS, BTR, BTC, XCHG, ADD, ADC, SUB, SBB, INC, DEC, AND, OR, XOR, NOT和NEG。在其他任何指令之前使用LOCK將導致未定義操作碼異常(中斷6)。
10.單步執行外部中斷處理函數。
80386單步異常的優先級不同于8086/8088。這個改變使得在程序在單步執行時阻止外部中斷進入后被單步執行。80386單步異常的優先級高于任何外部中斷。由INT指令或異常產生的中斷進入處理函數后,80386仍將單步執行。
11.IDIV指令80H或8000H商異常。
80386的IDIV指令的商可以是最大的負數。8086/8088產生異常0。
12.堆棧中的標志位。
由PUSHF,中斷,異常存儲的標志位在位12-15上與8086不同。在8086上,它們被作為一個整體,而在80386上,位15總是0,位14-12反映的是最后裝入它們的值。
13.NMI中斷和NMI處理函數。
在80386識別出NMI中斷后,NMI中斷保持屏蔽,直到執行了IRET指令。
14.協處理器錯誤指向中斷16。
任何帶有協處理器的80386系統必須使用中斷向量16來指向協處理器錯誤異常。如果8086/8088使用另一個向量,那么這兩個向量都要指向協處理器錯誤異常處理函數。
15.數字異常處理函數應該允許前綴。
在80386上,為協處理器異常保存的CS:IP指向ESC指令之前的任何前綴。在8086/8088上,保存的CS:IP指向ESC指令。
16.協處理器不使用中斷控制器。
協處理器錯誤信號在80386上不會進入中斷控制器(8087 INT信號這樣做)。如果在協處理器錯誤處理函數中有些指令是用來處理中斷控制器的,就需要刪除它們。
17.6個新的中斷向量。
80386增加了6個異常,它們只有在8086程序有隱含錯誤的時候才發生。建議按照非法操作來增加這些異常的處理函數。這些增加的代碼不會明顯的影響現有的8086軟件,因為這些中斷正常情況下不會發生。這些中斷標識符應該還沒有被8086軟件使用,因為它們被Intel放在了保留區域。表14-2描述了這6個新異常。
18.1M地址回繞。
實地址模式下,80386在1M地址外不會回繞。在8086家族中,可能聲明的地址超過1M大小。例如,選擇符是0FFFFH,偏移值是0FFFFH,有效地址將是10FFFFH(1M + 65519)。8086,最長20位地址,截斷高位。然而80386可以有32位長地址,因此不會截斷這樣的地址。
Table 14-1. 80386 Real-Address Mode Exceptions
```
Description Interrupt Function that Can
Return Address
Number Generate the Exception
Points to Faulting
Instruction
Divide error 0 DIV, IDIV
YES
Debug exceptions 1 All
Some debug exceptions point to the faulting instruction, others to the
next instruction. The exception handler can determine which has occurred by
examining DR6.
Breakpoint 3 INT
NO
Overflow 4 INTO
NO
Bounds check 5 BOUND
YES
Invalid opcode 6 Any undefined opcode or LOCK
YES
used with wrong instruction
Coprocessor not available 7 ESC or WAIT
YES
Interrupt table limit too small 8 INT vector is not within IDTR
YES
limit
Reserved 9-12
Stack fault 12 Memory operand crosses offset
YES
0 or 0FFFFH
Pseudo-protection exception 13 Memory operand crosses offset
YES
0FFFFH or attempt to execute
past offset 0FFFFH or
instruction longer than 15
bytes
Reserved 14,15
Coprocessor error 16 ESC or WAIT
YES
Coprocessor errors are reported on the first ESC or WAIT instruction
after the ESC instruction that caused the error.
Two-byte SW interrupt 0-255 INT n
NO
```
Table 14-2. New 80386 Exceptions
| Interrupt | Function |
| --- | --- |
| Identifier | |
| 5 | BOUND指令以一個超出上限的寄存器值被執行。 |
| 6 | 未定義的操作碼或LOCK應用與錯誤的指令。 |
| 7 | 執行ESC指令時,MSW中EM被置位。執行WAIT指令時TS被置位。 |
| 8 | 異常或中斷向量超出了IDTR中定義的上限值;只有在用LIDT指令修改上限值才有可能發生這個錯誤,因為默認的3FFH對于256個中斷ID足夠了。 |
| 12 | 操作數越過了堆棧段邊界,比如,用偏移值0FFFFH執行MOV或者SP=1時,執行壓棧指令PUSH, CALL或INT。 |
| 13 | 操作數越過了段邊界,不包括堆棧段;或者順序指令執行試圖跨越偏移值0FFFFH;或者指令長度超過了15字節(包括前綴)。 |
- 第一章 80386介紹
- 1.1 該手冊的組織結構
- 1.2 其他文獻
- 第二章 編程基本模型
- 2.1 存儲器組織和段
- 2.2 數據類型
- 2.3 寄存器
- 2.4 指令格式
- 2.5 操作數選擇
- 2.6 中斷和異常
- 第4章 系統寄存器
- 4.1 系統寄存器 (System Registers)
- 4.2 系統指令 (System Instructions)
- 第五章 內存管理
- 5.1 分段地址轉換(Segment Translation)
- 5.2 分頁地址轉換(Page Translation)
- 5.3 混合分段和分頁地址轉換(Combining Segment and Page Translation)
- 第六章 內存管理
- 6.1 為什么要保護(Why Protection?)
- 6.2 80386保護機制概述(Overview of 80386 Protection Mechnaisms)
- 6.3 段級保護(Segment-Level Protection)
- 6.4 頁級保護(Page-Level Protection)
- 6.5 混合分頁和分段保護(Combining Page and Segment Protection)
- 第7章 多任務(Multitasking)
- 8.1 I/O 尋址(I/O Addressing)
- 7.1 任務狀態段(Task State Segment)
- 7.3 任務寄存器(Task Register)
- 7.4 任務門描述符(Task Gate Descriptor)
- 7.5 任務切換(Task Switching)
- 7.6 任務鏈(Task Linking)
- 7.7 任務尋址空間(Task Address Space)
- 第8章 輸入 輸出
- 8.2 I/O 指令(I/O Instructions)
- 8.3 保護和I/O(Protection and I/O)
- 第9章 異常和中斷(Exceptions and Interrupts)
- 9.1 識別中斷(Identifying Interrupts)
- 9.2 允許和禁止中斷(Enabling and Disabling Interrupts)
- 9.3 同時發生的中斷和異常的優先級(Priority Among Simultaneous Interrupts and Exceptions)
- 9.4 中斷描述符表(Interrupt Descriptor Table)
- 9.5 IDT 描述符(IDT Descriptors)
- 9.6 中斷任務和中斷子程序(Interrupt Tasks and Interrupt Procedures)
- 9.7 出錯碼(Error Code)
- 9.8 異常條件(Exception Conditions)
- 9.9 異常總結(Exception Summary)
- 9.10 出錯碼總結(Error Code Summary)
- 第10章 初始化(Initialization)
- 10.1 復位后處理器狀態(Processor State After Reset)
- 10.2 實模式初始化(Software Initialization for Real-Address Mode)
- 10.3 切換到保護模式(Switching to Protected Mode)
- 10.4 保護模式初始化(Software Initialization for Protected Mode)
- 10.5 初始化示例
- 10.6 TLB測試
- 第十四章 80386實地址模式
- 14.1 物理地址構成
- 14.2 寄存器和指令
- 14.3 中斷和異常處理
- 14.4 進入和離開實地址模式
- 14.6 實地址模式異常
- 14.7 與8086的不同
- 14.8 與80286實地址模式的不同