汇编语言笔记17-使用BIOS进行键盘输入和磁盘读写
转载必须注明出处,违者必究。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的字符串输入程序
完整代码:
1 assume cs:code, ds:data 2 3 data segment 4 dw 100 dup (0) ; 模拟读取字符的栈 5 data ends 6 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov si, 0 12 ; 将ds:si设置为存放字符的栈 13 call getstr 14 return: 15 mov ax, 4c00h 16 int 21h 17 18 ; 完整的接受字符串输入的子程序 19 getstr: 20 push ax 21 22 getstrs: 23 mov ah, 0 24 int 16h 25 cmp al, 20h 26 jb nochar ; ASCII码小于20h, 说明不是字符 27 28 ; 字符的处理分为两步,1:入栈,2:显示栈中的字符 29 mov ah, 0 ; 1: 字符入栈 30 call charstack 31 mov ah, 2 ; 2: 显示栈中的字符 32 call charstack 33 jmp getstrs 34 35 nochar: 36 cmp ah, 0eh ; 退格键的扫描码 37 je backspace 38 cmp ah, 1ch ; Enter键的扫描码 39 je enters 40 jmp getstrs ; 其他控制键忽略 41 42 backspace: 43 mov ah, 1 44 call charstack ; 字符出栈 45 mov ah, 2 46 call charstack ; 字符显示 47 jmp getstrs 48 49 enters: 50 mov al, 0 51 mov ah, 0 52 call charstack ; 0入栈 53 mov ah, 2 54 call charstack ; 显示栈中的字符串 55 56 pop ax 57 ret 58 59 60 ; 子程序: 字符栈的入栈、出栈和显示 61 ; 参数说明:(ah)=功能号,0表示入栈,1表示出栈,2表示显示 62 ; ds:si指向字符栈的空间 63 ; 对于0号功能:(al)=入栈字符; 64 ; 对于1号功能: (al)=返回的字符; 65 ; 对于2号功能:(dh)、(dl)=字符串在屏幕上显示的行、列位置。 66 67 charstack: jmp short charstart 68 table dw charpush, charpop, charshow 69 top dw 0 ; 栈顶 70 71 charstart: 72 push bx 73 push dx 74 push di 75 push es 76 77 cmp ah, 2 78 ja sret 79 mov bl, ah 80 mov bh, 0 81 add bx, bx 82 jmp word ptr table[bx] 83 84 charpush: 85 mov bx, top 86 mov [si][bx], al 87 inc top 88 jmp sret 89 90 charpop: 91 cmp top, 0 92 je sret 93 dec top 94 mov bx, top 95 mov al, [si][bx] 96 jmp sret 97 98 charshow: ;(dh)、(dl)=字符串在屏幕上显示的行、列位置。 99 cmp bx, 0b800h 100 mov es, bx 101 mov al, 160 102 mov ah, 0 103 mul dh 104 mov di, ax 105 add dl, dl 106 mov dh, 0 107 add di, dx ; 设置 es:di 108 109 mov bx, 0 110 charshows: cmp bx, top 111 jne noempty 112 mov byte ptr es:[di], ' ' 113 jmp sret 114 noempty: 115 mov al, [si][bx] 116 mov es:[di], al 117 mov byte ptr es:[di+2], ' ' 118 inc bx 119 add di, 2 120 jmp charshows 121 sret: 122 pop es 123 pop di 124 pop dx 125 pop bx 126 ret 127 128 code ends 129 130 end start
☞使用BIOS进行磁盘的读写
-
磁盘的读写原理
磁盘的实际访问由磁盘控制器进行,可以通过磁盘控制器访问磁盘。扇区是磁盘读写的最小单位。
磁盘寻址: 面号(从0开始)->磁道号(从0开始)->扇区号(从1开始)
- BIOS提供int 13h中断例程来读写磁盘
-
读扇区
示例代码: 读取软盘的0面0道1扇区的内容到0:200。
1 assume cs:code 2 3 code segment 4 start: 5 ; 入口参数设置 6 mov ax, 0 7 mov es, ax 8 mov bx, 200 ; 1. es:bx 指向接受从扇区读入数据的内存区 9 10 mov al, 1 ; 2. (al)=需要读取扇区的数 11 12 mov dl, 0 ; 3. (dl)=驱动器号 软驱从0开始, 0:软驱A,1:软驱B 13 ; 硬盘从80h开始,80h:C盘,81h:D盘 14 mov dh, 0 ; 4. (dh)=磁头号(对于软盘即面号,一个面对应一个磁头) 15 mov ch, 0 ; 5. (ch)=磁道号 16 mov cl, 1 ; 6. (cl)=扇区号 17 18 mov ah, 2 ; 7. (ah)=int 13h的功能号(2表示读扇区) 19 int 13h 20 ; 返回参数: 21 ; 操作成功: (ah)=0, (al)=读入的扇区数 22 ; 操作失败: (ah)=出错代码 23 24 mov ax, 4c00h 25 int 21h 26 code ends 27 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