For Cortex-M3,Cortex-M0, Multitask scheduler library. Arduino due compatible

Dependents:   scheduler-demo-cq-lpc11u35 scheduler-demo scheduler-demo-cq-lpc11u35 mbed-scli-test

Revision:
0:c68459544a17
Child:
1:8967b575bb46
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Scheduler.cpp	Sun Aug 25 16:48:21 2013 +0900
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2012 audin
+ * This program is licensed under the Apache License, Version 2.0.
+ * Modified 2012/10: For working on Cortex-M0 and M3.
+ *                   Defined static tcb option for the cpu that has quite a less SRAM < 8kbyte.  
+ *
+ * Original file is arduino-1.5\hardware\arduino\sam\libraries\Scheduler
+ */
+
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include "Scheduler.h"
+
+#define _ARM_CM0_			1		/* 1: Cortex-M0 or M3,  0: Cortex-M3		*/
+#define _USE_MALLOC_		0		/* 1: 8kbyte >= SRAM,   0: 8kbyte < SRAM	*/
+
+
+#if _USE_MALLOC_
+#	include <stdlib.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+uint32_t millis(void);
+
+#define NUM_REGS 10	// r4-r11, sp, lr
+
+typedef struct CoopTask {
+	uint32_t regs[NUM_REGS];
+	void* stackPtr;
+	struct CoopTask* next;
+	struct CoopTask* prev;
+} CoopTask;
+
+#if  !_USE_MALLOC_
+static uint32_t id = 0;
+static CoopTask tcb[ COOP_TASK_NUM_MAX ];
+static uint8_t task_stack[ COOP_TASK_NUM_MAX - 1 ][ MIN_STACK_SIZE ];
+#endif
+
+static CoopTask *cur = 0;
+
+CoopTask* __attribute__((noinline)) coopSchedule(char taskDied) {
+	CoopTask* next = cur->next;
+
+#if _USE_MALLOC_
+	if (taskDied) {
+		// Halt if last task died.
+		if (next == cur)
+			while (1)
+				;
+
+		// Delete task
+		if (cur->stackPtr)
+			free(cur->stackPtr);
+		cur->next->prev = cur->prev;
+		cur->prev->next = cur->next;
+		free(cur);
+	}
+#endif
+	cur = next;
+	return next;
+}
+
+static void __attribute__((naked)) __attribute__((noinline)) coopTaskStart(void) {
+#if _ARM_CM0_
+	/* for Cortex-m0 */
+	__asm (
+		"mov   r0, r5;"
+		"blx   r4;"
+		"mov   r0, #1;"
+		"bl    coopSchedule;"
+	/****	"ldmia r0, {r4-r12, lr};"	*/
+		"add r0, r0, #16;"
+		"ldmia r0!, {r4-r7};"		/* get r7->r11, r6->r10, r5->r9, r4->r8		*/
+		"mov r11, r7;"
+		"mov r10, r6;"
+		"mov r9,  r5;"
+		"mov r8 , r4;"
+
+		"ldmia r0!, {r4-r5};"		/* get r5->lr, r4->r12						*/
+		"mov lr,  r5;"
+		"mov r12, r4;"
+
+		"sub r0, r0, #40;"			/* set offset for r4, 40 = 10reg * 4byte	*/
+		"ldmia  r0!, {r4-r7};"		/* get r7,r6,r5,r4							*/
+	/**** end ldmia converted by Cortex-M0 instructions	*/
+		"msr   msp, r12;"			/* use main stack							*/
+		"bx    lr;"
+	);
+#else
+	/* for Cortex-m3 or ARM code cpu */
+	asm (
+		"mov   r0, r5;"						/* r5 = new task func */
+		"blx   r4;"							/* r4 = helper func   */
+		"mov   r0, #1;"						
+		"bl    coopSchedule;"
+		"ldmia r0, {r4-r12, lr};"
+		"mov   sp, r12;"
+		"bx    lr;"
+	);
+#endif
+}
+
+static void __attribute__((naked)) __attribute__((noinline)) coopDoYield(CoopTask* curTask) {
+#if _ARM_CM0_
+	/* for Cortex-m0 */
+	__asm (
+			"mrs   r12, msp;"
+		/**** "stmia r0, {r4-r12, lr};" */
+			"stmia r0!, {r4-r7};"		/* first store r4-r7 data				*/
+
+			"mov r4, r8;"
+			"mov r5, r9;"
+			"mov r6, r10;"
+			"mov r7, r11;"
+			"stmia r0!, {r4-r7};"		/* store r8-r11							*/
+
+			"mov r4, r12;"
+			"mov r5, lr;"
+			"stmia r0!, {r4,r5};"		/* store r12, lr						*/
+		/**** end stmia converted by cortex-m0 instructions	*/
+
+			"mov   r0, #0;"
+			"bl    coopSchedule;"
+
+		/**** "ldmia r0, {r4-r12, lr};"	*/
+			"add r0, r0, #16;"			/* set offset for r8					*/
+			"ldmia r0!, {r4-r7};"		/* get r7->r11, r6->r10, r5->r9, r4->r8 */
+			"mov r11, r7;"
+			"mov r10, r6;"
+			"mov r9,  r5;"
+			"mov r8 , r4;"
+
+			"ldmia r0!, {r4-r5};"		/* get r5->lr, r4->r12					*/
+			"mov lr,  r5;"
+			"mov r12, r4;"
+
+			"sub r0, r0, #40;"			/* set offset for r4, 40 = 10reg * 4byte  */
+			"ldmia  r0!, {r4-r7};"
+		/**** end ldmia converted by Cortex-M0 instructions	*/
+
+			"msr   msp, r12;"
+			"bx    lr;"
+		);
+#else
+	/* for Cortex-m3 or ARM code cpu */
+	__asm (
+			"mov   r12, sp;"
+			"stmia r0, {r4-r12, lr};"
+			"mov   r0, #0;"
+			"bl    coopSchedule;"
+			"ldmia r0, {r4-r12, lr};"
+			"mov   sp, r12;"
+			"bx    lr;"
+		);
+#endif
+
+}
+
+static int coopInit(void) {
+	CoopTask* task;
+#if _USE_MALLOC_
+#	ifdef __cplusplus
+		task = reinterpret_cast<CoopTask *>(malloc(sizeof(CoopTask)));
+#	else
+		task = (CoopTask *)(malloc(sizeof(CoopTask)));
+#	endif
+	if (!task)
+		return 0;
+#else
+	task = &tcb[ id ];
+#endif
+	task->next = task;
+	task->prev = task;
+	task->stackPtr = 0;
+	cur = task;
+
+	return 1;
+}
+
+static int coopSpawn(SchedulerParametricTask taskF, void* taskData, uint32_t stackSz) {
+#if _USE_MALLOC_
+	uint8_t *stack = (uint8_t*)malloc(stackSz);
+	if (!stack)
+		return 0;
+#	ifdef __cplusplus
+		CoopTask *task = reinterpret_cast<CoopTask *>(malloc(sizeof(CoopTask)));
+#	else
+		CoopTask *task = (CoopTask *)(malloc(sizeof(CoopTask)));
+#	endif
+	if (!task) {
+		free(stack);
+		return 0;
+	}
+#else
+	uint8_t *stack = task_stack[ id ];
+	id++;
+	CoopTask *task = &tcb[ id ];
+#endif
+	task->stackPtr = stack;
+	task->regs[0] = (uint32_t) taskF;							/* Helper func: r4	*/
+	task->regs[1] = (uint32_t) taskData;						/* New task :	r5	*/
+#if _USE_MALLOC_
+	task->regs[8] = ((uint32_t)(stack + stackSz)) & ~7;
+#else
+	task->regs[8] = ((uint32_t)(stack + MIN_STACK_SIZE)) & ~7;		/* r12	*/
+#endif
+	task->regs[9] = (uint32_t) & coopTaskStart;					/* lr	*/
+
+	task->prev = cur;
+	task->next = cur->next;
+	cur->next->prev = task;
+	cur->next = task;
+
+	// These are here so compiler is sure that function is
+	// referenced in both variants (cancels a warning)
+	if (stackSz == 0xFFFFFFFF)
+		coopSchedule(0);
+	if (stackSz == 0xFFFFFFFE)
+		coopSchedule(1);
+
+	return 1;
+}
+
+void yield(void) {
+	coopDoYield(cur);
+}
+
+void wait(uint32_t ms) {
+	uint32_t start = millis();
+	while (millis() - start < ms)
+		yield();
+}
+
+#ifdef __cplusplus
+}; // extern "C"
+#endif
+
+void scheduler_init( void ) {
+	coopInit();
+}
+
+static void startLoopHelper(void *taskData) {
+#ifdef __cplusplus
+	SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData);
+#else
+	SchedulerTask task = (SchedulerTask)(taskData);
+#endif
+	while (1){
+		task();
+	}
+}
+
+static void startTaskHelper(void *taskData) {
+#ifdef __cplusplus
+	SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData);
+#else
+	SchedulerTask task = (SchedulerTask)(taskData);
+#endif
+	task();
+}
+
+void scheduler_start( SchedulerTask task ) {
+	coopSpawn( startTaskHelper, (void *)(task), MIN_STACK_SIZE );
+}
+
+void scheduler_startLoop( SchedulerTask task) {
+	coopSpawn( startLoopHelper, (void *)(task), MIN_STACK_SIZE );
+}
+
+#ifdef __cplusplus
+SchedulerClass::SchedulerClass() {
+	coopInit();
+}
+
+void SchedulerClass::startLoop(SchedulerTask task, uint32_t stackSize) {
+	coopSpawn(startLoopHelper, reinterpret_cast<void *>(task), stackSize);
+}
+
+void SchedulerClass::start(SchedulerTask task, uint32_t stackSize) {
+	coopSpawn(startTaskHelper, reinterpret_cast<void *>(task), stackSize);
+}
+
+void SchedulerClass::start(SchedulerParametricTask task, void *taskData, uint32_t stackSize) {
+	coopSpawn(task, taskData, stackSize);
+}
+
+SchedulerClass Scheduler;
+#endif
+