北邮微机原理软件实验报告

更新时间:2024-06-20 14:23:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实验一 DEBUG 的使用 一、实验目的

1.掌握汇编程序的编辑,编译,连接和执行的全过程; 2.学习和掌握用DEBUG调试程序的方法.

二、实验任务及内容

用 DEBUG 将可执行文件调入,并进行调试.

(1)用 D 命令观察数据区在内存中的具体内容,记录单元 A 和 B 的具体地址. A的地址是:0B89H:0000H;B的地址是:0B89H:0001H

(2)用 U 命令对目标代码反汇编,观察反汇编后的结果.注意发现源程序的起始位置, 并记录这个起始地址.

DATA段段基址:0B89H A的偏移地址:0000H B的偏移地址:0001H Y的偏移地址:0002H Z的偏移地址:0005H STACK段段基址:0B8AH CODE段段基址:0B91H 第一条指令的偏移地址:000H 子程序SUB1入口的偏移地址:003FH

(3)用 T 命令作单步跟踪调试.比较每条指令执行后的结果和原来的理解是否一致.得出程序运行的结果:它们是写在什么单元,具体内容是什么; 并判断结果是否正确.

1、这是第一次调用SUB1子程序退出后的结果,从图中可以看出Y存储的数据是400,即是A*A的结果。

2、这是第二次调用SUB1子程序退出后的结果,从图中可以看出执行完“MUL AH”指令后,AX存储的数据是225,即是B*B的结果,子程序退出后Y存储的数据是625,即是400+225的结果。

3、这是第三次调用SUB1子程序的结果,从图中可以看出执行完“MUL AH”指令后,AX存储的数据是300,即是A*B的结果,子程序退出后Y存储的数据是925,即是625+300的结果。

4、这是程序退出时的最终结果,从图中可以看出,Y存储的数据最终为 1225 ,即为(A+B)*(A+B)的结果。结果正确。

(4)在子程序 SUB1 的入口处设一断点,用 G 命令执行程序. 在断点处观察堆栈的内容,比较堆栈的内容和程序返回地址是否一致.

从图中可以看出, IP指针的变化说明调用了子程序SUB1,而堆栈段段基址SS和栈顶指针SP的值都没有改变。程序返回地址一致。

ADD DL,'0' INT 21H

MOV AH,09H

MOV DX,SEG STRING0 MOV DS,DX

MOV DX,OFFSET STRING0 INT 21H

;正奇数的个数 MOV AH,09H

MOV DX,SEG STRING3 MOV DS,DX

MOV DX,OFFSET STRING3 INT 21H

MOV AH,02H MOV DL,PJ ADD DL,'0' INT 21H

MOV AH,09H

MOV DX,SEG STRING0 MOV DS,DX

MOV DX,OFFSET STRING0 INT 21H

;正偶数的个数 MOV AH,09H

MOV DX,SEG STRING4 MOV DS,DX

MOV DX,OFFSET STRING4 INT 21H

MOV AH,02H MOV DL,PO ADD DL,'0' INT 21H

MOV AH,09H

MOV DX,SEG STRING0 MOV DS,DX

MOV DX,OFFSET STRING0 INT 21H ;负数的个数 MOV AH,09H

MOV DX,SEG STRING5 MOV DS,DX

MOV DX,OFFSET STRING5 INT 21H

MOV AH,02H

MOV DL,M ADD DL,'0' INT 21H

MOV AH,09H

MOV DX,SEG STRING0 MOV DS,DX

MOV DX,OFFSET STRING0 ;负奇数的个数 INT 21H

MOV AH,09H

MOV DX,SEG STRING6 MOV DS,DX

MOV DX,OFFSET STRING6 INT 21H

MOV AH,02H MOV DL,MJ ADD DL,'0' INT 21H

MOV AH,09H

MOV DX,SEG STRING0 MOV DS,DX

MOV DX,OFFSET STRING0 INT 21H

;负偶数的个数 MOV AH,09H

MOV DX,SEG STRING7 MOV DS,DX

MOV DX,OFFSET STRING7 INT 21H

MOV AH,02H MOV DL,MO ADD DL,'0' INT 21H

MOV AH,09H

MOV DX,SEG STRING0 MOV DS,DX

MOV DX,OFFSET STRING0 INT 21H

MOV AH,4CH INT 21H CODES ENDS END START 四、程序流程图

开始 进入循环 是 否 负数+1 判断>=0 是 非负数 判断奇偶偶 负偶数+1 性奇 负奇数+1 是 正数+1 判断>0 否 零+1 奇偶判断 偶 正偶数+1 奇 正奇数+1 判断是否继续循环 否 输出结果 结束

五、程序运行结果

六、预习题:

1.十进制数 0 -- 9 所对应的 ASCII 码是什么? 如何将十进制数 0 -- 9 在屏幕上显示出来?

答:0的ASCII码是30h,以后依次递增。 要屏显0-9的数码,只需将AH置成02H(DOS功能调用),然后将要显示的数码的ASCII码存进DL里,然后执行INT 21H就可以打印字符。 或者,若这些数码是以字符串的格式存储,则可以将AH置成09H,(最后以’$’字符结束,)然后将串首地址传给DS,然后执行INT 21H就可以打印字符串。 2.如何检验一个数为正,为负或为零? 你能举出多少种不同的方法?

答:可以将待检验数与0比较(使用CMP指令后判断CF、OF或者以表达式【实用EQ、GE等操作符】的返回值来判断),也可以将待检验数与80H相与,判断ZF的值。 七、心得体会:

这个实验有两个要点,其实就是两个预习题目里讨论的问题。

一是字符显示。要显示数字字符,首先要把数据转换成ASCII码,然后调用DOS功能将其显示。其中使用09H号功能时,要特别注意每段待输出的字符串要以’$’结尾,不然无法识别串尾,输出乱码。

二是判断正负数。本程序选用CMP指令来实现该功能。注意与0相比时,要使用有符号数的条件跳转指令,JGE等等,在使用无符号数的条件跳转指令时,不是与0相比较。

判断奇偶同样也有很多途径,这里选择将待判别的数与01H相与后改变的标志位来判断奇偶,用TEST指令是一个很好的选择。

另外,通过这次试验,我对汇编程序的分支、循环结构有了进一步的理解。

实验三 代码转换程序设计 一、实验目的:

1.掌握几种最基本的代码转换方法; 2.运用子程序进行程序设计。

二、实验要求及内容:

1.从键盘上输入若干两位十进制数,寻找其中的最小值,然后在屏幕上显示出来; 2.两个十进制数之间的分隔符,输入结束标志自定,但要在报告中说明; 3.对输入要有检错措施,以防止非法字符输入,并有适当的提示;

4.将整个程序分解为若干模块,分别用子程序实现.在报告中要给出模块层次图。

三、源程序

DATA SEGMENT BUFFER DB 100

STR1 DB 'Please input number(space as list separator and enter as end):$' STR2 DB 'The minimum :$'

STR3 DB 'WHAT YOU HAVE INPUT IS WRONG!$' STR4 DB 0AH,0DH,'$' MIN DW ? DATA ENDS

STACK SEGMENT STACK 'stack' DB 100 DUP('s') STACK ENDS

CODE SEGMENT PARA'code'

ASSUME CS:CODE,DS:DATA,SS:STACK START PROC FAR

MOV AX,DATA MOV DS,AX

CALL INPUT ;调用INPUT子程序

CALL COMPARE ;调用COMPARE子程序 CALL OUTPUT ;调用OUTPUT子程序 MOV AH,4CH INT 21H START ENDP ;输入字符子程序 INPUT PROC

MOV DX,OFFSET STR1 ;输入显示 MOV AH,9 INT 21H

MOV DX,OFFSET STR4 MOV AH,9 INT 21H

LEA BX,BUFFER

RE1: ;输入字符,进行独立判断,并

MOV AH,1 ;保存需要判断大小的字符 INT 21H CMP AL,39H JA ERO CMP AL,30H JB ERO

MOV [BX],AL MOV AH,1 INT 21H CMP AL,39H JA ERO CMP AL,30H JB ERO

MOV [BX+1],AL MOV AH,1 INT 21H

CMP AL,0DH JZ FINISH CMP AL,' ' JZ RE JMP ERO RE:

INC BX INC BX JMP RE1

ERO: MOV DX,OFFSET STR4 MOV AH,09H INT 21H

MOV DX,OFFSET STR3 MOV AH,09H INT 21H

MOV DX,OFFSET STR4 MOV AH,09H INT 21H JMP RE1 FINISH:

MOV [BX+2],AL RET INPUT ENDP ;比较大小子程序 COMPARE PROC

LEA BX,BUFFER MOV AH,[BX] MOV AL,[BX+1]

;判断是否符合条件 ;保存结束符 RE2:

ADD BX,2 ;比较高位 CMP AH,[BX] JZ RE3 JB RE4

MOV AH,[BX] MOV AL,[BX+1] JMP RE4

RE3: ;高位相等,比较低位 CMP AL,[BX+1] JB RE4

MOV AL,[BX+1] JMP RE4

RE4: MOV CL,[BX+2] CMP CL,0DH JNE RE2

MOV MIN,AX RET

COMPARE ENDP ;输出子程序

OUTPUT PROC

MOV AH,09H

MOV DX,OFFSET STR4 INT 21H

MOV AH,09H

MOV DX,OFFSET STR2 INT 21H

LEA SI,MIN+1 MOV DL,[SI] MOV AH,02H INT 21H

MOV SI,OFFSET MIN MOV DL,[SI] MOV AH,02H INT 21H RET

OUTPUT ENDP CODE ENDS

END START

四、程序流程图

;判断是否结束 ;保存最小值 ;先输出高位 ;再输出低位 开始 结束程序 程序初始化 显示输出最小值 调用输入子程序 调用显示子程序 显示提示语 返回主程序 报错提示重新输入 否 输入字符判断是否为0~9 是 是否结束 否 继续输入字符判断 空格 比较低位 是 保存较小的数 否 比较高位是否相等 否 否 输入结束符或间隔符 提取前一个数与后一个数比较 回车 返回主程序 调用比较子程序

五、程序运行结果

六、预习题:

1.如何将输入的两个字符(0 -- 9)变为十进制或二进制数?

答:可以通过将字符的减去30H再乘以10D,加上个位的值(同样要将ASCII码减去30H变为十进制数)即可得两个字符的十进制数。

2.如何将选出的最小值(二进制或十进制)变为 ASCII 码再进行显示?

答:选出最小十进制数后可以通过除十得到余数和商,商为高位,余数为低位,分别对这两个加30H即可到得其ASCII码。

3.你觉得采用二进制运算还是十进制运算更适合于这个实验?

答:个人觉得采用二进制运算更简便,这样可以直接使用ASCII码比较,使问题简化。

七、心得体会: 做这个实验的过程中出了一些错误,最开始的代码在运行时输出乱码,这个问题困扰了我很久。后来我通过单步调试,发现是因为调用子程序时没有注意现场保护,几个寄存器被多次赋值,导致结果显示时不仅不能输出正确结果,程序还跑飞了。所以比较和显示时都出现了问题。经过这次实验,我发现汇编编程过程中一定要注意,在子程序调用时要做好现场保护,毕竟汇编不像高级语言,子程序压栈出栈的过程对编程者并不是透明的。

实验四 子程序设计 一、实验目的:

1.进一步掌握子程序设计方法;

2.进一步掌握基本的 DOS 功能调用.

二、实验内容:

1.从键盘上输入某班学生的某科目成绩.输入按学生的学号由小到大的顺序输入. 2.统计检查每个学生的名次. 3.将统计结果在荧幕上显示.

4.为便于观察,输入学生数目不宜太多,以不超过一屏为宜.输出应便于阅读.尽可能考虑美观. 5.输入要有检错手段

三、源程序

DATA SEGMENT BUFFER DB 100 ;定义缓冲区,最多允许输入100个字符(包括回车) DB ? ;存放实际输入的字符数(不包括回车) DB 100 DUP (?) ;存放输入的字符串 STR1 DB 'Input the score of the students:',0DH,0AH,'$'

STR2 DB 0DH,0AH,'Error! Please input the score again:',0DH,0AH,'$' VAR1 DW ? VAR2 DW ? FLA DB ?

NUM DB 100 DUP(?) DATA ENDS

STACK SEGMENT STACK 'STACK' DB 100 DUP ('s') STACK ENDS

CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK START: MOV AX,DATA MOV DS,AX MOV AH,09H ;输出提示语 MOV DX,SEG STR1 MOV DS,DX MOV DX,OFFSET STR1 INT 21H

INPUT: MOV DX,SEG BUFFER ;输入成绩 从BUFFER+2开始的单元存放 MOV DS,DX MOV DX,OFFSET BUFFER MOV AH,0AH INT 21H LEA DI,NUM ;DI指向存放区域首地址

XOR CX,CX ;CX清零 MOV AH,30H ;赋学号第一位的AscII码 \ MOV DH,31H ;赋学号第二位的AscII码 \ LEA BX,BUFFER+2 ;BX指向第一个成绩数据 CALL CHECK CMP FLA,1 ;输入错误则重新输入 JZ INPUT CALL COM MOV AH,02H ;输出回车及换行 MOV DL,0DH INT 21H MOV AH,02H MOV DL,0AH INT 21H CALL DISPY MOV AX,4C00H INT 21H

CHECK PROC

NEXT: MOV FLA,0 MOV [DI],AH ;将学号第一位的AscII码存入指定内存区域 MOV [DI+1],DH ;将学号第二位的AscII码存入指定内存区域 INC DI INC DI ;指向下一个 CMP DH,39H ;十进制转换 JZ DECA INC DH ;学号+1 JMP NEXT1 DECA: MOV DH,30H ;满十进一 INC AH

NEXT1: MOV AL,[BX] ;检查分数的AscII码 CMP AL,30H ;若小于30h(“0”),则报错 JB ERROR CMP AL,39H ;若大于39h(“9”),则报错 JA ERROR MOV [DI],AL ;若正确,则存储 INC DI ;查下一个数 INC BX

MOV AL,[BX] CMP AL,30H ;检查第二位的AscII码 JB ERROR CMP AL,39H JA ERROR MOV [DI],AL ;若正确,则存储

INC DI INC BX INC CX ;已存个数+1 MOV AL,[BX] ;判断是否为回车符 CMP AL,0DH JZ FINISH1 ;是回车 则回主程序 转入冒泡排序 CMP AL,20H ;判断是否为空格 JNZ ERROR ;不是则报错 INC BX ;是 则BX+1后继续检查 JMP NEXT ERROR: MOV AH,09H ;报错 MOV DX,SEG STR2 MOV DS,DX MOV DX,OFFSET STR2 INT 21H MOV FLA,1 FINISH1:RET

CHECK ENDP

COM PROC

COMP1: PUSH CX ;保存现场 MOV VAR1,CX ;先通过运算得到两个需要的常量 VAR1为数据组数 SHL CX,1 SHL CX,1 ;乘以4为数据总字节数 SUB CX,4 MOV VAR2,CX POP CX ;恢复现场 DEC DI

DEC DI ;DI指向最后一个分数的十位的AscII码 JMP COTI

COMP2: ADD DI,VAR2 ;比较完一轮后,使DI指向最后一个分数的十位的AscII码

COTI: MOV BL,0 ;建立标志 MOV CX,VAR1 DEC CX ;比较次数 AGAN: MOV AL,[DI] CMP AL,[DI-4] JA CHAN1 ;大于,则交换 JB COTI2 MOV AL,[DI+1] ;十位相同 比较个位 CMP AL,[DI-3] JA CHAN1 JBE COTI2

CHAN1: MOV BL,1 ;若要交换,修改标志, PUSH CX MOV CX,4 DEC DI

DEC DI ;使DI指向该分数对应的学号的第一位的AscII码 CHAN2: MOV AL,[DI] ;交换 XCHG AL,[DI-4] MOV [DI],AL INC DI LOOP CHAN2 POP CX DEC DI DEC DI 码

COTI2: DEC DI DEC DI DEC DI

DEC DI 便进行下次比较 LOOP AGAN CMP BL,0 JNZ COMP2 DEC DI DEC DI MOV CX,VAR1 MOV BH,30H MOV BL,31H RET

COM ENDP

DISPY PROC

DISPY1: MOV DL,BH MOV AH,02H INT 21H MOV DL,BL

MOV AH,02H INT 21H

MOV DL,20H MOV AH,02H INT 21H

MOV DL,[DI] MOV AH,02H INT 21H INC DI

;修改DI,使DI指向高地址分数的十位的AscII ;修改DI,使DI指向高分数的十位的AscII码,以 ;若标志没被修改,则排序完成 ;修改DI,使DI指向最高分对应的学号 ;显示次数 ;名次 十位AscII码 ;名次 个位AscII码 ;先输出名次 ;输出空格 ;再输出学号 MOV DL,[DI] MOV AH,02H INT 21H INC DI

MOV DL,20H MOV AH,02H INT 21H MOV DL,[DI] ;输出空格

;输出分数

MOV AH,02H INT 21H INC DI MOV DL,[DI] MOV AH,02H INT 21H INC DI

MOV DL,0DH MOV AH,02H INT 21H MOV DL,0AH MOV AH,02H INT 21H CMP BL,39H JZ DECA2 INC BL JMP NEXT2

DECA2: MOV BL,30H INC BH NEXT2: LOOP DISPY1 RET DISPY ENDP CODE ENDS END START

四、程序流程图

;回车并换行,准备下一轮输出

检错 输出显示

五、程序运行结果

开始 初始化 显示提示 输入成绩 调用检错子程序 否 输入是否正确 是 调用比较子程序 比较 调用显示子程序 结束

六、预习题

1.如何确定一个学生在这门科目中的名次? 答:利用排序,看最后这个学生的位置

2.你觉得输入结束后,采用什么方法进行比较以得到学生的名次最为简单? 答:冒泡排序 七、心得体会

通过这次试验学会了子程序的使用,可以对子程序重复利用简便了程序的编译,使得编写简便了许多。在编写过程中发现PUSHF及POPF的用处显得尤为重要,对冒泡排序的正确性起了决定性作用。并且学会了如何使用指针。完成这次实验后我觉得学习过的各种编程,不管是C++还是数据结构或者汇编都是相互贯通的。

六、预习题

1.如何确定一个学生在这门科目中的名次? 答:利用排序,看最后这个学生的位置

2.你觉得输入结束后,采用什么方法进行比较以得到学生的名次最为简单? 答:冒泡排序 七、心得体会

通过这次试验学会了子程序的使用,可以对子程序重复利用简便了程序的编译,使得编写简便了许多。在编写过程中发现PUSHF及POPF的用处显得尤为重要,对冒泡排序的正确性起了决定性作用。并且学会了如何使用指针。完成这次实验后我觉得学习过的各种编程,不管是C++还是数据结构或者汇编都是相互贯通的。

本文来源:https://www.bwwdw.com/article/yqm3.html

Top