EmbeddedRelated.com
Forums
Memfault Beyond the Launch

C programming on ARM

Started by aamer January 30, 2008
"David Brown" <david.brown@hesbynett.removethisbit.no> wrote in message 
news:47a23426$0$14988$8404b019@news.wineasy.se...
> Wilco Dijkstra wrote: >> "David Brown" <david@westcontrol.removethisbit.com> wrote in message >> news:47a1a46d$0$14996$8404b019@news.wineasy.se...
>>> there are many architectures with different pointer types and different memory spaces. These don't fit well with C >>> (which expects a single memory space), but they are the reality we live with. On an AVR Mega256, a general flash >>> pointer will 24 bits, while a ram pointer will be 16 bits. On some architectures you get "far" and "near" pointers. >>> There are some that have a section of bit-addressable memory, with a different pointer type. You can't rely on >>> these things having a consistent pointer size - you should not even rely on the C requirement of a "void *" >>> supporting them all (embedded compilers don't always follow the standards if they conflict with generating good >>> object code for real-world source code). >> >> But as you say C doesn't map onto these architectures, so we're not >> talking about standard C. Most programs won't compile for these >> architectures (assuming the code would fit), and if they did still wouldn't >> run correctly - precisely because these architectures do not support the >> defacto assumptions that most C programs make. >> > > C doesn't map directly onto these architectures - but that does not stop people using C for them on a regular basis! > Look at the AVR, for example - it has different address spaces for flash and ram data, so the pointers are > incompatible. On the larger AVRs, a full flash pointer must be 24 bits, while ram pointers are only 16 bits. Yet > somehow there are vast numbers of these devices in use, almost all of them programmed in C. You certainly can't take > a random C program off the internet and expect it to compile and work on an AVR, but there is no problem writing > portable code that works on the 8-bit AVR, 16-bit msp430, 32-bit big-endian ColdFire, 32-bit little-endian ARM, and > even some of these horrible DSP architectures with their 16-bit chars. You just have to stick to assumptions that are > appropriate for embedded programming, rather than thinking "big" C.
There are indeed architectures which can't fully support standard C. You can indeed write standard conforming programs on these if you avoid any of the default assumptions (casting pointers being one of them) and use macros to map the differences (assuming you know all of them). However this illustrates the difference between "it just works" and putting a lot of effort into making it work. Most software isn't specifically written to be portable, and yet porting is surprisingly easy. You can download random source code from the internet and expect it to compile and work on ARM, MIPS, PPC, ColdFire, AVR32 or any other modern embedded architecture with minimal effort.
>> The reverse is true as well, programs written for these C dialects do not >> work on standard C compilers. One case that comes up often is: >> unsigned char c = 255; if (~c == 0) ... This is always false in standard C, >> but there are compilers which think it is true... >> > > If code like that comes up "often", you have bigger problems than just bad assumptions - that code snippet is > horrible. But it is certainly true that code written for small embedded C systems often has compiler/target specific > features that don't work on larger systems - code for a compiler with an extra "flash" keyword for flash-based data > will clearly not compile on anything else without some changes.
It was an example of what goes wrong when people try to port applications when moving to a different architecture, and find that their code doesn't work any more. Some 8-bit compilers apparently don't apply the standard integer promotion rules, which makes porting of all but the most trivial programs rather tricky. Wilco
Wilco Dijkstra wrote:
> "David Brown" <david.brown@hesbynett.removethisbit.no> wrote in message > news:47a23426$0$14988$8404b019@news.wineasy.se... >> Wilco Dijkstra wrote: >>> "David Brown" <david@westcontrol.removethisbit.com> wrote in message >>> news:47a1a46d$0$14996$8404b019@news.wineasy.se... > >>>> there are many architectures with different pointer types and different memory spaces. These don't fit well with C >>>> (which expects a single memory space), but they are the reality we live with. On an AVR Mega256, a general flash >>>> pointer will 24 bits, while a ram pointer will be 16 bits. On some architectures you get "far" and "near" pointers. >>>> There are some that have a section of bit-addressable memory, with a different pointer type. You can't rely on >>>> these things having a consistent pointer size - you should not even rely on the C requirement of a "void *" >>>> supporting them all (embedded compilers don't always follow the standards if they conflict with generating good >>>> object code for real-world source code). >>> But as you say C doesn't map onto these architectures, so we're not >>> talking about standard C. Most programs won't compile for these >>> architectures (assuming the code would fit), and if they did still wouldn't >>> run correctly - precisely because these architectures do not support the >>> defacto assumptions that most C programs make. >>> >> C doesn't map directly onto these architectures - but that does not stop people using C for them on a regular basis! >> Look at the AVR, for example - it has different address spaces for flash and ram data, so the pointers are >> incompatible. On the larger AVRs, a full flash pointer must be 24 bits, while ram pointers are only 16 bits. Yet >> somehow there are vast numbers of these devices in use, almost all of them programmed in C. You certainly can't take >> a random C program off the internet and expect it to compile and work on an AVR, but there is no problem writing >> portable code that works on the 8-bit AVR, 16-bit msp430, 32-bit big-endian ColdFire, 32-bit little-endian ARM, and >> even some of these horrible DSP architectures with their 16-bit chars. You just have to stick to assumptions that are >> appropriate for embedded programming, rather than thinking "big" C. > > There are indeed architectures which can't fully support standard C. You > can indeed write standard conforming programs on these if you avoid > any of the default assumptions (casting pointers being one of them) and > use macros to map the differences (assuming you know all of them). >
It depends on how much the target differs from being a good C target, and what kind of code you are writing. For example, the AVR cannot access flash data using the same kind of pointer as ram data. If you are writing code that uses a constant table, you have three possible choices - you can waste large amounts of precious ram keeping a copy of the table, so that normal ram data pointers can be used, you can write compiler/target specific code, or you can write code that includes special wrapper functions/macros for all table access, with these being defined according to the compiler/target combination in use. None of these are practical - in reality, such code will be written using the "flash" keyword if you are using IAR, a slightly non-standard abuse of "const" if you are using ImageCraft, and "progmem" and assorted macros if you are using avr-gcc.
> However this illustrates the difference between "it just works" and putting > a lot of effort into making it work. Most software isn't specifically written to > be portable, and yet porting is surprisingly easy. You can download random > source code from the internet and expect it to compile and work on ARM, > MIPS, PPC, ColdFire, AVR32 or any other modern embedded architecture > with minimal effort. >
In the context of embedded development, all of these processors listed are fairly "big". They are all 32-bit processors with good support for C, and thus you can expect that code "just works". Portability issues (for general code that is not interfacing directly with hardware) come to light when using smaller or more specialised processors.
>>> The reverse is true as well, programs written for these C dialects do not >>> work on standard C compilers. One case that comes up often is: >>> unsigned char c = 255; if (~c == 0) ... This is always false in standard C, >>> but there are compilers which think it is true... >>> >> If code like that comes up "often", you have bigger problems than just bad assumptions - that code snippet is >> horrible. But it is certainly true that code written for small embedded C systems often has compiler/target specific >> features that don't work on larger systems - code for a compiler with an extra "flash" keyword for flash-based data >> will clearly not compile on anything else without some changes. > > It was an example of what goes wrong when people try to port applications > when moving to a different architecture, and find that their code doesn't > work any more. Some 8-bit compilers apparently don't apply the standard > integer promotion rules, which makes porting of all but the most trivial > programs rather tricky. >
I've more often had issues with 8-bit compilers producing correct but inefficient code due to C's promotion rules, but I get the point.

Memfault Beyond the Launch