Working with FAR pointers in a code library for multiple embedded platforms

I am trying to maintain a sample code library for several embedded platforms. I need to support the concept of “far” (not 16-bit) pointers for some function parameters.

I thought I had a good solution defining the FAR macro as __far on some platforms and nothing on platforms with 32-bit pointers (embedded Linux, Win32, etc.). With this macro, I could easily define pointers as somestruct_t FAR *foo .

But then I started working with Freescale processors, and their compiler requires FAR to go between the asterisk and the variable name. ( somestruct_t * __far foo ).

The best solution I developed for this case is to define the FARPTR macro as __far * , * __far or just * depending on the platform. This allows somestruct_t FARPTR foo .

Are there cleaner solutions? In particular, I do not like that someone reads this code without seeing * . I am also worried that I will have problems with feature declarations. Get a load of this syntax from the Freescale compiler help:

 int __far *f(); // __far function returning a pointer to int int * __far f(); // Function returning a __far pointer to int int __near * __far f(); // __near function returning a __far pointer to int 

This last one is killing me - the qualifier inside the return type indicates a close function ?! And I recently found out that adding __near not enough to actually compile the function into the nearest memory - I need to wrap it in pragmas.

So, has anyone seen a nicer solution than my idea of ​​a FARPTR macro?

+7
source share
5 answers

Using a freescale processor is more compatible with standard type classifiers such as const , which means that it refers to a pointer and not to the data it points to. However, since “far away data” rather than a “far pointer” would be meaningless, you would think that it does not matter, but more consistency seems to make the compiler's simpler parser.

You can use kludgey something like:

 #if defined __SOME_ARCHITECTURE__ #define DECLARE_FARPTR( type, identifier ) type __far * identifier #if defined __SOME_OTHER_ARRCHITECTURE__ #define DECLARE_FARPTR( type, identifier ) type * __far identifier #else #define DECLARE_FARPTR( type, identifier ) #endif 

Then your ads will look like this:

 DECLARE_FARPTR( somestruct_t, foo ) ; 

or in a function prototype that takes a pointer parameter:

 void fn( DECLARE_FARPTR( somestruct_t, foo ) ) ; 

or a function that returns a far pointer:

 DECLARE_FARPTR( somestruct_t, fn( void ) ) ; 

As you can see, it quickly becomes difficult to read, and a declarative macro like a function is usually best avoided.

+2
source

I do not have a specific best solution for you. However, considering the same problem several times, I recommend a review of the AUTOSAR Compiler Abstraction Specification (PDF) .

It includes a detailed approach to working with multiple compilers.

+2
source

To add to Clifford's message , although functional macros are probably bad ideas, you can use a macro to create typedefs:

 #ifdef SOME_ARCH #define DEF_FAR_PTR(type, farptr_typename) typedef type __far *farptr_typename; #elsif SOME_OTHER_ARCH #define DEF_FAR_PTR(type, farptr_typename) typedef type * __far farptr_typename; #else #define DEF_FAR_PTR(type, farptr_typename) typedef type * farptr_typename; #endif 
+1
source

I also work with Freescale, and my own solution for this is one of the following:

1) If possible, replace far pointers with prime integers. This does not work in any situation, but is especially useful when working with function pointers, for example, when writing interrupt vector tables.

2) Instead of using long pointers, write code that will be identical to what the compiler will produce during the remote pointer. Here is an example for MCU Freescale:

 unsigned char readFromPage (unsigned char page, const unsigned char* address) { unsigned char value; unsigned char tmp = PPAGE; SAFE_DisableInterrupts; PPAGE = page; value = *address; PPAGE = tmp; SAFE_EnableInterrupts; return value; } 

(this code may be embedded depending on the case)

3) Use #pragmas as far as possible.

As a result, I don’t have a single far and near pointer in my code, it is portable (like portable, like hardware-related code), and I can check it with static analyzers that understand only the C standard.

+1
source

It can simply be cleared to define two FAR macros: one for before * and one for after *.

0
source

All Articles