diff --git a/desmume/src/addons/slot2_mpcf.cpp b/desmume/src/addons/slot2_mpcf.cpp
index 74be3554e..36b377697 100644
--- a/desmume/src/addons/slot2_mpcf.cpp
+++ b/desmume/src/addons/slot2_mpcf.cpp
@@ -17,8 +17,250 @@
along with the this software. If not, see .
*/
+#include
+#include
+#include
+#include
+#include
+#include "../types.h"
+#include "../debug.h"
+#include "../path.h"
+#include "../utils/vfat.h"
#include "../slot2.h"
+// Set up addresses for GBAMP
+#define CF_REG_DATA 0x9000000
+#define CF_REG_ERR 0x9020000
+#define CF_REG_SEC 0x9040000
+#define CF_REG_LBA1 0x9060000
+#define CF_REG_LBA2 0x9080000
+#define CF_REG_LBA3 0x90A0000
+#define CF_REG_LBA4 0x90C0000
+#define CF_REG_CMD 0x90E0000
+#define CF_REG_STS 0x98C0000
+
+// CF Card commands
+#define CF_CMD_LBA 0xE0
+#define CF_CMD_READ 0x20
+#define CF_CMD_WRITE 0x30
+
+static u16 cf_reg_sts,
+ cf_reg_lba1,
+ cf_reg_lba2,
+ cf_reg_lba3,
+ cf_reg_lba4,
+ cf_reg_cmd;
+static off_t currLBA;
+
+static const int lfnPos[13] = {1,3,5,7,9,14,16,18,20,22,24,28,30};
+
+static u32 fileStartLBA,fileEndLBA;
+static std::string sFlashPath;
+static BOOL cflashDeviceEnabled = FALSE;
+
+static EMUFILE* file = NULL;
+
+// ===========================
+BOOL inited;
+
+enum EListCallbackArg {
+ EListCallbackArg_Item, EListCallbackArg_Pop
+};
+
+static BOOL cflash_init()
+{
+ if (inited) return FALSE;
+ BOOL init_good = FALSE;
+
+ CFLASHLOG("CFlash_Mode: %d\n",CFlash_Mode);
+
+ if (CFlash_Mode == ADDON_CFLASH_MODE_RomPath)
+ {
+ sFlashPath = path.RomDirectory;
+ INFO("Using CFlash directory of rom: %s\n", sFlashPath.c_str());
+ }
+ else if(CFlash_Mode == ADDON_CFLASH_MODE_Path)
+ {
+ sFlashPath = CFlash_Path;
+ INFO("Using CFlash directory: %s\n", sFlashPath.c_str());
+ }
+
+ if (sFlashPath == "") return FALSE;
+
+ if(CFlash_IsUsingPath())
+ {
+ cflashDeviceEnabled = FALSE;
+ currLBA = 0;
+
+ fileStartLBA = fileEndLBA = 0xFFFFFFFF;
+ VFAT vfat;
+ bool ret = vfat.build(sFlashPath.c_str(),16); //allocate 16MB extra for writing. this is probably enough for anyone, but maybe it should be configurable.
+ //we could always suggest to users to add a big file to their directory to overwrite (that would cause the image to get padded)
+
+ if(!ret)
+ {
+ CFLASHLOG("FAILED cflash_build_fat\n");
+ return FALSE;
+ }
+
+ file = vfat.detach();
+
+ cf_reg_sts = 0x58; // READY
+
+ cflashDeviceEnabled = TRUE;
+ init_good = TRUE;
+ }
+ else
+ {
+ sFlashPath = CFlash_Path;
+ INFO("Using CFlash disk image file %s\n", sFlashPath.c_str());
+ file = new EMUFILE_FILE(sFlashPath.c_str(),"rb+");
+ if(file->fail())
+ {
+ INFO("Failed to open file %s\n", sFlashPath.c_str());
+ delete file;
+ file = NULL;
+ }
+ }
+
+ // READY
+ cf_reg_sts = 0x58;
+
+ currLBA = 0;
+ cf_reg_lba1 = cf_reg_lba2 =
+ cf_reg_lba3 = cf_reg_lba4 = 0;
+
+ inited = TRUE;
+ return init_good;
+}
+
+static unsigned int cflash_read(unsigned int address)
+{
+ unsigned int ret_value = 0;
+ size_t elems_read = 0;
+
+ switch (address)
+ {
+ case CF_REG_STS:
+ ret_value = cf_reg_sts;
+ break;
+
+ case CF_REG_DATA:
+ if (cf_reg_cmd == CF_CMD_READ)
+ {
+ if(file)
+ {
+ u8 data[2];
+ file->fseek(currLBA, SEEK_SET);
+ elems_read += file->fread(data,2);
+ ret_value = data[1] << 8 | data[0];
+ }
+ currLBA += 2;
+ }
+ break;
+
+ case CF_REG_CMD:
+ break;
+
+ case CF_REG_LBA1:
+ ret_value = cf_reg_lba1;
+ break;
+ }
+
+ return ret_value;
+}
+
+static void cflash_write(unsigned int address,unsigned int data)
+{
+ static u8 sector_data[512];
+ static u32 sector_write_index = 0;
+
+ switch (address)
+ {
+ case CF_REG_STS:
+ cf_reg_sts = data&0xFFFF;
+ break;
+
+ case CF_REG_DATA:
+ if (cf_reg_cmd == CF_CMD_WRITE)
+ {
+ {
+ sector_data[sector_write_index] = (data >> 0) & 0xff;
+ sector_data[sector_write_index + 1] = (data >> 8) & 0xff;
+
+ sector_write_index += 2;
+
+ if (sector_write_index == 512)
+ {
+ CFLASHLOG( "Write sector to %ld\n", currLBA);
+ size_t written = 0;
+
+ if(file)
+ if(currLBA + 512 < file->size())
+ {
+ file->fseek(currLBA,SEEK_SET);
+
+ while(written < 512)
+ {
+ size_t todo = 512-written;
+ file->fwrite(§or_data[written], todo);
+ size_t cur_write = todo;
+ written += cur_write;
+ if ( cur_write == (size_t)-1) break;
+ }
+ }
+
+ CFLASHLOG("Wrote %u bytes\n", written);
+
+ currLBA += 512;
+ sector_write_index = 0;
+ }
+ }
+ }
+ break;
+
+ case CF_REG_CMD:
+ cf_reg_cmd = data&0xFF;
+ cf_reg_sts = 0x58; // READY
+ break;
+
+ case CF_REG_LBA1:
+ cf_reg_lba1 = data&0xFF;
+ currLBA = (currLBA&0xFFFFFF00)| cf_reg_lba1;
+ break;
+
+ case CF_REG_LBA2:
+ cf_reg_lba2 = data&0xFF;
+ currLBA = (currLBA&0xFFFF00FF)|(cf_reg_lba2<<8);
+ break;
+
+ case CF_REG_LBA3:
+ cf_reg_lba3 = data&0xFF;
+ currLBA = (currLBA&0xFF00FFFF)|(cf_reg_lba3<<16);
+ break;
+
+ case CF_REG_LBA4:
+ cf_reg_lba4 = data&0xFF;
+
+ if ((cf_reg_lba4 & 0xf0) == CF_CMD_LBA)
+ {
+ currLBA = (currLBA&0x00FFFFFF)|((cf_reg_lba4&0x0F)<<24);
+ currLBA *= 512;
+ sector_write_index = 0;
+ }
+ break;
+ }
+}
+
+static void cflash_close( void)
+{
+ if (!inited) return;
+ if(file) delete file;
+ cflashDeviceEnabled = FALSE;
+ file = NULL;
+ inited = FALSE;
+}
+
class Slot2_CFlash : public ISlot2Interface
{
public:
@@ -27,6 +269,25 @@ public:
static Slot2InfoSimple info("MPCF Flash Card Device", "MPCF Flash Card Device");
return &info;
}
+
+ virtual void connect()
+ {
+ cflash_close();
+ cflash_init();
+ }
+ virtual void disconnect()
+ {
+ cflash_close();
+ }
+
+ virtual void writeByte(u8 PROCNUM, u32 addr, u8 val) { cflash_write(addr, val); }
+ virtual void writeWord(u8 PROCNUM, u32 addr, u16 val) { cflash_write(addr, val); }
+ virtual void writeLong(u8 PROCNUM, u32 addr, u32 val) { cflash_write(addr, val); }
+
+ virtual u8 readByte(u8 PROCNUM, u32 addr) { return (cflash_read(addr)); }
+ virtual u16 readWord(u8 PROCNUM, u32 addr) { return (cflash_read(addr)); }
+ virtual u32 readLong(u8 PROCNUM, u32 addr) { return (cflash_read(addr)); }
+
};
ISlot2Interface* construct_Slot2_CFlash() { return new Slot2_CFlash(); }
diff --git a/desmume/src/addons/slot2_paddle.cpp b/desmume/src/addons/slot2_paddle.cpp
index cb2ee32af..3852604e2 100644
--- a/desmume/src/addons/slot2_paddle.cpp
+++ b/desmume/src/addons/slot2_paddle.cpp
@@ -37,16 +37,96 @@ The emulation in all the handling of erroneous cases is not perfect, and some ot
maybe legally configure the paddle differently, which could be rejected here; in which case this code will need finetuning
*/
+#include
+#include "../NDSSystem.h"
#include "../slot2.h"
class Slot2_Paddle : public ISlot2Interface
{
+private:
+ void calibrate() { nds.paddle = 0; }
+ bool Validate(u32 procnum, bool rom)
+ {
+ if(rom)
+ return ValidateSlot2Access(procnum, 0, 0, 0, -1);
+ else
+ return ValidateSlot2Access(procnum, 18, 0, 0, 1);
+ }
+
public:
virtual Slot2Info const* info()
{
static Slot2InfoSimple info("Paddle", "Paddle");
return &info;
}
+
+ virtual void writeByte(u8 PROCNUM, u32 addr, u8 val)
+ {
+ if (addr < 0x0A000000) return; // ???
+ calibrate();
+ }
+ virtual void writeWord(u8 PROCNUM, u32 addr, u16 val)
+ {
+ if (addr < 0x0A000000)
+ calibrate();
+ }
+ virtual void writeLong(u8 PROCNUM, u32 addr, u32 val)
+ {
+ if (addr < 0x0A000000)
+ calibrate();
+ }
+
+ virtual u8 readByte(u8 PROCNUM, u32 addr)
+ {
+ //printf("paddle: read 08 at 0x%08X\n", adr);
+ if (!Validate(PROCNUM, (addr < 0x0A000000)))
+ return 0xFF;
+
+ if (addr < 0x0A000000)
+ return (addr & 1)?0xFF:0xEF;
+
+ if (addr == 0x0A000000)
+ return (nds.paddle & 0xFF);
+
+ if (addr == 0x0A000001)
+ return ((nds.paddle >> 8) & 0x0F);
+
+ return 0x00;
+ }
+ virtual u16 readWord(u8 PROCNUM, u32 addr)
+ {
+ //printf("paddle : read 16 at 0x%08X\n", adr);
+ if (!Validate(PROCNUM, (addr < 0x0A000000)))
+ return 0xFFFF;
+
+ if (addr < 0x0A000000)
+ return 0xEFFF;
+
+ if (addr == 0x0A000000)
+ {
+ u8 val = (nds.paddle & 0xFF);
+ return (val | (val << 8));
+ }
+
+ return 0x0000;
+ }
+ virtual u32 readLong(u8 PROCNUM, u32 addr)
+ {
+ //printf("paddle: read 32 at 0x%08X\n", adr);
+ if (!Validate(PROCNUM, (addr < 0x0A000000)))
+ return 0xFFFFFFFF;
+
+ if (addr < 0x0A000000)
+ return 0xEFFFEFFF;
+
+ if (addr == 0x0A000000)
+ {
+ u8 val = (nds.paddle & 0xFF);
+ return (val | (val << 8) | (val << 16) | (val << 24));
+ }
+
+ return 0x00000000;
+ }
};
ISlot2Interface* construct_Slot2_Paddle() { return new Slot2_Paddle(); }