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

任务1

 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     ; add si,2
36     ; add di,2
37     
38     loop s
39 
40     pop di
41     pop si
42     pop cx
43     pop ax
44     ret
45 code ends
46 end start

 

 

 这是源程序运行得到的结果,因为用的是adc,所以进位也参与了运算,所以得到的是正确的128位数的加法

 

 

 然后这张图告诉我们,add会影响zf和cf,而cf会影响adc指令执行正确与否。

inc并不会影响cf,不用担心后面影响到adc

所以我们不能把inc改成add

 

 

任务2

 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

 

line11-18:

 

 dos的1号调用,对于输入的字符,将他们保存到data段中。当遇到输入字符是“#”时,表示到了结尾,跳转到next函数,“#”本身不保存到data段

 

line20-22:

 

 dos的2号调用,输出输入的字符。

 

line24-30:

 

 读取data段里读到的字符,然后逐个输出

运行截图如下:

 

 

任务3

 

 1 assume cs:code, ds:data
 2 data segment
 3     ;x db  99,72,85,63,89,97,55 
 4     x dw 91, 792, 8536, 65521, 2021
 5     len equ $- x    
 6 data ends
 7 
 8 code segment
 9     start:
10         mov ax,data
11         mov ds,ax
12 
13         mov si,offset x
14         mov cx,len/2
15         
16         do:
17             mov ax,[si]
18             
19             add si,2
20             push ax ;保存寄存器状态
21             push bx ;保存寄存器状态
22             push cx ;保存寄存器状态
23             push dx ;保存寄存器状态
24 
25             mov bx,10
26             mov cx,0
27 
28             yazhan:
29                 mov dx,0
30                 div bx
31                 
32                 push dx
33                 inc cx
34                 
35                 cmp ax,0
36                 jz chuzhan
37                 
38                 jmp yazhan
39                 
40             chuzhan:
41                 pop dx
42                 printNumber:
43                     add dl,30h
44                     mov ah,2            
45                     int 21h
46                     
47             loop chuzhan
48                 
49                 pop dx
50                 pop cx
51                 pop bx
52                 pop ax
53 
54             printSpace:
55                 mov ah,2
56                 mov dl,' '
57                 int 21h
58 
59         loop do
60 
61 
62         mov ah, 4ch
63         int 21h
64 code ends
65 end start

这个和上一次实验的差不多,唯一的区别就是数据由单字节变成了双字节,那么只要在上一次的基础上修改几个地方就好了

1.ah不用清零,mov ax,[si]就行了

2.add si,2 每次要加2

3.mov cx,len/2 因为是双字节,循环次数要除以2

 

 

 

任务4

 1 assume cs:code, ds:data
 2 
 3 data segment
 4     str db "assembly language, it's not difficult but tedious"
 5     len = $ - str
 6 data ends
 7 
 8 code segment 
 9 start:
10     mov ax, data
11     mov ds, ax
12     mov si,offset str 
13     mov cx,len
14 
15     strupr:
16     mov al,[si]
17     call isLow
18 
19     and al,11011111b
20     mov [si],al
21         printUpperLetter:
22         mov ah,2
23         mov dl,[si]
24         int 21h
25     next:inc si
26     loop strupr
27 
28     cmp cx,0
29     je endd
30 
31     isLow:
32     cmp al,'a'
33     jb next
34     cmp al,'z'
35     ja next
36     ret
37 
38     endd:mov ah, 4ch
39     int 21h
40 
41 code ends
42 end start

 

之前做过大写转成小写,原理是or 00100000; 现在要小写转成大写,只要反过来and 11011111

当然这里还有一个前提判断,你得是小写字母才可以去转(大写字母转了等于没转,非字母转了就错了)

所以我就写了个isLow判断一下,小于a或者大于z都直接si往下一个字节跳过了

然后这里为了便于看到结果,我还把转的字母都打印出来了,写了个printUpperLetter

然后最终结果如下:

 

 

 这是转换前的

 

 

 

 

  转后后的

 

补充:一开始做的时候考虑欠佳,有一些小问题。原因是在循环结束(cx=0)时,没有进行一个判断,有一次进入了isLow函数,造成了一些不合理的跳转。后来补充了一个判断后就解决了这个问题,至此,这个题目是完全的做对了。

 

任务5:

 

 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

 

 

 

来分析一下这个程序:

 

 获取输入的字符

 

 

设置输出的位置

 

 

 如果输入的是7,跳转到s1,输出yes;否则输出no

 

 

任务6

 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
 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

 

 

谈谈我对中断和软中断的理解:中断可以来自CPU外部和内部,软中断是内部中断的一种。一种比较典型的软中断就是int n指令的终端。

它看上去很像在一个程序运行的时候调用了另一个文件的程序。

用高级语言打个比方,像python导入了另外一个py文件的类或函数,并且执行了该函数。不同于之前的各种跳转,那东西更像是同一个文件内,同一个程序内部的函数之间互相调用,是自己和自己玩。

int n,似乎可以通过设置n来表示不同的含义,所以我们就可以自定义一些终端码,对应不同的终端处理程序,需要用的时候就直接调用,应该还是蛮方便的。

 

posted @ 2021-12-08 21:40  星穹铁道  阅读(103)  评论(1)    收藏  举报