第六节 汇编语言程序设计一、概述
1,编写汇编语言程序步骤
2,判断程序质量的标准
3,几种程序结构二,汇编语言程序设计举例例 1 将寄存器 BX中的内容以十六进制形式显示出来 。
例 2 将键盘输入的十进制数据串转换成其相应大小的数值存放在 BX寄存器中 。
一,概述
1,编写汇编语言程序步骤
2,判断程序质量的标准
3,几种程序结构一,编写汇编语言程序步骤
分析实际问题,抽象描述问题的模型
确定解决模型的算法
按算法画出程序流程图
按流程图编写程序
上机调试,运行程序
2,判断程序质量的标准
程序的正确性
程序的可读性
程序的执行时间
程序所占内存大小
3,几种程序结构
顺序结构
分支结构
循环结构
子程结构顺序结构两个分支
Y
N
、、、
CMP AL,BL
JG great
JMP exit
great:
exit:,、、
、、、
AL≤BL处理
AL>BL处理分支结构三个分支
、、、
CMP AL,0
JG great
JL less
JMP exit
less:
JMP exit
great:
exit:,、、
AL=0处理
AL>0处理
AL<0处理
Y
Y
N
N
分支结构循环结构当型循环
(当条件成立进入循环 )
循环初始设置循环体循环条件判断?
Y
N
直到型循环
(直到条件成立退出循环 )
Y
N
循环初始设置循环体循环条件判断?
1,多处调用完成同一功能的子程:
code SEGMENT
start:,、
CALL sub
、、
CALL sub
、、
CALL sub
、、
MOV AH,4CH
INT 21H
sub PROC
、、
、、
RET
sub ENDP
code ENDS
END start
2,模块化程序设计:
code SEGMENT
begin,CALL sub1
CALL sub2
CALL sub3
MOV AH,4CH
INT 21H
sub1 PROC
、、
RET
sub1 ENDP
sub2 PROC
、、
RET
sub2 ENDP
sub3 PROC
、、
RET
sub3 ENDP
code ENDS
END begin
子程结构注意返回 DOS语句位置思考如下程序的执行流程,
code SEGMENT
start:,、
CALL sub
、、
CALL sub
、、; MOV AH,4CH; INT 21H
sub PROC
、、
、、
RET
sub ENDP
MOV AH,4CH
INT 21H
code ENDS
END start
程序执行不到返回 DOS功能调用处,
最后的结果是死机,
二,汇编语言程序设计举例例 1 将寄存器 BX中的内容以十六进制形式显示出来 。
例 2 将键盘输入的十进制数据串转换成其相应大小的数值存放在 BX寄存器中 。
▲ 有关字符,数码转换的处理
1,计算机处理字符时,常用的字符编码是 ASCII 码 。
2,数字和字母的 ASCII码是一个有序序列数字 0~9,30H ~ 39H
大写字母 A~Z,41H ~ 5AH
小写字母 a~z,61H ~ 7AH
3.计算机处理信息时,其对象都是二进制数 。
外设 (显示器,打印机,键盘等 )用 ASCII码与 CPU进行信息传送 。
例如,1) 在键盘上按下某一字符键 (如 ’ 9’),键盘接口向键盘缓冲区送去的是该字符的 ASCII码 (如 39H),
不是送数字 09H。
2) 在文本方式下,要在显示器上显示某一字符 (如 ’ A’),
须将该字符的 ASCII码 (如 41H)送显示缓冲区,
不是送数字 0AH。
▲ 计算机要利用显示器,键盘等外设时,
须据程序设计的需要进行有关转换 。
例 将 CPU运算的结果通过显示器显示时,
需将结果转换成其对应的 ASCII码才能进行显示 。
显示缓冲区存放的内容
( 字符的 A S C II 码 )
CPU 运算后所得的二进制数
1 0 1 0 1 0 0 1
十六进制形式显示
41 h,39 h
显示 ’ A9 ’
十进制形式显示
31 h,36 h,39 h
显示 ’ 169 ’
( 无符号数 )
2D h,38 h,37 h
显示 ’ - 87 ’
( 带符号数 )
二进制形式显示
31 h,30 h,31 h,30 h,31 h,30 h,30 h,31 h
显示 ’ 1 010 100 1 ’
例 1
前例例 CPU要处理从键盘输入的某一数据,
需将该数据串进行转换后才能应用 。
CPU 处理时从键盘输入 ’ 1 234 ’,缓冲区存放
31H,32H,33H,34H
看作十六进制数输入 1234H
看作十进制数输入 04D2H
例 2
例 1 将 BX寄存器中的内容以十六进制形式显示出来 。
▲ BX是一个 16位寄存器二进制 1010 1001 0011 1110
▲ 用十六进显示时,每 4位用一个字符显示,共 4个其中 0000 →’ 0’ 30H,1010 →’A’ 41H
0001 →’ 1’ 31H,1011 →’B’ 42H
、、,、
1001 →’ 9’ 39H,1111 →’F’ 46H
十六进制 A 9 3 E 屏幕上的显示 ‘ A’ ‘9’ ‘3’ ‘E’ 对应的 ASCII 41H 39H 33H 45H
算法,
取出要显示的某 4位,转换为对应的 ASCII码,
再调用 DOS系统功能进行显示 。
1) 对于 0000~1001,先扩展成一个字节,高 4位清 0,
加上 30H后,即可得字符’ 0’~’9’对应的 ASCII码。
0000 0001B + 30H= 31H 0000 1001B + 30H=39H
0001B ‘1’ 1001B ‘9’
2) 对于 1010~1111,先扩展成一个字节,高 4位清 0,
加上 30H后,还要再加上 07H,才能得到’ A’~’F’ 对应的 ASCII码
0000 1010B+30H+07H = 41H 0000 1111B+30H+07H =46H
1010B ‘A’ 1111B ‘F’
code SEGMENT
ASSUME CS:code
start,MOV CH,4 ;字符个数
MOV CL,4 ;循环移位次数
next,ROL BX,CL ;取显示位的值
MOV DL,BL ;保存在 DL中
AND DL,0FH ;清除高 4位
ADD DL,30H ;转变为数字的 ASCII
CMP DL,39H ;大于 39H,则应转变
JLE print ;为字母 A~F的 ASCII
ADD DL,07H
print,MOV AH,2H ;显示 DL中的字符
INT 21H
DEC CH ;显示结束?
JNZ next
MOV AH,4CH ;返回 DOS
INT 21H
code ENDS
END start
显示字符个数 CH=4
循环移位次数 CL=4
BX循环左移 4位,将要显示的值移至低 4位,保存在 DL中清 DL 的高 4位,
只保留要显示位的值
DL ← DL+30H
完成数值 0~9的 ASCII码转换
Y
N
DL←DL+07H
完成数值 A~F的 ASCII码转换用 02功能显示 DL中的字符
Y
N
返回 DOS
DL 超出 39H?
CH ←CH -1转换结束?
开始思考:
1,例 1采用的是大写字母 A~F进行显示,
若采用小写字符 a ~ f 进行显示,程序如何改写?
1010 0011 1001 1110 ‘A39E’ 或 ‘ a39e’
2,编程将 CPU 内 14个 16位寄存器当前的内容分别用十六进制形式显示出来。
编程将 CPU内 14个 16位寄存器当前的内容分别用十六进制形式显示出来 。
要点:
▲ 将上例改写为一个子程,入口参数为 BX
▲ 子程中注意寄存器值的保存和恢复
▲ 注意 CS,IP,PSW寄存器值的获取方法例 将 CPU内 14个 16位寄存器当前内容分别用 16进制形式显示出来
(采用 DEBUG下 R命令的显示顺序 )
code SEGMENT
ASSUME CS:code
start,PUSH BX
MOV BX,AX ;显示 AX
CALL listbx
POP BX ;显示 BX
CALL listbx
MOV BX,CX ;显示 CX
CALL listbx
MOV BX,DX ;显示 DX
CALL listbx
MOV BX,SP ;显示 SP
CALL listbx
MOV BX,BP ;显示 BP
CALL listbx
MOV BX,SI ;显示 SI
CALL listbx
MOV BX,DI ;显示 DI
CALL listbx
MOV BX,DS ;显示 DS
CALL listbx
MOV BX,ES ;显示 ES
CALL listbx
MOV BX,SS ;显示 SS
CALL listbx
MOV BX,SEG start
CALL listbx ;显示 CS
MOV BX,OFFSET start
CALL listbx ;显示 IP
PUSHF
POP BX ;显示 PSW
CALL listbx
MOV AH,4CH ;返回 DOS
INT 21H
listbx PROC
MOV CH,4
MOV CL,4
next,ROL BX,CL
MOV DL,BL
AND DL,0FH
ADD DL,30H
CMP DL,39H
JLE print
ADD DL,07H
print,MOV AH,2H
INT 21H
DEC CH
JNZ next
MOV DL,20H ;显示空格符
MOV AH,02H
INT 21H
RET ;子程返回
listbx ENDP
code ENDS
END start
listbx PROC
PUSH CX ;保存寄存器
PUSH BX
PUSH DX
PUSH AX
PUSHF
POPF ;恢复寄存器
POP AX
POP DX
POP BX
POP CX
RET ;子程返回
listbx ENDP
code ENDS
END start
用十六进制显示 BX内容子程
D:\>LIST_REG ;在 DOS下执行程序
0000 0000 00FF 0BDF 0000 0912 0000 0000 0BDF 0BDF 0BEF 0BEF 0000 3202
D:\ >DEBUG LIST_REG.EXE ;利用 DEBUG检测结果
-R ;显示当前寄存器内容
AX=0000 BX=0000 CX=007B DX=0000 SP=0000 BP=0000 SI=0000 DI=0000
DS=128E ES=128E SS=129E CS=129E IP=0000 NV UP EI PL NZ NA PO NC
129E:0000 53 PUSH BX
-G ;执行程序
0000 0000 007B 0000 0000 0000 0000 0000 128E 128E 129E 129E 0000 7202
Program terminated normally
-
运行的结果与用 R命令显示的结果相同,程序运行结果正确例 2 将键盘输入的十进制数据串转换成相应大小的数值存放在 BX寄存器中 。
分析,从键盘输入 ’ 1234’ ( 表示 1234 )
用 0AH功能输入,则缓冲区存放的内容为,
06h 04h 31h 32h 33h 34h 0Dh
num
问题,要转换成 1234 即 04D2h存放在 BX中,怎么实现?
清 ASCII码的高 4位可得各数位大小值 。
01h 02h 03h 04h 04D2h?
算法一:
数值大小 = 各位值 × 权值之和
1234D = 千位 × 1000 + 百位 × 100 + 十位 × 10 + 个位
= 1× 1000 + 2× 100 + 3× 10 + 4
= 0000 0100 1101 0010B
= 04D2H
01h 02h 03h 04h 04D2h?
算法二:
数值大小 =部分和 × 10 +下一位数值
1234D = ( ( ( 0× 10 + 1 ) × 10 + 2 ) × 10 + 3 ) × 10 + 4
= 0000 0100 1101 0010B
= 04D2H
部分和从 0开始,循环次数等于输入的位数
01h 02h 03h 04h 04D2h?
data SEGMENT
string DB ‘Input:’,’$’
num DB 6,?,6 DUP(?)
data ENDS
CODE SEGMENT
ASSUME CS:code,DS:data
start,MOV AX,data
MOV DS,AX
CALL input
CALL change
CALL list_bx
MOV AH,4CH
INT 21H
开始初始化 DS的值
CALL input
显示输入提示,等待从键盘输入十进制数据串
CALL change
将数据串转化为相应的数值存放在 BX中返回 DOS
主程序流程图
CALL list_bx
将 BX内容以 16 进制显示出来
input
子程序流程图调用 09功能显示输入提示调用 0A 功能等待从键盘输入数据
RET返回
input PROC
LEA DX,string
MOV AH,09H
INT 21H
LEA DX,num
MOV AH,0AH
INT 21H
RET
input ENDP
06 04 31 32 33 34 0D 00
num
00 00
change子程序流程图
(BX) ← 输入字符的数值大小
SI ← 数据串偏址
CX ← 数据串长度
AX ← 部分和初值 0
DI ← 乘数 10
Y
N
RET返回
AX← 部分和乘 10
(AX) ← (AX)+(BX)
形成新的部分和修改 SI指针,
指向下一位输入
BX← 转换结果 AX
CX ← CX -1
CX=0?
change PROC
LEA SI,num+2
MOV CL,num+1
MOV CH,0
MOV AX,0
MOV DI,10
next,MUL DI
MOV BH,0
MOV BL,[SI]
AND BL,0FH
ADD AX,BX
INC SI
LOOP next
zero,MOV BX,AX
RET
change ENDP
06 04 31 32 33 34 0D 00
num
00 00
1234D = ( ( ( 0× 10 + 1 ) × 10 + 2 ) × 10 + 3 ) × 10 + 4
显示字符个数 CH=4
循环移位次数 CL=4
BX循环左移 4位,将要显示的值移至低 4位,保存在 DL中清 DL 的高 4位,
只保留要显示位的值
DL ← DL+30H
完成数值 0~9的 ASCII码转换
Y
N
DL←DL+07H
完成数值 A~F的 ASCII码转换用 02功能显示 DL中的字符
Y
N
RET返回
DL 超出 39H?
CH ←CH -1转换结束?
list_bx子程序流程图
list_bx PROC
MOV CH,4
MOV CL,4
next,ROL BX,CL
MOV DL,BL
AND DL,0FH
ADD DL,30H
CMP DL,39H
JLE print
ADD DL,07H
print,MOV AH,2H
INT 21H
DEC CH
JNZ next
RET ;子程返回
list_bx ENDP
code ENDS
END start
例 2 程序存在的问题:
1,未处理输入非数字字符的情况
2,输入的十进制数范围为 0~65535
3,当输入字符个数为 0( 直接回车 ) 时,结果错误
4,未处理负数情况
5,结果的显示未换行
Input:1234 最后看到的是,0D42t:1234
编写子程序的注意事项,
注意子程中 PUSH,POP应成对,否则易造成死机 。
data SEGMENT
string DB ‘Hello’,’$’
data ENDS
code SEGMENT
ASSUME CS:code,DS:data
start,MOV AX,data
MOV DS,AX
CALL input
MOV AH,4CH
INT 21H
input PROC
PUSH AX
LEA DX,string
MOV AH,09H
INT 21H
RET
input ENDP
code ENDS
END start
执行 call前SS:SP
(AX)
执行 call后SS:SP (IP)
执行 push 后SS:SP
执行 ret后SS:SP
(IP)
2,子程与主程的参数传送:
1) 用寄存器传送
2) 用定义的变量传送 ( 例二 )
3) 用堆栈传送 ( 自学 )
例 下面程序段,思考是否可以完成 AX→ CX,BX→DX
CODE SEGMENT
ASSUME CS:code
start,MOV AX,data
MOV DS,AX
PUSH AX
PUSH BX
CALL sub
MOV AH,4CH
INT 21H
sub PROC
POP DX
POP CX
、、
、、
RET
sub ENDP
code ENDS
END start
如何用堆栈传送参数,
参看教材,或相关参考书 。
push ax前SS:SP
(BX)
push ax后SS:SP (AX)
push bx后SS:SP
执行 ret后SS:SP
(IP)call sub后SS:SP
SS:SP
pop dx后
SS:SPpop cx后
(DX)
(CX)