[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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350