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

Which registers can I trash with user-defined bank switching?

Using C51 (v6.xx/7.xx) with user defined bank switching (mode 4), which registers must be preserved on the call and return?

R1-R7 must be preserved on the call & return, since these pass parameters & return values.

The carry flag must be preserved on return, since it may return a bit value.

Examining Keil code & examples, it seems that it's ok to trash ACC and DPTR.

What about R0, B and other flags?

I couldn't find anything explicit in the documentation, so have currently taken a conservative position with my (rather complicated) bank switching routine.

  • The comments in XBANKING.A51 now tell you which registers can be trashed. For example:

    ;-----------------------------------------------------------------------------
    ; CLDXPTR: Load   BYTE in A             via Address given in R1/R2/R3
    ; Registers which can be used without saving:  DPTR, CY, A
    ;
    

    Actually, I think I had the same question a while back and nagged them into putting this information in the comments. So it should be available in the 7.x example. If not, I suspect the convention hasn't changed. The v8 comments might still apply to the older code generator. But only Keil can say for sure.

  • Thanks for pointing me in the right direction. It is documented in later versions of L51_BANK.A51 -

    ; ?B_BANKn    is a routine which saves the entry of the ?B_SWITCHn function   *
    ;             for the current active bank on the STACK and switches to the    *
    ;             bank 'n'.  Then it jumps to the address specified by the DPTR   *
    ;             register.  It is allowed to modify the following registers in   *
    ;             the ?B_BANKn routine:  A, B, R0, DPTR, PSW                      *
    ;                                                                             *
    ; ?B_SWITCHn  is a function which selects the bank 'n'.  This function is     *
    ;             used at the end of a user function to return to the calling     *
    ;             code bank.  Only the following registers may be altered in the  *
    ;             ?B_SWITCHn function:  R0, DPTR                                  *
    

    Looking through the source, if VAR_BANKING is not used, it's not necessary to preserve A, B or R0 in the ?B_SWITCHn (return) code either. This makes sense, because it's ok to use these registers in the ?B_BANKn (entry) code and C51 never returns values in these registers. The only other thing that may have required register preservation is global register colouring, but this would have required that registers retain their entry values. Keil must disable, or limit global register optimisation for interbank calls.

    VAR_BANKING does use A, B and R0, to pass and return values.

  • Keil must disable, or limit global register optimisation for interbank calls.

    A good point. One less charitable option is that it doesn't work in this case... That occurs to me simply because a while back we had some weird problems that we traced down to the global register optimization. Our solution was to disable it. However, maybe our bank switch stubs are trashing something they're not supposed to. Time to review that code.