Mini OS

Système minimal démontrant les bases d’un OS.


// Exemple de code pour le Mini OS
#include "xc.h"

// --- Configuration Bits (Example for PIC16/PIC18) ---
#pragma config WDTE = OFF // Disable Watchdog Timer
// Note: You may need to add other config bits depending on your exact PIC model

#define _XTAL_FREQ 4000000 // Define clock speed (4 MHz) for __delay_ms()

// --- Hardware Mapping ---
#define LED_TASK_A  PORTBbits.RB0  // Indicator for Task A
#define LED_TASK_B  PORTBbits.RB1  // Indicator for Task B
#define LED_OS_TICK PORTBbits.RB2  // Flashes to indicate the OS is changing tasks

// --- OS Structures ---
typedef enum { 
    TASK_A, 
    TASK_B 
} TaskType;

TaskType current_task = TASK_A;

// --- Task Definitions ---
void execute_task_A() {
    // Task A takes control of the CPU
    LED_TASK_A = 1;
    LED_TASK_B = 0;
    
    // Simulate some workload being processed
    __delay_ms(400); 
}

void execute_task_B() {
    // Task B takes control of the CPU
    LED_TASK_A = 0;
    LED_TASK_B = 1;
    
    // Simulate some workload being processed
    __delay_ms(400); 
}

// --- OS Scheduler ---
void os_switch_task() {
    // 1. Visual Indicator: The OS is actively switching tasks
    LED_OS_TICK = 1;
    __delay_ms(50); // Quick flash for visual feedback on the breadboard
    LED_OS_TICK = 0;

    // 2. Round-robin context switch logic
    if (current_task == TASK_A) {
        current_task = TASK_B;
    } else {
        current_task = TASK_A;
    }
}

// --- Main System Entry ---
void main(void) {
    // Initialize Hardware Ports
    TRISB = 0x00; // Set all PORTB pins as outputs
    PORTB = 0x00; // Ensure all LEDs start in the OFF state

    // The "OS" Super-Loop
    while(1) {
        
        // 1. Dispatch the current task
        if (current_task == TASK_A) {
            execute_task_A();
        } 
        else if (current_task == TASK_B) {
            execute_task_B();
        }

        // 2. Task yields. Scheduler takes over to switch to the next one.
        os_switch_task();
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////
Version ARINC 653

#include 

// --- ARM Cortex-M MPU Hardware Registers ---
#define MPU_CTRL    (*((volatile uint32_t*)0xE000ED94)) // MPU Control Register
#define MPU_RNR     (*((volatile uint32_t*)0xE000ED98)) // Region Number Register
#define MPU_RBAR    (*((volatile uint32_t*)0xE000ED9C)) // Region Base Address Register
#define MPU_RASR    (*((volatile uint32_t*)0xE000EDA0)) // Region Attribute and Size Register

// --- Memory Map Definition ---
// Assume each task gets a strict 8 Kilobyte block of RAM
#define TASK_A_MEM_BASE 0x20002000 
#define TASK_B_MEM_BASE 0x20004000 

typedef enum { PARTITION_A, PARTITION_B } ActivePartition;
ActivePartition current_partition = PARTITION_A;

// --- Space Partitioning: The Hardware Wall ---
void load_mpu_for_task(ActivePartition task) {
    // 1. Disable the MPU before configuring it
    MPU_CTRL = 0; 

    // 2. Select MPU Region 1 (This is the slot we will use for our task RAM)
    MPU_RNR = 1;  

    if (task == PARTITION_A) {
        // Assign Task A's memory address
        MPU_RBAR = TASK_A_MEM_BASE; 
    } else {
        // Assign Task B's memory address
        MPU_RBAR = TASK_B_MEM_BASE; 
    }

    // 3. Set Attributes: 
    // - Enable the region
    // - Set size to 8KB 
    // - Give Full Read/Write access ONLY to this specific 8KB block
    // (A real OS would use bitwise operations here, using a magic hex value for brevity: 0x03080025)
    MPU_RASR = 0x03080025; 

    // 4. Re-enable the MPU
    // The hardware wall is now active. If the task tries to access address 0x20000000 
    // or 0x20006000, the CPU will immediately trigger a "MemManage Fault" (Hardware Crash).
    MPU_CTRL = 1; 
}

// --- Time Partitioning: The Unforgiving Clock ---
// This is the hardware timer interrupt (SysTick) that fires exactly every 10 milliseconds.
// The tasks CANNOT stop this from happening.
void SysTick_Handler(void) {
    
    // 1. Stop the current task and save its CPU registers (Context Save)
    // __asm volatile ("... save registers to stack ..."); 

    // 2. Switch the active partition
    if (current_partition == PARTITION_A) {
        current_partition = PARTITION_B;
    } else {
        current_partition = PARTITION_A;
    }

    // 3. Reconfigure the physical memory walls for the new task
    load_mpu_for_task(current_partition);

    // 4. Load the new task's CPU registers and resume execution (Context Restore)
    // __asm volatile ("... load registers from stack ..."); 
}

// --- Main Kernel Boot ---
int main(void) {
    // Initialize standard hardware (Clocks, UART, etc.)
    
    // Configure the SysTick hardware timer to fire every 10ms
    // This enforces our strict Time Slicing
    // SystemCoreClock / 100 = 10ms interrupts
    // SysTick_Config(SystemCoreClock / 100); 

    // Load Task A's memory walls to start
    load_mpu_for_task(PARTITION_A);

    // Jump to the first task
    // execute_task_A(); 

    while(1) {
        // The main OS thread sleeps here. 
        // All the work is driven by the SysTick hardware interrupt violently swapping tasks.
    }
}