I don't think programming in assembly language for modern architectures (x86-64 as implemented by the latest Intel/AMD chips) will ever be as fun as doing so for microcontrollers or embedded devices, because it's almost impossible to keep all of their inner workings in your head.

A 6502 is a really stupidly simple machine. If you've had previous exposure to programming in assembly, you can get a pretty complete understanding of the machine in an afternoon. It doesn't take very much experience to get to the point where you can take a look at a subroutine and figure out exactly how many cycles it will take to execute, on which exact cycle this I/O operation will occur, etc.

I've tried that approach with x86 (not even x86-64!) manuals before, and I ran away screaming. I don't know how long it would take me just to be aware of all of those instructions, let alone be able to even roughly estimate their execution time across the hundreds of differing x86(-64) implementations! Just peeking at Agner Fog's optimization manuals[1], I remember that some instructions can take 20~ cycles on a Pentium 4 (probably the oldest x86 processor still in common public use), and 1~2 cycles on anything past the Core series. Some instructions an Intel Atom will choke to death upon. With some similar pairs of instructions, one of the two is faster on every machine except the Atoms! How am I supposed to reconcile all of these discrepancies and write something that is anywhere near optimal for a large portion of the x86 userbase?

You can make the argument that you don't need to know all of the x86 instructions to write a decent assembly language program. That's probably true. Yet, part of the fun of working on a simpler system is that you can write a piece of code and know that it is very close to optimal -- maybe you could rewrite the whole thing and save a few bytes or a few cycles, but you still feel like you've put your repertoire of tricks to good use and made something that you would be feel reasonably comfortable showing off to the experts. If I can't get that feeling on x86, only getting to beat a compiler that has to work within the limitations of its language, and producing a result where no one really cares (and can't even tell!) that I shaved a few cycles here and there, there is little point, and not as much fun.

If you want to have fun writing assembly language, pick a processor microarchitecture that you can comfortably fit in your head, and an environment where you'll only have to deal with one or two implementations of that microarchitecture. Intel and AMD, in the (very well justified) interest of developing the most powerful machines on the market, have turned x86 into something that is not fun to write assembly for, and not possible to fit in your head (at least, without serious commitment on the level of "I am going to make a career out being the x86 guy/gal"). Don't bother! Don't even bother writing something for a platform where you need libraries to print something to the screen, or convert a line of text into a number. Find a platform that lets you turn lights on and off by poking addresses, and go from there.

In the mean time, I'm not at all surprised that no one tries to write optimal software for x86 PCs. No user will feel the effort you put into shaving cycles off of anything but the tightest loops and most critical of paths, and there isn't even a scene of ``expert programmers'' comparable to the ones currently around the 6502 or 68000 to appreciate what you do. The best you get is a mention on Hacker News and a few wistful comments about the good ol' days.

</stupid rant>

[1] http://www.agner.org/optimize/

Lots of very useful information here, even if you don't ever want to attempt programming in x86 assembly.

EDIT: The funny thing about all this is that even ``back in the day,'' a 6502 was fast enough that you could get away with all kinds of inefficiencies. You find a game that blew your mind as a kid and stuff it into a debugging emulator, trying to understand bits and pieces of how the engine works, and find yourself laughing at trivial inefficiencies all over the place, even in critical loops! Yet, even with all the hundreds or thousands of bytes and cycles wasted here and there, then end result still feels plenty ``fast.''