@@ -24,31 +24,119 @@ extern "C" {
2424
2525#if defined(ARDUINO_ARCH_AVR)
2626 typedef uint8_t reg_t ;
27+
28+ #include < stdlib.h>
29+
30+ struct __freelist {
31+ size_t sz;
32+ struct __freelist *nx;
33+ };
34+
35+ uint32_t __mainloopstack = DEFAULT_STACK_SIZE;
36+
37+ void *__poison_malloc (size_t len)
38+ {
39+ extern size_t __malloc_margin;
40+ extern char *__malloc_heap_start;
41+ extern char *__malloc_heap_end;
42+ extern char *__brkval;
43+ extern struct __freelist *__flp;
44+
45+ struct __freelist *fp1, *fp2, *sfp1, *sfp2;
46+ char *cp;
47+ size_t s, avail;
48+
49+ if (len < sizeof (struct __freelist ) - sizeof (size_t ))
50+ len = sizeof (struct __freelist ) - sizeof (size_t );
51+
52+ for (s = 0 , fp1 = __flp, fp2 = 0 ;
53+ fp1;
54+ fp2 = fp1, fp1 = fp1->nx ) {
55+ if (fp1->sz < len)
56+ continue ;
57+ if (fp1->sz == len) {
58+ if (fp2)
59+ fp2->nx = fp1->nx ;
60+ else
61+ __flp = fp1->nx ;
62+ return &(fp1->nx );
63+ }
64+ else {
65+ if (s == 0 || fp1->sz < s) {
66+ s = fp1->sz ;
67+ sfp1 = fp1;
68+ sfp2 = fp2;
69+ }
70+ }
71+ }
72+
73+ if (s) {
74+ if (s - len < sizeof (struct __freelist )) {
75+ if (sfp2)
76+ sfp2->nx = sfp1->nx ;
77+ else
78+ __flp = sfp1->nx ;
79+ return &(sfp1->nx );
80+ }
81+
82+ cp = (char *)sfp1;
83+ s -= len;
84+ cp += s;
85+ sfp2 = (struct __freelist *)cp;
86+ sfp2->sz = len;
87+ sfp1->sz = s - sizeof (size_t );
88+ return &(sfp2->nx );
89+ }
90+
91+ if (__brkval == 0 )
92+ __brkval = __malloc_heap_start;
93+ cp = __malloc_heap_end;
94+
95+ if (cp == 0 )
96+ cp = (char *)(RAMEND + __mainloopstack) - __malloc_margin;
97+
98+ if (cp <= __brkval)
99+ return 0 ;
100+
101+ avail = cp - __brkval;
102+
103+ if (avail >= len && avail >= len + sizeof (size_t )) {
104+ fp1 = (struct __freelist *)__brkval;
105+ __brkval += len + sizeof (size_t );
106+ fp1->sz = len;
107+ return &(fp1->nx );
108+ }
109+
110+ return 0 ;
111+
112+ }
113+
114+
27115#ifdef EIND
28- #define GET_FAR_ADDRESS (var ) ({ \
29- uint32_t tmp;\
30- __asm__ __volatile__ ( \
31- " ldi %A0, lo8(%1) \n\t " \
32- " ldi %B0, hi8(%1) \n\t " \
33- " ldi %C0, hh8(%1) \n\t " \
34- " clr %D0 \n\t " \
35- : \
36- " =d" (tmp) \
37- : \
38- " p" (&(var)) \
39- ); \
40- tmp;\
41- })
116+ #define GET_FAR_ADDRESS (var ) ({ \
117+ uint32_t tmp;\
118+ __asm__ __volatile__ ( \
119+ " ldi %A0, lo8(%1) \n\t " \
120+ " ldi %B0, hi8(%1) \n\t " \
121+ " ldi %C0, hh8(%1) \n\t " \
122+ " clr %D0 \n\t " \
123+ : \
124+ " =d" (tmp) \
125+ : \
126+ " p" (&(var)) \
127+ ); \
128+ tmp;\
129+ })
42130#endif
43131 #define NUM_REGS 40 // r0/31 + sp(2) + pc(2) + data(2) + ftask(2)
44- #define SPL_REG 32
45- #define SPH_REG 33
46- #define PCL_REG 34
132+ #define PCL_REG 34
47133 #define PCH_REG 35
48134 #define DATAL_REG 36
49135 #define DATAH_REG 37
50136 #define TASKFL_REG 38
51137 #define TASKFH_REG 39
138+ #define SPL_REG 32
139+ #define SPH_REG 33
52140
53141 #define STACK_EM0 0xFFFF
54142 #define STACK_EM1 0xFFFE
@@ -63,7 +151,6 @@ extern "C" {
63151
64152 #define STACK_EM0 0xFFFFFFFF
65153 #define STACK_EM1 0xFFFFFFFE
66-
67154#endif
68155
69156typedef struct CoopTask {
@@ -74,6 +161,7 @@ typedef struct CoopTask {
74161} CoopTask;
75162
76163static CoopTask *cur = 0 ;
164+ CoopTask *mainloop = 0 ;
77165
78166static CoopTask* __attribute__ ((noinline)) coopSchedule(char taskDied) {
79167 CoopTask* next = cur->next ;
@@ -104,7 +192,8 @@ static void _NAKED_ _NONINLINE_ coopTaskStart(void) {
104192 " movw 30, r4 \n\t "
105193 " ldd r26, Z+34 ;increment PC, next call ret without call ftask(data) \n\t "
106194 " ldd r27, Z+35 \n\t "
107- " adiw r26, 62 ;offset ret\n\t "
195+ " adiw r26, 60 ;offset ret\n\t "
196+ " adiw r26, 6 ;offset ret\n\t "
108197 " movw r18, r26 \n\t "
109198 " std Z+34, r18 \n\t "
110199 " std Z+35, r19 \n\t "
@@ -119,11 +208,14 @@ static void _NAKED_ _NONINLINE_ coopTaskStart(void) {
119208 " movw r4, r24 ;r25:r24 cur task\n\t "
120209 " movw 30, r4 ;load context \n\t "
121210 " ldd r6, Z+32 ;load stack\n\t "
211+ " in r0, __SREG__ ;safe interrupt\n\t "
212+ " cli \n\t "
122213 " mov r28,r6 \n\t "
123214 " out __SP_L__, r6 \n\t "
124215 " ldd r6, Z+33 \n\t "
125216 " mov r29,r6 \n\t "
126217 " out __SP_H__, r6 \n\t "
218+ " out __SREG__, r0 \n\t "
127219 " ldd r0, Z+0 ;load register \n\t "
128220 " ldd r1, Z+1 \n\t "
129221 " ldd r2, Z+2 \n\t "
@@ -210,6 +302,8 @@ static void _NAKED_ _NONINLINE_ coopDoYield(CoopTask* curTask _UNUSED_) {
210302 " std Z+33, r4 \n\t "
211303 " ldi r24, 0 ;next coop \n\t "
212304 " call coopSchedule \n\t "
305+ " in r0, __SREG__ ;safe interrupt\n\t "
306+ " cli \n\t "
213307 " movw r4, r24 ;load context \n\t "
214308 " movw 30, r4 \n\t "
215309 " ldd r6, Z+32 \n\t "
@@ -221,6 +315,7 @@ static void _NAKED_ _NONINLINE_ coopDoYield(CoopTask* curTask _UNUSED_) {
221315 " ldd r6, Z+34 ;load pc\n\t "
222316 " ldd r7, Z+35 \n\t "
223317 " movw r30, r6 \n\t "
318+ " out __SREG__, r0 \n\t "
224319 " icall ;call coopTaskStart if begin else return after icall \n\t "
225320 " movw r30, r4 ;need reload structure \n\t "
226321 " ldd r0, Z+0 ;load register \n\t "
@@ -346,8 +441,9 @@ static void _NAKED_ _NONINLINE_ coopDoYield(CoopTask* curTask) {
346441
347442static int coopInit (void ) {
348443 CoopTask* task;
349-
444+
350445 task = reinterpret_cast <CoopTask *>(malloc (sizeof (CoopTask)));
446+
351447 if (!task)
352448 return 0 ;
353449
@@ -356,24 +452,24 @@ static int coopInit(void) {
356452 task->stackPtr = NULL ;
357453
358454#ifdef ARDUINO_ARCH_AVR
455+ mainloop = task;
359456 task->regs [SPL_REG] = 0 ;
360457 task->regs [SPH_REG] = 0 ;
361458#ifdef EIND
362- uint32_t pf = GET_FAR_ADDRESS (coopTaskStart);
363- task->regs [PCL_REG] = ((uint16_t )(pf) + 62 ) & 0xFF ;
364- task->regs [PCH_REG] = (((uint16_t )(pf) + 62 ) >> 8 ) & 0xFF ;
459+ uint32_t pf = GET_FAR_ADDRESS (coopTaskStart);
460+ task->regs [PCL_REG] = ((uint16_t )(pf) + 66 ) & 0xFF ;
461+ task->regs [PCH_REG] = (((uint16_t )(pf) + 66 ) >> 8 ) & 0xFF ;
365462#else
366- task->regs [PCL_REG] = ((uint16_t )(coopTaskStart) + 62 ) & 0xFF ;
367- task->regs [PCH_REG] = (((uint16_t )(coopTaskStart) + 62 ) >> 8 ) & 0xFF ;
463+ task->regs [PCL_REG] = ((uint16_t )(coopTaskStart) + 66 ) & 0xFF ;
464+ task->regs [PCH_REG] = (((uint16_t )(coopTaskStart) + 66 ) >> 8 ) & 0xFF ;
368465#endif
369466 task->regs [DATAL_REG] = 0 ;
370467 task->regs [DATAH_REG] = 0 ;
371468 task->regs [TASKFL_REG] = 0 ;
372469 task->regs [TASKFH_REG] = 0 ;
373470#endif
374-
471+
375472 cur = task;
376-
377473 return 1 ;
378474}
379475
@@ -397,15 +493,16 @@ static int coopSpawn(SchedulerParametricTask taskF, void* taskData, uint32_t sta
397493 task->regs [DATAL_REG] = (uint16_t )(taskData) & 0xFF ;
398494 task->regs [DATAH_REG] = ((uint16_t )(taskData) >> 8 ) & 0xFF ;
399495#ifdef EIND
400- uint32_t pf = GET_FAR_ADDRESS (coopTaskStart);
401- task->regs [PCL_REG] = (uint16_t )(pf) & 0xFF ;
496+ uint32_t pf = GET_FAR_ADDRESS (coopTaskStart);
497+ task->regs [PCL_REG] = (uint16_t )(pf) & 0xFF ;
402498 task->regs [PCH_REG] = ((uint16_t )(pf) >> 8 ) & 0xFF ;
403499#else
404500 task->regs [PCL_REG] = (uint16_t )(coopTaskStart) & 0xFF ;
405501 task->regs [PCH_REG] = ((uint16_t )(coopTaskStart) >> 8 ) & 0xFF ;
406502#endif
407503 task->regs [SPL_REG] = (uint16_t )(stack + stackSz - 1 ) & 0xFF ;
408- task->regs [SPH_REG] = ((uint16_t )(stack + stackSz - 1 ) >> 8 ) & 0xFF ;
504+ task->regs [SPH_REG] = ((uint16_t )(stack + stackSz - 1 ) >> 8 ) & 0xFF ;
505+
409506
410507#elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)
411508 task->regs [TASKF_REG] = (uint32_t ) taskF;
@@ -434,6 +531,27 @@ void yield(void) {
434531 coopDoYield (cur);
435532}
436533
534+ #if defined(ARDUINO_ARCH_AVR)
535+
536+ void *__scheduler_malloc (size_t len)
537+ {
538+ extern int __heap_start, *__brkval;
539+ int v = (__brkval == NULL ) ? __heap_start : (int )(__brkval);
540+ char * c[5 ];
541+ if ( (int )(c) < v )
542+ {
543+ return __poison_malloc (len);
544+ }
545+
546+ #pragma pop_macro("malloc")
547+ return malloc (len);
548+ #pragma push_macro("malloc")
549+ #undef malloc
550+ #define malloc __scheduler_malloc
551+ }
552+
553+ #endif
554+
437555}; // extern "C"
438556
439557SchedulerClass::SchedulerClass () {
@@ -450,27 +568,29 @@ static void startLoopHelper(void *taskData) {
450568
451569void SchedulerClass::startLoop (SchedulerTask task, stacksz_t stackSize)
452570{
571+ if ( stackSize < DEFAULT_MIN_STACK_SIZE)
572+ stackSize = DEFAULT_MIN_STACK_SIZE;
453573 coopSpawn (startLoopHelper, reinterpret_cast <void *>(task), stackSize);
454574}
455575
456576static void startTaskHelper (void *taskData) {
457577 SchedulerTask task = reinterpret_cast <SchedulerTask>(taskData);
458578 task ();
459- #if defined( ARDUINO_ARCH_AVR)
460- yield ();
579+ #ifdef ARDUINO_ARCH_AVR
580+ yield ();
461581#endif
462582}
463583
464584void SchedulerClass::start (SchedulerTask task, stacksz_t stackSize) {
585+ if ( stackSize < DEFAULT_MIN_STACK_SIZE)
586+ stackSize = DEFAULT_MIN_STACK_SIZE;
465587 coopSpawn (startTaskHelper, reinterpret_cast <void *>(task), stackSize);
466588}
467589
468590void SchedulerClass::start (SchedulerParametricTask task, void *taskData, stacksz_t stackSize) {
469- coopSpawn (task, taskData, stackSize);
591+ if ( stackSize < DEFAULT_MIN_STACK_SIZE)
592+ stackSize = DEFAULT_MIN_STACK_SIZE;
593+ coopSpawn (task, taskData, stackSize);
470594}
471595
472596SchedulerClass Scheduler;
473-
474- #undef _NONINLINE_
475- #undef _NOKED_
476- #undef _UNUSED_
0 commit comments