Dreamcast Emulator...Update


And still, PSP has no MMU to detect those f*cking attempts to modify code segment (pseudo variable using pc relative constant loading instruction). The same goes for memory access from a register base you cannot be sure it is a constant address. SH4 is trickier than I thought. A lot of things is really a pain in the ass to emulate. In fact, a lot of things will need to be dynarec-ed like address detection to execute the right memory operation, etc. without using the fixed registers used for SH4 registers (that cannot be done in C). If only PSP has a gdb usable with Eclipse or Code::Block debugger.
 
Exophase said:
All of this is nullDC's problem and not MIPS. It's because you're relying too much on C functions. Anything that the recompiler calls with any frequency should be ASM where you control the convention and keep register usage to a minimum.. and of course isn't poorly generated GCC code. For the times when you do call C code you save/restore what you need to. Works well for gpSP and I'm sure it would work well for you too.

Of course i rely on C++ code.Its nowhere near as speed critical as you think ;p.Not compared to the sh4 anyway ..I don't want to have 10000's of lines of ugly platform dependant ASM when targeting 4 different cpus (x86,mips,arm,ppc).While i do plan to profile that part later on there are only a few memory regions that are performance critical (RAM,VRAM,SQ buffers) and these have a special fast path that doesn't call any external code.On the dreamcast a LOT of the work is done actually with the cpu and less offloaded to the memory mapped hardware so even C++ code is fairly fast.

Also you don't have constants, everything is on literal pools around the code, mixed (sometimes) with real variables and the code jumping around em.And there are many call gates (jump opcodes have very small range ..)

Exophase said:
Eh? That sounds completely backwards. The smaller basic blocks are, the more overhead there will be in loading/storing registers and the shorter the dynamic allocation will last, at least for a local only allocation scheme. Of course global allocation is a huge pain in the ass that no one really wants to do. Static allocation, on the other hand, removes all of that overhead entirely and if it's 1:1 then it's perfect to do so.

Come on guys, get your hands dirty ;P But not too dirty. Any work on doing dynamic register allocation would be a step in a very wrong/unnecessary direction that will only hurt performance if you don't do it globally.

90%+ of the blocks don't touch more than 4 registers, and that is usualy a fixed set of registers (r0/r1/r2/r3/r7/r13/r14/r15 iirc)
 
drkIIRaziel said:
Of course i rely on C++ code.Its nowhere near as speed critical as you think ;p.Not compared to the sh4 anyway ..I don't want to have 10000's of lines of ugly platform dependant ASM when targeting 4 different cpus (x86,mips,arm,ppc).While i do plan to profile that part later on there are only a few memory regions that are performance critical (RAM,VRAM,SQ buffers) and these have a special fast path that doesn't call any external code.On the dreamcast a LOT of the work is done actually with the cpu and less offloaded to the memory mapped hardware so even C++ code is fairly fast.

Tens of thousands of lines? I think you totally missed what I was saying. I didn't say to only use ASM code, I said to use it for the most commonly executed portions, which like you said is just a few cases. And you probably wouldn't bother with this except on archs that have a lot of registers. Doing dynamic register allocation worth anything would be much more work than stubbing out fast memory cases in ASM for a few archs.

drkIIRaziel said:
Also you don't have constants, everything is on literal pools around the code, mixed (sometimes) with real variables and the code jumping around em.And there are many call gates (jump opcodes have very small range ..)

What does this have to do with register allocation?

drkIIRaziel said:
90%+ of the blocks don't touch more than 4 registers, and that is usualy a fixed set of registers (r0/r1/r2/r3/r7/r13/r14/r15 iirc)

I wonder if you really profiled that number out, but nonetheless that means 4 loads and up to 4 stores for a block that sounds like it's very small, if you're using dynamic allocation. If you feel like a partial static allocation is a good idea then go ahead, but I think compilation for Dreamcast games must have been very poor if only half of your registers are being used almost all the time.
 
Exophase said:
Tens of thousands of lines? I think you totally missed what I was saying. I didn't say to only use ASM code, I said to use it for the most commonly executed portions, which like you said is just a few cases. And you probably wouldn't bother with this except on archs that have a lot of registers. Doing dynamic register allocation worth anything would be much more work than stubbing out fast memory cases in ASM for a few archs.

The way the memory is mapped right now its either directly mapped (an array) or a handler (calls an external function).I can only have 'fast path' for the array case as the handlers need to be generic.I use a 256 entry lookup table and map in 16 MB segments.Each mapping can be a handler or a masked array {u32 val=LUT[addr>>24];u32* ptr=val&~1F; return ptr[(addr<<val)>>val]; //for the 'fast path'}.Anyway, memory just calls C functions for now, its not yet a significant bottleneck =P

Exophase said:
drkIIRaziel said:
Also you don't have constants, everything is on literal pools around the code, mixed (sometimes) with real variables and the code jumping around em.And there are many call gates (jump opcodes have very small range ..)

What does this have to do with register allocation?

You have no idea if a memory access reads from ram, or needs to call C code.This requires a possible save/restore of 10 registers for 1:1 mapping on each memory opcode (And for code that does lots of h/w reads in a row thats gonna get ugly real fast).On other cpu (like mips) most memory accesses to registers are detectable constants so you can use special code to save on register store/loads.

Exophase said:
drkIIRaziel said:
90%+ of the blocks don't touch more than 4 registers, and that is usualy a fixed set of registers (r0/r1/r2/r3/r7/r13/r14/r15 iirc)

I wonder if you really profiled that number out, but nonetheless that means 4 loads and up to 4 stores for a block that sounds like it's very small, if you're using dynamic allocation. If you feel like a partial static allocation is a good idea then go ahead, but I think compilation for Dreamcast games must have been very poor if only half of your registers are being used almost all the time.

Yup, i profiled that one :p.Most (all ?) sh4 code is VERY badly written, with very bad register usage and a special love for doing reg -> stack -> reg -> stack -> reg operations just to move data around.It seems the compiler really did a bad job at optimizing the code.The 'hand-tuned' parts that use assembly rely mostly on fpu (most of the work is done using fpu) and that has a nice 1:1 mapping for psp.Pandora will be less efficient on that part but it has larger cache so it should be allright.I don't do any kind of register allocation on psp anyway, and pandora probably doesn't need it to get fullspeed in some games.
 
drkIIRaziel said:
The way the memory is mapped right now its either directly mapped (an array) or a handler (calls an external function).I can only have 'fast path' for the array case as the handlers need to be generic.I use a 256 entry lookup table and map in 16 MB segments.Each mapping can be a handler or a masked array {u32 val=LUT[addr>>24];u32* ptr=val&~1F; return ptr[(addr<<val)>>val]; //for the 'fast path'}.Anyway, memory just calls C functions for now, its not yet a significant bottleneck =P

Even if the C functions themselves aren't the bottleneck, it's the requirement for your register allocation... That fast path is so small and requires so few registers..

It's actually kind of interesting though, that you say they're not a bottleneck when it's not as if you're getting anywhere close to fullspeed >_> So how do you know that there are no improvements to be had here?

drkIIRaziel said:
You have no idea if a memory access reads from ram, or needs to call C code.This requires a possible save/restore of 10 registers for 1:1 mapping on each memory opcode (And for code that does lots of h/w reads in a row thats gonna get ugly real fast).On other cpu (like mips) most memory accesses to registers are detectable constants so you can use special code to save on register store/loads.

Yes, a potential save/restore that happens a statistically low amount of time, that's kind of the point, also it wouldn't be 10 registers but I digress... Who cares if a bunch of H/W reads are done in a row if they're still a very low percentage statistically? You have an entire frame to make up the difference. Unless we're talking about an idle loop, which you should be able to detect/eliminate for other obviously beneficial purposes.

Or do you really think that hardware registers are read anywhere close to the amount SH4 registers you're not allocating, which is currently all of them?

This should also only apply if reading hardware registers can have side effects. On some platforms it can, on say GBA it doesn't - I don't know about DC, but if there are no side effects then you should map to memory if possible.

By the way, how are these detectable constants on say PSP, if you don't know if the values in RAM you're seeding from will change and can't detect it with MMU?

drkIIRaziel said:
Yup, i profiled that one :p.Most (all ?) sh4 code is VERY badly written, with very bad register usage and a special love for doing reg -> stack -> reg -> stack -> reg operations just to move data around.It seems the compiler really did a bad job at optimizing the code.The 'hand-tuned' parts that use assembly rely mostly on fpu (most of the work is done using fpu) and that has a nice 1:1 mapping for psp.Pandora will be less efficient on that part but it has larger cache so it should be allright.I don't do any kind of register allocation on psp anyway, and pandora probably doesn't need it to get fullspeed in some games.

You said yourself that games tend to use a fixed 8 registers so why not make a static allocation for at least those registers? You should have that amount available in callee save regs for both MIPS and ARM, it seems like you're turning down a free meal otherwise...
 
Exophase said:
Even if the C functions themselves aren't the bottleneck, it's the requirement for your register allocation... That fast path is so small and requires so few registers..

It's actually kind of interesting though, that you say they're not a bottleneck when it's not as if you're getting anywhere close to fullspeed >_> So how do you know that there are no improvements to be had here?

Theres lots of things to improve.Like recompiling most opcodes and make fpu not call helper functions for all of the 'recompiled' opcodes :p

The slow path is pretty much like : if ((s32)val<0) return SecondLookupTable[256+val](addr);

Exophase said:
Yes, a potential save/restore that happens a statistically low amount of time, that's kind of the point, also it wouldn't be 10 registers but I digress... Who cares if a bunch of H/W reads are done in a row if they're still a very low percentage statistically? You have an entire frame to make up the difference. Unless we're talking about an idle loop, which you should be able to detect/eliminate for other obviously beneficial purposes.

Or do you really think that hardware registers are read anywhere close to the amount SH4 registers you're not allocating, which is currently all of them?

This needs to be measured.

Exophase said:
This should also only apply if reading hardware registers can have side effects. On some platforms it can, on say GBA it doesn't - I don't know about DC, but if there are no side effects then you should map to memory if possible.
Sadly many have side effects ...

Exophase said:
By the way, how are these detectable constants on say PSP, if you don't know if the values in RAM you're seeding from will change and can't detect it with MMU?

I mean, i can't detect em :p.You can detect em when emulating mips.I can probably use the mmu on pandora to minimize the problem like i do on x86, so another point for arm !

Exophase said:
You said yourself that games tend to use a fixed 8 registers so why not make a static allocation for at least those registers? You should have that amount available in callee save regs for both MIPS and ARM, it seems like you're turning down a free meal otherwise...

Thats the plan ! when i get to do reg alloc anyway ....

The problem is progress is slow, and i'm lazy .. and i always have the worst luck when it comes to working with linux.And exams are coming .....
 
Back
Top