实验报告课程名称:《微机原理》实验第3次实验实验名称:宏命令与子程序的区别实验时间:2015年10月13日实验地点:XXXXXX组号__________学号:XXXX姓名:XXX指导老师:XX评定成绩:___________微机原理实验4南京大学工程管理学院一、实验设备:计算机二、实验用时:4小时三、实验内容:1.单步运行实例函数NO3_Mpy_8,了解单字节无符号数乘法的实现方法。2.编写子程序Mpy_16,实现双字节无符号数乘法。自行定义变量,其中:ACCALO;存放乘数低8位ACCAHI;存放乘数高8位ACCBLO;存放被乘数低8位和乘积第16~23位ACCBHI;存放被乘数高8位和乘积第24~31位ACCCLO;存放乘积第0~7位ACCCHI;存放乘积第8~15位编写Main主程序,使用乘数0x4015和被乘数0x3321对编写的子程序进行测试,结果应为0x0CCC71B5。3.编写宏命令Mpy_16,实现单字节无符号数乘法。编写Main主程序调用宏命令并对运算结果进行测试。4.使用反汇编工具DisassemblyListing单步运行程序,观察子程序与宏命令的差异。四、实验报告要求:1.程序框图和源程序清单。2.分析宏扩展过程,说明宏与子程序的差别。五、实验结果:1、程序框图(1)子程序Mpy_16否是子程序调用初始化循环计数器TEMP将乘数ACCBHI、ACCBLO复制到MDHI、MDLO中ACCAHI、ACCBHI、ACCALO、ACCBLO分别相加,结果放入ACCBHI、ACCBLO中ACCBHI、ACCBLO、ACCCHI、ACCCLO清零MDHI、MDLO算数右移一位,最低位进入CC=1?否是(2)宏命令Mpy_16ACCBHI、ACCBLO带进位位右移,最低位放入C中ACCCHI、ACCCLO带进位位右移,最低位放入C中TEMP=TEMP-1TEMP=0?子程序返回开始初始化循环计数器TEMP将乘数ACCBHI、ACCBLO复制到MDHI、MDLO中ACCBHI、ACCBLO、ACCCHI、ACCCLO清零否是否是2、源程序清单(1)子程序Mpy_16listp=16f877A;listdirectivetodefineprocessorACCBHI、ACCBLO带进位位右移,最低位放入C中ACCAHI、ACCBHI、ACCALO、ACCBLO分别相加,结果放入ACCBHI、ACCBLO中ACCCHI、ACCCLO带进位位右移,最低位放入C中MDHI、MDLO算数右移一位,最低位进入CTEMP=TEMP-1C=1?TEMP=0?结束#includep16f877A.inc;processorspecificvariabledefinitions__CONFIG_CP_OFF&_WDT_OFF&_BODEN_OFF&_PWRTE_OFF&_HS_OSC&_WRT_OFF&_LVP_OFF&_CPD_OFFACCALOEQU0x20;存放加数低8位ACCAHIEQU0x21;存放加数高8位ACCBLOEQU0x22;存放被加数低8位ACCBHIEQU0x23;存放被加数高8位ACCCLOEQU0x24;ACCCHIEQU0x25;MDLOEQU0x26;MDHIEQU0x27;TEMPEQU0x28;临时寄存器;双字节加法子程序,入口地址ACCB+ACCA,出口地址ACCORG0x0000;复位入口地址nop;兼容ICD调试工具,必须加nopgotoMain;跳转至Main函数MainMOVLW0x15;MOVWFACCALO;MOVLW0x40;MOVWFACCAHI;MOVLW0x21;MOVWFACCBLO;MOVLW0x33;MOVWFACCBHI;CALLMPY_16;NOP;GOTO$;ORG0x0100MPY_16CALLSETUP;MLOOPBCFSTATUS,C;清进位位RRFMDHI;MD右移RRFMDLO;BTFSCSTATUS,C;判断是否需要相加CALLAdd_16;加乘数至MBRRFACCBHI;右移部分乘积RRFACCBLO;RRFACCCHI;RRFACCCLO;DECFSZTEMP;乘法完成否?GOTOMLOOP;否,继续求乘积RETURN;子程序返回SETUPMOVLW.16;初始化TEMP寄存器MOVWFTEMPMOVFACCBLO,W;乘数送MDMOVWFMDLO;MOVFACCBHI,W;MOVWFMDHI;CLRFACCBLO;清MBCLRFACCBHI;CLRFACCCLO;清MCCLRFACCCHI;RETURN;子程序返回Add_16MOVFACCALO,w;ACCB和ACCA低半字节相加ADDWFACCBLO,f;BTFSCSTATUS,C;有进位否?INCFACCBHI;有,ACCB高字节加1,再加ACCAHIMOVFACCAHI,w;ACCA、ACCB高半字节相加ADDWFACCBHI,f;RETURN;子程序返回END;(2)宏命令Mpy_16listp=16f877A;listdirectivetodefineprocessor#includep16f877A.inc;processorspecificvariabledefinitions__CONFIG_CP_OFF&_WDT_OFF&_BODEN_OFF&_PWRTE_OFF&_HS_OSC&_WRT_OFF&_LVP_OFF&_CPD_OFFMPY_16macroACCALO1,ACCAHI1,ACCBLO1,ACCBHI1,ACCCLO1,ACCCHI1,MDHI1,MDLO1,TEMP1;SETUPACCALO1,ACCAHI1,ACCBLO1,ACCBHI1,ACCCLO1,ACCCHI1,MDHI1,MDLO1,TEMP1;MLOOPBCFSTATUS,C;清进位位RRFMDHI1;MD右移RRFMDLO1;BTFSSSTATUS,C;判断是否需要相加GOTOLOOP;Add_16ACCALO1,ACCAHI1,ACCBLO1,ACCBHI1,ACCCLO1,ACCCHI1,MDHI1,MDLO1,TEMP1;加乘数至MBLOOPRRFACCBHI1;右移部分乘积RRFACCBLO1;RRFACCCHI1;RRFACCCLO1;DECFSZTEMP1;乘法完成否?GOTOMLOOP;否,继续求乘积ENDM;子程序返回SETUPmacroACCALO2,ACCAHI2,ACCBLO2,ACCBHI2,ACCCLO2,ACCCHI2,MDHI2,MDLO2,TEMP2;MOVLW.16;初始化TEMP寄存器MOVWFTEMP2MOVFACCBLO2,W;乘数送MDMOVWFMDLO2;MOVFACCBHI2,W;MOVWFMDHI2;CLRFACCBLO2;清MBCLRFACCBHI2;CLRFACCCLO2;清MCCLRFACCCHI2;ENDM;子程序返回Add_16macroACCALO3,ACCAHI3,ACCBLO3,ACCBHI3,ACCCLO3,ACCCHI3,MDHI3,MDLO3,TEMP3;MOVFACCALO3,w;ACCB和ACCA低半字节相加ADDWFACCBLO3,f;BTFSCSTATUS,C;有进位否?INCFACCBHI3;有,ACCB高字节加1,再加ACCAHIMOVFACCAHI3,w;ACCA、ACCB高半字节相加ADDWFACCBHI3,f;ENDM;子程序返回ACCALOEQU0x20;存放加数低8位ACCAHIEQU0x21;存放加数高8位ACCBLOEQU0x22;存放被加数低8位ACCBHIEQU0x23;存放被加数高8位ACCCLOEQU0x24;ACCCHIEQU0x25;MDLOEQU0x26;MDHIEQU0x27;TEMPEQU0x28;临时寄存器;双字节加法子程序,入口地址ACCB+ACCA,出口地址ACCORG0x0000;复位入口地址nop;兼容ICD调试工具,必须加nopgotoMain;跳转至Main函数MainMOVLW0x15;MOVWFACCALO;MOVLW0x40;MOVWFACCAHI;MOVLW0x21;MOVWFACCBLO;MOVLW0x33;MOVWFACCBHI;MPY_16ACCALO,ACCAHI,ACCBLO,ACCBHI,ACCCLO,ACCCHI,MDHI,MDLO,TEMP;NOP;GOTO$;END;3、程序运行结果截图(1)子程序Mpy_16子程序运行结果(2)宏命令Mpy_16宏指令运行结果4、分析宏扩展过程,说明宏与子程序的差别(1)子程序Mpy_16的反汇编结果子程序的反汇编代码1子程序的反汇编代码2(2)宏命令Mpy_16的反汇编结果00000000NOP00012802GOTO0x200023015MOVLW0x15000300A0MOVWF0x2000043040MOVLW0x40000500A1MOVWF0x2100063021MOVLW0x21000700A2MOVWF0x2200083033MOVLW0x33000900A3MOVWF0x23000A3010MOVLW0x10000B00A8MOVWF0x28000C0822MOVF0x22,W000D00A6MOVWF0x26000E0823MOVF0x23,W000F00A7MOVWF0x27001001A2CLRF0x22001101A3CLRF0x23001201A4CLRF0x24001301A5CLRF0x2500141003BCF0x3,000150CA7RRF0x27,F00160CA6RRF0x26,F00171C03BTFSS0x3,00018281FGOTO0x1f00190820MOVF0x20,W001A07A2ADDWF0x22,F001B1803BTFSC0x3,0001C0AA3INCF0x23,F001D0821MOVF0x21,W001E07A3ADDWF0x23,F001F0CA3RRF0x23,F00200CA2RRF0x22,F00210CA5RRF0x25,F00220CA4RRF0x24,F00230BA8DECFSZ0x28,F00242814GOTO0x1400250000NOP00262826GOTO0x2620072394CALL0x394(3)宏扩展过程宏扩展只是用原来宏定义中的若干条汇编指令代替程序中的“一条”宏指令插入到此宏指令位置处,进行直接替换功能。(4)宏与子程序的差别宏指令(宏扩展)只是用原来宏定义中的若干条汇编指令代替程序中的“一条”宏指令插入到此宏指令位置处,进行直接替换功能,而子程序是调用一个程序块;宏指令通过花费空间来节省时间,子程序通过花费时间来节省空间。5、两个无符号数相乘的本质两个无符号数相乘,其本质就是根据被乘数的位上是否为1,为1则临时寄存器结果加上乘数再右移一位,为0则临时寄存器结果直接右移一位,当乘数所有位数判断结束则临时寄存器里存放的结果即为所求结果,不过要注意单字节数相乘右移一位和双字节数相乘右移一位的区别,单字节右移一位只需一次RRF指令,双字节则需要先对高位使用RRF指令,再对低位使用RRF指令。六、实验数据误差分析及反思:1、在编译汇编程序时,由于END指令放错位置,导致程序编译失败,后来发现END指令应该放在整个汇编程序的最后,而不是主程序的最后;2、两个无符号数相乘,其本质就是根据被乘数的位上是否为1,为1则临时寄存器结果加上乘数再右移一位,为0则临时寄存器结果直接右移一位,当乘数所有位数判断结束则临时寄存器里存放的结果即为所求结果,不过要注意单字节数相乘右移一位和双字节数相乘右移一位的区别,单字节右移一位只需一次RRF指令,双字节则需要先对高位使用RRF指令,再对低位使用RRF指令;3、使用反汇编工具可以很好地发现子程序和宏指令之间的区别,宏指令(宏扩展)只是用原来宏定义中的若干条汇编指