Initial import
[avr_bc100.git] / BaseTinyFirmware / GCC / delay_x_gcc.h
1 /*
2    Copyright (c) 2005, Hans-Juergen Heinrichs
3    All rights reserved.
4
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions are met:
7
8    * Redistributions of source code must retain the above copyright
9      notice, this list of conditions and the following disclaimer.
10
11    * Redistributions in binary form must reproduce the above copyright
12      notice, this list of conditions and the following disclaimer in
13      the documentation and/or other materials provided with the
14      distribution.
15
16    * Neither the name of the copyright holders nor the names of
17      contributors may be used to endorse or promote products derived
18      from this software without specific prior written permission.
19
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   POSSIBILITY OF SUCH DAMAGE.
31 */
32
33
34 /*
35  *  delay_x.h
36  *
37  *  Accurate delays ranging from a single CPU cycle up to
38  *  more than 500 second (e.g. with 8MHz device):
39  *
40  *  The idea for the functions below was heavily inspired by the
41  *  file <avr/delay.h> which is part of the excellent WinAVR
42  *  distribution. Therefore, thanks to Marek Michalkiewicz and
43  *  Joerg Wunsch.
44  *
45  *  The idea is to have the GCC preprocessor handle all calculations
46  *  necessary for determining the exact implementation of a delay
47  *  algorithm. The implementation itself is then inlined into the
48  *  user code.
49  *  In this way it is possible to always get the code size optimized
50  *  delay implementation.
51  *
52  */
53
54 #ifndef _AVR_DELAY_X_H_
55 #define _AVR_DELAY_X_H_ 1
56
57 #include <stdint.h>
58
59 #ifndef F_CPU
60 # warning "Macro F_CPU must be defined"
61 #endif
62
63 /*
64  * Forward declaration for all functions with attribute
65  * 'always_inline' enforces GCC to inline the code (even
66  * if it would be better not to do so from optimization
67  * perspective).
68  * Without this attribute GCC is free to implement
69  * inline code or not (using the keyword 'inline'
70  * alone is not sufficient).
71  *
72  */
73 static __inline__ void _NOP1( void) __attribute__((always_inline));
74 static __inline__ void _NOP2( void) __attribute__((always_inline));
75 static __inline__ void _NOP3( void) __attribute__((always_inline));
76 static __inline__ void _NOP4( void) __attribute__((always_inline));
77 static __inline__ void _NOP5( void) __attribute__((always_inline));
78 static __inline__ void _NOP6( void) __attribute__((always_inline));
79 static __inline__ void _NOP7( void) __attribute__((always_inline));
80 static __inline__ void _NOP8( void) __attribute__((always_inline));
81 static __inline__ void _NOP9( void) __attribute__((always_inline));
82 static __inline__ void _NOP10(void) __attribute__((always_inline));
83 static __inline__ void _NOP11(void) __attribute__((always_inline));
84 static __inline__ void _NOP12(void) __attribute__((always_inline));
85
86 static __inline__ void _delay_loop_3(  uint32_t) __attribute__((always_inline));
87 static __inline__ void _delay_loop_1_x( uint8_t) __attribute__((always_inline));
88 static __inline__ void _delay_loop_2_x(uint16_t) __attribute__((always_inline));
89 static __inline__ void _delay_loop_3_x(uint32_t) __attribute__((always_inline));
90
91 static __inline__ void _delay_cycles(const double) __attribute__((always_inline));
92
93
94 /*
95  * _ N O P x ( void )
96  *
97  * Code sized optimized NOPs - not using any registers
98  *
99  * These NOPs will be used for very short delays where
100  * it is more code efficient than executing loops.
101  *
102  */
103 static __inline__ void _NOP1 (void) { __asm__ volatile ( "nop    " "\n\t" ); }
104 static __inline__ void _NOP2 (void) { __asm__ volatile ( "rjmp 1f" "\n\t"  "1:" "\n\t" ); }
105 static __inline__ void _NOP3 (void) { __asm__ volatile ( "lpm    " "\n\t" ); }
106 static __inline__ void _NOP4 (void) { _NOP3(); _NOP1(); }
107 static __inline__ void _NOP5 (void) { _NOP3(); _NOP2(); }
108 static __inline__ void _NOP6 (void) { _NOP3(); _NOP3(); }
109 static __inline__ void _NOP7 (void) { _NOP3(); _NOP3(); _NOP1(); }
110 static __inline__ void _NOP8 (void) { _NOP3(); _NOP3(); _NOP2(); }
111 static __inline__ void _NOP9 (void) { _NOP3(); _NOP3(); _NOP3(); }
112 static __inline__ void _NOP10(void) { _NOP3(); _NOP3(); _NOP3(); _NOP1(); }
113 static __inline__ void _NOP11(void) { _NOP3(); _NOP3(); _NOP3(); _NOP2(); }
114 static __inline__ void _NOP12(void) { _NOP3(); _NOP3(); _NOP3(); _NOP3(); }
115
116
117
118 /*
119  *  _ d e l a y _ l o o p _ 3( uint32_t __count )
120  *
121  * This delay loop is not used in the code below: It is
122  * a supplement to the _delay_loop_1() and _delay_loop_2()
123  * within standard WinAVR <arv/delay.h> giving a wider
124  * (32 bit) delay range.
125  *
126  */
127 static __inline__ void
128 _delay_loop_3( uint32_t __count )
129 {
130     __asm__ volatile (
131         "1: sbiw %A0,1" "\n\t"
132         "sbc %C0,__zero_reg__" "\n\t"
133         "sbc %D0,__zero_reg__" "\n\t"
134         "brne 1b"
135         : "=w" (__count)
136         : "0" (__count)
137     );
138 }
139
140
141 /*
142  *  _ d e l a y _ l o o p _ 1 _ x( uint8_t __count )
143  *  _ d e l a y _ l o o p _ 2 _ x( uint16_t  __count )
144  *  _ d e l a y _ l o o p _ 4 _ x( uint32_t __count )
145  *
146  *  These delay loops always have exactly 4(8) cycles per loop.
147  *  They use a 8/16/32 bit register counter respectively.
148  *
149  */
150 static __inline__ void      /* exactly 4 cycles/loop, max 2**8 loops */
151 _delay_loop_1_x( uint8_t __n )
152 {                                               /* cycles per loop      */
153     __asm__ volatile (                          /* __n..one        zero */
154         "1: dec  %0"   "\n\t"                   /*    1             1   */
155         "   breq 2f"   "\n\t"                   /*    1             2   */
156         "2: brne 1b"   "\n\t"                   /*    2             1   */
157         : "=r" (__n)                            /*  -----         ----- */
158         : "0" (__n)                             /*    4             4   */
159     );
160 }
161
162 static __inline__ void      /* exactly 4 cycles/loop, max 2**16 loops */
163 _delay_loop_2_x( uint16_t __n )
164 {                                               /* cycles per loop      */
165     __asm__ volatile (                          /* __n..one        zero */
166         "1: sbiw %0,1"   "\n\t"                 /*    2             2   */
167         "   brne 1b  "   "\n\t"                 /*    2             1   */
168         "   nop      "   "\n\t"                 /*                  1   */
169         : "=w" (__n)                            /*  -----         ----- */
170         : "0" (__n)                             /*    4             4   */
171     );
172 }
173
174 static __inline__ void      /* exactly 8 cycles/loop, max 2**32 loops */
175 _delay_loop_3_x( uint32_t __n )
176 {                                               /* cycles per loop      */
177     __asm__ volatile (                          /* __n..one        zero */
178         "1: sbiw %A0,1           "  "\n\t"      /*    2             2   */
179         "   sbc  %C0,__zero_reg__"  "\n\t"      /*    1             1   */
180         "   sbc  %D0,__zero_reg__"  "\n\t"      /*    1             1   */
181         "   nop                  "  "\n\t"      /*    1             1   */
182         "   breq 2f              "  "\n\t"      /*    1             2   */
183         "2: brne 1b              "  "\n\t"      /*    2             1   */
184         : "=w" (__n)                            /*  -----         ----- */
185         : "0" (__n)                             /*    8             8   */
186     );
187 }
188
189
190 /*
191  *
192  *  _ d e l a y _ c y c l e s (double __ticks_d)
193  *
194  *  Perform an accurate delay of a given number of processor cycles.
195  *
196  *  All the floating point arithmetic will be handled by the
197  *  GCC Preprocessor and no floating point code will be generated.
198  *  Allthough the parameter __ticks_d is of type 'double' this
199  *  function can be called with any constant integer value, too.
200  *  GCC will handle the casting appropriately.
201  *
202  *  With an 8 MHz clock e.g., delays ranging from 125 nanoseconds
203  *  up to (2**32-1) * 125ns ~= 536,87 seconds are feasible.
204  *
205  */
206 static __inline__ void
207 _delay_cycles(const double __ticks_d)
208 {
209     uint32_t __ticks = (uint32_t)(__ticks_d);
210     uint32_t __padding;
211     uint32_t __loops;
212
213     /*
214      * Special optimization for very
215      * small delays - not using any register.
216      */
217     if( __ticks <= 12 )  {              /* this can be done with 4 opcodes      */
218         __padding = __ticks;
219
220     /* create a single byte counter */
221     } else if( __ticks <= 0x400 )  {
222         __ticks -= 1;                   /* caller needs 1 cycle to init counter */
223         __loops = __ticks / 4;
224         __padding = __ticks % 4;
225         if( __loops != 0 )
226             _delay_loop_1_x( (uint8_t)__loops );
227
228     /* create a two byte counter */
229     } else if( __ticks <= 0x40001 )  {
230         __ticks -= 2;                   /* caller needs 2 cycles to init counter */
231         __loops = __ticks / 4;
232         __padding = __ticks % 4;
233         if( __loops != 0 )
234             _delay_loop_2_x( (uint16_t)__loops );
235
236     /* create a four byte counter */
237     } else  {
238         __ticks -= 4;                   /* caller needs 4 cycles to init counter */
239         __loops = __ticks / 8;
240         __padding = __ticks % 8;
241         if( __loops != 0 )
242             _delay_loop_3_x( (uint32_t)__loops );
243     }
244
245     if( __padding ==  1 )  _NOP1();
246     if( __padding ==  2 )  _NOP2();
247     if( __padding ==  3 )  _NOP3();
248     if( __padding ==  4 )  _NOP4();
249     if( __padding ==  5 )  _NOP5();
250     if( __padding ==  6 )  _NOP6();
251     if( __padding ==  7 )  _NOP7();
252     if( __padding ==  8 )  _NOP8();
253     if( __padding ==  9 )  _NOP9();
254     if( __padding == 10 ) _NOP10();
255     if( __padding == 11 ) _NOP11();
256     if( __padding == 12 ) _NOP12();
257 }
258
259
260 /*
261  *
262  *   _ d e l a y _ n s (double __ns)
263  *   _ d e l a y _ u s (double __us)
264  *   _ d e l a y _ m s (double __ms)
265  *   _ d e l a y _ s   (double __s)
266  *
267  *   Perform a very exact delay with a resolution as accurate as a
268  *   single CPU clock (the macro F_CPU is supposed to be defined to a
269  *   constant defining the CPU clock frequency in Hertz).
270  *
271  */
272 #define _delay_ns(__ns)     _delay_cycles( (double)(F_CPU)*((double)__ns)/1.0e9 + 0.5 )
273 #define _delay_us(__us)     _delay_cycles( (double)(F_CPU)*((double)__us)/1.0e6 + 0.5 )
274 #define _delay_ms(__ms)     _delay_cycles( (double)(F_CPU)*((double)__ms)/1.0e3 + 0.5 )
275 #define _delay_s(  __s)     _delay_cycles( (double)(F_CPU)*((double)__s )/1.0e0 + 0.5 )
276
277 #endif /* _AVR_DELAY_X_H_ */