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

四、实验结论

1. 实验任务1

(1)验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。 在debug环境中,分别实践、观察: ① add指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响? ==>add指令对ZF,CF均有影响。 ② inc指令对标志寄存器中的零标志位ZF(Zero Flag)、进位标志位CF(Carry Flag)是否有影响? ==>inc指令对ZF有影响,但对CF无影响。 (2)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  ;将CF进位标志位置为0(NC)

    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

(3)回答问题: line31~line34的4条inc指令,能否替换成如下代码?你的结论的依据/理由是什么?

add si, 2
add di, 2

==>不能。因为add指令会修改CF的值。 而inc指令却不会修改CF的值(不影响CF标志位的有2个:inc和dec) (4)在debug中调试,观察数据段中做128位加之前和加之后,数据段的值的变化。给出调试观察截 图。 ①.inc指令的结果——128位加有效,数据段的值成功正确相加。 实验4 8086标志寄存器及中断 ②.add指令:结果不正确(因为CF进位标志位被错误修改) 实验4 8086标志寄存器及中断

2. 实验任务2

(1)程序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

(2)运行测试截图: 实验4 8086标志寄存器及中断

(3)回答问题 运行程序,从键盘上输入一串字符,以#结束(比如,输入George Orwell, 1984#),观察结 果。结合运行结果,理解代码并回答问题: ① 汇编指令代码line11-18,实现的功能是?

s1:    
    mov ah, 1   ;调用int 21h的1号子功能
    int 21h   ;从键盘上输入单个字符
    mov [si], al
    cmp al, '#' ;将输入的字符与‘#’比较
    je next  ;若相等,则跳转到next
    inc si  ;否则si+1
    jmp s1  ;继续回到s1输入下一个字符

==>功能:一个一个输入字符直到#结束

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

 mov ah, 2  ;调用int 21h的2号子功能
 mov dl, 0ah ; 0ah是换行符的ascii码值
 int 21h ;输出单个字符到屏幕上

==>功能:打印一个换行符

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

 mov cx, si  ;si中存放了输入字符的个数(从0开始,因此不包括#)
 mov si, 0  ;将si置为0,从头开始
s2:   mov ah, 2 ;调用int 21h的2号子功能
    mov dl, [si] ;一个一个输出,(dl) = 待输出的字符或其ascii码
    int 21h ;输出单个字符到屏幕上
    inc si ;继续下一个
    loop s2 ;回s2遍历,直到输入字符全部输出完

3. 实验任务3

(1)task3.asm源码:

assume cs:code,ds:data,ss:stack
data segment
x dw 91, 792, 8536, 65521, 2021  ;0 1 2 3 4
len equ $ - x  ;$指下一个数据项的偏移地址=5
data ends

stack segment
db 16 dup('0')
stack ends

code segment
start:
mov ax,data
mov ds,ax  ;送data
mov ax,stack
mov ss,ax
mov sp,16  ;设置ss:sp

mov si,offset x
mov cx,5 ;5个数,执行5次循环
print:
push cx ;将cx存入栈,防止后续冲突
mov cx,0 ;重置cx=0
mov ax,ds:[si]
call printNumber
call printSpace
pop cx ;取出原来的cx
inc si
inc si
loop print

mov ah,4ch
int 21h

;子程序:printNumber
;功能:以十进制形式输出一个任意位数的整数(整数范围0 ~ 65535)
printNumber:
mov dx,0 ;余数先初始为0
mov bx,10 ;除10
div bx  ;把十进制除以10,商数存在ax中
inc cx ;位数+1
push dx  ;把分离出来的余数先保存在栈
mov dx,0 ;余数重置为0
cmp ax,0 ;ax存放的是商,当商=0时除法结束
je s1  ;跳转到s1输出
jmp printNumber  ;否则继续除

s1:
mov ah,2
pop dx
or dl,30h ;将其转为相对应的ascii码
int 21h ;调用2号子功能输出该字符
loop s1
ret

;子程序:printSpace
;功能:打印一个空格
printSpace:
mov ah,2
mov dl,' '
int 21h
ret

code ends
end start

(2)运行测试截图: 实验4 8086标志寄存器及中断

4. 实验任务4

(1)task4.asm源码:

assume cs:code,ds:data
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,ds:[si]  ;从str中取出一个字符

cmp al,'a' ;与'a'的ascii码进行比较
jb print ;比'a'的ascii码值小,不是字母直接打印
cmp al,'z' ;与'z'的ascii码进行比较
ja print ;比'z'的ascii码值大,不是字符直接打印

mov ah,2
and al,11011111b ;大写字母2进制时从左开始第三位一定是0
mov dl,al ;将转换好的大写字母字符送到dl
int 21h  ;调用2号子功能打印字符
inc si  ;si+1,继续下一个
loop s
ret

;直接输出不是字母的字符
print:
mov ah,2
mov dl,al  ;dl中为待输出的字符
int 21h  ;调用2号子功能输出
inc si  
loop s ;继续下一个字符

code ends
end start

(2)在debug中调试截图( call strupr 调用之前,数据段的值,以及,调用之后,数据段的值) ①.运行结果: 实验4 8086标志寄存器及中断 ②.call strupr调用之前数据段的值: 实验4 8086标志寄存器及中断 ③.调用之后,数据段的值: 实验4 8086标志寄存器及中断

5. 实验任务5

(1)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   ;若相等,跳转到s1
    mov ah, 9  ;调用9号子功能:显示字符串
    mov dx, offset str2
    int 21h ;显示'no'

    jmp over ;跳转到over处结束程序

s1: mov ah, 9 ;调用9号子功能:显示字符串
    mov dx, offset str1
    int 21h ;显示'yes'
over:  
    mov ah, 4ch
    int 21h
code ends
end start

注:

;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

(2)程序运行测试截图(输入7,以及输入其他字符,运行结果截图) ①.输入7的情况: 实验4 8086标志寄存器及中断 ②.输入其他字符的情况: 实验4 8086标志寄存器及中断

(3)程序的功能是? 功能:从键盘输入一个字符,如果为'7',则在指定的24行,70列输出'yes';否则在指定位置输出'no'。

6. 实验任务6

(1)代码: 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

(2)结果: 实验4 8086标志寄存器及中断 ==>编译链接以后,如图,屏幕底部输出了'welcome to 2049!',表示自己实现的42号软中断被成功调用。

(3)通过此项实现任务,你对中断、软中断实现机制的理解: ①.由书上可知iret指令作用: 实验4 8086标志寄存器及中断 ②.中断的过程其实很容易理解,概括的说就是CPU自己完成以下操作: a.取得中断类型码N; b.pushf, 标志寄存器压栈; c.设置标志为TF=0,IF=0; d.push CS,将CS压栈; e.push IP,将IP压栈; f.设置IP,CS为中断向量表存放的地址,也就是使(IP) = (N4),(CS) = (N4+2)。

③.至于编写中断处理程序,和编写普通的子程序没有多大区别: a.保存用到的寄存器 b.处理中断 c.恢复寄存器 d.iret 返回 其中,iret 指令相当于先retf ,然后popf。

上一篇:实验4 8086标志寄存器及中断


下一篇:量水问题的进一步学习