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; output[0] = output[1] = output[2] = 0;
char astr[128],ins[4]; char astr[128],ins[4];
int len = strlen(str); int len = strlen(str);
if ((!len) || (len > 0x127)) return 1; if ((!len) || (len > 127)) return 1;
strcpy(astr,str); strcpy(astr,str);
str_ucase(astr); str_ucase(astr);

View File

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

View File

@ -35,31 +35,39 @@ static SFORMAT StateRegs[] =
static void Sync(void) { static void Sync(void) {
int i; int i;
setmirror(((latched >> 6) & 1) ^ 1); setmirror(((latched >> 6) & 1) ^ 1);
switch (latchea) { switch (latchea & 3) {
case 0x8000: case 0:
for (i = 0; i < 4; i++) 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; break;
case 0x8002: case 2:
for (i = 0; i < 4; i++) 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; break;
case 0x8001: case 1:
case 0x8003: case 3:
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
unsigned int b; unsigned int b;
b = latched & 0x7F; b = latched & 0x3F;
if (i >= 2 && !(latchea & 0x2)) if (i >= 2 && !(latchea & 0x2))
b = 0x7F; b = b | 0x07;
setprg8(0x8000 + (i << 13), (i & 1) + ((b << 1) ^ (latched >> 7))); setprg8(0x8000 + (i << 13), (i & 1) + (b << 1));
} }
break; break;
} }
setchr8(0);
} }
static DECLFW(M15Write) { static DECLFW(M15Write) {
latchea = A; latchea = A;
latched = V; 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(); Sync();
} }
@ -70,7 +78,6 @@ static void StateRestore(int version) {
static void M15Power(void) { static void M15Power(void) {
latchea = 0x8000; latchea = 0x8000;
latched = 0; latched = 0;
setchr8(0);
setprg8r(0x10, 0x6000, 0); setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x6000, 0x7FFF, CartBW);

View File

@ -1,232 +1,232 @@
/* FCE Ultra - NES/Famicom Emulator /* FCE Ultra - NES/Famicom Emulator
* *
* Copyright notice for this file: * Copyright notice for this file:
* Copyright (C) 2002 Xodnizel 2006 CaH4e3 * Copyright (C) 2002 Xodnizel 2006 CaH4e3
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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 * 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 * mapper modes enabled or disabled in software or hardware, need more nanjing
* carts * carts
*/ */
#include "mapinc.h" #include "mapinc.h"
static uint8 laststrobe, trigger; static uint8 laststrobe, trigger;
static uint8 reg[8]; static uint8 reg[8];
static uint8 *WRAM = NULL; static uint8 *WRAM = NULL;
static uint32 WRAMSIZE; static uint32 WRAMSIZE;
static writefunc pcmwrite; static writefunc pcmwrite;
static void (*WSync)(void); static void (*WSync)(void);
static SFORMAT StateRegs[] = static SFORMAT StateRegs[] =
{ {
{ &laststrobe, 1, "STB" }, { &laststrobe, 1, "STB" },
{ &trigger, 1, "TRG" }, { &trigger, 1, "TRG" },
{ reg, 8, "REGS" }, { reg, 8, "REGS" },
{ 0 } { 0 }
}; };
static void Sync(void) { static void Sync(void) {
setprg8r(0x10, 0x6000, 0); setprg8r(0x10, 0x6000, 0);
setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF)); setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF));
setchr8(0); setchr8(0);
} }
static void StateRestore(int version) { static void StateRestore(int version) {
WSync(); WSync();
} }
static DECLFR(ReadLow) { static DECLFR(ReadLow) {
switch (A & 0x7700) { switch (A & 0x7700) {
case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break; case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break;
case 0x5500: case 0x5500:
if (trigger) if (trigger)
return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
else else
return 0; return 0;
} }
return 4; return 4;
} }
static void M163HB(void) { static void M163HB(void) {
if (reg[1] & 0x80) { if (reg[1] & 0x80) {
if (scanline == 239) { if (scanline == 239) {
setchr4(0x0000, 0); setchr4(0x0000, 0);
setchr4(0x1000, 0); setchr4(0x1000, 0);
} else if (scanline == 127) { } else if (scanline == 127) {
setchr4(0x0000, 1); setchr4(0x0000, 1);
setchr4(0x1000, 1); setchr4(0x1000, 1);
} }
/* /*
if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
{ {
setchr4(0x0000,1); setchr4(0x0000,1);
setchr4(0x1000,1); setchr4(0x1000,1);
} }
else else
{ {
setchr4(0x0000,0); setchr4(0x0000,0);
setchr4(0x1000,0); setchr4(0x1000,0);
} }
*/ */
} }
} }
static DECLFW(Write) { static DECLFW(Write) {
switch (A & 0x7300) { switch (A & 0x7300) {
case 0x5100: reg[0] = V; WSync(); break; case 0x5100: reg[0] = V; WSync(); break;
case 0x5000: reg[1] = V; WSync(); break; case 0x5000: reg[1] = V; WSync(); break;
case 0x5300: reg[2] = V; break; case 0x5300: reg[2] = V; break;
case 0x5200: reg[3] = V; WSync(); break; case 0x5200: reg[3] = V; WSync(); break;
} }
} }
static void Power(void) { static void Power(void) {
memset(reg, 0, 8); memset(reg, 0, 8);
reg[1] = 0xFF; reg[1] = 0xFF;
SetWriteHandler(0x5000, 0x5FFF, Write); SetWriteHandler(0x5000, 0x5FFF, Write);
SetReadHandler(0x6000, 0xFFFF, CartBR); SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync(); WSync();
} }
static void Close(void) { static void Close(void) {
if (WRAM) if (WRAM)
FCEU_gfree(WRAM); FCEU_gfree(WRAM);
WRAM = NULL; WRAM = NULL;
} }
void Mapper164_Init(CartInfo *info) { void Mapper164_Init(CartInfo *info) {
info->Power = Power; info->Power = Power;
info->Close = Close; info->Close = Close;
WSync = Sync; WSync = Sync;
WRAMSIZE = 8192; WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM"); AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) { if (info->battery) {
info->SaveGame[0] = WRAM; info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE; info->SaveGameLen[0] = WRAMSIZE;
} }
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0);
} }
static DECLFW(Write2) { static DECLFW(Write2) {
if (A == 0x5101) { if (A == 0x5101) {
if (laststrobe && !V) { if (laststrobe && !V) {
trigger ^= 1; trigger ^= 1;
} }
laststrobe = V; laststrobe = V;
} else if (A == 0x5100 && V == 6) //damn thoose protected games } else if (A == 0x5100 && V == 6) //damn thoose protected games
setprg32(0x8000, 3); setprg32(0x8000, 3);
else else
switch (A & 0x7300) { switch (A & 0x7300) {
case 0x5200: reg[0] = V; WSync(); break; 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 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break;
case 0x5300: reg[2] = V; break; case 0x5300: reg[2] = V; break;
case 0x5100: reg[3] = V; WSync(); break; case 0x5100: reg[3] = V; WSync(); break;
} }
} }
static void Power2(void) { static void Power2(void) {
memset(reg, 0, 8); memset(reg, 0, 8);
laststrobe = 1; laststrobe = 1;
pcmwrite = GetWriteHandler(0x4011); pcmwrite = GetWriteHandler(0x4011);
SetReadHandler(0x5000, 0x5FFF, ReadLow); SetReadHandler(0x5000, 0x5FFF, ReadLow);
SetWriteHandler(0x5000, 0x5FFF, Write2); SetWriteHandler(0x5000, 0x5FFF, Write2);
SetReadHandler(0x6000, 0xFFFF, CartBR); SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync(); WSync();
} }
void Mapper163_Init(CartInfo *info) { void Mapper163_Init(CartInfo *info) {
info->Power = Power2; info->Power = Power2;
info->Close = Close; info->Close = Close;
WSync = Sync; WSync = Sync;
GameHBIRQHook = M163HB; GameHBIRQHook = M163HB;
WRAMSIZE = 8192; WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM"); AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) { if (info->battery) {
info->SaveGame[0] = WRAM; info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE; info->SaveGameLen[0] = WRAMSIZE;
} }
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0);
} }
static void Sync3(void) { static void Sync3(void) {
setchr8(0); setchr8(0);
setprg8r(0x10, 0x6000, 0); setprg8r(0x10, 0x6000, 0);
switch (reg[3] & 7) { switch (reg[3] & 7) {
case 0: case 0:
case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break; case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break;
case 1: case 1:
case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break; case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break;
case 4: case 4:
case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break; case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break;
case 5: case 5:
case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break; case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break;
} }
} }
static DECLFW(Write3) { static DECLFW(Write3) {
// FCEU_printf("bs %04x %02x\n",A,V); // FCEU_printf("bs %04x %02x\n",A,V);
reg[(A >> 8) & 3] = V; reg[(A >> 8) & 3] = V;
WSync(); WSync();
} }
static void Power3(void) { static void Power3(void) {
reg[0] = 3; reg[0] = 3;
reg[1] = 0; reg[1] = 0;
reg[2] = 0; reg[2] = 0;
reg[3] = 7; reg[3] = 7;
SetWriteHandler(0x5000, 0x5FFF, Write3); SetWriteHandler(0x5000, 0x5FFF, Write3);
SetReadHandler(0x6000, 0xFFFF, CartBR); SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x6000, 0x7FFF, CartBW);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
WSync(); WSync();
} }
void UNLFS304_Init(CartInfo *info) { void UNLFS304_Init(CartInfo *info) {
info->Power = Power3; info->Power = Power3;
info->Close = Close; info->Close = Close;
WSync = Sync3; WSync = Sync3;
WRAMSIZE = 8192; WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM"); AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) { if (info->battery) {
info->SaveGame[0] = WRAM; info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE; info->SaveGameLen[0] = WRAMSIZE;
} }
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0); 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 // highly experimental, not actually working, just curious if it hapen to work with some other decoder
// SND Registers // SND Registers
static uint8 pcm_enable = 0; static uint8 pcm_enable = 0;
static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6; //static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
static writefunc pcmwrite; //static writefunc pcmwrite;
static SFORMAT StateRegs[] = static SFORMAT StateRegs[] =
{ {

View File

@ -18,6 +18,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* *
* Family Study Box by Fukutake Shoten * 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" #include "mapinc.h"

View File

@ -52,15 +52,23 @@ static DECLFW(M225Write) {
} }
static DECLFW(M225LoWrite) { static DECLFW(M225LoWrite) {
if (A & 0x800) {
prot[A & 0x03] = V;
}
} }
static DECLFR(M225LoRead) { static DECLFR(M225LoRead) {
return 0; if (A & 0x800) {
return prot[A & 3] & 0x0F;
}
return X.DB;
} }
static void M225Power(void) { static void M225Power(void) {
prg = 0; prg = 0;
chr = 0;
mode = 0; mode = 0;
mirr = 0;
Sync(); Sync();
SetReadHandler(0x5000, 0x5FFF, M225LoRead); SetReadHandler(0x5000, 0x5FFF, M225LoRead);
SetWriteHandler(0x5000, 0x5FFF, M225LoWrite); SetWriteHandler(0x5000, 0x5FFF, M225LoWrite);
@ -70,7 +78,9 @@ static void M225Power(void) {
static void M225Reset(void) { static void M225Reset(void) {
prg = 0; prg = 0;
chr = 0;
mode = 0; mode = 0;
mirr = 0;
Sync(); Sync();
} }

View File

@ -53,8 +53,8 @@ void Mirror(uint8 value)
static void Sync() static void Sync()
{ {
int prglo; int prglo = 0;
int prghi; int prghi = 0;
int outb = outer << 1; int outb = outer << 1;
//this can probably be rolled up, but i have no motivation to do so //this can probably be rolled up, but i have no motivation to do so
@ -127,14 +127,14 @@ static void Sync()
static DECLFW(WriteEXP) static DECLFW(WriteEXP)
{ {
uint32 addr = A; //uint32 addr = A;
uint8 value = V; uint8 value = V;
reg = value & 0x81; reg = value & 0x81;
} }
static DECLFW(WritePRG) static DECLFW(WritePRG)
{ {
uint32 addr = A; //uint32 addr = A;
uint8 value = V; uint8 value = V;
switch (reg) switch (reg)
{ {

View File

@ -21,6 +21,7 @@
#include "mapinc.h" #include "mapinc.h"
static uint8 preg, mirr; static uint8 preg, mirr;
static int hardmirr;
static SFORMAT StateRegs[] = static SFORMAT StateRegs[] =
{ {
@ -35,6 +36,8 @@ static void Sync(void) {
setchr8(0); setchr8(0);
if(mirr) if(mirr)
setmirror(mirr); setmirror(mirr);
else
setmirror(hardmirr); // restore hardwired mirroring
} }
static DECLFW(M71Write) { static DECLFW(M71Write) {
@ -46,6 +49,7 @@ static DECLFW(M71Write) {
} }
static void M71Power(void) { static void M71Power(void) {
preg = 0;
mirr = 0; mirr = 0;
Sync(); Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR);
@ -57,6 +61,7 @@ static void StateRestore(int version) {
} }
void Mapper71_Init(CartInfo *info) { void Mapper71_Init(CartInfo *info) {
hardmirr = info->mirror;
info->Power = M71Power; info->Power = M71Power;
GameStateRestore = StateRestore; GameStateRestore = StateRestore;

View File

@ -19,7 +19,6 @@
* *
* Super Game (Sugar Softec) protected mapper * Super Game (Sugar Softec) protected mapper
* Pocahontas 2 (Unl) [U][!], etc. * Pocahontas 2 (Unl) [U][!], etc.
* TODO: 9in1 LION KING HANGS!
*/ */
#include "mapinc.h" #include "mapinc.h"
@ -139,7 +138,7 @@ static DECLFW(UNL8237Write) {
} }
static DECLFW(UNL8237ExWrite) { static DECLFW(UNL8237ExWrite) {
switch (A) { switch (A & 0xF007) {
case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); break; case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); break;
case 0x5001: EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break; case 0x5001: EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break;
case 0x5007: EXPREGS[2] = V; break; case 0x5007: EXPREGS[2] = V; break;

View File

@ -237,13 +237,8 @@ void Mapper200_Init(CartInfo *info) {
//------------------ Map 201 --------------------------- //------------------ Map 201 ---------------------------
static void M201Sync(void) { static void M201Sync(void) {
if (latche & 8) { setprg32(0x8000, latche & 3);
setprg32(0x8000, latche & 3); setchr8(latche & 3);
setchr8(latche & 3);
} else {
setprg32(0x8000, 0);
setchr8(0);
}
} }
void Mapper201_Init(CartInfo *info) { void Mapper201_Init(CartInfo *info) {
@ -353,6 +348,17 @@ static void M227Sync(void) {
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3); uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
uint32 L = (latche >> 9) & 1; 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 ((latche >> 7) & 1) {
if (S) { if (S) {
setprg32(0x8000, p >> 1); setprg32(0x8000, p >> 1);

View File

@ -48,120 +48,205 @@ static SFORMAT StateRegs[] =
#define X24C0X_READ 3 #define X24C0X_READ 3
#define X24C0X_WRITE 4 #define X24C0X_WRITE 4
static uint8 x24c0x_data[256], x24c0x_state; static uint8 x24c0x_data[512];
static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount;
static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe;
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" }, { &x24c01_addr, 1, "ADDR" },
{ &x24c0x_word, 1, "WORD" }, { &x24c01_word, 1, "WORD" },
{ &x24c0x_latch, 1, "LATC" }, { &x24c01_latch, 1, "LATC" },
{ &x24c0x_bitcount, 1, "BITC" }, { &x24c01_bitcount, 1, "BITC" },
{ &x24c0x_sda, 1, "SDA" }, { &x24c01_sda, 1, "SDA" },
{ &x24c0x_scl, 1, "SCL" }, { &x24c01_scl, 1, "SCL" },
{ &x24c0x_out, 1, "OUT" }, { &x24c01_out, 1, "OUT" },
{ &x24c0x_oe, 1, "OE" }, { &x24c01_state, 1, "STAT" },
{ &x24c0x_state, 1, "STAT" },
{ 0 } { 0 }
}; };
static void x24c0x_init() { static SFORMAT x24c02StateRegs[] =
x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0; {
x24c0x_state = X24C0X_STANDBY; { &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) { static void x24c02_init() {
uint8 sda = (data >> 6) & 1; x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0;
uint8 scl = (data >> 5) & 1; x24c02_state = X24C0X_STANDBY;
x24c0x_oe = (data >> 7); }
if(x24c0x_scl && scl) { static void x24c01_write(uint8 data) {
if(x24c0x_sda && !sda) { // START uint8 scl = (data >> 5) & 1;
x24c0x_state = X24C0X_ADDRESS; uint8 sda = (data >> 6) & 1;
x24c0x_bitcount = 0;
x24c0x_addr = 0; if(x24c01_scl && scl) {
} else if(!x24c0x_sda && sda) { //STOP if(x24c01_sda && !sda) { // START
x24c0x_state = X24C0X_STANDBY; 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 } else if(!x24c01_scl && scl) { // RISING EDGE
switch(x24c0x_state) { switch(x24c01_state) {
case X24C0X_ADDRESS: case X24C0X_ADDRESS:
if(x24c0x_bitcount < 7) { if(x24c01_bitcount < 7) {
x24c0x_addr <<= 1; x24c01_addr <<= 1;
x24c0x_addr |= sda; x24c01_addr |= sda;
} else { } else {
if(!x24c02) // X24C01 mode x24c01_word = x24c01_addr;
x24c0x_word = x24c0x_addr; if(sda) // READ COMMAND
if(sda) { // READ COMMAND x24c01_state = X24C0X_READ;
x24c0x_state = X24C0X_READ; else // WRITE COMMAND
} else { // WRITE COMMAND x24c01_state = X24C0X_WRITE;
if(x24c02) // X24C02 mode
x24c0x_state = X24C0X_WORD;
else
x24c0x_state = X24C0X_WRITE;
}
} }
x24c0x_bitcount++; x24c01_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++;
break; break;
case X24C0X_READ: case X24C0X_READ:
if (x24c0x_bitcount == 8) { // ACK if (x24c01_bitcount == 8) { // ACK
x24c0x_out = 0; x24c01_out = 0;
x24c0x_latch = x24c0x_data[x24c0x_word]; x24c01_latch = x24c0x_data[x24c01_word];
x24c0x_bitcount = 0; x24c01_bitcount = 0;
} else { // REAL OUTPUT } else { // REAL OUTPUT
x24c0x_out = x24c0x_latch >> 7; x24c01_out = x24c01_latch >> 7;
x24c0x_latch <<= 1; x24c01_latch <<= 1;
x24c0x_bitcount++; x24c01_bitcount++;
if(x24c0x_bitcount == 8) { if(x24c01_bitcount == 8) {
x24c0x_word++; x24c01_word++;
x24c0x_word &= 0xff; x24c01_word &= 0xff;
} }
} }
break; break;
case X24C0X_WRITE: case X24C0X_WRITE:
if (x24c0x_bitcount == 8) { // ACK if (x24c01_bitcount == 8) { // ACK
x24c0x_out = 0; x24c01_out = 0;
x24c0x_latch = 0; x24c01_latch = 0;
x24c0x_bitcount = 0; x24c01_bitcount = 0;
} else { // REAL INPUT } else { // REAL INPUT
x24c0x_latch <<= 1; x24c01_latch <<= 1;
x24c0x_latch |= sda; x24c01_latch |= sda;
x24c0x_bitcount++; x24c01_bitcount++;
if(x24c0x_bitcount == 8) { if(x24c01_bitcount == 8) {
x24c0x_data[x24c0x_word] = x24c0x_latch; x24c0x_data[x24c01_word] = x24c01_latch;
x24c0x_word++; x24c01_word++;
x24c0x_word &= 0xff; x24c01_word &= 0xff;
} }
} }
break; break;
} }
} }
x24c0x_sda = sda; x24c01_sda = sda;
x24c0x_scl = scl; x24c01_scl = scl;
} }
static uint8 x24c0x_read() { static void x24c02_write(uint8 data) {
return x24c0x_out << 4; 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) { static void Sync(void) {
if (is153) { if (is153) {
int base = (reg[0] & 1) << 4; int base = (reg[0] & 1) << 4;
@ -174,12 +259,7 @@ static void Sync(void) {
setprg16(0x8000, reg[8]); setprg16(0x8000, reg[8]);
setprg16(0xC000, ~0); setprg16(0xC000, ~0);
} }
switch (reg[9] & 3) { SyncMirror();
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 DECLFW(BandaiWrite) { static DECLFW(BandaiWrite) {
@ -192,12 +272,15 @@ static DECLFW(BandaiWrite) {
case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break;
case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; 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) { 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) { static void BandaiIRQHook(int a) {
@ -213,7 +296,10 @@ static void BandaiIRQHook(int a) {
static void BandaiPower(void) { static void BandaiPower(void) {
IRQa = 0; IRQa = 0;
x24c0x_init(); if(x24c02)
x24c02_init();
else
x24c01_init();
Sync(); Sync();
SetReadHandler(0x6000, 0x7FFF, BandaiRead); SetReadHandler(0x6000, 0x7FFF, BandaiRead);
SetReadHandler(0x8000, 0xFFFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR);
@ -231,12 +317,12 @@ void Mapper16_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook; MapIRQHook = BandaiIRQHook;
info->battery = 1; info->battery = 1;
info->SaveGame[0] = x24c0x_data; info->SaveGame[0] = x24c0x_data + 256;
info->SaveGameLen[0] = 256; info->SaveGameLen[0] = 256;
AddExState(x24c0x_data, 256, 0, "DATA"); AddExState(x24c0x_data, 256, 0, "DATA");
AddExState(&x24c02StateRegs, ~0, 0, 0);
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
AddExState(&x24c0xStateRegs, ~0, 0, 0);
AddExState(&StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0);
} }
@ -250,9 +336,9 @@ void Mapper159_Init(CartInfo *info) {
info->SaveGame[0] = x24c0x_data; info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 128; info->SaveGameLen[0] = 128;
AddExState(x24c0x_data, 128, 0, "DATA"); AddExState(x24c0x_data, 128, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
AddExState(&x24c0xStateRegs, ~0, 0, 0);
AddExState(&StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0);
} }
@ -307,7 +393,9 @@ static int BarcodeReadPos;
static int BarcodeCycleCount; static int BarcodeCycleCount;
static uint32 BarcodeOut; static uint32 BarcodeOut;
int FCEUI_DatachSet(const uint8 *rcode) { // #define INTERL2OF5
int FCEUI_DatachSet(uint8 *rcode) {
int prefix_parity_type[10][6] = { 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, 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 }, { 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]; uint8 code[13 + 1];
uint32 tmp_p = 0; uint32 tmp_p = 0;
uint32 csum = 0;
int i, j; int i, j;
int len; int len;
@ -341,18 +430,46 @@ int FCEUI_DatachSet(const uint8 *rcode) {
} }
if (len != 13 && len != 12 && len != 8 && len != 7) return(0); 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); 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); BS(1); BS(0); BS(1);
if (len == 13 || len == 12) { if (len == 13 || len == 12) {
uint32 csum;
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
if (prefix_parity_type[code[0]][i]) { if (prefix_parity_type[code[0]][i]) {
for (j = 0; j < 7; j++) { for (j = 0; j < 7; j++) {
@ -362,53 +479,53 @@ int FCEUI_DatachSet(const uint8 *rcode) {
for (j = 0; j < 7; j++) { for (j = 0; j < 7; j++) {
BS(data_left_odd[code[i + 1]][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); BS(0); BS(1); BS(0); BS(1); BS(0);
for (i = 7; i < 12; i++) for (i = 7; i < 12; i++)
for (j = 0; j < 7; j++) { for (j = 0; j < 7; j++) {
BS(data_right[code[i]][j]); BS(data_right[code[i]][j]);
} }
csum = 0; // Calc and write down the control code if not assigned, instead, send code as is
for (i = 0; i < 12; i++) csum += code[i] * ((i & 1) ? 3 : 1); // Battle Rush uses modified type of codes with different control code calculation
csum = (10 - (csum % 10)) % 10; 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++) { for (j = 0; j < 7; j++) {
BS(data_right[csum][j]); BS(data_right[code[12]][j]);
} }
} else if (len == 8 || len == 7) { } 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 (i = 0; i < 4; i++)
for (j = 0; j < 7; j++) { for (j = 0; j < 7; j++) {
BS(data_left_odd[code[i]][j]); BS(data_left_odd[code[i]][j]);
} }
// Center guard bars
/* Center guard bars */
BS(0); BS(1); BS(0); BS(1); BS(0); BS(0); BS(1); BS(0); BS(1); BS(0);
for (i = 4; i < 7; i++) for (i = 4; i < 7; i++)
for (j = 0; j < 7; j++) { for (j = 0; j < 7; j++) {
BS(data_right[code[i]][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++) { for (j = 0; j < 7; j++) {
BS(data_right[csum][j]); BS(data_right[csum][j]);
} }
} }
// Right guard bars
/* Right guard bars */
BS(1); BS(0); BS(1); BS(1); BS(0); BS(1);
#endif
for (j = 0; j < 32; j++) { for (j = 0; j < 32; j++) {
BS(0x00); BS(0x00);
} }
BS(0xFF); BS(0xFF);
#undef BS #undef BS
@ -419,6 +536,26 @@ int FCEUI_DatachSet(const uint8 *rcode) {
return(1); 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) { static void BarcodeIRQHook(int a) {
BandaiIRQHook(a); BandaiIRQHook(a);
@ -436,7 +573,7 @@ static void BarcodeIRQHook(int a) {
} }
static DECLFR(BarcodeRead) { static DECLFR(BarcodeRead) {
return BarcodeOut; return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut;
} }
static void M157Power(void) { static void M157Power(void) {
@ -446,20 +583,29 @@ static void M157Power(void) {
BarcodeOut = 0; BarcodeOut = 0;
BarcodeCycleCount = 0; BarcodeCycleCount = 0;
Sync(); x24c01_init();
x24c02_init();
BarcodeSync();
SetWriteHandler(0x6000, 0xFFFF, BandaiWrite);
SetReadHandler(0x6000, 0x7FFF, BarcodeRead); SetReadHandler(0x6000, 0x7FFF, BarcodeRead);
SetReadHandler(0x8000, 0xFFFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite);
} }
void Mapper157_Init(CartInfo *info) { void Mapper157_Init(CartInfo *info) {
is153 = 1; x24c02 = 1;
info->Power = M157Power; info->Power = M157Power;
MapIRQHook = BarcodeIRQHook; MapIRQHook = BarcodeIRQHook;
GameInfo->cspecial = SIS_DATACH; 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; GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0); 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 byte_8CC6: .BYTE 0,$78, 0, 0,$12
*/ */
static uint8 sim0reset[0x1F] = { //static uint8 sim0reset[0x1F] = {
0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE, // 0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE,
0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53, // 0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53,
0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10, // 0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 // 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
}; //};
static void Sync(void) { static void Sync(void) {
setprg32(0x8000, prg_reg); setprg32(0x8000, prg_reg);

View File

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

View File

@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator /* FCE Ultra - NES/Famicom Emulator
* *
* Copyright notice for this file: * 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 * 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 * 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 * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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 * 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.
* only MMC3 mode
* *
* 6000 (xx76x210) | 0xC0 * COOLBOY cartridges use registers at address $6xxx
* 6001 (xxx354x) * MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000
* 6002 = 0 *
* 6003 = 0 * $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" #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 // Last banks are first in this mode, ignored when MMC3_cmd&0x40
if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
switch (A & 0xE000) { switch (A & 0xE000) {
case 0xA000:
if ((MMC3_cmd & 0x40)) V = 0;
break;
case 0xC000: case 0xC000:
if (!(MMC3_cmd & 0x40)) V = 0;
break;
case 0xE000: case 0xE000:
V = 0; V = 0;
break; break;
@ -115,10 +155,6 @@ static DECLFW(COOLBOYWrite) {
static void COOLBOYReset(void) { static void COOLBOYReset(void) {
MMC3RegReset(); MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
} }
@ -126,21 +162,52 @@ static void COOLBOYReset(void) {
static void COOLBOYPower(void) { static void COOLBOYPower(void) {
GenMMC3Power(); GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(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(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) { void COOLBOY_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 256, 8, 0); GenMMC3_Init(info, 2048, 256, 8, 1);
pwrap = COOLBOYPW; pwrap = COOLBOYPW;
cwrap = COOLBOYCW; cwrap = COOLBOYCW;
info->Power = COOLBOYPower; info->Power = COOLBOYPower;
info->Reset = COOLBOYReset; info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR"); 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" #include "emu2413.h"
static const unsigned char default_inst[15][8] = { static const unsigned char default_inst[15][8] = {
/* VRC7 instruments, January 17, 2004 update -Xodnizel */ /* VRC7 instruments, March 15, 2019 dumped by Nuke.YKT */
{ 0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17 }, { 0x03, 0x21, 0x05, 0x06, 0xE8, 0x81, 0x42, 0x27 },
{ 0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12 }, { 0x13, 0x41, 0x14, 0x0D, 0xD8, 0xF6, 0x23, 0x12 },
{ 0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02 }, { 0x11, 0x11, 0x08, 0x08, 0xFA, 0xB2, 0x20, 0x12 },
{ 0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27 }, { 0x31, 0x61, 0x0C, 0x07, 0xA8, 0x64, 0x61, 0x27 },
{ 0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28 }, { 0x32, 0x21, 0x1E, 0x06, 0xE1, 0x76, 0x01, 0x28 },
{ 0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95 }, { 0x02, 0x01, 0x06, 0x00, 0xA3, 0xE2, 0xF4, 0xF4 },
{ 0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07 }, { 0x21, 0x61, 0x1D, 0x07, 0x82, 0x81, 0x11, 0x07 },
{ 0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15 }, { 0x23, 0x21, 0x22, 0x17, 0xA2, 0x72, 0x01, 0x17 },
{ 0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11 }, { 0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 },
{ 0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12 }, { 0xB5, 0x01, 0x0F, 0x0F, 0xA8, 0xA5, 0x51, 0x02 },
{ 0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4 }, { 0x17, 0xC1, 0x24, 0x07, 0xF8, 0xF8, 0x22, 0x12 },
{ 0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16 }, { 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 },
{ 0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51 }, { 0x01, 0x02, 0xD3, 0x05, 0xC9, 0x95, 0x03, 0x02 },
{ 0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05 }, { 0x61, 0x63, 0x0C, 0x00, 0x94, 0xC0, 0x33, 0xF6 },
{ 0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17 }, { 0x21, 0x72, 0x0D, 0x00, 0xC1, 0xD5, 0x56, 0x06 },
}; };
/* Size of Sintable ( 8 -- 18 can be used. 9 recommended.)*/ /* 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++) for (i = 0; i < 0x40; i++)
OPLL_writeReg(opll, i, 0); OPLL_writeReg(opll, i, 0);
opll->realstep = (uint32)((1 << 31) / rate); opll->realstep = (uint32)((1u << 31) / rate);
opll->opllstep = (uint32)((1 << 31) / (clk / 72)); opll->opllstep = (uint32)((1u << 31) / (clk / 72));
opll->oplltime = 0; opll->oplltime = 0;
} }

View File

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

View File

@ -82,10 +82,10 @@ static int prg_mask;
//PRG wrapper //PRG wrapper
static void BMCFK23CPW(uint32 A, uint8 V) static void BMCFK23CPW(uint32 A, uint8 V)
{ {
uint32 bank = (EXPREGS[1] & 0x1F); //uint32 bank = (EXPREGS[1] & 0x1F);
uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0); //uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
uint32 block = (EXPREGS[1] & 0x60) | hiblock; //uint32 block = (EXPREGS[1] & 0x60) | hiblock;
uint32 extra = (EXPREGS[3] & 2); //uint32 extra = (EXPREGS[3] & 2);
// FCEU_printf("0:%04X:%02X\n",A,V); // FCEU_printf("0:%04X:%02X\n",A,V);
if((EXPREGS[0]&7)==4) if((EXPREGS[0]&7)==4)
@ -161,7 +161,7 @@ static DECLFW(BMCFK23CWrite)
EXPREGS[A&3]=V; EXPREGS[A&3]=V;
// BUT WHY is there any rom that need it actually? // 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("K3:(exp0=%02x)\n",EXPREGS[0]);
// FCEU_printf("WH0:%04X:%02X\n",A,V); // 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 //this little hack makes sure that we try all the dip switch settings eventually, if we reset enough
dipswitch++; dipswitch++;
dipswitch&=7; 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[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF; EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;

View File

@ -113,6 +113,9 @@ void MMC3RegReset(void) {
DRegBuf[6] = 0; DRegBuf[6] = 0;
DRegBuf[7] = 1; 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); FixMMC3PRG(0);
FixMMC3CHR(0); FixMMC3CHR(0);
} }
@ -187,7 +190,14 @@ DECLFW(MMC3_IRQWrite) {
DECLFW(KT008HackWrite) { DECLFW(KT008HackWrite) {
// FCEU_printf("%04x:%04x\n",A,V); // FCEU_printf("%04x:%04x\n",A,V);
switch (A & 3) { 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 1: break; // unk
case 2: break; // unk case 2: break; // unk
case 3: break; // unk case 3: break; // unk
@ -1353,3 +1363,30 @@ void TQROM_Init(CartInfo *info) {
void HKROM_Init(CartInfo *info) { void HKROM_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 512, 1, info->battery); 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 "mapinc.h"
#include <array>
#define ABANKS MMC5SPRVPage #define ABANKS MMC5SPRVPage
#define BBANKS MMC5BGVPage #define BBANKS MMC5BGVPage
#define SpriteON (PPU[1] & 0x10) //Show Sprite #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 uint8 WRAMPage;
static uint16 CHRBanksA[8], CHRBanksB[4]; static std::array<uint16,8> CHRBanksA;
static uint8 WRAMMaskEnable[2]; static std::array<uint16,4> CHRBanksB;
static std::array<uint8,2> WRAMMaskEnable;
uint8 mmc5ABMode; /* A=0, B=1 */ uint8 mmc5ABMode; /* A=0, B=1 */
static uint8 IRQScanline, IRQEnable; static uint8 IRQScanline, IRQEnable;
@ -93,18 +96,20 @@ static uint8 CHRMode, NTAMirroring, NTFill, ATFill;
static uint8 MMC5IRQR; static uint8 MMC5IRQR;
static uint8 MMC5LineCounter; static uint8 MMC5LineCounter;
static uint8 mmc5psize, mmc5vsize; static uint8 mmc5psize, mmc5vsize;
static uint8 mul[2]; static std::array<uint8,2> mul;
static uint32 WRAMSIZE = 0; static uint32 WRAMSIZE = 0;
static uint8 *WRAM = NULL; static uint8 *WRAM = NULL;
static uint8 *MMC5fill = NULL; static uint8 *MMC5fill = NULL;
static uint8 *ExRAM = NULL; static uint8 *ExRAM = NULL;
static uint8 MMC5battery = 0;
static uint8 MMC5WRAMsize; //configuration, not state const int MMC5WRAMMAX = 1<<7; // 7 bits in register interface (real MMC5 has only 4 pins, however)
static uint8 MMC5WRAMIndex[8]; //configuration, not state static uint8 MMC5WRAMsize=0; //configuration, not state
static uint8 MMC5WRAMIndex[MMC5WRAMMAX]; //configuration, not state
static uint8 MMC5ROMWrProtect[4]; static std::array<uint8,4> MMC5ROMWrProtect;
static uint8 MMC5MemIn[5]; static std::array<uint8,5> MMC5MemIn;
static void MMC5CHRA(void); static void MMC5CHRA(void);
static void MMC5CHRB(void); static void MMC5CHRB(void);
@ -146,12 +151,18 @@ uint8* MMC5BGVRAMADR(uint32 A)
static void mmc5_PPUWrite(uint32 A, uint8 V) { static void mmc5_PPUWrite(uint32 A, uint8 V) {
uint32 tmp = A; uint32 tmp = A;
extern uint8 PALRAM[0x20]; extern uint8 PALRAM[0x20];
extern uint8 UPALRAM[0x03];
if (tmp >= 0x3F00) { if (tmp >= 0x3F00) {
// hmmm.... if (!(tmp & 3)) {
if (!(tmp & 0xf)) if (!(tmp & 0xC)) {
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
else if (tmp & 3) PALRAM[(tmp & 0x1f)] = 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) { } else if (tmp < 0x2000) {
if (PPUCHRRAM & (1 << (tmp >> 10))) if (PPUCHRRAM & (1 << (tmp >> 10)))
VPage[tmp >> 10][tmp] = V; VPage[tmp >> 10][tmp] = V;
@ -308,6 +319,8 @@ int DetectMMC5WRAMSize(uint32 crc32) {
} }
static void BuildWRAMSizeTable(void) { static void BuildWRAMSizeTable(void) {
bool other = false; // non-standard configuration
// fill first 8 entries
int x; int x;
for (x = 0; x < 8; x++) { for (x = 0; x < 8; x++) {
switch (MMC5WRAMsize) { 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 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 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 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) { static void MMC5CHRA(void) {
@ -385,7 +411,7 @@ static void MMC5CHRB(void) {
} }
static void MMC5WRAM(uint32 A, uint32 V) { static void MMC5WRAM(uint32 A, uint32 V) {
V = MMC5WRAMIndex[V & 7]; V = MMC5WRAMIndex[V & (MMC5WRAMMAX-1)];
if (V != 255) { if (V != 255) {
setprg8r(0x10, A, V); setprg8r(0x10, A, V);
FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1)))); FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1))));
@ -410,8 +436,8 @@ static void MMC5PRG(void) {
MMC5MemIn[1] = MMC5MemIn[2] = 1; MMC5MemIn[1] = MMC5MemIn[2] = 1;
} else { } else {
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0; MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE); MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1); MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
} }
MMC5MemIn[3] = MMC5MemIn[4] = 1; MMC5MemIn[3] = MMC5MemIn[4] = 1;
MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1; MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1;
@ -424,8 +450,8 @@ static void MMC5PRG(void) {
setprg16(0x8000, (PRGBanks[1] & 0x7F) >> 1); setprg16(0x8000, (PRGBanks[1] & 0x7F) >> 1);
} else { } else {
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0; MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0;
MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE); MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE);
MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1); MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1);
} }
if (PRGBanks[2] & 0x80) { if (PRGBanks[2] & 0x80) {
MMC5ROMWrProtect[2] = 1; MMC5ROMWrProtect[2] = 1;
@ -433,7 +459,7 @@ static void MMC5PRG(void) {
setprg8(0xC000, PRGBanks[2] & 0x7F); setprg8(0xC000, PRGBanks[2] & 0x7F);
} else { } else {
MMC5ROMWrProtect[2] = 0; MMC5ROMWrProtect[2] = 0;
MMC5WRAM(0xC000, PRGBanks[2] & 7); MMC5WRAM(0xC000, PRGBanks[2] & (MMC5WRAMMAX-1));
} }
MMC5MemIn[4] = 1; MMC5MemIn[4] = 1;
MMC5ROMWrProtect[3] = 1; MMC5ROMWrProtect[3] = 1;
@ -447,7 +473,7 @@ static void MMC5PRG(void) {
MMC5MemIn[1 + x] = 1; MMC5MemIn[1 + x] = 1;
} else { } else {
MMC5ROMWrProtect[x] = 0; MMC5ROMWrProtect[x] = 0;
MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & 7); MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & (MMC5WRAMMAX-1));
} }
MMC5MemIn[4] = 1; MMC5MemIn[4] = 1;
MMC5ROMWrProtect[3] = 1; MMC5ROMWrProtect[3] = 1;
@ -510,7 +536,7 @@ static DECLFW(Mapper5_write) {
break; break;
case 0x5113: case 0x5113:
WRAMPage = V; WRAMPage = V;
MMC5WRAM(0x6000, V & 7); MMC5WRAM(0x6000, V & (MMC5WRAMMAX-1));
break; break;
case 0x5114: case 0x5114:
case 0x5115: case 0x5115:
@ -606,7 +632,7 @@ void MMC5Synco(void) {
case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break; case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break;
} }
} }
MMC5WRAM(0x6000, WRAMPage & 7); MMC5WRAM(0x6000, WRAMPage & (MMC5WRAMMAX-1));
if (!mmc5ABMode) { if (!mmc5ABMode) {
MMC5CHRB(); MMC5CHRB();
MMC5CHRA(); MMC5CHRA();
@ -869,22 +895,42 @@ void NSFMMC5_Close(void) {
if (WRAM) if (WRAM)
FCEU_gfree(WRAM); FCEU_gfree(WRAM);
WRAM = NULL; WRAM = NULL;
MMC5WRAMsize = 0;
FCEU_gfree(ExRAM); FCEU_gfree(ExRAM);
ExRAM = NULL; ExRAM = NULL;
} }
static void GenMMC5Reset(void) { static void GenMMC5Power(void) {
int x;
for (x = 0; x < 4; x++) PRGBanks[x] = ~0; PRGBanks.fill(0xFF);
for (x = 0; x < 8; x++) CHRBanksA[x] = ~0; WRAMPage = 0;
for (x = 0; x < 4; x++) CHRBanksB[x] = ~0; CHRBanksA.fill(0xFF);
WRAMMaskEnable[0] = WRAMMaskEnable[1] = ~0; CHRBanksB.fill(0xFF);
WRAMMaskEnable.fill(0xFF);
mmc5psize = mmc5vsize = 3; mmc5ABMode = 0;
IRQScanline = 0;
IRQEnable = 0;
CHRMode = 0; CHRMode = 0;
NTAMirroring = NTFill = ATFill = 0xFF; 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(); MMC5Synco();
@ -907,11 +953,11 @@ static void GenMMC5Reset(void) {
} }
static SFORMAT MMC5_StateRegs[] = { static SFORMAT MMC5_StateRegs[] = {
{ PRGBanks, 4, "PRGB" }, { &PRGBanks, 4, "PRGB" },
{ CHRBanksA, 16, "CHRA" }, { &CHRBanksA, 16, "CHRA" },
{ CHRBanksB, 8, "CHRB" }, { &CHRBanksB, 8, "CHRB" },
{ &WRAMPage, 1, "WRMP" }, { &WRAMPage, 1, "WRMP" },
{ WRAMMaskEnable, 2, "WRME" }, { &WRAMMaskEnable, 2, "WRME" },
{ &mmc5ABMode, 1, "ABMD" }, { &mmc5ABMode, 1, "ABMD" },
{ &IRQScanline, 1, "IRQS" }, { &IRQScanline, 1, "IRQS" },
{ &IRQEnable, 1, "IRQE" }, { &IRQEnable, 1, "IRQE" },
@ -925,9 +971,9 @@ static SFORMAT MMC5_StateRegs[] = {
{ &MMC5LineCounter, 1, "LCTR" }, { &MMC5LineCounter, 1, "LCTR" },
{ &mmc5psize, 1, "PSIZ" }, { &mmc5psize, 1, "PSIZ" },
{ &mmc5vsize, 1, "VSIZ" }, { &mmc5vsize, 1, "VSIZ" },
{ mul, 2, "MUL2" }, { &mul, 2, "MUL2" },
{ MMC5ROMWrProtect, 4, "WRPR" }, { &MMC5ROMWrProtect, 4, "WRPR" },
{ MMC5MemIn, 5, "MEMI" }, { &MMC5MemIn, 5, "MEMI" },
{ &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" }, { &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" },
{ &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" }, { &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) { static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
if (wsize) { 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); SetupCartPRGMapping(0x10, WRAM, wsize * 1024, 1);
AddExState(WRAM, wsize * 1024, 0, "WRAM"); AddExState(WRAM, wsize * 1024, 0, "WRAM");
} }
MMC5fill = (uint8*)FCEU_gmalloc(1024); MMC5fill = (uint8*)FCEU_malloc(1024);
ExRAM = (uint8*)FCEU_gmalloc(1024); ExRAM = (uint8*)FCEU_malloc(1024);
// MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable FCEU_MemoryRand(MMC5fill,1024);
u8 nval = MMC5fill[0x000]; FCEU_MemoryRand(ExRAM,1024);
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);
AddExState(ExRAM, 1024, 0, "ERAM"); AddExState(ExRAM, 1024, 0, "ERAM");
AddExState(&MMC5HackSPMode, 1, 0, "SPLM"); AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
@ -974,19 +1018,26 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
MMC5WRAMsize = wsize / 8; MMC5WRAMsize = wsize / 8;
BuildWRAMSizeTable(); BuildWRAMSizeTable();
GameStateRestore = MMC5_StateRestore; GameStateRestore = MMC5_StateRestore;
info->Power = GenMMC5Reset; info->Power = GenMMC5Power;
MMC5battery = battery;
if (battery) { if (battery) {
info->SaveGame[0] = WRAM; info->SaveGame[0] = WRAM;
if (info->ines2)
//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 info->SaveGameLen[0] = info->battery_wram_size;
if (wsize <= 16) }
info->SaveGameLen[0] = 8192;
else if(wsize == 64)
info->SaveGameLen[0] = 64*1024;
else 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]; MMC5HackVROMMask = CHRmask4[0];
@ -1002,7 +1053,14 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
} }
void Mapper5_Init(CartInfo *info) { 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); 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 0x02: FreqCache[w] &= ~0x0000FF00; FreqCache[w] |= V << 8; break;
case 0x04: case 0x04:
FreqCache[w] &= ~0x00030000; FreqCache[w] |= (V & 3) << 16; 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; break;
case 0x07: EnvCache[w] = (double)(V & 0xF) * 576716; 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) { static void Mapper19_StateRestore(int version) {
SyncPRG(); SyncPRG();
SyncMirror();
FixNTAR(); FixNTAR();
FixCRR(); FixCRR();
SyncMirror();
int x; int x;
for (x = 0x40; x < 0x80; x++) for (x = 0x40; x < 0x80; x++)
FixCache(x, IRAM[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 writefunc defapuwrite[64];
static readfunc defapuread[64]; static readfunc defapuread[64];
static uint32 WRAMSIZE;
static uint8 *WRAM = NULL;
static SFORMAT StateRegs[] = static SFORMAT StateRegs[] =
{ {
{ cpu410x, 16, "REGC" }, { cpu410x, 16, "REGC" },
@ -265,6 +268,13 @@ static void UNLOneBusPower(void) {
SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X); SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X);
SetWriteHandler(0x8000, 0xffff, UNLOneBusWriteMMC3); 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(); Sync();
} }
@ -282,9 +292,16 @@ static void StateRestore(int version) {
Sync(); Sync();
} }
void UNLOneBusClose(void) {
if (WRAM)
FCEU_gfree(WRAM);
WRAM = NULL;
}
void UNLOneBus_Init(CartInfo *info) { void UNLOneBus_Init(CartInfo *info) {
info->Power = UNLOneBusPower; info->Power = UNLOneBusPower;
info->Reset = UNLOneBusReset; info->Reset = UNLOneBusReset;
info->Close = UNLOneBusClose;
if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts
((*(uint32*)&(info->MD5)) == 0x6abfce8e)) ((*(uint32*)&(info->MD5)) == 0x6abfce8e))
@ -294,4 +311,17 @@ void UNLOneBus_Init(CartInfo *info) {
MapIRQHook = UNLOneBusCpuHook; MapIRQHook = UNLOneBusCpuHook;
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0); 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 * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* PEC-586 FC based computer series by DUNDA
*
*/ */
#include "mapinc.h" #include "mapinc.h"

View File

@ -40,38 +40,38 @@ static uint16 latcha;
static uint8 *flashdata; static uint8 *flashdata;
static uint32 *flash_write_count; static uint32 *flash_write_count;
static uint8 *FlashPage[32]; static uint8 *FlashPage[32];
static uint32 *FlashWriteCountPage[32]; //static uint32 *FlashWriteCountPage[32];
static uint8 flashloaded = false; //static uint8 flashloaded = false;
static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank; static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank;
static void (*WLSync)(void); static void (*WLSync)(void);
static void (*WHSync)(void); static void (*WHSync)(void);
static INLINE void setfpageptr(int s, uint32 A, uint8 *p) { static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
uint32 AB = A >> 11; uint32 AB = A >> 11;
int x; int x;
if (p) if (p)
for (x = (s >> 1) - 1; x >= 0; x--) { for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = p - A; FlashPage[AB + x] = p - A;
} }
else else
for (x = (s >> 1) - 1; x >= 0; x--) { for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = 0; FlashPage[AB + x] = 0;
} }
} }
void setfprg16(uint32 A, uint32 V) { void setfprg16(uint32 A, uint32 V) {
if (PRGsize[0] >= 16384) { if (PRGsize[0] >= 16384) {
V &= PRGmask16[0]; V &= PRGmask16[0];
setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0); setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
} else { } else {
uint32 VA = V << 3; uint32 VA = V << 3;
int x; int x;
for (x = 0; x < 8; x++) for (x = 0; x < 8; x++)
setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0); setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
} }
} }
void inc_flash_write_count(uint8 bank, uint32 A) void inc_flash_write_count(uint8 bank, uint32 A)
@ -282,4 +282,4 @@ void UNROM512_Init(CartInfo *info) {
} }
AddExState(&latche, 1, 0, "LATC"); AddExState(&latche, 1, 0, "LATC");
AddExState(&bus_conflict, 1, 0, "BUSC"); AddExState(&bus_conflict, 1, 0, "BUSC");
} }

View File

@ -28,7 +28,6 @@ static uint8 prgreg[2], chrreg[8];
static uint16 chrhi[8]; static uint16 chrhi[8];
static uint8 regcmd, irqcmd, mirr, big_bank; static uint8 regcmd, irqcmd, mirr, big_bank;
static uint16 acount = 0; static uint16 acount = 0;
static uint16 weirdo = 0;
static uint8 *WRAM = NULL; static uint8 *WRAM = NULL;
static uint32 WRAMSIZE; static uint32 WRAMSIZE;
@ -38,6 +37,7 @@ static SFORMAT StateRegs[] =
{ prgreg, 2, "PREG" }, { prgreg, 2, "PREG" },
{ chrreg, 8, "CREG" }, { chrreg, 8, "CREG" },
{ chrhi, 16, "CRGH" }, { chrhi, 16, "CRGH" },
{ &acount, 2, "ACNT" },
{ &regcmd, 1, "CMDR" }, { &regcmd, 1, "CMDR" },
{ &irqcmd, 1, "CMDI" }, { &irqcmd, 1, "CMDI" },
{ &mirr, 1, "MIRR" }, { &mirr, 1, "MIRR" },
@ -62,15 +62,8 @@ static void Sync(void) {
setchr8(0); setchr8(0);
else{ else{
uint8 i; uint8 i;
//if(!weirdo) for (i = 0; i < 8; i++)
for (i = 0; i < 8; i++) setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
//else {
// setchr1(0x0000, 0xFC);
// setchr1(0x0400, 0xFD);
// setchr1(0x0800, 0xFF);
// weirdo--;
//}
} }
switch (mirr & 0x3) { switch (mirr & 0x3) {
case 0: setmirror(MI_V); break; case 0: setmirror(MI_V); break;

View File

@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator /* FCE Ultra - NES/Famicom Emulator
* *
* Copyright notice for this file: * 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 * 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 * 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 * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 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" #include "mapinc.h"
static uint8 QTAINTRAM[2048]; //#define CAI_DEBUG
static writefunc old2007wrap;
// 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 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 *CHRRAM = NULL;
static uint8 *WRAM = NULL; static uint8 *WRAM = NULL;
static uint8 IRQa, K4IRQ; static uint8 IRQa, K4IRQ;
static uint32 IRQLatch, IRQCount; 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 regs[16];
//static uint8 test[8];
static SFORMAT StateRegs[] = static SFORMAT StateRegs[] =
{ {
{ &IRQCount, 1, "IRQC" }, { &IRQCount, 1, "IRQC" },
@ -48,93 +141,68 @@ static SFORMAT StateRegs[] =
static void chrSync(void) { static void chrSync(void) {
setchr4r(0x10, 0x0000, regs[5] & 1); 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) { static void Sync(void) {
chrSync(); chrSync();
// if(regs[0xA]&0x10) 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
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); if (PRGptr[1] == NULL) { // for iNES 2.0 version it even more hacky lol
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); setprg8(0x8000, (regs[2] & 0x3F) + ((regs[2] & 0x40) >> 2));
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); setprg8(0xA000, (regs[3] & 0x3F) + ((regs[3] & 0x40) >> 2));
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); setprg8(0xC000, (regs[4] & 0x3F) + ((regs[4] & 0x40) >> 2));
setchr1r(0x10,0x1000,0); setprg8(0xE000, 0x10 + 0x3F);
setchr1r(0x10,0x1400,1); } else {
setchr1r(0x10,0x1800,2); setprg8r((regs[2] >> 6) & 1, 0x8000, (regs[2] & 0x3F));
setchr1r(0x10,0x1c00,3);*/ setprg8r((regs[3] >> 6) & 1, 0xA000, (regs[3] & 0x3F));
/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); setprg8r((regs[4] >> 6) & 1, 0xC000, (regs[4] & 0x3F));
setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); setprg8r(1, 0xE000, ~0); // always sees the last bank of the external cart, so can't be booted without it.
setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); }
setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); setmirror(((regs[0xA]&2)>>1)^1);
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);
} }
/*static DECLFW(TestWrite) static DECLFW(QTAiWrite) {
{ regs[(A & 0x0F00) >> 8] = V; // IRQ pretty the same as in other VRC mappers by Konami
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;
switch (A) { switch (A) {
case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break; case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break;
case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; 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 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xd800: IRQa = K4IRQ; 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(); Sync();
} }
static DECLFR(M190Read) { static DECLFR(QTAiRead) {
// FCEU_printf("read %04x:%04x %d, %d\n",A,regs[(A&0x0F00)>>8],scanline,timestamp);
return regs[(A & 0x0F00) >> 8] + regs[0x0B]; // 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) { static void VRC5IRQ(int a) {
if (IRQa) { if (IRQa) {
IRQCount += a; IRQCount += a;
@ -145,50 +213,17 @@ static void VRC5IRQ(int a) {
} }
} }
//static void Mapper190_PPU(uint32 A) static void QTAiPower(void) {
//{
// 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);
SetReadHandler(0x6000, 0xFFFF, CartBR); SetReadHandler(0x6000, 0xFFFF, CartBR);
// SetWriteHandler(0x5000,0x5007,TestWrite);
SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetWriteHandler(0x8000, 0xFFFF, M190Write); SetWriteHandler(0x8000, 0xFFFF, QTAiWrite);
SetReadHandler(0xDC00, 0xDC00, M190Read); SetReadHandler(0xDC00, 0xDC00, QTAiRead);
SetReadHandler(0xDD00, 0xDD00, M190Read); SetReadHandler(0xDD00, 0xDD00, QTAiRead);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
Sync(); Sync();
} }
static void M190Close(void) { static void QTAiClose(void) {
if (CHRRAM) if (CHRRAM)
FCEU_gfree(CHRRAM); FCEU_gfree(CHRRAM);
CHRRAM = NULL; CHRRAM = NULL;
@ -200,3 +235,31 @@ static void M190Close(void) {
static void StateRestore(int version) { static void StateRestore(int version) {
Sync(); 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; CHRmask4[chip] = (size >> 12) - 1;
CHRmask8[chip] = (size >> 13) - 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; CHRram[chip] = ram;
} }
@ -242,7 +247,7 @@ void setchr2r(int r, uint32 A, uint32 V) {
PPUCHRRAM &= ~(3 << (A >> 10)); 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; if (!CHRptr[r]) return;
FCEUPPU_LineUpdate(); FCEUPPU_LineUpdate();
V &= CHRmask4[r]; V &= CHRmask4[r];

View File

@ -1,3 +1,6 @@
#ifndef CART_H
#define CART_H
typedef struct { typedef struct {
// Set by mapper/board code: // Set by mapper/board code:
void (*Power)(void); void (*Power)(void);
@ -68,21 +71,21 @@ void setprg8(uint32 A, uint32 V);
void setprg16(uint32 A, uint32 V); void setprg16(uint32 A, uint32 V);
void setprg32(uint32 A, uint32 V); void setprg32(uint32 A, uint32 V);
void setprg2r(int r, uint32 A, uint32 V); void setprg2r(int r, unsigned int A, unsigned int V);
void setprg4r(int r, uint32 A, uint32 V); void setprg4r(int r, unsigned int A, unsigned int V);
void setprg8r(int r, uint32 A, uint32 V); void setprg8r(int r, unsigned int A, unsigned int V);
void setprg16r(int r, uint32 A, uint32 V); void setprg16r(int r, unsigned int A, unsigned int V);
void setprg32r(int r, uint32 A, uint32 V); void setprg32r(int r, unsigned int A, unsigned int V);
void setchr1r(int r, uint32 A, uint32 V); void setchr1r(int r, unsigned int A, unsigned int V);
void setchr2r(int r, uint32 A, uint32 V); void setchr2r(int r, unsigned int A, unsigned int V);
void setchr4r(int r, uint32 A, uint32 V); void setchr4r(int r, unsigned int A, unsigned int V);
void setchr8r(int r, uint32 V); void setchr8r(int r, unsigned int V);
void setchr1(uint32 A, uint32 V); void setchr1(unsigned int A, unsigned int V);
void setchr2(uint32 A, uint32 V); void setchr2(unsigned int A, unsigned int V);
void setchr4(uint32 A, uint32 V); void setchr4(unsigned int A, unsigned int V);
void setchr8(uint32 V); void setchr8(unsigned int V);
void setmirror(int t); void setmirror(int t);
void setmirrorw(int a, int b, int c, int d); void setmirrorw(int a, int b, int c, int d);
@ -100,3 +103,5 @@ void FCEU_GeniePower(void);
bool FCEU_OpenGenie(void); bool FCEU_OpenGenie(void);
void FCEU_CloseGenie(void); void FCEU_CloseGenie(void);
void FCEU_KillGenie(void); void FCEU_KillGenie(void);
#endif

View File

@ -39,8 +39,7 @@ using namespace std;
static uint8 *CheatRPtrs[64]; static uint8 *CheatRPtrs[64];
vector<uint16> FrozenAddresses; //List of addresses that are currently frozen 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) void FCEU_CheatResetRAM(void)
{ {
@ -60,27 +59,13 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
} }
struct CHEATF { CHEATF_SUBFAST SubCheats[256] = { 0 };
struct CHEATF *next; uint32 numsubcheats = 0;
char *name; int globalCheatDisabled = 0;
uint16 addr; int disableAutoLSCheats = 0;
uint8 val; bool disableShowGG = 0;
int compare; /* -1 for no compare. */ static _8BYTECHEATMAP* cheatMap = NULL;
int type; /* 0 for replace, 1 for substitute(GG). */ struct CHEATF *cheats = 0, *cheatsl = 0;
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;
#define CHEATC_NONE 0x8000 #define CHEATC_NONE 0x8000
@ -92,7 +77,7 @@ int savecheats = 0;
static DECLFR(SubCheatsRead) static DECLFR(SubCheatsRead)
{ {
CHEATF_SUBFAST *s=SubCheats; CHEATF_SUBFAST *s = SubCheats;
int x=numsubcheats; int x=numsubcheats;
do do
@ -116,79 +101,97 @@ static DECLFR(SubCheatsRead)
void RebuildSubCheats(void) void RebuildSubCheats(void)
{ {
int x; uint32 x;
struct CHEATF *c=cheats; struct CHEATF *c = cheats;
for(x=0;x<numsubcheats;x++) for (x = 0; x < numsubcheats; x++)
SetReadHandler(SubCheats[x].addr,SubCheats[x].addr,SubCheats[x].PrevRead);
numsubcheats=0;
while(c)
{ {
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. */ SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr);
//FCEU_DispMessage("oops",0); SubCheats[numsubcheats].addr = c->addr;
} SubCheats[numsubcheats].val = c->val;
else SubCheats[numsubcheats].compare = c->compare;
{ SetReadHandler(c->addr, c->addr, SubCheatsRead);
SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr); if (cheatMap)
SubCheats[numsubcheats].addr=c->addr; FCEUI_SetCheatMapByte(SubCheats[numsubcheats].addr, true);
SubCheats[numsubcheats].val=c->val;
SubCheats[numsubcheats].compare=c->compare;
SetReadHandler(c->addr,c->addr,SubCheatsRead);
numsubcheats++; numsubcheats++;
} }
c = c->next;
} }
c=c->next;
} }
FrozenAddressCount = numsubcheats; //Update the frozen address list FrozenAddressCount = numsubcheats; //Update the frozen address list
UpdateFrozenList();
//FCEUI_DispMessage("Active Cheats: %d",0, FrozenAddresses.size()/*FrozenAddressCount*/); //Debug
} }
void FCEU_PowerCheats() 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(); 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) static void CheatMemErr(void)
{ {
FCEUD_PrintError("Error allocating memory for cheat data."); FCEUD_PrintError("Error allocating memory for cheat data.");
} }
/* This function doesn't allocate any memory for "name" */ int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type)
{ {
struct CHEATF *temp; struct CHEATF *temp;
if(!(temp=(struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF)))) if(!(temp = (struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF))))
{ {
CheatMemErr(); CheatMemErr();
return(0); return(0);
} }
temp->name=name;
temp->addr=addr; temp->name = strcpy((char*) FCEU_dmalloc(strlen(name) + 1), name);
temp->val=val; temp->addr = addr;
temp->status=status; temp->val = val;
temp->compare=compare; temp->status = status;
temp->type=type; temp->compare = compare;
temp->next=0; temp->type = type;
temp->next = 0;
if(cheats) if(cheats)
{ {
cheatsl->next=temp; cheatsl->next = temp;
cheatsl=temp; cheatsl = temp;
} }
else 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; FILE *fp;
unsigned int addr; unsigned int addr;
@ -198,89 +201,121 @@ void FCEU_LoadGameCheats(FILE *override)
unsigned int compare; unsigned int compare;
int x; int x;
char linebuf[2048]; char linebuf[2048] = { 0 };
char *namebuf; char namebuf[128] = { 0 };
int tc=0; int tc = 0;
char *fn; char *fn;
numsubcheats=savecheats=0; if (override_existing)
{
numsubcheats = 0;
if (cheatMap)
FCEUI_RefreshCheatMap();
}
if(override) if(override)
fp = override; fp = override;
else else
{ {
fn=strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str()); fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT, 0, 0).c_str());
fp=FCEUD_UTF8fopen(fn,"rb"); fp = FCEUD_UTF8fopen(fn, "rb");
free(fn); 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; char *tbuf = linebuf;
int doc=0; int doc = 0;
addr=val=compare=status=type=0; addr = val = compare = status = type = 0;
if(tbuf[0]=='S') if(tbuf[0] == 'S')
{ {
tbuf++; tbuf++;
type=1; type = 1;
} }
else type=0; else
type = 0;
if(tbuf[0]=='C') if(tbuf[0] == 'C')
{ {
tbuf++; tbuf++;
doc=1; doc = 1;
} }
if(tbuf[0]==':') if(tbuf[0] == ':')
{ {
tbuf++; tbuf++;
status=0; status = 0;
} }
else status=1; else status = 1;
if(doc) if(doc)
{ {
char *neo=&tbuf[4+2+2+1+1+1]; char *neo = &tbuf[4+2+2+1+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3) if(sscanf(tbuf, "%04x%*[:]%02x%*[:]%02x", &addr, &val, &compare) != 3)
continue; continue;
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1))) strcpy(namebuf, neo);
return;
strcpy(namebuf,neo);
} }
else else
{ {
char *neo=&tbuf[4+2+1+1]; char *neo = &tbuf[4+2+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2) if(sscanf(tbuf, "%04x%*[:]%02x", &addr, &val) != 2)
continue; continue;
if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1))) strcpy(namebuf, neo);
return;
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; break;
} }
else if(namebuf[x] > 0x00 && namebuf[x] < 0x20) 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++; tc++;
} }
RebuildSubCheats(); RebuildSubCheats();
FCEU_DispMessage("Cheats file loaded.", 0); //Tells user a cheats file was loaded.
if(!override) if(!override)
fclose(fp); 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) void FCEU_FlushGameCheats(FILE *override, int nosave)
{ {
if(CheatComp) if(CheatComp)
@ -313,7 +348,6 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
if(cheats) if(cheats)
{ {
struct CHEATF *next=cheats;
FILE *fp; FILE *fp;
if(override) if(override)
@ -323,28 +357,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
if(fp) if(fp)
{ {
for(;;) FCEU_SaveGameCheats(fp, 1);
{
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;
}
if(!override) if(!override)
fclose(fp); 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) int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
{ {
char *t;
if(!(t=(char *)FCEU_dmalloc(strlen(name)+1))) if(!AddCheatEntry(name, addr, val, compare, 1, type))
{ return 0;
CheatMemErr(); savecheats = 1;
return(0);
}
strcpy(t,name);
if(!AddCheatEntry(t,addr,val,compare,1,type))
{
free(t);
return(0);
}
savecheats=1;
RebuildSubCheats(); RebuildSubCheats();
return(1); return 1;
} }
int FCEUI_DelCheat(uint32 which) 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 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); if(strlen(str)!=8) return(0);
sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3); 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) int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int s, int type)
{ {
struct CHEATF *next=cheats; struct CHEATF *next = cheats;
uint32 x=0; uint32 x = 0;
while(next) while(next)
{ {
if(x==which) if(x == which)
{ {
if(name) if(name)
{ {
char *t; char *t;
if((t=(char *)realloc(next->name, strlen(name)+1))) if((t = (char *)realloc(next->name, strlen(name) + 1)))
{ strcpy(next->name = t, name);
next->name=t;
strcpy(next->name,name);
}
else else
return(0); return 0;
} }
if(a>=0) if(a >= 0)
next->addr=a; next->addr = a;
if(v>=0) if(v >= 0)
next->val=v; next->val = v;
if(s>=0) if(s >= 0)
next->status=s; next->status = s;
if(c>=-1) if(c >= -1)
next->compare=c; next->compare = c;
next->type=type; next->type = type;
savecheats=1; savecheats = 1;
RebuildSubCheats(); RebuildSubCheats();
return(1); return 1;
} }
next=next->next; next = next->next;
x++; x++;
} }
return(0); return 0;
} }
/* Convenience function. */ /* Convenience function. */
@ -659,6 +659,14 @@ int FCEUI_ToggleCheat(uint32 which)
return(-1); return(-1);
} }
int FCEUI_GlobalToggleCheat(int global_enabled)
{
int _numsubcheats = numsubcheats;
globalCheatDisabled = !global_enabled;
RebuildSubCheats();
return _numsubcheats != numsubcheats;
}
static int InitCheatComp(void) static int InitCheatComp(void)
{ {
uint32 x; 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)) void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current))
{ {
uint32 x; uint32 x;
uint32 in=0; uint32 in = 0;
if(!CheatComp) if(!CheatComp)
{ {
@ -750,14 +758,15 @@ void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a,
return; return;
} }
for(x=0;x<0x10000;x++) for(x = 0; x < 0x10000; x++)
if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) if(!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10])
{ {
if(in>=first) if(in >= first)
if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x])) if(!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x]))
break; break;
in++; in++;
if(in>last) return; if(in > last)
return;
} }
} }
@ -803,130 +812,56 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
} }
} }
switch (type)
if(!type) // Change to a specific value.
{ {
for(x=0;x<0x10000;x++) default:
if(!(CheatComp[x]&CHEATC_NOSHOW)) case FCEU_SEARCH_SPECIFIC_CHANGE: // Change to a specific value
{ for (x = 0; x < 0x10000; ++x)
if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2) 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).
else for (x = 0; x < 0x10000; x++)
CheatComp[x]|=CHEATC_EXCLUDED; 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) int FCEU_CheatGetByte(uint32 A)
@ -949,18 +884,75 @@ void FCEU_CheatSetByte(uint32 A, uint8 V)
BWrite[A](A, 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 int count = 0;
//and make these accessible to other dialogs that deal with memory addresses such as struct CHEATF *next = cheats;
//memwatch, hex editor, ramfilter, etc. while(next)
int x;
FrozenAddresses.clear(); //Clear vector and repopulate
for(x=0;x<numsubcheats;x++)
{ {
FrozenAddresses.push_back(SubCheats[x].addr); if(next->status){
//FCEU_printf("Address %d: %d \n",x,FrozenAddresses[x]); //Debug 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_CheatResetRAM(void);
void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p); 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_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_ApplyPeriodicCheats(void);
void FCEU_PowerCheats(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); int FCEU_CheatGetByte(uint32 A);
void FCEU_CheatSetByte(uint32 A, uint8 V); 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); scan(str);
c->lhs = Connect(str);
if (!c) return 0; if (!c) return 0;
c->lhs = Connect(str);
if (next == closePar) if (next == closePar)
{ {
scan(str); scan(str);
@ -400,9 +400,12 @@ Condition* Term(const char** str)
Condition* t1; Condition* t1;
Condition* mid; Condition* mid;
t = (Condition*)FCEU_dmalloc(sizeof(Condition)); t = (Condition*)FCEU_dmalloc(sizeof(Condition));
if (!t)
return NULL; if (!t)
{
return NULL;
}
memset(t, 0, sizeof(Condition)); memset(t, 0, sizeof(Condition));

View File

@ -13,18 +13,23 @@
static char *aboutString = 0; static char *aboutString = 0;
#ifndef FCEUX_BUILD_TIMESTAMP
#define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__
#endif
// returns a string suitable for use in an aboutbox // returns a string suitable for use in an aboutbox
char *FCEUI_GetAboutString() { const char *FCEUI_GetAboutString(void)
{
const char *aboutTemplate = const char *aboutTemplate =
FCEU_NAME_AND_VERSION "\n\n" FCEU_NAME_AND_VERSION "\n\n"
"Administrators:\n" "Administrators:\n"
"zeromus, punkrockguy318 (Lukas Sabota), feos\n" "zeromus, feos\n"
"\n" "\n"
"Current Contributors:\n" "Current Contributors:\n"
"CaH4e3, rainwarrior\n" "CaH4e3, rainwarrior, owomomo, punkrockguy318\n"
"\n" "\n"
"Past Contributors:\n" "Past Contributors:\n"
"xhainingx, gocha, AnS\n" "xhainingx, gocha, AnS, mjbudd77\n"
"\n" "\n"
"FCEUX 2.0:\n" "FCEUX 2.0:\n"
"mz, nitsujrehtona, SP, Ugly Joe,\n" "mz, nitsujrehtona, SP, Ugly Joe,\n"
@ -40,13 +45,17 @@ char *FCEUI_GetAboutString() {
"FCEU TAS - blip & nitsuja\n" "FCEU TAS - blip & nitsuja\n"
"FCEU TAS+ - Luke Gustafson\n" "FCEU TAS+ - Luke Gustafson\n"
"\n" "\n"
"Logo/icon:\n"
"Terwilf\n"
"\n"
"FCEUX is dedicated to the fallen heroes\n" "FCEUX is dedicated to the fallen heroes\n"
"of NES emulation. In Memoriam --\n" "of NES emulation. In Memoriam --\n"
"ugetab\n" "ugetab\n"
"\n" "\n"
__TIME__ " " __DATE__ "\n"; "\n"
FCEUX_BUILD_TIMESTAMP "\n";
if(aboutString) return aboutString; if (aboutString) return aboutString;
const char *compilerString = FCEUD_GetCompilerString(); const char *compilerString = FCEUD_GetCompilerString();
@ -54,6 +63,6 @@ char *FCEUI_GetAboutString() {
if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1))) if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1)))
return NULL; return NULL;
sprintf(aboutString,"%s%s",aboutTemplate,compilerString); sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
return aboutString; return aboutString;
} }

View File

@ -22,7 +22,7 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
{ {
int offset = -1; int offset = -1;
if (sscanf(offsetBuffer,"%4X",&offset) == EOF) if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
{ {
return -1; return -1;
} }
@ -35,14 +35,24 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
{ {
return offset & 0x00FF; return offset & 0x00FF;
} }
else if (type & BT_R)
{
return offset;
}
else // BT_C 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,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8)); if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<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,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8)); if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<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 // 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|=BT_S;
watchpoint[num].flags&=~WP_X; //disable execute flag! watchpoint[num].flags&=~WP_X; //disable execute flag!
} }
if (type & BT_R) {
watchpoint[num].flags|=BT_R;
}
if (watchpoint[num].desc) if (watchpoint[num].desc)
free(watchpoint[num].desc); free(watchpoint[num].desc);
@ -208,11 +221,27 @@ int GetPRGAddress(int A){
int result; int result;
if(A > 0xFFFF) if(A > 0xFFFF)
return -1; return -1;
result = &Page[A>>11][A]-PRGptr[0]; if (GameInfo->type == GIT_FDS) {
if((result > (int)PRGsize[0]) || (result < 0)) if (A < 0xE000) {
return -1; result = &Page[A >> 11][A] - PRGptr[1];
else if ((result > (int)PRGsize[1]) || (result < 0))
return result; 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; volatile int codecount = 0, datacount = 0, undefinedcount = 0;
unsigned char *cdloggerdata; unsigned char *cdloggerdata = NULL;
unsigned int cdloggerdataSize = 0; 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 //called by the cpu to perform logging if CDLogging is enabled
void LogCDVectors(int which){ 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; int i, j;
uint8 memop = 0; uint8 memop = 0;
bool newCodeHit = false, newDataHit = false;
if((j = GetPRGAddress(_PC)) != -1) if ((j = GetPRGAddress(_PC)) != -1)
for (i = 0; i < size; i++) { {
if(cdloggerdata[j+i] & 1)continue; //this has been logged so skip 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] |= 1;
cdloggerdata[j+i] |= ((_PC + i) >> 11) & 0x0c; 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) 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++; codecount++;
if(!(cdloggerdata[j+i] & 2))undefinedcount--; if (!(cdloggerdata[j+i] & 2))undefinedcount--;
newCodeHit = true;
} }
}
//log instruction jumped to in an indirect jump //log instruction jumped to in an indirect jump
if(opcode[0] == 0x6c) if(opcode[0] == 0x6c)
@ -474,14 +512,43 @@ void LogCDData(uint8 *opcode, uint16 A, int size) {
case 4: memop = 0x20; break; case 4: memop = 0x20; break;
} }
if((j = GetPRGAddress(A)) != -1) { if ((j = GetPRGAddress(A)) != -1)
if(!(cdloggerdata[j] & 2)) { {
cdloggerdata[j] |= 2; if (opwrite[opcode[0]] == 0)
cdloggerdata[j] |=(A>>11)&0x0c; {
cdloggerdata[j] |= memop; if (!(cdloggerdata[j] & 2))
datacount++; {
if(!(cdloggerdata[j] & 1))undefinedcount--; 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++; delta_instructions++;
} }
void BreakHit(int bp_num, bool force) bool CondForbidTest(int bp_num) {
{ if (bp_num >= 0 && !condition(&watchpoint[bp_num]))
if(!force)
{ {
if (bp_num >= 0 && !condition(&watchpoint[bp_num])) return false; // condition rejected
{ }
return; // condition rejected
}
//check to see whether we fall in any forbid zone //check to see whether we fall in any forbid zone
for (int i = 0; i < numWPs; i++) for (int i = 0; i < numWPs; i++)
{ {
watchpointinfo& wp = watchpoint[i]; watchpointinfo& wp = watchpoint[i];
if(!(wp.flags & WP_F) || !(wp.flags & WP_E)) if (!(wp.flags & WP_F) || !(wp.flags & WP_E))
continue; continue;
if (condition(&wp)) if (condition(&wp))
{ {
if (wp.endaddress) { if (wp.endaddress) {
if( (wp.address <= _PC) && (wp.endaddress >= _PC) ) if ((wp.address <= _PC) && (wp.endaddress >= _PC))
return; //forbid return false; // forbid
} else { }
if(wp.address == _PC) else {
return; //forbid 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() FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED); //mbg merge 7/19/06 changed to use EmulationPaused()
#ifdef WIN32 //#ifdef WIN32
FCEUD_DebugBreakpoint(bp_num); FCEUD_DebugBreakpoint(bp_num);
#endif //#endif
} }
int StackAddrBackup; int StackAddrBackup;
@ -574,10 +642,10 @@ uint16 StackNextIgnorePC = 0xFFFF;
///fires a breakpoint ///fires a breakpoint
static void breakpoint(uint8 *opcode, uint16 A, int size) { static void breakpoint(uint8 *opcode, uint16 A, int size) {
int i, j; int i, j, romAddrPC;
uint8 brk_type; uint8 brk_type;
uint8 stackop=0; uint8 stackop=0;
uint8 stackopstartaddr,stackopendaddr; uint8 stackopstartaddr=0,stackopendaddr=0;
debugLastAddress = A; debugLastAddress = A;
debugLastOpcode = opcode[0]; debugLastOpcode = opcode[0];
@ -585,17 +653,17 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (break_asap) if (break_asap)
{ {
break_asap = false; 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)) 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)) 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 the current instruction is bad, and we are breaking on bad opcodes, then hit the breakpoint
if(dbgstate.badopbreak && (size == 0)) if(dbgstate.badopbreak && (size == 0))
BreakHit(BREAK_TYPE_BADOP, true); BreakHit(BREAK_TYPE_BADOP);
//if we're stepping out, track the nest level //if we're stepping out, track the nest level
if (dbgstate.stepout) { 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 we're stepping, then we'll always want to break
if (dbgstate.step) { if (dbgstate.step) {
dbgstate.step = false; dbgstate.step = false;
BreakHit(BREAK_TYPE_STEP, true); BreakHit(BREAK_TYPE_STEP);
return; return;
} }
@ -626,7 +694,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (diff<=0) if (diff<=0)
{ {
dbgstate.runline=false; dbgstate.runline=false;
BreakHit(BREAK_TYPE_STEP, true); BreakHit(BREAK_TYPE_STEP);
return; return;
} }
} }
@ -635,10 +703,12 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) { if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) {
watchpoint[64].address = 0; watchpoint[64].address = 0;
watchpoint[64].flags = 0; watchpoint[64].flags = 0;
BreakHit(BREAK_TYPE_STEP, true); BreakHit(BREAK_TYPE_STEP);
return; return;
} }
romAddrPC = GetNesFileAddress(_PC);
brk_type = opbrktype[opcode[0]] | WP_X; brk_type = opbrktype[opcode[0]] | WP_X;
switch (opcode[0]) { switch (opcode[0]) {
@ -657,7 +727,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
default: break; default: break;
} }
#define BREAKHIT(x) { breakHit = (x); goto STOPCHECKING; } #define BREAKHIT(x) { if (CondForbidTest(x)) { breakHit = (x); goto STOPCHECKING; } }
int breakHit = -1; int breakHit = -1;
for (i = 0; i < numWPs; i++) 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)) || 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))) ((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC)))
BREAKHIT(i); BREAKHIT(i);
} else }
else
{ {
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) || if (watchpoint[i].flags & BT_R)
((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC))) {
BREAKHIT(i); 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 } else
{ {
@ -864,10 +954,5 @@ void DebugCycle()
if(debug_loggingCD) if(debug_loggingCD)
LogCDData(opcode, A, size); 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); FCEUD_TraceInstruction(opcode, size);
#endif
} }

View File

@ -15,12 +15,15 @@
#define BT_C 0x00 //break type, cpu mem #define BT_C 0x00 //break type, cpu mem
#define BT_P 0x20 //break type, ppu mem #define BT_P 0x20 //break type, ppu mem
#define BT_S 0x40 //break type, sprite 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_STEP -1
#define BREAK_TYPE_BADOP -2 #define BREAK_TYPE_BADOP -2
#define BREAK_TYPE_CYCLES_EXCEED -3 #define BREAK_TYPE_CYCLES_EXCEED -3
#define BREAK_TYPE_INSTRUCTIONS_EXCEED -4 #define BREAK_TYPE_INSTRUCTIONS_EXCEED -4
#define BREAK_TYPE_LUA -5 #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. //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. //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 { typedef struct {
uint16 address; uint32 address;
uint16 endaddress; uint32 endaddress;
uint8 flags; uint16 flags;
Condition* cond; Condition* cond;
char* condText; char* condText;
@ -59,6 +62,7 @@ typedef struct {
//mbg merge 7/18/06 had to make this extern //mbg merge 7/18/06 had to make this extern
extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over
extern unsigned int debuggerPageSize;
int getBank(int offs); int getBank(int offs);
int GetNesFileAddress(int A); int GetNesFileAddress(int A);
int GetPRGAddress(int A); int GetPRGAddress(int A);
@ -93,9 +97,12 @@ static INLINE int FCEUI_GetLoggingCD() { return debug_loggingCD; }
extern int iaPC; extern int iaPC;
extern uint32 iapoffset; //mbg merge 7/18/06 changed from int extern uint32 iapoffset; //mbg merge 7/18/06 changed from int
void DebugCycle(); 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_asap;
extern bool break_on_unlogged_code;
extern bool break_on_unlogged_data;
extern uint64 total_cycles_base; extern uint64 total_cycles_base;
extern uint64 delta_cycles_base; extern uint64 delta_cycles_base;
extern bool break_on_cycles; extern bool break_on_cycles;
@ -113,8 +120,9 @@ extern void IncrementInstructionsCounters();
//internal variables that debuggers will want access to //internal variables that debuggers will want access to
extern uint8 *vnapage[4],*VPage[8]; 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 uint32 FCEUPPU_PeekAddress();
extern uint8 READPAL_MOTHEROFALL(uint32 A);
extern int numWPs; extern int numWPs;
///encapsulates the operational state of the debugger core ///encapsulates the operational state of the debugger core

View File

@ -395,10 +395,10 @@ static int FixJoedChar(uint8 ch)
int c = ch - 32; int c = ch - 32;
return (c < 0 || c > 98) ? 0 : c; return (c < 0 || c > 98) ? 0 : c;
} }
static int JoedCharWidth(uint8 ch) //static int JoedCharWidth(uint8 ch)
{ //{
return Font6x7[FixJoedChar(ch)*8]; // return Font6x7[FixJoedChar(ch)*8];
} //}
char target[64][256]; 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); 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); } 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);
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);
FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel);
ArchiveScanRecord FCEUD_ScanArchive(std::string fname); ArchiveScanRecord FCEUD_ScanArchive(std::string fname);
//mbg 7/23/06 //mbg 7/23/06
const char *FCEUD_GetCompilerString(); const char *FCEUD_GetCompilerString();
//This makes me feel dirty for some reason. //This makes me feel dirty for some reason.
void FCEU_printf(char *format, ...); void FCEU_printf(const char *format, ...);
#define FCEUI_printf FCEU_printf #define FCEUI_printf FCEU_printf
//Video interface //Video interface
@ -123,6 +125,7 @@ void FCEUI_SetVidSystem(int a);
//Set variables for NTSC(0) / PAL(1) / Dendy(2) //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 //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); void FCEUI_SetRegion(int region, int notify = 1);
int FCEUI_GetRegion(void);
//Convenience function; returns currently emulated video system(0=NTSC, 1=PAL). //Convenience function; returns currently emulated video system(0=NTSC, 1=PAL).
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend); 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. //Sets the base directory(save states, snapshots, etc. are saved in directories below this directory.
void FCEUI_SetBaseDirectory(std::string const & dir); void FCEUI_SetBaseDirectory(std::string const & dir);
const char *FCEUI_GetBaseDirectory(void);
bool FCEUI_GetUserPaletteAvail(void);
void FCEUI_SetUserPalette(uint8 *pal, int nEntries); void FCEUI_SetUserPalette(uint8 *pal, int nEntries);
//Sets up sound code to render sound at the specified rate, in samples //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_MovieReplayFrom(void);
void FCEUD_LuaRunFrom(void); void FCEUD_LuaRunFrom(void);
#ifdef _S9XLUA_H
// lua engine
void TaseditorAutoFunction(void);
void TaseditorManualFunction(void);
#endif
int32 FCEUI_GetDesiredFPS(void); int32 FCEUI_GetDesiredFPS(void);
void FCEUI_SaveSnapshot(void); void FCEUI_SaveSnapshot(void);
void FCEUI_SaveSnapshotAs(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 #define FCEUI_DispMessage FCEU_DispMessage
int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type); 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_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type);
int FCEUI_DelCheat(uint32 which); int FCEUI_DelCheat(uint32 which);
int FCEUI_ToggleCheat(uint32 which); int FCEUI_ToggleCheat(uint32 which);
int FCEUI_GlobalToggleCheat(int global_enable);
int32 FCEUI_CheatSearchGetCount(void); int32 FCEUI_CheatSearchGetCount(void);
void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current)); 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); //int FCEUI_FDSEject(void);
void FCEUI_FDSSelect(void); void FCEUI_FDSSelect(void);
int FCEUI_DatachSet(const uint8 *rcode); int FCEUI_DatachSet(uint8 *rcode);
///returns a flag indicating whether emulation is paused ///returns a flag indicating whether emulation is paused
int FCEUI_EmulationPaused(); 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) ///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); 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) ///the driver might should update its NTView (only used if debugging support is compiled in)
void FCEUD_UpdateNTView(int scanline, bool drawall); void FCEUD_UpdateNTView(int scanline, bool drawall);
@ -337,7 +352,8 @@ enum EFCEUI
FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE, FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE,
FCEUI_OPENGAME, FCEUI_CLOSEGAME, FCEUI_OPENGAME, FCEUI_CLOSEGAME,
FCEUI_TASEDITOR, 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 //checks whether an EFCEUI is valid right now

View File

@ -86,6 +86,7 @@ void EMUFILE_FILE::truncate(s32 length)
#else #else
ftruncate(fileno(fp),length); ftruncate(fileno(fp),length);
#endif #endif
// this is probably wrong if mode is "wb"
fclose(fp); fclose(fp);
fp = NULL; fp = NULL;
open(fname.c_str(),mode); open(fname.c_str(),mode);
@ -132,7 +133,7 @@ void EMUFILE::write64le(u64 val)
size_t EMUFILE::read64le(u64 *Bufo) size_t EMUFILE::read64le(u64 *Bufo)
{ {
u64 buf; u64 buf=0;
if(fread((char*)&buf,8) != 8) if(fread((char*)&buf,8) != 8)
return 0; return 0;
#ifndef LOCAL_BE #ifndef LOCAL_BE
@ -173,7 +174,7 @@ size_t EMUFILE::read32le(s32* Bufo) { return read32le((u32*)Bufo); }
size_t EMUFILE::read32le(u32* Bufo) size_t EMUFILE::read32le(u32* Bufo)
{ {
u32 buf; u32 buf=0;
if(fread(&buf,4)<4) if(fread(&buf,4)<4)
return 0; return 0;
#ifndef LOCAL_BE #ifndef LOCAL_BE
@ -212,7 +213,7 @@ size_t EMUFILE::read16le(s16* Bufo) { return read16le((u16*)Bufo); }
size_t EMUFILE::read16le(u16* Bufo) size_t EMUFILE::read16le(u16* Bufo)
{ {
u32 buf; u32 buf=0;
if(fread(&buf,2)<2) if(fread(&buf,2)<2)
return 0; return 0;
#ifndef LOCAL_BE #ifndef LOCAL_BE

View File

@ -222,7 +222,7 @@ public:
reserve(pos+(s32)bytes); reserve(pos+(s32)bytes);
memcpy(buf()+pos,ptr,bytes); memcpy(buf()+pos,ptr,bytes);
pos += (s32)bytes; pos += (s32)bytes;
len = std::max(pos,len); len = std::max<int>(pos,len);
} }
virtual int fseek(int offset, int origin){ virtual int fseek(int offset, int origin){

View File

@ -43,7 +43,7 @@
#include "file.h" #include "file.h"
#include "vsuni.h" #include "vsuni.h"
#include "ines.h" #include "ines.h"
#ifdef WIN32 #ifdef __WIN_DRIVER__
#include "drivers/win/pref.h" #include "drivers/win/pref.h"
#include "utils/xstring.h" #include "utils/xstring.h"
@ -65,7 +65,7 @@ extern void RefreshThrottleFPS();
#endif #endif
//TODO - we really need some kind of global platform-specific options api //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/main.h"
#include "drivers/win/memview.h" #include "drivers/win/memview.h"
#include "drivers/win/cheat.h" #include "drivers/win/cheat.h"
@ -117,21 +117,26 @@ bool DebuggerWasUpdated = false; //To prevent the debugger from updating things
bool AutoResumePlay = false; bool AutoResumePlay = false;
char romNameWhenClosingEmulator[2048] = {0}; char romNameWhenClosingEmulator[2048] = {0};
FCEUGI::FCEUGI() FCEUGI::FCEUGI()
: filename(0), : filename(0),
archiveFilename(0) { archiveFilename(0)
{
//printf("%08x",opsize); // WTF?! //printf("%08x",opsize); // WTF?!
} }
FCEUGI::~FCEUGI() { FCEUGI::~FCEUGI()
if (filename) { {
free(filename); if (filename)
filename = NULL; {
} free(filename);
if (archiveFilename) { filename = NULL;
delete archiveFilename; }
archiveFilename = NULL; if (archiveFilename)
} {
free(archiveFilename);
archiveFilename = NULL;
}
} }
bool CheckFileExists(const char* filename) { bool CheckFileExists(const char* filename) {
@ -160,7 +165,7 @@ void FCEU_TogglePPU(void) {
FCEUI_printf("Old PPU loaded"); FCEUI_printf("Old PPU loaded");
} }
normalscanlines = (dendy ? 290 : 240)+newppu; // use flag as number! normalscanlines = (dendy ? 290 : 240)+newppu; // use flag as number!
#ifdef WIN32 #ifdef __WIN_DRIVER__
SetMainWindowText(); SetMainWindowText();
#endif #endif
} }
@ -175,7 +180,7 @@ static void FCEU_CloseGame(void)
FCEUSS_Save(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false); FCEUSS_Save(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false);
} }
#ifdef WIN32 #ifdef __WIN_DRIVER__
extern char LoadedRomFName[2048]; extern char LoadedRomFName[2048];
if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str())) if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))
FCEUD_PrintError("Couldn't store debugging data"); FCEUD_PrintError("Couldn't store debugging data");
@ -192,7 +197,14 @@ static void FCEU_CloseGame(void)
} }
if (GameInfo->type != GIT_NSF) { 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); GameInterface(GI_CLOSE);
@ -393,6 +405,7 @@ void ResetGameLoaded(void) {
MapIRQHook = NULL; MapIRQHook = NULL;
MMC5Hack = 0; MMC5Hack = 0;
PEC586Hack = 0; PEC586Hack = 0;
QTAIHack = 0;
PAL &= 1; PAL &= 1;
default_palette_selection = 0; 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 FDSLoad(const char *name, FCEUFILE *fp);
int NSFLoad(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 //name should be UTF-8, hopefully, or else there may be trouble
FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silent) 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 lastpal = PAL;
int lastdendy = dendy; int lastdendy = dendy;
const char* romextensions[] = { "nes", "fds", 0 }; const char* romextensions[] = { "nes", "fds", "nsf", 0 };
fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions);
// 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 (!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); FCEU_PrintError("Error opening \"%s\"!", name);
return 0; return 0;
} else if (fp->archiveFilename != "") }
else if (fp->archiveFilename != "")
{ {
strcpy(fullname, fp->archiveFilename.c_str()); strcpy(fullname, fp->archiveFilename.c_str());
strcat(fullname, "|"); strcat(fullname, "|");
strcat(fullname, fp->filename.c_str()); strcat(fullname, fp->filename.c_str());
} else } else
{
strcpy(fullname, name); strcpy(fullname, name);
}
// reset loaded game BEFORE it's loading.
ResetGameLoaded();
//file opened ok. start loading. //file opened ok. start loading.
FCEU_printf("Loading %s...\n\n", fullname); FCEU_printf("Loading %s...\n\n", fullname);
GetFileBase(fp->filename.c_str()); 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 //reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing
MasterRomInfoParams = TMasterRomInfoParams(); MasterRomInfoParams = TMasterRomInfoParams();
@ -446,7 +464,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
FCEU_CloseGame(); FCEU_CloseGame();
GameInfo = new FCEUGI(); GameInfo = new FCEUGI();
memset(GameInfo, 0, sizeof(FCEUGI)); memset( (void*)GameInfo, 0, sizeof(FCEUGI));
GameInfo->filename = strdup(fp->filename.c_str()); GameInfo->filename = strdup(fp->filename.c_str());
if (fp->archiveFilename != "") if (fp->archiveFilename != "")
@ -464,99 +482,115 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
//try to load each different format //try to load each different format
bool FCEUXLoad(const char *name, FCEUFILE * fp); 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) int load_result;
FCEU_PrintError("An error occurred while loading the file."); load_result = iNESLoad(fullname, fp, OverwriteVidMode);
FCEU_fclose(fp); if (load_result == LOADER_INVALID_FORMAT)
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)
{ {
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); load_result = FDSLoad(fullname, fp);
#ifdef WIN32
genie = 0;
#endif
} }
} }
} }
PowerNES(); if (load_result == LOADER_OK)
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)
{ {
// 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) if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str())))
DoDebuggerDataReload(); // Reloads data without reopening window if (!silent)
CDLoggerROMChanged(); FCEU_printf("Couldn't load debugging data.\n");
if (hMemView) UpdateColorTable();
if (hCheat) UpdateCheatsAdded(); // ################################## End of SP CODE ###########################
if (FrozenAddressCount)
FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount);
#endif #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; return GameInfo;
} }
@ -610,47 +644,81 @@ void FCEUI_Kill(void) {
} }
int rapidAlternator = 0; 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; int AutoFirePatternLength = 2;
void SetAutoFirePattern(int onframes, int offframes) { void SetAutoFirePattern(int onframes, int offframes)
int i; {
for (i = 0; i < onframes && i < 8; i++) { //int i;
AutoFirePattern[i] = 1; //for (i = 0; i < onframes && i < 8; i++) {
} // AutoFirePattern[i] = 1;
for (; i < 8; i++) { //}
AutoFirePattern[i] = 0; //for (; i < 8; i++) {
} // AutoFirePattern[i] = 0;
if (onframes + offframes < 2) { //}
AutoFirePatternLength = 2; //if (onframes + offframes < 2) {
} else if (onframes + offframes > 8) { // AutoFirePatternLength = 2;
AutoFirePatternLength = 8; //} else if (onframes + offframes > 8) {
} else { // AutoFirePatternLength = 8;
AutoFirePatternLength = onframes + offframes; //} else {
} // AutoFirePatternLength = onframes + offframes;
//}
AutoFirePatternLength = onframes + offframes;
AFon = onframes; AFoff = 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; if (offset < 0 || offset > 8) return;
AutoFireOffset = offset; AutoFireOffset = offset;
} }
void AutoFire(void) { bool GetAutoFireState(int btnIdx)
{
return rapidAlternator;
}
void AutoFire(void)
{
static int counter = 0; static int counter = 0;
if (justLagged == false) 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 //If recording a movie, use the frame # for the autofire so the offset
//doesn't get screwed up when loading. //doesn't get screwed up when loading.
if (FCEUMOV_Mode(MOVIEMODE_RECORD | MOVIEMODE_PLAY)) { 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 + FCEUMOV_GetFrame()) % AutoFirePatternLength]; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire?
rapidAlternator = AutoFirePattern[(AutoFireOffset + counter) % AutoFirePatternLength]; //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); void UpdateAutosave(void);
#ifdef __QT_DRIVER__
extern unsigned int frameAdvHoldTimer;
#endif
///Emulates a single frame. ///Emulates a single frame.
///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one 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) 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) if (frameAdvance_Delay_count == 0 || frameAdvance_Delay_count >= frameAdvance_Delay)
EmulationPaused = EMULATIONPAUSED_FA; EmulationPaused = EMULATIONPAUSED_FA;
if (frameAdvance_Delay_count < frameAdvance_Delay) if (frameAdvance_Delay_count < frameAdvance_Delay)
frameAdvance_Delay_count++; frameAdvance_Delay_count++;
#endif
} }
if (EmulationPaused & EMULATIONPAUSED_FA) 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 // the user is holding Frame Advance key
// clear paused flag temporarily // clear paused flag temporarily
EmulationPaused &= ~EMULATIONPAUSED_PAUSED; EmulationPaused &= ~EMULATIONPAUSED_PAUSED;
#ifdef WIN32 #ifdef __WIN_DRIVER__
// different emulation speed when holding Frame Advance // different emulation speed when holding Frame Advance
if (fps_scale_frameadvance > 0) if (fps_scale_frameadvance > 0)
{ {
@ -683,7 +768,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
#endif #endif
} else } else
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (fps_scale_frameadvance > 0) if (fps_scale_frameadvance > 0)
{ {
// restore emulation speed when Frame Advance is not held // 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 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 #ifdef _S9XLUA_H
CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
#endif #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 //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(); UpdateTextHooker();
Update_RAM_Search(); // Update_RAM_Watch() is also called. Update_RAM_Search(); // Update_RAM_Watch() is also called.
RamChange(); 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 EmulationPaused = EMULATIONPAUSED_PAUSED; // restore EMULATIONPAUSED_PAUSED flag and clear EMULATIONPAUSED_FA flag
JustFrameAdvanced = true; JustFrameAdvanced = true;
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (soundoptions & SO_MUTEFA) //mute the frame advance if the user requested it if (soundoptions & SO_MUTEFA) //mute the frame advance if the user requested it
*SoundBufSize = 0; //keep sound muted *SoundBufSize = 0; //keep sound muted
#endif #endif
@ -796,7 +889,7 @@ void ResetNES(void) {
extern uint8 *XBackBuf; extern uint8 *XBackBuf;
memset(XBackBuf, 0, 256 * 256); memset(XBackBuf, 0, 256 * 256);
//FCEU_DispMessage("Reset", 0); // FCEU_DispMessage("Reset", 0);
} }
@ -927,7 +1020,7 @@ void PowerNES(void) {
timestampbase = 0; timestampbase = 0;
X6502_Power(); X6502_Power();
#ifdef WIN32 #ifdef __WIN_DRIVER__
ResetDebugStatisticsCounters(); ResetDebugStatisticsCounters();
#endif #endif
FCEU_PowerCheats(); FCEU_PowerCheats();
@ -936,11 +1029,11 @@ void PowerNES(void) {
extern uint8 *XBackBuf; extern uint8 *XBackBuf;
memset(XBackBuf, 0, 256 * 256); memset(XBackBuf, 0, 256 * 256);
#ifdef WIN32 #ifdef __WIN_DRIVER__
Update_RAM_Search(); // Update_RAM_Watch() is also called. Update_RAM_Search(); // Update_RAM_Watch() is also called.
#endif #endif
FCEU_DispMessage("Power on", 0); // FCEU_DispMessage("Power on", 0);
} }
void FCEU_ResetVidSys(void) { void FCEU_ResetVidSys(void) {
@ -970,7 +1063,8 @@ void FCEU_ResetVidSys(void) {
FCEUS FSettings; FCEUS FSettings;
void FCEU_printf(char *format, ...) { void FCEU_printf(const char *format, ...)
{
#ifndef GEKKO #ifndef GEKKO
char temp[2048]; char temp[2048];
@ -991,7 +1085,8 @@ void FCEU_printf(char *format, ...) {
#endif #endif
} }
void FCEU_PrintError(char *format, ...) { void FCEU_PrintError(const char *format, ...)
{
#ifndef GEKKO #ifndef GEKKO
char temp[2048]; char temp[2048];
@ -1037,51 +1132,67 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) {
} }
#ifndef GEKKO #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) { switch (region) {
case 0: // NTSC case 0: // NTSC
normalscanlines = 240; normalscanlines = 240;
pal_emulation = 0; pal_emulation = 0;
dendy = 0; dendy = 0;
// until it's fixed on sdl. see issue #740
#ifdef WIN32
if (notify) if (notify)
{ {
FCEU_DispMessage("NTSC mode set", 0); FCEU_DispMessage("NTSC mode set", 0);
FCEUI_printf("NTSC mode set"); FCEUI_printf("NTSC mode set\n");
} }
#endif
break; break;
case 1: // PAL case 1: // PAL
normalscanlines = 240; normalscanlines = 240;
pal_emulation = 1; pal_emulation = 1;
dendy = 0; dendy = 0;
#ifdef WIN32
if (notify) if (notify)
{ {
FCEU_DispMessage("PAL mode set", 0); FCEU_DispMessage("PAL mode set", 0);
FCEUI_printf("PAL mode set"); FCEUI_printf("PAL mode set\n");
} }
#endif
break; break;
case 2: // Dendy case 2: // Dendy
normalscanlines = 290; normalscanlines = 290;
pal_emulation = 0; pal_emulation = 0;
dendy = 1; dendy = 1;
#ifdef WIN32
if (notify) if (notify)
{ {
FCEU_DispMessage("Dendy mode set", 0); FCEU_DispMessage("Dendy mode set", 0);
FCEUI_printf("Dendy mode set"); FCEUI_printf("Dendy mode set\n");
} }
#endif
break; break;
} }
normalscanlines += newppu; normalscanlines += newppu;
totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0); totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0);
FCEUI_SetVidSystem(pal_emulation); FCEUI_SetVidSystem(pal_emulation);
RefreshThrottleFPS(); RefreshThrottleFPS();
#ifdef WIN32 #ifdef __WIN_DRIVER__
UpdateCheckedMenuItems(); UpdateCheckedMenuItems();
PushCurrentVideoSettings(); PushCurrentVideoSettings();
#endif #endif
@ -1125,12 +1236,16 @@ void FCEUI_ClearEmulationFrameStepped()
//ideally maybe we shouldnt be using this, but i need it for quick merging //ideally maybe we shouldnt be using this, but i need it for quick merging
void FCEUI_SetEmulationPaused(int val) { void FCEUI_SetEmulationPaused(int val) {
EmulationPaused = val; EmulationPaused = val;
if(EmulationPaused)
FCEUD_FlushTrace();
} }
void FCEUI_ToggleEmulationPause(void) void FCEUI_ToggleEmulationPause(void)
{ {
EmulationPaused = (EmulationPaused & EMULATIONPAUSED_PAUSED) ^ EMULATIONPAUSED_PAUSED; EmulationPaused = (EmulationPaused & EMULATIONPAUSED_PAUSED) ^ EMULATIONPAUSED_PAUSED;
DebuggerWasUpdated = false; DebuggerWasUpdated = false;
if(EmulationPaused)
FCEUD_FlushTrace();
} }
void FCEUI_FrameAdvanceEnd(void) { void FCEUI_FrameAdvanceEnd(void) {
@ -1210,10 +1325,14 @@ bool FCEU_IsValidUI(EFCEUI ui) {
break; break;
case FCEUI_STOPMOVIE: 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: 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: case FCEUI_STOPAVI:
return FCEUI_AviIsRecording(); return FCEUI_AviIsRecording();
@ -1229,12 +1348,21 @@ bool FCEU_IsValidUI(EFCEUI ui) {
case FCEUI_INSERT_COIN: case FCEUI_INSERT_COIN:
if (!GameInfo) return false; if (!GameInfo) return false;
if (FCEUMOV_Mode(MOVIEMODE_RECORD)) return true; if (FCEUMOV_Mode(MOVIEMODE_RECORD)) return true;
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR) && isTaseditorRecording()) return true; if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR) && isTaseditorRecording()) return true;
#endif #endif
if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false; if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false;
break; 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 #endif
return true; return true;
} }
@ -1295,10 +1423,16 @@ virtual void Power() {
} }
}; };
void FCEUXGameInterface(GI command) { void FCEUXGameInterface(GI command)
switch (command) { {
case GI_POWER: switch (command)
cart->Power(); {
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) { void FCEU_WriteRomByte(uint32 i, uint8 value) {
if (i < 16) if (i < 16)
#ifdef WIN32 #ifdef __WIN_DRIVER__
MessageBox(hMemView,"Sorry", "You can't edit the ROM header.", MB_OK); MessageBox(hMemView, "Sorry", "You can't edit the ROM header.", MB_OK | MB_ICONERROR);
#else #else
printf("Sorry, you can't edit the ROM header.\n"); printf("Sorry, you can't edit the ROM header.\n");
#endif #endif

View File

@ -17,6 +17,7 @@ extern int postrenderscanlines;
extern int vblankscanlines; extern int vblankscanlines;
extern bool AutoResumePlay; extern bool AutoResumePlay;
extern bool frameAdvanceLagSkip;
extern char romNameWhenClosingEmulator[]; extern char romNameWhenClosingEmulator[];
#define DECLFR(x) uint8 x (uint32 A) #define DECLFR(x) uint8 x (uint32 A)
@ -39,16 +40,20 @@ void PowerNES(void);
void SetAutoFireOffset(int offset); void SetAutoFireOffset(int offset);
void SetAutoFirePattern(int onframes, int offframes); void SetAutoFirePattern(int onframes, int offframes);
void GetAutoFirePattern( int *onframes, int *offframes);
bool GetAutoFireState(int btnIdx);
void AutoFire(void); void AutoFire(void);
void FCEUI_RewindToLastAutosave(void); void FCEUI_RewindToLastAutosave(void);
//mbg 7/23/06 //mbg 7/23/06
char *FCEUI_GetAboutString(); const char *FCEUI_GetAboutString(void);
extern uint64 timestampbase; extern uint64 timestampbase;
// MMC5 external shared buffers/vars
extern int MMC5Hack;
extern uint32 MMC5HackVROMMask; extern uint32 MMC5HackVROMMask;
extern uint8 *MMC5HackExNTARAMPtr; extern uint8 *MMC5HackExNTARAMPtr;
extern int MMC5Hack, PEC586Hack;
extern uint8 *MMC5HackVROMPTR; extern uint8 *MMC5HackVROMPTR;
extern uint8 MMC5HackCHRMode; extern uint8 MMC5HackCHRMode;
extern uint8 MMC5HackSPMode; extern uint8 MMC5HackSPMode;
@ -56,11 +61,19 @@ extern uint8 MMC50x5130;
extern uint8 MMC5HackSPScroll; extern uint8 MMC5HackSPScroll;
extern uint8 MMC5HackSPPage; 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 #define GAME_MEM_BLOCK_SIZE 131072
extern uint8 *RAM; //shared memory modifications extern uint8 *RAM; //shared memory modifications
extern int EmulationPaused; extern int EmulationPaused;
extern int frameAdvance_Delay;
extern int RAMInitOption;
uint8 FCEU_ReadRomByte(uint32 i); uint8 FCEU_ReadRomByte(uint32 i);
void FCEU_WriteRomByte(uint32 i, uint8 value); void FCEU_WriteRomByte(uint32 i, uint8 value);
@ -85,10 +98,11 @@ extern int GameAttributes;
extern uint8 PAL; extern uint8 PAL;
extern int dendy; extern int dendy;
extern bool movieSubtitles;
//#include "driver.h" //#include "driver.h"
typedef struct { typedef struct fceu_settings_struct {
int PAL; int PAL;
int NetworkPlay; int NetworkPlay;
int SoundVolume; //Master volume 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 bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists
void FCEU_PrintError(char *format, ...); void FCEU_PrintError(const char *format, ...);
void FCEU_printf(char *format, ...); void FCEU_printf(const char *format, ...);
void FCEU_DispMessage(char *format, int disppos, ...); void FCEU_DispMessage(const char *format, int disppos, ...);
void FCEU_DispMessageOnMovie(char *format, ...); void FCEU_DispMessageOnMovie(const char *format, ...);
void FCEU_TogglePPU(); void FCEU_TogglePPU();
void SetNESDeemph_OldHacky(uint8 d, int force); 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 FCEUDEF_DEBUGGER //mbg merge 7/17/06 - cleaning out conditional compiles
#define JOY_A 1 #define JOY_A 0x01
#define JOY_B 2 #define JOY_B 0x02
#define JOY_SELECT 4 #define JOY_SELECT 0x04
#define JOY_START 8 #define JOY_START 0x08
#define JOY_UP 0x10 #define JOY_UP 0x10
#define JOY_DOWN 0x20 #define JOY_DOWN 0x20
#define JOY_LEFT 0x40 #define JOY_LEFT 0x40
#define JOY_RIGHT 0x80 #define JOY_RIGHT 0x80
#define LOADER_INVALID_FORMAT 0
#define LOADER_OK 1
#define LOADER_HANDLED_ERROR 2
#define LOADER_UNHANDLED_ERROR 3
#endif #endif
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))

View File

@ -90,12 +90,31 @@ static int32 DiskPtr;
static int32 DiskSeekIRQ; static int32 DiskSeekIRQ;
static uint8 SelectDisk, InDisk; 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 #define DC_INC 1
void FDSGI(GI h) { void FDSGI(GI h) {
switch (h) { switch (h)
case GI_CLOSE: FDSClose(); break; {
case GI_POWER: FDSInit(); break; 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(); FDSSoundReset();
InDisk = 0; InDisk = 0;
SelectDisk = 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) 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'); 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) { static void FDSFix(int a) {
if ((IRQa & 2) && IRQCount) { if ((IRQa & IRQ_Enabled) && IRQCount) {
IRQCount -= a; IRQCount -= a;
if (IRQCount <= 0) { if (IRQCount <= 0) {
if (!(IRQa & 1)) { IRQCount = IRQLatch;
IRQa &= ~2;
IRQCount = IRQLatch = 0;
} else
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT); X6502_IRQBegin(FCEU_IQEXT);
if (!(IRQa & IRQ_Repeat)) {
IRQa &= ~IRQ_Enabled;
}
} }
} }
if (DiskSeekIRQ > 0) { if (DiskSeekIRQ > 0) {
@ -237,17 +266,45 @@ static DECLFR(FDSRead4030) {
} }
static DECLFR(FDSRead4031) { static DECLFR(FDSRead4031) {
static uint8 z = 0; static uint8 ret = 0;
if (InDisk != 255) {
z = diskdata[InDisk][DiskPtr]; ret = 0xff;
if (!fceuindbg) { if (mapperFDS_diskinsert && mapperFDS_control & 0x04) {
if (DiskPtr < 64999) DiskPtr++; mapperFDS_diskaccess = 1;
DiskSeekIRQ = 150;
X6502_IRQEnd(FCEU_IQEXT2); 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) { static DECLFR(FDSRead4032) {
uint8 ret; uint8 ret;
@ -537,33 +594,87 @@ static DECLFW(FDSWrite) {
break; break;
case 0x4023: break; case 0x4023: break;
case 0x4024: case 0x4024:
if ((InDisk != 255) && !(FDSRegs[5] & 0x4) && (FDSRegs[3] & 0x1)) { if (mapperFDS_diskinsert && ~mapperFDS_control & 0x04) {
if (DiskPtr >= 0 && DiskPtr < 65500) {
if (writeskip) if (mapperFDS_diskaccess == 0) {
writeskip--; mapperFDS_diskaccess = 1;
else if (DiskPtr >= 2) { break;
DiskWritten = 1;
diskdata[InDisk][DiskPtr - 2] = V;
}
} }
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; break;
case 0x4025: case 0x4025:
X6502_IRQEnd(FCEU_IQEXT2); X6502_IRQEnd(FCEU_IQEXT2);
if (InDisk != 255) { if (mapperFDS_diskinsert) {
if (!(V & 0x40)) { if (V & 0x40 && ~mapperFDS_control & 0x40) {
if ((FDSRegs[5] & 0x40) && !(V & 0x10)) { mapperFDS_diskaccess = 0;
DiskSeekIRQ = 200;
DiskPtr -= 2; 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) { if (V & 0x02) { // transfer reset
DiskPtr = 0; DiskSeekIRQ = 200; 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); setmirror(((V >> 3) & 1) ^ 1);
break; break;
} }
@ -585,6 +696,7 @@ static int SubLoad(FCEUFILE *fp) {
uint8 header[16]; uint8 header[16];
int x; int x;
FCEU_fseek(fp, 0, SEEK_SET);
FCEU_fread(header, 16, 1, fp); FCEU_fread(header, 16, 1, fp);
if (memcmp(header, "FDS\x1a", 4)) { if (memcmp(header, "FDS\x1a", 4)) {
@ -596,7 +708,7 @@ static int SubLoad(FCEUFILE *fp) {
TotalSides = t / 65500; TotalSides = t / 65500;
FCEU_fseek(fp, 0, SEEK_SET); FCEU_fseek(fp, 0, SEEK_SET);
} else } else
return(0); return 1;
} else } else
TotalSides = header[4]; TotalSides = header[4];
@ -606,18 +718,12 @@ static int SubLoad(FCEUFILE *fp) {
if (TotalSides < 1) TotalSides = 1; if (TotalSides < 1) TotalSides = 1;
for (x = 0; x < TotalSides; x++) { for (x = 0; x < TotalSides; x++) {
diskdata[x] = (uint8*)FCEU_malloc(65500); if ((diskdata[x] = (uint8*)FCEU_malloc(65500)) == NULL) return 2;
if (!diskdata[x]) {
int zol;
for (zol = 0; zol < x; zol++)
free(diskdata[zol]);
return 0;
}
FCEU_fread(diskdata[x], 1, 65500, fp); FCEU_fread(diskdata[x], 1, 65500, fp);
md5_update(&md5, diskdata[x], 65500); md5_update(&md5, diskdata[x], 65500);
} }
md5_finish(&md5, GameInfo->MD5.data); md5_finish(&md5, GameInfo->MD5.data);
return(1); return 0;
} }
static void PreSave(void) { static void PreSave(void) {
@ -643,22 +749,38 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
FILE *zp; FILE *zp;
#endif #endif
int x; 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 #ifndef GEKKO
char *fn = strdup(FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str()); char *fn = strdup(FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str());
if (!(zp = FCEUD_UTF8fopen(fn, "rb"))) { if (!(zp = FCEUD_UTF8fopen(fn, "rb"))) {
FCEU_PrintError("FDS BIOS ROM image missing: %s", FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str()); FCEU_PrintError("FDS BIOS ROM image missing: %s", FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str());
free(fn); free(fn);
return 0; FreeFDSMemory();
return LOADER_HANDLED_ERROR;
} }
free(fn); free(fn);
fseek(zp, 0L, SEEK_END); fseek(zp, 0L, SEEK_END);
if (ftell(zp) != 8192) { if (ftell(zp) != 8192) {
fclose(zp); fclose(zp);
FCEU_PrintError("FDS BIOS ROM image incompatible: %s", FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str()); 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); fseek(zp, 0L, SEEK_SET);
#endif #endif
@ -686,23 +808,13 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
free(FDSBIOS); free(FDSBIOS);
FDSBIOS = NULL; FDSBIOS = NULL;
fclose(zp); fclose(zp);
FreeFDSMemory();
FCEU_PrintError("Error reading FDS BIOS ROM image."); FCEU_PrintError("Error reading FDS BIOS ROM image.");
return 0; return LOADER_HANDLED_ERROR;
} }
fclose(zp); fclose(zp);
#endif #endif
FCEU_fseek(fp, 0, SEEK_SET);
FreeFDSMemory();
if (!SubLoad(fp)) {
#ifndef GEKKO
if(FDSBIOS)
free(FDSBIOS);
FDSBIOS = NULL;
#endif
return(0);
}
if (!disableBatteryLoading) { if (!disableBatteryLoading) {
FCEUFILE *tp; FCEUFILE *tp;
@ -715,15 +827,16 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
} }
#ifndef GEKKO #ifndef GEKKO
if ((tp = FCEU_fopen(fn, 0, "rb", 0))) { 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(); FreeFDSMemory();
if (!SubLoad(tp)) { if (SubLoad(tp)) {
FCEU_PrintError("Error reading auxillary FDS file."); FCEU_PrintError("Error reading auxiliary FDS file.");
if(FDSBIOS) if(FDSBIOS)
free(FDSBIOS); free(FDSBIOS);
FDSBIOS = NULL; FDSBIOS = NULL;
free(fn); free(fn);
return(0); FreeFDSMemory();
return LOADER_HANDLED_ERROR;
} }
FCEU_fclose(tp); FCEU_fclose(tp);
DiskWritten = 1; /* For save state handling. */ DiskWritten = 1; /* For save state handling. */
@ -761,6 +874,13 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
AddExState(&SelectDisk, 1, 0, "SELD"); AddExState(&SelectDisk, 1, 0, "SELD");
AddExState(&InDisk, 1, 0, "INDI"); AddExState(&InDisk, 1, 0, "INDI");
AddExState(&DiskWritten, 1, 0, "DSKW"); 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; CHRRAMSize = 8192;
CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize);
@ -778,7 +898,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
FCEUI_SetVidSystem(0); FCEUI_SetVidSystem(0);
return 1; return LOADER_OK;
} }
void FDSClose(void) { void FDSClose(void) {

View File

@ -104,12 +104,14 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp)
if((offset+size)>(uint32)fp->size) if((offset+size)>(uint32)fp->size)
{ {
// Probably a little slow. // Probably a little slow.
buf=(char *)realloc(buf,offset+size); char *newbuf=(char *)realloc(buf,offset+size);
if(!buf) 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); FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n",count);
goto end; goto end;
} }
buf=newbuf;
memset(buf+fp->size,0,offset+size-fp->size); memset(buf+fp->size,0,offset+size-fp->size);
fp->size=offset+size; fp->size=offset+size;
} }
@ -127,12 +129,14 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp)
if((offset+size)>(uint32)fp->size) if((offset+size)>(uint32)fp->size)
{ {
// Probably a little slow. // Probably a little slow.
buf=(char *)realloc(buf,offset+size); char *newbuf=(char *)realloc(buf,offset+size);
if(!buf) 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); FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n",count);
goto end; goto end;
} }
buf=newbuf;
memset(buf+fp->size,0,offset+size-fp->size); memset(buf+fp->size,0,offset+size-fp->size);
} }
fread(buf+offset,1,size,ips); fread(buf+offset,1,size,ips);
@ -256,14 +260,14 @@ zpfail:
return 0; 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; FILE *ipsfile=0;
FCEUFILE *fceufp=0; FCEUFILE *fceufp=0;
bool read = (std::string)mode == "rb"; bool read = !strcmp(mode, "rb");
bool write = (std::string)mode == "wb"; bool write = !strcmp(mode, "wb");
if((read&&write) || (!read&&!write)) if(read && write || !read && !write)
{ {
FCEU_PrintError("invalid file open mode specified (only wb and rb are supported)"); FCEU_PrintError("invalid file open mode specified (only wb and rb are supported)");
return 0; return 0;
@ -279,16 +283,28 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext
if(read) if(read)
{ {
ArchiveScanRecord asr = FCEUD_ScanArchive(fileToOpen); 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); asr.files.FilterByExtension(extensions);
if(!asr.isArchive()) if(!asr.isArchive())
{ {
//if the archive contained no files, try to open it the old fashioned way //if the archive contained no files, try to open it the old fashioned way
EMUFILE_FILE* fp = FCEUD_UTF8_fstream(fileToOpen,mode); 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; return 0;
} }
//try to read a zip file //try to read a zip file
{ {
fceufp = TryUnzip(fileToOpen); fceufp = TryUnzip(fileToOpen);
@ -355,11 +371,11 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext
//open an archive file //open an archive file
if(archive == "") if(archive == "")
if(index != -1) if(index != -1)
fceufp = FCEUD_OpenArchiveIndex(asr, fileToOpen, index); fceufp = FCEUD_OpenArchiveIndex(asr, fileToOpen, index, userCancel);
else else
fceufp = FCEUD_OpenArchive(asr, fileToOpen, 0); fceufp = FCEUD_OpenArchive(asr, fileToOpen, 0, userCancel);
else else
fceufp = FCEUD_OpenArchive(asr, archive, &fname); fceufp = FCEUD_OpenArchive(asr, archive, &fname, userCancel);
if(!fceufp) return 0; if(!fceufp) return 0;
@ -452,6 +468,11 @@ void FCEUI_SetBaseDirectory(std::string const & dir)
{ {
BaseDirectory = 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. ^_^ 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; va_list ap;
int ret; int ret;
va_start(ap,fmt);
if(!(*strp=(char*)FCEU_dmalloc(2048))) //mbg merge 7/17/06 cast to char* if(!(*strp=(char*)FCEU_dmalloc(2048))) //mbg merge 7/17/06 cast to char*
return(0); return(0);
va_start(ap,fmt);
ret=vsnprintf(*strp,2048,fmt,ap); ret=vsnprintf(*strp,2048,fmt,ap);
va_end(ap); va_end(ap);
return(ret); return(ret);

View File

@ -42,7 +42,7 @@ struct FCEUFILE {
FCEUFILE() FCEUFILE()
: stream(0) : stream(0)
, archiveCount(-1) , archiveCount(-1), archiveIndex(0), size(0), mode(READ)
{} {}
~FCEUFILE() ~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); bool FCEU_isFileInArchive(const char *path);
int FCEU_fclose(FCEUFILE*); int FCEU_fclose(FCEUFILE*);
uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, 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); int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover);
void MakeFilters(int32 rate); void MakeFilters(int32 rate);
void SexyFilter(int32 *in, int32 *out, int32 count); 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_MOUSE = 6,
SI_SNES = 7, SI_SNES = 7,
SI_SNES_MOUSE = 8, 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) inline const char* ESI_Name(ESI esi)
@ -54,7 +56,9 @@ inline const char* ESI_Name(ESI esi)
"Arkanoid Paddle", "Arkanoid Paddle",
"Subor Mouse", "Subor Mouse",
"SNES Pad", "SNES Pad",
"SNES Mouse" "SNES Mouse",
"Virtual Boy",
"LCD Zapper (Advance)"
}; };
if(esi >= SI_NONE && esi <= SI_COUNT) if(esi >= SI_NONE && esi <= SI_COUNT)
@ -82,8 +86,10 @@ enum ESIFC
SIFC_OEKAKIDS = 12, SIFC_OEKAKIDS = 12,
SIFC_BWORLD = 13, SIFC_BWORLD = 13,
SIFC_TOPRIDER = 14, 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", "Family Trainer B",
"Oeka Kids Tablet", "Oeka Kids Tablet",
"Barcode World", "Barcode World",
"Top Rider" "Top Rider",
"Famicom Network Controller",
"Hori 4-Player Adapter"
}; };
if(esifc >= SIFC_NONE && esifc <= SIFC_COUNT) if(esifc >= SIFC_NONE && esifc <= SIFC_COUNT)

View File

@ -1,41 +1,41 @@
{ 0xecf78d8a13a030a6LL, "Ai Sensei no Oshiete", INESB_HACKED }, { 0xecf78d8a13a030a6ULL, "Ai Sensei no Oshiete", INESB_HACKED },
{ 0x4712856d3e12f21fLL, "Akumajou Densetsu", INESB_HACKED }, { 0x4712856d3e12f21fULL, "Akumajou Densetsu", INESB_HACKED },
{ 0x10f90ba5bd55c22eLL, "Alien Syndrome", INESB_HACKED }, { 0x10f90ba5bd55c22eULL, "Alien Syndrome", INESB_HACKED },
{ 0x0d69ab3ad28ad1c2LL, "Banana", INESB_INCOMPLETE }, { 0x0d69ab3ad28ad1c2ULL, "Banana", INESB_INCOMPLETE },
{ 0x85d2c348a161cdbfLL, "Bio Senshi Dan", INESB_HACKED }, { 0x85d2c348a161cdbfULL, "Bio Senshi Dan", INESB_HACKED },
{ 0x18fdb7c16aa8cb5cLL, "Bucky O'Hare", INESB_CORRUPT }, { 0x18fdb7c16aa8cb5cULL, "Bucky O'Hare", INESB_CORRUPT },
{ 0xe27c48302108d11bLL, "Chibi Maruko Chan", INESB_HACKED }, { 0xe27c48302108d11bULL, "Chibi Maruko Chan", INESB_HACKED },
{ 0x9d1f505c6ba507bfLL, "Contra", INESB_HACKED }, { 0x9d1f505c6ba507bfULL, "Contra", INESB_HACKED },
{ 0x60936436d3ea0ab6LL, "Crisis Force", INESB_HACKED }, { 0x60936436d3ea0ab6ULL, "Crisis Force", INESB_HACKED },
{ 0xcf31097ddbb03c5dLL, "Crystalis (Prototype)", INESB_CORRUPT }, { 0xcf31097ddbb03c5dULL, "Crystalis (Prototype)", INESB_CORRUPT },
{ 0x92080a8ce94200eaLL, "Digital Devil Story II", INESB_HACKED }, { 0x92080a8ce94200eaULL, "Digital Devil Story II", INESB_HACKED },
{ 0x6c2a2f95c2fe4b6eLL, "Dragon Ball", INESB_HACKED }, { 0x6c2a2f95c2fe4b6eULL, "Dragon Ball", INESB_HACKED },
{ 0x767aaff62963c58fLL, "Dragon Ball", INESB_HACKED }, { 0x767aaff62963c58fULL, "Dragon Ball", INESB_HACKED },
{ 0x97f133d8bc1c28dbLL, "Dragon Ball", INESB_HACKED }, { 0x97f133d8bc1c28dbULL, "Dragon Ball", INESB_HACKED },
{ 0x500b267abb323005LL, "Dragon Warrior 4", INESB_CORRUPT }, { 0x500b267abb323005ULL, "Dragon Warrior 4", INESB_CORRUPT },
{ 0x02bdcf375704784bLL, "Erika to Satoru no Yume Bouken", INESB_HACKED }, { 0x02bdcf375704784bULL, "Erika to Satoru no Yume Bouken", INESB_HACKED },
{ 0xd4fea9d2633b9186LL, "Famista 91", INESB_HACKED }, { 0xd4fea9d2633b9186ULL, "Famista 91", INESB_HACKED },
{ 0xfdf8c812839b61f0LL, "Famista 92", INESB_HACKED }, { 0xfdf8c812839b61f0ULL, "Famista 92", INESB_HACKED },
{ 0xb5bb1d0fb47d0850LL, "Famista 93", INESB_HACKED }, { 0xb5bb1d0fb47d0850ULL, "Famista 93", INESB_HACKED },
{ 0x30471e773f7cdc89LL, "Famista 94", INESB_HACKED }, { 0x30471e773f7cdc89ULL, "Famista 94", INESB_HACKED },
{ 0x76c5c44ffb4a0bd7LL, "Fantasy Zone", INESB_HACKED }, { 0x76c5c44ffb4a0bd7ULL, "Fantasy Zone", INESB_HACKED },
{ 0xb470bfb90e2b1049LL, "Fire Emblem Gaiden", INESB_HACKED }, { 0xb470bfb90e2b1049ULL, "Fire Emblem Gaiden", INESB_HACKED },
{ 0x27da2b0c500dc346LL, "Fire Emblem", INESB_HACKED }, { 0x27da2b0c500dc346ULL, "Fire Emblem", INESB_HACKED },
{ 0x23214fe456fba2ceLL, "Ganbare Goemon 2", INESB_HACKED }, { 0x23214fe456fba2ceULL, "Ganbare Goemon 2", INESB_HACKED },
{ 0xbf8b22524e8329d9LL, "Ganbare Goemon Gaiden", INESB_HACKED }, { 0xbf8b22524e8329d9ULL, "Ganbare Goemon Gaiden", INESB_HACKED },
{ 0xa97041c3da0134e3LL, "Gegege no Kitarou 2", INESB_INCOMPLETE }, { 0xa97041c3da0134e3ULL, "Gegege no Kitarou 2", INESB_INCOMPLETE },
{ 0x805db49a86db5449LL, "Goonies", INESB_HACKED }, { 0x805db49a86db5449ULL, "Goonies", INESB_HACKED },
{ 0xc5abdaa65ac49b6bLL, "Gradius 2", INESB_HACKED }, { 0xc5abdaa65ac49b6bULL, "Gradius 2", INESB_HACKED },
{ 0x04afae4ad480c11cLL, "Gradius 2", INESB_HACKED }, { 0x04afae4ad480c11cULL, "Gradius 2", INESB_HACKED },
{ 0x9b4bad37b5498992LL, "Gradius 2", INESB_HACKED }, { 0x9b4bad37b5498992ULL, "Gradius 2", INESB_HACKED },
{ 0xb068d4ac10ef848eLL, "Highway Star", INESB_HACKED }, { 0xb068d4ac10ef848eULL, "Highway Star", INESB_HACKED },
{ 0xbf5175271e5019c3LL, "Kaiketsu Yanchamaru 3", INESB_HACKED }, { 0xbf5175271e5019c3ULL, "Kaiketsu Yanchamaru 3", INESB_HACKED },
{ 0x81c1de64550a1531LL, "Nobunaga no Yabou Zenkokuban", INESB_HACKED }, { 0x81c1de64550a1531ULL, "Nobunaga no Yabou Zenkokuban", INESB_HACKED },
{ 0xfb4b508a236bbba3LL, "Salamander", INESB_HACKED }, { 0xfb4b508a236bbba3ULL, "Salamander", INESB_HACKED },
{ 0x1895afc6eef26c7dLL, "Super Mario Bros.", INESB_HACKED }, { 0x1895afc6eef26c7dULL, "Super Mario Bros.", INESB_HACKED },
{ 0x3716c4bebf885344LL, "Super Mario Bros.", INESB_HACKED }, { 0x3716c4bebf885344ULL, "Super Mario Bros.", INESB_HACKED },
{ 0xfffda4407d80885aLL, "Sweet Home", INESB_CORRUPT }, { 0xfffda4407d80885aULL, "Sweet Home", INESB_CORRUPT },
{ 0x103fc85d978b861bLL, "Sweet Home", INESB_CORRUPT }, { 0x103fc85d978b861bULL, "Sweet Home", INESB_CORRUPT },
{ 0x7979dc51da86f19fLL, "110-in-1", INESB_CORRUPT }, { 0x7979dc51da86f19fULL, "110-in-1", INESB_CORRUPT },
{ 0x001c0bb9c358252aLL, "110-in-1", INESB_CORRUPT }, { 0x001c0bb9c358252aULL, "110-in-1", INESB_CORRUPT },
{ 0, 0, 0 } { 0, 0, 0 }

View File

@ -124,7 +124,6 @@
{0x054bd3e9, 74, -1}, /* Di 4 Ci - Ji Qi Ren Dai Zhan (As) */ {0x054bd3e9, 74, -1}, /* Di 4 Ci - Ji Qi Ren Dai Zhan (As) */
{0x496ac8f7, 74, -1}, /* Ji Jia Zhan Shi (As) */ {0x496ac8f7, 74, -1}, /* Ji Jia Zhan Shi (As) */
{0xae854cef, 74, -1}, /* Jia A Fung Yun (Chinese) */ {0xae854cef, 74, -1}, /* Jia A Fung Yun (Chinese) */
{0xba51ac6f, 78, 2},
{0x3d1c3137, 78, 8}, /* Uchuusen - Cosmo Carrier */ {0x3d1c3137, 78, 8}, /* Uchuusen - Cosmo Carrier */
{0xa4fbb438, 79, 0}, {0xa4fbb438, 79, 0},
{0xd4a76b07, 79, 0}, /* F-15 City Wars*/ {0xd4a76b07, 79, 0}, /* F-15 City Wars*/
@ -281,4 +280,6 @@
{0x4d4a0e1b, 260|0x1000,-1}, {0x4d4a0e1b, 260|0x1000,-1},
{0xb6dd2c9d, 260|0x1000,-1}, {0xb6dd2c9d, 260|0x1000,-1},
{0xb02fcb57, 406|0x1000,-1}, /* Haradius Zero ver 1.2a 2019 */
{0x00000000, -1, -1} {0x00000000, -1, -1}

View File

@ -67,7 +67,7 @@ static int iNES_Init(int num);
static int MapperNo = 0; static int MapperNo = 0;
static int iNES2 = 0; int iNES2 = 0;
static DECLFR(TrainerRead) { static DECLFR(TrainerRead) {
return(trainerpoo[A & 0x1FF]); return(trainerpoo[A & 0x1FF]);
@ -201,7 +201,8 @@ static void SetInput(void) {
{0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor {0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor
{0x8b265862, 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 {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 {0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Super Team Games
{0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1 {0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1
{0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Supor English (Chinese) {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 {0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman
{0x5112dc21, 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 {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 } {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET }
}; };
int x = 0; int x = 0;
@ -236,7 +238,7 @@ static void SetInput(void) {
struct BADINF { struct BADINF {
uint64 md5partial; uint64 md5partial;
char *name; const char *name;
uint32 type; uint32 type;
}; };
@ -265,15 +267,15 @@ struct CHINF {
}; };
static const TMasterRomInfo sMasterRomInfo[] = { static const TMasterRomInfo sMasterRomInfo[] = {
{ 0x62b51b108a01d2beLL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes { 0x62b51b108a01d2beULL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes
{ 0x8bb48490d8d22711LL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes { 0x8bb48490d8d22711ULL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes
{ 0xc75888d7b48cd378LL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes { 0xc75888d7b48cd378ULL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes
{ 0xf81a376fa54fdd69LL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes { 0xf81a376fa54fdd69ULL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes
{ 0xa37eb9163e001a46LL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes { 0xa37eb9163e001a46ULL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes
{ 0xde5ce25860233f7eLL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes { 0xde5ce25860233f7eULL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes
{ 0x5b3aa4cdc484a088LL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes { 0x5b3aa4cdc484a088ULL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes
{ 0x9342bf9bae1c798aLL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes { 0x9342bf9bae1c798aULL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes
{ 0x164eea6097a1e313LL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation { 0x164eea6097a1e313ULL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation
}; };
const TMasterRomInfo* MasterRomInfo; const TMasterRomInfo* MasterRomInfo;
TMasterRomInfoParams MasterRomInfoParams; TMasterRomInfoParams MasterRomInfoParams;
@ -288,38 +290,39 @@ static void CheckHInfo(void) {
static uint64 savie[] = static uint64 savie[] =
{ {
0xc04361e499748382LL, /* AD&D Heroes of the Lance */ 0xc04361e499748382ULL, /* AD&D Heroes of the Lance */
0xb72ee2337ced5792LL, /* AD&D Hillsfar */ 0xb72ee2337ced5792ULL, /* AD&D Hillsfar */
0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */ 0x2b7103b7a27bd72fULL, /* AD&D Pool of Radiance */
0x498c10dc463cfe95LL, /* Battle Fleet */ 0x498c10dc463cfe95ULL, /* Battle Fleet */
0x854d7947a3177f57LL, /* Crystalis */ 0x854d7947a3177f57ULL, /* Crystalis */
0x4a1f5336b86851b6LL, /* DW */ 0xfad22d265cd70820ULL, /* Downtown Special: Kunio-kun no Jidaigeki Dayo Zenin Shuugou! */
0xb0bcc02c843c1b79LL, /* DW */ 0x4a1f5336b86851b6ULL, /* DW */
0x2dcf3a98c7937c22LL, /* DW 2 */ 0xb0bcc02c843c1b79ULL, /* DW */
0x98e55e09dfcc7533LL, /* DW 4*/ 0x2dcf3a98c7937c22ULL, /* DW 2 */
0x733026b6b72f2470LL, /* Dw 3 */ 0x98e55e09dfcc7533ULL, /* DW 4*/
0x6917ffcaca2d8466LL, /* Famista '90 */ 0x733026b6b72f2470ULL, /* Dw 3 */
0x8da46db592a1fcf4LL, /* Faria */ 0x6917ffcaca2d8466ULL, /* Famista '90 */
0xedba17a2c4608d20LL, /* Final Fantasy */ 0x8da46db592a1fcf4ULL, /* Faria */
0x91a6846d3202e3d6LL, /* Final Fantasy */ 0xedba17a2c4608d20ULL, /* Final Fantasy */
0x012df596e2b31174LL, /* Final Fantasy 1+2 */ 0x91a6846d3202e3d6ULL, /* Final Fantasy */
0xf6b359a720549ecdLL, /* Final Fantasy 2 */ 0x012df596e2b31174ULL, /* Final Fantasy 1+2 */
0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */ 0xf6b359a720549ecdULL, /* Final Fantasy 2 */
0xd63dcc68c2b20adcLL, /* Final Fantasy J */ 0x5a30da1d9b4af35dULL, /* Final Fantasy 3 */
0x2ee3417ba8b69706LL, /* Hydlide 3*/ 0xd63dcc68c2b20adcULL, /* Final Fantasy J */
0xebbce5a54cf3ecc0LL, /* Justbreed */ 0x2ee3417ba8b69706ULL, /* Hydlide 3*/
0x6a858da551ba239eLL, /* Kaijuu Monogatari */ 0xebbce5a54cf3ecc0ULL, /* Justbreed */
0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */ 0x6a858da551ba239eULL, /* Kaijuu Monogatari */
0x04a31647de80fdabLL, /* Legend of Zelda */ 0x2db8f5d16c10b925ULL, /* Kyonshiizu 2 */
0x94b9484862a26cbaLL, /* Legend of Zelda */ 0x04a31647de80fdabULL, /* Legend of Zelda */
0xa40666740b7d22feLL, /* Mindseeker */ 0x94b9484862a26cbaULL, /* Legend of Zelda */
0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */ 0xa40666740b7d22feULL, /* Mindseeker */
0x77b811b2760104b9LL, /* Mouryou Senki Madara */ 0x82000965f04a71bbULL, /* Mirai Shinwa Jarvas */
0x11b69122efe86e8cLL, /* RPG Jinsei Game */ 0x77b811b2760104b9ULL, /* Mouryou Senki Madara */
0x9aa1dc16c05e7de5LL, /* Startropics */ 0x11b69122efe86e8cULL, /* RPG Jinsei Game */
0x1b084107d0878bd0LL, /* Startropics 2*/ 0x9aa1dc16c05e7de5ULL, /* Startropics */
0xa70b495314f4d075LL, /* Ys 3 */ 0x1b084107d0878bd0ULL, /* Startropics 2*/
0x836c0ff4f3e06e45LL, /* Zelda 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 */ 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) if (tofix & 1)
sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo); sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo);
if (tofix & 2) { 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]); sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]);
} }
if (tofix & 4) if (tofix & 4)
@ -443,17 +446,19 @@ typedef struct {
//that are not in the power of 2 tends to come //that are not in the power of 2 tends to come
//in obscure mappers themselves which supports such //in obscure mappers themselves which supports such
//size //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[] = 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}, {"NROM", 0, NROM_Init},
{"MMC1", 1, Mapper1_Init}, {"MMC1", 1, Mapper1_Init},
{"UNROM", 2, UNROM_Init}, {"UNROM", 2, UNROM_Init},
@ -672,9 +677,9 @@ static BMAPPINGLocal bmap[] = {
{"", 215, UNL8237_Init}, {"", 215, UNL8237_Init},
{"", 216, Mapper216_Init}, {"", 216, Mapper216_Init},
{"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper {"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper
// {"", 218, Mapper218_Init}, {"Magic Floor", 218, Mapper218_Init},
{"UNLA9746", 219, UNLA9746_Init}, {"UNLA9746", 219, UNLA9746_Init},
{"Debug Mapper", 220, UNLKS7057_Init}, {"Debug Mapper", 220, QTAi_Init},
{"UNLN625092", 221, UNLN625092_Init}, {"UNLN625092", 221, UNLN625092_Init},
{"", 222, Mapper222_Init}, {"", 222, Mapper222_Init},
// {"", 223, Mapper223_Init}, // {"", 223, Mapper223_Init},
@ -725,7 +730,12 @@ static BMAPPINGLocal bmap[] = {
{"158B Prot Board", 258, UNL158B_Init}, {"158B Prot Board", 258, UNL158B_Init},
{"F-15 MMC3 Based", 259, BMCF15_Init}, {"F-15 MMC3 Based", 259, BMCF15_Init},
{"HP10xx/H20xx Boards", 260, BMCHPxx_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} {"", 0, NULL}
}; };
@ -733,12 +743,9 @@ static BMAPPINGLocal bmap[] = {
int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
struct md5_context md5; struct md5_context md5;
if (FCEU_fread(&head, 1, 16, fp) != 16) if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4))
return 0; return LOADER_INVALID_FORMAT;
if (memcmp(&head, "NES\x1a", 4))
return 0;
head.cleanup(); head.cleanup();
memset(&iNESCart, 0, sizeof(iNESCart)); memset(&iNESCart, 0, sizeof(iNESCart));
@ -763,15 +770,35 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
} else } else
Mirroring = (head.ROM_type & 1); Mirroring = (head.ROM_type & 1);
int not_round_size = head.ROM_size; int not_round_size;
if(iNES2) not_round_size |= ((head.Upper_ROM_VROM_size & 0x0F) << 8); 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) if (!head.ROM_size && !iNES2)
ROM_size = 256; ROM_size = 256;
else else
ROM_size = uppow2(not_round_size); ROM_size = uppow2(not_round_size);
VROM_size = uppow2(head.VROM_size | (iNES2?((head.Upper_ROM_VROM_size & 0xF0)<<4):0)); 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; int round = true;
for (int i = 0; i != sizeof(not_power2) / sizeof(not_power2[0]); ++i) { 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) { if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) {
free(ROM); free(ROM);
ROM = NULL; ROM = NULL;
return 0; FCEU_PrintError("Unable to allocate memory.");
return LOADER_HANDLED_ERROR;
} }
memset(VROM, 0xFF, VROM_size << 13); memset(VROM, 0xFF, VROM_size << 13);
} }
@ -828,9 +856,9 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
iNESCart.CRC32 = iNESGameCRC32; iNESCart.CRC32 = iNESGameCRC32;
FCEU_printf(" PRG ROM: %3d x 16KiB\n", (round) ? ROM_size: not_round_size); 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: %3d x 8KiB\n", head.VROM_size); FCEU_printf(" CHR ROM: %d x 8KiB = %d KiB\n", VROM_size, VROM_size * 8);
FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32);
{ {
int x; int x;
FCEU_printf(" ROM MD5: 0x"); FCEU_printf(" ROM MD5: 0x");
@ -839,7 +867,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
FCEU_printf("\n"); FCEU_printf("\n");
} }
char* mappername = "Not Listed"; const char* mappername = "Not Listed";
for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
if (bmap[mappertest].number == MapperNo) { 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(" Mapper name: %s\n", mappername);
FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); 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"); 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(" NES2.0 Extensions\n");
FCEU_printf(" Sub Mapper #: %d\n", iNESCart.submapper); 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 WRAM size: %d KiB\n", (iNESCart.wram_size + iNESCart.battery_wram_size) / 1024);
FCEU_printf(" Total VRAM size: %d\n", iNESCart.vram_size + iNESCart.battery_vram_size); FCEU_printf(" Total VRAM size: %d KiB\n", (iNESCart.vram_size + iNESCart.battery_vram_size) / 1024);
if(head.ROM_type & 2) if(head.ROM_type & 2)
{ {
FCEU_printf(" WRAM backed by battery: %d\n", iNESCart.battery_wram_size); FCEU_printf(" WRAM backed by battery: %d KiB\n", iNESCart.battery_wram_size / 1024);
FCEU_printf(" VRAM backed by battery: %d\n", iNESCart.battery_vram_size); 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.battery = (head.ROM_type & 2) ? 1 : 0;
iNESCart.mirror = Mirroring; 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); 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; GameInfo->mappernum = MapperNo;
FCEU_LoadGameSave(&iNESCart); 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); FCEUI_SetVidSystem(((head.TV_system & 3) == 1) ? 1 : 0);
} else if (OverwriteVidMode) { } else if (OverwriteVidMode) {
if (strstr(name, "(E)") || strstr(name, "(e)") 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, "(Europe)") || strstr(name, "(PAL)")
|| strstr(name, "(F)") || strstr(name, "(f)") || strstr(name, "(F)") || strstr(name, "(f)")
|| strstr(name, "(G)") || strstr(name, "(g)") || 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, "(Italy)") || strstr(name, "(Spain)")
|| strstr(name, "(Sweden)") || strstr(name, "(Sw)") || strstr(name, "(Sweden)") || strstr(name, "(Sw)")
|| strstr(name, "(Australia)") || strstr(name, "(A)") || strstr(name, "(Australia)") || strstr(name, "(A)")
|| strstr(name, "(a)")) || strstr(name, "(a)"))
FCEUI_SetVidSystem(1); FCEUI_SetVidSystem(1);
else else
FCEUI_SetVidSystem(0); FCEUI_SetVidSystem(0);
} }
return 1; return LOADER_OK;
} }
// bbit edited: the whole function below was added // bbit edited: the whole function below was added
int iNesSave() { int iNesSave(void) {
char name[2048]; char name[2048];
strcpy(name, LoadedRomFName); strcpy(name, LoadedRomFName);
@ -954,7 +999,7 @@ int iNesSave() {
return iNesSaveAs(name); 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 //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. //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 //para edit: added function below
char *iNesShortFName() { char *iNesShortFName(void) {
char *ret; char *ret;
if (!(ret = strrchr(LoadedRomFName, '\\'))) if (!(ret = strrchr(LoadedRomFName, '\\')))
@ -1010,7 +1055,7 @@ static int iNES_Init(int num) {
while (tmp->init) { while (tmp->init) {
if (num == tmp->number) { 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 (!VROM_size) {
if(!iNESCart.ines2) if(!iNESCart.ines2)
{ {
@ -1030,29 +1075,31 @@ static int iNES_Init(int num) {
{ {
CHRRAMSize = iNESCart.battery_vram_size + iNESCart.vram_size; CHRRAMSize = iNESCart.battery_vram_size + iNESCart.vram_size;
} }
if ((VROM = (uint8*)FCEU_dmalloc(CHRRAMSize)) == NULL) return 0; if (CHRRAMSize > 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
{ {
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); SetupCartCHRMapping(0, VROM, CHRRAMSize, 1);
AddExState(VROM, CHRRAMSize, 0, "CHRR"); 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) if (head.ROM_type & 8)
AddExState(ExtraNTARAM, 2048, 0, "EXNR"); {
if (ExtraNTARAM != NULL)
{
AddExState(ExtraNTARAM, 2048, 0, "EXNR");
}
}
tmp->init(&iNESCart); tmp->init(&iNESCart);
return 1; return 0;
} }
tmp++; tmp++;
} }
return 0; return 1;
} }

View File

@ -43,48 +43,43 @@ extern uint8 *VROM;
extern uint32 VROM_size; extern uint32 VROM_size;
extern uint32 ROM_size; extern uint32 ROM_size;
extern uint8 *ExtraNTARAM; extern uint8 *ExtraNTARAM;
extern int iNesSave(); //bbit Edited: line added extern int iNesSave(void); //bbit Edited: line added
extern int iNesSaveAs(char* name); extern int iNesSaveAs(const char* name);
extern char LoadedRomFName[2048]; //bbit Edited: line added extern char LoadedRomFName[2048]; //bbit Edited: line added
extern char *iNesShortFName(void);
extern const TMasterRomInfo* MasterRomInfo; extern const TMasterRomInfo* MasterRomInfo;
extern TMasterRomInfoParams MasterRomInfoParams; extern TMasterRomInfoParams MasterRomInfoParams;
//mbg merge 7/19/06 changed to c++ decl format //mbg merge 7/19/06 changed to c++ decl format
struct iNES_HEADER { struct iNES_HEADER {
char ID[4]; /*NES^Z*/ char ID[4]; /*NES^Z*/ // 0-3
uint8 ROM_size; uint8 ROM_size; // 4
uint8 VROM_size; uint8 VROM_size; // 5
uint8 ROM_type; uint8 ROM_type; // 6
uint8 ROM_type2; uint8 ROM_type2; // 7
uint8 ROM_type3; uint8 ROM_type3; // 8
uint8 Upper_ROM_VROM_size; uint8 Upper_ROM_VROM_size; // 9
uint8 RAM_size; uint8 RAM_size; // 10
uint8 VRAM_size; uint8 VRAM_size; // 11
uint8 TV_system; uint8 TV_system; // 12
uint8 VS_hardware; uint8 VS_hardware; // 13
uint8 reserved[2]; uint8 reserved[2]; // 14, 15
void cleanup() void cleanup()
{ {
if(!memcmp((char *)(this)+0x7,"DiskDude",8)) if(!memcmp((char*)(this) + 0x7, "DiskDude", 8) || !memcmp((char*)(this) + 0x7, "demiforce", 9))
{ memset((char*)(this) + 0x7, 0, 0x9);
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) + 0x7, "Dis", 3))
} 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);
else else
memset((char *)(this)+0xA,0,0x6); memset((char*)(this) + 0xA, 0, 0x6);
} }
} }
}; };
extern struct iNES_HEADER head; //for mappers usage extern struct iNES_HEADER head; //for mappers usage
void NSFVRC6_Init(void); void NSFVRC6_Init(void);
@ -220,6 +215,7 @@ void Mapper186_Init(CartInfo *);
void Mapper187_Init(CartInfo *); void Mapper187_Init(CartInfo *);
void Mapper188_Init(CartInfo *); void Mapper188_Init(CartInfo *);
void Mapper189_Init(CartInfo *); void Mapper189_Init(CartInfo *);
void Mapper190_Init(CartInfo *);
void Mapper191_Init(CartInfo *); void Mapper191_Init(CartInfo *);
void Mapper192_Init(CartInfo *); void Mapper192_Init(CartInfo *);
void Mapper193_Init(CartInfo *); void Mapper193_Init(CartInfo *);
@ -246,6 +242,7 @@ void Mapper213_Init(CartInfo *);
void Mapper214_Init(CartInfo *); void Mapper214_Init(CartInfo *);
void Mapper216_Init(CartInfo *); void Mapper216_Init(CartInfo *);
void Mapper217_Init(CartInfo *); void Mapper217_Init(CartInfo *);
void Mapper218_Init(CartInfo *);
void Mapper220_Init(CartInfo *); void Mapper220_Init(CartInfo *);
void Mapper222_Init(CartInfo *); void Mapper222_Init(CartInfo *);
void Mapper225_Init(CartInfo *); void Mapper225_Init(CartInfo *);
@ -272,5 +269,11 @@ void Mapper250_Init(CartInfo *);
void Mapper252_Init(CartInfo *); void Mapper252_Init(CartInfo *);
void Mapper253_Init(CartInfo *); void Mapper253_Init(CartInfo *);
void Mapper254_Init(CartInfo *); void Mapper254_Init(CartInfo *);
void Mapper406_Init(CartInfo *);
typedef struct {
const char *name;
int32 number;
void (*init)(CartInfo *);
} BMAPPINGLocal;
#endif #endif

View File

@ -64,6 +64,8 @@ extern INPUTC *FCEU_InitPowerpadB(int w);
extern INPUTC *FCEU_InitArkanoid(int w); extern INPUTC *FCEU_InitArkanoid(int w);
extern INPUTC *FCEU_InitMouse(int w); extern INPUTC *FCEU_InitMouse(int w);
extern INPUTC *FCEU_InitSNESMouse(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_InitArkanoidFC(void);
extern INPUTCFC *FCEU_InitSpaceShadow(void); extern INPUTCFC *FCEU_InitSpaceShadow(void);
@ -77,6 +79,7 @@ extern INPUTCFC *FCEU_InitFamilyTrainerA(void);
extern INPUTCFC *FCEU_InitFamilyTrainerB(void); extern INPUTCFC *FCEU_InitFamilyTrainerB(void);
extern INPUTCFC *FCEU_InitOekaKids(void); extern INPUTCFC *FCEU_InitOekaKids(void);
extern INPUTCFC *FCEU_InitTopRider(void); extern INPUTCFC *FCEU_InitTopRider(void);
extern INPUTCFC *FCEU_InitFamiNetSys(void);
extern INPUTCFC *FCEU_InitBarcodeWorld(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 GPC={ReadGP,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP};
static INPUTC GPCVS={ReadGPVS,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) switch(joyports[port].type)
{ {
case SI_GAMEPAD: case SI_GAMEPAD:
if(GameInfo->type==GIT_VSUNI){ if (GameInfo)
joyports[port].driver = &GPCVS; {
} else { if (GameInfo->type==GIT_VSUNI){
joyports[port].driver = &GPCVS;
} else {
joyports[port].driver= &GPC;
}
}
else
{
joyports[port].driver= &GPC; joyports[port].driver= &GPC;
} }
break; break;
@ -478,7 +520,14 @@ static void SetInputStuff(int port)
case SI_SNES_MOUSE: case SI_SNES_MOUSE:
joyports[port].driver=FCEU_InitSNESMouse(port); joyports[port].driver=FCEU_InitSNESMouse(port);
break; 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_NONE:
case SI_UNSET:
joyports[port].driver=&DummyJPort; joyports[port].driver=&DummyJPort;
break; break;
} }
@ -489,6 +538,7 @@ static void SetInputStuffFC()
switch(portFC.type) switch(portFC.type)
{ {
case SIFC_NONE: case SIFC_NONE:
case SIFC_UNSET:
portFC.driver=&DummyPortFC; portFC.driver=&DummyPortFC;
break; break;
case SIFC_ARKANOID: case SIFC_ARKANOID:
@ -534,6 +584,13 @@ static void SetInputStuffFC()
case SIFC_TOPRIDER: case SIFC_TOPRIDER:
portFC.driver=FCEU_InitTopRider(); portFC.driver=FCEU_InitTopRider();
break; 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)) if(!FCEU_IsValidUI(FCEUI_SWITCH_DISK))
return; return;
FCEU_DispMessage("Command: Switch disk side", 0); // FCEU_DispMessage("Command: Switch disk side", 0);
FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT); FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT);
} }
@ -652,7 +709,7 @@ void FCEUI_FDSInsert(void)
if(!FCEU_IsValidUI(FCEUI_EJECT_DISK)) if(!FCEU_IsValidUI(FCEUI_EJECT_DISK))
return; return;
FCEU_DispMessage("Command: Insert/Eject disk", 0); // FCEU_DispMessage("Command: Insert/Eject disk", 0);
FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT); FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT);
} }
@ -713,7 +770,7 @@ const char* FCEUI_CommandTypeNames[]=
"TAS Editor", "TAS Editor",
}; };
static void CommandUnImpl(void); //static void CommandUnImpl(void);
static void CommandToggleDip(void); static void CommandToggleDip(void);
static void CommandStateLoad(void); static void CommandStateLoad(void);
static void CommandStateSave(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_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_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_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_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_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_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 }, { 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) // Function not currently used
{ //static void CommandUnImpl(void)
FCEU_DispMessage("command '%s' unimplemented.",0, FCEUI_CommandTable[i].name); //{
} // FCEU_DispMessage("command '%s' unimplemented.",0, FCEUI_CommandTable[i].name);
//}
static void CommandToggleDip(void) static void CommandToggleDip(void)
{ {
@ -948,7 +1015,7 @@ static void CommandSelectSaveSlot(void)
{ {
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
handleEmuCmdByTaseditor(execcmd); handleEmuCmdByTaseditor(execcmd);
#endif #endif
} else } else
@ -966,7 +1033,7 @@ static void CommandStateSave(void)
{ {
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
handleEmuCmdByTaseditor(execcmd); handleEmuCmdByTaseditor(execcmd);
#endif #endif
} else } else
@ -1058,64 +1125,64 @@ static void LaunchTasEditor(void)
static void LaunchMemoryWatch(void) static void LaunchMemoryWatch(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
CreateMemWatch(); CreateMemWatch();
#endif #endif
} }
static void LaunchDebugger(void) static void LaunchDebugger(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
DoDebug(0); DoDebug(0);
#endif #endif
} }
static void LaunchNTView(void) static void LaunchNTView(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
DoNTView(); DoNTView();
#endif #endif
} }
static void LaunchPPU(void) static void LaunchPPU(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
DoPPUView(); DoPPUView();
#endif #endif
} }
static void LaunchHex(void) static void LaunchHex(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
DoMemView(); DoMemView();
#endif #endif
} }
static void LaunchTraceLogger(void) static void LaunchTraceLogger(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
DoTracer(); DoTracer();
#endif #endif
} }
static void LaunchCodeDataLogger(void) static void LaunchCodeDataLogger(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
DoCDLogger(); DoCDLogger();
#endif #endif
} }
static void LaunchCheats(void) static void LaunchCheats(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
extern HWND pwindow; extern HWND hCheat;
ConfigCheats(pwindow); ConfigCheats(hCheat);
#endif #endif
} }
static void LaunchRamWatch(void) static void LaunchRamWatch(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
extern void OpenRamWatch(); //adelikat: Blah blah hacky, I know extern void OpenRamWatch(); //adelikat: Blah blah hacky, I know
OpenRamWatch(); OpenRamWatch();
#endif #endif
@ -1123,14 +1190,14 @@ static void LaunchRamWatch(void)
static void LaunchRamSearch(void) static void LaunchRamSearch(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
extern void OpenRamSearch(); extern void OpenRamSearch();
OpenRamSearch(); OpenRamSearch();
#endif #endif
} }
static void RamSearchOpLT(void) { static void RamSearchOpLT(void) {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (GameInfo) if (GameInfo)
{ {
extern void SetSearchType(int SearchType); extern void SetSearchType(int SearchType);
@ -1142,7 +1209,7 @@ static void RamSearchOpLT(void) {
} }
static void RamSearchOpGT(void) { static void RamSearchOpGT(void) {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (GameInfo) if (GameInfo)
{ {
extern void SetSearchType(int SearchType); extern void SetSearchType(int SearchType);
@ -1154,7 +1221,7 @@ static void RamSearchOpGT(void) {
} }
static void RamSearchOpLTE(void) { static void RamSearchOpLTE(void) {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (GameInfo) if (GameInfo)
{ {
extern void SetSearchType(int SearchType); extern void SetSearchType(int SearchType);
@ -1166,7 +1233,7 @@ static void RamSearchOpLTE(void) {
} }
static void RamSearchOpGTE(void) { static void RamSearchOpGTE(void) {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (GameInfo) if (GameInfo)
{ {
extern void SetSearchType(int SearchType); extern void SetSearchType(int SearchType);
@ -1178,7 +1245,7 @@ static void RamSearchOpGTE(void) {
} }
static void RamSearchOpEQ(void) { static void RamSearchOpEQ(void) {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (GameInfo) if (GameInfo)
{ {
extern void SetSearchType(int SearchType); extern void SetSearchType(int SearchType);
@ -1190,7 +1257,7 @@ static void RamSearchOpEQ(void) {
} }
static void RamSearchOpNE(void) { static void RamSearchOpNE(void) {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (GameInfo) if (GameInfo)
{ {
extern void SetSearchType(int SearchType); extern void SetSearchType(int SearchType);
@ -1203,7 +1270,7 @@ static void RamSearchOpNE(void) {
static void DebuggerStepInto() static void DebuggerStepInto()
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (GameInfo) if (GameInfo)
{ {
extern void DoDebuggerStepInto(); extern void DoDebuggerStepInto();
@ -1219,7 +1286,7 @@ static void FA_SkipLag(void)
static void OpenRom(void) static void OpenRom(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
extern HWND hAppWnd; extern HWND hAppWnd;
LoadNewGamey(hAppWnd, 0); LoadNewGamey(hAppWnd, 0);
#endif #endif
@ -1227,14 +1294,14 @@ static void OpenRom(void)
static void CloseRom(void) static void CloseRom(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
CloseGame(); CloseGame();
#endif #endif
} }
void ReloadRom(void) void ReloadRom(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
{ {
// load most recent project // load most recent project
@ -1266,14 +1333,14 @@ static void UndoRedoSavestate(void)
static void FCEUI_DoExit(void) static void FCEUI_DoExit(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
DoFCEUExit(); DoFCEUExit();
#endif #endif
} }
void ToggleFullscreen() void ToggleFullscreen()
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
extern int SetVideoMode(int fs); //adelikat: Yeah, I know, hacky extern int SetVideoMode(int fs); //adelikat: Yeah, I know, hacky
extern void UpdateCheckedMenuItems(); extern void UpdateCheckedMenuItems();
@ -1289,21 +1356,34 @@ void ToggleFullscreen()
static void TaseditorRewindOn(void) static void TaseditorRewindOn(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
mustRewindNow = true; mustRewindNow = true;
#endif #endif
} }
static void TaseditorRewindOff(void) static void TaseditorRewindOff(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
mustRewindNow = false; mustRewindNow = false;
#endif #endif
} }
static void TaseditorCommand(void) static void TaseditorCommand(void)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))
handleEmuCmdByTaseditor(execcmd); handleEmuCmdByTaseditor(execcmd);
#endif #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 extern struct JOYPORT
{ {
JOYPORT(int _w) JOYPORT(int _w)
: w(_w) : w(_w), attrib(0), type(SI_UNSET), ptr(0), driver(0)
{} {}
int w; int w;
@ -248,6 +248,17 @@ enum EMUCMD
EMUCMD_FPS_DISPLAY_TOGGLE, EMUCMD_FPS_DISPLAY_TOGGLE,
EMUCMD_TOOL_DEBUGSTEPINTO, 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 EMUCMD_MAX
}; };
@ -284,7 +295,7 @@ struct EMUCMDTABLE
EMUCMDFN* fn_on; EMUCMDFN* fn_on;
EMUCMDFN* fn_off; EMUCMDFN* fn_off;
int state; int state;
char* name; const char* name;
int flags; //EMUCMDFLAG int flags; //EMUCMDFLAG
}; };
@ -295,5 +306,6 @@ extern bool lagCounterDisplay;
extern char lagFlag; extern char lagFlag;
extern bool turbo; extern bool turbo;
void LagCounterReset(); void LagCounterReset();
EMUCMDTABLE* GetEmuCommandById(int cmd);
#endif //_INPUT_H_ #endif //_INPUT_H_

View File

@ -76,9 +76,9 @@ static void ZapperFrapper(int w, uint8 *bg, uint8 *spr, uint32 linets, int final
} }
endo: endo:
ZD[w].zappo=final; ZD[w].zappo=final;
#ifndef GEKKO #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) if(ZD[w].mzb&2)
ZD[w].zaphit=0; ZD[w].zaphit=0;
#endif #endif
@ -87,8 +87,8 @@ endo:
static INLINE int CheckColor(int w) static INLINE int CheckColor(int w)
{ {
FCEUPPU_LineUpdate(); FCEUPPU_LineUpdate();
if(newppu) if(newppu)
{ {
int x = (int)ZD[w].mzx; int x = (int)ZD[w].mzx;
int y = (int)ZD[w].mzy; 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].mzy=ptr[1];
ZD[w].mzb=ptr[2]; ZD[w].mzb=ptr[2];
#else #else
bool newclicked = (ptr[2]&3)!=0; bool newclicked = (ptr[2]&3)!=0;
bool oldclicked = (ZD[w].lastInput)!=0; bool oldclicked = (ZD[w].lastInput)!=0;
if(ZD[w].bogo) if(ZD[w].bogo)
{ {
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. //woah.. this looks like broken bit logic.
if(newclicked && !oldclicked) if (newclicked && !oldclicked)
{ {
ZD[w].bogo=5; ZD[w].bogo=5;
ZD[w].mzb=ptr[2]; ZD[w].mzb=ptr[2];
ZD[w].mzx=ptr[0]; ZD[w].mzx=ptr[0];
ZD[w].mzy=ptr[1]; 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 #endif
} }
@ -230,7 +235,7 @@ static INPUTC ZAPVSC={ReadZapperVS,0,StrobeZapperVS,UpdateZapper,ZapperFrapper,D
INPUTC *FCEU_InitZapper(int w) INPUTC *FCEU_InitZapper(int w)
{ {
memset(&ZD[w],0,sizeof(ZAPPER)); memset(&ZD[w],0,sizeof(ZAPPER));
if(GameInfo->type == GIT_VSUNI) if ( (GameInfo != NULL) && (GameInfo->type == GIT_VSUNI) )
return(&ZAPVSC); return(&ZAPVSC);
else else
return(&ZAPC); return(&ZAPC);

View File

@ -21,6 +21,7 @@
#include "utils/memory.h" #include "utils/memory.h"
#include "utils/xstring.h" #include "utils/xstring.h"
#include <sstream> #include <sstream>
#include <algorithm>
#ifdef CREATE_AVI #ifdef CREATE_AVI
#include "drivers/videolog/nesvideos-piece.h" #include "drivers/videolog/nesvideos-piece.h"
@ -28,6 +29,8 @@
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
#ifdef __WIN_DRIVER__
#include "./drivers/win/common.h" #include "./drivers/win/common.h"
#include "./drivers/win/window.h" #include "./drivers/win/window.h"
extern void AddRecentMovieFile(const char *filename); extern void AddRecentMovieFile(const char *filename);
@ -35,6 +38,8 @@ extern void AddRecentMovieFile(const char *filename);
extern bool mustEngageTaseditor; extern bool mustEngageTaseditor;
#endif #endif
#endif
extern int RAMInitOption; extern int RAMInitOption;
extern int RAMInitSeed; extern int RAMInitSeed;
@ -98,6 +103,7 @@ int input_display = 0;
int frame_display = 0; int frame_display = 0;
int rerecord_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) 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[]={ SFORMAT FCEUMOV_STATEINFO[]={
{ &currFrameCounter, 4|FCEUSTATE_RLSB, "FCNT"}, { &currFrameCounter, 4|FCEUSTATE_RLSB, "FCNT"},
@ -129,7 +135,6 @@ void MovieRecord::dump(MovieData* md, EMUFILE* os, int index) { }
MovieData::MovieData() { } MovieData::MovieData() { }
void MovieData::truncateAt(int frame) { } void MovieData::truncateAt(int frame) { }
void MovieData::installValue(std::string& key, std::string& val) { } 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 FCEUMOV_GetFrame(void) { return 0; }
int FCEUI_GetLagCount(void) { return 0; } int FCEUI_GetLagCount(void) { return 0; }
bool FCEUI_GetLagged(void) { return false; } bool FCEUI_GetLagged(void) { return false; }
@ -460,12 +465,12 @@ MovieData::MovieData()
, fds(false) , fds(false)
, palFlag(false) , palFlag(false)
, PPUflag(false) , PPUflag(false)
, RAMInitOption(0)
, RAMInitSeed(0)
, rerecordCount(0) , rerecordCount(0)
, binaryFlag(false) , binaryFlag(false)
, loadFrameCount(-1) , loadFrameCount(-1)
, microphone(false) , microphone(false)
, RAMInitOption(0)
, RAMInitSeed(0)
{ {
memset(&romChecksum,0,sizeof(MD5DATA)); 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(); int start = os->ftell();
os->fprintf("version %d\n", version); os->fprintf("version %d\n", version);
@ -580,19 +585,30 @@ int MovieData::dump(EMUFILE *os, bool binary)
if (this->loadFrameCount >= 0) if (this->loadFrameCount >= 0)
os->fprintf("length %d\n" , this->loadFrameCount); os->fprintf("length %d\n" , this->loadFrameCount);
int currFramePos = -1;
if(binary) if(binary)
{ {
//put one | to start the binary dump //put one | to start the binary dump
os->fputc('|'); 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); records[i].dumpBinary(this, os, i);
}
} else } 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); records[i].dump(this, os, i);
}
} }
int end = os->ftell(); int end = os->ftell();
if (currFramePos >= 0)
os->fseek(currFramePos, SEEK_SET);
return end-start; return end-start;
} }
@ -671,7 +687,7 @@ static void LoadFM2_binarychunk(MovieData& movieData, EMUFILE* fp, int size)
fp->fseek(curr,SEEK_SET); fp->fseek(curr,SEEK_SET);
//the amount todo is the min of the limiting size we received and the remaining contents of the file //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; int numRecords = todo/recordsize;
if (movieData.loadFrameCount!=-1 && movieData.loadFrameCount<numRecords) if (movieData.loadFrameCount!=-1 && movieData.loadFrameCount<numRecords)
@ -782,6 +798,9 @@ bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader)
state = VALUE; state = VALUE;
if(isnewline) goto commit; if(isnewline) goto commit;
value += c; value += c;
break;
default:
break;
} }
goto done; goto done;
@ -799,65 +818,145 @@ bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader)
return true; return true;
} }
/// Stop movie playback. static const char *GetMovieModeStr()
static void StopPlayback()
{ {
FCEU_DispMessageOnMovie("Movie playback stopped."); if (movieMode == MOVIEMODE_INACTIVE)
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 const char *GetMovieReadOnlyStr()
static void FinishPlayback()
{ {
extern int closeFinishedMovie; if (movieMode == MOVIEMODE_RECORD)
if (closeFinishedMovie) return movie_readonly ? " R-O" : "";
StopPlayback();
else else
return movie_readonly ? "" : " R+W";
}
static const char *GetMovieRecordModeStr()
{
switch (movieRecordMode)
{ {
FCEU_DispMessage("Movie finished playing.",0); case MOVIE_RECORD_MODE_OVERWRITE:
movieMode = MOVIEMODE_FINISHED; 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() static void closeRecordingMovie()
{ {
if(osRecordingMovie) if (osRecordingMovie)
{ {
delete osRecordingMovie; delete osRecordingMovie;
osRecordingMovie = 0; 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 /// Stop movie recording
static void StopRecording() static void StopRecording()
{ {
FCEU_DispMessage("Movie recording stopped.",0); assert(movieMode == MOVIEMODE_RECORD);
movieMode = MOVIEMODE_INACTIVE;
closeRecordingMovie(); movieMode = MOVIEMODE_INACTIVE;
RedumpWholeMovieFile(true);
FCEU_DispMessage("Movie recording stopped.",0);
} }
void FCEUI_StopMovie() static void OnMovieClosed()
{ {
if(suppressMovieStop) assert(movieMode == MOVIEMODE_INACTIVE);
return;
if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED)
StopPlayback();
else if(movieMode == MOVIEMODE_RECORD)
StopRecording();
curMovieFilename[0] = 0; //No longer a current movie filename curMovieFilename[0] = 0; //No longer a current movie filename
freshMovie = false; //No longer a fresh movie loaded 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 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(); SetMainWindowText();
#endif #endif
} }
bool bogorf; 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) void poweron(bool shouldDisableBatteryLoading)
{ {
//// make a for-movie-recording power-on clear the game's save data, too //// make a for-movie-recording power-on clear the game's save data, too
@ -892,7 +991,10 @@ void FCEUMOV_CreateCleanMovie()
currMovieData = MovieData(); currMovieData = MovieData();
currMovieData.palFlag = FCEUI_GetCurrentVidSystem(0,0)!=0; currMovieData.palFlag = FCEUI_GetCurrentVidSystem(0,0)!=0;
currMovieData.romFilename = FileBase; currMovieData.romFilename = FileBase;
currMovieData.romChecksum = GameInfo->MD5; if ( GameInfo )
{
currMovieData.romChecksum = GameInfo->MD5;
}
currMovieData.guid.newGuid(); currMovieData.guid.newGuid();
currMovieData.fourscore = FCEUI_GetInputFourscore(); currMovieData.fourscore = FCEUI_GetInputFourscore();
currMovieData.microphone = FCEUI_GetInputMicrophone(); 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 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 //Fix relative path if necessary and then add to the recent movie menu
extern std::string BaseDirectory; 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 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 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 //fully reload the game to reinitialize everything before playing any movie
poweron(true); poweron(true);
@ -1070,7 +1173,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
else else
FCEU_DispMessage("Replay started Read+Write.",0); FCEU_DispMessage("Replay started Read+Write.",0);
#ifdef WIN32 #ifdef __WIN_DRIVER__
SetMainWindowText(); SetMainWindowText();
#endif #endif
@ -1085,18 +1188,6 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
return true; 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 //begin recording a new movie
//TODO - BUG - the record-from-another-savestate doesnt work. //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(); FCEUI_StopMovie();
openRecordingMovie(fname); if (NULL == openRecordingMovie(fname))
return;
#ifdef __WIN_DRIVER__
//Add to the recent movie menu
AddRecentMovieFile(fname);
#endif
currFrameCounter = 0; currFrameCounter = 0;
LagCounterReset(); 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 //either dumps the current joystick state or loads one state from the movie
void FCEUMOV_AddInputState() void FCEUMOV_AddInputState()
{ {
#ifdef _WIN32 #ifdef __WIN_DRIVER__
if (movieMode == MOVIEMODE_TASEDITOR) if (movieMode == MOVIEMODE_TASEDITOR)
{ {
// if movie length is less or equal to currFrame, pad it with empty frames // if movie length is less or equal to currFrame, pad it with empty frames
@ -1241,14 +1338,29 @@ void FCEUMOV_AddInputState()
mr.commands = _currCommand; mr.commands = _currCommand;
_currCommand = 0; _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 the user chooses it can be delayed to here
if (fullSaveStateLoads && (currFrameCounter < (int)currMovieData.records.size())) if (currFrameCounter < (int)currMovieData.records.size())
currMovieData.truncateAt(currFrameCounter); 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 mr.dump(&currMovieData, osRecordingMovie, currFrameCounter); // to disk
currMovieData.records.push_back(mr);
} }
currFrameCounter++; currFrameCounter++;
@ -1282,33 +1394,42 @@ void FCEUMOV_AddCommand(int cmd)
void FCEU_DrawMovies(uint8 *XBuf) 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}; char counterbuf[32] = {0};
int color = 0x20; int color = 0x20;
if(movieMode == MOVIEMODE_PLAY)
sprintf(counterbuf,"%d/%d",currFrameCounter,(int)currMovieData.records.size()); if (movieMode == MOVIEMODE_PLAY)
else if(movieMode == MOVIEMODE_RECORD)
sprintf(counterbuf,"%d",currFrameCounter);
else if (movieMode == MOVIEMODE_FINISHED)
{ {
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 color = 0x17; //Show red to get attention
} else if(movieMode == MOVIEMODE_TASEDITOR) } else if (movieMode == MOVIEMODE_TASEDITOR)
{ {
sprintf(counterbuf,"%d",currFrameCounter); sprintf(counterbuf,"%d",currFrameCounter);
} else } else
sprintf(counterbuf,"%d (no movie)",currFrameCounter); sprintf(counterbuf,"%d (no movie)",currFrameCounter);
if(counterbuf[0]) if (counterbuf[0])
DrawTextTrans(ClipSidesOffset+XBuf+FCEU_TextScanlineOffsetFromBottom(30)+1, 256, (uint8*)counterbuf, color+0x80); 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}; 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); 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) 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); 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) if (result == IDYES)
mustEngageTaseditor = true; mustEngageTaseditor = true;
@ -1451,10 +1572,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
if(tempMovieData.guid != currMovieData.guid) if(tempMovieData.guid != currMovieData.guid)
{ {
//mbg 8/18/08 - this code can be used to turn the error message into an OK/CANCEL //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?"; 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(hAppWnd, msg.c_str(), "Error loading savestate", MB_OKCANCEL);
int result = MessageBox(pwindow,msg.c_str(),"Error loading savestate",MB_OKCANCEL);
if(result == IDCANCEL) 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 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 #endif
} }
closeRecordingMovie();
if (movie_readonly) if (movie_readonly)
{ {
if (movieMode == MOVIEMODE_RECORD)
{
movieMode = MOVIEMODE_PLAY;
RedumpWholeMovieFile(true);
closeRecordingMovie();
}
// currFrameCounter at this point represents the savestate framecount // currFrameCounter at this point represents the savestate framecount
int frame_of_mismatch = CheckTimelines(tempMovieData, currMovieData); int frame_of_mismatch = CheckTimelines(tempMovieData, currMovieData);
if (frame_of_mismatch >= 0) if (frame_of_mismatch >= 0)
@ -1494,50 +1619,42 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
} else } else
FCEU_PrintError("Error: Savestate not in the same timeline as movie!\nFrame %d branches from current timeline", frame_of_mismatch); FCEU_PrintError("Error: Savestate not in the same timeline as movie!\nFrame %d branches from current timeline", frame_of_mismatch);
return false; return false;
} else if (movieMode == MOVIEMODE_FINISHED } else if ((int)tempMovieData.records.size() < currFrameCounter)
&& currFrameCounter > (int)currMovieData.records.size()
&& currMovieData.records.size() == tempMovieData.records.size())
{ {
// special case (in MOVIEMODE_FINISHED mode) // this is post-movie savestate and must be checked further
// allow loading post-movie savestates that were made after finishing current movie if (tempMovieData.records.size() < currMovieData.records.size())
} 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
{ {
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); // this savestate doesn't contain enough input to be checked
FCEUI_StopMovie(); //TODO: turn frame counter to red to get attention
} else if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user
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; 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);
} else if (currFrameCounter > (int)tempMovieData.records.size()) FCEUI_StopMovie();
{ } else
// this is post-movie savestate, don't allow it 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);
//TODO: turn frame counter to red to get attention return false;
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;
} }
// 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 } else
{ {
//Read+Write mode //Read+Write mode
closeRecordingMovie();
if (currFrameCounter > (int)tempMovieData.records.size()) if (currFrameCounter > (int)tempMovieData.records.size())
{ {
//This is a post movie savestate, handle it differently //This is a post movie savestate, handle it differently
//Replace movie contents but then switch to movie finished mode //Replace movie contents but then switch to movie finished mode
currMovieData = tempMovieData; currMovieData = tempMovieData;
openRecordingMovie(curMovieFilename); movieMode = MOVIEMODE_PLAY;
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/); FCEUMOV_IncrementRerecordCount();
RedumpWholeMovieFile();
FinishPlayback(); FinishPlayback();
} else } else
{ {
@ -1547,11 +1664,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
tempMovieData.truncateAt(currFrameCounter); tempMovieData.truncateAt(currFrameCounter);
currMovieData = tempMovieData; currMovieData = tempMovieData;
FCEUMOV_IncrementRerecordCount();
openRecordingMovie(curMovieFilename);
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/);
movieMode = MOVIEMODE_RECORD; movieMode = MOVIEMODE_RECORD;
FCEUMOV_IncrementRerecordCount();
RedumpWholeMovieFile(true);
} }
} }
} }
@ -1659,37 +1774,213 @@ void FCEUI_SetMovieToggleReadOnly(bool which)
FCEU_DispMessage("Movie is Read+Write.",0); FCEU_DispMessage("Movie is Read+Write.",0);
} }
} }
//auqnull: What's the point to toggle Read-Only without a movie loaded?
void FCEUI_MovieToggleReadOnly() void FCEUI_MovieToggleReadOnly()
{ {
char message[260]; char message[260];
if(movie_readonly) movie_readonly = !movie_readonly;
strcpy(message, "Movie is now Read+Write"); if (movie_readonly)
else
strcpy(message, "Movie is now Read-Only"); 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) if (movieMode == MOVIEMODE_INACTIVE)
strcat(message, " (no movie)"); strcpy(message, "Cannot toggle Recording");
else if (movieMode == MOVIEMODE_FINISHED) else if (currFrameCounter > (int)currMovieData.records.size())
strcat(message, " (finished)"); {
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); strcat(message, GetMovieModeStr());
movie_readonly = !movie_readonly;
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) void FCEUI_MoviePlayFromBeginning(void)
{ {
if (movieMode == MOVIEMODE_TASEDITOR) if (movieMode == MOVIEMODE_TASEDITOR)
{ {
#ifdef WIN32 #ifdef __WIN_DRIVER__
handleEmuCmdByTaseditor(EMUCMD_MOVIE_PLAY_FROM_BEGINNING); handleEmuCmdByTaseditor(EMUCMD_MOVIE_PLAY_FROM_BEGINNING);
#endif #endif
} else if (movieMode != MOVIEMODE_INACTIVE) } else if (movieMode != MOVIEMODE_INACTIVE)
{ {
if (movieMode == MOVIEMODE_RECORD)
{
movieMode = MOVIEMODE_PLAY;
RedumpWholeMovieFile(true);
}
if (currMovieData.savestate.empty()) if (currMovieData.savestate.empty())
{ {
movie_readonly = true; movie_readonly = true;
movieMode = MOVIEMODE_PLAY; movieMode = MOVIEMODE_PLAY;
cur_input_display = 0; //clear previous input display
poweron(true); poweron(true);
currFrameCounter = 0; currFrameCounter = 0;
FCEU_DispMessage("Movie is now Read-Only. Playing from beginning.",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 //currMovieData.loadSavestateFrom(&currMovieData.savestate); //TODO: make something like this work instead so it doesn't have to reload
} }
} }
#ifdef WIN32 #ifdef __WIN_DRIVER__
SetMainWindowText(); SetMainWindowText();
#endif #endif
} }
@ -1783,7 +2074,7 @@ void ProcessSubtitles(void)
} }
} }
void FCEU_DisplaySubtitles(char *format, ...) void FCEU_DisplaySubtitles(const char *format, ...)
{ {
va_list ap; va_list ap;

View File

@ -65,6 +65,16 @@ enum EMOVIEMODE
MOVIEMODE_FINISHED = 16 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 enum EMOVIECMD
{ {
MOVIECMD_RESET = 1, MOVIECMD_RESET = 1,
@ -200,7 +210,7 @@ public:
//whether microphone is enabled //whether microphone is enabled
bool microphone; bool microphone;
int getNumRecords() { return records.size(); } int getNumRecords() { return (int)records.size(); }
int RAMInitOption, RAMInitSeed; int RAMInitOption, RAMInitSeed;
@ -234,7 +244,7 @@ public:
void truncateAt(int frame); void truncateAt(int frame);
void installValue(std::string& key, std::string& val); 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 clearRecordRange(int start, int len);
void eraseRecords(int at, int frames = 1); void eraseRecords(int at, int frames = 1);
@ -267,6 +277,9 @@ extern bool freshMovie;
extern bool movie_readonly; extern bool movie_readonly;
extern bool autoMovieBackup; extern bool autoMovieBackup;
extern bool fullSaveStateLoads; extern bool fullSaveStateLoads;
extern int movieRecordMode;
extern int input_display;
//-------------------------------------------------- //--------------------------------------------------
void FCEUI_MakeBackupMovie(bool dispMessage); void FCEUI_MakeBackupMovie(bool dispMessage);
void FCEUI_CreateMovieFile(std::string fn); 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); bool FCEUI_MovieGetInfo(FCEUFILE* fp, MOVIE_INFO& info, bool skipFrameCount = false);
//char* FCEUI_MovieGetCurrentName(int addSlotNumber); //char* FCEUI_MovieGetCurrentName(int addSlotNumber);
void FCEUI_MovieToggleReadOnly(void); 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(); bool FCEUI_GetMovieToggleReadOnly();
void FCEUI_SetMovieToggleReadOnly(bool which); void FCEUI_SetMovieToggleReadOnly(bool which);
int FCEUI_GetMovieLength(); int FCEUI_GetMovieLength();
@ -288,9 +310,10 @@ void FCEUI_ToggleInputDisplay(void);
void LoadSubtitles(MovieData &); void LoadSubtitles(MovieData &);
void ProcessSubtitles(void); void ProcessSubtitles(void);
void FCEU_DisplaySubtitles(char *format, ...); void FCEU_DisplaySubtitles(const char *format, ...);
void poweron(bool shouldDisableBatteryLoading); void poweron(bool shouldDisableBatteryLoading);
bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader);
#endif //__MOVIE_H_ #endif //__MOVIE_H_

View File

@ -134,25 +134,30 @@ void NSFGI(GI h)
{ {
switch(h) switch(h)
{ {
case GI_CLOSE: case GI_CLOSE:
if(NSFDATA) {free(NSFDATA);NSFDATA=0;} if(NSFDATA) {free(NSFDATA);NSFDATA=0;}
if(ExWRAM) {free(ExWRAM);ExWRAM=0;} if(ExWRAM) {free(ExWRAM);ExWRAM=0;}
if(NSFHeader.SoundChip&1) { if(NSFHeader.SoundChip&1) {
// NSFVRC6_Init(); // NSFVRC6_Init();
} else if(NSFHeader.SoundChip&2) { } else if(NSFHeader.SoundChip&2) {
// NSFVRC7_Init(); // NSFVRC7_Init();
} else if(NSFHeader.SoundChip&4) { } else if(NSFHeader.SoundChip&4) {
// FDSSoundReset(); // FDSSoundReset();
} else if(NSFHeader.SoundChip&8) { } else if(NSFHeader.SoundChip&8) {
NSFMMC5_Close(); NSFMMC5_Close();
} else if(NSFHeader.SoundChip&0x10) { } else if(NSFHeader.SoundChip&0x10) {
// NSFN106_Init(); // NSFN106_Init();
} else if(NSFHeader.SoundChip&0x20) { } else if(NSFHeader.SoundChip&0x20) {
// NSFAY_Init(); // NSFAY_Init();
} }
break;
case GI_RESETM2:
case GI_POWER:
NSF_init();
break;
default:
//Unhandled cases
break; 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_fseek(fp,0,SEEK_SET);
FCEU_fread(&NSFHeader,1,0x80,fp); FCEU_fread(&NSFHeader,1,0x80,fp);
if(memcmp(NSFHeader.ID,"NESM\x1a",5)) if(memcmp(NSFHeader.ID,"NESM\x1a",5))
return 0; return LOADER_INVALID_FORMAT;
NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0; NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0;
LoadAddr=NSFHeader.LoadAddressLow; LoadAddr=NSFHeader.LoadAddressLow;
@ -183,7 +188,7 @@ int NSFLoad(const char *name, FCEUFILE *fp)
if(LoadAddr<0x6000) if(LoadAddr<0x6000)
{ {
FCEUD_PrintError("Invalid load address."); FCEUD_PrintError("Invalid load address.");
return(0); return LOADER_HANDLED_ERROR;
} }
InitAddr=NSFHeader.InitAddressLow; InitAddr=NSFHeader.InitAddressLow;
InitAddr|=NSFHeader.InitAddressHigh<<8; InitAddr|=NSFHeader.InitAddressHigh<<8;
@ -196,8 +201,11 @@ int NSFLoad(const char *name, FCEUFILE *fp)
NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096); NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096);
NSFMaxBank=PRGsize[0]=uppow2(NSFMaxBank); NSFMaxBank=PRGsize[0]=uppow2(NSFMaxBank);
if(!(NSFDATA=(uint8 *)FCEU_malloc(NSFMaxBank*4096))) if (!(NSFDATA = (uint8 *)FCEU_malloc(NSFMaxBank * 4096)))
return 0; {
FCEU_PrintError("Unable to allocate memory.");
return LOADER_HANDLED_ERROR;
}
FCEU_fseek(fp,0x80,SEEK_SET); FCEU_fseek(fp,0x80,SEEK_SET);
memset(NSFDATA,0x00,NSFMaxBank*4096); 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); FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright);
if(NSFHeader.SoundChip) 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++) for(x=0;x<6;x++)
if(NSFHeader.SoundChip&(1<<x)) if(NSFHeader.SoundChip&(1<<x))
@ -288,7 +296,7 @@ int NSFLoad(const char *name, FCEUFILE *fp)
FCEUI_SetVidSystem(NSFHeader.VideoSystem); FCEUI_SetVidSystem(NSFHeader.VideoSystem);
return 1; return LOADER_OK;
} }
static DECLFR(NSFVectorRead) 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)); case 0x9F: ST_ABY(_A&_X&(((A-_Y)>>8)+1));
/* SYA */ /* 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 */ /* 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 */ /* XAS */
case 0x9B: _S=_A&_X;ST_ABY(_S& (((A-_Y)>>8)+1) ); case 0x9B: _S=_A&_X;ST_ABY(_S& (((A-_Y)>>8)+1) );

View File

@ -41,13 +41,14 @@
#include <cstring> #include <cstring>
bool force_grayscale = false; bool force_grayscale = false;
pal *grayscaled_palo = NULL;
pal palette_game[64*8]; //custom palette for an individual game. (formerly palettei) 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_user[64*8]; //user's overridden palette (formerly palettec)
pal palette_ntsc[64*8]; //mathematically generated NTSC palette (formerly paletten) pal palette_ntsc[64*8]; //mathematically generated NTSC palette (formerly paletten)
static bool palette_game_available; //whether palette_game is available static bool palette_game_available=false; //whether palette_game is available
static bool palette_user_available; //whether palette_user is available static bool palette_user_available=false; //whether palette_user is available
//ntsc parameters: //ntsc parameters:
bool ntsccol_enable = false; //whether NTSC palette is selected bool ntsccol_enable = false; //whether NTSC palette is selected
@ -61,10 +62,11 @@ int default_palette_selection = 0;
static pal *default_palette[8]= static pal *default_palette[8]=
{ {
palette, palette,
rp2c04001, rp2c04_0001,
rp2c04002, rp2c04_0002,
rp2c04003, rp2c04_0003,
rp2c05004, rp2c04_0004,
rp2c03,
}; };
static void CalculatePalette(void); static void CalculatePalette(void);
@ -72,7 +74,7 @@ static void ChoosePalette(void);
static void WritePalette(void); static void WritePalette(void);
//points to the actually selected current palette //points to the actually selected current palette
pal *palo; pal *palo = NULL;
#define RGB_TO_YIQ( r, g, b, y, i ) (\ #define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ (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 }; { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
fb = YIQ_TO_RGB( y, i, q, default_decoder, float, fr, fg ); 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 //doesnt help
//float gamma=1.8f; //float gamma=1.8f;
// auto gammafix = [=](float f) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); }; // 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; }; // auto clamp = [](int v) { return v<0 ? 0 : v>255 ? 255 : v; };
// r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q)); // r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q));
// g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q)); // g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q));
// b = clamp(255 * gammafix(y + -1.108545f*i + 1.709007f*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; } 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; } int bisqwit_wave(int p, int color) { return (color+p+8)%12 < 6; }
static void ApplyDeemphasisBisqwit(int entry, u8& r, u8& g, u8& b) static void ApplyDeemphasisBisqwit(int entry, u8& r, u8& g, u8& b)
{ {
if(entry<64) return; if(entry<64) return;
int myr, myg, myb; int myr=0, myg=0, myb=0;
// The input value is a NES color index (with de-emphasis bits). // The input value is a NES color index (with de-emphasis bits).
// We need RGB values. Convert the index into RGB. // We need RGB values. Convert the index into RGB.
// For most part, this process is described at: // For most part, this process is described at:
// http://wiki.nesdev.com/w/index.php/NTSC_video // http://wiki.nesdev.com/w/index.php/NTSC_video
// Decode the color index // Decode the color index
int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1; int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1;
// Voltage levels, relative to synch voltage // Voltage levels, relative to synch voltage
static const float black=.518f, white=1.962f, attenuation=.746f, static const float black=.518f, white=1.962f, attenuation=.746f,
levels[8] = {.350f, .518f, .962f,1.550f, // Signal low levels[8] = {.350f, .518f, .962f,1.550f, // Signal low
1.094f,1.506f,1.962f,1.962f}; // Signal high 1.094f,1.506f,1.962f,1.962f}; // Signal high
float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)], float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)],
levels[level + 4 * (color < 0xD)] }; levels[level + 4 * (color < 0xD)] };
//fceux alteration: two passes //fceux alteration: two passes
//1st pass calculates bisqwit's base color //1st pass calculates bisqwit's base color
//2nd pass calculates it with deemph //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) //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. //whatever, it gets the job done.
for(int pass=0;pass<2;pass++) for(int pass=0;pass<2;pass++)
{ {
float y=0.f, i=0.f, q=0.f, gamma=1.8f; 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. for(int p=0; p<12; ++p) // 12 clock cycles per pixel.
{ {
// NES NTSC modulator (square wave between two voltage levels): // NES NTSC modulator (square wave between two voltage levels):
float spot = lo_and_hi[bisqwit_wave(p,color)]; float spot = lo_and_hi[bisqwit_wave(p,color)];
// De-emphasis bits attenuate a part of the signal: // De-emphasis bits attenuate a part of the signal:
if(pass==1) if(pass==1)
{ {
if(((entry & 0x40) && bisqwit_wave(p,12)) if(((entry & 0x40) && bisqwit_wave(p,12))
|| ((entry & 0x80) && bisqwit_wave(p, 4)) || ((entry & 0x80) && bisqwit_wave(p, 4))
|| ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation; || ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation;
} }
// Normalize: // Normalize:
float v = (spot - black) / (white-black) / 12.f; float v = (spot - black) / (white-black) / 12.f;
// Ideal TV NTSC demodulator: // Ideal TV NTSC demodulator:
y += v; y += v;
i += v * std::cos(3.141592653 * p / 6); i += v * std::cos(3.141592653 * p / 6);
q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... ) 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 // 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). // the exactly same result, scaled by a factor of 2*cos(pi/12).
} }
// Convert YIQ into RGB according to FCC-sanctioned conversion matrix. // 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 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 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)); int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma));
if(pass==0) myr = rt, myg = gt, myb = bt; if(pass==0) myr = rt, myg = gt, myb = bt;
else else
{ {
float rscale = (float)rt / myr; float rscale = (float)rt / myr;
float gscale = (float)gt / myg; float gscale = (float)gt / myg;
float bscale = (float)bt / myb; float bscale = (float)bt / myb;
#define BCLAMP(x) ((x)<0?0:((x)>255?255:(x))) #define BCLAMP(x) ((x)<0?0:((x)>255?255:(x)))
if(myr!=0) r = (u8)(BCLAMP(r*rscale)); if(myr!=0) r = (u8)(BCLAMP(r*rscale));
if(myg!=0) g = (u8)(BCLAMP(g*gscale)); 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 //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) void FCEUI_SetUserPalette(uint8 *pal, int nEntries)
{ {
if(!pal) if(!pal)
@ -521,6 +528,29 @@ static void ChoosePalette(void)
//need to calcualte a deemph on the fly.. sorry. maybe support otherwise later //need to calcualte a deemph on the fly.. sorry. maybe support otherwise later
ApplyDeemphasisComplete(palo); 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) 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_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 #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] = { pal rp2c04_0001[512] = {
#include "rp2c04001.h" #include "rp2c04-0001.h"
EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_DEEMPH_X_7
}; };
pal rp2c04002[512] = { pal rp2c04_0002[512] = {
#include "rp2c04002.h" #include "rp2c04-0002.h"
EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_DEEMPH_X_7
}; };
pal rp2c04003[512] = { pal rp2c04_0003[512] = {
#include "rp2c04003.h" #include "rp2c04-0003.h"
EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_DEEMPH_X_7
}; };
pal rp2c05004[512] = { pal rp2c04_0004[512] = {
#include "rp2c05004.h" #include "rp2c04-0004.h"
EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_DEEMPH_X_7
}; };
pal rp2c03[512] = {
#include "rp2c03.h"
};
// Fixed palette entries used by the GUI // Fixed palette entries used by the GUI
pal palette_unvarying[] = { pal palette_unvarying[] = {
{ 0x00<<2,0x00<<2,0x00<<2}, // 0 = Black { 0x00<<2,0x00<<2,0x00<<2}, // 0 = Black

View File

@ -330,7 +330,7 @@ int fceuindbg = 0;
//0xFF shall indicate to use palette[0] //0xFF shall indicate to use palette[0]
uint8 gNoBGFillColor = 0xFF; uint8 gNoBGFillColor = 0xFF;
int MMC5Hack = 0, PEC586Hack = 0;; int MMC5Hack = 0;
uint32 MMC5HackVROMMask = 0; uint32 MMC5HackVROMMask = 0;
uint8 *MMC5HackExNTARAMPtr = 0; uint8 *MMC5HackExNTARAMPtr = 0;
uint8 *MMC5HackVROMPTR = 0; uint8 *MMC5HackVROMPTR = 0;
@ -340,6 +340,12 @@ uint8 MMC50x5130 = 0;
uint8 MMC5HackSPScroll = 0; uint8 MMC5HackSPScroll = 0;
uint8 MMC5HackSPPage = 0; uint8 MMC5HackSPPage = 0;
int PEC586Hack = 0;
int QTAIHack = 0;
uint8 QTAINTRAM[2048];
uint8 qtaintramreg;
uint8 VRAMBuffer = 0, PPUGenLatch = 0; uint8 VRAMBuffer = 0, PPUGenLatch = 0;
uint8 *vnapage[4]; uint8 *vnapage[4];
uint8 PPUNTARAM = 0; 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* 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 //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 //which figures out where to get CHR data from depending on various hack modes
//mostly involving mmc5. //mostly involving mmc5.
@ -414,12 +432,18 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) {
if (PPUCHRRAM & (1 << (tmp >> 10))) if (PPUCHRRAM & (1 << (tmp >> 10)))
VPage[tmp >> 10][tmp] = V; VPage[tmp >> 10][tmp] = V;
} else if (tmp < 0x3F00) { } else if (tmp < 0x3F00) {
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) if (QTAIHack && (qtaintramreg & 1)) {
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; 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 { } else {
if (!(tmp & 3)) { if (!(tmp & 3)) {
if (!(tmp & 0xC)) if (!(tmp & 0xC)) {
PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
PALRAM[0x10] = PALRAM[0x14] = PALRAM[0x18] = PALRAM[0x1C] = V & 0x3F;
}
else else
UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F; UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F;
} else } else
@ -941,8 +965,12 @@ static DECLFW(B2007) {
if (PPUCHRRAM & (1 << (tmp >> 10))) if (PPUCHRRAM & (1 << (tmp >> 10)))
VPage[tmp >> 10][tmp] = V; VPage[tmp >> 10][tmp] = V;
} else if (tmp < 0x3F00) { } else if (tmp < 0x3F00) {
if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) if (QTAIHack && (qtaintramreg & 1)) {
vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; 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 { } else {
if (!(tmp & 3)) { if (!(tmp & 3)) {
if (!(tmp & 0xC)) if (!(tmp & 0xC))
@ -1060,7 +1088,7 @@ static void RefreshLine(int lastpixel) {
uint32 vofs; uint32 vofs;
int X1; int X1;
register uint8 *P = Pline; uint8 *P = Pline;
int lasttile = lastpixel >> 3; int lasttile = lastpixel >> 3;
int numtiles; int numtiles;
static int norecurse = 0; // Yeah, recursion would be bad. static int norecurse = 0; // Yeah, recursion would be bad.
@ -1182,6 +1210,12 @@ static void RefreshLine(int lastpixel) {
#include "pputile.inc" #include "pputile.inc"
} }
#undef PPU_BGFETCH #undef PPU_BGFETCH
} if (QTAIHack) {
#define PPU_VRC5FETCH
for (X1 = firsttile; X1 < lasttile; X1++) {
#include "pputile.inc"
}
#undef PPU_VRC5FETCH
} else { } else {
for (X1 = firsttile; X1 < lasttile; X1++) { for (X1 = firsttile; X1 < lasttile; X1++) {
#include "pputile.inc" #include "pputile.inc"
@ -1627,7 +1661,6 @@ static void RefreshSprites(void) {
} }
static void CopySprites(uint8 *target) { static void CopySprites(uint8 *target) {
uint8 n = ((PPU[1] & 4) ^ 4) << 1;
uint8 *P = target; uint8 *P = target;
if (!spork) return; if (!spork) return;
@ -1635,65 +1668,19 @@ static void CopySprites(uint8 *target) {
if (!rendersprites) return; //User asked to not display sprites. 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); uint8 t = sprlinebuf[i];
if(!(t&0x80))
if (t != 0x80808080) { if (!(t & 0x40) || (P[i] & 0x40)) // Normal sprite || behind bg sprite
#ifdef LSB_FIRST P[i] = t;
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
}
} }
n += 4;
if (n) goto loopskie;
} }
void FCEUPPU_SetVideoSystem(int w) { 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. :/ for (scanline = 0; scanline < totalscanlines; ) { //scanline is incremented in DoLine. Evil. :/
deempcnt[deemp]++; deempcnt[deemp]++;
if (scanline < 240) if (scanline < 240)
DEBUG(FCEUD_UpdatePPUView(scanline, 1)); DEBUG(FCEUD_UpdatePPUView(scanline, 1));
DoLine(); DoLine();
if (scanline < normalscanlines || scanline == totalscanlines) if (scanline < normalscanlines || scanline == totalscanlines)
@ -1900,7 +1889,6 @@ int FCEUPPU_Loop(int skip) {
} else } else
#endif #endif
{ {
FCEU_PutImage();
return(1); 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 //todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory
struct BGData { struct BGData {
struct Record { struct Record {
uint8 nt, pecnt, at, pt[2]; uint8 nt, pecnt, at, pt[2], qtnt;
INLINE void Read() { INLINE void Read() {
NTRefreshAddr = RefreshAddr = ppur.get_ntread(); NTRefreshAddr = RefreshAddr = ppur.get_ntread();
if (PEC586Hack) if (PEC586Hack)
ppur.s = (RefreshAddr & 0x200) >> 9; 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; pecnt = (RefreshAddr & 1) << 3;
nt = CALL_PPUREAD(RefreshAddr); nt = CALL_PPUREAD(RefreshAddr);
runppu(kFetchTime); runppu(kFetchTime);
@ -2029,12 +2021,16 @@ struct BGData {
ppur.par = nt; ppur.par = nt;
RefreshAddr = ppur.get_ptread(); RefreshAddr = ppur.get_ptread();
if (PEC586Hack) { if (PEC586Hack) {
if (ScreenON)
RENDER_LOG(RefreshAddr | pecnt);
pt[0] = CALL_PPUREAD(RefreshAddr | pecnt); pt[0] = CALL_PPUREAD(RefreshAddr | pecnt);
runppu(kFetchTime); runppu(kFetchTime);
pt[1] = CALL_PPUREAD(RefreshAddr | pecnt); pt[1] = CALL_PPUREAD(RefreshAddr | pecnt);
runppu(kFetchTime); runppu(kFetchTime);
} else if (QTAIHack && (qtnt & 0x40)) {
pt[0] = *(CHRptr[0] + RefreshAddr);
runppu(kFetchTime);
RefreshAddr |= 8;
pt[1] = *(CHRptr[0] + RefreshAddr);
runppu(kFetchTime);
} else { } else {
if (ScreenON) if (ScreenON)
RENDER_LOG(RefreshAddr); RENDER_LOG(RefreshAddr);
@ -2139,7 +2135,8 @@ int FCEUX_PPU_Loop(int skip) {
//int xscroll = ppur.fh; //int xscroll = ppur.fh;
//render 241/291 scanlines (1 dummy at beginning, dendy's 50 at the end) //render 241/291 scanlines (1 dummy at beginning, dendy's 50 at the end)
//ignore overclocking! //ignore overclocking!
for (int sl = 0; sl < normalscanlines; sl++) { for (int sl = 0; sl < normalscanlines; sl++)
{
spr_read.start_scanline(); spr_read.start_scanline();
g_rasterpos = 0; g_rasterpos = 0;
@ -2150,7 +2147,8 @@ int FCEUX_PPU_Loop(int skip) {
const int yp = sl - 1; const int yp = sl - 1;
ppuphase = PPUPHASE_BG; 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_UpdatePPUView(scanline = yp, 1));
DEBUG(FCEUD_UpdateNTView(scanline = yp, 1)); DEBUG(FCEUD_UpdateNTView(scanline = yp, 1));
} }
@ -2209,7 +2207,7 @@ int FCEUX_PPU_Loop(int skip) {
{ {
pixel = addr & 0x1F; pixel = addr & 0x1F;
} }
pixelcolor = PALRAM[pixel]; pixelcolor = READPAL_MOTHEROFALL(pixel);
} }
//generate the BG data //generate the BG data
@ -2467,7 +2465,5 @@ int FCEUX_PPU_Loop(int skip) {
} }
finish: finish:
FCEU_PutImage();
return 0; return 0;
} }

View File

@ -48,3 +48,7 @@ enum PPUPHASE {
}; };
extern PPUPHASE 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; uint8 *C;
register uint8 cc; uint8 cc;
uint32 vadr; uint32 vadr;
#ifdef PPU_VRC5FETCH
uint8 tmpd;
#endif
#ifndef PPUT_MMC5SP #ifndef PPUT_MMC5SP
register uint8 zz; uint8 zz;
#else #else
uint8 xs, ys; uint8 xs, ys;
xs = X1; xs = X1;
@ -42,7 +45,11 @@ if (X1 >= 2) {
#else #else
zz = RefreshAddr & 0x1F; zz = RefreshAddr & 0x1F;
C = vnapage[(RefreshAddr >> 10) & 3]; 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 #endif
#ifdef PPUT_HOOK #ifdef PPUT_HOOK
@ -78,7 +85,16 @@ pshift[1] <<= 8;
#elif defined(PPUT_MMC5) #elif defined(PPUT_MMC5)
C = MMC5BGVRAMADR(vadr); C = MMC5BGVRAMADR(vadr);
#else #else
#ifdef PPU_VRC5FETCH
if(tmpd & 0x40)
C = CHRptr[0] + vadr;
else
C = VRAMADR(vadr); C = VRAMADR(vadr);
#else
C = VRAMADR(vadr);
#endif
#endif #endif
#endif #endif
@ -99,12 +115,20 @@ pshift[1] <<= 8;
pshift[1] |= C[0]; pshift[1] |= C[0];
} }
#else #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) if(ScreenON)
RENDER_LOGP(C); RENDER_LOGP(C);
pshift[0] |= C[0]; pshift[0] |= C[0];
if(ScreenON) if(ScreenON)
RENDER_LOGP(C + 8); RENDER_LOGP(C + 8);
pshift[1] |= C[8]; pshift[1] |= C[8];
#endif
#endif #endif
if ((RefreshAddr & 0x1f) == 0x1f) if ((RefreshAddr & 0x1f) == 0x1f)

View File

@ -67,6 +67,7 @@ static int32 RectDutyCount[2];
static uint8 sweepon[2]; static uint8 sweepon[2];
/*static*/ int32 curfreq[2]; /*static*/ int32 curfreq[2];
static uint8 SweepCount[2]; static uint8 SweepCount[2];
static uint8 SweepReload[2];
static uint16 nreg=0; static uint16 nreg=0;
@ -99,7 +100,7 @@ extern const uint32 NoiseFreqTableNTSC[0x10] =
extern const uint32 NoiseFreqTablePAL[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 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++) { for (int dpcmstart = i; dpcmstart < (i + dpcmsize); dpcmstart++) {
if(!(cdloggerdata[dpcmstart] & 0x40)) { if(!(cdloggerdata[dpcmstart] & 0x40)) {
cdloggerdata[dpcmstart] |= 0x40; cdloggerdata[dpcmstart] |= 0x40;
cdloggerdata[dpcmstart] |= (romaddress >> 11) & 0x0c;
if(!(cdloggerdata[dpcmstart] & 2)){ if(!(cdloggerdata[dpcmstart] & 2)){
datacount++; datacount++;
@ -206,22 +208,15 @@ void LogDPCM(int romaddress, int dpcmsize){
static void SQReload(int x, uint8 V) static void SQReload(int x, uint8 V)
{ {
if(EnabledChannels&(1<<x)) if(EnabledChannels&(1<<x))
{ lengthcount[x]=lengthtable[(V>>3)&0x1f];
if(x)
DoSQ2();
else
DoSQ1();
lengthcount[x]=lengthtable[(V>>3)&0x1f];
}
sweepon[x]=PSG[(x<<2)|1]&0x80; /* use the low 8 bits data from pulse period
curfreq[x]=PSG[(x<<2)|0x2]|((V&7)<<8); * instead of from the sweep period */
SweepCount[x]=((PSG[(x<<2)|0x1]>>4)&7)+1; /* https://forums.nesdev.com/viewtopic.php?t=219&p=1431 */
curfreq[x]=(curfreq[x] & 0xff)|((V&7)<<8);
RectDutyCount[x]=7; RectDutyCount[x]=7;
EnvUnits[x].reloaddec=1; EnvUnits[x].reloaddec=1;
//reloadfreq[x]=1;
} }
static DECLFW(Write_PSG) static DECLFW(Write_PSG)
@ -237,7 +232,9 @@ static DECLFW(Write_PSG)
V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1);
break; break;
case 0x1: case 0x1:
DoSQ1();
sweepon[0]=V&0x80; sweepon[0]=V&0x80;
SweepReload[0]=1;
break; break;
case 0x2: case 0x2:
DoSQ1(); DoSQ1();
@ -245,6 +242,7 @@ static DECLFW(Write_PSG)
curfreq[0]|=V; curfreq[0]|=V;
break; break;
case 0x3: case 0x3:
DoSQ1();
SQReload(0,V); SQReload(0,V);
break; break;
case 0x4: case 0x4:
@ -255,7 +253,9 @@ static DECLFW(Write_PSG)
V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1);
break; break;
case 0x5: case 0x5:
DoSQ2();
sweepon[1]=V&0x80; sweepon[1]=V&0x80;
SweepReload[1]=1;
break; break;
case 0x6: case 0x6:
DoSQ2(); DoSQ2();
@ -263,6 +263,7 @@ static DECLFW(Write_PSG)
curfreq[1]|=V; curfreq[1]|=V;
break; break;
case 0x7: case 0x7:
DoSQ2();
SQReload(1,V); SQReload(1,V);
break; break;
case 0xa: case 0xa:
@ -421,44 +422,28 @@ static void FrameSoundStuff(int V)
/* Frequency Sweep Code Here */ /* Frequency Sweep Code Here */
/* xxxx 0000 */ /* xxxx 0000 */
/* xxxx = hz. 120/(x+1)*/ /* 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; int sweepShift = (PSG[(P << 2) + 0x1] & 7);
if (sweepon[P] && sweepShift && curfreq[P] >= 8)
if(SweepCount[P]>0) SweepCount[P]--;
if(SweepCount[P]<=0)
{ {
SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1; int32 mod = (curfreq[P] >> sweepShift);
if(PSG[(P<<2)+0x1]&0x8) if (PSG[(P << 2) + 0x1] & 0x8)
{ curfreq[P] -= (mod + (P ^ 1));
mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7)); else if ((mod + curfreq[P]) < 0x800)
if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/) curfreq[P] += mod;
{
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;
}
}
}
} }
SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1);
} }
else /* Sweeping is disabled: */
if (SweepReload[P])
{ {
//curfreq[P]&=0xFF00; SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1);
//curfreq[P]|=PSG[(P<<2)|0x2]; //|((PSG[(P<<2)|3]&7)<<8); SweepReload[P] = 0;
} }
} }
} }
@ -579,9 +564,10 @@ void FCEU_SoundCPUHook(int cycles)
/* Unbelievably ugly hack */ /* Unbelievably ugly hack */
if(FSettings.SndRate) if(FSettings.SndRate)
{ {
soundtsoffs+=DMCacc; const uint32 fudge = std::min<uint32>(-DMCacc, soundtsoffs + timestamp);
DoPCM(); soundtsoffs -= fudge;
soundtsoffs-=DMCacc; DoPCM();
soundtsoffs += fudge;
} }
RawDALatch+=t; RawDALatch+=t;
if(RawDALatch&0x80) if(RawDALatch&0x80)
@ -1096,8 +1082,9 @@ int FlushEmulateSound(void)
SexyFilter(Wave,WaveFinal,end>>4); SexyFilter(Wave,WaveFinal,end>>4);
//if(FSettings.lowpass) if(FSettings.lowpass)
// SexyFilter2(WaveFinal,end>>4); SexyFilter2(WaveFinal,end>>4);
if(end&0xF) if(end&0xF)
Wave[0]=Wave[(end>>4)]; Wave[0]=Wave[(end>>4)];
Wave[end>>4]=0; Wave[end>>4]=0;

View File

@ -43,8 +43,9 @@
#endif #endif
//TODO - we really need some kind of global platform-specific options api //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/main.h"
#include "drivers/win/cheat.h"
#include "drivers/win/ram_search.h" #include "drivers/win/ram_search.h"
#include "drivers/win/ramwatch.h" #include "drivers/win/ramwatch.h"
#endif #endif
@ -60,14 +61,14 @@
using namespace std; using namespace std;
static void (*SPreSave)(void); static void (*SPreSave)(void) = NULL;
static void (*SPostSave)(void); static void (*SPostSave)(void) = NULL;
static int SaveStateStatus[10]; static int SaveStateStatus[10];
static int StateShow; static int StateShow;
//tells the save system innards that we're loading the old format //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) 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 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? //MBG TODO - can this be moved to a better place?
//does it even make sense, displaying XBuf when its XBackBuf we just loaded? //does it even make sense, displaying XBuf when its XBackBuf we just loaded?
#ifdef WIN32 #ifdef __WIN_DRIVER__
else else
{ {
FCEUD_BlitScreen(XBuf); FCEUD_BlitScreen(XBuf);
@ -412,7 +413,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel)
if(SPreSave) SPreSave(); if(SPreSave) SPreSave();
totalsize+=WriteStateChunk(os,0x10,SFMDATA); totalsize+=WriteStateChunk(os,0x10,SFMDATA);
if(SPreSave) SPostSave(); if(SPostSave) SPostSave();
//save the length of the file //save the length of the file
int len = memory_savestate.size(); int len = memory_savestate.size();
@ -794,7 +795,7 @@ bool FCEUSS_Load(const char *fname, bool display_message)
} }
#endif #endif
#ifdef WIN32 #ifdef __WIN_DRIVER__
Update_RAM_Search(); // Update_RAM_Watch() is also called. Update_RAM_Search(); // Update_RAM_Watch() is also called.
#endif #endif
@ -847,7 +848,7 @@ void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
for(x=0;x<SFEXINDEX;x++) for(x=0;x<SFEXINDEX;x++)
{ {
if(SFMDATA[x].desc) 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 // 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; SFMDATA[0].s = 0;
@ -857,8 +858,11 @@ void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
SFEXINDEX=0; 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) if(s==~0)
{ {
SFORMAT* sf = (SFORMAT*)v; SFORMAT* sf = (SFORMAT*)v;
@ -884,8 +888,8 @@ void AddExState(void *v, uint32 s, int type, char *desc)
if(desc) if(desc)
{ {
SFMDATA[SFEXINDEX].desc=(char *)FCEU_malloc(strlen(desc)+1); SFMDATA[SFEXINDEX].desc=(const char *)FCEU_malloc(strlen(desc)+1);
strcpy(SFMDATA[SFEXINDEX].desc,desc); strcpy( (char*)SFMDATA[SFEXINDEX].desc,desc);
} }
else else
SFMDATA[SFEXINDEX].desc=0; SFMDATA[SFEXINDEX].desc=0;
@ -917,8 +921,8 @@ void FCEUI_SelectStateNext(int n)
int FCEUI_SelectState(int w, int show) int FCEUI_SelectState(int w, int show)
{ {
FCEUSS_CheckStates();
int oldstate=CurrentState; int oldstate=CurrentState;
FCEUSS_CheckStates();
if(w == -1) { StateShow = 0; return 0; } //mbg merge 7/17/06 had to make return a value if(w == -1) { StateShow = 0; return 0; } //mbg merge 7/17/06 had to make return a value
CurrentState=w; CurrentState=w;

View File

@ -44,11 +44,11 @@ struct SFORMAT
uint32 s; uint32 s;
//a string description of the element //a string description of the element
char *desc; const char *desc;
}; };
void ResetExState(void (*PreSave)(void),void (*PostSave)(void)); 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 //indicates that the value is a multibyte integer that needs to be put in the correct byte order
#define FCEUSTATE_RLSB 0x80000000 #define FCEUSTATE_RLSB 0x80000000

View File

@ -131,6 +131,10 @@ typedef uint32_t uint32;
#endif #endif
#if defined(WIN32) && !defined(__QT_DRIVER__)
#define __WIN_DRIVER__
#endif
typedef void (*writefunc)(uint32 A, uint8 V); typedef void (*writefunc)(uint32 A, uint8 V);
typedef uint8 (*readfunc)(uint32 A); typedef uint8 (*readfunc)(uint32 A);

View File

@ -45,13 +45,13 @@ typedef struct {
} UNIF_HEADER; } UNIF_HEADER;
typedef struct { typedef struct {
char *name; const char *name;
void (*init)(CartInfo *); void (*init)(CartInfo *);
int flags; int flags;
} BMAPPING; } BMAPPING;
typedef struct { typedef struct {
char *name; const char *name;
int (*init)(FCEUFILE *fp); int (*init)(FCEUFILE *fp);
} BFMAPPING; } BFMAPPING;
@ -133,7 +133,7 @@ static int DoMirroring(FCEUFILE *fp) {
return(0); return(0);
mirrortodo = t; 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) if (t < 6)
FCEU_printf(" Name/Attribute Table Mirroring: %s\n", stuffo[t]); 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 by: %s\n", name);
FCEU_printf(" Dumped with: %s\n", method); FCEU_printf(" Dumped with: %s\n", method);
{ {
char *months[12] = { const char *months[12] = {
"January", "February", "March", "April", "May", "June", "July", "January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December" "August", "September", "October", "November", "December"
}; };
@ -236,7 +236,7 @@ static int TVCI(FCEUFILE *fp) {
if ((t = FCEU_fgetc(fp)) == EOF) if ((t = FCEU_fgetc(fp)) == EOF)
return(0); return(0);
if (t <= 2) { if (t <= 2) {
char *stuffo[3] = { "NTSC", "PAL", "NTSC and PAL" }; const char *stuffo[3] = { "NTSC", "PAL", "NTSC and PAL" };
if (t == 0) { if (t == 0) {
GameInfo->vidsys = GIV_NTSC; GameInfo->vidsys = GIV_NTSC;
FCEUI_SetVidSystem(0); FCEUI_SetVidSystem(0);
@ -372,7 +372,7 @@ static BMAPPING bmap[] = {
{ "H2288", UNLH2288_Init, 0 }, { "H2288", UNLH2288_Init, 0 },
{ "HKROM", HKROM_Init, 0 }, { "HKROM", HKROM_Init, 0 },
{ "KOF97", UNLKOF97_Init, 0 }, { "KOF97", UNLKOF97_Init, 0 },
{ "KONAMI-QTAI", Mapper190_Init, 0 }, { "KONAMI-QTAI", QTAi_Init, 0 },
{ "KS7010", UNLKS7010_Init, 0 }, { "KS7010", UNLKS7010_Init, 0 },
{ "KS7012", UNLKS7012_Init, 0 }, { "KS7012", UNLKS7012_Init, 0 },
{ "KS7013B", UNLKS7013B_Init, 0 }, { "KS7013B", UNLKS7013B_Init, 0 },
@ -475,6 +475,10 @@ static BMAPPING bmap[] = {
{ "8-IN-1", BMC8IN1_Init, 0 }, { "8-IN-1", BMC8IN1_Init, 0 },
{ "80013-B", BMC80013B_Init, 0 }, { "80013-B", BMC80013B_Init, 0 },
{ "HPxx", BMCHPxx_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 } { 0, 0, 0 }
}; };
@ -539,23 +543,22 @@ static int InitializeBoard(void) {
CHRRAMSize = 256; CHRRAMSize = 256;
else else
CHRRAMSize = 8; CHRRAMSize = 8;
CHRRAMSize <<= 10; CHRRAMSize <<= 10;
if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) { if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) {
SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1); SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1);
AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR"); AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR");
} else } else
return(-1); return 2;
} }
if (bmap[x].flags & BMCFLAG_FORCE4) if (bmap[x].flags & BMCFLAG_FORCE4)
mirrortodo = 4; mirrortodo = 4;
MooMirroring(); MooMirroring();
bmap[x].init(&UNIFCart); bmap[x].init(&UNIFCart);
return(1); return 0;
} }
x++; x++;
} }
FCEU_PrintError("Board type not supported."); return 1;
return(0);
} }
static void UNIFGI(GI h) { static void UNIFGI(GI h) {
@ -588,53 +591,58 @@ int UNIFLoad(const char *name, FCEUFILE *fp) {
FCEU_fseek(fp, 0, SEEK_SET); FCEU_fseek(fp, 0, SEEK_SET);
FCEU_fread(&unhead, 1, 4, fp); FCEU_fread(&unhead, 1, 4, fp);
if (memcmp(&unhead, "UNIF", 4)) if (memcmp(&unhead, "UNIF", 4))
return 0; return LOADER_INVALID_FORMAT;
ResetCartMapping(); ResetCartMapping();
ResetExState(0, 0); ResetExState(0, 0);
ResetUNIF(); ResetUNIF();
if (!FCEU_read32le(&unhead.info, fp)) if (!FCEU_read32le(&unhead.info, fp)
goto aborto; || (FCEU_fseek(fp, 0x20, SEEK_SET) < 0)
if (FCEU_fseek(fp, 0x20, SEEK_SET) < 0) || !LoadUNIFChunks(fp))
goto aborto;
if (!LoadUNIFChunks(fp))
goto aborto;
{ {
int x; FreeUNIF();
struct md5_context md5; ResetUNIF();
FCEU_PrintError("Error reading UNIF ROM image.");
md5_starts(&md5); return LOADER_HANDLED_ERROR;
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));
} }
if (!InitializeBoard()) struct md5_context md5;
goto aborto; 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 #ifndef GEKKO
FCEU_LoadGameSave(&UNIFCart); FCEU_LoadGameSave(&UNIFCart);
#endif #endif
strcpy(LoadedRomFName, name); //For the debugger list strcpy(LoadedRomFName, name); //For the debugger list
GameInterface = UNIFGI; GameInterface = UNIFGI;
currCartInfo = &UNIFCart; currCartInfo = &UNIFCart;
return 1; return LOADER_OK;
aborto:
FreeUNIF();
ResetUNIF();
return 0;
} }

View File

@ -51,7 +51,7 @@ void EKROM_Init(CartInfo *info);
void ELROM_Init(CartInfo *info); void ELROM_Init(CartInfo *info);
void ETROM_Init(CartInfo *info); void ETROM_Init(CartInfo *info);
void EWROM_Init(CartInfo *info); void EWROM_Init(CartInfo *info);
void GNROM_Init(CartInfo *info); //void GNROM_Init(CartInfo *info);
void HKROM_Init(CartInfo *info); void HKROM_Init(CartInfo *info);
void LE05_Init(CartInfo *info); void LE05_Init(CartInfo *info);
void LH10_Init(CartInfo *info); void LH10_Init(CartInfo *info);
@ -59,7 +59,7 @@ void LH32_Init(CartInfo *info);
void LH53_Init(CartInfo *info); void LH53_Init(CartInfo *info);
void MALEE_Init(CartInfo *info); void MALEE_Init(CartInfo *info);
void MHROM_Init(CartInfo *info); void MHROM_Init(CartInfo *info);
void Mapper190_Init(CartInfo *info); void QTAi_Init(CartInfo *info);
void NROM_Init(CartInfo *info); void NROM_Init(CartInfo *info);
void Novel_Init(CartInfo *info); void Novel_Init(CartInfo *info);
void S74LS374NA_Init(CartInfo *info); void S74LS374NA_Init(CartInfo *info);
@ -158,6 +158,11 @@ void BMC810131C_Init(CartInfo *info);
void BMC8IN1_Init(CartInfo *info); void BMC8IN1_Init(CartInfo *info);
void BMC80013B_Init(CartInfo *info); void BMC80013B_Init(CartInfo *info);
void BMCHPxx_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 extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM
// bank switcherooing with certain boards... // bank switcherooing with certain boards...

View File

@ -275,7 +275,7 @@ int write64le(uint64 b, EMUFILE* os)
int read32le(uint32 *Bufo, EMUFILE *fp) int read32le(uint32 *Bufo, EMUFILE *fp)
{ {
uint32 buf; uint32 buf=0;
if(fp->_fread(&buf,4)<4) if(fp->_fread(&buf,4)<4)
return 0; return 0;
#ifdef LOCAL_LE #ifdef LOCAL_LE
@ -288,7 +288,7 @@ int read32le(uint32 *Bufo, EMUFILE *fp)
int read16le(u16 *Bufo, EMUFILE *is) int read16le(u16 *Bufo, EMUFILE *is)
{ {
u16 buf; u16 buf=0;
if(is->_fread((char*)&buf,2) != 2) if(is->_fread((char*)&buf,2) != 2)
return 0; return 0;
#ifdef LOCAL_LE #ifdef LOCAL_LE
@ -301,7 +301,7 @@ int read16le(u16 *Bufo, EMUFILE *is)
int read64le(uint64 *Bufo, EMUFILE *is) int read64le(uint64 *Bufo, EMUFILE *is)
{ {
uint64 buf; uint64 buf=0;
if(is->_fread((char*)&buf,8) != 8) if(is->_fread((char*)&buf,8) != 8)
return 0; return 0;
#ifdef LOCAL_LE #ifdef LOCAL_LE

View File

@ -28,10 +28,10 @@ uint32 uppow2(uint32 n)
int x; int x;
for(x=31;x>=0;x--) for(x=31;x>=0;x--)
if(n&(1<<x)) if(n&(1u<<x))
{ {
if((1<<x)!=n) if((1u<<x)!=n)
return(1<<(x+1)); return(1u<<(x+1));
break; break;
} }
return n; return n;

View File

@ -157,7 +157,7 @@ int chr_replace(char *str, char search, char replace) {
///Replaces all instances of 'search' with 'replace' ///Replaces all instances of 'search' with 'replace'
///Returns number of sub-strings modified, or -1 on error ///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 unsigned int i=0,j=0; //mbg merge 7/17/06 changed to unsigned int
int searchlen,replacelen; int searchlen,replacelen;
char *astr; char *astr;
@ -580,7 +580,7 @@ std::string mass_replace(const std::string &source, const std::string &victim, c
return answer; 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 //http://www.codeproject.com/KB/string/UtfConverter.aspx
#include "ConvertUTF.h" #include "ConvertUTF.h"
namespace UtfConverter namespace UtfConverter
@ -752,7 +752,7 @@ std::wstring mbstowcs(std::string str) // UTF8->UTF32
{ {
try { try {
return UtfConverter::FromUtf8(str); return UtfConverter::FromUtf8(str);
} catch(std::exception) { } catch(std::exception &e) {
return L"(failed UTF-8 conversion)"; 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_rtrim(char *str, int flags);
int str_strip(char *str, int flags); int str_strip(char *str, int flags);
int chr_replace(char *str, char search, char replace); 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 HexStringToBytesLength(const std::string& str);
int Base64StringToBytesLength(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 getExtension(const char* input);
std::string StripExtension(std::string filename); 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 #define __FCEU_VERSION
//todo - everyone will want to support this eventually, i suppose //todo - everyone will want to support this eventually, i suppose
#ifdef _MSC_VER #if defined(_MSC_VER) && !defined(__QT_DRIVER__)
#include "scmrev.h" #include "scmrev.h"
#else #else
#ifdef SVN_REV #ifdef SVN_REV
@ -60,8 +60,16 @@
#define FCEU_COMPILER_DETAIL "" #define FCEU_COMPILER_DETAIL ""
#endif #endif
#define FCEU_VERSION_NUMERIC 22020 #define FCEU_VERSION_MAJOR 2
#define FCEU_VERSION_STRING "2.2.3" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER #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 #define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING
#endif #endif

View File

@ -37,7 +37,7 @@
#include "fceulua.h" #include "fceulua.h"
#endif #endif
#ifdef WIN32 #ifdef __WIN_DRIVER__
#include "drivers/win/common.h" //For DirectX constants #include "drivers/win/common.h" //For DirectX constants
#include "drivers/win/input.h" #include "drivers/win/input.h"
#endif #endif
@ -72,6 +72,8 @@ static u8 *xbsave=NULL;
GUIMESSAGE guiMessage; GUIMESSAGE guiMessage;
GUIMESSAGE subtitleMessage; GUIMESSAGE subtitleMessage;
bool vidGuiMsgEna = true;
//for input display //for input display
extern int input_display; extern int input_display;
extern uint32 cur_input_display; extern uint32 cur_input_display;
@ -87,23 +89,23 @@ std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
void FCEU_KillVirtualVideo(void) void FCEU_KillVirtualVideo(void)
{ {
//mbg merge TODO 7/17/06 temporarily removed if ( XBuf )
//if(xbsave) {
//{ FCEU_free(XBuf); XBuf = NULL;
// free(xbsave); }
// xbsave=0; if ( XBackBuf )
//} {
//if(XBuf) FCEU_free(XBackBuf); XBackBuf = NULL;
//{ }
//UnmapViewOfFile(XBuf); if ( XDBuf )
//CloseHandle(mapXBuf); {
//mapXBuf=NULL; FCEU_free(XDBuf); XDBuf = NULL;
//} }
//if(XBackBuf) if ( XDBackBuf )
//{ {
// free(XBackBuf); FCEU_free(XDBackBuf); XDBackBuf = NULL;
// XBackBuf=0; }
//} //printf("Video Core Cleanup\n");
} }
/** /**
@ -178,6 +180,31 @@ static void ReallySnap(void)
FCEU_DispMessage("Screen snapshot %d saved.",0,x-1); 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) void FCEU_PutImage(void)
{ {
if(dosnapsave==2) //Save screenshot as, currently only flagged & run by the Win32 build. //TODO SDL: implement this? 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 //Fancy input display code
if(input_display) if(input_display)
{ {
extern uint32 JSAutoHeld;
uint32 held;
int controller, c, ci, color;
int i, j; 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* uint8 *t = XBuf+(FSettings.LastSLine-9)*256 + 20; //mbg merge 7/17/06 changed t to uint8*
if(input_display > 4) input_display = 4; 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(i = 0; i < 34;i++)
for(j = 0; j <9 ; j++) for(j = 0; j <9 ; j++)
@ -267,33 +284,28 @@ void FCEU_PutImage(void)
for(i = 3; i < 6; i++) for(i = 3; i < 6; i++)
for(j = 3; j< 6; j++) for(j = 3; j< 6; j++)
t[i+j*256] = 0xCF; 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. // This doesn't work in anything except windows for now.
// It doesn't get set anywhere in other ports. // It doesn't get set anywhere in other ports.
#ifdef WIN32 if (!oldInputDisplay)
if (!oldInputDisplay) ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0:GetGamepadPressedImmediate() >> (controller * 8); ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0 : GetGamepadPressedImmediate() >> (controller * 8);
else ci = 0;
if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY)) held = (JSAutoHeld >> (controller * 8)); if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY))
else held = 0; held = (JSAutoHeld >> (controller * 8));
#else #else
// Put other port info here // Put other port info here
ci = 0;
held = 0;
#endif #endif
//adelikat: I apologize to anyone who ever sifts through this color assignment //adelikat: I apologize to anyone who ever sifts through this color assignment
//A //A
if (held&1) { //If auto-hold color = GetButtonColor(held, c, ci, 0);
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;
}
for(i=0; i < 4; i++) for(i=0; i < 4; i++)
{ {
for(j = 0; j < 4; j++) for(j = 0; j < 4; j++)
@ -304,15 +316,7 @@ void FCEU_PutImage(void)
} }
} }
//B //B
if (held&2) { //If auto-hold color = GetButtonColor(held, c, ci, 1);
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;
}
for(i=0; i < 4; i++) for(i=0; i < 4; i++)
{ {
for(j = 0; j < 4; j++) for(j = 0; j < 4; j++)
@ -323,45 +327,21 @@ void FCEU_PutImage(void)
} }
} }
//Select //Select
if (held&4) { //If auto-hold color = GetButtonColor(held, c, ci, 2);
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;
}
for(i = 0; i < 4; i++) for(i = 0; i < 4; i++)
{ {
t[11+5*256+i] = color; t[11+5*256+i] = color;
t[11+6*256+i] = color; t[11+6*256+i] = color;
} }
//Start //Start
if (held&8) { //If auto-hold color = GetButtonColor(held, c, ci, 3);
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;
}
for(i = 0; i < 4; i++) for(i = 0; i < 4; i++)
{ {
t[17+5*256+i] = color; t[17+5*256+i] = color;
t[17+6*256+i] = color; t[17+6*256+i] = color;
} }
//Up //Up
if (held&16) { //If auto-hold color = GetButtonColor(held, c, ci, 4);
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;
}
for(i = 0; i < 3; i++) for(i = 0; i < 3; i++)
{ {
for(j = 0; j < 3; j++) for(j = 0; j < 3; j++)
@ -370,15 +350,7 @@ void FCEU_PutImage(void)
} }
} }
//Down //Down
if (held&32) { //If auto-hold color = GetButtonColor(held, c, ci, 5);
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;
}
for(i = 0; i < 3; i++) for(i = 0; i < 3; i++)
{ {
for(j = 0; j < 3; j++) for(j = 0; j < 3; j++)
@ -387,15 +359,7 @@ void FCEU_PutImage(void)
} }
} }
//Left //Left
if (held&64) { //If auto-hold color = GetButtonColor(held, c, ci, 6);
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;
}
for(i = 0; i < 3; i++) for(i = 0; i < 3; i++)
{ {
for(j = 0; j < 3; j++) for(j = 0; j < 3; j++)
@ -404,15 +368,7 @@ void FCEU_PutImage(void)
} }
} }
//Right //Right
if (held&128) { //If auto-hold color = GetButtonColor(held, c, ci, 7);
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;
}
for(i = 0; i < 3; i++) for(i = 0; i < 3; i++)
{ {
for(j = 0; j < 3; j++) for(j = 0; j < 3; j++)
@ -444,7 +400,7 @@ void snapAVI()
FCEUI_AviVideoUpdate(XBuf); FCEUI_AviVideoUpdate(XBuf);
} }
void FCEU_DispMessageOnMovie(char *format, ...) void FCEU_DispMessageOnMovie(const char *format, ...)
{ {
va_list ap; va_list ap;
@ -452,7 +408,10 @@ void FCEU_DispMessageOnMovie(char *format, ...)
vsnprintf(guiMessage.errmsg,sizeof(guiMessage.errmsg),format,ap); vsnprintf(guiMessage.errmsg,sizeof(guiMessage.errmsg),format,ap);
va_end(ap); va_end(ap);
guiMessage.howlong = 180; if ( vidGuiMsgEna )
{
guiMessage.howlong = 180;
}
guiMessage.isMovieMessage = true; guiMessage.isMovieMessage = true;
guiMessage.linesFromBottom = 0; guiMessage.linesFromBottom = 0;
@ -460,7 +419,7 @@ void FCEU_DispMessageOnMovie(char *format, ...)
guiMessage.howlong = 0; guiMessage.howlong = 0;
} }
void FCEU_DispMessage(char *format, int disppos=0, ...) void FCEU_DispMessage(const char *format, int disppos=0, ...)
{ {
va_list ap; va_list ap;
@ -475,7 +434,10 @@ void FCEU_DispMessage(char *format, int disppos=0, ...)
strcat(temp, "\n"); strcat(temp, "\n");
FCEU_printf(temp); FCEU_printf(temp);
guiMessage.howlong = 180; if ( vidGuiMsgEna )
{
guiMessage.howlong = 180;
}
guiMessage.isMovieMessage = false; guiMessage.isMovieMessage = false;
guiMessage.linesFromBottom = disppos; 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; uint32 crc;
@ -631,7 +593,7 @@ int SaveSnapshot(void)
dest++; dest++;
for(x=256;x;x--) for(x=256;x;x--)
{ {
u32 color = ModernDeemphColorMap(tmp,XBuf,1,1); u32 color = ModernDeemphColorMap(tmp,XBuf,1);
*dest++=(color>>0x10)&0xFF; *dest++=(color>>0x10)&0xFF;
*dest++=(color>>0x08)&0xFF; *dest++=(color>>0x08)&0xFF;
*dest++=(color>>0x00)&0xFF; *dest++=(color>>0x00)&0xFF;
@ -774,29 +736,54 @@ bool FCEUI_ShowFPS()
} }
void FCEUI_SetShowFPS(bool showFPS) void FCEUI_SetShowFPS(bool showFPS)
{ {
if ( Show_FPS != showFPS )
{
ResetFPS();
}
Show_FPS = showFPS; Show_FPS = showFPS;
} }
void FCEUI_ToggleShowFPS() void FCEUI_ToggleShowFPS()
{ {
Show_FPS ^= 1; Show_FPS ^= 1;
ResetFPS();
} }
static uint64 boop[60]; static uint64 boop_ts = 0;
static int boopcount = 0; static unsigned int boopcount = 0;
void ResetFPS(void)
{
boop_ts = 0;
boopcount = 0;
}
void ShowFPS(void) void ShowFPS(void)
{ {
#ifndef GEKKO #ifndef GEKKO
if(Show_FPS == false) if (Show_FPS == false)
{
return; return;
uint64 da = FCEUD_GetTime() - boop[boopcount]; }
char fpsmsg[16]; static char fpsmsg[16] = { 0 };
int booplimit = PAL?50:60; uint64 ts = FCEUD_GetTime();
boop[boopcount] = 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); 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 #endif
} }

View File

@ -12,7 +12,8 @@ extern uint8 *XBackBuf;
extern uint8 *XDBuf; extern uint8 *XDBuf;
extern uint8 *XDBackBuf; extern uint8 *XDBackBuf;
extern int ClipSidesOffset; extern int ClipSidesOffset;
extern struct GUIMESSAGE
struct GUIMESSAGE
{ {
//countdown for gui messages //countdown for gui messages
int howlong; int howlong;
@ -26,10 +27,21 @@ extern struct GUIMESSAGE
//in case of multiple lines, allow one to move the message //in case of multiple lines, allow one to move the message
int linesFromBottom; int linesFromBottom;
} guiMessage; // constructor
GUIMESSAGE(void)
{
howlong = 0;
linesFromBottom = 0;
isMovieMessage = false;
errmsg[0] = 0;
}
};
extern GUIMESSAGE guiMessage;
extern GUIMESSAGE subtitleMessage; extern GUIMESSAGE subtitleMessage;
extern bool vidGuiMsgEna;
void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur); void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur);
std::string FCEUI_GetSnapshotAsName(); std::string FCEUI_GetSnapshotAsName();
@ -37,6 +49,7 @@ void FCEUI_SetSnapshotAsName(std::string name);
bool FCEUI_ShowFPS(); bool FCEUI_ShowFPS();
void FCEUI_SetShowFPS(bool showFPS); void FCEUI_SetShowFPS(bool showFPS);
void FCEUI_ToggleShowFPS(); void FCEUI_ToggleShowFPS();
void ShowFPS(); void ShowFPS(void);
void snapAVI(); void ResetFPS(void);
void snapAVI(void);
#endif #endif

View File

@ -35,7 +35,7 @@
#define IOPTION_PREDIP 0x10 #define IOPTION_PREDIP 0x10
typedef struct { typedef struct {
char *name; const char *name;
uint64 md5partial; uint64 md5partial;
int mapper; int mapper;
int mirroring; int mirroring;
@ -102,10 +102,10 @@ void FCEU_VSUniCoin(void) {
static int curppu; static int curppu;
static int64 curmd5; static int64 curmd5;
#define RP2C04_001 1 #define RP2C04_0001 1
#define RP2C04_002 2 #define RP2C04_0002 2
#define RP2C04_003 3 #define RP2C04_0003 3
#define RP2C05_004 4 #define RP2C04_0004 4
#define RCP2C03B 5 #define RCP2C03B 5
#define RC2C05_01 6 #define RC2C05_01 6
#define RC2C05_02 7 #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 /* Games/PPU list. Information copied from MAME. ROMs are exchangable, so don't take
this list as "this game must use this PPU". this list as "this game must use this PPU".
RP2C04-001: RP2C04-0001:
- Baseball - Baseball
- Freedom Force - Freedom Force
- Gradius - Gradius
@ -202,7 +202,7 @@ RP2C04-001:
- Platoon - Platoon
- Super Xevious - Super Xevious
RP2C04-002: RP2C04-0002:
- Castlevania - Castlevania
- Ladies golf - Ladies golf
- Mach Rider (Endurance Course) - Mach Rider (Endurance Course)
@ -211,21 +211,21 @@ RP2C04-002:
- Stroke N' Match Golf - Stroke N' Match Golf
- Wrecking Crew - Wrecking Crew
RP2C04-003: RP2C04-0003:
- Dr mario - Dr. Mario
- Excite Bike - Excite Bike
- Goonies - Goonies
- Soccer - Soccer
- TKO Boxing - TKO Boxing
RP2c05-004: RP2C04-0004:
- Clu Clu Land - Clu Clu Land
- Excite Bike (Japan) - Excite Bike (Japan)
- Ice Climber - Ice Climber
- Ice Climber Dual (Japan) - Ice Climber Dual (Japan)
- Super Mario Bros. - Super Mario Bros.
Rcp2c03b: RCP2C03B:
- Battle City - Battle City
- Duck Hunt - Duck Hunt
- Mahjang - Mahjang
@ -252,47 +252,47 @@ RC2C05-04:
VSUNIENTRY VSUniGames[] = VSUNIENTRY VSUniGames[] =
{ {
{ "Baseball", 0x691d4200ea42be45LL, 99, 2, RP2C04_001, 0 }, { "Baseball", 0x691d4200ea42be45LL, 99, 2, RP2C04_0001, 0 },
{ "Battle City", 0x8540949d74c4d0ebLL, 99, 2, RP2C04_001, 0 }, { "Battle City", 0x8540949d74c4d0ebLL, 99, 2, RP2C04_0001, 0 },
{ "Battle City(Bootleg)", 0x8093cbe7137ac031LL, 99, 2, RP2C04_001, 0 }, { "Battle City(Bootleg)", 0x8093cbe7137ac031LL, 99, 2, RP2C04_0001, 0 },
{ "Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB }, { "Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB },
{ "Dr Mario", 0xe1af09c477dc0081LL, 1, 0, RP2C04_003, IOPTION_SWAPDIRAB }, { "Dr Mario", 0xe1af09c477dc0081LL, 1, 0, RP2C04_0003, IOPTION_SWAPDIRAB },
{ "Duck Hunt", 0x47735d1e5f1205bbLL, 99, 2, RCP2C03B, IOPTION_GUN }, { "Duck Hunt", 0x47735d1e5f1205bbULL, 99, 2, RCP2C03B, IOPTION_GUN },
{ "Excitebike", 0x3dcd1401bcafde77LL, 99, 2, RP2C04_003, 0 }, { "Excitebike", 0x3dcd1401bcafde77LL, 99, 2, RP2C04_0003, 0 },
{ "Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2, RP2C05_004, 0 }, { "Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2, RP2C04_0004, 0 },
{ "Freedom Force", 0xed96436bd1b5e688LL, 4, 0, RP2C04_001, IOPTION_GUN }, /* Wrong color in game select screen? */ { "Freedom Force", 0xed96436bd1b5e688LL, 4, 0, RP2C04_0001, IOPTION_GUN }, /* Wrong color in game select screen? */
{ "Stroke and Match Golf", 0x612325606e82bc66LL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 }, { "Stroke and Match Golf", 0x612325606e82bc66LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 },
{ "Goonies", 0xb4032d694e1d2733LL, 151, 1, RP2C04_003, 0 }, { "Goonies", 0xb4032d694e1d2733LL, 151, 1, RP2C04_0003, 0 },
{ "Gradius", 0x50687ae63bdad976LL, 151, 1, RP2C04_001, IOPTION_SWAPDIRAB }, { "Gradius", 0x50687ae63bdad976LL, 151, 1, RP2C04_0001, IOPTION_SWAPDIRAB },
{ "Gumshoe", 0x87161f8ee37758d3LL, 99, 2, RC2C05_03, IOPTION_GUN }, { "Gumshoe", 0x87161f8ee37758d3ULL, 99, 2, RC2C05_03, IOPTION_GUN },
{ "Gumshoe", 0xb8500780bf69ce29LL, 99, 2, RC2C05_03, IOPTION_GUN }, { "Gumshoe", 0xb8500780bf69ce29ULL, 99, 2, RC2C05_03, IOPTION_GUN },
{ "Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_001, IOPTION_GUN }, { "Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_0001, IOPTION_GUN },
{ "Ice Climber", 0xd21e999513435e2aLL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB }, { "Ice Climber", 0xd21e999513435e2aLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB },
{ "Ladies Golf", 0x781b24be57ef6785LL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, { "Ladies Golf", 0x781b24be57ef6785LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
{ "Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_002, 0 }, { "Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_0002, 0 },
{ "Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_001, 0 }, { "Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_0001, 0 },
{ "Mighty Bomb Jack", 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02, 0 }, { "Mighty Bomb Jack", 0xe6a89f4873fac37bULL, 0, 2, RC2C05_02, 0 },
{ "Ninja Jajamaru Kun", 0xb26a2c31474099c0LL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB }, { "Ninja Jajamaru Kun", 0xb26a2c31474099c0ULL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB },
{ "Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_001, IOPTION_PREDIP, 0x01 }, { "Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_0001, IOPTION_PREDIP, 0x01 },
{ "Pinball (J)", 0x66ab1a3828cc901cLL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 }, { "Pinball (J)", 0x66ab1a3828cc901cULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 },
{ "Platoon", 0x160f237351c19f1fLL, 68, 1, RP2C04_001, 0 }, { "Platoon", 0x160f237351c19f1fLL, 68, 1, RP2C04_0001, 0 },
{ "RBI Baseball", 0x6a02d345812938afLL, 4, 1, RP2C04_001, IOPTION_SWAPDIRAB }, { "RBI Baseball", 0x6a02d345812938afLL, 4, 1, RP2C04_0001, IOPTION_SWAPDIRAB },
{ "Soccer", 0xd4e7a9058780eda3LL, 99, 2, RP2C04_003, IOPTION_SWAPDIRAB }, { "Soccer", 0xd4e7a9058780eda3LL, 99, 2, RP2C04_0003, IOPTION_SWAPDIRAB },
{ "Star Luster", 0x8360e134b316d94cLL, 99, 2, RCP2C03B, 0 }, { "Star Luster", 0x8360e134b316d94cULL, 99, 2, RCP2C03B, 0 },
{ "Stroke and Match Golf (J)", 0x869bb83e02509747LL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, { "Stroke and Match Golf (J)", 0x869bb83e02509747ULL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
{ "Super Sky Kid", 0x78d04c1dd4ec0101LL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 }, { "Super Sky Kid", 0x78d04c1dd4ec0101ULL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 },
{ "Super Xevious", 0x2d396247cf58f9faLL, 206, 0, RP2C04_001, 0 }, { "Super Xevious", 0x2d396247cf58f9faLL, 206, 0, RP2C04_0001, 0 },
{ "Tetris", 0x531a5e8eea4ce157LL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 }, { "Tetris", 0x531a5e8eea4ce157ULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 },
{ "Top Gun", 0xf1dea36e6a7b531dLL, 2, 0, RC2C05_04, 0 }, { "Top Gun", 0xf1dea36e6a7b531dULL, 2, 0, RC2C05_04, 0 },
{ "VS Castlevania", 0x92fd6909c81305b9LL, 2, 1, RP2C04_002, 0 }, { "VS Castlevania", 0x92fd6909c81305b9LL, 2, 1, RP2C04_0002, 0 },
{ "VS Slalom", 0x4889b5a50a623215LL, 0, 1, RP2C04_002, 0 }, { "VS Slalom", 0x4889b5a50a623215LL, 0, 1, RP2C04_0002, 0 },
{ "VS Super Mario Bros", 0x39d8cfa788e20b6cLL, 99, 2, RP2C05_004, 0 }, { "VS Super Mario Bros", 0x39d8cfa788e20b6cLL, 99, 2, RP2C04_0004, 0 },
{ "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dLL, 99, 2, RP2C05_004, 0 }, { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dLL, 99, 2, RP2C04_0004, 0 },
{ "VS TKO Boxing", 0x6e1ee06171d8ce3aLL, 4, 1, RP2C04_003, IOPTION_PREDIP, 0x00 }, { "VS TKO Boxing", 0x6e1ee06171d8ce3aLL, 4, 1, RP2C04_0003, IOPTION_PREDIP, 0x00 },
{ 0 } { 0 }
}; };
@ -302,6 +302,7 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring) {
while (vs->name) { while (vs->name) {
if (md5partial == vs->md5partial) { if (md5partial == vs->md5partial) {
if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu; if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu;
else default_palette_selection = 5;
*MapperNo = vs->mapper; *MapperNo = vs->mapper;
*Mirroring = vs->mirroring; *Mirroring = vs->mirroring;
GameInfo->type = GIT_VSUNI; GameInfo->type = GIT_VSUNI;

View File

@ -24,7 +24,7 @@ void FCEU_WriteWaveData(int32 *Buffer, int Count)
int16 *dest; int16 *dest;
int x; int x;
#ifndef WIN32 #ifdef __WIN_DRIVER__
if(!soundlog) return; if(!soundlog) return;
#else #else
if(!soundlog && !FCEUI_AviIsRecording()) return; if(!soundlog && !FCEUI_AviIsRecording()) return;
@ -46,7 +46,7 @@ void FCEU_WriteWaveData(int32 *Buffer, int Count)
if(soundlog) if(soundlog)
wsize+=fwrite(temp,1,Count*sizeof(int16),soundlog); wsize+=fwrite(temp,1,Count*sizeof(int16),soundlog);
#ifdef WIN32 #ifdef __WIN_DRIVER__
if(FCEUI_AviIsRecording()) if(FCEUI_AviIsRecording())
{ {
FCEUI_AviSoundUpdate((void*)temp, Count); FCEUI_AviSoundUpdate((void*)temp, Count);
@ -124,3 +124,8 @@ bool FCEUI_BeginWaveRecord(const char *fn)
return true; return true;
} }
bool FCEUI_WaveRecordRunning(void)
{
return (soundlog != NULL);
}

View File

@ -1,4 +1,6 @@
#include "types.h" #include "types.h"
bool FCEUI_BeginWaveRecord(const char *fn);
bool FCEUI_WaveRecordRunning(void);
void FCEU_WriteWaveData(int32 *Buffer, int Count); 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, /*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) void X6502_IRQBegin(int w)
{ {
_IRQlow|=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, /*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, /*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, /*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_IRQBegin(int w);
void X6502_IRQEnd(int w); void X6502_IRQEnd(int w);
int X6502_GetOpcodeCycles( int op );
#define _X6502H #define _X6502H
#endif #endif

View File

@ -177,6 +177,7 @@ DUMMY(FCEUD_LoadStateFrom)
DUMMY(FCEUD_MovieRecordTo) DUMMY(FCEUD_MovieRecordTo)
DUMMY(FCEUD_MovieReplayFrom) DUMMY(FCEUD_MovieReplayFrom)
DUMMY(FCEUD_ToggleStatusIcon) DUMMY(FCEUD_ToggleStatusIcon)
DUMMY(FCEUD_FlushTrace)
DUMMY(FCEUD_DebugBreakpoint) DUMMY(FCEUD_DebugBreakpoint)
DUMMY(FCEUD_SoundToggle) DUMMY(FCEUD_SoundToggle)
DUMMY(FCEUD_AviRecordTo) DUMMY(FCEUD_AviRecordTo)

View File

@ -37,7 +37,7 @@ extern unsigned char * nesrom;
int GetFCEUTiming(); int GetFCEUTiming();
void UpdateDendy(); void UpdateDendy();
void RebuildSubCheats(void); 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 FDSLoad(const char *name, FCEUFILE *fp);
extern int iNESLoad(const char *name, FCEUFILE *fp, int o); extern int iNESLoad(const char *name, FCEUFILE *fp, int o);