ARM Technical Support Knowledge Articles

EFFICIENT CODE FOR BYTE ACCESS CONVERSION TO LONG

Applies to: C51 C Compiler

Answer


Information in this article applies to:


QUESTION

I need to generate efficient code for accessing three SFR registers. Currently I have implemented the following code but the compiler generates very inefficient output. Is there a better way to implement this?

sfr TIMER_PID_TML   = 0x95;   // LSByte
sfr TIMER_PID_TMI   = 0x96;
sfr TIMER_PID_TMM   = 0x97;

unsigned long read_SFR() {
  return(((unsigned long) (TIMER_PID_TMM)<<16) |
         ((unsigned int) (TIMER_PID_TMI)<<8) | TIMER_PID_TML);
}

ANSWER

In the case shown above, the C51 compiler does not generate optimal code. While it is possible for the compiler to optimize the long shift code that results from this statement, this optimization is not currently implemented. It will be included in a future release.

For the moment, there are several solutions that generate more efficient code.


One solution is to use a union as follows:

sfr TIMER_PID_TML   = 0x95;   // LSByte
sfr TIMER_PID_TMI   = 0x96;
sfr TIMER_PID_TMM   = 0x97;

union TIMER_PID  {
  unsigned char  b[4];
  unsigned long  l;
};


unsigned long read_SFR() {
  union TIMER_PID v;

  v.b[3] = TIMER_PID_TML;
  v.b[2] = TIMER_PID_TMI;
  v.b[1] = TIMER_PID_TMM;
  v.b[0] = 0;
  return (v.l);
}

Another solutions is to use a small assembler module that contains only the function for the SFR read. This function can be easily generated by using the SRC directive of the C51 compiler and further modified. The following example shows such an assembler source file that is derived from the SRC file. Note that the REGUSE directive is used to tell the C51 compiler that only the CPU registers R4-R7 are modified in the assembler routine.

sfr TIMER_PID_TML   = 0x95;   // LSByte
sfr TIMER_PID_TMI   = 0x96;
sfr TIMER_PID_TMM   = 0x97;

?PR?read_SFR?read_sfr  SEGMENT CODE
        PUBLIC  read_SFR

        RSEG    ?PR?read_SFR?read_sfr
; C definition:  extern unsigned long read_SFR();
$REGUSE read_SFR(R4,R5,R6,R7)
read_SFR:
        MOV     R7,TIMER_PID_TML
        MOV     R6,TIMER_PID_TMI
        MOV     R5,TIMER_PID_TMM
        MOV     R4,#0
        RET
; END OF read_SFR

        END

Article last edited on: 2002-02-15 00:00:00

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential