Go Back   Project64 Forums > General Discussion > Open Discussion

Reply
 
Thread Tools Display Modes
  #281  
Old 24th May 2013, 04:08 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

No, I'm pretty sure you're right about it.

It was never an issue because if(SEMAPHORE) was the most likely condition.
else if (MFCO_count has pointer addr to something that exists) was the next branch frame after that.
else (some other way of setting SP_STATUS_HALT using MTC0 strictly) was almost impossible because no game ever seems to do that.

So the second branch frame may as well be an unconditional `else`, and it would still work just as well.

I just forgot to change it back when I made MFC0_count an array counting for each of the 32 scalar GPRs.

Quote:
Originally Posted by suanyuan View Post
And Top Gear Rally (USA) (one of Boss Stuido games) will get stuck in the loop of wait for cpu host (tested with rsp_pj64.dll mingw build without any modification).
I'm not finding this issue.

I'm running Top Gear Rally (U), and I'm able to get in-game past the menus and start a race.

You can try creating a new global int variable flagging a MFC0_count overflow and checking that at the end outside the run_task() function instead if you like.
Reply With Quote
  #282  
Old 24th May 2013, 05:54 PM
shunyuan's Avatar
shunyuan shunyuan is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Apr 2013
Posts: 491
Default

Quote:
Originally Posted by FatCat View Post
I'm running Top Gear Rally (U), and I'm able to get in-game past the menus and start a race.

You can try creating a new global int variable flagging a MFC0_count overflow and checking that at the end outside the run_task() function instead if you like.
My fault, get stuck on vc build z64gl. Don't why vc build z64gl is more unstable than mingw build.
__________________
---------------------
CPU: Intel U7300 1.3 GHz
GPU: Mobile Intel 4 Series (on board)
AUDIO: Realtek HD Audio (on board)
RAM: 4 GB
OS: Windows 7 - 32 bit
Reply With Quote
  #283  
Old 24th May 2013, 06:32 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

I turned MFC0_count into an array of counts instead of just one total count for all the scalar registers, because World Driver gave me problems using zilmar's method. zilmar just counted the total MFC0 status reads and said that if it exceeded 10 the RSP was probably stuck in a permanent loop and should restart.

It gave me an error that there was an alternative reason the HALT bit was getting set at some point in World Driver, so I needed to change the MFC0 count limit to exceed or make it into an array.

I made it into an array so that I could have a smaller count, less looping of the RSP to wait to find out if it was a permanent loop.

I guess it fixed the issue just perfectly, but not in the way that I expected...it was for the wrong reasons. The if() was unconditional as you pointed out.

I can worry about fixing it later if there is a game this has a problem with.
Until then I am way busier finding things out about the RDP now.
Reply With Quote
  #284  
Old 26th May 2013, 05:22 PM
shunyuan's Avatar
shunyuan shunyuan is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Apr 2013
Posts: 491
Default

Quote:
Originally Posted by FatCat View Post
You can try creating a new global int variable flagging a MFC0_count overflow and checking that at the end outside the run_task() function instead if you like.
I follow your suggestion add a variable MFC0_count_exceed and change the code as below:

Code:
#ifdef WAIT_FOR_CPU_HOST
	if (IsWaitForCpuHost())
	{
		MFC0_count_exceed = 0;
		for (rt = 0; rt < 32; rt++)
			MFC0_count[rt] = 0;
	}
#endif
Code:
#ifdef WAIT_FOR_CPU_HOST
static int MFC0_count[32];
static int MFC0_count_exceed;
/* Keep one C0 MF status read count for each scalar register. */
#endif
Code:
        case 0x4:
            SR[rt] = *RSP.SP_STATUS_REG;
#ifdef WAIT_FOR_CPU_HOST
			++MFC0_count[rt];
			if (MFC0_count[rt] > 7)
			{
				*RSP.SP_STATUS_REG |= 0x00000001; /* Let OS restart the task. */
				MFC0_count_exceed = 1;
			}
#endif
Code:
    if (*RSP.SP_SEMAPHORE_REG == 0x00000001) /* SP semaphore lock (zilmar) */
        *RSP.SP_STATUS_REG &= ~0x00000001; /* Guess I need to let emu retask. */
#ifdef WAIT_FOR_CPU_HOST
	else if (MFC0_count_exceed)
        *RSP.SP_STATUS_REG &= ~0x00000001; /* CPU restarts with correct SIGs. */
#endif
    else
    {
        message("Halted RSP CPU loop by means of MTC0.", 2); /* not sure */
        *RSP.MI_INTR_REG |= 0x00000001; /* VR4300 SP interrupt */
        RSP.CheckInterrupts();
    }
But it didn't work.

When testing with World Driver Championship, after the title menu, the HALT flag will set and MFC0_count_exceed is not overflow, but one element of MFC0_count array is 1.

If at this time return to CPU without clear the HALT flag, no more RSP task will send to RSP. And with this modification, most game won't boot.

So I think actually the code can simplify as no matter what causes current task to halt, just clear the HALT flag before return to CPU:

Code:
#if 0
    if (*RSP.SP_SEMAPHORE_REG == 0x00000001) /* SP semaphore lock (zilmar) */
        *RSP.SP_STATUS_REG &= ~0x00000001; /* Guess I need to let emu retask. */
#ifdef WAIT_FOR_CPU_HOST
	else if (MFC0_count_exceed)
        *RSP.SP_STATUS_REG &= ~0x00000001; /* CPU restarts with correct SIGs. */
#endif
    else
    {
        message("Halted RSP CPU loop by means of MTC0.", 2); /* not sure */
        *RSP.MI_INTR_REG |= 0x00000001; /* VR4300 SP interrupt */
        RSP.CheckInterrupts();
    }
#endif 


    // just clear current HALT flag
    *RSP.SP_STATUS_REG &= ~0x00000001;  
And actually it works as before.
__________________
---------------------
CPU: Intel U7300 1.3 GHz
GPU: Mobile Intel 4 Series (on board)
AUDIO: Realtek HD Audio (on board)
RAM: 4 GB
OS: Windows 7 - 32 bit
Reply With Quote
  #285  
Old 26th May 2013, 06:04 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Quote:
Originally Posted by suanyuan View Post
I follow your suggestion add a variable MFC0_count_exceed and change the code as below

But it didn't work.

When testing with World Driver Championship, after the title menu, the HALT flag will set and MFC0_count_exceed is not overflow, but one element of MFC0_count array is 1.

If at this time return to CPU without clear the HALT flag, no more RSP task will send to RSP. And with this modification, most game won't boot.
Then, it's possible this could be the very first game we have ever seen to use MTC0 to set halt.
Code:
.name   SP_STATUS           $c4
#define SP_STATUS_HALT      0x00000001

mfc0    $at, SP_STATUS
ori     $at, SP_STATUS_HALT
mtc0    $at, SP_STATUS
Which is meant to be an alternative way of setting the HALT bit and breaking the SP task.
Funny thing is, zilmar's RSP emulator never supported that properly. It sets the HALT bit, but he relies on a custom `RSP_Running` global Boolean which he declined to maintain in that function. So if this was the correct path of code for World Driver to reach it would have broken his interpreter.

Yet, it doesn't break his interpreter, which most likely means that code was never encountered...I'm not sure if that's good or bad. I will look into it later.

Quote:
Originally Posted by suanyuan View Post
So I think actually the code can simplify as no matter what causes current task to halt, just clear the HALT flag before return to CPU:

Code:
#if 0
    if (*RSP.SP_SEMAPHORE_REG == 0x00000001) /* SP semaphore lock (zilmar) */
        *RSP.SP_STATUS_REG &= ~0x00000001; /* Guess I need to let emu retask. */
#ifdef WAIT_FOR_CPU_HOST
	else if (MFC0_count_exceed)
        *RSP.SP_STATUS_REG &= ~0x00000001; /* CPU restarts with correct SIGs. */
#endif
    else
    {
        message("Halted RSP CPU loop by means of MTC0.", 2); /* not sure */
        *RSP.MI_INTR_REG |= 0x00000001; /* VR4300 SP interrupt */
        RSP.CheckInterrupts();
    }
#endif 


    // just clear current HALT flag
    *RSP.SP_STATUS_REG &= ~0x00000001;  
And actually it works as before.
Possibly, but I wouldn't worry about that.
The compiler would most likely optimize that change you just did by in-lining the halt clear at the end of both if() blocks like I did, to avoid branching out of the block to reach the shared common code.

So it would possibly be a size change, but not really an efficiency change on the low level of things.

I wrote out the cases for when HALT should be un-set so Project64 knows to re-try the task.
If all cases fail, it should remain set, because mtc0 instructed HALT to be set.
Otherwise I wrote out the cases where it should be cleared.
Reply With Quote
  #286  
Old 26th May 2013, 06:53 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Just taking notes.

DP command-fetching queue code:
Code:
    for (i = 0; i < length; i += 4)
    {
        rdp_cmd_data[rdp_cmd_ptr++] = READ_RDP_DATA(*gfx.DPC_CURRENT_REG + i);
        if (rdp_cmd_ptr >= 0x00010000)
        {
            fatalerror(
                "overflow\n0x%x 0x%x 0x%x", rdp_cmd_ptr, length, ptr_onstart);
        }
    }
Original MESS code surviving in angrylion's RDP.

I was thinking why not factor out the if() out of the loop:

Code:
    if ((rdp_cmd_ptr + length>>2) & ~0x0000FFFF)
    {
        MessageBoxA(gfx.hWnd, "ProcessRDPList", NULL, 0x00000010);
        return;
    }
    for (i = 0; i < length; i += 4)
    {
        rdp_cmd_data[rdp_cmd_ptr++] = READ_RDP_DATA(*gfx.DPC_CURRENT_REG + i);
    }
The loop is not extremely big, since command lengths are very rarely greater than 128 bits wide.
Still, it's a fair, static speed-up.

But there are two interesting ways of doing the first `if`:

method A
Code:
if ((rdp_cmd_ptr + length>>2) & ~0x0000FFFF)
On MIPS this would be better, because you can do a LUI on the result to ask if it's 0x0000????.

On Intel however, I'm thinking the arithmetic method may be faster....

method B, algebraically rewritten off of method A
Code:
if ((P + L>>2) & ~0x0000FFFF)
if (P + L/4 > 0x0000FFFF)
if (P + L/4 >= 0x00010000)
if (4*P + L >= 0x00040000)
Can also rewrite this back into bit-wise form:
Code:
if ((rdp_cmd_ptr<<2 + length) & ~0x0003FFFF)
[edit] shit lol, posted in the wrong thread

Last edited by HatCat; 26th May 2013 at 07:01 PM.
Reply With Quote
  #287  
Old 26th May 2013, 10:47 PM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

Far be it from the truth that this is the only thing I am optimizing.
But there is something special about this precise inefficiency.

Have a closer look at the original code here in angrylion's plugin:
http://code.google.com/p/angrylions-...video.cpp#7476

Notice:
`dp_current += rdp_command_length[cmd];`
(dp_current is a defined macro for *gfx.DP_CURRENT_REG.)

dp_current is never read from anywhere within the body of that loop.
dp_current is never read from anywhere after the body of that loop.
dp_current is *completely overwritten* at the end of the loop:
Code:
        ( ... loop body ... )
    };
    rdp_cmd_ptr = 0;
    rdp_cmd_cur = 0;
    dp_start = dp_current = dp_end;
}
wtf is this redundant bs ,,
it probably was one of those MAME prototype rewrites that got overlooked and never removed from a while back

Unless I am missing some informational value behind that code?
But it looks redundant/pointless.
Reply With Quote
  #288  
Old 27th May 2013, 12:21 AM
shunyuan's Avatar
shunyuan shunyuan is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Apr 2013
Posts: 491
Default

Quote:
Originally Posted by FatCat View Post
Far be it from the truth that this is the only thing I am optimizing.
But there is something special about this precise inefficiency.

Have a closer look at the original code here in angrylion's plugin:
http://code.google.com/p/angrylions-...video.cpp#7476

Notice:
`dp_current += rdp_command_length[cmd];`
(dp_current is a defined macro for *gfx.DP_CURRENT_REG.)

dp_current is never read from anywhere within the body of that loop.
dp_current is never read from anywhere after the body of that loop.
dp_current is *completely overwritten* at the end of the loop:
Code:
        ( ... loop body ... )
    };
    rdp_cmd_ptr = 0;
    rdp_cmd_cur = 0;
    dp_start = dp_current = dp_end;
}
wtf is this redundant bs ,,
it probably was one of those MAME prototype rewrites that got overlooked and never removed from a while back

Unless I am missing some informational value behind that code?
But it looks redundant/pointless.
Currently the rdp_process_list always complete to process a display list, so it seems redundant to keep track the dp_current in the loop and assign dp_end to dp_current after exit the loop.

But if rdp_process_list has cycles limitation and is possible to break the loop when runs out of CPU cycles, then it is make sense to keep track dp_current.
__________________
---------------------
CPU: Intel U7300 1.3 GHz
GPU: Mobile Intel 4 Series (on board)
AUDIO: Realtek HD Audio (on board)
RAM: 4 GB
OS: Windows 7 - 32 bit
Reply With Quote
  #289  
Old 27th May 2013, 12:48 AM
HatCat's Avatar
HatCat HatCat is offline
Alpha Tester
Project Supporter
Senior Member
 
Join Date: Feb 2007
Location: In my hat.
Posts: 16,236
Default

True, as a vendor-extension viewpoint.
For if someone should decide to merge in cycle-accuracy.

For reasons like that I'd decided that, being the least of the bottlenecks behind the slow speed I leave it in, just commented.
Reply With Quote
  #290  
Old 9th June 2013, 04:40 PM
angrylion angrylion is offline
Member
 
Join Date: Oct 2008
Location: Moscow, Russia
Posts: 36
Default

Mia Hamm Soccer 64 (U) seems to quit with "LUV illegal element" / "SQV illegal element".
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT. The time now is 09:08 PM.


Powered by vBulletin® Version 3.7.3
Copyright ©2000 - 2023, Jelsoft Enterprises Ltd.