From: ChrisQ on 28 Sep 2009 05:59 David Brown wrote: > Code that uses pointers to structs will see particular benefits of > having Y available for general use. > More good info - I suspect avr is a far better architecture than 8051. Memories of legacy 8051 hw platforms, multiple code banks, not enough common area and hard work trying to ensure that all the correct data appeared in the selected bank at the right time suggests that there must be a better way. The impact on development timescales can be significant and outweighs any device cost advantage for small to medium volume products. As you suggest, more than 2 arguments and the best way is to package up into a structure and pass a pointer to it. Such a structure can also aid encapsulation as common variables can also be declared within it. Object oriented methods for 8 bit micros indeed :-)... Regards, Chris
From: David Brown on 28 Sep 2009 06:49 ChrisQ wrote: > David Brown wrote: > >> Code that uses pointers to structs will see particular benefits of >> having Y available for general use. >> > > More good info - I suspect avr is a far better architecture than 8051. > Memories of legacy 8051 hw platforms, multiple code banks, not enough > common area and hard work trying to ensure that all the correct data > appeared in the selected bank at the right time suggests that there must > be a better way. The impact on development timescales can be significant > and outweighs any device cost advantage for small to medium volume > products. > > As you suggest, more than 2 arguments and the best way is to package up > into a structure and pass a pointer to it. Such a structure can also aid > encapsulation as common variables can also be declared within it. Object > oriented methods for 8 bit micros indeed :-)... > No, no - I did not suggest packing function call arguments in a struct! How did you manage to read that from my post? You only need to use such tricks for braindead architectures like the 8051, where you have a hopeless stack and almost no registers, and thus need to pass data via globals or extra structs. (A good compiler will hide these messy implementation details from you, and do a better job that using these tricks manually.) 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.
From: David Brown on 28 Sep 2009 07:12 ChrisQ wrote: > Niklas Holsti wrote: >> A small addition to my own posting, sorry for omitting it initially: >> >> Niklas Holsti wrote: >> (I elide most of the context): >> >>> However, sometimes the IAR compiler generates code that adds or >>> subtracts a larger number (> 1) to/from Y, and then it must use two >>> 8-bit operations, and must disable interrupts just as gcc does. >> >> Some AVR models do provide instructions (ADIW, SBIW) that can >> atomically add/subtract an immediate number (0..63) to/from the 16-bit >> Y register. I assume, but haven't checked, that IAR uses these >> instructions when possible, rather than two 8-bit operations in an >> interrupt-disabled region. >> > > A very good explanation and thanks. It's the intricacies of architecture > that is sometimes hard to get a big picture of when choosing a processor > for a project. I've never used avr for any project and info like this > would tend to keep me in the 8051 world for small logic replacement > tasks, no matter how constrained it is. AVR32 looks much better though. > 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. The AVR32 is a different beast entirely. It shares the same developer (Atmel), and some tools, but other than that it is a totally different processor. > In summary then, it looks like the 8 bit avr's need special compiler > support to get best results, which I wouldn't necessarily expect gcc to The AVR needs an AVR compiler - just like any other cpu needs its own compiler. It doesn't need any "special" support or tricks here - every target has it's own way of handling function prologues and epilogues. gcc is best suited to RISC-type architectures with plenty of registers and an orthogonal instruction set. The AVR comes fairly close to that, but with two big exceptions - it is 8-bit (most gcc targets are 32-bit), and it has a separate memory space for flash. avr-gcc does a good job in working around these "non-standard" features, but is occasionally sub-optimal in that regard. This is hugely different from cores like the 8051 or the COP8, which need much more specialised compilers to generate good code. > provide. I'm quite happy to accept that IAR would produce better code, > in much the same way as Keil is arguably the best solution for 8051. It's a different world entirely. IAR produces better code than gcc (at least, according to popular opinion - I have not yet compared it myself, or seen any independent comparisons) because they have more resources to use in the development of their compiler, and their compiler architecture is probably also more suited to optimising 8-bit code. They have also been working with the AVR developers since before the core was fully specified. Not to belittle the work of either the avr-gcc or IAR development teams, but writing a solid AVR compiler that produces small and fast code is a fraction of the work needed to make a close-to-optimal 8051 compiler. And if you've got a working multi-target compiler to start with (as both avr-gcc and IAR had), then porting it to the AVR is a practical task. For the 8051, you have to start almost from scratch. > Both are 8 bit legacy architectures, designed before the days of general > hll development. I think if I were trying to find a low end micro now, 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. > msp430 would be the first point of call, as it is a much more compiler > friendly 16 bit architecture. Stuff like this does matter as it can have > a significant impact on software development timescales and quality... > 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. And the newer msp430 cores with their 20-bit registers totally buggers up their C compiler friendliness.
From: Niklas Holsti on 28 Sep 2009 07:28 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". Some other architectures, such as the H8/300, have more flexible interplay of 8-bit and 16-bit computations. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .
From: ChrisQ on 28 Sep 2009 09:02
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. 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. > > 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. > > 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. > 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... Regards, Chris |