From: David Brown on
Niklas Holsti wrote:
> David Brown wrote:
>
>> The AVR has plenty of registers - you pass arguments in these
>> registers by using normal C function calls. If you have so many
>> parameters (or such large parameters) that passing by stack is needed,
>> the compiler handles that fine - there is a minor overhead, but any
>> code that needs it will already be large.
>>
>> What I said about pointers to structs is that the AVR has two pointer
>> registers that work well with structs - Y and Z (since there are
>> Y+index and Z+index addressing modes). If your compiler dedicates Y
>> to a data stack pointer, it's going to be inefficient at code that
>> could otherwise take advantage of two pointer-to-struct registers.
>
> ... which is a drawback of the two-stack solution. On the other hand,
> since the AVR provides no SP-relative addressing, single-stack code must
> often use one of the Y or Z pointers as a frame pointer, and there we
> are again.
>

A single-stack compiler must use Y or Z (invariably Y, since Z is also
tied to other functions like lpm) if a frame pointer is needed. My
point is that a frame pointer is seldom needed. The great majority of
code (in my experience) uses the registers, and there is no data on the
stack (except for preserving registers if needed, and that uses pushes
and pops without a frame pointer).

With a single-frame solution, the code can use Y as a frame pointer or
as a general pointer, and can change the usage within a function.

> Although the AVR is register-rich, it is "pointer-poor". Some other
> architectures, such as the H8/300, have more flexible interplay of 8-bit
> and 16-bit computations.
>

The AVR is certainly pointer-poor - it would be much nicer with at least
one more general pointer (at the very least, X+index modes would be
useful). I don't know anything about the H8/300, so I can't comment on it.
From: David Brown on
ChrisQ wrote:
> David Brown wrote:
>
>>
>> I'm guessing you wrote this before reading my other post? Remember,
>> these are details that are hidden by the compiler, and the AVR will
>> have executed the necessary pushes, stack pointer manipulation,
>> interrupt disable and whatever before the average 8051 device has
>> managed to push the A register onto the stack. The discussion is
>> about whether gcc's stack arrangement or IAR's stack arrangement is
>> best for producing optimal interrupt code on the AVR - no one would
>> seriously compare it to the 8051.
>
> Stuff like that may be hidden by the compiler, much as one might stick a
> bandaid on a sore to hide it, but the inefficiency is still there. C on
> 8 bit micros only gets away with it in most cases because the later cpu
> performance is far greater than cpu's used in the old assembler days.

You are making a mountain out of a molehill. It is true that there are
a few places where the AVR could have been made slightly more C-friendly
- I cannot think of any cpu where that is not the case (and I know the
architectural details of at least a dozen, including several 32-bit
architectures). As I said in another post, in the 20 KB program I
checked there are a total of *2* functions which require a stack frame
at all - and by compiling with -mtiny-stack there is *no* interrupt
disabling at function entry. It is not a problem in the huge majority
of cases.

I am a great believer in knowing your tools and knowing your target.
There are times when code size or speed is critical, and you should be
aware of the advantages and disadvantages of your tools and targets when
working with such code. However, you must keep things in perspective -
when you have a function that takes 1000 cycles to run (it must be big
to need a stack frame), 3 or 4 extra prologue cycles do not matter.

You have not used the avr, you have not used avr-gcc. I don't know how
familiar you are with the 8051 or with gcc on other targets, but your
knowledge about the AVR and avr-gcc's inefficiencies seems to be based
entirely on this thread. I have difficulty understanding why you see
the occasional interrupt disable in avr-gcc function prologues as such a
big issue based solely on some comments in this newsgroup.

> This is not a critique of avr either. Its a long time since I looked at
> the output from Keil C, but remember being horrified by a function with
> a simple switch statement + a few other lines of code producing over 2
> A4 pages of 8051 assembler. We get away with it, but let's not pretend
> that it's anything like elegant - it's a compromise made to make
> software development easier, portable and more maintainable using cheap
> micros. The downside is that such limitations can make it much more
> difficult to produce structured, robust and portable code.
>

Once you have tried using C on an AVR and looked at the resulting
assembly code, you'll see that there are *no* limitations to making
standard, robust and portable C code run perfectly well on an AVR. You
will see that there are times when you get better code by writing
slightly different C than you would for a larger device (such as using
"uint8_t" instead of "int" for index variables). And occasionally you
might want to re-structure your code a little to fit the processor
better in critical code. But there is nothing more to it than that.

>>
>> I think you should read a little about the AVR before making such
>> ignorant and incorrect statements. The AVR was specifically designed
>> as a small and low power core that worked well with C - it was
>> developed in cooperation with IAR. The 8051 is legacy, even though
>> there are modern implementations. But the AVR, while not perfect, is
>> about as close to modern cpu design as you get in 8 bits.
>>
>
> As I said, I haven't used avr, but why not 16 bit registers instead of 8
> ?. Sorry, but I don't see that as being particularly compiler friendly.
> Compiler friendly to me means n * 16 bit registers at a minimum and
> addressing modes to allow use for vars or addresses.
>

I certainly agree that 16-bit is /more/ C-friendly than 8-bit. I'm not
going to try and tell you that the AVR is more C-friendly than the
ColdFire or the ARM (or the AVR32). But it is undoubtedly in a totally
different class of C-friendliness than the 8051.

>>
>> The msp430 is certainly very compiler friendly - even more so than the
>> AVR (16-bit registers, plenty of flexible pointers, and a single
>> address space). But they too have their "special issues". For
>> example, the multiplier is implemented as a peripheral and the state
>> of the multiplier cannot be properly saved by an interrupt. Thus
>> either interrupts must avoid using the multiplier, or main code must
>> disable interrupts when using the multiplier. /Every/ cpu core has it
>> issues.
>>
>
> That's a bit of a red herring. Not all versions of the 430 have the
> multiplier in any case and it looks like it was intended as a fast dsp
> type 'peripheral'. The compiler must provide support via shift and add
> or similar to get multiply and divide in C.
>

Marvellous rationalising! The AVR is C-unfriendly and needs "band-aids"
because on the rare occasion that you have a function requiring a large
stack frame, it needs to disable interrupts for a couple of cycles. The
msp430 needs to disable interrupts every time you use a multiplier
(unless you are very careful with your interrupt code), yet that is a
"red herring". For your information, multiplies turn up a good deal
more often than just "dsp" code.

The msp430 has the multiplier as a peripheral because it takes space and
power to make a fast multiplier - more than TI wanted in a low-power,
low cost core. Making in a peripheral rather than part of the core was
the cheapest way to make it optional.

>> And the newer msp430 cores with their 20-bit registers totally buggers
>> up their C compiler friendliness.
>
> Agreed, that could be a problem, but no doubt the compilers will be
> updated to make use of the added address space. They manage fine on the
> 24 bit 80C87 series and probably others as well...
>

I don't know anything about the 80C87, but I *do* know that 20-bit
registers fit very badly with C - worse than 8-bit, and worse than 24-bit.
From: Grant Edwards on
On 2009-09-28, David Brown <david(a)westcontrol.removethisbit.com> wrote:

> The msp430 is certainly very compiler friendly - even more so
> than the AVR (16-bit registers, plenty of flexible pointers,
> and a single address space).

And the msp430 gcc backend is able to do a pretty good job of
code generation -- and I'm pretty sure far fewer resources have
gone into the '430 port than went into the AVR port.

> But they too have their "special issues". For example, the
> multiplier is implemented as a peripheral and the state of the
> multiplier cannot be properly saved by an interrupt. Thus
> either interrupts must avoid using the multiplier, or main
> code must disable interrupts when using the multiplier.
> /Every/ cpu core has it issues.

The '430 HW multipler issue is very similar to issues that many
processors have with floating-point units.

> And the newer msp430 cores with their 20-bit registers totally
> buggers up their C compiler friendliness.

As you can till by how long it's taking to get 20-bit support
into gcc for the '430.

--
Grant
From: Grant Edwards on
On 2009-09-28, Niklas Holsti <niklas.holsti(a)tidorum.invalid> wrote:
> David Brown wrote:
>
>> The AVR has plenty of registers - you pass arguments in these registers
>> by using normal C function calls. If you have so many parameters (or
>> such large parameters) that passing by stack is needed, the compiler
>> handles that fine - there is a minor overhead, but any code that needs
>> it will already be large.
>>
>> What I said about pointers to structs is that the AVR has two pointer
>> registers that work well with structs - Y and Z (since there are Y+index
>> and Z+index addressing modes). If your compiler dedicates Y to a data
>> stack pointer, it's going to be inefficient at code that could otherwise
>> take advantage of two pointer-to-struct registers.
>
> ... which is a drawback of the two-stack solution. On the other hand,
> since the AVR provides no SP-relative addressing, single-stack code must
> often use one of the Y or Z pointers as a frame pointer, and there we
> are again.
>
> Although the AVR is register-rich, it is "pointer-poor".

That's an excellent description. As soon as you start doing
anything using pointers (either explicity or implicitly) on the
AVR, it falls over. OTOH, something like the msp430 with
16-bit registers and ALU handles pointers effortlessly.

> Some other architectures, such as the H8/300, have more
> flexible interplay of 8-bit and 16-bit computations.

The H8/300 handles 32-bit data and pointers atomically as well
which makes the life of a compiler writer (and that of an RTOS
implementer/user) very easy.

--
Grant



From: Mel on
ChrisQ wrote:

> Stuff like that may be hidden by the compiler, much as one might stick a
> bandaid on a sore to hide it, but the inefficiency is still there.

That's not really the C programming attitude. I don't care what steps to
the left or right the program takes while getting where I want it to go. If
it meets specs and performance targets, then it's a product, and that's why
we're there.

On one project I prototyped with an Atmega168. The client had more
experience (plus all the programming/debugging stuff) with PIC, so they
tweaked the I/O statements in the C code and now the product runs on PIC18.
C friendliness or un- made no difference.

Mel.