【新书推荐】16.4 软中断处理程序举例

本节内容:打印I/O源程序和时钟显示程序。

         ■打印I/O源程序:t16-6.asm。

         ■时钟显示程序:t16-7.asm。

16.4.1 打印I/O源程序

我们以打印I/O程序的源程序,作为BIOS中断处理程序设计的例子。每个打印机有三个寄存器:数据寄存器、状态寄存器和控制寄存器。三个寄存器的端口地址都是连续的,系统初始化期间,数据寄存器端口地址被依次保存到BIOS数据区,从40H段的偏移8H处开始。

尽管通过中断控制器8259A可实现中断方式打印输出,但BIOS提供的打印I/O程序却采用查询方式实现打印输出。查询时使用的超时参数在BIOS数据区中,从40H段的偏移78H开始。

BIOS提供的打印I/O程序作为17H中断处理程序,实现流程图16-8所示。

图16-8 打印I/O程序的流程

作为BIOS软中断处理程序,没有自己的堆栈,而是使用主程序的堆栈。

示例代码77

;BIOS打印I/O程序的源程序

;程序名:biosio.asm

;---------------------------

assume cs:code

;常量说明

print_tim_out=78h           ;超时参数存放单元开始偏移

printer_base=8                  ;端口地址存放单元开始地址偏移

bios_data_seg=40h          ;BIOS数据段的段值

;代码部分

code segment

print_io proc far

         sti                                 ;开中断

         push ds

         push dx

         push si

         push cx

         push bx

         mov bx,bios_data_seg

         mov ds,bx                   ;置BIOS数据段段值

         mov si,dx                    ;DX=0,0号打印机

         mov bl,print_tim_out[si] ;取超时测试基本单位数

         shl si,1

         mov dx,printer_base[si]   ;取数据寄存器端口地址

         or dx,dx             ;判断系统是否有对应接口

         jz b1                   ;无,转结束

         or ah,ah             ;0号功能?

         jz b2

         dec ah                ;1号功能?

         jz b8                   ;是,转

         dec ah                ;2号功能?

         jz b5

b1:   pop bx

         pop cx                                           

         pop si

         pop dx

         pop ds

         iret

         ;0号处理功能

b2:   push ax

         out dx,al           ;输出打印机数据

         inc dx                 ;DX=状态寄存器端口地址

         push bx

         sub bh,bh

         rcl bx,1              ;确定超时参数单位数

         rcl bx,1

b3:   sub cx,cx           ;每一单位测试65536次                          

b3_1:        in al,dx     ;读状态寄存器

         mov ah,al

         test al,80h       ;是否忙碌?            

         jnz b4                 ;否转

         loop b3_1         ;是,继续测

         dec bx                ;单位数完?

         jnz b3                 ;否,转

         pop bx               ;是

         or ah,1               ;置超时标志位

         and ah,0f9h      ;去掉无定义位

         jmp short b7    ;转,中断返回       

b4:   pop bx

         mov al,0dh       ;选通,即真正输出到打印机

         inc dx

out dx,al

         mov al,0ch

         jmp $+2

         out dx,al

         pop ax

         ;2号功能处理

b5:   push ax

b6:   mov dx,printer_base[si]

         inc dx                 ;DX=状态寄存器端口地址

         mov ah,al

         and ah,0f8h      ;去掉无定义位和清超时标志位

b7:   pop dx

         mov al,dl

         xor ah,48h        ;第6位和第3位取反(符合出口约定)

         jmp b1               ;转,中断返回

         ;1号功能处理

b8:   push ax

         inc dx

         inc dx                 ;DX=控制寄存器端口地址

         mov al,8

         out dx,al            ;输出初始化命令

         mov ax,10000

b9:   dec ax                ;等待一段时间

         jnz b9

         mov al,0ch        ;输出正常控制命令

         out dx,al

         jmp b6            ;转取状态字节和中断返回

print_io endp

code ends

         end

上述17H中断处理程序直接操纵控制打印接口,没有再调用其他程序。

16.4.2 时钟显示程序

在系统加电初始化期间,把系统定时器初始化为每隔55毫秒发出一次中断请求。

CPU在响应中断请求后转入8H中断处理程序。BIOS提供的8H号中断处理程序中有一条中断指令“INT 1CH”,所以每秒调用约18.2次1CH号中断处理程序。实际上1CH中断没有做任何工作,只有一条返回指令。目的是为了给应用程序留下一个软接口,应用程序只要提供新的1CH号中断处理程序,就可以实现某些周期性的工作。

下面介绍的时钟显示程序就是利用这个软接口,实现时钟显示。

新的1CH号中断处理程序中安排一个计数器,记录调用它的次数,当计数器满18次后,就在屏幕的右上角显示当前的时间(时,分,秒),清计数器。约每秒显示一次当前时间。

当前时间的获取是调用1AH号中断处理程序的2号功能完成的,该功能在CH,CL和DH寄存器返回时,分,秒的BCD码。转换为对应的十进制数ASCII码后,调用显示I/O程序完成显示。

动手实验102写一个利用1CH号中断软接口实现时钟显示的程序。

在理解下面示例程序的基础上,自己独立编写源程序。编译完成后,在debug调试器中单步跟踪调试,以验证程序的正确性。

算法分析:

首先保存原1CH号中断处理程序,然后设置新的1CH,完成工作后,再恢复。

示例代码78

;程序名:t16-7.asm

;功能:利用1CH号中断软接口,实现时钟显示

;首先保存原1CH号中断处理程序,然后设置新的1CH,完成工作后,再恢复

;作为例子,这里的主程序实际上没有进行实质性的工作

;--------------------------------------------------

assume cs:code,ds:code

;中断处理程序常量定义

count_val=18            ;间隔“滴答”数

dpage=0                     ;显示页号

row=0                         ;显示时钟的行号

column=80-buff_len         ;显示时钟的开始列号

color=07h                   ;显示时钟的属性值

;代码

code segment

;1CH号中断处理程序使用的变量

count dw count_val          ;嘀嗒计数

hhhh db ?,?,':'                    ;时

mmmm db ?,?,':'               ;分

ssss db ?,?                           ;秒

buff_len=$-offset hhhh   ;buff_len为显示信息长度

cursor dw ?                         ;原光标位置

;=======================================================

;1CH号中断处理程序代码

new1ch:

         cmp cs:count,0         ;是否已到显示时候?

         jz next                         ;是,转

         dec cs:count

         iret                              ;中断返回

next:

         mov cs:count,count_val  ;重置间隔数初值

         sti                                 ;开中断

         push ds

         push es

         push ax

         push bx

         push cx

         push dx

         push si

         push bp

        

         push cs

         pop ds

         push ds

         pop es                ;置代码段寄存器

         call get_t          ;取时间

        

         mov bh,dpage

         mov ah,3          ;取原光标位置

         int 10h

         mov cursor,dx  ;保存原光标位置

         mov bp,offset hhhh

         mov bh,dpage

         mov dh,row

         mov dl,column

         mov bl,color

         mov cx,buff_len        ;?

         mov al,0

         mov ah,13h               ;显示时钟

         int 10h

         mov bh,dpage           ;恢复原光标

         mov dx,cursor

         mov ah,2

         int 10h

        

         pop bp

         pop si

         pop dx

         pop cx

         pop bx

         pop ax

         pop es

         pop ds

         iret

         ;

;-----------------------------------------------

;子程序说明信息略

get_t proc

         mov ah,2 ;取时间信息

         int 1ah               ;时钟管理中断

         mov al,ch          ;把时数转为可显示形式

         call ttasc

         xchg ah,al

         mov word ptr hhhh,ax

         mov al,cl           ;把分数转为可显示形式

         call ttasc

         xchg ah,al

         mov word ptr mmmm,ax         ;保存

         mov al,dh          ;把秒数转为可显示形式

         call ttasc

         xchg ah,al

         mov word ptr ssss,ax        ;保存

         ret

get_t endp

;------------------------------------------------

;子程序:ttasc

;功能:把两位压缩的BCD码转换为对应的ASCII码

;入口参数:AL=压缩BCD码

;出口参数:AH=高位BCD码所对应的ASCII码,AL=低位BCD码所对应的ASCII码

ttasc proc

         mov ah,al

         and al,0fh

         shr ah,1

         shr ah,1

         shr ah,1

         shr ah,1

         add ax,3030h

         ret

ttasc endp

;-----------------------------

;初始化部分代码变量

old1ch dd ?                ;原中断向量保存单元

start:

         push cs

         pop ds

         mov ax,351ch  ;取1CH号中断向量

         int 21h

         mov word ptr old1ch,bx  ;保存

         mov word ptr old1ch+2,es

         ;

         mov dx,offset new1ch

         mov ax,251ch

         int 21h

         ;......

         ;其他工作

         mov ah,0          ;假设其他工作是等待按键

         int 16h

         ;

         lds dx,old1ch    ;取保存的原1CH号中断向量

         mov ax,251ch

         int 21h               ;恢复原1CH号中断向量

         ;

         mov ax,4c00h

         int 21h

        

code ends

end start

练习

1、基本输入输出系统BIOS主要含有哪些内容?是如何实现的?

2、简述应用程序实现输入输出的几种方式。

3、简述实现键盘输入的流程。

4、写一个程序采用十六进制数的形式显示所按键的扫描码及对应的ASCII码。连续两次按回车键时结束程序。

5、可以使用多少种方法实现在屏幕左上角显示AB两个字符?请比较这些方法。

6、使用两种不同的方法实现清屏。

7、写一个程序,采用直接写屏的方法在屏幕上循环显示26个大写字母。当按任一键后终止程序,通过调用BIOS键盘缓冲管理模块的1号功能判别是否有按键按下。

8、写一个程序在屏幕上循环显示26个大写字母,每行显示10个,逐行变化显示颜色,当按下ALT+F1键时终止程序。

9、可以有多少种方法实现“把屏幕上显示的大写字母全部变换成对应的小写字母”。

10、写一个程序统计当前屏幕上正在显示的字母符个数。

11、写一个程序判别屏幕上是否有显示字符串'AB'。在屏幕的最底行显示提示信息,按任意键终止程序。

12、请写一个显示打印接口当前状态的程序。

13、请写一个将TEST.TXT文件打印输出的程序。

14、修改9H号键盘中断程序,使所按的大写字母全部变换为对应的小写字母。

15、修改16H号键盘I/O程序,使所按的大写字母全部变换为对应的小写字母。

16、修改10H号显示I/O程序,使所按的大写字母全部变换为对应的小写字母。

17、写一个程序在屏幕中央显示系统当前时间,同时按下左右SHIFT键时,清屏并结束程序。

18、如何不使用软中断指令INT调用16H中断处理程序,请给出实例。

本文摘自编程达人系列教材《X86汇编语言基础教程》。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/520878.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP传输收发

TCP通信: TCP发端: socket connect send recv close TCP收端: socket bind listen accept send recv close 1.connect int connect(int sockfd, const struct sockaddr *addr, socklen_t ad…

selenium也能过某数、5s盾..

文章转载于:selenium也能过某数、5s盾… 直接安装: pip install undetected_chromedriver运行代码: import undetected_chromedriver as uc import timedriver uc.Chrome(executable_pathrC:\Users\chromedriver.exe,version_main111) driver.get(网…

VMware Workstation安装Linux虚拟机与虚拟机克隆

虚拟机 一、安装虚拟机二、克隆虚拟机三、配置静态IP地址一、安装虚拟机 设置虚拟机名称与安装位置 设置磁盘大小 配置硬件参数

Ubuntu环境使用docker构建并运行SpringBoot镜像

今天Ubuntu环境使用docker构建并运行SpringBoot镜像,看文章之前建议先查看安装流程: Linux环境之Ubuntu安装Docker流程 一、镜像打包过程及执行 1、创建一个测试目录 mkdir javaDemo 2、springBoot的包复制到此目录下 cp demo1-0.0.1-SNAPSHOT.jar /data/app/…

代码之旅:我的算法探索之路(二)力扣 最接近的三数之和

目录 LeetCode 第16题 最接近的三数之和 题目 解题思路 代码 结果 LeetCode 第18题 四数之和 题目 解题思路 代码 结果 LeetCode 第16题 最接近的三数之和 题目 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使…

mysql如何开启远程访问?

MySQL是一种常见的关系型数据库管理系统,广泛应用于各行各业。默认情况下,MySQL仅允许本地访问,即只能在本地主机上进行数据库操作。有时候我们需要通过远程连接访问MySQL数据库,以便实现更灵活的管理和操作。本文将介绍如何在MyS…

vue3+elementPlus:el-table-column表格列动态设置单元格颜色

:cell-style属性 //html<el-tableempty-text"暂无数据":data"datalist.table":max-height"height"row-key"id"border:cell-style"cellStyle"> <el-table>//js //动态设置单元格颜色 const cellStyle ({ row, c…

如何将当前目录的github.com替换为镜像源(kkgithub.com)

find . -type f -exec sed -i ‘s/github.com/kkgithub.com/g’ {} 这个命令会执行以下操作&#xff1a;find .: 在当前目录及其所有子目录中递归搜索文件。 -type f: 指定只搜索普通文件&#xff08;regular files&#xff09;&#xff0c;排除目录等其他类型的文件。 -exec…

【C++干货基地】六大默认成员函数: This指针 | 构造函数 | 析构函数

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

平台工程指南:从架构构建到职责分工

平台工程只是 DevOps 专业化的另一个术语&#xff0c;还是另有所指&#xff1f;事实可能介于两者之间。DevOps 及其相关的 DevXOps 有着浓厚的文化色彩&#xff0c;以各个团队为中心。不幸的是&#xff0c;在许多地方&#xff0c;DevOps 引发了新的问题&#xff0c;如工具激增和…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑净负荷均衡的分布式光伏集群电压调控策略研究》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

智引未来:2024年科技革新引领工业界变革与机遇

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…