gps/GPSResources/tcpmp/common/fixed.h

193 lines
5.7 KiB
C
Executable File

/*****************************************************************************
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: fixed.h 271 2005-08-09 08:31:35Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#ifndef __FIXED_H
#define __FIXED_H
// general fixed point range (-16..16)
#define FIX_FRACBITS 27
// additional fast acc output range limitation (-2..2)
#define ACCFAST_ADJ 3
// additional fast mul b range limitation (-16..16)
#define FIXFAST_ADJ 0
// very bad approx when there is no support for fix_mul (32x32=64)
#define FIX_MUL_ADJ 3
#ifdef FIXED_POINT
// fixed point
#define FIX_SHIFT_A (FIX_FRACBITS-FIX_FRACBITS/2)
#define FIX_SHIFT_B (FIX_FRACBITS/2)
typedef int32_t fix_t;
typedef fix_t fixint_t;
#define FIXC(v) ((fix_t)((v)*(1<<FIX_FRACBITS)+((v)>=0?0.5:-0.5)))
#define FIXI(v) (v)
#if FIX_FRACBITS<28
#define FIX28(v) RSHIFT_ROUND(v,28-FIX_FRACBITS)
#else
#define FIX28(v) (v)
#endif
#define ACCFAST_ASHIFT(a,n) RSHIFT_ROUND(a,FIX_SHIFT_A-ACCFAST_ADJ+(n))
#define ACCFAST_BSHIFT(b) RSHIFT_ROUND(b,FIX_SHIFT_B)
#define accfast_var(name) int32_t name
#define accfast_mul(name,a,b) (name) = (a)*(b)
#define accfast_mla(name,a,b) (name) += (a)*(b)
#define accfast_neg(name) (name) = -(name)
#define accfast_get(name,n) ((fix_t)((name)>>(ACCFAST_ADJ-(n))))
#if defined(_MSC_VER) && defined(MIPS)
#define FIXFAST_BSHIFT(b) ((b)<<FIXFAST_ADJ)
#define fixfast_mul(a,b) ((fix_t)(__emul(a,b)>>32) << (32-FIXFAST_ADJ-FIX_FRACBITS))
#define fix_mul(a,b) ((fix_t)(__emul(a,b)>>FIX_FRACBITS))
#define fix_mul64(a,b) ((fix_t)(__emul(a,b)>>FIX_FRACBITS))
#endif
#if defined(_MSC_VER) && defined(_M_IX86)
#if 0
// emulate ARM (just for testing)
#define acc_var(name) int64_t name
#define acc_mul(name,a,b) (name) = (int64_t)(a)*(int64_t)(b)
#define acc_mla(name,a,b) (name) += (int64_t)(a)*(int64_t)(b)
#define acc_neg(name) (name) = -(name);
#define acc_get(name) ((fix_t)((name) >> FIX_FRACBITS))
#define FIXFAST_BSHIFT(b) ((b)<<FIXFAST_ADJ)
#define fixfast_mul(a,b) ((fix_t)((((int64_t)(a)*(int64_t)(b)) >> 32) << (32-FIXFAST_ADJ-FIX_FRACBITS)))
#endif
#define fix_mul(a,b) _fix_mul(a,b)
#define fix_mul64(a,b) _fix_mul(a,b)
static INLINE fix_t _fix_mul(fix_t a,fix_t b)
{
__asm
{
mov eax,a
imul b
shrd eax, edx, FIX_FRACBITS
}
}
#endif
#if defined(__GNUC__) && defined(ARM)
#define acc_lo(name) lo##name
#define acc_hi(name) hi##name
#define acc_var(name) int32_t acc_lo(name),acc_hi(name)
#define acc_mul(name,a,b) asm( "smull %0, %1, %2, %3" : "=&r" (acc_lo(name)), "=&r" (acc_hi(name)) : "%r" (a), "r" (b))
#define acc_mla(name,a,b) asm( "smlal %0, %1, %2, %3" : "+r" (acc_lo(name)), "+r" (acc_hi(name)) : "%r" (a), "r" (b))
#define acc_neg(name) asm ("rsbs %0, %2, #0;\n" \
"rsc %1, %3, #0" : "=r" (acc_lo(name)), "=r" (acc_hi(name)) : "r" (acc_lo(name)), "r" (acc_hi(name)) : "cc")
#define acc_get(name) ((fix_t)(((uint32_t)(acc_lo(name)) >> FIX_FRACBITS)|((acc_hi(name)) << (32-FIX_FRACBITS))))
#endif
#if defined(acc_hi)
#ifndef fixfast_mul
#define FIXFAST_BSHIFT(b) ((b)<<FIXFAST_ADJ)
#define fixfast_mul(a,b) ({ acc_var(_tmp); acc_mul(_tmp,(a),(b)); acc_hi(_tmp) << (32-FIXFAST_ADJ-FIX_FRACBITS); })
#endif
#ifndef fix_mul
#define fix_mul(a,b) ({ acc_var(_tmp); acc_mul(_tmp,(a),(b)); acc_get(_tmp); })
#endif
#ifndef fix_mul64
#define fix_mul64(a,b) ({ acc_var(_tmp); acc_mul(_tmp,(a),(b)); acc_get(_tmp); })
#endif
#else
#ifndef fixfast_mul
#ifdef fix_mul
#define FIXFAST_BSHIFT(b) (b)
#define fixfast_mul(a,b) fix_mul(a,b)
#else
#define FIXFAST_BSHIFT(b) RSHIFT_ROUND(b,FIX_SHIFT_B+FIX_MUL_ADJ)
#define fixfast_mul(a,b) (((a)>>(FIX_SHIFT_A-FIX_MUL_ADJ))*(b))
#endif
#endif
#ifndef fix_mul
#define fix_mul(a,b) (((a)>>(FIX_SHIFT_A-FIX_MUL_ADJ))*((b)>>(FIX_SHIFT_B+FIX_MUL_ADJ)))
#endif
#ifndef fix_mul64
#define fix_mul64(a,b) ((fix_t)(((int64_t)(a)*(int64_t)(b))>>FIX_FRACBITS))
#endif
#endif
#ifndef fix_1div
#define fix_1div(a) ((fix_t)((((int64_t)1)<<(FIX_FRACBITS*2))/(a)))
#endif
#define checkfix(a) assert((a)>-0x60000000 && (a)<0x60000000);
#else
// floating point
typedef float fix_t;
typedef int32_t fixint_t; // have to be same size as fix_t
typedef float acclo_t;
typedef int acchi_t;
#define FIXC(v) ((fix_t)(v))
#define FIXI(v) ((int32_t)((v)*(1<<FIX_FRACBITS)))
#define FIX28(v) ((fix_t)(v)/(1<<28))
#define fix_mul(a,b) ((a)*(b))
#define fix_1div(a) (1.0f/(a))
#define ACCFAST_ASHIFT(a,n) (a)
#define ACCFAST_BSHIFT(b) (b)
#define accfast_var(name) acc_var(name)
#define accfast_mul(name,a,b) acc_mul(name,a,b)
#define accfast_mla(name,a,b) acc_mla(name,a,b)
#define accfast_neg(name) acc_neg(name)
#define accfast_get(name,n) acc_get(name)
#define FIXFAST_BSHIFT(b) (b)
#define fixfast_mul(a,b) fix_mul(a,b)
#define checkfix(a)
#endif
#ifndef acc_mul
#define acc_var(name) fix_t name
#define acc_mul(name,a,b) name = fix_mul(a,b)
#define acc_mla(name,a,b) name += fix_mul(a,b)
#define acc_neg(name) name = -name
#define acc_get(name) name
#endif
#endif