From 6f34e08e2f52813dd2f23b9ed234123420a8d4cb Mon Sep 17 00:00:00 2001 From: Natie van Rooyen Date: Wed, 3 Oct 2012 21:19:44 +0200 Subject: [PATCH] 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__ */