一、实验要求
1.熟悉并掌握EMU8086 汇编语言调试环境;
2.学习8086 的指令系统,输入简单的指令,观察各寄存器、内存相关单元以及处理器标志位的变化(数据传送类指令,算数运算类指令,逻辑运算类指令,标志处理和CPU控制类指令, 移位和循环移位类指令,处理器控制类指令等, 要求每类指令至少一个用例。具体用例自行设计,可参考教材用例);
3.学习汇编语言程序设计的基本步骤和方法;
4.学会使用EMU8086 debug调试程序;
二、实验目的
1.学习EMU8086仿真开发环境的使用,理解和掌握汇编语言编程的基本步
骤;
2.熟悉8086指令系统;
3.熟悉变量、常量及伪指令的使用;
4.熟悉内存单元的存储结构,字符串的处理以及简单的编程。
三、实验过程(调试分析)
实验一:熟悉并掌握EMU8086 汇编语言调试环境
启动界面,用户可以选择新建文本、程序实例、启动指南、近期文档。新建文档,用户可以选择四类模板。
①COM——无需分段,所有内容均放在代码段中,程序代码默认从ORG 0100H开始
②EXE——需要分段,内容按代码段、数据段、堆栈段划分,编译器自动完成空间的分配
③BIN——二进制文件,适用于所有用户定义的结构类型
④BOOT——适用于在软盘中创建的文件
此外,选择empty workspace可以创建空的文档。
启动界面和新建文档选择界面如下所示。
实验二:寻址方式
1.立即寻址
立即寻址就是指令当中自带数据,直接读取,最快。
操作数作为指令的一部分而直接写在指令中,这种操作数称为立即数,这种寻址方式也就称为立即数寻址方式。立即数可以是8位、16位,该数值紧跟在操作码之后。如果立即数为16位,那么,它将按“高高低低”的原则进行存储。“高高低低”是指高八位和低八位。如AX有高八位字节AH 和低八位字节AL。指令中的第二操作数都是立即数,在汇编语言中,规定:立即数不能作为指令中的第二操作数。该规定与高级语言中“赋值语句的左边不能是常量”的规定相一致。
立即数寻址方式通常用于对通用寄存器或内存单元赋初值。
例如:
MOV BL, 12H
MOV CH, 34H
MOV DX, 8000H
CS:IP 两个寄存器指示了 CPU 当前将要读取的指令的地址,其中CS为代码段寄存器,而IP为指令指针寄存器。在8086(8088)读程序时,CS、IP通过内部总线到地址加法器计算物理地址,通过外部总线到内存取指令操作码。 CPU 从起始地址开始往下读取指令,读取完指令后,CS:IP将会自动的改变,基本上是改变IP,从而指向下一条要读取的指令。例如本次实验中,CPU为了执行 MOV BL, 12H这条指令,已经将内存中相对应的3个内存单元读入内存中了。所以,执行完这条指令后,CPU就要将偏移地址向下移动3个单元,从而使得CS:IP指向下一条需要执行的指令,IP加3,因此CS代码段寄存器CS=0100H,指令指针寄存器IP=0007H,读程序的内存物理地址=CSx16+IP=01000H+0007H=01007H。
2.直接寻址
直接寻址就是指令中存放的是地址,直接解析这个地址。
直接寻址的特点是在指令中直接给出参与运算的操作数及运算结果所存放的主存地址,即在指令中直接给出有效地址。汇编语言中,带方括号“[ ]”的操作数表示存储器操作数,括号中的内容作为存储单元的有效地址EA。存储器操作数本身并不能表明地址的类型,而需通过另一个寄存器操作数的类型或别的方式来确定。由于目标操作数AX为字类型,源操作数也应与之配套,所以有效地址EA=2000H为字单元。
操作数在寄存器中,指令直接包含有操作数的有效地址(偏移地址),操作数一般存放在数据段中,所以操作数的地址由DS加上指令中直接给出的16位偏移得到。物理地址=(DS)×16+EA
例如:
MOV DX, 100H (立即寻址)
MOV DS, DX (寄存器寻址)
MOV BX, DS:[1DH]
在该寻址方式中,操作数是在存储单元中,所以通过查看EMU8088中存储操作数的情况,对实验结果进行判断分析。
取物理的地址就是DS×16+1DH=0101DH,结合上图(内存地址分布图),我们可以推断BX中的内容。即从0101DH单元取90放入BL中,从0101EH中取F4放入BH中,所以BX中的内容为F490H。我们可以看到下图中BX的结果符合我们的判断。
3.寄存器寻址
寄存器寻址方式是一种简单快捷的寻址方式,源和目的操作数都可以是寄存器。
指令所要的操作数已存储在某寄存器中,或把目标操作数存入寄存器。把在指令中指出所使用寄存器(即:寄存器的助忆符)的寻址方式称为寄存器寻址方式。
指令中可以引用的寄存器及其符号名称如下:
8位寄存器有:AH、AL、BH、BL、CH、CL、DH和DL等;
16位寄存器有:AX、BX、CX、DX、SI、DI、SP、BP和段寄存器等;
32位寄存器有:EAX、EBX、ECX、EDX、ESI、EDI、ESP和EBP等。
例如:
MOV AX, 03H
MOV BL, 12H
MOV DS, AX
MOV CH, BL
4.寄存器间接寻址
在寄存器间接寻址方式中,操作数存放在存储器中,操作数的16位段内偏移地址存放在4个寄存器SI、DI、BP、BX之一中。
由于上述4个寄存器所默认的段存储器不同,故又可以分成两种情况:
(1)若以SI、DI、BX这三个寄存器进行寄存器间接寻址,则操作数通常放在DS所决定的数据段中。此时数据段寄存器内容乘16加上SI、DI、BX中的十六位段内偏移地址,即得操作数的地址。
例如:
MOV AX, 0100H
MOV DS, AX
MOV DI, 004EH
MOV SP, [DI]
上面第四条指令执行时,操作数的地址为DS×16+DI=0104EH,即从0104EH单元和0104FH中各取一个字节放入SP中。
(2)若以寄存器BP间接寻址,则操作数存放在堆栈段区域中。此时,堆栈寄存器SS的内容乘16加上BP中的16位段内偏移地址,即得操作数的地址。
例如:
MOV AX, 0100H
MOV SS, AX
MOV BP, 001EH
MOV BX, [BP]
执行上面的指令时,第4条指令从0101EH单元取一个字节放入BL,从0101FH单元中取一个字节放入BH中。
在这里说明段超越问题。在对存储器操作数寻址时,存储单元的物理地址由段寄存器的内容和偏移地址来决定。8088(8086)指令系统对段寄存器有基本规定,即默认状态。指令中的操作数也可以不在基本规定的默认段内,这时就必须在指令中明确指定段寄存器,这就是段超越。
例如: MOV AX, ES: [SI]
该指令中ES为段超越前缀,指令功能就是从ES16+SI形成的物理地址及其下一个地址中取一个字节放入SP中。
在指令中,默认段寄存器是可以缺省的,而段超越的前缀是不能缺省的,必须明确指定。当使用段超越前缀时,指令代码增加一个字节,从而也增加了指令的执行时间。因此,能不用段超越时尽量不用。
5.寄存器相对寻址
在寄存器相对寻址方式中,操作数存放在存储器中,操作数的地址是由段寄存器内容乘16加上SI、DI、BP、BX之一的内容,再加上由指令中所给出的8位或16位带符号的位移量而得到的。
在一般情况下,若用SI、DI或BX进行相对寻址,默认数据段寄存器DS作为地址基准;若用BP寻址,则默认堆栈寄存器SS为地址基准。
例如:
MOV AX, 0100H
MOV DS, AX
MOV SI, 0022H
MOV BX, [SI-3]
则执行寄存器相对寻址指令时,操作数的物理地址为
DS×16+SI-3=01022H-3=0101FH
即从地址0101F单元取一个字节放入BL。
6.基址、变址寻址
在8088(8086)中,通常把BX和BP作为基址寄存器,而把SI和DI作为变址寄存器。将这两种寄存器联合起来进行的寻址就称为基址、变址寻址。操作数的地址应该是段寄存器内容乘16加上基址寄存器内容(BX或BP内容),再加上变址寄存器内容(SI或DI内容)而得到的。
同理,若用BX作为基地址,则操作数应放在数据段DS所决定的内存区域中;若BP作为基地址,则操作数应放在堆栈段SS所决定的内存区域中。
例如:
MOV DX, 0100H
MOV SS, DX
MOV BP, 0001H
MOV DI, 0020H
MOV AX, [BP][DI]
操作数地址应该为SS×16+BP+DI=01021H,则在执行基址变址指令时,就是从01020H单元分别取一个字节放入AH中,从01021H单元分别取一个字节放入AL中。
7.基址、变址、相对寻址
这种方式实际上是第6种寻址方式的扩充。操作数的地址是由基址、变址方式得到的地址再加上由指令指明的8位或16位的相对便宜地址而得到的。
例如:
MOV DX, 0100H
MOV SS, DX
MOV BP, 0001H
MOV DI, 0020H
MOV AX,[BP+DI+01H]
上述代码仅对第六种寻址代码的最后一行做了修改。
操作数地址应该为SS×16+BP+DI+01H=01022H,则在执行基址变址指令时,就是从01022H单元取一个字节放入AL中。