Home | | Embedded Systems Design | C extensions for embedded systems

Chapter: Embedded Systems Design : Writing software for embedded systems

C extensions for embedded systems

Whenever writing in a high level language, there are always times when there is a need to go down to assembler level coding, either for speed reasons or because it is simpler to do so.

C extensions for embedded systems

 

Whenever writing in a high level language, there are always times when there is a need to go down to assembler level coding, either for speed reasons or because it is simpler to do so. Accessing memory ports is another example of where this is needed. C in itself does not necessarily support this. Assembler routines can be written as library routines and included at link time — a technique that has been explained and used in this and later chapters. It is possible to define access a specific memory mapped peripheral by defining a pointer and then assigning the peripheral’s memory address to the pointer. Vector tables can be created by an array of pointers to functions. While these techniques work in many cases, they are susceptible to failing.

 

Many compilers provide extensions to the compilers that allow embedded system software designers facilities to help them use low level code. These extensions are compiler specific and may need changing or not be supported if a different compiler is substituted. Many of these extensions are supplied as additional #pragma definitions that supply addi-tional information to the compiler on how to handle the rou-tines. These routines may be in C or in assembler and the number and variety will vary considerably. It is worth check-ing out the compiler documentation to see what it does sup-port.

 

#pragma interrupt func2

 

This declares the function func2 as an interrupt func-tion and therefore will ensure that the compiler will save all registers so that the function code does not need to do this. It also instructs the compiler that the return mechanism is differ-ent — with a PowerPC instruction a special assembler level instruction has to be used to synchronise and restart the processor. #pragma pure_function func2

 

This declares that the function func2 does not use or modify any global or static data and that it is a pure function. This can be used to identify assembler-based routines that configure the processor without accessing any data. This could be to change the cache control, disable or enable interrupts.

 

#pragma no_side_effects func2

 

This declares that the function func2 does not modify any global or static data and that it has no side effects. This could be used in preference to the pure_function option to allow access to data to allow an interrupt mask to be changed depending on a global value, for example.

 

#pragma no_return func2

 

This declares that the function func2 does not return and therefore the normal preparation of retaining the subrou-tine return address can be dispensed with. This is used when an exit or abort function is used. Jumps can also be better implemented using this as the stack will be correctly main-tained and not filled with return addresses that will never be used. This can cause stack overflows.

 

#pragma mem_port int2

 

This declares that the variable int2 is a value of a specific memory address and therefore should be treated ac-cordingly. This is normally used with a definition that defines where the address is.

 

asm and _ _asm

 

The asm and _ _asm directives — note that the number of underlines varies from compiler to compiler — provide a way to generate assembly code from a C program. Both usually have similar functionality that allows assembler code to be directly inserted in the middle of C without having to use the external routine and linking technique. In most cases, the terms are interchangeable, but beware since this is not always the case. Care must also be taken with them as they break the main standards and enforcing strict compatibility with the compiler can cause them to either be flagged up as an error or simply ignored.

 

There are two ways of using the asm/_ _asm directives. The first is a simple way to pass a string to the assembler, an asm string. The second is an advanced method to define an asm macro that in-lines different assembly code sections, depend-ing on the type of arguments given. The examples shown are based on the Diab PowerPC compiler.

 

asm strings

 

An asm string can be specified wherever a statement or an external declaration is allowed. It must have exactly one argument, which should be a string constant to be passed to the assembly output. Some optimisations will be turned off when an asm string statement is encountered.

 

int f() { /* returns value at $$address */ asm(“ addis r3,rO,$$address)@ha”); asm(“ lwz r3,r3,$$address@1”);

 

This technique is very useful for executing small func-tions such as enabling and disabling interrupts, flushing caches and other processor level activities. With the code directly in-lined into the assembler, it is very quick with little or no overhead.

 

asm macros

 

An asm macro definition looks like a function definition in that the body of the function is replaced with one or more assembly code sequences. The compiler chooses one of these sequences depending on which types of arguments are pro-vided when using the asm macro, e.g.

 

asm int busy_wait(char *addr)

 

{ % reg addr; lab loop; addi r4,rO,l

loop:                                                           # label is replaced by

compiler

lwarx r5,rO,addr                                       # argument is forced to

register

 

cmpi crO,r5,0 bne loop

 

stwcx. r4,rO,addr bae loop

}

 

extern char *sem fn(char *addr) {

 

busy_wait(addr); /* wait for semaphore */ busy_wait(sem) ; /* wait for semaphore */

}

 

The first part of the source defines the assembler routine that waits for the semaphore or event to change. The second part of the source calls this assembler function twice with the event name as its parameter.

 

addi                                      r4,rO,1

.L11:                                            # label is replaced by compiler

lwarx                                            r5,rO,r31 # argument is forced to

register

cmpi                                              crO,r5,0

bne                                               .L11

stwcx.                                          r4,rO,r31

bne                                               .L11

addis                                            r3,rO,sem@ha

lwz                                               r3,sem@1(r3)

addi                                              r4,rO,1

.L12:                        # label is replaced by compiler

lwarx                        5,rO,r3 # argument is forced to

register                       

cmpl                         crO,r5,0    

bne                          .L12   

stwcx.                       r4,rO,r3    

bne                          .L12   

 

 

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail
Embedded Systems Design : Writing software for embedded systems : C extensions for embedded systems |


Privacy Policy, Terms and Conditions, DMCA Policy and Compliant

Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.