$NetBSD: patch-aj,v 1.2 2002/06/23 08:45:09 kent Exp $ --- mpg123.h.orig Fri May 28 23:51:58 1999 +++ mpg123.h @@ -56,8 +56,115 @@ # define real float #elif defined(REAL_IS_LONG_DOUBLE) # define real long double +#elif defined(REAL_IS_FIXED) +# define real long + +# define REAL_RADIX 15 +# define REAL_FACTOR (32.0 * 1024.0) + +# define REAL_PLUS_32767 ( 32767 << REAL_RADIX ) +# define REAL_MINUS_32768 ( -32768 << REAL_RADIX ) + +# define DOUBLE_TO_REAL(x) ((int)((x) * REAL_FACTOR)) +# define REAL_TO_SHORT(x) ((x) >> REAL_RADIX) +# define REAL_MUL(x, y) (((long long)(x) * (long long)(y)) >> REAL_RADIX) + +#elif defined(REAL_IS_FIXED_ARMV4) +# define REAL_IS_FIXED +# define real long long + +# define REAL_RADIX 32 +# define REAL_FACTOR (4294967296.0) + +# define REAL_PLUS_32767 ( 32767LL << REAL_RADIX ) +# define REAL_MINUS_32768 ( -32768LL << REAL_RADIX ) + +# define DOUBLE_TO_REAL(x) ((long long)((x) * REAL_FACTOR)) +# define REAL_TO_SHORT(x) ((x) >> REAL_RADIX) + +/* + * "Reals" are signed, 15 bits before the point, 32 bits after. + * Multiplication is done like so: + * + * if |x| < 2^8, shift x >> 7, else shift x >>15 + * if |y| < 2^8, shift y >> 7, else shift y >>15 + * multiply x * y (just avoids clipping MSB) + * shift the result >> 2, 10 or 18 bits, to make a total shift of 32 bits + * + * I'd do it in C, but gcc optimises it rather poorly (2K stack + * frames, anyone?). Hence the bit of (ARMv4) asm magic below. + * (Unfortunately, the CLZ opcode, which would make for a much neater + * solution to this, doesn't appear until ARMv5) + * + * (tjd April 2002) + */ + +# define REAL_MUL(x, y) real_mul((x),(y)) + +static __inline__ long long real_mul(long long x, long long y) { + const register long long _x asm("r0") = (x); + const register long long _y asm("r2") = (y); + register long long rv asm("r0"); + __asm__ __volatile__ ( +"@ we'll need to shift the result at least >> 2\n" +" mov r4, #2\n" +"@ both args >> 7,\n" +" mov r0, r0, lsr #7\n" +" mov r2, r2, lsr #7\n" +" orr r0, r0, r1, lsl #25\n" +" orr r2, r2, r3, lsl #25\n" +" mov r1, r1, asr #7\n" +" mov r3, r3, asr #7\n" +"@ check if x needs further shiftage\n" +" cmp r1, #0\n" +" cmnne r1, #1\n" +" addeq r4, r4, #8\n" +"@ shift x if needed\n" +" movne r0, r0, lsr #8\n" +" orrne r0, r0, r1, lsl #24\n" +" movne r1, r1, asr #8\n" +"@ check if y needs further shiftage\n" +" cmp r3, #0\n" +" cmnne r3, #1\n" +" addeq r4, r4, #8\n" +"@ shift y if needed\n" +" movne r2, r2, lsr #8\n" +" orrne r2, r2, r3, lsl #24\n" +" movne r3, r3, asr #8\n" +"@ multiply (ignoring overflow)\n" +" mul r3, r0, r3\n" +" mla r3, r1, r2, r3\n" +" umull r0, r1, r2, r0\n" +" add r1, r1, r3\n" +"@ shift the result the appropriate amount\n" +" rsb r3, r4, #32\n" +" mov r0, r0, lsr r4\n" +" orr r0, r0, r1, lsl r3\n" +" mov r1, r1, asr r4\n" + : "=r" (rv) + : "0" (_x), "r" (_y) + : "r1", "r3", "r4", "cc"); + return rv; +} + #else # define real double +#endif + +#ifndef DOUBLE_TO_REAL +# define DOUBLE_TO_REAL(x) (x) +#endif +#ifndef REAL_TO_SHORT +# define REAL_TO_SHORT(x) (x) +#endif +#ifndef REAL_PLUS_32767 +# define REAL_PLUS_32767 32767.0 +#endif +#ifndef REAL_MINUS_32768 +# define REAL_MINUS_32768 -32768.0 +#endif +#ifndef REAL_MUL +# define REAL_MUL(x, y) ((x) * (y)) #endif #ifdef __GNUC__