实验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来表示不同的含义,所以我们就可以自定义一些终端码,对应不同的终端处理程序,需要用的时候就直接调用,应该还是蛮方便的。

浙公网安备 33010602011771号