...so I wrote this self-hosting compiler for the 6502 and Z80:
http://cowlark.com/cowgol/
I say self-hosting, but on a 64kB BBC Micro second processor with floppy disk it takes about seven minutes to compile Hello World, so I haven't bothered to actually recompile the whole toolchain. (The overwhelming majority of of that time is spent doing disk I/O, as there's way too much state to keep in RAM. The compiler is an eight-pass behemoth.)
Here's an accelerated screencast of the thing in action: https://www.youtube.com/watch?v=epTQPSi3IyQ
The language itself is a simple strongly-typed fully compiled thing with a syntax based on Ada, supporting nice stuff like nested subroutines and so on. It has native 8-bit types (unlike C). Its main claim to being interesting is that it statically allocates all variables, using a simple but effective algorithm to walk the call tree and assign multiple variables to the same address if they're not going to be used at the same time. It's super effective. (This is Wheeler's solution 1.) This feature made the entire project possible, because it allowed me to do without stack frames completely. Trying to access the stack on either the 6502 or Z80 is an utter disaster.
The 6502 is a _bizarre_ thing to generate code for. 8-bit code is fine, but 16-bit and above is painful --- efficient maths is really hard. I kept finding the generated code breaking down into tiny microloops because when doing arithmetic with 16-bit values it can actually be shorter to use a loop than to inline it (in certain circumstances). The instruction set is orthogonal, except when it isn't; there's no LDA zpg,Y for example, but there's a LDX zpg,Y. Things like moving values from one memory location to another are so expensive that the setup cost in using helper functions frequently outweighs the benefit.
But in general, once you get your head around it and accept that it simply cannot do things like 16-bit signed comparisons in a fashion which won't make you cringe, it's not too bad. Index registers are great, as is zero page indirection (at least for 8-bit offsets). It's fast, taking a few cycles per instruction. It's also fairly sensible: there's frequently only one sane way to do things.
The Z80 drove me nuts, though. It's unbelievably unorthogonal. (You can only do 8-bit direct memory accesses via A --- B, C, D, E, H or L cannot be directly read from or written to memory!) It's slow --- the non-8080 instructions are so painfully slow (ld ix, (abs) is 20 cycles!) that they're only barely worth it. The 16-bit stuff doesn't help nearly as much as you'd think, either; you can only do adds and subtractions, with limited registers, and there's no carry so they're no use so 32 bit operations have to be done using the 8 bit instructions anyway. I did find the resulting code density to be better than the 6502, but not that much.
I'm really looking forward to doing a 6809 port one day...