aboutsummaryrefslogtreecommitdiff
path: root/core.c
diff options
context:
space:
mode:
authorOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
committerOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
commitda34d97efb21719b2b332f8c60b2750d11bcde1f (patch)
tree2de9fe89f6d79b8ebfcde64c5e86204e904aedf2 /core.c
downloadarmen-master.tar.gz
armen-master.zip
git: update to v1.0HEADv1.0master
Diffstat (limited to 'core.c')
-rw-r--r--core.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/core.c b/core.c
new file mode 100644
index 0000000..6b00e3b
--- /dev/null
+++ b/core.c
@@ -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 );
+}