Newsletter

Using Dynamic Register Allocation to Boost PIC32 Performance

Efficiently exploiting the PIC32's 32 registers can reduce the number of load/store cycles, freeing them up for computation and potentially improving processor throughput.

Page 1 of 3

Industrial Control Designline

Developing code for Microchip's PIC32 poses a new set of opportunities for engineers who are accustomed to the company's 8- and 16-bit microcontrollers. PIC32 devices have as much as 512 kbytes of flash, up to 32-kbytes of SRAM memory, 32 general-purpose registers, and a completely linear address space. In contrast, traditional PIC MCUS have as few as one or two registers and banked memories that require manual assembly language programming or the addition of non-standard C-extensions for efficient memory addressing.

The large number of registers on the PIC32 provides a substantial opportunity for boosting CPU performance because function parameters and other data, usually stored in SRAM, can be stored in the registers which take fewer cycles to access. Efficiently exploiting the PIC32's 32 registers can reduce the number of load/store cycles, freeing them up for computation and potentially improving processor throughput.

How much the compiler "knows" about the register usage of a called function plays a big role in how efficiently the compiler exploits the PIC32's registers. Conventional compilation technology does not gather enough intelligence about the whole program to truly optimize register coverage because of the modular nature of embedded software and compilation. Conventional GCC-based compilers generate code independently for each program module, with no information about what is in other modules. At the end of this process the various modules are combined by a linker, along with any pre-compiled library code (Figure 1 - Conventional Compilation). The drawback of this approach is the "global" optimization claimed by many vendors is done only within each individual module. There is no optimization across the entire program, leading to sub-optimal stack, register,and memory allocation.

Figure 1 - Conventional Compilation

The main means of dealing with the compiler's lack of information about the whole program has been to create restrictive, fixed calling conventions to protect different modules from overwriting each other's data. This is necessary because over-writing a single register could have catastrophic consequences. The spectacular crash of the European Space Agency's Arianne rocket was caused by a data overflow into the wrong register that caused the rocket to reverse course and plunge to earth. Protecting the data in registers is extremely important.

Conventional compilers use calling conventions to restrict the use of some registers specifically to avoid this type of error. Conventional compilers also attempt to prevent overwriting registers by saving and restoring very large contexts during interrupts. Since a conventional compiler has no way of knowing when a register is available or what data from another module might be written to them, the only way to ensure registers are not over-written is to reserve specific registers only for some kinds of data (e.g., function parameters) and to always save all registers that might be used to the stack when calling a function or saving a context during an interrupt.

These calling strategies attempt to balance which registers are allocated for function parameters and which registers can be used by the called function for internal calculations, based on "average" code. If too many registers are used for parameters, there may not be enough available for the function's code. If too few are used for function parameters, the stack may be overutilized, wasting both cycles and SRAM resources.

Conventional compilers must rely on rigid, static calling conventions which dictate how arguments are passed and values returned. Each calling convention contains a set of rules that defines which CPU registers are to be preserved across calls. All functions in the program must adhere to the same calling convention.

The calling convention in GCC-based PIC32 compilers specifies a fixed set of four PIC32 registers for passing parameters to functions. If a function requires fewer than four parameters, the compiler still considers all four registers to be used by parameters. They cannot be used for anything else. If the function requires more than four parameters, the extra parameters are passed on the stack in SRAM, even if other non-reserved registers are available.

For example, if a function, f1, calls another function, f2, a conventional compiler will put f1's parameters on the stack to make room for f2's parameters which will be loaded to the four registers specified by the calling convention. Other registers may be available, but they will not be used unless they have been specified in the calling convention for this purpose. When the second function is complete, the parameters from the first function also may be retrieved from RAM and loaded back into the registers. This cycle- and code-wasting data shifting will occur because the calling convention says it must be so.



Page 2: Omniscient" Code Generation Fosters More Efficient, Dynamic Register Use  

Page 1 | 2 | 3







Related Content

COURSE
1. Fundamentals of Embedded Systems Security

TECH PAPER
2. Stimulus Spending Brings Medical Applications to Life

WEBINAR
3. Mutexes vs. Semaphores: How to Use Each Properly

TECH PAPER
4. Accelerate your MCU-based design process

 


 Featured Jobs
Ascension Health seeking Solutions Development Analyst in St. Louis, MO

National Semiconductor seeking Principal IC Design Engineer in Santa Clara, CA

Taylor Guitars seeking Sr. Web Designer in El Cajon, CA

Covidien seeking Hardware Manager in Boulder, CO

Sierra Nevada seeking Software Engineer in Hagerstown, MD

More jobs on EETimesCareers
 Sponsor
 CAREER CENTER
Ready to take that job and shove it?
SEARCH JOBS:

 SPONSOR

 RECENT JOB POSTINGS
For more great jobs, career related news, features and services, please visit EETimes' Career Center.