轉載必須注明出處,違者必究。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
