Updated to the latest FCEUX 2.6.4 (git def5768)

This commit is contained in:
Daryl Borth 2022-06-15 19:58:04 -06:00
parent 2fbcb7a036
commit 965e1c6719
82 changed files with 4358 additions and 2853 deletions

View File

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

View File

@ -1,90 +1,90 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2005 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
*
* NTDEC, ASDER games
*
*/
#include "mapinc.h"
static uint8 reg[8];
static uint8 mirror, cmd, bank;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] =
{
{ &cmd, 1, "CMD" },
{ &mirror, 1, "MIRR" },
{ &bank, 1, "BANK" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setmirror(mirror ^ 1);
setprg8(0x8000, reg[0]);
setprg8(0xA000, reg[1]);
setchr2(0x0000, (reg[2] >> 1));
setchr2(0x0800, (reg[3] >> 1));
setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]);
setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]);
setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]);
setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]);
}
static DECLFW(M112Write) {
switch (A) {
case 0xe000: mirror = V & 1; Sync();; break;
case 0x8000: cmd = V & 7; break;
case 0xa000: reg[cmd] = V; Sync(); break;
case 0xc000: bank = V; Sync(); break;
}
}
static void M112Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
static void M112Power(void) {
bank = 0;
setprg16(0xC000, ~0);
setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M112Write);
SetWriteHandler(0x4020, 0x5FFF, M112Write);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(8, 0x6000, WRAM);
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}
}
static void StateRestore(int version) {
Sync();
}
void Mapper112_Init(CartInfo *info) {
info->Power = M112Power;
info->Close = M112Close;
GameStateRestore = StateRestore;
WRAM = (uint8*)FCEU_gmalloc(8192);
SetupCartPRGMapping(0x10, WRAM, 8192, 1);
AddExState(WRAM, 8192, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);
}

View File

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

View File

@ -1,232 +1,232 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
*
* It seems that 162/163/164 mappers are the same mapper with just different
* mapper modes enabled or disabled in software or hardware, need more nanjing
* carts
*/
#include "mapinc.h"
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static writefunc pcmwrite;
static void (*WSync)(void);
static SFORMAT StateRegs[] =
{
{ &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" },
{ reg, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0);
}
static void StateRestore(int version) {
WSync();
}
static DECLFR(ReadLow) {
switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500:
if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else
return 0;
}
return 4;
}
static void M163HB(void) {
if (reg[1] & 0x80) {
if (scanline == 239) {
setchr4(0x0000, 0);
setchr4(0x1000, 0);
} else if (scanline == 127) {
setchr4(0x0000, 1);
setchr4(0x1000, 1);
}
/*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{
setchr4(0x0000,1);
setchr4(0x1000,1);
}
else
{
setchr4(0x0000,0);
setchr4(0x1000,0);
}
*/
}
}
static DECLFW(Write) {
switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break;
}
}
static void Power(void) {
memset(reg, 0, 8);
reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
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;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
static void Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void Mapper164_Init(CartInfo *info) {
info->Power = Power;
info->Close = Close;
WSync = Sync;
WRAMSIZE = 8192;
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;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static DECLFW(Write2) {
if (A == 0x5101) {
if (laststrobe && !V) {
trigger ^= 1;
}
laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3);
else
switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break;
}
}
static void Power2(void) {
memset(reg, 0, 8);
laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
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;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
WSync();
}
void Mapper163_Init(CartInfo *info) {
info->Power = Power2;
info->Close = Close;
WSync = Sync;
GameHBIRQHook = M163HB;
WRAMSIZE = 8192;
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;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
static void Sync3(void) {
setchr8(0);
setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) {
case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
}
}
static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V;
WSync();
}
static void Power3(void) {
reg[0] = 3;
reg[1] = 0;
reg[2] = 0;
reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
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;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
WSync();
}
void UNLFS304_Init(CartInfo *info) {
info->Power = Power3;
info->Close = Close;
WSync = Sync3;
WRAMSIZE = 8192;
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;
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

View File

@ -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[] =
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,34 +1,34 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
*/
// mapper 111 - Cheapocabra board by Memblers
// 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:
// 2 x 8k pattern pages
// 2 x 8k nametable pages
//
// Notes:
// - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k?
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2002 Xodnizel
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
*/
// mapper 111 - Cheapocabra board by Memblers
// http://forums.nesdev.com/viewtopic.php?p=146039
//
// 512k PRG-ROM in 32k pages (flashable if battery backed is specified)
// 32k CHR-RAM used as:
// 2 x 8k pattern pages
// 2 x 8k nametable pages
//
// Notes:
// - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k?
#include "mapinc.h"
#include "../ines.h"

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,18 +1,18 @@
#ifndef _EMU2413_H_
#define _EMU2413_H_
#ifndef INLINE
#if defined(_MSC_VER)
#define INLINE __forceinline
#elif defined(__GNUC__)
#define INLINE __inline__
#elif defined(_MWERKS_)
#define INLINE inline
#else
#define INLINE
#endif
#endif
#ifndef INLINE
#if defined(_MSC_VER)
#define INLINE __forceinline
#elif defined(__GNUC__)
#define INLINE __inline__
#elif defined(_MWERKS_)
#define INLINE inline
#else
#define INLINE
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -27,14 +27,14 @@ typedef int16_t int16 ;
typedef uint32_t uint32 ;
typedef int32_t int32 ;
#else
typedef unsigned char uint8 ;
typedef signed char int8 ;
typedef unsigned short uint16 ;
typedef signed short int16 ;
typedef unsigned int uint32 ;
typedef signed int int32 ;
typedef unsigned char uint8 ;
typedef signed char int8 ;
typedef unsigned short uint16 ;
typedef signed short int16 ;
typedef unsigned int uint32 ;
typedef signed int int32 ;
#endif
#define PI 3.14159265358979323846

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -40,38 +40,38 @@ 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);
static void (*WHSync)(void);
static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
uint32 AB = A >> 11;
int x;
if (p)
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = p - A;
}
else
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = 0;
}
static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
uint32 AB = A >> 11;
int x;
if (p)
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = p - A;
}
else
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = 0;
}
}
void setfprg16(uint32 A, uint32 V) {
if (PRGsize[0] >= 16384) {
V &= PRGmask16[0];
setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
} else {
uint32 VA = V << 3;
int x;
for (x = 0; x < 8; x++)
setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
}
void setfprg16(uint32 A, uint32 V) {
if (PRGsize[0] >= 16384) {
V &= PRGmask16[0];
setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
} else {
uint32 VA = V << 3;
int x;
for (x = 0; x < 8; x++)
setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
}
}
void inc_flash_write_count(uint8 bank, uint32 A)
@ -282,4 +282,4 @@ void UNROM512_Init(CartInfo *info) {
}
AddExState(&latche, 1, 0, "LATC");
AddExState(&bus_conflict, 1, 0, "BUSC");
}
}

View File

@ -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" },
{ &regcmd, 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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,12 +743,9 @@ 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();
memset(&iNESCart, 0, sizeof(iNESCart));
@ -763,15 +770,35 @@ 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;
else
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)")
@ -934,16 +979,16 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
|| strstr(name, "(Italy)") || strstr(name, "(Spain)")
|| strstr(name, "(Sweden)") || strstr(name, "(Sw)")
|| strstr(name, "(Australia)") || strstr(name, "(A)")
|| strstr(name, "(a)"))
|| strstr(name, "(a)"))
FCEUI_SetVidSystem(1);
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;
}

View File

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

View File

@ -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,9 +870,18 @@ 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_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Toggle Frame Display", 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;
}

View File

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

View File

@ -76,9 +76,9 @@ static void ZapperFrapper(int w, uint8 *bg, uint8 *spr, uint32 linets, int final
}
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
@ -87,8 +87,8 @@ endo:
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);

View File

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

View File

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

View File

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

View File

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

View File

@ -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),\
@ -149,7 +151,7 @@ static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
}
}
static float const default_decoder [6] =
static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
fb = YIQ_TO_RGB( y, i, q, default_decoder, float, fr, fg );
@ -160,94 +162,94 @@ static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
//doesnt help
//float gamma=1.8f;
// auto gammafix = [=](float f) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); };
// auto clamp = [](int v) { return v<0 ? 0 : v>255 ? 255 : v; };
// r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q));
// g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q));
// auto gammafix = [=](float f) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); };
// auto clamp = [](int v) { return v<0 ? 0 : v>255 ? 255 : v; };
// r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q));
// g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q));
// b = clamp(255 * gammafix(y + -1.108545f*i + 1.709007f*q));
}
float bisqwit_gammafix(float f, float gamma) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); }
float bisqwit_gammafix(float f, float gamma) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); }
int bisqwit_clamp(int v) { return v<0 ? 0 : v>255 ? 255 : v; }
// Calculate the luma and chroma by emulating the relevant circuits:
// Calculate the luma and chroma by emulating the relevant circuits:
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;
// 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:
// http://wiki.nesdev.com/w/index.php/NTSC_video
// Decode the color index
int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1;
// Voltage levels, relative to synch voltage
static const float black=.518f, white=1.962f, attenuation=.746f,
levels[8] = {.350f, .518f, .962f,1.550f, // Signal low
1.094f,1.506f,1.962f,1.962f}; // Signal high
float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)],
levels[level + 4 * (color < 0xD)] };
//fceux alteration: two passes
//1st pass calculates bisqwit's base color
//2nd pass calculates it with deemph
//finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, we could pregenerate the scale factors)
//whatever, it gets the job done.
for(int pass=0;pass<2;pass++)
{
float y=0.f, i=0.f, q=0.f, gamma=1.8f;
for(int p=0; p<12; ++p) // 12 clock cycles per pixel.
{
// NES NTSC modulator (square wave between two voltage levels):
float spot = lo_and_hi[bisqwit_wave(p,color)];
// De-emphasis bits attenuate a part of the signal:
if(pass==1)
{
if(((entry & 0x40) && bisqwit_wave(p,12))
|| ((entry & 0x80) && bisqwit_wave(p, 4))
|| ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation;
}
// Normalize:
float v = (spot - black) / (white-black) / 12.f;
// Ideal TV NTSC demodulator:
y += v;
i += v * std::cos(3.141592653 * p / 6);
q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... )
// Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives
// the exactly same result, scaled by a factor of 2*cos(pi/12).
}
// Convert YIQ into RGB according to FCC-sanctioned conversion matrix.
int rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f*i + 0.623557f*q,gamma));
int gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f*i + -0.635691f*q,gamma));
int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma));
if(pass==0) myr = rt, myg = gt, myb = bt;
else
{
float rscale = (float)rt / myr;
float gscale = (float)gt / myg;
float bscale = (float)bt / myb;
#define BCLAMP(x) ((x)<0?0:((x)>255?255:(x)))
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:
// http://wiki.nesdev.com/w/index.php/NTSC_video
// Decode the color index
int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1;
// Voltage levels, relative to synch voltage
static const float black=.518f, white=1.962f, attenuation=.746f,
levels[8] = {.350f, .518f, .962f,1.550f, // Signal low
1.094f,1.506f,1.962f,1.962f}; // Signal high
float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)],
levels[level + 4 * (color < 0xD)] };
//fceux alteration: two passes
//1st pass calculates bisqwit's base color
//2nd pass calculates it with deemph
//finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, we could pregenerate the scale factors)
//whatever, it gets the job done.
for(int pass=0;pass<2;pass++)
{
float y=0.f, i=0.f, q=0.f, gamma=1.8f;
for(int p=0; p<12; ++p) // 12 clock cycles per pixel.
{
// NES NTSC modulator (square wave between two voltage levels):
float spot = lo_and_hi[bisqwit_wave(p,color)];
// De-emphasis bits attenuate a part of the signal:
if(pass==1)
{
if(((entry & 0x40) && bisqwit_wave(p,12))
|| ((entry & 0x80) && bisqwit_wave(p, 4))
|| ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation;
}
// Normalize:
float v = (spot - black) / (white-black) / 12.f;
// Ideal TV NTSC demodulator:
y += v;
i += v * std::cos(3.141592653 * p / 6);
q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... )
// Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives
// the exactly same result, scaled by a factor of 2*cos(pi/12).
}
// Convert YIQ into RGB according to FCC-sanctioned conversion matrix.
int rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f*i + 0.623557f*q,gamma));
int gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f*i + -0.635691f*q,gamma));
int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma));
if(pass==0) myr = rt, myg = gt, myb = bt;
else
{
float rscale = (float)rt / myr;
float gscale = (float)gt / myg;
float bscale = (float)bt / myb;
#define BCLAMP(x) ((x)<0?0:((x)>255?255:(x)))
if(myr!=0) r = (u8)(BCLAMP(r*rscale));
if(myg!=0) g = (u8)(BCLAMP(g*gscale));
if(myb!=0) b = (u8)(BCLAMP(b*bscale));
}
}
if(myb!=0) b = (u8)(BCLAMP(b*bscale));
}
}
}
//classic algorithm
@ -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)

View File

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

View File

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

View File

@ -48,3 +48,7 @@ enum PPUPHASE {
};
extern PPUPHASE ppuphase;
extern unsigned char *cdloggervdata;
extern unsigned int cdloggerVideoDataSize;
extern volatile int rendercount, vromreadcount, undefinedvromcount;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
@ -129,4 +129,4 @@ std::string wcstombs(std::wstring str);
std::string getExtension(const char* input);
std::string StripExtension(std::string filename);
std::string StripPath(std::string filename);
std::string StripPath(std::string filename);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
@ -629,4 +634,4 @@ const uint8 opwrite[256] = {
/*0xD0*/ 0, 0, 0,10, 0, 0,10,10, 0, 0, 0,10, 0, 0,10,10,
/*0xE0*/ 0, 0, 0, 9, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9,
/*0xF0*/ 0, 0, 0, 9, 0, 0, 9, 9, 0, 0, 0, 9, 0, 0, 9, 9,
};
};

View File

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

View File

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

View File

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