[015][x86匯編語言]習(xí)題9-1:對(duì)8259芯片編程,屏蔽除RTC外的其他所有中斷,觀察字符“@”的變化速度,動(dòng)態(tài)時(shí)鐘

學(xué)習(xí)筆記

《x86匯編語言:從實(shí)模式到保護(hù)模式》
http://www.itdecent.cn/p/d481cb547e9f

習(xí)題9-1:對(duì)8259芯片編程,屏蔽除RTC外的其他所有中斷,觀察字符“@”的變化速度

運(yùn)行結(jié)果

  • 屏蔽完除了RTC以外的所有中斷后,字符@的變化速度和秒的變化同步
    習(xí)題9-1:對(duì)8259芯片編程,屏蔽除RTC外的其他所有中斷,觀察字符“@”的變化速度

完整源碼(根據(jù)配書代碼 c09_1.asm 修改而來)

;======================================================================
;用戶程序開始
;====================================================================== 
;代碼清單9-1
;文件名:code_9-1.asm
;文件說明:用戶程序
;代碼功能:顯示動(dòng)態(tài)時(shí)鐘
;創(chuàng)建日期:7:20 2018/5/27

;======================================================================
;頭部段
;======================================================================
SECTION header vstart=0 

    ;用戶程序長(zhǎng)度
    program_length  dd program_end              ;[0x00]
    
    ;用戶程序入口地址
    code_entry      dw start                    ;[0x04]
                    dd section.code.start       ;[0x06]
    
    ;段重定位表項(xiàng)長(zhǎng)度
    realloc_tbl_len dw (header_end - realloc_begin)/4 ;[0x0a]
    
    ;段重定位表項(xiàng)
    realloc_begin:
    code_segment    dd section.code.start       ;[0x0c]
    data_segment    dd section.data.start       ;[0x14]
    stack_segment   dd section.stack.start      ;[0x1c]
    
header_end:

;======================================================================
;代碼段
;======================================================================
SECTION code align=16 vstart=0
;-------------------------------------------------------------------------------
;0x70號(hào)中斷程序
;-------------------------------------------------------------------------------
new_int_0x70:           ;新的0x70中斷
                        ;在屏幕上顯示 時(shí)分秒
        push ax
        push bx
        push cx
        push dx
        push es
    
    ;讀RTC寄存器A,根據(jù)UIP位的狀態(tài)來決定是等待更新周期結(jié)束還是繼續(xù)往下執(zhí)行
    .w0:
        mov al,0x0a     ;阻斷NMI RTC寄存器A 第7位UIP位 
        or al,0x80
        out 0x70,al
        in al,0x71          
        test al,0x80
        jnz .w0
        
    ;更新周期結(jié)束中斷
        xor al,al           ;al = 0
        or al,0x80
        out 0x70,al
        in al,0x71          ;讀RTC當(dāng)前時(shí)間(秒)
        push ax
        
        mov al,2
        or al,0x80
        out 0x70,al
        in al,0x71          ;讀RTC當(dāng)前時(shí)間(分)
        push ax
        
        mov al,4
        or al,0x80
        out 0x70,al
        in al,0x71          ;讀RTC當(dāng)前時(shí)間(時(shí))
        push ax

        
        mov al,0x0c         ;RTC寄存器C 開發(fā)NMI
        out 0x70,al
        in al,0x71          ;讀一下RTC的寄存器C,否則只發(fā)生一次中斷
        
    
        mov ax,0xb800
        mov es,ax
        
        pop ax
        call bcd_to_ascii
        mov bx,12*160+36*2      ;從屏幕上的12行36列開始顯示
        
        mov [es:bx],ah
        mov [es:bx+2],al        ;顯示兩位小時(shí)數(shù)字
        
        mov byte [es:bx+4],':'      
        not byte [es:bx+5]
        
        pop ax
        call bcd_to_ascii
        mov [es:bx+6],ah
        mov [es:bx+8],al        ;顯示兩位分鐘數(shù)字
        
        mov byte [es:bx+10],':'     
        not byte [es:bx+11]
        
        pop ax
        call bcd_to_ascii
        mov [es:bx+12],ah
        mov [es:bx+14],al       ;顯示兩位秒鐘數(shù)字
        
        
        mov al,0x20             ;中斷結(jié)束命令EOI(End Of Interrupt)
        out 0xa0,al             ;向8259芯片從片(Slave)發(fā)送EOI
        out 0x20,al             ;向8259芯片主片(Master)發(fā)送EOI
        
        
        pop es
        pop dx
        pop cx
        pop bx
        pop ax
            
iret                    
;-------------------------------------------------------------------------------
;子程序:   bcd_to_ascii
;參數(shù):        AL = BCD碼
;返回:        AH 十位數(shù)的ASCII碼 
;           AL 個(gè)位數(shù)的ASCII碼
;-------------------------------------------------------------------------------
bcd_to_ascii:           ;新0x70中斷中調(diào)用的子程序
                        ;將BCD碼轉(zhuǎn)換成ASCII
    mov ah,al
    and al,0x0f         
    add al,0x30         ;個(gè)位數(shù)的ASCII碼
    
    shr ah,4
    and ah,0x0f
    add ah,0x30         ;十位數(shù)的ASCII碼

ret

;-------------------------------------------------------------------------------
;用戶程序入口
;-------------------------------------------------------------------------------
start:                  ;用戶程序入口
    
    ;設(shè)置寄存器
    mov ax,[stack_segment]
    mov ss,ax
    mov sp,ss_pointer
    mov ax,[data_segment]
    mov ds,ax
    
    ;顯示信息,調(diào)用子程序 put_string
    mov bx,init_msg     ;顯示初始信息
    call put_string
    
    mov bx,inst_msg     ;顯示安裝信息
    call put_string
    
    ;計(jì)算0x70號(hào)中斷在中斷向量表(IVT)中的入口地址
    mov al,0x70
    mov bl,4
    mul bl
    mov bx,ax
    
    ;將0x70號(hào)中斷的入口地址改寫為 cs:new_int_0x70
    cli
    
    push es
    mov ax,0x0000
    mov es,ax
    mov word [es:bx],new_int_0x70   ;偏移地址
    mov word [es:bx+2],cs           ;段地址
    pop es
    
    ;0x70 [索引端口],用來指定CMOS RAM內(nèi)的單元
    ;0x71 [數(shù)據(jù)端口],用來讀寫CMOS RAM相應(yīng)單元里的內(nèi)容
    ;現(xiàn)在要訪問的就是位于CMOS RAM中的RTC(REAL TIME CLOCK)
    mov al,0x0b         ;RTC寄存器B
    or al,0x80          ;端口0x70的最高位(bit 7)是控制NMI的開關(guān),
    out 0x70,al         ;                         0表示允許NMI中斷到達(dá)處理器、1表示阻斷所有NMI信號(hào)
    
    mov al,0x12         ;設(shè)置“更新周期結(jié)束中斷”
    out 0x71,al
    
    mov al,0x0c         ;RTC寄存器C
    out 0x70,al
    in al,0x71          ;讀一下RTC寄存器C,使之可以產(chǎn)生新的中斷信號(hào)
    
                        ;處理 從片slave
    mov al,0xfe         ;0xfe = 1111 1110B 清除第0位(此位通過從片引腳IRO連接著RTC)
    out 0xa1,al         ;回寫寄存器
    
                        ;處理 主片master
    mov al,0xfb         ;只打開引腳IR2 使從片連接上主片
    out 0x21,al         ;回寫 
    
    sti
    
    
    ;顯示信息,調(diào)用子程序 put_string
    mov bx,done_msg
    call put_string
    
    mov bx,tips_msg
    call put_string
    
    ;顯示標(biāo)志  @ 符號(hào)
    mov cx,0xb800
    mov ds,cx
    mov byte [12*160+32*2],'@'
    
    ;創(chuàng)建循環(huán) 停機(jī)狀態(tài)響應(yīng)外部中斷恢復(fù)執(zhí)行
    .idle:
            hlt                         ;使CPU進(jìn)入低功耗狀態(tài),直到用外部中斷喚醒
            not byte [12*160+32*2+1]    ;反轉(zhuǎn)顯示屬性
            jmp .idle
            
;-------------------------------------------------------------------------------
;子程序:   put_string
;功能:        顯示字符串,字符串以0結(jié)尾
;-------------------------------------------------------------------------------
    
put_string:                              ;顯示串(0結(jié)尾)。
                                         ;輸入:DS:BX=串地址
         mov cl,[bx]
         or cl,cl                        ;cl=0 ?
         jz .exit                        ;是的,返回主程序 
         call put_char
         inc bx                          ;下一個(gè)字符 
         jmp put_string

   .exit:
         ret

;-------------------------------------------------------------------------------
    put_char:                                ;顯示一個(gè)字符
                                             ;輸入:cl=字符ascii
             push ax
             push bx
             push cx
             push dx
             push ds
             push es

             ;以下取當(dāng)前光標(biāo)位置
             mov dx,0x3d4
             mov al,0x0e
             out dx,al
             mov dx,0x3d5
             in al,dx                        ;高8位 
             mov ah,al

             mov dx,0x3d4
             mov al,0x0f
             out dx,al
             mov dx,0x3d5
             in al,dx                        ;低8位 
             mov bx,ax                       ;BX=代表光標(biāo)位置的16位數(shù)

             cmp cl,0x0d                     ;回車符?
             jnz .put_0a                     ;不是。看看是不是換行等字符 
             mov ax,bx                       ;此句略顯多余,但去掉后還得改書,麻煩 
             mov bl,80                       
             div bl
             mul bl
             mov bx,ax
             jmp .set_cursor

     .put_0a:
             cmp cl,0x0a                     ;換行符?
             jnz .put_other                  ;不是,那就正常顯示字符 
             add bx,80
             jmp .roll_screen

     .put_other:                             ;正常顯示字符
             mov ax,0xb800
             mov es,ax
             shl bx,1
             mov [es:bx],cl

             ;以下將光標(biāo)位置推進(jìn)一個(gè)字符
             shr bx,1
             add bx,1

     .roll_screen:
             cmp bx,2000                     ;光標(biāo)超出屏幕?滾屏
             jl .set_cursor

             mov ax,0xb800
             mov ds,ax
             mov es,ax
             cld
             mov si,0xa0
             mov di,0x00
             mov cx,1920
             rep movsw
             mov bx,3840                     ;清除屏幕最底一行
             mov cx,80
     .cls:
             mov word[es:bx],0x0720
             add bx,2
             loop .cls

             mov bx,1920

     .set_cursor:
             mov dx,0x3d4
             mov al,0x0e
             out dx,al
             mov dx,0x3d5
             mov al,bh
             out dx,al
             mov dx,0x3d4
             mov al,0x0f
             out dx,al
             mov dx,0x3d5
             mov al,bl
             out dx,al

             pop es
             pop ds
             pop dx
             pop cx
             pop bx
             pop ax

             ret
        
;======================================================================
;數(shù)據(jù)段
;====================================================================== 
SECTION data align=16 vstart=0

    init_msg db 'Starting...',0x0d,0x0a,0
    
    inst_msg db 'Installing a new interrupt 70H...',0
    
    done_msg db 'Done.',0x0d,0x0a,0
    
    tips_msg db 'Clock is now working.',0
    
;======================================================================
;棧段
;====================================================================== 
SECTION stack align=16 vstart=0

        resb 256
        
ss_pointer:

;======================================================================
;尾部段
;====================================================================== 
SECTION program_trail

program_end:

;======================================================================
;用戶程序結(jié)束
;====================================================================== 

代碼說明

  • 屏蔽完除了RTC中斷外的全部中斷
                    ;處理 從片slave
mov al,0xfe         ;0xfe = 1111 1110B 清除第0位(此位通過從片引腳IRO連接著RTC)
out 0xa1,al         ;回寫寄存器
    
                    ;處理 主片master
mov al,0xfb         ;只打開引腳IR2 使從片連接上主片
out 0x21,al         ;回寫 
  • 0xfe0xfb 是什么意思?
8259芯片主片以及從片各有一個(gè)IMR(中斷屏蔽寄存器),
該寄存器是8位寄存器,寄存器的值與8個(gè)引腳一一對(duì)應(yīng)(IR0~IR7),
從引腳而來的中斷信號(hào),0表示允許中斷,1表示阻斷中斷;

0xfe = 1111 1110B ,就是打開從片上的引腳IR0
使得 RTC 與從片相連,這樣RTC的中斷就可以傳到從片,并且從片上其余引腳全部阻斷;

0xfb = 1111 1011B,就是打開主片上的引腳IR2
使得 從片與主片相連,并且主片上其余引腳全部阻斷;

RTC-從片-主片-處理器 
就連好了,并且除了RTC以外的中斷全部被屏蔽。
RTC-IR0-8259從片-IR2-8259主片.png

解題參考

http://www.cnblogs.com/Philip-Tell-Truth/p/5317983.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容