- add new MPCF Flash Card Device code;
- add new paddle code (untested);
This commit is contained in:
mtabachenko 2013-11-10 21:05:11 +00:00
parent 08c66df12b
commit 41fe58e0f8
2 changed files with 341 additions and 0 deletions

View File

@ -17,8 +17,250 @@
along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#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(&sector_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(); }

View File

@ -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 <string.h>
#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(); }