;	RCS Header $Id: FPRF24.TXT Last Revised, 26/08/2008
;	Floating point routine library file needed by RFLvlMeter.asm
;	program, made by extracting from various Microchip Technology
;	floating point library and function files, including
;	FP24.A16 (Rev 2.7 1996/10/07 13:50:29 by F.J.Testa) 
;	FP32.A16 (Rev 2.8 1996/10/07 13:50:59 by F.J.Testa)
;	MATH16.MAC (Rev 1.3 1996/10/05 19:52:32 by F.J.Testa)
;	EXP1024.A16 (Rev 1.3 1997/02/25 14:27:16 by F.J.Testa)
;	RND3224.A16 (Rev 1.1 1996/08/22 00:51:17 by F.J.Testa)
;	FLOOR24.A16 (Rev 1.3 1996/10/09 13:23:39 by F.J.Testa)
;	MATH16.INC (Rev 2.4 1997/02/11 16:58:49 by F.J.Testa)
;	FXM46.a16 (Rev 2.3 1996/10/16 14:23:23 by F.J.Testa)
;	FXD26.a16 (Rev 2.3 1996/10/16 14:23:57 by F.J.Testa)
;	FLOAT_ASCII (by Rick Evans, in AN670)

;	**************************************************************************

	org h'400'		; make the include routines start at 0400h, regardless
					; of the length of the main program...
;	**************************************************************************

;	THIS FIRST SECTION COMES FROM FP24.A16...

;       Unary operations: both input and output are in AEXP,AARG
;
;       Binary operations: input in AEXP,AARG and BEXP,BARG with output in AEXP,AARG
;
;       All routines return WREG = 0x00 for successful completion, and WREG = 0xFF
;       for an error condition specified in FPFLAGS.
;
;	*************************************************************************************
;	*************************************************************************************
;
;       24 bit floating point representation
;
;       EXPONENT        8 bit biased exponent
;                       It is important to note that the use of biased exponents produces
;                       a unique representation of a floating point 0, given by
;                       EXP = HIGHBYTE = LOWBYTE = 0x00, with 0 being the only
;                       number with EXP = 0.
;
;       HIGHBYTE        8 bit most significant byte of fraction in sign-magnitude representation,
;                       with SIGN = MSB, implicit MSB = 1 and radix point to the right of MSB
;
;       LOWBYTE         8 bit least significant byte of sign-magnitude fraction
;
;       EXPONENT        HIGHBYTE        LOWBYTE
;
;       xxxxxxxx        S.xxxxxxx       xxxxxxxx
;
;                        |
;                      RADIX
;                      POINT
;

; 	*****************************************************************************************
;	*****************************************************************************************

;       Integer to float conversion

;       Input:  16 bit 2's complement integer right justified in AARGB0, AARGB1

;       Use:    CALL    FLO1624 or      CALL    FLO24

;       Output: 24 bit floating point number in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  FLOAT( AARG )

;       Max Timing:     11+72 = 83 clks         SAT = 0
;                       11+77 = 88 clks         SAT = 1

;       Min Timing:     7+14 = 21 clks                  AARG = 0
;                       7+18 = 25 clks

;       PM: 11+26 = 37                                  DM: 6

;----------------------------------------------------------------------------------------------

FLO1624

FLO24           MOVLW           D'15'+EXPBIAS		; initialize exponent and add bias
                MOVWF           EXP
                MOVF            AARGB0,W
                MOVWF           SIGN
                BTFSS           AARGB0,MSB		; test sign
                GOTO            NRM2424
                COMF            AARGB1,F		; if < 0, negate and set MSB in SIGN
                COMF            AARGB0,F
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

;**********************************************************************************************

;       Normalization routine

;       Input:  24 bit unnormalized floating point number in AEXP, AARGB0, AARGB1,
;               with sign in SIGN,MSB and other bits zero.

;       Use:    CALL    NRM2424 or      CALL    NRM24

;       Output: 24 bit normalized floating point number in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  NORMALIZE( AARG )

;       Max Timing:     10+6+7*7+7 = 72 clks            SAT = 0
;                       10+6+7*7+1+11 = 77 clks SAT = 1

;       Min Timing:     14 clks                         AARG = 0
;                       5+9+4 = 18 clks

;       PM: 26                                          DM: 6

;----------------------------------------------------------------------------------------------

NRM2424
NRM24
		CLRF            TEMP			; clear exponent decrement
                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM2424
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                BTFSC           _Z			; if highbyte=0, result=0
                GOTO            RES024
                CLRF            AARGB1
                BSF             TEMP,3

NORM2424        MOVF            TEMP,W
                SUBWF           EXP,F
                BTFSS           _Z
                BTFSS           _C
                GOTO            SETFUN24

                BCF             _C			; clear carry bit

NORM2424A       BTFSC           AARGB0,MSB		; if MSB=1, normalization done
                GOTO            FIXSIGN24
                RLF             AARGB1,F		; otherwise, shift left and 
                RLF             AARGB0,F		; decrement EXP
                DECFSZ          EXP,F
                GOTO            NORM2424A

                GOTO            SETFUN24                ; underflow if EXP=0

FIXSIGN24       BTFSS           SIGN,MSB
                BCF             AARGB0,MSB		; clear explicit MSB if positive
                RETLW           0

RES024          CLRF            AARGB0			; result equals zero
                CLRF            AARGB1
		CLRF		AARGB2			; clear extended byte
                CLRF            EXP
                RETLW           0


;**********************************************************************************************
;**********************************************************************************************

;       Integer to float conversion

;       Input:  24 bit 2's complement integer right justified in AARGB0, AARGB1, AARGB2

;       Use:    CALL    FLO2424

;       Output: 24 bit floating point number in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  FLOAT( AARG )

;       Max Timing:     14+94 = 108 clks                RND = 0
;                       14+103 = 117 clks               RND = 1, SAT = 0
;                       14+109 = 123 clks               RND = 1, SAT = 1

;       Min Timing:     6+28 = 34 clks                  AARG = 0
;                       6+22 = 28 clks

;       PM: 14+51 = 65                                  DM: 7

;----------------------------------------------------------------------------------------------

FLO2424         MOVLW           D'23'+EXPBIAS		; initialize exponent and add bias
                MOVWF           EXP
                CLRF            SIGN
                BTFSS           AARGB0,MSB		; test sign
                GOTO            NRM3224
                COMF            AARGB2,F		; if < 0, negate and set MSB in SIGN
                COMF            AARGB1,F
                COMF            AARGB0,F
                INCF            AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F
                BSF             SIGN,MSB

;**********************************************************************************************

;       Normalization routine

;       Input:  32 bit unnormalized floating point number in AEXP, AARGB0, AARGB1,
;               AARGB2, with sign in SIGN,MSB

;       Use:    CALL    NRM3224

;       Output: 24 bit normalized floating point number in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  NORMALIZE( AARG )

;       Max Timing:     21+6+7*8+7+4 = 94 clks  RND = 0
;                       21+6+7*8+20+4 = 103 clks        RND = 1, SAT = 0
;                       21+6+7*8+19+11 = 109 clks       RND = 1, SAT = 1

;       Min Timing:     22+6 = 28 clks                  AARG = 0
;                       5+9+4+4 = 22 clks

;       PM: 51                                          DM: 7

;----------------------------------------------------------------------------------------------

NRM3224         CLRF            TEMP                    ; clear exponent decrement
                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM3224
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                MOVF            AARGB2,W
                MOVWF           AARGB1
                CLRF            AARGB2
                BSF             TEMP,3                  ; increase decrement by 8

                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM3224
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                CLRF            AARGB1
                BCF             TEMP,3                  ; increase decrement by 8
                BSF             TEMP,4
        
                MOVF            AARGB0,W		; if highbyte=0, result=0
                BTFSC           _Z
                GOTO            RES024

NORM3224        MOVF            TEMP,W
                SUBWF           EXP,F
                BTFSS           _Z
                BTFSS           _C
                GOTO            SETFUN24

                BCF             _C                      ; clear carry bit

NORM3224A       BTFSC           AARGB0,MSB		; if MSB=1, normalization done
                GOTO            NRMRND3224
                RLF             AARGB2,F		; otherwise, shift left and 
                RLF             AARGB1,F		; decrement EXP
                RLF             AARGB0,F
                DECFSZ          EXP,F
                GOTO            NORM3224A
                GOTO            SETFUN24                ; underflow if EXP=0

NRMRND3224      BTFSC           FPFLAGS,RND
                BTFSS           AARGB1,LSB
                GOTO            FIXSIGN24
		BTFSS		AARGB2,MSB		; round if next bit is set
                GOTO            FIXSIGN24
		INCF		AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

                BTFSS           _Z                     ; has rounding caused carryout?
                GOTO            FIXSIGN24
                RRF             AARGB0,F		; if so, right shift
                RRF             AARGB1,F
                INCF            EXP,F
                BTFSC           _Z                     ; check for overflow
                GOTO            SETFOV24
                GOTO            FIXSIGN24

;**********************************************************************************************
;**********************************************************************************************

;       Float to integer conversion (needed by EXP1024)

;       Input:  24 bit floating point number in AEXP, AARGB0, AARGB1

;       Use:    CALL    INT2416         or      CALL    INT24

;       Output: 16 bit 2's complement integer right justified in AARGB0, AARGB1

;       Result: AARG  <--  INT( AARG )

;       Max Timing:     29+6*6+5+13 = 83 clks           RND = 0
;                       29+6*6+5+19 = 89 clks           RND = 1, SAT = 0
;                       29+6*6+5+22 = 92 clks           RND = 1, SAT = 1

;       Min Timing:     18+5+7 = 30 clks

;       PM: 63                                  DM: 6

;----------------------------------------------------------------------------------------------

INT2416
INT24
		MOVF		EXP,W			; test for zero argument
		BTFSC		_Z
		RETLW		0x00

		MOVF            AARGB0,W		; save sign in SIGN
                MOVWF           SIGN
                BSF             AARGB0,MSB		; make MSB explicit

                MOVLW           EXPBIAS+D'15'		; remove bias from EXP
                SUBWF           EXP,F
		BTFSS		EXP,MSB
                GOTO            SETIOV16
		COMF		EXP,F
		INCF		EXP,F        

                MOVLW           8                       ; do byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT2416
                MOVWF           EXP
                RLF             AARGB1,F		; rotate next bit for rounding
                MOVF            AARGB0,W
                MOVWF           AARGB1
                CLRF            AARGB0

                MOVLW           8                       ; do byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT2416
                MOVWF           EXP
                RLF             AARGB1,F		; rotate next bit for rounding
                CLRF            AARGB1
		MOVF		EXP,W
		BTFSS		_Z
		BCF		_C
		GOTO		SHIFT2416OK

TSHIFT2416      MOVF            EXP,W                   ; shift completed if EXP = 0
                BTFSC           _Z
                GOTO            SHIFT2416OK

SHIFT2416       BCF             _C
                RRF             AARGB0,F		; right shift by EXP
                RRF             AARGB1,F
                DECFSZ          EXP,F
                GOTO            SHIFT2416

SHIFT2416OK     BTFSC           FPFLAGS,RND
                BTFSS           AARGB1,LSB
                GOTO            INT2416OK
		BTFSS		_C			; round if next bit is set
                GOTO            INT2416OK
		INCF		AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

                BTFSC           AARGB0,MSB		; test for overflow
                GOTO            SETIOV16

INT2416OK       BTFSS           SIGN,MSB                ; if sign bit set, negate               
                RETLW           0
                COMF            AARGB1,F
                COMF            AARGB0,F
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F
                RETLW           0

SETIOV16        BSF             FPFLAGS,IOV             ; set integer overflow flag
                BTFSS           FPFLAGS,SAT             ; test for saturation
                RETLW           0xFF                    ; return error code in WREG

                CLRF            AARGB0			; saturate to largest two's
                BTFSS           SIGN,MSB                ; complement 16 bit integer
                MOVLW           0xFF
                MOVWF           AARGB0			; SIGN = 0, 0x 7F FF
                MOVWF           AARGB1			; SIGN = 1, 0x 80 00
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF                    ; return error code in WREG

;**********************************************************************************************
;**********************************************************************************************

;       Float to integer conversion

;       Input:  24 bit floating point number in AEXP, AARGB0, AARGB1

;       Use:    CALL    INT2424

;       Output: 24 bit 2's complement integer right justified in AARGB0, AARGB1, AARGB2

;       Result: AARG  <--  INT( AARG )

;       Max Timing:     41+6*7+6+16 = 105 clks		RND = 0
;                       41+6*7+6+24 = 113 clks		RND = 1, SAT = 0
;                       41+6*7+6+26 = 115 clks  	RND = 1, SAT = 1

;       Min Timing:     5 clks

;       PM: 82                                          DM: 6

;----------------------------------------------------------------------------------------------

INT2424
                CLRF            AARGB2
		MOVF		EXP,W			; test for zero argument
		BTFSC		_Z
		RETLW		0x00

		MOVF            AARGB0,W		; save sign in SIGN
                MOVWF           SIGN
                BSF             AARGB0,MSB		; make MSB explicit

                MOVLW           EXPBIAS+D'23'		; remove bias from EXP
                SUBWF           EXP,F
                BTFSS           EXP,MSB
                GOTO            SETIOV24        
		COMF		EXP,F
		INCF		EXP,F        

                MOVLW           8                       ; do byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT2424
                MOVWF           EXP
                RLF             AARGB2,F		; rotate next bit for rounding
                MOVF            AARGB1,W
                MOVWF           AARGB2
                MOVF            AARGB0,W
                MOVWF           AARGB1
                CLRF            AARGB0

                MOVLW           8                       ; do another byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT2424
                MOVWF           EXP
                RLF             AARGB2,F		; rotate next bit for rounding
                MOVF            AARGB1,W
                MOVWF           AARGB2
                CLRF            AARGB1

                MOVLW           8                       ; do another byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT2424
                MOVWF           EXP
                RLF             AARGB2,F		; rotate next bit for rounding
                CLRF            AARGB2
		MOVF		EXP,W
		BTFSS		_Z
		BCF		_C
		GOTO		SHIFT2424OK

TSHIFT2424      MOVF            EXP,W                   ; shift completed if EXP = 0
                BTFSC           _Z
                GOTO            SHIFT2424OK

SHIFT2424       BCF             _C
                RRF             AARGB0,F		; right shift by EXP
                RRF             AARGB1,F
                RRF             AARGB2,F
                DECFSZ          EXP,F
                GOTO            SHIFT2424

SHIFT2424OK     BTFSC           FPFLAGS,RND
                BTFSS           AARGB2,LSB
                GOTO            INT2424OK
                BTFSS           _C
                GOTO            INT2424OK
                INCF            AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F
                BTFSC           AARGB0,MSB		; test for overflow
                GOTO            SETIOV24

INT2424OK       BTFSS           SIGN,MSB                ; if sign bit set, negate               
                RETLW           0
                COMF            AARGB0,F
                COMF            AARGB1,F
                COMF            AARGB2,F
                INCF            AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F
                RETLW           0

IRES024         CLRF            AARGB0			; integer result equals zero
                CLRF            AARGB1
                CLRF            AARGB2
                RETLW           0

SETIOV24        BSF             FPFLAGS,IOV             ; set integer overflow flag
                BTFSS           FPFLAGS,SAT             ; test for saturation
                RETLW           0xFF                    ; return error code in WREG

                CLRF            AARGB0			; saturate to largest two's
                BTFSS           SIGN,MSB                ; complement 24 bit integer
                MOVLW           0xFF
                MOVWF           AARGB0			; SIGN = 0, 0x 7F FF FF
                MOVWF           AARGB1			; SIGN = 1, 0x 80 00 00
                MOVWF           AARGB2
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF                    ; return error code in WREG

;**********************************************************************************************
;**********************************************************************************************

;       Floating Point Multiply

;       Input:  24 bit floating point number in AEXP, AARGB0, AARGB1
;               24 bit floating point number in BEXP, BARGB0, BARGB1

;       Use:    CALL    FPM24

;       Output: 24 bit floating point product in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  AARG * BARG

;       Max Timing:     25+15*16+15+18 = 298 clks       RND = 0
;                       25+15*16+15+29 = 309 clks       RND = 1, SAT = 0
;                       25+15*16+15+33 = 313 clks       RND = 1, SAT = 1

;       Min Timing:     6+5 = 11 clks                   AARG * BARG = 0
;                       24+15*11+14+15 = 218 clks

;       PM: 80                                  DM: 11

;----------------------------------------------------------------------------------------------

FPM24           MOVF            AEXP,W                  ; test for zero arguments
                BTFSS           _Z
                MOVF            BEXP,W
                BTFSC           _Z
                GOTO            RES024

M24BNE0         MOVF            AARGB0,W
                XORWF           BARGB0,W
                MOVWF           SIGN                    ; save sign in SIGN

                MOVF            BEXP,W
                ADDWF           EXP,F
                MOVLW           EXPBIAS-1
                BTFSS           _C
                GOTO            MTUN24

                SUBWF           EXP,F
                BTFSC           _C
                GOTO            SETFOV24                ; set multiply overflow flag
                GOTO            MOK24

MTUN24          SUBWF           EXP,F
                BTFSS           _C
                GOTO            SETFUN24

MOK24
                MOVF            AARGB0,W
                MOVWF           AARGB2			; move result to AARG
                MOVF            AARGB1,W
                MOVWF           AARGB3
		BSF             AARGB2,MSB		; make argument MSB's explicit
                BSF             BARGB0,MSB
                BCF             _C
                CLRF            AARGB0			; clear initial partial product
                CLRF            AARGB1
                MOVLW           D'16'
                MOVWF           TEMP                    ; initialize counter

MLOOP24         BTFSS           AARGB3,LSB		; test next bit
                GOTO            MNOADD24

MADD24          MOVF            BARGB1,W
                ADDWF           AARGB1,F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           AARGB0,F

MNOADD24        RRF             AARGB0,F
                RRF             AARGB1,F
                RRF             AARGB2,F
                RRF             AARGB3,F
                BCF             _C
                DECFSZ          TEMP,F
                GOTO            MLOOP24

                BTFSC           AARGB0,MSB		; check for postnormalization
                GOTO            MROUND24
                RLF             AARGB2,F
                RLF             AARGB1,F
                RLF             AARGB0,F
                DECF            EXP,F

MROUND24        BTFSC           FPFLAGS,RND
                BTFSS           AARGB1,LSB
                GOTO            MUL24OK
		BTFSS		AARGB2,MSB		; round if next bit is set
                GOTO            MUL24OK
		INCF		AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

                BTFSS           _Z                      ; has rounding caused carryout?
                GOTO            MUL24OK
                RRF             AARGB0,F		; if so, right shift
                RRF             AARGB1,F
                INCF            EXP,F
                BTFSC           _Z                      ; check for overflow
                GOTO            SETFOV24

MUL24OK         BTFSS           SIGN,MSB
                BCF             AARGB0,MSB		; clear explicit MSB if positive

                RETLW           0  

SETFOV24        BSF             FPFLAGS,FOV             ; set floating point underflag
                BTFSS           FPFLAGS,SAT             ; test for saturation
                RETLW           0xFF                    ; return error code in WREG

                MOVLW           0xFF
                MOVWF           AEXP                    ; saturate to largest floating
                MOVWF           AARGB0			; point number = 0x FF 7F FF
                MOVWF           AARGB1			; modulo the appropriate sign bit
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF                    ; return error code in WREG

;**********************************************************************************************
;**********************************************************************************************

;       Floating Point Divide

;       Input:  24 bit floating point dividend in AEXP, AARGB0, AARGB1
;               24 bit floating point divisor in BEXP, BARGB0, BARGB1

;       Use:    CALL    FPD24

;       Output: 24 bit floating point quotient in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  AARG / BARG

;       Max Timing:     32+13+15*26+25+12 = 472 clks    RND = 0
;                       32+13+15*26+25+34 = 494 clks    RND = 1, SAT = 0
;                       32+13+15*26+25+38 = 498 clks    RND = 1, SAT = 1

;       Min Timing:     7+5 = 12 clks

;       PM: 120                                 DM: 11

;----------------------------------------------------------------------------------------------

FPD24           MOVF            BEXP,W                  ; test for divide by zero
                BTFSC           _Z
                GOTO            SETFDZ24

                MOVF            AEXP,W
                BTFSC           _Z
                GOTO            RES024

D24BNE0         MOVF            AARGB0,W
                XORWF           BARGB0,W
                MOVWF           SIGN                    ; save sign in SIGN
                BSF             AARGB0,MSB		; make argument MSB's explicit
                BSF             BARGB0,MSB

TALIGN24        CLRF            TEMP                    ; clear align increment
                MOVF            AARGB0,W
                MOVWF           AARGB2			; test for alignment
                MOVF            AARGB1,W
                MOVWF           AARGB3

                MOVF            BARGB1,W
                SUBWF           AARGB3, f
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           AARGB2, f

                CLRF            AARGB2
                CLRF            AARGB3

                BTFSS           _C
                GOTO            DALIGN24OK

                BCF             _C                      ; align if necessary
                RRF             AARGB0,F
                RRF             AARGB1,F
                RRF             AARGB2,F
                MOVLW           0x01
                MOVWF           TEMP                    ; save align increment          

DALIGN24OK      MOVF            BEXP,W                  ; compare AEXP and BEXP
                SUBWF           EXP,F
                BTFSS           _C
                GOTO            ALTB24
        
AGEB24          MOVLW           EXPBIAS-1
                ADDWF           TEMP,W
                ADDWF           EXP,F
                BTFSC           _C
                GOTO            SETFOV24
                GOTO            DARGOK24                ; set overflow flag

ALTB24          MOVLW           EXPBIAS-1
                ADDWF           TEMP,W
                ADDWF           EXP,F
                BTFSS           _C
                GOTO            SETFUN24                ; set underflow flag

DARGOK24        MOVLW           D'16'			; initialize counter
                MOVWF           TEMPB1

DLOOP24         RLF             AARGB3,F		; left shift
                RLF             AARGB2,F
                RLF             AARGB1,F
                RLF             AARGB0,F
                RLF             TEMP,F

                MOVF            BARGB1,W		; subtract
                SUBWF           AARGB1,F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           AARGB0,F

                RLF             BARGB0,W
                IORWF           TEMP,F
                
                BTFSS           TEMP,LSB                ; test for restore
                GOTO            DREST24

                BSF             AARGB3,LSB
                GOTO            DOK24

DREST24         MOVF            BARGB1,W		; restore if necessary
                ADDWF           AARGB1,F
                MOVF            BARGB0,W
                BTFSC           _C
                INCF            BARGB0,W
                ADDWF           AARGB0,F
                BCF             AARGB3,LSB

DOK24           DECFSZ          TEMPB1,F
                GOTO            DLOOP24

DROUND24        BTFSC           FPFLAGS,RND
                BTFSS           AARGB3,LSB
                GOTO            DIV24OK
                BCF             _C
                RLF             AARGB1,F		; compute next significant bit
                RLF             AARGB0,F		; for rounding
                RLF             TEMP,F

                MOVF            BARGB1,W		; subtract
                SUBWF           AARGB1,F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           AARGB0,F

                RLF             BARGB0,W
                IORWF           TEMP,W
                ANDLW           0x01            

                ADDWF           AARGB3,F
                BTFSC           _C
                INCF            AARGB2,F

                BTFSS           _Z                      ; test if rounding caused carryout
                GOTO            DIV24OK
                RRF             AARGB2,F
                RRF             AARGB3,F
                INCF            EXP,F
                BTFSC           _Z                      ; test for overflow
                GOTO            SETFOV24

DIV24OK         BTFSS           SIGN,MSB
                BCF             AARGB2,MSB		; clear explicit MSB if positive

                MOVF            AARGB2,W
                MOVWF           AARGB0			; move result to AARG
                MOVF            AARGB3,W
                MOVWF           AARGB1

                RETLW           0

SETFUN24        BSF             FPFLAGS,FUN             ; set floating point underflag
                BTFSS           FPFLAGS,SAT             ; test for saturation
                RETLW           0xFF                    ; return error code in WREG

                MOVLW           0x01                    ; saturate to smallest floating
                MOVWF           AEXP                    ; point number = 0x 01 00 00
                CLRF            AARGB0			; modulo the appropriate sign bit
                CLRF            AARGB1
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF                    ; return error code in WREG

SETFDZ24        BSF             FPFLAGS,FDZ             ; set divide by zero flag
                RETLW           0xFF

;**********************************************************************************************
;**********************************************************************************************

;       Floating Point Subtract

;       Input:  24 bit floating point number in AEXP, AARGB0, AARGB1
;               24 bit floating point number in BEXP, BARGB0, BARGB1

;       Use:    CALL FPS24

;       Output: 24 bit floating point sum in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  AARG - BARG

;       Max Timing:     2+197 = 199 clks                RND = 0
;                       2+208 = 210 clks                RND = 1, SAT = 0
;                       2+213 = 215 clks                RND = 1, SAT = 1

;       Min Timing:     2+12 = 14 clks

;       PM: 2+112 = 114                         DM: 11

;----------------------------------------------------------------------------------------------

FPS24           MOVLW           0x80
                XORWF           BARGB0,F

;**********************************************************************************************

;       Floating Point Add

;       Input:  24 bit floating point number in AEXP, AARGB0, AARGB1
;               24 bit floating point number in BEXP, BARGB0, BARGB1

;       Use:    CALL FPA24

;       Output: 24 bit floating point sum in AEXP, AARGB0, AARGB1

;       Result: AARG  <--  AARG - BARG

;       Max Timing:     25+28+6*6+5+31+72 = 197 clks            RND = 0
;                       25+28+6*6+5+42+72 = 208 clks            RND = 1, SAT = 0
;                       25+28+6*6+5+42+77 = 213 clks            RND = 1, SAT = 1

;       Min Timing:     8+4 = 12 clks

;       PM: 112                                                 DM: 11

;----------------------------------------------------------------------------------------------

FPA24           MOVF            AARGB0,W		; exclusive or of signs in TEMP
                XORWF           BARGB0,W
                MOVWF           TEMP

		CLRF		AARGB2			; clear extended byte
		CLRF		BARGB2

                MOVF            AEXP,W                  ; use AARG if AEXP >= BEXP
                SUBWF           BEXP,W
                BTFSS           _C
                GOTO            USEA24

                MOVF            BEXP,W                  ; use BARG if AEXP < BEXP
                MOVWF           AARGB4			; therefore, swap AARG and BARG
                MOVF            AEXP,W
                MOVWF           BEXP
                MOVF            AARGB4,W
                MOVWF           AEXP

                MOVF            BARGB0,W
                MOVWF           AARGB4
                MOVF            AARGB0,W
                MOVWF           BARGB0
                MOVF            AARGB4,W
                MOVWF           AARGB0

                MOVF            BARGB1,W
                MOVWF           AARGB4
                MOVF            AARGB1,W
                MOVWF           BARGB1
                MOVF            AARGB4,W
                MOVWF           AARGB1

USEA24          MOVF            BEXP,W                  ; return AARG if BARG = 0
                BTFSC           _Z
                RETLW           0x00

                MOVF            AARGB0,W
                MOVWF           SIGN                    ; save sign in SIGN
                BSF             AARGB0,MSB		; make MSB's explicit
                BSF             BARGB0,MSB

                MOVF            BEXP,W                  ; compute shift count in BEXP
                SUBWF           AEXP,W
                MOVWF           BEXP
                BTFSC           _Z
                GOTO            ALIGNED24

                MOVLW           8
                SUBWF           BEXP,W
                BTFSS           _C                      ; if BEXP >= 8, do byte shift
                GOTO            ALIGNB24
                MOVWF           BEXP
                MOVF            BARGB1,W		; keep for postnormalization
		MOVWF		BARGB2
                MOVF            BARGB0,W
		MOVWF		BARGB1
                CLRF            BARGB0

                MOVLW           8
                SUBWF           BEXP,W
                BTFSS           _C                      ; if BEXP >= 8, BARG = 0 relative to AARG
                GOTO            ALIGNB24
                MOVF            SIGN,W
                MOVWF           AARGB0
                RETLW           0x00

ALIGNB24        MOVF            BEXP,W                  ; already aligned if BEXP = 0
                BTFSC           _Z
                GOTO            ALIGNED24

ALOOPB24        BCF             _C                      ; right shift by BEXP
                RRF             BARGB0,F
                RRF             BARGB1,F
		RRF		BARGB2,F
                DECFSZ          BEXP,F
                GOTO            ALOOPB24

ALIGNED24       BTFSS           TEMP,MSB                ; negate if signs opposite
                GOTO            AOK24
		COMF		BARGB2,F
                COMF            BARGB1,F
                COMF            BARGB0,F
                INCF            BARGB2,F
                BTFSC           _Z
                INCF            BARGB1,F
		BTFSC		_Z
		INCF		BARGB0,F

AOK24
                MOVF    	BARGB2,W
                ADDWF   	AARGB2,F
                MOVF            BARGB1,W
                BTFSC           _C
                INCFSZ          BARGB1,W
                ADDWF           AARGB1,F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           AARGB0,F

                BTFSC           TEMP,MSB
                GOTO            ACOMP24
                BTFSS           _C
                GOTO            NRMRND3224

                RRF             AARGB0,F		; shift right and increment EXP
                RRF             AARGB1,F
		RRF		AARGB2,F
                INCFSZ          AEXP,F
                GOTO            NRMRND3224
                GOTO            SETFOV24

ACOMP24         BTFSC           _C
                GOTO            NRM3224			; normalize and fix sign

		COMF		AARGB2,F
                COMF            AARGB1,F		; negate, toggle sign bit and
                COMF            AARGB0,F		; then normalize
                INCF            AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

                MOVLW           0x80
                XORWF           SIGN,F
                GOTO            NRM24

;**********************************************************************************************

	org h'800'		; we make the remaining routines start at 0800h, to
					; simplify page crossings...

;	****************************************************************************************
;	THIS NEXT SECTION COMES FROM FP32.A16 
;	(TO GET FPA32 -- called by EXP1024, POL24, also
;	 	FPM32 -- needed by POL24 macro & FLOAT_ASCII, also
;		INT3232 -- needed by FLOAT_ASCII, also
;	 	SETFUN32 -- needed by NORM4032, also
;	 	SETFOV32 -- needed by NRM4032)

;       PIC16 32 BIT FLOATING POINT LIBRARY

;       Floating Point Add

;       Input:  32 bit floating point number in AEXP, AARGB0, AARGB1, AARGB2
;               32 bit floating point number in BEXP, BARGB0, BARGB1, BARGB2

;       Use:    CALL FPA32

;       Output: 32 bit floating point sum in AEXP, AARGB0, AARGB1, AARGB2

;       Result: AARG  <--  AARG - BARG

;       Max Timing:     31+41+6*7+6+41+90 = 251 clks            RND = 0
;                       31+41+6*7+6+55+90 = 265 clks            RND = 1, SAT = 0
;                       31+41+6*7+6+55+96 = 271 clks            RND = 1, SAT = 1

;       Min Timing:     8+4 = 12 clks

;       PM: 146                                                 DM: 14

;----------------------------------------------------------------------------------------------
FPA32
        MOVF            AARGB0,W                ; exclusive or of signs in TEMP
                XORWF           BARGB0,W
                MOVWF           TEMP

		CLRF		AARGB3			; clear extended byte
		CLRF		BARGB3

                MOVF            AEXP,W                  ; use AARG if AEXP >= BEXP
                SUBWF           BEXP,W
                BTFSS           _C
                GOTO            USEA32

                MOVF            BEXP,W                  ; use BARG if AEXP < BEXP
                MOVWF           AARGB5			; therefore, swap AARG and BARG
                MOVF            AEXP,W
                MOVWF           BEXP
                MOVF            AARGB5,W
                MOVWF           AEXP

                MOVF            BARGB0,W
                MOVWF           AARGB5
                MOVF            AARGB0,W
                MOVWF           BARGB0
                MOVF            AARGB5,W
                MOVWF           AARGB0

                MOVF            BARGB1,W
                MOVWF           AARGB5
                MOVF            AARGB1,W
                MOVWF           BARGB1
                MOVF            AARGB5,W
                MOVWF           AARGB1

                MOVF            BARGB2,W
                MOVWF           AARGB5
                MOVF            AARGB2,W
                MOVWF           BARGB2
                MOVF            AARGB5,W
                MOVWF           AARGB2

USEA32          MOVF            BEXP,W                  ; return AARG if BARG = 0
                BTFSC           _Z
                RETLW           0x00

                MOVF            AARGB0,W
                MOVWF           SIGN                    ; save sign in SIGN
                BSF             AARGB0,MSB              ; make MSB's explicit
                BSF             BARGB0,MSB

                MOVF            BEXP,W                  ; compute shift count in BEXP
                SUBWF           AEXP,W
                MOVWF           BEXP
                BTFSC           _Z
                GOTO            ALIGNED32

                MOVLW           8
                SUBWF           BEXP,W
                BTFSS           _C                      ; if BEXP >= 8, do byte shift
                GOTO            ALIGNB32
                MOVWF           BEXP
                MOVF            BARGB2,W		; keep for postnormalization
		MOVWF		BARGB3
                MOVF            BARGB1,W
		MOVWF		BARGB2
                MOVF            BARGB0,W
		MOVWF		BARGB1
                CLRF            BARGB0

                MOVLW           8
                SUBWF           BEXP,W
                BTFSS           _C                      ; if BEXP >= 8, do byte shift
                GOTO            ALIGNB32
                MOVWF           BEXP
                MOVF            BARGB2,W		; keep for postnormalization
		MOVWF		BARGB3
                MOVF            BARGB1,W
		MOVWF		BARGB2
                CLRF            BARGB1

                MOVLW           8
                SUBWF           BEXP,W
                BTFSS           _C                      ; if BEXP >= 8, BARG = 0 relative to AARG
                GOTO            ALIGNB32
                MOVF            SIGN,W
                MOVWF           AARGB0
                RETLW           0x00

ALIGNB32        MOVF            BEXP,W                  ; already aligned if BEXP = 0
                BTFSC           _Z
                GOTO            ALIGNED32

ALOOPB32        BCF             _C                      ; right shift by BEXP
                RRF             BARGB0,F
                RRF             BARGB1,F
		RRF		BARGB2,F
		RRF		BARGB3,F
                DECFSZ          BEXP,F
                GOTO            ALOOPB32

ALIGNED32       BTFSS           TEMP,MSB                ; negate if signs opposite
                GOTO            AOK32

		COMF		BARGB3,F
		COMF		BARGB2,F
                COMF            BARGB1,F
                COMF            BARGB0,F
                INCF            BARGB3,F
                BTFSC           _Z
                INCF            BARGB2,F
		BTFSC		_Z
		INCF		BARGB1,F
		BTFSC		_Z
		INCF		BARGB0,F

AOK32
                MOVF   		BARGB3,W
                ADDWF   	AARGB3,F
                MOVF            BARGB2,W
                BTFSC           _C
                INCFSZ          BARGB2,W
                ADDWF           AARGB2,F
                MOVF            BARGB1,W
                BTFSC           _C
                INCFSZ          BARGB1,W
                ADDWF           AARGB1,F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           AARGB0,F

                BTFSC           TEMP,MSB
                GOTO            ACOMP32
                BTFSS           _C
                GOTO            NRMRND4032

                RRF             AARGB0,F               ; shift right and increment EXP
                RRF             AARGB1,F
                RRF             AARGB2,F
		RRF		AARGB3,F
                INCFSZ          AEXP,F
                GOTO            NRMRND4032
                GOTO            SETFOV32

ACOMP32         BTFSC           _C
                GOTO            NRM4032			; normalize and fix sign

		COMF		AARGB3,F
                COMF            AARGB2,F		; negate, toggle sign bit and
                COMF            AARGB1,F		; then normalize
                COMF            AARGB0,F
                INCF            AARGB3,F
                BTFSC           _Z
                INCF            AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

                MOVLW           0x80
                XORWF           SIGN,F

NRM32           CLRF            TEMP			; clear exponent decrement
                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM3232
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                MOVF            AARGB2,W
                MOVWF           AARGB1
                CLRF            AARGB2
                BSF             TEMP,3                  ; increase decrement by 8

                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM3232
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                CLRF            AARGB1
                BCF             TEMP,3                  ; increase decrement by 8
                BSF             TEMP,4
        
                MOVF            AARGB0,W		; if highbyte=0, result=0
                BTFSC           _Z
                GOTO            RES032

NORM3232        MOVF            TEMP,W
                SUBWF           EXP,F
                BTFSS           _Z
                BTFSS           _C
                GOTO            SETFUN32

                BCF             _C                      ; clear carry bit

NORM3232A       BTFSC           AARGB0,MSB		; if MSB=1, normalization done
                GOTO            FIXSIGN32
                RLF             AARGB2,F                ; otherwise, shift left and 
                RLF             AARGB1,F                ; decrement EXP
                RLF             AARGB0,F
                DECFSZ          EXP,F
                GOTO            NORM3232A
                GOTO            SETFUN32                ; underflow if EXP=0

FIXSIGN32       BTFSS           SIGN,MSB
                BCF             AARGB0,MSB              ; clear explicit MSB if positive
                RETLW           0

RES032          CLRF            AARGB0                  ; result equals zero
                CLRF            AARGB1
                CLRF            AARGB2
		CLRF		AARGB3
                CLRF            EXP
                RETLW           0

SETFUN32        BSF             FPFLAGS,FUN             ; set floating point underflag
                BTFSS           FPFLAGS,SAT             ; test for saturation
                RETLW           0xFF                    ; return error code in WREG

                MOVLW           0x01                    ; saturate to smallest floating
                MOVWF           AEXP                    ; point number = 0x 01 00 00 00
                CLRF            AARGB0                  ; modulo the appropriate sign bit
                CLRF            AARGB1
                CLRF            AARGB2
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF                    ; return error code in WREG

;**********************************************************************************************

;       Normalization routine (needed by FPA32)

;       Input:  40 bit unnormalized floating point number in AEXP, AARGB0, AARGB1,
;               AARGB2, AARGB3 with sign in SIGN,MSB

;       Use:    CALL    NRM4032

;       Output: 32 bit normalized floating point number in AEXP, AARGB0, AARGB1, AARGB2,
;               AARGB3

;       Result: AARG  <--  NORMALIZE( AARG )

;       Max Timing:     38+6*9+12+8 = 112 clks  RND = 0
;                       38+6*9+12+24 = 128 clks RND = 1, SAT = 0
;                       38+6*9+12+31 = 135 clks RND = 1, SAT = 1

;       Min Timing:     33+6 = 39 clks                  AARG = 0
;                       5+9+8 = 22 clks

;       PM: 66                                          DM: 8

;----------------------------------------------------------------------------------------------
NRM4032         CLRF            TEMP			; clear exponent decrement
                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM4032
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                MOVF            AARGB2,W
                MOVWF           AARGB1
                MOVF            AARGB3,W
                MOVWF           AARGB2
                CLRF            AARGB3
                BSF             TEMP,3                  ; increase decrement by 8

                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM4032
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                MOVF            AARGB2,W
                MOVWF           AARGB1
                CLRF            AARGB2
                BCF             TEMP,3                  ; increase decrement by 8
                BSF             TEMP,4
        
                MOVF            AARGB0,W		; test if highbyte=0
                BTFSS           _Z
                GOTO            NORM4032
                MOVF            AARGB1,W		; if so, shift 8 bits by move
                MOVWF           AARGB0
                CLRF            AARGB1
                BSF             TEMP,3                  ; increase decrement by 8
        
                MOVF            AARGB0,W		; if highbyte=0, result=0
                BTFSC           _Z
                GOTO            RES032

NORM4032        MOVF            TEMP,W
                SUBWF           EXP,F
                BTFSS           _Z
                BTFSS           _C
                GOTO            SETFUN32

                BCF             _C                      ; clear carry bit

NORM4032A       BTFSC           AARGB0,MSB		; if MSB=1, normalization done
                GOTO            NRMRND4032
                RLF             AARGB3,F                ; otherwise, shift left and 
                RLF             AARGB2,F                ; decrement EXP
                RLF             AARGB1,F
                RLF             AARGB0,F
                DECFSZ          EXP,F
                GOTO            NORM4032A

                GOTO            SETFUN32                ; underflow if EXP=0

NRMRND4032      BTFSC           FPFLAGS,RND
                BTFSS           AARGB2,LSB
                GOTO            FIXSIGN32
		BTFSS		AARGB3,MSB		; round if next bit is set
                GOTO            FIXSIGN32
		INCF		AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

                BTFSS           _Z                      ; has rounding caused carryout?
                GOTO            FIXSIGN32
                RRF             AARGB0,F                ; if so, right shift
                RRF             AARGB1,F
                RRF             AARGB2,F
                INCF            EXP,F
                BTFSC           _Z                      ; check for overflow
                GOTO            SETFOV32
                GOTO            FIXSIGN32

SETFOV32        BSF             FPFLAGS,FOV             ; set floating point underflag
                BTFSS           FPFLAGS,SAT             ; test for saturation
                RETLW           0xFF                    ; return error code in WREG

                MOVLW           0xFF
                MOVWF           AEXP                    ; saturate to largest floating
                MOVWF           AARGB0                  ; point number = 0x FF 7F FF FF
                MOVWF           AARGB1                  ; modulo the appropriate sign bit
                MOVWF           AARGB2
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF                    ; return error code in WREG

;**********************************************************************************************
;**********************************************************************************************

;       Floating Point Multiply (needed by POL24 macro)

;       Input:  32 bit floating point number in AEXP, AARGB0, AARGB1, AARGB2
;               32 bit floating point number in BEXP, BARGB0, BARGB1, BARGB2

;       Use:    CALL    FPM32

;       Output: 32 bit floating point product in AEXP, AARGB0, AARGB1, AARGB2

;       Result: AARG  <--  AARG * BARG

;       Max Timing:     26+23*22+21+21 = 574 clks       RND = 0
;                       26+23*22+21+35 = 588 clks       RND = 1, SAT = 0
;                       26+23*22+21+38 = 591 clks       RND = 1, SAT = 1

;       Min Timing:     6+6 = 12 clks                   AARG * BARG = 0
;                       24+23*11+21+17 = 315 clks

;       PM: 94                                          DM: 14

;----------------------------------------------------------------------------------------------

FPM32           MOVF            AEXP,W                  ; test for zero arguments
                BTFSS           _Z
                MOVF            BEXP,W
                BTFSC           _Z
                GOTO            RES032

M32BNE0         MOVF            AARGB0,W
                XORWF           BARGB0,W
                MOVWF           SIGN                    ; save sign in SIGN

                MOVF            BEXP,W
                ADDWF           EXP,F
                MOVLW           EXPBIAS-1
                BTFSS           _C
                GOTO            MTUN32

                SUBWF           EXP,F
                BTFSC           _C
                GOTO            SETFOV32                ; set multiply overflow flag
                GOTO            MOK32

MTUN32          SUBWF           EXP,F
                BTFSS           _C
                GOTO            SETFUN32

MOK32		MOVF		AARGB0,W
		MOVWF		AARGB3
		MOVF		AARGB1,W
		MOVWF		AARGB4
		MOVF		AARGB2,W
		MOVWF		AARGB5
		BSF             AARGB3,MSB              ; make argument MSB's explicit
                BSF             BARGB0,MSB
                BCF             _C
                CLRF            AARGB0			; clear initial partial product
                CLRF            AARGB1
                CLRF            AARGB2
                MOVLW           D'24'
                MOVWF           TEMP                    ; initialize counter

MLOOP32         BTFSS           AARGB5,LSB              ; test next bit
                GOTO            MNOADD32

MADD32          MOVF            BARGB2,W
                ADDWF           AARGB2,F
                MOVF            BARGB1,W
                BTFSC           _C
                INCFSZ          BARGB1,W
                ADDWF           AARGB1,F

                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           AARGB0,F

MNOADD32        RRF             AARGB0,F
                RRF             AARGB1,F
                RRF             AARGB2,F
                RRF             AARGB3,F
                RRF             AARGB4,F
                RRF             AARGB5,F
                BCF             _C
                DECFSZ          TEMP,F
                GOTO            MLOOP32

                BTFSC           AARGB0,MSB               ; check for postnormalization
                GOTO            MROUND32
                RLF             AARGB3,F
                RLF             AARGB2,F
                RLF             AARGB1,F
                RLF             AARGB0,F
                DECF            EXP,F

MROUND32        BTFSC           FPFLAGS,RND
                BTFSS           AARGB2,LSB
                GOTO            MUL32OK
		BTFSS		AARGB3,MSB
                GOTO            MUL32OK
		INCF		AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F

                BTFSS           _Z                      ; has rounding caused carryout?
                GOTO            MUL32OK
                RRF             AARGB0,F                ; if so, right shift
                RRF             AARGB1,F
                RRF             AARGB2,F
                INCF            EXP,F
                BTFSC           _Z                      ; check for overflow
                GOTO            SETFOV32

MUL32OK         BTFSS           SIGN,MSB
                BCF             AARGB0,MSB		; clear explicit MSB if positive
                RETLW           0 
 
SETIOV3224	BSF         FPFLAGS,IOV             ; set integer overflow flag
                BTFSS   FPFLAGS,SAT             ; test for saturation
                RETLW   0xFF                    ; return error code in WREG

                CLRF            AARGB0			; saturate to largest two's
                BTFSS           SIGN,MSB        ; complement 24 bit integer
                MOVLW           0xFF
                MOVWF           AARGB0			; SIGN = 0, 0x 7F FF FF
                MOVWF           AARGB1			; SIGN = 1, 0x 80 00 00
                MOVWF           AARGB2
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF            ; return error code in WREG
;   *******************************************************************************************
;	*******************************************************************************************
;       Float to integer conversion

;       Input:  32 bit floating point number in AEXP, AARGB0, AARGB1, AARGB2

;       Use:    CALL    INT3232

;       Output: 32 bit 2's complement integer right justified in AARGB0, AARGB1, AARGB2,
;               AARGB3

;       Result: AARG  <--  INT( AARG )

;       Max Timing:     54+6*8+7+21 = 130 clks          RND = 0
;                       54+6*8+7+29 = 137 clks          RND = 1, SAT = 0
;                       54+6*8+7+29 = 137 clks          RND = 1, SAT = 1

;       Min Timing:     5 clks

;       PM: 102                                                 DM: 7

;----------------------------------------------------------------------------------------------

INT3232
                CLRF            AARGB3
		MOVF		EXP,W			; test for zero argument
		BTFSC		_Z
		RETLW		0x00

		MOVF            AARGB0,W		; save sign in SIGN
                MOVWF           SIGN
                BSF             AARGB0,MSB		; make MSB explicit

                MOVLW           EXPBIAS+D'31'		; remove bias from EXP
                SUBWF           EXP,F
                BTFSS           EXP,MSB
                GOTO            SETIOV32
		COMF		EXP,F
		INCF		EXP,F        

                MOVLW           8                       ; do byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT3232
                MOVWF           EXP
                RLF             AARGB3,F                ; rotate next bit for rounding
                MOVF            AARGB2,W
                MOVWF           AARGB3
                MOVF            AARGB1,W
                MOVWF           AARGB2
                MOVF            AARGB0,W
                MOVWF           AARGB1
                CLRF            AARGB0

                MOVLW           8                       ; do another byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT3232
                MOVWF           EXP
                RLF             AARGB3,F                ; rotate next bit for rounding
                MOVF            AARGB2,W
                MOVWF           AARGB3
                MOVF            AARGB1,W
                MOVWF           AARGB2
                CLRF            AARGB1

                MOVLW           8                       ; do another byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT3232
                MOVWF           EXP
                RLF             AARGB3,F                ; rotate next bit for rounding
                MOVF            AARGB2,W
                MOVWF           AARGB3
                CLRF            AARGB2

                MOVLW           8                       ; do another byte shift if EXP >= 8
                SUBWF           EXP,W
                BTFSS           _C
                GOTO            TSHIFT3232
                MOVWF           EXP
                RLF             AARGB3,F                ; rotate next bit for rounding
                CLRF            AARGB3
		MOVF		EXP,W
		BTFSS		_Z
		BCF		_C
		GOTO		SHIFT3232OK

TSHIFT3232      MOVF            EXP,W                   ; shift completed if EXP = 0
                BTFSC           _Z
                GOTO            SHIFT3232OK

SHIFT3232       BCF             _C
                RRF             AARGB0,F                ; right shift by EXP
                RRF             AARGB1,F
                RRF             AARGB2,F
                RRF             AARGB3,F
                DECFSZ          EXP,F
                GOTO            SHIFT3232

SHIFT3232OK     BTFSC           FPFLAGS,RND
                BTFSS           AARGB3,LSB
                GOTO            INT3232OK
                BTFSS           _C
                GOTO            INT3232OK
                INCF            AARGB3,F
                BTFSC           _Z
                INCF            AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F
                BTFSC           AARGB0,MSB		; test for overflow
                GOTO            SETIOV3224

INT3232OK       BTFSS           SIGN,MSB                ; if sign bit set, negate               
                RETLW           0
                COMF            AARGB0,F
                COMF            AARGB1,F
                COMF            AARGB2,F
                COMF            AARGB3,F
                INCF            AARGB3,F
                BTFSC           _Z
                INCF            AARGB2,F
                BTFSC           _Z
                INCF            AARGB1,F
                BTFSC           _Z
                INCF            AARGB0,F
                RETLW           0

IRES032         CLRF            AARGB0			; integer result equals zero
                CLRF            AARGB1
                CLRF            AARGB2
                CLRF            AARGB3
                RETLW           0

SETIOV32        BSF             FPFLAGS,IOV             ; set integer overflow flag
                BTFSS           FPFLAGS,SAT             ; test for saturation
                RETLW           0xFF                    ; return error code in WREG

                CLRF            AARGB0			; saturate to largest two's
                BTFSS           SIGN,MSB                ; complement 32 bit integer
                MOVLW           0xFF
                MOVWF           AARGB0			; SIGN = 0, 0x 7F FF FF FF
                MOVWF           AARGB1			; SIGN = 1, 0x 80 00 00 00
                MOVWF           AARGB2
                MOVWF           AARGB3
                RLF             SIGN,F
                RRF             AARGB0,F
                RETLW           0xFF            ; return error code in WREG

;	***********************************************************************
;	***********************************************************************

;	THIS SECTION COMES FROM MATH16.MAC (for POL24 macro, needed by EXP1024)

;	POL24	macro		COF,N,ROUND

;	32 bit evaluation of polynomial of degree N, PN(AARG), with coefficients COF,
;	and where AARG is assumed have been be saved in DARG when N>1.
;	The result is in AARG.

;	ROUND = 0	no rounding is enabled; can be previously enabled
;	ROUND = 1	rounding is enabled
;	ROUND = 2	rounding is enabled then disabled before last add
;	ROUND = 3	rounding is assumed disabled then enabled before last add
;	ROUND = 4	rounding is assumed enabled and then disabled before last
;			add if DARGB3,RND is clear
;	ROUND = 5	rounding is assumed disabled and then enabled before last
;			add if DARGB3,RND is set

POL24	macro		COF,N,ROUND
	local		i,j
	variable	i = N, j = 0

	if	ROUND == 1  ||  ROUND == 2

		BSF		FPFLAGS,RND

	endif

		MOVLW		COF#v(i)
		MOVWF		BEXP

	while		j <= 2

		MOVLW		COF#v(i)#v(j)
		MOVWF		BARGB#v(j)

	variable	j = j + 1

	endw
		BSF PCLATH,3
		BCF PCLATH,4
		CALL		FPM32

	variable	i = i - 1

		MOVLW		COF#v(i)
		MOVWF		BEXP

	variable	j = 0

	while		j <= 2

		MOVLW		COF#v(i)#v(j)
		MOVWF		BARGB#v(j)

	variable	j = j + 1

	endw
		BSF PCLATH,3
		BCF PCLATH,4
		CALL		FPA32

	variable	i = i - 1

	while		i >= 0

		MOVF		DEXP,W
		MOVWF		BEXP
		MOVF		DARGB0,W
		MOVWF		BARGB0
		MOVF		DARGB1,W
		MOVWF		BARGB1
		MOVF		DARGB2,W
		MOVWF		BARGB2
		BSF PCLATH,3
		BCF PCLATH,4
		CALL		FPM32

		MOVLW		COF#v(i)
		MOVWF		BEXP

	variable	j = 0

	while		j <= 2

		MOVLW		COF#v(i)#v(j)
		MOVWF		BARGB#v(j)

	variable	j = j + 1

	endw

	if	i == 0

		if	ROUND == 2

		BCF		FPFLAGS,RND

		endif

		if	ROUND == 3

		BSF		FPFLAGS,RND

		endif

		if	ROUND == 4

		BTFSS		DARGB3,RND
		BCF		FPFLAGS,RND

		endif

		if	ROUND == 5

		BTFSC		DARGB3,RND
		BSF		FPFLAGS,RND

		endif

	endif
		BSF PCLATH,3
		BCF PCLATH,4
		CALL		FPA32

	variable	i = i - 1

	endw

	endm
;
;	******************************************************************
;	******************************************************************

;	THIS NEXT SECTION IS FROM EXP1024.A16 (ALL OF IT, IN FACT)

;	Evaluate exp10(x)

;	Input:	24 bit floating point number in AEXP, AARGB0, AARGB1

;	Use:	CALL	EXP1024

;	Output:	24 bit floating point number in AEXP, AARGB0, AARGB1

;	Result:	AARG  <--  EXP10( AARG )

;	Testing on [MINLOG10,MAXLOG10] from 10000 trials:

;			min	max	mean
;	Timing:	2043	2561	2328.7	clks

;			min	max	mean	rms
;	Error:	-0x75	0x77	-0.95	40.34	nsb

;	------------------------------------------------------------------------

;	This approximation of the base 10 exponential function is based upon the
;	expansion

;		exp10(x) = 10**x = 2**(x/log10(2)) = 2**z * 2**n

;			x/log10(2) = z + n,

;	where 0 <= z < 1 and n is an integer, evaluated during range reduction.
;	Segmented third degree minimax polynomial approximations are used to
;	estimate 2**z on the intervals [0,.25], [.25,.5], [.5,.75] and [.75,1].

EXP1024
		MOVLW		0x64			; test for |x| < 2**(-24)/(2*LOG(10))
		SUBWF		EXP,W
		MOVWF		TEMPB0
		BTFSC		TEMPB0,MSB
		GOTO		EXP1024ONE		; return 10**x = 1

		BTFSC		AARGB0,MSB
		GOTO		TNEXP1024
TPEXP1024
		MOVF		AEXP,W
		SUBLW		MAXLOG1024EXP
		BTFSS		_C
		GOTO		DOMERR24
		BTFSS		_Z
		GOTO		EXP1024ARGOK

		MOVF		AARGB0,W
		SUBLW		MAXLOG1024B0
		BTFSS		_C
		GOTO		DOMERR24
		BTFSS		_Z
		GOTO		EXP1024ARGOK

		MOVF		AARGB1,W
		SUBLW		MAXLOG1024B1
		BTFSS		_C
		GOTO		DOMERR24
		GOTO		EXP1024ARGOK

DOMERR24
		BSF		FPFLAGS,DOM		; domain error
		RETLW		0xFF

TNEXP1024
		MOVF		AEXP,W
		SUBLW		MINLOG1024EXP
		BTFSS		_C
		GOTO		DOMERR24
		BTFSS		_Z
		GOTO		EXP1024ARGOK

		MOVF		AARGB0,W
		SUBLW		MINLOG1024B0
		BTFSS		_C
		GOTO		DOMERR24
		BTFSS		_Z
		GOTO		EXP1024ARGOK

		MOVF		AARGB1,W
		SUBLW		MINLOG1024B1
		BTFSS		_C
		GOTO		DOMERR24

EXP1024ARGOK
		MOVF		FPFLAGS,W
		MOVWF		DARGB3			; save rounding flag
		BCF		FPFLAGS,RND		; disable rounding
		BSF PCLATH,3			; make sure we will stay in page1
		BCF PCLATH,4			; when we call RREXP1024
		CALL		RREXP1024

		MOVLW		0x7E
		SUBWF		AEXP,W
		BTFSS		_Z
		GOTO		EXP1024L

EXP1024H	BTFSS		AARGB0,MSB-1
		GOTO		EXP1024HL

		POL24		EXP24HH,3,0		; minimax approximation on [.75,1]

		MOVF		EARGB3,W
		ADDWF		AEXP,F
		RETLW		0x00

EXP1024HL	POL24		EXP24HL,3,0		; minimax approximation on [.5,.75]

		MOVF		EARGB3,W
		ADDWF		AEXP,F
		RETLW		0x00

EXP1024L	MOVLW		0x7D
		SUBWF		AEXP,W
		BTFSS		_Z
		GOTO		EXP1024LL

		POL24		EXP24LH,3,0		; minimax approximation on [.25,.5]

		MOVF		EARGB3,W
		ADDWF		AEXP,F
		RETLW		0x00

EXP1024LL	POL24		EXP24LL,3,0		; minimax approximation on [0,.25]

EXP1024OK
		MOVF		EARGB3,W
		ADDWF		AEXP,F
		BTFSS		DARGB3,RND
		RETLW		0x00

		BSF		FPFLAGS,RND		; restore rounding flag
		GOTO		RND3224

EXP1024ONE	MOVLW		EXPBIAS			; return e**x = 1.0
		MOVWF		AEXP
		CLRF		AARGB0
		CLRF		AARGB1
		CLRF		AARGB2
		RETLW		0x00


;	*************************************************************

;	Range reduction routine for the exponential function

;		x/log10(2) = z + n

RREXP1024
		MOVF		AARGB0,W
		MOVWF		DARGB0
		BSF		AARGB0,MSB

		MOVF		AARGB0,W
		MOVWF		BARGB0
		MOVF		AARGB1,W
		MOVWF		BARGB1

		MOVLW		0xD4			; 1/log10(2) = 3.32192809489
		MOVWF		AARGB0
		MOVLW		0x9A
		MOVWF		AARGB1
		MOVLW		0x78
		MOVWF		AARGB2
		BSF PCLATH,3			; make sure we will stay in page1
		BCF PCLATH,4			; when we call FXM2416U
		CALL		FXM2416U		; x * (1/log10(2))

		INCF		AEXP,F
		INCF		AEXP,F

		BTFSC		AARGB0,MSB
		GOTO		RREXP1024YOK
		RLF		AARGB3,F
		RLF		AARGB2,F
		RLF		AARGB1,F
		RLF		AARGB0,F
		DECF		AEXP,F

RREXP1024YOK
		BTFSS		DARGB0,MSB
		BCF		AARGB0,MSB
		
		MOVF		AEXP,W
		MOVWF		BEXP			; save y in BARG
		MOVF		AARGB0,W
		MOVWF		BARGB0
		MOVF		AARGB1,W
		MOVWF		BARGB1
		MOVF		AARGB2,W
		MOVWF		BARGB2
		BSF PCLATH,3				; make sure we stay in page 1
		BCF PCLATH,4
		CALL		FLOOR24

		MOVF		AEXP,W
		MOVWF		DEXP			; save k in DARG
		MOVF		AARGB0,W
		MOVWF		DARGB0
		MOVF		AARGB1,W
		MOVWF		DARGB1

		BCF PCLATH,3		; prepare to swing down to page 0
		BCF PCLATH,4
		CALL		INT2416			; k = [ x * (1/ln2) ]
		MOVF		AARGB1,W
		MOVWF		EARGB3			; save k in EARG

		MOVF		DEXP,W
		MOVWF		AEXP
		MOVF		DARGB0,W
		MOVWF		AARGB0
		MOVF		DARGB1,W
		MOVWF		AARGB1
		CLRF		AARGB2

		MOVLW		0x80
		XORWF		AARGB0,F
		BSF PCLATH,3		; make sure we'll stay in page1
		BCF PCLATH,4		; when we call FPA32
		CALL		FPA32
		MOVF		AEXP,W
		MOVWF		DEXP			; save y in DARG
		MOVF		AARGB0,W
		MOVWF		DARGB0
		MOVF		AARGB1,W
		MOVWF		DARGB1
		MOVF		AARGB2,W
		MOVWF		DARGB2

		RETLW		0x00
;	-------------------------------------------------------------------

;	third degree minimax polynomial coefficients for 2**(x) on [.75,1]

EXP24HH0	EQU		0x7E		; EXP24HH0 = .99103284632
EXP24HH00	EQU		0x7D
EXP24HH01	EQU		0xB4
EXP24HH02	EQU		0x54

EXP24HH1	EQU		0x7E		; EXP24HH1 = .73346850266
EXP24HH10	EQU		0x3B
EXP24HH11	EQU		0xC4
EXP24HH12	EQU		0x97

EXP24HH2	EQU		0x7C		; EXP24HH2 = .17374128273
EXP24HH20	EQU		0x31
EXP24HH21	EQU		0xE9
EXP24HH22	EQU		0x3C

EXP24HH3	EQU		0x7B		; EXP24HH3 = .10175678143
EXP24HH30	EQU		0x50
EXP24HH31	EQU		0x65
EXP24HH32	EQU		0xDC

;	third degree minimax polynomial coefficients for 2**(x) on [.5,.75]

EXP24HL0	EQU		0x7E		; EXP24HL0 = .99801686089
EXP24HL00	EQU		0x7F
EXP24HL01	EQU		0x7E
EXP24HL02	EQU		0x08

EXP24HL1	EQU		0x7E		; EXP24HL1 = .70586404164
EXP24HL10	EQU		0x34
EXP24HL11	EQU		0xB3
EXP24HL12	EQU		0x81

EXP24HL2	EQU		0x7C		; EXP24HL2 = .21027360637
EXP24HL20	EQU		0x57
EXP24HL21	EQU		0x51
EXP24HL22	EQU		0xF7

EXP24HL3	EQU		0x7B		; EXP24HL3 = .85566912730E-1
EXP24HL30	EQU		0x2F
EXP24HL31	EQU		0x3D
EXP24HL32	EQU		0xB5

;	third degree minimax polynomial coefficients for 2**(x) on [.25,.5]

EXP24LH0	EQU		0x7E		; EXP24LH0 = .99979384559
EXP24LH00	EQU		0x7F
EXP24LH01	EQU		0xF2
EXP24LH02	EQU		0x7D

EXP24LH1	EQU		0x7E		; EXP24LH1 = .69545887384
EXP24LH10	EQU		0x32
EXP24LH11	EQU		0x09
EXP24LH12	EQU		0x98

EXP24LH2	EQU		0x7C		; EXP24LH2 = .23078300446
EXP24LH20	EQU		0x6C
EXP24LH21	EQU		0x52
EXP24LH22	EQU		0x61

EXP24LH3	EQU		0x7B		; EXP24LH3 = .71952910179E-1
EXP24LH30	EQU		0x13
EXP24LH31	EQU		0x5C
EXP24LH32	EQU		0x0C

;	third degree minimax polynomial coefficients for 2**(x) on [0,.25]

EXP24LL0	EQU		0x7E		; EXP24LL0 = .99999970657
EXP24LL00	EQU		0x7F
EXP24LL01	EQU		0xFF
EXP24LL02	EQU		0xFB

EXP24LL1	EQU		0x7E		; EXP24LL1 = .69318585159
EXP24LL10	EQU		0x31
EXP24LL11	EQU		0x74
EXP24LL12	EQU		0xA1

EXP24LL2	EQU		0x7C		; EXP24LL2 = .23944330933
EXP24LL20	EQU		0x75
EXP24LL21	EQU		0x30
EXP24LL22	EQU		0xA0

EXP24LL3	EQU		0x7A		; EXP24LL3 = .60504944237E-1
EXP24LL30	EQU		0x77
EXP24LL31	EQU		0xD4
EXP24LL32	EQU		0x08

;	*******************************************************************
;	*******************************************************************

;	THIS NEXT SECTION COMES FROM FROM FLOOR24.A16 (needed by EXP1024)

;	Evaluate floor(x)

;	Input:	24 bit floating point number in AEXP, AARGB0, AARGB1

;	Use:	CALL	FLOOR24

;	Output:	24 bit floating point number in AEXP, AARGB0, AARGB1

;	Result:	AARG  <--  FLOOR( AARG )

;	Testing on [-MAXNUM,MAXNUM] from 100000 trials:

;		min	max	mean
;	Timing:	37	55	42.7	clks

;		min	max	mean	rms
;	Error:	0x00	0x00	0.0	0.0	nsb

;	-----------------------------------------------------------------------

;	floor(x) evaluates the largest integer, as a float, not greater than x.

FLOOR24
		CLRF		AARGB2			; test for zero argument
		MOVF		AEXP,W
		BTFSC		_Z
		RETLW		0x00

		MOVF		AARGB0,W
		MOVWF		AARGB3			; save mantissa
		MOVF		AARGB1,W
		MOVWF		AARGB4

		MOVLW		EXPBIAS			; computed unbiased exponent
		SUBWF		AEXP,W
		MOVWF		TEMPB1
		BTFSC		TEMPB1,MSB
		GOTO		FLOOR24ZERO

		SUBLW		0x10-1
		MOVWF		TEMPB0			; save number of zero bits in TEMPB0
		MOVWF		TEMPB1

		BTFSC		TEMPB1,LSB+3		; divide by eight
		GOTO		FLOOR24MASKH

FLOOR24MASKL
		MOVLW		0x07			; get remainder for mask pointer
		ANDWF		TEMPB0,F
		MOVLW		LOW FLOOR24MASKTABLE
		ADDWF		TEMPB0,F
		MOVLW		HIGH FLOOR24MASKTABLE
		BTFSC		_C
		ADDLW		0x01
		MOVWF		PCLATH
		INCF		TEMPB0,W

		CALL		FLOOR24MASKTABLE	; access table for mask

		ANDWF		AARGB1,F
		BTFSS		AARGB0,MSB		; if negative, round down
		RETLW		0x00

		MOVWF		AARGB7
		MOVF		AARGB4,W
		SUBWF		AARGB1,W
		BTFSS		_Z
		GOTO		FLOOR24RNDL
		RETLW		0x00

FLOOR24RNDL
		COMF		AARGB7,W
		MOVWF		TEMPB1
		INCF		TEMPB1,W
		ADDWF		AARGB1,F
                BTFSC           _Z
                INCF            AARGB0, F
		BTFSS		_Z			; has rounding caused carryout?
		RETLW		0x00
		RRF		AARGB0,F
		RRF		AARGB1,F
		INCFSZ		AEXP,F			; check for overflow
		RETLW		0x00
		BCF PCLATH,4		; prepare to go back to page 0
		BCF PCLATH,3
		GOTO		SETFOV24

FLOOR24MASKH
		MOVLW		0x07			; get remainder for mask pointer
		ANDWF		TEMPB0,F
		MOVLW		LOW FLOOR24MASKTABLE
		ADDWF		TEMPB0,F
		MOVLW		HIGH FLOOR24MASKTABLE
		BTFSC		_C
		ADDLW		0x01
		MOVWF		PCLATH
		INCF		TEMPB0,W
		CALL		FLOOR24MASKTABLE	; access table for mask
		ANDWF		AARGB0,F
		CLRF		AARGB1
		BTFSS		AARGB0,MSB		; if negative, round down
		RETLW		0x00

		MOVWF		AARGB7
		MOVF		AARGB4,W
		SUBWF		AARGB1,W
		BTFSS		_Z
		GOTO		FLOOR24RNDH
		MOVF		AARGB3,W
		SUBWF		AARGB0,W
		BTFSS		_Z
		GOTO		FLOOR24RNDH
		RETLW		0x00

FLOOR24RNDH
		COMF		AARGB7,W
		MOVWF		TEMPB1
		INCF		TEMPB1,W
		ADDWF		AARGB0,F
		BTFSS		_C			; has rounding caused carryout?
		RETLW		0x00
		RRF		AARGB0,F
		RRF		AARGB1,F
		INCFSZ		AEXP,F
		RETLW		0x00
		BCF PCLATH,3		; prepare to swing back to page 0
		BCF PCLATH,4
		GOTO		SETFOV24		; check for overflow

FLOOR24ZERO
		BTFSC		AARGB0,MSB
		GOTO		FLOOR24MINUSONE
		CLRF		AEXP
		CLRF		AARGB0
		CLRF		AARGB1
		RETLW		0x00

FLOOR24MINUSONE
		MOVLW		0x7F
		MOVWF		AEXP
		MOVLW		0x80
		MOVWF		AARGB0
		CLRF		AARGB1
		RETLW		0x00

;	----------------------------------------------------------------------

;	table for least significant byte requiring masking, using pointer from 
;	the remainder of the number of zero bits divided by eight.

FLOOR24MASKTABLE
		MOVWF		PCL
		RETLW		0xFF
		RETLW		0xFE
		RETLW		0xFC
		RETLW		0xF8
		RETLW		0xF0
		RETLW		0xE0
		RETLW		0xC0
		RETLW		0x80
		RETLW		0x00

;	***********************************************************************
;	***********************************************************************

;	THIS NEXT SECTION COMES FROM RND3224.A16 (RND3224 needed by EXP1024)

;	Nearest neighbor rounding

;	Input:	32 bit floating point number in AEXP, AARGB0, AARGB1, AARGB2

;	Use:	CALL	RND3224

;	Output:	24 bit floating point number in AEXP, AARGB0, AARGB1

;	Result:	AARG  <-- RND( AARG )

;	Testing on [MINNUM,MAXNUM] from 10000 trials:

;		min	max	mean
;	Timing:	3	17		clks

;		min	max	mean
;	Error:	0	0	0 	nsb

;	---------------------------------------------------------------------

RND3224
		BTFSS	AARGB2,MSB		; is NSB < 0x80?
		RETLW	0x00

		BSF		_C			; set carry for rounding
		MOVLW	0x7F
		ANDWF	AARGB2,W
		BTFSC	_Z
		RRF		AARGB1,W		; select even if NSB = 0x80

		MOVF	AARGB0,W
		MOVWF	SIGN			; save sign
		BSF		AARGB0,MSB		; make MSB explicit

		BCF		_Z

		BTFSC	_C			; round
		INCF	AARGB1,F
		BTFSC	_Z
		INCF	AARGB0,F
		
        BTFSS   _Z		; has rounding caused carryout?
        GOTO	RND3224OK
		RRF		AARGB0,F		; if so, right shift
        RRF		AARGB1,F
        INCF	EXP,F		; test for floating point overflow
		BTFSS	_Z			; if Z=1, go to SETFOV24 (page 0)
		GOTO RND3224OK		; but if Z=0 go to RND3223OK
		BCF PCLATH,4		; going to SETFOV24, so prepare
		BCF PCLATH,3		; for just back to page 0
        GOTO    SETFOV24
RND3224OK
		BTFSS	SIGN,MSB
		BCF		AARGB0,MSB		; clear sign bit if positive
		RETLW	0x00

;	***************************************************************
;	***************************************************************

;     THIS NEXT SECTION COMES FROM MATH16.INC FILE
;
;	24 BIT FLOATING POINT CONSTANTS

;	Maximum argument to EXP1024

MAXLOG1024EXP	equ	0x84		; 38.531839445 = log10(2**128)

MAXLOG1024B0	equ	0x1A

MAXLOG1024B1	equ	0x21

;	Minimum argument to EXP1024

MINLOG1024EXP	equ	0x84		; -37.9297794537 = log10(2**-126)

MINLOG1024B0	equ	0x97

MINLOG1024B1	equ	0xB8

;	******************************************************************
;	******************************************************************

;	THIS NEXT SECTION COMES FROM FXM46.A16 (for the FXM2416U routine,
;	needed by EXP1024) Note that the original version of FXM2416U
;	in turn used the macro UMUL2416L (also in FXM46.A16), but only
;	once. This version incorporates that macro code, 'unrolled'...

;       24x16 Bit Unsigned Fixed Point Multiply 24x16 -> 40

;       Input:  24 bit unsigned fixed point multiplicand in AARGB0
;               16 bit unsigned fixed point multiplier in BARGB0

;       Use:    CALL    FXM2416U

;       Output: 40 bit unsigned fixed point product in AARGB0

;       Result: AARG  <--  AARG x BARG

;       Max Timing:     8+324+2 = 334 clks

;       Min Timing:     8+102 = 110 clks

;       PM: 8+61+1 = 70              DM: 12
;	-----------------------------------------------------------------

FXM2416U
                CLRF    AARGB3          ; clear partial product
                CLRF    AARGB4
                MOVF   AARGB0,W
                MOVWF   TEMPB0
                MOVF   AARGB1,W
                MOVWF   TEMPB1
                MOVF   AARGB2,W
                MOVWF   TEMPB2

                MOVLW   0x08			; (this is the start of the 
                MOVWF   LOOPCOUNT		; code from the UMUL2416L macro)

LOOPUM2416A
                RRF     BARGB1, F
                BTFSC   _C
                GOTO    ALUM2416NAP
                DECFSZ  LOOPCOUNT, F
                GOTO    LOOPUM2416A

                MOVWF   LOOPCOUNT

LOOPUM2416B
                RRF     BARGB0, F
                BTFSC   _C
                GOTO    BLUM2416NAP
                DECFSZ  LOOPCOUNT, F
                GOTO    LOOPUM2416B

                CLRF    AARGB0
                CLRF    AARGB1
                CLRF    AARGB2
                RETLW   0x00

BLUM2416NAP
                BCF     _C
                GOTO    BLUM2416NA

ALUM2416NAP
                BCF     _C
                GOTO    ALUM2416NA

ALOOPUM2416
                RRF     BARGB1, F
                BTFSS   _C
                GOTO    ALUM2416NA
                MOVF   TEMPB2,W
                ADDWF   AARGB2, F
                MOVF            TEMPB1,W
                BTFSC           _C
                INCFSZ          TEMPB1,W
                ADDWF           AARGB1, F
                MOVF            TEMPB0,W
                BTFSC           _C
                INCFSZ          TEMPB0,W
                ADDWF           AARGB0, F

ALUM2416NA
                RRF    AARGB0, F
                RRF    AARGB1, F
                RRF    AARGB2, F
                RRF     AARGB3, F
                DECFSZ  LOOPCOUNT, F
                GOTO    ALOOPUM2416

                MOVLW   0x08
                MOVWF   LOOPCOUNT

BLOOPUM2416
                RRF     BARGB0, F
                BTFSS   _C
                GOTO    BLUM2416NA
                MOVF    TEMPB2,W
                ADDWF   AARGB2, F
                MOVF            TEMPB1,W
                BTFSC           _C
                INCFSZ          TEMPB1,W
                ADDWF           AARGB1, F
                MOVF            TEMPB0,W
                BTFSC           _C
                INCFSZ          TEMPB0,W
                ADDWF           AARGB0, F

BLUM2416NA
                RRF    AARGB0, F
                RRF    AARGB1, F
                RRF    AARGB2, F
                RRF             AARGB3, F
                RRF             AARGB4, F
                DECFSZ  LOOPCOUNT, F
                GOTO    BLOOPUM2416			; this is the end of the macro code

                RETLW           0x00

;**********************************************************************************************
;**********************************************************************************************

;	THIS NEXT SECTION COMES FROM FXD26.A16 (for FXD3216U, needed by float_ascii)
;		note also that UDIV3216L macro is needed by FXD3216U
;
;       32/16 PIC16 FIXED POINT DIVIDE ROUTINES
;
;       Input:  fixed point arguments in AARG and BARG
;
;       Output: quotient AARG/BARG followed by remainder in REM
;
;       All timings are worst case cycle counts
;
;       It is useful to note that the additional unsigned routines requiring a non-power of two
;       argument can be called in a signed divide application where it is known that the
;       respective argument is nonnegative, thereby offering some improvement in
;       performance.
;
;         Routine            Clocks     Function
;
;       FXD3216S    595 32 bit/16 bit -> 32.16 signed fixed point divide
;
;       FXD3216U    703 32 bit/16 bit -> 32.16 unsigned fixed point divide <-- **
;
;       FXD3115U    541 31 bit/15 bit -> 31.15 unsigned fixed point divide
;
;**********************************************************************************************

;       Max Timing:     16+6*22+21+21+6*22+21+21+6*22+21+21+6*22+21+8 = 699 clks

;       Min Timing:     16+6*21+20+20+6*21+20+20+6*21+20+20+6*21+20+3 = 663 clks

;       PM: 240                                 DM: 9

UDIV3216L       macro
                CLRF            TEMP

                RLF             AARGB0,W
                RLF             REMB1, F
                MOVF            BARGB1,W
                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                RLF             AARGB0, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3216A      RLF             AARGB0,W
                RLF             REMB1, F
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB1,W
                BTFSS           AARGB0,LSB
                GOTO            UADD26LA

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                GOTO            UOK26LA

UADD26LA        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
                CLRW
                BTFSC           _C
                MOVLW           1
                ADDWF           TEMP, F
        
UOK26LA RLF             AARGB0, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3216A

                RLF             AARGB1,W
                RLF             REMB1, F
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB1,W
                BTFSS           AARGB0,LSB
                GOTO            UADD26L8

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                GOTO            UOK26L8

UADD26L8        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
                CLRW
                BTFSC           _C
                MOVLW           1
                ADDWF           TEMP, F
        
UOK26L8 RLF             AARGB1, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3216B      RLF             AARGB1,W
                RLF             REMB1, F
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB1,W
                BTFSS           AARGB1,LSB
                GOTO            UADD26LB

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                GOTO            UOK26LB

UADD26LB        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
                CLRW
                BTFSC           _C
                MOVLW           1
                ADDWF           TEMP, F
        
UOK26LB RLF             AARGB1, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3216B

                RLF             AARGB2,W
                RLF             REMB1, F
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB1,W
                BTFSS           AARGB1,LSB
                GOTO            UADD26L16

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                GOTO            UOK26L16

UADD26L16       ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
                CLRW
                BTFSC           _C
                MOVLW           1
                ADDWF           TEMP, F
        
UOK26L16        RLF             AARGB2, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3216C      RLF             AARGB2,W
                RLF             REMB1, F
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB1,W
                BTFSS           AARGB2,LSB
                GOTO            UADD26LC

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                GOTO            UOK26LC

UADD26LC        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
                CLRW
                BTFSC           _C
                MOVLW           1
                ADDWF           TEMP, F
        
UOK26LC RLF             AARGB2, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3216C

                RLF             AARGB3,W
                RLF             REMB1, F
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB1,W
                BTFSS           AARGB2,LSB
                GOTO            UADD26L24

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                GOTO            UOK26L24

UADD26L24       ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
                CLRW
                BTFSC           _C
                MOVLW           1
                ADDWF           TEMP, F
        
UOK26L24        RLF             AARGB3, F

                MOVLW           7
                MOVWF           LOOPCOUNT

LOOPU3216D      RLF             AARGB3,W
                RLF             REMB1, F
                RLF             REMB0, F
                RLF             TEMP, F
                MOVF            BARGB1,W
                BTFSS           AARGB3,LSB
                GOTO            UADD26LD

                SUBWF           REMB1, F
                MOVF            BARGB0,W
                BTFSS           _C
                INCFSZ          BARGB0,W
                SUBWF           REMB0, F
                CLRW
                BTFSS           _C
                MOVLW           1
                SUBWF           TEMP, F
                GOTO            UOK26LD

UADD26LD        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
                CLRW
                BTFSC           _C
                MOVLW           1
                ADDWF           TEMP, F
        
UOK26LD RLF             AARGB3, F

                DECFSZ          LOOPCOUNT, F
                GOTO            LOOPU3216D

                BTFSC           AARGB3,LSB
                GOTO            UOK26L
                MOVF            BARGB1,W
	        ADDWF           REMB1, F
                MOVF            BARGB0,W
                BTFSC           _C
                INCFSZ          BARGB0,W
                ADDWF           REMB0, F
UOK26L

                endm

;**********************************************************************************************
;**********************************************************************************************
        
;       32/16 Bit Unsigned Fixed Point Divide 32/16 -> 32.16

;       Input:  32 bit unsigned fixed point dividend in AARGB0, AARGB1,AARGB2,AARGB3
;               16 bit unsigned fixed point divisor in BARGB0, BARGB1

;       Use:    CALL    FXD3216U

;       Output: 32 bit unsigned fixed point quotient in AARGB0, AARGB1,AARGB2,AARGB3
;               16 bit unsigned fixed point remainder in REMB0, REMB1

;       Result: AARG, REM  <--  AARG / BARG

;       Max Timing:     2+699+2 = 703 clks

;       Max Timing:     2+663+2 = 667 clks

;       PM: 2+240+1 = 243               DM: 9

FXD3216U        CLRF            REMB0
                CLRF            REMB1

                UDIV3216L

                RETLW           0x00

;****************************************************************************
;****************************************************************************

;		THIS SECTION IS TAKEN FROM FLOAT_ASCII.INC (most of it, in fact)
;		to provide Floating Point to ASCII conversion (from AN670)
;
; INPUT: 32 bit floating point number in AEXP, AARGB0, AARGB1, AARGB2
;
; OUTPUT: ones, tenths, hundredths, thousandths, tenthous (ASCII digit in each)
;         
;
; USED: INDF,FSR,AARG,BARG,REMB,digit_count
;
; PROCEDURE: The floating point number in AARG is multiplied by 1000 (or 100)
;            Then the product is divided by 10 three times.  After each
;            divide, the remainder is kept.  
;
;            After each digit is obtained, 30H is added to it to make it
;            an ASCII representation of that number.  Then, the ASCII
;            value is stored in register RAM at the locations specified
;            in the "cblock."      
;
;	Note: The ASCII decimal point is not generated by this routine.
;            You must output the decimal point in the correct decimal
;            position for your application.  For this example, the
;            decimal point is after the first digit: ones.

;	Note also: in this version, the initial BARG setup with the multiplier
;			(10kd, 1kd or 100d) has been moved into the calling program.
;            
;****************************************************************************

last_digit set tenthous

SIG_FIG equ     5               ;set SIG_FIG equal to the number of 
                                ;significant figures in your decimal number
                                ;for example: ones, tenths,hundredths, 
                                ;thousandths - requires 4 sig figs

float_ascii
	BSF PCLATH,3			; make sure we will stay in page1
	BCF PCLATH,4			; when we call FPM32
	call	FPM32			;AARG = AARG * BARG (where BARG = 1000d or 100d)
	BSF PCLATH,3			; also make sure we will stay in page1
	BCF PCLATH,4			; when we call INT3232
	call	INT3232			;AARG  <--  INT( AARG )

	movlw	last_digit
	movwf	FSR				;pointer = address of smallest digit
	movlw	SIG_FIG         ;load counter with the number of
	movwf	digit_count     ;significant figures in the decimal number	

flo_asclp
	clrf	BARGB0		;Make the divisor 10.  
	movlw	d'10'
	movwf	BARGB1
	BSF PCLATH,3			; make sure we will stay in page1
	BCF PCLATH,4			; when we call FXD3216U
	call	FXD3216U	;divide (32 bit fixed) / 10 (to get remainder)
	
	movf	REMB1,w		;put remainder in w register
	movwf	INDF		;put number into appropriate digit position

	movlw	0x30
	addwf	INDF,f		;add 30h to decimal number to convert to ASCII

	decf	FSR,f		;move pointer to next digit 	

	decfsz	digit_count,f
	goto	flo_asclp	; loop back to continue, if not done

	return

 ;	***********************************************************************************

 
    


