EmbeddedRelated.com
Forums
Memfault State of IoT Report

Moving from 8051 to AVR

Started by ziggy February 5, 2006
On 2006-02-08, David Brown <david@westcontrol.removethisbit.com> wrote:


> [...] On an avr, a C compiler can produce pretty good code - > not optimal, but not bad. On an 8051, it's a struggle for a > compiler to produce good code because the language is such a > bad fit for the cpu architecture. On an msp430 or an ARM, the > compiler is going to be able to come much closer to optimal, > and probably will produce better code than an assembly > programmer would
I'll vouch for that last statement. After profiling an application running on an ARM platform, I found that the IP checksum routine from the BSD TCP/IP stack was by far the largest sink of CPU time. In order to try to squeeze more performance out of the platform, I decided to re-write the C-language IP checksum routine in assembly language. The first couple versions of the assembly language version were slower than the C version. After three or so re-writes of the assembly language routine, I had one that was a little bit faster than the C function. I didn't seem to be making much headway, so I turned to Google and Usenet and found pointers to a couple very obscure tricks (in both the math and the ARM instruction set). After a couple more days of hard work, I had an IP checksum routine that was about 40% faster than the C version. Beating GCC on the ARM wasn't easy, and at the time GCC's ARM back end was reputed to be only mediocre compared to a couple other compilers. -- Grant Edwards grante Yow! I wonder if I ought at to tell them about my visi.com PREVIOUS LIFE as a COMPLETE STRANGER?
David Brown wrote:

<snip>
 > But I'm happy to hear if
> you've got some examples of program snippets or tasks that work well on > the 8051 but would be poor (either big, slow, or awkward to code) on an > AVR or msp430, programmed in either assembly or C.
That's actually quite easy, because the 80C51 has opcodes the AVR simply lacks ( the AVR is closer to the 8048, than the 8051 ) : Any code that is BOOLEAN in nature flys on an 80c51 ( and is fully atomic ) - but the C radar, back when the AVR was designed, did not include BOOLEAN types, plus the AVRs target was as a small ASIC core. In the 80C51 you can also map BITs onto BYTES in the BIT ADDRESSABLE space, for very efficent code. The 80C51 also has Direct Memory opcodes: Go outside the registers, and the AVR suddenly suffers from 'pointer thrashing', and is NOT interrupt friendly - so any code that is not large arrays, but has a smattering of named variables ( gee, most embedded code, actually ) has the 80C51 well in front. Most 80C51's have 4 priority levels on interrupts, and all have register bank switching - even the lowly 8048 had register bank switching, something else the AVR lacks. Some AVR devices do appeal, but it is more in spite of the core, than because of it. The new Tiny2313 and Tiny25/45/85 features like Wide Vcc, on chip OSC, and reasonable peripherals with on chip debug, all make for nice little devices. Of course, the new LP213/214/216 devices from Atmel, have 1 cycle 80C51 cores, and tiny packages, nearly as Wide Vcc, and on chip debug - so you get a good core _and_ good peripherals :) Philips, STC, Coreriver, SiLabs also have small package 80C51's -jg
Jim Granville wrote:
> David Brown wrote: > > <snip> > > But I'm happy to hear if >> you've got some examples of program snippets or tasks that work well >> on the 8051 but would be poor (either big, slow, or awkward to code) >> on an AVR or msp430, programmed in either assembly or C. > > That's actually quite easy, because the 80C51 has opcodes the AVR > simply lacks ( the AVR is closer to the 8048, than the 8051 ) : > > Any code that is BOOLEAN in nature flys on an 80c51 ( and is fully > atomic ) - but the C radar, back when the AVR was designed, did not > include BOOLEAN types, plus the AVRs target was as a small ASIC core.
The AVR can do atomic bit manipulation on a useful segment of its IO space, and on half its registers. So if you want very fast access flags, you can reserve a register and use that. Normal booleans in C are implemented as an int or a byte (you'd use a byte on an AVR). With a few macros, you can get reasonably convenient bit access, although it's not atomic (which can be a disadvantage).
> In the 80C51 you can also map BITs onto BYTES in the BIT ADDRESSABLE > space, for very efficent code.
I can't think off hand of any advantage of bit addressability like this unless you are dealing with an array of bits, or pointers to bits, except perhaps for atomic access.
> The 80C51 also has Direct Memory opcodes: Go outside the registers, > and the AVR suddenly suffers from 'pointer thrashing', and is > NOT interrupt friendly - so any code that is not large arrays, but > has a smattering of named variables ( gee, most embedded code, actually > ) has the 80C51 well in front.
I'm not sure why you would want to access your named variables through pointers, except for arrays, or very occasionally when passing pointers to functions. Unless, of course, you are using an architecture which does not have direct access to more than a small part of its memory space, and is forced to use pointers to access fixed-position global data. Perhaps you haven't looked at the details of the AVR (I had not looked at the details of the 8051 until this evening). The AVR can directly read or write to any fixed address in its RAM or IO space, without going through pointers. It has no way to do read-modify-write atomically to memory. I'd happily agree that the AVR should have had four full pointers, instead of two and a half (one of the pointers does not support all addressing modes), and the separate flash and data memory spaces is a pain, but it's a world ahead of the 8051 with convenient access to a grand total of 128 bytes data, two different sorts of pointers to access different parts of ram (no doubt causing great programmer joy when re-arranging the placement of variables in data sections), and a third type for flash access. The DPTR arrangement for access to XDATA is, I'm sure you'll agree, awkward, slow and inefficient for anything but the most simple access, and much less efficient than the AVR's memory access. Even for 8051 variants with more than one DPTR, it's still poor - a simple block copy routine needs seven instructions within the loop, while an AVR would need 4. When it comes to indexed addressing, which is essential for use of structures and data stacks (used in high-level languages, but less used in assembly), the 8051 is a non-starter. The 8051 has better atomic access to memory than the AVR, which could be useful in some applications - I'm not claiming the AVR could not be improved upon.
> Most 80C51's have 4 priority levels on interrupts, and all have > register bank switching - even the lowly 8048 had register bank > switching, something else the AVR lacks. >
Yes, the 8051 has 4 banks of 8 registers, whereas the AVR has 1 bank of 32 registers. When writing assembly for the AVR, I generally dedicate a group of registers to the interrupt routines, so that there is no bank switching or register saving needed at all. And yes, the 8051 has interrupt priorities, allowing low-priority interrupts to be pre-empted by high-priority interrupts. Personally, if I have a low-priority interrupt routine that I know may take significant time, I simply re-enable the interrupt flag so that it may be pre-empted. There's not a lot of difference for real applications.
> Some AVR devices do appeal, but it is more in spite of the core, than > because of it. > The new Tiny2313 and Tiny25/45/85 features like Wide Vcc, on chip OSC, > and reasonable peripherals with on chip debug, all make for > nice little devices. > > Of course, the new LP213/214/216 devices from Atmel, have 1 cycle 80C51 > cores, and tiny packages, nearly as Wide Vcc, and on chip debug - so > you get a good core _and_ good peripherals :) > > Philips, STC, Coreriver, SiLabs also have small package 80C51's > > -jg >
And do these small 8051 chips still have the "wonderful" system of I/O pins that can't drive high? I know that is not part of the 8051 cpu core, but it's part of the baggage that backwards compatibility brings. I suppose the 8051 is a reasonable enough core for very small micros and simple tasks, but I would not like to have to use it for anything sizeable (unless combining a C compiler, a fast clock speed, and plenty of memory, and just try to forget the architecture inefficiencies). It's perhaps not the worst choice (the COP8 and PIC16 vie for that position, out of the micros I've used). But I'm still left with the very clear position that the AVR can do almost anything the 8051 can do, and can do much more besides. Of course, if you look at the msp430, you see a cpu that's even better to work with.
CBFalconer wrote:
> David Brown wrote: >> Ian Bell wrote: >> > ... snip ... >>> Here we go again, the tail wagging the dog. A micro 'designed' to >>> use C is not a recommendation its a good reason not to use it. >> Why do you say that? If you want to complain that C is a badly >> designed language, that's fair enough - you'll get plenty of >> agreement there. But generally speaking, being "designed for C" >> means the cpu must have support for accessing data on a stack >> through some sort of index, and it should have fast access to data >> through a pointer or two. Where is the disadvantage in that? >> Some high level languages could benefit from other features (Forth >> would benefit from direct stack operations, Pascal would benefit >> from a frame pointer, etc.). Some types of code cannot be >> conveniently expressed in C (bit variables, rotation, dsp-type >> operations), but being designed for C doesn't mean non-C >> operations not supported. And from experience writing assembly >> code on "C-friendly" and "non-C-friendly" architectures, I have >> no doubt that being C-friendly is a big plus. > > I am not sufficiently conversant with Forth to be sure, but I > believe it does have direct stack operations available. You may > not recognize them. However Pascal most definitely does have frame > pointers. They are embodied in nested procedures, and suitable > local declarations, not to mention the use of the WITH statement. > Again, you may not recognize them. >
Forth does everything on the stack. An ideal Forth machine would not have any registers at all, other than two stack pointers (a data stack and a return stack). For example, the "add instruction" in Forth pops the top two items from the data stack, adds them, and pushes the result. An efficient cpu for Forth therefore needs good stack manipulation instructions (although Forth compilers typically emulate the top few stack positions in registers). Pascal does indeed need frame pointers for local procedures (though not, I believe, for WITH statements - a "WITH" is a syntactic abbreviation). The AVR can emulate a frame pointer, but really it would need a couple more pointer registers to do so efficiently. This is why I said that while being "designed for C" is a help in implementing other languages, it's not enough to be ideal for all languages.
David Brown wrote:

> Ian Bell wrote:
>> >> I don't know if C is badly designed - that's not my point. A >> microcontroller 'designed for C' wrongly encourages people to think that >> C will produce the most efficient/effective code on that device which is >> plainly not true. >> > > Depending on what metrics you use for "efficient/effective", that may or > may not be true.
I agree there are cases where C is the best language of choice even on an 8 bit microcontroller - for example where resources are not scarce or unit cost is not paramount or high performance is not required. I have no problem with using C in the right circumstances. My objection is the implication that 'designed for C' means C is always best when clearly it is not.
> Ultimately, of course, a good assembler programmer is > going to be able to get the highest code density and fastest run speed > on any architecture, but the cost (both in terms of time, and programmer > ability) of writing the code compared to the gains in code efficiency > are going to be different for different sorts of cpu, and different > sorts of programming task.
Agreed.
> On an avr, a C compiler can produce pretty > good code - not optimal, but not bad. On an 8051, it's a struggle for a > compiler to produce good code because the language is such a bad fit for > the cpu architecture. On an msp430 or an ARM, the compiler is going to > be able to come much closer to optimal, and probably will produce better > code than an assembly programmer would (assuming the programmer is > interested in things like maintainability and readability of the code, > and in finishing in a sensible amount of time), at least for larger > programs.
I'll not comment on the maintainability or readability of code - that's a separate debate ;-) , but I concur that C on an ARM is generally a better choice than assembler - if someone said the ARM was 'designed for C' I would have no objection. I am not familiar with the MPS340 so cannot comment.
> (This is based on having written assembly and C code on a > range of micros, from C-unfriendly ones like the COP8 and PIC16, through > the AVR, the msp430, and big cpus like the 68k and PPC.) >
Good lord, I remember the COP8 and I also remember writing 6K of code for the 1802 using a line based editor - I don't think C had been invented then.
> > So as a sweeping generalisation, I'd say that most "designed for C" > micros are most efficiently programmed in C. >
I am happy to agree with that statement for processors like the ARM but not for ones like the AVR.
> > To be entirely honest, I have never actually used an 8051, and have only > briefly looked at the core. But (at least for a standard 8051) AFAIK > access to data on the stack is very inefficient - hence 8051 C compilers > play all sorts of tricks to implement local variables and parameters as > dedicated globally-allocated objects. And I believe different 8051 > manufacturers have added different numbers of pointer registers in > attempts to make the devices more C friendly. Am I also right in > thinking that different parts of memory ("normal" ram, "extended" ram, > flash, I/O, etc.) are all accessed in different ways? >
Pretty much spot on. It also has a Harvard architecture which is 'less C friendly' per se than a von neuman one. That's the thing with 8 bit microcontrollers - they are designed to do a specific job not suit a particular high level language.
> As to what "designed for C" means beyond these basics, I'd guess that > the other major implication is that there is a C compiler (and debugger) > available for it. > > I'd also note that except for cases where backwards compatibility with > older C-unfriendly cores is vital, or for very specialised cores, > probably all modern cpu designs are "designed for C". Like it or not, C > is the lowest common denominator of programming languages. > >
I think it is important to differentiate between 8 bit microcontrollers and everything else. It is only the former where I object to the 'C friendly' label for the reasons given earlier. 8+ bit microprocessors and16+ bit microcontrollers I have no problem with as far as labeling them 'C friendly' is concerned.
>>> >> >> Depends on the processor and the application. Here we are specifically >> considering 8 microcontrollers where the emphasis is on control. IME non >> C friendly microcontrollers make better controllers and are best >> programmed in assembler. >> > > Non C friendly architectures are often best programmed in assembly, it's > true. And for many types of programs, assembly is a sensible choice of > language. But I really cannot think of any advantage the C-unfriendly > micros I have used have over the C-friendly ones (in terms of their cpu > core, I mean), for any sort of programming. But I'm happy to hear if > you've got some examples of program snippets or tasks that work well on > the 8051 but would be poor (either big, slow, or awkward to code) on an > AVR or msp430, programmed in either assembly or C. >
Try an atomic byte increment or decrement. Personally I don't think we are a million miles apart. 'C friendly' applied to anything other than an 8 bit microcontroller is OK by me. One last point. When using C you are at the mercy of the compiler and the C programmer. There is little you can do about the former and my experience of the latter, where C was the primary language of the programmer, has been that extremely inefficient code is produced. My first embedded C project (about 15 years ago) fell into this category. The microcontroller, an Hitachi H8 was certainly what you would describe as 'C friendly' but the combination of a poor compiler and C language programmers meant the code was 50% too large and 500% too slow. I spent a lot of time educating the C programmers how to write efficient/effective C code and just as long tweaking it to circumvent the idiosyncracies of the compiler. We reused this code in a scaled down version of the product using the same H8 core quite successfully but we did have to tweak the code again to cope with the latest version of the compiler. Later, a third version was created using third party programmers (there were good reasons for this) but once again the resultant code was bloated and slow. This time we had to modify the code ourselves as by now the third party had disappeared from the scene. I admit, C compilers are (hopefully) better today, but C programmers still do not migrate to 8 bit microcontrollers with any degree of ease. Give me an assembler coder who has learned C any day. Ian
David Brown wrote:


> > When it comes to indexed addressing, which is essential for use of > structures and data stacks (used in high-level languages, but less used > in assembly), the 8051 is a non-starter. >
What makes you think structures and data stacks are less used in assembly? And the 8051 has three index registers so it's hardly a non-starter. Ian
In article <0smdu1190970s8mmh9aqrmu3t3hre9reku@4ax.com>,
 Jonathan Kirwan <jkirwan@easystreet.com> wrote:

> On 5 Feb 2006 15:05:01 -0800, "larwe" <zwsdotcom@gmail.com> wrote: > > >ziggy wrote: > > > >> Its mostly the concern of 'falling behind' a bit, and since the AVR AVR > >> seemed similar, it wouldn't be a big change.. > > > >Mmmmmfff... this is a really tough one to comment on usefully. Yes, > >8051 is old and scraggly. AVR is clean and modern by comparison. But > >unless you have a real project that would benefit in a concrete way > >from AVR, I would not advise moving. > > > >(Price is a consideration... dollar for feature, I think 8051 variants > >will beat AVRs in the high end at least - maybe not down at the 8-pin > >end though). > > > >If you are planning some massive upheaval like migrating from asm to C > >as your language of choice, then yes - run, do not walk to a modern > >architecture like AVR or MSP430. Otherwise, a careful study of actual > >dollar benefits is necessary. > > I would add that 8051 cores are available from such a wide variety of > sources, too. They are quite modern, in many of these incarnations. > Even Atmel has them, if that is one of the reasons ziggy is > considering a change towards AVR. > > If you already have excellent development tools for the 8051 family, > part of the cost of shifting will be both the new costs for equipment > as well as the learning curve and possibly for developing software > that may be needed to fill in the gaps. The change takes time and > money and always adds risk. > > For merely a "concern of 'falling behind' a bit" I don't think I'd > change. > > Or is this about getting ready for a job move? > > Jon
Nah, no job change in the near future, just was getting concerned about the '51 getting long in the tooth.. But the way it looks, i might as well stick with what i know and be happy :)
David Brown wrote:
> Jim Granville wrote: > >> David Brown wrote: >> >> <snip> >> > But I'm happy to hear if >> >>> you've got some examples of program snippets or tasks that work well >>> on the 8051 but would be poor (either big, slow, or awkward to code) >>> on an AVR or msp430, programmed in either assembly or C. >> >> >> That's actually quite easy, because the 80C51 has opcodes the AVR >> simply lacks ( the AVR is closer to the 8048, than the 8051 ) : >> >> Any code that is BOOLEAN in nature flys on an 80c51 ( and is fully >> atomic ) - but the C radar, back when the AVR was designed, did not >> include BOOLEAN types, plus the AVRs target was as a small ASIC core. > > > The AVR can do atomic bit manipulation on a useful segment of its IO > space, and on half its registers. So if you want very fast access > flags, you can reserve a register and use that. Normal booleans in C > are implemented as an int or a byte (you'd use a byte on an AVR). With > a few macros, you can get reasonably convenient bit access, although > it's not atomic (which can be a disadvantage).
The 80C51 has a Boolean processor, so can do : CPL, AND OR and AND NOT etc, that's much more clumsy on a AVR. In an C51, you can simply name a BIT, and the linker does the rest, packing them for you. The AVR cannot branch on a BIT, only Skip Thus the AVR is simpler, ( which saved them ASIC space ) but it has a cost in RAM and CODE size.
>> In the 80C51 you can also map BITs onto BYTES in the BIT ADDRESSABLE >> space, for very efficent code. > > I can't think off hand of any advantage of bit addressability like this > unless you are dealing with an array of bits, or pointers to bits, > except perhaps for atomic access.
We have done this, for PulseDensity DACs, in a high priority interrupt. Somewhat specialised, but true embedded uC stuff. This mapping allows you to run/test counters, with no CY or ACC impact at all.
> >> The 80C51 also has Direct Memory opcodes: Go outside the registers, >> and the AVR suddenly suffers from 'pointer thrashing', and is >> NOT interrupt friendly - so any code that is not large arrays, but >> has a smattering of named variables ( gee, most embedded code, >> actually ) has the 80C51 well in front. > > > I'm not sure why you would want to access your named variables through > pointers, except for arrays, or very occasionally when passing pointers > to functions. Unless, of course, you are using an architecture which > does not have direct access to more than a small part of its memory > space, and is forced to use pointers to access fixed-position global > data. Perhaps you haven't looked at the details of the AVR (I had not > looked at the details of the 8051 until this evening). > > The AVR can directly read or write to any fixed address in its RAM or IO > space, without going through pointers. It has no way to do > read-modify-write atomically to memory.
As an example, try INC of a DATA memory location : ... or memory-memory moves, or even Load SFR,#Constant INC Direct in a 80C51 [2 bytes] ( or INC @ Ri via pointer ) or DJNZ DIRECT looping.... On an AVR, that's 2 x 32 bit opcodes to READ/WRITE and one 16 bit one to INC. So yes, you can _do_ it on an AVR, but in many more cycles and bytes of code, and you need a working register....
> I'd happily agree that the AVR > should have had four full pointers, instead of two and a half (one of > the pointers does not support all addressing modes), <snip>
.. and a register frame pointer would have been really nice - then the efficent register stuff, (which the AVR does well), could work into the RAM. The Z8 does this. The 196 extended the register array. IIRC the Sparc (?) had a register frame scheme, that allowed split usage - some for parameters, and some for local variables. Even the lowly 8048 could INC/DEC/XCH/DJNZ at the pointers, and it could add/subtract/or/xor/and into the ACC from at a pointer as well. The AVR can only load and store data memory....
>> Some AVR devices do appeal, but it is more in spite of the core, than >> because of it. >> The new Tiny2313 and Tiny25/45/85 features like Wide Vcc, on chip >> OSC, and reasonable peripherals with on chip debug, all make for >> nice little devices. >> >> Of course, the new LP213/214/216 devices from Atmel, have 1 cycle >> 80C51 cores, and tiny packages, nearly as Wide Vcc, and on chip debug >> - so >> you get a good core _and_ good peripherals :) >> >> Philips, STC, Coreriver, SiLabs also have small package 80C51's >> >> -jg >> > > And do these small 8051 chips still have the "wonderful" system of I/O > pins that can't drive high? I know that is not part of the 8051 cpu > core, but it's part of the baggage that backwards compatibility brings.
Yes, thankfully :), most new ones have 4 options per port bit : Quasi/CMOS/IP/OpenDrain.
> I suppose the 8051 is a reasonable enough core for very small micros and > simple tasks, but I would not like to have to use it for anything > sizeable (unless combining a C compiler, a fast clock speed, and plenty > of memory, and just try to forget the architecture inefficiencies). It's > perhaps not the worst choice (the COP8 and PIC16 vie for that position, > out of the micros I've used). But I'm still left with the very clear > position that the AVR can do almost anything the 8051 can do, and can do > much more besides. > > Of course, if you look at the msp430, you see a cpu that's even better > to work with.
.. and the ARMs - if you need > 64K code, they pretty much self-select, and their peripherals tend to have better thruput, so even an 8K(!) ARM might be chosen - not for the core, but for the peripherals. That's an advantage of multi-sourced cores :) On the subject of Multisourced: I see today mention of an Async 80C51 core that needs 89pJ per instruction, and gives very low EMC. -jg
Grant Edwards wrote:
> On 2006-02-08, David Brown <david@westcontrol.removethisbit.com> wrote: >> The msp430 is probably the best example of a C-friendly cpu. > > Agreed. Though it's missing a few key features of the pdp11 > (one of the C-friendliest architectures I've seen), it has a > very pdp11-like feel to it.
You do realize that C was designed to do 'high level' system work specifically for the PDP-11. Many of the C constructs map directly into one PDP-11 instruction, such as d[i++] = s[j++] See the old Kernigan and Ritchie papers. -- Pat
"Ian Bell" <ruffrecords@yahoo.com> wrote in message 
news:dscsjv$u6l$2@slavica.ukpost.com...
> diggerdo wrote: >> >> I've used the 8051 for years, but it is dated. I've used the PICS too, >> arrg! The 8051 was a great microcontroller in its time. However, the new >> AVR >> is very pointer friendly, instruction set designed to be optimum with C, >> highly scalable FLASH (4K-256K), fair amount of on board RAM, EE, and >> flexible peripherials. >> > > Here we go again, the tail wagging the dog. A micro 'designed' to use C is > not a recommendation its a good reason not to use it.
Why? Would you prefer to use a micro that forces a C compiler to generate inefficent wasteful assembly code? Op codes that are friendly to C are certainly useful in assembly. Justifying a processor as being efficient just for assembly is nonsense today. For fast development C blows away assembly. Assembly has a place in limited applications; rare time critical code, high volume cost sensitive production.

Memfault State of IoT Report