• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            luqingfei@C++

            為中華之崛起而崛起!
            兼聽則明,偏聽則暗。

            匯編語言--外中斷

             

            外中斷

             

            以前我們討論的都是CPU對指令的執行。

            我們知道,CPU在計算機系統中,除了能夠執行指令,進行運算以外,還應該能夠對外部設備進行控制,接收它們的輸入,向它們進行輸出。也就是說,CPU除了有運算能力外,還要有I/OInput/Output,輸入/輸出)能力。

            比如,我們按下鍵盤上的確個鍵,CPU最終要能夠處理這個鍵。在使用文本編輯器時,按下a鍵后,我們可以看到屏幕上出現“a”,是CPU將從鍵盤上輸入的鍵所對應的字符送到顯示上的。

             

            要及時處理外設的輸入,顯然需要解決兩個問題:

            一是外設的輸入隨時可能發生,CPU如何得知?

            二是CPU從何處得到外設的輸入?

             

             

             

            接口芯片和端口

            在前面我們知道,PC系統的接口卡和主板上,裝有各種接口芯片。

            這些外設接口芯片的內部有若干寄存器,CPU將這些寄存器當作端口來訪問。

             

            外設的輸入不直接送入內存和CPU,而是送入相關的接口芯片的端口中;

            CPU向外設的輸出也不是直接送入外設,而是先送入端口中,再由相關的芯片送到外設。

            CPU還可以向外設輸出控制命令,而這些控制命令也是先送到相關芯片的端口中,然后再由相關的芯片根據命令對外設實施控制。

             

            可見,CPU通過端口和外部設備進行聯系

             

             

             

            外中斷信息

            現在,我們知道了外設的輸入被存放在端口中,可是外設的輸入隨時都有可能到達,CPU如何及時地知道,并進行處理呢?更一般地講,就是外設隨時都可能發生需要CPU及時處理的事件,CPU如何及時得知并進行處理?

             

                   CPU提供中斷機制來滿足這種需要。前面講過,當CPU的內部有需要處理的事情發生的時候,將產生中斷信息,引發中斷過程。這種中斷信息來自CPU的內部。

             

                   還有一種中斷信息,來自于CPU外部,當CPU外部有需要處理的事情發生的時候,比如說,外設的輸入到達,相關芯片將向CPU發出相應的中斷信息。CPU在執行完當前指令后,可以檢測到發送過來的中斷信息,引發中斷過程,處理外設的輸入。

             

                   PC系統中,外中斷源一共有兩類:

            1、可屏蔽中斷

                   可屏蔽中斷是CPU可以不響應的外中斷,CPU是否響應可屏蔽中斷,要看標志寄存器的IF位的設置。當CPU檢測到可屏蔽中斷信息時,如果IF=1,則CPU在執行完當前指令后響應中斷,引發中斷過程;如果IF=0,則不響應可屏蔽中斷。

                   回憶一下內中斷所引發的中斷過程:

                   1)取中斷類型碼n

                   2)標志寄存器入棧,IF=0TF=0

                   3CSIP入棧;

                   4(IP)=(n*4)(CS)=(n*4+2)

                   由此轉去執行中斷處理程序。

             

                   可屏蔽中斷所引發的中斷過程,除在第1步的實現上有所不同外,基本上和內中斷的中斷過程相同。因為可屏蔽中斷信息來自于CPU外部,中斷類型碼是通過數據總路線送入CPU的;而內中斷的中斷類型碼是在CPU內部產生的。

             

                   現在,我們可以解釋中斷過程中將IF設置為0的原因了。將IF0的原因就是,在進入中斷處理程序后,禁止其他的可屏蔽中斷。

             

                   當然,如果在中斷處理程序中需要處理可屏蔽中斷,可以用指令將IF18086CPU提供的設置IF的指令如下:

                   sti,用于設置IF=1

                   cli,用于設置IF=0

             

            2、不可屏蔽中斷

                   不可屏蔽中斷是CPU必須響應的外中斷。當CPU檢測到不可屏蔽中斷信息時,則在執行完當前指令后,立即響應,引發中斷過程。

                   對于8086CPU,不可屏蔽中斷的中斷類型碼固定為2,所以中斷過程中,不需要取中斷類型碼。則不可屏蔽中斷的中斷過程為:

                   1)標志寄存器入棧,IF=0TF=0

                   2CSIP入棧;

                   3(IP)=(8)(CS)=(0AH)

             

                   幾乎所有由外設引發的外中斷,都是可屏蔽中斷。當外設有需要處理的事件(比如說鍵盤輸入)發生時,相關芯片向CPU發出可屏蔽中斷信息。不可屏蔽中斷是在系統中有必須處理的情況發生時用來通知CPU的中斷信息。

             

             

             

             

            PC機鍵盤的處理過程

            下面來看一下鍵盤輸入的處理過程,并以此來體會一下PC機處理外設輸入的基本方法。

            1、鍵盤輸入

                   鍵盤上的每一個鍵相當于一個開關,鍵盤中有一個芯片對鍵盤上的每一個鍵的開關狀態進行掃描。

                   按下一個鍵時,開關接通,該芯片就產生一個掃描碼,掃描碼說明了按下的鍵在鍵盤上的位置。掃描碼被送入主板上的相關接口芯片的寄存器中,該寄存器的端口地址為60H

                   松開按下的鍵時,也產生一個掃描碼,掃描碼說明了松開的鍵在鍵盤上的位置。松開按鍵時產生的掃描碼也被送入60H端口中。

                   一般將按下一個鍵時產生的掃描碼稱為通碼,松開一個鍵產生的掃描碼稱為斷碼。

                   掃描碼長度為一個字節,通碼的第7位為0,斷碼的第7位為1,即:

                   斷碼=通碼+80H

                   比如:g鍵的通碼為22H,斷碼為a2H

             

            2、引發9號中斷

                   鍵盤的輸入到達60H端口時,相關的芯片就會向CPU發出中斷類型碼為9的可屏蔽中斷信息。CPU檢測到該中斷信息后,如果IF=1,則響應中斷,引發中斷過程,轉去執行int 9中斷例程。

             

            3、執行int 9中斷例程

                   BIOS提供了int 9中斷例程,用來進行基本的鍵盤輸入處理,主要的工作如下:

                   1)讀出60H端口中的掃描碼;

                   2)如果是字符鍵的掃描碼,將該掃描碼和它所對應的字符碼(即ASCII碼)送入內存中的BIOS鍵盤緩沖區;如果是控制鍵(比如Ctrl)和切換鍵(比如CapsLock)的掃描碼,則將其轉變為狀態字節(用二進制位記錄控制鍵和切換鍵狀態的字節)寫入內存中存儲狀態字節的單元

                   3)對鍵盤系統進行相關的控制,比如說,向相關芯片發出應答信息。

             

                   BIOS鍵盤緩沖區是系統啟動后,BIOS用于存放int 9中斷例程所接收的鍵盤輸入的內存區。該內存區可以存儲15個鍵盤輸入,因為int 9中斷例程除了接收掃描碼外,還要產生和掃描碼對應的字符碼,所以在BIOS鍵盤緩沖區中,一個鍵盤輸入用一個字單元存放高位字節存放掃描碼,低位字節存放字符碼

             

                   0040:17單元存儲鍵盤狀態字節,該字節記錄了控制鍵和切換鍵的狀態。鍵盤狀態字節各位記錄的信息如下:

                   0:右shift狀態,置1表示按下右shift鍵;

                   1:左shift狀態,置1表示按下左shift鍵;

                   2Ctrl狀態,置1表示按下Ctrl鍵;

                   3Alt狀態,置1表示按下Alt鍵;

                   4ScrolLock狀態,置1表示Scroll指示燈亮;

                   5NumLock狀態,置1表示小鍵盤輸入的是數字;

                   6CapsLock狀態,置1表示輸入大寫字母;

                   7Insert狀態:置1表示處于刪除狀態。

             

             

             

             

            編寫int 9中斷例程

            鍵盤輸入的處理過程:

            1)鍵盤產生掃描碼;

            2)掃描碼送入60h端口;

            3)引發9號中斷;

            4CPU執行int 9中斷例程處理鍵盤輸入。

             

            上面的過程中,第(1)、(2)、(3)步都是由硬件系統完成的。我們能夠改變的只有int 9的中斷處理程序。

             

            編程:在屏蔽中間依次顯示“a~z”,并可以讓人看清。在顯示的過程中,按下Esc鍵后,改變顯示的顏色。

            assume cs:code

            code segment

             start:  mov ax,0b800h

                          mov es,ax

                          mov ah,’a’

                   s:     mov es:[160*12+40*2],ah

                          inc ah

                          cmp ah,’z’

                          jna s

             

                          mov ax,4c00h

                          int 21h

            code ends

            end start

             

            上面的程序的執行過程中,我們無法看清屏幕上的顯示,因為一個字母剛顯示到屏幕上,因為CPU執行指令太快了。

            我們應該在每顯示一個字母后,延時一段時間,讓人看清后,再顯示下一個字母。

            那么如何延時呢?我們讓CPU執行一段時間的空循環,因為現在的CPU的速度都非常快,所以循環的次數一定要大,我們用兩個16位寄存器來存放32位的循環次數。如下:

                   mov dx,10h

                   mov ax,0

             s: sub ax,1

                   sbb dx,0

                   cmp ax,0

                   jne s

                   cmp dx,0

                   jne s

             

            上面的程序,循環100000h次。我們可以將循環延時的程序段寫為一個子程序。

            assume cs:code

            stack segment

                   db 128 dup (0)

            stack ends

             

            code segment

             start:    mov ax,stack

                          mov ss,ax

                          mov sp,128

             

                          mov ax,0b800h

                          mov ex,ax

                          mov ah,’a’

                 s:   mov es:[160*12+40*2],ah

                          call delay

                          inc ah

                          cmp ah,’z’

                          jna s

             

                          mov ax,4c00h

                          int 21h

             

             delay:   push ax

                          push dx

                          mov dx,1000h        ;循環10000000次,讀者可以根據自己機器的速度調整循環次數

                          mov ax,0

                 s1: sub ax,1

                          sbb dx,0

                          jne sl

                          cmp dx,0

                          jne s1

                          pop dx

                          pop ax

                          ret

            code ends

            end start

             

            上面的程序,顯示“a~z”,并可以讓人看清,這個任務已經實現。

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

                   鍵盤輸入到達60h端口后,就會引發9號中斷,CPU則轉去執行int 9中斷例程。我們可以編寫int 9中斷例程,功能如下:

                   1)從60h端口讀出鍵盤的輸入;

                   2)調用BIOSint 9中斷全程,處理其他硬件細節;

                   3)判斷是否為Esc鍵的掃描碼,如果是,改變顯示的顏色后返回;如果不是則直接返回。

             

            分析:

            1、從端口60h讀出鍵盤的輸入

                   in al,60h

            2、調用BIOSint 9中斷例程

                   注意,我們寫的中斷處理程序要成為新的int 9中斷例程,主程序必須要將中斷向量表中的int 9中斷例程的入口地址改為我們寫的中斷處理程序的入口地址。則在新的中斷處理程序中調用原來的int 9中斷例程時,中斷向量表中的int 9中斷例程的入口地址卻不是原來的int 9中斷例程的地址,所以我們不能使用int 指令直接調用。

             

                   要能在我們寫的新的中斷例程中調用原來的中斷例程,就必須在將中斷向量表中的中斷例程的入口地址改為新地址之前,將原來的入口地址保存起來。這樣,在需要調用的時候我們才能找到原來的中斷例程的入口。

             

                   有了入口地址后,我們如何進行調用呢?

                   當然不能使用指令int 9來調用,我們可以用別的指令來對int 指令進行一些模擬,從而實現對中斷例程的調用。

             

                   int指令在執行的時候,CPU進行下面的工作:

                   1)取中斷類型碼n

                   2)標志寄存器入棧;

                   3IF=0TF=0

                   4CSIP入棧;

                   5(IP)=(n*4)(CS)=(n*4+2)

             

                   取中斷類型碼是為了定位中斷例程的入口地址,在我們的問題中,中斷例程的入口地址已經知道。所以,我們用別的指令模擬int指令時候,不需要做第(1)步。在假設要調用的中斷例程的入口地址在ds:0ds:2單元中的前提下,我們將int過程用下面幾步模擬:

                   1)標志寄存器入棧;

                   2IF=0TF=0

                   3CSIP入棧;

                   4(IP)=((ds)*16+0)(CS)=((ds)*16+2)

             

            所以int 過程的模擬過程變為:

                   1)標志寄存器入棧;

                   2IF=0TF=0

                   3call dword ptr ds:[0]

             

            對于(1),可用pushf實現。

            對于(2),可用下面的指令實現。

            pushf

            pop ax

            and ah,11111100b                 ;IFTF為標志寄存的第9位和第8

            push ax

            popf

             

            則,模擬int指令的調用功能,調用入口地址在ds:0ds:2中的中斷例程的程序為:

            pushf            ;標志寄存器入棧

             

            pushf

            pop ax

            and ah,11111100b

            push ax

            popf                             ;IF=0, TF=0

             

            call dword ptr ds:[0]      ;CSIP入棧;(IP)=((ds)*16+0), (CS)=((ds)*16+2)

             

            3、如果是Esc鍵掃描碼,改變顯示的顏色后返回

                   如果改變顯示的顏色?

                   顯示的位置是屏幕的中間,即第1240列,顯存中的偏移地址為:160*12+40*2。所以字符的ASCII碼要送入b800:160*12+40*2處。而b800:160*12+40*2+1處是字符的屬性,我們只要改變此處的數據就可以改變在b800:160*12+40*2處顯示的字符的顏色了。

             

            該程序的最后一個問題是,要在程序返回前,將中斷向量表中的int 9中斷例程的入口地址恢復為原來的地址。否則程序返回后,別的程序將無法使用鍵盤。

             

            完整的程序如下:

            assume cs:code

             

            stack segment

             db 128 dup (0)

            stack ends

             

            data segment

             dw 0,0

            data ends

             

            code segment

             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]

                    push es:[9*4+2]

                    pop ds:[2]      ;將原來的int 9中斷例程的入口地址保存在ds:0ds:2單元中

                   

                    mov word ptr es:[9*4],offset int9

                    mov es:[9*4+2],cs   ;在中斷向量表中設置新的int 9中斷例程的入口地址

                   

                    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 ax,0

                    mov es,ax

                   

                    push ds:[0]

                    pop es:[9*4]

                    push ds:[2]

                    pop es:[9*4+2]    ;將中斷向量表中int 9中斷例程的入口恢復為原來的地址

                   

                    mov ax,4c00h

                    int 21h

                   

             delay:push ax

                    push dx

                    mov dx,1000h

                    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

                   

                    ;-------以下為新的int 9中斷例程------------------

             int9: push ax

                    push bx

                    push es

                   

                    in al,60h

                   

                    pushf

                    pushf

                    pop bx

                    and bh,11111100b

                    push bx

                    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

                   

            code ends

            end start

             

             

            檢測點15.1

            1)模擬int指令調用原int9中斷例程的程序段是可以精簡的,因為在進入中斷例程后,IFTF都已經置0,沒有必要再進行設置了。

                   對于程序段:

                   pushf

                   pushf

                   pop ax

                   and ah,11111100b

                   push ax

                   popf

                   call dword ptr ds:[0]

            可以精簡為:

            pushf

            call dword ptr ds:[0]

            再條指令。

             

            2)仔細分析上面程序中的主程序,會發現一個潛在的問題?在主程序中,如果在執行設置int9中斷例程的段地址和偏移地址的指令之間發生了鍵盤中斷,則CPU將轉去一個錯誤的地址執行,將發生錯誤。

                   排除潛在問題方法:

                   pop ds:[2]指令后加入一條cli指令,并在mov es:[9*4+2],cs指令后加入一條sti指令即可。意思是在這段期間,讓IF=0,禁止或屏蔽外中斷處事程序的執行。

             

             

             

             

             

            安裝新的int9中斷處理例程

            安裝一個新的int 9中斷例程,使得原int 9中斷例程的功能得到擴展。

            任務:安裝一個新的int 9中斷例程,功能:在DOS下,按F1鍵后改變當前屏幕的顯示顏色,其他的鍵照常處理。

            分析:

            1)改變屏幕的顯示顏色

                   改變從B8000開始的4000個字節中的所有奇地址單元中的內容,當前屏幕的顯示顏色即發生改變。程序如下:

                   mov ax,0b800h

                   mov es,ax

                   mov bx,1

                   mov cx,2000

             s: nc byte ptr es:[bx]

                   add bx,2

                   loop s

             

            2)其他鍵照常處理

                   可以調用原int 9中斷處理程序,來處理其他的鍵盤輸入。

             

            3)原int 9中斷例程入口地址的保存

                   因為在編寫的新int 9中斷例程中要調用原int 9中斷例程,所以,要保存原int 9中斷例程的入口地址。保存在哪里?顯然不能保存在安裝程序中,因為安裝程序返回后地址將丟失。我們將地址保存在0:200單元處。

             

            4)新int 9中斷例程的安裝

                   我們可將新的int 9中斷例程安裝在0:204處。

             

            完整的程序如下:

            assume cs:code

             

            stack segment

             db 128 dup (0)

            stack ends

             

            code 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

                   

                    push es:[9*4]

                    pop es:[200h]

                    push es:[9*4+2]

                    pop es:[202h]     ;保存原有的int 9中斷例程入口地址

                   

                    cli               ;設置IF0,禁止CPU執行可屏蔽外中斷。

                    mov word ptr es:[9*4],204h

                    mov word ptr es:[9*4+2],0   ;設置int 9中斷向量,指向新的中斷例程入口地址

                    sti               ;恢復設置IF1

                   

                    mov ax,4c00h

                    int 21h

                   

               int9:push ax

                    push bx

                    push cx

                    push es

                   

                    in al,60h

                   

                    pushf

                    call dword ptr cs:[200h]    ;當此中斷例程執行時(CS)=0

                   

                    ;cmp al,1                  ;F1的掃描碼為3bh

                    ;jne int9ret

                   

                    mov ax,0b800h

                    mov es,ax

                    mov bx,1

                    mov cx,2000

                  s:mov byte ptr es:[bx],2

                    ;inc byte ptr es:[bx]

                    and bx,2

                    loop s

                   

            int9ret:pop es

                    pop cx

                    pop bx

                    pop ax

                    iret

                   

            int9end:nop

             

            code ends

             

            end start

             

             

            通過對鍵盤輸入的處理,了解了CPU對外設輸入的通常 通常方法,即:

            1)外設的輸入送入端口;

            2)向CPU發出外中斷(可屏蔽中斷)信息;

            3CPU檢測到可屏蔽中斷信息,如果IF=1CPU在執行完當前指令后響應中斷,執行相應的中斷例程;

            4)可在中斷例程中實現對外設輸入的處理。

             

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

             

             

             

            指令系統總結

            8086CPU提供以下幾大類指令:

            1、數據傳送指令

                   mov, push, pop, pushf, popf, xchg等。

                   實現寄存器和內存、寄存器和寄存器之間的單個數據傳送。

             

            2、自述運算指令

                   add, sub, adc, sbb, inc, dec, cmp, imul, idiv, aaa 等。

                   實現寄存器和內存中的數據的算術運算。它們的執行結果影響標志寄存器的:sf, zf, of, cf, pf, af位。

             

            3、邏輯指令

                   and, or, not, xor, test, shl, shr, sal, sar, rol, ror, rcl, rcr等。

                   除了not指令外,它們的執行結果都影響標志寄存器的相關標志位。

             

            4、轉移指令

                   可以修改IP,或同時修改CSIP的指令統稱為轉移指令。分為以下幾類:

                   1)無條件轉移指令,比如:jmp

                   2)條件轉移指令,比如:jcxz, je, jb, ja, jnb, jna等;

                   3)循環指令,比如:loop

                   4)過程,比如:call, ret, reft

                   5)中斷,比如:int, iret

             

            5、處理機控制指令

                   這些指令對標志寄存器或其他處理機狀態進行設置,比如:cld, std, cli, sti, nop, clc, cmc, stc, hlt, wait, csc, lock等都是處理機控制指令。

             

            6、串處理指令

                   這些指令對內存中的批量數據進行處理,比如:movsb, movsw, cmps, scas, lods, stos等。

                   基要使用這些指令方便地進行批量數據的處理,則需要和rep, repe, repne等前綴指令配合使用。

             

             

             

             

             

            posted on 2010-08-04 10:38 luqingfei 閱讀(1642) 評論(0)  編輯 收藏 引用 所屬分類: 匯編語言基礎學習

            導航

            <2025年6月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            統計

            留言簿(6)

            隨筆分類(109)

            隨筆檔案(105)

            Blogers

            Game

            Life

            NodeJs

            Python

            Useful Webs

            大牛

            搜索

            積分與排名

            最新評論

            閱讀排行榜

            評論排行榜

            色综合久久久久综合体桃花网| 久久AAAA片一区二区| 三级三级久久三级久久| 亚洲色欲久久久综合网| 国产午夜免费高清久久影院| 伊人色综合久久天天| 国产精品久久久香蕉| 久久91精品国产91久久户| 久久亚洲高清综合| 热re99久久6国产精品免费| 国产精品久久久天天影视香蕉| 老男人久久青草av高清| 亚洲成色999久久网站| 久久亚洲AV无码精品色午夜麻豆 | 久久99国内精品自在现线| 爱做久久久久久| 久久99精品久久久久久久不卡| 亚洲一区精品伊人久久伊人| 久久天天躁狠狠躁夜夜avapp| 国产精品日韩欧美久久综合| 色婷婷综合久久久久中文一区二区| 国产成人综合久久久久久| 97久久久久人妻精品专区| 久久精品国产乱子伦| 麻豆久久久9性大片| 欧美激情精品久久久久久| 久久免费小视频| 久久精品国产一区二区三区日韩| 久久久久免费看成人影片| 亚洲伊人久久大香线蕉综合图片| 亚洲国产婷婷香蕉久久久久久| 久久久久久亚洲精品不卡 | 亚洲欧洲久久久精品| 日韩一区二区三区视频久久| 久久av免费天堂小草播放| 精品久久久久中文字| 久久久久这里只有精品| 久久精品一区二区影院| 久久精品99无色码中文字幕| 欧美精品福利视频一区二区三区久久久精品| 久久久91精品国产一区二区三区 |