2016-01-19 18:53:18 +00:00
|
|
|
/****************************************************************************
|
|
|
|
* *
|
|
|
|
* Project64 - A Nintendo 64 emulator. *
|
|
|
|
* http://www.pj64-emu.com/ *
|
|
|
|
* Copyright (C) 2012 Project64. All rights reserved. *
|
|
|
|
* *
|
|
|
|
* License: *
|
|
|
|
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
|
|
|
* *
|
|
|
|
****************************************************************************/
|
2016-01-22 02:17:25 +00:00
|
|
|
// Based from MAME's N64DD driver code by Happy_
|
2016-01-19 18:53:18 +00:00
|
|
|
#include "stdafx.h"
|
2016-01-20 13:31:29 +00:00
|
|
|
#include "Disk.h"
|
|
|
|
#include <Project64-core/N64System/N64DiskClass.h>
|
2016-01-19 18:53:18 +00:00
|
|
|
#include <Project64-core/N64System/SystemGlobals.h>
|
|
|
|
#include <Project64-core/N64System/Mips/RegisterClass.h>
|
2016-01-23 21:44:58 +00:00
|
|
|
#include <Project64-core/N64System/Mips/SystemTiming.h>
|
2016-01-19 18:53:18 +00:00
|
|
|
|
2016-01-27 21:41:31 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <Windows.h>
|
|
|
|
#else
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
2016-05-25 02:06:10 +00:00
|
|
|
uint8_t dd_swapdelay;
|
|
|
|
|
2016-01-20 13:31:29 +00:00
|
|
|
bool dd_write;
|
|
|
|
bool dd_reset_hold;
|
|
|
|
uint32_t dd_track_offset, dd_zone;
|
2016-01-20 16:43:23 +00:00
|
|
|
uint32_t dd_start_block, dd_current;
|
2016-01-20 13:31:29 +00:00
|
|
|
|
2016-01-19 18:53:18 +00:00
|
|
|
void DiskCommand()
|
|
|
|
{
|
2016-01-20 13:31:29 +00:00
|
|
|
//ASIC_CMD_STATUS - Commands
|
|
|
|
uint32_t cmd = g_Reg->ASIC_CMD;
|
2019-08-10 19:18:17 +00:00
|
|
|
WriteTrace(TraceN64System, TraceDebug, "DD CMD %08X - DATA %08X", cmd, g_Reg->ASIC_DATA);
|
2016-01-19 18:53:18 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
2016-01-20 13:31:29 +00:00
|
|
|
SYSTEMTIME sysTime;
|
|
|
|
::GetLocalTime(&sysTime);
|
|
|
|
|
|
|
|
//BCD format needed for 64DD RTC
|
2016-08-27 21:29:11 +00:00
|
|
|
uint8_t year = (uint8_t)(((sysTime.wYear / 10 % 10) << 4) | (sysTime.wYear % 10));
|
2016-01-20 13:31:29 +00:00
|
|
|
uint8_t month = (uint8_t)(((sysTime.wMonth / 10) << 4) | (sysTime.wMonth % 10));
|
|
|
|
uint8_t day = (uint8_t)(((sysTime.wDay / 10) << 4) | (sysTime.wDay % 10));
|
|
|
|
uint8_t hour = (uint8_t)(((sysTime.wHour / 10) << 4) | (sysTime.wHour % 10));
|
|
|
|
uint8_t minute = (uint8_t)(((sysTime.wMinute / 10) << 4) | (sysTime.wMinute % 10));
|
|
|
|
uint8_t second = (uint8_t)(((sysTime.wSecond / 10) << 4) | (sysTime.wSecond % 10));
|
2016-01-19 18:53:18 +00:00
|
|
|
#else
|
2016-01-20 13:31:29 +00:00
|
|
|
time_t ltime;
|
|
|
|
ltime = time(<ime);
|
2016-01-27 21:41:31 +00:00
|
|
|
|
2016-01-20 13:31:29 +00:00
|
|
|
struct tm result = { 0 };
|
|
|
|
localtime_r(<ime, &result);
|
|
|
|
|
|
|
|
//BCD format needed for 64DD RTC
|
2016-08-27 21:29:11 +00:00
|
|
|
uint8_t year = (uint8_t)(((result.tm_year / 10 % 10) << 4) | (result.tm_year % 10));
|
2016-01-27 21:41:31 +00:00
|
|
|
uint8_t month = (uint8_t)((((result.tm_mon + 1) / 10) << 4) | ((result.tm_mon + 1) % 10));
|
2016-01-20 13:31:29 +00:00
|
|
|
uint8_t day = (uint8_t)(((result.tm_mday / 10) << 4) | (result.tm_mday % 10));
|
|
|
|
uint8_t hour = (uint8_t)(((result.tm_hour / 10) << 4) | (result.tm_hour % 10));
|
|
|
|
uint8_t minute = (uint8_t)(((result.tm_min / 10) << 4) | (result.tm_min % 10));
|
|
|
|
uint8_t second = (uint8_t)(((result.tm_sec / 10) << 4) | (result.tm_sec % 10));
|
2016-01-19 18:53:18 +00:00
|
|
|
#endif
|
|
|
|
|
2016-01-20 13:31:29 +00:00
|
|
|
switch (cmd & 0xFFFF0000)
|
|
|
|
{
|
|
|
|
case 0x00010000:
|
|
|
|
//Seek Read
|
|
|
|
g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000;
|
|
|
|
dd_write = false;
|
|
|
|
break;
|
|
|
|
case 0x00020000:
|
|
|
|
//Seek Write
|
|
|
|
g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000;
|
|
|
|
dd_write = true;
|
|
|
|
break;
|
|
|
|
case 0x00080000:
|
|
|
|
//Unset Disk Changed Bit
|
|
|
|
g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG; break;
|
|
|
|
case 0x00090000:
|
|
|
|
//Unset Reset Bit
|
2016-05-25 02:06:10 +00:00
|
|
|
g_Reg->ASIC_STATUS &= ~DD_STATUS_RST_STATE;
|
|
|
|
g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG;
|
2016-06-02 14:35:10 +00:00
|
|
|
//F-Zero X + Expansion Kit fix so it doesn't enable "swapping" at boot
|
|
|
|
dd_swapdelay = 0;
|
|
|
|
if (g_Disk != NULL)
|
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_DISK_PRES;
|
2016-05-25 02:06:10 +00:00
|
|
|
break;
|
2016-01-20 13:31:29 +00:00
|
|
|
case 0x00120000:
|
|
|
|
//RTC Get Year & Month
|
|
|
|
g_Reg->ASIC_DATA = (year << 24) | (month << 16); break;
|
|
|
|
case 0x00130000:
|
|
|
|
//RTC Get Day & Hour
|
|
|
|
g_Reg->ASIC_DATA = (day << 24) | (hour << 16); break;
|
|
|
|
case 0x00140000:
|
|
|
|
//RTC Get Minute & Second
|
|
|
|
g_Reg->ASIC_DATA = (minute << 24) | (second << 16); break;
|
|
|
|
case 0x001B0000:
|
|
|
|
//Disk Inquiry
|
|
|
|
g_Reg->ASIC_DATA = 0x00000000; break;
|
|
|
|
}
|
2016-01-19 18:53:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiskReset(void)
|
|
|
|
{
|
2016-01-20 13:31:29 +00:00
|
|
|
//ASIC_HARD_RESET 0xAAAA0000
|
2016-05-25 02:06:10 +00:00
|
|
|
WriteTrace(TraceN64System, TraceDebug, "DD RESET");
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_RST_STATE;
|
2016-05-25 02:06:10 +00:00
|
|
|
dd_swapdelay = 0;
|
|
|
|
if (g_Disk != NULL)
|
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_DISK_PRES;
|
2016-01-19 18:53:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiskBMControl(void)
|
|
|
|
{
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_CUR_SECTOR = g_Reg->ASIC_BM_CTL & 0x00FF0000;
|
2016-01-20 16:43:23 +00:00
|
|
|
|
2016-01-20 13:31:29 +00:00
|
|
|
if ((g_Reg->ASIC_CUR_SECTOR >> 16) == 0x00)
|
|
|
|
{
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_start_block = 0;
|
|
|
|
dd_current = 0;
|
2016-01-20 13:31:29 +00:00
|
|
|
}
|
|
|
|
else if ((g_Reg->ASIC_CUR_SECTOR >> 16) == 0x5A)
|
|
|
|
{
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_start_block = 1;
|
|
|
|
dd_current = 0;
|
2016-01-20 13:31:29 +00:00
|
|
|
}
|
2016-01-20 16:43:23 +00:00
|
|
|
|
2016-01-20 13:31:29 +00:00
|
|
|
if (g_Reg->ASIC_BM_CTL & DD_BM_CTL_BLK_TRANS)
|
|
|
|
g_Reg->ASIC_BM_STATUS |= DD_BM_STATUS_BLOCK;
|
|
|
|
|
|
|
|
if (g_Reg->ASIC_BM_CTL & DD_BM_CTL_MECHA_RST)
|
|
|
|
g_Reg->ASIC_STATUS &= ~DD_STATUS_MECHA_INT;
|
|
|
|
|
|
|
|
if (g_Reg->ASIC_BM_CTL & DD_BM_CTL_RESET)
|
|
|
|
dd_reset_hold = true;
|
|
|
|
|
|
|
|
if (!(g_Reg->ASIC_BM_CTL & DD_BM_CTL_RESET) && dd_reset_hold)
|
|
|
|
{
|
|
|
|
dd_reset_hold = false;
|
|
|
|
g_Reg->ASIC_STATUS &= ~(DD_STATUS_BM_INT | DD_STATUS_BM_ERR | DD_STATUS_DATA_RQ | DD_STATUS_C2_XFER);
|
|
|
|
g_Reg->ASIC_BM_STATUS = 0;
|
|
|
|
g_Reg->ASIC_CUR_SECTOR = 0;
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_start_block = 0;
|
|
|
|
dd_current = 0;
|
2016-01-20 13:31:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(g_Reg->ASIC_STATUS & DD_STATUS_MECHA_INT) && !(g_Reg->ASIC_STATUS & DD_STATUS_BM_INT))
|
|
|
|
g_Reg->FAKE_CAUSE_REGISTER &= ~CAUSE_IP3;
|
|
|
|
|
|
|
|
if (g_Reg->ASIC_BM_CTL & DD_BM_CTL_START)
|
|
|
|
{
|
|
|
|
g_Reg->ASIC_BM_STATUS |= DD_BM_STATUS_RUNNING;
|
|
|
|
DiskBMUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiskGapSectorCheck()
|
|
|
|
{
|
|
|
|
if (g_Reg->ASIC_STATUS & DD_STATUS_BM_INT)
|
|
|
|
{
|
2016-01-20 16:43:23 +00:00
|
|
|
if (SECTORS_PER_BLOCK < dd_current)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
|
|
|
g_Reg->ASIC_STATUS &= ~DD_STATUS_BM_INT;
|
2016-01-23 21:44:58 +00:00
|
|
|
g_Reg->FAKE_CAUSE_REGISTER &= ~CAUSE_IP3;
|
|
|
|
g_Reg->CheckInterrupts();
|
2016-01-20 13:31:29 +00:00
|
|
|
DiskBMUpdate();
|
|
|
|
}
|
|
|
|
}
|
2016-05-25 02:06:10 +00:00
|
|
|
|
2016-05-29 23:09:52 +00:00
|
|
|
if (!(g_Reg->ASIC_STATUS & DD_STATUS_DISK_PRES) && g_Disk != NULL && g_Settings->LoadBool(GameRunning_LoadingInProgress) == false)
|
2016-05-25 02:06:10 +00:00
|
|
|
{
|
|
|
|
dd_swapdelay++;
|
2016-05-29 23:09:52 +00:00
|
|
|
if (dd_swapdelay >= 50)
|
2016-05-25 02:06:10 +00:00
|
|
|
{
|
|
|
|
g_Reg->ASIC_STATUS |= (DD_STATUS_DISK_PRES | DD_STATUS_DISK_CHNG);
|
|
|
|
dd_swapdelay = 0;
|
|
|
|
WriteTrace(TraceN64System, TraceDebug, "DD SWAP DONE");
|
|
|
|
}
|
|
|
|
}
|
2016-01-20 13:31:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiskBMUpdate()
|
|
|
|
{
|
|
|
|
if (!(g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_RUNNING))
|
|
|
|
return;
|
2016-01-23 21:44:58 +00:00
|
|
|
|
2016-01-20 13:31:29 +00:00
|
|
|
if (dd_write)
|
|
|
|
{
|
|
|
|
//Write Data
|
2016-01-25 14:47:12 +00:00
|
|
|
if (dd_current < SECTORS_PER_BLOCK)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
|
|
|
DiskBMWrite();
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_current += 1;
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ;
|
|
|
|
}
|
2016-01-20 16:43:23 +00:00
|
|
|
else if (dd_current < SECTORS_PER_BLOCK + 1)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
|
|
|
if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK)
|
|
|
|
{
|
2016-01-25 14:47:12 +00:00
|
|
|
dd_start_block = 1 - dd_start_block;
|
|
|
|
dd_current = 0;
|
2016-01-20 13:31:29 +00:00
|
|
|
DiskBMWrite();
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_current += 1;
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_BM_STATUS &= ~DD_BM_STATUS_BLOCK;
|
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_current += 1;
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_BM_STATUS &= ~DD_BM_STATUS_RUNNING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_BM_INT;
|
|
|
|
g_Reg->FAKE_CAUSE_REGISTER |= CAUSE_IP3;
|
|
|
|
g_Reg->CheckInterrupts();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Read Data
|
2016-01-30 21:23:27 +00:00
|
|
|
if (((g_Reg->ASIC_CUR_TK >> 16) & 0x1FFF) == 6 && g_Reg->ASIC_CUR_SECTOR == 0)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
|
|
|
g_Reg->ASIC_STATUS &= ~DD_STATUS_DATA_RQ;
|
|
|
|
g_Reg->ASIC_BM_STATUS |= DD_BM_STATUS_MICRO;
|
|
|
|
}
|
2016-01-22 02:17:25 +00:00
|
|
|
else if (dd_current < SECTORS_PER_BLOCK)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
|
|
|
DiskBMRead();
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_current += 1;
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ;
|
|
|
|
}
|
2016-01-20 16:43:23 +00:00
|
|
|
else if (dd_current < SECTORS_PER_BLOCK + 4)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
|
|
|
//READ C2 (00!)
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_current += 1;
|
|
|
|
if (dd_current == SECTORS_PER_BLOCK + 4)
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_C2_XFER;
|
|
|
|
}
|
2016-01-20 16:43:23 +00:00
|
|
|
else if (dd_current == SECTORS_PER_BLOCK + 4)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
|
|
|
if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK)
|
|
|
|
{
|
2016-01-20 16:43:23 +00:00
|
|
|
dd_start_block = 1 - dd_start_block;
|
|
|
|
dd_current = 0;
|
2016-01-20 13:31:29 +00:00
|
|
|
g_Reg->ASIC_BM_STATUS &= ~DD_BM_STATUS_BLOCK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_Reg->ASIC_BM_STATUS &= ~DD_BM_STATUS_RUNNING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_Reg->ASIC_STATUS |= DD_STATUS_BM_INT;
|
|
|
|
g_Reg->FAKE_CAUSE_REGISTER |= CAUSE_IP3;
|
|
|
|
g_Reg->CheckInterrupts();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiskBMRead()
|
|
|
|
{
|
2019-08-10 19:18:17 +00:00
|
|
|
DiskBMReadWrite(false);
|
2016-01-20 13:31:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiskBMWrite()
|
|
|
|
{
|
2019-08-10 19:18:17 +00:00
|
|
|
DiskBMReadWrite(true);
|
2016-01-20 13:31:29 +00:00
|
|
|
}
|
|
|
|
|
2019-08-10 19:18:17 +00:00
|
|
|
void DiskBMReadWrite(bool write)
|
2016-01-20 13:31:29 +00:00
|
|
|
{
|
2019-08-10 19:18:17 +00:00
|
|
|
uint16_t head = ((g_Reg->ASIC_CUR_TK >> 16) / 0x1000) & 1;
|
2016-01-20 13:31:29 +00:00
|
|
|
uint16_t track = (g_Reg->ASIC_CUR_TK >> 16) & 0xFFF;
|
2019-08-10 19:18:17 +00:00
|
|
|
uint16_t block = dd_start_block;
|
|
|
|
uint16_t sector = dd_current;
|
|
|
|
uint16_t sectorsize = (((g_Reg->ASIC_HOST_SECBYTE & 0x00FF0000) >> 16) + 1);
|
|
|
|
|
2019-08-11 09:45:05 +00:00
|
|
|
uint32_t addr = g_Disk->GetDiskAddressBlock(head, track, block, sector, sectorsize);
|
2019-08-10 19:18:17 +00:00
|
|
|
g_Disk->SetDiskAddressBuffer(addr);
|
2016-01-25 14:47:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiskDMACheck(void)
|
|
|
|
{
|
|
|
|
if (g_Reg->PI_CART_ADDR_REG == 0x05000000)
|
|
|
|
{
|
|
|
|
g_Reg->ASIC_STATUS &= ~(DD_STATUS_BM_INT | DD_STATUS_BM_ERR | DD_STATUS_C2_XFER);
|
|
|
|
g_Reg->FAKE_CAUSE_REGISTER &= ~CAUSE_IP3;
|
|
|
|
g_Reg->CheckInterrupts();
|
|
|
|
}
|
|
|
|
else if (g_Reg->PI_CART_ADDR_REG == 0x05000400)
|
|
|
|
{
|
|
|
|
g_Reg->ASIC_STATUS &= ~(DD_STATUS_BM_INT | DD_STATUS_BM_ERR | DD_STATUS_DATA_RQ);
|
|
|
|
g_Reg->FAKE_CAUSE_REGISTER &= ~CAUSE_IP3;
|
|
|
|
g_Reg->CheckInterrupts();
|
|
|
|
}
|
2016-01-19 18:53:18 +00:00
|
|
|
}
|