diff --git a/source/fceultra/asm.cpp b/source/fceultra/asm.cpp index 5b2f502..0aa2a61 100644 --- a/source/fceultra/asm.cpp +++ b/source/fceultra/asm.cpp @@ -16,7 +16,7 @@ int Assemble(unsigned char *output, int addr, char *str) { output[0] = output[1] = output[2] = 0; char astr[128],ins[4]; int len = strlen(str); - if ((!len) || (len > 0x127)) return 1; + if ((!len) || (len > 127)) return 1; strcpy(astr,str); str_ucase(astr); diff --git a/source/fceultra/boards/112.cpp b/source/fceultra/boards/112.cpp index f0aeff3..f0ee7ac 100644 --- a/source/fceultra/boards/112.cpp +++ b/source/fceultra/boards/112.cpp @@ -1,90 +1,90 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2005 CaH4e3 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * NTDEC, ASDER games - * - */ - -#include "mapinc.h" - -static uint8 reg[8]; -static uint8 mirror, cmd, bank; -static uint8 *WRAM = NULL; - -static SFORMAT StateRegs[] = -{ - { &cmd, 1, "CMD" }, - { &mirror, 1, "MIRR" }, - { &bank, 1, "BANK" }, - { reg, 8, "REGS" }, - { 0 } -}; - -static void Sync(void) { - setmirror(mirror ^ 1); - setprg8(0x8000, reg[0]); - setprg8(0xA000, reg[1]); - setchr2(0x0000, (reg[2] >> 1)); - setchr2(0x0800, (reg[3] >> 1)); - setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]); - setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]); - setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]); - setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]); -} - -static DECLFW(M112Write) { - switch (A) { - case 0xe000: mirror = V & 1; Sync();; break; - case 0x8000: cmd = V & 7; break; - case 0xa000: reg[cmd] = V; Sync(); break; - case 0xc000: bank = V; Sync(); break; - } -} - -static void M112Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void M112Power(void) { - bank = 0; - setprg16(0xC000, ~0); - setprg8r(0x10, 0x6000, 0); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M112Write); - SetWriteHandler(0x4020, 0x5FFF, M112Write); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005 CaH4e3 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * NTDEC, ASDER games + * + */ + +#include "mapinc.h" + +static uint8 reg[8]; +static uint8 mirror, cmd, bank; +static uint8 *WRAM = NULL; + +static SFORMAT StateRegs[] = +{ + { &cmd, 1, "CMD" }, + { &mirror, 1, "MIRR" }, + { &bank, 1, "BANK" }, + { reg, 8, "REGS" }, + { 0 } +}; + +static void Sync(void) { + setmirror(mirror ^ 1); + setprg8(0x8000, reg[0]); + setprg8(0xA000, reg[1]); + setchr2(0x0000, (reg[2] >> 1)); + setchr2(0x0800, (reg[3] >> 1)); + setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]); + setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]); + setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]); + setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]); +} + +static DECLFW(M112Write) { + switch (A) { + case 0xe000: mirror = V & 1; Sync();; break; + case 0x8000: cmd = V & 7; break; + case 0xa000: reg[cmd] = V; Sync(); break; + case 0xc000: bank = V; Sync(); break; + } +} + +static void M112Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void M112Power(void) { + bank = 0; + setprg16(0xC000, ~0); + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M112Write); + SetWriteHandler(0x4020, 0x5FFF, M112Write); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(8, 0x6000, WRAM); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper112_Init(CartInfo *info) { - info->Power = M112Power; - info->Close = M112Close; - GameStateRestore = StateRestore; - WRAM = (uint8*)FCEU_gmalloc(8192); - SetupCartPRGMapping(0x10, WRAM, 8192, 1); - AddExState(WRAM, 8192, 0, "WRAM"); - AddExState(&StateRegs, ~0, 0, 0); -} +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper112_Init(CartInfo *info) { + info->Power = M112Power; + info->Close = M112Close; + GameStateRestore = StateRestore; + WRAM = (uint8*)FCEU_gmalloc(8192); + SetupCartPRGMapping(0x10, WRAM, 8192, 1); + AddExState(WRAM, 8192, 0, "WRAM"); + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/15.cpp b/source/fceultra/boards/15.cpp index 8ea05bf..01f55cd 100644 --- a/source/fceultra/boards/15.cpp +++ b/source/fceultra/boards/15.cpp @@ -35,31 +35,39 @@ static SFORMAT StateRegs[] = static void Sync(void) { int i; setmirror(((latched >> 6) & 1) ^ 1); - switch (latchea) { - case 0x8000: + switch (latchea & 3) { + case 0: for (i = 0; i < 4; i++) - setprg8(0x8000 + (i << 13), (((latched & 0x7F) << 1) + i) ^ (latched >> 7)); + setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + i); break; - case 0x8002: + case 2: for (i = 0; i < 4; i++) - setprg8(0x8000 + (i << 13), ((latched & 0x7F) << 1) + (latched >> 7)); + setprg8(0x8000 + (i << 13), ((latched & 0x3F) << 1) + (latched >> 7)); break; - case 0x8001: - case 0x8003: + case 1: + case 3: for (i = 0; i < 4; i++) { unsigned int b; - b = latched & 0x7F; + b = latched & 0x3F; if (i >= 2 && !(latchea & 0x2)) - b = 0x7F; - setprg8(0x8000 + (i << 13), (i & 1) + ((b << 1) ^ (latched >> 7))); + b = b | 0x07; + setprg8(0x8000 + (i << 13), (i & 1) + (b << 1)); } break; } + setchr8(0); } static DECLFW(M15Write) { latchea = A; latched = V; + // cah4e3 02.10.19 once again, there may be either two similar mapper 15 exist. the one for 110in1 or 168in1 carts with complex multi game features. + // and another implified version for subor/waixing chinese originals and hacks with no different modes, working only in mode 0 and which does not + // expect there is any CHR write protection. protecting CHR writes only for mode 3 fixes the problem, all roms may be run on the same source again. + if((latchea & 3) == 3) + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + else + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); Sync(); } @@ -70,7 +78,6 @@ static void StateRestore(int version) { static void M15Power(void) { latchea = 0x8000; latched = 0; - setchr8(0); setprg8r(0x10, 0x6000, 0); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); diff --git a/source/fceultra/boards/164.cpp b/source/fceultra/boards/164.cpp index 37b0439..6eb963b 100644 --- a/source/fceultra/boards/164.cpp +++ b/source/fceultra/boards/164.cpp @@ -1,232 +1,232 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel 2006 CaH4e3 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * It seems that 162/163/164 mappers are the same mapper with just different - * mapper modes enabled or disabled in software or hardware, need more nanjing - * carts - */ - -#include "mapinc.h" - -static uint8 laststrobe, trigger; -static uint8 reg[8]; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static writefunc pcmwrite; - -static void (*WSync)(void); - -static SFORMAT StateRegs[] = -{ - { &laststrobe, 1, "STB" }, - { &trigger, 1, "TRG" }, - { reg, 8, "REGS" }, - { 0 } -}; - -static void Sync(void) { - setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF)); - setchr8(0); -} - -static void StateRestore(int version) { - WSync(); -} - -static DECLFR(ReadLow) { - switch (A & 0x7700) { - case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break; - case 0x5500: - if (trigger) - return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games - else - return 0; - } - return 4; -} - -static void M163HB(void) { - if (reg[1] & 0x80) { - if (scanline == 239) { - setchr4(0x0000, 0); - setchr4(0x1000, 0); - } else if (scanline == 127) { - setchr4(0x0000, 1); - setchr4(0x1000, 1); - } -/* - if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it - { - setchr4(0x0000,1); - setchr4(0x1000,1); - } - else - { - setchr4(0x0000,0); - setchr4(0x1000,0); - } -*/ - } -} - -static DECLFW(Write) { - switch (A & 0x7300) { - case 0x5100: reg[0] = V; WSync(); break; - case 0x5000: reg[1] = V; WSync(); break; - case 0x5300: reg[2] = V; break; - case 0x5200: reg[3] = V; WSync(); break; - } -} - -static void Power(void) { - memset(reg, 0, 8); - reg[1] = 0xFF; - SetWriteHandler(0x5000, 0x5FFF, Write); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel 2006 CaH4e3 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * It seems that 162/163/164 mappers are the same mapper with just different + * mapper modes enabled or disabled in software or hardware, need more nanjing + * carts + */ + +#include "mapinc.h" + +static uint8 laststrobe, trigger; +static uint8 reg[8]; +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; + +static writefunc pcmwrite; + +static void (*WSync)(void); + +static SFORMAT StateRegs[] = +{ + { &laststrobe, 1, "STB" }, + { &trigger, 1, "TRG" }, + { reg, 8, "REGS" }, + { 0 } +}; + +static void Sync(void) { + setprg8r(0x10, 0x6000, 0); + setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF)); + setchr8(0); +} + +static void StateRestore(int version) { + WSync(); +} + +static DECLFR(ReadLow) { + switch (A & 0x7700) { + case 0x5100: return reg[2] | reg[0] | reg[1] | reg[3] ^ 0xff; break; + case 0x5500: + if (trigger) + return reg[2] | reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games + else + return 0; + } + return 4; +} + +static void M163HB(void) { + if (reg[1] & 0x80) { + if (scanline == 239) { + setchr4(0x0000, 0); + setchr4(0x1000, 0); + } else if (scanline == 127) { + setchr4(0x0000, 1); + setchr4(0x1000, 1); + } +/* + if(scanline>=127) // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it + { + setchr4(0x0000,1); + setchr4(0x1000,1); + } + else + { + setchr4(0x0000,0); + setchr4(0x1000,0); + } +*/ + } +} + +static DECLFW(Write) { + switch (A & 0x7300) { + case 0x5100: reg[0] = V; WSync(); break; + case 0x5000: reg[1] = V; WSync(); break; + case 0x5300: reg[2] = V; break; + case 0x5200: reg[3] = V; WSync(); break; + } +} + +static void Power(void) { + memset(reg, 0, 8); + reg[1] = 0xFF; + SetWriteHandler(0x5000, 0x5FFF, Write); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - WSync(); -} - -static void Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -void Mapper164_Init(CartInfo *info) { - info->Power = Power; - info->Close = Close; - WSync = Sync; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -static DECLFW(Write2) { - if (A == 0x5101) { - if (laststrobe && !V) { - trigger ^= 1; - } - laststrobe = V; - } else if (A == 0x5100 && V == 6) //damn thoose protected games - setprg32(0x8000, 3); - else - switch (A & 0x7300) { - case 0x5200: reg[0] = V; WSync(); break; - case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break; - case 0x5300: reg[2] = V; break; - case 0x5100: reg[3] = V; WSync(); break; - } -} - -static void Power2(void) { - memset(reg, 0, 8); - laststrobe = 1; - pcmwrite = GetWriteHandler(0x4011); - SetReadHandler(0x5000, 0x5FFF, ReadLow); - SetWriteHandler(0x5000, 0x5FFF, Write2); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); + WSync(); +} + +static void Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +void Mapper164_Init(CartInfo *info) { + info->Power = Power; + info->Close = Close; + WSync = Sync; + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} + +static DECLFW(Write2) { + if (A == 0x5101) { + if (laststrobe && !V) { + trigger ^= 1; + } + laststrobe = V; + } else if (A == 0x5100 && V == 6) //damn thoose protected games + setprg32(0x8000, 3); + else + switch (A & 0x7300) { + case 0x5200: reg[0] = V; WSync(); break; + case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break; + case 0x5300: reg[2] = V; break; + case 0x5100: reg[3] = V; WSync(); break; + } +} + +static void Power2(void) { + memset(reg, 0, 8); + laststrobe = 1; + pcmwrite = GetWriteHandler(0x4011); + SetReadHandler(0x5000, 0x5FFF, ReadLow); + SetWriteHandler(0x5000, 0x5FFF, Write2); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - WSync(); -} - -void Mapper163_Init(CartInfo *info) { - info->Power = Power2; - info->Close = Close; - WSync = Sync; - GameHBIRQHook = M163HB; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -static void Sync3(void) { - setchr8(0); - setprg8r(0x10, 0x6000, 0); - switch (reg[3] & 7) { - case 0: - case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break; - case 1: - case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break; - case 4: - case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break; - case 5: - case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break; - } -} - -static DECLFW(Write3) { -// FCEU_printf("bs %04x %02x\n",A,V); - reg[(A >> 8) & 3] = V; - WSync(); -} - -static void Power3(void) { - reg[0] = 3; - reg[1] = 0; - reg[2] = 0; - reg[3] = 7; - SetWriteHandler(0x5000, 0x5FFF, Write3); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); + WSync(); +} + +void Mapper163_Init(CartInfo *info) { + info->Power = Power2; + info->Close = Close; + WSync = Sync; + GameHBIRQHook = M163HB; + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} + +static void Sync3(void) { + setchr8(0); + setprg8r(0x10, 0x6000, 0); + switch (reg[3] & 7) { + case 0: + case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break; + case 1: + case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break; + case 4: + case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break; + case 5: + case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break; + } +} + +static DECLFW(Write3) { +// FCEU_printf("bs %04x %02x\n",A,V); + reg[(A >> 8) & 3] = V; + WSync(); +} + +static void Power3(void) { + reg[0] = 3; + reg[1] = 0; + reg[2] = 0; + reg[3] = 7; + SetWriteHandler(0x5000, 0x5FFF, Write3); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - WSync(); -} - -void UNLFS304_Init(CartInfo *info) { - info->Power = Power3; - info->Close = Close; - WSync = Sync3; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} + WSync(); +} + +void UNLFS304_Init(CartInfo *info) { + info->Power = Power3; + info->Close = Close; + WSync = Sync3; + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/178.cpp b/source/fceultra/boards/178.cpp index 65e98a1..d577329 100644 --- a/source/fceultra/boards/178.cpp +++ b/source/fceultra/boards/178.cpp @@ -37,8 +37,8 @@ static int32 SensorDelay; // highly experimental, not actually working, just curious if it hapen to work with some other decoder // SND Registers static uint8 pcm_enable = 0; -static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6; -static writefunc pcmwrite; +//static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6; +//static writefunc pcmwrite; static SFORMAT StateRegs[] = { diff --git a/source/fceultra/boards/186.cpp b/source/fceultra/boards/186.cpp index 10902dc..045a0da 100644 --- a/source/fceultra/boards/186.cpp +++ b/source/fceultra/boards/186.cpp @@ -18,6 +18,33 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Family Study Box by Fukutake Shoten + * + * REG[0] R dddddddd / W ww---sss + * ddd - TAPE DATA BYTE (ready when IRQ occurs) + * sss - BRAM hi-bank + * ww - PRAM bank + * REG[1] R 0123---- / W ----PPPP + * 0 - ? + * 1 - ? + * 2 - ? + * 3 - ? + * PPPP- PROM bank + * REG[2] R -?--R--- / W A-BC-DEF + * 4 - ? + * R - sb4x power supply status (active low) + * A - ? + * B - ? + * C - ? + * D - ? + * E - ? + * F - ? + * + * BRAM0 4400-4FFF, 3K bank 0 (32K SWRAM) [hardwired] + * BRAMB 5000-5FFF, 4K banks 1-7 (32K SWRAM) [REG[0] W -----sss] + * PRAMB 6000-7FFF, 8K banks 1-3 (32K PRAM) [REG[0] W ww------] + * PROMB 8000-BFFF, 16K banks 1-15 (256K PROM)[REG[1] W ----PPPP] + * PROM0 C000-FFFF, 16K bank 0 (256K PROM) [hardwired] + * */ #include "mapinc.h" diff --git a/source/fceultra/boards/225.cpp b/source/fceultra/boards/225.cpp index fd008ea..e8237ed 100644 --- a/source/fceultra/boards/225.cpp +++ b/source/fceultra/boards/225.cpp @@ -52,15 +52,23 @@ static DECLFW(M225Write) { } static DECLFW(M225LoWrite) { + if (A & 0x800) { + prot[A & 0x03] = V; + } } static DECLFR(M225LoRead) { - return 0; + if (A & 0x800) { + return prot[A & 3] & 0x0F; + } + return X.DB; } static void M225Power(void) { prg = 0; + chr = 0; mode = 0; + mirr = 0; Sync(); SetReadHandler(0x5000, 0x5FFF, M225LoRead); SetWriteHandler(0x5000, 0x5FFF, M225LoWrite); @@ -70,7 +78,9 @@ static void M225Power(void) { static void M225Reset(void) { prg = 0; + chr = 0; mode = 0; + mirr = 0; Sync(); } diff --git a/source/fceultra/boards/28.cpp b/source/fceultra/boards/28.cpp index 617b3ae..473cca4 100644 --- a/source/fceultra/boards/28.cpp +++ b/source/fceultra/boards/28.cpp @@ -53,8 +53,8 @@ void Mirror(uint8 value) static void Sync() { - int prglo; - int prghi; + int prglo = 0; + int prghi = 0; int outb = outer << 1; //this can probably be rolled up, but i have no motivation to do so @@ -127,14 +127,14 @@ static void Sync() static DECLFW(WriteEXP) { - uint32 addr = A; + //uint32 addr = A; uint8 value = V; reg = value & 0x81; } static DECLFW(WritePRG) { - uint32 addr = A; + //uint32 addr = A; uint8 value = V; switch (reg) { diff --git a/source/fceultra/boards/71.cpp b/source/fceultra/boards/71.cpp index 37c05aa..0fbf585 100644 --- a/source/fceultra/boards/71.cpp +++ b/source/fceultra/boards/71.cpp @@ -21,6 +21,7 @@ #include "mapinc.h" static uint8 preg, mirr; +static int hardmirr; static SFORMAT StateRegs[] = { @@ -35,6 +36,8 @@ static void Sync(void) { setchr8(0); if(mirr) setmirror(mirr); + else + setmirror(hardmirr); // restore hardwired mirroring } static DECLFW(M71Write) { @@ -46,6 +49,7 @@ static DECLFW(M71Write) { } static void M71Power(void) { + preg = 0; mirr = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -57,6 +61,7 @@ static void StateRestore(int version) { } void Mapper71_Init(CartInfo *info) { + hardmirr = info->mirror; info->Power = M71Power; GameStateRestore = StateRestore; diff --git a/source/fceultra/boards/8237.cpp b/source/fceultra/boards/8237.cpp index 3807769..0967970 100644 --- a/source/fceultra/boards/8237.cpp +++ b/source/fceultra/boards/8237.cpp @@ -19,7 +19,6 @@ * * Super Game (Sugar Softec) protected mapper * Pocahontas 2 (Unl) [U][!], etc. - * TODO: 9in1 LION KING HANGS! */ #include "mapinc.h" @@ -139,7 +138,7 @@ static DECLFW(UNL8237Write) { } static DECLFW(UNL8237ExWrite) { - switch (A) { + switch (A & 0xF007) { case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); break; case 0x5001: EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break; case 0x5007: EXPREGS[2] = V; break; diff --git a/source/fceultra/boards/addrlatch.cpp b/source/fceultra/boards/addrlatch.cpp index 44480ae..05d05f0 100644 --- a/source/fceultra/boards/addrlatch.cpp +++ b/source/fceultra/boards/addrlatch.cpp @@ -237,13 +237,8 @@ void Mapper200_Init(CartInfo *info) { //------------------ Map 201 --------------------------- static void M201Sync(void) { - if (latche & 8) { - setprg32(0x8000, latche & 3); - setchr8(latche & 3); - } else { - setprg32(0x8000, 0); - setchr8(0); - } + setprg32(0x8000, latche & 3); + setchr8(latche & 3); } void Mapper201_Init(CartInfo *info) { @@ -353,6 +348,17 @@ static void M227Sync(void) { uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3); uint32 L = (latche >> 9) & 1; +// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7. +// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional +// functionality. as I see from the menu code, it disables the chr writing before run an actual game. +// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware +// but if I find some i'll definitly do this. + + if ((latche & 0xF000) == 0xF000) + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + else + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); + if ((latche >> 7) & 1) { if (S) { setprg32(0x8000, p >> 1); diff --git a/source/fceultra/boards/bandai.cpp b/source/fceultra/boards/bandai.cpp index 24043a9..d6670f5 100644 --- a/source/fceultra/boards/bandai.cpp +++ b/source/fceultra/boards/bandai.cpp @@ -48,120 +48,205 @@ static SFORMAT StateRegs[] = #define X24C0X_READ 3 #define X24C0X_WRITE 4 -static uint8 x24c0x_data[256], x24c0x_state; -static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount; -static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe; +static uint8 x24c0x_data[512]; -static SFORMAT x24c0xStateRegs[] = +static uint8 x24c01_state; +static uint8 x24c01_addr, x24c01_word, x24c01_latch, x24c01_bitcount; +static uint8 x24c01_sda, x24c01_scl, x24c01_out; + +static uint8 x24c02_state; +static uint8 x24c02_addr, x24c02_word, x24c02_latch, x24c02_bitcount; +static uint8 x24c02_sda, x24c02_scl, x24c02_out; + +static SFORMAT x24c01StateRegs[] = { - { &x24c0x_addr, 1, "ADDR" }, - { &x24c0x_word, 1, "WORD" }, - { &x24c0x_latch, 1, "LATC" }, - { &x24c0x_bitcount, 1, "BITC" }, - { &x24c0x_sda, 1, "SDA" }, - { &x24c0x_scl, 1, "SCL" }, - { &x24c0x_out, 1, "OUT" }, - { &x24c0x_oe, 1, "OE" }, - { &x24c0x_state, 1, "STAT" }, + { &x24c01_addr, 1, "ADDR" }, + { &x24c01_word, 1, "WORD" }, + { &x24c01_latch, 1, "LATC" }, + { &x24c01_bitcount, 1, "BITC" }, + { &x24c01_sda, 1, "SDA" }, + { &x24c01_scl, 1, "SCL" }, + { &x24c01_out, 1, "OUT" }, + { &x24c01_state, 1, "STAT" }, { 0 } }; -static void x24c0x_init() { - x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0; - x24c0x_state = X24C0X_STANDBY; +static SFORMAT x24c02StateRegs[] = +{ + { &x24c02_addr, 1, "ADDR" }, + { &x24c02_word, 1, "WORD" }, + { &x24c02_latch, 1, "LATC" }, + { &x24c02_bitcount, 1, "BITC" }, + { &x24c02_sda, 1, "SDA" }, + { &x24c02_scl, 1, "SCL" }, + { &x24c02_out, 1, "OUT" }, + { &x24c02_state, 1, "STAT" }, + { 0 } +}; + +static void x24c01_init() { + x24c01_addr = x24c01_word = x24c01_latch = x24c01_bitcount = x24c01_sda = x24c01_scl = 0; + x24c01_state = X24C0X_STANDBY; } -static void x24c0x_write(uint8 data) { - uint8 sda = (data >> 6) & 1; - uint8 scl = (data >> 5) & 1; - x24c0x_oe = (data >> 7); +static void x24c02_init() { + x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0; + x24c02_state = X24C0X_STANDBY; +} - if(x24c0x_scl && scl) { - if(x24c0x_sda && !sda) { // START - x24c0x_state = X24C0X_ADDRESS; - x24c0x_bitcount = 0; - x24c0x_addr = 0; - } else if(!x24c0x_sda && sda) { //STOP - x24c0x_state = X24C0X_STANDBY; +static void x24c01_write(uint8 data) { + uint8 scl = (data >> 5) & 1; + uint8 sda = (data >> 6) & 1; + + if(x24c01_scl && scl) { + if(x24c01_sda && !sda) { // START + x24c01_state = X24C0X_ADDRESS; + x24c01_bitcount = 0; + x24c01_addr = 0; + } else if(!x24c01_sda && sda) { //STOP + x24c01_state = X24C0X_STANDBY; } - } else if(!x24c0x_scl && scl) { // RISING EDGE - switch(x24c0x_state) { + } else if(!x24c01_scl && scl) { // RISING EDGE + switch(x24c01_state) { case X24C0X_ADDRESS: - if(x24c0x_bitcount < 7) { - x24c0x_addr <<= 1; - x24c0x_addr |= sda; + if(x24c01_bitcount < 7) { + x24c01_addr <<= 1; + x24c01_addr |= sda; } else { - if(!x24c02) // X24C01 mode - x24c0x_word = x24c0x_addr; - if(sda) { // READ COMMAND - x24c0x_state = X24C0X_READ; - } else { // WRITE COMMAND - if(x24c02) // X24C02 mode - x24c0x_state = X24C0X_WORD; - else - x24c0x_state = X24C0X_WRITE; - } + x24c01_word = x24c01_addr; + if(sda) // READ COMMAND + x24c01_state = X24C0X_READ; + else // WRITE COMMAND + x24c01_state = X24C0X_WRITE; } - x24c0x_bitcount++; - break; - case X24C0X_WORD: - if(x24c0x_bitcount == 8) { // ACK - x24c0x_word = 0; - x24c0x_out = 0; - } else { // WORD ADDRESS INPUT - x24c0x_word <<= 1; - x24c0x_word |= sda; - if(x24c0x_bitcount == 16) { // END OF ADDRESS INPUT - x24c0x_bitcount = 7; - x24c0x_state = X24C0X_WRITE; - } - } - x24c0x_bitcount++; + x24c01_bitcount++; break; case X24C0X_READ: - if (x24c0x_bitcount == 8) { // ACK - x24c0x_out = 0; - x24c0x_latch = x24c0x_data[x24c0x_word]; - x24c0x_bitcount = 0; - } else { // REAL OUTPUT - x24c0x_out = x24c0x_latch >> 7; - x24c0x_latch <<= 1; - x24c0x_bitcount++; - if(x24c0x_bitcount == 8) { - x24c0x_word++; - x24c0x_word &= 0xff; + if (x24c01_bitcount == 8) { // ACK + x24c01_out = 0; + x24c01_latch = x24c0x_data[x24c01_word]; + x24c01_bitcount = 0; + } else { // REAL OUTPUT + x24c01_out = x24c01_latch >> 7; + x24c01_latch <<= 1; + x24c01_bitcount++; + if(x24c01_bitcount == 8) { + x24c01_word++; + x24c01_word &= 0xff; } } break; case X24C0X_WRITE: - if (x24c0x_bitcount == 8) { // ACK - x24c0x_out = 0; - x24c0x_latch = 0; - x24c0x_bitcount = 0; - } else { // REAL INPUT - x24c0x_latch <<= 1; - x24c0x_latch |= sda; - x24c0x_bitcount++; - if(x24c0x_bitcount == 8) { - x24c0x_data[x24c0x_word] = x24c0x_latch; - x24c0x_word++; - x24c0x_word &= 0xff; + if (x24c01_bitcount == 8) { // ACK + x24c01_out = 0; + x24c01_latch = 0; + x24c01_bitcount = 0; + } else { // REAL INPUT + x24c01_latch <<= 1; + x24c01_latch |= sda; + x24c01_bitcount++; + if(x24c01_bitcount == 8) { + x24c0x_data[x24c01_word] = x24c01_latch; + x24c01_word++; + x24c01_word &= 0xff; } } break; } } - x24c0x_sda = sda; - x24c0x_scl = scl; + x24c01_sda = sda; + x24c01_scl = scl; } -static uint8 x24c0x_read() { - return x24c0x_out << 4; +static void x24c02_write(uint8 data) { + uint8 scl = (data >> 5) & 1; + uint8 sda = (data >> 6) & 1; + + if (x24c02_scl && scl) { + if (x24c02_sda && !sda) { // START + x24c02_state = X24C0X_ADDRESS; + x24c02_bitcount = 0; + x24c02_addr = 0; + } else if (!x24c02_sda && sda) { //STOP + x24c02_state = X24C0X_STANDBY; + } + } else if (!x24c02_scl && scl) { // RISING EDGE + switch (x24c02_state) { + case X24C0X_ADDRESS: + if (x24c02_bitcount < 7) { + x24c02_addr <<= 1; + x24c02_addr |= sda; + } else { + if (sda) // READ COMMAND + x24c02_state = X24C0X_READ; + else // WRITE COMMAND + x24c02_state = X24C0X_WORD; + } + x24c02_bitcount++; + break; + case X24C0X_WORD: + if (x24c02_bitcount == 8) { // ACK + x24c02_word = 0; + x24c02_out = 0; + } else { // WORD ADDRESS INPUT + x24c02_word <<= 1; + x24c02_word |= sda; + if (x24c02_bitcount == 16) {// END OF ADDRESS INPUT + x24c02_bitcount = 7; + x24c02_state = X24C0X_WRITE; + } + } + x24c02_bitcount++; + break; + case X24C0X_READ: + if (x24c02_bitcount == 8) { // ACK + x24c02_out = 0; + x24c02_latch = x24c0x_data[x24c02_word|0x100]; + x24c02_bitcount = 0; + } else { // REAL OUTPUT + x24c02_out = x24c02_latch >> 7; + x24c02_latch <<= 1; + x24c02_bitcount++; + if (x24c02_bitcount == 8) { + x24c02_word++; + x24c02_word &= 0xff; + } + } + break; + case X24C0X_WRITE: + if (x24c02_bitcount == 8) { // ACK + x24c02_out = 0; + x24c02_latch = 0; + x24c02_bitcount = 0; + } else { // REAL INPUT + x24c02_latch <<= 1; + x24c02_latch |= sda; + x24c02_bitcount++; + if (x24c02_bitcount == 8) { + x24c0x_data[x24c02_word|0x100] = x24c02_latch; + x24c02_word++; + x24c02_word &= 0xff; + } + } + break; + } + } + x24c02_sda = sda; + x24c02_scl = scl; } // +static void SyncMirror(void) { + switch (reg[9] & 3) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + static void Sync(void) { if (is153) { int base = (reg[0] & 1) << 4; @@ -174,12 +259,7 @@ static void Sync(void) { setprg16(0x8000, reg[8]); setprg16(0xC000, ~0); } - switch (reg[9] & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } + SyncMirror(); } static DECLFW(BandaiWrite) { @@ -192,12 +272,15 @@ static DECLFW(BandaiWrite) { case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; - case 0x0D: x24c0x_write(V); break; + case 0x0D: if(x24c02) x24c02_write(V); else x24c01_write(V); break; } } static DECLFR(BandaiRead) { - return (X.DB & 0xEF) | x24c0x_read(); + if(x24c02) + return (X.DB & 0xEF) | (x24c02_out << 4); + else + return (X.DB & 0xEF) | (x24c01_out << 4); } static void BandaiIRQHook(int a) { @@ -213,7 +296,10 @@ static void BandaiIRQHook(int a) { static void BandaiPower(void) { IRQa = 0; - x24c0x_init(); + if(x24c02) + x24c02_init(); + else + x24c01_init(); Sync(); SetReadHandler(0x6000, 0x7FFF, BandaiRead); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -231,12 +317,12 @@ void Mapper16_Init(CartInfo *info) { MapIRQHook = BandaiIRQHook; info->battery = 1; - info->SaveGame[0] = x24c0x_data; + info->SaveGame[0] = x24c0x_data + 256; info->SaveGameLen[0] = 256; AddExState(x24c0x_data, 256, 0, "DATA"); + AddExState(&x24c02StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; - AddExState(&x24c0xStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); } @@ -250,9 +336,9 @@ void Mapper159_Init(CartInfo *info) { info->SaveGame[0] = x24c0x_data; info->SaveGameLen[0] = 128; AddExState(x24c0x_data, 128, 0, "DATA"); + AddExState(&x24c01StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; - AddExState(&x24c0xStateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); } @@ -307,7 +393,9 @@ static int BarcodeReadPos; static int BarcodeCycleCount; static uint32 BarcodeOut; -int FCEUI_DatachSet(const uint8 *rcode) { +// #define INTERL2OF5 + +int FCEUI_DatachSet(uint8 *rcode) { int prefix_parity_type[10][6] = { { 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 1, 0 }, { 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 1 }, { 0, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 0, 1 }, @@ -330,6 +418,7 @@ int FCEUI_DatachSet(const uint8 *rcode) { }; uint8 code[13 + 1]; uint32 tmp_p = 0; + uint32 csum = 0; int i, j; int len; @@ -341,18 +430,46 @@ int FCEUI_DatachSet(const uint8 *rcode) { } if (len != 13 && len != 12 && len != 8 && len != 7) return(0); - #define BS(x) BarcodeData[tmp_p] = x; tmp_p++ +#define BS(x) BarcodeData[tmp_p] = x; tmp_p++ - for (j = 0; j < 32; j++) { + for (j = 0; j < 32; j++) { // delay before sending a code BS(0x00); } - /* Left guard bars */ +#ifdef INTERL2OF5 + + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(1); BS(0); BS(0); // 1 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 + BS(1); BS(0); BS(0); // 0 cs + BS(1); BS(1); BS(0); BS(0); // 1 + +#else + // Left guard bars BS(1); BS(0); BS(1); - if (len == 13 || len == 12) { - uint32 csum; - for (i = 0; i < 6; i++) if (prefix_parity_type[code[0]][i]) { for (j = 0; j < 7; j++) { @@ -362,53 +479,53 @@ int FCEUI_DatachSet(const uint8 *rcode) { for (j = 0; j < 7; j++) { BS(data_left_odd[code[i + 1]][j]); } - - /* Center guard bars */ + // Center guard bars BS(0); BS(1); BS(0); BS(1); BS(0); - for (i = 7; i < 12; i++) for (j = 0; j < 7; j++) { BS(data_right[code[i]][j]); } - csum = 0; - for (i = 0; i < 12; i++) csum += code[i] * ((i & 1) ? 3 : 1); - csum = (10 - (csum % 10)) % 10; + // Calc and write down the control code if not assigned, instead, send code as is + // Battle Rush uses modified type of codes with different control code calculation + if (len == 12) { + for (i = 0; i < 12; i++) + csum += code[i] * ((i & 1) ? 3 : 1); + csum = (10 - (csum % 10)) % 10; + rcode[12] = csum + 0x30; // update check code to the input string as well + rcode[13] = 0; + code[12] = csum; + } for (j = 0; j < 7; j++) { - BS(data_right[csum][j]); + BS(data_right[code[12]][j]); } } else if (len == 8 || len == 7) { - uint32 csum = 0; - - for (i = 0; i < 7; i++) csum += (i & 1) ? code[i] : (code[i] * 3); - - csum = (10 - (csum % 10)) % 10; - for (i = 0; i < 4; i++) for (j = 0; j < 7; j++) { BS(data_left_odd[code[i]][j]); } - - - /* Center guard bars */ + // Center guard bars BS(0); BS(1); BS(0); BS(1); BS(0); - for (i = 4; i < 7; i++) for (j = 0; j < 7; j++) { BS(data_right[code[i]][j]); } - + csum = 0; + for (i = 0; i < 7; i++) + csum += (i & 1) ? code[i] : (code[i] * 3); + csum = (10 - (csum % 10)) % 10; + rcode[7] = csum + 0x30; // update check code to the input string as well + rcode[8] = 0; for (j = 0; j < 7; j++) { BS(data_right[csum][j]); } } - - /* Right guard bars */ + // Right guard bars BS(1); BS(0); BS(1); +#endif for (j = 0; j < 32; j++) { BS(0x00); } - BS(0xFF); #undef BS @@ -419,6 +536,26 @@ int FCEUI_DatachSet(const uint8 *rcode) { return(1); } +static void BarcodeSync(void) { + setchr8(0); + setprg16(0x8000, (reg[8] & 0x0F)); + setprg16(0xC000, 0x0F); + SyncMirror(); +} + +static DECLFW(BarcodeWrite) { + A &= 0x0F; + switch (A) { + case 0x00: reg[0] = (V & 8) << 2; x24c01_write(reg[0xD] | reg[0]); break; // extra EEPROM x24C01 used in Battle Rush mini-cart + case 0x08: + case 0x09: reg[A] = V; BarcodeSync(); break; + case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; + case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; + case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; + case 0x0D: reg[0xD] = V & (~0x20); x24c01_write(reg[0xD] | reg[0]); x24c02_write(V); break; + } +} + static void BarcodeIRQHook(int a) { BandaiIRQHook(a); @@ -436,7 +573,7 @@ static void BarcodeIRQHook(int a) { } static DECLFR(BarcodeRead) { - return BarcodeOut; + return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut; } static void M157Power(void) { @@ -446,20 +583,29 @@ static void M157Power(void) { BarcodeOut = 0; BarcodeCycleCount = 0; - Sync(); + x24c01_init(); + x24c02_init(); + BarcodeSync(); - SetWriteHandler(0x6000, 0xFFFF, BandaiWrite); SetReadHandler(0x6000, 0x7FFF, BarcodeRead); SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite); } void Mapper157_Init(CartInfo *info) { - is153 = 1; + x24c02 = 1; info->Power = M157Power; MapIRQHook = BarcodeIRQHook; GameInfo->cspecial = SIS_DATACH; + info->battery = 1; + info->SaveGame[0] = x24c0x_data; + info->SaveGameLen[0] = 512; + AddExState(x24c0x_data, 512, 0, "DATA"); + AddExState(&x24c01StateRegs, ~0, 0, 0); + AddExState(&x24c02StateRegs, ~0, 0, 0); + GameStateRestore = StateRestore; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); } diff --git a/source/fceultra/boards/bonza.cpp b/source/fceultra/boards/bonza.cpp index 58f04f2..ac8a2cf 100644 --- a/source/fceultra/boards/bonza.cpp +++ b/source/fceultra/boards/bonza.cpp @@ -84,12 +84,12 @@ byte_8C29: .BYTE 0,$76, 0, 0, 8 byte_8CC6: .BYTE 0,$78, 0, 0,$12 */ -static uint8 sim0reset[0x1F] = { - 0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE, - 0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53, - 0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 -}; +//static uint8 sim0reset[0x1F] = { +// 0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE, +// 0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53, +// 0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10, +// 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 +//}; static void Sync(void) { setprg32(0x8000, prg_reg); diff --git a/source/fceultra/boards/cheapocabra.cpp b/source/fceultra/boards/cheapocabra.cpp index c018fd0..3183781 100644 --- a/source/fceultra/boards/cheapocabra.cpp +++ b/source/fceultra/boards/cheapocabra.cpp @@ -1,34 +1,34 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -// mapper 111 - Cheapocabra board by Memblers -// http://forums.nesdev.com/viewtopic.php?p=146039 -// -// 512k PRG-ROM in 32k pages (flashable if battery backed is specified) -// 32k CHR-ROM used as: -// 2 x 8k pattern pages -// 2 x 8k nametable pages -// -// Notes: -// - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k? - +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// mapper 111 - Cheapocabra board by Memblers +// http://forums.nesdev.com/viewtopic.php?p=146039 +// +// 512k PRG-ROM in 32k pages (flashable if battery backed is specified) +// 32k CHR-RAM used as: +// 2 x 8k pattern pages +// 2 x 8k nametable pages +// +// Notes: +// - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k? + #include "mapinc.h" #include "../ines.h" diff --git a/source/fceultra/boards/coolboy.cpp b/source/fceultra/boards/coolboy.cpp index 3224919..e220ae8 100644 --- a/source/fceultra/boards/coolboy.cpp +++ b/source/fceultra/boards/coolboy.cpp @@ -1,7 +1,7 @@ /* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2015 CaH4e3, ClusteR + * Copyright (C) 2018 CaH4e3, Cluster * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,15 +17,60 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM - * only MMC3 mode + * SMD132 and SMD133 ASICs, MMC3 clones that can address up to 32 MiB of PRG-ROM, 256 KiB of CHR-RAM, and 8 KiB of WRAM. * - * 6000 (xx76x210) | 0xC0 - * 6001 (xxx354x) - * 6002 = 0 - * 6003 = 0 + * COOLBOY cartridges use registers at address $6xxx + * MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000 + * + * $xxx0 + * 7 bit 0 + * ---- ---- + * ABCC DEEE + * |||| |||| + * |||| |+++-- PRG offset (PRG A19, A18, A17) + * |||| +----- Alternate CHR A17 + * ||++------- PRG offset (PRG A24, A23) + * |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset) + * +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate) + * + * $xxx1 + * + * 7 bit 0 + * ---- ---- + * GHIJ KKLx + * |||| ||| + * |||| ||+--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14) + * |||+-++---- PRG offset (in order: PRG A20, A22, A21) + * ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3) + * |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3) + * +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset) + * + * $xxx2 + * 7 bit 0 + * ---- ---- + * xxxx MMMM + * |||| + * ++++-- CHR offset for GNROM mode (CHR A16, A15, A14, A13) + * + * $xxx3 + * 7 bit 0 + * ---- ---- + * NPxP QQRx + * || | ||| + * || | +++--- PRG offset for GNROM mode (PRG A16, A15, A14) + * || +------- 1: GNROM mode; 0: MMC3 mode + * || | (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10; + * || | 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 ) + * |+-+------- Banking mode + * |+--------- "Weird MMC3 mode" + * +---------- Lockout (prevent further writes to these four registers, only works in MMC3 mode) + * + * Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper, + * which allows you to rewrite flash memory without soldering. + * This also allows console to write data to the cartridge. + * This behavior is not emulated. + * No cart has been discovered so far that makes use of this feature, but this can be used for homebrew. * - * hardware tested logic, don't try to understand lol */ #include "mapinc.h" @@ -71,12 +116,7 @@ static void COOLBOYPW(uint32 A, uint8 V) { // Last banks are first in this mode, ignored when MMC3_cmd&0x40 if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { switch (A & 0xE000) { - case 0xA000: - if ((MMC3_cmd & 0x40)) V = 0; - break; case 0xC000: - if (!(MMC3_cmd & 0x40)) V = 0; - break; case 0xE000: V = 0; break; @@ -115,10 +155,6 @@ static DECLFW(COOLBOYWrite) { static void COOLBOYReset(void) { MMC3RegReset(); EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; -// EXPREGS[0] = 0; -// EXPREGS[1] = 0x60; -// EXPREGS[2] = 0; -// EXPREGS[3] = 0; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } @@ -126,21 +162,52 @@ static void COOLBOYReset(void) { static void COOLBOYPower(void) { GenMMC3Power(); EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; -// EXPREGS[0] = 0; -// EXPREGS[1] = 0x60; -// EXPREGS[2] = 0; -// EXPREGS[3] = 0; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol - SetWriteHandler(0x6000, 0x7fff, COOLBOYWrite); + SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite); } +static void MINDKIDSPower(void) { + GenMMC3Power(); + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite); +} + +// Registers at $6xxx void COOLBOY_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, 0); + GenMMC3_Init(info, 2048, 256, 8, 1); pwrap = COOLBOYPW; cwrap = COOLBOYCW; info->Power = COOLBOYPower; info->Reset = COOLBOYReset; AddExState(EXPREGS, 4, 0, "EXPR"); -} \ No newline at end of file +} + +// 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; + } +} diff --git a/source/fceultra/boards/datalatch.cpp b/source/fceultra/boards/datalatch.cpp index dd8acf8..026354d 100644 --- a/source/fceultra/boards/datalatch.cpp +++ b/source/fceultra/boards/datalatch.cpp @@ -1,544 +1,543 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "mapinc.h" -#include "../ines.h" - -static uint8 latche, latcheinit, bus_conflict; -static uint16 addrreg0, addrreg1; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static void (*WSync)(void); - -static DECLFW(LatchWrite) { -// FCEU_printf("bs %04x %02x\n",A,V); - if (bus_conflict) +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mapinc.h" +#include "../ines.h" + +static uint8 latche, latcheinit, bus_conflict; +static uint16 addrreg0, addrreg1; +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; +static void (*WSync)(void); + +static DECLFW(LatchWrite) { +// FCEU_printf("bs %04x %02x\n",A,V); + if (bus_conflict) latche = V & CartBR(A); - else - latche = V; - WSync(); -} - -static void LatchPower(void) { - latche = latcheinit; - WSync(); - if (WRAM) { - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - } else { - SetReadHandler(0x8000, 0xFFFF, CartBR); - } - SetWriteHandler(addrreg0, addrreg1, LatchWrite); -} - -static void LatchClose(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - WSync(); -} - -static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 adr0, uint16 adr1, uint8 wram, uint8 busc) { - bus_conflict = busc; - latcheinit = init; - addrreg0 = adr0; - addrreg1 = adr1; - WSync = proc; - info->Power = LatchPower; - info->Close = LatchClose; - GameStateRestore = StateRestore; - if(info->ines2) - if(info->battery_wram_size + info->wram_size > 0) - wram = 1; - if (wram) - { - if(info->ines2) - { - //I would like to do it in this way, but FCEUX is woefully inadequate - //for instance if WRAMSIZE is large, the cheat pointers may get overwritten. and it's just a giant mess. - //WRAMSIZE = info->battery_wram_size + info->wram_size; - //WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - //if(!info->wram_size && !info->battery_wram_size) {} - //else if(info->wram_size && !info->battery_wram_size) - // SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1); - //else if(!info->wram_size && info->battery_wram_size) - //{ - // SetupCartPRGMapping(0x10, WRAM, info->battery_wram_size, 1); - // info->SaveGame[0] = WRAM; - // info->SaveGameLen[0] = info->battery_wram_size; - //} else { - // //well, this is annoying - // SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1); - // SetupCartPRGMapping(0x11, WRAM, info->battery_wram_size, 1); //? ? ? there probably isnt even a way to select this - // info->SaveGame[0] = WRAM + info->wram_size; - // info->SaveGameLen[0] = info->battery_wram_size; - //} - - //this is more likely the only practical scenario - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - setprg8r(0x10, 0x6000, 0); - if(info->battery_wram_size) - { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = 8192; - } - } - else - { - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - } - - } - AddExState(&latche, 1, 0, "LATC"); - AddExState(&bus_conflict, 1, 0, "BUSC"); -} - -//------------------ Map 0 --------------------------- - -#ifdef DEBUG_MAPPER -static DECLFW(NROMWrite) { - FCEU_printf("bs %04x %02x\n", A, V); - CartBW(A, V); -} -#endif - -static void NROMPower(void) { - setprg8r(0x10, 0x6000, 0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB - setprg16(0x8000, ~1); - setprg16(0xC000, ~0); - setchr8(0); - - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - + else + latche = V; + WSync(); +} + +static void LatchPower(void) { + latche = latcheinit; + WSync(); + if (WRAM) { + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } else { + SetReadHandler(0x8000, 0xFFFF, CartBR); + } + SetWriteHandler(addrreg0, addrreg1, LatchWrite); +} + +static void LatchClose(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) { + WSync(); +} + +static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 adr0, uint16 adr1, uint8 wram, uint8 busc) { + bus_conflict = busc; + latcheinit = init; + addrreg0 = adr0; + addrreg1 = adr1; + WSync = proc; + info->Power = LatchPower; + info->Close = LatchClose; + GameStateRestore = StateRestore; + if(info->ines2) + if(info->battery_wram_size + info->wram_size > 0) + wram = 1; + if (wram) + { + if(info->ines2) + { + //I would like to do it in this way, but FCEUX is woefully inadequate + //for instance if WRAMSIZE is large, the cheat pointers may get overwritten. and it's just a giant mess. + //WRAMSIZE = info->battery_wram_size + info->wram_size; + //WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + //if(!info->wram_size && !info->battery_wram_size) {} + //else if(info->wram_size && !info->battery_wram_size) + // SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1); + //else if(!info->wram_size && info->battery_wram_size) + //{ + // SetupCartPRGMapping(0x10, WRAM, info->battery_wram_size, 1); + // info->SaveGame[0] = WRAM; + // info->SaveGameLen[0] = info->battery_wram_size; + //} else { + // //well, this is annoying + // SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1); + // SetupCartPRGMapping(0x11, WRAM, info->battery_wram_size, 1); //? ? ? there probably isnt even a way to select this + // info->SaveGame[0] = WRAM + info->wram_size; + // info->SaveGameLen[0] = info->battery_wram_size; + //} + + //this is more likely the only practical scenario + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + setprg8r(0x10, 0x6000, 0); + if(info->battery_wram_size) + { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = 8192; + } + } + else + { + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } + + } + AddExState(&latche, 1, 0, "LATC"); +} + +//------------------ Map 0 --------------------------- + +#ifdef DEBUG_MAPPER +static DECLFW(NROMWrite) { + FCEU_printf("bs %04x %02x\n", A, V); + CartBW(A, V); +} +#endif + +static void NROMPower(void) { + setprg8r(0x10, 0x6000, 0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB + setprg16(0x8000, ~1); + setprg16(0xC000, ~0); + setchr8(0); + + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetReadHandler(0x8000, 0xFFFF, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - -#ifdef DEBUG_MAPPER - SetWriteHandler(0x4020, 0xFFFF, NROMWrite); - #endif -} - -void NROM_Init(CartInfo *info) { - info->Power = NROMPower; - info->Close = LatchClose; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); -} - -//------------------ Map 2 --------------------------- - -static void UNROMSync(void) { -// static uint32 mirror_in_use = 0; -// if (PRGsize[0] <= 128 * 1024) { -// setprg16(0x8000, latche & 0x7); -// if (latche & 8) mirror_in_use = 1; -// if (mirror_in_use) -// setmirror(((latche >> 3) & 1) ^ 1); // Higway Star Hacked mapper, disabled till new mapper defined -// } else - setprg16(0x8000, latche); - setprg16(0xc000, ~0); - setchr8(0); -} - -void UNROM_Init(CartInfo *info) { - Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 0, 1); -} - -//------------------ Map 3 --------------------------- - -static void CNROMSync(void) { - setchr8(latche); - setprg32(0x8000, 0); - setprg8r(0x10, 0x6000, 0); // Hayauchy IGO uses 2Kb or RAM -} - -void CNROM_Init(CartInfo *info) { - Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, 1); -} - -//------------------ Map 7 --------------------------- - -static void ANROMSync() { - setprg32(0x8000, latche & 0xF); - setmirror(MI_0 + ((latche >> 4) & 1)); - setchr8(0); -} - -void ANROM_Init(CartInfo *info) { - Latch_Init(info, ANROMSync, 0, 0x4020, 0xFFFF, 0, 0); -} - -//------------------ Map 8 --------------------------- - -static void M8Sync() { - setprg16(0x8000, latche >> 3); - setprg16(0xc000, 1); - setchr8(latche & 3); -} - -void Mapper8_Init(CartInfo *info) { - Latch_Init(info, M8Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 11 --------------------------- - -static void M11Sync(void) { - setprg32(0x8000, latche & 0xF); - setchr8(latche >> 4); -} - -void Mapper11_Init(CartInfo *info) { - Latch_Init(info, M11Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -void Mapper144_Init(CartInfo *info) { - Latch_Init(info, M11Sync, 0, 0x8001, 0xFFFF, 0, 0); -} - -//------------------ Map 13 --------------------------- - -static void CPROMSync(void) { - setchr4(0x0000, 0); - setchr4(0x1000, latche & 3); - setprg32(0x8000, 0); -} - -void CPROM_Init(CartInfo *info) { - Latch_Init(info, CPROMSync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 29 --------------------------- //Used by Glider, http://www.retrousb.com/product_info.php?cPath=30&products_id=58 - -static void M29Sync() { - setprg16(0x8000, (latche & 0x1C) >> 2); - setprg16(0xc000, ~0); - setchr8r(0, latche & 3); - setprg8r(0x10, 0x6000, 0); -} - -void Mapper29_Init(CartInfo *info) { - Latch_Init(info, M29Sync, 0, 0x8000, 0xFFFF, 1, 0); -} - - -//------------------ Map 38 --------------------------- - -static void M38Sync(void) { - setprg32(0x8000, latche & 3); - setchr8(latche >> 2); -} - -void Mapper38_Init(CartInfo *info) { - Latch_Init(info, M38Sync, 0, 0x7000, 0x7FFF, 0, 0); -} - -//------------------ Map 66 --------------------------- - -static void MHROMSync(void) { - setprg32(0x8000, latche >> 4); - setchr8(latche & 0xF); -} - -void MHROM_Init(CartInfo *info) { - Latch_Init(info, MHROMSync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 70 --------------------------- - -static void M70Sync() { - setprg16(0x8000, latche >> 4); - setprg16(0xc000, ~0); - setchr8(latche & 0xf); -} - -void Mapper70_Init(CartInfo *info) { - Latch_Init(info, M70Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 78 --------------------------- -/* Should be two separate emulation functions for this "mapper". Sigh. URGE TO KILL RISING. */ -static void M78Sync() { - setprg16(0x8000, (latche & 7)); - setprg16(0xc000, ~0); - setchr8(latche >> 4); - setmirror(MI_0 + ((latche >> 3) & 1)); -} - -void Mapper78_Init(CartInfo *info) { - Latch_Init(info, M78Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 86 --------------------------- - -static void M86Sync(void) { - setprg32(0x8000, (latche >> 4) & 3); - setchr8((latche & 3) | ((latche >> 4) & 4)); -} - -void Mapper86_Init(CartInfo *info) { - Latch_Init(info, M86Sync, ~0, 0x6000, 0x6FFF, 0, 0); -} - -//------------------ Map 87 --------------------------- - -static void M87Sync(void) { - setprg32(0x8000, 0); - setchr8(((latche >> 1) & 1) | ((latche << 1) & 2)); -} - -void Mapper87_Init(CartInfo *info) { - Latch_Init(info, M87Sync, ~0, 0x6000, 0xFFFF, 0, 0); -} - -//------------------ Map 89 --------------------------- - -static void M89Sync(void) { - setprg16(0x8000, (latche >> 4) & 7); - setprg16(0xc000, ~0); - setchr8((latche & 7) | ((latche >> 4) & 8)); - setmirror(MI_0 + ((latche >> 3) & 1)); -} - -void Mapper89_Init(CartInfo *info) { - Latch_Init(info, M89Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 93 --------------------------- - -static void SSUNROMSync(void) { - setprg16(0x8000, latche >> 4); - setprg16(0xc000, ~0); - setchr8(0); -} - -void SUNSOFT_UNROM_Init(CartInfo *info) { - Latch_Init(info, SSUNROMSync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 94 --------------------------- - -static void M94Sync(void) { - setprg16(0x8000, latche >> 2); - setprg16(0xc000, ~0); - setchr8(0); -} - -void Mapper94_Init(CartInfo *info) { - Latch_Init(info, M94Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 97 --------------------------- - -static void M97Sync(void) { - setchr8(0); - setprg16(0x8000, ~0); - setprg16(0xc000, latche & 15); - switch (latche >> 6) { - case 0: break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_V); break; - case 3: break; - } - setchr8(((latche >> 1) & 1) | ((latche << 1) & 2)); -} - -void Mapper97_Init(CartInfo *info) { - Latch_Init(info, M97Sync, ~0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 101 --------------------------- - -static void M101Sync(void) { - setprg32(0x8000, 0); - setchr8(latche); -} - -void Mapper101_Init(CartInfo *info) { - Latch_Init(info, M101Sync, ~0, 0x6000, 0x7FFF, 0, 0); -} - -//------------------ Map 107 --------------------------- - -static void M107Sync(void) { - setprg32(0x8000, (latche >> 1) & 3); - setchr8(latche & 7); -} - -void Mapper107_Init(CartInfo *info) { - Latch_Init(info, M107Sync, ~0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 113 --------------------------- - -static void M113Sync(void) { - setprg32(0x8000, (latche >> 3) & 7); - setchr8(((latche >> 3) & 8) | (latche & 7)); -// setmirror(latche>>7); // only for HES 6in1 -} - -void Mapper113_Init(CartInfo *info) { - Latch_Init(info, M113Sync, 0, 0x4100, 0x7FFF, 0, 0); -} - -//------------------ Map 140 --------------------------- - -void Mapper140_Init(CartInfo *info) { - Latch_Init(info, MHROMSync, 0, 0x6000, 0x7FFF, 0, 0); -} - -//------------------ Map 152 --------------------------- - -static void M152Sync() { - setprg16(0x8000, (latche >> 4) & 7); - setprg16(0xc000, ~0); - setchr8(latche & 0xf); - setmirror(MI_0 + ((latche >> 7) & 1)); /* Saint Seiya...hmm. */ -} - -void Mapper152_Init(CartInfo *info) { - Latch_Init(info, M152Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 180 --------------------------- - -static void M180Sync(void) { - setprg16(0x8000, 0); - setprg16(0xc000, latche); - setchr8(0); -} - -void Mapper180_Init(CartInfo *info) { - Latch_Init(info, M180Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 184 --------------------------- - -static void M184Sync(void) { - setchr4(0x0000, latche); - setchr4(0x1000, latche >> 4); - setprg32(0x8000, 0); -} - -void Mapper184_Init(CartInfo *info) { - Latch_Init(info, M184Sync, 0, 0x6000, 0x7FFF, 0, 0); -} - -//------------------ Map 203 --------------------------- - -static void M203Sync(void) { - setprg16(0x8000, (latche >> 2) & 3); - setprg16(0xC000, (latche >> 2) & 3); - setchr8(latche & 3); -} - -void Mapper203_Init(CartInfo *info) { - Latch_Init(info, M203Sync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ Map 240 --------------------------- - -static void M240Sync(void) { - setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, latche >> 4); - setchr8(latche & 0xF); -} - -void Mapper240_Init(CartInfo *info) { - Latch_Init(info, M240Sync, 0, 0x4020, 0x5FFF, 1, 0); -} - -//------------------ Map 241 --------------------------- -// Mapper 7 mostly, but with SRAM or maybe prot circuit -// figure out, which games do need 5xxx area reading - -static void M241Sync(void) { - setchr8(0); - setprg8r(0x10, 0x6000, 0); - if (latche & 0x80) - setprg32(0x8000, latche | 8); // no 241 actually, but why not afterall? - else - setprg32(0x8000, latche); -} - -void Mapper241_Init(CartInfo *info) { - Latch_Init(info, M241Sync, 0, 0x8000, 0xFFFF, 1, 0); -} - -//------------------ A65AS --------------------------- - -// actually, there is two cart in one... First have extra mirroring -// mode (one screen) and 32K bankswitching, second one have only -// 16 bankswitching mode and normal mirroring... But there is no any -// correlations between modes and they can be used in one mapper code. - -static void BMCA65ASSync(void) { - if (latche & 0x40) - setprg32(0x8000, (latche >> 1) & 0x0F); - else { - setprg16(0x8000, ((latche & 0x30) >> 1) | (latche & 7)); - setprg16(0xC000, ((latche & 0x30) >> 1) | 7); - } - setchr8(0); - if (latche & 0x80) - setmirror(MI_0 + (((latche >> 5) & 1))); - else - setmirror(((latche >> 3) & 1) ^ 1); -} - -void BMCA65AS_Init(CartInfo *info) { - Latch_Init(info, BMCA65ASSync, 0, 0x8000, 0xFFFF, 0, 0); -} - -//------------------ BMC-11160 --------------------------- -// Simple BMC discrete mapper by TXC - -static void BMC11160Sync(void) { - uint32 bank = (latche >> 4) & 7; - setprg32(0x8000, bank); - setchr8((bank << 2) | (latche & 3)); - setmirror((latche >> 7) & 1); -} - -void BMC11160_Init(CartInfo *info) { - Latch_Init(info, BMC11160Sync, 0, 0x8000, 0xFFFF, 0, 0); -} + +#ifdef DEBUG_MAPPER + SetWriteHandler(0x4020, 0xFFFF, NROMWrite); + #endif +} + +void NROM_Init(CartInfo *info) { + info->Power = NROMPower; + info->Close = LatchClose; + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); +} + +//------------------ Map 2 --------------------------- + +static void UNROMSync(void) { +// static uint32 mirror_in_use = 0; +// if (PRGsize[0] <= 128 * 1024) { +// setprg16(0x8000, latche & 0x7); +// if (latche & 8) mirror_in_use = 1; +// if (mirror_in_use) +// setmirror(((latche >> 3) & 1) ^ 1); // Higway Star Hacked mapper, disabled till new mapper defined +// } else + setprg16(0x8000, latche); + setprg16(0xc000, ~0); + setchr8(0); +} + +void UNROM_Init(CartInfo *info) { + Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 0, info->ines2 && info->submapper == 2); +} + +//------------------ Map 3 --------------------------- + +static void CNROMSync(void) { + setchr8(latche); + setprg32(0x8000, 0); + setprg8r(0x10, 0x6000, 0); // Hayauchy IGO uses 2Kb or RAM +} + +void CNROM_Init(CartInfo *info) { + Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, info->ines2 && info->submapper == 2); +} + +//------------------ Map 7 --------------------------- + +static void ANROMSync() { + setprg32(0x8000, latche & 0xF); + setmirror(MI_0 + ((latche >> 4) & 1)); + setchr8(0); +} + +void ANROM_Init(CartInfo *info) { + Latch_Init(info, ANROMSync, 0, 0x4020, 0xFFFF, 0, 0); +} + +//------------------ Map 8 --------------------------- + +static void M8Sync() { + setprg16(0x8000, latche >> 3); + setprg16(0xc000, 1); + setchr8(latche & 3); +} + +void Mapper8_Init(CartInfo *info) { + Latch_Init(info, M8Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 11 --------------------------- + +static void M11Sync(void) { + setprg32(0x8000, latche & 0xF); + setchr8(latche >> 4); +} + +void Mapper11_Init(CartInfo *info) { + Latch_Init(info, M11Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +void Mapper144_Init(CartInfo *info) { + Latch_Init(info, M11Sync, 0, 0x8001, 0xFFFF, 0, 0); +} + +//------------------ Map 13 --------------------------- + +static void CPROMSync(void) { + setchr4(0x0000, 0); + setchr4(0x1000, latche & 3); + setprg32(0x8000, 0); +} + +void CPROM_Init(CartInfo *info) { + Latch_Init(info, CPROMSync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 29 --------------------------- //Used by Glider, http://www.retrousb.com/product_info.php?cPath=30&products_id=58 + +static void M29Sync() { + setprg16(0x8000, (latche & 0x1C) >> 2); + setprg16(0xc000, ~0); + setchr8r(0, latche & 3); + setprg8r(0x10, 0x6000, 0); +} + +void Mapper29_Init(CartInfo *info) { + Latch_Init(info, M29Sync, 0, 0x8000, 0xFFFF, 1, 0); +} + + +//------------------ Map 38 --------------------------- + +static void M38Sync(void) { + setprg32(0x8000, latche & 3); + setchr8(latche >> 2); +} + +void Mapper38_Init(CartInfo *info) { + Latch_Init(info, M38Sync, 0, 0x7000, 0x7FFF, 0, 0); +} + +//------------------ Map 66 --------------------------- + +static void MHROMSync(void) { + setprg32(0x8000, latche >> 4); + setchr8(latche & 0xF); +} + +void MHROM_Init(CartInfo *info) { + Latch_Init(info, MHROMSync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 70 --------------------------- + +static void M70Sync() { + setprg16(0x8000, latche >> 4); + setprg16(0xc000, ~0); + setchr8(latche & 0xf); +} + +void Mapper70_Init(CartInfo *info) { + Latch_Init(info, M70Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 78 --------------------------- +/* Should be two separate emulation functions for this "mapper". Sigh. URGE TO KILL RISING. */ +static void M78Sync() { + setprg16(0x8000, (latche & 7)); + setprg16(0xc000, ~0); + setchr8(latche >> 4); + setmirror(MI_0 + ((latche >> 3) & 1)); +} + +void Mapper78_Init(CartInfo *info) { + Latch_Init(info, M78Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 86 --------------------------- + +static void M86Sync(void) { + setprg32(0x8000, (latche >> 4) & 3); + setchr8((latche & 3) | ((latche >> 4) & 4)); +} + +void Mapper86_Init(CartInfo *info) { + Latch_Init(info, M86Sync, ~0, 0x6000, 0x6FFF, 0, 0); +} + +//------------------ Map 87 --------------------------- + +static void M87Sync(void) { + setprg32(0x8000, 0); + setchr8(((latche >> 1) & 1) | ((latche << 1) & 2)); +} + +void Mapper87_Init(CartInfo *info) { + Latch_Init(info, M87Sync, ~0, 0x6000, 0xFFFF, 0, 0); +} + +//------------------ Map 89 --------------------------- + +static void M89Sync(void) { + setprg16(0x8000, (latche >> 4) & 7); + setprg16(0xc000, ~0); + setchr8((latche & 7) | ((latche >> 4) & 8)); + setmirror(MI_0 + ((latche >> 3) & 1)); +} + +void Mapper89_Init(CartInfo *info) { + Latch_Init(info, M89Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 93 --------------------------- + +static void SSUNROMSync(void) { + setprg16(0x8000, latche >> 4); + setprg16(0xc000, ~0); + setchr8(0); +} + +void SUNSOFT_UNROM_Init(CartInfo *info) { + Latch_Init(info, SSUNROMSync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 94 --------------------------- + +static void M94Sync(void) { + setprg16(0x8000, latche >> 2); + setprg16(0xc000, ~0); + setchr8(0); +} + +void Mapper94_Init(CartInfo *info) { + Latch_Init(info, M94Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 97 --------------------------- + +static void M97Sync(void) { + setchr8(0); + setprg16(0x8000, ~0); + setprg16(0xc000, latche & 15); + switch (latche >> 6) { + case 0: break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_V); break; + case 3: break; + } + setchr8(((latche >> 1) & 1) | ((latche << 1) & 2)); +} + +void Mapper97_Init(CartInfo *info) { + Latch_Init(info, M97Sync, ~0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 101 --------------------------- + +static void M101Sync(void) { + setprg32(0x8000, 0); + setchr8(latche); +} + +void Mapper101_Init(CartInfo *info) { + Latch_Init(info, M101Sync, ~0, 0x6000, 0x7FFF, 0, 0); +} + +//------------------ Map 107 --------------------------- + +static void M107Sync(void) { + setprg32(0x8000, (latche >> 1) & 3); + setchr8(latche & 7); +} + +void Mapper107_Init(CartInfo *info) { + Latch_Init(info, M107Sync, ~0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 113 --------------------------- + +static void M113Sync(void) { + setprg32(0x8000, (latche >> 3) & 7); + setchr8(((latche >> 3) & 8) | (latche & 7)); +// setmirror(latche>>7); // only for HES 6in1 +} + +void Mapper113_Init(CartInfo *info) { + Latch_Init(info, M113Sync, 0, 0x4100, 0x7FFF, 0, 0); +} + +//------------------ Map 140 --------------------------- + +void Mapper140_Init(CartInfo *info) { + Latch_Init(info, MHROMSync, 0, 0x6000, 0x7FFF, 0, 0); +} + +//------------------ Map 152 --------------------------- + +static void M152Sync() { + setprg16(0x8000, (latche >> 4) & 7); + setprg16(0xc000, ~0); + setchr8(latche & 0xf); + setmirror(MI_0 + ((latche >> 7) & 1)); /* Saint Seiya...hmm. */ +} + +void Mapper152_Init(CartInfo *info) { + Latch_Init(info, M152Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 180 --------------------------- + +static void M180Sync(void) { + setprg16(0x8000, 0); + setprg16(0xc000, latche); + setchr8(0); +} + +void Mapper180_Init(CartInfo *info) { + Latch_Init(info, M180Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 184 --------------------------- + +static void M184Sync(void) { + setchr4(0x0000, latche); + setchr4(0x1000, latche >> 4); + setprg32(0x8000, 0); +} + +void Mapper184_Init(CartInfo *info) { + Latch_Init(info, M184Sync, 0, 0x6000, 0x7FFF, 0, 0); +} + +//------------------ Map 203 --------------------------- + +static void M203Sync(void) { + setprg16(0x8000, (latche >> 2) & 3); + setprg16(0xC000, (latche >> 2) & 3); + setchr8(latche & 3); +} + +void Mapper203_Init(CartInfo *info) { + Latch_Init(info, M203Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ Map 240 --------------------------- + +static void M240Sync(void) { + setprg8r(0x10, 0x6000, 0); + setprg32(0x8000, latche >> 4); + setchr8(latche & 0xF); +} + +void Mapper240_Init(CartInfo *info) { + Latch_Init(info, M240Sync, 0, 0x4020, 0x5FFF, 1, 0); +} + +//------------------ Map 241 --------------------------- +// Mapper 7 mostly, but with SRAM or maybe prot circuit +// figure out, which games do need 5xxx area reading + +static void M241Sync(void) { + setchr8(0); + setprg8r(0x10, 0x6000, 0); + if (latche & 0x80) + setprg32(0x8000, latche | 8); // no 241 actually, but why not afterall? + else + setprg32(0x8000, latche); +} + +void Mapper241_Init(CartInfo *info) { + Latch_Init(info, M241Sync, 0, 0x8000, 0xFFFF, 1, 0); +} + +//------------------ A65AS --------------------------- + +// actually, there is two cart in one... First have extra mirroring +// mode (one screen) and 32K bankswitching, second one have only +// 16 bankswitching mode and normal mirroring... But there is no any +// correlations between modes and they can be used in one mapper code. + +static void BMCA65ASSync(void) { + if (latche & 0x40) + setprg32(0x8000, (latche >> 1) & 0x0F); + else { + setprg16(0x8000, ((latche & 0x30) >> 1) | (latche & 7)); + setprg16(0xC000, ((latche & 0x30) >> 1) | 7); + } + setchr8(0); + if (latche & 0x80) + setmirror(MI_0 + (((latche >> 5) & 1))); + else + setmirror(((latche >> 3) & 1) ^ 1); +} + +void BMCA65AS_Init(CartInfo *info) { + Latch_Init(info, BMCA65ASSync, 0, 0x8000, 0xFFFF, 0, 0); +} + +//------------------ BMC-11160 --------------------------- +// Simple BMC discrete mapper by TXC + +static void BMC11160Sync(void) { + uint32 bank = (latche >> 4) & 7; + setprg32(0x8000, bank); + setchr8((bank << 2) | (latche & 3)); + setmirror((latche >> 7) & 1); +} + +void BMC11160_Init(CartInfo *info) { + Latch_Init(info, BMC11160Sync, 0, 0x8000, 0xFFFF, 0, 0); +} diff --git a/source/fceultra/boards/emu2413.c b/source/fceultra/boards/emu2413.c index 240aeb0..8b6035c 100644 --- a/source/fceultra/boards/emu2413.c +++ b/source/fceultra/boards/emu2413.c @@ -53,22 +53,22 @@ #include "emu2413.h" static const unsigned char default_inst[15][8] = { - /* VRC7 instruments, January 17, 2004 update -Xodnizel */ - { 0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17 }, - { 0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12 }, - { 0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02 }, - { 0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27 }, - { 0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28 }, - { 0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95 }, - { 0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07 }, - { 0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15 }, - { 0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11 }, - { 0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12 }, - { 0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4 }, - { 0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16 }, - { 0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51 }, - { 0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05 }, - { 0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17 }, + /* VRC7 instruments, March 15, 2019 dumped by Nuke.YKT */ + { 0x03, 0x21, 0x05, 0x06, 0xE8, 0x81, 0x42, 0x27 }, + { 0x13, 0x41, 0x14, 0x0D, 0xD8, 0xF6, 0x23, 0x12 }, + { 0x11, 0x11, 0x08, 0x08, 0xFA, 0xB2, 0x20, 0x12 }, + { 0x31, 0x61, 0x0C, 0x07, 0xA8, 0x64, 0x61, 0x27 }, + { 0x32, 0x21, 0x1E, 0x06, 0xE1, 0x76, 0x01, 0x28 }, + { 0x02, 0x01, 0x06, 0x00, 0xA3, 0xE2, 0xF4, 0xF4 }, + { 0x21, 0x61, 0x1D, 0x07, 0x82, 0x81, 0x11, 0x07 }, + { 0x23, 0x21, 0x22, 0x17, 0xA2, 0x72, 0x01, 0x17 }, + { 0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 }, + { 0xB5, 0x01, 0x0F, 0x0F, 0xA8, 0xA5, 0x51, 0x02 }, + { 0x17, 0xC1, 0x24, 0x07, 0xF8, 0xF8, 0x22, 0x12 }, + { 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 }, + { 0x01, 0x02, 0xD3, 0x05, 0xC9, 0x95, 0x03, 0x02 }, + { 0x61, 0x63, 0x0C, 0x00, 0x94, 0xC0, 0x33, 0xF6 }, + { 0x21, 0x72, 0x0D, 0x00, 0xC1, 0xD5, 0x56, 0x06 }, }; /* Size of Sintable ( 8 -- 18 can be used. 9 recommended.)*/ @@ -604,8 +604,8 @@ void OPLL_reset(OPLL * opll) { for (i = 0; i < 0x40; i++) OPLL_writeReg(opll, i, 0); - opll->realstep = (uint32)((1 << 31) / rate); - opll->opllstep = (uint32)((1 << 31) / (clk / 72)); + opll->realstep = (uint32)((1u << 31) / rate); + opll->opllstep = (uint32)((1u << 31) / (clk / 72)); opll->oplltime = 0; } diff --git a/source/fceultra/boards/emu2413.h b/source/fceultra/boards/emu2413.h index 1dd0e23..2eb42ca 100644 --- a/source/fceultra/boards/emu2413.h +++ b/source/fceultra/boards/emu2413.h @@ -1,18 +1,18 @@ #ifndef _EMU2413_H_ #define _EMU2413_H_ -#ifndef INLINE -#if defined(_MSC_VER) -#define INLINE __forceinline -#elif defined(__GNUC__) -#define INLINE __inline__ -#elif defined(_MWERKS_) -#define INLINE inline -#else -#define INLINE -#endif -#endif - +#ifndef INLINE +#if defined(_MSC_VER) +#define INLINE __forceinline +#elif defined(__GNUC__) +#define INLINE __inline__ +#elif defined(_MWERKS_) +#define INLINE inline +#else +#define INLINE +#endif +#endif + #ifdef __cplusplus extern "C" { #endif @@ -27,14 +27,14 @@ typedef int16_t int16 ; typedef uint32_t uint32 ; typedef int32_t int32 ; #else -typedef unsigned char uint8 ; -typedef signed char int8 ; - -typedef unsigned short uint16 ; -typedef signed short int16 ; - -typedef unsigned int uint32 ; -typedef signed int int32 ; +typedef unsigned char uint8 ; +typedef signed char int8 ; + +typedef unsigned short uint16 ; +typedef signed short int16 ; + +typedef unsigned int uint32 ; +typedef signed int int32 ; #endif #define PI 3.14159265358979323846 diff --git a/source/fceultra/boards/fk23c.cpp b/source/fceultra/boards/fk23c.cpp index d7b3889..e0df71d 100644 --- a/source/fceultra/boards/fk23c.cpp +++ b/source/fceultra/boards/fk23c.cpp @@ -82,10 +82,10 @@ static int prg_mask; //PRG wrapper static void BMCFK23CPW(uint32 A, uint8 V) { - uint32 bank = (EXPREGS[1] & 0x1F); - uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0); - uint32 block = (EXPREGS[1] & 0x60) | hiblock; - uint32 extra = (EXPREGS[3] & 2); + //uint32 bank = (EXPREGS[1] & 0x1F); + //uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0); + //uint32 block = (EXPREGS[1] & 0x60) | hiblock; + //uint32 extra = (EXPREGS[3] & 2); // FCEU_printf("0:%04X:%02X\n",A,V); if((EXPREGS[0]&7)==4) @@ -161,7 +161,7 @@ static DECLFW(BMCFK23CWrite) EXPREGS[A&3]=V; // BUT WHY is there any rom that need it actually? - bool remap = false; +// bool remap = false; // FCEU_printf("K3:(exp0=%02x)\n",EXPREGS[0]); // FCEU_printf("WH0:%04X:%02X\n",A,V); @@ -199,7 +199,7 @@ static void BMCFK23CReset(void) //this little hack makes sure that we try all the dip switch settings eventually, if we reset enough dipswitch++; dipswitch&=7; - printf("BMCFK23C dipswitch set to %d\n",dipswitch); + printf("BMCFK23C dipswitch set to %u\n",dipswitch); EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0; EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF; diff --git a/source/fceultra/boards/mmc3.cpp b/source/fceultra/boards/mmc3.cpp index 6a93ba9..880a607 100644 --- a/source/fceultra/boards/mmc3.cpp +++ b/source/fceultra/boards/mmc3.cpp @@ -113,6 +113,9 @@ void MMC3RegReset(void) { DRegBuf[6] = 0; DRegBuf[7] = 1; +// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support + kt_extra = 0; + FixMMC3PRG(0); FixMMC3CHR(0); } @@ -187,7 +190,14 @@ DECLFW(MMC3_IRQWrite) { DECLFW(KT008HackWrite) { // FCEU_printf("%04x:%04x\n",A,V); switch (A & 3) { - case 0: kt_extra = V; FixMMC3PRG(MMC3_cmd); break; + case 0: { + if (V == 0x27) // FF Xn hack! one more mapper in one + kt_extra = 0; + else + kt_extra = V; + FixMMC3PRG(MMC3_cmd); + break; + } case 1: break; // unk case 2: break; // unk case 3: break; // unk @@ -1353,3 +1363,30 @@ void TQROM_Init(CartInfo *info) { void HKROM_Init(CartInfo *info) { GenMMC3_Init(info, 512, 512, 1, info->battery); } + +// -------------------------------- iNES 2.0 ---------------------------- + +// ---------------------------- Mapper 406 ------------------------------ + +static DECLFW(M406CMDWrite) { + MMC3_CMDWrite((A & 0xFFFE) | ((A & 2) >> 1), V); +} + +static DECLFW(M406IRQWrite) { + MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V); +} + +static DECLFW(M406Write) { +} + +static void M406_Power(void) { + GenMMC3Power(); + // TODO : FLASH + SetWriteHandler(0x8000, 0xBFFF, M406CMDWrite); + SetWriteHandler(0xC000, 0xFFFF, M406IRQWrite); +} + +void Mapper406_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 256, 0, 0); + info->Power = M406_Power; +} diff --git a/source/fceultra/boards/mmc5.cpp b/source/fceultra/boards/mmc5.cpp index e11ca08..ac98d57 100644 --- a/source/fceultra/boards/mmc5.cpp +++ b/source/fceultra/boards/mmc5.cpp @@ -22,6 +22,8 @@ #include "mapinc.h" +#include + #define ABANKS MMC5SPRVPage #define BBANKS MMC5BGVPage #define SpriteON (PPU[1] & 0x10) //Show Sprite @@ -81,10 +83,11 @@ static INLINE void MMC5BGVROM_BANK8(uint32 V) { } } -static uint8 PRGBanks[4]; +static std::array PRGBanks; static uint8 WRAMPage; -static uint16 CHRBanksA[8], CHRBanksB[4]; -static uint8 WRAMMaskEnable[2]; +static std::array CHRBanksA; +static std::array CHRBanksB; +static std::array WRAMMaskEnable; uint8 mmc5ABMode; /* A=0, B=1 */ static uint8 IRQScanline, IRQEnable; @@ -93,18 +96,20 @@ static uint8 CHRMode, NTAMirroring, NTFill, ATFill; static uint8 MMC5IRQR; static uint8 MMC5LineCounter; static uint8 mmc5psize, mmc5vsize; -static uint8 mul[2]; +static std::array mul; static uint32 WRAMSIZE = 0; static uint8 *WRAM = NULL; static uint8 *MMC5fill = NULL; static uint8 *ExRAM = NULL; +static uint8 MMC5battery = 0; -static uint8 MMC5WRAMsize; //configuration, not state -static uint8 MMC5WRAMIndex[8]; //configuration, not state +const int MMC5WRAMMAX = 1<<7; // 7 bits in register interface (real MMC5 has only 4 pins, however) +static uint8 MMC5WRAMsize=0; //configuration, not state +static uint8 MMC5WRAMIndex[MMC5WRAMMAX]; //configuration, not state -static uint8 MMC5ROMWrProtect[4]; -static uint8 MMC5MemIn[5]; +static std::array MMC5ROMWrProtect; +static std::array MMC5MemIn; static void MMC5CHRA(void); static void MMC5CHRB(void); @@ -146,12 +151,18 @@ uint8* MMC5BGVRAMADR(uint32 A) static void mmc5_PPUWrite(uint32 A, uint8 V) { uint32 tmp = A; extern uint8 PALRAM[0x20]; + extern uint8 UPALRAM[0x03]; if (tmp >= 0x3F00) { - // hmmm.... - if (!(tmp & 0xf)) - PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; - else if (tmp & 3) PALRAM[(tmp & 0x1f)] = V & 0x3f; + if (!(tmp & 3)) { + if (!(tmp & 0xC)) { + PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; + PALRAM[0x10] = PALRAM[0x14] = PALRAM[0x18] = PALRAM[0x1C] = V & 0x3F; + } + else + UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F; + } else + PALRAM[tmp & 0x1F] = V & 0x3F; } else if (tmp < 0x2000) { if (PPUCHRRAM & (1 << (tmp >> 10))) VPage[tmp >> 10][tmp] = V; @@ -308,6 +319,8 @@ int DetectMMC5WRAMSize(uint32 crc32) { } static void BuildWRAMSizeTable(void) { + bool other = false; // non-standard configuration + // fill first 8 entries int x; for (x = 0; x < 8; x++) { switch (MMC5WRAMsize) { @@ -315,9 +328,22 @@ static void BuildWRAMSizeTable(void) { case 1: MMC5WRAMIndex[x] = (x > 3) ? 255 : 0; break; //0,0,0,0,X,X,X,X case 2: MMC5WRAMIndex[x] = (x & 4) >> 2; break; //0,0,0,0,1,1,1,1 case 4: MMC5WRAMIndex[x] = (x > 3) ? 255 : (x & 3); break; //0,1,2,3,X,X,X,X - case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7 + case 8: MMC5WRAMIndex[x] = x; break; //0,1,2,3,4,5,6,7 + default: MMC5WRAMIndex[x] = x; other = true; break; //0,1,2... } } + // extend to fill complete table + if (other) + { + for (x = 0; x < MMC5WRAMMAX && x < MMC5WRAMsize; ++x) MMC5WRAMIndex[x] = x; // linear mapping + for (x = MMC5WRAMsize; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x-MMC5WRAMsize]; // repeat to fill table + // theoretically the table fill should decompose into powers of two for possible mismatched SRAM combos, + // but I don't want to complicate the code with unnecessary hypotheticals + } + else + { + for (x = 8; x < MMC5WRAMMAX; ++x) MMC5WRAMIndex[x] = MMC5WRAMIndex[x & 7]; // fill table, repeating groups of 8 + } } static void MMC5CHRA(void) { @@ -385,7 +411,7 @@ static void MMC5CHRB(void) { } static void MMC5WRAM(uint32 A, uint32 V) { - V = MMC5WRAMIndex[V & 7]; + V = MMC5WRAMIndex[V & (MMC5WRAMMAX-1)]; if (V != 255) { setprg8r(0x10, A, V); FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1)))); @@ -410,8 +436,8 @@ static void MMC5PRG(void) { MMC5MemIn[1] = MMC5MemIn[2] = 1; } else { MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0; - MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE); - MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1); + MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE); + MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1); } MMC5MemIn[3] = MMC5MemIn[4] = 1; MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1; @@ -424,8 +450,8 @@ static void MMC5PRG(void) { setprg16(0x8000, (PRGBanks[1] & 0x7F) >> 1); } else { MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = 0; - MMC5WRAM(0x8000, PRGBanks[1] & 7 & 0xFE); - MMC5WRAM(0xA000, (PRGBanks[1] & 7 & 0xFE) + 1); + MMC5WRAM(0x8000, PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE); + MMC5WRAM(0xA000, (PRGBanks[1] & (MMC5WRAMMAX-1) & 0xFE) + 1); } if (PRGBanks[2] & 0x80) { MMC5ROMWrProtect[2] = 1; @@ -433,7 +459,7 @@ static void MMC5PRG(void) { setprg8(0xC000, PRGBanks[2] & 0x7F); } else { MMC5ROMWrProtect[2] = 0; - MMC5WRAM(0xC000, PRGBanks[2] & 7); + MMC5WRAM(0xC000, PRGBanks[2] & (MMC5WRAMMAX-1)); } MMC5MemIn[4] = 1; MMC5ROMWrProtect[3] = 1; @@ -447,7 +473,7 @@ static void MMC5PRG(void) { MMC5MemIn[1 + x] = 1; } else { MMC5ROMWrProtect[x] = 0; - MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & 7); + MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & (MMC5WRAMMAX-1)); } MMC5MemIn[4] = 1; MMC5ROMWrProtect[3] = 1; @@ -510,7 +536,7 @@ static DECLFW(Mapper5_write) { break; case 0x5113: WRAMPage = V; - MMC5WRAM(0x6000, V & 7); + MMC5WRAM(0x6000, V & (MMC5WRAMMAX-1)); break; case 0x5114: case 0x5115: @@ -606,7 +632,7 @@ void MMC5Synco(void) { case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break; } } - MMC5WRAM(0x6000, WRAMPage & 7); + MMC5WRAM(0x6000, WRAMPage & (MMC5WRAMMAX-1)); if (!mmc5ABMode) { MMC5CHRB(); MMC5CHRA(); @@ -869,22 +895,42 @@ void NSFMMC5_Close(void) { if (WRAM) FCEU_gfree(WRAM); WRAM = NULL; + MMC5WRAMsize = 0; FCEU_gfree(ExRAM); ExRAM = NULL; } -static void GenMMC5Reset(void) { - int x; +static void GenMMC5Power(void) { - for (x = 0; x < 4; x++) PRGBanks[x] = ~0; - for (x = 0; x < 8; x++) CHRBanksA[x] = ~0; - for (x = 0; x < 4; x++) CHRBanksB[x] = ~0; - WRAMMaskEnable[0] = WRAMMaskEnable[1] = ~0; - - mmc5psize = mmc5vsize = 3; + PRGBanks.fill(0xFF); + WRAMPage = 0; + CHRBanksA.fill(0xFF); + CHRBanksB.fill(0xFF); + WRAMMaskEnable.fill(0xFF); + mmc5ABMode = 0; + IRQScanline = 0; + IRQEnable = 0; CHRMode = 0; - NTAMirroring = NTFill = ATFill = 0xFF; + MMC5IRQR = 0; + MMC5LineCounter = 0; + mmc5psize = mmc5vsize = 3; + mul.fill(0); + + MMC5ROMWrProtect.fill(0); + MMC5MemIn.fill(0); + + // MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable + u8 nval = MMC5fill[0x000]; + u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6); + FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0); + FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040); + + if(MMC5battery == 0) { + FCEU_MemoryRand(WRAM, MMC5WRAMsize * 8 * 1024); + FCEU_MemoryRand(MMC5fill,1024); + FCEU_MemoryRand(ExRAM,1024); + } MMC5Synco(); @@ -907,11 +953,11 @@ static void GenMMC5Reset(void) { } static SFORMAT MMC5_StateRegs[] = { - { PRGBanks, 4, "PRGB" }, - { CHRBanksA, 16, "CHRA" }, - { CHRBanksB, 8, "CHRB" }, + { &PRGBanks, 4, "PRGB" }, + { &CHRBanksA, 16, "CHRA" }, + { &CHRBanksB, 8, "CHRB" }, { &WRAMPage, 1, "WRMP" }, - { WRAMMaskEnable, 2, "WRME" }, + { &WRAMMaskEnable, 2, "WRME" }, { &mmc5ABMode, 1, "ABMD" }, { &IRQScanline, 1, "IRQS" }, { &IRQEnable, 1, "IRQE" }, @@ -925,9 +971,9 @@ static SFORMAT MMC5_StateRegs[] = { { &MMC5LineCounter, 1, "LCTR" }, { &mmc5psize, 1, "PSIZ" }, { &mmc5vsize, 1, "VSIZ" }, - { mul, 2, "MUL2" }, - { MMC5ROMWrProtect, 4, "WRPR" }, - { MMC5MemIn, 5, "MEMI" }, + { &mul, 2, "MUL2" }, + { &MMC5ROMWrProtect, 4, "WRPR" }, + { &MMC5MemIn, 5, "MEMI" }, { &MMC5Sound.wl[0], 2 | FCEUSTATE_RLSB, "SDW0" }, { &MMC5Sound.wl[1], 2 | FCEUSTATE_RLSB, "SDW1" }, @@ -950,19 +996,17 @@ static SFORMAT MMC5_StateRegs[] = { static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { if (wsize) { - WRAM = (uint8*)FCEU_gmalloc(wsize * 1024); + WRAM = (uint8*)FCEU_malloc(wsize * 1024); + FCEU_MemoryRand(WRAM, wsize * 1024); SetupCartPRGMapping(0x10, WRAM, wsize * 1024, 1); AddExState(WRAM, wsize * 1024, 0, "WRAM"); } - MMC5fill = (uint8*)FCEU_gmalloc(1024); - ExRAM = (uint8*)FCEU_gmalloc(1024); + MMC5fill = (uint8*)FCEU_malloc(1024); + ExRAM = (uint8*)FCEU_malloc(1024); - // MMC5fill is and 8-bit tile index, and a 2-bit attribute implented as a mirrored nametable - u8 nval = MMC5fill[0x000]; - u8 aval = MMC5fill[0x3C0] & 3; aval = aval | (aval << 2) | (aval << 4) | (aval << 6); - FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0); - FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040); + FCEU_MemoryRand(MMC5fill,1024); + FCEU_MemoryRand(ExRAM,1024); AddExState(ExRAM, 1024, 0, "ERAM"); AddExState(&MMC5HackSPMode, 1, 0, "SPLM"); @@ -974,19 +1018,26 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { MMC5WRAMsize = wsize / 8; BuildWRAMSizeTable(); GameStateRestore = MMC5_StateRestore; - info->Power = GenMMC5Reset; + info->Power = GenMMC5Power; + MMC5battery = battery; if (battery) { info->SaveGame[0] = WRAM; - - //this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you - //I added 64KB for the new 64KB homebrews - if (wsize <= 16) - info->SaveGameLen[0] = 8192; - else if(wsize == 64) - info->SaveGameLen[0] = 64*1024; + if (info->ines2) + { + info->SaveGameLen[0] = info->battery_wram_size; + } else - info->SaveGameLen[0] = 32768; + { + //this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you + //I added 64KB for the new 64KB homebrews + if (wsize <= 16) + info->SaveGameLen[0] = 8192; + else if(wsize == 64) + info->SaveGameLen[0] = 64*1024; + else + info->SaveGameLen[0] = 32768; + } } MMC5HackVROMMask = CHRmask4[0]; @@ -1002,7 +1053,14 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { } void Mapper5_Init(CartInfo *info) { - WRAMSIZE = DetectMMC5WRAMSize(info->CRC32); + if (info->ines2) + { + WRAMSIZE = (info->wram_size + info->battery_wram_size) / 1024; + } + else + { + WRAMSIZE = DetectMMC5WRAMSize(info->CRC32); + } GenMMC5_Init(info, WRAMSIZE, info->battery); } diff --git a/source/fceultra/boards/n106.cpp b/source/fceultra/boards/n106.cpp index 76c9340..cbbbc79 100644 --- a/source/fceultra/boards/n106.cpp +++ b/source/fceultra/boards/n106.cpp @@ -157,7 +157,10 @@ static void FixCache(int a, int V) { case 0x02: FreqCache[w] &= ~0x0000FF00; FreqCache[w] |= V << 8; break; case 0x04: FreqCache[w] &= ~0x00030000; FreqCache[w] |= (V & 3) << 16; - LengthCache[w] = (8 - ((V >> 2) & 7)) << 2; +// something wrong here http://www.romhacking.net/forum/index.php?topic=21907.msg306903#msg306903 +// LengthCache[w] = (8 - ((V >> 2) & 7)) << 2; +// fix be like in https://github.com/SourMesen/Mesen/blob/cda0a0bdcb5525480784f4b8c71de6fc7273b570/Core/Namco163Audio.h#L61 + LengthCache[w] = 256 - (V & 0xFC); break; case 0x07: EnvCache[w] = (double)(V & 0xF) * 576716; break; } @@ -348,9 +351,9 @@ static void DoNamcoSound(int32 *Wave, int Count) { static void Mapper19_StateRestore(int version) { SyncPRG(); + SyncMirror(); FixNTAR(); FixCRR(); - SyncMirror(); int x; for (x = 0x40; x < 0x80; x++) FixCache(x, IRAM[x]); diff --git a/source/fceultra/boards/onebus.cpp b/source/fceultra/boards/onebus.cpp index 7cd23d7..4336b77 100644 --- a/source/fceultra/boards/onebus.cpp +++ b/source/fceultra/boards/onebus.cpp @@ -47,6 +47,9 @@ static int16 pcm_addr, pcm_size, pcm_latch, pcm_clock = 0xE1; static writefunc defapuwrite[64]; static readfunc defapuread[64]; +static uint32 WRAMSIZE; +static uint8 *WRAM = NULL; + static SFORMAT StateRegs[] = { { cpu410x, 16, "REGC" }, @@ -265,6 +268,13 @@ static void UNLOneBusPower(void) { SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X); SetWriteHandler(0x8000, 0xffff, UNLOneBusWriteMMC3); + if (WRAMSIZE) { + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + SetWriteHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBW); + SetReadHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBR); + setprg8r(0x10, 0x6000, 0); + } + Sync(); } @@ -282,9 +292,16 @@ static void StateRestore(int version) { Sync(); } +void UNLOneBusClose(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + void UNLOneBus_Init(CartInfo *info) { info->Power = UNLOneBusPower; info->Reset = UNLOneBusReset; + info->Close = UNLOneBusClose; if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || // PowerJoy Supermax Carts ((*(uint32*)&(info->MD5)) == 0x6abfce8e)) @@ -294,4 +311,17 @@ void UNLOneBus_Init(CartInfo *info) { MapIRQHook = UNLOneBusCpuHook; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); + + WRAMSIZE = 8 * 1024; + if (info->ines2) + WRAMSIZE = info->wram_size + info->battery_wram_size; + if (WRAMSIZE) { + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } } diff --git a/source/fceultra/boards/pec-586.cpp b/source/fceultra/boards/pec-586.cpp index 0eac60c..b7559c5 100644 --- a/source/fceultra/boards/pec-586.cpp +++ b/source/fceultra/boards/pec-586.cpp @@ -16,6 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * PEC-586 FC based computer series by DUNDA + * */ #include "mapinc.h" diff --git a/source/fceultra/boards/unrom512.cpp b/source/fceultra/boards/unrom512.cpp index ac6bd57..973749e 100644 --- a/source/fceultra/boards/unrom512.cpp +++ b/source/fceultra/boards/unrom512.cpp @@ -40,38 +40,38 @@ static uint16 latcha; static uint8 *flashdata; static uint32 *flash_write_count; static uint8 *FlashPage[32]; -static uint32 *FlashWriteCountPage[32]; -static uint8 flashloaded = false; +//static uint32 *FlashWriteCountPage[32]; +//static uint8 flashloaded = false; static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank; static void (*WLSync)(void); static void (*WHSync)(void); -static INLINE void setfpageptr(int s, uint32 A, uint8 *p) { - uint32 AB = A >> 11; - int x; - - if (p) - for (x = (s >> 1) - 1; x >= 0; x--) { - FlashPage[AB + x] = p - A; - } - else - for (x = (s >> 1) - 1; x >= 0; x--) { - FlashPage[AB + x] = 0; - } +static INLINE void setfpageptr(int s, uint32 A, uint8 *p) { + uint32 AB = A >> 11; + int x; + + if (p) + for (x = (s >> 1) - 1; x >= 0; x--) { + FlashPage[AB + x] = p - A; + } + else + for (x = (s >> 1) - 1; x >= 0; x--) { + FlashPage[AB + x] = 0; + } } -void setfprg16(uint32 A, uint32 V) { - if (PRGsize[0] >= 16384) { - V &= PRGmask16[0]; - setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0); - } else { - uint32 VA = V << 3; - int x; - - for (x = 0; x < 8; x++) - setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0); - } +void setfprg16(uint32 A, uint32 V) { + if (PRGsize[0] >= 16384) { + V &= PRGmask16[0]; + setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0); + } else { + uint32 VA = V << 3; + int x; + + for (x = 0; x < 8; x++) + setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0); + } } void inc_flash_write_count(uint8 bank, uint32 A) @@ -282,4 +282,4 @@ void UNROM512_Init(CartInfo *info) { } AddExState(&latche, 1, 0, "LATC"); AddExState(&bus_conflict, 1, 0, "BUSC"); -} \ No newline at end of file +} diff --git a/source/fceultra/boards/vrc2and4.cpp b/source/fceultra/boards/vrc2and4.cpp index 7b68fbe..97e6e53 100644 --- a/source/fceultra/boards/vrc2and4.cpp +++ b/source/fceultra/boards/vrc2and4.cpp @@ -28,7 +28,6 @@ static uint8 prgreg[2], chrreg[8]; static uint16 chrhi[8]; static uint8 regcmd, irqcmd, mirr, big_bank; static uint16 acount = 0; -static uint16 weirdo = 0; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; @@ -38,6 +37,7 @@ static SFORMAT StateRegs[] = { prgreg, 2, "PREG" }, { chrreg, 8, "CREG" }, { chrhi, 16, "CRGH" }, + { &acount, 2, "ACNT" }, { ®cmd, 1, "CMDR" }, { &irqcmd, 1, "CMDI" }, { &mirr, 1, "MIRR" }, @@ -62,15 +62,8 @@ static void Sync(void) { setchr8(0); else{ uint8 i; - //if(!weirdo) - for (i = 0; i < 8; i++) - setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22); - //else { - // setchr1(0x0000, 0xFC); - // setchr1(0x0400, 0xFD); - // setchr1(0x0800, 0xFF); - // weirdo--; - //} + for (i = 0; i < 8; i++) + setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22); } switch (mirr & 0x3) { case 0: setmirror(MI_V); break; diff --git a/source/fceultra/boards/vrc5.cpp b/source/fceultra/boards/vrc5.cpp index 6d17bd5..07de801 100644 --- a/source/fceultra/boards/vrc5.cpp +++ b/source/fceultra/boards/vrc5.cpp @@ -1,7 +1,7 @@ /* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2005-2019 CaH4e3 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,25 +17,118 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * VRC-5 (CAI Shogakko no Sansu) + * VRC-V (CAI Shogakko no Sansu) * */ #include "mapinc.h" -static uint8 QTAINTRAM[2048]; -static writefunc old2007wrap; +//#define CAI_DEBUG + +// main tiles RAM is 8K in size, but unless other non-CHR ROM type carts, +// this one accesses the $0000 and $1000 pages based on extra NT RAM on board +// which is similar to MMC5 but much simpler because there are no additional +// bankings here. +// extra NT RAM handling is in PPU code now. static uint16 CHRSIZE = 8192; -static uint16 WRAMSIZE = 8192 + 4096; +// there are two separate WRAMs 8K each, on main system cartridge (not battery +// backed), and one on the daughter cart (with battery). both are accessed +// via the same registers with additional selector flags. +static uint16 WRAMSIZE = 8192 + 8192; static uint8 *CHRRAM = NULL; static uint8 *WRAM = NULL; static uint8 IRQa, K4IRQ; static uint32 IRQLatch, IRQCount; +// some kind of 16-bit text encoding (actually 14-bit) used in game resources +// may be converted by the hardware into the tile indexes for internal CHR ROM +// not sure whey they made it hardware, because most of calculations are just +// bit shifting. the main purpose of this table is to calculate actual CHR ROM +// bank for every character. there is a some kind of regularity, so this table +// may be calculated in software easily. + +// table read out from hardware registers as is + +///* +static uint8 conv_tbl[4][8] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x40, 0x10, 0x28, 0x00, 0x18, 0x30 }, + { 0x00, 0x00, 0x48, 0x18, 0x30, 0x08, 0x20, 0x38 }, + { 0x00, 0x00, 0x80, 0x20, 0x38, 0x10, 0x28, 0xB0 } +}; +//*/ +/* +static uint8 conv_tbl[64][4] = { + { 0x40, 0x40, 0x40, 0x40 }, // 00 | A - 40 41 42 43 44 45 46 47 + { 0x41, 0x41, 0x41, 0x41 }, // 02 | B - 48 49 4A 4B 4C 4D 4E 4F + { 0x42, 0x42, 0x42, 0x42 }, // 04 | C - 50 51 52 53 54 55 56 57 + { 0x43, 0x43, 0x43, 0x43 }, // 06 | D - 58 59 5A 5B 5C 5D 5E 5F + { 0x44, 0x44, 0x44, 0x44 }, // 08 | E - 60 61 62 63 64 65 66 67 + { 0x45, 0x45, 0x45, 0x45 }, // 0A | F - 68 69 6A 6B 6C 6D 6E 6F + { 0x46, 0x46, 0x46, 0x46 }, // 0C | G - 70 71 72 73 74 75 76 77 + { 0x47, 0x47, 0x47, 0x47 }, // 0E | H - 78 79 7A 7B 7C 7D 7E 7F + { 0x40, 0x40, 0x40, 0x40 }, // 10 | + { 0x41, 0x41, 0x41, 0x41 }, // 12 +---------------------------- + { 0x42, 0x42, 0x42, 0x42 }, // 14 | A A A A + { 0x43, 0x43, 0x43, 0x43 }, // 16 | A A A A + { 0x44, 0x44, 0x44, 0x44 }, // 18 | A A' B' A" + { 0x45, 0x45, 0x45, 0x45 }, // 1A | A C D E + { 0x46, 0x46, 0x46, 0x46 }, // 1C | A F G H + { 0x47, 0x47, 0x47, 0x47 }, // 1E | A A B C + { 0x40, 0x40, 0x48, 0x44 }, // 20 | A D E F + { 0x41, 0x41, 0x49, 0x45 }, // 22 | A G H G" + { 0x42, 0x42, 0x4A, 0x46 }, // 24 +---------------------------- + { 0x43, 0x43, 0x4B, 0x47 }, // 26 | A' - 40 41 42 43 40 41 42 43 + { 0x44, 0x40, 0x48, 0x44 }, // 28 | A" - 44 45 46 47 44 45 46 47 + { 0x45, 0x41, 0x49, 0x45 }, // 2A | B' - 48 49 4A 4B 48 49 4A 4B + { 0x46, 0x42, 0x4A, 0x46 }, // 2C | G" - 74 75 76 77 74 75 76 77 + { 0x47, 0x43, 0x4B, 0x47 }, // 2E + { 0x40, 0x50, 0x58, 0x60 }, // 30 + { 0x41, 0x51, 0x59, 0x61 }, // 32 + { 0x42, 0x52, 0x5A, 0x62 }, // 34 + { 0x43, 0x53, 0x5B, 0x63 }, // 36 + { 0x44, 0x54, 0x5C, 0x64 }, // 38 + { 0x45, 0x55, 0x5D, 0x65 }, // 3A + { 0x46, 0x56, 0x5E, 0x66 }, // 3C + { 0x47, 0x57, 0x5F, 0x67 }, // 3E + { 0x40, 0x68, 0x70, 0x78 }, // 40 + { 0x41, 0x69, 0x71, 0x79 }, // 42 + { 0x42, 0x6A, 0x72, 0x7A }, // 44 + { 0x43, 0x6B, 0x73, 0x7B }, // 46 + { 0x44, 0x6C, 0x74, 0x7C }, // 48 + { 0x45, 0x6D, 0x75, 0x7D }, // 4A + { 0x46, 0x6E, 0x76, 0x7E }, // 4C + { 0x47, 0x6F, 0x77, 0x7F }, // 4E + { 0x40, 0x40, 0x48, 0x50 }, // 50 + { 0x41, 0x41, 0x49, 0x51 }, // 52 + { 0x42, 0x42, 0x4A, 0x52 }, // 54 + { 0x43, 0x43, 0x4B, 0x53 }, // 56 + { 0x44, 0x44, 0x4C, 0x54 }, // 58 + { 0x45, 0x45, 0x4D, 0x55 }, // 5A + { 0x46, 0x46, 0x4E, 0x56 }, // 5C + { 0x47, 0x47, 0x4F, 0x57 }, // 5E + { 0x40, 0x58, 0x60, 0x68 }, // 60 + { 0x41, 0x59, 0x61, 0x69 }, // 62 + { 0x42, 0x5A, 0x62, 0x6A }, // 64 + { 0x43, 0x5B, 0x63, 0x6B }, // 66 + { 0x44, 0x5C, 0x64, 0x6C }, // 68 + { 0x45, 0x5D, 0x65, 0x6D }, // 6A + { 0x46, 0x5E, 0x66, 0x6E }, // 6C + { 0x47, 0x5F, 0x67, 0x6F }, // 6E + { 0x40, 0x70, 0x78, 0x74 }, // 70 + { 0x41, 0x71, 0x79, 0x75 }, // 72 + { 0x42, 0x72, 0x7A, 0x76 }, // 74 + { 0x43, 0x73, 0x7B, 0x77 }, // 76 + { 0x44, 0x74, 0x7C, 0x74 }, // 78 + { 0x45, 0x75, 0x7D, 0x75 }, // 7A + { 0x46, 0x76, 0x7E, 0x76 }, // 7C + { 0x47, 0x77, 0x7F, 0x77 }, // 7E +}; +*/ + static uint8 regs[16]; -//static uint8 test[8]; static SFORMAT StateRegs[] = { { &IRQCount, 1, "IRQC" }, @@ -48,93 +141,68 @@ static SFORMAT StateRegs[] = static void chrSync(void) { setchr4r(0x10, 0x0000, regs[5] & 1); - setchr4r(0x10, 0x1000, 0); + // 30.06.19 CaH4e3 there is much more complicated behaviour with second banking register, you may actually + // view the content of the internal character CHR rom via this window, but it is useless because hardware + // does not use this area to access the internal ROM. not sure why they did this, but I see no need to + // emulate this behaviour carefully, unless I find something that I missed... + setchr4r(0x10, 0x1000, 1); } static void Sync(void) { chrSync(); -// if(regs[0xA]&0x10) -// { -/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); - setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); - setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); - setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); - setchr1r(0x10,0x1000,0); - setchr1r(0x10,0x1400,1); - setchr1r(0x10,0x1800,2); - setchr1r(0x10,0x1c00,3);*/ -/* setchr1r(0x10,0x0000,(((regs[5]&1))<<2)+0); - setchr1r(0x10,0x0400,(((regs[5]&1))<<2)+1); - setchr1r(0x10,0x0800,(((regs[5]&1))<<2)+2); - setchr1r(0x10,0x0c00,(((regs[5]&1))<<2)+3); - setchr1r(0x10,0x1000,(((regs[5]&1)^1)<<2)+4); - setchr1r(0x10,0x1400,(((regs[5]&1)^1)<<2)+5); - setchr1r(0x10,0x1800,(((regs[5]&1)^1)<<2)+6); - setchr1r(0x10,0x1c00,(((regs[5]&1)^1)<<2)+7); -*/ -// } -// else -// { -/* - setchr1r(0x10,0x0000,(((regs[5]&1)^1)<<2)+0); - setchr1r(0x10,0x0400,(((regs[5]&1)^1)<<2)+1); - setchr1r(0x10,0x0800,(((regs[5]&1)^1)<<2)+2); - setchr1r(0x10,0x0c00,(((regs[5]&1)^1)<<2)+3); - setchr1r(0x10,0x1000,(((regs[5]&1))<<2)+4); - setchr1r(0x10,0x1400,(((regs[5]&1))<<2)+5); - setchr1r(0x10,0x1800,(((regs[5]&1))<<2)+6); - setchr1r(0x10,0x1c00,(((regs[5]&1))<<2)+7); -// } -//*/ -/* setchr1r(1,0x0000,test[0]); - setchr1r(1,0x0400,test[1]); - setchr1r(1,0x0800,test[2]); - setchr1r(1,0x0c00,test[3]); - setchr1r(1,0x1000,test[4]); - setchr1r(1,0x1400,test[5]); - setchr1r(1,0x1800,test[6]); - setchr1r(1,0x1c00,test[7]); -*/ - setprg4r(0x10, 0x6000, regs[0] & 1); - if (regs[2] >= 0x40) - setprg8r(1, 0x8000, (regs[2] - 0x40)); - else - setprg8r(0, 0x8000, (regs[2] & 0x3F)); - if (regs[3] >= 0x40) - setprg8r(1, 0xA000, (regs[3] - 0x40)); - else - setprg8r(0, 0xA000, (regs[3] & 0x3F)); - if (regs[4] >= 0x40) - setprg8r(1, 0xC000, (regs[4] - 0x40)); - else - setprg8r(0, 0xC000, (regs[4] & 0x3F)); - - setprg8r(1, 0xE000, ~0); - setmirror(MI_V); + setprg4r(0x10, 0x6000, (regs[0] & 1) | (regs[0] >> 2)); // two 4K banks are identical, either internal or excernal + setprg4r(0x10, 0x7000, (regs[1] & 1) | (regs[1] >> 2)); // SRAMs may be mapped in any bank independently + if (PRGptr[1] == NULL) { // for iNES 2.0 version it even more hacky lol + setprg8(0x8000, (regs[2] & 0x3F) + ((regs[2] & 0x40) >> 2)); + setprg8(0xA000, (regs[3] & 0x3F) + ((regs[3] & 0x40) >> 2)); + setprg8(0xC000, (regs[4] & 0x3F) + ((regs[4] & 0x40) >> 2)); + setprg8(0xE000, 0x10 + 0x3F); + } else { + setprg8r((regs[2] >> 6) & 1, 0x8000, (regs[2] & 0x3F)); + setprg8r((regs[3] >> 6) & 1, 0xA000, (regs[3] & 0x3F)); + setprg8r((regs[4] >> 6) & 1, 0xC000, (regs[4] & 0x3F)); + setprg8r(1, 0xE000, ~0); // always sees the last bank of the external cart, so can't be booted without it. + } + setmirror(((regs[0xA]&2)>>1)^1); } -/*static DECLFW(TestWrite) -{ - test[A&7] = V; - Sync(); -}*/ - -static DECLFW(M190Write) { -// FCEU_printf("write %04x:%04x %d, %d\n",A,V,scanline,timestamp); - regs[(A & 0x0F00) >> 8] = V; +static DECLFW(QTAiWrite) { + regs[(A & 0x0F00) >> 8] = V; // IRQ pretty the same as in other VRC mappers by Konami switch (A) { case 0xd600: IRQLatch &= 0xFF00; IRQLatch |= V; break; case 0xd700: IRQLatch &= 0x00FF; IRQLatch |= V << 8; break; case 0xd900: IRQCount = IRQLatch; IRQa = V & 2; K4IRQ = V & 1; X6502_IRQEnd(FCEU_IQEXT); break; case 0xd800: IRQa = K4IRQ; X6502_IRQEnd(FCEU_IQEXT); break; + case 0xda00: qtaintramreg = regs[0xA] & 3; break; // register shadow to share it with ppu } Sync(); } -static DECLFR(M190Read) { -// FCEU_printf("read %04x:%04x %d, %d\n",A,regs[(A&0x0F00)>>8],scanline,timestamp); - return regs[(A & 0x0F00) >> 8] + regs[0x0B]; +static DECLFR(QTAiRead) { + +// uint8 res1 = conv_tbl[(regs[0xD] & 0x7F) >> 1][(regs[0xC] >> 5) & 3]; +// uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3); + + uint8 tabl = conv_tbl[(regs[0xC] >> 5) & 3][(regs[0xD] & 0x7F) >> 4]; + uint8 res1 = 0x40 | (tabl & 0x3F) | ((regs[0xD] >> 1) & 7) | ((regs[0xB] & 4) << 5); + uint8 res2 = ((regs[0xD] & 1) << 7) | ((regs[0xC] & 0x1F) << 2) | (regs[0xB] & 3); + + if (tabl & 0x40) + res1 &= 0xFB; + else if (tabl & 0x80) + res1 |= 0x04; + + if (A == 0xDD00) { + return res1; + } else if (A == 0xDC00) { +#ifdef CAI_DEBUG + FCEU_printf("%02x:%02x+%d -> %02x:%02x\n", regs[0xD], regs[0xC], regs[0xB], res1, res2); +#endif + return res2; + } else + return 0; } + static void VRC5IRQ(int a) { if (IRQa) { IRQCount += a; @@ -145,50 +213,17 @@ static void VRC5IRQ(int a) { } } -//static void Mapper190_PPU(uint32 A) -//{ -// if(A<0x2000) -// setchr4r(0x10,0x1000,QTAINTRAM[A&0x1FFF]&1); -// else -// chrSync(); -//} - -static DECLFW(M1902007Wrap) { - if (A >= 0x2000) { - if (regs[0xA] & 1) - QTAINTRAM[A & 0x1FFF] = V; - else - old2007wrap(A, V); - } -} - - -static void M190Power(void) { -/* test[0]=0; - test[1]=1; - test[2]=2; - test[3]=3; - test[4]=4; - test[5]=5; - test[6]=6; - test[7]=7; -*/ - setprg4r(0x10, 0x7000, 2); - - old2007wrap = GetWriteHandler(0x2007); - SetWriteHandler(0x2007, 0x2007, M1902007Wrap); - +static void QTAiPower(void) { SetReadHandler(0x6000, 0xFFFF, CartBR); -// SetWriteHandler(0x5000,0x5007,TestWrite); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0xFFFF, M190Write); - SetReadHandler(0xDC00, 0xDC00, M190Read); - SetReadHandler(0xDD00, 0xDD00, M190Read); + SetWriteHandler(0x8000, 0xFFFF, QTAiWrite); + SetReadHandler(0xDC00, 0xDC00, QTAiRead); + SetReadHandler(0xDD00, 0xDD00, QTAiRead); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); Sync(); } -static void M190Close(void) { +static void QTAiClose(void) { if (CHRRAM) FCEU_gfree(CHRRAM); CHRRAM = NULL; @@ -200,3 +235,31 @@ static void M190Close(void) { static void StateRestore(int version) { Sync(); } + +void QTAi_Init(CartInfo *info) { + QTAIHack = 1; + + info->Power = QTAiPower; + info->Close = QTAiClose; + GameStateRestore = StateRestore; + + MapIRQHook = VRC5IRQ; + + CHRRAM = (uint8*)FCEU_gmalloc(CHRSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRSIZE, 1); + AddExState(CHRRAM, CHRSIZE, 0, "CRAM"); + + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + // note, only extrnal cart's SRAM is battery backed, the the part on the main cartridge is just + // an additional work ram. so we may save only half here, but I forgot what part is saved lol, will + // find out later. + info->SaveGameLen[0] = WRAMSIZE; + } + + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/cart.cpp b/source/fceultra/cart.cpp index 9451f55..e050811 100644 --- a/source/fceultra/cart.cpp +++ b/source/fceultra/cart.cpp @@ -132,6 +132,11 @@ void SetupCartCHRMapping(int chip, uint8 *p, uint32 size, int ram) { CHRmask4[chip] = (size >> 12) - 1; CHRmask8[chip] = (size >> 13) - 1; + if (CHRmask1[chip] >= (unsigned int)(-1)) CHRmask1[chip] = 0; + if (CHRmask2[chip] >= (unsigned int)(-1)) CHRmask2[chip] = 0; + if (CHRmask4[chip] >= (unsigned int)(-1)) CHRmask4[chip] = 0; + if (CHRmask8[chip] >= (unsigned int)(-1)) CHRmask8[chip] = 0; + CHRram[chip] = ram; } @@ -242,7 +247,7 @@ void setchr2r(int r, uint32 A, uint32 V) { PPUCHRRAM &= ~(3 << (A >> 10)); } -void setchr4r(int r, uint32 A, uint32 V) { +void setchr4r(int r, unsigned int A, unsigned int V) { if (!CHRptr[r]) return; FCEUPPU_LineUpdate(); V &= CHRmask4[r]; diff --git a/source/fceultra/cart.h b/source/fceultra/cart.h index 9cba1b9..e78c87e 100644 --- a/source/fceultra/cart.h +++ b/source/fceultra/cart.h @@ -1,3 +1,6 @@ +#ifndef CART_H +#define CART_H + typedef struct { // Set by mapper/board code: void (*Power)(void); @@ -68,21 +71,21 @@ void setprg8(uint32 A, uint32 V); void setprg16(uint32 A, uint32 V); void setprg32(uint32 A, uint32 V); -void setprg2r(int r, uint32 A, uint32 V); -void setprg4r(int r, uint32 A, uint32 V); -void setprg8r(int r, uint32 A, uint32 V); -void setprg16r(int r, uint32 A, uint32 V); -void setprg32r(int r, uint32 A, uint32 V); +void setprg2r(int r, unsigned int A, unsigned int V); +void setprg4r(int r, unsigned int A, unsigned int V); +void setprg8r(int r, unsigned int A, unsigned int V); +void setprg16r(int r, unsigned int A, unsigned int V); +void setprg32r(int r, unsigned int A, unsigned int V); -void setchr1r(int r, uint32 A, uint32 V); -void setchr2r(int r, uint32 A, uint32 V); -void setchr4r(int r, uint32 A, uint32 V); -void setchr8r(int r, uint32 V); +void setchr1r(int r, unsigned int A, unsigned int V); +void setchr2r(int r, unsigned int A, unsigned int V); +void setchr4r(int r, unsigned int A, unsigned int V); +void setchr8r(int r, unsigned int V); -void setchr1(uint32 A, uint32 V); -void setchr2(uint32 A, uint32 V); -void setchr4(uint32 A, uint32 V); -void setchr8(uint32 V); +void setchr1(unsigned int A, unsigned int V); +void setchr2(unsigned int A, unsigned int V); +void setchr4(unsigned int A, unsigned int V); +void setchr8(unsigned int V); void setmirror(int t); void setmirrorw(int a, int b, int c, int d); @@ -100,3 +103,5 @@ void FCEU_GeniePower(void); bool FCEU_OpenGenie(void); void FCEU_CloseGenie(void); void FCEU_KillGenie(void); + +#endif diff --git a/source/fceultra/cheat.cpp b/source/fceultra/cheat.cpp index 391bb0b..ddfa824 100644 --- a/source/fceultra/cheat.cpp +++ b/source/fceultra/cheat.cpp @@ -39,8 +39,7 @@ using namespace std; static uint8 *CheatRPtrs[64]; vector FrozenAddresses; //List of addresses that are currently frozen -void UpdateFrozenList(void); //Function that populates the list of frozen addresses -unsigned int FrozenAddressCount=0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor) +unsigned int FrozenAddressCount = 0; //Keeps up with the Frozen address count, necessary for using in other dialogs (such as hex editor) void FCEU_CheatResetRAM(void) { @@ -60,27 +59,13 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p) } -struct CHEATF { - struct CHEATF *next; - char *name; - uint16 addr; - uint8 val; - int compare; /* -1 for no compare. */ - int type; /* 0 for replace, 1 for substitute(GG). */ - int status; -}; - -typedef struct { - uint16 addr; - uint8 val; - int compare; - readfunc PrevRead; -} CHEATF_SUBFAST; - - -static CHEATF_SUBFAST SubCheats[256]; -static int numsubcheats=0; -struct CHEATF *cheats=0,*cheatsl=0; +CHEATF_SUBFAST SubCheats[256] = { 0 }; +uint32 numsubcheats = 0; +int globalCheatDisabled = 0; +int disableAutoLSCheats = 0; +bool disableShowGG = 0; +static _8BYTECHEATMAP* cheatMap = NULL; +struct CHEATF *cheats = 0, *cheatsl = 0; #define CHEATC_NONE 0x8000 @@ -92,7 +77,7 @@ int savecheats = 0; static DECLFR(SubCheatsRead) { - CHEATF_SUBFAST *s=SubCheats; + CHEATF_SUBFAST *s = SubCheats; int x=numsubcheats; do @@ -116,79 +101,97 @@ static DECLFR(SubCheatsRead) void RebuildSubCheats(void) { - int x; - struct CHEATF *c=cheats; - for(x=0;xtype==1 && c->status) + SetReadHandler(SubCheats[x].addr, SubCheats[x].addr, SubCheats[x].PrevRead); + if (cheatMap) + FCEUI_SetCheatMapByte(SubCheats[x].addr, false); + } + + numsubcheats = 0; + + if (!globalCheatDisabled) + { + while(c) { - if(GetReadHandler(c->addr)==SubCheatsRead) + if(c->type == 1 && c->status && GetReadHandler(c->addr) != SubCheatsRead) { - /* Prevent a catastrophe by this check. */ - //FCEU_DispMessage("oops",0); - } - else - { - SubCheats[numsubcheats].PrevRead=GetReadHandler(c->addr); - SubCheats[numsubcheats].addr=c->addr; - SubCheats[numsubcheats].val=c->val; - SubCheats[numsubcheats].compare=c->compare; - SetReadHandler(c->addr,c->addr,SubCheatsRead); + SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr); + SubCheats[numsubcheats].addr = c->addr; + SubCheats[numsubcheats].val = c->val; + SubCheats[numsubcheats].compare = c->compare; + SetReadHandler(c->addr, c->addr, SubCheatsRead); + if (cheatMap) + FCEUI_SetCheatMapByte(SubCheats[numsubcheats].addr, true); numsubcheats++; } + c = c->next; } - c=c->next; } FrozenAddressCount = numsubcheats; //Update the frozen address list - UpdateFrozenList(); - //FCEUI_DispMessage("Active Cheats: %d",0, FrozenAddresses.size()/*FrozenAddressCount*/); //Debug + } void FCEU_PowerCheats() { - numsubcheats=0; /* Quick hack to prevent setting of ancient read addresses. */ + numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */ + if (cheatMap) + FCEUI_RefreshCheatMap(); RebuildSubCheats(); } -int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type); +int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size) { + + uint32 count = 0; + if (cheatMap) + for (uint32 i = 0; i < size; ++i) + if (FCEUI_FindCheatMapByte(address + i)) + ++count; + return count; +} + static void CheatMemErr(void) { FCEUD_PrintError("Error allocating memory for cheat data."); } -/* This function doesn't allocate any memory for "name" */ -int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type) +int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type) { struct CHEATF *temp; - if(!(temp=(struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF)))) + if(!(temp = (struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF)))) { CheatMemErr(); return(0); } - temp->name=name; - temp->addr=addr; - temp->val=val; - temp->status=status; - temp->compare=compare; - temp->type=type; - temp->next=0; + + temp->name = strcpy((char*) FCEU_dmalloc(strlen(name) + 1), name); + temp->addr = addr; + temp->val = val; + temp->status = status; + temp->compare = compare; + temp->type = type; + temp->next = 0; if(cheats) { - cheatsl->next=temp; - cheatsl=temp; + cheatsl->next = temp; + cheatsl = temp; } else - cheats=cheatsl=temp; + cheats = cheatsl = temp; - return(1); + return (1); } -void FCEU_LoadGameCheats(FILE *override) +/* The "override_existing" parameter is used only in cheat dialog import. + Since the default behaviour will reset numsubcheats to 0 everytime, + In game loading, this is absolutely right, but when importing in cheat window, + resetting numsubcheats to 0 will override existed cheat items to make them + invalid. +*/ +void FCEU_LoadGameCheats(FILE *override, int override_existing) { FILE *fp; unsigned int addr; @@ -198,89 +201,121 @@ void FCEU_LoadGameCheats(FILE *override) unsigned int compare; int x; - char linebuf[2048]; - char *namebuf; - int tc=0; + char linebuf[2048] = { 0 }; + char namebuf[128] = { 0 }; + int tc = 0; char *fn; - numsubcheats=savecheats=0; + if (override_existing) + { + numsubcheats = 0; + if (cheatMap) + FCEUI_RefreshCheatMap(); + } if(override) fp = override; else { - fn=strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str()); - fp=FCEUD_UTF8fopen(fn,"rb"); + fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT, 0, 0).c_str()); + fp = FCEUD_UTF8fopen(fn, "rb"); free(fn); - if(!fp) return; + if (!fp) { + return; + } } - FCEU_DispMessage("Cheats file loaded.",0); //Tells user a cheats file was loaded. - while(fgets(linebuf,2048,fp) != nullptr) + while(fgets(linebuf, 2048, fp) != nullptr) { - char *tbuf=linebuf; - int doc=0; + char *tbuf = linebuf; + int doc = 0; - addr=val=compare=status=type=0; + addr = val = compare = status = type = 0; - if(tbuf[0]=='S') + if(tbuf[0] == 'S') { tbuf++; - type=1; + type = 1; } - else type=0; + else + type = 0; - if(tbuf[0]=='C') + if(tbuf[0] == 'C') { tbuf++; - doc=1; + doc = 1; } - if(tbuf[0]==':') + if(tbuf[0] == ':') { tbuf++; - status=0; + status = 0; } - else status=1; + else status = 1; if(doc) { - char *neo=&tbuf[4+2+2+1+1+1]; - if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3) + char *neo = &tbuf[4+2+2+1+1+1]; + if(sscanf(tbuf, "%04x%*[:]%02x%*[:]%02x", &addr, &val, &compare) != 3) continue; - if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1))) - return; - strcpy(namebuf,neo); + strcpy(namebuf, neo); } else { - char *neo=&tbuf[4+2+1+1]; - if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2) + char *neo = &tbuf[4+2+1+1]; + if(sscanf(tbuf, "%04x%*[:]%02x", &addr, &val) != 2) continue; - if (!(namebuf=(char *)FCEU_dmalloc(strlen(neo)+1))) - return; - strcpy(namebuf,neo); + strcpy(namebuf, neo); } - for(x=0;x<(int)strlen(namebuf);x++) + for(x = 0; x < (int)strlen(namebuf); x++) { - if(namebuf[x]==10 || namebuf[x]==13) + if(namebuf[x] == 10 || namebuf[x] == 13) { - namebuf[x]=0; + namebuf[x] = 0; break; } else if(namebuf[x] > 0x00 && namebuf[x] < 0x20) - namebuf[x]=0x20; + namebuf[x] = 0x20; } - AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type); + AddCheatEntry(namebuf, addr, val, doc ? compare : -1, status, type); tc++; } + RebuildSubCheats(); + + FCEU_DispMessage("Cheats file loaded.", 0); //Tells user a cheats file was loaded. + if(!override) fclose(fp); } +void FCEU_SaveGameCheats(FILE* fp, int release) +{ + struct CHEATF *next = cheats; + while (next) + { + if (next->type) + fputc('S', fp); + if (next->compare >= 0) + fputc('C', fp); + + if (!next->status) + fputc(':', fp); + + if (next->compare >= 0) + fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name); + else + fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name); + + if (release) free(next->name); + struct CHEATF *t = next; + next = next->next; + if (release) free(t); + } +} + void FCEU_FlushGameCheats(FILE *override, int nosave) { if(CheatComp) @@ -313,7 +348,6 @@ void FCEU_FlushGameCheats(FILE *override, int nosave) if(cheats) { - struct CHEATF *next=cheats; FILE *fp; if(override) @@ -323,28 +357,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave) if(fp) { - for(;;) - { - struct CHEATF *t; - if(next->type) - fputc('S',fp); - if(next->compare>=0) - fputc('C',fp); - - if(!next->status) - fputc(':',fp); - - if(next->compare>=0) - fprintf(fp,"%04x:%02x:%02x:%s\n",next->addr,next->val,next->compare,next->name); - else - fprintf(fp,"%04x:%02x:%s\n",next->addr,next->val,next->name); - - free(next->name); - t=next; - next=next->next; - free(t); - if(!next) break; - } + FCEU_SaveGameCheats(fp, 1); if(!override) fclose(fp); } @@ -365,23 +378,13 @@ void FCEU_FlushGameCheats(FILE *override, int nosave) int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type) { - char *t; - if(!(t=(char *)FCEU_dmalloc(strlen(name)+1))) - { - CheatMemErr(); - return(0); - } - strcpy(t,name); - if(!AddCheatEntry(t,addr,val,compare,1,type)) - { - free(t); - return(0); - } - savecheats=1; + if(!AddCheatEntry(name, addr, val, compare, 1, type)) + return 0; + savecheats = 1; RebuildSubCheats(); - return(1); + return 1; } int FCEUI_DelCheat(uint32 which) @@ -566,7 +569,7 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c) int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type) { - int boo[4]; + unsigned int boo[4]; if(strlen(str)!=8) return(0); sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3); @@ -598,43 +601,40 @@ int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type) int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int s, int type) { - struct CHEATF *next=cheats; - uint32 x=0; + struct CHEATF *next = cheats; + uint32 x = 0; while(next) { - if(x==which) + if(x == which) { if(name) { char *t; - if((t=(char *)realloc(next->name, strlen(name)+1))) - { - next->name=t; - strcpy(next->name,name); - } + if((t = (char *)realloc(next->name, strlen(name) + 1))) + strcpy(next->name = t, name); else - return(0); + return 0; } - if(a>=0) - next->addr=a; - if(v>=0) - next->val=v; - if(s>=0) - next->status=s; - if(c>=-1) - next->compare=c; - next->type=type; + if(a >= 0) + next->addr = a; + if(v >= 0) + next->val = v; + if(s >= 0) + next->status = s; + if(c >= -1) + next->compare = c; + next->type = type; - savecheats=1; + savecheats = 1; RebuildSubCheats(); - return(1); + return 1; } - next=next->next; + next = next->next; x++; } - return(0); + return 0; } /* Convenience function. */ @@ -659,6 +659,14 @@ int FCEUI_ToggleCheat(uint32 which) return(-1); } +int FCEUI_GlobalToggleCheat(int global_enabled) +{ + int _numsubcheats = numsubcheats; + globalCheatDisabled = !global_enabled; + RebuildSubCheats(); + return _numsubcheats != numsubcheats; +} + static int InitCheatComp(void) { uint32 x; @@ -741,7 +749,7 @@ void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current)) { uint32 x; - uint32 in=0; + uint32 in = 0; if(!CheatComp) { @@ -750,14 +758,15 @@ void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, return; } - for(x=0;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW) && CheatRPtrs[x>>10]) + for(x = 0; x < 0x10000; x++) + if(!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10]) { - if(in>=first) - if(!callb(x,CheatComp[x],CheatRPtrs[x>>10][x])) + if(in >= first) + if(!callb(x, CheatComp[x], CheatRPtrs[x >> 10][x])) break; in++; - if(in>last) return; + if(in > last) + return; } } @@ -803,130 +812,56 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) } } - - if(!type) // Change to a specific value. + switch (type) { - for(x=0;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if(CheatComp[x]==v1 && CheatRPtrs[x>>10][x]==v2) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } + default: + case FCEU_SEARCH_SPECIFIC_CHANGE: // Change to a specific value + for (x = 0; x < 0x10000; ++x) + if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CheatRPtrs[x >> 10][x] != v2)) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_RELATIVE_CHANGE: // Search for relative change (between values). + for (x = 0; x < 0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] != v1 || CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2)) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_PUERLY_RELATIVE_CHANGE: // Purely relative change. + for (x = 0x000; x<0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && CAbs(CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_ANY_CHANGE: // Any change. + for (x = 0x000; x < 0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] == CheatRPtrs[x >> 10][x]) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_NEWVAL_KNOWN: // new value = known + for (x = 0x000; x < 0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] != v1) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_NEWVAL_GT: // new value greater than + for (x = 0x000; x < 0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] >= CheatRPtrs[x >> 10][x]) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_NEWVAL_LT: // new value less than + for (x = 0x000; x < 0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatComp[x] <= CheatRPtrs[x >> 10][x]) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_NEWVAL_GT_KNOWN: // new value greater than by known value + for (x = 0x000; x < 0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && CheatRPtrs[x >> 10][x] - CheatComp[x] != v2) + CheatComp[x] |= CHEATC_EXCLUDED; + break; + case FCEU_SEARCH_NEWVAL_LT_KNOWN: // new value less than by known value + for (x = 0x000; x < 0x10000; x++) + if (!(CheatComp[x] & CHEATC_NOSHOW) && (CheatComp[x] - CheatRPtrs[x >> 10][x]) != v2) + CheatComp[x] |= CHEATC_EXCLUDED; + break; } - else if(type==1) // Search for relative change(between values). - { - for(x=0;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if(CheatComp[x]==v1 && CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2) - { - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - } - else if(type==2) // Purely relative change. - { - for(x=0x000;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if(CAbs(CheatComp[x]-CheatRPtrs[x>>10][x])==v2) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - } - else if(type==3) // Any change. - { - for(x=0x000;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if(CheatComp[x]!=CheatRPtrs[x>>10][x]) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - - } - else if(type==4) // new value = known - { - for(x=0x000;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if(CheatRPtrs[x>>10][x]==v1) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - - } - else if(type==5) // new value greater than - { - for(x=0x000;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if(CheatComp[x]>10][x]) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - - } - else if(type==6) // new value less than - { - for(x=0x000;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if(CheatComp[x]>CheatRPtrs[x>>10][x]) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - - } - else if(type==7) // new value greater than by known value - { - for(x=0x000;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if((CheatRPtrs[x>>10][x]-CheatComp[x])==v2) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - - } - else if(type==8) // new value less than by known value - { - for(x=0x000;x<0x10000;x++) - if(!(CheatComp[x]&CHEATC_NOSHOW)) - { - if((CheatComp[x]-CheatRPtrs[x>>10][x])==v2) - { - - } - else - CheatComp[x]|=CHEATC_EXCLUDED; - } - - } } int FCEU_CheatGetByte(uint32 A) @@ -949,18 +884,75 @@ void FCEU_CheatSetByte(uint32 A, uint8 V) BWrite[A](A, V); } -void UpdateFrozenList(void) +// disable all cheats +int FCEU_DisableAllCheats(void) { - //The purpose of this function is to keep an up to date list of addresses that are currently frozen - //and make these accessible to other dialogs that deal with memory addresses such as - //memwatch, hex editor, ramfilter, etc. - - int x; - FrozenAddresses.clear(); //Clear vector and repopulate - for(x=0;xstatus){ + 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 } diff --git a/source/fceultra/cheat.h b/source/fceultra/cheat.h index 431ff0a..82037fc 100644 --- a/source/fceultra/cheat.h +++ b/source/fceultra/cheat.h @@ -1,12 +1,70 @@ +#ifndef CHEAT_H +#define CHEAT_H void FCEU_CheatResetRAM(void); void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p); -void FCEU_LoadGameCheats(FILE *override); +void FCEU_LoadGameCheats(FILE *override, int override_existing = 1); void FCEU_FlushGameCheats(FILE *override, int nosave); +void FCEU_SaveGameCheats(FILE *fp, int release = 0); +int FCEUI_GlobalToggleCheat(int global_enabled); void FCEU_ApplyPeriodicCheats(void); void FCEU_PowerCheats(void); +int FCEU_CalcCheatAffectedBytes(uint32 address, uint32 size); + +// Trying to find a more efficient way for determining if an address has a cheat +// each bit of 1 byte represents to 8 bytes in NES +typedef unsigned char _8BYTECHEATMAP; +#define CHEATMAP_SIZE 0x10000 / 8 + +extern int FCEUI_FindCheatMapByte(uint16 address); +extern void FCEUI_SetCheatMapByte(uint16 address, bool cheat); +extern void FCEUI_CreateCheatMap(void); +extern void FCEUI_RefreshCheatMap(void); +extern void FCEUI_ReleaseCheatMap(void); +extern unsigned int FrozenAddressCount; int FCEU_CheatGetByte(uint32 A); void FCEU_CheatSetByte(uint32 A, uint8 V); -extern int savecheats; \ No newline at end of file +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 diff --git a/source/fceultra/conddebug.cpp b/source/fceultra/conddebug.cpp index 915fcfd..3775d2b 100644 --- a/source/fceultra/conddebug.cpp +++ b/source/fceultra/conddebug.cpp @@ -194,10 +194,10 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP { scan(str); - c->lhs = Connect(str); - if (!c) return 0; + c->lhs = Connect(str); + if (next == closePar) { scan(str); @@ -400,9 +400,12 @@ Condition* Term(const char** str) Condition* t1; Condition* mid; - t = (Condition*)FCEU_dmalloc(sizeof(Condition)); - if (!t) - return NULL; + t = (Condition*)FCEU_dmalloc(sizeof(Condition)); + + if (!t) + { + return NULL; + } memset(t, 0, sizeof(Condition)); diff --git a/source/fceultra/config.cpp b/source/fceultra/config.cpp index f998a74..6615763 100644 --- a/source/fceultra/config.cpp +++ b/source/fceultra/config.cpp @@ -13,18 +13,23 @@ static char *aboutString = 0; +#ifndef FCEUX_BUILD_TIMESTAMP +#define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__ +#endif + // returns a string suitable for use in an aboutbox -char *FCEUI_GetAboutString() { +const char *FCEUI_GetAboutString(void) +{ const char *aboutTemplate = FCEU_NAME_AND_VERSION "\n\n" "Administrators:\n" - "zeromus, punkrockguy318 (Lukas Sabota), feos\n" + "zeromus, feos\n" "\n" "Current Contributors:\n" - "CaH4e3, rainwarrior\n" + "CaH4e3, rainwarrior, owomomo, punkrockguy318\n" "\n" "Past Contributors:\n" - "xhainingx, gocha, AnS\n" + "xhainingx, gocha, AnS, mjbudd77\n" "\n" "FCEUX 2.0:\n" "mz, nitsujrehtona, SP, Ugly Joe,\n" @@ -40,13 +45,17 @@ char *FCEUI_GetAboutString() { "FCEU TAS - blip & nitsuja\n" "FCEU TAS+ - Luke Gustafson\n" "\n" + "Logo/icon:\n" + "Terwilf\n" + "\n" "FCEUX is dedicated to the fallen heroes\n" "of NES emulation. In Memoriam --\n" "ugetab\n" "\n" - __TIME__ " " __DATE__ "\n"; + "\n" + FCEUX_BUILD_TIMESTAMP "\n"; - if(aboutString) return aboutString; + if (aboutString) return aboutString; const char *compilerString = FCEUD_GetCompilerString(); @@ -54,6 +63,6 @@ char *FCEUI_GetAboutString() { if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1))) return NULL; - sprintf(aboutString,"%s%s",aboutTemplate,compilerString); + sprintf(aboutString,"%s%s",aboutTemplate,compilerString); return aboutString; } diff --git a/source/fceultra/debug.cpp b/source/fceultra/debug.cpp index dbde6a3..b02a151 100644 --- a/source/fceultra/debug.cpp +++ b/source/fceultra/debug.cpp @@ -22,7 +22,7 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) { int offset = -1; - if (sscanf(offsetBuffer,"%4X",&offset) == EOF) + if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF) { return -1; } @@ -35,14 +35,24 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) { return offset & 0x00FF; } + else if (type & BT_R) + { + return offset; + } else // BT_C { - if (GameInfo->type == GIT_NSF) { //NSF Breakpoint keywords + int type = GIT_CART; + + if (GameInfo) + { + type = GameInfo->type; + } + if (type == GIT_NSF) { //NSF Breakpoint keywords if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8)); if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8)); if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8)); } - else if (GameInfo->type == GIT_FDS) { //FDS Breakpoint keywords + else if (type == GIT_FDS) { //FDS Breakpoint keywords if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8)); if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8)); if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8)); @@ -56,7 +66,7 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer) } } - return offset; + return offset & 0xFFFF; } // Returns the value of a given type or register @@ -194,6 +204,9 @@ unsigned int NewBreak(const char* name, int start, int end, unsigned int type, c watchpoint[num].flags|=BT_S; watchpoint[num].flags&=~WP_X; //disable execute flag! } + if (type & BT_R) { + watchpoint[num].flags|=BT_R; + } if (watchpoint[num].desc) free(watchpoint[num].desc); @@ -208,11 +221,27 @@ int GetPRGAddress(int A){ int result; if(A > 0xFFFF) return -1; - result = &Page[A>>11][A]-PRGptr[0]; - if((result > (int)PRGsize[0]) || (result < 0)) - return -1; - else - return result; + if (GameInfo->type == GIT_FDS) { + if (A < 0xE000) { + result = &Page[A >> 11][A] - PRGptr[1]; + if ((result > (int)PRGsize[1]) || (result < 0)) + return -1; + else + return result; + } else { + result = &Page[A >> 11][A] - PRGptr[0]; + if ((result > (int)PRGsize[0]) || (result < 0)) + return -1; + else + return result + PRGsize[1]; + } + } else { + result = &Page[A >> 11][A] - PRGptr[0]; + if ((result > (int)PRGsize[0]) || (result < 0)) + return -1; + else + return result; + } } /** @@ -421,12 +450,12 @@ int condition(watchpointinfo* wp) //--------------------- -volatile int codecount, datacount, undefinedcount; -unsigned char *cdloggerdata; +volatile int codecount = 0, datacount = 0, undefinedcount = 0; +unsigned char *cdloggerdata = NULL; unsigned int cdloggerdataSize = 0; -static int indirectnext; +static int indirectnext = 0; -int debug_loggingCD; +int debug_loggingCD = 0; //called by the cpu to perform logging if CDLogging is enabled void LogCDVectors(int which){ @@ -448,20 +477,29 @@ void LogCDVectors(int which){ } } -void LogCDData(uint8 *opcode, uint16 A, int size) { +bool break_on_unlogged_code = false; +bool break_on_unlogged_data = false; + +void LogCDData(uint8 *opcode, uint16 A, int size) +{ int i, j; uint8 memop = 0; + bool newCodeHit = false, newDataHit = false; - if((j = GetPRGAddress(_PC)) != -1) - for (i = 0; i < size; i++) { - if(cdloggerdata[j+i] & 1)continue; //this has been logged so skip + if ((j = GetPRGAddress(_PC)) != -1) + { + for (i = 0; i < size; i++) + { + if (cdloggerdata[j+i] & 1) continue; //this has been logged so skip cdloggerdata[j+i] |= 1; cdloggerdata[j+i] |= ((_PC + i) >> 11) & 0x0c; cdloggerdata[j+i] |= ((_PC & 0x8000) >> 8) ^ 0x80; // 19/07/14 used last reserved bit, if bit 7 is 1, then code is running from lowe area (6000) - if(indirectnext)cdloggerdata[j+i] |= 0x10; + if (indirectnext)cdloggerdata[j+i] |= 0x10; codecount++; - if(!(cdloggerdata[j+i] & 2))undefinedcount--; + if (!(cdloggerdata[j+i] & 2))undefinedcount--; + newCodeHit = true; } + } //log instruction jumped to in an indirect jump if(opcode[0] == 0x6c) @@ -474,14 +512,43 @@ void LogCDData(uint8 *opcode, uint16 A, int size) { case 4: memop = 0x20; break; } - if((j = GetPRGAddress(A)) != -1) { - if(!(cdloggerdata[j] & 2)) { - cdloggerdata[j] |= 2; - cdloggerdata[j] |=(A>>11)&0x0c; - cdloggerdata[j] |= memop; - datacount++; - if(!(cdloggerdata[j] & 1))undefinedcount--; + if ((j = GetPRGAddress(A)) != -1) + { + if (opwrite[opcode[0]] == 0) + { + if (!(cdloggerdata[j] & 2)) + { + cdloggerdata[j] |= 2; + cdloggerdata[j] |= (A >> 11) & 0x0c; + cdloggerdata[j] |= memop; + cdloggerdata[j] |= ((A & 0x8000) >> 8) ^ 0x80; + datacount++; + if (!(cdloggerdata[j] & 1))undefinedcount--; + newDataHit = true; + } } + else + { + if (cdloggerdata[j] & 1) + { + codecount--; + } + if (cdloggerdata[j] & 2) + { + datacount--; + } + if ((cdloggerdata[j] & 3) != 0) undefinedcount++; + cdloggerdata[j] = 0; + } + } + + if ( break_on_unlogged_code && newCodeHit ) + { + BreakHit( BREAK_TYPE_UNLOGGED_CODE ); + } + else if ( break_on_unlogged_data && newDataHit ) + { + BreakHit( BREAK_TYPE_UNLOGGED_DATA ); } } @@ -533,40 +600,41 @@ void IncrementInstructionsCounters() delta_instructions++; } -void BreakHit(int bp_num, bool force) -{ - if(!force) +bool CondForbidTest(int bp_num) { + if (bp_num >= 0 && !condition(&watchpoint[bp_num])) { - if (bp_num >= 0 && !condition(&watchpoint[bp_num])) - { - return; // condition rejected - } + return false; // condition rejected + } - //check to see whether we fall in any forbid zone - for (int i = 0; i < numWPs; i++) - { - watchpointinfo& wp = watchpoint[i]; - if(!(wp.flags & WP_F) || !(wp.flags & WP_E)) - continue; + //check to see whether we fall in any forbid zone + for (int i = 0; i < numWPs; i++) + { + watchpointinfo& wp = watchpoint[i]; + if (!(wp.flags & WP_F) || !(wp.flags & WP_E)) + continue; - if (condition(&wp)) - { - if (wp.endaddress) { - if( (wp.address <= _PC) && (wp.endaddress >= _PC) ) - return; //forbid - } else { - if(wp.address == _PC) - return; //forbid - } + if (condition(&wp)) + { + if (wp.endaddress) { + if ((wp.address <= _PC) && (wp.endaddress >= _PC)) + return false; // forbid + } + else { + if (wp.address == _PC) + return false; // forbid } } } + return true; +} +void BreakHit(int bp_num) +{ FCEUI_SetEmulationPaused(EMULATIONPAUSED_PAUSED); //mbg merge 7/19/06 changed to use EmulationPaused() -#ifdef WIN32 +//#ifdef WIN32 FCEUD_DebugBreakpoint(bp_num); -#endif +//#endif } int StackAddrBackup; @@ -574,10 +642,10 @@ uint16 StackNextIgnorePC = 0xFFFF; ///fires a breakpoint static void breakpoint(uint8 *opcode, uint16 A, int size) { - int i, j; + int i, j, romAddrPC; uint8 brk_type; uint8 stackop=0; - uint8 stackopstartaddr,stackopendaddr; + uint8 stackopstartaddr=0,stackopendaddr=0; debugLastAddress = A; debugLastOpcode = opcode[0]; @@ -585,17 +653,17 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (break_asap) { break_asap = false; - BreakHit(BREAK_TYPE_LUA, true); + BreakHit(BREAK_TYPE_LUA); } if (break_on_cycles && ((timestampbase + (uint64)timestamp - total_cycles_base) > break_cycles_limit)) - BreakHit(BREAK_TYPE_CYCLES_EXCEED, true); + BreakHit(BREAK_TYPE_CYCLES_EXCEED); if (break_on_instructions && (total_instructions > break_instructions_limit)) - BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED, true); + BreakHit(BREAK_TYPE_INSTRUCTIONS_EXCEED); //if the current instruction is bad, and we are breaking on bad opcodes, then hit the breakpoint if(dbgstate.badopbreak && (size == 0)) - BreakHit(BREAK_TYPE_BADOP, true); + BreakHit(BREAK_TYPE_BADOP); //if we're stepping out, track the nest level if (dbgstate.stepout) { @@ -614,7 +682,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { //if we're stepping, then we'll always want to break if (dbgstate.step) { dbgstate.step = false; - BreakHit(BREAK_TYPE_STEP, true); + BreakHit(BREAK_TYPE_STEP); return; } @@ -626,7 +694,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (diff<=0) { dbgstate.runline=false; - BreakHit(BREAK_TYPE_STEP, true); + BreakHit(BREAK_TYPE_STEP); return; } } @@ -635,10 +703,12 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if ((watchpoint[64].address == _PC) && (watchpoint[64].flags)) { watchpoint[64].address = 0; watchpoint[64].flags = 0; - BreakHit(BREAK_TYPE_STEP, true); + BreakHit(BREAK_TYPE_STEP); return; } + romAddrPC = GetNesFileAddress(_PC); + brk_type = opbrktype[opcode[0]] | WP_X; switch (opcode[0]) { @@ -657,7 +727,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { default: break; } - #define BREAKHIT(x) { breakHit = (x); goto STOPCHECKING; } +#define BREAKHIT(x) { if (CondForbidTest(x)) { breakHit = (x); goto STOPCHECKING; } } int breakHit = -1; for (i = 0; i < numWPs; i++) { @@ -708,11 +778,31 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address <= A) && (watchpoint[i].endaddress >= A)) || ((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC))) BREAKHIT(i); - } else + } + else { - if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) || - ((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC))) - BREAKHIT(i); + if (watchpoint[i].flags & BT_R) + { + if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == romAddrPC) ) + { + BREAKHIT(i); + } + //else if ( (watchpoint[i].flags & WP_R) && (watchpoint[i].address == A) ) + //{ + // BREAKHIT(i); + //} + } + else + { + if ( (watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) + { + BREAKHIT(i); + } + else if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC) ) + { + BREAKHIT(i); + } + } } } else { @@ -864,10 +954,5 @@ void DebugCycle() if(debug_loggingCD) LogCDData(opcode, A, size); -#ifdef WIN32 - //This needs to be windows only or else the linux build system will fail since logging is declared in a - //windows source file FCEUD_TraceInstruction(opcode, size); -#endif - } diff --git a/source/fceultra/debug.h b/source/fceultra/debug.h index d531abf..e1d8b57 100644 --- a/source/fceultra/debug.h +++ b/source/fceultra/debug.h @@ -15,12 +15,15 @@ #define BT_C 0x00 //break type, cpu mem #define BT_P 0x20 //break type, ppu mem #define BT_S 0x40 //break type, sprite mem +#define BT_R 0x80 //break type, rom mem #define BREAK_TYPE_STEP -1 #define BREAK_TYPE_BADOP -2 #define BREAK_TYPE_CYCLES_EXCEED -3 #define BREAK_TYPE_INSTRUCTIONS_EXCEED -4 #define BREAK_TYPE_LUA -5 +#define BREAK_TYPE_UNLOGGED_CODE -6 +#define BREAK_TYPE_UNLOGGED_DATA -7 //opbrktype is used to grab the breakpoint type that each instruction will cause. //WP_X is not used because ALL opcodes will have the execute bit set. @@ -46,9 +49,9 @@ static const uint8 opbrktype[256] = { typedef struct { - uint16 address; - uint16 endaddress; - uint8 flags; + uint32 address; + uint32 endaddress; + uint16 flags; Condition* cond; char* condText; @@ -59,6 +62,7 @@ typedef struct { //mbg merge 7/18/06 had to make this extern extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over +extern unsigned int debuggerPageSize; int getBank(int offs); int GetNesFileAddress(int A); int GetPRGAddress(int A); @@ -93,9 +97,12 @@ static INLINE int FCEUI_GetLoggingCD() { return debug_loggingCD; } extern int iaPC; extern uint32 iapoffset; //mbg merge 7/18/06 changed from int void DebugCycle(); -void BreakHit(int bp_num, bool force = false); +bool CondForbidTest(int bp_num); +void BreakHit(int bp_num); extern bool break_asap; +extern bool break_on_unlogged_code; +extern bool break_on_unlogged_data; extern uint64 total_cycles_base; extern uint64 delta_cycles_base; extern bool break_on_cycles; @@ -113,8 +120,9 @@ extern void IncrementInstructionsCounters(); //internal variables that debuggers will want access to extern uint8 *vnapage[4],*VPage[8]; -extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset; +extern uint8 PPU[4],PALRAM[0x20],UPALRAM[3],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset; extern uint32 FCEUPPU_PeekAddress(); +extern uint8 READPAL_MOTHEROFALL(uint32 A); extern int numWPs; ///encapsulates the operational state of the debugger core diff --git a/source/fceultra/drawing.cpp b/source/fceultra/drawing.cpp index 2d64fd8..7597c06 100644 --- a/source/fceultra/drawing.cpp +++ b/source/fceultra/drawing.cpp @@ -395,10 +395,10 @@ static int FixJoedChar(uint8 ch) int c = ch - 32; return (c < 0 || c > 98) ? 0 : c; } -static int JoedCharWidth(uint8 ch) -{ - return Font6x7[FixJoedChar(ch)*8]; -} +//static int JoedCharWidth(uint8 ch) +//{ +// return Font6x7[FixJoedChar(ch)*8]; +//} char target[64][256]; diff --git a/source/fceultra/driver.h b/source/fceultra/driver.h index 7d228e0..e82f744 100644 --- a/source/fceultra/driver.h +++ b/source/fceultra/driver.h @@ -14,14 +14,16 @@ inline FILE *FCEUD_UTF8fopen(const std::string &n, const char *mode) { return FC EMUFILE_FILE* FCEUD_UTF8_fstream(const char *n, const char *m); inline EMUFILE_FILE* FCEUD_UTF8_fstream(const std::string &n, const char *m) { return FCEUD_UTF8_fstream(n.c_str(),m); } FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex); +FCEUFILE* FCEUD_OpenArchiveIndex(ArchiveScanRecord& asr, std::string& fname, int innerIndex, int* userCancel); FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename); +FCEUFILE* FCEUD_OpenArchive(ArchiveScanRecord& asr, std::string& fname, std::string* innerFilename, int* userCancel); ArchiveScanRecord FCEUD_ScanArchive(std::string fname); //mbg 7/23/06 const char *FCEUD_GetCompilerString(); //This makes me feel dirty for some reason. -void FCEU_printf(char *format, ...); +void FCEU_printf(const char *format, ...); #define FCEUI_printf FCEU_printf //Video interface @@ -123,6 +125,7 @@ void FCEUI_SetVidSystem(int a); //Set variables for NTSC(0) / PAL(1) / Dendy(2) //Dendy has PAL framerate and resolution, but ~NTSC timings, and has 50 dummy scanlines to force 50 fps void FCEUI_SetRegion(int region, int notify = 1); +int FCEUI_GetRegion(void); //Convenience function; returns currently emulated video system(0=NTSC, 1=PAL). int FCEUI_GetCurrentVidSystem(int *slstart, int *slend); @@ -140,7 +143,9 @@ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall); //Sets the base directory(save states, snapshots, etc. are saved in directories below this directory. void FCEUI_SetBaseDirectory(std::string const & dir); +const char *FCEUI_GetBaseDirectory(void); +bool FCEUI_GetUserPaletteAvail(void); void FCEUI_SetUserPalette(uint8 *pal, int nEntries); //Sets up sound code to render sound at the specified rate, in samples @@ -178,10 +183,16 @@ void FCEUD_MovieRecordTo(void); void FCEUD_MovieReplayFrom(void); void FCEUD_LuaRunFrom(void); +#ifdef _S9XLUA_H +// lua engine +void TaseditorAutoFunction(void); +void TaseditorManualFunction(void); +#endif + int32 FCEUI_GetDesiredFPS(void); void FCEUI_SaveSnapshot(void); void FCEUI_SaveSnapshotAs(void); -void FCEU_DispMessage(char *format, int disppos, ...); +void FCEU_DispMessage(const char *format, int disppos, ...); #define FCEUI_DispMessage FCEU_DispMessage int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type); @@ -189,6 +200,7 @@ int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c); int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type); int FCEUI_DelCheat(uint32 which); int FCEUI_ToggleCheat(uint32 which); +int FCEUI_GlobalToggleCheat(int global_enable); int32 FCEUI_CheatSearchGetCount(void); void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current)); @@ -247,7 +259,7 @@ void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make //int FCEUI_FDSEject(void); void FCEUI_FDSSelect(void); -int FCEUI_DatachSet(const uint8 *rcode); +int FCEUI_DatachSet(uint8 *rcode); ///returns a flag indicating whether emulation is paused int FCEUI_EmulationPaused(); @@ -318,6 +330,9 @@ void FCEUD_DebugBreakpoint(int bp_num); ///the driver should log the current instruction, if it wants (we should move the code in the win driver that does this to the shared area) void FCEUD_TraceInstruction(uint8 *opcode, int size); +///the driver should flush its trace log +void FCEUD_FlushTrace(); + ///the driver might should update its NTView (only used if debugging support is compiled in) void FCEUD_UpdateNTView(int scanline, bool drawall); @@ -337,7 +352,8 @@ enum EFCEUI FCEUI_STOPMOVIE, FCEUI_RECORDMOVIE, FCEUI_PLAYMOVIE, FCEUI_OPENGAME, FCEUI_CLOSEGAME, FCEUI_TASEDITOR, - FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN + FCEUI_RESET, FCEUI_POWER, FCEUI_PLAYFROMBEGINNING, FCEUI_EJECT_DISK, FCEUI_SWITCH_DISK, FCEUI_INSERT_COIN, FCEUI_INPUT_BARCODE, + FCEUI_TOGGLERECORDINGMOVIE, FCEUI_TRUNCATEMOVIE, FCEUI_INSERT1FRAME, FCEUI_DELETE1FRAME }; //checks whether an EFCEUI is valid right now diff --git a/source/fceultra/emufile.cpp b/source/fceultra/emufile.cpp index 5102f2c..e0e8311 100644 --- a/source/fceultra/emufile.cpp +++ b/source/fceultra/emufile.cpp @@ -86,6 +86,7 @@ void EMUFILE_FILE::truncate(s32 length) #else ftruncate(fileno(fp),length); #endif + // this is probably wrong if mode is "wb" fclose(fp); fp = NULL; open(fname.c_str(),mode); @@ -132,7 +133,7 @@ void EMUFILE::write64le(u64 val) size_t EMUFILE::read64le(u64 *Bufo) { - u64 buf; + u64 buf=0; if(fread((char*)&buf,8) != 8) return 0; #ifndef LOCAL_BE @@ -173,7 +174,7 @@ size_t EMUFILE::read32le(s32* Bufo) { return read32le((u32*)Bufo); } size_t EMUFILE::read32le(u32* Bufo) { - u32 buf; + u32 buf=0; if(fread(&buf,4)<4) return 0; #ifndef LOCAL_BE @@ -212,7 +213,7 @@ size_t EMUFILE::read16le(s16* Bufo) { return read16le((u16*)Bufo); } size_t EMUFILE::read16le(u16* Bufo) { - u32 buf; + u32 buf=0; if(fread(&buf,2)<2) return 0; #ifndef LOCAL_BE diff --git a/source/fceultra/emufile.h b/source/fceultra/emufile.h index 4d7d702..d9a5b2b 100644 --- a/source/fceultra/emufile.h +++ b/source/fceultra/emufile.h @@ -222,7 +222,7 @@ public: reserve(pos+(s32)bytes); memcpy(buf()+pos,ptr,bytes); pos += (s32)bytes; - len = std::max(pos,len); + len = std::max(pos,len); } virtual int fseek(int offset, int origin){ diff --git a/source/fceultra/fceu.cpp b/source/fceultra/fceu.cpp index d68b131..cf5fcdb 100644 --- a/source/fceultra/fceu.cpp +++ b/source/fceultra/fceu.cpp @@ -43,7 +43,7 @@ #include "file.h" #include "vsuni.h" #include "ines.h" -#ifdef WIN32 +#ifdef __WIN_DRIVER__ #include "drivers/win/pref.h" #include "utils/xstring.h" @@ -65,7 +65,7 @@ extern void RefreshThrottleFPS(); #endif //TODO - we really need some kind of global platform-specific options api -#ifdef WIN32 +#ifdef __WIN_DRIVER__ #include "drivers/win/main.h" #include "drivers/win/memview.h" #include "drivers/win/cheat.h" @@ -117,21 +117,26 @@ bool DebuggerWasUpdated = false; //To prevent the debugger from updating things bool AutoResumePlay = false; char romNameWhenClosingEmulator[2048] = {0}; + FCEUGI::FCEUGI() : filename(0), - archiveFilename(0) { + archiveFilename(0) +{ //printf("%08x",opsize); // WTF?! } -FCEUGI::~FCEUGI() { - if (filename) { - free(filename); - filename = NULL; - } - if (archiveFilename) { - delete archiveFilename; - archiveFilename = NULL; - } +FCEUGI::~FCEUGI() +{ + if (filename) + { + free(filename); + filename = NULL; + } + if (archiveFilename) + { + free(archiveFilename); + archiveFilename = NULL; + } } bool CheckFileExists(const char* filename) { @@ -160,7 +165,7 @@ void FCEU_TogglePPU(void) { FCEUI_printf("Old PPU loaded"); } normalscanlines = (dendy ? 290 : 240)+newppu; // use flag as number! -#ifdef WIN32 +#ifdef __WIN_DRIVER__ SetMainWindowText(); #endif } @@ -175,7 +180,7 @@ static void FCEU_CloseGame(void) FCEUSS_Save(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false); } -#ifdef WIN32 +#ifdef __WIN_DRIVER__ extern char LoadedRomFName[2048]; if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str())) FCEUD_PrintError("Couldn't store debugging data"); @@ -192,7 +197,14 @@ static void FCEU_CloseGame(void) } if (GameInfo->type != GIT_NSF) { - FCEU_FlushGameCheats(0, 0); +#ifdef __WIN_DRIVER__ + if (disableAutoLSCheats == 2) + FCEU_FlushGameCheats(0, 1); + else if (disableAutoLSCheats == 1) + AskSaveCheat(); + else if (disableAutoLSCheats == 0) +#endif + FCEU_FlushGameCheats(0, 0); } GameInterface(GI_CLOSE); @@ -393,6 +405,7 @@ void ResetGameLoaded(void) { MapIRQHook = NULL; MMC5Hack = 0; PEC586Hack = 0; + QTAIHack = 0; PAL &= 1; default_palette_selection = 0; } @@ -402,8 +415,6 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode); int FDSLoad(const char *name, FCEUFILE *fp); int NSFLoad(const char *name, FCEUFILE *fp); -//char lastLoadedGameName [2048] = {0,}; // hack for movie WRAM clearing on record from poweron - //name should be UTF-8, hopefully, or else there may be trouble FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silent) { @@ -414,28 +425,35 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen int lastpal = PAL; int lastdendy = dendy; - const char* romextensions[] = { "nes", "fds", 0 }; - fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions); + const char* romextensions[] = { "nes", "fds", "nsf", 0 }; + + // indicator for if the operaton was canceled by user + // currently there's only one situation: + // the user clicked cancel form the open from archive dialog + int userCancel = 0; + fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions, &userCancel); if (!fp) { - if (!silent) + // Although !fp, if the operation was canceled from archive select dialog box, don't show the error message; + if (!silent && !userCancel) FCEU_PrintError("Error opening \"%s\"!", name); + return 0; - } else if (fp->archiveFilename != "") + } + else if (fp->archiveFilename != "") { strcpy(fullname, fp->archiveFilename.c_str()); strcat(fullname, "|"); strcat(fullname, fp->filename.c_str()); } else - { strcpy(fullname, name); - } + // reset loaded game BEFORE it's loading. + ResetGameLoaded(); //file opened ok. start loading. FCEU_printf("Loading %s...\n\n", fullname); GetFileBase(fp->filename.c_str()); - ResetGameLoaded(); //reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing MasterRomInfoParams = TMasterRomInfoParams(); @@ -446,7 +464,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen FCEU_CloseGame(); GameInfo = new FCEUGI(); - memset(GameInfo, 0, sizeof(FCEUGI)); + memset( (void*)GameInfo, 0, sizeof(FCEUGI)); GameInfo->filename = strdup(fp->filename.c_str()); if (fp->archiveFilename != "") @@ -464,99 +482,115 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen //try to load each different format bool FCEUXLoad(const char *name, FCEUFILE * fp); - /*if(FCEUXLoad(name,fp)) - goto endlseq;*/ - if (iNESLoad(fullname, fp, OverwriteVidMode)) - goto endlseq; - if (NSFLoad(fullname, fp)) - goto endlseq; - if (UNIFLoad(fullname, fp)) - goto endlseq; - if (FDSLoad(fullname, fp)) - goto endlseq; - if (!silent) - FCEU_PrintError("An error occurred while loading the file."); - FCEU_fclose(fp); - - delete GameInfo; - GameInfo = 0; - - return 0; - - endlseq: - - FCEU_fclose(fp); - -#ifdef WIN32 -// ################################## Start of SP CODE ########################### - extern char LoadedRomFName[2048]; - extern int loadDebugDataFailed; - - if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))) - if (!silent) - FCEU_printf("Couldn't load debugging data.\n"); - -// ################################## End of SP CODE ########################### -#endif - - if (OverwriteVidMode) - FCEU_ResetVidSys(); - - if (GameInfo->type != GIT_NSF) + int load_result; + load_result = iNESLoad(fullname, fp, OverwriteVidMode); + if (load_result == LOADER_INVALID_FORMAT) { - if (FSettings.GameGenie) + load_result = NSFLoad(fullname, fp); + if (load_result == LOADER_INVALID_FORMAT) { - if (FCEU_OpenGenie()) + load_result = UNIFLoad(fullname, fp); + if (load_result == LOADER_INVALID_FORMAT) { - FCEUI_SetGameGenie(false); -#ifdef WIN32 - genie = 0; -#endif + load_result = FDSLoad(fullname, fp); } } - } - PowerNES(); - - if (GameInfo->type != GIT_NSF) - FCEU_LoadGamePalette(); - - FCEU_ResetPalette(); - FCEU_ResetMessages(); // Save state, status messages, etc. - - if (!lastpal && PAL) { - FCEU_DispMessage("PAL mode set", 0); - FCEUI_printf("PAL mode set"); - } else if (!lastdendy && dendy) { - // this won't happen, since we don't autodetect dendy, but maybe someday we will? - FCEU_DispMessage("Dendy mode set", 0); - FCEUI_printf("Dendy mode set"); - } else if ((lastpal || lastdendy) && !(PAL || dendy)) { - FCEU_DispMessage("NTSC mode set", 0); - FCEUI_printf("NTSC mode set"); - } - - if (GameInfo->type != GIT_NSF) - FCEU_LoadGameCheats(0); - - if (AutoResumePlay) + } + if (load_result == LOADER_OK) { - // load "-resume" savestate - if (FCEUSS_Load(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false)) - FCEU_DispMessage("Old play session resumed.", 0); - } - ResetScreenshotsCounter(); +#ifdef __WIN_DRIVER__ + // ################################## Start of SP CODE ########################### + extern char LoadedRomFName[2048]; + extern int loadDebugDataFailed; -#if defined (WIN32) || defined (WIN64) - DoDebuggerDataReload(); // Reloads data without reopening window - CDLoggerROMChanged(); - if (hMemView) UpdateColorTable(); - if (hCheat) UpdateCheatsAdded(); - if (FrozenAddressCount) - FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount); + if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))) + if (!silent) + FCEU_printf("Couldn't load debugging data.\n"); + + // ################################## End of SP CODE ########################### #endif + if (OverwriteVidMode) + FCEU_ResetVidSys(); + + if (GameInfo->type != GIT_NSF && + FSettings.GameGenie && + FCEU_OpenGenie()) + { + FCEUI_SetGameGenie(false); +#ifdef __WIN_DRIVER__ + genie = 0; +#endif + } + + PowerNES(); + + if (GameInfo->type != GIT_NSF) + FCEU_LoadGamePalette(); + + FCEU_ResetPalette(); + FCEU_ResetMessages(); // Save state, status messages, etc. + + if (!lastpal && PAL) { + FCEU_DispMessage("PAL mode set", 0); + FCEUI_printf("PAL mode set\n"); + } + else if (!lastdendy && dendy) { + // this won't happen, since we don't autodetect dendy, but maybe someday we will? + FCEU_DispMessage("Dendy mode set", 0); + FCEUI_printf("Dendy mode set\n"); + } + else if ((lastpal || lastdendy) && !(PAL || dendy)) { + FCEU_DispMessage("NTSC mode set", 0); + FCEUI_printf("NTSC mode set\n"); + } + + if (GameInfo->type != GIT_NSF && !disableAutoLSCheats) + FCEU_LoadGameCheats(0); + + if (AutoResumePlay) + { + // load "-resume" savestate + if (FCEUSS_Load(FCEU_MakeFName(FCEUMKF_RESUMESTATE, 0, 0).c_str(), false)) + FCEU_DispMessage("Old play session resumed.", 0); + } + + ResetScreenshotsCounter(); + +#ifdef __WIN_DRIVER__ + DoDebuggerDataReload(); // Reloads data without reopening window + CDLoggerROMChanged(); + if (hMemView) UpdateColorTable(); + if (hCheat) + { + UpdateCheatsAdded(); + UpdateCheatRelatedWindow(); + } + if (FrozenAddressCount) + FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount); +#endif + } + else { + if (!silent) + { + switch (load_result) + { + case LOADER_UNHANDLED_ERROR: + FCEU_PrintError("An error occurred while loading the file."); + break; + case LOADER_INVALID_FORMAT: + FCEU_PrintError("Unknown ROM file format."); + break; + } + } + + delete GameInfo; + GameInfo = 0; + } + + FCEU_fclose(fp); return GameInfo; } @@ -610,47 +644,81 @@ void FCEUI_Kill(void) { } int rapidAlternator = 0; -int AutoFirePattern[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; +//int AutoFirePattern[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; int AutoFirePatternLength = 2; -void SetAutoFirePattern(int onframes, int offframes) { - int i; - for (i = 0; i < onframes && i < 8; i++) { - AutoFirePattern[i] = 1; - } - for (; i < 8; i++) { - AutoFirePattern[i] = 0; - } - if (onframes + offframes < 2) { - AutoFirePatternLength = 2; - } else if (onframes + offframes > 8) { - AutoFirePatternLength = 8; - } else { - AutoFirePatternLength = onframes + offframes; - } +void SetAutoFirePattern(int onframes, int offframes) +{ + //int i; + //for (i = 0; i < onframes && i < 8; i++) { + // AutoFirePattern[i] = 1; + //} + //for (; i < 8; i++) { + // AutoFirePattern[i] = 0; + //} + //if (onframes + offframes < 2) { + // AutoFirePatternLength = 2; + //} else if (onframes + offframes > 8) { + // AutoFirePatternLength = 8; + //} else { + // AutoFirePatternLength = onframes + offframes; + //} + AutoFirePatternLength = onframes + offframes; AFon = onframes; AFoff = offframes; } -void SetAutoFireOffset(int offset) { +void GetAutoFirePattern( int *onframes, int *offframes) +{ + if ( onframes ) + { + *onframes = AFon; + } + if ( offframes ) + { + *offframes = AFoff; + } +} + +void SetAutoFireOffset(int offset) +{ if (offset < 0 || offset > 8) return; AutoFireOffset = offset; } -void AutoFire(void) { +bool GetAutoFireState(int btnIdx) +{ + return rapidAlternator; +} + +void AutoFire(void) +{ static int counter = 0; if (justLagged == false) - counter = (counter + 1) % (8 * 7 * 5 * 3); + { + //counter = (counter + 1) % (8 * 7 * 5 * 3); + counter = (counter + 1) % AutoFirePatternLength; + } //If recording a movie, use the frame # for the autofire so the offset //doesn't get screwed up when loading. - if (FCEUMOV_Mode(MOVIEMODE_RECORD | MOVIEMODE_PLAY)) { - rapidAlternator = AutoFirePattern[(AutoFireOffset + FCEUMOV_GetFrame()) % AutoFirePatternLength]; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire? - } else { - rapidAlternator = AutoFirePattern[(AutoFireOffset + counter) % AutoFirePatternLength]; + if (FCEUMOV_Mode(MOVIEMODE_RECORD | MOVIEMODE_PLAY)) + { + //rapidAlternator = AutoFirePattern[(AutoFireOffset + FCEUMOV_GetFrame()) % AutoFirePatternLength]; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire? + //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire? + rapidAlternator = ( (AutoFireOffset + FCEUMOV_GetFrame()) % AutoFirePatternLength ) < AFon; + } + else + { + //rapidAlternator = AutoFirePattern[(AutoFireOffset + counter) % AutoFirePatternLength]; + rapidAlternator = ( (AutoFireOffset + counter) % AutoFirePatternLength ) < AFon; } } void UpdateAutosave(void); +#ifdef __QT_DRIVER__ +extern unsigned int frameAdvHoldTimer; +#endif + ///Emulates a single frame. ///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame @@ -662,10 +730,27 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski if (frameAdvanceRequested) { +#ifdef __QT_DRIVER__ + uint32_t frameAdvanceDelayScaled = frameAdvance_Delay * (PAL ? 20 : 16); + + if ( frameAdvanceDelayScaled < 1 ) + { + frameAdvanceDelayScaled = 1; + } + if ( (frameAdvance_Delay_count == 0) || (frameAdvHoldTimer >= frameAdvanceDelayScaled) ) + { + EmulationPaused = EMULATIONPAUSED_FA; + } + if (frameAdvance_Delay_count < frameAdvanceDelayScaled) + { + frameAdvance_Delay_count++; + } +#else if (frameAdvance_Delay_count == 0 || frameAdvance_Delay_count >= frameAdvance_Delay) EmulationPaused = EMULATIONPAUSED_FA; if (frameAdvance_Delay_count < frameAdvance_Delay) frameAdvance_Delay_count++; +#endif } if (EmulationPaused & EMULATIONPAUSED_FA) @@ -673,7 +758,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski // the user is holding Frame Advance key // clear paused flag temporarily EmulationPaused &= ~EMULATIONPAUSED_PAUSED; -#ifdef WIN32 +#ifdef __WIN_DRIVER__ // different emulation speed when holding Frame Advance if (fps_scale_frameadvance > 0) { @@ -683,7 +768,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski #endif } else { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (fps_scale_frameadvance > 0) { // restore emulation speed when Frame Advance is not held @@ -722,13 +807,21 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski if (skip != 2) ssize = FlushEmulateSound(); //If skip = 2 we are skipping sound processing + //flush tracer once a frame, since we're likely to end up back at a user interaction loop after this with emulation paused + FCEUD_FlushTrace(); + #ifdef _S9XLUA_H CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); #endif -#ifdef WIN32 + FCEU_PutImage(); + +#ifdef __WIN_DRIVER__ //These Windows only dialogs need to be updated only once per frame so they are included here - UpdateCheatList(); // CaH4e3: can't see why, this is only cause problems with selection - adelikat: selection is only a problem when not paused, it shoudl be paused to select, we want to see the values update + // CaH4e3: can't see why, this is only cause problems with selection + // adelikat: selection is only a problem when not paused, it should be paused to select, we want to see the values update + // owomomo: use an OWNERDATA CListCtrl to partially solve the problem + UpdateCheatList(); UpdateTextHooker(); Update_RAM_Search(); // Update_RAM_Watch() is also called. RamChange(); @@ -762,7 +855,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski { EmulationPaused = EMULATIONPAUSED_PAUSED; // restore EMULATIONPAUSED_PAUSED flag and clear EMULATIONPAUSED_FA flag JustFrameAdvanced = true; - #ifdef WIN32 + #ifdef __WIN_DRIVER__ if (soundoptions & SO_MUTEFA) //mute the frame advance if the user requested it *SoundBufSize = 0; //keep sound muted #endif @@ -796,7 +889,7 @@ void ResetNES(void) { extern uint8 *XBackBuf; memset(XBackBuf, 0, 256 * 256); - //FCEU_DispMessage("Reset", 0); + // FCEU_DispMessage("Reset", 0); } @@ -927,7 +1020,7 @@ void PowerNES(void) { timestampbase = 0; X6502_Power(); -#ifdef WIN32 +#ifdef __WIN_DRIVER__ ResetDebugStatisticsCounters(); #endif FCEU_PowerCheats(); @@ -936,11 +1029,11 @@ void PowerNES(void) { extern uint8 *XBackBuf; memset(XBackBuf, 0, 256 * 256); -#ifdef WIN32 +#ifdef __WIN_DRIVER__ Update_RAM_Search(); // Update_RAM_Watch() is also called. #endif - FCEU_DispMessage("Power on", 0); + // FCEU_DispMessage("Power on", 0); } void FCEU_ResetVidSys(void) { @@ -970,7 +1063,8 @@ void FCEU_ResetVidSys(void) { FCEUS FSettings; -void FCEU_printf(char *format, ...) { +void FCEU_printf(const char *format, ...) +{ #ifndef GEKKO char temp[2048]; @@ -991,7 +1085,8 @@ void FCEU_printf(char *format, ...) { #endif } -void FCEU_PrintError(char *format, ...) { +void FCEU_PrintError(const char *format, ...) +{ #ifndef GEKKO char temp[2048]; @@ -1037,51 +1132,67 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) { } #ifndef GEKKO -void FCEUI_SetRegion(int region, int notify) { +int FCEUI_GetRegion(void) +{ + int region; + + if ( pal_emulation ) + { + region = 1; + } + else if ( dendy ) + { + region = 2; + } + else + { + region = 0; + } + return region; +} + +void FCEUI_SetRegion(int region, int notify) +{ switch (region) { case 0: // NTSC normalscanlines = 240; pal_emulation = 0; dendy = 0; -// until it's fixed on sdl. see issue #740 -#ifdef WIN32 + if (notify) { FCEU_DispMessage("NTSC mode set", 0); - FCEUI_printf("NTSC mode set"); + FCEUI_printf("NTSC mode set\n"); } -#endif break; case 1: // PAL normalscanlines = 240; pal_emulation = 1; dendy = 0; -#ifdef WIN32 + if (notify) { FCEU_DispMessage("PAL mode set", 0); - FCEUI_printf("PAL mode set"); + FCEUI_printf("PAL mode set\n"); } -#endif break; case 2: // Dendy normalscanlines = 290; pal_emulation = 0; dendy = 1; -#ifdef WIN32 + if (notify) { FCEU_DispMessage("Dendy mode set", 0); - FCEUI_printf("Dendy mode set"); + FCEUI_printf("Dendy mode set\n"); } -#endif break; } normalscanlines += newppu; totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0); FCEUI_SetVidSystem(pal_emulation); RefreshThrottleFPS(); -#ifdef WIN32 +#ifdef __WIN_DRIVER__ UpdateCheckedMenuItems(); PushCurrentVideoSettings(); #endif @@ -1125,12 +1236,16 @@ void FCEUI_ClearEmulationFrameStepped() //ideally maybe we shouldnt be using this, but i need it for quick merging void FCEUI_SetEmulationPaused(int val) { EmulationPaused = val; + if(EmulationPaused) + FCEUD_FlushTrace(); } void FCEUI_ToggleEmulationPause(void) { EmulationPaused = (EmulationPaused & EMULATIONPAUSED_PAUSED) ^ EMULATIONPAUSED_PAUSED; DebuggerWasUpdated = false; + if(EmulationPaused) + FCEUD_FlushTrace(); } void FCEUI_FrameAdvanceEnd(void) { @@ -1210,10 +1325,14 @@ bool FCEU_IsValidUI(EFCEUI ui) { break; case FCEUI_STOPMOVIE: - return(FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED)); + case FCEUI_TOGGLERECORDINGMOVIE: + return FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_FINISHED); case FCEUI_PLAYFROMBEGINNING: - return(FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_TASEDITOR | MOVIEMODE_FINISHED)); + return FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD | MOVIEMODE_TASEDITOR | MOVIEMODE_FINISHED); + + case FCEUI_TRUNCATEMOVIE: + return FCEUMOV_Mode(MOVIEMODE_PLAY | MOVIEMODE_RECORD); case FCEUI_STOPAVI: return FCEUI_AviIsRecording(); @@ -1229,12 +1348,21 @@ bool FCEU_IsValidUI(EFCEUI ui) { case FCEUI_INSERT_COIN: if (!GameInfo) return false; if (FCEUMOV_Mode(MOVIEMODE_RECORD)) return true; -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR) && isTaseditorRecording()) return true; #endif if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false; break; + + case FCEUI_INPUT_BARCODE: + if (!GameInfo) return false; + if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false; + break; + default: + // Unhandled falls out to end of function + break; } + #endif return true; } @@ -1295,10 +1423,16 @@ virtual void Power() { } }; -void FCEUXGameInterface(GI command) { - switch (command) { - case GI_POWER: - cart->Power(); +void FCEUXGameInterface(GI command) +{ + switch (command) + { + case GI_POWER: + cart->Power(); + break; + default: + // Unhandled cases + break; } } @@ -1366,8 +1500,8 @@ uint8 FCEU_ReadRomByte(uint32 i) { void FCEU_WriteRomByte(uint32 i, uint8 value) { if (i < 16) -#ifdef WIN32 - MessageBox(hMemView,"Sorry", "You can't edit the ROM header.", MB_OK); +#ifdef __WIN_DRIVER__ + MessageBox(hMemView, "Sorry", "You can't edit the ROM header.", MB_OK | MB_ICONERROR); #else printf("Sorry, you can't edit the ROM header.\n"); #endif diff --git a/source/fceultra/fceu.h b/source/fceultra/fceu.h index 1b76249..7fec58c 100644 --- a/source/fceultra/fceu.h +++ b/source/fceultra/fceu.h @@ -17,6 +17,7 @@ extern int postrenderscanlines; extern int vblankscanlines; extern bool AutoResumePlay; +extern bool frameAdvanceLagSkip; extern char romNameWhenClosingEmulator[]; #define DECLFR(x) uint8 x (uint32 A) @@ -39,16 +40,20 @@ void PowerNES(void); void SetAutoFireOffset(int offset); void SetAutoFirePattern(int onframes, int offframes); +void GetAutoFirePattern( int *onframes, int *offframes); +bool GetAutoFireState(int btnIdx); void AutoFire(void); void FCEUI_RewindToLastAutosave(void); //mbg 7/23/06 -char *FCEUI_GetAboutString(); +const char *FCEUI_GetAboutString(void); extern uint64 timestampbase; + +// MMC5 external shared buffers/vars +extern int MMC5Hack; extern uint32 MMC5HackVROMMask; extern uint8 *MMC5HackExNTARAMPtr; -extern int MMC5Hack, PEC586Hack; extern uint8 *MMC5HackVROMPTR; extern uint8 MMC5HackCHRMode; extern uint8 MMC5HackSPMode; @@ -56,11 +61,19 @@ extern uint8 MMC50x5130; extern uint8 MMC5HackSPScroll; extern uint8 MMC5HackSPPage; +extern int PEC586Hack; + +// VRCV extarnal shared buffers/vars +extern int QTAIHack; +extern uint8 QTAINTRAM[2048]; +extern uint8 qtaintramreg; #define GAME_MEM_BLOCK_SIZE 131072 extern uint8 *RAM; //shared memory modifications extern int EmulationPaused; +extern int frameAdvance_Delay; +extern int RAMInitOption; uint8 FCEU_ReadRomByte(uint32 i); void FCEU_WriteRomByte(uint32 i, uint8 value); @@ -85,10 +98,11 @@ extern int GameAttributes; extern uint8 PAL; extern int dendy; +extern bool movieSubtitles; //#include "driver.h" -typedef struct { +typedef struct fceu_settings_struct { int PAL; int NetworkPlay; int SoundVolume; //Master volume @@ -125,10 +139,10 @@ extern FCEUS FSettings; bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists -void FCEU_PrintError(char *format, ...); -void FCEU_printf(char *format, ...); -void FCEU_DispMessage(char *format, int disppos, ...); -void FCEU_DispMessageOnMovie(char *format, ...); +void FCEU_PrintError(const char *format, ...); +void FCEU_printf(const char *format, ...); +void FCEU_DispMessage(const char *format, int disppos, ...); +void FCEU_DispMessageOnMovie(const char *format, ...); void FCEU_TogglePPU(); void SetNESDeemph_OldHacky(uint8 d, int force); @@ -149,14 +163,20 @@ extern uint8 vsdip; //#define FCEUDEF_DEBUGGER //mbg merge 7/17/06 - cleaning out conditional compiles -#define JOY_A 1 -#define JOY_B 2 -#define JOY_SELECT 4 -#define JOY_START 8 -#define JOY_UP 0x10 +#define JOY_A 0x01 +#define JOY_B 0x02 +#define JOY_SELECT 0x04 +#define JOY_START 0x08 +#define JOY_UP 0x10 #define JOY_DOWN 0x20 #define JOY_LEFT 0x40 #define JOY_RIGHT 0x80 + +#define LOADER_INVALID_FORMAT 0 +#define LOADER_OK 1 +#define LOADER_HANDLED_ERROR 2 +#define LOADER_UNHANDLED_ERROR 3 + #endif #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) diff --git a/source/fceultra/fds.cpp b/source/fceultra/fds.cpp index 6ec9df3..c5d0a45 100644 --- a/source/fceultra/fds.cpp +++ b/source/fceultra/fds.cpp @@ -90,12 +90,31 @@ static int32 DiskPtr; static int32 DiskSeekIRQ; static uint8 SelectDisk, InDisk; +/* 4024(w), 4025(w), 4031(r) by dink(fbneo) */ +enum FDS_DiskBlockIDs { DSK_INIT = 0, DSK_VOLUME, DSK_FILECNT, DSK_FILEHDR, DSK_FILEDATA }; +static uint8 mapperFDS_control; // 4025(w) control register +static uint16 mapperFDS_filesize; // size of file being read/written +static uint8 mapperFDS_block; // block-id of current block +static uint16 mapperFDS_blockstart; // start-address of current block +static uint16 mapperFDS_blocklen; // length of current block +static uint16 mapperFDS_diskaddr; // current address relative to blockstart +static uint8 mapperFDS_diskaccess; // disk needs to be accessed at least once before writing +#define fds_disk() (diskdata[InDisk][mapperFDS_blockstart + mapperFDS_diskaddr]) +#define mapperFDS_diskinsert (InDisk != 255) + + #define DC_INC 1 void FDSGI(GI h) { - switch (h) { - case GI_CLOSE: FDSClose(); break; - case GI_POWER: FDSInit(); break; + switch (h) + { + case GI_CLOSE: FDSClose(); break; + case GI_POWER: FDSInit(); break; + + // Unhandled Cases + case GI_RESETM2: + case GI_RESETSAVE: + break; } } @@ -145,6 +164,14 @@ static void FDSInit(void) { FDSSoundReset(); InDisk = 0; SelectDisk = 0; + + mapperFDS_control = 0; + mapperFDS_filesize = 0; + mapperFDS_block = 0; + mapperFDS_blockstart = 0; + mapperFDS_blocklen = 0; + mapperFDS_diskaddr = 0; + mapperFDS_diskaccess = 0; } void FCEU_FDSInsert(void) @@ -200,16 +227,18 @@ void FCEU_FDSSelect(void) FCEU_DispMessage("", 0); //FCEU_DispMessage("Disk %d Side %c Selected", 0, SelectDisk >> 1, (SelectDisk & 1) ? 'B' : 'A'); } +#define IRQ_Repeat (IRQa & 0x01) +#define IRQ_Enabled (IRQa & 0x02) + static void FDSFix(int a) { - if ((IRQa & 2) && IRQCount) { + if ((IRQa & IRQ_Enabled) && IRQCount) { IRQCount -= a; if (IRQCount <= 0) { - if (!(IRQa & 1)) { - IRQa &= ~2; - IRQCount = IRQLatch = 0; - } else - IRQCount = IRQLatch; + IRQCount = IRQLatch; X6502_IRQBegin(FCEU_IQEXT); + if (!(IRQa & IRQ_Repeat)) { + IRQa &= ~IRQ_Enabled; + } } } if (DiskSeekIRQ > 0) { @@ -237,17 +266,45 @@ static DECLFR(FDSRead4030) { } static DECLFR(FDSRead4031) { - static uint8 z = 0; - if (InDisk != 255) { - z = diskdata[InDisk][DiskPtr]; - if (!fceuindbg) { - if (DiskPtr < 64999) DiskPtr++; - DiskSeekIRQ = 150; - X6502_IRQEnd(FCEU_IQEXT2); + static uint8 ret = 0; + + ret = 0xff; + if (mapperFDS_diskinsert && mapperFDS_control & 0x04) { + mapperFDS_diskaccess = 1; + + ret = 0; + + switch (mapperFDS_block) { + case DSK_FILEHDR: + if (mapperFDS_diskaddr < mapperFDS_blocklen) { + ret = fds_disk(); + switch (mapperFDS_diskaddr) { + case 13: mapperFDS_filesize = ret; break; + case 14: + mapperFDS_filesize |= ret << 8; + //char fdsfile[10]; + //strncpy(fdsfile, (char*)&diskdata[InDisk][mapperFDS_blockstart + 3], 8); + //printf("Read file: %s (size: %d)\n"), fdsfile, mapperFDS_filesize); + break; + } + mapperFDS_diskaddr++; + } + break; + default: + if (mapperFDS_diskaddr < mapperFDS_blocklen) { + ret = fds_disk(); + mapperFDS_diskaddr++; + } + break; } + + DiskSeekIRQ = 150; + X6502_IRQEnd(FCEU_IQEXT2); } - return z; + + return ret; } + static DECLFR(FDSRead4032) { uint8 ret; @@ -537,33 +594,87 @@ static DECLFW(FDSWrite) { break; case 0x4023: break; case 0x4024: - if ((InDisk != 255) && !(FDSRegs[5] & 0x4) && (FDSRegs[3] & 0x1)) { - if (DiskPtr >= 0 && DiskPtr < 65500) { - if (writeskip) - writeskip--; - else if (DiskPtr >= 2) { - DiskWritten = 1; - diskdata[InDisk][DiskPtr - 2] = V; - } + if (mapperFDS_diskinsert && ~mapperFDS_control & 0x04) { + + if (mapperFDS_diskaccess == 0) { + mapperFDS_diskaccess = 1; + break; } + + switch (mapperFDS_block) { + case DSK_FILEHDR: + if (mapperFDS_diskaddr < mapperFDS_blocklen) { + fds_disk() = V; + DiskWritten = 1; + switch (mapperFDS_diskaddr) { + case 13: mapperFDS_filesize = V; break; + case 14: + mapperFDS_filesize |= V << 8; + //char fdsfile[10]; + //strncpy(fdsfile, (char*)&diskdata[InDisk][mapperFDS_blockstart + 3], 8); + //printf("Write file: %s (size: %d)\n"), fdsfile, mapperFDS_filesize); + break; + } + mapperFDS_diskaddr++; + } + break; + default: + if (mapperFDS_diskaddr < mapperFDS_blocklen) { + fds_disk() = V; + DiskWritten = 1; + mapperFDS_diskaddr++; + } + break; + } + } break; case 0x4025: X6502_IRQEnd(FCEU_IQEXT2); - if (InDisk != 255) { - if (!(V & 0x40)) { - if ((FDSRegs[5] & 0x40) && !(V & 0x10)) { - DiskSeekIRQ = 200; - DiskPtr -= 2; + if (mapperFDS_diskinsert) { + if (V & 0x40 && ~mapperFDS_control & 0x40) { + mapperFDS_diskaccess = 0; + + DiskSeekIRQ = 150; + + // blockstart - address of block on disk + // diskaddr - address relative to blockstart + // _block -> _blockID ? + mapperFDS_blockstart += mapperFDS_diskaddr; + mapperFDS_diskaddr = 0; + + mapperFDS_block++; + if (mapperFDS_block > DSK_FILEDATA) + mapperFDS_block = DSK_FILEHDR; + + switch (mapperFDS_block) { + case DSK_VOLUME: + mapperFDS_blocklen = 0x38; + break; + case DSK_FILECNT: + mapperFDS_blocklen = 0x02; + break; + case DSK_FILEHDR: + mapperFDS_blocklen = 0x10; + break; + case DSK_FILEDATA: // + mapperFDS_blocklen = 0x01 + mapperFDS_filesize; + break; } - if (DiskPtr < 0) DiskPtr = 0; } - if (!(V & 0x4)) writeskip = 2; - if (V & 2) { - DiskPtr = 0; DiskSeekIRQ = 200; + + if (V & 0x02) { // transfer reset + mapperFDS_block = DSK_INIT; + mapperFDS_blockstart = 0; + mapperFDS_blocklen = 0; + mapperFDS_diskaddr = 0; + DiskSeekIRQ = 150; + } + if (V & 0x40) { // turn on motor + DiskSeekIRQ = 150; } - if (V & 0x40) DiskSeekIRQ = 200; } + mapperFDS_control = V; setmirror(((V >> 3) & 1) ^ 1); break; } @@ -585,6 +696,7 @@ static int SubLoad(FCEUFILE *fp) { uint8 header[16]; int x; + FCEU_fseek(fp, 0, SEEK_SET); FCEU_fread(header, 16, 1, fp); if (memcmp(header, "FDS\x1a", 4)) { @@ -596,7 +708,7 @@ static int SubLoad(FCEUFILE *fp) { TotalSides = t / 65500; FCEU_fseek(fp, 0, SEEK_SET); } else - return(0); + return 1; } else TotalSides = header[4]; @@ -606,18 +718,12 @@ static int SubLoad(FCEUFILE *fp) { if (TotalSides < 1) TotalSides = 1; for (x = 0; x < TotalSides; x++) { - diskdata[x] = (uint8*)FCEU_malloc(65500); - if (!diskdata[x]) { - int zol; - for (zol = 0; zol < x; zol++) - free(diskdata[zol]); - return 0; - } + if ((diskdata[x] = (uint8*)FCEU_malloc(65500)) == NULL) return 2; FCEU_fread(diskdata[x], 1, 65500, fp); md5_update(&md5, diskdata[x], 65500); } md5_finish(&md5, GameInfo->MD5.data); - return(1); + return 0; } static void PreSave(void) { @@ -643,22 +749,38 @@ int FDSLoad(const char *name, FCEUFILE *fp) { FILE *zp; #endif int x; + + // try to load FDS image first + FreeFDSMemory(); + int load_result = SubLoad(fp); + switch (load_result) + { + case 1: + FreeFDSMemory(); + return LOADER_INVALID_FORMAT; + case 2: + FreeFDSMemory(); + FCEU_PrintError("Unable to allocate memory."); + return LOADER_HANDLED_ERROR; + } + + // load FDS BIOS next #ifndef GEKKO char *fn = strdup(FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str()); if (!(zp = FCEUD_UTF8fopen(fn, "rb"))) { FCEU_PrintError("FDS BIOS ROM image missing: %s", FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str()); free(fn); - return 0; + FreeFDSMemory(); + return LOADER_HANDLED_ERROR; } - free(fn); fseek(zp, 0L, SEEK_END); if (ftell(zp) != 8192) { fclose(zp); FCEU_PrintError("FDS BIOS ROM image incompatible: %s", FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0).c_str()); - return 0; + return LOADER_HANDLED_ERROR; } fseek(zp, 0L, SEEK_SET); #endif @@ -686,23 +808,13 @@ int FDSLoad(const char *name, FCEUFILE *fp) { free(FDSBIOS); FDSBIOS = NULL; fclose(zp); + FreeFDSMemory(); FCEU_PrintError("Error reading FDS BIOS ROM image."); - return 0; + return LOADER_HANDLED_ERROR; } fclose(zp); #endif - FCEU_fseek(fp, 0, SEEK_SET); - - FreeFDSMemory(); - if (!SubLoad(fp)) { -#ifndef GEKKO - if(FDSBIOS) - free(FDSBIOS); - FDSBIOS = NULL; -#endif - return(0); - } if (!disableBatteryLoading) { FCEUFILE *tp; @@ -715,15 +827,16 @@ int FDSLoad(const char *name, FCEUFILE *fp) { } #ifndef GEKKO if ((tp = FCEU_fopen(fn, 0, "rb", 0))) { - FCEU_printf("Disk was written. Auxillary FDS file open \"%s\".\n",fn); + FCEU_printf("Disk was written. Auxiliary FDS file open \"%s\".\n",fn); FreeFDSMemory(); - if (!SubLoad(tp)) { - FCEU_PrintError("Error reading auxillary FDS file."); + if (SubLoad(tp)) { + FCEU_PrintError("Error reading auxiliary FDS file."); if(FDSBIOS) free(FDSBIOS); FDSBIOS = NULL; free(fn); - return(0); + FreeFDSMemory(); + return LOADER_HANDLED_ERROR; } FCEU_fclose(tp); DiskWritten = 1; /* For save state handling. */ @@ -761,6 +874,13 @@ int FDSLoad(const char *name, FCEUFILE *fp) { AddExState(&SelectDisk, 1, 0, "SELD"); AddExState(&InDisk, 1, 0, "INDI"); AddExState(&DiskWritten, 1, 0, "DSKW"); + AddExState(&mapperFDS_control, 1, 0, "CTRG"); + AddExState(&mapperFDS_filesize, 2, 1, "FLSZ"); + AddExState(&mapperFDS_block, 1, 0, "BLCK"); + AddExState(&mapperFDS_blockstart, 2, 1, "BLKS"); + AddExState(&mapperFDS_blocklen, 2, 1, "BLKL"); + AddExState(&mapperFDS_diskaddr, 2, 1, "DADR"); + AddExState(&mapperFDS_diskaccess, 1, 0, "DACC"); CHRRAMSize = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); @@ -778,7 +898,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) { FCEUI_SetVidSystem(0); - return 1; + return LOADER_OK; } void FDSClose(void) { diff --git a/source/fceultra/file.cpp b/source/fceultra/file.cpp index 39f00c8..34872fd 100644 --- a/source/fceultra/file.cpp +++ b/source/fceultra/file.cpp @@ -104,12 +104,14 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp) if((offset+size)>(uint32)fp->size) { // Probably a little slow. - buf=(char *)realloc(buf,offset+size); - if(!buf) + char *newbuf=(char *)realloc(buf,offset+size); + if(!newbuf) { + free(buf); buf=NULL; FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n",count); goto end; } + buf=newbuf; memset(buf+fp->size,0,offset+size-fp->size); fp->size=offset+size; } @@ -127,12 +129,14 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp) if((offset+size)>(uint32)fp->size) { // Probably a little slow. - buf=(char *)realloc(buf,offset+size); - if(!buf) + char *newbuf=(char *)realloc(buf,offset+size); + if(!newbuf) { + free(buf); buf=NULL; FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n",count); goto end; } + buf=newbuf; memset(buf+fp->size,0,offset+size-fp->size); } fread(buf+offset,1,size,ips); @@ -256,14 +260,14 @@ zpfail: return 0; } -FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext, int index, const char** extensions) +FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, const char *mode, char *ext, int index, const char** extensions, int* userCancel) { FILE *ipsfile=0; FCEUFILE *fceufp=0; - bool read = (std::string)mode == "rb"; - bool write = (std::string)mode == "wb"; - if((read&&write) || (!read&&!write)) + bool read = !strcmp(mode, "rb"); + bool write = !strcmp(mode, "wb"); + if(read && write || !read && !write) { FCEU_PrintError("invalid file open mode specified (only wb and rb are supported)"); return 0; @@ -279,16 +283,28 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext if(read) { ArchiveScanRecord asr = FCEUD_ScanArchive(fileToOpen); + if (asr.numFilesInArchive < 0) + { + // error occurred, return + // actually it's canceled not by user but an error message already shown + *userCancel = 1; + return fceufp; + } asr.files.FilterByExtension(extensions); if(!asr.isArchive()) { //if the archive contained no files, try to open it the old fashioned way EMUFILE_FILE* fp = FCEUD_UTF8_fstream(fileToOpen,mode); - if(!fp || (fp->get_fp() == NULL)) + if(!fp) + return 0; + if (fp->get_fp() == NULL) { + //fp is new'ed so it has to be deleted + delete fp; return 0; } + //try to read a zip file { fceufp = TryUnzip(fileToOpen); @@ -355,11 +371,11 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext //open an archive file if(archive == "") if(index != -1) - fceufp = FCEUD_OpenArchiveIndex(asr, fileToOpen, index); + fceufp = FCEUD_OpenArchiveIndex(asr, fileToOpen, index, userCancel); else - fceufp = FCEUD_OpenArchive(asr, fileToOpen, 0); + fceufp = FCEUD_OpenArchive(asr, fileToOpen, 0, userCancel); else - fceufp = FCEUD_OpenArchive(asr, archive, &fname); + fceufp = FCEUD_OpenArchive(asr, archive, &fname, userCancel); if(!fceufp) return 0; @@ -452,6 +468,11 @@ void FCEUI_SetBaseDirectory(std::string const & dir) { BaseDirectory = dir; } +/// Gets the base directory +const char *FCEUI_GetBaseDirectory(void) +{ + return BaseDirectory.c_str(); +} static char *odirs[FCEUIOD__COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0}; // odirs, odors. ^_^ @@ -470,9 +491,9 @@ void FCEUI_SetDirOverride(int which, char *n) va_list ap; int ret; - va_start(ap,fmt); if(!(*strp=(char*)FCEU_dmalloc(2048))) //mbg merge 7/17/06 cast to char* return(0); + va_start(ap,fmt); ret=vsnprintf(*strp,2048,fmt,ap); va_end(ap); return(ret); diff --git a/source/fceultra/file.h b/source/fceultra/file.h index 20c3dd4..84235f7 100644 --- a/source/fceultra/file.h +++ b/source/fceultra/file.h @@ -42,7 +42,7 @@ struct FCEUFILE { FCEUFILE() : stream(0) - , archiveCount(-1) + , archiveCount(-1), archiveIndex(0), size(0), mode(READ) {} ~FCEUFILE() @@ -122,7 +122,7 @@ struct ArchiveScanRecord }; -FCEUFILE *FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext, int index=-1, const char** extensions = 0); +FCEUFILE *FCEU_fopen(const char *path, const char *ipsfn, const char *mode, char *ext, int index=-1, const char** extensions = 0, int* userCancel = 0); bool FCEU_isFileInArchive(const char *path); int FCEU_fclose(FCEUFILE*); uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, FCEUFILE*); diff --git a/source/fceultra/filter.h b/source/fceultra/filter.h index 9a02518..07754ed 100644 --- a/source/fceultra/filter.h +++ b/source/fceultra/filter.h @@ -1,3 +1,4 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover); void MakeFilters(int32 rate); void SexyFilter(int32 *in, int32 *out, int32 count); +void SexyFilter2(int32 *in, int32 count); diff --git a/source/fceultra/git.h b/source/fceultra/git.h index 67accc1..6eca186 100644 --- a/source/fceultra/git.h +++ b/source/fceultra/git.h @@ -38,8 +38,10 @@ enum ESI SI_MOUSE = 6, SI_SNES = 7, SI_SNES_MOUSE = 8, + SI_VIRTUALBOY = 9, + SI_LCDCOMP_ZAPPER = 10, - SI_COUNT = SI_SNES_MOUSE + SI_COUNT = SI_LCDCOMP_ZAPPER }; inline const char* ESI_Name(ESI esi) @@ -54,7 +56,9 @@ inline const char* ESI_Name(ESI esi) "Arkanoid Paddle", "Subor Mouse", "SNES Pad", - "SNES Mouse" + "SNES Mouse", + "Virtual Boy", + "LCD Zapper (Advance)" }; if(esi >= SI_NONE && esi <= SI_COUNT) @@ -82,8 +86,10 @@ enum ESIFC SIFC_OEKAKIDS = 12, SIFC_BWORLD = 13, SIFC_TOPRIDER = 14, + SIFC_FAMINETSYS = 15, + SIFC_HORI4PLAYER = 16, - SIFC_COUNT = SIFC_TOPRIDER + SIFC_COUNT = SIFC_HORI4PLAYER }; @@ -105,7 +111,9 @@ inline const char* ESIFC_Name(ESIFC esifc) "Family Trainer B", "Oeka Kids Tablet", "Barcode World", - "Top Rider" + "Top Rider", + "Famicom Network Controller", + "Hori 4-Player Adapter" }; if(esifc >= SIFC_NONE && esifc <= SIFC_COUNT) diff --git a/source/fceultra/ines-bad.h b/source/fceultra/ines-bad.h index a332b35..1d0d485 100644 --- a/source/fceultra/ines-bad.h +++ b/source/fceultra/ines-bad.h @@ -1,41 +1,41 @@ -{ 0xecf78d8a13a030a6LL, "Ai Sensei no Oshiete", INESB_HACKED }, -{ 0x4712856d3e12f21fLL, "Akumajou Densetsu", INESB_HACKED }, -{ 0x10f90ba5bd55c22eLL, "Alien Syndrome", INESB_HACKED }, -{ 0x0d69ab3ad28ad1c2LL, "Banana", INESB_INCOMPLETE }, -{ 0x85d2c348a161cdbfLL, "Bio Senshi Dan", INESB_HACKED }, -{ 0x18fdb7c16aa8cb5cLL, "Bucky O'Hare", INESB_CORRUPT }, -{ 0xe27c48302108d11bLL, "Chibi Maruko Chan", INESB_HACKED }, -{ 0x9d1f505c6ba507bfLL, "Contra", INESB_HACKED }, -{ 0x60936436d3ea0ab6LL, "Crisis Force", INESB_HACKED }, -{ 0xcf31097ddbb03c5dLL, "Crystalis (Prototype)", INESB_CORRUPT }, -{ 0x92080a8ce94200eaLL, "Digital Devil Story II", INESB_HACKED }, -{ 0x6c2a2f95c2fe4b6eLL, "Dragon Ball", INESB_HACKED }, -{ 0x767aaff62963c58fLL, "Dragon Ball", INESB_HACKED }, -{ 0x97f133d8bc1c28dbLL, "Dragon Ball", INESB_HACKED }, -{ 0x500b267abb323005LL, "Dragon Warrior 4", INESB_CORRUPT }, -{ 0x02bdcf375704784bLL, "Erika to Satoru no Yume Bouken", INESB_HACKED }, -{ 0xd4fea9d2633b9186LL, "Famista 91", INESB_HACKED }, -{ 0xfdf8c812839b61f0LL, "Famista 92", INESB_HACKED }, -{ 0xb5bb1d0fb47d0850LL, "Famista 93", INESB_HACKED }, -{ 0x30471e773f7cdc89LL, "Famista 94", INESB_HACKED }, -{ 0x76c5c44ffb4a0bd7LL, "Fantasy Zone", INESB_HACKED }, -{ 0xb470bfb90e2b1049LL, "Fire Emblem Gaiden", INESB_HACKED }, -{ 0x27da2b0c500dc346LL, "Fire Emblem", INESB_HACKED }, -{ 0x23214fe456fba2ceLL, "Ganbare Goemon 2", INESB_HACKED }, -{ 0xbf8b22524e8329d9LL, "Ganbare Goemon Gaiden", INESB_HACKED }, -{ 0xa97041c3da0134e3LL, "Gegege no Kitarou 2", INESB_INCOMPLETE }, -{ 0x805db49a86db5449LL, "Goonies", INESB_HACKED }, -{ 0xc5abdaa65ac49b6bLL, "Gradius 2", INESB_HACKED }, -{ 0x04afae4ad480c11cLL, "Gradius 2", INESB_HACKED }, -{ 0x9b4bad37b5498992LL, "Gradius 2", INESB_HACKED }, -{ 0xb068d4ac10ef848eLL, "Highway Star", INESB_HACKED }, -{ 0xbf5175271e5019c3LL, "Kaiketsu Yanchamaru 3", INESB_HACKED }, -{ 0x81c1de64550a1531LL, "Nobunaga no Yabou Zenkokuban", INESB_HACKED }, -{ 0xfb4b508a236bbba3LL, "Salamander", INESB_HACKED }, -{ 0x1895afc6eef26c7dLL, "Super Mario Bros.", INESB_HACKED }, -{ 0x3716c4bebf885344LL, "Super Mario Bros.", INESB_HACKED }, -{ 0xfffda4407d80885aLL, "Sweet Home", INESB_CORRUPT }, -{ 0x103fc85d978b861bLL, "Sweet Home", INESB_CORRUPT }, -{ 0x7979dc51da86f19fLL, "110-in-1", INESB_CORRUPT }, -{ 0x001c0bb9c358252aLL, "110-in-1", INESB_CORRUPT }, +{ 0xecf78d8a13a030a6ULL, "Ai Sensei no Oshiete", INESB_HACKED }, +{ 0x4712856d3e12f21fULL, "Akumajou Densetsu", INESB_HACKED }, +{ 0x10f90ba5bd55c22eULL, "Alien Syndrome", INESB_HACKED }, +{ 0x0d69ab3ad28ad1c2ULL, "Banana", INESB_INCOMPLETE }, +{ 0x85d2c348a161cdbfULL, "Bio Senshi Dan", INESB_HACKED }, +{ 0x18fdb7c16aa8cb5cULL, "Bucky O'Hare", INESB_CORRUPT }, +{ 0xe27c48302108d11bULL, "Chibi Maruko Chan", INESB_HACKED }, +{ 0x9d1f505c6ba507bfULL, "Contra", INESB_HACKED }, +{ 0x60936436d3ea0ab6ULL, "Crisis Force", INESB_HACKED }, +{ 0xcf31097ddbb03c5dULL, "Crystalis (Prototype)", INESB_CORRUPT }, +{ 0x92080a8ce94200eaULL, "Digital Devil Story II", INESB_HACKED }, +{ 0x6c2a2f95c2fe4b6eULL, "Dragon Ball", INESB_HACKED }, +{ 0x767aaff62963c58fULL, "Dragon Ball", INESB_HACKED }, +{ 0x97f133d8bc1c28dbULL, "Dragon Ball", INESB_HACKED }, +{ 0x500b267abb323005ULL, "Dragon Warrior 4", INESB_CORRUPT }, +{ 0x02bdcf375704784bULL, "Erika to Satoru no Yume Bouken", INESB_HACKED }, +{ 0xd4fea9d2633b9186ULL, "Famista 91", INESB_HACKED }, +{ 0xfdf8c812839b61f0ULL, "Famista 92", INESB_HACKED }, +{ 0xb5bb1d0fb47d0850ULL, "Famista 93", INESB_HACKED }, +{ 0x30471e773f7cdc89ULL, "Famista 94", INESB_HACKED }, +{ 0x76c5c44ffb4a0bd7ULL, "Fantasy Zone", INESB_HACKED }, +{ 0xb470bfb90e2b1049ULL, "Fire Emblem Gaiden", INESB_HACKED }, +{ 0x27da2b0c500dc346ULL, "Fire Emblem", INESB_HACKED }, +{ 0x23214fe456fba2ceULL, "Ganbare Goemon 2", INESB_HACKED }, +{ 0xbf8b22524e8329d9ULL, "Ganbare Goemon Gaiden", INESB_HACKED }, +{ 0xa97041c3da0134e3ULL, "Gegege no Kitarou 2", INESB_INCOMPLETE }, +{ 0x805db49a86db5449ULL, "Goonies", INESB_HACKED }, +{ 0xc5abdaa65ac49b6bULL, "Gradius 2", INESB_HACKED }, +{ 0x04afae4ad480c11cULL, "Gradius 2", INESB_HACKED }, +{ 0x9b4bad37b5498992ULL, "Gradius 2", INESB_HACKED }, +{ 0xb068d4ac10ef848eULL, "Highway Star", INESB_HACKED }, +{ 0xbf5175271e5019c3ULL, "Kaiketsu Yanchamaru 3", INESB_HACKED }, +{ 0x81c1de64550a1531ULL, "Nobunaga no Yabou Zenkokuban", INESB_HACKED }, +{ 0xfb4b508a236bbba3ULL, "Salamander", INESB_HACKED }, +{ 0x1895afc6eef26c7dULL, "Super Mario Bros.", INESB_HACKED }, +{ 0x3716c4bebf885344ULL, "Super Mario Bros.", INESB_HACKED }, +{ 0xfffda4407d80885aULL, "Sweet Home", INESB_CORRUPT }, +{ 0x103fc85d978b861bULL, "Sweet Home", INESB_CORRUPT }, +{ 0x7979dc51da86f19fULL, "110-in-1", INESB_CORRUPT }, +{ 0x001c0bb9c358252aULL, "110-in-1", INESB_CORRUPT }, { 0, 0, 0 } diff --git a/source/fceultra/ines-correct.h b/source/fceultra/ines-correct.h index b47dbf3..37dc700 100644 --- a/source/fceultra/ines-correct.h +++ b/source/fceultra/ines-correct.h @@ -124,7 +124,6 @@ {0x054bd3e9, 74, -1}, /* Di 4 Ci - Ji Qi Ren Dai Zhan (As) */ {0x496ac8f7, 74, -1}, /* Ji Jia Zhan Shi (As) */ {0xae854cef, 74, -1}, /* Jia A Fung Yun (Chinese) */ - {0xba51ac6f, 78, 2}, {0x3d1c3137, 78, 8}, /* Uchuusen - Cosmo Carrier */ {0xa4fbb438, 79, 0}, {0xd4a76b07, 79, 0}, /* F-15 City Wars*/ @@ -281,4 +280,6 @@ {0x4d4a0e1b, 260|0x1000,-1}, {0xb6dd2c9d, 260|0x1000,-1}, + {0xb02fcb57, 406|0x1000,-1}, /* Haradius Zero ver 1.2a 2019 */ + {0x00000000, -1, -1} diff --git a/source/fceultra/ines.cpp b/source/fceultra/ines.cpp index 52e0531..640133f 100644 --- a/source/fceultra/ines.cpp +++ b/source/fceultra/ines.cpp @@ -67,7 +67,7 @@ static int iNES_Init(int num); static int MapperNo = 0; -static int iNES2 = 0; +int iNES2 = 0; static DECLFR(TrainerRead) { return(trainerpoo[A & 0x1FF]); @@ -201,7 +201,8 @@ static void SetInput(void) { {0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor {0x8b265862, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor {0x82f1fb96, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor 1.0 Russian - {0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa + {0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa (bad dump) + {0xc7bcc981, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa {0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Super Team Games {0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1 {0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Supor English (Chinese) @@ -215,6 +216,7 @@ static void SetInput(void) { {0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman {0x5112dc21, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman {0xaf4010ea, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // World Class Track Meet + {0x67b126b9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FAMINETSYS }, // Famicom Network System {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET } }; int x = 0; @@ -236,7 +238,7 @@ static void SetInput(void) { struct BADINF { uint64 md5partial; - char *name; + const char *name; uint32 type; }; @@ -265,15 +267,15 @@ struct CHINF { }; static const TMasterRomInfo sMasterRomInfo[] = { - { 0x62b51b108a01d2beLL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes - { 0x8bb48490d8d22711LL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes - { 0xc75888d7b48cd378LL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes - { 0xf81a376fa54fdd69LL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes - { 0xa37eb9163e001a46LL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes - { 0xde5ce25860233f7eLL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes - { 0x5b3aa4cdc484a088LL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes - { 0x9342bf9bae1c798aLL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes - { 0x164eea6097a1e313LL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation + { 0x62b51b108a01d2beULL, "bonus=0" }, //4-in-1 (FK23C8021)[p1][!].nes + { 0x8bb48490d8d22711ULL, "bonus=0" }, //4-in-1 (FK23C8033)[p1][!].nes + { 0xc75888d7b48cd378ULL, "bonus=0" }, //4-in-1 (FK23C8043)[p1][!].nes + { 0xf81a376fa54fdd69ULL, "bonus=0" }, //4-in-1 (FK23Cxxxx, S-0210A PCB)[p1][!].nes + { 0xa37eb9163e001a46ULL, "bonus=0" }, //4-in-1 (FK23C8026) [p1][!].nes + { 0xde5ce25860233f7eULL, "bonus=0" }, //4-in-1 (FK23C8045) [p1][!].nes + { 0x5b3aa4cdc484a088ULL, "bonus=0" }, //4-in-1 (FK23C8056) [p1][!].nes + { 0x9342bf9bae1c798aULL, "bonus=0" }, //4-in-1 (FK23C8079) [p1][!].nes + { 0x164eea6097a1e313ULL, "busc=1" }, //Cybernoid - The Fighting Machine (U)[!].nes -- needs bus conflict emulation }; const TMasterRomInfo* MasterRomInfo; TMasterRomInfoParams MasterRomInfoParams; @@ -288,38 +290,39 @@ static void CheckHInfo(void) { static uint64 savie[] = { - 0xc04361e499748382LL, /* AD&D Heroes of the Lance */ - 0xb72ee2337ced5792LL, /* AD&D Hillsfar */ - 0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */ - 0x498c10dc463cfe95LL, /* Battle Fleet */ - 0x854d7947a3177f57LL, /* Crystalis */ - 0x4a1f5336b86851b6LL, /* DW */ - 0xb0bcc02c843c1b79LL, /* DW */ - 0x2dcf3a98c7937c22LL, /* DW 2 */ - 0x98e55e09dfcc7533LL, /* DW 4*/ - 0x733026b6b72f2470LL, /* Dw 3 */ - 0x6917ffcaca2d8466LL, /* Famista '90 */ - 0x8da46db592a1fcf4LL, /* Faria */ - 0xedba17a2c4608d20LL, /* Final Fantasy */ - 0x91a6846d3202e3d6LL, /* Final Fantasy */ - 0x012df596e2b31174LL, /* Final Fantasy 1+2 */ - 0xf6b359a720549ecdLL, /* Final Fantasy 2 */ - 0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */ - 0xd63dcc68c2b20adcLL, /* Final Fantasy J */ - 0x2ee3417ba8b69706LL, /* Hydlide 3*/ - 0xebbce5a54cf3ecc0LL, /* Justbreed */ - 0x6a858da551ba239eLL, /* Kaijuu Monogatari */ - 0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */ - 0x04a31647de80fdabLL, /* Legend of Zelda */ - 0x94b9484862a26cbaLL, /* Legend of Zelda */ - 0xa40666740b7d22feLL, /* Mindseeker */ - 0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */ - 0x77b811b2760104b9LL, /* Mouryou Senki Madara */ - 0x11b69122efe86e8cLL, /* RPG Jinsei Game */ - 0x9aa1dc16c05e7de5LL, /* Startropics */ - 0x1b084107d0878bd0LL, /* Startropics 2*/ - 0xa70b495314f4d075LL, /* Ys 3 */ - 0x836c0ff4f3e06e45LL, /* Zelda 2 */ + 0xc04361e499748382ULL, /* AD&D Heroes of the Lance */ + 0xb72ee2337ced5792ULL, /* AD&D Hillsfar */ + 0x2b7103b7a27bd72fULL, /* AD&D Pool of Radiance */ + 0x498c10dc463cfe95ULL, /* Battle Fleet */ + 0x854d7947a3177f57ULL, /* Crystalis */ + 0xfad22d265cd70820ULL, /* Downtown Special: Kunio-kun no Jidaigeki Dayo Zenin Shuugou! */ + 0x4a1f5336b86851b6ULL, /* DW */ + 0xb0bcc02c843c1b79ULL, /* DW */ + 0x2dcf3a98c7937c22ULL, /* DW 2 */ + 0x98e55e09dfcc7533ULL, /* DW 4*/ + 0x733026b6b72f2470ULL, /* Dw 3 */ + 0x6917ffcaca2d8466ULL, /* Famista '90 */ + 0x8da46db592a1fcf4ULL, /* Faria */ + 0xedba17a2c4608d20ULL, /* Final Fantasy */ + 0x91a6846d3202e3d6ULL, /* Final Fantasy */ + 0x012df596e2b31174ULL, /* Final Fantasy 1+2 */ + 0xf6b359a720549ecdULL, /* Final Fantasy 2 */ + 0x5a30da1d9b4af35dULL, /* Final Fantasy 3 */ + 0xd63dcc68c2b20adcULL, /* Final Fantasy J */ + 0x2ee3417ba8b69706ULL, /* Hydlide 3*/ + 0xebbce5a54cf3ecc0ULL, /* Justbreed */ + 0x6a858da551ba239eULL, /* Kaijuu Monogatari */ + 0x2db8f5d16c10b925ULL, /* Kyonshiizu 2 */ + 0x04a31647de80fdabULL, /* Legend of Zelda */ + 0x94b9484862a26cbaULL, /* Legend of Zelda */ + 0xa40666740b7d22feULL, /* Mindseeker */ + 0x82000965f04a71bbULL, /* Mirai Shinwa Jarvas */ + 0x77b811b2760104b9ULL, /* Mouryou Senki Madara */ + 0x11b69122efe86e8cULL, /* RPG Jinsei Game */ + 0x9aa1dc16c05e7de5ULL, /* Startropics */ + 0x1b084107d0878bd0ULL, /* Startropics 2*/ + 0xa70b495314f4d075ULL, /* Ys 3 */ + 0x836c0ff4f3e06e45ULL, /* Zelda 2 */ 0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */ }; @@ -420,7 +423,7 @@ static void CheckHInfo(void) { if (tofix & 1) sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo); if (tofix & 2) { - char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; + const char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]); } if (tofix & 4) @@ -443,17 +446,19 @@ typedef struct { //that are not in the power of 2 tends to come //in obscure mappers themselves which supports such //size +//Cah4e3 25.10.19: iNES 2.0 attempts to cover all +// boards including UNIF boards with non power 2 +// total rom size (a lot of them with a couple of +// roms different sizes (may vary a lot) +// so we need either add here ALL ines 2.0 mappers +// with not power2 roms or change logic here +// to something more unified for ines 2.0 specific static int not_power2[] = { - 53, 198, 228 + 53, 198, 228, 547 }; -typedef struct { - char *name; - int32 number; - void (*init)(CartInfo *); -} BMAPPINGLocal; -static BMAPPINGLocal bmap[] = { +BMAPPINGLocal bmap[] = { {"NROM", 0, NROM_Init}, {"MMC1", 1, Mapper1_Init}, {"UNROM", 2, UNROM_Init}, @@ -672,9 +677,9 @@ static BMAPPINGLocal bmap[] = { {"", 215, UNL8237_Init}, {"", 216, Mapper216_Init}, {"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper -// {"", 218, Mapper218_Init}, + {"Magic Floor", 218, Mapper218_Init}, {"UNLA9746", 219, UNLA9746_Init}, - {"Debug Mapper", 220, UNLKS7057_Init}, + {"Debug Mapper", 220, QTAi_Init}, {"UNLN625092", 221, UNLN625092_Init}, {"", 222, Mapper222_Init}, // {"", 223, Mapper223_Init}, @@ -725,7 +730,12 @@ static BMAPPINGLocal bmap[] = { {"158B Prot Board", 258, UNL158B_Init}, {"F-15 MMC3 Based", 259, BMCF15_Init}, {"HP10xx/H20xx Boards", 260, BMCHPxx_Init}, - {"810544-CA-1", 261, BMC810544CA1_Init}, + {"810544-CA-1", 261, BMC810544CA1_Init}, + {"SMD132/SMD133", 268, SMD132_SMD133_Init}, + + {"Impact Soft MMC3 Flash Board", 406, Mapper406_Init }, + + {"KONAMI QTAi Board", 547, QTAi_Init }, {"", 0, NULL} }; @@ -733,12 +743,9 @@ static BMAPPINGLocal bmap[] = { int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { struct md5_context md5; - if (FCEU_fread(&head, 1, 16, fp) != 16) - return 0; - - if (memcmp(&head, "NES\x1a", 4)) - return 0; - + if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4)) + return LOADER_INVALID_FORMAT; + head.cleanup(); memset(&iNESCart, 0, sizeof(iNESCart)); @@ -763,15 +770,35 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { } else Mirroring = (head.ROM_type & 1); - int not_round_size = head.ROM_size; - if(iNES2) not_round_size |= ((head.Upper_ROM_VROM_size & 0x0F) << 8); - + int not_round_size; + if (!iNES2) { + not_round_size = head.ROM_size; + } + else { + if ((head.Upper_ROM_VROM_size & 0x0F) != 0x0F) + // simple notation + not_round_size = head.ROM_size | ((head.Upper_ROM_VROM_size & 0x0F) << 8); + else + // exponent-multiplier notation + not_round_size = ((1 << (head.ROM_size >> 2)) * ((head.ROM_size & 0b11) * 2 + 1)) >> 14; + } + if (!head.ROM_size && !iNES2) ROM_size = 256; else ROM_size = uppow2(not_round_size); VROM_size = uppow2(head.VROM_size | (iNES2?((head.Upper_ROM_VROM_size & 0xF0)<<4):0)); + if (!iNES2) { + VROM_size = uppow2(head.VROM_size); + } + else { + if ((head.Upper_ROM_VROM_size & 0xF0) != 0xF0) + // simple notation + VROM_size = uppow2(head.VROM_size | ((head.Upper_ROM_VROM_size & 0xF0) << 4)); + else + VROM_size = ((1 << (head.VROM_size >> 2)) * ((head.VROM_size & 0b11) * 2 + 1)) >> 13; + } int round = true; for (int i = 0; i != sizeof(not_power2) / sizeof(not_power2[0]); ++i) { @@ -794,7 +821,8 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) { free(ROM); ROM = NULL; - return 0; + FCEU_PrintError("Unable to allocate memory."); + return LOADER_HANDLED_ERROR; } memset(VROM, 0xFF, VROM_size << 13); } @@ -828,9 +856,9 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { iNESCart.CRC32 = iNESGameCRC32; - FCEU_printf(" PRG ROM: %3d x 16KiB\n", (round) ? ROM_size: not_round_size); - FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size); - FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); + FCEU_printf(" PRG ROM: %d x 16KiB = %d KiB\n", round ? ROM_size : not_round_size, (round ? ROM_size : not_round_size) * 16); + FCEU_printf(" CHR ROM: %d x 8KiB = %d KiB\n", VROM_size, VROM_size * 8); + FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); { int x; FCEU_printf(" ROM MD5: 0x"); @@ -839,7 +867,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { FCEU_printf("\n"); } - char* mappername = "Not Listed"; + const char* mappername = "Not Listed"; for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { if (bmap[mappertest].number == MapperNo) { @@ -848,7 +876,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { } } - FCEU_printf(" Mapper #: %d\n", MapperNo); + FCEU_printf(" Mapper #: %d\n", MapperNo); FCEU_printf(" Mapper name: %s\n", mappername); FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); @@ -857,12 +885,12 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { { FCEU_printf(" NES2.0 Extensions\n"); FCEU_printf(" Sub Mapper #: %d\n", iNESCart.submapper); - FCEU_printf(" Total WRAM size: %d\n", iNESCart.wram_size + iNESCart.battery_wram_size); - FCEU_printf(" Total VRAM size: %d\n", iNESCart.vram_size + iNESCart.battery_vram_size); + FCEU_printf(" Total WRAM size: %d KiB\n", (iNESCart.wram_size + iNESCart.battery_wram_size) / 1024); + FCEU_printf(" Total VRAM size: %d KiB\n", (iNESCart.vram_size + iNESCart.battery_vram_size) / 1024); if(head.ROM_type & 2) { - FCEU_printf(" WRAM backed by battery: %d\n", iNESCart.battery_wram_size); - FCEU_printf(" VRAM backed by battery: %d\n", iNESCart.battery_vram_size); + FCEU_printf(" WRAM backed by battery: %d KiB\n", iNESCart.battery_wram_size / 1024); + FCEU_printf(" VRAM backed by battery: %d KiB\n", iNESCart.battery_vram_size / 1024); } } @@ -895,8 +923,29 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; iNESCart.mirror = Mirroring; - if (!iNES_Init(MapperNo)) + int result = iNES_Init(MapperNo); + switch(result) + { + case 0: + goto init_ok; + case 1: FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo); + break; + case 2: + FCEU_PrintError("Unable to allocate CHR-RAM."); + break; + } + if (ROM) free(ROM); + if (VROM) free(VROM); + if (trainerpoo) free(trainerpoo); + if (ExtraNTARAM) free(ExtraNTARAM); + ROM = NULL; + VROM = NULL; + trainerpoo = NULL; + ExtraNTARAM = NULL; + return LOADER_HANDLED_ERROR; + +init_ok: GameInfo->mappernum = MapperNo; FCEU_LoadGameSave(&iNESCart); @@ -921,10 +970,6 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { FCEUI_SetVidSystem(((head.TV_system & 3) == 1) ? 1 : 0); } else if (OverwriteVidMode) { if (strstr(name, "(E)") || strstr(name, "(e)") - || strstr(name, "(Europe)") || strstr(name, "(PAL)") - || strstr(name, "(F)") || strstr(name, "(f)") - || strstr(name, "(G)") || strstr(name, "(g)") - || strstr(name, "(I)") || strstr(name, "(i)") || strstr(name, "(Europe)") || strstr(name, "(PAL)") || strstr(name, "(F)") || strstr(name, "(f)") || strstr(name, "(G)") || strstr(name, "(g)") @@ -934,16 +979,16 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { || strstr(name, "(Italy)") || strstr(name, "(Spain)") || strstr(name, "(Sweden)") || strstr(name, "(Sw)") || strstr(name, "(Australia)") || strstr(name, "(A)") - || strstr(name, "(a)")) + || strstr(name, "(a)")) FCEUI_SetVidSystem(1); else FCEUI_SetVidSystem(0); } - return 1; + return LOADER_OK; } // bbit edited: the whole function below was added -int iNesSave() { +int iNesSave(void) { char name[2048]; strcpy(name, LoadedRomFName); @@ -954,7 +999,7 @@ int iNesSave() { return iNesSaveAs(name); } -int iNesSaveAs(char* name) +int iNesSaveAs(const char* name) { //adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function //caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename. @@ -989,7 +1034,7 @@ int iNesSaveAs(char* name) } //para edit: added function below -char *iNesShortFName() { +char *iNesShortFName(void) { char *ret; if (!(ret = strrchr(LoadedRomFName, '\\'))) @@ -1010,7 +1055,7 @@ static int iNES_Init(int num) { while (tmp->init) { if (num == tmp->number) { - UNIFchrrama = 0; // need here for compatibility with UNIF mapper code + UNIFchrrama = NULL; // need here for compatibility with UNIF mapper code if (!VROM_size) { if(!iNESCart.ines2) { @@ -1030,29 +1075,31 @@ static int iNES_Init(int num) { { CHRRAMSize = iNESCart.battery_vram_size + iNESCart.vram_size; } - if ((VROM = (uint8*)FCEU_dmalloc(CHRRAMSize)) == NULL) return 0; - FCEU_MemoryRand(VROM, CHRRAMSize); - - UNIFchrrama = VROM; - if(CHRRAMSize == 0) - { - //probably a mistake. - //but (for chrram): "Use of $00 with no CHR ROM implies that the game is wired to map nametable memory in CHR space. The value $00 MUST NOT be used if a mapper isn't defined to allow this. " - //well, i'm not going to do that now. we'll save it for when it's needed - //"it's only mapper 218 and no other mappers" - } - else + if (CHRRAMSize > 0) { + int mCHRRAMSize = (CHRRAMSize < 1024) ? 1024 : CHRRAMSize; // VPage has a resolution of 1k banks, ensure minimum allocation to prevent malicious access from NES software + if ((UNIFchrrama = VROM = (uint8*)FCEU_dmalloc(mCHRRAMSize)) == NULL) return 2; + FCEU_MemoryRand(VROM, CHRRAMSize); SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); AddExState(VROM, CHRRAMSize, 0, "CHRR"); } + else { + // mapper 256 (OneBus) has not CHR-RAM _and_ has not CHR-ROM region in iNES file + // so zero-sized CHR should be supported at least for this mapper + VROM = NULL; + } } if (head.ROM_type & 8) - AddExState(ExtraNTARAM, 2048, 0, "EXNR"); + { + if (ExtraNTARAM != NULL) + { + AddExState(ExtraNTARAM, 2048, 0, "EXNR"); + } + } tmp->init(&iNESCart); - return 1; + return 0; } tmp++; } - return 0; + return 1; } diff --git a/source/fceultra/ines.h b/source/fceultra/ines.h index 7bcbf47..c34239e 100644 --- a/source/fceultra/ines.h +++ b/source/fceultra/ines.h @@ -43,48 +43,43 @@ extern uint8 *VROM; extern uint32 VROM_size; extern uint32 ROM_size; extern uint8 *ExtraNTARAM; -extern int iNesSave(); //bbit Edited: line added -extern int iNesSaveAs(char* name); +extern int iNesSave(void); //bbit Edited: line added +extern int iNesSaveAs(const char* name); extern char LoadedRomFName[2048]; //bbit Edited: line added +extern char *iNesShortFName(void); extern const TMasterRomInfo* MasterRomInfo; extern TMasterRomInfoParams MasterRomInfoParams; //mbg merge 7/19/06 changed to c++ decl format struct iNES_HEADER { - char ID[4]; /*NES^Z*/ - uint8 ROM_size; - uint8 VROM_size; - uint8 ROM_type; - uint8 ROM_type2; - uint8 ROM_type3; - uint8 Upper_ROM_VROM_size; - uint8 RAM_size; - uint8 VRAM_size; - uint8 TV_system; - uint8 VS_hardware; - uint8 reserved[2]; + char ID[4]; /*NES^Z*/ // 0-3 + uint8 ROM_size; // 4 + uint8 VROM_size; // 5 + uint8 ROM_type; // 6 + uint8 ROM_type2; // 7 + uint8 ROM_type3; // 8 + uint8 Upper_ROM_VROM_size; // 9 + uint8 RAM_size; // 10 + uint8 VRAM_size; // 11 + uint8 TV_system; // 12 + uint8 VS_hardware; // 13 + uint8 reserved[2]; // 14, 15 void cleanup() { - if(!memcmp((char *)(this)+0x7,"DiskDude",8)) - { - memset((char *)(this)+0x7,0,0x9); - } + if(!memcmp((char*)(this) + 0x7, "DiskDude", 8) || !memcmp((char*)(this) + 0x7, "demiforce", 9)) + memset((char*)(this) + 0x7, 0, 0x9); - if(!memcmp((char *)(this)+0x7,"demiforce",9)) + if(!memcmp((char*)(this) + 0xA, "Ni03", 4)) { - memset((char *)(this)+0x7,0,0x9); - } - - if(!memcmp((char *)(this)+0xA,"Ni03",4)) - { - if(!memcmp((char *)(this)+0x7,"Dis",3)) - memset((char *)(this)+0x7,0,0x9); + if(!memcmp((char*)(this) + 0x7, "Dis", 3)) + memset((char*)(this) + 0x7, 0, 0x9); else - memset((char *)(this)+0xA,0,0x6); + memset((char*)(this) + 0xA, 0, 0x6); } } }; + extern struct iNES_HEADER head; //for mappers usage void NSFVRC6_Init(void); @@ -220,6 +215,7 @@ void Mapper186_Init(CartInfo *); void Mapper187_Init(CartInfo *); void Mapper188_Init(CartInfo *); void Mapper189_Init(CartInfo *); +void Mapper190_Init(CartInfo *); void Mapper191_Init(CartInfo *); void Mapper192_Init(CartInfo *); void Mapper193_Init(CartInfo *); @@ -246,6 +242,7 @@ void Mapper213_Init(CartInfo *); void Mapper214_Init(CartInfo *); void Mapper216_Init(CartInfo *); void Mapper217_Init(CartInfo *); +void Mapper218_Init(CartInfo *); void Mapper220_Init(CartInfo *); void Mapper222_Init(CartInfo *); void Mapper225_Init(CartInfo *); @@ -272,5 +269,11 @@ void Mapper250_Init(CartInfo *); void Mapper252_Init(CartInfo *); void Mapper253_Init(CartInfo *); void Mapper254_Init(CartInfo *); +void Mapper406_Init(CartInfo *); +typedef struct { + const char *name; + int32 number; + void (*init)(CartInfo *); +} BMAPPINGLocal; #endif diff --git a/source/fceultra/input.cpp b/source/fceultra/input.cpp index adb5b62..30073f1 100644 --- a/source/fceultra/input.cpp +++ b/source/fceultra/input.cpp @@ -64,6 +64,8 @@ extern INPUTC *FCEU_InitPowerpadB(int w); extern INPUTC *FCEU_InitArkanoid(int w); extern INPUTC *FCEU_InitMouse(int w); extern INPUTC *FCEU_InitSNESMouse(int w); +extern INPUTC *FCEU_InitVirtualBoy(int w); +extern INPUTC *FCEU_InitLCDCompZapper(int w); extern INPUTCFC *FCEU_InitArkanoidFC(void); extern INPUTCFC *FCEU_InitSpaceShadow(void); @@ -77,6 +79,7 @@ extern INPUTCFC *FCEU_InitFamilyTrainerA(void); extern INPUTCFC *FCEU_InitFamilyTrainerB(void); extern INPUTCFC *FCEU_InitOekaKids(void); extern INPUTCFC *FCEU_InitTopRider(void); +extern INPUTCFC *FCEU_InitFamiNetSys(void); extern INPUTCFC *FCEU_InitBarcodeWorld(void); //--------------- @@ -370,7 +373,39 @@ static void StrobeSNES(int w) //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//--------Hori 4 player driver for expansion port-------- +static uint8 Hori4ReadBit[2]; +static void StrobeHori4(void) +{ + Hori4ReadBit[0] = Hori4ReadBit[1] = 0; +} +static uint8 ReadHori4(int w, uint8 ret) +{ + ret &= 1; + + if (Hori4ReadBit[w] < 8) + { + ret |= ((joy[w] >> (Hori4ReadBit[w])) & 1) << 1; + } + else if (Hori4ReadBit[w] < 16) + { + ret |= ((joy[2 + w] >> (Hori4ReadBit[w] - 8)) & 1) << 1; + } + else if (Hori4ReadBit[w] < 24) + { + ret |= (((w ? 0x10 : 0x20) >> (7 - (Hori4ReadBit[w] - 16))) & 1) << 1; + } + if (Hori4ReadBit[w] >= 24) ret |= 2; + else Hori4ReadBit[w]++; + + return(ret); +} + +static INPUTCFC HORI4C = { ReadHori4,0,StrobeHori4,0,0,0 }; +//------------------ + +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ static INPUTC GPC={ReadGP,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP}; static INPUTC GPCVS={ReadGPVS,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP}; @@ -451,9 +486,16 @@ static void SetInputStuff(int port) switch(joyports[port].type) { case SI_GAMEPAD: - if(GameInfo->type==GIT_VSUNI){ - joyports[port].driver = &GPCVS; - } else { + if (GameInfo) + { + if (GameInfo->type==GIT_VSUNI){ + joyports[port].driver = &GPCVS; + } else { + joyports[port].driver= &GPC; + } + } + else + { joyports[port].driver= &GPC; } break; @@ -478,7 +520,14 @@ static void SetInputStuff(int port) case SI_SNES_MOUSE: joyports[port].driver=FCEU_InitSNESMouse(port); break; + case SI_VIRTUALBOY: + joyports[port].driver=FCEU_InitVirtualBoy(port); + break; + case SI_LCDCOMP_ZAPPER: + joyports[port].driver = FCEU_InitLCDCompZapper(port); + break; case SI_NONE: + case SI_UNSET: joyports[port].driver=&DummyJPort; break; } @@ -489,6 +538,7 @@ static void SetInputStuffFC() switch(portFC.type) { case SIFC_NONE: + case SIFC_UNSET: portFC.driver=&DummyPortFC; break; case SIFC_ARKANOID: @@ -534,6 +584,13 @@ static void SetInputStuffFC() case SIFC_TOPRIDER: portFC.driver=FCEU_InitTopRider(); break; + case SIFC_FAMINETSYS: + portFC.driver = FCEU_InitFamiNetSys(); + break; + case SIFC_HORI4PLAYER: + portFC.driver = &HORI4C; + memset(&Hori4ReadBit, 0, sizeof(Hori4ReadBit)); + break; } } @@ -643,7 +700,7 @@ void FCEUI_FDSSelect(void) if(!FCEU_IsValidUI(FCEUI_SWITCH_DISK)) return; - FCEU_DispMessage("Command: Switch disk side", 0); + // FCEU_DispMessage("Command: Switch disk side", 0); FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT); } @@ -652,7 +709,7 @@ void FCEUI_FDSInsert(void) if(!FCEU_IsValidUI(FCEUI_EJECT_DISK)) return; - FCEU_DispMessage("Command: Insert/Eject disk", 0); + // FCEU_DispMessage("Command: Insert/Eject disk", 0); FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT); } @@ -713,7 +770,7 @@ const char* FCEUI_CommandTypeNames[]= "TAS Editor", }; -static void CommandUnImpl(void); +//static void CommandUnImpl(void); static void CommandToggleDip(void); static void CommandStateLoad(void); static void CommandStateSave(void); @@ -813,9 +870,18 @@ struct EMUCMDTABLE FCEUI_CommandTable[]= { EMUCMD_MOVIE_RECORD_TO, EMUCMDTYPE_MOVIE, FCEUD_MovieRecordTo, 0, 0, "Record Movie To...", 0 }, { EMUCMD_MOVIE_REPLAY_FROM, EMUCMDTYPE_MOVIE, FCEUD_MovieReplayFrom, 0, 0, "Play Movie From...", 0 }, { EMUCMD_MOVIE_PLAY_FROM_BEGINNING, EMUCMDTYPE_MOVIE, FCEUI_MoviePlayFromBeginning, 0, 0, "Play Movie From Beginning", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MOVIE_TOGGLE_RECORDING, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleRecording, 0, 0, "Toggle Movie Recording/Playing", 0 }, + { EMUCMD_MOVIE_INSERT_1_FRAME, EMUCMDTYPE_MOVIE, FCEUI_MovieInsertFrame, 0, 0, "Insert 1 Frame To Movie", 0 }, + { EMUCMD_MOVIE_DELETE_1_FRAME, EMUCMDTYPE_MOVIE, FCEUI_MovieDeleteFrame, 0, 0, "Delete 1 Frame From Movie", 0 }, + { EMUCMD_MOVIE_TRUNCATE, EMUCMDTYPE_MOVIE, FCEUI_MovieTruncate, 0, 0, "Truncate Movie At Current Frame", 0 }, { EMUCMD_MOVIE_STOP, EMUCMDTYPE_MOVIE, FCEUI_StopMovie, 0, 0, "Stop Movie", 0 }, { EMUCMD_MOVIE_READONLY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleReadOnly, 0, 0, "Toggle Read-Only", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Toggle Frame Display", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MOVIE_NEXT_RECORD_MODE, EMUCMDTYPE_MOVIE, FCEUI_MovieNextRecordMode, 0, 0, "Next Record Mode", 0 }, + { EMUCMD_MOVIE_PREV_RECORD_MODE, EMUCMDTYPE_MOVIE, FCEUI_MoviePrevRecordMode, 0, 0, "Prev Record Mode", 0 }, + { EMUCMD_MOVIE_RECORD_MODE_TRUNCATE, EMUCMDTYPE_MOVIE, FCEUI_MovieRecordModeTruncate, 0, 0, "Record Mode Truncate", 0 }, + { EMUCMD_MOVIE_RECORD_MODE_OVERWRITE, EMUCMDTYPE_MOVIE, FCEUI_MovieRecordModeOverwrite, 0, 0, "Record Mode Overwrite", 0 }, + { EMUCMD_MOVIE_RECORD_MODE_INSERT, EMUCMDTYPE_MOVIE, FCEUI_MovieRecordModeInsert, 0, 0, "Record Mode Insert", 0 }, + { EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Toggle Frame Display", EMUCMDFLAG_TASEDITOR }, { EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleInputDisplay, 0, 0, "Toggle Input Display", EMUCMDFLAG_TASEDITOR }, { EMUCMD_MOVIE_ICON_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUD_ToggleStatusIcon, 0, 0, "Toggle Status Icon", EMUCMDFLAG_TASEDITOR }, @@ -921,10 +987,11 @@ void FCEUI_HandleEmuCommands(TestCommandState* testfn) } } -static void CommandUnImpl(void) -{ - FCEU_DispMessage("command '%s' unimplemented.",0, FCEUI_CommandTable[i].name); -} +// Function not currently used +//static void CommandUnImpl(void) +//{ +// FCEU_DispMessage("command '%s' unimplemented.",0, FCEUI_CommandTable[i].name); +//} static void CommandToggleDip(void) { @@ -948,7 +1015,7 @@ static void CommandSelectSaveSlot(void) { if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ handleEmuCmdByTaseditor(execcmd); #endif } else @@ -966,7 +1033,7 @@ static void CommandStateSave(void) { if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ handleEmuCmdByTaseditor(execcmd); #endif } else @@ -1058,64 +1125,64 @@ static void LaunchTasEditor(void) static void LaunchMemoryWatch(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ CreateMemWatch(); #endif } static void LaunchDebugger(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ DoDebug(0); #endif } static void LaunchNTView(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ DoNTView(); #endif } static void LaunchPPU(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ DoPPUView(); #endif } static void LaunchHex(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ DoMemView(); #endif } static void LaunchTraceLogger(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ DoTracer(); #endif } static void LaunchCodeDataLogger(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ DoCDLogger(); #endif } static void LaunchCheats(void) { -#ifdef WIN32 - extern HWND pwindow; - ConfigCheats(pwindow); +#ifdef __WIN_DRIVER__ + extern HWND hCheat; + ConfigCheats(hCheat); #endif } static void LaunchRamWatch(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ extern void OpenRamWatch(); //adelikat: Blah blah hacky, I know OpenRamWatch(); #endif @@ -1123,14 +1190,14 @@ static void LaunchRamWatch(void) static void LaunchRamSearch(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ extern void OpenRamSearch(); OpenRamSearch(); #endif } static void RamSearchOpLT(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (GameInfo) { extern void SetSearchType(int SearchType); @@ -1142,7 +1209,7 @@ static void RamSearchOpLT(void) { } static void RamSearchOpGT(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (GameInfo) { extern void SetSearchType(int SearchType); @@ -1154,7 +1221,7 @@ static void RamSearchOpGT(void) { } static void RamSearchOpLTE(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (GameInfo) { extern void SetSearchType(int SearchType); @@ -1166,7 +1233,7 @@ static void RamSearchOpLTE(void) { } static void RamSearchOpGTE(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (GameInfo) { extern void SetSearchType(int SearchType); @@ -1178,7 +1245,7 @@ static void RamSearchOpGTE(void) { } static void RamSearchOpEQ(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (GameInfo) { extern void SetSearchType(int SearchType); @@ -1190,7 +1257,7 @@ static void RamSearchOpEQ(void) { } static void RamSearchOpNE(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (GameInfo) { extern void SetSearchType(int SearchType); @@ -1203,7 +1270,7 @@ static void RamSearchOpNE(void) { static void DebuggerStepInto() { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (GameInfo) { extern void DoDebuggerStepInto(); @@ -1219,7 +1286,7 @@ static void FA_SkipLag(void) static void OpenRom(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ extern HWND hAppWnd; LoadNewGamey(hAppWnd, 0); #endif @@ -1227,14 +1294,14 @@ static void OpenRom(void) static void CloseRom(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ CloseGame(); #endif } void ReloadRom(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) { // load most recent project @@ -1266,14 +1333,14 @@ static void UndoRedoSavestate(void) static void FCEUI_DoExit(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ DoFCEUExit(); #endif } void ToggleFullscreen() { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ extern int SetVideoMode(int fs); //adelikat: Yeah, I know, hacky extern void UpdateCheckedMenuItems(); @@ -1289,21 +1356,34 @@ void ToggleFullscreen() static void TaseditorRewindOn(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ mustRewindNow = true; #endif } static void TaseditorRewindOff(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ mustRewindNow = false; #endif } static void TaseditorCommand(void) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) handleEmuCmdByTaseditor(execcmd); #endif } + +/** +* Function to get command info entry by command number +**/ +EMUCMDTABLE* GetEmuCommandById(int cmd) +{ + for (i = 0; itype == GIT_VSUNI) + if ( (GameInfo != NULL) && (GameInfo->type == GIT_VSUNI) ) return(&ZAPVSC); else return(&ZAPC); diff --git a/source/fceultra/movie.cpp b/source/fceultra/movie.cpp index 37b32b9..131c89d 100644 --- a/source/fceultra/movie.cpp +++ b/source/fceultra/movie.cpp @@ -21,6 +21,7 @@ #include "utils/memory.h" #include "utils/xstring.h" #include +#include #ifdef CREATE_AVI #include "drivers/videolog/nesvideos-piece.h" @@ -28,6 +29,8 @@ #ifdef WIN32 #include + +#ifdef __WIN_DRIVER__ #include "./drivers/win/common.h" #include "./drivers/win/window.h" extern void AddRecentMovieFile(const char *filename); @@ -35,6 +38,8 @@ extern void AddRecentMovieFile(const char *filename); extern bool mustEngageTaseditor; #endif +#endif + extern int RAMInitOption; extern int RAMInitSeed; @@ -98,6 +103,7 @@ int input_display = 0; int frame_display = 0; int rerecord_display = 0; bool fullSaveStateLoads = false; //Option for loading a savestates full contents in read+write mode instead of up to the frame count in the savestate (useful as a recovery option) +int movieRecordMode = 0; //Option for various movie recording modes such as TRUNCATE (normal), OVERWRITE etc. SFORMAT FCEUMOV_STATEINFO[]={ { &currFrameCounter, 4|FCEUSTATE_RLSB, "FCNT"}, @@ -129,7 +135,6 @@ void MovieRecord::dump(MovieData* md, EMUFILE* os, int index) { } MovieData::MovieData() { } void MovieData::truncateAt(int frame) { } void MovieData::installValue(std::string& key, std::string& val) { } -int MovieData::dump(EMUFILE *os, bool binary) { return 0; } int FCEUMOV_GetFrame(void) { return 0; } int FCEUI_GetLagCount(void) { return 0; } bool FCEUI_GetLagged(void) { return false; } @@ -460,12 +465,12 @@ MovieData::MovieData() , fds(false) , palFlag(false) , PPUflag(false) - , RAMInitOption(0) - , RAMInitSeed(0) , rerecordCount(0) , binaryFlag(false) , loadFrameCount(-1) , microphone(false) + , RAMInitOption(0) + , RAMInitSeed(0) { memset(&romChecksum,0,sizeof(MD5DATA)); } @@ -542,7 +547,7 @@ void MovieData::installValue(std::string& key, std::string& val) } } -int MovieData::dump(EMUFILE *os, bool binary) +int MovieData::dump(EMUFILE *os, bool binary, bool seekToCurrFramePos) { int start = os->ftell(); os->fprintf("version %d\n", version); @@ -580,19 +585,30 @@ int MovieData::dump(EMUFILE *os, bool binary) if (this->loadFrameCount >= 0) os->fprintf("length %d\n" , this->loadFrameCount); + int currFramePos = -1; if(binary) { //put one | to start the binary dump os->fputc('|'); - for(int i=0;i<(int)records.size();i++) + for (int i = 0; i < (int)records.size(); i++) + { + if (seekToCurrFramePos && currFrameCounter == i) + currFramePos = os->ftell(); records[i].dumpBinary(this, os, i); + } } else { - for(int i=0;i<(int)records.size();i++) + for (int i = 0; i < (int)records.size(); i++) + { + if (seekToCurrFramePos && currFrameCounter == i) + currFramePos = os->ftell(); records[i].dump(this, os, i); + } } int end = os->ftell(); + if (currFramePos >= 0) + os->fseek(currFramePos, SEEK_SET); return end-start; } @@ -671,7 +687,7 @@ static void LoadFM2_binarychunk(MovieData& movieData, EMUFILE* fp, int size) fp->fseek(curr,SEEK_SET); //the amount todo is the min of the limiting size we received and the remaining contents of the file - int todo = std::min(size, flen); + int todo = std::min(size, flen); int numRecords = todo/recordsize; if (movieData.loadFrameCount!=-1 && movieData.loadFrameCountfail()) { + FCEU_PrintError("Error opening movie output file: %s", fname); + return NULL; + } + strcpy(curMovieFilename, fname); + + return osRecordingMovie; +} + static void closeRecordingMovie() { - if(osRecordingMovie) + if (osRecordingMovie) { delete osRecordingMovie; osRecordingMovie = 0; } } +// Callers shall set the approriate movieMode before calling this +static void RedumpWholeMovieFile(bool justToggledRecording = false) +{ + bool recording = (movieMode == MOVIEMODE_RECORD); + assert((NULL != osRecordingMovie) == (recording != justToggledRecording) && "osRecordingMovie should be consistent with movie mode!"); + + if (NULL == openRecordingMovie(curMovieFilename)) + return; + + currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/, recording); + if (recording) + osRecordingMovie->fflush(); + else + closeRecordingMovie(); +} + +/// Stop movie playback. +static void StopPlayback() +{ + assert(movieMode != MOVIEMODE_RECORD && NULL == osRecordingMovie); + + movieMode = MOVIEMODE_INACTIVE; + FCEU_DispMessageOnMovie("Movie playback stopped."); +} + +// Stop movie playback without closing the movie. +static void FinishPlayback() +{ + assert(movieMode != MOVIEMODE_RECORD); + + extern int closeFinishedMovie; + if (closeFinishedMovie) + StopPlayback(); + else + { + movieMode = MOVIEMODE_FINISHED; + FCEU_DispMessage("Movie finished playing.",0); + } +} + /// Stop movie recording static void StopRecording() { - FCEU_DispMessage("Movie recording stopped.",0); - movieMode = MOVIEMODE_INACTIVE; + assert(movieMode == MOVIEMODE_RECORD); - closeRecordingMovie(); + movieMode = MOVIEMODE_INACTIVE; + RedumpWholeMovieFile(true); + FCEU_DispMessage("Movie recording stopped.",0); } -void FCEUI_StopMovie() +static void OnMovieClosed() { - if(suppressMovieStop) - return; - - if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED) - StopPlayback(); - else if(movieMode == MOVIEMODE_RECORD) - StopRecording(); + assert(movieMode == MOVIEMODE_INACTIVE); curMovieFilename[0] = 0; //No longer a current movie filename freshMovie = false; //No longer a fresh movie loaded if (bindSavestate) AutoSS = false; //If bind movies to savestates is true, then there is no longer a valid auto-save to load -#ifdef WIN32 +#if defined(__WIN_DRIVER__) SetMainWindowText(); #endif } bool bogorf; +void FCEUI_StopMovie() +{ + if (suppressMovieStop) + return; + + if (movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED) + StopPlayback(); + else if (movieMode == MOVIEMODE_RECORD) + StopRecording(); + + OnMovieClosed(); +} + void poweron(bool shouldDisableBatteryLoading) { //// make a for-movie-recording power-on clear the game's save data, too @@ -892,7 +991,10 @@ void FCEUMOV_CreateCleanMovie() currMovieData = MovieData(); currMovieData.palFlag = FCEUI_GetCurrentVidSystem(0,0)!=0; currMovieData.romFilename = FileBase; - currMovieData.romChecksum = GameInfo->MD5; + if ( GameInfo ) + { + currMovieData.romChecksum = GameInfo->MD5; + } currMovieData.guid.newGuid(); currMovieData.fourscore = FCEUI_GetInputFourscore(); currMovieData.microphone = FCEUI_GetInputMicrophone(); @@ -1004,7 +1106,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) return true; //adelikat: file did not fail to load, so return true (false is only for file not exist/unable to open errors } -#ifdef WIN32 +#ifdef __WIN_DRIVER__ //Fix relative path if necessary and then add to the recent movie menu extern std::string BaseDirectory; @@ -1025,6 +1127,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) freshMovie = true; //Movie has been loaded, so it must be unaltered if (bindSavestate) AutoSS = false; //If bind savestate to movie is true, then their isn't a valid auto-save to load, so flag it + cur_input_display = 0; //clear previous input display //fully reload the game to reinitialize everything before playing any movie poweron(true); @@ -1070,7 +1173,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) else FCEU_DispMessage("Replay started Read+Write.",0); -#ifdef WIN32 +#ifdef __WIN_DRIVER__ SetMainWindowText(); #endif @@ -1085,18 +1188,6 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) return true; } -static void openRecordingMovie(const char* fname) -{ - osRecordingMovie = FCEUD_UTF8_fstream(fname, "wb"); - if(!osRecordingMovie) - FCEU_PrintError("Error opening movie output file: %s",fname); - strcpy(curMovieFilename, fname); -#ifdef WIN32 - //Add to the recent movie menu - AddRecentMovieFile(fname); -#endif -} - //begin recording a new movie //TODO - BUG - the record-from-another-savestate doesnt work. @@ -1109,7 +1200,13 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author) FCEUI_StopMovie(); - openRecordingMovie(fname); + if (NULL == openRecordingMovie(fname)) + return; + +#ifdef __WIN_DRIVER__ + //Add to the recent movie menu + AddRecentMovieFile(fname); +#endif currFrameCounter = 0; LagCounterReset(); @@ -1153,7 +1250,7 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author) //either dumps the current joystick state or loads one state from the movie void FCEUMOV_AddInputState() { -#ifdef _WIN32 +#ifdef __WIN_DRIVER__ if (movieMode == MOVIEMODE_TASEDITOR) { // if movie length is less or equal to currFrame, pad it with empty frames @@ -1241,14 +1338,29 @@ void FCEUMOV_AddInputState() mr.commands = _currCommand; _currCommand = 0; - //Adelikat: in normal mode, this is done at the time of loading a savestate in read+write mode + //aquanull: now it supports other recording modes that don't necessarily truncate further frame data //If the user chooses it can be delayed to here - if (fullSaveStateLoads && (currFrameCounter < (int)currMovieData.records.size())) - currMovieData.truncateAt(currFrameCounter); + if (currFrameCounter < (int)currMovieData.records.size()) + switch (movieRecordMode) + { + case MOVIE_RECORD_MODE_OVERWRITE: + currMovieData.records[currFrameCounter].Clone(mr); + break; + case MOVIE_RECORD_MODE_INSERT: + //FIXME: this could be very insufficient + currMovieData.records.insert(currMovieData.records.begin() + currFrameCounter, mr); + break; + //case MOVIE_RECORD_MODE_TRUNCATE: + default: + //Adelikat: in normal mode, this is done at the time of loading a savestate in read+write mode + currMovieData.truncateAt(currFrameCounter); + currMovieData.records.push_back(mr); + break; + } + else + currMovieData.records.push_back(mr); - mr.dump(&currMovieData, osRecordingMovie,currMovieData.records.size()); // to disk - - currMovieData.records.push_back(mr); + mr.dump(&currMovieData, osRecordingMovie, currFrameCounter); // to disk } currFrameCounter++; @@ -1282,33 +1394,42 @@ void FCEUMOV_AddCommand(int cmd) void FCEU_DrawMovies(uint8 *XBuf) { - if(frame_display) + // not the best place, but just working + assert((NULL != osRecordingMovie) == (movieMode == MOVIEMODE_RECORD)); + + if (frame_display) { char counterbuf[32] = {0}; int color = 0x20; - if(movieMode == MOVIEMODE_PLAY) - sprintf(counterbuf,"%d/%d",currFrameCounter,(int)currMovieData.records.size()); - else if(movieMode == MOVIEMODE_RECORD) - sprintf(counterbuf,"%d",currFrameCounter); - else if (movieMode == MOVIEMODE_FINISHED) + + if (movieMode == MOVIEMODE_PLAY) { - sprintf(counterbuf,"%d/%d (finished)",currFrameCounter,(int)currMovieData.records.size()); + sprintf(counterbuf, "%d/%d%s%s", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr()); + } else if (movieMode == MOVIEMODE_RECORD) + { + if (movieRecordMode == MOVIE_RECORD_MODE_TRUNCATE) + sprintf(counterbuf, "%d%s%s (record)", currFrameCounter, GetMovieRecordModeStr(), GetMovieReadOnlyStr()); // nearly classic + else + sprintf(counterbuf, "%d/%d%s%s (record)", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr()); + } else if (movieMode == MOVIEMODE_FINISHED) + { + sprintf(counterbuf,"%d/%d%s%s (finished)",currFrameCounter,(int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr()); color = 0x17; //Show red to get attention - } else if(movieMode == MOVIEMODE_TASEDITOR) + } else if (movieMode == MOVIEMODE_TASEDITOR) { sprintf(counterbuf,"%d",currFrameCounter); } else sprintf(counterbuf,"%d (no movie)",currFrameCounter); - if(counterbuf[0]) + if (counterbuf[0]) DrawTextTrans(ClipSidesOffset+XBuf+FCEU_TextScanlineOffsetFromBottom(30)+1, 256, (uint8*)counterbuf, color+0x80); } - if(rerecord_display && movieMode != MOVIEMODE_INACTIVE) + if (rerecord_display && movieMode != MOVIEMODE_INACTIVE) { char counterbuf[32] = {0}; - sprintf(counterbuf,"%d",currMovieData.rerecordCount); + sprintf(counterbuf, "%d", currMovieData.rerecordCount); - if(counterbuf[0]) + if (counterbuf[0]) DrawTextTrans(ClipSidesOffset+XBuf+FCEU_TextScanlineOffsetFromBottom(50)+1, 256, (uint8*)counterbuf, 0x28+0x80); } } @@ -1363,7 +1484,7 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) { if (currMovieData.loadFrameCount >= 0) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ int result = MessageBox(hAppWnd, "This movie is a TAS Editor project file.\nIt can be modified in TAS Editor only.\n\nOpen it in TAS Editor now?", "Movie Replay", MB_YESNO); if (result == IDYES) mustEngageTaseditor = true; @@ -1451,10 +1572,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) if(tempMovieData.guid != currMovieData.guid) { //mbg 8/18/08 - this code can be used to turn the error message into an OK/CANCEL - #ifdef WIN32 + #ifdef __WIN_DRIVER__ std::string msg = "There is a mismatch between savestate's movie and current movie.\ncurrent: " + currMovieData.guid.toString() + "\nsavestate: " + tempMovieData.guid.toString() + "\n\nThis means that you have loaded a savestate belonging to a different movie than the one you are playing now.\n\nContinue loading this savestate anyway?"; - extern HWND pwindow; - int result = MessageBox(pwindow,msg.c_str(),"Error loading savestate",MB_OKCANCEL); + int result = MessageBox(hAppWnd, msg.c_str(), "Error loading savestate", MB_OKCANCEL); if(result == IDCANCEL) { if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user @@ -1478,10 +1598,15 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) #endif } - closeRecordingMovie(); - if (movie_readonly) { + if (movieMode == MOVIEMODE_RECORD) + { + movieMode = MOVIEMODE_PLAY; + RedumpWholeMovieFile(true); + closeRecordingMovie(); + } + // currFrameCounter at this point represents the savestate framecount int frame_of_mismatch = CheckTimelines(tempMovieData, currMovieData); if (frame_of_mismatch >= 0) @@ -1494,50 +1619,42 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) } else FCEU_PrintError("Error: Savestate not in the same timeline as movie!\nFrame %d branches from current timeline", frame_of_mismatch); return false; - } else if (movieMode == MOVIEMODE_FINISHED - && currFrameCounter > (int)currMovieData.records.size() - && currMovieData.records.size() == tempMovieData.records.size()) + } else if ((int)tempMovieData.records.size() < currFrameCounter) { - // special case (in MOVIEMODE_FINISHED mode) - // allow loading post-movie savestates that were made after finishing current movie - - } else if (currFrameCounter > (int)currMovieData.records.size()) - { - // this is future event state, don't allow it - //TODO: turn frame counter to red to get attention - if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user + // this is post-movie savestate and must be checked further + if (tempMovieData.records.size() < currMovieData.records.size()) { - FCEU_PrintError("Error: Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, currMovieData.records.size()-1); - FCEUI_StopMovie(); - } else - FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.", currFrameCounter, currMovieData.records.size()-1); - return false; - } else if (currFrameCounter > (int)tempMovieData.records.size()) - { - // this is post-movie savestate, don't allow it - //TODO: turn frame counter to red to get attention - if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user - { - FCEU_PrintError("Error: Savestate is from a frame (%d) after the final frame in the savestated movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size()-1); - FCEUI_StopMovie(); - } else - FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the savestated movie (%d). This is not permitted.", currFrameCounter, tempMovieData.records.size()-1); - return false; - } else - { - // Finally, this is a savestate file for this movie - movieMode = MOVIEMODE_PLAY; + // this savestate doesn't contain enough input to be checked + //TODO: turn frame counter to red to get attention + if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user + { + FCEU_PrintError("Error: Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1); + FCEUI_StopMovie(); + } else + FCEU_PrintError("Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1); + return false; + } } + + // Finally, this is a savestate file for this movie + // We'll allow loading post-movie savestates that were made after finishing current movie + if (currFrameCounter < (int)currMovieData.records.size()) + movieMode = MOVIEMODE_PLAY; + else + FinishPlayback(); } else { //Read+Write mode + closeRecordingMovie(); + if (currFrameCounter > (int)tempMovieData.records.size()) { //This is a post movie savestate, handle it differently //Replace movie contents but then switch to movie finished mode currMovieData = tempMovieData; - openRecordingMovie(curMovieFilename); - currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/); + movieMode = MOVIEMODE_PLAY; + FCEUMOV_IncrementRerecordCount(); + RedumpWholeMovieFile(); FinishPlayback(); } else { @@ -1547,11 +1664,9 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size) tempMovieData.truncateAt(currFrameCounter); currMovieData = tempMovieData; - FCEUMOV_IncrementRerecordCount(); - openRecordingMovie(curMovieFilename); - currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/); movieMode = MOVIEMODE_RECORD; - + FCEUMOV_IncrementRerecordCount(); + RedumpWholeMovieFile(true); } } } @@ -1659,37 +1774,213 @@ void FCEUI_SetMovieToggleReadOnly(bool which) FCEU_DispMessage("Movie is Read+Write.",0); } } + +//auqnull: What's the point to toggle Read-Only without a movie loaded? void FCEUI_MovieToggleReadOnly() { char message[260]; - if(movie_readonly) - strcpy(message, "Movie is now Read+Write"); - else + movie_readonly = !movie_readonly; + if (movie_readonly) strcpy(message, "Movie is now Read-Only"); + else + strcpy(message, "Movie is now Read+Write"); + + strcat(message, GetMovieModeStr()); + FCEU_DispMessage(message,0); +} + +void FCEUI_MovieToggleRecording() +{ + char message[260] = ""; if (movieMode == MOVIEMODE_INACTIVE) - strcat(message, " (no movie)"); - else if (movieMode == MOVIEMODE_FINISHED) - strcat(message, " (finished)"); + strcpy(message, "Cannot toggle Recording"); + else if (currFrameCounter > (int)currMovieData.records.size()) + { + movie_readonly = !movie_readonly; + if (movie_readonly) + strcpy(message, "Movie is now Read-Only (finished)"); + else + strcpy(message, "Movie is now Read+Write (finished)"); + } else if (movieMode == MOVIEMODE_PLAY || (movieMode == MOVIEMODE_FINISHED && currFrameCounter == (int)currMovieData.records.size())) + { + strcpy(message, "Movie is now Read+Write"); + movie_readonly = false; + FCEUMOV_IncrementRerecordCount(); + movieMode = MOVIEMODE_RECORD; + RedumpWholeMovieFile(true); + } else if (movieMode == MOVIEMODE_RECORD) + { + strcpy(message, "Movie is now Read-Only"); + movie_readonly = true; + movieMode = MOVIEMODE_PLAY; + RedumpWholeMovieFile(true); + if (currFrameCounter >= (int)currMovieData.records.size()) + { + extern int closeFinishedMovie; + if (closeFinishedMovie) + { + movieMode = MOVIEMODE_INACTIVE; + OnMovieClosed(); + } else + movieMode = MOVIEMODE_FINISHED; + } + } else + strcpy(message, "Nothing to do in this mode"); - FCEU_DispMessage(message,0); - movie_readonly = !movie_readonly; + strcat(message, GetMovieModeStr()); + + FCEU_DispMessage(message, 0); +} + +void FCEUI_MovieInsertFrame() +{ + char message[260] = ""; + + if (movieMode == MOVIEMODE_INACTIVE) + strcpy(message, "No movie to insert a frame."); + else if (movie_readonly) + strcpy(message, "Cannot modify movie in Read-Only mode."); + else if (currFrameCounter > (int)currMovieData.records.size()) + strcpy(message, "Cannot insert a frame here."); + else if (movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED) + { + strcpy(message, "1 frame inserted"); + strcat(message, GetMovieModeStr()); + std::vector::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::iterator iter = currMovieData.records.begin(); + currMovieData.records.erase(iter + currFrameCounter); + FCEUMOV_IncrementRerecordCount(); + RedumpWholeMovieFile(); + + if (movieMode != MOVIEMODE_RECORD && currFrameCounter >= (int)currMovieData.records.size()) + { + extern int closeFinishedMovie; + if (closeFinishedMovie) + { + movieMode = MOVIEMODE_INACTIVE; + OnMovieClosed(); + } else + movieMode = MOVIEMODE_FINISHED; + } + strcat(message, GetMovieModeStr()); + } else + { + strcpy(message, "Nothing to do in this mode"); + strcat(message, GetMovieModeStr()); + } + + FCEU_DispMessage(message, 0); +} + +void FCEUI_MovieTruncate() +{ + char message[260] = ""; + + if (movieMode == MOVIEMODE_INACTIVE) + strcpy(message, "No movie to truncate."); + else if (movie_readonly) + strcpy(message, "Cannot modify movie in Read-Only mode."); + else if (currFrameCounter >= (int)currMovieData.records.size()) + strcpy(message, "Nothing to truncate past movie end."); + else if (movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY) + { + strcpy(message, "Movie truncated"); + currMovieData.truncateAt(currFrameCounter); + FCEUMOV_IncrementRerecordCount(); + RedumpWholeMovieFile(); + + if (movieMode != MOVIEMODE_RECORD) + { + extern int closeFinishedMovie; + if (closeFinishedMovie) + { + movieMode = MOVIEMODE_INACTIVE; + OnMovieClosed(); + } + else + movieMode = MOVIEMODE_FINISHED; + } + strcat(message, GetMovieModeStr()); + } else + { + strcpy(message, "Nothing to do in this mode"); + strcat(message, GetMovieModeStr()); + } + + FCEU_DispMessage(message, 0); +} + +void FCEUI_MovieNextRecordMode() +{ + movieRecordMode = (movieRecordMode + 1) % MOVIE_RECORD_MODE_MAX; +} + +void FCEUI_MoviePrevRecordMode() +{ + movieRecordMode = (movieRecordMode + MOVIE_RECORD_MODE_MAX - 1) % MOVIE_RECORD_MODE_MAX; +} + +void FCEUI_MovieRecordModeTruncate() +{ + movieRecordMode = MOVIE_RECORD_MODE_TRUNCATE; +} + +void FCEUI_MovieRecordModeOverwrite() +{ + movieRecordMode = MOVIE_RECORD_MODE_OVERWRITE; +} + +void FCEUI_MovieRecordModeInsert() +{ + movieRecordMode = MOVIE_RECORD_MODE_INSERT; } void FCEUI_MoviePlayFromBeginning(void) { if (movieMode == MOVIEMODE_TASEDITOR) { -#ifdef WIN32 +#ifdef __WIN_DRIVER__ handleEmuCmdByTaseditor(EMUCMD_MOVIE_PLAY_FROM_BEGINNING); #endif } else if (movieMode != MOVIEMODE_INACTIVE) { + if (movieMode == MOVIEMODE_RECORD) + { + movieMode = MOVIEMODE_PLAY; + RedumpWholeMovieFile(true); + } if (currMovieData.savestate.empty()) { movie_readonly = true; movieMode = MOVIEMODE_PLAY; + cur_input_display = 0; //clear previous input display poweron(true); currFrameCounter = 0; FCEU_DispMessage("Movie is now Read-Only. Playing from beginning.",0); @@ -1708,7 +1999,7 @@ void FCEUI_MoviePlayFromBeginning(void) //currMovieData.loadSavestateFrom(&currMovieData.savestate); //TODO: make something like this work instead so it doesn't have to reload } } -#ifdef WIN32 +#ifdef __WIN_DRIVER__ SetMainWindowText(); #endif } @@ -1783,7 +2074,7 @@ void ProcessSubtitles(void) } } -void FCEU_DisplaySubtitles(char *format, ...) +void FCEU_DisplaySubtitles(const char *format, ...) { va_list ap; diff --git a/source/fceultra/movie.h b/source/fceultra/movie.h index a19d25b..45398a0 100644 --- a/source/fceultra/movie.h +++ b/source/fceultra/movie.h @@ -65,6 +65,16 @@ enum EMOVIEMODE MOVIEMODE_FINISHED = 16 }; +enum EMOVIERECORDMODE +{ + MOVIE_RECORD_MODE_TRUNCATE = 0, + MOVIE_RECORD_MODE_OVERWRITE = 1, + MOVIE_RECORD_MODE_INSERT = 2, + //MOVIE_RECORD_MODE_XOR = 3, + + MOVIE_RECORD_MODE_MAX +}; + enum EMOVIECMD { MOVIECMD_RESET = 1, @@ -200,7 +210,7 @@ public: //whether microphone is enabled bool microphone; - int getNumRecords() { return records.size(); } + int getNumRecords() { return (int)records.size(); } int RAMInitOption, RAMInitSeed; @@ -234,7 +244,7 @@ public: void truncateAt(int frame); void installValue(std::string& key, std::string& val); - int dump(EMUFILE* os, bool binary); + int dump(EMUFILE* os, bool binary, bool seekToCurrFramePos = false); void clearRecordRange(int start, int len); void eraseRecords(int at, int frames = 1); @@ -267,6 +277,9 @@ extern bool freshMovie; extern bool movie_readonly; extern bool autoMovieBackup; extern bool fullSaveStateLoads; +extern int movieRecordMode; +extern int input_display; + //-------------------------------------------------- void FCEUI_MakeBackupMovie(bool dispMessage); void FCEUI_CreateMovieFile(std::string fn); @@ -277,6 +290,15 @@ void FCEUI_StopMovie(void); bool FCEUI_MovieGetInfo(FCEUFILE* fp, MOVIE_INFO& info, bool skipFrameCount = false); //char* FCEUI_MovieGetCurrentName(int addSlotNumber); void FCEUI_MovieToggleReadOnly(void); +void FCEUI_MovieToggleRecording(); +void FCEUI_MovieInsertFrame(); +void FCEUI_MovieDeleteFrame(); +void FCEUI_MovieTruncate(); +void FCEUI_MovieNextRecordMode(); +void FCEUI_MoviePrevRecordMode(); +void FCEUI_MovieRecordModeTruncate(); +void FCEUI_MovieRecordModeOverwrite(); +void FCEUI_MovieRecordModeInsert(); bool FCEUI_GetMovieToggleReadOnly(); void FCEUI_SetMovieToggleReadOnly(bool which); int FCEUI_GetMovieLength(); @@ -288,9 +310,10 @@ void FCEUI_ToggleInputDisplay(void); void LoadSubtitles(MovieData &); void ProcessSubtitles(void); -void FCEU_DisplaySubtitles(char *format, ...); +void FCEU_DisplaySubtitles(const char *format, ...); void poweron(bool shouldDisableBatteryLoading); +bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader); #endif //__MOVIE_H_ diff --git a/source/fceultra/nsf.cpp b/source/fceultra/nsf.cpp index 453e4fa..d7aee06 100644 --- a/source/fceultra/nsf.cpp +++ b/source/fceultra/nsf.cpp @@ -134,25 +134,30 @@ void NSFGI(GI h) { switch(h) { - case GI_CLOSE: - if(NSFDATA) {free(NSFDATA);NSFDATA=0;} - if(ExWRAM) {free(ExWRAM);ExWRAM=0;} - if(NSFHeader.SoundChip&1) { - // NSFVRC6_Init(); - } else if(NSFHeader.SoundChip&2) { - // NSFVRC7_Init(); - } else if(NSFHeader.SoundChip&4) { - // FDSSoundReset(); - } else if(NSFHeader.SoundChip&8) { - NSFMMC5_Close(); - } else if(NSFHeader.SoundChip&0x10) { - // NSFN106_Init(); - } else if(NSFHeader.SoundChip&0x20) { - // NSFAY_Init(); - } + case GI_CLOSE: + if(NSFDATA) {free(NSFDATA);NSFDATA=0;} + if(ExWRAM) {free(ExWRAM);ExWRAM=0;} + if(NSFHeader.SoundChip&1) { + // NSFVRC6_Init(); + } else if(NSFHeader.SoundChip&2) { + // NSFVRC7_Init(); + } else if(NSFHeader.SoundChip&4) { + // FDSSoundReset(); + } else if(NSFHeader.SoundChip&8) { + NSFMMC5_Close(); + } else if(NSFHeader.SoundChip&0x10) { + // NSFN106_Init(); + } else if(NSFHeader.SoundChip&0x20) { + // NSFAY_Init(); + } + break; + case GI_RESETM2: + case GI_POWER: + NSF_init(); + break; + default: + //Unhandled cases break; - case GI_RESETM2: - case GI_POWER: NSF_init();break; } } @@ -174,7 +179,7 @@ int NSFLoad(const char *name, FCEUFILE *fp) FCEU_fseek(fp,0,SEEK_SET); FCEU_fread(&NSFHeader,1,0x80,fp); if(memcmp(NSFHeader.ID,"NESM\x1a",5)) - return 0; + return LOADER_INVALID_FORMAT; NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0; LoadAddr=NSFHeader.LoadAddressLow; @@ -183,7 +188,7 @@ int NSFLoad(const char *name, FCEUFILE *fp) if(LoadAddr<0x6000) { FCEUD_PrintError("Invalid load address."); - return(0); + return LOADER_HANDLED_ERROR; } InitAddr=NSFHeader.InitAddressLow; InitAddr|=NSFHeader.InitAddressHigh<<8; @@ -196,8 +201,11 @@ int NSFLoad(const char *name, FCEUFILE *fp) NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096); NSFMaxBank=PRGsize[0]=uppow2(NSFMaxBank); - if(!(NSFDATA=(uint8 *)FCEU_malloc(NSFMaxBank*4096))) - return 0; + if (!(NSFDATA = (uint8 *)FCEU_malloc(NSFMaxBank * 4096))) + { + FCEU_PrintError("Unable to allocate memory."); + return LOADER_HANDLED_ERROR; + } FCEU_fseek(fp,0x80,SEEK_SET); memset(NSFDATA,0x00,NSFMaxBank*4096); @@ -262,7 +270,7 @@ int NSFLoad(const char *name, FCEUFILE *fp) FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright); if(NSFHeader.SoundChip) { - static char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"}; + static const char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"}; for(x=0;x<6;x++) if(NSFHeader.SoundChip&(1<>8)+1)); case 0x9F: ST_ABY(_A&_X&(((A-_Y)>>8)+1)); /* SYA */ -case 0x9C: ST_ABX(_Y&(((A-_X)>>8)+1)); +case 0x9C: /* Can't reuse existing ST_ABI macro here, due to addressing weirdness. */ +{ + unsigned int A; GetABIWR(A,_X); A = ((_Y&((A>>8)+1)) << 8) | (A & 0xff); WrMem(A,A>>8); break; +} /* SXA */ -case 0x9E: ST_ABY(_X&(((A-_Y)>>8)+1)); +case 0x9E: /* Can't reuse existing ST_ABI macro here, due to addressing weirdness. */ +{ + unsigned int A; GetABIWR(A,_Y); A = ((_X&((A>>8)+1)) << 8) | (A & 0xff); WrMem(A,A>>8); break; +} /* XAS */ case 0x9B: _S=_A&_X;ST_ABY(_S& (((A-_Y)>>8)+1) ); diff --git a/source/fceultra/palette.cpp b/source/fceultra/palette.cpp index 3ab97f4..2d888d4 100644 --- a/source/fceultra/palette.cpp +++ b/source/fceultra/palette.cpp @@ -41,13 +41,14 @@ #include bool force_grayscale = false; +pal *grayscaled_palo = NULL; pal palette_game[64*8]; //custom palette for an individual game. (formerly palettei) pal palette_user[64*8]; //user's overridden palette (formerly palettec) pal palette_ntsc[64*8]; //mathematically generated NTSC palette (formerly paletten) -static bool palette_game_available; //whether palette_game is available -static bool palette_user_available; //whether palette_user is available +static bool palette_game_available=false; //whether palette_game is available +static bool palette_user_available=false; //whether palette_user is available //ntsc parameters: bool ntsccol_enable = false; //whether NTSC palette is selected @@ -61,10 +62,11 @@ int default_palette_selection = 0; static pal *default_palette[8]= { palette, - rp2c04001, - rp2c04002, - rp2c04003, - rp2c05004, + rp2c04_0001, + rp2c04_0002, + rp2c04_0003, + rp2c04_0004, + rp2c03, }; static void CalculatePalette(void); @@ -72,7 +74,7 @@ static void ChoosePalette(void); static void WritePalette(void); //points to the actually selected current palette -pal *palo; +pal *palo = NULL; #define RGB_TO_YIQ( r, g, b, y, i ) (\ (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ @@ -149,7 +151,7 @@ static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b) } } - static float const default_decoder [6] = + static float const default_decoder [6] = { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f }; fb = YIQ_TO_RGB( y, i, q, default_decoder, float, fr, fg ); @@ -160,94 +162,94 @@ static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b) //doesnt help //float gamma=1.8f; - // auto gammafix = [=](float f) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); }; - // auto clamp = [](int v) { return v<0 ? 0 : v>255 ? 255 : v; }; - // r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q)); - // g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q)); + // auto gammafix = [=](float f) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); }; + // auto clamp = [](int v) { return v<0 ? 0 : v>255 ? 255 : v; }; + // r = clamp(255 * gammafix(y + 0.946882f*i + 0.623557f*q)); + // g = clamp(255 * gammafix(y + -0.274788f*i + -0.635691f*q)); // b = clamp(255 * gammafix(y + -1.108545f*i + 1.709007f*q)); } -float bisqwit_gammafix(float f, float gamma) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); } +float bisqwit_gammafix(float f, float gamma) { return f < 0.f ? 0.f : std::pow(f, 2.2f / gamma); } int bisqwit_clamp(int v) { return v<0 ? 0 : v>255 ? 255 : v; } - -// Calculate the luma and chroma by emulating the relevant circuits: + +// Calculate the luma and chroma by emulating the relevant circuits: int bisqwit_wave(int p, int color) { return (color+p+8)%12 < 6; } static void ApplyDeemphasisBisqwit(int entry, u8& r, u8& g, u8& b) { if(entry<64) return; - int myr, myg, myb; - // The input value is a NES color index (with de-emphasis bits). - // We need RGB values. Convert the index into RGB. - // For most part, this process is described at: - // http://wiki.nesdev.com/w/index.php/NTSC_video - - // Decode the color index - int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1; - - // Voltage levels, relative to synch voltage - static const float black=.518f, white=1.962f, attenuation=.746f, - levels[8] = {.350f, .518f, .962f,1.550f, // Signal low - 1.094f,1.506f,1.962f,1.962f}; // Signal high - - float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)], - levels[level + 4 * (color < 0xD)] }; - - - - //fceux alteration: two passes - //1st pass calculates bisqwit's base color - //2nd pass calculates it with deemph - //finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, we could pregenerate the scale factors) - //whatever, it gets the job done. - for(int pass=0;pass<2;pass++) - { - float y=0.f, i=0.f, q=0.f, gamma=1.8f; - for(int p=0; p<12; ++p) // 12 clock cycles per pixel. - { - // NES NTSC modulator (square wave between two voltage levels): - float spot = lo_and_hi[bisqwit_wave(p,color)]; - - // De-emphasis bits attenuate a part of the signal: - if(pass==1) - { - if(((entry & 0x40) && bisqwit_wave(p,12)) - || ((entry & 0x80) && bisqwit_wave(p, 4)) - || ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation; - } - - // Normalize: - float v = (spot - black) / (white-black) / 12.f; - - // Ideal TV NTSC demodulator: - y += v; - i += v * std::cos(3.141592653 * p / 6); - q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... ) - // Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives - // the exactly same result, scaled by a factor of 2*cos(pi/12). - } - - // Convert YIQ into RGB according to FCC-sanctioned conversion matrix. - - int rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f*i + 0.623557f*q,gamma)); - int gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f*i + -0.635691f*q,gamma)); - int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma)); - - if(pass==0) myr = rt, myg = gt, myb = bt; - else - { - float rscale = (float)rt / myr; - float gscale = (float)gt / myg; - float bscale = (float)bt / myb; - #define BCLAMP(x) ((x)<0?0:((x)>255?255:(x))) + int myr=0, myg=0, myb=0; + // The input value is a NES color index (with de-emphasis bits). + // We need RGB values. Convert the index into RGB. + // For most part, this process is described at: + // http://wiki.nesdev.com/w/index.php/NTSC_video + + // Decode the color index + int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1; + + // Voltage levels, relative to synch voltage + static const float black=.518f, white=1.962f, attenuation=.746f, + levels[8] = {.350f, .518f, .962f,1.550f, // Signal low + 1.094f,1.506f,1.962f,1.962f}; // Signal high + + float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)], + levels[level + 4 * (color < 0xD)] }; + + + + //fceux alteration: two passes + //1st pass calculates bisqwit's base color + //2nd pass calculates it with deemph + //finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, we could pregenerate the scale factors) + //whatever, it gets the job done. + for(int pass=0;pass<2;pass++) + { + float y=0.f, i=0.f, q=0.f, gamma=1.8f; + for(int p=0; p<12; ++p) // 12 clock cycles per pixel. + { + // NES NTSC modulator (square wave between two voltage levels): + float spot = lo_and_hi[bisqwit_wave(p,color)]; + + // De-emphasis bits attenuate a part of the signal: + if(pass==1) + { + if(((entry & 0x40) && bisqwit_wave(p,12)) + || ((entry & 0x80) && bisqwit_wave(p, 4)) + || ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation; + } + + // Normalize: + float v = (spot - black) / (white-black) / 12.f; + + // Ideal TV NTSC demodulator: + y += v; + i += v * std::cos(3.141592653 * p / 6); + q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... ) + // Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives + // the exactly same result, scaled by a factor of 2*cos(pi/12). + } + + // Convert YIQ into RGB according to FCC-sanctioned conversion matrix. + + int rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f*i + 0.623557f*q,gamma)); + int gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f*i + -0.635691f*q,gamma)); + int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma)); + + if(pass==0) myr = rt, myg = gt, myb = bt; + else + { + float rscale = (float)rt / myr; + float gscale = (float)gt / myg; + float bscale = (float)bt / myb; + #define BCLAMP(x) ((x)<0?0:((x)>255?255:(x))) if(myr!=0) r = (u8)(BCLAMP(r*rscale)); if(myg!=0) g = (u8)(BCLAMP(g*gscale)); - if(myb!=0) b = (u8)(BCLAMP(b*bscale)); - } - } - - - + if(myb!=0) b = (u8)(BCLAMP(b*bscale)); + } + } + + + } //classic algorithm @@ -289,6 +291,11 @@ static void ApplyDeemphasisComplete(pal* pal512) } } +bool FCEUI_GetUserPaletteAvail( void ) +{ + return palette_user_available; +} + void FCEUI_SetUserPalette(uint8 *pal, int nEntries) { if(!pal) @@ -521,6 +528,29 @@ static void ChoosePalette(void) //need to calcualte a deemph on the fly.. sorry. maybe support otherwise later ApplyDeemphasisComplete(palo); } + if (force_grayscale) + { + // need to apply grayscale filter + // allocate memory for grayscale palette + if (grayscaled_palo == NULL) + grayscaled_palo = (pal*)malloc(sizeof(pal) * 64 * 8); + // make every color grayscale + for (int x = 0; x < 64 * 8; x++) + { + uint8 gray = ((float)palo[x].r * 0.299 + (float)palo[x].g * 0.587 + (float)palo[x].b * 0.114); + grayscaled_palo[x].r = gray; + grayscaled_palo[x].g = gray; + grayscaled_palo[x].b = gray; + } + // apply new palette + palo = grayscaled_palo; + } + else if (grayscaled_palo != NULL) + { + // free allocated memory if the grayscale filter is not used anymore + free(grayscaled_palo); + grayscaled_palo = NULL; + } } void WritePalette(void) diff --git a/source/fceultra/palettes/palettes.h b/source/fceultra/palettes/palettes.h index 7721bec..b9a43da 100644 --- a/source/fceultra/palettes/palettes.h +++ b/source/fceultra/palettes/palettes.h @@ -4,25 +4,29 @@ #define EMPTY_PALETTE_64 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 #define EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 -pal rp2c04001[512] = { - #include "rp2c04001.h" +pal rp2c04_0001[512] = { + #include "rp2c04-0001.h" EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04002[512] = { - #include "rp2c04002.h" +pal rp2c04_0002[512] = { + #include "rp2c04-0002.h" EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04003[512] = { - #include "rp2c04003.h" +pal rp2c04_0003[512] = { + #include "rp2c04-0003.h" EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c05004[512] = { - #include "rp2c05004.h" +pal rp2c04_0004[512] = { + #include "rp2c04-0004.h" EMPTY_PALETTE_DEEMPH_X_7 }; +pal rp2c03[512] = { + #include "rp2c03.h" +}; + // Fixed palette entries used by the GUI pal palette_unvarying[] = { { 0x00<<2,0x00<<2,0x00<<2}, // 0 = Black diff --git a/source/fceultra/ppu.cpp b/source/fceultra/ppu.cpp index ed401d6..01a03a7 100644 --- a/source/fceultra/ppu.cpp +++ b/source/fceultra/ppu.cpp @@ -330,7 +330,7 @@ int fceuindbg = 0; //0xFF shall indicate to use palette[0] uint8 gNoBGFillColor = 0xFF; -int MMC5Hack = 0, PEC586Hack = 0;; +int MMC5Hack = 0; uint32 MMC5HackVROMMask = 0; uint8 *MMC5HackExNTARAMPtr = 0; uint8 *MMC5HackVROMPTR = 0; @@ -340,6 +340,12 @@ uint8 MMC50x5130 = 0; uint8 MMC5HackSPScroll = 0; uint8 MMC5HackSPPage = 0; +int PEC586Hack = 0; + +int QTAIHack = 0; +uint8 QTAINTRAM[2048]; +uint8 qtaintramreg; + uint8 VRAMBuffer = 0, PPUGenLatch = 0; uint8 *vnapage[4]; uint8 PPUNTARAM = 0; @@ -376,6 +382,18 @@ uint8 UPALRAM[0x03];//for 0x4/0x8/0xC addresses in palette, the ones in uint8* MMC5BGVRAMADR(uint32 A); +uint8 READPAL_MOTHEROFALL(uint32 A) +{ + if(!(A & 3)) { + if(!(A & 0xC)) + return READPAL(0x00); + else + return READUPAL(((A & 0xC) >> 2) - 1); + } + else + return READPAL(A & 0x1F); +} + //this duplicates logic which is embedded in the ppu rendering code //which figures out where to get CHR data from depending on various hack modes //mostly involving mmc5. @@ -414,12 +432,18 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) { if (PPUCHRRAM & (1 << (tmp >> 10))) VPage[tmp >> 10][tmp] = V; } else if (tmp < 0x3F00) { - if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) - vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + if (QTAIHack && (qtaintramreg & 1)) { + QTAINTRAM[((((tmp & 0xF00) >> 10) >> ((qtaintramreg >> 1)) & 1) << 10) | (tmp & 0x3FF)] = V; + } else { + if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) + vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + } } else { if (!(tmp & 3)) { - if (!(tmp & 0xC)) + if (!(tmp & 0xC)) { PALRAM[0x00] = PALRAM[0x04] = PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F; + PALRAM[0x10] = PALRAM[0x14] = PALRAM[0x18] = PALRAM[0x1C] = V & 0x3F; + } else UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F; } else @@ -941,8 +965,12 @@ static DECLFW(B2007) { if (PPUCHRRAM & (1 << (tmp >> 10))) VPage[tmp >> 10][tmp] = V; } else if (tmp < 0x3F00) { - if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) - vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + if (QTAIHack && (qtaintramreg & 1)) { + QTAINTRAM[((((tmp & 0xF00) >> 10) >> ((qtaintramreg >> 1)) & 1) << 10) | (tmp & 0x3FF)] = V; + } else { + if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) + vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + } } else { if (!(tmp & 3)) { if (!(tmp & 0xC)) @@ -1060,7 +1088,7 @@ static void RefreshLine(int lastpixel) { uint32 vofs; int X1; - register uint8 *P = Pline; + uint8 *P = Pline; int lasttile = lastpixel >> 3; int numtiles; static int norecurse = 0; // Yeah, recursion would be bad. @@ -1182,6 +1210,12 @@ static void RefreshLine(int lastpixel) { #include "pputile.inc" } #undef PPU_BGFETCH + } if (QTAIHack) { + #define PPU_VRC5FETCH + for (X1 = firsttile; X1 < lasttile; X1++) { + #include "pputile.inc" + } + #undef PPU_VRC5FETCH } else { for (X1 = firsttile; X1 < lasttile; X1++) { #include "pputile.inc" @@ -1627,7 +1661,6 @@ static void RefreshSprites(void) { } static void CopySprites(uint8 *target) { - uint8 n = ((PPU[1] & 4) ^ 4) << 1; uint8 *P = target; if (!spork) return; @@ -1635,65 +1668,19 @@ static void CopySprites(uint8 *target) { if (!rendersprites) return; //User asked to not display sprites. - loopskie: + if(!SpriteON) return; + + int start=8; + if(PPU[1] & 0x04) + start = 0; + + for(int i=start;i<256;i++) { - uint32 t = *(uint32*)(sprlinebuf + n); - - if (t != 0x80808080) { - #ifdef LSB_FIRST - if (!(t & 0x80)) { - if (!(t & 0x40) || (P[n] & 0x40)) // Normal sprite || behind bg sprite - P[n] = sprlinebuf[n]; - } - - if (!(t & 0x8000)) { - if (!(t & 0x4000) || (P[n + 1] & 0x40)) // Normal sprite || behind bg sprite - P[n + 1] = (sprlinebuf + 1)[n]; - } - - if (!(t & 0x800000)) { - if (!(t & 0x400000) || (P[n + 2] & 0x40)) // Normal sprite || behind bg sprite - P[n + 2] = (sprlinebuf + 2)[n]; - } - - if (!(t & 0x80000000)) { - if (!(t & 0x40000000) || (P[n + 3] & 0x40)) // Normal sprite || behind bg sprite - P[n + 3] = (sprlinebuf + 3)[n]; - } - #else - /* TODO: Simplify */ - if (!(t & 0x80000000)) { - if (!(t & 0x40000000)) // Normal sprite - P[n] = sprlinebuf[n]; - else if (P[n] & 64) // behind bg sprite - P[n] = sprlinebuf[n]; - } - - if (!(t & 0x800000)) { - if (!(t & 0x400000)) // Normal sprite - P[n + 1] = (sprlinebuf + 1)[n]; - else if (P[n + 1] & 64) // behind bg sprite - P[n + 1] = (sprlinebuf + 1)[n]; - } - - if (!(t & 0x8000)) { - if (!(t & 0x4000)) // Normal sprite - P[n + 2] = (sprlinebuf + 2)[n]; - else if (P[n + 2] & 64) // behind bg sprite - P[n + 2] = (sprlinebuf + 2)[n]; - } - - if (!(t & 0x80)) { - if (!(t & 0x40)) // Normal sprite - P[n + 3] = (sprlinebuf + 3)[n]; - else if (P[n + 3] & 64) // behind bg sprite - P[n + 3] = (sprlinebuf + 3)[n]; - } - #endif - } + uint8 t = sprlinebuf[i]; + if(!(t&0x80)) + if (!(t & 0x40) || (P[i] & 0x40)) // Normal sprite || behind bg sprite + P[i] = t; } - n += 4; - if (n) goto loopskie; } void FCEUPPU_SetVideoSystem(int w) { @@ -1864,8 +1851,10 @@ int FCEUPPU_Loop(int skip) { for (scanline = 0; scanline < totalscanlines; ) { //scanline is incremented in DoLine. Evil. :/ deempcnt[deemp]++; + if (scanline < 240) DEBUG(FCEUD_UpdatePPUView(scanline, 1)); + DoLine(); if (scanline < normalscanlines || scanline == totalscanlines) @@ -1900,7 +1889,6 @@ int FCEUPPU_Loop(int skip) { } else #endif { - FCEU_PutImage(); return(1); } } @@ -1998,12 +1986,16 @@ void runppu(int x) { //todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory struct BGData { struct Record { - uint8 nt, pecnt, at, pt[2]; + uint8 nt, pecnt, at, pt[2], qtnt; INLINE void Read() { NTRefreshAddr = RefreshAddr = ppur.get_ntread(); if (PEC586Hack) ppur.s = (RefreshAddr & 0x200) >> 9; + else if (QTAIHack) { + qtnt = QTAINTRAM[((((RefreshAddr >> 10) & 3) >> ((qtaintramreg >> 1)) & 1) << 10) | (RefreshAddr & 0x3FF)]; + ppur.s = qtnt & 0x3F; + } pecnt = (RefreshAddr & 1) << 3; nt = CALL_PPUREAD(RefreshAddr); runppu(kFetchTime); @@ -2029,12 +2021,16 @@ struct BGData { ppur.par = nt; RefreshAddr = ppur.get_ptread(); if (PEC586Hack) { - if (ScreenON) - RENDER_LOG(RefreshAddr | pecnt); pt[0] = CALL_PPUREAD(RefreshAddr | pecnt); runppu(kFetchTime); pt[1] = CALL_PPUREAD(RefreshAddr | pecnt); runppu(kFetchTime); + } else if (QTAIHack && (qtnt & 0x40)) { + pt[0] = *(CHRptr[0] + RefreshAddr); + runppu(kFetchTime); + RefreshAddr |= 8; + pt[1] = *(CHRptr[0] + RefreshAddr); + runppu(kFetchTime); } else { if (ScreenON) RENDER_LOG(RefreshAddr); @@ -2139,7 +2135,8 @@ int FCEUX_PPU_Loop(int skip) { //int xscroll = ppur.fh; //render 241/291 scanlines (1 dummy at beginning, dendy's 50 at the end) //ignore overclocking! - for (int sl = 0; sl < normalscanlines; sl++) { + for (int sl = 0; sl < normalscanlines; sl++) + { spr_read.start_scanline(); g_rasterpos = 0; @@ -2150,7 +2147,8 @@ int FCEUX_PPU_Loop(int skip) { const int yp = sl - 1; ppuphase = PPUPHASE_BG; - if (sl != 0 && sl < 241) { // ignore the invisible + if (sl != 0 && sl < 241) // ignore the invisible + { DEBUG(FCEUD_UpdatePPUView(scanline = yp, 1)); DEBUG(FCEUD_UpdateNTView(scanline = yp, 1)); } @@ -2209,7 +2207,7 @@ int FCEUX_PPU_Loop(int skip) { { pixel = addr & 0x1F; } - pixelcolor = PALRAM[pixel]; + pixelcolor = READPAL_MOTHEROFALL(pixel); } //generate the BG data @@ -2467,7 +2465,5 @@ int FCEUX_PPU_Loop(int skip) { } finish: - FCEU_PutImage(); - return 0; } diff --git a/source/fceultra/ppu.h b/source/fceultra/ppu.h index a3d2ded..4555264 100644 --- a/source/fceultra/ppu.h +++ b/source/fceultra/ppu.h @@ -48,3 +48,7 @@ enum PPUPHASE { }; extern PPUPHASE ppuphase; + +extern unsigned char *cdloggervdata; +extern unsigned int cdloggerVideoDataSize; +extern volatile int rendercount, vromreadcount, undefinedvromcount; diff --git a/source/fceultra/pputile.inc b/source/fceultra/pputile.inc index fc6d04a..ce4a6d0 100644 --- a/source/fceultra/pputile.inc +++ b/source/fceultra/pputile.inc @@ -1,9 +1,12 @@ uint8 *C; -register uint8 cc; +uint8 cc; uint32 vadr; +#ifdef PPU_VRC5FETCH +uint8 tmpd; +#endif #ifndef PPUT_MMC5SP - register uint8 zz; + uint8 zz; #else uint8 xs, ys; xs = X1; @@ -42,7 +45,11 @@ if (X1 >= 2) { #else zz = RefreshAddr & 0x1F; C = vnapage[(RefreshAddr >> 10) & 3]; - vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; // Fetch name table byte. +#ifdef PPU_VRC5FETCH + tmpd = QTAINTRAM[((((RefreshAddr >> 10) & 3) >> ((qtaintramreg >> 1)) & 1) << 10) | (RefreshAddr & 0x3FF)]; + vofs = ((tmpd & 0x3F) << 12) | ((RefreshAddr >> 12) & 7); // recalculate VROM offset +#endif + vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; // Fetch name table byte. #endif #ifdef PPUT_HOOK @@ -78,7 +85,16 @@ pshift[1] <<= 8; #elif defined(PPUT_MMC5) C = MMC5BGVRAMADR(vadr); #else + + #ifdef PPU_VRC5FETCH + if(tmpd & 0x40) + C = CHRptr[0] + vadr; + else C = VRAMADR(vadr); + #else + C = VRAMADR(vadr); +#endif + #endif #endif @@ -99,12 +115,20 @@ pshift[1] <<= 8; pshift[1] |= C[0]; } #else + #ifdef PPU_VRC5FETCH + pshift[0] |= C[0]; + if(tmpd & 0x40) + pshift[1] |= (tmpd & 0x80) ? 0xFF : 0x00; + else + pshift[1] |= C[8]; + #else if(ScreenON) RENDER_LOGP(C); pshift[0] |= C[0]; if(ScreenON) RENDER_LOGP(C + 8); pshift[1] |= C[8]; + #endif #endif if ((RefreshAddr & 0x1f) == 0x1f) diff --git a/source/fceultra/sound.cpp b/source/fceultra/sound.cpp index 7390cce..b484129 100644 --- a/source/fceultra/sound.cpp +++ b/source/fceultra/sound.cpp @@ -67,6 +67,7 @@ static int32 RectDutyCount[2]; static uint8 sweepon[2]; /*static*/ int32 curfreq[2]; static uint8 SweepCount[2]; +static uint8 SweepReload[2]; static uint16 nreg=0; @@ -99,7 +100,7 @@ extern const uint32 NoiseFreqTableNTSC[0x10] = extern const uint32 NoiseFreqTablePAL[0x10] = { - 4, 7, 14, 30, 60, 88, 118, 148, 188, + 4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778 }; @@ -180,6 +181,7 @@ void LogDPCM(int romaddress, int dpcmsize){ for (int dpcmstart = i; dpcmstart < (i + dpcmsize); dpcmstart++) { if(!(cdloggerdata[dpcmstart] & 0x40)) { cdloggerdata[dpcmstart] |= 0x40; + cdloggerdata[dpcmstart] |= (romaddress >> 11) & 0x0c; if(!(cdloggerdata[dpcmstart] & 2)){ datacount++; @@ -206,22 +208,15 @@ void LogDPCM(int romaddress, int dpcmsize){ static void SQReload(int x, uint8 V) { - if(EnabledChannels&(1<>3)&0x1f]; - } + if(EnabledChannels&(1<>3)&0x1f]; - sweepon[x]=PSG[(x<<2)|1]&0x80; - curfreq[x]=PSG[(x<<2)|0x2]|((V&7)<<8); - SweepCount[x]=((PSG[(x<<2)|0x1]>>4)&7)+1; - - RectDutyCount[x]=7; - EnvUnits[x].reloaddec=1; - //reloadfreq[x]=1; + /* use the low 8 bits data from pulse period + * instead of from the sweep period */ + /* https://forums.nesdev.com/viewtopic.php?t=219&p=1431 */ + curfreq[x]=(curfreq[x] & 0xff)|((V&7)<<8); + RectDutyCount[x]=7; + EnvUnits[x].reloaddec=1; } static DECLFW(Write_PSG) @@ -237,7 +232,9 @@ static DECLFW(Write_PSG) V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); break; case 0x1: + DoSQ1(); sweepon[0]=V&0x80; + SweepReload[0]=1; break; case 0x2: DoSQ1(); @@ -245,6 +242,7 @@ static DECLFW(Write_PSG) curfreq[0]|=V; break; case 0x3: + DoSQ1(); SQReload(0,V); break; case 0x4: @@ -255,7 +253,9 @@ static DECLFW(Write_PSG) V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); break; case 0x5: + DoSQ2(); sweepon[1]=V&0x80; + SweepReload[1]=1; break; case 0x6: DoSQ2(); @@ -263,6 +263,7 @@ static DECLFW(Write_PSG) curfreq[1]|=V; break; case 0x7: + DoSQ2(); SQReload(1,V); break; case 0xa: @@ -421,44 +422,28 @@ static void FrameSoundStuff(int V) /* Frequency Sweep Code Here */ /* xxxx 0000 */ /* xxxx = hz. 120/(x+1)*/ - if(sweepon[P]) + /* http://wiki.nesdev.com/w/index.php/APU_Sweep */ + /* https://forums.nesdev.com/viewtopic.php?t=219&p=1431 */ + if (SweepCount[P] > 0) SweepCount[P]--; + if (SweepCount[P] <= 0) { - int32 mod=0; - - if(SweepCount[P]>0) SweepCount[P]--; - if(SweepCount[P]<=0) + int sweepShift = (PSG[(P << 2) + 0x1] & 7); + if (sweepon[P] && sweepShift && curfreq[P] >= 8) { - SweepCount[P]=((PSG[(P<<2)+0x1]>>4)&7)+1; //+1; - if(PSG[(P<<2)+0x1]&0x8) - { - mod-=(P^1)+((curfreq[P])>>(PSG[(P<<2)+0x1]&7)); - if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/) - { - curfreq[P]+=mod; - } - } - else - { - mod=curfreq[P]>>(PSG[(P<<2)+0x1]&7); - if((mod+curfreq[P])&0x800) - { - sweepon[P]=0; - curfreq[P]=0; - } - else - { - if(curfreq[P] && (PSG[(P<<2)+0x1]&7)/* && sweepon[P]&0x80*/) - { - curfreq[P]+=mod; - } - } - } + int32 mod = (curfreq[P] >> sweepShift); + if (PSG[(P << 2) + 0x1] & 0x8) + curfreq[P] -= (mod + (P ^ 1)); + else if ((mod + curfreq[P]) < 0x800) + curfreq[P] += mod; } + + SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); } - else /* Sweeping is disabled: */ + + if (SweepReload[P]) { - //curfreq[P]&=0xFF00; - //curfreq[P]|=PSG[(P<<2)|0x2]; //|((PSG[(P<<2)|3]&7)<<8); + SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); + SweepReload[P] = 0; } } } @@ -579,9 +564,10 @@ void FCEU_SoundCPUHook(int cycles) /* Unbelievably ugly hack */ if(FSettings.SndRate) { - soundtsoffs+=DMCacc; - DoPCM(); - soundtsoffs-=DMCacc; + const uint32 fudge = std::min(-DMCacc, soundtsoffs + timestamp); + soundtsoffs -= fudge; + DoPCM(); + soundtsoffs += fudge; } RawDALatch+=t; if(RawDALatch&0x80) @@ -1096,8 +1082,9 @@ int FlushEmulateSound(void) SexyFilter(Wave,WaveFinal,end>>4); - //if(FSettings.lowpass) - // SexyFilter2(WaveFinal,end>>4); + if(FSettings.lowpass) + SexyFilter2(WaveFinal,end>>4); + if(end&0xF) Wave[0]=Wave[(end>>4)]; Wave[end>>4]=0; diff --git a/source/fceultra/state.cpp b/source/fceultra/state.cpp index 0f22f90..e8e0ab0 100644 --- a/source/fceultra/state.cpp +++ b/source/fceultra/state.cpp @@ -43,8 +43,9 @@ #endif //TODO - we really need some kind of global platform-specific options api -#ifdef WIN32 +#ifdef __WIN_DRIVER__ #include "drivers/win/main.h" +#include "drivers/win/cheat.h" #include "drivers/win/ram_search.h" #include "drivers/win/ramwatch.h" #endif @@ -60,14 +61,14 @@ using namespace std; -static void (*SPreSave)(void); -static void (*SPostSave)(void); +static void (*SPreSave)(void) = NULL; +static void (*SPostSave)(void) = NULL; static int SaveStateStatus[10]; static int StateShow; //tells the save system innards that we're loading the old format -bool FCEU_state_loading_old_format; +bool FCEU_state_loading_old_format = false; char lastSavestateMade[2048]; //Stores the filename of the last savestate made (needed for UndoSavestate) bool undoSS = false; //This will be true if there is lastSavestateMade, it was made since ROM was loaded, a backup state for lastSavestateMade exists @@ -311,7 +312,7 @@ static bool ReadStateChunks(EMUFILE* is, int32 totalsize) //MBG TODO - can this be moved to a better place? //does it even make sense, displaying XBuf when its XBackBuf we just loaded? -#ifdef WIN32 +#ifdef __WIN_DRIVER__ else { FCEUD_BlitScreen(XBuf); @@ -412,7 +413,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel) if(SPreSave) SPreSave(); totalsize+=WriteStateChunk(os,0x10,SFMDATA); - if(SPreSave) SPostSave(); + if(SPostSave) SPostSave(); //save the length of the file int len = memory_savestate.size(); @@ -794,7 +795,7 @@ bool FCEUSS_Load(const char *fname, bool display_message) } #endif -#ifdef WIN32 +#ifdef __WIN_DRIVER__ Update_RAM_Search(); // Update_RAM_Watch() is also called. #endif @@ -847,7 +848,7 @@ void ResetExState(void (*PreSave)(void), void (*PostSave)(void)) for(x=0;xvidsys = GIV_NTSC; FCEUI_SetVidSystem(0); @@ -372,7 +372,7 @@ static BMAPPING bmap[] = { { "H2288", UNLH2288_Init, 0 }, { "HKROM", HKROM_Init, 0 }, { "KOF97", UNLKOF97_Init, 0 }, - { "KONAMI-QTAI", Mapper190_Init, 0 }, + { "KONAMI-QTAI", QTAi_Init, 0 }, { "KS7010", UNLKS7010_Init, 0 }, { "KS7012", UNLKS7012_Init, 0 }, { "KS7013B", UNLKS7013B_Init, 0 }, @@ -475,6 +475,10 @@ static BMAPPING bmap[] = { { "8-IN-1", BMC8IN1_Init, 0 }, { "80013-B", BMC80013B_Init, 0 }, { "HPxx", BMCHPxx_Init, 0 }, + { "MINDKIDS", MINDKIDS_Init, BMCFLAG_256KCHRR }, + { "FNS", FNS_Init, BMCFLAG_16KCHRR }, + { "BS-400R", BS400R_Init, 0 }, + { "BS-4040R", BS4040R_Init, 0 }, { 0, 0, 0 } }; @@ -539,23 +543,22 @@ static int InitializeBoard(void) { CHRRAMSize = 256; else CHRRAMSize = 8; - CHRRAMSize <<= 10; + CHRRAMSize <<= 10; if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) { SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1); AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR"); } else - return(-1); + return 2; } if (bmap[x].flags & BMCFLAG_FORCE4) mirrortodo = 4; MooMirroring(); bmap[x].init(&UNIFCart); - return(1); + return 0; } x++; } - FCEU_PrintError("Board type not supported."); - return(0); + return 1; } static void UNIFGI(GI h) { @@ -588,53 +591,58 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { FCEU_fseek(fp, 0, SEEK_SET); FCEU_fread(&unhead, 1, 4, fp); if (memcmp(&unhead, "UNIF", 4)) - return 0; + return LOADER_INVALID_FORMAT; ResetCartMapping(); ResetExState(0, 0); ResetUNIF(); - if (!FCEU_read32le(&unhead.info, fp)) - goto aborto; - if (FCEU_fseek(fp, 0x20, SEEK_SET) < 0) - goto aborto; - if (!LoadUNIFChunks(fp)) - goto aborto; + if (!FCEU_read32le(&unhead.info, fp) + || (FCEU_fseek(fp, 0x20, SEEK_SET) < 0) + || !LoadUNIFChunks(fp)) { - int x; - struct md5_context md5; - - md5_starts(&md5); - - for (x = 0; x < 32; x++) - if (malloced[x]) { - md5_update(&md5, malloced[x], mallocedsizes[x]); - } - md5_finish(&md5, UNIFCart.MD5); - FCEU_printf(" ROM MD5: 0x"); - for (x = 0; x < 16; x++) - FCEU_printf("%02x", UNIFCart.MD5[x]); - FCEU_printf("\n"); - memcpy(&GameInfo->MD5, &UNIFCart.MD5, sizeof(UNIFCart.MD5)); + FreeUNIF(); + ResetUNIF(); + FCEU_PrintError("Error reading UNIF ROM image."); + return LOADER_HANDLED_ERROR; } - if (!InitializeBoard()) - goto aborto; + struct md5_context md5; + md5_starts(&md5); + for (int x = 0; x < 32; x++) + if (malloced[x]) { + md5_update(&md5, malloced[x], mallocedsizes[x]); + } + md5_finish(&md5, UNIFCart.MD5); + FCEU_printf(" ROM MD5: 0x"); + for (int x = 0; x < 16; x++) + FCEU_printf("%02x", UNIFCart.MD5[x]); + FCEU_printf("\n"); + memcpy(&GameInfo->MD5, &UNIFCart.MD5, sizeof(UNIFCart.MD5)); + + int result = InitializeBoard(); + switch (result) + { + case 0: + goto init_ok; + case 1: + FCEU_PrintError("UNIF mapper \"%s\" is not supported at all.", sboardname); + break; + case 2: + FCEU_PrintError("Unable to allocate CHR-RAM."); + break; + } + FreeUNIF(); + ResetUNIF(); + return LOADER_HANDLED_ERROR; + +init_ok: #ifndef GEKKO FCEU_LoadGameSave(&UNIFCart); #endif - strcpy(LoadedRomFName, name); //For the debugger list GameInterface = UNIFGI; currCartInfo = &UNIFCart; - return 1; - - aborto: - - FreeUNIF(); - ResetUNIF(); - - - return 0; + return LOADER_OK; } diff --git a/source/fceultra/unif.h b/source/fceultra/unif.h index 3644a37..b6759bd 100644 --- a/source/fceultra/unif.h +++ b/source/fceultra/unif.h @@ -51,7 +51,7 @@ void EKROM_Init(CartInfo *info); void ELROM_Init(CartInfo *info); void ETROM_Init(CartInfo *info); void EWROM_Init(CartInfo *info); -void GNROM_Init(CartInfo *info); +//void GNROM_Init(CartInfo *info); void HKROM_Init(CartInfo *info); void LE05_Init(CartInfo *info); void LH10_Init(CartInfo *info); @@ -59,7 +59,7 @@ void LH32_Init(CartInfo *info); void LH53_Init(CartInfo *info); void MALEE_Init(CartInfo *info); void MHROM_Init(CartInfo *info); -void Mapper190_Init(CartInfo *info); +void QTAi_Init(CartInfo *info); void NROM_Init(CartInfo *info); void Novel_Init(CartInfo *info); void S74LS374NA_Init(CartInfo *info); @@ -158,6 +158,11 @@ void BMC810131C_Init(CartInfo *info); void BMC8IN1_Init(CartInfo *info); void BMC80013B_Init(CartInfo *info); void BMCHPxx_Init(CartInfo *info); +void MINDKIDS_Init(CartInfo *info); +void FNS_Init(CartInfo *info); +void BS400R_Init(CartInfo *info); +void BS4040R_Init(CartInfo *info); +void SMD132_SMD133_Init(CartInfo *info); extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM // bank switcherooing with certain boards... diff --git a/source/fceultra/utils/endian.cpp b/source/fceultra/utils/endian.cpp index f054e53..25b5c4e 100644 --- a/source/fceultra/utils/endian.cpp +++ b/source/fceultra/utils/endian.cpp @@ -275,7 +275,7 @@ int write64le(uint64 b, EMUFILE* os) int read32le(uint32 *Bufo, EMUFILE *fp) { - uint32 buf; + uint32 buf=0; if(fp->_fread(&buf,4)<4) return 0; #ifdef LOCAL_LE @@ -288,7 +288,7 @@ int read32le(uint32 *Bufo, EMUFILE *fp) int read16le(u16 *Bufo, EMUFILE *is) { - u16 buf; + u16 buf=0; if(is->_fread((char*)&buf,2) != 2) return 0; #ifdef LOCAL_LE @@ -301,7 +301,7 @@ int read16le(u16 *Bufo, EMUFILE *is) int read64le(uint64 *Bufo, EMUFILE *is) { - uint64 buf; + uint64 buf=0; if(is->_fread((char*)&buf,8) != 8) return 0; #ifdef LOCAL_LE diff --git a/source/fceultra/utils/general.cpp b/source/fceultra/utils/general.cpp index c84d9e7..9f49a19 100644 --- a/source/fceultra/utils/general.cpp +++ b/source/fceultra/utils/general.cpp @@ -28,10 +28,10 @@ uint32 uppow2(uint32 n) int x; for(x=31;x>=0;x--) - if(n&(1<UTF32 { try { return UtfConverter::FromUtf8(str); - } catch(std::exception) { + } catch(std::exception &e) { return L"(failed UTF-8 conversion)"; } } diff --git a/source/fceultra/utils/xstring.h b/source/fceultra/utils/xstring.h index b42aec1..9d86048 100644 --- a/source/fceultra/utils/xstring.h +++ b/source/fceultra/utils/xstring.h @@ -43,7 +43,7 @@ int str_ltrim(char *str, int flags); int str_rtrim(char *str, int flags); int str_strip(char *str, int flags); int chr_replace(char *str, char search, char replace); -int str_replace(char *str, char *search, char *replace); +int str_replace(char *str, const char *search, const char *replace); int HexStringToBytesLength(const std::string& str); int Base64StringToBytesLength(const std::string& str); @@ -129,4 +129,4 @@ std::string wcstombs(std::wstring str); std::string getExtension(const char* input); std::string StripExtension(std::string filename); -std::string StripPath(std::string filename); \ No newline at end of file +std::string StripPath(std::string filename); diff --git a/source/fceultra/version.h b/source/fceultra/version.h index d0bca7d..dc2c1be 100644 --- a/source/fceultra/version.h +++ b/source/fceultra/version.h @@ -25,7 +25,7 @@ #define __FCEU_VERSION //todo - everyone will want to support this eventually, i suppose -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__QT_DRIVER__) #include "scmrev.h" #else #ifdef SVN_REV @@ -60,8 +60,16 @@ #define FCEU_COMPILER_DETAIL "" #endif -#define FCEU_VERSION_NUMERIC 22020 -#define FCEU_VERSION_STRING "2.2.3" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER +#define FCEU_VERSION_MAJOR 2 +#define FCEU_VERSION_MINOR 6 +#define FCEU_VERSION_PATCH 4 + +#define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) ) +#define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) ) +#define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 ) +#define FCEU_VERSION_PATCH_DECODE(x) (x % 100) + +#define FCEU_VERSION_STRING "2.6.4" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER #define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING #endif diff --git a/source/fceultra/video.cpp b/source/fceultra/video.cpp index 6c19e39..4905f8e 100644 --- a/source/fceultra/video.cpp +++ b/source/fceultra/video.cpp @@ -37,7 +37,7 @@ #include "fceulua.h" #endif -#ifdef WIN32 +#ifdef __WIN_DRIVER__ #include "drivers/win/common.h" //For DirectX constants #include "drivers/win/input.h" #endif @@ -72,6 +72,8 @@ static u8 *xbsave=NULL; GUIMESSAGE guiMessage; GUIMESSAGE subtitleMessage; +bool vidGuiMsgEna = true; + //for input display extern int input_display; extern uint32 cur_input_display; @@ -87,23 +89,23 @@ std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; } void FCEU_KillVirtualVideo(void) { - //mbg merge TODO 7/17/06 temporarily removed - //if(xbsave) - //{ - // free(xbsave); - // xbsave=0; - //} - //if(XBuf) - //{ - //UnmapViewOfFile(XBuf); - //CloseHandle(mapXBuf); - //mapXBuf=NULL; - //} - //if(XBackBuf) - //{ - // free(XBackBuf); - // XBackBuf=0; - //} + if ( XBuf ) + { + FCEU_free(XBuf); XBuf = NULL; + } + if ( XBackBuf ) + { + FCEU_free(XBackBuf); XBackBuf = NULL; + } + if ( XDBuf ) + { + FCEU_free(XDBuf); XDBuf = NULL; + } + if ( XDBackBuf ) + { + FCEU_free(XDBackBuf); XDBackBuf = NULL; + } + //printf("Video Core Cleanup\n"); } /** @@ -178,6 +180,31 @@ static void ReallySnap(void) FCEU_DispMessage("Screen snapshot %d saved.",0,x-1); } +static uint32 GetButtonColor(uint32 held, uint32 c, uint32 ci, int bit) +{ + uint32 on = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0x90 : 0xA7; //Standard, or Gray depending on movie mode + uint32 oni = 0xA0; //Color for immediate keyboard buttons + uint32 blend = 0xB6; //Blend of immiate and last held buttons + uint32 ahold = 0x87; //Auto hold + uint32 off = 0xCF; + + uint32 color; + uint8 mask = 1u << bit; + if (held & mask) { //If auto-hold + if (!(ci & mask)) + color = ahold; + else + color = (c & mask) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! + } + else { + if (c & mask) + color = (ci & mask) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors + else + color = (ci & mask) ? oni : off; + } + return color; +} + void FCEU_PutImage(void) { if(dosnapsave==2) //Save screenshot as, currently only flagged & run by the Win32 build. //TODO SDL: implement this? @@ -246,20 +273,10 @@ void FCEU_PutImage(void) //Fancy input display code if(input_display) { - extern uint32 JSAutoHeld; - uint32 held; - - int controller, c, ci, color; int i, j; - uint32 on = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0x90:0xA7; //Standard, or Gray depending on movie mode - uint32 oni = 0xA0; //Color for immediate keyboard buttons - uint32 blend = 0xB6; //Blend of immiate and last held buttons - uint32 ahold = 0x87; //Auto hold - uint32 off = 0xCF; - uint8 *t = XBuf+(FSettings.LastSLine-9)*256 + 20; //mbg merge 7/17/06 changed t to uint8* if(input_display > 4) input_display = 4; - for(controller = 0; controller < input_display; controller++, t += 56) + for(int controller = 0; controller < input_display; controller++, t += 56) { for(i = 0; i < 34;i++) for(j = 0; j <9 ; j++) @@ -267,33 +284,28 @@ void FCEU_PutImage(void) for(i = 3; i < 6; i++) for(j = 3; j< 6; j++) t[i+j*256] = 0xCF; - c = cur_input_display >> (controller * 8); + uint32 held = 0; + uint32 c = cur_input_display >> (controller * 8); + uint32 ci = 0; + uint32 color; + +#ifdef __WIN_DRIVER__ + extern uint32 JSAutoHeld; // This doesn't work in anything except windows for now. // It doesn't get set anywhere in other ports. -#ifdef WIN32 - if (!oldInputDisplay) ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0:GetGamepadPressedImmediate() >> (controller * 8); - else ci = 0; + if (!oldInputDisplay) + ci = FCEUMOV_Mode(MOVIEMODE_PLAY) ? 0 : GetGamepadPressedImmediate() >> (controller * 8); - if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY)) held = (JSAutoHeld >> (controller * 8)); - else held = 0; + if (!oldInputDisplay && !FCEUMOV_Mode(MOVIEMODE_PLAY)) + held = (JSAutoHeld >> (controller * 8)); #else // Put other port info here - ci = 0; - held = 0; #endif //adelikat: I apologize to anyone who ever sifts through this color assignment //A - if (held&1) { //If auto-hold - if (!(ci&1) ) color = ahold; - else - color = (c&1) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&1) color = (ci&1) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&1) ? oni : off; - } + color = GetButtonColor(held, c, ci, 0); for(i=0; i < 4; i++) { for(j = 0; j < 4; j++) @@ -304,15 +316,7 @@ void FCEU_PutImage(void) } } //B - if (held&2) { //If auto-hold - if (!(ci&2) ) color = ahold; - else - color = (c&2) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&2) color = (ci&2) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&2) ? oni : off; - } + color = GetButtonColor(held, c, ci, 1); for(i=0; i < 4; i++) { for(j = 0; j < 4; j++) @@ -323,45 +327,21 @@ void FCEU_PutImage(void) } } //Select - if (held&4) { //If auto-hold - if (!(ci&4) ) color = ahold; - else - color = (c&4) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&4) color = (ci&4) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&4) ? oni : off; - } + color = GetButtonColor(held, c, ci, 2); for(i = 0; i < 4; i++) { t[11+5*256+i] = color; t[11+6*256+i] = color; } //Start - if (held&8) { //If auto-hold - if (!(ci&8) ) color = ahold; - else - color = (c&8) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&8) color = (ci&8) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&8) ? oni : off; - } + color = GetButtonColor(held, c, ci, 3); for(i = 0; i < 4; i++) { t[17+5*256+i] = color; t[17+6*256+i] = color; } //Up - if (held&16) { //If auto-hold - if (!(ci&16) ) color = ahold; - else - color = (c&16) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&16) color = (ci&16) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&16) ? oni : off; - } + color = GetButtonColor(held, c, ci, 4); for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) @@ -370,15 +350,7 @@ void FCEU_PutImage(void) } } //Down - if (held&32) { //If auto-hold - if (!(ci&32) ) color = ahold; - else - color = (c&32) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&32) color = (ci&32) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&32) ? oni : off; - } + color = GetButtonColor(held, c, ci, 5); for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) @@ -387,15 +359,7 @@ void FCEU_PutImage(void) } } //Left - if (held&64) { //If auto-hold - if (!(ci&64) ) color = ahold; - else - color = (c&64) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&64) color = (ci&64) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&64) ? oni : off; - } + color = GetButtonColor(held, c, ci, 6); for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) @@ -404,15 +368,7 @@ void FCEU_PutImage(void) } } //Right - if (held&128) { //If auto-hold - if (!(ci&128) ) color = ahold; - else - color = (c&128) ? on : off; //If the button is pressed down (immediate) that negates auto hold, however it is only off if the previous frame the button wasn't pressed! - } - else { - if (c&128) color = (ci&128) ? blend : on; //If immedaite buttons are pressed and they match the previous frame, blend the colors - else color = (ci&128) ? oni : off; - } + color = GetButtonColor(held, c, ci, 7); for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) @@ -444,7 +400,7 @@ void snapAVI() FCEUI_AviVideoUpdate(XBuf); } -void FCEU_DispMessageOnMovie(char *format, ...) +void FCEU_DispMessageOnMovie(const char *format, ...) { va_list ap; @@ -452,7 +408,10 @@ void FCEU_DispMessageOnMovie(char *format, ...) vsnprintf(guiMessage.errmsg,sizeof(guiMessage.errmsg),format,ap); va_end(ap); - guiMessage.howlong = 180; + if ( vidGuiMsgEna ) + { + guiMessage.howlong = 180; + } guiMessage.isMovieMessage = true; guiMessage.linesFromBottom = 0; @@ -460,7 +419,7 @@ void FCEU_DispMessageOnMovie(char *format, ...) guiMessage.howlong = 0; } -void FCEU_DispMessage(char *format, int disppos=0, ...) +void FCEU_DispMessage(const char *format, int disppos=0, ...) { va_list ap; @@ -475,7 +434,10 @@ void FCEU_DispMessage(char *format, int disppos=0, ...) strcat(temp, "\n"); FCEU_printf(temp); - guiMessage.howlong = 180; + if ( vidGuiMsgEna ) + { + guiMessage.howlong = 180; + } guiMessage.isMovieMessage = false; guiMessage.linesFromBottom = disppos; @@ -501,7 +463,7 @@ void FCEU_ResetMessages() } -static int WritePNGChunk(FILE *fp, uint32 size, char *type, uint8 *data) +static int WritePNGChunk(FILE *fp, uint32 size, const char *type, uint8 *data) { uint32 crc; @@ -631,7 +593,7 @@ int SaveSnapshot(void) dest++; for(x=256;x;x--) { - u32 color = ModernDeemphColorMap(tmp,XBuf,1,1); + u32 color = ModernDeemphColorMap(tmp,XBuf,1); *dest++=(color>>0x10)&0xFF; *dest++=(color>>0x08)&0xFF; *dest++=(color>>0x00)&0xFF; @@ -774,29 +736,54 @@ bool FCEUI_ShowFPS() } void FCEUI_SetShowFPS(bool showFPS) { + if ( Show_FPS != showFPS ) + { + ResetFPS(); + } Show_FPS = showFPS; } void FCEUI_ToggleShowFPS() { Show_FPS ^= 1; + + ResetFPS(); } -static uint64 boop[60]; -static int boopcount = 0; +static uint64 boop_ts = 0; +static unsigned int boopcount = 0; + +void ResetFPS(void) +{ + boop_ts = 0; + boopcount = 0; +} void ShowFPS(void) { #ifndef GEKKO - if(Show_FPS == false) + if (Show_FPS == false) + { return; - uint64 da = FCEUD_GetTime() - boop[boopcount]; - char fpsmsg[16]; - int booplimit = PAL?50:60; - boop[boopcount] = FCEUD_GetTime(); + } + static char fpsmsg[16] = { 0 }; + uint64 ts = FCEUD_GetTime(); + uint64 da; + + if ( boop_ts == 0 ) + { + boop_ts = ts; + } + da = ts - boop_ts; + + if ( da > FCEUD_GetTimeFreq() ) + { + sprintf(fpsmsg, "%.1f", (double)boopcount / ((double)da / FCEUD_GetTimeFreq())); + + boopcount = 0; + boop_ts = ts; + } + boopcount++; - sprintf(fpsmsg, "%.1f", (double)booplimit / ((double)da / FCEUD_GetTimeFreq())); DrawTextTrans(XBuf + ((256 - ClipSidesOffset) - 40) + (FSettings.FirstSLine + 4) * 256, 256, (uint8*)fpsmsg, 0xA0); - // It's not averaging FPS over exactly 1 second, but it's close enough. - boopcount = (boopcount + 1) % booplimit; #endif } diff --git a/source/fceultra/video.h b/source/fceultra/video.h index 79c6fec..64e0688 100644 --- a/source/fceultra/video.h +++ b/source/fceultra/video.h @@ -12,7 +12,8 @@ extern uint8 *XBackBuf; extern uint8 *XDBuf; extern uint8 *XDBackBuf; extern int ClipSidesOffset; -extern struct GUIMESSAGE + +struct GUIMESSAGE { //countdown for gui messages int howlong; @@ -26,10 +27,21 @@ extern struct GUIMESSAGE //in case of multiple lines, allow one to move the message int linesFromBottom; -} guiMessage; + // constructor + GUIMESSAGE(void) + { + howlong = 0; + linesFromBottom = 0; + isMovieMessage = false; + errmsg[0] = 0; + } +}; +extern GUIMESSAGE guiMessage; extern GUIMESSAGE subtitleMessage; +extern bool vidGuiMsgEna; + void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur); std::string FCEUI_GetSnapshotAsName(); @@ -37,6 +49,7 @@ void FCEUI_SetSnapshotAsName(std::string name); bool FCEUI_ShowFPS(); void FCEUI_SetShowFPS(bool showFPS); void FCEUI_ToggleShowFPS(); -void ShowFPS(); -void snapAVI(); +void ShowFPS(void); +void ResetFPS(void); +void snapAVI(void); #endif diff --git a/source/fceultra/vsuni.cpp b/source/fceultra/vsuni.cpp index 5755474..1fc6f52 100644 --- a/source/fceultra/vsuni.cpp +++ b/source/fceultra/vsuni.cpp @@ -35,7 +35,7 @@ #define IOPTION_PREDIP 0x10 typedef struct { - char *name; + const char *name; uint64 md5partial; int mapper; int mirroring; @@ -102,10 +102,10 @@ void FCEU_VSUniCoin(void) { static int curppu; static int64 curmd5; -#define RP2C04_001 1 -#define RP2C04_002 2 -#define RP2C04_003 3 -#define RP2C05_004 4 +#define RP2C04_0001 1 +#define RP2C04_0002 2 +#define RP2C04_0003 3 +#define RP2C04_0004 4 #define RCP2C03B 5 #define RC2C05_01 6 #define RC2C05_02 7 @@ -192,7 +192,7 @@ void FCEU_VSUniPower(void) { /* Games/PPU list. Information copied from MAME. ROMs are exchangable, so don't take this list as "this game must use this PPU". -RP2C04-001: +RP2C04-0001: - Baseball - Freedom Force - Gradius @@ -202,7 +202,7 @@ RP2C04-001: - Platoon - Super Xevious -RP2C04-002: +RP2C04-0002: - Castlevania - Ladies golf - Mach Rider (Endurance Course) @@ -211,21 +211,21 @@ RP2C04-002: - Stroke N' Match Golf - Wrecking Crew -RP2C04-003: -- Dr mario +RP2C04-0003: +- Dr. Mario - Excite Bike - Goonies - Soccer - TKO Boxing -RP2c05-004: +RP2C04-0004: - Clu Clu Land - Excite Bike (Japan) - Ice Climber - Ice Climber Dual (Japan) - Super Mario Bros. -Rcp2c03b: +RCP2C03B: - Battle City - Duck Hunt - Mahjang @@ -252,47 +252,47 @@ RC2C05-04: VSUNIENTRY VSUniGames[] = { - { "Baseball", 0x691d4200ea42be45LL, 99, 2, RP2C04_001, 0 }, - { "Battle City", 0x8540949d74c4d0ebLL, 99, 2, RP2C04_001, 0 }, - { "Battle City(Bootleg)", 0x8093cbe7137ac031LL, 99, 2, RP2C04_001, 0 }, + { "Baseball", 0x691d4200ea42be45LL, 99, 2, RP2C04_0001, 0 }, + { "Battle City", 0x8540949d74c4d0ebLL, 99, 2, RP2C04_0001, 0 }, + { "Battle City(Bootleg)", 0x8093cbe7137ac031LL, 99, 2, RP2C04_0001, 0 }, - { "Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB }, - { "Dr Mario", 0xe1af09c477dc0081LL, 1, 0, RP2C04_003, IOPTION_SWAPDIRAB }, - { "Duck Hunt", 0x47735d1e5f1205bbLL, 99, 2, RCP2C03B, IOPTION_GUN }, - { "Excitebike", 0x3dcd1401bcafde77LL, 99, 2, RP2C04_003, 0 }, - { "Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2, RP2C05_004, 0 }, - { "Freedom Force", 0xed96436bd1b5e688LL, 4, 0, RP2C04_001, IOPTION_GUN }, /* Wrong color in game select screen? */ - { "Stroke and Match Golf", 0x612325606e82bc66LL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 }, + { "Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB }, + { "Dr Mario", 0xe1af09c477dc0081LL, 1, 0, RP2C04_0003, IOPTION_SWAPDIRAB }, + { "Duck Hunt", 0x47735d1e5f1205bbULL, 99, 2, RCP2C03B, IOPTION_GUN }, + { "Excitebike", 0x3dcd1401bcafde77LL, 99, 2, RP2C04_0003, 0 }, + { "Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2, RP2C04_0004, 0 }, + { "Freedom Force", 0xed96436bd1b5e688LL, 4, 0, RP2C04_0001, IOPTION_GUN }, /* Wrong color in game select screen? */ + { "Stroke and Match Golf", 0x612325606e82bc66LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 }, - { "Goonies", 0xb4032d694e1d2733LL, 151, 1, RP2C04_003, 0 }, - { "Gradius", 0x50687ae63bdad976LL, 151, 1, RP2C04_001, IOPTION_SWAPDIRAB }, - { "Gumshoe", 0x87161f8ee37758d3LL, 99, 2, RC2C05_03, IOPTION_GUN }, - { "Gumshoe", 0xb8500780bf69ce29LL, 99, 2, RC2C05_03, IOPTION_GUN }, - { "Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_001, IOPTION_GUN }, - { "Ice Climber", 0xd21e999513435e2aLL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB }, - { "Ladies Golf", 0x781b24be57ef6785LL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, + { "Goonies", 0xb4032d694e1d2733LL, 151, 1, RP2C04_0003, 0 }, + { "Gradius", 0x50687ae63bdad976LL, 151, 1, RP2C04_0001, IOPTION_SWAPDIRAB }, + { "Gumshoe", 0x87161f8ee37758d3ULL, 99, 2, RC2C05_03, IOPTION_GUN }, + { "Gumshoe", 0xb8500780bf69ce29ULL, 99, 2, RC2C05_03, IOPTION_GUN }, + { "Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_0001, IOPTION_GUN }, + { "Ice Climber", 0xd21e999513435e2aLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB }, + { "Ladies Golf", 0x781b24be57ef6785LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, - { "Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_002, 0 }, - { "Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_001, 0 }, - { "Mighty Bomb Jack", 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02, 0 }, - { "Ninja Jajamaru Kun", 0xb26a2c31474099c0LL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB }, - { "Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_001, IOPTION_PREDIP, 0x01 }, - { "Pinball (J)", 0x66ab1a3828cc901cLL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 }, - { "Platoon", 0x160f237351c19f1fLL, 68, 1, RP2C04_001, 0 }, - { "RBI Baseball", 0x6a02d345812938afLL, 4, 1, RP2C04_001, IOPTION_SWAPDIRAB }, - { "Soccer", 0xd4e7a9058780eda3LL, 99, 2, RP2C04_003, IOPTION_SWAPDIRAB }, - { "Star Luster", 0x8360e134b316d94cLL, 99, 2, RCP2C03B, 0 }, - { "Stroke and Match Golf (J)", 0x869bb83e02509747LL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, - { "Super Sky Kid", 0x78d04c1dd4ec0101LL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 }, + { "Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_0002, 0 }, + { "Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_0001, 0 }, + { "Mighty Bomb Jack", 0xe6a89f4873fac37bULL, 0, 2, RC2C05_02, 0 }, + { "Ninja Jajamaru Kun", 0xb26a2c31474099c0ULL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB }, + { "Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_0001, IOPTION_PREDIP, 0x01 }, + { "Pinball (J)", 0x66ab1a3828cc901cULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 }, + { "Platoon", 0x160f237351c19f1fLL, 68, 1, RP2C04_0001, 0 }, + { "RBI Baseball", 0x6a02d345812938afLL, 4, 1, RP2C04_0001, IOPTION_SWAPDIRAB }, + { "Soccer", 0xd4e7a9058780eda3LL, 99, 2, RP2C04_0003, IOPTION_SWAPDIRAB }, + { "Star Luster", 0x8360e134b316d94cULL, 99, 2, RCP2C03B, 0 }, + { "Stroke and Match Golf (J)", 0x869bb83e02509747ULL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, + { "Super Sky Kid", 0x78d04c1dd4ec0101ULL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 }, - { "Super Xevious", 0x2d396247cf58f9faLL, 206, 0, RP2C04_001, 0 }, - { "Tetris", 0x531a5e8eea4ce157LL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 }, - { "Top Gun", 0xf1dea36e6a7b531dLL, 2, 0, RC2C05_04, 0 }, - { "VS Castlevania", 0x92fd6909c81305b9LL, 2, 1, RP2C04_002, 0 }, - { "VS Slalom", 0x4889b5a50a623215LL, 0, 1, RP2C04_002, 0 }, - { "VS Super Mario Bros", 0x39d8cfa788e20b6cLL, 99, 2, RP2C05_004, 0 }, - { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dLL, 99, 2, RP2C05_004, 0 }, - { "VS TKO Boxing", 0x6e1ee06171d8ce3aLL, 4, 1, RP2C04_003, IOPTION_PREDIP, 0x00 }, + { "Super Xevious", 0x2d396247cf58f9faLL, 206, 0, RP2C04_0001, 0 }, + { "Tetris", 0x531a5e8eea4ce157ULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 }, + { "Top Gun", 0xf1dea36e6a7b531dULL, 2, 0, RC2C05_04, 0 }, + { "VS Castlevania", 0x92fd6909c81305b9LL, 2, 1, RP2C04_0002, 0 }, + { "VS Slalom", 0x4889b5a50a623215LL, 0, 1, RP2C04_0002, 0 }, + { "VS Super Mario Bros", 0x39d8cfa788e20b6cLL, 99, 2, RP2C04_0004, 0 }, + { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dLL, 99, 2, RP2C04_0004, 0 }, + { "VS TKO Boxing", 0x6e1ee06171d8ce3aLL, 4, 1, RP2C04_0003, IOPTION_PREDIP, 0x00 }, { 0 } }; @@ -302,6 +302,7 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring) { while (vs->name) { if (md5partial == vs->md5partial) { if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu; + else default_palette_selection = 5; *MapperNo = vs->mapper; *Mirroring = vs->mirroring; GameInfo->type = GIT_VSUNI; diff --git a/source/fceultra/wave.cpp b/source/fceultra/wave.cpp index de6f1dc..3af64ed 100644 --- a/source/fceultra/wave.cpp +++ b/source/fceultra/wave.cpp @@ -24,7 +24,7 @@ void FCEU_WriteWaveData(int32 *Buffer, int Count) int16 *dest; int x; -#ifndef WIN32 +#ifdef __WIN_DRIVER__ if(!soundlog) return; #else if(!soundlog && !FCEUI_AviIsRecording()) return; @@ -46,7 +46,7 @@ void FCEU_WriteWaveData(int32 *Buffer, int Count) if(soundlog) wsize+=fwrite(temp,1,Count*sizeof(int16),soundlog); - #ifdef WIN32 + #ifdef __WIN_DRIVER__ if(FCEUI_AviIsRecording()) { FCEUI_AviSoundUpdate((void*)temp, Count); @@ -124,3 +124,8 @@ bool FCEUI_BeginWaveRecord(const char *fn) return true; } + +bool FCEUI_WaveRecordRunning(void) +{ + return (soundlog != NULL); +} diff --git a/source/fceultra/wave.h b/source/fceultra/wave.h index 3305528..22d56a1 100644 --- a/source/fceultra/wave.h +++ b/source/fceultra/wave.h @@ -1,4 +1,6 @@ #include "types.h" +bool FCEUI_BeginWaveRecord(const char *fn); +bool FCEUI_WaveRecordRunning(void); void FCEU_WriteWaveData(int32 *Buffer, int Count); -int FCEUI_EndWaveRecord(); +int FCEUI_EndWaveRecord(void); diff --git a/source/fceultra/x6502.cpp b/source/fceultra/x6502.cpp index c167adc..fa6c98b 100644 --- a/source/fceultra/x6502.cpp +++ b/source/fceultra/x6502.cpp @@ -355,6 +355,11 @@ static uint8 CycTable[256] = /*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, }; +int X6502_GetOpcodeCycles( int op ) +{ + return CycTable[op]; +} + void X6502_IRQBegin(int w) { _IRQlow|=w; @@ -629,4 +634,4 @@ const uint8 opwrite[256] = { /*0xD0*/ 0, 0, 0,10, 0, 0,10,10, 0, 0, 0,10, 0, 0,10,10, /*0xE0*/ 0, 0, 0, 9, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, /*0xF0*/ 0, 0, 0, 9, 0, 0, 9, 9, 0, 0, 0, 9, 0, 0, 9, 9, -}; \ No newline at end of file +}; diff --git a/source/fceultra/x6502.h b/source/fceultra/x6502.h index 3204e69..460683d 100644 --- a/source/fceultra/x6502.h +++ b/source/fceultra/x6502.h @@ -90,5 +90,7 @@ void X6502_DMW(uint32 A, uint8 V); void X6502_IRQBegin(int w); void X6502_IRQEnd(int w); +int X6502_GetOpcodeCycles( int op ); + #define _X6502H #endif diff --git a/source/fceusupport.cpp b/source/fceusupport.cpp index 26a84c7..e738dbf 100644 --- a/source/fceusupport.cpp +++ b/source/fceusupport.cpp @@ -177,6 +177,7 @@ DUMMY(FCEUD_LoadStateFrom) DUMMY(FCEUD_MovieRecordTo) DUMMY(FCEUD_MovieReplayFrom) DUMMY(FCEUD_ToggleStatusIcon) +DUMMY(FCEUD_FlushTrace) DUMMY(FCEUD_DebugBreakpoint) DUMMY(FCEUD_SoundToggle) DUMMY(FCEUD_AviRecordTo) diff --git a/source/fceusupport.h b/source/fceusupport.h index 1a5fb39..9e2d011 100644 --- a/source/fceusupport.h +++ b/source/fceusupport.h @@ -37,7 +37,7 @@ extern unsigned char * nesrom; int GetFCEUTiming(); void UpdateDendy(); void RebuildSubCheats(void); -int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int status, int type); +int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type); extern int FDSLoad(const char *name, FCEUFILE *fp); extern int iNESLoad(const char *name, FCEUFILE *fp, int o);