Merge contributed patch to extend support of atxmega.
[bertos.git] / bertos / cpu / attr.h
index 59748126a943432a3cce7c5f2edebad4b7058ea8..331f26dff0c372d7290a7e9862b9651ac36dfafc 100644 (file)
@@ -26,9 +26,8 @@
  * invalidate any other reasons why the executable file might be covered by
  * the GNU General Public License.
  *
- * Copyright 2004, 2005, 2006, 2007 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2004, 2005, 2006, 2007, 2008 Develer S.r.l. (http://www.develer.com/)
  * Copyright 2004 Giovanni Bajo
- *
  * -->
  *
  * \brief CPU-specific attributes.
@@ -43,9 +42,8 @@
 
 #include "detect.h"
 
+#include "cfg/cfg_proc.h"      /* CONFIG_KERN_PREEMPT */
 #include "cfg/cfg_attr.h"      /* CONFIG_FAST_MEM */
-#include "cfg/cfg_arch.h"      /* ARCH_EMUL */
-#include <cfg/compiler.h>      /* for uintXX_t */
 
 
 /**
 
        #define CPU_REG_BITS            16
        #define CPU_REGS_CNT            16
-       #define CPU_STACK_GROWS_UPWARD  0
-       #define CPU_SP_ON_EMPTY_SLOT    0
        #define CPU_BYTE_ORDER          CPU_LITTLE_ENDIAN
-       #define CPU_HARVARD             0
+       #define CPU_HARVARD             0
 
        /// Valid pointers should be >= than this value (used for debug)
        #define CPU_RAM_START           0x100
 
 #elif CPU_X86
 
-       #define NOP                     asm volatile ("nop")
-
        #define CPU_REGS_CNT            7
-       #define CPU_SAVED_REGS_CNT      7
-       #define CPU_STACK_GROWS_UPWARD  0
-       #define CPU_SP_ON_EMPTY_SLOT    0
        #define CPU_BYTE_ORDER          CPU_LITTLE_ENDIAN
-       #define CPU_HARVARD             0
+       #define CPU_HARVARD             0
 
        #if CPU_X86_64
                #define CPU_REG_BITS    64
        #endif
 
        /// Valid pointers should be >= than this value (used for debug)
-       #define CPU_RAM_START           0x1000
+       #define CPU_RAM_START      0x1000
+
+       #ifdef __GNUC__
+               #define NOP         asm volatile ("nop")
+               /* This is a good thing to insert into busy-wait loops. */
+               #define PAUSE       asm volatile ("rep; nop" ::: "memory")
+               #define BREAKPOINT  asm volatile ("int3" ::)
+       #endif
 
 #elif CPU_ARM
 
-       /* Register counts include SREG too */
        #define CPU_REG_BITS           32
        #define CPU_REGS_CNT           16
-       #define CPU_SAVED_REGS_CNT     9
-       #define CPU_STACK_GROWS_UPWARD 0
-       #define CPU_SP_ON_EMPTY_SLOT   0
        #define CPU_HARVARD            0
 
        /// Valid pointers should be >= than this value (used for debug)
-       #define CPU_RAM_START           0x200
+       #if CPU_ARM_AT91
+               #define CPU_RAM_START           0x00200000
+       #elif CPU_ARM_LPC2
+               #define CPU_RAM_START           0x40000000
+       #else
+               #warning Fix CPU_RAM_START address for your ARM, default value set to 0x200
+               #define CPU_RAM_START           0x200
+       #endif
 
        #ifdef __IAR_SYSTEMS_ICC__
                #warning Check CPU_BYTE_ORDER
                #endif
 
                #define NOP            asm volatile ("mov r0,r0" ::)
-
-               /**
-                * Initialization value for registers in stack frame.
-                * The register index is not directly corrispondent to CPU
-                * register numbers, but is related to how are pushed to
-                * stack (\see asm_switch_context).
-                * Index (CPU_SAVED_REGS_CNT - 1) is the CPSR register,
-                * the initial value is set to:
-                * - All flags (N, Z, C, V) set to 0.
-                * - IRQ and FIQ enabled.
-                * - ARM state.
-                * - CPU in Supervisor Mode (SVC).
-                */
-               #define CPU_REG_INIT_VALUE(reg) (reg == (CPU_SAVED_REGS_CNT - 1) ? 0x13 : 0)
+               #define BREAKPOINT  /* asm("bkpt 0") DOES NOT WORK */
 
                #if CONFIG_FAST_MEM
                        /**
                         * to get them transparently copied to SRAM for zero-wait-state
                         * operation.
                         */
-                       #define FAST_FUNC __attribute__((section(".data")))
+                       #define FAST_FUNC __attribute__((section(".ramfunc")))
 
                        /**
                         * Data attribute to move constant data to fast memory storage.
                        #define FAST_FUNC /**/
                #endif
 
-               /**
-                * Function attribute to declare an interrupt service routine.
+               /*
+                * Function attribute to move it into ram memory.
                 */
-               #define ISR_FUNC __attribute__((interrupt))
+               #define RAM_FUNC __attribute__((section(".ramfunc")))
 
        #endif /* !__IAR_SYSTEMS_ICC_ */
+#elif CPU_CM3
+
+       #define CPU_REG_BITS           32
+       #define CPU_REGS_CNT           16
+       #define CPU_HARVARD            0
+
+       /// Valid pointers should be >= than this value (used for debug)
+       #if (CPU_CM3_LM3S1968 || CPU_CM3_LM3S8962 || CPU_CM3_STM32 || CPU_CM3_SAM3)
+               #define CPU_RAM_START 0x20000000
+       #else
+               #warning Fix CPU_RAM_START address for your Cortex-M3, default value set to 0x20000000
+               #define CPU_RAM_START 0x20000000
+       #endif
+
+    #if defined( __ICCARM__)
+        #if ((defined __LITTLE_ENDIAN__) && (__LITTLE_ENDIAN__ == 0))
+            #define CPU_BYTE_ORDER CPU_BIG_ENDIAN
+        #elif ((defined __LITTLE_ENDIAN__) && (__LITTLE_ENDIAN__ == 1))
+                   #define CPU_BYTE_ORDER CPU_LITTLE_ENDIAN
+        #else
+            #error Unable to detect Cortex-M3 endianess!
+        #endif
+
+       #define NOP            __no_operation()
+    #else
+        #if defined(__ARMEB__) // GCC
+            #define CPU_BYTE_ORDER CPU_BIG_ENDIAN
+        #elif defined(__ARMEL__) // GCC
+            #define CPU_BYTE_ORDER CPU_LITTLE_ENDIAN
+        #else
+            #error Unable to detect Cortex-M3 endianess!
+        #endif
+
+       #define NOP         asm volatile ("nop")
+       #define PAUSE       asm volatile ("wfi" ::: "memory")
+       #define BREAKPOINT  /* asm("bkpt 0") DOES NOT WORK */
+
+       /*
+        * Function attribute to move it into ram memory.
+        */
+       #define RAM_FUNC __attribute__((section(".ramfunc")))
+    #endif
 
 #elif CPU_PPC
-       #define NOP                 asm volatile ("nop" ::)
 
-       /* Register counts include SREG too */
        #define CPU_REG_BITS           (CPU_PPC32 ? 32 : 64)
        #define CPU_REGS_CNT           FIXME
-       #define CPU_SAVED_REGS_CNT     1  // FIXME
-       #define CPU_STACK_GROWS_UPWARD 0  //FIXME
-       #define CPU_SP_ON_EMPTY_SLOT   0  //FIXME
        #define CPU_BYTE_ORDER         (__BIG_ENDIAN__ ? CPU_BIG_ENDIAN : CPU_LITTLE_ENDIAN)
        #define CPU_HARVARD            0
 
        /// Valid pointers should be >= than this value (used for debug)
-       #define CPU_RAM_START           0x1000
+       #define CPU_RAM_START          0x1000
 
-#elif CPU_DSP56K
+       #ifdef __GNUC__
+           #define NOP         asm volatile ("nop" ::)
+               #define BREAKPOINT  asm volatile ("twge 2,2" ::)
+       #endif
 
-       #define NOP                     asm(nop)
+#elif CPU_DSP56K
 
        #define CPU_REG_BITS            16
        #define CPU_REGS_CNT            FIXME
-       #define CPU_SAVED_REGS_CNT      8
-       #define CPU_STACK_GROWS_UPWARD  1
-       #define CPU_SP_ON_EMPTY_SLOT    0
        #define CPU_BYTE_ORDER          CPU_BIG_ENDIAN
-       #define CPU_HARVARD             1
+       #define CPU_HARVARD             1
 
        /* Memory is word-addessed in the DSP56K */
        #define CPU_BITS_PER_CHAR  16
        #define SIZEOF_PTR          1
 
        /// Valid pointers should be >= than this value (used for debug)
-       #define CPU_RAM_START           0x200
+       #define CPU_RAM_START       0x200
+
+       #define NOP                     asm(nop)
+       #define BREAKPOINT              asm(debug)
 
 #elif CPU_AVR
 
-       #define NOP           asm volatile ("nop" ::)
+       #define NOP                     asm volatile ("nop" ::)
 
-       /* Register counts include SREG too */
        #define CPU_REG_BITS            8
-       #define CPU_REGS_CNT           33
-       #define CPU_SAVED_REGS_CNT     19
-       #define CPU_STACK_GROWS_UPWARD  0
-       #define CPU_SP_ON_EMPTY_SLOT    1
+       #define CPU_REGS_CNT           33 /* Includes SREG */
        #define CPU_BYTE_ORDER          CPU_LITTLE_ENDIAN
        #define CPU_HARVARD             1
 
-       /**
-        * Initialization value for registers in stack frame.
-        * The register index is not directly corrispondent to CPU
-        * register numbers. Index 0 is the SREG register: the initial
-        * value is all 0 but the interrupt bit (bit 7).
-        */
-       #define CPU_REG_INIT_VALUE(reg) (reg == 0 ? 0x80 : 0)
+       /// Valid pointers should be >= than this value (used for debug)
+       #if CPU_AVR_ATMEGA8 || CPU_AVR_ATMEGA32 || CPU_AVR_ATMEGA103
+               #define CPU_RAM_START       0x60
+       #elif CPU_AVR_ATMEGA64 || CPU_AVR_ATMEGA128 || CPU_AVR_ATMEGA168 || CPU_AVR_ATMEGA328P
+               #define CPU_RAM_START       0x100
+       #elif CPU_AVR_ATMEGA1281 || CPU_AVR_ATMEGA1280 || CPU_AVR_ATMEGA2560
+               #define CPU_RAM_START       0x200
+       #elif CPU_AVR_XMEGA
+               #define CPU_RAM_START           0x2000
+       #else
+               #warning Fix CPU_RAM_START address for your AVR, default value set to 0x100
+               #define CPU_RAM_START       0x100
+       #endif
+
+#elif CPU_MSP430
+
+       #define CPU_REG_BITS            16
+       #define CPU_REGS_CNT            12
+       #define CPU_BYTE_ORDER          CPU_LITTLE_ENDIAN
+       #define CPU_HARVARD                     0
 
        /// Valid pointers should be >= than this value (used for debug)
-       #define CPU_RAM_START           0x100
+       #define CPU_RAM_START           0x200
+
+       #define NOP                     __asm__ __volatile__ ("nop")
 
 #else
        #error No CPU_... defined.
 #endif
 
-/// Default for macro not defined in the right arch section
-#ifndef CPU_REG_INIT_VALUE
-       #define CPU_REG_INIT_VALUE(reg)     0
-#endif
-
-#ifndef CPU_STACK_GROWS_UPWARD
-       #error CPU_STACK_GROWS_UPWARD should have been defined to either 0 or 1
-#endif
-
-#ifndef CPU_SP_ON_EMPTY_SLOT
-       #error CPU_SP_ON_EMPTY_SLOT should have been defined to either 0 or 1
+#ifndef BREAKPOINT
+#define BREAKPOINT /* nop */
 #endif
 
 #ifndef FAST_FUNC
-       /**
-        * Function attribute for use with performance critical code.
-        */
+       /// Function attribute for use with performance critical code.
        #define FAST_FUNC /* */
 #endif
 
 #ifndef FAST_RODATA
-       /**
-        * Data attribute to move constant data to fast memory storage.
-        */
+       /// Data attribute to move constant data to fast memory storage.
        #define FAST_RODATA /* */
 #endif
 
-/*
- * Support stack handling peculiarities of a few CPUs.
- *
- * Most processors let their stack grow downward and
- * keep SP pointing at the last pushed value.
- */
-#if !CPU_STACK_GROWS_UPWARD
-       #if !CPU_SP_ON_EMPTY_SLOT
-               /* Most microprocessors (x86, m68k...) */
-               #define CPU_PUSH_WORD(sp, data) \
-                       do { *--(sp) = (data); } while (0)
-               #define CPU_POP_WORD(sp) \
-                       (*(sp)++)
-       #else
-               /* AVR insanity */
-               #define CPU_PUSH_WORD(sp, data) \
-                       do { *(sp)-- = (data); } while (0)
-               #define CPU_POP_WORD(sp) \
-                       (*++(sp))
-       #endif
-
-#else /* CPU_STACK_GROWS_UPWARD */
-
-       #if !CPU_SP_ON_EMPTY_SLOT
-               /* DSP56K and other weirdos */
-               #define CPU_PUSH_WORD(sp, data) \
-                       do { *++(sp) = (cpustack_t)(data); } while (0)
-               #define CPU_POP_WORD(sp) \
-                       (*(sp)--)
-       #else
-               #error I bet you cannot find a CPU like this
-       #endif
+#ifndef PAUSE
+       /// Generic PAUSE implementation.
+       #define PAUSE   do {NOP; MEMORY_BARRIER;} while (0)
 #endif
 
-
-#if CPU_DSP56K
-       /*
-        * DSP56k pushes both PC and SR to the stack in the JSR instruction, but
-        * RTS discards SR while returning (it does not restore it). So we push
-        * 0 to fake the same context.
-        */
-       #define CPU_PUSH_CALL_CONTEXT(sp, func) \
-               do { \
-                       CPU_PUSH_WORD((sp), (func)); \
-                       CPU_PUSH_WORD((sp), 0x100); \
-               } while (0);
-
-#elif CPU_AVR
-       /*
-        * In AVR, the addresses are pushed into the stack as little-endian, while
-        * memory accesses are big-endian (actually, it's a 8-bit CPU, so there is
-        * no natural endianess).
-        */
-       #define CPU_PUSH_CALL_CONTEXT(sp, func) \
-               do { \
-                       uint16_t funcaddr = (uint16_t)(func); \
-                       CPU_PUSH_WORD((sp), funcaddr); \
-                       CPU_PUSH_WORD((sp), funcaddr>>8); \
-               } while (0)
-
-       /*
-        * If the kernel is in idle-spinning, the processor executes:
-        *
-        * IRQ_ENABLE;
-        * CPU_IDLE;
-        * IRQ_DISABLE;
-        *
-        * IRQ_ENABLE is translated in asm as "sei" and IRQ_DISABLE as "cli".
-        * We could define CPU_IDLE to expand to none, so the resulting
-        * asm code would be:
-        *
-        * sei;
-        * cli;
-        *
-        * But Atmel datasheet states:
-        * "When using the SEI instruction to enable interrupts,
-        * the instruction following SEI will be executed *before*
-        * any pending interrupts", so "cli" is executed before any
-        * pending interrupt with the result that IRQs will *NOT*
-        * be enabled!
-        * To ensure that IRQ will run a NOP is required.
-        */
-       #define CPU_IDLE NOP
-
-#else
-       #define CPU_PUSH_CALL_CONTEXT(sp, func) \
-               CPU_PUSH_WORD((sp), (cpustack_t)(func))
-#endif
-
-/**
- * \def CPU_IDLE
- *
- * \brief Invoked by the scheduler to stop the CPU when idle.
- *
- * This hook can be redefined to put the CPU in low-power mode, or to
- * profile system load with an external strobe, or to save CPU cycles
- * in hosted environments such as emulators.
- */
-#ifndef CPU_IDLE
-       #if defined(ARCH_EMUL) && (ARCH & ARCH_EMUL)
-               /* This emulator hook should yield the CPU to the host.  */
-               EXTERN_C_BEGIN
-               void emul_idle(void);
-               EXTERN_C_END
-               #define CPU_IDLE emul_idle()
-       #else /* !ARCH_EMUL */
-               #define CPU_IDLE do { /* nothing */ } while (0)
-       #endif /* !ARCH_EMUL */
-#endif /* !CPU_IDLE */
-
 #endif /* CPU_ATTR_H */