山东大学汇编语言上机实验——实验五.doc
《山东大学汇编语言上机实验——实验五.doc》由会员分享,可在线阅读,更多相关《山东大学汇编语言上机实验——实验五.doc(29页珍藏版)》请在冰点文库上搜索。
子程序设计
2.6显示学生名次表rank
编制一个程序,要求接受键盘输入的一个班的学生成绩,并存放于一个50字的grade数组中,其中grade+i保存学号为I+1的学生成绩。
然后根据grade中的学生成绩,把学生成绩依次填入50字的rank数组中,其中rank+i的内容是学号为i+1的学生的名次。
再按学号顺序把名次从终端上显示出来。
本题要做的主要工作和例2.2的内容是完全一样的,只是增加了由用户键入学生成绩及输出学生名次两个部分的内容,因此这三个部分可以用子程序结构来完成。
子程序结构划分的层次图如图2.17所示,可以看出,main为主要模块,其下一层的三个模块为程序的三大部分。
现将各模块说明如下:
1.模块名:
main为总模块
输入:
从键盘输入一个班的学生成绩
输出:
显示一个班的学生成绩
功能:
根据输入的学生成绩,计算并显示学生名次。
算法如下:
一个学生名次等于成绩高于该学生的人数+1.
2.模块名:
input
输入:
以学号为序型键盘输入一个班的学生成绩。
各个成绩之间用逗号隔开,最后以回车符号结束。
输出:
把一个班的学生成绩存入grade数组。
功能:
接受一个班的学生成绩。
调用子模块decibin把键盘输入的一个十进制数转换为二进制数。
调用子模块crlf完成回车,换行功能。
3.模块名:
rankp
输入:
从grade数组取得一个班的学生成绩。
输出:
以学号为序计算出该班每个学生的名次存入rank数组。
功能:
计算一个班的学生成绩。
算法为:
一个学生的名次等于成绩高于该生的学生人数加1.
4,。
模块名;output
输入:
把rank数组取得一个班的学生名次。
输出:
把一个班的学生名次以学号为序在总端上显示出来。
功能:
先是一个班的学生名次。
调用子模块decibin把键盘输入的一个十进制数转换为二进制数。
调用子模块crlf完成回车,换行功能。
5:
模块名:
decilin
输入:
从键盘输入一个十进制数。
输出:
把该数转换成二进制数并存入BX寄存器中。
功能:
从键盘输入一个十进制数转换成二进制数并存入BX寄存器中。
6.模块名:
crlf
输出:
向终端发出回车换行符。
功能:
完成一次回车换行操作。
7.模块名:
binidec
输入:
从BX寄存器取得一个二进制数。
输出:
在终端屏幕显示一个十进制数。
功能:
把BX寄存器中的二进制数转换为十进制数,并在终端显示出来。
调用子模块DCE_DIV用来作除法运算并显示字符。
8.模块名:
dec_div
输入:
从BX寄存器中的二进制数除以相应的十的幂,并在屏幕显示一位商。
余数保存在BX寄存器中。
有了以上的层次图及模块说明,对程序的全貌有了基本了解。
在图2.18中,我们给出了除rankp以外的其余各个子程序的程序框图。
Rankp的框图与图2.4相同。
图2.19是程序清单,图2.20是本例的运行情况。
;PROGRAMTITLEGOESHERE——Rank
;**************************************************************************
datareasegment
grade dw 50dup(?
)
rank dw 50dup(?
)
count dw ?
mess1 db 'Grade?
$'
mess2 db 13,10,'InputError!
',13,10,'$'
mess3 db 'Rank:
$'
datarea ends
;**************************************************************************
prognamsegment
;--------------------------------------------------------------------------
main proc far
assumecs:
prognam,ds:
datarea
start:
;setupstackforreturn
push ds
sub ax,ax
push ax
;setDSregistertocurrentdatasegment
mov ax,datarea
mov ds,ax
;MAINPARTOFPROGRAMGOESHERE
call input
call rankp
call output
ret
main endp
;--------------------------------------------------------------------------
input proc near
lea dx,mess1
mov ah,09
int 21h
;
mov si,0
mov count,0
enter:
call decibin
inc count
cmp dl,','
je store
cmp dl,13
je exit2
jne error
store:
mov grade[si],bx
add si,2
jmp enter
error:
lea dx,mess2
mov ah,09
int 21h
exit2:
mov grade[si],bx
call crlf
ret
input endp
;--------------------------------------------------------------------------
rankp proc near
mov di,count
mov bx,0
loop1:
mov ax,grade[bx]
mov wordptrrank[bx],0
mov cx,count
lea si,grade
next:
cmp ax,[si]
jg no_count
inc wordptrrank[bx]
no_count:
add si,2
loop next
add bx,2
dec di
jne loop1
ret
rankp endp
;--------------------------------------------------------------------------
output proc near
lea dx,mess3
mov ah,09
int 21h
;
mov si,0
mov di,count
next1:
mov bx,rank[si]
call binidec
mov dl,','
mov ah,02
int 21h
add si,2
dec di
jnz next1
call crlf
ret
output endp
;--------------------------------------------------------------------------
decibin proc near
;proceduretoconverdecimalonkeybdtobinary.
;resultisleftinBXregister.
mov bx,0
;getdigitfromkeyboard,converttobinary
newchar:
mov ah,1
int 21h
mov dl,al
sub al,30h
jl exit1
cmp al,9d
jg exit1
cbw
;(digitisnowinAX)
;multiplynumberinBXby10decimal.
xchg ax,bx
mov cx,10d
mul cx
xchg ax,bx
;adddigitinAXtonumberinBX
add bx,ax
jmp newchar
exit1:
ret
decibin endp
;--------------------------------------------------------------------------
binidec proc near
;proceduretoconvertbinarynumberinBXtodecimal
;onconsolescreen
push bx
push cx
push si
push di
mov cx,100d
call dec_div
mov cx,10d
call dec_div
mov cx,1d
call dec_div
pop di
pop si
pop cx
pop bx
ret
binidec endp
;--------------------------------------------------------------------------
dec_div proc near
;sub_subroutinetodividenumberinBXybnumberinCX
;printquotientonscreen
mov ax,bx
mov dx,0
div cx
mov bx,dx
mov dl,al
;printthecontentsofDLonscreen
add dl,30h
mov ah,02h
int 21h
ret
dec_div endp
;--------------------------------------------------------------------------
crlf proc near
;printcarriagereturnandlinefeed
mov dl,0ah
mov ah,02h
int 21h
;
mov dl,0dh
mov ah,02h
int 21h
;
ret
crlf endp
;--------------------------------------------------------------------------
prognamends
;**************************************************************************
end start
程序框图如下:
实验截图如下:
实验总结:
在复杂的程序设计中,采用模块化结构可以划分功能、分界程序,使得程序有复杂变简单,变清晰。
主程序和子程序之间嵌套使用,使得写代码时思路更清楚明白,读代码时方便快捷清晰明了。
这点跟高级编程语言类似。
而此程序中变量p可以跟踪并控制输入的人数、输名字要预留缓存区、十进制码要和二进制码间相互转换,这些又体现了编程低级语言的特点。
学习汇编语言,重要的事掌握如何通过汇编指令和程序来控制计算机各个组成部件工作,完成一系列任务。
因此,学习汇编用语言与学习高级语言的不同之处是要学习如何深入到计算机的内部进行控制。
通过这次实验,加深了我对汇编语言的理解。
每一步的输入、存储、转换、输出,都需要一条条的汇编指令执行。
而且每一步都有自己的源和目标的地址,每个数据都有自己的存储空间和地址,我们可以很清晰的“跟踪”每一个数据的变化和地址的转移。
实验体会:
在复杂的程序设计中,采用模块化结构可以划分功能、分界程序,使得程序有复杂变简单,变清晰。
主程序和子程序之间嵌套使用,使得写代码时思路更清楚明白,读代码时方便快捷清晰明了。
这点跟高级编程语言类似。
而此程序中变量p可以跟踪并控制输入的人数、输名字要预留缓存区、十进制码要和二进制码间相互转换,这些又体现了编程低级语言的特点。
学习汇编语言,重要的事掌握如何通过汇编指令和程序来控制计算机各个组成部件工作,完成一系列任务。
因此,学习汇编用语言与学习高级语言的不同之处是要学习如何深入到计算机的内部进行控制。
通过这次实验,加深了我对汇编语言的理解。
每一步的输入、存储、转换、输出,都需要一条条的汇编指令执行。
而且每一步都有自己的源和目标的地址,每个数据都有自己的存储空间和地址,我们可以很清晰的“跟踪”每一个数据的变化和地址的转移。
2.7计算工资scremp
编写一个程序,接受用户输入的工作时间及工资率,显示计算得到的工资数。
本程序有三个部分组成,输入工作时间和工资率,计算工资;显示工资值。
在输入输出部分,与例2.6一样,必须考虑自负与数字的装换,以及十进制换二进制,二进制换十进制的问题。
除此之外,还应注意到本例中的输入数可能是小数。
在这里并不需要使用浮点数格式来进行计算,只是在计算中必须处理小数。
我们采用在接受输入数字是记录小数点后的位数,并把两个输入数的小数点后位数之和存放在nodec单元当中。
在计算工资的乘法中,并不考虑小数点后的存在,而输出的工资数又只取出小数点后的两位数,因此我们用SHIFT单元记录移位因子,用ADJUST单元记录舍入值。
对于不同的NODEC可以分以下情况进行处理。
1.NODEC>6
我们知道,对于16位整数而言,及其允许的最大数是65535,对于NODEC>6的数,移位因子将>=10000,该数已经超过机器允许的范围,因此本例限制NODEC的值必须<=6.如果NODEC>6,则作为溢出处理,此时将输出值变为0。
2.NODEC=3~6
此时移位因子SHIFT=(10)^nodec—2
舍入值ADJUST=1/2SHIFT
例如:
输入工作时间为8.52,工资率为10.25,则乘机为
Product=852X1025=873300
移位因子为shift=(10)^nodec—2
舍入值ADJUST=1/2SHIFT=50
作舍入及移位处理
(Product+adjust)/shift=(873300+50)/100
=8733
又如:
输入工作时间为65.245,工资率为8.52
则,product=65245X852=55588740
SHIFT=(10)^5-2=1000
Adjust=500
作舍入及移位处理
55588740+500/1000=55589240/1000
=55589
金处理的值只是取得了答案的有效值,并未考录小数点的位置,这个问题将会在输出时得到解决。
3.NODEC=0~2
在这种情况下,乘积的结果不必做舍入及移位处理,只需记录NODEC的值,并在输出显示是解决小数点的问题即可
在计算时还需啊哟说明一个问题:
由于采用整数运算,要求输入数不超过6535,任意输入数超过改制就做溢出处理,在这里我们用输出0来表示。
此外,两个输入数的成绩可能得到三十二位二进制数的结果,这用一般的运算乘法指令就可以得到。
对于这样的双精度数作除法运算时,尽管我们已经限制shift的值不超过65535,但字运算的出发指令要求双精度被除数和单精度的除数相除,其结果应该是双精度的商,否则作为溢出处理。
为了避免这种溢出情况的发生,我们采用以下程序段来作为除法。
设在以下程序段运行前,我们已取得双精度被除数在DX:
AX中,除数在shift单元中,除法运算结果的商在DX,AX中。
模块名:
begin为中控制模块
输入:
接受从键盘输入的工作时间hour和工资rate
输出:
在屏幕上显示工资值wage
功能:
根据工作时间和工资率计算工资
Wage=hour*rate
调用:
2:
模块名:
Q10SCR
功能:
清除屏幕
3:
模块名:
Q20CURS
功能:
置于光标位置
4模块名:
B10inpt
输入:
接受从键盘输入的以小时为单位的工作时间及工资率
输出:
把工作时间缓存HASPAR缓存区,吧工资率存入ratepar缓冲区
功能:
接受从键盘输入的工作时间及工资率,分别存入相应的缓存区中。
5模块名:
D10HOUR
输入:
从HRSPAR中取出工作时间
输出:
把转换为二进制的时间存入BINHRS单元中。
功能:
调用子过程M10ASBI,把工作时间从ASCLL吗转换为二进制数。
6模块名:
E10RATE
输入:
从RATEPAR中取出工资率。
输出:
把转换为二进制的工资率存入BINRATE单元中。
功能:
调用子过程M10ASBI,把工资率从ASCLL码转换为二进制数。
7:
模块名:
M10ASBI
输入:
根据调用过程给出的指针以及字符个数取得一个ASCLL字符窜、
输出:
将ASCLL字符窜转换为二进制数,结果存放与BINAL单元中
功能:
把ASCLL字符窜转换为二进制数。
同时记录输入的小数点后的位数累计在NODEC单元中。
8:
模块名:
F10MULT
输入:
从binHRAS中取得工作时间,从BINRATE中取得工资率。
输出:
根据工作时间及工资率的取值将其结果存放在DX,AX中
功能:
把工作时间和工资率的成绩经过舍入和移位处理后得到的二进制工资值存放在DX.:
AX中。
9模块名:
G10WAGE
输入:
DX,AX中的二进制工资数以及NODEC单元中的小数点后的位数
输出:
把二进制的工资数转换为ASCLL码存放在ASCWAGE为首地址的字符窜当中
功能:
10模块名
输入:
ASCWAGE中的字符窜
输出:
把字符窜在屏幕上显示出来
功能:
显示工资数
;PROGRAMTITLEGOESHERE--SCREMP
;Enterhours&rate,displaywage
;*************************************
stacksgsegmentparastack'stack'
dw 32dup(?
)
stacksgends
;*************************************
datasg segmentpara 'data'
hrspar label byte;Hoursparameterlist;
maxhlen db 6
acthlen db ?
hrsfld db 6dup(?
)
ratepar label byte;rateparameterlist;
maxrlen db 6
actrlen db ?
ratefld db 6dup(?
)
messg1 db 'Hoursworked?
','$'
messg2 db 'Rateofpay?
','$'
messg3 db 'Wage='
ascwage db 14dup(30h),13,10,'$'
messg4 db 13,10,'Overflow!
',13,10,'$'
adjust dw ?
binval dw 0
binhrs dw 0
binrate dw 0
col db 0
decind db 0
mult10 dw 01
nodec dw 0
row db 3
shift dw ?
tenwd dw 10
tempdx dw ?
tempax dw ?
datasg ends
;*************************************
codesg segment para 'code'
;-------------------------------------
begin proc far;mainpartofprogram
assumecs:
codesg,ds:
datasg,ss:
stacksg,es:
datasg
;setupstackforreturn
push ds
sub ax,ax
push ax
;setDSregistertocurrentdatasegment
mov ax,datasg
mov ds,ax
mov es,ax
;mainpartofprogramgoeshere
mov ax,0600h
;CALLDISP
call q10scr
call q20curs
a20loop:
call b10inpt
cmp acthlen,0
je a30
call d10hour
call e10rate
call f10mult
call g10wage
call k10disp
jmp a20loop
a30:
;calltimedate
mov ax,0600h
call q10scr
ret
begin endp
;-------------------------------------------
;Inputhours&rate
;
b10inpt proc near
lea dx,messg1
mov ah,09h
int 21h
lea dx,hrspar
mov ah,0ah
int 21h
cmp acthlen,0
jne b20
ret
b20:
mov col,25
call q20curs
lea dx,messg2
mov ah,09h
int 21h
lea dx,ratepar
mov ah,0ah
int 21h
ret
b10inpt endp
;--------------------------------------------
;Processhours:
;--------------
d10hour proc near
mov nodec,0
mov cl,acthlen
sub ch,ch
lea si,hrsfld-1
add si,cx
call m10asbi
mov ax,binval
mov binhrs,ax
ret
d10hour endp
;---------------------------------------------
;Processrate:
;-------------
e10rate proc near
mov cl,actrlen
sub ch,ch
lea si,ratefld-1
add si,cx
call m10asbi
mov ax,binval
mov binrate,ax
ret
e10rate endp
;----------------------------------------------
;Multiply,round,&shift
;---------------------
f10mult proc near
mov cx,07
lea di,ascwage
mov ax,3030h
cld
r