;---------------------------------------------------------------------
; MATH.ASM
; Keith Larson
; TMS320 DSP Applications
; (C) Copyright 1996
; Texas Instruments Incorporated
;
; This is unsupported freeware with no implied warranties or
; liabilities.  See the disclaimer document for details
;---------------------------------------------------------------------;
; This example shows several math algorithms implimented on the       ;
; TMS320C3x.  For more information regarding these algorithm see      ;
; the TMS320C3x users guide, applications manuals and designer	      ;
; notebook pages. (either download from the FTP or BBS sites or       ;
; contact the product information center)			      ;
;                                                                     ;
; These functions are written for readability, not speed.  You can    ;
; find more information in the see the C3x Users Guide, Applications  ;
; Book, Designer Notebook Pages, Compiler manual or Textbooks.	      ;
;                                                                     ;
; In this example, the value 3.0000 is continuously loaded into R0    ;
; for each function.  Functions are then called and the result is     ;
; returned in R0.  To view the registers in floating point you can    ;
; use the F3 key, which always pop back to the default hex display,   ;
; or you can view the contents of the floating point registers using  ;
; the following two methods					      ;
;								      ;
; CMD>MEMF _F0	    This will open a floating point memory window     ;
;		    whose 'view' begins at the context storage area   ;
;		 >> _F0 is a symbol, and is therefor case sensitive <<;
;								      ;
; From Windows, open another DOS prompt (DOS window), shrink it to    ;
; be in the Windowed mode (alt enter).	The go to 'settings' and set  ;
; the window to run as a background task.  At this time, you should   ;
; also set the debugger to run as a background task.  Then execute    ;
; the register view utility with NO reset arguments.  (If you do,     ;
; comm link to the debugger will crash).  IE			      ;
;								      ;
; From another DOS box, run the following program...		      ;
;								      ;
; C:\DSKTOOLS\REGVIEW [LPTx]					      ;
;---------------------------------------------------------------------
;  NOTES ABOUT FLOATING POINT NUMBERS
;  ----------------------------------
;  By knowing that the exponent and mantissa are both two's compliment values
;  and also knowing that a floating point number is a very close approximation
;  of the same number expressed in log2 form (see DNP #22), a quick inversions
;  and square roots can be implimented with simple functions.  For example
;  a quick inverse is calculated by negating the exponent and mantissa bits.
;
;  Furthermore a shift is all that is required to create a square root.
;  Albeit that the sign bit that is in the middle of the bit field must
;  be accounted for.  Also note the use of NOT mnemonic instead of NEGI.
;  In this case a 1's compliment, which is very close to a 2's compliment
;  is desired since there is no carry or modify of the sign bit.
; --------------------------------------------------------------------;
; This example does not use 0x809800 and 0x809801 since the           ;
; bootloader uses these locations for mini call stack space during    ;
; the boot process.  By avoiding these locations this file can be     ;
; either loaded or bootloaded.	For this app this is unlikely to be   ;
; a problem, but is included as a reminder.			      ;
;---------------------------------------------------------------------;
        .start "CODE",0x809802 ; Start assembling CODE section here
        .sect  "CODE"          ;
        .entry  SAMPLE         ; Debugger entry point
        ;----------------------
SAMPLE  ldp     @stack         ; Load a data page
        ldi     @stack,SP      ; Load a stack pointer
OUTER	ldf	3.00,R0        ; Load value to send to function
	call	SQRT	       ; Call function
	ldf	3.00,R0        ;
	call	INVF	       ;
	ldf	3.00,R0        ;
	call	FLOG2	       ;
	ldf	3.00,R0        ;
	call	LOG2	       ;
        b       OUTER          ; Do it again!
******************************************************************************
* R0=SQRT(R0)
*   Calculates the square root of the value of R0 and
*   returns the result in R0.
******************************************************************************
SQRT:	cmpf	0.0,R0	      ;
	ldflt	-1,R0	      ; if x<0 return -1 (error)
	ldfeq	0.0,R0	      ; if x == 0, return 0
	retsle		      ; return if X<=0
     ;	pushf	R1	      ; R1,R2 used for temps
     ;	pushf	R2	      ;
	ldf	R0,R1	      ;
	lsh	1,R1	      ; concatenate mantissa field to exponent
	pushf	R1	      ; Access R0's bit fields as integers
	pop	R1	      ;
	not	R1,R1	      ; invert bits, equivelent to log inverse
	ash	-1,R1	      ; quick square root
	push	R1	      ; put back as float
	popf	R1	      ;
	lsh	-1,R1	      ; restore a sign bit
	mpyf	0.5,R0	      ;
	;----------------------------------------------
	; Now iterate Newton Raphson reduction 5 times
	;----------------------------------------------
	ldi	4,RC	      ; Set up a block repeat (expand for speed!)
	rptb	NR_SQRT       ;
	;---------------------
	mpyf3	R1,R1,R2      ; R0 = x[0] * (v/2)
	mpyf	R0,R2	      ; R0 = (v/2) * x[0] * x[0]
	subrf	1.5,R2	      ; R0 = 1.5 - (v/2) * x[0] * x[0]
NR_SQRT mpyf	R2,R1	      ; x[1] = x[0] * (1.5 - v/2 * x[0] * x[0])
	;---------------------
	rnd	R1,R1
	mpyf	R1,R0	      ; sqrt(x) = x * sqrt(1/x)
	mpyf	2.0,R0
     ;	popf	R2	      ; restore temps if used
     ;	popf	R1	      ;
	RETS
******************************************************************************
* R0=INVF(R0)
*   Calculates the inverse float of the value of R0 and
*   returns the result in R0.
******************************************************************************
MASK	.word	0xFF7FFFFF    ; Mask for fast inverse float
INVF: ; pushf	R1	      ; R1,R2 used for temps
      ; pushf	R2	      ;
	ldf	R0,R1	      ;
	pushf	R1	      ; Access R0's bit fields as integers
	pop	R1	      ;
	xor	@MASK,R1      ; invert bits. except sign, eq to log inverse
	push	R1	      ; put back as float
	popf	R1	      ;
	;----------------------------------------------
	; Now iterate Newton Raphson reduction 5 times
	;----------------------------------------------
	ldi	4,RC	      ; Set up a block repeat (expand for speed!)
	rptb	NR_INV	      ;
	;---------------------
	mpyf3	R1,R0,R2      ; R0 = v * x[0]
	subrf	2.0,R2	      ; R0 = 2.0 - v * x[0]
NR_INV	mpyf	R2,R1	      ; R2 = x[1] = x[0] * (2.0 - v * x[0])
	;---------------------
	ldf	R1,R0
	rets
;----------------------------------------
; LOG2() FUNCTION USING DNP#22 METHOD
;----------------------------------------
LOG2:	cmpf	0.0,R0	       ; Exit if value is <= Zero
	ldfle	-1,R0	       ; if x<=0 return -1 (error)
	retsle		       ; return if X<=0
	;----------------------
	ldi	2,RC	       ; Set up block repeat
	rptb	LOG2B	       ;
	;----------------------
	pushf	R0	       ; save all bits
	lde	1.0,R0	       ; Set exp bits to zero leaving only mantissa
	mpyf	R0,R0	       ; M^2
	mpyf	R0,R0	       ; M^4
	mpyf	R0,R0	       ; M^8
	mpyf	R0,R0	       ; M^16
	mpyf	R0,R0	       ; M^32
	mpyf	R0,R0	       ; M^64
LOG2B	mpyf	R0,R0	       ; M^128	(M^256 not allowed... overflow)
	pushf	R0
	;--------------------------------
	; Now reconstruct all bits...
	;--------------------------------
	pop	R0
	lsh	-21,R0	       ;
	and	@MSK4,R0       ;
	pop	R1	       ;
	lsh	-14,R1	       ;
	and	@MSK3,R1       ;
	or	R1,R0	       ;
	pop	R1	       ;
	lsh	-7,R1	       ;
	and	@MSK2,R1       ;
	or	R1,R0	       ;
	pop	R1	       ; Original value
	and	@MSK1,R1       ;
	or	R1,R0	       ;
	;----------------------
	float	R0,R0	       ;
	mpyf	@FLOG2SC,R0    ; Mpy by scale factor
	;----------------------
	rets
MSK1   .word	0xFF000000
MSK2   .word	0x00FE0000
MSK3   .word	0x0001FC00
MSK4   .word	0x000003FF
;----------------------------------------
; FLOG2() Ultra Fast LOG2 FUNCTION
;----------------------------------------
FLOG2:	cmpf	0.0,R0	       ; Exit if value is <= Zero
	ldfle	-1,R0	       ; if x<=0 return -1 (error)
	retsle		       ; return if X<=0
	lsh	1,R0	       ; Concatenate mantissa to exponent
	pushf	R0	       ; Convert 'fast log' to int, then float
	pop	R0	       ; At this point result is 2^24 to large
	float	R0,R0	       ;
	mpyf	@FLOG2SC,R0    ; Mpy by scale factor
	rets		       ;
FLOG2SC .float	pow(2.0,-24.0) ; Scale factor for properly scaled answer
;------------------------------
stack	.word	0x809C00       ; Begin stack in second RAM block for speed
        .end

