由段地址x16引發(fā)的討論
“段地址x16”有一個(gè)更為常用的說法是左移4位。計(jì)算機(jī)中的所有信息都是以二進(jìn)制的形式存儲(chǔ)的,段地址當(dāng)然也不例外。機(jī)器只能處理二進(jìn)制信息,“左移4 位”中的位,指的是二進(jìn)制位。
一個(gè)例子,一個(gè)數(shù)據(jù)為2H,二進(jìn)制形式為10B, 對其進(jìn)行左移運(yùn)算:

觀察上面移位次數(shù)和各種形式數(shù)據(jù)的關(guān)系,我們可以發(fā)現(xiàn):一個(gè)數(shù)據(jù)的二進(jìn)制形式左移1位,相當(dāng)于該數(shù)據(jù)乘以2;
一個(gè)數(shù)據(jù)的二進(jìn)制形式左移N位,相當(dāng)于該數(shù)據(jù)乘以2的N次方;
地址加法器如何完成段地址x16的運(yùn)算?就是將以二進(jìn)制形式存放的段地址左移4位。
一個(gè)數(shù)據(jù)的十六進(jìn)制形式左移1位,相當(dāng)于乘以16;? 一個(gè)數(shù)據(jù)的十進(jìn)制形式左移1位,相當(dāng)于乘以10;一個(gè)X進(jìn)制的數(shù)據(jù)左移1位,相當(dāng)于乘以X。
“段地址x16+偏移地址=物理地址”的本質(zhì)含義
討論的是8086CPU段地址和偏移地址的本質(zhì)含義,而不是為了解決具體的問題而在本質(zhì)含義之上引申出來的更高級的邏輯意義。不管以多少種不同的邏輯意義去看待“段地址x16+偏移地址=物理地址”的尋址模式,一定要清楚地知道它的本質(zhì)含義,這樣才能更靈活地利用它來分析、解決問題。如果只拘泥于某一種引申出來的邏輯含義,而模糊本質(zhì)含義的話,將從意識(shí)上限制對這種尋址功能的靈活應(yīng)用。
“段地址x16+偏移地址=物理地址”的本質(zhì)含義是: CPU在訪問內(nèi)存時(shí),用一個(gè)基礎(chǔ)地址(段地址x16)和一個(gè)相對于基礎(chǔ)地址的偏移地址相加,給出內(nèi)存單元的物理地址。
8086CPU的這種尋址功能是“基礎(chǔ)地址+偏移地址=物理地址”尋址模式的一-種具體實(shí)現(xiàn)方案。8086CPU中, 段地址x16可看作是基礎(chǔ)地址。
段的概念
其實(shí),內(nèi)存并沒有分段,段的劃分來自于CPU,由于8086CPU用“基礎(chǔ)地址(段地址x16)+偏移地址=物理地址”的方式給出內(nèi)存單元的物理地址,使得我們可以用分段的方式來管理內(nèi)存。如圖所示,我們可以認(rèn)為:地址10000H~ 100FFH的內(nèi)存單元組成一個(gè)段,該段的起始地址(基礎(chǔ)地址)為10000H, 段地址為1000H, 大小為100H;我們也可以認(rèn)為地址10000H~ 1007FH、10080H~ 10FFH的內(nèi)存單元組成兩個(gè)段,它們的起始地址(基礎(chǔ)地址)為:10000H 和10080H,段地址為: 1000H 和1008H,大小都為80H。

在編程時(shí)可以根據(jù)需要,將若干地址連續(xù)的內(nèi)存單元看作一個(gè)段,用段地址x16定位段的起始地址(基礎(chǔ)地址),用偏移地址定位段中的內(nèi)存單元。有兩點(diǎn)需要注意:段地址x16必然是16 的倍數(shù),所以一個(gè)段的起始地址也一定是16 的倍數(shù);偏移地址為16位,16位地址的尋址能力為64KB,所以一個(gè)段的長度最大為64KB
內(nèi)存單位地址小結(jié)
CPU訪問內(nèi)存單元時(shí),必須向內(nèi)存提供內(nèi)存單元的物理地址。8086CPU在內(nèi)部用段地址和偏移地址移位相加的方法形成最終的物理地址。
CPU可以用不同的段地址和偏移地址形成同一個(gè)物理地址。
比如CPU要訪問21F60H單元,則它給出的段地址SA和偏移地址EA滿足SAx16+EA=21F60H即可。
如果給定一個(gè)段地址,儀通過變化偏移地址來進(jìn)行尋址,最多可定位多少個(gè)內(nèi)存單元?
結(jié)論:偏移地址16位,變化范圍為0~FFFFH,僅用偏移地址來尋址最多可尋64KB個(gè)內(nèi)存單元。比如給定段地址1000H,用偏移地址尋址,CPU的尋址范圍為: 10000H~1FFFFH。
在8086PC機(jī)中,存儲(chǔ)單元的地址用兩個(gè)元素來描述,即段地址和偏移地址。
“數(shù)據(jù)在21F60H內(nèi)存單元中。”這句話對于8086PC機(jī)-般不這樣講,取而代之的是兩種類似的說法:1.數(shù)據(jù)存在內(nèi)存2000:1F60單元中;2.數(shù)據(jù)存在內(nèi)存的2000H段中的1F60H單元中。這兩種描述都表示“數(shù)據(jù)在內(nèi)存21F60H單元中”。
可以根據(jù)需要,將地址連續(xù)、起始地址為16的倍數(shù)的一組內(nèi)存單元定義為一個(gè)段。
段寄存器
8086CPU在訪問內(nèi)存時(shí)要由相關(guān)部件提供內(nèi)存單元的段地址和偏移地址,送入地址加法器合成物理地址。需要看一下,是什么部件提供段地址。段地址在8086CPU的段寄存器中存放。8086CPU 有4個(gè)段寄存器: CS、DS、SS、ES。當(dāng)8086CPU要訪問內(nèi)存時(shí)由這4個(gè)段寄存器提供內(nèi)存單元的段地址。
CS和IP
CS和IP是8086CPU中兩個(gè)最關(guān)鍵的寄存器,它們指示了CPU當(dāng)前要讀取指令的地址。CS為代碼段寄存器,IP 為指令指針寄存器,從名稱上我們可以看出它們和指令的關(guān)系。在8086PC機(jī)中,任意時(shí)刻, 設(shè)CS中的內(nèi)容為M,IP 中的內(nèi)容為N,8086CPU 將從內(nèi)存Mx16+N單元開始,讀取一條指令并執(zhí)行。
也可以這樣表述: 8086 機(jī)中,任意時(shí)刻,CPU將CS:IP指向的內(nèi)容當(dāng)作指令執(zhí)行。
圖展示了8086CPU 讀取、執(zhí)行指令的工作原理(圖中只包括了和所要說明的問題密切相關(guān)的部件,圖中數(shù)字都為十六進(jìn)制)。

8086CPU當(dāng)前狀態(tài): CS中的內(nèi)容為2000H,IP 中的內(nèi)容為0000H;
內(nèi)存20000H~20009H單元存放著可執(zhí)行的機(jī)器碼;
內(nèi)存20000H~20009H單元中存放的機(jī)器碼對應(yīng)的匯編指令如下。
地址:20000H~20002H,內(nèi)容: B8 23 01,長度: 3Byte, 對應(yīng)匯編指令:mov ax,0123H
地址: 20003H~20005H,內(nèi)容: BB 03 00,長度: 3Byte, 對應(yīng)匯編指令: mov bx,0003H
地址: 20006H~ 20007H,內(nèi)容: 89 D8,長度: 2Byte, 對應(yīng)匯編指令: mov ax,bx
地址: 20008H~20009H,內(nèi)容: 01 D8,長度: 2Byte, 對應(yīng)匯編指令: add ax,bx
下面的一組圖(圖2.11~圖2.19),以圖2.10描述的情況為初始狀態(tài),展示了8086CPU讀取、執(zhí)行一條指令的過程。注意每幅圖中發(fā)生的變化(下面對8086CPU 的描述,是在邏輯結(jié)構(gòu)、宏觀過程的層面上進(jìn)行的,目的是使讀者對CPU工作原理有一個(gè)清晰、 直觀的認(rèn)識(shí),為匯編語言的學(xué)習(xí)打下基礎(chǔ)。其中隱蔽了CPU的物理結(jié)構(gòu)以及具體的工作細(xì)節(jié))。







(讀取一條指令后,IP中的值自動(dòng)增加,以使CPU可以讀取下一條指令。因當(dāng)前讀入的指令B82301長度為3個(gè)字符,所以IP中的值加3。此時(shí),CS:IP指向內(nèi)存單元 2000:0003。)


下面的一組圖(圖 2.20-圖2.26),以圖2.19的情況為初始狀態(tài),展示了8086CPU 繼續(xù)讀取、執(zhí)行3條指令的過程。注意IP的變化(下面的描述中,隱蔽了讀取每條指令的細(xì)節(jié))。







8086CPU的工作過程簡要描述如下
(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)存FFFOH單元中讀取指令執(zhí)行,F(xiàn)FFF0H 單元中的指令是8086PC機(jī)開機(jī)后執(zhí)行的第一條指令。
我們更清楚了CS和IP的重要性,它們的內(nèi)容提供了CPU要執(zhí)行指令的地址。
在內(nèi)存中,指令和數(shù)據(jù)沒有任何區(qū)別,都是進(jìn)制信息, CPU在工作的時(shí)候把有的信息看作指令,有的信息看作數(shù)據(jù)?,F(xiàn)在,如果提出一個(gè)問題: CPU根據(jù)什么將內(nèi)存中的信息看作指令?如何回答?我們可以說,CPU 將CS:IP指向的內(nèi)存單元中的內(nèi)容看作指令,因?yàn)?,在任何時(shí)候,CPU將CS、IP中的內(nèi)容當(dāng)作指令的段地址和偏移地址,用它們合成指令的物理地址,到內(nèi)存中讀取指令碼,執(zhí)行。如果說,內(nèi)存中的一段信息曾被CPU執(zhí)行過的話,那么,它所在的內(nèi)存單元必然被CS:IP指向過。
修改CS、 IP的指令
在CPU中,程序員能夠用指令讀寫的部件只有寄存器,程序員可以通過改變寄存器中的內(nèi)容實(shí)現(xiàn)對CPU的控制。CPU從何處執(zhí)行指令是由CS、IP中的內(nèi)容決定的,程序員可以通過改變CS、IP 中的內(nèi)容來控制CPU執(zhí)行目標(biāo)指令。
我們?nèi)绾胃淖僀S、IP 的值呢?8086CPU 必須提供相應(yīng)的指令。我們?nèi)绾涡薷腁X中的值?可以用mov指令,如mov ax,123 將ax中的值設(shè)為123,顯然,我們也可以用同樣的方法設(shè)置其他寄存器的值,如mov bx,123, movex,123, movdx, 123等。其實(shí),8086CPU大部分寄存器的值,都可以用mov指令來改變,mov指令被稱為傳送指令。
但是,mov 指令不能用于設(shè)置CS、IP 的值,原因很簡單,因?yàn)?086CPU沒有提供這樣的功能。8086CPU為CS、IP提供了另外的指令來改變它們的值。能夠改變CS、IP的內(nèi)容的指令被統(tǒng)稱為轉(zhuǎn)移指令。
一個(gè)最簡單的可以修改CS、IP的指令: jmp 指令。
若想同時(shí)修改CS、IP 的內(nèi)容,可用形如“jmp段地址:偏移地址”的指令完成,如
jmp 2AE3:3,執(zhí)行后: CS=2AE3H, IP=0003H, CPU將從2AE33H處讀取指令。
jmp 3:0B16,執(zhí)行后: CS=0003H,IP=0B16H,CPU將從00B46H處讀取指令。
“jmp段地址:偏移地址”指令的功能為:用指令中給出的段地址修改CS,偏移地址修改IP。
若想僅修改IP的內(nèi)容,可用形如“jmp某一合法寄存器” 的指令完成,
jmp ax,指令執(zhí)行前:ax=1000H,CS=2000H,IP=00030
指令執(zhí)行后: ax=100 CS=2000H,IP=1000H
jmp bx,指令執(zhí)行前: bx=0B16H,CS=2000H,IP=0003H
指令執(zhí)行后: bx= 0B16H,CS=2000H, IP=0B16H
“jmp某一合法寄存器” 指令的功能為:用寄存器中的值修改IP
jmp ax,在含義上好似: mov IP,ax。
我們在適當(dāng)?shù)臅r(shí)候,會(huì)用已知的匯編指令的語法來描述新學(xué)的匯編指令的功能。采用一種“用匯編解釋匯編”的方法更好地理解匯編指令的功能,這樣做有助于進(jìn)行知識(shí)的相互融會(huì)。要強(qiáng)調(diào)的是,我們是用“已知的匯編指令的語法”進(jìn)行描述,并不是用“已知的匯編指令”來描述,比如,我們用mov IP,ax 來描述jmp ax,并不是說真有mov IP,ax 這樣的指令,而是用mov指令的語法來說明jmp指令的功能。我們可以用同樣的方法描述jmp 3:01B6 的功能: jmp 3:01B6 在含義上好似mov CS,3 movIP,01B6。
內(nèi)存中存放的機(jī)器碼和對應(yīng)的匯編指令情況如圖2.27所示,設(shè)CPU初始狀態(tài):CS=2000H,IP=0000H,請寫出指令執(zhí)行序列。思考后看分析。

(1) 當(dāng)前CS=2000H,IP=0000H則CPU從內(nèi)存2000Hx 16+0 2000H處讀取指令,讀入的指令是: B8 22 66(mov x,6622),讀入后IP=IP+3=0003H;
(2) 指令執(zhí)行后,CS=2000H, IP=0003H則CPU從內(nèi)存2000Hx16+0003H=20003H處讀取指令,讀入的指令是: EA 03 00 00 10(jmp 1000:0003),讀入后IP=IP+5=0008H;
(3)指令執(zhí)行后,CS=1000H,IP =0003H,則CPU從內(nèi)存1000Hx16+0003H= 10003H處讀取指令,讀入的指令是: B8 00 00(mov ax,0000),讀入后IP=IP+3=0006H;
(4) 指令執(zhí)行后,CS=1000H,IP=0006H, 則CPU從內(nèi)存1000H x 16+0006H= 10006H處讀取指令,讀入的指令是: 8B D8(mov bx,ax),讀入后IP=IP+2=0008H;
(5)指令執(zhí)行后,CS=1000H,IP 0008H,則CPU從內(nèi)存1000Hx16+0008H= 10008H處讀取指令,讀入的指令是: FF E3(jmp bx),讀入后IP=IP+2=000AH;
(6)指令執(zhí)行后,CS= 1000H,IP=0000H,CPU從內(nèi)存10000H處讀取指令.....
經(jīng)分析后,可知指令執(zhí)行序列為:
(1) mov ax,6622H
(2) jmp 1000:3
(3) mov ax,0000
(4)mov bx,ax
(5) jmp bx
(6)mov ax,0123H
(7)轉(zhuǎn)到第3步執(zhí)行
代碼段
前面講過,對于8086PC機(jī),在編程時(shí),可以根據(jù)需要,將一組內(nèi)存單元定義為一個(gè)段。我們可以將長度為N(N<=64KB)的一組代碼, 存在一組地址連續(xù)、 起始地址為16的倍數(shù)的內(nèi)存單元中,我們可以認(rèn)為,這段內(nèi)存是用來存放代碼的,從而定義了一個(gè)代碼段。比如,將:

這段長度為10 個(gè)字節(jié)的指令,存放在123B0H~4123B9H 的一組內(nèi)存單元中,我們就可以認(rèn)為,123B0H~123B9H 這段內(nèi)存是用來存放代碼的,是一個(gè)代碼段,它的段地址為123BH,長度為10 個(gè)字節(jié)。
如何使得代碼段中的指令被執(zhí)行呢?將一段內(nèi)存當(dāng)作代碼段,僅僅是我們在編程時(shí)的一種安排,CPU并不會(huì)由于這種安排,就自動(dòng)地將我們定義的代碼段中的指令當(dāng)作指令來執(zhí)行。CPU只認(rèn)被CS:IP指向的內(nèi)存單元中的內(nèi)容為指令。所以,要讓CPU執(zhí)行我們放在代碼段中的指令,必須要將CS:IP指向所定義的代碼段中的第一條指令的首地址。 對于上面的例子,我們將段代碼存放 在123B0H~ 123B9H 內(nèi)存單元中,將其定義為代碼段,如果要讓這段代碼得到執(zhí)行,可設(shè)CS=123BH、IP=0000H。
小結(jié)
(1)段地址在8086CPU的段寄存器中存放。當(dāng)8086CPU要訪問內(nèi)存時(shí),由段寄存器提供內(nèi)存單元的段地址。8086CPU 有4個(gè)段寄存器,其中CS用來存放指令的段地址。
(2) CS存放指令的段地址,IP 存放指令的偏移地址。
8086機(jī)中,任意時(shí)刻,CPU將CS:IP指向的內(nèi)容當(dāng)作指令執(zhí)行。
(3) 8086CPU的工作過程:
①從CS: IP指向的內(nèi)存單元讀取指令,讀取的指令進(jìn)入指令緩沖器;
②IP 指向下一條指令;
③執(zhí)行指令。(轉(zhuǎn)到步驟①,重復(fù)這個(gè)過程。)
(4)8086CPU提供轉(zhuǎn)移指令修改CS、IP的內(nèi)容。