Pumpkin, Inc.

Pumpkin User Forums

OS_Replace() via OSDispatch broken for avr-gcc??

For issues specific to Atmel's AVR and MegaAVR microcontrollers, including Atmel AVRStudio and ImageCraft's ICCAVR C compiler.

OS_Replace() via OSDispatch broken for avr-gcc??

Postby zoomcityzoom » Wed Sep 13, 2006 12:03 am

This is a call graph for the test_salvo avr-fcc 3.4.6 project. The test_salvo project
was written to illustrate a problem with using the OS_Replace() macro.

OSDispatch() pushes r28,r29 onto stack, then adjusts stack frame and jumps to task. This works when using OS_Yield(), or any of the OS_Wait type user services because in the end, they all call OSCtxSw() which cleans up the stack, including removing r28,r29. This is not happening when using OS_Replace().

With OS_Replace(), the contents of registers r28 and r29 that are left on the stack by OSDispatch() are used as a return address by the task being OS_Replaced.


The WinAVR (Salvo Pro) test_salvo.zip project can be found here

The callgraph.txt file can be found here

Tom

[This message has been edited by zoomcityzoom (edited September 13, 2006).]

[This message has been edited by zoomcityzoom (edited September 13, 2006).]

Tom Deutschman
Wizbang Designs, Inc.
zoomcityzoom
 
Posts: 13
Joined: Sat Dec 24, 2005 12:00 am
Location: Spokane, WA, USA

Re: OS_Replace() via OSDispatch broken for avr-gcc??

Postby zoomcityzoom » Wed Sep 13, 2006 12:56 am

Thanks for the workaround. OS_Replace() works on the AVR with the ICCAVR compiler. I think, because to the hardware stack being used only for return addresses.

You can imagine my confusion when I switched from ICCAVR to WinAVR! I'm in it this far, I'm going to see if I can come up with a solution.

Tom Deutschman
Wizbang Designs, Inc.
zoomcityzoom
 
Posts: 13
Joined: Sat Dec 24, 2005 12:00 am
Location: Spokane, WA, USA

Re: OS_Replace() via OSDispatch broken for avr-gcc??

Postby aek » Wed Sep 13, 2006 11:43 am

Yes, it's broken for several ports. I think it only worked for the PICC/PICC-18 ports, but I'm not sure. Am investigating.

Here's what one user did recently:

code:
I worked around replacing
OS_Replace(MODEM_TaskConnect,1);
with
OSCreateTask(MODEM_TaskConnect, ANOTHER TCB, 1);
OS_Destroy();

It costs me another TCB but later I can reuse the destroyed TCBs with OSCreateTask ()

------------------

-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: OS_Replace() via OSDispatch broken for avr-gcc??

Postby zoomcityzoom » Fri Sep 15, 2006 2:30 am

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).]

Tom Deutschman
Wizbang Designs, Inc.
zoomcityzoom
 
Posts: 13
Joined: Sat Dec 24, 2005 12:00 am
Location: Spokane, WA, USA


Return to Atmel AVR and MegaAVR

Who is online

Users browsing this forum: Baidu [Spider] and 1 guest

cron