|
|
View previous topic :: View next topic |
Author |
Message |
Vintermute
Joined: 11 Apr 2008 Posts: 5 Location: UK
|
A little bit on optimisation |
Posted: Fri Apr 11, 2008 6:19 am |
|
|
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
|
|
Posted: Sat Apr 26, 2008 9:46 pm |
|
|
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.
Cheers,
-Ben |
|
|
elder
Joined: 16 Mar 2005 Posts: 19
|
|
Posted: Tue May 06, 2008 6:47 am |
|
|
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
|
|
Posted: Wed May 07, 2008 8:56 am |
|
|
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 |
|
|
|
|
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
|