
汇编语言程序汇总.ppt
62页第四节 汇编语言程序设计及举例z 概述z 顺序结构 z 分支z 循环z 字符串处理z 码转换z DOS系统功能调用z 宏汇编与条件汇编一、概述一、概述z1.编写步骤编写步骤z (1)分析问题,抽象出数学模型z (2)确定算法z (3)画程序流程图z (4)分配内存工作单元和寄存器z (5)按程序流程图编制程序z (6)上机调试,排错起始框终止框工作框判断调子程序z2.程序质量判断程序质量判断z (1)执行时间z (2)占用内存空间z (3)语句行数z3.程序结构程序结构z 顺序z 分支z 循环z 子程序二、二、 顺序结构顺序结构z例4-1: 8086没有32位无符号数乘法指令,需借助于16位无符号数乘法指令做4次乘法,然后把部分积相加, z 16位z × 16位z 部分积1z 部分积2z 部分积3z + 部分积4z 32位A │ BC │ DB×DA×DB×CA×C设地址指针被乘数低16位B→AX乘数低16位D→SI存入缓冲区乘数高16位C→DIB*D=部分积1被乘数高16位A→AXA*D=部分积2部分积2低16位加部分积1高16位存入缓冲区B*C=部分积3进位加至部分积2高16位与前面对应16位相加保存进位部分积4与前面的和相加保存在缓冲区A*C=部分积4恢复进位返回说明:z(1)数据段:mulnum dw 0000,0ffffh,0000,0ffffh,4dup(?) 被乘数 乘数 乘积z(2)堆栈段:z stack segment para stack ‘stack’ db 100dup(?) stack ends NAME MULTIPLY_32BITDATA SEGMENTMULNUM DW 8000H,0001H,0FFFH,0001H ;定义被乘数B、A与乘数D、CPRODUCT DW 4 DUP(?) ;定义乘积,低字在前DATA ENDSSTACK SEGMENT PARA STACK ‘STACK’DB 100 DUP(?) ;初始化堆栈大小为100byteSTACK ENDS CODE SEGMENTASSUME CS: CODE,DS:DATA,SS:STACKSTART PROC FARBEGIN: PUSH DS ; DS中包含的是程序段前缀的起始地址MOV AX,0PUSH AX ; 设置返回至DOS的段值和偏移量MOV AX, DATAMOV DS, AX ; 置段寄存器初值MOV BX, 0MULU32: MOV AX, MULNUM[BX] ; B→AXMOV SI, MULNUM[BX+4] ; D→SIMOV DI, MULNUM[BX+6] ; C→DIMUL SI ; B×DMOV PRODUCT[BX], AX ; 保存部分积1MOV PRODUCT[BX+2], DXMOV AX, MULNUM[BX+2] ; A→AXMUL SI ; A×DADD AX, PRODUCT[BX+2]ADC DX, 0 ; 部分积2的一部分与部分积1的相应部分相加MOV PRODUCT[BX+2], AXMOV PRODUCT[BX+4], DX ; 保存MOV AX, MULNUM[BX] ; B→AXMUL DI ; B×CADD AX, PRODUCT[BX+2] ; 与部分积3的相应部分相加 ADC DX, PRODUCT[BX+4]MOV PRODUCT[BX+2], AXMOV PRODUCT[BX+4], DXPUSHF ; 保存后一次相加的进位标志MOV AX, MULNUM[BX+2] ; A→AXMUL DI ; A×CPOPF;标志出栈ADC DX,0ADC AX, PRODUCT[BX+4] ; 与部分积4的相应部分相加ADC DX, 0MOV PRODUCT[BX+4], AXMOV PRODUCT[BX+6], DXRETSTART ENDPCODE ENDSEND BEGIN 分支程序的基本思想是根据逻辑判断的结果来形成程序的分支。
分支有两分支和多分支对于两分支,若条件P成立则执行A;否则执行B,如图4.2所示三、分支程序三、分支程序三、分支程序三、分支程序z z例: SIGEF:MOV AX,BUFFER OR AX, AX ;建立条件 JE ZERO ;为0转ZERO JNS PLUS ;为正转PLUS MOV BX,0FFH ;为负 JMP CONTI ZERO:MOV BX,0 JMP CONTI PLUS:MOV BX,1 CONTI: …y←-1判断y←0y←1X<0X>0X=0四、循环程序四、循环程序z结构形式:z z 先执行,后判断 先判断,后执行z组成: (1) 初始化z (2) 循环体z (3) 修改参数z (4) 循环控制初始化循环控制循环体修改参数入口出口初始化循环控制循环体修改参数入口出口z1.用计数器控制循环用计数器控制循环z (1)减1计数器z (2)加1计数器例4-2:P.141在一串给定个数的数中寻找最大值,放至指定的存储单元,每个数为16位。
NAME SEARCH_MAX ;源程序名 DATA SEGMENT ;(1)数据段 BUFFER DW X1,X2,…XN ;n个数据字 COUNT EQU $-BUFFER ;COUNT=2×n MAX DW ? ;放结果(最大值) DATA ENDS STACK SEGMENT STACK ‘STACK’ ;(2)堆栈段 DB 64 DUP(?) ;64个字节 TOP EQU $-STACK ;TOP为栈顶偏移 STACK ENDS CODE SEGMENT ;(3) 代码段 START PROC FAR ; 定义子程序 ASSUME CS:CODE,DS:DATA,SS:STACK BEGIN: PUSH DS ;(4)置子程序返回地址 MOV AX,0 PUSH AX MOV AX,DATA ;置DS MOV DS,AX MOV AX,STACK ;置SS MOV SS,AX MOV AX,TOP ;置SP MOV SP,AX MOV CX,COUNT ;(5) 循环初始化,CX=2n LEA BX,BUFFER ; BX为数据指针 MOV AX,[BX] ; 取第一个字 INC BX ; 指针指向下一个字 INC BX SHR CX ; CX=个数 DEC CX ; 个数减1 AGAIN: CMP AX,[BX] ;(6) 循环体,比较 JGE NEXT ; AX大,转NEXT MOV AX,[BX] ; 最大值→AX NEXT: INC BX ;(7) 修改参数,指针加1 INC BX LOOP AGAIN ;(8)循环控制,CX-1→CX,为0结束 MOV [BX],AX ;存最大值 RET START ENDP CODE ENDS END START 2.2.用开关变量控制循环用开关变量控制循环z 一个循环体中有两个循环支路,设一个开关变量,控制进入哪个循环支路。
z例:数据采集系统z 采到的前5个数用一种函数(FUN1)处理,开关=0z 采到的后7个数用另一种函数(FUN2)处理,开关=1说明:z(1)数据:buffer dw 05,05,…. ;12个数据 block dw 12 dup(?) ;存结果 count1 equ 5 ;个数 count2 equ 7 ;个数z(2)初始化:源数据指针 buffer→bxz 处理后数据指针 block→siz count1+1,count2+1→cxz 开关0→dxz(3)循环主体: 判开关量dx=0? dx=0 call fun1z 5个数据处理完后dx=1,cx=count2+1 dx=1 call fun2z 每处理完一个数,修改指针bx,si mov dx,0 ;(1)循环初始化 开关dx=0mov cx,count1+1 ; cx为计数器 lea bx,buffer ; bx源指针leasi,block ; si目的指针again:mov ax,[bx] ;(2)循环主体 cmpdx,0jneanoth; 开关不为0转anothcallfun1; 为0,函数1处理loopnextmovdx,1; 开关量转为1movcx,count2+1jmpagainnext:mov[si],ax; 处理后保存incbx ; (3)修改参数incbxincsiincsijmpagainanoth:callfun2; 函数2处理loopnext ;(4)循环控制ret 223.3.多重循环多重循环z 一个循环中包含另一个循环,称多重循环。
z 如:二维数组处理,二重循环z注意:z (1)各重循环的初始控制条件及实现z (2)内循环可嵌套在外循环中,也可几个内循环并列在外循环中,可从内循环跳到外循环,不可从外循环中直接跳进内循环z (3)要防止出现死循环 z例:延时程序,多重循环实现软件延时z DELAY:MOV DX,3FFH TIME:MOV AX,0FFFFH TIME1:DEC AX NOP JNE TIME1 DEC DX JNE TIME RETz 内循环控制变量AX,初值=FFFFHz 外循环控制变量DX,初值=3FFH五、字符串处理程序五、字符串处理程序z字符:ASCII码z说明:z (1)ASCII码数字,字母形成一个有序序列:z 0~9:30H~39Hz A~Z:41H~5AHz a~z:61H ~ 7AHz (2)一些I/O装置(键盘,显示器,打印机)采 用ASCII码传送。
z (3)常用的控制字符:0AH 换行(LF)z 0DH 回车(CR)z 08H 退格1.1.确定字符串长度确定字符串长度z 字符串长度不定,以某个特定字符为结束符z例4-3:从头搜索字符串的结束符,统计长度z 字符串地址指针:DIz 字符串长度: DLz 串结束字符: ALz (1)数据段:串放string开始单元z 串长度放LL单元z 结束符放CR单元z (2) 堆栈段:100个字节 长度=0CF=0?取串元素设置字符串指针返回长度+1存串元素YNz (3) 程序 lea di,string ;串地址偏移→DI mov dl,0 ;串长度初始DL=0 mov al,cr ;结束符→AL again:scasb ;搜索串 je done;找到转DONE,停止搜索 inc dl ;未找到,长度加1 jmp again ;继续搜索 done:lea bx,ll mov [bx],dl ;存长度 RETSTART ENDPCODE ENDSEND BEGIN2.2.加偶校验到加偶校验到ASCIIASCII字符字符zASCII码:7位二进制数,最高z 位可作为校验位。
z偶校验:1的个数为偶数,最高z 位置“0”,否则置“1”z例4-4:有一个ASCII字符串放z在STRING开始的单元,从串z中取出每一个字符,检查“1”z的个数,为偶数,则最高位z置“0”;为奇数,最高位置“1” 取元素“1”为偶数?自行与初始化返回最高位置1送回串中长度修改=0?NNYY说明:说明: lea si,string ;串指针:si mov cx,count ;串长度:cx again:lodsb ;取数,si+1→si/LODSB块装入指令 把SI指向的存储单元读入累加器,LODSB就读入 AL,LODSW就读入AX中,然后SI自动增加或减小1或2. and al,al ;自行与,影响PF jpe next ;偶,转至next or al,80h ;奇,最高位置1 mov [si-1],al ;送回 next:dec cx ;修改长度 jnz again ;≠0,转again六、码转换程序六、码转换程序z 十 六 进 制 , 二 进 制 , BCD码 ,ASCII码z转换方法:z(1) 算术和逻辑运算指令,软件实现;z(2) 查表指令;z(3) 硬件译码。
z1.十六进制十六进制→ASCIIz说明:说明: z(1) 十六进制: 0~9 A~F ASCII码:30H~39H 41H~46Hz 对 0 ~ 9,加上30H 对 A ~ F,加上‘A’-10 30H+0AH+07H=41H z(2) 地址指针:源(十六进制) bx 目的(ASCII) siz(3) cx=L1=2,每次循环转换一个字节两位十六进制数:低位与高位 拆开:1) ANDAL,0FH ;留下低四位 2) MOVCL,4 SHRAL,CL ;原高四位 低四位z1.十六进制十六进制→ASCIIagain:mov al,[bx] ;取十六进制数 mov dl,al ;保存 and al,0fh ;留下低四位 call change ;低四位→ASCII mov al,dl ;取数 push cx mov cl,4 ;移位次数 shr al,cl ;原高四位 低四位 pop cx call change ;高四位→ASCII inc bx loop again一位十六进制数 ASCII码子程序: change:proc cmp al,10 jl add_0 ;0~9转add_0 add al,’A’-’0’-10 ;A~F add_0:add al,’0’ mov [si],al inc si ret change endp2.ASCII→压缩压缩BCDz 长度L2 长度L1 buffer string 压缩BCD ASCII码 非压缩BCDz说明:说明:z (1)对非压缩BCD码,只要将ASCII的高4位屏蔽(AND)即可z (2)对压缩BCD码,要处理两个ASCII码,先为低位BCD码,后为高位BCD码,组合组合起来。
434H33H38H39H234H98H404030809data segment l2 dw 4buffer db 34h,33h,38h,39h ;ASCIIl1 dw ? string db 4dup(?) ;存BCD码data endsstack segment stack ’stack’ db 100dup(?)stack ends code segment assume cs:code,ds:data,es:data,ss:stack start proc far begin: push ds mov ax,0 push ax mov ax,data mov ds,ax mov es,ax mov cx,l2 shr cx,1 mov l1,cx ;BCD码区长度 lea bx,buffer lea si,string again:mov al,[bx] ;取ASCII码 and al,0fh ;化为BCD码 mov dl,al ;保存 inc bx ;指向下一个 mov al,[bx] ;取ASCII码 and al,0fh ;化为BCD码 push cx mov cl,4 shl al,cl ;左移四位 pop cx or al,dl ;组合两位BCD码 mov [si],al ;保存 inc bx ;修改指针 inc si loop again retstart endpcode ends end begin3.3.二进制到二进制到ASCII串串z例4-6:P.179,把在内z存变量NUMBER中的16位z二进制数,每一位转换z为相应的ASCII码,存入z串变量STRING中。
z分析:分析: z(1) 数据 zbuffer dw 4f78h ;16位二进制数 zstring dw 16dup(?) ;存ASCII码 取要转换数C=“1”?左移1位‘0’填满串返回存入‘1’修改地址指针完成否?YNYN初始化z(2) 代码段startproc farbegin:push dsmov ax ,0push axmov ax ,datamov ds ,axmov es ,axlea di,string ;串指针dimov cx,length string ;串长度push dipush cxmov al,30h;0的ASCII码repstosb;建立串为全’0’popcxpopdimov al,31h;1的ASCII码mov bx,num;取数 again:rclbx,1 ;左移一位,相应位进CFjncnext ;为0转nextmov [di],al ;为1,1的ASCII码送串 next:incdiloop againretstartendp codeends 244.BCD→二进制二进制z 压缩BCD码4位→二进制z方法: z(1)(((千位×10)+百位)×10+十位)×10+个位z(2)千 位 控 制 加 1000的 次 数 , 百 位 控 制 加 100 的次数,十位控制加10的次数,再加上个位。
z注意:注意:所有运算都用二进制z例:采用第一种方法 (((千位×10)+百位)×10+十位)×10+个位z说明:z(1)数据 dnum dw 9999h ;BCD码 bnum dw ? ;二进制数 z(2)分离 mov ax,dnum mov di,ax mov dx,ax mov bx,ax and bx,000fh ;个位→bx and dx,00f0h mov cl,4 shr dx,cl ;十位→di and di,0f00h mov cl,8 shr di,cl ;百位→di and ax,0f000h mov cl,12 shr ax,cl ;千位→axz(3)乘以10,x×10=x×2+x×8 add ax,ax mov cx,ax add ax,ax add ax,ax add ax,cx ;千位乘10 add ax,di ;加上百位 ……z 也可采用循环结构进行。
z方法: 十进制数 z Y=anXn+ ┄ +a1X1+a0 X=10 = (┅(anX+an-1)X+ ┅ +a1)X+a0z 初值 Y=an,i=n-1 Y=Y×X+ai i=i-1 结束条件:i<0 5.二进制二进制→ BCDz 十六位二进制数转换成BCD码z方法1: 找出二进制数中所包含的10000, 1000,100,10的个数,即BCD码z方法2: 二进制数Bz B=bm × 2m+ ┄ +b1 × 21+b0 = (┅(bm × 2+bn-1) × 2+ ┅ +b1) × 2+a0z 初值 B=0,i=m-1 B=B×2+bi i=i-1 结束条件:i<0z 乘法和加法用十进制运算十进制运算,结果为BCD码。
z 例例::采用方法1,16位二进制→5位非压缩BCD码z说明:(1)数据段 bnum dw 270fh ;16位二进制数 a_strg db 5dup(?) ;5个单元存BCD码 (2) mov ax,bnum lea bx,a_strg mov dl,0 ;计数清0 again1:sub ax,2710h ;减10000 js next1 ;<10000,转next1 inc dl ;包含10000的个数 jmp again1 next1:…. ;处理1000,100,10 z 若程序中采用除法指令,即: mov dx,0 mov ax,bnum ;二进制数 mov cx,10000 div cx ;÷10000 xchg ax,dx ;商(BCD码)在dx,余数在axz例:采用方法2, 16位二进制→4位压缩BCD码(≤9999)z说明:z 输入:DX放16位二进制数z 输出:CF=0,AX=4位压缩BCD码 CF=1,转换数>9999,DX不变z btobcd proc far cmp dx,9999 jbe tran ;dx<9999转tran stc ;dx>9999,置CF=1,退出 jmp exit tran: tran:mov ax,0 ;结果(BCD)清0 mov cx,16 ;16位 again:clc rcl dx,1 ;循环左移bi→CF adc ax,ax ;B×2+bi daa ;十进制调整,ax中为BCD loop again clc exit:ret btobcd endp 25七、七、DOSDOS系统功能调用系统功能调用zDOS(Disk Operating System)z核心:核心:z 有关I/O驱动、磁盘读写以及文件管理子程序,编了号供汇编语言的源程序调用。
z方法:方法:z (1) 子程序号(或称系统功能调用号)送AHz (2) 入口参数→指定寄存器z (3) INT 21Hz (4) 根据出口参数分析功能调用执行情况1. 显示显示AH 功能 入口参数 2 显示一个字符 DL=字符 9 显示一个字符串 DS:DX=串地址,串以‘$’结束z 例:在CRT上显示一个字符 MOV DL,OUTPUT_CHAR MOV AH,2 INT 21Hz 例:功能调用9,连续显示字符串 mov dx,offset buffer mov ah,9 int 21hz 例:P.150,功能调用9,在CRT上连续显示00~59 z分析:分析:z cx:循环次数z bl:要显示的两位十进制数00~59z si:缓冲区指针bufferz movcx,1000z movbl,0z lea si,buffer z一次循环: pushbxgoon: movdl,0dh mov ah,2 ;输出回车符 int 21hmovdl,0ah mov ah,2 ;输出换行处理 int 21h popbx mov al,bl;(2) bl+1→bl inc aldaacmpal,60hjcnextmoval,0 znext:movbl,al ;(3) 高四位→ASCII码 pushbx movdl,al pushcx movcl,4 shral,cl or al,30h;把AL十进制转换为ASCII mov[si],al incsi moval,dl ;(4) 低四位→ASCII码 andal,0fh; AL寄存器的低4位清零 or al,30h;把AL个位转换为ASCII mov[si],al incsi z mov al,’$’ ;(5)结束符’$’送缓冲区 mov[si],al movdx,offset buffer movah,9; 调用9显示字符串 int21h movcx,0ffffh; 延时 again:deccx jne again;标志寄存器中全零标志ZF不为1则跳转。
即CX不等于 0则跳转 popcx deccx jedone movsi,offset buffer;(8)循环未结束 jmpgoon ; si重指向缓冲区首址done:ret z(3) next11开始将ASCII码转换成BCD码z(4) again1开始将BCD码转换成二进制数,若为负取补,放CXz(5)putdn子程序将键盘输入的十进制数输出显示,用功能调用9z 1)根据符号sign,将+或-号送字符串z 2)二进制数(CX)为负取补z 3)goon开始调用change子程序将二进制数(CX)转换为BCD码,再转换为ASCII码,送字符串z 4)功能调用9显示字符串2. 键盘输入键盘输入AH 功能 入口参数 出口参数 1 输入一个字符 AL=字符 并显示0AH 输入一个字符 DS:DX=缓冲区首址 串到内存区第一个字节指出能容纳的最大字符个数,由用户给出。
第二个字节存放实际输入的字符数,由系统最后填入第三个字节开始存放从键盘接收的字符3.结束用户程序返回结束用户程序返回DOSDOS的方法的方法z用户程序结束后,一般应返回DOS,方法有:z(1)用功能调用4CHz 用户程序结束后插入 MOV AH,4CH INT 21Hz(2)用中断调用20Hz 用户程序结束后插入 INT 20Hz(3)转移到0单元(程序段前缀的开始处) JMP 0z 0单元处放的是一条INT 20H START PROC FAR BEGIN: PUSH DS ;压入DS MOV AX,0 PUSH AX ;压入0000 …… RET ;实际上是转移到0单元处 START ENDPz 连接程序为每个用户程序建立了一个程序段前缀,开始处(0单元)安排了一条返回DOS的指令,而且给DS赋的值就是程序段前缀的段地址。
z(4)用功能调用00H MOV AH,0 INT 21Hz 实质上实现JUMP到单元0,相当于(3) 26。
