Merge pull request #1783 from LuigiBlood/ddtiming

[Disk] Introduce Seek Times
This commit is contained in:
zilmar 2020-06-06 09:09:28 +09:30 committed by GitHub
commit f3747c2802
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 19 deletions

View File

@ -62,23 +62,28 @@ void DiskCommand()
uint8_t second = (uint8_t)(((result.tm_sec / 10) << 4) | (result.tm_sec % 10));
#endif
//Used for seek times
bool isSeek = false;
switch (cmd & 0xFFFF0000)
{
case 0x00010000:
//Seek Read
g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000;
dd_write = false;
isSeek = true;
break;
case 0x00020000:
//Seek Write
g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000;
dd_write = true;
isSeek = true;
break;
case 0x00080000:
//Unset Disk Changed Bit
g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG; break;
case 0x00090000:
//Unset Reset Bit
//Unset Reset & Disk Changed bit Bit
g_Reg->ASIC_STATUS &= ~DD_STATUS_RST_STATE;
g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG;
//F-Zero X + Expansion Kit fix so it doesn't enable "swapping" at boot
@ -99,6 +104,71 @@ void DiskCommand()
//Disk Inquiry
g_Reg->ASIC_DATA = 0x00000000; break;
}
if (isSeek)
{
//Emulate Seek Times, send interrupt later
uint32_t seektime = 0;
//Start Motor, can take half a second, delay the response
if (g_Reg->ASIC_STATUS & DD_STATUS_MTR_N_SPIN)
{
seektime += (0x5A00000 / 2);
g_Reg->ASIC_STATUS &= ~DD_STATUS_MTR_N_SPIN;
}
//Get Zone to calculate seek times
uint32_t track = g_Reg->ASIC_CUR_TK >> 16 & 0x0FFF;
uint32_t zone = 0;
uint32_t zonebound = 0;
for (uint8_t i = 0; i < 8; i++)
{
zonebound += ddZoneTrackSize[i];
if (track < zonebound)
{
zone = i;
if (g_Reg->ASIC_CUR_TK & 0x10000000)
zone++;
break;
}
}
//Add seek delay depending on the zone (this is inaccurate timing, but close enough)
seektime += 0x179200;
switch (zone)
{
case 0:
case 1:
default:
seektime += track * 38;
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
seektime += 0x13C * 38 + (track - 0x13C) * 46;
break;
case 8:
seektime += 0x13C * 38 + 0x2E9 * 46 + (track - 0x425) * 58;
break;
}
//Set timer for seek response
g_SystemTimer->SetTimer(g_SystemTimer->DDSeekTimer, seektime, false);
//Set timer for motor to shutdown in 5 seconds, reset the timer if other seek commands were sent
g_SystemTimer->SetTimer(g_SystemTimer->DDMotorTimer, 0x5A00000 * 5, false);
}
else
{
//Other commands are basically instant
g_Reg->ASIC_STATUS |= DD_STATUS_MECHA_INT;
g_Reg->FAKE_CAUSE_REGISTER |= CAUSE_IP3;
g_Reg->CheckInterrupts();
}
}
void DiskReset(void)
@ -157,6 +227,9 @@ void DiskBMControl(void)
void DiskGapSectorCheck()
{
//On 64DD Status Register Read
//Buffer Manager Interrupt, Gap Sector Check
if (g_Reg->ASIC_STATUS & DD_STATUS_BM_INT)
{
if (SECTORS_PER_BLOCK < dd_current)
@ -168,6 +241,7 @@ void DiskGapSectorCheck()
}
}
//Delay Disk Swapping by removing the disk for a certain amount of time, then insert the newly loaded disk (after 50 Status Register reads, here).
if (!(g_Reg->ASIC_STATUS & DD_STATUS_DISK_PRES) && g_Disk != NULL && g_Settings->LoadBool(GameRunning_LoadingInProgress) == false)
{
dd_swapdelay++;
@ -190,12 +264,14 @@ void DiskBMUpdate()
//Write Data
if (dd_current < SECTORS_PER_BLOCK)
{
//User Sector
if (!DiskBMReadWrite(true))
g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ;
dd_current += 1;
}
else if (dd_current < SECTORS_PER_BLOCK + 1)
{
//C2 Sector
if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK)
{
dd_start_block = 1 - dd_start_block;
@ -222,25 +298,27 @@ void DiskBMUpdate()
//Read Data
if (((g_Reg->ASIC_CUR_TK >> 16) & 0x1FFF) == 6 && g_Reg->ASIC_CUR_SECTOR == 0 && g_Disk->GetCountry() != Country::UnknownCountry)
{
//Copy Protection
//Copy Protection if Retail Disk
g_Reg->ASIC_STATUS &= ~DD_STATUS_DATA_RQ;
g_Reg->ASIC_BM_STATUS |= DD_BM_STATUS_MICRO;
}
else if (dd_current < SECTORS_PER_BLOCK)
{
//User Sector
if (!DiskBMReadWrite(false))
g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ;
dd_current += 1;
}
else if (dd_current < SECTORS_PER_BLOCK + 4)
{
//READ C2 (00!)
//C2 sectors (All 00s)
dd_current += 1;
if (dd_current == SECTORS_PER_BLOCK + 4)
g_Reg->ASIC_STATUS |= DD_STATUS_C2_XFER;
}
else if (dd_current == SECTORS_PER_BLOCK + 4)
{
//Gap Sector
if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK)
{
dd_start_block = 1 - dd_start_block;

View File

@ -2157,9 +2157,6 @@ void CMipsMemoryVM::Write32CartridgeDomain2Address1(void)
case 0x05000508:
g_Reg->ASIC_CMD = m_MemLookupValue.UW[0];
DiskCommand();
g_Reg->ASIC_STATUS |= DD_STATUS_MECHA_INT;
g_Reg->FAKE_CAUSE_REGISTER |= CAUSE_IP3;
g_Reg->CheckInterrupts();
break;
case 0x05000510:
//ASIC_BM_STATUS_CTL

View File

@ -221,6 +221,16 @@ void CSystemTimer::TimerDone()
m_Reg.MI_INTR_REG |= MI_INTR_PI;
m_Reg.CheckInterrupts();
break;
case CSystemTimer::DDSeekTimer:
g_SystemTimer->StopTimer(CSystemTimer::DDSeekTimer);
g_Reg->ASIC_STATUS |= DD_STATUS_MECHA_INT;
g_Reg->FAKE_CAUSE_REGISTER |= CAUSE_IP3;
g_Reg->CheckInterrupts();
break;
case CSystemTimer::DDMotorTimer:
g_SystemTimer->StopTimer(CSystemTimer::DDMotorTimer);
g_Reg->ASIC_STATUS |= DD_STATUS_MTR_N_SPIN;
break;
case CSystemTimer::ViTimer:
try
{

View File

@ -32,6 +32,8 @@ public:
RspTimer,
RSPTimerDlist,
DDPiTimer,
DDSeekTimer,
DDMotorTimer,
MaxTimer
};

View File

@ -985,7 +985,9 @@ void CN64System::InitRegisters(bool bPostPif, CMipsMemoryVM & MMU)
m_Reg.STATUS_REGISTER = 0x34000000;
//64DD Registers
m_Reg.ASIC_STATUS = DD_STATUS_RST_STATE;
//Start 64DD in Reset State and Motor Not Spinning
m_Reg.ASIC_STATUS = DD_STATUS_RST_STATE | DD_STATUS_MTR_N_SPIN;
m_Reg.ASIC_ID_REG = 0x00030000;
if (g_DDRom && (g_DDRom->CicChipID() == CIC_NUS_DDTL || (g_Disk && g_Disk->GetCountry() == Country::UnknownCountry)))
m_Reg.ASIC_ID_REG = 0x00040000;

View File

@ -11783,18 +11783,6 @@ void CX86RecompilerOps::SW_Register(x86Reg Reg, uint32_t VAddr)
MoveX86regToVariable(Reg, &g_Reg->ASIC_CMD, "ASIC_CMD");
m_RegWorkingSet.BeforeCallDirect();
Call_Direct(AddressOf(&DiskCommand), "DiskCommand");
m_RegWorkingSet.AfterCallDirect();
OrConstToVariable((uint32_t)DD_STATUS_MECHA_INT, &g_Reg->ASIC_STATUS, "ASIC_STATUS");
OrConstToVariable((uint32_t)CAUSE_IP3, &g_Reg->FAKE_CAUSE_REGISTER, "FAKE_CAUSE_REGISTER");
m_RegWorkingSet.BeforeCallDirect();
#ifdef _MSC_VER
MoveConstToX86reg((uint32_t)g_Reg, x86_ECX);
Call_Direct(AddressOf(&CRegisters::CheckInterrupts), "CRegisters::CheckInterrupts");
#else
PushImm32((uint32_t)g_Reg);
Call_Direct(AddressOf(&CRegisters::CheckInterrupts), "CRegisters::CheckInterrupts");
AddConstToX86Reg(x86_ESP, 4);
#endif
m_RegWorkingSet.AfterCallDirect();
break;
}