实验二 汇编语言程序设计

实验二 汇编语言程序设计

实验目的

  1. 掌握顺序和循环程序结构和设计方法。
  2. 熟悉在 PC 机上建立、汇编、连接、调试和运行 8086/8088 汇编语言程序的过程。

实验内容

  1. X、Y、Z、V 均为字变量,在 X、Y、Z、V 字单元中存放是 16 位带符号数。试编写汇编语言程序完成以下功能:
  • 计算表达式值 (V – (X * Y + Z - 720)) / X
  • 将上述表达式运算结果整数放在 SUM1 单元,余数放在 SUM2 单元
  1. 使用地址表实现如下功能:根据输入的数字 1 ~ 7,分别显示相应的英文星期名,如果输入其他字符,则重新输入。
  2. 求一个班 50 名学生成绩的平均值、最大值和最小值,并将结果显示出来。
  3. 从键盘读入一个字符串,以 Enter 结束,字符串不超过 60 个字符,并打印该字符串;查找中间是否有自己名字拼音首字母缩写的子串。如果有,输出 “TRUE”;否则,输出 “FALSE”。

实验过程和程序

任务 1

X、Y、Z、V 均为字变量,在 X、Y、Z、V 字单元中存放是 16 位带符号数。试编写汇编语言程序完成以下功能:

  • 计算表达式值 (V – (X * Y + Z - 720)) / X
  • 将上述表达式运算结果整数放在 SUM1 单元,余数放在 SUM2 单元
折叠/展开代码
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
39
40
41
42
43
44
; cal.asm
stack segment stack
db 1024 dup(?)
stack ends

data segment
X dw 021cH
Y dw 0001H
Z dw 0FFFFH
V dw 0438H
SUM1 dw 0H
SUM2 dw 0H
data ends

code segment 'code'
assume cs:code, ds:data, ss:stack
start:
mov ax, data
mov ds, ax

mov ax, X
mul Y
mov cx, ax
mov bx, dx
mov ax, Z
cwd
add cx, ax
adc bx, dx
mov dx, 0
mov ax, 021CH
sub cx, ax
sbb bx, dx
mov ax, V
cwd
sub ax, cx
sbb dx, bx
idiv X
mov SUM1, ax
mov SUM2, dx

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

任务 2

使用地址表实现如下功能:根据输入的数字 1 ~ 7,分别显示相应的英文星期名,如果输入其他字符,则重新输入。

折叠/展开代码
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
; table.asm
stack segment stack
db 1024 dup(?)
stack ends

data segment
msg db 'enter the number$'
monday db 'monday$'
tuesday db 'tuesday$'
wednesday db 'wednesday$'
thursday db 'thursday$'
friday db 'friday$'
saturday db 'saturday$'
sunday db 'sunday$'
addr dw L1, L2, L3, L4, L5, L6, L7
data ends

code segment 'code'
assume cs:code, ds:data, ss:stack
start:
mov ax, data
mov ds, ax

lea dx, msg
mov ah, 09H
int 21H

mov ah, 02H
mov dl, 0dH
int 21H
mov dl, 0aH
int 21H

mov ah, 01H
int 21H

mov bl, al
mov ah, 02H
mov dl, 0dH
int 21H
mov dl, 0aH
int 21H
mov al, bl

cmp al, '1'
jb start
cmp al, '8'
ja start
and ax, 000fH
dec ax
shl ax, 1
mov bx, ax
jmp addr[bx]


L1:
lea dx, monday
jmp print
L2:
lea dx, tuesday
jmp print
L3:
lea dx, wednesday
jmp print
L4:
lea dx, thursday
jmp print
L5:
lea dx, friday
jmp print
L6:
lea dx, saturday
jmp print
L7:
lea dx, sunday
jmp print

print:
mov ah, 09H
int 21H

mov ah, 02H
mov dl, 0dH
int 21H
mov dl, 0aH
int 21H

mov ax, 4c00H
int 21H
code ends
end start

任务 3

求一个班 50 名学生成绩的平均值、最大值和最小值,并将结果显示出来。

折叠/展开代码
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
; grade.asm
stack segment stack
db 1024 dup(?)
stack ends

data segment
grade db 52H, 50H, 52H, 5FH, 52H, 5EH, 50H, 52H, 50H, 54H
sum dw 0H ; 0349H
avg db 0H ; 54H
max db 0H ; 5FH
min db 0H ; 50H
data ends

code segment 'code'
assume cs:code, ds:data, ss:stack
start:
mov ax, data
mov ds, ax

; calulate sum
mov ax, 0H
mov cx, 0aH
mov si, 0H
begin:
add al, grade[si]
adc ah, 0H
inc si
loop begin
mov sum, ax

; calculate avg
mov bl, 0aH
div bl
mov avg, al

; min
mov si, 01H
mov al, grade[0H]
mov cx, 09H
beginMin:
cmp al, grade[si]
jbe loopMin
mov al, grade[si]
loopMin:
inc si
loop beginMin
mov min, al

; max
mov si, 01H
mov al, grade[0H]
mov cx, 09H
beginMax:
inc si
cmp al, grade[si]
jae loopMax
mov al, grade[si]
loopMax:
loop beginMax
mov max, al

mov ax, 4c00H
int 21H
code ends
end start

任务 4

从键盘读入一个字符串,以 Enter 结束,字符串不超过 60 个字符,并打印该字符串;查找中间是否有自己名字拼音首字母缩写的子串。如果有,输出 “TRUE”;否则,输出 “FALSE”。

折叠/展开代码
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
; string.asm
stack segment stack
db 1024 dup(?)
stack ends

data segment
buf db 50, ?, 50 dup('$')
msg db 'enter a str: ', 0dH, 0aH, '$'
trueMsg db 'True', 0dH, 0aH, '$'
falseMsg db 'False', 0dH, 0aH, '$'
keyWord db 'gxw$'

data ends

code segment 'code'
assume cs:code, ds:data, ss:stack
start:
mov ax, data
mov ds, ax

; 提示消息
lea dx, msg
mov ah, 09H
int 21H

; 读取字符串
lea dx, buf
mov ah, 0aH
int 21H

; 换行
mov ah, 02H
mov dl, 0dH
int 21H
mov dl, 0aH
int 21H

; 查找字符串
mov ax, data
mov es, ax
cld

lea bx, buf + 01H
lea dx, buf + 02H
add dl, buf[01H]
adc dh, 0H
cmpBegin:
inc bx
cmp dx, bx
jb done
mov cx, 03H
mov si, bx
lea di, keyWord
repz cmpsb
jnz cmpBegin

lea dx, trueMsg
jmp endFlag

done:
lea dx, falseMsg

endFlag:
mov ah, 09H
int 21H
mov ax, 4c00H
int 21H
code ends
end start

实验结果

任务 1

如下代码所示,在 X、Y、Z、V 变量中分别存了几个数字,运行程序,计算结果

1
2
3
4
5
6
7
8
data    segment
X dw 021cH
Y dw 0001H
Z dw 0FFFFH
V dw 0438H
SUM1 dw 0H
SUM2 dw 0H
data ends

运行结果

程序得到了正确的结果:商是 2,余数是 1。

任务 2

运行结果如图所示,可以正常转换:

转换结果 1

转换结果 2

任务 3

为了方便数据录入,我在编写代码时只考虑了 10 个成绩,如下图,在 grade 数组中有 10 个成绩。下面的为结果存放的内存,注释部分为期待的结果。

1
2
3
4
5
6
7
data    segment
grade db 52H, 50H, 52H, 5FH, 52H, 5EH, 50H, 52H, 50H, 54H
sum dw 0H ; 0349H
avg db 0H ; 54H
max db 0H ; 5FH
min db 0H ; 50H
data ends

运行程序:可以看到结果正确:

运行结果

任务 4

在此题中,我的名字拼音首字母为 “gxw”,在编写代码后,运行程序:

比较结果 1

比较结果 2

实验体会

本次实验和上一次实验最大的不同是本次实验将代码写在了文件中,然后用 MASM 和 LINK 工具来编译和链接。这样写代码时更加方便,代码也可以保留下来。

实验中用到了地址表,相当于 switch 语句。可以根据需要跳转到不同的语句,比如第二题中,根据用户输入来跳转到不同的输出语句。

实验中还用到了循环语句的写法,使用循环可以简化程序。例如对数组的求和以及遍历数组。

实验中用到了比较字符串的指令和重复前缀,结合这两个命令可以实现从字符串中查找子串的目的。