Advertisement

王爽 《汇编语言》 读书笔记 十七

阅读量:

第十七章 使用BIOS进行键盘输入和磁盘读写

17.1 int9中断例程对键盘输入的处理

一般的键盘输入,在cpu执行完int9中断例程以后,欧放到了键盘缓冲区中。 键盘缓冲区有16个字单元,可以存储15个按键的扫描码和对应的ASCII码。

参照书P300页 关于键盘缓冲区的存储利用了队列或者环形队列数据结构。

17.2 使用int16h中断例程读取键盘缓冲区

int16h 能够从键盘缓冲区读取一个键盘输入, 功能标号为0.

mov ah, 0

int 16h

结果 ah = 扫描码 bl = ascii码

然后该字符从键盘缓冲区被删除

int 16h中断例程检测键盘缓冲区,发现缓冲区为空,则循环等待,直到缓冲区中有数据。

int 16h的中断例程0号功能,进行如下工作

1)检测键盘缓冲区是否有数据

2)没有则继续第一步

3)读取缓冲区第一个字单元的键盘输入

4)将读取的扫描码送入ah, ASCII码送入al

5)将已读取的键盘输入从缓冲区中删除。

编程,接受用户的键盘输入,输入“r” ,将屏幕上的字符设置为红色,输入“g”, 将屏幕上的字符设置为绿色

输入“b“ 将屏幕上的字符设置为蓝色。

复制代码
    assume cs:code
    
    code segment
    start: 		mov ah, 0
    			int 16h
    			
    			mov ah, 1 ; used to generate the color code
    			cmp al, 'r'
    			je red
    			cmp al, 'g'
    			je green
    			cmp al, 'b'
    			je blue
    			jmp short sret
    			
    	red:	shl ah, 1 ; left shift once
    	green:	shl ah, 1 ; left shift once .  if go through red it will generate 100B
    	
    	blue:	mov bx, 0b800h
    			mov es, bx
    			mov bx, 1
    			mov cx, 2000
    	s:		and byte ptr es:[bx], 11111000b ; reset color
    			or es:[bx], ah ; set new color
    			add bx, 2
    			loop s
    			
    	sret:	mov ax, 4c00h
    			int 21h
    code ends
    end start

监测点17.1

"在int 16h中断例程中,一定有设置IF=1的指令." 这种说法对吗?

不对.

8086CPU的中断系统具有256个中断(0-255),其中分为

(1)外部中断:又分为 1. 可屏蔽中断,可以由标志寄存器中的IF位控制是否屏蔽(IF=0则屏蔽);

2. 不可屏蔽中断, 中断向量号为02;

(2)内部中断: 包括除法溢出中断,int指令中断,溢出中断,单步中断, 不受标志寄存器的IF位控制;

题意中设置为1是为了保证在读取键盘缓冲区的第一个字节内容时,键盘中断可以响应, 以便将相应按键加入键盘缓冲区中,

但是按下键即调用 int 9h, 属于内部中断, 不受IF位的控制, 故不需要将IF设置为1。

故这种说法错误。

17.3 字符串的输入

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

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

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

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

复制代码
    assume cs:code
    data segment
    	db 256 dup(' ')
    data ends
    
    stack segment
    	db 64 dup(0)
    stack ends
    
    code segment
    start:			mov ax, stack
    				mov ss, ax
    				mov sp, 64
    				
    				mov ax, data
    				mov ds, ax
    				
    				mov ax, 0
    				mov si, 0
    				
    				mov dh, 5
    				mov dl, 0
    				call getstr
    				
    				mov ax, 4c00h
    				int 21h
    
    
    
    ;getstr:
    getstr:			push ax
    
    getstrs:		mov ah, 0
    				int 16h
    				
    				cmp al, 20h
    				jb nochar		; ascii code < 20h ,it is not a char
    				mov ah, 0
    				call charstack	; push char
    				mov ah, 2
    				call charstack	; charshow
    				jmp getstrs
    				
    nochar:			cmp ah, 0eh		; backspace
    				je backspace
    				cmp ah, 1ch		; return key
    				je return
    				jmp getstrs
    				
    backspace:		mov ah, 1
    				call charstack	; pop char
    				mov ah, 2
    				call charstack	; charshow
    				jmp getstrs
    				
    return:			mov al, 0
    				mov ah, 0
    				call charstack	; push char  '\0'
    				mov ah, 2
    				call charstack	; showchar
    				pop ax
    				ret
    
    ; charstack
    ; push char into stack, pop up char from stack. and show the current char
    ; ah= 0 push,  1 pop  2 show
    ; ds:si point to the char stack.
    ; for 0  push al
    ; for 1  pop char and store to al
    ; for 2 dh, dl point to the position. Show the full string.
    charstack:		jmp short charstart
    table			dw charpush, charpop, charshow
    top				dw 0					; point to the top of the stack
    
    charstart:		push bx
    				push dx
    				push di
    				push es
    				
    				cmp ah, 2				; invalid command
    				ja charret
    				mov bl, ah
    				mov bh, 0
    				add bx, bx
    				jmp word ptr table[bx]	; call the actual function.
    
    charpush:		mov bx, top
    				mov [si][bx], al
    				inc top
    				jmp charret
    				
    charpop:		cmp top, 0
    				je charret
    				dec top
    				mov bx, top
    				mov al, [si][bx]
    				jmp charret
    				
    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, ax ; calc the offset
    				
    				mov bx, 0
    				
    charshows:		cmp bx, top
    				jne noempty
    				mov byte ptr es:[di], ' '
    				jmp charret
    noempty:		mov al, [si][bx]
    				mov es:[di], al
    				;and es:[di + 1], 11111000b
    				;or es:[di + 1], 10b				; set color
    				mov byte ptr es:[di+2], ' '
    				inc bx
    				add di, 2
    				jmp charshows
    				
    charret:		pop es
    				pop di
    				pop dx
    				pop bx
    				
    				ret
    				
    code ends
    end start

17.4 应用int 13h中断例程对磁盘进行读写

需要先在虚拟机中创建虚拟软盘

参考这篇blog: <>

3.5 英寸软盘分为上下两面,每个面80个磁道,每个磁道有18个扇区,每个扇区512个字节。

只能以扇区为单位对磁盘进行读写。

bios采用int 13h来访问磁盘。

读取0 面 0 道 1扇区道内容道0:200点程序如下

复制代码
    mov ax, 0
    mov es, ax
    mov bx, 200h
    
    mov al, 1
    mov ch, 0
    mov cl, 1
    mov dl, 0
    mov dh, 0
    mov ah, 2
    int 13h

入口参数

ah = 13h 的功能号(2表示读扇区)

al = 读取扇区数

ch = 磁道号

cl = 扇区号

dh = 磁头号(也就是软盘的面号)

dl=驱动器号(软驱从0开始代码 A, 1 代表B)

es:bx指向接受从扇区读入数据的内存区。

返回参数:

操作成功: ah = 0, al = 读入扇区的数量

操作失败: ah = 错误代码

将0:200点内容写入0面0道1扇区

复制代码
    mov ax, 0
    mov es, ax
    mov bx, 200h
    
    mov al, 1
    mov ch, 0
    mov cl, 1
    mov dl, 0
    mov dh, 0
    
    mov ah, 3
    int 13h

入口参数:

ah = int13h 功能号(3表示写扇区)

al = 写入扇区数

ch = 磁道号

cl = 扇区号

dh = 磁头号

dl = 驱动器号

es:bx指向写入磁盘的数据

将当前屏幕的内容保存在磁盘上。

注意写入软盘的0扇区会破坏文件系统导致软盘在当前操作系统下不可用。

复制代码
    assume cs:code
    code segment
    start:	mov ax, 0b800h
    		mov es, ax
    		mov bx, 0
    		
    		mov al, 8	; write 8sectors
    		mov ch, 0	; #of the track
    		mov cl, 1	; #of the first sector
    		mov dl, 0	; !!!!VERY IMPORTANT Drive A:
    		mov dh, 0	; #of disk face 
    		mov ah, 3	; write floppy
    		int 13h		; call int 13h
    		
    		mov ax, 4c00h
    		int 21h
    code ends
    end start

写入以后发现windows会提示磁盘未格式化。(文件系统被破坏了)

实验17 编写包含多个功能子程序的中断例程。

安装一个新的int 7ch中断例程,实现通过逻辑扇区号对软盘进行读写。

参数说明

1)用ah 寄存器传递功能号: 0表示读,1表示写

2)用dx寄存器传递要读写的扇区的逻辑扇区号;

3)用es:bx指向存储读初数据或写入数据的内存区。

提示,用逻辑扇区号计算出面号,磁道号,扇区号后,调用int 13h 中断例程进行实际的读写。

安装int7ch的磁盘读写例程

复制代码
    assume cs:code
    stack segment
    	db 64 dup(0)
    stack ends
    
    code segment
    start:			; set es:di as target address 0000:0200h
    				mov ax, 0
    				mov es, ax
    				mov di, 200h
    							; set ds:si as source address cs:sqr
    				mov ax, cs
    				mov ds, ax
    				mov si, offset int7ch
    							; set cx as the data length
    				mov cx, offset int7chend - offset int7ch
    							; set the transport directive DF = 0 cld
    				cld
    				rep movsb
    
    			; set the IRQ table  1F0 = 200h(IP)    1F2 = 0(CS)
    				mov ax, 0
    				mov es, ax
    				mov word ptr es:[7ch * 4], 200h	; install IRQ7ch
    				mov word ptr es:[7ch * 4 + 2], 0
    			
    				mov ax, 4c00h
    				int 21h
    		
    org 200h		
    ;write/read floppy from logic sectors
    ;in ah 0 read, 1 write/read ,al number sectors to write
    ;dx store the logic sectors.
    ;es:bx point to the buffer
    int7ch:			push cx
    
    				push ax
    				mov ax, dx
    				call getsectors		; get pyhsical address of floppy
    				cmp ah, 1
    				jne int7ret
    				pop ax
    				
    				cmp ah, 0
    				je read
    				cmp ah, 1
    				je write
    				jmp int7ret			; return
    				
    read:			mov ah, 2			; call #2 function of int13h
    				int 13h
    				jmp int7ret
    
    write:			mov ah, 3			; call #3 function of int13h
    				int 13h
    				
    				
    int7ret:		pop cx	
    				iret
    					
    ; get the pyhsical face track and sector from logic #sectors
    ; in ax (store the logic #sectors from (0~1443))
    ; out 
    ; ah = 1 success, ah = 0 failed
    ; dh #of face
    ; dl drive: default = 0
    ; ch #of track
    ; cl #of sector
    getsectors:		push bx
    
    				cmp ax, 2879
    				ja errors
    				
    				mov dx, 0
    				mov bx, 1440
    				div bx					; al = #face  ah = 0		
    				
    				push dx					; store mode
    				mov dh, al				; store face
    				mov dl, 0				; store drive label 0
    				
    				pop ax
    				mov bl, 18
    				div bl					; al = #track , ah = #sector - 1
    				
    				mov ch, al				; store # track
    				mov cl, ah
    				inc cl					; store # sector
    				
    				mov ah, 1
    				jmp short retsectors	; return true
    
    errors:			mov ah, 0				; return false
    retsectors:		pop bx
    				ret
    				
    int7chend:		nop
    code ends
    end start

执行代码:

复制代码
    assume cs:code
    code segment
    start:	mov ax, 0b800h
    		mov es, ax
    		mov bx, 0
    		
    		mov al, 8	; write 8sectors
    		mov ah, 0	; read floppy of int7ch
    		mov dx, 0	; write logic sectors 1
    		int 7ch
    		
    		mov ax, 4c00h
    		int 21h
    code ends
    end start

例如可以将当前屏幕内容写入磁盘。然后再读取出来。

实现在软盘中写入了512x8的屏幕内容

接着读取

载入了之前写入磁盘的内容。说明IO功能有效。

全部评论 (0)

还没有任何评论哟~