This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

a proposal ?

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

Parents
  • 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
    Thus I repeat my call for a #pragna QUICKSWITCH

    Erik

Reply
  • 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
    Thus I repeat my call for a #pragna QUICKSWITCH

    Erik

Children
  • 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.

    Thomas

  • 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
    


  • I took out the default: and ?C?CCASE is still called.


    even on OT(8)? here that works

    Thomas

  • NO, NO WAY

    I have NO INTENTION of screwing up my debugging capabilities by optimizing beyond object = source.

    Erik

  • I have to agree with Erik on this one.

    Jump tables and their assocaited jmp @a+dptr are a fundamental instruction in the 51 for achieving efficiency, particularly within interrupts where the desire is to keep processing time to a minimum.

    However, I don't see why a pragma would even be necessary. Let's assume the pragma is implemented, but the code violates the required case values (i.e. byte size, increments of 2 or 3). In this case, the compiler's going to have to validate the case values to ensure compliance with the pragma anyway, so why not simply have the compiler check for "jump table possible" case values and render a direct jump table if found ???

  • I have to agree with Erik on this one.
    thanks

    However, I don't see why a pragma would even be necessary

    The advantage of a #pragma as I see it would be that you effectively told the compiler "tell me if you can not do this". If an 'automatic' were implemented, you would never know (except through investigating the assembler) if you had achieved the goal. Of course, a possibility would be a #pragma TELL_IF_SWITCH_CAN_NOT_BE_JUMP_TABLE which would satisfy both approaches.

    Anyhow, I STILL can not see why this has anything to do with optimization. as I see it, the compiler should do the best it can without disrupting the flow, and leave 'worthless' statements (inserted to provide a breakpoint opportunity) in the code. Then, if desired, optimization (which may/should disrupt the flow and skip dead code) can be implemented. Using jump tables has NOTHING to do with optimization (except to make the result of optimizing look better)

    Erik

  • The advantage of a #pragma as I see it would be that you effectively told the compiler "tell me if you can not do this". If an 'automatic' were implemented, you would never know (except through investigating the assembler) if you had achieved the goal.

    Good point. And I agree, the compiler should take every opportunity, regardless of OT level, to leverage direct jump tables if possible...IMO ;)