五、实验步骤
1、请自行编写或上述参考代码,补充重要操作注释,编译链接执行、详细记录各操作步骤并截图。
1)编制在屏幕上显示九九乘法表的程序。
1. 用文字编辑工具(记事本或EDIT)将源程序输入,其扩展名为jiujiu.ASM。将源文件放到Dosbox挂载的目录下面。
源程序:
;定义数据段
DATA SEGMENT
S2 DB ?
S1 DB ?
X DB 1 ;定义变量X,值为1
Y DB 1 ;定义变量Y,值为1
S DB 0AH ;定义变量S,值为0AH
FCH=2AH ;定义常量FCH,值为2AH
FDH=3DH ;定义常量FDH,值为3DH
FKG=20H ;定义常量FKG,值为20H
FHH=0AH ;定义常量FHH,值为0AH
FHC=0DH ;定义常量FHC,值为0DH
DATA ENDS
;定义堆栈段,大小为20H,初始值为0
STACK1 SEGMENT STACK
DB 20H DUP(0)
STACK1 ENDS
;定义代码段
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK1
START:MOV AX,DATA ;将数据段地址存入AX寄存器中
MOV DS,AX ;将AX寄存器中的地址存入DS寄存器中
MOV CL,9 ;赋值9给CL寄存器
;循环Y次
LL1:
PUSH CX ;将CL压入堆栈段
MOV CL,Y ;将Y的值存入CL寄存器中
LL2:
CALL L1 ;调用子程序L1
INC X ;x++
LOOP LL2 ;循环执行LL2,直到CX寄存器的值为0
MOV X,1 ;x=1
INC Y ;Y++
MOV DL,FHH ;输出换行和回车
MOV AH,2
INT 21H
MOV DL,FHC
MOV AH,2
INT 21H
POP CX ;从堆栈段中取出CL
LOOP LL1 ;循环执行LL1,直到CX寄存器的值为0
MOV AH,4CH ;程序结束
INT 21H
L1 PROC ;计算X*Y=Z并且输出X*Y=Z的子程序
MOV DL,X ;将X的值存入DL寄存器中
ADD DL,30H ;将DL寄存器中的值加30H,转换成ASCII码字符
MOV AH,2 ;将输出函数号码存入AH寄存器中
INT 21H ;调用输出函数
MOV DL,FCH ;将FCH常量的值存入DL寄存器中
MOV AH,2
INT 21H
MOV DL,Y ;将Y的值存入DL寄存器中
ADD DL,30H ;将DL寄存器中的值加上30H,转换成ASCII码字符
MOV AH,2
INT 21H
MOV DL,FDH ;将FDH常量的值存入DL寄存器中
MOV AH,2
INT 21H
MOV AL,X ;将X的值存入AL寄存器中
MUL Y ;将AL寄存器中的值乘Y,并将结果存入AX寄存器中
DIV S ;将AX寄存器中的值除S的值,并将商存入AL寄存器中,余数丢弃
MOV S1,AH ;将AX寄存器中的余数部分存入S1变量中
ADD AL,30H ;将AL寄存器中的值加上30H,转换成ASCII码字符
MOV DL,AL
MOV AH,2
INT 21H
ADD S1,30H ;将s1加上30H,转换成ASCII码字符
MOV DL,S1
MOV AH,2
INT 21H
MOV DL,FKG ;输出空格
MOV AH,2
INT 21H
RET
L1 ENDP ;子程序结束
CODE ENDS
END START
图5-1更改扩展名为jiujiu.ASM
- 用MASM对源文件进行汇编,产生OBJ文件和LST文件。
图5-2 MASM对源文件进行汇编
图5-3 OBJ文件和LST文件
- 用LINK将.OBJ文件连接成可执行的.EXE文件。
图5-4 link语句执行过程
图5-5 LINK将.OBJ文件连接成可执行的.EXE文件
4. 在DOS状态下运行LINK产生的.EXE文件。
图5-6 运行结果
2) 编制在屏幕上显示用*组成的三角形的程序。
1. 用文字编辑工具(记事本或EDIT)将源程序输入,其扩展名为sanjiao.ASM。将源文件放到Dosbox挂载的目录下面。
源程序:
DATA SEGMENT ; 数据段
N DB ? ; 存储输入的行数
FCH=2AH ; '*' 的 ASCII 码
FDH=3DH ; '=' 的 ASCII 码
FKG=20H ; ' ' 的 ASCII 码
FHH=0AH ; 换行的 ASCII 码
FHC=0DH ; 回车的 ASCII 码
DATA ENDS ;数据段结束
STACK1 SEGMENT STACK
DB 20H DUP(0)
STACK1 ENDS
CODES SEGMENT ;定义代码段
ASSUME CS:CODES,DS:DATA
START:
MOV AX,DATA ;将数据段地址存入AX寄存器中
MOV DS,AX
MOV AH,1 ;输入一位16进制数确定输出行数
INT 21H
CMP AL,39H ;判断输入的数是否小于等于39H
JBE L1 ;如果是,跳转到L1标签;如果不是,将输入的数减去7,得到对应的行数
SUB AL,07H
L1:
SUB AL,30H
MOV N,AL
XOR BX,BX ;清零BX寄存器
MOV DL,FCH
MOV CL,N
MOV DL,FHH ;输出换行和回车
MOV AH,2
INT 21H
MOV DL,FHC
MOV AH,2
INT 21H
LOP:PUSH CX ;将CX寄存器的值压入堆栈段中
INC BL ;将BL寄存器的值加1
MOV CL,BL
MOV DL,FCH
LOP2:MOV AH,02H
INT 21H
LOOP LOP2 ;循环执行LOP2,直到CX寄存器的值为0
POP CX ;从堆栈段中取出CX寄存器的值
MOV DL,0AH ;输出换行符和回车符
MOV AH,02H
INT 21H
MOV DL,FHC ;输出空格字符和回车符
MOV AH,02H
INT 21H
CMP BL,9 ;判断BL寄存器的值是否为9
JZ L2 ;如果是,跳转到L2标签;如果不是,继续执行LOP循环
LOOP LOP
L2:MOV AH,4CH ;程序结束
INT 21H
CODES ENDS
END START
图5-7更改扩展名为sanjiao.ASM
- 用MASM对源文件进行汇编,产生OBJ文件和LST文件。
图5-8 MASM对源文件进行汇编
图5-9 OBJ文件和LST文件
- 用LINK将.OBJ文件连接成可执行的.EXE文件。
图5-10 link语句执行过程
图5-11 LINK将.OBJ文件连接成可执行的.EXE文件
4. 在DOS状态下运行LINK产生的.EXE文件。
图5-12 运行结果
2、(选做)自行编写杨辉三角输出代码,补充重要操作注释,编译链接执行、详细记录各操作步骤并截图。
1. 用文字编辑工具(记事本或EDIT)将源程序输入,其扩展名为yanghui.ASM。将源文件放到Dosbox挂载的目录下面。
源程序:
STACK1 SEGMENT STACK ;堆栈段
DB 20H DUP(0)
STACK1 ENDS
CODE SEGMENT ;代码段
ASSUME CS:CODE,DS:CODE
ORG 100H
START: JMP BEGIN
MESSAGE DB 13,10,9,'n(1~9): $' ;输入1~9之间任意一个数 将会生成n行杨辉三角
BEGIN:
PUSH CS
POP DS
MOV DX,OFFSET MESSAGE ;提示上面的输入信息:n(1~9):
MOV AH,9
INT 21H
CALL GETMESSAGE ;调用输入程序
CMP BP,10 ;输入的数和10作比较
JBE GO ;小于等于10跳转至GO
GO:
MOV AX,0E0DH
INT 10H
MOV AL,0AH
INT 10H
PUSH BP
CALL YANGHUI ;调用输出n行杨辉三角
GETMESSAGE PROC ;输入n 程序
PUSH CX
PUSH BX
XOR BP,BP
MOV BX,10
MOV CX,2
INPUTME:
MOV AH,0 ;键盘输入数据
INT 16H
CMP AL,0DH ;回车结束输入
JZ OK
CMP AL,'1' ;限制输入1~9
JB INPUTME
CMP AL,'9'
JA INPUTME
MOV AH,0EH
INT 10H
SUB AL,31H ;转化ASCII为16进制
CBW ;字节扩展为字
XCHG AX,BP
MUL BX ;扩大10倍
ADD BP,AX
LOOP INPUTME
OK: NOP ;数值结果在BP中
;恢复用到的寄存器
POP BX
POP CX
RET
GETMESSAGE ENDP
; 输出N行杨辉三角
YANGHUI:
MOV BP, SP
MOV AX, [BP+2] ; 保存N到AX
SHR AX, 1 ; N = N / 2
PUSH AX
MOV AX, [BP+2] ; 保存N到AX
PUSH AX
CALL C ; C(N, N/2)获取最后一行中间的那个值,即最大值
CALL GETDIMAX ; 计算最大值的长度
MOV CX, AX
XOR DI, DI ; 外层循环输出每一行
JMP LOOP1
UPDI:
INC DI ; 更新DI
LOOP1:
CMP DI, [BP+2] ; 循环N次
JG RE
MOV AX, [BP+2] ; 计算行前空格数' ' = (N-i)*CL
SUB AX, DI
MUL CL ;CL是最大长度
CALL SHOWYVSPACE ; 输出行前空格
XOR SI, SI ; 内层循环输出一行中的每个数
JMP LOOP2
UPSI:
INC SI ; 更新SI
LOOP2:
CMP SI, DI ; 循环DI次
JG ENTER
PUSH SI
PUSH DI
CALL C ; 获取该行的位于SI位置的组合数,调用C(DI, SI)
PUSH AX ; 保存该组合数
CALL SHOWYV ; 输出该组合数
MOV AX, CX ;输出数字间空格,个数 = N - 1
SUB AX, 1 ;
CALL SHOWYVSPACE ;
POP AX ;
CALL GETDIMAX ;获取该组合数长度
MOV BX, AX ;
MOV AX, CX ;
SUB AX, BX ;需要填充的空格数 = 最大长度 - 该数长度 + 1
ADD AX, 1 ;
CALL SHOWYVSPACE ;
JMP UPSI ; 更新内层循环
ENTER: ; 实现换行
MOV AH, 2
MOV DL, 13
INT 21H
MOV DL, 10
INT 21H
JMP UPDI ; 更新外层循环
RE:
RET 2 ; 释放栈
; { C(n, m) = 1 (n < m 或 m = 0)
; { C(n, m) = C(n-1, m-1) + C(n-1, m) (n > m)
C:
PUSH BP
MOV BP, SP
SUB SP, 2
MOV BX, [BP+6] ; 保存m到BX
CMP BX, [BP+4] ; 如果m > n 返回1
JZ RETURN1
CMP BX, 0 ; 如果m = 0 返回1
JZ RETURN1
MOV AX, [BP+4] ; 保存n到AX
DEC AX ; AX--
DEC BX ; BX--
PUSH BX
PUSH AX
CALL C ; 返回上一行左边的那个数
MOV [BP-2], AX ; 保存上一行左边的数
MOV AX, [BP+4] ; 返回上一行右边的数
DEC AX
PUSH [BP+6]
PUSH AX
CALL C
ADD AX, [BP-2] ; 和左上的数相加得出该组合数
JMP RES
RETURN1:
MOV AX, 1
RES:
MOV SP, BP
POP BP
RET 4 ; AX返回组合数
; 递归输出AX
; 求出余数,AX = AX / 10
; AX = 0时退出,开始逆序输出求出的各位余数
SHOWYV:
MOV BX, 10
CMP AX, 0
JZ OK1
DIV BL
PUSH AX
AND AX, 00FFH
CALL SHOWYV
POP DX
MOV DL, DH
OR DL, 30H
MOV AH, 2
INT 21H
OK1:
RET
; 获取一个数的长度,AX为参数
GETDIMAX:
MOV BX, 10
XOR DX, DX
NEXT:
CMP AX, 0
JLE OK2
DIV BL
AND AX, 0FFH
INC DX
JMP NEXT
OK2:
MOV AX, DX
RET
; 输出AX个空格
SHOWYVSPACE:
MOV BX, AX
MOV AH, 2
MOV DL, ' '
NEXTS:
CMP BX, 0
JLE OVER
INT 21H
DEC BX
JMP NEXTS
OVER:
RET
CODE ENDS
END START
图5-13更改扩展名为sanjiao.ASM
- 用MASM对源文件进行汇编,产生OBJ文件和LST文件。
图5-14 MASM对源文件进行汇编
图5-15 OBJ文件和LST文件
- 用LINK将.OBJ文件连接成可执行的.EXE文件。
图5-16 link语句执行过程
图5-17 LINK将.OBJ文件连接成可执行的.EXE文件
4. 在DOS状态下运行LINK产生的.EXE文件。
图5-18 运行结果