美文网首页我爱编程
[015][x86汇编语言]习题9-1:对8259芯片编程,屏蔽

[015][x86汇编语言]习题9-1:对8259芯片编程,屏蔽

作者: AkuRinbu | 来源:发表于2018-05-26 09:40 被阅读0次

    学习笔记

    《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

    相关文章

      网友评论

        本文标题:[015][x86汇编语言]习题9-1:对8259芯片编程,屏蔽

        本文链接:https://www.haomeiwen.com/subject/elfbjftx.html