85 Commits

Author SHA1 Message Date
Kelvin Lawson
0e2d899e41 ARM/IntegratorCP: add spacing. 2013-03-19 00:23:57 +00:00
Kelvin Lawson
20d8da0eb6 ARM: Remove dbg_format_msg() which can be done via printf() now that mutex used. 2013-03-19 00:11:21 +00:00
Kelvin Lawson
65edc4ab09 ARM: Review READMEs. 2013-03-18 23:34:38 +00:00
Kelvin Lawson
8ecb72c755 ARM Port: Convert tabs to spaces. 2013-03-18 22:57:56 +00:00
Kelvin Lawson
eeefac9a40 ARM/IntegratorCP: Wait for newlines on expect script. 2013-03-18 22:48:03 +00:00
Kelvin Lawson
0222cd9ff7 ARM/IntegratorCP: Implement unhandled interrupt ISR. 2013-03-18 22:43:39 +00:00
Kelvin Lawson
0aa74332d4 ARM: Increase stack size above 1KB on ARM as printf() observed to use ~1700 bytes on GCC toolchain used during development. 2013-03-07 02:59:35 +00:00
Kelvin Lawson
3db5731941 ARM README: Add details on porting to other platforms. 2013-03-06 23:52:49 +00:00
Kelvin Lawson
dda5aedb57 ARM/IntegratorCP: Create doxygen output for common ARM port folder and platform folder. 2013-03-06 22:33:35 +00:00
Kelvin Lawson
4e7c9c4c52 ARM/IntegratorCP: Add platform README. Other ports, rename old atomuser.h (now atomport.h). 2013-03-05 02:28:38 +00:00
Kelvin Lawson
5ca7a2c7a5 ARM: Don't need C wrappers for context switch routines. 2013-03-05 01:34:30 +00:00
Kelvin Lawson
63debdf613 AVR: Typo tcb_save_ptr should be sp_save_ptr. 2013-03-05 01:17:23 +00:00
Kelvin Lawson
02d14edd9e ARM: Add comments describing port operation. 2013-03-05 01:08:53 +00:00
Kelvin Lawson
033ff4fd8d ARM/IntegratorCP: Tidying, remove unused code, make the interrupt dispatcher operation more clear. 2013-03-05 00:35:07 +00:00
Kelvin Lawson
144434ac22 ARM/IntegratorCP: Add instructions on qemutests. 2013-03-04 11:19:57 +00:00
Kelvin Lawson
e192dc4e35 ARM/IntegratorCP: Description changes only. 2013-03-04 02:31:39 +00:00
Kelvin Lawson
3d61d86a0a ARM/IntegratorCP: kern4 working after systick frequency change. 2013-03-04 02:24:30 +00:00
Kelvin Lawson
21411e439f ARM/IntegratorCP: Remove types.h file, macros only ever used in modules.h. 2013-03-04 02:20:21 +00:00
Kelvin Lawson
2925d865a4 ARM: Remove unused CONTEXT_THREAD_ID code. 2013-03-04 02:16:55 +00:00
Kelvin Lawson
36e856020b ARM/IntegratorCP: Farm UART out to platform-specific uart module. 2013-03-04 02:09:40 +00:00
Kelvin Lawson
07931272ae ARM syscalls.c: Tidy up formatting. 2013-03-04 01:18:28 +00:00
Kelvin Lawson
92cac339c9 ARM/IntegratorCP: Remove eh_ sections. 2013-02-28 16:12:55 +00:00
Kelvin Lawson
3ec86aca58 Move Newlib syscalls.c replacement to common ARM port folder. 2013-02-28 16:02:23 +00:00
Kelvin Lawson
e5882cb0e6 Support stack-check builds. Fix line endings. Remove deprecated Makefile. 2013-02-28 15:55:34 +00:00
Kelvin Lawson
84e2e7aecf ARM/IntegratorCP: Add automated run of all tests using expect ("make qemutests"). 2013-02-28 14:09:21 +00:00
Kelvin Lawson
ba5255ec0b ARM: Create new common tests-main.c, does not need to be a per-platform file. 2013-02-28 13:47:39 +00:00
Kelvin Lawson
0f175c5da4 ARM/IntegratorCP: Move platform folder underneath the relevant port folder (ports/arm/platforms/qemu_integratorcp). 2013-02-28 13:36:57 +00:00
Kelvin Lawson
3e41694c37 ARM/IntegratorCP: Assembler flags require "assembler-with-cpp" since renaming .S files to .s. 2013-02-27 14:37:20 +00:00
Kelvin Lawson
30183b1b9f Removed modules.o 2013-02-27 13:35:46 +00:00
Kelvin Lawson
8af57c8e8f ARM/IntegratorCP: Match avr/other platforms. 2013-02-27 01:21:39 +00:00
Kelvin Lawson
ada2ed3fac ARM/IntegratorCP: Match avr/other ports. 2013-02-27 01:13:09 +00:00
Kelvin Lawson
1e4f7892a4 ARM/IntegratorCP: Match avr/other port coding style. 2013-02-27 01:10:50 +00:00
Kelvin Lawson
0027134452 ARM/IntegratorCP: Use similar coding style to avr/other ports. 2013-02-27 01:09:11 +00:00
Kelvin Lawson
1b63c32848 Merge branch 'navaro' of github.com:kelvinlawson/atomthreads into navaro 2013-02-27 00:28:08 +00:00
Kelvin Lawson
2bd4163252 Merge navaro ARM changes into navaro branch. 2013-02-27 00:27:42 +00:00
Kelvin Lawson
b6339e65ca Merge navaro change into navaro branch. 2013-02-27 00:26:12 +00:00
Kelvin Lawson
554c772f95 ARM: Allow threads to run to completion. 2013-02-26 23:29:13 +00:00
Kelvin Lawson
dac253ceac ARM/IntegratorCP: Add -nographic to QEMU command-line. Use AFLAGS for assembler flags. 2013-02-26 23:17:38 +00:00
Kelvin Lawson
05f391631c ARM/IntegratorCP: Use the same heap linker pointers whether using hosted/newlib or standalone toolchain. 2013-02-26 23:08:10 +00:00
Kelvin Lawson
8e6270f30e ARM/IntegratorCP: Export __end__ from linker script, required by newlib-based toolchain crt0.s. 2013-02-26 22:35:31 +00:00
Kelvin Lawson
06684c94ce ARM/IntegratorCP: Build for compiler toolchains with and without newlib/startup code by making newlib syscalls and _mainCRTStartup() weak linkage. Also add missing test modules to Makefile. 2013-02-26 22:13:14 +00:00
Kelvin Lawson
5e56576b2d ARM: Fix timer tick speed, should be 10ms. 2013-02-26 20:09:18 +00:00
Kelvin Lawson
d83e5dbe00 C startup now only copies data section to RAM if running from ROM. Move C startup to modules.c and rename _mainCRTStartup() to match that included with certain toolchains. 2013-02-26 13:33:40 +00:00
Natie van Rooyen
b19004817c Added thread exit routine. 2012-11-18 11:29:32 +01:00
Natie van Rooyen
356685005a LPC17xx platform for Cortex M port 2012-10-25 10:41:23 +02:00
Natie van Rooyen
9d18dafd72 Atomvm SWI functionality added. 2012-10-23 17:50:16 +02:00
Natie van Rooyen
8cdd707b41 Updated README for lpx17xx 2012-10-23 16:58:10 +02:00
Natie van Rooyen
d9f1f8389f atomvm updates 2012-10-23 14:53:32 +02:00
Natie van Rooyen
8d62300d41 updates 2012-10-23 14:45:12 +02:00
Natie van Rooyen
648d35dbe6 LPC17xx platform for Cortex M port 2012-10-23 14:23:34 +02:00
Natie van Rooyen
6f34e08e2f Updates to the atomvm port. 2012-10-03 21:19:44 +02:00
Natie van Rooyen
c016f54ad0 Merge remote-tracking branch 'origin/master' 2012-09-27 21:49:34 +02:00
Natie van Rooyen
9ebb4d14b4 white space 2012-09-27 21:46:59 +02:00
Natie van Rooyen
5995495350 Updated for new stack alignment changes in atom.h. 2012-09-27 19:33:23 +02:00
Natie van Rooyen
4c669225c6 Updated for new stack alignment changes in atom.h. 2012-09-27 12:18:00 +02:00
Natie van Rooyen
b8afea38ba Merge remote-tracking branch 'origin/master' 2012-09-27 11:49:40 +02:00
Natie van Rooyen
047c741e21 Merge remote-tracking branch 'kelvin_atomthreads/master'
Conflicts:
	tests/kern1.c
	tests/kern3.c
	tests/kern4.c
	tests/mutex1.c
	tests/mutex2.c
	tests/mutex3.c
	tests/mutex4.c
	tests/mutex5.c
	tests/mutex6.c
	tests/mutex7.c
	tests/mutex8.c
	tests/mutex9.c
	tests/queue2.c
	tests/queue3.c
	tests/queue5.c
	tests/queue6.c
	tests/queue7.c
	tests/queue9.c
	tests/sem1.c
	tests/sem3.c
	tests/sem4.c
	tests/sem5.c
	tests/sem6.c
	tests/sem7.c
	tests/sem8.c
	tests/sem9.c
	tests/timer2.c
2012-09-27 11:48:42 +02:00
Natie van Rooyen
f6945acf5b Merge remote-tracking branch 'kelvin_atomthreads/master'
Conflicts:
	tests/kern1.c
	tests/kern3.c
	tests/kern4.c
	tests/mutex1.c
	tests/mutex2.c
	tests/mutex3.c
	tests/mutex4.c
	tests/mutex5.c
	tests/mutex6.c
	tests/mutex7.c
	tests/mutex8.c
	tests/mutex9.c
	tests/queue2.c
	tests/queue3.c
	tests/queue5.c
	tests/queue6.c
	tests/queue7.c
	tests/queue9.c
	tests/sem1.c
	tests/sem3.c
	tests/sem4.c
	tests/sem5.c
	tests/sem6.c
	tests/sem7.c
	tests/sem8.c
	tests/sem9.c
	tests/timer2.c
2012-09-27 11:33:36 +02:00
Natie van Rooyen
650f5e2ac3 Cortex M port added
qemu_lm3s platform added
2012-09-27 10:49:09 +02:00
Natie van Rooyen
daa748332b cortex m port
qemu_lm3s platform
2012-09-24 23:16:03 +02:00
Kelvin Lawson
c84c7d3222 modules.c: Line ending changes.
syscalls.c: Add _sbrk and friends, as well as a basic c startup.
2012-09-21 02:45:06 +01:00
Kelvin Lawson
6d8aee9e65 main.c: Remove unused stack variable. 2012-09-21 02:41:36 +01:00
Kelvin Lawson
af6671019f system.ld: Add 64KB heap. 2012-09-21 02:38:09 +01:00
Kelvin Lawson
f5de0d76ae ARM main.c: Use new thread creation APIs. 2012-09-21 01:52:21 +01:00
Kelvin Lawson
cd3edd6726 ARM atomport.h: Merge with latest template. 2012-09-21 01:50:25 +01:00
Kelvin Lawson
c009a05421 Use new atomThreadCreate() API with stack-alignment mods. 2012-09-21 01:34:09 +01:00
Kelvin Lawson
0d07f0274d Merge https://github.com/navaro/atomthreads into navaro branch. Remove tests/ folder changes as they were based on an old Atomthreads API. Remove some binaries and other unnecessary files. 2012-09-21 01:30:09 +01:00
Natie van Rooyen
28e7382732 Updated CortexM port 2012-09-18 15:24:59 +02:00
Natie van Rooyen
dfb831fa63 Added “arm” port .
Added platforms directory.
Added QEMU qemu_integratorcp platform in platforms.
Modified test cases to make stack top DWORD aligned.
2012-09-17 13:02:09 +02:00
Natie van Rooyen
a2646ec695 updates 2012-05-22 00:22:09 +02:00
Natie van Rooyen
12dbe5ebe9 tabs to spaces 2012-05-17 23:52:29 +02:00
Natie van Rooyen
1eb5c7bd41 Merge branch 'master' of github.com:navaro/atomthreads 2012-05-17 23:44:20 +02:00
Natie van Rooyen
113f0a8690 Please enter the commit message for your changes. Lines starting 2012-05-17 23:42:58 +02:00
Natie van Rooyen
37d6d553bf Update ports/atomvm/README.txt 2012-05-15 01:23:48 +03:00
unknown
5cc1e9831d atomvm fix 2012-05-15 00:03:43 +02:00
unknown
4a84c4cccf added armv7 and cortex_m3 port 2012-05-14 23:57:07 +02:00
Natie van Rooyen
10b93017a3 atomvmCtrlIntRequest bug fix (and other updates) 2011-02-28 16:49:35 +01:00
Natie van Rooyen
2e99ef35d5 Merge branch 'master' of git@github.com:navaro/atomthreads.git 2010-09-29 03:09:41 +02:00
Natie van Rooyen
b0d5a83689 Merge branch 'gh-pages' of git@github.com:navaro/atomthreads.git 2010-09-29 03:08:51 +02:00
Natie van Rooyen
202cbcf2df interrupt request updated.
started multicore support.
2010-09-24 18:44:18 +02:00
navaro
a3dec21707 2010-09-20 01:43:38 -07:00
Natie van Rooyen
8a880d2716 Added "Thread Local Storage" 2010-09-07 19:37:59 +02:00
Natie van Rooyen
e11d17147d Initial realease. 2010-09-07 19:27:15 +02:00
Natie van Rooyen
b9e7e9cc63 New, atomvm!
Added ATOM_TLS for TLS or other thread specific storage.
2010-09-03 22:23:47 +02:00
kelvinlawson
3ac858b8e0 github generated gh-pages branch 2010-01-14 13:59:49 -07:00
76 changed files with 15527 additions and 7 deletions

View File

@@ -44,8 +44,10 @@ struct atom_tcb;
typedef struct atom_tcb
{
/* Thread's current stack pointer. When a thread is scheduled
* out the architecture port can save*/
/*
* Thread's current stack pointer. When a thread is scheduled
* out the architecture port can save its stack pointer here.
*/
POINTER sp_save_ptr;
/* Thread priority (0-255) */
@@ -70,6 +72,10 @@ typedef struct atom_tcb
uint32_t stack_size; /* Size of stack allocation in bytes */
#endif
#ifdef ATOM_TLS
ATOM_TLS /* Thread Local Storage */
#endif
} ATOM_TCB;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,844 @@
/**************************************************************************//**
* @file core_cmFunc.h
* @brief CMSIS Cortex-M Core Function Access Header File
* @version V2.01
* @date 06. December 2010
*
* @note
* Copyright (C) 2009-2010 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __CORE_CMFUNC_H__
#define __CORE_CMFUNC_H__
/* ########################### Core Function Access ########################### */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
@{
*/
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/* ARM armcc specific functions */
/* intrinsic void __enable_irq(); */
/* intrinsic void __disable_irq(); */
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_CONTROL(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_CONTROL(void)
{
register uint32_t __regControl __ASM("control");
return(__regControl);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_CONTROL(uint32_t control);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_CONTROL(uint32_t control)
{
register uint32_t __regControl __ASM("control");
__regControl = control;
}
#endif /* __ARMCC_VERSION */
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_IPSR(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_IPSR(void)
{
register uint32_t __regIPSR __ASM("ipsr");
return(__regIPSR);
}
#endif /* __ARMCC_VERSION */
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_APSR(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_APSR(void)
{
register uint32_t __regAPSR __ASM("apsr");
return(__regAPSR);
}
#endif /* __ARMCC_VERSION */
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_xPSR(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_xPSR(void)
{
register uint32_t __regXPSR __ASM("xpsr");
return(__regXPSR);
}
#endif /* __ARMCC_VERSION */
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_PSP(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_PSP(void)
{
register uint32_t __regProcessStackPointer __ASM("psp");
return(__regProcessStackPointer);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_PSP(uint32_t topOfProcStack);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_PSP(uint32_t topOfProcStack)
{
register uint32_t __regProcessStackPointer __ASM("psp");
__regProcessStackPointer = topOfProcStack;
}
#endif /* __ARMCC_VERSION */
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_MSP(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_MSP(void)
{
register uint32_t __regMainStackPointer __ASM("msp");
return(__regMainStackPointer);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_MSP(uint32_t topOfMainStack);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_MSP(uint32_t topOfMainStack)
{
register uint32_t __regMainStackPointer __ASM("msp");
__regMainStackPointer = topOfMainStack;
}
#endif /* __ARMCC_VERSION */
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_PRIMASK(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_PRIMASK(void)
{
register uint32_t __regPriMask __ASM("primask");
return(__regPriMask);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_PRIMASK(uint32_t priMask);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_PRIMASK(uint32_t priMask)
{
register uint32_t __regPriMask __ASM("primask");
__regPriMask = (priMask);
}
#endif /* __ARMCC_VERSION */
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __enable_fault_irq __enable_fiq
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __disable_fault_irq __disable_fiq
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_BASEPRI(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_BASEPRI(void)
{
register uint32_t __regBasePri __ASM("basepri");
return(__regBasePri);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_BASEPRI(uint32_t basePri);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_BASEPRI(uint32_t basePri)
{
register uint32_t __regBasePri __ASM("basepri");
__regBasePri = (basePri & 0xff);
}
#endif /* __ARMCC_VERSION */
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask register.
\return Fault Mask register value
*/
#if (__ARMCC_VERSION < 400000)
extern uint32_t __get_FAULTMASK(void);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE uint32_t __get_FAULTMASK(void)
{
register uint32_t __regFaultMask __ASM("faultmask");
return(__regFaultMask);
}
#endif /* __ARMCC_VERSION */
/** \brief Set Fault Mask
This function assigns the given value to the Fault Mask register.
\param [in] faultMask Fault Mask value to set
*/
#if (__ARMCC_VERSION < 400000)
extern void __set_FAULTMASK(uint32_t faultMask);
#else /* (__ARMCC_VERSION >= 400000) */
static __INLINE void __set_FAULTMASK(uint32_t faultMask)
{
register uint32_t __regFaultMask __ASM("faultmask");
__regFaultMask = (faultMask & 1);
}
#endif /* __ARMCC_VERSION */
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
static __INLINE uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1)
register uint32_t __regfpscr __ASM("fpscr");
return(__regfpscr);
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
static __INLINE void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1)
register uint32_t __regfpscr __ASM("fpscr");
__regfpscr = (fpscr);
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* IAR iccarm specific functions */
#if defined (__ICCARM__)
#include <intrinsics.h> /* IAR Intrinsics */
#endif
#pragma diag_suppress=Pe940
/** \brief Enable IRQ Interrupts
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __enable_irq __enable_interrupt
/** \brief Disable IRQ Interrupts
This function disables IRQ interrupts by setting the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
#define __disable_irq __disable_interrupt
/* intrinsic unsigned long __get_CONTROL( void ); (see intrinsic.h) */
/* intrinsic void __set_CONTROL( unsigned long ); (see intrinsic.h) */
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
static uint32_t __get_IPSR(void)
{
__ASM("mrs r0, ipsr");
}
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
static uint32_t __get_APSR(void)
{
__ASM("mrs r0, apsr");
}
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
static uint32_t __get_xPSR(void)
{
__ASM("mrs r0, psr"); // assembler does not know "xpsr"
}
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
static uint32_t __get_PSP(void)
{
__ASM("mrs r0, psp");
}
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
static void __set_PSP(uint32_t topOfProcStack)
{
__ASM("msr psp, r0");
}
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
static uint32_t __get_MSP(void)
{
__ASM("mrs r0, msp");
}
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
static void __set_MSP(uint32_t topOfMainStack)
{
__ASM("msr msp, r0");
}
/* intrinsic unsigned long __get_PRIMASK( void ); (see intrinsic.h) */
/* intrinsic void __set_PRIMASK( unsigned long ); (see intrinsic.h) */
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
static __INLINE void __enable_fault_irq(void)
{
__ASM ("cpsie f");
}
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
static __INLINE void __disable_fault_irq(void)
{
__ASM ("cpsid f");
}
/* intrinsic unsigned long __get_BASEPRI( void ); (see intrinsic.h) */
/* intrinsic void __set_BASEPRI( unsigned long ); (see intrinsic.h) */
/* intrinsic unsigned long __get_FAULTMASK( void ); (see intrinsic.h) */
/* intrinsic void __set_FAULTMASK(unsigned long); (see intrinsic.h) */
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
static uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1)
__ASM("vmrs r0, fpscr");
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
static void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1)
__ASM("vmsr fpscr, r0");
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#pragma diag_default=Pe940
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* GNU gcc specific functions */
/** \brief Enable IRQ Interrupts
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __enable_irq(void)
{
__ASM volatile ("cpsie i");
}
/** \brief Disable IRQ Interrupts
This function disables IRQ interrupts by setting the I-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __disable_irq(void)
{
__ASM volatile ("cpsid i");
}
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_CONTROL(void)
{
uint32_t result;
__ASM volatile ("MRS %0, control" : "=r" (result) );
return(result);
}
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_CONTROL(uint32_t control)
{
__ASM volatile ("MSR control, %0" : : "r" (control) );
}
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_IPSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, ipsr" : "=r" (result) );
return(result);
}
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_APSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, apsr" : "=r" (result) );
return(result);
}
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_xPSR(void)
{
uint32_t result;
__ASM volatile ("MRS %0, xpsr" : "=r" (result) );
return(result);
}
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PSP(void)
{
register uint32_t result;
__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
return(result);
}
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_PSP(uint32_t topOfProcStack)
{
__ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) );
}
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_MSP(void)
{
register uint32_t result;
__ASM volatile ("MRS %0, msp\n" : "=r" (result) );
return(result);
}
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_MSP(uint32_t topOfMainStack)
{
__ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) );
}
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_PRIMASK(void)
{
uint32_t result;
__ASM volatile ("MRS %0, primask" : "=r" (result) );
return(result);
}
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_PRIMASK(uint32_t priMask)
{
__ASM volatile ("MSR primask, %0" : : "r" (priMask) );
}
#if (__CORTEX_M >= 0x03)
/** \brief Enable FIQ
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __enable_fault_irq(void)
{
__ASM volatile ("cpsie f");
}
/** \brief Disable FIQ
This function disables FIQ interrupts by setting the F-bit in the CPSR.
Can only be executed in Privileged modes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __disable_fault_irq(void)
{
__ASM volatile ("cpsid f");
}
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_BASEPRI(void)
{
uint32_t result;
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
return(result);
}
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_BASEPRI(uint32_t value)
{
__ASM volatile ("MSR basepri, %0" : : "r" (value) );
}
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask register.
\return Fault Mask register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_FAULTMASK(void)
{
uint32_t result;
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
return(result);
}
/** \brief Set Fault Mask
This function assigns the given value to the Fault Mask register.
\param [in] faultMask Fault Mask value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_FAULTMASK(uint32_t faultMask)
{
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) );
}
#endif /* (__CORTEX_M >= 0x03) */
#if (__CORTEX_M == 0x04)
/** \brief Get FPSCR
This function returns the current value of the Floating Point Status/Control register.
\return Floating Point Status/Control register value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __get_FPSCR(void)
{
#if (__FPU_PRESENT == 1)
uint32_t result;
__ASM volatile ("MRS %0, fpscr" : "=r" (result) );
return(result);
#else
return(0);
#endif
}
/** \brief Set FPSCR
This function assigns the given value to the Floating Point Status/Control register.
\param [in] fpscr Floating Point Status/Control value to set
*/
__attribute__( ( always_inline ) ) static __INLINE void __set_FPSCR(uint32_t fpscr)
{
#if (__FPU_PRESENT == 1)
__ASM volatile ("MSR fpscr, %0" : : "r" (fpscr) );
#endif
}
#endif /* (__CORTEX_M == 0x04) */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* TASKING carm specific functions */
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all instrinsics,
* Including the CMSIS ones.
*/
#endif
/*@} end of CMSIS_Core_RegAccFunctions */
#endif /* __CORE_CMFUNC_H__ */

View File

@@ -0,0 +1,775 @@
/**************************************************************************//**
* @file core_cmInstr.h
* @brief CMSIS Cortex-M Core Instruction Access Header File
* @version V2.01
* @date 06. December 2010
*
* @note
* Copyright (C) 2009-2010 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __CORE_CMINSTR_H__
#define __CORE_CMINSTR_H__
/* ########################## Core Instruction Access ######################### */
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
Access to dedicated instructions
@{
*/
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/* ARM armcc specific functions */
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
#define __NOP __nop
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
#define __WFI __wfi
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
#define __WFE __wfe
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
#define __SEV __sev
/** \brief Instruction Synchronization Barrier
Instruction Synchronization Barrier flushes the pipeline in the processor,
so that all instructions following the ISB are fetched from cache or
memory, after the instruction has been completed.
*/
#define __ISB() __isb(0xF)
/** \brief Data Synchronization Barrier
This function acts as a special kind of Data Memory Barrier.
It completes when all explicit memory accesses before this instruction complete.
*/
#define __DSB() __dsb(0xF)
/** \brief Data Memory Barrier
This function ensures the apparent order of the explicit memory operations before
and after the instruction, without ensuring their completion.
*/
#define __DMB() __dmb(0xF)
/** \brief Reverse byte order (32 bit)
This function reverses the byte order in integer value.
\param [in] value Value to reverse
\return Reversed value
*/
#define __REV __rev
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
extern uint32_t __REV16(uint32_t value);
#else /* (__ARMCC_VERSION >= 400677) */
static __INLINE __ASM uint32_t __REV16(uint32_t value)
{
rev16 r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
extern int32_t __REVSH(int32_t value);
#else /* (__ARMCC_VERSION >= 400677) */
static __INLINE __ASM int32_t __REVSH(int32_t value)
{
revsh r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
#define __RBIT __rbit
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
#define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr))
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
#define __LDREXH(ptr) ((uint16_t) __ldrex(ptr))
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
#define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr))
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXB(value, ptr) __strex(value, ptr)
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXH(value, ptr) __strex(value, ptr)
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#define __STREXW(value, ptr) __strex(value, ptr)
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
#if (__ARMCC_VERSION < 400000)
extern void __CLREX(void);
#else /* (__ARMCC_VERSION >= 400000) */
#define __CLREX __clrex
#endif /* __ARMCC_VERSION */
/** \brief Signed Saturate
This function saturates a signed value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (1..32)
\return Saturated value
*/
#define __SSAT __ssat
/** \brief Unsigned Saturate
This function saturates an unsigned value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (0..31)
\return Saturated value
*/
#define __USAT __usat
/** \brief Count leading zeros
This function counts the number of leading zeros of a data value.
\param [in] value Value to count the leading zeros
\return number of leading zeros in value
*/
#define __CLZ __clz
#endif /* (__CORTEX_M >= 0x03) */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* IAR iccarm specific functions */
#include <intrinsics.h> /* IAR Intrinsics */
#pragma diag_suppress=Pe940
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
#define __NOP __no_operation
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
static __INLINE void __WFI(void)
{
__ASM ("wfi");
}
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
static __INLINE void __WFE(void)
{
__ASM ("wfe");
}
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
static __INLINE void __SEV(void)
{
__ASM ("sev");
}
/* intrinsic void __ISB(void) (see intrinsics.h) */
/* intrinsic void __DSB(void) (see intrinsics.h) */
/* intrinsic void __DMB(void) (see intrinsics.h) */
/* intrinsic uint32_t __REV(uint32_t value) (see intrinsics.h) */
/* intrinsic __SSAT (see intrinsics.h) */
/* intrinsic __USAT (see intrinsics.h) */
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
static uint32_t __REV16(uint32_t value)
{
__ASM("rev16 r0, r0");
}
/* intrinsic uint32_t __REVSH(uint32_t value) (see intrinsics.h */
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
static uint32_t __RBIT(uint32_t value)
{
__ASM("rbit r0, r0");
}
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
static uint8_t __LDREXB(volatile uint8_t *addr)
{
__ASM("ldrexb r0, [r0]");
}
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
static uint16_t __LDREXH(volatile uint16_t *addr)
{
__ASM("ldrexh r0, [r0]");
}
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
/* intrinsic unsigned long __LDREX(unsigned long *) (see intrinsics.h) */
static uint32_t __LDREXW(volatile uint32_t *addr)
{
__ASM("ldrex r0, [r0]");
}
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
static uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
__ASM("strexb r0, r0, [r1]");
}
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
static uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
{
__ASM("strexh r0, r0, [r1]");
}
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
/* intrinsic unsigned long __STREX(unsigned long, unsigned long) (see intrinsics.h )*/
static uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
{
__ASM("strex r0, r0, [r1]");
}
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
static __INLINE void __CLREX(void)
{
__ASM ("clrex");
}
/* intrinsic unsigned char __CLZ( unsigned long ) (see intrinsics.h) */
#endif /* (__CORTEX_M >= 0x03) */
#pragma diag_default=Pe940
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* GNU gcc specific functions */
/** \brief No Operation
No Operation does nothing. This instruction can be used for code alignment purposes.
*/
__attribute__( ( always_inline ) ) static __INLINE void __NOP(void)
{
__ASM volatile ("nop");
}
/** \brief Wait For Interrupt
Wait For Interrupt is a hint instruction that suspends execution
until one of a number of events occurs.
*/
__attribute__( ( always_inline ) ) static __INLINE void __WFI(void)
{
__ASM volatile ("wfi");
}
/** \brief Wait For Event
Wait For Event is a hint instruction that permits the processor to enter
a low-power state until one of a number of events occurs.
*/
__attribute__( ( always_inline ) ) static __INLINE void __WFE(void)
{
__ASM volatile ("wfe");
}
/** \brief Send Event
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
*/
__attribute__( ( always_inline ) ) static __INLINE void __SEV(void)
{
__ASM volatile ("sev");
}
/** \brief Instruction Synchronization Barrier
Instruction Synchronization Barrier flushes the pipeline in the processor,
so that all instructions following the ISB are fetched from cache or
memory, after the instruction has been completed.
*/
__attribute__( ( always_inline ) ) static __INLINE void __ISB(void)
{
__ASM volatile ("isb");
}
/** \brief Data Synchronization Barrier
This function acts as a special kind of Data Memory Barrier.
It completes when all explicit memory accesses before this instruction complete.
*/
__attribute__( ( always_inline ) ) static __INLINE void __DSB(void)
{
__ASM volatile ("dsb");
}
/** \brief Data Memory Barrier
This function ensures the apparent order of the explicit memory operations before
and after the instruction, without ensuring their completion.
*/
__attribute__( ( always_inline ) ) static __INLINE void __DMB(void)
{
__ASM volatile ("dmb");
}
/** \brief Reverse byte order (32 bit)
This function reverses the byte order in integer value.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __REV(uint32_t value)
{
uint32_t result;
__ASM volatile ("rev %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __REV16(uint32_t value)
{
uint32_t result;
__ASM volatile ("rev16 %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE int32_t __REVSH(int32_t value)
{
uint32_t result;
__ASM volatile ("revsh %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
#if (__CORTEX_M >= 0x03)
/** \brief Reverse bit order of value
This function reverses the bit order of the given value.
\param [in] value Value to reverse
\return Reversed value
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __RBIT(uint32_t value)
{
uint32_t result;
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
/** \brief LDR Exclusive (8 bit)
This function performs a exclusive LDR command for 8 bit value.
\param [in] ptr Pointer to data
\return value of type uint8_t at (*ptr)
*/
__attribute__( ( always_inline ) ) static __INLINE uint8_t __LDREXB(volatile uint8_t *addr)
{
uint8_t result;
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) );
return(result);
}
/** \brief LDR Exclusive (16 bit)
This function performs a exclusive LDR command for 16 bit values.
\param [in] ptr Pointer to data
\return value of type uint16_t at (*ptr)
*/
__attribute__( ( always_inline ) ) static __INLINE uint16_t __LDREXH(volatile uint16_t *addr)
{
uint16_t result;
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) );
return(result);
}
/** \brief LDR Exclusive (32 bit)
This function performs a exclusive LDR command for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __LDREXW(volatile uint32_t *addr)
{
uint32_t result;
__ASM volatile ("ldrex %0, [%1]" : "=r" (result) : "r" (addr) );
return(result);
}
/** \brief STR Exclusive (8 bit)
This function performs a exclusive STR command for 8 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
{
uint32_t result;
__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}
/** \brief STR Exclusive (16 bit)
This function performs a exclusive STR command for 16 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
{
uint32_t result;
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}
/** \brief STR Exclusive (32 bit)
This function performs a exclusive STR command for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
__attribute__( ( always_inline ) ) static __INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
{
uint32_t result;
__ASM volatile ("strex %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
__attribute__( ( always_inline ) ) static __INLINE void __CLREX(void)
{
__ASM volatile ("clrex");
}
/** \brief Signed Saturate
This function saturates a signed value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (1..32)
\return Saturated value
*/
#define __SSAT(ARG1,ARG2) \
({ \
uint32_t __RES, __ARG1 = (ARG1); \
__ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
__RES; \
})
/** \brief Unsigned Saturate
This function saturates an unsigned value.
\param [in] value Value to be saturated
\param [in] sat Bit position to saturate to (0..31)
\return Saturated value
*/
#define __USAT(ARG1,ARG2) \
({ \
uint32_t __RES, __ARG1 = (ARG1); \
__ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
__RES; \
})
/** \brief Count leading zeros
This function counts the number of leading zeros of a data value.
\param [in] value Value to count the leading zeros
\return number of leading zeros in value
*/
__attribute__( ( always_inline ) ) static __INLINE uint8_t __CLZ(uint32_t value)
{
uint8_t result;
__ASM volatile ("clz %0, %1" : "=r" (result) : "r" (value) );
return(result);
}
#endif /* (__CORTEX_M >= 0x03) */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* TASKING carm specific functions */
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all instrinsics,
* Including the CMSIS ones.
*/
#endif
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
#endif /* __CORE_CMINSTR_H__ */

View File

@@ -0,0 +1,64 @@
/**************************************************************************//**
* @file system_LPC17xx.h
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File
* for the NXP LPC17xx Device Series
* @version V1.02
* @date 08. September 2009
*
* @note
* Copyright (C) 2009 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#ifndef __SYSTEM_LPC17xx_H
#define __SYSTEM_LPC17xx_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System and update the SystemCoreClock variable.
*/
extern void SystemInit (void);
/**
* Update SystemCoreClock variable
*
* @param none
* @return none
*
* @brief Updates the SystemCoreClock with current core Clock
* retrieved from cpu registers.
*/
extern void SystemCoreClockUpdate (void);
#ifdef __cplusplus
}
#endif
#endif /* __SYSTEM_LPC17xx_H */

View File

@@ -0,0 +1,339 @@
/**************************************************************************//**
* @file core_cm3.c
* @brief CMSIS Cortex-M3 Core Peripheral Access Layer Source File
* @version V2.00
* @date 13. September 2010
*
* @note
* Copyright (C) 2009-2010 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#include <stdint.h>
/* define compiler specific symbols */
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only avaiable in High optimization mode! */
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
#endif
/* ########################## Core Instruction Access ######################### */
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/** \brief Reverse byte order (16 bit)
This function reverses the byte order in two unsigned short values.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
__ASM uint32_t __REV16(uint32_t value)
{
rev16 r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Reverse byte order in signed short value
This function reverses the byte order in a signed short value with sign extension to integer.
\param [in] value Value to reverse
\return Reversed value
*/
#if (__ARMCC_VERSION < 400677)
__ASM int32_t __REVSH(int32_t value)
{
revsh r0, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Remove the exclusive lock
This function removes the exclusive lock which is created by LDREX.
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __CLREX(void)
{
clrex
}
#endif /* __ARMCC_VERSION */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* obsolete */
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* obsolete */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* obsolete */
#endif
/* ########################### Core Function Access ########################### */
#if defined ( __CC_ARM ) /*------------------ RealView Compiler ----------------*/
/** \brief Get Control Register
This function returns the content of the Control Register.
\return Control Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_CONTROL(void)
{
mrs r0, control
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Control Register
This function writes the given value to the Control Register.
\param [in] control Control Register value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_CONTROL(uint32_t control)
{
msr control, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get ISPR Register
This function returns the content of the ISPR Register.
\return ISPR Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_IPSR(void)
{
mrs r0, ipsr
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get APSR Register
This function returns the content of the APSR Register.
\return APSR Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_APSR(void)
{
mrs r0, apsr
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get xPSR Register
This function returns the content of the xPSR Register.
\return xPSR Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_xPSR(void)
{
mrs r0, xpsr
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Process Stack Pointer
This function returns the current value of the Process Stack Pointer (PSP).
\return PSP Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_PSP(void)
{
mrs r0, psp
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Process Stack Pointer
This function assigns the given value to the Process Stack Pointer (PSP).
\param [in] topOfProcStack Process Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_PSP(uint32_t topOfProcStack)
{
msr psp, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Main Stack Pointer
This function returns the current value of the Main Stack Pointer (MSP).
\return MSP Register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_MSP(void)
{
mrs r0, msp
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Main Stack Pointer
This function assigns the given value to the Main Stack Pointer (MSP).
\param [in] topOfMainStack Main Stack Pointer value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_MSP(uint32_t mainStackPointer)
{
msr msp, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Base Priority
This function returns the current value of the Base Priority register.
\return Base Priority register value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_BASEPRI(void)
{
mrs r0, basepri
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Base Priority
This function assigns the given value to the Base Priority register.
\param [in] basePri Base Priority value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_BASEPRI(uint32_t basePri)
{
msr basepri, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Priority Mask
This function returns the current state of the priority mask bit from the Priority Mask Register.
\return Priority Mask value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_PRIMASK(void)
{
mrs r0, primask
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set Priority Mask
This function assigns the given value to the Priority Mask Register.
\param [in] priMask Priority Mask
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_PRIMASK(uint32_t priMask)
{
msr primask, r0
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Get Fault Mask
This function returns the current value of the Fault Mask Register.
\return Fault Mask value
*/
#if (__ARMCC_VERSION < 400000)
__ASM uint32_t __get_FAULTMASK(void)
{
mrs r0, faultmask
bx lr
}
#endif /* __ARMCC_VERSION */
/** \brief Set the Fault Mask
This function assigns the given value to the Fault Mask Register.
\param [in] faultMask Fault Mask value value to set
*/
#if (__ARMCC_VERSION < 400000)
__ASM void __set_FAULTMASK(uint32_t faultMask)
{
msr faultmask, r0
bx lr
}
#endif /* __ARMCC_VERSION */
#elif (defined (__ICCARM__)) /*---------------- ICC Compiler ---------------------*/
/* obsolete */
#elif (defined (__GNUC__)) /*------------------ GNU Compiler ---------------------*/
/* obsolete */
#elif (defined (__TASKING__)) /*--------------- TASKING Compiler -----------------*/
/* obsolete */
#endif

View File

@@ -0,0 +1,532 @@
/**************************************************************************//**
* @file system_LPC17xx.c
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer Source File
* for the NXP LPC17xx Device Series
* @version V1.08
* @date 12. May 2010
*
* @note
* Copyright (C) 2009 ARM Limited. All rights reserved.
*
* @par
* ARM Limited (ARM) is supplying this software for use with Cortex-M
* processor based microcontrollers. This file can be freely distributed
* within development tools that are supporting such ARM based processors.
*
* @par
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
* ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
*
******************************************************************************/
#include <stdint.h>
#include "LPC17xx.h"
/*
//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
*/
/*--------------------- Clock Configuration ----------------------------------
//
// <e> Clock Configuration
// <h> System Controls and Status Register (SCS)
// <o1.4> OSCRANGE: Main Oscillator Range Select
// <0=> 1 MHz to 20 MHz
// <1=> 15 MHz to 24 MHz
// <e1.5> OSCEN: Main Oscillator Enable
// </e>
// </h>
//
// <h> Clock Source Select Register (CLKSRCSEL)
// <o2.0..1> CLKSRC: PLL Clock Source Selection
// <0=> Internal RC oscillator
// <1=> Main oscillator
// <2=> RTC oscillator
// </h>
//
// <e3> PLL0 Configuration (Main PLL)
// <h> PLL0 Configuration Register (PLL0CFG)
// <i> F_cco0 = (2 * M * F_in) / N
// <i> F_in must be in the range of 32 kHz to 50 MHz
// <i> F_cco0 must be in the range of 275 MHz to 550 MHz
// <o4.0..14> MSEL: PLL Multiplier Selection
// <6-32768><#-1>
// <i> M Value
// <o4.16..23> NSEL: PLL Divider Selection
// <1-256><#-1>
// <i> N Value
// </h>
// </e>
//
// <e5> PLL1 Configuration (USB PLL)
// <h> PLL1 Configuration Register (PLL1CFG)
// <i> F_usb = M * F_osc or F_usb = F_cco1 / (2 * P)
// <i> F_cco1 = F_osc * M * 2 * P
// <i> F_cco1 must be in the range of 156 MHz to 320 MHz
// <o6.0..4> MSEL: PLL Multiplier Selection
// <1-32><#-1>
// <i> M Value (for USB maximum value is 4)
// <o6.5..6> PSEL: PLL Divider Selection
// <0=> 1
// <1=> 2
// <2=> 4
// <3=> 8
// <i> P Value
// </h>
// </e>
//
// <h> CPU Clock Configuration Register (CCLKCFG)
// <o7.0..7> CCLKSEL: Divide Value for CPU Clock from PLL0
// <1-256><#-1>
// </h>
//
// <h> USB Clock Configuration Register (USBCLKCFG)
// <o8.0..3> USBSEL: Divide Value for USB Clock from PLL0
// <0-15>
// <i> Divide is USBSEL + 1
// </h>
//
// <h> Peripheral Clock Selection Register 0 (PCLKSEL0)
// <o9.0..1> PCLK_WDT: Peripheral Clock Selection for WDT
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.2..3> PCLK_TIMER0: Peripheral Clock Selection for TIMER0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.4..5> PCLK_TIMER1: Peripheral Clock Selection for TIMER1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.6..7> PCLK_UART0: Peripheral Clock Selection for UART0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.8..9> PCLK_UART1: Peripheral Clock Selection for UART1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.12..13> PCLK_PWM1: Peripheral Clock Selection for PWM1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.14..15> PCLK_I2C0: Peripheral Clock Selection for I2C0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.16..17> PCLK_SPI: Peripheral Clock Selection for SPI
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.20..21> PCLK_SSP1: Peripheral Clock Selection for SSP1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.22..23> PCLK_DAC: Peripheral Clock Selection for DAC
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.24..25> PCLK_ADC: Peripheral Clock Selection for ADC
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o9.26..27> PCLK_CAN1: Peripheral Clock Selection for CAN1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 6
// <o9.28..29> PCLK_CAN2: Peripheral Clock Selection for CAN2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 6
// <o9.30..31> PCLK_ACF: Peripheral Clock Selection for ACF
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 6
// </h>
//
// <h> Peripheral Clock Selection Register 1 (PCLKSEL1)
// <o10.0..1> PCLK_QEI: Peripheral Clock Selection for the Quadrature Encoder Interface
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.2..3> PCLK_GPIO: Peripheral Clock Selection for GPIOs
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.4..5> PCLK_PCB: Peripheral Clock Selection for the Pin Connect Block
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.6..7> PCLK_I2C1: Peripheral Clock Selection for I2C1
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.10..11> PCLK_SSP0: Peripheral Clock Selection for SSP0
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.12..13> PCLK_TIMER2: Peripheral Clock Selection for TIMER2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.14..15> PCLK_TIMER3: Peripheral Clock Selection for TIMER3
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.16..17> PCLK_UART2: Peripheral Clock Selection for UART2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.18..19> PCLK_UART3: Peripheral Clock Selection for UART3
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.20..21> PCLK_I2C2: Peripheral Clock Selection for I2C2
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.22..23> PCLK_I2S: Peripheral Clock Selection for I2S
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.26..27> PCLK_RIT: Peripheral Clock Selection for the Repetitive Interrupt Timer
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.28..29> PCLK_SYSCON: Peripheral Clock Selection for the System Control Block
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// <o10.30..31> PCLK_MC: Peripheral Clock Selection for the Motor Control PWM
// <0=> Pclk = Cclk / 4
// <1=> Pclk = Cclk
// <2=> Pclk = Cclk / 2
// <3=> Pclk = Hclk / 8
// </h>
//
// <h> Power Control for Peripherals Register (PCONP)
// <o11.1> PCTIM0: Timer/Counter 0 power/clock enable
// <o11.2> PCTIM1: Timer/Counter 1 power/clock enable
// <o11.3> PCUART0: UART 0 power/clock enable
// <o11.4> PCUART1: UART 1 power/clock enable
// <o11.6> PCPWM1: PWM 1 power/clock enable
// <o11.7> PCI2C0: I2C interface 0 power/clock enable
// <o11.8> PCSPI: SPI interface power/clock enable
// <o11.9> PCRTC: RTC power/clock enable
// <o11.10> PCSSP1: SSP interface 1 power/clock enable
// <o11.12> PCAD: A/D converter power/clock enable
// <o11.13> PCCAN1: CAN controller 1 power/clock enable
// <o11.14> PCCAN2: CAN controller 2 power/clock enable
// <o11.15> PCGPIO: GPIOs power/clock enable
// <o11.16> PCRIT: Repetitive interrupt timer power/clock enable
// <o11.17> PCMC: Motor control PWM power/clock enable
// <o11.18> PCQEI: Quadrature encoder interface power/clock enable
// <o11.19> PCI2C1: I2C interface 1 power/clock enable
// <o11.21> PCSSP0: SSP interface 0 power/clock enable
// <o11.22> PCTIM2: Timer 2 power/clock enable
// <o11.23> PCTIM3: Timer 3 power/clock enable
// <o11.24> PCUART2: UART 2 power/clock enable
// <o11.25> PCUART3: UART 3 power/clock enable
// <o11.26> PCI2C2: I2C interface 2 power/clock enable
// <o11.27> PCI2S: I2S interface power/clock enable
// <o11.29> PCGPDMA: GP DMA function power/clock enable
// <o11.30> PCENET: Ethernet block power/clock enable
// <o11.31> PCUSB: USB interface power/clock enable
// </h>
//
// <h> Clock Output Configuration Register (CLKOUTCFG)
// <o12.0..3> CLKOUTSEL: Selects clock source for CLKOUT
// <0=> CPU clock
// <1=> Main oscillator
// <2=> Internal RC oscillator
// <3=> USB clock
// <4=> RTC oscillator
// <o12.4..7> CLKOUTDIV: Selects clock divider for CLKOUT
// <1-16><#-1>
// <o12.8> CLKOUT_EN: CLKOUT enable control
// </h>
//
// </e>
*/
#define CLOCK_SETUP 1
#define SCS_Val 0x00000020
#define CLKSRCSEL_Val 0x00000001
#define PLL0_SETUP 1
#define PLL0CFG_Val 0x00050063
#define PLL1_SETUP 1
#define PLL1CFG_Val 0x00000023
#define CCLKCFG_Val 0x00000003
#define USBCLKCFG_Val 0x00000000
#define PCLKSEL0_Val 0x00000000
#define PCLKSEL1_Val 0x00000000
#define PCONP_Val 0x042887DE
#define CLKOUTCFG_Val 0x00000000
/*--------------------- Flash Accelerator Configuration ----------------------
//
// <e> Flash Accelerator Configuration
// <o1.12..15> FLASHTIM: Flash Access Time
// <0=> 1 CPU clock (for CPU clock up to 20 MHz)
// <1=> 2 CPU clocks (for CPU clock up to 40 MHz)
// <2=> 3 CPU clocks (for CPU clock up to 60 MHz)
// <3=> 4 CPU clocks (for CPU clock up to 80 MHz)
// <4=> 5 CPU clocks (for CPU clock up to 100 MHz)
// <5=> 6 CPU clocks (for any CPU clock)
// </e>
*/
#define FLASH_SETUP 0
#define FLASHCFG_Val 0x00004000
/*
//-------- <<< end of configuration section >>> ------------------------------
*/
/*----------------------------------------------------------------------------
Check the register settings
*----------------------------------------------------------------------------*/
#define CHECK_RANGE(val, min, max) ((val < min) || (val > max))
#define CHECK_RSVD(val, mask) (val & mask)
/* Clock Configuration -------------------------------------------------------*/
#if (CHECK_RSVD((SCS_Val), ~0x00000030))
#error "SCS: Invalid values of reserved bits!"
#endif
#if (CHECK_RANGE((CLKSRCSEL_Val), 0, 2))
#error "CLKSRCSEL: Value out of range!"
#endif
#if (CHECK_RSVD((PLL0CFG_Val), ~0x00FF7FFF))
#error "PLL0CFG: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PLL1CFG_Val), ~0x0000007F))
#error "PLL1CFG: Invalid values of reserved bits!"
#endif
#if (PLL0_SETUP) /* if PLL0 is used */
#if (CCLKCFG_Val < 2) /* CCLKSEL must be greater then 1 */
#error "CCLKCFG: CCLKSEL must be greater then 1 if PLL0 is used!"
#endif
#endif
#if (CHECK_RANGE((CCLKCFG_Val), 2, 255))
#error "CCLKCFG: Value out of range!"
#endif
#if (CHECK_RSVD((USBCLKCFG_Val), ~0x0000000F))
#error "USBCLKCFG: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCLKSEL0_Val), 0x000C0C00))
#error "PCLKSEL0: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCLKSEL1_Val), 0x03000300))
#error "PCLKSEL1: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((PCONP_Val), 0x10100821))
#error "PCONP: Invalid values of reserved bits!"
#endif
#if (CHECK_RSVD((CLKOUTCFG_Val), ~0x000001FF))
#error "CLKOUTCFG: Invalid values of reserved bits!"
#endif
/* Flash Accelerator Configuration -------------------------------------------*/
#if (CHECK_RSVD((FLASHCFG_Val), ~0x0000F000))
#error "FLASHCFG: Invalid values of reserved bits!"
#endif
/*----------------------------------------------------------------------------
DEFINES
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
Define clocks
*----------------------------------------------------------------------------*/
#define XTAL (12000000UL) /* Oscillator frequency */
#define OSC_CLK ( XTAL) /* Main oscillator frequency */
#define RTC_CLK ( 32000UL) /* RTC oscillator frequency */
#define IRC_OSC ( 4000000UL) /* Internal RC oscillator frequency */
/* F_cco0 = (2 * M * F_in) / N */
#define __M (((PLL0CFG_Val ) & 0x7FFF) + 1)
#define __N (((PLL0CFG_Val >> 16) & 0x00FF) + 1)
#define __FCCO(__F_IN) ((2/*ULL*/ * __M * __F_IN) / __N)
#define __CCLK_DIV (((CCLKCFG_Val ) & 0x00FF) + 1)
/* Determine core clock frequency according to settings */
#if (PLL0_SETUP)
#if ((CLKSRCSEL_Val & 0x03) == 1)
#define __CORE_CLK (__FCCO(OSC_CLK) / __CCLK_DIV)
#elif ((CLKSRCSEL_Val & 0x03) == 2)
#define __CORE_CLK (__FCCO(RTC_CLK) / __CCLK_DIV)
#else
#define __CORE_CLK (__FCCO(IRC_OSC) / __CCLK_DIV)
#endif
#else
#if ((CLKSRCSEL_Val & 0x03) == 1)
#define __CORE_CLK (OSC_CLK / __CCLK_DIV)
#elif ((CLKSRCSEL_Val & 0x03) == 2)
#define __CORE_CLK (RTC_CLK / __CCLK_DIV)
#else
#define __CORE_CLK (IRC_OSC / __CCLK_DIV)
#endif
#endif
/*----------------------------------------------------------------------------
Clock Variable definitions
*----------------------------------------------------------------------------*/
uint32_t SystemCoreClock = __CORE_CLK;/*!< System Clock Frequency (Core Clock)*/
/*----------------------------------------------------------------------------
Clock functions
*----------------------------------------------------------------------------*/
void SystemCoreClockUpdate (void) /* Get Core Clock Frequency */
{
/* Determine clock frequency according to clock register values */
if (((LPC_SC->PLL0STAT >> 24) & 3) == 3) { /* If PLL0 enabled and connected */
switch (LPC_SC->CLKSRCSEL & 0x03) {
case 0: /* Int. RC oscillator => PLL0 */
case 3: /* Reserved, default to Int. RC */
SystemCoreClock = (IRC_OSC *
((2/*ULL*/ * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) /
(((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) /
((LPC_SC->CCLKCFG & 0xFF)+ 1));
break;
case 1: /* Main oscillator => PLL0 */
SystemCoreClock = (OSC_CLK *
((2/*ULL*/ * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) /
(((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) /
((LPC_SC->CCLKCFG & 0xFF)+ 1));
break;
case 2: /* RTC oscillator => PLL0 */
SystemCoreClock = (RTC_CLK *
((2/*ULL*/ * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) /
(((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) /
((LPC_SC->CCLKCFG & 0xFF)+ 1));
break;
}
} else {
switch (LPC_SC->CLKSRCSEL & 0x03) {
case 0: /* Int. RC oscillator => PLL0 */
case 3: /* Reserved, default to Int. RC */
SystemCoreClock = IRC_OSC / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
break;
case 1: /* Main oscillator => PLL0 */
SystemCoreClock = OSC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
break;
case 2: /* RTC oscillator => PLL0 */
SystemCoreClock = RTC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
break;
}
}
}
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System.
*/
void SystemInit (void)
{
#if (CLOCK_SETUP) /* Clock Setup */
LPC_SC->SCS = SCS_Val;
if (SCS_Val & (1 << 5)) { /* If Main Oscillator is enabled */
while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready */
}
LPC_SC->CCLKCFG = CCLKCFG_Val; /* Setup Clock Divider */
LPC_SC->PCLKSEL0 = PCLKSEL0_Val; /* Peripheral Clock Selection */
LPC_SC->PCLKSEL1 = PCLKSEL1_Val;
LPC_SC->CLKSRCSEL = CLKSRCSEL_Val; /* Select Clock Source for PLL0 */
#if (PLL0_SETUP)
LPC_SC->PLL0CFG = PLL0CFG_Val; /* configure PLL0 */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
LPC_SC->PLL0CON = 0x01; /* PLL0 Enable */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0 */
LPC_SC->PLL0CON = 0x03; /* PLL0 Enable & Connect */
LPC_SC->PLL0FEED = 0xAA;
LPC_SC->PLL0FEED = 0x55;
while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24))));/* Wait for PLLC0_STAT & PLLE0_STAT */
#endif
#if (PLL1_SETUP)
LPC_SC->PLL1CFG = PLL1CFG_Val;
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
LPC_SC->PLL1CON = 0x01; /* PLL1 Enable */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1 */
LPC_SC->PLL1CON = 0x03; /* PLL1 Enable & Connect */
LPC_SC->PLL1FEED = 0xAA;
LPC_SC->PLL1FEED = 0x55;
while (!(LPC_SC->PLL1STAT & ((1<< 9) | (1<< 8))));/* Wait for PLLC1_STAT & PLLE1_STAT */
#else
LPC_SC->USBCLKCFG = USBCLKCFG_Val; /* Setup USB Clock Divider */
#endif
LPC_SC->PCONP = PCONP_Val; /* Power Control for Peripherals */
LPC_SC->CLKOUTCFG = CLKOUTCFG_Val; /* Clock Output Configuration */
#endif
#if (FLASH_SETUP == 1) /* Flash Accelerator Setup */
LPC_SC->FLASHCFG = (LPC_SC->FLASHCFG & ~0x0000F000) | FLASHCFG_Val;
#endif
}

View File

@@ -0,0 +1,94 @@
ifeq ($(TARGET_NAME),)
TARGET_NAME=boot
endif
ifeq ($(ATOMTHREADS),)
ATOMTHREADS = $(shell pwd)/../../
endif
ifeq ($(TEST_NAME),)
TEST_NAME = kern1
endif
CC = arm-none-eabi-gcc
LN = arm-none-eabi-gcc
AS = arm-none-eabi-gcc
CFLAGS := $(CFLAGS) -O3 -Os -g3 -Wall -c -mcpu=cortex-m3 -mthumb
AFLAGS := $(AFLAGS) -O3 -Os -g3 -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -fdata-sections -mcpu=cortex-m3 -mthumb
LFLAGS := $(LFLAGS) -O3 -Os -Wall -mcpu=cortex-m3 -mthumb -Wl,-Map=system.map -Tsystem.ld
CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' -DBOARD_MBED_LP1768
ADEFS := $(ADEFS) -D__thumb2__ -DARM_RDI_MONITOR
LLIBS := $(LLIBS)
SRCS := $(SRCS) \
./CMSISv2p00_LPC17xx/src/core_cm3.c \
./CMSISv2p00_LPC17xx/src/system_LPC17xx.c \
./drivers/lpc17xx_uart.c \
startup.c \
modules.c \
$(ATOMTHREADS)/tests/$(TEST_NAME).c \
main.c \
ASMS := $(ASMS) \
INCLUDES := $(INCLUDES) \
-I$(ATOMTHREADS)/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc \
-I$(ATOMTHREADS)/platforms/lpc17xx \
-I$(ATOMTHREADS)
include $(ATOMTHREADS)/ports/cortex_m/Makefile
OBJS = $(SRCS:.c=.o) $(ASMS:.S=.o)
include ../rules.mk
run_test: clean all
cp boot.bin bin/$(TEST_NAME).bin
all_tests:
echo "Starting atomthreads test suite"
make run_test "TEST_NAME=mutex1"
make run_test "TEST_NAME=mutex2"
make run_test "TEST_NAME=mutex3"
make run_test "TEST_NAME=mutex4"
make run_test "TEST_NAME=mutex5"
make run_test "TEST_NAME=mutex6"
make run_test "TEST_NAME=mutex7"
make run_test "TEST_NAME=mutex8"
make run_test "TEST_NAME=mutex9"
make run_test "TEST_NAME=kern1"
make run_test "TEST_NAME=kern2"
make run_test "TEST_NAME=kern3"
make run_test "TEST_NAME=kern4"
make run_test "TEST_NAME=timer1"
make run_test "TEST_NAME=timer2"
make run_test "TEST_NAME=timer3"
make run_test "TEST_NAME=timer4"
make run_test "TEST_NAME=timer5"
make run_test "TEST_NAME=timer6"
make run_test "TEST_NAME=timer7"
make run_test "TEST_NAME=queue1"
make run_test "TEST_NAME=queue2"
make run_test "TEST_NAME=queue3"
make run_test "TEST_NAME=queue4"
make run_test "TEST_NAME=queue5"
make run_test "TEST_NAME=queue6"
make run_test "TEST_NAME=queue7"
make run_test "TEST_NAME=queue8"
make run_test "TEST_NAME=queue9"
make run_test "TEST_NAME=sem1"
make run_test "TEST_NAME=sem2"
make run_test "TEST_NAME=sem3"
make run_test "TEST_NAME=sem4"
make run_test "TEST_NAME=sem5"
make run_test "TEST_NAME=sem6"
make run_test "TEST_NAME=sem7"
make run_test "TEST_NAME=sem8"
make run_test "TEST_NAME=sem9"

24
platforms/lpc17xx/README Normal file
View File

@@ -0,0 +1,24 @@
---------------------------------------------------------------------------
Library: Atomthreads NXP LPC17xx Platform.
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
NXP LPC17xx Platform
The "lpc17xx" platform contains sources for building the Atomthreads test
suite for the NXP LPC17xx microcontroller.
The build was tested on the "mbed NXP LPC1768" board (http://www.mbed.org)
but it should work on any LPC17xx development board where UART0 can be used
to monitor the output of the test.
The NXP LPC17xx microcontrollers use the ARM Cortex M3 processor core. The
source code in this example uses the ARM CMSIS Cortex-M Access Library V2.01
to initialize the platform and Newlib as the runtime library. Also it uses a
driver provided by NXP for the UART. The CMSIS library and the UART driver
are provided as source with the sample and Newlib is expected to be installed
together with the GNU ARM tool chain.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/**************************************************************************//**
* @file lpc17xx_uart.c
* @brief Drivers for UART peripheral in lpc17xx.
* @version 1.0
* @date 18. Nov. 2010
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include "lpc17xx_uart.h"
#include "lpc17xx.h"
/**
* @brief Initializes the UART0.
*
* @param baudrate: Specifies the baud rate
* @retval None
*/
void LPC17xx_UART_Init(uint32_t baudrate)
{
uint32_t Fdiv;
uint32_t pclkdiv, pclk;
/***/
LPC_PINCON->PINSEL0 &= ~0x000000F0;
LPC_PINCON->PINSEL0 |= 0x00000050; /* RxD0 and TxD0 */
/* PCLK_UART0=CCLK/2 */
//**LPC_SC->PCLKSEL1 &= ~(3<<6); /* PCLK_UART0 = CCLK/4 (18MHz) */
//**LPC_SC->PCLKSEL1 |= (2<<6); /* PCLK_UART0 = CCLK/2 (36MHz) */
//**pclk = SystemCoreClock/2;
/* By default, the PCLKSELx value is zero, thus, the PCLK for
all the peripherals is 1/4 of the SystemFrequency. */
/* Bit 6~7 is for UART0 */
pclkdiv = (LPC_SC->PCLKSEL0 >> 6) & 0x03;
switch ( pclkdiv )
{
case 0x00:
default:
pclk = SystemCoreClock/4;
break;
case 0x01:
pclk = SystemCoreClock;
break;
case 0x02:
pclk = SystemCoreClock/2;
break;
case 0x03:
pclk = SystemCoreClock/8;
break;
}
LPC_UART0->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
Fdiv = ( pclk / 16 ) / baudrate ; /*baud rate */
LPC_UART0->DLM = Fdiv / 256;
LPC_UART0->DLL = Fdiv % 256;
LPC_UART0->LCR = 0x03; /* DLAB = 0 */
LPC_UART0->FCR = 0x07; /* Enable and reset TX and RX FIFO. */
}
/**
* @brief Write one character to UART0.
*
* @param ch: Character to be written
* @retval None
*/
void LPC17xx_UART_PutChar (uint8_t ch)
{
while (!(LPC_UART0->LSR & 0x20));
LPC_UART0->THR = ch;
}
/**
* @brief Read one character from UART0 (blocking read).
*
* @param None
* @retval Received character
*/
uint8_t LPC17xx_UART_GetChar (void)
{
while (!(LPC_UART0->LSR & 0x01));
return (LPC_UART0->RBR);
}
/**
* @brief Read one character from UART0 (non blocking read).
*
* @param None
* @retval Received character
*/
uint8_t LPC17xx_UART_GetChar_nb (void)
{
if (LPC_UART0->LSR & 0x01)
return (LPC_UART0->RBR);
else
return 0;
}
/**
* @brief Write a string to UART0.
*
* @param str: NULL-terminated char string to be written
* @retval None
*/
void LPC17xx_UART_PutString (uint8_t *str)
{
/* usage: LPC1700_UART_Printf("xxx\n\r");*/
#if 1
while (*str != 0)
{
LPC17xx_UART_PutChar(*str++);
}
#else
/* usage: LPC1700_UART_Printf("xxx\n");*/
while ((*str) != 0) {
if (*str == '\n') {
LPC17xx_UART_PutChar(*str++);
LPC17xx_UART_PutChar('\r');
} else {
LPC17xx_UART_PutChar(*str++);
}
}
#endif
}
/**
* @brief Write a buffer to UART0.
*
* @param buffer: buffer to be written
* @retval None
*/
void LPC17xx_UART_WriteBuffer (uint8_t *buffer, uint32_t len)
{
while (len-- != 0) {
LPC17xx_UART_PutChar(*buffer++);
}
}
/**
* @brief Print formatted string. This function takes variable length arguments.
*
* @param format
* @param ...
* @retval None
*
* Note: using library functions "vsprintf" will increase the RO size by about 6KB
*/
//void LPC17xx_UART_Printf (const uint8_t *format, ...)
//{
// static uint8_t buffer[40 + 1];
// va_list vArgs;
//
// va_start(vArgs, format);
// vsprintf((char *)buffer, (char const *)format, vArgs);
// va_end(vArgs);
// LPC17xx_UART_PutString((uint8_t *) buffer);
//}
/* --------------------------------- End Of File ------------------------------ */

View File

@@ -0,0 +1,37 @@
/**************************************************************************//**
* @file lpc17xx_uart.h
* @brief Header file for lpc17xx_uart.c.
* @version 1.0
* @date 18. Nov. 2010
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
#ifndef __LPC17xx_UART_H_
#define __LPC17xx_UART_H_
#include <stdint.h>
/* external functions */
void LPC17xx_UART_PutChar (uint8_t);
uint8_t LPC17xx_UART_GetChar (void);
void LPC17xx_UART_Init(uint32_t baudrate);
void LPC17xx_UART_PutString (uint8_t *str) ;
void LPC17xx_UART_WriteBuffer (uint8_t *buffer, uint32_t len) ;
#endif // __LPC17xx_UART_H_
/* --------------------------------- End Of File ------------------------------ */

122
platforms/lpc17xx/main.c Normal file
View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "LPC17xx.h"
#include "drivers/lpc17xx_uart.h"
#include "modules.h"
#include "atom.h"
#include "tests/atomtests.h"
#ifndef ATOMTHREADS_TEST
#define ATOMTHREADS_TEST "kern1"
#endif
// for mbed board
#define MBED_LED1_GPIO (1 << 18)
#define MBED_LED2_GPIO (1 << 20)
#define MBED_LED3_GPIO (1 << 21)
#define MBED_LED4_GPIO (1 << 23)
#define MBED_LED_GET(led) (LPC_GPIO1->FIOSET & led)
#define MBED_LED_SET(led, on) { if (on) LPC_GPIO1->FIOSET = led ; else LPC_GPIO1->FIOCLR = led ; }
#define MBED_LED_TOGGLE(led) MBED_LED_SET(led, !MBED_LED_GET(led))
#define MBED_LED_COUNT(count) MBED_LED_SET(MBED_LED1_GPIO, count & 1) ; MBED_LED_SET(MBED_LED2_GPIO, count & 2) ; \
MBED_LED_SET(MBED_LED3_GPIO, count & 4) ; MBED_LED_SET(MBED_LED4_GPIO, count & 8) ;
#define TEST_STACK_BYTE_SIZE 512
#define IDLE_STACK_BYTE_SIZE 128
static unsigned char test_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
ATOM_TCB test_tcb ;
/**
* \b test_thread
*
* Function calling the test function of the Atomthreads test suite.
*
*/
void
test_thread (uint32_t param)
{
uint32_t failures ;
CRITICAL_STORE ;
failures = test_start () ;
atomTimerDelay (10) ;
CRITICAL_START() ;
dbg_format_msg ("%s %s\r\n", ATOMTHREADS_TEST, failures ? "FAIL" : "PASS") ;
CRITICAL_END() ;
while(1) {
#ifdef BOARD_MBED_LP1768
MBED_LED_TOGGLE(MBED_LED1_GPIO) ;
#endif
atomTimerDelay (65) ;
}
}
/**
* \b main
*
* Initialize atomthreads and start a test_thread to run the Atomthreads test suite.
*
*/
int
main(void)
{
#ifdef BOARD_MBED_LP1768
LPC_GPIO1->FIODIR |= MBED_LED1_GPIO | MBED_LED2_GPIO | MBED_LED3_GPIO | MBED_LED4_GPIO ;
MBED_LED_SET(MBED_LED1_GPIO | MBED_LED2_GPIO | MBED_LED3_GPIO | MBED_LED4_GPIO, 1);
#endif
dbg_format_msg ("\r\nLPC17xx SystemCoreClock = %d\r\n",SystemCoreClock) ;
//atomthreads_stress_test (36) ;
dbg_format_msg ("Atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ;
atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, TRUE) ;
atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0,
&test_stack[0], TEST_STACK_BYTE_SIZE, TRUE);
atomOSStart() ;
while(1) ;
return 0 ;
}

179
platforms/lpc17xx/modules.c Normal file
View File

@@ -0,0 +1,179 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "modules.h"
#include <stdio.h>
#include <stdarg.h>
#include "atomport_private.h"
#include "atom.h"
#include "atomport.h"
/**
* \b dbg_format_msg
*
* Same as printf.
*
*/
void
dbg_format_msg (char *format, ...)
{
va_list args;
static char msg[256] ;
//CRITICAL_STORE ;
va_start (args, format) ;
//CRITICAL_START() ;
vsniprintf ((char*)msg, 256, (char*)format, args) ;
LPC17xx_UART_PutString (msg) ;
//CRITICAL_END() ;
}
/**
* \b low_level_init
*
* Initializes the PIC and start the system timer tick intrerupt.
*
*/
int
low_level_init (void)
{
SystemInit () ;
SystemCoreClockUpdate ();
//contextInit () ;
NVIC_SetPriority (PendSV_IRQn, 0xFF) ;
LPC17xx_UART_Init (115200) ;
SysTick_Config (1000000) ;
return 0 ;
}
/**
* \b __context_preempt_handler
*
* System timer tic interupt handler.
*
*/
void
__context_tick_handler (void)
{
/* Call the interrupt enter routine */
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
/**
* \b dbg_mem_dump_40
*
* Dumps size bytes of memory from data.
*
*/
void dbg_mem_dump_40 (unsigned int* data, int size)
{
int j ;
dbg_format_msg ("Dump %d bytes at %.8X:\r\n",size * 4, (unsigned int)data) ;
data = (unsigned int*)((unsigned int)data & ~0x3) ;
for (j=0; j<size-3; j+=4) {
dbg_format_msg (" :%.8X: %.8X %.8X %.8X %.8X\r\n", (unsigned int)&data[j], data[j+0], data[j+1], data[j+2], data[j+3]) ;
}
if (size-j == 3) {
dbg_format_msg (" :%.8X: %.8X %.8X %.8X\r\n", (unsigned int)&data[j], data[j+0], data[j+1], data[j+2]) ;
} else if (size-j == 2) {
dbg_format_msg (" :%.8X: %.8X %.8X\r\n", (unsigned int)&data[j], data[j+0], data[j+1]) ;
} else if (size-j == 1) {
dbg_format_msg (" :%.8X: %.8X\r\n", (unsigned int)&data[j], data[j+0]) ;
}
}
/**
* \b dbg_fault_handler
*
* Prints cortex m exception debug information.
*
*/
void
dbg_fault_handler (unsigned int * hardfault_args)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
dbg_format_msg ("\r\n\r\n[Hard fault handler - all numbers in hex]\r\n");
dbg_format_msg ("SP = 0x%x\r\n", hardfault_args);
dbg_format_msg ("R0 = 0x%x\r\n", stacked_r0);
dbg_format_msg ("R1 = 0x%x\r\n", stacked_r1);
dbg_format_msg ("R2 = 0x%x\r\n", stacked_r2);
dbg_format_msg ("R3 = 0x%x\r\n", stacked_r3);
dbg_format_msg ("R12 = 0x%x\r\n", stacked_r12);
dbg_format_msg ("LR [R14] = 0x%x subroutine call return address\r\n", stacked_lr);
dbg_format_msg ("PC [R15] = 0x%x program counter\r\n", stacked_pc);
dbg_format_msg ("PSR = 0x%x\r\n", stacked_psr);
//printf ("BFAR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED38))));
//printf ("CFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED28))));
//printf ("HFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED2C))));
//printf ("DFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED30))));
//printf ("AFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED3C))));
// printf ("SCB_SHCSR = %x\n", SCB->SHCSR);
dbg_mem_dump_40 (hardfault_args, 0x40) ;
while (1);
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MODULES_H__
#define __MODULES_H__
/*
* Module definitions to use with the Stellaris LM3S6965 Microcontroller
*/
#include "LPC17xx.h"
#include "drivers/lpc17xx_uart.h"
/* Function prototypes */
extern int low_level_init (void) ;
extern void dbg_format_msg (char *format, ...) ;
extern void dbg_fault_handler (unsigned int * hardfault_args) ;
#endif /* __MODULES_H__ */

297
platforms/lpc17xx/startup.c Normal file
View File

@@ -0,0 +1,297 @@
/**************************************************************************//**
* @file startup.c
* @brief
* @version
* @date
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
#define WEAK __attribute__ ((weak))
#define ALIAS(f) __attribute__ ((weak, alias (#f)))
#include "system_LPC17xx.h"
#include "atomport_private.h"
void ResetISR(void);
WEAK void NMI_Handler(void);
WEAK void HardFault_Handler(void);
WEAK void MemManage_Handler(void);
WEAK void BusFault_Handler(void);
WEAK void UsageFault_Handler(void);
WEAK void SVC_Handler(void);
WEAK void DebugMon_Handler(void);
WEAK void PendSV_Handler(void);
WEAK void SysTick_Handler(void);
WEAK void IntDefault_Handler(void);
//*****************************************************************************
//
// The entry point for the application.
// __main() is the entry point for Redlib based applications
// main() is the entry point for Newlib based applications
//
//*****************************************************************************
extern int main(void);
extern void low_level_init(void);
//*****************************************************************************
//
// External declaration for the pointer to the stack top from the Linker Script
//
//*****************************************************************************
extern void _vStackTop(void);
//*****************************************************************************
//
// The vector table.
// This relies on the linker script to place at correct location in memory.
//
//*****************************************************************************
extern void (* const g_pfnVectors[])(void);
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
// Core Level - CM3
&_vStackTop, // The initial stack pointer
ResetISR, // The reset handler
NMI_Handler, // The NMI handler
HardFault_Handler, // The hard fault handler
MemManage_Handler, // The MPU fault handler
BusFault_Handler, // The bus fault handler
UsageFault_Handler, // The usage fault handler
0, // Reserved
0, // Reserved
0, // Reserved
0, // Reserved
SVC_Handler, // SVCall handler
DebugMon_Handler, // Debug monitor handler
0, // Reserved
archPendSVHandler, // The PendSV handler
archTickHandler /*SysTick_Handler*/, // The SysTick handler
// Chip Level - LPC17
IntDefault_Handler, // 16, 0x40 - WDT
IntDefault_Handler, // 17, 0x44 - TIMER0
IntDefault_Handler, // 18, 0x48 - TIMER1
IntDefault_Handler, // 19, 0x4c - TIMER2
IntDefault_Handler, // 20, 0x50 - TIMER3
IntDefault_Handler, // 21, 0x54 - UART0
IntDefault_Handler, // 22, 0x58 - UART1
IntDefault_Handler, // 23, 0x5c - UART2
IntDefault_Handler, // 24, 0x60 - UART3
IntDefault_Handler, // 25, 0x64 - PWM1
IntDefault_Handler, // 26, 0x68 - I2C0
IntDefault_Handler, // 27, 0x6c - I2C1
IntDefault_Handler, // 28, 0x70 - I2C2
IntDefault_Handler, // 29, 0x74 - SPI
IntDefault_Handler, // 30, 0x78 - SSP0
IntDefault_Handler, // 31, 0x7c - SSP1
IntDefault_Handler, // 32, 0x80 - PLL0 (Main PLL)
IntDefault_Handler, // 33, 0x84 - RTC
IntDefault_Handler, // 34, 0x88 - EINT0
IntDefault_Handler, // 35, 0x8c - EINT1
IntDefault_Handler, // 36, 0x90 - EINT2
IntDefault_Handler, // 37, 0x94 - EINT3
IntDefault_Handler, // 38, 0x98 - ADC
IntDefault_Handler, // 39, 0x9c - BOD
IntDefault_Handler, // 40, 0xA0 - USB
IntDefault_Handler, // 41, 0xa4 - CAN
IntDefault_Handler, // 42, 0xa8 - GP DMA
IntDefault_Handler, // 43, 0xac - I2S
IntDefault_Handler, // 44, 0xb0 - Ethernet
IntDefault_Handler, // 45, 0xb4 - RITINT
IntDefault_Handler, // 46, 0xb8 - Motor Control PWM
IntDefault_Handler, // 47, 0xbc - Quadrature Encoder
IntDefault_Handler, // 48, 0xc0 - PLL1 (USB PLL)
IntDefault_Handler, // 49, 0xc4 - USB Activity interrupt to wakeup
IntDefault_Handler, // 50, 0xc8 - CAN Activity interrupt to wakeup
};
//*****************************************************************************
// Functions to carry out the initialization of RW and BSS data sections. These
// are written as separate functions rather than being inlined within the
// ResetISR() function in order to cope with MCUs with multiple banks of
// memory.
//*****************************************************************************
__attribute__ ((section(".after_vectors")))
void data_init(unsigned int romstart, unsigned int start, unsigned int len) {
unsigned int *pulDest = (unsigned int*) start;
unsigned int *pulSrc = (unsigned int*) romstart;
unsigned int loop;
for (loop = 0; loop < len; loop = loop + 4)
*pulDest++ = *pulSrc++;
}
__attribute__ ((section(".after_vectors")))
void bss_init(unsigned int start, unsigned int len) {
unsigned int *pulDest = (unsigned int*) start;
unsigned int loop;
for (loop = 0; loop < len; loop = loop + 4)
*pulDest++ = 0;
}
//*****************************************************************************
// The following symbols are constructs generated by the linker, indicating
// the location of various points in the "Global Section Table". This table is
// created by the linker via the Code Red managed linker script mechanism. It
// contains the load address, execution address and length of each RW data
// section and the execution and length of each BSS (zero initialized) section.
//*****************************************************************************
extern unsigned int __data_section_table;
extern unsigned int __data_section_table_end;
extern unsigned int __bss_section_table;
extern unsigned int __bss_section_table_end;
//*****************************************************************************
// Reset entry point for your code.
// Sets up a simple runtime environment and initializes the C/C++
// library.
//*****************************************************************************
__attribute__ ((section(".after_vectors")))
void
ResetISR(void) {
//
// Copy the data sections from flash to SRAM.
//
unsigned int LoadAddr, ExeAddr, SectionLen;
unsigned int *SectionTableAddr;
// Load base address of Global Section Table
SectionTableAddr = &__data_section_table;
// Copy the data sections from flash to SRAM.
while (SectionTableAddr < &__data_section_table_end) {
LoadAddr = *SectionTableAddr++;
ExeAddr = *SectionTableAddr++;
SectionLen = *SectionTableAddr++;
data_init(LoadAddr, ExeAddr, SectionLen);
}
// At this point, SectionTableAddr = &__bss_section_table;
// Zero fill the bss segment
while (SectionTableAddr < &__bss_section_table_end) {
ExeAddr = *SectionTableAddr++;
SectionLen = *SectionTableAddr++;
bss_init(ExeAddr, SectionLen);
}
low_level_init();
main();
//
// main() shouldn't return, but if it does, we'll just enter an infinite loop
//
while (1) ;
}
//*****************************************************************************
// Default exception handlers. Override the ones here by defining your own
// handler routines in your application code.
//*****************************************************************************
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void NMI_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void HardFault_Handler(void)
{
__asm volatile
(
" tst lr, #4 \n"
" ite eq \n"
" mrseq r0, msp \n"
" mrsne r0, psp \n"
" b dbg_fault_handler \n"
);
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void MemManage_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void BusFault_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void UsageFault_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void SVC_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void DebugMon_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void PendSV_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void SysTick_Handler(void)
{
while(1) ;
}
__attribute__ ((section(".after_vectors"))) __attribute__( ( naked ) )
void IntDefault_Handler(void)
{
while(1) ;
}

148
platforms/lpc17xx/system.ld Normal file
View File

@@ -0,0 +1,148 @@
/**************************************************************************//**
* @file system.ld
* @brief
* @version
* @date
*
* @note
* Copyright (C) 2010 NXP Semiconductors(NXP). All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
******************************************************************************/
MEMORY
{
/* Define each memory region */
MFlash512 (rx) : ORIGIN = 0x0, LENGTH = 0x80000 /* 512k */
RamLoc32 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000 /* 32k */
RamAHB32 (rwx) : ORIGIN = 0x2007c000, LENGTH = 0x8000 /* 32k */
}
/* Define a symbol for the top of each memory region */
__top_MFlash512 = 0x0 + 0x80000;
__top_RamLoc32 = 0x10000000 + 0x8000;
__top_RamAHB32 = 0x2007c000 + 0x8000;
ENTRY(ResetISR)
SECTIONS
{
/* MAIN TEXT SECTION */
.text : ALIGN(4)
{
FILL(0xff)
KEEP(*(.isr_vector))
/* Global Section Table */
. = ALIGN(4) ;
__section_table_start = .;
__data_section_table = .;
LONG(LOADADDR(.data));
LONG( ADDR(.data)) ;
LONG( SIZEOF(.data));
LONG(LOADADDR(.data_RAM2));
LONG( ADDR(.data_RAM2)) ;
LONG( SIZEOF(.data_RAM2));
__data_section_table_end = .;
__bss_section_table = .;
LONG( ADDR(.bss));
LONG( SIZEOF(.bss));
LONG( ADDR(.bss_RAM2));
LONG( SIZEOF(.bss_RAM2));
__bss_section_table_end = .;
__section_table_end = . ;
/* End of Global Section Table */
*(.after_vectors*)
*(.text*)
*(.rodata .rodata.*)
. = ALIGN(4);
} > MFlash512
/*
* for exception handling/unwind - some Newlib functions (in common
* with C++ and STDC++) use this.
* Use KEEP so not discarded with --gc-sections
*/
.ARM.extab : ALIGN(4)
{
KEEP(*(.ARM.extab* .gnu.linkonce.armextab.*))
} > MFlash512
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
KEEP(*(.ARM.exidx* .gnu.linkonce.armexidx.*))
} > MFlash512
__exidx_end = .;
_etext = .;
.data_RAM2 : ALIGN(4)
{
FILL(0xff)
*(.data.$RAM2*)
*(.data.$RamAHB32*)
. = ALIGN(4) ;
} > RamAHB32 AT>MFlash512
/* MAIN DATA SECTION */
.uninit_RESERVED : ALIGN(4)
{
KEEP(*(.bss.$RESERVED*))
. = ALIGN(4) ;
_end_uninit_RESERVED = .;
} > RamLoc32
.data : ALIGN(4)
{
FILL(0xff)
_data = .;
*(vtable)
*(.data*)
. = ALIGN(4) ;
_edata = .;
} > RamLoc32 AT>MFlash512
.bss_RAM2 : ALIGN(4)
{
*(.bss.$RAM2*)
*(.bss.$RamAHB32*)
. = ALIGN(4) ;
} > RamAHB32
/* MAIN BSS SECTION */
.bss : ALIGN(4)
{
__bss_start__ = . ;
_bss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4) ;
__bss_end__ = . ;
_ebss = .;
PROVIDE(end = .);
} > RamLoc32
PROVIDE(_pvHeapStart = .);
PROVIDE(_vStackTop = __top_RamLoc32 - 0);
}

View File

@@ -0,0 +1,96 @@
ifeq ($(TARGET_NAME),)
TARGET_NAME=boot
endif
ifeq ($(ATOMTHREADS),)
ATOMTHREADS = $(shell pwd)/../../
endif
ifeq ($(TEST_NAME),)
TEST_NAME = kern1
endif
CC = arm-none-eabi-gcc
LN = arm-none-eabi-gcc
AS = arm-none-eabi-gcc
CFLAGS := $(CFLAGS) -Wall -g -c -mcpu=cortex-m3 -mthumb -mthumb-interwork -ffreestanding
AFLAGS := $(AFLAGS) -Wall -g -c -mcpu=cortex-m3 -mthumb -mthumb-interwork -ffreestanding
LFLAGS := $(LFLAGS) -Wall -mcpu=cortex-m3 -mthumb -Wl,-Map=system.map -Tsystem.ld
CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' -DPLATFORM_QEMU_LM3S_HACK
ADEFS := $(ADEFS) -D__thumb2__ -DARM_RDI_MONITOR -DPLATFORM_QEMU_LM3S_HACK
LLIBS := $(LLIBS)
SRCS := $(SRCS) \
modules.c \
main.c \
$(ATOMTHREADS)/tests/$(TEST_NAME).c \
ASMS := $(ASMS) \
startup.S \
INCLUDES := $(INCLUDES) \
-I$(ATOMTHREADS)
include $(ATOMTHREADS)/ports/cortex_m/Makefile
OBJS = $(SRCS:.c=.o) $(ASMS:.S=.o)
include ../rules.mk
run_test: clean all
echo "START TEST $(TEST_NAME)"
qemu-system-arm -M lm3s6965evb -kernel boot.elf -semihosting >> atomthreads_test.out
all_tests:
echo "Starting atomthreads test suite" > atomthreads_test.out
make run_test "TEST_NAME=mutex1"
make run_test "TEST_NAME=mutex2"
make run_test "TEST_NAME=mutex3"
make run_test "TEST_NAME=mutex5"
make run_test "TEST_NAME=mutex6"
make run_test "TEST_NAME=mutex7"
make run_test "TEST_NAME=mutex8"
make run_test "TEST_NAME=mutex9"
make run_test "TEST_NAME=kern1"
make run_test "TEST_NAME=kern2"
make run_test "TEST_NAME=kern3"
make run_test "TEST_NAME=kern4"
make run_test "TEST_NAME=timer1"
make run_test "TEST_NAME=timer2"
make run_test "TEST_NAME=timer3"
make run_test "TEST_NAME=timer5"
make run_test "TEST_NAME=timer6"
make run_test "TEST_NAME=timer7"
make run_test "TEST_NAME=queue1"
make run_test "TEST_NAME=queue2"
make run_test "TEST_NAME=queue3"
make run_test "TEST_NAME=queue4"
make run_test "TEST_NAME=queue5"
make run_test "TEST_NAME=queue6"
make run_test "TEST_NAME=queue7"
make run_test "TEST_NAME=queue8"
make run_test "TEST_NAME=queue9"
make run_test "TEST_NAME=sem1"
make run_test "TEST_NAME=sem2"
make run_test "TEST_NAME=sem3"
make run_test "TEST_NAME=sem5"
make run_test "TEST_NAME=sem6"
make run_test "TEST_NAME=sem7"
make run_test "TEST_NAME=sem8"
make run_test "TEST_NAME=sem9"
fail_tests:
make run_test "TEST_NAME=mutex4"
make run_test "TEST_NAME=timer4"
make run_test "TEST_NAME=sem4"
run_last:
qemu-system-arm -M lm3s6965evb -kernel boot.elf -semihosting

View File

@@ -0,0 +1,37 @@
---------------------------------------------------------------------------
Library: Atomthreads QEMU Stellaris LM3S6965 Platform.
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
QEMU Stellaris LM3S6965 Platform
The "qemu_lm3s" platform contains sources for building a sample Atomthreads
application for the Stellaris LM3S6965 platform.
ISSUES:
There seems to be several problems for the QEMU Cortex M3 processor. The
platform and port contains specific hacks to make it work on the QEMU 1.2.0
release it was tested on. Also see the latest patches for QEMU.
Fixes implemented for the QEMU 1.2.0 release:
1. Install the patch http://patchwork.ozlabs.org/patch/180315/
2. Use the PLATFORM_QEMU_LM3S_HACK define in the Makefile:
- Disabling interrupts on the processor does not work (verified).
- Disabling interrupts of the Cortex M Sys Tick Interrupt does not
work (verified).
- NVIC Interrupt priorities not implemented correctly (not verified).
Because of the problems with the Sys Tick Interrupt the The Stellaris
General-Purpose Timer Module (GPTM) was used to generate the system timer
tick.
BUGS:
mutex4 testcase fails.
sem4 testcase fails.

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "modules.h"
#include "atom.h"
#include "tests/atomtests.h"
#ifndef ATOMTHREADS_TEST
#define ATOMTHREADS_TEST "kern1"
#endif
#define TEST_STACK_BYTE_SIZE 1024
#define IDLE_STACK_BYTE_SIZE 512
static unsigned char test_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
ATOM_TCB test_tcb ;
/**
* \b test_thread
*
* Function calling the test function of the Atomthreads test suite.
*
*/
void
test_thread (uint32_t param)
{
uint32_t failures ;
CRITICAL_STORE ;
failures = test_start () ;
atomTimerDelay (10) ;
CRITICAL_START() ;
printf ("%s %s\r\n", ATOMTHREADS_TEST, failures ? "FAIL" : "PASS") ;
exit (failures) ;
CRITICAL_END() ;
}
/**
* \b main
*
* Initialize atomthreads and start a test_thread to run the Atomthreads test suite.
*
*/
int
main (void)
{
int i = 0 ;
uint32_t failures ;
printf ("Atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ;
atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, TRUE) ;
atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[0], TEST_STACK_BYTE_SIZE, TRUE);
atomOSStart() ;
return 0 ;
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "modules.h"
#include <stdio.h>
#include <stdarg.h>
#include "atomport_private.h"
#include "atom.h"
#include "atomport.h"
#include "types.h"
SYSTICK_T* const board_systick = (SYSTICK_T*) BOARD_BASE_ADDRESS_SYSTICK ;
NVIC_T* const board_nvic = (NVIC_T*) BOARD_BASE_ADDRESS_NVIC ;
SCB_T * const board_scb = (SCB_T*) BOARD_BASE_ADDRESS_SCB ;
GPTM_TIMER_T * const board_gptm0 = (GPTM_TIMER_T*) BOARD_BASE_ADDRESS_GPTIMER0 ;
/**
* \b dbg_format_msg
*
* Same as printf.
*
*/
void
dbg_format_msg (char *format, ...)
{
va_list args;
static char msg[256] ;
CRITICAL_STORE ;
va_start (args, format) ;
CRITICAL_START() ;
vsnprintf ((char*)msg, 256, (char*)format, args) ;
printf (msg) ;
CRITICAL_END() ;
}
/**
* \b low_level_init
*
* Initializes the PIC and start the system timer tick intrerupt.
*
*/
int
low_level_init (void)
{
contextInit () ;
//board_systick->STRELOAD = 0x010000 ;
//board_systick->STCTRL = NVIC_STCTRL_CLK |
// NVIC_STCTRL_INTEN |
// NVIC_STCTRL_ENABLE ;
board_gptm0->CTL &= ~GPTM_TIMER_CTL_TAEN ;
board_gptm0->CFG = 0 ;
board_gptm0->TAMR = GPTM_TIMER_TMR_TMR_PERIODIC ;
board_gptm0->TAILR = 0x10000 ;
board_gptm0->IMR |= GPTM_TIMER_INT_TATOIM ;
board_gptm0->CTL |= GPTM_TIMER_CTL_TAEN ;
// board_nvic->ISER[0] = 0x80000 ;
return 0 ;
}
/**
* \b __context_tick_handler
*
* System timer tic interupt handler.
*
*/
void
__context_tick_handler (void)
{
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
board_gptm0->ICR |= GPTM_TIMER_INT_TATOIM ;
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
/**
* \b dbg_hard_fault_handler_c
*
* Dumps the registers pushed on the stack after a fault.
*
*/
void
dbg_hard_fault_handler_c (unsigned int * hardfault_args)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
printf ("\r\n\r\n[Hard fault handler - all numbers in hex]\r\n");
printf ("SP = 0x%x\r\n", hardfault_args);
printf ("R0 = 0x%x\r\n", stacked_r0);
printf ("R1 = 0x%x\r\n", stacked_r1);
printf ("R2 = 0x%x\r\n", stacked_r2);
printf ("R3 = 0x%x\r\n", stacked_r3);
printf ("R12 = 0x%x\r\n", stacked_r12);
printf ("LR [R14] = 0x%x subroutine call return address\r\n", stacked_lr);
printf ("PC [R15] = 0x%x program counter\r\n", stacked_pc);
printf ("PSR = 0x%x\r\n", stacked_psr);
//printf ("BFAR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED38))));
//printf ("CFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED28))));
//printf ("HFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED2C))));
//printf ("DFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED30))));
//printf ("AFSR = 0x%x\r\n", (*((volatile unsigned long *)(0xE000ED3C))));
// printf ("SCB_SHCSR = %x\n", SCB->SHCSR);
while (1);
}

View File

@@ -0,0 +1,208 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MODULES_H__
#define __MODULES_H__
/*
* Module definitions to use with the Stellaris LM3S6965 Microcontroller
*/
#include "atomport.h"
// *****************************************************************************
// The Stellaris General-Purpose Timer Module (GPTM)
// *****************************************************************************
typedef struct GPTM_TIMER_S {
// offset read/write reset Description
__IO uint32_t CFG ; // 0x000 R/W 0x00000000 GPTM Configuration 345
__IO uint32_t TAMR ; // 0x004 R/W 0x00000000 GPTM TimerA Mode 346
__IO uint32_t TBMR ; // 0x008 R/W 0x00000000 GPTM TimerB Mode 348
__IO uint32_t CTL ; // 0x00C R/W 0x00000000 GPTM Control 350
uint32_t Reserved[2] ; // 0x010
__IO uint32_t IMR ; // 0x018 R/W 0x00000000 GPTM Interrupt Mask 353
__I uint32_t RIS ; // 0x01C RO 0x00000000 GPTM Raw Interrupt Status 355
__I uint32_t MIS ; // 0x020 RO 0x00000000 GPTM Masked Interrupt Status 356
__O uint32_t ICR ; // 0x024 W1C 0x00000000 GPTM Interrupt Clear 357
__IO uint32_t TAILR ; // 0x028 R/W 0xFFFFFFFF GPTM TimerA Interval Load 359
__IO uint32_t TBILR ; // 0x02C R/W 0x0000FFFF GPTM TimerB Interval Load 360
__IO uint32_t TAMATCHR ; // 0x030 R/W 0xFFFFFFFF GPTM TimerA Match 361
__IO uint32_t TBMATCHR ; // 0x034 R/W 0x0000FFFF GPTM TimerB Match 362
__IO uint32_t TAPR ; // 0x038 R/W 0x00000000 GPTM TimerA Prescale 363
__IO uint32_t TBPR ; // 0x03C R/W 0x00000000 GPTM TimerB Prescale 364
__IO uint32_t TAPMR ; // 0x040 R/W 0x00000000 GPTM TimerA Prescale Match 365
__IO uint32_t TBPMR ; // 0x044 R/W 0x00000000 GPTM TimerB Prescale Match 366
__I uint32_t TAR ; // 0x048 RO 0xFFFFFFFF GPTM TimerA 367
__I uint32_t TBR ; // 0x04C RO 0x0000FFFF GPTM TimerB 368
} GPTM_TIMER_T, *PGPTM_TIMER_T ;
// -------- GPTM_TIMER_CFG : (CFG Offset: 0x00) This register configures the global operation of the GPTM module --------
#define GPTM_TIMER_CFG_MASK ((unsigned int)0x07 << 0) //
#define GPTM_TIMER_CFG_32BIT ((unsigned int)0x00 << 0) // 32-bit timer configuration
#define GPTM_TIMER_CFG_32BIT_RT ((unsigned int)0x01 << 0) // 32-bit real-time clock (RTC) counter configuration
// -------- GPTM_TIMER_TAMR : (TAMR Offset: 0x04) This register configures the GPTM based on the configuration selected in the GPTMCFG register --------
// -------- GPTM_TIMER_TBMR : (TBMR Offset: 0x08) This register configures the GPTM based on the configuration selected in the GPTMCFG register --------
#define GPTM_TIMER_TMR_TAMS ((unsigned int)0x01 << 3) // GPTM TimerA Alternate Mode Select. 0 Capture mode is enabled. 1 PWM mode is enabled
#define GPTM_TIMER_TMR_TCMR ((unsigned int)0x01 << 2) // GPTM TimerA Capture Mode. 0 Edge-Count mode. 1 Edge-Time mode.
#define GPTM_TIMER_TMR_TMR_ONE_SHOT ((unsigned int)0x01 << 0) // One-Shot Timer mode
#define GPTM_TIMER_TMR_TMR_PERIODIC ((unsigned int)0x02 << 0) // Periodic Timer mode
#define GPTM_TIMER_TMR_TMR_CAPTURE ((unsigned int)0x03 << 0) // Capture mode
// -------- GPTM_TIMER_CTL : (CTL Offset: 0x0C) This register is used alongside the GPTMCFG and GMTMTnMR registers to fine-tune the timer configuration --------
#define GPTM_TIMER_CTL_TBPWML ((unsigned int)0x01 << 14) // GPTM TimerB PWM Output Level. 0 Output is unaffected. 1 Output is inverted.
#define GPTM_TIMER_CTL_TBOTE ((unsigned int)0x01 << 13) // GPTM TimerB Output Trigger Enable. 0 The output TimerB ADC trigger is disabled. 1 The output TimerB ADC trigger is enabled.
#define GPTM_TIMER_CTL_TBEVENT_MASK ((unsigned int)0x03 << 10) // GPTM TimerB Event Mode
#define GPTM_TIMER_CTL_TBEVENT_PE ((unsigned int)0x00 << 10) // Positive edge
#define GPTM_TIMER_CTL_TBEVENT_NE ((unsigned int)0x01 << 10) // Negative edge
#define GPTM_TIMER_CTL_TBEVENT ((unsigned int)0x03 << 10) // Both edges
#define GPTM_TIMER_CTL_TBSTALL ((unsigned int)0x01 << 9) // GPTM Timer B Stall Enable. 0 Timer B continues counting while the processor is halted by the debugger
#define GPTM_TIMER_CTL_TBEN ((unsigned int)0x01 << 8) // GPTM TimerB Enable
// --------
#define GPTM_TIMER_CTL_TAPWML ((unsigned int)0x01 << 6) // GPTM TimerA PWM Output Level. 0 Output is unaffected. 1 Output is inverted.
#define GPTM_TIMER_CTL_TAOTE ((unsigned int)0x01 << 5) // GPTM TimerA Output Trigger Enable. 0 The output TimerB ADC trigger is disabled. 1 The output TimerB ADC trigger is enabled.
#define GPTM_TIMER_CTL_RTCEN ((unsigned int)0x01 << 4) // GPTM RTC Enable
#define GPTM_TIMER_CTL_TAEVENT_MASK ((unsigned int)0x03 << 2) // GPTM TimerA Event Mode
#define GPTM_TIMER_CTL_TAEVENT_PE ((unsigned int)0x00 << 2) // Positive edge
#define GPTM_TIMER_CTL_TAEVENT_NE ((unsigned int)0x01 << 2) // Negative edge
#define GPTM_TIMER_CTL_TAEVENT ((unsigned int)0x03 << 2) // Both edges
#define GPTM_TIMER_CTL_TASTALL ((unsigned int)0x01 << 1) // GPTM Timer A Stall Enable. 0 Timer B continues counting while the processor is halted by the debugger
#define GPTM_TIMER_CTL_TAEN ((unsigned int)0x01 << 0) // GPTM TimerA Enable
// -------- GPTM_TIMER_IMR : (IMR Offset: 0x18) This register allows software to enable/disable GPTM controller-level interrupts. --------
// -------- GPTM_TIMER_RIS : (RIS Offset: 0x1C) This register shows the state of the GPTM's internal interrupt signal. --------
// -------- GPTM_TIMER_MIS : (MIS Offset: 0x20) This register show the state of the GPTM's controller-level interrupt. --------
// -------- GPTM_TIMER_ICR : (ICR Offset: 0x24) This register is used to clear the status bits in the GPTMRIS and GPTMMIS registers. --------
#define GPTM_TIMER_INT_CBEIM ((unsigned int)0x01 << 10) // GPTM CaptureB Event Interrupt Mask
#define GPTM_TIMER_INT_CBMIM ((unsigned int)0x01 << 9) // GPTM CaptureB Match Interrupt Mask
#define GPTM_TIMER_INT_TBTOIM ((unsigned int)0x01 << 8) // GPTM TimerB Time-Out Interrupt Mask
// --------
#define GPTM_TIMER_INT_RTCIM ((unsigned int)0x01 << 3) // GPTM RTC Interrupt Mask
#define GPTM_TIMER_INT_CAEIM ((unsigned int)0x01 << 2) // GPTM CaptureA Event Interrupt Mask
#define GPTM_TIMER_INT_CAMIM ((unsigned int)0x01 << 1) // GPTM CaptureA Match Interrupt Mask
#define GPTM_TIMER_INT_TATOIM ((unsigned int)0x01 << 0) // GPTM TimerA Time-Out Interrupt Mask
// *****************************************************************************
// Cortex M System Timer (SysTick)
// *****************************************************************************
typedef struct SYSTICK_S {
uint32_t Res0[1] ; // 0xE000E000
__IO uint32_t ICT ; // 0xE000E004
uint32_t Res1[2] ; // 0xE000E008
__IO uint32_t STCTRL ; // 0xE000E010
__IO uint32_t STRELOAD ; // 0xE000E014
__IO uint32_t STCURRENT; // 0xE000E018
__IO uint32_t STCALIB ; // 0xE000E01C
uint32_t Res2[56] ; // 0xE000E020
} SYSTICK_T, *PSYSTICK_T ;
// -------- SYSTICK_STCTRL : (STCTRL Offset: 0xE000E010) SysTick Control and Status Register --------
#define SYSTICK_STCTRL_COUNT ((unsigned int)0x1 << 16) // 0 - The SysTick timer has not counted to 0 since the last time this bit was read.
#define SYSTICK_STCTRL_CLK ((unsigned int)0x1 << 2) // 1 - System clock
#define SYSTICK_STCTRL_INTEN ((unsigned int)0x1 << 1) // 1 - An interrupt is generated to the NVIC when SysTick counts to 0.
#define SYSTICK_STCTRL_ENABLE ((unsigned int)0x1 << 1) // Enables SysTick to operate in a multi-shot way.
// -------- SYSTICK_STRELOAD : (STRELOAD Offset: 0xE000E014) Reload Value --------
#define SYSTICK_STRELOAD_MASK ((unsigned int)0xFFFFFF << 0) // IRQ mask
// -------- SYSTICK_STCURRENT : (STCURRENT Offset: 0xE000E018) SysTick Current Value Register --------
// *****************************************************************************
// Cortex M Nested Vectored Interrupt Controller
// *****************************************************************************
typedef struct NVIC_S {
__IO uint32_t ISER[2] ; // 0xE000E100
uint32_t Res3[30] ; // 0xE000E120
__IO uint32_t ICER[2] ; // 0xE000E180
uint32_t Res4[30] ; // 0xE000E1A0
__IO uint32_t ISPR[2] ; // 0xE000E200
uint32_t Res5[30] ; // 0xE000E220
__IO uint32_t ICPR[2] ; // 0xE000E280
uint32_t Res6[30] ; // 0xE000E2A0
__IO uint32_t IABR[2] ; // 0xE000E300
uint32_t Res7[64] ; // 0xE000E320
__IO uint32_t IPR[2] ; // 0xE000E400
// uint32_t Res7[515] ; // 0xE000E4F4
} NVIC_T, *PNVIC_T ;
#define NVIC_EXCEPTION_RESET 1
#define NVIC_EXCEPTION_NMI 2
#define NVIC_EXCEPTION_HARD_FAULT 3
#define NVIC_EXCEPTION_MEM_MANAGEMENT 4
#define NVIC_EXCEPTION_BUS_FAULT 5
#define NVIC_EXCEPTION_USAGE_FAULT 6
#define NVIC_EXCEPTION_SVCALL 11
#define NVIC_EXCEPTION_DEBUG_MON 12
#define NVIC_EXCEPTION_PEND_SV 14
#define NVIC_EXCEPTION_SYS_TICK 15
// *****************************************************************************
// System Control Block (SCB) Registers
// *****************************************************************************
typedef struct SCB_S {
__IO uint32_t CPUID ; // 0xE000ED00
__IO uint32_t ICSR ; // 0xE000ED04
__IO uint32_t VTOR ; // 0xE000ED08
__IO uint32_t AIRCR ; // 0xE000ED0C
__IO uint32_t SCR ; // 0xE000ED10
__IO uint32_t CCR ; // 0xE000ED14
__IO uint32_t SYS_PRIO[3] ; // 0xE000ED18
__IO uint32_t SYSHNDCTRL ; // 0xE000ED24
//__IO uint32_t FAULTSTAT ; // 0xE000ED28
//__IO uint32_t HFAULTSTAT ; // 0xE000ED2C
} SCB_T, *PSCB_T ;
/* module definitions */
#define BOARD_BASE_ADDRESS_SYSTICK 0xE000E000
#define BOARD_BASE_ADDRESS_NVIC 0xE000E100
#define BOARD_BASE_ADDRESS_SCB 0xE000ED00
#define BOARD_BASE_ADDRESS_GPTIMER0 0x40030000
extern SYSTICK_T* const board_systick ;
extern NVIC_T* const board_nvic ;
extern SCB_T* const board_scb ;
extern GPTM_TIMER_T* const board_gptm0 ;
/* Function prototypes */
extern int low_level_init (void) ;
extern void dbg_format_msg (char *format, ...) ;
extern void dbg_hard_fault_handler_c (unsigned int * hardfault_args) ;
#define DBG_MESSAGE(fmt_str) { dbg_format_msg fmt_str ; }
#endif /* __MODULES_H__ */

View File

@@ -0,0 +1,215 @@
/*
Copyright (c) 2012, Natie van Rooyen. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. No personal names or organizations' names associated with the
Atomthreads project may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* lm3s Startup Script */
.section .vectors,"x",%progbits
.syntax unified
.thumb
.global __interrupt_vector_table
.extern archTickHandler
.extern archPendSVHandler
.extern dbg_hard_fault_handler_c
/**
* \b __interrupt_vector_table
*
*/
__interrupt_vector_table:
.long __c_stack_top__
.long reset_Handler
.long fault_Handler
.long fault_Handler
.long fault_Handler
.long fault_Handler
.long fault_Handler
.long 0
.long 0
.long 0
.long 0
.long sys_Handler
.long sys_Handler
.long 0
.long archPendSVHandler
.long sys_Handler
/* External interrupts */
.long default_Handler // GPIO Port A
.long default_Handler // GPIO Port B
.long default_Handler // GPIO Port C
.long default_Handler // GPIO Port D
.long default_Handler // GPIO Port E
.long default_Handler // UART0 Rx and Tx
.long default_Handler // UART1 Rx and Tx
.long default_Handler // SSI0 Rx and Tx
.long default_Handler // I2C0 Master and Slave
.long default_Handler // PWM Fault
.long default_Handler // PWM Generator 0
.long default_Handler // PWM Generator 1
.long default_Handler // PWM Generator 2
.long default_Handler // Quadrature Encoder 0
.long default_Handler // ADC Sequence 0
.long default_Handler // ADC Sequence 1
.long default_Handler // ADC Sequence 2
.long default_Handler // ADC Sequence 3
.long default_Handler // Watchdog timer
.long archTickHandler // Timer 0 subtimer A
.long default_Handler // Timer 0 subtimer B
.long default_Handler // Timer 1 subtimer A
.long default_Handler // Timer 1 subtimer B
.long default_Handler // Timer 2 subtimer A
.long default_Handler // Timer 2 subtimer B
.long default_Handler // Analog Comparator 0
.long default_Handler // Analog Comparator 1
.long default_Handler // Analog Comparator 2
.long default_Handler // System Control (PLL, OSC, BO)
.long default_Handler // FLASH Control
.long default_Handler // GPIO Port F
.long default_Handler // GPIO Port G
.long default_Handler // GPIO Port H
.long default_Handler // UART2 Rx and Tx
.long default_Handler // SSI1 Rx and Tx
.long default_Handler // Timer 3 subtimer A
.long default_Handler // Timer 3 subtimer B
.long default_Handler // I2C1 Master and Slave
.long default_Handler // Quadrature Encoder 1
.long default_Handler // CAN0
.long default_Handler // CAN1
.long default_Handler // CAN2
.long default_Handler // Ethernet
.long default_Handler // Hibernate
/**
* \b sys_Handler
*
* @return None
*/
.thumb_func
sys_Handler:
B .
/**
* \b default_Handler
*
* @return None
*/
.thumb_func
default_Handler:
B .
/**
* \b fault_Handler
*
* @return None
*/
.thumb_func
fault_Handler:
tst lr, #4
ite eq
mrseq r0, MSP
mrsne r0, PSP
b dbg_hard_fault_handler_c
.section .startup,"x",%progbits
.syntax unified
.thumb
.global reset_Handler
.extern initialise_monitor_handles
.extern low_level_init
.extern main
/**
* \b reset_Handler
*
*
*
* @return None
*/
.thumb_func
reset_Handler:
/*
* Initialize the data and bss sections.
*/
init_data:
ldr r0, .ETEXT
ldr r1, .DATA
ldr r2, .EDATA
sub r2, r2, r1
cmp r2, #0
beq init_bss
init_data_copy:
ldrb r4, [r0], #1
strb r4, [r1], #1
subs r2, r2, #1
bne init_data_copy
init_bss:
mov r0, #0
ldr r1, = .BSS
ldr r2, = .EBSS
sub r2, r2, r1
cmp r2, #0
beq init_done
init_bss_zero:
strb r0, [r1], #1
subs r2, r2, #1
bne init_bss_zero
init_done:
/*
* The following call initializes the function pointers for stdio etc.
* These are used by the semihosting interface.
*
* This function is implemented in newlib.
*/
bl initialise_monitor_handles
/*
* Platform specific low level initialization.
*/
bl low_level_init
/*
* Call the application's entry point.
*/
bl main
.BSS: .long _bss
.EBSS: .long _ebss
.ETEXT: .long _etext
.DATA: .long _data
.EDATA: .long _edata
.end

View File

@@ -0,0 +1,72 @@
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000
}
SECTIONS
{
_vRamTop = 0x20000000 + 0x00010000;
.text :
{
KEEP(*(.vectors))
*(.startup)
*(.text*)
*(.rodata*)
} > FLASH
/*
* for exception handling/unwind - some Newlib functions (in common with
* C++ and STDC++) use this.
*/
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
_etext = .;
.data : AT (__exidx_end)
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM
/* zero initialized data */
.bss :
{
__bss_start__ = . ;
_bss = .;
*(.bss*)
*(COMMON)
__bss_end__ = . ;
_ebss = .;
} > SRAM
/* Where we put the heap with cr_clib */
.cr_heap :
{
end = .;
_pvHeapStart = .;
} > SRAM
_vStackTop = _vRamTop - 16;
.stack _vStackTop :
{
__c_stack_top__ = . ;
}
}

62
platforms/rules.mk Normal file
View File

@@ -0,0 +1,62 @@
#
# The following part of the makefile is generic; it can be used to
# build any executable just by changing the definitions above and by
# deleting dependencies appended to the file from 'make depend'
#
.SUFFIXES: .asm .elf .hex .lst .o .S .s .c .cpp
.PHONY: depend clean
dump:
@echo "Target: "
@echo $(TARGET_NAME)
@echo "Source files: "
@echo $(SRCS)
@echo $(ASMS)
@echo "Object files: "
@echo $(OBJS)
all: target
target: $(OBJS)
$(LN) $(LFLAGS) $(LIBFLAGS) $(OBJS) $(LLIBS) -o $(TARGET_NAME).elf
@echo $(TARGET_NAME).elf was compiled
arm-none-eabi-objcopy -O binary $(TARGET_NAME).elf $(TARGET_NAME).bin
arm-none-eabi-objdump -dxS $(TARGET_NAME).elf > $(TARGET_NAME).out
clean:
rm -f $(OBJS)
# this is a suffix replacement rule for building .o's from .c's
# it uses automatic variables $<: the name of the prerequisite of
# the rule(a .c file) and $@: the name of the target of the rule (a .o file)
# (see the gnu make manual section about automatic variables)
.c.o:
$(CC) $(CDEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
.cpp.o:
$(CC) $(CDEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@
.S.o:
$(AS) $(ADEFS) $(AFLAGS) $(INCLUDES) -c $< -o $@
.s.o:
$(AS) $(ADEFS) $(AFLAGS) $(INCLUDES) -c $< -o $@
DEPFILE=.depends
DEPTOKEN='\# MAKEDEPENDS'
DEPFLAGS=-Y -f $(DEPFILE) -s $(DEPTOKEN) -p $(OUTDIR)/
depend:
rm -f $(DEPFILE)
make $(DEPFILE)
$(DEPFILE):
@echo $(DEPTOKEN) > $(DEPFILE)
makedepend $(DEPFLAGS) -- $(CFLAGS) -- $(SRCS) >&/dev/null
# put this file in the last line of your Makefile
sinclude $(DEPFILE)

1161
ports/arm/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

107
ports/arm/README Normal file
View File

@@ -0,0 +1,107 @@
---------------------------------------------------------------------------
Library: Atomthreads ARM Port
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
ARM PORT
This folder contains a port of the Atomthreads real time kernel for the
ARM processor architecture. This port was tested on the ARMv5 and ARMv7
architectures.
The same common/core port can be used on a wide variety of ARM devices
but platform-specific code has been separated out into multiple "platform"
(BSP) folders. This allows the common ARM code to be shared among several
different ARM platforms and boards. For example, different ARM devices and
platforms might use different interrupt controllers, timer subsystems and
UARTs but share the same core OS context-switching routines etc.
An example platform is in the "platforms/qemu_integratorcp" folder. The
platform-specific folders such as this contain the Makefile to build the
project for that platform, so you may wish to head straight there if you
wish to quickly get started building and running Atomthreads on ARM. The
qemu_integratorcp platform is designed for the Integrator/CP platform with
ARM926EJ-S processor, and can be run within QEMU for quick evaluation of
Atomthreads without real hardware.
---------------------------------------------------------------------------
FILES IN THE COMMON ARM PORT FOLDER
* tests-main.c: Contains a sample Atomthreads application starting at
main() that initialises the operating system and runs the automated test
suite applications. You will normally make your own main() function
suitable for your application, possibly using this as a basis.
* atomport-asm.s: Contains the main assembler code that forms the portion
of the core ARM architecture port that must be implemented in assembler
(e.g. register save/restore for thread context-switching).
* atomport.c: Contains the main C code that forms the portion of the core
ARM architecture port that can be implemented in C (e.g. prefilling the
stack context for new threads).
* syscalls.c: Contains the open/close/read/write/heap-management
functions typically required if you want to do anything with stdio
(e.g. printf() calls etc). This is a very simple implementation that
always writes to the UART regardless of which file is "opened". Use of
printf() and friends with GCC toolchains typically requires a heap, and
thus a heap is supported in this file via the _sbrk() function. Your
linker script should specify where the heap starts and stops using "end"
and "heap_top" definitions respectively. Note that in QEMU environments
this may not be required as some "semi-hosted" toolchains implement
these functions and the UART driver for you. In that case these
functions will be left out of the build because they are defined with
weak linkage.
---------------------------------------------------------------------------
PORTING TO NEW ARM PLATFORMS
To port Atomthreads to your ARM platform you must provide the following
functionality in your platform folder (in all cases example filenames are
from the qemu_integratorcp sample platform):
* Startup code: see Reset_Handler in startup.s. Typically this will be (at
least in the first few instructions) some assembly code, and will set up
the initial stack pointer, perform any copying of segments from flash to
RAM, zero the BSS section etc, before branching to the main application
function (e.g. main()). At some point during initialisation the timer
tick interrupt required by the OS should be started (100 ticks per
second) and this might be done here in the very early startup code. Note
that some compiler toolchains will provide a portion of the C startup
code e.g. the function _mainCRTStartup() provided by some GCC
toolchains.
* Interrupt vector table: see __interrupt_vector_table in startup.s.
Typically this will contain at least an entry for the startup/reset
code, and an entry for the hardware IRQ handler. In order to share
common code amongst all platforms, the hardware IRQ handler
(archIRQHandler()) is actually implemented in the common ARM port
folder but calls back out to a dispatcher function in your platform
folder to determine the source of the interrupt and handle it
appropriately. Your platform folder should contain this dispatcher
function (__interrupt_dispatcher). It must support at least the timer
interrupt service routine (atomTimerTick()) required by the OS. The
dispatcher also handles other hardware interrupt sources; it determines
the source of the IRQ and calls out to the appropriate ISR for that
interrupt.
* Linker script: Here you should specify the location of the interrupt
vector table within RAM, location of code/text segment etc. The
Atomthreads ARM port does not dictate particular section names or
layout unless your toolchain does not provide a suitable syscalls.c and
you wish to use heap. In that case you will (at least initially) be
using the heap implementation _sbrk() in syscalls.c in the common ARM
port which expects "heap_top" and "end" (heap_base) to be defined by the
linker script. These names can be easily changed in ports/arm/syscalls.c
if necessary.
* UART driver: You should provide at least a UART write routine If you
would like to see debug statements, for example to see the results of
running the automated test suite. See uart.c for a simple example. Note
that for QEMU targets some semihosted toolchains will implement this for
you, in which case you won't need either ports/arm/syscalls.c or a UART
driver.
---------------------------------------------------------------------------

210
ports/arm/atomport-asm.s Normal file
View File

@@ -0,0 +1,210 @@
/*
Copyright (c) 2012, Natie van Rooyen. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. No personal names or organizations' names associated with the
Atomthreads project may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/**/
.global archIRQHandler
.global contextEnterCritical
.global contextExitCritical
.global contextEnableInterrupts
.global archContextSwitch
.global archFirstThreadRestore
.extern __interrupt_dispatcher
/**/
.equ USR_MODE, 0x10
.equ FIQ_MODE, 0x11
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ ABT_MODE, 0x17
.equ UND_MODE, 0x1B
.equ SYS_MODE, 0x1F
.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */
.text
.code 32
/*
* \b archContextSwitch
*
* Architecture-specific context switch routine.
*
* Note that interrupts are always locked out when this routine is
* called. For cooperative switches, the scheduler will have entered
* a critical region. For preemptions (called from an ISR), the
* ISR will have disabled interrupts on entry.
*
* @param[in] old_tcb_ptr Pointer to the thread being scheduled out
* @param[in] new_tcb_ptr Pointer to the thread being scheduled in
*
* @return None
*
* void archContextSwitch (ATOM_TCB *old_tcb_ptr, ATOM_TCB *new_tcb_ptr)
*/
archContextSwitch:
STMFD sp!, {r4 - r11, lr} /* Save registers */
STR sp, [r0] /* Save old SP in old_tcb_ptr->sp_save_ptr (first TCB element) */
LDR r1, [r1] /* Load new SP from new_tcb_ptr->sp_save_ptr (first TCB element) */
MOV sp, r1
LDMFD sp!, {r4 - r11, pc} /* Load new registers */
/**
* \b archFirstThreadRestore
*
* Architecture-specific function to restore and start the first thread.
* This is called by atomOSStart() when the OS is starting.
*
* This function will be largely similar to the latter half of
* archContextSwitch(). Its job is to restore the context for the
* first thread, and finally enable interrupts (although we actually
* enable interrupts in thread_shell() for new threads in this port
* rather than doing it explicitly here).
*
* It expects to see the context saved in the same way as if the
* thread has been previously scheduled out, and had its context
* saved. That is, archThreadContextInit() will have been called
* first (via atomThreadCreate()) to create a "fake" context save
* area, containing the relevant register-save values for a thread
* restore.
*
* Note that you can create more than one thread before starting
* the OS - only one thread is restored using this function, so
* all other threads are actually restored by archContextSwitch().
* This is another reminder that the initial context set up by
* archThreadContextInit() must look the same whether restored by
* archFirstThreadRestore() or archContextSwitch().
*
* @param[in] new_tcb_ptr Pointer to the thread being scheduled in
*
* @return None
*
* void archFirstThreadRestore (ATOM_TCB *new_tcb_ptr)
*/
archFirstThreadRestore:
LDR r0, [r0] /* Get SP (sp_save_ptr is conveniently first element of TCB) */
MOV sp, r0 /* Load new stack pointer */
LDMFD sp!, {r4 - r11, pc} /* Load new registers */
/**
* \b contextEnableInterrupts
*
* Enables interrupts on the processor
*
* @return None
*/
contextEnableInterrupts:
MRS r0, CPSR
MOV r1, #I_BIT
BIC r0, r0, r1
MSR CPSR_c, r0
BX lr
/**
* \b contextExitCritical
*
* Exit critical section (restores interrupt posture)
*
* @param[in] r0 Interrupt Posture
*
* @return None
*/
contextExitCritical:
MSR CPSR_cxsf, r0
BX lr
/**
* \b contextEnterCritical
*
* Enter critical section (disables interrupts)
*
* @return Current interrupt posture
*/
contextEnterCritical:
MRS r0, CPSR
ORR r1, r0, #I_BIT
MSR CPSR_cxsf, r1
BX lr
/**
* \b archIRQHandler
*
* IRQ entry point.
*
* Save the process/thread context onto its own stack before calling __interrupt_dispatcher().
* __interrupt_dispatcher() might switch stacks. On return the same context is popped from the
* stack and control is returned to the process.
*
* @return None
*/
archIRQHandler:
MSR cpsr_c, #(SVC_MODE | I_BIT) /* Save current process context in process stack */
STMFD sp!, {r0 - r3, ip, lr}
MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Save lr_irq and spsr_irq in process stack */
SUB lr, lr, #4
MOV r1, lr
MRS r2, spsr
MSR cpsr_c, #(SVC_MODE | I_BIT)
STMFD sp!, {r1, r2}
BL __interrupt_dispatcher /* Dispatch the interrupt to platform folder for
the timer tick interrupt or a simular function
for other interrupts. Some of those IRQs may
call Atomthreads kernel routines and cause a
thread switch. */
LDMFD sp!, {r1, r2} /* Restore lr_irq and spsr_irq from process stack */
MSR cpsr_c, #(IRQ_MODE | I_BIT)
STMFD sp!, {r1}
MSR spsr_cxsf, r2
MSR cpsr_c, #(SVC_MODE | I_BIT) /* Restore process regs */
LDMFD sp!, {r0 - r3, ip, lr}
MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Exit from IRQ */
LDMFD sp!, {pc}^

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_PRIVATE_H
#define __ATOM_PORT_PRIVATE_H
/* Function prototypes */
extern void archIRQHandler (void);
/* Platform-specific interrupt dispatcher called on receipt of IRQ */
extern void __interrupt_dispatcher (void);
#endif /* __ATOM_PORT_PRIVATE_H */

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_TESTS_H
#define __ATOM_PORT_TESTS_H
/* Include Atomthreads kernel API */
#include "atom.h"
/* Include printf for ATOMLOG() */
#include <stdio.h>
/* Logger macro for viewing test results */
#define ATOMLOG printf
/*
* String location macro: for platforms which need to place strings in
* alternative locations, e.g. on avr-gcc strings can be placed in
* program space, saving SRAM. On most platforms this can expand to
* empty.
*/
#define _STR(x) x
/* Default thread stack size (in bytes). Allow plenty for printf(). */
#define TEST_THREAD_STACK_SIZE 4096
/* Uncomment to enable logging of stack usage to UART */
/* #define TESTS_LOG_STACK_USAGE */
#endif /* __ATOM_PORT_TESTS_H */

157
ports/arm/atomport.c Normal file
View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2013, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomport.h"
/** Functions defined in atomport_s.s */
extern void contextEnableInterrupts (void);
/** Forward declarations */
static void thread_shell (void);
/**
* \b thread_shell
*
* Shell routine which is used to call all thread entry points.
*
* This routine is called whenever a new thread is starting, and
* provides a simple wrapper around the thread entry point that
* allows us to carry out any actions we want to do on thread's
* first starting up, or returning after completion.
*
* We mainly just want to make sure interrupts are enabled when a
* thread is run for the first time. This can be done via stack
* restores when threads are first run, but it's handy to have this
* wrapper anyway to run some common code if threads run to
* completion.
*
* A thread shell is also handy for providing port users with a place
* to do any other initialisation that must be done for each thread
* (e.g. opening stdio files etc).
*
* @return None
*/
static void thread_shell (void)
{
ATOM_TCB *curr_tcb;
/* Get the TCB of the thread being started */
curr_tcb = atomCurrentContext();
/**
* Enable interrupts - these will not be enabled when a thread
* is first restored.
*/
contextEnableInterrupts ();
/* Call the thread entry point */
if (curr_tcb && curr_tcb->entry_point)
{
curr_tcb->entry_point(curr_tcb->entry_param);
}
/* Thread has run to completion: remove it from the ready list */
curr_tcb->suspended = TRUE;
atomSched (FALSE);
}
/**
* \b archThreadContextInit
*
* Architecture-specific thread context initialisation routine.
*
* This function must set up a thread's context ready for restoring
* and running the thread via archFirstThreadRestore() or
* archContextSwitch().
*
* The layout required to fill the correct register values is
* described in archContextSwitch(). Note that not all registers
* are restored by archContextSwitch() and archFirstThreadRestore()
* as this port takes advantage of the fact that not all registers
* must be stored by ARM gcc C subroutines. This means that we don't
* provide start values for those registers, as they are "don't cares".
*
* @param[in] tcb_ptr Pointer to the TCB of the thread being created
* @param[in] stack_top Pointer to the top of the new thread's stack
* @param[in] entry_point Pointer to the thread entry point function
* @param[in] entry_param Parameter to be passed to the thread entry point
*
* @return None
*/
void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param)
{
uint32_t *stack_ptr;
/** Start at stack top */
tcb_ptr->sp_save_ptr = stack_ptr = stack_top;
/**
* After restoring all of the context registers, the thread restore
* routines will return to the address of the calling routine on the
* stack. In this case (the first time a thread is run) we "return"
* to the entry point for the thread. That is, we store the thread
* entry point in the place that return will look for the return
* address: the stack.
*
* Note that we are using the thread_shell() routine to start all
* threads, so we actually store the address of thread_shell()
* here. Other ports may store the real thread entry point here
* and call it directly from the thread restore routines.
*
* Because we are filling the stack from top to bottom, this goes
* on the stack first (at the top).
*/
*stack_ptr-- = (uint32_t)thread_shell;
/**
* Store starting register values for R4-R11
*/
*stack_ptr-- = (uint32_t) 0x00001111; /* R11 */
*stack_ptr-- = (uint32_t) 0x00001010; /* R10 */
*stack_ptr-- = (uint32_t) 0x00000909; /* R9 */
*stack_ptr-- = (uint32_t) 0x00000808; /* R8 */
*stack_ptr-- = (uint32_t) 0x00000707; /* R7 */
*stack_ptr-- = (uint32_t) 0x00000606; /* R6 */
*stack_ptr-- = (uint32_t) 0x00000505; /* R5 */
*stack_ptr = (uint32_t) 0x00000404; /* R4 */
/**
* All thread context has now been initialised. Save the current
* stack pointer to the thread's TCB so it knows where to start
* looking when the thread is started.
*/
tcb_ptr->sp_save_ptr = stack_ptr;
}

76
ports/arm/atomport.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_H
#define __ATOM_PORT_H
/* Portable uint8_t and friends available from stdint.h on this platform */
#include <stdint.h>
/* Definition of NULL is available from stddef.h on this platform */
#include <stddef.h>
/* Required number of system ticks per second (normally 100 for 10ms tick) */
#define SYSTEM_TICKS_PER_SEC 100
/* Size of each stack entry / stack alignment size (32 bits on this platform) */
#define STACK_ALIGN_SIZE sizeof(uint32_t)
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
/* *
*
* Functions defined in atomport_arm.asm
*
*/
extern uint32_t contextEnterCritical (void) ;
extern void contextExitCritical (uint32_t posture) ;
/**
* Critical region protection: this should disable interrupts
* to protect OS data structures during modification. It must
* allow nested calls, which means that interrupts should only
* be re-enabled when the outer CRITICAL_END() is reached.
*/
#define CRITICAL_STORE uint32_t __atom_critical
#define CRITICAL_START() __atom_critical = contextEnterCritical()
#define CRITICAL_END() contextExitCritical(__atom_critical)
/* Uncomment to enable stack-checking */
/* #define ATOM_STACK_CHECKING */
#endif /* __ATOM_PORT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
############
# Settings #
############
# Build all test applications:
# make
#
# Run all tests within QEMU
# make qemutests
# Location of build tools and atomthreads sources
KERNEL_DIR=../../../../kernel
TESTS_DIR=../../../../tests
PORT_DIR=../..
CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
QEMU=qemu-system-arm
# Enable stack-checking.
#STACK_CHECK=true
# Test programs: Log stack usage to UART (if STACK_CHECK is enabled)
#TESTS_LOG_STACK=true
# Directory for built objects
BUILD_DIR=build
# Platform-specific object files
PLATFORM_OBJECTS = modules.o uart.o
PLATFORM_ASM_OBJECTS = startup.o
# Port-specific object files
PORT_OBJECTS = atomport.o tests-main.o syscalls.o
PORT_ASM_OBJECTS = atomport-asm.o
# Kernel object files
KERNEL_OBJECTS = atomkernel.o atomsem.o atommutex.o atomtimer.o atomqueue.o
# Collection of built objects (excluding test applications)
ALL_OBJECTS = $(PLATFORM_OBJECTS) $(PLATFORM_ASM_OBJECTS) $(PORT_OBJECTS) $(PORT_ASM_OBJECTS) $(KERNEL_OBJECTS)
BUILT_OBJECTS = $(patsubst %,$(BUILD_DIR)/%,$(ALL_OBJECTS))
# Test object files (dealt with separately as only one per application build)
TEST_OBJECTS = $(notdir $(patsubst %.c,%.o,$(wildcard $(TESTS_DIR)/*.c)))
# Target application filenames for each test object
TEST_ELFS = $(patsubst %.o,%.elf,$(TEST_OBJECTS))
# Search build/output directory for dependencies
vpath %.o ./$(BUILD_DIR)
vpath %.elf ./$(BUILD_DIR)
# GCC flags
CFLAGS=-g -c -mcpu=arm926ej-s -ffreestanding -Wall -Werror
AFLAGS=$(CFLAGS) -x assembler-with-cpp
LFLAGS=-mcpu=arm926ej-s -Tsystem.ld -Wall
# Enable stack-checking options (disable if not required)
ifeq ($(STACK_CHECK),true)
CFLAGS += -DATOM_STACK_CHECKING
endif
ifeq ($(TESTS_LOG_STACK),true)
CFLAGS += -DTESTS_LOG_STACK_USAGE
endif
#################
# Build targets #
#################
# All tests
all: $(BUILD_DIR) $(TEST_ELFS) Makefile
# Make build/output directory
$(BUILD_DIR):
mkdir $(BUILD_DIR)
# Test ELF files (one application build for each test)
$(TEST_ELFS): %.elf: %.o $(ALL_OBJECTS)
$(CC) $(LFLAGS) $(BUILD_DIR)/$(notdir $<) $(BUILT_OBJECTS) --output $(BUILD_DIR)/$@ -Wl,-Map,$(BUILD_DIR)/$(basename $@).map
# Kernel objects builder
$(KERNEL_OBJECTS): %.o: $(KERNEL_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Test objects builder
$(TEST_OBJECTS): %.o: $(TESTS_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Platform C objects builder
$(PLATFORM_OBJECTS): %.o: ./%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Platform asm objects builder
$(PLATFORM_ASM_OBJECTS): %.o: ./%.s
$(CC) -c $(AFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Port C objects builder
$(PORT_OBJECTS): %.o: $(PORT_DIR)/%.c
$(CC) -c $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# Port asm objects builder
$(PORT_ASM_OBJECTS): %.o: $(PORT_DIR)/%.s
$(CC) -c $(AFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) $< -o $(BUILD_DIR)/$(notdir $@)
# .lst file builder
%.lst: %.c
$(CC) $(CFLAGS) -I. -I$(PORT_DIR) -I$(KERNEL_DIR) -I$(TESTS_DIR) -Wa,-al $< > $@
# Clean
clean:
rm -f *.o *.elf *.map *.lst
rm -rf doxygen-kernel
rm -rf doxygen-arm
rm -rf doxygen-platform
rm -rf build
# Generate Doxygen documentation
doxygen:
doxygen $(KERNEL_DIR)/Doxyfile
doxygen ../../Doxyfile
doxygen ./Doxyfile
# Run tests within simavr simulator
phony_qemu_elfs = $(addsuffix .sim, $(TEST_ELFS))
qemutests: $(phony_qemu_elfs)
.PHONY: qemutests $(phony_qemu_elfs)
$(phony_qemu_elfs):
./run_test.exp $(QEMU) $(BUILD_DIR)/$(basename $@)

View File

@@ -0,0 +1,223 @@
---------------------------------------------------------------------------
Library: Atomthreads QEMU ARM Integrator/CP (ARM926EJ-S) Platform.
Author: Natie van Rooyen <natie@navaro.nl>
Website: http://atomthreads.com
License: BSD Revised
---------------------------------------------------------------------------
QEMU ARM Integrator/CP (ARM926EJ-S) Platform
The "qemu_integratorcp" platform folder contains sources for building a
sample Atomthreads application for the ARM Integrator/CP (ARM926EJ-S)
platform running under QEMU.
All of the cross-platform kernel code is contained in the top-level
'kernel' folder, while ports to specific CPU architectures are contained in
the 'ports' folder tree. To support multiple ARM boards/platforms using a
single common ARM architecture port, the ARM port contains 'platform'
sub-folders in which the board/platform-specific code is situated. This
allows the sharing of common ARM port code between many different ARM
boards with different interrupt controllers, UARTs etc but which all reuse
the same common core ARM context-switching code.
This platform contains a few key platform-specific files:
* startup.s: Interrupt vector table and basic startup assembly code
* modules.c: Low level initialisation for this platform
* uart.c: Simple UART implementation for debug purposes
The common ARM architecture port that is used across all platforms contains
the basic code for thread-switching on all ARM platforms:
* atomport.c: Those functions which can be written in C
* atomport-asm.s: The main register save/restore assembler routines
Each Atomthreads port requires also a header file which describes various
architecture-specific details such as appropriate types for 8-bit, 16-bit
etc variables, the port's system tick frequency, and macros for performing
interrupt lockouts / critical sections:
* atomport.h: Port-specific header required by the kernel for each port
A couple of additional source files are also included in the common ARM port:
* tests-main.c: Main application file (used for launching automated tests)
* syscalls.c: Simple implementation of open/close/read/write for stdio
Atomthreads includes a suite of automated tests which prove the key OS
functionality, and can be used with any architecture ports. This port
provides an easy mechanism for building and quickly running the test suite
using QEMU to prove the OS without requiring any target hardware.
This platform folder has been tested on a variety of GCC ARM toolchains,
including hosted and non-hosted.
---------------------------------------------------------------------------
GCC TOOLCHAIN
The port works out-of-the-box with the GCC tools (for building) and QEMU
(for simulation). It can be built on any OS for which GCC is available, and
was tested using the CodeSourcery toolchain (2009q3 non-Linux but others
should be supported) and self-built toolchains such as hosted toolchains
built by build_arm_toolchain.sh (see http://navaro.nl for details). Note
that the Makefile for this platform assumes that your GCC binary is named
"arm-none-eabi-gcc".
Currently we assume that the toolchain will provide some header files like
stdint.h. Not all toolchains will include this, in which case you simply
need to add definitions for int32_t and friends in atomport.h, in place of
the include declaration for stdint.h.
Some toolchains provide newlib syscalls.c which implement stdio
functionality via open, close, read, write. Hosted toolchains will
automatically provide versions of these which work with QEMU, and no UART
driver will be needed to view the stdio printf()s etc. If these are not
provided by by the compiler toolchain then backup implementations are
implemented within the common ARM port folder (see ports/arm/syscalls.c)
and a UART driver is implemented here in uart.c.
Similarly some toolchains provide startup assembly code via
_mainCRTStartup(). If this is not provided by the toolchain then a backup
version is used within modules.c.
---------------------------------------------------------------------------
OTHER PREREQUISITES
QEMU is used for simulation of the target and versions 0.14.1, 1.2.0 &
1.4.0 were tested.
Running the entire automated test suite in one command via "make qemutests"
also requires the "expect" program.
---------------------------------------------------------------------------
BUILDING THE SOURCE
A Makefile is provided for building the kernel, port, platform and
automated tests. Make sure the ARM GCC toolchain is in the path
(e.g. "PATH=$PATH:/opt/arm-2009q3/bin && export path") as well as QEMU and
carry out the full build using the following:
* make all
All objects are built into the 'build' folder under
ports/arm/platforms/qemu_integrator_cp. The build process builds separate
target applications for each automated test, and appropriate ELF files can
be found in the build folder ready for running on the target or within
QEMU. Each test is built and run as a separate application.
All built objects etc can be cleaned using:
* make clean
The Atomthreads sources are documented using Doxygen markup. You can build
both the kernel and port documentation from this folder using:
* make doxygen
---------------------------------------------------------------------------
Integrator/CP SPECIFICS
The test applications make use of the Integrator's UART to print out
pass/fail indications and other information. For this you should connect a
serial debug cable to the board or when running in QEMU you will see the
UART messages on the console when running the test applications.
---------------------------------------------------------------------------
AUTOMATED TESTS
Atomthreads contains a set of generic kernel tests which can be run on any
port to prove that all core functionality is working on your target.
The full set of tests can be found in the top-level 'tests' folder. Each of
these tests is built as an independent application in the 'build' folder.
These can be run on the target or within QEMU using the instructions below.
To view the test results, connect a serial debug cable to your target
platform or view the console if using QEMU. On starting, the test
applications print out "Go" on the UART. Once the test is complete they
will print out "Pass" or "Fail", along with other information if the test
failed.
Most of the tests complete within a few seconds, but some (particularly
the stress tests) can take longer, so be patient.
The full suite of tests endeavours to exercise as much of the kernel code
as possible, and can be used for quick confirmation of core OS
functionality if you ever need to make a change to the kernel or port.
The test application main() is contained in tests-main.c. This initialises
the OS, creates a main thread, and calls out to the test modules.
---------------------------------------------------------------------------
RUNNING TESTS WITHIN THE QEMU SIMULATOR
It is possible to run the full automated test suite in a simulator without
programming the test applications into real hardware. This is very useful
for quick verification of the entire test suite after making any software
changes, and is much faster than downloading each test application to a
real target.
A single command runs every single test application, and automatically
parses the (simulated) UART output to verify that each test case passes.
This requires two applications on your development PC: expect and QEMU.
To run all tests in one command, type:
* make qemutests
This will run every single test application within the simulator and quit
immediately if any one test fails.
The ability to run these automated tests in one command (and without real
hardware) allows you to easily include the OS test suite in your nightly
build or continous integration system and quickly find out if any of your
local changes have caused any of the operating system tests to fail.
---------------------------------------------------------------------------
DEBUGGING WITH QEMU
You may also use QEMU in combination with GDB to debug your built
applications. To do this you should start QEMU with "-S -s" options e.g.:
* qemu-system-arm -M integratorcp -semihosting -nographic -kernel app.elf
You can now start GDB and attach to the target:
* arm-none-eabi-gdb
* file app.elf
* target remote localhost:1234
---------------------------------------------------------------------------
WRITING APPLICATIONS
The easiest way to start a new application which utilises the Atomthreads
scheduler is to base your main application startup on tests-main.c. This
initialises the OS and calls out to the test module entry functions. You
can generally simply replace the call to the test modules by a call to your
own application startup code.
---------------------------------------------------------------------------

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "modules.h"
#include <stdio.h>
#include <stdarg.h>
#include "atomport.h"
#include "atomport-private.h"
#include "atom.h"
#include "atomport.h"
#include "uart.h"
/** Imports required by C startup code */
extern unsigned long _end_text, _start_data, _end_data, _start_bss, _end_bss;
extern int main(void);
/** Board-specific registers */
ICP_TIMER_T * const board_timer_0 = (ICP_TIMER_T*)BOARD_BASE_ADDRESS_TIMER_0;
ICP_PIC_T * const board_pic = (ICP_PIC_T*)BOARD_BASE_ADDRESS_PIC;
/** TIMER0 clock speed (Hz) */
#define TIMER0_CLOCK_SPEED 40000000
/**
* \b _mainCRTStartup
*
* C startup code for environments without a suitable built-in one.
* May be provided by the compiler toolchain in some cases.
*
*/
extern void _mainCRTStartup (void) __attribute__((weak));
void _mainCRTStartup(void)
{
unsigned long *src;
#ifdef ROM
unsigned long *dst;
#endif
#ifdef ROM
// Running from ROM: copy data section to RAM
src = &_end_text;
dst = &_start_data;
while(dst < &_end_data)
*(dst++) = *(src++);
#endif
// Clear BSS
src = &_start_bss;
while(src < &_end_bss)
*(src++) = 0;
// Jump to main application entry point
main();
}
/**
* \b low_level_init
*
* Initializes the PIC and starts the system timer tick interrupt.
*
*/
int
low_level_init (void)
{
board_pic->IRQ_ENABLECLR = ICP_PIC_IRQ_TIMERINT0 ;
board_timer_0->INTCLR = 1 ;
board_pic->IRQ_ENABLESET |= ICP_PIC_IRQ_TIMERINT0 ;
/* Set the timer to go off 100 times per second (input clock speed is 40MHz) */
board_timer_0->LOAD = TIMER0_CLOCK_SPEED / SYSTEM_TICKS_PER_SEC ;
board_timer_0->BGLOAD = TIMER0_CLOCK_SPEED / SYSTEM_TICKS_PER_SEC ;
board_timer_0->CONTROL = ICP_TIMER_CONTROL_ENABLE |
ICP_TIMER_CONTROL_MODE |
ICP_TIMER_CONTROL_IE |
ICP_TIMER_CONTROL_TIMER_SIZE ;
return 0 ;
}
/**
* \b __interrupt_dispatcher
*
* Interrupt dispatcher: determines the source of the IRQ and calls
* the appropriate ISR.
*
* Currently only the OS system tick ISR is implemented.
*
* Note that any ISRs which call Atomthreads OS routines that can
* cause rescheduling of threads must be surrounded by calls to
* atomIntEnter() and atomIntExit().
*
*/
void
__interrupt_dispatcher (void)
{
unsigned int status;
/* Read STATUS register to determine the source of the interrupt */
status = board_pic->IRQ_STATUS;
/* Timer tick interrupt (call Atomthreads timer tick ISR) */
if (status | ICP_PIC_IRQ_TIMERINT0)
{
/*
* Let the Atomthreads kernel know we're about to enter an OS-aware
* interrupt handler which could cause scheduling of threads.
*/
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Ack the interrupt */
board_timer_0->INTCLR = 0x1;
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
}
/**
* \b null_handler
*
* Handler to catch interrupts at uninitialised vectors.
*
*/
void null_handler (void)
{
uart_write_halt ("Unhandled interrupt\n");
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MODULES_H__
#define __MODULES_H__
/*
* Module definitions to use with the ARM Integrator/CP (ARM926EJ-S)
*/
#include "atomport.h"
/* IO definitions (access restrictions to peripheral registers) */
#define __I volatile /*!< defines 'read only' permissions */
#define __O volatile /*!< defines 'write only' permissions */
#define __IO volatile /*!< defines 'read / write' permissions */
// *****************************************************************************
// INTEGRATORCP TIMER
// *****************************************************************************
typedef struct ICP_TIMER_S {
// offset read/write word size reset Description
__IO uint32_t LOAD ; // 0x0000 Read/write 32 0x00000000 Load value for Timer
__I uint32_t VALUE ; // 0x0004 Read 32 0xFFFFFFFF The current value for Timer
__IO uint8_t CONTROL ; // 0x0008 Read/write 8 0x20 Timer control register
__O uint32_t INTCLR ; // 0x000C Write - - Timer interrupt clear
__I uint32_t RIS ; // 0x0010 Read 1 0x0 Timer raw interrupt status
__I uint32_t MIS ; // 0x0014 Read 1 0x0 Timer masked interrupt status
__IO uint32_t BGLOAD ; // 0x0018 Read/write 32 0x00000000 Background load value for Timer
} ICP_TIMER_T, *PICP_TIMER_T ;
// -------- ICP_TIMER_LOAD : (LOAD Offset: 0x00) Load value for Timer --------
// -------- ICP_TIMER_VALUE : (LOAD Offset: 0x04) The current value for Timer --------
// -------- ICP_TIMER_CONTROL : (CONTROL Offset: 0x04) Timer control register --------
#define ICP_TIMER_CONTROL_MASK ((unsigned int)0x0F << 0) // Timer control mask
#define ICP_TIMER_CONTROL_ENABLE ((unsigned int)0x01 << 7) // Timer enable: 0 = disabled 1 = enabled.
#define ICP_TIMER_CONTROL_MODE ((unsigned int)0x01 << 6) // Timer mode: 0 = free running, counts once and then wraps to 0xFFFF 1 = periodic, reloads from load register at the end of each count..
#define ICP_TIMER_CONTROL_IE ((unsigned int)0x01 << 5) // Interrupt enable.
#define ICP_TIMER_CONTROL_R ((unsigned int)0x01 << 4) // Unused, always write as 0s.
#define ICP_TIMER_CONTROL_PRESCALE_MASK ((unsigned int)0x03 << 2) // Prescale divisor
#define ICP_TIMER_CONTROL_PRESCALE_NONE ((unsigned int)0x00 << 2) //
#define ICP_TIMER_CONTROL_PRESCALE_16 ((unsigned int)0x01 << 2) //
#define ICP_TIMER_CONTROL_PRESCALE_256 ((unsigned int)0x02 << 2) //
#define ICP_TIMER_CONTROL_TIMER_SIZE ((unsigned int)0x01 << 1) // Selects 16/32 bit counter operation: 0 = 16-bit counter (default) 1 = 32-bit counter For 16-bit mode, write the high 16 bits of the 32-bit value as 0.
#define ICP_TIMER_CONTROL_ONE_SHOT ((unsigned int)0x01 << 0) // Selects one-shot or wrapping counter mode: 0 = wrapping mode (default) 1 = one-shot mode
// -------- ICP_TIMER_INTCLR : (INTCLR Offset: 0x0C) Timer interrupt clear --------
// -------- ICP_TIMER_RIS : (RIS Offset: 0x10) Timer raw interrupt status --------
// -------- ICP_TIMER_MIS : (MIS Offset: 0x14) Timer masked interrupt status --------
#define ICP_TIMER_INT ((unsigned int)0x01 << 0) // Interrupt
// -------- ICP_TIMER_BGLOAD : (BGLOAD Offset: 0x18) Timer masked interrupt status --------
// *****************************************************************************
// INTEGRATORCP PIC
// *****************************************************************************
typedef struct ICP_PIC_S {
// offset read/write word size reset Description
__I uint32_t IRQ_STATUS ; // 0x0000 Read 22 IRQ gated interrupt status
__I uint32_t IRQ_RAWSTAT ; // 0x0004 Read 22 IRQ raw interrupt status
__IO uint32_t IRQ_ENABLESET ; // 0x0008 Read/write 22 IRQ enable set
__O uint32_t IRQ_ENABLECLR ; // 0x000C Write 22 IRQ enable clear
__IO uint32_t INT_SOFTSET ; // 0x0010 Read/write 16 Software interrupt set
__O uint32_t INT_SOFTCLR ; // 0x0014 Write 16 Software interrupt clear
uint32_t RESERVED[2] ; // 0x0018
__I uint32_t FIQ_STATUS ; // 0x0020 Read 22 FIQ gated interrupt status
__I uint32_t FIQ_RAWSTAT ; // 0x0024 Read 22 FIQ raw interrupt status
__IO uint32_t FIQ_ENABLESET ; // 0x0028 Read/write 22 FIQ enable set
__O uint32_t FIQ_ENABLECLR ; // 0x002C Write-only 22 FIQ enable clear
} ICP_PIC_T, *PICP_PIC_T ;
// -------- ICP_PIC_IRQ_STATUS : (IRQ_STATUS Offset: 0x00) IRQ gated interrupt status --------
// -------- ICP_PIC_IRQ_RAWSTAT : (IRQ_RAWSTAT Offset: 0x04) IRQ raw interrupt status --------
// -------- ICP_PIC_IRQ_ENABLESET : (IRQ_ENABLESET Offset: 0x08) IRQ enable set --------
// -------- ICP_PIC_IRQ_ENABLECLR : (IRQ_ENABLECLR Offset: 0x0C) IRQ enable clear --------
#define ICP_PIC_IRQ_MASK ((unsigned int)0x3FFFFF << 0) // IRQ mask
#define ICP_PIC_IRQ_TIMERINT2 ((unsigned int)0x01 << 7) // TIMERINT2 Counter-timer 2 interrupt
#define ICP_PIC_IRQ_TIMERINT1 ((unsigned int)0x01 << 6) // TIMERINT1 Counter-timer 1 interrupt
#define ICP_PIC_IRQ_TIMERINT0 ((unsigned int)0x01 << 5) // TIMERINT0 Counter-timer 0 interrupt
#define ICP_PIC_IRQ_SOFTINT ((unsigned int)0x01 << 0) // OFTINT Software interrupt
// -------- ICP_PIC_INT_SOFTSET : (INT_SOFTSET Offset: 0x10) Software interrupt set --------
// -------- ICP_PIC_INT_SOFTCLR : (INT_SOFTCLR Offset: 0x14) Software interrupt clear --------
/* module definitions */
#define BOARD_BASE_ADDRESS_TIMER_0 0x13000000
#define BOARD_BASE_ADDRESS_PIC 0x14000000
extern ICP_TIMER_T* const board_timer_0 ;
extern ICP_PIC_T* const board_pic ;
/* Function prototypes */
extern int low_level_init (void) ;
#endif /* __MODULES_H__ */

View File

@@ -0,0 +1,39 @@
#!/usr/bin/env expect
# Expect script to run an automated test within QEMU and check for successful
# completion.
#
# Arguments: <path_to_qemu> <test_elf_file>
#
# Returns 0 on successful test run within QEMU, 1 on failure
# Start the test
spawn [lindex $argv 0] -M integratorcp -semihosting -nographic -kernel [lindex $argv 1]
# Expect to see the test starting within 10 seconds
set timeout 10
# Wait for the test to start ("Go")
expect {
"Go\r\n" {
puts "Test started"
# The test could take up to 3 minutes to complete once started
set timeout 180
# Now expect to see "Pass" or "Fail" within 3 minutes
expect {
"Pass\r\n" { puts "Test passed"; exit 0 }
"Fail\r\n" { puts "Test failed"; exit 1 }
timeout { puts "Test timed out without completing"; exit 1 }
}
}
timeout {
# Didn't receive "Go" within 10 seconds
puts "Test failed to start ('Go' not seen)"
exit 1
}
}

View File

@@ -0,0 +1,54 @@
.section .vectors, "x"
.global __interrupt_vector_table
.extern __irq_stack_top__
.extern __fiq_stack_top__
.extern __svc_stack_top__
.equ USR_MODE, 0x10
.equ FIQ_MODE, 0x11
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ ABT_MODE, 0x17
.equ UND_MODE, 0x1B
.equ SYS_MODE, 0x1F
.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */
__interrupt_vector_table:
B Reset_Handler /* Reset */
B Null_Handler /* Undefined */
B Null_Handler /* SWI */
B Null_Handler /* Prefetch Abort */
B Null_Handler /* Data Abort */
B Null_Handler /* reserved */
B IRQ_Handler /* IRQ */
B Null_Handler /* FIQ */
Reset_Handler:
MSR CPSR_c,#(IRQ_MODE | I_BIT | F_BIT)
LDR sp,=__irq_stack_top__ /* set the IRQ stack pointer */
MSR CPSR_c,#(FIQ_MODE | I_BIT | F_BIT)
LDR sp,=__fiq_stack_top__ /* set the FIQ stack pointer */
MSR CPSR_c,#(SVC_MODE | I_BIT | F_BIT)
LDR sp,=__svc_stack_top__ /* set the SVC stack pointer */
BL low_level_init
BL _mainCRTStartup
B .
IRQ_Handler:
B archIRQHandler
Null_Handler:
B null_handler

View File

@@ -0,0 +1,89 @@
ENTRY(__interrupt_vector_table)
MEMORY
{
flash (rx) : ORIGIN = 0x00000000, LENGTH = 0x00020000
sram (rwx) : ORIGIN = 0x00020000, LENGTH = 0x00020000
}
EXTERN(__interrupt_vector_table);
C_STACK_SIZE = 512;
IRQ_STACK_SIZE = 256;
FIQ_STACK_SIZE = 256;
SVC_STACK_SIZE = 512;
ABT_STACK_SIZE = 256;
UND_STACK_SIZE = 256;
SECTIONS
{
.text :
{
*(.vectors)
/* Startup assembly */
*(.startup)
*(.init)
/* Rest of the code (C) */
*(.text)
*(.rodata)
*(.rodata*)
_end_text = .;
} >flash
.data :
{
_start_data = .;
*(.data)
_end_data = .;
} >sram
.bss :
{
_start_bss = .;
__bss_start__ = . ;
*(.bss)
} >sram
. = ALIGN(4);
_end_bss = .;
__bss_end__ = . ;
. = ALIGN(256);
.stack : {
__stack_start__ = . ;
. += IRQ_STACK_SIZE;
. = ALIGN (4);
__irq_stack_top__ = . ;
. += FIQ_STACK_SIZE;
. = ALIGN (4);
__fiq_stack_top__ = . ;
. += SVC_STACK_SIZE;
. = ALIGN (4);
__svc_stack_top__ = . ;
. += ABT_STACK_SIZE;
. = ALIGN (4);
__abt_stack_top__ = . ;
. += UND_STACK_SIZE;
. = ALIGN (4);
__und_stack_top__ = . ;
. += C_STACK_SIZE;
. = ALIGN (4);
__c_stack_top__ = . ;
__stack_end__ = .;
} >sram
}
__end__ = .;
_end = .;
PROVIDE(end = .);
heap_top = ORIGIN(sram) + LENGTH(sram) - 4;

View File

@@ -0,0 +1,255 @@
/*
* Copyright (c) 2013, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
* Simple polled UART implementation for non-hosted compiler toolchains.
*
*
* This is only required for non-hosted toolchains which don't implement
* stdout automatically for use within QEMU.
*/
#include "atom.h"
#include "atommutex.h"
#include "atomport.h"
#include "uart.h"
/* Constants */
/** UART0 registers base address */
#define UART0_ADDR 0x16000000
/** FR Register bits */
#define UART_FR_RXFE 0x10
#define UART_FR_TXFF 0x20
/** UART register access macros */
#define UART_DR(baseaddr) (*(unsigned int *)(baseaddr))
#define UART_FR(baseaddr) (*(((unsigned int *)(baseaddr))+6))
/* Local data */
/*
* Semaphore for single-threaded access to UART device
*/
static ATOM_MUTEX uart_mutex;
/*
* Initialised flag
*/
static int initialised = FALSE;
/* Forward declarations */
static int uart_init (void);
/**
* \b uart_init
*
* Initialisation of UART driver. Creates a mutex that enforces
* single-threaded access to the UART. We poll register bits
* to check when space is available, which would not otherwise
* be thread-safe.
*
* @retval ATOM_OK Success
* @retval ATOM_ERROR Failed to create mutex
*/
static int uart_init (void)
{
int status;
/* Check we are not already initialised */
if (initialised == FALSE)
{
/* Create a mutex for single-threaded UART access */
if (atomMutexCreate (&uart_mutex) != ATOM_OK)
{
/* Mutex creation failed */
status = ATOM_ERROR;
}
else
{
/* Success */
initialised = TRUE;
status = ATOM_OK;
}
}
/* Finished */
return (status);
}
/**
* \b uart_read
*
* Simple polled UART read.
*
* @param[in] ptr Pointer to receive buffer
* @param[in] len Max bytes to read
*
* @retval Number of bytes read
*
*/
int uart_read (char *ptr, int len)
{
int todo = 0;
/* Check we are initialised */
if (initialised == FALSE)
{
uart_init();
}
/* Check parameters */
if ((ptr == NULL) || (len == 0))
{
return 0;
}
/* Block thread on private access to the UART */
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
{
/* Wait for not-empty */
while(UART_FR(UART0_ADDR) & UART_FR_RXFE)
;
/* Read first byte */
*ptr++ = UART_DR(UART0_ADDR);
/* Loop over remaining bytes until empty */
for (todo = 1; todo < len; todo++)
{
/* Quit if receive FIFO empty */
if(UART_FR(UART0_ADDR) & UART_FR_RXFE)
{
break;
}
/* Read next byte */
*ptr++ = UART_DR(UART0_ADDR);
}
/* Return mutex access */
atomMutexPut(&uart_mutex);
}
/* Return number of bytes read */
return todo;
}
/**
* \b uart_write
*
* Simple polled UART write.
*
* @param[in] ptr Pointer to write buffer
* @param[in] len Number of bytes to write
*
* @retval Number of bytes written
*/
int uart_write (const char *ptr, int len)
{
int todo;
/* Check we are initialised */
if (initialised == FALSE)
{
uart_init();
}
/* Check parameters */
if ((ptr == NULL) || (len == 0))
{
return 0;
}
/* Block thread on private access to the UART */
if (atomMutexGet(&uart_mutex, 0) == ATOM_OK)
{
/* Loop through all bytes to write */
for (todo = 0; todo < len; todo++)
{
/* Wait for empty */
while(UART_FR(UART0_ADDR) & UART_FR_TXFF)
;
/* Write byte to UART */
UART_DR(UART0_ADDR) = *ptr++;
}
/* Return mutex access */
atomMutexPut(&uart_mutex);
}
/* Return bytes-written count */
return len;
}
/**
* \b uart_write_halt
*
* Simple polled UART write for handling critical failures
* by printing out a message on the UART and looping forever.
* Can be called from interrupt (unlike the standard
* uart_write()) but is not thread-safe because it cannot
* take the thread-safety mutex, and hence is only useful for
* a last-resort catastrophic debug message.
*
* @param[in] ptr Pointer to write string
*/
void uart_write_halt (const char *ptr)
{
/* Check parameters */
if (ptr != NULL)
{
/* Loop through all bytes until NULL terminator encountered */
while (*ptr != '\0')
{
/* Wait for empty */
while(UART_FR(UART0_ADDR) & UART_FR_TXFF)
;
/* Write byte to UART */
UART_DR(UART0_ADDR) = *ptr++;
}
}
/* Loop forever */
while (1)
;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_UART_H
#define __ATOM_UART_H
/* UART driver APIs */
extern int uart_read (char *ptr, int len);
extern int uart_write (const char *ptr, int len);
extern void uart_write_halt (const char *ptr);
#endif /* __ATOM_UART_H */

211
ports/arm/syscalls.c Normal file
View File

@@ -0,0 +1,211 @@
/*
* Copyright (c) 2013, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
* Syscalls implementation for stdio and heap management.
*
*
* Simple implementation of syscalls.c for ARM compiler toolchains built
* without newlib. Allows usage of printf() and friends as well as heap
* allocation.
*
* NOTE: Platform/BSP must implement uart_read() and uart_write().
*
* NOTE: Platform/BSP linker script must define "end" and "heap_top" which are
* the heap base and top respectively.
*
* No file table is implemented. All file read/write operations are carried
* out on the UART driver, regardless of file descriptor.
*
* Mostly based on code from http://balau82.wordpress.com
*
*/
#include <sys/stat.h>
#include "uart.h"
/**
* Define all functions as weak so that the functions in this file will
* only be used if the compiler toolchain doesn't already provide them.
*/
extern int _close(int file) __attribute__((weak));
extern int _fstat(int file, struct stat *st) __attribute__((weak));
extern int _isatty(int file) __attribute__((weak));
extern int _lseek(int file, int ptr, int dir) __attribute__((weak));
extern int _open(const char *name, int flags, int mode) __attribute__((weak));
extern int _read(int file, char *ptr, int len) __attribute__((weak));
extern caddr_t _sbrk(int incr) __attribute__((weak));
extern int _write(int file, char *ptr, int len) __attribute__((weak));
/**
* \b _close
*
* Simple stub implementation with no file table. All parameters ignored.
*
*/
int _close(int file)
{
return -1;
}
/**
* \b _fstat
*
* Simple stub implementation. Always return character device.
*
*/
int _fstat(int file, struct stat *st)
{
/* Only UART supported, always return character-oriented device file */
st->st_mode = S_IFCHR;
return 0;
}
/**
* \b _isatty
*
* Simple stub implementation. Only UART supported so TTY always true.
*
*/
int _isatty(int file)
{
return 1;
}
/**
* \b _lseek
*
* Simple stub implementation. All parameters ignored.
*
*/
int _lseek(int file, int ptr, int dir)
{
return 0;
}
/**
* \b _open
*
* Simple stub implementation with no file table. All parameters ignored.
*
*/
int _open(const char *name, int flags, int mode)
{
return -1;
}
/**
* \b _read
*
* Simple read file implementation. Ignores file descriptor parameter
* and always reads from the UART driver.
*
* @param[in] file File descriptor (parameter ignored)
* @param[in] ptr Pointer to receive buffer
* @param[in] len Max bytes to read
*
* @retval Number of bytes read
*/
int _read(int file, char *ptr, int len)
{
/* Read from the UART driver, regardless of file descriptor */
return (uart_read (ptr, len));
}
/**
* \b _write
*
* Simple write file implementation. Ignores file descriptor parameter
* and always writes to the UART driver.
*
* @param[in] file File descriptor (parameter ignored)
* @param[in] ptr Pointer to write buffer
* @param[in] len Number of bytes to write
*
* @retval Number of bytes written
*/
int _write(int file, char *ptr, int len)
{
/* Write to the UART driver, regardless of file descriptor */
return (uart_write (ptr, len));
}
/**
* \b _sbrk
*
* Simple heap implementation.
*
* The platform/BSP must define "end" and "heap_top" which are the heap
* base and top respectively.
*
* @param[in] incr Chunk size
*
* @retval Pointer to allocated chunk start
*/
caddr_t _sbrk(int incr)
{
extern char end; /* Defined by the linker */
extern char heap_top; /* Defined by the linker */
static char *heap_end = 0;
char *prev_heap_end;
/* First time in, initialise heap base using definition from linker script */
if (heap_end == 0)
{
heap_end = &end;
}
/* Save the previous heap base */
prev_heap_end = heap_end;
/* Check we have not passed the heap top */
if (heap_end + incr > &heap_top)
{
/* Heap top reached, failed to allocate */
return (caddr_t)0;
}
/* New heap base */
heap_end += incr;
/* Return pointer to previous base (where our allocation starts) */
return (caddr_t)prev_heap_end;
}

203
ports/arm/tests-main.c Normal file
View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) 2013, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "atom.h"
#include "atomport-private.h"
#include "atomtests.h"
#include "atomtimer.h"
/* Constants */
/*
* Idle thread stack size
*
* This needs to be large enough to handle any interrupt handlers
* and callbacks called by interrupt handlers (e.g. user-created
* timer callbacks) as well as the saving of all context when
* switching away from this thread.
*/
#define IDLE_STACK_SIZE_BYTES 512
/*
* Main thread stack size
*
* Note that this is not a required OS kernel thread - you will replace
* this with your own application thread.
*
* In this case the Main thread is responsible for calling out to the
* test routines. Once a test routine has finished, the test status is
* printed out on the UART and the thread remains running in a loop.
*
* The Main thread stack generally needs to be larger than the idle
* thread stack, as not only does it need to store interrupt handler
* stack saves and context switch saves, but the application main thread
* will generally be carrying out more nested function calls and require
* stack for application code local variables etc.
*
* 1KB might be adequate but if using printf() then at least 2KB would be
* prudent otherwise the stdio functions otherwise stack overruns are
* likely. Nearly 2KB was seen to be used on the toolchain used for
* development.
*/
#define MAIN_STACK_SIZE_BYTES 4096
/* Local data */
/* Application threads' TCBs */
static ATOM_TCB main_tcb;
/* Main thread's stack area */
static uint8_t main_thread_stack[MAIN_STACK_SIZE_BYTES];
/* Idle thread's stack area */
static uint8_t idle_thread_stack[IDLE_STACK_SIZE_BYTES];
/* Forward declarations */
static void main_thread_func (uint32_t data);
/**
* \b main
*
* Program entry point.
*
* Creates an application thread and starts the OS.
*/
int main ( void )
{
int8_t status;
/**
* Note: to protect OS structures and data during initialisation,
* interrupts must remain disabled until the first thread
* has been restored. They are reenabled at the very end of
* the first thread restore, at which point it is safe for a
* reschedule to take place.
*/
/**
* Initialise the OS before creating our threads.
*/
status = atomOSInit(&idle_thread_stack[0], IDLE_STACK_SIZE_BYTES, TRUE);
if (status == ATOM_OK)
{
/* Create an application thread */
status = atomThreadCreate(&main_tcb,
TEST_THREAD_PRIO, main_thread_func, 0,
&main_thread_stack[0],
MAIN_STACK_SIZE_BYTES,
TRUE);
if (status == ATOM_OK)
{
/**
* First application thread successfully created. It is
* now possible to start the OS. Execution will not return
* from atomOSStart(), which will restore the context of
* our application thread and start executing it.
*
* Note that interrupts are still disabled at this point.
* They will be enabled as we restore and execute our first
* thread in archFirstThreadRestore().
*/
atomOSStart();
}
}
while (1)
;
/* There was an error starting the OS if we reach here */
return (0);
}
/**
* \b main_thread_func
*
* Entry point for main application thread.
*
* This is the first thread that will be executed when the OS is started.
*
* @param[in] data Unused (optional thread entry parameter)
*
* @return None
*/
static void main_thread_func (uint32_t data)
{
uint32_t test_status;
/* Put a message out on the UART */
printf ("Go\n");
/* Start test. All tests use the same start API. */
test_status = test_start();
/* Check main thread stack usage (if enabled) */
#ifdef ATOM_STACK_CHECKING
if (test_status == 0)
{
uint32_t used_bytes, free_bytes;
/* Check idle thread stack usage */
if (atomThreadStackCheck (&main_tcb, &used_bytes, &free_bytes) == ATOM_OK)
{
/* Check the thread did not use up to the end of stack */
if (free_bytes == 0)
{
printf ("Main stack overflow\n");
test_status++;
}
/* Log the stack usage */
#ifdef TESTS_LOG_STACK_USAGE
printf ("MainUse:%d\n", (int)used_bytes);
#endif
}
}
#endif
/* Log final status */
if (test_status == 0)
{
printf ("Pass\n");
}
else
{
printf ("Fail(%d)\n", (int)test_status);
}
}

40
ports/atomvm/README Normal file
View File

@@ -0,0 +1,40 @@
---------------------------------------------------------------------------
Library: Atomvn
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
Atomvm is a tiny virtual machine that runs on Windows and can be debugged
from an IDE like Microsoft Visual C++ Express. The primary purpose of this
virtual machine is for the evaluation of Real Time Operating Systems like
Atomthreads and the development and testing of programs for it on a Windows
machine.
Atomvm makes use of the Windows API functions GetThreadContext() and
SetThreadContext() to create multiple virtual contexts or threads inside a
single Windows thread. Atomvm also simulates interrupts with an interrupt
mask accessible from the Atomvm threads. External events can be queued as
interrupts to Atomvm, for example a timer loop generating system timer tick
interrupts for a Real Time Operating System ported to Atomvm.
---------------------------------------------------------------------------
BUILDING THE SOURCE
To test this project, just add all the files from the "atomthreads/kernel"
directory and the "atomthreads/ports/atomvm" directory as well as the test
program "atomthreads/ports/atomvm/test/main.c" to your project. Add both the
before mentioned directories to the include paths of your project and compile.
Atomvm was designed for multi core systems but also runs fine on any single
core system.
---------------------------------------------------------------------------
RUNNING THE TESTS
The test, main.c, is intentioned to stress the virtual machine.

36
ports/atomvm/README.txt Normal file
View File

@@ -0,0 +1,36 @@
---------------------------------------------------------------------------
Library: Atomvn
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
Atomvm is a tiny virtual machine that can run on Windows inside an IDE with a
debugger like Microsoft Visual C++ Express. The primary purpose of this virtual
machine is for the evaluation of Real Time Operating Systems (like atomthreads)
and the development and testing of modules for this Real Time Operating System
in a user friendly environment.
---------------------------------------------------------------------------
BUILDING THE SOURCE
To test this project, just add all the files from the "atomthreads/kernel"
directory and the "atomthreads/ports/atomvm" directory as well as the test
program "atomthreads/ports/atomvm/test/main.c" to your project. Add both the
before mentioned directories to the include paths of your project and compile.
Atomvm was designed for multi core systems but also runs fine on any single
core system.
---------------------------------------------------------------------------
RUNNING THE TESTS
The test, main.c, is intentioned to stress the virtual machine as opposed to
testing the Real Time Operating System. However, this test can also run the
unit tests of atomthreads by using the preprocessor directive "UNIT_TESTS" and
linking in the desired unit test into the project.

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOMPORT_TEST_H__
#define __ATOMPORT_TEST_H__
/* Include Atomthreads kernel API */
#include "atom.h"
/* Prerequisite include for ATOMLOG() macro (via printf) */
#include <stdio.h>
/* Logger macro for viewing test results */
#define ATOMLOG printf
/*
* String location macro: for platforms which need to place strings in
* alternative locations, e.g. on avr-gcc strings can be placed in
* program space, saving SRAM. On most platforms this can expand to
* empty.
*/
#define _STR(x) x
/* Default thread stack size (in bytes) */
#define TEST_THREAD_STACK_SIZE 0x4000
/* Uncomment to enable logging of stack usage to UART */
/* #define TESTS_LOG_STACK_USAGE */
#endif /* __ATOMPORT_TEST_H__ */

159
ports/atomvm/atomport.c Normal file
View File

@@ -0,0 +1,159 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomport.h"
#include "atomvm.h"
#include "windows.h"
/** Forward declarations */
DWORD WINAPI cntrl_thread_proc (LPVOID lpParameter) ;
/* Global data */
HATOMVM the_atomvm ;
/* Local data */
static HANDLE cntrl_thread ;
/**
* \b atomvmRun
*
* Starts the atom vm. atomvmRun creates a thread from where the atomvmCtrlRun function
* will be called. atomvmCtrlRun never returns and this thread becomes the controll
* thread of the vm.
*
*/
void
atomvmRun (void)
{
atomvmCtrlCreate (&the_atomvm) ;
cntrl_thread = CreateThread (NULL, 0, cntrl_thread_proc, (uint32_t*)the_atomvm, CREATE_SUSPENDED, NULL) ;
ResumeThread (cntrl_thread) ;
}
DWORD WINAPI
cntrl_thread_proc (LPVOID lpParameter)
{
atomvmCtrlRun ((HATOMVM)lpParameter, 0) ;
return 0 ;
}
/**
* \b thread_shell
*
* Documented in atomThreads.
*
*/
void
thread_shell (uint32_t arg)
{
ATOM_TCB *curr_tcb;
/* Get the TCB of the thread being started */
curr_tcb = atomCurrentContext();
/**
* Enable interrupts - these will not be enabled when a thread
* is first restored.
*/
// sei();
//atomvmExitCritical () ;
atomvmInterruptMask (0) ;
/* Call the thread entry point */
if (curr_tcb && curr_tcb->entry_point)
{
curr_tcb->entry_point(curr_tcb->entry_param);
}
/* Not reached - threads should never return from the entry point */
}
/**
* \b archThreadContextInit
*
* Documented in atomThreads.
*
*/
void
archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param)
{
tcb_ptr->sp_save_ptr = stack_top;
tcb_ptr->entry_param = entry_param ;
tcb_ptr->entry_point = entry_point ;
tcb_ptr->context = atomvmContextCreate (1) ;
atomvmContextInit (tcb_ptr->context, (unsigned int *)stack_top, thread_shell, entry_param, 0) ;
}
/**
* \b archFirstThreadRestore
*
* Documented in atomThreads.
*
*/
void
archFirstThreadRestore(ATOM_TCB * p_sp_new)
{
atomvmContextSwitch (0, p_sp_new->context) ;
}
/**
* \b archContextSwitch
*
* Documented in atomThreads.
*
*/
void
archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new)
{
atomvmContextSwitch (p_sp_old->context, p_sp_new->context) ;
}
/**
* \b archTimerTickIrqHandler
*
* System timer tick interrupt handler.
*
*/
void archTimerTickIrqHandler (void)
{
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}

62
ports/atomvm/atomport.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_H__
#define __ATOM_PORT_H__
#include "atomvm.h"
#define SYSTEM_TICKS_PER_SEC 100
/* Size of each stack entry / stack alignment size (e.g. 32 bits) */
#define STACK_ALIGN_SIZE sizeof(unsigned int)
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
#define ATOM_TLS HATOMVM_CONTEXT context ;
/* Critical region protection */
#define CRITICAL_STORE unsigned int __atom_int_mask
#define CRITICAL_START() __atom_int_mask = atomvmInterruptMask(1)
#define CRITICAL_END() atomvmInterruptMask(__atom_int_mask)
#define ATOM_TLS HATOMVM_CONTEXT context ;
/* Function prototypes */
extern void atomvmRun (void) ;
extern void archTimerTickIrqHandler (void) ;
/* The instance of the atomvm for this port */
extern HATOMVM the_atomvm ;
#endif /* __ATOM_PORT_H__ */

63
ports/atomvm/atomuser.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010,Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if 1
#ifndef __ATOM_USER_H__
#define __ATOM_USER_H__
/* Portable uint8_t and friends not available from stdint.h on this platform */
#include <windows.h>
#define SYSTEM_MEMALIGN sizeof (unsigned int)
typedef unsigned int uintptr_t ;
typedef int intptr_t ;
typedef unsigned int uint32_t ;
typedef unsigned short uint16_t ;
typedef unsigned char uint8_t ;
typedef int int32_t ;
typedef short int16_t ;
typedef char int8_t ;
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
#define ATOM_TLS HATOMVM_CONTEXT context ;
#endif /* __ATOM_USER_H__ */
#endif

852
ports/atomvm/atomvm.c Normal file
View File

@@ -0,0 +1,852 @@
/*
* Copyright (c) 2010, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
* Atom Virtual Machine.
*
*
* This module implements the virtual machine.
*
*
* \b Functions contained in this module:\n
*
* \b Function prototypes used for controlling the atom virtual machine: \n
*
* \li atomvmCtrlCreate(): .
* \li atomvmCtrlRun(): .
* \li atomvmCtrlIntRequest(): .
* \li atomvmCtrlClose(): .
*
* \b Function prototypes for use by the atom virtual machine: \n
*
* \li atomvmInterruptMask(): .
* \li atomvmContextCreate(): .
* \li atomvmContextSwitch(): .
* \li atomvmContextDesrtroy(): .
* \li atomvmWriteThreadId(): .
* \li atomvmReadThreadId(): .
* \li atomvmInterruptWait(): .
* \li atomvmGetVmId(): .
*
* \b Function prototypes to be implemted in the atom virtual machine: \n
*
* \li __atomvmReset(): .
* \li __atomvmClose(): .
*
*/
#include "atomvm.h"
#include <string.h>
#include <windows.h>
#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS)
/* Data types */
/* Forward declarations */
typedef struct ATOMVM_S * PATOMVM ;
typedef struct ATOMVM_CALLBACK_S * PATOMVM_CALLBACK ;
typedef struct ATOMVM_CONTEXT_S * PATOMVM_CONTEXT ;
typedef uint32_t (*ATOMVM_CALLBACK_F) (PATOMVM, PATOMVM_CALLBACK) ;
typedef struct ATOMVM_CALLBACK_S {
/* Address of callback function */
volatile ATOMVM_CALLBACK_F callback ;
/* Synchronization lock, the virtual machine will be suspended during
the callback. Regular WIN32 synchronization methods cant be used
because SuspendThread() is used on the vm thread. */
volatile uint32_t lock ;
/* Result of the call */
volatile uint32_t result ;
} ATOMVM_CALLBACK, *PATOMVM_CALLBACK ;
/* ATOMVM_CALLBACK_CONTEXT is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to a ATOMVM_CONTEXT to operate on */
typedef struct ATOMVM_CALLBACK_CONTEXT_S {
ATOMVM_CALLBACK callback ;
/* Context the callback function will operate on */
volatile PATOMVM_CONTEXT pcontext ;
} ATOMVM_CALLBACK_CONTEXT, *PATOMVM_CALLBACK_CONTEXT ;
/* ATOMVM_CALLBACK_CONTEXT_SWITCH is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to a ATOMVM_CONTEXT to operate on */
typedef struct ATOMVM_CALLBACK_CONTEXT_SWITCH_S {
ATOMVM_CALLBACK callback ;
/* Context the callback function will operate on */
volatile PATOMVM_CONTEXT p_old_context ;
volatile PATOMVM_CONTEXT p_new_context ;
} ATOMVM_CALLBACK_CONTEXT_SWITCH, *PATOMVM_CALLBACK_CONTEXT_SWITCH ;
/* ATOMVM_CALLBACK_INT_REQUEST is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to to the function that will be called in
an interrupt context */
typedef struct ATOMVM_CALLBACK_INT_REQUEST_S {
ATOMVM_CALLBACK callback ;
/* Function pointer the callback will call */
void (*isr) (void) ;
} ATOMVM_CALLBACK_INT_REQUEST, *PATOMVM_CALLBACK_INT_REQUEST ;
/* ATOMVM_CONTEXT saves the state of a context created by
atomvmContextCreate() and sheduled by atomvmContextSwitch(). */
typedef struct ATOMVM_CONTEXT_S {
/* A virtual machine thread context. These are saved and restored
during context initialization and context switches */
CONTEXT context ;
/* When entering a critical section the interrupt_mask is
set for the context. Interrupts will only occur while
the interrupt_mask is zero. */
volatile uint32_t interrupt_mask ;
uint32_t thread_id ;
} ATOMVM_CONTEXT, *PATOMVM_CONTEXT ;
/* ATOMVM defines the state of an instance to an atomvm. It is created
by a call to atomvmCtrlCreate(). */
typedef struct ATOMVM_S {
uint32_t atomvm_id ;
/* Thread the virtual machine will run in */
HANDLE vm_thread ;
/* Handles to events and mutexes used for synchronization */
HANDLE atomvm_call ;
HANDLE atomvm_int ;
HANDLE atomvm_int_complete ;
HANDLE atomvm_close ;
/* next ISR */
volatile void (*isr)(void) ;
/* True if in an ISR */
volatile uint32_t status_isr ;
/* The current context that was scheduled by a call
to atomvmContextSwitch() */
PATOMVM_CONTEXT current_context ;
/* Service call address, synchronization lock, parameters
and, return value for the current service call */
PATOMVM_CALLBACK service_call ;
/* Context for startup, before any context was scheduled */
ATOMVM_CONTEXT atom_init_context ;
} ATOMVM, *PATOMVM ;
/* Global declarations */
volatile uint32_t g_atomvm_id = 0 ;
volatile DWORD g_atomvm_tls_idx ;
/* Forward declaration for the atom virtual machine thread */
static DWORD WINAPI vm_thread (LPVOID lpParameter) ;
/**
* \ingroup atomvm
* \b atomvmCtrlCreate
*
* This is an atomvm controll function used by a controlling thread.
*
* Initializes the virtual machine.
*
* @param[out] atomvm Handle to the virtual machine to create.
*
* @return Zero on failure.
*/
uint32_t
atomvmCtrlCreate (HATOMVM *atomvm)
{
PATOMVM patomvm = 0 ;
patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ;
if (patomvm) {
memset (patomvm, 0, sizeof(struct ATOMVM_S)) ;
patomvm->atomvm_id = InterlockedIncrement(&g_atomvm_id) - 1 ;
if (patomvm->atomvm_id == 0) {
g_atomvm_tls_idx = TlsAlloc () ;
}
patomvm->atomvm_call = CreateEvent (NULL, TRUE, FALSE, 0) ;
patomvm->atomvm_int = CreateEvent (NULL, TRUE, FALSE, 0) ;
patomvm->atomvm_int_complete = CreateEvent (NULL, FALSE, TRUE, 0) ;
patomvm->atomvm_close = CreateEvent (NULL, TRUE, FALSE, 0) ;
ATOMVM_ASSERT(patomvm->atomvm_call && patomvm->atomvm_int && patomvm->atomvm_int_complete &&
patomvm->atomvm_close, _T("ResumeThread failed")) ;
patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, (void*)patomvm, CREATE_SUSPENDED, NULL) ;
ATOMVM_ASSERT(patomvm->vm_thread, _T("CreateThread failed")) ;
patomvm->atom_init_context.interrupt_mask = 1 ;
patomvm->current_context = &patomvm->atom_init_context ;
*atomvm = (HATOMVM)patomvm ;
}
return patomvm != 0 ;
}
/**
* \ingroup atomvm
* \b atomvmCtrlRun
*
* After a call to atomvmCtrlCreate this function start the atom virtual machine.
* The calling thread will be used to manage interrupts and service calls in
* the virtual machine. This function will not return untill atomvmCtrlClose
* is called.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
* @param[in] flags not used.
*
* @return None
*/
void
atomvmCtrlRun (HATOMVM atomvm, uint32_t flags)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
HANDLE wait[3] ;
uint32_t res ;
uint32_t wait_object ;
PATOMVM_CALLBACK service_call ;
#if defined DEBUG || defined _DEBUG
BOOL tls_res =
#endif
TlsSetValue (g_atomvm_tls_idx, (void*) atomvm) ;
ATOMVM_ASSERT(tls_res, _T("TlsSetValue failed")) ;
ResumeThread (patomvm->vm_thread) ;
wait[0] = patomvm->atomvm_call ;
wait[1] = patomvm->atomvm_int ;
wait[2] = patomvm->atomvm_close ;
for(;;) {
wait_object = WaitForMultipleObjects (3, wait,FALSE,INFINITE) ;
if (wait_object == WAIT_OBJECT_0) {
service_call = patomvm->service_call ;
while (!service_call->lock) {
SwitchToThread () ;
}
while ((res = SuspendThread (patomvm->vm_thread)) == (DWORD)-1) ;
ATOMVM_ASSERT(res == 0 , _T("SuspendThread failed")) ;
#if (_WIN32_WINNT >= 0x0600)
/*
This is used for multi processor machines to ensure the thread
is stopped before executing the next instruction. Set
_WIN32_WINNT < 0x0600 if you are running Windows XP */
FlushProcessWriteBuffers ();
#endif
InterlockedExchange (&service_call->result, service_call->callback (patomvm, service_call)) ;
InterlockedExchange (&service_call->lock, 0) ;
ResetEvent (patomvm->atomvm_call) ;
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
}
else if (wait_object == WAIT_OBJECT_0 + 1) {
if (patomvm->current_context->interrupt_mask == 0) {
while ((res = SuspendThread (patomvm->vm_thread)) == (DWORD)-1) ;
ATOMVM_ASSERT(res == 0 , _T("SuspendThread failed")) ;
#if (_WIN32_WINNT >= 0x0600)
/*
This is used for multi processor machines to ensure the thread
is stopped before executing the next instruction. Set
_WIN32_WINNT < 0x0600 if you are running Windows XP */
FlushProcessWriteBuffers ();
#endif
if (patomvm->current_context->interrupt_mask == 0) {
patomvm->status_isr++ ;
patomvm->isr () ;
patomvm->status_isr-- ;
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
ResetEvent (patomvm->atomvm_int) ;
InterlockedExchange ((volatile uint32_t*)&patomvm->isr, 0) ;
SetEvent (patomvm->atomvm_int_complete) ;
} else {
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
SwitchToThread () ;
}
} else {
SwitchToThread () ;
}
} else if (wait_object == WAIT_OBJECT_0 + 2) {
break ;
} else {
ATOMVM_ASSERT(res == 1 , _T("WaitForMultipleObjects failed")) ;
}
}
}
/**
* \ingroup atomvm
* \b atomvmCtrlClose
*
* This is an atomvm controll function used by a controlling thread
* and must not be called from the atom virtual machine.
*
* Closes the virtual machine and release all memory and handles created
* in atomvmCtrlCreate.
*
* ToDo: more testing.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
*
* @return None
*/
void
atomvmCtrlClose (HATOMVM atomvm)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
DWORD code ;
__atomvmClose () ;
SetEvent (patomvm->atomvm_close) ;
do {
SwitchToThread () ;
GetExitCodeThread (patomvm->vm_thread, &code) ;
} while (code == STILL_ACTIVE) ;
CloseHandle (patomvm->atomvm_call) ;
CloseHandle (patomvm->atomvm_int) ;
CloseHandle (patomvm->atomvm_int_complete) ;
CloseHandle (patomvm->atomvm_close) ;
CloseHandle (patomvm->vm_thread) ;
// TlsFree (g_atomvm_tls_idx) ;
free (atomvm) ;
}
/**
* \b invokeCallback
*
* Invokes callback functions in the context of the controll thread as
* requested from the virtual machine. In case this callback came from inside,
* an isr it is already in the conrtext of the controll thread and the callback
* routine is called directly.
*
* The atom virtual machine thread is suspended during the callback.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[in] callback Callback function.
* @param[in/out] context Context the function will operate on.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
invokeCallback (PATOMVM patomvm, ATOMVM_CALLBACK_F callback, PATOMVM_CALLBACK service_call)
{
uint32_t res ;
if (patomvm->status_isr == 0) {
service_call->lock = 0 ;
service_call->callback = callback ;
patomvm->service_call = service_call ;
SetEvent (patomvm->atomvm_call) ;
InterlockedIncrement (&service_call->lock) ;
while (service_call->lock != 0) ;
res = service_call->result ;
} else {
res = callback (patomvm, service_call) ;
}
return res ;
}
/*
* \b getAtomvm
*
* Get the atomvm instance for the calling thread
*
* @return atomvm instance
*/
__inline PATOMVM
getAtomvm (void)
{
PATOMVM patomvm = (PATOMVM) TlsGetValue (g_atomvm_tls_idx) ;
ATOMVM_ASSERT(patomvm , _T("TlsGetValue failed")) ;
return patomvm ;
}
/**
* \ingroup atomvm
* \b atomvmInterruptMask
*
* This function is to be used by the atom virtual machine.
*
* This function will mask interrupts for the current atomvm context.
*
* @param[in] mask zero enables interrupts any other value masks interrupts.
*
* @return Interrupt mask before the function call.
*/
int32_t
atomvmInterruptMask (uint32_t mask)
{
PATOMVM patomvm = getAtomvm () ;
int32_t interrupts = 0;
if (patomvm->status_isr == 0) {
interrupts = InterlockedExchange (&patomvm->current_context->interrupt_mask, mask) ;
}
return interrupts ;
}
/**
* \ingroup atomvm
* \b atomvmCtrlIntRequest
*
* This is an atomvm controll function used by external threads
* and must not be called from the atom virtual machine.
*
* This function requests an interrupt service routine to be called in the
* context of the atom virtual machine.
*
* The call will return immediately after the interrupt was scheduled.
* The call will block while a previously scheduled interrupt is in progress.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
* @param[in] isr The address of the interrupt service routine.
*
* @return None
*/
void
atomvmCtrlIntRequest (HATOMVM atomvm, void (*isr) (void))
{
PATOMVM patomvm = (PATOMVM) atomvm ;
WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ;
while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, (uint32_t)isr, 0) != 0) {
SwitchToThread() ;
}
SetEvent (patomvm->atomvm_int) ;
}
/**
* \b callbackContextCreate
*
* This function is invoked from the controll thread after a call to atomvmContextCreate.
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[out] context Context to be initialized.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback;
CONTEXT * pcontext = &context_switch->pcontext->context ;
pcontext->ContextFlags = CONTEXT_VM ;
return GetThreadContext (patomvm->vm_thread, pcontext) ;
}
/**
* \ingroup atomvm
* \b atomvmContextCreate
*
* This function is to be used by the atom virtual machine.
*
* This function creates a atomvm thread context that can be scheduled
* by atomvmContextSwitch.
*
* @param[in] interrupt_mask initial interrupt mask of the thread.
*
* @return Handle to the context of the thread created.
*/
HATOMVM_CONTEXT
atomvmContextCreate (uint32_t interrupt_mask)
{
uint32_t res ;
PATOMVM patomvm = getAtomvm () ;
PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)malloc (sizeof(ATOMVM_CONTEXT)) ;
CONTEXT* pcontext = &new_context->context ;
ATOMVM_CALLBACK_CONTEXT context_init ;
context_init.pcontext = new_context ;
new_context->interrupt_mask = interrupt_mask ;
new_context->thread_id = (uint32_t) -1 ;
res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ;
if (res) {
return (HATOMVM_CONTEXT)new_context ;
} else {
free (new_context) ;
}
return 0 ;
}
/**
* \ingroup atomvm
* \b atomvmContextInit
*
* This function is to be used by the atom virtual machine.
*
* This function initialize a atomvm thread context that can be scheduled
* by atomvmContextSwitch.
*
* @param[out] context Handle to the context of the thread that are allocated
* by the caller.
* @param[in] stack Stack top.
* @param[in] entry Entry point of the thread.
* @param[in] arg argument passed on the stack as first parameter.
* @param[in] exit exit function to return to.
* @param[in] status status for exit function.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextInit (HATOMVM_CONTEXT context, uint32_t* stack, void (*entry)(uint32_t), uint32_t arg, void (*exit)(uint32_t))
{
uint32_t res = 0 ;
PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)context ;
CONTEXT* pcontext = &new_context->context ;
*stack-- = arg;
*stack = (uint32_t)exit ;
pcontext->Ebp = (uint32_t)stack ;
pcontext->Esp = (uint32_t)stack ;
pcontext->Eip = (uint32_t)entry ;
return res ;
}
/**
* \b callbackContextSwitch
*
* This function is invoked from the controll thread after a call to atomvmContextSwitch.
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[out] context Context to be scheduled.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
uint32_t res1 = 1 ;
uint32_t res2 ;
PATOMVM_CALLBACK_CONTEXT_SWITCH context_switch = (PATOMVM_CALLBACK_CONTEXT_SWITCH)callback ;
if (context_switch->p_old_context) {
res1 = GetThreadContext (patomvm->vm_thread, &context_switch->p_old_context->context) ;
ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ;
}
patomvm->current_context = context_switch->p_new_context ;
res2 = SetThreadContext (patomvm->vm_thread, &context_switch->p_new_context->context) ;
ATOMVM_ASSERT(res2 , _T("SetThreadContext failed")) ;
return res1 & res2 ;
}
/**
* \ingroup atomvm
* \b atomvmContextSwitch
*
* This function is to be used by the atom virtual machine.
*
* This function schedules a thread for the context created by atomvmContextCreate.
*
* @param[in] new_context The context to schedule.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK_CONTEXT_SWITCH context_switch ;
context_switch.p_old_context = (PATOMVM_CONTEXT) old_context ;
context_switch.p_new_context = (PATOMVM_CONTEXT) new_context ;
return invokeCallback (patomvm, callbackContextSwitch, (PATOMVM_CALLBACK)&context_switch) ;
}
/**
* \ingroup atomvm
* \b atomvmContextDesrtroy
*
* This function is to be used by the atom virtual machine.
*
* This functiondestroyes a atomvm context created by atomvmContextCreate.
*
* @param[in] context The context to destroy.
*
* @return None
*/
void
atomvmContextDesrtroy (HATOMVM_CONTEXT context)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context,
_T("atomvmContextDesrtroy failed")) ;
free((void*)context) ;
}
/**
* \ingroup atomvm
* \b atomvmWriteThreadId
*
* Write a thread ID.
*
* Write a thread ID for the current context.
*
* @param[in] thread_id thread_id.
*
* @return None
*/
void
atomvmWriteThreadId (uint32_t thread_id)
{
PATOMVM patomvm = getAtomvm () ;
patomvm->current_context->thread_id = thread_id ;
}
/**
* \ingroup atomvm
* \b atomvmReadThreadId
*
* Write a thread ID.
*
* Read a thread ID for the current context.
*
* @return thread_id
*/
uint32_t
atomvmReadThreadId (void)
{
PATOMVM patomvm = getAtomvm () ;
return patomvm->current_context->thread_id ;
}
/**
* \ingroup atomvm
* \b atomvmGetVmId
*
* Returns an identifier for the virtual machine. This is zero for the first
* virtual machine created with atomvmCtrlCreate(), 1 for the second and so on.
*
* @return The atom vm ID
*/
uint32_t
atomvmGetVmId (void)
{
PATOMVM patomvm = getAtomvm () ;
return patomvm->atomvm_id ;
}
/**
* \b callbackInterruptWait
*
* This function is invoked from the controll thread after a call to atomvmInterruptWait().
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[out] callback Callback parameter.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackIntWait (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ;
return WaitForSingleObject (patomvm->atomvm_int, INFINITE) == WAIT_OBJECT_0 ;
}
/**
* \ingroup atomvm
* \b atomvmInterruptWait
*
* This function is to be used by the atom virtual machine.
*
* This function if for synchronization between multiple
* atom vms.
*
*
* @return void.
*/
void
atomvmIntWait (void)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK callback ;
invokeCallback (patomvm, callbackIntWait, (PATOMVM_CALLBACK)&callback) ;
}
/**
* \b callbackIntRequest
*
* This function is invoked from the controll thread after a call to atomvmIntRequest().
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[in] callback Callback parameter.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackIntRequest (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
PATOMVM_CALLBACK_INT_REQUEST int_request = (PATOMVM_CALLBACK_INT_REQUEST)callback ;
int_request->isr () ;
return 1 ;
}
/**
* \ingroup atomvm
* \b atomvmIntRequest
*
* This function is to be used by the atom virtual machine.
*
* @param[in] isr Function that will be called from the controll thread.
*
* @return void.
*/
void
atomvmIntRequest (void (*isr) (void))
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK_INT_REQUEST callback ;
callback.isr = isr ;
invokeCallback (patomvm, callbackIntRequest, (PATOMVM_CALLBACK)&callback) ;
}
/**
* \b vm_thread
*
* Windows thread in which the atom virtual machine will execute.
*
* __atomvmReset() runs the virtual machie and should only return after
* __atomvmClose() was called.
*
* @return None.
*/
DWORD WINAPI
vm_thread (LPVOID lpParameter)
{
BOOL res = TlsSetValue (g_atomvm_tls_idx, lpParameter) ;
ATOMVM_ASSERT(res, _T("TlsSetValue failed")) ;
__atomvmReset () ;
return 0 ;
}

121
ports/atomvm/atomvm.h Normal file
View File

@@ -0,0 +1,121 @@
/*
* Copyright (c) 2010, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** \mainpage \ref atomvm
* \defgroup atomvm Atomvm API
*
* @authors Natie van Rooyen
*
* @section intro Introduction
* Atomvm is a tiny virtual machine that runs on Windows and can be debugged
* from an IDE like Microsoft Visual C++ Express. The primary purpose of this
* virtual machine is for the evaluation of Real Time Operating Systems (like
* Atomthreads) and the development and testing of modules for this Real Time
* Operating System on a Windows machine.
*
* Atomvm makes use of the Windows API functions GetThreadContext() and
* SetThreadContext() to create multiple virtual contexts or threads inside a
* single Windows thread. Atomvm also simulates interrupts with an interrupt
* mask accessible from the Atomvm threads. External events can be queued as
* interrupts to Atomvm, for example a timer loop generating system timer tick
* interrupts for a Real Time Operating System ported to Atomvm.
*
* */
#ifndef __ATOMVM_H__
#define __ATOMVM_H__
#include <crtdbg.h>
#include "types.h"
#if defined _DEBUG || defined DEBUG
#define ATOMVM_ASSERT(x, msg) _ASSERT((x))
#else
#define ATOMVM_ASSERT(x, msg)
#endif
#define ATOMVM_MAX_VM 8
/* Forward declarations */
/* This is an opaque handle to an instance of an atomvm created
by a call to atomvmCtrlCreate() */
typedef struct ATOMVM* HATOMVM ;
/* This is an opaque handle to an atomvm context created
by a call to atomvmContextCreate() */
typedef struct ATOMVM_CONTEXT* HATOMVM_CONTEXT ;
/* Function prototypes used for controlling the atom virtual machine */
extern uint32_t atomvmCtrlCreate (HATOMVM* atomvm) ;
extern void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ;
extern void atomvmCtrlIntRequest (HATOMVM atomvm, void (*isr) (void)) ;
extern void atomvmCtrlClose (HATOMVM atomvm) ;
/* Function prototypes for use by the atom virtual machine from within the
call to __atomvmReset(). */
extern int32_t atomvmInterruptMask (uint32_t mask) ;
extern HATOMVM_CONTEXT atomvmContextCreate (uint32_t interrupt_mask) ;
extern uint32_t atomvmContextInit (HATOMVM_CONTEXT context, uint32_t* stack,
void (*entry)(uint32_t), uint32_t arg, void (*exit)(uint32_t)) ;
extern uint32_t atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context) ;
extern void atomvmContextDesrtroy (HATOMVM_CONTEXT context) ;
extern void atomvmWriteThreadId (uint32_t thread_id) ;
extern uint32_t atomvmReadThreadId (void) ;
extern void atomvmIntWait (void) ;
extern void atomvmIntRequest (void (*isr) (void)) ;
extern uint32_t atomvmGetVmId (void) ;
/**
* \ingroup atomvm
* \b __atomvmReset
*
* Function prototype to be implemented as entry point for the atom virtual machine.
*
* @return void.
*/
extern void __atomvmReset (void) ;
/**
* \ingroup atomvm
* \b __atomvmClose
*
* Function prototype to be implemted in the atom virtual machine
*
* @return void.
*/
extern void __atomvmClose (void) ;
#endif /* __ATOMVM_H__ */

270
ports/atomvm/msvc/main.c Normal file
View File

@@ -0,0 +1,270 @@
#include <stdio.h>
#include <windows.h>
#include "atom.h"
#include "atomvm.h"
#include "atomport.h"
// #define UNIT_TESTS
#ifdef UNIT_TESTS
extern uint32_t test_start (void) ;
#endif
#define TEST_THREADS 47
#define TEST_STACK_BYTE_SIZE 0x10000
#define IDLE_STACK_BYTE_SIZE 0x10000
#define MONITOR_STACK_BYTE_SIZE 0x10000
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
static unsigned char monitor_stack[MONITOR_STACK_BYTE_SIZE] ;
static unsigned char test_stack[TEST_THREADS+1][TEST_STACK_BYTE_SIZE] ;
static unsigned int test_counter[TEST_THREADS+1] = {0} ;
static unsigned int test2_counter = 0 ;
static unsigned int test3_counter = 0 ;
static unsigned int test_isr_count = 0 ;
static unsigned char test2_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test3_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test_idle_stack[TEST_STACK_BYTE_SIZE] ;
static uint8_t test_prio[60] = {
001,010,100,200,250, 200,200,200,200,200,
150,150,150,150,150, 250,250,250,250,250,
101,102,103,104,105, 202,204,206,208,210,
150,150,150,150,150, 250,250,250,250,250,
121,122,123,124,125, 061,063,065,067,061,
150,150,150,150,150, 250,250,250,250,250
};
static uint32_t test_interv[60] = {
001,001,001,001,001, 002,003,004,005,006,
015,015,015,015,015, 025,024,023,022,021,
905,005,005,005,805, 050,051,052,053,054,
015,015,015,015,015, 025,024,023,022,021,
030,030,030,030,030, 070,071,072,073,474,
005,006,007,007,001, 001,001,003,003,005
};
ATOM_TCB test_tcb[TEST_THREADS+1] ;
ATOM_TCB monitor_tcb ;
ATOM_TCB test2_tcb ;
ATOM_TCB test3_tcb ;
ATOM_TCB test_idle_tcb ;
DWORD WINAPI isr_thread_proc (LPVOID lpParameter) ;
static HANDLE isr_thread_1 ;
static HANDLE isr_thread_2 ;
static HANDLE isr_thread_3 ;
static HANDLE isr_thread_4 ;
void
ipi_sr()
{
printf("ipi\r\n") ;
}
void
monitor_thread (uint32_t parm)
{
CRITICAL_STORE;
int i ;
int c = 0 ;
ATOM_TCB *tcb ;
static unsigned int idle_1 = 0, idle_2 = 0, int_count = 0 ;
unsigned int delta_idle_1 , delta_idle_2 , delta_int_count ;
tcb = atomCurrentContext() ;
for (;;)
{
CRITICAL_START();
printf("Monitor # %04d (%08d)\n", c++, atomTimeGet()) ;
printf("-------------------------\n") ;
for (i=0; i<TEST_THREADS/3; i++) {
printf("Thr %.2d cnt %08d\t",i,test_counter[i]);
printf("Thr %.2d cnt %08d\t",i+TEST_THREADS/3,test_counter[i+TEST_THREADS/3]);
printf("Thr %.2d cnt %08d\n",i+TEST_THREADS*2/3,test_counter[i+TEST_THREADS*2/3]);
}
delta_idle_1 = test2_counter - idle_1 ;
delta_idle_2 = test3_counter - idle_2 ;
delta_int_count = test_isr_count - int_count ;
printf("\nIdle Threadd 1 Counter = %d %d %d\nIdle Theadrd 2 Counter = %d %d %d\nInterrupt Counter = %d %d %d",
test2_counter, delta_idle_1, (unsigned int)(test2_counter / c),
test3_counter, delta_idle_2, (unsigned int)(test3_counter / c),
test_isr_count, delta_int_count, (unsigned int)(test_isr_count / c));
printf ("\n\n") ;
idle_1 = test2_counter ;
idle_2 = test3_counter ;
int_count = test_isr_count ;
CRITICAL_END();
//for (i=0; i<100;i++) {
// atomvmInterruptWait () ;
//}
atomTimerDelay (450) ;
//atomvmScheduleIpi (atomvmGetVmId(), (uint32_t) ipi_sr) ;
}
}
void
test_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
atomTimerDelay (test_interv[parm]) ;
CRITICAL_START();
test_counter[parm]++ ;
CRITICAL_END();
}
}
void
test2_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test2_counter++ ;
CRITICAL_END();
}
}
void test3_thread(uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test3_counter++ ;
CRITICAL_END();
}
}
#ifdef UNIT_TESTS
void unit_test_thread(uint32_t parm)
{
unsigned int failures ;
failures = test_start () ;
printf ("test_start %d failures\n", failures) ;
while(1) {
atomTimerDelay (100);
}
}
#endif
void
__atomvmReset ()
{
unsigned int i ;
atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, 1) ;
#ifndef UNIT_TESTS
for (i=0; i< TEST_THREADS;i++) {
atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], test_thread, i, &test_stack[i][0], TEST_STACK_BYTE_SIZE, 1);
}
atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 50, monitor_thread, 0, &monitor_stack[0], MONITOR_STACK_BYTE_SIZE, 1);
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 253, test2_thread, 0, &test2_stack[0], TEST_STACK_BYTE_SIZE, 1);
atomThreadCreate ((ATOM_TCB *)&test3_tcb, 253, test3_thread, 0, &test3_stack[0], TEST_STACK_BYTE_SIZE, 1);
#else
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 16, unit_test_thread, 0, &test2_stack[], TEST_STACK_BYTE_SIZE, 1);
#endif
atomOSStart() ;
}
void
__atomvmClose ()
{
}
void
test_isr (void)
{
static int i = 0 ;
test_isr_count++ ;
if (i++==25) {
//Sleep(3) ;
i = 0;
}
}
DWORD WINAPI
isr_thread_proc (LPVOID lpParameter)
{
int i = 0 ;
int x ;
int y = rand() % 100 ;
while (1) {
atomvmCtrlIntRequest (the_atomvm, test_isr) ;
if (i++==y) {
x = rand() % 50 ;
Sleep (x) ;
y = rand() % 100 ;
i = 0 ;
}
}
return 0 ;
}
void
main ()
{
atomvmRun () ;
#ifndef UNIT_TESTS
isr_thread_1 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_2 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_3 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_4 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
ResumeThread (isr_thread_1) ;
ResumeThread (isr_thread_2) ;
ResumeThread (isr_thread_3) ;
ResumeThread (isr_thread_4) ;
#endif
while (1) {
Sleep(1) ;
atomvmCtrlIntRequest (the_atomvm, archTimerTickIrqHandler) ;
}
}

View File

@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C++ Express 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc", "msvc.vcxproj", "{77095EB1-4988-4A04-8751-69C63C7C541B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{77095EB1-4988-4A04-8751-69C63C7C541B}.Debug|Win32.ActiveCfg = Debug|Win32
{77095EB1-4988-4A04-8751-69C63C7C541B}.Debug|Win32.Build.0 = Debug|Win32
{77095EB1-4988-4A04-8751-69C63C7C541B}.Release|Win32.ActiveCfg = Release|Win32
{77095EB1-4988-4A04-8751-69C63C7C541B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{77095EB1-4988-4A04-8751-69C63C7C541B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>msvc</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(MSBuildProjectDirectory)/../../../kernel;$(MSBuildProjectDirectory)/..;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(MSBuildProjectDirectory)/..;$(MSBuildProjectDirectory)/../../../kernel;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\kernel\atom.h" />
<ClInclude Include="..\..\..\kernel\atommutex.h" />
<ClInclude Include="..\..\..\kernel\atomqueue.h" />
<ClInclude Include="..\..\..\kernel\atomsem.h" />
<ClInclude Include="..\..\..\kernel\atomtimer.h" />
<ClInclude Include="..\atomport-tests.h" />
<ClInclude Include="..\atomport.h" />
<ClInclude Include="..\atomuser.h" />
<ClInclude Include="..\atomvm.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\kernel\atomkernel.c" />
<ClCompile Include="..\..\..\kernel\atommutex.c" />
<ClCompile Include="..\..\..\kernel\atomqueue.c" />
<ClCompile Include="..\..\..\kernel\atomsem.c" />
<ClCompile Include="..\..\..\kernel\atomtimer.c" />
<ClCompile Include="..\atomport.c" />
<ClCompile Include="..\atomvm.c" />
<ClCompile Include="main.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="atomthreads">
<UniqueIdentifier>{d05cbb5a-256f-4127-bd5b-c3bd69b3672c}</UniqueIdentifier>
</Filter>
<Filter Include="port">
<UniqueIdentifier>{f30700d8-652d-477c-a4f2-d23e7784de50}</UniqueIdentifier>
</Filter>
<Filter Include="atomvm">
<UniqueIdentifier>{a4f641bc-296d-4546-a831-2e1d0d7e9242}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\kernel\atom.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atommutex.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atomqueue.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atomsem.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\..\..\kernel\atomtimer.h">
<Filter>atomthreads</Filter>
</ClInclude>
<ClInclude Include="..\atomport.h">
<Filter>port</Filter>
</ClInclude>
<ClInclude Include="..\atomport-tests.h">
<Filter>port</Filter>
</ClInclude>
<ClInclude Include="..\atomuser.h">
<Filter>port</Filter>
</ClInclude>
<ClInclude Include="..\atomvm.h">
<Filter>atomvm</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\kernel\atomkernel.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atommutex.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atomqueue.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atomsem.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\..\..\kernel\atomtimer.c">
<Filter>atomthreads</Filter>
</ClCompile>
<ClCompile Include="..\atomport.c">
<Filter>port</Filter>
</ClCompile>
<ClCompile Include="main.c" />
<ClCompile Include="..\atomvm.c">
<Filter>atomvm</Filter>
</ClCompile>
</ItemGroup>
</Project>

270
ports/atomvm/test/main.c Normal file
View File

@@ -0,0 +1,270 @@
#include <stdio.h>
#include <windows.h>
#include "atom.h"
#include "atomvm.h"
#include "atomport.h"
// #define UNIT_TESTS
#ifdef UNIT_TESTS
extern uint32_t test_start (void) ;
#endif
#define TEST_THREADS 47
#define TEST_STACK_BYTE_SIZE 0x10000
#define IDLE_STACK_BYTE_SIZE 0x10000
#define MONITOR_STACK_BYTE_SIZE 0x10000
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
static unsigned char monitor_stack[MONITOR_STACK_BYTE_SIZE] ;
static unsigned char test_stack[TEST_THREADS+1][TEST_STACK_BYTE_SIZE] ;
static unsigned int test_counter[TEST_THREADS+1] = {0} ;
static unsigned int test2_counter = 0 ;
static unsigned int test3_counter = 0 ;
static unsigned int test_isr_count = 0 ;
static unsigned char test2_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test3_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test_idle_stack[TEST_STACK_BYTE_SIZE] ;
static uint8_t test_prio[60] = {
001,010,100,200,250, 200,200,200,200,200,
150,150,150,150,150, 250,250,250,250,250,
101,102,103,104,105, 202,204,206,208,210,
150,150,150,150,150, 250,250,250,250,250,
121,122,123,124,125, 061,063,065,067,061,
150,150,150,150,150, 250,250,250,250,250
};
static uint32_t test_interv[60] = {
001,001,001,001,001, 002,003,004,005,006,
015,015,015,015,015, 025,024,023,022,021,
905,005,005,005,805, 050,051,052,053,054,
015,015,015,015,015, 025,024,023,022,021,
030,030,030,030,030, 070,071,072,073,474,
005,006,007,007,001, 001,001,003,003,005
};
ATOM_TCB test_tcb[TEST_THREADS+1] ;
ATOM_TCB monitor_tcb ;
ATOM_TCB test2_tcb ;
ATOM_TCB test3_tcb ;
ATOM_TCB test_idle_tcb ;
DWORD WINAPI isr_thread_proc (LPVOID lpParameter) ;
static HANDLE isr_thread_1 ;
static HANDLE isr_thread_2 ;
static HANDLE isr_thread_3 ;
static HANDLE isr_thread_4 ;
void
ipi_sr()
{
printf("ipi\r\n") ;
}
void
monitor_thread (uint32_t parm)
{
CRITICAL_STORE;
int i ;
int c = 0 ;
ATOM_TCB *tcb ;
static unsigned int idle_1 = 0, idle_2 = 0, int_count = 0 ;
unsigned int delta_idle_1 , delta_idle_2 , delta_int_count ;
tcb = atomCurrentContext() ;
for (;;)
{
CRITICAL_START();
printf("Monitor # %04d (%08d)\n", c++, atomTimeGet()) ;
printf("-------------------------\n") ;
for (i=0; i<TEST_THREADS/3; i++) {
printf("Thr %.2d cnt %08d\t",i,test_counter[i]);
printf("Thr %.2d cnt %08d\t",i+TEST_THREADS/3,test_counter[i+TEST_THREADS/3]);
printf("Thr %.2d cnt %08d\n",i+TEST_THREADS*2/3,test_counter[i+TEST_THREADS*2/3]);
}
delta_idle_1 = test2_counter - idle_1 ;
delta_idle_2 = test3_counter - idle_2 ;
delta_int_count = test_isr_count - int_count ;
printf("\nIdle Threadd 1 Counter = %d %d %d\nIdle Theadrd 2 Counter = %d %d %d\nInterrupt Counter = %d %d %d",
test2_counter, delta_idle_1, (unsigned int)(test2_counter / c),
test3_counter, delta_idle_2, (unsigned int)(test3_counter / c),
test_isr_count, delta_int_count, (unsigned int)(test_isr_count / c));
printf ("\n\n") ;
idle_1 = test2_counter ;
idle_2 = test3_counter ;
int_count = test_isr_count ;
CRITICAL_END();
//for (i=0; i<100;i++) {
// atomvmInterruptWait () ;
//}
atomTimerDelay (150) ;
//atomvmScheduleIpi (atomvmGetVmId(), (uint32_t) ipi_sr) ;
}
}
void
test_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
atomTimerDelay (test_interv[parm]) ;
CRITICAL_START();
test_counter[parm]++ ;
CRITICAL_END();
}
}
void
test2_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test2_counter++ ;
CRITICAL_END();
}
}
void test3_thread(uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test3_counter++ ;
CRITICAL_END();
}
}
#ifdef UNIT_TESTS
void unit_test_thread(uint32_t parm)
{
unsigned int failures ;
failures = test_start () ;
printf ("test_start %d failures\n", failures) ;
while(1) {
atomTimerDelay (100);
}
}
#endif
void
__atomvmReset ()
{
unsigned int i ;
atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ;
#ifndef UNIT_TESTS
for (i=0; i< TEST_THREADS;i++) {
atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], test_thread, i, &test_stack[i][TEST_STACK_BYTE_SIZE - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int));
}
atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 50, monitor_thread, 0, &monitor_stack[(MONITOR_STACK_BYTE_SIZE) - sizeof(unsigned int)], MONITOR_STACK_BYTE_SIZE - sizeof(unsigned int));
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 253, test2_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
atomThreadCreate ((ATOM_TCB *)&test3_tcb, 253, test3_thread, 0, &test3_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
#else
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 16, unit_test_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
#endif
atomOSStart() ;
}
void
__atomvmClose ()
{
}
void
test_isr ()
{
static int i = 0 ;
test_isr_count++ ;
if (i++==25) {
//Sleep(3) ;
i = 0;
}
}
DWORD WINAPI
isr_thread_proc (LPVOID lpParameter)
{
int i = 0 ;
int x ;
int y = rand() % 100 ;
while (1) {
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)test_isr) ;
if (i++==y) {
x = rand() % 50 ;
Sleep (x) ;
y = rand() % 100 ;
i = 0 ;
}
}
return 0 ;
}
void
main ()
{
atomvmRun () ;
#ifndef UNIT_TESTS
isr_thread_1 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_2 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_3 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_4 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
ResumeThread (isr_thread_1) ;
ResumeThread (isr_thread_2) ;
ResumeThread (isr_thread_3) ;
ResumeThread (isr_thread_4) ;
#endif
while (1) {
Sleep(1) ;
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)archTimerTickIrqHandler) ;
}
}

61
ports/atomvm/types.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2010,Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_USER_H__
#define __ATOM_USER_H__
/* Portable uint8_t and friends not available from stdint.h on this platform */
#include <windows.h>
#define SYSTEM_MEMALIGN sizeof (unsigned int)
typedef unsigned int uintptr_t ;
typedef int intptr_t ;
typedef unsigned int uint32_t ;
typedef unsigned short uint16_t ;
typedef unsigned char uint8_t ;
typedef int int32_t ;
typedef short int16_t ;
typedef char int8_t ;
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
#define ATOM_TLS HATOMVM_CONTEXT context ;
#endif /* __ATOM_USER_H__ */

View File

@@ -27,7 +27,7 @@ architecture-specific details such as appropriate types for 8-bit, 16-bit
etc variables, the port's system tick frequency, and macros for performing
interrupt lockouts / critical sections:
* atomuser.h: Port-specific header required by the kernel for each port
* atomport.h: Port-specific header required by the kernel for each port
A couple of additional source files are also included here:

View File

@@ -148,7 +148,7 @@ archContextSwitch:
mov r28,r24 /* Move old_tcb_ptr param into the Y-regs so we */
mov r29,r25 /* can access the TCB via a pointer. */
st Y,r16 /* Store SPH/SPL to old_tcb_ptr->tcb_save_ptr which */
st Y,r16 /* Store SPH/SPL to old_tcb_ptr->sp_save_ptr which */
std Y+1,r17 /* is conveniently the first member of the TCB. */

View File

@@ -45,6 +45,8 @@
#endif
/* Local data */
/*
* Semaphore for single-threaded access to UART device
*/

19
ports/cortex_m/Makefile Normal file
View File

@@ -0,0 +1,19 @@
ATOMTHREADS_PORT = $(ATOMTHREADS)/ports/cortex_m
ATOMTHREADS_KERNEL = $(ATOMTHREADS)/kernel
INCLUDES := $(INCLUDES) \
-I$(ATOMTHREADS_KERNEL) \
-I$(ATOMTHREADS_PORT)
SRCS := $(SRCS) \
$(ATOMTHREADS_KERNEL)/atomkernel.c \
$(ATOMTHREADS_KERNEL)/atommutex.c \
$(ATOMTHREADS_KERNEL)/atomqueue.c \
$(ATOMTHREADS_KERNEL)/atomsem.c \
$(ATOMTHREADS_KERNEL)/atomtimer.c \
$(ATOMTHREADS_PORT)/atomport.c
ASMS := $(ASMS) \
$(ATOMTHREADS_PORT)/atomport_s.S

17
ports/cortex_m/README Normal file
View File

@@ -0,0 +1,17 @@
---------------------------------------------------------------------------
Library: Atomthreads ARM Cortex M Port
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
ARM Cortex M PORT
This folder contains a port of the Atomthreads real time kernel for the
ARM CortexM type processor architecture. This port was tested on the
Cortex M3 and the Cortex M4.
To Use:
See the example project in the "platforms/qemu_lm3s" directory.

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOMPORT_TEST_H__
#define __ATOMPORT_TEST_H__
/* Include Atomthreads kernel API */
#include "atom.h"
extern void dbg_format_msg (char *format, ...) ;
#define TEST_THREAD_STACK_SIZE 1024
#define ATOMLOG dbg_format_msg
#define _STR(x) x
/* API for starting each test */
extern uint32_t test_start (void);
#endif /* __ATOMPORT_TEST_H__ */

156
ports/cortex_m/atomport.c Normal file
View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomport.h"
#include "types.h"
/* *
*
* Functions defined in atomport_s.S
*
*/
typedef void * SYSCONTEXT ;
extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ;
extern void contextStart (SYSCONTEXT* context) ;
extern void contextEnableInterrupts (void) ;
/**
* \b thread_shell
*
* Documented in atomThreads.
*
*/
void
thread_shell (void)
{
ATOM_TCB *curr_tcb;
/* Get the TCB of the thread being started */
curr_tcb = atomCurrentContext();
/**
* Enable interrupts - these will not be enabled when a thread
* is first restored.
*/
// sei();
contextEnableInterrupts () ;
/* Call the thread entry point */
if (curr_tcb && curr_tcb->entry_point)
{
curr_tcb->entry_point(curr_tcb->entry_param);
}
/* Not reached - threads should never return from the entry point */
}
/**
* \b archThreadContextInit
*
* Documented in atomThreads.
*
*/
void
archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param)
{
uint32_t * stack_ptr ;
tcb_ptr->sp_save_ptr = stack_top;
tcb_ptr->entry_param = entry_param ;
tcb_ptr->entry_point = entry_point ;
stack_ptr = (uint32_t *)stack_top; //-- Load stack pointer
*stack_ptr = 0x01000000L; //-- xPSR
stack_ptr--;
#ifndef PLATFORM_QEMU_LM3S_HACK
*stack_ptr = ((uint32_t)thread_shell) | 1 ; //-- Entry Point (1 for THUMB mode)
#else
*stack_ptr = ((uint32_t)thread_shell) & ~1 ; //-- Entry Point (1 for THUMB mode)
#endif
stack_ptr--;
*stack_ptr = ((uint32_t)/*exit*/0) | 1; //-- R14 (LR) (1 for THUMB mode)
stack_ptr--;
*stack_ptr = 0x00121212L; //-- R12
stack_ptr--;
*stack_ptr = 0x00030303L; //-- R3
stack_ptr--;
*stack_ptr = 0x00020202L; //-- R2
stack_ptr--;
*stack_ptr = 0x00010101L; //-- R1
stack_ptr--;
*stack_ptr = entry_param ; //-- R0 - task's function argument
stack_ptr--;
*stack_ptr = 0x00111111L; //-- R11
stack_ptr--;
*stack_ptr = 0x00101010L; //-- R10
stack_ptr--;
*stack_ptr = 0x00090909L; //-- R9
stack_ptr--;
*stack_ptr = 0x00080808L; //-- R8
stack_ptr--;
*stack_ptr = 0x00070707L; //-- R7
stack_ptr--;
*stack_ptr = 0x00060606L; //-- R6
stack_ptr--;
*stack_ptr = 0x00050505L; //-- R5
stack_ptr--;
*stack_ptr = 0x00040404L; //-- R4
tcb_ptr->sp_save_ptr = stack_ptr ;
}
/**
* \b archFirstThreadRestore
*
* Documented in atomThreads.
*
*/
void
archFirstThreadRestore(ATOM_TCB * p_sp_new)
{
contextStart (&p_sp_new->sp_save_ptr) ;
}
/**
* \b archContextSwitch
*
* Documented in atomThreads.
*
*/
void
archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new)
{
contextSwitch (&p_sp_old->sp_save_ptr, &p_sp_new->sp_save_ptr) ;
}

81
ports/cortex_m/atomport.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_H__
#define __ATOM_PORT_H__
#include "types.h"
#define SYSTEM_TICKS_PER_SEC 100
/**
* Definition of NULL.
* If stddef.h is available on the platform it is simplest to include it
* from this header, otherwise define below.
*/
#ifndef NULL
#define NULL ((void *)(0))
#endif
/* Size of each stack entry / stack alignment size (e.g. 32 bits) */
#define STACK_ALIGN_SIZE sizeof(unsigned int)
/**
* Architecture-specific types.
* Most of these are available from types.h on this platform, which is
* included above.
*/
/**
* Architecture-specific types.
* Most of these are available from types.h on this platform, which is
* included above.
*/
#ifndef POINTER
#define POINTER void *
#endif
/* *
*
* Functions defined in atomport_arm.asm
*
*/
extern void contextInit (void) ;
extern uint32_t contextEnterCritical (void) ;
extern void contextExitCritical (uint32_t posture) ;
/* Critical region protection */
#define CRITICAL_STORE uint32_t __atom_critical
#define CRITICAL_START() __atom_critical = contextEnterCritical()
#define CRITICAL_END() contextExitCritical(__atom_critical)
#endif /* __ATOM_PORT_H__ */

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_PRIVATE_H__
#define __ATOM_PORT_PRIVATE_H__
/* Function prototypes */
extern void archPendSVHandler (void) ;
extern void archTickHandler (void) ;
/* required interface */
extern void __context_tick_handler (void) ;
#endif /* __ATOM_PORT_PRIVATE_H__ */

280
ports/cortex_m/atomport_s.S Normal file
View File

@@ -0,0 +1,280 @@
/*
Copyright (c) 2012, Natie van Rooyen. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. No personal names or organizations' names associated with the
Atomthreads project may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
.global archPendSVHandler
.global archTickHandler
.global contextInit
.global contextSwitch
.global contextStart
.global contextEnableInterrupts
.global contextEnterCritical
.global contextExitCritical
.extern __context_tick_handler
/**/
.equ NVIC_INT_CTRL, 0xE000ED04 // Interrupt control state register
.equ NVIC_PENDSVSET, 0x10000000 // Value to trigger PendSV exception
.equ NVIC_PR_12_15_ADDR, 0xE000ED20 // System Handlers 12-15 Priority Register Address
#ifdef PLATFORM_QEMU_LM3S_HACK
.equ NVIC_PENDS_VPRIORITY, 0x00F00000 // PendSV priority is minimal (0xFF -- 0x00FF0000)
#else
.equ NVIC_PENDS_VPRIORITY, 0x00FF0000 // PendSV priority is minimal (0xFF -- 0x00FF0000)
#endif
#ifdef PLATFORM_QEMU_LM3S_HACK
.equ NVIC_ISER, 0xE000E100
.equ NVIC_ICER, 0xE000E180
.equ NVIC_I_TIMER0, 0x80000
#endif
.syntax unified
.text
.thumb
/**
* \b contextInit
*
* Architecture-specific one time initialization.
*
* Configures PendSV priority to lowest.
*
* @return None
*/
contextInit:
LDR r1, =NVIC_PR_12_15_ADDR // Load the System 12-15 Priority Register
LDR r0, [r1]
ORR r0, r0, #NVIC_PENDS_VPRIORITY // set PRI_14 (PendSV) to 0xFF - minimal
STR r0, [r1]
BX lr
/**
* \b contextSwitch
*
* Architecture-specific context switch routine.
*
* Note that interrupts are always locked out when this routine is
* called. For cooperative switches, the scheduler will have entered
* a critical region. For preemptions (called from an ISR), the
* interrupts will have disabled in the tick_Handler.
*
* @param[in] [r0] -> Address to save old stack pointer
* @param[in] [r1] -> Address where new stack pointer is stored
*
* @return None
*/
contextSwitch:
LDR r2, =context_new_stack_ptr
STR r1, [r2]
LDR r2, =context_save_stack_ptr
LDR r1, [r2]
CMP r1, #0 // if contextSwitch is going to be called again before pend_sv
IT EQ
STREQ r0, [r2]
LDR R0, =NVIC_INT_CTRL // Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX lr
/**
* \b contextStart
*
* Architecture-specific context start routine.
*
* @param[in] [r0] -> Address where stack pointer is stored
*
* @return Does not return
*/
contextStart:
LDR r1, =context_new_stack_ptr
STR r0, [r1]
LDR r1, =context_save_stack_ptr
MOV r0, #0
STR r0, [r1]
LDR r0, =NVIC_INT_CTRL // Trigger the PendSV exception (causes context switch)
LDR r1, =NVIC_PENDSVSET
STR r1, [r0]
BX lr
/**
* \b contextEnableInterrupts
*
* Enables interrupts on the processor
*
* @return None
*/
contextEnableInterrupts:
#ifndef PLATFORM_QEMU_LM3S_HACK
CPSIE i
#else
LDR r1, =NVIC_ISER
LDR r0, =NVIC_I_TIMER0
STR r0, [r1]
#endif
BX lr
/**
* \b contextExitCritical
*
* Exit critical section (restores interrupt posture)
*
* @param[in] r0 Interrupt Posture
*
* @return None
*/
contextExitCritical:
#ifndef PLATFORM_QEMU_LM3S_HACK
MSR PRIMASK, r0
#else
LDR r1, =NVIC_ISER
STR r0, [r1]
#endif
BX lr
/**
* \b contextEnterCritical
*
* Enter critical section (disables interrupts)
*
* @return Current interrupt posture
*/
contextEnterCritical:
#ifndef PLATFORM_QEMU_LM3S_HACK
MRS r0, PRIMASK
CPSID i
#else
LDR r1, =NVIC_ISER
LDR r0, [r1]
LDR r1, =NVIC_ICER
STR r0, [r1]
#endif
BX lr
/**
* \b archPendSVHandler
*
* CortexM3 archPendSVHandler. Switch context to a new stack.
*
* @return None
*/
.thumb_func
archPendSVHandler:
#ifndef PLATFORM_QEMU_LM3S_HACK
CPSID i // Disable core int
#else
LDR r0, =NVIC_ICER
LDR r1, =NVIC_I_TIMER0
STR r1, [r0]
#endif
LDR r1, =context_save_stack_ptr
LDR r0, [r1] // Load old (current) stack pointer address
LDR r2, =context_new_stack_ptr
LDR r2, [r2] // Load new stack pointer address
CMP r0, r2
BEQ pendsv_handler_exit
CMP r0, #0
BEQ pendsv_handler_new_stack
// Save context
MRS r3, PSP // Get PSP point
STMDB r3!, {R4-R11} // Store r4-r11
STR r3, [r0] // Save old stack pointer
MOV r3, #0
STR r3, [r1]
pendsv_handler_new_stack:
// Restore context
LDR r2, [r2] // Load new stack pointer
LDMIA r2!, {r4-r11} // Restore context
MSR PSP, r2 // Mov new stack point to PSP
pendsv_handler_exit:
#ifndef PLATFORM_QEMU_LM3S_HACK
CPSIE i // Enable core int
#else
LDR r0, =NVIC_ISER
LDR r1, =NVIC_I_TIMER0
STR r1, [r0]
#endif
ORR lr, lr, #0x04 // Ensure exception return uses process stack
BX lr // Exit interrupt
/**
* \b archTickHandler
*
* System timer tick interrupt handler.
*
* @return None
*/
.thumb_func
archTickHandler:
PUSH {r4-r11, lr}
#ifndef PLATFORM_QEMU_LM3S_HACK
cpsid I // Disable core int
#else
LDR r0, =NVIC_ICER
LDR r1, =NVIC_I_TIMER0
STR r1, [r0]
#endif
BL __context_tick_handler
#ifndef PLATFORM_QEMU_LM3S_HACK
cpsie I // Enable core int
#else
LDR r0, =NVIC_ISER
LDR r1, =NVIC_I_TIMER0
STR r1, [r0]
#endif
POP {r4-r11, pc}
/**/
.data
context_new_stack_ptr: .long 0x00000000
context_save_stack_ptr: .long 0x00000000

65
ports/cortex_m/types.h Normal file
View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2012, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __TYPES_H__
#define __TYPES_H__
#ifndef _STDINT_H
typedef unsigned int uintptr_t ;
typedef int intptr_t ;
typedef unsigned long long uint64_t ;
typedef unsigned int uint32_t ;
typedef unsigned short uint16_t ;
typedef unsigned char uint8_t ;
typedef int int32_t ;
typedef short int16_t ;
typedef char int8_t ;
#endif
#ifndef OFFSETOF
#define OFFSETOF(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)
#endif
#ifndef INLINE
#define INLINE __inline
#endif
/* IO definitions (access restrictions to peripheral registers) */
#ifndef __I
#define __I volatile /*!< defines 'read only' permissions */
#endif
#ifndef __O
#define __O volatile /*!< defines 'write only' permissions */
#endif
#ifndef __IO
#define __IO volatile /*!< defines 'read / write' permissions */
#endif
#endif /* __TYPES_H__ */

View File

@@ -28,7 +28,7 @@ architecture-specific details such as appropriate types for 8-bit, 16-bit
etc variables, the port's system tick frequency, and macros for performing
interrupt lockouts / critical sections:
* atomuser.h: Port-specific header required by the kernel for each port
* atomport.h: Port-specific header required by the kernel for each port
A few additional source files are also included here:

View File

@@ -28,7 +28,7 @@ architecture-specific details such as appropriate types for 8-bit, 16-bit
etc variables, the port's system tick frequency, and macros for performing
interrupt lockouts / critical sections:
* atomuser.h: Port-specific header required by the kernel for each port
* atomport.h: Port-specific header required by the kernel for each port
A few additional source files are also included here:

View File

@@ -28,7 +28,7 @@ architecture-specific details such as appropriate types for 8-bit, 16-bit
etc variables, the port's system tick frequency, and macros for performing
interrupt lockouts / critical sections:
* atomuser.h: Port-specific header required by the kernel for each port
* atomport.h: Port-specific header required by the kernel for each port
A few additional source files are also included here:

176
tests/stress1.c Normal file
View File

@@ -0,0 +1,176 @@
#include <stdio.h>
#include "stress1.h"
#include "atom.h"
#include "atommutex.h"
#include "atomsem.h"
#include "atomport.h"
#include "atomport-tests.h"
#define MAX_TEST_THREADS 36
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
static unsigned char monitor_stack[MONITOR_STACK_BYTE_SIZE] ;
static unsigned char stress_test_stack[MAX_TEST_THREADS+1][TEST_STACK_BYTE_SIZE] ;
static unsigned int test_counter[MAX_TEST_THREADS+1] = {0} ;
//static unsigned char test_idle_stack[TEST_STACK_BYTE_SIZE] ;
static uint8_t test_prio[120] = {
005,010,100,200,250, 200,200,200,200,200,
150,150,150,150,150, 250,250,250,250,250,
101,102,103,104,105, 202,204,206,208,210,
150,150,150,150,150, 250,250,250,250,250,
121,122,123,124,125, 061,063,065,067,061,
150,150,150,150,150, 250,250,250,250,250,
005,010,100,200,250, 200,200,200,200,200,
150,150,150,150,150, 250,250,250,250,250,
101,102,103,104,105, 202,204,206,208,210,
150,150,150,150,150, 250,250,250,250,250,
121,122,123,124,125, 061,063,065,067,061,
150,150,150,150,150, 250,250,250,250,250,
};
static uint32_t test_interv[120] = {
002,001,001,001,001, 002,003,004,005,006,
015,015,015,015,015, 025,024,023,022,021,
905,005,005,005,805, 050,051,052,053,054,
015,015,015,015,015, 025,024,023,022,021,
030,030,030,030,030, 070,071,072,073,474,
005,006,007,007,001, 001,001,003,003,005,
001,001,001,001,001, 002,003,004,005,006,
015,015,015,015,015, 025,024,023,022,021,
905,005,005,005,805, 050,051,052,053,054,
015,015,015,015,015, 025,024,023,022,021,
030,030,030,030,030, 070,071,072,073,474,
005,006,007,007,001, 001,001,003,003,005,
};
ATOM_TCB test_tcb[MAX_TEST_THREADS+1] ;
ATOM_TCB monitor_tcb ;
ATOM_TCB test2_tcb ;
ATOM_TCB test3_tcb ;
ATOM_TCB test_idle_tcb ;
void
monitor_thread (uint32_t parm)
{
CRITICAL_STORE;
int i ;
unsigned int counter = 0 ;
ATOM_TCB *tcb ;
uint32_t print_lines_count = 0 ;
tcb = atomCurrentContext() ;
if (parm) {
print_lines_count = ((parm-1)>>2) + 1;
}
for (;;counter++)
{
uint32_t time = atomTimeGet() ;
CRITICAL_START();
ATOMLOG (_STR("\r\nMonitor %d threads # %d (%08d)\r\n"), (int)parm, counter, (unsigned int)time) ;
ATOMLOG (_STR("------------------------------\r\n")) ;
//CRITICAL_END();
for (i=0; i<print_lines_count; i++) {
//CRITICAL_START();
ATOMLOG (_STR("Thr %.2d cnt %08d\tThr %.2lu cnt %08d\tThr %.2lu cnt %08d\tThr %.2lu cnt %08d\r\n"),
i,test_counter[i],
i+print_lines_count,test_counter[i+print_lines_count],
i+print_lines_count*2,test_counter[i+print_lines_count*2],
i+print_lines_count*3,test_counter[i+print_lines_count*3]);
//CRITICAL_END();
}
CRITICAL_END();
atomTimerDelay (200) ;
}
}
void
stress_test_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test_counter[parm]++ ;
CRITICAL_END();
atomTimerDelay (test_interv[parm]) ;
}
}
uint32_t test_start (void)
{
uint32_t i ;
uint32_t failures = 0 ;
CRITICAL_STORE;
CRITICAL_START();
ATOMLOG (_STR("\r\natomthreads_stress_test %.3d threads\r\n"), TEST_THREADS) ;
ATOMLOG (_STR("-----------------------------------\r\n")) ;
CRITICAL_END();
for (i=0; i< TEST_THREADS;i++) {
CRITICAL_START();
ATOMLOG (_STR("stress_test_thread %.3d creating...\r\n"), (int)i) ;
CRITICAL_END();
if (atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], stress_test_thread, i,
&stress_test_stack[i][0], TEST_STACK_BYTE_SIZE, TRUE) != ATOM_OK) {
failures++ ;
break ;
}
}
if (atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 150, monitor_thread, TEST_THREADS,
&monitor_stack[0], MONITOR_STACK_BYTE_SIZE, TRUE) != ATOM_OK) {
failures++ ;
}
if (failures == 0) {
while (1) {
atomTimerDelay (1000) ;
}
}
return failures ;
}
void
atomthreads_stress_test (uint32_t thread_count)
{
unsigned int i ;
if (thread_count > MAX_TEST_THREADS) {
thread_count = MAX_TEST_THREADS ;
}
ATOMLOG (_STR("\r\natomthreads_stress_test %.3d threads\r\n"), (int)thread_count) ;
ATOMLOG (_STR("-----------------------------------\r\n")) ;
atomOSInit(&idle_stack[0], IDLE_STACK_BYTE_SIZE, TRUE) ;
for (i=0; i< thread_count;i++) {
atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], stress_test_thread, i,
&stress_test_stack[i][0], TEST_STACK_BYTE_SIZE, TRUE);
}
atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 150, monitor_thread, thread_count,
&monitor_stack[0], MONITOR_STACK_BYTE_SIZE, TRUE);
atomOSStart() ;
}

18
tests/stress1.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef __STRESS1_H__
#define __STRESS1_H__
#include "atomport.h"
#define TEST_STACK_BYTE_SIZE 0x200
#define IDLE_STACK_BYTE_SIZE 0x200
#define MONITOR_STACK_BYTE_SIZE 0x400
#ifndef TEST_THREADS
#define TEST_THREADS 16
#endif
extern void atomthreads_stress_test (uint32_t thread_count) ;
extern uint32_t test_start (void) ;
#endif /* __STRESS1_H__ */