mixing C and assembly

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

Reply to
Paul Keinanen
Loading thread data ...

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

Reply to
Mark Borgerson

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

Reply to
Mark Borgerson

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

Reply to
Grant Edwards

I am not sure how that works. I am talking about the code that jumps to main after setting up the C environment.

Reply to
Neil

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

Reply to
Paul Keinanen

Not true... most embedded C compilers have extensions which permit this.

--
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
\/\/\/\/\ Chris Hills  Staffs  England     /\/\/\/\/
\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Reply to
Chris H

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.

Reply to
David Brown

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 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!).

Reply to
David Brown

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..

Reply to
Walter Banks

Mark,

Actually Byte Craft compilers are a little more complex. The compiler / linker keeps track of the things that architecturally need to be initialized and generates code for this after reset. This usually initializes the stack from either default, declared values in the application or linker information. There are other architectural dependent things in some processor families like clock options default ISA's, memory map tables. These choices are selected with application pragma's.

The function called __STARTUP if it exists in the application gets executed as soon as the processor is stable but before the variables are initialized. __STARTUP is used to support user initialization and is the way many embedded products trap a maintenance startup mode. (Maintenance modes are user defined often ground a output pin when processor is reset, jump or call maintenance software in the application)

__STARTUP is written like any C function. When it is called no variables have been initialized so if it goes into a maintenance mode the variables have their values pre-reset.

After __STARTUP returns the remaining compiler generated initialization is executed and then there is a jump to main(..).

The compiler/linker in the simplest case just ties the reset vector to main (default stack) in the most complex goes through the steps outlined above.

Regards,

-- Walter Banks Byte Craft Limited Tel. (519) 888-6911

formatting link
snipped-for-privacy@bytecraft.com

Reply to
Walter Banks

upon

ut

ck

in

IEC

processor

of C's

the

t).

No we're talking about startup code, do try to keep up.

text -

Firstly you would be mad to try running C of these chips. Secondly you would not put call returns on the hardware stack unless you have some kind of death wish, you keep that space for the ISRs.

Reply to
cbarn24050

Because programmers WILL do something unreasonable and helping them to discover what that is, beyond the system going bye-bye, is good engineering. A bit of work here can potentially save a pile of work later on.

OK. So you DID do the "something reasonable," using a feature provided by your development package.

- Bill

Reply to
Bill Leary

Indeed you do but it's not usually more than 2 bytes, you cant get much more optimal than that.

ad section.

Reply to
cbarn24050

?

ain

Anything can upset a program, you need some kind of error code, also needs to be in assembly, to make the system safe.

Reply to
cbarn24050

Walter writes compilers for a living, so his comments are based at least partly on that - and I was commenting on your comments on his comments, if you see what I mean.

But we are also talking about project-specific startup code.

When you are writing your own startup code, as is appropriate for some projects, I can't really see why you would intentionally and knowingly want to waste some ram, flash and run-time by specifically choosing a call when a jump will do the job. If the source code is neater or clearer, or faster to write, then that is obviously the decider. But all other factors being equal, a jump will do the same thing.

In fact, if you are using a compiler that does some sort of whole-program optimisation, and you write your startup code in C, you can expect that you will get neither a call to main, nor a jump to main

- the entire main() function will be inlined within the startup code.

text -

Firstly, you must then call me mad, along with all the customers for PIC C compilers targeted at the smallest PICs, and ImageCraft's dedicated AVR Tiny C compiler. I've only used a Tiny once, but I wrote that program in C (using gcc - with a bit of arm-twisting to make it work without RAM). I studied the generated assembly - it is unlikely that I could have improved on it more than a few percent if I had hand-write the assembly.

Secondly, the AVR Tiny has no ram beyond its 32 cpu registers. I find it hard to imagine that you could write a program that needed more than

3 levels of calls (including interrupts) and have space in those registers to make a software call stack. These are devices aimed at small and simple programs - three levels of call stack is often sufficient.
Reply to
David Brown

A layer of a stack on a PIC with only 8 levels (In one case 2 levels) has a big impact the available subroutine return stack.

w..

Reply to
Walter Banks

But the 8 level pic, at least, simply overwrites the eldest stack return address if overused. This puts you back to the condition where you didn't stack anything, because the stack is used modulo

  1. Of course the only way to stack that return is to call in the first place. :-(
--
 [mail]: Chuck F (cbfalconer at maineline dot net) 
 [page]: 
            Try the download section.


** Posted from http://www.teranews.com **
Reply to
CBFalconer

Even the good intelligent people sometimes fall into the belief of their own hype :-)

Not too long ago I have burned up with the C startup code in C: it called the intrinsic function. Initially, that function was inlined; however after the new bugs in the CPU were discovered, that intrinsics had to be implemented as a walkaround function in the C library. So the startup called the library function before the library was intialized, and it caused all sorts of weird problems. It was quite difficult to find the cause.

Vladimir Vassilevsky DSP and Mixed Signal Design Consultant

formatting link

Reply to
Vladimir Vassilevsky

The new Cortex M3 is advertised by ARM not to require any assembly code, even boot up or ISR's.

formatting link
formatting link

"The Cortex-M3 processor includes many features that enable faster software development, with developers not required to write any assembler code or have a deep knowledge of the processor and its register set."

"By handling the stack operations in hardware, the Cortex-M3 processor removes the need to write assembler wrappers that are required to perform stack manipulation for traditional C-based interrupt service routines, making application development significantly easier."

"Traditionally ISRs require an assembler wrapper to handle stack manipulation before and after the main C-based routine is called and during start-up boot code. The Cortex-M3 processor handles all stack manipulation in hardware, removing the need for the assembler and enabling the developer to program just in C and without having to learn exactly how the processor and all of the register banks operate."

Reply to
steve

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.