关于debug的使用、安装 https://blog.youkuaiyun.com/PoorGuy_tn/article/details/80362992
8086cpu芯片引脚。地址引脚(20个),数据引脚(16个)
掌握以下dos命令和debug命令。
DOS命令:CD,DIR,DEL,RENAME,COPY,EDIT,MD,RD(选做)
DEBUG命令: A,D,E,P,R,T,U,G
显示属性字
一个字符在显示缓冲区占用2个字节空间,第一个字节为字符的ASCII码,第二个字节为字符的色彩属性。含义如下:
一个字节有8位 其中可组成为
对于8086 cpu 来说
1word=16bit
1byte=8bit
寄存器是多少位的一个字就等于多少bit
寄存器
1、段地址寄存器
CS(Code Segment)代码段寄存器
DS(Data Segment)数据段寄存器
ES(Extra Segment)附加段寄存器
SS(Stack Segment)堆栈段寄存器
2、地址寄存器
包括指针Ip(Instruction Pointer)
3、变址寄存器
SP(Stack Pointer)
BP(Base Pointer)
SI(Source Index)
DI(Destination Index)
4、数据寄存器
AH&AL=AX(accumulator)累加寄存器,常用于运算;在乘除等指令中指定用来存放操作数,另外,所有的I/O指令都使用这一寄存器与外界设备传送数据。
BH&BL=BX(base):基址寄存器,常用于地址索引
CH&CL=CX(count):计数寄存器,常用于计数;常用于保存计算值,如在移位指令,循环(loop)和串处理指令中用作隐含的计数器.
DH&DL=DX(data):数据寄存器,常用于数据传递。
5、FLAGS标志寄存器 9个
OF overflow flag 溢出标志 操作数超出机器能表示的范围表示溢出,溢出时为1.
SF sign Flag 符号标志 记录运算结果的符号,结果负时为1.
ZF zero flag 零标志 运算结果等于0时为1,否则为0.
CF carry flag 进位标志 最高有效位产生进位时为1,否则为0.
AF auxiliary carry flag 辅助进位标志 运算时,第3位向第4位产生进位时为1,否则为0.
PF parity flag 奇偶标志 运算结果操作数位为1的个数为偶数个时为1,否则为0.
IF interrupt flag 中断标志 IF=1时,允许CPU响应可屏蔽中断,否则关闭中断.
TF trap flag 陷阱标志 用于调试单步操作.
DF direcion flag 方向标志 用于串处理.DF=1时,每次操作后使SI和DI减小.DF=0时则增大.
内存
00000-9ffff 主存储器
A0000-bffff 显存
C0000-fffff 各类ROM (只读存储器
外设端口
各种接口芯片中的端口。端口地址64K个。
显存
显存 80*25彩色字符模式显示缓冲区 B8000H 显示缓冲区
偏移000~09f对应显示器上的第一行(80个字符占160个字节)
000~159 刚好一共160个 159B=09f
偏移0AF~13f对应显示器上的第二行
想在debug框中用-e输出各种字符(及其颜色属性
两种方法:
-e b800:0000 4a 4a 4b 4a //4a为ascii码 4a为颜色属性 后两个同理
-e b800:0000 'J' 4a 'K' 4a
要显示其字符及属性时
-e b800:0000
=>
B800:0000 3A.4a 07.4a 30....
最大段地址FFFF 最小段地址0000
易错
mov [0010],ax:将ax里的值放入16号单元
在最右下角可以看到DS的第16号单元即【0010】已经等于F8H 而F8H正是-8的补码11111000B的十六进制数
首先来看一下如何运行.asm文件
记事本里面写好代码 将扩展名改成.asm
在缓冲区buf中第一个字节里放的是最大定义的字符数,即buf[0],第二个字节是实际输入的字符数,由系统自动填写进去,即buf[1]
有一个难点是想要将缓冲区最后一个字符(本来是OD回车)改成能被识别的’$’字符,首先要获得最后一个字符的偏移地址,需要将实际输入的字符数(buf[1])加上2(前两个字节)
masm a.asm //注意这个文件放在挂载路径里
link a.obj
a.exe
debug a.exe //调试
data segment //数据段
buf db 20,?,20 dup(?) ;定义一个字符串buf 最大长度20,实际输入的字符数,20个?(算上前面两个共22个字节)
data ends
code segment //代码段
assume cs:code,ds:data //伪指令 指明段寄存器和段的对应关系
start:
mov ax,data
mov ds,ax //将data放入ds
mov dx,offset buf //将buf的偏移地址放入dx
mov ah,10 //将键盘输入字符串 调用10号DOS功能
int 21h //中断
mov bl,buf[1] //buf[1]里面的值放入bl
add bl,2 //给bl加2
mov bh,0//把0放入bh中
mov byte ptr buf[bx],'$' //把$放入buf[bx]
mov dx,offset buf//把buf的偏移地址放入dx
mov ah,9//调用9号DOS功能 显示字符串
int 21h //中断
mov ah,4ch //结束程序
int 21h
code ends
end start
实例:实现Y=2X+3,X是一位十进制数。要求X从键盘输入,在下一行上显示“Y=2X+3=”以及十进制计算结果。
1)首先定义字符串buf,然后定义变量x=03h(即需要加的3),定义y,这个y是换行的意思,使程序运行起来便于观察
2)先调用1号DOS功能,输入x,再输出y进行换行
3)需要注意的一点是 1、2号DOS功能都是需要更新al里面的值的,所以为了防止输入的x值变成输出的换行的ascii码,先将装有x的Ascii码值放入bl中,然后再输出换行符
4)先把al中的x的ascii码转换成x的数字,对al再加一次相当于将x乘以2,用daa进行调整,再加上变量x中的03h,也就是加3,在输出之前加上30h,转变成ascii码
5)先把buf的短地址和偏移地址分别放入ds、dx中,调用9号DOS功能,输出buf那一串表达式,再把结果输出即可
实验三:
1.用多种内存查询方式查询2班3号同学的成绩,需要使用debug方式进行,对每一次查询结果进行截图,(例如对mov dx,score[bx][si]那行截图)只截查询结果那一小条就可以。
首先我们定义二维表 数据类型为dw 所以每一个数据占两个字节 如果我们要查第二排的第三个 那么就是 一排有五个同学 而且在地址中都是从0开始的 则第14个地址 即[0eh]就是我们用直接寻址查到的偏移地址 ;寄存器间接寻址同理,只需要把14放入寄存器中,再用[寄存器]表示偏移地址即可 ;寄存器相对寻址则是以二维表初始地址加上第14个 即[score+bx] 或score[bx]; 基址变址寻址 即为 将score表的偏移地址放入寄存器和第14个位置放入变址寄存器SI中,以[bx+si]或[bx][si]查询;相对基址变址寻址则为我们将第一组地址和第二组地址的和14 拆成10 和 4 进行相加,再和score的偏移地址进行相加即可 即score[bx][si]
data segment
score dw 100,98,98,97,95
dw 100,98,96,95,95
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov dx,ds:[0eh] ;直接寻址
mov bx,14
mov dx,[bx] ;寄存器间接寻址
mov dx,[score+bx] ;寄存器相对寻址
mov bx,offset score
mov si,14
mov dx,[bx][si];基址变址寻址
mov bx,10
mov si,4
mov dx,score[bx][si] ;相对基址变址寻址
mov ah,4ch
int 21h
code ends
end start
注意:
cn dw ?
mov [cn],ax 是这样用的
换行和回车的区别:
'\r’是回车,前者使光标到行首,(carriage return)
'\n’是换行,后者使光标下移一格,(line feed)
\r 是回车,return
\n 是换行,newline
2.根据学号显示名字截图要求,两个代码,分别是模仿了C语言的二维字符数组和一维字符型指针数组。
(1)执行效果图
(2)两个代码数据段的截图
data segment
stu db 'noting $'
db 'zhaodanshi $'
db 'mizehui $'
db 'liruihan $'
db 'caoweiqiang$'
info db 'please input the student number no more than 4:$'
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov dx,offset info
mov ah,9
int 21h
mov ah,1
int 21h
sub al,30h
mov bl,12
mul bl
mov dx,offset stu
add dx,ax
mov ah,9
int 21h
mov ah,4ch
int 21h
code ends
end start
data segment
table dw stu0,stu1,stu2,stu3,stu4
stu0 db 'noting $'
stu1 db 'zhaodanshi $'
stu2 db 'mizehui $'
stu3 db 'liruihan $'
stu4 db 'caoweiqiang$'
info db 'please input the student number no more than 4:$'
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov dx,offset info
mov ah,9
int 21h
mov ah,1
int 21h
sub al,30h
mov bl,2
mul bl
mov bx,ax
mov dx,table[bx]
mov ah,9
int 21h
mov ah,4ch
int 21h
code ends
end start
#include<stdio.h>
int main(){
char *stu[5]={"noting","zhaodanshi","mizehui","liruihan","caoweiqiang"};//一位字符型指针数组 好处是可以输出地址
int d =0;
printf("%s","Please input the student number no more than 4:");
scanf("%d",&d);
printf("%s\n",stu[d]);
printf("%p\n",stu[d]);//输出地址
printf("%s\n","Adreess of 0-4");
printf("%p\n",stu[0]);
printf("%p\n",stu[1]);
printf("%p\n",stu[2]);
printf("%p\n",stu[3]);
printf("%p\n",stu[4]);
return 0;
}
查表实验
输入十进制 输出16进制 范围(0~F)
首先定义表table,里面放入对应十六进制符号的ASCII码,分别调用两次1号DOS,输入十位个位,通过xlat进行查找,并输出对应的符号
data segment
table db 30h,31h,32h,33h,34h,35h,36h,37h
db 38h,39h,41h,42h,43h,44h,45h,46h
info db 'please input the number you want to dispaly:$'
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov dx,offset info
mov ah,9
int 21h
mov ah,1
int 21h
sub al,30h
mov bl,al
mov ah,1
int 21h
sub al,30h
mov cl,al
mov al,bl
mov dl,10
mul dl
add al,cl
mov bx,offset table
xlat
mov dl,al
mov ah,02h
int 21h
mov ah,4ch
int 21h
code ends
end start
输入十进制数0-255,显示相应的十六进制数,用取余数的方法转换。
data segment
n db 4,?,3 dup(?)
a db 16
x db 100
y db 10
g db ?
s db ?
b db ?
sum dw 0
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov dx,offset n
mov ah,10
int 21h
mov cl,n[2]
mov b,cl
mov cl,n[3]
mov s,cl
mov cl,n[4]
mov g,cl
sub b,30h
sub s,30h
sub g,30h
mov dx,0Ah
mov ah,2
int 21h
mov ah,b
mov al,g
mov cl,22
mov ch,0
next: add al,s
daa
dec y
cmp y,0
ja next
mov sum,ax
let:
cmp ax,9
ja qiuyu
mov dx,ax
add dx,30h
mov ah,2
int 21h
jmp exit
qiuyu: sbb ax,6
das
sbb ax,10
das
inc y
cmp ax,cx
jae qiuyu
mov sum,ax
let1:
mov bx,sum
mov bh,y
cmp bh,9
ja print1
jmp print2
print1:
mov dl,bh
add dl,31h
mov ah,2
int 21h
cmp bl,9
ja print3 ;37h
jmp print4 ;30
print2:
mov dl,bh
add dl,30h
mov ah,2
int 21h
cmp bl,9
ja print3 ;37h
jmp print4 ;30
print3:
mov dl,bl
add dl,31h
mov ah,2
int 21h
jmp exit
print4:
mov dl,bl
add dl,30h
mov ah,2
int 21h
jmp exit
exit:
mov ah,4ch
int 21h
code ends
end start
3.模仿课本119页5.5.3示例5-9,将以前自己写的程序整理成菜单程序。table表里面保存的是跳转到程序的标号。
data segment
table dw p0,p1,p3
mess1 db '0:A->a'
db 0ah,'1:a->A'
db 0ah,'2:exit$'
data ends
code segment
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
let0:
mov dx,offset mess1
mov ah,9
int 21h
mov ah,1
int 21h
and al,03h
mov ah,0
shl ax,1
mov bx,ax
jmp table[bx]
p0:
mov ah,1
int 21h
add al,20h
mov dl,al
mov ah,2
int 21h
jmp let0
p1:
mov ah,1
int 21h
sub al,20h
mov dl,al
mov ah,2
int 21h
jmp let0
p3:
mov ah,4ch
int 21h
code ends
end start
实验6:子程序设计
1.完成从键盘输入学生姓名和成绩,按成绩降序排列,并显示排序结果。
(1)代码
data segment
table dw s1,s2,s3
s1 db 10,?,10 dup(?)
s2 db 10,?,10 dup(?)
s3 db 10,?,10 dup(?)
str db 0dh,0ah,'$'
score dw 0,0,0
rank dw 0,1,2
n db 3
grade db 0
data ends
code segment
assume cs:code,ds:data
main proc far
start:
mov ax,data
mov ds,ax
call shuru
call sort
call shuchu
mov ah,4ch
int 21h
main endp
shuru proc near
mov bx,0
mov cl,n
mov ch,0
mov dx,0
loop1:
mov dx,offset table[bx]
mov ah,10
int 21h
mov ah,9
mov dx,offset str
int 21h
mov dx,0
mov ah,1
int 21h
mov grade,al
mov ax,0
mov ah,1
int 21h
mov ah,grade
mov score[bx],ax
mov ah,9
mov dx,offset str
int 21h
next:
inc bl
inc bl
loop loop1
ret
shuru endp
sort proc near
mov cx,n
mov ch,0
dec cx
loop3: push cx
mov bx,0
loop2: mov ax,score[bx]
cmp ax,score[bx+2]
jae next2
xchg ax,score[bx+2]
mov score[bx],ax
mov ax,rank[bx]
xchg ax,rank[bx+2]
mov rank[bx],ax
next2: add bx,2
loop loop2
pop cx
loop loop3
ret
sort endp
shuchu proc near
mov di,0
mov cx,3
loop4: mov bx,rank[di]
add bx,bx
mov si,offset table[bx]
mov byte ptr table[si+7],'$'
add si,2 ;?
mov dx,si
mov ah,9
int 21h
mov ah,9
mov dx,offset str
int 21h
mov dx,score[di]
mov ah,2
int 21h
mov dx,score[di]
mov dl,dh
mov ah,2
int 21h
mov ah,9
mov dx,offset str
int 21h
next3: add di,2
loop loop4
ret
shuchu endp
code ends
end start
2.用递归完成阶乘运算。
(1)代码
code segment
assume cs:code
main proc far
start:
mov bx,5
push bx
call fac
mov ah,4ch
int 21h
main endp
fac proc near
mov bp,sp
mov bx,[bp+2]
cmp bx,1
ja next
mov ax,1
jmp res
next:
dec bx
push bx
call fac
mov bp,sp
mov bx,[bp+2]
mul bx
res:
ret 2
fac endp
code ends
end start
Ss:ffff:00 ——bh
Ss:fffe:05 ——bl
Ss:fffd:00 ——mov ah,4ch 的IP高位
Ss:fffc:07 ——mov ah,4ch 的IP低位
Ss:fffb:00 ——减一后的bh
Ss:fffa:04 ——减一后的bl
Ss:fff9:00 ——第一次进入next里的mov bp,sp 的IP高位
Ss:fff8:20 ——第一次进入next里的mov bp,sp 的IP低位
Ss:fff7:00 ——减一后的bh
Ss:fff6:03 ——减一后的bl
Ss:fff5:00 ——第二次进入next里的mov bp,sp 的IP高位
Ss:fff4:20 ——第二次进入next里的mov bp,sp 的IP低位
Ss:fff3:00 ——减一后的bh
Ss:fff2:02 ——减一后的bl
Ss:fff1:00 ——第三次进入next里的mov bp,sp 的IP高位
Ss:fff0:20 ——第三次进入next里的mov bp,sp 的IP低位
Ss:ffef:00 ——减一后的bh
Ss:ffee:01 ——减一后的bl
Ss:ffed:00 ——第四次进入next里的mov bp,sp 的IP高位
Ss:ffec:20 ——第四次进入next里的mov bp,sp 的IP低位
坑1:想要引用数组下标,括号里必须是立即数,否则视为寄存器间接寻址
坑2:字符串输出是从显示字符串的9号功能里面的偏移地址+1的字符开始输出
模块的参数设置
(1)Public :将本模块中的符号或者过程定义为全局变量,供其它模块使用。
格式:public 符号1,符号2,符号3
(2)Extrn :引入外部符号或者过程。
Extrn 符号1:类型,符号2:类型
其中类型为byte,word,dword,near,far
(3)参数传递
寄存器传参
存储单元传参
堆栈传参
将每一个子程序拆分出来作为新的asm文件,还要注意子程序里独有的变量定义在自己的asm文件里的数据段中,并把主模块中涉及到子模块的独有的变量定义语句删除
在主模块中,要用extrn定义其他子模块,并且有全局变量时需要用public定义
在子模块中,子程序的属性都要定义为far,最后的标号为end,如果引用了外部变量则需要用extrn 变量名:类型来定义,还需要用public定义自己这个子程序名以调用
main.asm
extrn sname:far,sscore:far,sort:far,pname:far,pscore:far
public table
data segment public 'data'
;输入姓名提示信息
info db 0dh,0ah,'Please input name no more than 14:$'
;输入成绩提示信息
info1 db 0dh,0ah,'Please input score[0-99]:$'
;输入学生个数
n equ 5
;最大允许输入的姓名长度
namec equ 14
;用来存放姓名偏移地址的字表/一维字数组
table dw s0,s1,s2,s3,s4
;s0-s4用来保存输入的姓名
s0 db namec,?,namec+1 dup('$')
s1 db namec,?,namec+1 dup('$')
s2 db namec,?,namec+1 dup('$')
s3 db namec,?,namec+1 dup('$')
s4 db namec,?,namec+1 dup('$')
;用来存放5个学生的成绩
score dw 5 dup(0)
;用来存放学号的数组
rank dw 0,1,2,3,4
data ends
stack segment stack 'stack'
db 512 dup(?)
stack ends
code segment para 'code'
assume cs:code,ds:data
main proc far
start:
mov ax,data
mov ds,ax
mov cx,5
mov bx,0 ;学号传递
scans: ;scans是用来输入5个同学姓名和成绩的循环。
;因为bx是sname子过程的参数,有可能被sname更改,而在之后的程序中又用到了bx,所以进行入栈保存。
mov dx,offset info
mov ah,9
int 21h
push bx
call sname ;输入姓名,并且将其保存在正确的位置。
pop bx
push bx
mov dx,offset info1
mov ah,9
int 21h
mov bp,offset score
call sscore ;输入两位成绩,将其转化为数字,存储到相应位置。
pop bx
inc bx ;学号加1
loop scans
mov bx,offset score
lea bp,rank
mov ax,n
call sort ;对学生成绩进行排序
mov cx,5
mov di,0
ps:
mov ax,rank[di]
call pname ;打印姓名
mov ax,score[di]
call pscore ;打印成绩
add di,2
loop ps
mov ah,4ch
int 21h
main endp
code ends
end start
m1.asm
public sscore
data segment public 'data'
;用来存放输入的成绩,最大允许输入两位
;经测试验证,虽然回车不算到输入字符的个数中,但是最大允许输入的字符个数要算上回车
score1 db 3,?,3 dup('$')
data ends
code segment 'code'
assume cs:code,ds:data
;参数:通过bx传递。学号:0-4 。bp传递成绩数组首地址。
;返回值:无
;功能:成绩输入到相应的字符缓冲区score1中,并转化为十进制数存放到score数组中。
sscore proc far
push dx
push ax
push cx
push si
push di
mov dx,offset score1
mov ah,10
int 21h ;输入成绩
mov si,dx ;取到输入成绩字符缓冲区首地址
mov al,[si+1] ;取到实际输入的字符个数
cmp al,1 ;看实际输入的成绩是一位数成绩,还是两位数成绩
jne next1
mov al,[si+2];一位数成绩,取到这一个字符,转化位十进制数。
sub al,30h
mov ah,0
jmp res1
next1: ;两位数成绩,转化为十进制数。
mov al,[si+2]
sub al,30h
mov cl,10
mul cl
mov cl,[si+3]
sub cl,30h
mov ch,0
add ax,cx
res1:
add bx,bx
mov di,bx
mov ds:[bp][di],ax ;将转换好的成绩存到数组中
pop di
pop si
pop cx
pop ax
pop dx
ret
sscore endp
code ends
end
m2.asm
extrn table:word
public sname
code segment 'code'
assume cs:code
;参数:通过bx传递。学号:0-4
;返回值:无
;功能:名字输入到指定的字符串缓冲区
sname proc far
push dx
push ax
push si
add bx,bx
mov dx,table[bx]
mov ah,10
int 21h
mov bx,dx
mov al,[bx+1]
mov ah,0
add ax,2
add ax,bx ;算到回车算在的位置,将其改为空格。否则输出姓名用到这个字符串,回车会让光标回到本行起始位置。会影响成绩的输出。
mov si,ax
mov byte ptr[si],20h;将回车替换为空格
mov byte ptr[bx],0dh ;将输入缓冲区的前两个字节换为回车换行
mov byte ptr[bx+1],0ah
pop si
pop ax
pop dx
ret
sname endp
code ends
end
m3.asm
extrn table:word
public pname
code segment 'code'
assume cs:code
;参数 ax:学号
;返回值:无
;功能:输出给定学号学生的姓名
pname proc far
push bx
push dx
add ax,ax ;找到姓名偏移地址值 在 table 表中的偏移位置
mov bx,ax
mov dx,[table+bx]
mov ah,9
int 21h
pop dx
pop bx
ret
pname endp
code ends
end
m4.asm
public sort
code segment 'code'
assume cs:code
sort proc far
push cx
push si
mov cx,ax
dec cx
outs:
push cx
mov si,0
ins:
mov ax,[bx][si]
cmp ax,[bx][si+2]
ja next
xchg ax,[bx][si+2]
mov [bx][si],ax
mov ax,ds:[bp][si]
xchg ax,ds:[bp][si+2]
mov ds:[bp][si],ax
next:
add si,2
loop ins
pop cx
loop outs
pop si
pop cx
ret
sort endp
code ends
end
m5.asm
public pscore
data segment public 'data'
x db ?,?
data ends
code segment para 'code'
assume cs:code,ds:data
;参数 ax:要输出的十进制数字
;返回值:无
;功能:将ax中的数字以十进制的方式输出。
pscore proc far
push bx
push dx
mov bl,10
div bl
mov x[0],al
mov x[1],ah
add al,30h
mov dl,al
mov ah,2
int 21h
mov al,x[1]
add al,30h
mov dl,al
mov ah,2
int 21h
mov dl,20h
mov ah,2
int 21h
pop dx
pop bx
ret
pscore endp
code ends
end
宏
a.mac
output macro str
mov dx,offset str
mov ah,9
int 21h
endm
input macro str
mov dx,offset str
mov ah,10
int 21h ;
endm
outc macro c
mov dl,c
mov ah,2
int 21h
endm
main.asm
include a.mac
extrn sname:far,sscore:far,sort:far,pname:far,pscore:far
public table
data segment public 'data'
;输入姓名提示信息
info db 0dh,0ah,'Please input name no more than 14:$'
;输入成绩提示信息
info1 db 0dh,0ah,'Please input score[0-99]:$'
;输入学生个数
n equ 5
;最大允许输入的姓名长度
namec equ 14
;用来存放姓名偏移地址的字表/一维字数组
table dw s0,s1,s2,s3,s4
;s0-s4用来保存输入的姓名
s0 db namec,?,namec+1 dup('$')
s1 db namec,?,namec+1 dup('$')
s2 db namec,?,namec+1 dup('$')
s3 db namec,?,namec+1 dup('$')
s4 db namec,?,namec+1 dup('$')
;用来存放5个学生的成绩
score dw 5 dup(0)
;用来存放学号的数组
rank dw 0,1,2,3,4
data ends
stack segment stack 'stack'
db 512 dup(?)
stack ends
code segment para 'code'
assume cs:code,ds:data
main proc far
start:
mov ax,data
mov ds,ax
mov cx,5
mov bx,0 ;学号传递
scans: ;scans是用来输入5个同学姓名和成绩的循环。
;因为bx是sname子过程的参数,有可能被sname更改,而在之后的程序中又用到了bx,所以进行入栈保存。
output info
push bx
call sname ;输入姓名,并且将其保存在正确的位置。
pop bx
push bx
output info1
mov bp,offset score
call sscore ;输入两位成绩,将其转化为数字,存储到相应位置。
pop bx
inc bx ;学号加1
loop scans
mov bx,offset score
lea bp,rank
mov ax,n
call sort ;对学生成绩进行排序
mov cx,5
mov di,0
ps:
mov ax,rank[di]
call pname ;打印姓名
mov ax,score[di]
call pscore ;打印成绩
add di,2
loop ps
mov ah,4ch
int 21h
main endp
code ends
end start
m1.asm
include a.mac
public sscore
data segment public 'data'
;用来存放输入的成绩,最大允许输入两位
;经测试验证,虽然回车不算到输入字符的个数中,但是最大允许输入的字符个数要算上回车
score1 db 3,?,3 dup('$')
data ends
code segment 'code'
assume cs:code,ds:data
;参数:通过bx传递。学号:0-4 。bp传递成绩数组首地址。
;返回值:无
;功能:成绩输入到相应的字符缓冲区score1中,并转化为十进制数存放到score数组中。
sscore proc far
push dx
push ax
push cx
push si
push di
input score1
mov si,dx ;取到输入成绩字符缓冲区首地址
mov al,[si+1] ;取到实际输入的字符个数
cmp al,1 ;看实际输入的成绩是一位数成绩,还是两位数成绩
jne next1
mov al,[si+2];一位数成绩,取到这一个字符,转化位十进制数。
sub al,30h
mov ah,0
jmp res1
next1: ;两位数成绩,转化为十进制数。
mov al,[si+2]
sub al,30h
mov cl,10
mul cl
mov cl,[si+3]
sub cl,30h
mov ch,0
add ax,cx
res1:
add bx,bx
mov di,bx
mov ds:[bp][di],ax ;将转换好的成绩存到数组中
pop di
pop si
pop cx
pop ax
pop dx
ret
sscore endp
code ends
end
m2.asm
include a.mac
extrn table:word
public sname
code segment 'code'
assume cs:code
;参数:通过bx传递。学号:0-4
;返回值:无
;功能:名字输入到指定的字符串缓冲区
sname proc far
push dx
push ax
push si
add bx,bx
input table[bx]
mov bx,dx
mov al,[bx+1]
mov ah,0
add ax,2
add ax,bx ;算到回车算在的位置,将其改为空格。否则输出姓名用到这个字符串,回车会让光标回到本行起始位置。会影响成绩的输出。
mov si,ax
mov byte ptr[si],20h;将回车替换为空格
mov byte ptr[bx],0dh ;将输入缓冲区的前两个字节换为回车换行
mov byte ptr[bx+1],0ah
pop si
pop ax
pop dx
ret
sname endp
code ends
end
m3.asm
include a.mac
extrn table:word
public pname
code segment 'code'
assume cs:code
;参数 ax:学号
;返回值:无
;功能:输出给定学号学生的姓名
pname proc far
push bx
push dx
add ax,ax ;找到姓名偏移地址值 在 table 表中的偏移位置
mov bx,ax
output [table+bx]
pop dx
pop bx
ret
pname endp
code ends
end
m4.asm
public sort
code segment 'code'
assume cs:code
sort proc far
push cx
push si
mov cx,ax
dec cx
outs:
push cx
mov si,0
ins:
mov ax,[bx][si]
cmp ax,[bx][si+2]
ja next
xchg ax,[bx][si+2]
mov [bx][si],ax
mov ax,ds:[bp][si]
xchg ax,ds:[bp][si+2]
mov ds:[bp][si],ax
next:
add si,2
loop ins
pop cx
loop outs
pop si
pop cx
ret
sort endp
code ends
end
m5.asm
include a.mac
public pscore
data segment public 'data'
x db ?,?
data ends
code segment para 'code'
assume cs:code,ds:data
;参数 ax:要输出的十进制数字
;返回值:无
;功能:将ax中的数字以十进制的方式输出。
pscore proc far
push bx
push dx
mov bl,10
div bl
mov x[0],al
mov x[1],ah
add al,30h
outc al
mov al,x[1]
add al,30h
outc al
outc 20h
pop dx
pop bx
ret
pscore endp
code ends
end
link main=m1+....+m5