refactor slot-1 to object oriented interface; clean up and clarify a lot of firmware boot process and card-eject handling stuff. I probably broke some things, but I'm in the mood lately to tidy it up as soon as anyone notices
This commit is contained in:
parent
5e0b720c9d
commit
590acba412
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
Copyright (C) 2006 yopyop
|
||||
Copyright (C) 2007 shash
|
||||
Copyright (C) 2007-2012 DeSmuME team
|
||||
Copyright (C) 2007-2013 DeSmuME team
|
||||
|
||||
This file is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -933,7 +933,9 @@ void MMU_Init(void) {
|
|||
//MMU.bupmem.fp = NULL;
|
||||
rtcInit();
|
||||
addonsInit();
|
||||
slot1Init();
|
||||
|
||||
slot1_Init();
|
||||
|
||||
if(Mic_Init() == FALSE)
|
||||
INFO("Microphone init failed.\n");
|
||||
else
|
||||
|
@ -949,7 +951,7 @@ void MMU_DeInit(void) {
|
|||
// fclose(MMU.bupmem.fp);
|
||||
//mc_free(&MMU.bupmem);
|
||||
addonsClose();
|
||||
slot1Close();
|
||||
slot1_Shutdown();
|
||||
Mic_DeInit();
|
||||
}
|
||||
|
||||
|
@ -1028,7 +1030,7 @@ void MMU_Reset()
|
|||
rtcInit();
|
||||
partie = 1;
|
||||
addonsReset();
|
||||
slot1Reset();
|
||||
slot1_Reset();
|
||||
Mic_Reset();
|
||||
MMU.gfx3dCycles = 0;
|
||||
|
||||
|
@ -1394,13 +1396,15 @@ void FASTCALL MMU_writeToGCControl(u32 val)
|
|||
break;
|
||||
default:
|
||||
//fall through to the special slot1 handler
|
||||
slot1_device.write32(PROCNUM, REG_GCROMCTRL,val);
|
||||
slot1_device->write32(PROCNUM, REG_GCROMCTRL,val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (card.mode == CardMode_KEY1 || card.mode == CardMode_KEY2)
|
||||
{
|
||||
//<zero> really? the values from memory are used here?
|
||||
//somehow I doubt it. are they stored in the gamecard controllers somehow?
|
||||
u32 gameID = MMU_read32(PROCNUM, 0x027FFE0C);
|
||||
u32 chipID = MMU_read32(PROCNUM, 0x027FF800);
|
||||
u64 cmd = bswap64(*(u64 *)&card.command[0]);
|
||||
|
@ -1411,7 +1415,7 @@ void FASTCALL MMU_writeToGCControl(u32 val)
|
|||
|
||||
switch (cmd >> 60)
|
||||
{
|
||||
case 0x02: // Get secure are block (4Kbytes) - 910h+11A8h
|
||||
case 0x02: // Get secure area block (4Kbytes) - 910h+11A8h
|
||||
{
|
||||
u32 addr = (u32)((cmd >> 32) & 0xF000);
|
||||
#ifdef _LOG_NEW_BOOT
|
||||
|
@ -1457,14 +1461,14 @@ void FASTCALL MMU_writeToGCControl(u32 val)
|
|||
//card.delay = 0x910;
|
||||
break;
|
||||
default:
|
||||
slot1_device.write32(PROCNUM, REG_GCROMCTRL, val);
|
||||
slot1_device->write32(PROCNUM, REG_GCROMCTRL, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (card.mode == CardMode_DATA_LOAD)
|
||||
{
|
||||
slot1_device.write32(PROCNUM, REG_GCROMCTRL, val);
|
||||
slot1_device->write32(PROCNUM, REG_GCROMCTRL, val);
|
||||
#ifdef _LOG_NEW_BOOT
|
||||
if (fp_dis7)
|
||||
fprintf(fp_dis7, "ARM%c: main data mode cmd %02X (addr %08X, len %08X)\n", PROCNUM?'7':'9', card.command[0], card.address, card.transfer_count);
|
||||
|
@ -1535,7 +1539,7 @@ u32 MMU_readFromGC()
|
|||
break;
|
||||
|
||||
default:
|
||||
val = slot1_device.read32(TEST_PROCNUM, REG_GCDATAIN);
|
||||
val = slot1_device->read32(TEST_PROCNUM, REG_GCDATAIN);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3748,7 +3752,7 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val)
|
|||
case REG_DISPA_DISP3DCNT: writereg_DISP3DCNT(32,adr,val); return;
|
||||
|
||||
case REG_GCDATAIN:
|
||||
slot1_device.write32(ARMCPU_ARM9, REG_GCDATAIN,val);
|
||||
slot1_device->write32(ARMCPU_ARM9, REG_GCDATAIN,val);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4490,7 +4494,7 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val)
|
|||
return;
|
||||
|
||||
case REG_GCDATAIN:
|
||||
slot1_device.write32(ARMCPU_ARM7, REG_GCDATAIN,val);
|
||||
slot1_device->write32(ARMCPU_ARM7, REG_GCDATAIN,val);
|
||||
return;
|
||||
}
|
||||
T1WriteLong(MMU.MMU_MEM[ARMCPU_ARM7][adr>>20], adr & MMU.MMU_MASK[ARMCPU_ARM7][adr>>20], val);
|
||||
|
|
|
@ -303,9 +303,9 @@ enum ECardMode
|
|||
CardMode_DATA_LOAD
|
||||
};
|
||||
|
||||
typedef struct
|
||||
//should rather be known as gamecard bus controller, or somesuch
|
||||
struct nds_dscard
|
||||
{
|
||||
|
||||
u8 command[8];
|
||||
|
||||
u32 address;
|
||||
|
@ -316,8 +316,7 @@ typedef struct
|
|||
|
||||
// NJSD stuff
|
||||
int blocklen;
|
||||
|
||||
} nds_dscard;
|
||||
};
|
||||
|
||||
#define DUP2(x) x, x
|
||||
#define DUP4(x) x, x, x, x
|
||||
|
|
|
@ -450,10 +450,7 @@ static void loadrom(std::string fname) {
|
|||
|
||||
extern NDS_SLOT1_TYPE slot1_device_type;
|
||||
|
||||
if (slot1_device_type == NDS_SLOT1_NONE)
|
||||
memset(gameInfo.romdata, 0xFF, size);
|
||||
else
|
||||
fread(gameInfo.romdata,1,size,inf);
|
||||
fread(gameInfo.romdata,1,size,inf);
|
||||
gameInfo.fillGap();
|
||||
|
||||
fclose(inf);
|
||||
|
@ -575,6 +572,14 @@ int NDS_LoadROM(const char *filename, const char *physicalName, const char *logi
|
|||
cheatSearch->close();
|
||||
FCEUI_StopMovie();
|
||||
|
||||
|
||||
//check whether this rom is any kind of valid
|
||||
if(!CheckValidRom((u8*)gameInfo.romdata,gameInfo.romsize))
|
||||
{
|
||||
printf("Specified file is not a valid rom\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
MMU_unsetRom();
|
||||
NDS_SetROM((u8*)gameInfo.romdata, gameInfo.mask);
|
||||
|
||||
|
@ -962,6 +967,7 @@ void NDS_Sleep() { nds.sleeping = TRUE; }
|
|||
void NDS_TriggerCardEjectIRQ()
|
||||
{
|
||||
NDS_makeIrq(ARMCPU_ARM7, IRQ_BIT_GC_IREQ_MC);
|
||||
NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_GC_IREQ_MC); //zero added on 11-aug-2013 with no proof of accuracy
|
||||
}
|
||||
|
||||
|
||||
|
@ -2209,8 +2215,10 @@ static void resetUserInput();
|
|||
|
||||
static void PrepareBiosARM7()
|
||||
{
|
||||
//begin with the bios unloaded
|
||||
NDS_ARM7.BIOS_loaded = false;
|
||||
memset(MMU.ARM7_BIOS, 0, sizeof(MMU.ARM7_BIOS));
|
||||
|
||||
if(CommonSettings.UseExtBIOS == true)
|
||||
{
|
||||
//read arm7 bios from inputfile and flag it if it succeeds
|
||||
|
@ -2264,8 +2272,10 @@ static void PrepareBiosARM7()
|
|||
|
||||
static void PrepareBiosARM9()
|
||||
{
|
||||
//begin with the bios unloaded
|
||||
memset(MMU.ARM9_BIOS, 0, sizeof(MMU.ARM9_BIOS));
|
||||
NDS_ARM9.BIOS_loaded = false;
|
||||
|
||||
if(CommonSettings.UseExtBIOS == true)
|
||||
{
|
||||
//read arm9 bios from inputfile and flag it if it succeeds
|
||||
|
@ -2322,11 +2332,12 @@ static void PrepareBiosARM9()
|
|||
0xD6,0x25,0xE4,0x8B,0x38,0x0A,0xAC,0x72,0x21,0xD4,0xF8,0x07
|
||||
};
|
||||
|
||||
// logo - Pokemon Platinum using this in Pal Park trade from GBA Slot
|
||||
//copy the logo content into the bios - Pokemon Platinum uses this in Pal Park trade
|
||||
//it compares the logo from the arm9 bios to the logo in the GBA header.
|
||||
//NOTE: we could solve this by patching the rom of a mounted GBA game with whatever's here, even if its all zeroes.
|
||||
for (int t = 0; t < 0x9C; t++)
|
||||
MMU.ARM9_BIOS[t + 0x20] = logo_data[t];
|
||||
|
||||
//...0xBC:
|
||||
//... and with that we are at 0xBC:
|
||||
|
||||
//(now what goes in this gap??)
|
||||
|
||||
|
@ -2512,21 +2523,31 @@ void NDS_Reset()
|
|||
// TODO: fw_success should be global
|
||||
bool fw_success = firmware->load();
|
||||
|
||||
//the firmware can't be booted without the roms, for the following reasons:
|
||||
//TBD
|
||||
if (NDS_ARM7.BIOS_loaded && NDS_ARM9.BIOS_loaded && CommonSettings.BootFromFirmware && fw_success)
|
||||
{
|
||||
gameInfo.restoreSecureArea();
|
||||
//crazymax: how would it have got whacked? dont think we need this
|
||||
//gameInfo.restoreSecureArea();
|
||||
|
||||
//partially clobber the loaded firmware with the user settings from DFC
|
||||
firmware->loadSettings();
|
||||
|
||||
// Firmware boot only encrypted ROMs
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
EncryptSecureArea((u8*)gameInfo.romdata,gameInfo.romsize);
|
||||
#endif
|
||||
//since firmware only boots encrypted roms, we have to make sure it's encrypted first
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
//this has not been validated on big endian systems. it almost positively doesn't work.
|
||||
EncryptSecureArea((u8*)gameInfo.romdata,gameInfo.romsize);
|
||||
#endif
|
||||
|
||||
//boot processors from their bios entrypoints
|
||||
armcpu_init(&NDS_ARM7, 0x00000000);
|
||||
armcpu_init(&NDS_ARM9, 0xFFFF0000);
|
||||
|
||||
// TODO: hack!!!
|
||||
// possible explanation - since we can't generally trust calibration info from the firmware (who's bothered to set it up?)
|
||||
// we don't bother to use the firmware's configured calibration info, and just enter our own.
|
||||
// Can someone verify this?
|
||||
// TODO - this isn't good. need revising.
|
||||
TSCal.adc.x1 = 0x0228;
|
||||
TSCal.adc.y1 = 0x0350;
|
||||
TSCal.scr.x1 = 0x0020;
|
||||
|
@ -2535,7 +2556,6 @@ void NDS_Reset()
|
|||
TSCal.adc.y2 = 0x0BFC;
|
||||
TSCal.scr.x2 = 0xE0;
|
||||
TSCal.scr.y2 = 0xA0;
|
||||
|
||||
TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1);
|
||||
TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1);
|
||||
TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1);
|
||||
|
@ -2543,12 +2563,14 @@ void NDS_Reset()
|
|||
}
|
||||
else
|
||||
{
|
||||
//fake firmware boot-up process
|
||||
//the fake firmware boot-up process
|
||||
|
||||
gameInfo.restoreSecureArea();
|
||||
//decrypt if necessary..
|
||||
//but this is untested and suspected to fail on big endian, so lets not support this on big endian
|
||||
//crazymax: how would it have got whacked? dont think we need this
|
||||
//gameInfo.restoreSecureArea();
|
||||
|
||||
//since we're bypassing the code to decrypt the secure area, we need to make sure its decrypted first
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
//this has not been validated on big endian systems. it almost positively doesn't work.
|
||||
bool okRom = DecryptSecureArea((u8*)gameInfo.romdata,gameInfo.romsize);
|
||||
|
||||
if(!okRom) {
|
||||
|
@ -2556,13 +2578,12 @@ void NDS_Reset()
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
//according to smea, this is initialized to 3 by the time we get into a user game program. who does this?
|
||||
//well, the firmware load process is about to write a boot program into SIWRAM for the arm7. so we need it setup by now.
|
||||
//but, this is a bit weird.. I would be expecting the bioses to do that. maybe we have some more detail to emulate.
|
||||
//* is this setting the default, or does the bios do it before loading the firmware programs?
|
||||
//at any, it's important that this be done long before the user code ever runs
|
||||
|
||||
//bios (or firmware) sets this default
|
||||
_MMU_write08<ARMCPU_ARM9>(REG_WRAMCNT,3);
|
||||
|
||||
//EDIT - whats this firmware and how is it relating to the dummy firmware below
|
||||
//how do these even get used? what is the purpose of unpack and why is it not used by the firmware boot process?
|
||||
if (CommonSettings.UseExtFirmware && fw_success)
|
||||
{
|
||||
firmware->unpack();
|
||||
|
@ -2570,8 +2591,11 @@ void NDS_Reset()
|
|||
}
|
||||
|
||||
// Create the dummy firmware
|
||||
//EDIT - whats dummy firmware and how is relating to the above?
|
||||
//it seems to be emplacing basic firmware data into MMU.fw.data
|
||||
NDS_CreateDummyFirmware(&CommonSettings.fw_config);
|
||||
|
||||
//firmware loads the game card arm9 and arm7 programs as specified in rom header
|
||||
{
|
||||
//copy the arm9 program to the address specified by rom header
|
||||
u32 src = header->ARM9src;
|
||||
|
@ -2594,25 +2618,21 @@ void NDS_Reset()
|
|||
}
|
||||
}
|
||||
|
||||
//set the cpus to an initial state with their respective programs entrypoints
|
||||
armcpu_init(&NDS_ARM7, header->ARM7exe);
|
||||
armcpu_init(&NDS_ARM9, header->ARM9exe);
|
||||
//bios does this (thats weird, though. shouldnt it get changed when the card is swapped in the firmware menu?
|
||||
//right now our firmware menu isnt detecting any change to the card.
|
||||
//are some games depending on it being written here? please document.
|
||||
//_MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E));
|
||||
|
||||
//set REG_POSTFLG to the value indicating post-firmware status
|
||||
MMU.ARM9_REG[0x300] = 1;
|
||||
MMU.ARM7_REG[0x300] = 1;
|
||||
|
||||
//Setup a copy of the firmware user settings in memory.
|
||||
//(this is what the DS firmware would do).
|
||||
//firmware sets up a copy of the firmware user settings in memory.
|
||||
//TBD - this code is really clunky
|
||||
//it seems to be copying the MMU.fw.data data into RAM in the user memory stash locations
|
||||
u8 temp_buffer[NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT];
|
||||
int fw_index;
|
||||
|
||||
if ( copy_firmware_user_data( temp_buffer, MMU.fw.data)) {
|
||||
for ( fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++)
|
||||
for ( int fw_index = 0; fw_index < NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT; fw_index++)
|
||||
_MMU_write08<ARMCPU_ARM9>(0x027FFC80 + fw_index, temp_buffer[fw_index]);
|
||||
}
|
||||
|
||||
// Copy the whole header to Main RAM 0x27FFE00 on startup. (http://nocash.emubase.de/gbatek.htm#dscartridgeheader)
|
||||
//firmware copies the whole header to Main RAM 0x27FFE00 on startup. (http://nocash.emubase.de/gbatek.htm#dscartridgeheader)
|
||||
//once upon a time this copied 0x90 more. this was thought to be wrong, and changed.
|
||||
if(nds.Is_DSI())
|
||||
{
|
||||
|
@ -2626,12 +2646,21 @@ void NDS_Reset()
|
|||
_MMU_write32<ARMCPU_ARM9>(0x027FFE00+i*4, LE_TO_LOCAL_32(((u32*)MMU.CART_ROM)[i]));
|
||||
}
|
||||
|
||||
// make system think it's booted from card -- EXTREMELY IMPORTANT!!! Thanks to cReDiAr
|
||||
//firmware sets the cpus to an initial state with their respective programs entrypoints
|
||||
armcpu_init(&NDS_ARM7, header->ARM7exe);
|
||||
armcpu_init(&NDS_ARM9, header->ARM9exe);
|
||||
|
||||
//firmware sets REG_POSTFLG to the value indicating post-firmware status
|
||||
MMU.ARM9_REG[0x300] = 1;
|
||||
MMU.ARM7_REG[0x300] = 1;
|
||||
|
||||
//firmware makes system think it's booted from card -- EXTREMELY IMPORTANT!!! Thanks to cReDiAr
|
||||
_MMU_write08<ARMCPU_ARM9>(0x02FFFC40,0x1);
|
||||
_MMU_write08<ARMCPU_ARM7>(0x02FFFC40,0x1);
|
||||
|
||||
// Save touchscreen calibration info in a structure
|
||||
// so we can easily access it at any time
|
||||
// TODO - this isn't good. need revising.
|
||||
TSCal.adc.x1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x58);
|
||||
TSCal.adc.y1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5A);
|
||||
TSCal.scr.x1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5C);
|
||||
|
@ -2640,15 +2669,15 @@ void NDS_Reset()
|
|||
TSCal.adc.y2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x60);
|
||||
TSCal.scr.x2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x62);
|
||||
TSCal.scr.y2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x63);
|
||||
|
||||
TSCal.adc.width = (TSCal.adc.x2 - TSCal.adc.x1);
|
||||
TSCal.adc.height = (TSCal.adc.y2 - TSCal.adc.y1);
|
||||
TSCal.scr.width = (TSCal.scr.x2 - TSCal.scr.x1);
|
||||
TSCal.scr.height = (TSCal.scr.y2 - TSCal.scr.y1);
|
||||
|
||||
_MMU_write16<ARMCPU_ARM9>(REG_KEYINPUT, 0x3FF);
|
||||
_MMU_write16<ARMCPU_ARM7>(REG_KEYINPUT, 0x3FF);
|
||||
_MMU_write08<ARMCPU_ARM7>(REG_EXTKEYIN, 0x43);
|
||||
//zero 11-aug-2013 - dont think we need this. the emulator will be setting these nonstop
|
||||
//_MMU_write16<ARMCPU_ARM9>(REG_KEYINPUT, 0x3FF);
|
||||
//_MMU_write16<ARMCPU_ARM7>(REG_KEYINPUT, 0x3FF);
|
||||
//_MMU_write08<ARMCPU_ARM7>(REG_EXTKEYIN, 0x43);
|
||||
|
||||
//bitbox 4k demo is so stripped down it relies on default stack values
|
||||
//otherwise the arm7 will crash before making a sound
|
||||
|
@ -2699,7 +2728,7 @@ void NDS_Reset()
|
|||
Screen_Reset();
|
||||
gfx3d_reset();
|
||||
gpu3D->NDS_3D_Reset();
|
||||
slot1Reset();
|
||||
slot1_Reset();
|
||||
|
||||
WIFI_Reset();
|
||||
memcpy(FW_Mac, (MMU.fw.data + 0x36), 6);
|
||||
|
|
|
@ -326,7 +326,7 @@ struct GameInfo
|
|||
memset(&header, 0, sizeof(header));
|
||||
memset(&ROMserial[0], 0, sizeof(ROMserial));
|
||||
memset(&ROMname[0], 0, sizeof(ROMname));
|
||||
memset(&securyArea[0], 0, sizeof(securyArea));
|
||||
memset(&secureArea[0], 0, sizeof(secureArea));
|
||||
}
|
||||
|
||||
void loadData(char* buf, int size)
|
||||
|
@ -340,13 +340,13 @@ struct GameInfo
|
|||
void storeSecureArea()
|
||||
{
|
||||
if ((header.ARM9src >= 0x4000) && (header.ARM9src < 0x8000))
|
||||
memcpy(&securyArea[0], &romdata[header.ARM9src], 0x8000 - header.ARM9src);
|
||||
memcpy(&secureArea[0], &romdata[header.ARM9src], 0x8000 - header.ARM9src);
|
||||
}
|
||||
|
||||
void restoreSecureArea()
|
||||
{
|
||||
if ((header.ARM9src >= 0x4000) && (header.ARM9src < 0x8000))
|
||||
memcpy(&romdata[header.ARM9src], &securyArea[0], 0x8000 - header.ARM9src);
|
||||
memcpy(&romdata[header.ARM9src], &secureArea[0], 0x8000 - header.ARM9src);
|
||||
}
|
||||
|
||||
void fillGap()
|
||||
|
@ -385,7 +385,9 @@ struct GameInfo
|
|||
const RomBanner& getRomBanner();
|
||||
bool hasRomBanner();
|
||||
bool isHomebrew;
|
||||
u8 securyArea[0x4000];
|
||||
|
||||
//a copy of the pristine secure area from the rom
|
||||
u8 secureArea[0x4000];
|
||||
};
|
||||
|
||||
typedef struct TSCalInfo
|
||||
|
|
|
@ -47,7 +47,7 @@ ADDONINTERFACE addonList[NDS_ADDON_COUNT] = {
|
|||
addonPaddle
|
||||
};
|
||||
|
||||
ADDONINTERFACE addon = addonCFlash; // default none pak
|
||||
ADDONINTERFACE addon = addonCFlash; // default cflash pak (why??)
|
||||
NDS_ADDON_TYPE addon_type = NDS_ADDON_CFLASH;
|
||||
|
||||
BOOL addonsInit()
|
||||
|
|
|
@ -20,51 +20,28 @@
|
|||
#include "../MMU.h"
|
||||
#include "../NDSSystem.h"
|
||||
|
||||
static void slot1_info(char *info) { strcpy(info, "Slot1 no-card emulation"); }
|
||||
static void slot1_config(void) {}
|
||||
|
||||
static BOOL slot1_init() { return (TRUE); }
|
||||
|
||||
static void slot1_reset()
|
||||
class Slot1_None : public ISlot1Interface
|
||||
{
|
||||
// Write the header checksum to memory (the firmware needs it to see the cart)
|
||||
if (!CommonSettings.BootFromFirmware)
|
||||
_MMU_write16<ARMCPU_ARM9>(0x027FF808, 0);
|
||||
}
|
||||
public:
|
||||
virtual Slot1Info const* info()
|
||||
{
|
||||
static Slot1InfoSimple info("None","Slot1 no-card emulation");
|
||||
return &info;
|
||||
}
|
||||
|
||||
static void slot1_close() {}
|
||||
virtual void connect()
|
||||
{
|
||||
}
|
||||
|
||||
virtual u32 read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
//return a chip ID of 0.
|
||||
//if (adr == REG_GCDATAIN && MMU.dscard[PROCNUM].command[0] == 0xB8) return 0;
|
||||
//EDIT - not sure who did this or why, but... but if a card is ejected, there can be no chip ID.
|
||||
//we certainly want it to appear differently from chipId 0, which is something we are faking in other slot-1 devices
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static void slot1_write08(u8 PROCNUM, u32 adr, u8 val) {}
|
||||
static void slot1_write16(u8 PROCNUM, u32 adr, u16 val) {}
|
||||
static void slot1_write32(u8 PROCNUM, u32 adr, u32 val) {}
|
||||
};
|
||||
|
||||
static u8 slot1_read08(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
static u16 slot1_read16(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
static u32 slot1_read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
if (adr == REG_GCDATAIN && MMU.dscard[PROCNUM].command[0] == 0xB8)
|
||||
return 0;
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
SLOT1INTERFACE slot1None = {
|
||||
"None",
|
||||
slot1_init,
|
||||
slot1_reset,
|
||||
slot1_close,
|
||||
slot1_config,
|
||||
slot1_write08,
|
||||
slot1_write16,
|
||||
slot1_write32,
|
||||
slot1_read08,
|
||||
slot1_read16,
|
||||
slot1_read32,
|
||||
slot1_info};
|
||||
ISlot1Interface* construct_Slot1_None() { return new Slot1_None(); }
|
|
@ -23,215 +23,209 @@
|
|||
#include "../NDSSystem.h"
|
||||
#include "../emufile.h"
|
||||
|
||||
static EMUFILE *img = NULL;
|
||||
static u32 write_count = 0;
|
||||
static u32 write_enabled = 0;
|
||||
static void init_r4_flash()
|
||||
class Slot1_R4 : public ISlot1Interface
|
||||
{
|
||||
srand(time(NULL));
|
||||
private:
|
||||
EMUFILE *img;
|
||||
u32 write_count;
|
||||
u32 write_enabled;
|
||||
|
||||
if (!img)
|
||||
img = slot1GetFatImage();
|
||||
|
||||
if(!img)
|
||||
public:
|
||||
Slot1_R4()
|
||||
: img(NULL)
|
||||
, write_count(0)
|
||||
, write_enabled(0)
|
||||
{
|
||||
INFO("slot1 fat not successfully mounted\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void info(char *info) { strcpy(info, "Slot1 R4 Emulation"); }
|
||||
static void config(void) {}
|
||||
|
||||
static BOOL init()
|
||||
{
|
||||
init_r4_flash();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
// Write the header checksum to memory (the firmware needs it to see the cart)
|
||||
_MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E));
|
||||
init_r4_flash();
|
||||
}
|
||||
|
||||
static void close() {
|
||||
img = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void write08(u8 PROCNUM, u32 adr, u8 val) {}
|
||||
static void write16(u8 PROCNUM, u32 adr, u16 val) {}
|
||||
|
||||
static void write32_GCROMCTRL(u32 val)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[0];
|
||||
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0xB0:
|
||||
break;
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
img->fseek(card.address,SEEK_SET);
|
||||
break;
|
||||
case 0xBB:
|
||||
write_enabled = 1;
|
||||
write_count = 0x80;
|
||||
case 0xBC:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
img->fseek(card.address,SEEK_SET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void write32_GCDATAIN(u32 val)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[0];
|
||||
//bool log=false;
|
||||
|
||||
memcpy(&card.command[0], &MMU.MMU_MEM[0][0x40][0x1A8], 8);
|
||||
|
||||
//last_write_count = write_count;
|
||||
if(card.command[4])
|
||||
{
|
||||
// transfer is done
|
||||
T1WriteLong(MMU.MMU_MEM[0][0x40], 0x1A4,val & 0x7F7FFFFF);
|
||||
|
||||
// if needed, throw irq for the end of transfer
|
||||
if(MMU.AUX_SPI_CNT & 0x4000)
|
||||
NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_GC_TRANSFER_COMPLETE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch(card.command[0])
|
||||
virtual Slot1Info const* info()
|
||||
{
|
||||
case 0xBB:
|
||||
{
|
||||
if(write_count && write_enabled)
|
||||
{
|
||||
img->fwrite(&val, 4);
|
||||
img->fflush();
|
||||
write_count--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
static Slot1InfoSimple info("R4","Slot1 R4 Emulation");
|
||||
return &info;
|
||||
}
|
||||
|
||||
if(write_count==0)
|
||||
|
||||
//called once when the emulator starts up, or when the device springs into existence
|
||||
virtual bool init()
|
||||
{
|
||||
write_enabled = 0;
|
||||
|
||||
// transfer is done
|
||||
T1WriteLong(MMU.MMU_MEM[0][0x40], 0x1A4,val & 0x7F7FFFFF);
|
||||
|
||||
// if needed, throw irq for the end of transfer
|
||||
if(MMU.AUX_SPI_CNT & 0x4000)
|
||||
NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_GC_TRANSFER_COMPLETE);
|
||||
//strange to do this here but we need to make sure its done at some point
|
||||
srand(time(NULL));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*if(log)
|
||||
{
|
||||
INFO("WRITE CARD command: %02X%02X%02X%02X%02X%02X%02X%02X\t",
|
||||
card.command[0], card.command[1], card.command[2], card.command[3],
|
||||
card.command[4], card.command[5], card.command[6], card.command[7]);
|
||||
INFO("FROM: %08X\t", NDS_ARM9.instruct_adr);
|
||||
INFO("VAL: %08X\n", val);
|
||||
}*/
|
||||
}
|
||||
|
||||
static void write32(u8 PROCNUM, u32 adr, u32 val)
|
||||
{
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCROMCTRL:
|
||||
write32_GCROMCTRL(val);
|
||||
break;
|
||||
case REG_GCDATAIN:
|
||||
write32_GCDATAIN(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 read08(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
static u16 read16(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
|
||||
static u32 read32_GCDATAIN()
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[0];
|
||||
|
||||
u32 val;
|
||||
|
||||
switch(card.command[0])
|
||||
virtual void connect()
|
||||
{
|
||||
//Get ROM chip ID
|
||||
case 0x90:
|
||||
case 0xB8:
|
||||
val = 0xFC2;
|
||||
break;
|
||||
img = slot1_GetFatImage();
|
||||
|
||||
case 0xB0:
|
||||
val = 0x1F4;
|
||||
break;
|
||||
case 0xB9:
|
||||
val = (rand() % 100) ? 0x1F4 : 0;
|
||||
break;
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
val = 0;
|
||||
break;
|
||||
case 0xBA:
|
||||
//INFO("Read from sd at sector %08X at adr %08X ",card.address/512,ftell(img));
|
||||
img->fread(&val, 4);
|
||||
//INFO("val %08X\n",val);
|
||||
break;
|
||||
if(!img)
|
||||
INFO("slot1 fat not successfully mounted\n");
|
||||
}
|
||||
|
||||
//called when the emulator disconnects the device
|
||||
virtual void disconnect()
|
||||
{
|
||||
img = NULL;
|
||||
}
|
||||
|
||||
//called when the emulator shuts down, or when the device disappears from existence
|
||||
virtual void shutdown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual u32 read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCDATAIN:
|
||||
return read32_GCDATAIN();
|
||||
default:
|
||||
val = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*INFO("READ CARD command: %02X%02X%02X%02X% 02X%02X%02X%02X RET: %08X ",
|
||||
card.command[0], card.command[1], card.command[2], card.command[3],
|
||||
card.command[4], card.command[5], card.command[6], card.command[7],
|
||||
val);
|
||||
INFO("FROM: %08X LR: %08X\n", NDS_ARM9.instruct_adr, NDS_ARM9.R[14]);*/
|
||||
|
||||
|
||||
return val;
|
||||
} //read32_GCDATAIN
|
||||
|
||||
|
||||
static u32 read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
switch(adr)
|
||||
virtual void write32(u8 PROCNUM, u32 adr, u32 val)
|
||||
{
|
||||
case REG_GCDATAIN:
|
||||
return read32_GCDATAIN();
|
||||
default:
|
||||
return 0;
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCROMCTRL:
|
||||
write32_GCROMCTRL(val);
|
||||
break;
|
||||
case REG_GCDATAIN:
|
||||
write32_GCDATAIN(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SLOT1INTERFACE slot1R4 = {
|
||||
"R4",
|
||||
init,
|
||||
reset,
|
||||
close,
|
||||
config,
|
||||
write08,
|
||||
write16,
|
||||
write32,
|
||||
read08,
|
||||
read16,
|
||||
read32,
|
||||
info};
|
||||
private:
|
||||
|
||||
u32 read32_GCDATAIN()
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[0];
|
||||
|
||||
u32 val;
|
||||
|
||||
switch(card.command[0])
|
||||
{
|
||||
//Get ROM chip ID
|
||||
case 0x90:
|
||||
case 0xB8:
|
||||
val = 0xFC2;
|
||||
break;
|
||||
|
||||
case 0xB0:
|
||||
val = 0x1F4;
|
||||
break;
|
||||
case 0xB9:
|
||||
val = (rand() % 100) ? 0x1F4 : 0;
|
||||
break;
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
val = 0;
|
||||
break;
|
||||
case 0xBA:
|
||||
//INFO("Read from sd at sector %08X at adr %08X ",card.address/512,ftell(img));
|
||||
img->fread(&val, 4);
|
||||
//INFO("val %08X\n",val);
|
||||
break;
|
||||
|
||||
default:
|
||||
val = 0;
|
||||
}
|
||||
|
||||
/*INFO("READ CARD command: %02X%02X%02X%02X% 02X%02X%02X%02X RET: %08X ",
|
||||
card.command[0], card.command[1], card.command[2], card.command[3],
|
||||
card.command[4], card.command[5], card.command[6], card.command[7],
|
||||
val);
|
||||
INFO("FROM: %08X LR: %08X\n", NDS_ARM9.instruct_adr, NDS_ARM9.R[14]);*/
|
||||
|
||||
|
||||
return val;
|
||||
} //read32_GCDATAIN
|
||||
|
||||
|
||||
void write32_GCROMCTRL(u32 val)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[0];
|
||||
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0xB0:
|
||||
break;
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
img->fseek(card.address,SEEK_SET);
|
||||
break;
|
||||
case 0xBB:
|
||||
write_enabled = 1;
|
||||
write_count = 0x80;
|
||||
case 0xBC:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
img->fseek(card.address,SEEK_SET);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write32_GCDATAIN(u32 val)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[0];
|
||||
//bool log=false;
|
||||
|
||||
memcpy(&card.command[0], &MMU.MMU_MEM[0][0x40][0x1A8], 8);
|
||||
|
||||
//last_write_count = write_count;
|
||||
if(card.command[4])
|
||||
{
|
||||
// transfer is done
|
||||
T1WriteLong(MMU.MMU_MEM[0][0x40], 0x1A4,val & 0x7F7FFFFF);
|
||||
|
||||
// if needed, throw irq for the end of transfer
|
||||
if(MMU.AUX_SPI_CNT & 0x4000)
|
||||
NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_GC_TRANSFER_COMPLETE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0xBB:
|
||||
{
|
||||
if(write_count && write_enabled)
|
||||
{
|
||||
img->fwrite(&val, 4);
|
||||
img->fflush();
|
||||
write_count--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(write_count==0)
|
||||
{
|
||||
write_enabled = 0;
|
||||
|
||||
// transfer is done
|
||||
T1WriteLong(MMU.MMU_MEM[0][0x40], 0x1A4,val & 0x7F7FFFFF);
|
||||
|
||||
// if needed, throw irq for the end of transfer
|
||||
if(MMU.AUX_SPI_CNT & 0x4000)
|
||||
NDS_makeIrq(ARMCPU_ARM9, IRQ_BIT_GC_TRANSFER_COMPLETE);
|
||||
}
|
||||
|
||||
/*if(log)
|
||||
{
|
||||
INFO("WRITE CARD command: %02X%02X%02X%02X%02X%02X%02X%02X\t",
|
||||
card.command[0], card.command[1], card.command[2], card.command[3],
|
||||
card.command[4], card.command[5], card.command[6], card.command[7]);
|
||||
INFO("FROM: %08X\t", NDS_ARM9.instruct_adr);
|
||||
INFO("VAL: %08X\n", val);
|
||||
}*/
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ISlot1Interface* construct_Slot1_R4() { return new Slot1_R4(); }
|
|
@ -20,226 +20,206 @@
|
|||
#include "../MMU.h"
|
||||
#include "../NDSSystem.h"
|
||||
|
||||
static void info(char *info) { strcpy(info, "Slot1 Retail card emulation"); }
|
||||
static void config(void) {}
|
||||
|
||||
static BOOL init() { return (TRUE); }
|
||||
|
||||
static void reset()
|
||||
class Slot1_Retail : public ISlot1Interface
|
||||
{
|
||||
// Write the header checksum to memory (the firmware needs it to see the cart)
|
||||
if (!CommonSettings.BootFromFirmware)
|
||||
_MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E));
|
||||
}
|
||||
|
||||
static void close() {}
|
||||
|
||||
|
||||
static void write08(u8 PROCNUM, u32 adr, u8 val) {}
|
||||
static void write16(u8 PROCNUM, u32 adr, u16 val) {}
|
||||
|
||||
static void write32_GCROMCTRL(u8 PROCNUM, u32 val)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
|
||||
if (card.mode == CardMode_Normal)
|
||||
public:
|
||||
virtual Slot1Info const* info()
|
||||
{
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0x00: //Data read (0000000000000000h Get Cartridge Header) - len 200h bytes
|
||||
case 0xB7:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
case 0x90: // 1st Get ROM Chip ID - len 4 bytes
|
||||
case 0xB8:
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
printf("ARM%c: SLOT1 invalid command %02X (write) - CardMode_Normal\n", PROCNUM?'7':'9', card.command[0]);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
static Slot1InfoSimple info("Retail","Slot1 Retail card emulation");
|
||||
return &info;
|
||||
}
|
||||
|
||||
if (card.mode == CardMode_KEY1 || card.mode == CardMode_KEY2)
|
||||
virtual void connect()
|
||||
{
|
||||
u8 cmd = (card.command[0] >> 4);
|
||||
}
|
||||
|
||||
virtual void write32(u8 PROCNUM, u32 adr, u32 val)
|
||||
{
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCROMCTRL:
|
||||
write32_GCROMCTRL(PROCNUM, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual u32 read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCDATAIN:
|
||||
return read32_GCDATAIN(PROCNUM);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
u32 read32_GCDATAIN(u8 PROCNUM)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
u8 cmd = card.command[0];
|
||||
|
||||
if (card.mode == CardMode_KEY1 || card.mode == CardMode_KEY2)
|
||||
cmd >>= 4;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case 0x01: // 2nd Get ROM Chip ID - len 4 bytes
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
case 0x90: // 1st Get ROM Chip ID - len 4 bytes
|
||||
case 0xB8: // 3rd Get ROM Chip ID - len 4 bytes
|
||||
{
|
||||
// Returns RAW unencrypted Chip ID (eg. C2h,0Fh,00h,00h), repeated every 4 bytes.
|
||||
//
|
||||
// 1st byte - Manufacturer (C2h = Macronix)
|
||||
// 2nd byte - Chip size in megabytes minus 1 (eg. 0Fh = 16MB)
|
||||
// 3rd byte - Reserved/zero (probably upper bits of chip size)
|
||||
// 4th byte - Bit7: Secure Area Block transfer mode (8x200h or 1000h)
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
printf("ARM%c: SLOT1 invalid command %02X (write) - %s\n", PROCNUM?'7':'9', cmd, (card.mode == CardMode_KEY1)?"CardMode_KEY1":"CardMode_KEY2");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#ifdef _NEW_BOOT
|
||||
u32 chipID = 0;
|
||||
if (CommonSettings.BootFromFirmware)
|
||||
chipID = 0x00000000 | 0x00000000 | 0x00000F00 | 0x000000C2;;
|
||||
#else
|
||||
u32 chipID = 0;
|
||||
#endif
|
||||
|
||||
// Note: the BIOS stores the chip ID in main memory
|
||||
// Most games continuously compare the chip ID with
|
||||
// the value in memory, probably to know if the card
|
||||
// was removed.
|
||||
// As DeSmuME normally boots directly from the game, the chip
|
||||
// ID in main mem is zero and this value needs to be
|
||||
// zero too.
|
||||
|
||||
if (card.mode == CardMode_DATA_LOAD)
|
||||
{
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0xB7: // Encrypted Data Read (B7aaaaaaaa000000h) - len 200h bytes
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
break;
|
||||
//note that even if desmume was booting from firmware, and reading this chip ID to store in main memory,
|
||||
//this still works, since it will have read 00 originally and then read 00 to validate.
|
||||
|
||||
case 0xB8: // 3nd Get ROM Chip ID - len 4 bytes
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
card.mode = CardMode_KEY1;
|
||||
printf("ARM%c: SLOT1 invalid command %02X (write) - CardMode_DATA_LOAD\n", PROCNUM?'7':'9', card.command[0]);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void write32(u8 PROCNUM, u32 adr, u32 val)
|
||||
{
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCROMCTRL:
|
||||
write32_GCROMCTRL(PROCNUM, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 read08(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
static u16 read16(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
static u32 read32_GCDATAIN(u8 PROCNUM)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
u8 cmd = card.command[0];
|
||||
|
||||
if (card.mode == CardMode_KEY1 || card.mode == CardMode_KEY2)
|
||||
cmd >>= 4;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case 0x01: // 2nd Get ROM Chip ID - len 4 bytes
|
||||
case 0x90: // 1st Get ROM Chip ID - len 4 bytes
|
||||
case 0xB8: // 3rd Get ROM Chip ID - len 4 bytes
|
||||
{
|
||||
// Returns RAW unencrypted Chip ID (eg. C2h,0Fh,00h,00h), repeated every 4 bytes.
|
||||
//
|
||||
// 1st byte - Manufacturer (C2h = Macronix)
|
||||
// 2nd byte - Chip size in megabytes minus 1 (eg. 0Fh = 16MB)
|
||||
// 3rd byte - Reserved/zero (probably upper bits of chip size)
|
||||
// 4th byte - Bit7: Secure Area Block transfer mode (8x200h or 1000h)
|
||||
|
||||
u32 chipID = 0;
|
||||
if (CommonSettings.BootFromFirmware)
|
||||
chipID = 0x00000000 | 0x00000000 | 0x00000F00 | 0x000000C2;;
|
||||
|
||||
// Note: the BIOS stores the chip ID in main memory
|
||||
// Most games continuously compare the chip ID with
|
||||
// the value in memory, probably to know if the card
|
||||
// was removed.
|
||||
// As DeSmuME normally boots directly from the game, the chip
|
||||
// ID in main mem is zero and this value needs to be
|
||||
// zero too.
|
||||
|
||||
//note that even if desmume was booting from firmware, and reading this chip ID to store in main memory,
|
||||
//this still works, since it will have read 00 originally and then read 00 to validate.
|
||||
|
||||
//staff of kings verifies this (it also uses the arm7 IRQ 20)
|
||||
if(nds.cardEjected) //TODO - handle this with ejected card slot1 device (and verify using this case)
|
||||
return 0xFFFFFFFF;
|
||||
else
|
||||
//staff of kings verifies this (it also uses the arm7 IRQ 20)
|
||||
return chipID;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// Data read
|
||||
case 0x00:
|
||||
case 0xB7:
|
||||
{
|
||||
//it seems that etrian odyssey 3 doesnt work unless we mask this to cart size.
|
||||
//but, a thought: does the internal rom address counter register wrap around? we may be making a mistake by keeping the extra precision
|
||||
//but there is no test case yet
|
||||
u32 address = card.address & (gameInfo.mask);
|
||||
|
||||
// Make sure any reads below 0x8000 redirect to 0x8000+(adr&0x1FF) as on real cart
|
||||
if((cmd == 0xB7) && (address < 0x8000))
|
||||
{
|
||||
//TODO - refactor this to include the PROCNUM, for debugging purposes if nothing else
|
||||
//(can refactor gbaslot also)
|
||||
|
||||
//INFO("Read below 0x8000 (0x%04X) from: ARM%s %08X\n",
|
||||
// card.address, (PROCNUM ? "7":"9"), (PROCNUM ? NDS_ARM7:NDS_ARM9).instruct_adr);
|
||||
|
||||
address = (0x8000 + (address&0x1FF));
|
||||
}
|
||||
break;
|
||||
|
||||
//as a sanity measure for funny-sized roms (homebrew and perhaps truncated retail roms)
|
||||
//we need to protect ourselves by returning 0xFF for things still out of range
|
||||
if(address >= gameInfo.romsize)
|
||||
|
||||
// Data read
|
||||
case 0x00:
|
||||
case 0xB7:
|
||||
{
|
||||
DEBUG_Notify.ReadBeyondEndOfCart(address,gameInfo.romsize);
|
||||
return 0xFFFFFFFF;
|
||||
//it seems that etrian odyssey 3 doesnt work unless we mask this to cart size.
|
||||
//but, a thought: does the internal rom address counter register wrap around? we may be making a mistake by keeping the extra precision
|
||||
//but there is no test case yet
|
||||
u32 address = card.address & (gameInfo.mask);
|
||||
|
||||
// Make sure any reads below 0x8000 redirect to 0x8000+(adr&0x1FF) as on real card
|
||||
if((cmd == 0xB7) && (address < 0x8000))
|
||||
{
|
||||
//TODO - refactor this to include the PROCNUM, for debugging purposes if nothing else
|
||||
//(can refactor gbaslot also)
|
||||
|
||||
//INFO("Read below 0x8000 (0x%04X) from: ARM%s %08X\n",
|
||||
// card.address, (PROCNUM ? "7":"9"), (PROCNUM ? NDS_ARM7:NDS_ARM9).instruct_adr);
|
||||
|
||||
address = (0x8000 + (address&0x1FF));
|
||||
}
|
||||
|
||||
//as a sanity measure for funny-sized roms (homebrew and perhaps truncated retail roms)
|
||||
//we need to protect ourselves by returning 0xFF for things still out of range
|
||||
if(address >= gameInfo.romsize)
|
||||
{
|
||||
DEBUG_Notify.ReadBeyondEndOfCart(address,gameInfo.romsize);
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return T1ReadLong(MMU.CART_ROM, address);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#ifdef _NEW_BOOT
|
||||
printf("ARM%c: SLOT1 invalid command %02X (read)\n", PROCNUM?'7':'9', cmd);
|
||||
#endif
|
||||
return 0;
|
||||
} //switch(card.command[0])
|
||||
} //read32_GCDATAIN
|
||||
|
||||
return T1ReadLong(MMU.CART_ROM, address);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//printf("ARM%c: SLOT1 invalid command %02X (read)\n", PROCNUM?'7':'9', cmd);
|
||||
return 0;
|
||||
} //switch(card.command[0])
|
||||
} //read32_GCDATAIN
|
||||
|
||||
static u32 read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
switch(adr)
|
||||
void write32_GCROMCTRL(u8 PROCNUM, u32 val)
|
||||
{
|
||||
case REG_GCDATAIN:
|
||||
return read32_GCDATAIN(PROCNUM);
|
||||
default:
|
||||
return 0;
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
|
||||
if (card.mode == CardMode_Normal)
|
||||
{
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0x00: //Data read (0000000000000000h Get Cartridge Header) - len 200h bytes
|
||||
case 0xB7:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
case 0x90: // 1st Get ROM Chip ID - len 4 bytes
|
||||
case 0xB8:
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
printf("ARM%c: SLOT1 invalid command %02X (write) - CardMode_Normal\n", PROCNUM?'7':'9', card.command[0]);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (card.mode == CardMode_KEY1 || card.mode == CardMode_KEY2)
|
||||
{
|
||||
u8 cmd = (card.command[0] >> 4);
|
||||
switch(cmd)
|
||||
{
|
||||
case 0x01: // 2nd Get ROM Chip ID - len 4 bytes
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
printf("ARM%c: SLOT1 invalid command %02X (write) - %s\n", PROCNUM?'7':'9', cmd, (card.mode == CardMode_KEY1)?"CardMode_KEY1":"CardMode_KEY2");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (card.mode == CardMode_DATA_LOAD)
|
||||
{
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0xB7: // Encrypted Data Read (B7aaaaaaaa000000h) - len 200h bytes
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
case 0xB8: // 3nd Get ROM Chip ID - len 4 bytes
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
card.mode = CardMode_KEY1;
|
||||
printf("ARM%c: SLOT1 invalid command %02X (write) - CardMode_DATA_LOAD\n", PROCNUM?'7':'9', card.command[0]);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SLOT1INTERFACE slot1Retail = {
|
||||
"Retail",
|
||||
init,
|
||||
reset,
|
||||
close,
|
||||
config,
|
||||
write08,
|
||||
write16,
|
||||
write32,
|
||||
read08,
|
||||
read16,
|
||||
read32,
|
||||
info
|
||||
};
|
||||
|
||||
|
||||
ISlot1Interface* construct_Slot1_Retail() { return new Slot1_Retail(); }
|
||||
|
||||
// ///writetoGCControl:
|
||||
//// --- Ninja SD commands -------------------------------------
|
||||
|
|
|
@ -20,188 +20,165 @@
|
|||
#include "../MMU.h"
|
||||
#include "../NDSSystem.h"
|
||||
|
||||
static void info(char *info) { strcpy(info, "Slot1 Retail NAND card emulation"); }
|
||||
static void config(void) {}
|
||||
|
||||
static BOOL init() { return (TRUE); }
|
||||
|
||||
static void reset()
|
||||
class Slot1_Retail_NAND : public ISlot1Interface
|
||||
{
|
||||
// Write the header checksum to memory (the firmware needs it to see the cart)
|
||||
_MMU_write16<ARMCPU_ARM9>(0x027FF808, T1ReadWord(MMU.CART_ROM, 0x15E));
|
||||
}
|
||||
|
||||
static void close() {}
|
||||
|
||||
|
||||
static void write08(u8 PROCNUM, u32 adr, u8 val) {}
|
||||
static void write16(u8 PROCNUM, u32 adr, u16 val) {}
|
||||
|
||||
static void write32_GCROMCTRL(u8 PROCNUM, u32 val)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
|
||||
switch(card.command[0])
|
||||
public:
|
||||
virtual Slot1Info const* info()
|
||||
{
|
||||
case 0x00: //Data read
|
||||
case 0xB7:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
case 0xB8: // Chip ID
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
// Nand Init
|
||||
case 0x94:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
// Nand Error?
|
||||
case 0xD6:
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
// Nand Write? ---- PROGRAM for INTERNAL DATA MOVE/RANDOM DATA INPUT
|
||||
//case 0x8B:
|
||||
case 0x85:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
break;
|
||||
static Slot1InfoSimple info("Retail+NAND","Slot1 Retail NAND card emulation");
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
|
||||
static void write32(u8 PROCNUM, u32 adr, u32 val)
|
||||
{
|
||||
switch(adr)
|
||||
virtual void connect()
|
||||
{
|
||||
case REG_GCROMCTRL:
|
||||
write32_GCROMCTRL(PROCNUM, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 read08(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
static u16 read16(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
|
||||
static u32 read32_GCDATAIN(u8 PROCNUM)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
|
||||
switch(card.command[0])
|
||||
virtual u32 read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
//Get ROM chip ID
|
||||
case 0x90:
|
||||
case 0xB8:
|
||||
{
|
||||
// Note: the BIOS stores the chip ID in main memory
|
||||
// Most games continuously compare the chip ID with
|
||||
// the value in memory, probably to know if the card
|
||||
// was removed.
|
||||
// As DeSmuME boots directly from the game, the chip
|
||||
// ID in main mem is zero and this value needs to be
|
||||
// zero too.
|
||||
|
||||
//note that even if desmume was booting from firmware, and reading this chip ID to store in main memory,
|
||||
//this still works, since it will have read 00 originally and then read 00 to validate.
|
||||
|
||||
//staff of kings verifies this (it also uses the arm7 IRQ 20)
|
||||
if(nds.cardEjected) //TODO - handle this with ejected card slot1 device (and verify using this case)
|
||||
return 0xFFFFFFFF;
|
||||
else return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// Data read
|
||||
case 0x00:
|
||||
case 0xB7:
|
||||
{
|
||||
// Make sure any reads below 0x8000 redirect to 0x8000+(adr&0x1FF) as on real cart
|
||||
if((card.command[0] == 0xB7) && (card.address < 0x8000))
|
||||
{
|
||||
//TODO - refactor this to include the PROCNUM, for debugging purposes if nothing else
|
||||
//(can refactor gbaslot also)
|
||||
|
||||
//INFO("Read below 0x8000 (0x%04X) from: ARM%s %08X\n",
|
||||
// card.address, (PROCNUM ? "7":"9"), (PROCNUM ? NDS_ARM7:NDS_ARM9).instruct_adr);
|
||||
|
||||
card.address = (0x8000 + (card.address&0x1FF));
|
||||
}
|
||||
|
||||
//it seems that etrian odyssey 3 doesnt work unless we mask this to cart size.
|
||||
//but, a thought: does the internal rom address counter register wrap around? we may be making a mistake by keeping the extra precision
|
||||
//but there is no test case yet
|
||||
u32 address = card.address & (gameInfo.mask);
|
||||
|
||||
//as a sanity measure for funny-sized roms (homebrew and perhaps truncated retail roms)
|
||||
//we need to protect ourselves by returning 0xFF for things still out of range
|
||||
if(address >= gameInfo.romsize)
|
||||
{
|
||||
DEBUG_Notify.ReadBeyondEndOfCart(address,gameInfo.romsize);
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return T1ReadLong(MMU.CART_ROM, address);
|
||||
}
|
||||
break;
|
||||
|
||||
// Nand Init?
|
||||
case 0x94:
|
||||
return 0; //Unsure what to return here so return 0 for now
|
||||
|
||||
// Nand Status?
|
||||
case 0xD6:
|
||||
//0x80 == busy
|
||||
// Made in Ore/WariWare D.I.Y. need set value to 0x80
|
||||
return 0x80; //0x20 == ready
|
||||
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCDATAIN:
|
||||
return read32_GCDATAIN(PROCNUM);
|
||||
default:
|
||||
return 0;
|
||||
} //switch(card.command[0])
|
||||
} //read32_GCDATAIN
|
||||
|
||||
static u32 read32(u8 PROCNUM, u32 adr)
|
||||
{
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCDATAIN:
|
||||
return read32_GCDATAIN(PROCNUM);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void write32(u8 PROCNUM, u32 adr, u32 val)
|
||||
{
|
||||
switch(adr)
|
||||
{
|
||||
case REG_GCROMCTRL:
|
||||
write32_GCROMCTRL(PROCNUM, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SLOT1INTERFACE slot1Retail_NAND = {
|
||||
"Retail with NAND Flash",
|
||||
init,
|
||||
reset,
|
||||
close,
|
||||
config,
|
||||
write08,
|
||||
write16,
|
||||
write32,
|
||||
read08,
|
||||
read16,
|
||||
read32,
|
||||
info
|
||||
private:
|
||||
|
||||
|
||||
void write32_GCROMCTRL(u8 PROCNUM, u32 val)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
|
||||
switch(card.command[0])
|
||||
{
|
||||
case 0x00: //Data read
|
||||
case 0xB7:
|
||||
card.address = (card.command[1] << 24) | (card.command[2] << 16) | (card.command[3] << 8) | card.command[4];
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
case 0xB8: // Chip ID
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
// Nand Init
|
||||
case 0x94:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
// Nand Error?
|
||||
case 0xD6:
|
||||
card.address = 0;
|
||||
card.transfer_count = 4;
|
||||
break;
|
||||
|
||||
// Nand Write? ---- PROGRAM for INTERNAL DATA MOVE/RANDOM DATA INPUT
|
||||
//case 0x8B:
|
||||
case 0x85:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0x200;
|
||||
break;
|
||||
|
||||
default:
|
||||
card.address = 0;
|
||||
card.transfer_count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 read32_GCDATAIN(u8 PROCNUM)
|
||||
{
|
||||
nds_dscard& card = MMU.dscard[PROCNUM];
|
||||
|
||||
switch(card.command[0])
|
||||
{
|
||||
//Get ROM chip ID
|
||||
case 0x90:
|
||||
case 0xB8:
|
||||
{
|
||||
// Note: the BIOS stores the chip ID in main memory
|
||||
// Most games continuously compare the chip ID with
|
||||
// the value in memory, probably to know if the card
|
||||
// was removed.
|
||||
// As DeSmuME boots directly from the game, the chip
|
||||
// ID in main mem is zero and this value needs to be
|
||||
// zero too.
|
||||
|
||||
u32 chipID = 0;
|
||||
|
||||
//note that even if desmume was booting from firmware, and reading this chip ID to store in main memory,
|
||||
//this still works, since it will have read 00 originally and then read 00 to validate.
|
||||
return chipID;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// Data read
|
||||
case 0x00:
|
||||
case 0xB7:
|
||||
{
|
||||
// Make sure any reads below 0x8000 redirect to 0x8000+(adr&0x1FF) as on real cart
|
||||
if((card.command[0] == 0xB7) && (card.address < 0x8000))
|
||||
{
|
||||
//TODO - refactor this to include the PROCNUM, for debugging purposes if nothing else
|
||||
//(can refactor gbaslot also)
|
||||
|
||||
//INFO("Read below 0x8000 (0x%04X) from: ARM%s %08X\n",
|
||||
// card.address, (PROCNUM ? "7":"9"), (PROCNUM ? NDS_ARM7:NDS_ARM9).instruct_adr);
|
||||
|
||||
card.address = (0x8000 + (card.address&0x1FF));
|
||||
}
|
||||
|
||||
//it seems that etrian odyssey 3 doesnt work unless we mask this to cart size.
|
||||
//but, a thought: does the internal rom address counter register wrap around? we may be making a mistake by keeping the extra precision
|
||||
//but there is no test case yet
|
||||
u32 address = card.address & (gameInfo.mask);
|
||||
|
||||
//as a sanity measure for funny-sized roms (homebrew and perhaps truncated retail roms)
|
||||
//we need to protect ourselves by returning 0xFF for things still out of range
|
||||
if(address >= gameInfo.romsize)
|
||||
{
|
||||
DEBUG_Notify.ReadBeyondEndOfCart(address,gameInfo.romsize);
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return T1ReadLong(MMU.CART_ROM, address);
|
||||
}
|
||||
break;
|
||||
|
||||
// Nand Init?
|
||||
case 0x94:
|
||||
return 0; //Unsure what to return here so return 0 for now
|
||||
|
||||
// Nand Status?
|
||||
case 0xD6:
|
||||
//0x80 == busy
|
||||
// Made in Ore/WariWare D.I.Y. need set value to 0x80
|
||||
return 0x80; //0x20 == ready
|
||||
|
||||
default:
|
||||
return 0;
|
||||
} //switch(card.command[0])
|
||||
} //read32_GCDATAIN
|
||||
|
||||
};
|
||||
|
||||
ISlot1Interface* construct_Slot1_Retail_NAND() { return new Slot1_Retail_NAND(); }
|
||||
|
||||
|
||||
|
|
|
@ -675,9 +675,9 @@ static BOOL isCoreStarted = NO;
|
|||
pthread_mutex_lock(&threadParam.mutexThreadExecute);
|
||||
|
||||
_slot1R4Path = (r4Path != nil) ? std::string([r4Path cStringUsingEncoding:NSUTF8StringEncoding]) : "";
|
||||
slot1SetFatDir(_slot1R4Path);
|
||||
slot1_SetFatDir(_slot1R4Path);
|
||||
|
||||
BOOL result = slot1Change((NDS_SLOT1_TYPE)deviceTypeID);
|
||||
BOOL result = slot1_Change((NDS_SLOT1_TYPE)deviceTypeID);
|
||||
|
||||
pthread_mutex_unlock(&threadParam.mutexThreadExecute);
|
||||
|
||||
|
|
|
@ -294,13 +294,13 @@ void CommandLine::process_addonCommands()
|
|||
}
|
||||
|
||||
if(slot1_fat_dir != "")
|
||||
slot1SetFatDir(slot1_fat_dir);
|
||||
slot1_SetFatDir(slot1_fat_dir);
|
||||
|
||||
if(slot1 == "RETAIL")
|
||||
slot1Change(NDS_SLOT1_RETAIL);
|
||||
slot1_Change(NDS_SLOT1_RETAIL);
|
||||
else if(slot1 == "R4")
|
||||
slot1Change(NDS_SLOT1_R4);
|
||||
slot1_Change(NDS_SLOT1_R4);
|
||||
else if(slot1 == "RETAILNAND")
|
||||
slot1Change(NDS_SLOT1_RETAIL_NAND);
|
||||
slot1_Change(NDS_SLOT1_RETAIL_NAND);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2010-2012 DeSmuME team
|
||||
Copyright (C) 2010-2013 DeSmuME team
|
||||
|
||||
This file is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -24,24 +24,11 @@
|
|||
#include "emufile.h"
|
||||
#include "utils/vfat.h"
|
||||
|
||||
extern SLOT1INTERFACE slot1None;
|
||||
extern SLOT1INTERFACE slot1Retail;
|
||||
extern SLOT1INTERFACE slot1R4;
|
||||
extern SLOT1INTERFACE slot1Retail_NAND;
|
||||
|
||||
//-------
|
||||
//fat-related common elements
|
||||
static EMUFILE* fatImage = NULL;
|
||||
static std::string fatDir;
|
||||
|
||||
SLOT1INTERFACE slot1List[NDS_SLOT1_COUNT] = {
|
||||
slot1None,
|
||||
slot1Retail,
|
||||
slot1R4,
|
||||
slot1Retail_NAND
|
||||
};
|
||||
|
||||
SLOT1INTERFACE slot1_device = slot1Retail; //default for frontends that dont even configure this
|
||||
NDS_SLOT1_TYPE slot1_device_type = NDS_SLOT1_RETAIL;
|
||||
|
||||
static void scanDir()
|
||||
{
|
||||
if(fatDir == "") return;
|
||||
|
@ -59,16 +46,69 @@ static void scanDir()
|
|||
}
|
||||
}
|
||||
|
||||
BOOL slot1Init()
|
||||
|
||||
void slot1_SetFatDir(const std::string& dir)
|
||||
{
|
||||
//printf("FAT path %s\n", dir.c_str());
|
||||
fatDir = dir;
|
||||
}
|
||||
|
||||
std::string slot1_GetFatDir()
|
||||
{
|
||||
return fatDir;
|
||||
}
|
||||
|
||||
EMUFILE* slot1_GetFatImage()
|
||||
{
|
||||
return fatImage;
|
||||
}
|
||||
|
||||
//------------
|
||||
|
||||
ISlot1Interface* slot1_List[NDS_SLOT1_COUNT];
|
||||
|
||||
ISlot1Interface* slot1_device = NULL;
|
||||
NDS_SLOT1_TYPE slot1_device_type = NDS_SLOT1_RETAIL; //default for frontends that dont even configure this
|
||||
|
||||
|
||||
void slot1_Init()
|
||||
{
|
||||
//due to sloppy initialization code in various untestable desmume ports, we might try this more than once
|
||||
static bool initialized = false;
|
||||
if(initialized) return;
|
||||
initialized = true;
|
||||
|
||||
//construct all devices
|
||||
extern TISlot1InterfaceConstructor construct_Slot1_None;
|
||||
extern TISlot1InterfaceConstructor construct_Slot1_Retail;
|
||||
extern TISlot1InterfaceConstructor construct_Slot1_R4;
|
||||
extern TISlot1InterfaceConstructor construct_Slot1_Retail_NAND;
|
||||
slot1_List[NDS_SLOT1_NONE] = construct_Slot1_None();
|
||||
slot1_List[NDS_SLOT1_RETAIL] = construct_Slot1_Retail();
|
||||
slot1_List[NDS_SLOT1_R4] = construct_Slot1_R4();
|
||||
slot1_List[NDS_SLOT1_RETAIL_NAND] = construct_Slot1_Retail_NAND();
|
||||
}
|
||||
|
||||
void slot1_Shutdown()
|
||||
{
|
||||
for(int i=0;i<ARRAY_SIZE(slot1_List);i++)
|
||||
{
|
||||
slot1_List[i]->shutdown();
|
||||
delete slot1_List[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool slot1_Connect()
|
||||
{
|
||||
if (slot1_device_type == NDS_SLOT1_R4)
|
||||
scanDir();
|
||||
return slot1_device.init();
|
||||
slot1_device->connect();
|
||||
return true;
|
||||
}
|
||||
|
||||
void slot1Close()
|
||||
void slot1_Disconnect()
|
||||
{
|
||||
slot1_device.close();
|
||||
slot1_device->disconnect();
|
||||
|
||||
//be careful to do this second, maybe the device will write something more
|
||||
if (fatImage)
|
||||
|
@ -78,43 +118,34 @@ void slot1Close()
|
|||
}
|
||||
}
|
||||
|
||||
void slot1Reset()
|
||||
void slot1_Reset()
|
||||
{
|
||||
slot1_device.reset();
|
||||
//disconnect existing device
|
||||
if(slot1_device != NULL) slot1_device->disconnect();
|
||||
|
||||
//connect new device
|
||||
slot1_device = slot1_List[slot1_device_type];
|
||||
slot1_device->connect();
|
||||
}
|
||||
|
||||
BOOL slot1Change(NDS_SLOT1_TYPE changeToType)
|
||||
bool slot1_Change(NDS_SLOT1_TYPE changeToType)
|
||||
{
|
||||
if(changeToType == slot1_device_type) return FALSE; //nothing to do
|
||||
if (changeToType > NDS_SLOT1_COUNT || changeToType < 0) return FALSE;
|
||||
slot1_device.close();
|
||||
if(slot1_device != NULL)
|
||||
slot1_device->disconnect();
|
||||
slot1_device_type = changeToType;
|
||||
slot1_device = slot1List[slot1_device_type];
|
||||
slot1_device = slot1_List[slot1_device_type];
|
||||
if (changeToType == NDS_SLOT1_R4)
|
||||
scanDir();
|
||||
printf("Slot 1: %s\n", slot1_device.name);
|
||||
printf("Slot 1: %s\n", slot1_device->info()->name());
|
||||
printf("sending eject signal to SLOT-1\n");
|
||||
NDS_TriggerCardEjectIRQ();
|
||||
return slot1_device.init();
|
||||
slot1_device->connect();
|
||||
return true;
|
||||
}
|
||||
|
||||
void slot1SetFatDir(const std::string& dir)
|
||||
{
|
||||
//printf("FAT path %s\n", dir.c_str());
|
||||
fatDir = dir;
|
||||
}
|
||||
|
||||
std::string slot1GetFatDir()
|
||||
{
|
||||
return fatDir;
|
||||
}
|
||||
|
||||
EMUFILE* slot1GetFatImage()
|
||||
{
|
||||
return fatImage;
|
||||
}
|
||||
|
||||
NDS_SLOT1_TYPE slot1GetCurrentType()
|
||||
NDS_SLOT1_TYPE slot1_GetCurrentType()
|
||||
{
|
||||
return slot1_device_type;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2010-2011 DeSmuME team
|
||||
Copyright (C) 2010-2013 DeSmuME team
|
||||
|
||||
This file is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,37 +25,58 @@
|
|||
|
||||
class EMUFILE;
|
||||
|
||||
struct SLOT1INTERFACE
|
||||
class Slot1Info
|
||||
{
|
||||
// The name of the plugin, this name will appear in the plugins list
|
||||
const char * name;
|
||||
public:
|
||||
virtual const char* name() const = 0;
|
||||
virtual const char* descr()const = 0;
|
||||
};
|
||||
|
||||
//called once when the plugin starts up
|
||||
BOOL (*init)(void);
|
||||
|
||||
//called when the emulator resets
|
||||
void (*reset)(void);
|
||||
|
||||
//called when the plugin shuts down
|
||||
void (*close)(void);
|
||||
|
||||
//called when the user configurating plugin
|
||||
void (*config)(void);
|
||||
class Slot1InfoSimple : public Slot1Info
|
||||
{
|
||||
public:
|
||||
Slot1InfoSimple(const char* _name, const char* _descr)
|
||||
: mName(_name)
|
||||
, mDescr(_descr)
|
||||
{
|
||||
}
|
||||
virtual const char* name() const { return mName; }
|
||||
virtual const char* descr() const { return mDescr; }
|
||||
private:
|
||||
const char* mName, *mDescr;
|
||||
};
|
||||
|
||||
//called when the emulator write to addon
|
||||
void (*write08)(u8 PROCNUM, u32 adr, u8 val);
|
||||
void (*write16)(u8 PROCNUM, u32 adr, u16 val);
|
||||
void (*write32)(u8 PROCNUM, u32 adr, u32 val);
|
||||
class ISlot1Interface
|
||||
{
|
||||
public:
|
||||
//called to get info about device (description)
|
||||
virtual Slot1Info const* info() = 0;
|
||||
|
||||
//called when the emulator read from addon
|
||||
u8 (*read08)(u8 PROCNUM, u32 adr);
|
||||
u16 (*read16)(u8 PROCNUM, u32 adr);
|
||||
u32 (*read32)(u8 PROCNUM, u32 adr);
|
||||
//called once when the emulator starts up, or when the device springs into existence
|
||||
virtual bool init() { return true; }
|
||||
|
||||
//called when the user get info about addon pak (description)
|
||||
void (*info)(char *info);
|
||||
//called when the emulator connects the device
|
||||
virtual void connect() { }
|
||||
|
||||
//called when the emulator disconnects the device
|
||||
virtual void disconnect() { }
|
||||
|
||||
//called when the emulator shuts down, or when the device disappears from existence
|
||||
virtual void shutdown() { }
|
||||
|
||||
//called when the emulator write to the slot
|
||||
virtual void write08(u8 PROCNUM, u32 adr, u8 val) { }
|
||||
virtual void write16(u8 PROCNUM, u32 adr, u16 val) { }
|
||||
virtual void write32(u8 PROCNUM, u32 adr, u32 val) { }
|
||||
|
||||
//called when the emulator reads from the slot
|
||||
virtual u8 read08(u8 PROCNUM, u32 adr) { return 0xFF; }
|
||||
virtual u16 read16(u8 PROCNUM, u32 adr) { return 0xFFFF; }
|
||||
virtual u32 read32(u8 PROCNUM, u32 adr) { return 0xFFFFFFFF; }
|
||||
};
|
||||
|
||||
typedef ISlot1Interface* TISlot1InterfaceConstructor();
|
||||
|
||||
enum NDS_SLOT1_TYPE
|
||||
{
|
||||
NDS_SLOT1_NONE,
|
||||
|
@ -65,15 +86,26 @@ enum NDS_SLOT1_TYPE
|
|||
NDS_SLOT1_COUNT // use for counter addons - MUST TO BE LAST!!!
|
||||
};
|
||||
|
||||
extern SLOT1INTERFACE slot1_device; // current slot1 device
|
||||
extern SLOT1INTERFACE slot1List[NDS_SLOT1_COUNT];
|
||||
extern ISlot1Interface* slot1_device; // current slot1 device
|
||||
extern ISlot1Interface* slot1_List[NDS_SLOT1_COUNT];
|
||||
|
||||
void slot1_Init();
|
||||
bool slot1_Connect();
|
||||
void slot1_Disconnect();
|
||||
void slot1_Shutdown();
|
||||
|
||||
//just disconnects and reconnects the device. ideally, the disconnection and connection would be called with sensible timing
|
||||
void slot1_Reset();
|
||||
|
||||
//change the current device
|
||||
bool slot1_Change(NDS_SLOT1_TYPE type);
|
||||
|
||||
//check on the current device
|
||||
NDS_SLOT1_TYPE slot1_GetCurrentType();
|
||||
|
||||
void slot1_SetFatDir(const std::string& dir);
|
||||
std::string slot1_GetFatDir();
|
||||
EMUFILE* slot1_GetFatImage();
|
||||
|
||||
|
||||
BOOL slot1Init();
|
||||
void slot1Close();
|
||||
void slot1Reset();
|
||||
BOOL slot1Change(NDS_SLOT1_TYPE type); // change current adddon
|
||||
void slot1SetFatDir(const std::string& dir);
|
||||
std::string slot1GetFatDir();
|
||||
NDS_SLOT1_TYPE slot1GetCurrentType();
|
||||
EMUFILE* slot1GetFatImage();
|
||||
#endif //__SLOT1_H__
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//taken from ndstool
|
||||
//taken from ndstool and modified trivially
|
||||
//http://devkitpro.svn.sourceforge.net/viewvc/devkitpro/trunk/tools/nds/ndstool/source/encryption.cpp?revision=1565
|
||||
|
||||
/* decrypt.cpp - this file is part of DeSmuME
|
||||
|
@ -481,6 +481,10 @@ static void encrypt_arm9(u32 cardheader_gamecode, unsigned char *data)
|
|||
encrypt(card_hash, p+1, p);
|
||||
}
|
||||
|
||||
//the NDS contains
|
||||
//0x0000 - 0x01FF : header
|
||||
//0x0200 - 0x3FFF : typically, nothing is stored here. on retail cards, you can't read from that area anyway, but im not sure if that's done in the game card or the GC bus controller on the system
|
||||
//0x4000 - 0x7FFF : secure area (details in gbatek)
|
||||
|
||||
bool DecryptSecureArea(u8 *romdata, long romlen)
|
||||
{
|
||||
|
@ -489,15 +493,6 @@ bool DecryptSecureArea(u8 *romdata, long romlen)
|
|||
|
||||
int romType = DetectRomType(*header,(char*)romdata);
|
||||
|
||||
/*bool do_decrypt = (endecrypt_option == 'd');
|
||||
bool do_encrypt = (endecrypt_option == 'e') || (endecrypt_option == 'E');
|
||||
unsigned int rounds_offsets = (endecrypt_option == 'E') ? 0x2000 : 0x1600;
|
||||
unsigned int sbox_offsets = (endecrypt_option == 'E') ? 0x2400 : 0x2800;*/
|
||||
#if 0
|
||||
unsigned int rounds_offsets = 0x1600;
|
||||
unsigned int sbox_offsets = 0x2800;
|
||||
#endif
|
||||
|
||||
if(romType == ROMTYPE_INVALID)
|
||||
return false;
|
||||
|
||||
|
@ -508,25 +503,15 @@ bool DecryptSecureArea(u8 *romdata, long romlen)
|
|||
}
|
||||
else if (romType >= ROMTYPE_ENCRSECURE) // includes ROMTYPE_MASKROM
|
||||
{
|
||||
unsigned char data[0x4000];
|
||||
memcpy(data,romdata+0x4000,0x4000);
|
||||
//unsigned char data[0x4000];
|
||||
//memcpy(data,romdata+0x4000,0x4000);
|
||||
//decrypt_arm9(*(u32 *)header->gamecode, data);
|
||||
//// clear data after header
|
||||
//memset(romdata+0x200,0,(0x4000-0x200));
|
||||
//// write secure 0x800
|
||||
//memcpy(romdata+0x4000,data,0x800);
|
||||
|
||||
decrypt_arm9(*(u32 *)header->gamecode, data);
|
||||
|
||||
// clear data after header
|
||||
//fseek(fNDS, 0x200, SEEK_SET);
|
||||
//for (unsigned int i=0x200; i<0x4000; i++) fputc(0, fNDS);
|
||||
memset(romdata+0x200,0,(0x4000-0x200));
|
||||
|
||||
// write secure 0x800
|
||||
//fseek(fNDS, 0x4000, SEEK_SET);
|
||||
//fwrite(data, 1, 0x800, fNDS);
|
||||
memcpy(romdata+0x4000,data,0x800);
|
||||
|
||||
// write header
|
||||
//(already poked directly)
|
||||
//fseek(fNDS, 0, SEEK_SET);
|
||||
//fwrite(&header, 512, 1, fNDS);
|
||||
decrypt_arm9(*(u32 *)header->gamecode, romdata+0x4000);
|
||||
|
||||
printf("Decrypted.\n");
|
||||
}
|
||||
|
@ -550,17 +535,27 @@ bool EncryptSecureArea(u8 *romdata, long romlen)
|
|||
|
||||
if (romType == ROMTYPE_NDSDUMPED)
|
||||
{
|
||||
unsigned char data[0x4000];
|
||||
memcpy(data,romdata+0x4000,0x4000);
|
||||
//unsigned char data[0x4000];
|
||||
//memcpy(data,romdata+0x4000,0x4000);
|
||||
//encrypt_arm9(*(u32 *)header->gamecode, data);
|
||||
//// clear data after header
|
||||
//memset(romdata+0x200,0,(0x4000-0x200));
|
||||
//// write secure 0x800
|
||||
//memcpy(romdata+0x4000,data,0x800);
|
||||
|
||||
encrypt_arm9(*(u32 *)header->gamecode, romdata+0x4000);
|
||||
|
||||
encrypt_arm9(*(u32 *)header->gamecode, data);
|
||||
// clear data after header
|
||||
memset(romdata+0x200,0,(0x4000-0x200));
|
||||
// write secure 0x800
|
||||
memcpy(romdata+0x4000,data,0x800);
|
||||
printf("Encrypted.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckValidRom(u8 *romdata, long romlen)
|
||||
{
|
||||
Header* header = (Header*)romdata;
|
||||
|
||||
int romType = DetectRomType(*header,(char*)romdata);
|
||||
|
||||
return (romType != ROMTYPE_INVALID);
|
||||
}
|
|
@ -21,7 +21,13 @@
|
|||
#ifndef _DECRYPT_H_
|
||||
#define _DECRYPT_H_
|
||||
|
||||
//decrypts the secure area of a rom (or does nothing if it is already decrypted)
|
||||
bool DecryptSecureArea(u8 *romdata, long romlen);
|
||||
|
||||
//encrypts the secure area of a rom (or does nothing if it is already encrypted)
|
||||
bool EncryptSecureArea(u8 *romdata, long romlen);
|
||||
|
||||
//since we have rom-type detection heuristics here, this module is responsible for checking whether a rom is valid
|
||||
bool CheckValidRom(u8 *romdata, long romlen);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3241,12 +3241,14 @@ int _main()
|
|||
|
||||
addonsChangePak(addon_type);
|
||||
|
||||
slot1_Init();
|
||||
|
||||
//override slot1 type with commandline, if present
|
||||
int slot1_device_type = (NDS_SLOT1_TYPE)GetPrivateProfileInt("Slot1", "type", NDS_SLOT1_RETAIL, IniName);
|
||||
if(cmdline.slot1 != "")
|
||||
WritePrivateProfileInt("Slot1","type",slot1_device_type,IniName);
|
||||
else
|
||||
slot1Change((NDS_SLOT1_TYPE)slot1_device_type);
|
||||
slot1_Change((NDS_SLOT1_TYPE)slot1_device_type);
|
||||
|
||||
|
||||
CommonSettings.wifi.mode = GetPrivateProfileInt("Wifi", "Mode", 0, IniName);
|
||||
|
|
|
@ -117,15 +117,12 @@ BOOL CALLBACK Slot1Box_Proc(HWND dialog, UINT msg,WPARAM wparam,LPARAM lparam)
|
|||
{
|
||||
OKbutton_slot1 = GetDlgItem(dialog, IDOK);
|
||||
for(int i = 0; i < NDS_SLOT1_COUNT; i++)
|
||||
ComboBox_AddString(GetDlgItem(dialog, IDC_ADDONS_LIST), slot1List[i].name);
|
||||
ComboBox_AddString(GetDlgItem(dialog, IDC_ADDONS_LIST), slot1_List[i]->info()->name());
|
||||
ComboBox_SetCurSel(GetDlgItem(dialog, IDC_ADDONS_LIST), temp_type_slot1);
|
||||
u8 tmp_info[512];
|
||||
slot1List[temp_type_slot1].info((char *)tmp_info);
|
||||
SetWindowText(GetDlgItem(dialog, IDC_ADDONS_INFO), (char *)tmp_info);
|
||||
SetWindowText(GetDlgItem(dialog, IDC_ADDONS_INFO), slot1_List[temp_type_slot1]->info()->descr());
|
||||
|
||||
_OKbutton_slot1 = false;
|
||||
wndConfigSlot1=CreateDialogW(hAppInst, MAKEINTRESOURCEW(Slot1_IDDs[temp_type_slot1]),
|
||||
dialog, (DLGPROC)Slot1_Procs[temp_type_slot1]);
|
||||
wndConfigSlot1 = CreateDialogW(hAppInst, MAKEINTRESOURCEW(Slot1_IDDs[temp_type_slot1]), dialog, (DLGPROC)Slot1_Procs[temp_type_slot1]);
|
||||
//SetWindowPos(GetDlgItem(dialog, IDC_ADDONS_INFO),HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
|
||||
//EnableWindow(GetDlgItem(dialog, IDC_ADDONS_INFO),FALSE);
|
||||
//EnableWindow(GetDlgItem(dialog, IDC_ADDONS_INFO),TRUE);
|
||||
|
@ -177,9 +174,7 @@ BOOL CALLBACK Slot1Box_Proc(HWND dialog, UINT msg,WPARAM wparam,LPARAM lparam)
|
|||
EnableWindow(OKbutton_slot1, TRUE);
|
||||
else
|
||||
EnableWindow(OKbutton_slot1, FALSE);
|
||||
u8 tmp_info[512];
|
||||
slot1List[temp_type_slot1].info((char *)tmp_info);
|
||||
SetWindowText(GetDlgItem(dialog, IDC_ADDONS_INFO), (char *)tmp_info);
|
||||
SetWindowText(GetDlgItem(dialog, IDC_ADDONS_INFO), slot1_List[temp_type_slot1]->info()->descr());
|
||||
last_type_slot1 = temp_type_slot1;
|
||||
}
|
||||
}
|
||||
|
@ -193,8 +188,8 @@ BOOL CALLBACK Slot1Box_Proc(HWND dialog, UINT msg,WPARAM wparam,LPARAM lparam)
|
|||
|
||||
void slot1Dialog(HWND hwnd)
|
||||
{
|
||||
strcpy(tmp_fat_path, slot1GetFatDir().c_str());
|
||||
temp_type_slot1 = slot1GetCurrentType();
|
||||
strcpy(tmp_fat_path, slot1_GetFatDir().c_str());
|
||||
temp_type_slot1 = slot1_GetCurrentType();
|
||||
last_type_slot1 = temp_type_slot1;
|
||||
_OKbutton_slot1 = false;
|
||||
needReset_slot1 = true;
|
||||
|
@ -204,7 +199,7 @@ void slot1Dialog(HWND hwnd)
|
|||
switch (temp_type_slot1)
|
||||
{
|
||||
case NDS_SLOT1_NONE:
|
||||
if (temp_type_slot1 != slot1GetCurrentType())
|
||||
if (temp_type_slot1 != slot1_GetCurrentType())
|
||||
needReset_slot1 = true;
|
||||
else
|
||||
needReset_slot1 = false;
|
||||
|
@ -214,7 +209,7 @@ void slot1Dialog(HWND hwnd)
|
|||
case NDS_SLOT1_R4:
|
||||
if (strlen(tmp_fat_path))
|
||||
{
|
||||
slot1SetFatDir(tmp_fat_path);
|
||||
slot1_SetFatDir(tmp_fat_path);
|
||||
WritePrivateProfileString("Slot1","FAT_path",tmp_fat_path,IniName);
|
||||
}
|
||||
break;
|
||||
|
@ -225,10 +220,8 @@ void slot1Dialog(HWND hwnd)
|
|||
}
|
||||
WritePrivateProfileInt("Slot1","type",temp_type_slot1,IniName);
|
||||
|
||||
slot1Change((NDS_SLOT1_TYPE)temp_type_slot1);
|
||||
//zero 30-aug-2012
|
||||
//if (romloaded && needReset_slot1)
|
||||
// NDS_Reset();
|
||||
slot1_Change((NDS_SLOT1_TYPE)temp_type_slot1);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue