Internals
Context Switching
Context switching is remarkeably simple since we only run one instance at any time for each given type of task, and since we don't save context for hard periodic tasks, we can save even more by sharing one context between the operating system and hard periodic tasks. For each of the four types of tasks we globally and statically assign:

  • Data Stack
  • Hardware Stack
  • Register Context
When a task is interrupted and its context needs to be saved, simply change the stack pointer to the register context, push all of the registers which should be saved (we don't need to save registers that either the operaeting system reserves, or if the user is not using registers in asm, etc), Next, just change the data and hardware stack pointers to their new context, or the context where they last left off.

Queue Implementation

Queues were used frequently in the operating system. Since every queue differs slightly, it would be very difficult to create universal queue functions, so each queue is managed on its own. In addition, function calls are slow, and since Codevision does not yet support inlined functions, we cannot even save code this way. Most queues were impelmented such that a head and tail was kept, along with a struct for the nodes with pointer to next and previous.

Startup
Very little actually happens on operating system startup. Init_OS mostly sets the correct context for the operating system, starts timer 0, and enables UART if debugging. Init_Start computes a schedule and jumps to the first task, enabling the scheduler at the same time.