Page 1 of 1

Context saving in an Exception handler

PostPosted: Sat May 16, 2015 4:50 pm
by Timbo
When I have code in an interrupt exception handler what do I need to do about interrupt context saving. And how do I find out what needs saving. eg is the simple way. I know I can look at the asm. I never do anything but basic maths and logic testing but not sure how it handles complex maths eg

RoundedDiv = (ValueNum + ( ValueDivisor / 2)) / ValueDivisor

Does that start using internal variables or is the code broken so does not need to hold intermediate vars


Thanks

Re: Context saving in an Exception handler

PostPosted: Sat May 16, 2015 11:20 pm
by Jerry Messina
There's no quick easy answer to that. It depends on a number of factors... the data types involved, 8/16/32 bit target, etc.

In general, multiplication and division will probably involve one of the system libraries, so you should use 'save(0)' to protect the internal system variables (those named SB_xxxxx). For the PIC18 (which I think you're using), save(0) will also save the FSR0, FSR1, and PROD registers for you.

An expression like
Code: Select all
RoundedDiv = (ValueNum + ( ValueDivisor / 2)) / ValueDivisor

will almost always generate some intermediate temp variables, but you normally shouldn't have to worry too much about those if the code is
directly inline in the isr. If it's in a sub or event that you call from the isr that's a different story. If you call a routine then you should add the sub's name to the save() list.

If you want to avoid the use of any intermediate values, then you have to help the compiler along and break up the expression so that there's nothing on the right-hand side that would have to be saved...
Code: Select all
    RoundedDiv = ValueDivisor / 2
    RoundedDiv = RoundedDiv + ValueNum
    RoundedDiv = RoundedDiv/ValueDivisor

Sometimes that can end up producing smaller code as well, but it's a lot of bother and makes it much harder to see what the intent is.

So, the general rule is something like this:
- if you don't want to bother looking at the asm, use 'save(0)'
- if you call ANY routines from the isr, add them to the 'save()' list

That should be safe. It might be overkill, but it should work. If you want to reduce the overhead then you need to do a little digging.

PS - I assumed you meant an interrupt handler, and not a PIC24 exception handler. Two different things.

Re: Context saving in an Exception handler

PostPosted: Sun May 17, 2015 9:27 am
by Timbo
Hi Jerry

You're a wealth of great info.

Normally I break up lines of code exactly like you showed, its no issue to me on the readability as I try to comment it well enough for me to figure it out later.

The reason I asked is that in the long past when talking to Dave about how the compiler works he said code size would not be affected as the compiler broke down long lines internally. But as you rightly pointed out there will have to be holding vars for that line.
I'm going to break it down just incase and use save(0)

The code is currently being written for the FireWing18 as I can VSM it. So for its been great boon as I am simulating the mechanical hardware it's connected to with another pic.

I know I have a lot to learn about the inner workings of Firewing but I have to say so far it's a fantastic accomplishment.

Thanks again.

Re: Context saving in an Exception handler

PostPosted: Sun May 17, 2015 11:52 am
by Jerry Messina
There's one thing you have to watch out for if you break the expression up into smaller pieces.

Lets say all of those variables are 16-bit (ushort) types.
In the original equation
Code: Select all
    RoundedDiv = (ValueNum + ( ValueDivisor / 2)) / ValueDivisor
the compiler's smart enough to recognize that in order to produce a correct result it needs to use 32-bit math, and halfway through the calculations it automatically switches precision, doing the addition and final division as 32-bit.

When you break it up into smaller chunks it may not do this. In the example code I posted the addition and division are done as 16-bit and any overflow from the addition is thrown away, so the results from the two methods can be different. That's one of the reasons the code ends up smaller.

If you know the range of values you're working with that can be ok, but if you want it to use "always produce the correct result for me" mode you're better off with leaving it all as one expression.

David's code is usually pretty good at recognizing this sort of thing. It can make life a lot easier.