Mark3 Realtime Kernel
threadport.cpp
Go to the documentation of this file.
1 /*===========================================================================
2  _____ _____ _____ _____
3  ___| _|__ __|_ |__ __|__ |__ __| __ |__ ______
4 | \ / | || \ || | || |/ / ||___ |
5 | \/ | || \ || \ || \ ||___ |
6 |__/\__/|__|_||__|\__\ __||__|\__\ __||__|\__\ __||______|
7  |_____| |_____| |_____| |_____|
8 
9 --[Mark3 Realtime Platform]--------------------------------------------------
10 
11 Copyright (c) 2012 - 2019 m0slevin, all rights reserved.
12 See license.txt for more information
13 ===========================================================================*/
22 #include "kerneltypes.h"
23 #include "mark3cfg.h"
24 #include "thread.h"
25 #include "threadport.h"
26 #include "kernelswi.h"
27 #include "kerneltimer.h"
28 #include "timerlist.h"
29 #include "quantum.h"
30 #include "kernel.h"
31 #include <avr/io.h>
32 #include <avr/interrupt.h>
33 
34 extern "C" {
37 } // extern "C"
38 
39 //---------------------------------------------------------------------------
40 namespace Mark3
41 {
42 //---------------------------------------------------------------------------
43 void ThreadPort::InitStack(Thread* pclThread_)
44 {
45  // Initialize the stack for a Thread
46  uint16_t u16Addr;
47  uint8_t* pu8Stack;
48  uint16_t i;
49 
50  // Get the address of the thread's entry function
51  u16Addr = (uint16_t)(pclThread_->m_pfEntryPoint);
52 
53  // Start by finding the bottom of the stack
54  pu8Stack = (uint8_t*)pclThread_->m_pwStackTop;
55 
57  // clear the stack, and initialize it to a known-default value (easier
58  // to debug when things go sour with stack corruption or overflow)
59  for (i = 0; i < pclThread_->m_u16StackSize; i++) { pclThread_->m_pwStack[i] = 0xFF; }
60 #endif // #if KERNEL_STACK_CHECK
61 
62  // Our context starts with the entry function
63  PORT_PUSH_TO_STACK(pu8Stack, (uint8_t)(u16Addr & 0x00FF));
64  PORT_PUSH_TO_STACK(pu8Stack, (uint8_t)((u16Addr >> 8) & 0x00FF));
65 
66  // R0
67  PORT_PUSH_TO_STACK(pu8Stack, 0x00); // R0
68 
69  // Push status register and R1 (which is used as a constant zero)
70  PORT_PUSH_TO_STACK(pu8Stack, 0x80); // SR
71  PORT_PUSH_TO_STACK(pu8Stack, 0x00); // R1
72 
73  // Push other registers
74  for (i = 2; i <= 23; i++) // R2-R23
75  {
76  PORT_PUSH_TO_STACK(pu8Stack, i);
77  }
78 
79  // Assume that the argument is the only stack variable
80  PORT_PUSH_TO_STACK(pu8Stack, (uint8_t)(((uint16_t)(pclThread_->m_pvArg)) & 0x00FF)); // R24
81  PORT_PUSH_TO_STACK(pu8Stack, (uint8_t)((((uint16_t)(pclThread_->m_pvArg)) >> 8) & 0x00FF)); // R25
82 
83  // Push the rest of the registers in the context
84  for (i = 26; i <= 31; i++) { PORT_PUSH_TO_STACK(pu8Stack, i); }
85 
86  PORT_PUSH_TO_STACK(pu8Stack, 0x00); // RAMPZ
87  // Set the top o' the stack.
88  pclThread_->m_pwStackTop = (uint8_t*)pu8Stack;
89 
90  // That's it! the thread is ready to run now.
91 }
92 
93 //---------------------------------------------------------------------------
94 static void Thread_Switch(void)
95 {
97 }
98 
99 //---------------------------------------------------------------------------
101 {
102  KernelSWI::Config(); // configure the task switch SWI
103  KernelTimer::Config(); // configure the kernel timer
104 
105  // Tell the kernel that we're ready to start scheduling threads
106  // for the first time.
108 
109  Scheduler::SetScheduler(1); // enable the scheduler
110  Scheduler::Schedule(); // run the scheduler - determine the first thread to run
111 
112  Thread_Switch(); // Set the next scheduled thread to the current thread
113 
114  KernelTimer::Start(); // enable the kernel timer
115  KernelSWI::Start(); // enable the task switch SWI
116 
117 #if KERNEL_ROUND_ROBIN
118  // Restart the thread quantum timer, as any value held prior to starting
119  // the kernel will be invalid. This fixes a bug where multiple threads
120  // started with the highest priority before starting the kernel causes problems
121  // until the running thread voluntarily blocks.
123 #endif // #if KERNEL_ROUND_ROBIN
124 
125  // Restore the context...
126  Thread_RestoreContext(); // restore the context of the first running thread
127  ASM("reti"); // return from interrupt - will return to the first scheduled thread
128 }
129 
130 //---------------------------------------------------------------------------
135 //---------------------------------------------------------------------------
136 ISR(INT2_vect) __attribute__((signal, naked));
137 ISR(INT2_vect)
138 {
139  Thread_SaveContext(); // Push the context (registers) of the current task
140  Thread_Switch(); // Switch to the next task
141  Thread_RestoreContext(); // Pop the context (registers) of the next task
142  ASM("reti"); // Return to the next task
143 }
144 } // namespace Mark3
K_WORD * m_pwStack
Pointer to the thread&#39;s stack.
Definition: thread.h:452
static void Update(Thread *pclTargetThread_)
Update Update the current thread being tracked for round-robing scheduling. Note - this has no effect...
Timer list declarations.
#define K_WORD
Size of a data word.
Definition: portcfg.h:62
Basic data type primatives used throughout the OS.
static void StartThreads()
StartThreads Function to start the scheduler, initial threads, etc.
Definition: threadport.cpp:100
Kernel initialization and startup class.
ISR(INT2_vect) __attribute__((signal
ISR(INT2 _vect) SWI using INT2 - used to trigger a context switch.
Definition: threadport.cpp:137
uint16_t m_u16StackSize
Size of the stack (in bytes)
Definition: thread.h:477
#define PORT_PUSH_TO_STACK(x, y)
Push a value y to the stack pointer x and decrement the stack pointer.
Definition: threadport.h:38
K_WORD * m_pwStackTop
Pointer to the top of the thread&#39;s stack.
Definition: thread.h:449
ThreadEntryFunc m_pfEntryPoint
The entry-point function called when the thread starts.
Definition: thread.h:486
void * m_pvArg
Pointer to the argument passed into the thread&#39;s entrypoint.
Definition: thread.h:489
Definition: atomic.cpp:23
Mark3 Kernel Configuration This file is used to configure the kernel for your specific application in...
Platform independent thread class declarations Threads are an atomic unit of execution, and each instance of the thread class represents an instance of a program running of the processor. The Thread is the fundmanetal user-facing object in the kernel - it is what makes multiprocessing possible from application code.
static void Start(void)
Start Starts the kernel time (must be configured first)
Definition: kerneltimer.cpp:76
#define Thread_SaveContext()
Save the context of the Thread.
Definition: threadport.h:42
Mark3::Thread * g_pclCurrent
Definition: scheduler.cpp:25
Kernel Software interrupt declarations.
ATMega1284p Multithreading support.
The Thread Class. This object providing the fundamental thread control data structures and functions ...
Definition: thread.h:64
Mark3::Thread * g_pclNext
Definition: scheduler.cpp:24
static void InitStack(Thread *pstThread_)
InitStack Initialize the thread&#39;s stack.
Definition: threadport.cpp:43
static void CompleteStart()
CompleteStart Call this from the thread initialization code at the point that the scheduler is to be ...
Definition: kernel.cpp:64
K_WORD g_kwSFR
Definition: threadport.cpp:35
static void Start(void)
Start Enable ("Start") the software interrupt functionality.
Definition: kernelswi.cpp:39
static void Schedule()
Schedule Run the scheduler, determines the next thread to run based on the current state of the threa...
Definition: scheduler.cpp:45
static void Thread_Switch(void)
Definition: threadport.cpp:94
K_WORD g_kwCriticalCount
Definition: threadport.cpp:36
#define KERNEL_STACK_CHECK
Definition: mark3cfg.h:43
#define ASM(x)
Definition: threadport.h:32
static void Config(void)
Config Configure the software interrupt - must be called before any other software interrupt function...
Definition: kernelswi.cpp:31
Kernel Timer Class declaration.
#define Thread_RestoreContext()
Restore the context of the Thread.
Definition: threadport.h:91
Thread Quantum declarations for Round-Robin Scheduling.
static void Config(void)
Config Initializes the kernel timer before use.
Definition: kerneltimer.cpp:60
static bool SetScheduler(bool bEnable_)
SetScheduler Set the active state of the scheduler. When the scheduler is disabled, the next thread is never set; the currently running thread will run forever until the scheduler is enabled again. Care must be taken to ensure that we don&#39;t end up trying to block while the scheduler is disabled, otherwise the system ends up in an unusable state.
Definition: scheduler.cpp:75