EmbeddedRelated.com
Forums
Memfault State of IoT Report

mixing C and assembly

Started by Lax April 22, 2008
On Wed, 23 Apr 2008 08:26:59 -0400, Walter Banks
<walter@bytecraft.com> wrote:


>Chris H wrote: > >> As has already been mentioned the start up code has to be in assembler >> as it sets up the memory for the stack etc however if you use the >> standard one that comes with the compiler you will never need to see it. > >There is no requirement for the start up code to be in asm. A lot of >compilers come with asm sample startup but the code could have >been written in C in the same compiler. The same extensions that >support embedded systems make this possible
While you might be able to write the startup code completely in C, but does this works with different optimization switches, with different compiler versions or even with different compilers ? The ability to understand the generated assembly code will significantly help, if you have to move into a different environment. Paul
In article <480F499B.70EA80B4@bytecraft.com>, walter@bytecraft.com 
says...
> > > Mark Borgerson wrote: > > > In article <480F2B12.69B62031@bytecraft.com>, walter@bytecraft.com > > says... > > > > > > > > > Chris H wrote: > > > > > > > As has already been mentioned the start up code has to be in assembler > > > > as it sets up the memory for the stack etc however if you use the > > > > standard one that comes with the compiler you will never need to see it. > > > > > > There is no requirement for the start up code to be in asm. A lot of > > > compilers come with asm sample startup but the code could have > > > been written in C in the same compiler. The same extensions that > > > support embedded systems make this possible > > > > Just out of curiosity, how do you set the initial value of the > > stack pointer in C? > > Most embedded systems compilers have extensions that > support processor register access. A lot of the compilers > were implemented from hosted compilers as a base and the > initial startup code was written before they added support > for processor access. The example startup has often been > this early code. My point is that it can be done in C. > > In our case the first C compiler was written for the C6805 > and that was based on a 6805 mistral compiler we had written > a few years earlier. Our initial startup code was written > in C on a compiler that would support it. > > register_sp SP; > > SP = int_value; >
I must be using the wrong compilers! ;-) Imagecraft for the MSP430, IAR for the ARM, IAR for the MSP430 and Codewarrior for M68K systems all seem to use an assembly-language routine for initial setup. In the case of the Atmel ARM chips, there's also some memory chip selects and block remapping to do. Thankfully, you generally don't have to touch that code unless, as I have, you need a custom memory map to separate a boot monitor from the user application. Mark Borgerson
In article <f9b88f12-3621-441c-ad80-1db7328f7621
@b64g2000hsa.googlegroups.com>, compton75@hotmail.com says...
> On Apr 22, 3:50=A0am, Lax <Lax.Cla...@gmail.com> wrote: > > Are there any situations where programming an embedded processor > > "requires" at least some assembly code? > > > > How about for AVR, MSP430, 68HC11, 8051(Atmel)? > > Can these 4 microcontrollers be programmed fully in C without touching > > assembly (even interrupts and etc.)? >=20 > Can't interface with with external hardware without assembly. >=20 >=20
Why not? With memory-mapped peripherals all you need to do is define the proper pointer values to access the hardware registers. I've done it that way for UARTS and USB devices on ARMS and M68Ks for years. You can even set up the chip selects using their memory-mapped control registers. Mark Borgerson
On 2008-04-24, Paul Keinanen <keinanen@sci.fi> wrote:

>>Are there any situations where programming an embedded processor >>"requires" at least some assembly code? >> >>How about for AVR, MSP430, 68HC11, 8051(Atmel)? >>Can these 4 microcontrollers be programmed fully in C without touching >>assembly (even interrupts and etc.)? > > Why do you ask this ? > > Do you expect that you could work with embedded systems > without learning anything about the hardware architecture and > the processor instruction set ? > > Most embedded project could be written completely in C except > for the initialization code, possibly some interrupt preamble > code, OS task switching and the use of some processor specific > special instructions. In most cases this would be 1-2 pages of > assembler code. > > However, if you are developing embedded applications in C or > in other high level languages, you really have to understand > what machine instructions are generated and what resources are > needed for a specific construction.
<lecture> I don't think it's possible to emphasize that last point enough. Especially if you're developing for a small processor you're never going to be very successful if you don't know how the code generation differs for logically equivalent blocks of code. For example, two ways to sum the bytes in a buffer: unsigned char buf[128]; unsigned sum = 0; unsigned i; for (i=0; i<sizeof buf; ++i) sum += buf[i]; unsigned char *p; p = buf; while (p < buf + (sizeof buf)) sum += *p++; Those two blocks of code do the same thing. On some target/toolchain combinations, they're both about the same number of bytes/clocks. On some platforms I've used the first was significantly smaller/faster. On others, the second was significantly smaller/faster. In the fist case, are you better off with an index that's an "unsigned" or an "unsigned char" or an "int"? They can be significatly different. Always pick something that will work on as many platforms as possible, but if there are multiple "correct" ways to do something, you might as well pick the one that's going to generate the smallest/fastest code for the target. If you want to be more than an amateur doing trivial projects, you've got to know your target's instruction set and know what code the compiler is going to generate each time you write a line of C. I always set up my makefile so that the toolchain produces a mixed C/assembly listing for each module. Anytime I'm not sure what the compiler is going to do with a particular construct, I look at the listing and see. </lecture> -- Grant Edwards grante Yow! I invented skydiving at in 1989! visi.com
Walter Banks wrote:
> > Neil wrote: > >> Walter Banks wrote: >>> Vladimir Vassilevsky wrote: >>> >>>> You have to resort to assembly in the two special cases: >>>> >>>> 1. The system level work like switching the contexts of the tasks, C >>>> startup code, etc. >>>> >>>> 2. The parts of code where the performance is very critical. >>> In your second point I would qualify it to parts of code >>> requiring exact timing on anything that we have released >>> recently that seems to be the only limitation. >>> >>> >> Do not forget the startup code > > Our startup code is in C. > > w.. > > >
I am not sure how that works. I am talking about the code that jumps to main after setting up the C environment.
On Wed, 23 Apr 2008 20:56:28 -0500, Grant Edwards <grante@visi.com>
wrote:

>On 2008-04-24, Paul Keinanen <keinanen@sci.fi> wrote:
>> However, if you are developing embedded applications in C or >> in other high level languages, you really have to understand >> what machine instructions are generated and what resources are >> needed for a specific construction. > ><lecture> > >I don't think it's possible to emphasize that last point >enough. > >Especially if you're developing for a small processor you're >never going to be very successful if you don't know how the >code generation differs for logically equivalent blocks of code.
The situation is not so problematic with C, but if you insist of using C++ in some embedded project, you _really_ have to understand, what resources a specific construct will require on your platform. Paul
In message 
<f9b88f12-3621-441c-ad80-1db7328f7621@b64g2000hsa.googlegroups.com>, 
compton75@hotmail.com writes
>On Apr 22, 3:50&#4294967295;am, Lax <Lax.Cla...@gmail.com> wrote: >> Are there any situations where programming an embedded processor >> "requires" at least some assembly code? >> >> How about for AVR, MSP430, 68HC11, 8051(Atmel)? >> Can these 4 microcontrollers be programmed fully in C without touching >> assembly (even interrupts and etc.)? > >Can't interface with with external hardware without assembly. >
Not true... most embedded C compilers have extensions which permit this. -- \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Bill Leary wrote:
> "Walter Banks" <walter@bytecraft.com> wrote in message > news:480FAC36.E382E22B@bytecraft.com... >>> Why would you bother optimising a traditional call to main into a jump? >> >> When C runs on embedded systems processors that are not hosted main >> should never return. > > Usually, no. But it's a good idea to make sure the system does > something reasonable if it does. >
Why should the system do something reasonable if the programmer does something unreasonable? In my gcc programs, main is tagged with a "noreturn" attribute - attempting to return from main will produce at least a warning message, possibly an error (I can't remember off-hand). I'm sure Walter's compilers are able to enforce no return from main equally well.
Paul Keinanen wrote:
> On Wed, 23 Apr 2008 08:26:59 -0400, Walter Banks > <walter@bytecraft.com> wrote: > > >> Chris H wrote: >> >>> As has already been mentioned the start up code has to be in assembler >>> as it sets up the memory for the stack etc however if you use the >>> standard one that comes with the compiler you will never need to see it. >> There is no requirement for the start up code to be in asm. A lot of >> compilers come with asm sample startup but the code could have >> been written in C in the same compiler. The same extensions that >> support embedded systems make this possible > > While you might be able to write the startup code completely in C, but > does this works with different optimization switches, with different > compiler versions or even with different compilers ? >
If it is written correctly, then for the most part the answer is yes. But when you are dealing with such low-level coding, you should be prepared at least to re-check the code when changing tools. Although technically written in C, start-up code often contains C statements that are just thin wrappers around assembly code, using macros, inlined functions, intrinsics, and the like. The definitions of these will often need modified for different compilers, but the usage of these macros and inlines is mostly independent of the compiler.
> The ability to understand the generated assembly code will > significantly help, if you have to move into a different environment. >
The ability to understand the generated assembly code is *always* a good thing in embedded development. It is particularly relevant during such critical startup code (as well as in any time-critical parts of the code). By writing startup routines in C rather than assembly, however, you reduce your requirements to an understanding of assembly, rather than the knowledge to write good assembly for the target. IIRC, I first started using C for startup code when targeting a PPC processor. Until you get used to it, it is hard to write good PPC assembly. Rather than trying to figure out which addressing modes made sense, which registers are used for which functions in the ABI, and so on, it was much easier to write it in C and let the compiler figure out the details. My task was then reduced to checking the generated assembly (and the not insignificant task of figuring out how to get the chip's hardware configured!).

CBFalconer wrote:

> Walter Banks wrote: > > > ... snip ... > > > > In our case the first C compiler was written for the C6805 > > and that was based on a 6805 mistral compiler we had written > > a few years earlier. Our initial startup code was written > > in C on a compiler that would support it. > > > > register_sp SP; > > > > SP = int_value; > > In other words you seized a user available identifier, register_sp, > and then recognized that in the code to accept an int_value and > initialize the stack pointer. This is not C, but an extension. > The only thing wrong with that is that it is not marked as an > extension. If the mechanism is also used to read the SP the above > declaration should mark it as volatile. I think it would be better > to use a name reserved for the implementation, such as > __register_sp. > > I am not objecting to extensions. However I believe they should > minimize any effects on standard C.
Force of habit. Both are actually supported in our compilers. register_sp existed before the ISO naming rules __register_sp was alludes after and register_sp was kept so old code wouldn't break with updated compilers. Your point is well taken, I should have used the proper current syntax. w..

Memfault State of IoT Report