From 3ac858b8e038b2435f47a8ad03422d196b15c3b9 Mon Sep 17 00:00:00 2001 From: kelvinlawson Date: Thu, 14 Jan 2010 13:59:49 -0700 Subject: [PATCH 01/28] github generated gh-pages branch --- index.html | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..7fdf81a --- /dev/null +++ b/index.html @@ -0,0 +1,82 @@ + + + + + + + kelvinlawson/atomthreads @ GitHub + + + + + + + Fork me on GitHub + +
+ +
+ + + + +
+ +

atomthreads + by kelvinlawson

+ +
+ Lightweight, Portable RTOS Scheduler +
+ +

License

+

BSD

+

Authors

+

Kelvin Lawson (kelvinl@users.sf.net)

+

Contact

+

Kelvin Lawson (kelvinl@users.sf.net)

+ + +

Download

+

+ You can download this project in either + zip or + tar formats. +

+

You can also clone the project with Git + by running: +

$ git clone git://github.com/kelvinlawson/atomthreads
+

+ + + +
+ + + + From b9e7e9cc63a69180539219c8044cdf2078151593 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Fri, 3 Sep 2010 22:23:47 +0200 Subject: [PATCH 02/28] New, atomvm! Added ATOM_TLS for TLS or other thread specific storage. --- kernel/atom.h | 4 + ports/atomvm/README.txt | 39 +++ ports/atomvm/atomport-tests.h | 58 ++++ ports/atomvm/atomport.c | 172 ++++++++++ ports/atomvm/atomport.h | 74 ++++ ports/atomvm/atomuser.h | 63 ++++ ports/atomvm/atomvm.c | 626 ++++++++++++++++++++++++++++++++++ ports/atomvm/atomvm.h | 72 ++++ ports/atomvm/test/main.c | 249 ++++++++++++++ 9 files changed, 1357 insertions(+) create mode 100644 ports/atomvm/README.txt create mode 100644 ports/atomvm/atomport-tests.h create mode 100644 ports/atomvm/atomport.c create mode 100644 ports/atomvm/atomport.h create mode 100644 ports/atomvm/atomuser.h create mode 100644 ports/atomvm/atomvm.c create mode 100644 ports/atomvm/atomvm.h create mode 100644 ports/atomvm/test/main.c diff --git a/kernel/atom.h b/kernel/atom.h index 43c3734..b725c66 100755 --- a/kernel/atom.h +++ b/kernel/atom.h @@ -66,6 +66,10 @@ typedef struct atom_tcb uint32_t stack_size; /* Size of stack allocation in bytes */ #endif +#ifdef ATOM_TLS + ATOM_TLS +#endif + } ATOM_TCB; diff --git a/ports/atomvm/README.txt b/ports/atomvm/README.txt new file mode 100644 index 0000000..0fa9099 --- /dev/null +++ b/ports/atomvm/README.txt @@ -0,0 +1,39 @@ +--------------------------------------------------------------------------- + +Library: Atomvn +Author: Natie van Rooyen +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 VM 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 well on single core +systems. + +--------------------------------------------------------------------------- + +RUNNING THE TESTS + +The test, main.c, was designed to stress the vm as opposed to testing the RTOS. +However, the test can also run the unit tests if desired by using the +precompiled directive UNIT_TESTS and linking in the desired unit test. + +--------------------------------------------------------------------------- + +FINALLY + +Good luck, but most of all, have fun! diff --git a/ports/atomvm/atomport-tests.h b/ports/atomvm/atomport-tests.h new file mode 100644 index 0000000..9f5320d --- /dev/null +++ b/ports/atomvm/atomport-tests.h @@ -0,0 +1,58 @@ +/* + * 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_PORT_TESTS_H +#define __ATOM_PORT_TESTS_H + +/* Include Atomthreads kernel API */ +#include "atom.h" + +/* Prerequisite include for ATOMLOG() macro (via printf) */ +#include + +/* 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 /* __ATOM_PORT_TESTS_H */ + diff --git a/ports/atomvm/atomport.c b/ports/atomvm/atomport.c new file mode 100644 index 0000000..a832e03 --- /dev/null +++ b/ports/atomvm/atomport.c @@ -0,0 +1,172 @@ +/* + * 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" + + +/** Forward declarations */ +static void thread_shell (void); +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 () +{ + atomvmCtrlInit (&the_atomvm) ; + cntrl_thread = CreateThread (NULL, 0, cntrl_thread_proc, 0, CREATE_SUSPENDED, NULL) ; + ResumeThread (cntrl_thread) ; +} + +DWORD WINAPI +cntrl_thread_proc (LPVOID lpParameter) + { + atomvmCtrlRun (the_atomvm, 0) ; + return 0 ; + } + + +/** + * \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(); + atomvmExitCritical (the_atomvm) ; + + /* 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 ; + + atomvmContextCreate (the_atomvm, &tcb_ptr->context, (unsigned int )stack_top, (unsigned int )thread_shell) ; +} + + +/** + * \b archFirstThreadRestore + * + * Documented in atomThreads. + * + */ +void +archFirstThreadRestore(ATOM_TCB * p_sp_new) +{ + atomvmContextSwitch (the_atomvm, p_sp_new->context) ; +} + + +/** + * \b archContextSwitch + * + * Documented in atomThreads. + * + */ +void +archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) +{ + atomvmContextSwitch (the_atomvm, p_sp_new->context) ; +} + + +/** + * \b archTimerTickIrqHandler + * + * System timer tick interrupt handler. + * + */ +void archTimerTickIrqHandler () +{ + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); +} + + +unsigned int +__enter_critical () +{ + return atomvmEnterCritical (the_atomvm) ; +} + + +void +__exit_critical (unsigned int isr) +{ + atomvmExitCritical (the_atomvm) ; +} diff --git a/ports/atomvm/atomport.h b/ports/atomvm/atomport.h new file mode 100644 index 0000000..1022e3e --- /dev/null +++ b/ports/atomvm/atomport.h @@ -0,0 +1,74 @@ +/* + * 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_PORT_H__ +#define __ATOM_PORT_H__ + +#include "atomvm.h" + +#define SYSTEM_MEMALIGN sizeof (unsigned int) +#define SYSTEM_TICKS_PER_SEC 100 + + +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 * + + +/* Critical region protection */ +extern unsigned int __enter_critical() ; +extern void __exit_critical(unsigned int) ; + +#define CRITICAL_STORE unsigned int __atom +#define CRITICAL_START() __atom = __enter_critical() +#define CRITICAL_END() __exit_critical(__atom) + +#define ATOM_TLS HATOMVM_CONTEXT context ; + +/* Function prototypes */ +extern void atomvmRun () ; +extern void archTimerTickIrqHandler () ; + +/* The instance of the atomvm for this port */ +extern HATOMVM the_atomvm ; + +#endif /* __ATOM_PORT_H */ diff --git a/ports/atomvm/atomuser.h b/ports/atomvm/atomuser.h new file mode 100644 index 0000000..c12374d --- /dev/null +++ b/ports/atomvm/atomuser.h @@ -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 + + +#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 diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c new file mode 100644 index 0000000..fe8ca3e --- /dev/null +++ b/ports/atomvm/atomvm.c @@ -0,0 +1,626 @@ +/* +* 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. +*/ + +#include "atomvm.h" +#include + +#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS) + +#define ATOMVM_ATOMVM_PERF_COUNTER(patomvm, counter) (InterlockedIncrement(&patomvm->perf_counters.counter)) + +/* 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 ; + +typedef struct ATOMVM_PERF_COUNTERS_S { + + /* Number of interrupt requests */ + uint32_t int_request ; + + /* Number of service calls (context switches and + context init from atom virtual machime) */ + uint32_t service_call ; + + /* Total number of context switches */ + uint32_t context_switch ; + +} ATOMVM_PERF_COUNTERS, *PATOMVM_PERF_COUNTERS ; + +/* 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 critical_count is + incremented for the context. Interrupts will only occur while + the critical_count is zero. The functions atomvmExitCritical() + and atomvmEnterCritical() will respectively decrement and + increment the critical count */ + volatile uint32_t critical_count ; + +} ATOMVM_CONTEXT, *PATOMVM_CONTEXT ; + +/* ATOMVM defines the state of an instance to an atomvm. It is created +by a call to atomvmCtrlInit(). */ +typedef struct ATOMVM_S { + + /* 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 + (workaround to not check everytime if the first context + was already started) */ + ATOMVM_CONTEXT atom_init_context ; + + /* Performance counters */ + volatile ATOMVM_PERF_COUNTERS perf_counters ; + +} ATOMVM, *PATOMVM ; + + +/* Forward declaration for the atom virtual machine thread */ +static DWORD WINAPI vm_thread (LPVOID lpParameter) ; + + +/** +* \b atomvmCtrlInit +* +* This is an atomvm controll function used by a controlling thread +* and must not be called from the atom virtual machine. +* +* Initializes the virtual machine. +* +* ToDo: More Error checking. +* +* @param[out] atomvm Handle to the virtual machine created. +* +* @return Zero on failure. +*/ +uint32_t +atomvmCtrlInit (HATOMVM *atomvm) +{ + PATOMVM patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ; + + if (patomvm) { + + memset (patomvm, 0, sizeof(struct ATOMVM_S)) ; + + 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) ; + + patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, 0, CREATE_SUSPENDED, NULL) ; + + patomvm->atom_init_context.critical_count = 1 ; + patomvm->current_context = &patomvm->atom_init_context ; + + *atomvm = (HATOMVM)patomvm ; + + } + + return patomvm != 0 ; +} + + +/** +* \b atomvmCtrlRun +* +* This is an atomvm controll function used by a controlling thread +* and must not be called from the atom virtual machine. +* +* After a call to atomvmCtrlInit 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 atomvmCtrlInit. +* @param[in] flags Reserved for later use. +* +* @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 pservice_call ; + + 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) { + + ATOMVM_ATOMVM_PERF_COUNTER(patomvm, service_call) ; + + //InterlockedExchange ((volatile uint32_t*)&pservice_call, (uint32_t)patomvm->service_call) ; + pservice_call = patomvm->service_call ; + while (!pservice_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. */ + FlushProcessWriteBuffers (); +#endif + InterlockedExchange (&pservice_call->result, pservice_call->callback (patomvm, pservice_call)) ; + InterlockedExchange (&pservice_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->critical_count == 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. */ + FlushProcessWriteBuffers (); +#endif + if (patomvm->current_context->critical_count == 0) { + + ATOMVM_ATOMVM_PERF_COUNTER(patomvm, int_request) ; + + patomvm->status_isr++ ; + patomvm->isr () ; + patomvm->status_isr-- ; + + res = ResumeThread (patomvm->vm_thread) ; + ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ; + InterlockedExchange ((volatile uint32_t*)&patomvm->isr, 0) ; + ResetEvent (patomvm->atomvm_int) ; + 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 ; + + } + + } + +} + + +/** +* \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 atomvmCtrlInit. +* +* ToDo: this function was never tested. +* +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* +* @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) ; + + 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 is suspended during the callback. +* +* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @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 atomvmExitCritical +* +* This function is to be used by the atom virtual machine. +* +* This function will decrement the critical count for the current atomvm context. +* When the critical count reaches zero, interrupts will be enabled again. Calling +* this function from inside an isr has no effect. +* +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* +* @return Critical count before this function was called. +*/ +int32_t +atomvmExitCritical (HATOMVM atomvm) +{ + PATOMVM patomvm = (PATOMVM) atomvm ; + int32_t count = 0; + + if (patomvm->status_isr == 0) { + count = InterlockedDecrement (&patomvm->current_context->critical_count) ; + } + + return count ; +} + + +/** +* \b atomvmEnterCritical +* +* This function is to be used by the atom virtual machine. +* +* This function will increment the critical count for the current atomvm +* context. Interrupts will be disabled when the critical count is not zero. +* Calling this function from inside an isr has no effect. +* +* All threads are created with a critical count of 1. +* +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* +* @return Critical count before this function was called. +*/ +int32_t +atomvmEnterCritical (HATOMVM atomvm) +{ + PATOMVM patomvm = (PATOMVM) atomvm ; + int32_t count = 0 ; + + if (patomvm->status_isr == 0) { + count = InterlockedIncrement (&patomvm->current_context->critical_count) ; + } + + return count ; +} + + +/** +* \b atomvmCtrlIntRequest +* +* This is an atomvm controll function used by a controlling thread(s) +* 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 block untill after the interrupt completes. +* +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* @param[in] isr The address of the interrupt service routine. The routine must use +* the default calling convention of the compiler. +* +* @return None +*/ +void +atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) +{ + PATOMVM patomvm = (PATOMVM) atomvm ; + + while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) == 0) { + SwitchToThread() ; + } + SignalObjectAndWait(patomvm->atomvm_int, patomvm->atomvm_int_complete, INFINITE, FALSE) ; + +} + + +/** +* \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 atomvmCtrlInit. +* @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) ; +} + + +/** +* \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] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* @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 using the default caling convention of the compiler. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t entry) +{ + uint32_t res ; + PATOMVM patomvm = (PATOMVM) atomvm ; + 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->critical_count = 1 ; + + res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ; + + if (res) { + pcontext->Ebp = stack ; + pcontext->Esp = stack ; + pcontext->Eip = entry ; + *atomvm_context = (HATOMVM_CONTEXT)new_context ; + } + + 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 atomvmCtrlInit. +* @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 ; + uint32_t res2 ; + PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback ; + CONTEXT* pnew_context = &context_switch->pcontext->context ; + + ATOMVM_ATOMVM_PERF_COUNTER(patomvm, context_switch) ; + + res1 = GetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ; + ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ; + + InterlockedExchange ((volatile uint32_t*)&patomvm->current_context, (uint32_t)pnew_context) ; + res2 = SetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ; + ATOMVM_ASSERT(res2 , _T("SetThreadContext failed")) ; + + return res1 & res2 ; +} + + +/** +* \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] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* @param[in] new_context The context to schedule. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) +{ + PATOMVM patomvm = (PATOMVM) atomvm ; + ATOMVM_CALLBACK_CONTEXT context_switch ; + + context_switch.pcontext = (PATOMVM_CONTEXT) new_context ; + + return invokeCallback (patomvm, callbackContextSwitch, (PATOMVM_CALLBACK)&context_switch) ; +} + +/** +* \b atomvmContextDesrtroy +* +* This function is to be used by the atom virtual machine. +* +* This functiondestroyes a atomvm context created by atomvmContextCreate. +* +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* @param[in] context The context to destroy. +* +* @return None +*/ +void +atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) +{ + PATOMVM patomvm = (PATOMVM) atomvm ; + + ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context, + _T("atomvmContextDesrtroy failed")) ; + + free((void*)context) ; +} + + +/** +* \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) +{ + __atomvmReset () ; + return 0 ; +} diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h new file mode 100644 index 0000000..52ab2cb --- /dev/null +++ b/ports/atomvm/atomvm.h @@ -0,0 +1,72 @@ +/* + * 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. + */ +#ifndef __ATOMVM_H__ +#define __ATOMVM_H__ + +#include +#include "atomuser.h" + + +#ifdef _DEBUG +#define ATOMVM_ASSERT(x, msg) _ASSERT(x) +#else +#define ATOMVM_ASSERT(x, msg) +#endif + + +/* Forward declarations */ + +/* This is an opaque handle to an instance of an atomvm created + by a call to atomvmCtrlInit() */ +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 atomvmCtrlInit (HATOMVM* atomvm) ; +extern void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ; +extern void atomvmCtrlIntRequest (HATOMVM atomvm, uintptr_t isr) ; +extern void atomvmCtrlClose (HATOMVM atomvm) ; + +/* Function prototypes for use by the atom virtual machine */ +extern int32_t atomvmExitCritical (HATOMVM atomvm) ; +extern int32_t atomvmEnterCritical (HATOMVM atomvm) ; +extern uint32_t atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; +extern uint32_t atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) ; +extern void atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) ; + +/* Function prototypes to be implemted in the atom virtual machine */ +extern void __atomvmReset (void) ; +extern void __atomvmClose (void) ; + + +#endif /* __ATOMVM_H__ */ diff --git a/ports/atomvm/test/main.c b/ports/atomvm/test/main.c new file mode 100644 index 0000000..ed05b5b --- /dev/null +++ b/ports/atomvm/test/main.c @@ -0,0 +1,249 @@ +#include +#include + +#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 51 + +#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 +monitor_thread (uint32_t parm) +{ + CRITICAL_STORE; + int i ; + int c = 0 ; + ATOM_TCB *tcb ; + + tcb = atomCurrentContext() ; + + for (;;) + { + + CRITICAL_START(); + + printf("Monitor # %04d (%08d)\n", c++, atomTimeGet()) ; + printf("-------------------------\n") ; + + for (i=0; i Date: Tue, 7 Sep 2010 19:27:15 +0200 Subject: [PATCH 03/28] Initial realease. --- ports/atomvm/README.txt | 19 +++---- ports/atomvm/atomvm.c | 115 ++++++++++++++++++++-------------------- ports/atomvm/atomvm.h | 29 +++++----- 3 files changed, 81 insertions(+), 82 deletions(-) diff --git a/ports/atomvm/README.txt b/ports/atomvm/README.txt index 0fa9099..c12310a 100644 --- a/ports/atomvm/README.txt +++ b/ports/atomvm/README.txt @@ -7,9 +7,9 @@ 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 VM is -for the evaluation of Real Time Operating Systems (like atomthreads) and -the development and testing of modules for this Real Time Operating System +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. --------------------------------------------------------------------------- @@ -21,19 +21,20 @@ directory and the 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 well on single core -systems. +Atomvm was designed for multi core systems but also runs fine on any single +core system. --------------------------------------------------------------------------- RUNNING THE TESTS -The test, main.c, was designed to stress the vm as opposed to testing the RTOS. -However, the test can also run the unit tests if desired by using the -precompiled directive UNIT_TESTS and linking in the desired unit test. +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. --------------------------------------------------------------------------- FINALLY -Good luck, but most of all, have fun! +Good luck, but most of all, have fun!! diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c index fe8ca3e..34075cb 100644 --- a/ports/atomvm/atomvm.c +++ b/ports/atomvm/atomvm.c @@ -30,31 +30,31 @@ #include "atomvm.h" #include -#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS) +#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS) -#define ATOMVM_ATOMVM_PERF_COUNTER(patomvm, counter) (InterlockedIncrement(&patomvm->perf_counters.counter)) +#define ATOMVM_ATOMVM_PERF_COUNTER(patomvm, counter) (InterlockedIncrement(&patomvm->perf_counters.counter)) /* Data types */ /* Forward declarations */ -typedef struct ATOMVM_S * PATOMVM ; -typedef struct ATOMVM_CALLBACK_S * PATOMVM_CALLBACK ; -typedef struct ATOMVM_CONTEXT_S * PATOMVM_CONTEXT ; +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 ; + 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 ; + volatile uint32_t lock ; /* Result of the call */ - volatile uint32_t result ; + volatile uint32_t result ; } ATOMVM_CALLBACK, *PATOMVM_CALLBACK ; @@ -63,24 +63,24 @@ typedef struct ATOMVM_CALLBACK_S { that take as parameter a pointer to a ATOMVM_CONTEXT to operate on */ typedef struct ATOMVM_CALLBACK_CONTEXT_S { - ATOMVM_CALLBACK callback ; + ATOMVM_CALLBACK callback ; /* Context the callback function will operate on */ - volatile PATOMVM_CONTEXT pcontext ; + volatile PATOMVM_CONTEXT pcontext ; } ATOMVM_CALLBACK_CONTEXT, *PATOMVM_CALLBACK_CONTEXT ; typedef struct ATOMVM_PERF_COUNTERS_S { /* Number of interrupt requests */ - uint32_t int_request ; + uint32_t int_request ; /* Number of service calls (context switches and context init from atom virtual machime) */ - uint32_t service_call ; + uint32_t service_call ; /* Total number of context switches */ - uint32_t context_switch ; + uint32_t context_switch ; } ATOMVM_PERF_COUNTERS, *PATOMVM_PERF_COUNTERS ; @@ -90,14 +90,14 @@ typedef struct ATOMVM_CONTEXT_S { /* A virtual machine thread context. These are saved and restored during context initialization and context switches */ - CONTEXT context ; + CONTEXT context ; /* When entering a critical section the critical_count is incremented for the context. Interrupts will only occur while the critical_count is zero. The functions atomvmExitCritical() and atomvmEnterCritical() will respectively decrement and increment the critical count */ - volatile uint32_t critical_count ; + volatile uint32_t critical_count ; } ATOMVM_CONTEXT, *PATOMVM_CONTEXT ; @@ -106,40 +106,40 @@ by a call to atomvmCtrlInit(). */ typedef struct ATOMVM_S { /* Thread the virtual machine will run in */ - HANDLE vm_thread ; + HANDLE vm_thread ; /* Handles to events and mutexes used for synchronization */ - HANDLE atomvm_call ; - HANDLE atomvm_int ; - HANDLE atomvm_int_complete ; - HANDLE atomvm_close ; + HANDLE atomvm_call ; + HANDLE atomvm_int ; + HANDLE atomvm_int_complete ; + HANDLE atomvm_close ; /* next ISR */ - volatile void (*isr)(void) ; + volatile void (*isr)(void) ; /* True if in an ISR */ - volatile uint32_t status_isr ; + volatile uint32_t status_isr ; /* The current context that was scheduled by a call to atomvmContextSwitch() */ - PATOMVM_CONTEXT current_context ; + PATOMVM_CONTEXT current_context ; /* Service call address, synchronization lock, parameters and, return value for the current service call */ - PATOMVM_CALLBACK service_call ; + PATOMVM_CALLBACK service_call ; /* Context for startup, before any context was scheduled (workaround to not check everytime if the first context was already started) */ - ATOMVM_CONTEXT atom_init_context ; + ATOMVM_CONTEXT atom_init_context ; /* Performance counters */ - volatile ATOMVM_PERF_COUNTERS perf_counters ; + volatile ATOMVM_PERF_COUNTERS perf_counters ; } ATOMVM, *PATOMVM ; /* Forward declaration for the atom virtual machine thread */ -static DWORD WINAPI vm_thread (LPVOID lpParameter) ; +static DWORD WINAPI vm_thread (LPVOID lpParameter) ; /** @@ -202,11 +202,11 @@ atomvmCtrlInit (HATOMVM *atomvm) void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) { - PATOMVM patomvm = (PATOMVM) atomvm ; - HANDLE wait[3] ; - uint32_t res ; - uint32_t wait_object ; - PATOMVM_CALLBACK pservice_call ; + PATOMVM patomvm = (PATOMVM) atomvm ; + HANDLE wait[3] ; + uint32_t res ; + uint32_t wait_object ; + PATOMVM_CALLBACK service_call ; ResumeThread (patomvm->vm_thread) ; @@ -222,9 +222,8 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ATOMVM_ATOMVM_PERF_COUNTER(patomvm, service_call) ; - //InterlockedExchange ((volatile uint32_t*)&pservice_call, (uint32_t)patomvm->service_call) ; - pservice_call = patomvm->service_call ; - while (!pservice_call->lock) { + service_call = patomvm->service_call ; + while (!service_call->lock) { SwitchToThread () ; } @@ -236,8 +235,8 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) is stopped before executing the next instruction. */ FlushProcessWriteBuffers (); #endif - InterlockedExchange (&pservice_call->result, pservice_call->callback (patomvm, pservice_call)) ; - InterlockedExchange (&pservice_call->lock, 0) ; + 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")) ; @@ -313,8 +312,8 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) void atomvmCtrlClose (HATOMVM atomvm) { - PATOMVM patomvm = (PATOMVM) atomvm ; - DWORD code ; + PATOMVM patomvm = (PATOMVM) atomvm ; + DWORD code ; __atomvmClose () ; @@ -392,8 +391,8 @@ invokeCallback (PATOMVM patomvm, ATOMVM_CALLBACK_F callback, PATOMVM_CALLBACK se int32_t atomvmExitCritical (HATOMVM atomvm) { - PATOMVM patomvm = (PATOMVM) atomvm ; - int32_t count = 0; + PATOMVM patomvm = (PATOMVM) atomvm ; + int32_t count = 0; if (patomvm->status_isr == 0) { count = InterlockedDecrement (&patomvm->current_context->critical_count) ; @@ -421,8 +420,8 @@ atomvmExitCritical (HATOMVM atomvm) int32_t atomvmEnterCritical (HATOMVM atomvm) { - PATOMVM patomvm = (PATOMVM) atomvm ; - int32_t count = 0 ; + PATOMVM patomvm = (PATOMVM) atomvm ; + int32_t count = 0 ; if (patomvm->status_isr == 0) { count = InterlockedIncrement (&patomvm->current_context->critical_count) ; @@ -452,7 +451,7 @@ atomvmEnterCritical (HATOMVM atomvm) void atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) { - PATOMVM patomvm = (PATOMVM) atomvm ; + PATOMVM patomvm = (PATOMVM) atomvm ; while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) == 0) { SwitchToThread() ; @@ -477,8 +476,8 @@ atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) uint32_t callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback) { - PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback; - CONTEXT * pcontext = &context_switch->pcontext->context ; + PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback; + CONTEXT * pcontext = &context_switch->pcontext->context ; pcontext->ContextFlags = CONTEXT_VM ; @@ -505,11 +504,11 @@ callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback) uint32_t atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t entry) { - uint32_t res ; - PATOMVM patomvm = (PATOMVM) atomvm ; - PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)malloc (sizeof(ATOMVM_CONTEXT)) ; - CONTEXT* pcontext = &new_context->context ; - ATOMVM_CALLBACK_CONTEXT context_init ; + uint32_t res ; + PATOMVM patomvm = (PATOMVM) atomvm ; + 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 ; @@ -543,10 +542,10 @@ atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* atomvm_context, uint32_t s uint32_t callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback) { - uint32_t res1 ; - uint32_t res2 ; - PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback ; - CONTEXT* pnew_context = &context_switch->pcontext->context ; + uint32_t res1 ; + uint32_t res2 ; + PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback ; + CONTEXT* pnew_context = &context_switch->pcontext->context ; ATOMVM_ATOMVM_PERF_COUNTER(patomvm, context_switch) ; @@ -576,8 +575,8 @@ callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback) uint32_t atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) { - PATOMVM patomvm = (PATOMVM) atomvm ; - ATOMVM_CALLBACK_CONTEXT context_switch ; + PATOMVM patomvm = (PATOMVM) atomvm ; + ATOMVM_CALLBACK_CONTEXT context_switch ; context_switch.pcontext = (PATOMVM_CONTEXT) new_context ; @@ -599,7 +598,7 @@ atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) void atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) { - PATOMVM patomvm = (PATOMVM) atomvm ; + PATOMVM patomvm = (PATOMVM) atomvm ; ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context, _T("atomvmContextDesrtroy failed")) ; diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h index 52ab2cb..3374506 100644 --- a/ports/atomvm/atomvm.h +++ b/ports/atomvm/atomvm.h @@ -34,7 +34,7 @@ #ifdef _DEBUG -#define ATOMVM_ASSERT(x, msg) _ASSERT(x) +#define ATOMVM_ASSERT(x, msg) _ASSERT(x) #else #define ATOMVM_ASSERT(x, msg) #endif @@ -44,29 +44,28 @@ /* This is an opaque handle to an instance of an atomvm created by a call to atomvmCtrlInit() */ -typedef struct ATOMVM* HATOMVM ; +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 ; +typedef struct ATOMVM_CONTEXT* HATOMVM_CONTEXT ; /* Function prototypes used for controlling the atom virtual machine */ -extern uint32_t atomvmCtrlInit (HATOMVM* atomvm) ; -extern void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ; -extern void atomvmCtrlIntRequest (HATOMVM atomvm, uintptr_t isr) ; -extern void atomvmCtrlClose (HATOMVM atomvm) ; +extern uint32_t atomvmCtrlInit (HATOMVM* atomvm) ; +extern void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ; +extern void atomvmCtrlIntRequest (HATOMVM atomvm, uintptr_t isr) ; +extern void atomvmCtrlClose (HATOMVM atomvm) ; /* Function prototypes for use by the atom virtual machine */ -extern int32_t atomvmExitCritical (HATOMVM atomvm) ; -extern int32_t atomvmEnterCritical (HATOMVM atomvm) ; -extern uint32_t atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; -extern uint32_t atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) ; -extern void atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) ; +extern int32_t atomvmExitCritical (HATOMVM atomvm) ; +extern int32_t atomvmEnterCritical (HATOMVM atomvm) ; +extern uint32_t atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; +extern uint32_t atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) ; +extern void atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) ; /* Function prototypes to be implemted in the atom virtual machine */ -extern void __atomvmReset (void) ; -extern void __atomvmClose (void) ; +extern void __atomvmReset (void) ; +extern void __atomvmClose (void) ; - #endif /* __ATOMVM_H__ */ From 8a880d27161e47ee63e707a98c4e90e19122e5de Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 7 Sep 2010 19:37:59 +0200 Subject: [PATCH 04/28] Added "Thread Local Storage" --- kernel/atom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/atom.h b/kernel/atom.h index b725c66..55d469e 100755 --- a/kernel/atom.h +++ b/kernel/atom.h @@ -67,7 +67,7 @@ typedef struct atom_tcb #endif #ifdef ATOM_TLS - ATOM_TLS + ATOM_TLS /* Thread Local Storage */ #endif } ATOM_TCB; From a3dec2170717df9cbbfbd13f3f4ad006bc80de60 Mon Sep 17 00:00:00 2001 From: navaro Date: Mon, 20 Sep 2010 01:43:38 -0700 Subject: [PATCH 05/28] --- ports/atomvm/README.txt | 80 ++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/ports/atomvm/README.txt b/ports/atomvm/README.txt index c12310a..77b327e 100644 --- a/ports/atomvm/README.txt +++ b/ports/atomvm/README.txt @@ -1,40 +1,40 @@ ---------------------------------------------------------------------------- - -Library: Atomvn -Author: Natie van Rooyen -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. - ---------------------------------------------------------------------------- - -FINALLY - -Good luck, but most of all, have fun!! +--------------------------------------------------------------------------- + +Library: Atomvn +Author: Natie van Rooyen +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. + +--------------------------------------------------------------------------- + +FINALLY + +Good luck, but most of all, have fun!! From 202cbcf2dffb5ea4243e84f43b4fa05131e8353c Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Fri, 24 Sep 2010 18:44:18 +0200 Subject: [PATCH 06/28] interrupt request updated. started multicore support. --- ports/atomvm/atomport.c | 12 +- ports/atomvm/atomvm.c | 461 +++++++++++++++++++++++++++++++++++---- ports/atomvm/atomvm.h | 74 ++++++- ports/atomvm/test/main.c | 6 +- 4 files changed, 497 insertions(+), 56 deletions(-) diff --git a/ports/atomvm/atomport.c b/ports/atomvm/atomport.c index a832e03..b930fde 100644 --- a/ports/atomvm/atomport.c +++ b/ports/atomvm/atomport.c @@ -85,7 +85,7 @@ thread_shell (void) * is first restored. */ // sei(); - atomvmExitCritical (the_atomvm) ; + atomvmExitCritical () ; /* Call the thread entry point */ if (curr_tcb && curr_tcb->entry_point) @@ -110,7 +110,7 @@ archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(u tcb_ptr->entry_param = entry_param ; tcb_ptr->entry_point = entry_point ; - atomvmContextCreate (the_atomvm, &tcb_ptr->context, (unsigned int )stack_top, (unsigned int )thread_shell) ; + atomvmContextCreate (&tcb_ptr->context, (unsigned int )stack_top, (unsigned int )thread_shell) ; } @@ -123,7 +123,7 @@ archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(u void archFirstThreadRestore(ATOM_TCB * p_sp_new) { - atomvmContextSwitch (the_atomvm, p_sp_new->context) ; + atomvmContextSwitch (0, p_sp_new->context) ; } @@ -136,7 +136,7 @@ archFirstThreadRestore(ATOM_TCB * p_sp_new) void archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) { - atomvmContextSwitch (the_atomvm, p_sp_new->context) ; + atomvmContextSwitch (p_sp_old->context, p_sp_new->context) ; } @@ -161,12 +161,12 @@ void archTimerTickIrqHandler () unsigned int __enter_critical () { - return atomvmEnterCritical (the_atomvm) ; + return atomvmEnterCritical () ; } void __exit_critical (unsigned int isr) { - atomvmExitCritical (the_atomvm) ; + atomvmExitCritical () ; } diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c index 34075cb..8367d8d 100644 --- a/ports/atomvm/atomvm.c +++ b/ports/atomvm/atomvm.c @@ -27,8 +27,43 @@ * 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 atomvmCtrlInit(): . + * \li atomvmCtrlRun(): . + * \li atomvmCtrlIntRequest(): . + * \li atomvmCtrlClose(): . + * + * \b Function prototypes for use by the atom virtual machine: \n + * + * \li atomvmExitCritical(): . + * \li atomvmEnterCritical(): . + * \li atomvmContextCreate(): . + * \li atomvmContextSwitch(): . + * \li atomvmContextDesrtroy(): . + * + * \b Function prototypes to be implemted in the atom virtual machine: \n + * + * \li __atomvmReset(): . + * \li __atomvmClose(): . + * + */ + #include "atomvm.h" #include +#include + + #define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS) @@ -70,6 +105,31 @@ typedef struct ATOMVM_CALLBACK_CONTEXT_S { } 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_IPI is the parameter for a ATOMVM_CALLBACK_F call +that take as parameter a pointer to a ipi target and the isr to call */ +typedef struct ATOMVM_CALLBACK_IPI_S { + + ATOMVM_CALLBACK callback ; + + /* Parameters the callback function will operate on */ + volatile uint32_t target ; + volatile uint32_t isr ; + +} ATOMVM_CALLBACK_IPI, *PATOMVM_CALLBACK_IPI ; + typedef struct ATOMVM_PERF_COUNTERS_S { /* Number of interrupt requests */ @@ -98,6 +158,7 @@ typedef struct ATOMVM_CONTEXT_S { and atomvmEnterCritical() will respectively decrement and increment the critical count */ volatile uint32_t critical_count ; + uint32_t thread_id ; } ATOMVM_CONTEXT, *PATOMVM_CONTEXT ; @@ -105,6 +166,8 @@ typedef struct ATOMVM_CONTEXT_S { by a call to atomvmCtrlInit(). */ typedef struct ATOMVM_S { + uint32_t atomvm_id ; + /* Thread the virtual machine will run in */ HANDLE vm_thread ; @@ -138,11 +201,19 @@ typedef struct ATOMVM_S { } ATOMVM, *PATOMVM ; +/* Global declarations */ +volatile uint32_t g_atomvm_counter = 0 ; +HANDLE g_atomvm_event = 0 ; +DWORD g_atomvm_tls_idx ; +PATOMVM g_vms[ATOMVM_MAX_VM] ; + + /* Forward declaration for the atom virtual machine thread */ static DWORD WINAPI vm_thread (LPVOID lpParameter) ; /** +* \ingroup atomvm * \b atomvmCtrlInit * * This is an atomvm controll function used by a controlling thread @@ -159,24 +230,41 @@ static DWORD WINAPI vm_thread (LPVOID lpParameter) ; uint32_t atomvmCtrlInit (HATOMVM *atomvm) { - PATOMVM patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ; + PATOMVM patomvm = 0 ; + int32_t i ; - if (patomvm) { + if (g_atomvm_counter < ATOMVM_MAX_VM) { - memset (patomvm, 0, sizeof(struct ATOMVM_S)) ; + patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ; - 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) ; + if (patomvm) { - patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, 0, CREATE_SUSPENDED, NULL) ; + memset (patomvm, 0, sizeof(struct ATOMVM_S)) ; - patomvm->atom_init_context.critical_count = 1 ; - patomvm->current_context = &patomvm->atom_init_context ; + patomvm->atomvm_id = InterlockedIncrement(&g_atomvm_counter) - 1 ; - *atomvm = (HATOMVM)patomvm ; + if (patomvm->atomvm_id == 0) { + g_atomvm_event = CreateEvent (NULL, FALSE, FALSE, 0) ; + g_atomvm_tls_idx = TlsAlloc () ; + for (i=0; iatomvm_id] = patomvm ; + 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) ; + + patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, (void*)patomvm, CREATE_SUSPENDED, NULL) ; + + patomvm->atom_init_context.critical_count = 1 ; + patomvm->current_context = &patomvm->atom_init_context ; + + *atomvm = (HATOMVM)patomvm ; + + } } return patomvm != 0 ; @@ -184,6 +272,7 @@ atomvmCtrlInit (HATOMVM *atomvm) /** +* \ingroup atomvm * \b atomvmCtrlRun * * This is an atomvm controll function used by a controlling thread @@ -207,6 +296,13 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) 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) ; @@ -240,6 +336,7 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ResetEvent (patomvm->atomvm_call) ; res = ResumeThread (patomvm->vm_thread) ; ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ; + } @@ -265,9 +362,10 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) res = ResumeThread (patomvm->vm_thread) ; ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ; + + ResetEvent (patomvm->atomvm_int) ; InterlockedExchange ((volatile uint32_t*)&patomvm->isr, 0) ; - ResetEvent (patomvm->atomvm_int) ; - SetEvent (patomvm->atomvm_int_complete) ; + SetEvent (patomvm->atomvm_int_complete) ; } else { @@ -295,6 +393,7 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) /** +* \ingroup atomvm * \b atomvmCtrlClose * * This is an atomvm controll function used by a controlling thread @@ -329,6 +428,8 @@ atomvmCtrlClose (HATOMVM atomvm) CloseHandle (patomvm->atomvm_close) ; CloseHandle (patomvm->vm_thread) ; + TlsFree (g_atomvm_tls_idx) ; + free (atomvm) ; } @@ -375,7 +476,27 @@ invokeCallback (PATOMVM patomvm, ATOMVM_CALLBACK_F callback, PATOMVM_CALLBACK se } +/* +* \b getAtomvm +* +* Get the atomvm instance for the calling thredd +* +* @return atomvm instance +*/ +__inline PATOMVM +getAtomvm () +{ + PATOMVM patomvm = (PATOMVM) TlsGetValue (g_atomvm_tls_idx) ; + + ATOMVM_ASSERT(patomvm , _T("TlsGetValue failed")) ; + + return patomvm ; + +} + + /** +* \ingroup atomvm * \b atomvmExitCritical * * This function is to be used by the atom virtual machine. @@ -384,14 +505,12 @@ invokeCallback (PATOMVM patomvm, ATOMVM_CALLBACK_F callback, PATOMVM_CALLBACK se * When the critical count reaches zero, interrupts will be enabled again. Calling * this function from inside an isr has no effect. * -* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. -* -* @return Critical count before this function was called. +* @return Critical count before the function call. */ int32_t -atomvmExitCritical (HATOMVM atomvm) +atomvmExitCritical () { - PATOMVM patomvm = (PATOMVM) atomvm ; + PATOMVM patomvm = getAtomvm () ; int32_t count = 0; if (patomvm->status_isr == 0) { @@ -403,6 +522,7 @@ atomvmExitCritical (HATOMVM atomvm) /** +* \ingroup atomvm * \b atomvmEnterCritical * * This function is to be used by the atom virtual machine. @@ -413,14 +533,13 @@ atomvmExitCritical (HATOMVM atomvm) * * All threads are created with a critical count of 1. * -* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. * -* @return Critical count before this function was called. +* @return Critical count before the function call. */ int32_t -atomvmEnterCritical (HATOMVM atomvm) +atomvmEnterCritical () { - PATOMVM patomvm = (PATOMVM) atomvm ; + PATOMVM patomvm = getAtomvm () ; int32_t count = 0 ; if (patomvm->status_isr == 0) { @@ -432,6 +551,24 @@ atomvmEnterCritical (HATOMVM atomvm) /** +* \ingroup atomvm +* \b atomvmCriticalCount +* +* Rerurns the critical cont of the current context. +* +* @return the critical cont of the current context. +*/ +int32_t +atomvmCriticalCount () +{ + PATOMVM patomvm = getAtomvm () ; + + return patomvm->current_context->critical_count ; +} + + +/** +* \ingroup atomvm * \b atomvmCtrlIntRequest * * This is an atomvm controll function used by a controlling thread(s) @@ -440,7 +577,7 @@ atomvmEnterCritical (HATOMVM atomvm) * This function requests an interrupt service routine to be called in the * context of the atom virtual machine. * -* The call will block untill after the interrupt completes. +* The call will block while a previously scheduled interrupt is in progress. * * @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. * @param[in] isr The address of the interrupt service routine. The routine must use @@ -453,10 +590,11 @@ atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) { PATOMVM patomvm = (PATOMVM) atomvm ; + WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) == 0) { SwitchToThread() ; } - SignalObjectAndWait(patomvm->atomvm_int, patomvm->atomvm_int_complete, INFINITE, FALSE) ; + SetEvent (patomvm->atomvm_int) ; } @@ -486,6 +624,7 @@ callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback) /** +* \ingroup atomvm * \b atomvmContextCreate * * This function is to be used by the atom virtual machine. @@ -493,7 +632,6 @@ callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback) * This function creates a atomvm thread context that can be scheduled * by atomvmContextSwitch. * -* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. * @param[out] context Handle to the context of the thread that are allocated * by the caller. * @param[in] stack Stack top. @@ -502,10 +640,10 @@ callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback) * @return Zero on failure, try to call GetLastError(). */ uint32_t -atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t entry) +atomvmContextCreate (HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t entry) { uint32_t res ; - PATOMVM patomvm = (PATOMVM) atomvm ; + PATOMVM patomvm = getAtomvm () ; PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)malloc (sizeof(ATOMVM_CONTEXT)) ; CONTEXT* pcontext = &new_context->context ; ATOMVM_CALLBACK_CONTEXT context_init ; @@ -542,17 +680,20 @@ atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* atomvm_context, uint32_t s uint32_t callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback) { - uint32_t res1 ; + uint32_t res1 = 1 ; uint32_t res2 ; - PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback ; - CONTEXT* pnew_context = &context_switch->pcontext->context ; + PATOMVM_CALLBACK_CONTEXT_SWITCH context_switch = (PATOMVM_CALLBACK_CONTEXT_SWITCH)callback ; + CONTEXT* p_old_context = &context_switch->p_old_context->context ; + CONTEXT* p_new_context = &context_switch->p_new_context->context ; ATOMVM_ATOMVM_PERF_COUNTER(patomvm, context_switch) ; - res1 = GetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ; - ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ; + if (p_old_context) { + res1 = GetThreadContext (patomvm->vm_thread, p_old_context) ; + ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ; + } - InterlockedExchange ((volatile uint32_t*)&patomvm->current_context, (uint32_t)pnew_context) ; + InterlockedExchange ((volatile uint32_t*)&patomvm->current_context, (uint32_t)p_new_context) ; res2 = SetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ; ATOMVM_ASSERT(res2 , _T("SetThreadContext failed")) ; @@ -561,44 +702,45 @@ callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback) /** +* \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] atomvm Handle to the virtual machine created by atomvmCtrlInit. * @param[in] new_context The context to schedule. * * @return Zero on failure, try to call GetLastError(). */ uint32_t -atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) +atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context) { - PATOMVM patomvm = (PATOMVM) atomvm ; - ATOMVM_CALLBACK_CONTEXT context_switch ; + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK_CONTEXT_SWITCH context_switch ; - context_switch.pcontext = (PATOMVM_CONTEXT) new_context ; + 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] atomvm Handle to the virtual machine created by atomvmCtrlInit. * @param[in] context The context to destroy. * * @return None */ void -atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) +atomvmContextDesrtroy (HATOMVM_CONTEXT context) { - PATOMVM patomvm = (PATOMVM) atomvm ; + PATOMVM patomvm = getAtomvm () ; ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context, _T("atomvmContextDesrtroy failed")) ; @@ -606,6 +748,240 @@ atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) 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 () +{ + 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 atomvmCtrlInit(), 1 for the second and so on. +* +* @return The atom vm ID +*/ +uint32_t +atomvmGetVmId () +{ + PATOMVM patomvm = getAtomvm () ; + + return patomvm->atomvm_id ; +} +/** +* \b callbackEventWait +* +* This function is invoked from the controll thread after a call to atomvmEventWait. +* +* The atom virtual machine is suspended while this function is called. +* +* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @param[out] context Context to be scheduled. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +callbackEventWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) +{ + return WaitForSingleObject (g_atomvm_event, INFINITE) == WAIT_OBJECT_0 ; + +} + + +/** +* \ingroup atomvm +* \b atomvmEventWait +* +* This function is to be used by the atom virtual machine. +* +* This function if for synchronization between multiple +* atom vms. +* +* +* @return void. +*/ +void +atomvmEventWait () +{ + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK callback ; + + invokeCallback (patomvm, callbackEventWait, (PATOMVM_CALLBACK)&callback) ; +} + +/** +* \b callbackEventSend +* +* This function is invoked from the controll thread after a call to atomvmEventSend. +* +* The atom virtual machine is suspended while this function is called. +* +* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @param[out] context Context to be scheduled. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +callbackEventSend (PATOMVM patomvm, PATOMVM_CALLBACK callback) +{ + return SetEvent (g_atomvm_event) ; +} + +/** +* \ingroup atomvm +* \b atomvmEventSend +* +* This function is to be used by the atom virtual machine. +* +* This function if for synchronization between multiple +* atom vms. +* +* +* @return void. +*/ +void +atomvmEventSend () +{ + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK callback ; + + invokeCallback (patomvm, callbackEventSend, (PATOMVM_CALLBACK)&callback) ; +} + +/** +* \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 atomvmCtrlInit. +* @param[out] callback Callback parameter. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +callbackInterruptWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) +{ + 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 +atomvmInterruptWait () +{ + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK callback ; + + invokeCallback (patomvm, callbackInterruptWait, (PATOMVM_CALLBACK)&callback) ; +} + +/** +* \ingroup atomvm +* \b callbackScheduleIpi +* +* This function is invoked from the controll thread after a call to atomvmScheduleIpi(). +* +* This function if for synchronization between multiple +* atom vms. +* +* @param[in] target Target atomvm ID, less than ATOMVM_MAX_VM +* @param[in] isr interrupt service routine +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +callbackScheduleIpi (PATOMVM patomvm, PATOMVM_CALLBACK callback) +{ + PATOMVM_CALLBACK_IPI callback_ipi = (PATOMVM_CALLBACK_IPI)callback ; + uint32_t res = 0 ; + + if ((callback_ipi->target < ATOMVM_MAX_VM) && + (g_vms[callback_ipi->target] != patomvm) ) { + + atomvmCtrlIntRequest ((HATOMVM)g_vms[callback_ipi->target], callback_ipi->isr) ; + res = 1 ; + + } + + return res ; +} + + +/** +* \ingroup atomvm +* \b atomvmScheduleIpi +* +* This function is to be used by the atom virtual machine. +* +* This function if for synchronization between multiple +* atom vms. +* +* @param[in] target Target atomvm ID +* @param[in] isr interrupt service routine +* +* @return Zero on failure, the vm is not running. +*/ +uint32_t +atomvmScheduleIpi (uint32_t target, uintptr_t isr) +{ + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK_IPI callback ; + + callback.target = target ; + callback.isr = isr ; + + return invokeCallback (patomvm, callbackScheduleIpi, (PATOMVM_CALLBACK)&callback) ; + + +} + /** * \b vm_thread @@ -620,6 +996,9 @@ atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) DWORD WINAPI vm_thread (LPVOID lpParameter) { + BOOL res = TlsSetValue (g_atomvm_tls_idx, lpParameter) ; + + ATOMVM_ASSERT(res, _T("TlsSetValue failed")) ; __atomvmReset () ; return 0 ; } diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h index 3374506..acc10d6 100644 --- a/ports/atomvm/atomvm.h +++ b/ports/atomvm/atomvm.h @@ -26,6 +26,36 @@ * 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 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.: +* +* @section build 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 main.c to your project. Add both the +* before mentioned directories to the include paths of your project and compile. \n +* Atomvm was designed for multi core systems but also runs fine on any single +* core system. +* +* @section test Running The Test +* 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. +* */ + #ifndef __ATOMVM_H__ #define __ATOMVM_H__ @@ -33,13 +63,15 @@ #include "atomuser.h" -#ifdef _DEBUG +#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 @@ -58,14 +90,42 @@ extern void atomvmCtrlIntRequest (HATOMVM atomvm, uintptr_t isr) ; extern void atomvmCtrlClose (HATOMVM atomvm) ; /* Function prototypes for use by the atom virtual machine */ -extern int32_t atomvmExitCritical (HATOMVM atomvm) ; -extern int32_t atomvmEnterCritical (HATOMVM atomvm) ; -extern uint32_t atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; -extern uint32_t atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) ; -extern void atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) ; +extern int32_t atomvmExitCritical () ; +extern int32_t atomvmEnterCritical () ; +extern int32_t atomvmCriticalCount () ; +extern uint32_t atomvmContextCreate (HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; +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 () ; +/* Function prototypes for use by the atom virtual machine + for synchronization with other running atom virtual machines */ +extern uint32_t atomvmGetVmId () ; +extern void atomvmInterruptWait () ; +extern void atomvmEventWait () ; +extern void atomvmEventSend () ; +extern uint32_t atomvmScheduleIpi (uint32_t target, uintptr_t isr) ; -/* Function prototypes to be implemted in the atom virtual machine */ + + + +/** +* \ingroup atomvm +* \b __atomvmReset +* +* Function prototype to be implemted in 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__ */ diff --git a/ports/atomvm/test/main.c b/ports/atomvm/test/main.c index ed05b5b..d991614 100644 --- a/ports/atomvm/test/main.c +++ b/ports/atomvm/test/main.c @@ -91,8 +91,10 @@ monitor_thread (uint32_t parm) printf("\nIdle Threadd 1 Counter = %d\nIdle Theadrd 2 Counter = %d\nInterrupt Counter = %d",test2_counter,test3_counter,test_isr_count); printf ("\n\n") ; CRITICAL_END(); - - atomTimerDelay (300) ; + //for (i=0; i<100;i++) { + // atomvmInterruptWait () ; + //} + atomTimerDelay (150) ; } } From 10b93017a3e307a7c8a93190687b3445d3debb20 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Mon, 28 Feb 2011 16:49:35 +0100 Subject: [PATCH 07/28] atomvmCtrlIntRequest bug fix (and other updates) --- ports/atomvm/atomport.c | 4 ++-- ports/atomvm/atomvm.c | 38 ++++++++++++++++++++++++-------------- ports/atomvm/atomvm.h | 2 +- ports/atomvm/test/main.c | 2 +- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/ports/atomvm/atomport.c b/ports/atomvm/atomport.c index b930fde..7660040 100644 --- a/ports/atomvm/atomport.c +++ b/ports/atomvm/atomport.c @@ -54,14 +54,14 @@ void atomvmRun () { atomvmCtrlInit (&the_atomvm) ; - cntrl_thread = CreateThread (NULL, 0, cntrl_thread_proc, 0, CREATE_SUSPENDED, NULL) ; + 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 (the_atomvm, 0) ; + atomvmCtrlRun ((HATOMVM)lpParameter, 0) ; return 0 ; } diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c index c01c28d..286428a 100644 --- a/ports/atomvm/atomvm.c +++ b/ports/atomvm/atomvm.c @@ -176,6 +176,7 @@ typedef struct ATOMVM_S { HANDLE atomvm_int ; HANDLE atomvm_int_complete ; HANDLE atomvm_close ; + HANDLE atomvm_event ; /* next ISR */ volatile void (*isr)(void) ; @@ -203,8 +204,7 @@ typedef struct ATOMVM_S { /* Global declarations */ volatile uint32_t g_atomvm_counter = 0 ; -HANDLE g_atomvm_event = 0 ; -DWORD g_atomvm_tls_idx ; +volatile DWORD g_atomvm_tls_idx ; PATOMVM g_vms[ATOMVM_MAX_VM] ; @@ -244,7 +244,6 @@ atomvmCtrlInit (HATOMVM *atomvm) patomvm->atomvm_id = InterlockedIncrement(&g_atomvm_counter) - 1 ; if (patomvm->atomvm_id == 0) { - g_atomvm_event = CreateEvent (NULL, FALSE, FALSE, 0) ; g_atomvm_tls_idx = TlsAlloc () ; for (i=0; iatomvm_int = CreateEvent (NULL, TRUE, FALSE, 0) ; patomvm->atomvm_int_complete = CreateEvent (NULL, FALSE, TRUE, 0) ; patomvm->atomvm_close = CreateEvent (NULL, TRUE, FALSE, 0) ; + patomvm->atomvm_event = CreateEvent (NULL, FALSE, FALSE, 0) ; patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, (void*)patomvm, CREATE_SUSPENDED, NULL) ; @@ -385,6 +385,10 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) break ; + } else { + + ATOMVM_ASSERT(res == 1 , _T("WaitForMultipleObjects failed")) ; + } } @@ -554,9 +558,9 @@ atomvmEnterCritical () * \ingroup atomvm * \b atomvmCriticalCount * -* Rerurns the critical count of the current context. +* Rerurns the critical cont of the current context. * -* @return the critical count of the current context. +* @return the critical cont of the current context. */ int32_t atomvmCriticalCount () @@ -591,7 +595,7 @@ atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) PATOMVM patomvm = (PATOMVM) atomvm ; WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; - while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) == 0) { + while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) != 0) { SwitchToThread() ; } SetEvent (patomvm->atomvm_int) ; @@ -818,7 +822,7 @@ atomvmGetVmId () uint32_t callbackEventWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) { - return WaitForSingleObject (g_atomvm_event, INFINITE) == WAIT_OBJECT_0 ; + return WaitForSingleObject (patomvm->atomvm_event, INFINITE) == WAIT_OBJECT_0 ; } @@ -859,7 +863,14 @@ atomvmEventWait () uint32_t callbackEventSend (PATOMVM patomvm, PATOMVM_CALLBACK callback) { - return SetEvent (g_atomvm_event) ; + int32_t i ; + for (i=0; iatomvm_event) ; + } + } + + return 1 ; } /** @@ -898,7 +909,7 @@ atomvmEventSend () uint32_t callbackInterruptWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) { - //WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; + WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; return WaitForSingleObject (patomvm->atomvm_int, INFINITE) == WAIT_OBJECT_0 ; } @@ -943,13 +954,12 @@ callbackScheduleIpi (PATOMVM patomvm, PATOMVM_CALLBACK callback) PATOMVM_CALLBACK_IPI callback_ipi = (PATOMVM_CALLBACK_IPI)callback ; uint32_t res = 0 ; - if (callback_ipi->target < ATOMVM_MAX_VM) { - if (g_vms[callback_ipi->target] != patomvm) { + if ((callback_ipi->target < ATOMVM_MAX_VM) && + (g_vms[callback_ipi->target] != patomvm) ) { - atomvmCtrlIntRequest ((HATOMVM)g_vms[callback_ipi->target], callback_ipi->isr) ; - res = 1 ; + atomvmCtrlIntRequest ((HATOMVM)g_vms[callback_ipi->target], callback_ipi->isr) ; + res = 1 ; - } } return res ; diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h index acc10d6..0b61570 100644 --- a/ports/atomvm/atomvm.h +++ b/ports/atomvm/atomvm.h @@ -64,7 +64,7 @@ #if defined _DEBUG || defined DEBUG -#define ATOMVM_ASSERT(x, msg) _ASSERT(x) +#define ATOMVM_ASSERT(x, msg) _ASSERT((x)) #else #define ATOMVM_ASSERT(x, msg) #endif diff --git a/ports/atomvm/test/main.c b/ports/atomvm/test/main.c index 9a7eb99..4bd4efb 100644 --- a/ports/atomvm/test/main.c +++ b/ports/atomvm/test/main.c @@ -11,7 +11,7 @@ extern uint32_t test_start (void) ; #endif -#define TEST_THREADS 51 +#define TEST_THREADS 47 #define TEST_STACK_BYTE_SIZE 0x10000 #define IDLE_STACK_BYTE_SIZE 0x10000 From 4a84c4cccfb60e972eb782468c0ece20a40ebe4a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 14 May 2012 23:57:07 +0200 Subject: [PATCH 08/28] added armv7 and cortex_m3 port --- ports/armv7/Makefile | 19 +++ ports/armv7/README | 38 +++++ ports/armv7/atomport.c | 170 ++++++++++++++++++++++ ports/armv7/atomport.h | 54 +++++++ ports/armv7/atomport_arm.asm | 213 ++++++++++++++++++++++++++++ ports/armv7/atomport_private.h | 37 +++++ ports/armv7/types.h | 63 +++++++++ ports/cortex_m3/Makefile | 19 +++ ports/cortex_m3/README | 31 +++++ ports/cortex_m3/atomport.c | 194 ++++++++++++++++++++++++++ ports/cortex_m3/atomport.h | 54 +++++++ ports/cortex_m3/atomport_arm.asm | 217 +++++++++++++++++++++++++++++ ports/cortex_m3/atomport_private.h | 38 +++++ ports/cortex_m3/types.h | 44 ++++++ 14 files changed, 1191 insertions(+) create mode 100644 ports/armv7/Makefile create mode 100644 ports/armv7/README create mode 100644 ports/armv7/atomport.c create mode 100644 ports/armv7/atomport.h create mode 100644 ports/armv7/atomport_arm.asm create mode 100644 ports/armv7/atomport_private.h create mode 100644 ports/armv7/types.h create mode 100644 ports/cortex_m3/Makefile create mode 100644 ports/cortex_m3/README create mode 100644 ports/cortex_m3/atomport.c create mode 100644 ports/cortex_m3/atomport.h create mode 100644 ports/cortex_m3/atomport_arm.asm create mode 100644 ports/cortex_m3/atomport_private.h create mode 100644 ports/cortex_m3/types.h diff --git a/ports/armv7/Makefile b/ports/armv7/Makefile new file mode 100644 index 0000000..87b9c17 --- /dev/null +++ b/ports/armv7/Makefile @@ -0,0 +1,19 @@ +ATOMTHREADS_PORT = $(COLOSSAL)/libraries/atomthreads/ports/armv7 +ATOMTHREADS_KERNEL = $(COLOSSAL)/libraries/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_arm.asm + + diff --git a/ports/armv7/README b/ports/armv7/README new file mode 100644 index 0000000..f3bc0fa --- /dev/null +++ b/ports/armv7/README @@ -0,0 +1,38 @@ +--------------------------------------------------------------------------- + +Library: Atomthreads ARMv7 Port +Author: Natie van Rooyen +License: BSD Revised + +--------------------------------------------------------------------------- + +ARM ARMv7 PORT + +This folder contains a port of the Atomthreads real time kernel for the +ARMv7 processor architecture. This port was only tested on a ARMv7 but +should work on other versions of the ARM processor as well. + +To Use: + +1. From your platforms IRQ vector branch to the "__irq_context_handler()". + All interrupts from where calls to Atomthreads will be made should do + this. The "__irq_context_handler()" will call a platform specific + function called "__context_preempt_handler()" to dispatch the interrupt. + +2. Implement the function "__context_preempt_handler()" + from where your platforms interrupt cotroller will be serviced and the + interrupt will be dispatched to a specic interrupt service routine. In + the case of your platforms timer tick interrupt call the "archTickHandler()" + implemented in "atomport.c". + +3. Initialize your platforms timer tick hardware to generata an OS timer tick + interrupt. + +4. Add code to acknowledge your timer hardware's interrupt in the + function "archTickHandler()" implemented in "atomport.c". This must + be done here because "atomIntExit()" might switch the context. + +5. After your platforms c-runtime initialization has completed, start + Atomthreads from your runtime's "main()" function. + +6. Include the port's Maefile in your platform build flow. \ No newline at end of file diff --git a/ports/armv7/atomport.c b/ports/armv7/atomport.c new file mode 100644 index 0000000..bac9c17 --- /dev/null +++ b/ports/armv7/atomport.c @@ -0,0 +1,170 @@ +/* + * 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_arm.asm + * + */ +extern void contextInit (void) ; +extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; +extern void contextStart (SYSCONTEXT* context) ; +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; +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 = ( uint32_t ) entry ; + stack_ptr--; + + *stack_ptr = ( uint32_t ) 0x00001111; /* R11 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00001010; /* R10 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000909; /* R9 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000808; /* R8 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000707; /* R7 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000606; /* R6 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000505; /* R5 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000404; /* R4 */ + +// #ifdef CONTEXT_THREAD_ID + stack_ptr--; + *stack_ptr = context_thread_id++ ; /* thread_id */ +// #endif + + 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) ; +} + + +/** + * \b archTimerTickIrqHandler + * + * System timer tick interrupt handler. + * + */ +void +archTickHandler (void) +{ + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* ack the interrupt if needed */ + /* ... */ + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); +} + + + diff --git a/ports/armv7/atomport.h b/ports/armv7/atomport.h new file mode 100644 index 0000000..2a6cf50 --- /dev/null +++ b/ports/armv7/atomport.h @@ -0,0 +1,54 @@ +/* + * 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 "arch/context.h" +#include "types.h" + +#define SYSTEM_TICKS_PER_SEC 1000 + + +/** + * Architecture-specific types. + * Most of these are available from types.h on this platform, which is + * included above. + */ +#define POINTER void * + + +/* 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__ */ diff --git a/ports/armv7/atomport_arm.asm b/ports/armv7/atomport_arm.asm new file mode 100644 index 0000000..9ba9664 --- /dev/null +++ b/ports/armv7/atomport_arm.asm @@ -0,0 +1,213 @@ +; +; 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. +; + + + PRESERVE8 {TRUE} + AREA UTILS, CODE, READONLY +;-- + EXPORT contextInit + EXPORT contextSwitch + EXPORT contextStart + EXPORT contextEnableInterrupts + EXPORT contextEnterCritical + EXPORT contextExitCritical + EXPORT __irq_context_handler + + + EXTERN archTickHandler + +;-- +ARM_SVC_MODE EQU 0xd3 +ARM_IRQ_MODE EQU 0xD2 +ARM_FIQ_MODE EQU 0xD1 +ARM_MODE_MASK EQU 0x1F +ARM_FIQ_MODE_BITS EQU 0x11 +ARM_IRQ_MODE_BITS EQU 0x12 +ARM_SVC_MODE_BITS EQU 0x13 + +CONTEXT_SWITCH_MODE EQU ARM_SVC_MODE + + ARM + +;-- +; \b contextInit +; +; Architecture-specific one time initialization. +; +; @return None +; +contextInit + + 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 + STMFD sp!, {r4 - r11, lr} ;- Save registers + + ;- IF :DEF:CONTEXT_THREAD_ID + MRC p15,0,r3,c13,c0,2 + STMFD sp!, {r3} + ;- ENDIF + + STR sp, [r0] ;- Save old stack pointer + LDR r1, [r1] + MOV sp, r1 ;- Load new stack pointer + + ISB + + ;- IF :DEF:CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15,0,r3,c13,c0,2 + ;- ENDIF + + LDMFD sp!, {r4 - r11, pc} ;- Load new registers + +;-- +; \b contextStart +; +; Architecture-specific context start routine. +; +; @param[in] [r0] -> Address where stack pointer is stored +; +; @return Does not return +; +contextStart + LDR r0, [r0] + MOV sp, r0 ;- Load new stack pointer + + ;- IF :DEF:CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15,0,r3,c13,c0,2 + ;- ENDIF + + LDMFD sp!, {r4 - r11, pc} ;- Load new registers + +;-- +; \b contextId +; +; Returns a unique ID for the context +; +; @return ID +; +contextId + MRC p15,0,r0,c13,c0,2 + BX lr + +;-- +; \b contextEnableInterrupts +; +; Enables interrupts on the processor +; +; @return None +; +contextEnableInterrupts + MRS r0,CPSR + MOV r1, #0x80 + 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,#0x80 + MSR CPSR_cxsf,r1 + BX lr + +;-- +; \b __irq_context_handler +; +; IRQ entry point +; +; @return None +; +__irq_context_handler + + MSR cpsr_c, #CONTEXT_SWITCH_MODE ;- Save current process context + STMFD sp!, {r0 - r3, ip, lr} + + MSR cpsr_c, #ARM_IRQ_MODE ;- Save lr_irq and spsr_irq in process stack + SUB lr,lr,#4 + MOV r1, lr + MRS r2, spsr + MSR cpsr_c, #CONTEXT_SWITCH_MODE + STMFD sp!, {r1, r2} + + BL __context_preempt_handler ;- Dispatch the interrupt to archTickHandler for the timer tick interrupt or a simular function for other interrupts which might call atomthread functions. + + LDMFD sp!, {r1, r2} ;- Restore lr_irq and spsr_irq from process stack + MSR cpsr_c, #ARM_IRQ_MODE + STMFD sp!, {r1} + MSR spsr_cxsf, r2 + + MSR cpsr_c, #CONTEXT_SWITCH_MODE ;- Restore process regs + LDMFD sp!, {r0 - r3, ip, lr} + + MSR cpsr_c, #ARM_IRQ_MODE ;- Exit from ISR + + LDMFD sp!, {pc}^ + + +;-- + END diff --git a/ports/armv7/atomport_private.h b/ports/armv7/atomport_private.h new file mode 100644 index 0000000..c0dfc6d --- /dev/null +++ b/ports/armv7/atomport_private.h @@ -0,0 +1,37 @@ +/* + * 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 archTickHandler (void) ; + +#endif /* __ATOM_PORT_PRIVATE_H__ */ diff --git a/ports/armv7/types.h b/ports/armv7/types.h new file mode 100644 index 0000000..0fd6feb --- /dev/null +++ b/ports/armv7/types.h @@ -0,0 +1,63 @@ +/* + * 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__ + +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 ; + +typedef volatile unsigned int REG_DWORD ;// Hardware register definition + +#define UWORD64 unsigned long long +#define UWORD32 unsigned int +#define UWORD16 unsigned short +#define UWORD8 unsigned char +#define WORD32 int +#define WORD16 short +#define WORD8 char + +#ifndef OFFSETOF +#define OFFSETOF(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) +#endif + +#ifndef INLINE +#define INLINE __inline +#endif + + +#endif /* __TYPES_H__ */ + diff --git a/ports/cortex_m3/Makefile b/ports/cortex_m3/Makefile new file mode 100644 index 0000000..fcf84e7 --- /dev/null +++ b/ports/cortex_m3/Makefile @@ -0,0 +1,19 @@ +ATOMTHREADS_PORT = ..... /libraries/atomthreads/ports/cortex_m3 +ATOMTHREADS_KERNEL = ..... /libraries/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_arm.asm + + diff --git a/ports/cortex_m3/README b/ports/cortex_m3/README new file mode 100644 index 0000000..6784187 --- /dev/null +++ b/ports/cortex_m3/README @@ -0,0 +1,31 @@ +--------------------------------------------------------------------------- + +Library: Atomthreads CortexM3 Port +Author: Natie van Rooyen +License: BSD Revised + +--------------------------------------------------------------------------- + +ARM CortexM3 PORT + +This folder contains a port of the Atomthreads real time kernel for the +ARM CortexM3 processor architecture. + +To Use: + +1. Install the "pendSV_Handler" and "tick_Handler" implemented in the file + "atomport_arm.asm" in your platforms interrupt vectors. + +2. Complete the function "archTickInit()" implemented in "atomport.c" to + initialize your platforms timer tick interrupt. If you use the build in + SysTick of the CortexM3 you also have to add code here to start it. + +3. If required, add code to acknowledge your timer hardware's interrupt in + the function "archTickHandler()" also implemented in "atomport.c". + +4. During your platform initialization call the function "archTickInit()" + exported from "atomport_private.h" to initialize the CortexM3 + "PendSV_Handler". + +5. After your platforms c-runtime initialization has completed, start + Atomthreads from your runtime's "main()" function. \ No newline at end of file diff --git a/ports/cortex_m3/atomport.c b/ports/cortex_m3/atomport.c new file mode 100644 index 0000000..1941305 --- /dev/null +++ b/ports/cortex_m3/atomport.c @@ -0,0 +1,194 @@ +/* + * 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_arm.asm + * + */ +extern void contextInit (void) ; +extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; +extern void contextStart (SYSCONTEXT* context) ; +extern uint32_t contextCreate (SYSCONTEXT* context, uint32_t stack_top, uint32_t entry) ; +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; +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--; + *stack_ptr = ((uint32_t)entry_point) | 1; //-- Entry Point (1 for THUMB mode) + 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) ; +} + + +/** + * \b archTimerTickIrqHandler + * + * System timer tick interrupt handler. + * + */ +void +archTickHandler (void) +{ + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* ack the interrupt if needed */ + /* ... */ + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); +} + +/** + * \b archTickInit + * + * System timer initialization. + * + */ +void +archTickInit (void) +{ + /* Initialize NVIC PendSV */ + contextInit () ; + + /* Initializa Timer Hardware */ + /* ... */ +} + + diff --git a/ports/cortex_m3/atomport.h b/ports/cortex_m3/atomport.h new file mode 100644 index 0000000..2a6cf50 --- /dev/null +++ b/ports/cortex_m3/atomport.h @@ -0,0 +1,54 @@ +/* + * 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 "arch/context.h" +#include "types.h" + +#define SYSTEM_TICKS_PER_SEC 1000 + + +/** + * Architecture-specific types. + * Most of these are available from types.h on this platform, which is + * included above. + */ +#define POINTER void * + + +/* 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__ */ diff --git a/ports/cortex_m3/atomport_arm.asm b/ports/cortex_m3/atomport_arm.asm new file mode 100644 index 0000000..2195db6 --- /dev/null +++ b/ports/cortex_m3/atomport_arm.asm @@ -0,0 +1,217 @@ +; +; 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. +; + + + PRESERVE8 {TRUE} + AREA UTILS, CODE, READONLY +;-- + EXPORT contextInit + EXPORT contextSwitch + EXPORT contextStart + EXPORT contextEnableInterrupts + EXPORT contextEnterCritical + EXPORT contextExitCritical + EXPORT pendSV_Handler + EXPORT tick_Handler + + EXTERN archTickHandler + +;-- +NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register +NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception +NVIC_PR_12_15_ADDR EQU 0xE000ED20 ; System Handlers 12-15 Priority Register Address +NVIC_PENDS_VPRIORITY EQU 0x00FF0000 ; PendSV priority is minimal (0xFF) + +;-- +; \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] + TEQ r1, #0 ; if contextSwitch is going to be called again before pend_sv + 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 + CPSIE i + BX lr + + +;-- +; \b contextExitCritical +; +; Exit critical section (restores interrupt posture) +; +; @param[in] r0 Interrupt Posture +; +; @return None +; +contextExitCritical + MSR PRIMASK, r0 + BX lr + + +;-- +; \b contextEnterCritical +; +; Enter critical section (disables interrupts) +; +; @return Current interrupt posture +; +contextEnterCritical + MRS r0, PRIMASK + CPSID i + BX lr + +;-- +; \b PendSV_Handler +; +; CortexM3 PendSV_Handler. Switch context to a new stack. +; +; @return None +; +pendSV_Handler + CPSID i ; Disable core int + + 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 + TEQ r0, r2 + BEQ pendsv_handler_exit + + TEQ 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 + CPSIE i ; Enable core int + + ORR lr, lr, #0x04 ; Ensure exception return uses process stack + BX lr ; Exit interrupt + + +;-- +; \b Tick_Handler +; +; System timer tick interrupt handler. +; +; @return None +; +tick_Handler + PUSH {r4-r11, lr} + cpsid I ; Disable core int + BL archTickHandler + cpsie I ; Enable core int + POP {r4-r11, pc} + + +;-- +context_new_stack_ptr DCD 0x00000000 +context_save_stack_ptr DCD 0x00000000 + +;-- + END diff --git a/ports/cortex_m3/atomport_private.h b/ports/cortex_m3/atomport_private.h new file mode 100644 index 0000000..0f4a004 --- /dev/null +++ b/ports/cortex_m3/atomport_private.h @@ -0,0 +1,38 @@ +/* + * 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 archTickHandler (void) ; +extern void archTickInit (void) ; + +#endif /* __ATOM_PORT_PRIVATE_H__ */ diff --git a/ports/cortex_m3/types.h b/ports/cortex_m3/types.h new file mode 100644 index 0000000..82317f7 --- /dev/null +++ b/ports/cortex_m3/types.h @@ -0,0 +1,44 @@ +/* + * 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__ + +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 /* __TYPES_H__ */ + From 5cc1e9831da2dcafb4d03df56cff54020f0035b6 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 15 May 2012 00:03:43 +0200 Subject: [PATCH 09/28] atomvm fix --- ports/atomvm/atomport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atomvm/atomport.c b/ports/atomvm/atomport.c index 7660040..a4de433 100644 --- a/ports/atomvm/atomport.c +++ b/ports/atomvm/atomport.c @@ -29,7 +29,7 @@ #include "atom.h" #include "atomport.h" #include "atomvm.h" - +#include "windows.h" /** Forward declarations */ static void thread_shell (void); From 37d6d553bfe114b758e59b34b8349ec696bc5238 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 15 May 2012 01:23:48 +0300 Subject: [PATCH 10/28] Update ports/atomvm/README.txt --- ports/atomvm/README.txt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ports/atomvm/README.txt b/ports/atomvm/README.txt index 77b327e..7a07533 100644 --- a/ports/atomvm/README.txt +++ b/ports/atomvm/README.txt @@ -33,8 +33,4 @@ 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. ---------------------------------------------------------------------------- -FINALLY - -Good luck, but most of all, have fun!! From 113f0a8690362b7ef56ad3d0293e27239796be5e Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Thu, 17 May 2012 23:42:58 +0200 Subject: [PATCH 11/28] Please enter the commit message for your changes. Lines starting --- ports/armv7/atomport.c | 18 +++++++++- ports/armv7/atomport_arm.asm | 64 ++++++++++++++++------------------ ports/armv7/atomport_private.h | 2 ++ ports/cortex_m3/atomport.c | 2 +- 4 files changed, 51 insertions(+), 35 deletions(-) diff --git a/ports/armv7/atomport.c b/ports/armv7/atomport.c index bac9c17..8fa0b2a 100644 --- a/ports/armv7/atomport.c +++ b/ports/armv7/atomport.c @@ -83,6 +83,7 @@ thread_shell (void) void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param) { + static uint32_t context_thread_id = 0 ; uint32_t * stack_ptr ; tcb_ptr->sp_save_ptr = stack_top; @@ -91,7 +92,7 @@ archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(u stack_ptr = (uint32_t *)stack_top; //-- Load stack pointer - *stack_ptr = ( uint32_t ) entry ; + *stack_ptr = ( uint32_t ) thread_shell ; stack_ptr--; *stack_ptr = ( uint32_t ) 0x00001111; /* R11 */ @@ -166,5 +167,20 @@ archTickHandler (void) atomIntExit(TRUE); } +/** + * \b archTickInit + * + * System timer initialization. + * + */ +void +archTickInit (void) +{ + /* Initialize NVIC PendSV */ + contextInit () ; + + /* Initializa Timer Hardware */ + /* ... */ +} diff --git a/ports/armv7/atomport_arm.asm b/ports/armv7/atomport_arm.asm index 9ba9664..db21f89 100644 --- a/ports/armv7/atomport_arm.asm +++ b/ports/armv7/atomport_arm.asm @@ -37,10 +37,9 @@ EXPORT contextEnableInterrupts EXPORT contextEnterCritical EXPORT contextExitCritical - EXPORT __irq_context_handler + EXPORT archIRQHandler - - EXTERN archTickHandler + EXTERN __context_preempt_handler [WEAK] ;-- ARM_SVC_MODE EQU 0xd3 @@ -49,9 +48,7 @@ ARM_FIQ_MODE EQU 0xD1 ARM_MODE_MASK EQU 0x1F ARM_FIQ_MODE_BITS EQU 0x11 ARM_IRQ_MODE_BITS EQU 0x12 -ARM_SVC_MODE_BITS EQU 0x13 -CONTEXT_SWITCH_MODE EQU ARM_SVC_MODE ARM @@ -85,19 +82,19 @@ contextSwitch STMFD sp!, {r4 - r11, lr} ;- Save registers ;- IF :DEF:CONTEXT_THREAD_ID - MRC p15,0,r3,c13,c0,2 + MRC p15, 0, r3, c13, c0, 2 STMFD sp!, {r3} ;- ENDIF STR sp, [r0] ;- Save old stack pointer - LDR r1, [r1] - MOV sp, r1 ;- Load new stack pointer + LDR r1, [r1] ;- Load new stack pointer + MOV sp, r1 ISB ;- IF :DEF:CONTEXT_THREAD_ID LDMFD sp!, {r3} - MCR p15,0,r3,c13,c0,2 + MCR p15, 0, r3, c13, c0, 2 ;- ENDIF LDMFD sp!, {r4 - r11, pc} ;- Load new registers @@ -113,11 +110,11 @@ contextSwitch ; contextStart LDR r0, [r0] - MOV sp, r0 ;- Load new stack pointer + MOV sp, r0 ;- Load new stack pointer ;- IF :DEF:CONTEXT_THREAD_ID LDMFD sp!, {r3} - MCR p15,0,r3,c13,c0,2 + MCR p15, 0, r3, c13, c0, 2 ;- ENDIF LDMFD sp!, {r4 - r11, pc} ;- Load new registers @@ -130,7 +127,7 @@ contextStart ; @return ID ; contextId - MRC p15,0,r0,c13,c0,2 + MRC p15, 0, r0, c13, c0, 2 BX lr ;-- @@ -141,12 +138,11 @@ contextId ; @return None ; contextEnableInterrupts - MRS r0,CPSR + MRS r0, CPSR MOV r1, #0x80 - BIC r0,r0,r1 - MSR CPSR_c,r0 - BX lr - + BIC r0, r0, r1 + MSR CPSR_c, r0 + BX lr ;-- ; \b contextExitCritical @@ -158,9 +154,8 @@ contextEnableInterrupts ; @return None ; contextExitCritical - MSR CPSR_cxsf,r0 - BX lr - + MSR CPSR_cxsf, r0 + BX lr ;-- ; \b contextEnterCritical @@ -170,42 +165,45 @@ contextExitCritical ; @return Current interrupt posture ; contextEnterCritical - MRS r0,CPSR - ORR r1,r0,#0x80 - MSR CPSR_cxsf,r1 + MRS r0, CPSR + ORR r1, r0, #0x80 + MSR CPSR_cxsf, r1 BX lr ;-- -; \b __irq_context_handler +; \b archIRQHandler ; -; IRQ entry point +; IRQ entry point. +; +; Save the process/thread context onto its own stackm before calling __context_preempt_handler (). +; __context_preempt_handler() might switch stacks. On return the same context is poped from the +; stack and control is returned to the process. ; ; @return None ; -__irq_context_handler +archIRQHandler - MSR cpsr_c, #CONTEXT_SWITCH_MODE ;- Save current process context + MSR cpsr_c, #ARM_SVC_MODE ;- Save current process context in process stack STMFD sp!, {r0 - r3, ip, lr} MSR cpsr_c, #ARM_IRQ_MODE ;- Save lr_irq and spsr_irq in process stack - SUB lr,lr,#4 + SUB lr, lr, #4 MOV r1, lr MRS r2, spsr - MSR cpsr_c, #CONTEXT_SWITCH_MODE + MSR cpsr_c, #ARM_SVC_MODE STMFD sp!, {r1, r2} - BL __context_preempt_handler ;- Dispatch the interrupt to archTickHandler for the timer tick interrupt or a simular function for other interrupts which might call atomthread functions. + BL __context_preempt_handler ;- Dispatch the interrupt to archTickHandler for the timer tick interrupt or a simular function for other interrupts which might call atomthread functions. LDMFD sp!, {r1, r2} ;- Restore lr_irq and spsr_irq from process stack MSR cpsr_c, #ARM_IRQ_MODE STMFD sp!, {r1} MSR spsr_cxsf, r2 - MSR cpsr_c, #CONTEXT_SWITCH_MODE ;- Restore process regs + MSR cpsr_c, #ARM_SVC_MODE ;- Restore process regs LDMFD sp!, {r0 - r3, ip, lr} - MSR cpsr_c, #ARM_IRQ_MODE ;- Exit from ISR - + MSR cpsr_c, #ARM_IRQ_MODE ;- Exit from IRQ LDMFD sp!, {pc}^ diff --git a/ports/armv7/atomport_private.h b/ports/armv7/atomport_private.h index c0dfc6d..87a032f 100644 --- a/ports/armv7/atomport_private.h +++ b/ports/armv7/atomport_private.h @@ -33,5 +33,7 @@ /* Function prototypes */ extern void archTickHandler (void) ; +extern void archTickInit (void) ; +extern void archIRQHandler (void) ; #endif /* __ATOM_PORT_PRIVATE_H__ */ diff --git a/ports/cortex_m3/atomport.c b/ports/cortex_m3/atomport.c index 1941305..1f659c3 100644 --- a/ports/cortex_m3/atomport.c +++ b/ports/cortex_m3/atomport.c @@ -94,7 +94,7 @@ archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(u *stack_ptr = 0x01000000L; //-- xPSR stack_ptr--; - *stack_ptr = ((uint32_t)entry_point) | 1; //-- Entry Point (1 for THUMB mode) + *stack_ptr = ((uint32_t)thread_shell) | 1; //-- Entry Point (1 for THUMB mode) stack_ptr--; *stack_ptr = ((uint32_t)/*exit*/0) | 1; //-- R14 (LR) (1 for THUMB mode) stack_ptr--; From 12dbe5ebe94be60d1672ffd5299ee488f484b146 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Thu, 17 May 2012 23:52:29 +0200 Subject: [PATCH 12/28] tabs to spaces --- ports/armv7/atomport_arm.asm | 106 +++++++++++++++++------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/ports/armv7/atomport_arm.asm b/ports/armv7/atomport_arm.asm index db21f89..496e779 100644 --- a/ports/armv7/atomport_arm.asm +++ b/ports/armv7/atomport_arm.asm @@ -61,7 +61,7 @@ ARM_IRQ_MODE_BITS EQU 0x12 ; contextInit - BX lr + BX lr ;-- ; \b contextSwitch @@ -79,25 +79,25 @@ contextInit ; @return None ; contextSwitch - STMFD sp!, {r4 - r11, lr} ;- Save registers + STMFD sp!, {r4 - r11, lr} ;- Save registers - ;- IF :DEF:CONTEXT_THREAD_ID - MRC p15, 0, r3, c13, c0, 2 - STMFD sp!, {r3} - ;- ENDIF + ;- IF :DEF:CONTEXT_THREAD_ID + MRC p15, 0, r3, c13, c0, 2 + STMFD sp!, {r3} + ;- ENDIF - STR sp, [r0] ;- Save old stack pointer - LDR r1, [r1] ;- Load new stack pointer - MOV sp, r1 + STR sp, [r0] ;- Save old stack pointer + LDR r1, [r1] ;- Load new stack pointer + MOV sp, r1 - ISB + ISB - ;- IF :DEF:CONTEXT_THREAD_ID - LDMFD sp!, {r3} - MCR p15, 0, r3, c13, c0, 2 - ;- ENDIF + ;- IF :DEF:CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15, 0, r3, c13, c0, 2 + ;- ENDIF - LDMFD sp!, {r4 - r11, pc} ;- Load new registers + LDMFD sp!, {r4 - r11, pc} ;- Load new registers ;-- ; \b contextStart @@ -109,15 +109,15 @@ contextSwitch ; @return Does not return ; contextStart - LDR r0, [r0] - MOV sp, r0 ;- Load new stack pointer + LDR r0, [r0] + MOV sp, r0 ;- Load new stack pointer - ;- IF :DEF:CONTEXT_THREAD_ID - LDMFD sp!, {r3} - MCR p15, 0, r3, c13, c0, 2 - ;- ENDIF + ;- IF :DEF:CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15, 0, r3, c13, c0, 2 + ;- ENDIF - LDMFD sp!, {r4 - r11, pc} ;- Load new registers + LDMFD sp!, {r4 - r11, pc} ;- Load new registers ;-- ; \b contextId @@ -127,8 +127,8 @@ contextStart ; @return ID ; contextId - MRC p15, 0, r0, c13, c0, 2 - BX lr + MRC p15, 0, r0, c13, c0, 2 + BX lr ;-- ; \b contextEnableInterrupts @@ -138,11 +138,11 @@ contextId ; @return None ; contextEnableInterrupts - MRS r0, CPSR - MOV r1, #0x80 - BIC r0, r0, r1 - MSR CPSR_c, r0 - BX lr + MRS r0, CPSR + MOV r1, #0x80 + BIC r0, r0, r1 + MSR CPSR_c, r0 + BX lr ;-- ; \b contextExitCritical @@ -154,8 +154,8 @@ contextEnableInterrupts ; @return None ; contextExitCritical - MSR CPSR_cxsf, r0 - BX lr + MSR CPSR_cxsf, r0 + BX lr ;-- ; \b contextEnterCritical @@ -165,10 +165,10 @@ contextExitCritical ; @return Current interrupt posture ; contextEnterCritical - MRS r0, CPSR - ORR r1, r0, #0x80 - MSR CPSR_cxsf, r1 - BX lr + MRS r0, CPSR + ORR r1, r0, #0x80 + MSR CPSR_cxsf, r1 + BX lr ;-- ; \b archIRQHandler @@ -183,28 +183,28 @@ contextEnterCritical ; archIRQHandler - MSR cpsr_c, #ARM_SVC_MODE ;- Save current process context in process stack - STMFD sp!, {r0 - r3, ip, lr} + MSR cpsr_c, #ARM_SVC_MODE ;- Save current process context in process stack + STMFD sp!, {r0 - r3, ip, lr} - MSR cpsr_c, #ARM_IRQ_MODE ;- Save lr_irq and spsr_irq in process stack - SUB lr, lr, #4 - MOV r1, lr - MRS r2, spsr - MSR cpsr_c, #ARM_SVC_MODE - STMFD sp!, {r1, r2} - - BL __context_preempt_handler ;- Dispatch the interrupt to archTickHandler for the timer tick interrupt or a simular function for other interrupts which might call atomthread functions. + MSR cpsr_c, #ARM_IRQ_MODE ;- Save lr_irq and spsr_irq in process stack + SUB lr, lr, #4 + MOV r1, lr + MRS r2, spsr + MSR cpsr_c, #ARM_SVC_MODE + STMFD sp!, {r1, r2} + + BL __context_preempt_handler ;- Dispatch the interrupt to archTickHandler for the timer tick interrupt or a simular function for other interrupts which might call atomthread functions. - LDMFD sp!, {r1, r2} ;- Restore lr_irq and spsr_irq from process stack - MSR cpsr_c, #ARM_IRQ_MODE - STMFD sp!, {r1} - MSR spsr_cxsf, r2 + LDMFD sp!, {r1, r2} ;- Restore lr_irq and spsr_irq from process stack + MSR cpsr_c, #ARM_IRQ_MODE + STMFD sp!, {r1} + MSR spsr_cxsf, r2 - MSR cpsr_c, #ARM_SVC_MODE ;- Restore process regs - LDMFD sp!, {r0 - r3, ip, lr} + MSR cpsr_c, #ARM_SVC_MODE ;- Restore process regs + LDMFD sp!, {r0 - r3, ip, lr} - MSR cpsr_c, #ARM_IRQ_MODE ;- Exit from IRQ - LDMFD sp!, {pc}^ + MSR cpsr_c, #ARM_IRQ_MODE ;- Exit from IRQ + LDMFD sp!, {pc}^ ;-- From a2646ec6953feb7905e1996284909e0702140be2 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 22 May 2012 00:22:09 +0200 Subject: [PATCH 13/28] updates --- ports/armv7/Makefile | 4 ++-- ports/armv7/README | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ports/armv7/Makefile b/ports/armv7/Makefile index 87b9c17..3a15998 100644 --- a/ports/armv7/Makefile +++ b/ports/armv7/Makefile @@ -1,5 +1,5 @@ -ATOMTHREADS_PORT = $(COLOSSAL)/libraries/atomthreads/ports/armv7 -ATOMTHREADS_KERNEL = $(COLOSSAL)/libraries/atomthreads/kernel +ATOMTHREADS_PORT = .../libraries/atomthreads/ports/armv7 +ATOMTHREADS_KERNEL = .../libraries/atomthreads/kernel INCLUDES := $(INCLUDES) \ -I$(ATOMTHREADS_KERNEL) \ diff --git a/ports/armv7/README b/ports/armv7/README index f3bc0fa..fae939d 100644 --- a/ports/armv7/README +++ b/ports/armv7/README @@ -20,12 +20,12 @@ To Use: function called "__context_preempt_handler()" to dispatch the interrupt. 2. Implement the function "__context_preempt_handler()" - from where your platforms interrupt cotroller will be serviced and the - interrupt will be dispatched to a specic interrupt service routine. In + from where your platforms interrupt controller will be serviced and the + interrupt will be dispatched to a specific interrupt service routine. In the case of your platforms timer tick interrupt call the "archTickHandler()" implemented in "atomport.c". -3. Initialize your platforms timer tick hardware to generata an OS timer tick +3. Initialize your platforms timer tick hardware to generate an OS timer tick interrupt. 4. Add code to acknowledge your timer hardware's interrupt in the @@ -35,4 +35,4 @@ To Use: 5. After your platforms c-runtime initialization has completed, start Atomthreads from your runtime's "main()" function. -6. Include the port's Maefile in your platform build flow. \ No newline at end of file +6. Include the port's Makefile in your platform build flow. \ No newline at end of file From dfb831fa6315aa4a78e9467e98397cb60643b21c Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Mon, 17 Sep 2012 13:02:09 +0200 Subject: [PATCH 14/28] =?UTF-8?q?Added=20=E2=80=9Carm=E2=80=9D=20port=20.?= =?UTF-8?q?=20Added=20platforms=20directory.=20Added=20QEMU=20qemu=5Finteg?= =?UTF-8?q?ratorcp=20platform=20in=20platforms.=20Modified=20test=20cases?= =?UTF-8?q?=20to=20make=20stack=20top=20DWORD=20aligned.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- platforms/qemu_integratorcp/Makefile | 91 +++++++ .../qemu_integratorcp/atomthreads_test.out | 75 ++++++ platforms/qemu_integratorcp/boot.elf | Bin 0 -> 419255 bytes platforms/qemu_integratorcp/main.c | 85 +++++++ platforms/qemu_integratorcp/modules.c | 115 +++++++++ platforms/qemu_integratorcp/modules.h | 124 ++++++++++ platforms/qemu_integratorcp/startup.s | 55 +++++ platforms/qemu_integratorcp/system.ld | 94 ++++++++ platforms/rules.mk | 60 +++++ ports/{armv7 => arm}/Makefile | 10 +- ports/{armv7 => arm}/README | 0 ports/arm/atomport-tests.h | 50 ++++ ports/{armv7 => arm}/atomport.c | 11 +- ports/{armv7 => arm}/atomport.h | 13 +- ports/arm/atomport.o | Bin 0 -> 5436 bytes ports/arm/atomport_asm.o | Bin 0 -> 2220 bytes ports/{armv7 => arm}/atomport_private.h | 0 ports/arm/atomport_s.S | 227 ++++++++++++++++++ ports/{armv7 => arm}/types.h | 2 +- ports/armv7/atomport_arm.asm | 211 ---------------- tests/atomtests.h | 2 +- tests/kern1.c | 6 +- tests/kern3.c | 4 +- tests/kern4.c | 8 +- tests/mutex1.c | 4 +- tests/mutex2.c | 2 +- tests/mutex3.c | 8 +- tests/mutex4.c | 8 +- tests/mutex5.c | 2 +- tests/mutex6.c | 2 +- tests/mutex7.c | 2 +- tests/mutex8.c | 6 +- tests/mutex9.c | 2 +- tests/queue2.c | 4 +- tests/queue3.c | 4 +- tests/queue5.c | 8 +- tests/queue6.c | 2 +- tests/queue7.c | 6 +- tests/queue9.c | 8 +- tests/sem1.c | 4 +- tests/sem3.c | 8 +- tests/sem4.c | 8 +- tests/sem5.c | 2 +- tests/sem6.c | 2 +- tests/sem7.c | 2 +- tests/sem8.c | 6 +- tests/sem9.c | 6 +- tests/timer2.c | 6 +- 48 files changed, 1062 insertions(+), 293 deletions(-) create mode 100644 platforms/qemu_integratorcp/Makefile create mode 100644 platforms/qemu_integratorcp/atomthreads_test.out create mode 100644 platforms/qemu_integratorcp/boot.elf create mode 100644 platforms/qemu_integratorcp/main.c create mode 100644 platforms/qemu_integratorcp/modules.c create mode 100644 platforms/qemu_integratorcp/modules.h create mode 100644 platforms/qemu_integratorcp/startup.s create mode 100644 platforms/qemu_integratorcp/system.ld create mode 100644 platforms/rules.mk rename ports/{armv7 => arm}/Makefile (68%) rename ports/{armv7 => arm}/README (100%) create mode 100644 ports/arm/atomport-tests.h rename ports/{armv7 => arm}/atomport.c (94%) rename ports/{armv7 => arm}/atomport.h (90%) create mode 100644 ports/arm/atomport.o create mode 100644 ports/arm/atomport_asm.o rename ports/{armv7 => arm}/atomport_private.h (100%) create mode 100644 ports/arm/atomport_s.S rename ports/{armv7 => arm}/types.h (96%) delete mode 100644 ports/armv7/atomport_arm.asm diff --git a/platforms/qemu_integratorcp/Makefile b/platforms/qemu_integratorcp/Makefile new file mode 100644 index 0000000..551529f --- /dev/null +++ b/platforms/qemu_integratorcp/Makefile @@ -0,0 +1,91 @@ +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=arm926ej-s -ffreestanding +AFLAGS := $(CFLAGS) -Wall -g -c -mcpu=arm926ej-s -ffreestanding +LFLAGS := $(LFLAGS) -Wall -mcpu=arm926ej-s -Wl,-Map=system.map,--verbose -Tsystem.ld + +CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' +ADEFS := $(ADEFS) + +LLIBS := $(LLIBS) + + +SRCS := $(SRCS) \ + modules.c \ + main.c \ + $(ATOMTHREADS)/tests/$(TEST_NAME).c + +ASMS := $(ASMS) \ + startup.S \ + +INCLUDES := $(INCLUDES) \ + -I$(ATOMTHREADS) + +include $(ATOMTHREADS)/ports/arm/Makefile + +OBJS = $(SRCS:.c=.o) $(ASMS:.S=.o) + +include ../rules.mk + + +run_test: clean all + echo "START TEST $(TEST_NAME)" + qemu-system-arm -M integratorcp -kernel boot.elf -semihosting | tee 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=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=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" + +run_last: + qemu-system-arm -M integratorcp -kernel boot.elf -monitor stdio -semihosting + diff --git a/platforms/qemu_integratorcp/atomthreads_test.out b/platforms/qemu_integratorcp/atomthreads_test.out new file mode 100644 index 0000000..1c4897d --- /dev/null +++ b/platforms/qemu_integratorcp/atomthreads_test.out @@ -0,0 +1,75 @@ +Starting atomthreads test suite +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex1... mutex1 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex2... mutex2 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex3... mutex3 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex4... mutex4 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex5... mutex5 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex6... mutex6 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex7... mutex7 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex8... mutex8 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting mutex9... mutex9 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting kern1... kern1 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting kern2... kern2 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting kern3... kern3 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting kern4... kern4 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting timer1... timer1 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting timer2... timer2 FAIL +VNC server running on `127.0.0.1:5900' +atomthreads starting timer3... timer3 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting timer5... timer5 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting timer6... timer6 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting timer7... timer7 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue1... queue1 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue2... queue2 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue3... queue3 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue4... queue4 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue5... queue5 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue6... queue6 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue7... queue7 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue8... queue8 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting queue9... queue9 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem1... sem1 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem2... sem2 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem3... sem3 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem4... sem4 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem5... sem5 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem6... sem6 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem7... sem7 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem8... sem8 PASS +VNC server running on `127.0.0.1:5900' +atomthreads starting sem9... sem9 PASS diff --git a/platforms/qemu_integratorcp/boot.elf b/platforms/qemu_integratorcp/boot.elf new file mode 100644 index 0000000000000000000000000000000000000000..c0f64680228255f4d2967105bc8793e9683e258a GIT binary patch literal 419255 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 z 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 +#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) +{ + uint32_t failures ; + + printf ("atomthreads starting %s... ", ATOMTHREADS_TEST) ; + + atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; + atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); + atomOSStart() ; + + return 0 ; +} diff --git a/platforms/qemu_integratorcp/modules.c b/platforms/qemu_integratorcp/modules.c new file mode 100644 index 0000000..c611d68 --- /dev/null +++ b/platforms/qemu_integratorcp/modules.c @@ -0,0 +1,115 @@ +/* + * 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 +#include +#include "atomport_private.h" +#include "atom.h" +#include "atomport.h" +#include "types.h" + +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 ; + +/** + * \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) ; + CRITICAL_END() ; + + printf (msg) ; +} + +/** + * \b low_level_init + * + * Initializes the PIC and start the system timer tick intrerupt. + * + */ +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 ; + + board_timer_0->LOAD = 0x2000 ; + board_timer_0->BGLOAD = 0x2000 ; + board_timer_0->CONTROL = ICP_TIMER_CONTROL_ENABLE | + ICP_TIMER_CONTROL_MODE | + ICP_TIMER_CONTROL_IE | + /*ICP_TIMER_CONTROL_PRESCALE_256 |*/ + ICP_TIMER_CONTROL_TIMER_SIZE ; + + return 0 ; +} + + +/** + * \b __context_preempt_handler + * + * System timer tic interupt handler. + * + */ +void +__context_preempt_handler (void) +{ + unsigned int status = board_pic->IRQ_STATUS ; + + if (status | ICP_PIC_IRQ_TIMERINT0) { + + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* ack the interrupt */ + board_timer_0->INTCLR = 0x1 ; + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); + + } + + +} + diff --git a/platforms/qemu_integratorcp/modules.h b/platforms/qemu_integratorcp/modules.h new file mode 100644 index 0000000..38aa37f --- /dev/null +++ b/platforms/qemu_integratorcp/modules.h @@ -0,0 +1,124 @@ +/* + * 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__ + +#include "atomport.h" + +extern void dbg_format_msg (char *format, ...) ; + +#define DBG_MESSAGE(fmt_str) { dbg_format_msg fmt_str ; } + + +typedef volatile unsigned int REG_DWORD ;// Hardware register definition +typedef volatile unsigned short REG_WORD ; +typedef volatile unsigned char REG_BYTE ; + + +// ***************************************************************************** +// INTEGRATORCP TIMER +// ***************************************************************************** +typedef struct ICP_TIMER_S { + // offset read/write word size reset Description + REG_DWORD LOAD ; // 0x0000 Read/write 32 0x00000000 Load value for Timer + REG_DWORD VALUE ; // 0x0004 Read 32 0xFFFFFFFF The current value for Timer + REG_BYTE CONTROL ; // 0x0008 Read/write 8 0x20 Timer control register + REG_DWORD INTCLR ; // 0x000C Write - - Timer interrupt clear + REG_DWORD RIS ; // 0x0010 Read 1 0x0 Timer raw interrupt status + REG_DWORD MIS ; // 0x0014 Read 1 0x0 Timer masked interrupt status + REG_DWORD 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 + REG_DWORD IRQ_STATUS ; // 0x0000 Read 22 IRQ gated interrupt status + REG_DWORD IRQ_RAWSTAT ; // 0x0004 Read 22 IRQ raw interrupt status + REG_DWORD IRQ_ENABLESET ; // 0x0008 Read/write 22 IRQ enable set + REG_DWORD IRQ_ENABLECLR ; // 0x000C Write 22 IRQ enable clear + REG_DWORD INT_SOFTSET ; // 0x0010 Read/write 16 Software interrupt set + REG_DWORD INT_SOFTCLR ; // 0x0014 Write 16 Software interrupt clear + REG_DWORD RESERVED[2] ; // 0x0018 + REG_DWORD FIQ_STATUS ; // 0x0020 Read 22 FIQ gated interrupt status + REG_DWORD FIQ_RAWSTAT ; // 0x0024 Read 22 FIQ raw interrupt status + REG_DWORD FIQ_ENABLESET ; // 0x0028 Read/write 22 FIQ enable set + REG_DWORD 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 -------- + + + + +#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 ; + + + +extern int low_level_init (void) ; + +#endif /* __MODULES_H__ */ diff --git a/platforms/qemu_integratorcp/startup.s b/platforms/qemu_integratorcp/startup.s new file mode 100644 index 0000000..dc4a167 --- /dev/null +++ b/platforms/qemu_integratorcp/startup.s @@ -0,0 +1,55 @@ +.section .vectors, "x" + +.global __interrupt_vector_table +.global __irq_stack_top__ +.global __fiq_stack_top__ +.global __svc_stack_top__ + +.global bsp_ints_enable +.global bsp_ints_disable +.global bsp_ints_restore + + +.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 . /* Undefined */ + B . /* SWI */ + B . /* Prefetch Abort */ + B . /* Data Abort */ + B . /* reserved */ + B IRQ_Handler /* IRQ */ + B . /* 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 + diff --git a/platforms/qemu_integratorcp/system.ld b/platforms/qemu_integratorcp/system.ld new file mode 100644 index 0000000..4d4fc2c --- /dev/null +++ b/platforms/qemu_integratorcp/system.ld @@ -0,0 +1,94 @@ + +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) + *(.eh_*) + } >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 + + + /*DISCARD : + { + *(.eh_*) + }*/ +} + +_end = .; +PROVIDE(end = .); \ No newline at end of file diff --git a/platforms/rules.mk b/platforms/rules.mk new file mode 100644 index 0000000..7f0f767 --- /dev/null +++ b/platforms/rules.mk @@ -0,0 +1,60 @@ +# +# 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 + +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) + \ No newline at end of file diff --git a/ports/armv7/Makefile b/ports/arm/Makefile similarity index 68% rename from ports/armv7/Makefile rename to ports/arm/Makefile index 3a15998..9c33741 100644 --- a/ports/armv7/Makefile +++ b/ports/arm/Makefile @@ -1,5 +1,5 @@ -ATOMTHREADS_PORT = .../libraries/atomthreads/ports/armv7 -ATOMTHREADS_KERNEL = .../libraries/atomthreads/kernel +ATOMTHREADS_PORT = $(ATOMTHREADS)/ports/arm +ATOMTHREADS_KERNEL = $(ATOMTHREADS)/kernel INCLUDES := $(INCLUDES) \ -I$(ATOMTHREADS_KERNEL) \ @@ -14,6 +14,6 @@ SRCS := $(SRCS) \ $(ATOMTHREADS_PORT)/atomport.c ASMS := $(ASMS) \ - $(ATOMTHREADS_PORT)/atomport_arm.asm - - + $(ATOMTHREADS_PORT)/atomport_s.S + + diff --git a/ports/armv7/README b/ports/arm/README similarity index 100% rename from ports/armv7/README rename to ports/arm/README diff --git a/ports/arm/atomport-tests.h b/ports/arm/atomport-tests.h new file mode 100644 index 0000000..cfb909a --- /dev/null +++ b/ports/arm/atomport-tests.h @@ -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__ */ diff --git a/ports/armv7/atomport.c b/ports/arm/atomport.c similarity index 94% rename from ports/armv7/atomport.c rename to ports/arm/atomport.c index 8fa0b2a..da96930 100644 --- a/ports/armv7/atomport.c +++ b/ports/arm/atomport.c @@ -33,14 +33,14 @@ /* * * - * Functions defined in atomport_arm.asm + * Functions defined in atomport_s.asm * */ +typedef void * SYSCONTEXT ; + extern void contextInit (void) ; extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; extern void contextStart (SYSCONTEXT* context) ; -extern uint32_t contextEnterCritical (void) ; -extern void contextExitCritical (uint32_t posture) ; extern void contextEnableInterrupts (void) ; /** @@ -83,7 +83,6 @@ thread_shell (void) void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param) { - static uint32_t context_thread_id = 0 ; uint32_t * stack_ptr ; tcb_ptr->sp_save_ptr = stack_top; @@ -111,10 +110,10 @@ archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(u stack_ptr--; *stack_ptr = ( uint32_t ) 0x00000404; /* R4 */ -// #ifdef CONTEXT_THREAD_ID +#ifdef CONTEXT_THREAD_ID stack_ptr--; *stack_ptr = context_thread_id++ ; /* thread_id */ -// #endif +#endif tcb_ptr->sp_save_ptr = stack_ptr ; } diff --git a/ports/armv7/atomport.h b/ports/arm/atomport.h similarity index 90% rename from ports/armv7/atomport.h rename to ports/arm/atomport.h index 2a6cf50..39bd0c0 100644 --- a/ports/armv7/atomport.h +++ b/ports/arm/atomport.h @@ -30,10 +30,9 @@ #ifndef __ATOM_PORT_H__ #define __ATOM_PORT_H__ -#include "arch/context.h" #include "types.h" -#define SYSTEM_TICKS_PER_SEC 1000 +#define SYSTEM_TICKS_PER_SEC 100 /** @@ -43,12 +42,18 @@ */ #define POINTER void * +/* * + * + * Functions defined in atomport_arm.asm + * + */ +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__ */ diff --git a/ports/arm/atomport.o b/ports/arm/atomport.o new file mode 100644 index 0000000000000000000000000000000000000000..31708720d585be2ba9192034494e6518dee87692 GIT binary patch literal 5436 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 d&fvQFZ$kzR$#^{$Kx~he*tXjaQy%P literal 0 HcmV?d00001 diff --git a/ports/armv7/atomport_private.h b/ports/arm/atomport_private.h similarity index 100% rename from ports/armv7/atomport_private.h rename to ports/arm/atomport_private.h diff --git a/ports/arm/atomport_s.S b/ports/arm/atomport_s.S new file mode 100644 index 0000000..1227c52 --- /dev/null +++ b/ports/arm/atomport_s.S @@ -0,0 +1,227 @@ +/* + 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 contextId +.global contextStart +.global contextSwitch +.global contextInit + + +.global __context_preempt_handler + +/**/ +.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 contextInit + * + * Architecture-specific one time initialization. + * + * @return None + */ +contextInit: + + 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: + STMFD sp!, {r4 - r11, lr} /* Save registers */ + +#ifdef CONTEXT_THREAD_ID + MRC p15, 0, r3, c13, c0, 2 + STMFD sp!, {r3} +#endif + + STR sp, [r0] /* Save old stack pointer */ + LDR r1, [r1] /* Load new stack pointer */ + MOV sp, r1 + +#ifdef CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15, 0, r3, c13, c0, 2 +#endif + + LDMFD sp!, {r4 - r11, pc} /* Load new registers */ + +/** + * \b contextStart + * + * Architecture-specific context start routine. + * + * @param[in] [r0] -> Address where stack pointer is stored + * + * @return Does not return + */ +contextStart: + LDR r0, [r0] + MOV sp, r0 /* Load new stack pointer */ + +#ifdef CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15, 0, r3, c13, c0, 2 +#endif + + LDMFD sp!, {r4 - r11, pc} /* Load new registers */ + +/** + * \b contextId + * + * Returns a unique ID for the context + * + * @return ID + */ +contextId: +#ifdef CONTEXT_THREAD_ID + MRC p15, 0, r0, c13, c0, 2 +#else + MOV r0, #0 +#endif + BX lr + +/** + * \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 stackm before calling __context_preempt_handler (). + * __context_preempt_handler() might switch stacks. On return the same context is poped 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 __context_preempt_handler /* Dispatch the interrupt to archTickHandler for + the timer tick interrupt or a simular function + for other interrupts which might call atomthread + functions. */ + + 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}^ + + + diff --git a/ports/armv7/types.h b/ports/arm/types.h similarity index 96% rename from ports/armv7/types.h rename to ports/arm/types.h index 0fd6feb..d383d84 100644 --- a/ports/armv7/types.h +++ b/ports/arm/types.h @@ -40,7 +40,7 @@ typedef int int32_t ; typedef short int16_t ; typedef char int8_t ; -typedef volatile unsigned int REG_DWORD ;// Hardware register definition +// typedef volatile unsigned int REG_DWORD ;// Hardware register definition #define UWORD64 unsigned long long #define UWORD32 unsigned int diff --git a/ports/armv7/atomport_arm.asm b/ports/armv7/atomport_arm.asm deleted file mode 100644 index 496e779..0000000 --- a/ports/armv7/atomport_arm.asm +++ /dev/null @@ -1,211 +0,0 @@ -; -; 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. -; - - - PRESERVE8 {TRUE} - AREA UTILS, CODE, READONLY -;-- - EXPORT contextInit - EXPORT contextSwitch - EXPORT contextStart - EXPORT contextEnableInterrupts - EXPORT contextEnterCritical - EXPORT contextExitCritical - EXPORT archIRQHandler - - EXTERN __context_preempt_handler [WEAK] - -;-- -ARM_SVC_MODE EQU 0xd3 -ARM_IRQ_MODE EQU 0xD2 -ARM_FIQ_MODE EQU 0xD1 -ARM_MODE_MASK EQU 0x1F -ARM_FIQ_MODE_BITS EQU 0x11 -ARM_IRQ_MODE_BITS EQU 0x12 - - - ARM - -;-- -; \b contextInit -; -; Architecture-specific one time initialization. -; -; @return None -; -contextInit - - 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 - STMFD sp!, {r4 - r11, lr} ;- Save registers - - ;- IF :DEF:CONTEXT_THREAD_ID - MRC p15, 0, r3, c13, c0, 2 - STMFD sp!, {r3} - ;- ENDIF - - STR sp, [r0] ;- Save old stack pointer - LDR r1, [r1] ;- Load new stack pointer - MOV sp, r1 - - ISB - - ;- IF :DEF:CONTEXT_THREAD_ID - LDMFD sp!, {r3} - MCR p15, 0, r3, c13, c0, 2 - ;- ENDIF - - LDMFD sp!, {r4 - r11, pc} ;- Load new registers - -;-- -; \b contextStart -; -; Architecture-specific context start routine. -; -; @param[in] [r0] -> Address where stack pointer is stored -; -; @return Does not return -; -contextStart - LDR r0, [r0] - MOV sp, r0 ;- Load new stack pointer - - ;- IF :DEF:CONTEXT_THREAD_ID - LDMFD sp!, {r3} - MCR p15, 0, r3, c13, c0, 2 - ;- ENDIF - - LDMFD sp!, {r4 - r11, pc} ;- Load new registers - -;-- -; \b contextId -; -; Returns a unique ID for the context -; -; @return ID -; -contextId - MRC p15, 0, r0, c13, c0, 2 - BX lr - -;-- -; \b contextEnableInterrupts -; -; Enables interrupts on the processor -; -; @return None -; -contextEnableInterrupts - MRS r0, CPSR - MOV r1, #0x80 - 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, #0x80 - MSR CPSR_cxsf, r1 - BX lr - -;-- -; \b archIRQHandler -; -; IRQ entry point. -; -; Save the process/thread context onto its own stackm before calling __context_preempt_handler (). -; __context_preempt_handler() might switch stacks. On return the same context is poped from the -; stack and control is returned to the process. -; -; @return None -; -archIRQHandler - - MSR cpsr_c, #ARM_SVC_MODE ;- Save current process context in process stack - STMFD sp!, {r0 - r3, ip, lr} - - MSR cpsr_c, #ARM_IRQ_MODE ;- Save lr_irq and spsr_irq in process stack - SUB lr, lr, #4 - MOV r1, lr - MRS r2, spsr - MSR cpsr_c, #ARM_SVC_MODE - STMFD sp!, {r1, r2} - - BL __context_preempt_handler ;- Dispatch the interrupt to archTickHandler for the timer tick interrupt or a simular function for other interrupts which might call atomthread functions. - - LDMFD sp!, {r1, r2} ;- Restore lr_irq and spsr_irq from process stack - MSR cpsr_c, #ARM_IRQ_MODE - STMFD sp!, {r1} - MSR spsr_cxsf, r2 - - MSR cpsr_c, #ARM_SVC_MODE ;- Restore process regs - LDMFD sp!, {r0 - r3, ip, lr} - - MSR cpsr_c, #ARM_IRQ_MODE ;- Exit from IRQ - LDMFD sp!, {pc}^ - - -;-- - END diff --git a/tests/atomtests.h b/tests/atomtests.h index 9e0d0f2..2018a28 100644 --- a/tests/atomtests.h +++ b/tests/atomtests.h @@ -44,4 +44,4 @@ extern uint32_t test_start (void); -#endif /* __ATOM_TESTS_H */ +#endif /* __ATOM_TESTS_H */ \ No newline at end of file diff --git a/tests/kern1.c b/tests/kern1.c index 1695039..d0cce0c 100644 --- a/tests/kern1.c +++ b/tests/kern1.c @@ -64,7 +64,7 @@ uint32_t test_start (void) /* atomThreadCreate: Pass a bad TCB pointer */ if (atomThreadCreate (NULL, TEST_THREAD_PRIO, test_thread_func, 0, - &test_thread_stack[TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_ERR_PARAM) { ATOMLOG (_STR("Bad TCB check\n")); @@ -73,7 +73,7 @@ uint32_t test_start (void) /* atomThreadCreate: Pass a bad entry point */ if (atomThreadCreate (&tcb1, TEST_THREAD_PRIO, NULL, 0, - &test_thread_stack[TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_ERR_PARAM) { ATOMLOG (_STR("Bad entry check\n")); @@ -90,7 +90,7 @@ uint32_t test_start (void) /* atomThreadCreate: Pass a bad stack size */ if (atomThreadCreate (&tcb1, TEST_THREAD_PRIO, test_thread_func, 0, - &test_thread_stack[TEST_THREAD_STACK_SIZE - 1], 0) != ATOM_ERR_PARAM) + &test_thread_stack[TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], 0) != ATOM_ERR_PARAM) { ATOMLOG (_STR("Bad stack size check\n")); failures++; diff --git a/tests/kern3.c b/tests/kern3.c index 20304f8..47fc6bb 100644 --- a/tests/kern3.c +++ b/tests/kern3.c @@ -95,7 +95,7 @@ uint32_t test_start (void) /* Create low priority thread */ if (atomThreadCreate (&tcb[0], 253, test_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { ATOMLOG (_STR("Bad thread create\n")); @@ -104,7 +104,7 @@ uint32_t test_start (void) /* Create high priority thread */ else if (atomThreadCreate (&tcb[1], 252, test_thread_func, 1, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { ATOMLOG (_STR("Bad thread create\n")); diff --git a/tests/kern4.c b/tests/kern4.c index 909232e..b38be51 100644 --- a/tests/kern4.c +++ b/tests/kern4.c @@ -97,28 +97,28 @@ uint32_t test_start (void) * a spell in which this thread was run. */ if (atomThreadCreate (&tcb[0], TEST_THREAD_PRIO + 1, test_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { ATOMLOG (_STR("Bad thread create\n")); failures++; } else if (atomThreadCreate (&tcb[1], TEST_THREAD_PRIO + 1, test_thread_func, 1, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { ATOMLOG (_STR("Bad thread create\n")); failures++; } else if (atomThreadCreate (&tcb[2], TEST_THREAD_PRIO + 1, test_thread_func, 2, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { ATOMLOG (_STR("Bad thread create\n")); failures++; } else if (atomThreadCreate (&tcb[3], TEST_THREAD_PRIO + 1, test_thread_func, 3, - &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[3][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { ATOMLOG (_STR("Bad thread create\n")); diff --git a/tests/mutex1.c b/tests/mutex1.c index e3bc16a..af1e157 100644 --- a/tests/mutex1.c +++ b/tests/mutex1.c @@ -138,7 +138,7 @@ uint32_t test_start (void) } else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -201,7 +201,7 @@ uint32_t test_start (void) } else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex2.c b/tests/mutex2.c index 9725f44..033d8b6 100644 --- a/tests/mutex2.c +++ b/tests/mutex2.c @@ -144,7 +144,7 @@ uint32_t test_start (void) /* Create a test thread, the sole purpose of which is to own mutex2 */ g_owned = 0; if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex3.c b/tests/mutex3.c index f604430..1f2becc 100644 --- a/tests/mutex3.c +++ b/tests/mutex3.c @@ -108,7 +108,7 @@ uint32_t test_start (void) { /* Create Thread 1 (lower priority thread A) */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -121,7 +121,7 @@ uint32_t test_start (void) /* Create Thread 2 (lower priority thread B) */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -134,7 +134,7 @@ uint32_t test_start (void) /* Create Thread 3 (higher priority thread A) */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -147,7 +147,7 @@ uint32_t test_start (void) /* Create Thread 4 (higher priority thread B) */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, - &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[3][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex4.c b/tests/mutex4.c index b478517..7d9eeda 100644 --- a/tests/mutex4.c +++ b/tests/mutex4.c @@ -101,7 +101,7 @@ uint32_t test_start (void) /* Create Thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -113,7 +113,7 @@ uint32_t test_start (void) /* Create Thread 2 */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 2, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -125,7 +125,7 @@ uint32_t test_start (void) /* Create Thread 3 */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -137,7 +137,7 @@ uint32_t test_start (void) /* Create Thread 4 */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, - &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[3][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex5.c b/tests/mutex5.c index 9aa18f2..7e91197 100644 --- a/tests/mutex5.c +++ b/tests/mutex5.c @@ -95,7 +95,7 @@ uint32_t test_start (void) /* Create second thread */ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex6.c b/tests/mutex6.c index ca2c2d6..de4754f 100644 --- a/tests/mutex6.c +++ b/tests/mutex6.c @@ -100,7 +100,7 @@ uint32_t test_start (void) /* Create second thread */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex7.c b/tests/mutex7.c index 9189dee..5a9f312 100644 --- a/tests/mutex7.c +++ b/tests/mutex7.c @@ -94,7 +94,7 @@ uint32_t test_start (void) /* Create second thread */ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex8.c b/tests/mutex8.c index 14febb9..3c1776d 100644 --- a/tests/mutex8.c +++ b/tests/mutex8.c @@ -94,7 +94,7 @@ uint32_t test_start (void) /* Create test thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -104,7 +104,7 @@ uint32_t test_start (void) /* Create test thread 2 */ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -114,7 +114,7 @@ uint32_t test_start (void) /* Create test thread 3 */ else if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 2, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/mutex9.c b/tests/mutex9.c index e509762..23d2782 100644 --- a/tests/mutex9.c +++ b/tests/mutex9.c @@ -88,7 +88,7 @@ uint32_t test_start (void) /* Create second thread */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/queue2.c b/tests/queue2.c index 8528ade..24bcd60 100644 --- a/tests/queue2.c +++ b/tests/queue2.c @@ -90,7 +90,7 @@ uint32_t test_start (void) /* Create a test thread that will block because the queue is empty */ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -147,7 +147,7 @@ uint32_t test_start (void) /* Create a test thread that will block because the queue is empty */ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/queue3.c b/tests/queue3.c index 277a4e3..fed9ca8 100644 --- a/tests/queue3.c +++ b/tests/queue3.c @@ -107,7 +107,7 @@ uint32_t test_start (void) /* Create a test thread that will block because the queue is full */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -178,7 +178,7 @@ uint32_t test_start (void) /* Create a test thread that will block because the queue is full */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/queue5.c b/tests/queue5.c index bf07960..bf7303b 100644 --- a/tests/queue5.c +++ b/tests/queue5.c @@ -115,7 +115,7 @@ uint32_t test_start (void) /* Create Thread 1 (lower priority thread A) */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -128,7 +128,7 @@ uint32_t test_start (void) /* Create Thread 2 (lower priority thread B) */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -141,7 +141,7 @@ uint32_t test_start (void) /* Create Thread 3 (higher priority thread A) */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -154,7 +154,7 @@ uint32_t test_start (void) /* Create Thread 4 (higher priority thread B) */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, - &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[3][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/queue6.c b/tests/queue6.c index 4de62f0..eb77e04 100644 --- a/tests/queue6.c +++ b/tests/queue6.c @@ -107,7 +107,7 @@ uint32_t test_start (void) /* Create a test thread that will block because the queue is empty */ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO + 1, test1_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/queue7.c b/tests/queue7.c index 5b249d8..fda8132 100644 --- a/tests/queue7.c +++ b/tests/queue7.c @@ -94,7 +94,7 @@ uint32_t test_start (void) /* Create test thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -104,7 +104,7 @@ uint32_t test_start (void) /* Create test thread 2 */ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -114,7 +114,7 @@ uint32_t test_start (void) /* Create test thread 3 */ else if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 2, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/queue9.c b/tests/queue9.c index 1bc1034..7251dd6 100644 --- a/tests/queue9.c +++ b/tests/queue9.c @@ -103,7 +103,7 @@ uint32_t test_start (void) { /* Create Thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -115,7 +115,7 @@ uint32_t test_start (void) /* Create Thread 2 */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 2, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -127,7 +127,7 @@ uint32_t test_start (void) /* Create Thread 3 */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -139,7 +139,7 @@ uint32_t test_start (void) /* Create Thread 4 */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, - &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[3][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem1.c b/tests/sem1.c index b7b6335..69be29b 100644 --- a/tests/sem1.c +++ b/tests/sem1.c @@ -134,7 +134,7 @@ uint32_t test_start (void) } else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test1_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -201,7 +201,7 @@ uint32_t test_start (void) failures++; } else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test2_thread_func, 0, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem3.c b/tests/sem3.c index 6648b39..7bdb489 100644 --- a/tests/sem3.c +++ b/tests/sem3.c @@ -103,7 +103,7 @@ uint32_t test_start (void) { /* Create Thread 1 (lower priority thread A) */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO+1, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -116,7 +116,7 @@ uint32_t test_start (void) /* Create Thread 2 (lower priority thread B) */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO+1, test_thread_func, 2, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -129,7 +129,7 @@ uint32_t test_start (void) /* Create Thread 3 (higher priority thread A) */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -142,7 +142,7 @@ uint32_t test_start (void) /* Create Thread 4 (higher priority thread B) */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, - &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[3][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem4.c b/tests/sem4.c index 419195c..092b0f9 100644 --- a/tests/sem4.c +++ b/tests/sem4.c @@ -97,7 +97,7 @@ uint32_t test_start (void) { /* Create Thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -109,7 +109,7 @@ uint32_t test_start (void) /* Create Thread 2 */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 2, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -121,7 +121,7 @@ uint32_t test_start (void) /* Create Thread 3 */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -133,7 +133,7 @@ uint32_t test_start (void) /* Create Thread 4 */ if (atomThreadCreate(&tcb[3], TEST_THREAD_PRIO, test_thread_func, 4, - &test_thread_stack[3][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[3][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem5.c b/tests/sem5.c index dc87f9f..ae0c0a5 100644 --- a/tests/sem5.c +++ b/tests/sem5.c @@ -84,7 +84,7 @@ uint32_t test_start (void) { /* Create second thread */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem6.c b/tests/sem6.c index 851f9b8..309de97 100644 --- a/tests/sem6.c +++ b/tests/sem6.c @@ -94,7 +94,7 @@ uint32_t test_start (void) /* Create second thread */ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem7.c b/tests/sem7.c index 62fa16f..5507c70 100644 --- a/tests/sem7.c +++ b/tests/sem7.c @@ -100,7 +100,7 @@ uint32_t test_start (void) /* Create second thread */ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem8.c b/tests/sem8.c index 432cf32..67e2ea3 100644 --- a/tests/sem8.c +++ b/tests/sem8.c @@ -110,7 +110,7 @@ uint32_t test_start (void) /* Create thread 1: Higher priority than main thread so should sleep */ else if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO - 1, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -120,7 +120,7 @@ uint32_t test_start (void) /* Create thread 2: Same priority as main thread so should not sleep */ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 0, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -130,7 +130,7 @@ uint32_t test_start (void) /* Create thread 3: Same priority as main thread so should not sleep */ else if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO + 1, test_thread_func, 0, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/sem9.c b/tests/sem9.c index d7a86d6..ab4653d 100644 --- a/tests/sem9.c +++ b/tests/sem9.c @@ -87,7 +87,7 @@ uint32_t test_start (void) { /* Create test thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 0, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -97,7 +97,7 @@ uint32_t test_start (void) /* Create test thread 2 */ else if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -107,7 +107,7 @@ uint32_t test_start (void) /* Create test thread 3 */ else if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 2, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ diff --git a/tests/timer2.c b/tests/timer2.c index a606830..95c1dc6 100644 --- a/tests/timer2.c +++ b/tests/timer2.c @@ -73,7 +73,7 @@ uint32_t test_start (void) /* Create Thread 1 */ if (atomThreadCreate(&tcb[0], TEST_THREAD_PRIO, test_thread_func, 1, - &test_thread_stack[0][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[0][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -83,7 +83,7 @@ uint32_t test_start (void) /* Create Thread 2 */ if (atomThreadCreate(&tcb[1], TEST_THREAD_PRIO, test_thread_func, 2, - &test_thread_stack[1][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[1][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ @@ -93,7 +93,7 @@ uint32_t test_start (void) /* Create Thread 3 */ if (atomThreadCreate(&tcb[2], TEST_THREAD_PRIO, test_thread_func, 3, - &test_thread_stack[2][TEST_THREAD_STACK_SIZE - 1], + &test_thread_stack[2][TEST_THREAD_STACK_SIZE - sizeof(uint32_t)], TEST_THREAD_STACK_SIZE) != ATOM_OK) { /* Fail */ From 28e7382732c8ec14f6f3a07c83adc2d3e600bf9b Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 18 Sep 2012 15:24:59 +0200 Subject: [PATCH 15/28] Updated CortexM port --- ports/arm/atomport.c | 2 +- ports/{cortex_m3 => cortex_m}/Makefile | 10 +- ports/{cortex_m3 => cortex_m}/README | 0 ports/cortex_m/atomport-tests.h | 50 ++++ ports/{cortex_m3 => cortex_m}/atomport.c | 7 +- ports/{cortex_m3 => cortex_m}/atomport.h | 13 +- .../atomport_private.h | 0 ports/cortex_m/atomport_s.S | 220 ++++++++++++++++++ ports/{cortex_m3 => cortex_m}/types.h | 0 ports/cortex_m3/atomport_arm.asm | 217 ----------------- 10 files changed, 288 insertions(+), 231 deletions(-) rename ports/{cortex_m3 => cortex_m}/Makefile (67%) rename ports/{cortex_m3 => cortex_m}/README (100%) create mode 100644 ports/cortex_m/atomport-tests.h rename ports/{cortex_m3 => cortex_m}/atomport.c (95%) rename ports/{cortex_m3 => cortex_m}/atomport.h (90%) rename ports/{cortex_m3 => cortex_m}/atomport_private.h (100%) create mode 100644 ports/cortex_m/atomport_s.S rename ports/{cortex_m3 => cortex_m}/types.h (100%) delete mode 100644 ports/cortex_m3/atomport_arm.asm diff --git a/ports/arm/atomport.c b/ports/arm/atomport.c index da96930..d6fc47b 100644 --- a/ports/arm/atomport.c +++ b/ports/arm/atomport.c @@ -33,7 +33,7 @@ /* * * - * Functions defined in atomport_s.asm + * Functions defined in atomport_s.S * */ typedef void * SYSCONTEXT ; diff --git a/ports/cortex_m3/Makefile b/ports/cortex_m/Makefile similarity index 67% rename from ports/cortex_m3/Makefile rename to ports/cortex_m/Makefile index fcf84e7..c389b0d 100644 --- a/ports/cortex_m3/Makefile +++ b/ports/cortex_m/Makefile @@ -1,5 +1,5 @@ -ATOMTHREADS_PORT = ..... /libraries/atomthreads/ports/cortex_m3 -ATOMTHREADS_KERNEL = ..... /libraries/atomthreads/kernel +ATOMTHREADS_PORT = $(ATOMTHREADS)/ports/cortex_m +ATOMTHREADS_KERNEL = $(ATOMTHREADS)/kernel INCLUDES := $(INCLUDES) \ -I$(ATOMTHREADS_KERNEL) \ @@ -14,6 +14,6 @@ SRCS := $(SRCS) \ $(ATOMTHREADS_PORT)/atomport.c ASMS := $(ASMS) \ - $(ATOMTHREADS_PORT)/atomport_arm.asm - - + $(ATOMTHREADS_PORT)/atomport_s.S + + diff --git a/ports/cortex_m3/README b/ports/cortex_m/README similarity index 100% rename from ports/cortex_m3/README rename to ports/cortex_m/README diff --git a/ports/cortex_m/atomport-tests.h b/ports/cortex_m/atomport-tests.h new file mode 100644 index 0000000..cfb909a --- /dev/null +++ b/ports/cortex_m/atomport-tests.h @@ -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__ */ diff --git a/ports/cortex_m3/atomport.c b/ports/cortex_m/atomport.c similarity index 95% rename from ports/cortex_m3/atomport.c rename to ports/cortex_m/atomport.c index 1f659c3..6d6fc6a 100644 --- a/ports/cortex_m3/atomport.c +++ b/ports/cortex_m/atomport.c @@ -33,15 +33,14 @@ /* * * - * Functions defined in atomport_arm.asm + * Functions defined in atomport_s.S * */ +typedef void * SYSCONTEXT ; + extern void contextInit (void) ; extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; extern void contextStart (SYSCONTEXT* context) ; -extern uint32_t contextCreate (SYSCONTEXT* context, uint32_t stack_top, uint32_t entry) ; -extern uint32_t contextEnterCritical (void) ; -extern void contextExitCritical (uint32_t posture) ; extern void contextEnableInterrupts (void) ; /** diff --git a/ports/cortex_m3/atomport.h b/ports/cortex_m/atomport.h similarity index 90% rename from ports/cortex_m3/atomport.h rename to ports/cortex_m/atomport.h index 2a6cf50..39bd0c0 100644 --- a/ports/cortex_m3/atomport.h +++ b/ports/cortex_m/atomport.h @@ -30,10 +30,9 @@ #ifndef __ATOM_PORT_H__ #define __ATOM_PORT_H__ -#include "arch/context.h" #include "types.h" -#define SYSTEM_TICKS_PER_SEC 1000 +#define SYSTEM_TICKS_PER_SEC 100 /** @@ -43,12 +42,18 @@ */ #define POINTER void * +/* * + * + * Functions defined in atomport_arm.asm + * + */ +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__ */ diff --git a/ports/cortex_m3/atomport_private.h b/ports/cortex_m/atomport_private.h similarity index 100% rename from ports/cortex_m3/atomport_private.h rename to ports/cortex_m/atomport_private.h diff --git a/ports/cortex_m/atomport_s.S b/ports/cortex_m/atomport_s.S new file mode 100644 index 0000000..46c3138 --- /dev/null +++ b/ports/cortex_m/atomport_s.S @@ -0,0 +1,220 @@ +/* + 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 contextInit +.global contextSwitch +.global contextStart +.global contextEnableInterrupts +.global contextEnterCritical +.global contextExitCritical +.global pendSV_Handler +.global tick_Handler + +.global archTickHandler + + + +/**/ +.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 +.equ NVIC_PENDS_VPRIORITY, 0x00FF0000 // PendSV priority is minimal (0xFF) + +.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: + CPSIE i + BX lr + + +/** + * \b contextExitCritical + * + * Exit critical section (restores interrupt posture) + * + * @param[in] r0 Interrupt Posture + * + * @return None + */ +contextExitCritical: + MSR PRIMASK, r0 + BX lr + + +/** + * \b contextEnterCritical + * + * Enter critical section (disables interrupts) + * + * @return Current interrupt posture + */ +contextEnterCritical: + MRS r0, PRIMASK + CPSID i + BX lr + +/** + * \b PendSV_Handler + * + * CortexM3 PendSV_Handler. Switch context to a new stack. + * + * @return None + */ +pendSV_Handler: + CPSID i // Disable core int + + 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: + CPSIE i // Enable core int + + ORR lr, lr, #0x04 // Ensure exception return uses process stack + BX lr // Exit interrupt + + +/** + * \b Tick_Handler + * + * System timer tick interrupt handler. + * + * @return None + */ +tick_Handler: + PUSH {r4-r11, lr} + cpsid I // Disable core int + BL archTickHandler + cpsie I // Enable core int + POP {r4-r11, pc} + + +/**/ +context_new_stack_ptr: .long 0x00000000 +context_save_stack_ptr: .long 0x00000000 + + diff --git a/ports/cortex_m3/types.h b/ports/cortex_m/types.h similarity index 100% rename from ports/cortex_m3/types.h rename to ports/cortex_m/types.h diff --git a/ports/cortex_m3/atomport_arm.asm b/ports/cortex_m3/atomport_arm.asm deleted file mode 100644 index 2195db6..0000000 --- a/ports/cortex_m3/atomport_arm.asm +++ /dev/null @@ -1,217 +0,0 @@ -; -; 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. -; - - - PRESERVE8 {TRUE} - AREA UTILS, CODE, READONLY -;-- - EXPORT contextInit - EXPORT contextSwitch - EXPORT contextStart - EXPORT contextEnableInterrupts - EXPORT contextEnterCritical - EXPORT contextExitCritical - EXPORT pendSV_Handler - EXPORT tick_Handler - - EXTERN archTickHandler - -;-- -NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register -NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception -NVIC_PR_12_15_ADDR EQU 0xE000ED20 ; System Handlers 12-15 Priority Register Address -NVIC_PENDS_VPRIORITY EQU 0x00FF0000 ; PendSV priority is minimal (0xFF) - -;-- -; \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] - TEQ r1, #0 ; if contextSwitch is going to be called again before pend_sv - 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 - CPSIE i - BX lr - - -;-- -; \b contextExitCritical -; -; Exit critical section (restores interrupt posture) -; -; @param[in] r0 Interrupt Posture -; -; @return None -; -contextExitCritical - MSR PRIMASK, r0 - BX lr - - -;-- -; \b contextEnterCritical -; -; Enter critical section (disables interrupts) -; -; @return Current interrupt posture -; -contextEnterCritical - MRS r0, PRIMASK - CPSID i - BX lr - -;-- -; \b PendSV_Handler -; -; CortexM3 PendSV_Handler. Switch context to a new stack. -; -; @return None -; -pendSV_Handler - CPSID i ; Disable core int - - 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 - TEQ r0, r2 - BEQ pendsv_handler_exit - - TEQ 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 - CPSIE i ; Enable core int - - ORR lr, lr, #0x04 ; Ensure exception return uses process stack - BX lr ; Exit interrupt - - -;-- -; \b Tick_Handler -; -; System timer tick interrupt handler. -; -; @return None -; -tick_Handler - PUSH {r4-r11, lr} - cpsid I ; Disable core int - BL archTickHandler - cpsie I ; Enable core int - POP {r4-r11, pc} - - -;-- -context_new_stack_ptr DCD 0x00000000 -context_save_stack_ptr DCD 0x00000000 - -;-- - END From daa748332b55f4f590a2edb421b6a0121582f1ba Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Mon, 24 Sep 2012 23:16:03 +0200 Subject: [PATCH 16/28] cortex m port qemu_lm3s platform --- platforms/qemu_integratorcp/Makefile | 2 +- platforms/qemu_integratorcp/system.ld | 4 - platforms/qemu_lm3s/Makefile | 96 ++++++++++++ platforms/qemu_lm3s/main.c | 89 +++++++++++ platforms/qemu_lm3s/modules.c | 161 +++++++++++++++++++ platforms/qemu_lm3s/modules.h | 213 +++++++++++++++++++++++++ platforms/qemu_lm3s/startup.S | 215 ++++++++++++++++++++++++++ platforms/qemu_lm3s/system.ld | 100 ++++++++++++ ports/arm/types.h | 10 -- ports/cortex_m/atomport.c | 53 ++++--- ports/cortex_m/atomport.h | 1 + ports/cortex_m/atomport_s.S | 64 +++++++- ports/cortex_m/types.h | 9 ++ 13 files changed, 973 insertions(+), 44 deletions(-) create mode 100644 platforms/qemu_lm3s/Makefile create mode 100644 platforms/qemu_lm3s/main.c create mode 100644 platforms/qemu_lm3s/modules.c create mode 100644 platforms/qemu_lm3s/modules.h create mode 100644 platforms/qemu_lm3s/startup.S create mode 100644 platforms/qemu_lm3s/system.ld diff --git a/platforms/qemu_integratorcp/Makefile b/platforms/qemu_integratorcp/Makefile index 551529f..e88e47d 100644 --- a/platforms/qemu_integratorcp/Makefile +++ b/platforms/qemu_integratorcp/Makefile @@ -15,7 +15,7 @@ LN = arm-none-eabi-gcc AS = arm-none-eabi-gcc CFLAGS := $(CFLAGS) -Wall -g -c -mcpu=arm926ej-s -ffreestanding -AFLAGS := $(CFLAGS) -Wall -g -c -mcpu=arm926ej-s -ffreestanding +AFLAGS := $(AFLAGS) -Wall -g -c -mcpu=arm926ej-s -ffreestanding LFLAGS := $(LFLAGS) -Wall -mcpu=arm926ej-s -Wl,-Map=system.map,--verbose -Tsystem.ld CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' diff --git a/platforms/qemu_integratorcp/system.ld b/platforms/qemu_integratorcp/system.ld index 4d4fc2c..40682db 100644 --- a/platforms/qemu_integratorcp/system.ld +++ b/platforms/qemu_integratorcp/system.ld @@ -84,10 +84,6 @@ SECTIONS } >sram - /*DISCARD : - { - *(.eh_*) - }*/ } _end = .; diff --git a/platforms/qemu_lm3s/Makefile b/platforms/qemu_lm3s/Makefile new file mode 100644 index 0000000..5b86d1f --- /dev/null +++ b/platforms/qemu_lm3s/Makefile @@ -0,0 +1,96 @@ +ifeq ($(TARGET_NAME),) +TARGET_NAME=boot +endif +ifeq ($(ATOMTHREADS),) +ATOMTHREADS = $(shell pwd)/../../ +endif +ifeq ($(TEST_NAME),) +TEST_NAME = mutex1 +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 \ + +# startup_c.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" + +all_fail: + make run_test "TEST_NAME=mutex4" + make run_test "TEST_NAME=sem4" + + +run_last: + qemu-system-arm -M lm3s6965evb -kernel boot.elf -monitor stdio -semihosting + diff --git a/platforms/qemu_lm3s/main.c b/platforms/qemu_lm3s/main.c new file mode 100644 index 0000000..3f68d6c --- /dev/null +++ b/platforms/qemu_lm3s/main.c @@ -0,0 +1,89 @@ +/* + * 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 +#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[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; + atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); + atomOSStart() ; + + return 0 ; +} + diff --git a/platforms/qemu_lm3s/modules.c b/platforms/qemu_lm3s/modules.c new file mode 100644 index 0000000..fc7cbc8 --- /dev/null +++ b/platforms/qemu_lm3s/modules.c @@ -0,0 +1,161 @@ +/* + * 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 +#include +#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_preempt_handler + * + * System timer tic interupt handler. + * + */ +void +__context_tick_handler (void) +{ + + if (1) { + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + board_gptm0->ICR |= GPTM_TIMER_INT_TATOIM ; + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); + + } + +} + +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); + +} + diff --git a/platforms/qemu_lm3s/modules.h b/platforms/qemu_lm3s/modules.h new file mode 100644 index 0000000..3a341e0 --- /dev/null +++ b/platforms/qemu_lm3s/modules.h @@ -0,0 +1,213 @@ +/* + * 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" + + +typedef volatile unsigned int REG_DWORD ; +typedef volatile unsigned short REG_WORD ; +typedef volatile unsigned char REG_BYTE ; + + +// ***************************************************************************** +// The Stellaris General-Purpose Timer Module (GPTM) +// ***************************************************************************** +typedef struct GPTM_TIMER_S { + + // offset read/write reset Description + REG_DWORD CFG ; // 0x000 R/W 0x00000000 GPTM Configuration 345 + REG_DWORD TAMR ; // 0x004 R/W 0x00000000 GPTM TimerA Mode 346 + REG_DWORD TBMR ; // 0x008 R/W 0x00000000 GPTM TimerB Mode 348 + REG_DWORD CTL ; // 0x00C R/W 0x00000000 GPTM Control 350 + REG_DWORD Reserved[2] ; // 0x010 + REG_DWORD IMR ; // 0x018 R/W 0x00000000 GPTM Interrupt Mask 353 + REG_DWORD RIS ; // 0x01C RO 0x00000000 GPTM Raw Interrupt Status 355 + REG_DWORD MIS ; // 0x020 RO 0x00000000 GPTM Masked Interrupt Status 356 + REG_DWORD ICR ; // 0x024 W1C 0x00000000 GPTM Interrupt Clear 357 + REG_DWORD TAILR ; // 0x028 R/W 0xFFFFFFFF GPTM TimerA Interval Load 359 + REG_DWORD TBILR ; // 0x02C R/W 0x0000FFFF GPTM TimerB Interval Load 360 + REG_DWORD TAMATCHR ; // 0x030 R/W 0xFFFFFFFF GPTM TimerA Match 361 + REG_DWORD TBMATCHR ; // 0x034 R/W 0x0000FFFF GPTM TimerB Match 362 + REG_DWORD TAPR ; // 0x038 R/W 0x00000000 GPTM TimerA Prescale 363 + REG_DWORD TBPR ; // 0x03C R/W 0x00000000 GPTM TimerB Prescale 364 + REG_DWORD TAPMR ; // 0x040 R/W 0x00000000 GPTM TimerA Prescale Match 365 + REG_DWORD TBPMR ; // 0x044 R/W 0x00000000 GPTM TimerB Prescale Match 366 + REG_DWORD TAR ; // 0x048 RO 0xFFFFFFFF GPTM TimerA 367 + REG_DWORD 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_NE ((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_NE ((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 { + + REG_DWORD Res0[1] ; // 0xE000E000 + REG_DWORD ICT ; // 0xE000E004 + REG_DWORD Res1[2] ; // 0xE000E008 + REG_DWORD STCTRL ; // 0xE000E010 + REG_DWORD STRELOAD ; // 0xE000E014 + REG_DWORD STCURRENT; // 0xE000E018 + REG_DWORD STCALIB ; // 0xE000E01C + REG_DWORD 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 { + + REG_DWORD ISER[2] ; // 0xE000E100 + REG_DWORD Res3[30] ; // 0xE000E120 + REG_DWORD ICER[2] ; // 0xE000E180 + REG_DWORD Res4[30] ; // 0xE000E1A0 + REG_DWORD ISPR[2] ; // 0xE000E200 + REG_DWORD Res5[30] ; // 0xE000E220 + REG_DWORD ICPR[2] ; // 0xE000E280 + REG_DWORD Res6[30] ; // 0xE000E2A0 + REG_DWORD IABR[2] ; // 0xE000E300 + REG_DWORD Res7[64] ; // 0xE000E320 + REG_DWORD IPR[2] ; // 0xE000E400 + // REG_DWORD 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 { + + REG_DWORD CPUID ; // 0xE000ED00 + REG_DWORD ICSR ; // 0xE000ED04 + REG_DWORD VTOR ; // 0xE000ED08 + REG_DWORD AIRCR ; // 0xE000ED0C + REG_DWORD SCR ; // 0xE000ED10 + REG_DWORD CCR ; // 0xE000ED14 + + REG_DWORD SYS_PRIO[3] ; // 0xE000ED18 + REG_DWORD SYSHNDCTRL ; // 0xE000ED24 + //REG_DWORD FAULTSTAT ; // 0xE000ED28 + //REG_DWORD HFAULTSTAT ; // 0xE000ED2C + +} SCB_T, *PSCB_T ; + + + +#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 ; + + + +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__ */ diff --git a/platforms/qemu_lm3s/startup.S b/platforms/qemu_lm3s/startup.S new file mode 100644 index 0000000..da5823b --- /dev/null +++ b/platforms/qemu_lm3s/startup.S @@ -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 +.global tick_Handler +.global pendSV_Handler +.global 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 pendSV_Handler +.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 tick_Handler // 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 +.global initialise_monitor_handles +.global low_level_init +.global 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 \ No newline at end of file diff --git a/platforms/qemu_lm3s/system.ld b/platforms/qemu_lm3s/system.ld new file mode 100644 index 0000000..de5ffc8 --- /dev/null +++ b/platforms/qemu_lm3s/system.ld @@ -0,0 +1,100 @@ +/****************************************************************************** + * + * hello_codered.ld - Code Red linker configuration file for hello. + * + * Copyright (c) 2006-2012 Texas Instruments Incorporated. All rights reserved. + * Software License Agreement + * + * Texas Instruments (TI) is supplying this software for use solely and + * exclusively on TI's microcontroller products. The software is owned by + * TI and/or its suppliers, and is protected under applicable copyright + * laws. You may not combine this software with "viral" open-source + * software in order to form a larger program. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. + * 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. TI SHALL NOT, UNDER ANY + * CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL + * DAMAGES, FOR ANY REASON WHATSOEVER. + * + * This is part of revision 9107 of the EK-LM3S6965 Firmware Package. + * + *****************************************************************************/ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 + SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000 +} + +SECTIONS +{ + _vRamTop = 0x20000000 + 0x00010000; + .text : + { + *(.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 + + /* + * Note: (ref: M0000066) + * Moving the stack down by 16 is to work around a GDB bug. + * This space can be reclaimed for Production Builds. + */ + + _vStackTop = _vRamTop - 16; + .stack _vStackTop : + { + __c_stack_top__ = . ; + } +} diff --git a/ports/arm/types.h b/ports/arm/types.h index d383d84..c07e295 100644 --- a/ports/arm/types.h +++ b/ports/arm/types.h @@ -40,16 +40,6 @@ typedef int int32_t ; typedef short int16_t ; typedef char int8_t ; -// typedef volatile unsigned int REG_DWORD ;// Hardware register definition - -#define UWORD64 unsigned long long -#define UWORD32 unsigned int -#define UWORD16 unsigned short -#define UWORD8 unsigned char -#define WORD32 int -#define WORD16 short -#define WORD8 char - #ifndef OFFSETOF #define OFFSETOF(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) #endif diff --git a/ports/cortex_m/atomport.c b/ports/cortex_m/atomport.c index 6d6fc6a..d41359d 100644 --- a/ports/cortex_m/atomport.c +++ b/ports/cortex_m/atomport.c @@ -38,7 +38,6 @@ */ typedef void * SYSCONTEXT ; -extern void contextInit (void) ; extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; extern void contextStart (SYSCONTEXT* context) ; extern void contextEnableInterrupts (void) ; @@ -93,7 +92,11 @@ archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(u *stack_ptr = 0x01000000L; //-- xPSR stack_ptr--; - *stack_ptr = ((uint32_t)thread_shell) | 1; //-- Entry Point (1 for THUMB mode) +#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--; @@ -159,20 +162,20 @@ archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) * System timer tick interrupt handler. * */ -void -archTickHandler (void) -{ - atomIntEnter(); - - /* Call the OS system tick handler */ - atomTimerTick(); - - /* ack the interrupt if needed */ - /* ... */ - - /* Call the interrupt exit routine */ - atomIntExit(TRUE); -} +//void +//archTickHandler (void) +//{ +// atomIntEnter(); +// +// /* Call the OS system tick handler */ +// atomTimerTick(); +// +// /* ack the interrupt if needed */ +// /* ... */ +// +// /* Call the interrupt exit routine */ +// atomIntExit(TRUE); +//} /** * \b archTickInit @@ -180,14 +183,14 @@ archTickHandler (void) * System timer initialization. * */ -void -archTickInit (void) -{ - /* Initialize NVIC PendSV */ - contextInit () ; - - /* Initializa Timer Hardware */ - /* ... */ -} +//void +//archTickInit (void) +//{ +// /* Initialize NVIC PendSV */ +// contextInit () ; +// +// /* Initializa Timer Hardware */ +// /* ... */ +//} diff --git a/ports/cortex_m/atomport.h b/ports/cortex_m/atomport.h index 39bd0c0..f7ac10d 100644 --- a/ports/cortex_m/atomport.h +++ b/ports/cortex_m/atomport.h @@ -47,6 +47,7 @@ * Functions defined in atomport_arm.asm * */ +extern void contextInit (void) ; extern uint32_t contextEnterCritical (void) ; extern void contextExitCritical (uint32_t posture) ; diff --git a/ports/cortex_m/atomport_s.S b/ports/cortex_m/atomport_s.S index 46c3138..0ae97c4 100644 --- a/ports/cortex_m/atomport_s.S +++ b/ports/cortex_m/atomport_s.S @@ -37,20 +37,28 @@ .global pendSV_Handler .global tick_Handler -.global archTickHandler +.global __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 -.equ NVIC_PENDS_VPRIORITY, 0x00FF0000 // PendSV priority is minimal (0xFF) +.equ NVIC_PENDS_VPRIORITY, 0x00F00000 // PendSV priority is minimal (0xFF -- 0x00FF0000) + +#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 * @@ -128,7 +136,13 @@ contextStart: * @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 @@ -142,10 +156,14 @@ contextEnableInterrupts: * @return None */ contextExitCritical: +#ifndef PLATFORM_QEMU_LM3S_HACK MSR PRIMASK, r0 +#else + LDR r1, =NVIC_ISER + STR r0, [r1] +#endif BX lr - /** * \b contextEnterCritical * @@ -154,8 +172,15 @@ contextExitCritical: * @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 /** @@ -165,8 +190,15 @@ contextEnterCritical: * * @return None */ + .thumb_func pendSV_Handler: +#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 @@ -192,7 +224,13 @@ pendsv_handler_new_stack: 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 @@ -205,15 +243,33 @@ pendsv_handler_exit: * * @return None */ + .thumb_func tick_Handler: PUSH {r4-r11, lr} + +#ifndef PLATFORM_QEMU_LM3S_HACK cpsid I // Disable core int - BL archTickHandler +#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 diff --git a/ports/cortex_m/types.h b/ports/cortex_m/types.h index 82317f7..c07e295 100644 --- a/ports/cortex_m/types.h +++ b/ports/cortex_m/types.h @@ -40,5 +40,14 @@ typedef int int32_t ; typedef short int16_t ; typedef char int8_t ; +#ifndef OFFSETOF +#define OFFSETOF(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) +#endif + +#ifndef INLINE +#define INLINE __inline +#endif + + #endif /* __TYPES_H__ */ From 650f5e2ac36ada49d9c44ff8b1b2a220fcc557ff Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Thu, 27 Sep 2012 10:49:09 +0200 Subject: [PATCH 17/28] Cortex M port added qemu_lm3s platform added --- platforms/qemu_integratorcp/README | 12 +++++++++ platforms/qemu_integratorcp/modules.h | 18 ++++++++----- platforms/qemu_integratorcp/startup.s | 6 ++--- platforms/qemu_lm3s/Makefile | 3 +-- platforms/qemu_lm3s/README | 33 +++++++++++++++++++++++ platforms/qemu_lm3s/main.c | 3 +-- platforms/qemu_lm3s/modules.c | 15 +++++------ platforms/qemu_lm3s/modules.h | 10 +++---- platforms/qemu_lm3s/startup.S | 16 +++++------ platforms/qemu_lm3s/system.ld | 32 ++-------------------- ports/arm/README | 29 +++----------------- ports/arm/atomport.c | 39 --------------------------- ports/arm/atomport.h | 1 + ports/arm/atomport_private.h | 5 ++-- ports/arm/atomport_s.S | 3 +-- ports/cortex_m/README | 24 ++++------------- ports/cortex_m/atomport.c | 38 -------------------------- ports/cortex_m/atomport_private.h | 7 +++-- ports/cortex_m/atomport_s.S | 16 +++++------ 19 files changed, 109 insertions(+), 201 deletions(-) create mode 100644 platforms/qemu_integratorcp/README create mode 100644 platforms/qemu_lm3s/README diff --git a/platforms/qemu_integratorcp/README b/platforms/qemu_integratorcp/README new file mode 100644 index 0000000..5deb509 --- /dev/null +++ b/platforms/qemu_integratorcp/README @@ -0,0 +1,12 @@ +--------------------------------------------------------------------------- + +Library: Atomthreads QEMU ARM Integrator/CP (ARM926EJ-S) Platform. +Author: Natie van Rooyen +License: BSD Revised + +--------------------------------------------------------------------------- + +QEMU ARM Integrator/CP (ARM926EJ-S) Platform + +The "qemu_integratorcp" platform contains sources for building a sample +Atomthreads application for the ARM Integrator/CP (ARM926EJ-S) platform. \ No newline at end of file diff --git a/platforms/qemu_integratorcp/modules.h b/platforms/qemu_integratorcp/modules.h index 38aa37f..58a48ed 100644 --- a/platforms/qemu_integratorcp/modules.h +++ b/platforms/qemu_integratorcp/modules.h @@ -29,14 +29,14 @@ #ifndef __MODULES_H__ #define __MODULES_H__ +/* + * Module definitions to use with the ARM Integrator/CP (ARM926EJ-S) + */ + #include "atomport.h" -extern void dbg_format_msg (char *format, ...) ; -#define DBG_MESSAGE(fmt_str) { dbg_format_msg fmt_str ; } - - -typedef volatile unsigned int REG_DWORD ;// Hardware register definition +typedef volatile unsigned int REG_DWORD ; typedef volatile unsigned short REG_WORD ; typedef volatile unsigned char REG_BYTE ; @@ -110,7 +110,7 @@ typedef struct ICP_PIC_S { - +/* module definitions */ #define BOARD_BASE_ADDRESS_TIMER_0 0x13000000 #define BOARD_BASE_ADDRESS_PIC 0x14000000 @@ -118,7 +118,11 @@ extern ICP_TIMER_T* const board_timer_0 ; extern ICP_PIC_T* const board_pic ; - +/* Function prototypes */ extern int low_level_init (void) ; +extern void dbg_format_msg (char *format, ...) ; + +#define DBG_MESSAGE(fmt_str) { dbg_format_msg fmt_str ; } + #endif /* __MODULES_H__ */ diff --git a/platforms/qemu_integratorcp/startup.s b/platforms/qemu_integratorcp/startup.s index dc4a167..0c3675d 100644 --- a/platforms/qemu_integratorcp/startup.s +++ b/platforms/qemu_integratorcp/startup.s @@ -1,9 +1,9 @@ .section .vectors, "x" .global __interrupt_vector_table -.global __irq_stack_top__ -.global __fiq_stack_top__ -.global __svc_stack_top__ +.extern __irq_stack_top__ +.extern __fiq_stack_top__ +.extern __svc_stack_top__ .global bsp_ints_enable .global bsp_ints_disable diff --git a/platforms/qemu_lm3s/Makefile b/platforms/qemu_lm3s/Makefile index 5b86d1f..c8568ad 100644 --- a/platforms/qemu_lm3s/Makefile +++ b/platforms/qemu_lm3s/Makefile @@ -5,7 +5,7 @@ ifeq ($(ATOMTHREADS),) ATOMTHREADS = $(shell pwd)/../../ endif ifeq ($(TEST_NAME),) -TEST_NAME = mutex1 +TEST_NAME = kern1 endif @@ -29,7 +29,6 @@ SRCS := $(SRCS) \ main.c \ $(ATOMTHREADS)/tests/$(TEST_NAME).c \ -# startup_c.c \ ASMS := $(ASMS) \ startup.S \ diff --git a/platforms/qemu_lm3s/README b/platforms/qemu_lm3s/README new file mode 100644 index 0000000..6e340d1 --- /dev/null +++ b/platforms/qemu_lm3s/README @@ -0,0 +1,33 @@ +--------------------------------------------------------------------------- + +Library: Atomthreads QEMU Stellaris LM3S6965 Platform. +Author: Natie van Rooyen +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. diff --git a/platforms/qemu_lm3s/main.c b/platforms/qemu_lm3s/main.c index 3f68d6c..9aa5bdc 100644 --- a/platforms/qemu_lm3s/main.c +++ b/platforms/qemu_lm3s/main.c @@ -43,7 +43,6 @@ static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ; ATOM_TCB test_tcb ; - /** * \b test_thread * @@ -78,7 +77,7 @@ main (void) int i = 0 ; uint32_t failures ; - printf ("atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ; + printf ("Atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ; atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); diff --git a/platforms/qemu_lm3s/modules.c b/platforms/qemu_lm3s/modules.c index fc7cbc8..c375e4e 100644 --- a/platforms/qemu_lm3s/modules.c +++ b/platforms/qemu_lm3s/modules.c @@ -101,18 +101,15 @@ void __context_tick_handler (void) { - if (1) { - atomIntEnter(); + atomIntEnter(); - /* Call the OS system tick handler */ - atomTimerTick(); + /* Call the OS system tick handler */ + atomTimerTick(); - board_gptm0->ICR |= GPTM_TIMER_INT_TATOIM ; + board_gptm0->ICR |= GPTM_TIMER_INT_TATOIM ; - /* Call the interrupt exit routine */ - atomIntExit(TRUE); - - } + /* Call the interrupt exit routine */ + atomIntExit(TRUE); } diff --git a/platforms/qemu_lm3s/modules.h b/platforms/qemu_lm3s/modules.h index 3a341e0..8d3bb4c 100644 --- a/platforms/qemu_lm3s/modules.h +++ b/platforms/qemu_lm3s/modules.h @@ -86,7 +86,7 @@ typedef struct GPTM_TIMER_S { #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_NE ((unsigned int)0x03 << 10) // Both edges + #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 // -------- @@ -96,7 +96,7 @@ typedef struct GPTM_TIMER_S { #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_NE ((unsigned int)0x03 << 2) // Both edges + #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. -------- @@ -191,7 +191,7 @@ typedef struct SCB_S { } SCB_T, *PSCB_T ; - +/* module definitions */ #define BOARD_BASE_ADDRESS_SYSTICK 0xE000E000 #define BOARD_BASE_ADDRESS_NVIC 0xE000E100 #define BOARD_BASE_ADDRESS_SCB 0xE000ED00 @@ -203,11 +203,11 @@ 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 ; } +#define DBG_MESSAGE(fmt_str) { dbg_format_msg fmt_str ; } #endif /* __MODULES_H__ */ diff --git a/platforms/qemu_lm3s/startup.S b/platforms/qemu_lm3s/startup.S index da5823b..f570fea 100644 --- a/platforms/qemu_lm3s/startup.S +++ b/platforms/qemu_lm3s/startup.S @@ -35,9 +35,9 @@ .global __interrupt_vector_table -.global tick_Handler -.global pendSV_Handler -.global dbg_hard_fault_handler_c +.extern archTickHandler +.extern archPendSVHandler +.extern dbg_hard_fault_handler_c /** * \b __interrupt_vector_table @@ -58,7 +58,7 @@ __interrupt_vector_table: .long sys_Handler .long sys_Handler .long 0 -.long pendSV_Handler +.long archPendSVHandler .long sys_Handler /* External interrupts */ @@ -81,7 +81,7 @@ __interrupt_vector_table: .long default_Handler // ADC Sequence 2 .long default_Handler // ADC Sequence 3 .long default_Handler // Watchdog timer -.long tick_Handler // Timer 0 subtimer A +.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 @@ -144,9 +144,9 @@ fault_Handler: .thumb .global reset_Handler -.global initialise_monitor_handles -.global low_level_init -.global main +.extern initialise_monitor_handles +.extern low_level_init +.extern main /** diff --git a/platforms/qemu_lm3s/system.ld b/platforms/qemu_lm3s/system.ld index de5ffc8..dd59b49 100644 --- a/platforms/qemu_lm3s/system.ld +++ b/platforms/qemu_lm3s/system.ld @@ -1,26 +1,4 @@ -/****************************************************************************** - * - * hello_codered.ld - Code Red linker configuration file for hello. - * - * Copyright (c) 2006-2012 Texas Instruments Incorporated. All rights reserved. - * Software License Agreement - * - * Texas Instruments (TI) is supplying this software for use solely and - * exclusively on TI's microcontroller products. The software is owned by - * TI and/or its suppliers, and is protected under applicable copyright - * laws. You may not combine this software with "viral" open-source - * software in order to form a larger program. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. - * 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. TI SHALL NOT, UNDER ANY - * CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL - * DAMAGES, FOR ANY REASON WHATSOEVER. - * - * This is part of revision 9107 of the EK-LM3S6965 Firmware Package. - * - *****************************************************************************/ + MEMORY { @@ -33,7 +11,7 @@ SECTIONS _vRamTop = 0x20000000 + 0x00010000; .text : { - *(.vectors) + KEEP(*(.vectors)) *(.startup) *(.text*) *(.rodata*) @@ -86,12 +64,6 @@ SECTIONS _pvHeapStart = .; } > SRAM - /* - * Note: (ref: M0000066) - * Moving the stack down by 16 is to work around a GDB bug. - * This space can be reclaimed for Production Builds. - */ - _vStackTop = _vRamTop - 16; .stack _vStackTop : { diff --git a/ports/arm/README b/ports/arm/README index fae939d..8846ff5 100644 --- a/ports/arm/README +++ b/ports/arm/README @@ -6,33 +6,12 @@ License: BSD Revised --------------------------------------------------------------------------- -ARM ARMv7 PORT +ARM PORT This folder contains a port of the Atomthreads real time kernel for the -ARMv7 processor architecture. This port was only tested on a ARMv7 but -should work on other versions of the ARM processor as well. +ARM processor architecture. This port was tested on Cortex A9, Cortex A15 +and the ARM926EJ-S (QEMU). To Use: -1. From your platforms IRQ vector branch to the "__irq_context_handler()". - All interrupts from where calls to Atomthreads will be made should do - this. The "__irq_context_handler()" will call a platform specific - function called "__context_preempt_handler()" to dispatch the interrupt. - -2. Implement the function "__context_preempt_handler()" - from where your platforms interrupt controller will be serviced and the - interrupt will be dispatched to a specific interrupt service routine. In - the case of your platforms timer tick interrupt call the "archTickHandler()" - implemented in "atomport.c". - -3. Initialize your platforms timer tick hardware to generate an OS timer tick - interrupt. - -4. Add code to acknowledge your timer hardware's interrupt in the - function "archTickHandler()" implemented in "atomport.c". This must - be done here because "atomIntExit()" might switch the context. - -5. After your platforms c-runtime initialization has completed, start - Atomthreads from your runtime's "main()" function. - -6. Include the port's Makefile in your platform build flow. \ No newline at end of file +See the example project in the "platforms/qemu_integratorcp" directory. \ No newline at end of file diff --git a/ports/arm/atomport.c b/ports/arm/atomport.c index d6fc47b..8775004 100644 --- a/ports/arm/atomport.c +++ b/ports/arm/atomport.c @@ -38,7 +38,6 @@ */ typedef void * SYSCONTEXT ; -extern void contextInit (void) ; extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; extern void contextStart (SYSCONTEXT* context) ; extern void contextEnableInterrupts (void) ; @@ -145,41 +144,3 @@ archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) } -/** - * \b archTimerTickIrqHandler - * - * System timer tick interrupt handler. - * - */ -void -archTickHandler (void) -{ - atomIntEnter(); - - /* Call the OS system tick handler */ - atomTimerTick(); - - /* ack the interrupt if needed */ - /* ... */ - - /* Call the interrupt exit routine */ - atomIntExit(TRUE); -} - -/** - * \b archTickInit - * - * System timer initialization. - * - */ -void -archTickInit (void) -{ - /* Initialize NVIC PendSV */ - contextInit () ; - - /* Initializa Timer Hardware */ - /* ... */ -} - - diff --git a/ports/arm/atomport.h b/ports/arm/atomport.h index 39bd0c0..f7ac10d 100644 --- a/ports/arm/atomport.h +++ b/ports/arm/atomport.h @@ -47,6 +47,7 @@ * Functions defined in atomport_arm.asm * */ +extern void contextInit (void) ; extern uint32_t contextEnterCritical (void) ; extern void contextExitCritical (uint32_t posture) ; diff --git a/ports/arm/atomport_private.h b/ports/arm/atomport_private.h index 87a032f..a99c447 100644 --- a/ports/arm/atomport_private.h +++ b/ports/arm/atomport_private.h @@ -32,8 +32,9 @@ /* Function prototypes */ -extern void archTickHandler (void) ; -extern void archTickInit (void) ; extern void archIRQHandler (void) ; +/* required interface */ +extern void __context_preempt_handler (void) ; + #endif /* __ATOM_PORT_PRIVATE_H__ */ diff --git a/ports/arm/atomport_s.S b/ports/arm/atomport_s.S index 1227c52..d3a9ece 100644 --- a/ports/arm/atomport_s.S +++ b/ports/arm/atomport_s.S @@ -34,7 +34,6 @@ .global archIRQHandler - .global contextEnterCritical .global contextExitCritical .global contextEnableInterrupts @@ -44,7 +43,7 @@ .global contextInit -.global __context_preempt_handler +.extern __context_preempt_handler /**/ .equ USR_MODE, 0x10 diff --git a/ports/cortex_m/README b/ports/cortex_m/README index 6784187..83527b1 100644 --- a/ports/cortex_m/README +++ b/ports/cortex_m/README @@ -1,31 +1,17 @@ --------------------------------------------------------------------------- -Library: Atomthreads CortexM3 Port +Library: Atomthreads ARM Cortex M Port Author: Natie van Rooyen License: BSD Revised --------------------------------------------------------------------------- -ARM CortexM3 PORT +ARM Cortex M PORT This folder contains a port of the Atomthreads real time kernel for the -ARM CortexM3 processor architecture. +ARM CortexM type processor architecture. This port was tested on the +Cortex M3 and the Cortex M4. To Use: -1. Install the "pendSV_Handler" and "tick_Handler" implemented in the file - "atomport_arm.asm" in your platforms interrupt vectors. - -2. Complete the function "archTickInit()" implemented in "atomport.c" to - initialize your platforms timer tick interrupt. If you use the build in - SysTick of the CortexM3 you also have to add code here to start it. - -3. If required, add code to acknowledge your timer hardware's interrupt in - the function "archTickHandler()" also implemented in "atomport.c". - -4. During your platform initialization call the function "archTickInit()" - exported from "atomport_private.h" to initialize the CortexM3 - "PendSV_Handler". - -5. After your platforms c-runtime initialization has completed, start - Atomthreads from your runtime's "main()" function. \ No newline at end of file +See the example project in the "platforms/qemu_lm3s" directory. \ No newline at end of file diff --git a/ports/cortex_m/atomport.c b/ports/cortex_m/atomport.c index d41359d..019b05f 100644 --- a/ports/cortex_m/atomport.c +++ b/ports/cortex_m/atomport.c @@ -156,41 +156,3 @@ archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) } -/** - * \b archTimerTickIrqHandler - * - * System timer tick interrupt handler. - * - */ -//void -//archTickHandler (void) -//{ -// atomIntEnter(); -// -// /* Call the OS system tick handler */ -// atomTimerTick(); -// -// /* ack the interrupt if needed */ -// /* ... */ -// -// /* Call the interrupt exit routine */ -// atomIntExit(TRUE); -//} - -/** - * \b archTickInit - * - * System timer initialization. - * - */ -//void -//archTickInit (void) -//{ -// /* Initialize NVIC PendSV */ -// contextInit () ; -// -// /* Initializa Timer Hardware */ -// /* ... */ -//} - - diff --git a/ports/cortex_m/atomport_private.h b/ports/cortex_m/atomport_private.h index 0f4a004..0bdf11c 100644 --- a/ports/cortex_m/atomport_private.h +++ b/ports/cortex_m/atomport_private.h @@ -32,7 +32,10 @@ /* Function prototypes */ -extern void archTickHandler (void) ; -extern void archTickInit (void) ; +extern void archPendSVHandler (void) ; +extern void archTickHandler (void) ; + +/* required interface */ +extern void __context_tick_handler (void) ; #endif /* __ATOM_PORT_PRIVATE_H__ */ diff --git a/ports/cortex_m/atomport_s.S b/ports/cortex_m/atomport_s.S index 0ae97c4..2e25d93 100644 --- a/ports/cortex_m/atomport_s.S +++ b/ports/cortex_m/atomport_s.S @@ -28,17 +28,17 @@ */ +.global archPendSVHandler +.global archTickHandler .global contextInit .global contextSwitch .global contextStart .global contextEnableInterrupts .global contextEnterCritical .global contextExitCritical -.global pendSV_Handler -.global tick_Handler -.global __context_tick_handler +.extern __context_tick_handler /**/ @@ -184,14 +184,14 @@ contextEnterCritical: BX lr /** - * \b PendSV_Handler + * \b archPendSVHandler * - * CortexM3 PendSV_Handler. Switch context to a new stack. + * CortexM3 archPendSVHandler. Switch context to a new stack. * * @return None */ .thumb_func -pendSV_Handler: +archPendSVHandler: #ifndef PLATFORM_QEMU_LM3S_HACK CPSID i // Disable core int #else @@ -237,14 +237,14 @@ pendsv_handler_exit: /** - * \b Tick_Handler + * \b archTickHandler * * System timer tick interrupt handler. * * @return None */ .thumb_func -tick_Handler: +archTickHandler: PUSH {r4-r11, lr} #ifndef PLATFORM_QEMU_LM3S_HACK From 4c669225c608eaacd468960c2ab5585b999385ec Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Thu, 27 Sep 2012 12:18:00 +0200 Subject: [PATCH 18/28] Updated for new stack alignment changes in atom.h. --- platforms/qemu_integratorcp/Makefile | 4 ++-- platforms/qemu_integratorcp/main.c | 4 ++-- platforms/qemu_lm3s/Makefile | 4 ++-- platforms/qemu_lm3s/main.c | 4 ++-- ports/arm/atomport.h | 24 +++++++++++++++++++----- ports/cortex_m/atomport.h | 25 +++++++++++++++++++++---- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/platforms/qemu_integratorcp/Makefile b/platforms/qemu_integratorcp/Makefile index e88e47d..cc54f51 100644 --- a/platforms/qemu_integratorcp/Makefile +++ b/platforms/qemu_integratorcp/Makefile @@ -44,7 +44,7 @@ include ../rules.mk run_test: clean all echo "START TEST $(TEST_NAME)" - qemu-system-arm -M integratorcp -kernel boot.elf -semihosting | tee atomthreads_test.out + qemu-system-arm -M integratorcp -kernel boot.elf -semihosting >> atomthreads_test.out all_tests: echo "Starting atomthreads test suite" > atomthreads_test.out @@ -87,5 +87,5 @@ all_tests: make run_test "TEST_NAME=sem9" run_last: - qemu-system-arm -M integratorcp -kernel boot.elf -monitor stdio -semihosting + qemu-system-arm -M integratorcp -kernel boot.elf -semihosting diff --git a/platforms/qemu_integratorcp/main.c b/platforms/qemu_integratorcp/main.c index 3222170..aebdd3d 100644 --- a/platforms/qemu_integratorcp/main.c +++ b/platforms/qemu_integratorcp/main.c @@ -77,8 +77,8 @@ main (void) printf ("atomthreads starting %s... ", ATOMTHREADS_TEST) ; - atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; - atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); + 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 ; diff --git a/platforms/qemu_lm3s/Makefile b/platforms/qemu_lm3s/Makefile index c8568ad..dc9c117 100644 --- a/platforms/qemu_lm3s/Makefile +++ b/platforms/qemu_lm3s/Makefile @@ -85,11 +85,11 @@ all_tests: make run_test "TEST_NAME=sem8" make run_test "TEST_NAME=sem9" -all_fail: +fail_tests: make run_test "TEST_NAME=mutex4" make run_test "TEST_NAME=sem4" run_last: - qemu-system-arm -M lm3s6965evb -kernel boot.elf -monitor stdio -semihosting + qemu-system-arm -M lm3s6965evb -kernel boot.elf -semihosting diff --git a/platforms/qemu_lm3s/main.c b/platforms/qemu_lm3s/main.c index 9aa5bdc..725a642 100644 --- a/platforms/qemu_lm3s/main.c +++ b/platforms/qemu_lm3s/main.c @@ -79,8 +79,8 @@ main (void) uint32_t failures ; printf ("Atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ; - atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; - atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); + 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 ; diff --git a/ports/arm/atomport.h b/ports/arm/atomport.h index f7ac10d..f07e75a 100644 --- a/ports/arm/atomport.h +++ b/ports/arm/atomport.h @@ -32,8 +32,17 @@ #include "types.h" -#define SYSTEM_TICKS_PER_SEC 100 +#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. + */ +#define NULL ((void *)(0)) + +/* Size of each stack entry / stack alignment size (e.g. 32 bits) */ +#define STACK_ALIGN_SIZE sizeof(unsigned int) /** * Architecture-specific types. @@ -47,12 +56,17 @@ * Functions defined in atomport_arm.asm * */ -extern void contextInit (void) ; -extern uint32_t contextEnterCritical (void) ; -extern void contextExitCritical (uint32_t posture) ; +extern void contextInit (void) ; +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; -/* Critical region protection */ +/** + * 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) diff --git a/ports/cortex_m/atomport.h b/ports/cortex_m/atomport.h index f7ac10d..1a4cfd9 100644 --- a/ports/cortex_m/atomport.h +++ b/ports/cortex_m/atomport.h @@ -32,7 +32,23 @@ #include "types.h" -#define SYSTEM_TICKS_PER_SEC 100 +#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. + */ +#define NULL ((void *)(0)) + +/* 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. + */ /** @@ -47,9 +63,9 @@ * Functions defined in atomport_arm.asm * */ -extern void contextInit (void) ; -extern uint32_t contextEnterCritical (void) ; -extern void contextExitCritical (uint32_t posture) ; +extern void contextInit (void) ; +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; /* Critical region protection */ @@ -58,3 +74,4 @@ extern void contextExitCritical (uint32_t posture) ; #define CRITICAL_END() contextExitCritical(__atom_critical) #endif /* __ATOM_PORT_H__ */ + From 599549535062d7275e52a754d5632f896d0ae986 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Thu, 27 Sep 2012 12:18:00 +0200 Subject: [PATCH 19/28] Updated for new stack alignment changes in atom.h. --- platforms/qemu_integratorcp/Makefile | 11 +++++++---- platforms/qemu_integratorcp/README | 4 +++- platforms/qemu_integratorcp/main.c | 4 ++-- platforms/qemu_lm3s/Makefile | 4 ++-- platforms/qemu_lm3s/README | 4 ++++ platforms/qemu_lm3s/main.c | 4 ++-- ports/arm/README | 4 ++-- ports/arm/atomport.h | 24 +++++++++++++++++++----- ports/cortex_m/atomport.h | 25 +++++++++++++++++++++---- 9 files changed, 62 insertions(+), 22 deletions(-) diff --git a/platforms/qemu_integratorcp/Makefile b/platforms/qemu_integratorcp/Makefile index e88e47d..efed519 100644 --- a/platforms/qemu_integratorcp/Makefile +++ b/platforms/qemu_integratorcp/Makefile @@ -44,7 +44,7 @@ include ../rules.mk run_test: clean all echo "START TEST $(TEST_NAME)" - qemu-system-arm -M integratorcp -kernel boot.elf -semihosting | tee atomthreads_test.out + qemu-system-arm -M integratorcp -kernel boot.elf -semihosting >> atomthreads_test.out all_tests: echo "Starting atomthreads test suite" > atomthreads_test.out @@ -60,7 +60,6 @@ all_tests: 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" @@ -86,6 +85,10 @@ all_tests: make run_test "TEST_NAME=sem8" make run_test "TEST_NAME=sem9" -run_last: - qemu-system-arm -M integratorcp -kernel boot.elf -monitor stdio -semihosting +fail_tests: + make run_test "TEST_NAME=kern4" + + +run_last: + qemu-system-arm -M integratorcp -kernel boot.elf -semihosting diff --git a/platforms/qemu_integratorcp/README b/platforms/qemu_integratorcp/README index 5deb509..0177f81 100644 --- a/platforms/qemu_integratorcp/README +++ b/platforms/qemu_integratorcp/README @@ -9,4 +9,6 @@ License: BSD Revised QEMU ARM Integrator/CP (ARM926EJ-S) Platform The "qemu_integratorcp" platform contains sources for building a sample -Atomthreads application for the ARM Integrator/CP (ARM926EJ-S) platform. \ No newline at end of file +Atomthreads application for the ARM Integrator/CP (ARM926EJ-S) platform. +BUGS: +kern4 testcase fails (sometimes). \ No newline at end of file diff --git a/platforms/qemu_integratorcp/main.c b/platforms/qemu_integratorcp/main.c index 3222170..aebdd3d 100644 --- a/platforms/qemu_integratorcp/main.c +++ b/platforms/qemu_integratorcp/main.c @@ -77,8 +77,8 @@ main (void) printf ("atomthreads starting %s... ", ATOMTHREADS_TEST) ; - atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; - atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); + 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 ; diff --git a/platforms/qemu_lm3s/Makefile b/platforms/qemu_lm3s/Makefile index c8568ad..dc9c117 100644 --- a/platforms/qemu_lm3s/Makefile +++ b/platforms/qemu_lm3s/Makefile @@ -85,11 +85,11 @@ all_tests: make run_test "TEST_NAME=sem8" make run_test "TEST_NAME=sem9" -all_fail: +fail_tests: make run_test "TEST_NAME=mutex4" make run_test "TEST_NAME=sem4" run_last: - qemu-system-arm -M lm3s6965evb -kernel boot.elf -monitor stdio -semihosting + qemu-system-arm -M lm3s6965evb -kernel boot.elf -semihosting diff --git a/platforms/qemu_lm3s/README b/platforms/qemu_lm3s/README index 6e340d1..bdd09ab 100644 --- a/platforms/qemu_lm3s/README +++ b/platforms/qemu_lm3s/README @@ -31,3 +31,7 @@ Fixes implemented for the QEMU 1.2.0 release: 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. \ No newline at end of file diff --git a/platforms/qemu_lm3s/main.c b/platforms/qemu_lm3s/main.c index 9aa5bdc..725a642 100644 --- a/platforms/qemu_lm3s/main.c +++ b/platforms/qemu_lm3s/main.c @@ -79,8 +79,8 @@ main (void) uint32_t failures ; printf ("Atomthreads starting %s... \r\n", ATOMTHREADS_TEST) ; - atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; - atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); + 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 ; diff --git a/ports/arm/README b/ports/arm/README index 8fa5797..e471306 100644 --- a/ports/arm/README +++ b/ports/arm/README @@ -9,8 +9,8 @@ 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 Cortex A9, Cortex A15 -and the ARM926EJ-S (QEMU). +ARM processor architecture. This port was tested on the ARMv5 and ARMv7 +architectures. To Use: diff --git a/ports/arm/atomport.h b/ports/arm/atomport.h index f7ac10d..f07e75a 100644 --- a/ports/arm/atomport.h +++ b/ports/arm/atomport.h @@ -32,8 +32,17 @@ #include "types.h" -#define SYSTEM_TICKS_PER_SEC 100 +#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. + */ +#define NULL ((void *)(0)) + +/* Size of each stack entry / stack alignment size (e.g. 32 bits) */ +#define STACK_ALIGN_SIZE sizeof(unsigned int) /** * Architecture-specific types. @@ -47,12 +56,17 @@ * Functions defined in atomport_arm.asm * */ -extern void contextInit (void) ; -extern uint32_t contextEnterCritical (void) ; -extern void contextExitCritical (uint32_t posture) ; +extern void contextInit (void) ; +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; -/* Critical region protection */ +/** + * 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) diff --git a/ports/cortex_m/atomport.h b/ports/cortex_m/atomport.h index f7ac10d..1a4cfd9 100644 --- a/ports/cortex_m/atomport.h +++ b/ports/cortex_m/atomport.h @@ -32,7 +32,23 @@ #include "types.h" -#define SYSTEM_TICKS_PER_SEC 100 +#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. + */ +#define NULL ((void *)(0)) + +/* 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. + */ /** @@ -47,9 +63,9 @@ * Functions defined in atomport_arm.asm * */ -extern void contextInit (void) ; -extern uint32_t contextEnterCritical (void) ; -extern void contextExitCritical (uint32_t posture) ; +extern void contextInit (void) ; +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; /* Critical region protection */ @@ -58,3 +74,4 @@ extern void contextExitCritical (uint32_t posture) ; #define CRITICAL_END() contextExitCritical(__atom_critical) #endif /* __ATOM_PORT_H__ */ + From 9ebb4d14b4b362b1c2b7be19483ce97e99b4c511 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Thu, 27 Sep 2012 21:46:59 +0200 Subject: [PATCH 20/28] white space --- platforms/qemu_integratorcp/README | 1 + platforms/qemu_integratorcp/modules.c | 8 +- platforms/qemu_integratorcp/modules.h | 38 ++++----- platforms/qemu_integratorcp/startup.s | 4 - platforms/qemu_lm3s/modules.c | 84 +++++++++--------- platforms/qemu_lm3s/modules.h | 118 +++++++++++++------------- 6 files changed, 128 insertions(+), 125 deletions(-) diff --git a/platforms/qemu_integratorcp/README b/platforms/qemu_integratorcp/README index 0177f81..d8b53c9 100644 --- a/platforms/qemu_integratorcp/README +++ b/platforms/qemu_integratorcp/README @@ -10,5 +10,6 @@ QEMU ARM Integrator/CP (ARM926EJ-S) Platform The "qemu_integratorcp" platform contains sources for building a sample Atomthreads application for the ARM Integrator/CP (ARM926EJ-S) platform. + BUGS: kern4 testcase fails (sometimes). \ No newline at end of file diff --git a/platforms/qemu_integratorcp/modules.c b/platforms/qemu_integratorcp/modules.c index c611d68..a6ee156 100644 --- a/platforms/qemu_integratorcp/modules.c +++ b/platforms/qemu_integratorcp/modules.c @@ -46,16 +46,16 @@ ICP_PIC_T * const board_pic = (ICP_PI void dbg_format_msg (char *format, ...) { - va_list args; - static char msg[256] ; + va_list args; + static char msg[256] ; CRITICAL_STORE ; va_start (args, format) ; CRITICAL_START() ; - vsnprintf ((char*)msg, 256, (char*)format, args) ; + vsnprintf ((char*)msg, 256, (char*)format, args) ; + printf (msg) ; CRITICAL_END() ; - printf (msg) ; } /** diff --git a/platforms/qemu_integratorcp/modules.h b/platforms/qemu_integratorcp/modules.h index 58a48ed..a94140a 100644 --- a/platforms/qemu_integratorcp/modules.h +++ b/platforms/qemu_integratorcp/modules.h @@ -59,21 +59,21 @@ typedef struct ICP_TIMER_S { // -------- 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 +#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 +#define ICP_TIMER_INT ((unsigned int)0x01 << 0) // Interrupt // -------- ICP_TIMER_BGLOAD : (BGLOAD Offset: 0x18) Timer masked interrupt status -------- @@ -100,19 +100,19 @@ typedef struct ICP_PIC_S { // -------- 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 +#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 +#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 ; diff --git a/platforms/qemu_integratorcp/startup.s b/platforms/qemu_integratorcp/startup.s index 0c3675d..a19ea76 100644 --- a/platforms/qemu_integratorcp/startup.s +++ b/platforms/qemu_integratorcp/startup.s @@ -5,10 +5,6 @@ .extern __fiq_stack_top__ .extern __svc_stack_top__ -.global bsp_ints_enable -.global bsp_ints_disable -.global bsp_ints_restore - .equ USR_MODE, 0x10 .equ FIQ_MODE, 0x11 diff --git a/platforms/qemu_lm3s/modules.c b/platforms/qemu_lm3s/modules.c index c375e4e..10c0058 100644 --- a/platforms/qemu_lm3s/modules.c +++ b/platforms/qemu_lm3s/modules.c @@ -49,13 +49,13 @@ GPTM_TIMER_T * const board_gptm0 = (GPTM_TIMER_T*) void dbg_format_msg (char *format, ...) { - va_list args; - static char msg[256] ; + va_list args; + static char msg[256] ; CRITICAL_STORE ; va_start (args, format) ; CRITICAL_START() ; - vsnprintf ((char*)msg, 256, (char*)format, args) ; + vsnprintf ((char*)msg, 256, (char*)format, args) ; printf (msg) ; CRITICAL_END() ; @@ -92,7 +92,7 @@ low_level_init (void) /** - * \b __context_preempt_handler + * \b __context_tick_handler * * System timer tic interupt handler. * @@ -113,44 +113,50 @@ __context_tick_handler (void) } +/** + * \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); + 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); diff --git a/platforms/qemu_lm3s/modules.h b/platforms/qemu_lm3s/modules.h index 8d3bb4c..5a074b4 100644 --- a/platforms/qemu_lm3s/modules.h +++ b/platforms/qemu_lm3s/modules.h @@ -46,26 +46,26 @@ typedef volatile unsigned char REG_BYTE ; // ***************************************************************************** typedef struct GPTM_TIMER_S { - // offset read/write reset Description - REG_DWORD CFG ; // 0x000 R/W 0x00000000 GPTM Configuration 345 - REG_DWORD TAMR ; // 0x004 R/W 0x00000000 GPTM TimerA Mode 346 - REG_DWORD TBMR ; // 0x008 R/W 0x00000000 GPTM TimerB Mode 348 - REG_DWORD CTL ; // 0x00C R/W 0x00000000 GPTM Control 350 - REG_DWORD Reserved[2] ; // 0x010 - REG_DWORD IMR ; // 0x018 R/W 0x00000000 GPTM Interrupt Mask 353 - REG_DWORD RIS ; // 0x01C RO 0x00000000 GPTM Raw Interrupt Status 355 - REG_DWORD MIS ; // 0x020 RO 0x00000000 GPTM Masked Interrupt Status 356 - REG_DWORD ICR ; // 0x024 W1C 0x00000000 GPTM Interrupt Clear 357 - REG_DWORD TAILR ; // 0x028 R/W 0xFFFFFFFF GPTM TimerA Interval Load 359 - REG_DWORD TBILR ; // 0x02C R/W 0x0000FFFF GPTM TimerB Interval Load 360 - REG_DWORD TAMATCHR ; // 0x030 R/W 0xFFFFFFFF GPTM TimerA Match 361 - REG_DWORD TBMATCHR ; // 0x034 R/W 0x0000FFFF GPTM TimerB Match 362 - REG_DWORD TAPR ; // 0x038 R/W 0x00000000 GPTM TimerA Prescale 363 - REG_DWORD TBPR ; // 0x03C R/W 0x00000000 GPTM TimerB Prescale 364 - REG_DWORD TAPMR ; // 0x040 R/W 0x00000000 GPTM TimerA Prescale Match 365 - REG_DWORD TBPMR ; // 0x044 R/W 0x00000000 GPTM TimerB Prescale Match 366 - REG_DWORD TAR ; // 0x048 RO 0xFFFFFFFF GPTM TimerA 367 - REG_DWORD TBR ; // 0x04C RO 0x0000FFFF GPTM TimerB 368 + // offset read/write reset Description + REG_DWORD CFG ; // 0x000 R/W 0x00000000 GPTM Configuration 345 + REG_DWORD TAMR ; // 0x004 R/W 0x00000000 GPTM TimerA Mode 346 + REG_DWORD TBMR ; // 0x008 R/W 0x00000000 GPTM TimerB Mode 348 + REG_DWORD CTL ; // 0x00C R/W 0x00000000 GPTM Control 350 + REG_DWORD Reserved[2] ; // 0x010 + REG_DWORD IMR ; // 0x018 R/W 0x00000000 GPTM Interrupt Mask 353 + REG_DWORD RIS ; // 0x01C RO 0x00000000 GPTM Raw Interrupt Status 355 + REG_DWORD MIS ; // 0x020 RO 0x00000000 GPTM Masked Interrupt Status 356 + REG_DWORD ICR ; // 0x024 W1C 0x00000000 GPTM Interrupt Clear 357 + REG_DWORD TAILR ; // 0x028 R/W 0xFFFFFFFF GPTM TimerA Interval Load 359 + REG_DWORD TBILR ; // 0x02C R/W 0x0000FFFF GPTM TimerB Interval Load 360 + REG_DWORD TAMATCHR ; // 0x030 R/W 0xFFFFFFFF GPTM TimerA Match 361 + REG_DWORD TBMATCHR ; // 0x034 R/W 0x0000FFFF GPTM TimerB Match 362 + REG_DWORD TAPR ; // 0x038 R/W 0x00000000 GPTM TimerA Prescale 363 + REG_DWORD TBPR ; // 0x03C R/W 0x00000000 GPTM TimerB Prescale 364 + REG_DWORD TAPMR ; // 0x040 R/W 0x00000000 GPTM TimerA Prescale Match 365 + REG_DWORD TBPMR ; // 0x044 R/W 0x00000000 GPTM TimerB Prescale Match 366 + REG_DWORD TAR ; // 0x048 RO 0xFFFFFFFF GPTM TimerA 367 + REG_DWORD TBR ; // 0x04C RO 0x0000FFFF GPTM TimerB 368 } GPTM_TIMER_T, *PGPTM_TIMER_T ; @@ -81,36 +81,36 @@ typedef struct GPTM_TIMER_S { #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 +#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 +#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 @@ -131,10 +131,10 @@ typedef struct SYSTICK_S { } 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. +#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 -------- @@ -155,7 +155,7 @@ typedef struct NVIC_S { REG_DWORD Res6[30] ; // 0xE000E2A0 REG_DWORD IABR[2] ; // 0xE000E300 REG_DWORD Res7[64] ; // 0xE000E320 - REG_DWORD IPR[2] ; // 0xE000E400 + REG_DWORD IPR[2] ; // 0xE000E400 // REG_DWORD Res7[515] ; // 0xE000E4F4 } NVIC_T, *PNVIC_T ; @@ -192,15 +192,15 @@ typedef struct SCB_S { /* 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 +#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 ; +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 */ From 6f34e08e2f52813dd2f23b9ed234123420a8d4cb Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Wed, 3 Oct 2012 21:19:44 +0200 Subject: [PATCH 21/28] Updates to the atomvm port. --- ports/atomvm/{README.txt => README} | 22 +- ports/atomvm/atomport-tests.h | 5 +- ports/atomvm/atomport.c | 19 +- ports/atomvm/atomport.h | 28 +- ports/atomvm/atomvm.c | 394 ++++-------------- ports/atomvm/atomvm.h | 59 ++- ports/atomvm/{test => msvc}/main.c | 540 ++++++++++++------------- ports/atomvm/msvc/msvc.sln | 20 + ports/atomvm/msvc/msvc.vcxproj | 102 +++++ ports/atomvm/msvc/msvc.vcxproj.filters | 67 +++ ports/atomvm/{atomuser.h => types.h} | 124 +++--- 11 files changed, 646 insertions(+), 734 deletions(-) rename ports/atomvm/{README.txt => README} (51%) rename ports/atomvm/{test => msvc}/main.c (85%) create mode 100644 ports/atomvm/msvc/msvc.sln create mode 100644 ports/atomvm/msvc/msvc.vcxproj create mode 100644 ports/atomvm/msvc/msvc.vcxproj.filters rename ports/atomvm/{atomuser.h => types.h} (96%) diff --git a/ports/atomvm/README.txt b/ports/atomvm/README similarity index 51% rename from ports/atomvm/README.txt rename to ports/atomvm/README index 7a07533..b912b47 100644 --- a/ports/atomvm/README.txt +++ b/ports/atomvm/README @@ -6,11 +6,18 @@ 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. +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. --------------------------------------------------------------------------- @@ -28,9 +35,6 @@ 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. +The test, main.c, is intentioned to stress the virtual machine. diff --git a/ports/atomvm/atomport-tests.h b/ports/atomvm/atomport-tests.h index 9f5320d..354acc7 100644 --- a/ports/atomvm/atomport-tests.h +++ b/ports/atomvm/atomport-tests.h @@ -27,8 +27,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __ATOM_PORT_TESTS_H -#define __ATOM_PORT_TESTS_H +#ifndef __ATOMPORT_TEST_H__ +#define __ATOMPORT_TEST_H__ /* Include Atomthreads kernel API */ #include "atom.h" @@ -56,3 +56,4 @@ #endif /* __ATOM_PORT_TESTS_H */ +#endif /* __ATOMPORT_TEST_H__ */ diff --git a/ports/atomvm/atomport.c b/ports/atomvm/atomport.c index a4de433..a9bc46f 100644 --- a/ports/atomvm/atomport.c +++ b/ports/atomvm/atomport.c @@ -53,7 +53,7 @@ static HANDLE cntrl_thread ; void atomvmRun () { - atomvmCtrlInit (&the_atomvm) ; + atomvmCtrlCreate (&the_atomvm) ; cntrl_thread = CreateThread (NULL, 0, cntrl_thread_proc, (uint32_t*)the_atomvm, CREATE_SUSPENDED, NULL) ; ResumeThread (cntrl_thread) ; } @@ -85,7 +85,8 @@ thread_shell (void) * is first restored. */ // sei(); - atomvmExitCritical () ; + //atomvmExitCritical () ; + atomvmInterruptMask (0) ; /* Call the thread entry point */ if (curr_tcb && curr_tcb->entry_point) @@ -156,17 +157,3 @@ void archTimerTickIrqHandler () /* Call the interrupt exit routine */ atomIntExit(TRUE); } - - -unsigned int -__enter_critical () -{ - return atomvmEnterCritical () ; -} - - -void -__exit_critical (unsigned int isr) -{ - atomvmExitCritical () ; -} diff --git a/ports/atomvm/atomport.h b/ports/atomvm/atomport.h index 1022e3e..84edb64 100644 --- a/ports/atomvm/atomport.h +++ b/ports/atomvm/atomport.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Kelvin Lawson. All rights reserved. + * 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 @@ -32,19 +32,9 @@ #include "atomvm.h" -#define SYSTEM_MEMALIGN sizeof (unsigned int) #define SYSTEM_TICKS_PER_SEC 100 - - -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 ; - +/* Size of each stack entry / stack alignment size (e.g. 32 bits) */ +#define STACK_ALIGN_SIZE sizeof(unsigned int) /** * Architecture-specific types. @@ -52,15 +42,13 @@ typedef char int8_t ; * included above. */ #define POINTER void * +#define ATOM_TLS HATOMVM_CONTEXT context ; /* Critical region protection */ -extern unsigned int __enter_critical() ; -extern void __exit_critical(unsigned int) ; - -#define CRITICAL_STORE unsigned int __atom -#define CRITICAL_START() __atom = __enter_critical() -#define CRITICAL_END() __exit_critical(__atom) +#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 ; @@ -71,4 +59,4 @@ extern void archTimerTickIrqHandler () ; /* The instance of the atomvm for this port */ extern HATOMVM the_atomvm ; -#endif /* __ATOM_PORT_H */ +#endif /* __ATOM_PORT_H__ */ diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c index 286428a..f6ff3a9 100644 --- a/ports/atomvm/atomvm.c +++ b/ports/atomvm/atomvm.c @@ -39,18 +39,21 @@ * * \b Function prototypes used for controlling the atom virtual machine: \n * - * \li atomvmCtrlInit(): . + * \li atomvmCtrlCreate(): . * \li atomvmCtrlRun(): . * \li atomvmCtrlIntRequest(): . * \li atomvmCtrlClose(): . * * \b Function prototypes for use by the atom virtual machine: \n * - * \li atomvmExitCritical(): . - * \li atomvmEnterCritical(): . + * \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 * @@ -67,8 +70,6 @@ #define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS) -#define ATOMVM_ATOMVM_PERF_COUNTER(patomvm, counter) (InterlockedIncrement(&patomvm->perf_counters.counter)) - /* Data types */ /* Forward declarations */ @@ -118,32 +119,6 @@ typedef struct ATOMVM_CALLBACK_CONTEXT_SWITCH_S { } ATOMVM_CALLBACK_CONTEXT_SWITCH, *PATOMVM_CALLBACK_CONTEXT_SWITCH ; -/* ATOMVM_CALLBACK_IPI is the parameter for a ATOMVM_CALLBACK_F call -that take as parameter a pointer to a ipi target and the isr to call */ -typedef struct ATOMVM_CALLBACK_IPI_S { - - ATOMVM_CALLBACK callback ; - - /* Parameters the callback function will operate on */ - volatile uint32_t target ; - volatile uint32_t isr ; - -} ATOMVM_CALLBACK_IPI, *PATOMVM_CALLBACK_IPI ; - -typedef struct ATOMVM_PERF_COUNTERS_S { - - /* Number of interrupt requests */ - uint32_t int_request ; - - /* Number of service calls (context switches and - context init from atom virtual machime) */ - uint32_t service_call ; - - /* Total number of context switches */ - uint32_t context_switch ; - -} ATOMVM_PERF_COUNTERS, *PATOMVM_PERF_COUNTERS ; - /* ATOMVM_CONTEXT saves the state of a context created by atomvmContextCreate() and sheduled by atomvmContextSwitch(). */ typedef struct ATOMVM_CONTEXT_S { @@ -152,18 +127,16 @@ typedef struct ATOMVM_CONTEXT_S { during context initialization and context switches */ CONTEXT context ; - /* When entering a critical section the critical_count is - incremented for the context. Interrupts will only occur while - the critical_count is zero. The functions atomvmExitCritical() - and atomvmEnterCritical() will respectively decrement and - increment the critical count */ - volatile uint32_t critical_count ; + /* 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 atomvmCtrlInit(). */ +by a call to atomvmCtrlCreate(). */ typedef struct ATOMVM_S { uint32_t atomvm_id ; @@ -176,7 +149,6 @@ typedef struct ATOMVM_S { HANDLE atomvm_int ; HANDLE atomvm_int_complete ; HANDLE atomvm_close ; - HANDLE atomvm_event ; /* next ISR */ volatile void (*isr)(void) ; @@ -191,21 +163,15 @@ typedef struct ATOMVM_S { and, return value for the current service call */ PATOMVM_CALLBACK service_call ; - /* Context for startup, before any context was scheduled - (workaround to not check everytime if the first context - was already started) */ + /* Context for startup, before any context was scheduled */ ATOMVM_CONTEXT atom_init_context ; - /* Performance counters */ - volatile ATOMVM_PERF_COUNTERS perf_counters ; - } ATOMVM, *PATOMVM ; /* Global declarations */ -volatile uint32_t g_atomvm_counter = 0 ; -volatile DWORD g_atomvm_tls_idx ; -PATOMVM g_vms[ATOMVM_MAX_VM] ; +volatile uint32_t g_atomvm_id = 0 ; +volatile DWORD g_atomvm_tls_idx ; /* Forward declaration for the atom virtual machine thread */ @@ -214,57 +180,52 @@ static DWORD WINAPI vm_thread (LPVOID lpParameter) ; /** * \ingroup atomvm -* \b atomvmCtrlInit +* \b atomvmCtrlCreate * * This is an atomvm controll function used by a controlling thread * and must not be called from the atom virtual machine. * * Initializes the virtual machine. * -* ToDo: More Error checking. -* * @param[out] atomvm Handle to the virtual machine created. * * @return Zero on failure. */ uint32_t -atomvmCtrlInit (HATOMVM *atomvm) +atomvmCtrlCreate (HATOMVM *atomvm) { PATOMVM patomvm = 0 ; int32_t i ; - if (g_atomvm_counter < ATOMVM_MAX_VM) { + patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ; - patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ; + if (patomvm) { - if (patomvm) { + memset (patomvm, 0, sizeof(struct ATOMVM_S)) ; - memset (patomvm, 0, sizeof(struct ATOMVM_S)) ; - - patomvm->atomvm_id = InterlockedIncrement(&g_atomvm_counter) - 1 ; - - if (patomvm->atomvm_id == 0) { - g_atomvm_tls_idx = TlsAlloc () ; - for (i=0; iatomvm_id] = patomvm ; - - 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) ; - patomvm->atomvm_event = CreateEvent (NULL, FALSE, FALSE, 0) ; - - patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, (void*)patomvm, CREATE_SUSPENDED, NULL) ; - - patomvm->atom_init_context.critical_count = 1 ; - patomvm->current_context = &patomvm->atom_init_context ; - - *atomvm = (HATOMVM)patomvm ; + 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 ; @@ -275,16 +236,13 @@ atomvmCtrlInit (HATOMVM *atomvm) * \ingroup atomvm * \b atomvmCtrlRun * -* This is an atomvm controll function used by a controlling thread -* and must not be called from the atom virtual machine. -* -* After a call to atomvmCtrlInit this function start the atom virtual machine. +* 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 atomvmCtrlInit. -* @param[in] flags Reserved for later use. +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate. +* @param[in] flags not used. * * @return None */ @@ -299,9 +257,7 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) #if defined DEBUG || defined _DEBUG BOOL tls_res = #endif - TlsSetValue (g_atomvm_tls_idx, (void*) atomvm) ; - - + TlsSetValue (g_atomvm_tls_idx, (void*) atomvm) ; ATOMVM_ASSERT(tls_res, _T("TlsSetValue failed")) ; ResumeThread (patomvm->vm_thread) ; @@ -316,8 +272,6 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) if (wait_object == WAIT_OBJECT_0) { - ATOMVM_ATOMVM_PERF_COUNTER(patomvm, service_call) ; - service_call = patomvm->service_call ; while (!service_call->lock) { SwitchToThread () ; @@ -336,25 +290,23 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) 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->critical_count == 0) { + 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. */ + is stopped before executing the next instruction. Set + _WIN32_WINNT < 0x0600 if you are running Windows XP */ FlushProcessWriteBuffers (); #endif - if (patomvm->current_context->critical_count == 0) { - - ATOMVM_ATOMVM_PERF_COUNTER(patomvm, int_request) ; + if (patomvm->current_context->interrupt_mask == 0) { patomvm->status_isr++ ; patomvm->isr () ; @@ -404,11 +356,11 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) * and must not be called from the atom virtual machine. * * Closes the virtual machine and release all memory and handles created -* in atomvmCtrlInit. +* in atomvmCtrlCreate. * * ToDo: this function was never tested. * -* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit. +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate. * * @return None */ @@ -432,7 +384,7 @@ atomvmCtrlClose (HATOMVM atomvm) CloseHandle (patomvm->atomvm_close) ; CloseHandle (patomvm->vm_thread) ; - TlsFree (g_atomvm_tls_idx) ; + // TlsFree (g_atomvm_tls_idx) ; free (atomvm) ; } @@ -446,9 +398,9 @@ atomvmCtrlClose (HATOMVM atomvm) * an isr it is already in the conrtext of the controll thread and the callback * routine is called directly. * -* The atom virtual machine is suspended during the callback. +* The atom virtual machine thread is suspended during the callback. * -* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @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. * @@ -483,12 +435,12 @@ invokeCallback (PATOMVM patomvm, ATOMVM_CALLBACK_F callback, PATOMVM_CALLBACK se /* * \b getAtomvm * -* Get the atomvm instance for the calling thredd +* Get the atomvm instance for the calling thread * * @return atomvm instance */ __inline PATOMVM -getAtomvm () +getAtomvm (void) { PATOMVM patomvm = (PATOMVM) TlsGetValue (g_atomvm_tls_idx) ; @@ -498,76 +450,29 @@ getAtomvm () } - /** * \ingroup atomvm -* \b atomvmExitCritical +* \b atomvmInterruptMask * * This function is to be used by the atom virtual machine. * -* This function will decrement the critical count for the current atomvm context. -* When the critical count reaches zero, interrupts will be enabled again. Calling -* this function from inside an isr has no effect. +* This function will mask interrupts for the current atomvm context. * -* @return Critical count before the function call. +* @param[in] mask zero enables interrupts any other value masks interrupts. +* +* @return Interrupt mask before the function call. */ int32_t -atomvmExitCritical () +atomvmInterruptMask (uint32_t mask) { PATOMVM patomvm = getAtomvm () ; - int32_t count = 0; + int32_t interrupts = 0; if (patomvm->status_isr == 0) { - count = InterlockedDecrement (&patomvm->current_context->critical_count) ; + interrupts = InterlockedExchange (&patomvm->current_context->interrupt_mask, mask) ; } - return count ; -} - - -/** -* \ingroup atomvm -* \b atomvmEnterCritical -* -* This function is to be used by the atom virtual machine. -* -* This function will increment the critical count for the current atomvm -* context. Interrupts will be disabled when the critical count is not zero. -* Calling this function from inside an isr has no effect. -* -* All threads are created with a critical count of 1. -* -* -* @return Critical count before the function call. -*/ -int32_t -atomvmEnterCritical () -{ - PATOMVM patomvm = getAtomvm () ; - int32_t count = 0 ; - - if (patomvm->status_isr == 0) { - count = InterlockedIncrement (&patomvm->current_context->critical_count) ; - } - - return count ; -} - - -/** -* \ingroup atomvm -* \b atomvmCriticalCount -* -* Rerurns the critical cont of the current context. -* -* @return the critical cont of the current context. -*/ -int32_t -atomvmCriticalCount () -{ - PATOMVM patomvm = getAtomvm () ; - - return patomvm->current_context->critical_count ; + return interrupts ; } @@ -575,17 +480,17 @@ atomvmCriticalCount () * \ingroup atomvm * \b atomvmCtrlIntRequest * -* This is an atomvm controll function used by a controlling thread(s) +* 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 atomvmCtrlInit. -* @param[in] isr The address of the interrupt service routine. The routine must use -* the default calling convention of the compiler. +* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate. +* @param[in] isr The address of the interrupt service routine. * * @return None */ @@ -610,7 +515,7 @@ atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) * * The atom virtual machine is suspended while this function is called. * -* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @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(). @@ -654,7 +559,7 @@ atomvmContextCreate (HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t e context_init.pcontext = new_context ; - new_context->critical_count = 1 ; + new_context->interrupt_mask = 1 ; res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ; @@ -676,7 +581,7 @@ atomvmContextCreate (HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t e * * The atom virtual machine is suspended while this function is called. * -* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @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(). @@ -690,8 +595,6 @@ callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback) CONTEXT* p_old_context = &context_switch->p_old_context->context ; CONTEXT* p_new_context = &context_switch->p_new_context->context ; - ATOMVM_ATOMVM_PERF_COUNTER(patomvm, context_switch) ; - if (p_old_context) { res1 = GetThreadContext (patomvm->vm_thread, p_old_context) ; ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ; @@ -783,7 +686,7 @@ atomvmWriteThreadId (uint32_t thread_id) * @return thread_id */ uint32_t -atomvmReadThreadId () +atomvmReadThreadId (void) { PATOMVM patomvm = getAtomvm () ; @@ -796,103 +699,18 @@ atomvmReadThreadId () * \b atomvmGetVmId * * Returns an identifier for the virtual machine. This is zero for the first -* virtual machine created with atomvmCtrlInit(), 1 for the second and so on. +* virtual machine created with atomvmCtrlCreate(), 1 for the second and so on. * * @return The atom vm ID */ uint32_t -atomvmGetVmId () +atomvmGetVmId (void) { PATOMVM patomvm = getAtomvm () ; return patomvm->atomvm_id ; } -/** -* \b callbackEventWait -* -* This function is invoked from the controll thread after a call to atomvmEventWait. -* -* The atom virtual machine is suspended while this function is called. -* -* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. -* @param[out] context Context to be scheduled. -* -* @return Zero on failure, try to call GetLastError(). -*/ -uint32_t -callbackEventWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) -{ - return WaitForSingleObject (patomvm->atomvm_event, INFINITE) == WAIT_OBJECT_0 ; -} - - -/** -* \ingroup atomvm -* \b atomvmEventWait -* -* This function is to be used by the atom virtual machine. -* -* This function if for synchronization between multiple -* atom vms. -* -* -* @return void. -*/ -void -atomvmEventWait () -{ - PATOMVM patomvm = getAtomvm () ; - ATOMVM_CALLBACK callback ; - - invokeCallback (patomvm, callbackEventWait, (PATOMVM_CALLBACK)&callback) ; -} - -/** -* \b callbackEventSend -* -* This function is invoked from the controll thread after a call to atomvmEventSend. -* -* The atom virtual machine is suspended while this function is called. -* -* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. -* @param[out] context Context to be scheduled. -* -* @return Zero on failure, try to call GetLastError(). -*/ -uint32_t -callbackEventSend (PATOMVM patomvm, PATOMVM_CALLBACK callback) -{ - int32_t i ; - for (i=0; iatomvm_event) ; - } - } - - return 1 ; -} - -/** -* \ingroup atomvm -* \b atomvmEventSend -* -* This function is to be used by the atom virtual machine. -* -* This function if for synchronization between multiple -* atom vms. -* -* -* @return void. -*/ -void -atomvmEventSend () -{ - PATOMVM patomvm = getAtomvm () ; - ATOMVM_CALLBACK callback ; - - invokeCallback (patomvm, callbackEventSend, (PATOMVM_CALLBACK)&callback) ; -} /** * \b callbackInterruptWait @@ -901,7 +719,7 @@ atomvmEventSend () * * The atom virtual machine is suspended while this function is called. * -* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate. * @param[out] callback Callback parameter. * * @return Zero on failure, try to call GetLastError(). @@ -926,7 +744,7 @@ callbackInterruptWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) * @return void. */ void -atomvmInterruptWait () +atomvmInterruptWait (void) { PATOMVM patomvm = getAtomvm () ; ATOMVM_CALLBACK callback ; @@ -934,66 +752,6 @@ atomvmInterruptWait () invokeCallback (patomvm, callbackInterruptWait, (PATOMVM_CALLBACK)&callback) ; } -/** -* \ingroup atomvm -* \b callbackScheduleIpi -* -* This function is invoked from the controll thread after a call to atomvmScheduleIpi(). -* -* This function if for synchronization between multiple -* atom vms. -* -* @param[in] target Target atomvm ID, less than ATOMVM_MAX_VM -* @param[in] isr interrupt service routine -* -* @return Zero on failure, try to call GetLastError(). -*/ -uint32_t -callbackScheduleIpi (PATOMVM patomvm, PATOMVM_CALLBACK callback) -{ - PATOMVM_CALLBACK_IPI callback_ipi = (PATOMVM_CALLBACK_IPI)callback ; - uint32_t res = 0 ; - - if ((callback_ipi->target < ATOMVM_MAX_VM) && - (g_vms[callback_ipi->target] != patomvm) ) { - - atomvmCtrlIntRequest ((HATOMVM)g_vms[callback_ipi->target], callback_ipi->isr) ; - res = 1 ; - - } - - return res ; -} - - -/** -* \ingroup atomvm -* \b atomvmScheduleIpi -* -* This function is to be used by the atom virtual machine. -* -* This function if for synchronization between multiple -* atom vms. -* -* @param[in] target Target atomvm ID -* @param[in] isr interrupt service routine -* -* @return Zero on failure, the vm is not running. -*/ -uint32_t -atomvmScheduleIpi (uint32_t target, uintptr_t isr) -{ - PATOMVM patomvm = getAtomvm () ; - ATOMVM_CALLBACK_IPI callback ; - - callback.target = target ; - callback.isr = isr ; - - return invokeCallback (patomvm, callbackScheduleIpi, (PATOMVM_CALLBACK)&callback) ; - - -} - /** * \b vm_thread diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h index 0b61570..24e2a99 100644 --- a/ports/atomvm/atomvm.h +++ b/ports/atomvm/atomvm.h @@ -35,32 +35,26 @@ * @authors Natie van Rooyen * * @section intro Introduction -* 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.: +* 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. * -* @section build 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 main.c to your project. Add both the -* before mentioned directories to the include paths of your project and compile. \n -* Atomvm was designed for multi core systems but also runs fine on any single -* core system. -* -* @section test Running The Test -* 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. * */ #ifndef __ATOMVM_H__ #define __ATOMVM_H__ #include -#include "atomuser.h" +#include "types.h" #if defined _DEBUG || defined DEBUG @@ -75,7 +69,7 @@ /* Forward declarations */ /* This is an opaque handle to an instance of an atomvm created - by a call to atomvmCtrlInit() */ + by a call to atomvmCtrlCreate() */ typedef struct ATOMVM* HATOMVM ; /* This is an opaque handle to an atomvm context created @@ -84,40 +78,33 @@ typedef struct ATOMVM_CONTEXT* HATOMVM_CONTEXT ; /* Function prototypes used for controlling the atom virtual machine */ -extern uint32_t atomvmCtrlInit (HATOMVM* atomvm) ; +extern uint32_t atomvmCtrlCreate (HATOMVM* atomvm) ; extern void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ; extern void atomvmCtrlIntRequest (HATOMVM atomvm, uintptr_t isr) ; extern void atomvmCtrlClose (HATOMVM atomvm) ; -/* Function prototypes for use by the atom virtual machine */ -extern int32_t atomvmExitCritical () ; -extern int32_t atomvmEnterCritical () ; -extern int32_t atomvmCriticalCount () ; +/* Function prototypes for use by the atom virtual machine from within the + call to __atomvmReset(). */ +extern int32_t atomvmInterruptMask (uint32_t mask) ; extern uint32_t atomvmContextCreate (HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; 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 () ; -/* Function prototypes for use by the atom virtual machine - for synchronization with other running atom virtual machines */ -extern uint32_t atomvmGetVmId () ; -extern void atomvmInterruptWait () ; -extern void atomvmEventWait () ; -extern void atomvmEventSend () ; -extern uint32_t atomvmScheduleIpi (uint32_t target, uintptr_t isr) ; - - +extern uint32_t atomvmReadThreadId (void) ; +extern void atomvmInterruptWait (void) ; +extern uint32_t atomvmGetVmId (void) ; /** * \ingroup atomvm * \b __atomvmReset * -* Function prototype to be implemted in the atom virtual machine +* Function prototype to be implemted as entry point for the atom virtual machine. * * @return void. */ extern void __atomvmReset (void) ; + /** * \ingroup atomvm * \b __atomvmClose diff --git a/ports/atomvm/test/main.c b/ports/atomvm/msvc/main.c similarity index 85% rename from ports/atomvm/test/main.c rename to ports/atomvm/msvc/main.c index 4bd4efb..28f78a8 100644 --- a/ports/atomvm/test/main.c +++ b/ports/atomvm/msvc/main.c @@ -1,270 +1,270 @@ -#include -#include - -#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 +#include + +#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 + + + + Debug + Win32 + + + Release + Win32 + + + + {77095EB1-4988-4A04-8751-69C63C7C541B} + Win32Proj + msvc + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + $(MSBuildProjectDirectory)/../../../kernel;$(MSBuildProjectDirectory)/..;$(IncludePath) + + + false + $(MSBuildProjectDirectory)/..;$(MSBuildProjectDirectory)/../../../kernel;$(IncludePath) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ports/atomvm/msvc/msvc.vcxproj.filters b/ports/atomvm/msvc/msvc.vcxproj.filters new file mode 100644 index 0000000..e719db8 --- /dev/null +++ b/ports/atomvm/msvc/msvc.vcxproj.filters @@ -0,0 +1,67 @@ + + + + + {d05cbb5a-256f-4127-bd5b-c3bd69b3672c} + + + {f30700d8-652d-477c-a4f2-d23e7784de50} + + + {a4f641bc-296d-4546-a831-2e1d0d7e9242} + + + + + atomthreads + + + atomthreads + + + atomthreads + + + atomthreads + + + atomthreads + + + port + + + port + + + port + + + atomvm + + + + + atomthreads + + + atomthreads + + + atomthreads + + + atomthreads + + + atomthreads + + + port + + + + atomvm + + + \ No newline at end of file diff --git a/ports/atomvm/atomuser.h b/ports/atomvm/types.h similarity index 96% rename from ports/atomvm/atomuser.h rename to ports/atomvm/types.h index c12374d..340133c 100644 --- a/ports/atomvm/atomuser.h +++ b/ports/atomvm/types.h @@ -1,63 +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. - */ -#if 1 -#ifndef __ATOM_USER_H__ -#define __ATOM_USER_H__ - - -/* Portable uint8_t and friends not available from stdint.h on this platform */ -#include - - -#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 +/* + * 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 + + +#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__ */ From 648d35dbe6598bc9322267a85db072ff065a1483 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 23 Oct 2012 14:23:34 +0200 Subject: [PATCH 22/28] LPC17xx platform for Cortex M port --- .../docs/CMSIS END USER LICENCE AGREEMENT.pdf | Bin 0 -> 51511 bytes .../lpc17xx/CMSISv2p00_LPC17xx/inc/LPC17xx.h | 1035 ++++++++++++++ .../lpc17xx/CMSISv2p00_LPC17xx/inc/core_cm3.h | 1236 +++++++++++++++++ .../CMSISv2p00_LPC17xx/inc/core_cmFunc.h | 844 +++++++++++ .../CMSISv2p00_LPC17xx/inc/core_cmInstr.h | 775 +++++++++++ .../CMSISv2p00_LPC17xx/inc/system_LPC17xx.h | 64 + .../lpc17xx/CMSISv2p00_LPC17xx/src/core_cm3.c | 339 +++++ .../CMSISv2p00_LPC17xx/src/system_LPC17xx.c | 532 +++++++ platforms/lpc17xx/Makefile | 95 ++ platforms/lpc17xx/atomthreads_test.out | 153 ++ platforms/lpc17xx/drivers/lpc17xx.h | 1035 ++++++++++++++ platforms/lpc17xx/drivers/lpc17xx_uart.c | 166 +++ platforms/lpc17xx/drivers/lpc17xx_uart.h | 37 + platforms/lpc17xx/main.c | 116 ++ platforms/lpc17xx/modules.c | 178 +++ platforms/lpc17xx/modules.h | 46 + platforms/lpc17xx/startup.c | 295 ++++ platforms/lpc17xx/system.ld | 148 ++ 18 files changed, 7094 insertions(+) create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/docs/CMSIS END USER LICENCE AGREEMENT.pdf create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/LPC17xx.h create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cm3.h create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmFunc.h create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmInstr.h create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/system_LPC17xx.h create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/src/core_cm3.c create mode 100644 platforms/lpc17xx/CMSISv2p00_LPC17xx/src/system_LPC17xx.c create mode 100644 platforms/lpc17xx/Makefile create mode 100644 platforms/lpc17xx/atomthreads_test.out create mode 100644 platforms/lpc17xx/drivers/lpc17xx.h create mode 100644 platforms/lpc17xx/drivers/lpc17xx_uart.c create mode 100644 platforms/lpc17xx/drivers/lpc17xx_uart.h create mode 100644 platforms/lpc17xx/main.c create mode 100644 platforms/lpc17xx/modules.c create mode 100644 platforms/lpc17xx/modules.h create mode 100644 platforms/lpc17xx/startup.c create mode 100644 platforms/lpc17xx/system.ld diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/docs/CMSIS END USER LICENCE AGREEMENT.pdf b/platforms/lpc17xx/CMSISv2p00_LPC17xx/docs/CMSIS END USER LICENCE AGREEMENT.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e04afaee6286ce461b2ab5f286c6f99b232f5ae0 GIT binary patch literal 51511 zcma&MQ;;Q0)UH`ww%ujhwry)ybzzrn+h!NKY}>YN+qN;^f8v~pn3V5h0Q_&w ze}38ilk~rR%K>f8oXv^Y|CdM!3u|YfBcp`1p)*hnX#AgR0RbmxN1&k%0<3%H68~Bv z9%t-L?5v>k-`yA?~4M`(_T_PzT`m_{Q1f!0-!3I4K{t5rMs%=t|!5hAFZDMmTD z;$SH0Vs$wtT152p@)g9iF}yNj=#^Py&9= z72H8T)%x4-hchqh4b5AedzW)jx;F3a`~}3rKD^mk{O?c8emR^SQMCrsBU|DtO&|8( zL)ZB`aVIlw5559FXK%KVe!g1(_>b?;Glt8K*9q|!yXhL&t8V@uHed6SSKY7ywhrd+ zjbgulTR(j7ak_4VTknTGwm$c9je!hu9}3G%u^+wyJ_sz~Izw4E-7%w6Coir5vEz#H zjegp;jt&sHo~^zxNq=uyq|I2QnG=JWxyug7Qd#rn0pGS?WkBSR;}t1#kuwG0G1Il^ z2y58ytGZ}nv>by=g0HSj^R>7JI)`=6FL~2^;YHM&kuJMw!p*8m8|;^buRczW0Qhax8JzpoDKQQ-wI*BP?Y zP_SARDT^Ho4{RTmLFCMA+`t?bvk(xVe`TT~9ezb_rhSAHOtW5&{H8;e98D6(QJ=5V z<-tzYSlG74#S>*bM-4u4|2FC>pMCsL&|u&6_vH%IQP--n3=d-HEVu1Maht`ysPeo; z7+t;ooEh5R$G#K9M&c?AI4d?>RkZj2@af0|G$M>r_3niLi^~X~4I{kyE>9XDikHH_ z-}K#@(ec=Znuh9-YdUr$1`{!VgO)bjxaC$7Z2N#1usIM)f%`#_xJQs+`%)0SgD8f+ z3byoY0w(V+px67A+=Q(M5?)PL7;?3`xB6Hxm1snvz&63IP^Wuj%OOoKl}|u~XMRKq zYSO(Tc{G-{X6(V^7&G%0*Kd&XS^VC`7QpUn%X{wb%`t?+g)x7KzM{ZZ_qv+~&Y&U+ zD>n&~uuwA>&MI+%(Yu`~=# zoqfTp1;@3n=+kk6Zc28+)L1w_H++r1@`)@Cs-O3B^$|HI9#c52jX z5ab0_H1;`oo5E-zwLekHcrEa04L7jgFRH!m$mw22XJR{+eL^y)&GdqnsLI#qzx=ADnglN*fa8n_Ax683F#kaF6uSY{bCW$@;hINmpK_^|A@f8bD& z+l)9m)Yr;>10NwU~fo7s!;3czDvdmMBe4iZhS z$1)I>nM%fnhYEsTJ=iz?;-1%M64Q$rP2UsH7O>kA!6LVujzGj6qacUq^NCG>TRXhi zbx>`y;_iqcv1RU*G+@5C;rume0WMrd$rqpnGQu=**dCs)kwKQ_g+B0g#&MBFY%8RD z=M>nIVZ4zVpHp_K{Ag#YNo`9K^B=V5@7!z?!c%^m}DpK@Pdq%>C`Ac+I9ndEK6uc~wa2Z+4S${=8iQW`yfAeEuqK?XN^a`OykW#9-;^q#PkS1Ddf>)5*U78B=5KB zvggVHADd$`D2jjFe!&9@Df-`yHR_gj(6D8_7NSr$OUT8xE|s$&u<3(6cT=!cC!jhv z0BMa92WdNEd zH+AcVh~bor4ZcbL)2*o@ULe9i$F;)^-yKp#H9YKZtE65dNvM)UhlXz~s`^HGrEBg1 zC{Gv~r-(E7VW}o(!F@&R`#XTq4f3looeH$TZOTFFl;VYEi492KcCaZ^lE~*KQybjs6B`dvtuX*MX`vygKoK zxRxn1*4@O1v)Gvl!KP#_(gz2QX1MCg`(c$3b!IH}KU+C0txj=)GFl-^k}BK&&MMn* zWb`w^QkVXChVKw=vsPGFDp5$))vs3o&pr{{N%tlQ>2pQ4;O%1l;pwiys%#estGgaT z4+dd~a5BE*=jZ->T+UASnwzRl8|~i|p>}>%sQ)goO^j^6X}Dj}={$FwT9D!80%!2# zDeul>&9GuF2k#U#zlX37_eR8K{H?aF%b>lV-4ET7;-Z28cBJ%E+ll4Q3tWh{ODavrgq&zb}kiD)lf@xlcq%oyB z&A;Y)%n>H7Yw>r~W{1A4NsF-lJmQk(6D~k7Icf*ztgH)f2B!=|T;$$77SEpy==Y0D z{lX^)3FT&GhG&6))5!=SB=x#1=XxZTb|$k|%N6(~rIaxoYX1f02}ZmI6TH;<%0?lI zQ+cQYJJ!siM@i0P8-+-Ij$!u1B`A72W1K#625E2L&7jZoi@x=W!rpZ@{-e<-OeiB% zZo7$qG+5~I67|bK5!t7RPk4tH0Y7lwDLikWT5W2!EOf*W%RE2#PUmVqy)fx4qoTat&q@B4R?whcfp$$ z2Np470dYZ5th-?fQVTCYL{wWQSr8~#U13dPxkYk^Al{YSjV0V_-8&t zs8@lYK%#fC-xop+bNCHL5s~Br7jt=V%G*fEbH+e$U?$bH?FO|J|B16fLA!}WO5a(K zJ)I?dg!TIwaT1=*Gf2gkU zdstamU`|fYcEy~V?JI(gC(x>IK>vP47Gq_+;PK+7gIN~Y%U0%1NRP9)!JYau6b{AK z=o|kG+~sYrqD2ZNV5Yxtm-e7i{l~smf>1v{zA#BR{%5lY znFQsDX0M`JSYdsZre&mH&3He4LP(AXtQFUJ>IoD0Wx0|v+qq8Og=kQ0Lfm~xy#zr< zA52CAeT#eW3qdttS#so)osa*-WqhH6e%OMrd*@eHO#+?>i;+1z-{&nXXQb&nrEY3z zN6v&;!MYz8WWdaqF6jz`cyz4&@1NJtJtPCNhLltuUpj!YTq>sCIqbug3yUYWR2)oFg(1oU78WZqd`Y>n{5&a&XP)CDm5c~13#f$#0^z<1(Onb+H_v1v2a{M^4 zcaXeslQwnhDMWeVLIvpQS7K4>`&=ph?9>HuT6&#QHd1%3?m^i=71r;I%gNbcW$dHs zbZ;)!WRbUZycEhJ|KAduf~&2Q=B<9NPJS|!=|npg#i*ek(L`zZ9Ar5rjSf<^*ziKSE~B^nQP)4 z5;#>eM85!IZJh6td(GOczqMi6WgC&#sE9%d*sxDMltdZhnM2T}<8;b@JINzYb_V2x zG%kIBQi%!&A_^3w2Cztzf>w~=yrw|K1`c{uqQ!61w&10!wgymuqx;yhh@9crF-VqY z|NeY~cQuk4M#Asct?uE;lACHUKHLk`9NW(JJ zq*aK*5yM1^IOj{p7uiU?pbuw^c7$_(F&4I}9nW|#1v{}43`wWp7Tr7|SvRMRQ zW2-@cvA5%q-Eg~t3*L8^9rK^yG>WeY^0Dmssz{D!YGODvr0>)>x2gs2CI=~DIEgP* zDxgaqPp=Xcb~^b>+wWN;wt;3SCFT8+3nKV6bOl_HLMKSvikZ&HB#zrs0l3UU1-)z5 z8HX_C)WOJwPEp1$tmrOUQ;|7H=F1#!i(-Y_sf5HrBE=b|SBZ&(0YMMv(E;dRUznaU z8~HFD)UT~dy^G0&8)75!?%uKawsBycCNqrRe3c@s!<87RbD<_8tU#ow%W8EKD5#eA zw{#7}oMn{JfZ0NBeM{Q;ayG=x?j}Bu7)R|;zj7O}j0>z|N1U_*5HHtnT2AR+Po=(% zY)q8MdV~4IK`Lp#?DY_2YE7BJ!E-V)*D^rFJbf#6n7x)EMxS|bQ1~&E$uJ9Qe<)4% zd9EY3U4+#X=7%^Ejbg@V5<&{LW~%y)>8& z-J@S9x~=dga`i=f;eYfo!JABvmRL>F*x9^4w6mQ4A(qc=6h9dN*?$p;PSe+*FFQMr zks3=yxj^msA1LsIY*&y`JazKkQWmdaNkaJ^Yr1_k6=u#CQlI@zS zN5kH_{@8n;vf1{2k@4`?dQgmM^?(UJkBhy*{Fj6uOD!s3_`Jm4EnGLqrPDjl677po zaa*i_O~@tawm~qr{F2Z#i5{`eg6m&zar^V>o@%e}Om>oTJgsxj|G24zyPKv8&a(&& z+oCmsC@ms@dPSjnjODEYdUqikfKE;kiN?KMA>>T2Ph#lXmZA11bv=h%I7xXuLz6h;dTcS9&SQ)}$UTUcRqv{a{*fLABeZ=Ki zWqfw_+dVepFAZ&Cu((ymZlgtT<`dd8y(VnurTtLl*Y4#PBN=>GUzJG29u2237@3CKc_@ViGG<`O(9&Cetmg*?aE4OJT|yBYTj$5%l3=@ILyfiS>Y10 zs9@DSAoTe)#nc^en zJBWCP!bfMAwLFJdvVfgs8Qz7LeljH2+5Fq}UmPjOpMNWKF@*vRV9LW_M5ZR!(w#x^l%oN z1T*8Z0cL26L80YNcBgUeyP%xO4Gy&qS@Tkq5McQyZ)DgTC);E>qC`?mMauYFHrvabmG3e!aYlKp= zoD}ZtKIsU1SF=;0g_Sa(RQS^T(UNBEzmlJ&^+%O`cuT4w*ksduc;W*V#en@eh{fnH zNlih^MZ>wl5<9#VKx~=40A3#i9mzIOjw($Lew~Ot8&z>==ZG`pma(IYKVLW0ZD2Zxp(fDJ!^A>7|p-k7;j8$V3ZTn|~b~BOa_L>)dtEu?5tj_keZ0*E=*Ht-(m_)eYt25{ z!AsX&pmz&j)h?>m@)@UGyP4=p_dhJuyqpYkwn|q-dJC#aGS{gLOznMrLd^ox`uJZ< zIh(LV^9P`Koy4cB%Kk~Ui_)Rf3S0Q5AZD>pM-6DgB#0POk?ie0W?)MxGeez)fv}ev zTmW2Nx$~rn*+mA|h9&&bNsOX2?=SBj7j$&7TA<@I_Ki*JYU=P*r6Oycmrr2h|7a`Q zD-96h&y|qn1i>Yp*G%C`JYZ<6d%a>@Jm(}_wXe8y5dh-_^w_RNa2FT(#AM2ngZoy zpbLnTJeP4sm&f>f$_@U~5AOSqQ7&>qXhKDI9gXvb?Mj-rC68wS6yOxPjimz`-aUoj z#9}A1l2dh&7F5m((FBcP?tW_3t?&moH4b1J$ZwWANoLqHGUAveEts*-J!BVlA@{Dl zk{-`B{Y-`E)!JW}rlan`XVz&G?yGK8f7qFe*AKA?bf#ufUjInNe|oyhJ)woI(;<-T zp)+?OOTr*5hx0gU_$!VN6X3}Y{|GC`$b6R*X{$}%nWbl{VsXzw&OzzCSwr!MDI_W1 zf>S#1pF@uyGl^XG<4Uy_>ohusRiJmXEI+4Ur#nPPM0rY6c}JvL4HfSR`9K<5SHTi& z-*PpPcI0}>=1sA{u)v{94)Qo(HuaR5g4xl=MFdHo53uT`>fBBVJ=`4bTeG)k?xexf zRma-aMdVD_T-~gK^oYXve9f34Cv%Cyc)Y85iNY;+zf3buHY;LmL!i!5lwzY*j#u9% z5U6zwnQP7ue48eaEt6!rPOVu5M@ITxoqvyw)8}B|jK!lt&T?+5sFKSyO+)2ZDkX*= zwW6ht83{M_lEFThEXNDIF!R2t`PKrH_RjUekbo9`9{coDT)E5Iiq*^yeS72)H&fT8 z&cNGuGf|HwCrg_bM`h(*s=>ow+{s5G2r%(-B!ii>4$yg=k((VDq65%y7R0aoTfeKt z{H7ighTgQ;IEJuW4{#Pz%M%~V9o&h3KR!<{!fF`NJ3@5PvRR8$rhdv#N~UNpEM%&& z4|}0SY6_cKz-ODeq`w#>CzFsSfO zxD+VBtwpd5u9v*;oy4#rpQ7(V`+K(5S}z4IRpkNL$#V&9^DSR-Q(KQ{tOX0!xtXv; zB@(7raeNvtW9ZV3mdM83sj$HwWkL~`utJnx15v^$zJT;E=wc14`sm;$GtyV9zAzQ1 zyp_{yad8r+l%ycY%yS4xMu~6Kzhi6S1{AK(ENs_lQPgEW(nOcp318$Fz5iDlfr~hF zj6e>Zk17ijqrFNR&_BL_(mXi?&pTmhJ9W-XhnFd{w^CEKSPE{Bj%o0N?KknJ$*Zo$ z_fT^uOq-|&iKh`3|0&GPIzxCOo51;+bS1X(%&}+u;O7b&1b2b%vTR^Wx48C3jq-mK z`%Q0h+9X%Ovuysi$ly~RQg zm)`jnMcaQ-#fq_7%kwoW0y|TE8@>pV@mk}2oNUxrn3OM-ds-=KI;Tp)h=zkFt(491 zeDJt#7DYndZGh~u-F58u+Q&U9xD-=4cG>Po91Dvx`ilixph}c_tYnX+z~e`|WVoJl zPBww6hnbco|K#suZ^AaAGWATHPYk_;HvTz)e`U+gAUxSTi^ z2^?OMHHU9x7wC@|U=G(HEi>*EV96_&KIEC%+>LqgeAky&_aQ!JaYA)lsh!+*@@UEH z(o0;JW|N7TIxy3TmZdvBnwe*OX`oK4M&u(<7iv1I)l-bJw?Iv2Au!9gV%CM>?Jl-G z>qvH52*B{K{>2Egb%86;TyQp@&(B7dE1@XR+E(0ETDtWgixQYW?Px;T?R!2}zxF4( zZz9;r9MjREP>SL0*k`fXImr;_FGLkG#Yy#1MBWp6(-Ca8T&02m99e-DaVbaMs5GuF z*W#4Dj~_p2aj;N}Vz9sic=HG z5k%9Ar-ev=9eEtUUr0;| z(~o|bqJhuDwJS$KS@ujeGXG^Kq1NWC@xjy~)$NiLhBBAErRGhLqJWx7;3=Jz@kzZ+7Phe}HBGp0ter;IL$ z-^6a=_7vs%QEndzZxswZO<(wN8z_q>9{8=QVNnx3U{QvJuk7eHp>+9 ztfOqNOtC|5tU2{lB*-%367mp9)|PmLzS&_j^YKO8|KE}DW?N!zi%LvR(hLzzj|C2e zz)?6?-dE7_hg&ddHi1wsJ;r2M9W9flH!rY0gfPb*xJ2&ZnK8KGqQNJ>@l7j5+Se`= zY!)VD-HaF#vER?6B&cej#9Ug3^a;IN|84J}px7tt8X&j%Sd?6P1C14PSQ5wB0sGCD z(H&qVnlbgE0S7wI`aM^(V;<(5J`>JUMGrb3z8tuNjJBUAY2cmq=W%rCj4gl7BtZJ6 zW-3j0-Z%tGU!GqZ+)k?P-i4I77WW)VrJ~yR#0!4VC#!yeO($RLfg7S(Y1 zMO_;cygQLCuztSR@M*;aL!s(xznP|@A6$91%%z7F6}5;aWKP3*^YY22n4Yl172}4U zyE?e7#!oPauEG@ZC?Q9)xRNaXuVgj@$ecK%v281+MVQK6Dn%3QY1_rUW$_Zv_=4nX z@}0w=WPW@^&bQ6VN)1IjchMNKV?5kJ$Ek5GyC(;=a-dZfgLU0gd8*tq3n2%T@n3b! z;yc1>-#sJt1rJ%s=A$YyGwUe{@;peML3)paOuJT0Dsf!nQ`57s(W*;vBRb>9q%N%v zQ$uhc7<_1=Ru51SK)V39Exhm!1QV|}T{2N3jwX1pWBDhKL=LXg`pL{>Y^X6^iIt8MZZlc}u2 zlA}{aGFQ(xLJ`c5Z@(lVRv?(^SNg%_=;gY;#xs<4-dCeW^BcXtG~&R5>oK$G&6C1p ztgHqYe2mpbF;KL2J{EP;31!iE^ENvuKpa$Kp<*(KF~D2C(@?r$-;io+%k9EJ7~veE zZR=(-ji^G*svI=0y7LvQ$UH>Mkdy;d(3TmvtuS(oEfXft7`7u7Ayrug7KYLZFUTLf zS}*)pHEGajkyQWVIs&l14o`N~K6rgi(7G^{zYvn72B_3Rs~H)DhyFy40})}=NoxiU z*X70y@1r&+M1~$HepBAiLhy;_Zg$$sC3Rd@h8U+8-dd)8whBcITH);#m2MXkudVB+ z+Taiuji?2A+CgbBAFg{vk_%Kt`pKtzp=4KwoiT2XBVN%6rQolMGuiH8Ie~7yry;<+s7w0|7--aB9T0gfn`G%O9THv^n8aa7fNpJ_; zWd;;thI=INIewXv>3QY+3<@>5CE2GR=i2JndGcAF)st?jPkz?Jrsl~om2^szi(Qbf z$8gP@UZxHTS>{JZx_67?d0C`BPOJJnkEf#B{+EOnDqb=)%j0urLj9&N$Xqo@Fy*4T zJEbE`a##KA3em+#9fJp<#xUbk|C>qr z-!#+zuuK0#GZAsKvNQi5#EJX=gE%oW{r_N`uK2Z`GFuXEs^|Uw90ASB2glq9FDP~L z<0_45NscOMx1q-JO(+wkF6@_oeCH@}UvH;Y3itVJipIy`O9CKgvEKU`Uj#gyZj$N* zoGA}B3C_PwaFMR;Ra(M)xjejFZvF$Df(gA{J!*IYe!6@-ZjuCj^>Y@V@+=h@3^pt7 zF5ZK~uo0i^9Ub4^w|88Zz8m=`I}H8S*`D&Y_&0N0!wlV;au64;M=HLszdgDHuaLH` z*Sh)H_83d1^47byR>C~p1iec~Zd*b_%brDF?P7kao`0O)O1w@|Uj*JJx)go;Fxal# z&7Bbj>`#j~YJ{PfE8K6dIDh^3Y5&#@GwO|D{|`uh@}b)M_>bSa75vcZyHES|uJOY& z!gNKgwjYlyW=kn(-%Fk&Q4^I+cr{ z{F;IFj>t43u76FlW8@^H>1n|5bG2y(U5`8 zE#r@>plut=@Z8a~1Os?}$Aa`UT;J_hw=L)hd}A+|qg+7IfQ7R#NHnF36O_YZ<|795 zuZ%?Odu3r;Ie<{y@fp$pKBg4u;84ms32m479CDZ)h8T(flmqHz0VGsIusXd{J^p@j7u1nX{K3}2VZ}i^$kRG)k z4t_GD(|ZFkpD5j)AFRB-uLLD$v&L4aj<9Me7{Aui1aesLK@EaVIW7n8PU#s$5we(;d z`l#c`ol|JZAj9jp!hOO)^pXhixAJKKBJv} zTv21l6#E3}I^cUagNnQp;f*>5#B+P$l~!(jc^C}9{ETFaji5H<38SSlRSayuDWTPd z{D8sO%SD@-Un#7;5eI>)nn%`rx~NL>8NfL}>xR*Tne z+Dq{SSvpD3b{VE8X|BFv_t+54k;h;L>e2HPMWF^W~~%!P5HLuT&_ybP-d?f{9JX2P!t{b`dS(yWbyg!b`G9VO%eQZNG^ zIzYe3MJhYhBQ86nsU*2+*PkKh>=|tkQe6NkT4{42sTc=YvZ;8fVx;^nn(1z12@~3a zvhM0PsH%owcE$u*`M`zEojsFm}C6YEC_-v&fPuQUtx<8elRNoiusY%AKBp#m>{tG<=g_)YCA)9y&|!L zf0B0wV%ptRdmZpVXg5EaAKLQJhjY`VR*vWaqan5&vV>tpbwx>FFn(ILLp{!v?e^u9 zgIzZSdB~=Oj#p7&NVPSsL#H=)(UU}`CJAnZ>Z6y)U7GN_;1x0CiD3ok{c`CU#Iz;2 zZs~l8y48x%6l}pdyzkaZ5Y*Nq$|EPm<|7E}EJ306HNX4G+ta=EqKN{OqBv2RjKU1R z#@!Zg))8w5&fNfsZr5%$B{c0KE1%W$&-H4fHSiV-xb*BbR??H7QJy%|9uo2y%q`zdcB;NW(-7+bMPiZN6&EZ@kAu+nzk7d zOe;RAkG~y6Fvr{#2Z4=3O|-2V3=VxnD02|ns0?sDQ2Y4=QhyfJp-ebQCt$#01zOrg z=0bP5T07i0zoLS1{GCmZgs_Qg`Y3WC*8_jlit^^tMiz||>E{!7TqLcxTr zH?H_o7uS@5i9TI|(EO(Yp5IxZK|lABqx!W%)AhhYWSWzDx~O6X^})UfKl$t2(s^AD-c)(U zR;{c;6tYVgdRrXd8u7nyfNhjFb(P*c~|C5_pd+8WZ*@V=&eL>CMHSvpH$hD|V z_q7$EGmlJ{%gHXri|+}&!Fk>LFiYI+@hr5{VY}>ubo`>(NYLbkpbc0<>yQb5^4aH~ z0{a>Cg=PAwC&y}9xQx1$I#E+Qci_}WJ_>@J)&C21T^HX%sPr)Rqrw@1-_drdSKSXn{ z1A~0}lZyH_JZ@2f{nz$hg!86s;G^_5h;Yy-cs1mF@v!;S8)4+!DH~v#9~uS?)M9H; zZQ+7C(&MGMtr5N>gB0I@fKv!}Lc+cj^Z;o2gr zr!bQ^7lW#hd%eFuhKAetiLEfx%JsX6V!?zB^e4c(*e+Koh~sA}jP_2cGK#{%HQ2Z#-~K1lbS67tw`AtfI!2TesO}7UL`UG3c~(*C@qzOuP&;JOQaq zPilYwePR7E9cT}n)pM(%!AqE7YM9WUWe)3JR@9r`10Q4bsiv6NuK7~)9r(X7 ziAum%V>E7p)Mf0R(G-^^=66Ok(C9-Le-2proC(LRv|kB8m|czg$Z29ElhuD&X=F7+ z#^N1yi>s{(Z~qZ6flKcP0JH4`8)$fWnoOKm(Ta=tgWV~N%t=a;pimaql0i5 z5mAS-&V1VdvVHrpDQ{{N=AH)*R1_$Th&1a1tJe$j2f)BB1`BY{2oJtpczXH30R@C# z2i*k@tq|c5eWc2pBM=0qzHPIh`J{+`5b|=EkjfgI#iFef1}+{O$u1L+2TzioxnWY_ zdu=!_AJv%S`5It$akoNBrd!S3KCD0dz$5-)GFl|*JV@V)kO=?hc9Zd|5^U4TW3kN< z20dUd;0IIH`_}x`_vPgf6TK>DdYR4tA0*&PI{2mx1BW6G%1?WN5Qz=MkERaY#DZ;$ z9!Vr17GDD4SGu%>>+u(j5}rr;tFB_&CB=!}8_N#*cqRrB}GIMD&4Or2&p{wk2ZB?lt{9c3U1+D>nSahsg?>7HG>BCiJ zAM0*j>P!uRd`K~mVaIvtvV&go7Z>v+m>iF%8<`Me=8k6A3q){sh(3VhfzuT9SO#}5 z-L1-LtN|kA24zV+65;egCtKVdL#pI-(Jl255_3G|<68&~j8VC|BUr#R-!6T)8G+8u zmssB9Vw>*Nrr>-=3au4xmm*zL%IZ+_GjOk?%xB~es!-qAWwra|$R1M}->fyD!bZl$ z6VC5PiB6%A4u^%Yrr{Ttr>WZ@_`lHV-2tJF_?9-cbG8EU!49Ss-xfBJp%^MNsYG#` ze(1DO(q_RErmFO*#@vJKV38`8XSiJmgziZgh{UH$0`!ZdzUsVyj$!V4p`k1lRbvLg zk@*~Lu>>*lb~8R%7>v&JKIE_YCkFYL<}Bi+WGLG#b~#v}7Pw3RWRmG49rFyak*$-Ot&}feoc#NcyK74Mx*;o`ny(L&F45~0j2%^mDLnOey%kL zIQjHhi&yAqg1!3YGPwTM6;f+R1L;bTAs<=Btq716>;V?&G4%@)1D|a6kjMr>An707 zLslegGXrK_7!q+GKNgMZTsTnpx<`Q-B)V5pTU1aiKu5A2-YvVOFe7EiVDxcrDN+}s z9E}jHE7bABGW6==#6?1p)_bnYh-pYuq$|_K$gnAyGW$lfTtV-nVoj{zR6?c%7n=;5{7lp2 zdb@1s=;Ly#4BMNx$TIzBDr3(0X~!fYnS(V-;*Loq3yw4gC^}@qW!_Fn=i4uX5)e+3 zk6`ph&*`ABCd>9m%QS}N(+P*G14zAFC%ksSy_a(sAL*_)^mxv?r(!HG%0=h}a%pUn zQXxp)-kbp};XseciF6$~<-PPkIhQvL^zq4LGw%h&PjfW9ShaA~_JG_yHcgE4Q|a82 zuU5kLTv%ebe{(pLyToxcWJEzzGIAM;0+d*afgyTaRMej21E7q2TJto#Iv=o~=;M`r z2FtoqT*0UU#KvZVpubqCtWAv?@rzBwL+_@@lwfcOBhYf&MNceEu(2$t799=zOg~7R zPUV#?4iUQor$tPejEfWbjr1fOz!9m+LU=-_VYrquq1MAM9yPk&7YU72-DId&L)D_=ZmxfL7qXbGUB!74gKnJo zo-(BBL@@kKIP8AzgH4;!!Zn<6WIXoxRKxev_>r|hYwCC7YR zv=OX<9}VgHB*Jz_VC@C9ciKuWMJk8H^dzFRA+@#b;auFy_rk{Qk=;8y} zz)Ap}&)o|(erKk=aig}1J{X0L?AzmC_3cDJd#5br-`U?C8-IS-Bxt&mX5hkXZIP=y zJl%7;5TPMibRFtyeucySyW1s~mU}(0f)JlY zM4jP7K?vUQ-_kxlc!vvt*#t0PE+P<7x0_frPDDJK z@TD?LZ5}mDpmeeC3BjUjy4hMqs|96!7HL~uYuMNzhfAEXD(baX=18ZZf^UR=D-feVPx6Ry^(X>Ca$1DDyCY^w!n-c8RerO)pA}vVB$P+%>#qsW8#HxSTAoH zY^y=4v#dW+^$(XFVSLKvU4Z^WHZov=*JS>-e3e-b&b8o9{%N%+luy%&!x@cCSBr?T z#c7)qy*$EAzH`v#^jl;H551D5YvCndX=)#_?XuFLk?g5e!S2)rdzfLBpTVG6gdP`j zd`zWH{|t96_eC{)M%oK@=@7OxzCBzML_48DH4Vg}`m;i0pJdbI2tCV9Ido5W2Lm!| z^4ja`6_m_Nxm=Nivd3EFXcHp964h=lVKViXF|K3U*X6{yMy=M5P-1`!CZ-$W(jG@m zO6}p>QoYDHxlBsS8OA6^C4UR7p6eg_vO2fLU-?^A?vFAe|6r_WCy=A(P?9F~Qo+1O zVem5vDF@GS?MV4LIH44C=^%SFQT6%#+i0OR;=?b6;{EA-;iM(538xmQ)N!!X6x_nY zFvQvzfeCqZJm>A>3tG@sjqh&!Q`KioRWT@ml!@L~8_?qKRqUHRM<36x$1v}XHfQ5z|3RWVq4|C}iPRxVNzuS(b{=ty5{10IhHb8MP) zufc5O?m(#G~Pi8C>VuJjnRZ~gj zSgTm|!n`dUL5==e>e?%9SnuaP)JR9&(e&_!i6eD1%-nu(SWBEiAUP}llG)}n3s8#Y zBb&7rAP%0nb%}q0#C$zuT?ec@>s_UtmawFL+f z2(u66R72I~kzil?^?O)np5=mKIOy}vHr@u~@QhKTmpxVzQOn@A{nwkR!N&!Fa5fKCn3r3gBvs$^SD-$(GZp@K zvoawY`{Ux(CQl=-(ZmiP9^pNQlU^x{+#ui=)ao)z*DjH`;HK7X*EtY0kH8h=O*o z4iG9+%4H3g`>Lfuhrdmtw70Du<^(eA?GdR$NdP`NDcBF5G0G6i4?KAKPM-?~P zQc7p6SUKX7BbzT;={l*WbgNls5k)sJ=(Z8eZjT=h*7ZY0;#Z+TBcgBmepv<)V<;;? zY8HIFX164W$I59ZWUu@1iVvSQhZdWDHmfcf2Hy6(^?7`)Hz;88+(||^DT8l;jhCO|D;K!;BlHGAxaqeoz#w1fGux~4NhF@Dug{EH*FNZHDzTHp_}pve3Z^Y_^r9i zxl(F%)5Kg2gHD%wy3SSO4Q7=&8S&Vr=g{|`7HbGWU)=3~Dvpm-js4G@Npfc&1OA75W&!2Z=%&jFyVEI}`?% zAqP^F3KjyWp-L)6fazKEzRiWf)X-UIWSci7$MoSNafI3v+LKOXbDwPhzr>*D-00Vm z)#Xg6bwe}jOmB~9ht`>NjcN-DbUo8iaK|a~N_WX&Bay|pWg*Erl0%@7{+43lWurQ8nBHysHrcaXRAY<2GwHJcEJ{=;zVt*c% zsl{3ohl>-tq4Ch9<(W3BNg=qu13pc=7xjv58(@|QY0fA>UHgpn!J2TmIM~sRX=MNx z0Pq{IRZd{v+m&9cv!)AD|K`t8-ai-XXJklMhFytSeKFimiZ54YEu9$1jf==ZZwOWX zd+oT~tt(jmO@eFs+}+8i3AVh^5TU&1F}tTzj(oFQtY3JR$*@uB87;g7@`ygwAK|7= zb+UJ6(JEpT)6_2->tf-s(w_-`6j}w)XlD3afkflS^w8F|7l2knV09Mc7GBYscW*8x z@pe^R{abZkTlVGOhpoDyzG1s7^9$&CP3$U5{S)6uo$d2~@%2u@xo}~WW=?ow+qP}n zwr$(CZQFLf6Wg|JJDI<`r>DAVrsne9*ZXSWS%Y=c;RXz{BaHri@v3^exuN=judO;e z!=lC)w&hnvYdji(2A|wR~0H(?XQajc=0ff zyWHDyQ7M9*>~>Hl@DyAgRD@5j$p#e6sB9x6ry4CZWi?Ai!o%3w))$0+ZY#=9rho_% zNR_nS(mp6z=ecL?sY>%UNygoUfZA=#p)WIecEHB4tGDTE2t=CC9<-%uGwx7{@$k7e zJDyquGC8Ai|EZSIYrkMC{aeBmhT3+!%Ud)#u?WA2&U&Ao>q?8_0yEPY89`oBM(%6L zfnVtfd#xr2*hN}JI@#3OR9mZgM$_43Yg{~I ztQ#iZ^6;^tKHbv{V`S#|pesdXdwTgK%J00)5`OXdS53l~md%-w5^zoF30wR6ZUDwS znSidph`MERHf)9GCBWx;K$}OvCg#loS6DD~KP0}92L1x8-%0<1C`%NZkg%98wQhNc zT>e2HNtpRk(4~ck>g$*N#{0k{Y+x%&2!CAIi|QGgR?@C%71v87)@1{~@}&a#Bum(B&=vsg#sR3^_aku%Di5SklooL{yQI-CFen1nYfYNjS_eClQA zP1v<$bwuh`rKNH#{DqdJnRC0WD&E$ZZ$LLS3(J-EZYk7ycO33(Q@Py(O+*bRo7cXS z9gyqRwkT!mi)!cc6DVz!7Mb8yQyj548)xT|9-wiFkXD#eFPqqBNkn`((X5AV7fNmQ z)FR3JD^#!gS)=ry+s-DBBly$xL0+<3p(Jg^LURX~gA^h)*$f;1zhe40pAECTM$HXc z7j@P8c1#_tx(amhX-jrQnh7B?O3yD5Yf3fF(!iaBu9(NxCmrt&2!b9<3{B8(- zfW7%$SqJq|nZ#5*({YuIWw}Rt~QN29+FMDGp~Et5JK(sO7+}RC6cK zNdiZeJrZMo+lRNL(T<6lM7{-?W=r!eYcR>?cm4j#VQo&f13*>B`c@ho2BmR&!vl3w z8{QG`%>G(-4r?JZiAw1|Sc&>{Le6RH5JS{9|Ix#!n-JcVN7lTKRwoVVu*|1tHFHiL zOKFV%k*p|ud@!`R%N@tof>(P5NPryH%vD!u&R}@4JtxJWOJkyJe=?(CC0)GEE1!EB zP-Y=uA83k68V#%B?k(5ZCya6Mmla1HSw3Inah=^;Dvkc>#9q;JuBA@8SYXKb%}@Ik zthwx_y;xh8!JrIHS-6KNKhL~i*qPvR^P7_4A9BSo=m_Vh(e9|kGA9oeuSlrqF|PSW zZNe`2Hq}o+ tUalKRzebAb&M3~sg1N@69tiNYEcv#SJuSx{(h5XK)D<|Vx&_L; zMn?TzZ}8@12S+ufac8+BuRp4|ylVaT%#r5kccRFzhX?Rkp}WQES(M*}IK6p9*Ej2> zJY!uxuP-_B2LSweynKC~tIkqwSoNS=Tp@a!h;mU$+!)!jJcairvjoPAweJ1G*c3gU zf2faqdHd~JG{`U3Lw>pDGUED!=*3WB&bpVJVm8`n@;$bRlxo;PI}qf5r#y7-G~S#+ zgXk{AxfAhDVw39TU5H@IIo-Aer8+veA~Mr|F{(ok))(ng^*Zqhl_lXO)|ImZlA4vO zh~}Rp%Fr&Ho;DCj*eauT@P3;1GTB6rOF zNAsAFFD{Jm9y#P`y)y_{9iQ{a#9jAx@WYK@+89`ppw&U~^WRYVAYE>yZYjZ+Bh9pd?3~$7*%KcaUyZdsme~A^L(F^{R*NjdvFW2Y=+V0Cu^uC!kYA z{WgS6bO{eUZ4`l`1qDlT)4*&@z?w73$Bfi~5T?X-C>Bt7^p&n~*;5}g?SEHTHMH!r ziV0?tmIOSfo^*e&F+*SOzuG;CB+R<+JVmW5^O$v>IJ%7!Fb@ib8n|t(6wsuvFa3f> zl4qz{Ugj)QfWT9UBmXNlO3*$wOFM}kp=mZ|x`bPJPJVz66o9kgDVc9Q&qobEcWV*^ zrMZDkFzNIV5;%7<_}3JvU&^I7G5B>n0ZHA7MPAAhhca?d_J`JHC`8P<)DwdJDWjWk zItjSFd)=oSrpeBpbG?eX^Awy}T|)s%u**^HhB9(cBb?QeVRgDMq*p*R92nP3FCj1+ z_(aN#y-0PV&MG2y6G1$G)yLDjDz|l4gH;bj98ONh?AENlW2WXwta6dq&23I4I)V8m zOPobl3AUR;v2qvW`6|sw7umESb&QT#LBRN9%hnGho?o-M4IUhLGMxwMZWT0NbQZ*%`X%&MyiUlU6%kJq7H;WoYL37!a1n2#NDc$gNxs>yA#btu$ZPR7IZ6xkgz9WzT z=SS8=$4c8}7V#>u4(A45(n7py`j>Xr)=SdWX2_CzcK#L9t$EOC2P6HwiZL+&S4zS) zb77iPU^x<@VD?JzdmxLA$V(!i0vtG@%|UQKun50OxL(U?QQxcHJc>s z4Z~%^wu9bz0g+Vn`sd8g1~x{d~q z51sxA3wiXA{}XxWz9^8?w~@ivd#ocue4#rcjPT(g$Ij6>>3hSBpsaxQ2hs@;NY+22 z0Vd$0Rp(9;bVrbig06qi4vqN~%gc<0V|&x-oA9^yF}zfO>x12bv3Ze_K){jL6!sys zQ!d}Uj*4IgE*IO&isZ{bKsT@z1^=^_Z0 zzQ?1832ViRFqntSIQKOHjpK^%6YmGy`Zv#RMgEAs(@1;5cRTi|?9so-peE!0BhvLh zvs(Wv)5Xfk@V_%%jQ;L9fG5#+|*Z)7bs+HH;9)~??7xs+*?+7qEh(@kmQ+~F5 zT=CY)-WuQLI>f;zfo4-KulB=)+RN8%{BRXfwZsdIxTC?pg(nwOP56~)(F=X?*SfeH zS=~i^`Doj&eUCgWZanuk%#p+F$zpGRZZ~?L*M|z;Fn@OY_#59xVfQUpS?hTHKF*7; z!Kc!l`QmD zsim86^H$*UpU8|8<0B;5b45cFZnl-Xu@^ZeIF5mT*~!m|S&(QByDpRWlB+?nL7YAF6D-fd z#^~%2vtwW*sm$Le5Y9a$R4kkaI80e<$n4DB@1rZzo?AT|U664zU7WKHz_a;w@@B7J zo!&g1t;aaP3f=FMXg(Y92I=Y3&;gEYDbuXHen-2UqF+yh=vJp`S3Jy^b}?8)zzTAI zJsJ^pR;e=}cnZ%&7W`hEJ@3gguFrDlJ&m;5$#uU}oW|iq@lUJ;U|(n1fkNNA0-K(X zB5py9UaeAjFr^%X#?M%gX}%TIszA`y7y_j@`0;Ji%H68Iy-R8Ma$Bs3cRHiB~e-0~GJ|LEa{aA{(=`X%z-53B zZK+ts&u5q$zl}XCaK}2bd&2Y)^osbr0-pinJK#}HtfKR5U$kqg! z+~~iIH5z`;(P`*50UyiYldmFKF*+*chJx9pj|(rCx&QQ+?pkaEYkFtwbhg;{P-sP3 zRdsN6L-w2SNq)`SMBIR{g{|rpk^P*rpgePa9h|}9HiXC^6sdW82k`U%;H7+aio18} zZr$eZO(XV!#O>Jhdi_RGE?fW1JSO7lG0Xk=Hh;B=IVdb=`2fLt0p{QJ8jFA1=Oy}f zh1d-$4n(n6#NgoQ@FOmqV zODu}NdO0K_*ew&&VJ9Uy19KQSu1Sarh7eSlg_FUpi-&#?m`%|nB zwRY1*()_pgWiF3lY*oxys}%$RZ)-Mu9}tp;*dXA~DHC;x)$_q*{P7|~=RpW#$1b35 z#1mkR4`Gg22BP!H!7&?|=c{#p71Hd?*9J!|$Y`{`Nh#<2gO2MO(S=7A$K}sR0>)Rx z#;pXLkLF~dFsOkZ!2J;tO%JhG3~hJq@YlYuhx68uj_7)00w*&7_&}dS>EZ#5m%H;G zXoOZ(n;G~|Qq0{K;Xmd@i=cSGi#xFZedfp(cKUz%y2DvOrtBHr$y{iWl(Zv`-rdA>c zQ|2!r>8FfWCF)~`@L%f_M8Nb^u~!W)4J7%Qa7z-}SQ*V}?-QV1vOu+hUOOTNUfbc1 z#cI)IIA-6m==>5PSw;j0eWF03XAXQW6NuIF{xHG2fj|mnGde2NJoD zSW|f7Q4;;CxCkX8L;ZQ!>H7gzBn06it8^Wp@Qt)b_bCWg5QO425Fo?iiyEqxkbiLABrJS8>|*q$v-n z-m^W`(pKbVqdJ}t&|#{T_p60`i*nGDa@B$LGR=K&;ukio|A15Y%8t6#Y)Rb_C@8C$ z9;iG|p6?YAWrY?A8ks;??h4mz3o|jvC*GS2rnT8Vb|^qfl0I_b0*(xyE)X4Ey79zs z2_Sb%?u8u*();K{Eb9?1lu@}Ax$cO2Rp0y;m!W@`wf#~Lq}afQfTuhEy;57grzF)y z+-4E3TN$uup7m;c?a*3jno=MJXv|6}>cOug?&qFND8vL5{Vb%JwY*Cl=RVn`X-1|! z?Ho&mj7_bgrBkbTgdLhz>Qps{7Qk4_(n4DIX4-7YR*&PEYEsZoGEO4YDv{}ONFQPp zIXDc|!^Hy`Ji%F-O9)9&KgSz@?&$oIsmu?OMKb`~?`Z8!>6rvI(muthq(ZTf{{(3D zLwe~Nsx4~$fmN#d;~c^w%}jxw%nRufkvP{2c zL@m_{N*XH4EEw!pCQ|nB?96)Df};?z{jVOv)d|slIS%8`IHX^qYpgaNdssqSK6Q>@ zx4?vWv!;)?Sm-<%1!pdc|4d9gtMQiVp1~vYix(&^H*}%essGqFVXJ!D1xELaU`iGA z6uy=?QS#<04boPj1`FD1;G&jy+SAt@=_YwuJpBrInh1{)S_Gb}FAMXL{+yY~+cj>+@PN$?o65 zTsc19+LUC!JbW z4y7<;zj>aosUUnG!g!UMY7Kb=!`jJmSqCh_{fen03{l0JVI)C+6o`y#>JE@AgdA;d z{B4AC+rkrL3Wme5=k#Tt^nZ=%%_dT2JF(*h)({zF_Zk4}9EirU?YR$_)AXYvLa&ZlGR<)N6Ce_15 zBAjx^{PMl-cUw=JmyL9f>2bY2O)e50)9aTT` z0uJeY(32H*?6*lJu? zQJqGt`c&f&TwUs8&~4t&G;z}9Z!bAY*4St|Lp9)tc2|WsCXL0Agh#k|rfGX`NXi7K%V9)q)g;vlxF-3T znX8bNjX_jQ7+BF{7)*?+AAHo+UYkNadY6Y<^IWglD9tPMg&5M{@{)ova*lPb!xyqK*G*fg|!SUw0rR$O{yCF(;HL9+7ce`knn;O39LFJXBSH**itw?g$de{#Gtra_1b3Z+2s1{U#jv{17ZuATW-Tfn>A z9bhnvIsYbXXn9m0;KoP-Oa((xB}l~ac3$-eO&Et}FT#XM_7KvU<`DI4U#YpRDPAN+P4L_uk2JVOvK;jiP&WN7 z@>~BN@t5XKh`W!NPG&D=of@KUY;9HgZzqx8N44RsJZ)W{GlW z{G)r^dQ|64 z#g#F{{eUvcI(PzYfWjxh4)XAGE&=W=hs9HFbP7#WBfZXDSyviX@hm5zfh1R1Po+@54#*`7MdW0%;0=mq@1Ioqs!Xirohm2EsPP#kPhFtuxM z|C_O>NOxs*5Cj2PuY)-Z1y{;1jn`vx zs1Y-(f~(cNg&~DfLrqxKwI0quOIBBN+dlLfu$VjoA z=XZ5hwAL4QQza)WVA{aZdeCatWp_G!djlwUdoZs#H)N?&Ms*bbkLb|;l88PJE27!9 z;Ew*X@>$>!kjMT%aa(<18P{^ZUKUkRlkUN70?#Q3I19ni=AU8E6~(X>`Qc*2rIqSOg%-P|RuqJ86{ zmqPUgx0q1XMwPZ`A`F~|Ej}?is+-i3xN%C|^fgANm6Zdx;+5Hm)cL%HLK;cNXr-!5 zGGn3NVU@Z2QQ?*~k99jKt@kI$%Y5uZdtcSi?U%j3<>zj`y2r7FM=8cZr_xlR7b@&t zrl*Z%eRTr;22Kqv&%sp^_^zoW^tILIr3X5LuISq>zT+mS^g4>#2HXkZX~K$h58f7~ zekD%=cTqrvD7YS4=Ma!&OfJkOb#q)0@RR8wtShdYj43IqYm_*v&IA@ytl>(60zolb z#ln%OX|%?5O7`FjDo4$ETAgkuT;?+hNS+%+`S4)gQV`LZ0ieMrIf9dCm*^rP(cKps zA_hrOE|YTFRx}ltmtKCzn3gR@%KK0GRg0zK-cjs51X=aYzVMFXdgAIl$R_FQj=c{S z&^>)au}2`mP{zEq4x~Lw(y*1#0b&QN_RW-U2QQp zC`X?sR%?4-qY8=A0r}75%a_onZWsq~;}?wi?{mg{#b>q9e22Ca;-cxvDftI&dn7Yg zVPy%6)JK^+?P{gBa~2O8w2TwGLC!qifLhD!mdA5rjrcdU#tfYLvk7CIZP#jdT+CMj-<}JC>58|bLN^^BQBrdwhX95`LP z)U6Zssb|r1g%?3RbM~OxmQx}AXk(0fhpL`XQUOS`sKt{-{EX`-JKV5$u66}aYZ&0j z^SUu2JG%o@i}iI=RWLbLk6)$R#cGiWcPCA0bU2*7v6>DnqBd1SKRi267&a;nCf(2& zb4IRfe}>mO9*FuEPfx7aC9zDP1z}b}&6^H^`-Aw7$5Erl0o2QZe4-7{&&n~$A+qjpZuziJ43-&a z#P)L+G*n_tk;2a)m-5AF@^}IqVs7P2wd`33h9r^7i>w;0@dOtgo84#jpVFs1t)8Y+ zbfh1 zAIfN-Kd2!%iPRMy`!%jI`S3DcIWw}wGw;zwOYq6cb&}EVQKtPv#|c}O2xW8xe>W)E zG}PmPL-4#?i)X5ni##Mh+pzHFK5kN0=t^ZSY zURUavFr>IKMTERyk1@xSy{*+#S z*}}Hf(j97Z%xvN7Ef!wdx!Ead0%{hpgKVN_A{S%oVxua&?^VO)Hhl5zP^s1*rBTg{ z3zqKYG%Il!Ly^goAS9wY>acfG=@9E*CGGR2Zn+l9OykQAT^`b=)ZFa`*!=dDYUHeJ zMc4T&g^C{K=%vL*YB76p-Styr^$xS`5&{NlQG_q0{Y$1t)VA+1148)1Q$%fRV^gE! z&=zl=hVw&1C-u6I3l1IcR%y9r3|u~CDII$Z#-W&(Be|PiMTV!GQVwsbZKjygjigf4 z&Mh)_fMF#|_0zkgb?Dq(SJ&Vs`dwR+7ko;HYB(Ftej7`-Kze*lAQXS(UOGe5A4I(Z z*e^ErfR;=jZx={2INhq z63rJiT9GD+da3+HiQ;+pT3r_Kbk>%*cV7yp9NqFw1Yq2=VRF=$$vLUcf1p_p@3JXt zHVGO{jNUdSkjqeBhsjt|m6|y)Pc^)*xC*!S#p@|Q^g$KN-(P@+#e+mPs~hgrl-R3e z4a!ea2e(|b+=(-GW8S0@Z0;klNi=p zC6oMRJYW2(ui{iknP1Vd8$jUpH0+WqU=`L~L=~3Q3*l!y^?!ORellnJ#ZNbKHT?f_ z8vciY@IRdfHbz#~|HoxqZ2loHjDF0sTD7 zR%XG%IPD^9WF%80CM#nU{F~`KLzLEI-}m|p`0ehyoH*!Zew6V)v2;$*4M7xgs{os? zAmQb&ew}LdB37UyE}^~3$47Il7*~o+@aCG6ny{LBKBNXX1U^9jl?2dWZw^Vp(WDX{ zZ3ZPs=qc)JJ|>-?FoXb~5|KDp*W@V}5?7-WqCj5z4inR!JP@~)dj3VV3%xfI114NQ zA=Revhc(SlWR*Si=09JHR6q<)u<~-%&3sSpQwSED4tu!5dVKQ&3;jmOssSa^wytXw z;aj%nPcfX9(_dX>Wg}esD$LIgf|w!x|EQ&A14M& zDZ$znOdBhk7N*5Etz!@A&QJxZS=1GLB-6jy1X3bjmay)TI+~Z1zlxjfaWagt7=P{y|Q?AUc(?3CXP`Y zvt=F8Oq7E{OiWaKSbP|c@z_o4X5iP+JfE1qYnM=3NCl{BV#}DWqJ@TqX9B-N_SB~C zs9f{8)Ok+}Yg9E&6JxTZez}=Jr4e$WZW9+sSFXh!5J{KQ9#TU4^P4~lvB-HnE&W^e73^?5eg?|^kDO_IG*LZF^1?QD4at?VNr zi-(3UP?uS;y_)U9+N;38aq{v}Ic0i~4~sqkKFHG?g;Qkt z`x92Fk5TSt6@w%#Xe3GmIT8byH+X7Hi}fg*94jmP2x(~OY8v^NYy9^rw&!i3sS8Wa zjfWM(jajJ(0~wmwNM7j42sy%GJhf5LipU%*^x7150pS&X-?X5svfvdaL@lSp>w~FX zywwGzWz|9~;?0B(f<+L9Dx^6aVA8i|<e+x5!3&DP%V(!*jfc-JmZH~;nTh|=%;8a?b_qmR3>WOpLI zM;iB6B69h;9^Sr_kKS%2PdYtM5cd{VXJ_^_nAY!`?1sbO=G}U)n?L8x=1o03$c*Gx zyY;r&9^AdJ>ot~=eYaWH_c}AK03P|VWrG92uk;ZB=Z>Xai4V%F_J!ecT`Uh`)-4iY zGN>Mx``v)|+io#Zd|?rDSr-@lds1RJg5ak#2*^%Z(!~0ymAb*(%YR=ECnlG3m#nv- z%X8}SmCY<{7Tjzoe?KgT zX-q0_khXn3@`lUSMc@%;WzRFV?Y@7dJu9!Pa+|?x(|;d&AJ$gyH2NwZ-{$!*UcRjd z^2^Dtr?(S&Q0I9Vf3JYe<66_9#Us_8Gky#t9*c9!rEW2O6KH1tJT7f*#0Ijz%&LCq zYrd6wTu=R>CVx((ioqjKtrq{iH{ORci?$rL`;~^yZ6ntmtDpQ~@LKNca*F4j42FMx zGaQ&@MYiYEW$9^oOhyvB|2jE%HCIobW5J3CaG(1RGhaS`87`mi_sHHY&uxE<6HCKdwbQX) z@@;Y7i8$MwrJKyGhwI?A0Z%)#sQ09;RC(@tYVz64d#*ft42L@H?c}^&zwt*ae-2v} zx~lh=!)3v89d)y;n0VCpuoSe7$GCuT=v6E1CYbGy0piRCX zEeE&#C3B^z%Dd_HM9-R!#QUaMyDBg&^&~=_T*)@stgq|m*>k7=a5oXKqL|Klb&zDTH9CQkB&6xnxYOXGg>;q}5_?q{EUIE8*UzsK+@qsn;p_0~3KVy|vnb19ManADi67!27loekve0y8Zwl~wD-|Nh!Ec`Ccj zIT8R?(SFeuJHlOC=O-krdOSw90-yH^gxG#U!Mth5UYc|&0g@xc!t2Iw1Kdtk(`yNP&n7=Jglke#A zy^0K)wg3A1l6eiaE>pkqG=3UV`qqpuaenc*FFhWO4^gSn;aq4qkP*5=-1H3%`)|=C zfqaw}e&+xm@b0wIvIM<&4PRS>XR))x<*6$<*3rjbx2B!f;S}KAu{3Hpora$W=hV4& zxXu)wB$Q|xD{iw>!>{*cO8H#&GDr-<{4!<9ndH!EUtd3RAw^)SZRrZr!6}J4bMG4pKoOj`4 zt~>bq`)K{m&NQPLYMO2nNB8!OnSMrny>`0jSfwAHDpI3q`zY6RcD@cRPolH5-NEJ| zdDqw4yG!?dd_!K2gdA=YNm+4mS1HNqXm!ase^ft!{-jY{gYQ})yuDj`akkBDiLN5N z_QRhlx6!%$d|jZio1jj6x#aA7J<0Z^xaTMBeo%8*@40EcNJR3gmHYeE*QAyB`MH1T zX^;D}-*HceO_zP$Nb`^O)EM6C@HwsiyjR$N^LcqQxL&JiXM%bSkp80XPRHdf+vOnj z$!u>E4f|tv;GR9Ii_wjii<#f>!5Fuqg4*R%w9mQW8Z3X`)lw z(X;YZkot@}8GHxVeQUgrk3arrUEQP0UV$HZKL1=7x0ldgu0G8V$Mr}MZ2#Z;wZ`V| z6MB96PFnzg)&6+4)*er-ukrnCd44f}Viga|p&MtG^W;hKQo;l)-%lBL^;S;vX0_cL z=Znv6^_?k_&oPFw>eas3{i*AG_3ZpxuBzJn=BFnW-;Sf$bCK0FrsHIUN%tdSiCSE~ zhQfR^UUXYG-_LQuF23PK_S8??{f9HxSKQEJHqcSo4ejS{`?v_QZ}aCbjB@Evth}7> z!*JrR>^Z)+u!y%5h zAIucpFE`D}Kxwz>85nMUn*<=8r1T^x#$73H`GMP{AVMFsg{SoAlC*El_~&pIG! zlM=%7vh*BG>h8Pe`l6S%d>fmh9eY^$JmswW#;0Lzv&qfEr|XWXyxZ&UefH}?XnUB6 z-JaR!ZDsWO`d(HG|C5CszFqtK52pih0Jp4)|NSM=wW;NO9%eM$3_Z`0pVfN!WSZE| z%Twpf`Yi113>JdDgh4AS>TI%GO}A9u%8(-f)o_0VG) z$SEv0*N)n)zw>t`yZBV~@ADD*rj|9SzLpNW-H-2yb<>i0J$9SA?3OFd*>D?FeJr=R zq&R=ErG2#KKIKM15AV+H%+5wE^l)NmcNj#~RcvjM1cRy8PR#gpuNoj2BP8KCksRe$TV}*} z6CEEF6IIwwx)A|ekTDA-R`!?n6XD_=Ui{+QH|d=;y=iYh<>%GWeln`f{#^a?t;X#(O0TXj;dS{oUt~zR z`NATG#g;0^DzBmbp?!U2YHkJavYv*ZKdKtZ(yz<6)@xh;bKEk>lPMXR_7>a;Iegt2L zJD?4J?bzp8jOC4`R%KJNFeziW?Y25bW34ScT>h1fZbKgOeVS@+IS=N!QqWb@a>@68 z59V>>_oY25t+kOuqvVTU{W>p+4&&x-b{xeLli%pFncg&DTaK3VntK|(1Z<7h!m*dL z`ZfJ58axXOyDXie&yQO~nP{r}#p0X1L_Mi2w1WOFmc7YzZF5$~`MFv(`sFz*6-GBVszGTvG?8(A^UXPSMU=ri$a}zK> zDLnO)!e+XRPCue$kKXzFbMr|a{_@UeG@yEm8Eq^40)z2!VqG>cV2hvAhv0VgbezT7 zh&-U3iEO~OTfo33xBUtj;ovjayX7Cz<9;rhFPtp=ICOxdJ;)nCW~avKje%>w{yD-) z^8=V5+nHbKU0N*d-j0O?@8k`z112uLNlc?=P>|C)0ISHh0Iitk?XI=3bS&wWkrt6a zc=lo|6|kM2KRcRB(94BdOCeZ<{C_nAHvYN@87p!?iHe~#&deP=rYCK)6!z6M_3Q9E z4GcDtEJn?jxn|mfieagO=(6d9_v`hw z^@^%}n_FR;?kEVftU~Xzx*-nxupKdUqpZP#PJ?JkH;G)=g~d!^IC8@>OR%) z+egW6ylwEmZZ&MI6wUYcXWRYL>*gze3v#JNNMSYXev_Zh(SxcFzCcQ}mHJB?&w~F* zu&hRNj4luutEp|`a!%*T_UhjlEO^&tC9?mL(;g2G4<8R79}$HIywaY%SBZHHwQ8!D zXn*r#{Jg+C?(0wI@xn;7w?IyN0DH{@(EJ0Tgd0AKwU^rHINow{tGC@?r&G`VFk({A z-#cc1Gcpc9vtjnpc{eHjuC@1bXEpWne3{9*#-C+qSv$I>_<5U^1#{+OL#^2=<00GR zeOo$Zck63@7I|)wOx9=X``*ZL-k5TCf6C?hR$2_Ahk~6%m&I)z?)jjOx5Raapu%Mn zeT|TOwU_t4^vym+-ihuqguy)B-?@DA?pj2R6l-5fmA~#N`Mq!Av|g`S@dk8#X+546 zbi73Og|hDU;@UM+-AnZ2o`=i#E~nvpls}wjTxsgJ;}@yxPguI#SNMo>o!{;E4)Q%l zxG2|dJS?u4-+o~(o%4@v~y42+UiQ-Va#VJV5@BdjOx9ypeT z9Qav_`{|1(;~Ym0rQqBH#s<&&(Zg0y(u?N+e)qhVUGU#9z5zQ^LyNNuljoFA$xq5M z@LmMl0_Y3NPo^JGzNtT0ivoztWE+q69GR; z%zy&0l+ZW@u4#b{3kGT-p#=w(IC1|AOCh8Mkynyk;pKVdlad!vUl65DeCiskw~;>& z5Pbh|2bB6D*H+Bv0r?#c5B%(C^qo`>JpS_}Rgb2ZfG0j+f%80&Z(2EBcew4HWMgE`s0c8hR`$6R!&`$j3{p6F77f5gFjvT+N zd=dJg`FZP;l^1TGpk#)MNjy|WpA3B&d$Q!M$wLNCS-^Pt3FG%2<`-XbG^z*LcKnQ4 zQ^wDev7D2bq+M2yQA2#qsn6!2zF@JBz~XOW@>OVt4C8$1FDSZSFLg*jEiLs8JZ z?ofn&C|j~%oXEdt%7($=j^qU;dqwh!dW*2Mg|?O~x03I3mo7{>cRJpDJ#oNfjKM^P z*@@*WW*(qPY9-Otm{-$&pQZ~b9IZM%SOHTGSP&0e~)uQ1``57#X zkyIwQS)zILDQt%BU{}Kp&Ezy5{nQT0)XfsBcb{D%L-)jHtM!Xh2Cic>vD75An|YV& z5H~Lu-JrLkxkWi%Vcbi&>Yk9LI^6^JduRc47WA%eM&w+3JHWOZ0mAaKT^@Kjx8;rP zbCYk^iP#_eqxL78d)Mc4I@I}*gEuRtkoFmSS&(@MXU?q!`Feyh9h;x)8u+e^`Fweb z!Hh$BMup+|FXOWeGIL($manKxazfp05zp)us*`x;DxSsW4?xe~k}G?$5B)6H1^1hU zv{3z!`ALEdS`Cn<6j1V1^jl)Tk1d1On~^62w&1__dQL@_0ck>X=11^oG>1)T4tCWK z=Mg}92aL-E#Z>~%{9^%>90W!1LAap;f~6dh4`$sT(2Ec}oDj^$9n@>U8O?}e z1Kx;%XTTgG*BUTvVJhQ6rV$G=WVeUxL3h@KBb^AFM#yaw&7u*C(}2Zk2yqm_I)-YU zi0vl6vj%bANdM3eeiZ$U5Z#-|KO_2w10L+a2PFhr;V)j4&^-f6I)pk)VS>4Df1biA;p2hm0B=%Hi zd9e>qum&Lu3cbLv2O(Biz7X-JF8>dR7dZCpM!t#M|1sovg z;@*%291w+dhsXklFD}2AYyoA}U#>{)2QNE(dw?ntXq$kvSs3VnMm0D&rtt>vqu!v{ zZ&2TJ$LfP@6BMDO6qmwpD%`2KV^AnmNkA2%CCMuvs$5-(L6s*}^q~M!p*A5Qs*tFH zf+{<#)Md zi6tFdJfe(TDY=Bal)S`Z#l;$&B{^MmqVQPpzNEYaY(>}_p(RCIo>!PxTBa0T*}1g1 z1ZBnjjP%Udn)wmn6}usPUHYO3QK??hy!6M4{TbXf$t!R}!nR1Sq)lnF0(VKSDt1Hk zx_qNDy;69|@Zzs)3YS=~94^G>C)*mpy+V1(@T$0aqw|e%}QJS9WyH(S;{hfP6vH1)eLDZJyWCd?Qq@RMiCv zSIT=qk45@(&d&u)0}Y-lD6W*RaIsST9Oy!pD``WhT9MfgHg>qa`2G!+1rjj*UUWZ% z95_nIR|(UzOLXVme$M@*`+>JD=pJM`0wY2V6AUmDiOEQ0P!by%!^9p*Q)F<9;Vm{% ziOHIu`#firK`=HE%5We{iZm0-#2|}_G&0KMAPc}8LSYKdBx-OY&M2HhXz(81<4ryv zm+{9D;lYm^T>mSn7OboH5TJ+$gtZZ&wP#MI6_8dyd6((08 z|0C=3sPE+}gRo4X{QW=<(tRX>i52?cMJN6;X&INBThAu~qSL@NyvVQuBlTZyT}m^c z=ei2~Qgt%bs;~}ehq{0TSSwYKItj2_1-A@>_0NvIxbaSTb{ps&sSA7N+IF=bqVIgvUZLPk)2U|dGDR%a&bA;r>yE9*}=8}zi8^N*>eoVp!dR`|&v zCx0l~kEvfjNU7-EBa0TyLjww}@Z@|m0s3s=DSi>(;JkX#GJ?GQ!A061Q`mIk*7^eW zdA=5qYmrY*y|h289&sA)O8xf@cpeOxZXC6nQJz1smj^2-YuxLbI)>$kfjb+uqZ)zn zCC4llV9=`bJZ{$+{Mp+$?K5lb7;;0jKhFAKh>c^=C zg4YGR52z+-!+Y|zhfTVd*WXxmr%~Gr&=o4=h^@$hU-W1`8&=(665Y`tJ8(8WE<5M3q z%*Fj(I>d>k2ZZT`Gg%I&?}*q3hH^#j2$s)zpTSb}PWA#|OPS9=o(MlcsR>^BJ`i_q z3z^Gyj)}w2;jy_&DjW<1{q$}Ee!iVP%wESQuC}R(d1+hADM>rUm5hXZbZlf?G%O?< z0R5}tx7Wu91xg##Hb+dAA~ZyRR>6ME4?R+w?81^*#xrJSVF^up@SslY|4uNadWg-I zMp7N-m;N*|3(b24Y2@97rDY`Qb&?bmq$#tr^|r-xuQpuxaoUitAQxZ6O}Eg=QwPtH zf2b%5bLRyR+51dPxweC(He%ZKjl`#BDJ6p*-8M&-A1u*4BpBC8n*uA~PPRWEAG&M& zn9i6J{KSUnTMeit8*CfwgE~8G{}*Xr8C=)0tLbfKX540GW@ct)W@cul*p8i;nJH$B z8RD3knHge??Qzb%_qaT$# zvlFV!4LV@bMDnZ2Tap+X%G5gWzVwB}tdyauxX$V9awW|*YT358rysfRm9fZ#1)55> zH#VhyBkt|-zsP0$9qQ8@&ykw?Ii9S1nME@s)kHvn171ycPfTn{T>H&avxkA@n}rzzaLD8;=V$5nRb3F1@zU0XPm zvf1HcM}gLPj#Si2>5CfOP`K%VbzNKXxnIFCWVje=q!ifLqv^wtH&);+ zP;`>kz;=a#@8!qH)Y*=|elDNKIDTCGuJuVnD`libe#M@S9JzgAVDdIyc2_qA0-_G* z^PK~npOI2>osej zOlN!|?WE!M@Kf)vzMv=wgb?{y1nmQF=MyTWaRa0EyRM%;8l(4LZ5=M{sIxo9%)aX8 zDzmTz$K_AbSxsQJpoqO$ds zS~L69bfj&j8Hmbg`9?_0cFNH6QAw!lii9M7godQr*7944l!aHCbAf6y*bYY(N>{VR z{aB&SDQTRc%46mmADAA2LmV|HtHb_j52>q=VCgbF(nc;W)|P~ZPyV~#UMn|lh06bi zK`z>Ub#bZgnq=o|X(^n4 z(ReSDj3{Q0Z6sx!Ne6BBeWV4c@l;+3bZ^6+-rV9FB3oV3UD~5X8bN=(Q|QMkHz78mWRQi%W{A)83m42TwvF|K|} z%C!!zp7b(75)Ho)aRcWagBio5jWS6VO<&b1hoo*!PUn;7-Ay^^Sp%BQdRW zO0o@?5o;EIS)tmq|E7eE{FdA)Po*rKTw7EYWyq)bm7Fc8EzO>zjzpAG1C}6&S1C<= z0rcIXS4Dc()GTAoBej$W>2o;US3GIZd3)GRI#%q!?(Yancg_nFDkh|MVay4)YB0-f z^jF#U^j4RC%7Vg+=NPC}loP?w6f=b2y%OTCL==q(2(U1p1?1G7_S#&FV}?Dqp2*eR zio-@Mf)<5HTC>?_hO`NwgdVO6&H_QFuFy8RQ5k7tlaE4dKnf(9X^Vwe*x0M$QihKYSu$>6A9i`RHPFW2jQ4{OSH`)ju9YP-1~;%}ZiDjw@b z90i^!)}qvTFrc7#Wk{TnPrF3Rtpr8o%*@1CFbK@2d{>q6>1il9z9ht564udKE6P8~YYvvymm$-s_>BGzJ$nEnFL zH~v%oG?lu7O0aw$W5t4;tAr7B~g7ed@`X^6_2Zyn)%-{8l<%rF_+yXwKmyXRG%?ulaK5d}9 z%*`Vj*0SewMAP3(OMf-{=r(=4Pt3Cd%1BEq4-ZF%V_;Qg?W!lKi__GKm5~JR3J(ge z!9hSg@o-0Te}0+fSxH#%#e-+A&p2#o5K}zOu%Om>_VIqQF_T;GiY>HileoOtwoNSd z;w*Ifb!!H;ewHEq$QMu@nX-_OPu|Ruwd5>PlEh5HTaDJRI;0>otKypp@j#JW+Hx>q z8&^GoMpo&T$SVU6nscVSgD+KkUVk_<=8LZ9;@--^J~!C@Lcj|_ncDUTFP!U5`uBIUwKC$aMirECDf=Q1l-J=qqQ*Qvj&{50sjQ(jD&J^5IU=R@ zvU7aU-;EHAdWKCG7Zb(_c6kd5yCoh@izC1LezRB*X7U|hrSKydL)QO5D>C5~`6)6* z%YGxWD@RDpQ{^0-ZJSzW9}jk>T^NC2t7p{mRa6bUtP1brNN6ypUd7hTCXC}6_(m&1 zftnO#XZ^Z;dZqnvgnj{Nstb8>EEdtVbZdQv)fa<9`zQ_ZL9r8~!%tLO5eDMey>$4E z*DECnl@kEK#FFQ2v3lD}!AbMPTAS_7LWGyi{sAxEZRhU{4Z+%8JcjDB70#|neRY>H zW|xvWRv(r#I_&uM{R7IZvfMfwLF4&=zKYi{^_M19niRPbV|F^ajcNi}`4~(v0h=C6 z_$4Fcj^_RV^tOPcGt}D`0GtY637{EcD7yL6rUtm@1d>B6uT}O*J{|v;WZI&K&q)L- z7%JgvWFakx%p3F&&gN!Gmy*WiA`^ESw(}|hEheg-k zo*N}_Mw)VnX zrcFT$=Q9v>%+gR!ilDKFHx%Vyrw2Rd!0_t(ow8x}i@I33XqD5l=?b%l?sO_L5|mD6 z-Vp}=FoJE7I=uv|o?!IDw+Y^CYqB#qm=}@0?xZ@#53&nhh3b;erw8S5B+WYurq5Vd zzu?d}aJqAbdq<=^bRw-v`Jl|zW1d@Ty{Oqtx>@DG)pml$aJi0#Gu0cJ`)14;{qrsr z-LSG&LSY@gq|vPbS;M5O-LP;7$adZA!oFJywlRBWm{}p-eG zuN6B>QY68G`MNfxY8xCr8dNYmS^hbNxwMNvOED8}c7NYqJ_Ccpd7x@=G>zAD*y_rU zXz?VpSfHkeXdAxH=pW{yV4{#hv(F|sLk|zjQanS}t88gZaM3nzey_BwcS*8OLJ$=j z3Da;nO?B`AIyR0>AaB+Bh`Ih{3sCn4Xxq^PNg$gD+D+t=I@#JkshX84Pmo#}n(ptN zp6!h|If@sa(bLz8C)48n#Qxkma>a#`W4(J|?o?gBXk&LtWV4@LjM^4v(c>4AqCYLZ ziGE~ydQjWNo3XKnb7Vt0>&11G1;JP$!ao(qA8>z<2+I0_FC>Mb=M&E~D{NE(HY}&; zZDj>+Y!MdA?;RR}BBT2$lmewF8r6Gfe^m7R6n^)}XyP*F5?d?dfiYIk#`e(G%;UexOUXrJHIy};jczdSGd_Gzc?ZS`5T zHe?dw)SQ<19WKA>7S>g|NEEkDCPm%>F$@Y(EDt{_))~k!)EjQ8S|mM0Li+HqlmqI@ z4veXXu^D}o>5z=sf&lTNaR%c#Y_JICs?)l_Ir$x?;!V?I;-E!+BU2G{b*Pp-09 zfqaZzlQSPgKqJsJcXP_}^fZ?M#R&UGu0JEK|FwL-^5O!Q*=zRFR&#BG+hl6Uuw{-g zXR+4kE&oSE;jIfSX17Qu&C*tj(EFM)2=4bWNjf{RKcg&5ONqO_4uu&7V3`JGocJ*! zXEcIeeCm`ArxnD{Bxp80=r&0)SNk~Z@3{_EJXj|?gQ$oar=BCnS!T!EW*ol^b+H9R z%N4qkYmiSN@IoG_&EFv`rE|4%d5yci()d12$^M*Nq;L=OIEKJ)8sIix3hRB96klHN z*x&4czvi{DGa6>5BH*{bQH!WBDXu%w`WCC@fK_j%S^sgWU^^8FJR=V~seq&^C`-mD z{_g>+)v(I121Do_*aed*H^CnS_Ttty5t6+9`zp=rG+9#19)ZhTShh8YB{d+7Twx-I z&Dj`L2`xSaErI0`2Y%tIU*c?Q_qfEh&UlDBf((m{L+1;`b`(Wtsji2qprHRrofikq zz-Ioa!iqDae~_)r-fZUVm`YdAh?Fpt&|rTdWa-hR|H7b{lLLtk3TGKZwWawxI8;Yo zQNT6eU*g1Y{Rze}IKH+Om zbW*RPa99^j%7k_bU*u-!LMh@SoZFx4cr0wFfIW;5*bYf9)_8~JCf3R?blBud2pPT;ZlXXUA|ZSeSc)%#ZcDK zL*90-SCJYjq9D`6(!>g_)y#>N8h>$j_luEA1cl~wiG}BgQNA4z>j9&TLweD_%6N<-NQ&0>9F%W>&Igw^S$UqUk8b3Rz z!9Y%3=k6;)=4sPF=GU6`4u8{PgM>gusz(YzXk(DzO2Xa_G6@SMHg`~DK7Uk9SzwOJ z=mmaWV~zR@j^Yoa;d z-e3x6WyQqB9! zg@vqXoefcf4BY8@l0YYwWwN9g;vVMD0)X@q?vAx+H#q0@MG-zvYepCbLbM)3e;tuQxf&PKj*XIUl4CF2mTB@A|$aqoFxx`q4p8;3-4 zZD6zux{0IRaEEWMB;$YDPeO{is| z3sRAfd=A4tRj;85udIz+VY61ejUz=vOLN#@@W91t%1xgz^fVgYvJMv(5cVk_3YAh} zzA}gKM}^3zYV1eH#!Nv~{Q!W9^0U%H{bB3YOXdYl(T6Gr+F(SUOtG|H?SCxH2(G;M z+@3h1h)!CUg3>yaX5X5sNgENBp@8*U1Fj(||6@zRhvE$JpUH|6rRU0=ot#tgE-PN( zkHvIsdV4Xy&_r1hC56LfYt^0(Q4K>aOLIRDIwdNR-N6bj`gZX9&L4jL(a>i{&SCPk zfSiLlbSUG*z)ngEx1rf??%Ss%`MWS@{s?kk(TttaF+xGAx#@9blfw!Pt229hJ$<%O zv{gzDf~>E}8;^SVCGOT%hO%_^oZZPy~i zY3*p47By4kLZ-e7&bJ6*N0G(n2W#wBu3CpFkC!WI79@r+51mqfE>e+BJ(TvhkSFr5 zNTk=o@r`fDma-sqjs7W5l~%UKCUCZ%8!b$d2yP|0Ah}!e2^}eyol3~qv2yz&l$OUa zb|MHLK}hgRqfK$VQzj>sy`8h6Al8jRZlo{259uC(YfI*?;_q>kxU|wzwCH|5(#H-E zPueX8@GS5j!GTba8ERaXLN|q2b^%M03_Fomxm2Lk^Qb5)!j4c*m{5uj_q2&yl52Ha==UkKsNCX^pr#g^>Ad*tsae^t{>N z=aIb47{wx}*d=WV;X)}rGNarsCdOw(xBEtn)_3YsO$cDee3yF*WM0cUS61MUO19-4 z>NtN9T9bxhh}4n~zBJYcc+~&;bxC6XtS7Q7i{OrDYr2Ei!YP8=A)3io5vZZwu8_%6 z5qMDMh8bw+>tx|^lG=rkbRX>IqG4<8Hy5>#B~X3vShii=>88pE>PVuzyzy*hSBJGX zZm?9|r9OHNA>2TDQz=1#pan`&5M_tg7X0)1tC_Gr{C$GmXH!EmXgowx!fm`tJ9o|N zVQFMa9+MMs8M+jiY<@p{{rG8^=ScFw7E6)NNRh)`2KO7aQ8SiuQLD`*U;D%# z{f!xJg1$O5>0@VH{)lH>k$BUKQn7m-_F3!6H-)o)LA1$No(Ed;i=syo_1O(J2~zpa z^JQ848DETdcXkg>cI_IbXld96e(6W+$;@t**O!Qo(F~f9%UXDq+#>10u`U4*^~rwn zwdaPVu;8}3;Kpq*vt(zmTI4Y)v~tjKQ>W&YcxqWe2EC+~ClFb+9jWg{6?LSNpkrb> zxM6;#G=`CxeX_;gdFI44vnuGU|lyOouJ@ z0s5M?U`gB6Fh%KkE1*@<9uR(kM#?TzYN{}8#WnEa2QMb^8=IURGrB^rToX!>2&Evv ztlv^*osJ1DQ#@2oY2Z&&oq>X4FWrhk&-xrvs8Xj0t6*I^BZt_0anX!ccwJ_dMG%ix z;H<=!5E1j5hfGHoV}A1k~^4CyiIgM;2Ca#*b$6RYlgS5Ud2Q zmFR4Cml*NFh#E)7{~SV2LDS}QH3B(bV6{~8nlB*fM?B0RF7NhdQCV}N?pKxTPvO6c z2)3m#dwM9(dFi|QU0r#oPBD5m&jITjpS>ba-K4tw%YK>V=f>=yzy?bxnXy>K$3=Xy z{O*$KQOt`X0&a9jUN0(GSS~u3aV123QF=m zCx<|ck?cq&P{H9<+sA2SUnp$v;F$96+qk%29WrFSWwD~(?7^OIDzs&+@tyz5$=Q2~ z1$#I+-l9(2T^T?LygUka-Dyn#O?Hd({UQVQ0nI_^GV*}*dPE3CtPV>}R8P3y7pHb} zio%UUIu9LMqJx!fqwiKxcceyQL(>-hIC(@^kmOq}|-)lK0W+r^Fmn`dCKmGinTv9K<%{`kV!0A&l&lGPV3%|J-QZ3G`Zpn5x#B4+u zMAX%rhJpL|g=)uQ1>4FdsUppbIb;BiFKP=hwqQYUR7dcto5yB_&MIpincolKNep zh}%Tfphcqg*GXxiv1kX_st zhx0py@b}pWN0UF^x`#+UIlTDYWDPxIpS)G0GZf|>tvgu#PJV^U9d*0?0{^O^CBHfs z&8Pv6Q@Q$q!n$HniXiiY84-WJf3%_W1EIkPDG&>X-E;Y}<7a5g?|P48BE9zYPM5PD ztwq4CVR^uF_Gj?i#%%=F9=~&tCVf&DiToqql*B~J`|BQo3$5Bg0f(hw3_QKMUK}W= zPR$0H0{uEw2;&wM(mow@-~b)~R1^%H5)a6PJ|h?%1(gJ)>yg7yloE^J-J%TR15RD4 zNh6%tKAi}Q6cqGp%Cs7`lI_GJ>ziaQR-WB3>f4jI*pIGRGURQ8QfVp&|AJmxu!|U} znDF7#1xZ|*Xf3-fk{c~U;saIZ#dda+HW3%cjDZCSy3f=_OBWo`?bh}2@K7wxHdsw? zm6-2jO)1ec><%)~V#g)Q9pz?srDJ<>eY4v81&tU)#P9xJgW<-r!&#j8d(I)Z?r(v! zqgLh8D9E9qe9l2o99|}>9rFlZ>d=x+C?{^XP&l}Qu`d$u!imrsuXx_fPo&NIS%)Dr z%)ixBp2fvlE_)$&PrW89>`eKY`|;klxIkA8U_gKJHU)*;b6aGr;39NRlqNJ%sG`6* zgSa#S4@UP~Mud4_I`U5bY2d-QGBIr+GInl%311VV*&&G(bz(dL8ySo5MVLHCUT@{L za|JP&uh3<=kX=Gje9uuJVB;AtS8(U%a^>csVf0itxGNhP;)2@Q_1aZzqbTW1S)5&% zxIyl-G!VBZ4d=;`l~&%?T8e7dXR>8Tj7bod^jJ2UU1tZ4m=3Di7rhhd>IX;Z2j^H? zAb%6^6cO;M2b^I|E|q|^G68a0qA4LztSHF(*hnkVFRG5Yqzf9DHT69CNAYFtxyir zym@b_#}kB|uFVynNOw?Cv*s}L6qxWK##6hYu5yz6py- z<%}LN)G03Lr;rz-LPXyNfrOgknhHX2$x=uNB9}};w5h1GDH|Se!Y9hXFu+iN3O7}n zH%ftDUal`ARQB^4jMVm(&PbEGLusc#73|@Ev{x8lj_yLGMYYZq%UV)^_;S|gw|(ys zYEI7l9pa#)(e#*MG|!=z1Ixk{=^-Xuinq_^*=r({fmvigUOSCiW9{_|#_iTCd&I_` z(a-G0Vgafa%eqi_ztFj%?~(>Z-Uh}@7+sA;KGMmC17%paF1gqiH>&4%3iQ&)+;r3H z><&^k_kJh)A?LOS@p6sI74rrT3JxA5zD@r3sq+1uanTsJw^00?&6+|A<7@6+IvyH$ z{m+U;-5gjdR`5+GN@U(Yfz#&0GkNG7K$-)~^yImIH3E*rh0b zk23|mubOxZmSr=pzF%#^v04mW1i*ZUN_Cfd_at8M$RRO`$UB$gVG+bk&%a>ti8vP1 z0ewbYK^#GzF#!DmLJFb^@$B(T-l%UD8zBIHzz_$8`~_K-*@}12?LK&pXvRy3%LpV- z&DKC~=u2?qQkKe^IqVRl2(devaSP1ke_QxCj^DXjw z$PaAC3^*W7xF7MJ_g)J6{i1FVX-{#bAIh?4 zAkR$&Cz4ErN4wL078oqsV^##+YueD|v_)S)1bc*p2#w&U)IqQ$Vi%N0jlO;2J)EU9 zvIF_W9;rPiP8^7^aL=qmiP`_C=xGdL#Ft(RVkeIAj>&i%hCl`B@M=n1S#G`G5~R_)W+c=V$VQ{h9T{X$CEy815eJ zwPg35Gx{r2YnMO_hMd}=tenmvy&vXyk0q}yaZ{ulbPxm^2rM8?NE4tjB{>a0gf>1T z=pI0q7qI&*(H1>Eh<{K~FuWka0U6}}4$`#d1(7sJbY z%0)gW-54TyNH1k;P4HtM;8JPLit}^ zCW)wpGXnXKMaP8?79^je7eMEl2cM1^~ z&Uz#2*0MBBM+oDZCALh0Y6ye8(+eP5IE`sx0P6VRUBM7>${f8oN!!5dIZ;>-K7-3!jmZy?yx^^VW=W{`$s&MZl$}4k$7?IdNT{5daMq#RZ!u3I#9c~Jxuo&E z(6fC}xiln!_=jMGf!gVpe8wPWF$EJ?YcX{z@L9ay8Q-@m`vAcYuQ*ty$b!2udjpFw z&CB6$Al|G5LQty+-&#YW_x!9Xjz}9t<^cNwQVcX8E4D%2z*RUSdqhWFqFD#HKH#iiY+CFJf>bC0ELsi>5#uwHs2lE@Oz2bGXLqP6hiT90dWP&uVO9{da*8EYG+YsR$xx8-RG700m?M8Byu6#* zm0qn%z%Ixx!1N0T+t*{jb&oz9>=YQ0Me0KzyMrWAm$Cj?-%aWrsnor zE96RbFqeGfx1wYt+KUkX?;tESAJ-_Tu!ZS z$m+ezndP*|@9W|!sE$coL636v5O&T0+#g)|0(q{qfH43i*HV5qDsPsN{Qm2dj5Ge) zI!)5|t2^>v!b<(`tW)8MP+kd8AX!hotuL3v2ETJfQJ=k}EJ?|He_bbCKGybHock}m zy*=b{z2){h+zLKIy}uj1bBp}Id&ikm4n+DI7Ii!*bD}*S~;C<^mTFt4qRqfkkUm*zbOb(otVagie`lYWoNP1of6Rv-$~ z6A|+fIhpV(09~bk$t*ao4e`r4b}~Z74mI!Qj2&n zi6U`rUJiyitT(S3{Zsqt`>UAL3#@k>*$lNvPRMWgQ%+DI*0CS)B*-fSF{4QH%!hgS zJ1`N0kesA$n!Vx?<OkqA&zLj zRRAfeU$Z^(O^@Yjg9zcH-Ai^7l)&o7A3=D_2T2?EA*~ug|KJCK#7KV4A2x$0J$IwHD`mF& zr;C9u+oY{a`X50sR(te%? zFEhT@a+sw5X(9hToc%7m+kAwGDxL~NC(V`ic>EW617A*L7#O>f;Y4-tS$?vvF=={( zlRXS0O^^=QlMNd{W*2;-Va<{|U8MVKX0`B=F!ykxj6*7q@f<}${{wf=W%|!iS&-ym zI)^|EA!gTH^)=vCRdAu2Yo!C~y)qt6xKvyR zjR3iClO+zcK-L9U-}->h?32a;=Vm25TOecpF|Opp;WQVnnWKlsobD+Ql?vBz-n*966`Mmp*K%qD0e-f)0(i4q-6(L|-A!&nFx!-99Z3JL|D~ zTFaz4t^AJLtJ20U?6&3njY}KOA!bMkTgchV@Q8-H>MmoUAQ8ne&sWD-37+07^KYu zRu$c5OTI1wqv3wm#76oT=RV5N#NV;rPb}8DkbVvajm@2>@ITs~eI^(bkA@z697>x& z51;Dk)_9YPA|K>WyrX|b8UV7gtAqWu+s%%q)#n9RZZ;36U#F`zLNV@gT0+f{jy`~` zzdL#p>1mp9A|_>D`EFMy&3kaTX*aqkl-hEybG+{>cnf3_ZIz4H?IP*A_NkM2kLyjk zC-C(heQe8`og(#W#=dwKI*!@zS%XiR3$0nbliYQ%4eA;8@hc%`-17j>gMN zu68U7#YlnZKboI+-(5;}VzX11?`o@x-Ua2R*1~Z!uB@~%X4ulURww6V5>!qx_d|25 z!L^5J%1JjQ)itfj?)l8#e|>XGaaPq7XNvc8PpQIab!u9#pJOq_+Gs!~k4-~9>_FbV zF2CMP*1{vJEk7bRmZ{aQs11N=VGaF?xA_}OV?j+>b9Ii2jr<9gmCk|9T2pNiUN)KKU5vpP=a~8!W>`(-BJ67HV(fD4eC!(R66^}>0xC6l4R{rJHFza- zs%P3~>KhDy41aX*n2i{Nm|65v8Xp=TDh1^|ns(ZD>UJ6hjjSRrzf8 zLxdqn)vbxI>{t4zaUH)?x0AGEJE$4Mh+#-2py^lgsCFH_V>&1qgM>juwV~Nr%2mdd z=cRd_uwy?MFsK{DiQ!0PpxIgCrG6c=V?HPwgN4CJbx)n6$ye&7aUHi~J*XN(iJ?eE zsL5C2rFI>)V>~Dt(-p%X1BHP^KwV_ zF=!tXwWBdeACrl(iq1*hOyi)ome*?FoNW@jqcg}JQ;DHTU8AO#->T>QWk+R@JSG+c zi<&`AFOSQx{^K9N^~&|a&N(}JgWNF<7^fJP)Dvn|s#a&r@%$zA!)*5%Lxi(SrntUx zris@7qfjG%>bL3FK)KsQ>o?|c!IGzsw+R^sM6>^&!vCzh!Yt2QVm-`uo>4+D+i3dL zLvA*~dZqq1!F12uS<}(Jk;T1ESRVVD&Uw=jVBX0VqiMz#1xnr37NRLjM}q#>w`U>Q z&MH4E=B6mvTP=(hnsV3+y(9Bq;h0MMbACB2iC<;MuUTG18_Kok*T>GFq^Xpurj(-^a7OE*mBY+=Rb=2w#upDMF{q2hmq;j+mZQu$*>bMYnGIGkJbY6~s0$xEd|JkNrx1~hqI%imwzI@l~)U@2r;82Oa zjE*MdN8VT8@krrgwXchQT&Xg}PL@$J2NM=*sx;BVsO3OU3Z-i`{KP>OW;HZITR8$z z_L~_=A%w2GWF;_~p6mbzoc+r5dF8;lT$Asvr<^C6Cs>3pUvveP1yux5pS1>9sK1#J`ET(HB`!VJ+z!Fouix^=G!NA@E@s0YW+9_M(Cb2jHqzTkIu~$4pL0XevXN)-pfW5{>s@Y|r&+GqdTV|{ej-%@$LX}IrO-LBwYJRm-1fxw^p!!@%k72rIsG{Wo5=JT zyqnHcm?@8n&+RGgq3zl2@i9s*KGa&Z=a?J&7B+Z^>tgoB4n+=mHKjF$%}R?m7K>L5 znyQ-DOKEc$AKy@!cW$XT=!@vf=?|D<-7sJ&9o{Zk*q}8fuLxxivrg_WaL+Bz`JB+5 z$T6zHR^N)K=CPJF8CdZ&M(CV}>y-_`88bJl8%!x?FpOKvimGBy!u4P)2P3Z25 z^d7a%&o^*^vVvBmE`szO&49B*Zh=$*Yi;O}HGui`@M$vS*?Y7y&yTSU^5m4AKImD= zTg|Z|eG&cr)uGh+RE@D5`$YQJ)u#f-c-1mJMr)9{by-{}_uEfHqWa!vW+!Bf<@|0W zlV>~R;@|5h3{>ux&&1sK_6Z&_R#dq=mtoX+H>&98BW&cGZax(R%6t^5_vEhEq^Wm< z-NsQwdEV26xqT$V0arE6eR2^OQ^Q~5`s8YB(Cp|-I~k^iaG$+-P5%xlYG zHh)TW=L>?j1=t0=Qos)?Lj!%M7_|MwEw#f3qc693&ze_ok2o&@eceR8NL#*6;4k07 zHg}ddmjvJugKK*=m)^-AL5Br~?=81fuV5azj3aK9`{WKquK->|oss@f+hAMzSBTA< z5f7m)J(*kakK7Zd*ZNtDTbjFvJhcNY9tMz%`G#?m&ITYaJ-1wM`1kyHf|K5muWZjB z=ftlYvMF~gxf6#c-3ViIxA|ghiF#iNA(4VR+q)h+q4=N)qjZnX5-Oc85-Z&i0)=)Zrw()y}yXx9Cp+)N-ufaM1I798XDC$12 z30+D3z*-3x^`IQ1vv>7kyCMDATVeglFWez6+_^8@aqjhD830(Ju|45ipn9GH7cJZt z84c7Htqsf;5e>u^m97RqIV|<_(p)8gi`uqr6Syry`UK_9nr-tJKct%QbnWZsapuG4 z$0|wZUn*}SIAXN78C=sPKex%Q4_8p-YYweCf!C=Q|!a(p@(7>;{dZD4Cc-D2IWzj(w3xqj}iFq6d33q7g0IFO} zH@^}{U(y+`Bzqy z71teP{KbpB8~${ao0M_aXlOeQvO8`it_vr)r1wCpTPICBQ9x6$AF zt+UbN94@5%MFpvdP{w|Wj^*WoGHF1z@A>24)6wgAza z1R<(0vbhQKh4I*EX1hqpN^z%KERe~n*GPXV7i-|S7o4(}=v6Hpc|`VTrVEIDIq*`L zd$I#Y?R~w3)@7R6iXsltt3|nRd7nT)csdz-o^6dToA*v!br~Itr$#xx0D(=;*LBdDj-Ny7pJwE@j-RLvy`X z$J1@BO-kYWkGtn{cRY^AZ_k(u7V(6K5Y2X@C%SrCx@hN}ozFF~%}Ax_hpB22w5~1{ zGFRnA-)KtTi0rhv+SAb1ab8Qm!LClfhn=>(Ka2l*e+w-YPNBV4{&m=0@%~iseo1ui z`8_D`ZPHYb`R7@r_jA%-Kw_TZW= zGbdCo6gR-fmEuzvOOZf`g3!4x8K7@Zu z_zGkR;R5O**teI#38@ut4Z*vh^XfNVPT>D6tOhkgV5$N{u=mtKVlRO7;~Hs!!P^EI z|Nja9Ui=L2!SUuk48b+rHE3L`TE>)&qjD7iSAxtp512&kGGJE%HZxB-KzTh0=gZV!|+ zcQAJ`c5`(3*Q0;w0p+YsT#Q}*W%qA8|L>7{89V*=k$yb*h?MDHk$x~df5qhJqUPvm zCm?Ta>f-47CtA&qIDqs(IdM^XB^7acCMGs6Zh8$41}0ztP+VP382Irw0*cD3N~;1@ zoy<*v#tvpcF;yj?93SKVZuBFFzeVO^ANdntVPa;YXJ(;i;!tB|qT=56%DgKf?LnmizCv?_aWye)U&2{_c5y zxWD_Rxx+`J@%*bRevqziA9=C=yD|T#U;p>u?SJ)WMH3rUH~SB4cbAXt$;HH|0AyzV z8`hnTo#nrJwO7`-=BmRQ2l8vk8`vhCW~VA>90WdZCVKQL8^=nc1mT|kipJI%ByF4g zTeoFI5gD)ToUq{y6L05FoQZhS8dMeR{GzIGs9OW@{4|#WObKuDR8$Ghq`E$>b8wG1 z*CwT#f%Uow8Y zyGL)UxQtNCdRC(-U*kff1fDfIT0CDXz%#?!U-}f6npq`M+`V025JFRMfM6YgQ*~zb zEcyrGLL0P<2&1LJ)ms72WyGr1m4L5hiIfwuelZBEgZNAA$=St?s2&1&i3<(uC-|o@ zZ@#fny$FWEoL#M*Wivkp4E<8K28L_}2J-4m@n19nPnI3J51V!$D01HKfC$-qa69(O zc8gEO{N#DYF5&vKte!IBf-VcD_i35K9!Fmky0qv5qB4Ko-}EE3ULG0>44%mQ61<#v z`L^JMl^eL9zJbz<#k9-`XK0&TewScq$qfF)HMQsGiRJw({hqX0?N`+~sqF9j-$zf& zu|$chs~0Yd>XV$6=k2R{nt^Vah4P#6x8^OUk-M25k=^QD4!2soP@}(`W(}(h2}Q%G#E zkLO>6USryBlD4ECv7)9c^QfEj+3vzrfY=TNY%mQiWaw5EzAVHK1n4wyt@a>(`|^0C z2=@Kh&&@TqA%l|)ju3s)c~y97cZQ2idgC~WTL7#X1+qO(+7&L7I$Au5gZt2^?(Y7jR(Yfssburw~ww5tu5dD>MA7473PzRih!$ z5y)|G77%F`CM}gZcf^EA9=g*#b};^=S%kf#I36sR?=YS!r))M&H$&I2c

  • x#e1h{baLP@AcAEbh($8fkN8HUQ;0!C|bj-I? zC3xCvDY2pY6K-#iix|4&WDlAW_cl$v;i`yLk&4OBOGEeDv-(0OzCASLaHO54{V;o^ zthF@f|61vhBCD5N6O1S4sl6{^dh7Az=!_-oQ(|;y&b??e*(!a1$Pwp99_Le^g-+9c zym8ag)duUk+MoVelHG9NjqTzWQ$M|47x4Z)*Ov9@~|3kA2U z#Yg|$S0(-X?cF@lYKD*R;^rQGxTval)0%USpDWI7o2#mH-fLQihgCr%yNTJt{o>!O zH!S?gmvbQe%|$WWr#;K>%$K*hHf{UcQvbixS>{dbWEU%c>~K-udu@TVtd6bpqvQ8K zZe3R=*AOk6yDoq6gsX+WU#7lUm(Qj(`PGW}iN_g2N(_4WKb%VX;LWuE^q~sbkoC#l z_ZhaZGW_57tc_oHnN_a+^3G4C!E?)M`8VF=y1DaB-r{3lZrk|BFSg~o9RBk_#uocs z7k6A+S0VFCy;A4yndGILjx)Uf9I?`%GH2~9n`;J7_8s3+bpGI%uIVQ)#siCyJmKHf zLg`n#-~QZYbu$0YtGn~-Ie$)G(sfwhZFBj*{mRcTV!PkN$O3VbM{s6Us)CUvwi`Xb zl|n>NYMQ=hUP@|3v;k0EtbTa3p@NZuVJxg>ur${X%FizWiWw*b0ad2uD;PqUF3~p0 zMyAQ8rpbn;X~}6xiK(du1}TXarY5Gz2IgsLsmVrmHl~*5i6+U(KygchB(o#~qtrA5 z!?e^?qZC5}6Z14vyIACEN3>@zuLFaG%l)6rCrwbuYGu_?+_qtktjeNIje;g#+&}g` zdU`Lmkb%*5(U&Px7CtQF@43)nvM1wSO}D9h#@ai=%2%xx)qa}isGE^8FFXFt&aL+( re}uiLx$yNPvx6y58kUYuaS5JcjE;B$L(NY literal 0 HcmV?d00001 diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/LPC17xx.h b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/LPC17xx.h new file mode 100644 index 0000000..377fdf2 --- /dev/null +++ b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/LPC17xx.h @@ -0,0 +1,1035 @@ +/**************************************************************************//** + * @file LPC17xx.h + * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File for + * NXP LPC17xx Device Series + * @version: V1.09 + * @date: 17. March 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. + * + ******************************************************************************/ + + +#ifndef __LPC17xx_H__ +#define __LPC17xx_H__ + +/* + * ========================================================================== + * ---------- Interrupt Number Definition ----------------------------------- + * ========================================================================== + */ + +typedef enum IRQn +{ +/****** Cortex-M3 Processor Exceptions Numbers ***************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */ + BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */ + UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */ + SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */ + DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */ + +/****** LPC17xx Specific Interrupt Numbers *******************************************************/ + WDT_IRQn = 0, /*!< Watchdog Timer Interrupt */ + TIMER0_IRQn = 1, /*!< Timer0 Interrupt */ + TIMER1_IRQn = 2, /*!< Timer1 Interrupt */ + TIMER2_IRQn = 3, /*!< Timer2 Interrupt */ + TIMER3_IRQn = 4, /*!< Timer3 Interrupt */ + UART0_IRQn = 5, /*!< UART0 Interrupt */ + UART1_IRQn = 6, /*!< UART1 Interrupt */ + UART2_IRQn = 7, /*!< UART2 Interrupt */ + UART3_IRQn = 8, /*!< UART3 Interrupt */ + PWM1_IRQn = 9, /*!< PWM1 Interrupt */ + I2C0_IRQn = 10, /*!< I2C0 Interrupt */ + I2C1_IRQn = 11, /*!< I2C1 Interrupt */ + I2C2_IRQn = 12, /*!< I2C2 Interrupt */ + SPI_IRQn = 13, /*!< SPI Interrupt */ + SSP0_IRQn = 14, /*!< SSP0 Interrupt */ + SSP1_IRQn = 15, /*!< SSP1 Interrupt */ + PLL0_IRQn = 16, /*!< PLL0 Lock (Main PLL) Interrupt */ + RTC_IRQn = 17, /*!< Real Time Clock Interrupt */ + EINT0_IRQn = 18, /*!< External Interrupt 0 Interrupt */ + EINT1_IRQn = 19, /*!< External Interrupt 1 Interrupt */ + EINT2_IRQn = 20, /*!< External Interrupt 2 Interrupt */ + EINT3_IRQn = 21, /*!< External Interrupt 3 Interrupt */ + ADC_IRQn = 22, /*!< A/D Converter Interrupt */ + BOD_IRQn = 23, /*!< Brown-Out Detect Interrupt */ + USB_IRQn = 24, /*!< USB Interrupt */ + CAN_IRQn = 25, /*!< CAN Interrupt */ + DMA_IRQn = 26, /*!< General Purpose DMA Interrupt */ + I2S_IRQn = 27, /*!< I2S Interrupt */ + ENET_IRQn = 28, /*!< Ethernet Interrupt */ + RIT_IRQn = 29, /*!< Repetitive Interrupt Timer Interrupt */ + MCPWM_IRQn = 30, /*!< Motor Control PWM Interrupt */ + QEI_IRQn = 31, /*!< Quadrature Encoder Interface Interrupt */ + PLL1_IRQn = 32, /*!< PLL1 Lock (USB PLL) Interrupt */ + USBActivity_IRQn = 33, /* USB Activity interrupt */ + CANActivity_IRQn = 34, /* CAN Activity interrupt */ +} IRQn_Type; + + +/* + * ========================================================================== + * ----------- Processor and Core Peripheral Section ------------------------ + * ========================================================================== + */ + +/* Configuration of the Cortex-M3 Processor and Core Peripherals */ +#define __MPU_PRESENT 1 /*!< MPU present or not */ +#define __NVIC_PRIO_BITS 5 /*!< Number of Bits used for Priority Levels */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + + +#include "core_cm3.h" /* Cortex-M3 processor and core peripherals */ +#include "system_LPC17xx.h" /* System Header */ + + +/******************************************************************************/ +/* Device Specific Peripheral registers structures */ +/******************************************************************************/ + +#if defined ( __CC_ARM ) +#pragma anon_unions +#endif + +/*------------- System Control (SC) ------------------------------------------*/ +typedef struct +{ + __IO uint32_t FLASHCFG; /* Flash Accelerator Module */ + uint32_t RESERVED0[31]; + __IO uint32_t PLL0CON; /* Clocking and Power Control */ + __IO uint32_t PLL0CFG; + __I uint32_t PLL0STAT; + __O uint32_t PLL0FEED; + uint32_t RESERVED1[4]; + __IO uint32_t PLL1CON; + __IO uint32_t PLL1CFG; + __I uint32_t PLL1STAT; + __O uint32_t PLL1FEED; + uint32_t RESERVED2[4]; + __IO uint32_t PCON; + __IO uint32_t PCONP; + uint32_t RESERVED3[15]; + __IO uint32_t CCLKCFG; + __IO uint32_t USBCLKCFG; + __IO uint32_t CLKSRCSEL; + __IO uint32_t CANSLEEPCLR; + __IO uint32_t CANWAKEFLAGS; + uint32_t RESERVED4[10]; + __IO uint32_t EXTINT; /* External Interrupts */ + uint32_t RESERVED5; + __IO uint32_t EXTMODE; + __IO uint32_t EXTPOLAR; + uint32_t RESERVED6[12]; + __IO uint32_t RSID; /* Reset */ + uint32_t RESERVED7[7]; + __IO uint32_t SCS; /* Syscon Miscellaneous Registers */ + __IO uint32_t IRCTRIM; /* Clock Dividers */ + __IO uint32_t PCLKSEL0; + __IO uint32_t PCLKSEL1; + uint32_t RESERVED8[4]; + __IO uint32_t USBIntSt; /* USB Device/OTG Interrupt Register */ + __IO uint32_t DMAREQSEL; + __IO uint32_t CLKOUTCFG; /* Clock Output Configuration */ + } LPC_SC_TypeDef; + +/*------------- Pin Connect Block (PINCON) -----------------------------------*/ +typedef struct +{ + __IO uint32_t PINSEL0; + __IO uint32_t PINSEL1; + __IO uint32_t PINSEL2; + __IO uint32_t PINSEL3; + __IO uint32_t PINSEL4; + __IO uint32_t PINSEL5; + __IO uint32_t PINSEL6; + __IO uint32_t PINSEL7; + __IO uint32_t PINSEL8; + __IO uint32_t PINSEL9; + __IO uint32_t PINSEL10; + uint32_t RESERVED0[5]; + __IO uint32_t PINMODE0; + __IO uint32_t PINMODE1; + __IO uint32_t PINMODE2; + __IO uint32_t PINMODE3; + __IO uint32_t PINMODE4; + __IO uint32_t PINMODE5; + __IO uint32_t PINMODE6; + __IO uint32_t PINMODE7; + __IO uint32_t PINMODE8; + __IO uint32_t PINMODE9; + __IO uint32_t PINMODE_OD0; + __IO uint32_t PINMODE_OD1; + __IO uint32_t PINMODE_OD2; + __IO uint32_t PINMODE_OD3; + __IO uint32_t PINMODE_OD4; + __IO uint32_t I2CPADCFG; +} LPC_PINCON_TypeDef; + +/*------------- General Purpose Input/Output (GPIO) --------------------------*/ +typedef struct +{ + union { + __IO uint32_t FIODIR; + struct { + __IO uint16_t FIODIRL; + __IO uint16_t FIODIRH; + }; + struct { + __IO uint8_t FIODIR0; + __IO uint8_t FIODIR1; + __IO uint8_t FIODIR2; + __IO uint8_t FIODIR3; + }; + }; + uint32_t RESERVED0[3]; + union { + __IO uint32_t FIOMASK; + struct { + __IO uint16_t FIOMASKL; + __IO uint16_t FIOMASKH; + }; + struct { + __IO uint8_t FIOMASK0; + __IO uint8_t FIOMASK1; + __IO uint8_t FIOMASK2; + __IO uint8_t FIOMASK3; + }; + }; + union { + __IO uint32_t FIOPIN; + struct { + __IO uint16_t FIOPINL; + __IO uint16_t FIOPINH; + }; + struct { + __IO uint8_t FIOPIN0; + __IO uint8_t FIOPIN1; + __IO uint8_t FIOPIN2; + __IO uint8_t FIOPIN3; + }; + }; + union { + __IO uint32_t FIOSET; + struct { + __IO uint16_t FIOSETL; + __IO uint16_t FIOSETH; + }; + struct { + __IO uint8_t FIOSET0; + __IO uint8_t FIOSET1; + __IO uint8_t FIOSET2; + __IO uint8_t FIOSET3; + }; + }; + union { + __O uint32_t FIOCLR; + struct { + __O uint16_t FIOCLRL; + __O uint16_t FIOCLRH; + }; + struct { + __O uint8_t FIOCLR0; + __O uint8_t FIOCLR1; + __O uint8_t FIOCLR2; + __O uint8_t FIOCLR3; + }; + }; +} LPC_GPIO_TypeDef; + +typedef struct +{ + __I uint32_t IntStatus; + __I uint32_t IO0IntStatR; + __I uint32_t IO0IntStatF; + __O uint32_t IO0IntClr; + __IO uint32_t IO0IntEnR; + __IO uint32_t IO0IntEnF; + uint32_t RESERVED0[3]; + __I uint32_t IO2IntStatR; + __I uint32_t IO2IntStatF; + __O uint32_t IO2IntClr; + __IO uint32_t IO2IntEnR; + __IO uint32_t IO2IntEnF; +} LPC_GPIOINT_TypeDef; + +/*------------- Timer (TIM) --------------------------------------------------*/ +typedef struct +{ + __IO uint32_t IR; + __IO uint32_t TCR; + __IO uint32_t TC; + __IO uint32_t PR; + __IO uint32_t PC; + __IO uint32_t MCR; + __IO uint32_t MR0; + __IO uint32_t MR1; + __IO uint32_t MR2; + __IO uint32_t MR3; + __IO uint32_t CCR; + __I uint32_t CR0; + __I uint32_t CR1; + uint32_t RESERVED0[2]; + __IO uint32_t EMR; + uint32_t RESERVED1[12]; + __IO uint32_t CTCR; +} LPC_TIM_TypeDef; + +/*------------- Pulse-Width Modulation (PWM) ---------------------------------*/ +typedef struct +{ + __IO uint32_t IR; + __IO uint32_t TCR; + __IO uint32_t TC; + __IO uint32_t PR; + __IO uint32_t PC; + __IO uint32_t MCR; + __IO uint32_t MR0; + __IO uint32_t MR1; + __IO uint32_t MR2; + __IO uint32_t MR3; + __IO uint32_t CCR; + __I uint32_t CR0; + __I uint32_t CR1; + __I uint32_t CR2; + __I uint32_t CR3; + uint32_t RESERVED0; + __IO uint32_t MR4; + __IO uint32_t MR5; + __IO uint32_t MR6; + __IO uint32_t PCR; + __IO uint32_t LER; + uint32_t RESERVED1[7]; + __IO uint32_t CTCR; +} LPC_PWM_TypeDef; + +/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/ +typedef struct +{ + union { + __I uint8_t RBR; + __O uint8_t THR; + __IO uint8_t DLL; + uint32_t RESERVED0; + }; + union { + __IO uint8_t DLM; + __IO uint32_t IER; + }; + union { + __I uint32_t IIR; + __O uint8_t FCR; + }; + __IO uint8_t LCR; + uint8_t RESERVED1[7]; + __I uint8_t LSR; + uint8_t RESERVED2[7]; + __IO uint8_t SCR; + uint8_t RESERVED3[3]; + __IO uint32_t ACR; + __IO uint8_t ICR; + uint8_t RESERVED4[3]; + __IO uint8_t FDR; + uint8_t RESERVED5[7]; + __IO uint8_t TER; + uint8_t RESERVED6[39]; + __IO uint32_t FIFOLVL; +} LPC_UART_TypeDef; + +typedef struct +{ + union { + __I uint8_t RBR; + __O uint8_t THR; + __IO uint8_t DLL; + uint32_t RESERVED0; + }; + union { + __IO uint8_t DLM; + __IO uint32_t IER; + }; + union { + __I uint32_t IIR; + __O uint8_t FCR; + }; + __IO uint8_t LCR; + uint8_t RESERVED1[7]; + __I uint8_t LSR; + uint8_t RESERVED2[7]; + __IO uint8_t SCR; + uint8_t RESERVED3[3]; + __IO uint32_t ACR; + __IO uint8_t ICR; + uint8_t RESERVED4[3]; + __IO uint8_t FDR; + uint8_t RESERVED5[7]; + __IO uint8_t TER; + uint8_t RESERVED6[39]; + __IO uint32_t FIFOLVL; +} LPC_UART0_TypeDef; + +typedef struct +{ + union { + __I uint8_t RBR; + __O uint8_t THR; + __IO uint8_t DLL; + uint32_t RESERVED0; + }; + union { + __IO uint8_t DLM; + __IO uint32_t IER; + }; + union { + __I uint32_t IIR; + __O uint8_t FCR; + }; + __IO uint8_t LCR; + uint8_t RESERVED1[3]; + __IO uint8_t MCR; + uint8_t RESERVED2[3]; + __I uint8_t LSR; + uint8_t RESERVED3[3]; + __I uint8_t MSR; + uint8_t RESERVED4[3]; + __IO uint8_t SCR; + uint8_t RESERVED5[3]; + __IO uint32_t ACR; + uint32_t RESERVED6; + __IO uint32_t FDR; + uint32_t RESERVED7; + __IO uint8_t TER; + uint8_t RESERVED8[27]; + __IO uint8_t RS485CTRL; + uint8_t RESERVED9[3]; + __IO uint8_t ADRMATCH; + uint8_t RESERVED10[3]; + __IO uint8_t RS485DLY; + uint8_t RESERVED11[3]; + __IO uint32_t FIFOLVL; +} LPC_UART1_TypeDef; + +/*------------- Serial Peripheral Interface (SPI) ----------------------------*/ +typedef struct +{ + __IO uint32_t SPCR; + __I uint32_t SPSR; + __IO uint32_t SPDR; + __IO uint32_t SPCCR; + uint32_t RESERVED0[3]; + __IO uint32_t SPINT; +} LPC_SPI_TypeDef; + +/*------------- Synchronous Serial Communication (SSP) -----------------------*/ +typedef struct +{ + __IO uint32_t CR0; + __IO uint32_t CR1; + __IO uint32_t DR; + __I uint32_t SR; + __IO uint32_t CPSR; + __IO uint32_t IMSC; + __IO uint32_t RIS; + __IO uint32_t MIS; + __IO uint32_t ICR; + __IO uint32_t DMACR; +} LPC_SSP_TypeDef; + +/*------------- Inter-Integrated Circuit (I2C) -------------------------------*/ +typedef struct +{ + __IO uint32_t I2CONSET; + __I uint32_t I2STAT; + __IO uint32_t I2DAT; + __IO uint32_t I2ADR0; + __IO uint32_t I2SCLH; + __IO uint32_t I2SCLL; + __O uint32_t I2CONCLR; + __IO uint32_t MMCTRL; + __IO uint32_t I2ADR1; + __IO uint32_t I2ADR2; + __IO uint32_t I2ADR3; + __I uint32_t I2DATA_BUFFER; + __IO uint32_t I2MASK0; + __IO uint32_t I2MASK1; + __IO uint32_t I2MASK2; + __IO uint32_t I2MASK3; +} LPC_I2C_TypeDef; + +/*------------- Inter IC Sound (I2S) -----------------------------------------*/ +typedef struct +{ + __IO uint32_t I2SDAO; + __IO uint32_t I2SDAI; + __O uint32_t I2STXFIFO; + __I uint32_t I2SRXFIFO; + __I uint32_t I2SSTATE; + __IO uint32_t I2SDMA1; + __IO uint32_t I2SDMA2; + __IO uint32_t I2SIRQ; + __IO uint32_t I2STXRATE; + __IO uint32_t I2SRXRATE; + __IO uint32_t I2STXBITRATE; + __IO uint32_t I2SRXBITRATE; + __IO uint32_t I2STXMODE; + __IO uint32_t I2SRXMODE; +} LPC_I2S_TypeDef; + +/*------------- Repetitive Interrupt Timer (RIT) -----------------------------*/ +typedef struct +{ + __IO uint32_t RICOMPVAL; + __IO uint32_t RIMASK; + __IO uint8_t RICTRL; + uint8_t RESERVED0[3]; + __IO uint32_t RICOUNTER; +} LPC_RIT_TypeDef; + +/*------------- Real-Time Clock (RTC) ----------------------------------------*/ +typedef struct +{ + __IO uint8_t ILR; + uint8_t RESERVED0[7]; + __IO uint8_t CCR; + uint8_t RESERVED1[3]; + __IO uint8_t CIIR; + uint8_t RESERVED2[3]; + __IO uint8_t AMR; + uint8_t RESERVED3[3]; + __I uint32_t CTIME0; + __I uint32_t CTIME1; + __I uint32_t CTIME2; + __IO uint8_t SEC; + uint8_t RESERVED4[3]; + __IO uint8_t MIN; + uint8_t RESERVED5[3]; + __IO uint8_t HOUR; + uint8_t RESERVED6[3]; + __IO uint8_t DOM; + uint8_t RESERVED7[3]; + __IO uint8_t DOW; + uint8_t RESERVED8[3]; + __IO uint16_t DOY; + uint16_t RESERVED9; + __IO uint8_t MONTH; + uint8_t RESERVED10[3]; + __IO uint16_t YEAR; + uint16_t RESERVED11; + __IO uint32_t CALIBRATION; + __IO uint32_t GPREG0; + __IO uint32_t GPREG1; + __IO uint32_t GPREG2; + __IO uint32_t GPREG3; + __IO uint32_t GPREG4; + __IO uint8_t RTC_AUXEN; + uint8_t RESERVED12[3]; + __IO uint8_t RTC_AUX; + uint8_t RESERVED13[3]; + __IO uint8_t ALSEC; + uint8_t RESERVED14[3]; + __IO uint8_t ALMIN; + uint8_t RESERVED15[3]; + __IO uint8_t ALHOUR; + uint8_t RESERVED16[3]; + __IO uint8_t ALDOM; + uint8_t RESERVED17[3]; + __IO uint8_t ALDOW; + uint8_t RESERVED18[3]; + __IO uint16_t ALDOY; + uint16_t RESERVED19; + __IO uint8_t ALMON; + uint8_t RESERVED20[3]; + __IO uint16_t ALYEAR; + uint16_t RESERVED21; +} LPC_RTC_TypeDef; + +/*------------- Watchdog Timer (WDT) -----------------------------------------*/ +typedef struct +{ + __IO uint8_t WDMOD; + uint8_t RESERVED0[3]; + __IO uint32_t WDTC; + __O uint8_t WDFEED; + uint8_t RESERVED1[3]; + __I uint32_t WDTV; + __IO uint32_t WDCLKSEL; +} LPC_WDT_TypeDef; + +/*------------- Analog-to-Digital Converter (ADC) ----------------------------*/ +typedef struct +{ + __IO uint32_t ADCR; + __IO uint32_t ADGDR; + uint32_t RESERVED0; + __IO uint32_t ADINTEN; + __I uint32_t ADDR0; + __I uint32_t ADDR1; + __I uint32_t ADDR2; + __I uint32_t ADDR3; + __I uint32_t ADDR4; + __I uint32_t ADDR5; + __I uint32_t ADDR6; + __I uint32_t ADDR7; + __I uint32_t ADSTAT; + __IO uint32_t ADTRM; +} LPC_ADC_TypeDef; + +/*------------- Digital-to-Analog Converter (DAC) ----------------------------*/ +typedef struct +{ + __IO uint32_t DACR; + __IO uint32_t DACCTRL; + __IO uint16_t DACCNTVAL; +} LPC_DAC_TypeDef; + +/*------------- Motor Control Pulse-Width Modulation (MCPWM) -----------------*/ +typedef struct +{ + __I uint32_t MCCON; + __O uint32_t MCCON_SET; + __O uint32_t MCCON_CLR; + __I uint32_t MCCAPCON; + __O uint32_t MCCAPCON_SET; + __O uint32_t MCCAPCON_CLR; + __IO uint32_t MCTIM0; + __IO uint32_t MCTIM1; + __IO uint32_t MCTIM2; + __IO uint32_t MCPER0; + __IO uint32_t MCPER1; + __IO uint32_t MCPER2; + __IO uint32_t MCPW0; + __IO uint32_t MCPW1; + __IO uint32_t MCPW2; + __IO uint32_t MCDEADTIME; + __IO uint32_t MCCCP; + __IO uint32_t MCCR0; + __IO uint32_t MCCR1; + __IO uint32_t MCCR2; + __I uint32_t MCINTEN; + __O uint32_t MCINTEN_SET; + __O uint32_t MCINTEN_CLR; + __I uint32_t MCCNTCON; + __O uint32_t MCCNTCON_SET; + __O uint32_t MCCNTCON_CLR; + __I uint32_t MCINTFLAG; + __O uint32_t MCINTFLAG_SET; + __O uint32_t MCINTFLAG_CLR; + __O uint32_t MCCAP_CLR; +} LPC_MCPWM_TypeDef; + +/*------------- Quadrature Encoder Interface (QEI) ---------------------------*/ +typedef struct +{ + __O uint32_t QEICON; + __I uint32_t QEISTAT; + __IO uint32_t QEICONF; + __I uint32_t QEIPOS; + __IO uint32_t QEIMAXPOS; + __IO uint32_t CMPOS0; + __IO uint32_t CMPOS1; + __IO uint32_t CMPOS2; + __I uint32_t INXCNT; + __IO uint32_t INXCMP; + __IO uint32_t QEILOAD; + __I uint32_t QEITIME; + __I uint32_t QEIVEL; + __I uint32_t QEICAP; + __IO uint32_t VELCOMP; + __IO uint32_t FILTER; + uint32_t RESERVED0[998]; + __O uint32_t QEIIEC; + __O uint32_t QEIIES; + __I uint32_t QEIINTSTAT; + __I uint32_t QEIIE; + __O uint32_t QEICLR; + __O uint32_t QEISET; +} LPC_QEI_TypeDef; + +/*------------- Controller Area Network (CAN) --------------------------------*/ +typedef struct +{ + __IO uint32_t mask[512]; /* ID Masks */ +} LPC_CANAF_RAM_TypeDef; + +typedef struct /* Acceptance Filter Registers */ +{ + __IO uint32_t AFMR; + __IO uint32_t SFF_sa; + __IO uint32_t SFF_GRP_sa; + __IO uint32_t EFF_sa; + __IO uint32_t EFF_GRP_sa; + __IO uint32_t ENDofTable; + __I uint32_t LUTerrAd; + __I uint32_t LUTerr; + __IO uint32_t FCANIE; + __IO uint32_t FCANIC0; + __IO uint32_t FCANIC1; +} LPC_CANAF_TypeDef; + +typedef struct /* Central Registers */ +{ + __I uint32_t CANTxSR; + __I uint32_t CANRxSR; + __I uint32_t CANMSR; +} LPC_CANCR_TypeDef; + +typedef struct /* Controller Registers */ +{ + __IO uint32_t MOD; + __O uint32_t CMR; + __IO uint32_t GSR; + __I uint32_t ICR; + __IO uint32_t IER; + __IO uint32_t BTR; + __IO uint32_t EWL; + __I uint32_t SR; + __IO uint32_t RFS; + __IO uint32_t RID; + __IO uint32_t RDA; + __IO uint32_t RDB; + __IO uint32_t TFI1; + __IO uint32_t TID1; + __IO uint32_t TDA1; + __IO uint32_t TDB1; + __IO uint32_t TFI2; + __IO uint32_t TID2; + __IO uint32_t TDA2; + __IO uint32_t TDB2; + __IO uint32_t TFI3; + __IO uint32_t TID3; + __IO uint32_t TDA3; + __IO uint32_t TDB3; +} LPC_CAN_TypeDef; + +/*------------- General Purpose Direct Memory Access (GPDMA) -----------------*/ +typedef struct /* Common Registers */ +{ + __I uint32_t DMACIntStat; + __I uint32_t DMACIntTCStat; + __O uint32_t DMACIntTCClear; + __I uint32_t DMACIntErrStat; + __O uint32_t DMACIntErrClr; + __I uint32_t DMACRawIntTCStat; + __I uint32_t DMACRawIntErrStat; + __I uint32_t DMACEnbldChns; + __IO uint32_t DMACSoftBReq; + __IO uint32_t DMACSoftSReq; + __IO uint32_t DMACSoftLBReq; + __IO uint32_t DMACSoftLSReq; + __IO uint32_t DMACConfig; + __IO uint32_t DMACSync; +} LPC_GPDMA_TypeDef; + +typedef struct /* Channel Registers */ +{ + __IO uint32_t DMACCSrcAddr; + __IO uint32_t DMACCDestAddr; + __IO uint32_t DMACCLLI; + __IO uint32_t DMACCControl; + __IO uint32_t DMACCConfig; +} LPC_GPDMACH_TypeDef; + +/*------------- Universal Serial Bus (USB) -----------------------------------*/ +typedef struct +{ + __I uint32_t HcRevision; /* USB Host Registers */ + __IO uint32_t HcControl; + __IO uint32_t HcCommandStatus; + __IO uint32_t HcInterruptStatus; + __IO uint32_t HcInterruptEnable; + __IO uint32_t HcInterruptDisable; + __IO uint32_t HcHCCA; + __I uint32_t HcPeriodCurrentED; + __IO uint32_t HcControlHeadED; + __IO uint32_t HcControlCurrentED; + __IO uint32_t HcBulkHeadED; + __IO uint32_t HcBulkCurrentED; + __I uint32_t HcDoneHead; + __IO uint32_t HcFmInterval; + __I uint32_t HcFmRemaining; + __I uint32_t HcFmNumber; + __IO uint32_t HcPeriodicStart; + __IO uint32_t HcLSTreshold; + __IO uint32_t HcRhDescriptorA; + __IO uint32_t HcRhDescriptorB; + __IO uint32_t HcRhStatus; + __IO uint32_t HcRhPortStatus1; + __IO uint32_t HcRhPortStatus2; + uint32_t RESERVED0[40]; + __I uint32_t Module_ID; + + __I uint32_t OTGIntSt; /* USB On-The-Go Registers */ + __IO uint32_t OTGIntEn; + __O uint32_t OTGIntSet; + __O uint32_t OTGIntClr; + __IO uint32_t OTGStCtrl; + __IO uint32_t OTGTmr; + uint32_t RESERVED1[58]; + + __I uint32_t USBDevIntSt; /* USB Device Interrupt Registers */ + __IO uint32_t USBDevIntEn; + __O uint32_t USBDevIntClr; + __O uint32_t USBDevIntSet; + + __O uint32_t USBCmdCode; /* USB Device SIE Command Registers */ + __I uint32_t USBCmdData; + + __I uint32_t USBRxData; /* USB Device Transfer Registers */ + __O uint32_t USBTxData; + __I uint32_t USBRxPLen; + __O uint32_t USBTxPLen; + __IO uint32_t USBCtrl; + __O uint32_t USBDevIntPri; + + __I uint32_t USBEpIntSt; /* USB Device Endpoint Interrupt Regs */ + __IO uint32_t USBEpIntEn; + __O uint32_t USBEpIntClr; + __O uint32_t USBEpIntSet; + __O uint32_t USBEpIntPri; + + __IO uint32_t USBReEp; /* USB Device Endpoint Realization Reg*/ + __O uint32_t USBEpInd; + __IO uint32_t USBMaxPSize; + + __I uint32_t USBDMARSt; /* USB Device DMA Registers */ + __O uint32_t USBDMARClr; + __O uint32_t USBDMARSet; + uint32_t RESERVED2[9]; + __IO uint32_t USBUDCAH; + __I uint32_t USBEpDMASt; + __O uint32_t USBEpDMAEn; + __O uint32_t USBEpDMADis; + __I uint32_t USBDMAIntSt; + __IO uint32_t USBDMAIntEn; + uint32_t RESERVED3[2]; + __I uint32_t USBEoTIntSt; + __O uint32_t USBEoTIntClr; + __O uint32_t USBEoTIntSet; + __I uint32_t USBNDDRIntSt; + __O uint32_t USBNDDRIntClr; + __O uint32_t USBNDDRIntSet; + __I uint32_t USBSysErrIntSt; + __O uint32_t USBSysErrIntClr; + __O uint32_t USBSysErrIntSet; + uint32_t RESERVED4[15]; + + union { + __I uint32_t I2C_RX; /* USB OTG I2C Registers */ + __O uint32_t I2C_TX; + }; + __I uint32_t I2C_STS; + __IO uint32_t I2C_CTL; + __IO uint32_t I2C_CLKHI; + __O uint32_t I2C_CLKLO; + uint32_t RESERVED5[824]; + + union { + __IO uint32_t USBClkCtrl; /* USB Clock Control Registers */ + __IO uint32_t OTGClkCtrl; + }; + union { + __I uint32_t USBClkSt; + __I uint32_t OTGClkSt; + }; +} LPC_USB_TypeDef; + +/*------------- Ethernet Media Access Controller (EMAC) ----------------------*/ +typedef struct +{ + __IO uint32_t MAC1; /* MAC Registers */ + __IO uint32_t MAC2; + __IO uint32_t IPGT; + __IO uint32_t IPGR; + __IO uint32_t CLRT; + __IO uint32_t MAXF; + __IO uint32_t SUPP; + __IO uint32_t TEST; + __IO uint32_t MCFG; + __IO uint32_t MCMD; + __IO uint32_t MADR; + __O uint32_t MWTD; + __I uint32_t MRDD; + __I uint32_t MIND; + uint32_t RESERVED0[2]; + __IO uint32_t SA0; + __IO uint32_t SA1; + __IO uint32_t SA2; + uint32_t RESERVED1[45]; + __IO uint32_t Command; /* Control Registers */ + __I uint32_t Status; + __IO uint32_t RxDescriptor; + __IO uint32_t RxStatus; + __IO uint32_t RxDescriptorNumber; + __I uint32_t RxProduceIndex; + __IO uint32_t RxConsumeIndex; + __IO uint32_t TxDescriptor; + __IO uint32_t TxStatus; + __IO uint32_t TxDescriptorNumber; + __IO uint32_t TxProduceIndex; + __I uint32_t TxConsumeIndex; + uint32_t RESERVED2[10]; + __I uint32_t TSV0; + __I uint32_t TSV1; + __I uint32_t RSV; + uint32_t RESERVED3[3]; + __IO uint32_t FlowControlCounter; + __I uint32_t FlowControlStatus; + uint32_t RESERVED4[34]; + __IO uint32_t RxFilterCtrl; /* Rx Filter Registers */ + __IO uint32_t RxFilterWoLStatus; + __IO uint32_t RxFilterWoLClear; + uint32_t RESERVED5; + __IO uint32_t HashFilterL; + __IO uint32_t HashFilterH; + uint32_t RESERVED6[882]; + __I uint32_t IntStatus; /* Module Control Registers */ + __IO uint32_t IntEnable; + __O uint32_t IntClear; + __O uint32_t IntSet; + uint32_t RESERVED7; + __IO uint32_t PowerDown; + uint32_t RESERVED8; + __IO uint32_t Module_ID; +} LPC_EMAC_TypeDef; + +#if defined ( __CC_ARM ) +#pragma no_anon_unions +#endif + + +/******************************************************************************/ +/* Peripheral memory map */ +/******************************************************************************/ +/* Base addresses */ +#define LPC_FLASH_BASE (0x00000000UL) +#define LPC_RAM_BASE (0x10000000UL) +#define LPC_GPIO_BASE (0x2009C000UL) +#define LPC_APB0_BASE (0x40000000UL) +#define LPC_APB1_BASE (0x40080000UL) +#define LPC_AHB_BASE (0x50000000UL) +#define LPC_CM3_BASE (0xE0000000UL) + +/* APB0 peripherals */ +#define LPC_WDT_BASE (LPC_APB0_BASE + 0x00000) +#define LPC_TIM0_BASE (LPC_APB0_BASE + 0x04000) +#define LPC_TIM1_BASE (LPC_APB0_BASE + 0x08000) +#define LPC_UART0_BASE (LPC_APB0_BASE + 0x0C000) +#define LPC_UART1_BASE (LPC_APB0_BASE + 0x10000) +#define LPC_PWM1_BASE (LPC_APB0_BASE + 0x18000) +#define LPC_I2C0_BASE (LPC_APB0_BASE + 0x1C000) +#define LPC_SPI_BASE (LPC_APB0_BASE + 0x20000) +#define LPC_RTC_BASE (LPC_APB0_BASE + 0x24000) +#define LPC_GPIOINT_BASE (LPC_APB0_BASE + 0x28080) +#define LPC_PINCON_BASE (LPC_APB0_BASE + 0x2C000) +#define LPC_SSP1_BASE (LPC_APB0_BASE + 0x30000) +#define LPC_ADC_BASE (LPC_APB0_BASE + 0x34000) +#define LPC_CANAF_RAM_BASE (LPC_APB0_BASE + 0x38000) +#define LPC_CANAF_BASE (LPC_APB0_BASE + 0x3C000) +#define LPC_CANCR_BASE (LPC_APB0_BASE + 0x40000) +#define LPC_CAN1_BASE (LPC_APB0_BASE + 0x44000) +#define LPC_CAN2_BASE (LPC_APB0_BASE + 0x48000) +#define LPC_I2C1_BASE (LPC_APB0_BASE + 0x5C000) + +/* APB1 peripherals */ +#define LPC_SSP0_BASE (LPC_APB1_BASE + 0x08000) +#define LPC_DAC_BASE (LPC_APB1_BASE + 0x0C000) +#define LPC_TIM2_BASE (LPC_APB1_BASE + 0x10000) +#define LPC_TIM3_BASE (LPC_APB1_BASE + 0x14000) +#define LPC_UART2_BASE (LPC_APB1_BASE + 0x18000) +#define LPC_UART3_BASE (LPC_APB1_BASE + 0x1C000) +#define LPC_I2C2_BASE (LPC_APB1_BASE + 0x20000) +#define LPC_I2S_BASE (LPC_APB1_BASE + 0x28000) +#define LPC_RIT_BASE (LPC_APB1_BASE + 0x30000) +#define LPC_MCPWM_BASE (LPC_APB1_BASE + 0x38000) +#define LPC_QEI_BASE (LPC_APB1_BASE + 0x3C000) +#define LPC_SC_BASE (LPC_APB1_BASE + 0x7C000) + +/* AHB peripherals */ +#define LPC_EMAC_BASE (LPC_AHB_BASE + 0x00000) +#define LPC_GPDMA_BASE (LPC_AHB_BASE + 0x04000) +#define LPC_GPDMACH0_BASE (LPC_AHB_BASE + 0x04100) +#define LPC_GPDMACH1_BASE (LPC_AHB_BASE + 0x04120) +#define LPC_GPDMACH2_BASE (LPC_AHB_BASE + 0x04140) +#define LPC_GPDMACH3_BASE (LPC_AHB_BASE + 0x04160) +#define LPC_GPDMACH4_BASE (LPC_AHB_BASE + 0x04180) +#define LPC_GPDMACH5_BASE (LPC_AHB_BASE + 0x041A0) +#define LPC_GPDMACH6_BASE (LPC_AHB_BASE + 0x041C0) +#define LPC_GPDMACH7_BASE (LPC_AHB_BASE + 0x041E0) +#define LPC_USB_BASE (LPC_AHB_BASE + 0x0C000) + +/* GPIOs */ +#define LPC_GPIO0_BASE (LPC_GPIO_BASE + 0x00000) +#define LPC_GPIO1_BASE (LPC_GPIO_BASE + 0x00020) +#define LPC_GPIO2_BASE (LPC_GPIO_BASE + 0x00040) +#define LPC_GPIO3_BASE (LPC_GPIO_BASE + 0x00060) +#define LPC_GPIO4_BASE (LPC_GPIO_BASE + 0x00080) + + +/******************************************************************************/ +/* Peripheral declaration */ +/******************************************************************************/ +#define LPC_SC ((LPC_SC_TypeDef *) LPC_SC_BASE ) +#define LPC_GPIO0 ((LPC_GPIO_TypeDef *) LPC_GPIO0_BASE ) +#define LPC_GPIO1 ((LPC_GPIO_TypeDef *) LPC_GPIO1_BASE ) +#define LPC_GPIO2 ((LPC_GPIO_TypeDef *) LPC_GPIO2_BASE ) +#define LPC_GPIO3 ((LPC_GPIO_TypeDef *) LPC_GPIO3_BASE ) +#define LPC_GPIO4 ((LPC_GPIO_TypeDef *) LPC_GPIO4_BASE ) +#define LPC_WDT ((LPC_WDT_TypeDef *) LPC_WDT_BASE ) +#define LPC_TIM0 ((LPC_TIM_TypeDef *) LPC_TIM0_BASE ) +#define LPC_TIM1 ((LPC_TIM_TypeDef *) LPC_TIM1_BASE ) +#define LPC_TIM2 ((LPC_TIM_TypeDef *) LPC_TIM2_BASE ) +#define LPC_TIM3 ((LPC_TIM_TypeDef *) LPC_TIM3_BASE ) +#define LPC_RIT ((LPC_RIT_TypeDef *) LPC_RIT_BASE ) +#define LPC_UART0 ((LPC_UART0_TypeDef *) LPC_UART0_BASE ) +#define LPC_UART1 ((LPC_UART1_TypeDef *) LPC_UART1_BASE ) +#define LPC_UART2 ((LPC_UART_TypeDef *) LPC_UART2_BASE ) +#define LPC_UART3 ((LPC_UART_TypeDef *) LPC_UART3_BASE ) +#define LPC_PWM1 ((LPC_PWM_TypeDef *) LPC_PWM1_BASE ) +#define LPC_I2C0 ((LPC_I2C_TypeDef *) LPC_I2C0_BASE ) +#define LPC_I2C1 ((LPC_I2C_TypeDef *) LPC_I2C1_BASE ) +#define LPC_I2C2 ((LPC_I2C_TypeDef *) LPC_I2C2_BASE ) +#define LPC_I2S ((LPC_I2S_TypeDef *) LPC_I2S_BASE ) +#define LPC_SPI ((LPC_SPI_TypeDef *) LPC_SPI_BASE ) +#define LPC_RTC ((LPC_RTC_TypeDef *) LPC_RTC_BASE ) +#define LPC_GPIOINT ((LPC_GPIOINT_TypeDef *) LPC_GPIOINT_BASE ) +#define LPC_PINCON ((LPC_PINCON_TypeDef *) LPC_PINCON_BASE ) +#define LPC_SSP0 ((LPC_SSP_TypeDef *) LPC_SSP0_BASE ) +#define LPC_SSP1 ((LPC_SSP_TypeDef *) LPC_SSP1_BASE ) +#define LPC_ADC ((LPC_ADC_TypeDef *) LPC_ADC_BASE ) +#define LPC_DAC ((LPC_DAC_TypeDef *) LPC_DAC_BASE ) +#define LPC_CANAF_RAM ((LPC_CANAF_RAM_TypeDef *) LPC_CANAF_RAM_BASE) +#define LPC_CANAF ((LPC_CANAF_TypeDef *) LPC_CANAF_BASE ) +#define LPC_CANCR ((LPC_CANCR_TypeDef *) LPC_CANCR_BASE ) +#define LPC_CAN1 ((LPC_CAN_TypeDef *) LPC_CAN1_BASE ) +#define LPC_CAN2 ((LPC_CAN_TypeDef *) LPC_CAN2_BASE ) +#define LPC_MCPWM ((LPC_MCPWM_TypeDef *) LPC_MCPWM_BASE ) +#define LPC_QEI ((LPC_QEI_TypeDef *) LPC_QEI_BASE ) +#define LPC_EMAC ((LPC_EMAC_TypeDef *) LPC_EMAC_BASE ) +#define LPC_GPDMA ((LPC_GPDMA_TypeDef *) LPC_GPDMA_BASE ) +#define LPC_GPDMACH0 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH0_BASE ) +#define LPC_GPDMACH1 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH1_BASE ) +#define LPC_GPDMACH2 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH2_BASE ) +#define LPC_GPDMACH3 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH3_BASE ) +#define LPC_GPDMACH4 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH4_BASE ) +#define LPC_GPDMACH5 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH5_BASE ) +#define LPC_GPDMACH6 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH6_BASE ) +#define LPC_GPDMACH7 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH7_BASE ) +#define LPC_USB ((LPC_USB_TypeDef *) LPC_USB_BASE ) + +#endif // __LPC17xx_H__ diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cm3.h b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cm3.h new file mode 100644 index 0000000..a2b29ee --- /dev/null +++ b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cm3.h @@ -0,0 +1,1236 @@ +/**************************************************************************//** + * @file core_cm3.h + * @brief CMSIS Cortex-M3 Core Peripheral Access Layer 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. + * + ******************************************************************************/ +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +#ifndef __CORE_CM3_H_GENERIC +#define __CORE_CM3_H_GENERIC + + +/** \mainpage CMSIS Cortex-M3 + + This documentation describes the CMSIS Cortex-M Core Peripheral Access Layer. + It consists of: + + - Cortex-M Core Register Definitions + - Cortex-M functions + - Cortex-M instructions + + The CMSIS Cortex-M3 Core Peripheral Access Layer contains C and assembly functions that ease + access to the Cortex-M Core + */ + +/** \defgroup CMSIS_LintCinfiguration CMSIS Lint Configuration + List of Lint messages which will be suppressed and not shown: + - not yet checked + . + Note: To re-enable a Message, insert a space before 'lint' * + + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** \defgroup CMSIS_core_definitions CMSIS Core Definitions + This file defines all structures and symbols for CMSIS core: + - CMSIS version number + - Cortex-M core + - Cortex-M core Revision Number + @{ + */ + +/* CMSIS CM3 definitions */ +#define __CM3_CMSIS_VERSION_MAIN (0x02) /*!< [31:16] CMSIS HAL main version */ +#define __CM3_CMSIS_VERSION_SUB (0x00) /*!< [15:0] CMSIS HAL sub version */ +#define __CM3_CMSIS_VERSION ((__CM3_CMSIS_VERSION_MAIN << 16) | __CM3_CMSIS_VERSION_SUB) /*!< CMSIS HAL version number */ + +#define __CORTEX_M (0x03) /*!< Cortex core */ + + +#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 + +#include /*!< standard types definitions */ +#include "core_cmInstr.h" /*!< Core Instruction Access */ +#include "core_cmFunc.h" /*!< Core Function Access */ + +#endif /* __CORE_CM3_H_GENERIC */ + + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM3_H_DEPENDANT +#define __CORE_CM3_H_DEPENDANT + +/* IO definitions (access restrictions to peripheral registers) */ +#ifdef __cplusplus + #define __I volatile /*!< defines 'read only' permissions */ +#else + #define __I volatile const /*!< defines 'read only' permissions */ +#endif +#define __O volatile /*!< defines 'write only' permissions */ +#define __IO volatile /*!< defines 'read / write' permissions */ + +/*@} end of group CMSIS_core_definitions */ + + + +/******************************************************************************* + * Register Abstraction + ******************************************************************************/ +/** \defgroup CMSIS_core_register CMSIS Core Register + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + - Core Debug Register + - Core MPU Register +*/ + +/** \ingroup CMSIS_core_register + \defgroup CMSIS_CORE CMSIS Core + Type definitions for the Cortex-M Core Registers + @{ + */ + +/** \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { +#if (__CORTEX_M != 0x04) + uint32_t _reserved0:27; /*!< bit: 0..26 Reserved */ +#else + uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ +#endif + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + + +/** \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + + +/** \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ +#if (__CORTEX_M != 0x04) + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ +#else + uint32_t _reserved0:7; /*!< bit: 9..15 Reserved */ + uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ + uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ +#endif + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t IT:2; /*!< bit: 25..26 saved IT state (read 0) */ + uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + + +/** \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t FPCA:1; /*!< bit: 2 FP extension active flag */ + uint32_t _reserved0:29; /*!< bit: 3..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/*@} end of group CMSIS_CORE */ + + +/** \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC CMSIS NVIC + Type definitions for the Cortex-M NVIC Registers + @{ + */ + +/** \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IO uint32_t ISER[8]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24]; + __IO uint32_t ICER[8]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[24]; + __IO uint32_t ISPR[8]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24]; + __IO uint32_t ICPR[8]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24]; + __IO uint32_t IABR[8]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56]; + __IO uint8_t IP[240]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644]; + __O uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** \ingroup CMSIS_core_register + \defgroup CMSIS_SCB CMSIS SCB + Type definitions for the Cortex-M System Control Block Registers + @{ + */ + +/** \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __I uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPU ID Base Register */ + __IO uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control State Register */ + __IO uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ + __IO uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt / Reset Control Register */ + __IO uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IO uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + __IO uint8_t SHP[12]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ + __IO uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ + __IO uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ + __IO uint32_t HFSR; /*!< Offset: 0x02C (R/W) Hard Fault Status Register */ + __IO uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ + __IO uint32_t MMFAR; /*!< Offset: 0x034 (R/W) Mem Manage Address Register */ + __IO uint32_t BFAR; /*!< Offset: 0x038 (R/W) Bus Fault Address Register */ + __IO uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ + __I uint32_t PFR[2]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ + __I uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ + __I uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ + __I uint32_t MMFR[4]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ + __I uint32_t ISAR[5]; /*!< Offset: 0x060 (R/ ) ISA Feature Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24 /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20 /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_PARTNO_Pos 4 /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0 /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL << SCB_CPUID_REVISION_Pos) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31 /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28 /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27 /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26 /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25 /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23 /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22 /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12 /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_RETTOBASE_Pos 11 /*!< SCB ICSR: RETTOBASE Position */ +#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0 /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL << SCB_ICSR_VECTACTIVE_Pos) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_VTOR_TBLBASE_Pos 29 /*!< SCB VTOR: TBLBASE Position */ +#define SCB_VTOR_TBLBASE_Msk (1UL << SCB_VTOR_TBLBASE_Pos) /*!< SCB VTOR: TBLBASE Mask */ + +#define SCB_VTOR_TBLOFF_Pos 7 /*!< SCB VTOR: TBLOFF Position */ +#define SCB_VTOR_TBLOFF_Msk (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16 /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16 /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15 /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_PRIGROUP_Pos 8 /*!< SCB AIRCR: PRIGROUP Position */ +#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2 /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1 /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +#define SCB_AIRCR_VECTRESET_Pos 0 /*!< SCB AIRCR: VECTRESET Position */ +#define SCB_AIRCR_VECTRESET_Msk (1UL << SCB_AIRCR_VECTRESET_Pos) /*!< SCB AIRCR: VECTRESET Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4 /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2 /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1 /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9 /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_BFHFNMIGN_Pos 8 /*!< SCB CCR: BFHFNMIGN Position */ +#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ + +#define SCB_CCR_DIV_0_TRP_Pos 4 /*!< SCB CCR: DIV_0_TRP Position */ +#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3 /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +#define SCB_CCR_USERSETMPEND_Pos 1 /*!< SCB CCR: USERSETMPEND Position */ +#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ + +#define SCB_CCR_NONBASETHRDENA_Pos 0 /*!< SCB CCR: NONBASETHRDENA Position */ +#define SCB_CCR_NONBASETHRDENA_Msk (1UL << SCB_CCR_NONBASETHRDENA_Pos) /*!< SCB CCR: NONBASETHRDENA Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_USGFAULTENA_Pos 18 /*!< SCB SHCSR: USGFAULTENA Position */ +#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ + +#define SCB_SHCSR_BUSFAULTENA_Pos 17 /*!< SCB SHCSR: BUSFAULTENA Position */ +#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ + +#define SCB_SHCSR_MEMFAULTENA_Pos 16 /*!< SCB SHCSR: MEMFAULTENA Position */ +#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ + +#define SCB_SHCSR_SVCALLPENDED_Pos 15 /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +#define SCB_SHCSR_BUSFAULTPENDED_Pos 14 /*!< SCB SHCSR: BUSFAULTPENDED Position */ +#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ + +#define SCB_SHCSR_MEMFAULTPENDED_Pos 13 /*!< SCB SHCSR: MEMFAULTPENDED Position */ +#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ + +#define SCB_SHCSR_USGFAULTPENDED_Pos 12 /*!< SCB SHCSR: USGFAULTPENDED Position */ +#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ + +#define SCB_SHCSR_SYSTICKACT_Pos 11 /*!< SCB SHCSR: SYSTICKACT Position */ +#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ + +#define SCB_SHCSR_PENDSVACT_Pos 10 /*!< SCB SHCSR: PENDSVACT Position */ +#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ + +#define SCB_SHCSR_MONITORACT_Pos 8 /*!< SCB SHCSR: MONITORACT Position */ +#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ + +#define SCB_SHCSR_SVCALLACT_Pos 7 /*!< SCB SHCSR: SVCALLACT Position */ +#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ + +#define SCB_SHCSR_USGFAULTACT_Pos 3 /*!< SCB SHCSR: USGFAULTACT Position */ +#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ + +#define SCB_SHCSR_BUSFAULTACT_Pos 1 /*!< SCB SHCSR: BUSFAULTACT Position */ +#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ + +#define SCB_SHCSR_MEMFAULTACT_Pos 0 /*!< SCB SHCSR: MEMFAULTACT Position */ +#define SCB_SHCSR_MEMFAULTACT_Msk (1UL << SCB_SHCSR_MEMFAULTACT_Pos) /*!< SCB SHCSR: MEMFAULTACT Mask */ + +/* SCB Configurable Fault Status Registers Definitions */ +#define SCB_CFSR_USGFAULTSR_Pos 16 /*!< SCB CFSR: Usage Fault Status Register Position */ +#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ + +#define SCB_CFSR_BUSFAULTSR_Pos 8 /*!< SCB CFSR: Bus Fault Status Register Position */ +#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ + +#define SCB_CFSR_MEMFAULTSR_Pos 0 /*!< SCB CFSR: Memory Manage Fault Status Register Position */ +#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL << SCB_CFSR_MEMFAULTSR_Pos) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ + +/* SCB Hard Fault Status Registers Definitions */ +#define SCB_HFSR_DEBUGEVT_Pos 31 /*!< SCB HFSR: DEBUGEVT Position */ +#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ + +#define SCB_HFSR_FORCED_Pos 30 /*!< SCB HFSR: FORCED Position */ +#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ + +#define SCB_HFSR_VECTTBL_Pos 1 /*!< SCB HFSR: VECTTBL Position */ +#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ + +/* SCB Debug Fault Status Register Definitions */ +#define SCB_DFSR_EXTERNAL_Pos 4 /*!< SCB DFSR: EXTERNAL Position */ +#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ + +#define SCB_DFSR_VCATCH_Pos 3 /*!< SCB DFSR: VCATCH Position */ +#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ + +#define SCB_DFSR_DWTTRAP_Pos 2 /*!< SCB DFSR: DWTTRAP Position */ +#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ + +#define SCB_DFSR_BKPT_Pos 1 /*!< SCB DFSR: BKPT Position */ +#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ + +#define SCB_DFSR_HALTED_Pos 0 /*!< SCB DFSR: HALTED Position */ +#define SCB_DFSR_HALTED_Msk (1UL << SCB_DFSR_HALTED_Pos) /*!< SCB DFSR: HALTED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick CMSIS SysTick + Type definitions for the Cortex-M System Timer Registers + @{ + */ + +/** \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IO uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IO uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __I uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** \ingroup CMSIS_core_register + \defgroup CMSIS_ITM CMSIS ITM + Type definitions for the Cortex-M Instrumentation Trace Macrocell (ITM) + @{ + */ + +/** \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). + */ +typedef struct +{ + __O union + { + __O uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ + __O uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ + __O uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ + } PORT [32]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ + uint32_t RESERVED0[864]; + __IO uint32_t TER; /*!< Offset: (R/W) ITM Trace Enable Register */ + uint32_t RESERVED1[15]; + __IO uint32_t TPR; /*!< Offset: (R/W) ITM Trace Privilege Register */ + uint32_t RESERVED2[15]; + __IO uint32_t TCR; /*!< Offset: (R/W) ITM Trace Control Register */ + uint32_t RESERVED3[29]; + __IO uint32_t IWR; /*!< Offset: (R/W) ITM Integration Write Register */ + __IO uint32_t IRR; /*!< Offset: (R/W) ITM Integration Read Register */ + __IO uint32_t IMCR; /*!< Offset: (R/W) ITM Integration Mode Control Register */ + uint32_t RESERVED4[43]; + __IO uint32_t LAR; /*!< Offset: (R/W) ITM Lock Access Register */ + __IO uint32_t LSR; /*!< Offset: (R/W) ITM Lock Status Register */ + uint32_t RESERVED5[6]; + __I uint32_t PID4; /*!< Offset: (R/ ) ITM Peripheral Identification Register #4 */ + __I uint32_t PID5; /*!< Offset: (R/ ) ITM Peripheral Identification Register #5 */ + __I uint32_t PID6; /*!< Offset: (R/ ) ITM Peripheral Identification Register #6 */ + __I uint32_t PID7; /*!< Offset: (R/ ) ITM Peripheral Identification Register #7 */ + __I uint32_t PID0; /*!< Offset: (R/ ) ITM Peripheral Identification Register #0 */ + __I uint32_t PID1; /*!< Offset: (R/ ) ITM Peripheral Identification Register #1 */ + __I uint32_t PID2; /*!< Offset: (R/ ) ITM Peripheral Identification Register #2 */ + __I uint32_t PID3; /*!< Offset: (R/ ) ITM Peripheral Identification Register #3 */ + __I uint32_t CID0; /*!< Offset: (R/ ) ITM Component Identification Register #0 */ + __I uint32_t CID1; /*!< Offset: (R/ ) ITM Component Identification Register #1 */ + __I uint32_t CID2; /*!< Offset: (R/ ) ITM Component Identification Register #2 */ + __I uint32_t CID3; /*!< Offset: (R/ ) ITM Component Identification Register #3 */ +} ITM_Type; + +/* ITM Trace Privilege Register Definitions */ +#define ITM_TPR_PRIVMASK_Pos 0 /*!< ITM TPR: PRIVMASK Position */ +#define ITM_TPR_PRIVMASK_Msk (0xFUL << ITM_TPR_PRIVMASK_Pos) /*!< ITM TPR: PRIVMASK Mask */ + +/* ITM Trace Control Register Definitions */ +#define ITM_TCR_BUSY_Pos 23 /*!< ITM TCR: BUSY Position */ +#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ + +#define ITM_TCR_ATBID_Pos 16 /*!< ITM TCR: ATBID Position */ +#define ITM_TCR_ATBID_Msk (0x7FUL << ITM_TCR_ATBID_Pos) /*!< ITM TCR: ATBID Mask */ + +#define ITM_TCR_TSPrescale_Pos 8 /*!< ITM TCR: TSPrescale Position */ +#define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ + +#define ITM_TCR_SWOENA_Pos 4 /*!< ITM TCR: SWOENA Position */ +#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ + +#define ITM_TCR_DWTENA_Pos 3 /*!< ITM TCR: DWTENA Position */ +#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ + +#define ITM_TCR_SYNCENA_Pos 2 /*!< ITM TCR: SYNCENA Position */ +#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ + +#define ITM_TCR_TSENA_Pos 1 /*!< ITM TCR: TSENA Position */ +#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ + +#define ITM_TCR_ITMENA_Pos 0 /*!< ITM TCR: ITM Enable bit Position */ +#define ITM_TCR_ITMENA_Msk (1UL << ITM_TCR_ITMENA_Pos) /*!< ITM TCR: ITM Enable bit Mask */ + +/* ITM Integration Write Register Definitions */ +#define ITM_IWR_ATVALIDM_Pos 0 /*!< ITM IWR: ATVALIDM Position */ +#define ITM_IWR_ATVALIDM_Msk (1UL << ITM_IWR_ATVALIDM_Pos) /*!< ITM IWR: ATVALIDM Mask */ + +/* ITM Integration Read Register Definitions */ +#define ITM_IRR_ATREADYM_Pos 0 /*!< ITM IRR: ATREADYM Position */ +#define ITM_IRR_ATREADYM_Msk (1UL << ITM_IRR_ATREADYM_Pos) /*!< ITM IRR: ATREADYM Mask */ + +/* ITM Integration Mode Control Register Definitions */ +#define ITM_IMCR_INTEGRATION_Pos 0 /*!< ITM IMCR: INTEGRATION Position */ +#define ITM_IMCR_INTEGRATION_Msk (1UL << ITM_IMCR_INTEGRATION_Pos) /*!< ITM IMCR: INTEGRATION Mask */ + +/* ITM Lock Status Register Definitions */ +#define ITM_LSR_ByteAcc_Pos 2 /*!< ITM LSR: ByteAcc Position */ +#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ + +#define ITM_LSR_Access_Pos 1 /*!< ITM LSR: Access Position */ +#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ + +#define ITM_LSR_Present_Pos 0 /*!< ITM LSR: Present Position */ +#define ITM_LSR_Present_Msk (1UL << ITM_LSR_Present_Pos) /*!< ITM LSR: Present Mask */ + +/*@}*/ /* end of group CMSIS_ITM */ + + +/** \ingroup CMSIS_core_register + \defgroup CMSIS_InterruptType CMSIS Interrupt Type + Type definitions for the Cortex-M Interrupt Type Register + @{ + */ + +/** \brief Structure type to access the Interrupt Type Register. + */ +typedef struct +{ + uint32_t RESERVED0; + __I uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Control Type Register */ +#if ((defined __CM3_REV) && (__CM3_REV >= 0x200)) + __IO uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ +#else + uint32_t RESERVED1; +#endif +} InterruptType_Type; + +/* Interrupt Controller Type Register Definitions */ +#define IntType_ICTR_INTLINESNUM_Pos 0 /*!< InterruptType ICTR: INTLINESNUM Position */ +#define IntType_ICTR_INTLINESNUM_Msk (0x1FUL << IntType_ICTR_INTLINESNUM_Pos) /*!< InterruptType ICTR: INTLINESNUM Mask */ + +/* Auxiliary Control Register Definitions */ +#define IntType_ACTLR_DISFOLD_Pos 2 /*!< InterruptType ACTLR: DISFOLD Position */ +#define IntType_ACTLR_DISFOLD_Msk (1UL << IntType_ACTLR_DISFOLD_Pos) /*!< InterruptType ACTLR: DISFOLD Mask */ + +#define IntType_ACTLR_DISDEFWBUF_Pos 1 /*!< InterruptType ACTLR: DISDEFWBUF Position */ +#define IntType_ACTLR_DISDEFWBUF_Msk (1UL << IntType_ACTLR_DISDEFWBUF_Pos) /*!< InterruptType ACTLR: DISDEFWBUF Mask */ + +#define IntType_ACTLR_DISMCYCINT_Pos 0 /*!< InterruptType ACTLR: DISMCYCINT Position */ +#define IntType_ACTLR_DISMCYCINT_Msk (1UL << IntType_ACTLR_DISMCYCINT_Pos) /*!< InterruptType ACTLR: DISMCYCINT Mask */ + +/*@}*/ /* end of group CMSIS_InterruptType */ + + +#if (__MPU_PRESENT == 1) +/** \ingroup CMSIS_core_register + \defgroup CMSIS_MPU CMSIS MPU + Type definitions for the Cortex-M Memory Protection Unit (MPU) + @{ + */ + +/** \brief Structure type to access the Memory Protection Unit (MPU). + */ +typedef struct +{ + __I uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ + __IO uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ + __IO uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ + __IO uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ + __IO uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ + __IO uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ + __IO uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ + __IO uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ + __IO uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ + __IO uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ + __IO uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ +} MPU_Type; + +/* MPU Type Register */ +#define MPU_TYPE_IREGION_Pos 16 /*!< MPU TYPE: IREGION Position */ +#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ + +#define MPU_TYPE_DREGION_Pos 8 /*!< MPU TYPE: DREGION Position */ +#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ + +#define MPU_TYPE_SEPARATE_Pos 0 /*!< MPU TYPE: SEPARATE Position */ +#define MPU_TYPE_SEPARATE_Msk (1UL << MPU_TYPE_SEPARATE_Pos) /*!< MPU TYPE: SEPARATE Mask */ + +/* MPU Control Register */ +#define MPU_CTRL_PRIVDEFENA_Pos 2 /*!< MPU CTRL: PRIVDEFENA Position */ +#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ + +#define MPU_CTRL_HFNMIENA_Pos 1 /*!< MPU CTRL: HFNMIENA Position */ +#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ + +#define MPU_CTRL_ENABLE_Pos 0 /*!< MPU CTRL: ENABLE Position */ +#define MPU_CTRL_ENABLE_Msk (1UL << MPU_CTRL_ENABLE_Pos) /*!< MPU CTRL: ENABLE Mask */ + +/* MPU Region Number Register */ +#define MPU_RNR_REGION_Pos 0 /*!< MPU RNR: REGION Position */ +#define MPU_RNR_REGION_Msk (0xFFUL << MPU_RNR_REGION_Pos) /*!< MPU RNR: REGION Mask */ + +/* MPU Region Base Address Register */ +#define MPU_RBAR_ADDR_Pos 5 /*!< MPU RBAR: ADDR Position */ +#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ + +#define MPU_RBAR_VALID_Pos 4 /*!< MPU RBAR: VALID Position */ +#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ + +#define MPU_RBAR_REGION_Pos 0 /*!< MPU RBAR: REGION Position */ +#define MPU_RBAR_REGION_Msk (0xFUL << MPU_RBAR_REGION_Pos) /*!< MPU RBAR: REGION Mask */ + +/* MPU Region Attribute and Size Register */ +#define MPU_RASR_XN_Pos 28 /*!< MPU RASR: XN Position */ +#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: XN Mask */ + +#define MPU_RASR_AP_Pos 24 /*!< MPU RASR: AP Position */ +#define MPU_RASR_AP_Msk (7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: AP Mask */ + +#define MPU_RASR_TEX_Pos 19 /*!< MPU RASR: TEX Position */ +#define MPU_RASR_TEX_Msk (7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: TEX Mask */ + +#define MPU_RASR_S_Pos 18 /*!< MPU RASR: Shareable bit Position */ +#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: Shareable bit Mask */ + +#define MPU_RASR_C_Pos 17 /*!< MPU RASR: Cacheable bit Position */ +#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: Cacheable bit Mask */ + +#define MPU_RASR_B_Pos 16 /*!< MPU RASR: Bufferable bit Position */ +#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: Bufferable bit Mask */ + +#define MPU_RASR_SRD_Pos 8 /*!< MPU RASR: Sub-Region Disable Position */ +#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ + +#define MPU_RASR_SIZE_Pos 1 /*!< MPU RASR: Region Size Field Position */ +#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ + +#define MPU_RASR_ENA_Pos 0 /*!< MPU RASR: Region enable bit Position */ +#define MPU_RASR_ENA_Msk (0x1UL << MPU_RASR_ENA_Pos) /*!< MPU RASR: Region enable bit Disable Mask */ + +/*@} end of group CMSIS_MPU */ +#endif + + +/** \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug CMSIS Core Debug + Type definitions for the Cortex-M Core Debug Registers + @{ + */ + +/** \brief Structure type to access the Core Debug Register (CoreDebug). + */ +typedef struct +{ + __IO uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ + __O uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ + __IO uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ + __IO uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ +} CoreDebug_Type; + +/* Debug Halting Control and Status Register */ +#define CoreDebug_DHCSR_DBGKEY_Pos 16 /*!< CoreDebug DHCSR: DBGKEY Position */ +#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ + +#define CoreDebug_DHCSR_S_RESET_ST_Pos 25 /*!< CoreDebug DHCSR: S_RESET_ST Position */ +#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ + +#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24 /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ +#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ + +#define CoreDebug_DHCSR_S_LOCKUP_Pos 19 /*!< CoreDebug DHCSR: S_LOCKUP Position */ +#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ + +#define CoreDebug_DHCSR_S_SLEEP_Pos 18 /*!< CoreDebug DHCSR: S_SLEEP Position */ +#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ + +#define CoreDebug_DHCSR_S_HALT_Pos 17 /*!< CoreDebug DHCSR: S_HALT Position */ +#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ + +#define CoreDebug_DHCSR_S_REGRDY_Pos 16 /*!< CoreDebug DHCSR: S_REGRDY Position */ +#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ + +#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5 /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ +#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ + +#define CoreDebug_DHCSR_C_MASKINTS_Pos 3 /*!< CoreDebug DHCSR: C_MASKINTS Position */ +#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ + +#define CoreDebug_DHCSR_C_STEP_Pos 2 /*!< CoreDebug DHCSR: C_STEP Position */ +#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ + +#define CoreDebug_DHCSR_C_HALT_Pos 1 /*!< CoreDebug DHCSR: C_HALT Position */ +#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ + +#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0 /*!< CoreDebug DHCSR: C_DEBUGEN Position */ +#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL << CoreDebug_DHCSR_C_DEBUGEN_Pos) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ + +/* Debug Core Register Selector Register */ +#define CoreDebug_DCRSR_REGWnR_Pos 16 /*!< CoreDebug DCRSR: REGWnR Position */ +#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ + +#define CoreDebug_DCRSR_REGSEL_Pos 0 /*!< CoreDebug DCRSR: REGSEL Position */ +#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL << CoreDebug_DCRSR_REGSEL_Pos) /*!< CoreDebug DCRSR: REGSEL Mask */ + +/* Debug Exception and Monitor Control Register */ +#define CoreDebug_DEMCR_TRCENA_Pos 24 /*!< CoreDebug DEMCR: TRCENA Position */ +#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ + +#define CoreDebug_DEMCR_MON_REQ_Pos 19 /*!< CoreDebug DEMCR: MON_REQ Position */ +#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ + +#define CoreDebug_DEMCR_MON_STEP_Pos 18 /*!< CoreDebug DEMCR: MON_STEP Position */ +#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ + +#define CoreDebug_DEMCR_MON_PEND_Pos 17 /*!< CoreDebug DEMCR: MON_PEND Position */ +#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ + +#define CoreDebug_DEMCR_MON_EN_Pos 16 /*!< CoreDebug DEMCR: MON_EN Position */ +#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ + +#define CoreDebug_DEMCR_VC_HARDERR_Pos 10 /*!< CoreDebug DEMCR: VC_HARDERR Position */ +#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ + +#define CoreDebug_DEMCR_VC_INTERR_Pos 9 /*!< CoreDebug DEMCR: VC_INTERR Position */ +#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ + +#define CoreDebug_DEMCR_VC_BUSERR_Pos 8 /*!< CoreDebug DEMCR: VC_BUSERR Position */ +#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ + +#define CoreDebug_DEMCR_VC_STATERR_Pos 7 /*!< CoreDebug DEMCR: VC_STATERR Position */ +#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ + +#define CoreDebug_DEMCR_VC_CHKERR_Pos 6 /*!< CoreDebug DEMCR: VC_CHKERR Position */ +#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ + +#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5 /*!< CoreDebug DEMCR: VC_NOCPERR Position */ +#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ + +#define CoreDebug_DEMCR_VC_MMERR_Pos 4 /*!< CoreDebug DEMCR: VC_MMERR Position */ +#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ + +#define CoreDebug_DEMCR_VC_CORERESET_Pos 0 /*!< CoreDebug DEMCR: VC_CORERESET Position */ +#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL << CoreDebug_DEMCR_VC_CORERESET_Pos) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ + +/*@} end of group CMSIS_CoreDebug */ + + +/** \ingroup CMSIS_core_register + @{ + */ + +/* Memory mapping of Cortex-M3 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ +#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define InterruptType ((InterruptType_Type *) SCS_BASE) /*!< Interrupt Type Register */ +#define SCB ((SCB_Type *) SCB_BASE) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE) /*!< NVIC configuration struct */ +#define ITM ((ITM_Type *) ITM_BASE) /*!< ITM configuration struct */ +#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ + +#if (__MPU_PRESENT == 1) + #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ + #define MPU ((MPU_Type*) MPU_BASE) /*!< Memory Protection Unit */ +#endif + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + ******************************************************************************/ +/** \defgroup CMSIS_Core_FunctionInterface CMSIS Core Function Interface + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Debug Functions + - Core Register Access Functions +*/ + + + +/* ########################## NVIC functions #################################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions CMSIS Core NVIC Functions + @{ + */ + +/** \brief Set Priority Grouping + + This function sets the priority grouping field using the required unlock sequence. + The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. + Only values from 0..7 are used. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. + + \param [in] PriorityGroup Priority grouping field + */ +static __INLINE void NVIC_SetPriorityGrouping(uint32_t PriorityGroup) +{ + uint32_t reg_value; + uint32_t PriorityGroupTmp = (PriorityGroup & 0x07); /* only values 0..7 are used */ + + reg_value = SCB->AIRCR; /* read old register configuration */ + reg_value &= ~(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk); /* clear bits to change */ + reg_value = (reg_value | + (0x5FA << SCB_AIRCR_VECTKEY_Pos) | + (PriorityGroupTmp << 8)); /* Insert write key and priorty group */ + SCB->AIRCR = reg_value; +} + + +/** \brief Get Priority Grouping + + This function gets the priority grouping from NVIC Interrupt Controller. + Priority grouping is SCB->AIRCR [10:8] PRIGROUP field. + + \return Priority grouping field + */ +static __INLINE uint32_t NVIC_GetPriorityGrouping(void) +{ + return ((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos); /* read priority grouping field */ +} + + +/** \brief Enable External Interrupt + + This function enables a device specific interupt in the NVIC interrupt controller. + The interrupt number cannot be a negative value. + + \param [in] IRQn Number of the external interrupt to enable + */ +static __INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */ +} + + +/** \brief Disable External Interrupt + + This function disables a device specific interupt in the NVIC interrupt controller. + The interrupt number cannot be a negative value. + + \param [in] IRQn Number of the external interrupt to disable + */ +static __INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* disable interrupt */ +} + + +/** \brief Get Pending Interrupt + + This function reads the pending register in the NVIC and returns the pending bit + for the specified interrupt. + + \param [in] IRQn Number of the interrupt for get pending + \return 0 Interrupt status is not pending + \return 1 Interrupt status is pending + */ +static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t) ((NVIC->ISPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0)); /* Return 1 if pending else 0 */ +} + + +/** \brief Set Pending Interrupt + + This function sets the pending bit for the specified interrupt. + The interrupt number cannot be a negative value. + + \param [in] IRQn Number of the interrupt for set pending + */ +static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* set interrupt pending */ +} + + +/** \brief Clear Pending Interrupt + + This function clears the pending bit for the specified interrupt. + The interrupt number cannot be a negative value. + + \param [in] IRQn Number of the interrupt for clear pending + */ +static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* Clear pending interrupt */ +} + + +/** \brief Get Active Interrupt + + This function reads the active register in NVIC and returns the active bit. + \param [in] IRQn Number of the interrupt for get active + \return 0 Interrupt status is not active + \return 1 Interrupt status is active + */ +static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +{ + return((uint32_t)((NVIC->IABR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0)); /* Return 1 if active else 0 */ +} + + +/** \brief Set Interrupt Priority + + This function sets the priority for the specified interrupt. The interrupt + number can be positive to specify an external (device specific) + interrupt, or negative to specify an internal (core) interrupt. + + Note: The priority cannot be set for every core interrupt. + + \param [in] IRQn Number of the interrupt for set priority + \param [in] priority Priority to set + */ +static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if(IRQn < 0) { + SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M System Interrupts */ + else { + NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for device specific Interrupts */ +} + + +/** \brief Get Interrupt Priority + + This function reads the priority for the specified interrupt. The interrupt + number can be positive to specify an external (device specific) + interrupt, or negative to specify an internal (core) interrupt. + + The returned priority value is automatically aligned to the implemented + priority bits of the microcontroller. + + \param [in] IRQn Number of the interrupt for get priority + \return Interrupt Priority + */ +static __INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if(IRQn < 0) { + return((uint32_t)(SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] >> (8 - __NVIC_PRIO_BITS))); } /* get priority for Cortex-M system interrupts */ + else { + return((uint32_t)(NVIC->IP[(uint32_t)(IRQn)] >> (8 - __NVIC_PRIO_BITS))); } /* get priority for device specific interrupts */ +} + + +/** \brief Encode Priority + + This function encodes the priority for an interrupt with the given priority group, + preemptive priority value and sub priority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the samllest possible priority group is set. + + The returned priority value can be used for NVIC_SetPriority(...) function + + \param [in] PriorityGroup Used priority group + \param [in] PreemptPriority Preemptive priority value (starting from 0) + \param [in] SubPriority Sub priority value (starting from 0) + \return Encoded priority for the interrupt + */ +static __INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & 0x07); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp; + SubPriorityBits = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS; + + return ( + ((PreemptPriority & ((1 << (PreemptPriorityBits)) - 1)) << SubPriorityBits) | + ((SubPriority & ((1 << (SubPriorityBits )) - 1))) + ); +} + + +/** \brief Decode Priority + + This function decodes an interrupt priority value with the given priority group to + preemptive priority value and sub priority value. + In case of a conflict between priority grouping and available + priority bits (__NVIC_PRIO_BITS) the samllest possible priority group is set. + + The priority value can be retrieved with NVIC_GetPriority(...) function + + \param [in] Priority Priority value + \param [in] PriorityGroup Used priority group + \param [out] pPreemptPriority Preemptive priority value (starting from 0) + \param [out] pSubPriority Sub priority value (starting from 0) + */ +static __INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* pPreemptPriority, uint32_t* pSubPriority) +{ + uint32_t PriorityGroupTmp = (PriorityGroup & 0x07); /* only values 0..7 are used */ + uint32_t PreemptPriorityBits; + uint32_t SubPriorityBits; + + PreemptPriorityBits = ((7 - PriorityGroupTmp) > __NVIC_PRIO_BITS) ? __NVIC_PRIO_BITS : 7 - PriorityGroupTmp; + SubPriorityBits = ((PriorityGroupTmp + __NVIC_PRIO_BITS) < 7) ? 0 : PriorityGroupTmp - 7 + __NVIC_PRIO_BITS; + + *pPreemptPriority = (Priority >> SubPriorityBits) & ((1 << (PreemptPriorityBits)) - 1); + *pSubPriority = (Priority ) & ((1 << (SubPriorityBits )) - 1); +} + + +/** \brief System Reset + + This function initiate a system reset request to reset the MCU. + */ +static __INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | + (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk); /* Keep priority group unchanged */ + __DSB(); /* Ensure completion of memory access */ + while(1); /* wait until reset */ +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions CMSIS Core SysTick Functions + @{ + */ + +#if (__Vendor_SysTickConfig == 0) + +/** \brief System Tick Configuration + + This function initialises the system tick timer and its interrupt and start the system tick timer. + Counter is in free running mode to generate periodical interrupts. + + \param [in] ticks Number of ticks between two interrupts + \return 0 Function succeeded + \return 1 Function failed + */ +static __INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ + + SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */ + SysTick->VAL = 0; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + +/* ##################################### Debug In/Output function ########################################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_core_DebugFunctions CMSIS Core Debug Functions + @{ + */ + +extern volatile int32_t ITM_RxBuffer; /*!< external variable to receive characters */ +#define ITM_RXBUFFER_EMPTY 0x5AA55AA5 /*!< value identifying ITM_RxBuffer is ready for next character */ + + +/** \brief ITM Send Character + + This function transmits a character via the ITM channel 0. + It just returns when no debugger is connected that has booked the output. + It is blocking when a debugger is connected, but the previous character send is not transmitted. + + \param [in] ch Character to transmit + \return Character to transmit + */ +static __INLINE uint32_t ITM_SendChar (uint32_t ch) +{ + if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) && /* Trace enabled */ + (ITM->TCR & ITM_TCR_ITMENA_Msk) && /* ITM enabled */ + (ITM->TER & (1UL << 0) ) ) /* ITM Port #0 enabled */ + { + while (ITM->PORT[0].u32 == 0); + ITM->PORT[0].u8 = (uint8_t) ch; + } + return (ch); +} + + +/** \brief ITM Receive Character + + This function inputs a character via external variable ITM_RxBuffer. + It just returns when no debugger is connected that has booked the output. + It is blocking when a debugger is connected, but the previous character send is not transmitted. + + \return Received character + \return -1 No character received + */ +static __INLINE int32_t ITM_ReceiveChar (void) { + int32_t ch = -1; /* no character available */ + + if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) { + ch = ITM_RxBuffer; + ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ + } + + return (ch); +} + + +/** \brief ITM Check Character + + This function checks external variable ITM_RxBuffer whether a character is available or not. + It returns '1' if a character is available and '0' if no character is available. + + \return 0 No character available + \return 1 Character available + */ +static __INLINE int32_t ITM_CheckChar (void) { + + if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) { + return (0); /* no character available */ + } else { + return (1); /* character available */ + } +} + +/*@} end of CMSIS_core_DebugFunctions */ + +#endif /* __CORE_CM3_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ + +#ifdef __cplusplus +} +#endif + +/*lint -restore */ diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmFunc.h b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmFunc.h new file mode 100644 index 0000000..e3d0edb --- /dev/null +++ b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmFunc.h @@ -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 /* 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__ */ diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmInstr.h b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmInstr.h new file mode 100644 index 0000000..fb3c092 --- /dev/null +++ b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/core_cmInstr.h @@ -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 /* 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__ */ diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/system_LPC17xx.h b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/system_LPC17xx.h new file mode 100644 index 0000000..d72cb50 --- /dev/null +++ b/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc/system_LPC17xx.h @@ -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 + +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 */ diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/src/core_cm3.c b/platforms/lpc17xx/CMSISv2p00_LPC17xx/src/core_cm3.c new file mode 100644 index 0000000..6e13f4c --- /dev/null +++ b/platforms/lpc17xx/CMSISv2p00_LPC17xx/src/core_cm3.c @@ -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 + +/* 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 diff --git a/platforms/lpc17xx/CMSISv2p00_LPC17xx/src/system_LPC17xx.c b/platforms/lpc17xx/CMSISv2p00_LPC17xx/src/system_LPC17xx.c new file mode 100644 index 0000000..11aa44f --- /dev/null +++ b/platforms/lpc17xx/CMSISv2p00_LPC17xx/src/system_LPC17xx.c @@ -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 +#include "LPC17xx.h" + +/* +//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------ +*/ + +/*--------------------- Clock Configuration ---------------------------------- +// +// Clock Configuration +// System Controls and Status Register (SCS) +// OSCRANGE: Main Oscillator Range Select +// <0=> 1 MHz to 20 MHz +// <1=> 15 MHz to 24 MHz +// OSCEN: Main Oscillator Enable +// +// +// +// Clock Source Select Register (CLKSRCSEL) +// CLKSRC: PLL Clock Source Selection +// <0=> Internal RC oscillator +// <1=> Main oscillator +// <2=> RTC oscillator +// +// +// PLL0 Configuration (Main PLL) +// PLL0 Configuration Register (PLL0CFG) +// F_cco0 = (2 * M * F_in) / N +// F_in must be in the range of 32 kHz to 50 MHz +// F_cco0 must be in the range of 275 MHz to 550 MHz +// MSEL: PLL Multiplier Selection +// <6-32768><#-1> +// M Value +// NSEL: PLL Divider Selection +// <1-256><#-1> +// N Value +// +// +// +// PLL1 Configuration (USB PLL) +// PLL1 Configuration Register (PLL1CFG) +// F_usb = M * F_osc or F_usb = F_cco1 / (2 * P) +// F_cco1 = F_osc * M * 2 * P +// F_cco1 must be in the range of 156 MHz to 320 MHz +// MSEL: PLL Multiplier Selection +// <1-32><#-1> +// M Value (for USB maximum value is 4) +// PSEL: PLL Divider Selection +// <0=> 1 +// <1=> 2 +// <2=> 4 +// <3=> 8 +// P Value +// +// +// +// CPU Clock Configuration Register (CCLKCFG) +// CCLKSEL: Divide Value for CPU Clock from PLL0 +// <1-256><#-1> +// +// +// USB Clock Configuration Register (USBCLKCFG) +// USBSEL: Divide Value for USB Clock from PLL0 +// <0-15> +// Divide is USBSEL + 1 +// +// +// Peripheral Clock Selection Register 0 (PCLKSEL0) +// PCLK_WDT: Peripheral Clock Selection for WDT +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_TIMER0: Peripheral Clock Selection for TIMER0 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_TIMER1: Peripheral Clock Selection for TIMER1 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_UART0: Peripheral Clock Selection for UART0 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_UART1: Peripheral Clock Selection for UART1 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_PWM1: Peripheral Clock Selection for PWM1 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_I2C0: Peripheral Clock Selection for I2C0 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_SPI: Peripheral Clock Selection for SPI +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_SSP1: Peripheral Clock Selection for SSP1 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_DAC: Peripheral Clock Selection for DAC +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_ADC: Peripheral Clock Selection for ADC +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_CAN1: Peripheral Clock Selection for CAN1 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 6 +// PCLK_CAN2: Peripheral Clock Selection for CAN2 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 6 +// PCLK_ACF: Peripheral Clock Selection for ACF +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 6 +// +// +// Peripheral Clock Selection Register 1 (PCLKSEL1) +// 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 +// PCLK_GPIO: Peripheral Clock Selection for GPIOs +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// 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 +// PCLK_I2C1: Peripheral Clock Selection for I2C1 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_SSP0: Peripheral Clock Selection for SSP0 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_TIMER2: Peripheral Clock Selection for TIMER2 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_TIMER3: Peripheral Clock Selection for TIMER3 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_UART2: Peripheral Clock Selection for UART2 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_UART3: Peripheral Clock Selection for UART3 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_I2C2: Peripheral Clock Selection for I2C2 +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// PCLK_I2S: Peripheral Clock Selection for I2S +// <0=> Pclk = Cclk / 4 +// <1=> Pclk = Cclk +// <2=> Pclk = Cclk / 2 +// <3=> Pclk = Hclk / 8 +// 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 +// 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 +// 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 +// +// +// Power Control for Peripherals Register (PCONP) +// PCTIM0: Timer/Counter 0 power/clock enable +// PCTIM1: Timer/Counter 1 power/clock enable +// PCUART0: UART 0 power/clock enable +// PCUART1: UART 1 power/clock enable +// PCPWM1: PWM 1 power/clock enable +// PCI2C0: I2C interface 0 power/clock enable +// PCSPI: SPI interface power/clock enable +// PCRTC: RTC power/clock enable +// PCSSP1: SSP interface 1 power/clock enable +// PCAD: A/D converter power/clock enable +// PCCAN1: CAN controller 1 power/clock enable +// PCCAN2: CAN controller 2 power/clock enable +// PCGPIO: GPIOs power/clock enable +// PCRIT: Repetitive interrupt timer power/clock enable +// PCMC: Motor control PWM power/clock enable +// PCQEI: Quadrature encoder interface power/clock enable +// PCI2C1: I2C interface 1 power/clock enable +// PCSSP0: SSP interface 0 power/clock enable +// PCTIM2: Timer 2 power/clock enable +// PCTIM3: Timer 3 power/clock enable +// PCUART2: UART 2 power/clock enable +// PCUART3: UART 3 power/clock enable +// PCI2C2: I2C interface 2 power/clock enable +// PCI2S: I2S interface power/clock enable +// PCGPDMA: GP DMA function power/clock enable +// PCENET: Ethernet block power/clock enable +// PCUSB: USB interface power/clock enable +// +// +// Clock Output Configuration Register (CLKOUTCFG) +// CLKOUTSEL: Selects clock source for CLKOUT +// <0=> CPU clock +// <1=> Main oscillator +// <2=> Internal RC oscillator +// <3=> USB clock +// <4=> RTC oscillator +// CLKOUTDIV: Selects clock divider for CLKOUT +// <1-16><#-1> +// CLKOUT_EN: CLKOUT enable control +// +// +// +*/ +#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 ---------------------- +// +// Flash Accelerator Configuration +// 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) +// +*/ +#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 +} diff --git a/platforms/lpc17xx/Makefile b/platforms/lpc17xx/Makefile new file mode 100644 index 0000000..172df5a --- /dev/null +++ b/platforms/lpc17xx/Makefile @@ -0,0 +1,95 @@ +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)"' +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./CMSISv2p00_LPC17xx/inc \ + -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" + + \ No newline at end of file diff --git a/platforms/lpc17xx/atomthreads_test.out b/platforms/lpc17xx/atomthreads_test.out new file mode 100644 index 0000000..510711a --- /dev/null +++ b/platforms/lpc17xx/atomthreads_test.out @@ -0,0 +1,153 @@ + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex1... +mutex1 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex2... +mutex2 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex3... +mutex3 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex5... +mutex5 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex6... +mutex6 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex7... +mutex7 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex8... +mutex8 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex9... +mutex9 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting kern1... +kern1 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting kern2... +kern2 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting kern3... +kern3 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting kern4... +kern4 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting timer1... +timer1 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting timer2... +timer2 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting timer3... +timer3 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting timer5... +timer5 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting timer6... +timer6 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting timer7... +timer7 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue1... +queue1 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue2... +queue2 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue3... +queue3 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue4... +queue4 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue5... +queue5 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue6... +queue6 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue7... +queue7 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue8... +queue8 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting queue9... +queue9 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem1... +sem1 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem2... +sem2 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem3... +sem3 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem5... +sem5 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem6... +sem6 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem7... +sem7 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem8... +sem8 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem9... +sem9 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting mutex4... +mutex4 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting sem4... +sem4 PASS + +LPC17xx SystemCoreClock = 100000000 +Atomthreads starting timer4... +timer4 PASS + diff --git a/platforms/lpc17xx/drivers/lpc17xx.h b/platforms/lpc17xx/drivers/lpc17xx.h new file mode 100644 index 0000000..377fdf2 --- /dev/null +++ b/platforms/lpc17xx/drivers/lpc17xx.h @@ -0,0 +1,1035 @@ +/**************************************************************************//** + * @file LPC17xx.h + * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File for + * NXP LPC17xx Device Series + * @version: V1.09 + * @date: 17. March 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. + * + ******************************************************************************/ + + +#ifndef __LPC17xx_H__ +#define __LPC17xx_H__ + +/* + * ========================================================================== + * ---------- Interrupt Number Definition ----------------------------------- + * ========================================================================== + */ + +typedef enum IRQn +{ +/****** Cortex-M3 Processor Exceptions Numbers ***************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */ + BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */ + UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */ + SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */ + DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */ + +/****** LPC17xx Specific Interrupt Numbers *******************************************************/ + WDT_IRQn = 0, /*!< Watchdog Timer Interrupt */ + TIMER0_IRQn = 1, /*!< Timer0 Interrupt */ + TIMER1_IRQn = 2, /*!< Timer1 Interrupt */ + TIMER2_IRQn = 3, /*!< Timer2 Interrupt */ + TIMER3_IRQn = 4, /*!< Timer3 Interrupt */ + UART0_IRQn = 5, /*!< UART0 Interrupt */ + UART1_IRQn = 6, /*!< UART1 Interrupt */ + UART2_IRQn = 7, /*!< UART2 Interrupt */ + UART3_IRQn = 8, /*!< UART3 Interrupt */ + PWM1_IRQn = 9, /*!< PWM1 Interrupt */ + I2C0_IRQn = 10, /*!< I2C0 Interrupt */ + I2C1_IRQn = 11, /*!< I2C1 Interrupt */ + I2C2_IRQn = 12, /*!< I2C2 Interrupt */ + SPI_IRQn = 13, /*!< SPI Interrupt */ + SSP0_IRQn = 14, /*!< SSP0 Interrupt */ + SSP1_IRQn = 15, /*!< SSP1 Interrupt */ + PLL0_IRQn = 16, /*!< PLL0 Lock (Main PLL) Interrupt */ + RTC_IRQn = 17, /*!< Real Time Clock Interrupt */ + EINT0_IRQn = 18, /*!< External Interrupt 0 Interrupt */ + EINT1_IRQn = 19, /*!< External Interrupt 1 Interrupt */ + EINT2_IRQn = 20, /*!< External Interrupt 2 Interrupt */ + EINT3_IRQn = 21, /*!< External Interrupt 3 Interrupt */ + ADC_IRQn = 22, /*!< A/D Converter Interrupt */ + BOD_IRQn = 23, /*!< Brown-Out Detect Interrupt */ + USB_IRQn = 24, /*!< USB Interrupt */ + CAN_IRQn = 25, /*!< CAN Interrupt */ + DMA_IRQn = 26, /*!< General Purpose DMA Interrupt */ + I2S_IRQn = 27, /*!< I2S Interrupt */ + ENET_IRQn = 28, /*!< Ethernet Interrupt */ + RIT_IRQn = 29, /*!< Repetitive Interrupt Timer Interrupt */ + MCPWM_IRQn = 30, /*!< Motor Control PWM Interrupt */ + QEI_IRQn = 31, /*!< Quadrature Encoder Interface Interrupt */ + PLL1_IRQn = 32, /*!< PLL1 Lock (USB PLL) Interrupt */ + USBActivity_IRQn = 33, /* USB Activity interrupt */ + CANActivity_IRQn = 34, /* CAN Activity interrupt */ +} IRQn_Type; + + +/* + * ========================================================================== + * ----------- Processor and Core Peripheral Section ------------------------ + * ========================================================================== + */ + +/* Configuration of the Cortex-M3 Processor and Core Peripherals */ +#define __MPU_PRESENT 1 /*!< MPU present or not */ +#define __NVIC_PRIO_BITS 5 /*!< Number of Bits used for Priority Levels */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + + +#include "core_cm3.h" /* Cortex-M3 processor and core peripherals */ +#include "system_LPC17xx.h" /* System Header */ + + +/******************************************************************************/ +/* Device Specific Peripheral registers structures */ +/******************************************************************************/ + +#if defined ( __CC_ARM ) +#pragma anon_unions +#endif + +/*------------- System Control (SC) ------------------------------------------*/ +typedef struct +{ + __IO uint32_t FLASHCFG; /* Flash Accelerator Module */ + uint32_t RESERVED0[31]; + __IO uint32_t PLL0CON; /* Clocking and Power Control */ + __IO uint32_t PLL0CFG; + __I uint32_t PLL0STAT; + __O uint32_t PLL0FEED; + uint32_t RESERVED1[4]; + __IO uint32_t PLL1CON; + __IO uint32_t PLL1CFG; + __I uint32_t PLL1STAT; + __O uint32_t PLL1FEED; + uint32_t RESERVED2[4]; + __IO uint32_t PCON; + __IO uint32_t PCONP; + uint32_t RESERVED3[15]; + __IO uint32_t CCLKCFG; + __IO uint32_t USBCLKCFG; + __IO uint32_t CLKSRCSEL; + __IO uint32_t CANSLEEPCLR; + __IO uint32_t CANWAKEFLAGS; + uint32_t RESERVED4[10]; + __IO uint32_t EXTINT; /* External Interrupts */ + uint32_t RESERVED5; + __IO uint32_t EXTMODE; + __IO uint32_t EXTPOLAR; + uint32_t RESERVED6[12]; + __IO uint32_t RSID; /* Reset */ + uint32_t RESERVED7[7]; + __IO uint32_t SCS; /* Syscon Miscellaneous Registers */ + __IO uint32_t IRCTRIM; /* Clock Dividers */ + __IO uint32_t PCLKSEL0; + __IO uint32_t PCLKSEL1; + uint32_t RESERVED8[4]; + __IO uint32_t USBIntSt; /* USB Device/OTG Interrupt Register */ + __IO uint32_t DMAREQSEL; + __IO uint32_t CLKOUTCFG; /* Clock Output Configuration */ + } LPC_SC_TypeDef; + +/*------------- Pin Connect Block (PINCON) -----------------------------------*/ +typedef struct +{ + __IO uint32_t PINSEL0; + __IO uint32_t PINSEL1; + __IO uint32_t PINSEL2; + __IO uint32_t PINSEL3; + __IO uint32_t PINSEL4; + __IO uint32_t PINSEL5; + __IO uint32_t PINSEL6; + __IO uint32_t PINSEL7; + __IO uint32_t PINSEL8; + __IO uint32_t PINSEL9; + __IO uint32_t PINSEL10; + uint32_t RESERVED0[5]; + __IO uint32_t PINMODE0; + __IO uint32_t PINMODE1; + __IO uint32_t PINMODE2; + __IO uint32_t PINMODE3; + __IO uint32_t PINMODE4; + __IO uint32_t PINMODE5; + __IO uint32_t PINMODE6; + __IO uint32_t PINMODE7; + __IO uint32_t PINMODE8; + __IO uint32_t PINMODE9; + __IO uint32_t PINMODE_OD0; + __IO uint32_t PINMODE_OD1; + __IO uint32_t PINMODE_OD2; + __IO uint32_t PINMODE_OD3; + __IO uint32_t PINMODE_OD4; + __IO uint32_t I2CPADCFG; +} LPC_PINCON_TypeDef; + +/*------------- General Purpose Input/Output (GPIO) --------------------------*/ +typedef struct +{ + union { + __IO uint32_t FIODIR; + struct { + __IO uint16_t FIODIRL; + __IO uint16_t FIODIRH; + }; + struct { + __IO uint8_t FIODIR0; + __IO uint8_t FIODIR1; + __IO uint8_t FIODIR2; + __IO uint8_t FIODIR3; + }; + }; + uint32_t RESERVED0[3]; + union { + __IO uint32_t FIOMASK; + struct { + __IO uint16_t FIOMASKL; + __IO uint16_t FIOMASKH; + }; + struct { + __IO uint8_t FIOMASK0; + __IO uint8_t FIOMASK1; + __IO uint8_t FIOMASK2; + __IO uint8_t FIOMASK3; + }; + }; + union { + __IO uint32_t FIOPIN; + struct { + __IO uint16_t FIOPINL; + __IO uint16_t FIOPINH; + }; + struct { + __IO uint8_t FIOPIN0; + __IO uint8_t FIOPIN1; + __IO uint8_t FIOPIN2; + __IO uint8_t FIOPIN3; + }; + }; + union { + __IO uint32_t FIOSET; + struct { + __IO uint16_t FIOSETL; + __IO uint16_t FIOSETH; + }; + struct { + __IO uint8_t FIOSET0; + __IO uint8_t FIOSET1; + __IO uint8_t FIOSET2; + __IO uint8_t FIOSET3; + }; + }; + union { + __O uint32_t FIOCLR; + struct { + __O uint16_t FIOCLRL; + __O uint16_t FIOCLRH; + }; + struct { + __O uint8_t FIOCLR0; + __O uint8_t FIOCLR1; + __O uint8_t FIOCLR2; + __O uint8_t FIOCLR3; + }; + }; +} LPC_GPIO_TypeDef; + +typedef struct +{ + __I uint32_t IntStatus; + __I uint32_t IO0IntStatR; + __I uint32_t IO0IntStatF; + __O uint32_t IO0IntClr; + __IO uint32_t IO0IntEnR; + __IO uint32_t IO0IntEnF; + uint32_t RESERVED0[3]; + __I uint32_t IO2IntStatR; + __I uint32_t IO2IntStatF; + __O uint32_t IO2IntClr; + __IO uint32_t IO2IntEnR; + __IO uint32_t IO2IntEnF; +} LPC_GPIOINT_TypeDef; + +/*------------- Timer (TIM) --------------------------------------------------*/ +typedef struct +{ + __IO uint32_t IR; + __IO uint32_t TCR; + __IO uint32_t TC; + __IO uint32_t PR; + __IO uint32_t PC; + __IO uint32_t MCR; + __IO uint32_t MR0; + __IO uint32_t MR1; + __IO uint32_t MR2; + __IO uint32_t MR3; + __IO uint32_t CCR; + __I uint32_t CR0; + __I uint32_t CR1; + uint32_t RESERVED0[2]; + __IO uint32_t EMR; + uint32_t RESERVED1[12]; + __IO uint32_t CTCR; +} LPC_TIM_TypeDef; + +/*------------- Pulse-Width Modulation (PWM) ---------------------------------*/ +typedef struct +{ + __IO uint32_t IR; + __IO uint32_t TCR; + __IO uint32_t TC; + __IO uint32_t PR; + __IO uint32_t PC; + __IO uint32_t MCR; + __IO uint32_t MR0; + __IO uint32_t MR1; + __IO uint32_t MR2; + __IO uint32_t MR3; + __IO uint32_t CCR; + __I uint32_t CR0; + __I uint32_t CR1; + __I uint32_t CR2; + __I uint32_t CR3; + uint32_t RESERVED0; + __IO uint32_t MR4; + __IO uint32_t MR5; + __IO uint32_t MR6; + __IO uint32_t PCR; + __IO uint32_t LER; + uint32_t RESERVED1[7]; + __IO uint32_t CTCR; +} LPC_PWM_TypeDef; + +/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/ +typedef struct +{ + union { + __I uint8_t RBR; + __O uint8_t THR; + __IO uint8_t DLL; + uint32_t RESERVED0; + }; + union { + __IO uint8_t DLM; + __IO uint32_t IER; + }; + union { + __I uint32_t IIR; + __O uint8_t FCR; + }; + __IO uint8_t LCR; + uint8_t RESERVED1[7]; + __I uint8_t LSR; + uint8_t RESERVED2[7]; + __IO uint8_t SCR; + uint8_t RESERVED3[3]; + __IO uint32_t ACR; + __IO uint8_t ICR; + uint8_t RESERVED4[3]; + __IO uint8_t FDR; + uint8_t RESERVED5[7]; + __IO uint8_t TER; + uint8_t RESERVED6[39]; + __IO uint32_t FIFOLVL; +} LPC_UART_TypeDef; + +typedef struct +{ + union { + __I uint8_t RBR; + __O uint8_t THR; + __IO uint8_t DLL; + uint32_t RESERVED0; + }; + union { + __IO uint8_t DLM; + __IO uint32_t IER; + }; + union { + __I uint32_t IIR; + __O uint8_t FCR; + }; + __IO uint8_t LCR; + uint8_t RESERVED1[7]; + __I uint8_t LSR; + uint8_t RESERVED2[7]; + __IO uint8_t SCR; + uint8_t RESERVED3[3]; + __IO uint32_t ACR; + __IO uint8_t ICR; + uint8_t RESERVED4[3]; + __IO uint8_t FDR; + uint8_t RESERVED5[7]; + __IO uint8_t TER; + uint8_t RESERVED6[39]; + __IO uint32_t FIFOLVL; +} LPC_UART0_TypeDef; + +typedef struct +{ + union { + __I uint8_t RBR; + __O uint8_t THR; + __IO uint8_t DLL; + uint32_t RESERVED0; + }; + union { + __IO uint8_t DLM; + __IO uint32_t IER; + }; + union { + __I uint32_t IIR; + __O uint8_t FCR; + }; + __IO uint8_t LCR; + uint8_t RESERVED1[3]; + __IO uint8_t MCR; + uint8_t RESERVED2[3]; + __I uint8_t LSR; + uint8_t RESERVED3[3]; + __I uint8_t MSR; + uint8_t RESERVED4[3]; + __IO uint8_t SCR; + uint8_t RESERVED5[3]; + __IO uint32_t ACR; + uint32_t RESERVED6; + __IO uint32_t FDR; + uint32_t RESERVED7; + __IO uint8_t TER; + uint8_t RESERVED8[27]; + __IO uint8_t RS485CTRL; + uint8_t RESERVED9[3]; + __IO uint8_t ADRMATCH; + uint8_t RESERVED10[3]; + __IO uint8_t RS485DLY; + uint8_t RESERVED11[3]; + __IO uint32_t FIFOLVL; +} LPC_UART1_TypeDef; + +/*------------- Serial Peripheral Interface (SPI) ----------------------------*/ +typedef struct +{ + __IO uint32_t SPCR; + __I uint32_t SPSR; + __IO uint32_t SPDR; + __IO uint32_t SPCCR; + uint32_t RESERVED0[3]; + __IO uint32_t SPINT; +} LPC_SPI_TypeDef; + +/*------------- Synchronous Serial Communication (SSP) -----------------------*/ +typedef struct +{ + __IO uint32_t CR0; + __IO uint32_t CR1; + __IO uint32_t DR; + __I uint32_t SR; + __IO uint32_t CPSR; + __IO uint32_t IMSC; + __IO uint32_t RIS; + __IO uint32_t MIS; + __IO uint32_t ICR; + __IO uint32_t DMACR; +} LPC_SSP_TypeDef; + +/*------------- Inter-Integrated Circuit (I2C) -------------------------------*/ +typedef struct +{ + __IO uint32_t I2CONSET; + __I uint32_t I2STAT; + __IO uint32_t I2DAT; + __IO uint32_t I2ADR0; + __IO uint32_t I2SCLH; + __IO uint32_t I2SCLL; + __O uint32_t I2CONCLR; + __IO uint32_t MMCTRL; + __IO uint32_t I2ADR1; + __IO uint32_t I2ADR2; + __IO uint32_t I2ADR3; + __I uint32_t I2DATA_BUFFER; + __IO uint32_t I2MASK0; + __IO uint32_t I2MASK1; + __IO uint32_t I2MASK2; + __IO uint32_t I2MASK3; +} LPC_I2C_TypeDef; + +/*------------- Inter IC Sound (I2S) -----------------------------------------*/ +typedef struct +{ + __IO uint32_t I2SDAO; + __IO uint32_t I2SDAI; + __O uint32_t I2STXFIFO; + __I uint32_t I2SRXFIFO; + __I uint32_t I2SSTATE; + __IO uint32_t I2SDMA1; + __IO uint32_t I2SDMA2; + __IO uint32_t I2SIRQ; + __IO uint32_t I2STXRATE; + __IO uint32_t I2SRXRATE; + __IO uint32_t I2STXBITRATE; + __IO uint32_t I2SRXBITRATE; + __IO uint32_t I2STXMODE; + __IO uint32_t I2SRXMODE; +} LPC_I2S_TypeDef; + +/*------------- Repetitive Interrupt Timer (RIT) -----------------------------*/ +typedef struct +{ + __IO uint32_t RICOMPVAL; + __IO uint32_t RIMASK; + __IO uint8_t RICTRL; + uint8_t RESERVED0[3]; + __IO uint32_t RICOUNTER; +} LPC_RIT_TypeDef; + +/*------------- Real-Time Clock (RTC) ----------------------------------------*/ +typedef struct +{ + __IO uint8_t ILR; + uint8_t RESERVED0[7]; + __IO uint8_t CCR; + uint8_t RESERVED1[3]; + __IO uint8_t CIIR; + uint8_t RESERVED2[3]; + __IO uint8_t AMR; + uint8_t RESERVED3[3]; + __I uint32_t CTIME0; + __I uint32_t CTIME1; + __I uint32_t CTIME2; + __IO uint8_t SEC; + uint8_t RESERVED4[3]; + __IO uint8_t MIN; + uint8_t RESERVED5[3]; + __IO uint8_t HOUR; + uint8_t RESERVED6[3]; + __IO uint8_t DOM; + uint8_t RESERVED7[3]; + __IO uint8_t DOW; + uint8_t RESERVED8[3]; + __IO uint16_t DOY; + uint16_t RESERVED9; + __IO uint8_t MONTH; + uint8_t RESERVED10[3]; + __IO uint16_t YEAR; + uint16_t RESERVED11; + __IO uint32_t CALIBRATION; + __IO uint32_t GPREG0; + __IO uint32_t GPREG1; + __IO uint32_t GPREG2; + __IO uint32_t GPREG3; + __IO uint32_t GPREG4; + __IO uint8_t RTC_AUXEN; + uint8_t RESERVED12[3]; + __IO uint8_t RTC_AUX; + uint8_t RESERVED13[3]; + __IO uint8_t ALSEC; + uint8_t RESERVED14[3]; + __IO uint8_t ALMIN; + uint8_t RESERVED15[3]; + __IO uint8_t ALHOUR; + uint8_t RESERVED16[3]; + __IO uint8_t ALDOM; + uint8_t RESERVED17[3]; + __IO uint8_t ALDOW; + uint8_t RESERVED18[3]; + __IO uint16_t ALDOY; + uint16_t RESERVED19; + __IO uint8_t ALMON; + uint8_t RESERVED20[3]; + __IO uint16_t ALYEAR; + uint16_t RESERVED21; +} LPC_RTC_TypeDef; + +/*------------- Watchdog Timer (WDT) -----------------------------------------*/ +typedef struct +{ + __IO uint8_t WDMOD; + uint8_t RESERVED0[3]; + __IO uint32_t WDTC; + __O uint8_t WDFEED; + uint8_t RESERVED1[3]; + __I uint32_t WDTV; + __IO uint32_t WDCLKSEL; +} LPC_WDT_TypeDef; + +/*------------- Analog-to-Digital Converter (ADC) ----------------------------*/ +typedef struct +{ + __IO uint32_t ADCR; + __IO uint32_t ADGDR; + uint32_t RESERVED0; + __IO uint32_t ADINTEN; + __I uint32_t ADDR0; + __I uint32_t ADDR1; + __I uint32_t ADDR2; + __I uint32_t ADDR3; + __I uint32_t ADDR4; + __I uint32_t ADDR5; + __I uint32_t ADDR6; + __I uint32_t ADDR7; + __I uint32_t ADSTAT; + __IO uint32_t ADTRM; +} LPC_ADC_TypeDef; + +/*------------- Digital-to-Analog Converter (DAC) ----------------------------*/ +typedef struct +{ + __IO uint32_t DACR; + __IO uint32_t DACCTRL; + __IO uint16_t DACCNTVAL; +} LPC_DAC_TypeDef; + +/*------------- Motor Control Pulse-Width Modulation (MCPWM) -----------------*/ +typedef struct +{ + __I uint32_t MCCON; + __O uint32_t MCCON_SET; + __O uint32_t MCCON_CLR; + __I uint32_t MCCAPCON; + __O uint32_t MCCAPCON_SET; + __O uint32_t MCCAPCON_CLR; + __IO uint32_t MCTIM0; + __IO uint32_t MCTIM1; + __IO uint32_t MCTIM2; + __IO uint32_t MCPER0; + __IO uint32_t MCPER1; + __IO uint32_t MCPER2; + __IO uint32_t MCPW0; + __IO uint32_t MCPW1; + __IO uint32_t MCPW2; + __IO uint32_t MCDEADTIME; + __IO uint32_t MCCCP; + __IO uint32_t MCCR0; + __IO uint32_t MCCR1; + __IO uint32_t MCCR2; + __I uint32_t MCINTEN; + __O uint32_t MCINTEN_SET; + __O uint32_t MCINTEN_CLR; + __I uint32_t MCCNTCON; + __O uint32_t MCCNTCON_SET; + __O uint32_t MCCNTCON_CLR; + __I uint32_t MCINTFLAG; + __O uint32_t MCINTFLAG_SET; + __O uint32_t MCINTFLAG_CLR; + __O uint32_t MCCAP_CLR; +} LPC_MCPWM_TypeDef; + +/*------------- Quadrature Encoder Interface (QEI) ---------------------------*/ +typedef struct +{ + __O uint32_t QEICON; + __I uint32_t QEISTAT; + __IO uint32_t QEICONF; + __I uint32_t QEIPOS; + __IO uint32_t QEIMAXPOS; + __IO uint32_t CMPOS0; + __IO uint32_t CMPOS1; + __IO uint32_t CMPOS2; + __I uint32_t INXCNT; + __IO uint32_t INXCMP; + __IO uint32_t QEILOAD; + __I uint32_t QEITIME; + __I uint32_t QEIVEL; + __I uint32_t QEICAP; + __IO uint32_t VELCOMP; + __IO uint32_t FILTER; + uint32_t RESERVED0[998]; + __O uint32_t QEIIEC; + __O uint32_t QEIIES; + __I uint32_t QEIINTSTAT; + __I uint32_t QEIIE; + __O uint32_t QEICLR; + __O uint32_t QEISET; +} LPC_QEI_TypeDef; + +/*------------- Controller Area Network (CAN) --------------------------------*/ +typedef struct +{ + __IO uint32_t mask[512]; /* ID Masks */ +} LPC_CANAF_RAM_TypeDef; + +typedef struct /* Acceptance Filter Registers */ +{ + __IO uint32_t AFMR; + __IO uint32_t SFF_sa; + __IO uint32_t SFF_GRP_sa; + __IO uint32_t EFF_sa; + __IO uint32_t EFF_GRP_sa; + __IO uint32_t ENDofTable; + __I uint32_t LUTerrAd; + __I uint32_t LUTerr; + __IO uint32_t FCANIE; + __IO uint32_t FCANIC0; + __IO uint32_t FCANIC1; +} LPC_CANAF_TypeDef; + +typedef struct /* Central Registers */ +{ + __I uint32_t CANTxSR; + __I uint32_t CANRxSR; + __I uint32_t CANMSR; +} LPC_CANCR_TypeDef; + +typedef struct /* Controller Registers */ +{ + __IO uint32_t MOD; + __O uint32_t CMR; + __IO uint32_t GSR; + __I uint32_t ICR; + __IO uint32_t IER; + __IO uint32_t BTR; + __IO uint32_t EWL; + __I uint32_t SR; + __IO uint32_t RFS; + __IO uint32_t RID; + __IO uint32_t RDA; + __IO uint32_t RDB; + __IO uint32_t TFI1; + __IO uint32_t TID1; + __IO uint32_t TDA1; + __IO uint32_t TDB1; + __IO uint32_t TFI2; + __IO uint32_t TID2; + __IO uint32_t TDA2; + __IO uint32_t TDB2; + __IO uint32_t TFI3; + __IO uint32_t TID3; + __IO uint32_t TDA3; + __IO uint32_t TDB3; +} LPC_CAN_TypeDef; + +/*------------- General Purpose Direct Memory Access (GPDMA) -----------------*/ +typedef struct /* Common Registers */ +{ + __I uint32_t DMACIntStat; + __I uint32_t DMACIntTCStat; + __O uint32_t DMACIntTCClear; + __I uint32_t DMACIntErrStat; + __O uint32_t DMACIntErrClr; + __I uint32_t DMACRawIntTCStat; + __I uint32_t DMACRawIntErrStat; + __I uint32_t DMACEnbldChns; + __IO uint32_t DMACSoftBReq; + __IO uint32_t DMACSoftSReq; + __IO uint32_t DMACSoftLBReq; + __IO uint32_t DMACSoftLSReq; + __IO uint32_t DMACConfig; + __IO uint32_t DMACSync; +} LPC_GPDMA_TypeDef; + +typedef struct /* Channel Registers */ +{ + __IO uint32_t DMACCSrcAddr; + __IO uint32_t DMACCDestAddr; + __IO uint32_t DMACCLLI; + __IO uint32_t DMACCControl; + __IO uint32_t DMACCConfig; +} LPC_GPDMACH_TypeDef; + +/*------------- Universal Serial Bus (USB) -----------------------------------*/ +typedef struct +{ + __I uint32_t HcRevision; /* USB Host Registers */ + __IO uint32_t HcControl; + __IO uint32_t HcCommandStatus; + __IO uint32_t HcInterruptStatus; + __IO uint32_t HcInterruptEnable; + __IO uint32_t HcInterruptDisable; + __IO uint32_t HcHCCA; + __I uint32_t HcPeriodCurrentED; + __IO uint32_t HcControlHeadED; + __IO uint32_t HcControlCurrentED; + __IO uint32_t HcBulkHeadED; + __IO uint32_t HcBulkCurrentED; + __I uint32_t HcDoneHead; + __IO uint32_t HcFmInterval; + __I uint32_t HcFmRemaining; + __I uint32_t HcFmNumber; + __IO uint32_t HcPeriodicStart; + __IO uint32_t HcLSTreshold; + __IO uint32_t HcRhDescriptorA; + __IO uint32_t HcRhDescriptorB; + __IO uint32_t HcRhStatus; + __IO uint32_t HcRhPortStatus1; + __IO uint32_t HcRhPortStatus2; + uint32_t RESERVED0[40]; + __I uint32_t Module_ID; + + __I uint32_t OTGIntSt; /* USB On-The-Go Registers */ + __IO uint32_t OTGIntEn; + __O uint32_t OTGIntSet; + __O uint32_t OTGIntClr; + __IO uint32_t OTGStCtrl; + __IO uint32_t OTGTmr; + uint32_t RESERVED1[58]; + + __I uint32_t USBDevIntSt; /* USB Device Interrupt Registers */ + __IO uint32_t USBDevIntEn; + __O uint32_t USBDevIntClr; + __O uint32_t USBDevIntSet; + + __O uint32_t USBCmdCode; /* USB Device SIE Command Registers */ + __I uint32_t USBCmdData; + + __I uint32_t USBRxData; /* USB Device Transfer Registers */ + __O uint32_t USBTxData; + __I uint32_t USBRxPLen; + __O uint32_t USBTxPLen; + __IO uint32_t USBCtrl; + __O uint32_t USBDevIntPri; + + __I uint32_t USBEpIntSt; /* USB Device Endpoint Interrupt Regs */ + __IO uint32_t USBEpIntEn; + __O uint32_t USBEpIntClr; + __O uint32_t USBEpIntSet; + __O uint32_t USBEpIntPri; + + __IO uint32_t USBReEp; /* USB Device Endpoint Realization Reg*/ + __O uint32_t USBEpInd; + __IO uint32_t USBMaxPSize; + + __I uint32_t USBDMARSt; /* USB Device DMA Registers */ + __O uint32_t USBDMARClr; + __O uint32_t USBDMARSet; + uint32_t RESERVED2[9]; + __IO uint32_t USBUDCAH; + __I uint32_t USBEpDMASt; + __O uint32_t USBEpDMAEn; + __O uint32_t USBEpDMADis; + __I uint32_t USBDMAIntSt; + __IO uint32_t USBDMAIntEn; + uint32_t RESERVED3[2]; + __I uint32_t USBEoTIntSt; + __O uint32_t USBEoTIntClr; + __O uint32_t USBEoTIntSet; + __I uint32_t USBNDDRIntSt; + __O uint32_t USBNDDRIntClr; + __O uint32_t USBNDDRIntSet; + __I uint32_t USBSysErrIntSt; + __O uint32_t USBSysErrIntClr; + __O uint32_t USBSysErrIntSet; + uint32_t RESERVED4[15]; + + union { + __I uint32_t I2C_RX; /* USB OTG I2C Registers */ + __O uint32_t I2C_TX; + }; + __I uint32_t I2C_STS; + __IO uint32_t I2C_CTL; + __IO uint32_t I2C_CLKHI; + __O uint32_t I2C_CLKLO; + uint32_t RESERVED5[824]; + + union { + __IO uint32_t USBClkCtrl; /* USB Clock Control Registers */ + __IO uint32_t OTGClkCtrl; + }; + union { + __I uint32_t USBClkSt; + __I uint32_t OTGClkSt; + }; +} LPC_USB_TypeDef; + +/*------------- Ethernet Media Access Controller (EMAC) ----------------------*/ +typedef struct +{ + __IO uint32_t MAC1; /* MAC Registers */ + __IO uint32_t MAC2; + __IO uint32_t IPGT; + __IO uint32_t IPGR; + __IO uint32_t CLRT; + __IO uint32_t MAXF; + __IO uint32_t SUPP; + __IO uint32_t TEST; + __IO uint32_t MCFG; + __IO uint32_t MCMD; + __IO uint32_t MADR; + __O uint32_t MWTD; + __I uint32_t MRDD; + __I uint32_t MIND; + uint32_t RESERVED0[2]; + __IO uint32_t SA0; + __IO uint32_t SA1; + __IO uint32_t SA2; + uint32_t RESERVED1[45]; + __IO uint32_t Command; /* Control Registers */ + __I uint32_t Status; + __IO uint32_t RxDescriptor; + __IO uint32_t RxStatus; + __IO uint32_t RxDescriptorNumber; + __I uint32_t RxProduceIndex; + __IO uint32_t RxConsumeIndex; + __IO uint32_t TxDescriptor; + __IO uint32_t TxStatus; + __IO uint32_t TxDescriptorNumber; + __IO uint32_t TxProduceIndex; + __I uint32_t TxConsumeIndex; + uint32_t RESERVED2[10]; + __I uint32_t TSV0; + __I uint32_t TSV1; + __I uint32_t RSV; + uint32_t RESERVED3[3]; + __IO uint32_t FlowControlCounter; + __I uint32_t FlowControlStatus; + uint32_t RESERVED4[34]; + __IO uint32_t RxFilterCtrl; /* Rx Filter Registers */ + __IO uint32_t RxFilterWoLStatus; + __IO uint32_t RxFilterWoLClear; + uint32_t RESERVED5; + __IO uint32_t HashFilterL; + __IO uint32_t HashFilterH; + uint32_t RESERVED6[882]; + __I uint32_t IntStatus; /* Module Control Registers */ + __IO uint32_t IntEnable; + __O uint32_t IntClear; + __O uint32_t IntSet; + uint32_t RESERVED7; + __IO uint32_t PowerDown; + uint32_t RESERVED8; + __IO uint32_t Module_ID; +} LPC_EMAC_TypeDef; + +#if defined ( __CC_ARM ) +#pragma no_anon_unions +#endif + + +/******************************************************************************/ +/* Peripheral memory map */ +/******************************************************************************/ +/* Base addresses */ +#define LPC_FLASH_BASE (0x00000000UL) +#define LPC_RAM_BASE (0x10000000UL) +#define LPC_GPIO_BASE (0x2009C000UL) +#define LPC_APB0_BASE (0x40000000UL) +#define LPC_APB1_BASE (0x40080000UL) +#define LPC_AHB_BASE (0x50000000UL) +#define LPC_CM3_BASE (0xE0000000UL) + +/* APB0 peripherals */ +#define LPC_WDT_BASE (LPC_APB0_BASE + 0x00000) +#define LPC_TIM0_BASE (LPC_APB0_BASE + 0x04000) +#define LPC_TIM1_BASE (LPC_APB0_BASE + 0x08000) +#define LPC_UART0_BASE (LPC_APB0_BASE + 0x0C000) +#define LPC_UART1_BASE (LPC_APB0_BASE + 0x10000) +#define LPC_PWM1_BASE (LPC_APB0_BASE + 0x18000) +#define LPC_I2C0_BASE (LPC_APB0_BASE + 0x1C000) +#define LPC_SPI_BASE (LPC_APB0_BASE + 0x20000) +#define LPC_RTC_BASE (LPC_APB0_BASE + 0x24000) +#define LPC_GPIOINT_BASE (LPC_APB0_BASE + 0x28080) +#define LPC_PINCON_BASE (LPC_APB0_BASE + 0x2C000) +#define LPC_SSP1_BASE (LPC_APB0_BASE + 0x30000) +#define LPC_ADC_BASE (LPC_APB0_BASE + 0x34000) +#define LPC_CANAF_RAM_BASE (LPC_APB0_BASE + 0x38000) +#define LPC_CANAF_BASE (LPC_APB0_BASE + 0x3C000) +#define LPC_CANCR_BASE (LPC_APB0_BASE + 0x40000) +#define LPC_CAN1_BASE (LPC_APB0_BASE + 0x44000) +#define LPC_CAN2_BASE (LPC_APB0_BASE + 0x48000) +#define LPC_I2C1_BASE (LPC_APB0_BASE + 0x5C000) + +/* APB1 peripherals */ +#define LPC_SSP0_BASE (LPC_APB1_BASE + 0x08000) +#define LPC_DAC_BASE (LPC_APB1_BASE + 0x0C000) +#define LPC_TIM2_BASE (LPC_APB1_BASE + 0x10000) +#define LPC_TIM3_BASE (LPC_APB1_BASE + 0x14000) +#define LPC_UART2_BASE (LPC_APB1_BASE + 0x18000) +#define LPC_UART3_BASE (LPC_APB1_BASE + 0x1C000) +#define LPC_I2C2_BASE (LPC_APB1_BASE + 0x20000) +#define LPC_I2S_BASE (LPC_APB1_BASE + 0x28000) +#define LPC_RIT_BASE (LPC_APB1_BASE + 0x30000) +#define LPC_MCPWM_BASE (LPC_APB1_BASE + 0x38000) +#define LPC_QEI_BASE (LPC_APB1_BASE + 0x3C000) +#define LPC_SC_BASE (LPC_APB1_BASE + 0x7C000) + +/* AHB peripherals */ +#define LPC_EMAC_BASE (LPC_AHB_BASE + 0x00000) +#define LPC_GPDMA_BASE (LPC_AHB_BASE + 0x04000) +#define LPC_GPDMACH0_BASE (LPC_AHB_BASE + 0x04100) +#define LPC_GPDMACH1_BASE (LPC_AHB_BASE + 0x04120) +#define LPC_GPDMACH2_BASE (LPC_AHB_BASE + 0x04140) +#define LPC_GPDMACH3_BASE (LPC_AHB_BASE + 0x04160) +#define LPC_GPDMACH4_BASE (LPC_AHB_BASE + 0x04180) +#define LPC_GPDMACH5_BASE (LPC_AHB_BASE + 0x041A0) +#define LPC_GPDMACH6_BASE (LPC_AHB_BASE + 0x041C0) +#define LPC_GPDMACH7_BASE (LPC_AHB_BASE + 0x041E0) +#define LPC_USB_BASE (LPC_AHB_BASE + 0x0C000) + +/* GPIOs */ +#define LPC_GPIO0_BASE (LPC_GPIO_BASE + 0x00000) +#define LPC_GPIO1_BASE (LPC_GPIO_BASE + 0x00020) +#define LPC_GPIO2_BASE (LPC_GPIO_BASE + 0x00040) +#define LPC_GPIO3_BASE (LPC_GPIO_BASE + 0x00060) +#define LPC_GPIO4_BASE (LPC_GPIO_BASE + 0x00080) + + +/******************************************************************************/ +/* Peripheral declaration */ +/******************************************************************************/ +#define LPC_SC ((LPC_SC_TypeDef *) LPC_SC_BASE ) +#define LPC_GPIO0 ((LPC_GPIO_TypeDef *) LPC_GPIO0_BASE ) +#define LPC_GPIO1 ((LPC_GPIO_TypeDef *) LPC_GPIO1_BASE ) +#define LPC_GPIO2 ((LPC_GPIO_TypeDef *) LPC_GPIO2_BASE ) +#define LPC_GPIO3 ((LPC_GPIO_TypeDef *) LPC_GPIO3_BASE ) +#define LPC_GPIO4 ((LPC_GPIO_TypeDef *) LPC_GPIO4_BASE ) +#define LPC_WDT ((LPC_WDT_TypeDef *) LPC_WDT_BASE ) +#define LPC_TIM0 ((LPC_TIM_TypeDef *) LPC_TIM0_BASE ) +#define LPC_TIM1 ((LPC_TIM_TypeDef *) LPC_TIM1_BASE ) +#define LPC_TIM2 ((LPC_TIM_TypeDef *) LPC_TIM2_BASE ) +#define LPC_TIM3 ((LPC_TIM_TypeDef *) LPC_TIM3_BASE ) +#define LPC_RIT ((LPC_RIT_TypeDef *) LPC_RIT_BASE ) +#define LPC_UART0 ((LPC_UART0_TypeDef *) LPC_UART0_BASE ) +#define LPC_UART1 ((LPC_UART1_TypeDef *) LPC_UART1_BASE ) +#define LPC_UART2 ((LPC_UART_TypeDef *) LPC_UART2_BASE ) +#define LPC_UART3 ((LPC_UART_TypeDef *) LPC_UART3_BASE ) +#define LPC_PWM1 ((LPC_PWM_TypeDef *) LPC_PWM1_BASE ) +#define LPC_I2C0 ((LPC_I2C_TypeDef *) LPC_I2C0_BASE ) +#define LPC_I2C1 ((LPC_I2C_TypeDef *) LPC_I2C1_BASE ) +#define LPC_I2C2 ((LPC_I2C_TypeDef *) LPC_I2C2_BASE ) +#define LPC_I2S ((LPC_I2S_TypeDef *) LPC_I2S_BASE ) +#define LPC_SPI ((LPC_SPI_TypeDef *) LPC_SPI_BASE ) +#define LPC_RTC ((LPC_RTC_TypeDef *) LPC_RTC_BASE ) +#define LPC_GPIOINT ((LPC_GPIOINT_TypeDef *) LPC_GPIOINT_BASE ) +#define LPC_PINCON ((LPC_PINCON_TypeDef *) LPC_PINCON_BASE ) +#define LPC_SSP0 ((LPC_SSP_TypeDef *) LPC_SSP0_BASE ) +#define LPC_SSP1 ((LPC_SSP_TypeDef *) LPC_SSP1_BASE ) +#define LPC_ADC ((LPC_ADC_TypeDef *) LPC_ADC_BASE ) +#define LPC_DAC ((LPC_DAC_TypeDef *) LPC_DAC_BASE ) +#define LPC_CANAF_RAM ((LPC_CANAF_RAM_TypeDef *) LPC_CANAF_RAM_BASE) +#define LPC_CANAF ((LPC_CANAF_TypeDef *) LPC_CANAF_BASE ) +#define LPC_CANCR ((LPC_CANCR_TypeDef *) LPC_CANCR_BASE ) +#define LPC_CAN1 ((LPC_CAN_TypeDef *) LPC_CAN1_BASE ) +#define LPC_CAN2 ((LPC_CAN_TypeDef *) LPC_CAN2_BASE ) +#define LPC_MCPWM ((LPC_MCPWM_TypeDef *) LPC_MCPWM_BASE ) +#define LPC_QEI ((LPC_QEI_TypeDef *) LPC_QEI_BASE ) +#define LPC_EMAC ((LPC_EMAC_TypeDef *) LPC_EMAC_BASE ) +#define LPC_GPDMA ((LPC_GPDMA_TypeDef *) LPC_GPDMA_BASE ) +#define LPC_GPDMACH0 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH0_BASE ) +#define LPC_GPDMACH1 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH1_BASE ) +#define LPC_GPDMACH2 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH2_BASE ) +#define LPC_GPDMACH3 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH3_BASE ) +#define LPC_GPDMACH4 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH4_BASE ) +#define LPC_GPDMACH5 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH5_BASE ) +#define LPC_GPDMACH6 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH6_BASE ) +#define LPC_GPDMACH7 ((LPC_GPDMACH_TypeDef *) LPC_GPDMACH7_BASE ) +#define LPC_USB ((LPC_USB_TypeDef *) LPC_USB_BASE ) + +#endif // __LPC17xx_H__ diff --git a/platforms/lpc17xx/drivers/lpc17xx_uart.c b/platforms/lpc17xx/drivers/lpc17xx_uart.c new file mode 100644 index 0000000..3a0202f --- /dev/null +++ b/platforms/lpc17xx/drivers/lpc17xx_uart.c @@ -0,0 +1,166 @@ +/**************************************************************************//** + * @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 +#include +#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 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 ------------------------------ */ diff --git a/platforms/lpc17xx/drivers/lpc17xx_uart.h b/platforms/lpc17xx/drivers/lpc17xx_uart.h new file mode 100644 index 0000000..9e7f045 --- /dev/null +++ b/platforms/lpc17xx/drivers/lpc17xx_uart.h @@ -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 + +/* external functions */ +void LPC17xx_UART_PutChar (uint8_t); +uint8_t LPC17xx_UART_GetChar (void); +void LPC17xx_UART_Init(uint32_t baudrate); +//void LPC17xx_UART_Printf (const uint8_t *format, ...); +void LPC17xx_UART_PutString (uint8_t *str) ; + +#endif // __LPC17xx_UART_H_ + +/* --------------------------------- End Of File ------------------------------ */ diff --git a/platforms/lpc17xx/main.c b/platforms/lpc17xx/main.c new file mode 100644 index 0000000..755f965 --- /dev/null +++ b/platforms/lpc17xx/main.c @@ -0,0 +1,116 @@ +/* + * 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 "LPC17xx.h" +#include "drivers/lpc17xx_uart.h" +#include +#include "modules.h" +#include "atom.h" +#include "tests/atomtests.h" + +// for mbed board +#define LED1_GPIO (1 << 18) +#define LED2_GPIO (1 << 20) +#define LED3_GPIO (1 << 21) +#define LED4_GPIO (1 << 23) + +#define LED_GET(led) (LPC_GPIO1->FIOSET & led) +#define LED_SET(led, on) { if (on) LPC_GPIO1->FIOSET = led ; else LPC_GPIO1->FIOCLR = led ; } +#define LED_TOGGLE(led) LED_SET(led, !LED_GET(led)) + + +#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 ; + static volatile unsigned int i ; + 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) { + LED_TOGGLE(LED1_GPIO) ; + for (i=0; i<1000000; i++) ; + } + +} + +int main(void) { + + static volatile unsigned int i ; + + // mbed board + LPC_GPIO1->FIODIR |= LED1_GPIO | LED2_GPIO | LED3_GPIO | LED4_GPIO ; + + 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) { + + LED_TOGGLE(LED1_GPIO) ; + for (i=0; i<1000000; i++) ; + + + } + return 0 ; +} + diff --git a/platforms/lpc17xx/modules.c b/platforms/lpc17xx/modules.c new file mode 100644 index 0000000..7901bcd --- /dev/null +++ b/platforms/lpc17xx/modules.c @@ -0,0 +1,178 @@ +/* + * 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 +#include +#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() ; + vsnprintf ((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; jSHCSR); + + dbg_mem_dump_40 (hardfault_args, 0x40) ; + + while (1); + +} + diff --git a/platforms/lpc17xx/modules.h b/platforms/lpc17xx/modules.h new file mode 100644 index 0000000..e947d38 --- /dev/null +++ b/platforms/lpc17xx/modules.h @@ -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__ */ diff --git a/platforms/lpc17xx/startup.c b/platforms/lpc17xx/startup.c new file mode 100644 index 0000000..87a90a5 --- /dev/null +++ b/platforms/lpc17xx/startup.c @@ -0,0 +1,295 @@ +/**************************************************************************//** + * @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); +//***************************************************************************** +// +// 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) ; + +} diff --git a/platforms/lpc17xx/system.ld b/platforms/lpc17xx/system.ld new file mode 100644 index 0000000..0112192 --- /dev/null +++ b/platforms/lpc17xx/system.ld @@ -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); +} From 8d62300d4144b5059dfa582ed6d479c326ac10e8 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 23 Oct 2012 14:45:12 +0200 Subject: [PATCH 23/28] updates --- platforms/lpc17xx/README | 16 +++ platforms/qemu_integratorcp/modules.h | 40 +++--- platforms/qemu_lm3s/Makefile | 1 + platforms/qemu_lm3s/modules.h | 107 ++++++++-------- platforms/rules.mk | 2 + ports/arm/types.h | 4 + ports/cortex_m/atomport_s.S | 4 + ports/cortex_m/types.h | 6 + tests/stress1.c | 176 ++++++++++++++++++++++++++ tests/stress1.h | 18 +++ 10 files changed, 296 insertions(+), 78 deletions(-) create mode 100644 platforms/lpc17xx/README create mode 100644 tests/stress1.c create mode 100644 tests/stress1.h diff --git a/platforms/lpc17xx/README b/platforms/lpc17xx/README new file mode 100644 index 0000000..d23d34f --- /dev/null +++ b/platforms/lpc17xx/README @@ -0,0 +1,16 @@ +--------------------------------------------------------------------------- + +Library: Atomthreads NXP LPC17xx Platform. +Author: Natie van Rooyen +License: BSD Revised + +--------------------------------------------------------------------------- + +NXP LPC17xx Platform + +The "lpc17xx" platform contains sources for building a sample Atomthreads +application for the NXP LPC17xx platform. + +The platform was tested on the mbed NXP LPC1768 (http://www.mbed.org). + + diff --git a/platforms/qemu_integratorcp/modules.h b/platforms/qemu_integratorcp/modules.h index a94140a..538dec6 100644 --- a/platforms/qemu_integratorcp/modules.h +++ b/platforms/qemu_integratorcp/modules.h @@ -36,23 +36,19 @@ #include "atomport.h" -typedef volatile unsigned int REG_DWORD ; -typedef volatile unsigned short REG_WORD ; -typedef volatile unsigned char REG_BYTE ; - // ***************************************************************************** // INTEGRATORCP TIMER // ***************************************************************************** typedef struct ICP_TIMER_S { // offset read/write word size reset Description - REG_DWORD LOAD ; // 0x0000 Read/write 32 0x00000000 Load value for Timer - REG_DWORD VALUE ; // 0x0004 Read 32 0xFFFFFFFF The current value for Timer - REG_BYTE CONTROL ; // 0x0008 Read/write 8 0x20 Timer control register - REG_DWORD INTCLR ; // 0x000C Write - - Timer interrupt clear - REG_DWORD RIS ; // 0x0010 Read 1 0x0 Timer raw interrupt status - REG_DWORD MIS ; // 0x0014 Read 1 0x0 Timer masked interrupt status - REG_DWORD BGLOAD ; // 0x0018 Read/write 32 0x00000000 Background load value for Timer + __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 ; @@ -82,17 +78,17 @@ typedef struct ICP_TIMER_S { // ***************************************************************************** typedef struct ICP_PIC_S { // offset read/write word size reset Description - REG_DWORD IRQ_STATUS ; // 0x0000 Read 22 IRQ gated interrupt status - REG_DWORD IRQ_RAWSTAT ; // 0x0004 Read 22 IRQ raw interrupt status - REG_DWORD IRQ_ENABLESET ; // 0x0008 Read/write 22 IRQ enable set - REG_DWORD IRQ_ENABLECLR ; // 0x000C Write 22 IRQ enable clear - REG_DWORD INT_SOFTSET ; // 0x0010 Read/write 16 Software interrupt set - REG_DWORD INT_SOFTCLR ; // 0x0014 Write 16 Software interrupt clear - REG_DWORD RESERVED[2] ; // 0x0018 - REG_DWORD FIQ_STATUS ; // 0x0020 Read 22 FIQ gated interrupt status - REG_DWORD FIQ_RAWSTAT ; // 0x0024 Read 22 FIQ raw interrupt status - REG_DWORD FIQ_ENABLESET ; // 0x0028 Read/write 22 FIQ enable set - REG_DWORD FIQ_ENABLECLR ; // 0x002C Write-only 22 FIQ enable clear + __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 ; diff --git a/platforms/qemu_lm3s/Makefile b/platforms/qemu_lm3s/Makefile index dc9c117..fbdb94f 100644 --- a/platforms/qemu_lm3s/Makefile +++ b/platforms/qemu_lm3s/Makefile @@ -87,6 +87,7 @@ all_tests: fail_tests: make run_test "TEST_NAME=mutex4" + make run_test "TEST_NAME=timer4" make run_test "TEST_NAME=sem4" diff --git a/platforms/qemu_lm3s/modules.h b/platforms/qemu_lm3s/modules.h index 5a074b4..cc0d5f0 100644 --- a/platforms/qemu_lm3s/modules.h +++ b/platforms/qemu_lm3s/modules.h @@ -36,36 +36,31 @@ #include "atomport.h" -typedef volatile unsigned int REG_DWORD ; -typedef volatile unsigned short REG_WORD ; -typedef volatile unsigned char REG_BYTE ; - - // ***************************************************************************** // The Stellaris General-Purpose Timer Module (GPTM) // ***************************************************************************** typedef struct GPTM_TIMER_S { // offset read/write reset Description - REG_DWORD CFG ; // 0x000 R/W 0x00000000 GPTM Configuration 345 - REG_DWORD TAMR ; // 0x004 R/W 0x00000000 GPTM TimerA Mode 346 - REG_DWORD TBMR ; // 0x008 R/W 0x00000000 GPTM TimerB Mode 348 - REG_DWORD CTL ; // 0x00C R/W 0x00000000 GPTM Control 350 - REG_DWORD Reserved[2] ; // 0x010 - REG_DWORD IMR ; // 0x018 R/W 0x00000000 GPTM Interrupt Mask 353 - REG_DWORD RIS ; // 0x01C RO 0x00000000 GPTM Raw Interrupt Status 355 - REG_DWORD MIS ; // 0x020 RO 0x00000000 GPTM Masked Interrupt Status 356 - REG_DWORD ICR ; // 0x024 W1C 0x00000000 GPTM Interrupt Clear 357 - REG_DWORD TAILR ; // 0x028 R/W 0xFFFFFFFF GPTM TimerA Interval Load 359 - REG_DWORD TBILR ; // 0x02C R/W 0x0000FFFF GPTM TimerB Interval Load 360 - REG_DWORD TAMATCHR ; // 0x030 R/W 0xFFFFFFFF GPTM TimerA Match 361 - REG_DWORD TBMATCHR ; // 0x034 R/W 0x0000FFFF GPTM TimerB Match 362 - REG_DWORD TAPR ; // 0x038 R/W 0x00000000 GPTM TimerA Prescale 363 - REG_DWORD TBPR ; // 0x03C R/W 0x00000000 GPTM TimerB Prescale 364 - REG_DWORD TAPMR ; // 0x040 R/W 0x00000000 GPTM TimerA Prescale Match 365 - REG_DWORD TBPMR ; // 0x044 R/W 0x00000000 GPTM TimerB Prescale Match 366 - REG_DWORD TAR ; // 0x048 RO 0xFFFFFFFF GPTM TimerA 367 - REG_DWORD TBR ; // 0x04C RO 0x0000FFFF GPTM TimerB 368 + __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 ; @@ -89,7 +84,7 @@ typedef struct GPTM_TIMER_S { #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 @@ -106,7 +101,7 @@ typedef struct GPTM_TIMER_S { #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 @@ -119,14 +114,14 @@ typedef struct GPTM_TIMER_S { // ***************************************************************************** typedef struct SYSTICK_S { - REG_DWORD Res0[1] ; // 0xE000E000 - REG_DWORD ICT ; // 0xE000E004 - REG_DWORD Res1[2] ; // 0xE000E008 - REG_DWORD STCTRL ; // 0xE000E010 - REG_DWORD STRELOAD ; // 0xE000E014 - REG_DWORD STCURRENT; // 0xE000E018 - REG_DWORD STCALIB ; // 0xE000E01C - REG_DWORD Res2[56] ; // 0xE000E020 + 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 ; @@ -145,18 +140,18 @@ typedef struct SYSTICK_S { // ***************************************************************************** typedef struct NVIC_S { - REG_DWORD ISER[2] ; // 0xE000E100 - REG_DWORD Res3[30] ; // 0xE000E120 - REG_DWORD ICER[2] ; // 0xE000E180 - REG_DWORD Res4[30] ; // 0xE000E1A0 - REG_DWORD ISPR[2] ; // 0xE000E200 - REG_DWORD Res5[30] ; // 0xE000E220 - REG_DWORD ICPR[2] ; // 0xE000E280 - REG_DWORD Res6[30] ; // 0xE000E2A0 - REG_DWORD IABR[2] ; // 0xE000E300 - REG_DWORD Res7[64] ; // 0xE000E320 - REG_DWORD IPR[2] ; // 0xE000E400 - // REG_DWORD Res7[515] ; // 0xE000E4F4 + __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 ; @@ -176,17 +171,17 @@ typedef struct NVIC_S { // ***************************************************************************** typedef struct SCB_S { - REG_DWORD CPUID ; // 0xE000ED00 - REG_DWORD ICSR ; // 0xE000ED04 - REG_DWORD VTOR ; // 0xE000ED08 - REG_DWORD AIRCR ; // 0xE000ED0C - REG_DWORD SCR ; // 0xE000ED10 - REG_DWORD CCR ; // 0xE000ED14 + __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 - REG_DWORD SYS_PRIO[3] ; // 0xE000ED18 - REG_DWORD SYSHNDCTRL ; // 0xE000ED24 - //REG_DWORD FAULTSTAT ; // 0xE000ED28 - //REG_DWORD HFAULTSTAT ; // 0xE000ED2C + __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 ; diff --git a/platforms/rules.mk b/platforms/rules.mk index 7f0f767..2d2210d 100644 --- a/platforms/rules.mk +++ b/platforms/rules.mk @@ -20,6 +20,8 @@ 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) diff --git a/ports/arm/types.h b/ports/arm/types.h index c07e295..d06e82f 100644 --- a/ports/arm/types.h +++ b/ports/arm/types.h @@ -48,6 +48,10 @@ typedef char int8_t ; #define INLINE __inline #endif +/* 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 */ #endif /* __TYPES_H__ */ diff --git a/ports/cortex_m/atomport_s.S b/ports/cortex_m/atomport_s.S index 2e25d93..0300234 100644 --- a/ports/cortex_m/atomport_s.S +++ b/ports/cortex_m/atomport_s.S @@ -45,7 +45,11 @@ .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 diff --git a/ports/cortex_m/types.h b/ports/cortex_m/types.h index c07e295..e6f927d 100644 --- a/ports/cortex_m/types.h +++ b/ports/cortex_m/types.h @@ -30,6 +30,7 @@ #ifndef __TYPES_H__ #define __TYPES_H__ +#ifndef _STDINT_H typedef unsigned int uintptr_t ; typedef int intptr_t ; typedef unsigned long long uint64_t ; @@ -39,6 +40,7 @@ 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) @@ -48,6 +50,10 @@ typedef char int8_t ; #define INLINE __inline #endif +/* 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 */ #endif /* __TYPES_H__ */ diff --git a/tests/stress1.c b/tests/stress1.c new file mode 100644 index 0000000..c27b01e --- /dev/null +++ b/tests/stress1.c @@ -0,0 +1,176 @@ +#include +#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"), parm, counter, (unsigned int)time) ; + ATOMLOG (_STR("------------------------------\r\n")) ; + //CRITICAL_END(); + + for (i=0; i MAX_TEST_THREADS) { + thread_count = MAX_TEST_THREADS ; + } + + ATOMLOG (_STR("\r\natomthreads_stress_test %.3d threads\r\n"), 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() ; +} diff --git a/tests/stress1.h b/tests/stress1.h new file mode 100644 index 0000000..303e867 --- /dev/null +++ b/tests/stress1.h @@ -0,0 +1,18 @@ +#ifndef __STRESS1_H__ +#define __STRESS1_H__ + +#include "types.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__ */ + From d9f1f8389f62171356233d06632da9b25a4a5a55 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 23 Oct 2012 14:53:32 +0200 Subject: [PATCH 24/28] atomvm updates --- ports/atomvm/atomvm.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c index f6ff3a9..b48363f 100644 --- a/ports/atomvm/atomvm.c +++ b/ports/atomvm/atomvm.c @@ -182,12 +182,11 @@ static DWORD WINAPI vm_thread (LPVOID lpParameter) ; * \ingroup atomvm * \b atomvmCtrlCreate * -* This is an atomvm controll function used by a controlling thread -* and must not be called from the atom virtual machine. +* This is an atomvm controll function used by a controlling thread. * * Initializes the virtual machine. * -* @param[out] atomvm Handle to the virtual machine created. +* @param[out] atomvm Handle to the virtual machine to create. * * @return Zero on failure. */ @@ -282,7 +281,8 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) #if (_WIN32_WINNT >= 0x0600) /* This is used for multi processor machines to ensure the thread - is stopped before executing the next instruction. */ + 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)) ; @@ -358,7 +358,7 @@ atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) * Closes the virtual machine and release all memory and handles created * in atomvmCtrlCreate. * -* ToDo: this function was never tested. +* ToDo: more testing. * * @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate. * @@ -447,7 +447,6 @@ getAtomvm (void) ATOMVM_ASSERT(patomvm , _T("TlsGetValue failed")) ; return patomvm ; - } /** @@ -504,7 +503,6 @@ atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) SwitchToThread() ; } SetEvent (patomvm->atomvm_int) ; - } @@ -558,7 +556,6 @@ atomvmContextCreate (HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t e ATOMVM_CALLBACK_CONTEXT context_init ; context_init.pcontext = new_context ; - new_context->interrupt_mask = 1 ; res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ; @@ -592,16 +589,14 @@ callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback) uint32_t res1 = 1 ; uint32_t res2 ; PATOMVM_CALLBACK_CONTEXT_SWITCH context_switch = (PATOMVM_CALLBACK_CONTEXT_SWITCH)callback ; - CONTEXT* p_old_context = &context_switch->p_old_context->context ; - CONTEXT* p_new_context = &context_switch->p_new_context->context ; - if (p_old_context) { - res1 = GetThreadContext (patomvm->vm_thread, p_old_context) ; + if (context_switch->p_old_context) { + res1 = GetThreadContext (patomvm->vm_thread, &context_switch->p_old_context->context) ; ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ; } - InterlockedExchange ((volatile uint32_t*)&patomvm->current_context, (uint32_t)p_new_context) ; - res2 = SetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ; + 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 ; From 8cdd707b413e4202028049b4c56b86f26cbb5013 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 23 Oct 2012 16:58:10 +0200 Subject: [PATCH 25/28] Updated README for lpx17xx --- platforms/lpc17xx/README | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/platforms/lpc17xx/README b/platforms/lpc17xx/README index d23d34f..d8055a3 100644 --- a/platforms/lpc17xx/README +++ b/platforms/lpc17xx/README @@ -8,9 +8,10 @@ License: BSD Revised NXP LPC17xx Platform -The "lpc17xx" platform contains sources for building a sample Atomthreads -application for the NXP LPC17xx platform. - -The platform was tested on the mbed NXP LPC1768 (http://www.mbed.org). +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) +and the sources were compiled on Ubuntu 12.0.4 with the GNU ARM tool chain +using Newlib. From 9d18dafd72085b5deefd39422312787673a07497 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Tue, 23 Oct 2012 17:45:25 +0200 Subject: [PATCH 26/28] Atomvm SWI functionality added. --- ports/atomvm/atomport.c | 4 +-- ports/atomvm/atomport.h | 4 +-- ports/atomvm/atomvm.c | 64 ++++++++++++++++++++++++++++++++++++---- ports/atomvm/atomvm.h | 5 ++-- ports/atomvm/msvc/main.c | 6 ++-- 5 files changed, 68 insertions(+), 15 deletions(-) diff --git a/ports/atomvm/atomport.c b/ports/atomvm/atomport.c index a9bc46f..55d6d69 100644 --- a/ports/atomvm/atomport.c +++ b/ports/atomvm/atomport.c @@ -51,7 +51,7 @@ static HANDLE cntrl_thread ; * */ void -atomvmRun () +atomvmRun (void) { atomvmCtrlCreate (&the_atomvm) ; cntrl_thread = CreateThread (NULL, 0, cntrl_thread_proc, (uint32_t*)the_atomvm, CREATE_SUSPENDED, NULL) ; @@ -147,7 +147,7 @@ archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) * System timer tick interrupt handler. * */ -void archTimerTickIrqHandler () +void archTimerTickIrqHandler (void) { atomIntEnter(); diff --git a/ports/atomvm/atomport.h b/ports/atomvm/atomport.h index 84edb64..0edbf3b 100644 --- a/ports/atomvm/atomport.h +++ b/ports/atomvm/atomport.h @@ -53,8 +53,8 @@ #define ATOM_TLS HATOMVM_CONTEXT context ; /* Function prototypes */ -extern void atomvmRun () ; -extern void archTimerTickIrqHandler () ; +extern void atomvmRun (void) ; +extern void archTimerTickIrqHandler (void) ; /* The instance of the atomvm for this port */ extern HATOMVM the_atomvm ; diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c index b48363f..960b13e 100644 --- a/ports/atomvm/atomvm.c +++ b/ports/atomvm/atomvm.c @@ -119,6 +119,18 @@ typedef struct ATOMVM_CALLBACK_CONTEXT_SWITCH_S { } 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 { @@ -194,7 +206,6 @@ uint32_t atomvmCtrlCreate (HATOMVM *atomvm) { PATOMVM patomvm = 0 ; - int32_t i ; patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ; @@ -494,12 +505,12 @@ atomvmInterruptMask (uint32_t mask) * @return None */ void -atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) +atomvmCtrlIntRequest (HATOMVM atomvm, void (*isr) (void)) { PATOMVM patomvm = (PATOMVM) atomvm ; WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; - while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) != 0) { + while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, (uint32_t)isr, 0) != 0) { SwitchToThread() ; } SetEvent (patomvm->atomvm_int) ; @@ -720,7 +731,7 @@ atomvmGetVmId (void) * @return Zero on failure, try to call GetLastError(). */ uint32_t -callbackInterruptWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) +callbackIntWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) { WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; return WaitForSingleObject (patomvm->atomvm_int, INFINITE) == WAIT_OBJECT_0 ; @@ -739,12 +750,53 @@ callbackInterruptWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) * @return void. */ void -atomvmInterruptWait (void) +atomvmIntWait (void) { PATOMVM patomvm = getAtomvm () ; ATOMVM_CALLBACK callback ; - invokeCallback (patomvm, callbackInterruptWait, (PATOMVM_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) ; } diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h index 24e2a99..b4ae55d 100644 --- a/ports/atomvm/atomvm.h +++ b/ports/atomvm/atomvm.h @@ -80,7 +80,7 @@ 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, uintptr_t isr) ; +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 @@ -91,7 +91,8 @@ extern uint32_t atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMV extern void atomvmContextDesrtroy (HATOMVM_CONTEXT context) ; extern void atomvmWriteThreadId (uint32_t thread_id) ; extern uint32_t atomvmReadThreadId (void) ; -extern void atomvmInterruptWait (void) ; +extern void atomvmIntWait (void) ; +extern void atomvmIntRequest (void (*isr) (void)) ; extern uint32_t atomvmGetVmId (void) ; diff --git a/ports/atomvm/msvc/main.c b/ports/atomvm/msvc/main.c index 28f78a8..7d0b4bf 100644 --- a/ports/atomvm/msvc/main.c +++ b/ports/atomvm/msvc/main.c @@ -213,7 +213,7 @@ __atomvmClose () void -test_isr () +test_isr (void) { static int i = 0 ; test_isr_count++ ; @@ -232,7 +232,7 @@ isr_thread_proc (LPVOID lpParameter) int x ; int y = rand() % 100 ; while (1) { - atomvmCtrlIntRequest (the_atomvm, (uintptr_t)test_isr) ; + atomvmCtrlIntRequest (the_atomvm, test_isr) ; if (i++==y) { x = rand() % 50 ; Sleep (x) ; @@ -264,7 +264,7 @@ main () while (1) { Sleep(1) ; - atomvmCtrlIntRequest (the_atomvm, (uintptr_t)archTimerTickIrqHandler) ; + atomvmCtrlIntRequest (the_atomvm, archTimerTickIrqHandler) ; } } From 356685005a86aa97bb57e4fb5e015a4b6451d823 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Thu, 25 Oct 2012 10:41:23 +0200 Subject: [PATCH 27/28] LPC17xx platform for Cortex M port --- platforms/lpc17xx/Makefile | 7 ++- platforms/lpc17xx/README | 13 +++-- platforms/lpc17xx/drivers/lpc17xx_uart.c | 13 +++++ platforms/lpc17xx/drivers/lpc17xx_uart.h | 2 +- platforms/lpc17xx/main.c | 66 +++++++++++++----------- platforms/lpc17xx/modules.c | 3 +- platforms/lpc17xx/startup.c | 2 + ports/cortex_m/atomport.h | 4 ++ ports/cortex_m/types.h | 6 +++ 9 files changed, 77 insertions(+), 39 deletions(-) diff --git a/platforms/lpc17xx/Makefile b/platforms/lpc17xx/Makefile index 172df5a..8975de9 100644 --- a/platforms/lpc17xx/Makefile +++ b/platforms/lpc17xx/Makefile @@ -8,8 +8,6 @@ ifeq ($(TEST_NAME),) TEST_NAME = kern1 endif - - CC = arm-none-eabi-gcc LN = arm-none-eabi-gcc AS = arm-none-eabi-gcc @@ -18,7 +16,7 @@ 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)"' +CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' -DBOARD_MBED_LP1768 ADEFS := $(ADEFS) -D__thumb2__ -DARM_RDI_MONITOR LLIBS := $(LLIBS) @@ -39,7 +37,8 @@ ASMS := $(ASMS) \ INCLUDES := $(INCLUDES) \ - -I./CMSISv2p00_LPC17xx/inc \ + -I$(ATOMTHREADS)/platforms/lpc17xx/CMSISv2p00_LPC17xx/inc \ + -I$(ATOMTHREADS)/platforms/lpc17xx \ -I$(ATOMTHREADS) include $(ATOMTHREADS)/ports/cortex_m/Makefile diff --git a/platforms/lpc17xx/README b/platforms/lpc17xx/README index d8055a3..8f69ee8 100644 --- a/platforms/lpc17xx/README +++ b/platforms/lpc17xx/README @@ -11,7 +11,14 @@ 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) -and the sources were compiled on Ubuntu 12.0.4 with the GNU ARM tool chain -using Newlib. +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. diff --git a/platforms/lpc17xx/drivers/lpc17xx_uart.c b/platforms/lpc17xx/drivers/lpc17xx_uart.c index 3a0202f..fca71ec 100644 --- a/platforms/lpc17xx/drivers/lpc17xx_uart.c +++ b/platforms/lpc17xx/drivers/lpc17xx_uart.c @@ -143,6 +143,19 @@ void LPC17xx_UART_PutString (uint8_t *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. * diff --git a/platforms/lpc17xx/drivers/lpc17xx_uart.h b/platforms/lpc17xx/drivers/lpc17xx_uart.h index 9e7f045..400a089 100644 --- a/platforms/lpc17xx/drivers/lpc17xx_uart.h +++ b/platforms/lpc17xx/drivers/lpc17xx_uart.h @@ -29,8 +29,8 @@ void LPC17xx_UART_PutChar (uint8_t); uint8_t LPC17xx_UART_GetChar (void); void LPC17xx_UART_Init(uint32_t baudrate); -//void LPC17xx_UART_Printf (const uint8_t *format, ...); void LPC17xx_UART_PutString (uint8_t *str) ; +void LPC17xx_UART_WriteBuffer (uint8_t *buffer, uint32_t len) ; #endif // __LPC17xx_UART_H_ diff --git a/platforms/lpc17xx/main.c b/platforms/lpc17xx/main.c index 755f965..04d053f 100644 --- a/platforms/lpc17xx/main.c +++ b/platforms/lpc17xx/main.c @@ -27,31 +27,34 @@ * POSSIBILITY OF SUCH DAMAGE. */ - +#include #include "LPC17xx.h" #include "drivers/lpc17xx_uart.h" -#include #include "modules.h" #include "atom.h" #include "tests/atomtests.h" -// for mbed board -#define LED1_GPIO (1 << 18) -#define LED2_GPIO (1 << 20) -#define LED3_GPIO (1 << 21) -#define LED4_GPIO (1 << 23) - -#define LED_GET(led) (LPC_GPIO1->FIOSET & led) -#define LED_SET(led, on) { if (on) LPC_GPIO1->FIOSET = led ; else LPC_GPIO1->FIOCLR = led ; } -#define LED_TOGGLE(led) LED_SET(led, !LED_GET(led)) #ifndef ATOMTHREADS_TEST #define ATOMTHREADS_TEST "kern1" #endif -#define TEST_STACK_BYTE_SIZE 1024 -#define IDLE_STACK_BYTE_SIZE 512 +// 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] ; @@ -68,7 +71,6 @@ void test_thread (uint32_t param) { uint32_t failures ; - static volatile unsigned int i ; CRITICAL_STORE ; failures = test_start () ; @@ -79,18 +81,28 @@ test_thread (uint32_t param) CRITICAL_END() ; while(1) { - LED_TOGGLE(LED1_GPIO) ; - for (i=0; i<1000000; i++) ; +#ifdef BOARD_MBED_LP1768 + MBED_LED_TOGGLE(MBED_LED1_GPIO) ; +#endif + atomTimerDelay (65) ; } } -int main(void) { +/** + * \b main + * + * Initialize atomthreads and start a test_thread to run the Atomthreads test suite. + * + */ +int +main(void) +{ - static volatile unsigned int i ; - - // mbed board - LPC_GPIO1->FIODIR |= LED1_GPIO | LED2_GPIO | LED3_GPIO | LED4_GPIO ; +#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) ; @@ -99,18 +111,12 @@ int main(void) { 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); + atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, + &test_stack[0], TEST_STACK_BYTE_SIZE, TRUE); atomOSStart() ; + while(1) ; - - while(1) { - - LED_TOGGLE(LED1_GPIO) ; - for (i=0; i<1000000; i++) ; - - - } return 0 ; } diff --git a/platforms/lpc17xx/modules.c b/platforms/lpc17xx/modules.c index 7901bcd..95b55cf 100644 --- a/platforms/lpc17xx/modules.c +++ b/platforms/lpc17xx/modules.c @@ -50,7 +50,8 @@ dbg_format_msg (char *format, ...) va_start (args, format) ; //CRITICAL_START() ; - vsnprintf ((char*)msg, 256, (char*)format, args) ; + + vsniprintf ((char*)msg, 256, (char*)format, args) ; LPC17xx_UART_PutString (msg) ; //CRITICAL_END() ; diff --git a/platforms/lpc17xx/startup.c b/platforms/lpc17xx/startup.c index 87a90a5..14d104f 100644 --- a/platforms/lpc17xx/startup.c +++ b/platforms/lpc17xx/startup.c @@ -51,6 +51,8 @@ WEAK void IntDefault_Handler(void); //***************************************************************************** extern int main(void); +extern void low_level_init(void); + //***************************************************************************** // // External declaration for the pointer to the stack top from the Linker Script diff --git a/ports/cortex_m/atomport.h b/ports/cortex_m/atomport.h index 1a4cfd9..bc77588 100644 --- a/ports/cortex_m/atomport.h +++ b/ports/cortex_m/atomport.h @@ -39,7 +39,9 @@ * 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) @@ -56,7 +58,9 @@ * Most of these are available from types.h on this platform, which is * included above. */ +#ifndef POINTER #define POINTER void * +#endif /* * * diff --git a/ports/cortex_m/types.h b/ports/cortex_m/types.h index e6f927d..ba0b9ee 100644 --- a/ports/cortex_m/types.h +++ b/ports/cortex_m/types.h @@ -51,9 +51,15 @@ typedef char int8_t ; #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__ */ From b19004817c68da56a757bc5f68dbbd3e8d96ab39 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Sun, 18 Nov 2012 11:29:32 +0100 Subject: [PATCH 28/28] Added thread exit routine. --- ports/atomvm/atomport.c | 6 ++--- ports/atomvm/atomvm.c | 59 +++++++++++++++++++++++++++++++---------- ports/atomvm/atomvm.h | 4 ++- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/ports/atomvm/atomport.c b/ports/atomvm/atomport.c index 55d6d69..8daac41 100644 --- a/ports/atomvm/atomport.c +++ b/ports/atomvm/atomport.c @@ -32,7 +32,6 @@ #include "windows.h" /** Forward declarations */ -static void thread_shell (void); DWORD WINAPI cntrl_thread_proc (LPVOID lpParameter) ; /* Global data */ @@ -73,7 +72,7 @@ cntrl_thread_proc (LPVOID lpParameter) * */ void -thread_shell (void) +thread_shell (uint32_t arg) { ATOM_TCB *curr_tcb; @@ -111,7 +110,8 @@ archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(u tcb_ptr->entry_param = entry_param ; tcb_ptr->entry_point = entry_point ; - atomvmContextCreate (&tcb_ptr->context, (unsigned int )stack_top, (unsigned int )thread_shell) ; + tcb_ptr->context = atomvmContextCreate (1) ; + atomvmContextInit (tcb_ptr->context, (unsigned int *)stack_top, thread_shell, entry_param, 0) ; } diff --git a/ports/atomvm/atomvm.c b/ports/atomvm/atomvm.c index 960b13e..3785212 100644 --- a/ports/atomvm/atomvm.c +++ b/ports/atomvm/atomvm.c @@ -550,15 +550,12 @@ callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback) * This function creates 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 using the default caling convention of the compiler. +* @param[in] interrupt_mask initial interrupt mask of the thread. * -* @return Zero on failure, try to call GetLastError(). +* @return Handle to the context of the thread created. */ -uint32_t -atomvmContextCreate (HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t entry) +HATOMVM_CONTEXT +atomvmContextCreate (uint32_t interrupt_mask) { uint32_t res ; PATOMVM patomvm = getAtomvm () ; @@ -567,21 +564,55 @@ atomvmContextCreate (HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t e ATOMVM_CALLBACK_CONTEXT context_init ; context_init.pcontext = new_context ; - new_context->interrupt_mask = 1 ; - + new_context->interrupt_mask = interrupt_mask ; + new_context->thread_id = (uint32_t) -1 ; res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ; if (res) { - pcontext->Ebp = stack ; - pcontext->Esp = stack ; - pcontext->Eip = entry ; - *atomvm_context = (HATOMVM_CONTEXT)new_context ; + 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 * diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h index b4ae55d..6d69058 100644 --- a/ports/atomvm/atomvm.h +++ b/ports/atomvm/atomvm.h @@ -86,7 +86,9 @@ 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 uint32_t atomvmContextCreate (HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; +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) ;