move.l %d0,%sp@- move.w %sr,%d0 move.l %d0,%sp@- move.l %d1,%sp@- move.l %d2,%sp@- move.l %d3,%sp@- move.l %d4,%sp@- move.l %d5,%sp@- move.l %d6,%sp@- move.l %d7,%sp@- move.l %a0,%sp@- move.l %a1,%sp@- move.l %a2,%sp@- move.l %a3,%sp@- move.l %a4,%sp@- move.l %a5,%sp@- move.l %a6,%sp@- move.l pxCurrentTCB,%a0 move.l %sp,(%a0)Code Extract 1 - Saving context
The data are pushed onto the stack in the opposite order to when they are restored. As the data is pushed onto the stack the stack pointer is decremented. Finally the stack pointer is saved in the task control block. The address of the next instruction will already be on the stack as they will have been put on the stack before the call to taskYIELD() and so after the task is later restored the RTS instruction will jump to the next instruction in the task.
The purpose of this is to establish an absolute frame of reference for calculating the location of local variables and parameters to the function. Unfortunately this disrupts our context switching code as our save context code expects the top of the stack to represent the return address of the task being suspended (as saved by the ISR instruction when the task calls taskYIELD). Now, however the top of the stack contains the previous value of the frame pointer.
The MegaAVR port avoids this problem by defining the taskYIELD function with the naked attribute which instructs the compiler not to create a function prologue or epilogue sequence.
During this phase of the project we resolved this problem by modifying the makefile to pass the -fomit-frame-pointer flag to the compiler which removes the LINK instruction from the function prologue.
As part of the on-board debugging functionality the MCF5272 can generate interrupts when a certain address is modified. Stack overflows could be detected by setting this address to the boundary of the allocated stack for the currently running task each time a context switch occurs. This would be a nice feature to add in the future but we considered it more important to investigate the next phase of our project than to attempt to implement this feature.
In order to test this increment we developed a simple test program, the body of which is shown in Program 2.
static void vTestTask( void *pvParameters ); static int task1id = 1; static int task2id = 2; portSHORT main( void ) { xTaskCreate( vTestTask, "Task 1", 1000, (void *) &task1id, tskIDLE_PRIORITY + 2, NULL ); xTaskCreate( vTestTask, "Task 2", 1000, (void *) &task2id, tskIDLE_PRIORITY + 2, NULL ); printf("starting scheduler...\n"); vTaskStartScheduler( pdFALSE ); return 0; } /*-----------------------------------------------*/ static void vTestTask( void *pvParameters ) { int taskId = *((int *)pvParameters); printf("Task %d yielding.\n", taskId); taskYIELD(); printf("Task %d resumed.\n", taskId); printf("Task %d yielding.\n", taskId); taskYIELD(); printf("Task %d resumed.\n", taskId); /* Tasks must be implemented as continuous loops */ while(1); }Program 2 - Program to demonstrate cooperative multitasking
The results of this test program are shown in Figure 2.
Figure 2 - Output from the test program demonstrating cooperative multitasking.
NEXT >>> ColdFire RTOS Port - Phase 4 - Preemptive Multitasking