乘除算法
- 格式:doc
- 大小:99.50 KB
- 文档页数:4
CALL !NMUL3 ;(D2,D1,D0)*(D6,D7,D8)=(D3,D4,D 5,D6,D7,D8)被乘数(D6,D7,D8),乘数(D2,D1,D0);;functionNMUL3:MOV D3,#0HMOV D4,#0HMOV D5,#0HMOV X,#24DCLR1 CYNMUL3_A:MOV A,D3RORC A,1MOV D3,AMOV A,D4RORC A,1MOV D4,AMOV A,D5RORC A,1MOV D5,AMOV A,D6RORC A,1MOV D6,AMOV A,D7RORC A,1MOV D7,AMOV A,D8RORC A,1MOV D8,ABNC $NMUL3_B; BNC $addr16,如果CY = 0,则PC=PC + 2 + jdisp8MOV A,D5ADD A,D0MOV D5,AMOV A,D4ADDC A,D1MOV D4,AMOV A,D3ADDC A,D2MOV D3,A;D3D4D5=D3D4D5+D3D2D1NMUL3_B:DEC X相加的结果存放在D3,D4,D5,右移24位后正好替换D6,D7,D8;BNZ $NMUL3_A;BNZ $addr16,如果Z = 0,则PC=PC + 2 + jdisp8 MOV A,D3RORC A,1MOV D3,AMOV A,D4RORC A,1MOV D4,AMOV A,D5RORC A,1MOV D5,AMOV A,D6RORC A,1MOV D6,AMOV A,D7RORC A,1MOV D7,AMOV A,D8RORC A,1MOV D8,ARET ;---------------------------------;subroutine call 子程序调用NDIV6:;(D5..D0)/(D8,D7,D6)=(D2,D1,D0)....(D5,D4,D3) MOV X,#24DCLR1 BIT_RAMNDIV6A:CLR1 CY ;BCF STA TUS,CMOV A,D0ROLC A,1MOV D0,AMOV A,D1ROLC A,1MOV D1,AMOV A,D2ROLC A,1MOV D2,AMOV A,D3ROLC A,1MOV D3,AMOV A,D4ROLC A,1MOV D4,AMOV A,D5ROLC A,1MOV D5,AMOV1 BIT_RAM,CYMOV A,D3MOV C,AMOV A,D4MOV D,AMOV A,D5MOV E,A; (E,D,C) = (E ,D, C)-(D8,D7,D6) MOV A,CSUB A,D6MOV C,AMOV A,DSUBC A,#0HMOV D,AMOV A,ESUBC A,#0HMOV E,ABNC $NDIV6B; BNC $addr16,如果CY = 0,借位置1<则PC=PC + 2 + jdisp8BF BIT_RAM,$NDIV6E;BF saddr.bit, $addr16,如果(saddr.bit) = 0则PC=PC + 4 + jdisp8CLR1 BIT_RAMNDIV6B:MOV A,DSUB A,D7MOV D,AMOV A,ESUBC A,#0HMOV E,ABNC $NDIV6CBF BIT_RAM,$NDIV6ECLR1 BIT_RAMNDIV6C:MOV A,ESUB A,D8MOV E,ABNC $NDIV6DBF BIT_RAM,$NDIV6ECLR1 BIT_RAMNDIV6D:SET1 D0.0MOV A,EMOV D5,AMOV A,DMOV D4,AMOV A,CMOV D3,ANDIV6E:DEC XBNZ $NDIV6ARET;------------------------------;R2/R4=R2,余R6,R7循环次数DIVB:SZ R4JMP DIVB0MOV A,0FFHMOV R2,ACLR R6RETDIVB0:MOV A,8MOV R7,ACLR R6DIVB1:CLR CRLC R2 ;商RLC R6 ;被除数R2赋给R6MOV A,R6SUB A,R4SNZ CJMP DIVB2 ;C=0,不够除MOVR6,A ;新的余数SET R2.0 ;商位置1DIVB2:SDZ R7JMP DIVB1RET;******************************;R2R5/R6=R7,余R2,R10循环次数DIVW:MOV A,R2SUB A,R6SNZ CJMP DIV1MOV A,0FFHMOV R7,ACLR R2RETDIV1:MOV A,08MOV R10,ADIV11:RLC R5RLC R2SZ CJMP DIV2MOV A,R2SUB A,R6SZ CJMP DIV3CLR CJMP DIV4DIV2:MOV A,R2 ;R2比R6多一位C=(100H-FFH) SUB A,R6DIV3:MOV R2,A ;R2=R2-R6SET C DIV4:RLC R7 ;商置1SDZ R10JMP DIV11RETDIVD功能:双字节二进制无符号数除法;入口条件:被除数在R2、R3、R4、R5中,除数在R6、R7中。
;出口信息:双字节商在R4、R5中,余数R2R3,若溢出,R4R5=0FFFFH。
;影响资源:A、STATUS、R2~R7,R10,R11 堆栈需求:2字节R2R3R4R5/R6R7=R4R5(商) ~R2R3(余数)DIVD:MOV A,10H ;计算双字节商MOV R10,ADVD1:CLR C ;部分商和余数同时左移一位RLC R5RLC R4RLC R3RLC R2MOV A,R3SNZ C ;是否溢出,多出一位,够减JMP DVD2;C=0,未溢出SUB A,R7 ;溢出,计算(R2R3-R6R7)MOV R11,AMOV A,R2SBC A,R6JMP DVD3DVD2:SUB A,R7 ;未溢出,计算(R2R3-R6R7)MOV R11,AMOV A,R2SBC A,R6SNZ C ;结果判断,C=1,大于,够减JMP DVD4 ;C=0,小于,不够减DVD3:MOV R2,A ;够减,存放新的余数MOV A,R11MOV R3,AINC R5 ;商的低位置一DVD4:SDZ R10JMP DVD1 ;计算完十六位商(R4R5)RET;以下为乘法部分;*************R2*R3=R2R5 ,R4 :循环次数MULI:mov a,R2 ;R2为被乘数muli_0:clr R2clr R5 ;积clr R4set R4.3 ;R4赋值为8muli_1:clr csz R3.0 ;R3乘数的低位为1?addm a,R2 ;是,加上被乘数rrc R2 ;本轮循环的结果右移一位rrc R5 ;积右移一位rrc R3 ;乘数右移一位sdz R4 ;共循环八次jmp muli_1ret在单片机的实际应用中,除法运算是比较常见的一种运算。
以MCS-51单片机为例,虽然它提供了除法指令,但只能进行单字节除以单字节的运算,如果要进行多字节的除法运算,就得自己设计算法。
目前,许多资料上都介绍了四字节除以二字节的算法,但它们主要有以下几点不足:1.只能求出商,不能求出余数;2.在被除数高二位大于等于除数时,不能进行运算;3.商只有两个字节。
例如,被除数是0FFFFFFFFH,除数是0004H时,商数应该是3FFFFFFFH,余数是0003H但是,用以前的算法是无法进行运算的。
在实际运用中,参与运算的数是任意的,有时需要求出余数,有时商数要求有四个字节,因此,以前的算法在实际应用中受到了很大的限制。
为了满足实际运用中的需要,我设计了一套新的四字节除以二字节的算法,克服了上述算法中的缺点,可以适合广泛的实际需要。
下面以MCS-51汇编语言为例进行说明。
该算法增加了两字节的余数单元,并把被除数单元用来存放商数。
运算时,首先判断除数是否为零,若为零时,则设溢出标志为1,然后退出。
若除数不为零,则采用移位相减法进行运算。
首先,把进位位和余数单元清零。
再将进位位、余数单元和被除数单元按顺序首尾相连,逐位进行向左循环移位(如图示),共移位32次。
每移位一次,余数单元都C (H L) (HH HL LH LL)进位位余数单元被除数单元和除数作一次减法运算,若够减,余数单元内容更新为两者之差,并且将被除数最末一位置为1;若不够减,则余数单元内容保持不变,且将被除数最末一位置为0。
判断是否够减的方法是:在作减法之前,先保存进位位,再看作完减法后的进位位。
仅在作减法之前进位位为0,并且作减法之后进位位为1时判为不够减,其余情况均视为够减。
这样,等到全部运算结束时,商数为四个字节,存放在被除数单元中;余数为两个字节,存放在余数单元中。
R2R3R4R5/R6R7=R2R3R4R5----R8R9 例如,被除数是0FFFFFFFFH,除数是0004H时,运行新的算法,商数是3FFFFFFFH,存放在被除数单元中,余数是0003H,存放在余数单元中。
这个算法自然、流畅,运算结果商数为四个字节,余数为两个字节,尤其是在求除以某数的N次方时,只需连续调用N次该算法子程序就可以了,省去了繁琐的数据转存语句。
该算法还可以依实际需要扩充为位数更高的多字节除数算法,也可以移植到其它的单片机平台上。
本算法已在A T89C51单片机上调试通过。
下面给出算法的程序代码清单。
divdll data 20h ;定义被除数单元divdlh data 21hdivdhl data 22hdlvdhh data 23hdivl data 24h ;定义除数单元divh data 25htempl data 26h ;定义余数单元temph data 27hdivd:push accpush bmov a,divdh ;判除数是否为零orl a,divljnz divd0setb ov ;除数为零,置溢出标志pop bpop accretdivd0:mov templ,#00h ;除数不为零,进行运算mov temph,#00hmov b,#20h ;置循环次数divd1:clr c ;进位位、余数单元和mov a,divdll ;被除数单元全体逐个rlc a ;向左循环移位mov divdll,amov a,divdlhrlc amov divdlh,amov a,divdhlrlc amov divdhl,amov a,divdhhrlc amov divdhh,amov a,templrlc amov templ,axch a,temphrlc axch a,temphmov f0,c ;保存进位位clr csubb a,divl ;用余数减去除数mov r7,amov a,temphsubb a,divhanl c,/f0 ;判断是否够减jc divd2 ;不够减,移下一位mov templ,r7 ;够减,刷新余数单元mov temph,ainc divdll ;商上1divd2:djnz b,divd1clr ovpop bpop accret end二进制除法:实际运算过程中,被除数位置不变,除数位置右移;而在算法过程中由于除数做减数,被除数做被减数,因而只有被除数在运算过程中左移;实际运算:被除数不移动,除数右移算法运算:除速不移动,被除数左移二进制乘法:实际运算过程中,被乘数位置不变,乘数和被乘数乘积左移;而在算法过程中由于乘数做加法运算,被乘数做被加数,因而只有加右移实际运算:被乘数不移动,乘数左移算法运算:乘数不移动,被乘数右移注意:RLC [m] 带进位将数据存储器左移一位,结果放入数据存储器注:可以用循环加减法计算;DIVD功能:双字节二进制无符号数除法;入口条件:被除数在R2、R3、R4、R5中,除数在R6、R7中。