mirror of
https://github.com/dborth/fceugx.git
synced 2024-10-31 22:45:05 +01:00
Updated to the latest FCEUX 2.6.4 (git def5768)
This commit is contained in:
parent
2fbcb7a036
commit
965e1c6719
@ -16,7 +16,7 @@ int Assemble(unsigned char *output, int addr, char *str) {
|
||||
output[0] = output[1] = output[2] = 0;
|
||||
char astr[128],ins[4];
|
||||
int len = strlen(str);
|
||||
if ((!len) || (len > 0x127)) return 1;
|
||||
if ((!len) || (len > 127)) return 1;
|
||||
|
||||
strcpy(astr,str);
|
||||
str_ucase(astr);
|
||||
|
@ -35,31 +35,39 @@ static SFORMAT StateRegs[] =
|
||||
static void Sync(void) {
|
||||
int i;
|
||||
setmirror(((latched >> 6) & 1) ^ 1);
|
||||
switch (latchea) {
|
||||
case 0x8000:
|
||||
switch (latchea & 3) {
|
||||
case 0:
|
||||
for (i = 0; i < 4; i++)
|
||||
setprg8(0x8000 + (i << 13), (((latched & 0x7F) << 1) + i) ^ (latched >> 7));
|
||||
setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + i);
|
||||
break;
|
||||
case 0x8002:
|
||||
case 2:
|
||||
for (i = 0; i < 4; i++)
|
||||
setprg8(0x8000 + (i << 13), ((latched & 0x7F) << 1) + (latched >> 7));
|
||||
setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + (latched >> 7));
|
||||
break;
|
||||
case 0x8001:
|
||||
case 0x8003:
|
||||
case 1:
|
||||
case 3:
|
||||
for (i = 0; i < 4; i++) {
|
||||
unsigned int b;
|
||||
b = latched & 0x7F;
|
||||
b = latched & 0x3F;
|
||||
if (i >= 2 && !(latchea & 0x2))
|
||||
b = 0x7F;
|
||||
setprg8(0x8000 + (i << 13), (i & 1) + ((b << 1) ^ (latched >> 7)));
|
||||
b = b | 0x07;
|
||||
setprg8(0x8000 + (i << 13), (i & 1) + (b << 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
setchr8(0);
|
||||
}
|
||||
|
||||
static DECLFW(M15Write) {
|
||||
latchea = A;
|
||||
latched = V;
|
||||
// cah4e3 02.10.19 once again, there may be either two similar mapper 15 exist. the one for 110in1 or 168in1 carts with complex multi game features.
|
||||
// and another implified version for subor/waixing chinese originals and hacks with no different modes, working only in mode 0 and which does not
|
||||
// expect there is any CHR write protection. protecting CHR writes only for mode 3 fixes the problem, all roms may be run on the same source again.
|
||||
if((latchea & 3) == 3)
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
||||
else
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
|
||||
Sync();
|
||||
}
|
||||
|
||||
@ -70,7 +78,6 @@ static void StateRestore(int version) {
|
||||
static void M15Power(void) {
|
||||
latchea = 0x8000;
|
||||
latched = 0;
|
||||
setchr8(0);
|
||||
setprg8r(0x10, 0x6000, 0);
|
||||
SetReadHandler(0x6000, 0x7FFF, CartBR);
|
||||
SetWriteHandler(0x6000, 0x7FFF, CartBW);
|
||||
|
@ -37,8 +37,8 @@ static int32 SensorDelay;
|
||||
// highly experimental, not actually working, just curious if it hapen to work with some other decoder
|
||||
// SND Registers
|
||||
static uint8 pcm_enable = 0;
|
||||
static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
|
||||
static writefunc pcmwrite;
|
||||
//static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
|
||||
//static writefunc pcmwrite;
|
||||
|
||||
static SFORMAT StateRegs[] =
|
||||
{
|
||||
|
@ -18,6 +18,33 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Family Study Box by Fukutake Shoten
|
||||
*
|
||||
* REG[0] R dddddddd / W ww---sss
|
||||
* ddd - TAPE DATA BYTE (ready when IRQ occurs)
|
||||
* sss - BRAM hi-bank
|
||||
* ww - PRAM bank
|
||||
* REG[1] R 0123---- / W ----PPPP
|
||||
* 0 - ?
|
||||
* 1 - ?
|
||||
* 2 - ?
|
||||
* 3 - ?
|
||||
* PPPP- PROM bank
|
||||
* REG[2] R -?--R--- / W A-BC-DEF
|
||||
* 4 - ?
|
||||
* R - sb4x power supply status (active low)
|
||||
* A - ?
|
||||
* B - ?
|
||||
* C - ?
|
||||
* D - ?
|
||||
* E - ?
|
||||
* F - ?
|
||||
*
|
||||
* BRAM0 4400-4FFF, 3K bank 0 (32K SWRAM) [hardwired]
|
||||
* BRAMB 5000-5FFF, 4K banks 1-7 (32K SWRAM) [REG[0] W -----sss]
|
||||
* PRAMB 6000-7FFF, 8K banks 1-3 (32K PRAM) [REG[0] W ww------]
|
||||
* PROMB 8000-BFFF, 16K banks 1-15 (256K PROM)[REG[1] W ----PPPP]
|
||||
* PROM0 C000-FFFF, 16K bank 0 (256K PROM) [hardwired]
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
|
@ -52,15 +52,23 @@ static DECLFW(M225Write) {
|
||||
}
|
||||
|
||||
static DECLFW(M225LoWrite) {
|
||||
if (A & 0x800) {
|
||||
prot[A & 0x03] = V;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFR(M225LoRead) {
|
||||
return 0;
|
||||
if (A & 0x800) {
|
||||
return prot[A & 3] & 0x0F;
|
||||
}
|
||||
return X.DB;
|
||||
}
|
||||
|
||||
static void M225Power(void) {
|
||||
prg = 0;
|
||||
chr = 0;
|
||||
mode = 0;
|
||||
mirr = 0;
|
||||
Sync();
|
||||
SetReadHandler(0x5000, 0x5FFF, M225LoRead);
|
||||
SetWriteHandler(0x5000, 0x5FFF, M225LoWrite);
|
||||
@ -70,7 +78,9 @@ static void M225Power(void) {
|
||||
|
||||
static void M225Reset(void) {
|
||||
prg = 0;
|
||||
chr = 0;
|
||||
mode = 0;
|
||||
mirr = 0;
|
||||
Sync();
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,8 @@ void Mirror(uint8 value)
|
||||
|
||||
static void Sync()
|
||||
{
|
||||
int prglo;
|
||||
int prghi;
|
||||
int prglo = 0;
|
||||
int prghi = 0;
|
||||
|
||||
int outb = outer << 1;
|
||||
//this can probably be rolled up, but i have no motivation to do so
|
||||
@ -127,14 +127,14 @@ static void Sync()
|
||||
|
||||
static DECLFW(WriteEXP)
|
||||
{
|
||||
uint32 addr = A;
|
||||
//uint32 addr = A;
|
||||
uint8 value = V;
|
||||
reg = value & 0x81;
|
||||
}
|
||||
|
||||
static DECLFW(WritePRG)
|
||||
{
|
||||
uint32 addr = A;
|
||||
//uint32 addr = A;
|
||||
uint8 value = V;
|
||||
switch (reg)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "mapinc.h"
|
||||
|
||||
static uint8 preg, mirr;
|
||||
static int hardmirr;
|
||||
|
||||
static SFORMAT StateRegs[] =
|
||||
{
|
||||
@ -35,6 +36,8 @@ static void Sync(void) {
|
||||
setchr8(0);
|
||||
if(mirr)
|
||||
setmirror(mirr);
|
||||
else
|
||||
setmirror(hardmirr); // restore hardwired mirroring
|
||||
}
|
||||
|
||||
static DECLFW(M71Write) {
|
||||
@ -46,6 +49,7 @@ static DECLFW(M71Write) {
|
||||
}
|
||||
|
||||
static void M71Power(void) {
|
||||
preg = 0;
|
||||
mirr = 0;
|
||||
Sync();
|
||||
SetReadHandler(0x8000, 0xFFFF, CartBR);
|
||||
@ -57,6 +61,7 @@ static void StateRestore(int version) {
|
||||
}
|
||||
|
||||
void Mapper71_Init(CartInfo *info) {
|
||||
hardmirr = info->mirror;
|
||||
info->Power = M71Power;
|
||||
GameStateRestore = StateRestore;
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
*
|
||||
* Super Game (Sugar Softec) protected mapper
|
||||
* Pocahontas 2 (Unl) [U][!], etc.
|
||||
* TODO: 9in1 LION KING HANGS!
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
@ -139,7 +138,7 @@ static DECLFW(UNL8237Write) {
|
||||
}
|
||||
|
||||
static DECLFW(UNL8237ExWrite) {
|
||||
switch (A) {
|
||||
switch (A & 0xF007) {
|
||||
case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); break;
|
||||
case 0x5001: EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break;
|
||||
case 0x5007: EXPREGS[2] = V; break;
|
||||
|
@ -237,13 +237,8 @@ void Mapper200_Init(CartInfo *info) {
|
||||
//------------------ Map 201 ---------------------------
|
||||
|
||||
static void M201Sync(void) {
|
||||
if (latche & 8) {
|
||||
setprg32(0x8000, latche & 3);
|
||||
setchr8(latche & 3);
|
||||
} else {
|
||||
setprg32(0x8000, 0);
|
||||
setchr8(0);
|
||||
}
|
||||
setprg32(0x8000, latche & 3);
|
||||
setchr8(latche & 3);
|
||||
}
|
||||
|
||||
void Mapper201_Init(CartInfo *info) {
|
||||
@ -353,6 +348,17 @@ static void M227Sync(void) {
|
||||
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
|
||||
uint32 L = (latche >> 9) & 1;
|
||||
|
||||
// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7.
|
||||
// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional
|
||||
// functionality. as I see from the menu code, it disables the chr writing before run an actual game.
|
||||
// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware
|
||||
// but if I find some i'll definitly do this.
|
||||
|
||||
if ((latche & 0xF000) == 0xF000)
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
|
||||
else
|
||||
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
|
||||
|
||||
if ((latche >> 7) & 1) {
|
||||
if (S) {
|
||||
setprg32(0x8000, p >> 1);
|
||||
|
@ -48,120 +48,205 @@ static SFORMAT StateRegs[] =
|
||||
#define X24C0X_READ 3
|
||||
#define X24C0X_WRITE 4
|
||||
|
||||
static uint8 x24c0x_data[256], x24c0x_state;
|
||||
static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount;
|
||||
static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe;
|
||||
static uint8 x24c0x_data[512];
|
||||
|
||||
static SFORMAT x24c0xStateRegs[] =
|
||||
static uint8 x24c01_state;
|
||||
static uint8 x24c01_addr, x24c01_word, x24c01_latch, x24c01_bitcount;
|
||||
static uint8 x24c01_sda, x24c01_scl, x24c01_out;
|
||||
|
||||
static uint8 x24c02_state;
|
||||
static uint8 x24c02_addr, x24c02_word, x24c02_latch, x24c02_bitcount;
|
||||
static uint8 x24c02_sda, x24c02_scl, x24c02_out;
|
||||
|
||||
static SFORMAT x24c01StateRegs[] =
|
||||
{
|
||||
{ &x24c0x_addr, 1, "ADDR" },
|
||||
{ &x24c0x_word, 1, "WORD" },
|
||||
{ &x24c0x_latch, 1, "LATC" },
|
||||
{ &x24c0x_bitcount, 1, "BITC" },
|
||||
{ &x24c0x_sda, 1, "SDA" },
|
||||
{ &x24c0x_scl, 1, "SCL" },
|
||||
{ &x24c0x_out, 1, "OUT" },
|
||||
{ &x24c0x_oe, 1, "OE" },
|
||||
{ &x24c0x_state, 1, "STAT" },
|
||||
{ &x24c01_addr, 1, "ADDR" },
|
||||
{ &x24c01_word, 1, "WORD" },
|
||||
{ &x24c01_latch, 1, "LATC" },
|
||||
{ &x24c01_bitcount, 1, "BITC" },
|
||||
{ &x24c01_sda, 1, "SDA" },
|
||||
{ &x24c01_scl, 1, "SCL" },
|
||||
{ &x24c01_out, 1, "OUT" },
|
||||
{ &x24c01_state, 1, "STAT" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void x24c0x_init() {
|
||||
x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0;
|
||||
x24c0x_state = X24C0X_STANDBY;
|
||||
static SFORMAT x24c02StateRegs[] =
|
||||
{
|
||||
{ &x24c02_addr, 1, "ADDR" },
|
||||
{ &x24c02_word, 1, "WORD" },
|
||||
{ &x24c02_latch, 1, "LATC" },
|
||||
{ &x24c02_bitcount, 1, "BITC" },
|
||||
{ &x24c02_sda, 1, "SDA" },
|
||||
{ &x24c02_scl, 1, "SCL" },
|
||||
{ &x24c02_out, 1, "OUT" },
|
||||
{ &x24c02_state, 1, "STAT" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static void x24c01_init() {
|
||||
x24c01_addr = x24c01_word = x24c01_latch = x24c01_bitcount = x24c01_sda = x24c01_scl = 0;
|
||||
x24c01_state = X24C0X_STANDBY;
|
||||
}
|
||||
|
||||
static void x24c0x_write(uint8 data) {
|
||||
uint8 sda = (data >> 6) & 1;
|
||||
uint8 scl = (data >> 5) & 1;
|
||||
x24c0x_oe = (data >> 7);
|
||||
static void x24c02_init() {
|
||||
x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0;
|
||||
x24c02_state = X24C0X_STANDBY;
|
||||
}
|
||||
|
||||
if(x24c0x_scl && scl) {
|
||||
if(x24c0x_sda && !sda) { // START
|
||||
x24c0x_state = X24C0X_ADDRESS;
|
||||
x24c0x_bitcount = 0;
|
||||
x24c0x_addr = 0;
|
||||
} else if(!x24c0x_sda && sda) { //STOP
|
||||
x24c0x_state = X24C0X_STANDBY;
|
||||
static void x24c01_write(uint8 data) {
|
||||
uint8 scl = (data >> 5) & 1;
|
||||
uint8 sda = (data >> 6) & 1;
|
||||
|
||||
if(x24c01_scl && scl) {
|
||||
if(x24c01_sda && !sda) { // START
|
||||
x24c01_state = X24C0X_ADDRESS;
|
||||
x24c01_bitcount = 0;
|
||||
x24c01_addr = 0;
|
||||
} else if(!x24c01_sda && sda) { //STOP
|
||||
x24c01_state = X24C0X_STANDBY;
|
||||
}
|
||||
} else if(!x24c0x_scl && scl) { // RISING EDGE
|
||||
switch(x24c0x_state) {
|
||||
} else if(!x24c01_scl && scl) { // RISING EDGE
|
||||
switch(x24c01_state) {
|
||||
case X24C0X_ADDRESS:
|
||||
if(x24c0x_bitcount < 7) {
|
||||
x24c0x_addr <<= 1;
|
||||
x24c0x_addr |= sda;
|
||||
if(x24c01_bitcount < 7) {
|
||||
x24c01_addr <<= 1;
|
||||
x24c01_addr |= sda;
|
||||
} else {
|
||||
if(!x24c02) // X24C01 mode
|
||||
x24c0x_word = x24c0x_addr;
|
||||
if(sda) { // READ COMMAND
|
||||
x24c0x_state = X24C0X_READ;
|
||||
} else { // WRITE COMMAND
|
||||
if(x24c02) // X24C02 mode
|
||||
x24c0x_state = X24C0X_WORD;
|
||||
else
|
||||
x24c0x_state = X24C0X_WRITE;
|
||||
}
|
||||
x24c01_word = x24c01_addr;
|
||||
if(sda) // READ COMMAND
|
||||
x24c01_state = X24C0X_READ;
|
||||
else // WRITE COMMAND
|
||||
x24c01_state = X24C0X_WRITE;
|
||||
}
|
||||
x24c0x_bitcount++;
|
||||
break;
|
||||
case X24C0X_WORD:
|
||||
if(x24c0x_bitcount == 8) { // ACK
|
||||
x24c0x_word = 0;
|
||||
x24c0x_out = 0;
|
||||
} else { // WORD ADDRESS INPUT
|
||||
x24c0x_word <<= 1;
|
||||
x24c0x_word |= sda;
|
||||
if(x24c0x_bitcount == 16) { // END OF ADDRESS INPUT
|
||||
x24c0x_bitcount = 7;
|
||||
x24c0x_state = X24C0X_WRITE;
|
||||
}
|
||||
}
|
||||
x24c0x_bitcount++;
|
||||
x24c01_bitcount++;
|
||||
break;
|
||||
case X24C0X_READ:
|
||||
if (x24c0x_bitcount == 8) { // ACK
|
||||
x24c0x_out = 0;
|
||||
x24c0x_latch = x24c0x_data[x24c0x_word];
|
||||
x24c0x_bitcount = 0;
|
||||
} else { // REAL OUTPUT
|
||||
x24c0x_out = x24c0x_latch >> 7;
|
||||
x24c0x_latch <<= 1;
|
||||
x24c0x_bitcount++;
|
||||
if(x24c0x_bitcount == 8) {
|
||||
x24c0x_word++;
|
||||
x24c0x_word &= 0xff;
|
||||
if (x24c01_bitcount == 8) { // ACK
|
||||
x24c01_out = 0;
|
||||
x24c01_latch = x24c0x_data[x24c01_word];
|
||||
x24c01_bitcount = 0;
|
||||
} else { // REAL OUTPUT
|
||||
x24c01_out = x24c01_latch >> 7;
|
||||
x24c01_latch <<= 1;
|
||||
x24c01_bitcount++;
|
||||
if(x24c01_bitcount == 8) {
|
||||
x24c01_word++;
|
||||
x24c01_word &= 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case X24C0X_WRITE:
|
||||
if (x24c0x_bitcount == 8) { // ACK
|
||||
x24c0x_out = 0;
|
||||
x24c0x_latch = 0;
|
||||
x24c0x_bitcount = 0;
|
||||
} else { // REAL INPUT
|
||||
x24c0x_latch <<= 1;
|
||||
x24c0x_latch |= sda;
|
||||
x24c0x_bitcount++;
|
||||
if(x24c0x_bitcount == 8) {
|
||||
x24c0x_data[x24c0x_word] = x24c0x_latch;
|
||||
x24c0x_word++;
|
||||
x24c0x_word &= 0xff;
|
||||
if (x24c01_bitcount == 8) { // ACK
|
||||
x24c01_out = 0;
|
||||
x24c01_latch = 0;
|
||||
x24c01_bitcount = 0;
|
||||
} else { // REAL INPUT
|
||||
x24c01_latch <<= 1;
|
||||
x24c01_latch |= sda;
|
||||
x24c01_bitcount++;
|
||||
if(x24c01_bitcount == 8) {
|
||||
x24c0x_data[x24c01_word] = x24c01_latch;
|
||||
x24c01_word++;
|
||||
x24c01_word &= 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
x24c0x_sda = sda;
|
||||
x24c0x_scl = scl;
|
||||
x24c01_sda = sda;
|
||||
x24c01_scl = scl;
|
||||
}
|
||||
|
||||
static uint8 x24c0x_read() {
|
||||
return x24c0x_out << 4;
|
||||
static void x24c02_write(uint8 data) {
|
||||
uint8 scl = (data >> 5) & 1;
|
||||
uint8 sda = (data >> 6) & 1;
|
||||
|
||||
if (x24c02_scl && scl) {
|
||||
if (x24c02_sda && !sda) { // START
|
||||
x24c02_state = X24C0X_ADDRESS;
|
||||
x24c02_bitcount = 0;
|
||||
x24c02_addr = 0;
|
||||
} else if (!x24c02_sda && sda) { //STOP
|
||||
x24c02_state = X24C0X_STANDBY;
|
||||
}
|
||||
} else if (!x24c02_scl && scl) { // RISING EDGE
|
||||
switch (x24c02_state) {
|
||||
case X24C0X_ADDRESS:
|
||||
if (x24c02_bitcount < 7) {
|
||||
x24c02_addr <<= 1;
|
||||
x24c02_addr |= sda;
|
||||
} else {
|
||||
if (sda) // READ COMMAND
|
||||
x24c02_state = X24C0X_READ;
|
||||
else // WRITE COMMAND
|
||||
x24c02_state = X24C0X_WORD;
|
||||
}
|
||||
x24c02_bitcount++;
|
||||
break;
|
||||
case X24C0X_WORD:
|
||||
if (x24c02_bitcount == 8) { // ACK
|
||||
x24c02_word = 0;
|
||||
x24c02_out = 0;
|
||||
} else { // WORD ADDRESS INPUT
|
||||
x24c02_word <<= 1;
|
||||
x24c02_word |= sda;
|
||||
if (x24c02_bitcount == 16) {// END OF ADDRESS INPUT
|
||||
x24c02_bitcount = 7;
|
||||
x24c02_state = X24C0X_WRITE;
|
||||
}
|
||||
}
|
||||
x24c02_bitcount++;
|
||||
break;
|
||||
case X24C0X_READ:
|
||||
if (x24c02_bitcount == 8) { // ACK
|
||||
x24c02_out = 0;
|
||||
x24c02_latch = x24c0x_data[x24c02_word|0x100];
|
||||
x24c02_bitcount = 0;
|
||||
} else { // REAL OUTPUT
|
||||
x24c02_out = x24c02_latch >> 7;
|
||||
x24c02_latch <<= 1;
|
||||
x24c02_bitcount++;
|
||||
if (x24c02_bitcount == 8) {
|
||||
x24c02_word++;
|
||||
x24c02_word &= 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case X24C0X_WRITE:
|
||||
if (x24c02_bitcount == 8) { // ACK
|
||||
x24c02_out = 0;
|
||||
x24c02_latch = 0;
|
||||
x24c02_bitcount = 0;
|
||||
} else { // REAL INPUT
|
||||
x24c02_latch <<= 1;
|
||||
x24c02_latch |= sda;
|
||||
x24c02_bitcount++;
|
||||
if (x24c02_bitcount == 8) {
|
||||
x24c0x_data[x24c02_word|0x100] = x24c02_latch;
|
||||
x24c02_word++;
|
||||
x24c02_word &= 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
x24c02_sda = sda;
|
||||
x24c02_scl = scl;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static void SyncMirror(void) {
|
||||
switch (reg[9] & 3) {
|
||||
case 0: setmirror(MI_V); break;
|
||||
case 1: setmirror(MI_H); break;
|
||||
case 2: setmirror(MI_0); break;
|
||||
case 3: setmirror(MI_1); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void Sync(void) {
|
||||
if (is153) {
|
||||
int base = (reg[0] & 1) << 4;
|
||||
@ -174,12 +259,7 @@ static void Sync(void) {
|
||||
setprg16(0x8000, reg[8]);
|
||||
setprg16(0xC000, ~0);
|
||||
}
|
||||
switch (reg[9] & 3) {
|
||||
case 0: setmirror(MI_V); break;
|
||||
case 1: setmirror(MI_H); break;
|
||||
case 2: setmirror(MI_0); break;
|
||||
case 3: setmirror(MI_1); break;
|
||||
}
|
||||
SyncMirror();
|
||||
}
|
||||
|
||||
static DECLFW(BandaiWrite) {
|
||||
@ -192,12 +272,15 @@ static DECLFW(BandaiWrite) {
|
||||
case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break;
|
||||
case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break;
|
||||
case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break;
|
||||
case 0x0D: x24c0x_write(V); break;
|
||||
case 0x0D: if(x24c02) x24c02_write(V); else x24c01_write(V); break;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFR(BandaiRead) {
|
||||
return (X.DB & 0xEF) | x24c0x_read();
|
||||
if(x24c02)
|
||||
return (X.DB & 0xEF) | (x24c02_out << 4);
|
||||
else
|
||||
return (X.DB & 0xEF) | (x24c01_out << 4);
|
||||
}
|
||||
|
||||
static void BandaiIRQHook(int a) {
|
||||
@ -213,7 +296,10 @@ static void BandaiIRQHook(int a) {
|
||||
|
||||
static void BandaiPower(void) {
|
||||
IRQa = 0;
|
||||
x24c0x_init();
|
||||
if(x24c02)
|
||||
x24c02_init();
|
||||
else
|
||||
x24c01_init();
|
||||
Sync();
|
||||
SetReadHandler(0x6000, 0x7FFF, BandaiRead);
|
||||
SetReadHandler(0x8000, 0xFFFF, CartBR);
|
||||
@ -231,12 +317,12 @@ void Mapper16_Init(CartInfo *info) {
|
||||
MapIRQHook = BandaiIRQHook;
|
||||
|
||||
info->battery = 1;
|
||||
info->SaveGame[0] = x24c0x_data;
|
||||
info->SaveGame[0] = x24c0x_data + 256;
|
||||
info->SaveGameLen[0] = 256;
|
||||
AddExState(x24c0x_data, 256, 0, "DATA");
|
||||
AddExState(&x24c02StateRegs, ~0, 0, 0);
|
||||
|
||||
GameStateRestore = StateRestore;
|
||||
AddExState(&x24c0xStateRegs, ~0, 0, 0);
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
||||
@ -250,9 +336,9 @@ void Mapper159_Init(CartInfo *info) {
|
||||
info->SaveGame[0] = x24c0x_data;
|
||||
info->SaveGameLen[0] = 128;
|
||||
AddExState(x24c0x_data, 128, 0, "DATA");
|
||||
AddExState(&x24c01StateRegs, ~0, 0, 0);
|
||||
|
||||
GameStateRestore = StateRestore;
|
||||
AddExState(&x24c0xStateRegs, ~0, 0, 0);
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
||||
@ -307,7 +393,9 @@ static int BarcodeReadPos;
|
||||
static int BarcodeCycleCount;
|
||||
static uint32 BarcodeOut;
|
||||
|
||||
int FCEUI_DatachSet(const uint8 *rcode) {
|
||||
// #define INTERL2OF5
|
||||
|
||||
int FCEUI_DatachSet(uint8 *rcode) {
|
||||
int prefix_parity_type[10][6] = {
|
||||
{ 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 1, 0 },
|
||||
{ 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 1 }, { 0, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 0, 1 },
|
||||
@ -330,6 +418,7 @@ int FCEUI_DatachSet(const uint8 *rcode) {
|
||||
};
|
||||
uint8 code[13 + 1];
|
||||
uint32 tmp_p = 0;
|
||||
uint32 csum = 0;
|
||||
int i, j;
|
||||
int len;
|
||||
|
||||
@ -341,18 +430,46 @@ int FCEUI_DatachSet(const uint8 *rcode) {
|
||||
}
|
||||
if (len != 13 && len != 12 && len != 8 && len != 7) return(0);
|
||||
|
||||
#define BS(x) BarcodeData[tmp_p] = x; tmp_p++
|
||||
#define BS(x) BarcodeData[tmp_p] = x; tmp_p++
|
||||
|
||||
for (j = 0; j < 32; j++) {
|
||||
for (j = 0; j < 32; j++) { // delay before sending a code
|
||||
BS(0x00);
|
||||
}
|
||||
|
||||
/* Left guard bars */
|
||||
#ifdef INTERL2OF5
|
||||
|
||||
BS(1); BS(1); BS(0); BS(0); // 1
|
||||
BS(1); BS(1); BS(0); BS(0); // 1
|
||||
BS(1); BS(1); BS(0); BS(0); // 1
|
||||
BS(1); BS(1); BS(0); BS(0); // 1
|
||||
BS(1); BS(1); BS(0); BS(0); // 1
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0
|
||||
BS(1); BS(0); BS(0); // 0 cs
|
||||
BS(1); BS(1); BS(0); BS(0); // 1
|
||||
|
||||
#else
|
||||
// Left guard bars
|
||||
BS(1); BS(0); BS(1);
|
||||
|
||||
if (len == 13 || len == 12) {
|
||||
uint32 csum;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
if (prefix_parity_type[code[0]][i]) {
|
||||
for (j = 0; j < 7; j++) {
|
||||
@ -362,53 +479,53 @@ int FCEUI_DatachSet(const uint8 *rcode) {
|
||||
for (j = 0; j < 7; j++) {
|
||||
BS(data_left_odd[code[i + 1]][j]);
|
||||
}
|
||||
|
||||
/* Center guard bars */
|
||||
// Center guard bars
|
||||
BS(0); BS(1); BS(0); BS(1); BS(0);
|
||||
|
||||
for (i = 7; i < 12; i++)
|
||||
for (j = 0; j < 7; j++) {
|
||||
BS(data_right[code[i]][j]);
|
||||
}
|
||||
csum = 0;
|
||||
for (i = 0; i < 12; i++) csum += code[i] * ((i & 1) ? 3 : 1);
|
||||
csum = (10 - (csum % 10)) % 10;
|
||||
// Calc and write down the control code if not assigned, instead, send code as is
|
||||
// Battle Rush uses modified type of codes with different control code calculation
|
||||
if (len == 12) {
|
||||
for (i = 0; i < 12; i++)
|
||||
csum += code[i] * ((i & 1) ? 3 : 1);
|
||||
csum = (10 - (csum % 10)) % 10;
|
||||
rcode[12] = csum + 0x30; // update check code to the input string as well
|
||||
rcode[13] = 0;
|
||||
code[12] = csum;
|
||||
}
|
||||
for (j = 0; j < 7; j++) {
|
||||
BS(data_right[csum][j]);
|
||||
BS(data_right[code[12]][j]);
|
||||
}
|
||||
} else if (len == 8 || len == 7) {
|
||||
uint32 csum = 0;
|
||||
|
||||
for (i = 0; i < 7; i++) csum += (i & 1) ? code[i] : (code[i] * 3);
|
||||
|
||||
csum = (10 - (csum % 10)) % 10;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
for (j = 0; j < 7; j++) {
|
||||
BS(data_left_odd[code[i]][j]);
|
||||
}
|
||||
|
||||
|
||||
/* Center guard bars */
|
||||
// Center guard bars
|
||||
BS(0); BS(1); BS(0); BS(1); BS(0);
|
||||
|
||||
for (i = 4; i < 7; i++)
|
||||
for (j = 0; j < 7; j++) {
|
||||
BS(data_right[code[i]][j]);
|
||||
}
|
||||
|
||||
csum = 0;
|
||||
for (i = 0; i < 7; i++)
|
||||
csum += (i & 1) ? code[i] : (code[i] * 3);
|
||||
csum = (10 - (csum % 10)) % 10;
|
||||
rcode[7] = csum + 0x30; // update check code to the input string as well
|
||||
rcode[8] = 0;
|
||||
for (j = 0; j < 7; j++) {
|
||||
BS(data_right[csum][j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Right guard bars */
|
||||
// Right guard bars
|
||||
BS(1); BS(0); BS(1);
|
||||
#endif
|
||||
|
||||
for (j = 0; j < 32; j++) {
|
||||
BS(0x00);
|
||||
}
|
||||
|
||||
BS(0xFF);
|
||||
|
||||
#undef BS
|
||||
@ -419,6 +536,26 @@ int FCEUI_DatachSet(const uint8 *rcode) {
|
||||
return(1);
|
||||
}
|
||||
|
||||
static void BarcodeSync(void) {
|
||||
setchr8(0);
|
||||
setprg16(0x8000, (reg[8] & 0x0F));
|
||||
setprg16(0xC000, 0x0F);
|
||||
SyncMirror();
|
||||
}
|
||||
|
||||
static DECLFW(BarcodeWrite) {
|
||||
A &= 0x0F;
|
||||
switch (A) {
|
||||
case 0x00: reg[0] = (V & 8) << 2; x24c01_write(reg[0xD] | reg[0]); break; // extra EEPROM x24C01 used in Battle Rush mini-cart
|
||||
case 0x08:
|
||||
case 0x09: reg[A] = V; BarcodeSync(); break;
|
||||
case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break;
|
||||
case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break;
|
||||
case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break;
|
||||
case 0x0D: reg[0xD] = V & (~0x20); x24c01_write(reg[0xD] | reg[0]); x24c02_write(V); break;
|
||||
}
|
||||
}
|
||||
|
||||
static void BarcodeIRQHook(int a) {
|
||||
BandaiIRQHook(a);
|
||||
|
||||
@ -436,7 +573,7 @@ static void BarcodeIRQHook(int a) {
|
||||
}
|
||||
|
||||
static DECLFR(BarcodeRead) {
|
||||
return BarcodeOut;
|
||||
return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut;
|
||||
}
|
||||
|
||||
static void M157Power(void) {
|
||||
@ -446,20 +583,29 @@ static void M157Power(void) {
|
||||
BarcodeOut = 0;
|
||||
BarcodeCycleCount = 0;
|
||||
|
||||
Sync();
|
||||
x24c01_init();
|
||||
x24c02_init();
|
||||
BarcodeSync();
|
||||
|
||||
SetWriteHandler(0x6000, 0xFFFF, BandaiWrite);
|
||||
SetReadHandler(0x6000, 0x7FFF, BarcodeRead);
|
||||
SetReadHandler(0x8000, 0xFFFF, CartBR);
|
||||
SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite);
|
||||
}
|
||||
|
||||
void Mapper157_Init(CartInfo *info) {
|
||||
is153 = 1;
|
||||
x24c02 = 1;
|
||||
info->Power = M157Power;
|
||||
MapIRQHook = BarcodeIRQHook;
|
||||
|
||||
GameInfo->cspecial = SIS_DATACH;
|
||||
info->battery = 1;
|
||||
info->SaveGame[0] = x24c0x_data;
|
||||
info->SaveGameLen[0] = 512;
|
||||
AddExState(x24c0x_data, 512, 0, "DATA");
|
||||
AddExState(&x24c01StateRegs, ~0, 0, 0);
|
||||
AddExState(&x24c02StateRegs, ~0, 0, 0);
|
||||
|
||||
GameStateRestore = StateRestore;
|
||||
GameStateRestore = StateRestore;
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
@ -84,12 +84,12 @@ byte_8C29: .BYTE 0,$76, 0, 0, 8
|
||||
byte_8CC6: .BYTE 0,$78, 0, 0,$12
|
||||
*/
|
||||
|
||||
static uint8 sim0reset[0x1F] = {
|
||||
0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE,
|
||||
0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53,
|
||||
0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
|
||||
};
|
||||
//static uint8 sim0reset[0x1F] = {
|
||||
// 0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE,
|
||||
// 0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53,
|
||||
// 0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10,
|
||||
// 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
|
||||
//};
|
||||
|
||||
static void Sync(void) {
|
||||
setprg32(0x8000, prg_reg);
|
||||
|
@ -22,7 +22,7 @@
|
||||
// http://forums.nesdev.com/viewtopic.php?p=146039
|
||||
//
|
||||
// 512k PRG-ROM in 32k pages (flashable if battery backed is specified)
|
||||
// 32k CHR-ROM used as:
|
||||
// 32k CHR-RAM used as:
|
||||
// 2 x 8k pattern pages
|
||||
// 2 x 8k nametable pages
|
||||
//
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2015 CaH4e3, ClusteR
|
||||
* Copyright (C) 2018 CaH4e3, Cluster
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -17,15 +17,60 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM
|
||||
* only MMC3 mode
|
||||
* SMD132 and SMD133 ASICs, MMC3 clones that can address up to 32 MiB of PRG-ROM, 256 KiB of CHR-RAM, and 8 KiB of WRAM.
|
||||
*
|
||||
* 6000 (xx76x210) | 0xC0
|
||||
* 6001 (xxx354x)
|
||||
* 6002 = 0
|
||||
* 6003 = 0
|
||||
* COOLBOY cartridges use registers at address $6xxx
|
||||
* MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000
|
||||
*
|
||||
* $xxx0
|
||||
* 7 bit 0
|
||||
* ---- ----
|
||||
* ABCC DEEE
|
||||
* |||| ||||
|
||||
* |||| |+++-- PRG offset (PRG A19, A18, A17)
|
||||
* |||| +----- Alternate CHR A17
|
||||
* ||++------- PRG offset (PRG A24, A23)
|
||||
* |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
|
||||
* +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
|
||||
*
|
||||
* $xxx1
|
||||
*
|
||||
* 7 bit 0
|
||||
* ---- ----
|
||||
* GHIJ KKLx
|
||||
* |||| |||
|
||||
* |||| ||+--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
|
||||
* |||+-++---- PRG offset (in order: PRG A20, A22, A21)
|
||||
* ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|
||||
* |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
|
||||
* +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
|
||||
*
|
||||
* $xxx2
|
||||
* 7 bit 0
|
||||
* ---- ----
|
||||
* xxxx MMMM
|
||||
* ||||
|
||||
* ++++-- CHR offset for GNROM mode (CHR A16, A15, A14, A13)
|
||||
*
|
||||
* $xxx3
|
||||
* 7 bit 0
|
||||
* ---- ----
|
||||
* NPxP QQRx
|
||||
* || | |||
|
||||
* || | +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
|
||||
* || +------- 1: GNROM mode; 0: MMC3 mode
|
||||
* || | (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
|
||||
* || | 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
|
||||
* |+-+------- Banking mode
|
||||
* |+--------- "Weird MMC3 mode"
|
||||
* +---------- Lockout (prevent further writes to these four registers, only works in MMC3 mode)
|
||||
*
|
||||
* Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper,
|
||||
* which allows you to rewrite flash memory without soldering.
|
||||
* This also allows console to write data to the cartridge.
|
||||
* This behavior is not emulated.
|
||||
* No cart has been discovered so far that makes use of this feature, but this can be used for homebrew.
|
||||
*
|
||||
* hardware tested logic, don't try to understand lol
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
@ -71,12 +116,7 @@ static void COOLBOYPW(uint32 A, uint8 V) {
|
||||
// Last banks are first in this mode, ignored when MMC3_cmd&0x40
|
||||
if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
|
||||
switch (A & 0xE000) {
|
||||
case 0xA000:
|
||||
if ((MMC3_cmd & 0x40)) V = 0;
|
||||
break;
|
||||
case 0xC000:
|
||||
if (!(MMC3_cmd & 0x40)) V = 0;
|
||||
break;
|
||||
case 0xE000:
|
||||
V = 0;
|
||||
break;
|
||||
@ -115,10 +155,6 @@ static DECLFW(COOLBOYWrite) {
|
||||
static void COOLBOYReset(void) {
|
||||
MMC3RegReset();
|
||||
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
|
||||
// EXPREGS[0] = 0;
|
||||
// EXPREGS[1] = 0x60;
|
||||
// EXPREGS[2] = 0;
|
||||
// EXPREGS[3] = 0;
|
||||
FixMMC3PRG(MMC3_cmd);
|
||||
FixMMC3CHR(MMC3_cmd);
|
||||
}
|
||||
@ -126,21 +162,52 @@ static void COOLBOYReset(void) {
|
||||
static void COOLBOYPower(void) {
|
||||
GenMMC3Power();
|
||||
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
|
||||
// EXPREGS[0] = 0;
|
||||
// EXPREGS[1] = 0x60;
|
||||
// EXPREGS[2] = 0;
|
||||
// EXPREGS[3] = 0;
|
||||
FixMMC3PRG(MMC3_cmd);
|
||||
FixMMC3CHR(MMC3_cmd);
|
||||
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
|
||||
SetWriteHandler(0x6000, 0x7fff, COOLBOYWrite);
|
||||
SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite);
|
||||
}
|
||||
|
||||
static void MINDKIDSPower(void) {
|
||||
GenMMC3Power();
|
||||
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
|
||||
FixMMC3PRG(MMC3_cmd);
|
||||
FixMMC3CHR(MMC3_cmd);
|
||||
SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite);
|
||||
}
|
||||
|
||||
// Registers at $6xxx
|
||||
void COOLBOY_Init(CartInfo *info) {
|
||||
GenMMC3_Init(info, 512, 256, 8, 0);
|
||||
GenMMC3_Init(info, 2048, 256, 8, 1);
|
||||
pwrap = COOLBOYPW;
|
||||
cwrap = COOLBOYCW;
|
||||
info->Power = COOLBOYPower;
|
||||
info->Reset = COOLBOYReset;
|
||||
AddExState(EXPREGS, 4, 0, "EXPR");
|
||||
}
|
||||
|
||||
// Registers at $5xxx
|
||||
void MINDKIDS_Init(CartInfo *info) {
|
||||
GenMMC3_Init(info, 2048, 256, 8, 1);
|
||||
pwrap = COOLBOYPW;
|
||||
cwrap = COOLBOYCW;
|
||||
info->Power = MINDKIDSPower;
|
||||
info->Reset = COOLBOYReset;
|
||||
AddExState(EXPREGS, 4, 0, "EXPR");
|
||||
}
|
||||
|
||||
// For NES 2.0 loader
|
||||
void SMD132_SMD133_Init(CartInfo *info) {
|
||||
switch (info->submapper)
|
||||
{
|
||||
case 0:
|
||||
COOLBOY_Init(info);
|
||||
break;
|
||||
case 1:
|
||||
MINDKIDS_Init(info);
|
||||
break;
|
||||
default:
|
||||
FCEU_PrintError("Unknown submapper: #%d.", info->submapper);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,6 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
|
||||
|
||||
}
|
||||
AddExState(&latche, 1, 0, "LATC");
|
||||
AddExState(&bus_conflict, 1, 0, "BUSC");
|
||||
}
|
||||
|
||||
//------------------ Map 0 ---------------------------
|
||||
@ -181,7 +180,7 @@ static void UNROMSync(void) {
|
||||
}
|
||||
|
||||
void UNROM_Init(CartInfo *info) {
|
||||
Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 0, 1);
|
||||
Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 0, info->ines2 && info->submapper == 2);
|
||||
}
|
||||
|
||||
//------------------ Map 3 ---------------------------
|
||||
@ -193,7 +192,7 @@ static void CNROMSync(void) {
|
||||
}
|
||||
|
||||
void CNROM_Init(CartInfo *info) {
|
||||
Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, 1);
|
||||
Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, info->ines2 && info->submapper == 2);
|
||||
}
|
||||
|
||||
//------------------ Map 7 ---------------------------
|
||||
|
@ -53,22 +53,22 @@
|
||||
#include "emu2413.h"
|
||||
|
||||
static const unsigned char default_inst[15][8] = {
|
||||
/* VRC7 instruments, January 17, 2004 update -Xodnizel */
|
||||
{ 0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17 },
|
||||
{ 0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12 },
|
||||
{ 0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02 },
|
||||
{ 0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27 },
|
||||
{ 0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28 },
|
||||
{ 0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95 },
|
||||
{ 0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07 },
|
||||
{ 0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15 },
|
||||
{ 0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11 },
|
||||
{ 0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12 },
|
||||
{ 0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4 },
|
||||
{ 0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16 },
|
||||
{ 0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51 },
|
||||
{ 0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05 },
|
||||
{ 0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17 },
|
||||
/* VRC7 instruments, March 15, 2019 dumped by Nuke.YKT */
|
||||
{ 0x03, 0x21, 0x05, 0x06, 0xE8, 0x81, 0x42, 0x27 },
|
||||
{ 0x13, 0x41, 0x14, 0x0D, 0xD8, 0xF6, 0x23, 0x12 },
|
||||
{ 0x11, 0x11, 0x08, 0x08, 0xFA, 0xB2, 0x20, 0x12 },
|
||||
{ 0x31, 0x61, 0x0C, 0x07, 0xA8, 0x64, 0x61, 0x27 },
|
||||
{ 0x32, 0x21, 0x1E, 0x06, 0xE1, 0x76, 0x01, 0x28 },
|
||||
{ 0x02, 0x01, 0x06, 0x00, 0xA3, 0xE2, 0xF4, 0xF4 },
|
||||
{ 0x21, 0x61, 0x1D, 0x07, 0x82, 0x81, 0x11, 0x07 },
|
||||
{ 0x23, 0x21, 0x22, 0x17, 0xA2, 0x72, 0x01, 0x17 },
|
||||
{ 0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 },
|
||||
{ 0xB5, 0x01, 0x0F, 0x0F, 0xA8, 0xA5, 0x51, 0x02 },
|
||||
{ 0x17, 0xC1, 0x24, 0x07, 0xF8, 0xF8, 0x22, 0x12 },
|
||||
{ 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 },
|
||||
{ 0x01, 0x02, 0xD3, 0x05, 0xC9, 0x95, 0x03, 0x02 },
|
||||
{ 0x61, 0x63, 0x0C, 0x00, 0x94, 0xC0, 0x33, 0xF6 },
|
||||
{ 0x21, 0x72, 0x0D, 0x00, 0xC1, 0xD5, 0x56, 0x06 },
|
||||
};
|
||||
|
||||
/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.)*/
|
||||
@ -604,8 +604,8 @@ void OPLL_reset(OPLL * opll) {
|
||||
for (i = 0; i < 0x40; i++)
|
||||
OPLL_writeReg(opll, i, 0);
|
||||
|
||||
opll->realstep = (uint32)((1 << 31) / rate);
|
||||
opll->opllstep = (uint32)((1 << 31) / (clk / 72));
|
||||
opll->realstep = (uint32)((1u << 31) / rate);
|
||||
opll->opllstep = (uint32)((1u << 31) / (clk / 72));
|
||||
opll->oplltime = 0;
|
||||
}
|
||||
|
||||
|
@ -82,10 +82,10 @@ static int prg_mask;
|
||||
//PRG wrapper
|
||||
static void BMCFK23CPW(uint32 A, uint8 V)
|
||||
{
|
||||
uint32 bank = (EXPREGS[1] & 0x1F);
|
||||
uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
|
||||
uint32 block = (EXPREGS[1] & 0x60) | hiblock;
|
||||
uint32 extra = (EXPREGS[3] & 2);
|
||||
//uint32 bank = (EXPREGS[1] & 0x1F);
|
||||
//uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
|
||||
//uint32 block = (EXPREGS[1] & 0x60) | hiblock;
|
||||
//uint32 extra = (EXPREGS[3] & 2);
|
||||
// FCEU_printf("0:%04X:%02X\n",A,V);
|
||||
|
||||
if((EXPREGS[0]&7)==4)
|
||||
@ -161,7 +161,7 @@ static DECLFW(BMCFK23CWrite)
|
||||
EXPREGS[A&3]=V;
|
||||
|
||||
// BUT WHY is there any rom that need it actually?
|
||||
bool remap = false;
|
||||
// bool remap = false;
|
||||
// FCEU_printf("K3:(exp0=%02x)\n",EXPREGS[0]);
|
||||
// FCEU_printf("WH0:%04X:%02X\n",A,V);
|
||||
|
||||
@ -199,7 +199,7 @@ static void BMCFK23CReset(void)
|
||||
//this little hack makes sure that we try all the dip switch settings eventually, if we reset enough
|
||||
dipswitch++;
|
||||
dipswitch&=7;
|
||||
printf("BMCFK23C dipswitch set to %d\n",dipswitch);
|
||||
printf("BMCFK23C dipswitch set to %u\n",dipswitch);
|
||||
|
||||
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
|
||||
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
|
||||
|
@ -113,6 +113,9 @@ void MMC3RegReset(void) {
|
||||
DRegBuf[6] = 0;
|
||||
DRegBuf[7] = 1;
|
||||
|
||||
// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support
|
||||
kt_extra = 0;
|
||||
|
||||
FixMMC3PRG(0);
|
||||
FixMMC3CHR(0);
|
||||
}
|
||||
@ -187,7 +190,14 @@ DECLFW(MMC3_IRQWrite) {
|
||||
DECLFW(KT008HackWrite) {
|
||||
// FCEU_printf("%04x:%04x\n",A,V);
|
||||
switch (A & 3) {
|
||||
case 0: kt_extra = V; FixMMC3PRG(MMC3_cmd); break;
|
||||
case 0: {
|
||||
if (V == 0x27) // FF Xn hack! one more mapper in one
|
||||
kt_extra = 0;
|
||||
else
|
||||
kt_extra = V;
|
||||
FixMMC3PRG(MMC3_cmd);
|
||||
break;
|
||||
}
|
||||
case 1: break; // unk
|
||||
case 2: break; // unk
|
||||
case 3: break; // unk
|
||||
@ -1353,3 +1363,30 @@ void TQROM_Init(CartInfo *info) {
|
||||
void HKROM_Init(CartInfo *info) {
|
||||
GenMMC3_Init(info, 512, 512, 1, info->battery);
|
||||
}
|
||||
|
||||
// -------------------------------- iNES 2.0 ----------------------------
|
||||
|
||||
// ---------------------------- Mapper 406 ------------------------------
|
||||
|
||||
static DECLFW(M406CMDWrite) {
|
||||
MMC3_CMDWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
|
||||
}
|
||||
|
||||
static DECLFW(M406IRQWrite) {
|
||||
MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
|
||||
}
|
||||
|
||||
static DECLFW(M406Write) {
|
||||
}
|
||||
|
||||
static void M406_Power(void) {
|
||||
GenMMC3Power();
|
||||
// TODO : FLASH
|
||||
SetWriteHandler(0x8000, 0xBFFF, M406CMDWrite);
|
||||
SetWriteHandler(0xC000, 0xFFFF, M406IRQWrite);
|
||||
}
|
||||
|
||||
void Mapper406_Init(CartInfo *info) {
|
||||
GenMMC3_Init(info, 512, 256, 0, 0);
|
||||
info->Power = M406_Power;
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include "mapinc.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#define ABANKS MMC5SPRVPage
|
||||
#define BBANKS MMC5BGVPage
|
||||
#define SpriteON (PPU[1] & 0x10) //Show Sprite
|
||||
@ -81,10 +83,11 @@ static INLINE void MMC5BGVROM_BANK8(uint32 V) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint8 PRGBanks[4];
|
||||
static std::array<uint8,4> PRGBanks;
|
||||
static uint8 WRAMPage;
|
||||
static uint16 CHRBanksA[8], CHRBanksB[4];
|
||||
static uint8 WRAMMaskEnable[2];
|
||||
static std::array<uint16,8> CHRBanksA;
|
||||
static std::array<uint16,4> CHRBanksB;
|
||||
static std::array<uint8,2> WRAMMaskEnable;
|
||||
uint8 mmc5ABMode; /* A=0, B=1 */
|
||||
|
||||
static uint8 IRQScanline, IRQEnable;
|
||||
@ -93,18 +96,20 @@ static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
|
||||
static uint8 MMC5IRQR;
|
||||
static uint8 MMC5LineCounter;
|
||||
static uint8 mmc5psize, mmc5vsize;
|
||||
static uint8 mul[2];
|
||||
static std::array<uint8,2> mul;
|
||||
|
||||
static uint32 WRAMSIZE = 0;
|
||||
static uint8 *WRAM = NULL;
|
||||
static uint8 *MMC5fill = NULL;
|
||||
static uint8 *ExRAM = NULL;
|
||||
static uint8 MMC5battery = 0;
|
||||
|
||||
static uint8 MMC5WRAMsize; //configuration, not state
|
||||
static uint8 MMC5WRAMIndex[8]; //configuration, not state
|
||||
const int MMC5WRAMMAX = 1<<7; // 7 bits in register interface (real MMC5 has only 4 pins, however)
|
||||
static uint8 MMC5WRAMsize=0; //configuration, not state
|
||||
static uint8 MMC5WRAMIndex[MMC5WRAMMAX]; //configuration, not state
|
||||
|
||||
static uint8 MMC5ROMWrProtect[4];
|
||||
static uint8 MMC5MemIn[5];
|
||||
static std::array<uint8,4> MMC5ROMWrProtect;
|
||||
static std::array<uint8,5> MMC5MemIn;
|
||||
|
||||
static void MMC5CHRA(void);
|
||||
static void MMC5CHRB(void);
|
||||
@ -146,12 +151,18 @@ uint8* MMC5BGVRAMADR(uint32 A)
|
||||
static void mmc5_PPUWrite(uint32 A, uint8 V) {
|
||||
uint32 tmp = A;
|
||||
extern uint8 PALRAM[0x20];
|
||||
extern uint8 UPALRAM[0x03];
|
||||
|
||||
if (tmp >= 0x3F00) {
|
||||
// hmmm....
|
||||
if (!(tmp & 0xf))
|
||||
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
|
||||
else if (tmp & 3) PALRAM[(tmp & 0x1f)] = V & 0x3f;
|
||||
if (!(tmp & 3)) {
|
||||
if (!(tmp & 0xC)) {
|
||||
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
|
||||
PALRAM[0x10] = PALRAM[0x14] = PALRAM[0x18] = PALRAM[0x1C] = V & 0x3F;
|
||||
}
|
||||
else
|
||||
UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F;
|
||||
} else
|
||||
PALRAM[tmp & 0x1F] = V & 0x3F;
|
||||
} else if (tmp < 0x2000) {
|
||||
if (PPUCHRRAM & (1 << (tmp >> 10)))
|
||||
VPage[tmp >> 10][tmp] = V;
|
||||
@ -308,6 +319,8 @@ int DetectMMC5WRAMSize(uint32 crc32) {
|
||||
}
|
||||
|
||||
static void BuildWRAMSizeTable(void) {
|
||||
bool other = false; // non-standard configuration
|
||||
// fill first 8 entries
|
||||
int x;
|
||||
for (x = 0; x < 8; x++) {
|
||||
switch (MMC5WRAMsize) {
|
||||
@ -315,9 +328,22 @@ static void BuildWRAMSizeTable(void) {
|
||||
case 1: MMC5WRAMIndex[x] = (x > 3) ? 255 : 0; break; //0,0,0,0,X,X,X,X
|
||||
case 2: MMC5WRAMIndex[x] = (x & 4) >> 2; break; //0,0,0,0,1,1,1,1
|
||||
case 4: MMC5WRAMIndex[x] = (x > 3) ? 255 : (x & 3); break; //0,1,2,3,X,X,X,X
|
||||
case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7
|
||||
case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7
|
||||
default: MMC5WRAMIndex[x] = x; other = true; break; //0,1,2...
|
||||
}
|
||||
}
|
||||
// extend to fill complete table
|
||||
if (other)
|
||||
{
|
||||
for (x = 0; x < MMC5WRAMMAX && x < MMC5WRAMsize; ++x) MMC5WRAMIndex[x] = x; // linear mapping
|
||||
for (x = MMC5WRAMsize; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x-MMC5WRAMsize]; // repeat to fill table
|
||||
// theoretically the table fill should decompose into powers of two for possible mismatched SRAM combos,
|
||||
// but I don't want to complicate the code with unnecessary hypotheticals
|
||||
}
|
||||
else
|
||||
{
|
||||
for (x = 8; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x & 7]; // fill table, repeating groups of 8
|
||||
}
|
||||
}
|
||||
|
||||
static void MMC5CHRA(void) {
|
||||
@ -385,7 +411,7 @@ static void MMC5CHRB(void) {
|
||||
}
|
||||
|
||||
static void MMC5WRAM(uint32 A, uint32 V) {
|
||||
V = MMC5WRAMIndex[V & 7];
|
||||
V = MMC5WRAMIndex[V & (MMC5WRAMMAX-1)];
|
||||
if (V != 255) {
|
||||
setprg8r(0x10, A, V);
|
||||
FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1))));
|
||||
@ -410,8 +436,8 @@ static void MMC5PRG(void) {
|
||||
MMC5MemIn[1] = MMC5MemIn[2] = 1;
|
||||
} else {
|
||||
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
|
||||
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE);
|
||||
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1);
|
||||
MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
|
||||
MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
|
||||
}
|
||||
MMC5MemIn[3] = MMC5MemIn[4] = 1;
|
||||
MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1;
|
||||
@ -424,8 +450,8 @@ static void MMC5PRG(void) {
|
||||
setprg16(0x8000, (PRGBanks[1] & 0x7F) >> 1);
|
||||
} else {
|
||||
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
|
||||
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE);
|
||||
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1);
|
||||
MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
|
||||
MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
|
||||
}
|
||||
if (PRGBanks[2] & 0x80) {
|
||||
MMC5ROMWrProtect[2] = 1;
|
||||
@ -433,7 +459,7 @@ static void MMC5PRG(void) {
|
||||
setprg8(0xC000, PRGBanks[2] & 0x7F);
|
||||
} else {
|
||||
MMC5ROMWrProtect[2] = 0;
|
||||
MMC5WRAM(0xC000, PRGBanks[2] & 7);
|
||||
MMC5WRAM(0xC000, PRGBanks[2] & (MMC5WRAMMAX-1));
|
||||
}
|
||||
MMC5MemIn[4] = 1;
|
||||
MMC5ROMWrProtect[3] = 1;
|
||||
@ -447,7 +473,7 @@ static void MMC5PRG(void) {
|
||||
MMC5MemIn[1 + x] = 1;
|
||||
} else {
|
||||
MMC5ROMWrProtect[x] = 0;
|
||||
MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & 7);
|
||||
MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & (MMC5WRAMMAX-1));
|
||||
}
|
||||
MMC5MemIn[4] = 1;
|
||||
MMC5ROMWrProtect[3] = 1;
|
||||
@ -510,7 +536,7 @@ static DECLFW(Mapper5_write) {
|
||||
break;
|
||||
case 0x5113:
|
||||
WRAMPage = V;
|
||||
MMC5WRAM(0x6000, V & 7);
|
||||
MMC5WRAM(0x6000, V & (MMC5WRAMMAX-1));
|
||||
break;
|
||||
case 0x5114:
|
||||
case 0x5115:
|
||||
@ -606,7 +632,7 @@ void MMC5Synco(void) {
|
||||
case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break;
|
||||
}
|
||||
}
|
||||
MMC5WRAM(0x6000, WRAMPage & 7);
|
||||
MMC5WRAM(0x6000, WRAMPage & (MMC5WRAMMAX-1));
|
||||
if (!mmc5ABMode) {
|
||||
MMC5CHRB();
|
||||
MMC5CHRA();
|
||||
@ -869,22 +895,42 @@ void NSFMMC5_Close(void) {
|
||||
if (WRAM)
|
||||
FCEU_gfree(WRAM);
|
||||
WRAM = NULL;
|
||||
MMC5WRAMsize = 0;
|
||||
FCEU_gfree(ExRAM);
|
||||
ExRAM = NULL;
|
||||
}
|
||||
|
||||
static void GenMMC5Reset(void) {
|
||||
int x;
|
||||
static void GenMMC5Power(void) {
|
||||
|
||||
for (x = 0; x < 4; x++) PRGBanks[x] = ~0;
|
||||
for (x = 0; x < 8; x++) CHRBanksA[x] = ~0;
|
||||
for (x = 0; x < 4; x++) CHRBanksB[x] = ~0;
|
||||
WRAMMaskEnable[0] = WRAMMaskEnable[1] = ~0;
|
||||
|
||||
mmc5psize = mmc5vsize = 3;
|
||||
PRGBanks.fill(0xFF);
|
||||
WRAMPage = 0;
|
||||
CHRBanksA.fill(0xFF);
|
||||
CHRBanksB.fill(0xFF);
|
||||
WRAMMaskEnable.fill(0xFF);
|
||||
mmc5ABMode = 0;
|
||||
IRQScanline = 0;
|
||||
IRQEnable = 0;
|
||||
CHRMode = 0;
|
||||
|
||||
NTAMirroring = NTFill = ATFill = 0xFF;
|
||||
MMC5IRQR = 0;
|
||||
MMC5LineCounter = 0;
|
||||
mmc5psize = mmc5vsize = 3;
|
||||
mul.fill(0);
|
||||
|
||||
MMC5ROMWrProtect.fill(0);
|
||||
MMC5MemIn.fill(0);
|
||||
|
||||
// MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable
|
||||
u8 nval = MMC5fill[0x000];
|
||||
u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6);
|
||||
FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0);
|
||||
FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040);
|
||||
|
||||
if(MMC5battery == 0) {
|
||||
FCEU_MemoryRand(WRAM, MMC5WRAMsize * 8 * 1024);
|
||||
FCEU_MemoryRand(MMC5fill,1024);
|
||||
FCEU_MemoryRand(ExRAM,1024);
|
||||
}
|
||||
|
||||
MMC5Synco();
|
||||
|
||||
@ -907,11 +953,11 @@ static void GenMMC5Reset(void) {
|
||||
}
|
||||
|
||||
static SFORMAT MMC5_StateRegs[] = {
|
||||
{ PRGBanks, 4, "PRGB" },
|
||||
{ CHRBanksA, 16, "CHRA" },
|
||||
{ CHRBanksB, 8, "CHRB" },
|
||||
{ &PRGBanks, 4, "PRGB" },
|
||||
{ &CHRBanksA, 16, "CHRA" },
|
||||
{ &CHRBanksB, 8, "CHRB" },
|
||||
{ &WRAMPage, 1, "WRMP" },
|
||||
{ WRAMMaskEnable, 2, "WRME" },
|
||||
{ &WRAMMaskEnable, 2, "WRME" },
|
||||
{ &mmc5ABMode, 1, "ABMD" },
|
||||
{ &IRQScanline, 1, "IRQS" },
|
||||
{ &IRQEnable, 1, "IRQE" },
|
||||
@ -925,9 +971,9 @@ static SFORMAT MMC5_StateRegs[] = {
|
||||
{ &MMC5LineCounter, 1, "LCTR" },
|
||||
{ &mmc5psize, 1, "PSIZ" },
|
||||
{ &mmc5vsize, 1, "VSIZ" },
|
||||
{ mul, 2, "MUL2" },
|
||||
{ MMC5ROMWrProtect, 4, "WRPR" },
|
||||
{ MMC5MemIn, 5, "MEMI" },
|
||||
{ &mul, 2, "MUL2" },
|
||||
{ &MMC5ROMWrProtect, 4, "WRPR" },
|
||||
{ &MMC5MemIn, 5, "MEMI" },
|
||||
|
||||
{ &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" },
|
||||
{ &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" },
|
||||
@ -950,19 +996,17 @@ static SFORMAT MMC5_StateRegs[] = {
|
||||
|
||||
static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
|
||||
if (wsize) {
|
||||
WRAM = (uint8*)FCEU_gmalloc(wsize * 1024);
|
||||
WRAM = (uint8*)FCEU_malloc(wsize * 1024);
|
||||
FCEU_MemoryRand(WRAM, wsize * 1024);
|
||||
SetupCartPRGMapping(0x10, WRAM, wsize * 1024, 1);
|
||||
AddExState(WRAM, wsize * 1024, 0, "WRAM");
|
||||
}
|
||||
|
||||
MMC5fill = (uint8*)FCEU_gmalloc(1024);
|
||||
ExRAM = (uint8*)FCEU_gmalloc(1024);
|
||||
MMC5fill = (uint8*)FCEU_malloc(1024);
|
||||
ExRAM = (uint8*)FCEU_malloc(1024);
|
||||
|
||||
// MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable
|
||||
u8 nval = MMC5fill[0x000];
|
||||
u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6);
|
||||
FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0);
|
||||
FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040);
|
||||
FCEU_MemoryRand(MMC5fill,1024);
|
||||
FCEU_MemoryRand(ExRAM,1024);
|
||||
|
||||
AddExState(ExRAM, 1024, 0, "ERAM");
|
||||
AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
|
||||
@ -974,19 +1018,26 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
|
||||
MMC5WRAMsize = wsize / 8;
|
||||
BuildWRAMSizeTable();
|
||||
GameStateRestore = MMC5_StateRestore;
|
||||
info->Power = GenMMC5Reset;
|
||||
info->Power = GenMMC5Power;
|
||||
|
||||
MMC5battery = battery;
|
||||
if (battery) {
|
||||
info->SaveGame[0] = WRAM;
|
||||
|
||||
//this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you
|
||||
//I added 64KB for the new 64KB homebrews
|
||||
if (wsize <= 16)
|
||||
info->SaveGameLen[0] = 8192;
|
||||
else if(wsize == 64)
|
||||
info->SaveGameLen[0] = 64*1024;
|
||||
if (info->ines2)
|
||||
{
|
||||
info->SaveGameLen[0] = info->battery_wram_size;
|
||||
}
|
||||
else
|
||||
info->SaveGameLen[0] = 32768;
|
||||
{
|
||||
//this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you
|
||||
//I added 64KB for the new 64KB homebrews
|
||||
if (wsize <= 16)
|
||||
info->SaveGameLen[0] = 8192;
|
||||
else if(wsize == 64)
|
||||
info->SaveGameLen[0] = 64*1024;
|
||||
else
|
||||
info->SaveGameLen[0] = 32768;
|
||||
}
|
||||
}
|
||||
|
||||
MMC5HackVROMMask = CHRmask4[0];
|
||||
@ -1002,7 +1053,14 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
|
||||
}
|
||||
|
||||
void Mapper5_Init(CartInfo *info) {
|
||||
WRAMSIZE = DetectMMC5WRAMSize(info->CRC32);
|
||||
if (info->ines2)
|
||||
{
|
||||
WRAMSIZE = (info->wram_size + info->battery_wram_size) / 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
WRAMSIZE = DetectMMC5WRAMSize(info->CRC32);
|
||||
}
|
||||
GenMMC5_Init(info, WRAMSIZE, info->battery);
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,10 @@ static void FixCache(int a, int V) {
|
||||
case 0x02: FreqCache[w] &= ~0x0000FF00; FreqCache[w] |= V << 8; break;
|
||||
case 0x04:
|
||||
FreqCache[w] &= ~0x00030000; FreqCache[w] |= (V & 3) << 16;
|
||||
LengthCache[w] = (8 - ((V >> 2) & 7)) << 2;
|
||||
// something wrong here http://www.romhacking.net/forum/index.php?topic=21907.msg306903#msg306903
|
||||
// LengthCache[w] = (8 - ((V >> 2) & 7)) << 2;
|
||||
// fix be like in https://github.com/SourMesen/Mesen/blob/cda0a0bdcb5525480784f4b8c71de6fc7273b570/Core/Namco163Audio.h#L61
|
||||
LengthCache[w] = 256 - (V & 0xFC);
|
||||
break;
|
||||
case 0x07: EnvCache[w] = (double)(V & 0xF) * 576716; break;
|
||||
}
|
||||
@ -348,9 +351,9 @@ static void DoNamcoSound(int32 *Wave, int Count) {
|
||||
|
||||
static void Mapper19_StateRestore(int version) {
|
||||
SyncPRG();
|
||||
SyncMirror();
|
||||
FixNTAR();
|
||||
FixCRR();
|
||||
SyncMirror();
|
||||
int x;
|
||||
for (x = 0x40; x < 0x80; x++)
|
||||
FixCache(x, IRAM[x]);
|
||||
|
@ -47,6 +47,9 @@ static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xE1;
|
||||
static writefunc defapuwrite[64];
|
||||
static readfunc defapuread[64];
|
||||
|
||||
static uint32 WRAMSIZE;
|
||||
static uint8 *WRAM = NULL;
|
||||
|
||||
static SFORMAT StateRegs[] =
|
||||
{
|
||||
{ cpu410x, 16, "REGC" },
|
||||
@ -265,6 +268,13 @@ static void UNLOneBusPower(void) {
|
||||
SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X);
|
||||
SetWriteHandler(0x8000, 0xffff, UNLOneBusWriteMMC3);
|
||||
|
||||
if (WRAMSIZE) {
|
||||
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
|
||||
SetWriteHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBW);
|
||||
SetReadHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBR);
|
||||
setprg8r(0x10, 0x6000, 0);
|
||||
}
|
||||
|
||||
Sync();
|
||||
}
|
||||
|
||||
@ -282,9 +292,16 @@ static void StateRestore(int version) {
|
||||
Sync();
|
||||
}
|
||||
|
||||
void UNLOneBusClose(void) {
|
||||
if (WRAM)
|
||||
FCEU_gfree(WRAM);
|
||||
WRAM = NULL;
|
||||
}
|
||||
|
||||
void UNLOneBus_Init(CartInfo *info) {
|
||||
info->Power = UNLOneBusPower;
|
||||
info->Reset = UNLOneBusReset;
|
||||
info->Close = UNLOneBusClose;
|
||||
|
||||
if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts
|
||||
((*(uint32*)&(info->MD5)) == 0x6abfce8e))
|
||||
@ -294,4 +311,17 @@ void UNLOneBus_Init(CartInfo *info) {
|
||||
MapIRQHook = UNLOneBusCpuHook;
|
||||
GameStateRestore = StateRestore;
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
|
||||
WRAMSIZE = 8 * 1024;
|
||||
if (info->ines2)
|
||||
WRAMSIZE = info->wram_size + info->battery_wram_size;
|
||||
if (WRAMSIZE) {
|
||||
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
|
||||
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
|
||||
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
|
||||
if (info->battery) {
|
||||
info->SaveGame[0] = WRAM;
|
||||
info->SaveGameLen[0] = WRAMSIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* PEC-586 FC based computer series by DUNDA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
|
@ -40,8 +40,8 @@ static uint16 latcha;
|
||||
static uint8 *flashdata;
|
||||
static uint32 *flash_write_count;
|
||||
static uint8 *FlashPage[32];
|
||||
static uint32 *FlashWriteCountPage[32];
|
||||
static uint8 flashloaded = false;
|
||||
//static uint32 *FlashWriteCountPage[32];
|
||||
//static uint8 flashloaded = false;
|
||||
|
||||
static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank;
|
||||
static void (*WLSync)(void);
|
||||
|
@ -28,7 +28,6 @@ static uint8 prgreg[2], chrreg[8];
|
||||
static uint16 chrhi[8];
|
||||
static uint8 regcmd, irqcmd, mirr, big_bank;
|
||||
static uint16 acount = 0;
|
||||
static uint16 weirdo = 0;
|
||||
|
||||
static uint8 *WRAM = NULL;
|
||||
static uint32 WRAMSIZE;
|
||||
@ -38,6 +37,7 @@ static SFORMAT StateRegs[] =
|
||||
{ prgreg, 2, "PREG" },
|
||||
{ chrreg, 8, "CREG" },
|
||||
{ chrhi, 16, "CRGH" },
|
||||
{ &acount, 2, "ACNT" },
|
||||
{ ®cmd, 1, "CMDR" },
|
||||
{ &irqcmd, 1, "CMDI" },
|
||||
{ &mirr, 1, "MIRR" },
|
||||
@ -62,15 +62,8 @@ static void Sync(void) {
|
||||
setchr8(0);
|
||||
else{
|
||||
uint8 i;
|
||||
//if(!weirdo)
|
||||
for (i = 0; i < 8; i++)
|
||||
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
|
||||
//else {
|
||||
// setchr1(0x0000, 0xFC);
|
||||
// setchr1(0x0400, 0xFD);
|
||||
// setchr1(0x0800, 0xFF);
|
||||
// weirdo--;
|
||||
//}
|
||||
for (i = 0; i < 8; i++)
|
||||
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
|
||||
}
|
||||
switch (mirr & 0x3) {
|
||||
case 0: setmirror(MI_V); break;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 CaH4e3
|
||||
* Copyright (C) 2005-2019 CaH4e3
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -17,25 +17,118 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* VRC-5 (CAI Shogakko no Sansu)
|
||||
* VRC-V (CAI Shogakko no Sansu)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mapinc.h"
|
||||
|
||||
static uint8 QTAINTRAM[2048];
|
||||
static writefunc old2007wrap;
|
||||
//#define CAI_DEBUG
|
||||
|
||||
// main tiles RAM is 8K in size, but unless other non-CHR ROM type carts,
|
||||
// this one accesses the $0000 and $1000 pages based on extra NT RAM on board
|
||||
// which is similar to MMC5 but much simpler because there are no additional
|
||||
// bankings here.
|
||||
// extra NT RAM handling is in PPU code now.
|
||||
|
||||
static uint16 CHRSIZE = 8192;
|
||||
static uint16 WRAMSIZE = 8192 + 4096;
|
||||
// there are two separate WRAMs 8K each, on main system cartridge (not battery
|
||||
// backed), and one on the daughter cart (with battery). both are accessed
|
||||
// via the same registers with additional selector flags.
|
||||
static uint16 WRAMSIZE = 8192 + 8192;
|
||||
static uint8 *CHRRAM = NULL;
|
||||
static uint8 *WRAM = NULL;
|
||||
|
||||
static uint8 IRQa, K4IRQ;
|
||||
static uint32 IRQLatch, IRQCount;
|
||||
|
||||
// some kind of 16-bit text encoding (actually 14-bit) used in game resources
|
||||
// may be converted by the hardware into the tile indexes for internal CHR ROM
|
||||
// not sure whey they made it hardware, because most of calculations are just
|
||||
// bit shifting. the main purpose of this table is to calculate actual CHR ROM
|
||||
// bank for every character. there is a some kind of regularity, so this table
|
||||
// may be calculated in software easily.
|
||||
|
||||
// table read out from hardware registers as is
|
||||
|
||||
///*
|
||||
static uint8 conv_tbl[4][8] = {
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x40, 0x10, 0x28, 0x00, 0x18, 0x30 },
|
||||
{ 0x00, 0x00, 0x48, 0x18, 0x30, 0x08, 0x20, 0x38 },
|
||||
{ 0x00, 0x00, 0x80, 0x20, 0x38, 0x10, 0x28, 0xB0 }
|
||||
};
|
||||
//*/
|
||||
/*
|
||||
static uint8 conv_tbl[64][4] = {
|
||||
{ 0x40, 0x40, 0x40, 0x40 }, // 00 | A - 40 41 42 43 44 45 46 47
|
||||
{ 0x41, 0x41, 0x41, 0x41 }, // 02 | B - 48 49 4A 4B 4C 4D 4E 4F
|
||||
{ 0x42, 0x42, 0x42, 0x42 }, // 04 | C - 50 51 52 53 54 55 56 57
|
||||
{ 0x43, 0x43, 0x43, 0x43 }, // 06 | D - 58 59 5A 5B 5C 5D 5E 5F
|
||||
{ 0x44, 0x44, 0x44, 0x44 }, // 08 | E - 60 61 62 63 64 65 66 67
|
||||
{ 0x45, 0x45, 0x45, 0x45 }, // 0A | F - 68 69 6A 6B 6C 6D 6E 6F
|
||||
{ 0x46, 0x46, 0x46, 0x46 }, // 0C | G - 70 71 72 73 74 75 76 77
|
||||
{ 0x47, 0x47, 0x47, 0x47 }, // 0E | H - 78 79 7A 7B 7C 7D 7E 7F
|
||||
{ 0x40, 0x40, 0x40, 0x40 }, // 10 |
|
||||
{ 0x41, 0x41, 0x41, 0x41 }, // 12 +----------------------------
|
||||
{ 0x42, 0x42, 0x42, 0x42 }, // 14 | A A A A
|
||||
{ 0x43, 0x43, 0x43, 0x43 }, // 16 | A A A A
|
||||
{ 0x44, 0x44, 0x44, 0x44 }, // 18 | A A' B' A"
|
||||
{ 0x45, 0x45, 0x45, 0x45 }, // 1A | A C D E
|
||||
{ 0x46, 0x46, 0x46, 0x46 }, // 1C | A F G H
|
||||
{ 0x47, 0x47, 0x47, 0x47 }, // 1E | A A B C
|
||||
{ 0x40, 0x40, 0x48, 0x44 }, // 20 | A D E F
|
||||
{ 0x41, 0x41, 0x49, 0x45 }, // 22 | A G H G"
|
||||
{ 0x42, 0x42, 0x4A, 0x46 }, // 24 +----------------------------
|
||||
{ 0x43, 0x43, 0x4B, 0x47 }, // 26 | A' - 40 41 42 43 40 41 42 43
|
||||
{ 0x44, 0x40, 0x48, 0x44 }, // 28 | A" - 44 45 46 47 44 45 46 47
|
||||
{ 0x45, 0x41, 0x49, 0x45 }, // 2A | B' - 48 49 4A 4B 48 49 4A 4B
|
||||
{ 0x46, 0x42, 0x4A, 0x46 }, // 2C | G" - 74 75 76 77 74 75 76 77
|
||||
{ 0x47, 0x43, 0x4B, 0x47 }, // 2E
|
||||
{ 0x40, 0x50, 0x58, 0x60 }, // 30
|
||||
{ 0x41, 0x51, 0x59, 0x61 }, // 32
|
||||
{ 0x42, 0x52, 0x5A, 0x62 }, // 34
|
||||
{ 0x43, 0x53, 0x5B, 0x63 }, // 36
|
||||
{ 0x44, 0x54, 0x5C, 0x64 }, // 38
|
||||
{ 0x45, 0x55, 0x5D, 0x65 }, // 3A
|
||||
{ 0x46, 0x56, 0x5E, 0x66 }, // 3C
|
||||
{ 0x47, 0x57, 0x5F, 0x67 }, // 3E
|
||||
{ 0x40, 0x68, 0x70, 0x78 }, // 40
|
||||
{ 0x41, 0x69, 0x71, 0x79 }, // 42
|
||||
{ 0x42, 0x6A, 0x72, 0x7A }, // 44
|
||||
{ 0x43, 0x6B, 0x73, 0x7B }, // 46
|
||||
{ 0x44, 0x6C, 0x74, 0x7C }, // 48
|
||||
{ 0x45, 0x6D, 0x75, 0x7D }, // 4A
|
||||
{ 0x46, 0x6E, 0x76, 0x7E }, // 4C
|
||||
{ 0x47, 0x6F, 0x77, 0x7F }, // 4E
|
||||
{ 0x40, 0x40, 0x48, 0x50 }, // 50
|
||||
{ 0x41, 0x41, 0x49, 0x51 }, // 52
|
||||
{ 0x42, 0x42, 0x4A, 0x52 }, // 54
|
||||
{ 0x43, 0x43, 0x4B, 0x53 }, // 56
|
||||
{ 0x44, 0x44, 0x4C, 0x54 }, // 58
|
||||
{ 0x45, 0x45, 0x4D, 0x55 }, // 5A
|
||||
{ 0x46, 0x46, 0x4E, 0x56 }, // 5C
|
||||
{ 0x47, 0x47, 0x4F, 0x57 }, // 5E
|
||||
{ 0x40, 0x58, 0x60, 0x68 }, // 60
|
||||
{ 0x41, 0x59, 0x61, 0x69 }, // 62
|
||||
{ 0x42, 0x5A, 0x62, 0x6A }, // 64
|
||||
{ 0x43, 0x5B, 0x63, 0x6B }, // 66
|
||||
{ 0x44, 0x5C, 0x64, 0x6C }, // 68
|
||||
{ 0x45, 0x5D, 0x65, 0x6D }, // 6A
|
||||
{ 0x46, 0x5E, 0x66, 0x6E }, // 6C
|
||||
{ 0x47, 0x5F, 0x67, 0x6F }, // 6E
|
||||
{ 0x40, 0x70, 0x78, 0x74 }, // 70
|
||||
{ 0x41, 0x71, 0x79, 0x75 }, // 72
|
||||
{ 0x42, 0x72, 0x7A, 0x76 }, // 74
|
||||
{ 0x43, 0x73, 0x7B, 0x77 }, // 76
|
||||
{ 0x44, 0x74, 0x7C, 0x74 }, // 78
|
||||
{ 0x45, 0x75, 0x7D, 0x75 }, // 7A
|
||||
{ 0x46, 0x76, 0x7E, 0x76 }, // 7C
|
||||
{ 0x47, 0x77, 0x7F, 0x77 }, // 7E
|
||||
};
|
||||
*/
|
||||
|
||||
static uint8 regs[16];
|
||||
//static uint8 test[8];
|
||||
static SFORMAT StateRegs[] =
|
||||
{
|
||||
{ &IRQCount, 1, "IRQC" },
|
||||
@ -48,93 +141,68 @@ static SFORMAT StateRegs[] =
|
||||
|
||||
static void chrSync(void) {
|
||||
setchr4r(0x10, 0x0000, regs[5] & 1);
|
||||
setchr4r(0x10, 0x1000, 0);
|
||||
// 30.06.19 CaH4e3 there is much more complicated behaviour with second banking register, you may actually
|
||||
// view the content of the internal character CHR rom via this window, but it is useless because hardware
|
||||
// does not use this area to access the internal ROM. not sure why they did this, but I see no need to
|
||||
// emulate this behaviour carefully, unless I find something that I missed...
|
||||
setchr4r(0x10, 0x1000, 1);
|
||||
}
|
||||
|
||||
static void Sync(void) {
|
||||
chrSync();
|
||||
// if(regs[0xA]&0x10)
|
||||
// {
|
||||
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0);
|
||||
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1);
|
||||
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2);
|
||||
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3);
|
||||
setchr1r(0x10,0x1000,0);
|
||||
setchr1r(0x10,0x1400,1);
|
||||
setchr1r(0x10,0x1800,2);
|
||||
setchr1r(0x10,0x1c00,3);*/
|
||||
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0);
|
||||
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1);
|
||||
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2);
|
||||
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3);
|
||||
setchr1r(0x10,0x1000,(((regs[5]&1)^1)<<2)+4);
|
||||
setchr1r(0x10,0x1400,(((regs[5]&1)^1)<<2)+5);
|
||||
setchr1r(0x10,0x1800,(((regs[5]&1)^1)<<2)+6);
|
||||
setchr1r(0x10,0x1c00,(((regs[5]&1)^1)<<2)+7);
|
||||
*/
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
/*
|
||||
setchr1r(0x10,0x0000,(((regs[5]&1)^1)<<2)+0);
|
||||
setchr1r(0x10,0x0400,(((regs[5]&1)^1)<<2)+1);
|
||||
setchr1r(0x10,0x0800,(((regs[5]&1)^1)<<2)+2);
|
||||
setchr1r(0x10,0x0c00,(((regs[5]&1)^1)<<2)+3);
|
||||
setchr1r(0x10,0x1000,(((regs[5]&1))<<2)+4);
|
||||
setchr1r(0x10,0x1400,(((regs[5]&1))<<2)+5);
|
||||
setchr1r(0x10,0x1800,(((regs[5]&1))<<2)+6);
|
||||
setchr1r(0x10,0x1c00,(((regs[5]&1))<<2)+7);
|
||||
// }
|
||||
//*/
|
||||
/* setchr1r(1,0x0000,test[0]);
|
||||
setchr1r(1,0x0400,test[1]);
|
||||
setchr1r(1,0x0800,test[2]);
|
||||
setchr1r(1,0x0c00,test[3]);
|
||||
setchr1r(1,0x1000,test[4]);
|
||||
setchr1r(1,0x1400,test[5]);
|
||||
setchr1r(1,0x1800,test[6]);
|
||||
setchr1r(1,0x1c00,test[7]);
|
||||
*/
|
||||
setprg4r(0x10, 0x6000, regs[0] & 1);
|
||||
if (regs[2] >= 0x40)
|
||||
setprg8r(1, 0x8000, (regs[2] - 0x40));
|
||||
else
|
||||
setprg8r(0, 0x8000, (regs[2] & 0x3F));
|
||||
if (regs[3] >= 0x40)
|
||||
setprg8r(1, 0xA000, (regs[3] - 0x40));
|
||||
else
|
||||
setprg8r(0, 0xA000, (regs[3] & 0x3F));
|
||||
if (regs[4] >= 0x40)
|
||||
setprg8r(1, 0xC000, (regs[4] - 0x40));
|
||||
else
|
||||
setprg8r(0, 0xC000, (regs[4] & 0x3F));
|
||||
|
||||
setprg8r(1, 0xE000, ~0);
|
||||
setmirror(MI_V);
|
||||
setprg4r(0x10, 0x6000, (regs[0] & 1) | (regs[0] >> 2)); // two 4K banks are identical, either internal or excernal
|
||||
setprg4r(0x10, 0x7000, (regs[1] & 1) | (regs[1] >> 2)); // SRAMs may be mapped in any bank independently
|
||||
if (PRGptr[1] == NULL) { // for iNES 2.0 version it even more hacky lol
|
||||
setprg8(0x8000, (regs[2] & 0x3F) + ((regs[2] & 0x40) >> 2));
|
||||
setprg8(0xA000, (regs[3] & 0x3F) + ((regs[3] & 0x40) >> 2));
|
||||
setprg8(0xC000, (regs[4] & 0x3F) + ((regs[4] & 0x40) >> 2));
|
||||
setprg8(0xE000, 0x10 + 0x3F);
|
||||
} else {
|
||||
setprg8r((regs[2] >> 6) & 1, 0x8000, (regs[2] & 0x3F));
|
||||
setprg8r((regs[3] >> 6) & 1, 0xA000, (regs[3] & 0x3F));
|
||||
setprg8r((regs[4] >> 6) & 1, 0xC000, (regs[4] & 0x3F));
|
||||
setprg8r(1, 0xE000, ~0); // always sees the last bank of the external cart, so can't be booted without it.
|
||||
}
|
||||
setmirror(((regs[0xA]&2)>>1)^1);
|
||||
}
|
||||
|
||||
/*static DECLFW(TestWrite)
|
||||
{
|
||||
test[A&7] = V;
|
||||
Sync();
|
||||
}*/
|
||||
|
||||
static DECLFW(M190Write) {
|
||||
// FCEU_printf("write %04x:%04x %d, %d\n",A,V,scanline,timestamp);
|
||||
regs[(A & 0x0F00) >> 8] = V;
|
||||
static DECLFW(QTAiWrite) {
|
||||
regs[(A & 0x0F00) >> 8] = V; // IRQ pretty the same as in other VRC mappers by Konami
|
||||
switch (A) {
|
||||
case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break;
|
||||
case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; break;
|
||||
case 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break;
|
||||
case 0xd800: IRQa = K4IRQ; X6502_IRQEnd(FCEU_IQEXT); break;
|
||||
case 0xda00: qtaintramreg = regs[0xA] & 3; break; // register shadow to share it with ppu
|
||||
}
|
||||
Sync();
|
||||
}
|
||||
|
||||
static DECLFR(M190Read) {
|
||||
// FCEU_printf("read %04x:%04x %d, %d\n",A,regs[(A&0x0F00)>>8],scanline,timestamp);
|
||||
return regs[(A & 0x0F00) >> 8] + regs[0x0B];
|
||||
static DECLFR(QTAiRead) {
|
||||
|
||||
// uint8 res1 = conv_tbl[(regs[0xD] & 0x7F) >> 1][(regs[0xC] >> 5) & 3];
|
||||
// uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3);
|
||||
|
||||
uint8 tabl = conv_tbl[(regs[0xC] >> 5) & 3][(regs[0xD] & 0x7F) >> 4];
|
||||
uint8 res1 = 0x40 | (tabl & 0x3F) | ((regs[0xD] >> 1) & 7) | ((regs[0xB] & 4) << 5);
|
||||
uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3);
|
||||
|
||||
if (tabl & 0x40)
|
||||
res1 &= 0xFB;
|
||||
else if (tabl & 0x80)
|
||||
res1 |= 0x04;
|
||||
|
||||
if (A == 0xDD00) {
|
||||
return res1;
|
||||
} else if (A == 0xDC00) {
|
||||
#ifdef CAI_DEBUG
|
||||
FCEU_printf("%02x:%02x+%d -> %02x:%02x\n", regs[0xD], regs[0xC], regs[0xB], res1, res2);
|
||||
#endif
|
||||
return res2;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void VRC5IRQ(int a) {
|
||||
if (IRQa) {
|
||||
IRQCount += a;
|
||||
@ -145,50 +213,17 @@ static void VRC5IRQ(int a) {
|
||||
}
|
||||
}
|
||||
|
||||
//static void Mapper190_PPU(uint32 A)
|
||||
//{
|
||||
// if(A<0x2000)
|
||||
// setchr4r(0x10,0x1000,QTAINTRAM[A&0x1FFF]&1);
|
||||
// else
|
||||
// chrSync();
|
||||
//}
|
||||
|
||||
static DECLFW(M1902007Wrap) {
|
||||
if (A >= 0x2000) {
|
||||
if (regs[0xA] & 1)
|
||||
QTAINTRAM[A & 0x1FFF] = V;
|
||||
else
|
||||
old2007wrap(A, V);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void M190Power(void) {
|
||||
/* test[0]=0;
|
||||
test[1]=1;
|
||||
test[2]=2;
|
||||
test[3]=3;
|
||||
test[4]=4;
|
||||
test[5]=5;
|
||||
test[6]=6;
|
||||
test[7]=7;
|
||||
*/
|
||||
setprg4r(0x10, 0x7000, 2);
|
||||
|
||||
old2007wrap = GetWriteHandler(0x2007);
|
||||
SetWriteHandler(0x2007, 0x2007, M1902007Wrap);
|
||||
|
||||
static void QTAiPower(void) {
|
||||
SetReadHandler(0x6000, 0xFFFF, CartBR);
|
||||
// SetWriteHandler(0x5000,0x5007,TestWrite);
|
||||
SetWriteHandler(0x6000, 0x7FFF, CartBW);
|
||||
SetWriteHandler(0x8000, 0xFFFF, M190Write);
|
||||
SetReadHandler(0xDC00, 0xDC00, M190Read);
|
||||
SetReadHandler(0xDD00, 0xDD00, M190Read);
|
||||
SetWriteHandler(0x8000, 0xFFFF, QTAiWrite);
|
||||
SetReadHandler(0xDC00, 0xDC00, QTAiRead);
|
||||
SetReadHandler(0xDD00, 0xDD00, QTAiRead);
|
||||
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
|
||||
Sync();
|
||||
}
|
||||
|
||||
static void M190Close(void) {
|
||||
static void QTAiClose(void) {
|
||||
if (CHRRAM)
|
||||
FCEU_gfree(CHRRAM);
|
||||
CHRRAM = NULL;
|
||||
@ -200,3 +235,31 @@ static void M190Close(void) {
|
||||
static void StateRestore(int version) {
|
||||
Sync();
|
||||
}
|
||||
|
||||
void QTAi_Init(CartInfo *info) {
|
||||
QTAIHack = 1;
|
||||
|
||||
info->Power = QTAiPower;
|
||||
info->Close = QTAiClose;
|
||||
GameStateRestore = StateRestore;
|
||||
|
||||
MapIRQHook = VRC5IRQ;
|
||||
|
||||
CHRRAM = (uint8*)FCEU_gmalloc(CHRSIZE);
|
||||
SetupCartCHRMapping(0x10, CHRRAM, CHRSIZE, 1);
|
||||
AddExState(CHRRAM, CHRSIZE, 0, "CRAM");
|
||||
|
||||
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
|
||||
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
|
||||
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
|
||||
|
||||
if (info->battery) {
|
||||
info->SaveGame[0] = WRAM;
|
||||
// note, only extrnal cart's SRAM is battery backed, the the part on the main cartridge is just
|
||||
// an additional work ram. so we may save only half here, but I forgot what part is saved lol, will
|
||||
// find out later.
|
||||
info->SaveGameLen[0] = WRAMSIZE;
|
||||
}
|
||||
|
||||
AddExState(&StateRegs, ~0, 0, 0);
|
||||
}
|
||||
|
@ -132,6 +132,11 @@ void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram) {
|
||||
CHRmask4[chip] = (size >> 12) - 1;
|
||||
CHRmask8[chip] = (size >> 13) - 1;
|
||||
|
||||
if (CHRmask1[chip] >= (unsigned int)(-1)) CHRmask1[chip] = 0;
|
||||
if (CHRmask2[chip] >= (unsigned int)(-1)) CHRmask2[chip] = 0;
|
||||
if (CHRmask4[chip] >= (unsigned int)(-1)) CHRmask4[chip] = 0;
|
||||
if (CHRmask8[chip] >= (unsigned int)(-1)) CHRmask8[chip] = 0;
|
||||
|
||||
CHRram[chip] = ram;
|
||||
}
|
||||
|
||||
@ -242,7 +247,7 @@ void setchr2r(int r, uint32 A, uint32 V) {
|
||||
PPUCHRRAM &= ~(3 << (A >> 10));
|
||||
}
|
||||
|
||||
void setchr4r(int r, uint32 A, uint32 V) {
|
||||
void setchr4r(int r, unsigned int A, unsigned int V) {
|
||||
if (!CHRptr[r]) return;
|
||||
FCEUPPU_LineUpdate();
|
||||
V &= CHRmask4[r];
|
||||
|
@ -1,3 +1,6 @@
|
||||
#ifndef CART_H
|
||||
#define CART_H
|
||||
|
||||
typedef struct {
|
||||
// Set by mapper/board code:
|
||||
void (*Power)(void);
|
||||
@ -68,21 +71,21 @@ void setprg8(uint32 A, uint32 V);
|
||||
void setprg16(uint32 A, uint32 V);
|
||||
void setprg32(uint32 A, uint32 V);
|
||||
|
||||
void setprg2r(int r, uint32 A, uint32 V);
|
||||
void setprg4r(int r, uint32 A, uint32 V);
|
||||
void setprg8r(int r, uint32 A, uint32 V);
|
||||
void setprg16r(int r, uint32 A, uint32 V);
|
||||
void setprg32r(int r, uint32 A, uint32 V);
|
||||
void setprg2r(int r, unsigned int A, unsigned int V);
|
||||
void setprg4r(int r, unsigned int A, unsigned int V);
|
||||
void setprg8r(int r, unsigned int A, unsigned int V);
|
||||
void setprg16r(int r, unsigned int A, unsigned int V);
|
||||
void setprg32r(int r, unsigned int A, unsigned int V);
|
||||
|
||||
void setchr1r(int r, uint32 A, uint32 V);
|
||||
void setchr2r(int r, uint32 A, uint32 V);
|
||||
void setchr4r(int r, uint32 A, uint32 V);
|
||||
void setchr8r(int r, uint32 V);
|
||||
void setchr1r(int r, unsigned int A, unsigned int V);
|
||||
void setchr2r(int r, unsigned int A, unsigned int V);
|
||||
void setchr4r(int r, unsigned int A, unsigned int V);
|
||||
void setchr8r(int r, unsigned int V);
|
||||
|
||||
void setchr1(uint32 A, uint32 V);
|
||||
void setchr2(uint32 A, uint32 V);
|
||||
void setchr4(uint32 A, uint32 V);
|
||||
void setchr8(uint32 V);
|
||||
void setchr1(unsigned int A, unsigned int V);
|
||||
void setchr2(unsigned int A, unsigned int V);
|
||||
void setchr4(unsigned int A, unsigned int V);
|
||||
void setchr8(unsigned int V);
|
||||
|
||||
void setmirror(int t);
|
||||
void setmirrorw(int a, int b, int c, int d);
|
||||
@ -100,3 +103,5 @@ void FCEU_GeniePower(void);
|
||||
bool FCEU_OpenGenie(void);
|
||||
void FCEU_CloseGenie(void);
|
||||
void FCEU_KillGenie(void);
|
||||
|
||||
#endif
|
||||
|
@ -39,8 +39,7 @@ using namespace std;
|
||||
static uint8 *CheatRPtrs[64];
|
||||
|
||||
vector<uint16> FrozenAddresses; //List of addresses that are currently frozen
|
||||
void UpdateFrozenList(void); //Function that populates the list of frozen addresses
|
||||
unsigned int FrozenAddressCount=0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor)
|
||||
unsigned int FrozenAddressCount = 0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor)
|
||||
|
||||
void FCEU_CheatResetRAM(void)
|
||||
{
|
||||
@ -60,27 +59,13 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
|
||||
}
|
||||
|
||||
|
||||
struct CHEATF {
|
||||
struct CHEATF *next;
|
||||
char *name;
|
||||
uint16 addr;
|
||||
uint8 val;
|
||||
int compare; /* -1 for no compare. */
|
||||
int type; /* 0 for replace, 1 for substitute(GG). */
|
||||
int status;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint16 addr;
|
||||
uint8 val;
|
||||
int compare;
|
||||
readfunc PrevRead;
|
||||
} CHEATF_SUBFAST;
|
||||
|
||||
|
||||
static CHEATF_SUBFAST SubCheats[256];
|
||||
static int numsubcheats=0;
|
||||
struct CHEATF *cheats=0,*cheatsl=0;
|
||||
CHEATF_SUBFAST SubCheats[256] = { 0 };
|
||||
uint32 numsubcheats = 0;
|
||||
int globalCheatDisabled = 0;
|
||||
int disableAutoLSCheats = 0;
|
||||
bool disableShowGG = 0;
|
||||
static _8BYTECHEATMAP* cheatMap = NULL;
|
||||
struct CHEATF *cheats = 0, *cheatsl = 0;
|
||||
|
||||
|
||||
#define CHEATC_NONE 0x8000
|
||||
@ -92,7 +77,7 @@ int savecheats = 0;
|
||||
|
||||
static DECLFR(SubCheatsRead)
|
||||
{
|
||||
CHEATF_SUBFAST *s=SubCheats;
|
||||
CHEATF_SUBFAST *s = SubCheats;
|
||||
int x=numsubcheats;
|
||||
|
||||
do
|
||||
@ -116,79 +101,97 @@ static DECLFR(SubCheatsRead)
|
||||
|
||||
void RebuildSubCheats(void)
|
||||
{
|
||||
int x;
|
||||
struct CHEATF *c=cheats;
|
||||
for(x=0;x<numsubcheats;x++)
|
||||
SetReadHandler(SubCheats[x].addr,SubCheats[x].addr,SubCheats[x].PrevRead);
|
||||
|
||||
numsubcheats=0;
|
||||
while(c)
|
||||
uint32 x;
|
||||
struct CHEATF *c = cheats;
|
||||
for (x = 0; x < numsubcheats; x++)
|
||||
{
|
||||
if(c->type==1 && c->status)
|
||||
SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead);
|
||||
if (cheatMap)
|
||||
FCEUI_SetCheatMapByte(SubCheats[x].addr, false);
|
||||
}
|
||||
|
||||
numsubcheats = 0;
|
||||
|
||||
if (!globalCheatDisabled)
|
||||
{
|
||||
while(c)
|
||||
{
|
||||
if(GetReadHandler(c->addr)==SubCheatsRead)
|
||||
if(c->type == 1 && c->status && GetReadHandler(c->addr) != SubCheatsRead)
|
||||
{
|
||||
/* Prevent a catastrophe by this check. */
|
||||
//FCEU_DispMessage("oops",0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr);
|
||||
SubCheats[numsubcheats].addr=c->addr;
|
||||
SubCheats[numsubcheats].val=c->val;
|
||||
SubCheats[numsubcheats].compare=c->compare;
|
||||
SetReadHandler(c->addr,c->addr,SubCheatsRead);
|
||||
SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr);
|
||||
SubCheats[numsubcheats].addr = c->addr;
|
||||
SubCheats[numsubcheats].val = c->val;
|
||||
SubCheats[numsubcheats].compare = c->compare;
|
||||
SetReadHandler(c->addr, c->addr, SubCheatsRead);
|
||||
if (cheatMap)
|
||||
FCEUI_SetCheatMapByte(SubCheats[numsubcheats].addr, true);
|
||||
numsubcheats++;
|
||||
}
|
||||
c = c->next;
|
||||
}
|
||||
c=c->next;
|
||||
}
|
||||
FrozenAddressCount = numsubcheats; //Update the frozen address list
|
||||
UpdateFrozenList();
|
||||
//FCEUI_DispMessage("Active Cheats: %d",0, FrozenAddresses.size()/*FrozenAddressCount*/); //Debug
|
||||
|
||||
}
|
||||
|
||||
void FCEU_PowerCheats()
|
||||
{
|
||||
numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */
|
||||
numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */
|
||||
if (cheatMap)
|
||||
FCEUI_RefreshCheatMap();
|
||||
RebuildSubCheats();
|
||||
}
|
||||
|
||||
int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type);
|
||||
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size) {
|
||||
|
||||
uint32 count = 0;
|
||||
if (cheatMap)
|
||||
for (uint32 i = 0; i < size; ++i)
|
||||
if (FCEUI_FindCheatMapByte(address + i))
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
static void CheatMemErr(void)
|
||||
{
|
||||
FCEUD_PrintError("Error allocating memory for cheat data.");
|
||||
}
|
||||
|
||||
/* This function doesn't allocate any memory for "name" */
|
||||
int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type)
|
||||
int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
|
||||
{
|
||||
struct CHEATF *temp;
|
||||
if(!(temp=(struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF))))
|
||||
if(!(temp = (struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF))))
|
||||
{
|
||||
CheatMemErr();
|
||||
return(0);
|
||||
}
|
||||
temp->name=name;
|
||||
temp->addr=addr;
|
||||
temp->val=val;
|
||||
temp->status=status;
|
||||
temp->compare=compare;
|
||||
temp->type=type;
|
||||
temp->next=0;
|
||||
|
||||
temp->name = strcpy((char*) FCEU_dmalloc(strlen(name) + 1), name);
|
||||
temp->addr = addr;
|
||||
temp->val = val;
|
||||
temp->status = status;
|
||||
temp->compare = compare;
|
||||
temp->type = type;
|
||||
temp->next = 0;
|
||||
|
||||
if(cheats)
|
||||
{
|
||||
cheatsl->next=temp;
|
||||
cheatsl=temp;
|
||||
cheatsl->next = temp;
|
||||
cheatsl = temp;
|
||||
}
|
||||
else
|
||||
cheats=cheatsl=temp;
|
||||
cheats = cheatsl = temp;
|
||||
|
||||
return(1);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void FCEU_LoadGameCheats(FILE *override)
|
||||
/* The "override_existing" parameter is used only in cheat dialog import.
|
||||
Since the default behaviour will reset numsubcheats to 0 everytime,
|
||||
In game loading, this is absolutely right, but when importing in cheat window,
|
||||
resetting numsubcheats to 0 will override existed cheat items to make them
|
||||
invalid.
|
||||
*/
|
||||
void FCEU_LoadGameCheats(FILE *override, int override_existing)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned int addr;
|
||||
@ -198,89 +201,121 @@ void FCEU_LoadGameCheats(FILE *override)
|
||||
unsigned int compare;
|
||||
int x;
|
||||
|
||||
char linebuf[2048];
|
||||
char *namebuf;
|
||||
int tc=0;
|
||||
char linebuf[2048] = { 0 };
|
||||
char namebuf[128] = { 0 };
|
||||
int tc = 0;
|
||||
char *fn;
|
||||
|
||||
numsubcheats=savecheats=0;
|
||||
if (override_existing)
|
||||
{
|
||||
numsubcheats = 0;
|
||||
if (cheatMap)
|
||||
FCEUI_RefreshCheatMap();
|
||||
}
|
||||
|
||||
if(override)
|
||||
fp = override;
|
||||
else
|
||||
{
|
||||
fn=strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());
|
||||
fp=FCEUD_UTF8fopen(fn,"rb");
|
||||
fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT, 0, 0).c_str());
|
||||
fp = FCEUD_UTF8fopen(fn, "rb");
|
||||
free(fn);
|
||||
if(!fp) return;
|
||||
if (!fp) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FCEU_DispMessage("Cheats file loaded.",0); //Tells user a cheats file was loaded.
|
||||
while(fgets(linebuf,2048,fp) != nullptr)
|
||||
while(fgets(linebuf, 2048, fp) != nullptr)
|
||||
{
|
||||
char *tbuf=linebuf;
|
||||
int doc=0;
|
||||
char *tbuf = linebuf;
|
||||
int doc = 0;
|
||||
|
||||
addr=val=compare=status=type=0;
|
||||
addr = val = compare = status = type = 0;
|
||||
|
||||
if(tbuf[0]=='S')
|
||||
if(tbuf[0] == 'S')
|
||||
{
|
||||
tbuf++;
|
||||
type=1;
|
||||
type = 1;
|
||||
}
|
||||
else type=0;
|
||||
else
|
||||
type = 0;
|
||||
|
||||
if(tbuf[0]=='C')
|
||||
if(tbuf[0] == 'C')
|
||||
{
|
||||
tbuf++;
|
||||
doc=1;
|
||||
doc = 1;
|
||||
}
|
||||
|
||||
if(tbuf[0]==':')
|
||||
if(tbuf[0] == ':')
|
||||
{
|
||||
tbuf++;
|
||||
status=0;
|
||||
status = 0;
|
||||
}
|
||||
else status=1;
|
||||
else status = 1;
|
||||
|
||||
if(doc)
|
||||
{
|
||||
char *neo=&tbuf[4+2+2+1+1+1];
|
||||
if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3)
|
||||
char *neo = &tbuf[4+2+2+1+1+1];
|
||||
if(sscanf(tbuf, "%04x%*[:]%02x%*[:]%02x", &addr, &val, &compare) != 3)
|
||||
continue;
|
||||
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1)))
|
||||
return;
|
||||
strcpy(namebuf,neo);
|
||||
strcpy(namebuf, neo);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *neo=&tbuf[4+2+1+1];
|
||||
if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2)
|
||||
char *neo = &tbuf[4+2+1+1];
|
||||
if(sscanf(tbuf, "%04x%*[:]%02x", &addr, &val) != 2)
|
||||
continue;
|
||||
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1)))
|
||||
return;
|
||||
strcpy(namebuf,neo);
|
||||
strcpy(namebuf, neo);
|
||||
}
|
||||
|
||||
for(x=0;x<(int)strlen(namebuf);x++)
|
||||
for(x = 0; x < (int)strlen(namebuf); x++)
|
||||
{
|
||||
if(namebuf[x]==10 || namebuf[x]==13)
|
||||
if(namebuf[x] == 10 || namebuf[x] == 13)
|
||||
{
|
||||
namebuf[x]=0;
|
||||
namebuf[x] = 0;
|
||||
break;
|
||||
}
|
||||
else if(namebuf[x] > 0x00 && namebuf[x] < 0x20)
|
||||
namebuf[x]=0x20;
|
||||
namebuf[x] = 0x20;
|
||||
}
|
||||
|
||||
AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type);
|
||||
AddCheatEntry(namebuf, addr, val, doc ? compare : -1, status, type);
|
||||
tc++;
|
||||
}
|
||||
|
||||
RebuildSubCheats();
|
||||
|
||||
FCEU_DispMessage("Cheats file loaded.", 0); //Tells user a cheats file was loaded.
|
||||
|
||||
if(!override)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void FCEU_SaveGameCheats(FILE* fp, int release)
|
||||
{
|
||||
struct CHEATF *next = cheats;
|
||||
while (next)
|
||||
{
|
||||
if (next->type)
|
||||
fputc('S', fp);
|
||||
if (next->compare >= 0)
|
||||
fputc('C', fp);
|
||||
|
||||
if (!next->status)
|
||||
fputc(':', fp);
|
||||
|
||||
if (next->compare >= 0)
|
||||
fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name);
|
||||
else
|
||||
fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name);
|
||||
|
||||
if (release) free(next->name);
|
||||
struct CHEATF *t = next;
|
||||
next = next->next;
|
||||
if (release) free(t);
|
||||
}
|
||||
}
|
||||
|
||||
void FCEU_FlushGameCheats(FILE *override, int nosave)
|
||||
{
|
||||
if(CheatComp)
|
||||
@ -313,7 +348,6 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
|
||||
|
||||
if(cheats)
|
||||
{
|
||||
struct CHEATF *next=cheats;
|
||||
FILE *fp;
|
||||
|
||||
if(override)
|
||||
@ -323,28 +357,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
|
||||
|
||||
if(fp)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
struct CHEATF *t;
|
||||
if(next->type)
|
||||
fputc('S',fp);
|
||||
if(next->compare>=0)
|
||||
fputc('C',fp);
|
||||
|
||||
if(!next->status)
|
||||
fputc(':',fp);
|
||||
|
||||
if(next->compare>=0)
|
||||
fprintf(fp,"%04x:%02x:%02x:%s\n",next->addr,next->val,next->compare,next->name);
|
||||
else
|
||||
fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name);
|
||||
|
||||
free(next->name);
|
||||
t=next;
|
||||
next=next->next;
|
||||
free(t);
|
||||
if(!next) break;
|
||||
}
|
||||
FCEU_SaveGameCheats(fp, 1);
|
||||
if(!override)
|
||||
fclose(fp);
|
||||
}
|
||||
@ -365,23 +378,13 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
|
||||
|
||||
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
|
||||
{
|
||||
char *t;
|
||||
|
||||
if(!(t=(char *)FCEU_dmalloc(strlen(name)+1)))
|
||||
{
|
||||
CheatMemErr();
|
||||
return(0);
|
||||
}
|
||||
strcpy(t,name);
|
||||
if(!AddCheatEntry(t,addr,val,compare,1,type))
|
||||
{
|
||||
free(t);
|
||||
return(0);
|
||||
}
|
||||
savecheats=1;
|
||||
if(!AddCheatEntry(name, addr, val, compare, 1, type))
|
||||
return 0;
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
|
||||
return(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FCEUI_DelCheat(uint32 which)
|
||||
@ -566,7 +569,7 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c)
|
||||
|
||||
int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type)
|
||||
{
|
||||
int boo[4];
|
||||
unsigned int boo[4];
|
||||
if(strlen(str)!=8) return(0);
|
||||
|
||||
sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3);
|
||||
@ -598,43 +601,40 @@ int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type)
|
||||
|
||||
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int s, int type)
|
||||
{
|
||||
struct CHEATF *next=cheats;
|
||||
uint32 x=0;
|
||||
struct CHEATF *next = cheats;
|
||||
uint32 x = 0;
|
||||
|
||||
while(next)
|
||||
{
|
||||
if(x==which)
|
||||
if(x == which)
|
||||
{
|
||||
if(name)
|
||||
{
|
||||
char *t;
|
||||
if((t=(char *)realloc(next->name, strlen(name)+1)))
|
||||
{
|
||||
next->name=t;
|
||||
strcpy(next->name,name);
|
||||
}
|
||||
if((t = (char *)realloc(next->name, strlen(name) + 1)))
|
||||
strcpy(next->name = t, name);
|
||||
else
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
if(a>=0)
|
||||
next->addr=a;
|
||||
if(v>=0)
|
||||
next->val=v;
|
||||
if(s>=0)
|
||||
next->status=s;
|
||||
if(c>=-1)
|
||||
next->compare=c;
|
||||
next->type=type;
|
||||
if(a >= 0)
|
||||
next->addr = a;
|
||||
if(v >= 0)
|
||||
next->val = v;
|
||||
if(s >= 0)
|
||||
next->status = s;
|
||||
if(c >= -1)
|
||||
next->compare = c;
|
||||
next->type = type;
|
||||
|
||||
savecheats=1;
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
|
||||
return(1);
|
||||
return 1;
|
||||
}
|
||||
next=next->next;
|
||||
next = next->next;
|
||||
x++;
|
||||
}
|
||||
return(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convenience function. */
|
||||
@ -659,6 +659,14 @@ int FCEUI_ToggleCheat(uint32 which)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int FCEUI_GlobalToggleCheat(int global_enabled)
|
||||
{
|
||||
int _numsubcheats = numsubcheats;
|
||||
globalCheatDisabled = !global_enabled;
|
||||
RebuildSubCheats();
|
||||
return _numsubcheats != numsubcheats;
|
||||
}
|
||||
|
||||
static int InitCheatComp(void)
|
||||
{
|
||||
uint32 x;
|
||||
@ -741,7 +749,7 @@ void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void
|
||||
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current))
|
||||
{
|
||||
uint32 x;
|
||||
uint32 in=0;
|
||||
uint32 in = 0;
|
||||
|
||||
if(!CheatComp)
|
||||
{
|
||||
@ -750,14 +758,15 @@ void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a,
|
||||
return;
|
||||
}
|
||||
|
||||
for(x=0;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10])
|
||||
for(x = 0; x < 0x10000; x++)
|
||||
if(!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
|
||||
{
|
||||
if(in>=first)
|
||||
if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x]))
|
||||
if(in >= first)
|
||||
if(!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x]))
|
||||
break;
|
||||
in++;
|
||||
if(in>last) return;
|
||||
if(in > last)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -803,130 +812,56 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!type) // Change to a specific value.
|
||||
switch (type)
|
||||
{
|
||||
for(x=0;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
default:
|
||||
case FCEU_SEARCH_SPECIFIC_CHANGE: // Change to a specific value
|
||||
for (x = 0; x < 0x10000; ++x)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CheatRPtrs[x >> 10][x] != v2))
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_RELATIVE_CHANGE: // Search for relative change (between values).
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2))
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_PUERLY_RELATIVE_CHANGE: // Purely relative change.
|
||||
for (x = 0x000; x<0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2)
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_ANY_CHANGE: // Any change.
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] == CheatRPtrs[x >> 10][x])
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_NEWVAL_KNOWN: // new value = known
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] != v1)
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_NEWVAL_GT: // new value greater than
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] >= CheatRPtrs[x >> 10][x])
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_NEWVAL_LT: // new value less than
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] <= CheatRPtrs[x >> 10][x])
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_NEWVAL_GT_KNOWN: // new value greater than by known value
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] - CheatComp[x] != v2)
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
case FCEU_SEARCH_NEWVAL_LT_KNOWN: // new value less than by known value
|
||||
for (x = 0x000; x < 0x10000; x++)
|
||||
if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2)
|
||||
CheatComp[x] |= CHEATC_EXCLUDED;
|
||||
break;
|
||||
}
|
||||
else if(type==1) // Search for relative change(between values).
|
||||
{
|
||||
for(x=0;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
}
|
||||
else if(type==2) // Purely relative change.
|
||||
{
|
||||
for(x=0x000;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
}
|
||||
else if(type==3) // Any change.
|
||||
{
|
||||
for(x=0x000;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if(CheatComp[x]!=CheatRPtrs[x>>10][x])
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
|
||||
}
|
||||
else if(type==4) // new value = known
|
||||
{
|
||||
for(x=0x000;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if(CheatRPtrs[x>>10][x]==v1)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
|
||||
}
|
||||
else if(type==5) // new value greater than
|
||||
{
|
||||
for(x=0x000;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if(CheatComp[x]<CheatRPtrs[x>>10][x])
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
|
||||
}
|
||||
else if(type==6) // new value less than
|
||||
{
|
||||
for(x=0x000;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if(CheatComp[x]>CheatRPtrs[x>>10][x])
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
|
||||
}
|
||||
else if(type==7) // new value greater than by known value
|
||||
{
|
||||
for(x=0x000;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if((CheatRPtrs[x>>10][x]-CheatComp[x])==v2)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
|
||||
}
|
||||
else if(type==8) // new value less than by known value
|
||||
{
|
||||
for(x=0x000;x<0x10000;x++)
|
||||
if(!(CheatComp[x]&CHEATC_NOSHOW))
|
||||
{
|
||||
if((CheatComp[x]-CheatRPtrs[x>>10][x])==v2)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
CheatComp[x]|=CHEATC_EXCLUDED;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int FCEU_CheatGetByte(uint32 A)
|
||||
@ -949,18 +884,75 @@ void FCEU_CheatSetByte(uint32 A, uint8 V)
|
||||
BWrite[A](A, V);
|
||||
}
|
||||
|
||||
void UpdateFrozenList(void)
|
||||
// disable all cheats
|
||||
int FCEU_DisableAllCheats(void)
|
||||
{
|
||||
//The purpose of this function is to keep an up to date list of addresses that are currently frozen
|
||||
//and make these accessible to other dialogs that deal with memory addresses such as
|
||||
//memwatch, hex editor, ramfilter, etc.
|
||||
|
||||
int x;
|
||||
FrozenAddresses.clear(); //Clear vector and repopulate
|
||||
for(x=0;x<numsubcheats;x++)
|
||||
int count = 0;
|
||||
struct CHEATF *next = cheats;
|
||||
while(next)
|
||||
{
|
||||
FrozenAddresses.push_back(SubCheats[x].addr);
|
||||
//FCEU_printf("Address %d: %d \n",x,FrozenAddresses[x]); //Debug
|
||||
if(next->status){
|
||||
count++;
|
||||
}
|
||||
next->status = 0;
|
||||
next = next->next;
|
||||
}
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
return count;
|
||||
}
|
||||
|
||||
// delete all cheats
|
||||
int FCEU_DeleteAllCheats(void)
|
||||
{
|
||||
struct CHEATF *cur = cheats;
|
||||
struct CHEATF *next = NULL;
|
||||
while (cur)
|
||||
{
|
||||
next = cur->next;
|
||||
if ( cur->name )
|
||||
{
|
||||
free(cur->name);
|
||||
}
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
cheats = cheatsl = 0;
|
||||
savecheats = 1;
|
||||
RebuildSubCheats();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FCEUI_FindCheatMapByte(uint16 address)
|
||||
{
|
||||
return cheatMap[address / 8] >> (address % 8) & 1;
|
||||
}
|
||||
|
||||
void FCEUI_SetCheatMapByte(uint16 address, bool cheat)
|
||||
{
|
||||
cheat ? cheatMap[address / 8] |= (1 << address % 8) : cheatMap[address / 8] ^= (1 << address % 8);
|
||||
}
|
||||
|
||||
void FCEUI_CreateCheatMap(void)
|
||||
{
|
||||
if (!cheatMap)
|
||||
cheatMap = (unsigned char*)malloc(CHEATMAP_SIZE);
|
||||
FCEUI_RefreshCheatMap();
|
||||
}
|
||||
|
||||
void FCEUI_RefreshCheatMap(void)
|
||||
{
|
||||
memset(cheatMap, 0, CHEATMAP_SIZE);
|
||||
for (uint32 i = 0; i < numsubcheats; ++i)
|
||||
FCEUI_SetCheatMapByte(SubCheats[i].addr, true);
|
||||
}
|
||||
|
||||
void FCEUI_ReleaseCheatMap(void)
|
||||
{
|
||||
if (cheatMap)
|
||||
{
|
||||
free(cheatMap);
|
||||
cheatMap = NULL;
|
||||
}
|
||||
//FCEUI_DispMessage("FrozenCount: %d",0,FrozenAddressCount);//Debug
|
||||
}
|
||||
|
@ -1,12 +1,70 @@
|
||||
#ifndef CHEAT_H
|
||||
#define CHEAT_H
|
||||
void FCEU_CheatResetRAM(void);
|
||||
void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p);
|
||||
|
||||
void FCEU_LoadGameCheats(FILE *override);
|
||||
void FCEU_LoadGameCheats(FILE *override, int override_existing = 1);
|
||||
void FCEU_FlushGameCheats(FILE *override, int nosave);
|
||||
void FCEU_SaveGameCheats(FILE *fp, int release = 0);
|
||||
int FCEUI_GlobalToggleCheat(int global_enabled);
|
||||
void FCEU_ApplyPeriodicCheats(void);
|
||||
void FCEU_PowerCheats(void);
|
||||
int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size);
|
||||
|
||||
// Trying to find a more efficient way for determining if an address has a cheat
|
||||
// each bit of 1 byte represents to 8 bytes in NES
|
||||
typedef unsigned char _8BYTECHEATMAP;
|
||||
#define CHEATMAP_SIZE 0x10000 / 8
|
||||
|
||||
extern int FCEUI_FindCheatMapByte(uint16 address);
|
||||
extern void FCEUI_SetCheatMapByte(uint16 address, bool cheat);
|
||||
extern void FCEUI_CreateCheatMap(void);
|
||||
extern void FCEUI_RefreshCheatMap(void);
|
||||
extern void FCEUI_ReleaseCheatMap(void);
|
||||
extern unsigned int FrozenAddressCount;
|
||||
|
||||
int FCEU_CheatGetByte(uint32 A);
|
||||
void FCEU_CheatSetByte(uint32 A, uint8 V);
|
||||
|
||||
extern int savecheats;
|
||||
extern int globalCheatDisabled;
|
||||
extern int disableAutoLSCheats;
|
||||
|
||||
int FCEU_DisableAllCheats(void);
|
||||
int FCEU_DeleteAllCheats(void);
|
||||
|
||||
typedef struct {
|
||||
uint16 addr;
|
||||
uint8 val;
|
||||
int compare;
|
||||
readfunc PrevRead;
|
||||
} CHEATF_SUBFAST;
|
||||
|
||||
struct CHEATF {
|
||||
struct CHEATF *next;
|
||||
char *name;
|
||||
uint16 addr;
|
||||
uint8 val;
|
||||
int compare; /* -1 for no compare. */
|
||||
int type; /* 0 for replace, 1 for substitute(GG). */
|
||||
int status;
|
||||
};
|
||||
|
||||
struct SEARCHPOSSIBLE {
|
||||
uint16 addr;
|
||||
uint8 previous;
|
||||
uint8 current;
|
||||
bool update;
|
||||
};
|
||||
|
||||
#define FCEU_SEARCH_SPECIFIC_CHANGE 0
|
||||
#define FCEU_SEARCH_RELATIVE_CHANGE 1
|
||||
#define FCEU_SEARCH_PUERLY_RELATIVE_CHANGE 2
|
||||
#define FCEU_SEARCH_ANY_CHANGE 3
|
||||
#define FCEU_SEARCH_NEWVAL_KNOWN 4
|
||||
#define FCEU_SEARCH_NEWVAL_GT 5
|
||||
#define FCEU_SEARCH_NEWVAL_LT 6
|
||||
#define FCEU_SEARCH_NEWVAL_GT_KNOWN 7
|
||||
#define FCEU_SEARCH_NEWVAL_LT_KNOWN 8
|
||||
|
||||
#endif
|
||||
|
@ -194,10 +194,10 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP
|
||||
{
|
||||
scan(str);
|
||||
|
||||
c->lhs = Connect(str);
|
||||
|
||||
if (!c) return 0;
|
||||
|
||||
c->lhs = Connect(str);
|
||||
|
||||
if (next == closePar)
|
||||
{
|
||||
scan(str);
|
||||
@ -400,9 +400,12 @@ Condition* Term(const char** str)
|
||||
Condition* t1;
|
||||
Condition* mid;
|
||||
|
||||
t = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
||||
if (!t)
|
||||
return NULL;
|
||||
t = (Condition*)FCEU_dmalloc(sizeof(Condition));
|
||||
|
||||
if (!t)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(t, 0, sizeof(Condition));
|
||||
|
||||
|
@ -13,18 +13,23 @@
|
||||
|
||||
static char *aboutString = 0;
|
||||
|
||||
#ifndef FCEUX_BUILD_TIMESTAMP
|
||||
#define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__
|
||||
#endif
|
||||
|
||||
// returns a string suitable for use in an aboutbox
|
||||
char *FCEUI_GetAboutString() {
|
||||
const char *FCEUI_GetAboutString(void)
|
||||
{
|
||||
const char *aboutTemplate =
|
||||
FCEU_NAME_AND_VERSION "\n\n"
|
||||
"Administrators:\n"
|
||||
"zeromus, punkrockguy318 (Lukas Sabota), feos\n"
|
||||
"zeromus, feos\n"
|
||||
"\n"
|
||||
"Current Contributors:\n"
|
||||
"CaH4e3, rainwarrior\n"
|
||||
"CaH4e3, rainwarrior, owomomo, punkrockguy318\n"
|
||||
"\n"
|
||||
"Past Contributors:\n"
|
||||
"xhainingx, gocha, AnS\n"
|
||||
"xhainingx, gocha, AnS, mjbudd77\n"
|
||||
"\n"
|
||||
"FCEUX 2.0:\n"
|
||||
"mz, nitsujrehtona, SP, Ugly Joe,\n"
|
||||
@ -40,13 +45,17 @@ char *FCEUI_GetAboutString() {
|
||||
"FCEU TAS - blip & nitsuja\n"
|
||||
"FCEU TAS+ - Luke Gustafson\n"
|
||||
"\n"
|
||||
"Logo/icon:\n"
|
||||
"Terwilf\n"
|
||||
"\n"
|
||||
"FCEUX is dedicated to the fallen heroes\n"
|
||||
"of NES emulation. In Memoriam --\n"
|
||||
"ugetab\n"
|
||||
"\n"
|
||||
__TIME__ " " __DATE__ "\n";
|
||||
"\n"
|
||||
FCEUX_BUILD_TIMESTAMP "\n";
|
||||
|
||||
if(aboutString) return aboutString;
|
||||
if (aboutString) return aboutString;
|
||||
|
||||
const char *compilerString = FCEUD_GetCompilerString();
|
||||
|
||||
@ -54,6 +63,6 @@ char *FCEUI_GetAboutString() {
|
||||
if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1)))
|
||||
return NULL;
|
||||
|
||||
sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
|
||||
sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
|
||||
return aboutString;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
||||
{
|
||||
int offset = -1;
|
||||
|
||||
if (sscanf(offsetBuffer,"%4X",&offset) == EOF)
|
||||
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -35,14 +35,24 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
||||
{
|
||||
return offset & 0x00FF;
|
||||
}
|
||||
else if (type & BT_R)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
else // BT_C
|
||||
{
|
||||
if (GameInfo->type == GIT_NSF) { //NSF Breakpoint keywords
|
||||
int type = GIT_CART;
|
||||
|
||||
if (GameInfo)
|
||||
{
|
||||
type = GameInfo->type;
|
||||
}
|
||||
if (type == GIT_NSF) { //NSF Breakpoint keywords
|
||||
if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
|
||||
if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
|
||||
}
|
||||
else if (GameInfo->type == GIT_FDS) { //FDS Breakpoint keywords
|
||||
else if (type == GIT_FDS) { //FDS Breakpoint keywords
|
||||
if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
|
||||
if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
|
||||
@ -56,7 +66,7 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
return offset & 0xFFFF;
|
||||
}
|
||||
|
||||
// Returns the value of a given type or register
|
||||
@ -194,6 +204,9 @@ unsigned int NewBreak(const char* name, int start, int end, unsigned int type, c
|
||||
watchpoint[num].flags|=BT_S;
|
||||
watchpoint[num].flags&=~WP_X; //disable execute flag!
|
||||
}
|
||||
if (type & BT_R) {
|
||||
watchpoint[num].flags|=BT_R;
|
||||
}
|
||||
|
||||
if (watchpoint[num].desc)
|
||||
free(watchpoint[num].desc);
|
||||
@ -208,11 +221,27 @@ int GetPRGAddress(int A){
|
||||
int result;
|
||||
if(A > 0xFFFF)
|
||||
return -1;
|
||||
result = &Page[A>>11][A]-PRGptr[0];
|
||||
if((result > (int)PRGsize[0]) || (result < 0))
|
||||
return -1;
|
||||
else
|
||||
return result;
|
||||
if (GameInfo->type == GIT_FDS) {
|
||||
if (A < 0xE000) {
|
||||
result = &Page[A >> 11][A] - PRGptr[1];
|
||||
if ((result > (int)PRGsize[1]) || (result < 0))
|
||||
return -1;
|
||||
else
|
||||
return result;
|
||||
} else {
|
||||
result = &Page[A >> 11][A] - PRGptr[0];
|
||||
if ((result > (int)PRGsize[0]) || (result < 0))
|
||||
return -1;
|
||||
else
|
||||
return result + PRGsize[1];
|
||||
}
|
||||
} else {
|
||||
result = &Page[A >> 11][A] - PRGptr[0];
|
||||
if ((result > (int)PRGsize[0]) || (result < 0))
|
||||
return -1;
|
||||
else
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -421,12 +450,12 @@ int condition(watchpointinfo* wp)
|
||||
|
||||
//---------------------
|
||||
|
||||
volatile int codecount, datacount, undefinedcount;
|
||||
unsigned char *cdloggerdata;
|
||||
volatile int codecount = 0, datacount = 0, undefinedcount = 0;
|
||||
unsigned char *cdloggerdata = NULL;
|
||||
unsigned int cdloggerdataSize = 0;
|
||||
static int indirectnext;
|
||||
static int indirectnext = 0;
|
||||
|
||||
int debug_loggingCD;
|
||||
int debug_loggingCD = 0;
|
||||
|
||||
//called by the cpu to perform logging if CDLogging is enabled
|
||||
void LogCDVectors(int which){
|
||||
@ -448,20 +477,29 @@ void LogCDVectors(int which){
|
||||
}
|
||||
}
|
||||
|
||||
void LogCDData(uint8 *opcode, uint16 A, int size) {
|
||||
bool break_on_unlogged_code = false;
|
||||
bool break_on_unlogged_data = false;
|
||||
|
||||
void LogCDData(uint8 *opcode, uint16 A, int size)
|
||||
{
|
||||
int i, j;
|
||||
uint8 memop = 0;
|
||||
bool newCodeHit = false, newDataHit = false;
|
||||
|
||||
if((j = GetPRGAddress(_PC)) != -1)
|
||||
for (i = 0; i < size; i++) {
|
||||
if(cdloggerdata[j+i] & 1)continue; //this has been logged so skip
|
||||
if ((j = GetPRGAddress(_PC)) != -1)
|
||||
{
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (cdloggerdata[j+i] & 1) continue; //this has been logged so skip
|
||||
cdloggerdata[j+i] |= 1;
|
||||
cdloggerdata[j+i] |= ((_PC + i) >> 11) & 0x0c;
|
||||
cdloggerdata[j+i] |= ((_PC & 0x8000) >> 8) ^ 0x80; // 19/07/14 used last reserved bit, if bit 7 is 1, then code is running from lowe area (6000)
|
||||
if(indirectnext)cdloggerdata[j+i] |= 0x10;
|
||||
if (indirectnext)cdloggerdata[j+i] |= 0x10;
|
||||
codecount++;
|
||||
if(!(cdloggerdata[j+i] & 2))undefinedcount--;
|
||||
if (!(cdloggerdata[j+i] & 2))undefinedcount--;
|
||||
newCodeHit = true;
|
||||
}
|
||||
}
|
||||
|
||||
//log instruction jumped to in an indirect jump
|
||||
if(opcode[0] == 0x6c)
|
||||
@ -474,14 +512,43 @@ void LogCDData(uint8 *opcode, uint16 A, int size) {
|
||||
case 4: memop = 0x20; break;
|
||||
}
|
||||
|
||||
if((j = GetPRGAddress(A)) != -1) {
|
||||
if(!(cdloggerdata[j] & 2)) {
|
||||
cdloggerdata[j] |= 2;
|
||||
cdloggerdata[j] |=(A>>11)&0x0c;
|
||||
cdloggerdata[j] |= memop;
|
||||
datacount++;
|
||||
if(!(cdloggerdata[j] & 1))undefinedcount--;
|
||||
if ((j = GetPRGAddress(A)) != -1)
|
||||
{
|
||||
if (opwrite[opcode[0]] == 0)
|
||||
{
|
||||
if (!(cdloggerdata[j] & 2))
|
||||
{
|
||||
cdloggerdata[j] |= 2;
|
||||
cdloggerdata[j] |= (A >> 11) & 0x0c;
|
||||
cdloggerdata[j] |= memop;
|
||||
cdloggerdata[j] |= ((A & 0x8000) >> 8) ^ 0x80;
|
||||
datacount++;
|
||||
if (!(cdloggerdata[j] & 1))undefinedcount--;
|
||||
newDataHit = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cdloggerdata[j] & 1)
|
||||
{
|
||||
codecount--;
|
||||
}
|
||||
if (cdloggerdata[j] & 2)
|
||||
{
|
||||
datacount--;
|
||||
}
|
||||
if ((cdloggerdata[j] & 3) != 0) undefinedcount++;
|
||||
cdloggerdata[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( break_on_unlogged_code && newCodeHit )
|
||||
{
|
||||
BreakHit( BREAK_TYPE_UNLOGGED_CODE );
|
||||
}
|
||||
else if ( break_on_unlogged_data && newDataHit )
|
||||
{
|
||||
BreakHit( BREAK_TYPE_UNLOGGED_DATA );
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,40 +600,41 @@ void IncrementInstructionsCounters()
|
||||
delta_instructions++;
|
||||
}
|
||||
|
||||
void BreakHit(int bp_num, bool force)
|
||||
{
|
||||
if(!force)
|
||||
bool CondForbidTest(int bp_num) {
|
||||
if (bp_num >= 0 && !condition(&watchpoint[bp_num]))
|
||||
{
|
||||
if (bp_num >= 0 && !condition(&watchpoint[bp_num]))
|
||||
{
|
||||
return; // condition rejected
|
||||
}
|
||||
return false; // condition rejected
|
||||
}
|
||||
|
||||
//check to see whether we fall in any forbid zone
|
||||
for (int i = 0; i < numWPs; i++)
|
||||
{
|
||||
watchpointinfo& wp = watchpoint[i];
|
||||
if(!(wp.flags & WP_F) || !(wp.flags & WP_E))
|
||||
continue;
|
||||
//check to see whether we fall in any forbid zone
|
||||
for (int i = 0; i < numWPs; i++)
|
||||
{
|
||||
watchpointinfo& wp = watchpoint[i];
|
||||
if (!(wp.flags & WP_F) || !(wp.flags & WP_E))
|
||||
continue;
|
||||
|
||||
if (condition(&wp))
|
||||
{
|
||||
if (wp.endaddress) {
|
||||
if( (wp.address <= _PC) && (wp.endaddress >= _PC) )
|
||||
return; //forbid
|
||||
} else {
|
||||
if(wp.address == _PC)
|
||||
return; //forbid
|
||||
}
|
||||
if (condition(&wp))
|
||||
{
|
||||
if (wp.endaddress) {
|
||||
if ((wp.address <= _PC) && (wp.endaddress >= _PC))
|
||||
return false; // forbid
|
||||
}
|
||||
else {
|
||||
if (wp.address == _PC)
|
||||
return false; // forbid
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BreakHit(int bp_num)
|
||||
{
|
||||
FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED); //mbg merge 7/19/06 changed to use EmulationPaused()
|
||||
|
||||
#ifdef WIN32
|
||||
//#ifdef WIN32
|
||||
FCEUD_DebugBreakpoint(bp_num);
|
||||
#endif
|
||||
//#endif
|
||||
}
|
||||
|
||||
int StackAddrBackup;
|
||||
@ -574,10 +642,10 @@ uint16 StackNextIgnorePC = 0xFFFF;
|
||||
|
||||
///fires a breakpoint
|
||||
static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
||||
int i, j;
|
||||
int i, j, romAddrPC;
|
||||
uint8 brk_type;
|
||||
uint8 stackop=0;
|
||||
uint8 stackopstartaddr,stackopendaddr;
|
||||
uint8 stackopstartaddr=0,stackopendaddr=0;
|
||||
|
||||
debugLastAddress = A;
|
||||
debugLastOpcode = opcode[0];
|
||||
@ -585,17 +653,17 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
||||
if (break_asap)
|
||||
{
|
||||
break_asap = false;
|
||||
BreakHit(BREAK_TYPE_LUA, true);
|
||||
BreakHit(BREAK_TYPE_LUA);
|
||||
}
|
||||
|
||||
if (break_on_cycles && ((timestampbase + (uint64)timestamp - total_cycles_base) > break_cycles_limit))
|
||||
BreakHit(BREAK_TYPE_CYCLES_EXCEED, true);
|
||||
BreakHit(BREAK_TYPE_CYCLES_EXCEED);
|
||||
if (break_on_instructions && (total_instructions > break_instructions_limit))
|
||||
BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED, true);
|
||||
BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED);
|
||||
|
||||
//if the current instruction is bad, and we are breaking on bad opcodes, then hit the breakpoint
|
||||
if(dbgstate.badopbreak && (size == 0))
|
||||
BreakHit(BREAK_TYPE_BADOP, true);
|
||||
BreakHit(BREAK_TYPE_BADOP);
|
||||
|
||||
//if we're stepping out, track the nest level
|
||||
if (dbgstate.stepout) {
|
||||
@ -614,7 +682,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
||||
//if we're stepping, then we'll always want to break
|
||||
if (dbgstate.step) {
|
||||
dbgstate.step = false;
|
||||
BreakHit(BREAK_TYPE_STEP, true);
|
||||
BreakHit(BREAK_TYPE_STEP);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -626,7 +694,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
||||
if (diff<=0)
|
||||
{
|
||||
dbgstate.runline=false;
|
||||
BreakHit(BREAK_TYPE_STEP, true);
|
||||
BreakHit(BREAK_TYPE_STEP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -635,10 +703,12 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
||||
if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) {
|
||||
watchpoint[64].address = 0;
|
||||
watchpoint[64].flags = 0;
|
||||
BreakHit(BREAK_TYPE_STEP, true);
|
||||
BreakHit(BREAK_TYPE_STEP);
|
||||
return;
|
||||
}
|
||||
|
||||
romAddrPC = GetNesFileAddress(_PC);
|
||||
|
||||
brk_type = opbrktype[opcode[0]] | WP_X;
|
||||
|
||||
switch (opcode[0]) {
|
||||
@ -657,7 +727,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
||||
default: break;
|
||||
}
|
||||
|
||||
#define BREAKHIT(x) { breakHit = (x); goto STOPCHECKING; }
|
||||
#define BREAKHIT(x) { if (CondForbidTest(x)) { breakHit = (x); goto STOPCHECKING; } }
|
||||
int breakHit = -1;
|
||||
for (i = 0; i < numWPs; i++)
|
||||
{
|
||||
@ -708,11 +778,31 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
|
||||
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address <= A) && (watchpoint[i].endaddress >= A)) ||
|
||||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC)))
|
||||
BREAKHIT(i);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) ||
|
||||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC)))
|
||||
BREAKHIT(i);
|
||||
if (watchpoint[i].flags & BT_R)
|
||||
{
|
||||
if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == romAddrPC) )
|
||||
{
|
||||
BREAKHIT(i);
|
||||
}
|
||||
//else if ( (watchpoint[i].flags & WP_R) && (watchpoint[i].address == A) )
|
||||
//{
|
||||
// BREAKHIT(i);
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A))
|
||||
{
|
||||
BREAKHIT(i);
|
||||
}
|
||||
else if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC) )
|
||||
{
|
||||
BREAKHIT(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
@ -864,10 +954,5 @@ void DebugCycle()
|
||||
if(debug_loggingCD)
|
||||
LogCDData(opcode, A, size);
|
||||
|
||||
#ifdef WIN32
|
||||
//This needs to be windows only or else the linux build system will fail since logging is declared in a
|
||||
//windows source file
|
||||
FCEUD_TraceInstruction(opcode, size);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -15,12 +15,15 @@
|
||||
#define BT_C 0x00 //break type, cpu mem
|
||||
#define BT_P 0x20 //break type, ppu mem
|
||||
#define BT_S 0x40 //break type, sprite mem
|
||||
#define BT_R 0x80 //break type, rom mem
|
||||
|
||||
#define BREAK_TYPE_STEP -1
|
||||
#define BREAK_TYPE_BADOP -2
|
||||
#define BREAK_TYPE_CYCLES_EXCEED -3
|
||||
#define BREAK_TYPE_INSTRUCTIONS_EXCEED -4
|
||||
#define BREAK_TYPE_LUA -5
|
||||
#define BREAK_TYPE_UNLOGGED_CODE -6
|
||||
#define BREAK_TYPE_UNLOGGED_DATA -7
|
||||
|
||||
//opbrktype is used to grab the breakpoint type that each instruction will cause.
|
||||
//WP_X is not used because ALL opcodes will have the execute bit set.
|
||||
@ -46,9 +49,9 @@ static const uint8 opbrktype[256] = {
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint16 address;
|
||||
uint16 endaddress;
|
||||
uint8 flags;
|
||||
uint32 address;
|
||||
uint32 endaddress;
|
||||
uint16 flags;
|
||||
|
||||
Condition* cond;
|
||||
char* condText;
|
||||
@ -59,6 +62,7 @@ typedef struct {
|
||||
//mbg merge 7/18/06 had to make this extern
|
||||
extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over
|
||||
|
||||
extern unsigned int debuggerPageSize;
|
||||
int getBank(int offs);
|
||||
int GetNesFileAddress(int A);
|
||||
int GetPRGAddress(int A);
|
||||
@ -93,9 +97,12 @@ static INLINE int FCEUI_GetLoggingCD() { return debug_loggingCD; }
|
||||
extern int iaPC;
|
||||
extern uint32 iapoffset; //mbg merge 7/18/06 changed from int
|
||||
void DebugCycle();
|
||||
void BreakHit(int bp_num, bool force = false);
|
||||
bool CondForbidTest(int bp_num);
|
||||
void BreakHit(int bp_num);
|
||||
|
||||
extern bool break_asap;
|
||||
extern bool break_on_unlogged_code;
|
||||
extern bool break_on_unlogged_data;
|
||||
extern uint64 total_cycles_base;
|
||||
extern uint64 delta_cycles_base;
|
||||
extern bool break_on_cycles;
|
||||
@ -113,8 +120,9 @@ extern void IncrementInstructionsCounters();
|
||||
|
||||
//internal variables that debuggers will want access to
|
||||
extern uint8 *vnapage[4],*VPage[8];
|
||||
extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
|
||||
extern uint8 PPU[4],PALRAM[0x20],UPALRAM[3],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
|
||||
extern uint32 FCEUPPU_PeekAddress();
|
||||
extern uint8 READPAL_MOTHEROFALL(uint32 A);
|
||||
extern int numWPs;
|
||||
|
||||
///encapsulates the operational state of the debugger core
|
||||
|
@ -395,10 +395,10 @@ static int FixJoedChar(uint8 ch)
|
||||
int c = ch - 32;
|
||||
return (c < 0 || c > 98) ? 0 : c;
|
||||
}
|
||||
static int JoedCharWidth(uint8 ch)
|
||||
{
|
||||
return Font6x7[FixJoedChar(ch)*8];
|
||||
}
|
||||
//static int JoedCharWidth(uint8 ch)
|
||||
//{
|
||||
// return Font6x7[FixJoedChar(ch)*8];
|
||||
//}
|
||||
|
||||
char target[64][256];
|
||||
|
||||
|
@ -14,14 +14,16 @@ inline FILE *FCEUD_UTF8fopen(const std::string &n, const char *mode) { return FC
|
||||
EMUFILE_FILE* FCEUD_UTF8_fstream(const char *n, const char *m);
|
||||
inline EMUFILE_FILE* FCEUD_UTF8_fstream(const std::string &n, const char *m) { return FCEUD_UTF8_fstream(n.c_str(),m); }
|
||||
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex);
|
||||
FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex, int* userCancel);
|
||||
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename);
|
||||
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel);
|
||||
ArchiveScanRecord FCEUD_ScanArchive(std::string fname);
|
||||
|
||||
//mbg 7/23/06
|
||||
const char *FCEUD_GetCompilerString();
|
||||
|
||||
//This makes me feel dirty for some reason.
|
||||
void FCEU_printf(char *format, ...);
|
||||
void FCEU_printf(const char *format, ...);
|
||||
#define FCEUI_printf FCEU_printf
|
||||
|
||||
//Video interface
|
||||
@ -123,6 +125,7 @@ void FCEUI_SetVidSystem(int a);
|
||||
//Set variables for NTSC(0) / PAL(1) / Dendy(2)
|
||||
//Dendy has PAL framerate and resolution, but ~NTSC timings, and has 50 dummy scanlines to force 50 fps
|
||||
void FCEUI_SetRegion(int region, int notify = 1);
|
||||
int FCEUI_GetRegion(void);
|
||||
|
||||
//Convenience function; returns currently emulated video system(0=NTSC, 1=PAL).
|
||||
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend);
|
||||
@ -140,7 +143,9 @@ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall);
|
||||
|
||||
//Sets the base directory(save states, snapshots, etc. are saved in directories below this directory.
|
||||
void FCEUI_SetBaseDirectory(std::string const & dir);
|
||||
const char *FCEUI_GetBaseDirectory(void);
|
||||
|
||||
bool FCEUI_GetUserPaletteAvail(void);
|
||||
void FCEUI_SetUserPalette(uint8 *pal, int nEntries);
|
||||
|
||||
//Sets up sound code to render sound at the specified rate, in samples
|
||||
@ -178,10 +183,16 @@ void FCEUD_MovieRecordTo(void);
|
||||
void FCEUD_MovieReplayFrom(void);
|
||||
void FCEUD_LuaRunFrom(void);
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
// lua engine
|
||||
void TaseditorAutoFunction(void);
|
||||
void TaseditorManualFunction(void);
|
||||
#endif
|
||||
|
||||
int32 FCEUI_GetDesiredFPS(void);
|
||||
void FCEUI_SaveSnapshot(void);
|
||||
void FCEUI_SaveSnapshotAs(void);
|
||||
void FCEU_DispMessage(char *format, int disppos, ...);
|
||||
void FCEU_DispMessage(const char *format, int disppos, ...);
|
||||
#define FCEUI_DispMessage FCEU_DispMessage
|
||||
|
||||
int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type);
|
||||
@ -189,6 +200,7 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c);
|
||||
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type);
|
||||
int FCEUI_DelCheat(uint32 which);
|
||||
int FCEUI_ToggleCheat(uint32 which);
|
||||
int FCEUI_GlobalToggleCheat(int global_enable);
|
||||
|
||||
int32 FCEUI_CheatSearchGetCount(void);
|
||||
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current));
|
||||
@ -247,7 +259,7 @@ void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make
|
||||
//int FCEUI_FDSEject(void);
|
||||
void FCEUI_FDSSelect(void);
|
||||
|
||||
int FCEUI_DatachSet(const uint8 *rcode);
|
||||
int FCEUI_DatachSet(uint8 *rcode);
|
||||
|
||||
///returns a flag indicating whether emulation is paused
|
||||
int FCEUI_EmulationPaused();
|
||||
@ -318,6 +330,9 @@ void FCEUD_DebugBreakpoint(int bp_num);
|
||||
///the driver should log the current instruction, if it wants (we should move the code in the win driver that does this to the shared area)
|
||||
void FCEUD_TraceInstruction(uint8 *opcode, int size);
|
||||
|
||||
///the driver should flush its trace log
|
||||
void FCEUD_FlushTrace();
|
||||
|
||||
///the driver might should update its NTView (only used if debugging support is compiled in)
|
||||
void FCEUD_UpdateNTView(int scanline, bool drawall);
|
||||
|
||||
@ -337,7 +352,8 @@ enum EFCEUI
|
||||
FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE,
|
||||
FCEUI_OPENGAME, FCEUI_CLOSEGAME,
|
||||
FCEUI_TASEDITOR,
|
||||
FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN
|
||||
FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN, FCEUI_INPUT_BARCODE,
|
||||
FCEUI_TOGGLERECORDINGMOVIE, FCEUI_TRUNCATEMOVIE, FCEUI_INSERT1FRAME, FCEUI_DELETE1FRAME
|
||||
};
|
||||
|
||||
//checks whether an EFCEUI is valid right now
|
||||
|
@ -86,6 +86,7 @@ void EMUFILE_FILE::truncate(s32 length)
|
||||
#else
|
||||
ftruncate(fileno(fp),length);
|
||||
#endif
|
||||
// this is probably wrong if mode is "wb"
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
open(fname.c_str(),mode);
|
||||
@ -132,7 +133,7 @@ void EMUFILE::write64le(u64 val)
|
||||
|
||||
size_t EMUFILE::read64le(u64 *Bufo)
|
||||
{
|
||||
u64 buf;
|
||||
u64 buf=0;
|
||||
if(fread((char*)&buf,8) != 8)
|
||||
return 0;
|
||||
#ifndef LOCAL_BE
|
||||
@ -173,7 +174,7 @@ size_t EMUFILE::read32le(s32* Bufo) { return read32le((u32*)Bufo); }
|
||||
|
||||
size_t EMUFILE::read32le(u32* Bufo)
|
||||
{
|
||||
u32 buf;
|
||||
u32 buf=0;
|
||||
if(fread(&buf,4)<4)
|
||||
return 0;
|
||||
#ifndef LOCAL_BE
|
||||
@ -212,7 +213,7 @@ size_t EMUFILE::read16le(s16* Bufo) { return read16le((u16*)Bufo); }
|
||||
|
||||
size_t EMUFILE::read16le(u16* Bufo)
|
||||
{
|
||||
u32 buf;
|
||||
u32 buf=0;
|
||||
if(fread(&buf,2)<2)
|
||||
return 0;
|
||||
#ifndef LOCAL_BE
|
||||
|
@ -222,7 +222,7 @@ public:
|
||||
reserve(pos+(s32)bytes);
|
||||
memcpy(buf()+pos,ptr,bytes);
|
||||
pos += (s32)bytes;
|
||||
len = std::max(pos,len);
|
||||
len = std::max<int>(pos,len);
|
||||
}
|
||||
|
||||
virtual int fseek(int offset, int origin){
|
||||
|
@ -43,7 +43,7 @@
|
||||
#include "file.h"
|
||||
#include "vsuni.h"
|
||||
#include "ines.h"
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
#include "drivers/win/pref.h"
|
||||
#include "utils/xstring.h"
|
||||
|
||||
@ -65,7 +65,7 @@ extern void RefreshThrottleFPS();
|
||||
#endif
|
||||
|
||||
//TODO - we really need some kind of global platform-specific options api
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
#include "drivers/win/main.h"
|
||||
#include "drivers/win/memview.h"
|
||||
#include "drivers/win/cheat.h"
|
||||
@ -117,21 +117,26 @@ bool DebuggerWasUpdated = false; //To prevent the debugger from updating things
|
||||
bool AutoResumePlay = false;
|
||||
char romNameWhenClosingEmulator[2048] = {0};
|
||||
|
||||
|
||||
FCEUGI::FCEUGI()
|
||||
: filename(0),
|
||||
archiveFilename(0) {
|
||||
archiveFilename(0)
|
||||
{
|
||||
//printf("%08x",opsize); // WTF?!
|
||||
}
|
||||
|
||||
FCEUGI::~FCEUGI() {
|
||||
if (filename) {
|
||||
free(filename);
|
||||
filename = NULL;
|
||||
}
|
||||
if (archiveFilename) {
|
||||
delete archiveFilename;
|
||||
archiveFilename = NULL;
|
||||
}
|
||||
FCEUGI::~FCEUGI()
|
||||
{
|
||||
if (filename)
|
||||
{
|
||||
free(filename);
|
||||
filename = NULL;
|
||||
}
|
||||
if (archiveFilename)
|
||||
{
|
||||
free(archiveFilename);
|
||||
archiveFilename = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckFileExists(const char* filename) {
|
||||
@ -160,7 +165,7 @@ void FCEU_TogglePPU(void) {
|
||||
FCEUI_printf("Old PPU loaded");
|
||||
}
|
||||
normalscanlines = (dendy ? 290 : 240)+newppu; // use flag as number!
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
SetMainWindowText();
|
||||
#endif
|
||||
}
|
||||
@ -175,7 +180,7 @@ static void FCEU_CloseGame(void)
|
||||
FCEUSS_Save(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
extern char LoadedRomFName[2048];
|
||||
if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))
|
||||
FCEUD_PrintError("Couldn't store debugging data");
|
||||
@ -192,7 +197,14 @@ static void FCEU_CloseGame(void)
|
||||
}
|
||||
|
||||
if (GameInfo->type != GIT_NSF) {
|
||||
FCEU_FlushGameCheats(0, 0);
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (disableAutoLSCheats == 2)
|
||||
FCEU_FlushGameCheats(0, 1);
|
||||
else if (disableAutoLSCheats == 1)
|
||||
AskSaveCheat();
|
||||
else if (disableAutoLSCheats == 0)
|
||||
#endif
|
||||
FCEU_FlushGameCheats(0, 0);
|
||||
}
|
||||
|
||||
GameInterface(GI_CLOSE);
|
||||
@ -393,6 +405,7 @@ void ResetGameLoaded(void) {
|
||||
MapIRQHook = NULL;
|
||||
MMC5Hack = 0;
|
||||
PEC586Hack = 0;
|
||||
QTAIHack = 0;
|
||||
PAL &= 1;
|
||||
default_palette_selection = 0;
|
||||
}
|
||||
@ -402,8 +415,6 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode);
|
||||
int FDSLoad(const char *name, FCEUFILE *fp);
|
||||
int NSFLoad(const char *name, FCEUFILE *fp);
|
||||
|
||||
//char lastLoadedGameName [2048] = {0,}; // hack for movie WRAM clearing on record from poweron
|
||||
|
||||
//name should be UTF-8, hopefully, or else there may be trouble
|
||||
FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silent)
|
||||
{
|
||||
@ -414,28 +425,35 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
|
||||
int lastpal = PAL;
|
||||
int lastdendy = dendy;
|
||||
|
||||
const char* romextensions[] = { "nes", "fds", 0 };
|
||||
fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions);
|
||||
const char* romextensions[] = { "nes", "fds", "nsf", 0 };
|
||||
|
||||
// indicator for if the operaton was canceled by user
|
||||
// currently there's only one situation:
|
||||
// the user clicked cancel form the open from archive dialog
|
||||
int userCancel = 0;
|
||||
fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions, &userCancel);
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
if (!silent)
|
||||
// Although !fp, if the operation was canceled from archive select dialog box, don't show the error message;
|
||||
if (!silent && !userCancel)
|
||||
FCEU_PrintError("Error opening \"%s\"!", name);
|
||||
|
||||
return 0;
|
||||
} else if (fp->archiveFilename != "")
|
||||
}
|
||||
else if (fp->archiveFilename != "")
|
||||
{
|
||||
strcpy(fullname, fp->archiveFilename.c_str());
|
||||
strcat(fullname, "|");
|
||||
strcat(fullname, fp->filename.c_str());
|
||||
} else
|
||||
{
|
||||
strcpy(fullname, name);
|
||||
}
|
||||
|
||||
// reset loaded game BEFORE it's loading.
|
||||
ResetGameLoaded();
|
||||
//file opened ok. start loading.
|
||||
FCEU_printf("Loading %s...\n\n", fullname);
|
||||
GetFileBase(fp->filename.c_str());
|
||||
ResetGameLoaded();
|
||||
//reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing
|
||||
MasterRomInfoParams = TMasterRomInfoParams();
|
||||
|
||||
@ -446,7 +464,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
|
||||
|
||||
FCEU_CloseGame();
|
||||
GameInfo = new FCEUGI();
|
||||
memset(GameInfo, 0, sizeof(FCEUGI));
|
||||
memset( (void*)GameInfo, 0, sizeof(FCEUGI));
|
||||
|
||||
GameInfo->filename = strdup(fp->filename.c_str());
|
||||
if (fp->archiveFilename != "")
|
||||
@ -464,99 +482,115 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
|
||||
|
||||
//try to load each different format
|
||||
bool FCEUXLoad(const char *name, FCEUFILE * fp);
|
||||
/*if(FCEUXLoad(name,fp))
|
||||
goto endlseq;*/
|
||||
if (iNESLoad(fullname, fp, OverwriteVidMode))
|
||||
goto endlseq;
|
||||
if (NSFLoad(fullname, fp))
|
||||
goto endlseq;
|
||||
if (UNIFLoad(fullname, fp))
|
||||
goto endlseq;
|
||||
if (FDSLoad(fullname, fp))
|
||||
goto endlseq;
|
||||
|
||||
if (!silent)
|
||||
FCEU_PrintError("An error occurred while loading the file.");
|
||||
FCEU_fclose(fp);
|
||||
|
||||
delete GameInfo;
|
||||
GameInfo = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
endlseq:
|
||||
|
||||
FCEU_fclose(fp);
|
||||
|
||||
#ifdef WIN32
|
||||
// ################################## Start of SP CODE ###########################
|
||||
extern char LoadedRomFName[2048];
|
||||
extern int loadDebugDataFailed;
|
||||
|
||||
if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str())))
|
||||
if (!silent)
|
||||
FCEU_printf("Couldn't load debugging data.\n");
|
||||
|
||||
// ################################## End of SP CODE ###########################
|
||||
#endif
|
||||
|
||||
if (OverwriteVidMode)
|
||||
FCEU_ResetVidSys();
|
||||
|
||||
if (GameInfo->type != GIT_NSF)
|
||||
int load_result;
|
||||
load_result = iNESLoad(fullname, fp, OverwriteVidMode);
|
||||
if (load_result == LOADER_INVALID_FORMAT)
|
||||
{
|
||||
if (FSettings.GameGenie)
|
||||
load_result = NSFLoad(fullname, fp);
|
||||
if (load_result == LOADER_INVALID_FORMAT)
|
||||
{
|
||||
if (FCEU_OpenGenie())
|
||||
load_result = UNIFLoad(fullname, fp);
|
||||
if (load_result == LOADER_INVALID_FORMAT)
|
||||
{
|
||||
FCEUI_SetGameGenie(false);
|
||||
#ifdef WIN32
|
||||
genie = 0;
|
||||
#endif
|
||||
load_result = FDSLoad(fullname, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
PowerNES();
|
||||
|
||||
if (GameInfo->type != GIT_NSF)
|
||||
FCEU_LoadGamePalette();
|
||||
|
||||
FCEU_ResetPalette();
|
||||
FCEU_ResetMessages(); // Save state, status messages, etc.
|
||||
|
||||
if (!lastpal && PAL) {
|
||||
FCEU_DispMessage("PAL mode set", 0);
|
||||
FCEUI_printf("PAL mode set");
|
||||
} else if (!lastdendy && dendy) {
|
||||
// this won't happen, since we don't autodetect dendy, but maybe someday we will?
|
||||
FCEU_DispMessage("Dendy mode set", 0);
|
||||
FCEUI_printf("Dendy mode set");
|
||||
} else if ((lastpal || lastdendy) && !(PAL || dendy)) {
|
||||
FCEU_DispMessage("NTSC mode set", 0);
|
||||
FCEUI_printf("NTSC mode set");
|
||||
}
|
||||
|
||||
if (GameInfo->type != GIT_NSF)
|
||||
FCEU_LoadGameCheats(0);
|
||||
|
||||
if (AutoResumePlay)
|
||||
if (load_result == LOADER_OK)
|
||||
{
|
||||
// load "-resume" savestate
|
||||
if (FCEUSS_Load(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false))
|
||||
FCEU_DispMessage("Old play session resumed.", 0);
|
||||
}
|
||||
|
||||
ResetScreenshotsCounter();
|
||||
#ifdef __WIN_DRIVER__
|
||||
// ################################## Start of SP CODE ###########################
|
||||
extern char LoadedRomFName[2048];
|
||||
extern int loadDebugDataFailed;
|
||||
|
||||
#if defined (WIN32) || defined (WIN64)
|
||||
DoDebuggerDataReload(); // Reloads data without reopening window
|
||||
CDLoggerROMChanged();
|
||||
if (hMemView) UpdateColorTable();
|
||||
if (hCheat) UpdateCheatsAdded();
|
||||
if (FrozenAddressCount)
|
||||
FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount);
|
||||
if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str())))
|
||||
if (!silent)
|
||||
FCEU_printf("Couldn't load debugging data.\n");
|
||||
|
||||
// ################################## End of SP CODE ###########################
|
||||
#endif
|
||||
|
||||
if (OverwriteVidMode)
|
||||
FCEU_ResetVidSys();
|
||||
|
||||
if (GameInfo->type != GIT_NSF &&
|
||||
FSettings.GameGenie &&
|
||||
FCEU_OpenGenie())
|
||||
{
|
||||
FCEUI_SetGameGenie(false);
|
||||
#ifdef __WIN_DRIVER__
|
||||
genie = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
PowerNES();
|
||||
|
||||
if (GameInfo->type != GIT_NSF)
|
||||
FCEU_LoadGamePalette();
|
||||
|
||||
FCEU_ResetPalette();
|
||||
FCEU_ResetMessages(); // Save state, status messages, etc.
|
||||
|
||||
if (!lastpal && PAL) {
|
||||
FCEU_DispMessage("PAL mode set", 0);
|
||||
FCEUI_printf("PAL mode set\n");
|
||||
}
|
||||
else if (!lastdendy && dendy) {
|
||||
// this won't happen, since we don't autodetect dendy, but maybe someday we will?
|
||||
FCEU_DispMessage("Dendy mode set", 0);
|
||||
FCEUI_printf("Dendy mode set\n");
|
||||
}
|
||||
else if ((lastpal || lastdendy) && !(PAL || dendy)) {
|
||||
FCEU_DispMessage("NTSC mode set", 0);
|
||||
FCEUI_printf("NTSC mode set\n");
|
||||
}
|
||||
|
||||
if (GameInfo->type != GIT_NSF && !disableAutoLSCheats)
|
||||
FCEU_LoadGameCheats(0);
|
||||
|
||||
if (AutoResumePlay)
|
||||
{
|
||||
// load "-resume" savestate
|
||||
if (FCEUSS_Load(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false))
|
||||
FCEU_DispMessage("Old play session resumed.", 0);
|
||||
}
|
||||
|
||||
ResetScreenshotsCounter();
|
||||
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoDebuggerDataReload(); // Reloads data without reopening window
|
||||
CDLoggerROMChanged();
|
||||
if (hMemView) UpdateColorTable();
|
||||
if (hCheat)
|
||||
{
|
||||
UpdateCheatsAdded();
|
||||
UpdateCheatRelatedWindow();
|
||||
}
|
||||
if (FrozenAddressCount)
|
||||
FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (!silent)
|
||||
{
|
||||
switch (load_result)
|
||||
{
|
||||
case LOADER_UNHANDLED_ERROR:
|
||||
FCEU_PrintError("An error occurred while loading the file.");
|
||||
break;
|
||||
case LOADER_INVALID_FORMAT:
|
||||
FCEU_PrintError("Unknown ROM file format.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete GameInfo;
|
||||
GameInfo = 0;
|
||||
}
|
||||
|
||||
FCEU_fclose(fp);
|
||||
return GameInfo;
|
||||
}
|
||||
|
||||
@ -610,47 +644,81 @@ void FCEUI_Kill(void) {
|
||||
}
|
||||
|
||||
int rapidAlternator = 0;
|
||||
int AutoFirePattern[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
|
||||
//int AutoFirePattern[8] = { 1, 0, 0, 0, 0, 0, 0, 0 };
|
||||
int AutoFirePatternLength = 2;
|
||||
|
||||
void SetAutoFirePattern(int onframes, int offframes) {
|
||||
int i;
|
||||
for (i = 0; i < onframes && i < 8; i++) {
|
||||
AutoFirePattern[i] = 1;
|
||||
}
|
||||
for (; i < 8; i++) {
|
||||
AutoFirePattern[i] = 0;
|
||||
}
|
||||
if (onframes + offframes < 2) {
|
||||
AutoFirePatternLength = 2;
|
||||
} else if (onframes + offframes > 8) {
|
||||
AutoFirePatternLength = 8;
|
||||
} else {
|
||||
AutoFirePatternLength = onframes + offframes;
|
||||
}
|
||||
void SetAutoFirePattern(int onframes, int offframes)
|
||||
{
|
||||
//int i;
|
||||
//for (i = 0; i < onframes && i < 8; i++) {
|
||||
// AutoFirePattern[i] = 1;
|
||||
//}
|
||||
//for (; i < 8; i++) {
|
||||
// AutoFirePattern[i] = 0;
|
||||
//}
|
||||
//if (onframes + offframes < 2) {
|
||||
// AutoFirePatternLength = 2;
|
||||
//} else if (onframes + offframes > 8) {
|
||||
// AutoFirePatternLength = 8;
|
||||
//} else {
|
||||
// AutoFirePatternLength = onframes + offframes;
|
||||
//}
|
||||
AutoFirePatternLength = onframes + offframes;
|
||||
AFon = onframes; AFoff = offframes;
|
||||
}
|
||||
|
||||
void SetAutoFireOffset(int offset) {
|
||||
void GetAutoFirePattern( int *onframes, int *offframes)
|
||||
{
|
||||
if ( onframes )
|
||||
{
|
||||
*onframes = AFon;
|
||||
}
|
||||
if ( offframes )
|
||||
{
|
||||
*offframes = AFoff;
|
||||
}
|
||||
}
|
||||
|
||||
void SetAutoFireOffset(int offset)
|
||||
{
|
||||
if (offset < 0 || offset > 8) return;
|
||||
AutoFireOffset = offset;
|
||||
}
|
||||
|
||||
void AutoFire(void) {
|
||||
bool GetAutoFireState(int btnIdx)
|
||||
{
|
||||
return rapidAlternator;
|
||||
}
|
||||
|
||||
void AutoFire(void)
|
||||
{
|
||||
static int counter = 0;
|
||||
if (justLagged == false)
|
||||
counter = (counter + 1) % (8 * 7 * 5 * 3);
|
||||
{
|
||||
//counter = (counter + 1) % (8 * 7 * 5 * 3);
|
||||
counter = (counter + 1) % AutoFirePatternLength;
|
||||
}
|
||||
//If recording a movie, use the frame # for the autofire so the offset
|
||||
//doesn't get screwed up when loading.
|
||||
if (FCEUMOV_Mode(MOVIEMODE_RECORD | MOVIEMODE_PLAY)) {
|
||||
rapidAlternator = AutoFirePattern[(AutoFireOffset + FCEUMOV_GetFrame()) % AutoFirePatternLength]; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire?
|
||||
} else {
|
||||
rapidAlternator = AutoFirePattern[(AutoFireOffset + counter) % AutoFirePatternLength];
|
||||
if (FCEUMOV_Mode(MOVIEMODE_RECORD | MOVIEMODE_PLAY))
|
||||
{
|
||||
//rapidAlternator = AutoFirePattern[(AutoFireOffset + FCEUMOV_GetFrame()) % AutoFirePatternLength]; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire?
|
||||
//adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire?
|
||||
rapidAlternator = ( (AutoFireOffset + FCEUMOV_GetFrame()) % AutoFirePatternLength ) < AFon;
|
||||
}
|
||||
else
|
||||
{
|
||||
//rapidAlternator = AutoFirePattern[(AutoFireOffset + counter) % AutoFirePatternLength];
|
||||
rapidAlternator = ( (AutoFireOffset + counter) % AutoFirePatternLength ) < AFon;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAutosave(void);
|
||||
|
||||
#ifdef __QT_DRIVER__
|
||||
extern unsigned int frameAdvHoldTimer;
|
||||
#endif
|
||||
|
||||
///Emulates a single frame.
|
||||
|
||||
///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame
|
||||
@ -662,10 +730,27 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||
|
||||
if (frameAdvanceRequested)
|
||||
{
|
||||
#ifdef __QT_DRIVER__
|
||||
uint32_t frameAdvanceDelayScaled = frameAdvance_Delay * (PAL ? 20 : 16);
|
||||
|
||||
if ( frameAdvanceDelayScaled < 1 )
|
||||
{
|
||||
frameAdvanceDelayScaled = 1;
|
||||
}
|
||||
if ( (frameAdvance_Delay_count == 0) || (frameAdvHoldTimer >= frameAdvanceDelayScaled) )
|
||||
{
|
||||
EmulationPaused = EMULATIONPAUSED_FA;
|
||||
}
|
||||
if (frameAdvance_Delay_count < frameAdvanceDelayScaled)
|
||||
{
|
||||
frameAdvance_Delay_count++;
|
||||
}
|
||||
#else
|
||||
if (frameAdvance_Delay_count == 0 || frameAdvance_Delay_count >= frameAdvance_Delay)
|
||||
EmulationPaused = EMULATIONPAUSED_FA;
|
||||
if (frameAdvance_Delay_count < frameAdvance_Delay)
|
||||
frameAdvance_Delay_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (EmulationPaused & EMULATIONPAUSED_FA)
|
||||
@ -673,7 +758,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||
// the user is holding Frame Advance key
|
||||
// clear paused flag temporarily
|
||||
EmulationPaused &= ~EMULATIONPAUSED_PAUSED;
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
// different emulation speed when holding Frame Advance
|
||||
if (fps_scale_frameadvance > 0)
|
||||
{
|
||||
@ -683,7 +768,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||
#endif
|
||||
} else
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (fps_scale_frameadvance > 0)
|
||||
{
|
||||
// restore emulation speed when Frame Advance is not held
|
||||
@ -722,13 +807,21 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||
|
||||
if (skip != 2) ssize = FlushEmulateSound(); //If skip = 2 we are skipping sound processing
|
||||
|
||||
//flush tracer once a frame, since we're likely to end up back at a user interaction loop after this with emulation paused
|
||||
FCEUD_FlushTrace();
|
||||
|
||||
#ifdef _S9XLUA_H
|
||||
CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
FCEU_PutImage();
|
||||
|
||||
#ifdef __WIN_DRIVER__
|
||||
//These Windows only dialogs need to be updated only once per frame so they are included here
|
||||
UpdateCheatList(); // CaH4e3: can't see why, this is only cause problems with selection - adelikat: selection is only a problem when not paused, it shoudl be paused to select, we want to see the values update
|
||||
// CaH4e3: can't see why, this is only cause problems with selection
|
||||
// adelikat: selection is only a problem when not paused, it should be paused to select, we want to see the values update
|
||||
// owomomo: use an OWNERDATA CListCtrl to partially solve the problem
|
||||
UpdateCheatList();
|
||||
UpdateTextHooker();
|
||||
Update_RAM_Search(); // Update_RAM_Watch() is also called.
|
||||
RamChange();
|
||||
@ -762,7 +855,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
||||
{
|
||||
EmulationPaused = EMULATIONPAUSED_PAUSED; // restore EMULATIONPAUSED_PAUSED flag and clear EMULATIONPAUSED_FA flag
|
||||
JustFrameAdvanced = true;
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (soundoptions & SO_MUTEFA) //mute the frame advance if the user requested it
|
||||
*SoundBufSize = 0; //keep sound muted
|
||||
#endif
|
||||
@ -796,7 +889,7 @@ void ResetNES(void) {
|
||||
extern uint8 *XBackBuf;
|
||||
memset(XBackBuf, 0, 256 * 256);
|
||||
|
||||
//FCEU_DispMessage("Reset", 0);
|
||||
// FCEU_DispMessage("Reset", 0);
|
||||
}
|
||||
|
||||
|
||||
@ -927,7 +1020,7 @@ void PowerNES(void) {
|
||||
|
||||
timestampbase = 0;
|
||||
X6502_Power();
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
ResetDebugStatisticsCounters();
|
||||
#endif
|
||||
FCEU_PowerCheats();
|
||||
@ -936,11 +1029,11 @@ void PowerNES(void) {
|
||||
extern uint8 *XBackBuf;
|
||||
memset(XBackBuf, 0, 256 * 256);
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
Update_RAM_Search(); // Update_RAM_Watch() is also called.
|
||||
#endif
|
||||
|
||||
FCEU_DispMessage("Power on", 0);
|
||||
// FCEU_DispMessage("Power on", 0);
|
||||
}
|
||||
|
||||
void FCEU_ResetVidSys(void) {
|
||||
@ -970,7 +1063,8 @@ void FCEU_ResetVidSys(void) {
|
||||
|
||||
FCEUS FSettings;
|
||||
|
||||
void FCEU_printf(char *format, ...) {
|
||||
void FCEU_printf(const char *format, ...)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
char temp[2048];
|
||||
|
||||
@ -991,7 +1085,8 @@ void FCEU_printf(char *format, ...) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void FCEU_PrintError(char *format, ...) {
|
||||
void FCEU_PrintError(const char *format, ...)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
char temp[2048];
|
||||
|
||||
@ -1037,51 +1132,67 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) {
|
||||
}
|
||||
|
||||
#ifndef GEKKO
|
||||
void FCEUI_SetRegion(int region, int notify) {
|
||||
int FCEUI_GetRegion(void)
|
||||
{
|
||||
int region;
|
||||
|
||||
if ( pal_emulation )
|
||||
{
|
||||
region = 1;
|
||||
}
|
||||
else if ( dendy )
|
||||
{
|
||||
region = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
region = 0;
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
void FCEUI_SetRegion(int region, int notify)
|
||||
{
|
||||
switch (region) {
|
||||
case 0: // NTSC
|
||||
normalscanlines = 240;
|
||||
pal_emulation = 0;
|
||||
dendy = 0;
|
||||
// until it's fixed on sdl. see issue #740
|
||||
#ifdef WIN32
|
||||
|
||||
if (notify)
|
||||
{
|
||||
FCEU_DispMessage("NTSC mode set", 0);
|
||||
FCEUI_printf("NTSC mode set");
|
||||
FCEUI_printf("NTSC mode set\n");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 1: // PAL
|
||||
normalscanlines = 240;
|
||||
pal_emulation = 1;
|
||||
dendy = 0;
|
||||
#ifdef WIN32
|
||||
|
||||
if (notify)
|
||||
{
|
||||
FCEU_DispMessage("PAL mode set", 0);
|
||||
FCEUI_printf("PAL mode set");
|
||||
FCEUI_printf("PAL mode set\n");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 2: // Dendy
|
||||
normalscanlines = 290;
|
||||
pal_emulation = 0;
|
||||
dendy = 1;
|
||||
#ifdef WIN32
|
||||
|
||||
if (notify)
|
||||
{
|
||||
FCEU_DispMessage("Dendy mode set", 0);
|
||||
FCEUI_printf("Dendy mode set");
|
||||
FCEUI_printf("Dendy mode set\n");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
normalscanlines += newppu;
|
||||
totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0);
|
||||
FCEUI_SetVidSystem(pal_emulation);
|
||||
RefreshThrottleFPS();
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
UpdateCheckedMenuItems();
|
||||
PushCurrentVideoSettings();
|
||||
#endif
|
||||
@ -1125,12 +1236,16 @@ void FCEUI_ClearEmulationFrameStepped()
|
||||
//ideally maybe we shouldnt be using this, but i need it for quick merging
|
||||
void FCEUI_SetEmulationPaused(int val) {
|
||||
EmulationPaused = val;
|
||||
if(EmulationPaused)
|
||||
FCEUD_FlushTrace();
|
||||
}
|
||||
|
||||
void FCEUI_ToggleEmulationPause(void)
|
||||
{
|
||||
EmulationPaused = (EmulationPaused & EMULATIONPAUSED_PAUSED) ^ EMULATIONPAUSED_PAUSED;
|
||||
DebuggerWasUpdated = false;
|
||||
if(EmulationPaused)
|
||||
FCEUD_FlushTrace();
|
||||
}
|
||||
|
||||
void FCEUI_FrameAdvanceEnd(void) {
|
||||
@ -1210,10 +1325,14 @@ bool FCEU_IsValidUI(EFCEUI ui) {
|
||||
break;
|
||||
|
||||
case FCEUI_STOPMOVIE:
|
||||
return(FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED));
|
||||
case FCEUI_TOGGLERECORDINGMOVIE:
|
||||
return FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED);
|
||||
|
||||
case FCEUI_PLAYFROMBEGINNING:
|
||||
return(FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_TASEDITOR | MOVIEMODE_FINISHED));
|
||||
return FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_TASEDITOR | MOVIEMODE_FINISHED);
|
||||
|
||||
case FCEUI_TRUNCATEMOVIE:
|
||||
return FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD);
|
||||
|
||||
case FCEUI_STOPAVI:
|
||||
return FCEUI_AviIsRecording();
|
||||
@ -1229,12 +1348,21 @@ bool FCEU_IsValidUI(EFCEUI ui) {
|
||||
case FCEUI_INSERT_COIN:
|
||||
if (!GameInfo) return false;
|
||||
if (FCEUMOV_Mode(MOVIEMODE_RECORD)) return true;
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR) && isTaseditorRecording()) return true;
|
||||
#endif
|
||||
if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false;
|
||||
break;
|
||||
|
||||
case FCEUI_INPUT_BARCODE:
|
||||
if (!GameInfo) return false;
|
||||
if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false;
|
||||
break;
|
||||
default:
|
||||
// Unhandled falls out to end of function
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@ -1295,10 +1423,16 @@ virtual void Power() {
|
||||
}
|
||||
};
|
||||
|
||||
void FCEUXGameInterface(GI command) {
|
||||
switch (command) {
|
||||
case GI_POWER:
|
||||
cart->Power();
|
||||
void FCEUXGameInterface(GI command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case GI_POWER:
|
||||
cart->Power();
|
||||
break;
|
||||
default:
|
||||
// Unhandled cases
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1366,8 +1500,8 @@ uint8 FCEU_ReadRomByte(uint32 i) {
|
||||
|
||||
void FCEU_WriteRomByte(uint32 i, uint8 value) {
|
||||
if (i < 16)
|
||||
#ifdef WIN32
|
||||
MessageBox(hMemView,"Sorry", "You can't edit the ROM header.", MB_OK);
|
||||
#ifdef __WIN_DRIVER__
|
||||
MessageBox(hMemView, "Sorry", "You can't edit the ROM header.", MB_OK | MB_ICONERROR);
|
||||
#else
|
||||
printf("Sorry, you can't edit the ROM header.\n");
|
||||
#endif
|
||||
|
@ -17,6 +17,7 @@ extern int postrenderscanlines;
|
||||
extern int vblankscanlines;
|
||||
|
||||
extern bool AutoResumePlay;
|
||||
extern bool frameAdvanceLagSkip;
|
||||
extern char romNameWhenClosingEmulator[];
|
||||
|
||||
#define DECLFR(x) uint8 x (uint32 A)
|
||||
@ -39,16 +40,20 @@ void PowerNES(void);
|
||||
|
||||
void SetAutoFireOffset(int offset);
|
||||
void SetAutoFirePattern(int onframes, int offframes);
|
||||
void GetAutoFirePattern( int *onframes, int *offframes);
|
||||
bool GetAutoFireState(int btnIdx);
|
||||
void AutoFire(void);
|
||||
void FCEUI_RewindToLastAutosave(void);
|
||||
|
||||
//mbg 7/23/06
|
||||
char *FCEUI_GetAboutString();
|
||||
const char *FCEUI_GetAboutString(void);
|
||||
|
||||
extern uint64 timestampbase;
|
||||
|
||||
// MMC5 external shared buffers/vars
|
||||
extern int MMC5Hack;
|
||||
extern uint32 MMC5HackVROMMask;
|
||||
extern uint8 *MMC5HackExNTARAMPtr;
|
||||
extern int MMC5Hack, PEC586Hack;
|
||||
extern uint8 *MMC5HackVROMPTR;
|
||||
extern uint8 MMC5HackCHRMode;
|
||||
extern uint8 MMC5HackSPMode;
|
||||
@ -56,11 +61,19 @@ extern uint8 MMC50x5130;
|
||||
extern uint8 MMC5HackSPScroll;
|
||||
extern uint8 MMC5HackSPPage;
|
||||
|
||||
extern int PEC586Hack;
|
||||
|
||||
// VRCV extarnal shared buffers/vars
|
||||
extern int QTAIHack;
|
||||
extern uint8 QTAINTRAM[2048];
|
||||
extern uint8 qtaintramreg;
|
||||
|
||||
#define GAME_MEM_BLOCK_SIZE 131072
|
||||
|
||||
extern uint8 *RAM; //shared memory modifications
|
||||
extern int EmulationPaused;
|
||||
extern int frameAdvance_Delay;
|
||||
extern int RAMInitOption;
|
||||
|
||||
uint8 FCEU_ReadRomByte(uint32 i);
|
||||
void FCEU_WriteRomByte(uint32 i, uint8 value);
|
||||
@ -85,10 +98,11 @@ extern int GameAttributes;
|
||||
|
||||
extern uint8 PAL;
|
||||
extern int dendy;
|
||||
extern bool movieSubtitles;
|
||||
|
||||
//#include "driver.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct fceu_settings_struct {
|
||||
int PAL;
|
||||
int NetworkPlay;
|
||||
int SoundVolume; //Master volume
|
||||
@ -125,10 +139,10 @@ extern FCEUS FSettings;
|
||||
|
||||
bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists
|
||||
|
||||
void FCEU_PrintError(char *format, ...);
|
||||
void FCEU_printf(char *format, ...);
|
||||
void FCEU_DispMessage(char *format, int disppos, ...);
|
||||
void FCEU_DispMessageOnMovie(char *format, ...);
|
||||
void FCEU_PrintError(const char *format, ...);
|
||||
void FCEU_printf(const char *format, ...);
|
||||
void FCEU_DispMessage(const char *format, int disppos, ...);
|
||||
void FCEU_DispMessageOnMovie(const char *format, ...);
|
||||
void FCEU_TogglePPU();
|
||||
|
||||
void SetNESDeemph_OldHacky(uint8 d, int force);
|
||||
@ -149,14 +163,20 @@ extern uint8 vsdip;
|
||||
|
||||
//#define FCEUDEF_DEBUGGER //mbg merge 7/17/06 - cleaning out conditional compiles
|
||||
|
||||
#define JOY_A 1
|
||||
#define JOY_B 2
|
||||
#define JOY_SELECT 4
|
||||
#define JOY_START 8
|
||||
#define JOY_UP 0x10
|
||||
#define JOY_A 0x01
|
||||
#define JOY_B 0x02
|
||||
#define JOY_SELECT 0x04
|
||||
#define JOY_START 0x08
|
||||
#define JOY_UP 0x10
|
||||
#define JOY_DOWN 0x20
|
||||
#define JOY_LEFT 0x40
|
||||
#define JOY_RIGHT 0x80
|
||||
|
||||
#define LOADER_INVALID_FORMAT 0
|
||||
#define LOADER_OK 1
|
||||
#define LOADER_HANDLED_ERROR 2
|
||||
#define LOADER_UNHANDLED_ERROR 3
|
||||
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
@ -90,12 +90,31 @@ static int32 DiskPtr;
|
||||
static int32 DiskSeekIRQ;
|
||||
static uint8 SelectDisk, InDisk;
|
||||
|
||||
/* 4024(w), 4025(w), 4031(r) by dink(fbneo) */
|
||||
enum FDS_DiskBlockIDs { DSK_INIT = 0, DSK_VOLUME, DSK_FILECNT, DSK_FILEHDR, DSK_FILEDATA };
|
||||
static uint8 mapperFDS_control; // 4025(w) control register
|
||||
static uint16 mapperFDS_filesize; // size of file being read/written
|
||||
static uint8 mapperFDS_block; // block-id of current block
|
||||
static uint16 mapperFDS_blockstart; // start-address of current block
|
||||
static uint16 mapperFDS_blocklen; // length of current block
|
||||
static uint16 mapperFDS_diskaddr; // current address relative to blockstart
|
||||
static uint8 mapperFDS_diskaccess; // disk needs to be accessed at least once before writing
|
||||
#define fds_disk() (diskdata[InDisk][mapperFDS_blockstart + mapperFDS_diskaddr])
|
||||
#define mapperFDS_diskinsert (InDisk != 255)
|
||||
|
||||
|
||||
#define DC_INC 1
|
||||
|
||||
void FDSGI(GI h) {
|
||||
switch (h) {
|
||||
case GI_CLOSE: FDSClose(); break;
|
||||
case GI_POWER: FDSInit(); break;
|
||||
switch (h)
|
||||
{
|
||||
case GI_CLOSE: FDSClose(); break;
|
||||
case GI_POWER: FDSInit(); break;
|
||||
|
||||
// Unhandled Cases
|
||||
case GI_RESETM2:
|
||||
case GI_RESETSAVE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,6 +164,14 @@ static void FDSInit(void) {
|
||||
FDSSoundReset();
|
||||
InDisk = 0;
|
||||
SelectDisk = 0;
|
||||
|
||||
mapperFDS_control = 0;
|
||||
mapperFDS_filesize = 0;
|
||||
mapperFDS_block = 0;
|
||||
mapperFDS_blockstart = 0;
|
||||
mapperFDS_blocklen = 0;
|
||||
mapperFDS_diskaddr = 0;
|
||||
mapperFDS_diskaccess = 0;
|
||||
}
|
||||
|
||||
void FCEU_FDSInsert(void)
|
||||
@ -200,16 +227,18 @@ void FCEU_FDSSelect(void)
|
||||
FCEU_DispMessage("", 0); //FCEU_DispMessage("Disk %d Side %c Selected", 0, SelectDisk >> 1, (SelectDisk & 1) ? 'B' : 'A');
|
||||
}
|
||||
|
||||
#define IRQ_Repeat (IRQa & 0x01)
|
||||
#define IRQ_Enabled (IRQa & 0x02)
|
||||
|
||||
static void FDSFix(int a) {
|
||||
if ((IRQa & 2) && IRQCount) {
|
||||
if ((IRQa & IRQ_Enabled) && IRQCount) {
|
||||
IRQCount -= a;
|
||||
if (IRQCount <= 0) {
|
||||
if (!(IRQa & 1)) {
|
||||
IRQa &= ~2;
|
||||
IRQCount = IRQLatch = 0;
|
||||
} else
|
||||
IRQCount = IRQLatch;
|
||||
IRQCount = IRQLatch;
|
||||
X6502_IRQBegin(FCEU_IQEXT);
|
||||
if (!(IRQa & IRQ_Repeat)) {
|
||||
IRQa &= ~IRQ_Enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DiskSeekIRQ > 0) {
|
||||
@ -237,17 +266,45 @@ static DECLFR(FDSRead4030) {
|
||||
}
|
||||
|
||||
static DECLFR(FDSRead4031) {
|
||||
static uint8 z = 0;
|
||||
if (InDisk != 255) {
|
||||
z = diskdata[InDisk][DiskPtr];
|
||||
if (!fceuindbg) {
|
||||
if (DiskPtr < 64999) DiskPtr++;
|
||||
DiskSeekIRQ = 150;
|
||||
X6502_IRQEnd(FCEU_IQEXT2);
|
||||
static uint8 ret = 0;
|
||||
|
||||
ret = 0xff;
|
||||
if (mapperFDS_diskinsert && mapperFDS_control & 0x04) {
|
||||
mapperFDS_diskaccess = 1;
|
||||
|
||||
ret = 0;
|
||||
|
||||
switch (mapperFDS_block) {
|
||||
case DSK_FILEHDR:
|
||||
if (mapperFDS_diskaddr < mapperFDS_blocklen) {
|
||||
ret = fds_disk();
|
||||
switch (mapperFDS_diskaddr) {
|
||||
case 13: mapperFDS_filesize = ret; break;
|
||||
case 14:
|
||||
mapperFDS_filesize |= ret << 8;
|
||||
//char fdsfile[10];
|
||||
//strncpy(fdsfile, (char*)&diskdata[InDisk][mapperFDS_blockstart + 3], 8);
|
||||
//printf("Read file: %s (size: %d)\n"), fdsfile, mapperFDS_filesize);
|
||||
break;
|
||||
}
|
||||
mapperFDS_diskaddr++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (mapperFDS_diskaddr < mapperFDS_blocklen) {
|
||||
ret = fds_disk();
|
||||
mapperFDS_diskaddr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DiskSeekIRQ = 150;
|
||||
X6502_IRQEnd(FCEU_IQEXT2);
|
||||
}
|
||||
return z;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DECLFR(FDSRead4032) {
|
||||
uint8 ret;
|
||||
|
||||
@ -537,33 +594,87 @@ static DECLFW(FDSWrite) {
|
||||
break;
|
||||
case 0x4023: break;
|
||||
case 0x4024:
|
||||
if ((InDisk != 255) && !(FDSRegs[5] & 0x4) && (FDSRegs[3] & 0x1)) {
|
||||
if (DiskPtr >= 0 && DiskPtr < 65500) {
|
||||
if (writeskip)
|
||||
writeskip--;
|
||||
else if (DiskPtr >= 2) {
|
||||
DiskWritten = 1;
|
||||
diskdata[InDisk][DiskPtr - 2] = V;
|
||||
}
|
||||
if (mapperFDS_diskinsert && ~mapperFDS_control & 0x04) {
|
||||
|
||||
if (mapperFDS_diskaccess == 0) {
|
||||
mapperFDS_diskaccess = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mapperFDS_block) {
|
||||
case DSK_FILEHDR:
|
||||
if (mapperFDS_diskaddr < mapperFDS_blocklen) {
|
||||
fds_disk() = V;
|
||||
DiskWritten = 1;
|
||||
switch (mapperFDS_diskaddr) {
|
||||
case 13: mapperFDS_filesize = V; break;
|
||||
case 14:
|
||||
mapperFDS_filesize |= V << 8;
|
||||
//char fdsfile[10];
|
||||
//strncpy(fdsfile, (char*)&diskdata[InDisk][mapperFDS_blockstart + 3], 8);
|
||||
//printf("Write file: %s (size: %d)\n"), fdsfile, mapperFDS_filesize);
|
||||
break;
|
||||
}
|
||||
mapperFDS_diskaddr++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (mapperFDS_diskaddr < mapperFDS_blocklen) {
|
||||
fds_disk() = V;
|
||||
DiskWritten = 1;
|
||||
mapperFDS_diskaddr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 0x4025:
|
||||
X6502_IRQEnd(FCEU_IQEXT2);
|
||||
if (InDisk != 255) {
|
||||
if (!(V & 0x40)) {
|
||||
if ((FDSRegs[5] & 0x40) && !(V & 0x10)) {
|
||||
DiskSeekIRQ = 200;
|
||||
DiskPtr -= 2;
|
||||
if (mapperFDS_diskinsert) {
|
||||
if (V & 0x40 && ~mapperFDS_control & 0x40) {
|
||||
mapperFDS_diskaccess = 0;
|
||||
|
||||
DiskSeekIRQ = 150;
|
||||
|
||||
// blockstart - address of block on disk
|
||||
// diskaddr - address relative to blockstart
|
||||
// _block -> _blockID ?
|
||||
mapperFDS_blockstart += mapperFDS_diskaddr;
|
||||
mapperFDS_diskaddr = 0;
|
||||
|
||||
mapperFDS_block++;
|
||||
if (mapperFDS_block > DSK_FILEDATA)
|
||||
mapperFDS_block = DSK_FILEHDR;
|
||||
|
||||
switch (mapperFDS_block) {
|
||||
case DSK_VOLUME:
|
||||
mapperFDS_blocklen = 0x38;
|
||||
break;
|
||||
case DSK_FILECNT:
|
||||
mapperFDS_blocklen = 0x02;
|
||||
break;
|
||||
case DSK_FILEHDR:
|
||||
mapperFDS_blocklen = 0x10;
|
||||
break;
|
||||
case DSK_FILEDATA: // <blockid><filedata>
|
||||
mapperFDS_blocklen = 0x01 + mapperFDS_filesize;
|
||||
break;
|
||||
}
|
||||
if (DiskPtr < 0) DiskPtr = 0;
|
||||
}
|
||||
if (!(V & 0x4)) writeskip = 2;
|
||||
if (V & 2) {
|
||||
DiskPtr = 0; DiskSeekIRQ = 200;
|
||||
|
||||
if (V & 0x02) { // transfer reset
|
||||
mapperFDS_block = DSK_INIT;
|
||||
mapperFDS_blockstart = 0;
|
||||
mapperFDS_blocklen = 0;
|
||||
mapperFDS_diskaddr = 0;
|
||||
DiskSeekIRQ = 150;
|
||||
}
|
||||
if (V & 0x40) { // turn on motor
|
||||
DiskSeekIRQ = 150;
|
||||
}
|
||||
if (V & 0x40) DiskSeekIRQ = 200;
|
||||
}
|
||||
mapperFDS_control = V;
|
||||
setmirror(((V >> 3) & 1) ^ 1);
|
||||
break;
|
||||
}
|
||||
@ -585,6 +696,7 @@ static int SubLoad(FCEUFILE *fp) {
|
||||
uint8 header[16];
|
||||
int x;
|
||||
|
||||
FCEU_fseek(fp, 0, SEEK_SET);
|
||||
FCEU_fread(header, 16, 1, fp);
|
||||
|
||||
if (memcmp(header, "FDS\x1a", 4)) {
|
||||
@ -596,7 +708,7 @@ static int SubLoad(FCEUFILE *fp) {
|
||||
TotalSides = t / 65500;
|
||||
FCEU_fseek(fp, 0, SEEK_SET);
|
||||
} else
|
||||
return(0);
|
||||
return 1;
|
||||
} else
|
||||
TotalSides = header[4];
|
||||
|
||||
@ -606,18 +718,12 @@ static int SubLoad(FCEUFILE *fp) {
|
||||
if (TotalSides < 1) TotalSides = 1;
|
||||
|
||||
for (x = 0; x < TotalSides; x++) {
|
||||
diskdata[x] = (uint8*)FCEU_malloc(65500);
|
||||
if (!diskdata[x]) {
|
||||
int zol;
|
||||
for (zol = 0; zol < x; zol++)
|
||||
free(diskdata[zol]);
|
||||
return 0;
|
||||
}
|
||||
if ((diskdata[x] = (uint8*)FCEU_malloc(65500)) == NULL) return 2;
|
||||
FCEU_fread(diskdata[x], 1, 65500, fp);
|
||||
md5_update(&md5, diskdata[x], 65500);
|
||||
}
|
||||
md5_finish(&md5, GameInfo->MD5.data);
|
||||
return(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void PreSave(void) {
|
||||
@ -643,22 +749,38 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
||||
FILE *zp;
|
||||
#endif
|
||||
int x;
|
||||
|
||||
// try to load FDS image first
|
||||
FreeFDSMemory();
|
||||
int load_result = SubLoad(fp);
|
||||
switch (load_result)
|
||||
{
|
||||
case 1:
|
||||
FreeFDSMemory();
|
||||
return LOADER_INVALID_FORMAT;
|
||||
case 2:
|
||||
FreeFDSMemory();
|
||||
FCEU_PrintError("Unable to allocate memory.");
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
|
||||
// load FDS BIOS next
|
||||
#ifndef GEKKO
|
||||
char *fn = strdup(FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str());
|
||||
|
||||
if (!(zp = FCEUD_UTF8fopen(fn, "rb"))) {
|
||||
FCEU_PrintError("FDS BIOS ROM image missing: %s", FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str());
|
||||
free(fn);
|
||||
return 0;
|
||||
FreeFDSMemory();
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
|
||||
free(fn);
|
||||
|
||||
fseek(zp, 0L, SEEK_END);
|
||||
if (ftell(zp) != 8192) {
|
||||
fclose(zp);
|
||||
FCEU_PrintError("FDS BIOS ROM image incompatible: %s", FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str());
|
||||
return 0;
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
fseek(zp, 0L, SEEK_SET);
|
||||
#endif
|
||||
@ -686,23 +808,13 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
||||
free(FDSBIOS);
|
||||
FDSBIOS = NULL;
|
||||
fclose(zp);
|
||||
FreeFDSMemory();
|
||||
FCEU_PrintError("Error reading FDS BIOS ROM image.");
|
||||
return 0;
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
|
||||
fclose(zp);
|
||||
#endif
|
||||
FCEU_fseek(fp, 0, SEEK_SET);
|
||||
|
||||
FreeFDSMemory();
|
||||
if (!SubLoad(fp)) {
|
||||
#ifndef GEKKO
|
||||
if(FDSBIOS)
|
||||
free(FDSBIOS);
|
||||
FDSBIOS = NULL;
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!disableBatteryLoading) {
|
||||
FCEUFILE *tp;
|
||||
@ -715,15 +827,16 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
||||
}
|
||||
#ifndef GEKKO
|
||||
if ((tp = FCEU_fopen(fn, 0, "rb", 0))) {
|
||||
FCEU_printf("Disk was written. Auxillary FDS file open \"%s\".\n",fn);
|
||||
FCEU_printf("Disk was written. Auxiliary FDS file open \"%s\".\n",fn);
|
||||
FreeFDSMemory();
|
||||
if (!SubLoad(tp)) {
|
||||
FCEU_PrintError("Error reading auxillary FDS file.");
|
||||
if (SubLoad(tp)) {
|
||||
FCEU_PrintError("Error reading auxiliary FDS file.");
|
||||
if(FDSBIOS)
|
||||
free(FDSBIOS);
|
||||
FDSBIOS = NULL;
|
||||
free(fn);
|
||||
return(0);
|
||||
FreeFDSMemory();
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
FCEU_fclose(tp);
|
||||
DiskWritten = 1; /* For save state handling. */
|
||||
@ -761,6 +874,13 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
||||
AddExState(&SelectDisk, 1, 0, "SELD");
|
||||
AddExState(&InDisk, 1, 0, "INDI");
|
||||
AddExState(&DiskWritten, 1, 0, "DSKW");
|
||||
AddExState(&mapperFDS_control, 1, 0, "CTRG");
|
||||
AddExState(&mapperFDS_filesize, 2, 1, "FLSZ");
|
||||
AddExState(&mapperFDS_block, 1, 0, "BLCK");
|
||||
AddExState(&mapperFDS_blockstart, 2, 1, "BLKS");
|
||||
AddExState(&mapperFDS_blocklen, 2, 1, "BLKL");
|
||||
AddExState(&mapperFDS_diskaddr, 2, 1, "DADR");
|
||||
AddExState(&mapperFDS_diskaccess, 1, 0, "DACC");
|
||||
|
||||
CHRRAMSize = 8192;
|
||||
CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize);
|
||||
@ -778,7 +898,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
|
||||
|
||||
FCEUI_SetVidSystem(0);
|
||||
|
||||
return 1;
|
||||
return LOADER_OK;
|
||||
}
|
||||
|
||||
void FDSClose(void) {
|
||||
|
@ -104,12 +104,14 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp)
|
||||
if((offset+size)>(uint32)fp->size)
|
||||
{
|
||||
// Probably a little slow.
|
||||
buf=(char *)realloc(buf,offset+size);
|
||||
if(!buf)
|
||||
char *newbuf=(char *)realloc(buf,offset+size);
|
||||
if(!newbuf)
|
||||
{
|
||||
free(buf); buf=NULL;
|
||||
FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n",count);
|
||||
goto end;
|
||||
}
|
||||
buf=newbuf;
|
||||
memset(buf+fp->size,0,offset+size-fp->size);
|
||||
fp->size=offset+size;
|
||||
}
|
||||
@ -127,12 +129,14 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp)
|
||||
if((offset+size)>(uint32)fp->size)
|
||||
{
|
||||
// Probably a little slow.
|
||||
buf=(char *)realloc(buf,offset+size);
|
||||
if(!buf)
|
||||
char *newbuf=(char *)realloc(buf,offset+size);
|
||||
if(!newbuf)
|
||||
{
|
||||
free(buf); buf=NULL;
|
||||
FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n",count);
|
||||
goto end;
|
||||
}
|
||||
buf=newbuf;
|
||||
memset(buf+fp->size,0,offset+size-fp->size);
|
||||
}
|
||||
fread(buf+offset,1,size,ips);
|
||||
@ -256,14 +260,14 @@ zpfail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext, int index, const char** extensions)
|
||||
FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, const char *mode, char *ext, int index, const char** extensions, int* userCancel)
|
||||
{
|
||||
FILE *ipsfile=0;
|
||||
FCEUFILE *fceufp=0;
|
||||
|
||||
bool read = (std::string)mode == "rb";
|
||||
bool write = (std::string)mode == "wb";
|
||||
if((read&&write) || (!read&&!write))
|
||||
bool read = !strcmp(mode, "rb");
|
||||
bool write = !strcmp(mode, "wb");
|
||||
if(read && write || !read && !write)
|
||||
{
|
||||
FCEU_PrintError("invalid file open mode specified (only wb and rb are supported)");
|
||||
return 0;
|
||||
@ -279,16 +283,28 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext
|
||||
if(read)
|
||||
{
|
||||
ArchiveScanRecord asr = FCEUD_ScanArchive(fileToOpen);
|
||||
if (asr.numFilesInArchive < 0)
|
||||
{
|
||||
// error occurred, return
|
||||
// actually it's canceled not by user but an error message already shown
|
||||
*userCancel = 1;
|
||||
return fceufp;
|
||||
}
|
||||
asr.files.FilterByExtension(extensions);
|
||||
if(!asr.isArchive())
|
||||
{
|
||||
//if the archive contained no files, try to open it the old fashioned way
|
||||
EMUFILE_FILE* fp = FCEUD_UTF8_fstream(fileToOpen,mode);
|
||||
if(!fp || (fp->get_fp() == NULL))
|
||||
if(!fp)
|
||||
return 0;
|
||||
if (fp->get_fp() == NULL)
|
||||
{
|
||||
//fp is new'ed so it has to be deleted
|
||||
delete fp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//try to read a zip file
|
||||
{
|
||||
fceufp = TryUnzip(fileToOpen);
|
||||
@ -355,11 +371,11 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext
|
||||
//open an archive file
|
||||
if(archive == "")
|
||||
if(index != -1)
|
||||
fceufp = FCEUD_OpenArchiveIndex(asr, fileToOpen, index);
|
||||
fceufp = FCEUD_OpenArchiveIndex(asr, fileToOpen, index, userCancel);
|
||||
else
|
||||
fceufp = FCEUD_OpenArchive(asr, fileToOpen, 0);
|
||||
fceufp = FCEUD_OpenArchive(asr, fileToOpen, 0, userCancel);
|
||||
else
|
||||
fceufp = FCEUD_OpenArchive(asr, archive, &fname);
|
||||
fceufp = FCEUD_OpenArchive(asr, archive, &fname, userCancel);
|
||||
|
||||
if(!fceufp) return 0;
|
||||
|
||||
@ -452,6 +468,11 @@ void FCEUI_SetBaseDirectory(std::string const & dir)
|
||||
{
|
||||
BaseDirectory = dir;
|
||||
}
|
||||
/// Gets the base directory
|
||||
const char *FCEUI_GetBaseDirectory(void)
|
||||
{
|
||||
return BaseDirectory.c_str();
|
||||
}
|
||||
|
||||
static char *odirs[FCEUIOD__COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0}; // odirs, odors. ^_^
|
||||
|
||||
@ -470,9 +491,9 @@ void FCEUI_SetDirOverride(int which, char *n)
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap,fmt);
|
||||
if(!(*strp=(char*)FCEU_dmalloc(2048))) //mbg merge 7/17/06 cast to char*
|
||||
return(0);
|
||||
va_start(ap,fmt);
|
||||
ret=vsnprintf(*strp,2048,fmt,ap);
|
||||
va_end(ap);
|
||||
return(ret);
|
||||
|
@ -42,7 +42,7 @@ struct FCEUFILE {
|
||||
|
||||
FCEUFILE()
|
||||
: stream(0)
|
||||
, archiveCount(-1)
|
||||
, archiveCount(-1), archiveIndex(0), size(0), mode(READ)
|
||||
{}
|
||||
|
||||
~FCEUFILE()
|
||||
@ -122,7 +122,7 @@ struct ArchiveScanRecord
|
||||
};
|
||||
|
||||
|
||||
FCEUFILE *FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext, int index=-1, const char** extensions = 0);
|
||||
FCEUFILE *FCEU_fopen(const char *path, const char *ipsfn, const char *mode, char *ext, int index=-1, const char** extensions = 0, int* userCancel = 0);
|
||||
bool FCEU_isFileInArchive(const char *path);
|
||||
int FCEU_fclose(FCEUFILE*);
|
||||
uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, FCEUFILE*);
|
||||
|
@ -1,3 +1,4 @@
|
||||
int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover);
|
||||
void MakeFilters(int32 rate);
|
||||
void SexyFilter(int32 *in, int32 *out, int32 count);
|
||||
void SexyFilter2(int32 *in, int32 count);
|
||||
|
@ -38,8 +38,10 @@ enum ESI
|
||||
SI_MOUSE = 6,
|
||||
SI_SNES = 7,
|
||||
SI_SNES_MOUSE = 8,
|
||||
SI_VIRTUALBOY = 9,
|
||||
SI_LCDCOMP_ZAPPER = 10,
|
||||
|
||||
SI_COUNT = SI_SNES_MOUSE
|
||||
SI_COUNT = SI_LCDCOMP_ZAPPER
|
||||
};
|
||||
|
||||
inline const char* ESI_Name(ESI esi)
|
||||
@ -54,7 +56,9 @@ inline const char* ESI_Name(ESI esi)
|
||||
"Arkanoid Paddle",
|
||||
"Subor Mouse",
|
||||
"SNES Pad",
|
||||
"SNES Mouse"
|
||||
"SNES Mouse",
|
||||
"Virtual Boy",
|
||||
"LCD Zapper (Advance)"
|
||||
};
|
||||
|
||||
if(esi >= SI_NONE && esi <= SI_COUNT)
|
||||
@ -82,8 +86,10 @@ enum ESIFC
|
||||
SIFC_OEKAKIDS = 12,
|
||||
SIFC_BWORLD = 13,
|
||||
SIFC_TOPRIDER = 14,
|
||||
SIFC_FAMINETSYS = 15,
|
||||
SIFC_HORI4PLAYER = 16,
|
||||
|
||||
SIFC_COUNT = SIFC_TOPRIDER
|
||||
SIFC_COUNT = SIFC_HORI4PLAYER
|
||||
};
|
||||
|
||||
|
||||
@ -105,7 +111,9 @@ inline const char* ESIFC_Name(ESIFC esifc)
|
||||
"Family Trainer B",
|
||||
"Oeka Kids Tablet",
|
||||
"Barcode World",
|
||||
"Top Rider"
|
||||
"Top Rider",
|
||||
"Famicom Network Controller",
|
||||
"Hori 4-Player Adapter"
|
||||
};
|
||||
|
||||
if(esifc >= SIFC_NONE && esifc <= SIFC_COUNT)
|
||||
|
@ -1,41 +1,41 @@
|
||||
{ 0xecf78d8a13a030a6LL, "Ai Sensei no Oshiete", INESB_HACKED },
|
||||
{ 0x4712856d3e12f21fLL, "Akumajou Densetsu", INESB_HACKED },
|
||||
{ 0x10f90ba5bd55c22eLL, "Alien Syndrome", INESB_HACKED },
|
||||
{ 0x0d69ab3ad28ad1c2LL, "Banana", INESB_INCOMPLETE },
|
||||
{ 0x85d2c348a161cdbfLL, "Bio Senshi Dan", INESB_HACKED },
|
||||
{ 0x18fdb7c16aa8cb5cLL, "Bucky O'Hare", INESB_CORRUPT },
|
||||
{ 0xe27c48302108d11bLL, "Chibi Maruko Chan", INESB_HACKED },
|
||||
{ 0x9d1f505c6ba507bfLL, "Contra", INESB_HACKED },
|
||||
{ 0x60936436d3ea0ab6LL, "Crisis Force", INESB_HACKED },
|
||||
{ 0xcf31097ddbb03c5dLL, "Crystalis (Prototype)", INESB_CORRUPT },
|
||||
{ 0x92080a8ce94200eaLL, "Digital Devil Story II", INESB_HACKED },
|
||||
{ 0x6c2a2f95c2fe4b6eLL, "Dragon Ball", INESB_HACKED },
|
||||
{ 0x767aaff62963c58fLL, "Dragon Ball", INESB_HACKED },
|
||||
{ 0x97f133d8bc1c28dbLL, "Dragon Ball", INESB_HACKED },
|
||||
{ 0x500b267abb323005LL, "Dragon Warrior 4", INESB_CORRUPT },
|
||||
{ 0x02bdcf375704784bLL, "Erika to Satoru no Yume Bouken", INESB_HACKED },
|
||||
{ 0xd4fea9d2633b9186LL, "Famista 91", INESB_HACKED },
|
||||
{ 0xfdf8c812839b61f0LL, "Famista 92", INESB_HACKED },
|
||||
{ 0xb5bb1d0fb47d0850LL, "Famista 93", INESB_HACKED },
|
||||
{ 0x30471e773f7cdc89LL, "Famista 94", INESB_HACKED },
|
||||
{ 0x76c5c44ffb4a0bd7LL, "Fantasy Zone", INESB_HACKED },
|
||||
{ 0xb470bfb90e2b1049LL, "Fire Emblem Gaiden", INESB_HACKED },
|
||||
{ 0x27da2b0c500dc346LL, "Fire Emblem", INESB_HACKED },
|
||||
{ 0x23214fe456fba2ceLL, "Ganbare Goemon 2", INESB_HACKED },
|
||||
{ 0xbf8b22524e8329d9LL, "Ganbare Goemon Gaiden", INESB_HACKED },
|
||||
{ 0xa97041c3da0134e3LL, "Gegege no Kitarou 2", INESB_INCOMPLETE },
|
||||
{ 0x805db49a86db5449LL, "Goonies", INESB_HACKED },
|
||||
{ 0xc5abdaa65ac49b6bLL, "Gradius 2", INESB_HACKED },
|
||||
{ 0x04afae4ad480c11cLL, "Gradius 2", INESB_HACKED },
|
||||
{ 0x9b4bad37b5498992LL, "Gradius 2", INESB_HACKED },
|
||||
{ 0xb068d4ac10ef848eLL, "Highway Star", INESB_HACKED },
|
||||
{ 0xbf5175271e5019c3LL, "Kaiketsu Yanchamaru 3", INESB_HACKED },
|
||||
{ 0x81c1de64550a1531LL, "Nobunaga no Yabou Zenkokuban", INESB_HACKED },
|
||||
{ 0xfb4b508a236bbba3LL, "Salamander", INESB_HACKED },
|
||||
{ 0x1895afc6eef26c7dLL, "Super Mario Bros.", INESB_HACKED },
|
||||
{ 0x3716c4bebf885344LL, "Super Mario Bros.", INESB_HACKED },
|
||||
{ 0xfffda4407d80885aLL, "Sweet Home", INESB_CORRUPT },
|
||||
{ 0x103fc85d978b861bLL, "Sweet Home", INESB_CORRUPT },
|
||||
{ 0x7979dc51da86f19fLL, "110-in-1", INESB_CORRUPT },
|
||||
{ 0x001c0bb9c358252aLL, "110-in-1", INESB_CORRUPT },
|
||||
{ 0xecf78d8a13a030a6ULL, "Ai Sensei no Oshiete", INESB_HACKED },
|
||||
{ 0x4712856d3e12f21fULL, "Akumajou Densetsu", INESB_HACKED },
|
||||
{ 0x10f90ba5bd55c22eULL, "Alien Syndrome", INESB_HACKED },
|
||||
{ 0x0d69ab3ad28ad1c2ULL, "Banana", INESB_INCOMPLETE },
|
||||
{ 0x85d2c348a161cdbfULL, "Bio Senshi Dan", INESB_HACKED },
|
||||
{ 0x18fdb7c16aa8cb5cULL, "Bucky O'Hare", INESB_CORRUPT },
|
||||
{ 0xe27c48302108d11bULL, "Chibi Maruko Chan", INESB_HACKED },
|
||||
{ 0x9d1f505c6ba507bfULL, "Contra", INESB_HACKED },
|
||||
{ 0x60936436d3ea0ab6ULL, "Crisis Force", INESB_HACKED },
|
||||
{ 0xcf31097ddbb03c5dULL, "Crystalis (Prototype)", INESB_CORRUPT },
|
||||
{ 0x92080a8ce94200eaULL, "Digital Devil Story II", INESB_HACKED },
|
||||
{ 0x6c2a2f95c2fe4b6eULL, "Dragon Ball", INESB_HACKED },
|
||||
{ 0x767aaff62963c58fULL, "Dragon Ball", INESB_HACKED },
|
||||
{ 0x97f133d8bc1c28dbULL, "Dragon Ball", INESB_HACKED },
|
||||
{ 0x500b267abb323005ULL, "Dragon Warrior 4", INESB_CORRUPT },
|
||||
{ 0x02bdcf375704784bULL, "Erika to Satoru no Yume Bouken", INESB_HACKED },
|
||||
{ 0xd4fea9d2633b9186ULL, "Famista 91", INESB_HACKED },
|
||||
{ 0xfdf8c812839b61f0ULL, "Famista 92", INESB_HACKED },
|
||||
{ 0xb5bb1d0fb47d0850ULL, "Famista 93", INESB_HACKED },
|
||||
{ 0x30471e773f7cdc89ULL, "Famista 94", INESB_HACKED },
|
||||
{ 0x76c5c44ffb4a0bd7ULL, "Fantasy Zone", INESB_HACKED },
|
||||
{ 0xb470bfb90e2b1049ULL, "Fire Emblem Gaiden", INESB_HACKED },
|
||||
{ 0x27da2b0c500dc346ULL, "Fire Emblem", INESB_HACKED },
|
||||
{ 0x23214fe456fba2ceULL, "Ganbare Goemon 2", INESB_HACKED },
|
||||
{ 0xbf8b22524e8329d9ULL, "Ganbare Goemon Gaiden", INESB_HACKED },
|
||||
{ 0xa97041c3da0134e3ULL, "Gegege no Kitarou 2", INESB_INCOMPLETE },
|
||||
{ 0x805db49a86db5449ULL, "Goonies", INESB_HACKED },
|
||||
{ 0xc5abdaa65ac49b6bULL, "Gradius 2", INESB_HACKED },
|
||||
{ 0x04afae4ad480c11cULL, "Gradius 2", INESB_HACKED },
|
||||
{ 0x9b4bad37b5498992ULL, "Gradius 2", INESB_HACKED },
|
||||
{ 0xb068d4ac10ef848eULL, "Highway Star", INESB_HACKED },
|
||||
{ 0xbf5175271e5019c3ULL, "Kaiketsu Yanchamaru 3", INESB_HACKED },
|
||||
{ 0x81c1de64550a1531ULL, "Nobunaga no Yabou Zenkokuban", INESB_HACKED },
|
||||
{ 0xfb4b508a236bbba3ULL, "Salamander", INESB_HACKED },
|
||||
{ 0x1895afc6eef26c7dULL, "Super Mario Bros.", INESB_HACKED },
|
||||
{ 0x3716c4bebf885344ULL, "Super Mario Bros.", INESB_HACKED },
|
||||
{ 0xfffda4407d80885aULL, "Sweet Home", INESB_CORRUPT },
|
||||
{ 0x103fc85d978b861bULL, "Sweet Home", INESB_CORRUPT },
|
||||
{ 0x7979dc51da86f19fULL, "110-in-1", INESB_CORRUPT },
|
||||
{ 0x001c0bb9c358252aULL, "110-in-1", INESB_CORRUPT },
|
||||
{ 0, 0, 0 }
|
||||
|
@ -124,7 +124,6 @@
|
||||
{0x054bd3e9, 74, -1}, /* Di 4 Ci - Ji Qi Ren Dai Zhan (As) */
|
||||
{0x496ac8f7, 74, -1}, /* Ji Jia Zhan Shi (As) */
|
||||
{0xae854cef, 74, -1}, /* Jia A Fung Yun (Chinese) */
|
||||
{0xba51ac6f, 78, 2},
|
||||
{0x3d1c3137, 78, 8}, /* Uchuusen - Cosmo Carrier */
|
||||
{0xa4fbb438, 79, 0},
|
||||
{0xd4a76b07, 79, 0}, /* F-15 City Wars*/
|
||||
@ -281,4 +280,6 @@
|
||||
{0x4d4a0e1b, 260|0x1000,-1},
|
||||
{0xb6dd2c9d, 260|0x1000,-1},
|
||||
|
||||
{0xb02fcb57, 406|0x1000,-1}, /* Haradius Zero ver 1.2a 2019 */
|
||||
|
||||
{0x00000000, -1, -1}
|
||||
|
@ -67,7 +67,7 @@ static int iNES_Init(int num);
|
||||
|
||||
static int MapperNo = 0;
|
||||
|
||||
static int iNES2 = 0;
|
||||
int iNES2 = 0;
|
||||
|
||||
static DECLFR(TrainerRead) {
|
||||
return(trainerpoo[A & 0x1FF]);
|
||||
@ -201,7 +201,8 @@ static void SetInput(void) {
|
||||
{0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor
|
||||
{0x8b265862, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor
|
||||
{0x82f1fb96, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor 1.0 Russian
|
||||
{0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa
|
||||
{0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa (bad dump)
|
||||
{0xc7bcc981, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa
|
||||
{0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Super Team Games
|
||||
{0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1
|
||||
{0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Supor English (Chinese)
|
||||
@ -215,6 +216,7 @@ static void SetInput(void) {
|
||||
{0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman
|
||||
{0x5112dc21, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman
|
||||
{0xaf4010ea, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // World Class Track Meet
|
||||
{0x67b126b9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FAMINETSYS }, // Famicom Network System
|
||||
{0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET }
|
||||
};
|
||||
int x = 0;
|
||||
@ -236,7 +238,7 @@ static void SetInput(void) {
|
||||
|
||||
struct BADINF {
|
||||
uint64 md5partial;
|
||||
char *name;
|
||||
const char *name;
|
||||
uint32 type;
|
||||
};
|
||||
|
||||
@ -265,15 +267,15 @@ struct CHINF {
|
||||
};
|
||||
|
||||
static const TMasterRomInfo sMasterRomInfo[] = {
|
||||
{ 0x62b51b108a01d2beLL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes
|
||||
{ 0x8bb48490d8d22711LL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes
|
||||
{ 0xc75888d7b48cd378LL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes
|
||||
{ 0xf81a376fa54fdd69LL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes
|
||||
{ 0xa37eb9163e001a46LL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes
|
||||
{ 0xde5ce25860233f7eLL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes
|
||||
{ 0x5b3aa4cdc484a088LL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes
|
||||
{ 0x9342bf9bae1c798aLL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes
|
||||
{ 0x164eea6097a1e313LL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation
|
||||
{ 0x62b51b108a01d2beULL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes
|
||||
{ 0x8bb48490d8d22711ULL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes
|
||||
{ 0xc75888d7b48cd378ULL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes
|
||||
{ 0xf81a376fa54fdd69ULL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes
|
||||
{ 0xa37eb9163e001a46ULL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes
|
||||
{ 0xde5ce25860233f7eULL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes
|
||||
{ 0x5b3aa4cdc484a088ULL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes
|
||||
{ 0x9342bf9bae1c798aULL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes
|
||||
{ 0x164eea6097a1e313ULL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation
|
||||
};
|
||||
const TMasterRomInfo* MasterRomInfo;
|
||||
TMasterRomInfoParams MasterRomInfoParams;
|
||||
@ -288,38 +290,39 @@ static void CheckHInfo(void) {
|
||||
|
||||
static uint64 savie[] =
|
||||
{
|
||||
0xc04361e499748382LL, /* AD&D Heroes of the Lance */
|
||||
0xb72ee2337ced5792LL, /* AD&D Hillsfar */
|
||||
0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */
|
||||
0x498c10dc463cfe95LL, /* Battle Fleet */
|
||||
0x854d7947a3177f57LL, /* Crystalis */
|
||||
0x4a1f5336b86851b6LL, /* DW */
|
||||
0xb0bcc02c843c1b79LL, /* DW */
|
||||
0x2dcf3a98c7937c22LL, /* DW 2 */
|
||||
0x98e55e09dfcc7533LL, /* DW 4*/
|
||||
0x733026b6b72f2470LL, /* Dw 3 */
|
||||
0x6917ffcaca2d8466LL, /* Famista '90 */
|
||||
0x8da46db592a1fcf4LL, /* Faria */
|
||||
0xedba17a2c4608d20LL, /* Final Fantasy */
|
||||
0x91a6846d3202e3d6LL, /* Final Fantasy */
|
||||
0x012df596e2b31174LL, /* Final Fantasy 1+2 */
|
||||
0xf6b359a720549ecdLL, /* Final Fantasy 2 */
|
||||
0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */
|
||||
0xd63dcc68c2b20adcLL, /* Final Fantasy J */
|
||||
0x2ee3417ba8b69706LL, /* Hydlide 3*/
|
||||
0xebbce5a54cf3ecc0LL, /* Justbreed */
|
||||
0x6a858da551ba239eLL, /* Kaijuu Monogatari */
|
||||
0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */
|
||||
0x04a31647de80fdabLL, /* Legend of Zelda */
|
||||
0x94b9484862a26cbaLL, /* Legend of Zelda */
|
||||
0xa40666740b7d22feLL, /* Mindseeker */
|
||||
0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */
|
||||
0x77b811b2760104b9LL, /* Mouryou Senki Madara */
|
||||
0x11b69122efe86e8cLL, /* RPG Jinsei Game */
|
||||
0x9aa1dc16c05e7de5LL, /* Startropics */
|
||||
0x1b084107d0878bd0LL, /* Startropics 2*/
|
||||
0xa70b495314f4d075LL, /* Ys 3 */
|
||||
0x836c0ff4f3e06e45LL, /* Zelda 2 */
|
||||
0xc04361e499748382ULL, /* AD&D Heroes of the Lance */
|
||||
0xb72ee2337ced5792ULL, /* AD&D Hillsfar */
|
||||
0x2b7103b7a27bd72fULL, /* AD&D Pool of Radiance */
|
||||
0x498c10dc463cfe95ULL, /* Battle Fleet */
|
||||
0x854d7947a3177f57ULL, /* Crystalis */
|
||||
0xfad22d265cd70820ULL, /* Downtown Special: Kunio-kun no Jidaigeki Dayo Zenin Shuugou! */
|
||||
0x4a1f5336b86851b6ULL, /* DW */
|
||||
0xb0bcc02c843c1b79ULL, /* DW */
|
||||
0x2dcf3a98c7937c22ULL, /* DW 2 */
|
||||
0x98e55e09dfcc7533ULL, /* DW 4*/
|
||||
0x733026b6b72f2470ULL, /* Dw 3 */
|
||||
0x6917ffcaca2d8466ULL, /* Famista '90 */
|
||||
0x8da46db592a1fcf4ULL, /* Faria */
|
||||
0xedba17a2c4608d20ULL, /* Final Fantasy */
|
||||
0x91a6846d3202e3d6ULL, /* Final Fantasy */
|
||||
0x012df596e2b31174ULL, /* Final Fantasy 1+2 */
|
||||
0xf6b359a720549ecdULL, /* Final Fantasy 2 */
|
||||
0x5a30da1d9b4af35dULL, /* Final Fantasy 3 */
|
||||
0xd63dcc68c2b20adcULL, /* Final Fantasy J */
|
||||
0x2ee3417ba8b69706ULL, /* Hydlide 3*/
|
||||
0xebbce5a54cf3ecc0ULL, /* Justbreed */
|
||||
0x6a858da551ba239eULL, /* Kaijuu Monogatari */
|
||||
0x2db8f5d16c10b925ULL, /* Kyonshiizu 2 */
|
||||
0x04a31647de80fdabULL, /* Legend of Zelda */
|
||||
0x94b9484862a26cbaULL, /* Legend of Zelda */
|
||||
0xa40666740b7d22feULL, /* Mindseeker */
|
||||
0x82000965f04a71bbULL, /* Mirai Shinwa Jarvas */
|
||||
0x77b811b2760104b9ULL, /* Mouryou Senki Madara */
|
||||
0x11b69122efe86e8cULL, /* RPG Jinsei Game */
|
||||
0x9aa1dc16c05e7de5ULL, /* Startropics */
|
||||
0x1b084107d0878bd0ULL, /* Startropics 2*/
|
||||
0xa70b495314f4d075ULL, /* Ys 3 */
|
||||
0x836c0ff4f3e06e45ULL, /* Zelda 2 */
|
||||
0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */
|
||||
};
|
||||
|
||||
@ -420,7 +423,7 @@ static void CheckHInfo(void) {
|
||||
if (tofix & 1)
|
||||
sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo);
|
||||
if (tofix & 2) {
|
||||
char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" };
|
||||
const char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" };
|
||||
sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]);
|
||||
}
|
||||
if (tofix & 4)
|
||||
@ -443,17 +446,19 @@ typedef struct {
|
||||
//that are not in the power of 2 tends to come
|
||||
//in obscure mappers themselves which supports such
|
||||
//size
|
||||
//Cah4e3 25.10.19: iNES 2.0 attempts to cover all
|
||||
// boards including UNIF boards with non power 2
|
||||
// total rom size (a lot of them with a couple of
|
||||
// roms different sizes (may vary a lot)
|
||||
// so we need either add here ALL ines 2.0 mappers
|
||||
// with not power2 roms or change logic here
|
||||
// to something more unified for ines 2.0 specific
|
||||
static int not_power2[] =
|
||||
{
|
||||
53, 198, 228
|
||||
53, 198, 228, 547
|
||||
};
|
||||
typedef struct {
|
||||
char *name;
|
||||
int32 number;
|
||||
void (*init)(CartInfo *);
|
||||
} BMAPPINGLocal;
|
||||
|
||||
static BMAPPINGLocal bmap[] = {
|
||||
BMAPPINGLocal bmap[] = {
|
||||
{"NROM", 0, NROM_Init},
|
||||
{"MMC1", 1, Mapper1_Init},
|
||||
{"UNROM", 2, UNROM_Init},
|
||||
@ -672,9 +677,9 @@ static BMAPPINGLocal bmap[] = {
|
||||
{"", 215, UNL8237_Init},
|
||||
{"", 216, Mapper216_Init},
|
||||
{"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper
|
||||
// {"", 218, Mapper218_Init},
|
||||
{"Magic Floor", 218, Mapper218_Init},
|
||||
{"UNLA9746", 219, UNLA9746_Init},
|
||||
{"Debug Mapper", 220, UNLKS7057_Init},
|
||||
{"Debug Mapper", 220, QTAi_Init},
|
||||
{"UNLN625092", 221, UNLN625092_Init},
|
||||
{"", 222, Mapper222_Init},
|
||||
// {"", 223, Mapper223_Init},
|
||||
@ -725,7 +730,12 @@ static BMAPPINGLocal bmap[] = {
|
||||
{"158B Prot Board", 258, UNL158B_Init},
|
||||
{"F-15 MMC3 Based", 259, BMCF15_Init},
|
||||
{"HP10xx/H20xx Boards", 260, BMCHPxx_Init},
|
||||
{"810544-CA-1", 261, BMC810544CA1_Init},
|
||||
{"810544-CA-1", 261, BMC810544CA1_Init},
|
||||
{"SMD132/SMD133", 268, SMD132_SMD133_Init},
|
||||
|
||||
{"Impact Soft MMC3 Flash Board", 406, Mapper406_Init },
|
||||
|
||||
{"KONAMI QTAi Board", 547, QTAi_Init },
|
||||
|
||||
{"", 0, NULL}
|
||||
};
|
||||
@ -733,11 +743,8 @@ static BMAPPINGLocal bmap[] = {
|
||||
int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
struct md5_context md5;
|
||||
|
||||
if (FCEU_fread(&head, 1, 16, fp) != 16)
|
||||
return 0;
|
||||
|
||||
if (memcmp(&head, "NES\x1a", 4))
|
||||
return 0;
|
||||
if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4))
|
||||
return LOADER_INVALID_FORMAT;
|
||||
|
||||
head.cleanup();
|
||||
|
||||
@ -763,8 +770,18 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
} else
|
||||
Mirroring = (head.ROM_type & 1);
|
||||
|
||||
int not_round_size = head.ROM_size;
|
||||
if(iNES2) not_round_size |= ((head.Upper_ROM_VROM_size & 0x0F) << 8);
|
||||
int not_round_size;
|
||||
if (!iNES2) {
|
||||
not_round_size = head.ROM_size;
|
||||
}
|
||||
else {
|
||||
if ((head.Upper_ROM_VROM_size & 0x0F) != 0x0F)
|
||||
// simple notation
|
||||
not_round_size = head.ROM_size | ((head.Upper_ROM_VROM_size & 0x0F) << 8);
|
||||
else
|
||||
// exponent-multiplier notation
|
||||
not_round_size = ((1 << (head.ROM_size >> 2)) * ((head.ROM_size & 0b11) * 2 + 1)) >> 14;
|
||||
}
|
||||
|
||||
if (!head.ROM_size && !iNES2)
|
||||
ROM_size = 256;
|
||||
@ -772,6 +789,16 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
ROM_size = uppow2(not_round_size);
|
||||
|
||||
VROM_size = uppow2(head.VROM_size | (iNES2?((head.Upper_ROM_VROM_size & 0xF0)<<4):0));
|
||||
if (!iNES2) {
|
||||
VROM_size = uppow2(head.VROM_size);
|
||||
}
|
||||
else {
|
||||
if ((head.Upper_ROM_VROM_size & 0xF0) != 0xF0)
|
||||
// simple notation
|
||||
VROM_size = uppow2(head.VROM_size | ((head.Upper_ROM_VROM_size & 0xF0) << 4));
|
||||
else
|
||||
VROM_size = ((1 << (head.VROM_size >> 2)) * ((head.VROM_size & 0b11) * 2 + 1)) >> 13;
|
||||
}
|
||||
|
||||
int round = true;
|
||||
for (int i = 0; i != sizeof(not_power2) / sizeof(not_power2[0]); ++i) {
|
||||
@ -794,7 +821,8 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) {
|
||||
free(ROM);
|
||||
ROM = NULL;
|
||||
return 0;
|
||||
FCEU_PrintError("Unable to allocate memory.");
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
memset(VROM, 0xFF, VROM_size << 13);
|
||||
}
|
||||
@ -828,9 +856,9 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
|
||||
iNESCart.CRC32 = iNESGameCRC32;
|
||||
|
||||
FCEU_printf(" PRG ROM: %3d x 16KiB\n", (round) ? ROM_size: not_round_size);
|
||||
FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size);
|
||||
FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32);
|
||||
FCEU_printf(" PRG ROM: %d x 16KiB = %d KiB\n", round ? ROM_size : not_round_size, (round ? ROM_size : not_round_size) * 16);
|
||||
FCEU_printf(" CHR ROM: %d x 8KiB = %d KiB\n", VROM_size, VROM_size * 8);
|
||||
FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32);
|
||||
{
|
||||
int x;
|
||||
FCEU_printf(" ROM MD5: 0x");
|
||||
@ -839,7 +867,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
FCEU_printf("\n");
|
||||
}
|
||||
|
||||
char* mappername = "Not Listed";
|
||||
const char* mappername = "Not Listed";
|
||||
|
||||
for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
|
||||
if (bmap[mappertest].number == MapperNo) {
|
||||
@ -848,7 +876,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
}
|
||||
}
|
||||
|
||||
FCEU_printf(" Mapper #: %d\n", MapperNo);
|
||||
FCEU_printf(" Mapper #: %d\n", MapperNo);
|
||||
FCEU_printf(" Mapper name: %s\n", mappername);
|
||||
FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal");
|
||||
FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No");
|
||||
@ -857,12 +885,12 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
{
|
||||
FCEU_printf(" NES2.0 Extensions\n");
|
||||
FCEU_printf(" Sub Mapper #: %d\n", iNESCart.submapper);
|
||||
FCEU_printf(" Total WRAM size: %d\n", iNESCart.wram_size + iNESCart.battery_wram_size);
|
||||
FCEU_printf(" Total VRAM size: %d\n", iNESCart.vram_size + iNESCart.battery_vram_size);
|
||||
FCEU_printf(" Total WRAM size: %d KiB\n", (iNESCart.wram_size + iNESCart.battery_wram_size) / 1024);
|
||||
FCEU_printf(" Total VRAM size: %d KiB\n", (iNESCart.vram_size + iNESCart.battery_vram_size) / 1024);
|
||||
if(head.ROM_type & 2)
|
||||
{
|
||||
FCEU_printf(" WRAM backed by battery: %d\n", iNESCart.battery_wram_size);
|
||||
FCEU_printf(" VRAM backed by battery: %d\n", iNESCart.battery_vram_size);
|
||||
FCEU_printf(" WRAM backed by battery: %d KiB\n", iNESCart.battery_wram_size / 1024);
|
||||
FCEU_printf(" VRAM backed by battery: %d KiB\n", iNESCart.battery_vram_size / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
@ -895,8 +923,29 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
iNESCart.battery = (head.ROM_type & 2) ? 1 : 0;
|
||||
iNESCart.mirror = Mirroring;
|
||||
|
||||
if (!iNES_Init(MapperNo))
|
||||
int result = iNES_Init(MapperNo);
|
||||
switch(result)
|
||||
{
|
||||
case 0:
|
||||
goto init_ok;
|
||||
case 1:
|
||||
FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo);
|
||||
break;
|
||||
case 2:
|
||||
FCEU_PrintError("Unable to allocate CHR-RAM.");
|
||||
break;
|
||||
}
|
||||
if (ROM) free(ROM);
|
||||
if (VROM) free(VROM);
|
||||
if (trainerpoo) free(trainerpoo);
|
||||
if (ExtraNTARAM) free(ExtraNTARAM);
|
||||
ROM = NULL;
|
||||
VROM = NULL;
|
||||
trainerpoo = NULL;
|
||||
ExtraNTARAM = NULL;
|
||||
return LOADER_HANDLED_ERROR;
|
||||
|
||||
init_ok:
|
||||
|
||||
GameInfo->mappernum = MapperNo;
|
||||
FCEU_LoadGameSave(&iNESCart);
|
||||
@ -921,10 +970,6 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
FCEUI_SetVidSystem(((head.TV_system & 3) == 1) ? 1 : 0);
|
||||
} else if (OverwriteVidMode) {
|
||||
if (strstr(name, "(E)") || strstr(name, "(e)")
|
||||
|| strstr(name, "(Europe)") || strstr(name, "(PAL)")
|
||||
|| strstr(name, "(F)") || strstr(name, "(f)")
|
||||
|| strstr(name, "(G)") || strstr(name, "(g)")
|
||||
|| strstr(name, "(I)") || strstr(name, "(i)")
|
||||
|| strstr(name, "(Europe)") || strstr(name, "(PAL)")
|
||||
|| strstr(name, "(F)") || strstr(name, "(f)")
|
||||
|| strstr(name, "(G)") || strstr(name, "(g)")
|
||||
@ -939,11 +984,11 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|
||||
else
|
||||
FCEUI_SetVidSystem(0);
|
||||
}
|
||||
return 1;
|
||||
return LOADER_OK;
|
||||
}
|
||||
|
||||
// bbit edited: the whole function below was added
|
||||
int iNesSave() {
|
||||
int iNesSave(void) {
|
||||
char name[2048];
|
||||
|
||||
strcpy(name, LoadedRomFName);
|
||||
@ -954,7 +999,7 @@ int iNesSave() {
|
||||
return iNesSaveAs(name);
|
||||
}
|
||||
|
||||
int iNesSaveAs(char* name)
|
||||
int iNesSaveAs(const char* name)
|
||||
{
|
||||
//adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function
|
||||
//caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename.
|
||||
@ -989,7 +1034,7 @@ int iNesSaveAs(char* name)
|
||||
}
|
||||
|
||||
//para edit: added function below
|
||||
char *iNesShortFName() {
|
||||
char *iNesShortFName(void) {
|
||||
char *ret;
|
||||
|
||||
if (!(ret = strrchr(LoadedRomFName, '\\')))
|
||||
@ -1010,7 +1055,7 @@ static int iNES_Init(int num) {
|
||||
|
||||
while (tmp->init) {
|
||||
if (num == tmp->number) {
|
||||
UNIFchrrama = 0; // need here for compatibility with UNIF mapper code
|
||||
UNIFchrrama = NULL; // need here for compatibility with UNIF mapper code
|
||||
if (!VROM_size) {
|
||||
if(!iNESCart.ines2)
|
||||
{
|
||||
@ -1030,29 +1075,31 @@ static int iNES_Init(int num) {
|
||||
{
|
||||
CHRRAMSize = iNESCart.battery_vram_size + iNESCart.vram_size;
|
||||
}
|
||||
if ((VROM = (uint8*)FCEU_dmalloc(CHRRAMSize)) == NULL) return 0;
|
||||
FCEU_MemoryRand(VROM, CHRRAMSize);
|
||||
|
||||
UNIFchrrama = VROM;
|
||||
if(CHRRAMSize == 0)
|
||||
{
|
||||
//probably a mistake.
|
||||
//but (for chrram): "Use of $00 with no CHR ROM implies that the game is wired to map nametable memory in CHR space. The value $00 MUST NOT be used if a mapper isn't defined to allow this. "
|
||||
//well, i'm not going to do that now. we'll save it for when it's needed
|
||||
//"it's only mapper 218 and no other mappers"
|
||||
}
|
||||
else
|
||||
if (CHRRAMSize > 0)
|
||||
{
|
||||
int mCHRRAMSize = (CHRRAMSize < 1024) ? 1024 : CHRRAMSize; // VPage has a resolution of 1k banks, ensure minimum allocation to prevent malicious access from NES software
|
||||
if ((UNIFchrrama = VROM = (uint8*)FCEU_dmalloc(mCHRRAMSize)) == NULL) return 2;
|
||||
FCEU_MemoryRand(VROM, CHRRAMSize);
|
||||
SetupCartCHRMapping(0, VROM, CHRRAMSize, 1);
|
||||
AddExState(VROM, CHRRAMSize, 0, "CHRR");
|
||||
}
|
||||
else {
|
||||
// mapper 256 (OneBus) has not CHR-RAM _and_ has not CHR-ROM region in iNES file
|
||||
// so zero-sized CHR should be supported at least for this mapper
|
||||
VROM = NULL;
|
||||
}
|
||||
}
|
||||
if (head.ROM_type & 8)
|
||||
AddExState(ExtraNTARAM, 2048, 0, "EXNR");
|
||||
{
|
||||
if (ExtraNTARAM != NULL)
|
||||
{
|
||||
AddExState(ExtraNTARAM, 2048, 0, "EXNR");
|
||||
}
|
||||
}
|
||||
tmp->init(&iNESCart);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -43,48 +43,43 @@ extern uint8 *VROM;
|
||||
extern uint32 VROM_size;
|
||||
extern uint32 ROM_size;
|
||||
extern uint8 *ExtraNTARAM;
|
||||
extern int iNesSave(); //bbit Edited: line added
|
||||
extern int iNesSaveAs(char* name);
|
||||
extern int iNesSave(void); //bbit Edited: line added
|
||||
extern int iNesSaveAs(const char* name);
|
||||
extern char LoadedRomFName[2048]; //bbit Edited: line added
|
||||
extern char *iNesShortFName(void);
|
||||
extern const TMasterRomInfo* MasterRomInfo;
|
||||
extern TMasterRomInfoParams MasterRomInfoParams;
|
||||
|
||||
//mbg merge 7/19/06 changed to c++ decl format
|
||||
struct iNES_HEADER {
|
||||
char ID[4]; /*NES^Z*/
|
||||
uint8 ROM_size;
|
||||
uint8 VROM_size;
|
||||
uint8 ROM_type;
|
||||
uint8 ROM_type2;
|
||||
uint8 ROM_type3;
|
||||
uint8 Upper_ROM_VROM_size;
|
||||
uint8 RAM_size;
|
||||
uint8 VRAM_size;
|
||||
uint8 TV_system;
|
||||
uint8 VS_hardware;
|
||||
uint8 reserved[2];
|
||||
char ID[4]; /*NES^Z*/ // 0-3
|
||||
uint8 ROM_size; // 4
|
||||
uint8 VROM_size; // 5
|
||||
uint8 ROM_type; // 6
|
||||
uint8 ROM_type2; // 7
|
||||
uint8 ROM_type3; // 8
|
||||
uint8 Upper_ROM_VROM_size; // 9
|
||||
uint8 RAM_size; // 10
|
||||
uint8 VRAM_size; // 11
|
||||
uint8 TV_system; // 12
|
||||
uint8 VS_hardware; // 13
|
||||
uint8 reserved[2]; // 14, 15
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(!memcmp((char *)(this)+0x7,"DiskDude",8))
|
||||
{
|
||||
memset((char *)(this)+0x7,0,0x9);
|
||||
}
|
||||
if(!memcmp((char*)(this) + 0x7, "DiskDude", 8) || !memcmp((char*)(this) + 0x7, "demiforce", 9))
|
||||
memset((char*)(this) + 0x7, 0, 0x9);
|
||||
|
||||
if(!memcmp((char *)(this)+0x7,"demiforce",9))
|
||||
if(!memcmp((char*)(this) + 0xA, "Ni03", 4))
|
||||
{
|
||||
memset((char *)(this)+0x7,0,0x9);
|
||||
}
|
||||
|
||||
if(!memcmp((char *)(this)+0xA,"Ni03",4))
|
||||
{
|
||||
if(!memcmp((char *)(this)+0x7,"Dis",3))
|
||||
memset((char *)(this)+0x7,0,0x9);
|
||||
if(!memcmp((char*)(this) + 0x7, "Dis", 3))
|
||||
memset((char*)(this) + 0x7, 0, 0x9);
|
||||
else
|
||||
memset((char *)(this)+0xA,0,0x6);
|
||||
memset((char*)(this) + 0xA, 0, 0x6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern struct iNES_HEADER head; //for mappers usage
|
||||
|
||||
void NSFVRC6_Init(void);
|
||||
@ -220,6 +215,7 @@ void Mapper186_Init(CartInfo *);
|
||||
void Mapper187_Init(CartInfo *);
|
||||
void Mapper188_Init(CartInfo *);
|
||||
void Mapper189_Init(CartInfo *);
|
||||
void Mapper190_Init(CartInfo *);
|
||||
void Mapper191_Init(CartInfo *);
|
||||
void Mapper192_Init(CartInfo *);
|
||||
void Mapper193_Init(CartInfo *);
|
||||
@ -246,6 +242,7 @@ void Mapper213_Init(CartInfo *);
|
||||
void Mapper214_Init(CartInfo *);
|
||||
void Mapper216_Init(CartInfo *);
|
||||
void Mapper217_Init(CartInfo *);
|
||||
void Mapper218_Init(CartInfo *);
|
||||
void Mapper220_Init(CartInfo *);
|
||||
void Mapper222_Init(CartInfo *);
|
||||
void Mapper225_Init(CartInfo *);
|
||||
@ -272,5 +269,11 @@ void Mapper250_Init(CartInfo *);
|
||||
void Mapper252_Init(CartInfo *);
|
||||
void Mapper253_Init(CartInfo *);
|
||||
void Mapper254_Init(CartInfo *);
|
||||
void Mapper406_Init(CartInfo *);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int32 number;
|
||||
void (*init)(CartInfo *);
|
||||
} BMAPPINGLocal;
|
||||
#endif
|
||||
|
@ -64,6 +64,8 @@ extern INPUTC *FCEU_InitPowerpadB(int w);
|
||||
extern INPUTC *FCEU_InitArkanoid(int w);
|
||||
extern INPUTC *FCEU_InitMouse(int w);
|
||||
extern INPUTC *FCEU_InitSNESMouse(int w);
|
||||
extern INPUTC *FCEU_InitVirtualBoy(int w);
|
||||
extern INPUTC *FCEU_InitLCDCompZapper(int w);
|
||||
|
||||
extern INPUTCFC *FCEU_InitArkanoidFC(void);
|
||||
extern INPUTCFC *FCEU_InitSpaceShadow(void);
|
||||
@ -77,6 +79,7 @@ extern INPUTCFC *FCEU_InitFamilyTrainerA(void);
|
||||
extern INPUTCFC *FCEU_InitFamilyTrainerB(void);
|
||||
extern INPUTCFC *FCEU_InitOekaKids(void);
|
||||
extern INPUTCFC *FCEU_InitTopRider(void);
|
||||
extern INPUTCFC *FCEU_InitFamiNetSys(void);
|
||||
extern INPUTCFC *FCEU_InitBarcodeWorld(void);
|
||||
//---------------
|
||||
|
||||
@ -370,7 +373,39 @@ static void StrobeSNES(int w)
|
||||
|
||||
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
//--------Hori 4 player driver for expansion port--------
|
||||
static uint8 Hori4ReadBit[2];
|
||||
static void StrobeHori4(void)
|
||||
{
|
||||
Hori4ReadBit[0] = Hori4ReadBit[1] = 0;
|
||||
}
|
||||
|
||||
static uint8 ReadHori4(int w, uint8 ret)
|
||||
{
|
||||
ret &= 1;
|
||||
|
||||
if (Hori4ReadBit[w] < 8)
|
||||
{
|
||||
ret |= ((joy[w] >> (Hori4ReadBit[w])) & 1) << 1;
|
||||
}
|
||||
else if (Hori4ReadBit[w] < 16)
|
||||
{
|
||||
ret |= ((joy[2 + w] >> (Hori4ReadBit[w] - 8)) & 1) << 1;
|
||||
}
|
||||
else if (Hori4ReadBit[w] < 24)
|
||||
{
|
||||
ret |= (((w ? 0x10 : 0x20) >> (7 - (Hori4ReadBit[w] - 16))) & 1) << 1;
|
||||
}
|
||||
if (Hori4ReadBit[w] >= 24) ret |= 2;
|
||||
else Hori4ReadBit[w]++;
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static INPUTCFC HORI4C = { ReadHori4,0,StrobeHori4,0,0,0 };
|
||||
//------------------
|
||||
|
||||
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
static INPUTC GPC={ReadGP,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP};
|
||||
static INPUTC GPCVS={ReadGPVS,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP};
|
||||
@ -451,9 +486,16 @@ static void SetInputStuff(int port)
|
||||
switch(joyports[port].type)
|
||||
{
|
||||
case SI_GAMEPAD:
|
||||
if(GameInfo->type==GIT_VSUNI){
|
||||
joyports[port].driver = &GPCVS;
|
||||
} else {
|
||||
if (GameInfo)
|
||||
{
|
||||
if (GameInfo->type==GIT_VSUNI){
|
||||
joyports[port].driver = &GPCVS;
|
||||
} else {
|
||||
joyports[port].driver= &GPC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
joyports[port].driver= &GPC;
|
||||
}
|
||||
break;
|
||||
@ -478,7 +520,14 @@ static void SetInputStuff(int port)
|
||||
case SI_SNES_MOUSE:
|
||||
joyports[port].driver=FCEU_InitSNESMouse(port);
|
||||
break;
|
||||
case SI_VIRTUALBOY:
|
||||
joyports[port].driver=FCEU_InitVirtualBoy(port);
|
||||
break;
|
||||
case SI_LCDCOMP_ZAPPER:
|
||||
joyports[port].driver = FCEU_InitLCDCompZapper(port);
|
||||
break;
|
||||
case SI_NONE:
|
||||
case SI_UNSET:
|
||||
joyports[port].driver=&DummyJPort;
|
||||
break;
|
||||
}
|
||||
@ -489,6 +538,7 @@ static void SetInputStuffFC()
|
||||
switch(portFC.type)
|
||||
{
|
||||
case SIFC_NONE:
|
||||
case SIFC_UNSET:
|
||||
portFC.driver=&DummyPortFC;
|
||||
break;
|
||||
case SIFC_ARKANOID:
|
||||
@ -534,6 +584,13 @@ static void SetInputStuffFC()
|
||||
case SIFC_TOPRIDER:
|
||||
portFC.driver=FCEU_InitTopRider();
|
||||
break;
|
||||
case SIFC_FAMINETSYS:
|
||||
portFC.driver = FCEU_InitFamiNetSys();
|
||||
break;
|
||||
case SIFC_HORI4PLAYER:
|
||||
portFC.driver = &HORI4C;
|
||||
memset(&Hori4ReadBit, 0, sizeof(Hori4ReadBit));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -643,7 +700,7 @@ void FCEUI_FDSSelect(void)
|
||||
if(!FCEU_IsValidUI(FCEUI_SWITCH_DISK))
|
||||
return;
|
||||
|
||||
FCEU_DispMessage("Command: Switch disk side", 0);
|
||||
// FCEU_DispMessage("Command: Switch disk side", 0);
|
||||
FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
|
||||
}
|
||||
|
||||
@ -652,7 +709,7 @@ void FCEUI_FDSInsert(void)
|
||||
if(!FCEU_IsValidUI(FCEUI_EJECT_DISK))
|
||||
return;
|
||||
|
||||
FCEU_DispMessage("Command: Insert/Eject disk", 0);
|
||||
// FCEU_DispMessage("Command: Insert/Eject disk", 0);
|
||||
FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
|
||||
}
|
||||
|
||||
@ -713,7 +770,7 @@ const char* FCEUI_CommandTypeNames[]=
|
||||
"TAS Editor",
|
||||
};
|
||||
|
||||
static void CommandUnImpl(void);
|
||||
//static void CommandUnImpl(void);
|
||||
static void CommandToggleDip(void);
|
||||
static void CommandStateLoad(void);
|
||||
static void CommandStateSave(void);
|
||||
@ -813,8 +870,17 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
|
||||
{ EMUCMD_MOVIE_RECORD_TO, EMUCMDTYPE_MOVIE, FCEUD_MovieRecordTo, 0, 0, "Record Movie To...", 0 },
|
||||
{ EMUCMD_MOVIE_REPLAY_FROM, EMUCMDTYPE_MOVIE, FCEUD_MovieReplayFrom, 0, 0, "Play Movie From...", 0 },
|
||||
{ EMUCMD_MOVIE_PLAY_FROM_BEGINNING, EMUCMDTYPE_MOVIE, FCEUI_MoviePlayFromBeginning, 0, 0, "Play Movie From Beginning", EMUCMDFLAG_TASEDITOR },
|
||||
{ EMUCMD_MOVIE_TOGGLE_RECORDING, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleRecording, 0, 0, "Toggle Movie Recording/Playing", 0 },
|
||||
{ EMUCMD_MOVIE_INSERT_1_FRAME, EMUCMDTYPE_MOVIE, FCEUI_MovieInsertFrame, 0, 0, "Insert 1 Frame To Movie", 0 },
|
||||
{ EMUCMD_MOVIE_DELETE_1_FRAME, EMUCMDTYPE_MOVIE, FCEUI_MovieDeleteFrame, 0, 0, "Delete 1 Frame From Movie", 0 },
|
||||
{ EMUCMD_MOVIE_TRUNCATE, EMUCMDTYPE_MOVIE, FCEUI_MovieTruncate, 0, 0, "Truncate Movie At Current Frame", 0 },
|
||||
{ EMUCMD_MOVIE_STOP, EMUCMDTYPE_MOVIE, FCEUI_StopMovie, 0, 0, "Stop Movie", 0 },
|
||||
{ EMUCMD_MOVIE_READONLY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleReadOnly, 0, 0, "Toggle Read-Only", EMUCMDFLAG_TASEDITOR },
|
||||
{ EMUCMD_MOVIE_NEXT_RECORD_MODE, EMUCMDTYPE_MOVIE, FCEUI_MovieNextRecordMode, 0, 0, "Next Record Mode", 0 },
|
||||
{ EMUCMD_MOVIE_PREV_RECORD_MODE, EMUCMDTYPE_MOVIE, FCEUI_MoviePrevRecordMode, 0, 0, "Prev Record Mode", 0 },
|
||||
{ EMUCMD_MOVIE_RECORD_MODE_TRUNCATE, EMUCMDTYPE_MOVIE, FCEUI_MovieRecordModeTruncate, 0, 0, "Record Mode Truncate", 0 },
|
||||
{ EMUCMD_MOVIE_RECORD_MODE_OVERWRITE, EMUCMDTYPE_MOVIE, FCEUI_MovieRecordModeOverwrite, 0, 0, "Record Mode Overwrite", 0 },
|
||||
{ EMUCMD_MOVIE_RECORD_MODE_INSERT, EMUCMDTYPE_MOVIE, FCEUI_MovieRecordModeInsert, 0, 0, "Record Mode Insert", 0 },
|
||||
{ EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Toggle Frame Display", EMUCMDFLAG_TASEDITOR },
|
||||
{ EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleInputDisplay, 0, 0, "Toggle Input Display", EMUCMDFLAG_TASEDITOR },
|
||||
{ EMUCMD_MOVIE_ICON_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUD_ToggleStatusIcon, 0, 0, "Toggle Status Icon", EMUCMDFLAG_TASEDITOR },
|
||||
@ -921,10 +987,11 @@ void FCEUI_HandleEmuCommands(TestCommandState* testfn)
|
||||
}
|
||||
}
|
||||
|
||||
static void CommandUnImpl(void)
|
||||
{
|
||||
FCEU_DispMessage("command '%s' unimplemented.",0, FCEUI_CommandTable[i].name);
|
||||
}
|
||||
// Function not currently used
|
||||
//static void CommandUnImpl(void)
|
||||
//{
|
||||
// FCEU_DispMessage("command '%s' unimplemented.",0, FCEUI_CommandTable[i].name);
|
||||
//}
|
||||
|
||||
static void CommandToggleDip(void)
|
||||
{
|
||||
@ -948,7 +1015,7 @@ static void CommandSelectSaveSlot(void)
|
||||
{
|
||||
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
handleEmuCmdByTaseditor(execcmd);
|
||||
#endif
|
||||
} else
|
||||
@ -966,7 +1033,7 @@ static void CommandStateSave(void)
|
||||
{
|
||||
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
handleEmuCmdByTaseditor(execcmd);
|
||||
#endif
|
||||
} else
|
||||
@ -1058,64 +1125,64 @@ static void LaunchTasEditor(void)
|
||||
|
||||
static void LaunchMemoryWatch(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
CreateMemWatch();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchDebugger(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoDebug(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchNTView(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoNTView();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchPPU(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoPPUView();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchHex(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoMemView();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchTraceLogger(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoTracer();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchCodeDataLogger(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoCDLogger();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchCheats(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
extern HWND pwindow;
|
||||
ConfigCheats(pwindow);
|
||||
#ifdef __WIN_DRIVER__
|
||||
extern HWND hCheat;
|
||||
ConfigCheats(hCheat);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LaunchRamWatch(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
extern void OpenRamWatch(); //adelikat: Blah blah hacky, I know
|
||||
OpenRamWatch();
|
||||
#endif
|
||||
@ -1123,14 +1190,14 @@ static void LaunchRamWatch(void)
|
||||
|
||||
static void LaunchRamSearch(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
extern void OpenRamSearch();
|
||||
OpenRamSearch();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void RamSearchOpLT(void) {
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (GameInfo)
|
||||
{
|
||||
extern void SetSearchType(int SearchType);
|
||||
@ -1142,7 +1209,7 @@ static void RamSearchOpLT(void) {
|
||||
}
|
||||
|
||||
static void RamSearchOpGT(void) {
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (GameInfo)
|
||||
{
|
||||
extern void SetSearchType(int SearchType);
|
||||
@ -1154,7 +1221,7 @@ static void RamSearchOpGT(void) {
|
||||
}
|
||||
|
||||
static void RamSearchOpLTE(void) {
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (GameInfo)
|
||||
{
|
||||
extern void SetSearchType(int SearchType);
|
||||
@ -1166,7 +1233,7 @@ static void RamSearchOpLTE(void) {
|
||||
}
|
||||
|
||||
static void RamSearchOpGTE(void) {
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (GameInfo)
|
||||
{
|
||||
extern void SetSearchType(int SearchType);
|
||||
@ -1178,7 +1245,7 @@ static void RamSearchOpGTE(void) {
|
||||
}
|
||||
|
||||
static void RamSearchOpEQ(void) {
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (GameInfo)
|
||||
{
|
||||
extern void SetSearchType(int SearchType);
|
||||
@ -1190,7 +1257,7 @@ static void RamSearchOpEQ(void) {
|
||||
}
|
||||
|
||||
static void RamSearchOpNE(void) {
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (GameInfo)
|
||||
{
|
||||
extern void SetSearchType(int SearchType);
|
||||
@ -1203,7 +1270,7 @@ static void RamSearchOpNE(void) {
|
||||
|
||||
static void DebuggerStepInto()
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (GameInfo)
|
||||
{
|
||||
extern void DoDebuggerStepInto();
|
||||
@ -1219,7 +1286,7 @@ static void FA_SkipLag(void)
|
||||
|
||||
static void OpenRom(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
extern HWND hAppWnd;
|
||||
LoadNewGamey(hAppWnd, 0);
|
||||
#endif
|
||||
@ -1227,14 +1294,14 @@ static void OpenRom(void)
|
||||
|
||||
static void CloseRom(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
CloseGame();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ReloadRom(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
|
||||
{
|
||||
// load most recent project
|
||||
@ -1266,14 +1333,14 @@ static void UndoRedoSavestate(void)
|
||||
|
||||
static void FCEUI_DoExit(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
DoFCEUExit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ToggleFullscreen()
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
extern int SetVideoMode(int fs); //adelikat: Yeah, I know, hacky
|
||||
extern void UpdateCheckedMenuItems();
|
||||
|
||||
@ -1289,21 +1356,34 @@ void ToggleFullscreen()
|
||||
|
||||
static void TaseditorRewindOn(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
mustRewindNow = true;
|
||||
#endif
|
||||
}
|
||||
static void TaseditorRewindOff(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
mustRewindNow = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void TaseditorCommand(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
|
||||
handleEmuCmdByTaseditor(execcmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get command info entry by command number
|
||||
**/
|
||||
EMUCMDTABLE* GetEmuCommandById(int cmd)
|
||||
{
|
||||
for (i = 0; i<NUM_EMU_CMDS; ++i)
|
||||
{
|
||||
if (FCEUI_CommandTable[i].cmd == cmd)
|
||||
return &FCEUI_CommandTable[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ struct INPUTCFC
|
||||
extern struct JOYPORT
|
||||
{
|
||||
JOYPORT(int _w)
|
||||
: w(_w)
|
||||
: w(_w), attrib(0), type(SI_UNSET), ptr(0), driver(0)
|
||||
{}
|
||||
|
||||
int w;
|
||||
@ -248,6 +248,17 @@ enum EMUCMD
|
||||
EMUCMD_FPS_DISPLAY_TOGGLE,
|
||||
EMUCMD_TOOL_DEBUGSTEPINTO,
|
||||
|
||||
EMUCMD_MOVIE_TOGGLE_RECORDING,
|
||||
EMUCMD_MOVIE_TRUNCATE,
|
||||
EMUCMD_MOVIE_INSERT_1_FRAME,
|
||||
EMUCMD_MOVIE_DELETE_1_FRAME,
|
||||
|
||||
EMUCMD_MOVIE_NEXT_RECORD_MODE,
|
||||
EMUCMD_MOVIE_PREV_RECORD_MODE,
|
||||
EMUCMD_MOVIE_RECORD_MODE_TRUNCATE,
|
||||
EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,
|
||||
EMUCMD_MOVIE_RECORD_MODE_INSERT,
|
||||
|
||||
EMUCMD_MAX
|
||||
};
|
||||
|
||||
@ -284,7 +295,7 @@ struct EMUCMDTABLE
|
||||
EMUCMDFN* fn_on;
|
||||
EMUCMDFN* fn_off;
|
||||
int state;
|
||||
char* name;
|
||||
const char* name;
|
||||
int flags; //EMUCMDFLAG
|
||||
};
|
||||
|
||||
@ -295,5 +306,6 @@ extern bool lagCounterDisplay;
|
||||
extern char lagFlag;
|
||||
extern bool turbo;
|
||||
void LagCounterReset();
|
||||
EMUCMDTABLE* GetEmuCommandById(int cmd);
|
||||
|
||||
#endif //_INPUT_H_
|
||||
|
@ -78,7 +78,7 @@ endo:
|
||||
ZD[w].zappo=final;
|
||||
|
||||
#ifndef GEKKO
|
||||
//if this was a miss, clear out the hit
|
||||
//if this was a miss, clear out the hit
|
||||
if(ZD[w].mzb&2)
|
||||
ZD[w].zaphit=0;
|
||||
#endif
|
||||
@ -88,7 +88,7 @@ static INLINE int CheckColor(int w)
|
||||
{
|
||||
FCEUPPU_LineUpdate();
|
||||
|
||||
if(newppu)
|
||||
if(newppu)
|
||||
{
|
||||
int x = (int)ZD[w].mzx;
|
||||
int y = (int)ZD[w].mzy;
|
||||
@ -184,23 +184,28 @@ static void UpdateZapper(int w, void *data, int arg)
|
||||
ZD[w].mzy=ptr[1];
|
||||
ZD[w].mzb=ptr[2];
|
||||
#else
|
||||
bool newclicked = (ptr[2]&3)!=0;
|
||||
bool oldclicked = (ZD[w].lastInput)!=0;
|
||||
bool newclicked = (ptr[2]&3)!=0;
|
||||
bool oldclicked = (ZD[w].lastInput)!=0;
|
||||
|
||||
if(ZD[w].bogo)
|
||||
{
|
||||
{
|
||||
ZD[w].bogo--;
|
||||
}
|
||||
}
|
||||
|
||||
ZD[w].lastInput = ptr[2]&3;
|
||||
ZD[w].lastInput = ptr[2]&3;
|
||||
|
||||
//woah.. this looks like broken bit logic.
|
||||
if(newclicked && !oldclicked)
|
||||
{
|
||||
if (newclicked && !oldclicked)
|
||||
{
|
||||
ZD[w].bogo=5;
|
||||
ZD[w].mzb=ptr[2];
|
||||
ZD[w].mzx=ptr[0];
|
||||
ZD[w].mzy=ptr[1];
|
||||
ZD[w].mzb=ptr[2];
|
||||
ZD[w].mzx=ptr[0];
|
||||
ZD[w].mzy=ptr[1];
|
||||
}
|
||||
// Always update X,Y so that gunsight draw function
|
||||
// is always following the cursor.
|
||||
ZD[w].mzx=ptr[0];
|
||||
ZD[w].mzy=ptr[1];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -230,7 +235,7 @@ static INPUTC ZAPVSC={ReadZapperVS,0,StrobeZapperVS,UpdateZapper,ZapperFrapper,D
|
||||
INPUTC *FCEU_InitZapper(int w)
|
||||
{
|
||||
memset(&ZD[w],0,sizeof(ZAPPER));
|
||||
if(GameInfo->type == GIT_VSUNI)
|
||||
if ( (GameInfo != NULL) && (GameInfo->type == GIT_VSUNI) )
|
||||
return(&ZAPVSC);
|
||||
else
|
||||
return(&ZAPC);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "utils/memory.h"
|
||||
#include "utils/xstring.h"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef CREATE_AVI
|
||||
#include "drivers/videolog/nesvideos-piece.h"
|
||||
@ -28,6 +29,8 @@
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __WIN_DRIVER__
|
||||
#include "./drivers/win/common.h"
|
||||
#include "./drivers/win/window.h"
|
||||
extern void AddRecentMovieFile(const char *filename);
|
||||
@ -35,6 +38,8 @@ extern void AddRecentMovieFile(const char *filename);
|
||||
extern bool mustEngageTaseditor;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
extern int RAMInitOption;
|
||||
extern int RAMInitSeed;
|
||||
|
||||
@ -98,6 +103,7 @@ int input_display = 0;
|
||||
int frame_display = 0;
|
||||
int rerecord_display = 0;
|
||||
bool fullSaveStateLoads = false; //Option for loading a savestates full contents in read+write mode instead of up to the frame count in the savestate (useful as a recovery option)
|
||||
int movieRecordMode = 0; //Option for various movie recording modes such as TRUNCATE (normal), OVERWRITE etc.
|
||||
|
||||
SFORMAT FCEUMOV_STATEINFO[]={
|
||||
{ &currFrameCounter, 4|FCEUSTATE_RLSB, "FCNT"},
|
||||
@ -129,7 +135,6 @@ void MovieRecord::dump(MovieData* md, EMUFILE* os, int index) { }
|
||||
MovieData::MovieData() { }
|
||||
void MovieData::truncateAt(int frame) { }
|
||||
void MovieData::installValue(std::string& key, std::string& val) { }
|
||||
int MovieData::dump(EMUFILE *os, bool binary) { return 0; }
|
||||
int FCEUMOV_GetFrame(void) { return 0; }
|
||||
int FCEUI_GetLagCount(void) { return 0; }
|
||||
bool FCEUI_GetLagged(void) { return false; }
|
||||
@ -460,12 +465,12 @@ MovieData::MovieData()
|
||||
, fds(false)
|
||||
, palFlag(false)
|
||||
, PPUflag(false)
|
||||
, RAMInitOption(0)
|
||||
, RAMInitSeed(0)
|
||||
, rerecordCount(0)
|
||||
, binaryFlag(false)
|
||||
, loadFrameCount(-1)
|
||||
, microphone(false)
|
||||
, RAMInitOption(0)
|
||||
, RAMInitSeed(0)
|
||||
{
|
||||
memset(&romChecksum,0,sizeof(MD5DATA));
|
||||
}
|
||||
@ -542,7 +547,7 @@ void MovieData::installValue(std::string& key, std::string& val)
|
||||
}
|
||||
}
|
||||
|
||||
int MovieData::dump(EMUFILE *os, bool binary)
|
||||
int MovieData::dump(EMUFILE *os, bool binary, bool seekToCurrFramePos)
|
||||
{
|
||||
int start = os->ftell();
|
||||
os->fprintf("version %d\n", version);
|
||||
@ -580,19 +585,30 @@ int MovieData::dump(EMUFILE *os, bool binary)
|
||||
if (this->loadFrameCount >= 0)
|
||||
os->fprintf("length %d\n" , this->loadFrameCount);
|
||||
|
||||
int currFramePos = -1;
|
||||
if(binary)
|
||||
{
|
||||
//put one | to start the binary dump
|
||||
os->fputc('|');
|
||||
for(int i=0;i<(int)records.size();i++)
|
||||
for (int i = 0; i < (int)records.size(); i++)
|
||||
{
|
||||
if (seekToCurrFramePos && currFrameCounter == i)
|
||||
currFramePos = os->ftell();
|
||||
records[i].dumpBinary(this, os, i);
|
||||
}
|
||||
} else
|
||||
{
|
||||
for(int i=0;i<(int)records.size();i++)
|
||||
for (int i = 0; i < (int)records.size(); i++)
|
||||
{
|
||||
if (seekToCurrFramePos && currFrameCounter == i)
|
||||
currFramePos = os->ftell();
|
||||
records[i].dump(this, os, i);
|
||||
}
|
||||
}
|
||||
|
||||
int end = os->ftell();
|
||||
if (currFramePos >= 0)
|
||||
os->fseek(currFramePos, SEEK_SET);
|
||||
return end-start;
|
||||
}
|
||||
|
||||
@ -671,7 +687,7 @@ static void LoadFM2_binarychunk(MovieData& movieData, EMUFILE* fp, int size)
|
||||
fp->fseek(curr,SEEK_SET);
|
||||
|
||||
//the amount todo is the min of the limiting size we received and the remaining contents of the file
|
||||
int todo = std::min(size, flen);
|
||||
int todo = std::min<int>(size, flen);
|
||||
|
||||
int numRecords = todo/recordsize;
|
||||
if (movieData.loadFrameCount!=-1 && movieData.loadFrameCount<numRecords)
|
||||
@ -782,6 +798,9 @@ bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader)
|
||||
state = VALUE;
|
||||
if(isnewline) goto commit;
|
||||
value += c;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
goto done;
|
||||
|
||||
@ -799,65 +818,145 @@ bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Stop movie playback.
|
||||
static void StopPlayback()
|
||||
static const char *GetMovieModeStr()
|
||||
{
|
||||
FCEU_DispMessageOnMovie("Movie playback stopped.");
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
if (movieMode == MOVIEMODE_INACTIVE)
|
||||
return " (no movie)";
|
||||
else if (movieMode == MOVIEMODE_PLAY)
|
||||
return " (playing)";
|
||||
else if (movieMode == MOVIEMODE_RECORD)
|
||||
return " (recording)";
|
||||
else if (movieMode == MOVIEMODE_FINISHED)
|
||||
return " (finished)";
|
||||
else if (movieMode == MOVIEMODE_TASEDITOR)
|
||||
return " (taseditor)";
|
||||
else
|
||||
return ".";
|
||||
}
|
||||
|
||||
// Stop movie playback without closing the movie.
|
||||
static void FinishPlayback()
|
||||
static const char *GetMovieReadOnlyStr()
|
||||
{
|
||||
extern int closeFinishedMovie;
|
||||
if (closeFinishedMovie)
|
||||
StopPlayback();
|
||||
if (movieMode == MOVIEMODE_RECORD)
|
||||
return movie_readonly ? " R-O" : "";
|
||||
else
|
||||
return movie_readonly ? "" : " R+W";
|
||||
}
|
||||
|
||||
static const char *GetMovieRecordModeStr()
|
||||
{
|
||||
switch (movieRecordMode)
|
||||
{
|
||||
FCEU_DispMessage("Movie finished playing.",0);
|
||||
movieMode = MOVIEMODE_FINISHED;
|
||||
case MOVIE_RECORD_MODE_OVERWRITE:
|
||||
return " [W]";
|
||||
case MOVIE_RECORD_MODE_INSERT:
|
||||
return " [I]";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static EMUFILE *openRecordingMovie(const char* fname)
|
||||
{
|
||||
if (osRecordingMovie)
|
||||
delete osRecordingMovie;
|
||||
|
||||
osRecordingMovie = FCEUD_UTF8_fstream(fname, "wb");
|
||||
if (!osRecordingMovie || osRecordingMovie->fail()) {
|
||||
FCEU_PrintError("Error opening movie output file: %s", fname);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(curMovieFilename, fname);
|
||||
|
||||
return osRecordingMovie;
|
||||
}
|
||||
|
||||
static void closeRecordingMovie()
|
||||
{
|
||||
if(osRecordingMovie)
|
||||
if (osRecordingMovie)
|
||||
{
|
||||
delete osRecordingMovie;
|
||||
osRecordingMovie = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Callers shall set the approriate movieMode before calling this
|
||||
static void RedumpWholeMovieFile(bool justToggledRecording = false)
|
||||
{
|
||||
bool recording = (movieMode == MOVIEMODE_RECORD);
|
||||
assert((NULL != osRecordingMovie) == (recording != justToggledRecording) && "osRecordingMovie should be consistent with movie mode!");
|
||||
|
||||
if (NULL == openRecordingMovie(curMovieFilename))
|
||||
return;
|
||||
|
||||
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/, recording);
|
||||
if (recording)
|
||||
osRecordingMovie->fflush();
|
||||
else
|
||||
closeRecordingMovie();
|
||||
}
|
||||
|
||||
/// Stop movie playback.
|
||||
static void StopPlayback()
|
||||
{
|
||||
assert(movieMode != MOVIEMODE_RECORD && NULL == osRecordingMovie);
|
||||
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
FCEU_DispMessageOnMovie("Movie playback stopped.");
|
||||
}
|
||||
|
||||
// Stop movie playback without closing the movie.
|
||||
static void FinishPlayback()
|
||||
{
|
||||
assert(movieMode != MOVIEMODE_RECORD);
|
||||
|
||||
extern int closeFinishedMovie;
|
||||
if (closeFinishedMovie)
|
||||
StopPlayback();
|
||||
else
|
||||
{
|
||||
movieMode = MOVIEMODE_FINISHED;
|
||||
FCEU_DispMessage("Movie finished playing.",0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Stop movie recording
|
||||
static void StopRecording()
|
||||
{
|
||||
FCEU_DispMessage("Movie recording stopped.",0);
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
assert(movieMode == MOVIEMODE_RECORD);
|
||||
|
||||
closeRecordingMovie();
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
RedumpWholeMovieFile(true);
|
||||
FCEU_DispMessage("Movie recording stopped.",0);
|
||||
}
|
||||
|
||||
void FCEUI_StopMovie()
|
||||
static void OnMovieClosed()
|
||||
{
|
||||
if(suppressMovieStop)
|
||||
return;
|
||||
|
||||
if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED)
|
||||
StopPlayback();
|
||||
else if(movieMode == MOVIEMODE_RECORD)
|
||||
StopRecording();
|
||||
assert(movieMode == MOVIEMODE_INACTIVE);
|
||||
|
||||
curMovieFilename[0] = 0; //No longer a current movie filename
|
||||
freshMovie = false; //No longer a fresh movie loaded
|
||||
if (bindSavestate) AutoSS = false; //If bind movies to savestates is true, then there is no longer a valid auto-save to load
|
||||
|
||||
#ifdef WIN32
|
||||
#if defined(__WIN_DRIVER__)
|
||||
SetMainWindowText();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool bogorf;
|
||||
|
||||
void FCEUI_StopMovie()
|
||||
{
|
||||
if (suppressMovieStop)
|
||||
return;
|
||||
|
||||
if (movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED)
|
||||
StopPlayback();
|
||||
else if (movieMode == MOVIEMODE_RECORD)
|
||||
StopRecording();
|
||||
|
||||
OnMovieClosed();
|
||||
}
|
||||
|
||||
void poweron(bool shouldDisableBatteryLoading)
|
||||
{
|
||||
//// make a for-movie-recording power-on clear the game's save data, too
|
||||
@ -892,7 +991,10 @@ void FCEUMOV_CreateCleanMovie()
|
||||
currMovieData = MovieData();
|
||||
currMovieData.palFlag = FCEUI_GetCurrentVidSystem(0,0)!=0;
|
||||
currMovieData.romFilename = FileBase;
|
||||
currMovieData.romChecksum = GameInfo->MD5;
|
||||
if ( GameInfo )
|
||||
{
|
||||
currMovieData.romChecksum = GameInfo->MD5;
|
||||
}
|
||||
currMovieData.guid.newGuid();
|
||||
currMovieData.fourscore = FCEUI_GetInputFourscore();
|
||||
currMovieData.microphone = FCEUI_GetInputMicrophone();
|
||||
@ -1004,7 +1106,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
|
||||
return true; //adelikat: file did not fail to load, so return true (false is only for file not exist/unable to open errors
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
//Fix relative path if necessary and then add to the recent movie menu
|
||||
extern std::string BaseDirectory;
|
||||
|
||||
@ -1025,6 +1127,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
|
||||
|
||||
freshMovie = true; //Movie has been loaded, so it must be unaltered
|
||||
if (bindSavestate) AutoSS = false; //If bind savestate to movie is true, then their isn't a valid auto-save to load, so flag it
|
||||
cur_input_display = 0; //clear previous input display
|
||||
//fully reload the game to reinitialize everything before playing any movie
|
||||
poweron(true);
|
||||
|
||||
@ -1070,7 +1173,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
|
||||
else
|
||||
FCEU_DispMessage("Replay started Read+Write.",0);
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
SetMainWindowText();
|
||||
#endif
|
||||
|
||||
@ -1085,18 +1188,6 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void openRecordingMovie(const char* fname)
|
||||
{
|
||||
osRecordingMovie = FCEUD_UTF8_fstream(fname, "wb");
|
||||
if(!osRecordingMovie)
|
||||
FCEU_PrintError("Error opening movie output file: %s",fname);
|
||||
strcpy(curMovieFilename, fname);
|
||||
#ifdef WIN32
|
||||
//Add to the recent movie menu
|
||||
AddRecentMovieFile(fname);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//begin recording a new movie
|
||||
//TODO - BUG - the record-from-another-savestate doesnt work.
|
||||
@ -1109,7 +1200,13 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author)
|
||||
|
||||
FCEUI_StopMovie();
|
||||
|
||||
openRecordingMovie(fname);
|
||||
if (NULL == openRecordingMovie(fname))
|
||||
return;
|
||||
|
||||
#ifdef __WIN_DRIVER__
|
||||
//Add to the recent movie menu
|
||||
AddRecentMovieFile(fname);
|
||||
#endif
|
||||
|
||||
currFrameCounter = 0;
|
||||
LagCounterReset();
|
||||
@ -1153,7 +1250,7 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author)
|
||||
//either dumps the current joystick state or loads one state from the movie
|
||||
void FCEUMOV_AddInputState()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if (movieMode == MOVIEMODE_TASEDITOR)
|
||||
{
|
||||
// if movie length is less or equal to currFrame, pad it with empty frames
|
||||
@ -1241,14 +1338,29 @@ void FCEUMOV_AddInputState()
|
||||
mr.commands = _currCommand;
|
||||
_currCommand = 0;
|
||||
|
||||
//Adelikat: in normal mode, this is done at the time of loading a savestate in read+write mode
|
||||
//aquanull: now it supports other recording modes that don't necessarily truncate further frame data
|
||||
//If the user chooses it can be delayed to here
|
||||
if (fullSaveStateLoads && (currFrameCounter < (int)currMovieData.records.size()))
|
||||
currMovieData.truncateAt(currFrameCounter);
|
||||
if (currFrameCounter < (int)currMovieData.records.size())
|
||||
switch (movieRecordMode)
|
||||
{
|
||||
case MOVIE_RECORD_MODE_OVERWRITE:
|
||||
currMovieData.records[currFrameCounter].Clone(mr);
|
||||
break;
|
||||
case MOVIE_RECORD_MODE_INSERT:
|
||||
//FIXME: this could be very insufficient
|
||||
currMovieData.records.insert(currMovieData.records.begin() + currFrameCounter, mr);
|
||||
break;
|
||||
//case MOVIE_RECORD_MODE_TRUNCATE:
|
||||
default:
|
||||
//Adelikat: in normal mode, this is done at the time of loading a savestate in read+write mode
|
||||
currMovieData.truncateAt(currFrameCounter);
|
||||
currMovieData.records.push_back(mr);
|
||||
break;
|
||||
}
|
||||
else
|
||||
currMovieData.records.push_back(mr);
|
||||
|
||||
mr.dump(&currMovieData, osRecordingMovie,currMovieData.records.size()); // to disk
|
||||
|
||||
currMovieData.records.push_back(mr);
|
||||
mr.dump(&currMovieData, osRecordingMovie, currFrameCounter); // to disk
|
||||
}
|
||||
|
||||
currFrameCounter++;
|
||||
@ -1282,33 +1394,42 @@ void FCEUMOV_AddCommand(int cmd)
|
||||
|
||||
void FCEU_DrawMovies(uint8 *XBuf)
|
||||
{
|
||||
if(frame_display)
|
||||
// not the best place, but just working
|
||||
assert((NULL != osRecordingMovie) == (movieMode == MOVIEMODE_RECORD));
|
||||
|
||||
if (frame_display)
|
||||
{
|
||||
char counterbuf[32] = {0};
|
||||
int color = 0x20;
|
||||
if(movieMode == MOVIEMODE_PLAY)
|
||||
sprintf(counterbuf,"%d/%d",currFrameCounter,(int)currMovieData.records.size());
|
||||
else if(movieMode == MOVIEMODE_RECORD)
|
||||
sprintf(counterbuf,"%d",currFrameCounter);
|
||||
else if (movieMode == MOVIEMODE_FINISHED)
|
||||
|
||||
if (movieMode == MOVIEMODE_PLAY)
|
||||
{
|
||||
sprintf(counterbuf,"%d/%d (finished)",currFrameCounter,(int)currMovieData.records.size());
|
||||
sprintf(counterbuf, "%d/%d%s%s", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
|
||||
} else if (movieMode == MOVIEMODE_RECORD)
|
||||
{
|
||||
if (movieRecordMode == MOVIE_RECORD_MODE_TRUNCATE)
|
||||
sprintf(counterbuf, "%d%s%s (record)", currFrameCounter, GetMovieRecordModeStr(), GetMovieReadOnlyStr()); // nearly classic
|
||||
else
|
||||
sprintf(counterbuf, "%d/%d%s%s (record)", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
|
||||
} else if (movieMode == MOVIEMODE_FINISHED)
|
||||
{
|
||||
sprintf(counterbuf,"%d/%d%s%s (finished)",currFrameCounter,(int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
|
||||
color = 0x17; //Show red to get attention
|
||||
} else if(movieMode == MOVIEMODE_TASEDITOR)
|
||||
} else if (movieMode == MOVIEMODE_TASEDITOR)
|
||||
{
|
||||
sprintf(counterbuf,"%d",currFrameCounter);
|
||||
} else
|
||||
sprintf(counterbuf,"%d (no movie)",currFrameCounter);
|
||||
|
||||
if(counterbuf[0])
|
||||
if (counterbuf[0])
|
||||
DrawTextTrans(ClipSidesOffset+XBuf+FCEU_TextScanlineOffsetFromBottom(30)+1, 256, (uint8*)counterbuf, color+0x80);
|
||||
}
|
||||
if(rerecord_display && movieMode != MOVIEMODE_INACTIVE)
|
||||
if (rerecord_display && movieMode != MOVIEMODE_INACTIVE)
|
||||
{
|
||||
char counterbuf[32] = {0};
|
||||
sprintf(counterbuf,"%d",currMovieData.rerecordCount);
|
||||
sprintf(counterbuf, "%d", currMovieData.rerecordCount);
|
||||
|
||||
if(counterbuf[0])
|
||||
if (counterbuf[0])
|
||||
DrawTextTrans(ClipSidesOffset+XBuf+FCEU_TextScanlineOffsetFromBottom(50)+1, 256, (uint8*)counterbuf, 0x28+0x80);
|
||||
}
|
||||
}
|
||||
@ -1363,7 +1484,7 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||
{
|
||||
if (currMovieData.loadFrameCount >= 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
int result = MessageBox(hAppWnd, "This movie is a TAS Editor project file.\nIt can be modified in TAS Editor only.\n\nOpen it in TAS Editor now?", "Movie Replay", MB_YESNO);
|
||||
if (result == IDYES)
|
||||
mustEngageTaseditor = true;
|
||||
@ -1451,10 +1572,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||
if(tempMovieData.guid != currMovieData.guid)
|
||||
{
|
||||
//mbg 8/18/08 - this code can be used to turn the error message into an OK/CANCEL
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
std::string msg = "There is a mismatch between savestate's movie and current movie.\ncurrent: " + currMovieData.guid.toString() + "\nsavestate: " + tempMovieData.guid.toString() + "\n\nThis means that you have loaded a savestate belonging to a different movie than the one you are playing now.\n\nContinue loading this savestate anyway?";
|
||||
extern HWND pwindow;
|
||||
int result = MessageBox(pwindow,msg.c_str(),"Error loading savestate",MB_OKCANCEL);
|
||||
int result = MessageBox(hAppWnd, msg.c_str(), "Error loading savestate", MB_OKCANCEL);
|
||||
if(result == IDCANCEL)
|
||||
{
|
||||
if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user
|
||||
@ -1478,10 +1598,15 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||
#endif
|
||||
}
|
||||
|
||||
closeRecordingMovie();
|
||||
|
||||
if (movie_readonly)
|
||||
{
|
||||
if (movieMode == MOVIEMODE_RECORD)
|
||||
{
|
||||
movieMode = MOVIEMODE_PLAY;
|
||||
RedumpWholeMovieFile(true);
|
||||
closeRecordingMovie();
|
||||
}
|
||||
|
||||
// currFrameCounter at this point represents the savestate framecount
|
||||
int frame_of_mismatch = CheckTimelines(tempMovieData, currMovieData);
|
||||
if (frame_of_mismatch >= 0)
|
||||
@ -1494,50 +1619,42 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||
} else
|
||||
FCEU_PrintError("Error: Savestate not in the same timeline as movie!\nFrame %d branches from current timeline", frame_of_mismatch);
|
||||
return false;
|
||||
} else if (movieMode == MOVIEMODE_FINISHED
|
||||
&& currFrameCounter > (int)currMovieData.records.size()
|
||||
&& currMovieData.records.size() == tempMovieData.records.size())
|
||||
} else if ((int)tempMovieData.records.size() < currFrameCounter)
|
||||
{
|
||||
// special case (in MOVIEMODE_FINISHED mode)
|
||||
// allow loading post-movie savestates that were made after finishing current movie
|
||||
|
||||
} else if (currFrameCounter > (int)currMovieData.records.size())
|
||||
{
|
||||
// this is future event state, don't allow it
|
||||
//TODO: turn frame counter to red to get attention
|
||||
if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user
|
||||
// this is post-movie savestate and must be checked further
|
||||
if (tempMovieData.records.size() < currMovieData.records.size())
|
||||
{
|
||||
FCEU_PrintError("Error: Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, currMovieData.records.size()-1);
|
||||
FCEUI_StopMovie();
|
||||
} else
|
||||
FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.", currFrameCounter, currMovieData.records.size()-1);
|
||||
return false;
|
||||
} else if (currFrameCounter > (int)tempMovieData.records.size())
|
||||
{
|
||||
// this is post-movie savestate, don't allow it
|
||||
//TODO: turn frame counter to red to get attention
|
||||
if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user
|
||||
{
|
||||
FCEU_PrintError("Error: Savestate is from a frame (%d) after the final frame in the savestated movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size()-1);
|
||||
FCEUI_StopMovie();
|
||||
} else
|
||||
FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the savestated movie (%d). This is not permitted.", currFrameCounter, tempMovieData.records.size()-1);
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
// Finally, this is a savestate file for this movie
|
||||
movieMode = MOVIEMODE_PLAY;
|
||||
// this savestate doesn't contain enough input to be checked
|
||||
//TODO: turn frame counter to red to get attention
|
||||
if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user
|
||||
{
|
||||
FCEU_PrintError("Error: Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
|
||||
FCEUI_StopMovie();
|
||||
} else
|
||||
FCEU_PrintError("Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, this is a savestate file for this movie
|
||||
// We'll allow loading post-movie savestates that were made after finishing current movie
|
||||
if (currFrameCounter < (int)currMovieData.records.size())
|
||||
movieMode = MOVIEMODE_PLAY;
|
||||
else
|
||||
FinishPlayback();
|
||||
} else
|
||||
{
|
||||
//Read+Write mode
|
||||
closeRecordingMovie();
|
||||
|
||||
if (currFrameCounter > (int)tempMovieData.records.size())
|
||||
{
|
||||
//This is a post movie savestate, handle it differently
|
||||
//Replace movie contents but then switch to movie finished mode
|
||||
currMovieData = tempMovieData;
|
||||
openRecordingMovie(curMovieFilename);
|
||||
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/);
|
||||
movieMode = MOVIEMODE_PLAY;
|
||||
FCEUMOV_IncrementRerecordCount();
|
||||
RedumpWholeMovieFile();
|
||||
FinishPlayback();
|
||||
} else
|
||||
{
|
||||
@ -1547,11 +1664,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
|
||||
tempMovieData.truncateAt(currFrameCounter);
|
||||
|
||||
currMovieData = tempMovieData;
|
||||
FCEUMOV_IncrementRerecordCount();
|
||||
openRecordingMovie(curMovieFilename);
|
||||
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/);
|
||||
movieMode = MOVIEMODE_RECORD;
|
||||
|
||||
FCEUMOV_IncrementRerecordCount();
|
||||
RedumpWholeMovieFile(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1659,37 +1774,213 @@ void FCEUI_SetMovieToggleReadOnly(bool which)
|
||||
FCEU_DispMessage("Movie is Read+Write.",0);
|
||||
}
|
||||
}
|
||||
|
||||
//auqnull: What's the point to toggle Read-Only without a movie loaded?
|
||||
void FCEUI_MovieToggleReadOnly()
|
||||
{
|
||||
char message[260];
|
||||
|
||||
if(movie_readonly)
|
||||
strcpy(message, "Movie is now Read+Write");
|
||||
else
|
||||
movie_readonly = !movie_readonly;
|
||||
if (movie_readonly)
|
||||
strcpy(message, "Movie is now Read-Only");
|
||||
else
|
||||
strcpy(message, "Movie is now Read+Write");
|
||||
|
||||
strcat(message, GetMovieModeStr());
|
||||
FCEU_DispMessage(message,0);
|
||||
}
|
||||
|
||||
void FCEUI_MovieToggleRecording()
|
||||
{
|
||||
char message[260] = "";
|
||||
|
||||
if (movieMode == MOVIEMODE_INACTIVE)
|
||||
strcat(message, " (no movie)");
|
||||
else if (movieMode == MOVIEMODE_FINISHED)
|
||||
strcat(message, " (finished)");
|
||||
strcpy(message, "Cannot toggle Recording");
|
||||
else if (currFrameCounter > (int)currMovieData.records.size())
|
||||
{
|
||||
movie_readonly = !movie_readonly;
|
||||
if (movie_readonly)
|
||||
strcpy(message, "Movie is now Read-Only (finished)");
|
||||
else
|
||||
strcpy(message, "Movie is now Read+Write (finished)");
|
||||
} else if (movieMode == MOVIEMODE_PLAY || (movieMode == MOVIEMODE_FINISHED && currFrameCounter == (int)currMovieData.records.size()))
|
||||
{
|
||||
strcpy(message, "Movie is now Read+Write");
|
||||
movie_readonly = false;
|
||||
FCEUMOV_IncrementRerecordCount();
|
||||
movieMode = MOVIEMODE_RECORD;
|
||||
RedumpWholeMovieFile(true);
|
||||
} else if (movieMode == MOVIEMODE_RECORD)
|
||||
{
|
||||
strcpy(message, "Movie is now Read-Only");
|
||||
movie_readonly = true;
|
||||
movieMode = MOVIEMODE_PLAY;
|
||||
RedumpWholeMovieFile(true);
|
||||
if (currFrameCounter >= (int)currMovieData.records.size())
|
||||
{
|
||||
extern int closeFinishedMovie;
|
||||
if (closeFinishedMovie)
|
||||
{
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
OnMovieClosed();
|
||||
} else
|
||||
movieMode = MOVIEMODE_FINISHED;
|
||||
}
|
||||
} else
|
||||
strcpy(message, "Nothing to do in this mode");
|
||||
|
||||
FCEU_DispMessage(message,0);
|
||||
movie_readonly = !movie_readonly;
|
||||
strcat(message, GetMovieModeStr());
|
||||
|
||||
FCEU_DispMessage(message, 0);
|
||||
}
|
||||
|
||||
void FCEUI_MovieInsertFrame()
|
||||
{
|
||||
char message[260] = "";
|
||||
|
||||
if (movieMode == MOVIEMODE_INACTIVE)
|
||||
strcpy(message, "No movie to insert a frame.");
|
||||
else if (movie_readonly)
|
||||
strcpy(message, "Cannot modify movie in Read-Only mode.");
|
||||
else if (currFrameCounter > (int)currMovieData.records.size())
|
||||
strcpy(message, "Cannot insert a frame here.");
|
||||
else if (movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED)
|
||||
{
|
||||
strcpy(message, "1 frame inserted");
|
||||
strcat(message, GetMovieModeStr());
|
||||
std::vector<MovieRecord>::iterator iter = currMovieData.records.begin();
|
||||
currMovieData.records.insert(iter + currFrameCounter, MovieRecord());
|
||||
FCEUMOV_IncrementRerecordCount();
|
||||
RedumpWholeMovieFile();
|
||||
} else
|
||||
{
|
||||
strcpy(message, "Nothing to do in this mode");
|
||||
strcat(message, GetMovieModeStr());
|
||||
}
|
||||
|
||||
FCEU_DispMessage(message, 0);
|
||||
}
|
||||
|
||||
void FCEUI_MovieDeleteFrame()
|
||||
{
|
||||
char message[260] = "";
|
||||
|
||||
if (movieMode == MOVIEMODE_INACTIVE)
|
||||
strcpy(message, "No movie to delete a frame.");
|
||||
else if (movie_readonly)
|
||||
strcpy(message, "Cannot modify movie in Read-Only mode.");
|
||||
else if (currFrameCounter >= (int)currMovieData.records.size())
|
||||
strcpy(message, "Nothing to delete past movie end.");
|
||||
else if (movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY)
|
||||
{
|
||||
strcpy(message, "1 frame deleted");
|
||||
std::vector<MovieRecord>::iterator iter = currMovieData.records.begin();
|
||||
currMovieData.records.erase(iter + currFrameCounter);
|
||||
FCEUMOV_IncrementRerecordCount();
|
||||
RedumpWholeMovieFile();
|
||||
|
||||
if (movieMode != MOVIEMODE_RECORD && currFrameCounter >= (int)currMovieData.records.size())
|
||||
{
|
||||
extern int closeFinishedMovie;
|
||||
if (closeFinishedMovie)
|
||||
{
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
OnMovieClosed();
|
||||
} else
|
||||
movieMode = MOVIEMODE_FINISHED;
|
||||
}
|
||||
strcat(message, GetMovieModeStr());
|
||||
} else
|
||||
{
|
||||
strcpy(message, "Nothing to do in this mode");
|
||||
strcat(message, GetMovieModeStr());
|
||||
}
|
||||
|
||||
FCEU_DispMessage(message, 0);
|
||||
}
|
||||
|
||||
void FCEUI_MovieTruncate()
|
||||
{
|
||||
char message[260] = "";
|
||||
|
||||
if (movieMode == MOVIEMODE_INACTIVE)
|
||||
strcpy(message, "No movie to truncate.");
|
||||
else if (movie_readonly)
|
||||
strcpy(message, "Cannot modify movie in Read-Only mode.");
|
||||
else if (currFrameCounter >= (int)currMovieData.records.size())
|
||||
strcpy(message, "Nothing to truncate past movie end.");
|
||||
else if (movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY)
|
||||
{
|
||||
strcpy(message, "Movie truncated");
|
||||
currMovieData.truncateAt(currFrameCounter);
|
||||
FCEUMOV_IncrementRerecordCount();
|
||||
RedumpWholeMovieFile();
|
||||
|
||||
if (movieMode != MOVIEMODE_RECORD)
|
||||
{
|
||||
extern int closeFinishedMovie;
|
||||
if (closeFinishedMovie)
|
||||
{
|
||||
movieMode = MOVIEMODE_INACTIVE;
|
||||
OnMovieClosed();
|
||||
}
|
||||
else
|
||||
movieMode = MOVIEMODE_FINISHED;
|
||||
}
|
||||
strcat(message, GetMovieModeStr());
|
||||
} else
|
||||
{
|
||||
strcpy(message, "Nothing to do in this mode");
|
||||
strcat(message, GetMovieModeStr());
|
||||
}
|
||||
|
||||
FCEU_DispMessage(message, 0);
|
||||
}
|
||||
|
||||
void FCEUI_MovieNextRecordMode()
|
||||
{
|
||||
movieRecordMode = (movieRecordMode + 1) % MOVIE_RECORD_MODE_MAX;
|
||||
}
|
||||
|
||||
void FCEUI_MoviePrevRecordMode()
|
||||
{
|
||||
movieRecordMode = (movieRecordMode + MOVIE_RECORD_MODE_MAX - 1) % MOVIE_RECORD_MODE_MAX;
|
||||
}
|
||||
|
||||
void FCEUI_MovieRecordModeTruncate()
|
||||
{
|
||||
movieRecordMode = MOVIE_RECORD_MODE_TRUNCATE;
|
||||
}
|
||||
|
||||
void FCEUI_MovieRecordModeOverwrite()
|
||||
{
|
||||
movieRecordMode = MOVIE_RECORD_MODE_OVERWRITE;
|
||||
}
|
||||
|
||||
void FCEUI_MovieRecordModeInsert()
|
||||
{
|
||||
movieRecordMode = MOVIE_RECORD_MODE_INSERT;
|
||||
}
|
||||
|
||||
void FCEUI_MoviePlayFromBeginning(void)
|
||||
{
|
||||
if (movieMode == MOVIEMODE_TASEDITOR)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
handleEmuCmdByTaseditor(EMUCMD_MOVIE_PLAY_FROM_BEGINNING);
|
||||
#endif
|
||||
} else if (movieMode != MOVIEMODE_INACTIVE)
|
||||
{
|
||||
if (movieMode == MOVIEMODE_RECORD)
|
||||
{
|
||||
movieMode = MOVIEMODE_PLAY;
|
||||
RedumpWholeMovieFile(true);
|
||||
}
|
||||
if (currMovieData.savestate.empty())
|
||||
{
|
||||
movie_readonly = true;
|
||||
movieMode = MOVIEMODE_PLAY;
|
||||
cur_input_display = 0; //clear previous input display
|
||||
poweron(true);
|
||||
currFrameCounter = 0;
|
||||
FCEU_DispMessage("Movie is now Read-Only. Playing from beginning.",0);
|
||||
@ -1708,7 +1999,7 @@ void FCEUI_MoviePlayFromBeginning(void)
|
||||
//currMovieData.loadSavestateFrom(&currMovieData.savestate); //TODO: make something like this work instead so it doesn't have to reload
|
||||
}
|
||||
}
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
SetMainWindowText();
|
||||
#endif
|
||||
}
|
||||
@ -1783,7 +2074,7 @@ void ProcessSubtitles(void)
|
||||
}
|
||||
}
|
||||
|
||||
void FCEU_DisplaySubtitles(char *format, ...)
|
||||
void FCEU_DisplaySubtitles(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
@ -65,6 +65,16 @@ enum EMOVIEMODE
|
||||
MOVIEMODE_FINISHED = 16
|
||||
};
|
||||
|
||||
enum EMOVIERECORDMODE
|
||||
{
|
||||
MOVIE_RECORD_MODE_TRUNCATE = 0,
|
||||
MOVIE_RECORD_MODE_OVERWRITE = 1,
|
||||
MOVIE_RECORD_MODE_INSERT = 2,
|
||||
//MOVIE_RECORD_MODE_XOR = 3,
|
||||
|
||||
MOVIE_RECORD_MODE_MAX
|
||||
};
|
||||
|
||||
enum EMOVIECMD
|
||||
{
|
||||
MOVIECMD_RESET = 1,
|
||||
@ -200,7 +210,7 @@ public:
|
||||
//whether microphone is enabled
|
||||
bool microphone;
|
||||
|
||||
int getNumRecords() { return records.size(); }
|
||||
int getNumRecords() { return (int)records.size(); }
|
||||
|
||||
int RAMInitOption, RAMInitSeed;
|
||||
|
||||
@ -234,7 +244,7 @@ public:
|
||||
|
||||
void truncateAt(int frame);
|
||||
void installValue(std::string& key, std::string& val);
|
||||
int dump(EMUFILE* os, bool binary);
|
||||
int dump(EMUFILE* os, bool binary, bool seekToCurrFramePos = false);
|
||||
|
||||
void clearRecordRange(int start, int len);
|
||||
void eraseRecords(int at, int frames = 1);
|
||||
@ -267,6 +277,9 @@ extern bool freshMovie;
|
||||
extern bool movie_readonly;
|
||||
extern bool autoMovieBackup;
|
||||
extern bool fullSaveStateLoads;
|
||||
extern int movieRecordMode;
|
||||
extern int input_display;
|
||||
|
||||
//--------------------------------------------------
|
||||
void FCEUI_MakeBackupMovie(bool dispMessage);
|
||||
void FCEUI_CreateMovieFile(std::string fn);
|
||||
@ -277,6 +290,15 @@ void FCEUI_StopMovie(void);
|
||||
bool FCEUI_MovieGetInfo(FCEUFILE* fp, MOVIE_INFO& info, bool skipFrameCount = false);
|
||||
//char* FCEUI_MovieGetCurrentName(int addSlotNumber);
|
||||
void FCEUI_MovieToggleReadOnly(void);
|
||||
void FCEUI_MovieToggleRecording();
|
||||
void FCEUI_MovieInsertFrame();
|
||||
void FCEUI_MovieDeleteFrame();
|
||||
void FCEUI_MovieTruncate();
|
||||
void FCEUI_MovieNextRecordMode();
|
||||
void FCEUI_MoviePrevRecordMode();
|
||||
void FCEUI_MovieRecordModeTruncate();
|
||||
void FCEUI_MovieRecordModeOverwrite();
|
||||
void FCEUI_MovieRecordModeInsert();
|
||||
bool FCEUI_GetMovieToggleReadOnly();
|
||||
void FCEUI_SetMovieToggleReadOnly(bool which);
|
||||
int FCEUI_GetMovieLength();
|
||||
@ -288,9 +310,10 @@ void FCEUI_ToggleInputDisplay(void);
|
||||
|
||||
void LoadSubtitles(MovieData &);
|
||||
void ProcessSubtitles(void);
|
||||
void FCEU_DisplaySubtitles(char *format, ...);
|
||||
void FCEU_DisplaySubtitles(const char *format, ...);
|
||||
|
||||
void poweron(bool shouldDisableBatteryLoading);
|
||||
bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader);
|
||||
|
||||
|
||||
#endif //__MOVIE_H_
|
||||
|
@ -134,25 +134,30 @@ void NSFGI(GI h)
|
||||
{
|
||||
switch(h)
|
||||
{
|
||||
case GI_CLOSE:
|
||||
if(NSFDATA) {free(NSFDATA);NSFDATA=0;}
|
||||
if(ExWRAM) {free(ExWRAM);ExWRAM=0;}
|
||||
if(NSFHeader.SoundChip&1) {
|
||||
// NSFVRC6_Init();
|
||||
} else if(NSFHeader.SoundChip&2) {
|
||||
// NSFVRC7_Init();
|
||||
} else if(NSFHeader.SoundChip&4) {
|
||||
// FDSSoundReset();
|
||||
} else if(NSFHeader.SoundChip&8) {
|
||||
NSFMMC5_Close();
|
||||
} else if(NSFHeader.SoundChip&0x10) {
|
||||
// NSFN106_Init();
|
||||
} else if(NSFHeader.SoundChip&0x20) {
|
||||
// NSFAY_Init();
|
||||
}
|
||||
case GI_CLOSE:
|
||||
if(NSFDATA) {free(NSFDATA);NSFDATA=0;}
|
||||
if(ExWRAM) {free(ExWRAM);ExWRAM=0;}
|
||||
if(NSFHeader.SoundChip&1) {
|
||||
// NSFVRC6_Init();
|
||||
} else if(NSFHeader.SoundChip&2) {
|
||||
// NSFVRC7_Init();
|
||||
} else if(NSFHeader.SoundChip&4) {
|
||||
// FDSSoundReset();
|
||||
} else if(NSFHeader.SoundChip&8) {
|
||||
NSFMMC5_Close();
|
||||
} else if(NSFHeader.SoundChip&0x10) {
|
||||
// NSFN106_Init();
|
||||
} else if(NSFHeader.SoundChip&0x20) {
|
||||
// NSFAY_Init();
|
||||
}
|
||||
break;
|
||||
case GI_RESETM2:
|
||||
case GI_POWER:
|
||||
NSF_init();
|
||||
break;
|
||||
default:
|
||||
//Unhandled cases
|
||||
break;
|
||||
case GI_RESETM2:
|
||||
case GI_POWER: NSF_init();break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +179,7 @@ int NSFLoad(const char *name, FCEUFILE *fp)
|
||||
FCEU_fseek(fp,0,SEEK_SET);
|
||||
FCEU_fread(&NSFHeader,1,0x80,fp);
|
||||
if(memcmp(NSFHeader.ID,"NESM\x1a",5))
|
||||
return 0;
|
||||
return LOADER_INVALID_FORMAT;
|
||||
NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0;
|
||||
|
||||
LoadAddr=NSFHeader.LoadAddressLow;
|
||||
@ -183,7 +188,7 @@ int NSFLoad(const char *name, FCEUFILE *fp)
|
||||
if(LoadAddr<0x6000)
|
||||
{
|
||||
FCEUD_PrintError("Invalid load address.");
|
||||
return(0);
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
InitAddr=NSFHeader.InitAddressLow;
|
||||
InitAddr|=NSFHeader.InitAddressHigh<<8;
|
||||
@ -196,8 +201,11 @@ int NSFLoad(const char *name, FCEUFILE *fp)
|
||||
NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096);
|
||||
NSFMaxBank=PRGsize[0]=uppow2(NSFMaxBank);
|
||||
|
||||
if(!(NSFDATA=(uint8 *)FCEU_malloc(NSFMaxBank*4096)))
|
||||
return 0;
|
||||
if (!(NSFDATA = (uint8 *)FCEU_malloc(NSFMaxBank * 4096)))
|
||||
{
|
||||
FCEU_PrintError("Unable to allocate memory.");
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
|
||||
FCEU_fseek(fp,0x80,SEEK_SET);
|
||||
memset(NSFDATA,0x00,NSFMaxBank*4096);
|
||||
@ -262,7 +270,7 @@ int NSFLoad(const char *name, FCEUFILE *fp)
|
||||
FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright);
|
||||
if(NSFHeader.SoundChip)
|
||||
{
|
||||
static char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"};
|
||||
static const char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"};
|
||||
|
||||
for(x=0;x<6;x++)
|
||||
if(NSFHeader.SoundChip&(1<<x))
|
||||
@ -288,7 +296,7 @@ int NSFLoad(const char *name, FCEUFILE *fp)
|
||||
|
||||
FCEUI_SetVidSystem(NSFHeader.VideoSystem);
|
||||
|
||||
return 1;
|
||||
return LOADER_OK;
|
||||
}
|
||||
|
||||
static DECLFR(NSFVectorRead)
|
||||
|
@ -464,10 +464,16 @@ case 0x93: ST_IY(_A&_X&(((A-_Y)>>8)+1));
|
||||
case 0x9F: ST_ABY(_A&_X&(((A-_Y)>>8)+1));
|
||||
|
||||
/* SYA */
|
||||
case 0x9C: ST_ABX(_Y&(((A-_X)>>8)+1));
|
||||
case 0x9C: /* Can't reuse existing ST_ABI macro here, due to addressing weirdness. */
|
||||
{
|
||||
unsigned int A; GetABIWR(A,_X); A = ((_Y&((A>>8)+1)) << 8) | (A & 0xff); WrMem(A,A>>8); break;
|
||||
}
|
||||
|
||||
/* SXA */
|
||||
case 0x9E: ST_ABY(_X&(((A-_Y)>>8)+1));
|
||||
case 0x9E: /* Can't reuse existing ST_ABI macro here, due to addressing weirdness. */
|
||||
{
|
||||
unsigned int A; GetABIWR(A,_Y); A = ((_X&((A>>8)+1)) << 8) | (A & 0xff); WrMem(A,A>>8); break;
|
||||
}
|
||||
|
||||
/* XAS */
|
||||
case 0x9B: _S=_A&_X;ST_ABY(_S& (((A-_Y)>>8)+1) );
|
||||
|
@ -41,13 +41,14 @@
|
||||
#include <cstring>
|
||||
|
||||
bool force_grayscale = false;
|
||||
pal *grayscaled_palo = NULL;
|
||||
|
||||
pal palette_game[64*8]; //custom palette for an individual game. (formerly palettei)
|
||||
pal palette_user[64*8]; //user's overridden palette (formerly palettec)
|
||||
pal palette_ntsc[64*8]; //mathematically generated NTSC palette (formerly paletten)
|
||||
|
||||
static bool palette_game_available; //whether palette_game is available
|
||||
static bool palette_user_available; //whether palette_user is available
|
||||
static bool palette_game_available=false; //whether palette_game is available
|
||||
static bool palette_user_available=false; //whether palette_user is available
|
||||
|
||||
//ntsc parameters:
|
||||
bool ntsccol_enable = false; //whether NTSC palette is selected
|
||||
@ -61,10 +62,11 @@ int default_palette_selection = 0;
|
||||
static pal *default_palette[8]=
|
||||
{
|
||||
palette,
|
||||
rp2c04001,
|
||||
rp2c04002,
|
||||
rp2c04003,
|
||||
rp2c05004,
|
||||
rp2c04_0001,
|
||||
rp2c04_0002,
|
||||
rp2c04_0003,
|
||||
rp2c04_0004,
|
||||
rp2c03,
|
||||
};
|
||||
|
||||
static void CalculatePalette(void);
|
||||
@ -72,7 +74,7 @@ static void ChoosePalette(void);
|
||||
static void WritePalette(void);
|
||||
|
||||
//points to the actually selected current palette
|
||||
pal *palo;
|
||||
pal *palo = NULL;
|
||||
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
@ -176,7 +178,7 @@ int bisqwit_wave(int p, int color) { return (color+p+8)%12 < 6; }
|
||||
static void ApplyDeemphasisBisqwit(int entry, u8& r, u8& g, u8& b)
|
||||
{
|
||||
if(entry<64) return;
|
||||
int myr, myg, myb;
|
||||
int myr=0, myg=0, myb=0;
|
||||
// The input value is a NES color index (with de-emphasis bits).
|
||||
// We need RGB values. Convert the index into RGB.
|
||||
// For most part, this process is described at:
|
||||
@ -289,6 +291,11 @@ static void ApplyDeemphasisComplete(pal* pal512)
|
||||
}
|
||||
}
|
||||
|
||||
bool FCEUI_GetUserPaletteAvail( void )
|
||||
{
|
||||
return palette_user_available;
|
||||
}
|
||||
|
||||
void FCEUI_SetUserPalette(uint8 *pal, int nEntries)
|
||||
{
|
||||
if(!pal)
|
||||
@ -521,6 +528,29 @@ static void ChoosePalette(void)
|
||||
//need to calcualte a deemph on the fly.. sorry. maybe support otherwise later
|
||||
ApplyDeemphasisComplete(palo);
|
||||
}
|
||||
if (force_grayscale)
|
||||
{
|
||||
// need to apply grayscale filter
|
||||
// allocate memory for grayscale palette
|
||||
if (grayscaled_palo == NULL)
|
||||
grayscaled_palo = (pal*)malloc(sizeof(pal) * 64 * 8);
|
||||
// make every color grayscale
|
||||
for (int x = 0; x < 64 * 8; x++)
|
||||
{
|
||||
uint8 gray = ((float)palo[x].r * 0.299 + (float)palo[x].g * 0.587 + (float)palo[x].b * 0.114);
|
||||
grayscaled_palo[x].r = gray;
|
||||
grayscaled_palo[x].g = gray;
|
||||
grayscaled_palo[x].b = gray;
|
||||
}
|
||||
// apply new palette
|
||||
palo = grayscaled_palo;
|
||||
}
|
||||
else if (grayscaled_palo != NULL)
|
||||
{
|
||||
// free allocated memory if the grayscale filter is not used anymore
|
||||
free(grayscaled_palo);
|
||||
grayscaled_palo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void WritePalette(void)
|
||||
|
@ -4,25 +4,29 @@
|
||||
#define EMPTY_PALETTE_64 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16
|
||||
#define EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64
|
||||
|
||||
pal rp2c04001[512] = {
|
||||
#include "rp2c04001.h"
|
||||
pal rp2c04_0001[512] = {
|
||||
#include "rp2c04-0001.h"
|
||||
EMPTY_PALETTE_DEEMPH_X_7
|
||||
};
|
||||
|
||||
pal rp2c04002[512] = {
|
||||
#include "rp2c04002.h"
|
||||
pal rp2c04_0002[512] = {
|
||||
#include "rp2c04-0002.h"
|
||||
EMPTY_PALETTE_DEEMPH_X_7
|
||||
};
|
||||
|
||||
pal rp2c04003[512] = {
|
||||
#include "rp2c04003.h"
|
||||
pal rp2c04_0003[512] = {
|
||||
#include "rp2c04-0003.h"
|
||||
EMPTY_PALETTE_DEEMPH_X_7
|
||||
};
|
||||
pal rp2c05004[512] = {
|
||||
#include "rp2c05004.h"
|
||||
pal rp2c04_0004[512] = {
|
||||
#include "rp2c04-0004.h"
|
||||
EMPTY_PALETTE_DEEMPH_X_7
|
||||
};
|
||||
|
||||
pal rp2c03[512] = {
|
||||
#include "rp2c03.h"
|
||||
};
|
||||
|
||||
// Fixed palette entries used by the GUI
|
||||
pal palette_unvarying[] = {
|
||||
{ 0x00<<2,0x00<<2,0x00<<2}, // 0 = Black
|
||||
|
@ -330,7 +330,7 @@ int fceuindbg = 0;
|
||||
//0xFF shall indicate to use palette[0]
|
||||
uint8 gNoBGFillColor = 0xFF;
|
||||
|
||||
int MMC5Hack = 0, PEC586Hack = 0;;
|
||||
int MMC5Hack = 0;
|
||||
uint32 MMC5HackVROMMask = 0;
|
||||
uint8 *MMC5HackExNTARAMPtr = 0;
|
||||
uint8 *MMC5HackVROMPTR = 0;
|
||||
@ -340,6 +340,12 @@ uint8 MMC50x5130 = 0;
|
||||
uint8 MMC5HackSPScroll = 0;
|
||||
uint8 MMC5HackSPPage = 0;
|
||||
|
||||
int PEC586Hack = 0;
|
||||
|
||||
int QTAIHack = 0;
|
||||
uint8 QTAINTRAM[2048];
|
||||
uint8 qtaintramreg;
|
||||
|
||||
uint8 VRAMBuffer = 0, PPUGenLatch = 0;
|
||||
uint8 *vnapage[4];
|
||||
uint8 PPUNTARAM = 0;
|
||||
@ -376,6 +382,18 @@ uint8 UPALRAM[0x03];//for 0x4/0x8/0xC addresses in palette, the ones in
|
||||
|
||||
uint8* MMC5BGVRAMADR(uint32 A);
|
||||
|
||||
uint8 READPAL_MOTHEROFALL(uint32 A)
|
||||
{
|
||||
if(!(A & 3)) {
|
||||
if(!(A & 0xC))
|
||||
return READPAL(0x00);
|
||||
else
|
||||
return READUPAL(((A & 0xC) >> 2) - 1);
|
||||
}
|
||||
else
|
||||
return READPAL(A & 0x1F);
|
||||
}
|
||||
|
||||
//this duplicates logic which is embedded in the ppu rendering code
|
||||
//which figures out where to get CHR data from depending on various hack modes
|
||||
//mostly involving mmc5.
|
||||
@ -414,12 +432,18 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) {
|
||||
if (PPUCHRRAM & (1 << (tmp >> 10)))
|
||||
VPage[tmp >> 10][tmp] = V;
|
||||
} else if (tmp < 0x3F00) {
|
||||
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
|
||||
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
|
||||
if (QTAIHack && (qtaintramreg & 1)) {
|
||||
QTAINTRAM[((((tmp & 0xF00) >> 10) >> ((qtaintramreg >> 1)) & 1) << 10) | (tmp & 0x3FF)] = V;
|
||||
} else {
|
||||
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
|
||||
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
|
||||
}
|
||||
} else {
|
||||
if (!(tmp & 3)) {
|
||||
if (!(tmp & 0xC))
|
||||
if (!(tmp & 0xC)) {
|
||||
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
|
||||
PALRAM[0x10] = PALRAM[0x14] = PALRAM[0x18] = PALRAM[0x1C] = V & 0x3F;
|
||||
}
|
||||
else
|
||||
UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F;
|
||||
} else
|
||||
@ -941,8 +965,12 @@ static DECLFW(B2007) {
|
||||
if (PPUCHRRAM & (1 << (tmp >> 10)))
|
||||
VPage[tmp >> 10][tmp] = V;
|
||||
} else if (tmp < 0x3F00) {
|
||||
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
|
||||
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
|
||||
if (QTAIHack && (qtaintramreg & 1)) {
|
||||
QTAINTRAM[((((tmp & 0xF00) >> 10) >> ((qtaintramreg >> 1)) & 1) << 10) | (tmp & 0x3FF)] = V;
|
||||
} else {
|
||||
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10)))
|
||||
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V;
|
||||
}
|
||||
} else {
|
||||
if (!(tmp & 3)) {
|
||||
if (!(tmp & 0xC))
|
||||
@ -1060,7 +1088,7 @@ static void RefreshLine(int lastpixel) {
|
||||
uint32 vofs;
|
||||
int X1;
|
||||
|
||||
register uint8 *P = Pline;
|
||||
uint8 *P = Pline;
|
||||
int lasttile = lastpixel >> 3;
|
||||
int numtiles;
|
||||
static int norecurse = 0; // Yeah, recursion would be bad.
|
||||
@ -1182,6 +1210,12 @@ static void RefreshLine(int lastpixel) {
|
||||
#include "pputile.inc"
|
||||
}
|
||||
#undef PPU_BGFETCH
|
||||
} if (QTAIHack) {
|
||||
#define PPU_VRC5FETCH
|
||||
for (X1 = firsttile; X1 < lasttile; X1++) {
|
||||
#include "pputile.inc"
|
||||
}
|
||||
#undef PPU_VRC5FETCH
|
||||
} else {
|
||||
for (X1 = firsttile; X1 < lasttile; X1++) {
|
||||
#include "pputile.inc"
|
||||
@ -1627,7 +1661,6 @@ static void RefreshSprites(void) {
|
||||
}
|
||||
|
||||
static void CopySprites(uint8 *target) {
|
||||
uint8 n = ((PPU[1] & 4) ^ 4) << 1;
|
||||
uint8 *P = target;
|
||||
|
||||
if (!spork) return;
|
||||
@ -1635,65 +1668,19 @@ static void CopySprites(uint8 *target) {
|
||||
|
||||
if (!rendersprites) return; //User asked to not display sprites.
|
||||
|
||||
loopskie:
|
||||
if(!SpriteON) return;
|
||||
|
||||
int start=8;
|
||||
if(PPU[1] & 0x04)
|
||||
start = 0;
|
||||
|
||||
for(int i=start;i<256;i++)
|
||||
{
|
||||
uint32 t = *(uint32*)(sprlinebuf + n);
|
||||
|
||||
if (t != 0x80808080) {
|
||||
#ifdef LSB_FIRST
|
||||
if (!(t & 0x80)) {
|
||||
if (!(t & 0x40) || (P[n] & 0x40)) // Normal sprite || behind bg sprite
|
||||
P[n] = sprlinebuf[n];
|
||||
}
|
||||
|
||||
if (!(t & 0x8000)) {
|
||||
if (!(t & 0x4000) || (P[n + 1] & 0x40)) // Normal sprite || behind bg sprite
|
||||
P[n + 1] = (sprlinebuf + 1)[n];
|
||||
}
|
||||
|
||||
if (!(t & 0x800000)) {
|
||||
if (!(t & 0x400000) || (P[n + 2] & 0x40)) // Normal sprite || behind bg sprite
|
||||
P[n + 2] = (sprlinebuf + 2)[n];
|
||||
}
|
||||
|
||||
if (!(t & 0x80000000)) {
|
||||
if (!(t & 0x40000000) || (P[n + 3] & 0x40)) // Normal sprite || behind bg sprite
|
||||
P[n + 3] = (sprlinebuf + 3)[n];
|
||||
}
|
||||
#else
|
||||
/* TODO: Simplify */
|
||||
if (!(t & 0x80000000)) {
|
||||
if (!(t & 0x40000000)) // Normal sprite
|
||||
P[n] = sprlinebuf[n];
|
||||
else if (P[n] & 64) // behind bg sprite
|
||||
P[n] = sprlinebuf[n];
|
||||
}
|
||||
|
||||
if (!(t & 0x800000)) {
|
||||
if (!(t & 0x400000)) // Normal sprite
|
||||
P[n + 1] = (sprlinebuf + 1)[n];
|
||||
else if (P[n + 1] & 64) // behind bg sprite
|
||||
P[n + 1] = (sprlinebuf + 1)[n];
|
||||
}
|
||||
|
||||
if (!(t & 0x8000)) {
|
||||
if (!(t & 0x4000)) // Normal sprite
|
||||
P[n + 2] = (sprlinebuf + 2)[n];
|
||||
else if (P[n + 2] & 64) // behind bg sprite
|
||||
P[n + 2] = (sprlinebuf + 2)[n];
|
||||
}
|
||||
|
||||
if (!(t & 0x80)) {
|
||||
if (!(t & 0x40)) // Normal sprite
|
||||
P[n + 3] = (sprlinebuf + 3)[n];
|
||||
else if (P[n + 3] & 64) // behind bg sprite
|
||||
P[n + 3] = (sprlinebuf + 3)[n];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
uint8 t = sprlinebuf[i];
|
||||
if(!(t&0x80))
|
||||
if (!(t & 0x40) || (P[i] & 0x40)) // Normal sprite || behind bg sprite
|
||||
P[i] = t;
|
||||
}
|
||||
n += 4;
|
||||
if (n) goto loopskie;
|
||||
}
|
||||
|
||||
void FCEUPPU_SetVideoSystem(int w) {
|
||||
@ -1864,8 +1851,10 @@ int FCEUPPU_Loop(int skip) {
|
||||
|
||||
for (scanline = 0; scanline < totalscanlines; ) { //scanline is incremented in DoLine. Evil. :/
|
||||
deempcnt[deemp]++;
|
||||
|
||||
if (scanline < 240)
|
||||
DEBUG(FCEUD_UpdatePPUView(scanline, 1));
|
||||
|
||||
DoLine();
|
||||
|
||||
if (scanline < normalscanlines || scanline == totalscanlines)
|
||||
@ -1900,7 +1889,6 @@ int FCEUPPU_Loop(int skip) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
FCEU_PutImage();
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
@ -1998,12 +1986,16 @@ void runppu(int x) {
|
||||
//todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory
|
||||
struct BGData {
|
||||
struct Record {
|
||||
uint8 nt, pecnt, at, pt[2];
|
||||
uint8 nt, pecnt, at, pt[2], qtnt;
|
||||
|
||||
INLINE void Read() {
|
||||
NTRefreshAddr = RefreshAddr = ppur.get_ntread();
|
||||
if (PEC586Hack)
|
||||
ppur.s = (RefreshAddr & 0x200) >> 9;
|
||||
else if (QTAIHack) {
|
||||
qtnt = QTAINTRAM[((((RefreshAddr >> 10) & 3) >> ((qtaintramreg >> 1)) & 1) << 10) | (RefreshAddr & 0x3FF)];
|
||||
ppur.s = qtnt & 0x3F;
|
||||
}
|
||||
pecnt = (RefreshAddr & 1) << 3;
|
||||
nt = CALL_PPUREAD(RefreshAddr);
|
||||
runppu(kFetchTime);
|
||||
@ -2029,12 +2021,16 @@ struct BGData {
|
||||
ppur.par = nt;
|
||||
RefreshAddr = ppur.get_ptread();
|
||||
if (PEC586Hack) {
|
||||
if (ScreenON)
|
||||
RENDER_LOG(RefreshAddr | pecnt);
|
||||
pt[0] = CALL_PPUREAD(RefreshAddr | pecnt);
|
||||
runppu(kFetchTime);
|
||||
pt[1] = CALL_PPUREAD(RefreshAddr | pecnt);
|
||||
runppu(kFetchTime);
|
||||
} else if (QTAIHack && (qtnt & 0x40)) {
|
||||
pt[0] = *(CHRptr[0] + RefreshAddr);
|
||||
runppu(kFetchTime);
|
||||
RefreshAddr |= 8;
|
||||
pt[1] = *(CHRptr[0] + RefreshAddr);
|
||||
runppu(kFetchTime);
|
||||
} else {
|
||||
if (ScreenON)
|
||||
RENDER_LOG(RefreshAddr);
|
||||
@ -2139,7 +2135,8 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
//int xscroll = ppur.fh;
|
||||
//render 241/291 scanlines (1 dummy at beginning, dendy's 50 at the end)
|
||||
//ignore overclocking!
|
||||
for (int sl = 0; sl < normalscanlines; sl++) {
|
||||
for (int sl = 0; sl < normalscanlines; sl++)
|
||||
{
|
||||
spr_read.start_scanline();
|
||||
|
||||
g_rasterpos = 0;
|
||||
@ -2150,7 +2147,8 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
const int yp = sl - 1;
|
||||
ppuphase = PPUPHASE_BG;
|
||||
|
||||
if (sl != 0 && sl < 241) { // ignore the invisible
|
||||
if (sl != 0 && sl < 241) // ignore the invisible
|
||||
{
|
||||
DEBUG(FCEUD_UpdatePPUView(scanline = yp, 1));
|
||||
DEBUG(FCEUD_UpdateNTView(scanline = yp, 1));
|
||||
}
|
||||
@ -2209,7 +2207,7 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
{
|
||||
pixel = addr & 0x1F;
|
||||
}
|
||||
pixelcolor = PALRAM[pixel];
|
||||
pixelcolor = READPAL_MOTHEROFALL(pixel);
|
||||
}
|
||||
|
||||
//generate the BG data
|
||||
@ -2467,7 +2465,5 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
}
|
||||
|
||||
finish:
|
||||
FCEU_PutImage();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -48,3 +48,7 @@ enum PPUPHASE {
|
||||
};
|
||||
|
||||
extern PPUPHASE ppuphase;
|
||||
|
||||
extern unsigned char *cdloggervdata;
|
||||
extern unsigned int cdloggerVideoDataSize;
|
||||
extern volatile int rendercount, vromreadcount, undefinedvromcount;
|
||||
|
@ -1,9 +1,12 @@
|
||||
uint8 *C;
|
||||
register uint8 cc;
|
||||
uint8 cc;
|
||||
uint32 vadr;
|
||||
#ifdef PPU_VRC5FETCH
|
||||
uint8 tmpd;
|
||||
#endif
|
||||
|
||||
#ifndef PPUT_MMC5SP
|
||||
register uint8 zz;
|
||||
uint8 zz;
|
||||
#else
|
||||
uint8 xs, ys;
|
||||
xs = X1;
|
||||
@ -42,7 +45,11 @@ if (X1 >= 2) {
|
||||
#else
|
||||
zz = RefreshAddr & 0x1F;
|
||||
C = vnapage[(RefreshAddr >> 10) & 3];
|
||||
vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; // Fetch name table byte.
|
||||
#ifdef PPU_VRC5FETCH
|
||||
tmpd = QTAINTRAM[((((RefreshAddr >> 10) & 3) >> ((qtaintramreg >> 1)) & 1) << 10) | (RefreshAddr & 0x3FF)];
|
||||
vofs = ((tmpd & 0x3F) << 12) | ((RefreshAddr >> 12) & 7); // recalculate VROM offset
|
||||
#endif
|
||||
vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; // Fetch name table byte.
|
||||
#endif
|
||||
|
||||
#ifdef PPUT_HOOK
|
||||
@ -78,7 +85,16 @@ pshift[1] <<= 8;
|
||||
#elif defined(PPUT_MMC5)
|
||||
C = MMC5BGVRAMADR(vadr);
|
||||
#else
|
||||
|
||||
#ifdef PPU_VRC5FETCH
|
||||
if(tmpd & 0x40)
|
||||
C = CHRptr[0] + vadr;
|
||||
else
|
||||
C = VRAMADR(vadr);
|
||||
#else
|
||||
C = VRAMADR(vadr);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -99,12 +115,20 @@ pshift[1] <<= 8;
|
||||
pshift[1] |= C[0];
|
||||
}
|
||||
#else
|
||||
#ifdef PPU_VRC5FETCH
|
||||
pshift[0] |= C[0];
|
||||
if(tmpd & 0x40)
|
||||
pshift[1] |= (tmpd & 0x80) ? 0xFF : 0x00;
|
||||
else
|
||||
pshift[1] |= C[8];
|
||||
#else
|
||||
if(ScreenON)
|
||||
RENDER_LOGP(C);
|
||||
pshift[0] |= C[0];
|
||||
if(ScreenON)
|
||||
RENDER_LOGP(C + 8);
|
||||
pshift[1] |= C[8];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ((RefreshAddr & 0x1f) == 0x1f)
|
||||
|
@ -67,6 +67,7 @@ static int32 RectDutyCount[2];
|
||||
static uint8 sweepon[2];
|
||||
/*static*/ int32 curfreq[2];
|
||||
static uint8 SweepCount[2];
|
||||
static uint8 SweepReload[2];
|
||||
|
||||
static uint16 nreg=0;
|
||||
|
||||
@ -99,7 +100,7 @@ extern const uint32 NoiseFreqTableNTSC[0x10] =
|
||||
|
||||
extern const uint32 NoiseFreqTablePAL[0x10] =
|
||||
{
|
||||
4, 7, 14, 30, 60, 88, 118, 148, 188,
|
||||
4, 8, 14, 30, 60, 88, 118, 148, 188,
|
||||
236, 354, 472, 708, 944, 1890, 3778
|
||||
};
|
||||
|
||||
@ -180,6 +181,7 @@ void LogDPCM(int romaddress, int dpcmsize){
|
||||
for (int dpcmstart = i; dpcmstart < (i + dpcmsize); dpcmstart++) {
|
||||
if(!(cdloggerdata[dpcmstart] & 0x40)) {
|
||||
cdloggerdata[dpcmstart] |= 0x40;
|
||||
cdloggerdata[dpcmstart] |= (romaddress >> 11) & 0x0c;
|
||||
|
||||
if(!(cdloggerdata[dpcmstart] & 2)){
|
||||
datacount++;
|
||||
@ -206,22 +208,15 @@ void LogDPCM(int romaddress, int dpcmsize){
|
||||
|
||||
static void SQReload(int x, uint8 V)
|
||||
{
|
||||
if(EnabledChannels&(1<<x))
|
||||
{
|
||||
if(x)
|
||||
DoSQ2();
|
||||
else
|
||||
DoSQ1();
|
||||
lengthcount[x]=lengthtable[(V>>3)&0x1f];
|
||||
}
|
||||
if(EnabledChannels&(1<<x))
|
||||
lengthcount[x]=lengthtable[(V>>3)&0x1f];
|
||||
|
||||
sweepon[x]=PSG[(x<<2)|1]&0x80;
|
||||
curfreq[x]=PSG[(x<<2)|0x2]|((V&7)<<8);
|
||||
SweepCount[x]=((PSG[(x<<2)|0x1]>>4)&7)+1;
|
||||
|
||||
RectDutyCount[x]=7;
|
||||
EnvUnits[x].reloaddec=1;
|
||||
//reloadfreq[x]=1;
|
||||
/* use the low 8 bits data from pulse period
|
||||
* instead of from the sweep period */
|
||||
/* https://forums.nesdev.com/viewtopic.php?t=219&p=1431 */
|
||||
curfreq[x]=(curfreq[x] & 0xff)|((V&7)<<8);
|
||||
RectDutyCount[x]=7;
|
||||
EnvUnits[x].reloaddec=1;
|
||||
}
|
||||
|
||||
static DECLFW(Write_PSG)
|
||||
@ -237,7 +232,9 @@ static DECLFW(Write_PSG)
|
||||
V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1);
|
||||
break;
|
||||
case 0x1:
|
||||
DoSQ1();
|
||||
sweepon[0]=V&0x80;
|
||||
SweepReload[0]=1;
|
||||
break;
|
||||
case 0x2:
|
||||
DoSQ1();
|
||||
@ -245,6 +242,7 @@ static DECLFW(Write_PSG)
|
||||
curfreq[0]|=V;
|
||||
break;
|
||||
case 0x3:
|
||||
DoSQ1();
|
||||
SQReload(0,V);
|
||||
break;
|
||||
case 0x4:
|
||||
@ -255,7 +253,9 @@ static DECLFW(Write_PSG)
|
||||
V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1);
|
||||
break;
|
||||
case 0x5:
|
||||
DoSQ2();
|
||||
sweepon[1]=V&0x80;
|
||||
SweepReload[1]=1;
|
||||
break;
|
||||
case 0x6:
|
||||
DoSQ2();
|
||||
@ -263,6 +263,7 @@ static DECLFW(Write_PSG)
|
||||
curfreq[1]|=V;
|
||||
break;
|
||||
case 0x7:
|
||||
DoSQ2();
|
||||
SQReload(1,V);
|
||||
break;
|
||||
case 0xa:
|
||||
@ -421,44 +422,28 @@ static void FrameSoundStuff(int V)
|
||||
/* Frequency Sweep Code Here */
|
||||
/* xxxx 0000 */
|
||||
/* xxxx = hz. 120/(x+1)*/
|
||||
if(sweepon[P])
|
||||
/* http://wiki.nesdev.com/w/index.php/APU_Sweep */
|
||||
/* https://forums.nesdev.com/viewtopic.php?t=219&p=1431 */
|
||||
if (SweepCount[P] > 0) SweepCount[P]--;
|
||||
if (SweepCount[P] <= 0)
|
||||
{
|
||||
int32 mod=0;
|
||||
|
||||
if(SweepCount[P]>0) SweepCount[P]--;
|
||||
if(SweepCount[P]<=0)
|
||||
int sweepShift = (PSG[(P << 2) + 0x1] & 7);
|
||||
if (sweepon[P] && sweepShift && curfreq[P] >= 8)
|
||||
{
|
||||
SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1;
|
||||
if(PSG[(P<<2)+0x1]&0x8)
|
||||
{
|
||||
mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7));
|
||||
if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
|
||||
{
|
||||
curfreq[P]+=mod;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mod=curfreq[P]>>(PSG[(P<<2)+0x1]&7);
|
||||
if((mod+curfreq[P])&0x800)
|
||||
{
|
||||
sweepon[P]=0;
|
||||
curfreq[P]=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/)
|
||||
{
|
||||
curfreq[P]+=mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
int32 mod = (curfreq[P] >> sweepShift);
|
||||
if (PSG[(P << 2) + 0x1] & 0x8)
|
||||
curfreq[P] -= (mod + (P ^ 1));
|
||||
else if ((mod + curfreq[P]) < 0x800)
|
||||
curfreq[P] += mod;
|
||||
}
|
||||
|
||||
SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1);
|
||||
}
|
||||
else /* Sweeping is disabled: */
|
||||
|
||||
if (SweepReload[P])
|
||||
{
|
||||
//curfreq[P]&=0xFF00;
|
||||
//curfreq[P]|=PSG[(P<<2)|0x2]; //|((PSG[(P<<2)|3]&7)<<8);
|
||||
SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1);
|
||||
SweepReload[P] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -579,9 +564,10 @@ void FCEU_SoundCPUHook(int cycles)
|
||||
/* Unbelievably ugly hack */
|
||||
if(FSettings.SndRate)
|
||||
{
|
||||
soundtsoffs+=DMCacc;
|
||||
DoPCM();
|
||||
soundtsoffs-=DMCacc;
|
||||
const uint32 fudge = std::min<uint32>(-DMCacc, soundtsoffs + timestamp);
|
||||
soundtsoffs -= fudge;
|
||||
DoPCM();
|
||||
soundtsoffs += fudge;
|
||||
}
|
||||
RawDALatch+=t;
|
||||
if(RawDALatch&0x80)
|
||||
@ -1096,8 +1082,9 @@ int FlushEmulateSound(void)
|
||||
|
||||
SexyFilter(Wave,WaveFinal,end>>4);
|
||||
|
||||
//if(FSettings.lowpass)
|
||||
// SexyFilter2(WaveFinal,end>>4);
|
||||
if(FSettings.lowpass)
|
||||
SexyFilter2(WaveFinal,end>>4);
|
||||
|
||||
if(end&0xF)
|
||||
Wave[0]=Wave[(end>>4)];
|
||||
Wave[end>>4]=0;
|
||||
|
@ -43,8 +43,9 @@
|
||||
#endif
|
||||
|
||||
//TODO - we really need some kind of global platform-specific options api
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
#include "drivers/win/main.h"
|
||||
#include "drivers/win/cheat.h"
|
||||
#include "drivers/win/ram_search.h"
|
||||
#include "drivers/win/ramwatch.h"
|
||||
#endif
|
||||
@ -60,14 +61,14 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void (*SPreSave)(void);
|
||||
static void (*SPostSave)(void);
|
||||
static void (*SPreSave)(void) = NULL;
|
||||
static void (*SPostSave)(void) = NULL;
|
||||
|
||||
static int SaveStateStatus[10];
|
||||
static int StateShow;
|
||||
|
||||
//tells the save system innards that we're loading the old format
|
||||
bool FCEU_state_loading_old_format;
|
||||
bool FCEU_state_loading_old_format = false;
|
||||
|
||||
char lastSavestateMade[2048]; //Stores the filename of the last savestate made (needed for UndoSavestate)
|
||||
bool undoSS = false; //This will be true if there is lastSavestateMade, it was made since ROM was loaded, a backup state for lastSavestateMade exists
|
||||
@ -311,7 +312,7 @@ static bool ReadStateChunks(EMUFILE* is, int32 totalsize)
|
||||
|
||||
//MBG TODO - can this be moved to a better place?
|
||||
//does it even make sense, displaying XBuf when its XBackBuf we just loaded?
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
else
|
||||
{
|
||||
FCEUD_BlitScreen(XBuf);
|
||||
@ -412,7 +413,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel)
|
||||
|
||||
if(SPreSave) SPreSave();
|
||||
totalsize+=WriteStateChunk(os,0x10,SFMDATA);
|
||||
if(SPreSave) SPostSave();
|
||||
if(SPostSave) SPostSave();
|
||||
|
||||
//save the length of the file
|
||||
int len = memory_savestate.size();
|
||||
@ -794,7 +795,7 @@ bool FCEUSS_Load(const char *fname, bool display_message)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
Update_RAM_Search(); // Update_RAM_Watch() is also called.
|
||||
#endif
|
||||
|
||||
@ -847,7 +848,7 @@ void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
|
||||
for(x=0;x<SFEXINDEX;x++)
|
||||
{
|
||||
if(SFMDATA[x].desc)
|
||||
free(SFMDATA[x].desc);
|
||||
free( (void*)SFMDATA[x].desc);
|
||||
}
|
||||
// adelikat, 3/14/09: had to add this to clear out the size parameter. NROM(mapper 0) games were having savestate crashes if loaded after a non NROM game because the size variable was carrying over and causing savestates to save too much data
|
||||
SFMDATA[0].s = 0;
|
||||
@ -857,8 +858,11 @@ void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
|
||||
SFEXINDEX=0;
|
||||
}
|
||||
|
||||
void AddExState(void *v, uint32 s, int type, char *desc)
|
||||
void AddExState(void *v, uint32 s, int type, const char *desc)
|
||||
{
|
||||
//do not accept extra state information if a null pointer was provided for v, so list won't terminate early
|
||||
if (v == 0) return;
|
||||
|
||||
if(s==~0)
|
||||
{
|
||||
SFORMAT* sf = (SFORMAT*)v;
|
||||
@ -884,8 +888,8 @@ void AddExState(void *v, uint32 s, int type, char *desc)
|
||||
|
||||
if(desc)
|
||||
{
|
||||
SFMDATA[SFEXINDEX].desc=(char *)FCEU_malloc(strlen(desc)+1);
|
||||
strcpy(SFMDATA[SFEXINDEX].desc,desc);
|
||||
SFMDATA[SFEXINDEX].desc=(const char *)FCEU_malloc(strlen(desc)+1);
|
||||
strcpy( (char*)SFMDATA[SFEXINDEX].desc,desc);
|
||||
}
|
||||
else
|
||||
SFMDATA[SFEXINDEX].desc=0;
|
||||
@ -917,8 +921,8 @@ void FCEUI_SelectStateNext(int n)
|
||||
|
||||
int FCEUI_SelectState(int w, int show)
|
||||
{
|
||||
FCEUSS_CheckStates();
|
||||
int oldstate=CurrentState;
|
||||
FCEUSS_CheckStates();
|
||||
if(w == -1) { StateShow = 0; return 0; } //mbg merge 7/17/06 had to make return a value
|
||||
|
||||
CurrentState=w;
|
||||
|
@ -44,11 +44,11 @@ struct SFORMAT
|
||||
uint32 s;
|
||||
|
||||
//a string description of the element
|
||||
char *desc;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
void ResetExState(void (*PreSave)(void),void (*PostSave)(void));
|
||||
void AddExState(void *v, uint32 s, int type, char *desc);
|
||||
void AddExState(void *v, uint32 s, int type, const char *desc);
|
||||
|
||||
//indicates that the value is a multibyte integer that needs to be put in the correct byte order
|
||||
#define FCEUSTATE_RLSB 0x80000000
|
||||
|
@ -131,6 +131,10 @@ typedef uint32_t uint32;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(__QT_DRIVER__)
|
||||
#define __WIN_DRIVER__
|
||||
#endif
|
||||
|
||||
|
||||
typedef void (*writefunc)(uint32 A, uint8 V);
|
||||
typedef uint8 (*readfunc)(uint32 A);
|
||||
|
@ -45,13 +45,13 @@ typedef struct {
|
||||
} UNIF_HEADER;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
const char *name;
|
||||
void (*init)(CartInfo *);
|
||||
int flags;
|
||||
} BMAPPING;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
const char *name;
|
||||
int (*init)(FCEUFILE *fp);
|
||||
} BFMAPPING;
|
||||
|
||||
@ -133,7 +133,7 @@ static int DoMirroring(FCEUFILE *fp) {
|
||||
return(0);
|
||||
mirrortodo = t;
|
||||
{
|
||||
static char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" };
|
||||
static const char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" };
|
||||
if (t < 6)
|
||||
FCEU_printf(" Name/Attribute Table Mirroring: %s\n", stuffo[t]);
|
||||
}
|
||||
@ -194,7 +194,7 @@ static int DINF(FCEUFILE *fp) {
|
||||
FCEU_printf(" Dumped by: %s\n", name);
|
||||
FCEU_printf(" Dumped with: %s\n", method);
|
||||
{
|
||||
char *months[12] = {
|
||||
const char *months[12] = {
|
||||
"January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"
|
||||
};
|
||||
@ -236,7 +236,7 @@ static int TVCI(FCEUFILE *fp) {
|
||||
if ((t = FCEU_fgetc(fp)) == EOF)
|
||||
return(0);
|
||||
if (t <= 2) {
|
||||
char *stuffo[3] = { "NTSC", "PAL", "NTSC and PAL" };
|
||||
const char *stuffo[3] = { "NTSC", "PAL", "NTSC and PAL" };
|
||||
if (t == 0) {
|
||||
GameInfo->vidsys = GIV_NTSC;
|
||||
FCEUI_SetVidSystem(0);
|
||||
@ -372,7 +372,7 @@ static BMAPPING bmap[] = {
|
||||
{ "H2288", UNLH2288_Init, 0 },
|
||||
{ "HKROM", HKROM_Init, 0 },
|
||||
{ "KOF97", UNLKOF97_Init, 0 },
|
||||
{ "KONAMI-QTAI", Mapper190_Init, 0 },
|
||||
{ "KONAMI-QTAI", QTAi_Init, 0 },
|
||||
{ "KS7010", UNLKS7010_Init, 0 },
|
||||
{ "KS7012", UNLKS7012_Init, 0 },
|
||||
{ "KS7013B", UNLKS7013B_Init, 0 },
|
||||
@ -475,6 +475,10 @@ static BMAPPING bmap[] = {
|
||||
{ "8-IN-1", BMC8IN1_Init, 0 },
|
||||
{ "80013-B", BMC80013B_Init, 0 },
|
||||
{ "HPxx", BMCHPxx_Init, 0 },
|
||||
{ "MINDKIDS", MINDKIDS_Init, BMCFLAG_256KCHRR },
|
||||
{ "FNS", FNS_Init, BMCFLAG_16KCHRR },
|
||||
{ "BS-400R", BS400R_Init, 0 },
|
||||
{ "BS-4040R", BS4040R_Init, 0 },
|
||||
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
@ -539,23 +543,22 @@ static int InitializeBoard(void) {
|
||||
CHRRAMSize = 256;
|
||||
else
|
||||
CHRRAMSize = 8;
|
||||
CHRRAMSize <<= 10;
|
||||
CHRRAMSize <<= 10;
|
||||
if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) {
|
||||
SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1);
|
||||
AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR");
|
||||
} else
|
||||
return(-1);
|
||||
return 2;
|
||||
}
|
||||
if (bmap[x].flags & BMCFLAG_FORCE4)
|
||||
mirrortodo = 4;
|
||||
MooMirroring();
|
||||
bmap[x].init(&UNIFCart);
|
||||
return(1);
|
||||
return 0;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
FCEU_PrintError("Board type not supported.");
|
||||
return(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void UNIFGI(GI h) {
|
||||
@ -588,53 +591,58 @@ int UNIFLoad(const char *name, FCEUFILE *fp) {
|
||||
FCEU_fseek(fp, 0, SEEK_SET);
|
||||
FCEU_fread(&unhead, 1, 4, fp);
|
||||
if (memcmp(&unhead, "UNIF", 4))
|
||||
return 0;
|
||||
return LOADER_INVALID_FORMAT;
|
||||
|
||||
ResetCartMapping();
|
||||
|
||||
ResetExState(0, 0);
|
||||
ResetUNIF();
|
||||
if (!FCEU_read32le(&unhead.info, fp))
|
||||
goto aborto;
|
||||
if (FCEU_fseek(fp, 0x20, SEEK_SET) < 0)
|
||||
goto aborto;
|
||||
if (!LoadUNIFChunks(fp))
|
||||
goto aborto;
|
||||
if (!FCEU_read32le(&unhead.info, fp)
|
||||
|| (FCEU_fseek(fp, 0x20, SEEK_SET) < 0)
|
||||
|| !LoadUNIFChunks(fp))
|
||||
{
|
||||
int x;
|
||||
struct md5_context md5;
|
||||
|
||||
md5_starts(&md5);
|
||||
|
||||
for (x = 0; x < 32; x++)
|
||||
if (malloced[x]) {
|
||||
md5_update(&md5, malloced[x], mallocedsizes[x]);
|
||||
}
|
||||
md5_finish(&md5, UNIFCart.MD5);
|
||||
FCEU_printf(" ROM MD5: 0x");
|
||||
for (x = 0; x < 16; x++)
|
||||
FCEU_printf("%02x", UNIFCart.MD5[x]);
|
||||
FCEU_printf("\n");
|
||||
memcpy(&GameInfo->MD5, &UNIFCart.MD5, sizeof(UNIFCart.MD5));
|
||||
FreeUNIF();
|
||||
ResetUNIF();
|
||||
FCEU_PrintError("Error reading UNIF ROM image.");
|
||||
return LOADER_HANDLED_ERROR;
|
||||
}
|
||||
|
||||
if (!InitializeBoard())
|
||||
goto aborto;
|
||||
struct md5_context md5;
|
||||
md5_starts(&md5);
|
||||
for (int x = 0; x < 32; x++)
|
||||
if (malloced[x]) {
|
||||
md5_update(&md5, malloced[x], mallocedsizes[x]);
|
||||
}
|
||||
md5_finish(&md5, UNIFCart.MD5);
|
||||
FCEU_printf(" ROM MD5: 0x");
|
||||
for (int x = 0; x < 16; x++)
|
||||
FCEU_printf("%02x", UNIFCart.MD5[x]);
|
||||
FCEU_printf("\n");
|
||||
memcpy(&GameInfo->MD5, &UNIFCart.MD5, sizeof(UNIFCart.MD5));
|
||||
|
||||
int result = InitializeBoard();
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
goto init_ok;
|
||||
case 1:
|
||||
FCEU_PrintError("UNIF mapper \"%s\" is not supported at all.", sboardname);
|
||||
break;
|
||||
case 2:
|
||||
FCEU_PrintError("Unable to allocate CHR-RAM.");
|
||||
break;
|
||||
}
|
||||
FreeUNIF();
|
||||
ResetUNIF();
|
||||
return LOADER_HANDLED_ERROR;
|
||||
|
||||
init_ok:
|
||||
|
||||
#ifndef GEKKO
|
||||
FCEU_LoadGameSave(&UNIFCart);
|
||||
#endif
|
||||
|
||||
strcpy(LoadedRomFName, name); //For the debugger list
|
||||
GameInterface = UNIFGI;
|
||||
currCartInfo = &UNIFCart;
|
||||
return 1;
|
||||
|
||||
aborto:
|
||||
|
||||
FreeUNIF();
|
||||
ResetUNIF();
|
||||
|
||||
|
||||
return 0;
|
||||
return LOADER_OK;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ void EKROM_Init(CartInfo *info);
|
||||
void ELROM_Init(CartInfo *info);
|
||||
void ETROM_Init(CartInfo *info);
|
||||
void EWROM_Init(CartInfo *info);
|
||||
void GNROM_Init(CartInfo *info);
|
||||
//void GNROM_Init(CartInfo *info);
|
||||
void HKROM_Init(CartInfo *info);
|
||||
void LE05_Init(CartInfo *info);
|
||||
void LH10_Init(CartInfo *info);
|
||||
@ -59,7 +59,7 @@ void LH32_Init(CartInfo *info);
|
||||
void LH53_Init(CartInfo *info);
|
||||
void MALEE_Init(CartInfo *info);
|
||||
void MHROM_Init(CartInfo *info);
|
||||
void Mapper190_Init(CartInfo *info);
|
||||
void QTAi_Init(CartInfo *info);
|
||||
void NROM_Init(CartInfo *info);
|
||||
void Novel_Init(CartInfo *info);
|
||||
void S74LS374NA_Init(CartInfo *info);
|
||||
@ -158,6 +158,11 @@ void BMC810131C_Init(CartInfo *info);
|
||||
void BMC8IN1_Init(CartInfo *info);
|
||||
void BMC80013B_Init(CartInfo *info);
|
||||
void BMCHPxx_Init(CartInfo *info);
|
||||
void MINDKIDS_Init(CartInfo *info);
|
||||
void FNS_Init(CartInfo *info);
|
||||
void BS400R_Init(CartInfo *info);
|
||||
void BS4040R_Init(CartInfo *info);
|
||||
void SMD132_SMD133_Init(CartInfo *info);
|
||||
|
||||
extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM
|
||||
// bank switcherooing with certain boards...
|
||||
|
@ -275,7 +275,7 @@ int write64le(uint64 b, EMUFILE* os)
|
||||
|
||||
int read32le(uint32 *Bufo, EMUFILE *fp)
|
||||
{
|
||||
uint32 buf;
|
||||
uint32 buf=0;
|
||||
if(fp->_fread(&buf,4)<4)
|
||||
return 0;
|
||||
#ifdef LOCAL_LE
|
||||
@ -288,7 +288,7 @@ int read32le(uint32 *Bufo, EMUFILE *fp)
|
||||
|
||||
int read16le(u16 *Bufo, EMUFILE *is)
|
||||
{
|
||||
u16 buf;
|
||||
u16 buf=0;
|
||||
if(is->_fread((char*)&buf,2) != 2)
|
||||
return 0;
|
||||
#ifdef LOCAL_LE
|
||||
@ -301,7 +301,7 @@ int read16le(u16 *Bufo, EMUFILE *is)
|
||||
|
||||
int read64le(uint64 *Bufo, EMUFILE *is)
|
||||
{
|
||||
uint64 buf;
|
||||
uint64 buf=0;
|
||||
if(is->_fread((char*)&buf,8) != 8)
|
||||
return 0;
|
||||
#ifdef LOCAL_LE
|
||||
|
@ -28,10 +28,10 @@ uint32 uppow2(uint32 n)
|
||||
int x;
|
||||
|
||||
for(x=31;x>=0;x--)
|
||||
if(n&(1<<x))
|
||||
if(n&(1u<<x))
|
||||
{
|
||||
if((1<<x)!=n)
|
||||
return(1<<(x+1));
|
||||
if((1u<<x)!=n)
|
||||
return(1u<<(x+1));
|
||||
break;
|
||||
}
|
||||
return n;
|
||||
|
@ -157,7 +157,7 @@ int chr_replace(char *str, char search, char replace) {
|
||||
|
||||
///Replaces all instances of 'search' with 'replace'
|
||||
///Returns number of sub-strings modified, or -1 on error
|
||||
int str_replace(char *str, char *search, char *replace) {
|
||||
int str_replace(char *str, const char *search, const char *replace) {
|
||||
unsigned int i=0,j=0; //mbg merge 7/17/06 changed to unsigned int
|
||||
int searchlen,replacelen;
|
||||
char *astr;
|
||||
@ -580,7 +580,7 @@ std::string mass_replace(const std::string &source, const std::string &victim, c
|
||||
return answer;
|
||||
}
|
||||
|
||||
#ifdef WIN32 // this code tends to crash on SDL.
|
||||
#ifdef __WIN_DRIVER__ // this code tends to crash on SDL.
|
||||
//http://www.codeproject.com/KB/string/UtfConverter.aspx
|
||||
#include "ConvertUTF.h"
|
||||
namespace UtfConverter
|
||||
@ -752,7 +752,7 @@ std::wstring mbstowcs(std::string str) // UTF8->UTF32
|
||||
{
|
||||
try {
|
||||
return UtfConverter::FromUtf8(str);
|
||||
} catch(std::exception) {
|
||||
} catch(std::exception &e) {
|
||||
return L"(failed UTF-8 conversion)";
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ int str_ltrim(char *str, int flags);
|
||||
int str_rtrim(char *str, int flags);
|
||||
int str_strip(char *str, int flags);
|
||||
int chr_replace(char *str, char search, char replace);
|
||||
int str_replace(char *str, char *search, char *replace);
|
||||
int str_replace(char *str, const char *search, const char *replace);
|
||||
|
||||
int HexStringToBytesLength(const std::string& str);
|
||||
int Base64StringToBytesLength(const std::string& str);
|
||||
|
@ -25,7 +25,7 @@
|
||||
#define __FCEU_VERSION
|
||||
|
||||
//todo - everyone will want to support this eventually, i suppose
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__QT_DRIVER__)
|
||||
#include "scmrev.h"
|
||||
#else
|
||||
#ifdef SVN_REV
|
||||
@ -60,8 +60,16 @@
|
||||
#define FCEU_COMPILER_DETAIL ""
|
||||
#endif
|
||||
|
||||
#define FCEU_VERSION_NUMERIC 22020
|
||||
#define FCEU_VERSION_STRING "2.2.3" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
|
||||
#define FCEU_VERSION_MAJOR 2
|
||||
#define FCEU_VERSION_MINOR 6
|
||||
#define FCEU_VERSION_PATCH 4
|
||||
|
||||
#define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) )
|
||||
#define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) )
|
||||
#define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 )
|
||||
#define FCEU_VERSION_PATCH_DECODE(x) (x % 100)
|
||||
|
||||
#define FCEU_VERSION_STRING "2.6.4" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
|
||||
#define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING
|
||||
|
||||
#endif
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "fceulua.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
#include "drivers/win/common.h" //For DirectX constants
|
||||
#include "drivers/win/input.h"
|
||||
#endif
|
||||
@ -72,6 +72,8 @@ static u8 *xbsave=NULL;
|
||||
GUIMESSAGE guiMessage;
|
||||
GUIMESSAGE subtitleMessage;
|
||||
|
||||
bool vidGuiMsgEna = true;
|
||||
|
||||
//for input display
|
||||
extern int input_display;
|
||||
extern uint32 cur_input_display;
|
||||
@ -87,23 +89,23 @@ std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
|
||||
|
||||
void FCEU_KillVirtualVideo(void)
|
||||
{
|
||||
//mbg merge TODO 7/17/06 temporarily removed
|
||||
//if(xbsave)
|
||||
//{
|
||||
// free(xbsave);
|
||||
// xbsave=0;
|
||||
//}
|
||||
//if(XBuf)
|
||||
//{
|
||||
//UnmapViewOfFile(XBuf);
|
||||
//CloseHandle(mapXBuf);
|
||||
//mapXBuf=NULL;
|
||||
//}
|
||||
//if(XBackBuf)
|
||||
//{
|
||||
// free(XBackBuf);
|
||||
// XBackBuf=0;
|
||||
//}
|
||||
if ( XBuf )
|
||||
{
|
||||
FCEU_free(XBuf); XBuf = NULL;
|
||||
}
|
||||
if ( XBackBuf )
|
||||
{
|
||||
FCEU_free(XBackBuf); XBackBuf = NULL;
|
||||
}
|
||||
if ( XDBuf )
|
||||
{
|
||||
FCEU_free(XDBuf); XDBuf = NULL;
|
||||
}
|
||||
if ( XDBackBuf )
|
||||
{
|
||||
FCEU_free(XDBackBuf); XDBackBuf = NULL;
|
||||
}
|
||||
//printf("Video Core Cleanup\n");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,6 +180,31 @@ static void ReallySnap(void)
|
||||
FCEU_DispMessage("Screen snapshot %d saved.",0,x-1);
|
||||
}
|
||||
|
||||
static uint32 GetButtonColor(uint32 held, uint32 c, uint32 ci, int bit)
|
||||
{
|
||||
uint32 on = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0x90 : 0xA7; //Standard, or Gray depending on movie mode
|
||||
uint32 oni = 0xA0; //Color for immediate keyboard buttons
|
||||
uint32 blend = 0xB6; //Blend of immiate and last held buttons
|
||||
uint32 ahold = 0x87; //Auto hold
|
||||
uint32 off = 0xCF;
|
||||
|
||||
uint32 color;
|
||||
uint8 mask = 1u << bit;
|
||||
if (held & mask) { //If auto-hold
|
||||
if (!(ci & mask))
|
||||
color = ahold;
|
||||
else
|
||||
color = (c & mask) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c & mask)
|
||||
color = (ci & mask) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else
|
||||
color = (ci & mask) ? oni : off;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
void FCEU_PutImage(void)
|
||||
{
|
||||
if(dosnapsave==2) //Save screenshot as, currently only flagged & run by the Win32 build. //TODO SDL: implement this?
|
||||
@ -246,20 +273,10 @@ void FCEU_PutImage(void)
|
||||
//Fancy input display code
|
||||
if(input_display)
|
||||
{
|
||||
extern uint32 JSAutoHeld;
|
||||
uint32 held;
|
||||
|
||||
int controller, c, ci, color;
|
||||
int i, j;
|
||||
uint32 on = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0x90:0xA7; //Standard, or Gray depending on movie mode
|
||||
uint32 oni = 0xA0; //Color for immediate keyboard buttons
|
||||
uint32 blend = 0xB6; //Blend of immiate and last held buttons
|
||||
uint32 ahold = 0x87; //Auto hold
|
||||
uint32 off = 0xCF;
|
||||
|
||||
uint8 *t = XBuf+(FSettings.LastSLine-9)*256 + 20; //mbg merge 7/17/06 changed t to uint8*
|
||||
if(input_display > 4) input_display = 4;
|
||||
for(controller = 0; controller < input_display; controller++, t += 56)
|
||||
for(int controller = 0; controller < input_display; controller++, t += 56)
|
||||
{
|
||||
for(i = 0; i < 34;i++)
|
||||
for(j = 0; j <9 ; j++)
|
||||
@ -267,33 +284,28 @@ void FCEU_PutImage(void)
|
||||
for(i = 3; i < 6; i++)
|
||||
for(j = 3; j< 6; j++)
|
||||
t[i+j*256] = 0xCF;
|
||||
c = cur_input_display >> (controller * 8);
|
||||
|
||||
uint32 held = 0;
|
||||
uint32 c = cur_input_display >> (controller * 8);
|
||||
uint32 ci = 0;
|
||||
uint32 color;
|
||||
|
||||
#ifdef __WIN_DRIVER__
|
||||
extern uint32 JSAutoHeld;
|
||||
// This doesn't work in anything except windows for now.
|
||||
// It doesn't get set anywhere in other ports.
|
||||
#ifdef WIN32
|
||||
if (!oldInputDisplay) ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0:GetGamepadPressedImmediate() >> (controller * 8);
|
||||
else ci = 0;
|
||||
if (!oldInputDisplay)
|
||||
ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0 : GetGamepadPressedImmediate() >> (controller * 8);
|
||||
|
||||
if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY)) held = (JSAutoHeld >> (controller * 8));
|
||||
else held = 0;
|
||||
if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY))
|
||||
held = (JSAutoHeld >> (controller * 8));
|
||||
#else
|
||||
// Put other port info here
|
||||
ci = 0;
|
||||
held = 0;
|
||||
#endif
|
||||
|
||||
//adelikat: I apologize to anyone who ever sifts through this color assignment
|
||||
//A
|
||||
if (held&1) { //If auto-hold
|
||||
if (!(ci&1) ) color = ahold;
|
||||
else
|
||||
color = (c&1) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&1) color = (ci&1) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&1) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 0);
|
||||
for(i=0; i < 4; i++)
|
||||
{
|
||||
for(j = 0; j < 4; j++)
|
||||
@ -304,15 +316,7 @@ void FCEU_PutImage(void)
|
||||
}
|
||||
}
|
||||
//B
|
||||
if (held&2) { //If auto-hold
|
||||
if (!(ci&2) ) color = ahold;
|
||||
else
|
||||
color = (c&2) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&2) color = (ci&2) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&2) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 1);
|
||||
for(i=0; i < 4; i++)
|
||||
{
|
||||
for(j = 0; j < 4; j++)
|
||||
@ -323,45 +327,21 @@ void FCEU_PutImage(void)
|
||||
}
|
||||
}
|
||||
//Select
|
||||
if (held&4) { //If auto-hold
|
||||
if (!(ci&4) ) color = ahold;
|
||||
else
|
||||
color = (c&4) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&4) color = (ci&4) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&4) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 2);
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
t[11+5*256+i] = color;
|
||||
t[11+6*256+i] = color;
|
||||
}
|
||||
//Start
|
||||
if (held&8) { //If auto-hold
|
||||
if (!(ci&8) ) color = ahold;
|
||||
else
|
||||
color = (c&8) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&8) color = (ci&8) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&8) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 3);
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
t[17+5*256+i] = color;
|
||||
t[17+6*256+i] = color;
|
||||
}
|
||||
//Up
|
||||
if (held&16) { //If auto-hold
|
||||
if (!(ci&16) ) color = ahold;
|
||||
else
|
||||
color = (c&16) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&16) color = (ci&16) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&16) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 4);
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 3; j++)
|
||||
@ -370,15 +350,7 @@ void FCEU_PutImage(void)
|
||||
}
|
||||
}
|
||||
//Down
|
||||
if (held&32) { //If auto-hold
|
||||
if (!(ci&32) ) color = ahold;
|
||||
else
|
||||
color = (c&32) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&32) color = (ci&32) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&32) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 5);
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 3; j++)
|
||||
@ -387,15 +359,7 @@ void FCEU_PutImage(void)
|
||||
}
|
||||
}
|
||||
//Left
|
||||
if (held&64) { //If auto-hold
|
||||
if (!(ci&64) ) color = ahold;
|
||||
else
|
||||
color = (c&64) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&64) color = (ci&64) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&64) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 6);
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 3; j++)
|
||||
@ -404,15 +368,7 @@ void FCEU_PutImage(void)
|
||||
}
|
||||
}
|
||||
//Right
|
||||
if (held&128) { //If auto-hold
|
||||
if (!(ci&128) ) color = ahold;
|
||||
else
|
||||
color = (c&128) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed!
|
||||
}
|
||||
else {
|
||||
if (c&128) color = (ci&128) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors
|
||||
else color = (ci&128) ? oni : off;
|
||||
}
|
||||
color = GetButtonColor(held, c, ci, 7);
|
||||
for(i = 0; i < 3; i++)
|
||||
{
|
||||
for(j = 0; j < 3; j++)
|
||||
@ -444,7 +400,7 @@ void snapAVI()
|
||||
FCEUI_AviVideoUpdate(XBuf);
|
||||
}
|
||||
|
||||
void FCEU_DispMessageOnMovie(char *format, ...)
|
||||
void FCEU_DispMessageOnMovie(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@ -452,7 +408,10 @@ void FCEU_DispMessageOnMovie(char *format, ...)
|
||||
vsnprintf(guiMessage.errmsg,sizeof(guiMessage.errmsg),format,ap);
|
||||
va_end(ap);
|
||||
|
||||
guiMessage.howlong = 180;
|
||||
if ( vidGuiMsgEna )
|
||||
{
|
||||
guiMessage.howlong = 180;
|
||||
}
|
||||
guiMessage.isMovieMessage = true;
|
||||
guiMessage.linesFromBottom = 0;
|
||||
|
||||
@ -460,7 +419,7 @@ void FCEU_DispMessageOnMovie(char *format, ...)
|
||||
guiMessage.howlong = 0;
|
||||
}
|
||||
|
||||
void FCEU_DispMessage(char *format, int disppos=0, ...)
|
||||
void FCEU_DispMessage(const char *format, int disppos=0, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
@ -475,7 +434,10 @@ void FCEU_DispMessage(char *format, int disppos=0, ...)
|
||||
strcat(temp, "\n");
|
||||
FCEU_printf(temp);
|
||||
|
||||
guiMessage.howlong = 180;
|
||||
if ( vidGuiMsgEna )
|
||||
{
|
||||
guiMessage.howlong = 180;
|
||||
}
|
||||
guiMessage.isMovieMessage = false;
|
||||
|
||||
guiMessage.linesFromBottom = disppos;
|
||||
@ -501,7 +463,7 @@ void FCEU_ResetMessages()
|
||||
}
|
||||
|
||||
|
||||
static int WritePNGChunk(FILE *fp, uint32 size, char *type, uint8 *data)
|
||||
static int WritePNGChunk(FILE *fp, uint32 size, const char *type, uint8 *data)
|
||||
{
|
||||
uint32 crc;
|
||||
|
||||
@ -631,7 +593,7 @@ int SaveSnapshot(void)
|
||||
dest++;
|
||||
for(x=256;x;x--)
|
||||
{
|
||||
u32 color = ModernDeemphColorMap(tmp,XBuf,1,1);
|
||||
u32 color = ModernDeemphColorMap(tmp,XBuf,1);
|
||||
*dest++=(color>>0x10)&0xFF;
|
||||
*dest++=(color>>0x08)&0xFF;
|
||||
*dest++=(color>>0x00)&0xFF;
|
||||
@ -774,29 +736,54 @@ bool FCEUI_ShowFPS()
|
||||
}
|
||||
void FCEUI_SetShowFPS(bool showFPS)
|
||||
{
|
||||
if ( Show_FPS != showFPS )
|
||||
{
|
||||
ResetFPS();
|
||||
}
|
||||
Show_FPS = showFPS;
|
||||
}
|
||||
void FCEUI_ToggleShowFPS()
|
||||
{
|
||||
Show_FPS ^= 1;
|
||||
|
||||
ResetFPS();
|
||||
}
|
||||
|
||||
static uint64 boop[60];
|
||||
static int boopcount = 0;
|
||||
static uint64 boop_ts = 0;
|
||||
static unsigned int boopcount = 0;
|
||||
|
||||
void ResetFPS(void)
|
||||
{
|
||||
boop_ts = 0;
|
||||
boopcount = 0;
|
||||
}
|
||||
|
||||
void ShowFPS(void)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
if(Show_FPS == false)
|
||||
if (Show_FPS == false)
|
||||
{
|
||||
return;
|
||||
uint64 da = FCEUD_GetTime() - boop[boopcount];
|
||||
char fpsmsg[16];
|
||||
int booplimit = PAL?50:60;
|
||||
boop[boopcount] = FCEUD_GetTime();
|
||||
}
|
||||
static char fpsmsg[16] = { 0 };
|
||||
uint64 ts = FCEUD_GetTime();
|
||||
uint64 da;
|
||||
|
||||
if ( boop_ts == 0 )
|
||||
{
|
||||
boop_ts = ts;
|
||||
}
|
||||
da = ts - boop_ts;
|
||||
|
||||
if ( da > FCEUD_GetTimeFreq() )
|
||||
{
|
||||
sprintf(fpsmsg, "%.1f", (double)boopcount / ((double)da / FCEUD_GetTimeFreq()));
|
||||
|
||||
boopcount = 0;
|
||||
boop_ts = ts;
|
||||
}
|
||||
boopcount++;
|
||||
|
||||
sprintf(fpsmsg, "%.1f", (double)booplimit / ((double)da / FCEUD_GetTimeFreq()));
|
||||
DrawTextTrans(XBuf + ((256 - ClipSidesOffset) - 40) + (FSettings.FirstSLine + 4) * 256, 256, (uint8*)fpsmsg, 0xA0);
|
||||
// It's not averaging FPS over exactly 1 second, but it's close enough.
|
||||
boopcount = (boopcount + 1) % booplimit;
|
||||
#endif
|
||||
}
|
||||
|
@ -12,7 +12,8 @@ extern uint8 *XBackBuf;
|
||||
extern uint8 *XDBuf;
|
||||
extern uint8 *XDBackBuf;
|
||||
extern int ClipSidesOffset;
|
||||
extern struct GUIMESSAGE
|
||||
|
||||
struct GUIMESSAGE
|
||||
{
|
||||
//countdown for gui messages
|
||||
int howlong;
|
||||
@ -26,10 +27,21 @@ extern struct GUIMESSAGE
|
||||
//in case of multiple lines, allow one to move the message
|
||||
int linesFromBottom;
|
||||
|
||||
} guiMessage;
|
||||
// constructor
|
||||
GUIMESSAGE(void)
|
||||
{
|
||||
howlong = 0;
|
||||
linesFromBottom = 0;
|
||||
isMovieMessage = false;
|
||||
errmsg[0] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern GUIMESSAGE guiMessage;
|
||||
extern GUIMESSAGE subtitleMessage;
|
||||
|
||||
extern bool vidGuiMsgEna;
|
||||
|
||||
void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur);
|
||||
|
||||
std::string FCEUI_GetSnapshotAsName();
|
||||
@ -37,6 +49,7 @@ void FCEUI_SetSnapshotAsName(std::string name);
|
||||
bool FCEUI_ShowFPS();
|
||||
void FCEUI_SetShowFPS(bool showFPS);
|
||||
void FCEUI_ToggleShowFPS();
|
||||
void ShowFPS();
|
||||
void snapAVI();
|
||||
void ShowFPS(void);
|
||||
void ResetFPS(void);
|
||||
void snapAVI(void);
|
||||
#endif
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
#define IOPTION_PREDIP 0x10
|
||||
typedef struct {
|
||||
char *name;
|
||||
const char *name;
|
||||
uint64 md5partial;
|
||||
int mapper;
|
||||
int mirroring;
|
||||
@ -102,10 +102,10 @@ void FCEU_VSUniCoin(void) {
|
||||
static int curppu;
|
||||
static int64 curmd5;
|
||||
|
||||
#define RP2C04_001 1
|
||||
#define RP2C04_002 2
|
||||
#define RP2C04_003 3
|
||||
#define RP2C05_004 4
|
||||
#define RP2C04_0001 1
|
||||
#define RP2C04_0002 2
|
||||
#define RP2C04_0003 3
|
||||
#define RP2C04_0004 4
|
||||
#define RCP2C03B 5
|
||||
#define RC2C05_01 6
|
||||
#define RC2C05_02 7
|
||||
@ -192,7 +192,7 @@ void FCEU_VSUniPower(void) {
|
||||
/* Games/PPU list. Information copied from MAME. ROMs are exchangable, so don't take
|
||||
this list as "this game must use this PPU".
|
||||
|
||||
RP2C04-001:
|
||||
RP2C04-0001:
|
||||
- Baseball
|
||||
- Freedom Force
|
||||
- Gradius
|
||||
@ -202,7 +202,7 @@ RP2C04-001:
|
||||
- Platoon
|
||||
- Super Xevious
|
||||
|
||||
RP2C04-002:
|
||||
RP2C04-0002:
|
||||
- Castlevania
|
||||
- Ladies golf
|
||||
- Mach Rider (Endurance Course)
|
||||
@ -211,21 +211,21 @@ RP2C04-002:
|
||||
- Stroke N' Match Golf
|
||||
- Wrecking Crew
|
||||
|
||||
RP2C04-003:
|
||||
- Dr mario
|
||||
RP2C04-0003:
|
||||
- Dr. Mario
|
||||
- Excite Bike
|
||||
- Goonies
|
||||
- Soccer
|
||||
- TKO Boxing
|
||||
|
||||
RP2c05-004:
|
||||
RP2C04-0004:
|
||||
- Clu Clu Land
|
||||
- Excite Bike (Japan)
|
||||
- Ice Climber
|
||||
- Ice Climber Dual (Japan)
|
||||
- Super Mario Bros.
|
||||
|
||||
Rcp2c03b:
|
||||
RCP2C03B:
|
||||
- Battle City
|
||||
- Duck Hunt
|
||||
- Mahjang
|
||||
@ -252,47 +252,47 @@ RC2C05-04:
|
||||
|
||||
VSUNIENTRY VSUniGames[] =
|
||||
{
|
||||
{ "Baseball", 0x691d4200ea42be45LL, 99, 2, RP2C04_001, 0 },
|
||||
{ "Battle City", 0x8540949d74c4d0ebLL, 99, 2, RP2C04_001, 0 },
|
||||
{ "Battle City(Bootleg)", 0x8093cbe7137ac031LL, 99, 2, RP2C04_001, 0 },
|
||||
{ "Baseball", 0x691d4200ea42be45LL, 99, 2, RP2C04_0001, 0 },
|
||||
{ "Battle City", 0x8540949d74c4d0ebLL, 99, 2, RP2C04_0001, 0 },
|
||||
{ "Battle City(Bootleg)", 0x8093cbe7137ac031LL, 99, 2, RP2C04_0001, 0 },
|
||||
|
||||
{ "Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB },
|
||||
{ "Dr Mario", 0xe1af09c477dc0081LL, 1, 0, RP2C04_003, IOPTION_SWAPDIRAB },
|
||||
{ "Duck Hunt", 0x47735d1e5f1205bbLL, 99, 2, RCP2C03B, IOPTION_GUN },
|
||||
{ "Excitebike", 0x3dcd1401bcafde77LL, 99, 2, RP2C04_003, 0 },
|
||||
{ "Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2, RP2C05_004, 0 },
|
||||
{ "Freedom Force", 0xed96436bd1b5e688LL, 4, 0, RP2C04_001, IOPTION_GUN }, /* Wrong color in game select screen? */
|
||||
{ "Stroke and Match Golf", 0x612325606e82bc66LL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 },
|
||||
{ "Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB },
|
||||
{ "Dr Mario", 0xe1af09c477dc0081LL, 1, 0, RP2C04_0003, IOPTION_SWAPDIRAB },
|
||||
{ "Duck Hunt", 0x47735d1e5f1205bbULL, 99, 2, RCP2C03B, IOPTION_GUN },
|
||||
{ "Excitebike", 0x3dcd1401bcafde77LL, 99, 2, RP2C04_0003, 0 },
|
||||
{ "Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2, RP2C04_0004, 0 },
|
||||
{ "Freedom Force", 0xed96436bd1b5e688LL, 4, 0, RP2C04_0001, IOPTION_GUN }, /* Wrong color in game select screen? */
|
||||
{ "Stroke and Match Golf", 0x612325606e82bc66LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 },
|
||||
|
||||
{ "Goonies", 0xb4032d694e1d2733LL, 151, 1, RP2C04_003, 0 },
|
||||
{ "Gradius", 0x50687ae63bdad976LL, 151, 1, RP2C04_001, IOPTION_SWAPDIRAB },
|
||||
{ "Gumshoe", 0x87161f8ee37758d3LL, 99, 2, RC2C05_03, IOPTION_GUN },
|
||||
{ "Gumshoe", 0xb8500780bf69ce29LL, 99, 2, RC2C05_03, IOPTION_GUN },
|
||||
{ "Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_001, IOPTION_GUN },
|
||||
{ "Ice Climber", 0xd21e999513435e2aLL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB },
|
||||
{ "Ladies Golf", 0x781b24be57ef6785LL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
|
||||
{ "Goonies", 0xb4032d694e1d2733LL, 151, 1, RP2C04_0003, 0 },
|
||||
{ "Gradius", 0x50687ae63bdad976LL, 151, 1, RP2C04_0001, IOPTION_SWAPDIRAB },
|
||||
{ "Gumshoe", 0x87161f8ee37758d3ULL, 99, 2, RC2C05_03, IOPTION_GUN },
|
||||
{ "Gumshoe", 0xb8500780bf69ce29ULL, 99, 2, RC2C05_03, IOPTION_GUN },
|
||||
{ "Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_0001, IOPTION_GUN },
|
||||
{ "Ice Climber", 0xd21e999513435e2aLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB },
|
||||
{ "Ladies Golf", 0x781b24be57ef6785LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
|
||||
|
||||
{ "Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_002, 0 },
|
||||
{ "Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_001, 0 },
|
||||
{ "Mighty Bomb Jack", 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02, 0 },
|
||||
{ "Ninja Jajamaru Kun", 0xb26a2c31474099c0LL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB },
|
||||
{ "Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_001, IOPTION_PREDIP, 0x01 },
|
||||
{ "Pinball (J)", 0x66ab1a3828cc901cLL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 },
|
||||
{ "Platoon", 0x160f237351c19f1fLL, 68, 1, RP2C04_001, 0 },
|
||||
{ "RBI Baseball", 0x6a02d345812938afLL, 4, 1, RP2C04_001, IOPTION_SWAPDIRAB },
|
||||
{ "Soccer", 0xd4e7a9058780eda3LL, 99, 2, RP2C04_003, IOPTION_SWAPDIRAB },
|
||||
{ "Star Luster", 0x8360e134b316d94cLL, 99, 2, RCP2C03B, 0 },
|
||||
{ "Stroke and Match Golf (J)", 0x869bb83e02509747LL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
|
||||
{ "Super Sky Kid", 0x78d04c1dd4ec0101LL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 },
|
||||
{ "Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_0002, 0 },
|
||||
{ "Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_0001, 0 },
|
||||
{ "Mighty Bomb Jack", 0xe6a89f4873fac37bULL, 0, 2, RC2C05_02, 0 },
|
||||
{ "Ninja Jajamaru Kun", 0xb26a2c31474099c0ULL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB },
|
||||
{ "Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_0001, IOPTION_PREDIP, 0x01 },
|
||||
{ "Pinball (J)", 0x66ab1a3828cc901cULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 },
|
||||
{ "Platoon", 0x160f237351c19f1fLL, 68, 1, RP2C04_0001, 0 },
|
||||
{ "RBI Baseball", 0x6a02d345812938afLL, 4, 1, RP2C04_0001, IOPTION_SWAPDIRAB },
|
||||
{ "Soccer", 0xd4e7a9058780eda3LL, 99, 2, RP2C04_0003, IOPTION_SWAPDIRAB },
|
||||
{ "Star Luster", 0x8360e134b316d94cULL, 99, 2, RCP2C03B, 0 },
|
||||
{ "Stroke and Match Golf (J)", 0x869bb83e02509747ULL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
|
||||
{ "Super Sky Kid", 0x78d04c1dd4ec0101ULL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 },
|
||||
|
||||
{ "Super Xevious", 0x2d396247cf58f9faLL, 206, 0, RP2C04_001, 0 },
|
||||
{ "Tetris", 0x531a5e8eea4ce157LL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 },
|
||||
{ "Top Gun", 0xf1dea36e6a7b531dLL, 2, 0, RC2C05_04, 0 },
|
||||
{ "VS Castlevania", 0x92fd6909c81305b9LL, 2, 1, RP2C04_002, 0 },
|
||||
{ "VS Slalom", 0x4889b5a50a623215LL, 0, 1, RP2C04_002, 0 },
|
||||
{ "VS Super Mario Bros", 0x39d8cfa788e20b6cLL, 99, 2, RP2C05_004, 0 },
|
||||
{ "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dLL, 99, 2, RP2C05_004, 0 },
|
||||
{ "VS TKO Boxing", 0x6e1ee06171d8ce3aLL, 4, 1, RP2C04_003, IOPTION_PREDIP, 0x00 },
|
||||
{ "Super Xevious", 0x2d396247cf58f9faLL, 206, 0, RP2C04_0001, 0 },
|
||||
{ "Tetris", 0x531a5e8eea4ce157ULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 },
|
||||
{ "Top Gun", 0xf1dea36e6a7b531dULL, 2, 0, RC2C05_04, 0 },
|
||||
{ "VS Castlevania", 0x92fd6909c81305b9LL, 2, 1, RP2C04_0002, 0 },
|
||||
{ "VS Slalom", 0x4889b5a50a623215LL, 0, 1, RP2C04_0002, 0 },
|
||||
{ "VS Super Mario Bros", 0x39d8cfa788e20b6cLL, 99, 2, RP2C04_0004, 0 },
|
||||
{ "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dLL, 99, 2, RP2C04_0004, 0 },
|
||||
{ "VS TKO Boxing", 0x6e1ee06171d8ce3aLL, 4, 1, RP2C04_0003, IOPTION_PREDIP, 0x00 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@ -302,6 +302,7 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring) {
|
||||
while (vs->name) {
|
||||
if (md5partial == vs->md5partial) {
|
||||
if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu;
|
||||
else default_palette_selection = 5;
|
||||
*MapperNo = vs->mapper;
|
||||
*Mirroring = vs->mirroring;
|
||||
GameInfo->type = GIT_VSUNI;
|
||||
|
@ -24,7 +24,7 @@ void FCEU_WriteWaveData(int32 *Buffer, int Count)
|
||||
int16 *dest;
|
||||
int x;
|
||||
|
||||
#ifndef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if(!soundlog) return;
|
||||
#else
|
||||
if(!soundlog && !FCEUI_AviIsRecording()) return;
|
||||
@ -46,7 +46,7 @@ void FCEU_WriteWaveData(int32 *Buffer, int Count)
|
||||
if(soundlog)
|
||||
wsize+=fwrite(temp,1,Count*sizeof(int16),soundlog);
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef __WIN_DRIVER__
|
||||
if(FCEUI_AviIsRecording())
|
||||
{
|
||||
FCEUI_AviSoundUpdate((void*)temp, Count);
|
||||
@ -124,3 +124,8 @@ bool FCEUI_BeginWaveRecord(const char *fn)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FCEUI_WaveRecordRunning(void)
|
||||
{
|
||||
return (soundlog != NULL);
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "types.h"
|
||||
|
||||
bool FCEUI_BeginWaveRecord(const char *fn);
|
||||
bool FCEUI_WaveRecordRunning(void);
|
||||
void FCEU_WriteWaveData(int32 *Buffer, int Count);
|
||||
int FCEUI_EndWaveRecord();
|
||||
int FCEUI_EndWaveRecord(void);
|
||||
|
@ -355,6 +355,11 @@ static uint8 CycTable[256] =
|
||||
/*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7,
|
||||
};
|
||||
|
||||
int X6502_GetOpcodeCycles( int op )
|
||||
{
|
||||
return CycTable[op];
|
||||
}
|
||||
|
||||
void X6502_IRQBegin(int w)
|
||||
{
|
||||
_IRQlow|=w;
|
||||
|
@ -90,5 +90,7 @@ void X6502_DMW(uint32 A, uint8 V);
|
||||
void X6502_IRQBegin(int w);
|
||||
void X6502_IRQEnd(int w);
|
||||
|
||||
int X6502_GetOpcodeCycles( int op );
|
||||
|
||||
#define _X6502H
|
||||
#endif
|
||||
|
@ -177,6 +177,7 @@ DUMMY(FCEUD_LoadStateFrom)
|
||||
DUMMY(FCEUD_MovieRecordTo)
|
||||
DUMMY(FCEUD_MovieReplayFrom)
|
||||
DUMMY(FCEUD_ToggleStatusIcon)
|
||||
DUMMY(FCEUD_FlushTrace)
|
||||
DUMMY(FCEUD_DebugBreakpoint)
|
||||
DUMMY(FCEUD_SoundToggle)
|
||||
DUMMY(FCEUD_AviRecordTo)
|
||||
|
@ -37,7 +37,7 @@ extern unsigned char * nesrom;
|
||||
int GetFCEUTiming();
|
||||
void UpdateDendy();
|
||||
void RebuildSubCheats(void);
|
||||
int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type);
|
||||
int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type);
|
||||
|
||||
extern int FDSLoad(const char *name, FCEUFILE *fp);
|
||||
extern int iNESLoad(const char *name, FCEUFILE *fp, int o);
|
||||
|
Loading…
Reference in New Issue
Block a user