Convert to new Doxygen style.
[bertos.git] / cfg / cpu.h
1 /**
2  * \file
3  * <!--
4  * Copyright 2004, 2005 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 2004 Giovanni Bajo
6  * This file is part of DevLib - See README.devlib for information.
7  * -->
8  *
9  * \brief CPU-specific definitions
10  *
11  * \version $Id$
12  *
13  * \author Giovanni Bajo <rasky@develer.com>
14  * \author Bernardo Innocenti <bernie@develer.com>
15  * \author Stefano Fedrigo <aleph@develer.com>
16  */
17
18 /*#*
19  *#* $Log$
20  *#* Revision 1.15  2006/07/19 12:56:25  bernie
21  *#* Convert to new Doxygen style.
22  *#*
23  *#* Revision 1.14  2006/07/19 12:54:12  bernie
24  *#* Documentation fixes.
25  *#*
26  *#* Revision 1.13  2006/03/27 04:49:23  bernie
27  *#* CPU_IDLE(): Fix for new emulator.
28  *#*
29  *#* Revision 1.12  2006/03/21 10:52:39  bernie
30  *#* Update ARM support.
31  *#*
32  *#* Revision 1.11  2006/03/20 17:49:00  bernie
33  *#* Spacing fix.
34  *#*
35  *#* Revision 1.10  2006/02/24 01:17:30  bernie
36  *#* CPU_SAVED_REGS_CNT: Declare for x86/x86_64.
37  *#*
38  *#* Revision 1.9  2006/02/23 09:08:43  bernie
39  *#* Add note for a frequently reported non-bug.
40  *#*
41  *#* Revision 1.8  2006/02/10 12:37:45  bernie
42  *#* Add support for ARM on IAR.
43  *#*
44  *#* Revision 1.7  2005/11/27 03:04:38  bernie
45  *#* Add POSIX emulation for IRQ_* macros; Add Qt support.
46  *#*
47  *#* Revision 1.6  2005/07/19 07:26:49  bernie
48  *#* Add missing #endif.
49  *#*
50  *#* Revision 1.5  2005/06/27 21:24:17  bernie
51  *#* CPU_CSOURCE(): New macro.
52  *#*
53  *#* Revision 1.4  2005/06/14 06:15:10  bernie
54  *#* Add X86_64 support.
55  *#*
56  *#* Revision 1.3  2005/04/12 04:06:17  bernie
57  *#* Catch missing CPU earlier.
58  *#*
59  *#* Revision 1.2  2005/04/11 19:10:27  bernie
60  *#* Include top-level headers from cfg/ subdir.
61  *#*
62  *#* Revision 1.1  2005/04/11 19:04:13  bernie
63  *#* Move top-level headers to cfg/ subdir.
64  *#*
65  *#* Revision 1.30  2005/03/15 00:20:09  bernie
66  *#* BREAKPOINT, IRQ_RUNNING(), IRQ_GETSTATE(): New DSP56K macros.
67  *#*
68  *#* Revision 1.29  2005/02/16 20:33:24  bernie
69  *#* Preliminary PPC support.
70  *#*
71  *#* Revision 1.28  2004/12/31 17:39:41  bernie
72  *#* Fix documentation.
73  *#*
74  *#* Revision 1.27  2004/12/31 17:02:47  bernie
75  *#* IRQ_SAVE_DISABLE(), IRQ_RESTORE(): Add null stubs for x86.
76  *#*
77  *#* Revision 1.26  2004/12/13 12:08:12  bernie
78  *#* DISABLE_IRQSAVE, ENABLE_IRQRESTORE, DISABLE_INTS, ENABLE_INTS: Remove obsolete macros.
79  *#*
80  *#* Revision 1.25  2004/12/08 08:31:02  bernie
81  *#* CPU_HARVARD: Define to 1 for AVR and DSP56K.
82  *#*/
83 #ifndef DEVLIB_CPU_H
84 #define DEVLIB_CPU_H
85
86 #include <cfg/compiler.h> /* for uintXX_t */
87 #include <cfg/arch_config.h>  /* ARCH_EMUL */
88
89
90 /**
91  * \name Macros for determining CPU endianness.
92  * \{
93  */
94 #define CPU_BIG_ENDIAN    0x1234
95 #define CPU_LITTLE_ENDIAN 0x3412 /* Look twice, pal. This is not a bug. */
96 /*\}*/
97
98 /** Macro to include cpu-specific versions of the headers. */
99 #define CPU_HEADER(module)          PP_STRINGIZE(PP_CAT3(module, _, CPU_ID).h)
100
101 /** Macro to include cpu-specific versions of implementation files. */
102 #define CPU_CSOURCE(module)         PP_STRINGIZE(PP_CAT3(module, _, CPU_ID).c)
103
104
105 #if CPU_I196
106
107         #define NOP                     nop_instruction()
108         #define IRQ_DISABLE             disable_interrupt()
109         #define IRQ_ENABLE              enable_interrupt()
110
111         typedef uint16_t cpuflags_t; // FIXME
112         typedef unsigned int cpustack_t;
113
114         #define CPU_REG_BITS            16
115         #define CPU_REGS_CNT            16
116         #define CPU_STACK_GROWS_UPWARD  0
117         #define CPU_SP_ON_EMPTY_SLOT    0
118         #define CPU_BYTE_ORDER          CPU_LITTLE_ENDIAN
119         #define CPU_HARVARD             0
120
121 #elif CPU_X86
122
123         #define NOP                     asm volatile ("nop")
124
125         /* Get IRQ_* definitions from the hosting environment. */
126         #include <cfg/os.h>
127         #if OS_EMBEDDED
128                 #define IRQ_DISABLE             FIXME
129                 #define IRQ_ENABLE              FIXME
130                 #define IRQ_SAVE_DISABLE(x)     FIXME
131                 #define IRQ_RESTORE(x)          FIXME
132                 typedef uint32_t cpuflags_t; // FIXME
133         #endif /* OS_EMBEDDED */
134
135
136         #define CPU_REGS_CNT            7
137         #define CPU_SAVED_REGS_CNT      7
138         #define CPU_STACK_GROWS_UPWARD  0
139         #define CPU_SP_ON_EMPTY_SLOT    0
140         #define CPU_BYTE_ORDER          CPU_LITTLE_ENDIAN
141         #define CPU_HARVARD             0
142
143         #if CPU_X86_64
144                 typedef uint64_t cpustack_t;
145                 #define CPU_REG_BITS    64
146
147                 #ifdef __WIN64__
148                         /* WIN64 is an IL32-P64 weirdo. */
149                         #define SIZEOF_LONG  4
150                 #endif
151         #else
152                 typedef uint32_t cpustack_t;
153                 #define CPU_REG_BITS    32
154         #endif
155
156 #elif CPU_ARM
157
158         typedef uint32_t cpuflags_t;
159         typedef uint32_t cpustack_t;
160
161         /* Register counts include SREG too */
162         #define CPU_REG_BITS           32
163         #define CPU_REGS_CNT           16
164         #define CPU_SAVED_REGS_CNT     FIXME
165         #define CPU_STACK_GROWS_UPWARD 0  //FIXME
166         #define CPU_SP_ON_EMPTY_SLOT   0  //FIXME
167         #define CPU_BYTE_ORDER         (__BIG_ENDIAN__ ? CPU_BIG_ENDIAN : CPU_LITTLE_ENDIAN)
168         #define CPU_HARVARD            0
169
170         #ifdef __IAR_SYSTEMS_ICC__
171
172                 #include <inarm.h>
173
174                 #if __CPU_MODE__ == 1 /* Thumb */
175                         /* Use stubs */
176                         extern cpuflags_t get_CPSR(void);
177                         extern void set_CPSR(cpuflags_t flags);
178                 #else
179                         #define get_CPSR __get_CPSR
180                         #define set_CPSR __set_CPSR
181                 #endif
182
183                 #define NOP         __no_operation()
184                 #define IRQ_DISABLE __disable_interrupt()
185                 #define IRQ_ENABLE  __enable_interrupt()
186
187                 #define IRQ_SAVE_DISABLE(x) \
188                 do { \
189                         (x) = get_CPSR(); \
190                         __disable_interrupt(); \
191                 } while (0)
192
193                 #define IRQ_RESTORE(x) \
194                 do { \
195                         set_CPSR(x); \
196                 } while (0)
197
198                 #define IRQ_GETSTATE() \
199                         ((bool)(get_CPSR() & 0xb0))
200
201                 #define BREAKPOINT  /* asm("bkpt 0") DOES NOT WORK */
202
203         #else /* !__IAR_SYSTEMS_ICC__ */
204
205                 #warning "IRQ_ macros need testing!"
206
207                 #define NOP         asm volatile ("mov r0,r0" ::)
208
209                 #define IRQ_DISABLE \
210                 do { \
211                         asm volatile ( \
212                                 "mrs r0, cpsr\n\t" \
213                                 "orr r0, r0, #0xb0\n\t" \
214                                 "msr cpsr, r0" \
215                                 :: \
216                         ); \
217                 } while (0)
218
219                 #define IRQ_ENABLE \
220                 do { \
221                         asm volatile ( \
222                                 "mrs r0, cpsr\n\t" \
223                                 "bic r0, r0, #0xb0\n\t" \
224                                 "msr cpsr, r0" \
225                                 :: \
226                         ); \
227                 } while (0)
228
229                 #define IRQ_SAVE_DISABLE(x) \
230                 do { \
231                         asm volatile ( \
232                                 "mrs r0, cpsr\n\t" \
233                                 "mov %0, r0\n\t" \
234                                 "orr r0, r0, #0xb0\n\t" \
235                                 "msr cpsr, r0" \
236                                 : "=r" (x) \
237                                 : /* no inputs */ \
238                                 : "r0" \
239                         ); \
240                 } while (0)
241
242                 #define IRQ_RESTORE(x) \
243                 do { \
244                         asm volatile ( \
245                                 "mov r0, %0\n\t" \
246                                 "msr cpsr, r0" \
247                                 : /* no outputs */ \
248                                 : "r" (x) \
249                                 : "r0" \
250                         ); \
251                 } while (0)
252
253                 #define IRQ_GETSTATE() \
254                 ({ \
255                         uint32_t sreg; \
256                         asm volatile ( \
257                                 "mrs r0, cpsr\n\t" \
258                                 "mov %0, r0" \
259                                 : "=r" (sreg)
260                                 : /* no inputs */
261                                 : "r0" \
262                         ); \
263                         (bool)(sreg & 0xb0); \
264                 })
265
266         #endif /* __IAR_SYSTEMS_ICC_ */
267
268 #elif CPU_PPC
269         #define NOP                 asm volatile ("nop" ::)
270
271         #define IRQ_DISABLE         FIXME
272         #define IRQ_ENABLE          FIXME
273         #define IRQ_SAVE_DISABLE(x) FIXME
274         #define IRQ_RESTORE(x)      FIXME
275         #define IRQ_GETSTATE()      FIXME
276
277         typedef uint32_t cpuflags_t; // FIXME
278         typedef uint32_t cpustack_t; // FIXME
279
280         /* Register counts include SREG too */
281         #define CPU_REG_BITS           (CPU_PPC32 ? 32 : 64)
282         #define CPU_REGS_CNT           FIXME
283         #define CPU_SAVED_REGS_CNT     FIXME
284         #define CPU_STACK_GROWS_UPWARD 0  //FIXME
285         #define CPU_SP_ON_EMPTY_SLOT   0  //FIXME
286         #define CPU_BYTE_ORDER         (__BIG_ENDIAN__ ? CPU_BIG_ENDIAN : CPU_LITTLE_ENDIAN)
287         #define CPU_HARVARD            0
288
289 #elif CPU_DSP56K
290
291         #define NOP                     asm(nop)
292         #define BREAKPOINT              asm(debug)
293         #define IRQ_DISABLE             do { asm(bfset #0x0200,SR); asm(nop); } while (0)
294         #define IRQ_ENABLE              do { asm(bfclr #0x0200,SR); asm(nop); } while (0)
295
296         #define IRQ_SAVE_DISABLE(x)  \
297                 do { (void)x; asm(move SR,x); asm(bfset #0x0200,SR); } while (0)
298         #define IRQ_RESTORE(x)  \
299                 do { (void)x; asm(move x,SR); } while (0)
300
301         static inline bool irq_running(void)
302         {
303                 extern void *user_sp;
304                 return !!user_sp;
305         }
306         #define IRQ_RUNNING() irq_running()
307
308         static inline bool irq_getstate(void)
309         {
310                 uint16_t x;
311                 asm(move SR,x);
312                 return !(x & 0x0200);
313         }
314         #define IRQ_GETSTATE() irq_getstate()
315
316         typedef uint16_t cpuflags_t;
317         typedef unsigned int cpustack_t;
318
319         #define CPU_REG_BITS            16
320         #define CPU_REGS_CNT            FIXME
321         #define CPU_SAVED_REGS_CNT      8
322         #define CPU_STACK_GROWS_UPWARD  1
323         #define CPU_SP_ON_EMPTY_SLOT    0
324         #define CPU_BYTE_ORDER          CPU_BIG_ENDIAN
325         #define CPU_HARVARD             1
326
327         /* Memory is word-addessed in the DSP56K */
328         #define CPU_BITS_PER_CHAR  16
329         #define SIZEOF_SHORT        1
330         #define SIZEOF_INT          1
331         #define SIZEOF_LONG         2
332         #define SIZEOF_PTR          1
333
334 #elif CPU_AVR
335
336         #define NOP           asm volatile ("nop" ::)
337         #define IRQ_DISABLE   asm volatile ("cli" ::)
338         #define IRQ_ENABLE    asm volatile ("sei" ::)
339
340         #define IRQ_SAVE_DISABLE(x) \
341         do { \
342                 __asm__ __volatile__( \
343                         "in %0,__SREG__\n\t" \
344                         "cli" \
345                         : "=r" (x) : /* no inputs */ : "cc" \
346                 ); \
347         } while (0)
348
349         #define IRQ_RESTORE(x) \
350         do { \
351                 __asm__ __volatile__( \
352                         "out __SREG__,%0" : /* no outputs */ : "r" (x) : "cc" \
353                 ); \
354         } while (0)
355
356         #define IRQ_GETSTATE() \
357         ({ \
358                 uint8_t sreg; \
359                 __asm__ __volatile__( \
360                         "in %0,__SREG__\n\t" \
361                         : "=r" (sreg)  /* no inputs & no clobbers */ \
362                 ); \
363                 (bool)(sreg & 0x80); \
364         })
365
366         typedef uint8_t cpuflags_t;
367         typedef uint8_t cpustack_t;
368
369         /* Register counts include SREG too */
370         #define CPU_REG_BITS            8
371         #define CPU_REGS_CNT           33
372         #define CPU_SAVED_REGS_CNT     19
373         #define CPU_STACK_GROWS_UPWARD  0
374         #define CPU_SP_ON_EMPTY_SLOT    1
375         #define CPU_BYTE_ORDER          CPU_LITTLE_ENDIAN
376         #define CPU_HARVARD             1
377
378         /**
379          * Initialization value for registers in stack frame.
380          * The register index is not directly corrispondent to CPU
381          * register numbers. Index 0 is the SREG register: the initial
382          * value is all 0 but the interrupt bit (bit 7).
383          */
384         #define CPU_REG_INIT_VALUE(reg) (reg == 0 ? 0x80 : 0)
385
386 #else
387         #error No CPU_... defined.
388 #endif
389
390 /**
391  * Execute \a CODE atomically with respect to interrupts.
392  *
393  * \see IRQ_SAVE_DISABLE IRQ_RESTORE
394  */
395 #define ATOMIC(CODE) \
396         do { \
397                 cpuflags_t __flags; \
398                 IRQ_SAVE_DISABLE(__flags); \
399                 CODE; \
400                 IRQ_RESTORE(__flags); \
401         } while (0)
402
403
404 /// Default for macro not defined in the right arch section
405 #ifndef CPU_REG_INIT_VALUE
406         #define CPU_REG_INIT_VALUE(reg)     0
407 #endif
408
409
410 #ifndef CPU_STACK_GROWS_UPWARD
411         #error CPU_STACK_GROWS_UPWARD should have been defined to either 0 or 1
412 #endif
413
414 #ifndef CPU_SP_ON_EMPTY_SLOT
415         #error CPU_SP_ON_EMPTY_SLOT should have been defined to either 0 or 1
416 #endif
417
418 /*
419  * Support stack handling peculiarities of a few CPUs.
420  *
421  * Most processors let their stack grow downward and
422  * keep SP pointing at the last pushed value.
423  */
424 #if !CPU_STACK_GROWS_UPWARD
425         #if !CPU_SP_ON_EMPTY_SLOT
426                 /* Most microprocessors (x86, m68k...) */
427                 #define CPU_PUSH_WORD(sp, data) \
428                         do { *--(sp) = (data); } while (0)
429                 #define CPU_POP_WORD(sp) \
430                         (*(sp)++)
431         #else
432                 /* AVR insanity */
433                 #define CPU_PUSH_WORD(sp, data) \
434                         do { *(sp)-- = (data); } while (0)
435                 #define CPU_POP_WORD(sp) \
436                         (*++(sp))
437         #endif
438
439 #else /* CPU_STACK_GROWS_UPWARD */
440
441         #if !CPU_SP_ON_EMPTY_SLOT
442                 /* DSP56K and other weirdos */
443                 #define CPU_PUSH_WORD(sp, data) \
444                         do { *++(sp) = (cpustack_t)(data); } while (0)
445                 #define CPU_POP_WORD(sp) \
446                         (*(sp)--)
447         #else
448                 #error I bet you cannot find a CPU like this
449         #endif
450 #endif
451
452
453 #if CPU_DSP56K
454         /*
455          * DSP56k pushes both PC and SR to the stack in the JSR instruction, but
456          * RTS discards SR while returning (it does not restore it). So we push
457          * 0 to fake the same context.
458          */
459         #define CPU_PUSH_CALL_CONTEXT(sp, func) \
460                 do { \
461                         CPU_PUSH_WORD((sp), (func)); \
462                         CPU_PUSH_WORD((sp), 0x100); \
463                 } while (0);
464
465 #elif CPU_AVR
466         /*
467          * In AVR, the addresses are pushed into the stack as little-endian, while
468          * memory accesses are big-endian (actually, it's a 8-bit CPU, so there is
469          * no natural endianess).
470          */
471         #define CPU_PUSH_CALL_CONTEXT(sp, func) \
472                 do { \
473                         uint16_t funcaddr = (uint16_t)(func); \
474                         CPU_PUSH_WORD((sp), funcaddr); \
475                         CPU_PUSH_WORD((sp), funcaddr>>8); \
476                 } while (0)
477
478 #else
479         #define CPU_PUSH_CALL_CONTEXT(sp, func) \
480                 CPU_PUSH_WORD((sp), (cpustack_t)(func))
481 #endif
482
483
484 /**
485  * \name Default type sizes.
486  *
487  * These defaults are reasonable for most 16/32bit machines.
488  * Some of these macros may be overridden by CPU-specific code above.
489  *
490  * ANSI C requires that the following equations be true:
491  * \code
492  *   sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)
493  *   sizeof(float) <= sizeof(double)
494  *   CPU_BITS_PER_CHAR  >= 8
495  *   CPU_BITS_PER_SHORT >= 8
496  *   CPU_BITS_PER_INT   >= 16
497  *   CPU_BITS_PER_LONG  >= 32
498  * \endcode
499  * \{
500  */
501 #ifndef SIZEOF_CHAR
502 #define SIZEOF_CHAR  1
503 #endif
504
505 #ifndef SIZEOF_SHORT
506 #define SIZEOF_SHORT  2
507 #endif
508
509 #ifndef SIZEOF_INT
510 #if CPU_REG_BITS < 32
511         #define SIZEOF_INT  2
512 #else
513         #define SIZEOF_INT  4
514 #endif
515 #endif /* !SIZEOF_INT */
516
517 #ifndef SIZEOF_LONG
518 #if CPU_REG_BITS > 32
519         #define SIZEOF_LONG  8
520 #else
521         #define SIZEOF_LONG  4
522 #endif
523 #endif
524
525 #ifndef SIZEOF_PTR
526 #if CPU_REG_BITS < 32
527         #define SIZEOF_PTR   2
528 #elif CPU_REG_BITS == 32
529         #define SIZEOF_PTR   4
530 #else /* CPU_REG_BITS > 32 */
531         #define SIZEOF_PTR   8
532 #endif
533 #endif
534
535 #ifndef CPU_BITS_PER_CHAR
536 #define CPU_BITS_PER_CHAR   (SIZEOF_CHAR * 8)
537 #endif
538
539 #ifndef CPU_BITS_PER_SHORT
540 #define CPU_BITS_PER_SHORT  (SIZEOF_SHORT * CPU_BITS_PER_CHAR)
541 #endif
542
543 #ifndef CPU_BITS_PER_INT
544 #define CPU_BITS_PER_INT    (SIZEOF_INT * CPU_BITS_PER_CHAR)
545 #endif
546
547 #ifndef CPU_BITS_PER_LONG
548 #define CPU_BITS_PER_LONG   (SIZEOF_LONG * CPU_BITS_PER_CHAR)
549 #endif
550
551 #ifndef CPU_BITS_PER_PTR
552 #define CPU_BITS_PER_PTR    (SIZEOF_PTR * CPU_BITS_PER_CHAR)
553 #endif
554
555 #ifndef BREAKPOINT
556 #define BREAKPOINT /* nop */
557 #endif
558
559 /*\}*/
560
561 /* Sanity checks for the above definitions */
562 STATIC_ASSERT(sizeof(char) == SIZEOF_CHAR);
563 STATIC_ASSERT(sizeof(short) == SIZEOF_SHORT);
564 STATIC_ASSERT(sizeof(long) == SIZEOF_LONG);
565 STATIC_ASSERT(sizeof(int) == SIZEOF_INT);
566 STATIC_ASSERT(sizeof(void *) == SIZEOF_PTR);
567 STATIC_ASSERT(sizeof(int8_t) * CPU_BITS_PER_CHAR == 8);
568 STATIC_ASSERT(sizeof(uint8_t) * CPU_BITS_PER_CHAR == 8);
569 STATIC_ASSERT(sizeof(int16_t) * CPU_BITS_PER_CHAR == 16);
570 STATIC_ASSERT(sizeof(uint16_t) * CPU_BITS_PER_CHAR == 16);
571 STATIC_ASSERT(sizeof(int32_t) * CPU_BITS_PER_CHAR == 32);
572 STATIC_ASSERT(sizeof(uint32_t) * CPU_BITS_PER_CHAR == 32);
573 #ifdef __HAS_INT64_T__
574 STATIC_ASSERT(sizeof(int64_t) * CPU_BITS_PER_CHAR == 64);
575 STATIC_ASSERT(sizeof(uint64_t) * CPU_BITS_PER_CHAR == 64);
576 #endif
577
578 /**
579  * \def CPU_IDLE
580  *
581  * \brief Invoked by the scheduler to stop the CPU when idle.
582  *
583  * This hook can be redefined to put the CPU in low-power mode, or to
584  * profile system load with an external strobe, or to save CPU cycles
585  * in hosted environments such as emulators.
586  */
587 #ifndef CPU_IDLE
588         #if defined(ARCH_EMUL) && (ARCH & ARCH_EMUL)
589                 /* This emulator hook should yield the CPU to the host.  */
590                 EXTERN_C_BEGIN
591                 void emul_idle(void);
592                 EXTERN_C_END
593                 #define CPU_IDLE emul_idle()
594         #else /* !ARCH_EMUL */
595                 #define CPU_IDLE do { /* nothing */ } while (0)
596         #endif /* !ARCH_EMUL */
597 #endif /* !CPU_IDLE */
598
599 #endif /* DEVLIB_CPU_H */