在屏幕中间显示,按ESC键后改变字符的颜色

程序功能:编写程序在屏幕中间显示“a”~“z”,并可以让人看清,这个任务比较好实现。
(1)在b800:[ 160*12+40*2]处存入a的ASCII码、(2)在循环中使用一个100000000000H次的循环空转达到延迟效果、(3)按键盘引发int9中断改变颜色
那么如何实现,按下Esc 键后,改变显示的颜色呢?
键盘输入到达60h 端口后,就会引发9号中断,CPU 则转去执行int 9中断例程。
我们可以编写int 9中断例程,功能如下:
?(1)从60h 端口读出键盘的输入;
?(2)调用BIOS 的int 9 中断例程,处理其他硬件细节;
?(3)判断是否为Esc的扫描码,如果是,改变显示的颜色后返回;如果不是则直接返回。
我们对这些功能的实现一一进行分析
1、从端口60h读出键盘的输入使用:in al,60h
2、调用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),可用and和popf实现,如下面的指令实现。
实现IF=0,TF=0步骤:
pushf
pop ax
and ah,11111100b ;IF和OF为标志寄存器的第9位和第8位
push ax
popf
这样,模拟int指令的调用功能,调用入口地址在ds:0、ds:2中的中断例程的程序如下
pushf ;标志寄存器入栈
pushf;实现IF=0,TF=0的功能
pop ax
and ah,11111100b ;IF和OF为标志寄存器的第9位和第8位
push ax
popf ;IF=0、TF=0
call dword ptr ds:[0];call功能: ①CS、IP入栈,②;(IP)=((ds)*16+0),③;(CS)=((ds)*16+2)
3、如果是Esc键的扫描码,改变显示的颜色后返回,如何改变显示的颜色?
显示的位置是屏幕的中问,即第12行40列,显存中的偏移地址为:160*12+40* 2。所以字符的ASCII码要送入b800:160*12+40*2处。而b800:160*12+40*2+1处是字符的属性,我们只要改变此处的数据就可以改变在b800:160*12+40*2处显示的字符的颜色了。
该程序的最后一个问题是,要在程序返回前,将中断向量表中的ini 9中断例程的入口地址恢复为原来的地址。否则程序返回后,别的程序将无法使用键盘。
注意,本章中所有关于键盘的程序,因要直接访问真实的硬件,则必须在DOS实模式下运行。在Windows 2000 的DOS 方式下运行,会出现一些和硬件工作原理不符合的现象。
开发int9中断例程架构:
?①在主程序中把原来的int9的原始程序入口保存到data段中,并把自己写的int9中断例程入口地址替换到中断向量表的9号中断地址,对应的是IP是0: [9*4]和CS是0[9*4+2]
?②等待外部中断自动调用int9
?③程序运行完后还原int9原来的中断例程入口
在int9中断例程内部结构
1.保存用到的通用寄存器
2.接收60h端口的数据
3.修改IF和TF的值为0
4.处理数据
5.使用call模拟调用int9的系统中断例程
6.还原通用寄存器
说明:由于中断例程使用的是iret返回,而iret的过程是①从栈中还原IP和CS,②从栈中还原寄存器状态;这里使用了call的远跳转(地址在data段中),而用call过程是先把CS和IP保存进栈,跳转到指定地址执行完再通过retf返回,调用完成后再从栈中还原IP和CS;而这里我们调用的是中断例程,是用iret返回的,retf和iret返回的IP和CS顺序相同,而iret比retf多一步还原寄存器状态,所以我们要构造供iret的返回的栈数据:就是在call前先保存寄存器状态,然后就可以使用iret的形式还原程序的IP,CS,标志寄存器。我们只要在自己编写的中断例程中处理完自己的数据后再调用BIOS 的int 9中断例程就可以了。

;程序功能:在屏幕中间同一点显示a-z的所有字符
;        1.使用cpu循环空运行实现延迟
;        2.按ESC键改变正在循环显示的字符的颜色
;        3.程序完成时,再次还原int9中断向量表
assume cs:code
data segment
db 100 dup(0)

data ends

code segment
start:
    ;init ds,es
    mov ax,data
    mov ds,ax
    mov ax,0
    mov es,ax

    ; save int9 IP and CS
    mov ax,es:[9*4]
    mov ds:[0],ax
    mov ax,es:[9*4+2]
    mov ds:[2],ax
    mov es:[9*4],offset int9
    mov es:[9*4+2],cs

    ;循环显示a-z的所有字符
    mov ax,0b800h
    mov es,ax
    mov ah,‘a‘
    show: mov es:[160*12+40*2],ah
    call delay    ;调用延迟
    inc ah
    cmp ah,‘z‘
    jna show

    ;还原int9中断向量表
    mov ax,0
    mov es,ax
    push ds:[0]
    pop es:[9*4]
    push ds:[2]
    pop es:[9*4+2]

    mov ax,4c00h
    int 21h

;使用cup循环空运行,实现延迟时间的作用
;使用32位的借位减法实现 1000 0000 0000h 次数的循环
delay:
    push ax
    push dx
    mov dx,1000h
    mov ax,0
    s: sub ax,1
    sbb dx,0
    cmp ax,0
    jne s
    cmp dx,0
    jne s
    pop dx
    pop ax
    ret

;实现int9中断例程
;pushf是16位,pop是16位
int9:

    push ax    ;保存临时变量
    in al,60h

    pushf    ;用于call模拟int9后的popf操作
    pushf    ;用于修改IF=0、TF=0 操作
    pop bx
    and bh,11111100b
    push bx
    popf
    call dword ptr ds:[0]
    ;调用完这个模拟的int9后,会执行iret操作
    ;会先popf出第一次pushf的值

    cmp al,1
    jne int9ret
    add byte ptr es:[160*12+40*2+1],11h
    int9ret:
    pop ax
    iret

code ends
end start

程序简化:

1)在键盘按键的时候触发int9中断例程,这时候IF和TF都已经设置成0了,使用我们就没必要设置了

2)原始的int9可以保存到0:200中,在程序中使用中断调用

存在的问题:

在上面的程序,如果设置中断向量表的时候没有全部完成,就是重定位中断向量表地址的时候出现了键盘的按键中断,在CUP会跳到一个错误的地址执行,如何解决呢?                            提示:使用sti和cli命令

时间: 2024-12-26 15:34:28

在屏幕中间显示,按ESC键后改变字符的颜色的相关文章

汇编题目:在DOS下,按F1键后改变当前屏幕的显示颜色

我们都知道int9中断是键盘的按键中断程序,按下键盘触发int9中断,不懂int9中断的请自己去百度查查说明和用法 利用中断任务安装一个新的int 9中断例程,功能:在DOS下,按F1键后改变当前屏幕的显示颜色,其他的键照常处理. ;任务:安装一个新的int 9中断例程, ;功能:在DOS下,按F1键后改变当前屏幕的显示颜色,其他的键照常处理. assume cs:code stack segment db 30h dup(0) stack ends data segment db 20h du

Qt窗口屏幕居中显示(有专门的QDesktopWidget,先计算后显示)

窗口的屏幕居中显示问题,在各开发工具中原理相同,首先使用特定的方法得到显示屏幕的宽度和高度,再根据窗口本身的宽度和高度计算出窗口的左上角坐标位置. Qt中可以采用两种方法达到窗口的屏幕居中显示: 方法一: 显示前先计算出窗口显示位子,并移到对应位子后再显示窗口 int main(int argc, char *argv[]){ QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030")); QApplication a(a

惠普笔记本按开机键后电源灯亮的,但是屏幕一直是黑的,只有大写锁定键闪烁,闪3次一个循环,听得到风扇

现象: 惠普笔记本按开机键后电源灯亮的,但是屏幕一直是黑的,只有大写锁定键闪烁,闪3次一个循环,听得到风扇转动的声音,热风,cpu应该也在工作,请问是什么问题. 解决(我按照红色的作了,就可以了,真是奇怪...): 您好,感谢您选择惠普产品. 1.您的笔记本开机黑屏,请您回忆一下最近是否进行过什么方面特殊操作,比如最近是否进行过硬件改动(例如添加过新内存)或者连接了外接设备,如果是,建议您恢复之前硬件配置及断开所有外接设备看是否可以正常开机. 2.如果您没有进行过特殊操作,使用电池或电源适配器供

thinkpad 睡眠唤醒后热键功能正常,但屏幕无法显示状态/进度条/图标

由于博主比较习惯笔记本开盖即用,合盖即走,不大习惯开机关机(毕竟SSD速度杠杠滴^_^).可是发现笔记本长时间睡眠乃至休眠唤醒后,使用thinkpad热键,虽然可以调节,但屏幕不显示调节状态了.解决步骤如下: 1. 在桌面鼠标右键,选择[屏幕分辨率],如果无此选项,打开控制面板,“排列方式”选择“小图标”,选择“显示”选项,找到[屏幕分辨率设置]. 2. 在弹出窗口中,选择[高级设置] 3. 在弹出窗口中,切换到[屏幕显示]选项卡,确保[启用屏幕显示]为勾选状态,先将[数字锁定和大小写锁定的指示

iphone按home键后,正在运行的程序是否退出了呢?

是否一直有个疑问,当iphone手机正在运行一个APP,如果按Home键后,那么原来正在运行的程序还在运行吗?如果开发过ios程序,可能不是问题,如果没有开发过的,可能会疑惑了,我就简单的说一下.以几个问题的形式来说明,以正在运行QQ为例. 1.为什么按home键后,长时间不操作,再启动qq的话,会重新运行qq(没有回到原来的状态)? 答:iphone实际上是伪后台,按home键后,程序就退出了.所以我们iphone中使用的程序一般都没有退出键. 试想一下,如果程序有退出键的话,那么当程序无响应

按下enter键后表单自动提交问题

在HTML的form表单里,按下enter键之后,默认情况下表单会自动提交. 在公司一个项目里,按下enter键自动提交表单的查询结果与按下搜索框的搜索结果页面显示不一样,按下搜索按钮之后是通过Ajax请求返回结果:而按下enter键是直接post请求然后跳转返回一个页面,失去了页面样式及导航等. 一开以为是写了js代码导致按下enter键之后会触发表单提交,后来把js代码全部移除也是一样地按下enter键会触发表单提交.到网上搜索发现是因为默认情况下在form表单内按下enter键会触发表单自

[email protected]:在PC屏幕上显示Android手机屏幕

这里介绍一款工具——[email protected],用来获取手机屏幕,显示在PC屏幕上.它集截图.录像等多种功能于一体. 安装 1.    下载地址:http://droid-at-screen.org/download.html,下载后是一个jar包,放到某个目录就可以. 2.    安装JDK6或以上版本 3.    安装Android SDK(从Android官方下载一个完整包解压即可) 4.    设置ANDROID_HOME环境变量指向AndroidSDK主目录(这步如果不做,则需

JavaScript基础 window.open(url,name,options) 弹出一个 新窗口 屏幕居中显示 获取屏幕的有效宽度

镇场诗: 清心感悟智慧语,不着世间名与利.学水处下纳百川,舍尽贡高我慢意. 学有小成返哺根,愿铸一良心博客.诚心于此写经验,愿见文者得启发.------------------------------------------ code: 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=ut

按Enter键后Form表单自动提交的问题

怪事年年有,今年特别多. 话说,最近项目中遇到一件怪事,当我鼠标focus在文本框中,轻轻敲了下回车键,尼玛页面突然刷新了,当时把宝宝给吓得. 接下来就是一番苦逼的烧脑和蛋疼~ 一.被表象所迷惑 突然出现这种情况,脑海中第一反应是,keydown事件是不是出问题了,然后找啊找啊找啊,然后没有然后. 在把input元素上的所有事件移除掉后,我自信的按了一下enter键.艾玛,又刷新了.心里那个苦哎. 二.列出所有可能 一阵捣鼓之后,脑海中列出了所有按下enter键后的改变,url改变,多了一个问号