- •List of Figures
- •List of Tables
- •Preface
- •1 Requirements
- •1.1 General Requirements
- •1.2 Memory Requirements
- •1.3 Performance
- •1.4 Portability
- •2 Concepts
- •2.1.1 Compiling and Linking
- •2.2 Loading and Execution of Programs
- •2.3 Preemptive Multitasking
- •2.3.1 Duplication of Hardware
- •2.3.2 Task Switch
- •2.3.3 Task Control Blocks
- •2.3.4 De-Scheduling
- •2.4 Semaphores
- •2.5 Queues
- •2.5.1 Ring Buffers
- •2.5.2 Ring Buffer with Get Semaphore
- •2.5.3 Ring Buffer with Put Semaphore
- •2.5.4 Ring Buffer with Get and Put Semaphores
- •3 Kernel Implementation
- •3.1 Kernel Architecture
- •3.2 Hardware Model
- •3.2.1 Processor
- •3.2.2 Memory Map
- •3.2.3 Peripherals
- •3.2.4 Interrupt Assignment
- •3.2.5 Data Bus Usage
- •3.3 Task Switching
- •3.4 Semaphores
- •3.4.1 Semaphore Constructors
- •3.4.2 Semaphore Destructor
- •3.4.3 Semaphore P()
- •3.4.4 Semaphore Poll()
- •3.4.5 Semaphore V()
- •3.5 Queues
- •3.5.1 Ring Buffer Constructor and Destructor
- •3.5.2 RingBuffer Member Functions
- •3.5.3 Queue Put and Get Functions
- •3.5.4 Queue Put and Get Without Disabling Interrupts
- •3.6 Interprocess Communication
- •3.7 Serial Input and Output
- •3.7.1 Channel Numbers
- •3.7.2 SerialIn and SerialOut Classes and Constructors/Destructors
- •3.7.3 Public SerialOut Member Functions
- •3.7.4 Public SerialIn Member Functions
- •3.8 Interrupt Processing
- •3.8.1 Hardware Initialization
- •3.8.2 Interrupt Service Routine
- •3.9 Memory Management
- •3.10 Miscellaneous Functions
- •4 Bootstrap
- •4.1 Introduction
- •4.3.1 Task Parameters
- •4.3.2 Task Creation
- •4.3.3 Task Activation
- •4.3.4 Task Deletion
- •5 An Application
- •5.1 Introduction
- •5.2 Using the Monitor
- •5.3 A Monitor Session
- •5.4 Monitor Implementation
- •6 Development Environment
- •6.1 General
- •6.2 Terminology
- •6.3 Prerequisites
- •6.3.1 Scenario 1: UNIX or Linux Host
- •6.3.2 Scenario 2: DOS Host
- •6.3.3 Scenario 3: Other Host or Scenarios 1 and 2 Failed
- •6.4 Building the Cross-Environment
- •6.4.1 Building the GNU cross-binutils package
- •6.4.2 Building the GNU cross-gcc package
- •6.4.3 The libgcc.a library
- •6.5 The Target Environment
- •6.5.2 The skip_aout Utility
- •7 Miscellaneous
- •7.1 General
- •7.2 Porting to different Processors
- •7.2.1 Porting to MC68000 or MC68008 Processors
- •7.2.2 Porting to Other Processor families
- •7.3 Saving Registers in Interrupt Service Routines
- •A Appendices
- •A.1 Startup Code (crt0.S)
- •A.3 Task.cc
- •A.6 Semaphore.hh
- •A.7 Queue.hh
- •A.8 Queue.cc
- •A.9 Message.hh
- •A.10 Channels.hh
- •A.11 SerialOut.hh
- •A.12 SerialOut.cc
- •A.13 SerialIn.hh
- •A.14 SerialIn.cc
- •A.15 TaskId.hh
- •A.18 ApplicationStart.cc
- •A.19 Monitor.hh
- •A.20 Monitor.cc
- •A.22 SRcat.cc
- •Index
3. Kernel Implementation |
79 |
|
|
3.10 Miscellaneous Functions
So far, we have discussed most of the code comprising the kernel. What is missing is the code for starting up tasks (which is described in Section 4.3) and some functions that are conceptually of minor importance but nevertheless of certain practical use. They are described in less detail in the following sections.
3.10.1Miscellaneous Functions in Task.cc
The Monitor class uses member functions that are not used otherwise. Current() returns a pointer to the current task. Dsched() explicitly deschedules the current task. MyName() returns a string for the current task that is provided as an argument when a task is started; Name() returns that string for any task. MyPriority() returns the priority of the current task, Priority() returns the priority for any task. userStackBase() returns the base address of the user stack; userStackSize() returns the size of the user stack; and userStackUsed() returns the size of the user stack that has already been used by a task. When a task is created, its user stack is initialized to contain characters ’U’. userStackUsed() scans the user stack from the bottom until it finds a character which differs from ’U’ and so computes the size of the used part of the stack. Status() returns the task status bitmap.
Next() returns the next task in the ring of all existing tasks. If we need to perform a certain function for all tasks, we could do it as follows:
for (const Task * t = Task::Current();;)
{
... |
|
t = t->Next(); |
|
if (t == Task::Current()) |
break; |
}
Sleep(unsigned int ticks) puts the current task into sleep mode for ticks timer interrupts. That is, the task does not execute for a time of ticks*10ms without wasting CPU time.
When a task is created, its state is set to STARTED; i.e. the task is not in state RUN. This allows for setting up tasks before multitasking is actually enabled. Start() resets the task state to RUN.
Terminate() sets a task’s state to TERMINATED. This way, the task is prevented from execution without the task being deleted.
GetMessage(Message & dest) copies the next message sent to the current task into dest and removes it from the task’s message queue (msgQ).
80 |
3.10 Miscellaneous Functions |
|
|
3.10.2Miscellaneous Functions in os.cc
getSystemTime() returns the time in millisecond since system start-up (more precisely since multitasking was enabled) as a long long. initChannel() initializes the data format (data bits, stop bits) of a DUART channel, setBaudRate() sets ??? What ???. Panic() disables all interrupts, turns on the red LED and then continuously dumps an exception stack frame on SERIAL_0. This function is used whenever an exception for which no handler exists is taken (label _fatal). That is, if a fatal system error occurs, the red LED is turned on, and we can connect a terminal to SERIAL_0. The exception stack frame can then be analyzed, together with the map file created by the linker, to locate the fault in the source code. readDuartRegister() is called to read a DUART register. writeRegister() is used to write into a hardware (i.e. DUART) register.