【实验四】8086标志寄存器及中断

目录

任务一

验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。
在debug环境中,分别实践、观察:

① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?

【实验四】8086标志寄存器及中断

② inc指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?

【实验四】8086标志寄存器及中断

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位加之前,和,加之后,数据段的值的变化。

加之前:

【实验四】8086标志寄存器及中断

加之后:

【实验四】8086标志寄存器及中断

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#),观察结果。结合运行结果,理解代码并回答问题:

【实验四】8086标志寄存器及中断

① 汇编指令代码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, 实现题目要求。

    【实验四】8086标志寄存器及中断

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, 实现题目要求。

【实验四】8086标志寄存器及中断

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,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能 .

【实验四】8086标志寄存器及中断

代码功能: 输入字符为'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。

【实验四】8086标志寄存器及中断

自定义43号中断:

中断执行程序即为 实验三 任务五 : 打印蓝屏 && 输出学号

【实验四】8086标志寄存器及中断

修改后的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
上一篇:调用webservice 设置超时时间


下一篇:Spring框架源码分析