微机原理软件实验报告_第1页
微机原理软件实验报告_第2页
微机原理软件实验报告_第3页
微机原理软件实验报告_第4页
微机原理软件实验报告_第5页
已阅读5页,还剩49页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

信息与通信工程学院微机原理软件实验报告 班 级: 姓 名: 学 号: 日 期: 实验一DEBUG的使用 1一、实验目的 1二、实验内容 1三、预习思考 3四、实验过程 4五、实验总结 7实验二分支、循环程序设计 8一、实验目的 8二、实验内容 8三、预习思考 8四、实验过程 9(一)、流程图 9(二)、源代码 10(三)、实验分析 13五、实验总结 14实验三代码转换程序设计 15一、实验目的 15二、实验内容 15三、预习思考 15四、实验过程 16(一)流程图 16(二)模块层次图 16(三)源代码 17(四)实验分析 21五、实验总结 22实验四子程序设计 23一、实验目的 23二、实验内容 23三、预习思考 23四、实验过程 24(一)流程图 24(二)模块层次图 25(三)源代码 25(四)实验分析 39五、实验总结 40实验五中断程序设计 41一、实验目的 41二、实验内容 41三、预习思考 41四、实验过程 42(一)流程图 42(二)源代码 43(三)实验分析 49五、实验总结 50实验一DEBUG的使用一、实验目的掌握汇编程序的编辑、编译、连接和执行的全过程;学习和掌握用DEBUG调试程序的方法。二、实验内容用编辑软件,输入以下汇编语言源程序:DATSEGMENTADB20BDB15YDB3DUP(0)ZDB0,0DATENDSSTASEGMENTSTACK DW50DUP(?)STAENDSCODSEGMENTASSUMECS:COD,DS:DATSTARPROCFAR PUSHDS XORAX,AX PUSHAX MOVAX,DAT MOVDS,AX MOVAX,STA MOVSS,AX MOVAL,A MOVZ,AL MOVZ+1,AL CALLSUB1 MOVAL,B MOVZ,AL MOVZ+1,AL CALLSUB1 MOVAL,A MOVZ,AL MOVAL,B MOVZ+1,AL CALLSUB1 ADDWORDPTRY,AX ADCBYTEPTR[Y+2],0 RETSTARENDPSUB1PROC MOVAL,Z MOVAH,Z+1 MULAH ADDWORDPTRY,AX ADCBYTEPTR[Y+2],0 RETSUB1ENDPCODENDS ENDSTAR通过编译,连接形成可执行文件。用DEBUG将可执行文件调入,并进行调试。用D命令观察数据区在内存中的具体内容,记录单元A和B的具体地址。用U命令对目标代码反汇编,观察反汇编后的结果。注意发现源程序的起始位置,并记录这个起始地址。用T命令作单步跟踪调试。比较每条指令执行后的结果和原来的理解是否一致,得出程序运行的结果:它们是写在什么单元,具体内容是什么;并判断结果是否正确。在子程序SUB1的入口处设一断点,用G命令执行程序。在断点处观察堆栈的内容,比较堆栈的内容和程序返回地址是否一致。用E命令修改单元A,B的内容,重新执行程序,并记录结果。用M命令和A命令对程序进行修改:将主程序中最后两条指令(ADD和ADC)修改为一条CALLSUB1指令,重新执行程序。退出DEBUG。重新使用编辑软件,把源程序最后一句中的STAR去掉。再次生成可执行文件,并用DEBUG调入内存。当使用U命令时,显示的结果与前一次(未加STAR)的结果有何不同?三、预习思考熟悉常用的DEBUG命令。答:常用的DEBUG命令如下图表所示。阅读并分析程序的功能。答:程序完成的功能是计算两个数的完全平方和,即计算。若SS=2000H,SP=FFFFH,向堆栈中压入4字节数据后,如何用D命令显示压入堆栈的内?答:使用的命令是:-D2000:FFFB,即使用段基址加偏移量查看。四、实验过程以下由实验截图展现具体的实验过程,截图进行了详细标注,便于阅读。上图为编译、链接形成可执行文件的过程。上图展现了进行反编译然后使用D命令查看数据段中A、B值的过程。上图使用E命令对数据段数据A和B进行了修改,分别由20和15改为了48和64,修改后用D命令进行了查看。上图演示了如何设置断点。在SUB1出设置一断点,可以看到程序执行到CALL0003F时中断,各寄存器的值均有显示。下图为调用子程序SUB1,然后子程序结束,返回主程序前寄存器的值。可以看到,压入堆栈的IP值弹出,CS:IP已经指向了下一条语句的地址。下图中操作实现的功能是将ADD和ADC两条语句替换为CALL语句,通过A命令可以直接修改程序指令,通过插入NOP指令使CPU空闲。也可以通过M命令拷贝CALLSUB1的机器代码到目的地址,但操作容易出错,原因是源地址和目标地址指令长度不一致。当重新使用编辑软件,把源程序最后一句中的STAR去掉。再次生成可执行文件,再次DEBUG时。当使用U命令时,结果如下图所示。可以看到,没有ENDSTAR语句,编译器将不知道代码段的入口地址是多少,导致从数据段开始译码,后续译码全部紊乱。ENDSTAR的作用是指示编译器程序结束,同时告诉编译器程序执行时代码段的入口地址。五、实验总结此次实验是微机原理软件实验的第一次实验。由于平时只是注重理论的学习,没有多少实际编程和调试经验,上机操作还不熟练。以后需要加强实践。汇编的调试很重要,有时比写出源代码更重要。代码是很容易写出的,就看是好是坏,编程技巧是否足够,编程经验是否丰富,但代码的测试,排错确实十分困难的,很难把每一种可能的情况考虑周到,用户的操作也可能出现各种不可预知的情况,往往细小的错误甚至是不明确的地方都可能成为错误的隐患。这也就是为何软件开发三个之一的人写代码,三分之二的人进行测试。这次实验我学会了汇编程序的基本调测方法,也体会到汇编的调试和C/C++或者Java调试的差异。汇编的调试需要深入堆栈和内存区,关心每一地址和每一个指令。这也体现汇编是底层语言的特点。实验二分支、循环程序设计一、实验目的开始独立进行汇编语言程序设计;掌握基本分支,循环程序设计;掌握最简单的DOS功能调用。二、实验内容安排一个数据区,内存有若干个正数,负数和零。每类数的个数都不超过9。编写一个程序统计数据区中正数,负数和零的个数。将统计结果在屏幕上显示。(扩展题)统计出正奇数、正偶数,负奇数、负偶数以及零的个数。三、预习思考十进制数0~9所对应的ASCII码是什么?如何将十进制数0~9在屏幕上显示出来?答:0~9分别对应ASCII码的30H~39H。欲将十进制数0~9显示在屏幕上,只需要用二进制数0~9分别加上30H即可。如何检验一个数为正,为负或为零?你能举出多少种不同的方法?答:方法有多种,现举出两种。一是直接用CMP命令和0比较,然后用JZ等命令进行判断;二是和0相比是否相等,然后用该数(假设为8位)和10000000相与,取出符号位判断,可区分正负。其余方法大同小异,核心的思想是要么直接和0相比,要么使用逻辑或移位运算,取出符号为进行判断。

四、实验过程(一)、流程图

(二)、源代码DATASEGMENT ARRAYDB1,2,3,4,5,6,-1,-2,-3,0,0,0 LENGEQU$-ARRAY;数组长度 POSIDB?;正数个数 NEGTDB?;负数个数 ZERODB?;零的个数 POSIEVENDB?;正偶数 POSIODDDB?;正奇数 NEGTEVENDB?;负偶数 NEGTODDDB?;负奇数 ;用于打印提示的字符串定义 POSICHARDB'Positive:$' NEGTCHARDB'Negtive:$' ZEROCHARDB'Zero:$' EVENCHARDB'Even:$' ODDCHARDB'Odd:$' CRDB0DH,0AH,'$';回车换行的ASCII码DATAENDS;CODESEGMENT ASSUMECS:CODE,DS:DATA;START: MOVAX,DATA MOVDS,AX MOVSI,OFFSETARRAY-1 MOVCL,LENG;数组长度赋予CL MOVAL,0LOP: CMPCL,0;循环控制条件:数组长度减为零 JECALC;为零则跳出 INCSI DECCL MOVBL,[SI];采用基址加变址寻址 CMPBL,AL;和零比较 JGISPOSI;是正数跳转 JEISZERO;是零跳转 JLISNEGT;是负数跳转;ISPOSI: INCPOSI;正数个数加一 ANDBX,1 ADDPOSIEVEN,BL;和1与之后的结果加到正偶数中 JMPLOPISZERO: INCZERO JMPLOPISNEGT: INCNEGT;负数个数加一 ANDBX,1 ADDNEGTEVEN,BL;和1与之后结果加到负偶数中 JMPLOP;CALC: MOVAH,POSI MOVAL,POSIEVEN SUBAH,AL;计算正奇数个数 MOVPOSIODD,AH MOVAH,NEGT MOVAL,NEGTEVEN SUBAH,AL;计算负奇数个数 MOVNEGTODD,AH;PRINT: ;打印正数提示符和正数(奇偶)个数 MOVAH,09H MOVDX,OFFSETPOSICHAR INT21H MOVAH,02H MOVDL,POSI ADDDL,30H INT21H MOVAH,09H MOVDX,OFFSETEVENCHAR INT21H MOVAH,02H MOVDL,POSIEVEN ADDDL,30H INT21H MOVAH,09H MOVDX,OFFSETODDCHAR INT21H MOVAH,02H MOVDL,POSIODD ADDDL,30H INT21H MOVDX,OFFSETCR MOVAH,09H INT21H; ;打印负数提示符和负数(奇偶)个数 MOVAH,09H MOVDX,OFFSETNEGTCHAR INT21H MOVAH,02H MOVDL,NEGT ADDDL,30H INT21H MOVAH,09H MOVDX,OFFSETEVENCHAR INT21H MOVAH,02H MOVDL,NEGTEVEN ADDDL,30H INT21H MOVAH,09H MOVDX,OFFSETODDCHAR INT21H MOVAH,02H MOVDL,NEGTODD ADDDL,30H INT21H MOVDX,OFFSETCR MOVAH,09H INT21H MOVAH,09H MOVDX,OFFSETZEROCHAR INT21H MOVAH,02H MOVDL,ZERO ADDDL,30H INT21HEXT: MOVAX,4C00H INT21H;CODE ENDS ENDSTART(三)、实验分析数据区待统计的数据为:1,2,3,4,5,6,-1,-2,-3,0,0,0实验结果如下图所示。本实验较为简单,意在练习基本的分支、循环结构。关键的点在于和0比较,区分正负和零,然后在正数和负数中判断奇偶,这里巧妙地使用了和1与之后加和到偶数中,最后利用统计的数的个数减去偶数得奇数的方法。使得程序更加流畅和简洁,思路也更清晰。五、实验总结实验中设计好的计算思路是很重要的,汇编的代码由各种跳转和逻辑结构组成,需要考虑代码间的逻辑关系,否则容易出错。语法错误是很显而易见的,但逻辑错误却不容易发现。当有大量判断和循环存在时,需要考虑清楚程序跳转的条件和方向,这点和高级语言有较大差异,汇编本质上没有循环和分支,都是通过将IP赋予代码区地址进行跳转实现的,程序员需要自主控制如何跳转,向何处跳转,这点和C/C++中饱受诟病的goto语句处理有些类似。考虑到实验练习的重点在分支循环结构,此次写代码时暂时没有使用子程序或宏,导致输出部分代码有些过长。实验三代码转换程序设计一、实验目的掌握几种最基本的代码转换方法;运用子程序进行程序设计。二、实验内容从键盘上输入若干两位十进制数,寻找其中的最小值,然后在屏幕上显示出来。两个十进制数之间的分隔符,输入结束标志自定,但要在报告中说明。对输入要有检错措施,以防止非法字符输入,并有适当的提示。将整个程序分解为若干模块,分别用子程序实现。在报告中要给出模块层次图。三、预习思考如何将输入的两个字符(0~9)变为十进制或二进制数?答:输入的字符0~9是ASCII码表示的,对应于30H~39H,通过减去30H,可以转换为相应的计算机数。如何将选出的最小值(二进制或十进制)变为ASCII码再进行显示?答:如果采用输入时把ASCII码转换为数字,然后比较数字的大小再输出,那么输出时还需要把数字再次转换为ASCII码。这是不明智的。可以直接读入并存储数字的ASCII码,容易比较其大小,然后直接输出ASCII码即可。你觉得采用二进制运算还是十进制运算更适合于这个实验?答:采用二进制或者十进制都需要进行ASCII码到数字的转换和其反向转换,换用新的思路可以大大简化编程负担。即直接使用数字对应的ASCII比较,分别比较十位和个位,最后直接输出字符即可。四、实验过程(一)流程图(二)模块层次图(三)源代码DATASEGMENTINPUTDB100DUP(?)MINTMPDB'9'-30H,'9'-30H;置最小值的初始值为99COUNTDB0DIFERRORDB0D;用于判断调用输入子程序是否有错;提示信息字符串WELCOMEDB'Pleaseinputnumbers:','$'OUTTIPDB'Minimumis:','$'CRDB0DH,0AH,'$';回车换行;各种错误输入提示ERROR1DB'ERROR:Characterisnotvalid!','$'ERROR2DB'ERROR:Numbermustcontainstwodigits!','$'ERROR3DB'ERROR:Numberisempty!','$'ERROR4DB'ERROR:Needseparatechar!','$'DATAENDS;CODESEGMENT ASSUMECS:CODE,DS:DATAMAINPROCFAR MOVAX,DATA MOVDS,AX MOVDX,OFFSETWELCOME;调用欢迎提示 CALLPRINT MOVDX,OFFSETCR;回车换行 CALLPRINT CALLGETNUM;获取用户输入 CMPIFERROR,0;判断输入过程是否有错 JNZBACK;错误则直接返回DOS MOVDX,OFFSETCR;回车换行 CALLPRINT CALLFINDMIN;查找最小数 MOVDX,OFFSETOUTTIP;调用输出提示 CALLPRINT MOVAH,02H MOVDL,MINTMP;输出最小值的十位 ADDDL,30H INT21H MOVAH,02H MOVDL,MINTMP[1];输出最小值的个位 ADDDL,30H INT21H BACK: MOVAX,4C00H;返回DOS INT21HMAINENDP;;获取输入,出口参数为IFERROR,表示是否有错GETNUMPROC PUSHAX;保存现场 PUSHBX PUSHCX PUSHDX PUSHDI MOVDI,0;数组偏移地址 MOVCX,0;标识数字的位数GETLOOP: MOVAH,01H;从键盘读取一个字符 INT21H CMPAL,0DH;和回车比较 JEEXIT1;是回车则结束输入 CMPCX,0;数字位数为空 JECMPSPACE0 CMPCX,1;数字位数为1 JECMPSPACE1 CMPCX,2;数字位数为2 JECMPSPACE2CMPSPACE0:CMPAL,20H JEGETLOOP;数字位数为0且输入空格则忽略,继续输入 JMPASCBIN;不是空格就读取该字符CMPSPACE1:CMPAL,20H JEERR2;数字位数为1且输入空格则位数不是两位数出错 JMPASCBIN;否则读取该字符CMPSPACE2:CMPAL,20H JNEERR4;数字位数为2后,不输入空格则分隔符错误 XORCX,CX;输入空格则清零重新计数 JMPGETLOOP ASCBIN: SUBAL,30H;化为二进制数字 JLERR1;小于则无效字符 CMPAL,9;和9比较 JGERR1;大于9则是无效字符 MOVINPUT[DI],AL;保存输入的数 INCCOUNT;统计输入的数字个数,为判断是否输入为两位数 INCDI;向后移动数组 INCCX JMPGETLOOPERR1: MOVIFERROR,1;输出错误1 MOVDX,OFFSETERROR1 CALLPRINT JMPRETURNERR2: MOVIFERROR,1;输出错误2 MOVDX,OFFSETERROR2 CALLPRINT JMPRETURN ERR3: MOVIFERROR,1;输出错误3 MOVDX,OFFSETERROR3 CALLPRINT JMPRETURN ERR4: MOVIFERROR,1;输出错误4 MOVDX,OFFSETERROR4 CALLPRINT JMPRETURN EXIT1: MOVBL,COUNT;判断输入数的个数是否为零 CMPBL,0 JEERR3;输入数目为0则输出错误并退出 ANDBL,01H;判断数字是否为两位数 CMPBL,0 JNEERR2;输入数字个数为奇数则出错RETURN: POPDI;恢复现场 POPDX POPCX POPBX POPAX RETGETNUMENDP;;回车换行输出字符串,入口参数为DXPRINTPROC PUSHAX MOVAH,09H INT21H POPAX RETPRINTENDP;;查找最小的数子程序FINDMINPROC PUSHDI;保护现场 PUSHAX PUSHCX MOVDI,-2;数组下标 MOVCL,COUNT;把数组长度移入CX MOVAL,CL CBW MOVCX,AXLOP: ADDDI,2 CMPCX,DI;是否已经比较完毕 JEEXIT2;如果比较完毕所有数则退出 MOVAH,INPUT[DI];否则接着比较,移入十位数 MOVAL,INPUT[DI+1];移入个位数 CMPAH,MINTMP;比较十位数,MINTMP低地址为十位 JALOP;如果MINTMP小,则直接比较下一个数 JEHIGHEQU ;如果十位数相等,比较个位数,再否则十位大就直接存储STOMIN: MOVMINTMP,AH MOVMINTMP[1],AL JMPLOPHIGHEQU: CMPAL,MINTMP[1];比较个位数 JNBLOP;个位数比MINTMP大则跳到下一个数 JMPSTOMIN;否则将当前数写入为MINTMPEXIT2: POPCX POPAX POPDI RETFINDMINENDP;CODEENDS ENDMAIN (四)实验分析下图是实验输出结果截图。实验中以空格为分隔符,空格的个数不限制,以回车为输入结束标志符。对输入的数字进行了位数和范围的严格限制,即必须是两位数字,如果数字小于10,需要补齐零。实验中对输入错误执行严格的检查,出错则重新输入。判断输入错误的核心思路为:以空格为分割,以回车结束,要求必须是两位数,也即,一位数字后不能有空格,两位数字后必须有空格,回车之后总的输入进行判断,数字个数必须为偶数,以上三种情况囊括了所有可能的格式错误,不满足任何一个条件即出错。满足格式输入后,再判断字符的是否0~9,不是则出错。每项错误均已错误列表的形式给出,打印出错误提示。总结实验中的关键设计思路如下:1、严格的输入格式检查,严格的输入字符有效性检查。2、以数组方式进行存储,每两个BYTE存储一个输入的两位数,存储格式为字符ASCII码。不进行字符ASCII码到数字的转换。3、比较数字大小时,采用分别比较高位ASCII码和低位ASCII码的方式,从而不用在输入时将字符存储为数字,输出时也不用再进行逆转换。程序效率大为提高。4、为使得程序结构清晰,减小代码耦合度,采用了多子程序的设计方式。把实验任务分为三步:读取输入、找出最小、输出打印,分别以子程序方式实现,主调函数依次调用完成实验任务。五、实验总结本实验的关键点在于如何设计子程序完成部分功能。在设计子程序的过程中,我依据结构化代码的流程进行划分,自然形成了读取输入、找出最小、打印输出的思路。这一思路是没有问题的,但存在子程序划分还不够细致的问题,比如,读取输入子程序代码过于冗长,这是因为我没有把输入格式检查、错误提示单独作为子过程进行独立编写。这是设计中的一大不足,这一缺陷也让我在调试子程序的时候颇费周折。这次教训一定要铭记。实验中比较大小的方式有多种,如何采用更加简洁有效的方式是值得思考的问题。我一开始也不免陷入到比较数字大小的常规方法中,但由于汇编输入具有特殊性,即输入的是ASCII码而非数字的大小,且存在将两个字符进行连接成为两位数的需求,而输出时又需要进行反过程。考虑到ASCII也是可以比较的,且十位数和个位数是可以分别比较的这一情况,我采用了巧妙的方式进行处理。这说明,在实际的编程中,需要根据具体情况调整一般方法,使得方法更加简洁可行且有效。实验四子程序设计一、实验目的进一步掌握子程序设计方法;进一步掌握基本的DOS功能调用。二、实验内容从键盘上输入某班学生的某科目成绩。输入按学生的学号由小到大的顺序输入。统计检查每个学生的名次。将统计结果在屏幕上显示。为便于观察,输入学生数目不宜太多,以不超过一屏为宜。输出应便于阅读.尽可能考虑美观。输入要有检错手段。三、预习思考如何确定一个学生在这门科目中的名次?答:有两种基本思路,一是抽取每个学生的成绩和其他所有学生的成绩进行比较,然后统计比其分数高的学生,得出该学生的名次;二是把学生成绩存入连续内存区域,即数组方式,取得每个学生的成绩偏移量,即成绩指针。然后比较指针所指的成绩的大小,根据比较结果移动指针完成排序。具体排序时可以采用诸多的方式,比如冒泡法,快速排序法等等,均是可行的。本实验采用第二种方式,用冒泡法予以具体实现。输入结束后,采用什么方法进行比较以得到学生的名次最为简单?答:如上问所述,采用冒泡排序法可获得较好的时间和空间性能。冒泡法平均时间性能O(N2)。相比于直接比较,性能有所改善。但相对于快速排序、归并排序等优化的算法的时间复杂度O(N*log2N)还不够好。但后两者使用汇编实现代码的复杂度和编程要求要高。考虑到学生人数比较少,使用冒泡法是比较简洁的,时间性能是可以接受的。准备好模块层次图。答:见下文“实验过程”中所示。给出输出显示的形式。答:输出以列表形式给出。学号、分数、名次各一列。具体形式参见实验分析部分的输出截图。四、实验过程(一)流程图(二)模块层次图(三)源代码DATASEGMENTIDDB400DUP(?);存储学号,每个16固定个BYTE,存储为字符串 MARKDB20DUP(?);存储分数,每个1BYTE,存储为二进制数 RANKDB20DUP(?);存储排名,每个1BYTE,存储为二进制数 RANKTMPDB20DUP(?);排序时指针临时区 MTMPDB?;记录成绩的临时区 COUNTBDB?;记录总的学生的个数,存为8位 COUNTWDW?;记录总的学生个数,存为16位 CHEOKDB?;输入检查标志位 ERRORDB?;记录错误号 TMPDB2DUP(?);开辟两个内存临时存储区,用作判断和计数 CRDB0DH,0AH,'$';回车换行 TABDB09H,09H,'$';输出TAB键 ERR0DB'Inputcannotbeempty!','$' ERR2DB'Characterisinvalid!','$' ERR4DB'Markisinvalid!','$' ERR6DB'Inputisinvalid!','$' ERRLISTDWERR0,ERR2,ERR4,ERR6 TIP0DB'Pleasere-input:','$' TIP1DB'Pleaseinputnumberofstudents:','$' TIP2DB'PleaseinputIDandMARK:','$' PRTIPDB'RESULT','$' PRINFODB'ID',09H,09H,'MARK',09H,09H,'RANK','$' PRPRE1DB'ID:','$' PRPRE2DB'MARK:','$' BUFFDB16;定义输入缓冲区,最长的字符长度 PRESDB?;存储实际输入了多少个字符 CHARDB16DUP(?);实际可存储有效字符16个DATAENDSCODESEGMENT;;打印提示字信息的宏,形参为PARAPRINTTIPMACROPARA PUSHAX PUSHDX MOVAH,09H MOVDX,OFFSETPARA INT21H POPDX POPAXENDM;;打印单个字符的宏,形参为ACHARPRINTCHARMACROACHAR PUSHAX PUSHDX MOVAH,02H MOVDL,ACHAR INT21H POPDX POPAXENDM;;主程序MAINPROCFAR ASSUMECS:CODE,DS:DATA,ES:DATA MOVAX,DATA MOVDS,AX MOVES,AX CALLGETNUMBER;获得学生的人数 CALLGETINFO;获得学号分数的输入 CALLSORT;执行排序活动名次 CALLPRINT;把名次结果打印出来BACK: MOVAX,4C00H;返回DOS INT21HMAINENDP ;;获得将要输入的学生的人数信息的子程序;每班的学生定义不超过100人GETNUMBERPROCNEAR PUSHAX PUSHBXHE: PRINTTIPTIP1GREP: CALLGETIN;获取一个输入缓冲 MOVCHEOK,0 CALLCHECK CMPCHEOK,0 JEGRETURN MOVERROR,6 CALLPRINTERR PRINTTIPTIP0 PRINTTIPCR JMPGREPERRHERE: PRINTTIPCR MOVERROR,6 CALLPRINTERR PRINTTIPTIP0 JMPGREPGRETURN: CALLCHANGE MOVAL,MTMP CMPAL,0 JEERRHERE MOVCOUNTB,AL;写入人数 CBW MOVCOUNTW,AX PRINTTIPCR POPBX POPAX RETGETNUMBERENDP;;循环直到输入人数满时终止,获得输入的字符串GETINFOPROCNEAR PUSHAX PUSHBX PUSHCX PUSHDX PUSHSI PUSHDI PRINTTIPTIP2 MOVTMP,0;记录是学号还是分数 XORBX,BX;记录每个ID的偏移量 XORAX,AX;记录学生数目MORE: PRINTTIPCR CMPCOUNTB,AL JNZHERE1 JMP RETURN;计数器为0则返回父程序HERE1: CMPTMP,0 JEPR1 CMPTMP,1 JEPR2PR1: PRINTTIPPRPRE1 JMPHERE2PR2: PRINTTIPPRPRE2HERE2: CALLGETIN;否则接受输入 CALLCHECK;检查输入是否是数字且不为空 CMPCHEOK,0 JNECHEFAIL;不为零则不合法,需要重新输入 CMPTMP,0 JEISID;输入的是学号 CMPTMP,1; JEISMARK;输入的是分数CHEFAIL: PRINTTIPTIP0 PRINTTIPCR MOVCHEOK,0;重新把返回判断位置零 JMPMORE;写入学号,固定为16个字符ISID: MOVDL,PRES;抽取需要写入字符的个数 XORDH,DH MOVCX,DX MOVSI,CX INCCX MOVCHAR[SI],'$';把最后一个字符之后的位置填充为'$' ;开始写入ID MOVTMP,1;表示下一个是分数 CLD MOVSI,OFFSETCHAR MOVDI,OFFSETID ADDDI,BX REPMOVSB;写入ID ;写完则为接受下一个输入BUFF作准备 ADDBX,16;ID的偏移地址向后挪动固定的16BYTE JMPMORE;跳回继续输入下一个BUFF;是学号,检查、转换、写入保存ISMARK: CALLCHANGE CMPCHEOK,0 JEWRITEMARK MOVERROR,4 JMPCHEFAILWRITEMARK: PUSHBX MOVBL,MTMP MOVDI,AX MOVMARK[DI],BL;实际写入成绩 POPBX MOVTMP,0;计数清理,表明下一个输入为学号 INCAX;已接受的学生个数加一 JMPMORERETURN: POPDI POPSI POPDX POPCX POPBX POPAX RETGETINFOENDP;;获得一次BUFF输入子程序;入口参数为BUFF的偏移地址,出口参数为BUFF中的字符串 GETINPROCNEAR PUSHAX PUSHDX PUSHDI MOVDX,OFFSETBUFF MOVAH,0AH INT21H POPDI POPDX POPAX RETGETINENDP;;执行输入字符是否是数字的合法性检查CHECKPROCNEAR PUSHDI PUSHCX PUSHAX XORDI,DI;记录CHAR读取的偏移量 MOVAL,PRES;读取输入的BUFF中的字符数 CBW MOVCX,AX CMPCX,0;判断是否输入BUFF为空 JEISEMPTY;为空则重新输入AGAIN: CMPCX,DI JERETURNCHECK MOVAH,CHAR[DI] CMPAH,30H; JLINVALID;小于则无效字符 CMPAH,39H; JGINVALID;大于则是无效字符 INCDI JMPAGAINISEMPTY: MOVERROR,0;输入为空的处理代码 PRINTTIPCR CALLPRINTERR PRINTTIPCR MOVCHEOK,1 JMPRETURNCHECKINVALID:MOVERROR,2;输入不合法的处理代码 PRINTTIPCR CALLPRINTERR PRINTTIPCR MOVCHEOK,1RETURNCHECK: POPAX POPCX POPDI RETCHECKENDP;;处理成绩输入的子程序;检查输入成绩是否在0-100之间的子程序并转化为二进制数CHANGEPROCNEAR ;把3位数字转换为二进制数 PUSHAX PUSHBX PUSHCX MOVCL,PRES CMPCL,3 JAMINVALID;四位数或以上,溢出 JETHRDIG;三位数 CMPCL,2 JETWODIG;两位数 CMPCL,1 JEONEDIG;一位数THRDIG: ;判断是否是100,是则直接在临时成绩区写入100 MOVBL,CHAR[0];百位 SUBBL,30H CMPBL,1 JNEMINVALID MOVBL,CHAR[1];十位 SUBBL,30H CMPBL,0 JNEMINVALID MOVBL,CHAR[2];个位 SUBBL,30H CMPBL,0 JNEMINVALID MOVMTMP,100;写入100 JMPCRETURNTWODIG:;当是两位数时判断十位是否是0,不是则进行转换,然后写入临时成绩中 MOVBL,CHAR[0];十位 SUBBL,30H CMPBL,0 JEMINVALID MOVAL,10 MULBL;成10取得十位数 MOVBL,CHAR[1];个位 SUBBL,30H ADDAL,BL;因为小于100所以有效数在AL中, ;可以直接加个位数得结果 MOVMTMP,AL;写入转换后的数字 JMPCRETURNONEDIG: ;一位数时直接写入临时成绩区即可 MOVBL,CHAR[0];个位 SUBBL,30H MOVMTMP,BL JMPCRETURNMINVALID: MOVERROR,4 CALLPRINTERR MOVCHEOK,1 CRETURN: POPCX POPBX POPAX RETCHANGEENDP;;打印错误信息子程序PRINTERRPROCNEAR PUSHAX PUSHDX PUSHBX MOVAL,ERROR CBW MOVBX,AX MOVAH,09H MOVDX,ERRLIST[BX] INT21H POPBX POPDX POPAX RETPRINTERRENDP;;排序子程序SORTPROCNEAR PUSHAX PUSHBX PUSHCX PUSHDX PUSHSI PUSHDI ;写入偏移量作为分数的指针 MOVAL,COUNTB;读取学生数目 XORBX,BX;BX作为寻址计数器 ;顺序写入成绩偏移量SLOP: DECAL MOVRANKTMP[BX],AL INCBX CMPAL,0 JNESLOP ;排序名次,冒泡排序法 MOVCX,COUNTW;CX记录了总的学生人数 DECCX JZWRRAK;如果只有一个学生则直接写入名次,否则排序异常LOP1: XORDI,DI;从第一个名次开始LOP2: MOVAL,RANKTMP[DI];取出地址指针,即成绩偏移量 XORAH,AH MOVSI,AX MOVDL,MARK[SI];取出成绩1 MOVAL,RANKTMP[DI+1] XORAH,AH MOVSI,AX MOVDH,MARK[SI];同理取出成绩2 CMPDL,DH JGENEXTCMP MOVAH,RANKTMP[DI];交换分数指针 XCHGAH,RANKTMP[DI+1] MOVRANKTMP[DI],AH NEXTCMP:INCDI CMPDI,CX JNELOP2 LOOPLOP1 ;写入最后的名次WRRAK: XORSI,SI MOVCX,COUNTW MOVBL,1;保存名次LOPSAVE: CMPSI,CX JEFINISH MOVAL,RANKTMP[SI];提取该名次学生的地址指针 XORAH,AH MOVDI,AX MOVRANK[DI],BL;写入该学生的名次 INCBL INCSI JMPLOPSAVEFINISH: POPDI POPSI POPDX POPCX POPBX POPAX RETSORTENDP;;打印输入成绩和名次子程序PRINTPROCNEAR PUSHAX PUSHBX PUSHCX PUSHDX PUSHSI PRINTTIPCR PRINTTIPPRTIP;打印提示信息 PRINTTIPCR PRINTTIPPRINFO PRINTTIPCR MOVCX,COUNTW;CX用于保存学生人数 XORSI,SI;SI用于指明当前处理的学生的序号 XORBX,BX;BX保存当前输入的学号偏移量,每次增16NEXPRINT: MOVTMP[1],0;对打印名次置标志位,表明没有打印名次 CMPSI,CX JNEPRINTID JMPPRETPRINTID: ;打印学号,直接字符串打印,因结尾写入了'$' MOVAH,09H MOVDX,OFFSETID ADDDX,BX INT21H PRINTTIPTABPRINTMARK: ;打印分数,分为100、10-99、0-9三中情况打印 MOVAL,MARK[SI]PRINTRANK: CMPAL,100 JEPTTHR CMPAL,10 JLPTONE JMPPTTWOPTTHR: ;是100则直接输出字符串即可,不必转化 PRINTCHAR'1' PRINTCHAR'0' PRINTCHAR'0' JMPNEXTPTTWO: ;10-99需要除以10,商和余数分别是十位和个位 CBW PUSHBX MOVBL,10 DIVBL MOVBX,AX ADDBL,30H ADDBH,30H PRINTCHARBL PRINTCHARBH POPBX JMPNEXTPTONE: ;0-9直接二进制转到ASCII码然后输出 ADDAL,30H PRINTCHARALNEXT: PRINTTIPTAB ;开始打印名次,和打印成绩复用代码 MOVAL,RANK[SI] CMPTMP[1],0 JNEFINISHP MOVTMP[1],1 JMPPRINTRANK FINISHP: PRINTTIPCR;打印完一个学生的学号成绩及名次,回车换行 INCSI ADDBX,16;进行下一个学生的打印 JMPNEXPRINTPRET: POPSI POPDX POPCX POPBX POPAX RETPRINTENDP;CODEENDS ENDMAIN(四)实验分析输入输出格式如下图所示。首先提示输入学生人数,然后逐个提示输入学号和分数,输入完毕之后打印出最终结果,结果输出按照表格的形式给出,三列分别为学号、分数、排名。设计输入的学生个数上限是100人。分数从0—100分。学号可以输入任意长度的15位数字,存储为字符串格式,每个学生固定长度。分数经过转换后存储为数字,每人占用一个BYTE。名次亦存储为数字,每人占用一个BYTE。下图演示了错误输入时的处理,根据错误类型打印出提示,并允许进行重新输入,而不用退出程序。本程序设计的主要特点如下:1、在程序设计思路上,采用了多子程序模块化设计,充分利用了宏和DOS功能调用等高级汇编技巧。2、在数据结构设计上,采用数组的方式进行存储,可直接又下标(即学生的班内序号)进行直接寻址,效率较高。3、在进行排名比较时,利用了指针技术,即对分数的偏移量进行排序,而不移动实际的分数。模拟了高级语言中的数组和指针的技术,结构和思路完整规范。排序技术选用了冒泡排序,获得一定的性能提升。4、对用户输入进行严格的检查,对各种可能出现的错误进行了提示和处理。使得程序具有很好的完备性和健壮性。五、实验总结此次实验是在前几次实验的基础上完成的,综合了子程序设计、DOS调用、宏汇编等等编程方法和技术。具有很强的综合性。程序的设计按照小型程序的要求,充分考虑了健壮性和运行效率等因素,精心设计了数据结构和算法。是可用于实际工程的代码雏形。由于完备性、健壮性、效率、界面等方方面面都考虑到,故代码长度达到了461行。这也使得调试花费了大量时间。综合实验对我的汇编编程能力的提升大有帮助。从四次实验的整个过程来看,我的进步是十分明显的。这也是令我十分欣喜的事情。实验五中断程序设计一、实验目的初步掌握中断程序的设计方法;初步掌握修改DOS系统中断,以适应实际使用的方法。二、实验内容编写一个32位二进制数除以16位二进制数的除法程序。观察当除数为0,或超过相应寄存器范围时,程序执行的结果。修改零号中断服务程序,使它具有以下功能:判断除数是否为0,当除数为0时,显示相应的结果;当除数不为0时,采用适当的方法完成商超过16位的二进制数的除法运算。注意必须保护原有中断服务程序的入口地址,并在程序完毕前加以恢复。选作题:用二进制将结果在屏幕上显示。从键盘输入二进制数。三、预习思考如何保护原有中断向量表中的中断服务程序的入口地址?答:先读取中断向量表中0号中断的地址,压入堆栈,程序结束时弹出堆栈,写回中断向量表即可。如何将你的中断服务程序入口地址置入中断向量表?答:有两种基本方法:一是直接写入法,使用指令将中断服务程序入口地址的IP写入n×4的RAM位置,中断服务程序入口的CS写入n×4+2的位置;二是DOS功能调用,25H用来写中断向量表,35H读中断向量表。四、实验过程(一)流程图(二)源代码DATASEGMENTXXDD?;被除数32bitYYDW?;除数16bitTMPDW?FLAGDB0;是否调用了中断处理程序的标志位,即是否溢出 ;一些提示信息ERR0DB'ERROR!DividebyZERO!','$'TIP1DB'Quotient:','$'TIP2DB'Remainder:','$'TIP3DB'Inputhigh16-bitofdividend:','$'TIP4DB'Inputlow16-bitofdividend:','$'TIP5DB'Input16-bitdivisor:','$'CRDB0DH,0AH,'$';回车换行ONEDB'1','$'ZERDB'0','$'TABDB09H,'$'BUFFDB17;输入缓冲区,可容纳包括回车在内的17个字符 PRESDB0 CHARDB17DUP(0)DATAENDS;;定义堆栈STACKSEGMENTSTACK'STACK'DB100DUP(0)STACKENDS;CODESEGMENTASSUMEDS:DATA,CS:CODE,ES:CODE,SS:STACK;打印字符串的宏PRINTMACROPARA PUSHAX PUSHDX MOVAH,09H MOVDX,OFFSETPARA INT21H POPDX POPAXENDM;;主程序入口MAIN:MOVAX,DATAMOVDS,AXMOVAX,0MOVES,AX ;保存原中断向量表MOVAX,WORDPTRES:[0000H]PUSHAXMOVAX,WORDPTRES:[0002H]PUSHAX;写入新的中断处理子程序地址MOVWORDPTRES:[0000H],OFFSETINT0MOVWORDPTRES:[0002H],SEGINT0CALLINPUT;获取输入MOVDX,WORDPTRXX;移入被除数高16位MOVAX,WORDPTRXX+2;移入被除数低16位MOVBX,YY;移入除数DIVBX;进行32位除法运算CMPFLAG,0;查看是否调用了中断处理程序,即可判断是否溢出JNEISOF;溢出跳转,到扩充除法的结果输出 ;否则直接输出没有溢出的正常除法结果PRINTTIP1MOVBX,AXCALLDISP2PRINTCRPRINTTIP2MOVBX,DXCALLDISP2JMPEOP ;有溢出的时候需要输出32位商和16位余数ISOF:PRINTTIP1MOVBX,DXCALLDISP2MOVBX,AXCALLDISP2PRINTCRPRINTTIP2MOVBX,CXCALLDISP2EOP:POPAX;程序结束出口 ;恢复中断向量表MOVWORDPTRES:[0002H],AXPOPAXMOVWORDPTRES:[0000H],AXMOVAX,4C00H;返回DOSINT21H;;新的0号中断子程序INT0: POPSIADDSI,2;修改IP的值,指向DIV后的指令PUSHSICMPBX,0;判断除数是否为0JEDIV0;为零则提示除数为0,然后返回DOSMOVFLAG,1;置标志为除数不为零溢出 ;进行扩展除法运算,分别用除数除以被除数高16位和低16位 ;输出参数为DX:商高16位,AX:商低16位,CX:16位余数PUSHAXMOVAX,DXXORDX,DX;除前将DX清零DIVBX;高16位除

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论