彙編語言(王爽版)學習筆記 第十五章 外中斷(檢測點15.1)


在這裏插入圖片描述

15.1 接口芯片和端口

在這裏插入圖片描述


15.2 外中斷信息

在這裏插入圖片描述

1.可屏蔽中斷

在這裏插入圖片描述

2.不可屏蔽中斷

在這裏插入圖片描述


15.3 PC機鍵盤的處理過程

1.鍵盤輸入

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2.引發9號中斷

在這裏插入圖片描述

3.執行int 9中斷例程

在這裏插入圖片描述


15.4 編寫int 9中斷例程

鍵盤輸入的處理過程:
1.鍵盤產生掃描碼
2.掃描碼送入60h端口
3.引發9號中斷
4.CPU執行int9中斷例程處理鍵盤輸入

在這裏插入圖片描述

編程,在屏幕中間依次顯示"a"-“z”,並可以讓人看清。在顯示的過程中,按下Esc鍵後,改變顯示的顏色。

在這裏插入圖片描述
在這裏插入圖片描述
程序如下:

DATAS SEGMENT
    ;此處輸入數據段代碼  
DATAS ENDS

STACK SEGMENT
    db 128 dup (0)
STACK ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATAS,SS:STACK
START:
   	mov ax,stack
   	mov ss,ax
   	mov sp,128
   	
   	mov ax,0b800h
   	mov es,ax
   	mov ah,'a'
  s:
  	mov es:[160*12+40*2],ah
  	call delay
  	inc ah
  	cmp ah,'z'
  	jna s
  	
   	 
    MOV AH,4CH
    INT 21H
    
  delay:
  push ax
  push dx
  mov dx,10h	;循環100000次
  mov ax,0
s1:
  sub ax,1
  sbb dx,0
  cmp ax,0
  jne s1
  cmp dx,0
  jne s1
  pop dx
  pop ax
  ret
CODES ENDS
    END START

運行結果:
在這裏插入圖片描述

如何實現按下Esc鍵後,改變顯示的顏色呢?

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
程序如下:

DATA SEGMENT
    dw 0,0 
DATA ENDS

STACK SEGMENT
    db 128 dup (0)
STACK ENDS

CODES SEGMENT
    ASSUME CS:CODES,DS:DATA,SS:STACK
START:
   	mov ax,stack
   	mov ss,ax
   	mov sp,128
   	
   	mov ax,data
   	mov ds,ax
   	
   	mov ax,0
   	mov es,ax
   	push es:[9*4]
   	pop ds:[0]	;將原來int 9中斷例程的入口地址保存在ds:0、ds:2單元中
   	push es:[9*4+2]
   	pop ds:[2]
   	
   	mov word ptr es:[9*4],offset newint9;在中斷向量表中設置新的 int 9中斷例程的入口地址
   	mov es:[9*4+2],cs

   	mov ax,0b800h
   	mov es,ax
   	mov ah,'a'
  s:
  	mov es:[160*12+40*2],ah
  	call delay
  	inc ah
  	cmp ah,'z'
  	jna s
  	
  	push ds:[0];將中斷向量表中int 9中斷例程的入口恢復爲原來的地址
  	pop es:[9*4]
  	push ds:[2]
  	pop es:[9*4+2]
   	 
    MOV AH,4CH
    INT 21H
    
  delay:
  push ax
  push dx
  mov dx,10h
  mov ax,0
s1:
  sub ax,1
  sbb dx,0
  cmp ax,0
  jne s1
  cmp dx,0
  jne s1
  pop dx
  pop ax
  ret
  
newint9:
  push ax
  push bx
  push es
  
  in al,60h
  pushf	;對應後面的調用原int 9中斷
  pushf	;對應後面的popf
  pop bx
  and bh,11111100b ;IF和TF是標誌寄存器的第9位和第8位,都置爲0
  push ax
  popf
  call dword ptr ds:[0]	;對int指令進行模擬,調用原來的int 9中斷例程
  
  cmp al,1
  jne int9ret
  
  mov ax,0b800h
  mov es,ax
  inc byte ptr es:[160*12+40*2+1]	;屬性值加1,改變顏色
  
int9ret:
  pop es
  pop bx
  pop ax
  iret
  
CODES ENDS
    END START

運行結果:
在這裏插入圖片描述


檢測點 15.1

(1)仔細分析一下上面的int 9中斷例程,看看是否可以精簡一下?

其實在我們的int 9中斷例程中,模擬int指令調用原int 9中斷例程的程序段是可以精簡的,因爲在進入中斷例程後,IF和TF都已經置零,沒有必要再進行設置了。對於程序段:

pushf                           ;將寄存器值入棧
pushf                           ;將寄存器值入棧
pop ax            ;彈棧到ax中,(ax)=(flag)
and ah, 11111100b  ;注意是高8位,IF和TF是標誌位中的第9和第8位,按位與
push ax                        ;將修改後的值入棧。
popf                            ;將修改後的值彈棧到標準寄存器中。這時IF=0,TF=0
call word ptr ds:[0];調用原來的int9中斷例程。


可以精簡爲:
pushf                  
call word ptr ds:[0] 
兩條指令。

程序分析:

【1】由於我們無論是調用那個中斷處理例程,CPU都幹如下的活:
       (1)從中斷信息中取得中斷類型碼
       (2)標誌寄存器入棧保存(因爲在中斷過程中要改變標誌寄存器的值。)
       (3)設置標誌寄存器的第8位TF(跟蹤標誌)和第9位IF(中斷標誌)爲0.(防止單步中斷和其他外部中斷髮生)
       (4)cs的內容入棧
       (5)IP的內容入棧
       (6)設置ip的值爲:N(中斷類型碼)*4;設置cs的值:N*4+2

所以第二個pushf是多餘的指令,然後是設置IF和TF的指令也是多餘的了。

【2】爲什麼還有個pushf呢?
這個pushf指令壓棧標誌寄存器,確實是保護標誌寄存器的值,也是爲了與中斷程序中的iret(它內部CPU操作步驟有popf)相呼應。
如果沒有這個pushf,那麼iret指令執行中出棧到標準寄存器的值可能不正確了。

在這裏插入圖片描述
程序分析:

【1】關於設置中斷向量表的指令,在程序中就2段。
mov word ptr es:[9*4], offset int9
mov es:[9*4+2], cs          ;將新的int9入口地址寫入中斷向量表中

; 將中斷向量回寫回中斷向量表中

mov ax, 0
mov es, ax                  ;將es指向0000段內存中斷向量表
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2] 

如果在指令執行在這2段中間,引發了鍵盤中斷事件,由於正在設置中斷向量表,故(ip)和(cs)值可能不確定。爲了避免這2段代碼不受到中斷事件的干擾,將中斷屏蔽了。

【2】sti和cli指令的用法:

       cli 禁止中斷髮生
       sti 允許中斷髮生

【3】這二段代碼前後加上cli和sti指令即可:

;在中斷向量表中設置新的中斷入口地址的時候不讓其發生中斷

cli
mov word ptr es:[9*4],offset int9
mov word ptr es:[9*4+2],cs
sti

恢復中斷向量表int9的源地址時:

cli
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2]
sti

15.5 安裝新的int9中斷例程

在這裏插入圖片描述
在這裏插入圖片描述
完整代碼如下:


ASSUME CS:CODES
STACK SEGMENT
    db 128 dup (0)
STACK ENDS

CODES SEGMENT
    
    
START:
   	mov ax,stack
   	mov ss,ax
   	mov sp,128
   	
	push cs
	pop ds
   	
   	mov ax,0
   	mov es,ax
   	
   	mov si,offset int9	;設置ds:si指向源地址
   	mov di,204h 	;設置es:di指向目的地址
   	mov cx,offset int9end - offset int9		;設置cx爲傳輸長度
   	cld		;設置傳輸方向爲正
   	
   	rep movsb	;重複前綴指令,在cx不等於0的情況下執行movsb,每次cx減1.movsb把ds:[si]的cx個字節複製到es:[di]
   	
   	
   	
   	
   	push es:[9*4]
   	pop ds:[200h]	;將原來int 9中斷例程的入口地址保存在ds:200h、ds:202h單元中
   	push es:[9*4+2]
   	pop ds:[202h]
   	
   	cli
   	mov word ptr es:[9*4],204h;把新的int 9中斷例程安裝在0:204處
	mov word ptr es:[9*4+2],0
	sti
	
	MOV AH,4CH
    INT 21H
    
	
  
int9:
  push ax
  push bx
  push cx
  push es
  
  in al,60h
  pushf	;對應後面的調用原int 9中斷  
  call dword ptr cs:[200h]	;對int指令進行模擬,調用原來的int 9中斷例程
  
  cmp al,3bh	;F1的掃描碼爲3bh
  jne int9ret
  
  mov ax,0b800h
  mov es,ax
  mov bx,1
  mov cx,2000
s:
  inc byte ptr es:[bx]
  add bx,2
  loop s
  
int9ret:
  pop es
  pop cx
  pop bx
  pop ax
  iret

int9end:nop
  
CODES ENDS
    END START

不過這段書上的代碼我運行起來沒有結果,於是我把新裝的int 9 中斷和前面動態顯示’a’-'z’字符的代碼組合起來了。


ASSUME CS:CODES,ss:stack
STACK SEGMENT
    db 128 dup (0)
STACK ENDS

CODES SEGMENT
    
    
START:
   	mov ax,stack
   	mov ss,ax
   	mov sp,128
   	
   
	push cs
	pop ds
   	
   	mov ax,0
   	mov es,ax
   	
   	mov si,offset int9	;設置ds:si指向源地址
   	mov di,204h 	;設置es:di指向目的地址
   	mov cx,offset int9end - offset int9		;設置cx爲傳輸長度
   	cld		;設置傳輸方向爲正
   	
   	rep movsb	;重複前綴指令,在cx不等於0的情況下執行movsb,每次cx減1.movsb把ds:[si]的cx個字節複製到es:[di]
   	
   	
   	
   	
   	push es:[9*4]
   	pop ds:[200h]	;將原來int 9中斷例程的入口地址保存在ds:200h、ds:202h單元中
   	push es:[9*4+2]
   	pop ds:[202h]
   	
   	cli
   	mov word ptr es:[9*4],204h;把新的int 9中斷例程安裝在0:204處
	mov word ptr es:[9*4+2],0
	sti

call start2
	MOV AH,4CH
    INT 21H
    
	
  
int9:
  push ax
  push bx
  push cx
  push es
  
  in al,60h
  pushf	;對應後面的調用原int 9中斷  
  call dword ptr cs:[200h]	;對int指令進行模擬,調用原來的int 9中斷例程
  
  cmp al,3bh	;F1的掃描碼爲3bh
  jne int9ret
  
  mov ax,0b800h
  mov es,ax
  mov bx,1
  mov cx,2000
s:
  inc byte ptr es:[bx]
  add bx,2
  loop s
  
int9ret:
  pop es
  pop cx
  pop bx
  pop ax
  iret

int9end:nop
  
start2:
	mov ax,0b800h
   	mov es,ax
   	mov ah,'a'
  s0:
  	mov es:[160*12+40*2],ah
  	call delay
  	inc ah
  	cmp ah,'z'
  	jna s0
  	
   	 
    MOV AH,4CH
    INT 21H
    
  delay:
  push ax
  push dx
  mov dx,10h	;循環100000次
  mov ax,0
s1:
  sub ax,1
  sbb dx,0
  cmp ax,0
  jne s1
  cmp dx,0
  jne s1
  pop dx
  pop ax
  ret
   	
CODES ENDS
    END START

運行結果如下(突然鬼畜了起來哈哈哈):
在這裏插入圖片描述


總結

這一章中,我們通過對鍵盤輸入的處理,講解了CPU對外設輸入的通常處理方法。
即:

  1. 外設的輸入送入端口;
  2. 向CPU發出外中斷(可屏蔽中斷)信息;
  3. CPU檢測到可屏蔽中斷信息,如果IF=1,CPU在執行完當前指令後響應中斷,執行相應的中斷例程;
  4. 可在中斷例程中實現對外設輸入的處理。

端口和中斷機制,是CPU進行I/O的基礎。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章