14.4汇编语言程序设计基础汇编语言程序设计的步骤:1-根据实际问题抽象出数学模型,确定算法2-画出程序框图(流程图)3-分配内存工作单元和寄存器4-根据框图编写源程序,存成.ASM文件5-对源程序汇编,生成.OBJ目标文件6-把.OBJ文件连接成.EXE执行文件7-运行、调试2源程序的基本结构顺序结构:按照指令的排列顺序逐条执行分支结构:根据不同的条件转移到不同的程序段。循环结构:多次重复执行同样的工作。子程序结构:也叫过程结构,是完成特定功能的程序段。3(2)用方框表示执行框,框中用简明语言标明要完成的功能如何绘制程序框图(流程图)?(1)起始和终止框4(4)各框之间用箭头连起来表示程序走向。(3)用菱形框表示判断框框中标明比较、判断和条件NY?5一、顺序程序设计计算机执行程序的方式是“从头到尾”逐条顺序执行指令语句,直到程序结束。例1:计算设x=60,y=468/)6(2yxz6DATASEGMENTxDB60yDB46zDW?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AXMOVAL,xMULALMOVDX,AXMOVAL,yMOVBL,6MULBLSUBDX,AXMOVCL,3SHRDX,CLMOVz,DXCODEENDSENDSTART7例2:把BUF开始的两个字节单元中的数相加,结果存入字单元RES中。DATASEGMENTBUFDB89H,34HRESDW?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AXLEABX,BUFMOVAL,[BX];取加数ADDAL,[BX+1];做加法ADCAH,00H;取CF位MOVRES,AX;存结果MOVAH,4CHINT21HCODEENDSENDSTART8例3:以BUF为首地址的内存中存有0~15的平方表。查表求X单元中数(在0~15之间)的平方值,并送回X单元。DATASEGMENTBUFDB0,1,4,9,16,25,36,49,64DB81,100,121,144,169,196,255XDB12DATAENDSSTACKSEGMENTDW100DUP(?)STACKENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK;段地址说明9START:MOVAX,DATAMOVDS,AX;数据段初始化MOVAX,STACKMOVSS,AX;堆栈段初始化MOVBX,OFFSETBUFMOVAL,X;取XXLATMOVAH,4CHINT21H;返回DOSCODEENDSENDSTART10二、分支程序设计YN条件满足?处理IF…THEN结构条件2条件满足?处理P1处理P2条件1IF…THEN…ELSE结构11条件1成立?P1NYCASE结构条件2成立?条件n成立?…Pn+1P2PnNNYY12例4:编程求符号函数DATASEGMENTXDB30YDB?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AX0,10,00,1xxxy13MOVAL,XCMPAL,0JLEXDMOVY,1JMPNEXTXD:CMPAL,0JZDYMOVY,-1JMPNEXTDY:MOVY,0NEXT:MOVAH,4CHINT21HCODEENDSENDSTART14例5:内存中以DATA1为首址的80个字节单元中存放着80个同学的考试成绩(0-100),编写程序统计≥90分以上、80-89分、70-79分、60-69分、60以下的人数,并把结果存在DATA2开始的5个单元中分析如下:1、这是一个多分支的程序,需要将每个同学的成绩依次与90、80、70、60比较。2、因为无论是成绩还是人数都不超过一个字节所能表示的范围,故定义的变量均为字节型。3、统计结果用一个数组存放,分别存放5个分数段的人数。15DATASEGMENTDATA1DB80DUP(?)DATA2DB5DUP(0)DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATABEGIN:MOVAX,DATAMOVDS,AXMOVCX,80;串长送CXLEASI,DATA1;SI指向学生成绩LEADI,DATA2;DI指向统计结果AGAIN:MOVAL,[SI];取一个学生的成绩CMPAL,90;大于90分吗?JBNEXT1;若不大于继续判断INCBYTEPTR[DI];否则≥90分的人数+1JMPSTO;转到循环控制16NEXT1:CMPAL,80;大于80分吗?JBNEXT2;若小于继续判断INCBYTEPTR[DI+1];否则80分以上;的人数+1JMPSTONEXT2:CMPAL,70;大于70分吗?JCNEXT3;若小于继续判断INCBYTEPTR[DI+2];否则70分以上;的人数+1JMPSTONEXT3:CMPAL,60;大于60分吗?17JCNEXT4;若小于继续判断INCBYTEPTR[DI+3];否则60分以上;的人数+1JMPSTONEXT4:INCBYTEPTR[DI+4];否则60分以下;的人数+1STO:INCSI;指向下一个学生成绩LOOPAGAIN;循环直到成绩统计完MOVAH,4CH;返回DOSINT21HCODEENDSENDSTART18三、循环程序设计1.DO…UNTIL条件结构先执行,再判断条件。工作部分至少执行一次。初始化循环体循环控制继续循环?YN192.DOWHILE条件结构先判断条件,再执行。工作部分有可能一次都不执行。初始化循环体循环控制继续循环?YN20循环初始部分:为进入循环做必要的准备工作循环体:是程序中重复执行的程序段循环控制部分:为进入下一次循环,修改地址指针、计数器内容等参数循环结束部分:进行循环之后的处理循环程序的构成21用计数控制循环:对于循环次数已知的程序,或是在进入循环前可由某变量确定循环次数的程序,通常用计数器来控制循环。用条件控制循环:适用于某些循环次数未知的程序,或循环次数可变的程序,可以由问题给出的条件控制循环结束。22例6:把BUF开始的10个字节单元中的二进制数据累加,求得的和放到RES字单元。DATASEGMENTBUFDB1,4,9,5,21,64,12,6,10,23RESDW?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATA23START:MOVAX,DATAMOVDS,AXMOVAX,0;AX清0MOVCX,10;置计数器初值MOVBX,OFFSETBUF;置地址指针LP:ADDAL,[BX];取一个数累加到AL上ADCAH,0INCBX;地址加1LOOPLP;CX不为0,循环MOVRES,AX;传送结果MOVAH,4CHINT21H;返回DOSCODEENDSENDSTART24例7:计算1001iiSDATASEGMENTSUMDW?DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AX25MOVCX,100MOVAX,0MOVSI,1AGAIN:ADCAX,SIINCSIDECCXJNZAGAINMOVSUM,AXMOVAH,4CHINT21HCODEENDSENDSTART26例8:把从DATA1开始的字符串“Wewillbegoodfriends!”显示在屏幕上,并移动到DATA2开始的内存单元中。DATASEGMENTDATA1DB‘Wewillbegoodfriends!’‘$’COUNTEQU$-DATA1;计算字符串长度DATAENDSEXTRASEGMENTDATA2DBCOUNTDUP(?)EXTRAENDS27STACKSEGMENTDB100DUP(?)STACKENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK,ES:EXTRASTART:MOVAX,DATAMOVDS,AXMOVAX,STACKMOVSS,AXMOVAX,EXTRAMOVES,AX28LEADX,DATA1MOVAH,09HINT21H;显示字符串LEASI,DATA1LEADI,DATA2MOVCX,COUNTCLDREPMOVSB;串传送MOVAH,4CHINT21HCODEENDSENDSTART29四、子程序设计1.在使用子程序时应注意:①参数传递②相应寄存器内容保护与恢复为防止破坏调用程序中寄存器的内容,需在子程序入口处将所用到的寄存器内容压栈。③子程序嵌套问题302.子程序结构子程序名PROC[NEAR/FAR]……RET子程序名ENDP注:如果是NEAR类型,调用时直接“CALL子程序名”如果是FAR类型,调用时直接“CALLFARPTR子程序名”313.堆栈参数的传递在主程序中,将相应参数压栈在子程序中,将相应参数出栈324.子程序设计掌握以下几点√调用子程序用CALL指令,返回程序用RET指令。子程序允许嵌套调用。进入子程序后首先要保护主程序的运行状态(标志位)和使用的寄存器内容(称为保护现场),退出子程序前要恢复现场。调用前要预先定义好入口参数和出口参数,参数传递可利用寄存器、存储单元或堆栈(要用BP寻址)。33例9:从一个字符串中删去一个字符DATASEGMENTSTRINGDB‘Exxperience…’’$’LENGTHDW$-STRINGKEYDB‘x’DATAENDSSTACKSEGMENTDB100DUP(?)STACKENDSCODESEGMENTASSUMECS:CODE,DS:DATA,SS:STACK34MAINPROCFARSTART:MOVAX,DATAMOVDS,AX;DS初始化MOVAX,STACKMOVSS,AXLEABX,STRINGLEACX,LENGTHPUSHBXPUSHCX;将地址压栈MOVAL,KEY;要查找关键字送(AL)CALLDELCHAR;调用子程序MOVAH,4CHINT21HMAINENDP35DELCHARPROCPUSHBPMOVBP,SP;将BP指向当前栈顶PUSHSIPUSHDIPUSHCXCLDMOVSI,[BP+4];得到CXMOVCX,[SI];取串长度MOVDI,[BP+6]得到BXREPNESCASB;查找关键字JNEDONE36MOVSI,[BP+4];得到CXDECWORDPTR[SI];串长度减1MOVSI,DIDECDIREPMOVSB;被删除字符后的字符依;次向前移位DONE:POPCX;恢复寄存器内容POPDIPOPSIPOPBPRETDELCHARENDPCODEENDSENDSTART例题10:当I/O状态端口0378H的Bit1(第1位)为0时,表示外设忙;为1则表示外设可以接收数据。现将当前数据段中从BUFFER开始的连续100个字节的内容从I/O数据端口03F8H输出到外设。分析①通过接口向外设输出数据时,首先要判断外设是否忙,只有外设不忙时,才能进行输出。每输出一个数据都要判断一下I/O端口的状态。②这里的I/O接口有一个状态输入端口和一个数据输出端口。传送数据之前,先通过输入指令从状态口读入一个字节数,该字节的第一位表示当前外设的状态。因此,可将其他7位屏蔽掉,而只关心第1位的状态(请注意,计算机中的字节数是从第0位开始的)。39DATASEGMENTBUFFERDB100DUP(?)DATAENDSCODESEGMENTASSUMECS:CODE,DS:DATASTART:MOVAX,DATAMOVDS,AXCALLSENDATA40SENDATAPROCFARPUSHAX;保护寄存器PUSHDXPUSHSIPUSHCXLEASI,BUFFERMOVCX,100AGAIN:MOVDX,0378H;状态端口WAIT:INAL,DX;