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

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

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

BIOS键盘缓冲区

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

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

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

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

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

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

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

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

松开左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的内容写入磁盘对应位置。

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

上一篇:【小米OJ-找多少个等差数列】动态规划


下一篇:用Unity3D做游戏开发在Android上的常用调试方法