汇编语言8086笔记
學(xué)到的知識(shí),很大的一部分會(huì)被忘卻,而被忘記的知識(shí)的影子卻保護(hù)你避免陷入很多的錯(cuò)覺。——伊頓公學(xué)校長威廉·考利
為什么要學(xué)習(xí)匯編語言?
匯編語言是很多相關(guān)課程的重要基礎(chǔ),比如:操作系統(tǒng)、接口技術(shù)等。它是底層編程語言,是計(jì)算機(jī)系統(tǒng)提供給用戶最快最有效的語言,也是能對硬件直接編程的語言。因此,對空間和時(shí)間要求很高的程序,或需要直接控制硬件的程序,必須使用匯編語言進(jìn)行程序設(shè)計(jì)。
- 程序員是個(gè)大江湖之我來自編譯門
匯編語言的特點(diǎn)
匯編語言的主要應(yīng)用場合
學(xué)習(xí)資源
BCD碼
BCD碼(Binary Coded Decimal)是一種二-十進(jìn)制的編碼,它使用4位二進(jìn)制數(shù)表示一位十進(jìn)制數(shù)。最常用的BCD碼是8421碼,又叫NBCD碼(Natural Binary Coded Decimal Code),由于4位二進(jìn)制數(shù)可表示16種狀態(tài),只取前10種狀態(tài)0000-1001來表示十進(jìn)制數(shù)碼0-9,從左到右每位二進(jìn)制數(shù)的權(quán)分別是8、4、2、1,因此又叫8421碼。
例如:十進(jìn)制數(shù)1258對應(yīng)的BCD碼是0001001001011000;
反之,BCD碼1001 1000 0111 0010對應(yīng)的十進(jìn)制數(shù)是9872。
壓縮BCD碼:用一個(gè)字節(jié)表達(dá)兩位BCD碼,比如 0100 1001表示49。
非壓縮BCD碼:將8位二進(jìn)制的高4位設(shè)置為0,僅用低4位表達(dá)一位BCD碼。比如00000100 00001001表示49。
80x86微處理器
80X86是美國Intel公司生產(chǎn)的微處理器系列。
微處理器:把運(yùn)算器和控制器集成在一個(gè)芯片上,構(gòu)成的中央處理器(CPU)。
微機(jī):即微計(jì)算機(jī)系統(tǒng),由微處理器配上存儲(chǔ)器、輸入輸出設(shè)備和系統(tǒng)軟件等構(gòu)成。各硬件用系統(tǒng)總線連接在一起。
系統(tǒng)總線包括數(shù)據(jù)總線(DB)、地址總線(AB)和控制總線(CB)三組。
基于微處理器的計(jì)算機(jī)系統(tǒng)構(gòu)成
數(shù)據(jù)總線寬度
數(shù)據(jù)總線寬度16位:決定了數(shù)據(jù)的傳輸速率。
機(jī)器字長16位
機(jī)器字長為16位:可表示數(shù)的范圍為0000~FFFFH(2^16 = 64K)
地址總線寬度
地址總線寬度為20位:尋址空間為2^20 = 1024KB = 1MB。
8086總線的工作周期
計(jì)算機(jī)是在時(shí)鐘控制下進(jìn)行工作的,若干個(gè)時(shí)鐘完成一個(gè)基本操作,一個(gè)基本操作就是一個(gè)總線周期,CPU有若干種典型操作,構(gòu)成相應(yīng)的總線周期。如存儲(chǔ)器的讀寫總線周期,I/O讀寫總線周期等。
執(zhí)行一條指令的時(shí)間稱為指令周期,指令周期是由若干總線周期構(gòu)成。
8086/8088的基本總線周期是由4個(gè)時(shí)鐘周期組成,在執(zhí)行WAIT指令或READY引腳輸入的狀態(tài)為低電平時(shí),都需要在T3和T4之間插入1個(gè)或若干個(gè)等待時(shí)鐘周期Tw。
T1狀態(tài)
CPU向多路復(fù)用總線上發(fā)送地址信息,指出要尋址的內(nèi)存單元地址或I/O端口地址。這期間CPU還要ALE(正向脈沖),在ALE下降沿將內(nèi)存單元地址或I/O端口地址打入地址鎖存器。
T2狀態(tài)
CPU從總線上撤銷有效地址,使地址總線低16位呈高阻狀態(tài),為數(shù)據(jù)傳輸做準(zhǔn)備。總線的高4位(A19~A16)輸出總線周期的狀態(tài)信息,用于表示中斷允許狀態(tài)及正在使用的段寄存器名。
T3狀態(tài)
A19~A16上的狀態(tài)信息不變,地址總線低16位上出現(xiàn)CPU要寫出的或準(zhǔn)備讀入的數(shù)據(jù)。若外設(shè)與內(nèi)存來不及與總線交換數(shù)據(jù),則應(yīng)通過CPU的READY信號,在T3前沿(下降沿)之前向CPU申請插入等待狀態(tài)TW,在T3及TW前沿查詢READY信號,查到高電平則結(jié)束等待狀態(tài),進(jìn)入下一狀態(tài)。否則繼續(xù)插入等待。
T4狀態(tài)之總線周期結(jié)束
在一個(gè)總線周期之后,若不立即進(jìn)入下一個(gè)總線周期,即CPU不與內(nèi)存或外設(shè)交換數(shù)據(jù)或者指令隊(duì)列已滿,系統(tǒng)總線處于空閑狀態(tài),CPU執(zhí)行總線空閑周期,總線空閑周期一般由一個(gè)或多個(gè)時(shí)鐘周期組成。
中央處理器
CPU包含了三個(gè)部分:算術(shù)邏輯、控制邏輯、寄存器組。
總線接口部件BIU (Bus Interface Unit)
內(nèi)部設(shè)有四個(gè)段地址寄存器,一個(gè)指令指針寄存器IP,一個(gè)6字節(jié)指令隊(duì)列緩沖器,20位地址加法器和總線控制電路。
主要功能:根據(jù)執(zhí)行部件EU的請求,負(fù)責(zé)從內(nèi)存單元中預(yù)取指令,并將它們送到指令隊(duì)列緩沖器暫存。即負(fù)責(zé)完成CPU與存儲(chǔ)器或I/O設(shè)備之間的數(shù)據(jù)傳送。
執(zhí)行部件EU(Execution Unit)
執(zhí)行部件中包含算術(shù)邏輯單元(ALU)、通用寄存器、狀態(tài)標(biāo)志寄存器、數(shù)據(jù)暫存寄存器和執(zhí)行部件的控制電路。
主要功能:從BIU的指令隊(duì)列中取出指令代碼,經(jīng)指令譯碼器譯碼后執(zhí)行指令所規(guī)定的全部功能。執(zhí)行指令所得結(jié)果或執(zhí)行指令所需的數(shù)據(jù),都由EU向BIU發(fā)出命令,對存儲(chǔ)器或I/O接口進(jìn)行讀/寫操作。
寄存器組
數(shù)據(jù)寄存器
| AX | Accumulator | 累加寄存器,常用于運(yùn)算;在乘除等指令中指定用來存放操作數(shù),另外,所有的I/O指令都使用這一寄存器與外界設(shè)備傳送數(shù)據(jù)。 |
| BX | Base | 基址寄存器,常用于存放存儲(chǔ)單元地址。 計(jì)算地址的時(shí)候用作基地址寄存器,用于擴(kuò)展尋址,起變址的作用。 |
| CX | Count | 計(jì)數(shù)寄存器,一般作為循環(huán)或串操作等指令中的隱含計(jì)數(shù)器;常用于保存計(jì)算值,如在移位指令,循環(huán)(loop)和串處理指令中用作隱含的計(jì)數(shù)器。 |
| DX | Count | 數(shù)據(jù)寄存器,常用來存放雙字?jǐn)?shù)據(jù)的高16位,或存放外設(shè)端口地址,比如雙字的乘除法。 存放操作數(shù)和列表數(shù)據(jù),在某些I/O操作期間,用來,在乘除運(yùn)算中有專用。 |
共同特點(diǎn):
這四個(gè)十六位的寄存器可以分為:
- 高8位:AH,BH, CH,DH;
- 低8位:AL,BL,CL,DL。
- 這兩組八位寄存器可以分別尋址,并單獨(dú)使用。
指針寄存器
| SP | Stack Pointer | 堆棧指針寄存器。與SS(堆棧段寄存器)配合使用來確定堆棧段棧頂?shù)奈恢?#xff0c;也就是說SP用于存放棧頂?shù)钠频刂贰?/td> |
| BP | Base Pointer | 基址指針寄存器,可用作SS的一個(gè)相對基址位置(用于存放堆棧段中某一存儲(chǔ)單元的偏移地址。) |
說明:指針寄存器和變址寄存器只能按16位進(jìn)行存取操作,主要用來形成操作數(shù)的地址,用于堆棧操作和變址運(yùn)算中計(jì)算操作數(shù)的有效地址。
變址寄存器
| SI | Source Index | 源變址寄存器可用來存放相對于DS段之源變址指針,也就是說,源操作數(shù)偏址存放在SI中。 |
| DI | Destination Index | 目的變址寄存器,可用來存放相對于 ES段的目的變址指針,也就是說,目的操作數(shù)偏址存放在DI中。 |
說明:
SI和DI一般與數(shù)據(jù)段寄存器DS聯(lián)合使用,用來確定數(shù)據(jù)段中某一存儲(chǔ)單元的地址。這兩個(gè)變址寄存器有自動(dòng)增量和自動(dòng)減量的功能,所以用來變址是十分方便的。
在串處理中,SI和DI作為隱含的源變址和目的變址寄存器,此時(shí)SI和DI聯(lián)用,DI和附加段寄存器ES聯(lián)用,分別達(dá)到了在數(shù)據(jù)段和附加段尋址的目的。
指針寄存器和變址寄存器只能按16位進(jìn)行存取操作,主要用來形成操作數(shù)的地址,用于堆棧操作和變址運(yùn)算中計(jì)算操作數(shù)的有效地址。
指令指針I(yè)P(Instruction Pointer)
指令指針I(yè)P是一個(gè)16位專用寄存器(指令指針寄存器),它指向當(dāng)前需要取出的指令字節(jié),當(dāng)BIU從內(nèi)存中取出一個(gè)指令字節(jié)后,IP就自動(dòng)加上指令長度的值,指向下一個(gè)指令字節(jié)。
注意:IP指向的是指令地址的段內(nèi)地址偏移量,又稱偏移地址(Offset Address)或有效地址(EA,Effective Address),程序不能直接訪問IP。
任意時(shí)刻,CPU將CS:IP指向的內(nèi)存單元中的內(nèi)容看作指令。
標(biāo)志寄存器FR(Flag Register)
8086有一個(gè)18位的標(biāo)志寄存器FR,在FR中有意義的有9位,其中6位是狀態(tài)位,3位是控制位。
標(biāo)志寄存器FR:
條件標(biāo)志
狀態(tài)信息是由中央處理機(jī)根據(jù)計(jì)算結(jié)果自動(dòng)設(shè)置的。
| OF | 溢出標(biāo)志位OF(overflow flag)用于反映有符號數(shù)加減運(yùn)算所得結(jié)果是否溢出。 如果運(yùn)算結(jié)果超過當(dāng)前運(yùn)算位數(shù)所能表示的范圍,則稱為溢出。溢出時(shí)OF=1,否則OF= 0。 注意,這里所講的溢出,只是對有符號數(shù)運(yùn)算而言,對無符號數(shù)沒有意義。 |
| SF | 符號標(biāo)志SF(sign flag)用來反映運(yùn)算結(jié)果的符號位,它與運(yùn)算結(jié)果的最高位相同。在微機(jī)系統(tǒng)中,有符號數(shù)采用補(bǔ)碼表示法,所以,SF也就反映運(yùn)算結(jié)果的正負(fù)號。正數(shù)SF=0,負(fù)數(shù)SF為1。 注意:SF是對有符號數(shù)運(yùn)算有意義的標(biāo)志位。 |
| ZF | 零標(biāo)志ZF(zero flag)用來反映運(yùn)算結(jié)果是否為0。如果運(yùn)算結(jié)果為0,則其值為1,否則其值為0。在判斷運(yùn)算結(jié)果是否為0時(shí),可使用此標(biāo)志位。 |
| AF | 輔助進(jìn)位標(biāo)志AF(auxiliary flag)記錄運(yùn)算時(shí)第3位(字節(jié)運(yùn)算)或第7位(字運(yùn)算)產(chǎn)生的進(jìn)位或借位值。例如,執(zhí)行加法指令時(shí)第3位有進(jìn)位時(shí)AF=1,否則AF=0。 |
| PF | 奇偶標(biāo)志PF(parity flag)用于反映運(yùn)算結(jié)果中“1”的個(gè)數(shù)的奇偶性。當(dāng)結(jié)果操作數(shù)中1的個(gè)數(shù)為偶數(shù)時(shí)PF=l,否則PF=0。 |
| CF | 進(jìn)位標(biāo)志CF(carry flag)主要用來反映運(yùn)算是否產(chǎn)生進(jìn)位或借位。當(dāng)最高有效位有進(jìn)位或借位時(shí)CF=1,否則置CF=0。 注意:CF是對無符號數(shù)運(yùn)算有意義的標(biāo)志位 |
無符號數(shù)比較示例:
控制標(biāo)志
控制標(biāo)志是系統(tǒng)程序或用戶程序根據(jù)需要用指令設(shè)置的。
| DF | 方向標(biāo)志DF(direction flag)位用來決定在串操作指令執(zhí)行時(shí)有關(guān)指針寄存器發(fā)生調(diào)整的方向。當(dāng)DF位為1時(shí),每次操作后使變址寄存器SI和DI減量;當(dāng)DF為0時(shí),則使SI和DI增量。 |
| IF | 中斷允許標(biāo)志IF(interrupt flag)位用來決定CPU是否響應(yīng)CPU外部的可屏蔽中斷發(fā)出的中斷請求。但不管該標(biāo)志為何值,CPU都必須響應(yīng)CPU外部的不可屏蔽中斷所發(fā)出的中斷請求,以及CPU內(nèi)部產(chǎn)生的中斷請求。具體規(guī)定如下: (1)當(dāng)IF=1時(shí),CPU可以響應(yīng)CPU外部的可屏蔽中斷發(fā)出的中斷請求; (2)當(dāng)IF=0時(shí),CPU不響應(yīng)CPU外部的可屏蔽中斷發(fā)出的中斷請求。 總的來說:IF為1時(shí),開中斷,否則關(guān)中斷。 |
| TF | 跟蹤標(biāo)志TF(trap flag), 也叫做陷阱標(biāo)志。該標(biāo)志可用于程序調(diào)試。TF標(biāo)志沒有專門的指令來設(shè)置或清楚。 (1)如果TF=1,則CPU處于單步執(zhí)行指令的工作方式,此時(shí)每執(zhí)行完一條指令,就顯示CPU內(nèi)各個(gè)寄存器的當(dāng)前值及CPU將要執(zhí)行的下一條指令。 (2)如果TF=0,則處于連續(xù)工作模式。 總的來說:TF=1時(shí),每條指令執(zhí)行完后產(chǎn)生陷井,TF=0時(shí),CPU正常工作不產(chǎn)生陷井。 |
Debug中標(biāo)志位的符號表示
| OF | OV | NV |
| DF | DN | UP |
| IF | EI | DI |
| SF | NG | PL |
| ZF | ZR | NZ |
| AF | AC | NA |
| PF | PE | PO |
| CF | CY | NC |
標(biāo)志寄存器FLAGS
這是一個(gè)存放條件碼標(biāo)志、控制標(biāo)志和系統(tǒng)標(biāo)志的寄存器。
段寄存器(Segment Register)
為了運(yùn)用所有的內(nèi)存空間,8086設(shè)定了四個(gè)段寄存器,專門用來保存段地址:
| CS(Code Segment) | 代碼段寄存器 | 代碼段存放當(dāng)前正在運(yùn)行的程序 |
| DS(Data Segment) | 數(shù)據(jù)段寄存器 | 數(shù)據(jù)段存放當(dāng)前正在運(yùn)行程序所有的數(shù)據(jù),如果程序使用了串處理指令,則其操作數(shù)也會(huì)存放在數(shù)據(jù)段中。 處理串的時(shí)候,DS默認(rèn)為源串。 |
| SS(Stack Segment) | 堆棧段寄存器 | 定義了堆棧所在的區(qū)域。 |
| ES(Extra Segment) | 附加段寄存器 | 這是一個(gè)輔助的數(shù)據(jù)區(qū),也是串處理指令的目的操作數(shù)存放區(qū)。 處理串的時(shí)候,ES默認(rèn)為目的串。 |
附錄
- 寄存器介紹
存儲(chǔ)器
存儲(chǔ)器是計(jì)算機(jī)的記憶部件,用來存放程序和數(shù)據(jù)。按所在的位置,存儲(chǔ)器可以分成主存儲(chǔ)器和輔助存儲(chǔ)器。
主存儲(chǔ)器存放當(dāng)前正在執(zhí)行的程序和使用的數(shù)據(jù),CPU可以直接存取,它由半導(dǎo)體存儲(chǔ)器芯片構(gòu)成,其成本高,容量小,但速度快。
輔助存儲(chǔ)器可用來長期保存大量程序和數(shù)據(jù),CPU需要通過I/O接口訪問,它由磁盤或光盤構(gòu)成,其成本低,容量大,但速度較慢。
存儲(chǔ)單元
存儲(chǔ)器被劃分為若干個(gè)存儲(chǔ)單元,每個(gè)存儲(chǔ)單元有一個(gè)惟一的存儲(chǔ)器地址,從0開始順序編號,存儲(chǔ)單元的地址是無符號數(shù), n位二進(jìn)制數(shù)共能表示2^n個(gè)存儲(chǔ)單元的地址。
類型
| DB | define byte | 定義字節(jié)類型變量,一個(gè)字節(jié)數(shù)據(jù)占1個(gè)字節(jié)單元,讀完一個(gè),偏移量加1 |
| BW | define word | 定義字類型變量,一個(gè)字?jǐn)?shù)據(jù)占2個(gè)字節(jié)單元,讀完一個(gè),偏移量加2 |
| DD | define double(word) | 定義雙字類型變量,一個(gè)雙字?jǐn)?shù)據(jù)占4個(gè)字節(jié)單元,讀完一個(gè),偏移量加4 |
字地址
字地址:一個(gè)字存放到存儲(chǔ)器要占用連續(xù)的兩個(gè)字節(jié)單元。字的低字節(jié)(低8位)存放在低地址中,高字節(jié)(高8位)存放在高地址中,字單元的地址用低地址表示。
例如:34560H的字單元的內(nèi)容是1234H,而地址為78780H時(shí)字單元的內(nèi)容是3332H。記作:
- (34560H)=1234H
(78780H)= 3332H
同一個(gè)地址既可以看成字節(jié)單元,也可以看作是字單元、雙字單元、或者是4字單元的地址,這要根據(jù)使用情況而定。字單元地址可以是偶數(shù),也可以是奇數(shù)。但是,在8086和80286中,訪問存儲(chǔ)器(要求取數(shù)或者存數(shù))都是以字為單元進(jìn)行的,也就是說,機(jī)器是以偶地址訪問存儲(chǔ)器的。這樣,對于奇地址的字單元,要取一個(gè)字需要訪問二次存儲(chǔ)器,當(dāng)然,這樣做需要花費(fèi)較多的時(shí)間。
存儲(chǔ)器有這樣一個(gè)特性:它的內(nèi)容取之不盡的。也就是說,從某個(gè)單元取出其內(nèi)容后,該單元仍然保持著原來的內(nèi)容不變,可以重復(fù)取出,只有存入新的信息后,原來保存的內(nèi)容就自動(dòng)丟失了。
各類存儲(chǔ)器芯片
從讀寫屬性上看分為兩類:
- 隨機(jī)存儲(chǔ)器(RAM)和只讀存儲(chǔ)器(ROM)
- 從功能和連接上分類:
- 隨機(jī)存儲(chǔ)器RAM
- 裝有BIOS的ROM
- 接口卡上的RAM
所有的物理存儲(chǔ)器被看作一個(gè)由若干存儲(chǔ)單元組成的邏輯存儲(chǔ)器;每個(gè)物理存儲(chǔ)器在這個(gè)邏輯存儲(chǔ)器中占有一個(gè)地址段,即一段地址空間;CPU在這段地址空間中讀寫數(shù)據(jù),實(shí)際上就是在相對應(yīng)的物理存儲(chǔ)器中讀寫數(shù)據(jù)。
寄存器與存儲(chǔ)器的比較
實(shí)模式存儲(chǔ)器尋址
8086CPU的地址線是20位的,這樣最大可尋址空間應(yīng)為220=1MB,其物理地址范圍從00000H~FFFFFH。
而8086CPU寄存器都是16位的,僅能表示地址范圍 0000H ~ FFFFH(64KB) 。那么,這1MB(2^20)空間如何用16位寄存器表達(dá)呢?
根據(jù)要求可把1M字節(jié)地址空間劃成若干邏輯段。每個(gè)邏輯段必須滿足兩個(gè)條件:
(1)邏輯段的起始地址(簡稱段首址)必須是16的倍數(shù);
(2)邏輯段的最大長度為64K(2^6)。
按照這兩個(gè)條件,1M字節(jié)地址空間最多可劃分成64K個(gè)邏輯段,最少也要?jiǎng)澐殖?6個(gè)邏輯段。邏輯段與邏輯段可以相連,也可以不連,還可以重疊。
邏輯地址(LA)和物理地址(PA)
物理地址
就是存儲(chǔ)器的實(shí)際地址,它是指CPU和存儲(chǔ)器進(jìn)行數(shù)據(jù)交換時(shí)所使用的地址(20位)。
邏輯地址
是在程序中使用的地址(16位) ,它由段地址和偏移地址兩部分組成。邏輯地址的表示形式為“段地址∶偏移地址”。
- 段地址:是指邏輯段在主存中的起始位置。
- 段內(nèi)偏移地址:是指主存單元距離段首址的偏移量,簡稱偏移地址,用EA來表示,由于限定每段不超過64KB,所以偏移地址可以用16位數(shù)據(jù)表示。
- 物理地址形成:物理地址用PA表示, 將邏輯地址中的段地址左移4位,加上偏移地址就得到20位物理地址。
- 物理地址 = 段地址 x 16 + 偏移地址
段的概念
錯(cuò)誤認(rèn)識(shí):
內(nèi)存被劃分成了一個(gè)一個(gè)的段,每一個(gè)段有一個(gè)段地址。
正確認(rèn)識(shí):
內(nèi)存并沒有分段,段的劃分來自于CPU,由于8086CPU用“(段地址×16)+偏移地址=物理地址”的方式給出內(nèi)存單元的物理地址,使得我們可以用分段的方式來管理內(nèi)存。
8086PC工作過程的簡要描述
- 1)從CS:IP指向內(nèi)存單元讀取指令,讀取的指令進(jìn)入指令緩沖器;
- 2)IP = IP + 所讀取指令的長度,從而指向下一條指令;
- 3)執(zhí)行指令。 轉(zhuǎn)到步驟 (1),重復(fù)這個(gè)過程。
- 在 8086CPU 加電啟動(dòng)或復(fù)位后( 即 CPU剛開始工作時(shí))CS和IP被設(shè)置為CS=FFFFH,IP=0000H,即在8086PC機(jī)剛啟動(dòng)時(shí),CPU從內(nèi)存FFFF0H單元中讀取指令執(zhí)行,FFFF0H單元中的指令是8086PC機(jī)開機(jī)后執(zhí)行的第一條指令。
匯編指令
指令格式
- ASMARM的專欄 - 淺談ARM 匯編中的標(biāo)號(Labels)
1、雙操作數(shù)指令(二地址指令)
- 格式:[標(biāo)號:] 操作符 DST,SRC [;注釋]
- 操作規(guī)定:
- 1)DST與SRC應(yīng)為同種操作類型且類型明確,即同為字節(jié)類型或字類型。
- 2)DST不能是立即數(shù)。
- 3)SRC和DST不能同時(shí)為存儲(chǔ)器操作數(shù)(mem) 。
- 4)操作結(jié)束后,運(yùn)算結(jié)果存入DST中,SRC內(nèi)容不變。
- 例如:
2、單操作數(shù)指令(一地址指令)
- 格式:[標(biāo)號:] 操作符 DST [;注釋]
- 操作規(guī)定:
- 1)DST類型必須明確即為字節(jié)類型或字類型,不能是模糊類型
- 2)操作對象為目的操作數(shù),操作結(jié)束后結(jié)果存入DST中
- 3)DST不能是立即數(shù),只能是寄存器操作數(shù)(reg) 或存儲(chǔ)器操作數(shù)(mem)。
3、無操作數(shù)指令(零地址指令)
- 格式:[標(biāo)號:] 操作符 [;注釋]
- 操作規(guī)定:指令中只有操作碼,不含操作數(shù),這種指令有兩種可能:
- 1)無需任何操作數(shù)。如停機(jī)指令(HLT)、空操作指令(NOP)等。
- 2)所需操作數(shù)是隱含指定的,操作時(shí)取固定操作數(shù)進(jìn)行操作。如進(jìn)位位置0(CLC)、方向標(biāo)志置0(CLD)。
尋址方式
定義:尋址方式是指尋找指令中操作數(shù)所在地址的方法。
常用的尋址方式有:立即尋址、直接尋址、寄存器尋址、寄存器間接尋址、變址尋址、基址加變址、隱含尋址等。
尋找指令中所需要操作數(shù)存放地址的方式或者程序轉(zhuǎn)移時(shí)尋找轉(zhuǎn)移地址的方式稱為尋址方式,因而尋址方式有兩大類:一類是數(shù)據(jù)尋址方式,另一類是轉(zhuǎn)移地址尋址方式。
由于80x86指令涉及四種操作數(shù):立即操作數(shù)(data)、寄存器操作數(shù)(reg)、存儲(chǔ)器操作數(shù)(mem)和隱含操作數(shù),因此,數(shù)據(jù)尋址方式又可對應(yīng)四種尋址方式,即:立即尋址、寄存器尋址、存儲(chǔ)器尋址和固定尋址。
數(shù)據(jù)尋址方式-立即尋址
操作數(shù)直接包含在指令中,它緊跟在指令操作碼后面,它作為指令存放在存儲(chǔ)器代碼段中,這種操作數(shù)稱為立即數(shù)。立即數(shù)可以是8位,也可以是16位。
MOV AX,1234H ;(AX)=1234H立即尋址方式用來表示常數(shù),它常用于給寄存器或內(nèi)存單元賦初值。需要強(qiáng)調(diào)的是,立即尋址只能用于源操作數(shù),不能用于目的操作數(shù),且源操作數(shù)的長度應(yīng)該與目的操作數(shù)的長度一致。
立即數(shù)可以為8位,也可以是16位;規(guī)定立即數(shù)只能是整數(shù),不能是小數(shù)、變量或者其他類型的數(shù)據(jù)。
數(shù)據(jù)尋址方式-寄存器尋址
操作數(shù)直接存放在由指令指明的寄存器中。在匯編指令中直接書寫寄存器名,16位寄存器操作數(shù)可以是AX、BX、CX、DX、SI、DI、BP、SP、DS、ES、SS、CS等;8位寄存器操作數(shù)只能是AH、AL、BH、BL、CH、CL、DH、DL。
指令指針寄存器IP和標(biāo)志寄存器FLAGS一般不直接出現(xiàn)在程序中。
此尋址方式由于存取操作數(shù)直接從CPU內(nèi)部寄存器中獲得,不需訪問存儲(chǔ)器,因而指令執(zhí)行的速度快。
寄存器尋址既可用于源操作數(shù),又可用于目的操作數(shù),應(yīng)用頻率最高。
注意:CS不能作為目的操作數(shù),因?yàn)镃S:IP控制著程序指令序列的執(zhí)行順序,不能在程序中由指令隨意改變。
數(shù)據(jù)尋址方式-存儲(chǔ)器尋址
存儲(chǔ)器尋址方式的操作數(shù)都是存放在除代碼段以外的存儲(chǔ)區(qū)中,一般是數(shù)據(jù)段、附加段、堆棧段中的存儲(chǔ)單元。指令中給出的是存儲(chǔ)單元的地址或產(chǎn)生存儲(chǔ)單元地址的表達(dá)式。
在匯編語言源程序中,存儲(chǔ)單元地址是采用邏輯地址的形式表示的,即:段首址:段內(nèi)偏移地址。段首址存放在某個(gè)段寄存器中,段內(nèi)偏移地址即有效地址EA是由3個(gè)地址分量的某種組合求得,這3個(gè)地址分量是:位移量、基址(BX,BP)、變址(SI,DI) 。
這3個(gè)地址分量的不同組合,使形成有效地址EA的方法不同,相應(yīng)有以下5種不同的存儲(chǔ)器操作數(shù)尋址方式:直接尋址、寄存器間接尋址、寄存器相對尋址、基址變址尋址、相對基址變址尋址。
直接尋址方式
直接尋址是最簡單的存儲(chǔ)器尋址,操作數(shù)的有效地址EA由指令直接給出,只包含位移量。它主要用于存取簡單變量。
MOV AX, [2000H] EA=2000H, 假設(shè)(DS)=3000H, 那么PA=32000H
對使用直接尋址方式需說明以下幾點(diǎn):
- 操作數(shù)默認(rèn)隱含的段為數(shù)據(jù)段 DS。
- 若操作數(shù)在代碼段、堆棧段或附加段中,可使用段跨越前綴 。MOV AX, ES: [2000H]
- 指令中操作數(shù)的EA既可以是一個(gè)數(shù)字地址,也可以是一個(gè)符號地址。當(dāng)EA是一個(gè)數(shù)字時(shí),一定要注意立即尋址方式與直接尋址方式的區(qū)別,直接尋址必須有[ ]符號。
- 操作數(shù)地址可由變量(符號地址)表示, 但要注意變量的屬性。
直接尋址方式適合于處理存儲(chǔ)器的單個(gè)存儲(chǔ)單元。例如,要處理某個(gè)存放在存儲(chǔ)器里面的變量,可以使用直接尋址方式把變量先取到一個(gè)寄存器中,然后在進(jìn)一步處理。
80x86中,為了使指令字不要太長,規(guī)定雙操作數(shù)指令的兩個(gè)操作數(shù)中,只能有一個(gè)使用存儲(chǔ)器尋址方式,這就是一個(gè)變量常常先要送到寄存器的原因了。
寄存器間接尋址
操作數(shù)的有效地址只包含基址寄存器或者變址寄存器內(nèi)容的一種成分。因此,有效地址就在某個(gè)寄存器中,而操作數(shù)則在存儲(chǔ)器中。
操作數(shù)的有效地址EA存放在SI、DI、BX或BP之一中,而操作數(shù)在存儲(chǔ)器中。若用BX、SI或DI間接尋址時(shí),則操作數(shù)默認(rèn)在數(shù)據(jù)段中,用DS的內(nèi)容作為段首址,操作數(shù)的物理地址為:
若指令中使用BP間接尋址時(shí),則用堆棧段SS的內(nèi)容作為段首址,操作數(shù)的物理地址為: PA=(SS)×16 +(BP)。
注意:
- 8086不允許使用AX、CX、DX 來存放 EA,比如:MOV AX, [CX]就是錯(cuò)誤的。
- SRC 和 DST 的字長一致,自動(dòng)適應(yīng)寄存器的長度。
- 適用于數(shù)組、字符串、表格的處理(可以看成一個(gè)數(shù)組來使用),執(zhí)行完一條指令后,只需修改寄存器內(nèi)容就可以取出下一項(xiàng)處理。
寄存器相對尋址方式
寄存器相對尋址方式也可以稱為直接變址尋址方式。
操作數(shù)的有效地址EA是指令中指定的基址寄存器或變址寄存器的內(nèi)容與指令中給出的位移量之和,即
操作數(shù)的物理地址為:
若操作數(shù)不在默認(rèn)段中,則應(yīng)使用段跨越前綴明確指定。
- 適于數(shù)組、字符串、表格的處理。
基址變址尋址
操作數(shù)的有效地址EA是指令中的基址寄存器的內(nèi)容+變址寄存器的內(nèi)容。
指令格式:
- 適于數(shù)組、字符串、表格的處理
- 必須是一個(gè)基址寄存器和一個(gè)變址寄存器的組合
相對基址變址尋址
操作數(shù)的有效地址EA是指令中的基址寄存器的內(nèi)容、變址寄存器的內(nèi)容、位移量三個(gè)地址分量之和,即:
相對基址加變址尋址方式有多種等價(jià)的書寫方式,書寫格式:[BX+SI+1000H]、1000H[BX+SI]、1000H[BX][SI]和1000H[SI][BX]等格式都是正確的,并且其尋址含義也是一致的,但格式:BX[1000H+SI]、SI[1000H+BX]等是錯(cuò)誤的,即所用寄存器不能在”[“,”]”之外,該限制對寄存器相對尋址方式的書寫也同樣起作用。
這種尋址方式通常用于對二維數(shù)組的尋址。例如,存儲(chǔ)器中存放著由多個(gè)記錄組成的文件,則位移量可指向文件之首,基址寄存器指向某個(gè)記錄,變址寄存器則指向該記錄中的一個(gè)元素。這種尋址方式也為堆棧處理提供了方便,一般(BP)可指向棧頂,從棧頂?shù)綌?shù)組的首地址可以使用位移量來表示,變址寄存器可以用來訪問數(shù)組中的某個(gè)元素。
附錄
可以出現(xiàn)在[]中的內(nèi)容是有限制的,他們必須是下列中的一個(gè)(其中idata表示一個(gè)立即數(shù)):
idata BX BP SI DI BX+SI BX+DI BP+SI BP+DI BX+idata BP+idata SI+idata DI+idata BX+SI+idata BX+DI+idata BP+SI+idata BP+DI+idata其中,使用到BP的默認(rèn)段寄存器為SS,其他未DS
段寄存器的使用規(guī)定
匯編語言源程序
- 匯編源程序:由三部分組成:匯編指令、偽指令、其他標(biāo)號與符號。
- 指令是能被計(jì)算機(jī)識(shí)別并執(zhí)行的二進(jìn)制代碼,它規(guī)定了計(jì)算機(jī)能完成的某一操作。
- 偽指令是對匯編起某種控制作用的特殊命令,其格式與通常的操作指令一樣,并加在匯編程序的任何地方,但是他們并不產(chǎn)生機(jī)器指令。
- 一個(gè)匯編源程序是由多個(gè)段組成的,這些段被用來存放代碼、數(shù)據(jù)或當(dāng)作棧空間來使用。
- 注意:一個(gè)有意義的匯編程序中至少要有一個(gè)段,這個(gè)段用來存放代碼。
處理器選擇偽操作
| .8086 | 選擇8086指令系統(tǒng) |
| .286 | 選擇80286指令系統(tǒng) |
| .286 P | 選擇保護(hù)模式下的80286指令系統(tǒng) |
| .386 | 選擇80386指令系統(tǒng) |
| .386 P | 選擇保護(hù)模式下的80386指令系統(tǒng) |
| .486 | 選擇80486指令系統(tǒng) |
| .486 P | 選擇保護(hù)模式下的80486指令系統(tǒng) |
| .586 | 選擇80586指令系統(tǒng) |
| .586 P | 選擇保護(hù)模式下的80586指令系統(tǒng) |
這類偽操作一般都是放在整個(gè)程序的最前面。如果不給出,則匯編程序一般認(rèn)為其默認(rèn)值為.8086。
段定義偽操作
在段定義時(shí),如果定位類型用戶未選擇,就表示是隱含類型,其隱含類型是PARA。
PARA屬定位類型,是對該段起始地址定位。一般,各個(gè)邏輯段的首地址在‘節(jié)’的整數(shù)邊界上(每16個(gè)存儲(chǔ)單元叫做一節(jié)),即每個(gè)邏輯段的起始地址是16的整數(shù)倍。對于PARA—指定定位段的起始地址必須在節(jié)的整數(shù)邊界。
存儲(chǔ)器的物理地址是由段地址和偏移地址組合而成的,匯編程序在把源程序轉(zhuǎn)換為目標(biāo)程序的時(shí)候,必須確定標(biāo)號和變量(代碼段和數(shù)據(jù)段的符號地址)的偏移地址,并且需要把有關(guān)信息通過目標(biāo)模塊傳送給連接程序,以便連接程序把不同的段和模塊連接起來,形成一個(gè)可執(zhí)行的程序。
明確段與寄存器的關(guān)系:assume cs:code, ds:data, es:extra
說明:
- 1)data為段名稱,也是段首地址,可自己定義
- 功能:定義一個(gè)段,segment說明一個(gè)段開始,ends 說明一個(gè)段結(jié)束。一個(gè)段必須有一個(gè)名稱來標(biāo)識(shí),使用格式為:
- 段名 segment
- 段名 ends
- 功能:定義一個(gè)段,segment說明一個(gè)段開始,ends 說明一個(gè)段結(jié)束。一個(gè)段必須有一個(gè)名稱來標(biāo)識(shí),使用格式為:
- 2)明確段和段寄存器的關(guān)系。assume只是說明關(guān)聯(lián)關(guān)系,并沒有對段寄存器賦值,除了CS(裝入程序時(shí)由CPU給出),其他段寄存器要在程序中設(shè)置。
- 3)mov ax,4c00h和int 21h最后兩條指令所實(shí)現(xiàn)的功能是程序返回。
- 4)程序結(jié)束標(biāo)志,格式:END [label],標(biāo)號label 指示程序開始執(zhí)行的起始地址。
偽操作(偽指令)
偽操作是匯編程序?qū)υ闯绦蜻M(jìn)行匯編時(shí)處理的操作,完成處理器選擇、存儲(chǔ)模式定義、數(shù)據(jù)定義、存儲(chǔ)器分配、指示程序開始結(jié)束等功能。
- 處理器選擇偽操作;
- 功能:告訴匯編程序應(yīng)該選擇哪一種指令系統(tǒng)。
位置:一般放在整個(gè)程序的最前面,也可放在程序中所用指令的上一行。
如不給出,則默認(rèn)為.8086。
- 功能:告訴匯編程序應(yīng)該選擇哪一種指令系統(tǒng)。
- 段定義偽操作;
- 程序開始和結(jié)束偽操作;
- Start
- end Start
- 數(shù)據(jù)定義及存儲(chǔ)器分配偽操作;
- 表達(dá)式賦值偽操作;
- 地址計(jì)數(shù)器與對準(zhǔn)偽操作;
- 基數(shù)控制偽操作。
數(shù)據(jù)定義和存儲(chǔ)器分配偽操作
格式:[變量] 助記符 操作數(shù) [ , 操作數(shù) , … ] [ ; 注釋]
- 助記符:DB DW DD DF DQ DT
- 例:操作數(shù)可以是常數(shù)或表達(dá)式
- DATA_BYTE DB 10,4,10H,?
- DATA_WORD DW 100,100H,-5,?
- 匯編程序在匯編期間在存儲(chǔ)器中存入數(shù)據(jù)
- 操作數(shù)也可以是字符串
- 操作數(shù)也可以是地址
- 操作數(shù)字段還可以使用復(fù)制操作符DUP來復(fù)制操作數(shù)
- repeat_count DUP(operand,……,operand)
- repeat_count可以是一個(gè)表達(dá)式,它的值應(yīng)該是一個(gè)正整數(shù),用來指定括號中的操作數(shù)的重復(fù)次數(shù)。
- 操作數(shù)?可以保留存儲(chǔ)空間,但是不存入數(shù)據(jù)。(僅僅申請一個(gè)存儲(chǔ)空間)
- (AX)=3402H (AL)=34H
- 可以看出:同一個(gè)變量可以具有不同的類型屬性。
LABEL 偽操作: name LABEL type
- LABEL可以使同一個(gè)變量具有不同的類型屬性。
其中變量的數(shù)據(jù)類型可以是BYTE,WORD,DWORD,標(biāo)號的代碼類型可以是NEAR或FAR。
數(shù)據(jù)定義及存儲(chǔ)器分配偽指令格式中的 “變量 “是操作數(shù)的符號地址,它是可有可無 的,它的作用與指令語句前的標(biāo)號相同,區(qū)別是變量后面不加冒號。如果語句中有變量,那么匯編程序?qū)⒉僮鲾?shù)的第一個(gè)字節(jié)的偏移地址賦于這個(gè)變量。
表達(dá)式賦值偽操作
說明:有時(shí)程序中多次出現(xiàn)同一個(gè)表達(dá)式,為了方便起見,可以使用賦值偽操作給表達(dá)式賦予一個(gè)名字。、
EQU是賦值偽指令。賦值語句僅在匯編源程序時(shí),作為替代符號用。不產(chǎn)生目標(biāo)代碼,也不占有存儲(chǔ)單元。
此后,程序中凡是用到該表達(dá)式之處,都可以用表達(dá)式名來代替了。可見,EQU的引入提高了程序的可讀性,也使其更加易于修改。
格式:表達(dá)式名 EQU 表達(dá)式
功能:給表達(dá)式賦予一個(gè)名字,在程序中用表達(dá)式名代替該表達(dá)式。
“ = ” 偽操作 (允許重復(fù)定義)
…… EMP = 7 …… EMP = EMP+1 ……說明:EQU指令類似于C語言的#define宏,在編譯前被轉(zhuǎn)化。
地址計(jì)數(shù)器與ORG偽操作
地址計(jì)數(shù)器$
地址計(jì)數(shù)器 $:保存當(dāng)前正在匯編的指令的偏移地址
- $ 用在指令中時(shí),表示本條指令的第一個(gè)字節(jié)的地址;
- $ 用在偽操作的參數(shù)字段時(shí)表示地址計(jì)數(shù)器的當(dāng)前值。
- 例如:ARRAY DW 1, 2 , $+4 , 3 , 4 , $+4
-
- 通過圖片可以看出,地址0078保存的數(shù)據(jù)為當(dāng)前地址加上4;
- 地址007E是當(dāng)前地址加上4。
ORG
ORG 偽操作:用來設(shè)置當(dāng)前地址計(jì)數(shù)器的值。即:指定一個(gè)地址,后面的程序或數(shù)據(jù)從這個(gè)地址值開始分配。
SEG1 SEGMENTORG 10VAR1 DW 1234HORG 20VAR2 DW 5678HORG $+8; 當(dāng)前地址加8,VAR3 DW 1357H SEG1 ENDSEVEN
EVEN偽操作使下一個(gè)變量或者指令開始于偶數(shù)字節(jié)地址。一個(gè)字的地址最好從偶地址開始,所以對于字?jǐn)?shù)組為了保證其從偶地址開始,可以在其前面使用EVEN偽操作來達(dá)到這一目的。
EVEN ;使下一地址從偶地址開始
A DB ‘morning’ EVEN ;使下一地址從偶地址開始 B DW 2 DUP (?)ALIGN
ALIGN偽操作為保證雙字?jǐn)?shù)組邊界從4的倍數(shù)開始創(chuàng)造了條件:
ALIGN 4 ; 保證下一個(gè)地址是4的倍數(shù) ALIGN 2 ; 與EVEN等價(jià)說明:
- ALIGN boundary(boundary的值必須是2的冪)。
基數(shù)控制偽操作
匯編程序默認(rèn)的數(shù)是十進(jìn)制數(shù),因而除非專門指定,匯編程序把程序中出現(xiàn)的數(shù)均看作為十進(jìn)制數(shù)。為此,當(dāng)使用其他基數(shù)的時(shí)候,需要專門給以標(biāo)記:
| 二進(jìn)制 | B |
| 十進(jìn)制 | D |
| 十六進(jìn)制 | H |
| 八進(jìn)制 | O 或者 Q |
匯編語言程序格式
匯編語言源程序中每個(gè)語句可以由四項(xiàng)組成,格式如下:
其中
- 名字(name)項(xiàng)是一個(gè)符號。
- 操作(operation)項(xiàng)是一個(gè)操作碼的助記符,它可以是指令、偽操作或者宏指令名。
- 操作數(shù)(operand)項(xiàng)是一個(gè)或多個(gè)表達(dá)式組成,它提供為執(zhí)行所要求的操作而需要的信息。
- 注釋(comment)項(xiàng)是用來說明程序或者語句的功能。;為識(shí)別注釋項(xiàng)的開始。;也可以從一行的第一個(gè)字符開始,此時(shí)整行都是注釋,常用來說明下面一段程序的功能。
名字項(xiàng)
操作項(xiàng)
操作數(shù)項(xiàng)由一個(gè)或者多個(gè)表達(dá)式組成,多個(gè)操作數(shù)項(xiàng)之間一般用逗號分開。
操作數(shù)項(xiàng)可以是常數(shù),寄存器,標(biāo)號,變量或者由表達(dá)式組成。表達(dá)式是常數(shù),寄存器,標(biāo)號,變量與一些操作符相結(jié)合的序列,可以有數(shù)字表達(dá)式和地址表達(dá)式兩種。
算術(shù)操作符
算術(shù)操作符有+,-,*,/、MOD。其中MOD是指除法運(yùn)算后得到的余數(shù)。算術(shù)操作符可以用于數(shù)字或者地址表達(dá)式中,但當(dāng)它用于地址表達(dá)式的時(shí)候,只有其結(jié)果有明確的物理意義的時(shí)候才是有效的結(jié)果。例如:兩個(gè)地址相乘和相除是沒有意義的。在地址表達(dá)式中,可以使用+或者-,但也必須注意其物理意義,例如把兩個(gè)不同段的地址相加也是沒有意義的。經(jīng)常使用的是地址±數(shù)字量,它是有意義的,例如,SUM+1是指SUM字節(jié)單元的下一個(gè)字節(jié)單元的地址(注意:不是指SUM單元的內(nèi)容加1),而SUM-1則是指SUM字節(jié)單元的前一個(gè)字節(jié)單元的地址。
邏輯與移位操作符
邏輯操作符有AND,OR,XOR和NOT;移位操作符有SHL和SHR。他們都是按位操作的,只能用于數(shù)字表達(dá)式中。
關(guān)系操作符
| EQ | Equal | 相等 |
| NE | Not equal | 不想等 |
| LT | Less than | 小于 |
| GT | Great than | 大于 |
| LE | Less and equal | 小于或等于 |
| GE | Great and equal | 大于或等于 |
說明:
- 關(guān)系操作符的兩個(gè)操作數(shù)必須都是數(shù)字,或者同一段內(nèi)的兩個(gè)存儲(chǔ)器地址。
- 計(jì)算結(jié)果應(yīng)為邏輯值,結(jié)果為真,表示為0FFFFH;結(jié)果為假的時(shí)候,則表示為0。
數(shù)值回送操作符
它主要有的TYPE,LENGTH,SIZE,OFFEST,SEG等等。這些操作符把一些特征或者存儲(chǔ)器地址的一部分作為數(shù)值回送。
TYPE
格式為:TYPE expression
如果該表達(dá)式是變量,則匯編程序?qū)⒒厮妥兞康囊宰止?jié)數(shù)表示的類型:DB=1,DW=2,DD=4,DF=6,DQ=8,DT=10。如果表達(dá)式是標(biāo)號,則匯編程序?qū)⒒厮痛碓摌?biāo)號類型的數(shù)值:NEAR=-1,FAR=-2。如果表達(dá)式是常數(shù),則應(yīng)回送0。
操作數(shù)項(xiàng)(表達(dá)式)
- (1) 算術(shù)操作符: +、- 、*、 /、Mod
- (2) 邏輯操作符: AND、OR、XOR、NOT,移位操作符: SHL、SHR
- (3) 關(guān)系操作符: EQ、NE、LT、LE、GT、GE
- (4) 數(shù)值回送操作符: TYPE、 LENGTH、 SIZE 、OFFSET、SEG、
- TYPE 變量 / 標(biāo)號 / 常數(shù)
- DB、DW、DD、DF、DQ、DT、NEAR、FAR、常數(shù)
- 1、2、4、6、8、10、-1、-2、0(與上面的變量對應(yīng))
- (5) 屬性操作符: PTR、段操作符、SHORT、THIS、HIGH、LOW、HIGHWORD、LOWWORD
- PTR
- 格式:<類型> PTR <符號名>
- 功能是定義符號名為新類型。如,設(shè)內(nèi)存變量D1是字節(jié)屬性,把它的兩個(gè)字節(jié)內(nèi)容送到AX中。
- PTR
LENGTH
- LENGTH 變量
- 功能:回送由DUP定義的變量的單元數(shù),其它情況回送1
- DR2 DW 10H DUP(0,2 DUP(2)),MOV CL,LENGTH DR2CL的值為10H
- DR1 DB 10H,30H,MOV BL,LENGTH DR1BL的值為1。
SIZE
- SIZE
- 變量功能:LENGTH * TYPE
OFFSET和SEG
- OFFSET / SEG 變量 / 標(biāo)號
- 功能:回送變量或標(biāo)號的偏址 / 段址
Debug
匯編調(diào)試程序Debug使用
使用DEBUG調(diào)試和運(yùn)行可執(zhí)行文件
- 在初次使用DEBUG時(shí),可參照下列步驟進(jìn)行:
- 1、調(diào)用DEBUG,裝入用戶程序
- 2、U命令反匯編程序,記錄代碼段與數(shù)據(jù)段首地址
- 3、R命令觀察寄存器初始狀態(tài)
- 4、以單步工作方式T開始運(yùn)行程序 ,設(shè)置段寄存器的值。
- 5、D觀察用戶程序數(shù)據(jù)段初始內(nèi)容
- 6、繼續(xù)以單步工作方式運(yùn)行程序
- 7.G連續(xù)工作方式運(yùn)行程序
- 8.E或A修改程序和數(shù)據(jù)
- 9.運(yùn)用斷點(diǎn)調(diào)試程序 G
80x86指令系統(tǒng)
空操作指令指令格式:NOP
說明:NOP是英語“No Operation”的縮寫。NOP無操作數(shù),所以稱為“空操作”。
執(zhí)行NOP指令只使程序計(jì)數(shù)器PC加1,所以占用一個(gè)機(jī)器周期。
通用數(shù)據(jù)傳送指令
數(shù)據(jù)傳送指令:MOV、XCHG、LEA、LDS、LES、PUSH、POP、PUSHF、POPF、CBW、CWD、CWDE。
棧的基本操作
8086CPU的入棧和出棧操作都是以字為單位進(jìn)行的。
push與pop指令的執(zhí)行過程
PUSH指令每次只能壓入一個(gè)字(16位)。
push ax (1)SP = SP–2; (2)將AX中的內(nèi)容送入SS:SP指向的內(nèi)存單元處。 pop ax (1)將SS:SP指向的內(nèi)存單元處的數(shù)據(jù)送入ax中; (2)SP = SP+2。說明:
- 每執(zhí)行一次PUSH,SP指針都會(huì)減1。
MOV指令
指令寫法:MOV DST,SRC
執(zhí)行操作:(DST)<-(SRC)
其中DST表示目的操作數(shù),SRC表示源操作數(shù)。可以在CPU內(nèi)部或者在存儲(chǔ)器之間傳送數(shù)據(jù)。
說明:
- SRC和DST的操作類型必須明確而且一致。
- DST不能是立即數(shù),而且也不能是CS。
- 數(shù)據(jù)傳送指令是不能把數(shù)據(jù)傳送給CS的,因?yàn)镃S是代碼段寄存器,CS如果被修改程序就無法執(zhí)行。
- DST、SRC也不能同時(shí)是存儲(chǔ)器尋址。
- DST、SRC也不能同時(shí)是段寄存器。
- 立即數(shù)不能直接送段寄存器,必須通過寄存器(比如AX)送達(dá)段寄存器。
- 指令的執(zhí)行不影響標(biāo)志位。
- 立即數(shù)可以直接送到存儲(chǔ)器,但應(yīng)指定存儲(chǔ)器的類型。如:
- mov byte ptr[di], 3
- mov word ptr[si], 3000
- mov dword ptr[bx], 0FFFFFFh
XCHG指令
指令格式: XCHG OPR1, OPR2
功能: 將操作數(shù)地址中的內(nèi)容互換。
執(zhí)行操作: (OPR1) <-> (OPR2)
注意:
- 指令的執(zhí)行并不影響標(biāo)志位。
- 不允許使用段寄存器,不允許使用立即數(shù),不支持兩個(gè)存儲(chǔ)單元之間的數(shù)據(jù)交換。
- 允許字或者字節(jié)操作。
累加器專用傳送指令
XLAT
功能:將表格中的一個(gè)字節(jié)內(nèi)容送到AL累加器中。常用于將一種代碼轉(zhuǎn)換為另一種代碼。
這條指令根據(jù)AL寄存器提供的位移量,將BX指使的字節(jié)表格中的代碼換存在AL中。(AL)<-((DS)*16+(BX)+(AL))
說明:本指令并不影響標(biāo)志位。
地址傳送指令
| LEA | load effective address | 有效地址送寄存器 |
| LDS | load DS with pointer | 指針?biāo)图拇嫫骱虳S |
| LES | load ES with pointer | 指針?biāo)图拇嫫骱虴S |
| LFS | load FS with pointer | 指針?biāo)图拇嫫骱虵S |
| LGS | load GS with pointer | 指針?biāo)图拇嫫骱虶S |
| LSS | load SS with pointer | 指針?biāo)图拇嫫骱蚐S |
LEA
功能:有效地址送寄存器。
全稱:load effective address
MOV BX, OFFSET [BX+SI] ;——× 注意:OFFSET只能與簡單的符號地址相連。
算術(shù)指令
算術(shù)運(yùn)算指令會(huì)根據(jù)運(yùn)算結(jié)果影響狀態(tài)標(biāo)志,主要影響6個(gè)標(biāo)志位:ZF、CF、AF、SF、OF和PF。
加法指令
| ADD | ADD DST,SRC | 功能:加法,將SRC和DST的值相加之后存放在DST中。 執(zhí)行操作: (DST) <- (SRC) + (DST) |
| ADC | ADC DST, SRC | 功能:帶進(jìn)位的加法指令,將SRC和DST的值和進(jìn)位標(biāo)志位(CF)相加之后存放在DST中。 執(zhí)行操作:(DST) <- (SRC) + (DST) + CF |
| INC | INC OPR | 功能:加一指令。 執(zhí)行操作:(OPR) <- (OPR) + 1 |
說明:加法指令都會(huì)影響條件標(biāo)志位,但I(xiàn)NC指令不影響CF標(biāo)志。
INC影響的條件標(biāo)志位包括:SF,ZF,OF,AF,PF。
ADC指令的作用
在執(zhí)行 adc 指令的時(shí)候加上的 CF 的值是由 adc指令前面的指令決定的,也就是說,關(guān)鍵在于所加上的CF值是被什么指令設(shè)置的。
下面的指令和add ax , bx具有相同的結(jié)果:
看來CPU提供 ADC指令的目的,就是來進(jìn)行加法的第二步運(yùn)算的。ADC指令和ADD指令相配合就可以對更大的數(shù)據(jù)進(jìn)行加法運(yùn)算。
注意:有符號的雙精度數(shù)的溢出,應(yīng)根據(jù)ADC指令的OF位判斷,而作低位加法用的ADD指令的溢出是無意義的。
用16位寄存器編寫程序:
說明:
OF位可以用來表示帶符號數(shù)的溢出,CF位可以用來表示無符號數(shù)的溢出。
條件標(biāo)志(或者稱呼為)位中最主要的是CF,ZF,SF,OF四位,分別表示了進(jìn)位、結(jié)果為零,符號和溢出的情況。
執(zhí)行加法指令的時(shí)候,CF位是根據(jù)最高有效位是否向最高位的進(jìn)位來設(shè)置的。有進(jìn)位的時(shí)候CF=1,無進(jìn)位的時(shí)候CF=0。
OF位則根據(jù)操作數(shù)的符號及其變化情況來設(shè)置的:若兩個(gè)操作數(shù)的符號相同,而結(jié)果的符號與之相反則OF=1,否則OF=0。
- 注意區(qū)分OF是根據(jù)原先的符號位來判斷的。
溢出位OF既然試試根據(jù)數(shù)的符號及其變化來設(shè)置的,當(dāng)然它是用來表示帶符號數(shù)的溢出的,從其設(shè)置條件來看結(jié)論也是明顯的。
CF位可以用來表示無符號數(shù)的溢出。一方面,由于無符號數(shù)的最高有效位只有數(shù)值意義而無符號意義,所以該位產(chǎn)生的進(jìn)位應(yīng)該是結(jié)果的實(shí)際的進(jìn)位值,但是在有限數(shù)位的范圍內(nèi)就說明了結(jié)果的溢出情況;另一方面,它所保存的進(jìn)位值有時(shí)候還是有用的。例如。雙字長數(shù)運(yùn)算的時(shí)候,可以利用進(jìn)位值把低位字的進(jìn)位計(jì)入高位字中。
加法的ASCII碼調(diào)整指令A(yù)AA
- 功能:
- 把AL中的和調(diào)整到非壓縮BCD碼格式 → AL
- AH + 調(diào)整產(chǎn)生的進(jìn)位值 → AH
- 影響標(biāo)志位:
- CF=1,AF
- 用途:
- 適用于數(shù)字ASCⅡ碼的調(diào)整;
- 也適用于一般的非壓縮BCD碼的十進(jìn)制調(diào)整
- 調(diào)整原則:
- ①若AL的低4位是在0~9之間,且AF=0,則無需調(diào)整
- ②若AL的低4位是在0AH~0FH之間,或AF=1,則AL
- 加6調(diào)整,AH+1→ AH,且使CF=1
加法的十進(jìn)制調(diào)整指令DAA
- 功能:
- 把AL中的和調(diào)整到壓縮BCD碼格式→ AL
- 影響標(biāo)志位:
- CF、PF、AF、ZF、SF
- 注:
- ① DAA通常跟在ADD和ADC指令之后使用
- ② 只能對AL中的運(yùn)算結(jié)果進(jìn)行BCD碼調(diào)整
減法指令
| SUB | SUB DST,SRC | 功能:減法,將SRC和DST的值相減之后存放在DST中。 執(zhí)行操作: (DST) <- (SRC) + (DST) |
| SBB | SUB DST, SRC | 功能:帶借位減法指令,將SRC和DST的值和進(jìn)位標(biāo)志位(CF)相加之后存放在DST中。 執(zhí)行操作:(DST) <- (SRC) + (DST) - CF CF為進(jìn)位位的值。 |
| DEC | DEC OPR | 功能:加一指令。 執(zhí)行操作:(OPR) <- (OPR) + 1 |
| NEG | NEG OPR | 功能:加一指令。 執(zhí)行操作:(OPR) <- (OPR) + 1 把操作數(shù)按位求反后末尾加1。 |
| CMP | CMP OPR1, OPR2 | 功能:加一指令。 執(zhí)行操作: (OPR1) - (OPR2) 執(zhí)行減法操作,不保存結(jié)果。往往根據(jù)比較發(fā)生轉(zhuǎn)移。 |
說明:
減法運(yùn)算的條件碼情況和加法類似。CF位說明無符號數(shù)相減的溢出,同時(shí)它又確實(shí)是被減數(shù)的最高有效位向高位的借位值。OF位則說明帶符號數(shù)的溢出。
減法的CF值反映了無符號數(shù)運(yùn)算中的借位情況,因此當(dāng)作為無符號運(yùn)算時(shí),若減數(shù)>被減數(shù),此時(shí)有借位,則CF=1;否則CF=0。或者,也可以簡單地用二進(jìn)制減法的運(yùn)算中的最高有效位向高位的進(jìn)位的情況來判別:有進(jìn)位的時(shí)候CF=0,沒有進(jìn)位的時(shí)候CF=1。
減法的OF位的設(shè)置方法為:若兩個(gè)數(shù)的符號相反,而結(jié)果的符號與減數(shù)相同則相同,則OF=1;除了上述情況外OF=0。OF=1說明帶符號數(shù)的減法溢出,結(jié)果是錯(cuò)誤的。
NEG指令的條件碼按照求補(bǔ)后的結(jié)果設(shè)置,只有當(dāng)操作數(shù)為0的時(shí)候,求補(bǔ)運(yùn)算的結(jié)果使得CF=0,其他情況都為CF=1。所以,只有當(dāng)字運(yùn)算時(shí)對-128求補(bǔ)的時(shí)候,以及字運(yùn)算的時(shí)候?qū)?32768求補(bǔ)以及雙字運(yùn)算的時(shí)候?qū)?2^31求補(bǔ)的情況下OF=1,其他則均為OF=0。
減法的ASCII碼調(diào)整指令A(yù)AS
- 功能:
- 把AL中的差調(diào)整到非壓縮BCD碼格式 → AL
- AH - 調(diào)整產(chǎn)生的進(jìn)位值 → AH
- 影響標(biāo)志位:
- CF=1,AF
- 用途:同AAA
- 調(diào)整原則:
- ①若AL的低4位是在0~9之間,且AF=0,則無需調(diào)整
- ②若AL的低4位是在0AH~0FH之間,或AF=1,則減6調(diào)整,AH+1→ AH,且使CF=1
減法的十進(jìn)制調(diào)整指令DAS
- 功能:
- 把AL中的差調(diào)整到壓縮BCD碼格式→ AL
- 影響標(biāo)志位:
- CF、PF、AF、ZF、SF
- 注:
- ① DAA通常跟在SUB和SBB指令之后使用
- ② 只能對AL中的運(yùn)算結(jié)果進(jìn)行BCD碼調(diào)整
乘法指令
| MUL | 無符號數(shù)乘法指令 | MUL SRC |
| IMUL | 帶符號數(shù)乘法指令 | IMUL SRC |
| 字節(jié)操作數(shù) | (AX) <- (AL) * (SRC) |
| 字操作數(shù) | (DX, AX) <- (AX) * (SRC) |
注意:
- AL (AX) 為隱含的乘數(shù)寄存器。
- AX (DX,AX) 為隱含的乘積寄存器。 CPU會(huì)根據(jù)乘數(shù)是8位、16位,還是32位操作數(shù),來自動(dòng)選用被乘數(shù):AL、AX或EAX。
- SRC不能為立即數(shù)。
- 除CF和OF外,對條件標(biāo)志位無定義。
- 當(dāng)乘積的高半部分不為0時(shí),CF=1,OF=1。
乘法的ASCII碼調(diào)整指令A(yù)AM
- 功能:
- 把AL中的內(nèi)容調(diào)整到非壓縮BCD碼格式 → AX
- 影響標(biāo)志位:
- SF,ZF,PF
- 調(diào)整原則:
- 將AL中的內(nèi)容除以0AH,高八位放在AH中,低八位保存在AL中
- 注:
- 執(zhí)行AAM前必須執(zhí)行MUL指令把兩個(gè)非壓縮的BCD碼相乘(要求高4位為0),結(jié)果放在AL中
除法指令
| DIV | 無符號數(shù)除法指令 | DIV SRC |
| IDIV | 帶符號數(shù)除法指令 | IDIV SRC |
| 字節(jié)操作數(shù) | (AL) <- (AX) / (SRC) 的商 (AH) <- (AX) / (SRC) 的余數(shù) |
| 字操作數(shù) | (AX) <- (DX, AX) / (SRC) 的商 (DX) <- (DX, AX) / (SRC) 的余數(shù) |
注意:
- AX (DX,AX) 為隱含的被除數(shù)寄存器。
- AL (AX) 為隱含的商寄存器。
- AH (DX) 為隱含的余數(shù)寄存器。
- SRC不能為立即數(shù)。
- 對所有條件標(biāo)志位均無定義。但是可能產(chǎn)生溢出。
- 執(zhí)行除法指令后,對AF,CF,OF,PF,SF,ZF標(biāo)志位的影響都不確定。
除法的ASCII碼調(diào)整指令A(yù)AD
- 功能:
- 把AX中的被除數(shù)調(diào)整為二進(jìn)制 → AL
- 影響標(biāo)志位:
- SF,ZF,PF
- 調(diào)整原則:
- 若被除數(shù)是存放在AX中的兩位非壓縮BCD碼,調(diào)整為二進(jìn)制數(shù)
- 若除數(shù)是一位非壓縮BCD碼,調(diào)整為二進(jìn)制數(shù)
- 注:
- 指令A(yù)AD放在DIV指令前
標(biāo)志寄存器傳送指令
| LAHF | load AH with flags | 將標(biāo)志寄存器中的低八位送到AH中。 |
| SAHF | store AH into flags | 將AH寄存器的相應(yīng)位傳送到標(biāo)志寄存器的低8位。 |
| PUSHF/PUSHFD | push the flags or eflags | 標(biāo)志進(jìn)棧 |
| PUPF/POPFD | pop the flags or eflags | 標(biāo)志出棧 |
注意:
這組指令中的LAHF和PUSHF/PUSHFD都不影響標(biāo)志位。SAHF和POPF/POPFD則由裝入的值來確定標(biāo)志位的值,但是POPFD指令不影響VM,RF,IOPF,VIF和VIP的值。
STC----是置進(jìn)位標(biāo)志指令,執(zhí)行的結(jié)果是將進(jìn)位標(biāo)志CF置1
CLC----是清進(jìn)位標(biāo)志指令,其執(zhí)行結(jié)果是置CF標(biāo)志為0
讀取標(biāo)志指令LAHF:
類型轉(zhuǎn)換指令
| CBW | 字節(jié)轉(zhuǎn)換為字 | AL符號擴(kuò)展到AH中,形成AX中的字。即如果(AL)中的最高有效位是0,則(AH)=0;如(AL)的最高有效位為1,則(AH)=0FFH。 執(zhí)行操作: 若(AL)的最高有效位為0,則(AH)= 00H 若(AL)的最高有效位為1,則(AH)= FFH |
| CWD/CWDE | 字轉(zhuǎn)換為雙字 | AX符號擴(kuò)展 -> (DX,AX)雙字 執(zhí)行操作: 若(AX)的最高有效位為0,則(DX)= 0000H 若(AX)的最高有效位為1,則(DX)= FFFFH |
| CWQ | 雙字轉(zhuǎn)換為4字 | EAX的內(nèi)容符號擴(kuò)展到EDX,形成EDX:EAX中的4字。 |
| BSWAP | 字節(jié)交換指令 | 格式:BASWAP r32。 該指令只能用于486及其后繼機(jī)型。r32指32位寄存器。 執(zhí)行的操作:使指令指定的32位寄存器的字節(jié)次序變反。具體的操作為:1、4字節(jié)互換,2 |
注意:
- 隱含對AL 或AX 進(jìn)行符號擴(kuò)展
- 本組指令都不影響條件標(biāo)志位
邏輯指令
邏輯運(yùn)算指令
| AND | and | 邏輯與 格式:AND DST,SRC |
| OR | or | 邏輯或 格式:OR DST,SRC |
| NOT | not | 邏輯非 格式:NOT DST,SRC |
| XOR | exclusive or | 異或 格式:XOR DST,SRC |
| TEST | test | 作用:測試 格式:TEST OPR1,OPR2 執(zhí)行的操作:(OPR1)∧(OPR2) 說明:兩個(gè)操作數(shù)相與的結(jié)果不保存,只是根據(jù)其特征置條件碼。 |
注意:
- 在以上的五種指令中,NOT不允許存放立即數(shù)。
- 其他4條指令除非源操作數(shù)是立即數(shù),至少有一個(gè)操作數(shù)必須存放在寄存器中,另一個(gè)操作數(shù)則可以使用任意尋址方式。
- NOT不影響標(biāo)志為。
- 其他4種指令將使CF位和OF位為0,AF位無定義,而SF位、ZF位和PF位則根據(jù)運(yùn)算結(jié)果設(shè)置。
- 這些指令對處理操作數(shù)的某些位很有用,例如可以屏蔽某些位(將這些位置0),或者使某些位置1或者測試某些位等等。
AND
要求屏蔽0、1兩位,可以用AND指令并設(shè)置常數(shù)0FCH。
這兩條指令的運(yùn)行結(jié)果使得(AL)=0BCH。因此,使用AND指令可以使得操作數(shù)的某些位被屏蔽。只需要把AND指令的源操作數(shù)設(shè)置成一個(gè)立即數(shù),并把需要屏蔽的位設(shè)置為0,這樣指令執(zhí)行的結(jié)果就可以把操作數(shù)的相應(yīng)位置0,其他位保持不變。
OR
要求第5位置1,可以使用OR指令。
MOV AL,43H MOV AL,20H這兩條指令執(zhí)行了之后,(AL)=63 H。因此,用OR指令可以使得操作數(shù)的某些位置1,其他位保持不變。只需要把OR指令的源操作數(shù)設(shè)置為一個(gè)立即數(shù),并把需要置1的位設(shè)置為1,就可以達(dá)到目的了。
TEST
要測試操作數(shù)的某些位是否為0,可以使用TEST指令,同樣把TEST指令的源操作數(shù)設(shè)置成一個(gè)立即數(shù),其中需要測試的位應(yīng)該設(shè)置為1。
這里要求測試第0,1,2,3,5,7位是否為0,根據(jù)測試的結(jié)果設(shè)置條件碼為CF=OF=0,SF=0,ZF=1,說明了所需要測試的位均為0。如果在這兩條指令之后跟一條件轉(zhuǎn)移指JNZ,結(jié)果如果不是0就轉(zhuǎn)移,結(jié)果如果是0就順序往下執(zhí)行,這樣就可以根據(jù)測試的情況產(chǎn)生不同的程序分支,轉(zhuǎn)向不同的處理方案了。
NOT
要測試操作數(shù)的某位是否為1,可以先把該操作數(shù)求反,然后使用TEST指令測試。如要測試AL寄存器中第2位是否為1,若為1則轉(zhuǎn)移到EXIT中去執(zhí)行,可以用下列指令序列:
如AL寄存器的內(nèi)容為0FH,為了避免破壞操作數(shù)的原始內(nèi)容,把它復(fù)制到了DL中去測試,執(zhí)行完TEST指令之后,結(jié)果為全0而有ZF=1,說明操作數(shù)的第2位為1引起的轉(zhuǎn)移到EXIT去執(zhí)行。
XOR
要是操作數(shù)的某些位變反,可以使用XOR指令,只要把源操作數(shù)的立即數(shù)字段的相應(yīng)位置設(shè)置為1就可以達(dá)到目的。如果求第0,1位變反,可以使用下面的指令:
則指令執(zhí)行后,(AL)=12H,達(dá)到了第0,1位變反而其他位不變的目的。
XOR指令還可以用來測試某一個(gè)操作數(shù)是否與另外一個(gè)確定的操作數(shù)相等。這種操作在檢查地址是否匹配的時(shí)候是經(jīng)常使用的。
這兩條指令是用來檢查AX的內(nèi)容是否等于042EH,若相等則轉(zhuǎn)移到MATCH去執(zhí)行匹配的情況需要做的工作,否則執(zhí)行JZ下面的程序。
位測試并修改指令
386及其后繼機(jī)型增加了本組指令。
位掃描指令
386及其后繼機(jī)型增加了本組指令。
移位指令-這里編輯未完成
| SHL | shift logical left | 邏輯左移 |
| SAL | shift arithmetic left | 算術(shù)左移 |
| SHR | shift logical right | 邏輯右移 |
| SAR | shift arithmetic right | 算術(shù)右移 |
| ROL | rotat left | 循環(huán)左移 |
| ROR | rotat right | 循環(huán)右移 |
| RCL | rotate left through carry | 帶進(jìn)位循環(huán)左移 |
| RCR | rotate right through carry | 帶進(jìn)位循環(huán)右移 |
| SHLD | shift left double | 雙精度左移 |
| SHRD | shift right double | 雙精度右移 |
注意:
- OPR可用除立即數(shù)以外的任何尋址方式
- 移位次數(shù)CNT=1,SHL OPR, 1
- CNT>1,MOV CL, CNT,SHL OPR, CL
- 條件標(biāo)志位:
- CF = 移入的數(shù)值
- OF = 1 CNT=1時(shí),最高有效位的值發(fā)生變化
- OF = 0 CNT=1時(shí),最高有效位的值不變
- 循環(huán)移位指令:
- 不影響 SF、ZF、PF、AF
- 移位指令:
- 常用來作乘以2或除以2 的操作。
- SAL:有符號數(shù)乘以2,SAR有符號數(shù)除以2;
- SHL:無符號數(shù)乘以2,SHR: 無符號數(shù)除以2。
| 邏輯左移 | 右邊統(tǒng)一添0,移出來的那一位放進(jìn)CF |
| 算術(shù)左移 | 右邊統(tǒng)一添0,移出來的那一位放進(jìn)CF |
| 邏輯右移 | 左邊統(tǒng)一添0,移出來的那一位放進(jìn)CF |
| 算術(shù)右移 | 左邊添加符號位上的數(shù),移出來的那一位放進(jìn)CF |
示例:1010101010,其中[]是添加的位
邏輯左移一位:010101010[0]
算術(shù)左移一位:010101010[0]
邏輯右移一位:[0]101010101
算術(shù)右移一位:[1]101010101
控制轉(zhuǎn)移指令
一般情況下指令都是順序逐條執(zhí)行的,但是實(shí)際上程序不可能全部順序執(zhí)行而經(jīng)常需要改變程序的執(zhí)行流程。
無條件轉(zhuǎn)移指令JMP
- 段內(nèi)直接短轉(zhuǎn)移:
- JMP SHORT OPR
- 執(zhí)行操作:(IP) ← (IP) + 8位位移量
- short:表示實(shí)現(xiàn)的是段內(nèi)直接短轉(zhuǎn)移,即位移量為8位數(shù)據(jù),它對IP的修改范圍為 -128~127,也就是說,它向前轉(zhuǎn)移時(shí)可以最多越過128個(gè)字節(jié),向后轉(zhuǎn)移可以最多越過127個(gè)字節(jié)。
- 段內(nèi)直接近轉(zhuǎn)移:(轉(zhuǎn)向的符號地址)
- JMP NEAR PTR OPR
- 執(zhí)行操作:(IP) ← (IP) + 16位位移量
- 段內(nèi)間接轉(zhuǎn)移:(除立即數(shù)以外的尋址方式)
- JMP WORD PTR OPR
- 執(zhí)行操作: (IP) ← (EA)
- 段間直接遠(yuǎn)轉(zhuǎn)移:(轉(zhuǎn)向的符號地址)
- JMP FAR PTR OPR
- 執(zhí)行操作:
- (IP) ← OPR 的段內(nèi)偏移地址
- (CS) ← OPR 所在段的段地址
- 段間間接轉(zhuǎn)移:(存儲(chǔ)器尋址方式)
- JMP DWORD PTR OPR
- 執(zhí)行操作:
- (IP) ← (EA)
- (CS) ← (EA+2)
注意:
- 執(zhí)行JMP指令的時(shí)候,IP改變兩次。
- 第一次是在讀取指令的時(shí)候,JMP指令被讀取放到了指令緩沖期中,這個(gè)時(shí)候IP改變了一次;之后,JMP指令執(zhí)行的時(shí)候進(jìn)行了跳轉(zhuǎn),IP又改變了一次。所以IP總共改變了兩次。
條件轉(zhuǎn)移指令
注意:只能使用段內(nèi)直接尋址的8 位位移量。
1)根據(jù)單個(gè)條件標(biāo)志的設(shè)置情況轉(zhuǎn)移:
| JZ(JE) OPR | jump if zero,or equal | ZF = 1 | 結(jié)果為0(相等)則轉(zhuǎn)移 |
| JNZ(JNE) OPR | jump if not zero, or not equal | ZF = 0 | 不為0(不相等)轉(zhuǎn)移 |
| JS OPR | jump if sign | SF = 1 | 為負(fù)轉(zhuǎn)移 |
| JNS OPR | jump if not sign | SF = 0 | 為正轉(zhuǎn)移 |
| JO OPR | jump if overflow | OF = 1 | 溢出轉(zhuǎn)移 |
| JNO OPR | jump if not overflow | OF = 0 | 不溢出轉(zhuǎn)移 |
| JP OPR | jump if parity, or parity even | PF = 1 | 有偶數(shù)個(gè)1則轉(zhuǎn)移 |
| JNP OPR | jump if not parity, or parity odd | PF = 0 | 有奇數(shù)個(gè)1 則轉(zhuǎn)移 |
| JC OPR | jump if carry | CF = 1 | 有進(jìn)位轉(zhuǎn)移 |
| JNC OPR | jump if not cary | CF = 0 | 無進(jìn)位轉(zhuǎn)移 |
2)比較兩個(gè)無符號數(shù),并根據(jù)比較結(jié)果轉(zhuǎn)移的指令(與比較指令CMP 聯(lián)用)
| < | JB (JNAE,JC) OPR | jump if below | CF = 1 | 有借位,被減數(shù)小于減數(shù)則轉(zhuǎn)移 |
| ≥ | JNB (JAE,JNC) OPR | jump if not below | CF = 0 | 沒有借位, 被減數(shù)大于或等于減數(shù)則轉(zhuǎn)移 |
| ≤ | JNA (JBE) OPR | jump if not above, jump if below of equal | CF∨ZF = 1 | 被減數(shù)小于或等于減數(shù)則轉(zhuǎn)移 |
| > | JA (JNBE) OPR | jump if above, jump if not below or not equal | CF ∨ ZF = 0 | 被減數(shù)大于減數(shù)則轉(zhuǎn)移 |
說明:
- 適用于地址或雙精度數(shù)低位字的比較。
無符號數(shù)比較示例:cmp ax,bx
cmp指令對有符號數(shù)的比較:cmp ah, bh
- 1、如果SF=1,而OF=0, (ah)<(bh)
- OF=0,說明沒有溢出,邏輯上真正結(jié)果的正負(fù)=實(shí)際結(jié)果的正負(fù);SF=1表示實(shí)際結(jié)果為負(fù),所以邏輯上真正的結(jié)果為負(fù),所以(ah)<(bh)。
- 2、如果SF=0,而OF=1 ,(ah)<(bh)
- OF=1 ,說明有溢出,邏輯上真正結(jié)果的正負(fù)≠實(shí)際結(jié)果的正負(fù);SF=0表示由于溢出導(dǎo)致了實(shí)際結(jié)果非負(fù),那么邏輯上真正的結(jié)果必然為負(fù)。這樣,SF=0,OF = 1 ,說明了(ah)<(bh)。
- 3、如果SF=0,而OF=0, (ah)≥(bh)
- OF=0,說明沒有溢出,邏輯上真正結(jié)果的正負(fù)=實(shí)際結(jié)果的正負(fù);SF=0表示實(shí)際結(jié)果非負(fù),所以邏輯上真正的結(jié)果必然非負(fù)。所以(ah)≥(bh)。
- 4、如果SF=1,而OF=1, (ah)>(bh)
- OF=1 ,說明有溢出,邏輯上真正結(jié)果的正負(fù)≠實(shí)際結(jié)果的正負(fù); SF=1 表示由于溢出導(dǎo)致了實(shí)際結(jié)果為負(fù),那么邏輯上真正的結(jié)果必然為正。這樣,SF=1,OF = 1 ,說明了(ah)>(bh)。
3)比較兩個(gè)帶符號數(shù),并根據(jù)比較結(jié)果轉(zhuǎn)移的指令
| < | JL (JNGE) OPR | jump if less | SF?OF = 1 | 小于,或者不大于或等于則轉(zhuǎn)移。 |
| ≥ | JNL (JGE) OPR | jump if not less | SF?OF = 0 | 不小于,或者大于或等于則轉(zhuǎn)移。 |
| ≤ | JNG (JLE ) OPR | jump if not greater | (SF?OF)∨ZF = 1 | 不大于或者小于或等于則轉(zhuǎn)移。 |
| > | JG (JNLE) OPR | jump if greater | (SF?OF)∨ZF = 0 | 大于或者不小于或等于則轉(zhuǎn)移。 |
說明:
適用于帶符號數(shù)的比較
4)測試 CX 的值為 0 則轉(zhuǎn)移的指令
| JCXZ OPR | jump if CX register is zero | (CX)=0 | CX寄存器的內(nèi)容為零則轉(zhuǎn)移。 |
循環(huán)指令
Loop
// 計(jì)算0+1+2+3+4+5+6+7+8+9的值 int sum=0; for(int i=0;i<10;i++)sum=sum+i;相當(dāng)于:
// 計(jì)算0+1+2+3+4+5+6+7+8+9的值mov ax,0; ax相當(dāng)于summov bx,0; bx相當(dāng)于imov cx,10;標(biāo)號s代表一個(gè)地址 s: add ax,bxinc bxloop s; 判斷 指令的格式是:loop 標(biāo)號
CPU 執(zhí)行l(wèi)oop指令的時(shí)候,要進(jìn)行兩步操作:
① (cx)=(cx)-1;
② 判斷cx中的值,不為零則轉(zhuǎn)至標(biāo)號處執(zhí)行程序,如果為零則向下執(zhí)行,退出循環(huán)。
可見,cx中的值影響著loop指令的執(zhí)行結(jié)果。用loop指令來實(shí)現(xiàn)循環(huán)功能時(shí),cx 中要存放循環(huán)次數(shù)。
一條循環(huán)指令LOOP AGAIN可以用修改循環(huán)計(jì)數(shù)和判斷轉(zhuǎn)移條件的兩條指令替代DEC CX,JNZ AGAIN。JNZ(或JNE)結(jié)果不為零(或不相等)則轉(zhuǎn)移,測試條件為ZF=0。
我們可以總結(jié)出用cx和loop 指令相配合實(shí)現(xiàn)循環(huán)功能的三個(gè)要點(diǎn):
- 1)在cx中要存放循環(huán)次數(shù);
- 2)loop 指令中的標(biāo)號所標(biāo)識(shí)地址要在前面;
- 3)要循環(huán)執(zhí)行的程序段,要寫在標(biāo)號和 loop 指令的中間。
- 4)loop指令的執(zhí)行不影響條件碼標(biāo)志位。
LOOP示例
MOV CX,0 S: ADD AX,BX LOOP S 以上指令序列執(zhí)行后ADD AX,BX指令被執(zhí)行了多少次?
答案是:65536次。
循環(huán) LOOP (loop)
指令的匯編格式:LOOP label
指令的基本功能:
①(CX)←(CX)-1
② 若(CX)≠0,則(IP)←(IP)當(dāng)前+位移量,否則循環(huán)結(jié)束。
指令的特殊要求:循環(huán)指令都是短轉(zhuǎn)移格式的指令,也就是說,位移量是用8位帶符號數(shù)來表示的,轉(zhuǎn)向地址在相對于當(dāng)前IP值的-128 ~ +127字節(jié)范圍之內(nèi)。
解析:LOOP指令是先執(zhí)行CX自減的功能,之后才進(jìn)行循環(huán)的。只要CX不為0,循環(huán)就不會(huì)終止。因此在上面中,第一次執(zhí)行的時(shí)候,CX自減為0FFFFH,這時(shí)CX就不為0的,循環(huán)不會(huì)被終止。由此,我們可以算出總共運(yùn)行了65536次。
可提前結(jié)束的循環(huán)指令
| 當(dāng)為0或相等時(shí)循環(huán) | LOOPZ / LOOPE 標(biāo)號 | ZF=1且(CX)≠0 |
| 不為0或不相等循環(huán) | LOOPNZ / LOOPNE 標(biāo)號 | ZF=0且(CX)≠ 0 |
執(zhí)行步驟:
- 1) (CX) ← (CX) - 1;
- 2) 檢查是否滿足測試條件,如滿足則實(shí)現(xiàn)循環(huán);不滿足則退出循環(huán)。
注意:
- CX 中存放循環(huán)次數(shù);
- 與比較指令CMP聯(lián)合使用可提前退出循環(huán)。
串處理指令
| 串傳送 | MOVSB / MOVSW | REP | CLD |
| 存入串 | STOSB / STOSW | REPE / REPZ | STD |
| 從串取 | LODSB / LODSW | REPNE / REPNZ | |
| 串比較 | CMPSB / CMPSW | ||
| 串掃描 | SCASB / SCASW | ||
| 串輸入 | INSB / INSW | ||
| 串輸出 | OUTSB / OUTSW |
說明:
字符串操作指令的實(shí)質(zhì)是對一片連續(xù)存儲(chǔ)單元進(jìn)行處理,這片存儲(chǔ)單元是由隱含指針DS:SI或ES:DI來指定的。
REP
與 REP 配合工作的MOVS / STOS / LODS / INS / OUTS。
REP 重復(fù)串操作直到計(jì)數(shù)寄存器CX的內(nèi)容為0為止。
執(zhí)行操作:
- 1) 如 (CX)=0 則退出 REP,否則轉(zhuǎn)(2)
- 2) (CX) <- (CX) -1
- 3) 執(zhí)行 MOVS / STOS / LODS / INS / OUTS
- 4) 重復(fù) (1) ~ (3)
MOVS串傳送指令
MOVS 串傳送指令:
MOVS DST, SRC MOVSB ;(字節(jié)) MOVSW ;(字) MOVSD ;(雙字,計(jì)數(shù)器為ECX,386及后繼機(jī)型) 例:MOVS ES: BYTE PTR [DI], DS: [SI]
執(zhí)行操作:
- 1) ((DI)) ← ((SI))
- 2) 字節(jié)操作:(SI)←(SI)±1, (DI)←(DI)±1,字操作: (SI)←(SI)±2, (DI)←(DI)±2
- (方向標(biāo)志 DF=0 時(shí)用 + ,DF=1 時(shí)用 - 。)
REP MOVS:將數(shù)據(jù)段中的整串?dāng)?shù)據(jù)傳送到附加段中。源串(數(shù)據(jù)段)→ 目的串(附加段)
執(zhí)行 REP MOVS 之前,應(yīng)先做好:
- 1) 源串首地址(末地址)→ SI
- 2) 目的串首地址(末地址)→ DI
- 3) 串長度 → CX
- 4) 建立方向標(biāo)志CLD ( STD )
- CLD 使 DF=0,從前往后處理,地址自動(dòng)增量;
- STD 使 DF=1 ,由后向前處理,地址自動(dòng)減量)
代碼實(shí)例
; -------- 定義數(shù)據(jù)段 data segmentmess1 db ‘personal_computer’ data ends ; -------- 定義附加段 extra segmentmess2 db 17 dup (?) extra endscode segment assume cs:code,ds:data.es:extra mov ax, datamov ds,axmov ax, extramov es, ax; ------ 總共5條指令。lea si, mess1lea di, mess2mov cx, 17cldrep movsb … code ends反向的指令:
lea si, mess1+16 lea di, mess2+16 mov cx, 17 std rep movsb為了在同一段內(nèi)處理數(shù)據(jù),可以在DS和ES中設(shè)置同樣的地址。
data segmentmess1 db ‘personal_computer’mess2 db 17 dup (?) data endscode segmentmov ax, datamov ds, axmov es, axlea si, mess1lea di, mess2mov cx, 17cldrep movsb… code endsSTOS存入指令
STOS DST STOSB (字節(jié)) STOSW (字) 執(zhí)行操作:
字節(jié)操作:((DI))←(AL), (DI)←(DI)±1
字操作:((DI))←(AX), (DI)←(DI)±2
例:把 附加段 中mess2開始的 10 個(gè)字節(jié)緩沖區(qū)全部置為 20H
或者:
lea di, mess2 mov ax, 2020H mov cx, 5 cld rep stoswLODS從串取指令
LODS SRC LODSB ;(字節(jié)) LODSW ;(字)執(zhí)行操作:
- 字節(jié)操作:(AL)←((SI)), (SI)←(SI)±1
- 字操作:(AX)←((SI)), (SI)←(SI)±2
注意:
- LODS 指令一般不與 REP 聯(lián)用;
- 有時(shí)緩沖區(qū)中的一串字符需要逐次取出來測試,可使用本指令。
INS 串輸入指令:
INS DST, DX INSB ; (字節(jié)) INSW ;(字)執(zhí)行操作:
字節(jié)操作:((DI))←((DX)), (DI)←(DI)±1
字操作:((DI))←((DX)), (DI)←(DI)±2功能:把端口號在DX的I/O空間的字節(jié)、字或雙字傳送到附加段中的由DI所指向的存儲(chǔ)單元中,并根據(jù)DF的值和數(shù)據(jù)類型修改DI的內(nèi)容。
OUTS 串輸出指令:
OUTS DX , SRC OUTSB ;(字節(jié)) OUTSW ;(字)執(zhí)行操作:
字節(jié)操作:((DX))←((SI)), (SI)←(SI)±1
字操作:((DX))←((SI)), (SI)←(SI)±2
功能:把由SI所指向的存儲(chǔ)單元中的字節(jié)、字或雙字傳送到端口號在DX的I/O端口中去,并根據(jù)DF的值和數(shù)據(jù)類型修改SI的內(nèi)容。
與 REPE / REPZ(REPNE / REPNZ)配合工作的
CMPS 和 SCAS
| REPE / REPZ | 當(dāng)相等 /為零時(shí)重復(fù)串操作 |
| REPNE / REPNZ | 當(dāng)不相等 /不為零時(shí)重復(fù)串操作 |
執(zhí)行操作:
- 1) 如 (CX)=0 或 ZF=0 (ZF=1) 則退出串操作,否則轉(zhuǎn)2)
- 2) (CX)←(CX) -1
- 3) 執(zhí)行 CMPS / SCAS
- 4) 重復(fù) (1) ~ (3)
CMPS 串比較指令:
CMPS SRC, DST CMPSB ;(字節(jié)) CMPSW ;(字)執(zhí)行操作:
- 1) ((SI)) - ((DI))根據(jù)比較結(jié)果置條件標(biāo)志位:相等 ZF=1,不等 ZF=0
2) 字節(jié)操作:(SI)←(SI)±1, (DI)←(DI)±1,字操作: (SI)←(SI)±2, (DI)←(DI)±2
匯編語言中,CMP和CMPS都是比較指令,不同主要有:
1、CMP比較指令是執(zhí)行兩個(gè)數(shù)的相減操作,包括有符號數(shù)。CMPS比較指令是執(zhí)行兩個(gè)字符串的相減操作,所有數(shù)據(jù)認(rèn)為是無符號數(shù)。
2、CMP比較指令必須有兩個(gè)顯式操作數(shù)。CMPS比較指令可以有兩個(gè)顯式操作數(shù),也可以使用指令CMPSB或CMPSW分別表示字節(jié)串比較或字串比較而隱含操作數(shù)。
3、使用CMP比較指令比較連續(xù)的數(shù)據(jù)時(shí),必須由程序改變其中一個(gè)操作數(shù)。使用CMPS比較指令比較連續(xù)的字符時(shí),對由SI尋址的源串中數(shù)據(jù)與由DI尋址的目的串中數(shù)據(jù)進(jìn)行比較,執(zhí)行完一條比較指令,SI,DI將自動(dòng)調(diào)整.
REPE
例:比較兩個(gè)字符串,找出它們不相匹配的位置。
lea si, mess1 lea di, mess2 mov cx, 5 cld repe cmpsb
反向比較:
SCAS 串掃描指令
SCAS DST SCASB (字節(jié)) SCASW (字)執(zhí)行操作:
字節(jié)操作:(AL) - ((DI)), (DI)←(DI)±1
字操作:(AX) - ((DI)), (DI)←(DI)±2
例:從一個(gè)字符串中查找一個(gè)指定的字符
mess db ‘COMPUTER’lea di, mess ; -------- (ES:DI)保留串地址mov al, ‘T’ ; -------- 搜索字符mov cx, 8 ; -------- 字符長度cldrepne scasb ; -------- 這里在循環(huán)的判斷是否(CX)=0或ZF=1。條件成立即中止執(zhí)行完后
- (di):相匹配字符的下一個(gè)地址
- (cx):剩下還未比較的字符個(gè)數(shù)
子程序設(shè)計(jì)
int i=0; int main(){func();return 0; } void func(){i++; }等價(jià)于:
ASSUME CS:CODE CODE SEGMENT START:MOV AX,0 ;AX相當(dāng)于iCALL FUNC ;調(diào)用FUNC子程序MOV AH,4CHINT 21H FUNC PROC NEARINC AX ;i++RET FUNC ENDP CODE ENDS END START 子程序:在許多應(yīng)用程序中,常常需要多次使用某功能的指令序列。這時(shí),為了減少重復(fù)編寫程序,節(jié)省內(nèi)存空間,把這一功能的指令序列組成一個(gè)相對獨(dú)立的程序段。在程序運(yùn)行時(shí),如果需要使用這個(gè)給定的功能,就轉(zhuǎn)移到這個(gè)獨(dú)立的程序段,待這個(gè)獨(dú)立的程序段指令序列執(zhí)行完后,又返回到原來位置繼續(xù)運(yùn)行程序。我們把這個(gè)相對獨(dú)立的程序段就叫子程序或過程。
調(diào)用程序:編制程序時(shí),按需要轉(zhuǎn)向子程序,稱為子程序調(diào)用,或稱為過程調(diào)用。調(diào)用子程序的程序稱為調(diào)用程序或主程序。主、子程序是相對而言的。但子程序一定是受調(diào)用程序或主程序調(diào)用的。子程序定義的位置可以放在主程序的前面或后面。
過程定義偽操作
過程名 PROC NEAR or FAR……RET 過程名 ENDP說明:
- 過程名是子程序入口的符號地址;
- RET是子程序返回的命令;
- NEAR屬性:調(diào)用程序和子程序在同一代碼段中,可省略。(段內(nèi)調(diào)用)
- FAR屬性:調(diào)用程序和子程序不在同一代碼段中。(段間調(diào)用)
- 同一個(gè)子程序可以被段內(nèi)調(diào)用,也可以段間調(diào)用。
子程序的調(diào)用與返回指令
1)CALL 子程序調(diào)用指令:隱含使用堆棧保存返回地址
指令格式:CAL DST ;其中DST為過程的目標(biāo)地址(即過程名)。
指令功能:
- 把CALL指令的下一條指令地址(稱為返回點(diǎn)或斷點(diǎn)) 推入堆棧保存,然后轉(zhuǎn)到目標(biāo)地址(DST)。
- CALL指令可以在段內(nèi)、段間調(diào)用,尋址方式分為直接和間接兩種。
段內(nèi)直接近調(diào)用:CALL DST
DST給出子程序的入口地址(子程序?yàn)閚ear屬性),比如:CALL subp
執(zhí)行操作:
- (SP) ← (SP) - 2
- ( (SP)+1,(SP) ) ← (IP)
- 上面兩句相當(dāng)于PUSH IP
- (IP) ← DST
- 實(shí)際操作是把從指令中得到的距目標(biāo)過程相對偏移量加到指令指針I(yè)P上(得到子程序的入口地址),實(shí)現(xiàn)過程調(diào)用。
段內(nèi)間接近調(diào)用:CALL DST
執(zhí)行操作:
- PUSH IP
- (IP) ← (EA)
- DST給出寄存器或存儲(chǔ)單元的內(nèi)容(轉(zhuǎn)向地址)
- 比如: CALL word ptr [bx]
段間直接遠(yuǎn)調(diào)用:CALL FAR PTR DST
DST給出子程序的入口地址(子程序?yàn)閒ar屬性),比如:CALL far ptr subp
執(zhí)行操作:
- PUSH CS
- PUSH IP
- (IP) ← DST偏移地址
- (CS) ← DST段地址
段間間接遠(yuǎn)調(diào)用:CALL FAR PTR DST
DST給出存儲(chǔ)單元的內(nèi)容(轉(zhuǎn)向地址),比如: CALL dword ptr [bx]
執(zhí)行操作:
- PUSH CS
- PUSH IP
- (IP) ← (EA)
- (CS) ← (EA+2)
2)RET 返回主程序指令
說明:屬于無條件轉(zhuǎn)移指令。可以在段內(nèi)或段間返回。
段內(nèi)近返回:RET
執(zhí)行操作:
- POP IP
段內(nèi)帶立即數(shù)近返回:RET EXP
執(zhí)行操作:
- POP IP
- (SP)←(SP)+EXP
段間遠(yuǎn)返回:RET(F)
執(zhí)行操作:
- POP IP
- POP CS
現(xiàn)場保護(hù)和恢復(fù)
要保護(hù)的寄存器:應(yīng)該是在子程序中將被使用,返回調(diào)用程序后仍然需要使用其原有內(nèi)容的那些寄存器。即保護(hù)調(diào)用程序和子程序兩者在使用上發(fā)生沖突的那些寄存器。但在編程時(shí),一時(shí)很難弄清哪些是有沖突的寄存器,一種較為簡單的方法是把所有的寄存器均加以保護(hù)。
一般在子程序中進(jìn)行寄存器保護(hù)較好。即在子程序的開始部分,先進(jìn)行相關(guān)寄存器(主要是在子程序中使用的各寄存器)的保護(hù)。然后再進(jìn)行子程序的處理操作。在執(zhí)行完子程序后,返回前,先恢復(fù)各寄存器內(nèi)容后,再返回調(diào)用程序。
子程序的參數(shù)傳送
入口參數(shù):子程序需要從主程序獲取的參數(shù)。使子程序可以對不同數(shù)據(jù)進(jìn)行相同功能的處理。
出口參數(shù):是子程序返回給主程序的參數(shù)。使子程序可以將不同的結(jié)果送至主程序
實(shí)現(xiàn)的方法是把子程序所需要的入口參數(shù),由調(diào)用程序預(yù)先放入指定的寄存器中。在進(jìn)入子程序后,子程序就可直接對這些寄存器內(nèi)容進(jìn)行操作了。同樣子程序的運(yùn)行結(jié)果,也可置入寄存器中,把它們作為子程序的出口參數(shù)寄存器使用。由于寄存器數(shù)目有限,適用于參數(shù)較少的情況。
- 1) 通過寄存器傳送參數(shù)
- 2) 通過存儲(chǔ)器傳送參數(shù)
- 3) 通過地址表傳送參數(shù)地址
- 4) 通過堆棧傳送參數(shù)或參數(shù)地址
參數(shù)的傳遞方法并不是固定不變的,即它們是可以綜合使用的。依實(shí)現(xiàn)的需要和情況的不同,可以靈活使用其中一種方式,也可以同時(shí)使用幾種方式的混合。有的時(shí)候還可能并不需要參數(shù)傳遞。
; 十六進(jìn)制到十進(jìn)制的轉(zhuǎn)換(通過寄存器傳送參數(shù)) ; hexidec:接收鍵盤輸入的十六進(jìn)制數(shù),在屏幕上輸出相應(yīng)的十進(jìn)制數(shù) hexidec segment ; 16?10assume cs: hexidec main proc far start: push dssub ax, axpush axcall hexibin ; 16轉(zhuǎn)2call crlfcall binidec ; 2轉(zhuǎn)10call crlfret main endp……………… hexidec ends; 按位取數(shù) binidec proc near mov cx, 10000dcall dec_divmov cx, 1000dcall dec_divmov cx, 100dcall dec_divmov cx, 10dcall dec_divmov cx, 1dcall dec_divretbinidec endpdec_div proc nearmov ax, bxmov dx, 0div cxmov bx, dxmov dl, aladd dl, 30hmov ah, 2int 21hret dec_div endp; hexibin:接收4位十六進(jìn)制數(shù)的輸入 ; binidec:輸出5位的十進(jìn)制數(shù)值 ; 入口參數(shù)為BX。 ; 出口參數(shù)為BX。 hexibin proc near mov bx, 0mov cx,4newchar:mov ah, 1int 21hcmp al, 30h ; 0~9的16進(jìn)制表示為30~39jl exitcmp al, 3ah ; 和10比較,如果小于10的就跳轉(zhuǎn)到add_tojl add_tocmp al, 41h ; 和A比較jl exitcmp al, 47h ; 和G比較jge exitcmp al, 61h ; 和a比較jl exitcmp al, 67h ; 和g比較jge exit add_to:push cxmov cl, 4shl bx, clmov ah, 0add bx, axpop cxloop newchar exit: ret hexibin endp; 回車換行 Crlf proc nearpush axpush dxmov dl, 0dhmov ah,2int 21hmov dl, 0ahmov ah,2int 21hpop dxpop axret Crlf endpend start宏
宏:源程序中一段有獨(dú)立功能的程序代碼。在使用之前先定義一次,以后就可以多次調(diào)用。
宏指令:用戶自定義的指令。在編程時(shí),將多次使用的功能用一條宏指令來代替。
匯編語言源程序包含:
- 指令:程序運(yùn)行時(shí)執(zhí)行的語句
- 偽指令(偽操作):匯編時(shí)執(zhí)行
- 宏指令:匯編時(shí)展開
高級語言的宏
C語言中以#define作為標(biāo)志的編譯預(yù)處理命令稱為宏定義命令。其不帶參數(shù)的格式為:
其中的標(biāo)識(shí)符叫宏名,字符串叫宏體。帶參的宏一般形式為:
如:
#define PI 3.1415926 #define area(r) (3.1415926*(r)*(r))系統(tǒng)對宏的處理是這樣的:當(dāng)遇到宏名時(shí),就用宏體替換,即所謂的宏替換。這一過程是由預(yù)編譯程序完成的(不必用戶自己操作),而后才將宏替換后的程序交編譯程序進(jìn)行編譯。
宏定義、宏調(diào)用和宏展開
; 宏定義: macro_name MACRO [啞元表] ; 形參/虛參…… …… ; 宏定義體 ENDM 宏調(diào)用: (必須先定義后調(diào)用)macro_name [實(shí)元表] ; 實(shí)參
宏展開: 宏定義體->復(fù)制到宏指令位置,實(shí)參代虛參。
宏和子程序的對比
| 子程序 | 模塊化,省內(nèi)存 | 開銷大 |
| 宏 | 參數(shù)傳送簡單,執(zhí)行效率高 | 占用內(nèi)存空間大 |
宏定義中的參數(shù)
- 1、宏定義可以無變元(無參數(shù));
- 2、變元可以是常數(shù)、寄存器、存儲(chǔ)單元名以及用尋址方式能找到的地址或表達(dá)式;
- 3、變元可以是操作碼或操作碼的一部分(必須用&作為分隔符);
- 4、變元可以是ASCII串(字符串)。
- 注意:宏調(diào)用時(shí)若實(shí)參個(gè)數(shù)少于形參個(gè)數(shù)會(huì)出現(xiàn)編譯錯(cuò)誤,若實(shí)參個(gè)數(shù)多于形參,則按形參的順序填入實(shí)參,多余部分被忽略。
宏匯編操作符
| & | 符號1 & 符號2 | 宏展開時(shí),合并前后兩個(gè)符號形成一個(gè)符號。 &可以作為啞元的前綴。 |
| ;; | 宏展開的時(shí)候,;;后面的注釋不予展開。 | |
| % | % 表達(dá)式 | 匯編程序?qū)?后面的表達(dá)式轉(zhuǎn)換為當(dāng)前基數(shù)下的數(shù)字,并在展開期間用這個(gè)數(shù)取代啞元。 |
LOCAL偽操作
LOCAL偽操作為每個(gè)標(biāo)號建立唯一的符號(??0000~??FFFF),必須緊跟在MACRO語句之后,中間不允許有任何操作包括注釋。
; 宏定義 absol MACRO operLOCAL nextcmp oper,0jge nextneg oper next: ENDM ; 宏調(diào)用 …… absol var …… absol bx …… 說明:
反匯編出來內(nèi)容如下:
從上面可以看出使用了LOCAL偽操作之后,每次調(diào)用absol后,next的地址都是不同的。即 LOCAL偽操作為每個(gè)標(biāo)號建立唯一的符號。
列表偽操作
| .LALL | 在LST清單中列出宏展開后的全部語句(包括注釋)。 |
| .SALL | 在LST清單中不列出任何宏展開后的語句。 |
| .XALL | 缺省的列表方式,只列出宏體中產(chǎn)生目標(biāo)代碼的語句。 |
宏庫的建立和調(diào)用
建立宏庫
>EDIT MACRO . MAC
調(diào)用宏庫
>EDIT EXP.ASM
include MACRO.MAC …… macro1 [實(shí)元表] …… macro2 [實(shí)元表] …… ; 刪除不用的宏定義`purge macroN` macroN [實(shí)元表] ……輸入輸出程序設(shè)計(jì)
不同外設(shè)具有的端口數(shù)各不相同,計(jì)算機(jī)中為每一個(gè)端口都賦予一個(gè)惟一編號——稱為端口地址(或端口號PORT)。 8086CPU采用I/O端口獨(dú)立編址的方式,采用16位地址最多能管理64K個(gè)端口,即端口占64KB地址空間,端口號為0~65535。必須使用專門的I/O指令訪問端口。
CPU與I/O接口進(jìn)行通信是通過接口電路內(nèi)部的一組寄存器實(shí)現(xiàn)的,這些寄存器稱為端口,包括:數(shù)據(jù)端口、狀態(tài)端口和命令端口。
累加器專用傳送指令I(lǐng)N/OUT
(只能用AX或AL與端口傳送信息)
輸入指令
- IN (I/O -> CPU)
長格式:(PORT是端口地址(00~FFH))
- IN AL, PORT (字節(jié))
- IN AX, PORT (字)
執(zhí)行操作:
- (AL) <- ( PORT ) (字節(jié))
- (AX) <- ( PORT+1, PORT )(字)
短格式:
- MOV DX, PORT
- IN AL, DX (字節(jié))
- IN AX, DX (字)
執(zhí)行操作:(端口號>255時(shí),先送到DX)
- (AL) <- ( (DX) ) (字節(jié))
- (AX) <- ( (DX)+1, (DX) )(字)
輸出指令
- OUT (CPU -> I/O)
長格式:
- OUT PORT, AL (字節(jié))
- OUT PORT, AX (字)
功能:將寄存器中內(nèi)容輸出到指定端口。
短格式:
- MOV DX , PORT
- OUT DX, AL (字節(jié))
- OUT DX, AX (字)
訪問端口
in al,60h;從60h號端口讀入一個(gè)字節(jié)。
執(zhí)行時(shí)與總線相關(guān)的操作:
- ① CPU通過地址線將地址信息60h發(fā)出;
- ② CPU通過控制線發(fā)出端口讀命令,選中端口所在的芯片,并通知它,將要從中讀取數(shù)據(jù);
- ③ 端口所在的芯片將60h端口中的數(shù)據(jù)通過數(shù)據(jù)線送入CPU。
- 注意:在in和out 指令中,只能使用 ax 或al來存放從端口中讀入的數(shù)據(jù)或要發(fā)送到端口中的數(shù)據(jù)。
I/O 設(shè)備的數(shù)據(jù)傳送方式
- 1、查詢方式(程序控制方式)
- 2 、中斷方式
- 3 、DMA方式(直接存儲(chǔ)器存取方式/成組傳送方式)
查詢方式
CPU和內(nèi)存通過端口與外部設(shè)備進(jìn)行通信。CPU在執(zhí)行主程序過程中,當(dāng)需要進(jìn)行I/O操作時(shí),很難保證輸入設(shè)備已經(jīng)準(zhǔn)備好了數(shù)據(jù),或者是輸出設(shè)備已經(jīng)處在可以接收數(shù)據(jù)的狀態(tài)。因此,一般要在外部設(shè)備準(zhǔn)備就緒并且I/O接口已經(jīng)做好數(shù)據(jù)傳送的情況下,才能進(jìn)行數(shù)據(jù)傳送,這種傳送方式稱為查詢傳送方式。
查詢過程使CPU很容易與不同速度的外設(shè)實(shí)現(xiàn)速度配合,使接口電路十分簡單,適用于較少數(shù)據(jù)傳輸情況下使用。但要占用CPU大量時(shí)間去查詢I/O設(shè)備的狀態(tài)。
中斷傳輸方式
采用中斷方式, CPU執(zhí)行主程序,等待中斷的發(fā)生。I/O設(shè)備與CPU并行操作,進(jìn)行數(shù)據(jù)傳輸?shù)臏?zhǔn)備工作。當(dāng)輸入設(shè)備將數(shù)據(jù)準(zhǔn)備好,或者輸出設(shè)備空閑時(shí),便通過I/O接口向CPU發(fā)申請中斷。CPU在每執(zhí)行完一條指令之后都會(huì)檢查是否有中斷請求,只要滿足中斷響應(yīng)條件,CPU就暫停執(zhí)行當(dāng)前的程序,轉(zhuǎn)向執(zhí)行中斷處理程序,進(jìn)行數(shù)據(jù)傳送,等傳送完成后,CPU返回到被中斷的主程序,繼續(xù)進(jìn)行原來的工作。
中斷方式:需要保護(hù)現(xiàn)場和恢復(fù)現(xiàn)場,數(shù)據(jù)傳輸由CPU完成。
DMA方式——成組數(shù)據(jù)傳送方式
主要由硬件DMA控制器實(shí)現(xiàn)其傳送功能,用于一些高速的I/O設(shè)備(比如磁盤),能使I/O設(shè)備直接與存儲(chǔ)器進(jìn)行成批數(shù)據(jù)的快速傳送。
DMA方式:用DMA控制器來控制存儲(chǔ)器和I/O設(shè)備之間的數(shù)據(jù)傳送時(shí),并不經(jīng)過CPU,傳輸過程中CPU不占用總線,CPU處于原地等待。這樣,傳輸時(shí)就不需要保存斷點(diǎn)等額外操作了。另外,整個(gè)控制數(shù)據(jù)塊傳送的過程,包括地址增量和計(jì)數(shù)器減量的操作,都是由硬件控制完成的,因而大大縮短了數(shù)據(jù)傳送的控制時(shí)間,提高了整個(gè)系統(tǒng)的處理效率。
程序直接控制 I/O 方式
I/O 指令是主機(jī)與外設(shè)進(jìn)行通信的最基本途徑。DOS 功能調(diào)用和BIOS例行程序中的輸入/輸出功能也是由IN和OUT指令完成的。
例:循環(huán)測試某狀態(tài)寄存器的2位是否為1
輪流查詢幾種I/O設(shè)備
輪流查詢幾種I/O設(shè)備: DEV1: IN AL, STAT1TEST AL, STAT1_BITJZ DEV2CALL FAR PTR PROC1 DEV2: IN AL, STAT2TEST AL, STAT2_BITJZ DEV3CALL FAR PTR PROC2 DEV3: IN AL, STAT3TEST AL, STAT3_BITJZ DEV1CALL FAR PTR PROC3- 優(yōu):由程序安排或修改 設(shè)備的優(yōu)先次序
- 缺:查詢等待浪費(fèi)CPU大量有效時(shí)間
- 使用I/O指令直接控制輸入輸出比調(diào)用DOS功能或BIOS例行程序效率更高,但其對硬件的依賴性很大,所以一般的程序設(shè)計(jì)還是盡可能使用DOS或BIOS功能調(diào)用。
I/O程序舉例: CMOS RAM 芯片
PC機(jī)中有一個(gè)CMOS RAM芯片,其有如下特征:
- 1)包含一個(gè)實(shí)時(shí)鐘和一個(gè)有128個(gè)存儲(chǔ)單元的RAM存儲(chǔ)器。
- 2)該芯片靠電池供電。所以,關(guān)機(jī)后其內(nèi)部的實(shí)時(shí)鐘仍可正常工作, RAM 中的信息不丟失。
- 3)128 個(gè)字節(jié)的 RAM 中,內(nèi)部實(shí)時(shí)鐘占用0~0DH單元來保存時(shí)間信息,其余大部分單元用于保存系統(tǒng)配置信息,供系統(tǒng)啟動(dòng)時(shí)BIOS程序的讀取。
- BIOS也提供了相關(guān)的程序,使我們可以在開機(jī)的時(shí)候配置CMOS RAM 中的系統(tǒng)信息。
- 4)該芯片內(nèi)部有兩個(gè)端口,端口地址為70h和71h。CPU 通過這兩個(gè)端口讀寫CMOS RAM。
- 5)70h為地址端口,存放要訪問的CMOS RAM單元的地址; 71h為數(shù)據(jù)端口,存放從選定的CMOS RAM 單元中讀取的數(shù)據(jù),或要寫入到其中的數(shù)據(jù)。可見,CPU對CMOS RAM的讀寫分兩步進(jìn)行。
- 比如:讀CMOS RAM的2號單元:
- 1、將2送入端口70h mov al, 2,out 70h, al
- 2、從71h讀出2號單元的內(nèi)容in al, 71h
- 比如:讀CMOS RAM的2號單元:
CMOS RAM中存儲(chǔ)的時(shí)間信息
在CMOS RAM中,存放著當(dāng)前時(shí)間:
| 秒 | 00H |
| 分 | 02H |
| 時(shí) | 04H |
| 星期 | 06H |
| 日 | 07H |
| 月 | 08H |
| 年 | 09H |
這6個(gè)信息的長度都為1個(gè)字節(jié),存儲(chǔ)了用兩個(gè) BCD碼表示的兩位十進(jìn)制數(shù),高 4 位的BCD碼表示十位,低4 位的BCD 碼表示個(gè)位。
比如:00010100b表示14。
讀取CMOS RAM的信息
要讀取 CMOS RAM的信息,我們首先要向地址端口70h寫入要訪問的單元的地址:
mov al,8 out 70h,al然后從數(shù)據(jù)端口71h中取得指定單元中的數(shù)據(jù):in al,71h
中斷傳送方式
中斷:使cpu中止正在執(zhí)行的程序而轉(zhuǎn)去處理特殊事件的操作。
中斷源:引起中斷的事件。8086/8088CPU最多有256個(gè)中斷源,這些中斷源根據(jù)來自CPU的內(nèi)部還是外部分為兩大類:內(nèi)部中斷源和外部中斷源。
外中斷(硬中斷):
- 外設(shè)的 I/O 請求 —— 可屏蔽中斷INTR
- 電源掉電 / 奇偶錯(cuò) —— 非屏蔽中斷NMI
所謂不可屏蔽中斷是指該中斷請求不能通過軟件的方式對其屏蔽,一旦出現(xiàn)NMI中斷請求,CPU必須立即響應(yīng)。
內(nèi)中斷(軟中斷10H):
- INT 指令 / CPU 錯(cuò)(除法錯(cuò)、溢出)
- 為調(diào)試程序設(shè)置的中斷(t、g命令)
80x86 中斷源
(圖中引線端標(biāo)示的數(shù)字為分配的終端類型號N(0-255))
8259A外部有28個(gè)引腳。有9片8259A可構(gòu)成64級中斷源。
中斷向量表
各類型(0~0FFH)中斷處理程序的入口地址表
中斷的條件
(從外設(shè)發(fā)出中斷請求到CPU響應(yīng)中斷,有兩個(gè)控制條件起決定性作用):
- 設(shè)置CPU中斷允許位:
- FLAGS 中的IF = 1 的時(shí)候允許中斷 ( STI 開中斷)IF = 0的時(shí)候禁止中斷 ( CLI 關(guān)中斷)
- 設(shè)置中斷屏蔽位:
- 中斷屏蔽寄存器的中斷屏蔽位 = 0的時(shí)候允許I/O設(shè)備請求中斷 ,= 1 的時(shí)候禁止I/O設(shè)備請求中斷。
修改中斷處理程序
DATAS SEGMENTDATAS ENDSSTACKS SEGMENT;此處輸入堆棧段代碼 STACKS ENDSCODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKS START:MOV AX,DATASMOV DS,AXMOV AL,0MOV AH,35HINT 21HPUSH ESPUSH BX ;保存原向量PUSH DSMOV AX,SEG FUNCTIONMOV DS,AXMOV DX,OFFSET FUNCTIONMOV AL,0MOV AH,25HINT 21H ;設(shè)置新的向量POP DS ;--------------------主程序部分 …… ;------------------POP DXPOP DSMOV AL,0MOV AH,25HINT 21H ;恢復(fù)原向量 MOV AH,4CHINT 21H;--------------中斷處理程序 FUNCTION PROC NEAR…… FUNCTION ENDP CODES ENDSEND STARTCPU中斷過程
- 1)取中斷類型:CPU ← type N
- 2)保護(hù)現(xiàn)場:FLAGS、CS、IP入棧
- 3)IF=0 (關(guān)中斷), TF=0(禁止單步中斷)
- 4)計(jì)算中斷向量地址,取中斷向量:(4×N)→ IP,(4×N+2)→ CS
- 5)轉(zhuǎn)中斷處理程序
- 以上步驟都由硬件完成。采用向量中斷的方法,大大加快了中斷處理的速度。因?yàn)橛?jì)算機(jī)可直接通過中斷向量表轉(zhuǎn)向相應(yīng)的處理程序,而不需要CPU去逐個(gè)檢測和確定中斷原因。
INT
格式: int n ; n為中斷類型碼。
功能:是引發(fā)n號中斷過程。
CPU 執(zhí)行int n過程如下:
- 1)取中斷類型碼n;
- 2)標(biāo)志寄存器入棧,IF = 0,TF = 0;
- 3)CS、IP入棧;
- 4)(IP) = (n*4),(CS) = (n*4+2)。
- 從此處轉(zhuǎn)去執(zhí)行n號中斷的中斷處理程序。
或者這么理解:
- 系統(tǒng)功能號送到寄存器AH中
- 入口參數(shù)送到指定的寄存器中
- 用INT 21H指令執(zhí)行功能調(diào)用
- 根據(jù)出口參數(shù)分析功能調(diào)用執(zhí)行情況
| 4CH | 返回DOS | 無 | 無 |
| 1 | 鍵盤輸入一個(gè)字符到AL中 | 無 | AL=字符 |
| 2 | 輸出DL寄存器的字符到顯示器 | DL(存放一個(gè)字符) | 無 |
| 9 | 輸出一個(gè)以“$”結(jié)尾的字符串到顯示器 | DS:字符串所在的段地址 DX:字符串首地址 | 無 |
| 0AH | 從鍵盤輸入一個(gè)字符串到指定緩沖區(qū) | DS:緩沖區(qū)所在的段地址 DX:緩沖區(qū)首地址 | 緩沖區(qū)相應(yīng)位置 |
- 更多請見: 匯編常用的INT 21H系統(tǒng)調(diào)用
IRET
可見,INT 指令的最終功能和call指令相似,都是調(diào)用一段程序。一般情況下,系統(tǒng)將一些具有一定功能的子程序,以中斷處理程序的方式提供給應(yīng)用程序調(diào)用。
我們在編程的時(shí)候,可以用int指令調(diào)用這些子程序,而在子程序中安排iret指令返回。我們將這樣的中斷處理子程序簡稱為中斷例程。
IRET指令的執(zhí)行過程相當(dāng)于:
中斷程序的編寫步驟
中斷處理程序的編寫與子程序類似,先保護(hù)現(xiàn)場,再完成功能,然后恢復(fù)現(xiàn)場,最后用IRET指令返回,返回地址是中斷發(fā)生時(shí)緊接著的下一條指令。
中斷處理子程序:
保存寄存器內(nèi)容,如允許中斷嵌套,則開中斷 ( STI )
中斷處理功能
關(guān)中斷(CLI)
送中斷結(jié)束命令( EOI )給中斷命令寄存器
恢復(fù)寄存器內(nèi)容
IRET中斷返回
主程序:
1、設(shè)置中斷向量
2、設(shè)置 CPU 的中斷允許位IF
3、設(shè)置設(shè)備的中斷屏蔽位
注意:程序員在編程的時(shí)候可以調(diào)用系統(tǒng)設(shè)置好的中斷例程,也可以自己編寫中斷處理程序。中斷類型號0、1、3、4是固定的內(nèi)部中斷,向量2是非屏蔽中斷,向量5~31是保留給系統(tǒng)使用的中斷,向量32~255則是用戶可用的中斷。
示例
編寫一個(gè)中斷處理程序,要求在主程序運(yùn)行期間,每隔 10秒顯示一次字符串‘ bell ’。
.model small .stack .datacnt dw 182 mes db 'bell',0ah,0dh,'$'.codestart:mov ax, @datamov ds, ax mov al, 1ch mov ah, 35hint 21h ;取向量1chpush espush bx ;保存原向量push ds mov dx, offset ringmov ax, seg ringmov ds, axmov al, 1chmov ah, 25hint 21h ;設(shè)置新向量pop dsin al, 21h;中斷屏蔽寄存器and al, 11111110bout 21h, al ;增加定時(shí)器中斷sti ;開中斷DOS系統(tǒng)功能調(diào)用
執(zhí)行過程
- 系統(tǒng)功能調(diào)用的格式:
- ① 傳送入口參數(shù)到指定寄存器中(可選項(xiàng))
- ② 功能號送入AH寄存器
- ③ INT 21H
- INT 21H是一個(gè)具有近90個(gè)子功能的中斷服務(wù)程序,這些子功能的編號稱為功能號。
- INT 21H的功能大致可以分為四個(gè)方面,即設(shè)備管理、目錄管理、文件管理和其他
BIOS和DOS中斷
BIOS是固化在PC機(jī)內(nèi)存地址0FE000開始的8KBROM中的基本輸入輸出系統(tǒng)的例行程序,它為PC系列的不同微處理器提供了兼容的系統(tǒng)加電自檢、引導(dǎo)裝入、主要I/O設(shè)備的處理程序以及接口控制等功能模塊,一般以中斷處理程序的形式存在。BIOS可以處理所有的系統(tǒng)中斷,如鍵盤、顯示器、磁盤、打印、日期與時(shí)間等。BIOS是模塊化的結(jié)構(gòu)形式,每個(gè)功能模塊的入口地址都在中斷向量表中,對這些中斷調(diào)用是通過軟中斷指令I(lǐng)NT來實(shí)現(xiàn)的。
DOS是IBM PC機(jī)的磁盤操作系統(tǒng),由軟盤或硬盤提供。它的兩個(gè)DOS模塊IBMBIO.COM和IBMDOS。COM使BIOS使用起來更方便。其中模塊IBMBIO.COM是一個(gè)輸入輸出設(shè)備處理程序,提供DOS到BIOS的低級接口,模塊IBMDOS。COM包括一個(gè)文件管理程序和一些處理程序,把信息傳送給IBMBIO.COM,形成BIOS調(diào)用。因?yàn)镈OS模塊提供了更多更必要的測試,使DOS操作比使用相應(yīng)功能的BIOS操作更簡易,而且DOS對硬件的依賴性更少些。
用戶編程原則
- ①盡可能使用DOS的系統(tǒng)功能調(diào)用,提高程序可移植性。
- ②在DOS功能不能實(shí)現(xiàn)的情況下,考慮用BIOS功能調(diào)用。(比如讀打印機(jī)狀態(tài):BIOS中斷17H的功能2)
- ③在DOS和BIOS的中斷子程序不能解決問題時(shí), 才使用IN/OUT指令直接控制硬件。(比如聲音控制)
中斷例程調(diào)用方法
一般來說,中斷例程中包含多個(gè)子程序,內(nèi)部用AH傳遞子程序的編號來決定執(zhí)行哪個(gè)子程序。
鍵盤I/O
- 大多數(shù)有用的程序都需要處理用戶的輸入。
- 鍵盤輸入寄存器的端口地址為60H,控制寄存器的端口地址為61H。
- 鍵盤上的每個(gè)鍵都有一個(gè)掃描碼(01~83)。
- ◢ 據(jù)掃描碼可確定操作的是哪個(gè)鍵、是按下鍵還是釋放鍵;
- 掃描碼用一個(gè)字節(jié)表示。低7位是掃描碼的數(shù)字編碼(即在鍵盤上的位置), 最高位D7位表示鍵的操作狀態(tài):
- 當(dāng)按下鍵時(shí), D7=0 ,取得通碼;
- 當(dāng)釋放鍵時(shí), D7=1,取得斷碼。
- 鍵盤通過鍵盤接口電路與計(jì)算機(jī)連接。 當(dāng)在鍵盤上“按下”或“放開”一個(gè)鍵時(shí),如果鍵盤中斷是允許的(21H端口的1位等于0),就會(huì)產(chǎn)生一個(gè)類型9的中斷,并轉(zhuǎn)入到BIOS的鍵盤中斷處理程序。
BIOS鍵盤中斷處理程序功能
- ◢ 從鍵盤接口(60H)讀取操作鍵的掃描碼;
- ◢ 將掃描碼轉(zhuǎn)換成字符碼(大部分鍵的字符碼即相應(yīng)字符的ASCII碼,沒有相應(yīng)ASCII碼的鍵字符碼為0。 );
- ◢ 將鍵的掃描碼、字符碼存放在ROM BIOS數(shù)據(jù)區(qū)的鍵盤緩沖區(qū)KB_BUFFER( 0040:001A ), 供其它有關(guān)鍵盤的中斷子程應(yīng)用。
BIOS鍵盤中斷(INT 16H)
| 0 | 從鍵盤讀一字符 | AL=字符碼,AH=掃描碼 |
| 1 | 讀鍵盤狀態(tài)并檢查是否有字符輸入 | 如按下ZF=0,AL=字符碼,AH=掃描碼,否則ZF=1,緩沖區(qū)空 |
| 2 | 取鍵盤狀態(tài)字節(jié) | AH=00,AL=鍵盤狀態(tài)字節(jié)(KB_FLAG) |
比如指令序列:
MOV AH, 0 INT 16H ;等待按鍵輸入然后取得掃描碼和字符碼 MOV BX,AX ;用BX傳遞參數(shù) CALL BINIHEX ;調(diào)用子程序?qū)X轉(zhuǎn)16進(jìn)制并顯示使用int 16h中斷例程讀取鍵盤緩沖區(qū)
- int 16h 中斷例程的 0 號功能,進(jìn)行如下的工作:
- 1)檢測鍵盤緩沖區(qū)中是否有數(shù)據(jù);
- 2)沒有則繼續(xù)做第1 步;
- 3)讀取緩沖區(qū)第一個(gè)字單元中的鍵盤輸入;
- 4)將讀取的掃描碼送入ah,ASCII 碼送入al;
- 5)將己讀取的鍵盤輸入從緩沖區(qū)中刪除。
- 可見,B1OS 的int 9 中斷例程和int 16h 中斷例程是一對相互配合的程序,int 9 中斷例程向鍵盤緩沖區(qū)中寫入,int 16h 中斷例程從緩沖區(qū)中讀出。
DOS鍵盤中斷(INT 21H)
| 1 | 從鍵盤輸入一個(gè)字符并回顯在屏幕上 | AL =字符 | |
| 6 | 讀鍵盤字符,不回顯 | DL = 0FFH | 若有字符可取,AL=字符,ZF=0 若無字符可取,AL=0,ZF=1 |
| 7 | 從鍵盤輸入一個(gè)字符,不回顯 | AL =字符 | |
| A | 輸入字符到緩沖區(qū) | DS:DX = 緩沖區(qū)首址 | (DX+1)=實(shí)際輸入字符數(shù) |
| B | 檢驗(yàn)鍵盤狀態(tài) | AL=0表示有輸入 ,AL=FF表示無輸入 |
0AH功能的注意事項(xiàng)
- ◢ 輸入的字符均帶回顯,且光標(biāo)隨字符移動(dòng)。當(dāng)輸入回車符結(jié)束時(shí),也回顯回車符。表現(xiàn)為功能調(diào)用結(jié)束后,光標(biāo)回到了行首。
- ◢ 回車符0DH作為一個(gè)輸入的字符存放在字符串尾,但計(jì)算輸入個(gè)數(shù)時(shí),不包括回車鍵。實(shí)際最多能輸入的字符數(shù) = 限制的最多數(shù)-1 (回車符占一個(gè))
- ◢ 執(zhí)行完0AH功能后,DS和DX的值不變, DS:DX仍指向緩沖區(qū)的首地址。
- ◢ 整個(gè)緩沖區(qū)的大小應(yīng)為:限制的最多數(shù) +2,max DB 11, ? , 11 dup (?),緩沖區(qū)必須定義為字節(jié)類型,不能定義為字類型。
顯示器I/O
- 1、顯示器通過顯卡(顯示適配器)連接到計(jì)算機(jī)上。
- 2、單色顯示適配器只能顯示黑白兩色。只能顯示ASCII碼字符和一些簡單字符圖形。
- 3、彩色顯示適配器能以紅、綠、藍(lán)彩色顯示以點(diǎn)繪制的圖形以及ASCII字符。
- 4、顯示器有兩種顯示方式:
- 文本方式:
- 指以字符為單位顯示的方式,字符通常是指字母、數(shù)字、普通符號和一些特殊符號(如矩形塊等)。
- 圖形方式:
- 指以點(diǎn)為單位顯示的方式。一個(gè)點(diǎn)就是一個(gè)像素。
- 文本方式:
- 5、屏幕上各象素的顯示信息,存放在顯示緩沖區(qū)(顯存)中。
文本方式
將屏幕劃分為 m列和n行 (m × n),在每個(gè)網(wǎng)格位置上顯示像素,一個(gè)字符是一個(gè)像素。在這種顯示方式下,顯示緩沖存儲(chǔ)區(qū)中存放的是字符的ASCII碼和對應(yīng)的顯示屬性,每個(gè)字符占用兩個(gè)字節(jié)的空間。
圖形方式:
將屏幕劃分為 m×n的點(diǎn)陣,在每個(gè)點(diǎn)的位置顯示像素,一個(gè)點(diǎn)是一個(gè)像素。顯示緩沖存儲(chǔ)區(qū)中存放的是“像素”點(diǎn)的信息,它的值為“0”或者“1”,為“0”就不在屏幕上打點(diǎn),為“1”則在屏幕上打點(diǎn)。
文本方式屬性字節(jié)的含義
DOS顯示功能調(diào)用中斷(INT 21H)
| 2 | 顯示一個(gè)字符(檢驗(yàn)Ctrl-Break) | DL = 字符 光標(biāo)跟隨字符移動(dòng) |
| 6 | 顯示一個(gè)字符(不檢驗(yàn)Ctrl-Break) | DL = 字符 光標(biāo)跟隨字符移動(dòng) |
| 9 | 顯示字符串 | DS:DX=串地址 串必須以$結(jié)束,光標(biāo)跟隨串移動(dòng) |
顯示存儲(chǔ)器
MDA顯存的起始地址為B000:0000,CGA、EGA、VGA的是B800:0000。 1屏幕的字符數(shù)據(jù)稱為1頁數(shù)據(jù)。據(jù)顯存大小,可存儲(chǔ)若干頁的字符象素。
例: 16KB 顯存能存儲(chǔ):(1000B=1KB)
25×80方式,4頁( 0 ~ 3 ), 80×25×2×4 =16000
25×40方式,8頁( 0 ~ 7 ), 40×25×2×8 =16000
對CGA、EGA、VGA的80列顯示方式,0頁顯存中的起始地址是B800:0000, 1頁B800:1000, 2頁B800:2000,3頁B800:3000。屏幕上某一字符位置在顯存中的偏移地址計(jì)算公式:
Char_offset=Page_offset+((row*width)+column)*byte
字符偏移地址=頁偏移地址+((行號 * 行寬)+列號)* 2
BIOS顯示中斷(INT 10H)
功能號 AH=0,1, 2, 3, 5, 6, 7, 8, 9, 0AH, 0EH 13H
設(shè)置顯示方式
- 1.入口參數(shù) AL = 顯示方式值
| 00 | 40×25 | 黑白文本方式 |
| 01 | 40×25 | 彩色文本方式 |
| 02 | 80×25 | 黑白文本方式 |
| 03 | 80×25 | 彩色文本方式 |
| 04 | 320×320 | 彩色圖形方式 |
- 2.功能號 AH = 00H
- 3.類型號 10H
- 4.出口參數(shù) 無
5.實(shí)現(xiàn)功能 將顯示方式設(shè)置為指定的形式
例: 將顯示方式設(shè)置為 25×80彩色文本方式
控制光標(biāo)
隱藏光標(biāo)
;隱藏光標(biāo) mov ch,20h mov cl,00h mov ah,1 int 10h光標(biāo)定位
Int 10h的功能02:。
DH和DL寄存器中為光標(biāo)位置的行列號,BH中為頁號(單色顯示器頁號為0 )。
例:
讀光標(biāo)位置
功能03 :BH中指定頁號。把光標(biāo)位置的行號回送給DH,列號回送給DL,光標(biāo)大小的參數(shù)填入CH和CL 。
mov ah,3 mov bh,0 int 10h ;返回參數(shù)dh:dl=行:列清屏和卷屏
功能06(07):使屏幕內(nèi)容上卷(或下卷)指定的行。需要7個(gè)參數(shù)。
例:清除屏幕
顯示字符及字符串
功能9(0a): 把一個(gè)字符送到顯示屏幕,可直接在cx中設(shè)定顯示次數(shù),調(diào)用結(jié)束后光標(biāo)返回它的初始位置。(0a以正常屬性顯示)
功能8:讀取當(dāng)前光標(biāo)位置的字符和屬性,入口參數(shù)bh=顯示頁號,返回ah/al=字符/屬性。
例: 在品紅背景下,顯示5個(gè)淺綠色閃爍的星號。(閃爍很快幾乎覺察不到)
顯示字符串
- 功能13H:顯示字符串。
- 參數(shù):
- ES:BP=字符串地址
- AL=寫方式(0~3)
- CX=字符串長度
- DH/DL=起始行/列
- BH/BL=頁號/屬性
- 子功能號
- AL=0,1,要指定整個(gè)顯示字符串的屬性。
- AL=2,3,必須指定每個(gè)字符的屬性。
顯示系統(tǒng)時(shí)間
DATAS SEGMENTCLOCK DB 0,0,':',0,0,':',0,0,'$' DATAS ENDS CODES SEGMENTASSUME CS:CODES,DS:DATAS START:MOV AX,DATASMOV DS,AX RESTART:LEA BX,CLOCKMOV AL,4CALL GETTIMEMOV AL,2CALL GETTIMEMOV AL,0CALL GETTIME;------ 設(shè)置光標(biāo)位置MOV DH,10 ;行MOV DL,30 ;列MOV BH,0MOV AH,2INT 10H;------ 隱藏光標(biāo)MOV CH,20HMOV CL,00HMOV AH,1INT 10H;------ 輸出時(shí)間LEA DX,CLOCKMOV AH,9INT 21H ; ------ 檢測鍵盤輸入。IN AL,60HCMP AL,1JNZ RESTART ;按下ESC退出,不斷更新時(shí)間MOV AH,4CHINT 21H ; ------ 獲取時(shí)間 入口參數(shù):AL GETTIME PROC; ------ 讀取數(shù)據(jù)OUT 70H,AL ; 設(shè)定讀數(shù)地址IN AL,71H ; 取數(shù); ------ 左移四位得到十位數(shù)值MOV AH,0 ;清零MOV CL,4SHL AX,CLSHR AL,CL ; 得到個(gè)位數(shù)值 ADD AH,30H ; 轉(zhuǎn)換成ASCIIADD AL,30H ; 轉(zhuǎn)換成ASCIIMOV CLOCK[BX],AHMOV CLOCK[BX+1],ALADD BX,3 ; 跳過三個(gè)字符->':'RET GETTIME ENDP CODES ENDSEND START總結(jié)
以上是生活随笔為你收集整理的汇编语言8086笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java集合基础练习题
- 下一篇: Panasonic: FP-X0 L30