Mupen64Plus


Thanks Craig and Pickle, I will probably wait for the one with controls though. Kind of hard to play without!

Hopefully I can be useful for testing and suggestions in the future, they call me "eagle eye".
 
http://jayfoxrox.bplaced.net/content/pandora/testing/PPSP-Input/

if this plugin doesn't work just contact me and I'll see what I can do, but it worked fine with previous versions I guess (however, didn't really have a chance to test it)

If that plugin doesn't work you can use one which works with normal joystick devices and use this "driver" to make a normal joystick device from the pandora controls:

http://jayfoxrox.bplaced.net/pandora/public/Pandora-Input-Drivers/ ("make pandora-joystick-driver")

However, both projects were just thrown together, don't expect too much ;)

//Edit: there is an array overflow in the ppsp-input driver, I suggest to avoid this driver until I fixed it.
//Edit: The binary in /testing/PPSP-Input/ was updated, and the source is now in /public/PPSP-Input/. The whole plugin source is dirty tho, but all mapping should happen in map.c now. However, I still recommend to use the joystick driver to turn the Pandora into a normal joystick device which are largely supported by games and plugins rather than changing the input code of the software.
 
Ari64 said:
notaz said:
I have some SH2 code where conditional branch lands in delay slot of other conditional branch, and this messes up my recompiler. Do you handle such case on MIPS?
Yeah, it messes up the recompiler.

Right now I leave the branch unresolved in cases like this, so when the branch is taken, it jumps back to the recompiler and recompiles that part. It ought to be possible to just compile that one instruction again as part of the branch that jumps to it, though I'd need to make sure the register mapping was correct, and adjust the cycle count to account for it. Kind of a pain in the butt, so I haven't done it yet.
i'm not sure to understand... are both of you saying that you had in SHx/MIPS code a branch instruction into a delay slot of another branch instruction like "blt 0f; b 1f" ??? are you sure you are in a valid code ? if processor doesn't complain, i will expect for the second branch instruction to be ignored.

EDIT: the only case i can see to occur is if you are ignoring a "nop" instruction in the delay slot of the first branch instruction BEFORE or DURING recompiling the branch, and wrongly considering the next instruction to be in the delay slot. But i'm sure you are not doing such a foolish thing :p .
 
Last edited by a moderator:
hlide said:
i'm not sure to understand... are both of you saying that you had in SHx/MIPS code a branch instruction into a delay slot of another branch instruction like "blt 0f; b 1f" ??? are you sure you are in a valid code ? if processor doesn't complain, i will expect for the second branch instruction to be ignored.
nope, what we meant is this:
Code:
  blt 0f
  nop
  nop
  bgtz whatever
0:add r1,r2,r3
  ...
 
Last edited by a moderator:
notaz said:
hlide said:
i'm not sure to understand... are both of you saying that you had in SHx/MIPS code a branch instruction into a delay slot of another branch instruction like "blt 0f; b 1f" ??? are you sure you are in a valid code ? if processor doesn't complain, i will expect for the second branch instruction to be ignored.
nope, what we meant is this:
Code:
     blt 0f
     nop
     nop
     bgtz whatever
   0:add r1,r2,r3
     ...
ah yes ! that was what you meant by "lands". I would treat it this way :
Code:
  bb0 { nop; blt bb2; @bb1; }
  bb1 { nop; add r1, r2, r3; bgtz bb3; @bb3; }
  bb2 { add r1, r2, r3; @bb3; }
  bb3 { ... }
legend:
  • bbX - basic block (linear instructions sequence).
  • @bbX - duplicate it because register allocation differs or do a direct jump to it if no register were allocated in the delay slot.
delay slot:
  • i hypothesize you are using the trick which uses a specific register to load the register used in the conditional branch instruction just before the delay slot instruction modifies the target register when they are the same.
 
Last edited by a moderator:
hlide said:
i'm not sure to understand... are both of you saying that you had in SHx/MIPS code a branch instruction into a delay slot of another branch instruction like "blt 0f; b 1f" ??? are you sure you are in a valid code ? if processor doesn't complain, i will expect for the second branch instruction to be ignored.
Here's an example. Suppose we have the following MIPS code:

80056f38: BLEZ r3,80056f54
80056f3c: ADDIU r16,r16,1

This gets compiled as follows:
Code:
0x07466230:     add     r0, r0, #1      ; ADDIU r16,r16,1
0x07466234:     adds    r10, r10, #8    ; Cycle count
0x07466238:     bpl     0x74664d8       ; Generate interrupt if timer expired
0x0746623c:     cmp     r3, #1          ; Compare r3
0x07466240:     bge     0x746624c       ; if r3>0
0x07466244:     str     r0, [r11, #256] ; Store r16
0x07466248:     b       0x746629c       ; Jump to translated 80056f54
Note that the code is reordered so that the delay slot is before the branch.
Now suppose we have this:

80056f4c: BNE r1,r0,80056f3c
80056f50: ADDIU r17,r17,48

Well now we have a problem because it can not jump to the instruction already generated for 80056f3c, which is at 7466230, because that is followed by a branch. So that instruction needs to be recompiled, and we end up with:
Code:
0x07466278:     add     r1, r1, #48     ; ADDIU r17,r17,48
0x0746627c:     cmn     r10, #10        ; Check cycle count
0x07466280:     bpl     0x7466528       ; Generate interrupt if timer expired
0x07466284:     tst     r2, r2          ; Compare r1
0x07466288:     beq     0x7466298       ; if r1==0
0x0746628c:     add     r10, r10, #12   ; Cycle count
0x07466290:     add     r0, r0, #1      ; ADDIU r16,r16,1
0x07466294:     b       0x746624c       ; Jump to translated 80056f40
 
Last edited by a moderator:
I don't know enough to comprehend all the work you have put into this nor do I understand how it works.


If the game never enables the TLB, then we can avoid that 5% slowdown. There is also some overhead for self-modifying code detection, but this varies from game to game. Many games use the TLB only for data and not executable code.

Maybe the editors can help you find if/when the TLB will be enabled. If it can, maybe you can set Mupen to preempt and compensate?
I'm just thinking "out loud".

Rom Editor - New Levels and more
Another editor - Similar

After seeing the GE level (does more) editor could some smart cookie use the above program to edit the GE ROM to help? You can also edit the original paths set by RARE.. Just an idea.

"Release Issues:

DAM - For some strange reason, the intro block type 3 swirling camera action causes the game to crash once it tries to zoom in on Bond. Delete all of type 3 intro blocks, and the level will load normally. It is unknown why this error occurs.

There are issues in the output of paths, with slowdown. If you create a new file, path linkage will not be present and there will be massive slowdown in guard movement. You can import Sets, but this is only recommended for extreme experts. Therefore, it is HIGHLY RECOMMENDED you simply open an included solo file, use Tools -> Make Level Bare-Bones, and then the path linkages will still be included. This does not affect multiplayer.

Paths must have at least 2 preset values in a path. Statue is just weird, but should work.

Do NOT delete Rare's Paths, only delete them by using the "Delete All Paths, Keep Sets" button. If you do, your level will crash and cannot be recovered by any ordinary means.

There may be bugs, surely, and actions that do not load properly in the game. Please let me know your issues, and we will resolve them."
 
He doesn't need a program to help him find if a game enables TLB or not. The emulator can assume it won't then recompile if it does.
 
Exophase said:
He doesn't need a program to help him find if a game enables TLB or not. The emulator can assume it won't then recompile if it does.
Hey Exophase, A bit off topic but are you getting a Pandora?

Surely Temper would run like a dream on it although you would probably have to find a way to slow it down to fullspeed :p . It would work much nicer than the other PC-engine emus out as I think yours is the only one to run Blazing Lazers past the first boss.
 
Last edited by a moderator:
DaveC said:
Hey Exophase, A bit off topic but are you getting a Pandora?

Surely Temper would run like a dream on it although you would probably have to find a way to slow it down to fullspeed :p . It would work much nicer than the other PC-engine emus out as I think yours is the only one to run Blazing Lazers past the first boss.

I'm not on the preorder list, so I'll only get one if OP want to give me one. Temper is a really easily port - I had it running before when I had a dev board (more or less). If I don't get one then I could get someone else to quickly port it, probably. Really I'm going to want one for totally different reasons.
 
Last edited by a moderator:
Exophase said:
He doesn't need a program to help him find if a game enables TLB or not. The emulator can assume it won't then recompile if it does.
Initially the TLB is not enabled, and any load or store on an address not in physical memory will cause an exception. If the game executes a TLBWI instruction with a valid TLB entry, then the dynamic recompiler changes how it compiles load and store instructions, so that memory addresses are looked up in the mapping table.

TLB disabled:
Code:
LW r1,8(r2)
->
add r1, r2, #8
cmp r1, $8388608
bvc handler
ldr r1, [r1]
TLB enabled:
Code:
LW r1,8(r2)
->
add r1, r2, #8
mov r0, #264
add r0, r0, r1, lsr #12
ldr r0, [r11, r0, lsl #2]
tst r0, r0
bmi handler
ldr r1, [r1, r0, lsl #2]
 
Last edited by a moderator:
Replying to some pretty old posts...
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).
Paper Mario pages code in and out of RAM a lot. It might be worth hacking that game to use the 8MB expansion, page its code in there, and never page it out again, if possible. Or have an alternate mode for games like this where you don't recompile the code every time it's swapped in, but just keep the compiled code in a pool, and point memory at it when it's swapped in.
I know of no official games that execute from ROM. It's far too slow. I've heard at least one unlicensed third-party add-on device did this, but there wouldn't be much reason to emulate those.

You probably already know these things, but my observations from game hacking:
$K1 is only used in an interrupt handler. It's always 0xAAA elsewhere. You can modify it, but the games are strict about register use, and don't touch it. In fact they'll shuffe registers around when calling, entering, or leaving a function so that the inputs are always in $Ax and the return value is always in $V0 (or $F0 for floats). They never(?) rely on the contents of any other register.
You often see things like this:
OR $A0, $xx, $zero ;copy $xx to $A0
JAL doSomethingCool
OR $A1, $yy, $zero

doSomethingCool:
OR $zz, $A0, $zero ;zz is often the same register as xx
OR $ww, $A1, $zero ;and ww -> yy

so it may well be worth rewriting functions when possible (those that don't call others should be safe) to change which registers are used, to eliminate this redundancy. This should be safe, since in my experience functions work like a "black box" - $Ax go in, $Vx come out, others aren't touched (really, are preserved on the stack).


N64 emulation would definitely be a killer app, at least for me. I'd love to help any way I can. I hack a lot of Nintendo's first-party games, so I'm pretty familiar with their coding style. (I'd also love to test, but I'll need a Pandora for that. ;))
 
Last edited by a moderator:
Dude, your username is awesome. Did you come from another dimension to teach us about N64? Should I call you hexagon?

So does Paper Mario page code in and out to the same regions, or is it just shuffling the TLB around a big virtual code space? Loading to the same region in virtual address space seems very unintuitive to me when the space is so big, and it'd require more logic in the background (not to mention, position independent code). If the virtual space is fixed then you can pull some tricks for emulating it more efficiently. I don't know yet how involved that'd be though. I think Ari64 was mentioning something along these lines.

It's pretty natural that the inputs would be in A0-A3 or so and the return value in V0, that is afterall the ABI. An option to assume that the other registers are dead across a function call is a good enough idea. However, are you really certain NO games violate this? Did you really check all of them? N64's library is small enough that I could sort of believe this.
 
⬡ said:
Paper Mario pages code in and out of RAM a lot. It might be worth hacking that game to use the 8MB expansion, page its code in there, and never page it out again, if possible.
Paper Mario changes the mapping frequently but maps only a few pages, so it's not a big problem. Most of its code is not in virtual memory, and I only see it paging code in and out when you switch scenes.

⬡ said:
Or have an alternate mode for games like this where you don't recompile the code every time it's swapped in, but just keep the compiled code in a pool, and point memory at it when it's swapped in.
That's basically what it does. If a page is modified, then the compiled blocks go on the 'dirty' list. If some of that code is executed again, then it will check whether what was compiled before matches what is now in memory. If they match, then it will use the existing code from the cache.

I don't know of any official game that executes from ROM. However, the Goldeneye hack mentioned earlier changes the mapping so that the game does execute from ROM, since it's much faster for the emulator to do it that way instead of making a copy (which was not the case for the original hardware).

$K0-K1 (r26-r27) are commonly used by the interrupt handler, and not restored. They're not used elsewhere because the values would get overwritten during the next interrupt.

Exophase said:
It's pretty natural that the inputs would be in A0-A3 or so and the return value in V0, that is afterall the ABI. An option to assume that the other registers are dead across a function call is a good enough idea. However, are you really certain NO games violate this? Did you really check all of them? N64's library is small enough that I could sort of believe this.
I don't know if all games strictly adhere to this or not. If you wanted to experiment, you could change the unneeded_registers function to assume certain registers are dead after a JAL or return instruction, then try some games and see if they still work. (You don't need a Pandora to test this; this function works the same on x86.)

Exophase said:
Dude, your username is awesome. Did you come from another dimension to teach us about N64? Should I call you hexagon?
LOL I was wondering about that...
 
Last edited by a moderator:
http://bunnitude.com/ari64/mupen64plus-arm-20100227.tar.gz


Changes since -20100212:

Optimized hash tables for virtual->physical address lookup

Cache invalidation now based on physical address instead of virtual address

Fixed load/store using r0 as a base register

Properly handle pending interrupts when interrupts are re-enabled

Some minor code generation improvements
 
Exophase said:
It's pretty natural that the inputs would be in A0-A3 or so and the return value in V0, that is afterall the ABI. An option to assume that the other registers are dead across a function call is a good enough idea. However, are you really certain NO games violate this? Did you really check all of them? N64's library is small enough that I could sort of believe this.
I tried this, and it works in some games and not others. Usually you can get away with discarding V0-V1 during a call and A0-A3 upon return. Sometimes it is also possible to discard AT and T6-T9. The speedup is about 2% when it works. This doesn't seem like a worthwhile optimization due to the minimal speed gain and high failure rate.
 
Last edited by a moderator:
Ari64 said:
I tried this, and it works in some games and not others. Usually you can get away with discarding V0-V1 during a call and A0-A3 upon return. Sometimes it is also possible to discard AT and T6-T9. The speedup is about 2% when it works. This doesn't seem like a worthwhile optimization due to the minimal speed gain and high failure rate.

Guess our six sided friend was wrong about that then :( I'm a little surprised myself.
 
Last edited by a moderator:
Ari64 said:
Exophase said:
It's pretty natural that the inputs would be in A0-A3 or so and the return value in V0, that is afterall the ABI. An option to assume that the other registers are dead across a function call is a good enough idea. However, are you really certain NO games violate this? Did you really check all of them? N64's library is small enough that I could sort of believe this.
I tried this, and it works in some games and not others. Usually you can get away with discarding V0-V1 during a call and A0-A3 upon return. Sometimes it is also possible to discard AT and T6-T9. The speedup is about 2% when it works. This doesn't seem like a worthwhile optimization due to the minimal speed gain and high failure rate.
If one just blindly assumes those registers can be discarded without doing some smart analyses about the usage of registers, games surely happen to fail to run if they were not coded in pure C source (that si, if the emulator needs to dynarec BIOS or custom assembly code). That is the main reason I never attempted it for psx4all. That smart analyser may also be proved difficult to issue efficient code if at the end you still need store registers back when executing, says, a return instruction which is quite common in a C source.
 
Last edited by a moderator:
Back
Top