分享SCAU汇编实验代码

实验一

计算(859FH*3)+8765H的值 ,并把结果存在存储器数据段偏移量3578H开始的位置

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
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX

; 题目:

; 计算 (859FH * 3) + 8765H的值

; 结果存在存储器数据段偏移量3578H开始的位置

; 此处输入代码段代码
MOV AX,859FH
MOV BX,3
MUL BX
ADD AX,8765H
ADC DX,0
MOV DS:[3578H],AX
MOV DS:[357AH],DX
; 此处输入代码段代码

MOV AH,4CH
INT 21H
CODES ENDS
END START

实验二

判断AX中的年份(无符号整数)是否闰年,是则将0001传送到BX,否则将BX清零(分别用数据1900、2008、1999、2000做测试)

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
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX

; 题目:

; 判断AX中的年份(无符号整数)是否闰年?

; 是则将0001传送到BX,否则将BX清零

; (分别用数据1900、2008、1999、2000做测试)

; 此处输入代码段代码
MOV AX,1900 ; 测试年份
MOV DX,0
MOV CX,AX ; 保存年份
MOV BX,400
DIV BX
TEST DX,DX
JZ L2 ; 整除400 直接跳转L2

MOV AX,CX
MOV DX,0
MOV BX,4
DIV BX
TEST DX,DX
JNZ L1 ; 无法整除4 直接跳转L1

MOV AX,CX
MOV BX,100
DIV BX
TEST DX,DX
JZ L1 ; 整除4 & 整除100 跳转L2
JNZ L2 ; 无法整除100 跳转L1

L1:
MOV BX,0
MOV AH,4CH
INT 21H
L2:
MOV BX,0001H
; 此处输入代码段代码
MOV AH,4CH
INT 21H
CODES ENDS
END START

实验三

将用户输入的四位(测试数据固定四位)十六进制数变成二进制形式输出(所有字母大写,用户输入非法字符则结束)例如用户输入50F0则输出0101000011110000测试数据:50F0,123A

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
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
; 题目:

; 将用户输入的四位(测试数据固定四位)

; 十六进制数变成二进制形式输出

; 所有字母大写,用户输入非法字符则结束

; 例如用户输入50F0则输出0101000011110000

; 此处输入代码段代码
MOV BX,0
MOV CH,4 ; 循环次数
INPUT:
MOV AH,01H ; 输入一个字符,ASCII码在AL中
INT 21H
CMP AX,0130H ; 判断是否非法,AX < 0
JL EXIT
CMP AX,0139H ; 判断是否数字
JLE L1 ; 是数字,跳转L1
CMP AX,0141H ; 判断是否非法,9 < AX < A
JL EXIT
CMP AX,015AH ; 判断是否非法,AX > Z
JNLE EXIT
SUB AL,07H ; 要把A当成数字10,减去A与9中间的差值

L1:
SUB AL,30H ; 把ASCII码转换为数字
MOV CL,4
SHL BX,CL ; BX每次左移4位
ADD BL,AL ; 将数字加到BX中
DEC CH ; 循环次数减一
CMP CH,0 ; 判断循环是否结束
JNZ INPUT ; 循环未结束,跳回

;处理结束,输出换行符
MOV DL,10
MOV AH,02H
INT 21H

MOV CH,16 ; 循环计数器,用来输出16位二进制数
L2:
SHL BX,1 ; BX左移1位,暂存到CF中
JC SET1 ; 若CF为1,则跳转到SET1标签
MOV DL,30H ; 若CF为0,则DL存'0'
JMP PRINT ; 跳转到PRINT标签,输出DL中的字符

SET1:
MOV DL,31H ; CF为1,则DL存'1'

PRINT:
MOV AH,02H ; 输出字符
INT 21H
DEC CH ; 循环次数减一
CMP CH,0 ; 判断循环是否结束
JNZ L2 ; 循环未结束,跳回

EXIT:
MOV AH,4CH
INT 21H
;此处输入代码段代码
CODES ENDS
END START

统计长度为N的字数组ARRAY中有多少种不同数值,例如数组{1,1,3,5,5}中有三种不同数值。将结果存放进BX测试数据:{1,1,3,5,5}{4,2,5,2,5,4,6,7,4,6,9,11,15,9}

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
DATAS SEGMENT
;此处输入数据段代码
FRONT LABEL WORD
ARRAY DW 4, 2, 5, 2, 5, 4, 6, 7, 4, 6, 9, 11, 15, 9
BACK LABEL WORD
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
; 题目:

; 编写程序,统计长度为N的字数组ARRAY中有多少种不同数值

; 例如: 数组{1,1,3,5,5}中有三种不同数值,将结果存放进BX

; 测试数据:{1,1,3,5,5}

; {4,2,5,2,5,4,6,7,4,6,9,11,15,9}

; 此处输入代码段代码
MOV BX,0 ; 初始化计数器
LEA DX,FRONT
LEA CX,BACK
SUB CX,DX ; CX记录数组长度
MOV SI,0
L1: ; 第一层循环
MOV DX,ARRAY[SI] ; DX暂存a[i]
MOV DI,0
L2:
CMP DI,SI ; 表示i==j
JZ ANS ; 跳转ANS
MOV AX,ARRAY[DI] ; AX暂存a[j]
CMP AX,DX ; 比较a[i],a[j]
JE NEXTL2 ; 表示a[i]==a[j],跳转NEXTL2
ADD DI,2 ; j++
JMP L2 ; 继续内层循环
ANS:
INC BX
NEXTL2:
ADD SI,2
CMP SI,CX
JB L1
; 此处输入代码段代码
MOV AH,4CH
INT 21H
CODES ENDS
END START

实验四

若数据段定义

1
2
3
4
data segment
array1 dw 11,22,3BH,4,35,100,12,27,78,24
sum dw ?
data ends

求数组array1中所有 偶数 的和,存放在sum中。测试时除了以上数据外,还需测试以下array1array1 dw 5,128,34,77,22,301,89,64,50,66

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
DATAS SEGMENT
array1 dw 11,22,3BH,4,35,100,12,27,78,24
sum dw ?
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
; 题目:

; 若数据段定义
; data segment
; array1 dw 11,22,3BH,4,35,100,12,27,78,24
; sum dw ?
; data ends
; 求数组array1中所有 偶数 的和,存放在sum中。
; 测试时除了以上数据外,还需测试
; array1
; array1 dw 5,128,34,77,22,301,89,64,50,66

;此处输入代码段代码
MOV SI,0
MOV CX,10 ; 循环次数
MOV DX,0 ; 初始化累加器
L1:
MOV AX,array1[SI]
TEST AX,1 ; 测试奇偶性
JNZ ODD ; 奇数跳转
ADD DX,AX ; 偶数累加
ODD:
ADD SI,2 ; 指针加2
LOOP L1 ; cx≠0,循环继续
MOV sum,DX ; 循环结束,结果存在sum中
;此处输入代码段代码
MOV AH,4CH
INT 21H
CODES ENDS
END START

将AX中数据的二进制形式倒置,并以二进制形式输出。例如0000000011110001,倒置后为1000111100000000(测试数据为1234H,5678H,00FFH,无需做输入,直接在程序中修改测试数据,需要做输出)

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
DATAS SEGMENT
; 此处输入数据段代码
DATAS ENDS

STACKS SEGMENT
; 此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
; 题目:

; 将AX中数据的二进制形式倒置,并以二进制形式输出。

; 例如0000000011110001,倒置后为1000111100000000

; 测试数据为1234H,5678H,00FFH

; 无需做输入,直接在程序中修改测试数据,需要做输出

; 此处输入代码段代码
MOV AX,1234H
MOV CX,2 ; 除数2
MOV BX,16 ; 计数器,记录未输出位数
L1:
XOR DX,DX ; 清空DX
DIV CX ; 除以2,相当于取出末位
CALL PRINT ; 调用打印函数
CMP AX,0 ; 检查是否为0
JNZ L1 ; 不为0,继续循环

MOV CX,BX ; 剩余位数皆为0,存到CX作循环输出

L2:
MOV DX,0 ; DX置0
ADD DX,30H ; 转换为ASCII码
MOV AH,2 ; 调用21号中断的2号功能,输出DX中字符
INT 21H
LOOP L2 ; CX≠0继续循环

MOV AH,4CH ; =退出
INT 21H
PRINT:
PUSH AX ; 压栈保存AX,DX
PUSH DX
ADD DX,30H ; 转换为ASCII码
MOV AH, 2 ; 调用21号中断的2号功能,输出DX中字符
INT 21H
POP DX ; 出栈恢复AX,DX
POP AX
DEC BX ; 已输出1位,计数器减1
RET
; 此处输入代码段代码
CODES ENDS
END START

用户输入四位十六进制数(固定四个字符,如“A123” ”0035”“123f”, 字母可能大写或小写,输入非法字符则退出),在屏幕输出其十进制形式。

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
DATAS SEGMENT
bin dw 10 dup(?) ;存放二进制结果
buf db 5 dup(?) ;存放十进制数 各个数位上的数值 如100,存放为 1,0,0
msg1 db 'please input a hex number',13,10,'$'
msg2 db 'the dec number:',13,10,'$'
crlf db 13,10,'$' ;回车换行
DATAS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS
START:
MOV AX,DATAS
MOV DS,AX

mov bx,0 ;初始化bx


input:
mov ah,1 ;输入一个字符
int 21h

sub al,30h ;把al中的ascii码转换成数值
jl init

cmp al,10 ;输入的数在0-9之间跳转
jl toBin

ADD AL,30H
CMP AL,41H
JL EXIT
CMP AL,46H
JNLE L1
ADD AL,20H

L1:
SUB AL,30H

sub al,27h ;再转换为a-f
cmp al,0ah ;输入的字符比a小
jl init ;结束输入
cmp al,10h ;输入的字符比f大
jge init ;结束输入

toBin: ;转换为二进制,把输入组合成意义上的数值
mov cl,4
shl bx,cl ;bx左移4位
mov ah,0
add bx,ax ;把输入后并从ascii码转换来的值与bx相加
mov bin,bx ;转换成二进制数后存到内存bin
jmp input ;继续输入

init: ;初始化,准备转换
mov ax,bin
mov bx,10
mov si,4 ;循环四次,最大到万位

toDec: ;转为各个数位上的数值,如100转换为1,0,0 百位为1...
mov dx,0
div bx ;除10法得到各个位上的数值
mov [buf+si],dl ;余数为该位上的值,第一次循环为个位,第二次为十位...;存到内存中
dec si
cmp ax,0 ;商是否为0,为0算法结束
ja toDec





output: ;输出内存中存放的各个数位上的数值
inc si
mov dl,[buf+si]
add dl,30h ;转为ascii
mov ah,2
int 21h
cmp si,4
jb output


mov ah,1
int 21h
MOV AH,4CH
INT 21H

EXIT:
MOV AH,4CH
INT 21H

CODES ENDS
END START

实验五

在屏幕上输出2-100之间的所有素数(源程序里要求用到子程序判断是否素数,以及用子程序输出十进制整数,要有计算过程,不可以直接抄结果输出)

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
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
; 问题

; 在屏幕上输出2-100之间的所有素数

; 源程序里要求用到子程序判断是否素数,以及用子程序输出十进制整数

;此处输入代码段代码
MAIN PROC FAR
MOV AX,DATAS
MOV DS,AX
MOV CX,1 ; 计数器,1 < CX <100
L1:
INC CX ; i++
MOV AX,CX ; 将CX存到AX中
PUSH CX ; CX压栈
CALL IS_PRIME ; 判断是否素数
POP CX ; CX出栈
CMP BX,0 ; 判断素数标志位
JZ L2 ; 非素数,不打印
CALL PRINT ; 素数,打印

L2:
CMP CX,100 ; 判断CX < 100
JL L1 ; < 继续循环
MOV AH,4CH ; 退出
INT 21H

MAIN ENDP

IS_PRIME PROC NEAR
PUSH AX ; AX压栈
MOV BX,1 ; 标志:是否素数
MOV CX,2 ; i 因子
L3:
POP AX ; AX出栈
PUSH AX ; AX进栈
CMP CX,AX ; 判断CX是否 < AX
JE PRIME ; CX == AX
MOV DX,0 ; 清空DX
DIV CX ; 除因子
CMP DX,0 ; 判断能否整除
JE NOT_PRIME ; 能整除不是素数

INC CX ; 因子++
JMP L3 ; 继续循环

NOT_PRIME:
MOV BX,0 ; 不是素数,置标志为0

PRIME:
POP AX
RET ; 返回
IS_PRIME ENDP



PRINT PROC NEAR
MOV BL,10
DIV BL ; 除10
MOV BX,AX ; BX暂存AX内容
MOV AH,02H
MOV DL,BL ; 打印 商(即十位数)
ADD DL,30H ; +'0'
INT 21H
MOV DL,BH ; 打印 余数(即个位数)
ADD DL,30H
INT 21H
MOV DL,' ' ; 打印空格
INT 21H
RET
PRINT ENDP
;此处输入代码段代码
CODES ENDS
END START

编写程序,将数据段里的某数组在原位置逆序(例如ARRAY数组{1,2,3}变为{3,2,1},但首地址依然是ARRAY),要求用子程序实现逆序操作。子程序要求有一定通用性,能够处理不同数组。

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
DATAS SEGMENT
ARY DW 1,2,3
ARY_SIZE EQU ($-ARY)/2 ; 数组长度
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
; 问题

; 编写程序,将数据段里的某数组在原位置逆序
; 例如ARRAY数组{1,2,3}变为{3,2,1},但首地址依然是ARRAY
; 要求用子程序实现逆序操作。


;此处输入代码段代码

MOV AX,OFFSET ARY
PUSH AX
MOV AX,OFFSET ARY_SIZE
PUSH AX

CALL REVERSE ; 调用逆序子程序

MOV AH,4CH ; 退出
INT 21H

REVERSE PROC NEAR
PUSH BP
MOV BP,SP

PUSH AX
PUSH CX
PUSH SI
PUSH DI

LEA AX,ARY ; 加载ary首地址到ax
MOV SI,AX
MOV CX,ARY_SIZE ; cx=ary[size]

MOV DI,SI
MOV AX,CX
MOV BL,2
MUL BL
ADD DI,AX
;数组的尾地址的下一个地址
SUB DI,2 ; 现在指向数组的尾地址

L1:
CMP CX,0
JLE OVER

MOV AL,[SI]
XCHG AL,[DI]
MOV [SI],AL

INC SI
DEC DI
LOOP L1


OVER:
POP DI
POP SI
POP CX
POP AX
POP BP
RET 6

REVERSE ENDP

CODES 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
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
DATAS SEGMENT
; 定义数据段,存储数据
ARRAY DW 2,3,4,10
BACK LABEL WORD ; 定义一个字大小的标签
DATAS ENDS

STACKS SEGMENT
; 定义堆栈段
STACKS ENDS

CODES SEGMENT
; 定义代码段
ASSUME CS:CODES,DS:DATAS,SS:STACKS ; 定义段寄存器

START:
MAIN PROC FAR
MOV AX,DATAS
MOV DS,AX

MOV AX, OFFSET ARRAY
; 将数组ARRAY的偏移地址加载到AX中(第一个元素的地址)
PUSH AX
; 将数组ARRAY的偏移地址压入堆栈(第一个元素的地址)
MOV AX, OFFSET BACK
; 将数组BACK的偏移地址加载到AX中(最后一个元素的地址)
PUSH AX
; 将数组BACK的偏移地址压入堆栈(最后一个元素的地址)
CALL FINDMAX
; 调用名为FINDMAX的子程序

MOV AH,4CH
INT 21H
RET
MAIN ENDP

; 用于查找数组中的最大值
FINDMAX PROC NEAR
MOV BP,SP
; 将栈指针加载到BP寄存器中
MOV SI,[BP+4]
; 将堆栈中第一个参数的偏移地址加载到SI中(数组的第一个元素的地址)
MOV DI,[BP+2]
; 将堆栈中第二个参数的偏移地址加载到DI中(数组的最后一个元素的地址)
MOV AX,[SI]
; 将AX加载为数组的第一个元素的值
ADD SI,2
L1:
CMP SI,DI
; 比较SI和DI,检查是否已经遍历完整个数组
JNB OVER
; 如果SI大于等于DI(已经到达数组末尾),则跳转到OVER
CMP AX,[SI]
; 比较AX(当前最大值)和[SI](当前元素的值)
JNB NEXT
; 如果AX大于等于[SI],则跳转到NEXT
MOV AX,[SI]
; 更新AX为[SI]的值(新的最大值)
NEXT:
ADD SI,2
; 移动到数组的下一个元素
JMP L1
; 跳回L1,继续遍历数组
OVER:
RET 4
; 从子程序返回,从堆栈中弹出4个字节
FINDMAX ENDP

CODES ENDS
END START

实验六

在屏幕上输出字符串“welcome to asm”,要求逐个字符输出,每隔约0.5秒左右(可以有0.05秒内的误差)输出一个字符。

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
DATAS SEGMENT
;此处输入数据段代码
STRING DB 'welcome to asm',0dh,0ah,'$' ; 0DH,0AH 回车,换行
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS

MS1 = 325 ; 1ms延时

START:
MOV AX,DATAS
MOV DS,AX
; 问题

; 在屏幕上输出字符串“welcome to asm”

; 要求逐个字符输出,每隔约0.5秒左右(可以有0.05秒内的误差)输出一个字符

;此处输入代码段代码

MOV CX,14 ; 字符串长度
MOV BX,0 ; 计数器BX
LEA DX,STRING ; STRING的地址存在DX
CALL PRINT ; 打印字符串


MOV AH,4CH
INT 21H

PRINT PROC
L1:
MOV DL,[STRING+BX] ; 字符加载到DL中
MOV AH,02H ; 输出
INT 21H
INC BX ; 计数器+1

PUSH CX
PUSH DX

MOV AL,1 ; 设置延时1次
CALL TIME ; 调用延时程序

POP DX
POP CX


LOOP L1
RET
PRINT ENDP


;延时0.5s子程序
TIME PROC
S0:
MOV CX,500 ; 内循环延时约1ms,外循环500次,则内循环一轮为0.5s
S1:
MOV DX,MS1 ; 延时次数计数
S2:
DEC DX ; 第一层循环 1ms
JNZ S2

DEC CX ; 第二层循环 0.5s
JNZ S1

DEC AL
JNZ S0

RET
TIME ENDP

CODES ENDS
END START

实现秒表,即从0秒开始进行计时,随着时间经过变更显示的秒数(例如经过10秒则显示10,最多100秒。可以有0.1秒以内的误差。)

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
92
93
94
95
96
97
98
99
100
101
DATAS SEGMENT
;此处输入数据段代码
COUNTER DB 0
COUNTER1 DB 0
COUNTER2 DB 0
TIME EQU 60000 ; 延迟计数器的值,根据实际需要调整

DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX

; 问题

; 实现秒表,即从0秒开始进行计时,随着时间经过变更显示的秒数

; 例如经过10秒则显示10,最多100秒。可以有0.1秒以内的误差。

; 提示:变更已显示的内容可以清屏后重新显示,清屏可以用

; MOV AX,3

; INT 10H

;此处输入代码段代码
MOV AX, 3 ; 清屏
INT 10H
MOV BX, 0

L2: ; 百位
MOV DL, [COUNTER2]
ADD DL, '0' ; 转换ASCII码
MOV AH, 02H
INT 21H ; 显示字符

L1: ;十位
MOV DL, [COUNTER1]
ADD DL, '0' ; 转换ASCII码
MOV AH, 02H
INT 21H ; 显示字符

L0: ; 个位
MOV DL, [COUNTER] ; 计数器加载到DL
ADD DL, '0' ; 转换ASCII码
MOV AH, 02H
INT 21H ; 显示字符

MOV DI, 30 ; 延迟一段时间
SET_CX:
MOV CX, TIME ; 初始化延迟计数器

DELAY_LOOP:
DEC CX ; 计数器减1
JNZ DELAY_LOOP ; 如果计数器不为0,则继续循环延迟
DEC DI
JNZ SET_CX

INC [COUNTER]
MOV AX, 3 ; 清屏
INT 10H

CMP [COUNTER2], 1 ;检查是否超过100秒
JE RESET_C


CMP [counter], 10 ; 检查计时器0是否超过10秒
JNE L2 ; 如果未超过10秒

CMP [counter], 10
JE C_1

C_1: ;十位进位
INC [COUNTER1]
MOV [COUNTER], 0
CMP [COUNTER1], 10
JE C_2
JMP L2

C_2: ;百位进位
INC [COUNTER2]
MOV [COUNTER1], 0
JMP L2

RESET_C: ;重置时间为000
MOV [COUNTER], 0
MOV [COUNTER1], 0
MOV [COUNTER2], 0
JMP L2

MOV AH,4CH
INT 21H

CODES ENDS
END START

实验七

将用户输入的无符号十进制数(不超过4位)变成十六进制的形式输出测试数据:1234,5,7008,66

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
DATA SEGMENT
STRING DB 0DH,0AH,"OVERFLOW!",'$'
DATA ENDS
STACK SEGMENT STACK
DW 100 DUP (?)
TOP LABEL WORD
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
MAIN PROC FAR
MOV AX,DATA
MOV DS,AX
MOV AX,STACK
MOV SS,AX
LEA SP,TOP

MOV BX,0
MOV CX,0 ;统计合法的数字字符个数
MOV SI,10
MOV BP,0 ;符号位默认为0(正数)

MOV AH,7 ;输入第一个字符
INT 21H

CMP AL,0DH ;输入回车,退出
JE EXIT

L1:
CMP AL,'+'
JNE L3 ;不是正号,跳转到L3继续判断
MOV BP,0 ;输入正号,更改符号位

MOV DL,AL ;显示正号
MOV AH,2
INT 21H

JMP L2 ;跳转到L2继续输入数字字符

L2:
MOV AH,7
INT 21H

CMP AL,0DH ;输入回车,跳转到以16进制显示BX
JE PRINT

L3:
CMP AL,30H ;小于30H,继续输入
JB L2
CMP AL,39H ;大于39H,继续输入
JA L2

MOV DL,AL ;显示合法的数字字符
MOV AH,2
INT 21H
INC CX ;合法的数字字符+1

AND DX,0FH ;屏蔽DX高12位
MOV AX,DX

XCHG AX,BX ;交换AX和BX
MUL SI ;AX*10

;数字部分以无符号数输入
;限制数字部分的输入范围0-65535
JC OVERFLOW
ADD BX,AX
JC OVERFLOW

JMP L2 ;无溢出,跳转到L2继续输入数字字符

PRINT:
CMP CX,0 ;判断合法的数字字符个数,CX为0退出
JE EXIT

;接下来判断有符号数的溢出
CMP BP,1
JE NEGATIVE ;判断负数的溢出

CMP BP,0
JE POSITIVE ;判断正数的溢出

NEGATIVE:
NEG BX ;BX是负数,求补
ADD BX,0 ;这条指令会改变PSW,接下来判断符号位
JNS OVERFLOW ;符号位是0,溢出
JMP L4 ;跳转到L4以16进制显示BX

POSITIVE:
ADD BX,0 ;BX是正数
JS OVERFLOW ;符号位是1,溢出

L4:
MOV CX,4

MOV DL,0DH
MOV AH,2
INT 21H

MOV DL,0AH
MOV AH,2
INT 21H

L5:
PUSH CX
MOV CL,4
ROL BX,CL
MOV DL,BL
AND DL,0FH
CMP DL,9
JA L6
ADD DL,30H
JMP L7

L6:
ADD DL,37H
L7:
MOV AH,2
INT 21H
POP CX
LOOP L5

CMP CX,0
JE EXIT

OVERFLOW:
LEA DX,STRING
MOV AH,9
INT 21H

EXIT:
MOV AH,4CH
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

创建文件abc.txt,并由用户输入不超过128个字符保存。创建文件def.txt,将abc.txt中的内容倒置保存(例如,”abcdef”变为“fedcba”,文件位置自定)

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
DATAS SEGMENT
;此处输入数据段代码
FILE1 DB 'abc.txt',0
HANDLE1 DW ?
FILE2 DB 'def.txt',0
HANDLE2 DW ?
BUFFER DB 256 DUP(0)
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
MOV AH,3CH ;INT 21H的3CH功能
LEA DX,FILE1 ;DX=ASCIIZ串的首地址
MOV CX,0 ;CX=0,普通文件
INT 21H ;新建文件
JC ERROR ;新建不成功,转ERROR
MOV HANDLE1,AX ;成功,保存文件句柄

READ0:
;读入字符
MOV AH,1
INT 21H
CMP AL,0Dh
JZ L1 ;若是回车则结束
MOV AH,40H
MOV BUFFER,AL
LEA DX,BUFFER
MOV BX,HANDLE1
MOV CX,1
INT 21H
JC ERROR ;写入错误

JMP READ0


L1:
;将FILE1的内容放到BUFFER中
MOV BX,AX
MOV CX,255
MOV DX,OFFSET BUFFER
MOV AH,3FH
INT 21H
JC ERROR

;将BUFFER的内容倒置
MOV SI,0
MOV DI,AX
DEC DI

;倒置操作
LOP1:
CMP SI,DI
JAE NEXT
MOV BH,BUFFER[SI]
MOV BL,BUFFER[DI]
MOV BUFFER[SI],BL
MOV BUFFER[DI],BH
INC SI
DEC DI
JMP LOP1

NEXT:
;创建并打开FILE2文件
MOV DX,OFFSET FILE2
MOV CX,0
MOV AH,3CH
INT 21H
JC ERROR
MOV HANDLE2,AX

;将BUFFER的内容写入FILE2中
MOV BX,HANDLE2
MOV DX,OFFSET BUFFER
MOV CX,255
MOV AH,40H
INT 21H

OVER:
;关闭FILE1文件
MOV BX,HANDLE1
MOV AH,3EH
INT 21H

;关闭FILE2文件
MOV BX,HANDLE2
MOV AH,3EH
INT 21H

ERROR:
MOV AH,4CH
INT 21H


EXIT0:
;关闭文件
MOV AH,3EH
MOV BX,HANDLE1
INT 21H
MOV AH,4CH
INT 21H
CODES ENDS
END START

判断数据段中定义的两个数a和b是否互素(ab均为小于10000的正整数),要求编写子程序完成,采用堆栈传递参数。

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
DATA SEGMENT
a DW ?
b DW ?
g DW ?
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA

START:
MOV AX, DATA
MOV DS, AX

; 假设a和b的值已经通过某种方式赋值,这里直接赋值用于演示
MOV a, 9
MOV b, 3

; 调用子程序计算最大公约数
MOV AX, a
MOV BX, b
CALL GCD

; 将计算出的最大公约数存储在gcd变量中
MOV g, CX

; 判断是否互素,即gcd是否为1
MOV CX, 1
CMP g, CX
JE MUTUAL_PRIME

; 如果不是互素,可以在这里添加代码处理
JMP END_PROGRAM

MUTUAL_PRIME:
; 如果是互素,可以在这里添加代码处理

END_PROGRAM:
; 结束程序
MOV AH, 4CH
INT 21H

GCD PROC NEAR ; 计算最大公约数的子程序
MOV CX, BX ; 将b的初始值传给CX,作为辗转相除的初始除数
MOV BX, 0

GCD_LOOP:
MOV DX, 0 ; DX用于存放余数

; AX除以CX,商在AX中,余数在DX中
DIV CX

CMP DX, 0 ; 检查余数是否为0
JE GCD_DONE ; 如果余数为0,退出循环

MOV BX, CX ; 将CX的值传给BX,为下一次迭代做准备
MOV CX, DX ; 将余数DX的值传给CX,作为下一次迭代的除数
JMP GCD_LOOP ; 继续循环

GCD_DONE:
RET ; 返回主程序

GCD ENDP

CODE ENDS
END START

实验八

将用户输入的无符号十进制数(不超过4位)变成十六进制的形式输出测试数据:1234,5,7008,66

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
DATAS SEGMENT
STR1 DB 0AH,'Input decimal number: ','$'
STR2 DB 0AH,'hexadecimal number: ','$'
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX

; 问题
; 将用户输入的无符号十进制数(不超过4位)变成十六进制的形式输出
; 测试数据:1234,5,7008,66

;此处输入代码段代码

CALL INPUT ; 调用读取
CALL CONVERT ; 调用转换
MOV AH,4CH ; 程序结束
INT 21H

INPUT PROC NEAR
LEA DX,STR1 ; 输出提示字符串
MOV AH,09
INT 21H

LEAGAL1:
MOV AH,01H ; 输入,并在屏幕上显示该字符。
INT 21H

CMP AL,'9' ; 比较输入字符合法性
JA EXIT
CMP AL,'0'
JB EXIT

SUB AL,'0'
MOV AH,0H

MOV DX,AX ; 将新数给 DX
MOV AX,BX ; BX 存的是之前的数要去做乘10运算
MOV BX,DX ; 把新数给 BX 在个位 待会儿直接做加法

MOV CX,0AH ; CX的值是10
MUL CX
ADD BX,AX

JMP LEAGAL1

EXIT:
RET
INPUT ENDP

CONVERT PROC NEAR
LEA DX,STR2
MOV AH,09
INT 21H

MOV CH,04H
MOV CL,04H
LOOPC:
ROL BX,CL
MOV AL,BL
AND AL,0fh
ADD AL,30H
CMP AL,'9'
JBE PRINTF
ADD AL,07H

PRINTF:
MOV DL,AL
MOV AH,2
INT 21H
DEC CH
JNE LOOPC

RET
CONVERT ENDP


CODES ENDS
END START

编写程序,用户输入一个字符串,统计其中数字字符之和并输出,例如输入”1a2b3c”则输出6(假设和不会超过四位数,输入以回车结束)测试数据:1a2b3c, #1abcD0w623v9

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
DATAS SEGMENT
;此处输入数据段代码
DB 0
NOTE DB 'Please enter the sentence: ',0DH,0AH,'$'
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX

; 问题
; 编写程序,用户输入一个字符串,统计其中数字字符之和并输出
; 例如输入”1a2b3c”则输出6(假设和不会超过四位数,输入以回车结束)
; 测试数据:1a2b3c, #1abcD0w623v9

;此处输入代码段代码
MOV AH,09H ;输出提示符
MOV DX,OFFSET NOTE
INT 21H

CALL COUNT ;调用统计子程序
CALL print

MOV AH,4CH
INT 21H

COUNT PROC NEAR
INPUT:
MOV AH,01H
INT 21H

CMP AL,0DH
JZ EXIT

CMP AL,'0'
JL INPUT
CMP AL,'9'
JA INPUT

INC BYTE PTR DS:[0]
JMP INPUT

EXIT:
RET
COUNT ENDP

print proc near
mov al,ds:[0]
mov ah,0
mov bx,10
mov cx,0
mov dx,0

legal1:
div bx
push dx
inc cx
cwd
cmp ax,0
jne legal1

legal2:
pop dx
add dl,30h
mov ah,02h
int 21h
loop legal2

mov ah,02h
mov dl,0dh
int 21h

ret
print endp

CODES 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
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
Esc_key		equ		1h
up_key equ 48h
down_key equ 50h
left_key equ 4bh
right_key equ 4dh
delayTime equ 3
BoxX equ 2
BoxY equ 1
SStartX equ 20
SStartY equ 10
BoxHeight equ 20
BoxWidth equ 36
BoxFloor equ 20h
BoxWallV equ 0b0h
BoxWallH equ 0b0h
Fruit equ 0fh
SnakeHead equ 02
SnakeBody equ 0dbh
SnakeLengthX equ (BoxX+BoxWidth)-16
SnakeLengthY equ (BoxY-1)
SnakeColor equ 0Eh
FruitColor equ 0Ah
FloorColor equ 07
WallColor equ 0ch

DATAS SEGMENT
SnakeBodyArray dw BoxHeight*BoxWidth dup (0)
SnakeHeadXY db 0,0
SnakeDir dw 2
FruitXY db 0,0
SnakeLength dw 1
DirTable db 0,-1,0,1,-1,0,1,0
NoThisDir db 1,0,3,2
GameOverStr db 'Game Over$'
GameOverXY db BoxX+5,BoxY-1
NewHeadXY dw 0
FruitFlag db 0
ex_table db up_key,down_key,left_key,right_key
ex_L equ $-offset ex_table
SnakeLengthStr db 'Snake Lenght'
SnakeLengthNum db 0,0,0,'$'
DATAS ENDS

STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START: MOV AX,DATAS
MOV DS,AX
MOV ES,AX
;此处输入代码段代码
mov ax,0013h
int 10h
mov cx,3030h
mov ah,1
int 10h
call DrawBox
call Init
call DrawFruit
j20: call DrawSnake
call DrawScore
mov ax,delayTime
call delay
j30: mov ah,1
int 16h
jnz j40
mov bx,SnakeDir
jmp j50
j40: mov ah,0
int 16h
cmp ah,Esc_key
jz j60
mov al,ah
mov cx,ex_L
mov di,offset ex_table
cld
repnz scasb
jnz j30
sub cx,ex_L-1
neg cx
mov bx,cx
cmp SnakeLength,1
jz j50
mov si,SnakeDir
cmp cl,NoThisDir[si]
jz j30
j50: mov SnakeDir,bx
shl bx,1
call GetHeadXY
mov NewHeadXY,ax
call CheckHead
jnc j20
call GameOver
mov ah,0
int 16h
j60: call Esc_process
;-------------------------------------------------------
DrawBox:xor bh,bh
mov dl,BoxX
mov dh,BoxY
mov ah,02h
int 10h
mov cx,BoxWidth
mov ah,0eh
mov bl,WallColor
@@: mov al,BoxWallV
int 10h
loop @b
mov dl,BoxX
mov dh,BoxY+BoxHeight
mov ah,02h
int 10h
mov cx,BoxWidth
mov ah,0eh
@@: mov al,BoxWallV
int 10h
loop @b
mov si,2
mov dl,BoxX
mov dh,BoxY+1
d20: mov bp,BoxHeight-1
@@: mov ah,02h
int 10h
mov ah,0eh
mov al,BoxWallH
int 10h
inc dh
dec bp
jnz @b
mov dl,BoxX+BoxWidth-1
mov dh,BoxY+1
dec si
jnz d20
ret
;-------------------------------------------------------
GetHeadXY:
mov ax,word ptr SnakeBodyArray
add al,byte ptr DirTable[bx]
add ah,byte ptr DirTable[bx+1]
ret
;-------------------------------------------------------
Esc_process:
mov ax,0003h
int 10h
mov ah,4ch
int 21h
;-------------------------------------------------------
DrawSnake:
lea si,SnakeBodyArray
mov cx,SnakeLength
mov dx,[si]
mov bh,0
mov ah,2
int 10h
mov ah,0eh
mov bl,SnakeColor
mov al,SnakeHead
int 10h
dec cx
jcxz DSx
@@: add si,2
mov dx,[si]
mov ah,2
int 10h
mov ah,0eh
mov al,SnakeBody
int 10h
loop @b
DSx: cmp FruitFlag,1
mov FruitFlag,0
jz DSxx
mov bx,SnakeLength
shl bx,1
mov dx,SnakeBodyArray[bx]
mov bh,0
mov ah,2
int 10h
mov al,BoxFloor
mov ah,0eh
mov bl,WallColor
int 10h
DSxx: ret
;-------------------------------------------------------
DrawFruit:
call Random
mov bx,BoxHeight-1
mov dx,0
div bx
add dx,BoxY+1
mov FruitXY+1,dl
call Random
mov bx,BoxWidth-2
mov dx,0
div bx
add dx,BoxX+1
mov FruitXY,dl
mov bx,0
mov ax,word ptr FruitXY
mov cx,SnakeLength
@@: cmp ax,SnakeBodyArray[bx]
jz DrawFruit
add bx,2
loop @b
mov dl,FruitXY
mov dh,FruitXY+1
mov ah,02h
int 10h
mov ah,0eh
mov bl,FruitColor
mov al,Fruit
int 10h
ret
;-------------------------------------------------------
CheckHead:
mov ax,NewHeadXY
cmp al,BoxX
jbe CheckErr
cmp ah,BoxX+BoxWidth-1
jae CheckErr
cmp ah,BoxY
jbe CheckErr
cmp ah,BoxY+BoxHeight
jae CheckErr
mov cx,SnakeLength
mov bx,SnakeLength
lea si,SnakeBodyArray
dec bx
shl bx,1
add si,bx
lea di,[si+2]
std
rep movsw
cld
mov ax,NewHeadXY
mov SnakeBodyArray,ax
mov bx,2
mov cx ,SnakeLength
dec cx
jcxz CNext
@@: cmp ax,SnakeBodyArray[bx]
jz CheckErr
add bx,2
loop @b
CNext: cmp ax,word ptr FruitXY
jnz CheckOK
call DrawFruit
inc SnakeLength
mov FruitFlag,1
CheckOK:
clc
ret
CheckErr:
stc
ret
;-------------------------------------------------------
DrawScore:
mov dl,SnakeLengthX
mov dh,SnakeLengthY
mov ah,2
mov bh,0
int 10h
mov ax,SnakeLength
lea di,SnakeLengthNum
call print_AX
lea dx,SnakeLengthStr
mov ah,9
int 21h
ret
;-------------------------------------------------------
print_AX:
mov cx,0
mov bx,10
@@: mov dx,0
div bx
push dx
inc cx
or ax,ax
jnz @b
@@: pop ax
or al,30h
stosb
loop @b
ret
;-------------------------------------------------------
GameOver:
mov dx,word ptr GameOverXY
mov bh,0
mov ah,2
int 10h
lea dx,GameOverStr
mov ah,9
int 21h
ret
;-------------------------------------------------------
Init: mov al,BoxX+SStartX
mov ah,BoxY+SStartY
mov SnakeBodyArray,ax
inc al
mov SnakeBodyArray+2,ax
mov NewHeadXY,ax
mov SnakeLength,1
ret
;-------------------------------------------------------
delay:
push es
push dx
mov dx,40h
mov es,dx
mov dx,es:[006ch]
add dx,ax
@@: cmp es:[006ch],dx
jbe @b
pop dx
pop es
ret
;-------------------------------------------------------
Random: ;(Return AX:0-65535)
db 0fh,31h
mov cx,ax
@@: xchg ah,al
loop @b
ret
;-------------------------------------------------------
;此处输入代码段代码
CODES 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
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
DATAS SEGMENT
len_left dw 0;哪里开始打印
len_right dw 0;哪里结束打印
COLUMN_A dw 0,100 dup(?);表示当前柱子上有哪几个盘
COLUMN_B dw 0,100 dup(?);表示当前柱子上有哪几个盘
COLUMN_C dw 0,100 dup(?);表示当前柱子上有哪几个盘
tip db 'input n:',0ah,0dh,'$' ;提示
n db 0 ;多少n个盘子
tempn db 0;临时存放N值
nowA dw 1;当前A对应哪个柱子
nowB dw 2;当前B对应哪个柱子
nowC dw 3;当前C对应哪个柱子
mover dw 0;偏移位置
flag dw 0
DATAS ENDS
STACKS SEGMENT
dw 80 dup(?)
STACKS ENDS
;**************************************************************
;如果需要调节速度,请到最下方的子程序sleep中调节
;7,8层以上推荐将dx设置为1
;递归中没有使用栈放参数,不会轻易出现栈溢出
;请输入十进制的数,并输入回车结束
;18层以上的效果将显示不完整或者不完美
;**************************************************************
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
main proc far
START:
push ds
sub ax,ax
push ax
mov bx,0
mov ax,DATAS
mov ds,ax;DOS返回数据
lea dx,tip
mov ah,09h;显示提示
int 21h
input:
mov ah,1
int 21h;接受输入
cmp al,0DH
jz InputOver
sub al,30h
mov bl,al
xor bh,bh
xor ax,ax
mov al,n
mov cl,10
mul cl
add ax,bx
mov n,al
jmp input
InputOver:
;初始化
call init
mov ah,0;变更模式
mov al,13h; 模式13h,把屏幕分成320*200像素,256色
int 10h
call Print
call hanoi
ret
main endp
;------------------------------------------------------------------
hanoi proc near
push ax
xor ah,ah
mov al,n
cmp ax,1
jnz dfs
call move
call Print
jmp dfsOver
dfs:
call Store1
call hanoi
call REC1
call Store3
call hanoi
call REC3
call Store2
call hanoi
call REC2
dfsOver:
pop ax
ret
hanoi ENDP
;------------------------------------------------------------------
move PROC FAR
push ax
push bx
push si
push di
push dx
mov ax,nowA
mov bx,nowC
;si
cmp ax,1
jnz exitJudnowA_1
lea si,COLUMN_A
jmp exitJudnowA
exitJudnowA_1:
cmp ax,2
jnz exitJudnowA_2
lea si,COLUMN_B
jmp exitJudnowA
exitJudnowA_2:
lea si,COLUMN_C
exitJudnowA:
;di
cmp bx,1
jnz exitJudnowC_1
lea di,COLUMN_A
jmp exitJudnowC
exitJudnowC_1:
cmp bx,2
jnz exitJudnowC_2
lea di,COLUMN_B
jmp exitJudnowC
exitJudnowC_2:
lea di,COLUMN_C
exitJudnowC:
;结束
mov ax,[si]
mov bx,[di]
add ax,ax
add bx,bx
add bx,2
mov mover,ax
add si,mover
mov dx,[si]
sub si,mover
add di,bx
mov [di],dx
sub di,bx
mov dx,[di]
inc dx
mov [di],dx
mov dx,[si]
dec dx
mov [si],dx
pop dx
pop di
pop si
pop bx
pop ax
ret
move ENDP
;------------------------------------------------------------------
Print PROC FAR
push ax
push bx
push cx
push dx
push si
mov ax,flag
jnz no
call Clear_page;清除缓冲区
mov flag,1
no:
mov dx,180
mov cx,50
lea si,COLUMN_A
mov bx,[si]
PrintA:
cmp bx,0
jz exitA
push bx
push ax
add si,2
mov ax,[si]
xor bx,bx
mov bl,2
mul bl
mov cx,50
sub cx,ax
sub cx,5
mov len_left,cx
mov cx,50
add cx,ax
add cx,5
mov len_right,cx
pop ax
pop bx
mov cx,len_left
PrintA_1:
mov al,5
mov ah,0ch
call Draw_dot ;调用绘点子程序
inc cx
cmp cx,len_right
jbe PrintA_1
sub dx,5
sub bx,1
jnz PrintA
exitA:
mov dx,180
lea si,COLUMN_B
mov bx,[si]
PrintB:
cmp bx,0
jz exitB
push bx
push ax
add si,2
mov ax,[si]
xor bx,bx
mov bl,2
mul bl
mov cx,150
sub cx,ax
sub cx,5
mov len_left,cx
mov cx,150
add cx,ax
add cx,5
mov len_right,cx
pop ax
pop bx
mov cx,len_left
PrintB_1:
mov al,5
mov ah,0ch
call Draw_dot ;调用绘点子程序
inc cx
cmp cx,len_right
jbe PrintB_1
sub dx,5
sub bx,1
jnz PrintB
exitB:
mov dx,180
lea si,COLUMN_C
mov bx,[si]
PrintC:
cmp bx,0
jz exitC
push bx
push ax
add si,2
mov ax,[si]
xor bx,bx
mov bl,2
mul bl
mov cx,250
sub cx,ax
sub cx,5
mov len_left,cx
mov cx,250
add cx,ax
add cx,5
mov len_right,cx
pop ax
pop bx
mov cx,len_left
PrintC_1:
mov al,5
mov ah,0ch
call Draw_dot ;调用绘点子程序
inc cx
cmp cx,len_right
jbe PrintC_1
sub dx,5
sub bx,1
jnz PrintC
exitC:
;打印柱子
;------------------------------------------------------------------
mov cx,50
mov dx,50
printCOLUMN1:
mov al,6
mov ah,0ch
call Draw_dot ;调用绘点子程序
inc dx
cmp dx,180
jbe printCOLUMN1
add cx,100
mov dx,50
printCOLUMN2:
mov al,6
mov ah,0ch
call Draw_dot ;调用绘点子程序
inc dx
cmp dx,180
jbe printCOLUMN2
add cx,100
mov dx,50
printCOLUMN3:
mov al,6
mov ah,0ch
call Draw_dot ;调用绘点子程序
inc dx
cmp dx,180
jbe printCOLUMN3
call move_page ;搬动图像覆盖之前图像的子程序
;------------------------------------------------------------------
pop si
pop dx
pop cx
pop bx
pop ax
RET
Print ENDP
;------------------------------------------------------------------
Store1 proc near
push ax
push bx
mov ax,nowB
mov bx,nowC
mov nowB,bx
mov nowC,ax
dec n
pop bx
pop ax
ret
Store1 endp
REC1 proc near
push ax
push bx
mov ax,nowB
mov bx,nowC
mov nowB,bx
mov nowC,ax
INC N
pop bx
pop ax
ret
REC1 endp
;------------------------------------------------------------------
Store2 proc near
push ax
push bx
mov ax,nowA
mov bx,nowB
mov nowA,bx
mov nowB,ax
dec n
POP bx
POP ax
ret
Store2 endp
REC2 proc near
push ax
push bx
mov ax,nowA
mov bx,nowB
mov nowA,bx
mov nowB,ax
INC N
POP bx
POP ax
ret
REC2 endp
;------------------------------------------------------------------
Store3 proc near
push ax
xor ax,ax
mov al,n
mov tempn,al
mov n,1
POP ax
ret
Store3 ENDP
REC3 proc near
push ax
xor ax,ax
mov al,tempn
mov n,al
POP ax
ret
REC3 ENDP
;------------------------------------------------------------------
init proc near
;下面开始初始化三个数
mov ax,DATAS
mov DS,ax
lea si,COLUMN_A
xor ah,ah
mov al,n
mov [si],ax
xor cx,cx
mov cl,n
initCOLUMNA:
add si,2
mov [si],cx
loop initCOLUMNA
ret
init endp
;-------------------------------------------------------
.286;启用286指令,pusha,popa用
;模拟ah=0Ch绘点至缓缓区
Draw_dot:
pusha;保存所有寄存器
push es ;保存ES
cld;清除方向, stosb,movsw等指示方向
mov di,ax ;保存al中的颜色
cmp ah,0Ch ;是否0ch函式
jnz SimX ;不是,离开
mov ax,0B000h ;缓冲段
mov es,ax ;es=ax
mov ax,320 ;一行长度(像素)
mov bx,dx ;
mul bx ; x320
add ax,cx ; 加列 (像素)
xchg di,ax ;交换al取回颜色, di=图点在缓冲段的相对位置
stosb ;es:[di] = al ; 存图点
SimX:
pop es ;取回es
popa ;取回所有寄存器
ret
;------------------------------------------------------------------
Clear_page:
;清除缓冲区资料子程序
pusha ;保存所有寄存器
push es ;保存ES
cld ;清除方向, stosb,movsw等指示方向
mov ax,0B000H ;缓冲区地址
mov es,ax
mov cx,320*200 / 2 ;长度
mov ax,0000h
mov di,0
rep stosw ;重覆cx次,es:[di]=ax,每次di+2
pop es ;取回es
popa ;取回所有暂存器
ret
;------------------------------------------------------------------
move_page:
;一次搬移缓冲区(B000)图点资料至显示区(A000)
pusha ;保存所有寄存器
push ds ;保存DS
push es ;保存ES
cld ;清除方向, stosb,movsw等指示方向
mov ax,0B000H ;来源
mov ds,ax
mov ax,0A000H ;目的
mov es,ax
mov cx,320*200 / 2 ;长度
xor si,si ;起始地址
xor di,di ;起始地址
rep movsw ;由ds:si 搬移 cx 次到 es:di , 每次si+2, di+2
pop es ;取回es
pop ds ;取回ds
popa
ret
;------------------------------------------------------------------
CODES ENDS
end