Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: Compiller neutral code

2006-04-18 by brendanmurphy37

Jermone,

See some suggestions below.

Brendan


--- In lpc2000@yahoogroups.com, jk jlkj <njad2002@...> wrote:
>
> Hi Firends,
>    
>   The other day i was reading a message in this group, about 
writing code which does not use any of the compiler specific 
extended keywords like __arm, __nested, __irq etc. 

The main point about any of these extensions is that they are 
compiler and/or system specific. This means if you ever have to 
change environments (i.e. either compiler or target) you almost 
certainly have to change them. This (a) generates extra work and (b) 
introduces scope for new bugs to be introduced and (c) adds to 
ongoing maintenance task, as two (or more) versions must be 
maintained. None of this is an issue if all you're doing is 
something quick and dirty. 

A second issue with compiler extensions is that they tend to be the 
area where most compiler's have problems/bugs.

>   Does any one have any sample code or any documentation or 
articles on how this can be done. 

I'm not aware of any: it's an issue that tends to be driven more by 
practical experience. I'd be very interested in seeing some though.

>   Because, i think that this is an important step towards writing 
code that is not compiler specific and would compile with very 
little or no changes between compilers.

It is perfectly possible to achieve on processors such as ARM etc. 
(next to impossible though on very low-end 8-bit micros such as PICs 
etc., where there are more extensions and restrictions than 
compatibility to standard 'C').

The techniques we use include:

- As a starting point for 'C' code: stick to standard 'C'. Don't use 
any extensions such as special keywords, pragmas, in-line assembler 
etc., if you can avoid them (which you almost certainly can)

- When accessing hardware, you can do it from 'C', but make sure you 
don't use non-portable features such as bit-fields. For a read or 
write to a 32-bit register you can type cast the hardware address to 
a "volatile int *" (or better yet define a type in a master include 
file with something like "uint32" as an unsigned 32-bit integer)

- We don't use any standard libraries (printf and the like), 
preferring to write our own. This is more to simplify maintenance 
than anything else - we use very few such functions. It avoids 
having to find and/or port libraries for multiple platforms.

- You will find that some things just can't be done from 'C'. Our 
preference is to code these in assembler in separate source files, 
as it eases maintenance.

>    
>   I think that such code would definitely require a little bit of 
assembly language.
>    
>   What i would like to know and do is 
>   a. List down all the compiler specfic instructions which are 
very commonly used.
>   b. Write code which would replace these compiler specific 
intructions.
>    
>   Well the (a) part of my job seems to be easier, so i am listing 
down the commonly used IAR ewarm compiler specific instructions 
here .
>    
>   __irq, __fiq, __arm, __thumb, __nested, __swi
>    
>   For the (b) part of my question i would need some serious help 
from some of the experts in this group. By help i do not expect any 
one to give me the entire code. All i need is some guidance and 
hints, i will try and compile the code. However, if some one has 
already done this exercise, then please share it with us.

For the LPC, the only assembler we have is as follows. All other 
code is standard 'C', including all low-level device drivers. As a 
matter of good practice, we code the hardware-specific parts of the 
device drivers to be as small as possible, and separate from the 
main body of the code, using well defined APIs. 

- Vector table and startup code. The startup code in our case 
initializes the stack pointers, sets the mode to supervisor with 
interrupts off and jumps to 'C'.  I believe I posted a version of 
this a while ago here. You can zero out the uninitialized data and 
copy in the initialized data as part of this: equally, you can do 
this from `C' (though do it near the start, obviously).

- IRQ interrupt dispatch, that enables nested interrupts. There were 
a couple of examples of this posted here recently. This can be 
written so that the main body of the interrupt handler can be a 
standard `C' function (no need for special keywords).

- A few miscellaneous functions: a pair of functions to disable and 
re-enable interrupts, and maybe one other to enable them in the 
first place (called at the end of the initialization code).

We don't use software interrupts.

Whether a source file is compiled as ARM or Thumb mode can be 
controlled from the build environment (either part of an IDE or 
makefile): the actual code can be agnostic as to how it's compiled.

Using this approach, we have applications that take up maybe 
100kbytes of code space, all of it standard `C' except for a handful 
of assembler functions. The main body of code gets compiled with 
five different compilers on about six or seven distinct platforms, 
without any changes. Moving to a new compiler takes a couple of days 
at worst (to generate build system for it), a couple of hours at 
best. Moving to a new platform takes a couple of weeks to code up 
the platform specific stuff.

A few other points I'd make:

Although we have a particular requirement for portability, we have 
found that even if we didn't, these techniques have advantages, in 
terms of training (by using standard features only, there's less to 
learn), code quality (no reliance on frequently poorly documented 
features, avoidance of bug-prone compiler features), maintenance 
(easier to understand something that's standardized), flexibility 
(not tied into a particular compiler vendor) etc.

Even if you don't think portability is an issue for you today, 
changing requirements will often make it an issue for you. I tried 
to make this point recently in an exchange on in-line assembler, and 
failed.

Having said all of the above, there will be occasions where it's 
just handy to use a compiler extension (for example, where some 
feature just isn't available otherwise: someone gave an example of 
accessing special DSP instructions on a DSP recently). 

Finally, all this is based on our own experience: clearly there are 
alternative approaches. I'm not really interested in debating the 
merits of this or any alternative approach to death: simply to 
present a number of well-known techniques that I have found very 
useful and effective, and hope that others can learn from our 
experience.

I hope you find the above of some use.

Brendan

P.S. apologies for not providing direct references to code examples, 
but the search facility on this site is woeful, and I'm out of time.

>    
>   Regards,
>   Jerome

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.