0%

《汇编语言》(第四版) 实验 11

《汇编语言(第四版)》 . 王爽著 . 清华大学出版社 . 2019

实验 11 编写子程序

标志寄存器

8086CPU 中有 16 位标志寄存器(flag),其中存储的信息被称为程序状态字(PSW),其作用有:
1)用来存储相关指令的某些执行结果;
2)用来为 CPU 执行相关指令提供行为依据
3)用来控制 CPU 的相关工作方式


标志寄存器的各个标志位

记法:
记它的英文
Carry Flag(CF:进位标志位)
Overflow Flag(OF:溢出标志位)
Direction Flag(DF:方向标志位)
Sign Flag(SF:符号标志位)
Zero Flag(ZF:零标志位)
Parity Flag(PF:奇偶标志位)



pushf 和 popf
pushf:将标志寄存器的值压栈
popf:从栈中弹出数据,送入标志寄存器中

检测点 11.1


mov、push、pop 等传送指令的执行对标志寄存器没有影响
注意 PF 记录的是相关指令执行后其结果的所有 bit 位中的 1 的个数的奇偶,不是结果的奇偶

1
2
3
4
5
6
7
sub al,al         ;ZF = 1, PF = 1, SF = 0 结果为 al=0
mov al,1 ;ZF = 1, PF = 1, SF = 0
push ax ;ZF = 1, PF = 1, SF = 0
pop bx ;ZF = 1, PF = 1, SF = 0
add al,bl ;ZF = 0, PF = 0, SF = 0 结果为 al=00000010B
add al,10 ;ZF = 0, PF = 1, SF = 0 结果为 al=00001100B
mul al ;ZF = 0, PF = 1, SF = 0 结果为 ax=0090H

检测点 11.2


1
2
3
4
5
6
7
8
9
sub al,al         ;CF = 0, OF = 0, SF = 0, ZF = 1, PF = 1 结果为 al=0
mov al,10H ;CF = 0, OF = 0, SF = 0, ZF = 1, PF = 1
add al,90H ;CF = 0, OF = 0, SF = 1, ZF = 0, PF = 1 结果为 al=10100000B
mov al,80H ;CF = 0, OF = 0, SF = 1, ZF = 0, PF = 1
add al,80H ;CF = 1, OF = 1, SF = 0, ZF = 1, PF = 1 结果为 al=0
mov al,0FCH ;CF = 1, OF = 1, SF = 0, ZF = 1, PF = 1
add al,05H ;CF = 1, OF = 0, SF = 0, ZF = 0, PF = 0 结果为 al=1
mov al,7DH ;CF = 1, OF = 0, SF = 0, ZF = 0, PF = 0
add al,0BH ;CF = 0, OF = 1, SF = 1, ZF = 0, PF = 1 结果为 al=10001000B

cmp 指令

cmp 是比较指令,它的功能相当于减法指令,但不保存结果,其执行后将对标志寄存器产生影响

cmp 通常与条件转移指令相配合使用,条件转移指令检测标志寄存器的相关标志位,根据检测的结果来决定是否修改 IP

1
2
3
4
5
6
7
8
9
10
11
12
13
;指令       ;同义名     ;跳转条件         ;描述
je ;jz ;ZF ;相等/零
jne ;jnz ;~ZF ;不相等/非零
js ;SF ;负数
jns ;~SF ;非负数
jg ;jnle ;~(SF^OF)&~ZF ;有符号大于
jge ;jnl ;~(SF^OF) ;有符号大于或等于
jl ;jnge ;SF^OF ;有符号小于
jle ;jng ;(SF^OF)|ZF ;有符号小于或等于
ja ;jnbe ;~CF&~ZF ;无符号大于
jae ;jnb ;~CF ;无符号大于或等于
jb ;jnae ;CF ;无符号小于
jbe ;jna ;CF|ZF ;无符号小于或等于

检测点 11.3

(1)

1
2
3
4
cmp al,32         ;al < 32
jb s0
cmp al,128 ;al > 128
ja s0

(2)

1
2
3
4
cmp al,32         ;al <= 32
jna s0
cmp al,128 ;al >= 128
jnb s0

注意满足逻辑即可

检测点 11.4

AX=0045H

1
2
3
4
5
6
7
8
9
10
mov ax,0
push ax
popf
mov ax,0fff0h
add ax,0010h ;fff0h + 0010h = 0000h, 注意:of=0
pushf ;此时的标志寄存器:0000 0000 0100 0101
pop ax ;(ax)=(flag)
and al,11000101B ;(al)=01000101B
and ah,00001000B ;(ah)=00000000B
;(ax) = 0000 0000 0100 0101 B = 0045h = 69

一些例程

编写子程序,对两个 128 位数据进行相加。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
;128 位数据需要 8 个字单元
;ds:si 指向存储第一个数的内存空间
;ds:di 指向存储第二个数的内存空间
;运算结果存储在第一个数的存储空间中

add128: push ax
push cx
push si
push di

sub ax,ax ;将 CF 设置为 0

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

;inc 指令不能替换成 add 指令
;inc 指令不影响 cf 位,而 add 指令会影响 cf 位

编程,统计 data 段中数值为 8 的字节个数,用 ax 保存统计结果。

比较下面两个程序的写法,注意使用 cmp 和条件转移指令时的编程思想

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
assume cs:code,ds:data
data segment
db 8,11,8,1,8,5,65,38
data ends

code segment
start: mov ax,data
mov ds,ax
mov bx,0 ;ds:bx 指向第一个字节
mov ax,0 ;初始化累加器
mov cx,8

s: cmp byte ptr [bx],8 ;和 8 进行比较
jne next ;如果不相等就转到 next,继续循环
inc ax ;如果相等就将计数值加 1

next: inc bx
loop s ;程序执行后:(ax)=3

mov ax,4c00h
int 21h
code ends
end start

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
assume cs:code,ds:data
data segment
db 8,11,8,1,8,5,65,38
data ends

code segment
start: mov ax,data
mov ds,ax
mov bx,0 ;ds:bx 指向第一个字节
mov ax,0 ;初始化累加器
mov cx,8

s: cmp byte ptr [bx],8 ;和 8 进行比较
je ok ;如果相等就转到 ok
jmp short next ;如果不相等就转 next,继续循环

ok: inc ax ;如果相等就将计数值加 1

next: inc bx
loop s

mov ax,4c00h
int 21h
code ends
end start

第一个程序更为精简,它用 jne 指令检测不等于 8 的情况,从而间接地检测了等于 8 的情况


编程,用串传送指令,将 data 段中的第一个字符串复制到它后面的空间中。

使用串传送指令(rep movsb / rep movsw)进行数据的传送,需要提供
1)传送的原始位置:ds:si
2)传送的目的位置:es:di
3)传送的长度:cx
4)传送的方向:df

8086CPU 提供下面两条指令对标志寄存器的 df 位进行设置
cld 指令:将 df 位置 0
std 指令:将 df 位置 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
assume cs:code,ds:data
data segment
db 'Welcome to masm!'
db 16 dup (0)
data ends

code segment
start: mov ax,data
mov ds,ax
mov si,0 ;ds:di 指向 data:0
mov es,ax
mov di,16 ;es:di 指向 data:0010
mov cx,16 ;(cx)=16,rep 循环 16 次
cld ;设置 df=0,正向传送
rep movsb

mov ax,4c00h
int 21h
code ends
end start

编程,用串传送指令,将 F000H 段中的最后 16 个字符复制到 data 段中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
assume cs:code,ds:data
data segment
db 16 dup (0)
data ends

code segment
start: mov ax,0f000h
mov ds,ax
mov si,0ffffh ;ds:di 指向 f000:ffff
mov ax,data
mov es,ax
mov di,15 ;es:di 指向 data:000f
mov cx,16 ;(cx)=16,rep 循环 16 次
std ;设置 df=1,逆向传送
rep movsb

mov ax,4c00h
int 21h
code ends
end start

实验任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
assume cs:codesg,ds:datasg

datasg segment
db "Beginner's All-purpose Symbolic Instruction Code.",0
datasg ends

codesg segment
begin: mov ax,datasg
mov ds,ax
mov si,0
call letterc

mov ax,4c00h
int 21h

letterc: push si
push ax

s1: cmp byte ptr ds:[si],0 ;检测结束符 0
je ok
cmp byte ptr ds:[si],61h ;检测是否为 a ~ z 之间的字符
jb s2 ;若不是则直接转移到标号 s2 处
cmp byte ptr ds:[si],7ah
ja s2
mov al,ds:[si] ;若是则进行大小写转换
and al,11011111b ;也可用 sub al,20h (即 小写字母-20H=大写字母 的关系)
mov ds:[si],al

s2: inc si
inc cx ;jmp short s1
loop s1

ok: pop ax
pop si
ret

codesg ends
end begin
用 Debug 跟踪程序运行


汇编语言实验合集

汇编语言实验合集

实验 1 查看 CPU 和内存,用机器指令和汇编指令编程
实验 2 用机器指令和汇编指令编程
实验 3 编程、编译、连接、跟踪
实验 4 [bx] 和 loop 的使用
实验 5 编写、调试具有多个段的程序
实验 6 实践课程中的程序
实验 7 寻址方式在结构化数据访问中的应用
实验 8 分析一个奇怪的程序
实验 9 根据材料编程
实验 10 编写子程序
课程设计 1
实验 11 编写子程序
实验 12 编写 0 号中断的处理程序
实验 13 编写、应用中断例程
实验 14 访问 CMOS RAM
实验 15 安装新的 int9 中断例程
实验 16 编写包含多个功能子程序的中断例程
实验 17 编写包含多个功能子程序的中断例程
课程设计 2