diff options
Diffstat (limited to 'core.c')
| -rw-r--r-- | core.c | 319 |
1 files changed, 319 insertions, 0 deletions
@@ -0,0 +1,319 @@ +/************************************************************************/ +/* */ +/* File: core.c */ +/* Description: kernel entry point */ +/* Version: 1.0 */ +/* Author: Otto Mattik */ +/* */ +/* (C)Copyright Otto Mattik 2014-2021. */ +/* */ +/* This file is a part of 'armen' (a tiny operating system). */ +/* 'armen' is distributed under the CeCILL-V2.1 licence. For more */ +/* details about this licence, please visit the website cecill.info */ +/* */ +/************************************************************************/ + +#include "core.h" + +static uint32_t _time; + +extern void* main( void* ); + +/* + * called from armen_start (see assembly code) + * + * input: + * ram_start beginning of free ram + * ram_end end of ram + * output: +*/ +void _sys_init( void* ram_start, void* ram_end ) +{ + register uint8_t i; + register uint16_t stack_per_thread; + register void* stack; + + /* + * initialize stacks in table of threads + */ + stack_per_thread = (ram_end - ram_start - IDLE_STACK_SIZE) / (ARMEN_THREADS - 1); + stack = ram_end; + for( i = 1; i < ARMEN_THREADS; i++ ) + { + _threads[i].istack = stack; + stack -= stack_per_thread; + } + + /* + * thread0 = idle + */ + _threads[0].istack = stack; + _threads[0].cstack = _init_context( _idle, 0, stack ); + _threads[0].rank = + _threads[0].order = 255; + _threads[0].entry = _idle; + _threads[0].status = TS_RUNNING; + + /* + * thread1 = main + */ + _threads[1].cstack = _threads[1].istack; + _threads[1].rank = 127; + _threads[1].entry = main; + _threads[1].status = TS_RUNNING; + _cur_thread = 1; + +#if defined(UART) && (UART != 0) + _uart_init( ); +#endif +} + +/* + * called by timer every millisecond (see assembly code) + * + * input: + * output: +*/ +void _sys_clock( void ) +{ + register uint8_t i; + register _thread_t* pthread; + + ++_time; + + /* + * update priorities + */ + for( i = 1; i < ARMEN_THREADS; i++ ) + { + pthread = &_threads[i]; + + if( pthread->status == TS_UNUSED ) + continue; + if( pthread->status == TS_RUNNING ) + { + if( i == _cur_thread ) + { + if( pthread->order != 254 ) + ++pthread->order; + } + else + { + if( pthread->order != 0 ) + --pthread->order; + } + } + + /* + * update thread timer(s) + */ + else + { + if( pthread->timer1 != 0 && --pthread->timer1 == 0 + && (pthread->events & EVENT_TIMER1) != 0 + ) + { + pthread->events &= ~EVENT_TIMER1; + pthread->event |= EVENT_TIMER1; + pthread->order = 0; + pthread->status = TS_RUNNING; + } +#if (ARMEN_TIMERS == 2) + if( pthread->timer2 != 0 && --pthread->timer2 == 0 + && (pthread->events & EVENT_TIMER2) != 0 + ) + { + pthread->events &= ~EVENT_TIMER2; + pthread->event |= EVENT_TIMER2; + pthread->order = 0; + pthread->status = TS_RUNNING; + } +#endif + } + } +} + +/* + * thread election + * + * input: + * sp current value of stack pointer + * output: +*/ +void _scheduler( void* sp ) +{ + register uint8_t i, rank, order, elected; + register _thread_t* pthread; + + elected = 0; + rank = order = 255; + _threads[_cur_thread].cstack = sp; + for( i = 1; i < ARMEN_THREADS; i++ ) + { + pthread = &_threads[i]; + + if( pthread->status != TS_RUNNING + || pthread->order > order + || (pthread->order == order && pthread->rank > rank ) ) + continue; + elected = i; + rank = pthread->rank; + order = pthread->order; + } + + if( elected != _cur_thread ) + { + _cur_thread = elected; + _restore_context( _threads[elected].cstack ); + /* no return */ + } +} + +/* + * get current time (milliseconds since start-up) + * + * input: + * output: + * count of milliseconds +*/ +uint32_t get_time( void ) +{ + return( _time ); +} + +/* + * suspend execution of the calling thread + * + * input: + * events mask of events + * output: + * event occured +*/ +uint16_t wait_event( uint16_t events ) +{ + uint16_t ret = 0; + + if( events != 0 ) + { + do + { + _disable_intr( ); + _threads[_cur_thread].events |= events; + _threads[_cur_thread].status = TS_SUSPENDED; + _schedule( ); + } + while( (_threads[_cur_thread].event & events) == 0 ) ; + + ret = _threads[_cur_thread].event & events; + _threads[_cur_thread].event &= ~events; + } + return( ret ); +} + +/* + * current value of timer + * + * input: + * timer timer identifier + * output: + * timer value if success, otherwise -1 +*/ +timer_t get_timer( uint8_t timer ) +{ +#ifdef CHECK_PARAM + if( timer < 1 || timer > ARMEN_TIMERS ) + return( (timer_t)-1 ); +#endif +#if (ARMEN_TIMERS == 2) + if( timer == 2 ) + return( _threads[_cur_thread].timer2 ); +#endif + return( _threads[_cur_thread].timer1 ); +} + +/* + * suspend current thread during a period + * + * input: + * timer timer identifier + * msecs period in milliseconds + * output: + * 0 if success, otherwise -1 +*/ +int8_t set_timer( uint8_t timer, timer_t msecs ) +{ +#ifdef CHECK_PARAM + if( timer < 1 || timer > ARMEN_TIMERS ) + return( -1 ); +#endif +#if (ARMEN_TIMERS == 2) + if( timer == 2 ) + { + _threads[_cur_thread].timer2 = msecs; + if( msecs != 0 ) + _threads[_cur_thread].events &= ~EVENT_TIMER2; + else + _threads[_cur_thread].events |= EVENT_TIMER2; + } + else +#endif + { + _threads[_cur_thread].timer1 = msecs; + if( msecs != 0 ) + _threads[_cur_thread].events &= ~EVENT_TIMER1; + else + _threads[_cur_thread].events |= EVENT_TIMER1; + } + return( 0 ); +} +void sleep( timer_t msecs ) +{ + if( msecs != 0 ) + { + _threads[_cur_thread].events |= EVENT_TIMER1; + _threads[_cur_thread].timer1 = msecs; + wait_event( EVENT_TIMER1 ); + } +} + +/* + * wake up thread(s) on event + * + * input: + * event reason for wake up + * param depends on event + * output: +*/ +void _wakeup( uint16_t event, void* param ) +{ + register uint8_t i; + register _thread_t* pthread; + + for( i = 1; i < ARMEN_THREADS; i++ ) + { + pthread = &_threads[i]; + + if( pthread->status != TS_SUSPENDED + || (pthread->events & event) == 0 +#if defined(USE_SEM) + || (event == EVENT_SEM && pthread->sem != param) +#endif + || (event == EVENT_JOIN && pthread->joinid != _cur_thread) ) + continue; + + if( event == EVENT_JOIN ) + pthread->param = param; + pthread->events &= ~event; + pthread->event |= event; + pthread->order = 0; + pthread->status = TS_RUNNING; + } +} +void send_user_event( void ) +{ + register uint8_t iflag; + + iflag = _disable_intr( ); + _wakeup( EVENT_USER, 0 ); + _enable_intr( iflag ); +} |
