【匯編基礎】2.寄存器
一個典型的CPU(此處討論的不是某一具體的CPU)由運算器、控制器、寄存器(CPU工作原理)等器件構成,這些器件靠內部總線相連。
匯編基礎1里面所說的總線,相對于CPU內部來說是外部總線。內部總線實現CPU內部各個器件之間的聯系,外部總線實現CPU和主板上其他器件的聯系。簡單地說,在CPU中:
- 運算器進行信息處理;
- 寄存器進行信息存儲:
- 控制器控制各種器件進行工作;
- 內部總線連接各種器件,在它們之間進行數據的傳送。
對于一個匯編程序員來說,CPU中的主要部件是寄存器。寄存器是CPU中程序員可以用指令讀寫的部件。程序員通過改變各種寄存器中的內容來實現對CPU的控制。
不同的CPU,寄存器的個數、結構是不相同的。8086CPU有14個寄存器,每個寄存器有一個名稱。這些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。我們不對這些寄存器進行一次性的介紹,在課程的進行中,需要用到哪些寄存器,再介紹哪些寄存器。
2.1 通用寄存器
8086CPU的所有寄存器都是l6位的,可以存放兩個字節。AX、BX、CX、DX這4個寄存器通常用來存放一般性的數據,被稱為通用寄存器。
以AX為例,寄存器的邏輯結構如圖所示。
一個16位寄存器可以存儲一個16位的數據,數據在寄存器中的存放情況如圖2.2所示。
想一想,一個16位寄存器所能存儲的數據的最大值為多少?
8086CPU的上一代CPU中的寄存器都是8位的,為了保證兼容,使原來基于上代CPU編寫的程序稍加修改就可以運行在8086之上,8086CPU的AX、BX、CX、DX這4個寄存器都可分為兩個可獨立使用的8位寄存器來用:
- AX可分為AH和AL;
- BX可分為BH和BL;
- CX可分為CH和CL;
- DX可分為DH和DL;
以AX為例,8086CPU的16位寄存器分為兩個8位寄存器的情況如下圖所示。
AX的低8位(0位~7位)構成了AL寄存器,高8位(8位~15位)構成了AH寄存器。
AH和AL寄存器是可以獨立使用的8位寄存器。下圖展示了16位寄存器及它所分成的兩個8位寄存器的數據存儲的情況
2.2 字在寄存器中的存儲
出于對兼容性的考慮,8086CPU可以一次性處理以下兩種尺寸的數據。
- 字節:記為byte,一個字節由8個bit組成,可以存在8位寄存器中。
- 字:記為word,一個字由兩個字節組成,這兩個字節分別稱為這個字的高位字節和低位字節,如圖2.5所示。
一個字可以存在一個16位寄存器中,這個字的高位字節和低位字節自然就存在這個寄存器的高8位寄存器和低8位寄存器中。如圖2.4所示,一個字型數據20000,存在AX寄存器中,在AH中存儲了它的高8位,在AL中存儲了它的低8位。AH和AL中的數據,既可以看成是一個字型數據的高8位和低8位,這個字型數據的大小是20000;又可以看成是兩個獨立的字節型數據,它們的大小分別是78和32。
關于數制的討論
任何數據,到了計算機中都是以二進制的形式存放的。為了描述不同的問題,又經常將它們用其他的進制來表示。比如圖2.4中寄存器AX中的數據是0100111000100000,這就是AX中的信息本身,可以用不同的邏輯意義來看待它。可以將它看作一個數值,大小是20000。
當然,二進制數0100111000100000本身也可表示一個數值的大小,但人類習慣的是十進制,用十進制20000表示可以使我們直觀地感受到這個數值的大小。
十六進制數的一位相當于二進制數的四位,如0100111000100000可表示成:4(0100)、E(1110)、2(0010)、0(0000)四位十六進制數。
由于一個內存單元可存放8位數據,CPU中的寄存器又可存放m個8位的數據。也就是說,計算機中的數據大多是由1-N個8位數據構成的。很多時候,需要直觀地看出組成數據的各個字節數據的值,用十六進制來表示數據可以直觀地看出這個數據是由哪些8位數據構成的。比如20000寫成4E20就可以直觀地看出,這個數據是由4E和20兩個8位數據構成的,如果AX中存放4E20,則AH里是4E,AL里是20.這種表示方法便于許多問題的直觀分析。在以后的課程中,我們多用十六進制來表示一個數據。
在以后的課程中,為了區分不同的進制,在十六進制表示的數據的后面加H,在二進制表示的數據后面加B,十進制表示的數據后面什么也不加。如:可用3種不同的進制表示圖2.4中AX里的數據,十進制:20000,十六進制:4E20H,二進制:0100111000100000B。
2.3 幾條匯編指令
通過匯編指令控制CPU進行工作,看一下表2.1中的幾條指令。
匯編指令 | 控制CPU完成的操作 | 用高級語言的語法描述 |
mov ax,18 | 將18送入寄存器AX | AX=18 |
mov ah,78 | 將78送入寄存器AH | AH=78 |
add ax,8 | 將寄存器AX中的數值加上8 | AX=AX+8 |
mov ax,bx | 將寄存器BX中的數據送入寄存器AX | AX=BX |
add ax,bx | 將AX和BX中的數值相加,結果存在AX中 | AX=AX+BX |
注意,為了使具有高級語言基礎的讀者更好地理解指令的含義,有時會用文字描述和高級語言描述這兩種方式來描述一條匯編指令的含義。在寫一條匯編指令或一個寄存器的名稱時不區分大小寫。如:mov ax,18和MOV AX,18的含義相同;bx和BX的含義相同。
接下來看一下CPU執行表2.2中所列的程序段中的每條指令后,對寄存器中的數據進行的改變。
原AX中的值:0000H ,原BX中的值:0000H | ||
程序段中的指令 | 指令執行后AX中的數據 | 指令執行后BX中的數據 |
mov ax,4E20H | 4E20H | 0000H |
add ax,1406H | 6226H | 0000H |
mov bx,2000H | 6226H | 2000H |
add ax,bx | 8226H | 2000H |
mov bx,ax | 8226H | 8226H |
add ax,bx | 044CH | 8226H |
上表標紅的數據為什么不是1044CH嗎?為什么是044CH?
程序段中的最后一條指令add ax,bx,在執行前ax和bx中的數據都為8226H,相加后所得的值為:1044CH,但是ax為16位寄存器,只能存放4位十六進制的數據,所以最高位的1不能在ax中保存,ax中的數據為:044CH。
程序段中的指令 | 指令執行后AX中的數據 | 指令執行后BX中的數據 |
mov ax,001AH | 001AH | 0000H |
mov bx,0026H | 001AH | 0026H |
add al,bl | 0040H | 0026H |
add ah,bl | 2640H | 0026H |
add bh,al | 2640H | 4026H |
mov ah,0 | 0040H | 4026H |
add al,85H | 00C5H | 4026H |
add al,93H | 0158H | 4026H |
程序段中的最后一條指令add al,93H,在執行前,al中的數據為C5H,相加后所得的值為:158H,但是al為8位寄存器,只能存放兩位十六進制的數據,所以最高位的1丟失,ax中的數據為:0058H。(這里的丟失,指的是進位值不能在8位寄存器中保存,但是CPU并不真的丟棄這個進位值,關于這個問題,將在后面的文章中討論。)
注意,此時al是作為一個獨立的8位寄存器來使用的,和ah沒有關系,CPU在執行這條指令時認為ah和al是兩個不相關的寄存器。不要錯誤地認為,諸如add al,93H的指令產生的進位會存儲在ah中,addal,93H進行的是8位運算。
如果執行addax,93H,低8位的進位會存儲在ah中,CPU在執行這條指令時認為只有一個16位寄存器ax,進行的是16位運算。指令add ax,93H執行后,ax中的值為:0158H。
此時,使用的寄存器是16位寄存器ax,add ax,93H相當于將ax中的16位數據00c5H和另一個16位數據0093H相加,結果是16位的0158H。
在進行數據傳送或運算時,要注意指令的兩個操作對象的位數應當是一致的,例如:
mov ax,bx
mov bx,cx
mov ax,18H
mov al,18H
add ax,bx
add ax,20000
等都是正確的指令
而:
mov ax,b1(在8位寄存器和16位寄存器之間傳送數據)
mov bh,ax(在16位寄存器和8位寄存器之間傳送數據)
mov a1,20000(8位寄存器最大可存放值為255的數據)
add al,100H(將一個高于8位的數據加到一個8位寄存器中)
等都是錯誤的指令,錯誤的原因都是指令的兩個操作對象的位數不一致。