dw做網(wǎng)站字體做多大今天新聞最新消息
《匯編語言》- 讀書筆記 - 第15章-外中斷
- 15.1 接口芯片和端口
- 15.2 外中斷信息
- 1. 可屏蔽中斷(Maskable Interrupt)
- 2. 不可屏蔽中斷(Non-Maskable Interrupt)
- 設(shè)計(jì)思想
- 15.3 PC 機(jī)鍵盤的處理過程
- 1. 鍵盤輸入
- 2. 引發(fā) 9 號中斷
- 3. 執(zhí)行 int 9 中斷例程
- 15.4 編寫int9 中斷例程
- 編程
- 思路
- 代碼
- 檢測點(diǎn) 15.1
- 15.5 安裝新的 int 9 中斷例程
- 分析
- 代碼
- 運(yùn)行效果
- 實(shí)驗(yàn) 15 安裝新的 int9 中斷例程
CPU
通過中斷機(jī)制
得知外部
輸入事件,并通過I/O接口
與數(shù)據(jù)總線
實(shí)現(xiàn)與外設(shè)的數(shù)據(jù)交換
,從而實(shí)現(xiàn)對外設(shè)輸入的有效處理。
CPU 對外設(shè)輸入的通常處理方法:
- 外設(shè)的輸入送入端口;
- 向 CPU 發(fā)出外中斷(可屏蔽中斷)信息;
CPU
檢測到可屏蔽中斷信息;
3.1. 如果IF=1
,CPU 在執(zhí)行完當(dāng)前指令后響應(yīng)中斷,執(zhí)行相應(yīng)的中斷例程;- 可在中斷例程中實(shí)現(xiàn)對外設(shè)輸入的處理。
端口和中斷機(jī)制,是 CPU 進(jìn)行 I/O 的基礎(chǔ)。
15.1 接口芯片和端口
CPU
通過端口
和外部設(shè)備
進(jìn)行聯(lián)系。
15.2 外中斷信息
外部設(shè)備
在完成一系列自己的工作后,需要將產(chǎn)生的數(shù)據(jù)
或狀態(tài)
發(fā)給CPU
處理時,就會觸發(fā)外中斷
- 中斷信息的發(fā)送過程大致如下:
-
中斷請求信號:
外設(shè)芯片在適當(dāng)時候會通過自身的中斷輸出引腳向主板上的中斷控制器發(fā)送中斷請求信號,這通常表現(xiàn)為一個電信號的變化。例如在8086體系結(jié)構(gòu)中,外設(shè)可以通過INTR(Interrupt Request)線向CPU發(fā)出中斷請求。 -
中斷控制器:
主板上的中斷控制器(如Intel 8259A可編程中斷控制器)負(fù)責(zé)接收來自多個外設(shè)的中斷請求,并根據(jù)它們的優(yōu)先級和中斷向量進(jìn)行管理。中斷控制器會將有效的中斷請求打包并通過IRQ(Interrupt Request Line)線傳輸?shù)紺PU。 -
CPU響應(yīng)中斷:
當(dāng)CPU在執(zhí)行完當(dāng)前指令后檢查中斷請求線時,如果發(fā)現(xiàn)有中斷請求存在,它會暫停當(dāng)前任務(wù),保存現(xiàn)場,然后通過讀取中斷向量表(IVT)獲取中斷服務(wù)程序(ISR)的地址,跳轉(zhuǎn)到相應(yīng)的處理程序執(zhí)行中斷處理。 -
線路連接:
中斷請求信號的傳送是通過主板上的硬件連線完成的。例如在8086/8088系統(tǒng)中,外設(shè)與CPU間的中斷請求線和中斷響應(yīng)線(INTA#)是主板上的物理連接線,它們屬于系統(tǒng)總線的一部分,通過這些線路上的電信號變化來進(jìn)行中斷請求和響應(yīng)的通訊。
注意,隨著技術(shù)的發(fā)展,更現(xiàn)代的計(jì)算機(jī)系統(tǒng)可能采用了更為復(fù)雜和高級的中斷控制器和總線標(biāo)準(zhǔn),但核心原理仍然是外設(shè)通過特定線路發(fā)送中斷信號給CPU,并由CPU依據(jù)一定的優(yōu)先級策略來響應(yīng)和處理中斷。
1. 可屏蔽中斷(Maskable Interrupt)
可屏蔽中斷 | CPU
在收到可屏蔽中斷
時會根據(jù) CF
的狀態(tài)來決定:執(zhí)行完當(dāng)前指令
后是否響應(yīng)
。
IF 狀態(tài) | 響應(yīng) | 不響應(yīng) |
---|---|---|
IF = 1 | ? | |
IF = 0 | ? |
- 中斷過程
可屏蔽中斷
的中斷過程
除了中斷類型碼是通過數(shù)據(jù)總線
從外部
傳進(jìn)CPU
的,其它與內(nèi)中斷相同。
我們可以通過指令(STI
, CLI
)設(shè)置IF
來控制是否響應(yīng)可屏蔽中斷
。
————?指?令?———— | —?功?能?— | 描述 |
---|---|---|
cli (Clear Interrupt Flag) | IF=0 禁止中斷 | CPU 執(zhí)行cli 將IF=0 后,僅保留對不可屏蔽中斷(NMI) 的響應(yīng),直至遇到STI 指令為止。此操作有助于保護(hù)在執(zhí)行重要且不能被打斷的代碼時,不被中斷處理程序打亂。 例如: 在更改棧指針(SS:SP)時,需要防止因中斷處理程序介入而破壞棧的狀態(tài)。 |
sti (Set Interrupt Flag) | IF=1 允許中斷 | CPU 執(zhí)行sti 將IF=1 后,重新開啟中斷響應(yīng) 功能。CPU會再次響應(yīng)掛起 的中斷請求,恢復(fù)正常的中斷處理流程。這對于完成關(guān)鍵區(qū)域操作后恢復(fù)系統(tǒng)的正常中斷響應(yīng)至關(guān)重要。 |
- 在IF=0期間,中斷請求不會丟失,但會被延遲處理,等待CPU重新打開中斷響應(yīng)后,按照中斷控制器維護(hù)的隊(duì)列順序逐一處理。是否超時以及超時后的處理方法取決于設(shè)備本身的特性以及操作系統(tǒng)的調(diào)度策略。
硬件中斷控制器(如Intel 8259A可編程中斷控制器)負(fù)責(zé)管理和維持中斷請求的排隊(duì)。 CLI
與STI
結(jié)合運(yùn)用,構(gòu)建短暫的中斷防護(hù)區(qū)域,確保其間代碼免受外部中斷影響,待關(guān)鍵操作完成后通過STI
恢復(fù)中斷響應(yīng),保障系統(tǒng)并發(fā)處理能力和實(shí)時響應(yīng)性能。在多任務(wù)OS中,內(nèi)核常在切換進(jìn)程環(huán)境、管控硬件資源等關(guān)鍵場景調(diào)用這兩條指令。
2. 不可屏蔽中斷(Non-Maskable Interrupt)
當(dāng)不可屏蔽中斷發(fā)生時,CPU會立即停止當(dāng)前的執(zhí)行流程,保存必要的上下文信息,然后跳轉(zhuǎn)到預(yù)設(shè)的NMI處理程序去執(zhí)行相應(yīng)的處理代碼。
即使在 CPU 執(zhí)行 CLI 指令 禁止了可屏蔽中斷 的情況下也不例外。
由于NMI的重要性,其處理過程一般要求快速、簡潔,盡量減少對系統(tǒng)運(yùn)行的影響。
- NMI觸發(fā)的原因可能包括但不限于以下幾種情況:
- 硬件故障:如電源故障、內(nèi)存錯誤、嚴(yán)重硬件故障等;
- 系統(tǒng)調(diào)試需求:在調(diào)試環(huán)境中,開發(fā)者可能通過人工或硬件手段觸發(fā)NMI,以便快速進(jìn)入調(diào)試模式;
- 監(jiān)控程序:某些嵌入式系統(tǒng)或服務(wù)器中,監(jiān)控程序可能會通過NMI報(bào)告嚴(yán)重的系統(tǒng)錯誤或警告;
- 性能計(jì)數(shù)器溢出:某些高性能處理器中,性能監(jiān)控單元(PMU)的計(jì)數(shù)器溢出可能導(dǎo)致NMI。
設(shè)計(jì)思想
可屏蔽中斷:幾乎都是外設(shè)觸發(fā)的。告訴CPU來活了。
不可屏蔽中斷:是發(fā)生了必須緊急處理的事件。CPU要先解決它了再說別的。
15.3 PC 機(jī)鍵盤的處理過程
1. 鍵盤輸入
鍵盤上每個鍵分:按下
、松開
兩種狀態(tài)都會產(chǎn)生相應(yīng)的掃描碼
。
按下時的叫通碼
,松開時的叫斷碼
。
它會被送入主板上的相關(guān)接口芯片的寄存器中,該寄存器的端口
地址為 60h
斷碼 = 通碼 + 80h
比如: g 鍵的通碼為 22h,斷碼為 a2h。
表 15.1 是鍵盤上部分鍵的掃描碼,只列出通碼。
2. 引發(fā) 9 號中斷
60h
端口收到信號,相關(guān)的芯片就會向 CPU
發(fā)出中斷類型碼
為9
的可屏蔽中斷
信息。
CPU
收到后,如果 IF=1
,則響應(yīng)中斷,引發(fā)中斷過程
,轉(zhuǎn)去執(zhí)行 int 9
中斷例程。
3. 執(zhí)行 int 9 中斷例程
BIOS 提供 int 9
中斷例程,處理基本的鍵盤輸入:
- 首先,中斷例程通常會從60h端口讀取掃描碼。
- 處理掃描碼
2.1. 若是字符鍵,則將掃描碼轉(zhuǎn)換為
ASCII碼,存入
鍵盤緩沖區(qū)。 2.2. 若是
功能鍵或
控制鍵,則可能更新內(nèi)存中的
鍵盤狀態(tài)字節(jié)`或其他內(nèi)部狀態(tài)。 - 向鍵盤控制器發(fā)送應(yīng)答信號,表明中斷已被處理。
BIOS鍵盤緩沖區(qū):
BIOS鍵盤緩沖區(qū)
是系統(tǒng)啟動時BIOS設(shè)置的一塊內(nèi)存區(qū)域,用于存儲15
個鍵盤輸入事件,每個事件占用2字節(jié)
,其中高位
字節(jié)為掃描碼
,低位
字節(jié)為字符碼
。- 這個緩沖區(qū)通過
int 9
中斷機(jī)制收集并暫存鍵盤輸入,確保在操作系統(tǒng)尚未完全加載或正忙時也能記錄用戶的按鍵動作。
字單元(1) | 字單元(2) | … | 字單元(15) |
---|---|---|---|
高位-掃描碼 | 高位-掃描碼 | … | 高位-掃描碼 |
高位-字符碼 | 高位-字符碼 | … | 高位-字符碼 |
0040:17
單元存儲鍵盤狀態(tài)字節(jié),該字節(jié)記錄了控制鍵和切換鍵的狀態(tài)。字節(jié)各位信息如下。
位 | 狀態(tài) |
---|---|
0 | 右 Shift 狀態(tài),置1表示按下右 Shift 鍵: |
1 | 左 Shitt 狀態(tài),置1表示按下左 Shit 鍵; |
2 | Ctrl 狀態(tài),置1表示按下 Ctrl 鍵; |
3 | Alt 狀態(tài),置1表示按下 Alt 鍵; |
4 | ScrollLock狀態(tài),置1表示 Scroll 指示燈亮; |
5 | NumLock 狀態(tài),置1表示小鍵盤輸入的是數(shù)字; |
6 | CapsLock 狀態(tài),置1表示輸入大寫字母: |
7 | Insert 狀態(tài),置1表示處于刪除態(tài)。 |
15.4 編寫int9 中斷例程
鍵盤輸入的處理過程:
- 鍵盤產(chǎn)生掃描碼;
- 掃描碼送入
60h
端口; - 引發(fā)
9
號中斷; - CPU 執(zhí)行
int 9
中斷例程處理鍵盤輸入。
前三步都是硬件系統(tǒng)的活,我們能插手的就只有和4步。但因?yàn)?int 9
中斷處理程序要與一些硬件細(xì)節(jié)打交到。所以我們只對 int 9
做下封裝擴(kuò)展。
編程
在屏幕中間依次顯示“a”~“z”
,并可以讓人看清。在顯示的過程中,按下 Esc
鍵后,改變顯示的顏色。
思路
- 先循環(huán)顯示
a ~ z
。(為了看清,書上給的方案是空循環(huán)模擬延遲效果) - 自己寫一個
int 9
代替原版。
2.1. 我們自己的int 9
中調(diào)用原版 int 9
。
2.2. 拿到原版int 9
返回的掃描碼。
2.3. 判斷如果是Esc
修改顯存改變顏色
。
代碼
assume cs:code
stack segmentdb 128 dup(0)
stack endsdata segmentoint9 dw 0,0
data endscode segmentstart: mov ax,stack ; 設(shè)置棧段和棧頂位置mov ss,axmov sp,128mov ax,data ; 設(shè)置數(shù)據(jù)段mov ds,axmov ax,0 ; 設(shè)置附加段mov es,ax; ------------ 保存原 int 9 中斷列和入口到 ds:0, ds:2 ------------push es:[9*4]pop ds:[0]push es:[9*4+2]pop ds: [2]; ---------------- 將我們的新 int 9 寫入中斷向量表 ----------------mov word ptr es:[9*4],offset int9mov es:[9*4+2],cs; ------------------------- 顯示 a 到 z -------------------------mov ax,0b800h ; 設(shè)置顯存段mov es,axmov ah,'a' ; 要顯示的字符串,從 a 開始s: mov es:[160*12+40*2],ah ; 顯示字符call delay ; 調(diào)用子程序:延時inc ah ; 下一個字符cmp ah,'z' ; 如果不是z繼續(xù)循環(huán)jna s; ------------- 將中斷向量表中 int 9恢復(fù)為原來的地址 -------------mov ax,0mov es,axpush ds:[0]pop es:[9*4]push ds:[2]pop es:[9*4+2]mov ax,4c00hint 21h
; =======================================================
; --------------------- 子程序 delay -------------------
; 讓CPU空循環(huán),模擬延時效果
; -------------------------------------------------------
; 參數(shù): 無
; 返回: 無
; -------------------------------------------------------
delay:push ax ; 備份寄存器push dxmov dx,2h ; 循環(huán) 2h 次,可以自己把握mov ax,0
delays: sub ax,1sbb dx,0 ; 10000000h 循環(huán)遞減cmp ax,0 ; 直到 ax, dx 都為 0 才跳出循環(huán)jne delayscmp dx,0jne delayspop dx ; 還原寄存器pop axret ; 返回
; ---------------------- 子程序 delay -------------------
; =======================================================; =======================================================
; --------------------- 子程序 int 9 -------------------
; 調(diào)用原 int 9 獲取掃描碼,實(shí)現(xiàn)按 Esc 變色
; -------------------------------------------------------
; 參數(shù): 無
; 返回: 無
; -------------------------------------------------------
int9:push ax ; 備份寄存器push dxpush esin al,60h ; 從60h端口讀取數(shù)據(jù)pushfpushfpop bxand bh,11111100bpush bxpopfcall dword ptr ds:[0] ; 調(diào)用原來的 int 9 中斷例程cmp al,1jne int9retmov ax,0b800hmov es,axinc byte ptr es:[160*12+40*2+1]int9ret:pop es ; 還原寄存器pop dxpop axiret ; 返回
; --------------------- 子程序 int 9 ------------------
; =======================================================
code ends
end start
檢測點(diǎn) 15.1
《匯編語言》- 讀書筆記 - 各章檢測點(diǎn)歸檔 - 檢測點(diǎn) 15.1
15.5 安裝新的 int 9 中斷例程
任務(wù) | 安裝一個新的 int9 中斷例程。 |
---|---|
功能 | 在 DOS下,按F1鍵后改變當(dāng)前屏幕的顯示顏色,其他的鍵照常處理 |
分析
- 改變屏幕的顯示顏色。
改變從B8000H
開始的4000
個字節(jié)中的所有奇
地址單元中的內(nèi)容
mov ax,0b800hmov es axmov bx,1mov cx,2000
s: inc byte ptr es:[bx]add bx,2loop s
-
按鍵常規(guī)處理
直接調(diào)用原 int 9 -
原 int9 入口地址
不能保存在安裝程序中。我們把它放在0:0200
。 -
安裝新 int9 中斷例程
0:0200 ~ 0:0203
用來保存原 int9 的地址了。
我們保存新 int9 時從0:0204
開始。
代碼
assume cs:code
stack segmentdb 128 dup(0)
stack endscode segmentstart: mov ax,stack ; 設(shè)置棧段和棧頂位置mov ss,axmov sp,128; -------- 安裝: 復(fù)制中斷例程到目標(biāo)內(nèi)存 -------mov ax,cs ;設(shè)置 ds:si 指向源地址mov ds,axmov si,offset int9mov ax,0 ;設(shè)置 es:di 指向目的地址mov es,axmov di,204h mov cx,offset int9end-offset int9 ;設(shè)置 cx為傳輸長度cld ;設(shè)置傳輸方向?yàn)檎?。movsb中si,di遞增rep movsb ;重復(fù)復(fù)制數(shù)據(jù)次數(shù)由 cx 控制; -------- 安裝: 復(fù)制中斷例程到目標(biāo)內(nèi)存 -------; ---------- 備份原 int9 入口到 [0:200~0203] ----------push es:[9*4]pop es:[200h]push es:[9*4+2]pop es:[202h]; ---------- 備份原 int9 入口到 [0:200~0203] ----------; ---------- 設(shè)置中斷向量表 ----------cli ; 臨時屏蔽中斷mov word ptr es:[9*4],204h ; 設(shè)置的偏移地址(0~3用來存原int9地址了)mov word ptr es:[9*4+2],0 ; 設(shè)置的段地址sti ; 恢復(fù)中斷; ---------- 設(shè)置中斷向量表 ----------ok: mov ax,4c00hint 21h; =======================================================
; --------------------- 子程序 int 9 -------------------
; 調(diào)用原 int 9 獲取掃描碼,實(shí)現(xiàn)按 Esc 變色
; -------------------------------------------------------
; 參數(shù): 無
; 返回: 無
; -------------------------------------------------------
int9:push ax ; 備份寄存器push bxpush cxpush esin al,60h ; 從60h端口讀取數(shù)據(jù); 模擬 int 指令,用 call 調(diào)用原 int 9pushf ; 進(jìn)入中斷后 IF、TF已經(jīng)是0 直接入棧即可call dword ptr cs:[200h] ; 調(diào)用原來的 int 9 中斷例程cmp al,3bh ; 判斷是否 F1 鍵jne int9ret ; 如果不是直接結(jié)束mov ax,0b800h ; 設(shè)置顯存mov es,axmov bx,1mov cx,2000s: inc byte ptr es:[bx]add bx,2loop sint9ret:pop es ; 還原寄存器pop cxpop bxpop axiret ; 返回
int9end:nop; --------------------- 子程序 int 9 ------------------
; =======================================================
code ends
end start
運(yùn)行效果
實(shí)驗(yàn) 15 安裝新的 int9 中斷例程
《匯編語言》- 讀書筆記 - 第15章-外中斷-實(shí)驗(yàn)15 安裝新的 int9 中斷例程