I have a thought that would make many processes much more effective and, being only one voice, I would like to know if there is a demand before I propose it to Keil. This is the result of me having to change a switch statement to a series of IFs to make an ISR process fast enough. I realize, and thus do not complain, that Keil caould not implemet an ANSI-C switch more efficient than the way it is done. 'n' below will be either 2 or 3 (if Keil decide to implement, they can choose) a Proposal: if #pragma QUICKSWITCH then a) no case value can be more than 255 b) all case values must be multiples of n c) the switch will be implemented as a jump table Erik
The compiler actually generates already a jump table if the cases are in sequence. Take a look to: http://www.keil.com/support/docs/1316.htm There is a quite extensive algorithm that decides whether a jump table or compare operations are more efficient.
this seems to 'follow the rules' but there still is the slow switch
348 //////////////////////////////////////////////////////////// 349 // 350 // ISR 14: void ISR_T3 (void) 351 // 352 353 void ISR_T3 (void) interrupt 14 using 1 354 { 355 1 SB1_TMR3CN_TR = 0; 356 1 SB1_TMR3CN_TF = 0; 357 1 switch (GC4holdState) 358 1 { 359 2 case G4HS_IDLE: // 0x00 should never happem 360 2 catchT3(0x01); 361 2 break; 362 2 363 2 case G4HS_RCDN: // 0x01 receive complted now processing 364 2 SBG_P0_D485 = 1; 365 2 SG_SFRPAGE = 0; 366 2 SB0_SCON0_TB8 = 1; 367 2 S0_SBUF0 = RSP_BUSY; 368 2 break; 369 2 370 2 case G4HS_RCCM: // 0x02 processing of receive complted 371 2 SBG_P0_D485 = 1; 372 2 SG_SFRPAGE = 0; 373 2 SB0_SCON0_TB8 = 1; 374 2 S0_SBUF0 = RSP_CMPL; 375 2 GC4holdState = G4HS_IDLE; 376 2 break; 377 2 378 2 case G4HS_RCER: // 0x03 receive complted, error detected, record ignored 379 2 SBG_P0_D485 = 1; 380 2 SG_SFRPAGE = 0; 381 2 SB0_SCON0_TB8 = 1; 382 2 S0_SBUF0 = RSP_ERR; 383 2 GC4holdState = G4HS_IDLE; 384 2 break; 385 2 386 2 case G4HS_RCHO: // 0x04 receive response completed hold off switch to receive 387 2 SBG_P0_D485 = 0; 388 2 GC4holdState = G4HS_IDLE; 389 2 break; 390 2 391 2 default: 392 2 catchT3(0xff); 393 2 break; 394 2 395 2 } 396 1 } ; SOURCE LINE # 353 ; SOURCE LINE # 355 000B C2CA CLR SB1_TMR3CN_TR ; SOURCE LINE # 356 000D C2CF CLR SB1_TMR3CN_TF ; SOURCE LINE # 357 000F E500 E MOV A,GC4holdState 0011 120000 E LCALL ?C?CCASE 0014 0000 R DW ?C0048 0016 00 DB 00H 0017 0000 R DW ?C0049 0019 01 DB 01H 001A 0000 R DW ?C0050 001C 02 DB 02H 001D 0000 R DW ?C0051 001F 03 DB 03H 0020 0000 R DW ?C0052 0022 04 DB 04H 0023 0000 DW 00H 0025 0000 R DW ?C0053
Which OPTIMIZE level are you using?
Which OPTIMIZE level are you using? 2, just to get the variable overlaying. I do not and will not use optimizers, they defeat the NASA principle "we fly what we test" which, since some testing for unforseen events is done by pegging values in the emulator makes working with 'optimized' code an impossibility. doing 'quickswitch' should be a compiler issue, not an optimizer issue. Erik
Two things to consider: - almost everyone uses the default optimization 8. You can still 'fly' what you 'test' since full debug information is provided. Therefore this is also the best tested compiler mode. - switch/case optimzation requires some other information that is generated by optimizers that need to run. switch/case optimzation is enabled with OT(4) and above.
- almost everyone uses the default optimization 8. You can still 'fly' what you 'test' since full debug information is provided. there is with any optimization (I do not consider overlaid variables optimization) several disadvantages: a) there will be many mismatches between source and actual code b) I know the Keil compiler is so excellent that I do not need to check the assembler, but I do anyhow, see also d). c) 'merged' sequences makes reasonable breakpointing impossible. d) often a fault in the c source is revealed by what is assembled from it and .. finally .. e) I am not "almost everyone" and have no desire to be. Therefore this is also the best tested compiler mode why 'tested' this is not about 'testing' it is functionality. switch/case optimzation requires some other information that is generated by optimizers that need to run. I am VERY curious, which added information would be required to make my example above into a jump table. Erik
a footnote to the above: I once had a timing error that only did show when the optimizer was active. Debugging it, by any 'helped means' (emulation) was impossible beacuse the critical sections were 'combined' with frequent operations by the optimizer. For that reason it took 6 weeks to find a problem that, had it shown in non-optimized, would have been a matter of a day or two. It turned out to be a subtle bug in a (then) recently released Atmel derivative, not the design. Erik
void ISR_T3 (void) interrupt 14 using 1 { SB1_TMR3CN_TR = 0; SB1_TMR3CN_TF = 0; switch (GC4holdState) { case G4HS_IDLE: // 0x00 should never happem catchT3(0x01); return; case G4HS_RCDN: // 0x01 receive complted now processing SBG_P0_D485 = 1; SG_SFRPAGE = 0; SB0_SCON0_TB8 = 1; S0_SBUF0 = RSP_BUSY; return; case G4HS_RCCM: // 0x02 processing of receive complted SBG_P0_D485 = 1; SG_SFRPAGE = 0; SB0_SCON0_TB8 = 1; S0_SBUF0 = RSP_CMPL; GC4holdState = G4HS_IDLE; return; case G4HS_RCER: // 0x03 receive complted, error detected, record ignored SBG_P0_D485 = 1; SG_SFRPAGE = 0; SB0_SCON0_TB8 = 1; S0_SBUF0 = RSP_ERR; GC4holdState = G4HS_IDLE; return; case G4HS_RCHO: // 0x04 receive response completed hold off switch to receive SBG_P0_D485 = 0; GC4holdState = G4HS_IDLE; return; } catchT3(0xff); }
Eric, just a thought to avoid the ccase: the above code should result in code without calling the cccase. Thats my trick to work around your proposal. ??? I have no problem with the call to ccase, I want it, it is a debug catcher for 'impossible' conditions. What I want is a JUMP TABLE instead of the cumbersome code for the 'flexible' switch statement. Erik
sorry, ccase you refer to is the Keil switch subroutine? I have a similarily named flycatcher. Are you, in effect, saying that the jump table is implemented if there is no default: in the code, that is a BUG!. Erik
I took out the default: and ?C?CCASE is still called. Erik
getting late, I now see the 'return', I included it to the below and ?C?CCase is still called. what is different from what you show?
367 //////////////////////////////////////////////////////////// 368 // 369 // ISR 14: void ISR_T3 (void) 370 // 371 372 void ISR_T3 (void) interrupt 14 using 1 373 { 374 1 SB1_TMR3CN_TR = 0; 375 1 SB1_TMR3CN_TF = 0; 376 1 switch (GC4holdState) 377 1 { 378 2 case G4HS_IDLE: // 0x00 should never happem 379 2 catchT3(0x01); 380 2 // break; 381 2 return; 382 2 383 2 case G4HS_RCDN: // 0x01 receive complted now processing 384 2 SBG_P0_D485 = 1; 385 2 SG_SFRPAGE = 0; 386 2 SB0_SCON0_TB8 = 1; 387 2 S0_SBUF0 = RSP_BUSY; 388 2 // break; 389 2 return; 390 2 391 2 case G4HS_RCCM: // 0x02 processing of receive complted 392 2 SBG_P0_D485 = 1; 393 2 SG_SFRPAGE = 0; 394 2 SB0_SCON0_TB8 = 1; 395 2 S0_SBUF0 = RSP_CMPL; 396 2 GC4holdState = G4HS_RCHO; 397 2 // break; 398 2 return; 399 2 400 2 case G4HS_RCER: // 0x03 receive complted, error detected, record ignored 401 2 SBG_P0_D485 = 1; 402 2 SG_SFRPAGE = 0; 403 2 SB0_SCON0_TB8 = 1; 404 2 S0_SBUF0 = RSP_ERR; 405 2 GC4holdState = G4HS_RCHO; 406 2 // break; 407 2 return; 408 2 409 2 case G4HS_RCHO: // 0x04 receive response completed hold off switch to receive 410 2 SBG_P0_D485 = 0; // now back to receive 411 2 GC4holdState = G4HS_IDLE; // no response cycle in progress 412 2 GCI4xferSt = I4_IDLE; // new interrupt sequence 413 2 // break; 414 2 return; 415 2 416 2 // default: 417 2 // catchT3(0xff); 418 2 // break; 419 2 420 2 } 421 1 } ; FUNCTION ISR_T3 (BEGIN) 0000 C0E0 PUSH ACC 0002 C083 PUSH DPH 0004 C082 PUSH DPL 0006 C0D0 PUSH PSW 0008 75D008 MOV PSW,#08H ; SOURCE LINE # 372 ; SOURCE LINE # 374 000B C2CA CLR SB1_TMR3CN_TR ; SOURCE LINE # 375 000D C2CF CLR SB1_TMR3CN_TF ; SOURCE LINE # 376 000F E500 E MOV A,GC4holdState 0011 120000 E LCALL ?C?CCASE
View all questions in Keil forum