Hi,(sorry long post, code included )
Benjamin Bromilow wrote:
<snip>
>
> movlw 0xFF
> movwf Divin1
> incf Divin1,F ; ie overflow from 0xFF to 0x00
> btfss STATUS,C ; If carry set then skip
> nop ; C flag is not set *1
> nop ; C flag is set (works)
Yes this is correct, in the manual it clearly states that INCF only affects
the zero flag. ( at least for the 16xx series ).
So in this case, after the operation INCF an overflow is always detected
by checking the zeroflag. Thats one of the reasons you also have the INCFSZ
instruction.
For the 18 series ( and perhaps others, i don't know ) the INCF actually
affect
also the C,DC,N,OV flags.
I know this is somewhat illogical but it's clearly stated in the manual,
also
this is what i meant with my previous statement, headbanging :)
{Quote hidden}>The actual code is as follows. As part of a division routine it subtracts
>Divisor[3]:[2]:[1] from Divin[3]:[2]:[1]. If it subtracts without a carry,
>the routine returns with C=1 and the new result in Divin. If a carry
>results, it returns with C=0 and the old result in Divin.....
>
>SUBC
>;1 stack
> movf Divin3,W
> movwf Divtemp3
> movf Divin2,W
> movwf Divtemp2 ; sort out temporary registers
> movf Divin1,W
> movwf Divtemp1
>
> movf Divisor1,W
> subwf Divtemp1,F ; subtract LSB
> movf Divisor2,W ; get ready for next subtract
> btfss STATUS,C ; if no borrow skip increment
> incfsz Divisor2,W ; increment of divisor
> subwf Divtemp2,F ; this sub is skipped if sub'd to zero
> movf Divisor3,W ; next one ready
> btfss STATUS,C ; if no borrow skip INC
> incfsz Divisor3,W
> subwf Divtemp3,F
> btfss STATUS,C ; if carry=1 then no borrow so SUB okay
> return
>
> movf Divtemp3,W
> movwf Divin3
> movf Divtemp2,W ; restore old values and return (C=0)
> movwf Divin2
> movf Divtemp1,W
> movwf Divin1
> return
>So it's not the best bit of code ever written but it demonstrates what I
>expected to happen!!!
>
>Ben
Hmmm that's odd, this is what I have ( and it works ! )
;++++++++++++
;
; SUB_24_FROM_24 - Subtracts a 24 bit variable from a 24 bit variable
; Formula: ARG2_24 = ARG2_24 - ARG1_24
; arguments must point to most significant bits, arg1_24+2 and arg2_24+2 is
lsb's
;
SUB_24_FROM_24 MACRO ARG1_24,ARG2_24
MOVF LOW(ARG1_24+2),W ; get lowest byte source
SUBWF LOW(ARG2_24+2),F ; subtract from lowest byte dest
MOVF LOW(ARG1_24+1),W ; get middle byte
SKPC ; if overflow
INCFSZ LOW(ARG1_24+1),W ; decrease source
SUBWF LOW(ARG2_24+1),F ; and subtract to dest.
MOVF LOW(ARG1_24),W ; get highest byte
SKPC
INCFSZ LOW(ARG1_24),W
SUBWF LOW(ARG2_24),F
ENDM
From what I gather the subtraction is performed excately as yours.
However the actual division routine is not included and I guess that there
could be 'something' about the interpretation of the 'carry' when returning.
Here's an 40 by 23 bit division routine that I know works, see if you can
spot
anything that differs from your implementation.
Credit should go to Nikolai Golovchenko, as the routine surfaced by his
guidance.
It's an variant of his 24 by 16 bit division routine at:
www.piclist.com/techref/microchip/math/div/24by16.htm
( mine not fully omptimized, exerzise for the reader :) )
; ***********************************************************************
; DIVIDE_ARG1LHbyARG2_40by23 - Unsigned routine to divide a 40 bit number
with a 23 bit number
; result upto 40 bits !
;
; Formula: ARG1_48L:H (top byte ignored) = ARG1_48L:H / ARG2_24
;
; Routine uses 'non-restoring' method there each loop only performs *one*
; addition or subtraction each time.
; Subtract from remainder if remainder is positive or zero and add to
remainder if remainder is negative.
; This way saves alot of cycles but requires that the sign of the remainder
must be kept somewhere
; in this routine the top bit of reaminder is use for that purpose and hence
the 40by23 limitation.
; Normally one would do both subtraction and addition in each loop.
;
; Format: Little endian, Ram = msb, Ram+x = lsb ( where x=bytesize-1)
; Ram used: ARG1_48H and ARGH1_48L (Dividend) 5 bytes ( 40 bits ), where
top byte is ignored
; ARG2_24 (Divisor) 3 bytes ( 23 bits, top bit used for temp
sign save )
; Temp 3 bytes
; MathBitCount 1 byte for loop counting ( and temp. saving of
carry )
;
; ARG2_24 is preserved
; ARG1_48H:L holds result
; Returns with zero in W if failed ( division with zero )
; Else returns with one in w
;
DIVIDE_ARG1LHbyARG2_40by23
GLOBAL DIVIDE_ARG1LHbyARG2_40by23
; Test for zero division
MOVF ARG2_24,W
IORWF ARG2_24+1,W
IORWF ARG2_24+2,W
BTFSC STATUS,Z
RETLW 0x00 ; divisor = zero, not possible to calculate return
with zero in w
; prepare 24 bit temp variable
CLRF Temp
CLRF Temp+1
CLRF Temp+2
MOVLW D'40' ; initialize bit counter
MOVWF MathBitCount
BSF STATUS,C ; set carry at entry
DIVIDE_40by23_LOOP
; a) first time carry set
; b) every other bit carry contains the result of
; last subtraction ( division ).
; shift in carry as lowest bit
RLCF ARG1_48L+2,F
RLCF ARG1_48L+1,F
RLCF ARG1_48L,F
RLCF ARG1_48H+2,F
RLCF ARG1_48H+1,F
; shift in highest bit from dividend through carry in temp
RLCF Temp+2,F
RLCF Temp+1,F
RLCF Temp,F
MOVF ARG2_24+2,W ; get LSB of divisor
BTFSS ARG1_48L+2,0 ; check lowest bit of dividend
GOTO DIVIDE_40by23_ADD
; subtract 23 bit divisor from 24 bit temp
SUBWF Temp+2,F ; subtract
MOVF ARG2_24+1,W ; get middle byte
SUBWFB Temp+1,F ; and subtract from dest.
MOVF ARG2_24,W ; get top byte
SUBWFB Temp,F ; and subtract from dest.
GOTO DIVIDE_40by23_SKIP ; carry was set, subtraction ok,
continue with next bit
DIVIDE_40by23_ADD
; result of subtraction was negative restore temp
ADDWF Temp+2,F ; add it to the lsb of temp
MOVF ARG2_24+1,W ; get middle byte
ADDWFC Temp+1,F ; and add it if not zero in that
case Product+Multipland=Product
MOVF ARG2_24,W ; get top byte
ADDWFC Temp,F ; and add
DIVIDE_40by23_SKIP
DECFSZ MathBitCount,F ; decrement loop counter
GOTO DIVIDE_40by23_LOOP ; another run
; finally shift in the last carry
RLCF ARG1_48L+2,F
RLCF ARG1_48L+1,F
RLCF ARG1_48L,F
RLCF ARG1_48H+2,F
RLCF ARG1_48H+1,F
RETLW 0x01 ; done
Oh, that's right, uses 18xx instr. replace:
SUBWFB Temp,F ; and subtract from dest.**
with:
SKPC ; if overflow ( from prev.
subtraction )
INCFSZ ARG2_24,W ; increase source
SUBWF Temp,F ; and subtract from dest.
and:
ADDWFC Temp+1,F ; and add it if not zero in that case
Product+Multipland=Product**
with:
BTFSC STATUS,C ; check carry for overflow from
previous addition
INCFSZ ARG2_24+1,W ; if carry set we add 1 to the source
ADDWF Temp+1,F ; and add it if not zero in that
case Product+Multipland=Product
If using 16xx series
/Tony
--
http://www.piclist.com hint: The PICList is archived three different
ways. See http://www.piclist.com/#archives for details.