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

assembler rtn called from C

I have the impression that an assembler non-interrupt subroutine called from 'C' need save no registers.

Is that correct?

Erik

  • It depends on your skill. If you don't alter registers in your subroutine, why to save them? I'll say even more, I never save registers even for interrupts, neither for C functions, but it is only possible if you have reached a certain level of qualification.
    Have fun.
    M.

  • If you do not use the registers you do not need to save them, that is evident even to the rankest amateur. I would have no reason to ask this question if I did not use the registers in routines. I have, however, noted that C functions do not seem to save the regs and thus ask the question.

    REPHRASE:
    The 'c' functions do not - as far as I have seen - save registers. Are there any cases - outside interrupts - where not saving (these specific) the registers will topple the code generated by the 'C' compiler.


    Erik

  • Excuse me, your rephrase seems even less clear than the original question. You say: "Are there any cases ... where not saving will topple the code." Should that be understood as "Can an example be constucted..."? If so, the answer is evidently YES. Everything is possible in an assembler routine. If you speak of some practical cases - all depends on your style and skill.
    M.

  • Correct. As stated in the manual, "Assembler functions can change all register contents in the current selected register bank as well as the contents of the registers ACC, B, DPTR, and PSW."

  • This is why having lots of "leaf" functions can greatly affect the optimiser - it has to assume that it needs to save & restore registers around a function call.
    However, the "Global Register Optimisation" can really help here.

  • When C makes a call to a function written in assembler, the C optimiser generally has to assume the worst case - that any of the registers may be overwritten by the assembly language function.

    However, using the REGUSE control in the assembly language function will inform the optimiser about exactly which registers are changed by the function - this allows global register optimisation to be applied.

    In the REGUSE control, you only have to specify those registers that are actually modified by the function. In order to optimise performance, you may choose to save and restore some (or all) of the registers that you use.

    If you are keen to optimise performance, you will need to do some investigation. In general, it is the registers R0 to R7 that are critical. The optimiser may alocate these registers to automatic variables in the calling C function - that are the most important. This optimisation can be very significant to performance so it may be important to ensure that the optimiser can apply it effectivly.

  • Thanks Dan, Andy & Graham.

    Michael, I was not asking about assembler code, but about the 'C' compiler.

    y'all have fun now, ya hear

    Erik

  • Yes. That's Correct.

    Saving registers in an assembler function (the way that I think you are thinking) is unnecessary and gains nothing.

    Note that you may want to use REGUSE in the assembler module to help the Global Register Coloring optimization (if you use it). But, this is not required.

    Jon

  • The point is the REGUSE control in the assembly code makes a big difference in the C code that calls the assembly code!!

    In the following example the calling C code was reduced by almost 1/2 in size by using REGUSE on the assembly side.

    Main.c
    
    void WithoutRegUse( char C );
    void WithRegUse( char C );
    
    void CallWithoutRegUse( void )
    {
      char i;
      char xdata* p = 0;
      for( i = 0; i != 0x12; ++i, ++p )
        WithoutRegUse(*p);
    }
    
    void CallWithRegUse( void )
    {
      char i;
      char xdata* p = 0;
      for( i = 0; i != 0x12; ++i, ++p )
        WithRegUse(*p);
    }
    
    void main( void )
    {
      CallWithoutRegUse();
      CallWithRegUse();
    }
    Sub.c
    
    #include <reg52.h>
    
    volatile V;
    
    void WithoutRegUse( char C )
    {
      ACC = C;
      #pragma asm
        swap a
        mov  V,a
      #pragma endasm
      return;
    }
    
    #pragma asm
      $reguse _WithRegUse( A, R7 ) 
    #pragma endasm
    void WithRegUse( char C )
    {
      ACC = C;
      #pragma asm
        swap a
        mov  V,a
      #pragma endasm
      return;
    }
    

    Partial Main.lst
    
                 ; FUNCTION CallWithoutRegUse (BEGIN)
                                               ; SOURCE LINE # 7
                                               ; SOURCE LINE # 8
                                               ; SOURCE LINE # 10
    0000 E4                CLR     A
    0001 F500        R     MOV     p,A
    0003 F500        R     MOV     p+01H,A
                                               ; SOURCE LINE # 11
    0005 F500        R     MOV     i,A
    0007         ?C0001:
    0007 E500        R     MOV     A,i
    0009 6412              XRL     A,#012H
    000B 6017              JZ      ?C0004
                                               ; SOURCE LINE # 12
    000D 850082      R     MOV     DPL,p+01H
    0010 850083      R     MOV     DPH,p
    0013 E0                MOVX    A,@DPTR
    0014 FF                MOV     R7,A
    0015 120000      E     LCALL   _WithoutRegUse
    0018 0500        R     INC     i
    001A 0500        R     INC     p+01H
    001C E500        R     MOV     A,p+01H
    001E 70E7              JNZ     ?C0001
    0020 0500        R     INC     p
    0022         ?C0010:
    0022 80E3              SJMP    ?C0001
                                               ; SOURCE LINE # 13
    0024         ?C0004:
    0024 22                RET     
                 ; FUNCTION CallWithoutRegUse (END)
    
                 ; FUNCTION CallWithRegUse (BEGIN)
                                               ; SOURCE LINE # 15
                                               ; SOURCE LINE # 16
                                               ; SOURCE LINE # 18
    ;---- Variable 'p' assigned to Register 'DPTR' ----
    0000 900000            MOV     DPTR,#00H
                                               ; SOURCE LINE # 19
    ;---- Variable 'i' assigned to Register 'R6' ----
    0003 E4                CLR     A
    0004 FE                MOV     R6,A
    0005         ?C0005:
    0005 EE                MOV     A,R6
    0006 6412              XRL     A,#012H
    0008 6009              JZ      ?C0008
                                               ; SOURCE LINE # 20
    000A E0                MOVX    A,@DPTR
    000B FF                MOV     R7,A
    000C 120000      E     LCALL   _WithRegUse
    000F 0E                INC     R6
    0010 A3                INC     DPTR
    0011 80F2              SJMP    ?C0005
                                               ; SOURCE LINE # 21
    0013         ?C0008:
    0013 22                RET     
                 ; FUNCTION CallWithRegUse (END)
    

  • Too right. Thanks for the nice examples.