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

Posted on 2021-12-07 17:43  小陶要努力  阅读(224)  评论(0编辑  收藏  举报

一、实验目的

1. 理解标志寄存器用途,理解常用标志位CF, ZF, OF, SF, TF, IF的用途和意义。
2. 理解条件转移指令je, jz, ja, jb, jg, jl等的跳转原理,掌握组合使用汇编指令cmp和条件转移指令实现
分支和循环的用法
3. 了解软中断指令的用法,体验和理解中断原理
4. 综合应用寻址方式和汇编指令完成简单应用编程

二、实验准备
复习教材「第10章 call和ret指令」、「第11章 标志寄存器」
学习教材「第12章 内中断 」、「第13章 int指令」三、实验内容

三、实验内容
1. 实验任务1
验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。
在debug环境中,分别实践、观察:
① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
答:add指令对ZF、CF都有影响
 
② inc指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?
答:inc指令对ZF有影响,但是对CF没有影响
因为指令系统设计人员考虑该指令主要用于对指针(即地址)进行增加,不存在进位问题,所以没有设计让INC影响进位标志CF,其原因是由硬件原因导致的

使用任意文本编辑器,录入8086汇编源码task1.asm。
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实现对标号xy处存储的两个128位数据相加,结果保存在x处的连续128个字
节中。
 
① line31~line34的4条inc指令,能否替换成如下代码?你的结论的依据/理由是什么?
add si, 2 
add di, 2
答:替换后的内存情况

 

替换后的结果与原代码得到的结果相同

逻辑上不能替换
根据之前的结论,inc指令不会影响指令寄存器中的CF,同时代码中用到了adc指令,adc ax,bx 实现的功能是:(ax)=(ax)+(bx)+CF
如果替换成add,CF受到影响,adc指令语句的结果也会受到影响。
但事实上该代码si,di的范围都在0-16,并且在自增的过程中没有发生进位,所以对CF没有影响

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

 加之后:

 

 

2. 实验任务2
使用任意文本编辑器,录入8086汇编源码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 21h1号子功能
功能:从键盘上输入单个字符
入口参数:(ah) = 1
出口参数: (al)存放输入字符的ASCⅡ码
即:
mov ah, 1 
int 21h ; (al) <-- 输入字符的ascⅡ码 

 

DOS系统功能调用int 21h2号子功能
功能:输出单个字符到屏幕上
入口参数:(ah) = 2, (dl) = 待输出的字符或其ascⅡ码
出口参数:无
即:
mov ah, 2 
mov dl, ×× ; ××是待输出的字符,或,其ascⅡ码 
int 21h

 

代码运行结果:

代码换行后输出

① 汇编指令代码line11-18,实现的功能是?
答:line11-18的功能是实现字符的输入,直到遇到终止符#停止,如果没有遇到#则一直输入
 
② 汇编指令代码line20-22,实现的功能是?
答:mov dl, 0ah对应的ASCII码为换行符,所以实现的功能是换行
 
③ 汇编指令代码line24-30,实现的功能是?
答:实现的功能是循环输出输入的字符
 

3. 实验任务3
针对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
data ends
 
stack segment
    db 16 dup(0)
stack ends

code segment
    start:     
        mov ax, data
        mov ds, ax
        
        mov cx, 5
        mov si, 0
    print:
        mov ax, ds:[si]
        call printNumber
        call printSpace
        inc si
        inc si
        loop print
 
        mov ah, 4ch
        int 21h

    printNumber:
        mov bl, 10       ;除数10
        mov dx, 0        ;记录余数
        mov di, 0
        push cx
     s1:    div bx
        push dx          ;存储余数
        inc di
        mov dx, 0
        cmp ax, 0        ;被除数为0结束
         je s2
        jmp s1

    s2:    mov ah, 2
        mov cx, di
    s3:    pop dx         ;余数出栈
        or dl, 30h        ;数字转字符    
        int 21h
        loop s3

        pop cx
        ret
             
    printSpace:
        mov ah, 2
        mov dl, ' '
        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段中字符串里的小写字符转换成大写。
要求:
编写子程序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
start:
    mov ax, data
    mov ds, ax
    mov cx, len
    mov si, 0
    call strupr

    mov ah, 4ch
    int 21h
strupr:
s:    mov al, byte ptr ds:[si]
    cmp al, 'a'
    jb print
    cmp al, 'z'            ;如果是字母才转大写,不是字母直接输出
    ja print
    
    mov ah, 2
    and al, 11011111b        ;转大写
    mov dl, al
    int 21h
    inc si 
    loop s

    ret

print:    
  mov ah,
2   mov dl, al
  int 21h   inc si   loop s 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 
    mov dh, 24 ; 设置光标位置在第24行 
    mov dl, 70 ; 设置光标位置在第70列 
    int 10h ; 设置光标位置 

    cmp al, '7' 
    je s1 
    mov ah, 9 
    mov dx, offset str2 
    int 21h ; 显示标号str2处的字符串 

    jmp over 

s1: mov ah, 9 
    mov dx, offset str1 
    int 21h ; 显示标号str2处的字符串 
over:mov ah, 4ch 
    int 21h 
code ends 
end start
对源程序task5.asm进行汇编、链接,得到可执行文件task5.exe。
运行程序,输入7,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。
 
DOS系统功能调用int 21h9号子功能
功能:显示字符串
入口参数:(ah) = 9(ds:dx) = 字符串的首地址的段地址和偏移地址
出口参数:
其它要求:字符串必须以$结束
mov ah, 9 
mov ds, ×× ; ××是待输出字符串所在段的段地址 
mov dx, ×× ; ××是待输出字符串第一个字符的偏移地址 
int 21h

BIOS中断例程int 10h2号子功能
功能:设置光标位置
入口参数:(ah) = 2, (bh) = 页号(默认取0), (dh) = 行号, (dl) = 列号
出口参数:无
即:
mov ah, 2 
mov bh, ×× ; ××是页号 
mov dh, ××
mov dl, ×× ; ××是列号 
int 10h

 

输入不为7的数字

 

输入数字为7

 

该程序的作用是当输入为7时,则在规定页号、行号、列号输出yes,程序结束

当输入不为7时,则在相同的位置输出no,程序结束


6. 实验任务6
实验任务1、2、3、5中使用了不少系统提供的中断例程。本实验任务中,要求自行实现一个42号软中断
例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to
2049!"。
建议配合教材第12章学习理解并实践。

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 ; 调用自己实现的42号软中断 
    
    mov ah, 4ch 
    int 21h 
code ends 
end start

 

程序运行结果:

 

屏幕底部输出了welcome to 2049!

表示42号中断被成功执行

 

总结与思考

 

1.cmp命令是比较指令,功能相当于做减法,只是不保存结果,cmp指令执行后,对标志寄存器产生影响,ja、jb等指令是通过检测相关标志位,进行跳转

2.标志寄存器受到多种指令的影响,而自增指令inc不影响CF,但add指令却会。

3.基本上,CPU在执行完一条指令后,如果检测到标志寄存器的TF位为1,则产生单步中断,引发中断过程。

4.iret指令执行之后,CPU回到执行中断处理程序前的执行点继续执行程序。

 

Copyright © 2024 小陶要努力
Powered by .NET 8.0 on Kubernetes