Mupen64Plus


Exophase said:
Ari64 said:
There is a preferred mapping, which is r1->r1, r2->r2...r7->r7, r8->r0, r9->r1, etc. This helps with branches, as things are usually in the same registers, however if it runs out of registers, then it will use whatever registers are available.

Okay, so it's a kind of mix between static and dynamic. But I was referring to dynamic between blocks.
How would that work?

Exophase said:
Ari64 said:
I hadn't seriously considered it, but it would be possible. The page size is 4K because that's the native page size on the r4300, although almost no N64 games actually use the MMU. (And if any do use the MMU, they probably won't work, since I haven't tested this.)

Would at least cut down the generated code size a bit. I'm always nervous about blowing away L1 icache with huge translated code blocks. Past a certain amount I'd move things to a function (probably for a store like that).
This would probably result in a gain in speed. I'd need to write a signal 11 handler tho, and this would make debugging more complicated, so this isn't one of the first things I'd want to optimize.
 
Last edited by a moderator:
MonkeyChops said:
ari, if you don't mind me asking, how long have you been working on this project?

I think that most of us here were hoping that someone was lurking behind the scenes with a n64 project. Its awesome that you made that dream come true. You sir, are my hero. Thank you.
Around 4-5 months. I didn't want to say anything until I was sure that this would actually work, otherwise it would have just been speculation about something that might never be finished.
 
Last edited by a moderator:
Ari64 said:
How would that work?

Sorry, I can't give you any clear ideas because I haven't spec'd something like this. But with a "deep" recursive recompiler you can translate blocks linked to before translating the current block, then register allocate weighted around that. Anything you can do to relieve pressure around block transitions.. I'm sure there are a lot of schemes, but any of them sound like they'd be fairly complex.

Exophase said:
This would probably result in a gain in speed. I'd need to write a signal 11 handler tho, and this would make debugging more complicated, so this isn't one of the first things I'd want to optimize.

*nod*

Said handler would also have to decipher the instruction. Blegh. And it wouldn't be hard for a game to run it into the ground (although it's not really hard for one now) with data accesses in the page. You'd probably have to track and patch the instruction if it gets out of hand.

I hope you're looking forward to being a big time celebrity around here, at any rate ;D Good job keeping quiet about it this long. I much prefer it when people make a substantial first showing instead of generating a ton of hype that they usually end up being incapable of delivering on.
 
Last edited by a moderator:
Ari64 said:
Around 4-5 months. I didn't want to say anything until I was sure that this would actually work, otherwise it would have just been speculation about something that might never be finished.
good lord! the way you just casually posted this topic it was like you had just had a quick look over it. major MAJOR props for all your hard work! i think you may possibly be on the way to something that pushes the interest in the pandora massively! killer app much! i bow my head to you and hope it all bears fruit
 
Last edited by a moderator:
Exophase said:
By the way, how many instructions per frame are we looking at here? I take it you're doing a fixed number of cycles per instruction and it's probably something like 2 90MHz cycles, so that'd mean 45 million per second? How complex are the idle loops? Can you give any examples of what they're like?
The r4300i has 8K of cache, and spends most of its time waiting on the memory. To make up for this, most N64 emulators run the emulated CPU at a much slower rate, usually 1/5 (ie 18.75 MIPS). This was in the original Mupen64plus, and I didn't change it.

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.
 
Last edited by a moderator:
zodttd said:
Hi Ari64!

Thank you so much for this! Amazing work! I'm looking through the sources as we speak.

I'm very much looking forward to porting this to the Apple iPhone 3gs. My port's source will be available on my github.com/zodttd.

You have no clue how happy you just made me! :)

Thanks again,
ZodTTD
BTW, it uses r9. :)

I also have no idea how the iphone OS will like the memory mapping hacks I did, like moving the text segment above the dynarec buffer, and mapping the ram at 0x80000000.
 
Last edited by a moderator:
I've been reading this thread with great interest, and felt it appropriate to pop in and say thankyou to you, Ari64. Congratulations on your work so far. :D
 
Exophase said:
Ari64 said:
How would that work?

Sorry, I can't give you any clear ideas because I haven't spec'd something like this. But with a "deep" recursive recompiler you can translate blocks linked to before translating the current block, then register allocate weighted around that. Anything you can do to relieve pressure around block transitions.. I'm sure there are a lot of schemes, but any of them sound like they'd be fairly complex.
It does this sort of weighted register allocation, but only within the same block. The deeper your recursion goes, the more bogus crap you have to deal with (data that's not code).

It should probably try to follow loops though. As you can see in the example posted before, this lack of foresight results in the needless writeback of r10 (r2).

Exophase said:
This would probably result in a gain in speed. I'd need to write a signal 11 handler tho, and this would make debugging more complicated, so this isn't one of the first things I'd want to optimize.

*nod*

Said handler would also have to decipher the instruction. Blegh. And it wouldn't be hard for a game to run it into the ground (although it's not really hard for one now) with data accesses in the page. You'd probably have to track and patch the instruction if it gets out of hand.
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.

The only way to really run it into the ground is with actual self-modifying code, something I haven't seen any examples of.

Exophase said:
I hope you're looking forward to being a big time celebrity around here, at any rate ;D Good job keeping quiet about it this long. I much prefer it when people make a substantial first showing instead of generating a ton of hype that they usually end up being incapable of delivering on.
;)
 
Last edited by a moderator:
I don't want to derail the thread with iPhone specifics so I'll keep things brief. :)

R9 can be used if it is saved and restored properly around function calls. I believe R9 is used for Thread Local Storage. Though it does obviously reduce performance by some degree with needing to do so.

The tricky part will be the memory mapping depending how it's done. Though on the iPhone there is access to mmap, etc., as it's BSD based.

Thanks again. Love the entrance you made. ;)
 
Ah yeah, I didn't even notice the 0x800000000 RAM part. That's some messed up stuff you've got going on there ;p Nice edge it gives, no need for an offset register.

Emulating 18.75MIPS is quite a low number - is that really good enough for a wide variety of games? I believe Daedalus and Project 64 default at 2 cycles per instruction, rather than 5. I recall the RDRAM access time being in the neighborhood of 64 cycles to load a word from memory. If an extra word takes 1 cycle each (optimistic, but with the RDRAM bandwidth should be possible) then that'd mean something like 72 cycles for an icache load, or 9 per instruction.. wow, this was really bad. The icache was 16KB, but only direct mapped.

I guess you could say the memory on N64 sucked at every level. The L1 cache (especially dcache) on the CPU would be prone to capacity misses and the dcache's line size is too small (not helping to mitigate latency), the RDRAM was ridiculously high latency, and both the RSP and RDP had way too little scratchpad. SGI really should have given the CPU an L2 cache and multipled the amount of RSP data/code RAM and RDP texture RAM by at least 4x each. The latter especially - how do you afford 24KB of cache on a CPU but limit the coprocessors to 8KB and 4KB of SRAM respectively? That's an awful lot like the Jaguar, that was a good three years older. Shame on you, Nintendo.

Still, most tight loops should be sitting in icache and dcache will hopefully at least let you hold on to the stack for a while. It'd be nice to have a more timing accurate emulator on PC that can at least give a better ballpark of exactly what games are using.

Mario 64's idle loop is extremely simple and certainly you can detect these and get out of the instruction dispatch early. It looks like Mario 64 doesn't even need those 18.75 MIPS.. which is pretty humorous. Sounds like some typical N64 games aren't even executing more instructions than the more demanding GBA games. And I know that you don't have to emulate as many low-interval events for N64 games.
 
Ari64 said:
I have rewritten the dynamic recompiler for Mupen64plus to generate ARM code. This will run on OpenPandora, TouchBook, and BeagleBoard.

I love you.
 
Last edited by a moderator:
Welcome Ari64 and thank you for taking on n64 so early in the game. :D

Good luck with this project, can't wait to see Mario 64 been displayed " It's a me Mario! " come up on all our Pandoras one day :)
 
joshwaan2k said:
Welcome Ari64 and thank you for taking on n64 so early in the game. :D

Good luck with this project, can't wait to see Mario 64 been displayed " It's a me Mario! " come up on all our Pandoras one day :)
Launching Mario 64 does work, although the title screen renders quite slowly at present due to the OpenGL issues.


Exophase said:
Mario 64's idle loop is extremely simple and certainly you can detect these and get out of the instruction dispatch early. It looks like Mario 64 doesn't even need those 18.75 MIPS.. which is pretty humorous. Sounds like some typical N64 games aren't even executing more instructions than the more demanding GBA games.
LOL, guess why it runs so well on PSP ;)
 
Last edited by a moderator:
Ari64, do you think that its possible to see full speed emulator of zelda Oot with sound on pandora? I mean sometime at the future... It could be soo sweet...
Do you have a pandora dev board os something like that? have you already preoder Pandora?
 
guizm said:
Ari64, do you think that its possible to see full speed emulator of zelda Oot with sound on pandora? I mean sometime at the future... It could be soo sweet...
Do you have a pandora dev board os something like that? have you already preoder Pandora?

If not, Craig has to send him one as soon as possible.
 
Last edited by a moderator:
I must also join in with the clapping of hands. I was beginning to get worried that nobody would attempt to give us a nice portable N64 experience! ;)
All the best with this, N64 was a great system even if it were overlooked by many due to not letting go of the cartridge format.

Also I love skimming all the technobabble even if I can't follow most of it... it is interesting. :)
 
I said I'd post this when N64 happened.

2j4tzi8.gif
 
Back
Top