Mupen64Plus


craigix said:
Ari64, what hardware do you currently have?

Well he clearly doesn't have a Pandora dev board, and I will agree with the rest that he should have one.
 
Last edited by a moderator:
BackAssward said:
Well he clearly doesn't have a Pandora dev board, and I will agree with the rest that he should have one.

Well he look like he have a BeagleBoard allready set up. So if he don't express a need for a pandora devboard, then he just don't need one :)
I think that's why craigx asked this...

EDIT: I forgot : THANKS ari ;-)
 
Last edited by a moderator:
Nice to hear that Pickle :) Ari64+Pickle='Awesome youtube video soon'!

and thanks Ari :) What a way to reveal yourself to the community!
 
Trying not to get ahead of myself, but this is exciting stuff.

Thanks for your hard work Ari.
 
Ari64 said:
That doesn't happen. Once the page is marked dirty, it stays that way, and jumps to this block go thru jump_dirty and verify_code, which checks for modifications before it executes that block. The reason for this is mainly because some programs touch the first page of memory, and we don't want to recompile the interrupt handler at 0x80000180 again and again.

This sounds like it could have bad results for anything that heavily overlays code into/out of RAM. You could end up with a lot of blocks that are being verified constantly. Hopefully this is not a scenario that happens on any actual games. It would seem kind of strange for games to do this when they can execute from ROM, to the best of my knowledge (and let the cache deal with the even worse access times).

Ari64 said:
The idle loop in Super Mario 64 looks like this:
Code:
   * 80246dd8: BEQ r0,r0,80246dd8
     80246ddc: SLL r0,r0,0
and gets compiled as this:
Code:
   0x0702ed40:     and     r10, r10, #3    ; 0x3
   0x0702ed44:     b       0x702ed48
   0x0702ed48:     ldr     r0, [pc, #32]   ; 0x702ed70
   0x0702ed4c:     str     r0, [r11, #80]
   0x0702ed50:     bl      0x80b3194 <cc_interrupt>
   0x0702ed54:     b       0x702ed40
Note: r11+80 is &pcaddr, it writes 0x80246dd8.

Yes, there's an excess branch in there. Usually there would be code in between, so I didn't optimize the trivial case.

EDIT: Oops, I looked again and saw you are cycle counting over r10 and appear to be checking for interrupts unconditionally having detected the idle loop. I think. But I'm not 100% sure so..

- Is the code inbetween referring to the the delay slot? It seems to me that nops in the delay slot would be common enough to optimize. If it's for the beq on the same registers then I can see this not being worth optimizing for unless this is a common idiom. I wonder why the game used that in the first place.
- You store the PC for the sake of being able to cause an interrupt, but since that interrupt usually won't be happening then it's worthwhile for you to try to avoid this. One thing that you can do is store the PCs somewhere else and have a mapping from translated PC to emulated PC somewhere. A hash table will work, of course - a scheme that I'd like to use is to have them built in descending order from the top of the translation cache which can be binary searched since they'd be added in sorted order. Of course a small first level hash would accelerate that too. I assume this wouldn't be an option for you because of how you've segmented the translation cache. Another method, one that I use in gpSP on ARM, is to store the PC after the bl to the event update routine (in your case, cc_interrupt) then return to pc + 4. I don't recall exactly if this works with Cortex-A8's return stack so it might not be a good option, but for any potential ARM9 ports it could be.
- If you aren't already (I'm assuming this because of your use of r11) then you should try merging persistent global store with the stack, especially since most of your memory executions are inlined already. You will of course need to branch to ASM functions to handle anything that will want the stack. If you need a dynamically indexed table and a statically indexed one I recommend storing it such that the static comes first then the dynamic, and keeping the stack pointer pointing to the dynamic portion. Then you can index it directly with a register, index the static part with a negative immediate offset, and get to a stack by decrementing (then incrementing) beneath this. This could potentially free a register, anyway.

Any chance I can get you on AIM sometime?
 
Last edited by a moderator:
My dream of (possibly) playing Turok: Dinosaur Hunter on-the-go seems to be this much closer to realization now. Kudos to your dedication, Ari64!
 
Oh my god, this is sooo sweet, I just jizzed my pants (sorry, had to do that...)

thanks a million Ari :lol:
 
Last edited by a moderator:
foxblock said:
Oh my god, this is sooo sweet, I just jizzed my pants (sorry, had to do that...)

thanks a million Ari :lol:

That's the best video I've ever seen, this week.
 
Last edited by a moderator:
Exophase said:
Ari64 said:
To schedule instructions this way would require an instruction-reordering pass after code generation. This could be done but would take some work. I guess the Cortex-A9 CPU will do this in hardware. It might be almost as effective to simply change the register allocation so that registers are allocated/loaded one instruction before they are needed.

Right, it's not the easiest thing in the world to do. But you'd be able to exploit parallelism a little more in general. If you can manage the register space for that then it should at least help a little, yeah.
I went ahead and tried this, loading registers before the previous instruction to avoid the load-use penalty. Generally it reduced the code density by requiring additional registers to be loaded before branches. If I avoid reordering loads near branch targets, then it looks like it is possible to get a small performance improvement without increasing code size.
 
Last edited by a moderator:
craigix said:
Ari64, what hardware do you currently have?
A beagleboard. Please send my Pandora ASAP :)
 
Last edited by a moderator:
RenegadeChic said:
Ari64 said:
craigix said:
Ari64, what hardware do you currently have?
A beagleboard. Please send my Pandora ASAP :)
audacious! i like it
I think he just means he ordered one like the rest of us and wants to get it as soon as possible...

...like the rest of us.

Anyway, congratulations on your great work, Ari64. :)
 
Last edited by a moderator:
Exophase said:
Ari64 said:
That doesn't happen. Once the page is marked dirty, it stays that way, and jumps to this block go thru jump_dirty and verify_code, which checks for modifications before it executes that block. The reason for this is mainly because some programs touch the first page of memory, and we don't want to recompile the interrupt handler at 0x80000180 again and again.

This sounds like it could have bad results for anything that heavily overlays code into/out of RAM. You could end up with a lot of blocks that are being verified constantly. Hopefully this is not a scenario that happens on any actual games. It would seem kind of strange for games to do this when they can execute from ROM, to the best of my knowledge (and let the cache deal with the even worse access times).
You think RDRAM is slow and you want to read from ROM? The N64 cartridge interface is only a few MHz, not much faster than SNES. I don't remember the exact timing, there were timing diagrams on Valery Pudov's website at one time, but I can't find them now.

BTW The original mupen64plus used the opposite strategy. Instead of checking the code blocks for changes, it checked every write to a code page to see if hit a compiled instruction. So basically it trapped a lot of writes.
 
Last edited by a moderator:
Back
Top