【實驗四】8086標誌暫存器及中斷
任務一
驗證性實驗:有些彙編指令會影響到標誌暫存器中的一個或多個狀態標誌位。
在debug環境中,分別實踐、觀察:
① add指令對標誌暫存器中的零標誌位ZF(Zero Flag)、進位標誌位CF(Carry Flag)是否有影響?
② inc指令對標誌暫存器中的零標誌位ZF(Zero Flag)、進位標誌位CF(Carry Flag)是否有影響?
task1.asm
assume cs:code, ds:data data segment x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h data ends code segment start: mov ax, data mov ds, ax mov si, offset x mov di, offset y call add128 mov ah, 4ch int 21h add128: push ax push cx push si push di sub ax, ax mov cx, 8 s: mov ax, [si] adc ax, [di] mov [si], ax inc si inc si inc di inc di loop s pop di pop si pop cx pop ax ret code ends end start
其中:
add128是子程式子程式。
功能:實現計算兩位128位數的加法
入口引數:
ds:si指向儲存第一個128位數的儲存空間(因為一個數128位,需要8個位元組的連續空間)
ds:di指向儲存第二個128位數的儲存空間
出口引數:
加運算後的結果,儲存在第一個數的儲存空間中,即:ds:si開始的連續8個位元組空間
在程式碼段種,呼叫add128實現對標號x和y處儲存的兩個128位資料相加,結果儲存在x處的連續128個位元組中。
對程式進行彙編、連結,得到可執行程式task1.exe。在debug中除錯程式,並回答問題。
① line31~line34的4條inc指令,能否替換成如下程式碼?你的結論的依據/理由是什麼?
add si, 2
add di, 2
不能替換為上述程式碼. add指令會影響進位標誌位CF, 從而影響128位加法的進位鏈.
② 在debug中除錯,觀察資料段中做128位加之前,和,加之後,資料段的值的變化。
加之前:
加之後:
076A:0000 ~ 076A:0009 的位置(x)存放了x和y的和.
任務二
task2.asm
assume cs:code, ds:data data segment str db 80 dup(?) data ends code segment start: mov ax, data mov ds, ax mov si, 0 s1: mov ah, 1 int 21h mov [si], al cmp al, '#' je next inc si jmp s1 next: mov ah, 2 mov dl, 0ah int 21h mov cx, si mov si, 0 s2: mov ah, 2 mov dl, [si] int 21h inc si loop s2 mov ah, 4ch int 21h code ends end start
說明:task2.asm中用到的兩個DOS系統功能呼叫:
DOS系統功能呼叫int 21h的1號子功能
功能:從鍵盤上輸入單個字元
入口引數:(ah) = 1
出口引數: (al)存放輸入字元的ASCⅡ碼
即:mov ah, 1 int 21h ;(al) <-- 輸入字元的ascii碼
DOS系統功能呼叫int 21h的2號子功能
功能:輸出單個字元到螢幕上
入口引數:(ah) = 2, (dl) = 待輸出的字元或其ascⅡ碼
出口引數:無
即:mov ah, 2 mov dl, xx ; xx是待輸出的字元, 或, 其ascii碼 int 21h
執行程式,從鍵盤上輸入一串字元,以#結束(比如,輸入George Orwell, 1984#),觀察結果。結合執行結果,理解程式碼並回答問題:
① 彙編指令程式碼line11-18,實現的功能是?
持續獲取鍵盤輸入字元, 直到獲取到的字元為'#'跳轉至next.
② 彙編指令程式碼line20-22,實現的功能是?
0ah是換行符的ascii碼, 該段程式碼功能是輸出換行.
③ 彙編指令程式碼line24-30,實現的功能是?
輸出str上儲存的字串(除了'#').
任務三
針對8086CPU,已知邏輯段定義如下:
data segment
x dw 91, 792, 8536, 65521, 2021
len equ $ - x
data ends
編寫8086彙編源程式task3.asm,在螢幕上以十進位制形式輸出data段中這一組連續的資料,資料和資料之間以空格間隔。
要求:
-
編寫子程式printNumber
- 功能:以十進位制形式輸出一個任意位數的整數(整數範圍0 ~ 65535)
- 入口引數:暫存器ax(待輸出的資料 --> ax)
- 出口引數:無
-
編寫子程式printSpace
- 功能:列印一個空格
- 入口引數:無
- 出口引數:無
-
在主體程式碼中,綜合應用定址方式和迴圈,呼叫printNumber和printSpace, 實現題目要求。
assume cs:code, ds:data
data segment
x dw 91, 792, 8536, 65521, 2021
len equ ($ - x)/2
data ends
code segment
main:
mov ax, data
mov ds, ax
mov cx, len
mov si, offset x
print:
mov ax, [si]
inc si
mov dx, [si]
inc si
call printNumber
call printSpace
loop print
mov ah, 4ch
int 21h
;功能:以十進位制形式輸出一個任意位數的整數(整數範圍0 ~ 65535)
;入口引數:暫存器ax(待輸出的資料 --> ax) 以及dx(存放高位)
;出口引數:無
;限定資料範圍 0 ~ 65535, 故32位除法時無需考慮除法溢位, 直接將dx置0
printNumber:
push bx
push cx ;用來存放資料位數
mov cx, 0
save:
mov dx, 0
mov bx, 10 ;除數
div bx
push dx ;餘數入棧
inc cx
cmp ax, 0 ;判斷商
jne save
print_save:
; mov bx, dx ;列印餘數
pop bx ;列印餘數
mov dl, bl
mov ah, 2
or dl, 30h
int 21h
loop print_save
pop cx
pop bx
ret
printSpace:
push ax
push dx
mov ah, 2
mov dl, ' '
int 21h
pop dx
pop ax
ret
code ends
end main
任務四
針對8086CPU,已知邏輯段定義如下:
data segment
str db "assembly language, it's not difficult but tedious"
len equ $ - str
data ends
編寫8086彙編源程式task4.asm,將data段中字串裡的小寫字元轉換成大寫。
要求:
- 編寫子程式strupr
- 功能:將包含任意字元的字串中的小寫字母變成大寫
- 入口引數
- (ds:si ) 字串首地址的段地址和偏移地址分別送至ds和si
- (cx) 字串的長度
- 出口引數:無
- 在主體程式碼中,設定入口引數,呼叫strupr, 實現題目要求。
assume cs:code
data segment
str db "assembly language, it's not difficult but tedious"
len equ $ - str
data ends
code segment
main:
mov ax, 0b800h
mov es, ax
mov ax, data
mov ds, ax
mov cx, len
mov si, offset str
call strupr
mov cx, len
mov si, offset str
mov bl, 00000010b
mov bh, 0
call printStr
mov ah, 4ch
int 21h
;功能:將包含任意字元的字串中的小寫字母變成大寫
;入口引數:
; (ds:si ) 字串首地址的段地址和偏移地址分別送至ds和si
; (cx) 字串的長度
;出口引數:無
strupr:
cmp byte ptr [si], 97
jb no_handle
cmp byte ptr [si], 122
ja no_handle
and byte ptr [si], 11011111b
no_handle:
inc si
loop strupr
ret
; 入口引數:
; 字串首字元地址 --> ds:si(其中,字串所在段的段地址—> ds, 字串起始地址的偏移地址—> si)
; 字串長度 --> cx
; 字串顏色 --> bl
; 指定行 --> bh (取值:0 ~24)
printStr:
push bp ; 因為要用到bp和di, 先儲存現場
push di
mov ah, 0
mov al, 160
mul bh
mov bp, ax ; 計算行數偏移地址儲存在bp
mov di, si ; di儲存視訊記憶體中每個字元偏移地址
printChar:
mov al, ds:[si]
mov es:[bp+di], al ; 字元
mov es:[bp+di+1], bl ; 顏色
inc si
inc di
inc di ; di要加兩次
loop printChar
pop bp ; 還原現場
pop di
ret
code ends
end main
實驗五
使用任意文字編輯器,錄入8086彙編原始碼task5.asm。
task5.asm
assume cs:code, ds:data
data segment
str1 db "yes", '$'
str2 db "no", '$'
data ends
code segment
start:
mov ax, data
mov ds, ax
mov ah, 1
int 21h
mov ah, 2
mov bh, 0
mov dh, 24
mov dl, 70
int 10h
cmp al, '7'
je s1
mov ah, 9
mov dx, offset str2
int 21h
jmp over
s1: mov ah, 9
mov dx, offset str1
int 21h
over:
mov ah, 4ch
int 21h
code ends
end start
執行程式,輸入7,觀察結果。輸入其他字元,觀察結果。結合執行結果和註釋,理解程式碼實現的功能 .
程式碼功能: 輸入字元為'7'時, 顯示標號str1處的字串. 輸入字元為非'7'時, 顯示標號str2處的字串.
說明:task5.asm中,使用用到的DOS系統功能呼叫和BIOS中斷例程
DOS系統功能呼叫int 21h的1號子功能
功能:從鍵盤上輸入單個字元
入口引數:(ah) = 1
出口引數: (al)存放輸入字元的ASCⅡ碼
即:mov ah, 1 int 21h ; (al) <-- 輸入字元的ascⅡ碼
DOS系統功能呼叫int 21h的9號子功能
功能:顯示字串
入口引數:(ah) = 9,(ds:dx) = 字串的首地址的段地址和偏移地址
出口引數: 無
其它要求:字串必須以$結束
即:mov ah, 9 mov ds, ×× ; ××是待輸出字串所在段的段地址 mov dx, ×× ; ××是待輸出字串第一個字元的偏移地址 int 21h
BIOS中斷例程int 10h的2號子功能
功能:設定游標位置
入口引數:(ah) = 2, (bh) = 頁號(預設取0), (dh) = 行號, (dl) = 列號
出口引數:無
即:mov ah, 2 mov bh, ×× ; ××是頁號 mov dh, ×× mov dl, ×× ; ××是列號 int 10h
任務六
實驗任務1、2、3、5中使用了不少系統提供的中斷例程。本實驗任務中,要求自行實現一個42號軟中斷例程,使得通過 int 42 或 int 2ah 軟中斷呼叫,實現在螢幕最下方中間以黑底綠字列印"welcome to 2049!"。
task6_1.asm
assume cs:code
code segment
start:
; 42 interrupt routine install code
mov ax, cs
mov ds, ax
mov si, offset int42 ; set ds:si
mov ax, 0
mov es, ax
mov di, 200h ; set es:di
mov cx, offset int42_end - offset int42
cld
rep movsb
; set IVT(Interrupt Vector Table)
mov ax, 0
mov es, ax
mov word ptr es:[42*4], 200h
mov word ptr es:[42*4+2], 0
mov ah, 4ch
int 21h
int42:
jmp short int42_start
str db "welcome to 2049!"
len equ $ - str
; display string "welcome to 2049!"
int42_start:
mov ax, cs
mov ds, ax
mov si, 202h
mov ax, 0b800h
mov es, ax
mov di, 24*160 + 32*2
mov cx, len
s: mov al, [si]
mov es:[di], al
mov byte ptr es:[di+1], 2
inc si
add di, 2
loop s
iret
int42_end:
nop
code ends
end start
task6_2.asm
assume cs:code
code segment
start:
int 42
mov ah, 4ch
int 21h
code ends
end start
執行task6_1.exe,實現將
42號中斷處理程式安裝到0:200開始的連續記憶體空間,並設定中斷向量表,使得將來通過 int 42 ,系統可以跳轉到中斷處理程式。
對彙編源程式task6_2.asm進行彙編、連結,得到可執行程式task6_2.exe。執行task6_2.exe。
自定義43號中斷:
中斷執行程式即為 實驗三 任務五 : 列印藍屏 && 輸出學號
修改後的task6_1.asm
assume cs:code
code segment
start:
; 43 interrupt routine install code
mov ax, cs
mov ds, ax
mov si, offset int43 ; set ds:si
mov ax, 0
mov es, ax
mov di, 200h ; set es:di
mov cx, offset int43_end - offset int43
cld
rep movsb
; set IVT(Interrupt Vector Table)
mov ax, 0
mov es, ax
mov word ptr es:[43*4], 200h
mov word ptr es:[43*4+2], 0
mov ah, 4ch
int 21h
int43:
jmp short int43_start
stu_no db '201983300514'
len = $ - stu_no
; display string "welcome to 2049!"
int43_start:
main:
call print_blue_screen
call print_stu_no
iret
print_blue_screen:
push ax ; 儲存現場
push es
push si
mov ax, 0b800h
mov es, ax
mov cx, 2000
mov si, 1
single_blue:
mov byte ptr es:[si], 00010000b
inc si
inc si
loop single_blue
pop si ; 還原現場
pop es
pop ax
ret
print_stu_no:
push ax
push es
push si
push ds
push di
prefix:
mov ax, 0b800h
mov es, ax
mov cx, 34
mov si, 3840 ; si存放每次視訊記憶體輸出的偏移地址
call print_dash
content:
mov ax, cs
mov ds, ax
mov cx, len
mov di, 202h ; di存放data中每個字元的偏移地址
single_no:
mov al, ds:[di]
inc di
mov byte ptr es:[si], al
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_no
postfix:
mov cx, 34
call print_dash
pop di
pop ds
pop si
pop es
pop ax
ret
; 輸入引數:
; 顯示的基地址si
; 輸出長度cx
; 輸出:
; 迭代後的基地址si
print_dash:
single_dash:
mov byte ptr es:[si], '-'
inc si
mov byte ptr es:[si], 00010111b
inc si
loop single_dash
ret
int43_end:
nop
code ends
end start
修改後的task6_2.asm
assume cs:code
code segment
start:
int 43
mov ah, 4ch
int 21h
code ends
end start