您的位置:首页 > 其它

外中断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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: