zoukankan      html  css  js  c++  java
  • 外中断02 零基础入门学习汇编语言70

    第十五章:外中断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]
  • 相关阅读:
    pycharm安装破解
    flask动态生成csv
    使用django开发restful接口
    python matplotlib显示中文和负数符号
    locust性能测试02—检查点
    locust性能测试01—初体验
    Mac中配置jmeter+grafana监控
    CF731E Funny Game
    CF197A Plate Game
    luoguP1823 [COI2007] Patrik 音乐会的等待
  • 原文地址:https://www.cnblogs.com/LoveFishC/p/3846090.html
Copyright © 2011-2022 走看看