diff --git a/Lang/English.pj.Lang b/Lang/English.pj.Lang index ab609e861..f17aa2489 100644 --- a/Lang/English.pj.Lang +++ b/Lang/English.pj.Lang @@ -96,6 +96,7 @@ #212# "Edit Game Settings" #213# "Edit Cheats" #214# "Graphics Plugin" +#215# "Play Game with Disk" //Alternate Name to save Slot #220# "Save Slot - Default" diff --git a/Source/Project64-core/AppInit.cpp b/Source/Project64-core/AppInit.cpp index 0b62fdfac..ae9c63e9e 100644 --- a/Source/Project64-core/AppInit.cpp +++ b/Source/Project64-core/AppInit.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "Settings/SettingType/SettingsType-Application.h" static void FixDirectories(void); @@ -152,8 +153,8 @@ void TraceDone(void) const char * AppName ( void ) { - static stdstr_f ApplicationName("Project64 %s", VER_FILE_VERSION_STR); - return ApplicationName.c_str(); + static stdstr_f ApplicationName("Project64 %s", VER_FILE_VERSION_STR); + return ApplicationName.c_str(); } static bool ParseCommand(int32_t argc, char **argv) @@ -168,8 +169,8 @@ static bool ParseCommand(int32_t argc, char **argv) if (strcmp(argv[i], "--basedir") == 0 && ArgsLeft >= 1) { g_Settings->SaveString(Cmd_BaseDirectory, argv[i + 1]); - CSettingTypeApplication::Initialize(AppName()); - i++; + CSettingTypeApplication::Initialize(AppName()); + i++; } else if (strcmp(argv[i], "--help") == 0) { @@ -195,11 +196,11 @@ bool AppInit(CNotification * Notify, int argc, char **argv) { g_Notify = Notify; InitializeLog(); - if (Notify == NULL) - { - WriteTrace(TraceAppInit, TraceError, "No Notification class passed"); - return false; - } + if (Notify == NULL) + { + WriteTrace(TraceAppInit, TraceError, "No Notification class passed"); + return false; + } g_Settings = new CSettings; g_Settings->Initialize(AppName()); @@ -232,14 +233,14 @@ bool AppInit(CNotification * Notify, int argc, char **argv) g_Lang = new CLanguage(); g_Lang->LoadCurrentStrings(); g_Notify->AppInitDone(); - WriteTrace(TraceAppInit, TraceDebug, "Initialized Successfully"); - return true; + WriteTrace(TraceAppInit, TraceDebug, "Initialized Successfully"); + return true; } catch (...) { g_Notify->DisplayError(stdstr_f("Exception caught\nFile: %s\nLine: %d", __FILE__, __LINE__).c_str()); - WriteTrace(TraceAppInit, TraceError, "Exception caught, Init was not successfull"); - return false; + WriteTrace(TraceAppInit, TraceError, "Exception caught, Init was not successfull"); + return false; } } @@ -249,6 +250,8 @@ void AppCleanup(void) CleanupTrace(); if (g_Rom) { delete g_Rom; g_Rom = NULL; } + if (g_DDRom) { delete g_DDRom; g_DDRom = NULL; } + if (g_Disk) { delete g_Disk; g_Disk = NULL; } if (g_Plugins) { delete g_Plugins; g_Plugins = NULL; } if (g_Settings) { delete g_Settings; g_Settings = NULL; } if (g_Lang) { delete g_Lang; g_Lang = NULL; } diff --git a/Source/Project64-core/Multilanguage.h b/Source/Project64-core/Multilanguage.h index 85c139832..64bf79658 100644 --- a/Source/Project64-core/Multilanguage.h +++ b/Source/Project64-core/Multilanguage.h @@ -125,6 +125,7 @@ enum LanguageStringID{ POPUP_SETTINGS = 212, POPUP_CHEATS = 213, POPUP_GFX_PLUGIN = 214, + POPUP_PLAYDISK = 215, //selecting save slot SAVE_SLOT_DEFAULT = 220, diff --git a/Source/Project64-core/Multilanguage/LanguageClass.cpp b/Source/Project64-core/Multilanguage/LanguageClass.cpp index cc6d99e16..861c1f186 100644 --- a/Source/Project64-core/Multilanguage/LanguageClass.cpp +++ b/Source/Project64-core/Multilanguage/LanguageClass.cpp @@ -133,6 +133,7 @@ void CLanguage::LoadDefaultStrings(void) DEF_STR(POPUP_SETTINGS, "Edit Game Settings"); DEF_STR(POPUP_CHEATS, "Edit Cheats"); DEF_STR(POPUP_GFX_PLUGIN, "Graphics Plugin"); + DEF_STR(POPUP_PLAYDISK, "Play Game with Disk"); //Alternate Name to save Slot DEF_STR(SAVE_SLOT_DEFAULT, "Save Slot - Default"); diff --git a/Source/Project64-core/N64System/Mips/Disk.cpp b/Source/Project64-core/N64System/Mips/Disk.cpp index 8a13c8a22..332056d17 100644 --- a/Source/Project64-core/N64System/Mips/Disk.cpp +++ b/Source/Project64-core/N64System/Mips/Disk.cpp @@ -8,77 +8,316 @@ * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ +// Based from MAME's N64DD driver code by Happy_ #pragma once #include "stdafx.h" +#include "Disk.h" +#include #include #include +#include + +bool dd_write; +bool dd_reset_hold; +uint32_t dd_track_offset, dd_zone; +uint32_t dd_start_block, dd_current; void DiskCommand() { - //ASIC_CMD_STATUS - Commands - uint32_t cmd = g_Reg->ASIC_CMD; + if (g_Disk != NULL) + g_Reg->ASIC_STATUS |= DD_STATUS_DISK_PRES; + + //ASIC_CMD_STATUS - Commands + uint32_t cmd = g_Reg->ASIC_CMD; #ifdef _WIN32 - SYSTEMTIME sysTime; - ::GetLocalTime(&sysTime); - //stdstr_f timestamp("%04d/%02d/%02d %02d:%02d:%02d.%03d %05d,", sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds, GetCurrentThreadId()); + SYSTEMTIME sysTime; + ::GetLocalTime(&sysTime); - //BCD format needed for 64DD RTC - uint8_t year = (uint8_t)(((sysTime.wYear / 10) << 4) | (sysTime.wYear % 10)); - 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)); + //BCD format needed for 64DD RTC + uint8_t year = (uint8_t)(((sysTime.wYear / 10) << 4) | (sysTime.wYear % 10)); + 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)); #else - time_t ltime; - ltime = time(<ime); - - struct tm result = { 0 }; - localtime_r(<ime, &result); + time_t ltime; + ltime = time(<ime); + + struct tm result = { 0 }; + localtime_r(<ime, &result); - //stdstr_f timestamp("%04d/%02d/%02d %02d:%02d:%02d.%03d %05d,", result.tm_year + 1900, result.tm_mon + 1, result.tm_mday, result.tm_hour, result.tm_min, result.tm_sec, milliseconds, GetCurrentThreadId()); - - //BCD format needed for 64DD RTC - uint8_t year = (uint8_t)(((result.tm_year / 10) << 4) | (result.tm_year % 10)); - uint8_t month = (uint8_t)(((result.tm_mon / 10) << 4) | (result.tm_mon % 10)); - 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)); + //BCD format needed for 64DD RTC + uint8_t year = (uint8_t)(((result.tm_year / 10) << 4) | (result.tm_year % 10)); + uint8_t month = (uint8_t)(((result.tm_mon / 10) << 4) | (result.tm_mon % 10)); + 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)); #endif - switch (cmd & 0xFFFF0000) - { - case 0x00080000: - //Unset Disk Changed Bit - g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG; break; - case 0x00090000: - //Unset Reset Bit - g_Reg->ASIC_STATUS &= ~DD_STATUS_RST_STATE; break; - 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; - } + switch (cmd & 0xFFFF0000) + { + case 0x00010000: + //Seek Read + g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000; + DiskSetOffset(); + dd_write = false; + break; + case 0x00020000: + //Seek Write + g_Reg->ASIC_CUR_TK = g_Reg->ASIC_DATA | 0x60000000; + DiskSetOffset(); + dd_write = true; + break; + case 0x00080000: + //Unset Disk Changed Bit + g_Reg->ASIC_STATUS &= ~DD_STATUS_DISK_CHNG; break; + case 0x00090000: + //Unset Reset Bit + g_Reg->ASIC_STATUS &= ~DD_STATUS_RST_STATE; break; + 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; + } } void DiskReset(void) { - //ASIC_HARD_RESET 0xAAAA0000 - g_Reg->ASIC_STATUS |= DD_STATUS_RST_STATE; + //ASIC_HARD_RESET 0xAAAA0000 + g_Reg->ASIC_STATUS |= DD_STATUS_RST_STATE; } void DiskBMControl(void) { - if (g_Reg->ASIC_BM_CTL & DD_BM_CTL_MECHA_RST) - { - g_Reg->ASIC_STATUS &= ~DD_STATUS_MECHA_INT; - g_Reg->FAKE_CAUSE_REGISTER &= ~CAUSE_IP3; - } + g_Reg->ASIC_CUR_SECTOR = g_Reg->ASIC_BM_CTL & 0x00FF0000; + + if ((g_Reg->ASIC_CUR_SECTOR >> 16) == 0x00) + { + dd_start_block = 0; + dd_current = 0; + } + else if ((g_Reg->ASIC_CUR_SECTOR >> 16) == 0x5A) + { + dd_start_block = 1; + dd_current = 0; + } + + 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; + dd_start_block = 0; + dd_current = 0; + } + + 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) + { + if (SECTORS_PER_BLOCK < dd_current) + { + g_Reg->ASIC_STATUS &= ~DD_STATUS_BM_INT; + g_Reg->FAKE_CAUSE_REGISTER &= ~CAUSE_IP3; + g_Reg->CheckInterrupts(); + DiskBMUpdate(); + } + } +} + +void DiskBMUpdate() +{ + if (!(g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_RUNNING)) + return; + + if (dd_write) + { + //Write Data + if (dd_current < SECTORS_PER_BLOCK) + { + DiskBMWrite(); + dd_current += 1; + g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ; + } + else if (dd_current < SECTORS_PER_BLOCK + 1) + { + if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK) + { + dd_start_block = 1 - dd_start_block; + dd_current = 0; + DiskBMWrite(); + dd_current += 1; + g_Reg->ASIC_BM_STATUS &= ~DD_BM_STATUS_BLOCK; + g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ; + } + else + { + dd_current += 1; + 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 + if (((g_Reg->ASIC_CUR_TK >> 16) & 0xFFF) == 6 && g_Reg->ASIC_CUR_SECTOR == 0) + { + g_Reg->ASIC_STATUS &= ~DD_STATUS_DATA_RQ; + g_Reg->ASIC_BM_STATUS |= DD_BM_STATUS_MICRO; + } + else if (dd_current < SECTORS_PER_BLOCK) + { + DiskBMRead(); + dd_current += 1; + g_Reg->ASIC_STATUS |= DD_STATUS_DATA_RQ; + } + else if (dd_current < SECTORS_PER_BLOCK + 4) + { + //READ C2 (00!) + 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) + { + if (g_Reg->ASIC_BM_STATUS & DD_BM_STATUS_BLOCK) + { + dd_start_block = 1 - dd_start_block; + dd_current = 0; + 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() +{ + uint32_t sector = 0; + sector += dd_track_offset; + sector += dd_start_block * SECTORS_PER_BLOCK * ddZoneSecSize[dd_zone]; + sector += (dd_current) * (((g_Reg->ASIC_HOST_SECBYTE & 0x00FF0000) >> 16) + 1); + WriteTrace(TraceN64System, TraceDebug, "READ Block %d Sector %02X - %08X", ((g_Reg->ASIC_CUR_TK & 0x0FFF0000) >> 15) | dd_start_block, dd_current, sector); + g_Disk->SetDiskAddressBuffer(sector); + return; +} + +void DiskBMWrite() +{ + uint32_t sector = 0; + sector += dd_track_offset; + sector += dd_start_block * SECTORS_PER_BLOCK * ddZoneSecSize[dd_zone]; + sector += (dd_current) * (((g_Reg->ASIC_HOST_SECBYTE & 0x00FF0000) >> 16) + 1); + WriteTrace(TraceN64System, TraceDebug, "WRITE Block %d Sector %02X - %08X", ((g_Reg->ASIC_CUR_TK & 0x0FFF0000) >> 15) | dd_start_block, dd_current, sector); + g_Disk->SetDiskAddressBuffer(sector); + return; +} + +void DiskSetOffset() +{ + uint16_t head = ((g_Reg->ASIC_CUR_TK >> 16) & 0x1000) >> 9; // Head * 8 + uint16_t track = (g_Reg->ASIC_CUR_TK >> 16) & 0xFFF; + uint16_t tr_off = 0; + + if (track >= 0x425) + { + dd_zone = 7 + head; + tr_off = track - 0x425; + } + else if (track >= 0x390) + { + dd_zone = 6 + head; + tr_off = track - 0x390; + } + else if (track >= 0x2FB) + { + dd_zone = 5 + head; + tr_off = track - 0x2FB; + } + else if (track >= 0x266) + { + dd_zone = 4 + head; + tr_off = track - 0x266; + } + else if (track >= 0x1D1) + { + dd_zone = 3 + head; + tr_off = track - 0x1D1; + } + else if (track >= 0x13C) + { + dd_zone = 2 + head; + tr_off = track - 0x13C; + } + else if (track >= 0x9E) + { + dd_zone = 1 + head; + tr_off = track - 0x9E; + } + else + { + dd_zone = 0 + head; + tr_off = track; + } + + dd_track_offset = ddStartOffset[dd_zone] + tr_off * ddZoneSecSize[dd_zone] * SECTORS_PER_BLOCK * BLOCKS_PER_TRACK; +} + +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(); + } } \ No newline at end of file diff --git a/Source/Project64-core/N64System/Mips/Disk.h b/Source/Project64-core/N64System/Mips/Disk.h index 04cd43dd1..7776664ac 100644 --- a/Source/Project64-core/N64System/Mips/Disk.h +++ b/Source/Project64-core/N64System/Mips/Disk.h @@ -8,9 +8,33 @@ * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ +// Based from MAME's N64DD driver code by Happy_ #pragma once -#include "stdafx.h" + +#include void DiskCommand(void); void DiskReset(void); void DiskBMControl(void); +void DiskGapSectorCheck(void); +void DiskBMUpdate(void); +void DiskBMRead(void); +void DiskBMWrite(void); +void DiskSetOffset(void); +void DiskDMACheck(void); + +extern bool dd_write; +extern bool dd_reset_hold; +extern uint32_t dd_track_offset, dd_zone; +extern uint32_t dd_start_block, dd_current; + +const uint32_t ddZoneSecSize[16] = { 232, 216, 208, 192, 176, 160, 144, 128, + 216, 208, 192, 176, 160, 144, 128, 112 }; +const uint32_t ddZoneTrackSize[16] = { 158, 158, 149, 149, 149, 149, 149, 114, + 158, 158, 149, 149, 149, 149, 149, 114 }; +const uint32_t ddStartOffset[16] = + { 0x0, 0x5F15E0, 0xB79D00, 0x10801A0, 0x1523720, 0x1963D80, 0x1D414C0, 0x20BBCE0, + 0x23196E0, 0x28A1E00, 0x2DF5DC0, 0x3299340, 0x36D99A0, 0x3AB70E0, 0x3E31900, 0x4149200 }; + +#define SECTORS_PER_BLOCK 85 +#define BLOCKS_PER_TRACK 2 diff --git a/Source/Project64-core/N64System/Mips/Dma.cpp b/Source/Project64-core/N64System/Mips/Dma.cpp index 5a5ba3794..86d7fde61 100644 --- a/Source/Project64-core/N64System/Mips/Dma.cpp +++ b/Source/Project64-core/N64System/Mips/Dma.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include CDMA::CDMA(CFlashram & FlashRam, CSram & Sram) : @@ -69,6 +71,37 @@ void CDMA::PI_DMA_READ() return; } + //64DD Buffers Write + if (g_Reg->PI_CART_ADDR_REG >= 0x05000000 && g_Reg->PI_CART_ADDR_REG <= 0x050003FF) + { + //64DD C2 Sectors (don't care) + g_SystemTimer->SetTimer(g_SystemTimer->DDPiTimer, (PI_RD_LEN_REG * 63) / 25, false); + return; + } + + if (g_Reg->PI_CART_ADDR_REG >= 0x05000400 && g_Reg->PI_CART_ADDR_REG <= 0x050004FF) + { + //64DD User Sector + uint32_t i; + uint8_t * RDRAM = g_MMU->Rdram(); + uint8_t * DISK = g_Disk->GetDiskAddressBuffer(); + for (i = 0; i < PI_RD_LEN_REG; i++) + { + *(DISK + (i ^ 3)) = *(RDRAM + ((g_Reg->PI_DRAM_ADDR_REG + i) ^ 3)); + } + g_SystemTimer->SetTimer(g_SystemTimer->DDPiTimer, (PI_RD_LEN_REG * 63) / 25, false); + return; + } + + if (g_Reg->PI_CART_ADDR_REG >= 0x05000580 && g_Reg->PI_CART_ADDR_REG <= 0x050005BF) + { + //64DD MSEQ (don't care) + g_Reg->PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY; + g_Reg->MI_INTR_REG |= MI_INTR_PI; + g_Reg->CheckInterrupts(); + return; + } + //Write ROM Area (for 64DD Convert) if (g_Reg->PI_CART_ADDR_REG >= 0x10000000 && g_Reg->PI_CART_ADDR_REG <= 0x1FBFFFFF && g_Settings->LoadBool(Game_AllowROMWrites)) { @@ -182,21 +215,52 @@ void CDMA::PI_DMA_WRITE() return; } + //64DD Buffers Read + if (g_Reg->PI_CART_ADDR_REG >= 0x05000000 && g_Reg->PI_CART_ADDR_REG <= 0x050003FF) + { + //64DD C2 Sectors (just read 0) + uint32_t i; + uint8_t * RDRAM = g_MMU->Rdram(); + for (i = 0; i < PI_WR_LEN_REG; i++) + { + *(RDRAM + ((g_Reg->PI_DRAM_ADDR_REG + i) ^ 3)) = 0; + } + + //Timer is needed for Track Read + g_SystemTimer->SetTimer(g_SystemTimer->DDPiTimer, (PI_WR_LEN_REG * 63) / 25, false); + return; + } + + if (g_Reg->PI_CART_ADDR_REG >= 0x05000400 && g_Reg->PI_CART_ADDR_REG <= 0x050004FF) + { + //64DD User Sector + uint32_t i; + uint8_t * RDRAM = g_MMU->Rdram(); + uint8_t * DISK = g_Disk->GetDiskAddressBuffer(); + for (i = 0; i < PI_WR_LEN_REG; i++) + { + *(RDRAM + ((g_Reg->PI_DRAM_ADDR_REG + i) ^ 3)) = *(DISK + (i ^ 3)); + } + + //Timer is needed for Track Read + g_SystemTimer->SetTimer(g_SystemTimer->DDPiTimer, (PI_WR_LEN_REG * 63) / 25, false); + return; + } + + if (g_Reg->PI_CART_ADDR_REG >= 0x05000580 && g_Reg->PI_CART_ADDR_REG <= 0x050005BF) + { + //64DD MSEQ (don't care) + g_Reg->PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY; + g_Reg->MI_INTR_REG |= MI_INTR_PI; + g_Reg->CheckInterrupts(); + return; + } + //64DD IPL ROM if (g_Reg->PI_CART_ADDR_REG >= 0x06000000 && g_Reg->PI_CART_ADDR_REG <= 0x063FFFFF) { uint32_t i; -#ifdef legacycode -#ifdef ROM_IN_MAPSPACE - if (WrittenToRom) - { - uint32_t OldProtect; - VirtualProtect(ROM, m_RomFileSize, PAGE_READONLY, &OldProtect); - } -#endif -#endif - uint8_t * ROM = g_DDRom->GetRomAddress(); uint8_t * RDRAM = g_MMU->Rdram(); g_Reg->PI_CART_ADDR_REG -= 0x06000000; diff --git a/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp b/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp index 61d98531f..0da3988e1 100644 --- a/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp +++ b/Source/Project64-core/N64System/Mips/MemoryVirtualMem.cpp @@ -959,7 +959,12 @@ void CMipsMemoryVM::Compile_LW(x86Reg Reg, uint32_t VAddr) { case 0x05000500: MoveVariableToX86reg(&g_Reg->ASIC_DATA, "ASIC_DATA", Reg); break; case 0x05000504: MoveVariableToX86reg(&g_Reg->ASIC_MISC_REG, "ASIC_MISC_REG", Reg); break; - case 0x05000508: MoveVariableToX86reg(&g_Reg->ASIC_STATUS, "ASIC_STATUS", Reg); break; + case 0x05000508: + MoveVariableToX86reg(&g_Reg->ASIC_STATUS, "ASIC_STATUS", Reg); + BeforeCallDirect(m_RegWorkingSet); + Call_Direct(AddressOf(&DiskGapSectorCheck), "DiskGapSectorCheck"); + AfterCallDirect(m_RegWorkingSet); + break; case 0x0500050C: MoveVariableToX86reg(&g_Reg->ASIC_CUR_TK, "ASIC_CUR_TK", Reg); break; case 0x05000510: MoveVariableToX86reg(&g_Reg->ASIC_BM_STATUS, "ASIC_BM_STATUS", Reg); break; case 0x05000514: MoveVariableToX86reg(&g_Reg->ASIC_ERR_SECTOR, "ASIC_ERR_SECTOR", Reg); break; @@ -1922,7 +1927,15 @@ void CMipsMemoryVM::Compile_SW_Register(x86Reg Reg, uint32_t VAddr) switch (PAddr) { case 0x04600000: MoveX86regToVariable(Reg, &g_Reg->PI_DRAM_ADDR_REG, "PI_DRAM_ADDR_REG"); break; - case 0x04600004: MoveX86regToVariable(Reg, &g_Reg->PI_CART_ADDR_REG, "PI_CART_ADDR_REG"); break; + case 0x04600004: + MoveX86regToVariable(Reg, &g_Reg->PI_CART_ADDR_REG, "PI_CART_ADDR_REG"); + if (g_Settings->LoadBool(Setting_EnableDisk)) + { + BeforeCallDirect(m_RegWorkingSet); + Call_Direct(AddressOf(&DiskDMACheck), "DiskDMACheck"); + AfterCallDirect(m_RegWorkingSet); + } + break; case 0x04600008: MoveX86regToVariable(Reg, &g_Reg->PI_RD_LEN_REG, "PI_RD_LEN_REG"); BeforeCallDirect(m_RegWorkingSet); @@ -4827,7 +4840,10 @@ void CMipsMemoryVM::Load32CartridgeDomain2Address1(void) { case 0x05000500: m_MemLookupValue.UW[0] = g_Reg->ASIC_DATA; break; case 0x05000504: m_MemLookupValue.UW[0] = g_Reg->ASIC_MISC_REG; break; - case 0x05000508: m_MemLookupValue.UW[0] = g_Reg->ASIC_STATUS; break; + case 0x05000508: + m_MemLookupValue.UW[0] = g_Reg->ASIC_STATUS; + DiskGapSectorCheck(); + break; case 0x0500050C: m_MemLookupValue.UW[0] = g_Reg->ASIC_CUR_TK; break; case 0x05000510: m_MemLookupValue.UW[0] = g_Reg->ASIC_BM_STATUS; break; case 0x05000514: m_MemLookupValue.UW[0] = g_Reg->ASIC_ERR_SECTOR; break; @@ -5407,7 +5423,11 @@ void CMipsMemoryVM::Write32PeripheralInterface(void) switch (m_MemLookupAddress & 0xFFFFFFF) { case 0x04600000: g_Reg->PI_DRAM_ADDR_REG = m_MemLookupValue.UW[0]; break; - case 0x04600004: g_Reg->PI_CART_ADDR_REG = m_MemLookupValue.UW[0]; break; + case 0x04600004: + g_Reg->PI_CART_ADDR_REG = m_MemLookupValue.UW[0]; + if (g_Settings->LoadBool(Setting_EnableDisk)) + DiskDMACheck(); + break; case 0x04600008: g_Reg->PI_RD_LEN_REG = m_MemLookupValue.UW[0]; g_MMU->PI_DMA_READ(); diff --git a/Source/Project64-core/N64System/Mips/SystemTiming.cpp b/Source/Project64-core/N64System/Mips/SystemTiming.cpp index 0bc492da3..9d301bdc6 100644 --- a/Source/Project64-core/N64System/Mips/SystemTiming.cpp +++ b/Source/Project64-core/N64System/Mips/SystemTiming.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -207,6 +208,13 @@ void CSystemTimer::TimerDone() g_Reg->MI_INTR_REG |= MI_INTR_PI; g_Reg->CheckInterrupts(); break; + case CSystemTimer::DDPiTimer: + g_SystemTimer->StopTimer(CSystemTimer::DDPiTimer); + g_Reg->PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY; + DiskBMUpdate(); + g_Reg->MI_INTR_REG |= MI_INTR_PI; + g_Reg->CheckInterrupts(); + break; case CSystemTimer::ViTimer: try { diff --git a/Source/Project64-core/N64System/Mips/SystemTiming.h b/Source/Project64-core/N64System/Mips/SystemTiming.h index a9b98efb9..85969a2cc 100644 --- a/Source/Project64-core/N64System/Mips/SystemTiming.h +++ b/Source/Project64-core/N64System/Mips/SystemTiming.h @@ -29,6 +29,7 @@ public: PiTimer, RspTimer, RSPTimerDlist, + DDPiTimer, MaxTimer }; diff --git a/Source/Project64-core/N64System/N64Class.cpp b/Source/Project64-core/N64System/N64Class.cpp index 0f8134e84..152d54ad2 100644 --- a/Source/Project64-core/N64System/N64Class.cpp +++ b/Source/Project64-core/N64System/N64Class.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -188,6 +189,7 @@ void CN64System::ExternalEvent(SystemEvent action) bool CN64System::RunFileImage(const char * FileLoc) { CloseSystem(); + g_Settings->SaveBool(Setting_EnableDisk, false); if (g_Settings->LoadBool(GameRunning_LoadingInProgress)) { return false; @@ -216,6 +218,12 @@ bool CN64System::RunFileImage(const char * FileLoc) { //64DD IPL g_DDRom = g_Rom; + g_Settings->SaveString(File_DiskIPLPath, FileLoc); + } + + if (g_DDRom != NULL) + { + g_Settings->SaveBool(Setting_EnableDisk, true); } g_System->RefreshGameSettings(); @@ -244,6 +252,107 @@ bool CN64System::RunFileImage(const char * FileLoc) return true; } +bool CN64System::RunFileImageIPL(const char * FileLoc) +{ + CloseSystem(); + if (g_Settings->LoadBool(GameRunning_LoadingInProgress)) + { + return false; + } + + //Mark the rom as loading + WriteTrace(TraceN64System, TraceDebug, "Mark DDRom as loading"); + //g_Settings->SaveString(Game_File, ""); + g_Settings->SaveBool(GameRunning_LoadingInProgress, true); + + //Try to load the passed N64 DDrom + if (g_DDRom == NULL) + { + WriteTrace(TraceN64System, TraceDebug, "Allocating global DDrom object"); + g_DDRom = new CN64Rom(); + } + else + { + WriteTrace(TraceN64System, TraceDebug, "Use existing global DDrom object"); + } + + WriteTrace(TraceN64System, TraceDebug, "Loading \"%s\"", FileLoc); + if (g_DDRom->LoadN64ImageIPL(FileLoc)) + { + if (g_DDRom->CicChipID() != CIC_NUS_8303) + { + //If not 64DD IPL then it's wrong + WriteTrace(TraceN64System, TraceError, "LoadN64ImageIPL failed (\"%s\")", FileLoc); + g_Notify->DisplayError(g_DDRom->GetError()); + delete g_DDRom; + g_DDRom = NULL; + g_Settings->SaveBool(GameRunning_LoadingInProgress, false); + return false; + } + + g_System->RefreshGameSettings(); + + g_Settings->SaveString(File_DiskIPLPath, FileLoc); + + //g_Settings->SaveString(Game_File, FileLoc); + g_Settings->SaveBool(GameRunning_LoadingInProgress, false); + } + else + { + WriteTrace(TraceN64System, TraceError, "LoadN64ImageIPL failed (\"%s\")", FileLoc); + g_Notify->DisplayError(g_DDRom->GetError()); + delete g_DDRom; + g_DDRom = NULL; + g_Settings->SaveBool(GameRunning_LoadingInProgress, false); + return false; + } + return true; +} + +bool CN64System::RunDiskImage(const char * FileLoc) +{ + CloseSystem(); + if (g_Settings->LoadBool(GameRunning_LoadingInProgress)) + { + return false; + } + + //Mark the rom as loading + WriteTrace(TraceN64System, TraceDebug, "Mark Disk as loading"); + //g_Settings->SaveString(Game_File, ""); + g_Settings->SaveBool(GameRunning_LoadingInProgress, true); + + //Try to load the passed N64 Disk + if (g_Disk == NULL) + { + WriteTrace(TraceN64System, TraceDebug, "Allocating global Disk object"); + g_Disk = new CN64Disk(); + } + else + { + WriteTrace(TraceN64System, TraceDebug, "Use existing global Disk object"); + } + + WriteTrace(TraceN64System, TraceDebug, "Loading \"%s\"", FileLoc); + if (g_Disk->LoadDiskImage(FileLoc)) + { + g_System->RefreshGameSettings(); + + //g_Settings->SaveString(Game_File, FileLoc); + g_Settings->SaveBool(GameRunning_LoadingInProgress, false); + } + else + { + WriteTrace(TraceN64System, TraceError, "LoadDiskImage failed (\"%s\")", FileLoc); + g_Notify->DisplayError(g_Disk->GetError()); + delete g_Disk; + g_Disk = NULL; + g_Settings->SaveBool(GameRunning_LoadingInProgress, false); + return false; + } + return true; +} + void CN64System::CloseSystem() { if (g_BaseSystem) diff --git a/Source/Project64-core/N64System/N64Class.h b/Source/Project64-core/N64System/N64Class.h index df41ba593..efe0e7403 100644 --- a/Source/Project64-core/N64System/N64Class.h +++ b/Source/Project64-core/N64System/N64Class.h @@ -56,6 +56,8 @@ public: //Methods static bool RunFileImage(const char * FileLoc); + static bool RunFileImageIPL(const char * FileLoc); + static bool RunDiskImage(const char * FileLoc); static void CloseSystem(void); void CloseCpu(); diff --git a/Source/Project64-core/N64System/N64DiskClass.cpp b/Source/Project64-core/N64System/N64DiskClass.cpp new file mode 100644 index 000000000..321d75929 --- /dev/null +++ b/Source/Project64-core/N64System/N64DiskClass.cpp @@ -0,0 +1,357 @@ +/**************************************************************************** +* * +* 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 * +* * +****************************************************************************/ +#pragma once +#include "stdafx.h" +#include "N64DiskClass.h" +#include "SystemGlobals.h" +#include +#include + +CN64Disk::CN64Disk() : +m_DiskImage(NULL), +m_DiskImageBase(NULL), +m_ErrorMsg(EMPTY_STRING), +m_DiskBufAddress(0) +{ +} + +CN64Disk::~CN64Disk() +{ +} + +bool CN64Disk::LoadDiskImage(const char * FileLoc) +{ + UnallocateDiskImage(); + + if (!AllocateAndLoadDiskImage(FileLoc)) + { + return false; + } + + if (g_Disk == this) + { + g_Settings->SaveBool(GameRunning_LoadingInProgress, false); + } + + return true; +} + +bool CN64Disk::IsValidDiskImage(uint8_t Test[4]) +{ + if (*((uint32_t *)&Test[0]) == 0x16D348E8) { return true; } + return false; +} + +bool CN64Disk::AllocateDiskImage(uint32_t DiskFileSize) +{ + WriteTrace(TraceN64System, TraceDebug, "Allocating memory for disk"); + std::auto_ptr ImageBase(new uint8_t[DiskFileSize + 0x1000]); + if (ImageBase.get() == NULL) + { + SetError(MSG_MEM_ALLOC_ERROR); + WriteTrace(TraceN64System, TraceError, "Failed to allocate memory for disk (size: 0x%X)", DiskFileSize); + return false; + } + uint8_t * Image = (uint8_t *)(((uint64_t)ImageBase.get() + 0xFFF) & ~0xFFF); // start at begining of memory page + WriteTrace(TraceN64System, TraceDebug, "Allocated disk memory (%p)", Image); + + //save information about the disk loaded + m_DiskImageBase = ImageBase.release(); + m_DiskImage = Image; + m_DiskFileSize = DiskFileSize; + return true; +} + +bool CN64Disk::AllocateAndLoadDiskImage(const char * FileLoc) +{ + WriteTrace(TraceN64System, TraceDebug, "Trying to open %s", FileLoc); + if (!m_DiskFile.Open(FileLoc, CFileBase::modeRead)) + { + WriteTrace(TraceN64System, TraceError, "Failed to open %s", FileLoc); + return false; + } + + //Read the first 4 bytes and make sure it is a valid disk image + uint8_t Test[4]; + m_DiskFile.SeekToBegin(); + if (m_DiskFile.Read(Test, sizeof(Test)) != sizeof(Test)) + { + m_DiskFile.Close(); + WriteTrace(TraceN64System, TraceError, "Failed to read ident bytes"); + return false; + } + if (!IsValidDiskImage(Test)) + { + m_DiskFile.Close(); + WriteTrace(TraceN64System, TraceError, "invalid image file %X %X %X %X", Test[0], Test[1], Test[2], Test[3]); + return false; + } + uint32_t DiskFileSize = m_DiskFile.GetLength(); + WriteTrace(TraceN64System, TraceDebug, "Successfully Opened, size: 0x%X", DiskFileSize); + + //Check Disk File Format + if (DiskFileSize == MameFormatSize) + { + //If Disk is MAME Format (size is constant, it should be the same for every file), then continue + WriteTrace(TraceN64System, TraceDebug, "Disk File is MAME Format", ); + + if (!AllocateDiskImage(DiskFileSize)) + { + m_DiskFile.Close(); + return false; + } + + //Load the n64 disk to the allocated memory + g_Notify->DisplayMessage(5, MSG_LOADING); + m_DiskFile.SeekToBegin(); + + uint32_t count, TotalRead = 0; + for (count = 0; count < (int)DiskFileSize; count += ReadFromRomSection) + { + uint32_t dwToRead = DiskFileSize - count; + if (dwToRead > ReadFromRomSection) { dwToRead = ReadFromRomSection; } + + if (m_DiskFile.Read(&m_DiskImage[count], dwToRead) != dwToRead) + { + m_DiskFile.Close(); + SetError(MSG_FAIL_IMAGE); + WriteTrace(TraceN64System, TraceError, "Failed to read file (TotalRead: 0x%X)", TotalRead); + return false; + } + TotalRead += dwToRead; + + //Show Message of how much % wise of the rom has been loaded + g_Notify->DisplayMessage(0, stdstr_f("%s: %.2f%c", GS(MSG_LOADED), ((float)TotalRead / (float)DiskFileSize) * 100.0f, '%').c_str()); + } + + if (DiskFileSize != TotalRead) + { + m_DiskFile.Close(); + SetError(MSG_FAIL_IMAGE); + WriteTrace(TraceN64System, TraceError, "Expected to read: 0x%X, read: 0x%X", TotalRead, DiskFileSize); + return false; + } + } + else if (DiskFileSize == SDKFormatSize) + { + //If Disk is SDK format (made with SDK based dumpers like LuigiBlood's, or Nintendo's, size is also constant) + //We need to convert it. + g_Notify->DisplayMessage(5, MSG_LOADING); + + //Allocate supported size + if (!AllocateDiskImage(MameFormatSize)) + { + m_DiskFile.Close(); + return false; + } + + ConvertDiskFormat(); + } + else + { + //Else the disk file is invalid + m_DiskFile.Close(); + WriteTrace(TraceN64System, TraceError, "Disk File is invalid, unexpected size"); + return false; + } + + g_Notify->DisplayMessage(5, MSG_BYTESWAP); + ByteSwapDisk(); + + ProtectMemory(m_DiskImage, m_DiskFileSize, MEM_READWRITE); + return true; +} + +void CN64Disk::ByteSwapDisk() +{ + uint32_t count; + + switch (*((uint32_t *)&m_DiskImage[0])) + { + case 0x16D348E8: + for (count = 0; count < m_DiskFileSize; count += 4) + { + m_DiskImage[count] ^= m_DiskImage[count + 3]; + m_DiskImage[count + 3] ^= m_DiskImage[count]; + m_DiskImage[count] ^= m_DiskImage[count + 3]; + m_DiskImage[count + 1] ^= m_DiskImage[count + 2]; + m_DiskImage[count + 2] ^= m_DiskImage[count + 1]; + m_DiskImage[count + 1] ^= m_DiskImage[count + 2]; + } + break; + case 0xE848D316: break; + default: + g_Notify->DisplayError(stdstr_f("ByteSwapDisk: %X", m_DiskImage[0]).c_str()); + } +} + +void CN64Disk::SetError(LanguageStringID ErrorMsg) +{ + m_ErrorMsg = ErrorMsg; +} + +void CN64Disk::UnallocateDiskImage() +{ + m_DiskFile.Close(); + + if (m_DiskImageBase) + { + ProtectMemory(m_DiskImage, m_DiskFileSize, MEM_READWRITE); + delete[] m_DiskImageBase; + m_DiskImageBase = NULL; + } + m_DiskImage = NULL; +} + +void CN64Disk::ConvertDiskFormat() +{ + //Original code by Happy_ + m_DiskFile.SeekToBegin(); + + const uint32_t ZoneSecSize[16] = { 232, 216, 208, 192, 176, 160, 144, 128, + 216, 208, 192, 176, 160, 144, 128, 112 }; + const uint32_t ZoneTracks[16] = { 158, 158, 149, 149, 149, 149, 149, 114, + 158, 158, 149, 149, 149, 149, 149, 114 }; + const uint32_t DiskTypeZones[7][16] = { + { 0, 1, 2, 9, 8, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10 }, + { 0, 1, 2, 3, 10, 9, 8, 4, 5, 6, 7, 15, 14, 13, 12, 11 }, + { 0, 1, 2, 3, 4, 11, 10, 9, 8, 5, 6, 7, 15, 14, 13, 12 }, + { 0, 1, 2, 3, 4, 5, 12, 11, 10, 9, 8, 6, 7, 15, 14, 13 }, + { 0, 1, 2, 3, 4, 5, 6, 13, 12, 11, 10, 9, 8, 7, 15, 14 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8, 15 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8 } + }; + const uint32_t RevDiskTypeZones[7][16] = { + { 0, 1, 2, 5, 6, 7, 8, 9, 4, 3, 15, 14, 13, 12, 11, 10 }, + { 0, 1, 2, 3, 7, 8, 9, 10, 6, 5, 4, 15, 14, 13, 12, 11 }, + { 0, 1, 2, 3, 4, 9, 10, 11, 8, 7, 6, 5, 15, 14, 13, 12 }, + { 0, 1, 2, 3, 4, 5, 11, 12, 10, 9, 8, 7, 6, 15, 14, 13 }, + { 0, 1, 2, 3, 4, 5, 6, 13, 12, 11, 10, 9, 8, 7, 15, 14 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8, 15 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8 } + }; + const uint32_t StartBlock[7][16] = { + { 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1 }, + { 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0 }, + { 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1 }, + { 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0 }, + { 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1 }, + { 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0 }, + { 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1 } + }; + + uint32_t disktype = 0; + uint32_t zone, track = 0; + int32_t atrack = 0; + int32_t block = 0; + uint8_t SystemData[0xE8]; + uint8_t BlockData0[0x100 * SECTORS_PER_BLOCK]; + uint8_t BlockData1[0x100 * SECTORS_PER_BLOCK]; + uint32_t InOffset, OutOffset = 0; + uint32_t InStart[16]; + uint32_t OutStart[16]; + + InStart[0] = 0; + OutStart[0] = 0; + + //Read System Area + m_DiskFile.Read(&SystemData, 0xE8); + + disktype = SystemData[5] & 0xF; + + //Prepare Input Offsets + for (zone = 1; zone < 16; zone++) + { + InStart[zone] = InStart[zone - 1] + + VZONESIZE(DiskTypeZones[disktype][zone - 1]); + } + + //Prepare Output Offsets + for (zone = 1; zone < 16; zone++) + { + OutStart[zone] = OutStart[zone - 1] + ZONESIZE(zone - 1); + } + + //Copy Head 0 + for (zone = 0; zone < 8; zone++) + { + OutOffset = OutStart[zone]; + InOffset = InStart[RevDiskTypeZones[disktype][zone]]; + m_DiskFile.Seek(InOffset, CFileBase::SeekPosition::begin); + block = StartBlock[disktype][zone]; + atrack = 0; + for (track = 0; track < ZoneTracks[zone]; track++) + { + if (track == SystemData[0x20 + zone * 0xC + atrack]) + { + memset((void *)(&BlockData0), 0, BLOCKSIZE(zone)); + memset((void *)(&BlockData1), 0, BLOCKSIZE(zone)); + atrack += 1; + } + else + { + if ((block % 2) == 1) + { + m_DiskFile.Read(&BlockData1, BLOCKSIZE(zone)); + m_DiskFile.Read(&BlockData0, BLOCKSIZE(zone)); + } + else + { + m_DiskFile.Read(&BlockData0, BLOCKSIZE(zone)); + m_DiskFile.Read(&BlockData1, BLOCKSIZE(zone)); + } + block = 1 - block; + } + memcpy(m_DiskImage + OutOffset, &BlockData0, BLOCKSIZE(zone)); + OutOffset += BLOCKSIZE(zone); + memcpy(m_DiskImage + OutOffset, &BlockData1, BLOCKSIZE(zone)); + OutOffset += BLOCKSIZE(zone); + } + } + + //Copy Head 1 + for (zone = 8; zone < 16; zone++) + { + //OutOffset = OutStart[zone]; + InOffset = InStart[RevDiskTypeZones[disktype][zone]]; + m_DiskFile.Seek(InOffset, CFileBase::SeekPosition::begin); + block = StartBlock[disktype][zone]; + atrack = 0xB; + for (track = 1; track < ZoneTracks[zone] + 1; track++) + { + if ((ZoneTracks[zone] - track) == SystemData[0x20 + (zone)* 0xC + atrack]) + { + memset((void *)(&BlockData0), 0, BLOCKSIZE(zone)); + memset((void *)(&BlockData1), 0, BLOCKSIZE(zone)); + atrack -= 1; + } + else + { + if ((block % 2) == 1) + { + m_DiskFile.Read(&BlockData1, BLOCKSIZE(zone)); + m_DiskFile.Read(&BlockData0, BLOCKSIZE(zone)); + } + else + { + m_DiskFile.Read(&BlockData0, BLOCKSIZE(zone)); + m_DiskFile.Read(&BlockData1, BLOCKSIZE(zone)); + } + block = 1 - block; + } + OutOffset = OutStart[zone] + (ZoneTracks[zone] - track) * TRACKSIZE(zone); + memcpy(m_DiskImage + OutOffset, &BlockData0, BLOCKSIZE(zone)); + OutOffset += BLOCKSIZE(zone); + memcpy(m_DiskImage + OutOffset, &BlockData1, BLOCKSIZE(zone)); + OutOffset += BLOCKSIZE(zone); + } + } +} \ No newline at end of file diff --git a/Source/Project64-core/N64System/N64DiskClass.h b/Source/Project64-core/N64System/N64DiskClass.h new file mode 100644 index 000000000..2b3938966 --- /dev/null +++ b/Source/Project64-core/N64System/N64DiskClass.h @@ -0,0 +1,56 @@ +/**************************************************************************** +* * +* 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 * +* * +****************************************************************************/ +#pragma once +#include + +class CN64Disk +{ +public: + CN64Disk(); + ~CN64Disk(); + + bool LoadDiskImage(const char * FileLoc); + static bool IsValidDiskImage(uint8_t Test[4]); + uint8_t * GetDiskAddress() { return m_DiskImage; } + uint8_t * GetDiskAddressBuffer() { return m_DiskImage + m_DiskBufAddress; } + void SetDiskAddressBuffer(uint32_t address) { m_DiskBufAddress = address; } + void UnallocateDiskImage(); + + LanguageStringID GetError() const { return m_ErrorMsg; } + +private: + bool AllocateDiskImage(uint32_t DiskFileSize); + bool AllocateAndLoadDiskImage(const char * FileLoc); + void ByteSwapDisk(); + void SetError(LanguageStringID ErrorMsg); + void ConvertDiskFormat(); + + //constant values + enum { ReadFromRomSection = 0x400000, MameFormatSize = 0x0435B0C0, SDKFormatSize = 0x03DEC800 }; + + //class variables + CFile m_DiskFile; + uint8_t * m_DiskImage; + uint8_t * m_DiskImageBase; + uint32_t m_DiskFileSize; + uint32_t m_DiskBufAddress; + LanguageStringID m_ErrorMsg; + stdstr m_FileName, m_DiskIdent; + + //disk convert + #define SECTORS_PER_BLOCK 85 + #define BLOCKS_PER_TRACK 2 + + #define BLOCKSIZE(_zone) ZoneSecSize[_zone] * SECTORS_PER_BLOCK + #define TRACKSIZE(_zone) BLOCKSIZE(_zone) * BLOCKS_PER_TRACK + #define ZONESIZE(_zone) TRACKSIZE(_zone) * ZoneTracks[_zone] + #define VZONESIZE(_zone) TRACKSIZE(_zone) * (ZoneTracks[_zone] - 0xC) +}; \ No newline at end of file diff --git a/Source/Project64-core/N64System/N64RomClass.cpp b/Source/Project64-core/N64System/N64RomClass.cpp index 33cbd81c6..bcf5c8a53 100644 --- a/Source/Project64-core/N64System/N64RomClass.cpp +++ b/Source/Project64-core/N64System/N64RomClass.cpp @@ -579,6 +579,183 @@ bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly) return true; } +bool CN64Rom::LoadN64ImageIPL(const char * FileLoc, bool LoadBootCodeOnly) +{ + UnallocateRomImage(); + m_ErrorMsg = EMPTY_STRING; + + stdstr ext = CPath(FileLoc).GetExtension(); + bool Loaded7zFile = false; + + if (strstr(FileLoc, "?") != NULL || _stricmp(ext.c_str(), "7z") == 0) + { + stdstr FullPath = FileLoc; + + //this should be a 7zip file + char * SubFile = strstr(const_cast(FullPath.c_str()), "?"); + if (SubFile == NULL) + { + //Pop up a dialog and select file + //allocate memory for sub name and copy selected file name to var + return false; //remove once dialog is done + } + else + { + *SubFile = '\0'; + SubFile += 1; + } + + C7zip ZipFile(FullPath.c_str()); + ZipFile.SetNotificationCallback((C7zip::LP7ZNOTIFICATION)NotificationCB, this); + for (int i = 0; i < ZipFile.NumFiles(); i++) + { + CSzFileItem * f = ZipFile.FileItem(i); + if (f->IsDir) + { + continue; + } + + stdstr ZipFileName; + ZipFileName.FromUTF16(ZipFile.FileNameIndex(i).c_str()); + if (SubFile != NULL) + { + if (_stricmp(ZipFileName.c_str(), SubFile) != 0) + { + continue; + } + } + + //Get the size of the rom and try to allocate the memory needed. + uint32_t RomFileSize = (uint32_t)f->Size; + //if loading boot code then just load the first 0x1000 bytes + if (LoadBootCodeOnly) { RomFileSize = 0x1000; } + + if (!AllocateRomImage(RomFileSize)) + { + return false; + } + + //Load the n64 rom to the allocated memory + g_Notify->DisplayMessage(5, MSG_LOADING); + if (!ZipFile.GetFile(i, m_ROMImage, RomFileSize)) + { + SetError(MSG_FAIL_IMAGE); + return false; + } + + if (!IsValidRomImage(m_ROMImage)) + { + SetError(MSG_FAIL_IMAGE); + return false; + } + g_Notify->DisplayMessage(5, MSG_BYTESWAP); + ByteSwapRom(); + + //Protect the memory so that it can not be written to. + ProtectMemory(m_ROMImage, m_RomFileSize, MEM_READONLY); + Loaded7zFile = true; + break; + } + if (!Loaded7zFile) + { + SetError(MSG_7Z_FILE_NOT_FOUND); + return false; + } + } + + //Try to open the file as a zip file + if (!Loaded7zFile) + { + if (!AllocateAndLoadZipImage(FileLoc, LoadBootCodeOnly)) + { + if (m_ErrorMsg != EMPTY_STRING) + { + return false; + } + if (!AllocateAndLoadN64Image(FileLoc, LoadBootCodeOnly)) + { + return false; + } + } + } + + char RomName[260]; + int count; + //Get the header from the rom image + memcpy(&RomName[0], (void *)(m_ROMImage + 0x20), 20); + for (count = 0; count < 20; count += 4) + { + RomName[count] ^= RomName[count + 3]; + RomName[count + 3] ^= RomName[count]; + RomName[count] ^= RomName[count + 3]; + RomName[count + 1] ^= RomName[count + 2]; + RomName[count + 2] ^= RomName[count + 1]; + RomName[count + 1] ^= RomName[count + 2]; + } + + //truncate all the spaces at the end of the string + for (count = 19; count >= 0; count--) + { + if (RomName[count] == ' ') + { + RomName[count] = '\0'; + } + else if (RomName[count] == '\0') + { + } + else + { + count = -1; + } + } + RomName[20] = '\0'; + if (strlen(RomName) == 0) + { + strcpy(RomName, CPath(FileLoc).GetName().c_str()); + } + + //remove all /,\,: from the string + for (count = 0; count < (int)strlen(RomName); count++) + { + switch (RomName[count]) + { + case '/': case '\\': RomName[count] = '-'; break; + case ':': RomName[count] = ';'; break; + } + } + WriteTrace(TraceN64System, TraceDebug, "RomName %s", RomName); + + m_RomName = RomName; + m_FileName = FileLoc; + m_MD5 = ""; + + if (!LoadBootCodeOnly) + { + //Calculate files MD5 + m_MD5 = MD5((const unsigned char *)m_ROMImage, m_RomFileSize).hex_digest(); + WriteTrace(TraceN64System, TraceDebug, "MD5: %s", m_MD5.c_str()); + } + + m_Country = (Country)m_ROMImage[0x3D]; + m_RomIdent.Format("%08X-%08X-C:%X", *(uint32_t *)(&m_ROMImage[0x10]), *(uint32_t *)(&m_ROMImage[0x14]), m_ROMImage[0x3D]); + WriteTrace(TraceN64System, TraceDebug, "Ident: %s", m_RomIdent.c_str()); + CalculateCicChip(); + + if (!LoadBootCodeOnly && g_DDRom == this) + { + g_Settings->SaveBool(GameRunning_LoadingInProgress, false); + SaveRomSettingID(false); + } + + if (g_Settings->LoadBool(Game_CRC_Recalc)) + { + //Calculate ROM Header CRC + CalculateRomCrc(); + } + + return true; +} + //Save the settings of the loaded rom, so all loaded settings about rom will be identified with //this rom void CN64Rom::SaveRomSettingID(bool temp) diff --git a/Source/Project64-core/N64System/N64RomClass.h b/Source/Project64-core/N64System/N64RomClass.h index 6e10a0709..fef95da55 100644 --- a/Source/Project64-core/N64System/N64RomClass.h +++ b/Source/Project64-core/N64System/N64RomClass.h @@ -21,6 +21,7 @@ public: ~CN64Rom(); bool LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly = false); + bool LoadN64ImageIPL(const char * FileLoc, bool LoadBootCodeOnly = false); static bool IsValidRomImage(uint8_t Test[4]); void SaveRomSettingID(bool temp); void ClearRomSettingID(); diff --git a/Source/Project64-core/N64System/SystemGlobals.cpp b/Source/Project64-core/N64System/SystemGlobals.cpp index 6ab72f809..f46c5a754 100644 --- a/Source/Project64-core/N64System/SystemGlobals.cpp +++ b/Source/Project64-core/N64System/SystemGlobals.cpp @@ -22,6 +22,7 @@ CNotification * g_Notify = NULL; CPlugins * g_Plugins = NULL; CN64Rom * g_Rom = NULL; //The current rom that this system is executing.. it can only execute one file at the time CN64Rom * g_DDRom = NULL; //64DD IPL ROM +CN64Disk * g_Disk = NULL; //64DD DISK CAudio * g_Audio = NULL; CSystemTimer * g_SystemTimer = NULL; CTransVaddr * g_TransVaddr = NULL; diff --git a/Source/Project64-core/N64System/SystemGlobals.h b/Source/Project64-core/N64System/SystemGlobals.h index cd279afaf..de4086076 100644 --- a/Source/Project64-core/N64System/SystemGlobals.h +++ b/Source/Project64-core/N64System/SystemGlobals.h @@ -37,6 +37,9 @@ class CN64Rom; extern CN64Rom * g_Rom; //The current rom that this system is executing.. it can only execute one file at the time extern CN64Rom * g_DDRom; //64DD IPL ROM +class CN64Disk; +extern CN64Disk * g_Disk; //64DD DISK + class CAudio; extern CAudio * g_Audio; diff --git a/Source/Project64-core/Project64-core.vcxproj b/Source/Project64-core/Project64-core.vcxproj index 5dd24c683..3c5e643be 100644 --- a/Source/Project64-core/Project64-core.vcxproj +++ b/Source/Project64-core/Project64-core.vcxproj @@ -61,6 +61,7 @@ + @@ -148,6 +149,7 @@ + diff --git a/Source/Project64-core/Project64-core.vcxproj.filters b/Source/Project64-core/Project64-core.vcxproj.filters index 0bac0a923..207c34c9a 100644 --- a/Source/Project64-core/Project64-core.vcxproj.filters +++ b/Source/Project64-core/Project64-core.vcxproj.filters @@ -297,6 +297,9 @@ Source Files\N64 System\Mips + + Source Files\N64 System + @@ -578,5 +581,8 @@ Header Files\N64 System\Mips + + Header Files\N64 System + \ No newline at end of file diff --git a/Source/Project64-core/Settings/Settings.h b/Source/Project64-core/Settings/Settings.h index 504dc81b8..010f4cc1d 100644 --- a/Source/Project64-core/Settings/Settings.h +++ b/Source/Project64-core/Settings/Settings.h @@ -224,6 +224,7 @@ enum SettingID //File Info File_RecentGameFileCount, File_RecentGameFileIndex, + File_DiskIPLPath, //Debugger Debugger_Enabled, diff --git a/Source/Project64-core/Settings/SettingsClass.cpp b/Source/Project64-core/Settings/SettingsClass.cpp index 65bda69eb..eff641bb6 100644 --- a/Source/Project64-core/Settings/SettingsClass.cpp +++ b/Source/Project64-core/Settings/SettingsClass.cpp @@ -132,7 +132,7 @@ void CSettings::AddHowToHandleSetting() AddHandler(Setting_RememberCheats, new CSettingTypeApplication("", "Remember Cheats", (uint32_t)false)); AddHandler(Setting_CurrentLanguage, new CSettingTypeApplication("", "Current Language", "")); - AddHandler(Setting_EnableDisk, new CSettingTypeApplication("", "Enable Disk", (uint32_t)false)); + AddHandler(Setting_EnableDisk, new CSettingTypeApplication("", "Enable Disk", (uint32_t)true)); AddHandler(Setting_LanguageDirDefault, new CSettingTypeRelativePath("Lang", "")); AddHandler(Setting_LanguageDir, new CSettingTypeApplicationPath("Directory", "Lang", Setting_LanguageDirDefault)); @@ -309,6 +309,7 @@ void CSettings::AddHowToHandleSetting() AddHandler(File_RecentGameFileCount, new CSettingTypeApplication("", "Remembered Rom Files", (uint32_t)10)); AddHandler(File_RecentGameFileIndex, new CSettingTypeApplicationIndex("Recent File", "Recent Rom", Default_None)); + AddHandler(File_DiskIPLPath, new CSettingTypeApplicationPath("", "Disk IPL ROM Path", Default_None)); AddHandler(Debugger_Enabled, new CSettingTypeApplication("Debugger", "Debugger", false)); AddHandler(Debugger_ShowTLBMisses, new CSettingTypeApplication("Debugger", "Show TLB Misses", false)); diff --git a/Source/Project64/UserInterface/GuiClass.cpp b/Source/Project64/UserInterface/GuiClass.cpp index d81e3d28a..018d4d1c4 100644 --- a/Source/Project64/UserInterface/GuiClass.cpp +++ b/Source/Project64/UserInterface/GuiClass.cpp @@ -979,6 +979,67 @@ LRESULT CALLBACK CMainGui::MainGui_Proc(HWND hWnd, DWORD uMsg, DWORD wParam, DWO switch (LOWORD(wParam)) { case ID_POPUPMENU_PLAYGAME: g_BaseSystem->RunFileImage(_this->CurrentedSelectedRom()); break; + case ID_POPUPMENU_PLAYGAMEWITHDISK: + { + stdstr IPLROM = g_Settings->LoadStringVal(File_DiskIPLPath); + if ((IPLROM.length() <= 0) || (!g_BaseSystem->RunFileImageIPL(IPLROM.c_str()))) + { + // Open DDROM + OPENFILENAME openfilename; + char FileName[_MAX_PATH], Directory[_MAX_PATH]; + + memset(&FileName, 0, sizeof(FileName)); + memset(&openfilename, 0, sizeof(openfilename)); + + strcpy(Directory, g_Settings->LoadStringVal(Directory_Game).c_str()); + + openfilename.lStructSize = sizeof(openfilename); + openfilename.hwndOwner = (HWND)hWnd; + openfilename.lpstrFilter = "64DD IPL ROM Image (*.zip, *.7z, *.?64, *.rom, *.usa, *.jap, *.pal, *.bin)\0*.?64;*.zip;*.7z;*.bin;*.rom;*.usa;*.jap;*.pal\0All files (*.*)\0*.*\0"; + openfilename.lpstrFile = FileName; + openfilename.lpstrInitialDir = Directory; + openfilename.nMaxFile = MAX_PATH; + openfilename.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + if (GetOpenFileName(&openfilename)) + { + g_BaseSystem->RunFileImageIPL(FileName); + // Open Disk + openfilename.lpstrFilter = "N64DD Disk Image (*.ndd)\0*.ndd\0All files (*.*)\0*.*\0"; + if (GetOpenFileName(&openfilename)) + { + if (g_BaseSystem->RunDiskImage(FileName)) + g_BaseSystem->RunFileImage(_this->CurrentedSelectedRom()); + } + } + } + else + { + // Open Disk + OPENFILENAME openfilename; + char FileName[_MAX_PATH], Directory[_MAX_PATH]; + + memset(&FileName, 0, sizeof(FileName)); + memset(&openfilename, 0, sizeof(openfilename)); + + strcpy(Directory, g_Settings->LoadStringVal(Directory_Game).c_str()); + + openfilename.lStructSize = sizeof(openfilename); + openfilename.hwndOwner = (HWND)hWnd; + openfilename.lpstrFilter = "N64DD Disk Image (*.ndd)\0*.ndd\0All files (*.*)\0*.*\0"; + openfilename.lpstrFile = FileName; + openfilename.lpstrInitialDir = Directory; + openfilename.nMaxFile = MAX_PATH; + openfilename.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + if (GetOpenFileName(&openfilename)) + { + if (g_BaseSystem->RunDiskImage(FileName)) + g_BaseSystem->RunFileImage(_this->CurrentedSelectedRom()); + } + } + } + break; case ID_POPUPMENU_ROMDIRECTORY: _this->SelectRomDir(); break; case ID_POPUPMENU_REFRESHROMLIST: _this->RefreshRomBrowser(); break; case ID_POPUPMENU_ROMINFORMATION: @@ -1081,7 +1142,43 @@ LRESULT CALLBACK CMainGui::MainGui_Proc(HWND hWnd, DWORD uMsg, DWORD wParam, DWO DragQueryFile(hDrop, 0, filename, sizeof(filename)); DragFinish(hDrop); - CN64System::RunFileImage(filename); + stdstr ext = CPath(filename).GetExtension(); + if (!(_stricmp(ext.c_str(), "ndd") == 0)) + { + delete g_DDRom; + g_DDRom = NULL; + CN64System::RunFileImage(filename); + } + else + { + // Open Disk + if (CN64System::RunDiskImage(filename)) + { + stdstr IPLROM = g_Settings->LoadStringVal(File_DiskIPLPath); + if ((IPLROM.length() <= 0) || (!CN64System::RunFileImage(IPLROM.c_str()))) + { + // Open DDROM + OPENFILENAME openfilename; + char FileName[_MAX_PATH], Directory[_MAX_PATH]; + memset(&FileName, 0, sizeof(FileName)); + memset(&openfilename, 0, sizeof(openfilename)); + + strcpy(Directory, g_Settings->LoadStringVal(Directory_Game).c_str()); + openfilename.lStructSize = sizeof(openfilename); + openfilename.hwndOwner = (HWND)hWnd; + openfilename.lpstrFilter = "64DD IPL ROM Image (*.zip, *.7z, *.?64, *.rom, *.usa, *.jap, *.pal, *.bin)\0*.?64;*.zip;*.7z;*.bin;*.rom;*.usa;*.jap;*.pal\0All files (*.*)\0*.*\0"; + openfilename.lpstrFile = FileName; + openfilename.lpstrInitialDir = Directory; + openfilename.nMaxFile = MAX_PATH; + openfilename.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + if (GetOpenFileName(&openfilename)) + { + CN64System::RunFileImage(FileName); + } + } + } + } } break; case WM_DESTROY: diff --git a/Source/Project64/UserInterface/MainMenuClass.cpp b/Source/Project64/UserInterface/MainMenuClass.cpp index 32473b38c..9cd63e182 100644 --- a/Source/Project64/UserInterface/MainMenuClass.cpp +++ b/Source/Project64/UserInterface/MainMenuClass.cpp @@ -92,7 +92,7 @@ stdstr CMainMenu::ChooseFileToOpen(HWND hParent) openfilename.lStructSize = sizeof(openfilename); openfilename.hwndOwner = (HWND)hParent; - openfilename.lpstrFilter = "N64 ROMs (*.zip, *.7z, *.?64, *.rom, *.usa, *.jap, *.pal, *.bin)\0*.?64;*.zip;*.7z;*.bin;*.rom;*.usa;*.jap;*.pal\0All files (*.*)\0*.*\0"; + openfilename.lpstrFilter = "N64 ROMs (*.zip, *.7z, *.?64, *.rom, *.usa, *.jap, *.pal, *.bin, *.ndd)\0*.?64;*.zip;*.7z;*.bin;*.rom;*.usa;*.jap;*.pal;*.ndd\0All files (*.*)\0*.*\0"; openfilename.lpstrFile = FileName; openfilename.lpstrInitialDir = Directory; openfilename.nMaxFile = MAX_PATH; @@ -119,7 +119,44 @@ bool CMainMenu::ProcessMessage(HWND hWnd, DWORD /*FromAccelerator*/, DWORD MenuI stdstr File = ChooseFileToOpen(hWnd); if (File.length() > 0) { - g_BaseSystem->RunFileImage(File.c_str()); + stdstr ext = CPath(File).GetExtension(); + if (!(_stricmp(ext.c_str(), "ndd") == 0)) + { + delete g_DDRom; + g_DDRom = NULL; + g_BaseSystem->RunFileImage(File.c_str()); + } + else + { + // Open Disk + if (g_BaseSystem->RunDiskImage(File.c_str())) + { + stdstr IPLROM = g_Settings->LoadStringVal(File_DiskIPLPath); + if ((IPLROM.length() <= 0) || (!g_BaseSystem->RunFileImage(IPLROM.c_str()))) + { + // Open DDROM + OPENFILENAME openfilename; + char FileName[_MAX_PATH], Directory[_MAX_PATH]; + memset(&FileName, 0, sizeof(FileName)); + memset(&openfilename, 0, sizeof(openfilename)); + + strcpy(Directory, g_Settings->LoadStringVal(Directory_Game).c_str()); + openfilename.lStructSize = sizeof(openfilename); + openfilename.hwndOwner = (HWND)hWnd; + openfilename.lpstrFilter = "64DD IPL ROM Image (*.zip, *.7z, *.?64, *.rom, *.usa, *.jap, *.pal, *.bin)\0*.?64;*.zip;*.7z;*.bin;*.rom;*.usa;*.jap;*.pal\0All files (*.*)\0*.*\0"; + openfilename.lpstrFile = FileName; + openfilename.lpstrInitialDir = Directory; + openfilename.nMaxFile = MAX_PATH; + openfilename.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + + if (GetOpenFileName(&openfilename)) + { + g_BaseSystem->RunFileImage(FileName); + } + } + } + } + } } break; diff --git a/Source/Project64/UserInterface/RomBrowserClass.cpp b/Source/Project64/UserInterface/RomBrowserClass.cpp index 97f444470..735072bdb 100644 --- a/Source/Project64/UserInterface/RomBrowserClass.cpp +++ b/Source/Project64/UserInterface/RomBrowserClass.cpp @@ -1472,6 +1472,10 @@ void CRomBrowser::RomList_OpenRom(uint32_t /*pnmh*/) if (!pRomInfo) { return; } m_StopRefresh = true; + + delete g_DDRom; + g_DDRom = NULL; + CN64System::RunFileImage(pRomInfo->szFullFileName); } @@ -1502,21 +1506,23 @@ void CRomBrowser::RomList_PopupMenu(uint32_t /*pnmh*/) //Fix up menu MenuSetText(hPopupMenu, 0, wGS(POPUP_PLAY).c_str(), NULL); - MenuSetText(hPopupMenu, 2, wGS(MENU_REFRESH).c_str(), NULL); - MenuSetText(hPopupMenu, 3, wGS(MENU_CHOOSE_ROM).c_str(), NULL); - MenuSetText(hPopupMenu, 5, wGS(POPUP_INFO).c_str(), NULL); - MenuSetText(hPopupMenu, 6, wGS(POPUP_GFX_PLUGIN).c_str(), NULL); - MenuSetText(hPopupMenu, 8, wGS(POPUP_SETTINGS).c_str(), NULL); - MenuSetText(hPopupMenu, 9, wGS(POPUP_CHEATS).c_str(), NULL); + MenuSetText(hPopupMenu, 1, wGS(POPUP_PLAYDISK).c_str(), NULL); + MenuSetText(hPopupMenu, 3, wGS(MENU_REFRESH).c_str(), NULL); + MenuSetText(hPopupMenu, 4, wGS(MENU_CHOOSE_ROM).c_str(), NULL); + MenuSetText(hPopupMenu, 6, wGS(POPUP_INFO).c_str(), NULL); + MenuSetText(hPopupMenu, 7, wGS(POPUP_GFX_PLUGIN).c_str(), NULL); + MenuSetText(hPopupMenu, 9, wGS(POPUP_SETTINGS).c_str(), NULL); + MenuSetText(hPopupMenu, 10, wGS(POPUP_CHEATS).c_str(), NULL); if (m_SelectedRom.size() == 0) { + DeleteMenu(hPopupMenu, 10, MF_BYPOSITION); DeleteMenu(hPopupMenu, 9, MF_BYPOSITION); DeleteMenu(hPopupMenu, 8, MF_BYPOSITION); DeleteMenu(hPopupMenu, 7, MF_BYPOSITION); DeleteMenu(hPopupMenu, 6, MF_BYPOSITION); DeleteMenu(hPopupMenu, 5, MF_BYPOSITION); - DeleteMenu(hPopupMenu, 4, MF_BYPOSITION); + DeleteMenu(hPopupMenu, 2, MF_BYPOSITION); DeleteMenu(hPopupMenu, 1, MF_BYPOSITION); DeleteMenu(hPopupMenu, 0, MF_BYPOSITION); } @@ -1524,17 +1530,17 @@ void CRomBrowser::RomList_PopupMenu(uint32_t /*pnmh*/) { bool inBasicMode = g_Settings->LoadDword(UserInterface_BasicMode) != 0; bool CheatsRemembered = g_Settings->LoadDword(Setting_RememberCheats) != 0; - if (!CheatsRemembered) { DeleteMenu(hPopupMenu, 9, MF_BYPOSITION); } - if (inBasicMode) { DeleteMenu(hPopupMenu, 8, MF_BYPOSITION); } - if (inBasicMode && !CheatsRemembered) { DeleteMenu(hPopupMenu, 7, MF_BYPOSITION); } - DeleteMenu(hPopupMenu, 6, MF_BYPOSITION); + if (!CheatsRemembered) { DeleteMenu(hPopupMenu, 10, MF_BYPOSITION); } + if (inBasicMode) { DeleteMenu(hPopupMenu, 9, MF_BYPOSITION); } + if (inBasicMode && !CheatsRemembered) { DeleteMenu(hPopupMenu, 8, MF_BYPOSITION); } + DeleteMenu(hPopupMenu, 7, MF_BYPOSITION); if (!inBasicMode && g_Plugins && g_Plugins->Gfx() && g_Plugins->Gfx()->GetRomBrowserMenu != NULL) { HMENU GfxMenu = (HMENU)g_Plugins->Gfx()->GetRomBrowserMenu(); if (GfxMenu) { MENUITEMINFO lpmii; - InsertMenuW(hPopupMenu, 6, MF_POPUP | MF_BYPOSITION, (uint32_t)GfxMenu, wGS(POPUP_GFX_PLUGIN).c_str()); + InsertMenuW(hPopupMenu, 7, MF_POPUP | MF_BYPOSITION, (uint32_t)GfxMenu, wGS(POPUP_GFX_PLUGIN).c_str()); lpmii.cbSize = sizeof(MENUITEMINFO); lpmii.fMask = MIIM_STATE; lpmii.fState = 0; diff --git a/Source/Project64/UserInterface/UIResources.rc b/Source/Project64/UserInterface/UIResources.rc index cd87b0b6b..afbc0b00d 100644 --- a/Source/Project64/UserInterface/UIResources.rc +++ b/Source/Project64/UserInterface/UIResources.rc @@ -895,6 +895,7 @@ BEGIN POPUP "PopupMenu" BEGIN MENUITEM "Play Game", ID_POPUPMENU_PLAYGAME + MENUITEM "Play Game with Disk", ID_POPUPMENU_PLAYGAMEWITHDISK MENUITEM SEPARATOR MENUITEM "Refresh Rom List", ID_POPUPMENU_REFRESHROMLIST MENUITEM "Choose Rom Directory...", ID_POPUPMENU_ROMDIRECTORY diff --git a/Source/Project64/UserInterface/resource.h b/Source/Project64/UserInterface/resource.h index 18799098c..04b70981d 100644 --- a/Source/Project64/UserInterface/resource.h +++ b/Source/Project64/UserInterface/resource.h @@ -329,6 +329,7 @@ #define IDC_NOTES_TEXT 1208 #define IDC_LANG_SEL 1219 #define ID_POPUP_SHOWINMEMORYVIEWER 40005 +#define ID_POPUPMENU_PLAYGAMEWITHDISK 40008 #define ID_POPUPMENU_ROMDIRECTORY 40137 #define ID_POPUPMENU_REFRESHROMLIST 40138 #define ID_POPUPMENU_PLAYGAME 40152 @@ -344,7 +345,7 @@ #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 150 -#define _APS_NEXT_COMMAND_VALUE 40008 +#define _APS_NEXT_COMMAND_VALUE 40009 #define _APS_NEXT_CONTROL_VALUE 1100 #define _APS_NEXT_SYMED_VALUE 101 #endif