• 汇编17:使用BIOS进行键盘输入和磁盘读写


    使用BIOS进行键盘输入和磁盘读写

    我们通过讨论键盘输入和磁盘读写来理解CPU对I/O的控制。

    BIOS键盘缓冲区

    键盘输入会引发9号中断,CPU会执行中断例程,从60h端口读出扫描码,然后将其转换为对应的ascii码信息,将扫描码和对应的ascii码存入内存中的指定空间中,这个空间一般是键盘缓冲区,键盘缓冲区是一个环形队列。

    如果我们按下A键就会引发键盘中断,CPU执行int9中断例程,从60h端口读出A键的通码,然后检测状态字节,将A的扫描码1eh和对应的ascii码61h写入键盘缓冲区中:

    接下来按下B、C、D、E后,缓冲区的内容如下,每个字单元的高位字节存储扫描码,低位字节存储ascii码:

    然后我们按下左shift键,此时int9接受到左shift的通码,设置0040:17处的状态字节的第一位为1,缓冲区不变。

    此时按下A键,因为检测到状态字节的改变,所以能确认左shift被按下,所以此时对应的ascii码为大写字母的ascii码41h,缓冲区内容如下:

    松开左shift键也会引发中断例程,然后将对应状态字节恢复为0.

    读取键盘缓冲区

    BIOS提供了int16h中断例程供程序员使用,它有一个功能是从键盘缓冲区中读取一个键盘输入,该功能的编号为0,下列指令可以读取一个键盘输入,同时将其从缓冲区中删除:

    mov ah,0
    int 16h
    

    执行完毕后,ah中是扫描码,al中是ascii码。

    这段代码执行后会检查键盘缓冲区中是否有数据,如果没有就一直检测,如果有的话再执行读取和从缓冲区中删除。可见,int9中断例程和int16h中断例程是一对相互配合的程序。

    字符串的输入

    最基本的字符串输入程序,需要具备下面的功能:

    1、在输入的同时需要显示这个字符串

    2、一般在输入回车符后,字符串输入结束

    3、能够删除已经输入的字符

    我们输入字符的时候是从左往右,但是删除时是先删除最右边的字符,这说明字符串应该用栈的形式存储,每次输入和删除一个字符的时候,应该将栈中的字符串显示到屏幕上,按下回车后可以在字符串中加入0,代表字符串结束。

    程序的处理过程如下:

    1、调用int16h读取键盘输入

    2、如果是字符,进入字符栈,显示字符栈中所有的字符,然后继续执行1

    3、如果是退格键,从字符栈中弹出一个字符,显示字符栈中所有的字符,继续执行1

    4、如果是enter就向字符栈中压入0,然后返回

    我们先把字符栈的入栈、出栈和显示栈中的内容写成子程序,参数说明:

    ah是功能号,0表示入栈,1表示出栈,2表示显示。ds:si指向字符栈空间,对0号功能,al是入栈字符;对1号功能,al是返回的字符;对于2号功能,dh和dl代表屏幕上显示的行、列位置。

    程序如下:

    charstack:	jmp short charstart
    		table dw charpush,charpop,charshow				建立定址表
    		top dw 0
    charstart:	push bx
    		push dx
    		push di
    		push es
    			
    		cmp ah,2
    		ja sret								如果ah大于2跳转到sret结束子程序
    		mov bl,ah
    		mov bh,0
    		add bx,bx							组成bx然后增加一倍
    		jmp word ptr table[bx]						调用对应的程序
    			
    charpush:	mov bx,top
    		mov [si][bx],al
    		inc top								入栈后修改指针的值
    		jmp sret
    			
    charpop:	cmp top,0
    		je sret								如果栈为空则直接跳转到sret
    		dec top
    		mov bx,top
    		mov al,[si][bx]							出栈后修改指针的值
    		jmp sret
    			
    charshow:	mov bx,0b800h
    		mov es,bx
    		mov al,160
    		mov ah,0
    		mul dh
    		mov di,ax
    		add dl,dl
    		mov dh,0
    		add di,dx
    			
    		mov bx,0							初始化bx为0
    			
    charshows:	cmp bx,top							比较bx和top的值判断栈是否为空
    		jne noempty
    		mov byte ptr es:[di],' '					为空则显示空格
    		jmp sret
    noempty:	mov al,[si][bx]
    		mov es:[di],al
    		mov byte ptr es:[di+2],' '
    		inc bx								不为空显示对应单元的值然后更新指针
    		add di,2
    		jmp charshows
    sret:		pop es
    		pop di
    		pop dx
    		pop bx
    		ret
    

    完整程序如下:

    getstr:	push ax
    
    getstrs:mov ah,0
    	int 16h									读取键盘缓冲区
    	cmp al,20h
    	jb nochar								ascii码低于20h说明不是字符转到nochar
    	mov ah,0
    	call charstack							        如果是字符就将其入栈
    	mov ah,2
    	call charstack							        显示字符串
    	jmp getstrs
    		
    nochar:	cmp ah,0eh
    	je backspace							        如果扫描码为0eh就转到backspace
    	cmp ah,1ch    
    	je enter								如果扫描码为1ch就转到enter
    	jmp getstrs								否则继续调用本程序
    		
    backspace:	mov ah,1
    		call charstack
    		mov ah,2
    		call charstack						        先出栈再显示字符串
    		jmp getstrs
    			
    enter:	mov al,0
    	mov ah,0
    	call charstack							        将0入栈,表示字符串的输入结束
    	mov ah,2
    	call charstack							        显示字符串
    	pop ax
    	ret
    

    用int13h中断例程对磁盘进行读写

    BIOS提供的访问磁盘的中断例程为int 13h,读取0面0道1扇区的内容到0:200的程序如下:

    mov ax,0
    mov es,ax
    mov bx,200h									es:bx指向接受数据的内存区
    
    mov al,1									读取的扇区数
    mov ch,0									磁道号为0
    mov cl,1									扇区号为1
    mov dl,0													
    mov dh,0									磁头号,也就是面号为0
    mov ah,2									2功能代表读扇区
    int 13h
    

    dl是驱动器号,对于软驱来讲0是软驱A,1是软驱B,对于硬驱来讲,80h是硬盘C,81h是硬盘D。

    如果读取成功,则ah为0,al为读入的扇区数,如果读取失败,ah里面是出错代码。

    如果是向磁盘写入,只需要将ah代表的功能号改为3即可,就可以将0:200的内容写入磁盘对应位置。

  • 相关阅读:
    Virtio:针对 Linux 的 I/O 虚拟化框架
    修复MySQL的MyISAM表命令check table用法
    Linux 下用 smartd 监测硬盘状况
    借助JVM生日的时机,说说关于JVM你所不知道的那些事
    实时流计算、Spark Streaming、Kafka、Redis、Exactly-once、实时去重
    使用Kafka、Elasticsearch、Grafana搭建业务监控系统(三)Elasticsearch
    zabbix监控多实例tomcat--不使用JMX
    KAFKA随机产生JMX 端口指定的问题
    nginx+keepalived高可用服务器宕机解决方案
    tomcat 内存参数优化示例
  • 原文地址:https://www.cnblogs.com/yinyunmoyi/p/12811639.html
Copyright © 2020-2023  润新知