汇编语言第四次实验

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

1. 实验任务1

验证性实验:有些汇编指令会影响到标志寄存器中的一个或多个状态标志位。

在debug环境中,分别实践、观察:

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

image-20211210103204469

答:有影响,因为FF + 1 后结果为0,则ZF标志位为ZR。因为FF + 1后产生了进位,CF的值为CY。

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

image-20211210103228545

答:对ZF标志有影响,得到结果为0,ZF的值为ZR。对CF标志无影响,CF标志仍然是NC。

使用任意文本编辑器,录入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中调试程序,并回答问题。

程序执行效果截图:

image-20211210110051908

若使用

add si, 2
add di, 2

则结果不一定正确,因为add指令会对CF产生影响,而adc指令是进位加法。当add指令对CF产生影响后,必然对adc指令产生影响,导致结果出错。

2. 实验任务2

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

1 assume cs:code, ds:data
2 data segment
3         str db 80 dup(?)
4 data ends
5 
6 code segment
7 start:  
8         mov ax, data
9         mov ds, ax
10         mov si, 0
11 s1:        
12         mov ah, 1
13         int 21h
14         mov [si], al
15         cmp al, '#'
16         je next
17         inc si
18         jmp s1
19 next:
20         mov ah, 2
21         mov dl, 0ah
22         int 21h
23         
24         mov cx, si
25         mov si, 0
26 s2:     mov ah, 2
27         mov dl, [si]
28         int 21h
29         inc si
30         loop s2
31 
32         mov ah, 4ch
33         int 21h
34 code ends
35 end start

对源程序task2.asm进行汇编、链接,得到可执行文件task2.exe。

运行程序,从键盘上输入一串字符,以#结束(比如,输入George Orwell, 1984#),观察结果。结合运

行结果,理解代码并回答问题:

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

s1部分的功能为:

​ 读入键盘输入的字符,并将它们呈现在屏幕上,并将每个字符与“#”作比较,若等于“#”将跳转到next。

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

next部分的功能为:

​ 将输出模式调整为输出dl中的值,0ah表示的值为创建新行。将si的值赋给cx,作为循环次数,将si置为0,表示回到字符串首位。

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

s2部分的功能为:

​ 将si作为地址指向的值,存入dl中,逐个输出。

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

结果截图:

image-20211210145615362

CODE:

assume cs:code, ds:data
data segment
	x dw 91, 792, 8536, 65521, 2021 
	len equ $ - x 
data ends
code segment
start:  
    mov ax, data
    mov ds, ax

    mov cx, 5
    mov si, 0
s:  mov ax,0    

    call printNumber
    call printSpace   
    add si,2 
    loop s    
    mov ah, 4ch
    int 21h
printNumber:
    push cx;保存cx的值
    mov cx,0    
    mov ax, ds:[si]
s1: 
    mov dx,0
    mov bx, 10
    div bx
    push dx
    inc cx;出栈的cx的值
    cmp ax,0
    jne s1

    mov ah,2

s2: pop dx
    or dx,30h;取ASCII码
    int 21h
    loop s2

    pop cx;归还cx的值
    ret
printSpace: 
    mov ah, 2
    mov dl, ' '
    int 21h
    ret
code ends
end start

​ 大致思路:针对每一个数字,如实验3那样,需要分解出每一位数字,使用到16位的除法。每次除完将数字存入栈中,保证输出为正常顺序。

注意点:

  • cx的值在进入内循环之前要保存到栈中,最后还要出栈归还cx的值。
  • 将除完的余数保存到栈中保证是正常的输出顺序。

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

程序效果截图:

image-20211210160343045

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 si,0
    mov cx,len
    call strupr
    inc si
    mov ah, 4ch
    int 21h
strupr: 
    mov byte ptr al,ds:[si]    
    cmp al,'a'
    jb s1
    cmp al,'z'
    ja s1
    and al,11011111b
s1:   
    push ax
    mov ah, 2
    pop dx
    int 21h
    inc si
    loop strupr
    ret
code ends
end start

​ 大致思路:如果是字母,则与上11011111b,再输出。不是则直接跳到输出。

5. 实验任务5

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

task5.asm

1 assume cs:code, ds:data
2 
3 data segment
4     str1 db "yes", '$'
5     str2 db "no", '$'
6 data ends
7 
8 code segment
9 start:
10     mov ax, data
11     mov ds, ax
12     ;输入
13     mov ah, 1
14     int 21h
15 
16     mov ah, 2
17     mov bh, 0;页号
18     mov dh, 24;行号
19     mov dl, 70;列号
20     int 10h
21 
22     cmp al, '7'
23     je s1
24     mov ah, 9
25     mov dx, offset str2;输出字符串的首字符的偏移地址,(已经设置过ds)
26     int 21h
27 
28     jmp over
29 
30 s1: mov ah, 9
31     mov dx, offset str1
32     int 21h
33 over:  
34     mov ah, 4ch
35     int 21h
36 code ends
37 end start

​ 功能:判断输入字符是否等于7。

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

    mov ah, 4ch
    int 21h
code ends
end start

中断

​ 当计算机内部发生中断时:

  1. 根据中断信息获得中断类型码N
  2. 标志寄存器的值入栈
  3. 设置标志寄存器TF和IF为0(防止CPU执行中断程序时发生单步中断)
  4. push CS,push IP
  5. 将IP设为(N * 4),CS设为(N * 4 + 2)

编写中断程序:

  1. 将中断程序安装到相应位置
  2. 将程序位置安装到中断向量表中
  3. 书写中断程序

效果截图:

image-20211215215534612

程序分析:

​ 首先安装中断程序,即将写好的中断程序安装至0000:0200的地址。再将该中断程序的段地址和偏移地址,注册到es:[42 * 4]和es:[42 * 4 + 2]的位置(因为中断指令是42)。

​ int42部分 :表示的就是将“welcome to 2049”显示在桌面上。

posted @ 2021-12-15 22:15  1024=0  阅读(251)  评论(3)    收藏  举报