I have a new OS_Replace() macro and an updated version of portgccavr.S that now work together properly.
Now, OSDispatch() pushes r29, r29 on to the stack, saves the SP at OSframeP+0, retrieves and jumps to the task entry/re-entry address. Since we agree that a task's local variables/parameters are not preserved, OSDispatch() does not have to mess with the frame at all. Here's what the stack looks like before and after OSDispatch().
code:
; ==== Stacks in OSSched(), just prior to call to OSDispatch()
;
; [ rtn address low : main()] 0x10ff
; [ rtn address high : main()] 0x10fe
; [SP] [ ] 0x10fd
;
;
;
; ==== Stacks upon entering OSDispatch()
;
; [ rtn address low : main()] 0x10ff
; [ rtn address high : main()] 0x10fe
; [ R28 : OSSched()] 0x10fd
; [ rtn address low : OSSched()] 0x10fc
; [ rtn address high : OSSched()] 0x10fb
; [SP] [ ] 0x10fa
;
;
; ==== Stacks once inside task. Note, this shows that the
; task has 4 bytes of local data. These will be lost
; after first call to OSCtxSw().
;
;
; [ rtn address low : main()] 0x10ff
; [ rtn address high : main()] 0x10fe
; [ R28 : OSSched()] 0x10fd
; [ rtn address low : OSSched()] 0x10fc
; [ rtn address high : OSSched()] 0x10fb
; [ R28 : OSDispatch()] 0x10fa
; [ R29 : OSDispatch()] 0x10f9
; [ task's local data & params ] 0x10f8
; [ task's local data & params ] 0x10f7
; [ task's local data & params ] 0x10f6
; [ task's local data & params ] 0x10f5
; [SP] [ ] 0x10f4
;
The revised OSCtxSw() does OSEnterCritical(), pops the task's return address off the stack, saving this in OScTcbP->tFP as the re-entry address, restores SP from the value saved by OSDispatch(), pops r29 and r28, followed by OSLeaveCritical() and returns to OSSched(). This approach effectively destroys a task's local variables/parameters (as explained in the manual.) Here's what the stacks look like before, during, and after OSCtxSw().
code:
; Notes: This example illustrates 4-bytes of stack used for task's
; local data and why static vars should be used within tasks.
;
;
; ==== After entering OSCtxSw() and OSEnterCritical():
;
; [ rtn address low : main()] 0x10ff
; [ rtn address high : main()] 0x10fe
; [ R28 : OSSched()] 0x10fd
; [ rtn address low : OSSched()] 0x10fc
; [ rtn address high : OSSched()] 0x10fb
; [ R28 : OSDispatch()] 0x10fa
; [ R29 : OSDispatch()] 0x10f9
; [ task's local data & params ] 0x10f8
; [ task's local data & params ] 0x10f7
; [ task's local data & params ] 0x10f6
; [ task's local data & params ] 0x10f5
; [ rtn address low : task()] 0x10f4
; [ rtn address high : task()] 0x10f3
; [SP] [ ] 0x10f2
;
;
; ==== After popping the stack's return address. Saved at
; TcbP->tFP for use as entry/resume address by OSDispatch()
;
;
; [ rtn address low : main()] 0x10ff
; [ rtn address high : main()] 0x10fe
; [ R28 : OSSched()] 0x10fd
; [ rtn address low : OSSched()] 0x10fc
; [ rtn address high : OSSched()] 0x10fb
; [ R28 : OSDispatch()] 0x10fa
; [ R29 : OSDispatch()] 0x10f9
; [ task's local data & params ] 0x10f8
; [ task's local data & params ] 0x10f7
; [ task's local data & params ] 0x10f6
; [ task's local data & params ] 0x10f5
; [SP] [ rtn address low : task()] 0x10f4
; [ rtn address high : task()] 0x10f3
; [ ] 0x10f2
;
;
;
; ==== After restoring SP to what was saved by OSDispatch()
;
;
; [ rtn address low : main()] 0x10ff
; [ rtn address high : main()] 0x10fe
; [ R28 : OSSched()] 0x10fd
; [ rtn address low : OSSched()] 0x10fc
; [ rtn address high : OSSched()] 0x10fb
; [ R28 : OSDispatch()] 0x10fa
; [ R29 : OSDispatch()] 0x10f9
; [SP] [ task's local data & params ] 0x10f8
; [ task's local data & params ] 0x10f7
; [ task's local data & params ] 0x10f6
; [ task's local data & params ] 0x10f5
; [ rtn address low : task()] 0x10f4
; [ rtn address high : task()] 0x10f3
; [ ] 0x10f2
;
;
; ==== Stacks just before return to OSSched()
;
;
; [ rtn address low : main()] 0x10ff
; [ rtn address high : main()] 0x10fe
; [ R28 : OSSched()] 0x10fd
; [ rtn address low : OSSched()] 0x10fc
; [ rtn address high : OSSched()] 0x10fb
; [SP] [ R28 : OSDispatch()] 0x10fa
; [ R29 : OSDispatch()] 0x10f9
; [ task's local data & params ] 0x10f8
; [ task's local data & params ] 0x10f7
; [ task's local data & params ] 0x10f6
; [ task's local data & params ] 0x10f5
; [ rtn address low : task()] 0x10f4
; [ rtn address high : task()] 0x10f3
; [ ] 0x10f2
;
Here's the new OS_Replace() macro. It works, but I'm afraid I'm a newbie when it comes to inline assembly for avr-gcc.
code:
#define OS_Replace(tFP, prio)
do {
__asm__ __volatile__( "in __tmp_reg__, __SREG__
"
"cli
"
"lds __zero_reg__, OSframeP+0
"
"out __SP_L__, __zero_reg__
"
"lds __zero_reg__, OSframeP+1
"
"out __SP_H__, __zero_reg__
"
"out __SREG__, __tmp_reg__
"
"clr __zero_reg__" : : );
OSCreateTask(tFP, OScTcbP, prio);
__asm__ __volatile__( "pop r29
"
"pop r28
"
"ret
" : : );
} while (0)
@aek: I'll email you the portgccavr_new.S source.
-Tom
EDIT: In the original macro, I forgot to zero r1 after its use and to pop the top two bytes into r29, r28. This is now fixed.
[This message has been edited by zoomcityzoom (edited September 16, 2006).]