PDA

View Full Version : GNU/Linux compatibility


RyDroid
5th May 2013, 11:26 AM
Hi.

It would be nice if PJ64 became natively compatible with GNU/Linux.
Have you planed to do it ?

zilmar
5th May 2013, 06:39 PM
I have no plans for doing it as I do not use linux at all.

most of the emu is open source now so it should not be to bad to convert it, that being said there is still a lot of windows stuff there.

I have a a library called common it would be nice if I could move all windows calls in to it and then have a linux version of the common as a separate version.

Also the core makes use of structured exception handling, not sure how well that converts to the linux world.

twostars
6th May 2013, 03:21 AM
Also the core makes use of structured exception handling, not sure how well that converts to the linux world.
Hmm, the only way I can think of handling that is with signals. :/

Edit:
It seems someone's tried to address this: syprog.blogspot.com.au/2012/02/vectored-exception-handling-for-linux.html
Not quite the same, but it's a lot more manageable than using signals as-is (which won't give you any context).

IBM also has an article on it: ibm.com/developerworks/library/l-cppexcep/index.html
Interesting stuff!

zilmar
6th May 2013, 03:26 AM
Hmm, the only way I can think of handling that is with signals. :/

it does not check if it is rdram on not on read/writes, just executes it.

If it is not, a structured exception occurs, the structure exception handler then looks at the asm opcode causing the error, detects if it is actually in the n64 zone and maps to a n64 register address. If it does then it cause the read/write to register, setups up the x86 ops that should be filled with that value, moves EIP to the next instruction and tells the cpu to continue executing.

Not sure if that would work with signals, possible the whole memory management needs to be re-written to allow porting to linux.

twostars
6th May 2013, 03:35 AM
it does not check if it is rdram on not on read/writes, just executes it.

If it is not, a structured exception occurs, the structure exception handler then looks at the asm opcode causing the error, detects if it is actually in the n64 zone and maps to a n64 register address. If it does then it cause the read/write to register, setups up the x86 ops that should be filled with that value, moves EIP to the next instruction and tells the cpu to continue executing.

Not sure if that would work with signals, possible the whole memory management needs to be re-written to allow porting to linux.
Yeah, that's half the trouble with using signals (or vectored exception handling, for that matter) as is -- context management. The flow of logic just becomes a bit cumbersome.

It could still work, it'd just be really messy keeping track of where you are/what tripped it, and resuming logic -- it might even work better coupled with typical C exception handling (setjmp(), longjmp()).

I might have a play around with it, though to figure out just how feasible that would be with the current system... perhaps rewriting it would be the better plan, here. :/

Edit: Wow, just found the code you were referring to. This might indeed be a tad infeasible to port as it is. It's a little bit more complicated than your post indicates. :P

I'm really new to emulation, so forgive me, but what's the reason behind all this to begin with? Is it typical behaviour for ROMs to access invalid memory, or is it more that it was just easier to handle certain behaviour like this? Or is it simply old legacy code that isn't strictly so necessary anymore?

Rather, what I'm saying is: what's the reason behind not differentiating in these cases?

zilmar
6th May 2013, 04:04 AM
Simple idea, the actual code is a lot more complicated.

The options are that I see:

Use SEH (which pj64 is doing)
Check address range on each read/write
have a function write table, where you pass the address in and execute the function in the list


the last one I had considered, since i am already looking up in essence on 4k memory address to check if an address is translated from virtual to physical.

Where at the moment I get a pointer, I write to it, if it is null then I generate an exception.

maybe if null .. then call the function.

Partly I considered this for be able to detect easier when writing to cfb.

Not sure of the performance issues. (causing an exception is very slow, with re compiler and advanced block linking, it does not happen that much).

zilmar
6th May 2013, 04:07 AM
http://www.winehq.org/docs/winedev-guide/seh

maybe there is something in the wine code that could make the translation.

zilmar
6th May 2013, 04:10 AM
I'm really new to emulation, so forgive me, but what's the reason behind all this to begin with? Is it typical behaviour for ROMs to access invalid memory, or is it more that it was just easier to handle certain behaviour like this? Or is it simply old legacy code that isn't strictly so necessary anymore?

Rather, what I'm saying is: what's the reason behind not differentiating in these cases?

the n64 memory space:

0x0000 0000 to 0x03EF FFFF RDRAM Memory
0x03F0 0000 to 0x03FF FFFF RDRAM Registers
0x0400 0000 to 0x040F FFFF SP Registers
0x0410 0000 to 0x041F FFFF DP Command Registers
0x0420 0000 to 0x042F FFFF DP Span Registers
0x0430 0000 to 0x043F FFFF MIPS Interface (MI) Registers
0x0440 0000 to 0x044F FFFF Video Interface (VI) Registers
0x0450 0000 to 0x045F FFFF Audio Interface (AI) Registers
0x0460 0000 to 0x046F FFFF Peripheral Interface (PI) Registers
0x0470 0000 to 0x047F FFFF RDRAM Interface (RI) Registers
0x0480 0000 to 0x048F FFFF Serial Interface (SI) Registers
0x0490 0000 to 0x04FF FFFF Unused
0x0500 0000 to 0x05FF FFFF Cartridge Domain 2 Address 1
0x0600 0000 to 0x07FF FFFF Cartridge Domain 1 Address 1
0x0800 0000 to 0x0FFF FFFF Cartridge Domain 2 Address 2
0x1000 0000 to 0x1FBF FFFF Cartridge Domain 1 Address 2
0x1FC0 0000 to 0x1FC0 07BF PIF Boot ROM
0x1FC0 07C0 to 0x1FC0 07FF PIF RAM
0x1FC0 0800 to 0x1FCF FFFF Reserved
0x1FD0 0000 to 0x7FFF FFFF Cartridge Domain 1 Address 3
0x8000 0000 to 0xFFFF FFFF External SysAD Device

I reserve a memory space of 0x1FF00000

so instead of detecting on each read/write to the address space to see if it is to a special area or rdram, I just assume it is rdram and detect the exception when it fails.

twostars
6th May 2013, 04:14 AM
You might be onto something there, with Wine.
Found a random github repo which uses it (doesn't look like it depends on much of anything):
http://github.com/ILOVEPIE/Cxbx-Reloaded/tree/master/build/wine/libseh

Edit:
Ahh, ok. Thanks!

I just can't help but feel there's a less kludgy way of doing it, but as you said -- the recompiler helps ensure that already. I guess in emulation, there's no real clean solutions. :/

twostars
6th May 2013, 04:38 AM
Not sure what happened to my post, but again -- thanks a lot for taking the time to help me understand what it's doing. :)

Regarding SEH, again, it seems libseh is what Wine uses (I won't link it again, in case that's why my post was removed).

Regarding memory management: so really all that comes down to is trying to conserve both unnecessary memory allocations (instead of allocating the entire thing, when you only need parts of it), and consequently CPU usage by not having to check where to write, each and every time.

Which of those sections aren't of concern to these reads/writes? Or the better question is, which of these special sections do we care about handling?

Apologies for all the questions, I really can't see anything else that explains the N64 in all that much detail (edit: that was kind of a silly thing to say, reading over the CPU's technical docs at the moment -- and well, there's source out there.). If you know of something, though, I'd happily wade through it instead of bothering you! Really appreciate your time. :)

Edit 2:
Hey, my post reappeared. I deleted it now anyway because I repeated it.
I came across this which pretty much answers my questions: http://infrid.com/rcp64/docfiles/n64maps.txt

Thanks :)

HatCat
6th May 2013, 05:35 PM
The second option sounds simple enough. If matters on the branch weighing are handled appropriately, checking if the address is invalid should be a very miniscule cut by assuming that the validity of the address is by far the most likely branch case. However the Microsoft compiler seems to override that concept at times. :(

I have no idea what SEH is.

The third option would be the sexiest. Function-oriented templating is always a bit more 1:1 translatable to the human concept, but I would always avoid laying a series out except for cases where the conditional operations were too large or too complex to maintain in the local scope.

Also, I think that writing any code for portability, is a plus anywhere, not just GNU/Linux.
Linux would be a prime example for targeting portability, but keeping code simplicity and purity as a general rule of thumb should suffice over the need of targeting any default operating system.

Lithium
7th May 2013, 12:10 AM
The port to Linux will facilitate a port for Android, Zilmar can raise money with a version for Android on google market.

squall_leonhart
7th May 2013, 12:21 AM
The port to Linux will facilitate a port for Android, Zilmar can raise money with a version for Android on google market.

No.

-------------