Hi Michal, On Mon, 2008-05-05 at 16:22 +0200, Michal Simek wrote: > Hi John, > > you wrote me you have smarter implementation that xilinx did. Can you find it > and send me it? It's not much (any?) better? One less multiply I think? Attached anyway - feel free to discard for now. We could do a nice asm implementation with the optional mulhi instruction, but that can wait. Cheers, John
diff --git a/include/asm-microblaze/delay.h b/include/asm-microblaze/delay.h index 481359c..e29a4de 100644 --- a/include/asm-microblaze/delay.h +++ b/include/asm-microblaze/delay.h @@ -2,32 +2,72 @@ * include/asm-microblaze/delay.h * * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive + * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2006 Atmark Techno, Inc. */ -#ifndef _ASM_MICROBLAZE_DELAY_H -#define _ASM_MICROBLAZE_DELAY_H +#ifndef _ASM_DELAY_H +#define _ASM_DELAY_H -#include <asm/param.h> +#include <asm/param.h> /* For HZ */ -static inline void __delay(unsigned long loops) +extern inline void __delay(unsigned long loops) { asm volatile ("# __delay \n\t" \ - "1: addi %0, %0, -1 \t\n" \ - "bneid %0, 1b \t\n" \ - "nop \t\n" - : "=r" (loops) - : "0" (loops)); + "1: addi %0, %0, -1 \t\n" \ + "bneid %0, 1b \t\n" \ + "nop \t\n" + : "=r" (loops) + : "0" (loops)); } -static inline void udelay(unsigned long usec) +/* + * Note that 19 * 226 == 4294 ==~ 2^32 / 10^6, so + * loops = (4294 * usecs * loops_per_jiffy * HZ) / 2^32. + * + * The mul instruction gives us loops = (a * b) / 2^32. + * We choose a = usecs * 19 * HZ and b = loops_per_jiffy * 226 + * because this lets us support a wide range of HZ and + * loops_per_jiffy values without either a or b overflowing 2^32. + * Thus we need usecs * HZ <= (2^32 - 1) / 19 = 226050910 and + * loops_per_jiffy <= (2^32 - 1) / 226 = 19004280 + * (which corresponds to ~3800 bogomips at HZ = 100). + * -- paulus + */ +#define __MAX_UDELAY (226050910UL/HZ) /* maximum udelay argument */ +#define __MAX_NDELAY (4294967295UL/HZ) /* maximum ndelay argument */ + +extern unsigned long loops_per_jiffy; + +extern __inline__ void __udelay(unsigned int x) { - unsigned long long tmp = usec; - unsigned long loops = (tmp * 4295 * HZ * loops_per_jiffy) >> 32; + unsigned long long tmp=(unsigned long long)x*(unsigned long long)loops_per_jiffy*226LL; + unsigned loops=tmp>>32; + __delay(loops); } -#endif /* _ASM_MICROBLAZE_DELAY_H */ +extern __inline__ void __ndelay(unsigned int x) +{ + unsigned long long tmp=(unsigned long long)x*(unsigned long long)loops_per_jiffy*226LL; + unsigned loops=tmp>>32; + + __delay(loops); +} + +extern void __bad_udelay(void); /* deliberately undefined */ +extern void __bad_ndelay(void); /* deliberately undefined */ + +#define udelay(n) (__builtin_constant_p(n)? \ + ((n) > __MAX_UDELAY? __bad_udelay(): __udelay((n) * (19 * HZ))) : \ + __udelay((n) * (19 * HZ))) + +#define ndelay(n) (__builtin_constant_p(n)? \ + ((n) > __MAX_NDELAY? __bad_ndelay(): __ndelay((n) * HZ)) : \ + __ndelay((n) * HZ)) + +#define muldiv(a, b, c) (((a)*(b))/(c)) + +#endif /* _ASM_DELAY_H */