《作业与子程序》PPT课件.ppt
1.作业讲评2.子程序:关注入口参数、出口参数、传递方式。特别注意堆栈的使用及其内容。能描述堆栈变化。,本次课内容,统计AX中1的个数送到CL,0的个数送到CH.分析 逐位处理,一般可以用移位指令完成.无论哪种移位,所移出的位都会放在CF中.,问题:,“广泛流传”的版本,code segmentassume cs:codestart:movxor bx,bxmov cx,16circle:rol ax,1,怎么会有两个loop circle?,jc BitSetinc bhloop circlejmp countoverBitSet:inc blloop circle,其实16位可以一块送,countover:mov ch,bhmov cl,blmov ax,4c00hint 21hcode endsend,该流程图虽然可行,但仍有以下问题:1.有必要两处判断CX=0吗?2.同样的代码(loop circle)写了两次.3.分支与循环结构交叉,易出现错误.此流程图需要完善。,CF=0?,BL-BL+1CX-CX-1,Y,N,开始,AX-数CX-16,CX=0?,Y,END,AX左移一位,CX=0?,Y,N,N,BH-BH+1CX-CX-1,CX-BX,circle,BitSet,countover,完善流程图,流程图本身不是目的,而是将想法表达为算法,为编写程序代码做准备。在流程图阶段,应当检查有没有原则性错误。好的流程图不应当出现交叉的程序结构,更不应存在逻辑错误。优化流程图,可以提高代码效率。,该流程图合乎规范,表现在:1.同样的代码(loop circle)只写了一次,效率提高了.2.分支与循环结构不再交叉,分支结构完全嵌套在循环结构中,不易出现错误.本流程图很容易转换成代码。,CF=0?,BL-BL+1,Y,N,开始,AX-数CX-16,Y,END,AX左移一位,CX=0?,N,BH-BH+1,CX-BX,circle,BitSet,countover,CX-CX-1,Y,修改后的程序,code segmentassume cs:codestart:movxor bx,bxmov cx,16circle:rol ax,1,分支在循环结构里面,jc BitSetinc bhjmp countoverBitSet:inc blcountover:loop circle,现在程序简洁了,mov cx,bxmov ax,4c00hint 21hcode endsend,调试程序,1.不要急于输入输出,在DEBUG中也可以查看程序的执行结果,而且更全面。2.记录程序运行的中间结果,分析其是否正确。如果不正确,要找出问题所在。3.尽量列表格说明程序执行情况,用直观的手段说明你的观点。,例,说明刚才程序的执行结果:至少要列举3种情况,串(string):顺序放在内存中一组相同类型数据(字/字节)串操作:对串中的元素进行相同的操作。串操作的寻址方式(隐含):源操作数指针DS:SI 目的操作数指针ES:DI(同一段内操作则须ES=DS)每次串操作后自动修改指针SI和DI:字节串操作后自动1,字串操作后自动2(指下一个)CLD令DF=0作,STD令DF=1作。重复前缀:REP CX0 则重复执行 MOVS/STOS CX减1 REPE/REPZ CX0ZF=1则重复执行CMPS/SCAS CX减1 上次比较相等则继续重复 直至CX=0为止REPNE/REPNZ CX0ZF=0则重复执行CMPS/SCAS CX减1 上次比较不相等则继续重复 直至CX=0为止,3.3.5 串操作指令 P.67,串操作指令,串是由字节、字、或双字组成的字符或数据序列,存放在存储器中。基本指令集处理的串长度不超过64K。串操作常用于数据块的快速移动、比较、搜索和存取,执行一次操作串中一个元 素,配上重复前缀可按条件完成对整个串的操作。,重复前缀,重复前缀指令的名称、汇编格式、重复条件、后续的串指令及操作见下表。重复前缀也是一条指令,但不能单独使用,需加在串操作指令之前,使 串操作指令重复或条件重复执行,相当于运行一个循环程序;取串指令LODS一般不加重复前缀,因为重复取出串中的元素送到累加 器Acc无意义(后面取出的数冲掉前面取出的数)。,串指令使用的一般方法,设置源串地址,设置目标串地址,设置串长度,设置操作方向DF,串指令,MOV SI,源串首地址(或LEA SI,源串),MOV DI,目的串首地址(或LEA DI,目的串),MOV CX,串长度,CLD(或STD),加重复前缀或循环编程实现批处理,重复执行?,MOVSB:(ES:DI)(DS:SI),SI1,DI1 MOVSW:(ES:DI+1、DI)(DS:SI+1、SI),SI2,DI2 例 将1000个字符的字符串从内存的BUFFER1搬移到内存的BUFFER2中去。MOV SI,OFFSET BUFFER1;BUFFER1偏移地址送SI MOV DI,OFFSET BUFFER2;BUFFER2偏移地址送DI MOV CX,1000;传送个数送CX CLD;令DF=0,地址自动递增LR:REP MOVSB;重复搬移1000个字节LC:.,3.3.5 1.串传送指令 MOVSB/MOVSW,CLDLR:MOVSB DEC CX JNZ LR LC:.,用串传送指令实现数据块传送,MOVSB:(ES:DI)(DS:SI),SI1,DI1 MOVSW:(ES:DI+1、DI)(DS:SI+1、SI),SI2,DI2 例 将1000个字符的字符串从内存的BUFFER1搬移到内存的BUFFER2中去。MOV SI,OFFSET BUFFER1;BUFFER1偏移地址送SI MOV DI,OFFSET BUFFER2;BUFFER2偏移地址送DI MOV CX,1000;传送个数送CX CLD;令DF=0,地址自动递增LR:REP MOVSB;重复搬移1000个字节LC:.,3.3.5 1.串传送指令 MOVSB/MOVSW(move),CMPSB:(DS:SI)(ES:DI),SI1,DI1 CMPSW:(DS:SI+1、SI)(ES:DI+1、DI),SI2,DI2 例 比较DEST和SOURCE中的500个字节,找出第一个不相同的字节,如果找到,则将SOURCE中的这个数送AL中。LEA DI,DEST;DEST偏移地址送DI LEA SI,SOURCE;SOURCE偏移地址送SI MOV CX,500;比较次数送CX CLD;令DF=0,地址自动递增 REPE CMPSB;相同则重复比较直至最后 JZ NEXT;遇不同或比完:判相同则不存MACH:DEC SI;SI退指最后比较不同的那个源数 MOV AL,SI;送ALNEXT:.本指令可用来检查两个串是否相等,3.3.5 2.串比较指令 CMPSB/CMPSW(compare),SCASB:(AL)(ES:DI),DI1(search)SCASW:(AX)(ES:DI+1、DI),DI2 例 在包含100个字符的字符串中寻找第一个回车符CR(其ASCII码为0DH),找到后将其地址保留在(DS:DI)中,并在屏幕上显示“Y”,否则显示“N”。LEA DI,STRING;STRING偏移地址送DI MOV AL,0DH;关键字送AL MOV CX,100;比较次数送CX CLD;令DF=0,地址自动递增 REPNE SCASB;不同则重复比较直至最后 JZ FOUND;遇相同或比完:判相同则转 MOV DL,N;不存在回车:显示“N”JMP DSPYFOUND:DEC DI;SI退指找到回车的那个单元 MOV DL,Y;显示“Y”DSPY:MOV AH,02H;调用2号软中断输出显示 INT 21H.本指令用于在串中查找指定的信息,3.3.5 3.串搜索(扫描)指令 SCASB/SCASW,MOV AX,DATAMOV DS,AXMOV ES,AX,;在100个字符中找回车符.MODEL SMALL;小模式.DATA;数据段STRING DB HOW DO YOU DO!,0DH,34H,43H,37H,41H,0DH.STACK 200;堆栈段,预留200字节.CODE;代码段START:MOV AX,DATA MOV DS,AX;数据段赋值MOV ES,AX;附加段赋值MOV DI,OFFSET STRING;STRING偏移地址送DI MOV AL,0DH;关键字送AL MOV CX,100;比较次数送CX CLD;令DF=0,地址自动递增 REPNE SCASB;不同则重复比较直至最后 JZ FOUND;遇相同或比完:判相同则转 MOV DL,N;不存在回车:显示“N”JMP DSPYFOUND:DEC DI;SI退指找到回车的那个单元 MOV DL,Y;显示“Y”DSPY:MOV AH,02H;调用2号软中断输出显示 INT 21H MOV AH,4CH;返回DOS INT 21H END START;汇编结束,LODSB:(AL)(DS:SI),SI1LODSW:(AX)(DS:SI+1、SI),SI2例 内存中以BUFFER为首址的缓冲区有10个以非压缩型BCD码形式存放的十进制数,它们的值可能是09中的任意一个,将这些十进制数按顺序显示在屏幕上。LEA SI,BUFFER;BUFFER偏移地址送DI MOV CX,10;数据个数送CXMOV AH,02H;置2号DOS功能调用 CLD;令DF=0,地址自动递增GET:LODSB;用串装入指令取一个BCD码到AL OR AL,30H;转换为ASCII码 MOV DL,AL;送DLINT 21H;输出显示DEC CX;循环计数 JNZ GET;未完继续MOV AH,4CH;返回DOSINT 21H.,3.3.5 4.串装入指令 LODSB/LODSW(load)从内存串数据逐个装入到CPU的AL里来,使用重复前缀没有意义,MOV AL,SIINC SI,STOSB:(ES:DI)AL,DI1 STOSW:(ES:DI+1、DI)AX,DI2 例 用STOS 指令将字符“#”装入到以AREA为首地址的 100个字节中。LEA DI,AREA LEA DI,AREA MOV AX,#MOV AX,#MOV CX,50 MOV CX,50 CLD CLDREP STOSW REP STOSB MOV AH,4CH MOV AH,4CH INT 21H INT 21H STOS指令加重复前缀通常用于初始化一个内存区域,3.3.5 5.串存储指令 STOSB/STOSW(store),;习题 求100个8位补码数平均值及小于平均值的数的个数.MODEL SMALL;小模式.DATA;数据段 BM DB 34,-38,43,-51,96 DUP(?)N EQU 4 PJ DB?XG DB?.STACK 200;堆栈段,预留200字节.CODE;代码段START:MOV AX,DATA;数据段赋值 MOV DS,AXMOV SI,OFFSET BM;SI指向数组首地址 MOV BX,0;累加寄存器清0 MOV CX,N;对N个数累加LB1:MOV AL,SI;取当前单字节补码数到ALCBW;扩展为字在AXADD BX,AX;加到BX中INC SI;SI指向下一个数LOOP LB1;循环,MOV AX,BX;累加和送AXMOV CL,N;置除数NIDIV CL;除以+100得平均值于ALCBW;扩展为字在AXMOV PJ,AL;存平均值MOV BL,0;计个数寄存器清0MOV SI,OFFSET BM;SI重新指向数组首地址MOV CX,N;对100个数统计LB2:CMP AL,SI;平均值与当前补码数比较JLE LB3;:不计INC BL;当前补码数小:BX计数加1LB3:INC SI;SI指向下一个数LOOP LB2;循环MOV XG,BL;存小于平均值的个数MOV AH,4CH;返回DOSINT 21HEND START,4.2.5 子程序设计 P.103,子程序(过程)的定义及结构(设过程名SUB1,NEAR属性),SUB1 PROC NEAR;过程定义伪指令 PUSH AX;保护现场(子程序中需要改变的寄存器)PUSHFPUSH BX.POP BX;恢复现场POPFPOP AX RET;子程序返回SUB1 ENDP 过程的类型属性缺省为NEAR(段内),段间调用则为FAR属性,关于子程序的一些要素子程序:保护现场与恢复现场(子程序内会破坏的寄存器);利用主程序传递的入口参数;子程序的处理功能(公用性、专门化);处理结果数据通过出口参数传递给主程序。主程序调用过程:入口参数初始化;调用子程序:CALL 过程名;出口参数利用与处理;,4.2.5子程序设计例(一),例 在BCDZ单元中有一个2位十进制数的压缩BCD码,试编程将其转换成二进制数,并保存到BINZ单元。分析:子程序SUB1的处理功能:将AL中的2位压缩BCD码转化为二进制数存回AL。入口参数:要转化的单字节压缩BCD码AL出口参数:转化好的二进制结果AL保护现场:F、BX、CX主、子程序共用寄存器:AL,MOV AH,AL;取BCD码 MOV BL,ALAND AH,0FH;保留低四位的个位码 AND BL,0FHMOV BL,AH;个位BCD码保存在BLMOV CL,04H;SHR AL,CL;十位BCD码移至低四位MOV BH,10;设乘数10于BHMUL BH;AL中十位码乘10ADD AL,BL;加上个位码得二进制结果于AL中,SUB1子程序主体程序段:,本例通过寄存器传递参数!,4.2.5子程序设计例(二),例 在一个带有符号的数组中选出绝对值最大的值,并找出该值所在的位置,分别存在MAX和INDEX单元中。分析变量定义及建立的参数表:0000H ARRAY DW 1,20,-5,;数组假设100个2单元00C8HCOUNT EQU($-ARRAY)/2;计算数组长度(元素个数):0064H00C8H MAX DW?;存放绝对值最大元素的原值00CAH INDEX DB?;存放绝对值最大元素的序号00CBH TAB:DW ARRAY,COUNT,MAX,INDEXII 表内值:0000H,0064H,00C8H,00CAHBX 表内址:以BX取 以BX+2取 以BX+4取 以BX+6取,本例通过建立的参数表传递参数!,MOV DH,1;元素序号跟踪计数初值MOV DL,0;存放序号,清0MOV SI,BX;取数组首址ARRAYMOV CX,BX+2;取数组元素个数COUNTDEC CX;循环次数少1LODSW;取首个元素到AXADD AX,0;转化为绝对值JNS NUM0NEG AX MOV DI,AX;首个元素绝对值进最大绝对值寄存器NUM0:LODSW;取DI指向的新一个元素到AX,DI加2 ADD AX,0;转化为绝对值JNS NUM0NEG AX,例 SUB1子程序主体程序段:,MOV DI,0;极小绝 对值,NUM1:CMP DI,AX;与新元素比较JNC NEXT;新元素不大,维持不变,转MOV DI,AX;新元素大则进入DIMOV DL,DH;新元素大则同时记存其序号NEXT:INC DH;元素序号跟踪计数加1LOOP NUM0;未完继续循环MOV SI,BX+6;比完,取最大元素序号INDEX单元地址MOV SI,DL;存最大绝对值元素序号MOV SI,BX;再取数组首址,SI重新指向数组头MOV DH,0;最大绝对值元素序号扩为字:DXSHL DX,1;最大绝对值元素序号乘2ADD SI,DX;相加指向最大绝对值元素MOV AX,SI;取最大绝对值元素原值 MOV DI,BX+4;取最大绝对值MAX单元地址MOV DI,AX;存最大绝对值元素值,MOV BX,SI,MOV SI,DX,JGE,增:,BX+SI,SI,例 在DAT1和DAT2分别开始的连续8个单元中存放了两个16位十进制数的压缩BCD码,试编程将其求和,并存放在SUM开始的连续10个单元中。主程序:.model small.datadat1 db 34h,67h,98h,86h,02h,41h,59h,23hdat2 db 33h,76h,89h,90h,05h,07h,65h,12h,4.2.5子程序设计例(三),sum db 10 dup(0).code mov ax,datamov ds,axmov ax,offset sumpush axmov ax,offset dat2push axmov ax,offset dat1push ax,4.2.5子程序设计例(三续),call addpmov ah,4chint 21haddp proc nearpush bpmov bp,spmov cx,8mov si,bp+4mov di,bp+6,4.2.5子程序设计例(三续),本例通过堆栈传递参数或参数地址!(画出参数在堆栈中的位置),mov bx,bp+8clcagain:mov al,siadc al,didaamov bx,alinc siinc diinc bxloop again,4.2.5子程序设计例(三续),本例通过堆栈传递参数或参数地址!(画出参数在堆栈中的位置),adc bx,0pop bpret 8addpendpend,4.2.5子程序设计例(三续),BP,断点IP值,DAT1,DAT2,SUM,进入子程序后的SP位置,子程序返回后的SP位置,例 编写计算N!的程序。主程序:ALN,CALL FACTDX(AL)!,RESULTDX子程序FACT:求(AL)!DX 若:(AL)=0则DX1(0!=1),RET 否则:AL值压栈,AL-1AL,CALL FACT DX(AL)!;弹出栈(原AL值)CL,CLDLDX RET,4.2.5子程序设计例(四)递归子程序:在子程序中又调用本子程序,主程序,0!=1DXRET,例 编写计算N!的程序运行示意。,子程序FACT:求(AL)!DX,FACT,FACT,FACT,AL=3栈3-1=2ALCALL 2!出栈 3CLCLDLDX(32=6)RET,AL=2栈2-1=1ALCALL 1!出栈 2CLCLDLDX(21=2)RET,AL=1栈1-1=0ALCALL 0!出栈 1CLCLDLDX(11=1)RET,AL N=3 CALL 3!RESULTDX=6,FACT,画出堆栈内容示意图,并用DEBUG检查。,实验任务1.找出10个有符号字中的最大负数和最小正数。要求:画出流程图,分析问题,给出程序,调试给出结果.2.找出6000060100范围内的全部素数。用一个子程序判断AX中的数是否为素数,主程序调用后找出全部素数。要求分别画出主程序和子程序流程图,给出程序,调试后给出全部素数.你的子程序给出入口参数、出口参数、功能说明、占用资源情况。3.上题用宏完成。比较宏和子程序各有什么优点、缺点。通知:近期会安排一次测验。,