日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BIOS编程-1

發(fā)布時間:2023/12/16 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BIOS编程-1 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

可看:?https://blog.csdn.net/qq_37232329/article/details/79939184

PS: 因為BIOS編程中INT 13h中斷都是對磁盤操作,所以我放棄用DosBox改成VM虛擬機里裝上32位XP系統(tǒng)。

這樣在虛擬8086模式即dos下可以直接執(zhí)行16位程序比如debug.exe,masm.exe還有l(wèi)ink.exe

INT 9 鍵盤輸入:

BIOS提供了int 9中斷例程來處理鍵盤輸出,一般完成int9中斷例程后鍵盤輸入都會放置到內(nèi)存中的鍵盤緩沖區(qū),這個緩沖區(qū)一共有16字長度,相當于32Byte,可以放15個按鍵的掃描碼和相對應(yīng)的ASCII碼。高字節(jié)放入掃描碼,低字節(jié)放入ASCII碼。

鍵盤緩沖區(qū)是用環(huán)形隊列結(jié)構(gòu)管理內(nèi)存區(qū)的,即FIFO先入先出。

INT 16h 鍵盤輸入的讀取 :

int 16h中斷例程中的0號子程序可以從鍵盤緩沖區(qū)中讀取一個輸盤輸入。調(diào)用方法:

mov ah, 0 ;ah指明了子程序編號 int 16h ;輸出結(jié)果在ax,ah為掃描碼,al為ascii碼

例子, 這個例子是讀取r,g,b會分別讓dos窗口字體顏色變成紅綠藍= =

assume cs:code code segment start:mov ah, 0 ;讀取鍵盤緩沖區(qū)int 16hmov ah, 1 ;這個是前景色即001,藍色cmp al, 'r' ;是否為紅色je redcmp al, 'g' ;是否為綠色je greencmp al, 'b' ;是否為藍色je bluejmp short sret;下面改變顏色的代碼 red:shl ah, 1 ;從001變成了010 變綠色 green:shl ah, 1 ;從010變成了100 變紅色 blue:mov bx, 0b800hmov es, bxmov bx, 1 ;bx是第二個字節(jié)就是控制顏色mov cx, 2000 ;執(zhí)行80 * 25次,即整頁 s:and byte ptr es:[bx], 11111000b ;把原本字體顏色清除or es:[bx], ah ;把新顏色存入add bx, 2 ;保持控制顏色loop s sret:mov ax, 4c00hint 21h code ends end start結(jié)果如下圖:

這個例子主要是為了演示一下int 16h中0號子程序的讀取功能,下面說一下0號子程序的運行過程

1.首先不停掃描鍵盤緩沖區(qū)

2.如果沒有發(fā)現(xiàn)任何字符就返回1步驟

3.讀取字符

由于馬上要開始IA-32架構(gòu)的x32匯編(MASM),所以下面開始用IA-32指令集語法:

這個例子是實現(xiàn)堆棧功能:?

.MODEL small ;這個指代模式,限制一個代碼段,一個數(shù)據(jù)段,如果是x32匯編則是flat平坦模式意味著4BG內(nèi)存都是任意使用,不存在段的概念了,就一個"段".STACK 100h ;堆棧.386 ;最低CPU要求是80836處理器.data ;數(shù)據(jù)段.code ;代碼段 main PROC start:call getstr ;這里跳轉(zhuǎn)至getstrmov ax, 4c00hint 21h charstack:jmp short charstart table dw charpush, charpop, charshow top dw 0 ;棧頂指針;選擇對堆棧的操作 charstart:push bx ;保護寄存器中的內(nèi)容push dxpush dipush es cmp ah, 2 ;ah超過2表示不符合,因為只有0,1,2有功能ja sretmov bl, ah ;把功能號放入blmov bh, 0add bx, bx ;加倍是因為直接尋址表中是以字為單位的,寬度是兩字節(jié)jmp word ptr table[bx] ;跳到charpush,charpop或者charshow;堆棧的具體操作 charpush: ;ah = 0 ; al is the character which should be pushed into the stackmov bx, topmov [si][bx], alinc topjmp sret charpop: ;ah = 1 ; al is the character which popped from the stackcmp top, 0je sret dec topmov bx, topmov al, [si][bx]jmp sret ;下面這段代碼是顯示字符 charshow: ;al = 2mov bx, 0b800hmov es, bxmov al, 160mov ah, 0mul dhmov di, axadd dl, dlmov dh, 0add di, dxmov bx, 0 ;為了和棧頂指針比較 charshows:cmp bx, top ;如果堆棧中沒有東西那么就直接結(jié)束了jne noempty ;不然就顯示這個字符mov byte ptr es:[di], ' 'jmp sret noempty:mov al, [si][bx]mov es:[di], almov byte ptr es:[di + 2], ' 'inc bxadd di, 2jmp charshows sret:pop es ;結(jié)束后把堆棧中的內(nèi)容返回pop dipop dxpop bxret;從鍵盤緩沖區(qū)中獲取字符 getstr: ;先保護ax寄存器中的數(shù)據(jù)push ax getstrs: mov ah, 0int 16h ;讀取鍵盤緩沖區(qū)cmp al, 20h ;20h一下是控制字符,所以不會有顯示jb nochar ;小于就跳轉(zhuǎn)至nocharmov ah, 0 ;不然就把al中的字符push到堆棧 call charstackjmp getstrsnochar:cmp ah, 0eh ;0eh是backspace的ascii碼je backspace cmp ah, 1ch ;1ch是enter的ascii碼je enter1jmp getstrs ;跳回getstrs段backspace: mov ah, 1 ;ah = 1意味著從堆棧中pop出一個字符call charstackmov ah, 2 ;ah = 2意味著pop掉一個字符后的堆棧內(nèi)容顯示出來call charstackjmp getstrs ;繼續(xù)獲取字符直到遇到回車鍵enter1:mov al, 0 ;表示字符串結(jié)束了mov ah, 0 ;ah = 0意味著push一個字符進入堆棧call charstack mov ah, 2 ;顯示call charstack pop ax ;把堆棧中的ax返回因為已經(jīng)結(jié)束了ret ;返回主程序 main endp end main

到現(xiàn)在我們總結(jié)一下:

int 9中斷例程的作用是把鍵盤輸入放入到內(nèi)存中的鍵盤緩沖區(qū)區(qū)域,這個緩沖區(qū)是以環(huán)形隊列結(jié)構(gòu)來管理的。每個字符都是通過60h號端口讀出鍵盤掃描碼,并且轉(zhuǎn)換為ascii碼后放入鍵盤緩沖區(qū)。

int 16h中斷例程的0號子程序的作用是不停掃描鍵盤緩沖區(qū)然后把里面的字符讀出,ah放掃描碼,al放ascii碼。

主要是這兩個中斷例程。

INT 13h 磁盤讀取或?qū)懭?

書上使用3.5英寸軟盤做例子的,所以先總結(jié)一下該軟盤的參數(shù):

3.5英寸軟盤 :分上下兩面,分別有兩個磁頭附在盤面上,每一面有80個磁道,每個磁道有18個扇區(qū),每個扇區(qū)是512字節(jié)(這就是為什么主引導記錄只有512B因為就只有一個扇區(qū)大小)。扇區(qū)號從1開始,磁道和磁頭號從0開始。

3.5英寸軟盤的入口參數(shù):

(ah) = int 13h的功能號(2表示讀取,3表示寫入)

(al) = 讀取的扇區(qū)數(shù)

(ch) = 磁道號

(cl) = 扇區(qū)號

(dh) = 磁頭號

(dl) = 驅(qū)動器號 軟盤從0開始(一般那時候的機器都有2個軟盤驅(qū)動A和B),硬盤從80h開始即C盤

es:bx 指向接收從扇區(qū)讀入數(shù)據(jù)的內(nèi)存區(qū)

返回參數(shù):

操作成功: (ah) = 0, (al) = 讀入或?qū)懭肷葏^(qū)數(shù)目

(ah) = 出錯代碼

下面是實驗17,我覺得題目中的一些資料很有用,所以我也記錄一下:

用磁頭號,磁道號,扇區(qū)號來訪問磁盤是很不方便的,所以對于不同面和磁道中的扇區(qū)我們進行統(tǒng)一編號,即成為一種叫做邏輯扇區(qū)號的東西,這個概念是這么來的:

物理磁盤號:????????????????? ? 邏輯磁盤號

0面0道1扇區(qū)????????????????????? ? 0

0面0道2扇區(qū)????????????????????? ? 1

...................................................................

0面0道18扇區(qū)????????????????????? 17

0面1道1扇區(qū)????????????????????????18

...................................................................

1面0道1扇區(qū)????????????????????? 1440

..................................................................

所以可以看出來一面有1440個扇區(qū),兩面就是2880個扇區(qū)也就是一共有2880 * 512B = 1440KB 整個軟盤差不多是1.44MB(和現(xiàn)在的U盤真是天壤之別啊。。。)

計算公式:

邏輯扇區(qū)號 = (磁頭號 * 80 + 磁道號) * 18 + 扇區(qū)號 - 1

解釋一下:如果磁頭號是1,那就代表其中一面已經(jīng)寫滿了(磁頭號從0開始的), 一面一共有80個磁道,所以磁頭號 * 80就意味著一面的總磁道數(shù)目,在加上磁道號(這里磁道號是第二面的磁道號)就是總共的磁道數(shù)目,在乘以18的意思是消耗掉的總共扇區(qū)數(shù)目(一個磁道有18個扇區(qū)),因為磁道號從0開始,所以還差一個磁道,這個磁道就是現(xiàn)在正在使用的那個,所以要加上扇區(qū)數(shù)。最后減去1是因為扇區(qū)號從1開始的,現(xiàn)在正在用的那個扇區(qū)是不算的

面號(磁頭號) = 邏輯扇區(qū)號 / 1440

磁道號 = (邏輯扇區(qū)號 % 1440)/18

扇區(qū)號 = ((邏輯扇區(qū)號 % 1440) % 18) + 1

下面是實驗17,上代碼:

.model small.STACK 100h.386.data.code main PROC start:mov ax, csmov ds, axmov si, offset int7chstartmov ax, 0mov es, axmov di, 200hmov cx, offset int7chend - offset int7chstartcldrep movsbmov word ptr es:[4 * 7ch], 200hmov word ptr es:[4 * 7ch + 2], 0mov ah, 1mov dx, 1440int 7chmov ax, 4c00hint 21h;這里是7ch中斷例程的代碼 int7chstart:cmp ah, 1 ;ah只能是0或者1,即讀或者寫ja none ;不然就直接返回主程序;為了保護通用寄存器中的內(nèi)容push axpush bxpush cxpush dxpush ax ;這是ah即功能號,還有al是寫入扇區(qū)數(shù)目,壓棧保護mov ax, dxmov dx, 0mov cx, 1440div cxpush ax ;磁頭號mov cx, 18mov ax, dxmov dx, 0div cxpush ax ;磁道號inc dxpush dx ;扇區(qū)號pop ax ;把扇區(qū)號出棧至axmov cl, al ;al是因為扇區(qū)號最多是18個,不可能超過255,所以8位足夠了pop ax ;把磁道號出棧至axmov ch, al ;ch即磁道號pop ax ;把磁頭號出棧至axmov dh, al ;dh即磁頭號mov dl, 0 ;驅(qū)動器號pop ax ;把功能號出棧mov al, 1 ;寫入的扇區(qū)數(shù)目cmp ah, 0 je readcmp ah, 1je writeread:mov ah, 2 ;因為int 13h中斷例程本來ah = 2才是讀操作,但是題目要求是0所以要轉(zhuǎn)換一下jmp short ok write:mov ah, 3 ;因為int 13h中斷例程本來ah = 2才是讀操作,但是題目要求是0所以要轉(zhuǎn)換一下 ok:int 13h ;調(diào)用13h中斷例程pop dx ;結(jié)束了所以可以把寄存器中的內(nèi)容還回去pop cxpop bxpop ax none:iret ;返回主過程,因為7ch號中斷已經(jīng)調(diào)用結(jié)束了 int7chend:nop main endp end main

這個程序把前面中斷例程的內(nèi)容和現(xiàn)在的知識結(jié)合了起來,新寫一個7ch中斷,并且在中斷中調(diào)用INT 13h中斷例程的功能。相當于改變一下中斷例程的使用條件,但是最終的結(jié)果還是要使用13h中斷例程。

PS:到今天為止,8086匯編就復習總結(jié)結(jié)束了。接下去是x86匯編的復習總結(jié)和BIOS編程的深入復習,那個課程設(shè)計2下次在寫了,因為要吃飯了。bye

(完)

接下去:BIOS編程-2

總結(jié)

以上是生活随笔為你收集整理的BIOS编程-1的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。