第9章 中断和动态时钟显示
来源:互联网 发布:ubuntu 双系统 主分区 编辑:程序博客网 时间:2024/05/21 19:49
本章的第一个代码功能是在屏幕中间实时显示时间,其实现的思想是:cpu停机---》时间每秒更新一次,每一次更新都会引起0x70中断(0x70中断的内容已经被我们更改为显示当前时间)---》中断唤醒cpu开始执行我们的中断程序知道结束---》CPU停机等待中断---》唤醒CPU。。。
本程序的难点在于对8259芯片的理解和设置,这件事重要但不紧急,一时理解不通可以暂时跳过去。
;代码清单9-1 ;文件名:c09_1.asm ;文件说明:用户程序 ;创建日期:2011-4-16 22:03 ;===============================================================================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 ;定义代码段(16字节对齐) new_int_0x70: push ax push bx push cx push dx push es .w0: mov al,0x0a ;阻断NMI。当然,通常是不必要的 or al,0x80 out 0x70,al in al,0x71 ;读寄存器A test al,0x80 ;测试第7位UIP jnz .w0 ;以上代码对于更新周期结束中断来说 ;是不必要的 xor al,al 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 ;寄存器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 al,':' mov [es:bx+4],al ;显示分隔符':' not byte [es:bx+5] ;反转显示属性 pop ax call bcd_to_ascii mov [es:bx+6],ah mov [es:bx+8],al ;显示两位分钟数字 mov al,':' mov [es:bx+10],al ;显示分隔符':' 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 out 0xa0,al ;向从片发送 out 0x20,al ;向主片发送 pop es pop dx pop cx pop bx pop ax iret;-------------------------------------------------------------------------------bcd_to_ascii: ;BCD码转ASCII ;输入:AL=bcd码 ;输出:AX=ascii mov ah,al ;分拆成两个数字 and al,0x0f ;仅保留低4位 add al,0x30 ;转换成ASCII shr ah,4 ;逻辑右移4位 and ah,0x0f add ah,0x30 ret;-------------------------------------------------------------------------------start: mov ax,[stack_segment] mov ss,ax mov sp,ss_pointer mov ax,[data_segment] mov ds,ax mov bx,init_msg ;显示初始信息 call put_string mov bx,inst_msg ;显示安装信息 call put_string mov al,0x70 mov bl,4 mul bl ;计算0x70号中断在IVT中的偏移 mov bx,ax cli ;防止改动期间发生新的0x70号中断 push es mov ax,0x0000 mov es,ax mov word [es:bx],new_int_0x70 ;偏移地址。 mov word [es:bx+2],cs ;段地址 pop es mov al,0x0b ;RTC寄存器B or al,0x80 ;阻断NMI out 0x70,al mov al,0x12 ;设置寄存器B,禁止周期性中断,开放更 out 0x71,al ;新结束后中断,BCD码,24小时制 mov al,0x0c out 0x70,al in al,0x71 ;读RTC寄存器C,复位未决的中断状态 in al,0xa1 ;读8259从片的IMR寄存器 and al,0xfe ;清除bit 0(此位连接RTC) out 0xa1,al ;写回此寄存器 sti ;重新开放中断 mov bx,done_msg ;显示安装完成信息 call put_string mov bx,tips_msg ;显示提示信息 call put_string mov cx,0xb800 mov ds,cx mov byte [12*160 + 33*2],'@' ;屏幕第12行,35列 .idle: hlt ;使CPU进入低功耗状态,直到用中断唤醒 not byte [12*160 + 33*2+1] ;反转显示属性 jmp .idle;-------------------------------------------------------------------------------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 256ss_pointer: ;===============================================================================SECTION program_trailprogram_end:
实验现象:
体会:作为工程性的学科,学习底层的东西就是学习历史,中间包含的不只是科学原因,还有当时的历史原因,里面有很多现在看来怪异的现象。
实验二
代码45~46行,在这里,当寄存器 AH 的内容是 0x00 时,执行int 0x16 后,中断服务例程会监视键盘动作。当它返回时,会在寄存器AL 中存放按键的 ASCII 码。假如 键盘没有什么动作,则cs:ip会一直陷在int 0x16中断中,直到有动作。
;代码清单9-2 ;文件名:c09_2.asm ;文件说明:用于演示BIOS中断的用户程序 ;创建日期:2012-3-28 20:35 ;===============================================================================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 ;定义代码段(16字节对齐) start: mov ax,[stack_segment] mov ss,ax mov sp,ss_pointer mov ax,[data_segment] mov ds,ax mov cx,msg_end-message mov bx,message .putc:;该功能用于在屏幕上的光标位置处写一个字符,并推进光标位置 mov ah,0x0e mov al,[bx] int 0x10 inc bx loop .putc .reps: mov ah,0x00 int 0x16 mov ah,0x0e mov bl,0x07;bl前景色,但是设置了也没用???[yb] int 0x10 jmp .reps;===============================================================================SECTION data align=16 vstart=0 message db 'Hello, friend!',0x0d,0x0a db 'This simple procedure used to demonstrate ' db 'the BIOS interrupt.',0x0d,0x0a db 'Please press the keys on the keyboard ->' msg_end: ;===============================================================================SECTION stack align=16 vstart=0 resb 256ss_pointer: ;===============================================================================SECTION program_trailprogram_end:
实验现象:
实验体会:
计算机的学习类似于学习英语,在语言中学习西方的思想和文化,同样,在计算机程序语言中学习计算机的设计理念和概念,这就是《像计算机学家一样思考Python》一书所倡导的学习理念,在程序中去学习,可以是数学可以是操作系统可以是网络,一个一个的问题解决,最后什么看似深刻的原理都明白了;
通过学习汇编语言,明白了cpu是怎样工作的,明白了程序的底层,这就是通过语言学到的理念。
不难,多看,多思考,多总结。
阅读全文
0 0
- 第9章 中断和动态时钟显示
- 第10章 中断与时钟
- 第10章 时钟中断(PIT编程)
- NJUPT 微机 中断系统 日时钟中断之替换1CH实现字符串动态显示
- 第9章 中断系统和中断控制器8259A
- Js动态显示时钟
- ARM的中断和时钟中断
- ucosii的中断和时钟
- 第四章 μCOS-Ⅱ的中断和时钟
- 第三章uc/os-2的中断和时钟
- 手机数字时钟动态显示
- 硬中断 和软中断以及时钟中断
- 外部中断和数码管动态显示的应用
- 汇编基于PC机的8254日时钟中断的字符串动态显示——时:分:秒
- 第6章:中断和中断处理程序--学习笔记
- 第9章 中断
- 时钟中断
- lpc23xx时钟和外部中断学习
- [bzoj-4808]马 题解
- 遇到的保存网页的问题
- JZOJsenior1168.【NOIP动态规划专题】合唱队形
- bzoj2794 [Poi2012]Cloakroom ( 背包DP+离线 )
- luogu 1057 传球游戏
- 第9章 中断和动态时钟显示
- 例题6-3 矩阵链乘 UVA442
- Android ADB emulator-5554 unauthorized
- C#入门--多态(二)
- noip2006 day1 t1 能量项链
- 0【NOIP2013初赛】整除 1铺砖问题 2【NOIP2012初赛】新壳栈 3【NOIP2013初赛】青蛙
- DeepMind成立DMES新部门,旨在研究AI带来的社会伦理问题
- 在这场人工智能“战争”中,这些国家都在做些什么?
- 谷歌硬件战略缺陷:无法围绕谷歌助手打造硬件体系