目录
一、顺序程序设计
举例:利用学号查询学生数学成绩表。
程序流程:
源程序:
DSEG SEGMENT
TABLE DB 81, 78, 90, 64, 85, 76, 93, 82, 57, 80
DB 73, 62, 87, 77, 74, 86, 95, 91, 82, 71
NUM DB 8 ; 存放学号
MATH DB ? ; 存放成绩
DSEG ENDS
SSEG SEGMENT STACK
DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
MOV AX, DSEG
MOV DS, AX
MOV BX, OFFSET TABLE
MOV AH, 0 ; 否则BX+AX时AH内容是随机的
MOV AL, NUM ; 将学号送入AL
DEC AL ; 偏移量=学号-1
ADD BX, AX ; 不能BX+AL
MOV AL, [BX] ; 查到成绩送入AL
MOV MATH, AL ; 存储器之间不能直接传送
MOV AH, 4CH ; 返回DOS
INT 21H
CSEG ENDS
END START
二、分支程序设计
1. 用比较/测试命令+条件转移指令实现分支
(1)单分支结构
举例:计算字单元 DMem 中带符号数的绝对值,并将结果存储于数据段 RESULT 中。
程序流程:
源程序:
DSEG SEGMENT
DMem DW -5
RESULT DW 0
DSEG ENDS
SSEG SEGMENT STACK
DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
MOV AX, DSEG
MOV DS, AX
MOV AX, DMem
CMP AX, 0 ; 比较/测试
JGE NOTNEG
NEG AX ; 特殊处理:负数需要求补
NOTNEG:
MOV RESULT, AX ; 共同事务:将数的绝对值存储到数据段
MOV AH, 4CH ; 返回DOS
INT 21H
CSEG ENDS
END START
需要注意的是,条件满足时转移,否则执行下一条语句。
; 另一种写法
CMP AX, 0 ; 比较/测试
JL ISNEG
JMP NOTNEG
ISNEG: ; 为负
NEG AX
NOTNEG: ; 为正
MOV RESULT, AX
因此,需要合理选择分支条件,同时理解与高级语言的差别。
(2)双分支结构
举例:编写一个能够显示 BX 二进制最高位的程序段。
程序流程:
源程序:
DSEG SEGMENT
DSEG ENDS
SSEG SEGMENT STACK
DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
MOV AX, DSEG
MOV DS, AX
SHL BX, 1 ; 左移得到最高位
JC ONE ; 比较/测试
MOV DL, '0' ; 程序段1
JMP DISPLAY
ONE:
MOV DL, '1' ; 程序段2
DISPLAY:
MOV AH, 2 ; 共同事务
INT 21H
MOV AH, 4CH ; 返回DOS
INT 21H
CSEG ENDS
END START
另一种写法:
AND BX, 8000H
JNZ ONE ; 比较/测试
MOV DL, '0' ; 程序段1
JMP DISPLAY
ONE:
MOV DL, '1' ; 程序段2
DISPLAY:
MOV AH, 2 ; 共同事务
INT 21H
2. 采用跳转表实现多路分支
举例:设某程序有 10 路分支,分别为:BRAND1、BRAND2、...、BRAND10 。试根据变量 N 的值(1~10),将程序转移到其中的一路分支去。
根据 N 的值形成查表地址:(N−1) * 2 + 表首址
程序流程:
源程序:
DSEG SEGMENT
ATABLE DW BRAND1, BRAND2, BRAND3, BRAND4, BRAND5
DW BRAND6, BRAND7, BRAND8, BRAND9, BRAND10
N DB 3
DSEG ENDS
SSEG SEGMENT STACK
DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
MOV AX, DSEG
MOV DS, AX
MOV AH, 0 ; 否则BX+AX时AH内容是随机的
MOV AL, N ; 送入变量N
DEC AL ; N-1
SHL AL, 1 ; 2*(N-1),SAL也可
MOV BX, OFFSET ATABLE
ADD BX, AX
MOV DX, [BX]
JMP DX ; 转移到N对应的分支入口地址
BRAND1: ...
JMP FINAL
BRAND2: ...
JMP FINAL
...
BRAND10: ...
JMP FINAL
FINAL: ...
MOV AH, 4CH ; 返回DOS
INT 21H
CSEG ENDS
END START
三、循环程序设计
1. 计数循环程序设计
举例:计算 1~100 数字之和,并将结果存入字变量 SUM 的程序段。
LOOP:① CX - 1 ② 判断 CX 是否为 0
MOV AX, 0 ; 初始化
MOV CX, 100 ; 初始化
AGAIN: ; 循环体
ADD AX, CX
LOOP AGAIN ; 控制条件
MOV SUM, AX ; 处理结果
2. 条件判断循环程序设计
举例:数据段的 ARY 字节数组中存放有 10 个无符号数,试找出其中最大者送入 MAX 字节单元。
程序流程:
源程序:
DSEG SEGMENT
ARY DB 17, 5, 40, 0, 67
DB 12, 34, 78, 32, 10
MAX DB ?
DSEG ENDS
SSEG SEGMENT STACK
DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
MOV AX, DSEG
MOV DS, AX
MOV SI, OFFSET ARY ; 初始化
MOV CX, 9 ; 初始化
MOV AL, [SI] ; 初始化
LOP:
INC SI
CMP AL, [SI]
JAE BIGGER
MOV AL, [SI]
BIGGER:
DEC CX
JNZ LOP ; 控制条件
MOV MAX, AL ; 处理结果
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
四、子程序设计
-
子程序是程序的一部分,是完成特定功能的程序段,它能够在程序中的任何地方被调用。
-
子程序的调用与返回是由指令 CALL 和 RET 来完成的。
-
子程序中一般都要使用寄存器,除了要返回参数的寄存器外,在子程序设计的开始部分,要将用到的寄存器进行压栈保存,在子程序结束返回调用程序之前要进行出栈恢复。
-
子程序和调用程序直接的信息传送称为参数传递。
1. 子程序设计举例
举例:实现一个显示回车和换行功能的子程序。
先完成主要程序,再看需要用到哪些寄存器。
DISPLAY PROC
; 压栈保存
PUSH AX
PUSH DX
MOV DL, 0DH
MOV AH, 2
INT 21H
MOV DL, 0AH
MOV AH, 2
INT 21H
; 出栈恢复
POP DX
POP AX
RET
DISPLAY ENDP
2. 主程序和子程序设计举例
举例:将两个给定的二进制数 BIN1 和 BIN2(8 位和 16 位)逐位转换为 ASCII 码字符串,并存储于 ASCBUF 中。
程序流程:
源程序:
DSEG SEGMENT
BIN1 DB 35H
BIN2 DW 0AB48H
ASCBUF DB 20H DUP(?)
DSEG ENDS
SSEG SEGMENT STACK
DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
MOV AX, DSEG
MOV DS, AX
XOR DX, DX ; DX清零
LEA DI, ASCBUF ; 给出存放结果的首址
MOV DH, BIN1 ; 给出待转换的数据
MOV CX, 8 ; 给出转换的位数
CALL BINASC ; 调用转换子程序
LEA DI, ASCBUF+8
MOV DX, BIN2
MOV CX, 16
CALL BINASC
BINASC PROC
PUSH AX
LOP:
ROL DX, 1
MOV AL, DL
AND AL, 1 ; 保留最低位,屏蔽其它位
ADD AL, 30H ; 获取ASCII码
MOV [DI], AL ; 存放结果
INC DI ; 修改指针
LOOP LOP ; 修改计数,控制循环
POP AX
RET
BINASC ENDP
MOV AH, 4CH
INT 21H
CSEG ENDS
END START
子程序流程:
原理说明:为了适配 8 位和 16 位,统一使用 DX 寄存器进行循环移位。
子程序部分:
BINASC PROC
PUSH AX
LOP:
ROL DX, 1
MOV AL, DL
AND AL, 1 ; 保留最低位,屏蔽其它位
ADD AL, 30H ; 获取ASCII码
MOV [DI], AL ; 存放结果
INC DI ; 修改指针
LOOP LOP ; 修改计数,控制循环
POP AX
RET
BINASC ENDP