|
|
View previous topic :: View next topic |
Author |
Message |
P51D
Joined: 25 Jan 2010 Posts: 36
|
switch or if/else if |
Posted: Tue Jun 08, 2010 10:10 am |
|
|
Hello all
I've some problems with the speed of a little program.
What optimization-level does the CCS PCWHD 4.104 have? because the loop-speed of the main-functions seems like the great switch is programmed like a if{}else if{} statement.
and these part of the C/ASM-list file says the same:
Code: |
.................... switch (RS232_state){
00C0C: PUSH 23C2
00C0E: MOV [--W15],W0
00C10: LSR W0,#8,W0
00C12: CLR.B 1
00C14: XOR #0,W0
00C16: BRA Z,C32
00C18: XOR #1,W0
00C1A: BRA Z,CA4
00C1C: XOR #3,W0
00C1E: BRA Z,CE0
00C20: XOR #1,W0
00C22: BRA Z,DE2
00C24: XOR #7,W0
00C26: BRA Z,E36
00C28: XOR #1,W0
00C2A: BRA Z,F86
00C2C: XOR #3,W0
00C2E: BRA Z,FA2
00C30: BRA FC8
.................... case waitENQ:
.................... switch (rxBuf[index_rxBuf_R]){
00C32: MOV 235A,W0
00C34: SE W0,W0
00C36: MOV #235C,W4
00C38: ADD W0,W4,W5
00C3A: MOV.B [W5],W0L
00C3C: CLR.B 1
00C3E: XOR #3F,W0
00C40: BRA Z,C48
00C42: XOR #3A,W0
00C44: BRA Z,C6C
00C46: BRA C88
.................... case '?': // Suche der LCU
.................... printf(txBuf_Write,"USB LCU");
00C48: MOV #0,W1
00C4A: MOV W1,W0
00C4C: CALL 974
00C50: INC W1,W1
00C52: MOV W1,[W15++]
00C54: PUSH 243E
00C56: MOV.B W0L,[W15-#1]
00C58: POP 243E
00C5A: CALL B66
00C5E: MOV [--W15],W1
00C60: MOV #6,W0
00C62: CPSGT W1,W0
00C64: BRA C4A
.................... output_high(LED_green);
00C66: BSET.B 2D1.5
.................... break;
00C68: GOTO CA0
....................
.................... case ENQ:
.................... RS232_state = waitSOH; // In nächsten State wechselnd
00C6C: MOV 23C2,W0
00C6E: SWAP W0
00C70: MOV.B #1,W0L
00C72: SWAP W0
00C74: MOV W0,23C2
.................... txBuf_Write(ACK);
00C76: MOV 243E,W0
00C78: SWAP W0
00C7A: MOV.B #6,W0L
00C7C: SWAP W0
00C7E: MOV W0,243E
00C80: CALL B66
.................... break;
00C84: GOTO CA0
....................
.................... default:
.................... txBuf_Write(rxBuf[index_rxBuf_R]); // Unbekanter Befehl zurückgeben
00C88: MOV 235A,W0
00C8A: SE W0,W0
00C8C: MOV #235C,W4
00C8E: ADD W0,W4,W0
00C90: MOV.B [W0],W5L
00C92: PUSH 243E
00C94: MOV.B W5L,[W15-#1]
00C96: POP 243E
00C98: CALL B66
.................... break;
00C9C: GOTO CA0
|
There are only goto's at the breaks.
How could I set the optimization-level higher, so that I received a jump-table for switch statements?
Or isn't this possible with the ccs-compilers?
I use the PCWHD for a dsPIC30F6012A.
Thank you for helping
best wishes
P51D |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Tue Jun 08, 2010 12:15 pm |
|
|
Thank you for the ansver.
Why doesn't the ccs compiler create any jump-table if there is a default-case?
best wishes
P51D
Last edited by P51D on Wed Jun 09, 2010 1:19 am; edited 3 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jun 08, 2010 12:19 pm |
|
|
Quote: | Why doesn't the ccs compiler create any jump-table if there is a default-case? |
Email CCS support and ask them. (This forum consists of compiler users). |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Wed Jun 09, 2010 1:19 am |
|
|
How could I do it, if I need one?
I use the switch for a communication protocol and there it is necessary to have some default-actions.
and what happened when I uses switchs in some cases like this?
Code: |
switch(rxByte){
case 0:
break;
case 1:
break;
case 2:
switch(cmd){
case 0:
break;
case 1:
break;
}
break;
}
|
thank you for helping
best wishes
P51D |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Wed Jun 09, 2010 6:39 am |
|
|
Quote: | and what happened when I uses switchs in some cases like this? |
Write a test program and look at the list file. That is the best way to see how the compiler will handle the situation. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Wed Jun 09, 2010 12:45 pm |
|
|
ok, I've did it:
Code: |
.................... switch(a){
00A6C: PUSH 2430
00A6E: MOV [--W15],W0
00A70: LSR W0,#8,W0
00A72: CLR.B 1
00A74: XOR #0,W0
00A76: BRA Z,A82
00A78: XOR #1,W0
00A7A: BRA Z,A88
00A7C: XOR #3,W0
00A7E: BRA Z,A8E
00A80: BRA AB6
.................... case 0:
.................... output_high(LED_red);
00A82: BSET.B 2D1.6
.................... break;
00A84: GOTO AB6
.................... case 1:
.................... output_high(LED_red);
00A88: BSET.B 2D1.6
.................... break;
00A8A: GOTO AB6
.................... case 2:
.................... switch(b){
00A8E: MOV 2432,W0
00A90: CLR.B 1
00A92: XOR #0,W0
00A94: BRA Z,AA0
00A96: XOR #1,W0
00A98: BRA Z,AA6
00A9A: XOR #3,W0
00A9C: BRA Z,AAC
00A9E: BRA AB2
.................... case 0:
.................... output_high(LED_red);
00AA0: BSET.B 2D1.6
.................... break;
00AA2: GOTO AB2
.................... case 1:
.................... output_high(LED_red);
00AA6: BSET.B 2D1.6
.................... break;
00AA8: GOTO AB2
.................... case 2:
.................... output_high(LED_red);
00AAC: BSET.B 2D1.6
.................... break;
00AAE: GOTO AB2
.................... }
.................... break;
00AB2: GOTO AB6
.................... }
|
hmmm....
first, there is no difference between the switch with a default-case. I can't also see something like a jump-table at the beginning of the switch.
I will testing these different versions with an oszi, but I think, that CCS could not create so fast code... because the only gotos are the breaks.
Did I do something wrong, or is there no fast-switch version possible?
Thank for answering
best wishes
P51D |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Wed Jun 09, 2010 1:56 pm |
|
|
Switch with 10 cases, and in one case is also a switch with 10 other cases:
No change.
The first list-file part
Code: |
switch(a){
00A70: PUSH 2430
00A72: MOV [--W15],W0
00A74: LSR W0,#8,W0
00A76: CLR.B 1
00A78: XOR #0,W0
00A7A: BRA Z,AA6
00A7C: XOR #1,W0
00A7E: BRA Z,AAC
00A80: XOR #3,W0
00A82: BRA Z,AB2
00A84: XOR #1,W0
00A86: BRA Z,AB8
00A88: XOR #7,W0
00A8A: BRA Z,ABE
00A8C: XOR #1,W0
00A8E: BRA Z,AC4
00A90: XOR #3,W0
00A92: BRA Z,ACA
00A94: XOR #1,W0
00A96: BRA Z,AD0
00A98: XOR #F,W0
00A9A: BRA Z,AD6
00A9C: XOR #1,W0
00A9E: BRA Z,ADC
00AA0: XOR #3,W0
00AA2: BRA Z,AE2
00AA4: BRA AE8
.................... case 0:
.................... output_high(LED_red);
00AA6: BSET.B 2D1.6
.................... break;
00AA8: GOTO AE8
|
The communication switch is build like this:
Code: |
#define waitENQ 0
#define waitSOH 1
#define waitCMD 2
#define waitNUM 3
#define waitPAR 4
#define waitRED 0
#define waitGREEN 1
#define waitBLUE 2
#define waitAX1 3
#define waitAX2 4
#define waitAX3 5
#define waitACK 5
#define waitEOT 6
|
There is a main-switch with 6 cases and in case 4 there is another switch with 5 cases.
In the linked post is something written about more than 5 cases...
the dummy switch says the opposite.
When I read this, I think the ccs compiler has the same optimization like the standard versions...
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en534868
best wishes
P51D |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Sun Jun 13, 2010 7:36 am |
|
|
OK, now I've tested more different versions of switch with the result, that all switchs are made with if else if.
There is no performance upgrade if there is no default case and the cases are in line (from 0 to 50).
The loop-time is various (tested with toggle a pin) and the cases had all the same action.
Is there any possibility like the gcc to create manual a jump-table?
Something like this:
Code: |
static void *jumptable[] = { &&case1, &&case2, &&case3 };
goto *jumptable[i];
case1:
/* ... */
goto end_switch;
case2:
/* ... */
goto end_switch;
case3:
/* ... */
goto end_switch;
end_switch:
|
thank you for helping
P51D |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Sun Jun 13, 2010 10:03 am |
|
|
You need to tell us more, and show a real example doing this.
I have just tried a simple example, doing 'garbage', with 4.104:
Code: |
#include <18F452.h>
#FUSES NOWDT //No Watch Dog Timer
#fuses XT
#use delay(clock=4000000)
#use rs232(baud=300,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
void main()
{
int8 tval;
int8 sval;
for (sval=0;sval<10;sval++) {
switch (sval) {
case 0:
tval=1;
break;
case 2:
tval*=2;
break;
case 3:
tval-=1;
break;
case 4:
tval+=1;
break;
case 5:
tval=4;
break;
case 6:
tval/=2;
break;
case 7:
tval=6;
break;
case 8:
tval=0;
break;
case 9:
tval=2;
break;
}
printf("%u/n/r",tval);
}
while (TRUE);
}
|
and it happily develops a jump table for you.
Code: |
0144: ADDWF FE8,W
0146: CLRF FF7
0148: RLCF FF7,F
014A: ADDLW 5F
014C: MOVWF FF6
014E: MOVLW 01
0150: ADDWFC FF7,F
0152: TBLRD*-
0154: MOVF FF5,W
0156: MOVWF FFA
0158: TBLRD*
015A: MOVF FF5,W
015C: MOVWF FF9
015E: DATA EC,00
0160: DATA 20,01
0162: DATA F2,00
0164: DATA F8,00
0166: DATA FE,00
0168: DATA 04,01
016A: DATA 0A,01
016C: DATA 10,01
016E: DATA 16,01
0170: DATA 1A,01
|
You need to remove the 'nolist' option from the processor header, or the table _will not_ be visible. All you see for the 'switch', is the code to call the table:
Code: |
.................... switch (sval) {
00E0: MOVF 07,W
00E2: ADDLW F6
00E4: BC 0120
00E6: ADDLW 0A
00E8: GOTO 0144
|
Adding 'default', still switches to not using a table.
Best Wishes |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Sun Jun 13, 2010 10:18 am |
|
|
This is my test-switch:
the c-file:
Code: |
for(i=0;i<10;i++){
switch(i){
case 0:
output_toggle(LED_red);
break;
case 1:
output_toggle(LED_blue);
break;
case 2:
output_toggle(LED_green);
break;
case 3:
output_toggle(LED_orange);
break;
case 4:
output_toggle(LED_red);
break;
case 5:
output_toggle(LED_blue);
break;
case 6:
output_toggle(LED_green);
break;
case 7:
output_toggle(LED_orange);
break;
case 8:
printf(txBuf_Write,"hello");
break;
case 9:
printf(txBuf_Write,"world");
break;
}
}
|
C/ASM-List file:
Code: |
.................... for(i=0;i<10;i++){
003A4: MOV 23C4,W0
003A6: CLR.B 1
003A8: MOV W0,23C4
003AA: MOV 23C4,W0
003AC: LSR W0,#8,W0
003AE: CP.B W0L,#A
003B0: BRA GE,468
.................... switch(i){
003B2: PUSH 23C4
003B4: MOV [--W15],W0
003B6: LSR W0,#8,W0
003B8: CLR.B 1
003BA: XOR #0,W0
003BC: BRA Z,3E4
003BE: XOR #1,W0
003C0: BRA Z,3EA
003C2: XOR #3,W0
003C4: BRA Z,3F0
003C6: XOR #1,W0
003C8: BRA Z,3F6
003CA: XOR #7,W0
003CC: BRA Z,3FC
003CE: XOR #1,W0
003D0: BRA Z,402
003D2: XOR #3,W0
003D4: BRA Z,408
003D6: XOR #1,W0
003D8: BRA Z,40E
003DA: XOR #F,W0
003DC: BRA Z,414
003DE: XOR #1,W0
003E0: BRA Z,436
003E2: BRA 458
.................... case 0:
.................... output_toggle(LED_red);
003E4: BTG.B 2D1.6
.................... break;
003E6: GOTO 458
.................... case 1:
.................... output_toggle(LED_blue);
003EA: BTG.B 2D0.1
.................... break;
003EC: GOTO 458
.................... case 2:
.................... output_toggle(LED_green);
003F0: BTG.B 2D1.5
.................... break;
003F2: GOTO 458
.................... case 3:
.................... output_toggle(LED_orange);
003F6: BTG.B 2D0.2
.................... break;
003F8: GOTO 458
.................... case 4:
.................... output_toggle(LED_red);
003FC: BTG.B 2D1.6
.................... break;
003FE: GOTO 458
.................... case 5:
.................... output_toggle(LED_blue);
00402: BTG.B 2D0.1
.................... break;
00404: GOTO 458
.................... case 6:
.................... output_toggle(LED_green);
00408: BTG.B 2D1.5
.................... break;
0040A: GOTO 458
.................... case 7:
.................... output_toggle(LED_orange);
0040E: BTG.B 2D0.2
.................... break;
00410: GOTO 458
.................... case 8:
.................... printf(txBuf_Write,"hello");
00414: MOV #0,W1
00416: MOV W1,W0
00418: CALL 100
0041C: INC W1,W1
0041E: MOV W1,[W15++]
00420: PUSH 23C6
00422: MOV.B W0L,[W15-#1]
00424: POP 23C6
00426: CALL 26A
0042A: MOV [--W15],W1
0042C: MOV #4,W0
0042E: CPSGT W1,W0
00430: BRA 416
.................... break;
00432: GOTO 458
.................... case 9:
.................... printf(txBuf_Write,"world");
00436: MOV #0,W1
00438: MOV W1,W0
0043A: CALL 112
0043E: INC W1,W1
00440: MOV W1,[W15++]
00442: PUSH 23C6
00444: MOV.B W0L,[W15-#1]
00446: POP 23C6
00448: CALL 26A
0044C: MOV [--W15],W1
0044E: MOV #4,W0
00450: CPSGT W1,W0
00452: BRA 438
.................... break;
00454: GOTO 458
.................... }
.................... }
00458: MOV 23C4,W0
0045A: LSR W0,#8,W0
0045C: INC.B W0L,W0L
0045E: PUSH 23C4
00460: MOV.B W0L,[W15-#1]
00462: POP 23C4
00464: GOTO 3AA
|
Quote: |
You need to remove the 'nolist' option from the processor header, or the table _will not_ be visible. All you see for the 'switch', is the code to call the table:
|
?? Where is this option? as a fuse?
best wishes
P51D |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Sun Jun 13, 2010 2:21 pm |
|
|
At the top of each header file, there is a line '#nolist'. This turns _off_ listing in the assembler .lst file, for some of the internal code.
On your example, the code is so short in each case, that the individual 'test' option, actually (just) results in shorter code than the jump table. The optimiser seems to be being 'smart ' enough to decide this, and is opting to do the individual tests.
Best Wishes |
|
|
P51D
Joined: 25 Jan 2010 Posts: 36
|
|
Posted: Mon Jun 14, 2010 1:12 am |
|
|
Now I've tried it with your example and also with another one where in the cases were more code (printf).
The jump-table was nowhere created:
Code: |
00466: PUSH 23C6
00468: MOV [--W15],W0
0046A: LSR W0,#8,W0
0046C: CLR.B 1
0046E: XOR #0,W0
00470: BRA Z,494
00472: XOR #2,W0
00474: BRA Z,49E
00476: XOR #1,W0
00478: BRA Z,4B2
0047A: XOR #7,W0
0047C: BRA Z,4C2
0047E: XOR #1,W0
00480: BRA Z,4D2
00482: XOR #3,W0
00484: BRA Z,4DC
00486: XOR #1,W0
00488: BRA Z,4F4
0048A: XOR #F,W0
0048C: BRA Z,4FE
0048E: XOR #1,W0
00490: BRA Z,508
00492: BRA 512
|
I have changed the header-file like this:
Code: |
//////// Standard Header file for the DSPIC30F6012A device ////////////////
#device DSPIC30F6012A
//#nolist
//////// Program memory: 49152x24 Data RAM: 8192 Stack: 31
//////// I/O: 52 Analog Pins: 16
//////// Data EEPROM: 4096
//////// Fuses: XTL,HS,XT,XT_PLL4,XT_PLL8,XT_PLL16,ER_IO,ER,EC,EC_IO,EC_PLL4
//////// Fuses: EC_PLL8,EC_PLL16,LP,FRC,LPRC,PR,NOCKSFSM,CKSNOFSM,CKSFSM,WDT
//////// Fuses: NOWDT,WPSB1,WPSB2,WPSB3,WPSB4,WPSB5,WPSB6,WPSB7,WPSB8,WPSB9
//////// Fuses: WPSB10,WPSB11,WPSB12,WPSB13,WPSB14,WPSB15,WPSB16,WPSA1,WPSA8
//////// Fuses: WPSA64,WPSA512,NOPUT,PUT4,PUT16,PUT64,BROWNOUT,NOBROWNOUT
//////// Fuses: BORRES,BORV27,BORV42,LPOL_LOW,HPOL_LOW,NOPWMPIN,MCLR,NOMCLR
//////// Fuses: PROTECT,NOPROTECT,WRT,NOWRT,DEBUG,NODEBUG,COE,NOCOE,ICSP1
//////// Fuses: ICSP2,ICSP3,ICSP4,FRC_PLL4,FRC_PLL8,FRC_PLL16,HS2_PLL4
//////// Fuses: HS2_PLL8,HS2_PLL16,HS3_PLL4,HS3_PLL8,HS3_PLL16,PR_PLL,BORV45
//////// Fuses: NOWRTSS,WRTSS,NOSSS,SSSS8K,SSSS16K,SSSS32K,NOSSS,SSSH8K
//////// Fuses: SSSH16K,SSSH32K,NORSS,RSS256,RSS2048,RSS4096,WRTB,NOWRTB
//////// Fuses: NOBSS,BSSSS,BSSSM,BSSSL,NOBSS,BSSHS,BSSHM,BSSHL,NOEBS,EBS
//////// Fuses: NORBS,RBSS,RBSM,RBSL,NOESS,ESSS,ESSM,ESSL,PROTECT_HIGH
////////
////////////////////////////////////////////////////////////////// I/O
// Discrete I/O Functions: SET_TRIS_x(), OUTPUT_x(), INPUT_x(),
// SET_PULLUP(), INPUT(),
// OUTPUT_LOW(), OUTPUT_HIGH(),
// OUTPUT_FLOAT(), OUTPUT_BIT()
// Constants used to identify pins in the above are:
|
This is the result with your controller:
Code: |
.................... int8 tval;
.................... int8 sval;
.................... for (sval=0;sval<10;sval++) {
00E0: CLRF 06
00E2: MOVF 06,W
00E4: SUBLW 09
00E6: BNC 0144
.................... switch (sval) {
00E8: MOVF 06,W
00EA: ADDLW F6
00EC: BC 0128
00EE: ADDLW 0A
00F0: GOTO 0148
.................... case 0:
.................... tval=1;
00F4: MOVLW 01
00F6: MOVWF 05
.................... break;
00F8: BRA 0128
.................... case 2:
.................... tval*=2;
00FA: BCF FD8.0
00FC: RLCF 05,F
.................... break;
00FE: BRA 0128
.................... case 3:
.................... tval-=1;
0100: MOVLW 01
0102: SUBWF 05,F
.................... break;
0104: BRA 0128
.................... case 4:
.................... tval+=1;
0106: MOVLW 01
0108: ADDWF 05,F
.................... break;
010A: BRA 0128
.................... case 5:
.................... tval=4;
010C: MOVLW 04
010E: MOVWF 05
.................... break;
0110: BRA 0128
.................... case 6:
.................... tval/=2;
0112: BCF FD8.0
0114: RRCF 05,F
.................... break;
0116: BRA 0128
.................... case 7:
.................... tval=6;
0118: MOVLW 06
011A: MOVWF 05
.................... break;
011C: BRA 0128
.................... case 8:
.................... tval=0;
011E: CLRF 05
.................... break;
0120: BRA 0128
.................... case 9:
.................... tval=2;
0122: MOVLW 02
0124: MOVWF 05
.................... break;
0126: BRA 0128
.................... }
.................... printf("%u/n/r",tval);
0128: MOVFF 05,07
012C: MOVLW 1B
012E: MOVWF 08
0130: BRA 0034
0132: MOVLW 06
0134: MOVWF FF6
0136: MOVLW 00
0138: MOVWF FF7
013A: MOVLW 04
013C: MOVWF 07
013E: BRA 00A2
.................... }
0140: INCF 06,F
0142: BRA 00E2
.................... while (TRUE);
0144: BRA 0144
.................... }
0146: SLEEP
|
Is there one more setting?
best wishes
P51D |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Mon Jun 14, 2010 7:30 am |
|
|
In your second lot of code, you have the jump table.
The GOTO 0148 instruction at 0xF0, is jumping to the jump table code. You need to then look at the code at 0148, which is the code to load a value from the table, and jump to it.
In your first lot of code, the test and branch version, is faster and smaller, for all except the last two solutions, than the jump table solution. It takes 'best case' 5 instruction times, and 'worst case', 21 instruction times. Average 13 instruction times. The jump table solution takes 18 instruction times for every possible value. The optimiser is deciding that the test is faster, since it is...
Best Wishes |
|
|
|
|
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
|