目錄
王爽《彙編語言》第四版 超級筆記
第14章 端口
14.1 端口的讀寫
14.2 CMOS RAM晶片
14.3 shl和shr指令
14.4 CMOS RAM中存儲的時間資訊
我們前面講過,各種存儲器都和CPU的位址線、資料線、控制線相連。CPU在操控它們的時候,把它們都當作記憶體來對待,把它們總地看做一個由若幹存儲單元組成的邏輯存儲器,這個邏輯存儲器我們稱其為記憶體位址空間。
在PC機系統中,和CPU通過總線相連的晶片除各種存儲器外,還有以下3種晶片。
(1)各種接口卡(比如,網卡、顯示卡)上的接口晶片,它們控制接口卡進行工作;
(2)主機闆上的接口晶片,CPU通過它們對部分外設進行通路;
(3)其他晶片,用來存儲相關的系統資訊,或進行相關的輸入輸出處理。
在這些晶片中,都有一組可以由CPU讀寫的寄存器。這些寄存器,它們在實體上可能處于不同的晶片中,但是它們在以下兩點上相同。
(1)都和CPU的總線相連,當然這種連接配接是通過它們所在的晶片進行的;
(2)CPU對它們進行讀或寫的時候都通過控制線向它們所在的晶片發出端口讀寫指令。
可見,從CPU的角度,将這些寄存器都當作端口,對它們進行統一編址,進而建立了一個統一的端口位址空間。每一個端口在位址空間中都有一個位址。
CPU可以直接讀寫以下3個地方的資料。
(1)CPU内部的寄存器;
(2)記憶體單元;
(3)端口。
這一章,我們讨論端口的讀寫。
在通路端口的時候,CPU通過端口位址來定位端口。因為端口所在的晶片和CPU通過總線相連,是以端口位址和記憶體位址一樣,通過位址總線來傳送。
在PC系統中,CPU最多可以定位64KB個不同的端口。則端口位址的範圍為0~65535。
對端口的讀寫不能用mov、push、pop等記憶體讀寫指令。端口的讀寫指令隻有兩條:in和out,分别用于從端口讀取資料和向端口寫入資料。
我們看一下CPU執行記憶體通路指令和端口通路指令時,總線上的資訊:
(1)通路記憶體:
mov ax,ds:[8] ;假設執行前(ds)=0
執行時與總線相關的操作如下所示。
CPU通過位址線将位址資訊8發出;
CPU通過控制線發出記憶體讀指令,選中存儲器晶片,并通知它将要從中讀取資料;
存儲器将8号單元中的資料通過資料線送入CPU。
(2)通路端口:
in al,60h ;從60h号端口讀入一個位元組
執行時與總線相關的操作如下。
CPU通過位址線将位址資訊60h發出;
CPU通過控制線發出端口讀指令,選中端口所在的晶片,并通知它将要從中讀取資料;
端口所在的晶片将60h端口中的資料通過資料線送入CPU。
注意,在in和out指令中,隻能使用ax或al來存放從端口中讀入的資料或要發送到端口中的資料。通路8位端口時用al,通路16位端口時用ax。
對0~255以内的端口進行讀寫時:
in al,20h ;從2011端口讀入一個位元組 out 20h,al ;向20打端口寫入一個位元組
對256~65535的端口進行讀寫時,端口号放在dx中:
mov dx,3f8h ;将端口号3f8h送入dx in al,dx ;從3f8h端口讀入一個位元組 out dx,al ;向3f8h端口寫入一個位元組
我們通過對CMOS RAM的讀寫來體會一下對端口的通路。
PC機中,有一個CMOS RAM晶片,一般簡稱為CMOS。此晶片的特征如下。
(1)包含一個實時鐘和一個有128個存儲單元的RAM存儲器(早期的計算機為64個位元組)。
(2)該晶片靠電池供電。是以,關機後其内部的實時鐘仍可正常工作,RAM中的資訊不丢失。
(3)128個位元組的RAM中,内部實時鐘占用0~0dh單元來儲存時間資訊,其餘大部分單元用于儲存系統配置資訊,供系統啟動時BIOS程式讀取。BIOS也提供了相關的程式,使我們可以在開機的時候配置CMOS RAM中的系統資訊。
(4)該晶片内部有兩個端口,端口位址為70h和71h。CPU通過這兩個端口來讀寫CMOS RAM。
(5)70h為位址端口,存放要通路的CMOS RAM單元的位址;71h為資料端口,存放從標明的CMOS RAM單元中讀取的資料,或要寫入到其中的資料。可見CPU對CMOS RAM的讀寫分兩步進行,如讀CMOS RAM的2号單元:
将2送入端口70h;
從端口71h讀出2号單元的内容。
shl和shr是邏輯移位指令,後面的課程中我們要用到移位指令,這裡進行一下講解。
shl是邏輯左移指令,它的功能為:
(1)将一個寄存器或記憶體單元中的資料向左移位;
(2)将最後移出的一位寫入CF中;
(3)最低位用0補充。
指令:
mov al,01001000b shl al,1 ;将al中的資料左移一位
執行後(al)=10010000b,CF=0。
我們來看一下shl al,1的操作過程。
(1)左移
原資料: 01001000
左移後: 01001000
(2)将最後移出的一位寫入CF中
左移後: 1001000 CF=0
(3)最低位用0補充
左移後: 10010000
如果接着上面,繼續執行一條shl al,1,則執行後:(al)=00100000b,CF=1。shl指令的操作過程如下。
原資料: 10010000
左移後: 0010000 CF=1
左移後: 00100000
如果移動位數大于1時,必須将移動位數放在cl中。
比如,指令:
mov al,01010001b mov cl,3 shl al,cl
執行後(al)=10001000b,因為最後移出的一位是0,是以CF=0。
可以看出,将X邏輯左移一位,相當于執行X=X*2。
比如:
mov al,00000001b ;執行後(al)=00000001b=l shl al,1 ;執行後(al)=00000010b=2 shl al,1 ;執行後(al)=00000100b=4 shl al,1 ;執行後(al)=00001000b=8 shl al,cl ;執行後(al)=01000000b=64
shr是邏輯右移指令,它和shl所進行的操作剛好相反。
(1)将一個寄存器或記憶體單元中的資料向右移位:
(3)最高位用0補充。
mov al,10000001b shr al,1 ;将al中的資料右移一位
執行後(al)=01000000b,CF=1。
如果接着上面,繼續執行一條shr al,1,則執行後:(al)=00100000b,CF=0。
shr al,cl
執行後(al)=00001010b,因為最後移出的一位是0,是以CF=0。
可以看出将X邏輯右移一位,相當于執行X=X/2。
在CMOS RAM中,存放着目前的時間:年、月、日、時、分、秒。這6個資訊的長度都為1個位元組,存放單元為:
秒:0 分:2 時:4 日:7 月:8 年:9
這些資料以BCD碼的方式存放。
BCD碼是以4位二進制數表示十進制數位的編碼方法,如下所示。
十進制數位:0 1 2 3 4 5 6 7 8 9
對應的BCD碼:0000 0001 0010 0011 0100 0101 0110 0111 1000 1001
比如,數值26用BCD碼表示為:0010 0110。
可見一個位元組可表示兩個BCD碼。則CMOS RAM存儲時間資訊的單元中,存儲了用兩個BCD碼表示的兩位十進制數,高4位的BCD碼表示十位,低4位的BCD碼表示個位。比如,00010100b表示14。
程式設計,在螢幕中間顯示目前的月份。
分析,這個程式主要做以下兩部分工作。
(1)從CMOS RAM的8号單元讀出目前月份的BCD碼。
要讀取CMOS RAM的資訊,首先要向位址端口70h寫入要通路的單元的位址:
mov al,8 out 70h,al
然後從資料端口71h中取得指定單元中的資料:
in al,71h
(2)将用BCD碼表示的月份以十進制的形式顯示到螢幕上。
我們可以看出,BCD碼值=十進制數位值,則BCD碼值+30h=十進制數對應的ASCII碼。
從CMOS RAM的8号單元讀出的一個位元組中,包含了用兩個BCD碼表示的兩位十進制數,高4位的BCD碼表示十位,低4位的BCD碼表示個位。比如,00010100b表示14。
我們需要進行以下兩步工作。
① 将從CMOS RAM的8号單元中讀出的一個位元組,分為兩個表示BCD碼值的資料。
mov ah,al ;al中為從CMOS RAM的8号單元中讀出的資料 mov cl,4 shr ah,cl ;ah中為月份的十位數位值 and al,00001111b ;al中為月份的個位數位值
② 顯示(ah)+30h和(al)+30h對應的ASCII碼字元。
完整的程式如下。