div32u.asm
1 ; Test program to verify correct emu8051 operation 2 ; Taken from http://www.vzsite.us/8051/ 3 ; 4 ; Test desc: 32-bit division 5 ; Test output: PC = $FFF0 6 ; Test output: SP = $60 7 ; Test output: R0 = $E6 8 ; Test output: R1 = $55 9 ; Test output: R2 = $00 10 ; Test output: R3 = $00 11 ; Test output: R4 = $20 12 ; Test output: R5 = $1B 13 ; Test output: PSW = $05 14 15 ;26 Oct 00 added code to zero remainder when dividend is zero 16 ;19 Dec 99 corrected comments, removed unnecessary instruction 17 ;16 May 99 8051 source code 18 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 19 ; 20 ;DIV32U is called to divide (unsigned) a 32-bit dividend using a 21 ; 16-bit divisor. 22 ; 23 ;DIV32U solves for quotient and remainder the equation: 24 ; 25 ; dividend = divisor*quotient + remainder 26 ; 27 ;Call: 28 ; r7,r6,r5,r4 = dividend 29 ; r1,r0 = divisor 30 ; lcall DIV32U 31 ; 32 ;Return: 33 ; r5,r4 = quotient 34 ; r7,r6 = remainder 35 ; c flag set to 1 if overflow occured 36 ; All registers, acc, b and two caller-assigned direct memory bytes 37 ; (q0 and q1)have been changed. 38 ; Data pointer has not been disturbed 39 ; 40 ;Note: 41 ; (1)Overflow is a divide by zero or any value that will cause 42 ; the quotient to be greater than 16 bits. 43 ; (2)Most significant (ms) register always listed first when comma separates 44 ; two in a comment. Example: r3,r2 (r3 contains the ms bits) 45 ; (3) The algorithm used in this code borrows heavily from work posted 46 ; by John C. Wren who said he got it from a C complier. 47 ; 48 ;Original author: John Veazey, Ridgecrest, CA, 18 APR 99 49 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 50 ; 51 q0 EQU 70h 52 q1 EQU 71h 53 TOS EQU 60h ; Adresse du dessus de la pile. 54 55 ORG 0000h ; Reset vector 56 MOV SP,#TOS ; Init stack pointer 57 58 ;; Set dividend 59 MOV R7,#012h 60 MOV R6,#034h 61 MOV R5,#056h 62 MOV R4,#078h 63 64 ;; Set divisor 65 MOV R1,#0ABh 66 MOV R0,#0CDh 67 68 LCALL DIV32U 69 LJMP 0FFF0h 70 71 DIV32U: 72 ; 73 ;Clear the working quotient 74 ; 75 clr a 76 mov q1,a 77 mov q0,a 78 ; 79 ;Clear the msb's of a 32-bit working divisor (r3,r2,r1,r0) 80 ; 81 mov r3,a 82 mov r2,a 83 ; 84 ;b counts the number of places+1 the divisor was initially 85 ; shifted left to align its ms bit set with the ms bit set 86 ; in the dividend 87 ; 88 mov b,#1 89 ; 90 ;Make an error return if trying to divide by zero 91 ; 92 mov a,r1 93 orl a,r0 94 jnz du100 95 ljmp du920 ;Make the error return 96 ; 97 ;Just return with quotient and remainder zero if dividend is zero 98 ; 99 du100: 100 mov a,r7 101 orl a,r6 102 orl a,r5 103 orl a,r4 104 jnz du200 105 mov r7,a 106 mov r6,a 107 ljmp du910 ;Make a normal return 108 ; 109 ;Align the msb set in the demoninator with the msb set in the 110 ; numerator. Increment the shift count in b each time a shift left 111 ; is performed. 112 ; 113 du200: 114 mov a,r3 ;Stop if msb set 115 clr c 116 rlc a 117 jc du600 118 subb a,r7 ;Compare r3 & r7, (c clear) 119 jz du210 ; jump if r3=r7 120 jnc du600 ; jump if r3>r7 121 sjmp du240 ; r3<r7 122 du210: 123 mov a,r6 ;r3=r7, so compare r2 & r6 124 subb a,r2 125 jc du600 ; jump if r2>r6 126 jnz du240 ; jump if r2<r6 127 mov a,r5 ;r2=r6, so compare r1 & r5 128 subb a,r1 129 jc du600 ; jump if r1>r5 130 jnz du240 ; jump if r1<r5 131 mov a,r4 ;r1=r5, so compare r0 & r4 132 subb a,r0 133 jc du600 ; jump if r0>r4 134 du240: 135 clr c ;Now shift the denominator 136 mov a,r0 ; left 1 bit position 137 rlc a 138 mov r0,a 139 mov a,r1 140 rlc a 141 mov r1,a 142 mov a,r2 143 rlc a 144 mov r2,a 145 mov a,r3 146 rlc a 147 mov r3,a 148 inc b ;Increment b counter and 149 sjmp du200 ; continue 150 ; 151 ;Compare the shifted divisor with the remainder (what's 152 ; left of the dividend) 153 ; 154 du600: 155 mov a,r7 156 clr c 157 subb a,r3 158 jc du720 ;jump if r3>r7 159 jnz du700 ;jump if r3<r7 160 mov a,r6 161 subb a,r2 162 jc du720 ;jump if r2>r6 163 jnz du700 ;jump if r2<r6 164 mov a,r5 165 subb a,r1 166 jc du720 ;jump if r1>r5 167 jnz du700 ;jump if r1<r5 168 mov a,r4 169 subb a,r0 170 jc du720 ;jump if r0>r4 171 ; 172 ;Divisor is equal or smaller, so subtract it off and 173 ; get a 1 for the quotient 174 ; 175 du700: 176 mov a,r4 177 clr c 178 subb a,r0 179 mov r4,a 180 mov a,r5 181 subb a,r1 182 mov r5,a 183 mov a,r6 184 subb a,r2 185 mov r6,a 186 mov a,r7 187 subb a,r3 188 mov r7,a 189 clr c 190 cpl c ;Get a 1 for the quotient 191 sjmp du730 192 ; 193 ;Divisor is greater, get a 0 for the quotient 194 ; 195 du720: 196 clr c 197 ; 198 ;Shift 0 or 1 into quotient 199 ; 200 du730: 201 mov a,q0 202 rlc a 203 mov q0,a 204 mov a,q1 205 rlc a 206 mov q1,a 207 jc du920 ;overflow - make the error return 208 ; 209 ;Now shift the denominator right 1, decrement the counter 210 ; in b until b = 0 211 ; 212 du740: 213 clr c 214 mov a,r3 215 rrc a 216 mov r3,a 217 mov a,r2 218 rrc a 219 mov r2,a 220 mov a,r1 221 rrc a 222 mov r1,a 223 mov a,r0 224 rrc a 225 mov r0,a 226 djnz b,du600 227 ; 228 ;Move quotient and remainder 229 ; 230 mov a,r5 231 mov r7,a 232 mov a,r4 233 mov r6,a 234 mov a,q1 235 mov r5,a 236 mov a,q0 237 mov r4,a 238 ; 239 ;Make the normal return 240 ; 241 du910: 242 clr c 243 ret 244 ; 245 ;Make the error return 246 ; 247 du920: 248 clr c 249 cpl c 250 ret