§3.3.0 8086指令系統(tǒng)
本節(jié)概述
指令是計算機所能識別和執(zhí)行的指示和命令,指令在計算機上執(zhí)行時,控制器根據(jù)指令的要求,控制計算機的各部件協(xié)調(diào)工作。
目標程序不能被操作系統(tǒng)裝入和執(zhí)行,為了讓操作系統(tǒng)裝入和執(zhí)行,必須把目標程序連接為操作系統(tǒng)下的可執(zhí)行文件,連接過程一般使用連接程序Link.EXE來完成。
教學目標
熟練掌握8086指令系統(tǒng)中的各種數(shù)據(jù)操作指令,并能編寫自己的程序。
學習內(nèi)容
概述
數(shù)據(jù)傳送指令
算術(shù)運算指令
邏輯運算、移位、循環(huán)指令
控制轉(zhuǎn)移指令
串操作指令
中斷指令
處理控制指令
重點難點
1、指令的運用
2、程序的編寫
關鍵字
指令
參考資料
1、《微型計算機技術(shù)及應用》,戴梅萼等編著,第二版,清華大學出版社
2、《微型計算機原理》,季維法等編著,第一版,電子科技大學出版社
3、《微型計算機原理—常見題型解析及模擬題》,武自芳主編,西北工業(yè)大學出版社
4、《80X86/80X87匯編語言程序設計》,洪志全等編著,電子科技大學出版社
§3.3.1 概述
指令是計算機所能識別和執(zhí)行的指示和命令,指令在計算機上執(zhí)行時,控制器根據(jù)指令的要求,控制計算機的各部件協(xié)調(diào)工作。CPU能夠直接執(zhí)行的指令,也是用二進制編碼表示的,稱為機器指令,這種語言稱為機器語言。機器語言不便于編程,在編程時,一般用助記符來代表機器指令,
用助記符編寫的程序,稱為"匯編語言源程序",匯編語言源程序(文件擴展名ASM)需要翻譯為機器指令表示的目標程序(文件擴展名OBJ),這一翻譯過程稱為"匯編",一般使用稱為"匯編程序"的程序來進行翻譯。典型的匯編程序如MicrosoftMASM 5.0。
目標程序不能被操作系統(tǒng)裝入和執(zhí)行,為了讓操作系統(tǒng)裝入和執(zhí)行,必須把目標程序連接為操作系統(tǒng)下的可執(zhí)行文件,如DOS及Windows下的可執(zhí)行文件擴展名為EXE或COM。連接過程一般使用連接程序Link.EXE來完成。
匯編語言指令與機器指令間有一一對應關系,可以充分發(fā)揮CPU的性能,如圖3-7。
另外,使用高級語言編寫的源程序,必須通過"編譯"、"連接"形成可執(zhí)行文件,如圖3-8。

能夠直接執(zhí)行的機器指令,用二進制編碼表示。在Intel 系列CISC(復雜指令集計算機)CPU中,機器指令的長度為1~6字節(jié)。
OP:操作碼字段,6位,規(guī)定該指令的操作性質(zhì),如圖3-9。

D: 方向位。D=0, REG為源操作數(shù); D=1,REG為目的操作數(shù)。
W: 操作數(shù)大小. W=0, 操作數(shù)為字節(jié); W=1, 操作數(shù)為字。
REG: 寄存器編碼如下表:

MOD: 方式字段
MOD=11, 寄存器方式, 兩個操作數(shù)均在寄存器中,第一個寄存器由REG字段給出, 第二寄存器由R/M字段給出,R/M的編碼與REG同.
MOD=00、01、10:存儲器方式,有一個操作數(shù)在存儲器中,存儲器的有效地址由R/M字段給出:(D8=8位常數(shù),D16=16位常數(shù))如下表所示。

§3.3.2 數(shù)據(jù)傳送指令
傳送指令執(zhí)行寄存器、存儲器、I/O接口電路、堆棧、地址的傳送。有效的傳送路徑及方向如圖3-10。

1、 通用型傳送指令
(1) MOV
一般格式: "MOV dst,src"
dst=目標(destination),src=源(source)
傳送(move)的實質(zhì)是復制(copy),即傳送后,src中的值不變,。
注意:① 上圖中未標明的路徑均是非法的。
?、?不能給CS或IP賦值。
?、?常數(shù)不能直接賦給段寄存器。
(2) 堆棧操作
堆棧(STACK)是一段連續(xù)的內(nèi)存,用于暫存數(shù)據(jù),例如,可以把寄存器中的值暫存在堆棧中,需要時再取回到寄存器;在子程序和中斷處理程序中,通常需要把寄存器中的值暫存在堆棧中。在子程序調(diào)用和中斷發(fā)生時,返回的斷點地址也保存在堆棧中。 堆棧段的基地址保存在SS寄存器中,堆棧的大小等于SP的初值。堆棧操作過程中,SP指向數(shù)據(jù)所在單元(稱為"棧頂")。
堆棧操作有兩條指令,PUSH和POP。
PUSH:把寄存器或存儲器中的16位數(shù)值存入堆棧,。
把數(shù)據(jù)存入堆棧稱為"推入"或"入棧"。向堆棧中存入數(shù)據(jù) 時,SP的值減少,稱堆棧具有"下推式"的特點。
POP:把堆棧中SP處的16位數(shù)取至寄存器或內(nèi)存中。
把數(shù)據(jù)從堆棧中取出稱為"彈出"或"出棧"。
堆棧操作指令PUSH/POP只能進行16位數(shù)(字)操作,且遵從"先進后出"原則,操作過程如圖3-11所示。

使用堆棧還應注意"溢出"問題。
(3) 交換指令XCHG
把兩個操作數(shù)的值相交換(Exchange)。
(4) 翻譯指令XLAT
格式:XLAT 原始表
或:XLAT ;形式上無操作數(shù)
功能:查找一個字節(jié)表格中某一項的值。表格的名字(表示表格的起始地址)放在BX寄存器中,所查找項相對于表格起始地
址的偏移量放在AL中;該指令執(zhí)行后,AL等于所查找項的值。
注意,即使使用"XLAT tab"格式,也必須把tab的偏移量放在BX中。
2、 輸入輸出型傳送指令
CPU與外部設備之間必須通過"I/O接口電路"連接。8086的I/O接口電路,其主要作用是完成CPU與外部設備間的信息傳送。CPU把信息直接送給外部設備對應的I/O接口電路,由I/O接口電路負責把信息送給外部設備?;蛘撸獠吭O備把信息送入對應的I/O接口電路,CPU從I/O接口電路中讀取信息。
從編程的角度看,I/O接口電路由一些"端口"(PORT)構(gòu)成,CPU把信息直接送給外部設備對應的端口,由端口負責把信息送給外部設備?;蛘?,外部設備把信息送入對應的端口,CPU從端口中讀取信息。
8086CPU采用"端口尋址方式",即端口地址與存儲器地址單獨編號,使用專用的輸入輸出指令,在端口與AL或AX寄存器之間傳送信息。端口地址范圍是0000~FFFFH,每個端口可以存放8位二進制數(shù),稱為"8位端口"。
輸入輸出指令有兩個:IN(輸入)、OUT(輸出)。
IN指令:把端口的值輸入到AL或AX寄存器中。
OUT指令:AL或AX寄存器中的值輸出到端口。
IN/OUT指令有兩種用法:
用法一:端口地址以常數(shù)給出,適用于端口地址00~FFH。
用法二:端口地址放在DX寄存器中,適用于端口地址0000~FFFFH。
3、 地址傳送型指令
這類指令用于處理存儲器地址。如果一個存儲單元的值是另一個存儲單元的地址,該存儲單元被稱為"指針"(Pointer)。
存儲單元P的地址是1000H,存儲單元X的地址是2000H,P中的值等于X的地址2000H,稱為P指向X,或者說P是X的指針如圖3-12所示。指針P僅包含X的地址偏移量(2字節(jié)),是一個"近指針"(Near型指針)。

指針FP包含Y的段地址和偏移量(4字節(jié)),是一個"遠指針"(Far型指針)。其中偏移量放在前2字節(jié),段地址放在后2字節(jié)如圖3-13所示。
(1)LEA指令(裝入有效地址,Load Effective Addres)
LEA把內(nèi)存數(shù)據(jù)的有效地址(地址偏移量,16位)送到一個16位通用寄存器。
(2) LDS指令(裝入有效地址和DS寄存器)
LDS 把內(nèi)存數(shù)據(jù)的段地址送DS,偏移量送另一個16位通用寄存器。
(3)LES指令(裝入有效地址和ES寄存器)
LES 把內(nèi)存數(shù)據(jù)的段地址送ES, 偏移量送另一個16位通用寄存器。
4、 標志傳送型指令
標志傳送指令用于讀出標志寄存器(FLAG 或稱PSW)的內(nèi)容,或設置標志寄存器新的值,如圖3-14所示。

(1)LAHF (Load AH with Flag) 將標志寄存器的值裝入AH(讀出標志寄存器的值)。
(2)SAHF (Save AH into Flag) 將AH的值裝入標志寄存器(設置新的標志)。
(3)PUSHF,POPF PUSHF:
?、?SP減2
② 將FLAG的值存入堆棧中SP處,F(xiàn)LAG中的值保 持不變
POPF: ① 從堆棧中SP處取出一字送到FLAG
② SP加2
§3.3.3 算術(shù)運算指令
8086提供了加、減、乘、除四種基本算術(shù)運算,這些運算都可對字節(jié)或字進行運算,既可以對無符號數(shù)運算,也可對有符號數(shù)運算。無符號數(shù)和有符號數(shù)的加、減法運算使用相同的指令。乘、除運算中,無符號數(shù)和有符號數(shù)運算使用不同的指令。
1、 加法
(1) 加法的一般格式
ADD dst,src
功能:dst ←dst+src,源操作數(shù)與目的操作數(shù)相加,和放在目的操作數(shù)中。
(2) 帶進位的加法
ADC dst,src
功能:dst←dst+src+CF,源操作數(shù)與目的操作數(shù)相加,并考慮上一次加法的進位,和放在目的操作數(shù)中。
(3) 加1指令 INC dst 功能:dst ←dst+1
2、 減法
(1) 減法的一般格式 SUB dst,src 功能:dst ←dst-src
(2) 帶進位的減法 SBB dst,src
功能:dst←dst-src-CF,考慮上一次減法的借位。(上一次減法 的借位在CF中)
(3) 減1指令 DEC dst 功能:dst←dst - 1
(4) 求補指令 NEG dst 功能:dst ←0-dst
(5) 比較指令
CMP dst,src
功能:比較dst和src的大小,比較的結(jié)果放在標志位中。
該指令采用"dst-src"的算法實現(xiàn)比較,但相減后的差不送給dst?! l件轉(zhuǎn)移指令(如JG,大于時轉(zhuǎn)移;JNZ,當ZF=0時轉(zhuǎn)移
可以直接利用比較指令的比較結(jié)果。(條件轉(zhuǎn)移指令后述)

3、 乘法
無符號數(shù)的乘法(MULtiplication)用MUL指令, 有符號數(shù)的乘法用IMUL指令(有符號數(shù)又稱整數(shù)INTEGER)。 8086CPU可執(zhí)行兩個8位數(shù)相乘,或兩個16位數(shù)相乘,如圖3-15所示。

指令格式為:
MUL 操作數(shù)
IMUL 操作數(shù)
指令形式上只給出一個操作數(shù)(被乘數(shù)),但乘數(shù)和積是固定存放的。
如:無符號數(shù)的乘法
MUL BL ;AL × BL → AX
MUL CX ;AX × CX → DX AX (DX為高16位)
有符號數(shù)的乘
IMUL BYTE PTR [DI] ; AL乘內(nèi)存中的一字節(jié)值 ,
; 該內(nèi)存的地址由DI的值指出。積存放在AX中。
IMUL WORD PTR [DI] ;AX乘內(nèi)存中的一個字, ;該字的地;址由DI的值指出。積存放在DX和AX中。
注意:(1) 乘法指令的形式操作數(shù)不能為立即數(shù);
(2) MUL∕IMUL指令執(zhí)行后,設置CF和OF標志,但AF,PF,SF,ZF的值不確定,這四個標志無意義。
MUL指令:積的高一半為零,則CF=OF=0,否則,CF=OF=1。
IMUL指令:積的高一半是低一半的符號擴展,則CF=OF=0, 否則,CF=OF=1。
4、 除法
無符號數(shù)的除法(DIVision)用DIV指令,
有符號數(shù)的除法用IDIV指令 8086CPU可執(zhí)行16位/8位,或32位/16位,如圖3-16所示。

指令格式為:
DIV 操作數(shù)
IDIV 操作數(shù)
指令形式上只給出一個操作數(shù)(除數(shù)),但被除數(shù)、商和余數(shù)是固定存放的。
注意:
(1) DIV∕IDIV指令執(zhí)行后,所有狀態(tài)標志(CF,OF,AF,PF,SF,ZF)的值不確定,都無意義。
(2) DIV∕IDIV指令執(zhí)行后,如果商超出了范圍(除數(shù)很小,極限為0),即除法溢出(或稱商溢出),不使溢出標志置1。此時,CPU產(chǎn)生"0號中斷"(除數(shù)為零中斷)。
(3) 有符號數(shù)除法,可能產(chǎn)生兩種正確結(jié)果:如
(-30)/(+8)= -4 余 +2 (余數(shù)的符號與被除數(shù)不同)
(-30)/(+8)= -3 余 -6 (余數(shù)的符號與被除數(shù)相同)
IDIV指令取第二種結(jié)果。
數(shù)的擴展
(1)概念
數(shù)的擴展是指增加數(shù)的位數(shù)。如,把8位數(shù)擴展為16位數(shù),或把16位數(shù)擴展為32位數(shù),擴展后的數(shù)在數(shù)值上與原數(shù)相等。
(2)必要性
在乘法前,如果參與運算的乘數(shù)和被乘數(shù)不滿足"8位×8位"或不滿足"16位×16位",則需將其中一個數(shù)擴展。如:參與乘法的兩個數(shù)為"8位×16位",應將其中的"8位"數(shù)擴展為"16位"數(shù),變成"16位×16位"運算。
在除法前,如果參與運算的除數(shù)和被除數(shù)不滿足"16位/8位"或不滿足"32位/16位",則需將被除數(shù)擴展。
如果 原除法為"8位/8位",應將被除數(shù)擴展為16位,變成"16位/8位"運算。
如果 原除法為"16位/16位",應將被除數(shù)擴展為32位,變成"32位/16位"運算。
(3)擴展方法
無符號數(shù)的擴展:
8位→16位,只需把高8位清零。如把AH清零,使AL(8位)擴展為AX(16位)。
16位→32位,只需把高16位清零。如把DX清零,使AX(16位)擴展為DXAX(32位)。
有符號數(shù)的擴展:
使用擴展指令。
CBW指令(Convert Byte to Word):把AL(Byte,8位)擴展為AX(Word,16位)。
CWD指令(Convert Word to Double Word):把AX(Word,16位)擴展為DXAX(Double Word,32位)。
有符號數(shù)的擴展采用"符號擴展"方法,如: 0111 1111B (符號位為0)→0000 0000 0111 1111B (擴展部分全為0) 1000 1111B (符號位為1)→1111 1111 1000 1111B (擴展部分全為1)
5、 十進制數(shù)的運算
(1)BCD碼的概念
在計算機中,十進制數(shù)用二進制編碼表示,稱為BCD碼(Binary Coded Decimal),又稱"二--十進制碼"。十進制有0~9 十個數(shù)碼,可用四位二進制碼來表示,如:

有兩種BCD碼:組合BCD碼和非組合BCD碼.
組合的BCD碼:用一字節(jié)(8位)表示兩位BCD碼。因此,一字節(jié)能表示的組合BCD碼范圍是0~99。組合的BCD碼又稱"壓縮的BCD碼"(packed BCD format)或"組合十進制數(shù)"。
如:一字節(jié)0101 0110B (56H)表示組合BCD碼56。
非組合的BCD碼:用一字節(jié)(8位)的低4位表示一位BCD碼,高4位為0。因此,一字節(jié)能表示的非組合BCD碼范圍是0~9。非組合的BCD碼又稱"非壓縮的BCD碼"(unpacked BCD format)或"分離十進制數(shù)"、"非壓縮十進制數(shù)"。
如:一字節(jié)0000 0111B (07H)表示非組合BCD碼7。 非組合的BCD碼 類似于 數(shù)字0~9的ASCII碼。非組合的BCD碼高4位為0000B,ASCII碼的高4位為0011B。
如: 數(shù)字7
非組合的BCD碼=00000111B
ASCII=00110111B
數(shù)字7 BCD碼運算的優(yōu)點:當數(shù)據(jù)含有小數(shù)時,用BCD碼運算不會引入截斷誤差,而用二進制運算會引入截斷誤差。如12.34的二進制表達: 1100.0101 0111 0000 101…,用有限位數(shù)表達,必然引入截斷誤差。
由于BCD碼運算不會引入截斷誤差,常用于會計軟件。另外,在工業(yè)控制中,BCD碼常用于表示撥號開關位置代表的數(shù)值。
(2) BCD碼的運算
BCD碼的運算方式:ADD,SUB,MUL,DIV等指令是用于運算二進制數(shù)的,不能直接用于運算BCD碼。要對BCD碼進行運算,可采用兩種方式:
①設置一套專用于BCD碼的指令
?、诶枚M制運算指令和十進制調(diào)整指令

8086CPU采用第二種方式,即利用二進制指令和十進制調(diào)整指令。
十進制調(diào)整指令:
DAA:Decimal Adjust for Addition,加法的十進制調(diào)整指令。
DAS:Decimal Adjust for Subtraction,減法的十進制調(diào)整指令。
AAA:ASCII Adjust for Addition,加法的ASCII調(diào)整指令。
AAS:ASCII Adjust for Subtraction,減法的ASCII調(diào)整指令。
AAM:ASCII Adjust for Multiply,乘法的ASCII調(diào)整指令。
AAD:ASCII Adjust for Division,除法的ASCII調(diào)整指令。
這里,使用術(shù)語"十進制"(Decimal)表示 組合的BCD碼,
使用術(shù)語"ASCII"表示 非組合的BCD碼。
使用二進制運算指令對BCD碼進行運算,必須同時使用十進制調(diào)整指令進行調(diào)整,因為:
?、?4位二進制表示的范圍是0~9,A,B,C,D,E,F, BCD碼只允許0~9。
?、?4位二進制運算逢十六進一,而BCD碼逢十進一。
(3)BCD碼的加法
對BCD碼做加法運算,每次只能運算一字節(jié)(2位組合BCD碼或1位非組合BCD碼),首先,使用二進制運算指令ADD/ADC,并將結(jié)果存于AL中,然后,對AL的值進行調(diào)整(DAA或AAA)。
DAA指令把AL中的值調(diào)整為組合BCD碼,并存于AL中。
AAA指令把AL中的值調(diào)整為非組合BCD碼,并存于AX中(AH高位)。
結(jié)論:用二進制指令運算BCD碼時,必須同時使用調(diào)整指令,組合BCD碼加法和非組合BCD碼加法的調(diào)整方法是 "加6調(diào)整"。即:當4位二進制碼超過9時,或有輔助進位(AF=1)時,調(diào)整指令DAA/AAA指令把二進制運算指令ADD/ADC的結(jié)果加6。
(4)BCD碼的減法
對BCD碼做減法運算,每次只能運算一字節(jié)(2位組合BCD碼或1位非組合BCD碼),首先,使用二進制運算指令SUB/SBB,并將結(jié)果存于AL中,然后,對AL的值進行調(diào)整(DAS或AAS)。
DAS指令把AL中的值調(diào)整為組合BCD碼,并存于AL中。
AAS指令把AL中的值調(diào)整為非組合BCD碼,并存于AX中(AH高位)。
結(jié)論:用二進制指令運算BCD碼時,必須同時使用調(diào)整指令,組合BCD碼減法和非組合BCD碼減法的調(diào)整方法是:"減6調(diào)整"。即:當4位二進制碼超過9時,或有輔助進位(AF=1)時,調(diào)整指令DAS/AAS指令把二進制運算指令SUB/SBB的結(jié)果減6。
(5)BCD碼的乘法和除法
(一)乘法
只能對非組合的BCD碼做乘法運算,且每次只能運算一字節(jié)(1位非組合BCD碼),首先,使用二進制運算指令MUL按二進制運算,然后,使用AAM指令把結(jié)果調(diào)整為非組合BCD碼。
(二)除法
只能進行2位非組合的BCD碼(被除數(shù),放在AX中)除以1位非組合的BCD碼運算。首先,使用調(diào)整指令AAD把被除數(shù)調(diào)整為二進制。然后,使用二進制運算指令DIV按二進制相除,在AL中獲得商的二進制形式,在AH中獲得余數(shù)的二進制形式。最后,用AAM指令把商調(diào)整為非組合BCD碼,存于AX中。
