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