微机原理与接口技术-第4-2章(用).ppt
微机原理与接口技术,第4章 汇编程序设计,要求掌握内容,汇编语言程序设计方法,系统功能调用,教学重点,汇编语言程序设计方法顺序程序设计分支程序设计循环程序设计子程序设计,一、系统功能调用方法,系统功能调用目前分为基本输入输出子程序层功能(BIOS)模块、DOS层功能模块和Windows层功能模块调用。BIOS模块、DOS层功能模块对用户来说可看成中断处理程序,他们的入口都在中断向量表中。Windows系统功能调用是通过Win32 API函数调用来实现的。,系统功能调用步骤,通常按照如下4个步骤进行:在指定寄存器中设置入口参数在AH寄存器中设置系统功能号 用中断调用指令(INT i8)执行功能调用 根据出口参数分析功能调用执行情况,BIOS层功能调用,主要功能是驱动系统的外部设备,如磁盘驱动器、显示器、键盘、打印机等。BIOS功能调用与操作系统无关中断号为51FH。具体参考P143,DOS层功能调用,DOS功能调用可能使可执行文件运行后正常结束,并返回到DOS状态下。否则会出现“死机”或不正确的结果等非正常现象。DOS功能模块在系统盘中,系统在启动时被装入内存,其功能比BIOS更加广泛和完整。主要功能是文件管理、存储管理、设备管理等。DOS调用是通过BIOS调用设备的。调用系统功能时总是先选DOS层功能模块,若这层模块的功能达不到要求,再选BIOS层的功能。,DOS输入输出功能调用,DOS通常利用21H号中断提供给用户近百个系统功能重点掌握:输入一个字符(带回显),01H号功能调用输出一个字符,02H号功能调用输出一个字符串,09H号功能调用键盘输入字符串,0AH号功能调用,01H号DOS功能调用,输入一个字符(带回显)功能调用号:AH01H 入口参数:无 功能调用:INT 21H 出口参数:AL键入字符的ASCII码,;输入一个字符mov ah,01h;设置功能调用号int 21h;功能调用mov dl,al;使用出口参数,02H号DOS功能调用,输出一个字符 功能调用号:AH02H 入口参数:DL欲显示字符的ASCII码 功能调用:INT 21H 出口参数:无,;显示一个问号“?”mov ah,02h;设置功能调用号mov dl,?;设置入口参数int 21h;功能调用,顺序可换,例题-回车换行的子程序,crlfprocpush ax;保护寄存器push dxmov ah,2mov dl,0dh;回车功能的ASCII码是0DHint 21hmov ah,2mov dl,0ah;换行功能的ASCII码是0AHint 21hpop dx;恢复寄存器pop axretcrlfendp,09H号DOS功能调用,输出一个字符串 功能调用号:AH09H 入口参数:DS:DX欲显示字符串在内存中的首地址(逻辑地址形式:DS段地址,DX偏移地址)内存中的字符串以ASCII码形式保存,最后必须添加一个“$”结尾(并不显示)功能调用:INT 21H 出口参数:无,例题-在屏幕上显示一段信息,;数据段(定义要显示的字符串)stringdb Hello,Assembly!,0dh,0ah,$;代码段(显示字符串的程序)mov dx,offset stringmov ah,9int 21h,Hello,Assembly!,0AH号DOS功能调用,输入一个字符串 功能调用号:AH0AH 入口参数:DS:DX存储键入字符串在内存中的首地址(逻辑地址形式:DS段地址,DX偏移地址)内存中的字符串以ASCII码形式保存,字符串以回车键结束,回车符是接收的最后一个字符 功能调用:INT 21H 出口参数:无,例题,;数据段(定义要输入的字符串)BUFFdb 10,?,10 DUP(?);代码段(输入字符串的程序)mov dx,offset BUFFmov ah,0AHint 21h,结束用户程序的方法,推荐采用第1种方法。,汇编语言程序设计方法顺序程序设计分支程序设计循环程序设计子程序设计,1.顺序程序设计,没有分支、循环等转移指令的程序,会按指令书写的前后顺利依次执行,这就是顺序程序顺序结构是最基本的程序结构完全采用顺序结构编写的程序并不多见,例题,DATA SEGMENT X DW 0010H Y DW 0123H Z DW 7890H V DW 3456H;分配变量X、Y、Z、V QR DW?;存放商 REMAINDER DW?;存放余数DATA ENDS,假设V、X、Y、Z均为带符号字变量,编程计算:(V(X*YZ540)/X,例 代码段,CODE SEGMENT ASSUME CS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX;初始化DS MOV AX,X;AXX IMUL Y;DX:AXX*Y MOV CX,AX MOV BX,DX;暂存在BX:CX中 MOV AX,Z CWD;Z扩展在DX:AX中(是否可不要?)ADD CX,AX ADC BX,DX;BX:CXX*YZ,(V(X*YZ540)/X,例 代码段(续1),SUB CX,540 SBB BX,0;可能有借位,结果在BX:CX中(是否可不要?)MOV AX,V CWD;扩展V,结果在DX:AX中 SUB AX,CX SBB DX,BX;结果在DX:AX中 IDIV X MOV QR,AX;保存商 MOV REMAINDER,DX;保存余数,(V(X*YZ540)/X,例 代码段(续2),MOV AH,4CH INT 21H;程序结束,返回到DOSCODE ENDS;码段结束 END START;结束汇编,指定程序入口地址,举例顺序程序设计实例,data segmentASCIIdb 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h;对应0 9的ASCII码db 41h,42h,43h,44h,45h,46h;对应A F的ASCII码hexdb 04h,0Bh;假设两个数据data ends,采用查表法,实现一位16进制数转换为ASCII码并显示,例代码段,code segmentassume cs:code,ds:datastart:mov ax,datamov ds,axmov bx,offset ASCII;BX指向ASCII码表mov al,hex;AL取得一位16进制数;恰好就是ASCII码表中的位移and al,0fh;只有低4位是有效的,高4位清0 xlat;查表:ALDS:BXAL,XLAT,例代码段(续),mov dl,al;入口参数:DLALmov ah,2;02号DOS功能调用int 21h;显示一个ASCII码字符mov al,hex+1;转换并显示下一个数据and al,0fhxlatmov dl,almov ah,2int 21hmov ah,4chint 21hcode endsend start,2.分支程序设计,分支程序根据条件是真或假决定执行与否判断的条件是各种指令,如CMP、TEST等执行后形成的状态标志转移指令Jcc和JMP可以实现分支控制分支结构有单分支结构双分支结构多分支结构,(1)单分支结构,条件成立跳转,否则顺序执行分支语句体注意选择正确的条件转移指令和转移目标地址,实例:求绝对值,例计算AX中有符号数的绝对值,cmp ax,0jge nonneg;条件满足(AX0),转移neg ax;条件不满足,求补nonneg:mov result,ax;条件满足,;不恰当的分支cmp ax,0jl yesneg;条件满足(AX0),转移jmp nonnegyesneg:neg ax;条件不满足,求补nonneg:mov result,ax;条件满足,(2)双分支结构,条件成立跳转执行第2个分支语句体,否则顺序执行第1个分支语句体注意第1个分支体后一定要有一个JMP指令跳到第2个分支体后,实例:显示BX的最高位,例 显示BX的最高位,shl bx,1;BX最高位移入CF标志jc one;CF1,即最高位为1,转移mov dl,30h;CF0,即最高位为0:DL30H0jmp two;一定要跳过另一个分支体one:mov dl,31h;DL 31H1two:mov ah,2int 21h;显示,可以用JNC替换JC,例显示BX的最高位(续),shl bx,1;BX最高位移入CF标志jnc one;CF0,即最高位为0,转移mov dl,31h;CF1,即最高位为1:DL31H1jmp two;一定要跳过另一个分支体!one:mov dl,30h;DL 30H0two:mov ah,2int 21h;显示,转换为单分支结构,例 显示BX的最高位(另解),mov dl,0;DL30H0shl bx,1;BX最高位移入CF标志jnc two;CF0,即最高位为0,转移mov dl,1;CF1,即最高位为1:DL31H1two:mov ah,2int 21h;显示,编写分支程序,需留心分支的开始和结束,例 显示BX的最高位(无分支),mov dl,0shl bx,1;BX最高位移入CF标志adc dl,30h;CF0,DL030h030H0;CF1,DL030h131H1 mov ah,2int 21h;显示,(3)多分支结构,多分支结构是多个条件对应各自的分支语句体,哪个条件成立就转入相应分支体执行,cmp ah,0jz function0cmp ah,1jz function1cmp ah,2jz function2,例大小写字母转换,;如果DL是一个小写字母,则转换为大写cmp dl,a;小于小写字母a,不需要处理jb dispcmp dl,z;大于小写字母z,也不需要处理ja dispsub dl,20h;是小写字母,则转换为大写disp:,大小写字母的比较和转换,结论1:大小写字母的ASCII码值相差20H结论2:大小写字母的ASCII码值仅D5位不同,方法1(加减指令):“ADD DL,20H”“SUB DL,20H”方法2(逻辑指令):“OR DL,20H”“AND DL,0DFH”,大小写互换(异或指令):“XOR DL,20H”,3.循环程序设计,循环程序结构是满足一定条件的情况下,重复执行某段程序循环结构的程序通常有3个部分:循环初始部分为开始循环准备必要的条件,如循环次数、循环体需要的数值等 循环体部分指重复执行的程序部分,其中包括对循环条件等的修改程序段循环控制部分判断循环条件是否成立,决定是否继续循环,关键是什么?,循环控制,循环结构程序的设计关键是循环控制部分循环控制可以在进入循环之前进行,也可以在循环体后进行,于是形成两种结构:“先判断、后循环”结构“先循环、后判断”结构循环结束的控制可以用循环次数,还可以用特定条件等,于是又有:计数控制循环条件控制循环,先循环后判断的循环结构,结束,初始化,循环的初始状态,循环体,循环的工作部分及修改部分,计数控制循环条件控制循环,修改部分,控制条件,Y,N,(1)计数控制循环,计数控制循环利用循环次数作为控制条件易于采用循环指令LOOP和JCXZ实现初始化:将循环次数或最大循环次数置入CX循环体循环控制:用LOOP指令对CX减1,并判断是否为0,例-用二进制显示BL内容,mov cx,8;CX8(循环次数)again:shl bl,1;左移进CF,从高位开始显示mov dl,0;MOV指令不改变CFadc dl,30h;DL030HCF;CF若是0,则DL 0;CF若是1,则DL 1 mov ah,2int 21h;显示loop again;CX减1,如果CX未减至0,则循环,计数控制循环先循环后判断,例-求最大最小值,在16位带符号数中找出其中的最大值和最小值,分别放在MAX和MIN单元中。,again,next1,next2,BX-存储单元地址AX-最大值DX-最小值CX-循环次数,例-求最大最小值(续),DATA SEGMENTBUFFER DW 100 DUP(?);自定义N个数COUNT EQU$-BUFFERMAX DW?;保存最大值MIN DW?;保存最小值DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA,定义数据,例-求最大最小值(续),START:MOV AX,DATAMOV DS,AXMOV CX,COUNTSHR CX,1;计算个数LEA BX,BUFFERMOV AX,BX;AX最大值初值 MOV DX,BX;DX最小值初值 DEC CX;循环次数减1,初始化,例-求最大最小值(续),AGAIN:ADD BX,2CMP AX,BX;比较JGE NEXT1MOV AX,BX;AX取得更大的数据JMP NEXT2NEXT1:CMP DX,BXJL NEXT2MOV DX,BX;BX取得更小的数据NEXT2:LOOP AGAIN;计数循环MOV MAX,AX;保存最大值MOV MIN,DX;保存最小值MOV AH,4CHINT 21HCODE ENDSEND START,循环体,(2)条件控制循环,条件控制循环需要利用特定条件判断循环是否结束条件控制循环用条件转移指令判断循环条件转移指令可以指定目的标号来改变程序的运行顺序,如果目的标号指向一个重复执行的语句体的开始或结束,便构成了循环控制结构,例-显示以0结尾的字符串,;数据段stringdb Let us have a try!,0;代码段mov bx,offset stringagain:mov dl,bxcmp dl,0jz done;为0结束mov ah,2;不为0,显示int 21hinc bx;指向下一个字符jmp againdone:,条件控制循环先判断后循环,例-记录某个字存储单元数据中1的个数,;数据段numberdw;代码段mov bx,numberxor dl,dl;循环初值:DL0again:cmp bx,0;也可以用test bx,0ffffhjz done;全部是0就可以退出循环,减少循环次数shl bx,1;用指令shr bx,1也可以adc dl,0;利用ADC指令加CF的特点进行计数jmp againDone:,条件控制循环先判断后循环,4.子程序设计,把功能相对独立的程序段单独编写和调试,作为一个相对独立的模块供程序使用,就形成子程序子程序可以实现源程序的模块化,可简化源程序结构,可以提高编程效率主程序(调用程序)需要利用CALL指令调用子程序(被调用程序)子程序需要利用RET指令返回主程序,过程定义和子程序编写,汇编语言中,子程序要用一对过程伪指令PROC和ENDP声明,格式如下:过程名PROC NEAR|FAR;过程体过程名ENDP可选的参数指定过程的调用属性。没有指定过程属性,则采用默认属性NEAR属性(段内近调用)的过程只能被相同代码段的其他程序调用FAR属性(段间远调用)的过程可以被相同或不同代码段的程序调用,子程序编写注意事项,子程序要利用过程定义伪指令声明子程序最后利用RET指令返回主程序,主程序执行CALL指令调用子程序子程序中对堆栈的压入和弹出操作要成对使用,保持堆栈的平衡子程序开始应该保护使用到的寄存器内容,子程序返回前相应进行恢复子程序应安排在代码段的主程序之外,最好放在主程序执行终止后的位置(返回DOS后、汇编结束END伪指令前),也可以放在主程序开始执行之前的位置,例用显示器功能调用输出一个字符的子程序,;主程序mov al,?;主程序提供显示字符call dpchar;调用子程序;子程序:显示AL中的字符dpcharproc;过程定义,过程名为dpcharpush bx;顺序入栈,保护寄存器push cxmov dl,almov ah,02h;02H号输出一个字符功能int 21hpop cx;逆序出栈,恢复寄存器pop bxret;子程序返回dpcharendp;过程结束,源程序,stack segment db 100 dup(?)stack endsdata segmentdata endscode segmentassume cs:code,ds:data,ss:stackstart:mov ax,datamov ds,axmov al,?;主程序提供显示字符call dpchar;调用子程序mov ax,4c00hint 21h,主程序部分,本程序可不需要数据段,源程序(续),dpcharproc;过程定义,过程名为dpcharpush ax;顺序入栈,保护寄存器push dxmov dl,almov ah,02h;02H号输出一个字符功能int 21hpop dx;逆序出栈,恢复寄存器pop axret;子程序返回dpcharendp;过程结束code endsend start,子程序安排在主程序执行终止后的位置,子程序编写注意事项(续),子程序允许嵌套和递归子程序可以与主程序共用一个数据段,也可以使用不同的数据段(注意修改DS子程序的编写可以很灵活,例如具有多个出口(多个RET指令)和入口,但一定要保证堆栈操作的正确性处理好子程序与主程序间的参数传递问题提供必要的子程序说明信息,例 显示以“0”结尾字符串的嵌套子程序,;数据段msgdb Well,I made it!,0;代码段(主程序)mov si,offset msg;主程序提供显示字符串call dpstri;调用子程序,例 子程序,;子程序dpstri:显示DS:SI指向的字符串(以0结尾)dpstriprocpush axnxt1:mov al,si;取显示字符inc sicmp al,0;是结尾,则显示结束jz nxt2call dpchar;调用字符显示子程序jmp nxt1nxt2:pop axretdpstriendp;子程序dpchar:显示AL中的字符(同上一例题),参数传递,主程序与子程序间一个主要问题是参数传递入口参数(输入参数):主程序调用子程序时,提供给子程序的参数出口参数(输出参数):子程序执行结束返回给主程序的参数参数的具体内容传数值:传送数据本身传地址:传送数据的主存地址常用的参数传递方法寄存器指定内存单元堆栈,1.用寄存器传递参数,最简单和常用的参数传递方法是通过寄存器,只要把参数存于约定的寄存器中就可以了由于通用寄存器个数有限,这种方法对少量数据可以直接传递数值,而对大量数据只能传递地址采用寄存器传递参数,注意带有出口参数的寄存器不能保护和恢复,带有入口参数的寄存器可以保护、也可以不保护,但最好能够保持一致,dpchar子程序的参数传递,;主程序mov al,?;主程序提供显示字符call dpchar;子程序:显示AL中的字符dpcharprocpush axpush dxmov dl,almov ah,02hint 21hpop dxpop axretdpcharendp,入口参数:寄存器AL,传数值出口参数:无,返回,2.指定内存单元传递参数,当传送的数据长度未知,则需用内存单元作为入口参数的传递。如果主程序还要利用原来的变量值,则需要保护和恢复利用指定内存单元传递参数,子程序的通用性较差,但特别适合在多个程序段间、尤其在不同的程序模块间传递数据,数据块之间的三种情况,数据块之间的三种情况(续),对于(A)的情况可分别从首(末)地址开始传送;而对(B)、(C)两种情况由于有重叠区,应分别对待。当源数据块首址大于目标块首址时,应从数据首址开始传数,如(C)当源数据块首址小于目标块首址时,应从数据末址开始传数,如(B)目的在于避免在传数时将重叠区源数据块的数据冲掉。,利用存储单元传递参数举例,例:数据块间的搬移。,利用子程序来实现数据块间的搬移。设参数传递采用指定内存单元传递方式,且SRCADR中存放源数据块首地址,DSTADR中存放目的数据块首地址,LEN中存放数据块字节数。,主程序,STACK SEGMENT DB 100 DUP(?)STACK ENDSDATA SEGMENT DAT DB 100 DUP(?)SRCADR DD DAT DSTADR DD DAT+20;注意有重叠!LEN DB 100DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACKSTART:MOV AX,DATA MOV DS,AX MOV ES,AX CALL MYMOVE MOV AH,4CH INT 21H,子程序,MYMOVE PROC LDS SI,SRCADR;SI源数据块首地址 LES DI,DSTADR;DI目的数据块首地址 MOV CX,LEN;CX长度 CLD CMP SI,DI;(SI)大于(DI)吗?JA DONE;大于,则转至DONE,首址传数(如C)STD;小于,末址传数(如B)ADD SI,CX DEC SI ADD DI,CX DEC DIDONE:REP MOVSB RETMYMOVE ENDPCODE ENDSEND START,3.用堆栈传递参数,参数传递还可以通过堆栈这个临时存储区。主程序将入口参数压入堆栈,子程序从堆栈中取出参数;子程序将出口参数压入堆栈,主程序弹出堆栈取得它们采用堆栈传递参数是程式化的,它是编译程序处理参数传递、以及汇编语言与高级语言混合编程时的常规方法,利用堆栈传递参数举例,例:求两个16位数的和。,STACK SEGMENT DB 100 DUP(?)STACK ENDSDATA SEGMENT DAT1 DW 100 DAT2 DW 200 SUM DW?DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACKSTART:MOV AX,DATA MOV DS,AX MOV AX,DAT1;将DAT1压入堆栈 PUSH AX MOV AX,DAT2;将DAT2压入堆栈 PUSH AX CALL ADDITION;调用加法子程序 MOV SUM,AX;存放结果 MOV AH,4CH INT 21H;返回DOS,子程序,ADDITION PROC NEAR MOV BP,SP MOV AX,BP+2;从堆栈中弹(取)出加数 ADD AX,BP+4;求和 RET 4ADDITION ENDPCODE ENDSEND START,综合举例,DATA SEGMENT ORG 0200H STRING DB 100 DUP(?)DATA ENDSSTACK SEGMENT DB 100 DUP(?)STACK ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATA ASSUME ES:DATA,SS:STACK,若从0200H单元开始有100个有符号数,编一个程序检查这些数,正数保持不变,负数都取补后送回。,AGAIN,OVER,综合举例(续),BEGIN:MOV AX,DATA MOV DS,AX MOV ES,AX MOV CX,100 LEA SI,STRINGAGAIN:MOV AL,SI CMP AL,0 JGE OVER;AL00,跳至OVER NEG AL;AL0,对AL求补OVER:MOV SI,AL INC SI LOOP AGAIN MOV AH,4CH INT 21H CODE ENDS END BEGIN,教学要求,掌握完整段和简化段定义源程序格式掌握常量表达、变量定义及应用、变量和标号的属性及操作符掌握基本伪指令和操作符:EQU;*/;DBDWDD、?DUP;ORG$、OFFSETSEGPTR;END;PROC/ENDP;SEGMENT/ENDS;ASSUME,教学要求(续),掌握基本的顺序、分支、循环、子程序设计方法熟悉常见程序设计问题:查表(查代码、特定值等)ASCII和BCD代码转换数据范围判断(09、AZ、az)字母大小写转换字符串传送、比较等操作求最小最大值数据求和、统计字符个数作业:,