[Disk] Put Mecha Interrupt management in DiskCommand(), delay seek times

This commit is contained in:
LuigiBlood 2020-06-05 14:36:49 +02:00
parent 0512e7199a
commit b428c14a27
5 changed files with 41 additions and 18 deletions

View File

@ -62,23 +62,28 @@ void DiskCommand()
uint8_t second = (uint8_t)(((result.tm_sec / 10) << 4) | (result.tm_sec % 10)); uint8_t second = (uint8_t)(((result.tm_sec / 10) << 4) | (result.tm_sec % 10));
#endif #endif
//Used for seek times
bool isSeek = false;
switch (cmd & 0xFFFF0000) switch (cmd & 0xFFFF0000)
{ {
case 0x00010000: case 0x00010000:
//Seek Read //Seek Read
g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000; g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000;
dd_write = false; dd_write = false;
isSeek = true;
break; break;
case 0x00020000: case 0x00020000:
//Seek Write //Seek Write
g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000; g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000;
dd_write = true; dd_write = true;
isSeek = true;
break; break;
case 0x00080000: case 0x00080000:
//Unset Disk Changed Bit //Unset Disk Changed Bit
g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG; break; g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG; break;
case 0x00090000: 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_RST_STATE;
g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG; g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG;
//F-Zero X + Expansion Kit fix so it doesn't enable "swapping" at boot //F-Zero X + Expansion Kit fix so it doesn't enable "swapping" at boot
@ -99,6 +104,19 @@ void DiskCommand()
//Disk Inquiry //Disk Inquiry
g_Reg->ASIC_DATA = 0x00000000; break; g_Reg->ASIC_DATA = 0x00000000; break;
} }
if (isSeek)
{
//Emulate Seek Times, send interrupt later
g_SystemTimer->SetTimer(g_SystemTimer->DDSeekTimer, 0x400000, 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) void DiskReset(void)
@ -157,6 +175,9 @@ void DiskBMControl(void)
void DiskGapSectorCheck() void DiskGapSectorCheck()
{ {
//On 64DD Status Register Read
//Buffer Manager Interrupt, Gap Sector Check
if (g_Reg->ASIC_STATUS & DD_STATUS_BM_INT) if (g_Reg->ASIC_STATUS & DD_STATUS_BM_INT)
{ {
if (SECTORS_PER_BLOCK < dd_current) if (SECTORS_PER_BLOCK < dd_current)
@ -168,6 +189,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) if (!(g_Reg->ASIC_STATUS & DD_STATUS_DISK_PRES) && g_Disk != NULL && g_Settings->LoadBool(GameRunning_LoadingInProgress) == false)
{ {
dd_swapdelay++; dd_swapdelay++;
@ -190,12 +212,14 @@ void DiskBMUpdate()
//Write Data //Write Data
if (dd_current < SECTORS_PER_BLOCK) if (dd_current < SECTORS_PER_BLOCK)
{ {
//User Sector
if (!DiskBMReadWrite(true)) if (!DiskBMReadWrite(true))
g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ; g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ;
dd_current += 1; dd_current += 1;
} }
else if (dd_current < SECTORS_PER_BLOCK + 1) else if (dd_current < SECTORS_PER_BLOCK + 1)
{ {
//C2 Sector
if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK) if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK)
{ {
dd_start_block = 1 - dd_start_block; dd_start_block = 1 - dd_start_block;
@ -222,25 +246,27 @@ void DiskBMUpdate()
//Read Data //Read Data
if (((g_Reg->ASIC_CUR_TK >> 16) & 0x1FFF) == 6 && g_Reg->ASIC_CUR_SECTOR == 0 && g_Disk->GetCountry() != Country::UnknownCountry) 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_STATUS &= ~DD_STATUS_DATA_RQ;
g_Reg->ASIC_BM_STATUS |= DD_BM_STATUS_MICRO; g_Reg->ASIC_BM_STATUS |= DD_BM_STATUS_MICRO;
} }
else if (dd_current < SECTORS_PER_BLOCK) else if (dd_current < SECTORS_PER_BLOCK)
{ {
//User Sector
if (!DiskBMReadWrite(false)) if (!DiskBMReadWrite(false))
g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ; g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ;
dd_current += 1; dd_current += 1;
} }
else if (dd_current < SECTORS_PER_BLOCK + 4) else if (dd_current < SECTORS_PER_BLOCK + 4)
{ {
//READ C2 (00!) //C2 sectors (All 00s)
dd_current += 1; dd_current += 1;
if (dd_current == SECTORS_PER_BLOCK + 4) if (dd_current == SECTORS_PER_BLOCK + 4)
g_Reg->ASIC_STATUS |= DD_STATUS_C2_XFER; g_Reg->ASIC_STATUS |= DD_STATUS_C2_XFER;
} }
else if (dd_current == SECTORS_PER_BLOCK + 4) else if (dd_current == SECTORS_PER_BLOCK + 4)
{ {
//Gap Sector
if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK) if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK)
{ {
dd_start_block = 1 - dd_start_block; dd_start_block = 1 - dd_start_block;

View File

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

View File

@ -221,6 +221,16 @@ void CSystemTimer::TimerDone()
m_Reg.MI_INTR_REG |= MI_INTR_PI; m_Reg.MI_INTR_REG |= MI_INTR_PI;
m_Reg.CheckInterrupts(); m_Reg.CheckInterrupts();
break; 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: case CSystemTimer::ViTimer:
try try
{ {

View File

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

View File

@ -11783,18 +11783,6 @@ void CX86RecompilerOps::SW_Register(x86Reg Reg, uint32_t VAddr)
MoveX86regToVariable(Reg, &g_Reg->ASIC_CMD, "ASIC_CMD"); MoveX86regToVariable(Reg, &g_Reg->ASIC_CMD, "ASIC_CMD");
m_RegWorkingSet.BeforeCallDirect(); m_RegWorkingSet.BeforeCallDirect();
Call_Direct(AddressOf(&DiskCommand), "DiskCommand"); 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(); m_RegWorkingSet.AfterCallDirect();
break; break;
} }