實驗四 8086標志寄存器及中斷
- 在實驗開始之前,需要一些通用的基礎知識,如果覺得自己基礎知識不牢靠的同學可以看這里~
- 在實驗123中用到的知識這里不再贅述~
- 標志寄存器與常用標志位
- 標志寄存器
- 標志寄存器與其他寄存器不同,不是用來記錄地址或者數據的
- 標志寄存器的每一位都有不同的,特殊的含義
- 標志寄存器中有一些常用的標志位被稱為常用標志位
- 下圖是8086的標志寄存器的圖示
- 常用標志位
- 下面介紹一些常用標志位( CF,ZF,SF,IF,OF ),介紹順序是從寄存器的低位到寄存器的高位
- CF( Carry Flag )
- 表示進位
- 反應無符號數運算時,最高位是否產生對更高位的進位或借位
- 最高位進位: 做加法時, 最高位向更高位進行進位操作,如90+11=110, 最高位十位向更高位百位進行了進位操作,這時CF被置為1
- 最高位借位:做減法時, 最高位向更高位進行借位操作,如10-11=-1, 最高位十位向更高位百位進行了借位操作,這時CF被置為1
- 如果沒有產生進位,則將CF置為0
- ZF( Zero Flag )
- 表示是否為0
- 反應運算結束后,結果是否為0
- 若運算結果為0,則ZF被置為1
- 若運算結果為1,則ZF被置為0
- SF( Sign Flag )
- 表示符號位
- 反應有符號數運算結果的符號情況
- 若運算結果為正,則SF被置為0
- 若運算結果為負,則SF被置為1
- 在無符號數計算時也會影響SF的值,但是對於我們來說,此時SF的值沒有意義
- IF( Interrupt-enable Flag )
- 表示中斷
- 反應cpu是否可以響應cpu外部的可屏蔽中斷請求
- 若IF被置為1,則表示cpu可以響應cpu外部發出的可屏蔽中斷的請求
- 若IF被置為0,則表示cpu不可響應cpu外部發出的可屏蔽中斷的請求
- 兩個注意點
- 無論IF被置為何值,cpu都必須相應cpu外部的不可屏蔽中斷的請求
- 無論IF被置為何值,cpu都必須相應cpu內部的中斷請求
- OF( Overflow Flag )
- 表示溢出
- 反應有符號數加減運算的結果是否溢出
- 如果有溢出,則OF被設置為1(符合直覺的設置,1表示真,表示有溢出)
- 如果沒有移出,則OF被設置為0
- OF與CF的不同點
- CF是對無符號數有意義的標志位
- OF是對有符號數有意義的標志位
- CF( Carry Flag )
- 下面介紹一些常用標志位( CF,ZF,SF,IF,OF ),介紹順序是從寄存器的低位到寄存器的高位
- 標志位在debug中的表示
- 個人理解
- OF
- OV = Over
- NV = Not Over
- IF
- EI = Enable Interruption
- DI = Deny Interruption
- SF
- NG = Negative
- PL = Positive
- ZF
- ZR = Zero
- NZ = Not Zero
- CF
- CY = Carry
- NC = Not Carry
- OF
- 個人理解
- 標志寄存器
- 條件轉移指令
- 解釋
- "條件轉移"中的"轉移": 指的是能夠修改IP
- "條件轉移"中的"條件":指的是能夠根據某種條件,決定是否更改IP
- 所有條件轉移指令的轉移位移都是[-128,127]
- 條件轉移指令的構成
- 字母j:表示轉移指令jump
- 字母e:表示equl
- ne:表示not equal
- 字母b:表示below
- nb:表示not below
- 字母a:表示above
- na:表示not above
- 常見的條件轉移指令
- je:jump equal,表示等於則轉移
- 使用時會檢查常用標志位zf的值,若為1則轉移
- 一般zf標志位的值通過cmp指令更改,若zf=1說明cmp指令對應的兩個操作數相等,所以可以實現"相等則轉移"
- 下面的條件跳轉指令中常用標志位的作用大體相同,不再贅述
- jne: jump not equal,表示不等於則轉移
- 使用時會檢查常用標志位zf的值,若為0則轉移
- jb: jump below,表示低於則轉移
- 使用時會檢查常用標志位cf的值,若為1則轉移
- jnb: jump not below, 表示不低於則轉移
- 使用時會檢查常用標志位cf的值,若為0則轉移
- ja: jump above, 表示高於(>)則轉移
- 使用時會檢查cf和zf的值, 若cf=0且zf=0則轉移
- jna: jump not above, 若不高於(<=)則轉移
- 使用時會檢查cf和zf的值,若cf=1或zf=1則轉移
- je:jump equal,表示等於則轉移
- 解釋
- cmp指令
- 指令格式
- cmp 操作對象a, 操作對象b
- 功能
- 計算a-b的值, 並根據結果修改相應標志位的值
- 例子
- cmp ax, ax
- 執行該指令后, zf=1 sf=0 cf=0 of=0
- debug中的表示為 ZR PL NC NV
- cmp指令修改后標志寄存器sf,of的值以及表示的含義(以cmp ax, bx為例)
- sf=0, of=0
- sf=0表示ax-bx的運算結果為正,of=0表示沒有溢出
- 該結果表示ax>bx
- sf=0, of=1
- sf=0表示ax-bx的運算結果為正, of=1表示有溢出
- 該結果表示ax<bx
- 因為運算結果溢出導致了運算結果為正.
- 眾所周知, 溢出是指在計算時對符號位產生了影響
- 現在的計算結果為正,且發生了溢出,則表示原來的運算結果為負
- 所以結果表示ax<bx
- sf=1, of=0
- sf=0表示運算結果為正, of=0表示未發生溢出
- 該結果表示ax>bx
- sf=1, of=1
- sf=1表示運算結果為負, of=1表示發生了溢出
- 該結果表示ax>bx
- 眾所周知,溢出是指在計算時對符號位產生了影響
- 現在的計算結果為負,且發生了溢出,則表示原來的運算結果為正
- 所以結果表示ax>bx
- sf=0, of=0
- 值得注意的是,並不是sf和of兩個標志位能反應cmp的運算結果,其他標志位(如zf)也可以表示結果,由於比較簡單,這里不再贅述
- 指令格式
- adc指令
- 指令格式
- adc 操作對象a, 操作對象b
- 實現功能
- 將a中的數值,b中的數值,CF標志位的數值相加,放入a中,即
- a = a + b +CF
- 應用場景
- 由於運算時加上了CF標志位,. 故而一般用作大整數加減法
- 指令格式
- 標志寄存器與常用標志位
- 下面正式開始實驗
四.實驗內容
實驗任務1
- 驗證實驗
- 對於add指令,先輸入相應的匯編代碼,單步執行查看結果
- 可以發現,add指令會對標志位ZF和CF產生影響
- ZF位從NZ變成了ZR,表示運算結果為0
- CF位從NC變成了CY,表示運算中最高位向更高位產生了進位
- 對於inc指令,輸入相應的匯編代碼,單步執行查看結果
- 可以發現,inc指令只會對ZF位產生影響, 對CF位不會產生影響
- ZF位從NZ變為ZR,表示運算結果位0
- CF位未發生變化
- 問答問題
- 實驗代碼如下所示
-
1 assume cs:code, ds:data 2 3 data segment 4 x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h 5 y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h 6 data ends 7 code segment 8 start: 9 mov ax, data 10 mov ds, ax 11 mov si, offset x 12 mov di, offset y 13 call add128 14 15 mov ah, 4ch 16 int 21h 17 18 add128: 19 push ax 20 push cx 21 push si 22 push di 23 24 sub ax, ax 25 26 mov cx, 8 27 s: mov ax, [si] 28 adc ax, [di] 29 mov [si], ax 30 31 inc si 32 inc si 33 inc di 34 inc di 35 loop s 36 37 pop di 38 pop si 39 pop cx 40 pop ax 41 ret 42 code ends 43 end start
- 回答問題
- inc指令不能換成add指令,理由如下
- 理論:
- 我們知道, 在進行128位大整數加法時,需要用到adc指令
- 而adc指令運算時會被CF標志位影響
- 大整數加法時,adc中存儲的應該是低幾位(此題中是低16個二進制位)向更高位的進位
- 而我們知道,inc指令不會影響CF標志位, add指令會影響CF標志位
- 此題:
- 此題是大整數加法, 所以進行加法運算時運用的是adc指令,會用到CF標志位的數值
- 若使用了add si, 2和add di, 2指令, 則會對CF標志位產生影響
- 進而影響到adc指令的執行結果
- 最終影響到計算結果
- 所以不能換成add指令
- 理論:
- inc指令不能換成add指令,理由如下
- 在程序運行前, x(第一行)和y(第二行)的數據如下
- 在程序運行后, x(第一行)和y(第二行)的數據如下
- 可以發現, 確實是完成了128位二進制數的加法
- 在程序運行前, x(第一行)和y(第二行)的數據如下
實驗任務2
- 在本題中,需要一些另外的匯編語言知識
- int 21h指令
- 在實驗3中講過,int 21h指令會根據寄存器ah中的值的不同作出不同的反應
- ah=1, 程序中斷, 等待用戶輸入,將用戶輸入的內容(單個字符)存放在AL中
- ah=2, 程序根據ASCII碼輸出存放在寄存器DL中的字符串
- 在實驗3中講過,int 21h指令會根據寄存器ah中的值的不同作出不同的反應
- int 21h指令
- 下面正式開始實驗
- 題目如下
-
- task2.asm源碼如下所示
-
1 assume cs:code, ds:data 2 data segment 3 str db 80 dup(?) 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 mov si, 0 11 s1: 12 mov ah, 1 13 int 21h 14 mov [si], al 15 cmp al, '#' 16 je next 17 inc si 18 jmp s1 19 next: 20 mov ah, 2 21 mov dl, 0ah 22 int 21h 23 24 mov cx, si 25 mov si, 0 26 s2: mov ah, 2 27 mov dl, [si] 28 int 21h 29 inc si 30 loop s2 31 32 mov ah, 4ch 33 int 21h 34 code ends 35 end start
-
- 運行結果如下
- 回答問題①
- 功能總覽
- 讀取用戶輸入的字符, 並將之保存在ds:[si]中.如果是"#"則跳轉到"next"處執行,否則繼續讀入下一個字符串
- 功能詳解
- line12~13: 調整寄存器AH中的值為1, 並通過int 21h指令中斷程序, 等待用戶輸入
- line14: 將用戶輸入的值移動到ds:[si]中
- line15~16: 將用戶輸入的輸入的字符與"#"比較, 如果相等則跳轉到"next"處
- line17: si自加
- line18: 程序跳轉到S1處,重復line12-18
- 功能總覽
- 回答問題②
- 功能總覽
- 換行
- 功能詳解
- line20: 將2存放在寄存器AH中,供下面的int 21h使用
- line21: 將換行的ASCII碼放在寄存器DL中, 供下面的int 21h使用
- line22: 打印換行
- 功能總覽
- 回答問題③
- 功能總覽
- 打印輸出除了"#"以外用戶輸入的所有字符
- 功能詳解
- line24: 將si的數值放在cx中,此時si中存放着字符串的終結地址, 字符串終結地址-字符串的開始地址=字符串長度,而開始地址為0(line10 mov si,0),所以此時si的值就是字符串長度,放入cx中為循環做准備
- line25: 將si的數值設置為0, 即用戶輸入的字符串的開頭的地址(line 10 mov si,0), 為循環做准備
- line26-28: 設置AH,DL的值,將si指向的字符的ASCII碼放入DL中, 並使用int 21h指令輸出
- line29: si自加, 指針下移, 准備輸出下一個字符
- 功能總覽
- 題目如下
實驗任務3
- 實驗題目
- 初見印象(可以先看實驗三的實驗任務3)
- 與上一次實驗,實驗三的題目類似, 需要先將存儲的數值型數據轉換成對應的ASCII碼,再將其進行輸出
- 與實驗三不同的是, 實驗三的每一個數據都是兩位數, 所以每個數循環兩次除法即可,此題需要用cmp進行判斷,以確定當前處理的數據需要進行幾次除法
- 題目思路
- 總體思路
- 先將對應的數據段送至ds中
- 循環處理ds中的每個數字, 調用printNumber代碼段進行輸出, 再調用printSpace代碼段進行輸出
- 編寫子程序printNumber(以91為例)
- 首先取出91的個位數, 將個位數1轉換為對應的ASCII碼
- 判斷此時的數是否為0,不為0,繼續
- 取出91的十位數, 將十位數9轉換成對應的ASCII碼
- 判斷此時的數是否為0,為0,終止
- 編寫子程序printSpace
- 比較簡單,與實驗三的試驗任務3的printSpace完全一致,不再贅述
- 總體思路
- 代碼設計
- 子程序printNumber
- 將待輸入的數據存放在寄存器AX中, 等待處理
- 使用div指令對AX中的數據做除法
- 使用or指令對余數進行處理, 將數值型數據改成相應的ASCII碼, 並將之壓入棧中
- 這里使用棧的原因: 因為最先處理的低位(如個位), 而輸出時需要先輸出高位(如十位), 所以使用棧"先進后出"的特點, 將最先處理的最后輸出
- 使用mov指令對商進行處理,將商放在AX中, 以供判斷
- 使用or指令對余數進行處理, 將數值型數據改成相應的ASCII碼, 並將之壓入棧中
- 使用cmp指令判斷AX中的數據是否為0
- 若不為0則表示尚未處理完成, 使用jne指令跳轉至printNumber的第二步
- 若為0則表示已經對該數值型數據處理完畢, 繼續進行下一步
- 將AH中的值改為02h, 使用pop指令將棧中的數據送至DL中
- 運用int 21h指令輸出
- 注意! 子程序printNumber編寫時應該注意
- 由於運算過程中商可能會大於兩個十六進制位(也就是大於AL的存儲范圍), 也就是說,16位/8位的除法不能使用, 所以需要使用32位/16位除法
- 當被除數被放在16位寄存器中, 進行除法時, 會將dx:ax當作被除數, dx中存放余數, ax中存放商
- 子程序printNumber
- 思路設計完成, 實現方式已經規划好, 下面開始編寫代碼, 代碼如下
-
1 assume ds:data, cs:code 2 data segment 3 x dw 91, 792, 8536, 65521, 2021 4 len equ $ - x 5 y db 200 dup(?) ;為棧的使用開辟空間 6 leny equ $ - y 7 data ends 8 9 code segment 10 start: 11 mov ax, offset y 12 mov ss, ax 13 mov sp, leny ;設置棧頂 14 15 mov ax, data ;將x數據段放入ds:[si]中 16 mov ds, ax 17 mov si, 0 18 mov cx, 5 ;一共五個數, 所以循環5次 19 s2: 20 call printNumber 21 call printSpace 22 add si, 2 23 loop s2 24 25 mov ah, 4ch 26 int 21h 27 28 29 30 printNumber: 31 push cx ;將外部循環s2的剩余次數壓入棧中 32 mov ax, ds:[si] ;將被除數放入ax中 33 mov dx, 0 ;由於數值最大位65521, 小於8位16進制能表達的最大數6535, 所以被除數的高16位可以設置位0 34 mov bx, 10 ;將除數10放入bx中 35 mov cx, 0h ;cx寄存器用於計數 36 s1: 37 inc cx ;每做一次除法都進行一次計數 38 div bx ;除法操作, 由於除數是16位, 被除數就被解讀為dx:ax, 余數在dx中, 商在ax中 39 or dx, 30h ;將余數轉為相應的ASCII碼 40 push dx ;將結果壓入棧中 41 mov dx, 0 ;作用與33行的一樣, 同時起到將余數清空為0的作用 42 cmp ax, 0 43 jne s1 44 s3: 45 pop dx ;將棧頂數據放入dx中 46 mov ah, 02h 47 int 21h ;使用int 21h指令輸出 48 loop s3 ;循環輸出, 次數為做除法的次數 49 pop cx ;將棧底的外部循環次數放入cx中 50 ret 51 52 printSpace: 53 mov dl, ' ' 54 mov ah, 02h 55 int 21h 56 ret 57 58 59 code ends 60 end start
- 運行結果如下
-
-
實驗任務4
- 實驗題目
- 初見印象
- 如果用C或者java等高級語言會很好寫
- 用匯編寫的思路和用高級語言的差不多
- 說的很對, "匯編語言, 不難但是很煩"
- 題目思路
- 總體思路
- 先將對應的數據地址送入ds中
- 運用循環, 對字符串的每一個字符, 判斷是否是小寫字母
- 如果是小寫字母,就把它變成大寫字符, 運用實驗一的實驗任務5中學到的or ax, 0dfh指令就可以做到(減去32), 在此之后將之輸出
- 如果不是小寫字母, 就直接輸出, 並進行下一輪循環
- 編寫子程序strupr
- 判斷ds:[si]中的數值是否大於(97)10, 即是否大於小寫字母a的ASCII碼
- 如果不是, 則可以將該字符放入DL中, 使用int 21h指令直接輸出
- 如果是. 則可以斷言該字符是小寫字母
- 原因如下
- 需要處理的字符串中, 只包含了小寫字母,單引號,逗號和空格
- 小寫字母的ASCII碼范圍是[97,112]
- 單引號的ASCII碼為39
- 逗號的ASCII碼為44
- 空格的ASCII碼為32
- 所以大於97的一定是小寫字母
- 確定了該字符是小寫字母, 則
- 使用or指令或sub指令將之轉為大寫字母
- 將大寫化后的字符存入DL中, 並使用int 21h指令輸出
- 原因如下
- 判斷ds:[si]中的數值是否大於(97)10, 即是否大於小寫字母a的ASCII碼
- 總體思路
- 代碼設計
- 整體代碼
- 將對應的數據段存入ds中
- 使用mov指令將len放入cx中
- 運用循環, 調用strupr代碼段
- 結束程序
- 子程序strupr
- 判斷ds:[si]中的數值是否大於(97)10, 即是否大於小寫字母a的ASCII碼
- 如果不是, 說明該字符是空格或大寫字母, 則可以將該字符放入DL中, 使用int 21h指令直接輸出
- 如果是, 說明該字符是小寫字母
- 使用or指令或sub指令將之轉為大寫字母
- 將大寫化后的字符存入DL中, 並使用int 21h指令輸出
- 判斷ds:[si]中的數值是否大於(97)10, 即是否大於小寫字母a的ASCII碼
- 整體代碼
- 思路設計完成, 實現方式已經規划好, 下面開始編寫代碼, 代碼如下
-
1 assume ds:data, cs:code 2 data segment 3 str db "assembly language, it's not difficult but tedious" 4 len equ $ - str 5 data ends 6 7 code segment 8 start: 9 10 mov ax, data 11 mov ds, ax 12 mov si, offset str 13 14 mov cx, len 15 16 s1: 17 call strupr 18 inc si 19 loop s1 20 21 mov ah, 4ch 22 int 21h 23 24 strupr: 25 cmp byte ptr ds:[si], 96 26 jna s2 ;如果當前的字符小於等於96,則直接輸出 27 sub byte ptr ds:[si], 32 ;否則轉為大寫字母 28 s2: 29 mov dx, ds:[si] 30 mov ah, 2 31 int 21h 32 ret 33 34 code ends 35 end start
- 測試結果如下
-
實驗任務5
- 實驗題目
- task5.asm源碼如下
-
1 assume cs:code, ds:data 2 3 data segment 4 str1 db "yes", '$' 5 str2 db "no", '$' 6 data ends 7 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 13 mov ah, 1 14 int 21h 15 16 mov ah, 2 17 mov bh, 0 18 mov dh, 24 19 mov dl, 70 20 int 10h 21 22 cmp al, '7' 23 je s1 24 mov ah, 9 25 mov dx, offset str2 26 int 21h 27 28 jmp over 29 30 s1: mov ah, 9 31 mov dx, offset str1 32 int 21h 33 over: 34 mov ah, 4ch 35 int 21h 36 code ends 37 end start
-
- 運行結果如下
- 程序功能分析
- 總體功能分析
- 接收用戶輸入的一個字符
- 如果輸入的是7, 則在(第27行, 第70列)輸出yes
- 如果輸入的不是7, 則在(第27行, 第70列)輸出no
- 接收用戶輸入的一個字符
- 逐行分析
- line10-11: 將需要處理的數據送入ds中
- line13-14: 設置寄存器ah的值, 調用int 21h指令中斷, 並等待用戶輸入
- line16-20: 設置一系列寄存器的值, 並最后調用int 10h指令將光標位置定在第24行第70列
- line22-32: 判斷用戶輸入的字符是否為'7',如果是則輸出yes, 若不是則輸出no
- line22: 將用戶輸入的字符與字符'7'進行比較, 並根據比較結果設置標志寄存器的值, 這里主要用到了ZF標志位
- line23: 使用je指令, 查看標志位ZF的值是否為0
- 若為0則說明用戶輸入的字符和字符'7'相同, 此時跳轉到s1代碼段
- 若不為0則說明用戶輸入的字符不是字符'7', 無視je指令, 繼續執行
- line24-28
- 當je指令未跳轉時執行
- 使用int 21h的9號子功能, 輸出一個以'$'結尾的字符串(不輸出$), 這里輸出no
- 執行完成后直接跳轉到line33
- line30-32
- 當je指令跳轉時執行
- 使用int 21h的9號子功能, 輸出一個以'$'結尾的字符串(不輸出$), 這里輸出yes
- line33-35:
- 程序退出
- 總體功能分析
實驗任務6
- 實驗開始之前, 我們需要一些基礎知識
- 8086cpu是如何處理中斷的?
- 8086cpu在收到中斷請求后, 會執行內存中特定的某段程序
- 在這段程序執行完畢后返回中斷的地方
- 這里面涉及到幾個問題
- 1. 如何得知需要執行的中斷程序在哪里?
- 2. 如何存儲中斷前的位置?
- 對以上幾個問題做出如下回答
- 對於問題1
- 在中斷時, 中斷請求會給出一個中斷類型碼N
- 中斷觸發時運行的程序的地址為(N*4) : (N*4+2)號內存中存放的地址
- 這句話看着比較難受, 舉個例子就很清楚
- 假設現在有個中斷程序, 他的起始位置是0000:0200h
- 那么就會把0000放在標號為N*4的地址空間里
- 把0200放在標號為(N*4+2)的地址空間里
- 若想知道中斷程序的起始地址, 就去(N*4) : (N*4+2)里找吧!
- 計算機會讓[IP]=[N*4+2], [CS] = [N*4]
- 這句話看着比較難受, 舉個例子就很清楚
- 以int指令為例
- int 21h的中斷類型碼就是21h
- 對於問題2
- 在執行中斷程序之前, cpu會將一系列數據進行入棧操作, 其中就包括了中斷執行前的CS,IP值
- 在中斷程序的最后,會有iret指令將CS,IP的值出棧並保存在相應位置
- 對於問題1
- rep movsb命令
- movsb指令用於把字節從ds:si 搬到es:di;
- rep是repeat的意思,rep movsb 就是多次搬運。
- 搬運前先把字符串的長度存在cx寄存器中,然后重復的次數就是cx寄存器所存數據的值。
- 8086cpu是如何處理中斷的?
- 對於該實驗, 我們先逐步理解老師給出的代碼
- 老師給出了兩個文件: task6_1.asm和task6_2.asm
- 為什么是兩個文件捏?
- 上面說過, 執行中斷時會直接到相應的內存空間去尋找中斷程序的起始地址, 所以得先將中斷程序裝入內存中, 這就是task6_1.asm的功能
- task6_2.asm就是一段測試代碼, 測試task6_1.asm編寫的中斷是否生效
- 為什么是兩個文件捏?
- task6_1.asm源代碼如下
-
1 assume cs:code 2 3 code segment 4 start: 5 ; 42 interrupt routine install code 6 mov ax, cs 7 mov ds, ax 8 mov si, offset int42 ; set ds:si 9 10 mov ax, 0 11 mov es, ax 12 mov di, 200h ; set es:di 13 14 mov cx, offset int42_end - offset int42 15 cld 16 rep movsb 17 18 ; set IVT(Interrupt Vector Table) 19 mov ax, 0 20 mov es, ax 21 mov word ptr es:[42*4], 200h 22 mov word ptr es:[42*4+2], 0 23 24 mov ah, 4ch 25 int 21h 26 27 int42: 28 jmp short int42_start 29 str db "welcome to 2049!" 30 len equ $ - str 31 32 ; display string "welcome to 2049!" 33 int42_start: 34 mov ax, cs 35 mov ds, ax 36 mov si, 202h 37 38 mov ax, 0b800h 39 mov es, ax 40 mov di, 24*160 + 32*2 41 42 mov cx, len 43 s: mov al, [si] 44 mov es:[di], al 45 mov byte ptr es:[di+1], 2 46 inc si 47 add di, 2 48 loop s 49 50 iret 51 int42_end: 52 nop 53 code ends 54 end start
-
- task6_2.asm源代碼如下
-
1 assume cs:code 2 3 code segment 4 start: 5 int 42 6 7 mov ah, 4ch 8 int 21h 9 code ends 10 end start
-
- 老師給出了兩個文件: task6_1.asm和task6_2.asm
- 下面着重理解task6_1.asm
- 功能總覽
- 將中斷時執行的代碼line27-50裝入0000:0200開始的內存中
- 逐行理解
- line6-8: 設置ds:[si]為該段程序的開始地址, 為下面line16行程序復制做准備
- line10-12: 將es:[di]設置為0000:0200, 即中斷程序的開始地址, 為下面line16行程序復制做准備
- line14: 將需要存入內存的代碼段的長度放入cx中, 為下面line16行程序復制做准備
- line15: 用於設置標志位
- line16: 利用rep mobsb的命令, 將line27- 50代碼裝入es:[di]中, 即裝入中斷程序開始地址
- line19-22: 將中斷程序的開始地址的段地址部分放入es:[42*4+2]中, 將開始地址的偏移地址部分放入es:[42*4]中
- 因為此題編寫的是中斷標志碼為42的中斷程序, 所以放入了es:[42*4+2]和es:[42*4]中
- line27-50: 運用80*25彩色字符顯示空間顯示彩色字符, 實驗三已經學過, 不再贅述
- 功能總覽
- 理解完畢
- 運行結果如下
- 如果需要自己寫一個中斷其實不難....
- 只要仿制老師寫的再寫一個就行了, 大致都是相同的, 最大的不同就是line27-50這一段
- 大致思路如下
- 首先設置ds,si , es,di的值,並用rep movsb指令往內存中存入代碼
- 其次將中斷程序的開始地址放入對應位置(也就是es的值放入[N*4+2]中, 將di的值放入[N*4]中)
- 最后編寫一段中斷程序即可
- 大致思路如下
- 因為懶, 所以不寫了, 欸嘿
- 只要仿制老師寫的再寫一個就行了, 大致都是相同的, 最大的不同就是line27-50這一段