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

A little bit on optimisation

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
Vintermute



Joined: 11 Apr 2008
Posts: 5
Location: UK

View user's profile Send private message

A little bit on optimisation
PostPosted: Fri Apr 11, 2008 6:19 am     Reply with quote

I thought I would post this little example of code optimisation (although it may be obvious to some people)

Normal good coding practice does not always produce the most efficient software so sometimes, when you want to squeeze a bit extra out of your PIC, it helps to bend the rules.

Lets say you have an array of variables and you want to perform some identical operation on every element in the array (for simplicity lets just set each variable to zero) Normally the way to do this is with a for loop as follows
Code:

#define ARRAY_SIZE 4
int16 Data[ARRAY_SIZE];
int8 Index;

for(Index = 0; Index < ARRAY_SIZE; Index++)
{
   Data[Index] = 0;
}


Ok, nice simple and compact code, or maybe not...

If you compile this you get the following assembly language (Compiled with PCD):

Code:

....................    #define ARRAY_SIZE 4
....................    int16 Data[ARRAY_SIZE];
....................    int8 Index;
....................    for(Index = 0; Index < ARRAY_SIZE; Index++)
*
0102:  CLR.B   848
0104:  MOV     848,W4
0106:  CP.B    W4L,#4
0108:  BRA     GE,11E
....................    {
....................       Data[Index] = 0;
010A:  MOV.B   848,W0L
010C:  SE      W0,W0
010E:  MOV     W0,W4
0110:  MUL.UU  W4,#2,W0
0112:  MOV     #840,W4
0114:  ADD     W0,W4,W5
0116:  MOV     #0,W4
0118:  MOV     W4,[W5+#0]
....................    }
011A:  INC.B   0848
011C:  BRA     104


Now this doesn't look like much but actually the majority of these instructions are used with every iteration of the loop, so as a rough guide you can multiply the number of instructions above by whatever size array you have and get the actual number of instructions that your PIC will have to work through - in other words 11x4 instructions (Ignoring the few instructions to do with setting up the loop).

An alternative, but slightly laborious and memory hungry alternative is to forget the loop and explicitly code each step. The example above would turn into the following code:

Code:

#define ARRAY_SIZE 4
int16 Data[ARRAY_SIZE];
Data[0] = 0;
Data[1] = 0;
Data[2] = 0;
Data[3] = 0;


This actually looks simpler than the first example but only because the loop is short and the operations inside it are simple. What really matters is how this turns into machine code:

Code:

....................    #define ARRAY_SIZE 4
....................    int16 Data[ARRAY_SIZE];
....................    Data[0] = 0;
019A:  CLR     840
....................    Data[1] = 0;
019C:  CLR     842
....................    Data[2] = 0;
019E:  CLR     844
....................    Data[3] = 0;
01A0:  CLR     846


As you can see explicitly un-looping this particular bit of code has reduced it from 11x4 instructions (48) to just 4!. Two things help make the first example very instruction hungry, first (obviously) is the loop iterating and checking but second is using the loop variable as the index for the array. If you use a constant to index an array it is a lot quicker than having the PIC fetch a variable from memory in order to fetch another variable from memory.

Of course this has a disadvantage in terms of code maintenance, if you want to change the size of the array the you have to re-write a lot of code, rather than just changing the value of the constant. If you want tu use a large array (say 256 elements) you can end up writing LOTS of code (and possibly running out of Flash memory in the process).

This kind of optimisation can be useful in some circumstances though. I have used it for filtering arrays of ADC data where I only ever have 8 channels so I don't have to worry about re-writing the code for a different array size.

Finally...

I can't help thinking that CCS should add an optimisation keyword to the compiler called #unloop which you could place before a for loop to convert it into explicit step-by-step instructions
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Sat Apr 26, 2008 9:46 pm     Reply with quote

Actually, I've been doing a mix of this on a PIC18F project with PCH.

Another good example of optimization is using bitwise XOR to flip bits on say, PORTB instead of using IF's to step through the process.

using an XOR takes a BUNCH of instruction (I think it was 7) while using IF's reduce the concept to a few test w/branches... so technically, the IF's are faster. Smile

Cheers,

-Ben
elder



Joined: 16 Mar 2005
Posts: 19

View user's profile Send private message

PostPosted: Tue May 06, 2008 6:47 am     Reply with quote

Another alternative is to use write_bank() command and force the starting address of the array using #byte to begin at the start of a ram bank.

Not as good in your case obviously, but this retains the variable functionality... Example on PIC18F using 8bit array:

Code:
int8 Data[ARRAY_SIZE];
int8 Index;

for(Index = 0; Index < ARRAY_SIZE; Index++){
  06BC    CLRF 0x22, ACCESS
  06BE    MOVF 0x22, W, ACCESS
  06C0    SUBLW 0x3
  06C2    BNC 0x6da
Data[Index] = 0;
  06C4    CLRF 0x3, ACCESS
  06C6    MOVF 0x22, W, ACCESS
  06C8    ADDLW 0x1e
  06CA    MOVWF 0xfe9, ACCESS
  06CC    MOVLW 0
  06CE    ADDWFC 0x3, W, ACCESS
  06D0    MOVWF 0xfea, ACCESS
  06D2    CLRF 0xfef, ACCESS
}
  06D4    INCF 0x22, F, ACCESS
  06D6    GOTO 0x6be


VS..

Code:
int8 Data[ARRAY_SIZE];
#Byte Data = 0x100  //bank 1 start (18F25K20)
int8 Index;
     
for(Index = 0; Index < ARRAY_SIZE; Index++){
  06BC    CLRF 0x1e, ACCESS
  06BE    MOVF 0x1e, W, ACCESS
  06C0    SUBLW 0x3
  06C2    BNC 0x6d4
write_bank(1, Index, 0); 
  06C4    MOVFF 0x1e, 0xfe1
  06C8    MOVLW 0x1
  06CA    MOVWF 0xfe2, ACCESS
  06CC    CLRF 0xfe7, ACCESS
}
  06CE    INCF 0x1e, F, ACCESS
  06D0    GOTO 0x6be


Thanks to PCM Programmer for showing me this years ago
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Wed May 07, 2008 8:56 am     Reply with quote

Hmmm, Neat trick.. I wonder how well that works out for arrays that are int16 or int32.

Will have to try that one out.

-Ben
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library 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