tepples wrote:
laughy wrote:
Adding calls to MMU code on every indirect access would greatly affect the speed of the translator, although that definately is a viable option.
Correctness before speed.
Quote:
Wouldn't it still be more efficient to have the interpreter always execute a block first, and then it can log if an indirect address goes to a I/O register?
Quote:
He ends blocks on BRANCHES!!! This leaves most blocks EXTREMELY small (3-4 instructions?) and you spend most of your time jumping into your translator to translate small blocks instead of actually running code. I would greatly suggest to this guy to pick a JMP, JSR, etc. instruction as ends to blocks. Picking a branch as ends of blocks simplifies things though.
Again, correctness before speed. Simplicity breeds correctness.
If correctness was the priority, one wouldn't be doing a translator in the first place! Hehe. However I agree with you - getting it working should be a priority, but at the end of the paper he claims it wasn't really worth the work: if he had worked a bit harder in the speed area he may have seen the fruits of his labor.
Tepples wrote:
And what happens if the same instruction writes to RAM or to I/O depending on what comes before the block?
It's been done.
Nessie wrote:
But it's impossible to determine whether the indirect access will ever affect an I/O register or not. If it's difficult to insert a call to a WriteHandler, perhaps it's simpler to just abandon translation of all blocks with indirect access. As blargg pointed out, they're not very common anyway.
You guys bring up a good issue. Normally this would work if the interpreter could assume an indirect instruction would always write to a I/O register OR always write to RAM. I can see three possibilities:
1) Execute a block multiple times in the interpreter looking for this special case (maybe in 10 times, a morphing indirect instruction will show its ugly head). - will possibly fail if we're unlucky
2) Keep a list of games which do this - abandon translations which use indirect addressing in these games, or use method call approach
3) Always use method call approach
Abanonding blocks can be fatal - I've seen the same blocks can be executed hundreds of thousands of times - if the indirect access is in a tight loop its a big loss. If I was gong to do this I'd probably go in the above in order, seeing which one worked out.
Nessie wrote:
Yeah, I think loops is where we would see the biggest performance gain, but that's lost when ending blocks on branches.
The size of the block has no affect on the speed of looping, but you bring up a good point in that the small block problem won't be as visible one is tightly looping. That said, if he isn't using the block linking optimization,
tight loops are almost as slow as using an interpreter anyway. Notice how he said what made his emulator playable in many cases was when he detected tight loops and "skipped" them by just executing the interrupt the loop was trying to detect. I can see why he would need to do this.
Thanks for your comments/input guys. Let me know if I can better clear anything up.