PC硬體元件控制詳解
目錄
前言
(一) 146818
(二) 8042
(三) 8237
(四) 8253與8254
(五) 8255
(六) 8259
參考文獻
硬體控制其實並不難,最難的是在於資料的收集整理。本文原是作者在1994年初研究軟體保護與破解技巧時整理寫下的,後來陸陸續續增添修改而成。為了確認所有資料正確無誤,作者除了參閱數本硬體零件特性以及PC硬體控制的相關書籍外,也從硬體線路圖、BIOS程式來追蹤驗證,更花了相當多的時間在數種廠牌的 286、386與486機器上進行實際的測試,並請教王光伯、柯元順兩位當時同在中科院從事硬體設計的同事,以彌補自己本身硬體知識的不足。然而百密仍有一疏的時候,如果您發現文中有錯誤之處,還請不吝指正,同時也希望本文對您能有所助益!
邱奕南 1996/10/15
146818為AT使用的及時時脈(RealTime Clock),內含 64 byte的CMOS記憶體,其中前14個byte為146818本身用以記錄時間、日期之用,後50個byte則供外界使用,通常由BIOS設定系統所需的組態資訊(configuration)。要讀取或寫入這些CMOS記憶體,首先必須經由I/O Port 70h選擇所要讀寫的位址(0~3Fh),然後再經由I/O Port 71h進行讀寫動作。以下為前 14 byte記憶體的意義:
| 位元組 | 用途 |
| 0 | 秒(0-59) |
| 1 | 鬧鈴秒(0-59) |
| 2 | 分(0-59) |
| 3 | 鬧鈴分(0-59) |
| 4 | 時(0-23或1-12) |
| 5 | 鬧鈴時(0-23或1-12) |
| 6 | 星期(1-7,由星期日開始) |
| 7 | 日(1-31) |
| 8 | 月(1-12) |
| 9 | 年(0-99) |
| A | 暫存器A |
| B | 暫存器B |
| C | 暫存器C(僅可讀) |
| D | 暫存器D(僅可讀) |
這些時間值內容格式取決於暫存器B的值,例如BCD格式、二進制格式、24小時制等等。以下為146818四個暫存器值的意義:
位元7 = 更新進行位元,值為 0時才能讀取146818的時間。本位元只能讀不能寫。
位元6~4 = 二階分除器選擇位元,必須與使用的時基頻率(time-base
frequency)
相搭配,以使得輸出結果相同,否則會造成內部時間和輸出頻率不準的現象。以下為各時基頻率所使用的分除器位元值:
000 = 4.194304M Hz
001 = 1.048576M Hz
010 = 32.768K Hz
位元3~0 = 選擇輸出方波和週期岔斷頻率。各值頻率為:
0000 = 禁止
0001 = 256K Hz
0010 = 128K Hz
其他 = 2^(16-x) Hz
說明:PC上使用的時基頻率為32.768K Hz。
位元7 =
中止更新週期,以便重新寫入新的日期或時間。
位元6 = 啟用週期岔斷。
位元5 = 啟用鬧鈴岔斷。
位元4 = 啟用更新結束岔斷。
位元3 = 啟用方波輸出。
位元2 = 資料模式,0表BCD,1表二進制。
位元1 = 時間格式,0表12小時制,1表24小時制。
位元0 = 啟用日光節約時間。
說明:
位元7 = 岔斷需求旗標。
位元6 = 週期岔斷旗標。
位元5 = 鬧鈴岔斷旗標。
位元4 = 更新結束岔斷旗標。
位元3~0 = 固定為0。
說明:當及時時脈發生岔斷時,岔斷處理程式必須讀取本暫存器值,以辨別發生的岔斷種類並加以處理。
位元7 = 1表時間及RAM有效,否則為電池耗盡。
位元6~0 = 固定為0。
以下為BIOS所設定的記憶體意義:
| 位元組 | 用途 |
| E | 診斷狀態位元組 |
| F | 停工(shutdown)狀態位元組 |
| 10 | 軟式磁碟機型式 |
| 11 | 保留 |
| 12 | 硬式磁碟機型式 |
| 13 | 保留 |
| 14 | 設備位元組 |
| 15-16 | 基底記憶體容量(單位KB) |
| 17-18 | 擴充記憶體容量(單位KB) |
| 19 | 第一部硬式磁碟擴展型式 |
| 1A | 第二部硬式磁碟擴展型式 |
| 1B-2D | 保留 |
| 2E-2F | 檢查碼 |
| 30-31 | 擴充記憶體容量(單位KB) |
| 32 | 世紀(年的千位和百位數)的BCD值 |
| 33 | 資訊旗標位元組 |
| 34-3F | 保留 |
位元7 = 電源耗盡
位元6 = 檢查碼錯誤
位元5 = 組態資訊錯誤
位元4 = 記憶體容量不合
位元3 = 硬式磁碟機轉接器有問題
位元2 = 及時時脈的時間無效
位元1~0 = 固定為0
這個位元組用來提供BIOS自測過程設定使用,隨著BIOS不同而有不同的意義。
前4位元指第一部軟碟,後4位元指第二部軟碟,各值意義為:
0000 = 沒有磁碟機
0001 = 360KB磁碟機
0010 = 1.2MB磁碟機
0011 = 720KB磁碟機
0100 = 1.44MB磁碟機
其他 = 保留
前4位元指第一部硬碟,後4位元指第二部硬碟,除了值 0表沒有硬碟外,其餘表硬碟的型式。若值為1111b時,表示使用硬式磁碟擴展型式來指明硬碟的型式,但型式值必須大於等於16。
位元7~6 = 磁碟機數目,由0起表示1部磁碟機。
位元5~4 = 顯示轉接器型式
00 表主顯示器的轉接器上有自己的BIOS
01 表彩色繪圖轉接器以40行模式顯示
10 表彩色繪圖轉接器以80行模式顯示
11 表黑白顯示轉接器
位元3~2 = 保留
位元1 = 數學處理器存在指示位元
位元0 = 磁碟機存在指示位元
位元7 = 1表已加裝IBM PC/AT 128KB記憶體擴充板
位元6 = 設定公用程式(Setup)利用此位元來發出啟始設定後的第一個使用者訊息
位元5~0 = 保留
嚴格說起來,146818內的所有CMOS記憶體均可讀寫任意值(標明僅讀者除外),但必須確定修改後不會與原146818或BIOS相衝突。不過雖然這些CMOS記憶體有很多是標明為保留的,事實上在許多較新的BIOS程式裡,已運用了這些保留記憶體,例如開機密碼即是一例。因此除了暫時存放資料外,最好不要隨意更動這些記憶體的值,以免造成與系統之間的衝突。
8042為AT使用的鍵盤控制器,內部有一個狀態暫存器,供外界檢測鍵盤狀態;一個輸出埠和一個輸入埠,用來做為與外界的控制訊號使用;一個輸入緩衝器和一個輸出緩衝器,用來存放與外界的界面資料,包括命令和資料等。以下為這些元件的意義:
位元7 = 同位錯誤
位元6 = 接收逾時錯誤
位元5 = 傳送逾時錯誤
位元4 = 鍵盤啟用開關,0表禁能,1表允能
位元3 = 命令/資料指示位元,0表資料,1表命令
位元2 = 系統旗標,由外界設定
位元1 = 輸入緩衝器已滿,但尚未被8042讀走
位元0 = 輸出緩衝器已滿,但尚未被外界讀走
說明:
狀態暫存器為一僅讀暫存器,各位元反應了鍵盤的某項狀態。例如8042所使用的同位位元為奇同位,因此如果取得的鍵盤資料偵測為偶同位的話,位元7的值便會設立成1,以便反應出同位錯誤。位元 3的值由線路所控制,反應出輸入緩衝器內的資料型態(即命令或資料),以供8042決定處理的方式。在AT上,命令的寫入是經由I/O Port 64h,而資料的寫入則經由I/O Port 60h。因此若輸入緩衝器內的資料是經前者(Port64h)寫入者,位元3的值便會設立成1;若是經由後者 (Port 60h)寫入者,則位元3的值便會設立成0。位元 2的值由外界所送入的命令所控制,請參閱後面所述之命令。位元1和位元0是用來指示外界是否可對8042的緩衝器寫入或讀取資料。當位元1為0時,外界才能再將資料送到8042的輸入緩衝器;當位元0為1時,外界才能從8042的輸出緩衝器讀取資料。當不是上述的情況時,外界程式便必須一直等待到上述的情況成立,否則不能對8042的緩衝器進行I/O動作。
備註:
位元 4的值根據其他書籍所言為用來反應鍵盤抑制開關的狀態,但經作者試用所有抑制鍵盤的命令均無法使之變成 0。猜想可能這個位元值係接至輸入埠位元 7,但由於無法找到8042內部線路圖,因此作者也無法確定。
位元7 = 鍵盤抑制開關,0為抑制,1為開啟
位元6 = 顯示器型態選擇,0為彩色,1為單色
位元5 = 0表已裝設製造時跳線
位元4 = 1表啟動系統電路板上的第二個256KB RAM
位元3~0 = 保留
說明:
輸入埠的資料僅能讀取,且必須透過命令方式讀取。輸入埠各位元的資訊均來自外界,其值因機器而異,因此便略而不提。位元7接至一個5支腳的Jumper的第4腳,這支腳的訊號同時也控制著外界RESET訊號的進入,若能改變這支腳的值成為0 (也就是低電位),則不但鍵盤不能作用,外界RESET也無法重新啟動電腦,必須整個關機重開,只可惜這個Jumper是做死的,無法利用軟體來控制(作者曾在某本書中看到這個位元值可以用軟體改變,但該書中所寫的I/O Port為 64h,似乎不太可能,再查閱各相關書籍及AT線路,已確認該書內容是錯誤的)。
備註:
由於8042輸入埠的值均依連接線路而定,並無法由軟體控制或改變,因此大都無實用價值。作者曾在不同廠牌PC上讀取輸入埠的值(均使用彩色螢幕),結果所得到的值由FFh、FBh、FCh、E7h等不定,其中位元 6的值並不正確,但查閱線路圖和各參考書籍均指出位元 6為接地時為彩色顯示器,再由 AT BIOS程式追蹤發現顯示器單彩色的判斷並非由這個位元來決定,因此這個輸入埠的值並不是很可靠,最好不要使用。
位元7 = 鍵盤資料線
位元6 = 鍵盤時脈
位元5 = 輸入緩衝器已滿
位元4 = 輸出緩衝器已滿
位元3~2 = 保留
位元1 = A20位址線控制
位元0 = 系統重置
說明:
輸出埠的資料是可以讀寫的,但必須透過命令方式讀寫 (請參閱D1h輸出埠寫入命令的說明)。鍵盤資料線傳送的便是由8042送出的資料,如掃描碼或回應資料等,其傳送的數據結構和RS232相似:
第1位元 = 開始位元
第2~9 = 資料,由低位元先送
第10 = 奇同位位元
第11 = 停止位元
而鍵盤時脈便是用來分辨鍵盤資料線各位元的時序的。因此這兩個位元的值並不固定,端視讀取時的狀態而定。位元1是用來控制CPU的 A20位址線輸出,當其值為0時,將強迫A20位址線輸出為 0,此時系統將無法讀寫HMA上的資料,也就是位址FFFF:10h將存取到 0000:0位址。當其值為1時,A20位址線才由CPU的輸出決定。位元0用來重置系統,當其值為0時,整個系統將會重置 (也就是重新開機)。由於位元0和位元1關係到整個系統的運作,因此最好不要加以隨意更動。
用來供外界讀取按鍵的掃描碼,或是鍵盤送出的回應資料。這個緩衝器必須在狀態暫存器位元0值為1時才可以讀取。
用來供外界輸入命令或資料使用,必須在狀態暫存器位元1值為0時才可以寫入。
在AT上,8042狀態暫存器的讀取,必須經由I/O Port 64h,輸出緩衝器的讀取,則經由I/O Port 60h。輸入緩衝器則分成60h和64h兩個Port,分別用來輸入資料和命令。至於8042的輸入埠和輸出埠的值,則必須籍由命令來取得或設定。送出命令給8042的方式,是先將命令寫入Port 64h,再依需要將資料寫入Port 60h,如此命令便算送出完畢。之後8042根據命令的處理結果,可能會回送一些資料回來,此時由Port 60h便可讀回這些回應資料。以下為一些8042常用的命令(標示 *者,為我後來另行參閱其他書籍而新加入的部份,我尚未測試過):
位元7 = 保留
位元6 = 0表雙斷開碼,1表單斷開碼
位元5 = 1表不使用輔助界面
位元4 = 1表抑制鍵盤
位元3 = 1表不理會鍵盤抑制
位元2 = 系統旗標
位元1 = 保留
位元0 = 啟用岔斷輸入(IRQ1)
位元 6用來控制斷開碼的格式,也就是按鍵在放開時8042所送出的資料格式。當值為0時,表示採用雙斷開碼格式,首先送出F0h,然後後面跟著放開鍵的掃描碼。當值為 1時,則採用單斷開碼格式,也就是將掃描碼的位元7設成1,用以表示這是個斷開碼。由於PC的BIOS程式均採用單斷開碼方式解譯8042送來的資料,因此這個位元大都設成1。位元5的值較有爭議,在有些書上寫明必須設成 1,做為IBM PC的相容模式;有的書上只說明這是用來檢查同位位元的而已;也有的書上說為輔助界面除能位元。經作者實際在多種PC上測試,結果這個位元的初值有的為0,有的為1,而且不管這個位元的值設成0或1,系統均仍正常運作。但以後述的其他命令來看,似乎應為不使用輔助界面,故建議設為0。位元4用來抑制鍵盤,當值設成1時,將使得時脈線路成為低電位,使得鍵盤界面失效。位元3根據各相關書籍所述為使鍵盤的抑制功能失效,但經作者試過,即使將這個位元設成 1,各種鍵盤抑制命令仍然會抑制鍵盤的功能,因此它的實際用途不明。位元2用來設定狀態暫存器位元2,也就是系統旗標的值,這個旗標並沒什麼作用,一般在PC均設成1。位元0用來控制是否採用岔斷輸入,一般均設成1。若將之設成0,則必須使用Polling 方式處理,較為麻煩。位元7和位元1為保留值,可任意寫入0或1。
00 = 正常
01 = 鍵盤時脈保持在低電位
02 = 鍵盤時脈保持在高電位
03 = 鍵盤資料線保持在低電位
04 = 鍵盤資料線保持在高電位
00 = 正常
01 = 鍵盤時脈保持在低電位
02 = 鍵盤時脈保持在高電位
03 = 鍵盤資料線保持在低電位
04 = 鍵盤資料線保持在高電位
位元7~2 = 固定為0
位元1 = 鍵盤資料線
位元0 = 鍵盤時脈
其中位元0~1係由輸出埠位元7~6所回送的輸入資料,以做為鍵盤自我測試時使用。同樣的,這個命令所讀出的值也因輸出埠的狀態而異,請參閱輸出埠中的說明。
以下則為8042的系統命令。系統命令和一般命令的送出方式不同,必須經由資料埠,也就是I/O Port 60h送出。8042收到後,除了 EEh回音命令以外,均會回送ACK訊號FAh(收到命令或資料均會回送)。以下為各系統命令的意義:
位元7~3 = 固定為0
位元2 = Caps Lock指示器
位元1 = Numeric Lock指示器
位元0 = Scroll Lock指示器
設定之後,鍵盤上對應的LED便會亮起來。
00 =
傳回目前使用的掃描碼編號
01 = 選擇第一組掃描碼(PC使用)
02 = 選擇第二組掃描碼
03 = 選擇第三組掃描碼
位元7 = 固定為0。
位元6~5 = 延遲參數,延遲(1+x)*250ms。
位元4~0 = 重複參數,假設位元2~0值為A,位元4~3值為 B,則重複週期為4.17*(8+A)*2^Bms。
以下為一些鍵盤可能回送的資料或命令:
注意在對8042進行命令控制時,必須將岔斷禁能,以免外界鍵盤輸入岔斷影響正常之鍵盤命令傳送。
8237為DMA控制器,內含4個 DMA通道。在XT中只使用了一個,各通道的作用分別為:
通道0 = DRAM更新
通道1 = 備用
通道2 = 軟碟
通道3 = 硬碟
但在AT中,8237已擴增為兩個,共有 8個通道,而且DRAM的更新大都改採分配式更新(distributed refresh),而不像XT一樣使用DMA式更新,因此通道 0已可以拿來隨意運用。由於 PC/XT的機器目前已甚少見了,因此後面關於8237的說明,我們均以AT為準(但通道0~3的控制方式與I/O Port仍相同)。AT各DMA通道作用為:
通道0 = 備用
通道1 = SDLC(Synchronous Data-Link Controll,為串列埠資料傳送的一種格式)
通道2 = 磁片
通道3 = 備用
通道4 = 供第一個8237串接(通道0~3)
通道5 = 備用
通道6 = 備用
通道7 = 備用
AT在規劃8237時,已將第一個8237線路設計成 8位元傳送,因此每次最多可傳送64KB;而第二個8237線路則設計成16位元傳送,因此每次最多可傳送128KB。 其實這兩者的差異,只是所接的位址線不同而已:第一個8237是接到A15~A0,而第二個8237則接到A16~A1,並強制A0位址線為0 (因此通道4~7的位址值必須為偶數)。這裡還有一個問題:AT上的位址線不只16條,多出的位址線如何設定其值呢?其實AT中每個8237均還搭配一個AL5573,以便設定DMA存取的記憶體高位址,一般稱之為頁暫存器。例如在286AT上,第一個AL5573接至位址線A23~A16,第二個AL5573則接至位址線A23~A17。以下為各DMA通道在AT上對應的頁暫存器I/O Port:
通道0 = 87h
通道1 = 83h
通道2 = 81h
通道3 = 82h
通道5 = 8Bh
通道6 = 89h
通道7 = 8Ah
藉由頁暫存器的值,和8237 DMA通道的位址值,我們才能定出所要存取的位址。至於位址值如何設定?8237各通道均相對應有一個基準位址暫存器和基準計數暫存器,用來初始8237 DMA傳輸的開始位址及資料數目,不過這些暫存器只能寫不能讀。要讀取,只有相對應的目前位址暫存器和目前計數暫存器,這兩個暫存器記錄了目前8237 DMA傳輸中的位址和剩餘計數。以下為這些暫存器的I/O Port位址:
| 通道 | 基準和目前位址暫存器 | 基準和目前計數暫存器 |
| 0 | 00h | 01h |
| 1 | 02h | 03h |
| 2 | 04h | 05h |
| 3 | 06h | 07h |
| 4 | C0h | C2h |
| 5 | C4h | C6h |
| 6 | C8h | CAh |
| 7 | CCh | CEh |
有一點必須特別注意的是,8237 DMA計數暫存器的計數規則為數目+1,也就是給定計數10,實際傳輸為11個資料。同理,在傳輸完後,目前計數暫存器的值便會變成0FFFFh(除非採用重新初始模式,請見後述)。另外,由於8237內部線路是以 8位元設計,故這些暫存器值的存取都必須透過內部的一個正反器來控制高位元組與低位元組的讀寫。因此在讀寫這些暫存器時,都必須清除此一正反器,其I/O Port在通道0~3為0Ch,在通道4~7為D8h。例如寫入通道 7的基準位址暫存器,其過程為:
out 0D8h,任意值
out 0CCh,低位元組
out 0CCh,高位元組
讀取過程過程亦相同,先讀低位元組,後讀高位元組。
除了前述的暫存器外,8237 DMA還有不少暫存器,均與8237 DMA傳輸的規劃與控制方式有關,因此以下我們便先一一介紹這些暫存器的意義:
位元7~6
00 需求傳輸模式
01 單一傳輸模式
10 區塊傳輸模式
11 串接模式
位元5 = 0表位址遞增,1表位址遞減
位元4 = 1表傳輸結束後自動重新初始
位元3~2(位元7~6 = 11,即串接模式時不作用)
00 驗證傳輸
01 寫入傳輸
10 讀取傳輸
位元1~0 = DMA通道選擇(0~3)
說明:
模式暫存器主要用來規劃各通道的DMA傳輸方式,位元7~6規劃了DMA的傳輸模式,至於各模式的意義牽涉到硬體訊號的控制,作者也並未弄得很清楚,因此在此作者不便太過詳細說明,有興趣的人可參考 Intel的硬體元件手冊。在PC上, DMA傳輸大都採用單一傳輸模式,以使得每次傳輸均佔用一整個CPU Cycle,而通道4當然必須採用串接模式。位元 4是用來不斷的 DMA傳輸,也就是傳輸完了後又重新依原來的設定重頭開始傳輸,例如XT的記憶體更新便必須採用此種方式。至於位元3~2則是傳輸動作的設定,驗證傳輸並不作DMA傳輸 (但各暫存器值仍同樣更新);寫入傳輸是將I/O 裝置的資料傳輸到記憶體中;讀取傳輸則將記憶體資料傳輸到I/O裝置中。因此在BIOS內使用通道2存取磁片資料時,讀取磁片便使用模式值46h,而寫入磁片則使用模式值4Ah。
位元7
= DACK訊號作用電壓值,0表low,1表high
位元6 = DREQ訊號作用電壓值,0表high,1表low
位元5 = 0表正常寫入時脈,1表擴展寫入時脈(位元3=1時不作用)
位元4 = 0表固定權限,1表滾動權限
位元3 = 0表正常讀取時脈,1表壓縮讀取時脈(位元0=1時不作用)
位元2 = 0表啟用8237,1表禁用8237
位元1 = 1表第0通道位址不變(位元0=0時不作用)
位元0 = 1表啟用記憶體對記憶體搬移功能
說明:
在PC上,DACK訊號採用low active,DREQ訊號採用 high active,因此位元7~6都必須為 0。位元5和位元3與PC上的時脈有關,在讀取時,8237可以將讀取時脈由正常的3個clock壓縮成2個clock,只要PC能夠承受此時脈,則傳輸效率可提高不少。至於8237的寫入時脈亦可由正常的2個clock擴展到3個clock,當然傳輸效率也會跟著下降。這兩個位元在BIOS上均設為0,因此為保險起見,讀者在使用時最好也設為0。位元 4涉及了各通道DMA傳輸權限的問題,固定權限(BIOS內定值)是以通道0為最高,而以通道3為最低;滾動權限則以最久未執行DMA傳輸的通道為最高。以系統的眼光來看,當然是滾動權限較好,但在BIOS中大都將之設定成固定權限,主要是因在XT上的通道 0是做為記憶體更新訊號使用,不能隨便受到干擾,不過在AT上便無此一限制了。位元 2用來啟用與禁用8237,當禁用時,所有通道的 DMA傳輸都會中止,通常用在規劃某個通道的時候。位元 0用來做記憶體對記憶體搬移的功能,當設定後,通道0必須規劃成讀取傳輸,通道1則必須規劃成寫入傳輸,之後的動作便是記憶體資料傳輸到通道0,然後給通道1傳輸到另一個記憶體中。至於位元1則是用來固定通道0的位址(當記憶體對記憶體傳輸時),以使得將某一定值能填到一整塊記憶體中。
位元7~4
= 不使用
位元3~0 = DMA通道3~0之遮罩位元
說明:
遮罩暫存器用來允許或禁止各通道的DMA傳輸,當遮罩位元為1時表示禁止,為 0時表示允許。由於此一暫存器無法讀取,因此為避免影響到其他通道,8237還提供另一寫入方法(通道0~3為Port 0Ah,通道4~7為Port D4h,只能寫入):
位元7~3 = 不使用
位元2 = 遮罩位元
位元1~0 = DMA通道選擇(0~3)
當重新規劃某一通道的 DMA傳輸前,應先設立遮罩位元,以避免規劃過程中仍發生DMA傳輸(另也可使用命令暫存器位元2),在規劃後再將遮罩位元清除,即可開始新的 DMA傳輸。此外,8237也提供了一個直接清除所有遮罩位元的命令(通道0~3為Port 0Eh,通道4~7為Port DCh,只能寫入),可允許所有的通道接受DMA傳輸要求。
位元7~3
= 不使用
位元2 = 要求位元
位元1~0 = DMA通道選擇(0~3)
說明:
當設定要求位元為1時,不管該通道的遮罩位元為何,都會強迫啟動DMA傳輸。一般I/O裝置在DMA傳輸時,都會主動驅動DREQ訊號,但在記憶體對記憶體傳輸中,由於無法產生此一訊號,故大都必須利用此一暫存器來驅動傳輸。其他的用途則很少見。
位元7~4
= DMA通道3~0是否有DMA傳輸要求等待中
位元3~0 = DMA通道3~0是否結束DMA傳輸
說明:
當讀取本暫存器值後,所有位元均會重置為 0。為避免相互干擾,檢測DMA 傳輸是否完成最好使用目前計數暫存器,但使用本暫存器值亦無不可。
說明:暫時暫存器裡面記錄了記憶體對記憶體搬移時,所暫存的資料值,一般很少會用到。
說明:重置時,命令暫存器、狀態暫存器、要求暫存器、暫時暫存器、正反器均會被清成0,而遮罩暫存器所有位元則會被設成1。
一般除了音效卡等硬體會用到8237 DMA外,程式設計師最大的興趣莫過於嘗試記憶體對記憶體的 DMA傳輸(比一般指令式的資料搬移還快)。然而作者曾寫了一個類似的測試程式,傳輸後所有暫存器值都對,而搬至的記憶體資料也有更新,就只是資料不對。同樣的程式在某些PC上則會當機。目前作者仍無法找出原因以做出正確的記憶體對記憶體的 DMA傳輸,只好留待將來由其他先進補充了。
8253和8254均為PC使用之計時器,兩者除了外接的頻率限制不同外(前者最多只能接2MHz,後者可接至8MHz,8254-2更可接至10MHz), 其餘部份均相容。但以PC計時器外接頻率才1.19MHz 來看,兩者在使用上並沒有什麼差別,因此以下之計時器,我們均以8253來稱呼。
8253具有三個16位元的計數器,可分別加以規劃。每個計數器均具有一個輸入的頻率、一個控制閘(GATE)和一個輸出端,其中控制閘便是用來控制輸出端是否輸出結果。以下為PC對於這三個16位元計數器的佈線方式及作用:
作用 = 系統計時器
輸入頻率 = 1,193,180Hz
GATE0 = 接至+5V
輸出 = 第一個8259之IRQ0
作用 = DRAM更新要求產生器
輸入頻率 = 1,193,180Hz
GATE1 = 接至+5V
輸出 = 更新要求週期
作用 = 喇叭音調頻率
輸入頻率 = 1,193,180Hz
GATE2 = 接至Port 61h位元0
輸出 = 喇叭
由上面的資料我們可以知道,在PC上,除了GATE2 (也就是Port 61h的位元0)可以控制計數器2是否有輸出外(控制喇叭是否發聲),其餘兩個計數器我們均無法禁止其計數結果的輸出,頂多是更改其輸出頻率和輸出波形而已。對於三個計數器的輸出規劃及計數值讀寫,首先必須寫出控制字組到控制暫存器中,這個暫存器在PC上是經由Port 43h寫入的,之後再分別由Port 40h~42h 讀寫計數器0~2的值。控制字組的格式為:
位元7~6 = 計數器選擇(0~2)
位元5~4 = 操作方式00 = Latch住目前的計數值
01 = 讀寫計數值的高位元組
10 = 讀寫計數值的低位元組
11 = 依次讀寫計數值的低、高位元組位元3~1 = 模式,各值意義為
000 - 模式0
001 - 模式1
x10 - 模式2
x11 - 模式3
100 - 模式4
101 - 模式5位元0 = 0表二進制計數,1表BCD制計數
以下為各輸出模式的意義:
計數時輸出為Low, 當計數完畢後,輸出昇至High,然後重新計數,並將輸出再還原為Low。
當GATE由Low昇成High時開始計數,計數時輸出為Low,當計數完畢後,輸出昇至High並結束計數。
當GATE為High時開始計數,計數時輸出為High,當計數完畢後,輸出降為Low一個Clock後升為High,然後繼續重新計數。
當GATE為High時開始計數,且以 2遞減,當計數完畢後,輸出高低互變,並繼續重新計數。
計數時輸出為High,當計數完畢後,輸出降為Low一個Clock後升為High,並停止計數。若GATE為Low時停止計數。
當GATE由Low昇成High時開始計數,計數時輸出為High, 當計數完畢後,輸出降為Low一個Clock後升為High,並停止計數。
由於在PC上,各計數器之用途及外接線路均已定死,因此計數器 0必須採用模式3;計數器1必須採用模式2;計數器2則必須採用模式 3,否則輸出之波形將無法與線路配合,而產生奇怪的現象(但並非絕對,見後述)。以下,作者再進一步介紹各計數器的計數值在PC上的規劃方式:
計數器0在PC上是做為時序之控制,以18.2Hz定頻觸發INT 8h。其初值為0,也就是每計數65536岔斷一次INT 8h,因此 1,193,180/65536=18.2Hz。通常這個計數值是不加以更動的,以免影響到系統時間的運作,但是若欲做為短時間定頻岔斷之特殊運用時,更動也是允許的。不過相同功能也可以運用146818(INT 70h)來完成,因此更改計數器0的計數值便不是那麼的需要。以下為本計數器的計數值寫入方式:
out 43h,36h
out 40h,計數值低位元組
out 40h,計數值高位元組
計數器1在PC上是做為DRAM定時更新使用,在XT上是接到8237
DMA通道0上,但在AT上已不再使用 DMA式更新了。這個計數器的初值為18,也就是每隔15us更新DRAM一次。由於DRAM的更新頻率對於程式運用上較無關,因此這個計數器的計數值通常我們不會加以改變。以下為本計數器的計數值寫入
方式:
out 43h,74h
out 41h,計數值低位元組
out 41h,計數值高位元組
計數器2在PC上是用來控制喇叭發聲的頻率,應寫入的計數值為1,193,180/頻率。以下為本計數器的計數值寫入方式:
out 43h,0B6h
out 42h,計數值低位元組
out 42h,計數值高位元組
另外,計數器2的輸出模式也常被規劃成模式0,做為播放數位語音之用,寫入值便是數位語音的電壓值,不過播放出來的品質大都不是很好罷了。
8255為可程式化的週邊界面,只用在XT上,AT則已取消使用這個元件,因此對於8255,我們只說明和XT相關且較重要的內容,至於詳細的內容,請參閱其他相關書籍。8255具有24位元的I/O線,並區分為兩組:Group
A和Group B,分別佔用12位元。而這24位元的I/O線又可區分為三個輸出入埠,其中
Port A和Port B係由Group A和Group B中的8個位元I/O線所組成,Port C則分為高四位元和低四位元,分別由Group
A和Group B剩下的四位元所組成。因此在規劃上,Port C可針對高四位元和低四位元分別程式化成不同的輸出入方式和處理
模式,Port A和Port B則不行。8255對於這24位元 I/O線的規劃方式,係經由其內部控制字組來完成的,這個控制字組的意義如下:
位元7 = 必須固定為1
位元6~5 = Group A模式,當位元6為1時,一律為模式2
位元4 = Port A輸出入方式,0表輸出,1表輸入
位元3 = Port C高四位元輸出入方式,0表輸出,1表輸入
位元2 = Group B模式
位元1 = Port B輸出入方式,0表輸出,1表輸入
位元0 = Port C低四位元輸出入方式,0表輸出,1表輸入
說明:
XT的設定值為99h,即Port A、Port C為輸入, Port B為輸出,採用的模式均為模式0。至於8255可規劃的三種模式名稱分別為:
模式0 = Basic Input/Output
模式1 = Strobed Input/Output
模式2 = Bi-Directional Bus
位元7 = 必須固定為0
位元6~4 = 不使用
位元3~1 = 選擇的位元
位元0 = 設定值
說明:位元重置格式只用在模式1和模式2上,用來控制岔斷訊號產生的禁能和允能。
在XT上,控制字組是在I/O Port 63h,而Port A、Port B、Port C則分別在I/O
Port 60h、61h、62h。其中Port A除了用來做為鍵盤資料的輸入外,亦可做為DIP開關1的輸入值,這項差別由Port
B位元7來控制。 Port B、Port C
各位元的意義如下:
位元7 = 0表啟用鍵盤,允許鍵盤岔斷的發生, Port A將讀取鍵盤掃描碼;1表鍵盤禁能,並清除鍵盤的輸入,Port
A將讀取 DIP開關1的值。
位元6 = 0表強迫鍵盤時基於低電位,1表鍵盤時基正常作用
位元5 = 0表啟用I/O通道檢查
位元4 = 0表啟用RAM同位檢查
位元3 = 控制錄音機馬達,0表運轉
位元2 = 值1表PC0讀取DIP開關2的位元0,0表讀取位元4
位元1 = 喇叭資料輸入控制
位元0 = 計時器Gate 2控制
說明:
喇叭的資料輸入係接至計時器2,而計時器2的輸出與否由Gate 2控制。在輸至喇叭前還有一個AND閘控制,因此欲使喇叭發聲,必須使得位元1和位元0均成為1,此時喇叭便會以計時器 2的輸出頻率發聲。關於計時器的部份,請參閱8237的說明。
位元7 = 1表RAM同位檢查錯誤
位元6 = 1表I/O通道檢查錯誤
位元5 = 計時器2輸出訊號
位元4 = 錄音機資料輸入
位元3~0 = DIP開關2讀取值。
在AT上,8255已不再使用。原Port 60h改接至8042鍵盤控制器,仍做為鍵盤資料讀取使用。Port 61h則改用ALS175來取代,並集結了Port B和Port C中幾個較重要的位元。至於Port 62h和63h,則均捨棄不用了。以下為AT中 Port61h各位元的意義,其中高4位元為僅讀位元:
位元7 = 1表RAM同位檢查錯誤
位元6 = 1表I/O通道檢查錯誤
位元5 = 計時器2輸出訊號
位元4 = RAM Reflesh訊號
位元3 = 1表啟用I/O通道檢查
位元2 = 1表啟用RAM同位檢查
位元1 = 喇叭資料輸入控制
位元0 = 計時器Gate 2控制
備註:
以上關於8255各I/O位元在XT上的作用, 作者參閱多本XT書籍後,發現所著內容均有所出入。雖然作者針對相異的部份,儘量和BIOS程式及線路圖搭配來做判斷,但因找不到XT機器做實際測試,因此不敢保證內容完全正確,但至少錯誤的機會應已較少。
8259為一種可程式化的優先序岔斷控制器,所有PC週邊硬體的岔斷均必須透過這個元件來觸發所對應的岔斷處理程式。以下我們先說明8259的硬體特性。8259共分成四個啟始命令字組ICW和三個操作命令字組OCW,前者做為初始化時使用,後者則可供程式自行使用。8259初始化的過程為:
送出ICW1
送出ICW2
if 串接模式 then 送出ICW3
if 需要ICW4 then 送出ICW4
各啟始命令字組的意義為:
位元7~5 = 岔斷向量位址(只用在MCS-80模式)
位元4 = 固定為1
位元3 = 0為邊緣觸發(edge trigger),1為位準觸發(level trigger)
位元2 = 呼叫位址間隔(只用在MCS-80模式),0為呼叫位址間隔8,1為呼叫位址間隔4
位元1 = 0為串接模式(cascade mode),1為單一模式(single mode)
位元0 = 0不需要ICW4,1需要ICW4
說明:
8259除了可供8088系列使用外,也可供MSC-80系列使用,因此當任何位元若標明只使用在MSC-80模式時,PC上均不需使用。另外,由於PC上使用的是8088系列的 CPU,必須利用ICW4指定為8088模式,因此本啟始命令的位元4、1均必須固定為1,位元7~5、2則可為0可為1。至於採用何種觸發方式,則依電路特性而定,PC上通常採用邊緣觸發,因此位元 3也大致固定為0。比較有爭議的是位元 1的值。在舊型的PC/XT上,由於只使用一個8259做為岔斷控制用,因此必須使用單一模式,故它的初值為13h。但到了PC/AT時,由於系統功能加強,原來的一個8259已不敷使用,於是便擴增為兩個8259串接在一起,因此這兩個8259便都必須使用初值11h。
(1) MCS-80模式
位元7~0 = 岔斷向量位址
(2) 8088模式
位元7~3 = 岔斷向量位址
位元2~0 = 固定為0
說明:
這個命令是用來設定硬體岔斷時,所要執行的岔斷向量啟始值。 PC/AT的第一個8259觸發的岔斷在08h~0Fh,因此初值為08h; 第二個8259觸發的岔斷在70h~77h,因此初值為 70h。這些初值若在不影響系統的岔斷功能下,是可以隨意改變的。
(1) 主控制器(master device)
位元7~0 = 各位元分別表示IRQx是否有串接另一個8259控制器,0表示沒有,1表示有。
(2) 次控制器(slave device)
位元7~3 = 固定為0
位元2~0 = 次控制器的識別碼。
說明:
這個初始命令必須有兩個以上的8259串接在一起時才使用的,因此PC/XT並不使用這個初始命令。至於PC/AT上的兩個8259,由於是串接在 IRQ2上的,因此主控制器(也就是第一個8259)的初值便必須為 04h。至於次控制器,由於必須配合所串接的 IRQ來做編號,因此次控制器的初值便必須為02h,否則無法正常工作。
位元7~5 = 固定為0
位元4 = 0為非特別全巢狀模式,1為特別全巢狀模式
位元3~2
0x 不帶緩衝模式
10 主控制器帶緩衝模式
11 次控制器帶緩衝模式
位元1 = 0表非自動結束岔斷(EOI),1表自動結束岔斷
位元0 = 0表MSC-80模式,1表8088模式
說明:
特別全巢狀模式 (special fully nested mode),主要用在大系統中使用多個8259串接模式時,以便規劃不同的岔斷權限,詳細資料請參閱相關書籍。通常我們均使用非特別全巢狀模式,也就是初始化時以IRQ0優先權最高,IRQ7最低(這個優先權是可以改變的)。而在某個岔斷發生處理時,優先權更高的岔斷允許再發生,以岔斷目前正在處理的岔斷,而相同或較低優先權的岔斷則不允許發生。至於是否要規劃成緩衝模式,必須視所連接系統之Data Bus線路而定。對於是否使用自動結束岔斷,則由作業系統或岔斷處理程式的設置程式來決定。一般使用自動結束岔斷對於岔斷處理程式會比較方便些,不會因忘了送出EOI命令(參閱OCW2命令)而使得系統功能停止或當機。但是它最大的缺點是,如果相同的IRQ岔斷一再發生,而該岔斷程式又使用了STI命令允許岔斷發生時(為了讓更高優先權的岔斷產生),則可能造成岔斷程式再被岔斷,導致重入問題,以及岔斷順序更動等問題。因此在絕大部份的情況下,大都會採用非自動岔斷結束,在PC上亦然。不過若使用非自動 EOI的結束方式時,岔斷處理程式在處理完岔斷後必須送出一個 EOI命令給8259,表示岔斷已處理完,否則8259便視為該岔斷未結束而不再產生下個岔斷了。
備註:
關於本初始命令的初值,由XT的BIOS查得為 09h,由286 AT的BIOS查得為 01h,也就是前者採用緩衝模式,後者並不採用緩衝模式。經查閱有關8259零件的手冊,其中說明緩衝模式主要用在具有 BUS驅動緩衝區的Data Bus,由8259的 SP/EN訊號來控制緩衝區。當不是緩衝模式時,這個訊號接腳在主控制器上必須接 Vcc,而在次控制器上則必須接地。再查閱86 XT和286、386 AT的線路圖,發現確實XT的設計電路是使用緩衝模式,而 286、386 AT的設計電路則為非緩衝模式。因此在初始化時,必須依PC的種類而有不同的初始化值(事實上,XT只有一個8259,在初始化過程方面便一定會有不太一樣的地方,必須與AT分別處理),如果未與設計的電路做好匹配的規劃,則有當機之虞(但並不一定會當機。據作者實際測試過,在某些AT上將8259規劃成緩衝模式會當機,而在某些AT上則不管是否規劃成緩衝模式卻仍都正常工作,這和主機電路板的線路設計有關)。
以下為各操作命令字組的意義:
位元7~0 = 分別表示IRQx是否啟動,0表示允能(enable),1表示禁能(disable)。
說明:
本命令也就是設定岔斷的罩遮值(IMR,Interrupt Mask Register)。在使用時,通常先讀取原值後,再設置所要處理的岔斷所對應的位元,以避免影響到其他岔斷。
位元7~5
000 取消自動EOI時旋轉優先權模式
001 不特別指定IRQx方式結束岔斷
010 無作用
011 指定IRQx方式結束岔斷
100 設定自動EOI時旋轉優先權模式
101 不特別指定IRQx結束岔斷時旋轉優先權
110 設定優先權
111 指定IRQx結束岔斷時旋轉優先權
位元4~3 = 固定為0
位元2~0 = 指定的IRQx
說明:
本命令是用來指定岔斷優先權的處理方式(請參閱相關書籍),以及指示岔斷是否處理完畢。一般在PC上大都使用 20h做不特別指定IRQx方式來結束8259的岔斷。所謂不特別指定IRQx方式,指的是要處理的 IRQ編號並不由位元2~0來指定,而以目前已發生且優先權最高的岔斷為準。
位元7 = 固定為0
位元6~5
0x 無作用
10 取消特殊罩值(reset special mask)
11 設定特殊罩值(set special mask)
位元4 = 固定為0
位元3 = 固定為1
位元2 = 0表使用岔斷方式服務,1表不使用岔斷方式服務(poll command)
位元1~0
0x 無作用
10 讀取岔斷需求暫存器(IRR)
11 讀取內部服務暫存器(ISR)
說明:
特殊罩值功能,主要是提供給需要任意改變岔斷的禁能、允能,而又不希望因未送出 EOI命令,而導致其他較低優先權的岔斷無法發生的程式使用。當設定了特殊罩值後,則每次在OCW1重設罩值時,均會將所有未被罩遮掉的IRQ重新啟用。 IRR及ISR這兩個暫存器的值可用來辨別各岔斷的產生與否。IRR (Interrupt Request Register)記錄了硬體已產生岔斷需求,但8259尚未發出岔斷訊號或 CPU尚未回應確認訊號的岔斷;ISR(Interrupt Service Register)則記錄了CPU已接收到岔斷訊號但處理程式尚未回應 EOI命令的岔斷。當要讀取這兩個暫存器值時,首先必須送出OCW3指定所要讀取的暫存器,然後再由相同的輸出入埠將之讀取。
備註:
不使用岔斷服務的方式(poll command),依8259之零件說明為RD訊號會讀取Priority Level值,其值意義如下:
位元7 = 1表有岔斷發生
位元6~3 = 保留
位元2~0 = 岔斷發生的編號
又說明Poll Command是使用在8259的岔斷輸出訊號不使用,或 CPU線路已將岔斷訊號輸入禁能的情況。據作者實際測試結果,在PC上將OCW3修改成Poll Command形態,並不影響到原岔斷的執行,讀取而得的值也並非Priority Level的值。至於為何如此,作者遍尋相關書籍,也問過許多硬體設計從業人員,竟找不到答案。作者猜測可能是因PC CPU仍然接收並使用8259的岔斷輸出訊號,使得8259的岔斷確認訊號並非由PollCommand的RD訊號確認所致,至於真正原因,則不得而知了。
當8259重新初始化後,IMR的值均會重設為00h(也就是允許所有的岔斷產生),並取消特殊罩值功能。因此當我們要重新初始化8259時,必須記錄原來的 IMR值,並在初始化後將之設回,以免初始化後某些原已被禁能的岔斷再次產生而發生問題。當然,初始化後視情況也必須重新設定OCW3的值。
上述所有命令字組在PC上均透過I/O Port 20h、21h(第一個8259)和A0h、A1h(第二個8259)來讀寫。I/O Port 20h和A0h做為ICW1、OCW2和OCW3命令的輸入,以及IRR、ISR暫存器值的輸出。I/O Port 21h和A1h則做為 ICW2、ICW3、ICW4和OCW1命令的輸入,以及 IMR暫存器值的輸出。至於8259是如何去分辨送來的是那個命令字組,這倒不必我們費心,因為這些命令字組中大都已安排好某些位元均固定為0或1。由這些固定位元,8259便能輕易地辨別出所輸入的命令種類。以下是目前在PC/AT中兩個8259所處理的16個硬體岔斷內容:
IRQ0 計時岔斷
IRQ1 鍵盤岔斷
IRQ2 串接第二個8259
IRQ3 次串列通訊埠(COM2)
IRQ4 主串列通訊埠(COM1)
IRQ5 印表機岔斷(LPT2)
IRQ6 軟碟岔斷
IRQ7 印表機岔斷(LPT1)
IRQ0 即時時脈岔斷
IRQ1 保留
IRQ2 保留
IRQ3 保留
IRQ4 保留
IRQ5 數學處理單元岔斷
IRQ6 硬碟岔斷
IRQ7 保留