Ugh, function pointers per hardware address.
I've found that the two driving factors for program design which take priority when i'm designing systems tend to be:
1) Elegance/simplicity in implementation
2) Reflection of the real world
1) You want your solutions to be elegant, simple, lean, and robust. This way, they can be easily optimized, easily replaced/rewritten, and easily representative of the underlying algorithms. Programmers are notorious for incorrectly guessing where performance bottlenecks will be. Compilers are smarter when you think they are naive, and vice versa. Spending time writing clever algorithms usually lands you in a world of thankless debugging in the future, when you could have replaced a bad algorithm with one tuned for the problem at hand.
2) When you mimic the real world, you isolate the problem domain, and make it easier to achieve goal #1. If the NES easily addresses pages of N bytes, build your architecture around that. If communication between I/O devices shares one bus, create a Bus architecture, that even if it seems like an extra layer of code and abstraction, will more naturally allow you to structure your execution and code architecture like the Real Thing.
Plus, if you optimize for a certain architecture, some system behavior, when the next generation comes out and all our assumptions are invalid, you will be locked into your previous faulty assumptions.
But that's just a rant. If you're optimizing for something and it works good-like, just ignore me.