您的位置:首页 > 移动开发 > IOS开发

汇编语言笔记17-使用BIOS进行键盘输入和磁盘读写

2012-10-28 14:37 786 查看
转载必须注明出处,违者必究。http://www.cnblogs.com/dennisOne

☞使用BIOS进行键盘输入和读取键盘缓冲区

复习键盘缓冲区和状态字节
(1). BIOS键盘缓冲区是系统启动后,BIOS用于存放int 9中断例程所接受的键盘输入的内存区。键盘缓冲区有16个字单元,可以存储15个按键的扫描码和对应的ASCII码,高位字节是扫描码,低位字节是字符码。

(2). 状态字节存放在0040:17单元。该字节记录了控制键和切换键的状态。

int 9中断例程
键盘输入将引发9号中断,BIOS提供了int 9中断例程。CPU在9号中断发生后,执行9号中断例程,从60号端口读出扫描码,将其转化为相应的ASCII码或者状态信息,存储在内存的指定空间(键盘缓冲区状态字节)中。

示意图:



简述Shift_A:

(1). 按下左Shift键,引发键盘中断;int 9中断例程接受左Shift键的通码,设置0040:17处的状态字节的第1位为1,表示左Shift键按下。

(2). 按下A键,引发键盘中断;CPU执行int 9中断例程,从60h端口读出A键的通码;检测状态字节,看看是否有切换键按下,发现左Shift键被按下,则将A键的扫描码1Eh和Shift_A对应的ASCII码,即大"A"的ASCII码41h,写入键盘缓冲区。

(3). 松开左Shift键,引发键盘中断;int 9中断例程接受左Shift键的断码,设置0040:17处的状态字节的第1位为0,表示左Shift键松开。

使用int 16h中断例程读取键盘缓冲区
mov ah, 0

int 16h

结果: (ah)=扫描码,(al)=ASCII码。

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



int 9和int 16h相互暧昧,有这不同寻找的关系,xxoo~~~

☞模拟dos的字符串输入程序



完整代码:

assume cs:code, ds:data

data segment
dw 100 dup (0)   ; 模拟读取字符的栈
data ends

code segment
start:
mov ax, data
mov ds, ax
mov si, 0
; 将ds:si设置为存放字符的栈
call getstr
return:
mov ax, 4c00h
int 21h

; 完整的接受字符串输入的子程序
getstr:
push ax

getstrs:
mov ah, 0
int 16h
cmp al, 20h
jb nochar                        ; ASCII码小于20h, 说明不是字符

; 字符的处理分为两步,1:入栈,2:显示栈中的字符
mov ah, 0                        ; 1: 字符入栈
call charstack
mov ah, 2                        ; 2: 显示栈中的字符
call charstack
jmp getstrs

nochar:
cmp ah, 0eh                    ; 退格键的扫描码
je backspace
cmp ah, 1ch                    ; Enter键的扫描码
je enters
jmp getstrs                    ; 其他控制键忽略

backspace:
mov ah, 1
call charstack                    ; 字符出栈
mov ah, 2
call charstack                    ; 字符显示
jmp getstrs

enters:
mov al, 0
mov ah, 0
call charstack                    ; 0入栈
mov ah, 2
call charstack                    ; 显示栈中的字符串

pop ax
ret

; 子程序: 字符栈的入栈、出栈和显示
; 参数说明:(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
mov bl, ah
mov bh, 0
add 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
dec top
mov bx, top
mov al, [si][bx]
jmp sret

charshow:   ;(dh)、(dl)=字符串在屏幕上显示的行、列位置。
cmp 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        ; 设置 es:di

mov bx, 0
charshows:     cmp 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

code ends

end start


☞使用BIOS进行磁盘的读写

磁盘的读写原理
磁盘的实际访问由磁盘控制器进行,可以通过磁盘控制器访问磁盘。扇区是磁盘读写的最小单位。

磁盘寻址: 面号(从0开始)->磁道号(从0开始)->扇区号(从1开始)

BIOS提供int 13h中断例程来读写磁盘

读扇区
示例代码: 读取软盘的0面0道1扇区的内容到0:200。

assume cs:code

code segment
start:
; 入口参数设置
mov ax, 0
mov es, ax
mov bx, 200         ; 1. es:bx 指向接受从扇区读入数据的内存区

mov al, 1            ; 2. (al)=需要读取扇区的数

mov dl, 0            ; 3. (dl)=驱动器号 软驱从0开始, 0:软驱A,1:软驱B
;    硬盘从80h开始,80h:C盘,81h:D盘
mov dh, 0            ; 4. (dh)=磁头号(对于软盘即面号,一个面对应一个磁头)
mov ch, 0            ; 5. (ch)=磁道号
mov cl, 1            ; 6. (cl)=扇区号

mov ah, 2            ; 7. (ah)=int 13h的功能号(2表示读扇区)
int 13h
; 返回参数:
; 操作成功: (ah)=0, (al)=读入的扇区数
; 操作失败: (ah)=出错代码

mov ax, 4c00h
int 21h
code ends
end start


写扇区--入口参数和读扇区一致,只是功能号不一样
示例代码:将0:200的内容写入软盘的0面0道1扇区。

assume cs:code

code segment
start:
; 入口参数设置
mov ax, 0
mov es, ax
mov bx, 200          ; 1. es:bx 指向写入磁盘的数据

mov al, 1            ; 2. (al)=需要写入扇区数

mov dl, 0            ; 3. (dl)=驱动器号 软驱从0开始, 0:软驱A,1:软驱B
;    硬盘从80h开始,80h:C盘,81h:D盘
mov dh, 0            ; 4. (dh)=磁头号(对于软盘即面号,一个面对应一个磁头)
mov ch, 0            ; 5. (ch)=磁道号
mov cl, 1            ; 6. (cl)=扇区号

mov ah, 3            ; 7. (ah)=int 13h的功能号(3表示写扇区)
int 13h
; 返回参数:
; 操作成功: (ah)=0, (al)=写入的扇区数
; 操作失败: (ah)=出错代码

mov ax, 4c00h
int 21h
code ends

end start
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: