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.
Show quoted textHide quoted text