/ tests / div32u.asm
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