From 50b3150515e0aec03367587dfcac887560ee5269 Mon Sep 17 00:00:00 2001 From: Daryl Borth Date: Mon, 13 Aug 2018 09:04:20 -0600 Subject: [PATCH] update to the latest FCEUX core from git head. --- readme.txt | 3 +- source/fceultra/asm.cpp | 12 +- source/fceultra/boards/01-222.cpp | 2 + source/fceultra/boards/112.cpp | 2 +- source/fceultra/boards/164.cpp | 6 +- source/fceultra/boards/168.cpp | 4 +- source/fceultra/boards/178.cpp | 110 +-- source/fceultra/boards/28.cpp | 3 +- source/fceultra/boards/36.cpp | 8 +- source/fceultra/boards/69.cpp | 7 +- source/fceultra/boards/addrlatch.cpp | 10 +- source/fceultra/boards/coolboy.cpp | 254 ++++--- source/fceultra/boards/datalatch.cpp | 65 +- source/fceultra/boards/emu2413.h | 37 +- source/fceultra/boards/famicombox.cpp | 2 +- source/fceultra/boards/fk23c.cpp | 259 ++++--- source/fceultra/boards/inlnsf.cpp | 84 +- source/fceultra/boards/ks7010.cpp | 170 ++--- source/fceultra/boards/malee.cpp | 1 + source/fceultra/boards/mihunche.cpp | 136 ++-- source/fceultra/boards/mmc1.cpp | 134 ++-- source/fceultra/boards/mmc3.cpp | 22 +- source/fceultra/boards/mmc5.cpp | 157 +++- source/fceultra/boards/n106.cpp | 27 +- source/fceultra/boards/onebus.cpp | 4 +- source/fceultra/boards/sb-2000.cpp | 390 +++++----- source/fceultra/boards/unrom512.cpp | 506 ++++++------ source/fceultra/boards/vrc2and4.cpp | 142 ++-- source/fceultra/boards/vrc5.cpp | 428 +++++------ source/fceultra/boards/vrc7.cpp | 2 +- source/fceultra/cart.cpp | 2 + source/fceultra/cart.h | 2 + source/fceultra/cheat.cpp | 16 +- source/fceultra/conddebug.cpp | 60 +- source/fceultra/conddebug.h | 6 +- source/fceultra/config.cpp | 9 +- source/fceultra/debug.cpp | 115 ++- source/fceultra/debug.h | 4 - source/fceultra/driver.h | 8 +- source/fceultra/fceu.cpp | 230 +++++- source/fceultra/fceu.h | 16 +- source/fceultra/fds.cpp | 61 +- source/fceultra/file.cpp | 8 +- source/fceultra/git.h | 8 +- source/fceultra/ines-bad.h | 1 + source/fceultra/ines-correct.h | 20 +- source/fceultra/ines.cpp | 48 +- source/fceultra/ines.h | 1 + source/fceultra/input.cpp | 341 ++++++--- source/fceultra/input.h | 5 + source/fceultra/input/mouse.cpp | 72 +- source/fceultra/input/pec586kb.cpp | 192 ++--- source/fceultra/movie.cpp | 116 ++- source/fceultra/movie.h | 13 +- source/fceultra/netplay.cpp | 2 +- source/fceultra/nsf.cpp | 12 +- source/fceultra/palette.cpp | 1013 +++++++++++++++---------- source/fceultra/palettes/palettes.h | 56 +- source/fceultra/ppu.cpp | 433 +++++++---- source/fceultra/ppu.h | 9 +- source/fceultra/pputile.inc | 8 +- source/fceultra/sound.cpp | 109 +-- source/fceultra/sound.h | 2 +- source/fceultra/state.cpp | 4 + source/fceultra/types-des.h | 916 +++++++++++----------- source/fceultra/types.h | 5 +- source/fceultra/unif.cpp | 16 +- source/fceultra/unif.h | 314 ++++---- source/fceultra/utils/memory.cpp | 12 +- source/fceultra/utils/memory.h | 4 +- source/fceultra/utils/xstring.cpp | 10 +- source/fceultra/version.h | 8 +- source/fceultra/video.cpp | 99 ++- source/fceultra/video.h | 2 + source/fceultra/vsuni.cpp | 2 +- source/fceultra/x6502.cpp | 84 +- source/fceultra/x6502.h | 7 +- source/fceusupport.cpp | 5 + 78 files changed, 4392 insertions(+), 3081 deletions(-) diff --git a/readme.txt b/readme.txt index 2969600..0afd822 100644 --- a/readme.txt +++ b/readme.txt @@ -30,7 +30,7 @@ https://github.com/dborth/fceugx/releases * Cheat support (.CHT files and Game Genie) * Famicom 3D System support * IPS/UPS automatic patching support -* NES Compatibility Based on FCEUX 2.2.0+ (r2951) +* NES Compatibility Based on FCEUX 2.2.3+ (git 21c0971) * Open Source! Χ—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ @@ -39,6 +39,7 @@ https://github.com/dborth/fceugx/releases [3.4.0] +* Update to the latest FCEUX core * Allow loader to pass two arguments instead of three (libertyernie) * Add PocketNES interoperability (load ROMs and read/write SRAM) * Add option to not append " Auto" on saves diff --git a/source/fceultra/asm.cpp b/source/fceultra/asm.cpp index 8221155..5b2f502 100644 --- a/source/fceultra/asm.cpp +++ b/source/fceultra/asm.cpp @@ -272,7 +272,7 @@ char *Disassemble(int addr, uint8 *opcode) { (a) = opcode[1] | opcode[2]<<8; \ } #define zpIndex(a,i) { \ - (a) = opcode[1]+(i); \ + (a) = (opcode[1]+(i))&0xFF; \ } #define indirectX(a) { \ (a) = (opcode[1]+RX)&0xFF; \ @@ -360,8 +360,8 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xE6: strcpy(chr,"INC"); goto _zeropage; _zeropage: // ################################## Start of SP CODE ########################### - // Change width to %04X - sprintf(str,"%s $%04X = #$%02X", chr,opcode[1],GetMem(opcode[1])); + // Change width to %04X // don't! + sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1])); // ################################## End of SP CODE ########################### break; @@ -457,7 +457,7 @@ char *Disassemble(int addr, uint8 *opcode) { _zeropagex: zpIndex(tmp,RX); // ################################## Start of SP CODE ########################### - // Change width to %04X + // Change width to %04X // don't! sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); // ################################## End of SP CODE ########################### break; @@ -515,8 +515,8 @@ char *Disassemble(int addr, uint8 *opcode) { _zeropagey: zpIndex(tmp,RY); // ################################## Start of SP CODE ########################### - // Change width to %04X - sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); + // Change width to %04X // don't! + sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); // ################################## End of SP CODE ########################### break; diff --git a/source/fceultra/boards/01-222.cpp b/source/fceultra/boards/01-222.cpp index 64d2c96..414d62d 100644 --- a/source/fceultra/boards/01-222.cpp +++ b/source/fceultra/boards/01-222.cpp @@ -19,6 +19,7 @@ * * TXC mappers, originally much complex banksitching * + * P/N PRG MAP, UNIF Name * 01-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang * 01-22110-000 (52S ) - MGC-002 2-in-1 Gun * 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block @@ -27,6 +28,7 @@ * 01-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman * 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior * 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1 + * 01-22026-000 (05-04010-090) ( ) - MGC-026 4-in-1 * 01-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom * 01-22200-400 (------------) (079 ) - ET.03 F-15 City War * (172 ) - 1991 Du Ma Racing diff --git a/source/fceultra/boards/112.cpp b/source/fceultra/boards/112.cpp index 077be0e..f0aeff3 100644 --- a/source/fceultra/boards/112.cpp +++ b/source/fceultra/boards/112.cpp @@ -72,7 +72,7 @@ static void M112Power(void) { SetWriteHandler(0x4020, 0x5FFF, M112Write); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(8, 0x6000, WRAM); + FCEU_CheatAddRAM(8, 0x6000, WRAM); } static void StateRestore(int version) { diff --git a/source/fceultra/boards/164.cpp b/source/fceultra/boards/164.cpp index aa859e3..37b0439 100644 --- a/source/fceultra/boards/164.cpp +++ b/source/fceultra/boards/164.cpp @@ -102,7 +102,7 @@ static void Power(void) { SetWriteHandler(0x5000, 0x5FFF, Write); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); WSync(); } @@ -156,7 +156,7 @@ static void Power2(void) { SetWriteHandler(0x5000, 0x5FFF, Write2); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); WSync(); } @@ -208,7 +208,7 @@ static void Power3(void) { SetWriteHandler(0x5000, 0x5FFF, Write3); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); WSync(); } diff --git a/source/fceultra/boards/168.cpp b/source/fceultra/boards/168.cpp index 5ec8e89..c85b221 100644 --- a/source/fceultra/boards/168.cpp +++ b/source/fceultra/boards/168.cpp @@ -55,7 +55,7 @@ static void M168Power(void) { SetReadHandler(0x8000, 0xFFFF, CartBR); } -static void MNNNClose(void) { +static void M168Close(void) { if (CHRRAM) FCEU_gfree(CHRRAM); CHRRAM = NULL; @@ -67,7 +67,7 @@ static void StateRestore(int version) { void Mapper168_Init(CartInfo *info) { info->Power = M168Power; - info->Close = MNNNClose; + info->Close = M168Close; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); diff --git a/source/fceultra/boards/178.cpp b/source/fceultra/boards/178.cpp index 775fece..65e98a1 100644 --- a/source/fceultra/boards/178.cpp +++ b/source/fceultra/boards/178.cpp @@ -29,6 +29,12 @@ static uint8 reg[4]; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; +// Tennis with VR sensor, very simple behaviour +extern void GetMouseData(uint32 (&md)[3]); +static uint32 MouseData[3], click, lastclick; +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; @@ -40,41 +46,41 @@ static SFORMAT StateRegs[] = { 0 } }; -static int16 step_size[49] = { - 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, - 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, - 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, - 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, - 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 -}; //49 items -static int32 step_adj[16] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 }; +//static int16 step_size[49] = { +// 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, +// 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, +// 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, +// 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, +// 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 +//}; //49 items +//static int32 step_adj[16] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 }; //decode stuff -static int32 jedi_table[16 * 49]; -static int32 acc = 0; //ADPCM accumulator, initial condition must be 0 -static int32 decstep = 0; //ADPCM decoding step, initial condition must be 0 +//static int32 jedi_table[16 * 49]; +//static int32 acc = 0; //ADPCM accumulator, initial condition must be 0 +//static int32 decstep = 0; //ADPCM decoding step, initial condition must be 0 -static void jedi_table_init() { - int step, nib; +//static void jedi_table_init() { +// int step, nib; +// +// for (step = 0; step < 49; step++) { +// for (nib = 0; nib < 16; nib++) { +// int value = (2 * (nib & 0x07) + 1) * step_size[step] / 8; +// jedi_table[step * 16 + nib] = ((nib & 0x08) != 0) ? -value : value; +// } +// } +//} - for (step = 0; step < 49; step++) { - for (nib = 0; nib < 16; nib++) { - int value = (2 * (nib & 0x07) + 1) * step_size[step] / 8; - jedi_table[step * 16 + nib] = ((nib & 0x08) != 0) ? -value : value; - } - } -} - -static uint8 decode(uint8 code) { - acc += jedi_table[decstep + code]; - if ((acc & ~0x7ff) != 0) // acc is > 2047 - acc |= ~0xfff; - else acc &= 0xfff; - decstep += step_adj[code & 7] * 16; - if (decstep < 0) decstep = 0; - if (decstep > 48 * 16) decstep = 48 * 16; - return (acc >> 8) & 0xff; -} +//static uint8 decode(uint8 code) { +// acc += jedi_table[decstep + code]; +// if ((acc & ~0x7ff) != 0) // acc is > 2047 +// acc |= ~0xfff; +// else acc &= 0xfff; +// decstep += step_adj[code & 7] * 16; +// if (decstep < 0) decstep = 0; +// if (decstep > 48 * 16) decstep = 48 * 16; +// return (acc >> 8) & 0xff; +//} static void Sync(void) { uint32 sbank = reg[1] & 0x7; @@ -109,11 +115,11 @@ static DECLFW(M178WriteSnd) { if (V & 0xF0) { pcm_enable = 1; // pcmwrite(0x4011, (V & 0xF) << 3); - pcmwrite(0x4011, decode(V & 0xf)); +// pcmwrite(0x4011, decode(V & 0xf)); } else pcm_enable = 0; - } else - FCEU_printf("misc %04x:%02x\n", A, V); + }// else +// FCEU_printf("misc %04x:%02x\n", A, V); } static DECLFR(M178ReadSnd) { @@ -123,13 +129,19 @@ static DECLFR(M178ReadSnd) { return X.DB; } +static DECLFR(M178ReadSensor) { + X6502_IRQEnd(FCEU_IQEXT); // hacky-hacky, actual reg is 6000 and it clear IRQ while reading, but then I need another mapper lol + return 0x00; +} + static void M178Power(void) { - reg[0] = reg[1] = reg[2] = reg[3] = 0; + reg[0] = reg[1] = reg[2] = reg[3] = SensorDelay = 0; Sync(); - pcmwrite = GetWriteHandler(0x4011); +// pcmwrite = GetWriteHandler(0x4011); SetWriteHandler(0x4800, 0x4fff, M178Write); SetWriteHandler(0x5800, 0x5fff, M178WriteSnd); SetReadHandler(0x5800, 0x5fff, M178ReadSnd); + SetReadHandler(0x5000, 0x5000, M178ReadSensor); SetReadHandler(0x6000, 0x7fff, CartBR); SetWriteHandler(0x6000, 0x7fff, CartBW); SetReadHandler(0x8000, 0xffff, CartBR); @@ -137,13 +149,25 @@ static void M178Power(void) { } static void M178SndClk(int a) { - if (pcm_enable) { - pcm_latch -= a; - if (pcm_latch <= 0) { - pcm_latch += pcm_clock; - pcm_enable = 0; - } + SensorDelay += a; + if(SensorDelay > 0x32768) { + SensorDelay -= 32768; + GetMouseData (MouseData); + lastclick = click; + click = MouseData[2] & 1; // to prevent from continuos IRQ trigger if button is held. + // actual circuit is just a D-C-R edge detector for IR-sensor + // triggered by the active IR bat. + if(lastclick && !click) + X6502_IRQBegin(FCEU_IQEXT); } + +// if (pcm_enable) { +// pcm_latch -= a; +// if (pcm_latch <= 0) { +// pcm_latch += pcm_clock; +// pcm_enable = 0; +// } +// } } static void M178Close(void) { @@ -162,7 +186,7 @@ void Mapper178_Init(CartInfo *info) { GameStateRestore = StateRestore; MapIRQHook = M178SndClk; - jedi_table_init(); +// jedi_table_init(); WRAMSIZE = 32768; WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); diff --git a/source/fceultra/boards/28.cpp b/source/fceultra/boards/28.cpp index c787b8c..617b3ae 100644 --- a/source/fceultra/boards/28.cpp +++ b/source/fceultra/boards/28.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 FCEUX team + Copyright (C) 2012-2017 FCEUX team This file is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -141,6 +141,7 @@ static DECLFW(WritePRG) case 0x00: chr = value & 3; Mirror(value); + Sync(); break; case 0x01: prg = value & 15; diff --git a/source/fceultra/boards/36.cpp b/source/fceultra/boards/36.cpp index 209d777..dea977e 100644 --- a/source/fceultra/boards/36.cpp +++ b/source/fceultra/boards/36.cpp @@ -22,11 +22,12 @@ #include "mapinc.h" -static uint8 latche; +static uint8 latche, mirr; static SFORMAT StateRegs[] = { { &latche, 1, "LATC" }, + { &mirr, 1, "MIRR" }, { 0 } }; @@ -36,6 +37,11 @@ static void Sync(void) { } static DECLFW(M36Write) { + + switch((A>>12)&7) { // need to 4-in-1 MGC-26 BMC, doesnt break other games though + case 0: mirr = MI_V; setmirror(mirr); break; + case 4: mirr = MI_H; setmirror(mirr); break; + } latche = V; Sync(); } diff --git a/source/fceultra/boards/69.cpp b/source/fceultra/boards/69.cpp index 1baa629..bc25621 100644 --- a/source/fceultra/boards/69.cpp +++ b/source/fceultra/boards/69.cpp @@ -41,7 +41,7 @@ static SFORMAT StateRegs[] = static void Sync(void) { uint8 i; if ((preg[3] & 0xC0) == 0xC0) - setprg8r(0x10, 0x6000, 0); + setprg8r(0x10, 0x6000, preg[3] & 0x3F); else setprg8(0x6000, preg[3] & 0x3F); setprg8(0x8000, preg[0]); @@ -258,7 +258,10 @@ void Mapper69_Init(CartInfo *info) { info->Power = M69Power; info->Close = M69Close; MapIRQHook = M69IRQHook; - WRAMSIZE = 8192; + if(info->ines2) + WRAMSIZE = info->wram_size + info->battery_wram_size; + else + WRAMSIZE = 8192; WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); diff --git a/source/fceultra/boards/addrlatch.cpp b/source/fceultra/boards/addrlatch.cpp index dc0128e..44480ae 100644 --- a/source/fceultra/boards/addrlatch.cpp +++ b/source/fceultra/boards/addrlatch.cpp @@ -303,14 +303,20 @@ static void M212Sync(void) { } void Mapper212_Init(CartInfo *info) { - Latch_Init(info, M212Sync, M212Read, 0xFFFF, 0x8000, 0xFFFF, 0); + Latch_Init(info, M212Sync, M212Read, 0x0000, 0x8000, 0xFFFF, 0); } //------------------ Map 213 --------------------------- static void M213Sync(void) { - setprg32(0x8000, (latche >> 1) & 3); + if(latche & 0x40) { + setprg16(0x8000, (latche & 7)); + setprg16(0xC000, (latche & 7)); + } else { + setprg32(0x8000, (latche >> 1) & 3); + } setchr8((latche >> 3) & 7); + setmirror(((latche & 1)^((latche >> 6) & 1)) ^ 1); } void Mapper213_Init(CartInfo *info) { diff --git a/source/fceultra/boards/coolboy.cpp b/source/fceultra/boards/coolboy.cpp index 4672553..3224919 100644 --- a/source/fceultra/boards/coolboy.cpp +++ b/source/fceultra/boards/coolboy.cpp @@ -1,108 +1,146 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2015 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 - * - * CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM - * only MMC3 mode - * - * 6000 (υυ76x210) | 0υΡ0 - * 6001 (υυυ354υυ) - * 6002 = 0 - * 6003 = 0 - * - */ - -#include "mapinc.h" -#include "mmc3.h" - -static void COOLBOYCW(uint32 A, uint8 V) { - if(EXPREGS[3] & 0x10) - setchr8(EXPREGS[2] & 0xF); - else { - uint32 mask = 0xFF; - switch(EXPREGS[0] & 0xC0) { - case 0xC0: - mask = 0x7F; - break; - } - setchr1(A, V & mask); - } -} - -static void COOLBOYPW(uint32 A, uint8 V) { - uint32 mask, shift; - uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); - switch(EXPREGS[0] & 0xC0) { - case 0x00: - mask = 0x3F; - break; - case 0x80: - mask = 0x1F; - break; - case 0xC0: - if(EXPREGS[3] & 0x10) { - mask = 0x01 | (EXPREGS[1] & 2); - } else { - mask = 0x0F; - } - break; - } - if(EXPREGS[3] & 0x10) - setprg8(A, (base << 4) | (V & mask) | ((EXPREGS[3] & (0x0E ^ (EXPREGS[1] & 2))) )); - else - setprg8(A, (base << 4) | (V & mask)); -} - -static DECLFW(COOLBOYWrite) { - if(A001B & 0x80) - CartBW(A,V); - else - if((EXPREGS[3] & 0x80) == 0) { - EXPREGS[A & 3] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); - FCEU_printf("exp %02x %02x (base %03d)\n",A,V,base); - } -} - -static void COOLBOYReset(void) { - MMC3RegReset(); - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); -} - -static void COOLBOYPower(void) { - GenMMC3Power(); - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = 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, 0x6fff, COOLBOYWrite); -} - -void COOLBOY_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 128, 8, 0); - pwrap = COOLBOYPW; - cwrap = COOLBOYCW; - info->Power = COOLBOYPower; - info->Reset = COOLBOYReset; - AddExState(EXPREGS, 4, 0, "EXPR"); -} - +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2015 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 + * 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 + * + * CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM + * only MMC3 mode + * + * 6000 (xx76x210) | 0xC0 + * 6001 (xxx354x) + * 6002 = 0 + * 6003 = 0 + * + * hardware tested logic, don't try to understand lol + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void COOLBOYCW(uint32 A, uint8 V) { + uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80); + if (EXPREGS[3] & 0x10) { + if (EXPREGS[3] & 0x40) { // Weird mode + int cbase = (MMC3_cmd & 0x80) << 5; + switch (cbase ^ A) { // Don't even try do understand + case 0x0400: + case 0x0C00: V &= 0x7F; break; + } + } + // Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise + setchr1(A, + (V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit + | ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits + | ((A >> 10) & 7) // 2-0 bits + ); + } else { + if (EXPREGS[3] & 0x40) { // Weird mode, again + int cbase = (MMC3_cmd & 0x80) << 5; + switch (cbase ^ A) { // Don't even try do understand + case 0x0000: V = DRegBuf[0]; break; + case 0x0800: V = DRegBuf[1]; break; + case 0x0400: + case 0x0C00: V = 0; break; + } + } + // Simple MMC3 mode + // Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise + setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask)); + } +} + +static void COOLBOYPW(uint32 A, uint8 V) { + uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2); + uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); + + // Very weird mode + // 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; + } + } + + // Regular MMC3 mode, internal ROM size can be up to 2048kb! + if (!(EXPREGS[3] & 0x10)) + setprg8(A, (((base << 4) & ~mask)) | (V & mask)); + else { // NROM mode + mask &= 0xF0; + uint8 emask; + if ((((EXPREGS[1] & 2) != 0))) // 32kb mode + emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13); + else // 16kb mode + emask = EXPREGS[3] & 0x0E; + setprg8(A, ((base << 4) & ~mask) // 7-4 bits are from base (see below) + | (V & mask) // ... or from MM3 internal regs, depends on mask + | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] + | ((A & 0x2000) >> 13)); // 0th just as is + } +} + +static DECLFW(COOLBOYWrite) { + if(A001B & 0x80) + CartBW(A,V); + + // Deny any further writes when 7th bit is 1 AND 4th is 0 + if ((EXPREGS[3] & 0x90) != 0x80) { + EXPREGS[A & 3] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +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); +} + +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); +} + +void COOLBOY_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 256, 8, 0); + pwrap = COOLBOYPW; + cwrap = COOLBOYCW; + info->Power = COOLBOYPower; + info->Reset = COOLBOYReset; + AddExState(EXPREGS, 4, 0, "EXPR"); +} \ No newline at end of file diff --git a/source/fceultra/boards/datalatch.cpp b/source/fceultra/boards/datalatch.cpp index 62bf2b5..dd8acf8 100644 --- a/source/fceultra/boards/datalatch.cpp +++ b/source/fceultra/boards/datalatch.cpp @@ -30,7 +30,7 @@ static void (*WSync)(void); static DECLFW(LatchWrite) { // FCEU_printf("bs %04x %02x\n",A,V); if (bus_conflict) - latche = (V == CartBR(A)) ? V : 0; + latche = V & CartBR(A); else latche = V; WSync(); @@ -68,15 +68,58 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad info->Power = LatchPower; info->Close = LatchClose; GameStateRestore = StateRestore; - if (wram) { - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; + 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; + } } - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + 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"); @@ -93,7 +136,7 @@ static DECLFW(NROMWrite) { static void NROMPower(void) { setprg8r(0x10, 0x6000, 0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB - setprg16(0x8000, 0); + setprg16(0x8000, ~1); setprg16(0xC000, ~0); setchr8(0); @@ -101,7 +144,7 @@ static void NROMPower(void) { SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); #ifdef DEBUG_MAPPER SetWriteHandler(0x4020, 0xFFFF, NROMWrite); diff --git a/source/fceultra/boards/emu2413.h b/source/fceultra/boards/emu2413.h index 38dd37c..1dd0e23 100644 --- a/source/fceultra/boards/emu2413.h +++ b/source/fceultra/boards/emu2413.h @@ -1,24 +1,23 @@ #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 - -#include - +#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 +#ifdef GEKKO typedef uint8_t uint8 ; typedef int8_t int8 ; @@ -27,6 +26,16 @@ 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 ; +#endif #define PI 3.14159265358979323846 diff --git a/source/fceultra/boards/famicombox.cpp b/source/fceultra/boards/famicombox.cpp index a47823f..077931f 100644 --- a/source/fceultra/boards/famicombox.cpp +++ b/source/fceultra/boards/famicombox.cpp @@ -70,7 +70,7 @@ static void SSSNROMPower(void) { regs[0] = regs[1] = regs[2] = regs[3] = regs[4] = regs[5] = regs[6] = 0; regs[7] = 0xff; Sync(); - memset(WRAM, 0x00, WRAMSIZE); + FCEU_MemoryRand(WRAM, WRAMSIZE, true); // SetWriteHandler(0x0000,0x1FFF,SSSNROMRamWrite); SetReadHandler(0x0800, 0x1FFF, CartBR); SetWriteHandler(0x0800, 0x1FFF, CartBW); diff --git a/source/fceultra/boards/fk23c.cpp b/source/fceultra/boards/fk23c.cpp index 604d516..d7b3889 100644 --- a/source/fceultra/boards/fk23c.cpp +++ b/source/fceultra/boards/fk23c.cpp @@ -30,26 +30,22 @@ static uint32 CHRRAMSize; static void BMCFK23CCW(uint32 A, uint8 V) { - if(EXPREGS[0]&0x40) - setchr8(EXPREGS[2]|unromchr); - else if(EXPREGS[0]&0x20) { - setchr1r(0x10, A, V); - } - else - { - uint16 base=(EXPREGS[2]&0x7F)<<3; - if(EXPREGS[3]&2) - { - int cbase=(MMC3_cmd&0x80)<<5; - setchr1(A,V|base); - setchr1(0x0000^cbase,DRegBuf[0]|base); - setchr1(0x0400^cbase,EXPREGS[6]|base); - setchr1(0x0800^cbase,DRegBuf[1]|base); - setchr1(0x0c00^cbase,EXPREGS[7]|base); - } - else - setchr1(A,V|base); - } + if(EXPREGS[0]&0x40) + setchr8(EXPREGS[2]|unromchr); + else if(EXPREGS[0]&0x20) { + setchr1r(0x10, A, V); + } else { + uint16 base=(EXPREGS[2]&0x7F)<<3; + if(EXPREGS[3]&2) { + int cbase=(MMC3_cmd&0x80)<<5; + setchr1(A,V|base); + setchr1(0x0000^cbase,DRegBuf[0]|base); + setchr1(0x0400^cbase,EXPREGS[6]|base); + setchr1(0x0800^cbase,DRegBuf[1]|base); + setchr1(0x0c00^cbase,EXPREGS[7]|base); + } else + setchr1(A,V|base); + } } //some games are wired differently, and this will need to be changed. @@ -86,110 +82,110 @@ 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) - setprg32(0x8000,EXPREGS[1]>>1); - else if ((EXPREGS[0]&7)==3) - { - setprg16(0x8000,EXPREGS[1]); - setprg16(0xC000,EXPREGS[1]); - } - else - { - if(EXPREGS[0]&3) - { + if((EXPREGS[0]&7)==4) + setprg32(0x8000,EXPREGS[1]>>1); + else if ((EXPREGS[0]&7)==3) { + setprg16(0x8000,EXPREGS[1]); + setprg16(0xC000,EXPREGS[1]); + } else { + if(EXPREGS[0]&3) { uint32 blocksize = (6)-(EXPREGS[0]&3); uint32 mask = (1<Power=BMCFK23CPower; - info->Reset=BMCFK23CReset; - AddExState(EXPREGS, 8, 0, "EXPR"); - AddExState(&unromchr, 1, 0, "UCHR"); - AddExState(&dipswitch, 1, 0, "DPSW"); + GenMMC3_Init(info, 512, 256, 8, 0); + cwrap=BMCFK23CCW; + pwrap=BMCFK23CPW; + info->Power=BMCFK23CPower; + info->Reset=BMCFK23CReset; + AddExState(EXPREGS, 8, 0, "EXPR"); + AddExState(&unromchr, 1, 0, "UCHR"); + AddExState(&dipswitch, 1, 0, "DPSW"); prg_bonus = 1; if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end()) @@ -267,21 +266,21 @@ void BMCFK23CA_Init(CartInfo *info) { is_BMCFK23CA = true; - GenMMC3_Init(info, 512, 256, 8, 0); - cwrap=BMCFK23CCW; - pwrap=BMCFK23CPW; - info->Power=BMCFK23CAPower; - info->Reset=BMCFK23CReset; - info->Close=BMCFK23CAClose; + GenMMC3_Init(info, 512, 256, 8, 0); + cwrap=BMCFK23CCW; + pwrap=BMCFK23CPW; + info->Power=BMCFK23CAPower; + info->Reset=BMCFK23CReset; + info->Close=BMCFK23CAClose; CHRRAMSize=8192; - CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1); - AddExState(CHRRAM, CHRRAMSize, 0, "CRAM"); + CHRRAM=(uint8*)FCEU_gmalloc(CHRRAMSize); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1); + AddExState(CHRRAM, CHRRAMSize, 0, "CRAM"); - AddExState(EXPREGS, 8, 0, "EXPR"); - AddExState(&unromchr, 1, 0, "UCHR"); - AddExState(&dipswitch, 1, 0, "DPSW"); + AddExState(EXPREGS, 8, 0, "EXPR"); + AddExState(&unromchr, 1, 0, "UCHR"); + AddExState(&dipswitch, 1, 0, "DPSW"); prg_bonus = 1; if(MasterRomInfoParams.find("bonus") != MasterRomInfoParams.end()) diff --git a/source/fceultra/boards/inlnsf.cpp b/source/fceultra/boards/inlnsf.cpp index ccd0985..c9b9fd6 100644 --- a/source/fceultra/boards/inlnsf.cpp +++ b/source/fceultra/boards/inlnsf.cpp @@ -18,45 +18,45 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "mapinc.h" - -static uint8 regs[8]; - -static SFORMAT StateRegs[] = -{ - { regs, 8, "REGS" }, - { 0 } -}; - -static void Sync(void) { - for (int i=0; i < 8; ++i) - { - setprg4(0x8000 + (0x1000 * i), regs[i]); - } -} - -static DECLFW(M31Write) { - if (A >= 0x5000 && A <= 0x5FFF) - { - regs[A&7] = V; - Sync(); - } -} - -static void M31Power(void) { - setchr8(0); - regs[7] = 0xFF; - Sync(); - SetReadHandler(0x8000, 0xffff, CartBR); - SetWriteHandler(0x5000, 0x5fff, M31Write); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper31_Init(CartInfo *info) { - info->Power = M31Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} +#include "mapinc.h" + +static uint8 regs[8]; + +static SFORMAT StateRegs[] = +{ + { regs, 8, "REGS" }, + { 0 } +}; + +static void Sync(void) { + for (int i=0; i < 8; ++i) + { + setprg4(0x8000 + (0x1000 * i), regs[i]); + } +} + +static DECLFW(M31Write) { + if (A >= 0x5000 && A <= 0x5FFF) + { + regs[A&7] = V; + Sync(); + } +} + +static void M31Power(void) { + setchr8(0); + regs[7] = 0xFF; + Sync(); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x5000, 0x5fff, M31Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper31_Init(CartInfo *info) { + info->Power = M31Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/ks7010.cpp b/source/fceultra/boards/ks7010.cpp index a4a9960..7adbe89 100644 --- a/source/fceultra/boards/ks7010.cpp +++ b/source/fceultra/boards/ks7010.cpp @@ -1,85 +1,85 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2007 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 - */ - -#include "mapinc.h" - -static uint8 preg[4], creg, mirr; - -static SFORMAT StateRegs[] = -{ - { preg, 4, "PREG" }, - { &creg, 1, "CREG" }, - { &mirr, 1, "MIRR" }, - { 0 } -}; - -static void Sync(void) { - setprg8(0x6000, preg[0]); - setprg8(0x8000, 0xa); - setprg8(0xa000, 0xb); - setprg8(0xc000, 0x6); - setprg8(0xe000, 0x7); - setchr8(0x0c); - setmirror(mirr); -} - -static DECLFW(UNLKS7010Write) { - switch (A) { - case 0x4025: mirr = (((V >> 3) & 1) ^ 1); Sync(); break; - default: - FCEU_printf("bs %04x %02x\n",A,V); - break; - } -} - -static void UNLKS7010Reset(void) { - preg[0]++; - if(preg[0] == 0x10) { - preg[0] = 0; - preg[1]++; - if(preg[1] == 0x10) { - preg[1] = 0; - preg[2]++; - } - } - FCEU_printf("preg %02x %02x %02x\n",preg[0], preg[1], preg[2]); - Sync(); -} - -static void UNLKS7010Power(void) { - preg[0] = preg[1] = preg[2] = 0; - Sync(); - SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetReadHandler(0x8000, 0xffff, CartBR); - SetWriteHandler(0x4020, 0xffff, UNLKS7010Write); -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLKS7010_Init(CartInfo *info) { - info->Power = UNLKS7010Power; - info->Reset = UNLKS7010Reset; - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 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 + */ + +#include "mapinc.h" + +static uint8 preg[4], creg, mirr; + +static SFORMAT StateRegs[] = +{ + { preg, 4, "PREG" }, + { &creg, 1, "CREG" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x6000, preg[0]); + setprg8(0x8000, 0xa); + setprg8(0xa000, 0xb); + setprg8(0xc000, 0x6); + setprg8(0xe000, 0x7); + setchr8(0x0c); + setmirror(mirr); +} + +static DECLFW(UNLKS7010Write) { + switch (A) { + case 0x4025: mirr = (((V >> 3) & 1) ^ 1); Sync(); break; + default: + FCEU_printf("bs %04x %02x\n",A,V); + break; + } +} + +static void UNLKS7010Reset(void) { + preg[0]++; + if(preg[0] == 0x10) { + preg[0] = 0; + preg[1]++; + if(preg[1] == 0x10) { + preg[1] = 0; + preg[2]++; + } + } + FCEU_printf("preg %02x %02x %02x\n",preg[0], preg[1], preg[2]); + Sync(); +} + +static void UNLKS7010Power(void) { + preg[0] = preg[1] = preg[2] = 0; + Sync(); + SetReadHandler(0x6000, 0x7fff, CartBR); + SetWriteHandler(0x6000, 0x7fff, CartBW); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x4020, 0xffff, UNLKS7010Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void UNLKS7010_Init(CartInfo *info) { + info->Power = UNLKS7010Power; + info->Reset = UNLKS7010Reset; + + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/malee.cpp b/source/fceultra/boards/malee.cpp index ca369a7..9bf4fa6 100644 --- a/source/fceultra/boards/malee.cpp +++ b/source/fceultra/boards/malee.cpp @@ -35,6 +35,7 @@ static void MALEEPower(void) { void MALEE_Init(CartInfo *info) { info->Power = MALEEPower; + FCEU_MemoryRand(WRAM,sizeof(WRAM),true); SetupCartPRGMapping(0x10, WRAM, 2048, 1); AddExState(WRAM, 2048, 0, "WRAM"); } diff --git a/source/fceultra/boards/mihunche.cpp b/source/fceultra/boards/mihunche.cpp index c17478f..512aa0f 100644 --- a/source/fceultra/boards/mihunche.cpp +++ b/source/fceultra/boards/mihunche.cpp @@ -1,68 +1,68 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2013 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 - */ - -#include "mapinc.h" - -static uint16 latche; - -static SFORMAT StateRegs[] = -{ - { &latche, 2, "LATC" }, - { 0 } -}; - -static void Sync(void) { - setprg32(0x8000, 0); - if(CHRsize[0] == 8192) { - setchr4(0x0000, latche & 1); - setchr4(0x1000, latche & 1); - } else { - setchr8(latche & 1); // actually, my bad, overdumped roms, the real CHR size if 8K - } - setmirror(MI_0 + (latche & 1)); -} - -static DECLFW(UNLCC21Write1) { - latche = A; - Sync(); -} - -static DECLFW(UNLCC21Write2) { - latche = V; - Sync(); -} - -static void UNLCC21Power(void) { - latche = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8001, 0xFFFF, UNLCC21Write1); - SetWriteHandler(0x8000, 0x8000, UNLCC21Write2); // another one many-in-1 mapper, there is a lot of similar carts with little different wirings -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLCC21_Init(CartInfo *info) { - info->Power = UNLCC21Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2013 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 + */ + +#include "mapinc.h" + +static uint16 latche; + +static SFORMAT StateRegs[] = +{ + { &latche, 2, "LATC" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, 0); + if(CHRsize[0] == 8192) { + setchr4(0x0000, latche & 1); + setchr4(0x1000, latche & 1); + } else { + setchr8(latche & 1); // actually, my bad, overdumped roms, the real CHR size if 8K + } + setmirror(MI_0 + (latche & 1)); +} + +static DECLFW(UNLCC21Write1) { + latche = A; + Sync(); +} + +static DECLFW(UNLCC21Write2) { + latche = V; + Sync(); +} + +static void UNLCC21Power(void) { + latche = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8001, 0xFFFF, UNLCC21Write1); + SetWriteHandler(0x8000, 0x8000, UNLCC21Write2); // another one many-in-1 mapper, there is a lot of similar carts with little different wirings +} + +static void StateRestore(int version) { + Sync(); +} + +void UNLCC21_Init(CartInfo *info) { + info->Power = UNLCC21Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/mmc1.cpp b/source/fceultra/boards/mmc1.cpp index 4631d6c..bfe07a7 100644 --- a/source/fceultra/boards/mmc1.cpp +++ b/source/fceultra/boards/mmc1.cpp @@ -22,12 +22,13 @@ #include "mapinc.h" static void GenMMC1Power(void); -static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery); +static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram); static uint8 DRegs[4]; static uint8 Buffer, BufferShift; -static int mmc1opts; +static uint32 WRAMSIZE; +static uint32 NONBRAMSIZE; // size of non-battery-backed portion of WRAM static void (*MMC1CHRHook4)(uint32 A, uint8 V); static void (*MMC1PRGHook16)(uint32 A, uint8 V); @@ -48,9 +49,9 @@ static DECLFR(MAWRAM) { } static void MMC1CHR(void) { - if (mmc1opts & 4) { - if (DRegs[0] & 0x10) - setprg8r(0x10, 0x6000, (DRegs[1] >> 4) & 1); + if (WRAMSIZE > 0x2000) { + if (WRAMSIZE > 0x4000) + setprg8r(0x10, 0x6000, (DRegs[1] >> 2) & 3); else setprg8r(0x10, 0x6000, (DRegs[1] >> 3) & 1); } @@ -73,37 +74,38 @@ static void MMC1CHR(void) { } static void MMC1PRG(void) { - uint8 offs = DRegs[1] & 0x10; + uint8 offs_16banks = DRegs[1] & 0x10; + uint8 prg_reg = DRegs[3] & 0xF; //homebrewers arent allowed to use more banks on MMC1. use another mapper. if (MMC1PRGHook16) { switch (DRegs[0] & 0xC) { case 0xC: - MMC1PRGHook16(0x8000, (DRegs[3] + offs)); - MMC1PRGHook16(0xC000, 0xF + offs); + MMC1PRGHook16(0x8000, (prg_reg + offs_16banks)); + MMC1PRGHook16(0xC000, 0xF + offs_16banks); break; case 0x8: - MMC1PRGHook16(0xC000, (DRegs[3] + offs)); - MMC1PRGHook16(0x8000, offs); + MMC1PRGHook16(0xC000, (prg_reg + offs_16banks)); + MMC1PRGHook16(0x8000, offs_16banks); break; case 0x0: case 0x4: - MMC1PRGHook16(0x8000, ((DRegs[3] & ~1) + offs)); - MMC1PRGHook16(0xc000, ((DRegs[3] & ~1) + offs + 1)); + MMC1PRGHook16(0x8000, ((prg_reg & ~1) + offs_16banks)); + MMC1PRGHook16(0xc000, ((prg_reg & ~1) + offs_16banks + 1)); break; } } else { switch (DRegs[0] & 0xC) { case 0xC: - setprg16(0x8000, (DRegs[3] + offs)); - setprg16(0xC000, 0xF + offs); + setprg16(0x8000, (prg_reg + offs_16banks)); + setprg16(0xC000, 0xF + offs_16banks); break; case 0x8: - setprg16(0xC000, (DRegs[3] + offs)); - setprg16(0x8000, offs); + setprg16(0xC000, (prg_reg + offs_16banks)); + setprg16(0x8000, offs_16banks); break; case 0x0: case 0x4: - setprg16(0x8000, ((DRegs[3] & ~1) + offs)); - setprg16(0xc000, ((DRegs[3] & ~1) + offs + 1)); + setprg16(0x8000, ((prg_reg & ~1) + offs_16banks)); + setprg16(0xc000, ((prg_reg & ~1) + offs_16banks + 1)); break; } } @@ -178,20 +180,39 @@ static void MMC1CMReset(void) { MMC1PRG(); } -static int DetectMMC1WRAMSize(uint32 crc32) { - switch (crc32) { +static int DetectMMC1WRAMSize(CartInfo *info, int *bs) { + int ws = 8; + switch (info->CRC32) { case 0xc6182024: // Romance of the 3 Kingdoms + case 0xabbf7217: // "" "" (J) (PRG0) + case 0xccf35c02: // "" "" (J) (PRG1) case 0x2225c20f: // Genghis Khan + case 0xfb69743a: // "" "" (J) case 0x4642dda6: // Nobunaga's Ambition - case 0x29449ba9: // "" "" (J) - case 0x2b11e0b0: // "" "" (J) - case 0xb8747abf: // Best Play Pro Yakyuu Special (J) - case 0xc9556b36: // Final Fantasy I & II (J) [!] - FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n"); - return(16); + case 0x3f7ad415: // "" "" (J) (PRG0) + case 0x2b11e0b0: // "" "" (J) (PRG1) + *bs = 8; + ws = 16; break; - default: return(8); + case 0xb8747abf: // Best Play Pro Yakyuu Special (J) (PRG0) + case 0xc3de7c69: // "" "" (J) (PRG1) + case 0xc9556b36: // Final Fantasy I & II (J) [!] + *bs = 32; + ws = 32; + break; + default: + if(info->ines2) { + ws = (info->wram_size + info->battery_wram_size) / 1024; + *bs = info->battery_wram_size / 1024; + // we only support sizes between 8K and 32K + if (ws > 0 && ws < 8) ws = 8; + if (ws > 32) ws = 32; + if (*bs > ws) *bs = ws; + } } + if (ws > 8) + FCEU_printf(" >8KB external WRAM present. Use NES 2.0 if you hack the ROM image.\n"); + return ws; } static uint32 NWCIRQCount; @@ -243,17 +264,16 @@ void Mapper105_Init(CartInfo *info) { static void GenMMC1Power(void) { lreset = 0; - if (mmc1opts & 1) { - FCEU_CheatAddRAM(8, 0x6000, WRAM); - if (mmc1opts & 4) - FCEU_dwmemset(WRAM, 0, 8192) - else if (!(mmc1opts & 2)) - FCEU_dwmemset(WRAM, 0, 8192); // wtf? - } SetWriteHandler(0x8000, 0xFFFF, MMC1_write); SetReadHandler(0x8000, 0xFFFF, CartBR); - if (mmc1opts & 1) { + if (WRAMSIZE) { + FCEU_CheatAddRAM(8, 0x6000, WRAM); + + // clear non-battery-backed portion of WRAM + if (NONBRAMSIZE) + FCEU_MemoryRand(WRAM, NONBRAMSIZE, true); + SetReadHandler(0x6000, 0x7FFF, MAWRAM); SetWriteHandler(0x6000, 0x7FFF, MBWRAM); setprg8r(0x10, 0x6000, 0); @@ -270,31 +290,24 @@ static void GenMMC1Close(void) { CHRRAM = WRAM = NULL; } -static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery) { +static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram) { is155 = 0; info->Close = GenMMC1Close; MMC1PRGHook16 = MMC1CHRHook4 = 0; - mmc1opts = 0; + WRAMSIZE = wram * 1024; + NONBRAMSIZE = (wram - bram) * 1024; PRGmask16[0] &= (prg >> 14) - 1; CHRmask4[0] &= (chr >> 12) - 1; CHRmask8[0] &= (chr >> 13) - 1; - if (wram) { - WRAM = (uint8*)FCEU_gmalloc(wram * 1024); - //mbg 17-jun-08 - this shouldve been cleared to re-initialize save ram - //ch4 10-dec-08 - nope, this souldn't - //mbg 29-mar-09 - no time to debate this, we need to keep from breaking some old stuff. - //we really need to make up a policy for how compatibility and accuracy can be resolved. - memset(WRAM, 0, wram * 1024); - mmc1opts |= 1; - if (wram > 8) mmc1opts |= 4; - SetupCartPRGMapping(0x10, WRAM, wram * 1024, 1); - AddExState(WRAM, wram * 1024, 0, "WRAM"); - if (battery) { - mmc1opts |= 2; - info->SaveGame[0] = WRAM + ((mmc1opts & 4) ? 8192 : 0); - info->SaveGameLen[0] = 8192; + if (WRAMSIZE) { + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (bram) { + info->SaveGame[0] = WRAM + NONBRAMSIZE; + info->SaveGameLen[0] = bram * 1024; } } if (!chr) { @@ -312,13 +325,14 @@ static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery) } void Mapper1_Init(CartInfo *info) { - int ws = DetectMMC1WRAMSize(info->CRC32); - GenMMC1Init(info, 512, 256, ws, info->battery); + int bs = info->battery ? 8 : 0; + int ws = DetectMMC1WRAMSize(info, &bs); + GenMMC1Init(info, 512, 256, ws, bs); } /* Same as mapper 1, without respect for WRAM enable bit. */ void Mapper155_Init(CartInfo *info) { - GenMMC1Init(info, 512, 256, 8, info->battery); + GenMMC1Init(info, 512, 256, 8, info->battery ? 8 : 0); is155 = 1; } @@ -330,7 +344,7 @@ void Mapper171_Init(CartInfo *info) { } void SAROM_Init(CartInfo *info) { - GenMMC1Init(info, 128, 64, 8, info->battery); + GenMMC1Init(info, 128, 64, 8, info->battery ? 8 : 0); } void SBROM_Init(CartInfo *info) { @@ -350,7 +364,7 @@ void SGROM_Init(CartInfo *info) { } void SKROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 64, 8, info->battery); + GenMMC1Init(info, 256, 64, 8, info->battery ? 8 : 0); } void SLROM_Init(CartInfo *info) { @@ -382,11 +396,9 @@ void SHROM_Init(CartInfo *info) { /* */ void SNROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 0, 8, info->battery); + GenMMC1Init(info, 256, 0, 8, info->battery ? 8 : 0); } void SOROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 0, 16, info->battery); + GenMMC1Init(info, 256, 0, 16, info->battery ? 8 : 0); } - - diff --git a/source/fceultra/boards/mmc3.cpp b/source/fceultra/boards/mmc3.cpp index ebd2db4..6a93ba9 100644 --- a/source/fceultra/boards/mmc3.cpp +++ b/source/fceultra/boards/mmc3.cpp @@ -279,11 +279,11 @@ void GenMMC3Power(void) { setprg8r(0x10, 0x6000, 0); } if (!(mmc3opts & 2)) - FCEU_dwmemset(WRAM, 0, WRAMSIZE); + FCEU_MemoryRand(WRAM, WRAMSIZE, true); } MMC3RegReset(); if (CHRRAM) - FCEU_dwmemset(CHRRAM, 0, CHRRAMSIZE); + FCEU_MemoryRand(CHRRAM, CHRRAMSIZE, true); } static void GenMMC3Close(void) { @@ -498,13 +498,18 @@ static void M45CW(uint32 A, uint8 V) { NV &= 0; // hack ;( don't know exactly how it should be NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4); setchr1(A, NV); - } + } else +// setchr8(0); // i don't know what cart need this, but a new one need other lol + setchr1(A, V); } static void M45PW(uint32 A, uint8 V) { - V &= (EXPREGS[3] & 0x3F) ^ 0x3F; - V |= EXPREGS[1]; - setprg8(A, V); + uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F); + MV |= EXPREGS[1]; + if(UNIFchrrama) + MV |= ((EXPREGS[2] & 0x40) << 2); + setprg8(A, MV); +// FCEU_printf("1:%02x 2:%02x 3:%02x A=%04x V=%03x\n",EXPREGS[1],EXPREGS[2],EXPREGS[3],A,MV); } static DECLFW(M45Write) { @@ -534,7 +539,6 @@ static void M45Reset(void) { } static void M45Power(void) { - setchr8(0); GenMMC3Power(); EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0; SetWriteHandler(0x5000, 0x7FFF, M45Write); @@ -1039,8 +1043,8 @@ static DECLFW(Mapper196Write) { } static DECLFW(Mapper196WriteLo) { - EXPREGS[0] = 1; - EXPREGS[1] = (V & 0xf) | (V >> 4); + EXPREGS[0] = 1; // hacky + EXPREGS[1] = (V & 0xf) | (V >> 4); // this is the same as 189 mapper, but with addr permutations FixMMC3PRG(MMC3_cmd); } diff --git a/source/fceultra/boards/mmc5.cpp b/source/fceultra/boards/mmc5.cpp index dcb32e4..e11ca08 100644 --- a/source/fceultra/boards/mmc5.cpp +++ b/source/fceultra/boards/mmc5.cpp @@ -22,6 +22,13 @@ #include "mapinc.h" +#define ABANKS MMC5SPRVPage +#define BBANKS MMC5BGVPage +#define SpriteON (PPU[1] & 0x10) //Show Sprite +#define ScreenON (PPU[1] & 0x08) //Show screen +#define PPUON (PPU[1] & 0x18) //PPU should operate +#define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8 + static void (*sfun)(int P); static void (*psfun)(void); @@ -107,15 +114,33 @@ typedef struct __cartdata { uint8 size; } cartdata; -#define Sprite16 (PPU[0]& 0x20) //Sprites 8x16/8x8 -//#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)] -static inline uint8 * MMC5BGVRAMADR(uint32 A) { +#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)] + +uint8* MMC5BGVRAMADR(uint32 A) +{ + if(newppu) + { + if(Sprite16) + { + bool isPattern = PPUON != 0; + if (ppuphase == PPUPHASE_OBJ && isPattern) + return &ABANKS[(A) >> 10][(A)]; + if (ppuphase == PPUPHASE_BG && isPattern) + return &BBANKS[(A) >> 10][(A)]; + else if(mmc5ABMode == 0) + return &ABANKS[(A) >> 10][(A)]; + else + return &BBANKS[(A) >> 10][(A)]; + } + else return &ABANKS[(A) >> 10][(A)];; + } + if (!Sprite16) { if (mmc5ABMode == 0) - return &MMC5SPRVPage[(A) >> 10][(A)]; + return &ABANKS[(A) >> 10][(A)]; else - return &MMC5BGVPage[(A) >> 10][(A)]; - } else return &MMC5BGVPage[(A) >> 10][(A)]; + return &BBANKS[(A) >> 10][(A)]; + } else return &BBANKS[(A) >> 10][(A)]; } static void mmc5_PPUWrite(uint32 A, uint8 V) { @@ -136,16 +161,105 @@ static void mmc5_PPUWrite(uint32 A, uint8 V) { } } -uint8 FASTCALL mmc5_PPURead(uint32 A) { - if (A < 0x2000) { - if (ppuphase == PPUPHASE_BG - //zero 03-aug-2014 - added this to fix Uchuu Keibitai SDF. The game reads NT entries from CHR rom while PPU is disabled. - //obviously we have enormous numbers of bugs springing from our terrible emulation of ppu-disabled states, but this does the job for fixing this one - && (PPU[1] & 0x10) - ) - return *MMC5BGVRAMADR(A); - else return MMC5SPRVPage[(A) >> 10][(A)]; - } else { +extern uint32 NTRefreshAddr; +uint8 FASTCALL mmc5_PPURead(uint32 A) +{ + bool split = false; + if(newppu) + { + if((MMC5HackSPMode&0x80) && !(MMC5HackCHRMode&2)) + { + int target = MMC5HackSPMode&0x1f; + int side = MMC5HackSPMode&0x40; + int ht = NTRefreshAddr&31; + + if(side==0) + { + if(ht=target) split = true; + } + } + } + + if (A < 0x2000) + { + if(Sprite16) + { + bool isPattern = !!PPUON; + if (ppuphase == PPUPHASE_OBJ && isPattern) + return ABANKS[(A) >> 10][(A)]; + if (ppuphase == PPUPHASE_BG && isPattern) + { + if(split) + return MMC5HackVROMPTR[MMC5HackSPPage*0x1000 + (A&0xFFF)]; + + //uhhh call through to this more sophisticated function, only if it's really needed? + //we should probably reuse it completely, if we can + if (MMC5HackCHRMode == 1) + return *FCEUPPU_GetCHR(A,NTRefreshAddr); + + return BBANKS[(A) >> 10][(A)]; + } + else if(mmc5ABMode == 0) + return ABANKS[(A) >> 10][(A)]; + else + return BBANKS[(A) >> 10][(A)]; + } + else + { + if (ppuphase == PPUPHASE_BG && ScreenON) + { + if(split) + return MMC5HackVROMPTR[MMC5HackSPPage*0x1000 + (A&0xFFF)]; + + //uhhh call through to this more sophisticated function, only if it's really needed? + //we should probably reuse it completely, if we can + if (MMC5HackCHRMode == 1) + return *FCEUPPU_GetCHR(A,NTRefreshAddr); + } + + return ABANKS[(A) >> 10][(A)]; + } + } + else + { + if(split) + { + static const int kHack = -1; //dunno if theres science to this or if it just fixes SDF (cant be bothered to think about it) + int linetile = (newppu_get_scanline()+kHack)/8 + MMC5HackSPScroll; + + //REF NT: return 0x2000 | (v << 0xB) | (h << 0xA) | (vt << 5) | ht; + //REF AT: return 0x2000 | (v << 0xB) | (h << 0xA) | 0x3C0 | ((vt & 0x1C) << 1) | ((ht & 0x1C) >> 2); + + if((A&0x3FF)>=0x3C0) + { + A &= ~(0x1C<<1); //mask off VT + A |= (linetile&0x1C)<<1; //mask on adjusted VT + return ExRAM[A & 0x3FF]; + } + else + { + A &= ~((0x1F<<5) | (1<<0xB)); //mask off VT and V + A |= (linetile&31)<<5; //mask on adjusted VT (V doesnt make any sense, I think) + return ExRAM[A & 0x3FF]; + } + } + + if (MMC5HackCHRMode == 1) + { + if((A&0x3FF)>=0x3C0) + { + uint8 byte = ExRAM[NTRefreshAddr & 0x3ff]; + //get attribute part and paste it 4x across the byte + byte >>= 6; + byte *= 0x55; + return byte; + } + } + return vnapage[(A >> 10) & 0x3][A & 0x3FF]; } } @@ -844,6 +958,12 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { MMC5fill = (uint8*)FCEU_gmalloc(1024); ExRAM = (uint8*)FCEU_gmalloc(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); + AddExState(ExRAM, 1024, 0, "ERAM"); AddExState(&MMC5HackSPMode, 1, 0, "SPLM"); AddExState(&MMC5HackSPScroll, 1, 0, "SPLS"); @@ -858,8 +978,13 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int 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; else info->SaveGameLen[0] = 32768; } diff --git a/source/fceultra/boards/n106.cpp b/source/fceultra/boards/n106.cpp index 71e189b..76c9340 100644 --- a/source/fceultra/boards/n106.cpp +++ b/source/fceultra/boards/n106.cpp @@ -57,9 +57,23 @@ static SFORMAT N106_StateRegs[] = { { PRG, 3, "PRG" }, { CHR, 8, "CHR" }, { NTAPage, 4, "NTA" }, + { &gorfus, 1, "GORF" }, + { &dopol, 1, "DOPO" }, + { &gorko, 1, "GORK" }, { 0 } }; +static void SyncMirror() +{ + switch(gorko) { + case 0: setmirror(MI_0); break; + case 1: setmirror(MI_V); break; + case 2: setmirror(MI_H); break; + case 3: setmirror(MI_0); break; + } + +} + static void SyncPRG(void) { setprg8(0x8000, PRG[0]); setprg8(0xa000, PRG[1]); @@ -179,8 +193,11 @@ static DECLFW(Mapper19_write) { X6502_IRQEnd(FCEU_IQEXT); break; case 0xE000: - gorko = V & 0xC0; PRG[0] = V & 0x3F; + if(is210) { + gorko = V>>6; + SyncMirror(); + } SyncPRG(); break; case 0xE800: @@ -333,6 +350,7 @@ static void Mapper19_StateRestore(int version) { SyncPRG(); FixNTAR(); FixCRR(); + SyncMirror(); int x; for (x = 0x40; x < 0x80; x++) FixCache(x, IRAM[x]); @@ -382,8 +400,8 @@ static void N106_Power(void) { FixCRR(); if (!battery) { - FCEU_dwmemset(WRAM, 0, 8192); - FCEU_dwmemset(IRAM, 0, 128); + FCEU_MemoryRand(WRAM, sizeof(WRAM), true); + FCEU_MemoryRand(IRAM, sizeof(IRAM), true); } for (x = 0x40; x < 0x80; x++) FixCache(x, IRAM[x]); @@ -401,6 +419,8 @@ void Mapper19_Init(CartInfo *info) { if (FSettings.SndRate) Mapper19_ESI(); + FCEU_MemoryRand(WRAM, sizeof(WRAM), true); + FCEU_MemoryRand(IRAM, sizeof(IRAM), true); AddExState(WRAM, 8192, 0, "WRAM"); AddExState(IRAM, 128, 0, "IRAM"); AddExState(N106_StateRegs, ~0, 0, 0); @@ -422,6 +442,7 @@ void Mapper210_Init(CartInfo *info) { is210 = 1; GameStateRestore = Mapper210_StateRestore; info->Power = N106_Power; + FCEU_MemoryRand(WRAM, sizeof(WRAM), true); AddExState(WRAM, 8192, 0, "WRAM"); AddExState(N106_StateRegs, ~0, 0, 0); } diff --git a/source/fceultra/boards/onebus.cpp b/source/fceultra/boards/onebus.cpp index 8b92fb2..7cd23d7 100644 --- a/source/fceultra/boards/onebus.cpp +++ b/source/fceultra/boards/onebus.cpp @@ -113,7 +113,7 @@ static void CSync(void) { setchr1(0x1800 ^ cswap, block | (bank6 & mask)); setchr1(0x1c00 ^ cswap, block | (bank7 & mask)); - setmirror(mirror & 1); + setmirror((mirror ^ 1) & 1); } static void Sync(void) { @@ -158,7 +158,7 @@ static DECLFW(UNLOneBusWriteMMC3) { } break; } - case 0xa000: mirror = V ^ 1; CSync(); break; + case 0xa000: mirror = V; CSync(); break; case 0xc000: IRQLatch = V & 0xfe; break; case 0xc001: IRQReload = 1; break; case 0xe000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break; diff --git a/source/fceultra/boards/sb-2000.cpp b/source/fceultra/boards/sb-2000.cpp index 6a60b3f..c2ea454 100644 --- a/source/fceultra/boards/sb-2000.cpp +++ b/source/fceultra/boards/sb-2000.cpp @@ -1,195 +1,195 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2014 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 - */ - -#include "mapinc.h" - -static uint8 preg[8]; -static uint8 IRQa; -static int16 IRQCount, IRQLatch; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -/* -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; -*/ - -static SFORMAT StateRegs[] = -{ - { preg, 8, "PREG" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, - { 0 } -}; - -static void Sync(void) { - setchr8(0); - setprg8r(0x10, 0x6000, 0); - if(preg[0] & 0x80) - setprg4r(0x10,0x8000,preg[0] & 0x7f); - else - setprg4(0x8000,preg[0] & 0x7f); - if(preg[1] & 0x80) - setprg4r(0x10,0x9000,preg[1] & 0x7f); - else - setprg4(0x9000,preg[1] & 0x7f); - if(preg[2] & 0x80) - setprg4r(0x10,0xa000,preg[2] & 0x7f); - else - setprg4(0xa000,preg[2] & 0x7f); - if(preg[3] & 0x80) - setprg4r(0x10,0xb000,preg[3] & 0x7f); - else - setprg4(0xb000,preg[3] & 0x7f); -/* - if(preg[4] & 0x80) - setprg4r(0x10,0xc000,preg[4] & 0x7f); - else - setprg4(0xc000,preg[4] & 0x7f); - if(preg[5] & 0x80) - setprg4r(0x10,0xd000,preg[5] & 0x7f); - else - setprg4(0xd000,preg[5] & 0x7f); - if(preg[6] & 0x80) - setprg4r(0x10,0xe000,preg[6] & 0x7f); - else - setprg4(0xe000,preg[6] & 0x7f); - if(preg[7] & 0x80) - setprg4r(0x10,0xf000,preg[7] & 0x7f); - else - setprg4(0xf000,preg[7] & 0x7f); -*/ - setprg16(0xC000,1); -} - -static DECLFR(UNLSB2000Read) { - switch(A) { - case 0x4033: // IRQ flags - X6502_IRQEnd(FCEU_IQFCOUNT); - return 0xff; -// case 0x4204: // unk -// return 0xff; -// case 0x4205: // unk -// return 0xff; - default: - FCEU_printf("unk read: %04x\n",A); -// break; - return 0xff; // needed to prevent C4715 warning? - } -} - -static DECLFW(UNLSB2000Write) { - switch(A) { - case 0x4027: // PCM output - BWrite[0x4015](0x4015, 0x10); - BWrite[0x4011](0x4011, V >> 1); - break; - case 0x4032: // IRQ mask - IRQa &= ~V; -// X6502_IRQEnd(FCEU_IQEXT); - break; - case 0x4040: - case 0x4041: - case 0x4042: - case 0x4043: - case 0x4044: - case 0x4045: - case 0x4046: - case 0x4047: -// FCEU_printf("bank write: %04x:%02x\n",A,V); - preg[A&7] = V; - Sync(); - break; - default: -// FCEU_printf("unk write: %04x:%02x\n",A,V); - break; - } -} - -static void UNLSB2000Reset(void) { - preg[0] = 0; - preg[1] = 1; - preg[2] = 2; - preg[3] = 3; - preg[4] = 4; - preg[5] = 5; - preg[6] = 6; - preg[7] = 7; - IRQa = 0; -// BWrite[0x4017](0x4017,0xC0); -// BWrite[0x4015](0x4015,0x1F); -} - -static void UNLSB2000Power(void) { - UNLSB2000Reset(); - Sync(); - SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetReadHandler(0x8000, 0xffff, CartBR); - SetWriteHandler(0x8000, 0xbfff, CartBW); - SetWriteHandler(0x4020, 0x5fff, UNLSB2000Write); - SetReadHandler(0x4020, 0x5fff, UNLSB2000Read); -} - -static void UNLSB2000Close(void) -{ - if (WRAM) - FCEU_gfree(WRAM); -/* - if (CHRRAM) - FCEU_gfree(CHRRAM); -*/ - WRAM = /*CHRRAM = */NULL; -} -/* -static void UNLSB2000IRQHook() { - X6502_IRQBegin(FCEU_IQEXT); -} -*/ -static void StateRestore(int version) { - Sync(); -} - -void UNLSB2000_Init(CartInfo *info) { - info->Reset = UNLSB2000Reset; - info->Power = UNLSB2000Power; - info->Close = UNLSB2000Close; -// GameHBIRQHook = UNLSB2000IRQHook; - GameStateRestore = StateRestore; -/* - CHRRAMSIZE = 8192; - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); -*/ - -// SetupCartCHRMapping(0, PRGptr[0], PRGsize[0], 0); - - WRAMSIZE = 512 * 1024; - 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; - } - - AddExState(&StateRegs, ~0, 0, 0); -} +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2014 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 + */ + +#include "mapinc.h" + +static uint8 preg[8]; +static uint8 IRQa; +static int16 IRQCount, IRQLatch; +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; +/* +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; +*/ + +static SFORMAT StateRegs[] = +{ + { preg, 8, "PREG" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { &IRQLatch, 2, "IRQL" }, + { 0 } +}; + +static void Sync(void) { + setchr8(0); + setprg8r(0x10, 0x6000, 0); + if(preg[0] & 0x80) + setprg4r(0x10,0x8000,preg[0] & 0x7f); + else + setprg4(0x8000,preg[0] & 0x7f); + if(preg[1] & 0x80) + setprg4r(0x10,0x9000,preg[1] & 0x7f); + else + setprg4(0x9000,preg[1] & 0x7f); + if(preg[2] & 0x80) + setprg4r(0x10,0xa000,preg[2] & 0x7f); + else + setprg4(0xa000,preg[2] & 0x7f); + if(preg[3] & 0x80) + setprg4r(0x10,0xb000,preg[3] & 0x7f); + else + setprg4(0xb000,preg[3] & 0x7f); +/* + if(preg[4] & 0x80) + setprg4r(0x10,0xc000,preg[4] & 0x7f); + else + setprg4(0xc000,preg[4] & 0x7f); + if(preg[5] & 0x80) + setprg4r(0x10,0xd000,preg[5] & 0x7f); + else + setprg4(0xd000,preg[5] & 0x7f); + if(preg[6] & 0x80) + setprg4r(0x10,0xe000,preg[6] & 0x7f); + else + setprg4(0xe000,preg[6] & 0x7f); + if(preg[7] & 0x80) + setprg4r(0x10,0xf000,preg[7] & 0x7f); + else + setprg4(0xf000,preg[7] & 0x7f); +*/ + setprg16(0xC000,1); +} + +static DECLFR(UNLSB2000Read) { + switch(A) { + case 0x4033: // IRQ flags + X6502_IRQEnd(FCEU_IQFCOUNT); + return 0xff; +// case 0x4204: // unk +// return 0xff; +// case 0x4205: // unk +// return 0xff; + default: + FCEU_printf("unk read: %04x\n",A); +// break; + return 0xff; // needed to prevent C4715 warning? + } +} + +static DECLFW(UNLSB2000Write) { + switch(A) { + case 0x4027: // PCM output + BWrite[0x4015](0x4015, 0x10); + BWrite[0x4011](0x4011, V >> 1); + break; + case 0x4032: // IRQ mask + IRQa &= ~V; +// X6502_IRQEnd(FCEU_IQEXT); + break; + case 0x4040: + case 0x4041: + case 0x4042: + case 0x4043: + case 0x4044: + case 0x4045: + case 0x4046: + case 0x4047: +// FCEU_printf("bank write: %04x:%02x\n",A,V); + preg[A&7] = V; + Sync(); + break; + default: +// FCEU_printf("unk write: %04x:%02x\n",A,V); + break; + } +} + +static void UNLSB2000Reset(void) { + preg[0] = 0; + preg[1] = 1; + preg[2] = 2; + preg[3] = 3; + preg[4] = 4; + preg[5] = 5; + preg[6] = 6; + preg[7] = 7; + IRQa = 0; +// BWrite[0x4017](0x4017,0xC0); +// BWrite[0x4015](0x4015,0x1F); +} + +static void UNLSB2000Power(void) { + UNLSB2000Reset(); + Sync(); + SetReadHandler(0x6000, 0x7fff, CartBR); + SetWriteHandler(0x6000, 0x7fff, CartBW); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x8000, 0xbfff, CartBW); + SetWriteHandler(0x4020, 0x5fff, UNLSB2000Write); + SetReadHandler(0x4020, 0x5fff, UNLSB2000Read); +} + +static void UNLSB2000Close(void) +{ + if (WRAM) + FCEU_gfree(WRAM); +/* + if (CHRRAM) + FCEU_gfree(CHRRAM); +*/ + WRAM = /*CHRRAM = */NULL; +} +/* +static void UNLSB2000IRQHook() { + X6502_IRQBegin(FCEU_IQEXT); +} +*/ +static void StateRestore(int version) { + Sync(); +} + +void UNLSB2000_Init(CartInfo *info) { + info->Reset = UNLSB2000Reset; + info->Power = UNLSB2000Power; + info->Close = UNLSB2000Close; +// GameHBIRQHook = UNLSB2000IRQHook; + GameStateRestore = StateRestore; +/* + CHRRAMSIZE = 8192; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); +*/ + +// SetupCartCHRMapping(0, PRGptr[0], PRGsize[0], 0); + + WRAMSIZE = 512 * 1024; + 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; + } + + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/source/fceultra/boards/unrom512.cpp b/source/fceultra/boards/unrom512.cpp index a52e0e6..ac6bd57 100644 --- a/source/fceultra/boards/unrom512.cpp +++ b/source/fceultra/boards/unrom512.cpp @@ -1,52 +1,52 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2014 CaitSith2 - * - * 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 - */ - -/* - * Roms still using NES 1.0 format should be loaded as 32K CHR RAM. - * Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present. - * UNIF doesn't have this problem, because unique board names can define this information. - * The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K - * - * The battery flag in the NES header enables flash, Mirrror mode 2 Enables MI_0 and MI_1 mode. - * Known games to use this board are: - * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled) - * Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled) - * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space), - * it otherwise functions identically. -*/ - -#include "mapinc.h" -#include "../ines.h" - -static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false; -static uint16 latcha; -static uint8 *flashdata; -static uint32 *flash_write_count; -static uint8 *FlashPage[32]; -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); - +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2014 CaitSith2 + * + * 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 + */ + +/* + * Roms still using NES 1.0 format should be loaded as 32K CHR RAM. + * Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present. + * UNIF doesn't have this problem, because unique board names can define this information. + * The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K + * + * The battery flag in the NES header enables flash, Mirrror mode 2 Enables MI_0 and MI_1 mode. + * Known games to use this board are: + * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled) + * Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled) + * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space), + * it otherwise functions identically. +*/ + +#include "mapinc.h" +#include "../ines.h" + +static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false; +static uint16 latcha; +static uint8 *flashdata; +static uint32 *flash_write_count; +static uint8 *FlashPage[32]; +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; @@ -59,8 +59,8 @@ static INLINE void setfpageptr(int s, uint32 A, uint8 *p) { 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]; @@ -72,198 +72,214 @@ void setfprg16(uint32 A, uint32 V) { 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) -{ - flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; - if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)]) - flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; -} - -uint32 GetFlashWriteCount(uint8 bank, uint32 A) -{ - return flash_write_count[(bank*4) + ((A&0x3000)>>12)]; -} - -static void StateRestore(int version) { - WHSync(); -} - -static DECLFW(UNROM512LLatchWrite) -{ - latche = V; - latcha = A; - WLSync(); -} - -static DECLFW(UNROM512HLatchWrite) -{ - if (bus_conflict) - latche = (V == CartBR(A)) ? V : 0; - else - latche = V; - latcha = A; - WHSync(); -} - -static DECLFR(UNROM512LatchRead) -{ - uint8 flash_id[3]={0xB5,0xB6,0xB7}; - if(software_id) - { - if(A&1) - return flash_id[ROM_size>>4]; - else - return 0xBF; - } - if(flash_save) - { - if(A < 0xC000) - { - if(GetFlashWriteCount(flash_bank,A)) - return FlashPage[A >> 11][A]; - } - else - { - if(GetFlashWriteCount(ROM_size-1,A)) - return FlashPage[A >> 11][A]; - } - } - return Page[A >> 11][A]; -} - -static void UNROM512LatchPower(void) { - latche = latcheinit; - WHSync(); - SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead); - if(!flash_save) - SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite); - else - { - SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite); - SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite); - } -} - -static void UNROM512LatchClose(void) { - if(flash_write_count) - FCEU_gfree(flash_write_count); - if(flashdata) - FCEU_gfree(flashdata); - flash_write_count = NULL; - flashdata = NULL; -} - - -static void UNROM512LSync() { - int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA}; - int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55}; - int erase_b[5]={1,0,1,1,0}; - - if(flash_mode==0) - { - if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state])) - { - flash_state++; - if(flash_state == 5) - { - flash_mode=1; - } - } - else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1)) - { - flash_state++; - flash_mode=2; - } - else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1)) - { - flash_state=0; - software_id=true; - } - else - { - if(latche==0xF0) - software_id=false; - flash_state=0; - } - } - else if(flash_mode==1) //Chip Erase or Sector Erase - { - if(latche==0x30) - { - inc_flash_write_count(flash_bank,latcha); - memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000); - } - else if (latche==0x10) - { - for(int i=0;i<(ROM_size*4);i++) - inc_flash_write_count(i>>2,i<<12); - memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :) - } - flash_state=0; - flash_mode=0; - } - else if(flash_mode==2) //Byte Program - { - if(!GetFlashWriteCount(flash_bank,latcha)) - { - inc_flash_write_count(flash_bank,latcha); - memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000); - } - FlashPage[latcha>>11][latcha]&=latche; - flash_state=0; - flash_mode=0; - } -} - -static void UNROM512HSync() -{ - flash_bank=latche&(ROM_size-1); - - setprg16(0x8000, flash_bank); - setprg16(0xc000, ~0); - setfprg16(0x8000, flash_bank); - setfprg16(0xC000, ~0); - setchr8r(0, (latche & chrram_mask) >> 5); - setmirror(MI_0+(latche>>7)); -} - -void UNROM512_Init(CartInfo *info) { - flash_state=0; - flash_bank=0; - flash_save=info->battery; - - if(info->vram_size == 8192) - chrram_mask = 0; - else if (info->vram_size == 16384) - chrram_mask = 0x20; - else - chrram_mask = 0x60; - - SetupCartMirroring(info->mirror,(info->mirror>=MI_0)?0:1,0); - bus_conflict = !info->battery; - latcheinit = 0; - WLSync = UNROM512LSync; - WHSync = UNROM512HSync; - info->Power = UNROM512LatchPower; - info->Close = UNROM512LatchClose; - GameStateRestore = StateRestore; - if(flash_save) - { - flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000); - flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32)); - info->SaveGame[0] = (uint8*)flash_write_count; - info->SaveGame[1] = flashdata; - info->SaveGameLen[0] = ROM_size*4*sizeof(uint32); - info->SaveGameLen[1] = ROM_size*0x4000; - AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT"); - AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA"); - AddExState(&flash_state,1,0,"FLASH_STATE"); - AddExState(&flash_mode,1,0,"FLASH_MODE"); - AddExState(&flash_bank,1,0,"FLASH_BANK"); - AddExState(&latcha,2,0,"LATA"); - } - AddExState(&latche, 1, 0, "LATC"); - AddExState(&bus_conflict, 1, 0, "BUSC"); +} + +void inc_flash_write_count(uint8 bank, uint32 A) +{ + flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; + if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)]) + flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; +} + +uint32 GetFlashWriteCount(uint8 bank, uint32 A) +{ + return flash_write_count[(bank*4) + ((A&0x3000)>>12)]; +} + +static void StateRestore(int version) { + WHSync(); +} + +static DECLFW(UNROM512LLatchWrite) +{ + latche = V; + latcha = A; + WLSync(); +} + +static DECLFW(UNROM512HLatchWrite) +{ + if (bus_conflict) + latche = (V == CartBR(A)) ? V : 0; + else + latche = V; + latcha = A; + WHSync(); +} + +static DECLFR(UNROM512LatchRead) +{ + uint8 flash_id[3]={0xB5,0xB6,0xB7}; + if(software_id) + { + if(A&1) + return flash_id[ROM_size>>4]; + else + return 0xBF; + } + if(flash_save) + { + if(A < 0xC000) + { + if(GetFlashWriteCount(flash_bank,A)) + return FlashPage[A >> 11][A]; + } + else + { + if(GetFlashWriteCount(ROM_size-1,A)) + return FlashPage[A >> 11][A]; + } + } + return Page[A >> 11][A]; +} + +static void UNROM512LatchPower(void) { + latche = latcheinit; + WHSync(); + SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead); + if(!flash_save) + SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite); + else + { + SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite); + SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite); + } +} + +static void UNROM512LatchClose(void) { + if(flash_write_count) + FCEU_gfree(flash_write_count); + if(flashdata) + FCEU_gfree(flashdata); + flash_write_count = NULL; + flashdata = NULL; +} + + +static void UNROM512LSync() { + int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA}; + int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55}; + int erase_b[5]={1,0,1,1,0}; + + if(flash_mode==0) + { + if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state])) + { + flash_state++; + if(flash_state == 5) + { + flash_mode=1; + } + } + else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1)) + { + flash_state++; + flash_mode=2; + } + else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1)) + { + flash_state=0; + software_id=true; + } + else + { + if(latche==0xF0) + software_id=false; + flash_state=0; + } + } + else if(flash_mode==1) //Chip Erase or Sector Erase + { + if(latche==0x30) + { + inc_flash_write_count(flash_bank,latcha); + memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000); + } + else if (latche==0x10) + { + for(uint32 i=0;i<(ROM_size*4);i++) + inc_flash_write_count(i>>2,i<<12); + memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :) + } + flash_state=0; + flash_mode=0; + } + else if(flash_mode==2) //Byte Program + { + if(!GetFlashWriteCount(flash_bank,latcha)) + { + inc_flash_write_count(flash_bank,latcha); + memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000); + } + FlashPage[latcha>>11][latcha]&=latche; + flash_state=0; + flash_mode=0; + } +} + +static void UNROM512HSync() +{ + flash_bank=latche&(ROM_size-1); + + setprg16(0x8000, flash_bank); + setprg16(0xc000, ~0); + setfprg16(0x8000, flash_bank); + setfprg16(0xC000, ~0); + setchr8r(0, (latche & chrram_mask) >> 5); + setmirror(MI_0+(latche>>7)); +} + +void UNROM512_Init(CartInfo *info) { + flash_state=0; + flash_bank=0; + flash_save=info->battery; + + if(info->vram_size == 8192) + chrram_mask = 0; + else if (info->vram_size == 16384) + chrram_mask = 0x20; + else + chrram_mask = 0x60; + + int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2); + switch (mirror) + { + case 0: // hard horizontal, internal + SetupCartMirroring(MI_H, 1, NULL); + break; + case 1: // hard vertical, internal + SetupCartMirroring(MI_V, 1, NULL); + break; + case 2: // switchable 1-screen, internal (flags: 4-screen + horizontal) + SetupCartMirroring(MI_0, 0, NULL); + break; + case 3: // hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical) + SetupCartMirroring( 4, 1, VROM + (info->vram_size - 8192)); + break; + } + + bus_conflict = !info->battery; + latcheinit = 0; + WLSync = UNROM512LSync; + WHSync = UNROM512HSync; + info->Power = UNROM512LatchPower; + info->Close = UNROM512LatchClose; + GameStateRestore = StateRestore; + if(flash_save) + { + flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000); + flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32)); + info->SaveGame[0] = (uint8*)flash_write_count; + info->SaveGame[1] = flashdata; + info->SaveGameLen[0] = ROM_size*4*sizeof(uint32); + info->SaveGameLen[1] = ROM_size*0x4000; + AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT"); + AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA"); + AddExState(&flash_state,1,0,"FLASH_STATE"); + AddExState(&flash_mode,1,0,"FLASH_MODE"); + AddExState(&flash_bank,1,0,"FLASH_BANK"); + AddExState(&latcha,2,0,"LATA"); + } + 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 571e4a8..7b68fbe 100644 --- a/source/fceultra/boards/vrc2and4.cpp +++ b/source/fceultra/boards/vrc2and4.cpp @@ -20,7 +20,8 @@ #include "mapinc.h" -static uint8 isPirate, is22; +static bool isPirate; +static uint8 is22, reg1mask, reg2mask; static uint16 IRQCount; static uint8 IRQLatch, IRQa; static uint8 prgreg[2], chrreg[8]; @@ -61,15 +62,15 @@ static void Sync(void) { setchr8(0); else{ uint8 i; - if(!weirdo) + //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--; - } + //else { + // setchr1(0x0000, 0xFC); + // setchr1(0x0400, 0xFD); + // setchr1(0x0800, 0xFF); + // weirdo--; + //} } switch (mirr & 0x3) { case 0: setmirror(MI_V); break; @@ -80,7 +81,7 @@ static void Sync(void) { } static DECLFW(VRC24Write) { - A &= 0xF003; + A = A & 0xF000 | !!(A & reg2mask) << 1 | !!(A & reg1mask); if ((A >= 0xB000) && (A <= 0xE003)) { if (UNIFchrrama) big_bank = (V & 8) << 2; // my personally many-in-one feature ;) just for support pirate cart 2-in-1 @@ -126,61 +127,17 @@ static DECLFW(VRC24Write) { } } -static DECLFW(M21Write) { - A = (A & 0xF000) | ((A >> 1) & 0x3); // Ganbare Goemon Gaiden 2 - Tenka no Zaihou (J) [!] isn't mapper 21 actually, - // it's mapper 23 by wirings - VRC24Write(A, V); -} - -static DECLFW(M22Write) { - if (A == 0xC007) { // Ganbare Goemon Gaiden does strange things!!! at the end credits - weirdo = 8; // quick dirty hack, seems there is no other games with such PCB, so - // we never know if it will not work for something else lol +static void VRC24Power(void) { + big_bank = 0x20; + Sync(); + if (WRAM) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } - A |= ((A >> 2) & 0x3); // It's just swapped lines from 21 mapper - // - VRC24Write((A & 0xF000) | ((A >> 1) & 1) | ((A << 1) & 2), V); -} - -static DECLFW(M23Write) { - A |= ((A >> 2) & 0x3) | ((A >> 4) & 0x3) | ((A >> 6) & 0x3);// actually there is many-in-one mapper source, some pirate or - // licensed games use various address bits for registers - VRC24Write(A, V); -} - -static void M21Power(void) { - Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M21Write); -} - -static void M22Power(void) { - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M22Write); -} - -static void M23Power(void) { - big_bank = 0x20; - Sync(); - setprg8r(0x10, 0x6000, 0); // Only two Goemon games are have battery backed RAM, three more shooters - // (Parodius Da!, Gradius 2 and Crisis Force uses 2k or SRAM at 6000-67FF only - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M23Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M25Power(void) { - big_bank = 0x20; - Sync(); - setprg8r(0x10, 0x6000, 0); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M22Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + SetWriteHandler(0x8000, 0xFFFF, VRC24Write); } void VRC24IRQHook(int a) { @@ -210,26 +167,8 @@ static void VRC24Close(void) { WRAM = NULL; } -void Mapper21_Init(CartInfo *info) { - isPirate = 0; - is22 = 0; - info->Power = M21Power; - MapIRQHook = VRC24IRQHook; - GameStateRestore = StateRestore; - - AddExState(&StateRegs, ~0, 0, 0); -} - -void Mapper22_Init(CartInfo *info) { - isPirate = 0; - is22 = 1; - info->Power = M22Power; - GameStateRestore = StateRestore; - - AddExState(&StateRegs, ~0, 0, 0); -} - -void VRC24_Init(CartInfo *info) { +static void VRC24_Init(CartInfo *info) { + info->Power = VRC24Power; info->Close = VRC24Close; MapIRQHook = VRC24IRQHook; GameStateRestore = StateRestore; @@ -247,23 +186,48 @@ void VRC24_Init(CartInfo *info) { AddExState(&StateRegs, ~0, 0, 0); } -void Mapper23_Init(CartInfo *info) { - isPirate = 0; +void Mapper21_Init(CartInfo *info) { + isPirate = false; is22 = 0; - info->Power = M23Power; + reg1mask = 0x42; + reg2mask = 0x84; + VRC24_Init(info); +} + +void Mapper22_Init(CartInfo *info) { + isPirate = false; + is22 = 1; + reg1mask = 2; + reg2mask = 1; + + // no IRQ (all mapper 22 games are VRC2) + // no WRAM + info->Power = VRC24Power; + GameStateRestore = StateRestore; + + AddExState(&StateRegs, ~0, 0, 0); +} + +void Mapper23_Init(CartInfo *info) { + isPirate = false; + is22 = 0; + reg1mask = 0x15; + reg2mask = 0x2a; VRC24_Init(info); } void Mapper25_Init(CartInfo *info) { - isPirate = 0; + isPirate = false; is22 = 0; - info->Power = M25Power; + reg1mask = 0xa; + reg2mask = 0x5; VRC24_Init(info); } void UNLT230_Init(CartInfo *info) { - isPirate = 1; + isPirate = true; is22 = 0; - info->Power = M23Power; + reg1mask = 0x15; + reg2mask = 0x2a; VRC24_Init(info); } diff --git a/source/fceultra/boards/vrc5.cpp b/source/fceultra/boards/vrc5.cpp index 43f7918..6d17bd5 100644 --- a/source/fceultra/boards/vrc5.cpp +++ b/source/fceultra/boards/vrc5.cpp @@ -1,226 +1,202 @@ -/* 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 - * - * VRC-5 (CAI Shogakko no Sansu) - * - */ - -#include "mapinc.h" - -static uint8 QTAINTRAM[2048]; -static writefunc old2007wrap; - -static uint16 CHRSIZE = 8192; -static uint16 WRAMSIZE = 8192 + 4096; -static uint8 *CHRRAM = NULL; -static uint8 *WRAM = NULL; - -static uint8 IRQa, K4IRQ; -static uint32 IRQLatch, IRQCount; - -static uint8 regs[16]; -//static uint8 test[8]; -static SFORMAT StateRegs[] = -{ - { &IRQCount, 1, "IRQC" }, - { &IRQLatch, 1, "IRQL" }, - { &IRQa, 1, "IRQA" }, - { &K4IRQ, 1, "KIRQ" }, - { regs, 16, "REGS" }, - { 0 } -}; - -static void chrSync(void) { - setchr4r(0x10, 0x0000, regs[5] & 1); - setchr4r(0x10, 0x1000, 0); -} - -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); -} - -/*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; - 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; - } - 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 void VRC5IRQ(int a) { - if (IRQa) { - IRQCount += a; - if (IRQCount & 0x10000) { - X6502_IRQBegin(FCEU_IQEXT); - IRQCount = IRQLatch; - } - } -} - -//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); - - SetReadHandler(0x6000, 0xFFFF, CartBR); -// SetWriteHandler(0x5000,0x5007,TestWrite); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0xFFFF, M190Write); - SetReadHandler(0xDC00, 0xDC00, M190Read); - SetReadHandler(0xDD00, 0xDD00, M190Read); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - Sync(); -} - -static void M190Close(void) { - if (CHRRAM) - FCEU_gfree(CHRRAM); - CHRRAM = NULL; - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper190_Init(CartInfo *info) { - info->Power = M190Power; - info->Close = M190Close; - GameStateRestore = StateRestore; - - MapIRQHook = VRC5IRQ; -// PPU_hook=Mapper190_PPU; - - 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; - info->SaveGameLen[0] = WRAMSIZE - 4096; - } - - AddExState(&StateRegs, ~0, 0, 0); -} +/* 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 + * + * VRC-5 (CAI Shogakko no Sansu) + * + */ + +#include "mapinc.h" + +static uint8 QTAINTRAM[2048]; +static writefunc old2007wrap; + +static uint16 CHRSIZE = 8192; +static uint16 WRAMSIZE = 8192 + 4096; +static uint8 *CHRRAM = NULL; +static uint8 *WRAM = NULL; + +static uint8 IRQa, K4IRQ; +static uint32 IRQLatch, IRQCount; + +static uint8 regs[16]; +//static uint8 test[8]; +static SFORMAT StateRegs[] = +{ + { &IRQCount, 1, "IRQC" }, + { &IRQLatch, 1, "IRQL" }, + { &IRQa, 1, "IRQA" }, + { &K4IRQ, 1, "KIRQ" }, + { regs, 16, "REGS" }, + { 0 } +}; + +static void chrSync(void) { + setchr4r(0x10, 0x0000, regs[5] & 1); + setchr4r(0x10, 0x1000, 0); +} + +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); +} + +/*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; + 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; + } + 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 void VRC5IRQ(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount & 0x10000) { + X6502_IRQBegin(FCEU_IQEXT); + IRQCount = IRQLatch; + } + } +} + +//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); + + SetReadHandler(0x6000, 0xFFFF, CartBR); +// SetWriteHandler(0x5000,0x5007,TestWrite); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0xFFFF, M190Write); + SetReadHandler(0xDC00, 0xDC00, M190Read); + SetReadHandler(0xDD00, 0xDD00, M190Read); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + Sync(); +} + +static void M190Close(void) { + if (CHRRAM) + FCEU_gfree(CHRRAM); + CHRRAM = NULL; + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) { + Sync(); +} diff --git a/source/fceultra/boards/vrc7.cpp b/source/fceultra/boards/vrc7.cpp index e6b173a..d4df33a 100644 --- a/source/fceultra/boards/vrc7.cpp +++ b/source/fceultra/boards/vrc7.cpp @@ -86,7 +86,7 @@ static void VRC7SKill(void) { static void VRC7_ESI(void) { GameExpSound.RChange = VRC7SC; GameExpSound.Kill = VRC7SKill; - VRC7Sound = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 44100); + VRC7Sound = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 48000); OPLL_reset(VRC7Sound); OPLL_reset(VRC7Sound); } diff --git a/source/fceultra/cart.cpp b/source/fceultra/cart.cpp index ff2f93b..9451f55 100644 --- a/source/fceultra/cart.cpp +++ b/source/fceultra/cart.cpp @@ -76,6 +76,8 @@ uint8 geniech[3]; uint32 genieaddr[3]; +CartInfo *currCartInfo; + static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram) { uint32 AB = A >> 11; int x; diff --git a/source/fceultra/cart.h b/source/fceultra/cart.h index f0dba59..9cba1b9 100644 --- a/source/fceultra/cart.h +++ b/source/fceultra/cart.h @@ -25,6 +25,8 @@ typedef struct { // other code in the future. } CartInfo; +extern CartInfo *currCartInfo; + void FCEU_SaveGameSave(CartInfo *LocalHWInfo); void FCEU_LoadGameSave(CartInfo *LocalHWInfo); void FCEU_ClearGameSave(CartInfo *LocalHWInfo); diff --git a/source/fceultra/cheat.cpp b/source/fceultra/cheat.cpp index a938076..391bb0b 100644 --- a/source/fceultra/cheat.cpp +++ b/source/fceultra/cheat.cpp @@ -216,7 +216,7 @@ void FCEU_LoadGameCheats(FILE *override) } FCEU_DispMessage("Cheats file loaded.",0); //Tells user a cheats file was loaded. - while(fgets(linebuf,2048,fp)>0) + while(fgets(linebuf,2048,fp) != nullptr) { char *tbuf=linebuf; int doc=0; @@ -931,12 +931,14 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2) int FCEU_CheatGetByte(uint32 A) { - // if(CheatRPtrs[A>>10]) - // return CheatRPtrs[A>>10][A]; //adelikat-commenting this stuff out so that lua can see frozen addresses, I hope this doesn't bork stuff. - /*else*/ if(A < 0x10000) - return ARead[A](A); - else - return 0; + if(A < 0x10000) { + uint32 ret; + fceuindbg=1; + ret = ARead[A](A); + fceuindbg=0; + return ret; + } else + return 0; } void FCEU_CheatSetByte(uint32 A, uint8 V) diff --git a/source/fceultra/conddebug.cpp b/source/fceultra/conddebug.cpp index af2099c..915fcfd 100644 --- a/source/fceultra/conddebug.cpp +++ b/source/fceultra/conddebug.cpp @@ -34,10 +34,11 @@ * Primitive -> Number | Address | Register | Flag | PC Bank | '(' Connect ')' * Number -> '#' [1-9A-F]* * Address -> '$' [1-9A-F]* | '$' '[' Connect ']' -* Register -> 'A' | 'X' | 'Y' | 'P' -* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' +* Register -> 'A' | 'X' | 'Y' | 'P' | 'S' +* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' | 'U' | 'D' * PC Bank -> 'K' -* Data Bank -> 'T' +* Data Bank -> 'T' +* Value -> 'R' | 'W' */ #include "types.h" @@ -50,8 +51,9 @@ #include #include -// hack: this address is used by 'T' condition -uint16 addressOfTheLastAccessedData = 0; +uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions +uint8 debugLastOpcode; // used to evaluate 'W' condition + // Next non-whitespace character in string char next; @@ -137,7 +139,7 @@ int isFlag(char c) // Determines if a character is a register int isRegister(char c) { - return c == 'A' || c == 'X' || c == 'Y' || c == 'P'; + return c == 'A' || c == 'X' || c == 'Y' || c == 'P' || c == 'S'; } // Determines if a character is for PC bank @@ -152,6 +154,18 @@ int isDataBank(char c) return c == 'T'; } +// Determines if a character is for value read +int isValueRead(char c) +{ + return c == 'R'; +} + +// Determines if a character is for value write +int isValueWrite(char c) +{ + return c == 'W'; +} + // Reads a hexadecimal number from str int getNumber(unsigned int* number, const char** str) { @@ -272,6 +286,40 @@ Condition* Primitive(const char** str, Condition* c) return c; } + else if (isValueRead(next)) + { + if (c->type1 == TYPE_NO) + { + c->type1 = TYPE_VALUE_READ; + c->value1 = next; + } + else + { + c->type2 = TYPE_VALUE_READ; + c->value2 = next; + } + + scan(str); + + return c; + } + else if (isValueWrite(next)) + { + if (c->type1 == TYPE_NO) + { + c->type1 = TYPE_VALUE_WRITE; + c->value1 = next; + } + else + { + c->type2 = TYPE_VALUE_WRITE; + c->value2 = next; + } + + scan(str); + + return c; + } else if (next == '#') /* Numbers */ { unsigned int number = 0; diff --git a/source/fceultra/conddebug.h b/source/fceultra/conddebug.h index 92ea633..24af528 100644 --- a/source/fceultra/conddebug.h +++ b/source/fceultra/conddebug.h @@ -28,6 +28,8 @@ #define TYPE_ADDR 4 #define TYPE_PC_BANK 5 #define TYPE_DATA_BANK 6 +#define TYPE_VALUE_READ 7 +#define TYPE_VALUE_WRITE 8 #define OP_NO 0 #define OP_EQ 1 @@ -43,7 +45,9 @@ #define OP_OR 11 #define OP_AND 12 -extern uint16 addressOfTheLastAccessedData; +extern uint16 debugLastAddress; +extern uint8 debugLastOpcode; + //mbg merge 7/18/06 turned into sane c++ struct Condition { diff --git a/source/fceultra/config.cpp b/source/fceultra/config.cpp index de66a1e..f998a74 100644 --- a/source/fceultra/config.cpp +++ b/source/fceultra/config.cpp @@ -18,10 +18,13 @@ char *FCEUI_GetAboutString() { const char *aboutTemplate = FCEU_NAME_AND_VERSION "\n\n" "Administrators:\n" - "zeromus, adelikat, AnS\n\n" + "zeromus, punkrockguy318 (Lukas Sabota), feos\n" + "\n" "Current Contributors:\n" - "punkrockguy318 (Lukas Sabota)\n" - "CaH4e3, gocha, xhainingx, feos\n" + "CaH4e3, rainwarrior\n" + "\n" + "Past Contributors:\n" + "xhainingx, gocha, AnS\n" "\n" "FCEUX 2.0:\n" "mz, nitsujrehtona, SP, Ugly Joe,\n" diff --git a/source/fceultra/debug.cpp b/source/fceultra/debug.cpp index 7d26682..dbde6a3 100644 --- a/source/fceultra/debug.cpp +++ b/source/fceultra/debug.cpp @@ -77,6 +77,7 @@ int getValue(int type) case 'Z': return _P & Z_FLAG ? 1 : 0; case 'C': return _P & C_FLAG ? 1 : 0; case 'P': return _PC; + case 'S': return _S; } return 0; @@ -290,9 +291,13 @@ uint8 GetMem(uint16 A) { } else if ((A >= 0x4018) && (A < 0x5000)) // AnS: changed the range, so MMC5 ExRAM can be watched in the Hexeditor return 0xFF; - if (GameInfo) //adelikat: 11/17/09: Prevent crash if this is called with no game loaded. - return ARead[A](A); - else return 0; + if (GameInfo) { //adelikat: 11/17/09: Prevent crash if this is called with no game loaded. + uint32 ret; + fceuindbg=1; + ret = ARead[A](A); + fceuindbg=0; + return ret; + } else return 0; } uint8 GetPPUMem(uint8 A) { @@ -305,6 +310,32 @@ uint8 GetPPUMem(uint8 A) { //--------------------- +uint8 evaluateWrite(uint8 opcode, uint16 address) +{ + // predicts value written by this opcode + switch (opwrite[opcode]) + { + default: + case 0: return 0; // no write + case 1: return _A; // STA, PHA + case 2: return _X; // STX + case 3: return _Y; // STY + case 4: return _P; // PHP + case 5: return GetMem(address) << 1; // ASL (SLO) + case 6: return GetMem(address) >> 1; // LSR (SRE) + case 7: return (GetMem(address) << 1) | (_P & 1); // ROL (RLA) + case 8: return (GetMem(address) >> 1) | ((_P & 1) << 7); // ROL (RRA) + case 9: return GetMem(address) + 1; // INC (ISC) + case 10: return GetMem(address) - 1; // DEC (DCP) + case 11: return _A & _X; // (SAX) + case 12: return _A&_X&(((address-_Y)>>8)+1); // (AHX) + case 13: return _Y&(((address-_X)>>8)+1); // (SHY) + case 14: return _X&(((address-_Y)>>8)+1); // (SHX) + case 15: return _S& (((address-_Y)>>8)+1); // (TAS) + } + return 0; +} + // Evaluates a condition int evaluate(Condition* c) { @@ -330,7 +361,9 @@ int evaluate(Condition* c) { case TYPE_ADDR: value1 = GetMem(value1); break; case TYPE_PC_BANK: value1 = getBank(_PC); break; - case TYPE_DATA_BANK: value1 = getBank(addressOfTheLastAccessedData); break; + case TYPE_DATA_BANK: value1 = getBank(debugLastAddress); break; + case TYPE_VALUE_READ: value1 = GetMem(debugLastAddress); break; + case TYPE_VALUE_WRITE: value1 = evaluateWrite(debugLastOpcode, debugLastAddress); break; } f = value1; @@ -355,7 +388,9 @@ int evaluate(Condition* c) { case TYPE_ADDR: value2 = GetMem(value2); break; case TYPE_PC_BANK: value2 = getBank(_PC); break; - case TYPE_DATA_BANK: value2 = getBank(addressOfTheLastAccessedData); break; + case TYPE_DATA_BANK: value2 = getBank(debugLastAddress); break; + case TYPE_VALUE_READ: value2 = GetMem(debugLastAddress); break; + case TYPE_VALUE_WRITE: value2 = evaluateWrite(debugLastOpcode, debugLastAddress); break; } switch (c->op) @@ -367,7 +402,7 @@ int evaluate(Condition* c) case OP_G: f = value1 > value2; break; case OP_L: f = value1 < value2; break; case OP_MULT: f = value1 * value2; break; - case OP_DIV: f = value1 / value2; break; + case OP_DIV: f = (value2==0) ? 0 : (value1 / value2); break; case OP_PLUS: f = value1 + value2; break; case OP_MINUS: f = value1 - value2; break; case OP_OR: f = value1 || value2; break; @@ -502,6 +537,11 @@ void BreakHit(int bp_num, bool force) { if(!force) { + if (bp_num >= 0 && !condition(&watchpoint[bp_num])) + { + return; // condition rejected + } + //check to see whether we fall in any forbid zone for (int i = 0; i < numWPs; i++) { @@ -529,7 +569,7 @@ void BreakHit(int bp_num, bool force) #endif } -uint8 StackAddrBackup = X.S; +int StackAddrBackup; uint16 StackNextIgnorePC = 0xFFFF; ///fires a breakpoint @@ -539,6 +579,9 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { uint8 stackop=0; uint8 stackopstartaddr,stackopendaddr; + debugLastAddress = A; + debugLastOpcode = opcode[0]; + if (break_asap) { break_asap = false; @@ -601,24 +644,25 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { switch (opcode[0]) { //Push Ops case 0x08: //Fall to next - case 0x48: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break; + case 0x48: debugLastAddress=stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break; //Pull Ops case 0x28: //Fall to next - case 0x68: stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break; + case 0x68: debugLastAddress=stackopstartaddr=stackopendaddr=X.S+1; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=_PC+1; break; //JSR (Includes return address - 1) case 0x20: stackopstartaddr=stackopendaddr=X.S-1; stackop=WP_W; StackAddrBackup = X.S; StackNextIgnorePC=(opcode[1]|opcode[2]<<8); break; //RTI (Includes processor status, and exact return address) case 0x40: stackopstartaddr=X.S+1; stackopendaddr=X.S+3; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(X.S+2|0x0100)|GetMem(X.S+3|0x0100)<<8); break; //RTS (Includes return address - 1) case 0x60: stackopstartaddr=X.S+1; stackopendaddr=X.S+2; stackop=WP_R; StackAddrBackup = X.S; StackNextIgnorePC=(GetMem(stackopstartaddr|0x0100)|GetMem(stackopendaddr|0x0100)<<8)+1; break; + default: break; } + #define BREAKHIT(x) { breakHit = (x); goto STOPCHECKING; } + int breakHit = -1; for (i = 0; i < numWPs; i++) { -// ################################## Start of SP CODE ########################### - if ((watchpoint[i].flags & WP_E) && condition(&watchpoint[i])) + if ((watchpoint[i].flags & WP_E)) { -// ################################## End of SP CODE ########################### if (watchpoint[i].flags & BT_P) { // PPU Mem breaks @@ -628,11 +672,11 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (watchpoint[i].endaddress) { if ((watchpoint[i].address <= PPUAddr) && (watchpoint[i].endaddress >= PPUAddr)) - BreakHit(i); + BREAKHIT(i); } else { if (watchpoint[i].address == PPUAddr) - BreakHit(i); + BREAKHIT(i); } } } else if (watchpoint[i].flags & BT_S) @@ -643,16 +687,16 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (watchpoint[i].endaddress) { if ((watchpoint[i].address <= PPU[3]) && (watchpoint[i].endaddress >= PPU[3])) - BreakHit(i); + BREAKHIT(i); } else { if (watchpoint[i].address == PPU[3]) - BreakHit(i); + BREAKHIT(i); } } else if ((watchpoint[i].flags & WP_W) && (A == 0x4014)) { // Sprite DMA! :P - BreakHit(i); + BREAKHIT(i); } } else { @@ -663,12 +707,12 @@ 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); + BREAKHIT(i); } else { if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) || ((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC))) - BreakHit(i); + BREAKHIT(i); } } else { @@ -685,11 +729,11 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (watchpoint[i].endaddress) { if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j)) - BreakHit(i); + BREAKHIT(i); } else { if (watchpoint[i].address == j) - BreakHit(i); + BREAKHIT(i); } } } @@ -700,7 +744,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { StackNextIgnorePC = 0xFFFF; } else { - if ((X.S < StackAddrBackup) && (stackop==0)) + if (StackAddrBackup != -1 && (X.S < StackAddrBackup) && (stackop==0)) { // Unannounced stack mem breaks // Pushes to stack @@ -711,15 +755,15 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (watchpoint[i].endaddress) { if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j)) - BreakHit(i); + BREAKHIT(i); } else { if (watchpoint[i].address == j) - BreakHit(i); + BREAKHIT(i); } } } - } else if ((StackAddrBackup < X.S) && (stackop==0)) + } else if (StackAddrBackup != -1 && (StackAddrBackup < X.S) && (stackop==0)) { // Pulls from stack if (watchpoint[i].flags & WP_R) @@ -729,11 +773,11 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { if (watchpoint[i].endaddress) { if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j)) - BreakHit(i); + BREAKHIT(i); } else { if (watchpoint[i].address == j) - BreakHit(i); + BREAKHIT(i); } } } @@ -742,13 +786,20 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) { } } -// ################################## Start of SP CODE ########################### } -// ################################## End of SP CODE ########################### - } + } //loop across all breakpoints +STOPCHECKING: + //Update the stack address with the current one, now that changes have registered. + //ZEROMUS THINKS IT MAKES MORE SENSE HERE StackAddrBackup = X.S; + + if(breakHit != -1) + BreakHit(i); + + ////Update the stack address with the current one, now that changes have registered. + //StackAddrBackup = X.S; } //bbit edited: this is the end of the inserted code @@ -777,9 +828,12 @@ void DebugCycle() size = opsize[opcode[0]]; switch (size) { + default: + case 1: break; case 2: opcode[1] = GetMem(_PC + 1); break; + case 0: // illegal instructions may have operands case 3: opcode[1] = GetMem(_PC + 1); opcode[2] = GetMem(_PC + 2); @@ -803,7 +857,6 @@ void DebugCycle() case 7: A = (opcode[1] | (opcode[2] << 8)) + _X; break; case 8: A = opcode[1] + _Y; break; } - addressOfTheLastAccessedData = A; if (numWPs || dbgstate.step || dbgstate.runline || dbgstate.stepout || watchpoint[64].flags || dbgstate.badopbreak || break_on_cycles || break_on_instructions || break_asap) breakpoint(opcode, A, size); diff --git a/source/fceultra/debug.h b/source/fceultra/debug.h index bd5472a..d531abf 100644 --- a/source/fceultra/debug.h +++ b/source/fceultra/debug.h @@ -49,13 +49,11 @@ typedef struct { uint16 address; uint16 endaddress; uint8 flags; -// ################################## Start of SP CODE ########################### Condition* cond; char* condText; char* desc; -// ################################## End of SP CODE ########################### } watchpointinfo; //mbg merge 7/18/06 had to make this extern @@ -117,8 +115,6 @@ extern void IncrementInstructionsCounters(); extern uint8 *vnapage[4],*VPage[8]; extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset; extern uint32 FCEUPPU_PeekAddress(); - -extern int debug_loggingCD; extern int numWPs; ///encapsulates the operational state of the debugger core diff --git a/source/fceultra/driver.h b/source/fceultra/driver.h index db12067..7d228e0 100644 --- a/source/fceultra/driver.h +++ b/source/fceultra/driver.h @@ -68,7 +68,7 @@ void FCEUI_NTSCSELTINT(void); void FCEUI_NTSCDEC(void); void FCEUI_NTSCINC(void); void FCEUI_GetNTSCTH(int *tint, int *hue); -void FCEUI_SetNTSCTH(int n, int tint, int hue); +void FCEUI_SetNTSCTH(bool en, int tint, int hue); void FCEUI_SetInput(int port, ESI type, void *ptr, int attrib); void FCEUI_SetInputFC(ESIFC type, void *ptr, int attrib); @@ -122,7 +122,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); +void FCEUI_SetRegion(int region, int notify = 1); //Convenience function; returns currently emulated video system(0=NTSC, 1=PAL). int FCEUI_GetCurrentVidSystem(int *slstart, int *slend); @@ -141,9 +141,7 @@ 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); -//Tells FCE Ultra to copy the palette data pointed to by pal and use it. -//Data pointed to by pal needs to be 64*3 bytes in length. -void FCEUI_SetPaletteArray(uint8 *pal); +void FCEUI_SetUserPalette(uint8 *pal, int nEntries); //Sets up sound code to render sound at the specified rate, in samples //per second. Only sample rates of 44100, 48000, and 96000 are currently supported. diff --git a/source/fceultra/fceu.cpp b/source/fceultra/fceu.cpp index dcad5eb..d68b131 100644 --- a/source/fceultra/fceu.cpp +++ b/source/fceultra/fceu.cpp @@ -56,9 +56,10 @@ extern bool isTaseditorRecording(); extern int32 fps_scale; extern int32 fps_scale_unpaused; extern int32 fps_scale_frameadvance; -extern void RefreshThrottleFPS(); #endif +extern void RefreshThrottleFPS(); + #ifdef _S9XLUA_H #include "fceulua.h" #endif @@ -93,6 +94,20 @@ extern void RefreshThrottleFPS(); using namespace std; +//----------- +//overclocking-related +// overclock the console by adding dummy scanlines to PPU loop or to vblank +// disables DMC DMA, WaveHi filling and image rendering for these dummies +// doesn't work with new PPU +bool overclock_enabled = 0; +bool overclocking = 0; +bool skip_7bit_overclocking = 1; // 7-bit samples have priority over overclocking +int normalscanlines; +int totalscanlines; +int postrenderscanlines = 0; +int vblankscanlines = 0; +//------------ + int AFon = 1, AFoff = 1, AutoFireOffset = 0; //For keeping track of autofire settings bool justLagged = false; bool frameAdvanceLagSkip = false; //If this is true, frame advance will skip over lag frame (i.e. it will emulate 2 frames instead of 1) @@ -101,7 +116,6 @@ bool movieSubtitles = true; //Toggle for displaying movie subtitles bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated. bool AutoResumePlay = false; char romNameWhenClosingEmulator[2048] = {0}; -int dendy = 0; FCEUGI::FCEUGI() : filename(0), @@ -140,10 +154,12 @@ void FCEU_TogglePPU(void) { if (newppu) { FCEU_DispMessage("New PPU loaded", 0); FCEUI_printf("New PPU loaded"); + overclock_enabled = 0; } else { FCEU_DispMessage("Old PPU loaded", 0); FCEUI_printf("Old PPU loaded"); } + normalscanlines = (dendy ? 290 : 240)+newppu; // use flag as number! #ifdef WIN32 SetMainWindowText(); #endif @@ -348,16 +364,10 @@ uint8 PAL = 0; static DECLFW(BRAML) { RAM[A] = V; - #ifdef _S9XLUA_H - CallRegisteredLuaMemHook(A, 1, V, LUAMEMHOOK_WRITE); - #endif } static DECLFW(BRAMH) { RAM[A & 0x7FF] = V; - #ifdef _S9XLUA_H - CallRegisteredLuaMemHook(A & 0x7FF, 1, V, LUAMEMHOOK_WRITE); - #endif } static DECLFR(ARAML) { @@ -384,7 +394,7 @@ void ResetGameLoaded(void) { MMC5Hack = 0; PEC586Hack = 0; PAL &= 1; - pale = 0; + default_palette_selection = 0; } int UNIFLoad(const char *name, FCEUFILE *fp); @@ -401,6 +411,8 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen //attempt to open the files FCEUFILE *fp; char fullname[2048]; // this name contains both archive name and ROM file name + int lastpal = PAL; + int lastdendy = dendy; const char* romextensions[] = { "nes", "fds", 0 }; fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions); @@ -488,7 +500,8 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen // ################################## End of SP CODE ########################### #endif - FCEU_ResetVidSys(); + if (OverwriteVidMode) + FCEU_ResetVidSys(); if (GameInfo->type != GIT_NSF) { @@ -511,6 +524,18 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen 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); @@ -712,10 +737,15 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski extern int KillFCEUXonFrame; if (KillFCEUXonFrame && (FCEUMOV_GetFrame() >= KillFCEUXonFrame)) DoFCEUExit(); +#else + extern int KillFCEUXonFrame; + if (KillFCEUXonFrame && (FCEUMOV_GetFrame() >= KillFCEUXonFrame)) + exit(0); #endif timestampbase += timestamp; timestamp = 0; + soundtimestamp = 0; *pXBuf = skip ? 0 : XBuf; if (skip == 2) { //If skip = 2, then bypass sound @@ -769,17 +799,79 @@ void ResetNES(void) { //FCEU_DispMessage("Reset", 0); } -void FCEU_MemoryRand(uint8 *ptr, uint32 size) { + +int RAMInitSeed = 0; +int RAMInitOption = 0; + +u64 splitmix64(u32 input) { + u64 z = (input + 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); +} + +static inline u64 xoroshiro128plus_rotl(const u64 x, int k) { + return (x << k) | (x >> (64 - k)); +} + +u64 xoroshiro128plus_s[2]; +void xoroshiro128plus_seed(u32 input) +{ +//http://xoroshiro.di.unimi.it/splitmix64.c + u64 x = input; + + u64 z = (x += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + xoroshiro128plus_s[0] = z ^ (z >> 31); + + z = (x += 0x9e3779b97f4a7c15); + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + xoroshiro128plus_s[1] = z ^ (z >> 31); +} + +//http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c +u64 xoroshiro128plus_next() { + const u64 s0 = xoroshiro128plus_s[0]; + u64 s1 = xoroshiro128plus_s[1]; + const u64 result = s0 + s1; + + s1 ^= s0; + xoroshiro128plus_s[0] = xoroshiro128plus_rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b + xoroshiro128plus_s[1] = xoroshiro128plus_rotl(s1, 36); // c + + return result; +} + +void FCEU_MemoryRand(uint8 *ptr, uint32 size, bool default_zero) { int x = 0; + while (size) { - *ptr = (x & 4) ? 0xFF : 0x00; // Huang Di DEBUG MODE enabled by default - // Cybernoid NO MUSIC by default -// *ptr = (x & 4) ? 0x7F : 0x00; // Huang Di DEBUG MODE enabled by default - // Minna no Taabou no Nakayoshi Daisakusen DOESN'T BOOT - // Cybernoid NO MUSIC by default -// *ptr = (x & 1) ? 0x55 : 0xAA; // F-15 Sity War HISCORE is screwed... - // 1942 SCORE/HISCORE is screwed... -// *ptr = 0xFF; // Work for all cases + uint8 v = 0; + switch (RAMInitOption) + { + default: + case 0: + if (!default_zero) v = (x & 4) ? 0xFF : 0x00; + else v = 0x00; + break; + case 1: v = 0xFF; break; + case 2: v = 0x00; break; + case 3: v = (u8)(xoroshiro128plus_next()); break; + + // the default is this 8 byte pattern: 00 00 00 00 FF FF FF FF + // it has been used in FCEUX since time immemorial + + // Some games to examine uninitialied RAM problems with: + // * Cybernoid - music option starts turned off with default pattern + // * Huang Di - debug mode is enabled with default pattern + // * Minna no Taabou no Nakayoshi Daisakusen - fails to boot with some patterns + // * F-15 City War - high score table + // * 1942 - high score table + // * Cheetahmen II - may start in different levels with different RAM startup + } + *ptr = v; x++; size--; ptr++; @@ -793,18 +885,21 @@ void PowerNES(void) { FCEUMOV_AddCommand(FCEUNPCMD_POWER); if (!GameInfo) return; + //reseed random, unless we're in a movie + extern int disableBatteryLoading; + if(FCEUMOV_Mode(MOVIEMODE_INACTIVE) && !disableBatteryLoading) + { + RAMInitSeed = rand() ^ (u32)xoroshiro128plus_next(); + } + + //always reseed the PRNG with the current seed, for deterministic results (for that seed) + xoroshiro128plus_seed(RAMInitSeed); + FCEU_CheatResetRAM(); FCEU_CheatAddRAM(2, 0, RAM); FCEU_GeniePower(); - //dont do this, it breaks some games: Cybernoid; Minna no Taabou no Nakayoshi Daisakusen; and maybe mechanized attack - //memset(RAM,0xFF,0x800); - //this fixes the above, but breaks Huang Di, which expects $100 to be non-zero or else it believes it has debug cheats enabled, giving you moon jump and other great but likely unwanted things - //FCEU_MemoryRand(RAM,0x800); - //this should work better, based on observational evidence. fixes all of the above: - //for(int i=0;i<0x800;i++) if(i&1) RAM[i] = 0xAA; else RAM[i] = 0x55; - //but we're leaving this for now until we collect some more data FCEU_MemoryRand(RAM, 0x800); SetReadHandler(0x0000, 0xFFFF, ANull); @@ -845,7 +940,7 @@ void PowerNES(void) { Update_RAM_Search(); // Update_RAM_Watch() is also called. #endif - //FCEU_DispMessage("Power on", 0); + FCEU_DispMessage("Power on", 0); } void FCEU_ResetVidSys(void) { @@ -861,6 +956,14 @@ void FCEU_ResetVidSys(void) { PAL = w ? 1 : 0; + if (PAL) + dendy = 0; + + if (newppu) + overclock_enabled = 0; + + normalscanlines = (dendy ? 290 : 240)+newppu; // use flag as number! + totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0); FCEUPPU_SetVideoSystem(w || dendy); SetSoundVariables(); } @@ -877,6 +980,13 @@ void FCEU_printf(char *format, ...) { vsnprintf(temp, sizeof(temp), format, ap); FCEUD_Message(temp); +#if 0 + FILE *ofile; + ofile = fopen("stdout.txt", "ab"); + fwrite(temp, 1, strlen(temp), ofile); + fclose(ofile); +#endif + va_end(ap); #endif } @@ -925,30 +1035,58 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) { *slend = FSettings.LastSLine; return(PAL); } -/* -// TODO: make use on SDL -void FCEUI_SetRegion(int region) { + +#ifndef GEKKO +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"); + } +#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"); + } +#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"); + } +#endif break; } + normalscanlines += newppu; + totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0); FCEUI_SetVidSystem(pal_emulation); RefreshThrottleFPS(); #ifdef WIN32 UpdateCheckedMenuItems(); PushCurrentVideoSettings(); #endif -}*/ +} +#endif //Enable or disable Game Genie option. void FCEUI_SetGameGenie(bool a) { @@ -1052,9 +1190,7 @@ int FCEU_TextScanlineOffsetFromBottom(int y) { } bool FCEU_IsValidUI(EFCEUI ui) { -#ifdef GEKKO - return true; -#endif +#ifndef GEKKO switch (ui) { case FCEUI_OPENGAME: case FCEUI_CLOSEGAME: @@ -1099,6 +1235,7 @@ bool FCEU_IsValidUI(EFCEUI ui) { if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false; break; } +#endif return true; } @@ -1165,8 +1302,6 @@ void FCEUXGameInterface(GI command) { } } - - bool FCEUXLoad(const char *name, FCEUFILE *fp) { //read ines header iNES_HEADER head; @@ -1218,11 +1353,26 @@ bool FCEUXLoad(const char *name, FCEUFILE *fp) { return true; } - uint8 FCEU_ReadRomByte(uint32 i) { extern iNES_HEADER head; - if (i < 16) return *((unsigned char*)&head + i); - if (i < 16 + PRGsize[0]) return PRGptr[0][i - 16]; - if (i < 16 + PRGsize[0] + CHRsize[0]) return CHRptr[0][i - 16 - PRGsize[0]]; + if (i < 16) + return *((unsigned char*)&head + i); + if (i < 16 + PRGsize[0]) + return PRGptr[0][i - 16]; + if (i < 16 + PRGsize[0] + CHRsize[0]) + return CHRptr[0][i - 16 - PRGsize[0]]; return 0; } + +void FCEU_WriteRomByte(uint32 i, uint8 value) { + if (i < 16) +#ifdef WIN32 + MessageBox(hMemView,"Sorry", "You can't edit the ROM header.", MB_OK); +#else + printf("Sorry, you can't edit the ROM header.\n"); +#endif + if (i < 16 + PRGsize[0]) + PRGptr[0][i - 16] = value; + else if (i < 16 + PRGsize[0] + CHRsize[0]) + CHRptr[0][i - 16 - PRGsize[0]] = value; +} diff --git a/source/fceultra/fceu.h b/source/fceultra/fceu.h index 743492c..1b76249 100644 --- a/source/fceultra/fceu.h +++ b/source/fceultra/fceu.h @@ -7,13 +7,22 @@ extern int fceuindbg; extern int newppu; void ResetGameLoaded(void); +//overclocking-related +extern bool overclock_enabled; +extern bool overclocking; +extern bool skip_7bit_overclocking; +extern int normalscanlines; +extern int totalscanlines; +extern int postrenderscanlines; +extern int vblankscanlines; + extern bool AutoResumePlay; extern char romNameWhenClosingEmulator[]; #define DECLFR(x) uint8 x (uint32 A) #define DECLFW(x) void x (uint32 A, uint8 V) -void FCEU_MemoryRand(uint8 *ptr, uint32 size); +void FCEU_MemoryRand(uint8 *ptr, uint32 size, bool default_zero=false); void SetReadHandler(int32 start, int32 end, readfunc func); void SetWriteHandler(int32 start, int32 end, writefunc func); writefunc GetWriteHandler(int32 a); @@ -54,6 +63,7 @@ extern uint8 *RAM; //shared memory modifications extern int EmulationPaused; uint8 FCEU_ReadRomByte(uint32 i); +void FCEU_WriteRomByte(uint32 i, uint8 value); extern readfunc ARead[0x10000]; extern writefunc BWrite[0x10000]; @@ -121,7 +131,7 @@ void FCEU_DispMessage(char *format, int disppos, ...); void FCEU_DispMessageOnMovie(char *format, ...); void FCEU_TogglePPU(); -void SetNESDeemph(uint8 d, int force); +void SetNESDeemph_OldHacky(uint8 d, int force); void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor); void FCEU_PutImage(void); #ifdef FRAMESKIP @@ -134,7 +144,7 @@ extern void PushCurrentVideoSettings(); #endif extern uint8 Exit; -extern uint8 pale; +extern int default_palette_selection; extern uint8 vsdip; //#define FCEUDEF_DEBUGGER //mbg merge 7/17/06 - cleaning out conditional compiles diff --git a/source/fceultra/fds.cpp b/source/fceultra/fds.cpp index 5584a56..6ec9df3 100644 --- a/source/fceultra/fds.cpp +++ b/source/fceultra/fds.cpp @@ -18,10 +18,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include - #include "types.h" #include "x6502.h" #include "fceu.h" @@ -37,10 +33,14 @@ #include "driver.h" #include "movie.h" +#include +#include +#include + // TODO: Add code to put a delay in between the time a disk is inserted // and the when it can be successfully read/written to. This should // prevent writes to wrong places OR add code to prevent disk ejects -// when the virtual motor is on(mmm...virtual motor). +// when the virtual motor is on (mmm...virtual motor). extern int disableBatteryLoading; bool isFDS = false; //flag for determining if a FDS game is loaded, movie.cpp needs this @@ -147,20 +147,26 @@ static void FDSInit(void) { SelectDisk = 0; } -void FCEU_FDSInsert(void) { - if (FCEUI_EmulationPaused()) EmulationPaused |= 2; +void FCEU_FDSInsert(void) +{ + if (TotalSides == 0) + { + FCEU_DispMessage("", 0);//FCEU_DispMessage("Not FDS; can't eject disk.", 0); + return; + } + + if (FCEUI_EmulationPaused()) + EmulationPaused |= EMULATIONPAUSED_FA; if (FCEUMOV_Mode(MOVIEMODE_RECORD)) FCEUMOV_AddCommand(FCEUNPCMD_FDSINSERT); - if (TotalSides == 0) { - FCEU_DispMessage("", 0);// remove text "Not FDS; can't eject disk." - return; - } - if (InDisk == 255) { + if (InDisk == 255) + { //FCEU_DispMessage("Disk %d Side %s Inserted", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); InDisk = SelectDisk; - } else { + } else + { //FCEU_DispMessage("Disk %d Side %s Ejected", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); InDisk = 255; } @@ -171,22 +177,27 @@ void FCEU_FDSEject(void) InDisk=255; } */ -void FCEU_FDSSelect(void) { - if (FCEUI_EmulationPaused()) EmulationPaused |= 2; +void FCEU_FDSSelect(void) +{ + if (TotalSides == 0) + { + FCEU_DispMessage("", 0); //FCEU_DispMessage("Not FDS; can't select disk.", 0); + return; + } + if (InDisk != 255) + { + FCEU_DispMessage("", 0); //FCEU_DispMessage("Eject disk before selecting.", 0); + return; + } + + if (FCEUI_EmulationPaused()) + EmulationPaused |= EMULATIONPAUSED_FA; if (FCEUMOV_Mode(MOVIEMODE_RECORD)) FCEUMOV_AddCommand(FCEUNPCMD_FDSSELECT); - if (TotalSides == 0) { - FCEU_DispMessage("", 0);//remove text "Not FDS; can't select disk." - return; - } - if (InDisk != 255) { - FCEU_DispMessage("", 0); //remove text "Eject disk before selecting" - return; - } SelectDisk = ((SelectDisk + 1) % TotalSides) & 3; - FCEU_DispMessage("", 0); //("Disk %d Side %c Selected", 0, SelectDisk >> 1, (SelectDisk & 1) ? 'B' : 'A'); + FCEU_DispMessage("", 0); //FCEU_DispMessage("Disk %d Side %c Selected", 0, SelectDisk >> 1, (SelectDisk & 1) ? 'B' : 'A'); } static void FDSFix(int a) { @@ -753,13 +764,11 @@ int FDSLoad(const char *name, FCEUFILE *fp) { CHRRAMSize = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); - memset(CHRRAM, 0, CHRRAMSize); SetupCartCHRMapping(0, CHRRAM, CHRRAMSize, 1); AddExState(CHRRAM, CHRRAMSize, 0, "CHRR"); FDSRAMSize = 32768; FDSRAM = (uint8*)FCEU_gmalloc(FDSRAMSize); - memset(FDSRAM, 0, FDSRAMSize); SetupCartPRGMapping(1, FDSRAM, FDSRAMSize, 1); AddExState(FDSRAM, FDSRAMSize, 0, "FDSR"); diff --git a/source/fceultra/file.cpp b/source/fceultra/file.cpp index 1f946dd..39f00c8 100644 --- a/source/fceultra/file.cpp +++ b/source/fceultra/file.cpp @@ -27,10 +27,6 @@ #include #include -#ifndef WIN32 -#include -#endif - #include "types.h" #include "file.h" #include "utils/endian.h" @@ -49,6 +45,10 @@ #include "driver.h" #include "utils/xstring.h" +#ifndef WIN32 +#include +#endif + using namespace std; bool bindSavestate = true; //Toggle that determines if a savestate filename will include the movie filename diff --git a/source/fceultra/git.h b/source/fceultra/git.h index d541cf1..67accc1 100644 --- a/source/fceultra/git.h +++ b/source/fceultra/git.h @@ -36,8 +36,10 @@ enum ESI SI_POWERPADB = 4, SI_ARKANOID = 5, SI_MOUSE = 6, + SI_SNES = 7, + SI_SNES_MOUSE = 8, - SI_COUNT = SI_MOUSE + SI_COUNT = SI_SNES_MOUSE }; inline const char* ESI_Name(ESI esi) @@ -50,7 +52,9 @@ inline const char* ESI_Name(ESI esi) "Power Pad A", "Power Pad B", "Arkanoid Paddle", - "Mouse" + "Subor Mouse", + "SNES Pad", + "SNES Mouse" }; if(esi >= SI_NONE && esi <= SI_COUNT) diff --git a/source/fceultra/ines-bad.h b/source/fceultra/ines-bad.h index 179ab01..a332b35 100644 --- a/source/fceultra/ines-bad.h +++ b/source/fceultra/ines-bad.h @@ -30,6 +30,7 @@ { 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 }, diff --git a/source/fceultra/ines-correct.h b/source/fceultra/ines-correct.h index 128d9f1..b47dbf3 100644 --- a/source/fceultra/ines-correct.h +++ b/source/fceultra/ines-correct.h @@ -62,6 +62,7 @@ {0x02cc3973, 3, 1}, /* Ninja Kid */ {0xbc065fc3, 3, 1}, /* Pipe Dream */ {0xc9ee15a7, 3, -1}, /* 3 is probably best. 41 WILL NOT WORK. */ + {0x13e09d7a, 4, 0}, /*Dragon Wars (U) (proto) - comes with erroneous 4-screen mirroring set*/ {0x22d6d5bd, 4, 1}, {0xd97c31b0, 4, 1}, //Rasaaru Ishii no Childs Quest (J) {0x404b2e8b, 4, 2}, /* Rad Racer 2 */ @@ -83,7 +84,6 @@ {0x6e68e31a, 16, 8}, /* Dragon Ball 3*/ {0x33b899c9, 16, -1}, /* Dragon Ball - Dai Maou Fukkatsu (J) [!] */ {0xa262a81f, 16, -1}, /* Rokudenashi Blues (J) */ - {0x286fcd20, 23, -1}, /* Ganbare Goemon Gaiden 2 - Tenka no Zaihou (J) [!] */ {0xe4a291ce, 23, -1}, /* World Hero (Unl) [!] */ {0x51e9cd33, 23, -1}, /* World Hero (Unl) [b1] */ {0x105dd586, 27, -1}, /* Mi Hun Che variations... */ @@ -257,10 +257,28 @@ {0x345ee51a, 245, -1}, /* DQ4c */ {0x57514c6c, 245, -1}, /* Yong Zhe Dou E Long - Dragon Quest VI (Ch) */ + // added a new mask bit to define these mappers as a dupes of the UNIF format boards + {0x1d75fd35, 256|0x1000,-1}, /* 2-in-1 - Street Dance + Hit Mouse (Unl) [!] */ {0x6eef8bb7, 257|0x1000,-1}, /* PEC-586 Chinese */ {0xac7e98fb, 257|0x1000,-1}, /* PEC-586 Chinese No Tape Out */ {0x8d51a23b, 257|0x1000,-1}, /* [KeWang] Chao Ji Wu Bi Han Ka (C) V1 */ {0x25c76773, 257|0x1000,-1}, /* [KeWang] Chao Ji Wu Bi Han Ka (C) V2 */ + {0x1ca9c322, 258|0x1000,-1}, /* Blood Of Jurassic (GD-98)(Unl) */ + {0x2469c1ae, 259|0x1000,-1}, /* 150-in-1 Unchained FIGHT version */ + + {0x99d4464f, 260|0x1000,-1}, /* HP10xx/HP20xx board dumps */ + {0xb72b2cf4, 260|0x1000,-1}, + {0x4dc6107d, 260|0x1000,-1}, + {0x0073dbd8, 260|0x1000,-1}, + {0x3b098344, 260|0x1000,-1}, + {0x1fc640c0, 260|0x1000,-1}, + {0x2f1ad1fc, 260|0x1000,-1}, + {0xa22214bb, 260|0x1000,-1}, + {0x5dd9073b, 260|0x1000,-1}, + {0x26a36cc2, 260|0x1000,-1}, + {0xd1e52b37, 260|0x1000,-1}, + {0x4d4a0e1b, 260|0x1000,-1}, + {0xb6dd2c9d, 260|0x1000,-1}, {0x00000000, -1, -1} diff --git a/source/fceultra/ines.cpp b/source/fceultra/ines.cpp index 4c56c38..93eed39 100644 --- a/source/fceultra/ines.cpp +++ b/source/fceultra/ines.cpp @@ -327,7 +327,7 @@ static void CheckHInfo(void) { { #include "ines-correct.h" }; - int32 tofix = 0, x; + int32 tofix = 0, x, mask; uint64 partialmd5 = 0; for (x = 0; x < 8; x++) @@ -361,9 +361,13 @@ static void CheckHInfo(void) { VROM = NULL; tofix |= 8; } - if (MapperNo != (moo[x].mapper & 0xFF)) { + if (moo[x].mapper & 0x1000) + mask = 0xFFF; + else + mask = 0xFF; + if (MapperNo != (moo[x].mapper & mask)) { tofix |= 1; - MapperNo = moo[x].mapper & 0xFF; + MapperNo = moo[x].mapper & mask; } } if (moo[x].mirror >= 0) { @@ -561,7 +565,7 @@ static BMAPPINGLocal bmap[] = { {"FDS UNROM BOARD", 108, Mapper108_Init}, // {"", 109, Mapper109_Init}, // {"", 110, Mapper110_Init}, -// {"", 111, Mapper111_Init}, + {"Cheapocabra", 111, Mapper111_Init}, {"ASDER/NTDEC BOARD", 112, Mapper112_Init}, {"HACKER/SACHEN BOARD", 113, Mapper113_Init}, {"MMC3 SG PROT. A", 114, Mapper114_Init}, @@ -640,7 +644,7 @@ static BMAPPINGLocal bmap[] = { {"", 187, Mapper187_Init}, {"", 188, Mapper188_Init}, {"", 189, Mapper189_Init}, -// {"", 190, Mapper190_Init}, + {"", 190, Mapper190_Init}, {"", 191, Mapper191_Init}, {"TW MMC3+VRAM Rev. B", 192, Mapper192_Init}, {"NTDEC TC-112", 193, Mapper193_Init}, // War in the Gulf @@ -711,6 +715,18 @@ static BMAPPINGLocal bmap[] = { //-------- Mappers 512-767 is the Supplementary Ideographic Plane ----------- //-------- Mappers 3840-4095 are for rom dumps not publicly released -------- +// An attempt to make working the UNIF BOARD ROMs in INES FORMAT +// I don't know if there a complete ines 2.0 mapper list exist, so if it does, +// just redefine these numbers to any others which isn't used before +// see the ines-correct.h files for the ROMs CHR list + + {"ONE-BUS Systems", 256, UNLOneBus_Init}, + {"PEC-586 Computer", 257, UNLPEC586Init}, + {"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}, + {"", 0, NULL} }; @@ -845,7 +861,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { FCEU_printf(" Total VRAM size: %d\n", iNESCart.vram_size + iNESCart.battery_vram_size); if(head.ROM_type & 2) { - FCEU_printf(" WRAM backked by battery: %d\n", iNESCart.battery_wram_size); + FCEU_printf(" WRAM backed by battery: %d\n", iNESCart.battery_wram_size); FCEU_printf(" VRAM backed by battery: %d\n", iNESCart.battery_vram_size); } } @@ -895,12 +911,15 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { } GameInterface = iNESGI; + currCartInfo = &iNESCart; FCEU_printf("\n"); // since apparently the iNES format doesn't store this information, // guess if the settings should be PAL or NTSC from the ROM name // TODO: MD5 check against a list of all known PAL games instead? - if (OverwriteVidMode) { + if (iNES2) { + 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)") @@ -990,6 +1009,7 @@ static int iNES_Init(int num) { case 6: case 29: case 30: + case 45: case 96: CHRRAMSize = 32 * 1024; break; case 176: CHRRAMSize = 128 * 1024; break; default: CHRRAMSize = 8 * 1024; break; @@ -1004,8 +1024,18 @@ static int iNES_Init(int num) { FCEU_MemoryRand(VROM, CHRRAMSize); UNIFchrrama = VROM; - SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); - AddExState(VROM, CHRRAMSize, 0, "CHRR"); + 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 + { + SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); + AddExState(VROM, CHRRAMSize, 0, "CHRR"); + } } if (head.ROM_type & 8) AddExState(ExtraNTARAM, 2048, 0, "EXNR"); diff --git a/source/fceultra/ines.h b/source/fceultra/ines.h index e3ef254..7bcbf47 100644 --- a/source/fceultra/ines.h +++ b/source/fceultra/ines.h @@ -177,6 +177,7 @@ void Mapper105_Init(CartInfo *); void Mapper106_Init(CartInfo *); void Mapper107_Init(CartInfo *); void Mapper108_Init(CartInfo *); +void Mapper111_Init(CartInfo *); void Mapper112_Init(CartInfo *); void Mapper113_Init(CartInfo *); void Mapper114_Init(CartInfo *); diff --git a/source/fceultra/input.cpp b/source/fceultra/input.cpp index a88ea16..adb5b62 100644 --- a/source/fceultra/input.cpp +++ b/source/fceultra/input.cpp @@ -62,6 +62,8 @@ extern INPUTC *FCEU_InitZapper(int w); extern INPUTC *FCEU_InitPowerpadA(int w); 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 INPUTCFC *FCEU_InitArkanoidFC(void); extern INPUTCFC *FCEU_InitSpaceShadow(void); @@ -88,6 +90,7 @@ extern bool movieSubtitles; static uint8 joy_readbit[2]; uint8 joy[4]={0,0,0,0}; //HACK - should be static but movie needs it +uint16 snesjoy[4]={0,0,0,0}; //HACK - should be static but movie needs it static uint8 LastStrobe; uint8 RawReg4016 = 0; // Joystick strobe (W) @@ -107,6 +110,9 @@ static bool FSAttached = false; JOYPORT joyports[2] = { JOYPORT(0), JOYPORT(1) }; FCPORT portFC; +FILE* DumpInputFile; +FILE* PlayInputFile; + static DECLFR(JPRead) { lagFlag = 0; @@ -139,6 +145,12 @@ static DECLFR(JPRead) } } + if(PlayInputFile) + ret = fgetc(PlayInputFile); + + if(DumpInputFile) + fputc(ret,DumpInputFile); + ret|=X.DB&0xC0; return(ret); @@ -305,9 +317,64 @@ static void StrobeGP(int w) //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +//SNES pad + +static void UpdateSNES(int w, void *data, int arg) +{ + //LUA NOT SUPPORTED YET + if(w==0) + { + snesjoy[0]= ((uint32 *)joyports[0].ptr)[0]; + snesjoy[2]= ((uint32 *)joyports[0].ptr)[2]; + } + else + { + snesjoy[1] = ((uint32 *)joyports[0].ptr)[1]; + snesjoy[3] = ((uint32 *)joyports[0].ptr)[3]; + } + +} + +static void LogSNES(int w, MovieRecord* mr) +{ + //not supported for SNES pad right noe +} + +static void LoadSNES(int w, MovieRecord* mr) +{ + //not supported for SNES pad right now +} + + +static uint8 ReadSNES(int w) +{ + //no fourscore support on snes (not clear how it would work) + + uint8 ret; + + if(joy_readbit[w]>=16) + ret = 1; + else + { + ret = ((snesjoy[w]>>(joy_readbit[w]))&1); + } + if(!fceuindbg) + joy_readbit[w]++; + return ret; +} + +static void StrobeSNES(int w) +{ + joy_readbit[w]=0; +} + +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + static INPUTC GPC={ReadGP,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP}; static INPUTC GPCVS={ReadGPVS,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP}; +static INPUTC GPSNES={ReadSNES,0,StrobeSNES,UpdateSNES,0,0,LogSNES,LoadSNES}; void FCEU_DrawInput(uint8 *buf) { @@ -325,7 +392,7 @@ void FCEU_UpdateInput(void) { for(int port=0;port<2;port++){ joyports[port].driver->Update(port,joyports[port].ptr,joyports[port].attrib); - } + } portFC.driver->Update(portFC.ptr,portFC.attrib); } @@ -340,7 +407,7 @@ void FCEU_UpdateInput(void) //TODO - should this apply to the movie data? should this be displayed in the input hud? if(GameInfo->type==GIT_VSUNI){ FCEU_VSUniSwap(&joy[0],&joy[1]); - } + } } static DECLFR(VSUNIRead0) @@ -386,9 +453,12 @@ static void SetInputStuff(int port) case SI_GAMEPAD: if(GameInfo->type==GIT_VSUNI){ joyports[port].driver = &GPCVS; - } else { + } else { joyports[port].driver= &GPC; - } + } + break; + case SI_SNES: + joyports[port].driver= &GPSNES; break; case SI_ARKANOID: joyports[port].driver=FCEU_InitArkanoid(port); @@ -402,6 +472,12 @@ static void SetInputStuff(int port) case SI_POWERPADB: joyports[port].driver=FCEU_InitPowerpadB(port); break; + case SI_MOUSE: + joyports[port].driver=FCEU_InitMouse(port); + break; + case SI_SNES_MOUSE: + joyports[port].driver=FCEU_InitSNESMouse(port); + break; case SI_NONE: joyports[port].driver=&DummyJPort; break; @@ -665,10 +741,11 @@ static void RamSearchOpLTE(void); static void RamSearchOpGTE(void); static void RamSearchOpEQ(void); static void RamSearchOpNE(void); +static void DebuggerStepInto(void); static void FA_SkipLag(void); static void OpenRom(void); static void CloseRom(void); -static void ReloadRom(void); +void ReloadRom(void); static void MovieSubtitleToggle(void); static void UndoRedoSavestate(void); static void FCEUI_DoExit(void); @@ -680,134 +757,139 @@ extern void FCEUI_ToggleShowFPS(); struct EMUCMDTABLE FCEUI_CommandTable[]= { - { EMUCMD_POWER, EMUCMDTYPE_MISC, FCEUI_PowerNES, 0, 0, "Power", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_RESET, EMUCMDTYPE_MISC, FCEUI_ResetNES, 0, 0, "Reset", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_PAUSE, EMUCMDTYPE_MISC, FCEUI_ToggleEmulationPause, 0, 0, "Pause", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_FRAME_ADVANCE, EMUCMDTYPE_MISC, FCEUI_FrameAdvance, FCEUI_FrameAdvanceEnd, 0, "Frame Advance", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SCREENSHOT, EMUCMDTYPE_MISC, FCEUI_SaveSnapshot, 0, 0, "Screenshot", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_HIDE_MENU_TOGGLE, EMUCMDTYPE_MISC, FCEUD_HideMenuToggle, 0, 0, "Hide Menu Toggle", 0 }, - { EMUCMD_EXIT, EMUCMDTYPE_MISC, FCEUI_DoExit, 0, 0, "Exit", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SPEED_SLOWEST, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Slowest Speed", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SPEED_SLOWER, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Speed Down", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SPEED_NORMAL, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Normal Speed", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SPEED_FASTER, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Speed Up", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SPEED_FASTEST, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Fastest Speed", 0 }, - { EMUCMD_SPEED_TURBO, EMUCMDTYPE_SPEED, FCEUD_TurboOn, FCEUD_TurboOff, 0, "Turbo", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SPEED_TURBO_TOGGLE, EMUCMDTYPE_SPEED, FCEUD_TurboToggle, 0, 0, "Turbo Toggle", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_POWER, EMUCMDTYPE_MISC, FCEUI_PowerNES, 0, 0, "Power", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_RESET, EMUCMDTYPE_MISC, FCEUI_ResetNES, 0, 0, "Reset", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_PAUSE, EMUCMDTYPE_MISC, FCEUI_ToggleEmulationPause, 0, 0, "Pause", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_FRAME_ADVANCE, EMUCMDTYPE_MISC, FCEUI_FrameAdvance, FCEUI_FrameAdvanceEnd, 0, "Frame Advance", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SCREENSHOT, EMUCMDTYPE_MISC, FCEUI_SaveSnapshot, 0, 0, "Screenshot", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_HIDE_MENU_TOGGLE, EMUCMDTYPE_MISC, FCEUD_HideMenuToggle, 0, 0, "Hide Menu Toggle", 0 }, + { EMUCMD_EXIT, EMUCMDTYPE_MISC, FCEUI_DoExit, 0, 0, "Exit", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_0, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 0", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_1, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 1", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_2, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 2", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_3, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 3", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_4, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 4", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_5, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 5", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_6, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 6", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_7, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 7", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_8, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 8", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_9, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 9", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_NEXT, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Next Savestate Slot", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_SLOT_PREV, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Previous Savestate Slot", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_AS, EMUCMDTYPE_STATE, FCEUD_SaveStateAs, 0, 0, "Save State As...", 0 }, - { EMUCMD_SAVE_STATE_SLOT_0, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 0", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_1, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 1", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_2, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 2", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_3, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 3", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_4, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 4", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_5, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 5", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_6, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 6", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_7, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 7", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_8, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 8", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SAVE_STATE_SLOT_9, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 9", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_FROM, EMUCMDTYPE_STATE, FCEUD_LoadStateFrom, 0, 0, "Load State From...", 0 }, - { EMUCMD_LOAD_STATE_SLOT_0, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 0", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_1, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 1", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_2, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 2", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_3, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 3", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_4, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 4", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_5, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 5", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_6, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 6", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_7, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 7", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_8, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 8", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_LOAD_STATE_SLOT_9, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 9", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SPEED_SLOWEST, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Slowest Speed", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SPEED_SLOWER, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Speed Down", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SPEED_NORMAL, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Normal Speed", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SPEED_FASTER, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Speed Up", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SPEED_FASTEST, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Fastest Speed", 0 }, + { EMUCMD_SPEED_TURBO, EMUCMDTYPE_SPEED, FCEUD_TurboOn, FCEUD_TurboOff, 0, "Turbo", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SPEED_TURBO_TOGGLE, EMUCMDTYPE_SPEED, FCEUD_TurboToggle, 0, 0, "Turbo Toggle", EMUCMDFLAG_TASEDITOR }, - { 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_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_SAVE_SLOT_0, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 0", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_1, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 1", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_2, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 2", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_3, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 3", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_4, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 4", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_5, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 5", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_6, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 6", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_7, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 7", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_8, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 8", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_9, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Savestate Slot 9", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_NEXT, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Next Savestate Slot", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_SLOT_PREV, EMUCMDTYPE_STATE, CommandSelectSaveSlot, 0, 0, "Previous Savestate Slot", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_AS, EMUCMDTYPE_STATE, FCEUD_SaveStateAs, 0, 0, "Save State As...", 0 }, + { EMUCMD_SAVE_STATE_SLOT_0, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 0", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_1, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 1", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_2, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 2", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_3, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 3", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_4, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 4", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_5, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 5", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_6, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 6", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_7, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 7", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_8, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 8", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SAVE_STATE_SLOT_9, EMUCMDTYPE_STATE, CommandStateSave, 0, 0, "Save State to Slot 9", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_FROM, EMUCMDTYPE_STATE, FCEUD_LoadStateFrom, 0, 0, "Load State From...", 0 }, + { EMUCMD_LOAD_STATE_SLOT_0, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 0", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_1, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 1", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_2, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 2", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_3, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 3", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_4, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 4", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_5, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 5", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_6, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 6", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_7, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 7", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_8, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 8", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_LOAD_STATE_SLOT_9, EMUCMDTYPE_STATE, CommandStateLoad, 0, 0, "Load State from Slot 9", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleInputDisplay, 0, 0, "Toggle Input Display", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MOVIE_ICON_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUD_ToggleStatusIcon, 0, 0, "Toggle Status Icon", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MOVIE_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_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_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 }, #ifdef _S9XLUA_H - { EMUCMD_SCRIPT_RELOAD, EMUCMDTYPE_MISC, FCEU_ReloadLuaCode, 0, 0, "Reload current Lua script", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SCRIPT_RELOAD, EMUCMDTYPE_MISC, FCEU_ReloadLuaCode, 0, 0, "Reload current Lua script", EMUCMDFLAG_TASEDITOR }, #endif - { EMUCMD_SOUND_TOGGLE, EMUCMDTYPE_SOUND, FCEUD_SoundToggle, 0, 0, "Sound Mute Toggle", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SOUND_VOLUME_UP, EMUCMDTYPE_SOUND, CommandSoundAdjust, 0, 0, "Sound Volume Up", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SOUND_VOLUME_DOWN, EMUCMDTYPE_SOUND, CommandSoundAdjust, 0, 0, "Sound Volume Down", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_SOUND_VOLUME_NORMAL, EMUCMDTYPE_SOUND, CommandSoundAdjust, 0, 0, "Sound Volume Normal", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SOUND_TOGGLE, EMUCMDTYPE_SOUND, FCEUD_SoundToggle, 0, 0, "Sound Mute Toggle", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SOUND_VOLUME_UP, EMUCMDTYPE_SOUND, CommandSoundAdjust, 0, 0, "Sound Volume Up", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SOUND_VOLUME_DOWN, EMUCMDTYPE_SOUND, CommandSoundAdjust, 0, 0, "Sound Volume Down", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_SOUND_VOLUME_NORMAL, EMUCMDTYPE_SOUND, CommandSoundAdjust, 0, 0, "Sound Volume Normal", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_AVI_RECORD_AS, EMUCMDTYPE_AVI, FCEUD_AviRecordTo, 0, 0, "Record AVI As...", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_AVI_STOP, EMUCMDTYPE_AVI, FCEUD_AviStop, 0, 0, "Stop AVI", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_AVI_RECORD_AS, EMUCMDTYPE_AVI, FCEUD_AviRecordTo, 0, 0, "Record AVI As...", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_AVI_STOP, EMUCMDTYPE_AVI, FCEUD_AviStop, 0, 0, "Stop AVI", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_FDS_EJECT_INSERT, EMUCMDTYPE_FDS, FCEUI_FDSInsert, 0, 0, "Eject or Insert FDS Disk", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_FDS_SIDE_SELECT, EMUCMDTYPE_FDS, FCEUI_FDSSelect, 0, 0, "Switch FDS Disk Side", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_FDS_EJECT_INSERT, EMUCMDTYPE_FDS, FCEUI_FDSInsert, 0, 0, "Eject or Insert FDS Disk", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_FDS_SIDE_SELECT, EMUCMDTYPE_FDS, FCEUI_FDSSelect, 0, 0, "Switch FDS Disk Side", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_VSUNI_TOGGLE_DIP_0, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 0", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_1, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 1", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_2, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 2", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_3, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 3", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_4, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 4", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_5, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 5", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_6, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 6", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 7", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_8, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 8", 0 }, - { EMUCMD_VSUNI_TOGGLE_DIP_9, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 9", 0 }, - { EMUCMD_MISC_AUTOSAVE, EMUCMDTYPE_MISC, FCEUI_RewindToLastAutosave, 0, 0, "Load Last Auto-save", 0}, - { EMUCMD_MISC_SHOWSTATES, EMUCMDTYPE_MISC, ViewSlots, 0, 0, "View save slots", 0 }, - { EMUCMD_MISC_USE_INPUT_PRESET_1, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 1", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_USE_INPUT_PRESET_2, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 2", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_USE_INPUT_PRESET_3, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 3", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_DISPLAY_BG_TOGGLE, EMUCMDTYPE_MISC, BackgroundDisplayToggle, 0, 0, "Toggle Background Display", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_DISPLAY_OBJ_TOGGLE, EMUCMDTYPE_MISC, ObjectDisplayToggle, 0, 0, "Toggle Object Display", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_DISPLAY_LAGCOUNTER_TOGGLE,EMUCMDTYPE_MISC, LagCounterToggle, 0, 0, "Lag Counter Toggle", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_OPENTASEDITOR, EMUCMDTYPE_TOOL, LaunchTasEditor, 0, 0, "Open TAS Editor", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENMEMORYWATCH, EMUCMDTYPE_TOOL, LaunchMemoryWatch,0, 0, "Open Memory Watch", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENCHEATS, EMUCMDTYPE_TOOL, LaunchCheats, 0, 0, "Open Cheats", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENDEBUGGER, EMUCMDTYPE_TOOL, LaunchDebugger, 0, 0, "Open Debugger", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENHEX, EMUCMDTYPE_TOOL, LaunchHex, 0, 0, "Open Hex Editor", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENPPU, EMUCMDTYPE_TOOL, LaunchPPU, 0, 0, "Open PPU Viewer", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENNTVIEW, EMUCMDTYPE_TOOL, LaunchNTView, 0, 0, "Open Name Table Viewer", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENTRACELOGGER, EMUCMDTYPE_TOOL, LaunchTraceLogger, 0, 0, "Open Trace Logger", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENCDLOGGER, EMUCMDTYPE_TOOL, LaunchCodeDataLogger, 0, 0, "Open Code/Data Logger", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_FRAMEADV_SKIPLAG, EMUCMDTYPE_MISC, FA_SkipLag, 0, 0, "Frame Adv.-Skip Lag", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_OPENROM, EMUCMDTYPE_TOOL, OpenRom, 0, 0, "Open ROM", 0}, - { EMUCMD_CLOSEROM, EMUCMDTYPE_TOOL, CloseRom, 0, 0, "Close ROM", 0}, - { EMUCMD_RELOAD, EMUCMDTYPE_TOOL, ReloadRom, 0, 0, "Reload ROM or TAS Editor Project", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_DISPLAY_MOVIESUBTITLES, EMUCMDTYPE_MISC, MovieSubtitleToggle,0,0,"Toggle Movie Subtitles", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_MISC_UNDOREDOSAVESTATE, EMUCMDTYPE_MISC, UndoRedoSavestate, 0,0,"Undo/Redo Savestate", 0}, - { EMUCMD_MISC_TOGGLEFULLSCREEN, EMUCMDTYPE_MISC, ToggleFullscreen, 0, 0, "Toggle Fullscreen", 0}, - { EMUCMD_TOOL_OPENRAMWATCH, EMUCMDTYPE_TOOL, LaunchRamWatch, 0, 0, "Open Ram Watch", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_OPENRAMSEARCH, EMUCMDTYPE_TOOL, LaunchRamSearch, 0, 0, "Open Ram Search", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TOOL_RAMSEARCHLT, EMUCMDTYPE_TOOL, RamSearchOpLT, 0, 0, "Ram Search - Less Than", 0}, - { EMUCMD_TOOL_RAMSEARCHGT, EMUCMDTYPE_TOOL, RamSearchOpGT, 0, 0, "Ram Search - Greater Than", 0}, - { EMUCMD_TOOL_RAMSEARCHLTE, EMUCMDTYPE_TOOL, RamSearchOpLTE, 0, 0, "Ram Search - Less Than or Equal", 0}, - { EMUCMD_TOOL_RAMSEARCHGTE, EMUCMDTYPE_TOOL, RamSearchOpGTE, 0, 0, "Ram Search - Greater Than or Equal", 0}, - { EMUCMD_TOOL_RAMSEARCHEQ, EMUCMDTYPE_TOOL, RamSearchOpEQ, 0, 0, "Ram Search - Equal", 0}, - { EMUCMD_TOOL_RAMSEARCHNE, EMUCMDTYPE_TOOL, RamSearchOpNE, 0, 0, "Ram Search - Not Equal", 0}, - { EMUCMD_RERECORD_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_MovieToggleRerecordDisplay, 0, 0, "Toggle Rerecord Display", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TASEDITOR_REWIND, EMUCMDTYPE_TASEDITOR, TaseditorRewindOn, TaseditorRewindOff, 0, "Frame Rewind", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TASEDITOR_RESTORE_PLAYBACK, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Restore Playback", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TASEDITOR_CANCEL_SEEKING, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Cancel Seeking", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TASEDITOR_SWITCH_AUTORESTORING, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Switch Auto-restore last position", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TASEDITOR_SWITCH_MULTITRACKING, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Switch current Multitracking mode", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_TASEDITOR_RUN_MANUAL_LUA, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Run Manual Lua function", EMUCMDFLAG_TASEDITOR }, - { EMUCMD_FPS_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleShowFPS, 0, 0, "Toggle FPS Display", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_VSUNI_TOGGLE_DIP_0, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 0", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_1, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 1", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_2, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 2", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_3, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 3", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_4, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 4", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_5, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 5", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_6, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 6", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 7", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_8, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 8", 0 }, + { EMUCMD_VSUNI_TOGGLE_DIP_9, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 9", 0 }, + + { EMUCMD_MISC_AUTOSAVE, EMUCMDTYPE_MISC, FCEUI_RewindToLastAutosave, 0, 0, "Load Last Auto-save", 0}, + { EMUCMD_MISC_SHOWSTATES, EMUCMDTYPE_MISC, ViewSlots, 0, 0, "View save slots", 0 }, + { EMUCMD_MISC_USE_INPUT_PRESET_1, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 1", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MISC_USE_INPUT_PRESET_2, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 2", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MISC_USE_INPUT_PRESET_3, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 3", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MISC_DISPLAY_BG_TOGGLE, EMUCMDTYPE_MISC, BackgroundDisplayToggle, 0, 0, "Toggle Background Display", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MISC_DISPLAY_OBJ_TOGGLE, EMUCMDTYPE_MISC, ObjectDisplayToggle, 0, 0, "Toggle Object Display", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MISC_DISPLAY_LAGCOUNTER_TOGGLE,EMUCMDTYPE_MISC, LagCounterToggle, 0, 0, "Lag Counter Toggle", EMUCMDFLAG_TASEDITOR }, + + { EMUCMD_MISC_OPENTASEDITOR, EMUCMDTYPE_TOOL, LaunchTasEditor, 0, 0, "Open TAS Editor", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENMEMORYWATCH, EMUCMDTYPE_TOOL, LaunchMemoryWatch, 0, 0, "Open Memory Watch", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENCHEATS, EMUCMDTYPE_TOOL, LaunchCheats, 0, 0, "Open Cheats", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENDEBUGGER, EMUCMDTYPE_TOOL, LaunchDebugger, 0, 0, "Open Debugger", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENHEX, EMUCMDTYPE_TOOL, LaunchHex, 0, 0, "Open Hex Editor", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENPPU, EMUCMDTYPE_TOOL, LaunchPPU, 0, 0, "Open PPU Viewer", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENNTVIEW, EMUCMDTYPE_TOOL, LaunchNTView, 0, 0, "Open Name Table Viewer", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENTRACELOGGER, EMUCMDTYPE_TOOL, LaunchTraceLogger, 0, 0, "Open Trace Logger", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENCDLOGGER, EMUCMDTYPE_TOOL, LaunchCodeDataLogger, 0, 0, "Open Code/Data Logger", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_FRAMEADV_SKIPLAG, EMUCMDTYPE_MISC, FA_SkipLag, 0, 0, "Frame Adv.-Skip Lag", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_OPENROM, EMUCMDTYPE_TOOL, OpenRom, 0, 0, "Open ROM", 0}, + { EMUCMD_CLOSEROM, EMUCMDTYPE_TOOL, CloseRom, 0, 0, "Close ROM", 0}, + { EMUCMD_RELOAD, EMUCMDTYPE_TOOL, ReloadRom, 0, 0, "Reload ROM or TAS Editor Project", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MISC_DISPLAY_MOVIESUBTITLES, EMUCMDTYPE_MISC, MovieSubtitleToggle, 0, 0, "Toggle Movie Subtitles", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_MISC_UNDOREDOSAVESTATE, EMUCMDTYPE_MISC, UndoRedoSavestate, 0, 0, "Undo/Redo Savestate", 0}, + { EMUCMD_MISC_TOGGLEFULLSCREEN, EMUCMDTYPE_MISC, ToggleFullscreen, 0, 0, "Toggle Fullscreen", 0}, + { EMUCMD_TOOL_OPENRAMWATCH, EMUCMDTYPE_TOOL, LaunchRamWatch, 0, 0, "Open Ram Watch", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_OPENRAMSEARCH, EMUCMDTYPE_TOOL, LaunchRamSearch, 0, 0, "Open Ram Search", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_RAMSEARCHLT, EMUCMDTYPE_TOOL, RamSearchOpLT, 0, 0, "Ram Search - Less Than", 0}, + { EMUCMD_TOOL_RAMSEARCHGT, EMUCMDTYPE_TOOL, RamSearchOpGT, 0, 0, "Ram Search - Greater Than", 0}, + { EMUCMD_TOOL_RAMSEARCHLTE, EMUCMDTYPE_TOOL, RamSearchOpLTE, 0, 0, "Ram Search - Less Than or Equal", 0}, + { EMUCMD_TOOL_RAMSEARCHGTE, EMUCMDTYPE_TOOL, RamSearchOpGTE, 0, 0, "Ram Search - Greater Than or Equal", 0}, + { EMUCMD_TOOL_RAMSEARCHEQ, EMUCMDTYPE_TOOL, RamSearchOpEQ, 0, 0, "Ram Search - Equal", 0}, + { EMUCMD_TOOL_RAMSEARCHNE, EMUCMDTYPE_TOOL, RamSearchOpNE, 0, 0, "Ram Search - Not Equal", 0}, + { EMUCMD_RERECORD_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_MovieToggleRerecordDisplay,0, 0, "Toggle Rerecord Display", EMUCMDFLAG_TASEDITOR }, + + { EMUCMD_TASEDITOR_REWIND, EMUCMDTYPE_TASEDITOR, TaseditorRewindOn, TaseditorRewindOff, 0, "Frame Rewind", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TASEDITOR_RESTORE_PLAYBACK, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Restore Playback", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TASEDITOR_CANCEL_SEEKING, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Cancel Seeking", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TASEDITOR_SWITCH_AUTORESTORING,EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Switch Auto-restore last position", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TASEDITOR_SWITCH_MULTITRACKING,EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Switch current Multitracking mode", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TASEDITOR_RUN_MANUAL_LUA, EMUCMDTYPE_TASEDITOR, TaseditorCommand, 0, 0, "Run Manual Lua function", EMUCMDFLAG_TASEDITOR }, + + { EMUCMD_FPS_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleShowFPS, 0, 0, "Toggle FPS Display", EMUCMDFLAG_TASEDITOR }, + { EMUCMD_TOOL_DEBUGSTEPINTO, EMUCMDTYPE_TOOL, DebuggerStepInto, 0, 0, "Debugger - Step Into", EMUCMDFLAG_TASEDITOR }, }; #define NUM_EMU_CMDS (sizeof(FCEUI_CommandTable)/sizeof(FCEUI_CommandTable[0])) @@ -1119,6 +1201,17 @@ static void RamSearchOpNE(void) { #endif } +static void DebuggerStepInto() +{ +#ifdef WIN32 + if (GameInfo) + { + extern void DoDebuggerStepInto(); + DoDebuggerStepInto(); + } +#endif +} + static void FA_SkipLag(void) { frameAdvanceLagSkip ^= 1; @@ -1139,7 +1232,7 @@ static void CloseRom(void) #endif } -static void ReloadRom(void) +void ReloadRom(void) { #ifdef WIN32 if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) diff --git a/source/fceultra/input.h b/source/fceultra/input.h index 3c89509..a4ba162 100644 --- a/source/fceultra/input.h +++ b/source/fceultra/input.h @@ -8,6 +8,10 @@ void LagCounterToggle(void); +extern FILE* PlayInputFile; +extern FILE* DumpInputFile; + + class MovieRecord; //MBG TODO - COMBINE THESE INPUTC AND INPUTCFC @@ -242,6 +246,7 @@ enum EMUCMD //----------------------------- //keep adding these in order of newness or else the hotkey binding configs will get messed up... EMUCMD_FPS_DISPLAY_TOGGLE, + EMUCMD_TOOL_DEBUGSTEPINTO, EMUCMD_MAX }; diff --git a/source/fceultra/input/mouse.cpp b/source/fceultra/input/mouse.cpp index 2f58c73..1976825 100644 --- a/source/fceultra/input/mouse.cpp +++ b/source/fceultra/input/mouse.cpp @@ -18,64 +18,66 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +// implementation of Subor Mouse +// used in Educational Computer 2000 + #include #include #include "share.h" typedef struct { - int32 mzx, mzy, mzxold, mzyold; - uint32 readbit; - uint32 data; + uint8 latch; + int32 dx,dy; + uint32 mb; } MOUSE; static MOUSE Mouse; +// since this game only picks up 1 mickey per frame, +// allow a single delta to spread out over a few frames +// to make it easier to move. +const int INERTIA = 32; + static void StrobeMOUSE(int w) { - Mouse.readbit=0; + Mouse.latch = Mouse.mb & 0x03; + + int32 dx = Mouse.dx; + int32 dy = Mouse.dy; + + if (dx > 0) { Mouse.latch |= (0x2 << 2); --Mouse.dx; } + else if (dx < 0) { Mouse.latch |= (0x3 << 2); ++Mouse.dx; } + if (dy > 0) { Mouse.latch |= (0x2 << 4); --Mouse.dy; } + else if (dy < 0) { Mouse.latch |= (0x3 << 4); ++Mouse.dy; } + + //FCEU_printf("Subor Mouse: %02X\n",Mouse.latch); } static uint8 ReadMOUSE(int w) { - uint8 ret=0; - if(Mouse.readbit>=8) - ret|=1; - else - { - ret|=(Mouse.data>>Mouse.readbit)&1; - if(!fceuindbg) - Mouse.readbit++; - } - return(ret); + uint8 result = Mouse.latch & 0x01; + Mouse.latch = (Mouse.latch >> 1) | 0x80; + return result; } static void UpdateMOUSE(int w, void *data, int arg) { - uint32 *ptr=(uint32*)data; - Mouse.data=0; - Mouse.mzxold=Mouse.mzx; - Mouse.mzyold=Mouse.mzy; - Mouse.mzx=ptr[0]; - Mouse.mzy=ptr[1]; - Mouse.data|=ptr[2]; - if((Mouse.mzxold-Mouse.mzx)>0) - Mouse.data|=0x0C; - else if((Mouse.mzxold-Mouse.mzx)<0) - Mouse.data|=0x04; - if((Mouse.mzyold-Mouse.mzy)>0) - Mouse.data|=0x30; - else if((Mouse.mzyold-Mouse.mzy)<0) - Mouse.data|=0x10; + uint32 *ptr=(uint32*)data; + Mouse.dx += ptr[0]; ptr[0] = 0; + Mouse.dy += ptr[1]; ptr[1] = 0; + Mouse.mb = ptr[2]; + + if (Mouse.dx > INERTIA) Mouse.dx = INERTIA; + else if (Mouse.dx < -INERTIA) Mouse.dx = -INERTIA; + + if (Mouse.dy > INERTIA) Mouse.dy = INERTIA; + else if (Mouse.dy < -INERTIA) Mouse.dy = -INERTIA; } static INPUTC MOUSEC={ReadMOUSE,0,StrobeMOUSE,UpdateMOUSE,0,0}; INPUTC *FCEU_InitMouse(int w) { - Mouse.mzx=0; - Mouse.mzy=0; - Mouse.mzxold=0; - Mouse.mzyold=0; - Mouse.data=0; - return(&MOUSEC); + memset(&Mouse,0,sizeof(Mouse)); + return(&MOUSEC); } diff --git a/source/fceultra/input/pec586kb.cpp b/source/fceultra/input/pec586kb.cpp index bdc00c6..5288760 100644 --- a/source/fceultra/input/pec586kb.cpp +++ b/source/fceultra/input/pec586kb.cpp @@ -1,96 +1,96 @@ -/* 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 -#include "share.h" -#include "suborkb.h" - -#define AK(x) FKB_ ## x - -static uint8 bufit[0x66]; -static uint8 kspos, kstrobe; -static uint8 ksindex; - -//TODO: check all keys, some of the are wrong - -static uint16 matrix[13][8] = -{ - { AK(ESCAPE),AK(SPACE),AK(LMENU),AK(LCONTROL),AK(LSHIFT),AK(GRAVE),AK(TAB),AK(CAPITAL) }, - { AK(F6),AK(F7),AK(F5),AK(F4),AK(F8),AK(F2),AK(F1),AK(F3) }, - { AK(EQUALS), AK(NUMPAD0),AK(PERIOD),AK(A),AK(RETURN),AK(1),AK(Q),AK(Z) }, - { 0, AK(NUMPAD3),AK(NUMPAD6),AK(S),AK(NUMPAD9),AK(2),AK(W),AK(X) }, - { AK(SLASH), AK(NUMPAD2),AK(NUMPAD5),AK(D),AK(NUMPAD8),AK(3),AK(E),AK(C) }, - { AK(BREAK), AK(NUMPAD1),AK(NUMPAD4),AK(F),AK(NUMPAD7),AK(4),AK(R),AK(V) }, - { AK(BACK),AK(BACKSLASH),AK(GRETURN),AK(G),AK(RBRACKET),AK(5),AK(T),AK(B) }, - { AK(9),AK(PERIOD),AK(L),AK(K),AK(O),AK(8),AK(I),AK(COMMA) }, - { AK(0),AK(SLASH),AK(SEMICOLON),AK(J),AK(P),AK(7),AK(U),AK(M) }, - { AK(MINUS),AK(MINUS),AK(APOSTROPHE),AK(H),AK(LBRACKET),AK(6),AK(Y),AK(N) }, - { AK(F11),AK(F12),AK(F10),0,AK(MINUS),AK(F9),0,0 }, - { AK(UP),AK(RIGHT),AK(DOWN),AK(DIVIDE),AK(LEFT),AK(MULTIPLY),AK(SUBTRACT),AK(ADD) }, - { AK(INSERT),AK(NUMPAD1),AK(HOME),AK(PRIOR),AK(DELETE),AK(END),AK(NEXT),AK(NUMLOCK) }, -}; - -static void PEC586KB_Write(uint8 v) { - if (!(kstrobe & 2) && (v & 2)) { - kspos = 0; - } - if ((kstrobe & 1) && !(v & 1)) { - ksindex = 0; - } - if ((kstrobe & 4) && !(v & 4)) { - kspos++; - kspos %= 13; - } - kstrobe = v; -} - -static uint8 PEC586KB_Read(int w, uint8 ret) { -#ifdef FCEUDEF_DEBUGGER - if (!fceuindbg) { -#endif - if (w) { - ret &= ~2; - if(bufit[matrix[kspos][7-ksindex]]) - ret |= 2; - ksindex++; - ksindex&=7; - } -#ifdef FCEUDEF_DEBUGGER - } -#endif - return(ret); -} - -static void PEC586KB_Strobe(void) { -// kstrobe = 0; -// ksindex = 0; -} - -static void PEC586KB_Update(void *data, int arg) { - memcpy(bufit + 1, data, sizeof(bufit) - 1); -} - -static INPUTCFC PEC586KB = { PEC586KB_Read, PEC586KB_Write, PEC586KB_Strobe, PEC586KB_Update, 0, 0 }; - -INPUTCFC *FCEU_InitPEC586KB(void) { - memset(bufit, 0, sizeof(bufit)); - kspos = ksindex = kstrobe = 0; - return(&PEC586KB); -} +/* 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 +#include "share.h" +#include "suborkb.h" + +#define AK(x) FKB_ ## x + +static uint8 bufit[0x66]; +static uint8 kspos, kstrobe; +static uint8 ksindex; + +//TODO: check all keys, some of the are wrong + +static uint16 matrix[13][8] = +{ + { AK(ESCAPE),AK(SPACE),AK(LMENU),AK(LCONTROL),AK(LSHIFT),AK(GRAVE),AK(TAB),AK(CAPITAL) }, + { AK(F6),AK(F7),AK(F5),AK(F4),AK(F8),AK(F2),AK(F1),AK(F3) }, + { AK(EQUALS), AK(NUMPAD0),AK(PERIOD),AK(A),AK(RETURN),AK(1),AK(Q),AK(Z) }, + { 0, AK(NUMPAD3),AK(NUMPAD6),AK(S),AK(NUMPAD9),AK(2),AK(W),AK(X) }, + { AK(SLASH), AK(NUMPAD2),AK(NUMPAD5),AK(D),AK(NUMPAD8),AK(3),AK(E),AK(C) }, + { AK(BREAK), AK(NUMPAD1),AK(NUMPAD4),AK(F),AK(NUMPAD7),AK(4),AK(R),AK(V) }, + { AK(BACK),AK(BACKSLASH),AK(GRETURN),AK(G),AK(RBRACKET),AK(5),AK(T),AK(B) }, + { AK(9),AK(PERIOD),AK(L),AK(K),AK(O),AK(8),AK(I),AK(COMMA) }, + { AK(0),AK(SLASH),AK(SEMICOLON),AK(J),AK(P),AK(7),AK(U),AK(M) }, + { AK(MINUS),AK(MINUS),AK(APOSTROPHE),AK(H),AK(LBRACKET),AK(6),AK(Y),AK(N) }, + { AK(F11),AK(F12),AK(F10),0,AK(MINUS),AK(F9),0,0 }, + { AK(UP),AK(RIGHT),AK(DOWN),AK(DIVIDE),AK(LEFT),AK(MULTIPLY),AK(SUBTRACT),AK(ADD) }, + { AK(INSERT),AK(NUMPAD1),AK(HOME),AK(PRIOR),AK(DELETE),AK(END),AK(NEXT),AK(NUMLOCK) }, +}; + +static void PEC586KB_Write(uint8 v) { + if (!(kstrobe & 2) && (v & 2)) { + kspos = 0; + } + if ((kstrobe & 1) && !(v & 1)) { + ksindex = 0; + } + if ((kstrobe & 4) && !(v & 4)) { + kspos++; + kspos %= 13; + } + kstrobe = v; +} + +static uint8 PEC586KB_Read(int w, uint8 ret) { +#ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) { +#endif + if (w) { + ret &= ~2; + if(bufit[matrix[kspos][7-ksindex]]) + ret |= 2; + ksindex++; + ksindex&=7; + } +#ifdef FCEUDEF_DEBUGGER + } +#endif + return(ret); +} + +static void PEC586KB_Strobe(void) { +// kstrobe = 0; +// ksindex = 0; +} + +static void PEC586KB_Update(void *data, int arg) { + memcpy(bufit + 1, data, sizeof(bufit) - 1); +} + +static INPUTCFC PEC586KB = { PEC586KB_Read, PEC586KB_Write, PEC586KB_Strobe, PEC586KB_Update, 0, 0 }; + +INPUTCFC *FCEU_InitPEC586KB(void) { + memset(bufit, 0, sizeof(bufit)); + kspos = ksindex = kstrobe = 0; + return(&PEC586KB); +} diff --git a/source/fceultra/movie.cpp b/source/fceultra/movie.cpp index 4c20fa5..37b32b9 100644 --- a/source/fceultra/movie.cpp +++ b/source/fceultra/movie.cpp @@ -11,6 +11,7 @@ #include "file.h" #include "video.h" #include "movie.h" +#include "cart.h" #include "fds.h" #include "vsuni.h" #ifdef _S9XLUA_H @@ -34,6 +35,9 @@ extern void AddRecentMovieFile(const char *filename); extern bool mustEngageTaseditor; #endif +extern int RAMInitOption; +extern int RAMInitSeed; + #include #include #include @@ -107,7 +111,6 @@ int currRerecordCount; // Keep the global value char lagcounterbuf[32] = {0}; - #ifdef GEKKO void MovieData::clearRecordRange(int start, int len) { } void MovieData::eraseRecords(int at, int frames) { } @@ -454,8 +457,11 @@ void MovieRecord::dump(MovieData* md, EMUFILE* os, int index) MovieData::MovieData() : version(MOVIE_VERSION) , emuVersion(FCEU_VERSION_NUMERIC) + , fds(false) , palFlag(false) , PPUflag(false) + , RAMInitOption(0) + , RAMInitSeed(0) , rerecordCount(0) , binaryFlag(false) , loadFrameCount(-1) @@ -476,6 +482,10 @@ void MovieData::installValue(std::string& key, std::string& val) installInt(val,fds); else if(key == "NewPPU") installBool(val,PPUflag); + else if(key == "RAMInitOption") + installInt(val,RAMInitOption); + else if(key == "RAMInitSeed") + installInt(val,RAMInitSeed); else if(key == "version") installInt(val,version); else if(key == "emuVersion") @@ -516,6 +526,16 @@ void MovieData::installValue(std::string& key, std::string& val) StringToBytes(val,&savestate[0],len); // decodes either base64 or hex } } + else if(key == "saveram") + { + int len = Base64StringToBytesLength(val); + if(len == -1) len = HexStringToBytesLength(val); // wasn't base64, try hex + if(len >= 1) + { + saveram.resize(len); + StringToBytes(val,&saveram[0],len); // decodes either base64 or hex + } + } else if (key == "length") { installInt(val, loadFrameCount); @@ -539,6 +559,8 @@ int MovieData::dump(EMUFILE *os, bool binary) os->fprintf("port2 %d\n" , ports[2] ); os->fprintf("FDS %d\n" , fds?1:0 ); os->fprintf("NewPPU %d\n" , PPUflag?1:0 ); + os->fprintf("RAMInitOption %d\n", RAMInitOption); + os->fprintf("RAMInitSeed %d\n", RAMInitSeed); for(uint32 i=0;ifprintf("comment %s\n" , wcstombs(comments[i]).c_str() ); @@ -552,6 +574,9 @@ int MovieData::dump(EMUFILE *os, bool binary) if(savestate.size()) os->fprintf("savestate %s\n" , BytesToString(&savestate[0],savestate.size()).c_str() ); + if(saveram.size()) + os->fprintf("saveram %s\n" , BytesToString(&saveram[0],saveram.size()).c_str() ); + if (this->loadFrameCount >= 0) os->fprintf("length %d\n" , this->loadFrameCount); @@ -831,6 +856,8 @@ void FCEUI_StopMovie() #endif } +bool bogorf; + void poweron(bool shouldDisableBatteryLoading) { //// make a for-movie-recording power-on clear the game's save data, too @@ -855,9 +882,9 @@ void poweron(bool shouldDisableBatteryLoading) //suppressAddPowerCommand=0; extern int disableBatteryLoading; - disableBatteryLoading = 1; + if(!bogorf) disableBatteryLoading = 1; PowerNES(); - disableBatteryLoading = 0; + if(!bogorf) disableBatteryLoading = 0; } void FCEUMOV_CreateCleanMovie() @@ -874,6 +901,8 @@ void FCEUMOV_CreateCleanMovie() currMovieData.ports[2] = portFC.type; currMovieData.fds = isFDS; currMovieData.PPUflag = (newppu != 0); + currMovieData.RAMInitOption = RAMInitOption; + currMovieData.RAMInitSeed = RAMInitSeed; } void FCEUMOV_ClearCommands() { @@ -897,6 +926,59 @@ void MovieData::dumpSavestateTo(std::vector* buf, int compressionLevel) ms.trim(); } +bool MovieData::loadSaveramFrom(std::vector* buf) +{ + EMUFILE_MEMORY ms(buf); + + bool hasBattery = !!ms.read32le(); + if(hasBattery != !!currCartInfo->battery) + { + FCEU_PrintError("movie battery load mismatch 1"); + return false; + } + + for(int i=0;i<4;i++) + { + int len = ms.read32le(); + + if(!currCartInfo->SaveGame[i] && len!=0) + { + FCEU_PrintError("movie battery load mismatch 2"); + return false; + } + + if(currCartInfo->SaveGameLen[i] != len) + { + FCEU_PrintError("movie battery load mismatch 3"); + return false; + } + + ms.fread(currCartInfo->SaveGame[i], len); + } + + return true; +} + +void MovieData::dumpSaveramTo(std::vector* buf, int compressionLevel) +{ + EMUFILE_MEMORY ms(buf); + + ms.write32le(currCartInfo->battery?1:0); + for(int i=0;i<4;i++) + { + if(!currCartInfo->SaveGame[i]) + { + ms.write32le((u32)0); + continue; + } + + ms.write32le(currCartInfo->SaveGameLen[i]); + ms.fwrite(currCartInfo->SaveGame[i], currCartInfo->SaveGameLen[i]); + } + +} + + //begin playing an existing movie bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) { @@ -938,6 +1020,9 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) LoadSubtitles(currMovieData); delete fp; + RAMInitOption = currMovieData.RAMInitOption; + RAMInitSeed = currMovieData.RAMInitSeed; + 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 //fully reload the game to reinitialize everything before playing any movie @@ -949,7 +1034,14 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) movieFromPoweron = false; bool success = MovieData::loadSavestateFrom(&currMovieData.savestate); if(!success) return true; //adelikat: I guess return true here? False is only for a bad movie filename, if it got this far the file was good? - } else { + } + else if(currMovieData.saveram.size()) + { + movieFromPoweron = true; + bool success = MovieData::loadSaveramFrom(&currMovieData.saveram); + if(!success) return true; //adelikat: I guess return true here? False is only for a bad movie filename, if it got this far the file was good? + } + else { movieFromPoweron = true; } @@ -960,6 +1052,8 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) else FCEUI_SetVidSystem(0); + + //force the input configuration stored in the movie to apply FCEUD_SetInput(currMovieData.fourscore, currMovieData.microphone, (ESI)currMovieData.ports[0], (ESI)currMovieData.ports[1], (ESIFC)currMovieData.ports[2]); @@ -1027,7 +1121,15 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author) movieFromPoweron = true; poweron(true); } - else + else if(flags & MOVIE_FLAG_FROM_SAVERAM) + { + movieFromPoweron = true; + MovieData::dumpSaveramTo(&currMovieData.saveram,Z_NO_COMPRESSION); //i guess with this there's a chance someone could hack the file, at least, so maybe it's helpfu + bogorf = true; + poweron(false); + bogorf = false; + } + else //from savestate { movieFromPoweron = false; MovieData::dumpSavestateTo(&currMovieData.savestate,Z_BEST_COMPRESSION); @@ -1481,7 +1583,7 @@ void FCEUMOV_IncrementRerecordCount() else currMovieData.rerecordCount++; #else - if (movieMode != MOVIEMODE_TASEDITOR)currRerecordCount++; + if (movieMode != MOVIEMODE_TASEDITOR) currRerecordCount++; else currMovieData.rerecordCount++; @@ -1627,6 +1729,8 @@ bool FCEUI_MovieGetInfo(FCEUFILE* fp, MOVIE_INFO& info, bool skipFrameCount) info.reset = false; //Soft-reset isn't used from starting movies anymore, so this will be false, better for FCEUFILE to have that info (as |1| on the first frame indicates it info.pal = md.palFlag; info.ppuflag = md.PPUflag; + info.RAMInitOption = md.RAMInitOption; + info.RAMInitSeed = md.RAMInitSeed; info.nosynchack = true; info.num_frames = md.records.size(); info.md5_of_rom_used = md.romChecksum; diff --git a/source/fceultra/movie.h b/source/fceultra/movie.h index 783e5b9..a19d25b 100644 --- a/source/fceultra/movie.h +++ b/source/fceultra/movie.h @@ -23,13 +23,15 @@ enum EMOVIE_FLAG MOVIE_FLAG_PAL = (1<<2), - //movie was recorded from poweron. the alternative is from a savestate (or from reset) + //movie was recorded from poweron. the alternative is from a savestate (or from reset). OR from saveram. MOVIE_FLAG_FROM_POWERON = (1<<3), // set in newer version, used for old movie compatibility //TODO - only use this flag to print a warning that the sync might be bad //so that we can get rid of the sync hack code - MOVIE_FLAG_NOSYNCHACK = (1<<4) + MOVIE_FLAG_NOSYNCHACK = (1<<4), + + MOVIE_FLAG_FROM_SAVERAM = (1<<5) }; typedef struct @@ -42,6 +44,7 @@ typedef struct uint32 emu_version_used; // 9813 = 0.98.13 MD5DATA md5_of_rom_used; std::string name_of_rom_used; + int RAMInitOption, RAMInitSeed; std::vector comments; std::vector subtitles; @@ -177,6 +180,7 @@ public: MD5DATA romChecksum; std::string romFilename; std::vector savestate; + std::vector saveram; std::vector records; std::vector comments; std::vector subtitles; @@ -198,6 +202,8 @@ public: int getNumRecords() { return records.size(); } + int RAMInitOption, RAMInitSeed; + class TDictionary : public std::map { public: @@ -238,6 +244,9 @@ public: static bool loadSavestateFrom(std::vector* buf); static void dumpSavestateTo(std::vector* buf, int compressionLevel); + static bool loadSaveramFrom(std::vector* buf); + static void dumpSaveramTo(std::vector* buf, int compressionLevel); + private: void installInt(std::string& val, int& var) { diff --git a/source/fceultra/netplay.cpp b/source/fceultra/netplay.cpp index ce6d9a3..4d2003a 100644 --- a/source/fceultra/netplay.cpp +++ b/source/fceultra/netplay.cpp @@ -119,7 +119,7 @@ int FCEUNET_SendFile(uint8 cmd, char *fn) if(!(fp=FCEUD_UTF8fopen(fn,"rb"))) return(0); - fstat(fileno(fp),&sb); + FCEUX_fstat(fileno(fp),&sb); len = sb.st_size; buf = (char*)FCEU_dmalloc(len); //mbg merge 7/17/06 added cast fread(buf, 1, len, fp); diff --git a/source/fceultra/nsf.cpp b/source/fceultra/nsf.cpp index d8c6b90..453e4fa 100644 --- a/source/fceultra/nsf.cpp +++ b/source/fceultra/nsf.cpp @@ -482,6 +482,7 @@ void DrawNSF(uint8 *XBuf) if(vismode==0) return; memset(XBuf,0,256*240); + memset(XDBuf,0,256*240); { @@ -567,13 +568,14 @@ void DrawNSF(uint8 *XBuf) } } - DrawTextTrans(ClipSidesOffset+XBuf+10*256+4+(((31-strlen((char*)NSFHeader.SongName))<<2)), 256, NSFHeader.SongName, 6); - DrawTextTrans(ClipSidesOffset+XBuf+26*256+4+(((31-strlen((char*)NSFHeader.Artist))<<2)), 256,NSFHeader.Artist, 6); - DrawTextTrans(ClipSidesOffset+XBuf+42*256+4+(((31-strlen((char*)NSFHeader.Copyright))<<2)), 256,NSFHeader.Copyright, 6); + static const int kFgColor = 1; + DrawTextTrans(ClipSidesOffset+XBuf+10*256+4+(((31-strlen((char*)NSFHeader.SongName))<<2)), 256, NSFHeader.SongName, kFgColor); + DrawTextTrans(ClipSidesOffset+XBuf+26*256+4+(((31-strlen((char*)NSFHeader.Artist))<<2)), 256,NSFHeader.Artist, kFgColor); + DrawTextTrans(ClipSidesOffset+XBuf+42*256+4+(((31-strlen((char*)NSFHeader.Copyright))<<2)), 256,NSFHeader.Copyright, kFgColor); - DrawTextTrans(ClipSidesOffset+XBuf+70*256+4+(((31-strlen("Song:"))<<2)), 256, (uint8*)"Song:", 6); + DrawTextTrans(ClipSidesOffset+XBuf+70*256+4+(((31-strlen("Song:"))<<2)), 256, (uint8*)"Song:", kFgColor); sprintf(snbuf,"<%d/%d>",CurrentSong,NSFHeader.TotalSongs); - DrawTextTrans(XBuf+82*256+4+(((31-strlen(snbuf))<<2)), 256, (uint8*)snbuf, 6); + DrawTextTrans(XBuf+82*256+4+(((31-strlen(snbuf))<<2)), 256, (uint8*)snbuf, kFgColor); { static uint8 last=0; diff --git a/source/fceultra/palette.cpp b/source/fceultra/palette.cpp index eba1a7b..3ab97f4 100644 --- a/source/fceultra/palette.cpp +++ b/source/fceultra/palette.cpp @@ -1,411 +1,648 @@ -/* FCE Ultra - NES/Famicom Emulator -* -* Copyright notice for this file: -* Copyright (C) 2002,2003 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 -*/ +/* FCE Ultra - NES/Famicom Emulator +* +* Copyright notice for this file: +* Copyright (C) 2002,2003 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 "types.h" +#include "file.h" +#include "fceu.h" +#include "driver.h" +#include "boards/mapinc.h" +#ifdef _S9XLUA_H +#include "fceulua.h" +#endif + +#include "palette.h" +#include "palettes/palettes.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#include +#include +#include +#include + +bool force_grayscale = false; + +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 + +//ntsc parameters: +bool ntsccol_enable = false; //whether NTSC palette is selected +static int ntsctint = 46+10; +static int ntschue = 72; + +//the default basic palette +int default_palette_selection = 0; + +//library of default palettes +static pal *default_palette[8]= +{ + palette, + rp2c04001, + rp2c04002, + rp2c04003, + rp2c05004, +}; + +static void CalculatePalette(void); +static void ChoosePalette(void); +static void WritePalette(void); + +//points to the actually selected current palette +pal *palo; + +#define RGB_TO_YIQ( r, g, b, y, i ) (\ + (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ + (i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\ + ((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\ +) + +#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ + r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\ + g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\ + (type) (y + to_rgb [4] * i + to_rgb [5] * q)\ +) + +static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b) +{ + static float const to_float = 1.0f / 0xFF; + float fr = to_float * r; + float fg = to_float * g; + float fb = to_float * b; + float y, i, q = RGB_TO_YIQ( fr, fg, fb, y, i ); + + + //--------------------------------- + //it seems a bit bogus here to use this segment which is essentially part of the base palette generation, + //but it's needed for 'hi' + static float const lo_levels [4] = { -0.12f, 0.00f, 0.31f, 0.72f }; + static float const hi_levels [4] = { 0.40f, 0.68f, 1.00f, 1.00f }; + int level = entry >> 4 & 0x03; + float lo = lo_levels [level]; + float hi = hi_levels [level]; + + int color = entry & 0x0F; + if ( color == 0 ) + lo = hi; + if ( color == 0x0D ) + hi = lo; + if ( color > 0x0D ) + hi = lo = 0.0f; + //--------------------------------- + + int tint = (entry >> 6) & 7; + if ( tint && color <= 0x0D ) + { + static float const phases [0x10 + 3] = { + -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, + 1.0f, 0.866025f, 0.5f, 0.0f, -0.5f, -0.866025f, + -1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f, + 1.0f + }; + #define TO_ANGLE_SIN( color ) phases [color] + #define TO_ANGLE_COS( color ) phases [(color) + 3] + + static float const atten_mul = 0.79399f; + static float const atten_sub = 0.0782838f; + + if ( tint == 7 ) + { + y = y * (atten_mul * 1.13f) - (atten_sub * 1.13f); + } + else + { + static unsigned char const tints [8] = { 0, 6, 10, 8, 2, 4, 0, 0 }; + int const tint_color = tints [tint]; + float sat = hi * (0.5f - atten_mul * 0.5f) + atten_sub * 0.5f; + y -= sat * 0.5f; + if ( tint >= 3 && tint != 4 ) + { + //combined tint bits + sat *= 0.6f; + y -= sat; + } + i += TO_ANGLE_SIN( tint_color ) * sat; + q += TO_ANGLE_COS( tint_color ) * sat; + } + } + + 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 ); + + #define CLAMP(x) ((x)<0?0:((x)>1.0f?1.0f:(x))) + r = (u8)(CLAMP(fr)*255); + g = (u8)(CLAMP(fg)*255); + b = (u8)(CLAMP(fb)*255); + + //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)); + // 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); } +int bisqwit_clamp(int v) { return v<0 ? 0 : v>255 ? 255 : v; } +// 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 -#include "types.h" -#include "file.h" -#include "fceu.h" -#include "driver.h" -#include "boards/mapinc.h" -#ifdef _S9XLUA_H -#include "fceulua.h" -#endif + // Decode the color index + int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1; -#include "palette.h" -#include "palettes/palettes.h" + // 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)] }; -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#include -#include -#include -#include - -static int ntsccol=0; -static int ntsctint=46+10; -static int ntschue=72; - -bool force_grayscale = false; - -/* These are dynamically filled/generated palettes: */ -pal palettei[64]; // Custom palette for an individual game. -pal palettec[64]; // Custom "global" palette. -pal paletten[64]; // Mathematically generated palette. - -static void CalculatePalette(void); -static void ChoosePalette(void); -static void WritePalette(void); -uint8 pale=0; - -pal *palo; -static pal *palpoint[8]= -{ - palette, - rp2c04001, - rp2c04002, - rp2c04003, - rp2c05004, -}; - -void FCEUI_SetPaletteArray(uint8 *pal) -{ - if(!pal) - palpoint[0]=palette; - else + //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++) { - int x; - palpoint[0]=palettec; - for(x=0;x<64;x++) + 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. { - palpoint[0][x].r=*((uint8 *)pal+x+x+x); - palpoint[0][x].g=*((uint8 *)pal+x+x+x+1); - palpoint[0][x].b=*((uint8 *)pal+x+x+x+2); - } - } - FCEU_ResetPalette(); -} + // NES NTSC modulator (square wave between two voltage levels): + float spot = lo_and_hi[bisqwit_wave(p,color)]; - -void FCEUI_SetNTSCTH(int n, int tint, int hue) -{ - ntsctint=tint; - ntschue=hue; - ntsccol=n; - FCEU_ResetPalette(); -} - -static uint8 lastd=0; -void SetNESDeemph(uint8 d, int force) -{ - static uint16 rtmul[]={ - static_cast(32768*1.239), - static_cast(32768*.794), - static_cast(32768*1.019), - static_cast(32768*.905), - static_cast(32768*1.023), - static_cast(32768*.741), - static_cast(32768*.75) - }; - static uint16 gtmul[]={ - static_cast(32768*.915), - static_cast(32768*1.086), - static_cast(32768*.98), - static_cast(32768*1.026), - static_cast(32768*.908), - static_cast(32768*.987), - static_cast(32768*.75) - }; - static uint16 btmul[]={ - static_cast(32768*.743), - static_cast(32768*.882), - static_cast(32768*.653), - static_cast(32768*1.277), - static_cast(32768*.979), - static_cast(32768*.101), - static_cast(32768*.75) - }; - - uint32 r,g,b; - int x; - - /* If it's not forced(only forced when the palette changes), - don't waste cpu time if the same deemphasis bits are set as the last call. - */ - if(!force) - { - if(d==lastd) - return; - } - else /* Only set this when palette has changed. */ - { - #ifdef _S9XLUA_H - FCEU_LuaUpdatePalette(); - #endif - - r=rtmul[6]; - g=rtmul[6]; - b=rtmul[6]; - - for(x=0;x<0x40;x++) - { - uint32 m,n,o; - m=palo[x].r; - n=palo[x].g; - o=palo[x].b; - m=(m*r)>>15; - n=(n*g)>>15; - o=(o*b)>>15; - if(m>0xff) m=0xff; - if(n>0xff) n=0xff; - if(o>0xff) o=0xff; - FCEUD_SetPalette(x|0xC0,m,n,o); - } - } - if(!d) return; /* No deemphasis, so return. */ - - r=rtmul[d-1]; - g=gtmul[d-1]; - b=btmul[d-1]; - - for(x=0;x<0x40;x++) - { - uint32 m,n,o; - - m=palo[x].r; - n=palo[x].g; - o=palo[x].b; - m=(m*r)>>15; - n=(n*g)>>15; - o=(o*b)>>15; - if(m>0xff) m=0xff; - if(n>0xff) n=0xff; - if(o>0xff) o=0xff; - - FCEUD_SetPalette(x|0x40,m,n,o); - } - - lastd=d; - #ifdef _S9XLUA_H - FCEU_LuaUpdatePalette(); - #endif -} - -// Converted from Kevin Horton's qbasic palette generator. -static void CalculatePalette(void) -{ - int x,z; - int r,g,b; - double s,luma,theta; - static uint8 cols[16]={0,24,21,18,15,12,9,6,3,0,33,30,27,0,0,0}; - static uint8 br1[4]={6,9,12,12}; - static double br2[4]={.29,.45,.73,.9}; - static double br3[4]={0,.24,.47,.77}; - - for(x=0;x<=3;x++) - for(z=0;z<16;z++) - { - s=(double)ntsctint/128; - luma=br2[x]; - if(z==0) {s=0;luma=((double)br1[x])/12;} - - if(z>=13) + // De-emphasis bits attenuate a part of the signal: + if(pass==1) { - s=luma=0; - if(z==13) - luma=br3[x]; + if(((entry & 0x40) && bisqwit_wave(p,12)) + || ((entry & 0x80) && bisqwit_wave(p, 4)) + || ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation; } - theta=(double)M_PI*(double)(((double)cols[z]*10+ (((double)ntschue/2)+300) )/(double)180); - r=(int)((luma+s*sin(theta))*256); - g=(int)((luma-(double)27/53*s*sin(theta)+(double)10/53*s*cos(theta))*256); - b=(int)((luma-s*cos(theta))*256); + // Normalize: + float v = (spot - black) / (white-black) / 12.f; - - if(r>255) r=255; - if(g>255) g=255; - if(b>255) b=255; - if(r<0) r=0; - if(g<0) g=0; - if(b<0) b=0; - - paletten[(x<<4)+z].r=r; - paletten[(x<<4)+z].g=g; - paletten[(x<<4)+z].b=b; + // 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). } - WritePalette(); -} -static int ipalette=0; + // Convert YIQ into RGB according to FCC-sanctioned conversion matrix. -void FCEU_LoadGamePalette(void) -{ - uint8 ptmp[192]; - FILE *fp; - char *fn; + 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)); - ipalette=0; - - fn=strdup(FCEU_MakeFName(FCEUMKF_PALETTE,0,0).c_str()); - - if((fp=FCEUD_UTF8fopen(fn,"rb"))) - { - int x; - fread(ptmp,1,192,fp); - fclose(fp); - for(x=0;x<64;x++) + if(pass==0) myr = rt, myg = gt, myb = bt; + else { - palettei[x].r=ptmp[x+x+x]; - palettei[x].g=ptmp[x+x+x+1]; - palettei[x].b=ptmp[x+x+x+2]; - } - ipalette=1; - } - free(fn); -} - -void FCEU_ResetPalette(void) -{ - if(GameInfo) - { - ChoosePalette(); - WritePalette(); - } -} - -static void ChoosePalette(void) -{ - if(GameInfo->type==GIT_NSF) - palo=0; - else if(ipalette) - palo=palettei; - else if(ntsccol && !PAL && GameInfo->type!=GIT_VSUNI) - { - palo=paletten; - CalculatePalette(); - } - else - palo=palpoint[pale]; -} - -void WritePalette(void) -{ - int x; - - for(x=0;x<7;x++) - FCEUD_SetPalette(x,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b); - if(GameInfo->type==GIT_NSF) - { - #ifdef _S9XLUA_H - FCEU_LuaUpdatePalette(); - #endif - //for(x=0;x<128;x++) - // FCEUD_SetPalette(x,x,0,x); - } - else - { - for(x=0;x<64;x++) - FCEUD_SetPalette(128+x,palo[x].r,palo[x].g,palo[x].b); - SetNESDeemph(lastd,1); - } -} - -void FCEUI_GetNTSCTH(int *tint, int *hue) -{ - *tint = ntsctint; - *hue = ntschue; -} - -static int controlselect=0; -static int controllength=0; - -void FCEUI_NTSCDEC(void) -{ - if(ntsccol && GameInfo->type!=GIT_VSUNI &&!PAL && GameInfo->type!=GIT_NSF) - { - int which; - if(controlselect) - { - if(controllength) - { - which=controlselect==1?ntschue:ntsctint; - which--; - if(which<0) which=0; - if(controlselect==1) - ntschue=which; - else ntsctint=which; - CalculatePalette(); - } - controllength=360; + 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)); } } -} -void FCEUI_NTSCINC(void) -{ - if(ntsccol && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF) - if(controlselect) - { - if(controllength) - { - switch(controlselect) - { - case 1:ntschue++; - if(ntschue>128) ntschue=128; - CalculatePalette(); - break; - case 2:ntsctint++; - if(ntsctint>128) ntsctint=128; - CalculatePalette(); - break; - } - } - controllength=360; - } -} -void FCEUI_NTSCSELHUE(void) -{ - if(ntsccol && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=1;controllength=360;} -} -void FCEUI_NTSCSELTINT(void) -{ - if(ntsccol && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=2;controllength=360;} -} - -void FCEU_DrawNTSCControlBars(uint8 *XBuf) -{ - uint8 *XBaf; - int which=0; - int x,x2; - - if(!controllength) return; - controllength--; - if(!XBuf) return; - - if(controlselect==1) - { - DrawTextTrans(XBuf+128-12+180*256, 256, (uint8 *)"Hue", 0x85); - which=ntschue<<1; - } - else if(controlselect==2) - { - DrawTextTrans(XBuf+128-16+180*256, 256, (uint8 *)"Tint", 0x85); - which=ntsctint<<1; - } - - XBaf=XBuf+200*256; - for(x=0;x=-6;x2--) - { - XBaf[x-256*x2]=0x85; - } - } - for(;x<256;x+=2) - { - for(x2=2;x2>=-2;x2--) - XBaf[x-256*x2]=0x85; - } -} +} + +//classic algorithm +static void ApplyDeemphasisClassic(int entry, u8& r, u8& g, u8& b) +{ + //DEEMPH BITS MAY BE ORDERED WRONG. PLEASE CHECK + + static const float rtmul[] = { 1.239f, 0.794f, 1.019f, 0.905f, 1.023f, 0.741f, 0.75f }; + static const float gtmul[] = { 0.915f, 1.086f, 0.98f, 1.026f, 0.908f, 0.987f, 0.75f }; + static const float btmul[] = { 0.743f, 0.882f, 0.653f, 1.277f, 0.979f, 0.101f, 0.75f }; + + int deemph_bits = entry >> 6; + + if (deemph_bits == 0) return; + + int d = deemph_bits - 1; + int nr = (int)(r * rtmul[d]); + int ng = (int)(g * gtmul[d]); + int nb = (int)(b * btmul[d]); + if (nr > 0xFF) nr = 0xFF; + if (ng > 0xFF) ng = 0xFF; + if (nb > 0xFF) nb = 0xFF; + r = (u8)nr; + g = (u8)ng; + b = (u8)nb; +} + +static void ApplyDeemphasisComplete(pal* pal512) +{ + //for each deemph level beyond 0 + for(int i=0,idx=0;i<8;i++) + { + //for each palette entry + for(int p=0;p<64;p++,idx++) + { + pal512[idx] = pal512[p]; + ApplyDeemphasisBisqwit(idx,pal512[idx].r,pal512[idx].g,pal512[idx].b); + } + } +} + +void FCEUI_SetUserPalette(uint8 *pal, int nEntries) +{ + if(!pal) + { + palette_user_available = false; + } + else + { + palette_user_available = true; + memcpy(palette_user,pal,nEntries*3); + + //if palette is incomplete, generate deemph entries + if(nEntries != 512) + ApplyDeemphasisComplete(palette_user); + } + FCEU_ResetPalette(); +} + +void FCEU_LoadGamePalette(void) +{ + palette_game_available = false; + std::string path = FCEU_MakeFName(FCEUMKF_PALETTE,0,0); + FILE* fp = FCEUD_UTF8fopen(path,"rb"); + if(fp) + { + int readed = fread(palette_game,1,64*8*3,fp); + int nEntries = readed/3; + fclose(fp); + + //if palette is incomplete, generate deemph entries + if(nEntries != 512) + ApplyDeemphasisComplete(palette_game); + + palette_game_available = true; + } + + //not sure whether this is needed + FCEU_ResetPalette(); +} + +void FCEUI_SetNTSCTH(bool en, int tint, int hue) +{ + ntsctint=tint; + ntschue=hue; + ntsccol_enable = en; + FCEU_ResetPalette(); +} + +//this prepares the 'deemph' palette which was a horrible idea to jam a single deemph palette into 0xC0-0xFF of the 8bpp palette. +//its needed for GUI and lua and stuff, so we're leaving it, despite having a newer codepath for applying deemph +static uint8 lastd=0; +void SetNESDeemph_OldHacky(uint8 d, int force) +{ + static uint16 rtmul[]={ + static_cast(32768*1.239), + static_cast(32768*.794), + static_cast(32768*1.019), + static_cast(32768*.905), + static_cast(32768*1.023), + static_cast(32768*.741), + static_cast(32768*.75) + }; + static uint16 gtmul[]={ + static_cast(32768*.915), + static_cast(32768*1.086), + static_cast(32768*.98), + static_cast(32768*1.026), + static_cast(32768*.908), + static_cast(32768*.987), + static_cast(32768*.75) + }; + static uint16 btmul[]={ + static_cast(32768*.743), + static_cast(32768*.882), + static_cast(32768*.653), + static_cast(32768*1.277), + static_cast(32768*.979), + static_cast(32768*.101), + static_cast(32768*.75) + }; + + uint32 r,g,b; + int x; + + /* If it's not forced(only forced when the palette changes), + don't waste cpu time if the same deemphasis bits are set as the last call. + */ + if(!force) + { + if(d==lastd) + return; + } + else /* Only set this when palette has changed. */ + { + #ifdef _S9XLUA_H + FCEU_LuaUpdatePalette(); + #endif + + r=rtmul[6]; + g=rtmul[6]; + b=rtmul[6]; + + for(x=0;x<0x40;x++) + { + uint32 m,n,o; + m=palo[x].r; + n=palo[x].g; + o=palo[x].b; + m=(m*r)>>15; + n=(n*g)>>15; + o=(o*b)>>15; + if(m>0xff) m=0xff; + if(n>0xff) n=0xff; + if(o>0xff) o=0xff; + FCEUD_SetPalette(x|0xC0,m,n,o); + } + } + if(!d) return; /* No deemphasis, so return. */ + + r=rtmul[d-1]; + g=gtmul[d-1]; + b=btmul[d-1]; + + for(x=0;x<0x40;x++) + { + uint32 m,n,o; + + m=palo[x].r; + n=palo[x].g; + o=palo[x].b; + m=(m*r)>>15; + n=(n*g)>>15; + o=(o*b)>>15; + if(m>0xff) m=0xff; + if(n>0xff) n=0xff; + if(o>0xff) o=0xff; + + FCEUD_SetPalette(x|0x40,m,n,o); + } + + lastd=d; + #ifdef _S9XLUA_H + FCEU_LuaUpdatePalette(); + #endif +} + +// Converted from Kevin Horton's qbasic palette generator. +static void CalculatePalette(void) +{ + //PRECONDITION: ntsc palette is enabled + if(!ntsccol_enable) + return; + + int x,z; + int r,g,b; + double s,luma,theta; + static uint8 cols[16]={0,24,21,18,15,12,9,6,3,0,33,30,27,0,0,0}; + static uint8 br1[4]={6,9,12,12}; + static double br2[4]={.29,.45,.73,.9}; + static double br3[4]={0,.24,.47,.77}; + + for(x=0;x<=3;x++) + for(z=0;z<16;z++) + { + s=(double)ntsctint/128; + luma=br2[x]; + if(z==0) {s=0;luma=((double)br1[x])/12;} + + if(z>=13) + { + s=luma=0; + if(z==13) + luma=br3[x]; + } + + theta=(double)M_PI*(double)(((double)cols[z]*10+ (((double)ntschue/2)+300) )/(double)180); + r=(int)((luma+s*sin(theta))*256); + g=(int)((luma-(double)27/53*s*sin(theta)+(double)10/53*s*cos(theta))*256); + b=(int)((luma-s*cos(theta))*256); + + + if(r>255) r=255; + if(g>255) g=255; + if(b>255) b=255; + if(r<0) r=0; + if(g<0) g=0; + if(b<0) b=0; + + palette_ntsc[(x<<4)+z].r=r; + palette_ntsc[(x<<4)+z].g=g; + palette_ntsc[(x<<4)+z].b=b; + } + + //can't call FCEU_ResetPalette(), it would be re-entrant + //see precondition for this function + WritePalette(); +} + +void FCEU_ResetPalette(void) +{ + if(GameInfo) + { + ChoosePalette(); + WritePalette(); + } +} + +static void ChoosePalette(void) +{ + //NSF uses a fixed palette always: + if(GameInfo->type==GIT_NSF) + palo = default_palette[0]; + //user palette takes priority over others + else if(palette_user_available) + palo = palette_user; + //NTSC takes priority next, if it's appropriate + else if(ntsccol_enable && !PAL && GameInfo->type!=GIT_VSUNI) + { + //for NTSC games, we can actually use the NTSC palette + palo = palette_ntsc; + CalculatePalette(); + } + //select the game's overridden palette if available + else if(palette_game_available) + palo = palette_game; + //finally, use a default built-in palette + else + { + palo = default_palette[default_palette_selection]; + //need to calcualte a deemph on the fly.. sorry. maybe support otherwise later + ApplyDeemphasisComplete(palo); + } +} + +void WritePalette(void) +{ + int x; + + //set the 'unvarying' palettes to low < 64 palette entries + const int unvaried = sizeof(palette_unvarying)/sizeof(palette_unvarying[0]); + for(x=0;x= 128 with the 64 selected main colors + for(x=0;x<64;x++) + FCEUD_SetPalette(128+x,palo[x].r,palo[x].g,palo[x].b); + SetNESDeemph_OldHacky(lastd,1); + #ifdef _S9XLUA_H + FCEU_LuaUpdatePalette(); + #endif +} + +void FCEUI_GetNTSCTH(int *tint, int *hue) +{ + *tint = ntsctint; + *hue = ntschue; +} + +static int controlselect=0; +static int controllength=0; + +void FCEUI_NTSCDEC(void) +{ + if(ntsccol_enable && GameInfo->type!=GIT_VSUNI &&!PAL && GameInfo->type!=GIT_NSF) + { + int which; + if(controlselect) + { + if(controllength) + { + which=controlselect==1?ntschue:ntsctint; + which--; + if(which<0) which=0; + if(controlselect==1) + ntschue=which; + else ntsctint=which; + CalculatePalette(); + } + controllength=360; + } + } +} + +void FCEUI_NTSCINC(void) +{ + if(ntsccol_enable && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF) + if(controlselect) + { + if(controllength) + { + switch(controlselect) + { + case 1:ntschue++; + if(ntschue>128) ntschue=128; + CalculatePalette(); + break; + case 2:ntsctint++; + if(ntsctint>128) ntsctint=128; + CalculatePalette(); + break; + } + } + controllength=360; + } +} + +void FCEUI_NTSCSELHUE(void) +{ + if(ntsccol_enable && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=1;controllength=360;} +} + +void FCEUI_NTSCSELTINT(void) +{ + if(ntsccol_enable && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=2;controllength=360;} +} + +void FCEU_DrawNTSCControlBars(uint8 *XBuf) +{ + uint8 *XBaf; + int which=0; + int x,x2; + + if(!controllength) return; + controllength--; + if(!XBuf) return; + + if(controlselect==1) + { + DrawTextTrans(XBuf+128-12+180*256, 256, (uint8 *)"Hue", 0x85); + which=ntschue<<1; + } + else if(controlselect==2) + { + DrawTextTrans(XBuf+128-16+180*256, 256, (uint8 *)"Tint", 0x85); + which=ntsctint<<1; + } + + XBaf=XBuf+200*256; + for(x=0;x=-6;x2--) + { + XBaf[x-256*x2]=0x85; + } + } + for(;x<256;x+=2) + { + for(x2=2;x2>=-2;x2--) + XBaf[x-256*x2]=0x85; + } +} diff --git a/source/fceultra/palettes/palettes.h b/source/fceultra/palettes/palettes.h index 3149254..7721bec 100644 --- a/source/fceultra/palettes/palettes.h +++ b/source/fceultra/palettes/palettes.h @@ -1,31 +1,59 @@ -pal rp2c04001[64] = { +#define EMPTY_PALETTE_1 {0,0,0}, +#define EMPTY_PALETTE_4 EMPTY_PALETTE_1 EMPTY_PALETTE_1 EMPTY_PALETTE_1 EMPTY_PALETTE_1 +#define EMPTY_PALETTE_16 EMPTY_PALETTE_4 EMPTY_PALETTE_4 EMPTY_PALETTE_4 EMPTY_PALETTE_4 +#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" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04002[64] = { +pal rp2c04002[512] = { #include "rp2c04002.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04003[64] = { +pal rp2c04003[512] = { #include "rp2c04003.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c05004[64] = { +pal rp2c05004[512] = { #include "rp2c05004.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal unvpalette[7] = { -{ 0x00<<2,0x00<<2,0x00<<2}, // Black -{ 0x3F<<2,0x3F<<2,0x34<<2}, // White -{ 0x00<<2,0x00<<2,0x00<<2}, // Black -{ 0x1d<<2,0x1d<<2,0x24<<2}, // Greyish -{ 190,0,0 }, // Redish -{ 51,255,51}, // Bright green -{ 49,14,200}, +// Fixed palette entries used by the GUI +pal palette_unvarying[] = { +{ 0x00<<2,0x00<<2,0x00<<2}, // 0 = Black +{ 0x3F<<2,0x3F<<2,0x34<<2}, // 1 = White +{ 0x00<<2,0x00<<2,0x00<<2}, // 2 = Black +{ 0x1d<<2,0x1d<<2,0x24<<2}, // 3 = Greyish +{ 190, 0, 0}, // 4 = Reddish +{ 51,255, 51}, // 5 = Bright green +{ 49, 14,200}, // 6 = Ultramarine Blue +// 16 saturated colors useful for Lua scripts +{ 0, 0, 0}, // 7 = Black +{ 0, 0,128}, // 8 = Dark Blue +{ 0,128, 0}, // 9 = Dark Green +{ 0,128,128}, // 10 = Dark Cyan +{ 128, 0, 0}, // 11 = Dark Red +{ 128, 0,128}, // 12 = Dark Magenta +{ 128,128, 0}, // 13 = Dark Yellow +{ 128,128,128}, // 14 = Light Grey +{ 64, 64, 64}, // 15 = Dark Grey +{ 0, 0,255}, // 16 = Bright Blue +{ 0,255, 0}, // 17 = Bright Green +{ 0,255,255}, // 18 = Bright Cyan +{ 255, 0, 0}, // 19 = Bright Red +{ 255, 0,255}, // 20 = Bright Magenta +{ 255,255, 0}, // 21 = Bright Yellow +{ 255,255,255}, // 22 = Bright White }; // Default palette -pal palette[64] = { +pal palette[512] = { { 0x1D<<2, 0x1D<<2, 0x1D<<2 }, /* Value 0 */ { 0x09<<2, 0x06<<2, 0x23<<2 }, /* Value 1 */ @@ -292,4 +320,6 @@ slightly better but too dark: */ +EMPTY_PALETTE_DEEMPH_X_7 + }; diff --git a/source/fceultra/ppu.cpp b/source/fceultra/ppu.cpp index b291e66..ed401d6 100644 --- a/source/fceultra/ppu.cpp +++ b/source/fceultra/ppu.cpp @@ -19,45 +19,46 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "types.h" -#include "x6502.h" -#include "fceu.h" -#include "ppu.h" -#include "nsf.h" -#include "sound.h" -#include "file.h" -#include "utils/endian.h" -#include "utils/memory.h" +#include "types.h" +#include "x6502.h" +#include "fceu.h" +#include "ppu.h" +#include "nsf.h" +#include "sound.h" +#include "file.h" +#include "utils/endian.h" +#include "utils/memory.h" + +#include "cart.h" +#include "palette.h" +#include "state.h" +#include "video.h" +#include "input.h" +#include "driver.h" +#include "debug.h" + +#include +#include +#include -#include "cart.h" -#include "palette.h" -#include "state.h" -#include "video.h" -#include "input.h" -#include "driver.h" -#include "debug.h" +#define VBlankON (PPU[0] & 0x80) //Generate VBlank NMI +#define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8 +#define BGAdrHI (PPU[0] & 0x10) //BG pattern adr $0000/$1000 +#define SpAdrHI (PPU[0] & 0x08) //Sprite pattern adr $0000/$1000 +#define INC32 (PPU[0] & 0x04) //auto increment 1/32 -#include -#include -#include +#define SpriteON (PPU[1] & 0x10) //Show Sprite +#define ScreenON (PPU[1] & 0x08) //Show screen +#define PPUON (PPU[1] & 0x18) //PPU should operate +#define GRAYSCALE (PPU[1] & 0x01) //Grayscale (AND palette entries with 0x30) -#define VBlankON (PPU[0] & 0x80) //Generate VBlank NMI -#define Sprite16 (PPU[0] & 0x20) //Sprites 8x16/8x8 -#define BGAdrHI (PPU[0] & 0x10) //BG pattern adr $0000/$1000 -#define SpAdrHI (PPU[0] & 0x08) //Sprite pattern adr $0000/$1000 -#define INC32 (PPU[0] & 0x04) //auto increment 1/32 +#define SpriteLeft8 (PPU[1] & 0x04) +#define BGLeft8 (PPU[1] & 0x02) -#define SpriteON (PPU[1] & 0x10) //Show Sprite -#define ScreenON (PPU[1] & 0x08) //Show screen -#define PPUON (PPU[1] & 0x18) //PPU should operate -#define GRAYSCALE (PPU[1] & 0x01) //Grayscale (AND palette entries with 0x30) +#define PPU_status (PPU[2]) -#define SpriteLeft8 (PPU[1] & 0x04) -#define BGLeft8 (PPU[1] & 0x02) - -#define PPU_status (PPU[2]) - -#define Pal (PALRAM) +#define READPAL(ofs) (PALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF)) +#define READUPAL(ofs) (UPALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF)) static void FetchSpriteData(void); static void RefreshLine(int lastpixel); @@ -69,6 +70,8 @@ static uint32 ppulut1[256]; static uint32 ppulut2[256]; static uint32 ppulut3[128]; +static bool new_ppu_reset = false; + int test = 0; template @@ -274,8 +277,24 @@ struct PPUREGS { v &= 1; fv &= 7; } + + void debug_log() + { + FCEU_printf("ppur: fv(%d), v(%d), h(%d), vt(%d), ht(%d)\n",fv,v,h,vt,ht); + FCEU_printf(" _fv(%d), _v(%d), _h(%d), _vt(%d), _ht(%d)\n",_fv,_v,_h,_vt,_ht); + FCEU_printf(" fh(%d), s(%d), par(%d)\n",fh,s,par); + FCEU_printf(" .status cycle(%d), end_cycle(%d), sl(%d)\n",status.cycle,status.end_cycle,status.sl); + } } ppur; +int newppu_get_scanline() { return ppur.status.sl; } +int newppu_get_dot() { return ppur.status.cycle; } +void newppu_hacky_emergency_reset() +{ + if(ppur.status.end_cycle == 0) + ppur.reset(); +} + static void makeppulut(void) { int x; int y; @@ -337,7 +356,7 @@ uint8 vtoggle = 0; uint8 XOffset = 0; uint8 SpriteDMA = 0; // $4014 / Writing $xx copies 256 bytes by reading from $xx00-$xxFF and writing to $2004 (OAM data) -uint32 TempAddr = 0, RefreshAddr = 0, DummyRead = 0; +uint32 TempAddr = 0, RefreshAddr = 0, DummyRead = 0, NTRefreshAddr = 0; static int maxsprites = 8; @@ -355,18 +374,7 @@ uint8 UPALRAM[0x03];//for 0x4/0x8/0xC addresses in palette, the ones in #define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)] #define VRAMADR(V) &VPage[(V) >> 10][(V)] -//mbg 8/6/08 - fix a bug relating to -//"When in 8x8 sprite mode, only one set is used for both BG and sprites." -//in mmc5 docs -uint8 * MMC5BGVRAMADR(uint32 V) { - if (!Sprite16) { - extern uint8 mmc5ABMode; /* A=0, B=1 */ - if (mmc5ABMode == 0) - return MMC5SPRVRAMADR(V); - else - return &MMC5BGVPage[(V) >> 10][(V)]; - } else return &MMC5BGVPage[(V) >> 10][(V)]; -} +uint8* MMC5BGVRAMADR(uint32 A); //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 @@ -420,7 +428,7 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) { } volatile int rendercount, vromreadcount, undefinedvromcount, LogAddress = -1; -unsigned char *cdloggervdata; +unsigned char *cdloggervdata = NULL; unsigned int cdloggerVideoDataSize = 0; int GetCHRAddress(int A) { @@ -428,6 +436,19 @@ int GetCHRAddress(int A) { int result = &VPage[A >> 10][A] - CHRptr[0]; if ((result >= 0) && (result < (int)cdloggerVideoDataSize)) return result; + } else + if(A < 0x2000) return A; + return -1; +} + +int GetCHROffset(uint8 *ptr) { + int result = ptr - CHRptr[0]; + if (cdloggerVideoDataSize) { + if ((result >= 0) && (result < (int)cdloggerVideoDataSize)) + return result; + } else { + if ((result >= 0) && (result < 0x2000)) + return result; } return -1; } @@ -441,8 +462,28 @@ int GetCHRAddress(int A) { if (!(cdloggervdata[addr] & 1)) \ { \ cdloggervdata[addr] |= 1; \ - if (!(cdloggervdata[addr] & 2)) undefinedvromcount--; \ - rendercount++; \ + if(cdloggerVideoDataSize) { \ + if (!(cdloggervdata[addr] & 2)) undefinedvromcount--; \ + rendercount++; \ + } \ + } \ + } \ + } \ +} + +#define RENDER_LOGP(tmp) { \ + if (debug_loggingCD) \ + { \ + int addr = GetCHROffset(tmp); \ + if (addr != -1) \ + { \ + if (!(cdloggervdata[addr] & 1)) \ + { \ + cdloggervdata[addr] |= 1; \ + if(cdloggerVideoDataSize) { \ + if (!(cdloggervdata[addr] & 2)) undefinedvromcount--; \ + rendercount++; \ + } \ } \ } \ } \ @@ -461,14 +502,11 @@ uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A) { uint8 ret; if (!(tmp & 3)) { if (!(tmp & 0xC)) - ret = PALRAM[0x00]; + ret = READPAL(0x00); else - ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; + ret = READUPAL(((tmp & 0xC) >> 2) - 1); } else - ret = PALRAM[tmp & 0x1F]; - - if (GRAYSCALE) - ret &= 0x30; + ret = READPAL(tmp & 0x1F); return ret; } } @@ -481,7 +519,7 @@ void (*FFCEUX_PPUWrite)(uint32 A, uint8 V) = 0; #define CALL_PPUWRITE(A, V) (FFCEUX_PPUWrite ? FFCEUX_PPUWrite(A, V) : FFCEUX_PPUWrite_Default(A, V)) -//whether to use the new ppu (new PPU doesn't handle MMC5 extra nametables at all +//whether to use the new ppu int newppu = 0; void ppu_getScroll(int &xpos, int &ypos) { @@ -665,7 +703,7 @@ static DECLFR(A2007) { if (!DummyRead && (LogAddress != -1)) { if (!(cdloggervdata[LogAddress] & 2)) { cdloggervdata[LogAddress] |= 2; - if (!(cdloggervdata[LogAddress] & 1)) undefinedvromcount--; + if ((!(cdloggervdata[LogAddress] & 1)) && cdloggerVideoDataSize) undefinedvromcount--; vromreadcount++; } } else @@ -683,13 +721,11 @@ static DECLFR(A2007) { //to get a gray color reading if (!(tmp & 3)) { if (!(tmp & 0xC)) - ret = PALRAM[0x00]; + ret = READPAL(0x00); else - ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; + ret = READUPAL(((tmp & 0xC) >> 2) - 1); } else - ret = PALRAM[tmp & 0x1F]; - if (GRAYSCALE) - ret &= 0x30; + ret = READPAL(tmp & 0x1F); VRAMBuffer = CALL_PPUREAD(RefreshAddr - 0x1000); } else { if (debug_loggingCD && (RefreshAddr < 0x2000)) @@ -700,18 +736,18 @@ static DECLFR(A2007) { RefreshAddr = ppur.get_2007access(); return ret; } else { + + //OLDPPU FCEUPPU_LineUpdate(); if (tmp >= 0x3F00) { // Palette RAM tied directly to the output data, without VRAM buffer if (!(tmp & 3)) { if (!(tmp & 0xC)) - ret = PALRAM[0x00]; + ret = READPAL(0x00); else - ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; + ret = READUPAL(((tmp & 0xC) >> 2) - 1); } else - ret = PALRAM[tmp & 0x1F]; - if (GRAYSCALE) - ret &= 0x30; + ret = READPAL(tmp & 0x1F); #ifdef FCEUDEF_DEBUGGER if (!fceuindbg) #endif @@ -731,9 +767,14 @@ static DECLFR(A2007) { if (PPU_hook) PPU_hook(tmp); PPUGenLatch = VRAMBuffer; if (tmp < 0x2000) { + if (debug_loggingCD) LogAddress = GetCHRAddress(tmp); - VRAMBuffer = VPage[tmp >> 10][tmp]; + if(MMC5Hack && newppu) + VRAMBuffer = *MMC5BGVRAMADR(tmp); + else + VRAMBuffer = VPage[tmp >> 10][tmp]; + } else if (tmp < 0x3F00) VRAMBuffer = vnapage[(tmp >> 10) & 0x3][tmp & 0x3FF]; } @@ -786,6 +827,8 @@ static DECLFW(B2000) { static DECLFW(B2001) { FCEUPPU_LineUpdate(); + if (paldeemphswap) + V = (V&0x9F)|((V&0x40)>>1)|((V&0x20)<<1); PPUGenLatch = V; PPU[1] = V; if (V & 0xE0) @@ -881,6 +924,11 @@ static DECLFW(B2006) { static DECLFW(B2007) { uint32 tmp = RefreshAddr & 0x3FFF; + if (debug_loggingCD) { + if(!cdloggerVideoDataSize && (tmp < 0x2000)) + cdloggervdata[tmp] = 0; + } + if (newppu) { PPUGenLatch = V; RefreshAddr = ppur.get_2007access() & 0x3FFF; @@ -1043,7 +1091,7 @@ static void RefreshLine(int lastpixel) { if (!ScreenON && !SpriteON) { uint32 tem; - tem = Pal[0] | (Pal[0] << 8) | (Pal[0] << 16) | (Pal[0] << 24); + tem = READPAL(0) | (READPAL(0) << 8) | (READPAL(0) << 16) | (READPAL(0) << 24); tem |= 0x40404040; FCEU_dwmemset(Pline, tem, numtiles * 8); P += numtiles * 8; @@ -1064,10 +1112,10 @@ static void RefreshLine(int lastpixel) { } //Priority bits, needed for sprite emulation. - Pal[0] |= 64; - Pal[4] |= 64; - Pal[8] |= 64; - Pal[0xC] |= 64; + PALRAM[0] |= 64; + PALRAM[4] |= 64; + PALRAM[8] |= 64; + PALRAM[0xC] |= 64; //This high-level graphics MMC5 emulation code was written for MMC5 carts in "CL" mode. //It's probably not totally correct for carts in "SL" mode. @@ -1145,15 +1193,15 @@ static void RefreshLine(int lastpixel) { #undef RefreshAddr //Reverse changes made before. - Pal[0] &= 63; - Pal[4] &= 63; - Pal[8] &= 63; - Pal[0xC] &= 63; + PALRAM[0] &= 63; + PALRAM[4] &= 63; + PALRAM[8] &= 63; + PALRAM[0xC] &= 63; RefreshAddr = smorkus; if (firsttile <= 2 && 2 < lasttile && !(PPU[1] & 2)) { uint32 tem; - tem = Pal[0] | (Pal[0] << 8) | (Pal[0] << 16) | (Pal[0] << 24); + tem = READPAL(0) | (READPAL(0) << 8) | (READPAL(0) << 16) | (READPAL(0) << 24); tem |= 0x40404040; *(uint32*)Plinef = *(uint32*)(Plinef + 4) = tem; } @@ -1161,7 +1209,7 @@ static void RefreshLine(int lastpixel) { if (!ScreenON) { uint32 tem; int tstart, tcount; - tem = Pal[0] | (Pal[0] << 8) | (Pal[0] << 16) | (Pal[0] << 24); + tem = READPAL(0) | (READPAL(0) << 8) | (READPAL(0) << 16) | (READPAL(0) << 24); tem |= 0x40404040; tcount = lasttile - firsttile; @@ -1218,11 +1266,16 @@ static void Fixit1(void) { void MMC5_hb(int); //Ugh ugh ugh. static void DoLine(void) { + if (scanline >= 240 && scanline != totalscanlines) { + X6502_Run(256 + 69); + scanline++; + X6502_Run(16); + return; + } + int x; - // scanlines after 239 are dummy for dendy, and Xbuf is capped at 0xffff bytes, don't let it overflow - // send all future writes to the invisible sanline. the easiest way to "skip" them altogether in old ppu - // todo: figure out what exactly should be skipped. it's known that there's no activity on PPU bus uint8 *target = XBuf + ((scanline < 240 ? scanline : 240) << 8); + u8* dtarget = XDBuf + ((scanline < 240 ? scanline : 240) << 8); if (MMC5Hack) MMC5_hb(scanline); @@ -1233,22 +1286,26 @@ static void DoLine(void) { uint32 tem; uint8 col; if (gNoBGFillColor == 0xFF) - col = Pal[0]; + col = READPAL(0); else col = gNoBGFillColor; tem = col | (col << 8) | (col << 16) | (col << 24); - tem |= 0x40404040; + tem |= 0x40404040; FCEU_dwmemset(target, tem, 256); } if (SpriteON) CopySprites(target); - if (ScreenON || SpriteON) { // Yes, very el-cheapo. + //greyscale handling (mask some bits off the color) ? ? ? + if (ScreenON || SpriteON) + { if (PPU[1] & 0x01) { for (x = 63; x >= 0; x--) *(uint32*)&target[x << 2] = (*(uint32*)&target[x << 2]) & 0x30303030; } } + + //some pathetic attempts at deemph if ((PPU[1] >> 5) == 0x7) { for (x = 63; x >= 0; x--) *(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0xc0c0c0c0; @@ -1259,6 +1316,10 @@ static void DoLine(void) { for (x = 63; x >= 0; x--) *(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0x80808080; + //write the actual deemph + for (x = 63; x >= 0; x--) + *(uint32*)&dtarget[x << 2] = ((PPU[1]>>5)<<0)|((PPU[1]>>5)<<8)|((PPU[1]>>5)<<16)|((PPU[1]>>5)<<24); + sphitx = 0x100; if (ScreenON || SpriteON) @@ -1362,10 +1423,10 @@ static void FetchSpriteData(void) { C = VRAMADR(vadr); if (SpriteON) - RENDER_LOG(vadr); + RENDER_LOGP(C); dst.ca[0] = C[0]; if (SpriteON) - RENDER_LOG(vadr + 8); + RENDER_LOGP(C + 8); dst.ca[1] = C[8]; dst.x = spr->x; dst.atr = spr->atr; @@ -1414,14 +1475,14 @@ static void FetchSpriteData(void) { else C = VRAMADR(vadr); if (SpriteON) - RENDER_LOG(vadr); + RENDER_LOGP(C); dst.ca[0] = C[0]; if (ns < 8) { PPU_hook(0x2000); PPU_hook(vadr); } if (SpriteON) - RENDER_LOG(vadr + 8); + RENDER_LOGP(C + 8); dst.ca[1] = C[8]; dst.x = spr->x; dst.atr = spr->atr; @@ -1466,7 +1527,7 @@ static void RefreshSprites(void) { int x = spr->x; uint8 *C; - uint8 *VB; + int VB; pixdata = ppulut1[spr->ca[0]] | ppulut2[spr->ca[1]]; J = spr->ca[0] | spr->ca[1]; @@ -1488,75 +1549,75 @@ static void RefreshSprites(void) { } C = sprlinebuf + x; - VB = (PALRAM + 0x10) + ((atr & 3) << 2); + VB = (0x10) + ((atr & 3) << 2); if (atr & SP_BACK) { if (atr & H_FLIP) { - if (J & 0x80) C[7] = VB[pixdata & 3] | 0x40; + if (J & 0x80) C[7] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x40) C[6] = VB[pixdata & 3] | 0x40; + if (J & 0x40) C[6] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x20) C[5] = VB[pixdata & 3] | 0x40; + if (J & 0x20) C[5] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x10) C[4] = VB[pixdata & 3] | 0x40; + if (J & 0x10) C[4] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x08) C[3] = VB[pixdata & 3] | 0x40; + if (J & 0x08) C[3] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x04) C[2] = VB[pixdata & 3] | 0x40; + if (J & 0x04) C[2] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x02) C[1] = VB[pixdata & 3] | 0x40; + if (J & 0x02) C[1] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x01) C[0] = VB[pixdata] | 0x40; + if (J & 0x01) C[0] = READPAL(VB | pixdata) | 0x40; } else { - if (J & 0x80) C[0] = VB[pixdata & 3] | 0x40; + if (J & 0x80) C[0] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x40) C[1] = VB[pixdata & 3] | 0x40; + if (J & 0x40) C[1] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x20) C[2] = VB[pixdata & 3] | 0x40; + if (J & 0x20) C[2] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x10) C[3] = VB[pixdata & 3] | 0x40; + if (J & 0x10) C[3] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x08) C[4] = VB[pixdata & 3] | 0x40; + if (J & 0x08) C[4] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x04) C[5] = VB[pixdata & 3] | 0x40; + if (J & 0x04) C[5] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x02) C[6] = VB[pixdata & 3] | 0x40; + if (J & 0x02) C[6] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x01) C[7] = VB[pixdata] | 0x40; + if (J & 0x01) C[7] = READPAL(VB | pixdata) | 0x40; } } else { if (atr & H_FLIP) { - if (J & 0x80) C[7] = VB[pixdata & 3]; + if (J & 0x80) C[7] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x40) C[6] = VB[pixdata & 3]; + if (J & 0x40) C[6] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x20) C[5] = VB[pixdata & 3]; + if (J & 0x20) C[5] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x10) C[4] = VB[pixdata & 3]; + if (J & 0x10) C[4] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x08) C[3] = VB[pixdata & 3]; + if (J & 0x08) C[3] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x04) C[2] = VB[pixdata & 3]; + if (J & 0x04) C[2] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x02) C[1] = VB[pixdata & 3]; + if (J & 0x02) C[1] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x01) C[0] = VB[pixdata]; + if (J & 0x01) C[0] = READPAL(VB | pixdata); } else { - if (J & 0x80) C[0] = VB[pixdata & 3]; + if (J & 0x80) C[0] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x40) C[1] = VB[pixdata & 3]; + if (J & 0x40) C[1] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x20) C[2] = VB[pixdata & 3]; + if (J & 0x20) C[2] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x10) C[3] = VB[pixdata & 3]; + if (J & 0x10) C[3] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x08) C[4] = VB[pixdata & 3]; + if (J & 0x08) C[4] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x04) C[5] = VB[pixdata & 3]; + if (J & 0x04) C[5] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x02) C[6] = VB[pixdata & 3]; + if (J & 0x02) C[6] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x01) C[7] = VB[pixdata]; + if (J & 0x01) C[7] = READPAL(VB | pixdata); } } } @@ -1640,10 +1701,12 @@ void FCEUPPU_SetVideoSystem(int w) { scanlines_per_frame = dendy ? 262: 312; FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; FSettings.LastSLine = FSettings.UsrLastSLine[1]; + //paldeemphswap = 1; // dendy has pal ppu, and pal ppu has these swapped } else { scanlines_per_frame = 262; FSettings.FirstSLine = FSettings.UsrFirstSLine[0]; FSettings.LastSLine = FSettings.UsrLastSLine[0]; + //paldeemphswap = 0; } } @@ -1666,8 +1729,7 @@ void FCEUPPU_Reset(void) { kook = 0; idleSynch = 1; - ppur.reset(); - spr_read.reset(); + new_ppu_reset = true; // delay reset of ppur/spr_read until it's ready to start a new frame } void FCEUPPU_Power(void) { @@ -1729,6 +1791,13 @@ int FCEUPPU_Loop(int skip) { TriggerNMI(); } X6502_Run((scanlines_per_frame - 242) * (256 + 85) - 12); + if (overclock_enabled && vblankscanlines) { + if (!DMC_7bit || !skip_7bit_overclocking) { + overclocking = 1; + X6502_Run(vblankscanlines * (256 + 85) - 12); + overclocking = 0; + } + } PPU_status &= 0x1f; X6502_Run(256); @@ -1759,7 +1828,7 @@ int FCEUPPU_Loop(int skip) { kook ^= 1; } if (GameInfo->type == GIT_NSF) - X6502_Run((256 + 85) * (dendy ? 290 : 240)); + X6502_Run((256 + 85) * normalscanlines); #ifdef FRAMESKIP else if (skip) { int y; @@ -1785,24 +1854,42 @@ int FCEUPPU_Loop(int skip) { } #endif else { - int x, max, maxref; - deemp = PPU[1] >> 5; - for (scanline = 0; scanline < (dendy ? 290 : 240); ) { //scanline is incremented in DoLine. Evil. :/ + + // manual samples can't play correctly with overclocking + if (DMC_7bit && skip_7bit_overclocking) // 7bit sample started before 240th line + totalscanlines = normalscanlines; + else + totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0); + + 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) + overclocking = 0; + else { + if (DMC_7bit && skip_7bit_overclocking) // 7bit sample started after 240th line + break; + overclocking = 1; + } } + DMC_7bit = 0; + if (MMC5Hack) MMC5_hb(scanline); - for (x = 1, max = 0, maxref = 0; x < 7; x++) { + + //deemph nonsense, kept for complicated reasons (see SetNESDeemph_OldHacky implementation) + int maxref = 0; + for (int x = 1, max = 0; x < 7; x++) { if (deempcnt[x] > max) { max = deempcnt[x]; maxref = x; } deempcnt[x] = 0; } - SetNESDeemph(maxref, 0); + SetNESDeemph_OldHacky(maxref, 0); } } //else... to if(ppudead) @@ -1902,7 +1989,10 @@ const int kFetchTime = 2; void runppu(int x) { ppur.status.cycle = (ppur.status.cycle + x) % ppur.status.end_cycle; - X6502_Run(x); + if (!new_ppu_reset) // if resetting, suspend CPU until the first frame + { + X6502_Run(x); + } } //todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory @@ -1911,7 +2001,7 @@ struct BGData { uint8 nt, pecnt, at, pt[2]; INLINE void Read() { - RefreshAddr = ppur.get_ntread(); + NTRefreshAddr = RefreshAddr = ppur.get_ntread(); if (PEC586Hack) ppur.s = (RefreshAddr & 0x200) >> 9; pecnt = (RefreshAddr & 1) << 3; @@ -1973,6 +2063,14 @@ static inline int PaletteAdjustPixel(int pixel) { int framectr = 0; int FCEUX_PPU_Loop(int skip) { + + if (new_ppu_reset) // first frame since reset, time to initialize + { + ppur.reset(); + spr_read.reset(); + new_ppu_reset = false; + } + //262 scanlines if (ppudead) { // not quite emulating all the NES power up behavior @@ -2003,12 +2101,20 @@ int FCEUX_PPU_Loop(int skip) { ppur.status.sl = 241; //for sprite reads - runppu(delay); //X6502_Run(12); + //formerly: runppu(delay); + for(int dot=0;dot 0 || SpriteLeft8); - const bool renderbgnow = ScreenON && renderbg && (xt > 0 || BGLeft8); + const bool renderspritenow = SpriteON && (xt > 0 || SpriteLeft8); + const bool renderbgnow = ScreenON && (xt > 0 || BGLeft8); for (int xp = 0; xp < 8; xp++, rasterpos++, g_rasterpos++) { //bg pos is different from raster pos due to its offsetability. //so adjust for that here @@ -2083,14 +2197,28 @@ int FCEUX_PPU_Loop(int skip) { const int bgpx = bgpos & 7; const int bgtile = bgpos >> 3; - uint8 pixel = 0, pixelcolor; + uint8 pixel = 0; + uint8 pixelcolor = blank; + + //according to qeed's doc, use palette 0 or $2006's value if it is & 0x3Fxx + if (!ScreenON && !SpriteON) + { + // if there's anything wrong with how we're doing this, someone please chime in + int addr = ppur.get_2007access(); + if ((addr & 0x3F00) == 0x3F00) + { + pixel = addr & 0x1F; + } + pixelcolor = PALRAM[pixel]; + } //generate the BG data if (renderbgnow) { uint8* pt = bgdata.main[bgtile].pt; pixel = ((pt[0] >> (7 - bgpx)) & 1) | (((pt[1] >> (7 - bgpx)) & 1) << 1) | bgdata.main[bgtile].at; } - pixelcolor = PALRAM[pixel]; + if (renderbg) + pixelcolor = READPAL(pixel); //look for a sprite to be drawn bool havepixel = false; @@ -2133,11 +2261,14 @@ int FCEUX_PPU_Loop(int skip) { //bring in the palette bits and palettize spixel |= (oam[2] & 3) << 2; - pixelcolor = PALRAM[0x10 + spixel]; + + if (rendersprites) + pixelcolor = READPAL(0x10 + spixel); } } *ptr++ = PaletteAdjustPixel(pixelcolor); + *dptr++= PPU[1]>>5; //grab deemph } } } @@ -2264,6 +2395,14 @@ int FCEUX_PPU_Loop(int skip) { } } + //blind attempt to replicate old ppu functionality + if(s == 2 && PPUON) + { + if (GameHBIRQHook2) { + GameHBIRQHook2(); + } + } + if (realSprite) runppu(kFetchTime); @@ -2318,6 +2457,8 @@ int FCEUX_PPU_Loop(int skip) { runppu(1); } //scanline loop + DMC_7bit = 0; + if (MMC5Hack) MMC5_hb(240); //idle for one line diff --git a/source/fceultra/ppu.h b/source/fceultra/ppu.h index 5db7158..a3d2ded 100644 --- a/source/fceultra/ppu.h +++ b/source/fceultra/ppu.h @@ -9,6 +9,10 @@ void FCEUPPU_SetVideoSystem(int w); extern void (*PPU_hook)(uint32 A); extern void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void); +int newppu_get_scanline(); +int newppu_get_dot(); +void newppu_hacky_emergency_reset(); + /* For cart.c and banksw.h, mostly */ extern uint8 NTARAM[0x800], *vnapage[4]; extern uint8 PPUNTARAM; @@ -18,10 +22,10 @@ void FCEUPPU_SaveState(void); void FCEUPPU_LoadState(int version); uint32 FCEUPPU_PeekAddress(); uint8* FCEUPPU_GetCHR(uint32 vadr, uint32 refreshaddr); +int FCEUPPU_GetAttr(int ntnum, int xt, int yt); void ppu_getScroll(int &xpos, int &ypos); - #ifdef _MSC_VER #define FASTCALL __fastcall #else @@ -34,9 +38,10 @@ extern void (*FFCEUX_PPUWrite)(uint32 A, uint8 V); extern uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A); void FFCEUX_PPUWrite_Default(uint32 A, uint8 V); -extern int scanline; extern int g_rasterpos; extern uint8 PPU[4]; +extern bool DMC_7bit; +extern bool paldeemphswap; enum PPUPHASE { PPUPHASE_VBL, PPUPHASE_BG, PPUPHASE_OBJ diff --git a/source/fceultra/pputile.inc b/source/fceultra/pputile.inc index b935a7f..fc6d04a 100644 --- a/source/fceultra/pputile.inc +++ b/source/fceultra/pputile.inc @@ -89,21 +89,21 @@ pshift[1] <<= 8; #ifdef PPU_BGFETCH if (RefreshAddr & 1) { if(ScreenON) - RENDER_LOG(vadr + 8); + RENDER_LOGP(C + 8); pshift[0] |= C[8]; pshift[1] |= C[8]; } else { if(ScreenON) - RENDER_LOG(vadr); + RENDER_LOGP(C); pshift[0] |= C[0]; pshift[1] |= C[0]; } #else if(ScreenON) - RENDER_LOG(vadr); + RENDER_LOGP(C); pshift[0] |= C[0]; if(ScreenON) - RENDER_LOG(vadr + 8); + RENDER_LOGP(C + 8); pshift[1] |= C[8]; #endif diff --git a/source/fceultra/sound.cpp b/source/fceultra/sound.cpp index e5ea920..7390cce 100644 --- a/source/fceultra/sound.cpp +++ b/source/fceultra/sound.cpp @@ -58,6 +58,7 @@ uint8 EnabledChannels=0; // $4015 / Sound channels enable and status uint8 IRQFrameMode=0; // $4017 / Frame counter control / xx000000 uint8 InitialRawDALatch=0; // used only for lua +bool DMC_7bit = 0; // used to skip overclocking ENVUNIT EnvUnits[3]; static const int RectDuties[4]={1,2,4,6}; @@ -90,19 +91,18 @@ static const uint8 lengthtable[0x20]= }; -static const uint32 NoiseFreqTableNTSC[0x10] = +extern const uint32 NoiseFreqTableNTSC[0x10] = { 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068 }; -static const uint32 NoiseFreqTablePAL[0x10] = +extern const uint32 NoiseFreqTablePAL[0x10] = { 4, 7, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778 }; -const uint32 *NoiseFreqTable = NoiseFreqTableNTSC; // for lua only static const uint32 NTSCDMCTable[0x10]= { @@ -233,10 +233,8 @@ static DECLFW(Write_PSG) DoSQ1(); EnvUnits[0].Mode=(V&0x30)>>4; EnvUnits[0].Speed=(V&0xF); -#ifdef WIN32 if (swapDuty) V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); -#endif break; case 0x1: sweepon[0]=V&0x80; @@ -253,10 +251,8 @@ static DECLFW(Write_PSG) DoSQ2(); EnvUnits[1].Mode=(V&0x30)>>4; EnvUnits[1].Speed=(V&0xF); -#ifdef WIN32 if (swapDuty) V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); -#endif break; case 0x5: sweepon[1]=V&0x80; @@ -311,58 +307,69 @@ static DECLFW(Write_PSG) static DECLFW(Write_DMCRegs) { - A&=0xF; - - switch(A) - { - case 0x00:DoPCM(); - LoadDMCPeriod(V&0xF); - - if(SIRQStat&0x80) - { - if(!(V&0x80)) - { - X6502_IRQEnd(FCEU_IQDPCM); - SIRQStat&=~0x80; - } - else X6502_IRQBegin(FCEU_IQDPCM); - } - DMCFormat=V; - break; - case 0x01:DoPCM(); - InitialRawDALatch=V&0x7F; - RawDALatch=InitialRawDALatch; - break; - case 0x02:DMCAddressLatch=V;break; - case 0x03:DMCSizeLatch=V;break; - } - - + A&=0xF; + + switch(A) + { + case 0x00: + DoPCM(); + LoadDMCPeriod(V&0xF); + + if(SIRQStat&0x80) + { + if(!(V&0x80)) + { + X6502_IRQEnd(FCEU_IQDPCM); + SIRQStat&=~0x80; + } + else X6502_IRQBegin(FCEU_IQDPCM); + } + DMCFormat=V; + break; + case 0x01: + DoPCM(); + InitialRawDALatch=V&0x7F; + RawDALatch=InitialRawDALatch; + if (RawDALatch) + DMC_7bit = 1; + break; + case 0x02: + DMCAddressLatch=V; + if (V) + DMC_7bit = 0; + break; + case 0x03: + DMCSizeLatch=V; + if (V) + DMC_7bit = 0; + break; + } } static DECLFW(StatusWrite) { int x; - DoSQ1(); - DoSQ2(); - DoTriangle(); - DoNoise(); - DoPCM(); - for(x=0;x<4;x++) - if(!(V&(1<>16)&255]+wlookup1[b>>24]; diff --git a/source/fceultra/sound.h b/source/fceultra/sound.h index 4522766..bdbd315 100644 --- a/source/fceultra/sound.h +++ b/source/fceultra/sound.h @@ -59,7 +59,7 @@ extern unsigned char *cdloggerdata; extern uint32 soundtsoffs; extern bool swapDuty; -#define SOUNDTS (timestamp + soundtsoffs) +#define SOUNDTS (soundtimestamp + soundtsoffs) void SetNESSoundMap(void); void FrameSoundUpdate(void); diff --git a/source/fceultra/state.cpp b/source/fceultra/state.cpp index 3059354..0f22f90 100644 --- a/source/fceultra/state.cpp +++ b/source/fceultra/state.cpp @@ -974,8 +974,12 @@ void FCEUI_LoadState(const char *fname, bool display_message) loadStateFailed = 1; return; // state doesn't exist; exit cleanly } + if (FCEUSS_Load(fname, display_message)) { + //in case we're loading a savestate made with old ppu, we need to make sure ppur's regs used for dividing are ready to go + newppu_hacky_emergency_reset(); + //mbg todo netplay #if 0 if(FCEUnetplay) diff --git a/source/fceultra/types-des.h b/source/fceultra/types-des.h index acb324a..e94536b 100644 --- a/source/fceultra/types-des.h +++ b/source/fceultra/types-des.h @@ -1,458 +1,458 @@ -/* Copyright (C) 2005 Guillaume Duhamel - Copyright (C) 2008-2009 DeSmuME team - - This file is part of DeSmuME - - DeSmuME 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. - - DeSmuME 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 DeSmuME; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef TYPES_HPP -#define TYPES_HPP - -//analyze microsoft compilers -#ifdef _MSC_VER - #ifdef _XBOX - //#define _XBOX //already defined - #else - #define _WINDOWS - #ifdef _M_X64 - //#define _WIN64 //already defined in x64 compiler - #else - //#define _WIN32 //already defined - #endif - #endif -#endif - -//todo - everyone will want to support this eventually, i suppose -#ifdef _WINDOWS -#include "config.h" -#endif - -//xbox needs to include this to resemble windows -#ifdef _XBOX - #include - #include -#endif - -#ifdef DEVELOPER -#define IF_DEVELOPER(X) X -#else -#define IF_DEVELOPER(X) -#endif - -#ifdef _WINDOWS - //#define HAVE_WX //not useful yet.... - #define HAVE_LIBAGG - #define ENABLE_SSE - #define ENABLE_SSE2 - #ifdef DEVELOPER - #define HAVE_LUA - #endif -#endif - -#ifdef __GNUC__ -#ifdef __SSE__ -#define ENABLE_SSE -#endif -#ifdef __SSE2__ -#define ENABLE_SSE2 -#endif -#endif - -#ifdef NOSSE -#undef ENABLE_SSE -#endif - -#ifdef NOSSE2 -#undef ENABLE_SSE2 -#endif - -#ifdef _MSC_VER -#define strcasecmp(x,y) _stricmp(x,y) -#define snprintf _snprintf -#else -#define WINAPI -#endif - -#ifdef __GNUC__ -#include -#ifndef PATH_MAX -#define MAX_PATH 1024 -#else -#define MAX_PATH PATH_MAX -#endif -#endif - - -#ifdef _XBOX -#define MAX_PATH 1024 -#define PATH_MAX 1024 -#endif - - -#if defined(_MSC_VER) || defined(__INTEL_COMPILER) -#define ALIGN(X) __declspec(align(X)) -#elif __GNUC__ -#define ALIGN(X) __attribute__ ((aligned (X))) -#else -#define ALIGN(X) -#endif - -#define CACHE_ALIGN ALIGN(32) - -//use this for example when you want a byte value to be better-aligned -#define FAST_ALIGN ALIGN(4) - -#ifndef FASTCALL -#ifdef __MINGW32__ -#define FASTCALL __attribute__((fastcall)) -#elif defined (__i386__) && !defined(__clang__) -#define FASTCALL __attribute__((regparm(3))) -#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) -#define FASTCALL -#else -#define FASTCALL -#endif -#endif - -#ifdef _MSC_VER -#define _CDECL_ __cdecl -#else -#define _CDECL_ -#endif - -#ifndef INLINE -#if defined(_MSC_VER) || defined(__INTEL_COMPILER) -#define INLINE _inline -#else -#define INLINE inline -#endif -#endif - -#ifndef FORCEINLINE -#if defined(_MSC_VER) || defined(__INTEL_COMPILER) -#define FORCEINLINE __forceinline -#define MSC_FORCEINLINE __forceinline -#else -#define FORCEINLINE inline __attribute__((always_inline)) -#define MSC_FORCEINLINE -#endif -#endif - -#if defined(__LP64__) -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; - -typedef signed char s8; -typedef signed short s16; -typedef signed int s32; -typedef signed long long s64; -#else -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -#if defined(_MSC_VER) || defined(__INTEL_COMPILER) -typedef unsigned __int64 u64; -#else -typedef unsigned long long u64; -#endif - -typedef signed char s8; -typedef signed short s16; -typedef signed int s32; -#if defined(_MSC_VER) || defined(__INTEL_COMPILER) -typedef __int64 s64; -#else -typedef signed long long s64; -#endif -#endif - -typedef u8 uint8; -typedef u16 uint16; - -#ifndef OBJ_C -typedef u32 uint32; -#else -#define uint32 u32 //uint32 is defined in Leopard somewhere, avoid conflicts -#endif - -/*---------- GPU3D fixed-points types -----------*/ - -typedef s32 f32; -#define inttof32(n) ((n) << 12) -#define f32toint(n) ((n) >> 12) -#define floattof32(n) ((int32)((n) * (1 << 12))) -#define f32tofloat(n) (((float)(n)) / (float)(1<<12)) - -typedef s16 t16; -#define f32tot16(n) ((t16)(n >> 8)) -#define inttot16(n) ((n) << 4) -#define t16toint(n) ((n) >> 4) -#define floattot16(n) ((t16)((n) * (1 << 4))) -#define t16ofloat(n) (((float)(n)) / (float)(1<<4)) - -typedef s16 v16; -#define inttov16(n) ((n) << 12) -#define f32tov16(n) (n) -#define floattov16(n) ((v16)((n) * (1 << 12))) -#define v16toint(n) ((n) >> 12) -#define v16tofloat(n) (((float)(n)) / (float)(1<<12)) - -typedef s16 v10; -#define inttov10(n) ((n) << 9) -#define f32tov10(n) ((v10)(n >> 3)) -#define v10toint(n) ((n) >> 9) -#define floattov10(n) ((v10)((n) * (1 << 9))) -#define v10tofloat(n) (((float)(n)) / (float)(1<<9)) - -/*----------------------*/ - -#ifndef OBJ_C -typedef int BOOL; -#else -//apple also defines BOOL -typedef int desmume_BOOL; -#define BOOL desmume_BOOL -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifdef __BIG_ENDIAN__ -#ifndef WORDS_BIGENDIAN -#define WORDS_BIGENDIAN -#endif -#endif - -#ifdef WORDS_BIGENDIAN -# define LOCAL_BE -#else -# define LOCAL_LE -#endif - -/* little endian (ds' endianess) to local endianess convert macros */ -#ifdef LOCAL_BE /* local arch is big endian */ -# define LE_TO_LOCAL_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff)) -# define LE_TO_LOCAL_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff)) -# define LE_TO_LOCAL_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff)) -# define LOCAL_TO_LE_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff)) -# define LOCAL_TO_LE_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff)) -# define LOCAL_TO_LE_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff)) -#else /* local arch is little endian */ -# define LE_TO_LOCAL_16(x) (x) -# define LE_TO_LOCAL_32(x) (x) -# define LE_TO_LOCAL_64(x) (x) -# define LOCAL_TO_LE_16(x) (x) -# define LOCAL_TO_LE_32(x) (x) -# define LOCAL_TO_LE_64(x) (x) -#endif - -// kilobytes and megabytes macro -#define MB(x) ((x)*1024*1024) -#define KB(x) ((x)*1024) - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - -#define CPU_STR(c) ((c==ARM9)?"ARM9":"ARM7") -typedef enum -{ - ARM9 = 0, - ARM7 = 1 -} cpu_id_t; - -///endian-flips count bytes. count should be even and nonzero. -inline void FlipByteOrder(u8 *src, u32 count) -{ - u8 *start=src; - u8 *end=src+count-1; - - if((count&1) || !count) return; /* This shouldn't happen. */ - - while(count--) - { - u8 tmp; - - tmp=*end; - *end=*start; - *start=tmp; - end--; - start++; - } -} - - - -inline u64 double_to_u64(double d) { - union { - u64 a; - double b; - } fuxor; - fuxor.b = d; - return fuxor.a; -} - -inline double u64_to_double(u64 u) { - union { - u64 a; - double b; - } fuxor; - fuxor.a = u; - return fuxor.b; -} - -inline u32 float_to_u32(float f) { - union { - u32 a; - float b; - } fuxor; - fuxor.b = f; - return fuxor.a; -} - -inline float u32_to_float(u32 u) { - union { - u32 a; - float b; - } fuxor; - fuxor.a = u; - return fuxor.b; -} - - -///stores a 32bit value into the provided byte array in guaranteed little endian form -inline void en32lsb(u8 *buf, u32 morp) -{ - buf[0]=(u8)(morp); - buf[1]=(u8)(morp>>8); - buf[2]=(u8)(morp>>16); - buf[3]=(u8)(morp>>24); -} - -inline void en16lsb(u8* buf, u16 morp) -{ - buf[0]=(u8)morp; - buf[1]=(u8)(morp>>8); -} - -///unpacks a 64bit little endian value from the provided byte array into host byte order -inline u64 de64lsb(u8 *morp) -{ - return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24)|((u64)morp[4]<<32)|((u64)morp[5]<<40)|((u64)morp[6]<<48)|((u64)morp[7]<<56); -} - -///unpacks a 32bit little endian value from the provided byte array into host byte order -inline u32 de32lsb(u8 *morp) -{ - return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24); -} - -///unpacks a 16bit little endian value from the provided byte array into host byte order -inline u16 de16lsb(u8 *morp) -{ - return morp[0]|(morp[1]<<8); -} - -#ifndef ARRAY_SIZE -//taken from winnt.h -extern "C++" // templates cannot be declared to have 'C' linkage -template -char (*BLAHBLAHBLAH( UNALIGNED T (&)[N] ))[N]; - -#define ARRAY_SIZE(A) (sizeof(*BLAHBLAHBLAH(A))) -#endif - - -//fairly standard for loop macros -#define MACRODO1(TRICK,TODO) { const int X = TRICK; TODO; } -#define MACRODO2(X,TODO) { MACRODO1((X),TODO) MACRODO1(((X)+1),TODO) } -#define MACRODO4(X,TODO) { MACRODO2((X),TODO) MACRODO2(((X)+2),TODO) } -#define MACRODO8(X,TODO) { MACRODO4((X),TODO) MACRODO4(((X)+4),TODO) } -#define MACRODO16(X,TODO) { MACRODO8((X),TODO) MACRODO8(((X)+8),TODO) } -#define MACRODO32(X,TODO) { MACRODO16((X),TODO) MACRODO16(((X)+16),TODO) } -#define MACRODO64(X,TODO) { MACRODO32((X),TODO) MACRODO32(((X)+32),TODO) } -#define MACRODO128(X,TODO) { MACRODO64((X),TODO) MACRODO64(((X)+64),TODO) } -#define MACRODO256(X,TODO) { MACRODO128((X),TODO) MACRODO128(((X)+128),TODO) } - -//this one lets you loop any number of times (as long as N<256) -#define MACRODO_N(N,TODO) {\ - if((N)&0x100) MACRODO256(0,TODO); \ - if((N)&0x080) MACRODO128((N)&(0x100),TODO); \ - if((N)&0x040) MACRODO64((N)&(0x100|0x080),TODO); \ - if((N)&0x020) MACRODO32((N)&(0x100|0x080|0x040),TODO); \ - if((N)&0x010) MACRODO16((N)&(0x100|0x080|0x040|0x020),TODO); \ - if((N)&0x008) MACRODO8((N)&(0x100|0x080|0x040|0x020|0x010),TODO); \ - if((N)&0x004) MACRODO4((N)&(0x100|0x080|0x040|0x020|0x010|0x008),TODO); \ - if((N)&0x002) MACRODO2((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004),TODO); \ - if((N)&0x001) MACRODO1((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004|0x002),TODO); \ -} - -//--------------------------- -//Binary constant generator macro By Tom Torfs - donated to the public domain - -//turn a numeric literal into a hex constant -//(avoids problems with leading zeroes) -//8-bit constants max value 0x11111111, always fits in unsigned long -#define HEX__(n) 0x##n##LU - -//8-bit conversion function -#define B8__(x) ((x&0x0000000FLU)?1:0) \ -+((x&0x000000F0LU)?2:0) \ -+((x&0x00000F00LU)?4:0) \ -+((x&0x0000F000LU)?8:0) \ -+((x&0x000F0000LU)?16:0) \ -+((x&0x00F00000LU)?32:0) \ -+((x&0x0F000000LU)?64:0) \ -+((x&0xF0000000LU)?128:0) - -//for upto 8-bit binary constants -#define B8(d) ((unsigned char)B8__(HEX__(d))) - -// for upto 16-bit binary constants, MSB first -#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \ -+ B8(dlsb)) - -// for upto 32-bit binary constants, MSB first */ -#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \ -+ ((unsigned long)B8(db2)<<16) \ -+ ((unsigned long)B8(db3)<<8) \ -+ B8(dlsb)) - -//Sample usage: -//B8(01010101) = 85 -//B16(10101010,01010101) = 43605 -//B32(10000000,11111111,10101010,01010101) = 2164238933 -//--------------------------- - -#ifndef CTASSERT -#define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1] -#endif - -static const char hexValid[23] = {"0123456789ABCDEFabcdef"}; - - -template inline void reconstruct(T* t) { - t->~T(); - new(t) T(); -} - - -#endif +/* Copyright (C) 2005 Guillaume Duhamel + Copyright (C) 2008-2009 DeSmuME team + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef TYPES_HPP +#define TYPES_HPP + +//analyze microsoft compilers +#ifdef _MSC_VER + #ifdef _XBOX + //#define _XBOX //already defined + #else + #define _WINDOWS + #ifdef _M_X64 + //#define _WIN64 //already defined in x64 compiler + #else + //#define _WIN32 //already defined + #endif + #endif +#endif + +//todo - everyone will want to support this eventually, i suppose +#ifdef _WINDOWS +#include "config.h" +#endif + +//xbox needs to include this to resemble windows +#ifdef _XBOX + #include + #include +#endif + +#ifdef DEVELOPER +#define IF_DEVELOPER(X) X +#else +#define IF_DEVELOPER(X) +#endif + +#ifdef _WINDOWS + //#define HAVE_WX //not useful yet.... + #define HAVE_LIBAGG + #define ENABLE_SSE + #define ENABLE_SSE2 + #ifdef DEVELOPER + #define HAVE_LUA + #endif +#endif + +#ifdef __GNUC__ +#ifdef __SSE__ +#define ENABLE_SSE +#endif +#ifdef __SSE2__ +#define ENABLE_SSE2 +#endif +#endif + +#ifdef NOSSE +#undef ENABLE_SSE +#endif + +#ifdef NOSSE2 +#undef ENABLE_SSE2 +#endif + +#ifdef _MSC_VER +#define strcasecmp(x,y) _stricmp(x,y) +#define snprintf _snprintf +#else +#define WINAPI +#endif + +#ifdef __GNUC__ +#include +#ifndef PATH_MAX +#define MAX_PATH 1024 +#else +#define MAX_PATH PATH_MAX +#endif +#endif + + +#ifdef _XBOX +#define MAX_PATH 1024 +#define PATH_MAX 1024 +#endif + + +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define ALIGN(X) __declspec(align(X)) +#elif __GNUC__ +#define ALIGN(X) __attribute__ ((aligned (X))) +#else +#define ALIGN(X) +#endif + +#define CACHE_ALIGN ALIGN(32) + +//use this for example when you want a byte value to be better-aligned +#define FAST_ALIGN ALIGN(4) + +#ifndef FASTCALL +#ifdef __MINGW32__ +#define FASTCALL __attribute__((fastcall)) +#elif defined (__i386__) && !defined(__clang__) +#define FASTCALL __attribute__((regparm(3))) +#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define FASTCALL +#else +#define FASTCALL +#endif +#endif + +#ifdef _MSC_VER +#define _CDECL_ __cdecl +#else +#define _CDECL_ +#endif + +#ifndef INLINE +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define INLINE _inline +#else +#define INLINE inline +#endif +#endif + +#ifndef FORCEINLINE +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#define FORCEINLINE __forceinline +#define MSC_FORCEINLINE __forceinline +#else +#define FORCEINLINE inline __attribute__((always_inline)) +#define MSC_FORCEINLINE +#endif +#endif + +#if defined(__LP64__) +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; +#else +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +typedef unsigned __int64 u64; +#else +typedef unsigned long long u64; +#endif + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +typedef __int64 s64; +#else +typedef signed long long s64; +#endif +#endif + +typedef u8 uint8; +typedef u16 uint16; + +#ifndef OBJ_C +typedef u32 uint32; +#else +#define uint32 u32 //uint32 is defined in Leopard somewhere, avoid conflicts +#endif + +/*---------- GPU3D fixed-points types -----------*/ + +typedef s32 f32; +#define inttof32(n) ((n) << 12) +#define f32toint(n) ((n) >> 12) +#define floattof32(n) ((int32)((n) * (1 << 12))) +#define f32tofloat(n) (((float)(n)) / (float)(1<<12)) + +typedef s16 t16; +#define f32tot16(n) ((t16)(n >> 8)) +#define inttot16(n) ((n) << 4) +#define t16toint(n) ((n) >> 4) +#define floattot16(n) ((t16)((n) * (1 << 4))) +#define t16ofloat(n) (((float)(n)) / (float)(1<<4)) + +typedef s16 v16; +#define inttov16(n) ((n) << 12) +#define f32tov16(n) (n) +#define floattov16(n) ((v16)((n) * (1 << 12))) +#define v16toint(n) ((n) >> 12) +#define v16tofloat(n) (((float)(n)) / (float)(1<<12)) + +typedef s16 v10; +#define inttov10(n) ((n) << 9) +#define f32tov10(n) ((v10)(n >> 3)) +#define v10toint(n) ((n) >> 9) +#define floattov10(n) ((v10)((n) * (1 << 9))) +#define v10tofloat(n) (((float)(n)) / (float)(1<<9)) + +/*----------------------*/ + +#ifndef OBJ_C +typedef int BOOL; +#else +//apple also defines BOOL +typedef int desmume_BOOL; +#define BOOL desmume_BOOL +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifdef __BIG_ENDIAN__ +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#endif + +#ifdef WORDS_BIGENDIAN +# define LOCAL_BE +#else +# define LOCAL_LE +#endif + +/* little endian (ds' endianess) to local endianess convert macros */ +#ifdef LOCAL_BE /* local arch is big endian */ +# define LE_TO_LOCAL_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff)) +# define LE_TO_LOCAL_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff)) +# define LE_TO_LOCAL_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff)) +# define LOCAL_TO_LE_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff)) +# define LOCAL_TO_LE_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff)) +# define LOCAL_TO_LE_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00)|(((x)>>40)&0xff00)|(((x)>>56)&0xff)) +#else /* local arch is little endian */ +# define LE_TO_LOCAL_16(x) (x) +# define LE_TO_LOCAL_32(x) (x) +# define LE_TO_LOCAL_64(x) (x) +# define LOCAL_TO_LE_16(x) (x) +# define LOCAL_TO_LE_32(x) (x) +# define LOCAL_TO_LE_64(x) (x) +#endif + +// kilobytes and megabytes macro +#define MB(x) ((x)*1024*1024) +#define KB(x) ((x)*1024) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define CPU_STR(c) ((c==ARM9)?"ARM9":"ARM7") +typedef enum +{ + ARM9 = 0, + ARM7 = 1 +} cpu_id_t; + +///endian-flips count bytes. count should be even and nonzero. +inline void FlipByteOrder(u8 *src, u32 count) +{ + u8 *start=src; + u8 *end=src+count-1; + + if((count&1) || !count) return; /* This shouldn't happen. */ + + while(count--) + { + u8 tmp; + + tmp=*end; + *end=*start; + *start=tmp; + end--; + start++; + } +} + + + +inline u64 double_to_u64(double d) { + union { + u64 a; + double b; + } fuxor; + fuxor.b = d; + return fuxor.a; +} + +inline double u64_to_double(u64 u) { + union { + u64 a; + double b; + } fuxor; + fuxor.a = u; + return fuxor.b; +} + +inline u32 float_to_u32(float f) { + union { + u32 a; + float b; + } fuxor; + fuxor.b = f; + return fuxor.a; +} + +inline float u32_to_float(u32 u) { + union { + u32 a; + float b; + } fuxor; + fuxor.a = u; + return fuxor.b; +} + + +///stores a 32bit value into the provided byte array in guaranteed little endian form +inline void en32lsb(u8 *buf, u32 morp) +{ + buf[0]=(u8)(morp); + buf[1]=(u8)(morp>>8); + buf[2]=(u8)(morp>>16); + buf[3]=(u8)(morp>>24); +} + +inline void en16lsb(u8* buf, u16 morp) +{ + buf[0]=(u8)morp; + buf[1]=(u8)(morp>>8); +} + +///unpacks a 64bit little endian value from the provided byte array into host byte order +inline u64 de64lsb(u8 *morp) +{ + return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24)|((u64)morp[4]<<32)|((u64)morp[5]<<40)|((u64)morp[6]<<48)|((u64)morp[7]<<56); +} + +///unpacks a 32bit little endian value from the provided byte array into host byte order +inline u32 de32lsb(u8 *morp) +{ + return morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24); +} + +///unpacks a 16bit little endian value from the provided byte array into host byte order +inline u16 de16lsb(u8 *morp) +{ + return morp[0]|(morp[1]<<8); +} + +#ifndef ARRAY_SIZE +//taken from winnt.h +extern "C++" // templates cannot be declared to have 'C' linkage +template +char (*BLAHBLAHBLAH( UNALIGNED T (&)[N] ))[N]; + +#define ARRAY_SIZE(A) (sizeof(*BLAHBLAHBLAH(A))) +#endif + + +//fairly standard for loop macros +#define MACRODO1(TRICK,TODO) { const int X = TRICK; TODO; } +#define MACRODO2(X,TODO) { MACRODO1((X),TODO) MACRODO1(((X)+1),TODO) } +#define MACRODO4(X,TODO) { MACRODO2((X),TODO) MACRODO2(((X)+2),TODO) } +#define MACRODO8(X,TODO) { MACRODO4((X),TODO) MACRODO4(((X)+4),TODO) } +#define MACRODO16(X,TODO) { MACRODO8((X),TODO) MACRODO8(((X)+8),TODO) } +#define MACRODO32(X,TODO) { MACRODO16((X),TODO) MACRODO16(((X)+16),TODO) } +#define MACRODO64(X,TODO) { MACRODO32((X),TODO) MACRODO32(((X)+32),TODO) } +#define MACRODO128(X,TODO) { MACRODO64((X),TODO) MACRODO64(((X)+64),TODO) } +#define MACRODO256(X,TODO) { MACRODO128((X),TODO) MACRODO128(((X)+128),TODO) } + +//this one lets you loop any number of times (as long as N<256) +#define MACRODO_N(N,TODO) {\ + if((N)&0x100) MACRODO256(0,TODO); \ + if((N)&0x080) MACRODO128((N)&(0x100),TODO); \ + if((N)&0x040) MACRODO64((N)&(0x100|0x080),TODO); \ + if((N)&0x020) MACRODO32((N)&(0x100|0x080|0x040),TODO); \ + if((N)&0x010) MACRODO16((N)&(0x100|0x080|0x040|0x020),TODO); \ + if((N)&0x008) MACRODO8((N)&(0x100|0x080|0x040|0x020|0x010),TODO); \ + if((N)&0x004) MACRODO4((N)&(0x100|0x080|0x040|0x020|0x010|0x008),TODO); \ + if((N)&0x002) MACRODO2((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004),TODO); \ + if((N)&0x001) MACRODO1((N)&(0x100|0x080|0x040|0x020|0x010|0x008|0x004|0x002),TODO); \ +} + +//--------------------------- +//Binary constant generator macro By Tom Torfs - donated to the public domain + +//turn a numeric literal into a hex constant +//(avoids problems with leading zeroes) +//8-bit constants max value 0x11111111, always fits in unsigned long +#define HEX__(n) 0x##n##LU + +//8-bit conversion function +#define B8__(x) ((x&0x0000000FLU)?1:0) \ ++((x&0x000000F0LU)?2:0) \ ++((x&0x00000F00LU)?4:0) \ ++((x&0x0000F000LU)?8:0) \ ++((x&0x000F0000LU)?16:0) \ ++((x&0x00F00000LU)?32:0) \ ++((x&0x0F000000LU)?64:0) \ ++((x&0xF0000000LU)?128:0) + +//for upto 8-bit binary constants +#define B8(d) ((unsigned char)B8__(HEX__(d))) + +// for upto 16-bit binary constants, MSB first +#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \ ++ B8(dlsb)) + +// for upto 32-bit binary constants, MSB first */ +#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \ ++ ((unsigned long)B8(db2)<<16) \ ++ ((unsigned long)B8(db3)<<8) \ ++ B8(dlsb)) + +//Sample usage: +//B8(01010101) = 85 +//B16(10101010,01010101) = 43605 +//B32(10000000,11111111,10101010,01010101) = 2164238933 +//--------------------------- + +#ifndef CTASSERT +#define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1] +#endif + +static const char hexValid[23] = {"0123456789ABCDEFabcdef"}; + + +template inline void reconstruct(T* t) { + t->~T(); + new(t) T(); +} + + +#endif diff --git a/source/fceultra/types.h b/source/fceultra/types.h index 498b317..b776419 100644 --- a/source/fceultra/types.h +++ b/source/fceultra/types.h @@ -44,10 +44,9 @@ typedef signed short int16; typedef signed int int32; #define dup _dup #define stat _stat -#define fstat _fstat #define mkdir _mkdir #define alloca _alloca -#define snprintf _snprintf +#define FCEUX_fstat _fstat #if _MSC_VER < 1500 #define vsnprintf _vsnprintf #endif @@ -74,6 +73,8 @@ typedef int32_t int32; typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; + +#define FCEUX_fstat fstat #endif #ifdef __GNUC__ diff --git a/source/fceultra/unif.cpp b/source/fceultra/unif.cpp index 7db121a..a4f57fc 100644 --- a/source/fceultra/unif.cpp +++ b/source/fceultra/unif.cpp @@ -118,6 +118,7 @@ static void MooMirroring(void) { if (mirrortodo < 0x4) SetupCartMirroring(mirrortodo, 1, 0); else if (mirrortodo == 0x4) { + FCEU_MemoryRand(exntar, sizeof(exntar), true); SetupCartMirroring(4, 1, exntar); AddExState(exntar, 2048, 0, "EXNR"); } else @@ -348,6 +349,7 @@ static BMAPPING bmap[] = { { "BS-5", BMCBS5_Init, 0 }, { "CC-21", UNLCC21_Init, 0 }, { "CITYFIGHT", UNLCITYFIGHT_Init, 0 }, + { "10-24-C-A1", BMC1024CA1_Init, 0 }, { "CNROM", CNROM_Init, 0 }, { "CPROM", CPROM_Init, BMCFLAG_16KCHRR }, { "D1038", BMCD1038_Init, 0 }, @@ -374,6 +376,7 @@ static BMAPPING bmap[] = { { "KS7010", UNLKS7010_Init, 0 }, { "KS7012", UNLKS7012_Init, 0 }, { "KS7013B", UNLKS7013B_Init, 0 }, + { "KS7016", UNLKS7016_Init, 0 }, { "KS7017", UNLKS7017_Init, 0 }, { "KS7030", UNLKS7030_Init, 0 }, { "KS7031", UNLKS7031_Init, 0 }, @@ -462,6 +465,16 @@ static BMAPPING bmap[] = { { "YOKO", UNLYOKO_Init, 0 }, { "SB-2000", UNLSB2000_Init, 0 }, { "COOLBOY", COOLBOY_Init, BMCFLAG_256KCHRR }, + { "158B", UNL158B_Init, 0 }, + { "DRAGONFIGHTER", UNLBMW8544_Init, 0 }, + { "EH8813A", UNLEH8813A_Init, 0 }, + { "HP898F", BMCHP898F_Init, 0 }, + { "F-15", BMCF15_Init, 0 }, + { "RT-01", UNLRT01_Init, 0 }, + { "81-01-31-C", BMC810131C_Init, 0 }, + { "8-IN-1", BMC8IN1_Init, 0 }, + { "80013-B", BMC80013B_Init, 0 }, + { "HPxx", BMCHPxx_Init, 0 }, { 0, 0, 0 } }; @@ -526,7 +539,7 @@ 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"); @@ -614,6 +627,7 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { strcpy(LoadedRomFName, name); //For the debugger list GameInterface = UNIFGI; + currCartInfo = &UNIFCart; return 1; aborto: diff --git a/source/fceultra/unif.h b/source/fceultra/unif.h index 0216c65..3644a37 100644 --- a/source/fceultra/unif.h +++ b/source/fceultra/unif.h @@ -1,151 +1,163 @@ -/* 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 - */ - -void AC08_Init(CartInfo *info); -void ANROM_Init(CartInfo *info); -void BMC11160_Init(CartInfo *info); -void BMC12IN1_Init(CartInfo *info); -void BMC13in1JY110_Init(CartInfo *info); -void BMC190in1_Init(CartInfo *info); -void BMC411120C_Init(CartInfo *info); -void BMC64in1nr_Init(CartInfo *info); -void BMC70in1B_Init(CartInfo *info); -void BMC70in1_Init(CartInfo *info); -void BMC810544CA1_Init(CartInfo *info); -void BMC830118C_Init(CartInfo *info); -void BMCA65AS_Init(CartInfo *info); -void BMCBS5_Init(CartInfo *info); -void BMCD1038_Init(CartInfo *info); -void BMCFK23CA_Init(CartInfo *info); -void BMCFK23C_Init(CartInfo *info); -void BMCG146_Init(CartInfo *info); -void BMCGK192_Init(CartInfo *info); -void BMCGS2004_Init(CartInfo *info); -void BMCGS2013_Init(CartInfo *info); -void BMCGhostbusters63in1_Init(CartInfo *info); -void BMCNTD03_Init(CartInfo *info); -void BMCT2271_Init(CartInfo *info); -void BMCT262_Init(CartInfo *info); -void CNROM_Init(CartInfo *info); -void CPROM_Init(CartInfo *info); -void DreamTech01_Init(CartInfo *info); -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 HKROM_Init(CartInfo *info); -void LE05_Init(CartInfo *info); -void LH10_Init(CartInfo *info); -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 NROM_Init(CartInfo *info); -void Novel_Init(CartInfo *info); -void S74LS374NA_Init(CartInfo *info); -void S74LS374N_Init(CartInfo *info); -void S8259A_Init(CartInfo *info); -void S8259B_Init(CartInfo *info); -void S8259C_Init(CartInfo *info); -void S8259D_Init(CartInfo *info); -void SA0036_Init(CartInfo *info); -void SA0037_Init(CartInfo *info); -void SA009_Init(CartInfo *info); -void SA0161M_Init(CartInfo *info); -void SA72007_Init(CartInfo *info); -void SA72008_Init(CartInfo *info); -void SA9602B_Init(CartInfo *info); -void SAROM_Init(CartInfo *info); -void SBROM_Init(CartInfo *info); -void SCROM_Init(CartInfo *info); -void SEROM_Init(CartInfo *info); -void SGROM_Init(CartInfo *info); -void SKROM_Init(CartInfo *info); -void SL1ROM_Init(CartInfo *info); -void SLROM_Init(CartInfo *info); -void SNROM_Init(CartInfo *info); -void SOROM_Init(CartInfo *info); -void SSSNROM_Init(CartInfo *info); -void SUNSOFT_UNROM_Init(CartInfo *info); // "Shanghi" original version mapper -void Super24_Init(CartInfo *info); -void Supervision16_Init(CartInfo *info); -void TBROM_Init(CartInfo *info); -void TCA01_Init(CartInfo *info); -void TCU01_Init(CartInfo *info); -void TCU02_Init(CartInfo *info); -void TEROM_Init(CartInfo *info); -void TFROM_Init(CartInfo *info); -void TGROM_Init(CartInfo *info); -void TKROM_Init(CartInfo *info); -void TKSROM_Init(CartInfo *info); -void TLROM_Init(CartInfo *info); -void TLSROM_Init(CartInfo *info); -void TQROM_Init(CartInfo *info); -void TQROM_Init(CartInfo *info); -void TSROM_Init(CartInfo *info); -void Transformer_Init(CartInfo *info); -void UNL22211_Init(CartInfo *info); -void UNL3DBlock_Init(CartInfo *info); -void UNL43272_Init(CartInfo *info); -void UNL6035052_Init(CartInfo *info); -void UNL8157_Init(CartInfo *info); -void UNL8237A_Init(CartInfo *info); -void UNL8237_Init(CartInfo *info); -void UNLA9746_Init(CartInfo *info); -void UNLAX5705_Init(CartInfo *info); -void UNLBB_Init(CartInfo *info); -void UNLCC21_Init(CartInfo *info); -void UNLCITYFIGHT_Init(CartInfo *info); -void UNLD2000_Init(CartInfo *info); -void UNLEDU2000_Init(CartInfo *info); -void UNLFS304_Init(CartInfo *info); -void UNLH2288_Init(CartInfo *info); -void UNLKOF97_Init(CartInfo *info); -void UNLKS7012_Init(CartInfo *info); -void UNLKS7013B_Init(CartInfo *info); -void UNLKS7017_Init(CartInfo *info); -void UNLKS7030_Init(CartInfo *info); -void UNLKS7031_Init(CartInfo *info); -void UNLKS7032_Init(CartInfo *info); -void UNLKS7037_Init(CartInfo *info); -void UNLKS7057_Init(CartInfo *info); -void UNLN625092_Init(CartInfo *info); -void UNLMaliSB_Init(CartInfo *info); -void UNLOneBus_Init(CartInfo *info); -void UNLPEC586Init(CartInfo *info); -void UNLSC127_Init(CartInfo *info); -void UNLSHeroes_Init(CartInfo *info); -void UNLSL12_Init(CartInfo *info); -void UNLSL1632_Init(CartInfo *info); -void UNLSMB2J_Init(CartInfo *info); -void UNLT230_Init(CartInfo *info); -void UNLTF1201_Init(CartInfo *info); -void UNLVRC7_Init(CartInfo *info); -void UNLYOKO_Init(CartInfo *info); -void UNROM_Init(CartInfo *info); -void UNROM512_Init(CartInfo *info); -void UNLSB2000_Init(CartInfo *info); -void UNLKS7010_Init(CartInfo *info); -void COOLBOY_Init(CartInfo *info); - -extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM - // bank switcherooing with certain boards... +/* 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 + */ + +void AC08_Init(CartInfo *info); +void ANROM_Init(CartInfo *info); +void BMC11160_Init(CartInfo *info); +void BMC12IN1_Init(CartInfo *info); +void BMC13in1JY110_Init(CartInfo *info); +void BMC190in1_Init(CartInfo *info); +void BMC411120C_Init(CartInfo *info); +void BMC64in1nr_Init(CartInfo *info); +void BMC70in1B_Init(CartInfo *info); +void BMC70in1_Init(CartInfo *info); +void BMC810544CA1_Init(CartInfo *info); +void BMC830118C_Init(CartInfo *info); +void BMCA65AS_Init(CartInfo *info); +void BMCBS5_Init(CartInfo *info); +void BMCD1038_Init(CartInfo *info); +void BMCFK23CA_Init(CartInfo *info); +void BMCFK23C_Init(CartInfo *info); +void BMCG146_Init(CartInfo *info); +void BMCGK192_Init(CartInfo *info); +void BMCGS2004_Init(CartInfo *info); +void BMCGS2013_Init(CartInfo *info); +void BMCGhostbusters63in1_Init(CartInfo *info); +void BMCNTD03_Init(CartInfo *info); +void BMCT2271_Init(CartInfo *info); +void BMCT262_Init(CartInfo *info); +void BMC1024CA1_Init(CartInfo *info); +void CNROM_Init(CartInfo *info); +void CPROM_Init(CartInfo *info); +void DreamTech01_Init(CartInfo *info); +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 HKROM_Init(CartInfo *info); +void LE05_Init(CartInfo *info); +void LH10_Init(CartInfo *info); +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 NROM_Init(CartInfo *info); +void Novel_Init(CartInfo *info); +void S74LS374NA_Init(CartInfo *info); +void S74LS374N_Init(CartInfo *info); +void S8259A_Init(CartInfo *info); +void S8259B_Init(CartInfo *info); +void S8259C_Init(CartInfo *info); +void S8259D_Init(CartInfo *info); +void SA0036_Init(CartInfo *info); +void SA0037_Init(CartInfo *info); +void SA009_Init(CartInfo *info); +void SA0161M_Init(CartInfo *info); +void SA72007_Init(CartInfo *info); +void SA72008_Init(CartInfo *info); +void SA9602B_Init(CartInfo *info); +void SAROM_Init(CartInfo *info); +void SBROM_Init(CartInfo *info); +void SCROM_Init(CartInfo *info); +void SEROM_Init(CartInfo *info); +void SGROM_Init(CartInfo *info); +void SKROM_Init(CartInfo *info); +void SL1ROM_Init(CartInfo *info); +void SLROM_Init(CartInfo *info); +void SNROM_Init(CartInfo *info); +void SOROM_Init(CartInfo *info); +void SSSNROM_Init(CartInfo *info); +void SUNSOFT_UNROM_Init(CartInfo *info); // "Shanghi" original version mapper +void Super24_Init(CartInfo *info); +void Supervision16_Init(CartInfo *info); +void TBROM_Init(CartInfo *info); +void TCA01_Init(CartInfo *info); +void TCU01_Init(CartInfo *info); +void TCU02_Init(CartInfo *info); +void TEROM_Init(CartInfo *info); +void TFROM_Init(CartInfo *info); +void TGROM_Init(CartInfo *info); +void TKROM_Init(CartInfo *info); +void TKSROM_Init(CartInfo *info); +void TLROM_Init(CartInfo *info); +void TLSROM_Init(CartInfo *info); +void TQROM_Init(CartInfo *info); +void TQROM_Init(CartInfo *info); +void TSROM_Init(CartInfo *info); +void Transformer_Init(CartInfo *info); +void UNL22211_Init(CartInfo *info); +void UNL3DBlock_Init(CartInfo *info); +void UNL43272_Init(CartInfo *info); +void UNL6035052_Init(CartInfo *info); +void UNL8157_Init(CartInfo *info); +void UNL8237A_Init(CartInfo *info); +void UNL8237_Init(CartInfo *info); +void UNLA9746_Init(CartInfo *info); +void UNLAX5705_Init(CartInfo *info); +void UNLBB_Init(CartInfo *info); +void UNLCC21_Init(CartInfo *info); +void UNLCITYFIGHT_Init(CartInfo *info); +void UNLD2000_Init(CartInfo *info); +void UNLEDU2000_Init(CartInfo *info); +void UNLFS304_Init(CartInfo *info); +void UNLH2288_Init(CartInfo *info); +void UNLKOF97_Init(CartInfo *info); +void UNLKS7012_Init(CartInfo *info); +void UNLKS7013B_Init(CartInfo *info); +void UNLKS7016_Init(CartInfo *info); +void UNLKS7017_Init(CartInfo *info); +void UNLKS7030_Init(CartInfo *info); +void UNLKS7031_Init(CartInfo *info); +void UNLKS7032_Init(CartInfo *info); +void UNLKS7037_Init(CartInfo *info); +void UNLKS7057_Init(CartInfo *info); +void UNLN625092_Init(CartInfo *info); +void UNLMaliSB_Init(CartInfo *info); +void UNLOneBus_Init(CartInfo *info); +void UNLPEC586Init(CartInfo *info); +void UNLSC127_Init(CartInfo *info); +void UNLSHeroes_Init(CartInfo *info); +void UNLSL12_Init(CartInfo *info); +void UNLSL1632_Init(CartInfo *info); +void UNLSMB2J_Init(CartInfo *info); +void UNLT230_Init(CartInfo *info); +void UNLTF1201_Init(CartInfo *info); +void UNLVRC7_Init(CartInfo *info); +void UNLYOKO_Init(CartInfo *info); +void UNROM_Init(CartInfo *info); +void UNROM512_Init(CartInfo *info); +void UNLSB2000_Init(CartInfo *info); +void UNLKS7010_Init(CartInfo *info); +void COOLBOY_Init(CartInfo *info); +void UNL158B_Init(CartInfo *info); +void UNLBMW8544_Init(CartInfo *info); +void UNLEH8813A_Init(CartInfo *info); +void BMCHP898F_Init(CartInfo *info); +void BMCF15_Init(CartInfo *info); +void UNLRT01_Init(CartInfo *info); +void BMC810131C_Init(CartInfo *info); +void BMC8IN1_Init(CartInfo *info); +void BMC80013B_Init(CartInfo *info); +void BMCHPxx_Init(CartInfo *info); + +extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM + // bank switcherooing with certain boards... diff --git a/source/fceultra/utils/memory.cpp b/source/fceultra/utils/memory.cpp index 088c9a8..80e072e 100644 --- a/source/fceultra/utils/memory.cpp +++ b/source/fceultra/utils/memory.cpp @@ -39,11 +39,7 @@ void *FCEU_gmalloc(uint32 size) FCEU_PrintError("Error allocating memory! Doing a hard exit."); exit(1); } - //mbg 6/17/08 - sometimes this memory is used as RAM or somesuch without clearing first. - //this yields different behavior in debug and release modes. - //specifically, saveram wasnt getting cleared so the games thought their savefiles were initialized - //so we are going to clear it here. - memset(ret,0,size); + FCEU_MemoryRand((uint8*)ret,size,true); // initialize according to RAMInitOption, default zero return ret; } @@ -57,11 +53,7 @@ void *FCEU_malloc(uint32 size) FCEU_PrintError("Error allocating memory!"); return(0); } - //mbg 6/17/08 - sometimes this memory is used as RAM or somesuch without clearing first. - //this yields different behavior in debug and release modes. - //specifically, saveram wasnt getting cleared so the games thought their savefiles were initialized - //so we are going to clear it here. - memset(ret,0,size); + memset(ret,0,size); // initialize to 0 return ret; } diff --git a/source/fceultra/utils/memory.h b/source/fceultra/utils/memory.h index 34676d3..559c7ba 100644 --- a/source/fceultra/utils/memory.h +++ b/source/fceultra/utils/memory.h @@ -24,8 +24,8 @@ #define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;} -void *FCEU_malloc(uint32 size); -void *FCEU_gmalloc(uint32 size); +void *FCEU_malloc(uint32 size); // initialized to 0 +void *FCEU_gmalloc(uint32 size); // used by boards for WRAM etc, initialized to 0 (default) or other via RAMInitOption void FCEU_gfree(void *ptr); void FCEU_free(void *ptr); void FCEU_memmove(void *d, void *s, uint32 l); diff --git a/source/fceultra/utils/xstring.cpp b/source/fceultra/utils/xstring.cpp index c85984e..831aebd 100644 --- a/source/fceultra/utils/xstring.cpp +++ b/source/fceultra/utils/xstring.cpp @@ -231,8 +231,8 @@ std::string BytesToString(const void* data, int len) { Base64Table[ input[0] >> 2 ], Base64Table[ ((input[0] & 0x03) << 4) | (input[1] >> 4) ], - n<2 ? '=' : Base64Table[ ((input[1] & 0x0F) << 2) | (input[2] >> 6) ], - n<3 ? '=' : Base64Table[ input[2] & 0x3F ] + static_cast (n<2 ? '=' : Base64Table[ ((input[1] & 0x0F) << 2) | (input[2] >> 6) ]), + static_cast (n<3 ? '=' : Base64Table[ input[2] & 0x3F ]) }; ret.append(output, output+4); } @@ -296,9 +296,9 @@ bool StringToBytes(const std::string& str, void* data, int len) } unsigned char outpacket[3] = { - (converted[0] << 2) | (converted[1] >> 4), - (converted[1] << 4) | (converted[2] >> 2), - (converted[2] << 6) | (converted[3]) + static_cast((converted[0] << 2) | (converted[1] >> 4)), + static_cast((converted[1] << 4) | (converted[2] >> 2)), + static_cast((converted[2] << 6) | (converted[3])) }; int outlen = (input[2] == '=') ? 1 : (input[3] == '=' ? 2 : 3); if(outlen > len) outlen = len; diff --git a/source/fceultra/version.h b/source/fceultra/version.h index 3b9e833..d0bca7d 100644 --- a/source/fceultra/version.h +++ b/source/fceultra/version.h @@ -26,12 +26,12 @@ //todo - everyone will want to support this eventually, i suppose #ifdef _MSC_VER -#include "svnrev.h" +#include "scmrev.h" #else #ifdef SVN_REV -#define SVN_REV_STR SVN_REV +#define SCM_REV_STR SCM_REV #else -#define SVN_REV_STR "" +#define SCM_REV_STR "" #endif #endif @@ -44,7 +44,7 @@ #elif defined(PUBLIC_RELEASE) #define FCEU_SUBVERSION_STRING "" #else -#define FCEU_SUBVERSION_STRING "-interim svn" SVN_REV_STR +#define FCEU_SUBVERSION_STRING "-interim git" SCM_REV_STR #endif #if defined(_MSC_VER) diff --git a/source/fceultra/video.cpp b/source/fceultra/video.cpp index 4956a38..6c19e39 100644 --- a/source/fceultra/video.cpp +++ b/source/fceultra/video.cpp @@ -32,6 +32,7 @@ #include "vsuni.h" #include "drawing.h" #include "driver.h" + #ifdef _S9XLUA_H #include "fceulua.h" #endif @@ -56,10 +57,17 @@ #include #include -uint8 *XBuf=NULL; -uint8 *XBackBuf=NULL; +//XBuf: +//0-63 is reserved for 7 special colours used by FCEUX (overlay, etc.) +//64-127 is the most-used emphasis setting per frame +//128-195 is the palette with no emphasis +//196-255 is the palette with all emphasis bits on +u8 *XBuf=NULL; //used for current display +u8 *XBackBuf=NULL; //ppu output is stashed here before drawing happens +u8 *XDBuf=NULL; //corresponding to XBuf but with deemph bits +u8 *XDBackBuf=NULL; //corresponding to XBackBuf but with deemph bits int ClipSidesOffset=0; //Used to move displayed messages when Clips left and right sides is checked -static uint8 *xbsave=NULL; +static u8 *xbsave=NULL; GUIMESSAGE guiMessage; GUIMESSAGE subtitleMessage; @@ -105,29 +113,35 @@ void FCEU_KillVirtualVideo(void) **/ int FCEU_InitVirtualVideo(void) { - if(!XBuf) /* Some driver code may allocate XBuf externally. */ - /* 256 bytes per scanline, * 240 scanline maximum, +16 for alignment, - */ - - if(!(XBuf= (uint8*) (FCEU_malloc(256 * 256 + 16))) || - !(XBackBuf= (uint8*) (FCEU_malloc(256 * 256 + 16)))) - { - return 0; - } - - xbsave = XBuf; - - if( sizeof(uint8*) == 4 ) - { - uintptr_t m = (uintptr_t)XBuf; - m = ( 8 - m) & 7; - XBuf+=m; - } - - memset(XBuf,128,256*256); //*240); - memset(XBackBuf,128,256*256); - + //Some driver code may allocate XBuf externally. + //256 bytes per scanline, * 240 scanline maximum, +16 for alignment, + if(XBuf) return 1; + + XBuf = (u8*)FCEU_malloc(256 * 256 + 16); + XBackBuf = (u8*)FCEU_malloc(256 * 256 + 16); + XDBuf = (u8*)FCEU_malloc(256 * 256 + 16); + XDBackBuf = (u8*)FCEU_malloc(256 * 256 + 16); + if(!XBuf || !XBackBuf || !XDBuf || !XDBackBuf) + { + return 0; + } + + xbsave = XBuf; + + if( sizeof(uint8*) == 4 ) + { + uintptr_t m = (uintptr_t)XBuf; + m = ( 8 - m) & 7; + XBuf+=m; + } + + memset(XBuf,128,256*256); + memset(XBackBuf,128,256*256); + memset(XBuf,128,256*256); + memset(XBackBuf,128,256*256); + + return 1; } #ifdef FRAMESKIP @@ -551,11 +565,14 @@ int GetScreenPixelPalette(int x, int y, bool usebackup) { int SaveSnapshot(void) { +#ifdef GEKKO + return 0; +#else int totallines=FSettings.LastSLine-FSettings.FirstSLine+1; int x,u,y; FILE *pp=NULL; uint8 *compmem=NULL; - uLongf compmemsize=totallines*263+12; + uLongf compmemsize=(totallines*263+12)*3; if(!(compmem=(uint8 *)FCEU_malloc(compmemsize))) return 0; @@ -575,7 +592,7 @@ int SaveSnapshot(void) } { - static uint8 header[8]={137,80,78,71,13,10,26,10}; + static const uint8 header[8]={137,80,78,71,13,10,26,10}; if(fwrite(header,8,1,pp)!=1) goto PNGerr; } @@ -589,8 +606,8 @@ int SaveSnapshot(void) chunko[4]=chunko[5]=chunko[6]=0; chunko[7]=totallines; // Height - chunko[8]=8; // bit depth - chunko[9]=3; // Color type; indexed 8-bit + chunko[8]=8; // 8 bits per sample(24 bits per pixel) + chunko[9]=2; // Color type; RGB triplet chunko[10]=0; // compression: deflate chunko[11]=0; // Basic adapative filter set(though none are used). chunko[12]=0; // No interlace. @@ -599,19 +616,12 @@ int SaveSnapshot(void) goto PNGerr; } - { - uint8 pdata[256*3]; - for(x=0;x<256;x++) - FCEUD_GetPalette(x,pdata+x*3,pdata+x*3+1,pdata+x*3+2); - if(!WritePNGChunk(pp,256*3,"PLTE",pdata)) - goto PNGerr; - } - { uint8 *tmp=XBuf+FSettings.FirstSLine*256; uint8 *dest,*mal,*mork; - if(!(mal=mork=dest=(uint8 *)FCEU_dmalloc((totallines<<8)+totallines))) + int bufsize = (256*3+1)*totallines; + if(!(mal=mork=dest=(uint8 *)FCEU_dmalloc(bufsize))) goto PNGerr; // mork=dest=XBuf; @@ -619,11 +629,17 @@ int SaveSnapshot(void) { *dest=0; // No filter. dest++; - for(x=256;x;x--,tmp++,dest++) - *dest=*tmp; + for(x=256;x;x--) + { + u32 color = ModernDeemphColorMap(tmp,XBuf,1,1); + *dest++=(color>>0x10)&0xFF; + *dest++=(color>>0x08)&0xFF; + *dest++=(color>>0x00)&0xFF; + tmp++; + } } - if(compress(compmem,&compmemsize,mork,(totallines<<8)+totallines)!=Z_OK) + if(compress(compmem,&compmemsize,mork,bufsize)!=Z_OK) { if(mal) free(mal); goto PNGerr; @@ -647,6 +663,7 @@ PNGerr: if(pp) fclose(pp); return(0); +#endif } //overloaded SaveSnapshot for "Savesnapshot As" function diff --git a/source/fceultra/video.h b/source/fceultra/video.h index 167a75d..79c6fec 100644 --- a/source/fceultra/video.h +++ b/source/fceultra/video.h @@ -9,6 +9,8 @@ uint32 GetScreenPixel(int x, int y, bool usebackup); int GetScreenPixelPalette(int x, int y, bool usebackup); extern uint8 *XBuf; extern uint8 *XBackBuf; +extern uint8 *XDBuf; +extern uint8 *XDBackBuf; extern int ClipSidesOffset; extern struct GUIMESSAGE { diff --git a/source/fceultra/vsuni.cpp b/source/fceultra/vsuni.cpp index e7e718a..5755474 100644 --- a/source/fceultra/vsuni.cpp +++ b/source/fceultra/vsuni.cpp @@ -301,7 +301,7 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring) { while (vs->name) { if (md5partial == vs->md5partial) { - if (vs->ppu < RCP2C03B) pale = vs->ppu; + if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu; *MapperNo = vs->mapper; *Mirroring = vs->mirroring; GameInfo->type = GIT_VSUNI; diff --git a/source/fceultra/x6502.cpp b/source/fceultra/x6502.cpp index 472232d..c167adc 100644 --- a/source/fceultra/x6502.cpp +++ b/source/fceultra/x6502.cpp @@ -32,14 +32,16 @@ #include X6502 X; uint32 timestamp; +uint32 soundtimestamp; void (*MapIRQHook)(int a); #define ADDCYC(x) \ -{ \ +{ \ int __x=x; \ _tcount+=__x; \ _count-=__x*48; \ timestamp+=__x; \ + if(!overclocking) soundtimestamp+=__x; \ } //normal memory read @@ -404,12 +406,14 @@ void X6502_Init(void) } } +extern int StackAddrBackup; void X6502_Power(void) { _count=_tcount=_IRQlow=_PC=_A=_X=_Y=_P=_PI=_DB=_jammed=0; _S=0xFD; - timestamp=0; + timestamp=soundtimestamp=0; X6502_Reset(); + StackAddrBackup = -1; } void X6502_Run(int32 cycles) @@ -493,7 +497,9 @@ extern int test; test++; temp=_tcount; _tcount=0; if(MapIRQHook) MapIRQHook(temp); - FCEU_SoundCPUHook(temp); + + if (!overclocking) + FCEU_SoundCPUHook(temp); #ifdef _S9XLUA_H CallRegisteredLuaMemHook(_PC, 1, 0, LUAMEMHOOK_EXEC); #endif @@ -537,7 +543,7 @@ const uint8 opsize[256] = { #else /*0x00*/ 1, //BRK #endif -/*0x01*/ 2,0,0,0,2,2,0,1,2,1,0,0,3,3,0, +/*0x01*/ 2,0,0,0,2,2,0,1,2,1,0,0,3,3,0, /*0x10*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0, /*0x20*/ 3,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0, /*0x30*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0, @@ -569,20 +575,58 @@ const uint8 opsize[256] = { // 8 = Zero Page,Y // const uint8 optype[256] = { -/*0x00*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0, -/*0x10*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, -/*0x20*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, -/*0x30*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, -/*0x40*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0, -/*0x50*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, -/*0x60*/ 0,1,0,0,0,2,2,0,0,0,0,0,3,3,3,0, -/*0x70*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, -/*0x80*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, -/*0x90*/ 0,4,0,0,5,5,8,0,0,6,0,0,0,7,0,0, -/*0xA0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, -/*0xB0*/ 0,4,0,0,5,5,8,0,0,6,0,0,7,7,6,0, -/*0xC0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, -/*0xD0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, -/*0xE0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, -/*0xF0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0 +/*0x00*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0x10*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7, +/*0x20*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0x30*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7, +/*0x40*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0x50*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7, +/*0x60*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0x70*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7, +/*0x80*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0x90*/ 0,4,0,3,5,5,8,8,0,6,0,6,7,7,6,6, +/*0xA0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0xB0*/ 0,4,0,3,5,5,8,8,0,6,0,6,7,7,6,6, +/*0xC0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0xD0*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7, +/*0xE0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3, +/*0xF0*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7, }; + +// the opwrite table aids in predicting the value written for any 6502 opcode +// +// 0 = No value written +// 1 = Write from A +// 2 = Write from X +// 3 = Write from Y +// 4 = Write from P +// 5 = ASL (SLO) +// 6 = LSR (SRE) +// 7 = ROL (RLA) +// 8 = ROR (RRA) +// 9 = INC (ISC) +// 10 = DEC (DCP) +// 11 = (SAX) +// 12 = (AHX) +// 13 = (SHY) +// 14 = (SHX) +// 15 = (TAS) + +const uint8 opwrite[256] = { +/*0x00*/ 0, 0, 0, 5, 0, 0, 5, 5, 4, 0, 0, 0, 0, 0, 5, 5, +/*0x10*/ 0, 0, 0, 5, 0, 0, 5, 5, 0, 0, 0, 5, 0, 0, 5, 5, +/*0x20*/ 0, 0, 0, 7, 0, 0, 7, 7, 0, 0, 7, 0, 0, 0, 7, 7, +/*0x30*/ 0, 0, 0, 7, 0, 0, 7, 7, 0, 0, 0, 7, 0, 0, 7, 7, +/*0x40*/ 0, 0, 0, 6, 0, 0, 6, 6, 1, 0, 6, 0, 0, 0, 6, 6, +/*0x50*/ 0, 0, 0, 6, 0, 0, 6, 6, 0, 0, 0, 6, 0, 0, 6, 6, +/*0x60*/ 0, 0, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 0, 0, 8, 8, +/*0x70*/ 0, 0, 0, 8, 0, 0, 8, 8, 0, 0, 0, 8, 0, 0, 8, 8, +/*0x80*/ 0, 1, 0,11, 3, 1, 2,11, 0, 0, 0, 0, 3, 1, 2,11, +/*0x90*/ 0, 1, 0,12, 3, 1, 2,11, 0, 1, 0,15,13, 1,14,12, +/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*0xC0*/ 0, 0, 0,10, 0, 0,10,10, 0, 0, 0, 0, 0, 0,10,10, +/*0xD0*/ 0, 0, 0,10, 0, 0,10,10, 0, 0, 0,10, 0, 0,10,10, +/*0xE0*/ 0, 0, 0, 9, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, +/*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 34d4385..3204e69 100644 --- a/source/fceultra/x6502.h +++ b/source/fceultra/x6502.h @@ -31,6 +31,9 @@ extern const uint8 opsize[256]; //the optype table is a quick way to grab the addressing mode for any 6502 opcode extern const uint8 optype[256]; +// the opwrite table aids in predicting the value written for any 6502 opcode +extern const uint8 opwrite[256]; + //----------- //mbg 6/30/06 - some of this was removed to mimic XD //#ifdef FCEUDEF_DEBUGGER @@ -47,8 +50,8 @@ void X6502_RunDebug(int32 cycles); //------------ extern uint32 timestamp; - - +extern uint32 soundtimestamp; +extern int scanline; #define N_FLAG 0x80 #define V_FLAG 0x40 diff --git a/source/fceusupport.cpp b/source/fceusupport.cpp index 4463edb..442ce82 100644 --- a/source/fceusupport.cpp +++ b/source/fceusupport.cpp @@ -18,6 +18,10 @@ #include "menu.h" bool turbo = false; +bool paldeemphswap = 0; +int dendy; +bool swapDuty; +int KillFCEUXonFrame = 0; /** * Closes a game. Frees memory, and deinitializes the drivers. @@ -172,3 +176,4 @@ const char *FCEUD_GetCompilerString() { return NULL; } void FCEUI_UseInputPreset(int preset) { } void FCEUD_SoundVolumeAdjust(int n) { } void FCEUD_SetEmulationSpeed(int cmd) { } +void GetMouseData(uint32 (&d)[3]) { }