From: David Brown on 28 Sep 2009 09:42 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 28 Sep 2009 10:02 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 28 Sep 2009 10:56 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 28 Sep 2009 11:20 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 28 Sep 2009 11:28
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. |