1
\$\begingroup\$

Most of my dsPIC3 application is written in C, but one function is particularly speed sensitive, so I had to write that function in assembler. The function looks roughly like this:

_FunctionName:
lnk #0x0
push w0 .. w15

< code that uses all registers >

pop w15 .. w0

ulnk
return

Is this a bad idea? Or will the use of some registers cause me problems, even if I've pushed them onto the stack?

\$\endgroup\$
  • \$\begingroup\$ How are you wrapping the function to call it from C-land? A .S file? A naked function? An asm(); directive? \$\endgroup\$ – Kevin Vermeer Sep 13 '11 at 23:01
3
\$\begingroup\$

The C30 compiler expects a subroutine to preserve W8-W15 but it may trash W0-W7. You therefore only need to save/restore W8-W14 if you are going to use them. Otherwise if you can make do with W0-W7 for scratch, then there is no need to save/restore anything.

Note that you never explicitly push/pop W15 since that's the stack pointer. The way to save/restore it is to pop the same amount of stuff off the stack that you push onto it, including the subroutine return address which is generally popped by executing RETURN.

I set the C30 mode to not use stack frames. Stack frames can occasionally be a aid in debugging, but otherwise they are just a waste of space and cycles. There is a command line option to the C30 compiler which prevents it from using stack frames, and therefore doesn't emit the silly link/unlink sequences. I have so far always used that and not had problems.

One other issue with your code above is that you forgot to declare _FunctionName global.

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Calling assembler routines from C programs is covered in Chapter 9 of the Compiler User's Guide. There is a lot to it and you need to read it thoroughly. W8-W15 are saved anyway, in a function call, and W0-W7 can be used as scratch registers.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Are they saved automatically, or is it the responsibility of the programmer/compiler author to preserve them? It appears that Rocketmagnet is placing this function in its own file. If the function is placed in a standard C function, and the body is assembly in an asm(); macro, then I think we can consider them saved, but otherwise we can't. \$\endgroup\$ – Kevin Vermeer Sep 13 '11 at 23:00
  • \$\begingroup\$ They are saved automatically, according to the User's Guide. \$\endgroup\$ – Leon Heller Sep 14 '11 at 8:48
  • \$\begingroup\$ That's...interesting. How would you write a function that didn't have the overhead of copying W8-W15 to the stack? \$\endgroup\$ – Kevin Vermeer Sep 14 '11 at 10:01
  • \$\begingroup\$ @Leon: What you're saying is a little misleading. If the calling code is in C30, then the compiler expects the subroutine to preserve W8-W14. There is no automatic saving of these that I know of. If your assembler subroutine uses any of W8-W14, then it has to somehow preserve them from entry to exit. The usual way is to push any of these registers it's going to trash onto the stack on entry and pop them on exit. You could also, for example, save them in dedicated static locations for that purpose. \$\endgroup\$ – Olin Lathrop Sep 14 '11 at 11:35
  • \$\begingroup\$ I already read that chapter, but sadly only a page and a half of it covers calling asm functions from C, and it never mentions which registers need saving. \$\endgroup\$ – Rocketmagnet Sep 14 '11 at 17:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.