1.2.3 8086的存儲器組織
個人計算機主板上的主存條和一個ROM芯片構成主存儲器,保存正在運行使用的指令和數據。處理器從存儲器讀取指令,在執行指令的過程中讀寫數據。對存儲器的基本操作是按照要求向指定地址(位置)存進(即寫入Write)或取出(即讀出Read)信息。應該注意的是,存儲器內容不會因為被讀出而消失,所以更準確地說是獲取其副本,而且可以重復取出;只有存入新的信息后,原有信息才會被更改。
1. 存儲單元和存儲單位
主存儲器是一個很大的信息儲存庫,被劃分成許多存儲單元。為了區分和識別各個存儲單元,并按指定位置進行存取,就給每個存儲單元編排一個順序號碼,稱為存儲單元地址或存儲器地址(Memory Address)。現代計算機中,主存儲器的每個存儲單元具有一個地址,保存一個字節(8個二進制位)的信息,這稱為字節編址(Byte Addressable),也直譯為字節可尋址,因為通過一個存儲器地址可以訪問到一個字節信息。
計算機中信息的基本單位是一個二進制位(bit,中文譯為比特),一般使用小寫字母 b表示,一個二進制位可表示一位二進制數:0 或 1。8 個二進制位組成一個字節(Byte),常用大寫字母B表示,位編號由右向左(由低位向高位)從0開始遞增計數為D0~D7,如圖1-6所示。8086是16位結構的處理器(即字長為16位),主要處理的數據長度是16位;所以稱16個二進制位為一個字(Word),位編號自右向左為D0~D15。一個16位字由2個字節組成。32位數據由4個字節組成,稱為雙字(Double Word),位編號自右向左為D0~D31。
一個二進制數據的右邊最低位稱為最低有效位LSB(Least Significant Bit),即D0位;左邊最高位稱為最高有效位MSB(Most Significant Bit),對應字節、字、雙字長度的數據依次指D7、D15和D31位。
主存儲器使用字節作為基本存儲單位,表1-3羅列了表達更大的存儲容量時常使用的單位及關系。雖然借用了日常生活中千、兆、吉等單位,但沒有使用其103的十進制倍數關系,而是使用 210=1024 的二進制倍數關系(近似等于 103=1000)。但有些產品,例如硬盤、U盤的生產廠商給出容量卻采用103倍數關系,注意分辨。
表1-3 常用存儲單位
主存條和ROM芯片構成的主存儲器需要處理器通過總線進行訪問,被稱為物理存儲器。物理存儲器的每個存儲單元有一個唯一的地址,就是物理地址(Physical Address)。物理地址空間從0開始順序編排,直到處理器支持的最大存儲單元。
我們知道一個二進制位有0和1兩種狀態,即2(=21)個編碼;那么,2位有00、01、10和11共4(22)個編碼,以此類推,借助排列組合知識,可以得到N位有2N個編碼。計算機使用數字信號傳輸信息,一個數字信號也只有低電平和高電平兩個狀態,可以分別用0和1表達,所以N位數字信號同樣也有2N個不同的編碼。如果用N個數字信號傳輸訪問存儲器的地址信息,就可以區別出2N個不同的存儲單元,也就是說可以直接訪問到2N個存儲單元。
8086處理器具有20位地址總線,即用20個數字信號訪問存儲器,故8086可以支持220,即1M個存儲單元。由于每個存儲單元保存一個字節數據,所以8086可以支持1MB存儲器容量,其物理地址空間是0~220?1。地址(編號)習慣用十六進制數表達,20位數字信號對應二進制20位,可以用5位十六進制數表達為:00000H~FFFFFH,參見圖1-7左側所示。
但是,8086處理器只有16位寄存器,沒有設計可以完整保存20位物理地址的寄存器。而使用二進制16位(對應十六進制4位)表示存儲器地址,可以表達的存儲器容量是64KB (=216字節),范圍是:0000H~FFFFH。
于是,8086處理器將1MB物理存儲器空間分成許多不超過64KB的區域進行管理,這種區域被稱為(區)段(Segment)。段用于8086內部和程序設計中,所以常被稱為邏輯段。
由于規定每段最大64KB,段內的存儲單元就可以使用16位地址表示。同時,8086處理器還規定每個段只能起始于低4位(二進制)全為0的物理地址位置,這種地址是模16地址,也就是可以被 16 整除的地址(用十進制表達是:0、16、2×16、3×16……),用十六進制表達是:XXXX0H(X表示十六進制一位,可以是0~F任何值)。既然段起始地址的低4位都是0(對應十六進制是一位0),可以省略不用表達,那這個20位物理地址就可以只表達出高16位。
這樣,某個存儲單元還可以通過它所在的(區)段及在該段中的位置指示,這就是在8086內部以及編程中使用的邏輯地址(Logical Address),它包括段基地址和偏移地址,都可以使用 16 位表示。段基地址(常簡稱段地址)確定該段在主存中的起始地址。以段基地址為起點,段內的位置可以用距離該起點的位移量表示,稱為偏移地址(Offset)。
邏輯地址常借用MASM匯編程序的方法,使用英文冒號“:”分隔段基地址和偏移地址,形如“段基地址:偏移地址”。并且在 8086 中,段基地址常只表達高 16 位。例如邏輯地址“1460H:0100H”表示段基地址是1460H,即該存儲單元所在的段起始于物理地址14600H;該存儲單元的偏移地址是0100H,說明它位于距離段起始位置的0100H處,參見圖1-7中間所示。
編程使用的邏輯地址由8086總線接口單元BIU的地址加法器電路轉換為物理地址,然后通過處理器引腳輸出外部訪問物理存儲器。進行轉換時,兩個 16 位組成的邏輯地址中的段地址需要左移4位(十六進制一位),加上偏移地址才能得到20位物理地址。例如某存儲單元的邏輯地址是“1460H:0100H”,其物理地址是14700H,參見圖1-7右邊所示。
某個存儲單元可以處于不同起點的邏輯段中(當然對應的偏移地址也就不同),所以可以有多個邏輯地址,但只有一個唯一的物理地址。或者說,同一個物理地址可以有多個邏輯地址。例如,物理地址14700H還可以用邏輯地址“1380H:0F00H”表示,該段起始于13800H,參見圖1-7所示。
3. 應用程序的基本段
8086設計有4種類型的邏輯段實現存儲器的分段管理,有4個段寄存器保存對應段的段基地址(注意,只是保存高16位),如表1-4所示。
表1-4 8086的4種邏輯段
程序的指令代碼必須安排在代碼段,否則將無法正常執行。程序利用代碼段寄存器 CS獲得當前代碼段的段基地址,指令指針寄存器IP保存代碼段中指令的偏移地址。處理器利用CS:IP取得下一條要執行的指令。
程序使用的堆棧(臨時存放數據的區域)一定在堆棧段。程序利用SS獲得當前堆棧段的段基地址,堆棧指針寄存器SP保存堆棧棧頂的偏移地址。處理器利用SS:SP操作堆棧數據。
一個程序可以使用多個數據段,便于安全有效地訪問不同類型的數據。例如,程序的主要數據存放在一個數據段,只讀的數據存放在另一個數據段,動態分配的數據安排在第3個數據段。8086 規定程序當前訪問的數據默認安排在數據段(應用中無須特別說明),也允許將數據安排在其他段(需要明確指明),數據的偏移地址由各種存儲器尋址方式計算出有效地址EA(詳見第2章)。
4. 存儲器的分段管理
8086 規定段基地址低 4 位均為 0,每段最大不超過 64KB。但并沒有要求每段必須是64KB,各段之間可以完全分開,也可以部分重疊,甚至完全重疊。當然各段的內容是不允許發生沖突的。圖1-8說明了這種情況。
圖1-8(a)是各段獨立的分配示例。CS=0150H、DS=4200H、SS=1CD0H、ES=B000H,它們分別為代碼段、數據段、堆棧段和附加段的段地址。自每個段地址開始,各段均占64KB字節的范圍,各段之間互不重疊。
圖1-8(b)則是相互重疊段的分配示例。CS=0200H、DS=0400H、SS=0480H,這樣代碼段、數據段和堆棧段的物理起始地址分別為02000H、04000H和04800H。其中代碼段大小為8KB,數據段占2KB,而堆棧段只有256字節,SP=0100H。由于該程序沒有使用附加段,所以沒有設置 ES 值。從這里可以看出,各段大小應根據實際需要來分配,可以重疊。有時,甚至可以將所有4種段都集中在一個邏輯段內,形成一個短小緊湊的程序,其大小不超過64KB。例如,在圖1-8(b)所示的情況下,如果設置CS=DS=SS=0200H;這時,代碼段將占據該邏輯段從偏移地址0000~1FFFH的8KB,而數據段在偏移地址2000H~27FFH位置,堆棧頂指針SP=2900H。