From b9e7e9cc63a69180539219c8044cdf2078151593 Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Fri, 3 Sep 2010 22:23:47 +0200 Subject: [PATCH] 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