51单片机:有符号/无符号双字节除法汇编程序(超详细)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/belous_zxy/article/details/81779660

DIV只能用于两个单字节之间的除法,有时处理的数据是双字节大小,就需要单独写出双字节除法子程序。

实现的原理还是简单的列式模拟,但是汇编的细节更多。对熟练掌握汇编需要对二进制运算和移位操作非常熟悉。

>>过程注释写的非常详细了

;有符号双字节数除法子程序 SIDIV
;正负数均用原码表示
;需要 UIDIV 子程序
;被除数存R6、R7,除数存R4、R5
;运算完成后,R6、R7存放商,R4、R5存放余数
SIDIV:
	CLR      F0
	MOV      A,R4
	JNB      0E0H.7,DIV_POSTIVE1
DIV_NEGATIVE1:
	CPL      F0					;标记此次运算除数为负数
	CLR      A			
	CLR      C					
	SUBB     A,R5	
	MOV      R5,A		
	CLR      A
	SUBB     A,R4		
	MOV      R4,A					;对除数取补码
DIV_POSTIVE1:
	MOV      A,R6
	JNB      0E0H.7,DIV_POSTIVE2	
DIV_NEGATIVE2:
	CPL      F0					;得出运算结果的正负号
	CLR      A
	CLR      C
	SUBB     A,R7
	MOV      R7,A
	CLR      A
	SUBB     A,R6	
	MOV      R6,A					;对被除数取补码
	LCALL    UIDIV					;开始运算
	CLR      C
	CLR      A
	SUBB     A,R5
	MOV      R5,A
	CLR      A
	SUBB     A,R4
	MOV      R4,A					;余数恢复原码(余数必须为正)
	SJMP     NOT_CFUNC
DIV_POSTIVE2:
	LCALL    UIDIV				        ;开始运算
NOT_CFUNC:
	JNB      F0,SIDIV_END			        ;运算结果为正,则直接结束程序
RESULT_NEGATIVE:
	CLR      C
	CLR      A
	SUBB     A,R7
	MOV      R7,A
	CLR      A
	SUBB     A,R6
	MOV      R6,A					;运算结果为负,则把商恢复原码
SIDIV_END:
	RET      					;结束子程序
	

;无符号双字节数除法子程序 UIDIV
;被除数存R6、R7,除数存R4、R5
;运算完成后,R6、R7存放商,R4、R5存放余数
UIDIV:
	CJNE     R4,#00H,DIV_H1			        ;判断除数高8位是否为00H
	CJNE     R6,#00H,DIV_H2			        ;判断被除数高8位是否为00H
ALLDIV_L:						;情况0:除数、被除数高8位均为00H
	MOV      A,R7					
	MOV      B,R5
	DIV      AB
	MOV      R7,A
	MOV      R5,B
	RET						;调用DIV指令结束
DIV_H1:							;情况1:除数高8位非00H,即商肯定是单字节(8位以内,R6=00H)
	CLR      A						
	XCH      A,R4					;除数高8位R4清零
	MOV      R0,A					;R0暂存R4内容
	MOV      B,#08H					;移位相减共08H次
UIDIV_LOOP1:
	MOV      A,R7					
	ADD      A,R7					
	MOV      R7,A					
	MOV      A,R6							
	RLC      A									
	MOV      R6,A					;被除数16位左移,最低位取0,最高位移至C					
	MOV      A,R4										
	RLC      A									
	MOV      R4,A					;除数高8位R4左移,最低位取被除数高8位的最高位,最高位移至C(C肯定为0)
	;*R4存储的是被除数左移的超出位,R6、R7存储的是被除数左移的剩余位,当08H次循环后,R7必然是00H,被除数变为余数在R4、R6
	MOV      A,R6									
	SUBB     A,R5					;判断当前R5和R6大小,(即判断除数低八位是否可以减去)											
	MOV      A,R4														
	SUBB     A,R0					;判断当前R4是否大于原始值,这里可能是借位减法(即判断除数高8位是否可以减去)				
	JC       R4_HIGH				;大于,不能减去余数		
R4_EQU_LOW:						;满足小于等于
	MOV      R4,A													
	MOV      A,R6											
	SUBB     A,R5											
	MOV      R6,A											
	INC      R7					;减去余数,商值加一							
R4_HIGH:							
	DJNZ     B,UIDIV_LOOP1			
	CLR      A
	XCH      A,R6				
	MOV      R5,A					;余数后8位移至R5,并清空R6
	RET      
DIV_H2:							;情况2:除数高8位为00H,被除数高8为非00H,则余数肯定是单字节(8位以内,R4=00H)
	MOV      A,R5
	MOV      R0,A					;R0暂存除数
	MOV      B,A	
	MOV      A,R6					
	DIV      AB					;被除数高8位除以余数
	JB       OV,UIDIV_END			        ;检查到除数低8位也为00H,直接结束程序(OV=1)
	MOV      R6,A					
	MOV      R5,B					;商存在R6,余数存在R5
	MOV      B,#08H					;移位相减共08H次
UIDIV_LOOP2:						;低8位运算
	MOV      A,R7
	ADD      A,R7		
	MOV      R7,A					;被除数低8位R7左移,最低位取0,最高位移至C
	MOV      A,R5
	RLC      A
	MOV      R5,A					;高8位运算的余数作为剩余值继续运算,左移,最低位取被除数低8位的最高位,
	JC       UIDIV_NEXT				;左移移出到了C,必然可以相减
	SUBB     A,R0					;判断当前值是否大于余数
	JNC      RE_EQU_LOW				;满足小于或等于
RE_HIGH:						;大于,不能减去
	DJNZ     B,UIDIV_LOOP2			
	RET     
UIDIV_NEXT:
	CLR      C
	SUBB     A,R0					;减去除数,必然存在借位 C=1
RE_EQU_LOW:
	MOV      R5,A					;更新当前剩余值
	INC      R7					;成功减一次除数,商的低8位加一
	DJNZ     B,UIDIV_LOOP2		
UIDIV_END:	
	RET

END

猜你喜欢

转载自blog.csdn.net/belous_zxy/article/details/81779660
今日推荐