实验4 8086标志寄存器及中断

1. 实验任务1

使用任意文本编辑器,录入8086汇编源码task1.asm。
task1.asm

assume cs:code,ds:data
data segment
    db 16 dup(0)
data ends
stack segment
    db 128 dup(0)
    top equ $+1
stack ends
code segment
start:
    mov ax,data
    mov ds,ax
    mov ax,stack
    mov ss,ax
    mov sp,top

    mov ax,0ffffh
    add ax,1
    ;测试add对CF和ZF的影响

    mov ax,1
    add ax,1
    ;恢复测试之前的影响,即无进位

    mov ax,0ffffh
    inc ax
    ;测试inc对CF和ZF的影响
    mov ah,4ch
    int 21h
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中调试程序,并回答问题。

1、line31~line34的4条inc指令,能否替换成如下代码?你的结论的依据/理由是什么?

add si 2
add di 2

更改指令前运算结果如下:

 更改指令后的运算结果如下:

 运算结果一致。

针对本体数据可以替换为改代码。

当需要用到进位制的时候不可用add指令,只能用inc指令。add会对CF标志寄存器造成影响,inc则不会。

如果本来应当是有进位的,CF的值为CY(1),但是做了add操作后CF会变成NC(0),会对后面的位数加法产生影响。所以不能使用add

inc指令并不影标志寄存器CF的值。

2、在debug中调试,观察数据段中做128位加之前,和,加之后,数据段的值的变化。

加之前数据段的值如下:

 

 加之后数据段的值如下:

2. 实验任务2

使用任意文本编辑器,录入8086汇编源码task2.asm。
task2.asm

assume cs:code, ds:data
data segment
        str db 80 dup(?);80个字节未初始化的内存空间
data ends

code segment
start:  
        mov ax, data
        mov ds, ax
        mov si, 0
s1:        
        mov ah, 1;int 21h中断的参数,表示输入单个字符
        int 21h;调用中断例程
        mov [si], al;将结果存入ds:[si]中
        cmp al, '#';与'#'比对,影响标志寄存器ZF,运算结果为0表示相同,则ZF标志寄存器变为ZR
        je next;if(al == '#'(ZF == ZR)) goto next
        inc si;偏移地址加一
        jmp s1;继续输入一个字符
next:
        mov ah, 2;int 21h中断的参数,表示打印一个ASCII字符
        mov dl, 0ah;换行
        int 21h;调用中断例程
        
        mov cx, si;将输入的字符的数量(不包括#)赋给cx寄存器
        mov si, 0;将si寄存器置零
s2:     mov ah, 2;int 21h中断的参数,表示打印一个ASCII字符
        mov dl, [si];将ds:[si]出内存的值赋给dl
        int 21h;调用中断例程
        inc si;偏移地址+1
        loop s2;循环,直到cx=0

        mov ah, 4ch;int 21h中断的参数,表示回到DOS
        int 21h;执行中断例程
code ends
end start

运行结果如下:

1、汇编指令代码line11-18,实现的功能是?

输入字符,将字符存保存在ds:[si]中,字符与‘#’比较,相同则跳转至next子程序,否则继续执行s1
2、汇编指令代码line20-22,实现的功能是?

调用中断程序并换行。
3、汇编指令代码line24-30,实现的功能是?

将输入的字符数量赋给寄存器cx,将ds:[si]的字符保存至显存区域实现字符打印。

3. 实验任务3

 针对8086CPU,已知逻辑段定义如下:

data segment
    x dw 91, 792, 8536, 65521, 2021
    len equ $ - x
data ends

编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据
之间以空格间隔。

assume ds:data,cs:code,ss:stack

data segment
	x dw 91, 792, 8536, 65521, 2021
	len equ $ - x
data ends

stack segment
	dw 8 dup(?)
stack ends

code segment
start:
	mov ax,data
	mov ds,ax
	
	mov ax,stack
	mov ss,ax
	mov sp,16

	mov cx,len/2			;数据是word型,数据个数是len/2 循环次数

	print:	
		mov ax,word ptr ds:[di]	;把数据放入al中
		add di,2
		
		push cx					;cx入栈,保存cx数值,子程序需要使用cx
		
		call printNumber		;调用子程序printNumber,打印字符
		call printSpace			;调用子程序printSpace,打印空格
		
		pop cx					;cx出栈,恢复cx的值
		
	loop print
	
	mov ah,4ch
	int 21h
	
;子程序:printNumber
;功能:打印字符
;入口参数:寄存器ax
printNumber:
	mov bx,0
	;逐位获取数字  getChar子程序:每获取一位,然后压入栈中
	getChar:
		mov bp,10		;除10运算
		mov dx,0
		div bp;			;商在ax中,余数在dx中
		
		push dx			;余数进栈
		inc bx			;位数+1
		
		mov cx,ax		;把商赋给cx
		inc cx
	loop getChar
	
	;打印数字
	mov cx,bx
	printEach:			;逐位打印字符
		pop dx			;取出一位字符
		add dl,30h
		mov ah,2		;调用int 21h的2号子程序打印
		int 21h
	loop printEach
	
	ret
	
printSpace:
	mov ah,2
	mov dl,20h
	int 21h
	ret
code ends
end start

程序运行结果如下:

 

 4. 实验任务4

针对8086CPU,已知逻辑段定义如下:

data segment
    str db "assembly language, it's not difficult but tedious"
    len equ $ - str
data ends

编写8086汇编源程序task4.asm,将data段中字符串里的小写字符转换成大写。

assume cs:code,ds:data
data segment
    str db "assembly language, it's not difficult but tedious"
    len equ $ - str
data ends

stack segment
    db 8 dup(?)
stack ends

code segment
start: 
    mov ax, data
    mov ds, ax
    mov si, 0
    mov cx, len     ; 参数:字符串长度存在cx中
    call strupr     ; 调用转换子程序
    call printStr   ; 调用打印子程序

    mov ax, 4c00h
    int 21h

; 子程序 strupr
;   功能: 将包含任意字符的字符串中的小写字母变成大写
;   入口参数
;       (ds:si) 字符串首地址的段地址和偏移地址分别送至ds和si
;       (cx) 字符串的长度 
strupr:
    push cx
    push si         ; 先保存两个寄存器的值
    transform:
        mov al, ds:[si] ; 取出一个字符
        cmp al, 97      ; 判断ASCII码是否 >= 97
        jl continue     ; 小于97直接进入下次循环
        cmp al, 122     ; 判断ASCII码是否 <= 122
        jg continue     ; 大于122直接进入下次循环
        and al, 0dfh    ; 小写转成大写,原理详见实验2
        mov ds:[si], al ; 把转换后的字符送回data段
    continue:
        inc si          ; 指针后移
        loop transform  ; 循环

    pop si
    pop cx          ; 恢复寄存器的值
    ret             ; 返回

; 子程序 printStr
;   功能: 打印字符串
;   入口参数
;       (ds:si) 字符串首地址的段地址和偏移地址分别送至ds和si
;       (cx) 字符串的长度
printStr:
    push cx         ; 保存寄存器的值
    push si

    print:          ; 打印字符循环
        mov ah, 2
        mov dl, ds:[si]
        int 21h
        inc si
    loop print

    pop si          ; 恢复寄存器的值
    pop cx
    ret             ; 返回

code ends
end start 

程序运行结果如下:

5. 实验任务5

 使用任意文本编辑器,录入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  ;设置显示页为第0页
    mov dh, 24  ;设置光标位置在第24行
    mov dl, 70  ;设置光标位置在第70列
    int 10h

    cmp al, '7'  ;把输入字符和7作比较
    je s1      ;如果相等,跳转到s1处
    mov ah, 9    ;调用int 21h的9号子程序显示str2
    mov dx, offset str2  ;把str2的偏移量放到dx
    int 21h

    jmp over

s1: mov ah, 9        ;调用int 21h的9号子程序显示str1
    mov dx, offset str1  ;把str1的偏移量放入dx
    int 21h          ;显示标号str1处的字符串 yes
over:  
    mov ah, 4ch
    int 21h
code ends
end start

对源程序task5.asm进行汇编、链接,得到可执行文件task5.exe。
运行程序,输入7,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。

程序运行结果如下:

 

 

 6. 实验任务6

本实验任务中,要求自行实现一个42号软中断
例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to
2049!"。

编译、链接task6_1、task6_2后运行得到结果如下

 

 说明42号中断程序被成功调用。

实验总结

1、标志寄存器会被多数指令修改,如add、sub、jmp等,会对CF造成影响。而另一些,如inc不会对CF造成影响。因此在多位计算加法中不能使用add指令。

2、cmp指令会对两个操作数进行减法,然后将结果保存在标志寄存器中,有条件跳转指令则会根据标志寄存器的值进行判断和跳转。

 

posted @ 2021-12-09 20:31  -千-  阅读(30)  评论(4)    收藏  举报