Next Previous Contents

## 25. TIPS

Here are a few guide-lines that will help the compiler generate more efficient code, some of the tips are specific to this compiler others are generally good programming practice.

- Use the smallest data type to represent your data-value. If it is known in advance that the value is going to be less than 256 then use a 'short' or 'char' instead of an 'int'.
- Use unsigned when it is known in advance that the value is not going to be negative. This helps especially if you are doing division or multiplication.
- NEVER jump into a LOOP.
- Declare the variables to be local whenever possible, especially loop control variables (induction).
- Since the compiler does not do implicit integral promotion, the programmer should do an explicit cast when integral promotion is required.
- Reducing the size of division , multiplication & modulus operations can reduce code size substantially. Take the following code for example.

      foobar( unsigned int p1, unsigned char ch)
      {
          unsigned char ch1
       = p1 % ch ;
          ....
      }

  For the modulus operation the variable ch will be promoted to unsigned int first then the modulus operation will be performed (this will lead to a call to a support routine). If the code is changed to

      foobar( unsigned int p1, unsigned char ch)
      {
          unsigned char ch1
       = (unsigned char)p1 % ch ;
          ....
      }

  It would substantially reduce the code generated (future versions of the compiler will be smart enough to detect such optimization oppurtunities).

Notes from an USER ( Trefor@magera.freeserve.co.uk )

The 8051 family of micro controller have a minimum of 128 bytes of internal memory which is structured as follows

- Bytes 00-1F - 32 bytes to hold up to 4 banks of the registers R7 to R7

- Bytes 20-2F - 16 bytes to hold 128 bit variables and

- Bytes 30-7F - 60 bytes for general purpose use.

Normally the SDCC compiler will only utilise the first bank of registers, but it is possible to specify that other banks of registers should be used in interrupt routines. By default, the compiler will place the stack after the last bank of used registers, i.e. if the first 2 banks of registers are used, it will position the base of the internal stack at address 16 (0X10). This implies that as the stack grows, it will use up the remaining register banks, and the 16 bytes used by the 128 bit variables, and 60 bytes for general purpose use.

By default, the compiler uses the 60 general purpose bytes to hold "near data". The compiler/optimiser may also declare some Local Variables in this area to hold local data.

If any of the 128 bit variables are used, or near data is being used then care needs to be taken to ensure that the stack does not grow so much that it starts to over write either your bit variables or "near data". There is no runtime checking to prevent this from happening.

The amount of stack being used is affected by the use of the "internal stack" to save registers before a subroutine call is made, - --stack-auto will declare parameters and local variables on the stack - the number of nested subroutines.

If you detect that the stack is over writing you data, then the following can be done. --xstack will cause an external stack to be used for saving registers and (if --stack-auto is being used) storing parameters and local variables. However this will produce more and code which will be slower to execute.

--stack-loc will allow you specify the start of the stack, i.e. you could start it after any data in the general purpose area. However this may waste the memory not used by the register banks and if the size of the "near data" increases, it may creep into the bottom of the stack.

--stack-after-data, similar to the --stack-loc, but it automatically places the stack after the end of the "near data". Again this could waste any spare register space.

--data-loc allows you to specify the start address of the near data. This could be used to move the "near data" further away from the stack giving it more room to grow. This will only work if no bit variables are being used and the stack can grow to use the bit variable space.

Conclusion.

If you find that the stack is over writing your bit variables or "near data" then the approach which best utilised the internal memory is to position the "near data" after the last bank of used registers or, if you use bit variables, after the last bit variable by using the --data-loc, e.g. if two register banks are being used and no data variables, --data-loc 16, and - use the --stack-after-data option.

If bit variables are being used, another method would be to try and squeeze the data area in the unused register banks if it will fit, and start the stack after the last bit variable.

Next Previous Contents