少妇被又大又粗又爽毛片久久黑人,国产无遮挡又黄又爽免费视频,18禁男女爽爽爽午夜网站免费,成全动漫影视大全在线观看国语

3.3 80486微處理器的基本指令系統

3.3 80486微處理器的基本指令系統

80486微處理器的指令系統包含133條基本指令,按功能可分為如下六大類指令:

  • 數據傳送類指令;
  • 算術運算類指令;
  • 邏輯運算與移位類指令;
  • 串操作類指令;
  • 程序控制類指令;
  • 處理器控制類指令。

由于80486微處理器指令系統的功能很強,同時也比較復雜,學習和掌握好這些指令會有一定的難度,因此,這部分內容的學習應主要掌握指令的格式、功能、操作及對標志位的影響。

3.3.1 數據傳送類指令

數據傳送類指令的功能是完成寄存器與寄存器之間、寄存器與存儲器之間及寄存器與I/O端口之間的字節數據或字數據的傳送。這類指令的共同特點是不影響標志寄存器的內容。數據傳送類指令又可分為4種類型,見表3.1。

表3.1 數據傳送類指令

注:d表示目標操作數,s表示源操作數。

1.通用數據傳送指令

通用數據傳送指令包括最基本的傳送指令MOV、堆棧操作指令PUSH與POP、數據交換指令XCHG和字節翻譯指令XLAT。

(1)傳送指令

MOV(move):最基本的傳送指令。

格式:MOV d,s

操作:(d)←(s),將由s指定的源操作數送目標操作數d。

注:( )表示有關的內容。

數據傳送方向如圖3.8所示。

圖3.8 數據傳送方向示意圖

在這類傳送指令中,由s與d分別指定源操作數與目標操作數。源操作數可以是8位或16位寄存器操作數,也可以是存儲器中的某個字節/字數據,或者是8位/16位立即數。目標操作數不允許為立即數,其他同源操作數一樣,且兩者不能同時為存儲器操作數。例如:

MOV AL,30H ; 寄存器←立即數(AL←30H),字節傳送
MOV AX,1122H ; 寄存器←立即數(AX←1122H),字傳送
MOV BH,CH ; 寄存器←寄存器,字節傳送
MOV SI,BX ; 寄存器←寄存器,字傳送
MOV CL,ADDR ; CL←內存單元ADDR中的字節內容
MOV AX,[DI] ; AH←(DI+1),AL←(DI),[DI]指定內存單元的字地址
MOV [SI] ,DX ; [SI+1]←DH,[SI]←DL,[SI]指定內存單元的字地址
MOV [2000H] ,DS ; [2001H]←DS15~8,[2000H]←DS7~0,[2000H]指定內存單元的字地址
MOV SS,AX ; 段寄存器←寄存器,字傳送

還應注意,CS和IP這兩個寄存器不能作為目標操作數,也就是說,這兩個寄存器的值不能用MOV指令來修改。另外,當操作數采用BX、SI、DI進行間接尋址時,默認的段寄存器為DS,訪問數據段。當采用BP進行間接尋址時,默認的段寄存器為SS,訪問堆棧段。

例如:MOV AL,00H ; AL←00H

   MOV BL,01H ; BL←01H

   MOV CL,02H ; CL←02H

   MOV BL,AL ; BL←00H

   MOV CL,BL ; CL←00H

這是一段全部由字節傳送類指令組成的程序。執行每條指令后的結果參見程序中的注釋。程序執行后,AL=00H,BL=00H,CL=00H。該程序段的功能是將AL、BL和CL寄存器清0。

例如:MOV AX,5060H

   MOV [2100H],AX

執行這兩條指令組成的程序段后,相應存儲單元中的內容是什么?

第一條指令的執行結果是AX=5060H,第二條指令將AX中的內容傳送到內存中偏移地址為2100H的字單元中,所以[2101H]=50H,[2100H]=60H。

(2)堆棧操作指令

80486微處理器對堆棧的操作遵循“先進后出”的原則,即最先存入堆棧的數據最后才能取出,最后存入的數據可最先取出。80486微處理器的堆棧采取“向下生長”的編址方式,即越靠近堆棧底部,其地址越大;越靠近堆棧頂部,其地址越小。在堆棧操作的過程中,堆棧指針SP的內容始終指向堆棧棧頂的地址(開始時,它指在堆棧的底部,地址最高)。在80486微處理器指令系統中,有兩條專用于堆棧操作的指令PUSH和POP。除此之外,子程序調用及返回指令、中斷調用及返回指令的操作過程,都會對堆棧有影響。下面講述80486微處理器的壓棧和出棧指令。

① 壓棧指令PUSH(push word onto the stack):將數據壓入堆棧。格式:PUSH s

操作:(SP-1),(SP-2)←(s)

    SP←SP-2

其中,s是源操作數,表示入棧的字操作數,除了不允許使用立即數外,寄存器、存儲器、段寄存器(CS除外)都可以作為源操作數。

具體操作過程:先將SP減1,將操作數的高位字節送入當前SP所指單元中,然后再將SP減1,將操作數的低位字節又送入當前SP所指單元中。也就是說,每執行一次PUSH操作,將源操作數s指定的一個字數據壓入堆棧中由SP指定的相鄰兩個單元保存起來,數據的高位字節壓入高地址單元,低位字節壓入低地址單元(即高位對應高地址,低位對應低地址),堆棧指針SP減2,SP總是指向最后壓入數據的單元地址,即棧頂。

例如:PUSH AX

指令執行前SS=4000H,SP=2500H,AX=3125H,指令執行過程及堆棧操作如圖3.9所示。

圖3.9 PUSH AX指令執行過程及堆棧操作

指令執行時,首先SP減1,則SP=24FFH,將AX的高位字節AH=31H送入SP和SS所指定的424FFH單元中,然后將SP再減1,此時SP=24FEH,將AX的低位字節AL=25H送入SP和SS所指定的424FEH單元中。執行完PUSH指令,SP=24FEH,是在原來SP=2500H的基礎上減2所得的結果。

② 出棧指令POP(pop word from the stack):將數據彈出堆棧。

格式:POP d

操作:(d)←(SP+1),(SP)

   SP←SP+2

其中,d為目標操作數,表示由堆棧彈出的字操作數所在的目標地址,除了立即數和CS段寄存器外,寄存器、存儲器和段寄存器都可以作為目標操作數。

具體操作過程:先將當前SP所指的棧頂單元的內容彈出,并送入d指定的低位字節單元,SP內容加1指向下一個單元。然后再將當前SP所指棧頂單元中的內容彈出,并送入d指定的高位字節單元,SP的內容再加1。也就是說,每執行一次POP操作,由當前SP所指的棧頂字單元中彈出一個字數據,送入d指定的目標操作數,高位對應高地址,低位對應低地址,堆棧指針SP加2,SP總是指向下一個該彈出數據的單元地址,即棧頂。

例如:POP BX

指令執行前,SS=8000H,SP=2000H,堆棧區段偏移地址為2000H單元中的內容為0BH,2001H單元中的內容為0AH。指令執行過程及堆棧操作如圖3.10所示。

指令執行時,首先將SP=2000H所指棧頂地址單元中的內容0BH彈出,并送入BX的低位字節BL中,然后SP加1為2001H,再將當前SP所指棧頂地址單元中的內容0AH彈出,送入BX的高位字節BH中,最后再將SP加1,指向2002H單元,SP在原來2000H的基礎上增加2。指令執行后,BX=0A0BH,SP=2002H。

堆棧操作在計算機中常常被用來保護現場。如果在程序中要用到某些寄存器,但它們原來的內容在后面程序執行過程中還要用到,這時就可以使用PUSH指令,將這些寄存器的內容暫時保存在堆棧中,以后要用到這些內容時,再使用POP指令恢復。其程序形式如下:

圖3.10 POP BX指令執行過程及堆棧操作

PUSH AX ; 將AX的內容壓入堆棧保護
PUSH BX ; 將BX的內容壓入堆棧保護
… ; 在此程序段中可使用AX,BX
POP BX ; 恢復BX原先的內容
POP AX ; 恢復AX原先的內容

此時,要遵循堆棧操作“先進后出”的原則,應特別注意有關內容的入棧及出棧的順序,防止造成數據的交叉或混亂。

在實際使用時,還可利用堆棧操作將某些寄存器或存儲單元內容進行交換。

例如:MOV SP,3000H ; 設置堆棧指針,SP←3000H

   MOV AX,1234H ; 設置AX初始值,AX←1234H

   MOV BX,5678H ; 設置BX初始值,BX←5678H

   PUSH AX ; 將AX內容壓入堆棧

   PUSH BX ; 將BX內容壓入堆棧

   POP AX ; AX←5678H

   POP BX ; BX←1234H

其執行過程如圖3.11所示。

圖3.11 程序執行情況

① 執行PUSH AX指令后,SP1=SP-2=2FFEH,將AX的內容1234H壓入堆棧2FFFH和2FFEH單元中。

② 執行PUSH BX指令后,SP2=SP1-2=2FFCH,將BX的內容5678H壓入堆棧2FFDH和2FFCH單元中。

③ 執行POP AX指令后,將棧頂SP2指定的2FFCH和2FFDH單元中原先BX的兩個字節數據彈出,并送入目標操作數AX,SP3=SP2+2=2FFEH。

④ 執行POP BX指令后,將棧頂SP3所指定的2FFEH和2FFFH兩個單元中保存的原AX內容彈出,并送入目標操作數BX,SP4=SP3+2=3000H。程序執行后,SP=SP4=3000H,AX=5678H,BX=1234H。

討論:

① 堆棧指針SP的變化情況。由于每執行一條PUSH指令SP-2,而每執行一條POP指令SP+2,所以SP=3000H-2-2+2+2=3000H。

② AX、BX寄存器中的內容變化情況。當進行PUSH操作時,先壓入AX中的內容,后壓入BX中的內容。而當進行POP操作時,最先彈出的內容(原BX的內容)送入AX,最后彈出的內容(原AX的內容)送入BX。由于堆棧操作先進后出的原則,導致AX和BX中的內容發生了交換。

(3)XCHG(exchange):交換指令

格式:XCHG d,s

操作:(d)←→(s)

交換指令的功能:將s表示的源操作數的內容與d表示的目標操作數的內容相互交換,這兩個操作數都可以是字節或字類型。交換可以在寄存器與寄存器之間、寄存器與存儲單元之間進行,但不能在兩個存儲單元之間交換數據。段寄存器與指令指針IP也不能作為源操作數和目標操作數。

例如:XCHG AX,CX ; AX←→CX,將AX,CX中原先保存的內容相互交換

圖3.12 數碼顯示代碼表

(4)XLAT(table look-up translation):字節轉換指令

格式:XLAT

操作:AL←(BX+AL)

字節轉換指令XLAT用來將一種字節代碼轉換成另一種字節代碼。它將BX中的內容(代碼表格首地址)和AL中的內容(表格偏移量)相加作為有效地址,并讀出地址單元中的內容傳送到AL寄存器中。指令執行后,AL中的內容是所要轉換的代碼。

【例3.1】 將0~F的十六進制數轉換為七段數碼管的顯示代碼。

此代碼位于當前數據段中,DS=2000H,起始單元的偏移地址值為0300H。若將十六進制數B轉換成相應的七段碼,步驟如下。

① 建立數碼顯示代碼表,如圖3.12所示。將表首單元的偏移地址送入BX,BX=0300H。

② 將待轉換的十六進制數在表中的序號(又稱索引值)0BH送入AL中。

③ 執行XLAT指令:

MOV BX,0300H ; BX←0300H
MOV AL,0BH ; AL←0BH
XLAT ; AL←03H

執行上述指令后,將物理地址=DS×16+偏移地址=2000H×16+0300H+0BH=2030BH單元中的內容03H傳送給AL,從而完成代碼轉換過程,AL中的內容03H即為十六進制數B轉換成的七段顯示代碼(共陽極數碼管)。

2.目標地址傳送指令

目標地址傳送指令共有三條,可將操作數的段基址或偏移地址傳送到指定的寄存器中。

(1)LEA(load effective address):取有效地址指令

格式:LEA d,s

操作:(d)←EA

該指令可將源操作數s的有效地址EA傳送到指令指定的寄存器中。源操作數s只能是各種尋址方式的存儲器操作數,而寄存器、立即數和段寄存器都不能作為源操作數。目標操作數d可以是一個16位的通用寄存器。這條指令常用來使一個寄存器作為地址指針。

例如:LEA BX,[SI]

指令執行前,SI=2500H,則EA=2500H;

指令執行后,BX=2500H。

該指令的執行結果是將源操作數確定的存儲單元的有效地址2500H傳送到目標操作數確定的寄存器BX中(關注的是存儲單元的有效地址,而不是其中的內容)。要特別注意,指令LEA BX,[SI]與指令MOV BX,[SI]的區別。前者將SI中的內容2500H作為存儲器的有效地址送入BX中,后者則將SI寄存器間接尋址方式確定的相鄰兩個存儲單元中的內容送入BX中。若DS=5000H,該數據段中52500H字單元中的內容為1234H,這兩條指令的操作過程如圖3.13所示。

圖3.13 LEA和MOV指令的執行過程

(2)LDS(load data segment register):取指針送寄存器和DS指令

格式:LDS d,s

操作:(d)←(s)

    DS←(s+2)

指令中的源操作數s確定一個雙字類型的存儲器操作數的首地址,目標操作數d指定一個16位的寄存器操作數(不允許使用段寄存器)。

LDS指令的功能:從源操作數s所指定的存儲單元開始的連續4個存儲單元中,取出某變量的地址指針,將其前兩個字節(即偏移地址值)傳送到目標操作數d所指定的16位通用寄存器中,而將后兩個字節(即段基址值)傳送到DS段寄存器中。

例如:LDS BX,LOP [DI]

若DS=4000H,DI=0200H,LOP=0010H,則該雙字操作數存儲單元的物理地址為:

物理地址=DS×16+DI+LOP=40000H+0200H+0010H=40210H

若指令執行前,BX=30A0H,雙字操作數在數據段中的存放情況如圖3.14(a)所示,則指令執行后,BX=2050H,DS=8000H,如圖3.14(b)所示。

圖3.14 LDS BX,LOP [DI]的執行情況

(3)LES(load extra segment register):取指針送寄存器和ES指令

格式:LES d,s

操作:(d)←(s)

   ES←(s+2)

LES指令的操作與LDS指令基本類似,所不同的是以ES代替DS,即將源操作數所指定的地址指針中的后兩個字節(段基址)傳送到ES段寄存器中,而不是DS段寄存器中。

例如:LES DI,[BX]

若DS=5000H,BX=2000H,則該雙字操作數的物理地址為:

物理地址=DS×16+BX=50000H+2000H=52000H

若指令執行前,DI=1234H,ES=6400H,數據區段中(52000H)=FFH,(52001H)=20H,(52002H)=00H,(52003H)=81H,則指令執行后,DI=20FFH,ES=8100H。

3.標志位傳送指令

標志位傳送指令的操作涉及標志寄存器,利用這些指令,可以讀出標志寄存器的內容,也可對標志寄存器的標志位進行設置。標志位傳送指令共有4條,這些指令都是單字節指令,指令的操作數規定為隱含方式,在指令的書寫格式中不出現,是無操作數指令。

(1)LAHF(load status flags into AH register):標志位送AH指令

格式:LAHF

操作:AH←FR的低位字節,該指令的操作如圖3.15所示。

將標志寄存器FR的低8位狀態標志送入AH寄存器的相應位,即SF送D7位,ZF送D6位,AF送D4位,PF送D2位,CF送D0位。LAHF指令執行以后,AH的D5、D3、D1位沒有意義。

(2)SAHF(store AH into flag register):AH內容送標志寄存器指令

格式:SAHF

操作:FR的低位字節←AH

圖3.15 LAHF操作情況

SAHF指令的功能正好與LAHF相反,它是將AH寄存器中的D7、D6、D4、D2、D0位的狀態標志送入標志寄存器FR的相應位,而FR的其他位不受影響。

(3)PUSHF(push flags register onto stack):標志寄存器壓入堆棧指令格式:PUSHF

操作:SP←SP-1,(SP)←FR的高8位字節

   SP←SP-1,(SP)←FR的低8位字節

該指令的功能是將16位標志寄存器FR的內容壓入堆棧頂部進行保存,堆棧指針SP的值減2。指令執行后,FR的內容不變。其操作過程與PUSH指令類似。

(4)POPF(pop stack into flag register):堆棧內容彈出到標志寄存器指令

格式:POPF

操作:FR低8位←(SP),SP←SP+1

FR高8位←(SP),SP←SP+1

POPF指令的功能正好與PUSHF相反,它將當前棧頂中的一個字數據彈出來,送到標志寄存器FR中,同時堆棧指針SP的值加2,其操作過程與POP指令類似。

4.I/O數據傳送指令

80486微處理器指令系統中的I/O指令,只能在AL或AX寄存器與輸入/輸出端口之間進行數據傳送。輸入/輸出端口地址的尋址方式包括直接尋址和DX寄存器間接尋址兩種。

(1)IN(input data from port):輸入指令

格式:IN 累加器,端口地址

輸入指令允許把一個字節或一個字數據由輸入端口傳送到AL(字節)或AX(字)中。若端口地址采用直接尋址方式,則由8位立即數直接給出,可尋址0~255共256個端口。若端口地址采用DX寄存器間接尋址方式,可間接尋址64K(65536)個16位端口地址。根據不同的尋址方式,輸入指令如下:

    IN AL,PORT ; AL←(端口PORT)
    IN AX,POPT ; AX←(端口(PORT+1))(端口PORT)
    IN AL,DX ; AL←(端口DX)
    IN AX,DX ; AX←(端口DX+1)(端口DX)

指令中的PORT代表8位的端口地址號0~255(用十六進制數表示為00H~FFH)。

例如:IN AL,80H ; 直接尋址方式的字節型輸入指令

該指令將8位端口80H中的內容傳送到AL寄存器中,若端口80H中的內容為3FH,則指令執行后AL=3FH。

例如:MOV DX,2000H

   IN AX,DX ; 間接尋址方式的字類型輸入指令

該指令將由(DX+1)和(DX)確定的相鄰兩個端口地址2001H和2000H中輸入的一個字數據傳送到累加器AX中。存放時,AH=(2001H),AL=(2000H),即高位對應高地址,低位對應低地址。

(2)OUT(output data to port):輸出指令

格式:OUT 端口地址,累加器

輸出指令把預先存放在AL中的一個字節數據或AX中的一個字數據傳送到指令指定的輸出端口,端口地址的尋址方式同輸入指令。根據不同的尋址方式,輸出指令如下:

    OUT PORT,AL ; (端口PORT)←AL
    OUT PORT,AX ; (端口PORT+1)(端口PORT)←AX
    OUT DX,AL ; (端口DX)←AL
    OUT DX,AX ; (端口DX+1)(端口DX)←AX

例如:OUT 50H,AX ; 直接尋址方式的字類型輸出指令

該指令將預先存放在AX累加器中的一個字數據傳送到端口51H和50H。傳送時,高位對應高地址,低位對應低地址。若AX=0304H,則指令執行后,(51H)=03H,(50H)=04H。

例如:MOV AL,68H

   MOV DX,3000H

   OUT DX,AL ; 間接尋址方式的字節型輸出指令

該指令可將AL中的一個字節數據68H傳送到由寄存器DX確定的一個輸出端口3000H。指令執行后,端口(3000H)=68H。

由以上討論可知,輸入/輸出指令只能在累加器AL/AX與I/O端口之間傳送數據,而不能使用其他寄存器代替。當采用直接尋址方式的指令時,尋址端口地址范圍為0~FFH,一般適用于較小規模的微機系統。當需要尋址大于FFH的端口地址時,必須使用DX間接尋址。在輸入/輸出過程中,要搞清楚以下三方面的要求。

① 是輸入過程還是輸出過程(指數據傳送的方向)?

② 數據是字節類型還是字類型(指輸入/輸出數據的類型)?

③ 是直接尋址還是DX間接尋址(指指令的尋址方式)?

明確了上述三個方面的要求后,才能正確地完成CPU與I/O端口之間的數據傳送。

【例3.2】 由端口3000H輸入一個字節數據到CPU內部寄存器中。

    MOV DX,3000H
    IN AL,DX

若由同一端口輸入一個字數據,則可將寄存器AL改為AX。

【例3.3】 將數據3A3BH輸出到端口20H。

    MOV AX,3A3BH
    OUT 20H,AX

3.3.2 算術運算類指令

80486微處理器的算術運算類指令包括二進制數運算指令及十進制數運算指令兩種。指令系統中提供了加、減、乘、除4種基本算術操作,用于字節或字的運算、有符號數和無符號數的運算。如果是有符號數,則用補碼來表示。指令系統中還提供了各種校正操作指令,可以進行BCD碼或ASCII碼表示的十進制數的算術運算。在學習算術運算類指令的過程中,除掌握指令的格式、操作功能外,還要掌握指令對標志位的影響。80486微處理器算術運算指令見表3.2。

1.加法指令

加法指令共有三條。

(1)ADD(signed or unsigned ADD):不帶進位的加法指令

格式:ADD d,s

操作:(d)←(d)+(s)

其中,目標操作數d為被加數操作數和結果(即和)操作數,源操作數s為加數操作數。

表3.2 80486指令系統的算術運算類指令

注:s表示源操作數,↑表示運算結果影響標志位,d表示目標操作數,·表示運算結果不影響標志位x表示標志位為任意值,1表示將標志位置1,0表示將標志位清0

ADD指令的功能:將源操作數與目標操作數相加,結果存放在目標操作數中,并根據結果置標志位。ADD指令完成半加器的功能。

源操作數可以是8/16位的通用寄存器操作數、存儲器操作數或立即數。目標操作數除不允許為立即數外,其他同源操作數。

注意:兩個操作數不能同時為存儲器操作數,段寄存器不能作為源操作數和目標操作數。

例如:ADD AL,BL

假設指令執行前,AL=66H,BL=20H。

執行指令:

指令執行后,AL=86H,BL=20H。

標志位的情況:最高位無進位,CF=0;結果不為0,ZF=0;最高位為1,SF=1;D3向D4無進位,AF=0;CS⊕CP=0⊕1=1,OF=1,發生溢出;結果中含3個1,PF=0。

例如:ADD WORD PTR [BX+106BH],1234H

注意:WORD PTR指明存儲器操作數為字類型。

若 DS=2000H,BX=1200H,則字操作數存儲單元的物理地址為:

物理地址=20000H+1200H+106BH=2226BH

指令執行前,(2226BH)=44H,(2226CH)=33H。

執行指令:

指令執行后,(2226BH)=78H,(2226CH)=45H。

標志位的情況:最高位無進位,CF=0;結果不為0,ZF=0;最高位為0,SF=0;D3向D4無進位,AF=0;CS⊕CP=0⊕0=0,OF=0;結果中含7個1,PF=0。

(2)ADC(add with carry):帶進位的加法指令

格式:ADC d,s

操作:(d)←(d)+(s)+CF

ADC指令的操作和功能與ADD指令基本相同,唯一的不同是還要加上當前進位標志的值。ADC指令完成全加器的功能,主要用于兩個多字節(或多字)二進制數的加法運算。

【例3.4】 兩個無符號雙精度數(雙字數據)的加法。

目標操作數(被加數)存放在DX和AX寄存器中,其中DX存放高位字,AX存放低位字。源操作數(加數)存放在BX和CX寄存器中,其中BX存放高位字,CX存放低位字。

指令執行前,DX=0002H,AX=F365H,BX=0005H,CX=E024H。

應完成的操作:0002F365H+0005E024H。

雙字加法指令序列為:

    ADD AX,CX ; 低位字相加
    ADC DX,BX ; 高位字帶進位相加

執行第一條指令:

第一條指令執行后,AX=D389H,最高位有進位,CF=1;結果不為0,ZF=0;最高位為1,SF=1;D3向D4無進位,AF=0;CS⊕CP=1⊕1=0,OF=0;結果中含8個1,PF=1。

執行第二條指令:

第二條指令執行后,DX=0008H,最高位無進位,CF=0;結果不為0,ZF=0;最高位為0,SF=0;D3向D4無進位,AF=0;CS⊕CP=0⊕0=0,OF=0;結果中含奇數個1,PF=0。

執行指令序列后,結果存放在DX,AX中,DX=0008H,AX=D389H,結果正確。

(3)INC(increment by 1):加1指令

格式:INC d

操作:(d)←(d)+1

INC指令的功能:將目標操作數當作無符號數,將其內容加1后,再送回到目標操作數中。目標操作數可以是8/16位的通用寄存器或存儲器操作數,但不允許是立即數和段寄存器。INC指令的執行不影響CF標志位,通常用于在循環過程中修改指針和循環次數。

例如:INC CX

指令執行后,將CX寄存器中的內容加1后又送回到CX中。

2.減法指令

減法指令共有5條。

(1)SUB(subtract):不帶借位的減法指令

格式:SUB d,s

操作:(d)←(d)-(s)

其中,目標操作數d和源操作數s的尋址方式的規定同ADD指令。

SUB指令的功能:將目標操作數減去源操作數,結果(差)存入目標操作數中,并根據結果置標志位。與ADD指令一樣,SUB指令可以是字操作,也可以是字節操作。

例如:SUB AL,[BP+8]

若SS=5000H,BP=2000H,則源操作數存儲單元的物理地址為:

物理地址=SS×16+BP+8=50000H+2000H+8=52008H

指令執行前,AL=45H,(52008H)=17H。

執行指令:

指令執行后:AL=2EH,(52008H)=17H。標志位的情況:最高位無借位,CF=0;結果不為0,ZF=0;最高位為0,SF=0;D3向D4有進位,AF=1;CS⊕CP=0⊕0=0,OF=0;結果中含4個1,PF=1。

(2)SBB(subtraction with borrow):帶借位的減法指令

格式:SBB d,s

操作:(d)←(d)-(s)-CF

其中,CF為當前借位標志的值。該指令的操作和功能以及兩個操作數尋址方式的規定與SUB指令極為相似,唯一的不同就是SBB指令在執行減法運算時,還要減去CF的值。SBB指令執行時,用被減數(d)減去減數(s),還要減去低位字節相減時所產生的借位。在實際應用中,SBB指令主要用于兩個多字節或多字二進制數的相減過程。

【例3.5】 兩個無符號的雙精度數(雙字數據)的減法。

假設目標操作數(被減數)存放在DX和AX寄存器中,其中DX存放高位字,AX存放低位字。源操作數(減數)存放在CX和BX寄存器中,其中CX存放高位字,BX存放低位字。

指令執行前,DX=0012H,AX=7546H,CX=0010H,BX=9428H,應完成00127546H-00109428H的減法過程。

雙字減法指令序列為:

    SUB AX,BX ; 低位字相減
    SBB DX,CX ; 高位字連同借位CF相減

執行第一條指令:

第一條指令執行后,AX=E11EH。最高位有借位,CF=1;結果不為0,ZF=0;最高位為1,SF=1;D3向D4有借位,AF=1;CS⊕CP=1⊕0=1,OF=1,發生溢出;結果中含8個1,PF=1。

執行第二條指令:

第二條指令執行后,DX=0001H。最高位無借位,CF=0;結果不為0,ZF=0;最高位為0,SF=0;D3向D4無借位,AF=0;CS⊕CP=0⊕0=0,OF=0;結果中含一個1,PF=0。

該指令序列執行后,差存放在DX,AX中,DX=0001H,AX=E11EH。

(3)DEC(decrement by 1):減1指令

格式:DEC d

操作:(d)←(d)-1

DEC指令的功能以及操作數的規定與INC指令基本相同,所不同的只是將目標操作數的內容減1,結果回送到目標操作數中。與INC指令一樣,DEC指令通常用于在循環過程中修改指針和循環次數。

例如:DEC CX

指令執行后,將CX寄存器中原先的內容減1后又回送到CX中。

(4)NEG(two’s complement negate):求補指令

格式:NEG d

操作:NEG指令的功能:將目標操作數的內容按位求反后末位加1,再回送到目標操作數中。對一個操作數求補實際上也相當于用0減去該操作數,則NEG指令執行的也是減法(d)←0-(d)。其目標操作數的規定同INC、DEC指令。

例如:NEG DL

指令執行前,DL=80H。

指令執行:

指令執行后:DL=80H,CF=1,ZF=0,SF=1,AF=0,OF=1,PF=0。

(5)CMP(compare two operands):比較指令

格式:CMP d,s

操作:(d)-(s)

CMP指令的功能、操作數的規定以及影響標志位的情況類似于SUB指令。唯一的不同是CMP指令不保存相減以后的結果(差),即該指令執行后,兩個操作數原先的內容不會改變,只是根據相減操作的結果設置標志位。CMP指令通常用于在分支程序結構中比較兩個數的大小,在該指令之后經常安排一條條件轉移指令,根據比較的結果讓程序轉移到相應的分支去執行。

例如:CMP AL,CL

指令執行前,AL=68H,CL=9AH。

指令執行:

指令執行后,AL=68H,CL=9AH,最高位有借位,CF=1;結果不為0,ZF=0;最高位為1,SF=1;D3向D4有借位,AF=1;CS⊕CP=1⊕0=1,OF=1;結果中有5個1,PF=0。

作為無符號數比較時,被減數小于減數,不夠減,有借位,CF=1。作為有符號數時,結果已超出有符號數所能表示的范圍,因此,OF=1,有溢出。

3.乘法指令

乘法共有兩條指令。

(1)MUL(unsigned multiply):無符號數的乘法指令

格式:MUL s

操作:s為字節操作數:AL×(s)→AX

   s為字操作數:AX×(s)→DX,AX

MUL指令中僅有一個操作數(源操作數),表示乘數,可使用寄存器或各種尋址方式的存儲器操作數,而絕對不可以使用立即數和段寄存器。指令中的目標操作數隱含在指令中且必須使用累加器(表示被乘數),字節相乘使用AL,字相乘使用AX。乘法操作的過程如圖3.16所示。

圖3.16 乘法指令操作

由圖3.16(a)可知,兩個8位數相乘時,用AL中的被乘數乘以乘數,得到的乘積為16位,存放在AX中。由圖3.16(b)可知,兩個16位數相乘時,用AX中的被乘數乘以乘數,得到的乘積為32位,存放在DX,AX中(DX存放結果的高位字,AX存放結果的低位字)。

(2)IMUL(signed multiply):有符號數的乘法指令格式:IMUL s

操作:s為字節操作數 AL×(s)→AX

   s為字操作數 AX×(s)→DX,AX

IMUL指令執行的操作與MUL指令基本相同,不同之處在于MUL指令中的操作數為無符號數,而IMUL指令中的操作數為有符號數。

無符號數和有符號數的乘法指令執行結果是不同的。例如:兩個4位二進制數1110和0011,如果理解為無符號數使用MUL指令運算,則1110B×0011B=2AH(即十進制數的14×3=42)。如果理解為有符號數用IMUL指令運算,則1110還原的原碼為1010B(即十進制數的-2),0011B的原碼仍為0011B(十進制數的+3)。運算時,先去掉符號位,將兩個數的絕對值相乘,0010B×0011B=00000110B,其結果的符號按兩個數符號位“異或”運算規則確定,1⊕0=1,結果為負,再將相乘所得的結果取補碼。所以,最后相乘的結果為11111010B=FAH(十進制數-2×3=-6)。

乘法指令的操作影響OF和CF標志位,對其余的標志位無定義(指令執行后,這些標志位的狀態不確定)。對于MUL指令,如果乘積的高一半數位為0,即字節操作時AH=0,字操作時DX=0,則操作結果使CF=0,OF=0。否則,當AH≠0或DX≠0時,則CF=1,OF=1,這種情況的標志位狀態可以用來檢查字節相乘的結果是字節還是字,字相乘的結果是字還是雙字。而對于IMUL指令,如果乘積的高一半數位是低一半符號位的擴展,則CF=0,OF=0;否則,CF=1,OF=1。

例如:MUL BL

指令執行前,AL=B4H=180,BL=11H=17,均為無符號數

指令執行:

指令執行后,AX=0BF4H=3060,BL=11H,CF=1,OF=1。

例如:IMUL BL

指令執行前,AL=B4H=-76,為有符號數,BL=11H=17。

指令執行時,先將AL和BL中的內容轉換為原碼并將符號位去掉(AL=4CH),數值部分相乘。

再求結果的符號,1-0=1,即乘積應該為負數,將結果取補碼[050CH]補=FAF4H=-1292,BL=11H,CF=1,OF=1。

4.除法指令

除法指令共有4條。

(1)DIV(unsigned divide):無符號數的除法指令

格式:DIV s

操作:分為字節和字兩種操作類型。

字節操作時,16位被除數在AX中,8位除數為源操作數,結果的8位商在AL中,8位余數在AH中,表示為:

    AX/(s)→AL 商
    AX/(s)→AH 余數

字操作時,32位被除數在DX和AX中,其中DX為高位字,16位除數為源操作數,結果的16位商在AX中,16位余數在DX中,表示為:

    DX,AX/(s)→ AX 商
    DX,AX/(s)→ DX 余數

DIV指令的被除數、除數、商和余數全部為無符號數。

(2)IDIV(signed divide):有符號數的除法指令

格式:IDIV s

操作:與DIV指令相同,只是被除數、除數、商和余數均為有符號數,且余數的符號和被除數的符號相同。

這兩條除法指令中操作數s的規定與乘法指令相同。除法指令的操作過程如圖3.17所示。

圖3.17 除法指令操作過程

除法指令執行后,標志位AF、OF、CF、PF、SF和ZF都是不確定的。

使用IDIV指令時,如果一個雙字除以一個字,則商的范圍為-32728~+32727。如果一個字除以一個字節,則商的范圍為-128~+127。如果超出這個范圍,那么會產生0型中斷,以除數為0的情況來處理,而不是使溢出標志OF置1。

與有符號數的乘法指令類似,執行IDIV指令時,先將操作數變為原碼,并去掉符號位,然后再將兩個數(絕對值)相除。其結果是,商的符號按兩個數符號位“異或”運算規則確定,若符號位為1(負數),再取補碼。

由于除法指令的字節操作要求被除數為16位,字操作要求被除數為32位,因此,當實際數據不滿足以上要求時,就需要進行被除數位數的擴展。

對于無符號數除法指令DIV來說,只需將字節操作時被除數的高8位AH和字操作時被除數的高16位DX清0即可。

對于有符號數除法指令IDIV來說,AH和DX的擴展是將其低位字節或低位字的符號位擴展。即把AL中的最高位擴展到AH的8位中(正數為00H,負數為FFH),或者把AX中的最高位擴展到DX的16位中(正數為0000H,負數為FFFFH)。為此,80486微處理器指令系統提供了專門的符號擴展指令CBW和CWD。

(3)CBW(convert byte to word):字節轉換為字指令

格式:CBW

操作:AL中的符號位(最高位D7)擴展到AH中。若D7=0,則AH=00H;若D7=1,則AH=FFH。

(4)CWD(convert word to doubleword):字轉換為雙字指令

格式:CWD

操作:AX中的符號位(最高位D15)擴展到DX中。若D15=0,則DX=0000H;若D15=1,則DX=FFFFH。

CBW和CWD指令的執行結果都不影響標志位。

下面舉例說明除法指令的用法。

例如:DIV BL

指令執行前,AX=0400H=1024,BL=B4H=180,均為無符號數。

指令執行:

指令執行后,AL=05H=5(商),AH=7CH=124(余數)。

例如:IDIV BL

指令執行前,AX=0400H=+1024,BL=B4H=-76,均為有符號數。

指令執行,先將BL中的內容轉換為原碼,去掉符號位,BL=4CH,數值部分相除:

數值相除后,求商的符號,0⊕1=1,即商為負數,對商再求補碼得F3H,余數的符號與被除數相同。

指令執行后,AL=F3H=-13(商),AH=24H=36(余數)。

下面是用加、減、乘、除指令進行算術運算的例子。

【例3.6】 編程計算(V-((X×Y)+Z-540))÷X=?

其中,XYZV均為16位有符號數,已分別裝入內存的X、Y、Z、V字單元中。要求將上式計算得到的結果存入AX中,余數存入DX中。現編制程序如下:

    MOV    AX,X   ; 將被乘數X存入AX中
    IMUL   Y       ; DX,AX←X*Y
    MOV    CX,AX
    MOV    BX,DX  ; 將乘積存入BX,CX中
    MOV    AX,Z   ; 將加數Z存入AX中
    CWD            ; 將加數擴展為雙字存入DX,AX中
    ADD    CX,AX
    ADC    BX,DX  ; 完成X*Y+Z并將結果存入BX,CX中
    SUB    CX,540
    SBB    BX,0   ; 完成X*Y+Z-540,結果存入BX,CX中
    MOV    AX,V   ; 將V存入AX
    CWD            ; 將V擴展為雙字數據存入DX,AX中
    SUB    AX,CX
    SBB    DX,BX  ; 完成V-(X*Y+Z-540),并將結果存入DX,AX中
    IDIV   X       ; 完成(V-(X*Y+Z-540))/X運算,并將結果存入DX,AX中

5.十進制調整指令

前面介紹過的算術運算指令都是二進制數的運算指令,如果要進行十進制數的運算,必須先把十進制數轉換為二進制數,用相應的二進制數運算指令進行運算,然后再將運算得到的二進制數結果轉換為十進制數加以輸出。為了便于十進制數的運算,80486指令系統提供了一組專門用于十進制調整的指令,可將由二進制數運算指令得到的結果進行調整,從而得到十進制數的結果。

表示十進制數的BCD碼分為兩種:壓縮BCD碼和非壓縮BCD碼。

壓縮的BCD碼用4位二進制數表示一個十進制數位,整個十進制數形式為一個順序的以4位為一組的數串。

例如,十進制數8564的壓縮BCD碼形式為:

用十六進制數表示為8564H。

非壓縮的BCD碼以8位二進制數為一組,表示一個十進制數位,8位中的低4位表示一位8421BCD碼,而高4位則沒有意義,通常將高4位清0。例如:8564的非壓縮BCD碼形式為:

用十六進制數表示為08050604H,為4字節數據。

由于數字0~9的ASCII碼其高4位為0011B,低4位是以8421BCD碼表示的十進制數位,符合非壓縮BCD碼高4位無意義的規定。

用普通二進制數運算指令對BCD碼運算時,為什么要進行調整?怎樣進行調整?下面通過加法來說明十進制調整的原理。

【例3.7】 實現7+6=13。

即BCD碼的7加6,結果為十六進制數D。在BCD碼中,只允許出現0~9共10個數字,D不代表任何BCD碼,因此,必須對其進行轉換,即進行調整。

如何調整?我們知道,BCD碼運算的進位規則是“逢十進一”,但80486指令系統中的加法指令進行的是二進制數運算,對于4位二進制數運算來說,是“逢十六進一”。用這些加法指令進行十進制數運算時,必須跳過6個數的編碼1010~1111。這些數在二進制數中是存在的,而在BCD碼中是不存在的。因此在調整過程中,遇到運算結果中出現1010~1111時,就必須加0110(6)進行調整,讓其產生進位,從而得到正確的十進制數結果。對上述結果進行加6調整,則:

【例3.8】 實現28+39=67。

用壓縮BCD碼表示,并用二進制數加法指令相加的過程如下:

若將結果看成BCD碼,則表示十進制數61,顯然是錯誤的。其原因是,計算機在運算時,要使低4位向高4位進位,二進制數必須是逢16才能進位,而BCD碼是逢十進一,所以當BCD碼按照二進制數運算規則進行計算時,只要產生了半進位,就會“暗中”丟失一個6,因此,必須在結果的低4位進行加6調整,才能得到正確的結果。對上述結果進行加6調整,則:

【例3.9】 實現80+94=174。

將兩個加數用壓縮BCD碼表示,并用二進制數加法指令相加,過程如下:

表示十進制數結果114,而不是174,錯誤的原因是高4位產生進位CF=1,所以應該對運算結果的高4位加6調整,則

由此可知:當BCD碼的數位增多需要進行多字節BCD碼加法時,調整的原理是一樣的。凡是遇上某4位二進制數值大于9時,則進行加6調整。凡是一個字節中的低4位向高4位產生進位(AF=1),或者是低位字節向高位字節產生進位(CF=1)時,也應進行加6調整。十進制調整指令會根據AF或CF的狀態做出判斷,看是否需要進行加6調整。

如果是進行多字節BCD碼減法,則相應地進行減6調整,乘、除法也有相應的調整辦法。

(1)壓縮BCD碼調整指令

① DAA(decimal adjust AL after addition):加法的十進制調整指令。

格式:DAA

操作:DAA指令必須緊跟在二進制數加法指令ADD或ADC之后,將二進制數加法的結果(必須放在AL中)調整為壓縮的BCD碼格式,再存入AL中。可見,二進制數加法指令ADD/ADC和DAA指令構成復合的壓縮BCD碼加法指令。

DAA指令的調整方法:考察結果(在AL中)的低4位和高4位的值以及半進位標志AF和進位標志CF的狀態,如果結果的低4位的值大于9或AF=1,則將結果的低4位進行加6調整,并將AF標志位置1。如果結果的高4位的值大于9或CF=1,則將結果的高4位進行加6調整,并將CF標志位置1;如果結果的高4位和低4位的值均大于9或既有AF=1,又有CF=1時,則將結果的高、低4位均進行加6調整,并將AF、CF標志位均置1,從而得到正確的壓縮BCD碼結果。

DAA指令對OF標志無定義,但卻影響其他所有標志。

例如:ADD AL,DL

   DAA

指令執行前:AL=27H,DL=49H。

執行ADD指令:

由于ADD指令執行后,得到的是二進制數結果,不是壓縮BCD碼,又有AF=1,必須進行十進制調整。

執行DAA指令:

此時,AL=76H是壓縮的BCD碼加法,結果為76(27+49=76)。

【例3.10】 假設(BCD1)=1834H,(BCD2)=2789H,要求將這兩個十進制數相加,相加的和存入BCD3中,即 (BCD1)+(BCD2)→(BCD3)。

BCD1和BCD2都是4位壓縮的BCD碼,每個數都占有兩個字節單元,高位字節數據存放在高地址單元中,低位字節數據存放在低地址單元中,其存放方式為:

(BCD1+1)=18H,(BCD1)=34H

(BCD2+1)=27H,(BCD2)=89H

根據題目要求編寫出4位十進制數相加的程序如下:

   MOV  AL,BCD1   ; 取第一個數低2位BCD碼送AL
   ADD  AL,BCD2   ; 兩個數低2位BCD碼二進制數加法運算,結果送AL
   DAA             ; 十進制調整,得到BCD碼結果
   MOV  BCD3,AL   ; 存低2位BCD碼結果到BCD3碼單元中
   MOV  AL,BCD1+1 ; 取第一個數高2位BCD碼送AL
   ADC  AL,BCD2+1 ; 兩個數高2位BCD碼帶低位進位相加,得到二進制數結果
   DAA             ; 十進制調整,得到BCD碼結果
   MOV  BCD3+1,AL ; 存高2位BCD碼結果到BCD3+1單元中

本程序共有8條指令,分成兩組。第一組前4條指令,完成兩個加數低2位BCD碼相加,經十進制調整后存入DCD3中。其中,ADD指令執行后,AL=BDH,CF=0,AF=0,經DAA指令調整后,AL=23H,CF=1,AF=1。

第二組后4條指令,完成兩個加數高2位BCD碼帶進位相加,經十進制調整后存入BCD3+1單元中。其中,ADC指令執行后,AL=40H,CF=0,AF=1,經DAA指令執行后,AL=46H,CF=0,AF=0。

程序執行后,字單元(BCD3)=4623H,結果正確。

② DAS(decimal adjust AL after subtraction):減法的十進制調整指令。

格式:DAS

操作:DAS指令必須緊跟在二進制數減法指令SUB或SBB指令之后,將二進制數減法的結果(必須放在AL中)調整為壓縮的BCD碼格式,再存入AL中。可見,二進制數減法指令SUB/SBB和DAS指令構成了復合的壓縮BCD碼減法指令。

DAS指令的調整方法類似于DAA,只是在進行十進制調整時,DAA指令是加6調整,而DAS指令是減6調整。對標志位的影響也同DAA指令。

例如:SUB AL,AH

   DAS

若指令執行前:AL=88H,AH=49H。

執行SUB指令后,AL=3FH,AF=1。執行DAS指令,因為AF=1,需要減06H進行調整。

指令執行后,AL=39H,是壓縮的BCD碼減法結果39(88-49=39)。

(2)非壓縮的BCD碼調整指令

① AAA(ASCII adjust after addition):加法的ASCII碼調整指令。

格式:AAA

操作:與DAA指令一樣,AAA指令也必須緊跟在二進制數加法指令ADD/ADC之后,先用二進制數加法指令將兩個非壓縮的BCD碼相加,并把結果存入AL寄存器中。

指令執行時:

AL←把AL中二進制數加法的結果調整為非壓縮BCD碼格式;

AH←AH+調整產生的進位值。

考察AL寄存器的低4位的值或AF標志,一旦發現其低4位的值大于9或AF=1,則將AL寄存器的內容進行加6調整,AH寄存器的內容加1,將AF標志位置1,清除AL寄存器的高4位,并將AF的值送給CF。AAA指令影響AF和CF標志位,對其余的標志位無效。

例如:ADD AL,CL

   AAA

指令執行前,AX=0035H,CL=38H,為數字5和8的ASCII碼,相加結果應為13。但是執行ADD指令后,AL=6DH,AF=0,需要進行加6調整。執行AAA指令進行調整,清除AL的高4位,低4位加06H。調整后,AL高4位為1,AH的內容加1,并將AF的值送給CF。所以,AX=0103H,即非壓縮BCD碼的13,AF=1,CF=1。

② AAS(ASCII adjust AL after subtraction):減法的ASCII碼調整指令。

格式:AAS

操作:和DAS指令一樣,AAS必須緊跟在減法指令SUB或SBB之后,先用二進制數減法指令將兩個非壓縮的BCD碼相減,并將結果存入AL寄存器中。

AAS指令執行時:

  AL←把AL中減法結果調整為壓縮的BCD格式;

  AH←AH-調整產生的借位值。

考察AL寄存器的低4位的值或AF標志,一旦發現其低4位的值大于9或AF=1,則把AL寄存器的內容減6,AH寄存器的內容減1,將AF標志位置1,清除AL寄存器的高4位,并將AF的值送給CF。AAS指令操作對標志位的影響同AAA指令。

例如:SUB AL,DL

   AAS

指令執行前,AX=0236H,DL=39H,寄存器AL和DL的內容分別為數字6和9的ASCII碼。

SUB指令執行后,AL=FDH,AF=1。

AAS指令執行后,AL減06H調整,AH減1,同時清除AL高4位,則AX=0107H,CF=1,AF=1。

③ AAM(ASCII adjust AX after multiplication):乘法的ASCII碼調整指令。

格式:AAM

操作:AX←把AL中的二進制乘積調整為非壓縮的BCD格式

在AAM指令執行前,必須先執行MUL指令,將兩個非壓縮的BCD碼相乘(此時要求其高4位為0),結果放在AL寄存器中。AAM指令的調整方法:將AL寄存器的內容除以0AH,所得的商(高位十進制數)保存在AH寄存器中,余數(為低位十進制數)保存在AL寄存器中。AAM指令影響標志位SF、ZF和PF,但對OF、CF和AF位無意義。

例如:MUL BL

   AAM

指令執行前,AL=07H,BL=09H。

MUL指令執行后,AL=3FH。

AAM指令執行后,AH=06H,AL=03H。

④ AAD(ASCII adjust AX before division):除法的ASCII碼調整指令。

格式:AAD

操作:AL←10×AH+AL

   AH←0

前面所述的加法、減法和乘法的ASCII碼調整指令都是用加法、減法和乘法指令對兩個非壓縮的BCD碼運算之后,再使用AAA、AAS、AAM指令來對運算結果進行十進制調整的,而AAD指令則是在除法之前先進行調整操作。

AAD指令的調整操作是,將預先存放在AX中的兩位非壓縮BCD碼的十進制數調整為二進制數,存放在AL中。具體做法是,將AH中的高位十進制數乘以10,與AL中的低位十進制數相加,結果以二進制數形式保留在AL中,然后將AH清0。

例如:AAD

指令執行前,AX=0607H。

操作過程:AL=(AH)×10+(AL)

      =06×10+07

      =67

      =43H

指令執行后,AX=0043H。

3.3.3 邏輯運算與移位類指令

邏輯運算與移位類指令可分為三種類型,見表3.3。

表3.3 邏輯運算與移位類指令

注:表中對標志位影響的符號含義同表3.2。

1.邏輯運算指令

邏輯運算指令共有5條。

(1)AND(logical AND):邏輯“與”指令

格式:AND d,s

操作:(d)←(d)∧(s)

其中,符號“∧”表示邏輯“與”操作。源操作數s可以是8/16位通用寄存器、存儲器操作數或立即數,而目標操作數d只允許是通用寄存器或存儲器操作數。

AND指令可將兩個操作數的內容按位相“與”,并將結果保存到目標操作數中。指令執行后,將使CF=0,OF=0,AF位無定義,并影響SF、ZF和PF標志位。

AND指令常用于將操作數的某些位清0(也稱為屏蔽某些位),而其余位維持不變。需要清0的位和0相“與”,需要維持不變的位和1相“與”。

【例3.11】 將AL寄存器中的D1位、D5位清0,其余位保持不變。

AND AL,0DDH ; 將D1位、D5位和0“與”,其他位和1“與”

指令執行前,AL=7AH。

指令執行:

指令執行后,AL=58H。

(2)OR(logical OR):邏輯“或”指令

格式:OR d,s

操作:(d)←(d)∨(s)

其中,符號“∨”表示邏輯“或”操作。源操作數和目標操作數的約定同AND指令。

OR指令可將兩個操作數的內容按位相“或”,并將結果保存到目標操作數中。對標志位的影響同AND指令。

利用OR指令可將操作數的某些位置1,而其余位不變。需要置1的位和1相“或”,需要維持不變的位和0相“或”。

例如:OR AL,80H

上述指令可以使AL寄存器中的最高位置1,其余位不變。

指令執行前,AL=3AH。

指令執行:

指令執行后,AL=BAH。

(3)XOR(logical exclusive OR):邏輯“異或”指令

格式:XOR d,s

操作:(d)←(d)⊕(s)

其中,符號“⊕”表示邏輯“異或”操作。源操作數和目標操作數的約定同AND指令。

XOR指令可將兩個操作數按位相“異或”,并將結果保存到目標操作數中。對標志位的影響同AND指令。

利用XOR指令,可將操作數的某些位求反,某些位不變。維持不變的位與0相“異或”,需要求反的位與1相“異或”。

例如:XOR BL,0FH

該指令可使BL寄存器的高4位維持不變,而將低4位求反。

指令執行前,BL=55H。

指令執行:

指令執行后,BL=5AH。

例如:XOR AL,AL

指令執行前,AL=78H。

指令執行:

指令執行后,AL=00H,CF=0,ZF=1。

可見,XOR指令可用于將操作數清0,并使CF=0。

(4)NOT(logical NOT):邏輯“非”指令

格式:NOT d

操作:其中,操作數d上面的“-”表示求反運算,有關操作數的約定同AND指令。

NOT指令可將操作數的內容按位求反,并將結果保存到源操作數中,其執行結果不影響任何標志位。

例如:NOT AL

指令執行前,AL=33H。

指令執行后,AL=CCH。

(5)TEST(test bits):測試指令

格式:TEST d,s

操作:(d)∧(s)

TEST指令完成的操作、操作數的約定,以及對標志位的影響同AND指令,只是TEST指令不回送結果到目標操作數中。

使用TEST指令,通常是在不希望改變原有操作數的情況下,檢測某一位或某幾位的狀態,所以常被用于條件轉移指令之前,根據測試的結果令程序發生跳轉。

【例3.12】 檢測DL中的最高位是否為1。若為1,則轉移到標號LOP1去執行;否則順序執行。

可用下列程序實現:

       TEST DL,80H
       JNZ LOP1
       …
LOP1: MOV AL,BL
       …

2.移位與循環移位指令

移位與循環移位指令共有8條,其功能如圖3.18所示。指令中的目標操作數d可以是8/16位通用寄存器和存儲器操作數,不允許使用立即數和段寄存器。移位次數由count決定。count可取1或CL寄存器操作數。當count為1時,每執行一條指令,可將操作數的內容移1位;若需要移位的次數大于1,則必須在移位指令之前,將移位次數置于CL中,而在移位指令中將count寫為CL,當移位結束后,CL=0。

(1)移位指令

移位指令共有4條。

① SHL(shift left):邏輯左移指令

格式:SHL d,count

操作:SHL指令可將目標操作數的內容向左移位,移位的次數由count給定,每左移1位,操作數最高位的狀態移入CF標志位,末位補0。

圖3.18 移位與循環移位指令功能

例如:MOV CL,4

   SHL AL,CL

SHL指令執行后,使AL的內容左移4位,即AL中的低4位的狀態移入高4位,并將低4位清0。

② SHR(shift right):邏輯右移指令

格式:SHR d,count

操作:SHR指令的操作和SHL指令相反,將目標操作數的內容向右移位,每右移1位,操作數最末位移入CF標志,最高位補0。

③ SAL(shift arithmetic left):算術左移指令

格式:SAL d,count

操作:與SHL指令完全相同。

④ SAR(shift arithmetic right):算術右移指令

格式:SAR d,count

操作:將目標操作數的內容向右移位,每右移1位,操作數最末位移入CF標志位,最高位移入次高位的同時其值不變,這樣,移位后最高位和次高位的值相同,符號位始終保持不變。

綜上所述,移位指令分為算術移位指令和邏輯移位指令。算術移位指令只對有符號數進行移位,在移位過程中保持符號位不變。而邏輯移位指令對無符號數移位,移位時,總是用0來填補已空出的數位。每左移1位,相當于將原數據乘以2,每右移1位,相當于將原數據除以2。根據移位操作的結果置標志寄存器中的狀態標志(AF位除外)。若移位的次數是1,移位的結果又使最高位(符號位)發生變化,則將溢出標志OF置1。移多位時,OF標志無效。這樣,對于有符號數而言,可由此判斷移位后的符號位和移位前的符號位是否相同。

(2)循環移位指令

循環移位指令共有4條。

① ROL(rotate left):循環左移指令

格式:ROL d,count

操作:每左移1位,目標操作數最高位的狀態移出,該狀態除送入標志位CF外,還循環傳遞到由于左移1位而空出的目標操作數最末位。

② ROR(rotate right):循環右移指令

格式:ROR d,count

操作:ROR指令的操作正好和ROL指令相反,每右移1位,將目標操作數最末位的狀態移出,并傳遞到CF標志和目標操作數的最高位。

③ RCL(rotate left through carry):帶進位循環左移指令

格式:RCL d,count

操作:每左移1位,將目標操作數最高位的狀態移入CF標志位,而CF標志原先的狀態移入目標操作數最末位。

④ RCR(rotate right through carry):帶進位循環右移指令

格式:RCR d,count

操作:RCR指令完成的操作和RCL指令正好相反。每右移1位,將目標操作數最末位的狀態移入CF標志,而CF標志原先的狀態移入目標操作數最高位。

綜上所述,循環移位指令有兩類。ROL和ROR指令在執行時,沒有把CF套在循環中,稱為小循環移位。而RCL和RCR指令在執行時,連同CF一起進行循環移位,稱為大循環移位。以上4條指令僅影響標志位CF和OF。對OF的影響表現為,ROL和RCL指令在執行一次左移后,如果目標操作數的最高位與CF(原先的符號位)不等,說明新的符號位與原來的符號位不同了,則使OF=1,表明左移循環操作造成了溢出。同樣,ROR和RCR指令在執行一次右移后,如果目標操作數的最高位和次高位不等,也表明移位后新的數據符號與原來的符號不同了,此時也會使OF=1,產生溢出。

【例3.13】 若X為字數據,已存放在寄存器AX中,現要求將該數乘以10。

在80486指令系統中有乘法指令,但從指令手冊中可知,執行乘法指令所花的時間為10~11個時鐘周期。而用移位指令實現乘2操作所需要的時間為1~3個時鐘周期,從而可提高計算速度3~10倍。

很明顯,X×10=X×2+X×8。某數乘2即左移1位,乘8即左移3位。程序如下:

    SAL AX,1  ; X*2
    MOV BX,AX ; X*2的乘積存入BX
    SAL AX,1  ; X*4
    SAL AX,1  ; X*8
    ADD AX,BX ; X*8+X*2=X*10

執行上述程序段所需要的時間為5個時鐘周期。若改用乘法指令實現乘10操作,則所需時間為11個時鐘周期。

3.3.4 串操作類指令

80486指令系統提供了一組強有力的串操作指令。串操作指令可以對一系列含有字母、數字的字節(也稱字符串)進行操作和處理,例如,傳送、比較、查找、插入、刪除操作等。

串操作指令是指令系統中唯一可以在存儲器內部進行源操作數與目標操作數之間的操作的指令,所有串操作指令均可以處理字或字節。串操作指令見表3.4。

為縮短指令長度,串操作指令均采用隱含尋址方式。一般,源串存放在當前數據段中,由DS段寄存器提供段基址,其偏移地址必須由源變址寄存器SI提供。目標串必須存放在附加段中,由ES段寄存器提供段基址,其偏移地址必須由目標變址寄存器DI提供。如果要在同一段內進行串操作,必須使DS和ES指向同一段。字符串長度必須存放在CX寄存器中。因此,在串指令執行之前,必須對SI、DI和CX預置初值,即將源串和目標串的首元素或末元素的偏移地址分別置入SI和DI中,將字符串長度置入CX中。這樣,CPU每處理完一個字符串元素,就自動修改SI和DI寄存器的內容,使之指向下一個元素。

表3.4 串操作指令

注:表中對標志位影響的符號含義同表3.2。

為加快串操作的執行速度,可在串操作指令前加上重復前綴,共有5種重復前綴。帶有重復前綴的串操作指令,每處理完一個字符串元素后自動修改CX的內容(按字節/字處理,減1或減2),以完成計數功能。當CX≠0時,繼續串操作,直到CX=0時才結束操作。

串操作指令對SI和DI寄存器的修改與兩個因素有關。①與被處理的字符串是字節串還是字串有關。②與當前標志寄存器中DF的狀態有關。當DF=0時,表示串操作由低地址向高地址進行,SI和DI內容遞增,其初始值應該是源串和目標串的首地址;當DF=1時,則情況正好相反。

1.字符串操作指令

80486指令系統中共有5種串操作指令,下面分別予以介紹。

(1)MOVS(move data from string to string):串傳送指令

格式(有三種形式):

    MOVS  d,s
    MOVSB       ; 字節串傳送
    MOVSW       ; 字串傳送

操作:① (DI)←(SI)

② 若為字節操作:SI←SI±1,DI←DI±1

當方向標志DF=0時,用“+”;當方向標志DF=1時,用“-”。

③ 若為字操作:SI←SI±2,DI←DI±2

當方向標志DF=0時,用“+”;當方向標志DF=1時,用“-”。

MOVS指令可以把一個字節或一個字從源串(由SI尋址)傳送到目標串(由DI尋址)中,并自動修改SI和DI的值,使之指向下一個字符串元素。MOVSB/MOVSW是MOVS的替代符,由于指令助記符中已明確是字節串還是字串傳送,因此沒有操作數。通常,指令前要加上重復前綴REP,此時,要傳送的字符個數在CX中,每傳送完一個元素,CPU自動修改CX的值(按字節/字處理,減1或減2),直到CX=0為止,從而完成從存儲器到存儲器的字符串成塊傳送。串傳送指令的結果不影響標志位。

例如,設變量ADDR1和ADDR2為字類型,下面兩條指令是等效的:

    MOVS  ADDR1,ADDR2
    MOVSW

【例3.14】 將源數據串的256個字節數據傳送到目標串的單元中。源數據串的段首地址的偏移地址為2000H,目標串首地址的偏移地址為5000H。

完成數據串傳送的程序段如下:

    CLD           ; DF=0,地址自動遞增
    MOV CX,256   ; 設置計數器,初始值為數據串的長度,CX←256
    MOV SI,2000H ; 源數據串首元素的偏移地址,SI←2000H
    MOV DI,5000H ; 目標數據串首元素的偏移地址,DI←5000H
    REP MOVSB     ; 重復串操作,直到CX=0為止

(2)CMPS(compare string operands):串比較指令

格式(有三種形式):

    CMPS s,d
    CMPSB
    CMPSW

字節操作:(SI)-(DI),SI←SI±1,DI←DI±1

字操作:(SI)-(DI),SI←SI±2,DI←DI±2

串比較指令將由SI作為指針的源串中的一個元素減去由DI作為指針的目標串中相對應的一個元素,不回送結果,只根據結果特征置標志位,并相應地修改SI和DI的值,使之指向下一個元素。指令的其他特性與MOVS指令的相同。通常,在CMPS指令前加重復前綴REPE/REPZ,兩者的定義完全相同,只是書寫的形式不一樣而已。此時,可重復進行兩數的比較。僅當ZF=1(兩數相等)且CX≠0(元素未比較結束)時,才可繼續進行比較,一旦發現ZF=0(兩數不相等或元素比較結束),則終止指令的執行。

注意:串比較指令的源串操作數(由SI尋址)是寫在逗號左邊的,而目標串操作數(用DI尋址)寫在右邊。這是指令系統中唯一例外的指令句法結構,編程時要特別注意。CMPSB和CMPSW同樣作為CMPS指令的替代符,不帶操作數。

(3)SCAS(scan byte or word string):搜索指令

格式(有三種形式):

    SCAS  d
    SCASB     ; 字節串搜索
    SCASW     ; 字串搜索

字節操作:AL-(DI),DI←DI±1

字操作:AX-(DI),DI←DI±2

搜索指令用來從目標串中查找某個關鍵字,要求將待查找的關鍵字預先置入AX(字)或AL(字節)中。指令執行時,將AX或AL中的關鍵字減去由DI指向的目標串中的一個元素,不傳送結果,只根據結果置標志位,然后修改DI的值使之指向下一個元素。通常,在SCAS前加重復前綴REPNE/REPNZ,可重復進行在目標串中尋找關鍵字的操作,一直到ZF=1(查到了某關鍵字)或CX=0(終未查找到)為止。同樣,SCASB和SCASW為SCAS指令的替代符,不帶操作數。

【例3.15】 從段首元素的偏移地址為0100H的一個字符串(字符個數為256)中找出指定的字符(如$),可用REPNZ SCASB指令實現。

程序如下:

CLD           ; DF=0,地址自動遞增
MOV DI,0100H ; 目標串首元素的偏移地址,DI←0100H
MOV CX,256   ; 設置計數器初始值,CX← 256
MOV AL,'$'   ; 設關鍵字,AL←24H($的ASCII碼)
REPNZ SCASB   ; 找關鍵字,若未找到則重復查找

(4)LODS(load byte or word string):讀字符串指令

格式(有三種形式):

LODS s
LODSB   ; 讀取字節串
LODSW   ; 讀取字串

字節操作:AL←(SI),SI←SI±1

字操作:AX←(SI),SI←SI±2

讀字符串指令把由SI指定的數據段中字節或字單元的內容送入AL或AX中,并根據方向標志DF及數據類型來修改SI的值。

指令執行之前,要取出的數據必須在存儲器中預先定義(用DB或DW),SI必須預置初始值。讀字符串指令一般不加重復前綴,常用來和其他指令相結合完成復雜的串操作功能。而LODSB和LODSW同樣為LODS的替代符,不帶操作數。讀字符串指令的執行結果不影響標志位。

(5)STOS(store byte or word string):寫字符串指令

格式(有三種形式):

STOS  d
STOSB   ; 寫入字節串
STOSW   ; 寫入字串

字節操作:(DI)←AL,DI←DI±1

字操作:(DI)←AX,DI←DI±2

寫字符串指令將AL或AX中的內容存入由DI指定的附加段中的字節或字單元中,并根據DF的值及數據類型來修改DI的值。

指令執行之前,必須把要存放的數據預先存入AX或AL中,并對DI預置初始值。寫字符串指令的執行結果也不影響標志位。STOSB和STOSW同樣為STOS的替代符,不帶操作數。如果加上前綴指令REP,則用STOSB和STOSW可使一串內存單元填滿相同的數。

【例3.16】 將字符'$'送入附加段中偏移地址為0100H的連續5個單元中。

程序如下:

CLD           ; DF=0,地址自動遞增
MOV CX,5     ; 設置計數器,CX←5
MOV DI,0100H ; 目標串首元素的偏移地址,DI←0100H
MOV AL,'$'   ; 設置關鍵字,AL←24H($的ASCII碼)
REP STOSB     ; 連續將'$'寫入相應存儲單元中

2.重復前綴

在實際應用中,如果必須重復執行基本串操作來處理一個數據陣列,則需要在指令前加上一個重復前綴。常用的重復前綴見表3.5。

表3.5 常用的重復前綴

(1)前綴REP(repeat)

REP將重復基本操作一直到CX寄存器的值為0為止。每次執行指令時都要測試CX。如果CX≠0,則CX減1,重復基本操作。當CX=0時,重復串操作結束,執行下一條指令。在執行重復串指令前必須先將重復次數裝入CX中。

(2)前綴REPE/REPZ(repeat while equal/repeat while zero)

REPE和REPZ的功能相同。它們與CMPS、SCAS指令一起使用。帶前綴的CMPS/ SCAS指令,只要CX≠0且ZF=1,基本比較或掃描操作就能夠一直重復執行。CX≠0表示還沒有到達串尾,ZF=1表示所比較的元素相等。

(3)前綴REPNE/REPNZ(repeat while not equal/repeat while not zero)

REPNE和REPNZ的工作方式類似于REPE/REPZ,只不過重復條件變為CX≠0且ZF=0。這就是說,只要串元素不等且未到達串尾,就重復執行比較或掃描操作。

3.3.5 程序控制類指令

在一般情況下,CPU執行程序是按照指令的順序逐條執行的,但實際上程序不可能總是順序執行,而經常需要改變程序的執行流程,轉移到所要求的目標地址去執行,這就必須安排一條程序轉移類指令。在80486指令系統中,程序控制類指令就是專門用來控制程序流向的,包括無條件轉移、條件轉移、循環控制及中斷控制4種類型。

1.無條件轉移指令

無條件轉移指令的功能是使程序無條件地轉移到指令指定的地址去執行。它分為無條件轉移、調用過程及從過程返回三種指令格式,見表3.6。

表3.6 無條件轉移指令的三種指令格式

(1)JMP(unconditional jump):無條件轉移指令

格式:JMP 目標標號

操作:JMP指令可以使程序無條件地轉移到目標標號指定的地址去執行。目標地址可以在當前代碼段內(段內轉移),也可在其他代碼段中(段間轉移)。根據目標地址的位置和尋址方式的不同,有5種基本格式。

① 段內直接短程轉移

格式:JMP SHORT 目標標號

操作:IP←IP+D8

其中,SHORT為屬性操作符,表明指令代碼中的操作數是一個以8位二進制補碼形式表示的偏移量,它只能在-128~+127范圍內取值。SHORT在指令中可以省略。執行指令時,轉移的目標地址由當前的IP值(即跳轉指令的下一條指令的首地址)與指令代碼中8位偏移量之和決定。

【例3.17】 在當前代碼段中有一條無條件轉移指令如下:

      JMP SHORT LOP1
       …
LOP1:MOV AL,55H
       …

上述指令的執行過程及轉移地址的形成如圖3.19所示。由圖3.19可知,當前IP的內容為0102H,偏移量為08H,所以,標號LOP1的偏移地址為0102H+08H=010AH。

圖3.19 例3.17指令的執行過程及轉移地址的形成

② 段內直接近程轉移

格式:JMP NEAR PTR 目標標號

操作:IP←IP+D16

其中,NEAR PTR為近程轉移的屬性操作符。段內直接近程轉移指令控制轉移的目標地址由當前IP值與指令代碼中16位偏移量之和決定,偏移量的取值范圍為-32768~+32767。其轉移的過程和短程轉移過程基本相同,屬性運算符NEAR PTR在指令中可以省略。

③ 段內間接轉移

格式:JMP WORD PTR OPR

操作:IP←(EA)

其中,OPR可以是存儲器或寄存器操作數。將段內轉移的目標地址預先存放在某寄存器或存儲器的某兩個連續地址中,指令中只需給出該寄存器名或存儲單元地址,這種方式稱為段內間接轉移(OPR為寄存器時,不加WORD PTR)。

例如:JMP BX

上述指令是由寄存器間接表示轉移的目標地址。設CS=1000H,IP=3000H,BX=0102H,該指令的執行首先以寄存器BX的內容取代IP的內容,然后,CPU將轉移到物理地址為CS×16+IP=10102H的單元中去執行后續指令。

例如:JMP WORD PTR [SI]

上述指令由存儲單元的內容表示轉移的目標地址,用該目標地址去置換IP的值,其中屬性字段WORD PTR表明后面緊跟的存儲器操作數是一個字類型。

設DS=2000H,SI=0100H,則存放轉移地址偏移量的字單元的物理地址為DS×16+SI=20100H。

指令執行前,CS=4000H,IP=2500H,(20100H)=22H,(20101H)=30H。

指令執行后,IP=3022H,程序轉移到43022H地址處繼續執行。

以上3種轉移方式均為段內轉移。在指令執行時,用指令提供的信息修改指令指針IP的內容,CS的值不變。

④ 段間直接轉移

格式:JMP FAR PTR 目標標號

操作:IP←目標標號的偏移地址

CS←目標標號所在段的段基址

其中,FAR PTR為屬性運算符,表示轉移是在段間進行的。目標標號在其他代碼段中,指令中直接給出目標標號的段基址和偏移地址,分別取代當前IP及CS的值,從而,轉移到另一代碼段中相應的位置去執行(FAR PTR在指令中可以省略)。

【例3.18】 下面程序段可實現段間直接轉移。

C1      SEGMENT
        …
        JMP FAR PTR ADDR1
        …
        C1 ENDS
        C2 SEGMENT
        …
ADDR1: MOV CL,AL
        …
C2      ENDS
圖3.20 例3.18指令的執行過程及轉移地址的形成

程序中,由段定義語句SEGMENT/ENDS(第4章介紹)定義了兩個代碼段C1段和C2段,JMP指令在C1段中,而要轉移去的目的標號ADDR1卻在C2段中。指令的執行過程及轉移地址的形成如圖3.20所示。

直接轉移同樣需要在指令中明確給出要跳轉到的目的標號。

⑤ 段間間接轉移

格式:JMP DWORD PTR OPR

操作:IP←(EA)

   CS←(EA+2)

其中,OPR只能是存儲器操作數。

指令中由操作數OPR的尋址方式確定一個有效地址EA,指向存放轉移地址的偏移地址和段基址的單元,根據尋址方式求出EA后,訪問相鄰的4個字節單元,低位字單元的16位數據送到IP寄存器中,高位字單元中的16位數據送到CS寄存器中,從而找到要轉移到的目標地址,實現段間間接轉移的目的。

例如:JMP DWORD PTR ALPHA [BP][DI]

也可以寫成 JMP DWORD PTR [BP+DI+ALPHA]

存放轉移地址(包括段基址和偏移地址)的堆棧段中的存儲單元的物理地址為SS×16+BP+DI+ALPHA。執行JMP指令時,從堆棧段中物理地址確定的連續4個單元中取出兩個字數據,將低位字送IP,高位字送CS。此時,程序便無條件轉移到新的CS確定的代碼段和新的IP為偏移地址的地方繼續執行程序。

(2)CALL(call a procedure):過程調用指令

格式:CALL 過程名

操作:CPU暫停執行下一條指令,無條件調用指定的過程。

“過程”即“子程序”。為了便于模塊化程序設計,往往把程序中某些具有獨立功能的部分編寫成獨立的程序模塊,稱為子程序。在程序中,可用調用指令CALL來調用這些子程序,而在子程序執行完后又用返回指令RET返回主程序繼續執行。

與JMP指令相似,CALL指令也有4種基本格式。

① 段內直接調用

格式:CALL NEAR PTR 過程名(或CALL 過程名)

操作:SP←SP-2

   (SP+1),(SP)←IP

   IP←IP+D16

將子程序的返回地址(CALL指令的下一條指令的首地址)存入堆棧中,使CPU無條件地轉到子程序的入口地址去執行,該入口地址是當前IP的值與16位偏移量D16相加的和(或稱調用以過程名為首地址的子程序)。

由于是段內調用,調用程序和子程序同在一個代碼段中,因此,不論是需要保護的返回地址,還是要調用的子程序首地址,只需要16位的偏移地址,即只改變IP的值,不改變CS值。直接調用是指在CALL指令中明確指出要調用程序的首地址(或稱過程名)。

② 段內間接調用

格式:CALL WORD PTR DST

操作:SP←SP-2

   (SP+1),(SP)←IP

   IP←(EA)

段內間接調用指令執行的操作步驟與段內直接調用大致相同,主要區別是子程序入口地址DST的尋址方式不同而已。指令的DST可以是寄存器操作數或存儲器操作數,不允許采用立即數和段寄存器操作數。執行CALL指令時,CPU把DST所對應的寄存器的內容或存儲器有效地址所在字單元的內容送入IP寄存器,作為子程序的入口地址,由于還是段內調用,因此CS值保持不變。

例如:CALL DI

   CALL WORD PTR [BX]

第一條指令,寄存器DI的內容就是子程序的入口地址。第二條指令,將BX的值確定的相鄰兩個存儲單元的內容作為子程序入口地址去修改IP,實現段內間接轉移。

③ 段間直接調用

格式:CALL FAR PTR 過程名 (或CALL 過程名)

操作:SP←SP-2

   (SP+1),(SP)←CS

   SP←SP-2

   (SP+1),(SP)←IP

   IP←子程序入口地址的偏移地址

   CS←子程序入口地址的段基址

其中,過程名即為段間直接調用的子程序的入口地址。段間直接調用指令的操作分為兩步:第一步,保護返回地址,即將CALL指令的下一條指令的地址(包括CS和IP的值)先后壓入堆棧保護,其順序為先CS后IP;第二步,將子程序入口地址(也包括段基址和偏移地址)分別送入IP和CS,從而實現段間直接調用。

由于是段間調用,調用程序和子程序不在同一代碼段中,因此,不論是需要保護的返回地址,還是要調用的子程序首地址,均包括段基址和偏移地址。直接調用同樣是指在指令中明確給出要調用的過程名。

④ 段間間接調用

格式:CALL DWORD PTR DST

操作:SP←SP-2

   (SP+1),(SP)←CS

   SP←SP-2

   (SP+1),(SP)←IP

   IP←(EA)

   CS←(EA+2)

其中,DST只能是各種尋址方式確定的存儲器操作數。執行的步驟分為兩步:第一步,將返回地址(包括IP和CS值)壓入堆棧保護;第二步,將指令的尋址方式確定的有效地址EA和EA+1兩個字節單元的內容送入IP,將EA+2和EA+3兩個字節單元的內容送入CS。這樣既修改了IP,又修改了CS,將CPU引導到另一個代碼段內子程序的首地址去執行。

例如:CALL DWORD PTR [BX]

   CALL DWORD PTR [BP][SI]

(3)RET(return from a procedure):過程返回指令

過程返回指令一般設置在子程序的末尾。它的功能是,從堆棧中彈出由CALL指令壓入的返回地址值,迫使CPU返回到主程序中CALL指令的下一條指令去繼續執行。段內返回指令把堆棧彈出的兩個字節內容送IP寄存器,而段間返回指令則將堆棧彈出4個字節的內容分別送IP和CS。

① 段內返回

格式:RET

操作:IP←(SP+1),(SP)

   SP←SP+2

② 段內帶立即數返回

格式:RET EXP

操作:IP←(SP+1),(SP)

   SP←SP+2

   SP←SP+D16

其中,EXP是一個表達式,根據它的值可計算出位移量D16。這種指令允許返回地址出棧后修改堆棧指針,這就便于調用程序在使用CALL指令調用子程序以前,把子程序所需要的參數入棧,以便子程序運行時使用這些參數。當子程序返回后,這些參數不再有用,就可以修改指針使其指向參數入棧以前的值,即自動刪除原子程序參數所占用的字節。

③ 段間返回

格式:RET

操作:IP←(SP+1),(SP)

   SP←SP+2

   CS←(SP+1),(SP)

   SP←SP+2

④ 段間帶立即數返回

格式:RET EXP

操作:IP←(SP+1),(SP)

   SP←SP+2

   CS←(SP+1),(SP)

   SP←SP+2

   SP←SP+D16

這里EXP的含義與段內帶立即數返回指令相同。

2.條件轉移指令

條件轉移指令根據對標志寄存器狀態位的測試結果來決定程序的走向,當條件滿足時,控制程序轉移到目標標號指定的那個存儲單元去執行程序,否則,程序不發生轉移,依然順序向下執行。

所有條件轉移指令的尋址方式只有一種,即位移量為8位的相對尋址方式,因此都是短程轉移,即轉向語句的目標地址必須在當前代碼段內,相對位移只能在-128~+127字節范圍內。

條件轉移指令共有18條,分為三類:第一類根據兩個無符號數比較/相減的結果決定是否轉移;第二類根據有符號數的比較/相減結果決定是否轉移;第三類根據單個標志位的值來決定程序是否轉移。條件轉移指令的指令名稱、指令格式及測試條件見表3.7。

表3.7 條件轉移指令

【例3.20】 在存儲器中有一個首地址為ARRAY的N字數組,要求測試其中正數、0及負數的個數。正數的個數放在DI中,0的個數放在SI中,并根據N-DI-SI求得負數的個數放在AX中。

程序如下:

            MOV CX,N                 ; 循環次數計數器CX置初始值
            MOV BX,0                 ; BX清0,設置數據指針
            MOV DI,0                 ; DI清0,累計正數個數
            MOV SI,0                 ; SI清0,累計0的個數
AGAIN:     CMP WORD PTR ARRAY[BX],0 ; 取一個數組元素與0進行比較
            JLE LESS OR EQ            ; 元素≤0,轉到LESS-OR-EQ標號
            INC DI                    ; 元素>0,使DI+1,累計正數個數
            JMP SHORT NEXT
LESS-OR-EQ:JL NEXT                   ; 元素<0,轉到NEXT標號
            INC SI                    ; 元素=0,使SI+1,累計0的個數
NEXT:      ADD BX,2                 ; 修改數據指針,指向下一個元素
            DEC CX                    ; 循環計數器減1
            JNZ AGAIN                 ; N個元素未測試完,轉到AGAIN標號
            MOV AX,N                 ; 數組已測試完,進行N-DI-SI運算
            SUB AX,DI
            SUB AX,SI                ; 求得負數的個數存入AX中

3.循環控制指令

循環控制指令又稱迭代控制指令,用來管理程序循環的次數。它與一般的條件轉移指令相同之處是:要依據給定的條件是否滿足來決定程序的走向。當滿足條件時,發生程序轉移;若不滿足條件,則順序向下執行程序。它與條件轉移指令不同之處是:循環指令要對CX寄存器的內容進行測試,用CX的內容是否為0作為轉移條件,或把CX的內容是否為0與ZF標志位的狀態相結合作為轉移條件。所有循環控制指令程序轉移的范圍只能在-128~+127字節內,具有短距離(SHORT)屬性。循環控制指令的指令名稱、指令格式及測試條件見表3.8。

表3.8 循環指令

由表3.8可知,JCXZ指令執行時不影響CX的內容;而執行其他的循環控制指令時,都會先使CX寄存器的內容自動減1,然后再判斷CX的內容是否為0,當CX≠0時才可能轉移。

【例3.21】 為檢查當前數據段所在的64K內存單元能否正確地進行讀/寫操作,一般做法是:先向每個字節單元寫入一個位組合模式01010101B(55H)或10101010B(AAH),然后讀出來進行比較,若讀/寫正確,則轉入處理正確的程序段,否則轉入出錯處理程序段。

程序如下:

       XOR   CX,CX        ; 初始值清0,CX=0
       XOR   BX,BX        ; BX寄存器清0,BX=0
       MOV   AL,01010101B ; 設置位組合模式,AL=01010101B=55H
CHECK:MOV   [BX],AL      ; 將55H寫入存儲單元
       INC   BX            ; 修改地址,BX←BX+1
       CMP   [BX-1],AL    ; 取出寫入單元的內容與AL(55H)相比較
       LOOPZ CHECK         ; 滿足ZF=1,且CX≠0則轉到CHECK執行
       JCXZ  RIGHT         ; CX=0,64KB內存單元均能正確讀/寫,轉到RIGHT執行
ERROR:…                  ; 一旦不能正確讀/寫,轉入出錯處理程序
       …
RIGHT:…                  ;處理正確程序
       …

4.中斷指令

中斷指令共有三條,見表3.9。

表3.9 中斷指令

(1)INT(interrupt):中斷指令

格式:INT TYPE

操作:SP←SP-2

   (SP+1),(SP)←FR

   SP←SP-2

   (SP+1),(SP)←CS

   SP←SP-2

   (SP+1),(SP)←IP

   IP←(TYPE×4)

   CS←(TYPE×4+2)

其中,TYPE為中斷類型號,可以是常數或常數表達式,其值必須在0~255范圍內。

(2)INTO(interrupt on overflow):溢出中斷指令

格式:INTO

操作:若OF=1,則

   SP←SP-2

   (SP+1),(SP)←FR

   SP←SP-2

   (SP+1),(SP)←CS

   SP←SP-2

   (SP+1),(SP)←IP

   IP←(0010H)

   CS←(0012H)

當OF=0時,則溢出中斷指令執行空操作。

(3)IRET(interrupt return):中斷返回指令

格式:IRET

操作:IP←(SP+1),(SP)

   SP←SP+2

   CS←(SP+1),(SP)

   SP←SP+2

   FR←(SP+1),(SP)

   SP←SP+2

3.3.6 處理器控制類指令

處理器控制類指令只能完成對CPU的簡單控制功能,共有12條指令,見表3.10。

表3.10 處理器控制類指令

注:·表示運算結果不影響標志位。

1.對標志位進行操作的指令

(1)對CF標志位進行操作的指令

(2)對DF標志位進行操作的指令

(3)對IF標志位進行操作的指令

2.同步控制指令

同步控制指令有三條,它們的操作均不影響標志位。

(1)WAIT(puts processor in wait state):等待指令

WAIT指令可使處理器處于空轉操作狀態,也可用來等待外部中斷發生,但中斷結束后仍返回WAIT指令繼續等待。

(2)ESC(escape):外部操作碼,源操作數交權指令

其中,外部操作碼是一個由程序員規定的6位立即數,源操作數為存儲器操作數。這條指令主要用于與協處理器配合工作。當CPU讀取ESC指令后,利用6位外部操作碼來控制協處理器,使它完成某種指定的操作,而協處理器則可以從CPU的程序中取得一條指令或一個存儲器操作數。這相當于在CPU執行ESC指令時,取出源操作數交給協處理器。

(3)LOCK(lock system bus prefix):封鎖總線指令

LOCK不是一條獨立的指令,常作為指令的前綴位于任何指令的前端。凡帶有LOCK前綴的指令,在該指令執行過程中,都禁止其他協處理器占用總線,故將它稱為總線鎖定前綴。

3.其他控制指令

其他控制指令,它們的操作不影響標志位。

(1)HLT(halt):暫停指令

HLT指令迫使CPU暫停執行程序,只有當下面三種情況之一發生時,CPU才退出暫停狀態:① 在CPU的復位輸入端RESET線上有有效的復位信號;② 非屏蔽中斷請求NMI端出現請求信號;③ 可屏蔽中斷輸入端INTR線上出現請求信號,且中斷允許標志位IF=1,CPU允許中斷。

(2)NOP(no operation):空操作指令

NOP指令并不使CPU完成任何有效操作,只是每執行一次該指令需要占用三個時鐘周期的時間,常用于延時或在調試時用于取代其他指令。

林深時見鹿 你追我趕 騙局 我的女友是喪尸 仙尊歸來(莫海謝雨桐) 沈非晚傅時筵 無愛言婚 幾度夕陽紅 最強打工人 亂三國之呂布

本站所有小說均由搜索引擎轉碼而來,只為讓更多讀者欣賞,本站不保存小說內容及數據,僅作宣傳展示。

Copyright © 2024 噠噠看書網sitemap