Threading

Threading allows functions to execute concurrently. The example below shows two threads switching between running and sleeping. As the RTI ISR executes it takes the current process off the schedule (list of processes) and switches in the next process on the schedule. Once all processes have been removed from the schedule the “Scheduler” steps in and creates a new schedule.

Cooperative multitasking allows for threads to switch themselves out of processing during down time. Below is an example of this. If you find problems with the code please let me know with a comment.

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned int size_t;
 
#define THREADMAX 16
#define STACKSIZE 0x200
 
void* threads[THREADMAX];
unsigned int threadcount;
void* _stackpointer;
 
struct sStack
{
    //GCC Stack Vars
    u16 xy; //Soft Register XY
    u16 z; //Soft Register Z
    u16 tmp; //Register Backup Pointer
    u16 frame; //Frame Pointer
 
    //HC12 Stack Vars
    u8 CCR; //Condition Code Register
    u8 A; //Accumulator A
    u8 B; //Accumulator B
    u16 X; //Index Register X
    u16 Y; //Index Register Y
    u16 PC; //Program Counter (Starts at functions address)
    u16 RS; //Return Service
};
 
void Spawn(void* function, void* callback)
{
    void* newstack = Allocate(STACKSIZE);
    sStack* sp = (sStack*)((u16)newstack + (u16)STACKSIZE - sizeof(sStack));
 
    sp->xy = 0x0000;
    sp->z = 0x0000;
    sp->tmp = 0x0000;
    sp->frame = 0x0000;
    sp->CCR = 0xC0;
    sp->A = 0x00;
    sp->B = 0x00;
    sp->X = 0x0000;
    sp->Y = 0x0000;
    sp->PC = (u16)function;
    sp->RS = (u16)callback;
 
    if( threadcount < THREADMAX )
    {
        threads[threadcount++] = sp;
    }
}
 
//
void __attribute__((interrupt)) Switch_RTI_ISR(void) 
{
    asm volatile("sei"); //Set interrupt mask
 
    //Save off the stack pointer
    asm volatile("LDX #_stackpointer");
    asm volatile("STS 0, X");
    threads[current] = _stackpointer;
 
    //Schedule the next thread
    current += 1;
    current %= threadcount;
 
    //Load the next stack pointer
    _stackpointer = threads[current];
    asm volatile("LDX #_stackpointer");
    asm volatile("LDS 0, X");
 
    CRGFLG |= 0x80; //Real Time Interrupt Flag 
    asm volatile("cli"); //Enable Interrupts
}
 
//More of a bootloader that sets up variables
void Main(void)
{ 
    //Disable Interrupts
    asm volatile("sei");
 
    //Spawn Threads
    threadcount = 0; //Init
    Spawn((void*)Thread1, 0x4000);
    Spawn((void*)Thread2, 0x4000);
 
    //Setup Thread Swap
    *(void(**)())0x3FF0 = Swith_RTI_ISR;
    asm volatile("cli");
 
    while(1)
    {
        asm volatile("swi");
    }
}
 
void Thread1(void)
    while(1)
    { 
        Print("Thread 1");
        Pause(500);
        asm volatile("swi");
    }
}
 
void Thread2(void)
{
    while(1)
    { 
        Print("Thread 2");
        Pause(500);
        asm volatile("swi");
    }
}

Leave a Reply