Merge pull request #937 from LuigiBlood/64dd_2

64DD support
This commit is contained in:
zilmar 2016-01-27 19:07:19 +11:00
commit a86ba8db2d
27 changed files with 1316 additions and 96 deletions

View File

@ -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"

View File

@ -8,6 +8,7 @@
#include <Project64-core/N64System/SystemGlobals.h>
#include <Project64-core/Plugins/PluginClass.h>
#include <Project64-core/N64System/N64RomClass.h>
#include <Project64-core/N64System/N64DiskClass.h>
#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; }

View File

@ -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,

View File

@ -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");

View File

@ -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 <Project64-core/N64System/N64DiskClass.h>
#include <Project64-core/N64System/SystemGlobals.h>
#include <Project64-core/N64System/Mips/RegisterClass.h>
#include <Project64-core/N64System/Mips/SystemTiming.h>
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(&ltime);
struct tm result = { 0 };
localtime_r(&ltime, &result);
time_t ltime;
ltime = time(&ltime);
struct tm result = { 0 };
localtime_r(&ltime, &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();
}
}

View File

@ -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 <Common/stdtypes.h>
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

View File

@ -16,6 +16,8 @@
#include <Project64-core/N64System/N64RomClass.h>
#include <Project64-core/N64System/Mips/MemoryVirtualMem.h>
#include <Project64-core/N64System/Mips/RegisterClass.h>
#include <Project64-core/N64System/Mips/Disk.h>
#include <Project64-core/N64System/N64DiskClass.h>
#include <Project64-core/N64System/N64Class.h>
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;

View File

@ -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();

View File

@ -12,6 +12,7 @@
#include <Project64-core/N64System/Mips/SystemTiming.h>
#include <Project64-core/N64System/SystemGlobals.h>
#include <Project64-core/N64System/Mips/RegisterClass.h>
#include <Project64-core/N64System/Mips/Disk.h>
#include <Project64-core/N64System/N64Class.h>
#include <Project64-core/3rdParty/zip.h>
@ -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
{

View File

@ -29,6 +29,7 @@ public:
PiTimer,
RspTimer,
RSPTimerDlist,
DDPiTimer,
MaxTimer
};

View File

@ -16,6 +16,7 @@
#include <Project64-core/N64System/Mips/Mempak.H>
#include <Project64-core/N64System/Interpreter/InterpreterCPU.h>
#include <Project64-core/N64System/Mips/OpcodeName.h>
#include <Project64-core/N64System/N64DiskClass.h>
#include <Project64-core/ExceptionHandler.h>
#include <Project64-core/Logging.h>
#include <Project64-core/Debugger.h>
@ -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)

View File

@ -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();

View File

@ -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 <Common/Platform.h>
#include <Common/MemoryManagement.h>
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<uint8_t> 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);
}
}
}

View File

@ -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 <Common/stdtypes.h>
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)
};

View File

@ -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<char*>(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)

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -61,6 +61,7 @@
<ClCompile Include="N64System\Mips\SystemTiming.cpp" />
<ClCompile Include="N64System\Mips\TLBclass.cpp" />
<ClCompile Include="N64System\N64Class.cpp" />
<ClCompile Include="N64System\N64DiskClass.cpp" />
<ClCompile Include="N64System\N64RomClass.cpp" />
<ClCompile Include="N64System\ProfilingClass.cpp" />
<ClCompile Include="N64System\Recompiler\CodeBlock.cpp" />
@ -148,6 +149,7 @@
<ClInclude Include="N64System\Mips\TLBClass.h" />
<ClInclude Include="N64System\Mips\TranslateVaddr.h" />
<ClInclude Include="N64System\N64Class.h" />
<ClInclude Include="N64System\N64DiskClass.h" />
<ClInclude Include="N64System\N64RomClass.h" />
<ClInclude Include="N64System\N64Types.h" />
<ClInclude Include="N64System\ProfilingClass.h" />

View File

@ -297,6 +297,9 @@
<ClCompile Include="N64System\Mips\Disk.cpp">
<Filter>Source Files\N64 System\Mips</Filter>
</ClCompile>
<ClCompile Include="N64System\N64DiskClass.cpp">
<Filter>Source Files\N64 System</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@ -578,5 +581,8 @@
<ClInclude Include="N64System\Mips\Disk.h">
<Filter>Header Files\N64 System\Mips</Filter>
</ClInclude>
<ClInclude Include="N64System\N64DiskClass.h">
<Filter>Header Files\N64 System</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -224,6 +224,7 @@ enum SettingID
//File Info
File_RecentGameFileCount,
File_RecentGameFileIndex,
File_DiskIPLPath,
//Debugger
Debugger_Enabled,

View File

@ -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));

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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