[015][x86汇编语言]习题9-1:对8259芯片编程,屏蔽除RTC外的其他所有中断,观察字符“@”的变化速度,动态时钟

学习笔记

《x86汇编语言:从实模式到保护模式》
https://www.jianshu.com/p/d481cb547e9f

习题9-1:对8259芯片编程,屏蔽除RTC外的其他所有中断,观察字符“@”的变化速度

运行结果

  • 屏蔽完除了RTC以外的所有中断后,字符@的变化速度和秒的变化同步
    习题9-1:对8259芯片编程,屏蔽除RTC外的其他所有中断,观察字符“@”的变化速度

完整源码(根据配书代码 c09_1.asm 修改而来)

;======================================================================
;用户程序开始
;====================================================================== 
;代码清单9-1
;文件名:code_9-1.asm
;文件说明:用户程序
;代码功能:显示动态时钟
;创建日期:7:20 2018/5/27

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

    ;用户程序长度
    program_length  dd program_end              ;[0x00]
    
    ;用户程序入口地址
    code_entry      dw start                    ;[0x04]
                    dd section.code.start       ;[0x06]
    
    ;段重定位表项长度
    realloc_tbl_len dw (header_end - realloc_begin)/4 ;[0x0a]
    
    ;段重定位表项
    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号中断程序
;-------------------------------------------------------------------------------
new_int_0x70:           ;新的0x70中断
                        ;在屏幕上显示 时分秒
        push ax
        push bx
        push cx
        push dx
        push es
    
    ;读RTC寄存器A,根据UIP位的状态来决定是等待更新周期结束还是继续往下执行
    .w0:
        mov al,0x0a     ;阻断NMI RTC寄存器A 第7位UIP位 
        or al,0x80
        out 0x70,al
        in al,0x71          
        test al,0x80
        jnz .w0
        
    ;更新周期结束中断
        xor al,al           ;al = 0
        or al,0x80
        out 0x70,al
        in al,0x71          ;读RTC当前时间(秒)
        push ax
        
        mov al,2
        or al,0x80
        out 0x70,al
        in al,0x71          ;读RTC当前时间(分)
        push ax
        
        mov al,4
        or al,0x80
        out 0x70,al
        in al,0x71          ;读RTC当前时间(时)
        push ax

        
        mov al,0x0c         ;RTC寄存器C 开发NMI
        out 0x70,al
        in al,0x71          ;读一下RTC的寄存器C,否则只发生一次中断
        
    
        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        ;显示两位小时数字
        
        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        ;显示两位分钟数字
        
        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       ;显示两位秒钟数字
        
        
        mov al,0x20             ;中断结束命令EOI(End Of Interrupt)
        out 0xa0,al             ;向8259芯片从片(Slave)发送EOI
        out 0x20,al             ;向8259芯片主片(Master)发送EOI
        
        
        pop es
        pop dx
        pop cx
        pop bx
        pop ax
            
iret                    
;-------------------------------------------------------------------------------
;子程序:   bcd_to_ascii
;参数:        AL = BCD码
;返回:        AH 十位数的ASCII码 
;           AL 个位数的ASCII码
;-------------------------------------------------------------------------------
bcd_to_ascii:           ;新0x70中断中调用的子程序
                        ;将BCD码转换成ASCII
    mov ah,al
    and al,0x0f         
    add al,0x30         ;个位数的ASCII码
    
    shr ah,4
    and ah,0x0f
    add ah,0x30         ;十位数的ASCII码

ret

;-------------------------------------------------------------------------------
;用户程序入口
;-------------------------------------------------------------------------------
start:                  ;用户程序入口
    
    ;设置寄存器
    mov ax,[stack_segment]
    mov ss,ax
    mov sp,ss_pointer
    mov ax,[data_segment]
    mov ds,ax
    
    ;显示信息,调用子程序 put_string
    mov bx,init_msg     ;显示初始信息
    call put_string
    
    mov bx,inst_msg     ;显示安装信息
    call put_string
    
    ;计算0x70号中断在中断向量表(IVT)中的入口地址
    mov al,0x70
    mov bl,4
    mul bl
    mov bx,ax
    
    ;将0x70号中断的入口地址改写为 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内的单元
    ;0x71 [数据端口],用来读写CMOS RAM相应单元里的内容
    ;现在要访问的就是位于CMOS RAM中的RTC(REAL TIME CLOCK)
    mov al,0x0b         ;RTC寄存器B
    or al,0x80          ;端口0x70的最高位(bit 7)是控制NMI的开关,
    out 0x70,al         ;                         0表示允许NMI中断到达处理器、1表示阻断所有NMI信号
    
    mov al,0x12         ;设置“更新周期结束中断”
    out 0x71,al
    
    mov al,0x0c         ;RTC寄存器C
    out 0x70,al
    in al,0x71          ;读一下RTC寄存器C,使之可以产生新的中断信号
    
                        ;处理 从片slave
    mov al,0xfe         ;0xfe = 1111 1110B 清除第0位(此位通过从片引脚IRO连接着RTC)
    out 0xa1,al         ;回写寄存器
    
                        ;处理 主片master
    mov al,0xfb         ;只打开引脚IR2 使从片连接上主片
    out 0x21,al         ;回写 
    
    sti
    
    
    ;显示信息,调用子程序 put_string
    mov bx,done_msg
    call put_string
    
    mov bx,tips_msg
    call put_string
    
    ;显示标志  @ 符号
    mov cx,0xb800
    mov ds,cx
    mov byte [12*160+32*2],'@'
    
    ;创建循环 停机状态响应外部中断恢复执行
    .idle:
            hlt                         ;使CPU进入低功耗状态,直到用外部中断唤醒
            not byte [12*160+32*2+1]    ;反转显示属性
            jmp .idle
            
;-------------------------------------------------------------------------------
;子程序:   put_string
;功能:        显示字符串,字符串以0结尾
;-------------------------------------------------------------------------------
    
put_string:                              ;显示串(0结尾)。
                                         ;输入:DS:BX=串地址
         mov cl,[bx]
         or cl,cl                        ;cl=0 ?
         jz .exit                        ;是的,返回主程序 
         call put_char
         inc bx                          ;下一个字符 
         jmp put_string

   .exit:
         ret

;-------------------------------------------------------------------------------
    put_char:                                ;显示一个字符
                                             ;输入:cl=字符ascii
             push ax
             push bx
             push cx
             push dx
             push ds
             push es

             ;以下取当前光标位置
             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=代表光标位置的16位数

             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

             ;以下将光标位置推进一个字符
             shr bx,1
             add bx,1

     .roll_screen:
             cmp bx,2000                     ;光标超出屏幕?滚屏
             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
        
;======================================================================
;数据段
;====================================================================== 
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:

;======================================================================
;用户程序结束
;====================================================================== 

代码说明

  • 屏蔽完除了RTC中断外的全部中断
                    ;处理 从片slave
mov al,0xfe         ;0xfe = 1111 1110B 清除第0位(此位通过从片引脚IRO连接着RTC)
out 0xa1,al         ;回写寄存器
    
                    ;处理 主片master
mov al,0xfb         ;只打开引脚IR2 使从片连接上主片
out 0x21,al         ;回写 
  • 0xfe0xfb 是什么意思?
8259芯片主片以及从片各有一个IMR(中断屏蔽寄存器),
该寄存器是8位寄存器,寄存器的值与8个引脚一一对应(IR0~IR7),
从引脚而来的中断信号,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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。