From b428c14a27468f29e89080c548385bce4cb1e8d8 Mon Sep 17 00:00:00 2001 From: LuigiBlood Date: Fri, 5 Jun 2020 14:36:49 +0200 Subject: [PATCH 1/4] [Disk] Put Mecha Interrupt management in DiskCommand(), delay seek times --- Source/Project64-core/N64System/Mips/Disk.cpp | 32 +++++++++++++++++-- .../N64System/Mips/MemoryVirtualMem.cpp | 3 -- .../N64System/Mips/SystemTiming.cpp | 10 ++++++ .../N64System/Mips/SystemTiming.h | 2 ++ .../Recompiler/x86/x86RecompilerOps.cpp | 12 ------- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/Disk.cpp b/Source/Project64-core/N64System/Mips/Disk.cpp index b4354c2a6..5ac125965 100644 --- a/Source/Project64-core/N64System/Mips/Disk.cpp +++ b/Source/Project64-core/N64System/Mips/Disk.cpp @@ -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,19 @@ void DiskCommand() //Disk Inquiry 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) @@ -157,6 +175,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 +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) { dd_swapdelay++; @@ -190,12 +212,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 +246,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; diff --git a/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp b/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp index 9a713fd53..455444f4f 100755 --- a/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp +++ b/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp @@ -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 diff --git a/Source/Project64-core/N64System/Mips/SystemTiming.cpp b/Source/Project64-core/N64System/Mips/SystemTiming.cpp index 9af409bd4..4602e16a5 100644 --- a/Source/Project64-core/N64System/Mips/SystemTiming.cpp +++ b/Source/Project64-core/N64System/Mips/SystemTiming.cpp @@ -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 { diff --git a/Source/Project64-core/N64System/Mips/SystemTiming.h b/Source/Project64-core/N64System/Mips/SystemTiming.h index d75c487d8..053a74534 100644 --- a/Source/Project64-core/N64System/Mips/SystemTiming.h +++ b/Source/Project64-core/N64System/Mips/SystemTiming.h @@ -32,6 +32,8 @@ public: RspTimer, RSPTimerDlist, DDPiTimer, + DDSeekTimer, + DDMotorTimer, MaxTimer }; diff --git a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp index 9e99a9d15..9f9220b22 100644 --- a/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp +++ b/Source/Project64-core/N64System/Recompiler/x86/x86RecompilerOps.cpp @@ -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; } From 2ad2b969f0dbd466f885a6346cc1af8eb0a35d82 Mon Sep 17 00:00:00 2001 From: LuigiBlood Date: Fri, 5 Jun 2020 16:48:19 +0200 Subject: [PATCH 2/4] [Disk] Emulate Motor Status & 3779 mSEC disk seek speeds --- Source/Project64-core/N64System/Mips/Disk.cpp | 56 ++++++++++++++++++- .../N64System/Mips/SystemTiming.cpp | 2 +- Source/Project64-core/N64System/N64Class.cpp | 4 +- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/Disk.cpp b/Source/Project64-core/N64System/Mips/Disk.cpp index 5ac125965..b7032f5f7 100644 --- a/Source/Project64-core/N64System/Mips/Disk.cpp +++ b/Source/Project64-core/N64System/Mips/Disk.cpp @@ -108,7 +108,61 @@ void DiskCommand() if (isSeek) { //Emulate Seek Times, send interrupt later - g_SystemTimer->SetTimer(g_SystemTimer->DDSeekTimer, 0x400000, false); + uint32_t seektime = 0x179200; + if (g_Reg->ASIC_STATUS & DD_STATUS_MTR_N_SPIN) + { + seektime += 0x800000; + g_Reg->ASIC_STATUS &= ~DD_STATUS_MTR_N_SPIN; + } + + //Get Zone + 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; + } + } + switch (zone) + { + case 0: + default: + break; + case 1: + seektime += 0x1900; + break; + case 2: + seektime += 0x2A00; + break; + case 3: + seektime += 0x4500; + break; + case 4: + seektime += 0x5E00; + break; + case 5: + seektime += 0x7A00; + break; + case 6: + seektime += 0x9700; + break; + case 7: + seektime += 0xAF00; + break; + case 8: + seektime += 0xCC00; + break; + } + + g_SystemTimer->SetTimer(g_SystemTimer->DDSeekTimer, seektime, false); + g_SystemTimer->SetTimer(g_SystemTimer->DDMotorTimer, 0x6000000, false); } else { diff --git a/Source/Project64-core/N64System/Mips/SystemTiming.cpp b/Source/Project64-core/N64System/Mips/SystemTiming.cpp index 4602e16a5..1b0a39d37 100644 --- a/Source/Project64-core/N64System/Mips/SystemTiming.cpp +++ b/Source/Project64-core/N64System/Mips/SystemTiming.cpp @@ -229,7 +229,7 @@ void CSystemTimer::TimerDone() break; case CSystemTimer::DDMotorTimer: g_SystemTimer->StopTimer(CSystemTimer::DDMotorTimer); - g_Reg->ASIC_STATUS &= ~DD_STATUS_MTR_N_SPIN; + g_Reg->ASIC_STATUS |= DD_STATUS_MTR_N_SPIN; break; case CSystemTimer::ViTimer: try diff --git a/Source/Project64-core/N64System/N64Class.cpp b/Source/Project64-core/N64System/N64Class.cpp index 5f13bd660..ca7e03741 100644 --- a/Source/Project64-core/N64System/N64Class.cpp +++ b/Source/Project64-core/N64System/N64Class.cpp @@ -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; From cc2c4e8786629e84a9eab3b690dccdb79c1799fe Mon Sep 17 00:00:00 2001 From: LuigiBlood Date: Fri, 5 Jun 2020 17:25:01 +0200 Subject: [PATCH 3/4] [Disk] Timing changes for Motor --- Source/Project64-core/N64System/Mips/Disk.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/Disk.cpp b/Source/Project64-core/N64System/Mips/Disk.cpp index b7032f5f7..98c1138ea 100644 --- a/Source/Project64-core/N64System/Mips/Disk.cpp +++ b/Source/Project64-core/N64System/Mips/Disk.cpp @@ -109,13 +109,15 @@ void DiskCommand() { //Emulate Seek Times, send interrupt later uint32_t seektime = 0x179200; + + //Start Motor, can take half a second, delay the response if (g_Reg->ASIC_STATUS & DD_STATUS_MTR_N_SPIN) { - seektime += 0x800000; + seektime += (0x5A00000 / 2); g_Reg->ASIC_STATUS &= ~DD_STATUS_MTR_N_SPIN; } - //Get Zone + //Get Zone to calculate seek times uint32_t track = g_Reg->ASIC_CUR_TK >> 16 & 0x0FFF; uint32_t zone = 0; uint32_t zonebound = 0; @@ -130,6 +132,8 @@ void DiskCommand() break; } } + + //Add delay depending on the zone switch (zone) { case 0: @@ -161,8 +165,11 @@ void DiskCommand() break; } + //Set timer for seek response g_SystemTimer->SetTimer(g_SystemTimer->DDSeekTimer, seektime, false); - g_SystemTimer->SetTimer(g_SystemTimer->DDMotorTimer, 0x6000000, 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 { From 737383b69530d4f37ffb404d4927731829ff9730 Mon Sep 17 00:00:00 2001 From: LuigiBlood Date: Sat, 6 Jun 2020 00:28:02 +0200 Subject: [PATCH 4/4] [Disk] Simplify Seek Timing calculation at expense of accuracy --- Source/Project64-core/N64System/Mips/Disk.cpp | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/Source/Project64-core/N64System/Mips/Disk.cpp b/Source/Project64-core/N64System/Mips/Disk.cpp index 98c1138ea..0f9052fa2 100644 --- a/Source/Project64-core/N64System/Mips/Disk.cpp +++ b/Source/Project64-core/N64System/Mips/Disk.cpp @@ -108,7 +108,7 @@ void DiskCommand() if (isSeek) { //Emulate Seek Times, send interrupt later - uint32_t seektime = 0x179200; + uint32_t seektime = 0; //Start Motor, can take half a second, delay the response if (g_Reg->ASIC_STATUS & DD_STATUS_MTR_N_SPIN) @@ -133,35 +133,26 @@ void DiskCommand() } } - //Add delay depending on the zone + //Add seek delay depending on the zone (this is inaccurate timing, but close enough) + seektime += 0x179200; + switch (zone) { case 0: - default: - break; case 1: - seektime += 0x1900; + default: + seektime += track * 38; break; case 2: - seektime += 0x2A00; - break; case 3: - seektime += 0x4500; - break; case 4: - seektime += 0x5E00; - break; case 5: - seektime += 0x7A00; - break; case 6: - seektime += 0x9700; - break; case 7: - seektime += 0xAF00; + seektime += 0x13C * 38 + (track - 0x13C) * 46; break; case 8: - seektime += 0xCC00; + seektime += 0x13C * 38 + 0x2E9 * 46 + (track - 0x425) * 58; break; }