;--------------------------------------------------------------------- ; 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