mirror of
https://github.com/kelvinlawson/atomthreads.git
synced 2026-03-01 18:13:20 +01:00
New, atomvm!
Added ATOM_TLS for TLS or other thread specific storage.
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
|
||||
39
ports/atomvm/README.txt
Normal file
39
ports/atomvm/README.txt
Normal file
@@ -0,0 +1,39 @@
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Library: Atomvn
|
||||
Author: Natie van Rooyen <natie@navaro.nl>
|
||||
License: BSD Revised
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Atomvm is a tiny virtual machine that can run on Windows inside an IDE with a
|
||||
debugger like Microsoft Visual C++ Express. The primary purpose of this 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!
|
||||
58
ports/atomvm/atomport-tests.h
Normal file
58
ports/atomvm/atomport-tests.h
Normal file
@@ -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 <stdio.h>
|
||||
|
||||
/* Logger macro for viewing test results */
|
||||
#define ATOMLOG printf
|
||||
|
||||
/*
|
||||
* String location macro: for platforms which need to place strings in
|
||||
* alternative locations, e.g. on avr-gcc strings can be placed in
|
||||
* program space, saving SRAM. On most platforms this can expand to
|
||||
* empty.
|
||||
*/
|
||||
#define _STR(x) x
|
||||
|
||||
/* Default thread stack size (in bytes) */
|
||||
#define TEST_THREAD_STACK_SIZE 0x4000
|
||||
|
||||
/* Uncomment to enable logging of stack usage to UART */
|
||||
/* #define TESTS_LOG_STACK_USAGE */
|
||||
|
||||
|
||||
#endif /* __ATOM_PORT_TESTS_H */
|
||||
|
||||
172
ports/atomvm/atomport.c
Normal file
172
ports/atomvm/atomport.c
Normal file
@@ -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) ;
|
||||
}
|
||||
74
ports/atomvm/atomport.h
Normal file
74
ports/atomvm/atomport.h
Normal file
@@ -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 */
|
||||
63
ports/atomvm/atomuser.h
Normal file
63
ports/atomvm/atomuser.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2010,Kelvin Lawson. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. No personal names or organizations' names associated with the
|
||||
* Atomthreads project may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#if 1
|
||||
#ifndef __ATOM_USER_H__
|
||||
#define __ATOM_USER_H__
|
||||
|
||||
|
||||
/* Portable uint8_t and friends not available from stdint.h on this platform */
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
#define SYSTEM_MEMALIGN sizeof (unsigned int)
|
||||
|
||||
|
||||
typedef unsigned int uintptr_t ;
|
||||
typedef int intptr_t ;
|
||||
typedef unsigned int uint32_t ;
|
||||
typedef unsigned short uint16_t ;
|
||||
typedef unsigned char uint8_t ;
|
||||
typedef int int32_t ;
|
||||
typedef short int16_t ;
|
||||
typedef char int8_t ;
|
||||
|
||||
|
||||
/**
|
||||
* Architecture-specific types.
|
||||
* Most of these are available from stdint.h on this platform, which is
|
||||
* included above.
|
||||
*/
|
||||
#define POINTER void *
|
||||
|
||||
|
||||
#define ATOM_TLS HATOMVM_CONTEXT context ;
|
||||
|
||||
|
||||
#endif /* __ATOM_USER_H__ */
|
||||
#endif
|
||||
626
ports/atomvm/atomvm.c
Normal file
626
ports/atomvm/atomvm.c
Normal file
@@ -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 <string.h>
|
||||
|
||||
#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 ;
|
||||
}
|
||||
72
ports/atomvm/atomvm.h
Normal file
72
ports/atomvm/atomvm.h
Normal file
@@ -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 <crtdbg.h>
|
||||
#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__ */
|
||||
249
ports/atomvm/test/main.c
Normal file
249
ports/atomvm/test/main.c
Normal file
@@ -0,0 +1,249 @@
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "atom.h"
|
||||
#include "atomvm.h"
|
||||
#include "atomport.h"
|
||||
|
||||
|
||||
// #define UNIT_TESTS
|
||||
#ifdef UNIT_TESTS
|
||||
extern uint32_t test_start (void) ;
|
||||
#endif
|
||||
|
||||
#define TEST_THREADS 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<TEST_THREADS/3; i++) {
|
||||
printf("Thr %.2d cnt %08d\t",i,test_counter[i]);
|
||||
printf("Thr %.2d cnt %08d\t",i+TEST_THREADS/3,test_counter[i+TEST_THREADS/3]);
|
||||
printf("Thr %.2d cnt %08d\n",i+TEST_THREADS*2/3,test_counter[i+TEST_THREADS*2/3]);
|
||||
}
|
||||
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) ;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test_thread (uint32_t parm)
|
||||
{
|
||||
CRITICAL_STORE;
|
||||
|
||||
for (;;) {
|
||||
|
||||
atomTimerDelay (test_interv[parm]) ;
|
||||
CRITICAL_START();
|
||||
test_counter[parm]++ ;
|
||||
CRITICAL_END();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test2_thread (uint32_t parm)
|
||||
{
|
||||
CRITICAL_STORE;
|
||||
|
||||
for (;;) {
|
||||
|
||||
CRITICAL_START();
|
||||
test2_counter++ ;
|
||||
CRITICAL_END();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test3_thread(uint32_t parm)
|
||||
{
|
||||
CRITICAL_STORE;
|
||||
|
||||
for (;;) {
|
||||
|
||||
CRITICAL_START();
|
||||
test3_counter++ ;
|
||||
CRITICAL_END();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNIT_TESTS
|
||||
void unit_test_thread(uint32_t parm)
|
||||
{
|
||||
unsigned int failures ;
|
||||
|
||||
failures = test_start () ;
|
||||
printf ("test_start %d failures\n", failures) ;
|
||||
|
||||
while(1) {
|
||||
|
||||
atomTimerDelay (100);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
__atomvmReset ()
|
||||
{
|
||||
unsigned int i ;
|
||||
|
||||
atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ;
|
||||
#ifndef UNIT_TESTS
|
||||
|
||||
for (i=0; i< TEST_THREADS;i++) {
|
||||
atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], test_thread, i, &test_stack[i][TEST_STACK_BYTE_SIZE - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int));
|
||||
}
|
||||
|
||||
atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 50, monitor_thread, 0, &monitor_stack[(MONITOR_STACK_BYTE_SIZE) - sizeof(unsigned int)], MONITOR_STACK_BYTE_SIZE - sizeof(unsigned int));
|
||||
|
||||
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 253, test2_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
|
||||
atomThreadCreate ((ATOM_TCB *)&test3_tcb, 253, test3_thread, 0, &test3_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
|
||||
#else
|
||||
|
||||
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 16, unit_test_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
|
||||
|
||||
#endif
|
||||
|
||||
atomOSStart() ;
|
||||
}
|
||||
|
||||
void
|
||||
__atomvmClose ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
test_isr ()
|
||||
{
|
||||
static int i = 0 ;
|
||||
test_isr_count++ ;
|
||||
if (i++==25) {
|
||||
//Sleep(3) ;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI
|
||||
isr_thread_proc (LPVOID lpParameter)
|
||||
{
|
||||
int i = 0 ;
|
||||
int x ;
|
||||
int y = rand() % 100 ;
|
||||
while (1) {
|
||||
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)test_isr) ;
|
||||
if (i++==y) {
|
||||
x = rand() % 50 ;
|
||||
Sleep (x) ;
|
||||
y = rand() % 100 ;
|
||||
i = 0 ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
main ()
|
||||
{
|
||||
atomvmRun () ;
|
||||
|
||||
#ifndef UNIT_TESTS
|
||||
isr_thread_1 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
|
||||
isr_thread_2 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
|
||||
isr_thread_3 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
|
||||
isr_thread_4 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
|
||||
|
||||
ResumeThread (isr_thread_1) ;
|
||||
ResumeThread (isr_thread_2) ;
|
||||
ResumeThread (isr_thread_3) ;
|
||||
ResumeThread (isr_thread_4) ;
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
Sleep(1) ;
|
||||
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)archTimerTickIrqHandler) ;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user