1. 程式人生 > 其它 >【實驗四】8086標誌暫存器及中斷

【實驗四】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