外中断02 - 零基础入门学习汇编语言70
2011-05-27 23:36
621 查看
第十五章:外中断02
让编程改变世界Change the world by program
小甲鱼和大家谈谈心
一个帖子引发小甲鱼的反省!猫姐曾经说过,步子别迈太大,容易扯着蛋!
结果还真蛋疼了……
因此,小甲鱼要学会淡定面对,不能忘记当初的宗旨!做视频也好、做网站也好,对得住大家才对得住自己的良心!
最后:希望大家继续支持鱼C、支持小甲鱼,看到大家都能坦诚相待,很开心,很幸福!
编写int 9 中断例程
复习一下前边的内容中,我们可以总结出键盘输入的处理过程:
(1)键盘产生扫描码;(2)扫描码送入60h 端口;
(3)一旦侦测到60h端口有动静,引发9 号中断;
(4)CPU执行int 9 中断例程处理键盘输入。
以上的过程,前三步都由硬件系统自动完成。我们能够改变的只有第四步,修改int 9 终端程序。
但是,在这门课程中,我们不准备完整地编写一个键盘中断的处理程序,因为要涉及到一些硬件细节,而这些内容脱离了我们的内容主线。
插入语:如果有兴趣想更为深入的学习汇编语言,探究汇编语言的奥妙,可以关注小甲鱼今后推出的《The Art of Assembly Language》。
但是,我们却还要编写新的键盘中断处理程序,来进行一些特殊的工作,那么这些硬件细节如何处理呢?
如果单纯要完成这点还是相对比较简单的,因为BIOS 提供的int 9中断例程已经对这些硬件细节进行了处理。我们只要在自己编写的中断例程中调用BIOS 的int 9中断例程就可以了。
任务演示:在屏幕中间依次显示 “a”~“z” ,并可以让人看清。在显示的过程中,按下Esc键后,改变显示的颜色。
我们先来看一下如何依次显示“a”~“z”:
[codesyntax lang="asm"]assume cs:code code segment start: mov ax,0b800h mov es,ax mov ah,'a' s: mov es:[160*12+40*2],ah inc ah cmp ah,'z' jna s mov ax,4c00h int 21h code ends end start
[/codesyntax]
我们发觉,因为一个字母刚显示到屏幕上,CPU执行几条指令后,就又变成了另一个字母,字母之间切换得太快,因此我们无法看清。
理想状况是:我们应该在每显示一个字母后,延时一段时间,让人看清后,再显示下一个字母。
那么如何延时呢?
不如……我们让CPU 执行一段时间的空循环。有时候让它做点无用功哈~请看源代码并试图分析作者的做法:相关代码下载
现在显示“a”~“z”的任务我们基本完成了,并做到可以让人看清,虽然做法有些无耻……
那么接下来将进一步来实现:按下 Esc 键后,改变显示的颜色!怎么办呢?
键盘输入到达60h 端口后,就会引发 9号中断,CPU 则转去执行int 9中断例程。
我们可以编写int 9中断例程,功能如下:
(1)从60h端口读出键盘的输入;
(2)调用BIOS 的int 9 中断例程,处理其他硬件细节;
(3)判断是否为Esc的扫描码,如果是,改 变显示的颜色后返回;如果不是则直接返回。
接下来,我们对这些功能的实现一一进行分析!
第一步:从端口60h读出键盘的输入
in al,60h第二步:调用BIOS的int 9中断例程
注:有一点要注意的是,我们写的中断处理程序要成为新的int 9中断例程,主程序必须要将中断向量表中的int 9中断例程的入口地址改为我们写的中断处理程序的入口地址。那么在新的中断处理程序中调用原来的int 9中断例程时,中断向量表中的int 9中断例程的入口地址却不是原来的int 9 中断例程的地址。所以我们不能使用int 指令直接调用。
这里有必要解释一下:。。。。。。
对于我们现在的问题,假设我们将原来int 9中断例程的偏移地址和段地址保存在ds:[0]和ds:[2]单元中。
那么我们在需要调用原来的int 9中断例程时候,就可以在 ds:[0]、ds:[2] 单元中找到它的入口地址。
那么,有了入口地址后,我们如何进行调用呢?
当然不能使用指令int 9来调用。我们可以用别的指令来对int指令进行一些模拟,从而实现对中断例程的调用。我们来看,int 指令在执行的时候,CPU 进行下面的工作:
(1)取中断类型码n;
(2)标志寄存器入栈;
(3) IF=0,TF=0;
(4) CS 、IP 入栈;
(5)(IP) = (n*4),(CS) = (n*4+2)。
取中断类型码是为了定位中断例程的入口地址,在我们的问题中,中断例程的入口地址已经知道。
所以,我们用别的指令模拟int 指令时候,不需要做第(1)步。
在假设要调用的中断例程的入口地址在ds:0和ds:2单元中的前提下,我们将int 过程用下面几步模拟:
(1)标志寄存器入栈;
(2)IF=0,TF=0;
(3)CS、IP入栈;
(4)(IP)=((ds)*16+0),(CS)=((ds)*16+2)。
可以注意到第(3)、(4)步和call dword ptr ds:[0]的功能一样。
call dword ptr ds:[0] 的功能也是:
(1)CS 、IP 入栈;
(2)(IP)=((ds)*16+0),(CS)=((ds)*16+2)。
如果这点上有疑问的童鞋,不妨可以复习下10.6节的内容。
所以经过我们总结后,int 过程的模拟最终变为:
(1)标志寄存器入栈;(2)IF=0,TF=0;
(3)call dword ptr ds:[0]
对于(1),可用pushf实现。
对于(2),我们又得动点歪脑筋,没办法,资源条件极其卑劣的8086 要么使人放弃,要么逼出天才!我们可用以下程序间接实现:
实现IF=0,TF=0步骤:
pushf
pop ax
and ah,11111100b ; IF和OF为标志寄存器的
; 第9位和第8位
push ax
popf
这样,模拟int指令的调用功能,调用入口地址在ds:0、ds:2中的中断例程的程序如下:
pushf ;标志寄存器入栈
pushf
pop ax
and ah,11111100b ; IF和OF为标志寄存器的第9
; 位和第8位
push ax
popf ;IF=0、TF=0
call dword ptr ds:[0]
第三步:如果是Esc键的扫描码,改变显示的颜色后返回……
那么,下一个问题:如何改变显示的颜色?[buy] 获得所有教学视频、课件、源代码等资源打包 [/buy]
[Downlink href='http://kuai.xunlei.com/d/LWPDSCJPSSUD']视频下载[/Downlink]
相关文章推荐
- 外中断02 - 零基础入门学习汇编语言70
- 内中断02 - 零基础入门学习汇编语言61
- 内中断02 - 零基础入门学习汇编语言61
- 数据处理的两个基本问题02 - 零基础入门学习汇编语言39
- 第一个程序02 - 零基础入门学习汇编语言21
- 转移指令的原理02 - 零基础入门学习汇编语言44
- 外中断03 - 零基础入门学习汇编语言71
- 转移指令的原理02 - 零基础入门学习汇编语言44
- 直接定址表02 - 零基础入门学习汇编语言73
- 内中断04 - 零基础入门学习汇编语言63
- 直接定址表02 - 零基础入门学习汇编语言73
- 内中断04 - 零基础入门学习汇编语言63
- 外中断01 - 零基础入门学习汇编语言69
- 外中断01 - 零基础入门学习汇编语言69
- Call指令和Ret指令讲解02 - 零基础入门学习汇编语言49
- Call指令和Ret指令讲解02 - 零基础入门学习汇编语言49
- 包含多个段的程序02 - 零基础入门学习汇编语言30
- 包含多个段的程序02 - 零基础入门学习汇编语言30
- 内中断01 - 零基础入门学习汇编语言60
- [BX]和loop指令02 - 零基础入门学习汇编语言24