1. 實驗任務1
驗證性實驗:有些匯編指令會影響到標志寄存器中的一個或多個狀態標志位。
在debug環境中,分別實踐、觀察:
① add指令對標志寄存器中的零標志位ZF(Zero Flag)、進位標志位CF(Carry Flag)是否有影響?
② inc指令對標志寄存器中的零標志位ZF(Zero Flag)、進位標志位CF(Carry Flag)是否有影響?

可以看到add對零標志位有影響,因為溢出一位后剩余位為0。對進位標志位也有影響,因為產生了進位。
inc對零標志位有影響,因為溢出一位后剩余位為0。對進位標志位沒有影響,可見inc產生的進位不會被記錄下來。
使用任意文本編輯器,錄入8086匯編源碼task1.asm。
task1.asm
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
其中:
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指令,能否替換成如下代碼?你的結論的依據/理由是什么?
1 add si, 2 2 add di, 2
若替換成如上代碼,仍然可以得到正確答案。因為si與di的范圍都在0~16內,對其進行自增運算並不會產生進位,而且樣例中每個字的加法均沒有產生進位,因此不會影響結果。
但是邏輯上並不能夠將上述代碼替換,如果某個字的相加產生了進位,那么計算結果將產生錯誤。

② 在debug中調試,觀察數據段中做128位加之前,和,加之后,數據段的值的變化。

2. 實驗任務2
使用任意文本編輯器,錄入8086匯編源碼task2.asm。
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
對源程序task2.asm進行匯編、鏈接,得到可執行文件task2.exe。
運行程序,從鍵盤上輸入一串字符,以#結束(比如,輸入George Orwell, 1984#),觀察結果。結合運行結果,理解代碼並回答問題:
① 匯編指令代碼line11-18,實現的功能是?
② 匯編指令代碼line20-22,實現的功能是?
③ 匯編指令代碼line24-30,實現的功能是?
①匯編指令代碼line11-18,實現的功能是從鍵盤輸入一個字符並存入數據段偏移地址為si的位置。每輸入一個字符si進行自增運算,並無條件跳轉到標記s1處,若字符為"#",則標志寄存器CF值為ZR,此時條件指令je指令執行跳轉到標記next處。
② 匯編指令代碼line20-22,實現的功能是輸出換行符,換行符的十六進制ASCII碼值就是0AH。
③ 匯編指令代碼line24-30,實現的功能是將數據段中長度為si的字符串輸出。

說明:task2.asm中用到的兩個DOS系統功能調用:
DOS系統功能調用int 21h的1號子功能
功能:從鍵盤上輸入單個字符
入口參數:(ah) = 1
出口參數: (al)存放輸入字符的ASCⅡ碼
即:
1 mov ah, 1 2 int 21h ; (al) <-- 輸入字符的ascⅡ碼
DOS系統功能調用int 21h的2號子功能
功能:輸出單個字符到屏幕上
入口參數:(ah) = 2, (dl) = 待輸出的字符或其ascⅡ碼
出口參數:無
即:
1 mov ah, 2 2 mov dl, ×× ; ××是待輸出的字符,或,其ascⅡ碼 3 int 21h
3. 實驗任務3
針對8086CPU,已知邏輯段定義如下:
1 data segment 2 x dw 91, 792, 8536, 65521, 2021 3 len equ $ - x 4 data ends
編寫8086匯編源程序task3.asm,在屏幕上以十進制形式輸出data段中這一組連續的數據,數據和數據之間以空格間隔。
要求:
編寫子程序printNumber
功能:以十進制形式輸出一個任意位數的整數(整數范圍0 ~ 65535)
入口參數:寄存器ax(待輸出的數據 --> ax)
出口參數:無
編寫子程序printSpace
功能:打印一個空格
入口參數:無
出口參數:無
在主體代碼中,綜合應用尋址方式和循環,調用printNumber和printSpace, 實現題目要求。
1 assume cs:code, ds:data 2 data segment 3 x dw 91, 792, 8536, 65521, 2021 4 len equ $ - x 5 data ends 6 7 stack segment 8 db 16 dup(0) 9 stack ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov cx, 5 17 mov si, offset x 18 s: mov ax, ds:[si] 19 call printNumber 20 call printSpace 21 inc si 22 inc si 23 loop s 24 25 mov ah, 4ch 26 int 21h 27 28 printNumber: 29 mov bx, 0AH ;除數 30 mov dx, 0 ;高位置為0,記錄余數 31 mov di, 0 32 push cx 33 s1: div bx 34 push dx ;余數入棧 35 inc di 36 mov dx, 0 37 cmp ax, 0 ;被除數為0時結束 38 je next 39 jmp s1 40 next: mov ah, 2 41 mov cx, di 42 s2: pop dx 43 or dl, 30H ;數字轉字符 44 int 21h 45 loop s2 46 47 pop cx 48 ret 49 50 printSpace: 51 mov dl, ' ' 52 mov ah, 2 53 int 21h 54 ret 55 code ends 56 end start

4. 實驗任務4
針對8086CPU,已知邏輯段定義如下:
1 data segment 2 str db "assembly language, it's not difficult but tedious" 3 len equ $ - str 4 data ends
編寫8086匯編源程序task4.asm,將data段中字符串里的小寫字符轉換成大寫。
要求:
編寫子程序strupr
功能:將包含任意字符的字符串中的小寫字母變成大寫
入口參數
(ds:si ) 字符串首地址的段地址和偏移地址分別送至ds和si
(cx) 字符串的長度
出口參數:無
在主體代碼中,設置入口參數,調用strupr, 實現題目要求。
1 assume cs:code, ds:data 2 data segment 3 str db "assembly language, it's not difficult but tedious" 4 len equ $ - str 5 data ends 6 7 stack segment 8 db 16 dup(0) 9 stack ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov cx, len 17 mov si, offset str 18 call strupr 19 20 mov ah, 4ch 21 int 21h 22 strupr: 23 s: mov al, byte ptr ds:[si] 24 cmp al, 'a' 25 jb next 26 cmp al, 'z' 27 ja next 28 29 mov ah, 2 ;若是小寫字母 30 and al, 11011111b ;轉大寫 31 mov dl, al 32 int 21h ;輸出 33 inc si 34 loop s 35 36 cmp cx, 0 37 je return 38 39 next: mov ah, 2 ;若是其他字符,直接輸出 40 mov dl, al 41 int 21h 42 inc si 43 loop s 44 return: 45 ret 46 code ends 47 end start
5. 實驗任務5
使用任意文本編輯器,錄入8086匯編源碼task5.asm。
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
對源程序task5.asm進行匯編、鏈接,得到可執行文件task5.exe。
運行程序,輸入7,觀察結果。輸入其他字符,觀察結果。結合運行結果和注釋,理解代碼實現的功能。
說明:task5.asm中,使用用到的DOS系統功能調用和BIOS中斷例程
DOS系統功能調用int 21h的1號子功能
功能:從鍵盤上輸入單個字符
入口參數:(ah) = 1
出口參數: (al)存放輸入字符的ASCⅡ碼
即:
1 mov ah, 1 2 int 21h ; (al) <-- 輸入字符的ascⅡ碼
DOS系統功能調用int 21h的9號子功能
功能:顯示字符串
入口參數:(ah) = 9,(ds:dx) = 字符串的首地址的段地址和偏移地址
出口參數: 無
其它要求:字符串必須以$結束
即:
1 mov ah, 9 2 mov ds, ×× ; ××是待輸出字符串所在段的段地址 3 mov dx, ×× ; ××是待輸出字符串第一個字符的偏移地址 4 int 21h
BIOS中斷例程int 10h的2號子功能
功能:設置光標位置
入口參數:(ah) = 2, (bh) = 頁號(默認取0), (dh) = 行號, (dl) = 列號
出口參數:無
即:
1 mov ah, 2 2 mov bh, ×× ; ××是頁號 3 mov dh, ×× 4 mov dl, ×× ; ××是列號 5 int 10h
task5重點在於匯編語言分支結構的運用。使用cmp指令以及對零標志寄存器進行判斷以及指令跳轉。上述結果表示如果輸入的字符不為7,則在屏幕指定位置輸出no,若為7,則在相同位置輸出yes。
6. 實驗任務6
實驗任務1、2、3、5中使用了不少系統提供的中斷例程。本實驗任務中,要求自行實現一個42號軟中斷例程,使得通過 int 42 或 int 2ah 軟中斷調用,實現在屏幕最下方中間以黑底綠字打印"welcome to 2049!"。
建議配合教材第12章學習理解並實踐。
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_1.exe。運行task6_1.exe,實現將42號中斷處理程序安裝到0:200開始的連續內存空間,並設置中斷向量表,使得將來通過 int 42 ,系統可以跳轉到中斷處理程序。
對匯編源程序task6_2.asm進行匯編、鏈接,得到可執行程序task6_2.exe。運行task6_2.exe。

軟中斷是通過執行中斷指令產生的,是軟件層面對進程的中斷,匯編語言的軟中斷可以理解為高級語言中函數的調用。上述例子中對中斷號的自定義可以靈活地執行編程需要的操作。