On a slightly related note, chances are good anyone reading this has an 8051 within a few meters of them - they're close to omnipresent in USB chips, particularly hubs, storage bridges and keyboards / mice. The architecture is equally atrocious as the 6502.
btw: a good indicator is GCC support - AVR, also an 8-bit µC - is perfectly well supported by GCC. 8051 and 6502, you need something like SDCC [http://sdcc.sourceforge.net/]
- internal CPU registers are 8 bits, no more, no less and you only have 3 of them (5 if you count the stack pointer and processor status register).
- fixed 8-bit stack pointer so things like automatic variables and pass-by-value can't take up a lot of space.
- things like "access memory location Z + contents of register A + this offset" aren't possible without a lot of instructions.
- no hardware divide or multiply.
Many CPUs have instructions that map neatly to C operations, but not 6502. With enough instructions C is hostable by any CPU (e.g. ZPU) but a lot of work is needed to do that on the 6502 and the real question is - will it fit in 16K, 32K, as most 6502 CPUs only have 16 address lines - meaning they only see 64K of addresses at once. Mechanisms exist to extend that but they are platform specific.
IMHO Z80 is better in this regard with it's 16-bit stack pointer and combinable index registers.
> - fixed 8-bit stack pointer so things like automatic variables and pass-by-value can't take up a lot of space.
Also, the stack isn't addressable. The only stack operations the CPU natively supports are push and pop. If you want to access values anywhere else on the stack (say, if you're trying to spill a couple of local variables to the stack), you're going to have a bad time.
No, the stack is in the next page up ($0100 - $01ff). While it's accessible as memory, the 6502 doesn't provide any addressing modes specific to this page; accessing it involves multiple instructions, and requires the use of the X register as a temporary.
6502 was nice only in comparison with Intel 8080/8085, but it was very limited in comparison with better architectures.
The great quality of 6502 was that it allowed a very cheap implementation, resulting in a very low price.
A very large number of computers used 6502 because it was the cheapest, not because it was better than the alternatives.
For a very large number of programmers, 6502 was the 1st CPU whose assembly language they have learned and possibly the only one, as later they have used only high-level languages, so it is fondly remembered. That does not mean that it was really good.
I also have nostalgic happy memories about my first programs, which I have entered on punched cards. That does not mean that using punched cards is preferable to modern computers.
Programming a 6502 was tedious, because you had only 8-bit operations (even Intel 8080 had 16-bit additions, which simplified a lot multiply routines and many other computations) and you had only a small number of 8-bit registers with dedicated functions.
So most or all variables of normal sizes had to be stored in memory and almost everything that would require a single instruction in modern microcontrollers, e.g. ARM, required a long sequence of instructions on 6502. (e.g. a single 32-bit integer addition would have required a dozen instructions in the best case, for statically allocated variables, but up to 20 instructions or even more when run-time address computations were also required, for dynamically-allocated variables.)
A good macroassemmbler could simplify a lot the programming on a 6502, by writing all programs with a set of macroinstructions designed to simulate a more powerful CPU.
I do not know whether good macro-assemblers existed for 6502, as in those days I have used mostly CP/M computers, which had a good macro-assembler from Microsoft, or the much more powerful Motorola 6809. I have programmed 6502 only a couple of times, at some friends who had Commodore computers, and it was weak in comparison with more recent CPUs, e.g. Zilog Z80 (which appeared one year later than 6502).
> I do not know whether good macro-assemblers existed for 6502
They certainly did. I don't know about the communities that grew around Commodore, Atari, or other 6502-based computers, but in the Apple II world, there were multiple macro assemblers available. Possibly the most famous was Merlin. As a pre-teen, I used the Mindcraft Assembler. Mindcraft even sold another product called Macrosoft, which was a macro library for their assembler that tried to combine the speed of assembly language with a BASIC-like syntax. The major downside, compared to both hand-coded assembly and Applesoft BASIC (which was stored in a pre-tokenized binary format), was the size of the executable.
Edit: Speaking of simulating a more powerful CPU, Steve Wozniak implemented the SWEET16 [1] bytecode interpreter as part of his original Apple II ROM. Apple Pascal used p-code. And a more recent bytecode interpreter for the Apple II is PLASMA [2].
6502 is nice to program in assembler. For a compiler it is an atrocious platform to support. The limited stack, the 8 bit limit, the zero page idiosyncrasies, the
page crossing bugs (some corrected in 65C02), etc.
Z80, while also full of adhoc-isms is a much more pleasant target for a C compiler, only just for its 16 bit register and stack.
One thing to keep in mind while programming AVR in C is that it still is small-ish MCU with different address spaces. This means that if you do not use correct compiler-specific type annotations for read-only data these will get copied into RAM on startup (both avr-libc and arduino contain some macrology that catches the obvious cases like some string constants, but you still need to keep this in mind).
Newer parts actually do have flash mapped into memory address space accessible through normal LD instruction, though I'm not sure if avr-libc moves constants into it automatically or still needs that PROGMEM/__flash annotation.
Hope RISC-V will displace 8051 over time. It's such an absurd thing to extend this architecture in myriad non-interoperable (although backwards-compatible with OG 8051) ways. And don't forget about the XRAM nonsense. Yuck.
AVR was designed much later with a C compiler in mind. 8051 while atrocious is much cheaper to license and fab than an ARM Cortex-M. These applications will probably go RISC-V in near future.
On the real low end PADAUK is king, at under 3 cent retail. They don't even bother with a C compiler and instead have a macro assembler on steroids called Mini-C (there is also sdcc but I never used that having needed every last 13 but word of ROM). Programming these, with 64 bytes of RAM, is strangely refreshing - no fancy abstractions, microsecond-precise instruction timings.
the 6502 has a single 16-bit address space with some parts (zero page, stack) addressable by means other than full 16-bit addresses.
the 8051 has 16-bit read-only code space, 16-bit read/write external memory space, and 8-bit internal memory space, except half of it is special: if you use indirect access (address in an 8-bit register), you get memory. but if you encode that same address literally in an instruction, you get a peripheral register.
btw: a good indicator is GCC support - AVR, also an 8-bit µC - is perfectly well supported by GCC. 8051 and 6502, you need something like SDCC [http://sdcc.sourceforge.net/]