CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Suggestion for scratch registers

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

Suggestion for scratch registers
PostPosted: Mon Nov 23, 2015 10:22 pm     Reply with quote

I often use #INT_GLOBAL for faster interrupt speed, rather than the CCS interrupt dispatcher. One problem with this is that nothing is saved, unless I do it myself. With the PIC18F parts this is not much of a problem since the hardware saves STATUS, W, and BSR. But not so with the @SCRATCH registers.

It occurs to me that it might be desirable to have the compiler use a separate set of scratch registers during interrupts, assuming there is enough unused RAM to do it. It also might be difficult for functions that are called from both interrupt code and main code. But I would be content if just the #INT_GLOBAL routine used the alternate scratch registers. If I decide to call a function from both the interrupt code and the main code, I can take responsibility for saving the main scratch registers, but that would be a very rare application.

Is there already some option I am not aware of that would provide for using alternate scratch registers in interrupts? So far what I have done is examine the compiled code in the .LST file to see if scratch registers are being employed and then rewrite the code, if possible, to make the use of those registers unnecessary. If I cannot do that, then I do go ahead and save and restore the scratch registers.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Tue Nov 24, 2015 3:16 am     Reply with quote

Problem is the PIC is very inefficient at using 'movable' registers. Code that accesses an address that can change needs about 10 extra lines versus the same code accessing an address at a fixed location. Hence 'movable scratch' is not going to be efficient in a PIC. What you could do is load a separate maths library (how to do this has been described here), which then creates separate versions for the interrupt and main code, each with their own scratch. This would only leave a very few scratch locations common to both. However this is going to be quite bulky, and generally the scratch locations are few compared to the number of processor registers involved.

I've often wished the PIC had duplicate/swappable primary registers available (as was done years before on several early processors).
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Tue Nov 24, 2015 10:44 am     Reply with quote

It would not be necessary to have run-time movable scratch registers. It would be sufficient if the alternate scratch registers were just used for the in-line code generated in the #INT_GLOBAL function itself. I know there are lots of library functions that probably use scratch registers, and I don't expect those to be the alternate ones. If my interrupt routine is doing things involved enough to need library routines, then I probable have enough time to save and restore the standard scratch registers they might use. The real benefit to such an option would be for those very fast interrupt routines that have no need to call library functions. Just a simple 32-bit add and subtract is enough to invoke scratch registers. If those could be done with alternate scratch registers that would be a big help to me.
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Tue Nov 24, 2015 12:26 pm     Reply with quote

You are fractionally missing the point.
If the maths routines are going to use alternative copies of the scratch, the routines themselves have to be duplicated, otherwise they are going to have to use movable registers. Hence the need to load an alternative maths library. Understand that if you tell the compiler to use an alternative library, it only actually loads the routines that are _used_, so loading an extra library would only load the maths functions your code uses in the section involved.

Look at this thread:
<http://www.ccsinfo.com/forum/viewtopic.php?t=25464&start=4>

Which shows how to make the compiler use a separate library for the maths.

Do this, and you will find that the symbol map suddenly has two sets of scratch registers for the div16 routine....
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Tue Nov 24, 2015 1:11 pm     Reply with quote

As I said, I don't want or expect the math library routines to use alternate scratch registers. I have lots of interrupt code that does not use any math routines (from the library) at all. It does use some math operations, like adding and subtracting 32-bit numbers. I have looked at the compiled code in the LST file and they do not call any math routines. They are compiled into in-line calculations, which also happen to use scratch registers. The compiler could use alternate scratch registers for these in-line calculations without affecting any math library routines. I don't need to do something so drastic as load an entirely separate alternate math library to accomplish this. One work-around, I suppose might be to compile as it current is, then take the compiled code from the LST file and use it to design a #ASM...#ENDASM equivalent for what that code does, except that I will use my own scratch registers instead of the ones the compiler did. Of course this is a lot of work and is not very maintainable, which is why I raised the possibility of just specifying an option that in the #INT_GLOBAL code and _only_ in the #INT_GLOBAL code, ram locations 4,5,6 and 7 would be used instead of 0,1,2,3 (the usual @SCRATCH locations).
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Wed Nov 25, 2015 2:56 am     Reply with quote

Just use the example I showed, and see what it does.

Separate maths routines for the interrupt, and separate scratch. Exactly what you want/is needed. All maths is 'from the library'. 'Maths.c', is not 'the library', it is the extended (things like log') library.

It does what you want.
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Wed Nov 25, 2015 4:50 am     Reply with quote

Let me do a demo of how to use this:
Code:

#include <18F4520.h>   
#fuses XT,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

#byte FSR0L=getenv("SFR:FSR0L")
#byte FSR1L=getenv("SFR:FSR1L")
#byte FSR2L=getenv("SFR:FSR2l")
#byte FSR0H=FSR0L+1
#byte FSR1H=FSR1L+1
#byte FSR2H=FSR2L+1

//demo of building a INT_GLOBAL, that handles multiple interrupts (INT_EXT, and INT_TIMER2)
//and uses it's own local scratch - placing as low as possible above the core
//'global' section
#org 0x50,0x400 DEFAULT
//Both handlers now using separate scratch from the main
void int_ext_handler(void)
{
   int16 locala,localb,localc;
   //INT_EXT interrupt handler
   //using separata scratch from the main code
   localc=locala/localb; //prove where division scratch is put
   clear_interrupt(INT_EXT);
}

void int_timer2_handler(void)
{
    //Timer2 handler - doing nothing at the moment, but would use local
    //scratch
    clear_interrupt(INT_TIMER2);
}
#org default

#int_global
void myint(void) {
   static int INT_saves[6];
   //Save the fsr'S
#ASM
   MOVFF   FSR0L,INT_saves //save what registers you need - just demo with FSR's
   MOVFF   FSR0H,INT_saves+1
   MOVFF   FSR1L,INT_saves+2
   MOVFF   FSR1H,INT_saves+3
   MOVFF   FSR2L,INT_saves+4
   MOVFF   FSR2H,INT_saves+5
#endasm
   //Test for interrupts required
   //Since I don't at any point disable the individual interrupts, can save time
   //by just checking if they are  active, not enabled/disabled.
   if (interrupt_active(INT_EXT))
      int_ext_handler();
   if (interrupt_active(INT_TIMER2))
      int_timer2_handler();
   //Restore registers - again you need to restore what your code uses.
#ASM
   MOVFF   INT_saves,FSR0L
   MOVFF   INT_saves+1,FSR0H
   MOVFF   INT_saves+2,FSR1L
   MOVFF   INT_saves+3,FSR1H
   MOVFF   INT_saves+4,FSR2L
   MOVFF   INT_saves+5,FSR2H
   //Here the 'fast' exit.
FEXIT:
   RETFIE  1 //use retfie 1 - ensures W etc., are restored
#ENDASM
}

//=============================
void main(void)
{
   int16 a,b,c;
   enable_interrupts(INT_TIMER2);
   enable_interrupts(INT_EXT);
   enable_interrupts(GLOBAL);
   //maths in the main, to test where scratch gets put
   c = a/b;


   while(1)
     ;
}


Note also one 'key difference' from the CCS global handler. This will handle _both_ interrupts if both have triggered, only saving the registers once. More efficient.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Wed Nov 25, 2015 8:42 am     Reply with quote

Thank you for taking the time to prepare this demo for me. I pasted it into my project and compiled it, and this is what I noticed from looking at the resulting LST file:

The interrupt handlers call a version of @@DIV1616 located at 0x50 and the main program calls a version of @@DIV1616 located at 0x402. Looking at the code at 0x50 and 0x402, they are indeed very similar. But both versions start out by clearing RAM locations 0, 1, 2, and 3 (@SCRATCH in the symbol table). How is that not a problem? Supposedly the 0x402 version of @@DIV1616 could be interrupted and the 0x50 version given control, thus corrupting the 0x402's use of these four registers.

Then I applied the #ORG statements to my current code to further demonstrate the problem. Around my #INT_GLOBAL routine I put:

Code:
#org 0x150,0x400 DEFAULT
#INT_GLOBAL
void isr(void)
{
//..lots of code snipped..
   TXREG = txdata[tdcount-1];
//..lots of code snipped
#asm
   RETFIE   1   ;..fast return restores STATUS, W, and BSR
#endasm
}
#org DEFAULT


and in my main program I also had:
Code:
TXREG = txdata[tdcount-1];

Looking at the compiled code, the interrupt routine had
Code:
0010:  MOVLW  01
0012:  SUBWF  1F,W
0014:  CLRF   03
0016:  ADDLW  1A
0018:  MOVWF  FE9
001A:  MOVLW  00
001C:  ADDWFC 03,W
001E:  MOVWF  FEA
0020:  MOVFF  FEF,FAD

and the main program had
Code:
051E:  MOVLW  01
0520:  SUBWF  1F,W
0522:  CLRF   03
0524:  ADDLW  1A
0526:  MOVWF  FE9
0528:  MOVLW  00
052A:  ADDWFC 03,W
052C:  MOVWF  FEA
052E:  MOVFF  FEF,FAD

As you can see, both blocks of code used the same temporary scratch register at 0x03. This does not even involve any maths at all, just ordinary in-line array access. It is this kind of conflict with scratch registers I wish to prevent, and this #ORG method does not solve it. (I realize there is also a conflict with the use of the FSR registers, and that is a separate issue where I would have to explicitly save them as you did in your example. I just grabbed this code as an example. The only thing I am focusing on right now is the conflict with 0x03.)
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Wed Nov 25, 2015 9:41 am     Reply with quote

That's why I always save those four registers....

You started by asking about maths scratch, which is what I answered.
These are the general temporary scratch variables.

Now technically it should be possible to relocate these with #locate.
This was an ability that worked at one time, then stopped, then started again, and is not being accepted by the current compilers.
Sad

The syntax was:

#locate auto=<address>

I'd suggest a quick email to CCS, pointing out that this ability is not working.
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Wed Nov 25, 2015 10:25 am     Reply with quote

Ttelmah wrote:
That's why I always save those four registers....

You started by asking about maths scratch, which is what I answered.
These are the general temporary scratch variables.

Now technically it should be possible to relocate these with #locate.
This was an ability that worked at one time, then stopped, then started again, and is not being accepted by the current compilers.
Sad

The syntax was:

#locate auto=<address>

I'd suggest a quick email to CCS, pointing out that this ability is not working.

Will do. Thanks for pointing that out. It does indeed look like just what I want, if would only work. Right now it causes the next line of code to error with "Expecting identifier".
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
RLScott



Joined: 10 Jul 2007
Posts: 465

View user's profile Send private message

PostPosted: Wed Nov 25, 2015 3:12 pm     Reply with quote

After reporting the problem to support, I got a very prompt and useful response. Here is the whole story on the #locate auto directive:

Despite what the help file says, the correct syntax is:

Code:
void somefunction(...) {
#locate auto=myspace
int a,b,c,d;
//...the rest of the function
}


where myspace was previously defined with the addressmod() directive. This compiles OK, but it does not solve the problem that we were talking about. What this does is locate the RAM address range where any automatic C variables, like a, b, c, and d above, are assigned. But it does not affect the use of the scratch registers (0x00- 0x03 in previous posts).
_________________
Robert Scott
Real-Time Specialties
Embedded Systems Consulting
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Thu Nov 26, 2015 2:19 am     Reply with quote

I'd query back and point out you want to relocate the scratch.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group