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

一、 实验任务1

验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。
在debug环境中,分别实践、观察:
① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响?

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

 inc指令对ZF有影响,但是对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实现对标号x和y处存储的两个128位数据相加,结果保存在x处的连续128个字
节中。
对程序进行汇编、链接,得到可执行程序task1.exe。在debug中调试程序,并回答问题。
① line31~line34的4条inc指令,能否替换成如下代码?你的结论的依据/理由是什么?

add si, 2
add di, 2

  替换后的结果与原代码得到的结果相同,但是不能替换,因为使用add会导致进位寄存器CF的值发生变化。

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

 

 

 

    可以观察到正确的求和结果。

 

二、 实验任务2
使用任意文本编辑器,录入8086汇编源码task2.asm。
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进行汇编、链接,得到可执行文件task2.exe。
运行程序,从键盘上输入一串字符,以#结束(比如,输入George Orwell, 1984#),观察结果。结合运
行结果,理解代码并回答问题:
① 汇编指令代码line11-18,实现的功能是?

分析:

s1:        
        mov ah, 1       ; 调用int 21h的1号子程序
        int 21h         ; 从键盘接收输入
        mov [si], al    ; 把输入的字符放入 ds:[si]
        cmp al, '#'     ; 判断接收到的字符是否是# 
        je next         ; 如果是'#',执行next处操作
        inc si          ; 否则si + 1
        jmp s1          ; 返回s1继续读入下一个字符

得出结论:从键盘上读取输入的字符,并保存到ds:[si],以#作为是否输入完成的判断标志,每读入一个就判断是否为#,如果是则不保存,转跳至标号next处执行;如果不是则si + 1并继续读入下一个字符。

② 汇编指令代码line20-22,实现的功能是?

分析:

	mov ah, 2       ; 调用
  mov dl, 0ah     ; 0ah是换行符回车的ASCII码
  int 21h         ; 打印一个换行符

得出结论:打印一个换行符。

③ 汇编指令代码line24-30,实现的功能是?

分析:

		mov cx, si      ; 由于si从0开始,si = 读入的字符个数-1,正好不会把'#'打印出来
    mov si, 0       ; si回到字符串开始的位置
s2: mov ah, 2       ; 调用int 21h的2号子程序
    mov dl, [si]    ; 打印字符
    int 21h         
    inc si                  
    loop s2         ; 打印字符串循环

得出结论:打印字符串,遇到#就跳过。


说明:task2.asm中用到的两个DOS系统功能调用:
DOS系统功能调用int 21h的1号子功能

功能:从键盘上输入单个字符
入口参数:(ah) = 1
出口参数: (al)存放输入字符的ASCⅡ码
即:

mov ah, 1
int 21h ; (al) <-- 输入字符的ascⅡ码

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

mov ah, 2
mov dl, ×× ; ××是待输出的字符,或,其ascⅡ码
int 21h

 

三、实验任务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, 实现题目要求。
正确编写后,预期测试结果如下:

 

提示:
题目限定了数据范围是0 ~ 65535, 可以借助32÷16位的除法,无需考虑除法溢出问题。具体地:
1. 被除数 -> dx:ax,由于数据不超过65535,所以,每次寻址取数-> ax后,在子程序printNumber中做
除法时,dx设置为0即可。
2. 除以10,得到余数后,入栈并计数。重复这一过程,直至商为0。然后,循环出栈,并借助int 21h中
的2号子功能,实现输出。
3. 注意事项:① 数字和数字字符的区别,及,必要转换;② 寄存器使用冲突问题,可借助栈解决。具体
地,如内容不熟悉,请复习第10章

完整代码:

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

data segment
    x dw 91, 792, 8536, 65535, 2021, 0
    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 
    print:
        mov ax, word ptr ds:[di]    
        add di, 2                   

        push cx             

        call printNumber   
        call printSpace     

        pop cx             
    loop print
    
    mov ah, 4ch
    int 21h

printNumber:
    mov bx, 0       

    getEach:

        mov bp, 10     
        mov dx, 0           
        div bp        

        push dx        
        inc bx          
        
        mov cx, ax      
        inc cx          

    loop getEach

    mov cx, bx         
    printEach:
        pop dx          
        add dl, 30h    
        mov ah, 2       
        int 21h
    loop printEach 

    ret

printSpace:
    mov ah, 2
    mov dl, 20h
    int 21h
    ret

code ends
end start

 编译链接运行结果:

 

 

 

四、 实验任务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
使用任意文本编辑器,录入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,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。
说明: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

运行task5.exe输入7 

 

 屏幕上倒数第2行右下角显示'yes'的字样

 

 输入其他字符 ,屏幕上倒数第2行右下角显示'no'的字样

 

六、 实验任务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

对汇编源程序task6_1.asm进行汇编、链接,得到可执行程序task6_1.exe。运行task6_1.exe,实现将
42号中断处理程序安装到0:200开始的连续内存空间,并设置中断向量表,使得将来通过 int 42 ,系统
可以跳转到中断处理程序。
对汇编源程序task6_2.asm进行汇编、链接,得到可执行程序task6_2.exe。运行task6_2.exe。
两个程序正确编写、汇编、链接,运行后,预期结果如下:

通过此项实现任务,你对中断、软中断的理解
自己选一个未被使用的中断码,实现一个中断例程,并调用测试。给出源码和运行测试截图。(选做
*)
8086一共提供了256个中断,中断码为0~255,其中,有些保留作为系统用,有些未使用。可以自
行挑选一个未被使用的中断码,程时自己编写中断例程。

28H ~ 2EH DOS保留用(实验任务6中,使用的是42号中断码,即2AH)
30H ~ 3FH DOS保留用
60H ~ 6FH 用户保留
F1 ~ FFH 未使用

 

 

 通过编译连接运行task6_1.asmtask6_2.asm后可以看到,屏幕底部出现了绿色的"welcome to 2049!",说明42号中断程序被成功调用。

 

七、总结

1.cmp指令会对两个操作数做减法,然后将结果存在标志寄存器中,有条件跳转指令则会根据标志寄存器的值进行判断并跳转;

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

3.内中断程序可以使CPU在执行到特殊情况时调用,中断处理程序可以让CPU从错误中恢复。

posted @ 2021-12-13 18:08  流年h  阅读(27)  评论(2编辑  收藏  举报