您的位置:首页 > 其它

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

2017-09-24 11:06 295 查看
第十七章 使用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: http://blog.csdn.net/apollon_krj/article/details/72026944

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功能有效。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  汇编语言