1、福建农林大学东方学院信息工程类实验报告系: 计算机系 专业: 电子信息工程 年级: 10 姓名: 廖少兵 学号: 1050302103 实验课程: 汇编语言 实验室号:_ 实验设备号: 实验时间: 指导教师签字: 成绩: 实验五 DOS 功能调用1实验目的和要求1. 学会 DOS 中关于显示功能调用指令的用法。2. 领会修改显存方法显示字符。2实验用的软硬件环境实验的硬件环境是:IBMPC 机及其兼容机实验的软件环境是:操作系统:DOS 2.0 以上;调试程序:DEBUG.COM;文本编程程序:EDIT.EXE、WPS.EXE;宏汇编程序:MASM.EXE(或 ASM .EXE) ;连接装配程
2、序:LINK .EXE;交叉引用程序:CREF.EXE(可有可无) 。3实验内容及实验数据记录1、输入一个字符,显示出来2、输入一个字符串,显示出来3、buf 开始的 3 个的 16 位二进制数用十六进制数的形式显示出来(1)理解程序(2)输入程序,汇编,运行(在 DOS 状态下输入:文件名.EXE) ,观察结果。(3)如果要分行显示,程序要如何修改?DATA SEGMENTBUF DW 4F59H, 56A8H, 0FF90HDATA ENDSCODE SEGMENTASSUME CS: CODE, DS: DATASTART: MOV AX, DATAMOV DS, AXMOV SI, 0
3、P: MOV BX, BUFSIMOV CH, 4L: MOV CL, 4ROL BX, CLMOV DL, BLAND DL, 0FHCMP DL, 10JB NEXTADD DL, 7NEXT: ADD DL, 30HMOV AH, 2INT 21HDEC CHJNZ LINC SIINC SICMP SI, 4JNA PMOV AH, 4CHINT 21HCODE ENDSEND START4、运行下列程序,在屏幕的第 1 行,会显示一个字符 X,理解程序段STACK SEGMENTDB 128 DUP(0)STACK ENDSCODE SEGMENTASSUME CS:CODE,SS:
4、STACKSTART: MOV AX,STACKMOV SS,AXMOV SP,128MOV AX,0B800HMOV ES,AXMOV AH,0 ;BIOS 10H 的 0 号功能,设置 80X25 的彩色字符模式MOV AL,03HINT 10H MOV AH,XMOV ES:160*1+40*2,AHMOV AL,0MOV AH,4CHINT 21HCODE ENDSEND START5、显示*6、 编写程序,统计字缓冲区中的 20 个数据的正数、负数、0 的个数,并将统计结果以 16 进制形式显示出来。4操作方法及实验步骤1)直接调用 DOS 1 号功能即可, debug 环境中 a
5、命令直接编辑代码写入内存如下指令MOV AH,01INT 21HMOV AH,4CINT 21H2)字符串的输入和显示,原以为在调用 10 号功能后需要调用 9 号显示功能,因此编辑代码如下DATA SEGMENTBUF DB 10DB ?DB 10 DUP(?);DB $DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART: MOV AX,DATAMOV DS,AXMOV DX,OFFSET BUFMOV AH,10INT 21H;MOV DX,OFFSET BUF+2;MOV AH,9;INT 21HMOV AH,4CHINT 21HCODE E
6、NDSEND START3)3.1段装入MOV CL,5 ;循环控制次数为 5MOV CH,0 ;高位清零MOV DH,* ;初始打印字符MOV AX,0H: ;MOV BL,1 ;从 1 列开始显示MOV DL,6 ;行控制参数SUB DL,CL ;控制当前行MOV AL,160MUL DLMOV DI,AX ;保存行参数MOV AL,2 MUL CLDEC AL(L:) MOV AL,2MUL BL ;控制当前列ADD AX,DI ;显存空间定位MOV ES:AX,DH ;通过显存显示INC BL ;列打印自加;INC BX(L:) MOV AL,2 MUL CLDEC AL;DEC AX
7、 ;MOV SI,AXCMP BL,AL;检验打印上限;CMP BX,SIJNA L ;未打印完当前行返回继续打印MOV DL,0AHMOV AH,2INT 21H ;打印完一行则换行LOOP H ;行打印循环MOV AH,4CHINT 21H ;退出到 DOS 界面CSEG ENDSEND START6)6.1 分析题目要求有三,首先定义缓冲区存放 20 个有符号数据,其次对于正负数和零的统计可通过两次筛选来完成,最后是 16 进制的转换这在 3)中已得以解决,因此有部分流程如下这样在 16 进制转换时就有了一个取数的麻烦,为此考虑如果多开辟一个缓冲区 BUF2 来存放三个结果,下一个指针
8、DI,一来解决了这个问题,二来筛选时通过指针的跳动也同时使得统计结果的代码得以简化,所以就有了如下流程:6.2 按分析结合流程编辑代码如下DATA SEGMENTBUF1 DB 1,-3,5,26,0,6,0,24,-17,-10,-21,-5,33,48,0,32,0,10,44,-1 BUF2 DB 3DUP(0)DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART: MOV AX,DATAMOV DS,AXMOV CX,20MOV AL,0;MOV SI,OFFSET BUF1(1) ;MOV DI,OFFSET BUF2S: CMP SI,A
9、LJGENEXTCMPJMP ADDD ;负数的个数NEXTCMP:INC DICMP SI,ALJZ ADDD ;零的个数INC DIADDD:ADD BYTE PTR DI,1 ;正数的个数INC SILOOP S ;统计个数MOV DI,OFFSET BUF2P: MOV BX,DI;以下为 16 进制的转换并显示注释参考 3)见附录MOV CH,4;L: MOV CL,4ROL BX,CL;ROL BL,CLMOV DL,BLAND DL,0FHCMP DL,10JB NEXTADD DL,7NEXT: ADD DL,30HMOV AH,2INT 21HDEC CHJNZLMOV AH
10、,0AH;MOV AH,2;MOV DL,0AHINT 21HINC DICMP DI,OFFSET BUF2+2JNA PMOV AH,4CHINT 21HCODE ENDSEND START5实验数据处理和分析2)按最初想法汇编程序得到了下面可怕的结果由此单步跟踪观察,d 定位到输入的字符串所在查看,如图得知 10 号功能的调用并没出错,所以应该是 9 号的问题单步到 9 号功能调用指令,p 执行后,发现在 debug 确实调用,并显示了字符串但在返回 DOS 界面却显示先前的一大堆乱码,所以认为是结束字符 $的关系,于是修改字符缓冲区为如下BUF DB 10DB ?DB 10 DUP(?
11、)DB $结果出现了如下情况,只要输入的字符少于 9 个都会缺失掉前面几个不唯一。至于问题处在哪,琢磨了好一段时也没弄清楚,猜想是 10 号功能的调用是否已自动回显了字符串而立刻调用 9 号功能是不是产生了覆盖。于是注释 9 号功能的调用。结果单一的 10 号功能的调用就已会显了字符串,符合题目要求。3)3.1-1debug 调试,单步跟踪如图程序进行取数操作:不难理解,程序首先通过循环左移 4 位将数据高 4 位(二进制数)移出并补到数据低位,再将内存中一单元的数据(数的低 8 位二进制数 )传送至寄存器 DL 如上图。3.1-2 数据处理操作通过指令 AND DL,0FH 将高四位清零保留
12、低四位如图 a 可以看到 DX 由0094 变为了 0004,至此取得二进制数的最高四位。将所要转化的四位二进制数与 10 做比较,若小于 10 即 0 到 9 可直接加 30H 得到其对应的 ASCII 码 30H到 39H 如图 b 所示,相反若大于等于 10 则应多加上 7 跳过 7 个符号 ASCII 码得到其对应的 16 进制 ASCII 码 41H 到 46H 以达到转换的目的即显示时打印其相应的 ASCII 码对应的字符。图 a图 b3.2 输入程序,编译,连接,运行结果如下虽然达到了以 16 进制的形式打印要求却连续输出了三个数。图 c4)立即的显示结果混在了 debug 环境
13、其他字符中,以至于没能注意到,老怀疑是自己显卡的显存空间分配彩色字符缓冲区不在内存的 B8000HBFFFFH 间,导致了随机更改 ES 段首地址,结果可想而知,无意清屏时直接在 DOS 下运行终于看到了字符X 。5)5.1 间接寻址,MOV ES:AL,DH 寄存器的错误应用即相对适用的寄存器只有 BX,BP,SI 和 DI 错误提示如下 通过添加 ADD AX,DI 和 MOV DI,AX 指令,写入字符指令相应地改为了MOV ES:DI,DH。5.2 更正了错误后并排错语法错误后运行结果仍然出现问题如下结果并没有如预期的一样,从图案可以看出,错误肯定是在于列打印的控制上,debug 单步
14、跟踪发现 DI 中保存的参数在每次打印时都更新为了前一次打印所计算的偏移地址也就是加上了列的增量,如下图所示,打印 1 行 2 列时,DI 由00A2H 即 162 变成了 00A6 即 166。5.3因此在下一行打印之前必须保证 DI 不变动,所以这里的 DI 应由其他寄存器代替,便修改之为 BP,编译运行也就得到了预期的图案。6)汇编代码出错如下修改错误,保证语法的正确性后,运行程序得到结果如下,显然 dos2 号功能调用出错了,统计结果也不正确,为此只能单步跟踪在第一次循环时过程和数据处理均正常如下图 a 第一个数第一次筛选图 b 第一个数为大于等于 0,DI 下移图 c 第一个数大于
15、0,DI 继续下移一位至 0016,实现结果加 1继续跟踪发现,问题出在了每次处理完一个数据后 DI 未能刷新至原点 0014 图下修改 S:标号至 (1)处,MOV DI,OFFSET BUF2得到结果如下不难发现,除了 dos2 号功能未修改错外,结果中后两位才是正确的结果,检查代码得知是 16 进制转换时寄存器高 8 位无用数据参与了转换,为此修改P: MOV BX,DIMOV CH,4L: MOV CL,4ROL BX,CL为P: MOV BX,DIMOV CH,2L: MOV CL,4ROL BL,CL问题想是可以得以解决。重新汇编,并运行程序。6. 实验结果1)G 运行后提示符提示
16、输入字符,结果如下回显输入的字符2)DOS 10 号功能调用,输入字符串到自定义的缓冲区内,并会显字符串到屏幕,如下 a 为 debug 下,b 为 dos 界面下。图 a图 b3)未进行换行操作换行后显示结果如下4)通过 MOV ES:160*1+40*2,AH 向 B80F0H 写入字符X,立即显示结果如下5)5.1 修改 DI 变动的问题后,运行结果和预期的差不多,但由于是通过显存修改来显示,之前的内容未被清零,就出现了覆盖现象如下对此,只要修改首列显示位置,及列显示上限即可,于是修改 MOV BL,1 为MOV BL,35(从 35 列开始打印),修改 DEC AX 和 MOV SI,
17、AX 为 ADD AX,34 结果是整体移动了位置,却又出现了错误的图案如下原本一个简单的加法,因被我忽略了未修改时起始位子 1,而多加了一个打印上限,被弄的晕头转向的,最终还是在 debug 单步运行时发现了问题所在。修改 34 为 33,终于得到了正确的结果如图6)分析并修改一系列错误后,更正 DOS 2 号功能调用输出换行符,得到预期结果如下,其中一行为负数个数,二行为 0 的个数,三行为正数个数。7. 质疑,建议,问题讨论和总结此次实验是上机以来花了最长时间的一次,从分析各个程序,单步跟踪来理解程序的个步骤及作者的整体思路,加之利用所学分析并解决问题,让我更深入的看到了设计一个程序的思路的严谨的重要性,其中修改显存显示的方法让我掌握了一个简单却实用的 DOS 调用功能,而通过 5)要求的再一次利用与实现使我对其认识更进一层,通过自己分析 5)和 6)的问题转换为数学逻辑表达式使得本繁杂的程序得以很大程度上得以简化,总之长时间的付出并没白费,虽然其中确实不甘心一次 openoffice 崩溃导致文档的从头重新编写,不过还算顺利完成了任务,也给自己一个不备份文件的教训了。