|Hello! | |Is there a simple way to Divide an 8 or 16 bit # by 47 that doesn't take |10,000 instructions (slight exaggeration)? I don't need a lot of accuracy. | |Thanks in advance | |Jon Dividing by a prime! Makes things a little difficult. The best method would be to use a general divide routine. The following is a simple divide of a 16-bit number by an 8-bit number, returning a rounded 8-bit number. If you are going to divide a value greater than 256*47 it will always return 0xFF. The routine should take about 124 clock cycles worse case, including a short call. If you only use this for dividing with numbers less than 128 the carry detection on the shift can be removed to save an extra 16 clock cycles and removed some extra code. If rounding is not needed then the loop count can be reduced by 1 and a few words of ROM can be removed, saving about 14 cycles (a little restructuring will be needed to get the last bit saved). ; Routine : Div16x8 ; Purpose : Does a divide of a 16-bit number by an 8-bit number to return ; a rounded 8-bit number. If the output overflows an 8-bit value ; the maximum value of 0xFF will be returned. This is normally ; intended to be used as a fractional divide routine. ; Inputs : Acc -- 16-bit number to be divided. LSB first. For fractional ; divide set high byte to data and set low byte to zero. ; w -- divisor. No zero allowed! ; Returns : W -- results, rounded. ; Acc -- low byte contains unrounded result. ; Globals : DivCntr -- a counter variable used as a loop count. ; Calls : none ; Notes : ; Timing : 124 clock cycles worst case, using short call. Div16x8 ; load our counter with number of bits to divide, 9. Do without ; corrupting our divider which is in w. clrf DivCntr ; make it zero. bsf DivCntr,3 ; now set bit three to make it 8. bsf DivCntr,0 ; make it 9, one extra shift needed. ; first see if our input number is in range of a 16-bit result subwf Acc+1,f ; do an initial subtract. expect borrow. skpz ; if zero. skpnc ; or borrow. goto Dv16_4 ; use saturated return. addwf Acc+1,f ; restore the value. clrc ; clear carry for initial rotate. ; main loop, do this for each bit. Shift is done one extra time to get ; set for initial compare. Dv16_2 rlf Acc,f ; multiply Acc by 2. Shift in new bit. rlf Acc+1,f ; both bytes. ; test for carry on shift up. bc Dv16_5 ; handle overflow. ; test. subwf Acc+1,f ; do a subtract. bc Dv16_3 ; branch if no borrow ; Had a borrow, adjust. addwf Acc+1,f ; restore accumulator. clrc ; clear carry, indicate a borrow occured. Dv16_3 decfsz DivCntr,f ; update counter, loop if not done. goto Dv16_2 ; loop until done. ; results are in Acc low bits. Carry is set if should round up. movf Acc,w ; get results in W. skpc ; if no carry return unrounded value. return ; done, return value in W. ; round, if overflow return saturated value. incfsz Acc,w ; update low byte. return ; if not zero then return. ; the output overflowed on rounding, return max value. Dv16_4 ; output saturated, return a 0xFFFF. movlw 0xFF ; Result = 0xFF movwf Acc ; set "unrounded" result. return ; and return the rounded version. Dv16_5 ; overflow on shift, subtract no mater what! subwf Acc+1,f ; do the subtract. setc ; carry is always set here. goto Dv16_3 ; update things. Chip.