From 0d07f0274d3a23841d38a77b9ef2e6f0e6c1b19f Mon Sep 17 00:00:00 2001 From: Kelvin Lawson Date: Fri, 21 Sep 2012 01:30:09 +0100 Subject: [PATCH] Merge https://github.com/navaro/atomthreads into navaro branch. Remove tests/ folder changes as they were based on an old Atomthreads API. Remove some binaries and other unnecessary files. --- kernel/atom.h | 4 + platforms/qemu_integratorcp/Makefile | 91 +++ platforms/qemu_integratorcp/main.c | 85 +++ platforms/qemu_integratorcp/modules.c | 115 +++ platforms/qemu_integratorcp/modules.h | 124 +++ platforms/qemu_integratorcp/startup.s | 55 ++ platforms/qemu_integratorcp/system.ld | 94 +++ platforms/rules.mk | 60 ++ ports/arm/Makefile | 19 + ports/arm/README | 38 + ports/arm/atomport-tests.h | 50 ++ ports/arm/atomport.c | 185 +++++ ports/arm/atomport.h | 59 ++ ports/arm/atomport_private.h | 39 + ports/arm/atomport_s.S | 227 ++++++ ports/arm/types.h | 63 ++ ports/atomvm/README.txt | 36 + 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 | 1016 +++++++++++++++++++++++++ ports/atomvm/atomvm.h | 131 ++++ ports/atomvm/test/main.c | 270 +++++++ ports/cortex_m/Makefile | 19 + ports/cortex_m/README | 31 + ports/cortex_m/atomport-tests.h | 50 ++ ports/cortex_m/atomport.c | 193 +++++ ports/cortex_m/atomport.h | 59 ++ ports/cortex_m/atomport_private.h | 38 + ports/cortex_m/atomport_s.S | 220 ++++++ ports/cortex_m/types.h | 44 ++ 32 files changed, 3782 insertions(+) create mode 100644 platforms/qemu_integratorcp/Makefile create mode 100644 platforms/qemu_integratorcp/main.c create mode 100644 platforms/qemu_integratorcp/modules.c create mode 100644 platforms/qemu_integratorcp/modules.h create mode 100644 platforms/qemu_integratorcp/startup.s create mode 100644 platforms/qemu_integratorcp/system.ld create mode 100644 platforms/rules.mk create mode 100644 ports/arm/Makefile create mode 100644 ports/arm/README create mode 100644 ports/arm/atomport-tests.h create mode 100644 ports/arm/atomport.c create mode 100644 ports/arm/atomport.h create mode 100644 ports/arm/atomport_private.h create mode 100644 ports/arm/atomport_s.S create mode 100644 ports/arm/types.h 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 create mode 100644 ports/cortex_m/Makefile create mode 100644 ports/cortex_m/README create mode 100644 ports/cortex_m/atomport-tests.h create mode 100644 ports/cortex_m/atomport.c create mode 100644 ports/cortex_m/atomport.h create mode 100644 ports/cortex_m/atomport_private.h create mode 100644 ports/cortex_m/atomport_s.S create mode 100644 ports/cortex_m/types.h diff --git a/kernel/atom.h b/kernel/atom.h index ed50fcd..b8e4426 100755 --- a/kernel/atom.h +++ b/kernel/atom.h @@ -70,6 +70,10 @@ typedef struct atom_tcb uint32_t stack_size; /* Size of stack allocation in bytes */ #endif +#ifdef ATOM_TLS + ATOM_TLS /* Thread Local Storage */ +#endif + } ATOM_TCB; diff --git a/platforms/qemu_integratorcp/Makefile b/platforms/qemu_integratorcp/Makefile new file mode 100644 index 0000000..551529f --- /dev/null +++ b/platforms/qemu_integratorcp/Makefile @@ -0,0 +1,91 @@ +ifeq ($(TARGET_NAME),) +TARGET_NAME=boot +endif +ifeq ($(ATOMTHREADS),) +ATOMTHREADS = $(shell pwd)/../../ +endif +ifeq ($(TEST_NAME),) +TEST_NAME = kern1 +endif + + + +CC = arm-none-eabi-gcc +LN = arm-none-eabi-gcc +AS = arm-none-eabi-gcc + +CFLAGS := $(CFLAGS) -Wall -g -c -mcpu=arm926ej-s -ffreestanding +AFLAGS := $(CFLAGS) -Wall -g -c -mcpu=arm926ej-s -ffreestanding +LFLAGS := $(LFLAGS) -Wall -mcpu=arm926ej-s -Wl,-Map=system.map,--verbose -Tsystem.ld + +CDEFS := $(CDEFS) -DATOMTHREADS_TEST='"$(TEST_NAME)"' +ADEFS := $(ADEFS) + +LLIBS := $(LLIBS) + + +SRCS := $(SRCS) \ + modules.c \ + main.c \ + $(ATOMTHREADS)/tests/$(TEST_NAME).c + +ASMS := $(ASMS) \ + startup.S \ + +INCLUDES := $(INCLUDES) \ + -I$(ATOMTHREADS) + +include $(ATOMTHREADS)/ports/arm/Makefile + +OBJS = $(SRCS:.c=.o) $(ASMS:.S=.o) + +include ../rules.mk + + +run_test: clean all + echo "START TEST $(TEST_NAME)" + qemu-system-arm -M integratorcp -kernel boot.elf -semihosting | tee atomthreads_test.out + +all_tests: + echo "Starting atomthreads test suite" > atomthreads_test.out + make run_test "TEST_NAME=mutex1" + make run_test "TEST_NAME=mutex2" + make run_test "TEST_NAME=mutex3" + make run_test "TEST_NAME=mutex4" + make run_test "TEST_NAME=mutex5" + make run_test "TEST_NAME=mutex6" + make run_test "TEST_NAME=mutex7" + make run_test "TEST_NAME=mutex8" + make run_test "TEST_NAME=mutex9" + make run_test "TEST_NAME=kern1" + make run_test "TEST_NAME=kern2" + make run_test "TEST_NAME=kern3" + make run_test "TEST_NAME=kern4" + make run_test "TEST_NAME=timer1" + make run_test "TEST_NAME=timer2" + make run_test "TEST_NAME=timer3" + make run_test "TEST_NAME=timer5" + make run_test "TEST_NAME=timer6" + make run_test "TEST_NAME=timer7" + make run_test "TEST_NAME=queue1" + make run_test "TEST_NAME=queue2" + make run_test "TEST_NAME=queue3" + make run_test "TEST_NAME=queue4" + make run_test "TEST_NAME=queue5" + make run_test "TEST_NAME=queue6" + make run_test "TEST_NAME=queue7" + make run_test "TEST_NAME=queue8" + make run_test "TEST_NAME=queue9" + make run_test "TEST_NAME=sem1" + make run_test "TEST_NAME=sem2" + make run_test "TEST_NAME=sem3" + make run_test "TEST_NAME=sem4" + make run_test "TEST_NAME=sem5" + make run_test "TEST_NAME=sem6" + make run_test "TEST_NAME=sem7" + make run_test "TEST_NAME=sem8" + make run_test "TEST_NAME=sem9" + +run_last: + qemu-system-arm -M integratorcp -kernel boot.elf -monitor stdio -semihosting + diff --git a/platforms/qemu_integratorcp/main.c b/platforms/qemu_integratorcp/main.c new file mode 100644 index 0000000..3222170 --- /dev/null +++ b/platforms/qemu_integratorcp/main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include "modules.h" +#include "atom.h" +#include "tests/atomtests.h" + +#ifndef ATOMTHREADS_TEST +#define ATOMTHREADS_TEST "kern1" +#endif + +#define TEST_STACK_BYTE_SIZE 1024 +#define IDLE_STACK_BYTE_SIZE 512 + +static unsigned char test_stack[TEST_STACK_BYTE_SIZE] ; +static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ; +ATOM_TCB test_tcb ; + + +/** + * \b test_thread + * + * Function calling the test function of the Atomthreads test suite. + * + */ +void +test_thread (uint32_t param) +{ + uint32_t failures ; + CRITICAL_STORE ; + + failures = test_start () ; + + atomTimerDelay (10) ; + CRITICAL_START() ; + printf ("%s %s\r\n", ATOMTHREADS_TEST, failures ? "FAIL" : "PASS") ; + exit (failures) ; + CRITICAL_END() ; +} + +/** + * \b main + * + * Initialize atomthreads and start a test_thread to run the Atomthreads test suite. + * + */ +int +main (void) +{ + uint32_t failures ; + + printf ("atomthreads starting %s... ", ATOMTHREADS_TEST) ; + + atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ; + atomThreadCreate ((ATOM_TCB *)&test_tcb, TEST_THREAD_PRIO, test_thread, 0, &test_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int)); + atomOSStart() ; + + return 0 ; +} diff --git a/platforms/qemu_integratorcp/modules.c b/platforms/qemu_integratorcp/modules.c new file mode 100644 index 0000000..c611d68 --- /dev/null +++ b/platforms/qemu_integratorcp/modules.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "modules.h" +#include +#include +#include "atomport_private.h" +#include "atom.h" +#include "atomport.h" +#include "types.h" + +ICP_TIMER_T* const board_timer_0 = (ICP_TIMER_T*) BOARD_BASE_ADDRESS_TIMER_0 ; +ICP_PIC_T * const board_pic = (ICP_PIC_T*) BOARD_BASE_ADDRESS_PIC ; + +/** + * \b dbg_format_msg + * + * Same as printf. + * + */ +void +dbg_format_msg (char *format, ...) +{ + va_list args; + static char msg[256] ; + CRITICAL_STORE ; + + va_start (args, format) ; + CRITICAL_START() ; + vsnprintf ((char*)msg, 256, (char*)format, args) ; + CRITICAL_END() ; + + printf (msg) ; +} + +/** + * \b low_level_init + * + * Initializes the PIC and start the system timer tick intrerupt. + * + */ +int +low_level_init (void) +{ + + board_pic->IRQ_ENABLECLR = ICP_PIC_IRQ_TIMERINT0 ; + board_timer_0->INTCLR = 1 ; + board_pic->IRQ_ENABLESET |= ICP_PIC_IRQ_TIMERINT0 ; + + board_timer_0->LOAD = 0x2000 ; + board_timer_0->BGLOAD = 0x2000 ; + board_timer_0->CONTROL = ICP_TIMER_CONTROL_ENABLE | + ICP_TIMER_CONTROL_MODE | + ICP_TIMER_CONTROL_IE | + /*ICP_TIMER_CONTROL_PRESCALE_256 |*/ + ICP_TIMER_CONTROL_TIMER_SIZE ; + + return 0 ; +} + + +/** + * \b __context_preempt_handler + * + * System timer tic interupt handler. + * + */ +void +__context_preempt_handler (void) +{ + unsigned int status = board_pic->IRQ_STATUS ; + + if (status | ICP_PIC_IRQ_TIMERINT0) { + + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* ack the interrupt */ + board_timer_0->INTCLR = 0x1 ; + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); + + } + + +} + diff --git a/platforms/qemu_integratorcp/modules.h b/platforms/qemu_integratorcp/modules.h new file mode 100644 index 0000000..38aa37f --- /dev/null +++ b/platforms/qemu_integratorcp/modules.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __MODULES_H__ +#define __MODULES_H__ + +#include "atomport.h" + +extern void dbg_format_msg (char *format, ...) ; + +#define DBG_MESSAGE(fmt_str) { dbg_format_msg fmt_str ; } + + +typedef volatile unsigned int REG_DWORD ;// Hardware register definition +typedef volatile unsigned short REG_WORD ; +typedef volatile unsigned char REG_BYTE ; + + +// ***************************************************************************** +// INTEGRATORCP TIMER +// ***************************************************************************** +typedef struct ICP_TIMER_S { + // offset read/write word size reset Description + REG_DWORD LOAD ; // 0x0000 Read/write 32 0x00000000 Load value for Timer + REG_DWORD VALUE ; // 0x0004 Read 32 0xFFFFFFFF The current value for Timer + REG_BYTE CONTROL ; // 0x0008 Read/write 8 0x20 Timer control register + REG_DWORD INTCLR ; // 0x000C Write - - Timer interrupt clear + REG_DWORD RIS ; // 0x0010 Read 1 0x0 Timer raw interrupt status + REG_DWORD MIS ; // 0x0014 Read 1 0x0 Timer masked interrupt status + REG_DWORD BGLOAD ; // 0x0018 Read/write 32 0x00000000 Background load value for Timer + +} ICP_TIMER_T, *PICP_TIMER_T ; + +// -------- ICP_TIMER_LOAD : (LOAD Offset: 0x00) Load value for Timer -------- +// -------- ICP_TIMER_VALUE : (LOAD Offset: 0x04) The current value for Timer -------- +// -------- ICP_TIMER_CONTROL : (CONTROL Offset: 0x04) Timer control register -------- +#define ICP_TIMER_CONTROL_MASK ((unsigned int)0x0F << 0) // Timer control mask + #define ICP_TIMER_CONTROL_ENABLE ((unsigned int)0x01 << 7) // Timer enable: 0 = disabled 1 = enabled. + #define ICP_TIMER_CONTROL_MODE ((unsigned int)0x01 << 6) // Timer mode: 0 = free running, counts once and then wraps to 0xFFFF 1 = periodic, reloads from load register at the end of each count.. + #define ICP_TIMER_CONTROL_IE ((unsigned int)0x01 << 5) // Interrupt enable. + #define ICP_TIMER_CONTROL_R ((unsigned int)0x01 << 4) // Unused, always write as 0s. + #define ICP_TIMER_CONTROL_PRESCALE_MASK ((unsigned int)0x03 << 2) // Prescale divisor + #define ICP_TIMER_CONTROL_PRESCALE_NONE ((unsigned int)0x00 << 2) // + #define ICP_TIMER_CONTROL_PRESCALE_16 ((unsigned int)0x01 << 2) // + #define ICP_TIMER_CONTROL_PRESCALE_256 ((unsigned int)0x02 << 2) // +#define ICP_TIMER_CONTROL_TIMER_SIZE ((unsigned int)0x01 << 1) // Selects 16/32 bit counter operation: 0 = 16-bit counter (default) 1 = 32-bit counter For 16-bit mode, write the high 16 bits of the 32-bit value as 0. +#define ICP_TIMER_CONTROL_ONE_SHOT ((unsigned int)0x01 << 0) // Selects one-shot or wrapping counter mode: 0 = wrapping mode (default) 1 = one-shot mode +// -------- ICP_TIMER_INTCLR : (INTCLR Offset: 0x0C) Timer interrupt clear -------- +// -------- ICP_TIMER_RIS : (RIS Offset: 0x10) Timer raw interrupt status -------- +// -------- ICP_TIMER_MIS : (MIS Offset: 0x14) Timer masked interrupt status -------- +#define ICP_TIMER_INT ((unsigned int)0x01 << 0) // Interrupt +// -------- ICP_TIMER_BGLOAD : (BGLOAD Offset: 0x18) Timer masked interrupt status -------- + + +// ***************************************************************************** +// INTEGRATORCP PIC +// ***************************************************************************** +typedef struct ICP_PIC_S { + // offset read/write word size reset Description + REG_DWORD IRQ_STATUS ; // 0x0000 Read 22 IRQ gated interrupt status + REG_DWORD IRQ_RAWSTAT ; // 0x0004 Read 22 IRQ raw interrupt status + REG_DWORD IRQ_ENABLESET ; // 0x0008 Read/write 22 IRQ enable set + REG_DWORD IRQ_ENABLECLR ; // 0x000C Write 22 IRQ enable clear + REG_DWORD INT_SOFTSET ; // 0x0010 Read/write 16 Software interrupt set + REG_DWORD INT_SOFTCLR ; // 0x0014 Write 16 Software interrupt clear + REG_DWORD RESERVED[2] ; // 0x0018 + REG_DWORD FIQ_STATUS ; // 0x0020 Read 22 FIQ gated interrupt status + REG_DWORD FIQ_RAWSTAT ; // 0x0024 Read 22 FIQ raw interrupt status + REG_DWORD FIQ_ENABLESET ; // 0x0028 Read/write 22 FIQ enable set + REG_DWORD FIQ_ENABLECLR ; // 0x002C Write-only 22 FIQ enable clear + +} ICP_PIC_T, *PICP_PIC_T ; + +// -------- ICP_PIC_IRQ_STATUS : (IRQ_STATUS Offset: 0x00) IRQ gated interrupt status -------- +// -------- ICP_PIC_IRQ_RAWSTAT : (IRQ_RAWSTAT Offset: 0x04) IRQ raw interrupt status -------- +// -------- ICP_PIC_IRQ_ENABLESET : (IRQ_ENABLESET Offset: 0x08) IRQ enable set -------- +// -------- ICP_PIC_IRQ_ENABLECLR : (IRQ_ENABLECLR Offset: 0x0C) IRQ enable clear -------- +#define ICP_PIC_IRQ_MASK ((unsigned int)0x3FFFFF << 0) // IRQ mask + #define ICP_PIC_IRQ_TIMERINT2 ((unsigned int)0x01 << 7) // TIMERINT2 Counter-timer 2 interrupt + #define ICP_PIC_IRQ_TIMERINT1 ((unsigned int)0x01 << 6) // TIMERINT1 Counter-timer 1 interrupt + #define ICP_PIC_IRQ_TIMERINT0 ((unsigned int)0x01 << 5) // TIMERINT0 Counter-timer 0 interrupt + #define ICP_PIC_IRQ_SOFTINT ((unsigned int)0x01 << 0) // OFTINT Software interrupt +// -------- ICP_PIC_INT_SOFTSET : (INT_SOFTSET Offset: 0x10) Software interrupt set -------- +// -------- ICP_PIC_INT_SOFTCLR : (INT_SOFTCLR Offset: 0x14) Software interrupt clear -------- + + + + +#define BOARD_BASE_ADDRESS_TIMER_0 0x13000000 +#define BOARD_BASE_ADDRESS_PIC 0x14000000 + +extern ICP_TIMER_T* const board_timer_0 ; +extern ICP_PIC_T* const board_pic ; + + + +extern int low_level_init (void) ; + +#endif /* __MODULES_H__ */ diff --git a/platforms/qemu_integratorcp/startup.s b/platforms/qemu_integratorcp/startup.s new file mode 100644 index 0000000..dc4a167 --- /dev/null +++ b/platforms/qemu_integratorcp/startup.s @@ -0,0 +1,55 @@ +.section .vectors, "x" + +.global __interrupt_vector_table +.global __irq_stack_top__ +.global __fiq_stack_top__ +.global __svc_stack_top__ + +.global bsp_ints_enable +.global bsp_ints_disable +.global bsp_ints_restore + + +.equ USR_MODE, 0x10 +.equ FIQ_MODE, 0x11 +.equ IRQ_MODE, 0x12 +.equ SVC_MODE, 0x13 +.equ ABT_MODE, 0x17 +.equ UND_MODE, 0x1B +.equ SYS_MODE, 0x1F + +.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */ +.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */ + +__interrupt_vector_table: + + B Reset_Handler /* Reset */ + B . /* Undefined */ + B . /* SWI */ + B . /* Prefetch Abort */ + B . /* Data Abort */ + B . /* reserved */ + B IRQ_Handler /* IRQ */ + B . /* FIQ */ + + + +Reset_Handler: + + + MSR CPSR_c,#(IRQ_MODE | I_BIT | F_BIT) + LDR sp,=__irq_stack_top__ /* set the IRQ stack pointer */ + MSR CPSR_c,#(FIQ_MODE | I_BIT | F_BIT) + LDR sp,=__fiq_stack_top__ /* set the FIQ stack pointer */ + MSR CPSR_c,#(SVC_MODE | I_BIT | F_BIT) + LDR sp,=__svc_stack_top__ /* set the SVC stack pointer */ + + BL low_level_init + BL _mainCRTStartup + + + B . + +IRQ_Handler: + B archIRQHandler + diff --git a/platforms/qemu_integratorcp/system.ld b/platforms/qemu_integratorcp/system.ld new file mode 100644 index 0000000..4d4fc2c --- /dev/null +++ b/platforms/qemu_integratorcp/system.ld @@ -0,0 +1,94 @@ + +ENTRY(__interrupt_vector_table) + + +MEMORY +{ + flash (rx) : ORIGIN = 0x00000000, LENGTH = 0x00020000 + sram (rwx) : ORIGIN = 0x00020000, LENGTH = 0x00020000 +} + + +EXTERN(__interrupt_vector_table); + + +C_STACK_SIZE = 512; +IRQ_STACK_SIZE = 256; +FIQ_STACK_SIZE = 256; +SVC_STACK_SIZE = 512; +ABT_STACK_SIZE = 256; +UND_STACK_SIZE = 256; + +SECTIONS +{ + + + .text : + { + *(.vectors) + /* Startup assembly */ + *(.startup) + *(.init) + + /* Rest of the code (C) */ + *(.text) + *(.rodata) + *(.rodata*) + + _end_text = .; + } >flash + + .data : + { + _start_data = .; + *(.data) + _end_data = .; + } >sram + + .bss : + { + _start_bss = .; + __bss_start__ = . ; + *(.bss) + *(.eh_*) + } >sram + + . = ALIGN(4); + _end_bss = .; + __bss_end__ = . ; + + . = ALIGN(256); + + + .stack : { + __stack_start__ = . ; + . += IRQ_STACK_SIZE; + . = ALIGN (4); + __irq_stack_top__ = . ; + . += FIQ_STACK_SIZE; + . = ALIGN (4); + __fiq_stack_top__ = . ; + . += SVC_STACK_SIZE; + . = ALIGN (4); + __svc_stack_top__ = . ; + . += ABT_STACK_SIZE; + . = ALIGN (4); + __abt_stack_top__ = . ; + . += UND_STACK_SIZE; + . = ALIGN (4); + __und_stack_top__ = . ; + . += C_STACK_SIZE; + . = ALIGN (4); + __c_stack_top__ = . ; + __stack_end__ = .; + } >sram + + + /*DISCARD : + { + *(.eh_*) + }*/ +} + +_end = .; +PROVIDE(end = .); \ No newline at end of file diff --git a/platforms/rules.mk b/platforms/rules.mk new file mode 100644 index 0000000..7f0f767 --- /dev/null +++ b/platforms/rules.mk @@ -0,0 +1,60 @@ +# +# The following part of the makefile is generic; it can be used to +# build any executable just by changing the definitions above and by +# deleting dependencies appended to the file from 'make depend' +# +.SUFFIXES: .asm .elf .hex .lst .o .S .s .c .cpp +.PHONY: depend clean + +dump: + @echo "Target: " + @echo $(TARGET_NAME) + @echo "Source files: " + @echo $(SRCS) + @echo $(ASMS) + @echo "Object files: " + @echo $(OBJS) + +all: target + +target: $(OBJS) + $(LN) $(LFLAGS) $(LIBFLAGS) $(OBJS) $(LLIBS) -o $(TARGET_NAME).elf + @echo $(TARGET_NAME).elf was compiled + +clean: + rm -f $(OBJS) + + +# this is a suffix replacement rule for building .o's from .c's +# it uses automatic variables $<: the name of the prerequisite of +# the rule(a .c file) and $@: the name of the target of the rule (a .o file) +# (see the gnu make manual section about automatic variables) + +.c.o: + $(CC) $(CDEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +.cpp.o: + $(CC) $(CDEFS) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +.S.o: + $(AS) $(ADEFS) $(AFLAGS) $(INCLUDES) -c $< -o $@ + +.s.o: + $(AS) $(ADEFS) $(AFLAGS) $(INCLUDES) -c $< -o $@ + +DEPFILE=.depends +DEPTOKEN='\# MAKEDEPENDS' +DEPFLAGS=-Y -f $(DEPFILE) -s $(DEPTOKEN) -p $(OUTDIR)/ + + +depend: + rm -f $(DEPFILE) + make $(DEPFILE) + +$(DEPFILE): + @echo $(DEPTOKEN) > $(DEPFILE) + makedepend $(DEPFLAGS) -- $(CFLAGS) -- $(SRCS) >&/dev/null + +# put this file in the last line of your Makefile +sinclude $(DEPFILE) + \ No newline at end of file diff --git a/ports/arm/Makefile b/ports/arm/Makefile new file mode 100644 index 0000000..9c33741 --- /dev/null +++ b/ports/arm/Makefile @@ -0,0 +1,19 @@ +ATOMTHREADS_PORT = $(ATOMTHREADS)/ports/arm +ATOMTHREADS_KERNEL = $(ATOMTHREADS)/kernel + +INCLUDES := $(INCLUDES) \ + -I$(ATOMTHREADS_KERNEL) \ + -I$(ATOMTHREADS_PORT) + +SRCS := $(SRCS) \ + $(ATOMTHREADS_KERNEL)/atomkernel.c \ + $(ATOMTHREADS_KERNEL)/atommutex.c \ + $(ATOMTHREADS_KERNEL)/atomqueue.c \ + $(ATOMTHREADS_KERNEL)/atomsem.c \ + $(ATOMTHREADS_KERNEL)/atomtimer.c \ + $(ATOMTHREADS_PORT)/atomport.c + +ASMS := $(ASMS) \ + $(ATOMTHREADS_PORT)/atomport_s.S + + diff --git a/ports/arm/README b/ports/arm/README new file mode 100644 index 0000000..fae939d --- /dev/null +++ b/ports/arm/README @@ -0,0 +1,38 @@ +--------------------------------------------------------------------------- + +Library: Atomthreads ARMv7 Port +Author: Natie van Rooyen +License: BSD Revised + +--------------------------------------------------------------------------- + +ARM ARMv7 PORT + +This folder contains a port of the Atomthreads real time kernel for the +ARMv7 processor architecture. This port was only tested on a ARMv7 but +should work on other versions of the ARM processor as well. + +To Use: + +1. From your platforms IRQ vector branch to the "__irq_context_handler()". + All interrupts from where calls to Atomthreads will be made should do + this. The "__irq_context_handler()" will call a platform specific + function called "__context_preempt_handler()" to dispatch the interrupt. + +2. Implement the function "__context_preempt_handler()" + from where your platforms interrupt controller will be serviced and the + interrupt will be dispatched to a specific interrupt service routine. In + the case of your platforms timer tick interrupt call the "archTickHandler()" + implemented in "atomport.c". + +3. Initialize your platforms timer tick hardware to generate an OS timer tick + interrupt. + +4. Add code to acknowledge your timer hardware's interrupt in the + function "archTickHandler()" implemented in "atomport.c". This must + be done here because "atomIntExit()" might switch the context. + +5. After your platforms c-runtime initialization has completed, start + Atomthreads from your runtime's "main()" function. + +6. Include the port's Makefile in your platform build flow. \ No newline at end of file diff --git a/ports/arm/atomport-tests.h b/ports/arm/atomport-tests.h new file mode 100644 index 0000000..cfb909a --- /dev/null +++ b/ports/arm/atomport-tests.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOMPORT_TEST_H__ +#define __ATOMPORT_TEST_H__ + +/* Include Atomthreads kernel API */ +#include "atom.h" + +extern void dbg_format_msg (char *format, ...) ; + + +#define TEST_THREAD_STACK_SIZE 1024 +#define ATOMLOG dbg_format_msg +#define _STR(x) x + + + + +/* API for starting each test */ +extern uint32_t test_start (void); + + +#endif /* __ATOMPORT_TEST_H__ */ diff --git a/ports/arm/atomport.c b/ports/arm/atomport.c new file mode 100644 index 0000000..d6fc47b --- /dev/null +++ b/ports/arm/atomport.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "atom.h" +#include "atomport.h" +#include "types.h" + + +/* * + * + * Functions defined in atomport_s.S + * + */ +typedef void * SYSCONTEXT ; + +extern void contextInit (void) ; +extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; +extern void contextStart (SYSCONTEXT* context) ; +extern void contextEnableInterrupts (void) ; + +/** + * \b thread_shell + * + * Documented in atomThreads. + * + */ +void +thread_shell (void) +{ + ATOM_TCB *curr_tcb; + + /* Get the TCB of the thread being started */ + curr_tcb = atomCurrentContext(); + + /** + * Enable interrupts - these will not be enabled when a thread + * is first restored. + */ + // sei(); + contextEnableInterrupts () ; + + /* Call the thread entry point */ + if (curr_tcb && curr_tcb->entry_point) + { + curr_tcb->entry_point(curr_tcb->entry_param); + } + + /* Not reached - threads should never return from the entry point */ +} + + +/** + * \b archThreadContextInit + * + * Documented in atomThreads. + * + */ +void +archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param) +{ + uint32_t * stack_ptr ; + + tcb_ptr->sp_save_ptr = stack_top; + tcb_ptr->entry_param = entry_param ; + tcb_ptr->entry_point = entry_point ; + + stack_ptr = (uint32_t *)stack_top; //-- Load stack pointer + + *stack_ptr = ( uint32_t ) thread_shell ; + stack_ptr--; + + *stack_ptr = ( uint32_t ) 0x00001111; /* R11 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00001010; /* R10 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000909; /* R9 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000808; /* R8 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000707; /* R7 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000606; /* R6 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000505; /* R5 */ + stack_ptr--; + *stack_ptr = ( uint32_t ) 0x00000404; /* R4 */ + +#ifdef CONTEXT_THREAD_ID + stack_ptr--; + *stack_ptr = context_thread_id++ ; /* thread_id */ +#endif + + tcb_ptr->sp_save_ptr = stack_ptr ; +} + + +/** + * \b archFirstThreadRestore + * + * Documented in atomThreads. + * + */ +void +archFirstThreadRestore(ATOM_TCB * p_sp_new) +{ + contextStart (&p_sp_new->sp_save_ptr) ; +} + + +/** + * \b archContextSwitch + * + * Documented in atomThreads. + * + */ +void +archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) +{ + contextSwitch (&p_sp_old->sp_save_ptr, &p_sp_new->sp_save_ptr) ; +} + + +/** + * \b archTimerTickIrqHandler + * + * System timer tick interrupt handler. + * + */ +void +archTickHandler (void) +{ + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* ack the interrupt if needed */ + /* ... */ + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); +} + +/** + * \b archTickInit + * + * System timer initialization. + * + */ +void +archTickInit (void) +{ + /* Initialize NVIC PendSV */ + contextInit () ; + + /* Initializa Timer Hardware */ + /* ... */ +} + + diff --git a/ports/arm/atomport.h b/ports/arm/atomport.h new file mode 100644 index 0000000..39bd0c0 --- /dev/null +++ b/ports/arm/atomport.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOM_PORT_H__ +#define __ATOM_PORT_H__ + +#include "types.h" + +#define SYSTEM_TICKS_PER_SEC 100 + + +/** + * Architecture-specific types. + * Most of these are available from types.h on this platform, which is + * included above. + */ +#define POINTER void * + +/* * + * + * Functions defined in atomport_arm.asm + * + */ +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; + + +/* Critical region protection */ +#define CRITICAL_STORE uint32_t __atom_critical +#define CRITICAL_START() __atom_critical = contextEnterCritical() +#define CRITICAL_END() contextExitCritical(__atom_critical) + +#endif /* __ATOM_PORT_H__ */ diff --git a/ports/arm/atomport_private.h b/ports/arm/atomport_private.h new file mode 100644 index 0000000..87a032f --- /dev/null +++ b/ports/arm/atomport_private.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOM_PORT_PRIVATE_H__ +#define __ATOM_PORT_PRIVATE_H__ + + +/* Function prototypes */ +extern void archTickHandler (void) ; +extern void archTickInit (void) ; +extern void archIRQHandler (void) ; + +#endif /* __ATOM_PORT_PRIVATE_H__ */ diff --git a/ports/arm/atomport_s.S b/ports/arm/atomport_s.S new file mode 100644 index 0000000..1227c52 --- /dev/null +++ b/ports/arm/atomport_s.S @@ -0,0 +1,227 @@ +/* + Copyright (c) 2012, Natie van Rooyen. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. No personal names or organizations' names associated with the + Atomthreads project may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + + + +/**/ + + + +.global archIRQHandler + +.global contextEnterCritical +.global contextExitCritical +.global contextEnableInterrupts +.global contextId +.global contextStart +.global contextSwitch +.global contextInit + + +.global __context_preempt_handler + +/**/ +.equ USR_MODE, 0x10 +.equ FIQ_MODE, 0x11 +.equ IRQ_MODE, 0x12 +.equ SVC_MODE, 0x13 +.equ ABT_MODE, 0x17 +.equ UND_MODE, 0x1B +.equ SYS_MODE, 0x1F + +.equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */ +.equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */ + + +.text +.code 32 + +/** + * \b contextInit + * + * Architecture-specific one time initialization. + * + * @return None + */ +contextInit: + + BX lr + +/** + * \b contextSwitch + * + * Architecture-specific context switch routine. + * + * Note that interrupts are always locked out when this routine is + * called. For cooperative switches, the scheduler will have entered + * a critical region. For preemptions (called from an ISR), the + * interrupts will have disabled in the tick_Handler. + * + * @param[in] [r0] -> Address to save old stack pointer + * @param[in] [r1] -> Address where new stack pointer is stored + * + * @return None + */ +contextSwitch: + STMFD sp!, {r4 - r11, lr} /* Save registers */ + +#ifdef CONTEXT_THREAD_ID + MRC p15, 0, r3, c13, c0, 2 + STMFD sp!, {r3} +#endif + + STR sp, [r0] /* Save old stack pointer */ + LDR r1, [r1] /* Load new stack pointer */ + MOV sp, r1 + +#ifdef CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15, 0, r3, c13, c0, 2 +#endif + + LDMFD sp!, {r4 - r11, pc} /* Load new registers */ + +/** + * \b contextStart + * + * Architecture-specific context start routine. + * + * @param[in] [r0] -> Address where stack pointer is stored + * + * @return Does not return + */ +contextStart: + LDR r0, [r0] + MOV sp, r0 /* Load new stack pointer */ + +#ifdef CONTEXT_THREAD_ID + LDMFD sp!, {r3} + MCR p15, 0, r3, c13, c0, 2 +#endif + + LDMFD sp!, {r4 - r11, pc} /* Load new registers */ + +/** + * \b contextId + * + * Returns a unique ID for the context + * + * @return ID + */ +contextId: +#ifdef CONTEXT_THREAD_ID + MRC p15, 0, r0, c13, c0, 2 +#else + MOV r0, #0 +#endif + BX lr + +/** + * \b contextEnableInterrupts + * + * Enables interrupts on the processor + * + * @return None + */ +contextEnableInterrupts: + MRS r0, CPSR + MOV r1, #I_BIT + BIC r0, r0, r1 + MSR CPSR_c, r0 + BX lr + +/** + * \b contextExitCritical + * + * Exit critical section (restores interrupt posture) + * + * @param[in] r0 Interrupt Posture + * + * @return None + */ +contextExitCritical: + MSR CPSR_cxsf, r0 + BX lr + +/** + * \b contextEnterCritical + * + * Enter critical section (disables interrupts) + * + * @return Current interrupt posture + */ +contextEnterCritical: + MRS r0, CPSR + ORR r1, r0, #I_BIT + MSR CPSR_cxsf, r1 + BX lr + + + +/** + * \b archIRQHandler + * + * IRQ entry point. + * + * Save the process/thread context onto its own stackm before calling __context_preempt_handler (). + * __context_preempt_handler() might switch stacks. On return the same context is poped from the + * stack and control is returned to the process. + * + * @return None + */ +archIRQHandler: + + MSR cpsr_c, #(SVC_MODE | I_BIT) /* Save current process context in process stack */ + STMFD sp!, {r0 - r3, ip, lr} + + MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Save lr_irq and spsr_irq in process stack */ + SUB lr, lr, #4 + MOV r1, lr + MRS r2, spsr + MSR cpsr_c, #(SVC_MODE | I_BIT) + STMFD sp!, {r1, r2} + + BL __context_preempt_handler /* Dispatch the interrupt to archTickHandler for + the timer tick interrupt or a simular function + for other interrupts which might call atomthread + functions. */ + + LDMFD sp!, {r1, r2} /* Restore lr_irq and spsr_irq from process stack */ + MSR cpsr_c, #(IRQ_MODE | I_BIT) + STMFD sp!, {r1} + MSR spsr_cxsf, r2 + + MSR cpsr_c, #(SVC_MODE | I_BIT) /* Restore process regs */ + LDMFD sp!, {r0 - r3, ip, lr} + + MSR cpsr_c, #(IRQ_MODE | I_BIT) /* Exit from IRQ */ + LDMFD sp!, {pc}^ + + + diff --git a/ports/arm/types.h b/ports/arm/types.h new file mode 100644 index 0000000..d383d84 --- /dev/null +++ b/ports/arm/types.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +typedef unsigned int uintptr_t ; +typedef int intptr_t ; +typedef unsigned long long uint64_t ; +typedef unsigned int uint32_t ; +typedef unsigned short uint16_t ; +typedef unsigned char uint8_t ; +typedef int int32_t ; +typedef short int16_t ; +typedef char int8_t ; + +// typedef volatile unsigned int REG_DWORD ;// Hardware register definition + +#define UWORD64 unsigned long long +#define UWORD32 unsigned int +#define UWORD16 unsigned short +#define UWORD8 unsigned char +#define WORD32 int +#define WORD16 short +#define WORD8 char + +#ifndef OFFSETOF +#define OFFSETOF(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER) +#endif + +#ifndef INLINE +#define INLINE __inline +#endif + + +#endif /* __TYPES_H__ */ + diff --git a/ports/atomvm/README.txt b/ports/atomvm/README.txt new file mode 100644 index 0000000..7a07533 --- /dev/null +++ b/ports/atomvm/README.txt @@ -0,0 +1,36 @@ +--------------------------------------------------------------------------- + +Library: Atomvn +Author: Natie van Rooyen +License: BSD Revised + +--------------------------------------------------------------------------- + +Atomvm is a tiny virtual machine that can run on Windows inside an IDE with a +debugger like Microsoft Visual C++ Express. The primary purpose of this virtual +machine is for the evaluation of Real Time Operating Systems (like atomthreads) +and the development and testing of modules for this Real Time Operating System +in a user friendly environment. + +--------------------------------------------------------------------------- + +BUILDING THE SOURCE + +To test this project, just add all the files from the "atomthreads/kernel" +directory and the "atomthreads/ports/atomvm" directory as well as the test +program "atomthreads/ports/atomvm/test/main.c" to your project. Add both the +before mentioned directories to the include paths of your project and compile. + +Atomvm was designed for multi core systems but also runs fine on any single +core system. + +--------------------------------------------------------------------------- + +RUNNING THE TESTS + +The test, main.c, is intentioned to stress the virtual machine as opposed to +testing the Real Time Operating System. However, this test can also run the +unit tests of atomthreads by using the preprocessor directive "UNIT_TESTS" and +linking in the desired unit test into the project. + + 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..a4de433 --- /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" +#include "windows.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, (uint32_t*)the_atomvm, CREATE_SUSPENDED, NULL) ; + ResumeThread (cntrl_thread) ; +} + +DWORD WINAPI +cntrl_thread_proc (LPVOID lpParameter) + { + atomvmCtrlRun ((HATOMVM)lpParameter, 0) ; + return 0 ; + } + + +/** + * \b thread_shell + * + * Documented in atomThreads. + * + */ +void +thread_shell (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 () ; + + /* 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 (&tcb_ptr->context, (unsigned int )stack_top, (unsigned int )thread_shell) ; +} + + +/** + * \b archFirstThreadRestore + * + * Documented in atomThreads. + * + */ +void +archFirstThreadRestore(ATOM_TCB * p_sp_new) +{ + atomvmContextSwitch (0, p_sp_new->context) ; +} + + +/** + * \b archContextSwitch + * + * Documented in atomThreads. + * + */ +void +archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) +{ + atomvmContextSwitch (p_sp_old->context, p_sp_new->context) ; +} + + +/** + * \b archTimerTickIrqHandler + * + * System timer tick interrupt handler. + * + */ +void archTimerTickIrqHandler () +{ + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* 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 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..286428a --- /dev/null +++ b/ports/atomvm/atomvm.c @@ -0,0 +1,1016 @@ +/* +* Copyright (c) 2010, Natie van Rooyen. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. No personal names or organizations' names associated with the +* Atomthreads project may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * \file + * Atom Virtual Machine. + * + * + * This module implements the virtual machine. + * + * + * \b Functions contained in this module:\n + * + * \b Function prototypes used for controlling the atom virtual machine: \n + * + * \li atomvmCtrlInit(): . + * \li atomvmCtrlRun(): . + * \li atomvmCtrlIntRequest(): . + * \li atomvmCtrlClose(): . + * + * \b Function prototypes for use by the atom virtual machine: \n + * + * \li atomvmExitCritical(): . + * \li atomvmEnterCritical(): . + * \li atomvmContextCreate(): . + * \li atomvmContextSwitch(): . + * \li atomvmContextDesrtroy(): . + * + * \b Function prototypes to be implemted in the atom virtual machine: \n + * + * \li __atomvmReset(): . + * \li __atomvmClose(): . + * + */ + +#include "atomvm.h" +#include +#include + + + +#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS) + +#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 ; + + +/* ATOMVM_CALLBACK_CONTEXT_SWITCH is the parameter for a ATOMVM_CALLBACK_F call +that take as parameter a pointer to a ATOMVM_CONTEXT to operate on */ +typedef struct ATOMVM_CALLBACK_CONTEXT_SWITCH_S { + + ATOMVM_CALLBACK callback ; + + /* Context the callback function will operate on */ + volatile PATOMVM_CONTEXT p_old_context ; + volatile PATOMVM_CONTEXT p_new_context ; + +} ATOMVM_CALLBACK_CONTEXT_SWITCH, *PATOMVM_CALLBACK_CONTEXT_SWITCH ; + +/* ATOMVM_CALLBACK_IPI is the parameter for a ATOMVM_CALLBACK_F call +that take as parameter a pointer to a ipi target and the isr to call */ +typedef struct ATOMVM_CALLBACK_IPI_S { + + ATOMVM_CALLBACK callback ; + + /* Parameters the callback function will operate on */ + volatile uint32_t target ; + volatile uint32_t isr ; + +} ATOMVM_CALLBACK_IPI, *PATOMVM_CALLBACK_IPI ; + +typedef struct ATOMVM_PERF_COUNTERS_S { + + /* Number of interrupt requests */ + 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 ; + 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(). */ +typedef struct ATOMVM_S { + + uint32_t atomvm_id ; + + /* Thread the virtual machine will run in */ + HANDLE vm_thread ; + + /* Handles to events and mutexes used for synchronization */ + HANDLE atomvm_call ; + HANDLE atomvm_int ; + HANDLE atomvm_int_complete ; + HANDLE atomvm_close ; + HANDLE atomvm_event ; + + /* 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 ; + + +/* Global declarations */ +volatile uint32_t g_atomvm_counter = 0 ; +volatile DWORD g_atomvm_tls_idx ; +PATOMVM g_vms[ATOMVM_MAX_VM] ; + + +/* Forward declaration for the atom virtual machine thread */ +static DWORD WINAPI vm_thread (LPVOID lpParameter) ; + + +/** +* \ingroup atomvm +* \b atomvmCtrlInit +* +* This is an atomvm controll function used by a controlling thread +* 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 = 0 ; + int32_t i ; + + if (g_atomvm_counter < ATOMVM_MAX_VM) { + + patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ; + + if (patomvm) { + + 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 ; + + } + } + + return patomvm != 0 ; +} + + +/** +* \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. +* 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 service_call ; +#if defined DEBUG || defined _DEBUG + BOOL tls_res = +#endif + TlsSetValue (g_atomvm_tls_idx, (void*) atomvm) ; + + + ATOMVM_ASSERT(tls_res, _T("TlsSetValue failed")) ; + + ResumeThread (patomvm->vm_thread) ; + + wait[0] = patomvm->atomvm_call ; + wait[1] = patomvm->atomvm_int ; + wait[2] = patomvm->atomvm_close ; + + for(;;) { + + wait_object = WaitForMultipleObjects (3, wait,FALSE,INFINITE) ; + + if (wait_object == WAIT_OBJECT_0) { + + ATOMVM_ATOMVM_PERF_COUNTER(patomvm, service_call) ; + + service_call = patomvm->service_call ; + while (!service_call->lock) { + SwitchToThread () ; + } + + while ((res = SuspendThread (patomvm->vm_thread)) == (DWORD)-1) ; + ATOMVM_ASSERT(res == 0 , _T("SuspendThread failed")) ; +#if (_WIN32_WINNT >= 0x0600) + /* + This is used for multi processor machines to ensure the thread + is stopped before executing the next instruction. */ + FlushProcessWriteBuffers (); +#endif + InterlockedExchange (&service_call->result, service_call->callback (patomvm, service_call)) ; + InterlockedExchange (&service_call->lock, 0) ; + ResetEvent (patomvm->atomvm_call) ; + res = ResumeThread (patomvm->vm_thread) ; + ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ; + + + } + + else if (wait_object == WAIT_OBJECT_0 + 1) { + + if (patomvm->current_context->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")) ; + + ResetEvent (patomvm->atomvm_int) ; + InterlockedExchange ((volatile uint32_t*)&patomvm->isr, 0) ; + SetEvent (patomvm->atomvm_int_complete) ; + + } else { + + res = ResumeThread (patomvm->vm_thread) ; + ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ; + SwitchToThread () ; + + } + + } else { + + SwitchToThread () ; + + } + + } else if (wait_object == WAIT_OBJECT_0 + 2) { + + break ; + + } else { + + ATOMVM_ASSERT(res == 1 , _T("WaitForMultipleObjects failed")) ; + + } + + } + +} + + +/** +* \ingroup atomvm +* \b atomvmCtrlClose +* +* This is an atomvm controll function used by a controlling thread +* and must not be called from the atom virtual machine. +* +* Closes the virtual machine and release all memory and handles created +* in 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) ; + + TlsFree (g_atomvm_tls_idx) ; + + free (atomvm) ; +} + + +/** +* \b invokeCallback +* +* Invokes callback functions in the context of the controll thread as +* requested from the virtual machine. In case this callback came from inside, +* an isr it is already in the conrtext of the controll thread and the callback +* routine is called directly. +* +* The atom virtual machine 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 getAtomvm +* +* Get the atomvm instance for the calling thredd +* +* @return atomvm instance +*/ +__inline PATOMVM +getAtomvm () +{ + PATOMVM patomvm = (PATOMVM) TlsGetValue (g_atomvm_tls_idx) ; + + ATOMVM_ASSERT(patomvm , _T("TlsGetValue failed")) ; + + return patomvm ; + +} + + +/** +* \ingroup atomvm +* \b atomvmExitCritical +* +* This function is to be used by the atom virtual machine. +* +* 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. +* +* @return Critical count before the function call. +*/ +int32_t +atomvmExitCritical () +{ + PATOMVM patomvm = getAtomvm () ; + int32_t count = 0; + + if (patomvm->status_isr == 0) { + count = InterlockedDecrement (&patomvm->current_context->critical_count) ; + } + + 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 ; +} + + +/** +* \ingroup atomvm +* \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 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. +* +* @return None +*/ +void +atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr) +{ + PATOMVM patomvm = (PATOMVM) atomvm ; + + WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; + while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) != 0) { + SwitchToThread() ; + } + SetEvent (patomvm->atomvm_int) ; + +} + + +/** +* \b callbackContextCreate +* +* This function is invoked from the controll thread after a call to atomvmContextCreate. +* +* The atom virtual machine is suspended while this function is called. +* +* @param[in] patomvm Pointer to the virtual machine created by 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) ; +} + + +/** +* \ingroup atomvm +* \b atomvmContextCreate +* +* This function is to be used by the atom virtual machine. +* +* This function creates a atomvm thread context that can be scheduled +* by atomvmContextSwitch. +* +* @param[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_CONTEXT* atomvm_context, uint32_t stack, uint32_t entry) +{ + uint32_t res ; + PATOMVM patomvm = getAtomvm () ; + PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)malloc (sizeof(ATOMVM_CONTEXT)) ; + CONTEXT* pcontext = &new_context->context ; + ATOMVM_CALLBACK_CONTEXT context_init ; + + context_init.pcontext = new_context ; + + new_context->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 = 1 ; + uint32_t res2 ; + PATOMVM_CALLBACK_CONTEXT_SWITCH context_switch = (PATOMVM_CALLBACK_CONTEXT_SWITCH)callback ; + CONTEXT* p_old_context = &context_switch->p_old_context->context ; + CONTEXT* p_new_context = &context_switch->p_new_context->context ; + + 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")) ; + } + + InterlockedExchange ((volatile uint32_t*)&patomvm->current_context, (uint32_t)p_new_context) ; + res2 = SetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ; + ATOMVM_ASSERT(res2 , _T("SetThreadContext failed")) ; + + return res1 & res2 ; +} + + +/** +* \ingroup atomvm +* \b atomvmContextSwitch +* +* This function is to be used by the atom virtual machine. +* +* This function schedules a thread for the context created by atomvmContextCreate. +* +* @param[in] new_context The context to schedule. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context) +{ + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK_CONTEXT_SWITCH context_switch ; + + context_switch.p_old_context = (PATOMVM_CONTEXT) old_context ; + context_switch.p_new_context = (PATOMVM_CONTEXT) new_context ; + + return invokeCallback (patomvm, callbackContextSwitch, (PATOMVM_CALLBACK)&context_switch) ; +} + +/** +* \ingroup atomvm +* \b atomvmContextDesrtroy +* +* This function is to be used by the atom virtual machine. +* +* This functiondestroyes a atomvm context created by atomvmContextCreate. +* +* @param[in] context The context to destroy. +* +* @return None +*/ +void +atomvmContextDesrtroy (HATOMVM_CONTEXT context) +{ + PATOMVM patomvm = getAtomvm () ; + + ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context, + _T("atomvmContextDesrtroy failed")) ; + + free((void*)context) ; +} + +/** +* \ingroup atomvm +* \b atomvmWriteThreadId +* +* Write a thread ID. +* +* Write a thread ID for the current context. +* +* @param[in] thread_id thread_id. +* +* @return None +*/ +void +atomvmWriteThreadId (uint32_t thread_id) +{ + PATOMVM patomvm = getAtomvm () ; + + patomvm->current_context->thread_id = thread_id ; +} + +/** +* \ingroup atomvm +* \b atomvmReadThreadId +* +* Write a thread ID. +* +* Read a thread ID for the current context. +* +* @return thread_id +*/ +uint32_t +atomvmReadThreadId () +{ + PATOMVM patomvm = getAtomvm () ; + + return patomvm->current_context->thread_id ; +} + + +/** +* \ingroup atomvm +* \b atomvmGetVmId +* +* Returns an identifier for the virtual machine. This is zero for the first +* virtual machine created with atomvmCtrlInit(), 1 for the second and so on. +* +* @return The atom vm ID +*/ +uint32_t +atomvmGetVmId () +{ + PATOMVM patomvm = getAtomvm () ; + + return patomvm->atomvm_id ; +} +/** +* \b callbackEventWait +* +* This function is invoked from the controll thread after a call to atomvmEventWait. +* +* The atom virtual machine is suspended while this function is called. +* +* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @param[out] context Context to be scheduled. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +callbackEventWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) +{ + return WaitForSingleObject (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 +* +* This function is invoked from the controll thread after a call to atomvmInterruptWait(). +* +* The atom virtual machine is suspended while this function is called. +* +* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit. +* @param[out] callback Callback parameter. +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +callbackInterruptWait (PATOMVM patomvm, PATOMVM_CALLBACK callback) +{ + WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ; + return WaitForSingleObject (patomvm->atomvm_int, INFINITE) == WAIT_OBJECT_0 ; +} + +/** +* \ingroup atomvm +* \b atomvmInterruptWait +* +* This function is to be used by the atom virtual machine. +* +* This function if for synchronization between multiple +* atom vms. +* +* +* @return void. +*/ +void +atomvmInterruptWait () +{ + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK callback ; + + invokeCallback (patomvm, callbackInterruptWait, (PATOMVM_CALLBACK)&callback) ; +} + +/** +* \ingroup atomvm +* \b callbackScheduleIpi +* +* This function is invoked from the controll thread after a call to atomvmScheduleIpi(). +* +* This function if for synchronization between multiple +* atom vms. +* +* @param[in] target Target atomvm ID, less than ATOMVM_MAX_VM +* @param[in] isr interrupt service routine +* +* @return Zero on failure, try to call GetLastError(). +*/ +uint32_t +callbackScheduleIpi (PATOMVM patomvm, PATOMVM_CALLBACK callback) +{ + PATOMVM_CALLBACK_IPI callback_ipi = (PATOMVM_CALLBACK_IPI)callback ; + uint32_t res = 0 ; + + if ((callback_ipi->target < ATOMVM_MAX_VM) && + (g_vms[callback_ipi->target] != patomvm) ) { + + atomvmCtrlIntRequest ((HATOMVM)g_vms[callback_ipi->target], callback_ipi->isr) ; + res = 1 ; + + } + + return res ; +} + + +/** +* \ingroup atomvm +* \b atomvmScheduleIpi +* +* This function is to be used by the atom virtual machine. +* +* This function if for synchronization between multiple +* atom vms. +* +* @param[in] target Target atomvm ID +* @param[in] isr interrupt service routine +* +* @return Zero on failure, the vm is not running. +*/ +uint32_t +atomvmScheduleIpi (uint32_t target, uintptr_t isr) +{ + PATOMVM patomvm = getAtomvm () ; + ATOMVM_CALLBACK_IPI callback ; + + callback.target = target ; + callback.isr = isr ; + + return invokeCallback (patomvm, callbackScheduleIpi, (PATOMVM_CALLBACK)&callback) ; + + +} + + +/** +* \b vm_thread +* +* Windows thread in which the atom virtual machine will execute. +* +* __atomvmReset() runs the virtual machie and should only return after +* __atomvmClose() was called. +* +* @return None. +*/ +DWORD WINAPI +vm_thread (LPVOID lpParameter) +{ + BOOL res = TlsSetValue (g_atomvm_tls_idx, lpParameter) ; + + ATOMVM_ASSERT(res, _T("TlsSetValue failed")) ; + __atomvmReset () ; + return 0 ; +} diff --git a/ports/atomvm/atomvm.h b/ports/atomvm/atomvm.h new file mode 100644 index 0000000..0b61570 --- /dev/null +++ b/ports/atomvm/atomvm.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2010, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + + +/** \mainpage \ref atomvm +* \defgroup atomvm Atomvm API +* +* @authors Natie van Rooyen +* +* @section intro Introduction +* Atomvm is a tiny virtual machine that can run on Windows inside an IDE with a +* debugger like Microsoft Visual C++ Express. The primary purpose of this virtual +* machine is for the evaluation of Real Time Operating Systems (like atomthreads) +* and the development and testing of modules for this Real Time Operating System +* in a user friendly environment.: +* +* @section build Building The Source +* To test this project, just add all the files from the "atomthreads/kernel" +* directory and the "atomthreads/ports/atomvm" directory as well as the test +* program main.c to your project. Add both the +* before mentioned directories to the include paths of your project and compile. \n +* Atomvm was designed for multi core systems but also runs fine on any single +* core system. +* +* @section test Running The Test +* The test, main.c, is intentioned to stress the virtual machine as opposed to +* testing the Real Time Operating System. However, this test can also run the +* unit tests of atomthreads by using the preprocessor directive "UNIT_TESTS" and +* linking in the desired unit test into the project. +* */ + +#ifndef __ATOMVM_H__ +#define __ATOMVM_H__ + +#include +#include "atomuser.h" + + +#if defined _DEBUG || defined DEBUG +#define ATOMVM_ASSERT(x, msg) _ASSERT((x)) +#else +#define ATOMVM_ASSERT(x, msg) +#endif + + +#define ATOMVM_MAX_VM 8 + +/* Forward declarations */ + +/* This is an opaque handle to an instance of an atomvm created + by a call to 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 () ; +extern int32_t atomvmEnterCritical () ; +extern int32_t atomvmCriticalCount () ; +extern uint32_t atomvmContextCreate (HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ; +extern uint32_t atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context) ; +extern void atomvmContextDesrtroy (HATOMVM_CONTEXT context) ; +extern void atomvmWriteThreadId (uint32_t thread_id) ; +extern uint32_t atomvmReadThreadId () ; +/* Function prototypes for use by the atom virtual machine + for synchronization with other running atom virtual machines */ +extern uint32_t atomvmGetVmId () ; +extern void atomvmInterruptWait () ; +extern void atomvmEventWait () ; +extern void atomvmEventSend () ; +extern uint32_t atomvmScheduleIpi (uint32_t target, uintptr_t isr) ; + + + + +/** +* \ingroup atomvm +* \b __atomvmReset +* +* Function prototype to be implemted in the atom virtual machine +* +* @return void. +*/ +extern void __atomvmReset (void) ; +/** +* \ingroup atomvm +* \b __atomvmClose +* +* Function prototype to be implemted in the atom virtual machine +* +* @return void. +*/ +extern void __atomvmClose (void) ; + +#endif /* __ATOMVM_H__ */ diff --git a/ports/atomvm/test/main.c b/ports/atomvm/test/main.c new file mode 100644 index 0000000..4bd4efb --- /dev/null +++ b/ports/atomvm/test/main.c @@ -0,0 +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 +License: BSD Revised + +--------------------------------------------------------------------------- + +ARM CortexM3 PORT + +This folder contains a port of the Atomthreads real time kernel for the +ARM CortexM3 processor architecture. + +To Use: + +1. Install the "pendSV_Handler" and "tick_Handler" implemented in the file + "atomport_arm.asm" in your platforms interrupt vectors. + +2. Complete the function "archTickInit()" implemented in "atomport.c" to + initialize your platforms timer tick interrupt. If you use the build in + SysTick of the CortexM3 you also have to add code here to start it. + +3. If required, add code to acknowledge your timer hardware's interrupt in + the function "archTickHandler()" also implemented in "atomport.c". + +4. During your platform initialization call the function "archTickInit()" + exported from "atomport_private.h" to initialize the CortexM3 + "PendSV_Handler". + +5. After your platforms c-runtime initialization has completed, start + Atomthreads from your runtime's "main()" function. \ No newline at end of file diff --git a/ports/cortex_m/atomport-tests.h b/ports/cortex_m/atomport-tests.h new file mode 100644 index 0000000..cfb909a --- /dev/null +++ b/ports/cortex_m/atomport-tests.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOMPORT_TEST_H__ +#define __ATOMPORT_TEST_H__ + +/* Include Atomthreads kernel API */ +#include "atom.h" + +extern void dbg_format_msg (char *format, ...) ; + + +#define TEST_THREAD_STACK_SIZE 1024 +#define ATOMLOG dbg_format_msg +#define _STR(x) x + + + + +/* API for starting each test */ +extern uint32_t test_start (void); + + +#endif /* __ATOMPORT_TEST_H__ */ diff --git a/ports/cortex_m/atomport.c b/ports/cortex_m/atomport.c new file mode 100644 index 0000000..6d6fc6a --- /dev/null +++ b/ports/cortex_m/atomport.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "atom.h" +#include "atomport.h" +#include "types.h" + + +/* * + * + * Functions defined in atomport_s.S + * + */ +typedef void * SYSCONTEXT ; + +extern void contextInit (void) ; +extern void contextSwitch (SYSCONTEXT* save_context, SYSCONTEXT* new_context) ; +extern void contextStart (SYSCONTEXT* context) ; +extern void contextEnableInterrupts (void) ; + +/** + * \b thread_shell + * + * Documented in atomThreads. + * + */ +void +thread_shell (void) +{ + ATOM_TCB *curr_tcb; + + /* Get the TCB of the thread being started */ + curr_tcb = atomCurrentContext(); + + /** + * Enable interrupts - these will not be enabled when a thread + * is first restored. + */ + // sei(); + contextEnableInterrupts () ; + + /* Call the thread entry point */ + if (curr_tcb && curr_tcb->entry_point) + { + curr_tcb->entry_point(curr_tcb->entry_param); + } + + /* Not reached - threads should never return from the entry point */ +} + + +/** + * \b archThreadContextInit + * + * Documented in atomThreads. + * + */ +void +archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param) +{ + uint32_t * stack_ptr ; + + tcb_ptr->sp_save_ptr = stack_top; + tcb_ptr->entry_param = entry_param ; + tcb_ptr->entry_point = entry_point ; + + stack_ptr = (uint32_t *)stack_top; //-- Load stack pointer + + *stack_ptr = 0x01000000L; //-- xPSR + stack_ptr--; + *stack_ptr = ((uint32_t)thread_shell) | 1; //-- Entry Point (1 for THUMB mode) + stack_ptr--; + *stack_ptr = ((uint32_t)/*exit*/0) | 1; //-- R14 (LR) (1 for THUMB mode) + stack_ptr--; + *stack_ptr = 0x00121212L; //-- R12 + stack_ptr--; + *stack_ptr = 0x00030303L; //-- R3 + stack_ptr--; + *stack_ptr = 0x00020202L; //-- R2 + stack_ptr--; + *stack_ptr = 0x00010101L; //-- R1 + stack_ptr--; + *stack_ptr = entry_param ; //-- R0 - task's function argument + stack_ptr--; + *stack_ptr = 0x00111111L; //-- R11 + stack_ptr--; + *stack_ptr = 0x00101010L; //-- R10 + stack_ptr--; + *stack_ptr = 0x00090909L; //-- R9 + stack_ptr--; + *stack_ptr = 0x00080808L; //-- R8 + stack_ptr--; + *stack_ptr = 0x00070707L; //-- R7 + stack_ptr--; + *stack_ptr = 0x00060606L; //-- R6 + stack_ptr--; + *stack_ptr = 0x00050505L; //-- R5 + stack_ptr--; + *stack_ptr = 0x00040404L; //-- R4 + + tcb_ptr->sp_save_ptr = stack_ptr ; +} + + +/** + * \b archFirstThreadRestore + * + * Documented in atomThreads. + * + */ +void +archFirstThreadRestore(ATOM_TCB * p_sp_new) +{ + contextStart (&p_sp_new->sp_save_ptr) ; +} + + +/** + * \b archContextSwitch + * + * Documented in atomThreads. + * + */ +void +archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new) +{ + contextSwitch (&p_sp_old->sp_save_ptr, &p_sp_new->sp_save_ptr) ; +} + + +/** + * \b archTimerTickIrqHandler + * + * System timer tick interrupt handler. + * + */ +void +archTickHandler (void) +{ + atomIntEnter(); + + /* Call the OS system tick handler */ + atomTimerTick(); + + /* ack the interrupt if needed */ + /* ... */ + + /* Call the interrupt exit routine */ + atomIntExit(TRUE); +} + +/** + * \b archTickInit + * + * System timer initialization. + * + */ +void +archTickInit (void) +{ + /* Initialize NVIC PendSV */ + contextInit () ; + + /* Initializa Timer Hardware */ + /* ... */ +} + + diff --git a/ports/cortex_m/atomport.h b/ports/cortex_m/atomport.h new file mode 100644 index 0000000..39bd0c0 --- /dev/null +++ b/ports/cortex_m/atomport.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOM_PORT_H__ +#define __ATOM_PORT_H__ + +#include "types.h" + +#define SYSTEM_TICKS_PER_SEC 100 + + +/** + * Architecture-specific types. + * Most of these are available from types.h on this platform, which is + * included above. + */ +#define POINTER void * + +/* * + * + * Functions defined in atomport_arm.asm + * + */ +extern uint32_t contextEnterCritical (void) ; +extern void contextExitCritical (uint32_t posture) ; + + +/* Critical region protection */ +#define CRITICAL_STORE uint32_t __atom_critical +#define CRITICAL_START() __atom_critical = contextEnterCritical() +#define CRITICAL_END() contextExitCritical(__atom_critical) + +#endif /* __ATOM_PORT_H__ */ diff --git a/ports/cortex_m/atomport_private.h b/ports/cortex_m/atomport_private.h new file mode 100644 index 0000000..0f4a004 --- /dev/null +++ b/ports/cortex_m/atomport_private.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOM_PORT_PRIVATE_H__ +#define __ATOM_PORT_PRIVATE_H__ + + +/* Function prototypes */ +extern void archTickHandler (void) ; +extern void archTickInit (void) ; + +#endif /* __ATOM_PORT_PRIVATE_H__ */ diff --git a/ports/cortex_m/atomport_s.S b/ports/cortex_m/atomport_s.S new file mode 100644 index 0000000..46c3138 --- /dev/null +++ b/ports/cortex_m/atomport_s.S @@ -0,0 +1,220 @@ +/* + Copyright (c) 2012, Natie van Rooyen. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. No personal names or organizations' names associated with the + Atomthreads project may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + + +.global contextInit +.global contextSwitch +.global contextStart +.global contextEnableInterrupts +.global contextEnterCritical +.global contextExitCritical +.global pendSV_Handler +.global tick_Handler + +.global archTickHandler + + + +/**/ +.equ NVIC_INT_CTRL, 0xE000ED04 // Interrupt control state register +.equ NVIC_PENDSVSET, 0x10000000 // Value to trigger PendSV exception +.equ NVIC_PR_12_15_ADDR, 0xE000ED20 // System Handlers 12-15 Priority Register Address +.equ NVIC_PENDS_VPRIORITY, 0x00FF0000 // PendSV priority is minimal (0xFF) + +.syntax unified +.text +.thumb + +/** + * \b contextInit + * + * Architecture-specific one time initialization. + * + * Configures PendSV priority to lowest. + * + * @return None + */ +contextInit: + LDR r1, =NVIC_PR_12_15_ADDR // Load the System 12-15 Priority Register + LDR r0, [r1] + ORR r0, r0, #NVIC_PENDS_VPRIORITY // set PRI_14 (PendSV) to 0xFF - minimal + STR r0, [r1] + + BX lr + +/** + * \b contextSwitch + * + * Architecture-specific context switch routine. + * + * Note that interrupts are always locked out when this routine is + * called. For cooperative switches, the scheduler will have entered + * a critical region. For preemptions (called from an ISR), the + * interrupts will have disabled in the tick_Handler. + * + * @param[in] [r0] -> Address to save old stack pointer + * @param[in] [r1] -> Address where new stack pointer is stored + * + * @return None + */ +contextSwitch: + LDR r2, =context_new_stack_ptr + STR r1, [r2] + + LDR r2, =context_save_stack_ptr + LDR r1, [r2] + CMP r1, #0 // if contextSwitch is going to be called again before pend_sv + IT EQ + STREQ r0, [r2] + + LDR R0, =NVIC_INT_CTRL // Trigger the PendSV exception (causes context switch) + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + + BX lr + +/** + * \b contextStart + * + * Architecture-specific context start routine. + * + * @param[in] [r0] -> Address where stack pointer is stored + * + * @return Does not return + */ +contextStart: + LDR r1, =context_new_stack_ptr + STR r0, [r1] + LDR r1, =context_save_stack_ptr + MOV r0, #0 + STR r0, [r1] + LDR r0, =NVIC_INT_CTRL // Trigger the PendSV exception (causes context switch) + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + BX lr + +/** + * \b contextEnableInterrupts + * + * Enables interrupts on the processor + * + * @return None + */ +contextEnableInterrupts: + CPSIE i + BX lr + + +/** + * \b contextExitCritical + * + * Exit critical section (restores interrupt posture) + * + * @param[in] r0 Interrupt Posture + * + * @return None + */ +contextExitCritical: + MSR PRIMASK, r0 + BX lr + + +/** + * \b contextEnterCritical + * + * Enter critical section (disables interrupts) + * + * @return Current interrupt posture + */ +contextEnterCritical: + MRS r0, PRIMASK + CPSID i + BX lr + +/** + * \b PendSV_Handler + * + * CortexM3 PendSV_Handler. Switch context to a new stack. + * + * @return None + */ +pendSV_Handler: + CPSID i // Disable core int + + LDR r1, =context_save_stack_ptr + LDR r0, [r1] // Load old (current) stack pointer address + + LDR r2, =context_new_stack_ptr + LDR r2, [r2] // Load new stack pointer address + CMP r0, r2 + BEQ pendsv_handler_exit + + CMP r0, #0 + BEQ pendsv_handler_new_stack + // Save context + MRS r3, PSP // Get PSP point + STMDB r3!, {R4-R11} // Store r4-r11 + STR r3, [r0] // Save old stack pointer + MOV r3, #0 + STR r3, [r1] + +pendsv_handler_new_stack: + // Restore context + LDR r2, [r2] // Load new stack pointer + LDMIA r2!, {r4-r11} // Restore context + MSR PSP, r2 // Mov new stack point to PSP + +pendsv_handler_exit: + CPSIE i // Enable core int + + ORR lr, lr, #0x04 // Ensure exception return uses process stack + BX lr // Exit interrupt + + +/** + * \b Tick_Handler + * + * System timer tick interrupt handler. + * + * @return None + */ +tick_Handler: + PUSH {r4-r11, lr} + cpsid I // Disable core int + BL archTickHandler + cpsie I // Enable core int + POP {r4-r11, pc} + + +/**/ +context_new_stack_ptr: .long 0x00000000 +context_save_stack_ptr: .long 0x00000000 + + diff --git a/ports/cortex_m/types.h b/ports/cortex_m/types.h new file mode 100644 index 0000000..82317f7 --- /dev/null +++ b/ports/cortex_m/types.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, Natie van Rooyen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +typedef unsigned int uintptr_t ; +typedef int intptr_t ; +typedef unsigned long long uint64_t ; +typedef unsigned int uint32_t ; +typedef unsigned short uint16_t ; +typedef unsigned char uint8_t ; +typedef int int32_t ; +typedef short int16_t ; +typedef char int8_t ; + +#endif /* __TYPES_H__ */ +