> Once the PC goes past $FFFF, it rolls over to $0000 without changing the bank.
I had forgotten about that! Yeah, that's horrendous.
> The only new registers are the code bank and data bank registers
There's the relocatable DP register, which you could use as a frame pointer (I've written code that does this). It's still quite awkward though.
> I think the code bank register can't even be directly set. You have to do a 24-bit JMP or JSR, and that automatically changes the bank.
To be fair that's how x86 works too, right? You have to do a far jump or far call to switch CS. (Also you could push addresses on the stack and do a far return on both 65816 and x86.)
> It's a particularly hard CPU to generate code for. There's a commercial, free to use for private use C compiler, but most people use assembler.
This is absolutely true. 6502 derivatives are almost uniquely hostile to C-like languages—witness all the failed attempts at porting LLVM to them—and the 65816 is no exception. I'm pretty sure that in an alternate world where 6502-based microcomputers had become dominant, the classic 6502 ISA would have quickly become relegated to some sort of legacy emulation mode, and the "normal" ISA would be nothing like it, unlike the relatively modest extensions that the 286 and 386 made to the 8086 ISA.