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

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

  可以看到add对零标志位有影响,因为溢出一位后剩余位为0。对进位标志位也有影响,因为产生了进位。

  inc对零标志位有影响,因为溢出一位后剩余位为0。对进位标志位没有影响,可见inc产生的进位不会被记录下来。

   
  使用任意文本编辑器,录入8086汇编源码task1.asm。
  task1.asm
 1 assume cs:code, ds:data
 2 
 3 data segment
 4    x dw 1020h, 2240h, 9522h, 5060h, 3359h, 6652h, 2530h, 7031h
 5    y dw 3210h, 5510h, 6066h, 5121h, 8801h, 6210h, 7119h, 3912h
 6 data ends
 7 code segment 
 8 start:
 9     mov ax, data
10     mov ds, ax
11     mov si, offset x
12     mov di, offset y
13     call add128
14 
15     mov ah, 4ch
16     int 21h
17 
18 add128:
19     push ax
20     push cx
21     push si
22     push di
23 
24     sub ax, ax
25 
26     mov cx, 8
27 s:  mov ax, [si]
28     adc ax, [di]
29     mov [si], ax
30 
31     inc si
32     inc si
33     inc di
34     inc di
35     loop s
36 
37     pop di
38     pop si
39     pop cx
40     pop ax
41     ret
42 code ends
43 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指令,能否替换成如下代码?你的结论的依据/理由是什么?
1 add si, 2
2 add di, 2
  若替换成如上代码,仍然可以得到正确答案。因为si与di的范围都在0~16内,对其进行自增运算并不会产生进位,而且样例中每个字的加法均没有产生进位,因此不会影响结果。
  但是逻辑上并不能够将上述代码替换,如果某个字的相加产生了进位,那么计算结果将产生错误。

 

  ② 在debug中调试,观察数据段中做128位加之前,和,加之后,数据段的值的变化。
2. 实验任务2
  使用任意文本编辑器,录入8086汇编源码task2.asm。
  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,实现的功能是?
  ② 汇编指令代码line20-22,实现的功能是?
  ③ 汇编指令代码line24-30,实现的功能是?
 
 ①汇编指令代码line11-18,实现的功能是从键盘输入一个字符并存入数据段偏移地址为si的位置。每输入一个字符si进行自增运算,并无条件跳转到标记s1处,若字符为"#",则标志寄存器CF值为ZR,此时条件指令je指令执行跳转到标记next处。
 
② 汇编指令代码line20-22,实现的功能是输出换行符,换行符的十六进制ASCII码值就是0AH。
 
③ 汇编指令代码line24-30,实现的功能是将数据段中长度为si的字符串输出。

 

  说明:task2.asm中用到的两个DOS系统功能调用:
    DOS系统功能调用int 21h的1号子功能
    功能:从键盘上输入单个字符
    入口参数:(ah) = 1
    出口参数: (al)存放输入字符的ASCⅡ码
    即:
1 mov ah, 1 
2 int 21h     ; (al) <-- 输入字符的ascⅡ码
    DOS系统功能调用int 21h的2号子功能
    功能:输出单个字符到屏幕上
    入口参数:(ah) = 2, (dl) = 待输出的字符或其ascⅡ码
    出口参数:无
    即:
1 mov ah, 2 
2 mov dl, ×× ; ××是待输出的字符,或,其ascⅡ码 
3 int 21h

 

3. 实验任务3
  针对8086CPU,已知逻辑段定义如下:
1 data segment 
2     x dw 91, 792, 8536, 65521, 2021 
3     len equ $ - x 
4 data ends
  编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据之间以空格间隔。
  要求:
    编写子程序printNumber
    功能:以十进制形式输出一个任意位数的整数(整数范围0 ~ 65535)
    入口参数:寄存器ax(待输出的数据 --> ax)
    出口参数:无
  编写子程序printSpace
    功能:打印一个空格
    入口参数:无
    出口参数:无
  在主体代码中,综合应用寻址方式和循环,调用printNumber和printSpace, 实现题目要求。
 1 assume cs:code, ds:data
 2 data segment
 3         x dw 91, 792, 8536, 65521, 2021 
 4         len equ $ - x
 5 data ends
 6 
 7 stack segment
 8         db 16 dup(0)
 9 stack ends
10 
11 code segment
12 start:  
13         mov ax, data
14         mov ds, ax
15 
16         mov cx, 5
17         mov si, offset x
18 s:      mov ax, ds:[si]
19         call printNumber
20         call printSpace
21         inc si
22         inc si
23         loop s
24 
25         mov ah, 4ch
26         int 21h
27 
28 printNumber:
29         mov bx, 0AH     ;除数
30         mov dx, 0       ;高位置为0,记录余数
31         mov di, 0
32         push cx
33  s1:    div bx
34         push dx         ;余数入栈
35         inc di
36         mov dx, 0
37         cmp ax, 0       ;被除数为0时结束
38         je next
39         jmp s1
40 next:   mov ah, 2
41         mov cx, di
42 s2:     pop dx
43         or dl, 30H      ;数字转字符
44         int 21h
45         loop s2
46 
47         pop cx
48         ret
49 
50 printSpace:
51         mov dl, ' '
52         mov ah, 2
53         int 21h
54         ret
55 code ends
56 end start
 

 

4. 实验任务4
  针对8086CPU,已知逻辑段定义如下:
1 data segment 
2     str db "assembly language, it's not difficult but tedious" 
3     len equ $ - str 
4 data ends
  编写8086汇编源程序task4.asm,将data段中字符串里的小写字符转换成大写。
  要求:
  编写子程序strupr
    功能:将包含任意字符的字符串中的小写字母变成大写
    入口参数
      (ds:si ) 字符串首地址的段地址和偏移地址分别送至ds和si
      (cx) 字符串的长度
    出口参数:无
  在主体代码中,设置入口参数,调用strupr, 实现题目要求。
 
 1 assume cs:code, ds:data
 2 data segment 
 3         str db "assembly language, it's not difficult but tedious" 
 4         len equ $ - str 
 5 data ends
 6 
 7 stack segment
 8         db 16 dup(0)
 9 stack ends
10 
11 code segment
12 start:  
13         mov ax, data
14         mov ds, ax
15 
16         mov cx, len
17         mov si, offset str
18         call strupr
19 
20         mov ah, 4ch
21         int 21h
22 strupr:
23 s:      mov al, byte ptr ds:[si]
24         cmp al, 'a'
25         jb next
26         cmp al, 'z'
27         ja next
28 
29         mov ah, 2               ;若是小写字母
30         and al, 11011111b       ;转大写
31         mov dl, al
32         int 21h                 ;输出
33         inc si
34         loop s
35 
36         cmp cx, 0
37         je return
38 
39 next:   mov ah, 2               ;若是其他字符,直接输出
40         mov dl, al
41         int 21h
42         inc si
43         loop s
44 return:
45         ret
46 code ends
47 end start

 

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
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
  对源程序task5.asm进行汇编、链接,得到可执行文件task5.exe。
  运行程序,输入7,观察结果。输入其他字符,观察结果。结合运行结果和注释,理解代码实现的功能。
 
  说明:task5.asm中,使用用到的DOS系统功能调用和BIOS中断例程
    DOS系统功能调用int 21h的1号子功能
    功能:从键盘上输入单个字符
    入口参数:(ah) = 1
    出口参数: (al)存放输入字符的ASCⅡ码
    即:
1 mov ah, 1 
2 int 21h     ; (al) <-- 输入字符的ascⅡ码
    DOS系统功能调用int 21h的9号子功能
    功能:显示字符串
    入口参数:(ah) = 9,(ds:dx) = 字符串的首地址的段地址和偏移地址
    出口参数: 无
    其它要求:字符串必须以$结束
    即:
1 mov ah, 9 
2 mov ds, ××     ; ××是待输出字符串所在段的段地址 
3 mov dx, ××     ; ××是待输出字符串第一个字符的偏移地址 
4 int 21h
    BIOS中断例程int 10h的2号子功能
    功能:设置光标位置
    入口参数:(ah) = 2, (bh) = 页号(默认取0), (dh) = 行号, (dl) = 列号
    出口参数:无
    即:
1 mov ah, 2 
2 mov bh, ××     ; ××是页号 
3 mov dh, ×× 
4 mov dl, ××      ; ××是列号 
5 int 10h

 

   task5重点在于汇编语言分支结构的运用。使用cmp指令以及对零标志寄存器进行判断以及指令跳转。上述结果表示如果输入的字符不为7,则在屏幕指定位置输出no,若为7,则在相同位置输出yes。

 

6. 实验任务6
  实验任务1、2、3、5中使用了不少系统提供的中断例程。本实验任务中,要求自行实现一个42号软中断例程,使得通过 int 42 或 int 2ah 软中断调用,实现在屏幕最下方中间以黑底绿字打印"welcome to 2049!"。
  建议配合教材第12章学习理解并实践。
  task6_1.asm
 1 assume cs:code
 2 
 3 code segment
 4 start:
 5     ; 42 interrupt routine install code
 6     mov ax, cs
 7     mov ds, ax
 8     mov si, offset int42  ; set ds:si
 9 
10     mov ax, 0
11     mov es, ax
12     mov di, 200h        ; set es:di
13 
14     mov cx, offset int42_end - offset int42
15     cld
16     rep movsb
17 
18     ; set IVT(Interrupt Vector Table)
19     mov ax, 0
20     mov es, ax
21     mov word ptr es:[42*4], 200h
22     mov word ptr es:[42*4+2], 0
23 
24     mov ah, 4ch
25     int 21h
26 
27 int42: 
28     jmp short int42_start
29     str db "welcome to 2049!"
30     len equ $ - str
31 
32     ; display string "welcome to 2049!"
33 int42_start:
34     mov ax, cs
35     mov ds, ax
36     mov si, 202h
37 
38     mov ax, 0b800h
39     mov es, ax
40     mov di, 24*160 + 32*2
41 
42     mov cx, len
43 s:  mov al, [si]
44     mov es:[di], al
45     mov byte ptr es:[di+1], 2
46     inc si
47     add di, 2
48     loop s
49 
50     iret
51 int42_end:
52    nop
53 code ends
54 end start
  task6_2.asm 
 1 assume cs:code
 2 
 3 code segment
 4 start:
 5     int 42
 6 
 7     mov ah, 4ch
 8     int 21h
 9 code ends
10 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。 

   软中断是通过执行中断指令产生的,是软件层面对进程的中断,汇编语言的软中断可以理解为高级语言中函数的调用。上述例子中对中断号的自定义可以灵活地执行编程需要的操作。

posted @ 2021-12-07 00:25  喲!這不昰蝕啊?  阅读(229)  评论(3编辑  收藏  举报