update to the latest FCEUX core from git head.

This commit is contained in:
Daryl Borth 2018-08-13 09:04:20 -06:00
parent a9c3f8c631
commit 50b3150515
78 changed files with 4392 additions and 3081 deletions

View File

@ -30,7 +30,7 @@ https://github.com/dborth/fceugx/releases
* Cheat support (.CHT files and Game Genie) * Cheat support (.CHT files and Game Genie)
* Famicom 3D System support * Famicom 3D System support
* IPS/UPS automatic patching 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! * Open Source!
×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬ ×—–­—–­—–­—–­ –­—–­—–­—–­—–­—–­—–­—–­—–­—–­— ­—–­—–­—–­—–­—–­—–­—–­—-­—–­-–•¬
@ -39,6 +39,7 @@ https://github.com/dborth/fceugx/releases
[3.4.0] [3.4.0]
* Update to the latest FCEUX core
* Allow loader to pass two arguments instead of three (libertyernie) * Allow loader to pass two arguments instead of three (libertyernie)
* Add PocketNES interoperability (load ROMs and read/write SRAM) * Add PocketNES interoperability (load ROMs and read/write SRAM)
* Add option to not append " Auto" on saves * Add option to not append " Auto" on saves

View File

@ -272,7 +272,7 @@ char *Disassemble(int addr, uint8 *opcode) {
(a) = opcode[1] | opcode[2]<<8; \ (a) = opcode[1] | opcode[2]<<8; \
} }
#define zpIndex(a,i) { \ #define zpIndex(a,i) { \
(a) = opcode[1]+(i); \ (a) = (opcode[1]+(i))&0xFF; \
} }
#define indirectX(a) { \ #define indirectX(a) { \
(a) = (opcode[1]+RX)&0xFF; \ (a) = (opcode[1]+RX)&0xFF; \
@ -360,8 +360,8 @@ char *Disassemble(int addr, uint8 *opcode) {
case 0xE6: strcpy(chr,"INC"); goto _zeropage; case 0xE6: strcpy(chr,"INC"); goto _zeropage;
_zeropage: _zeropage:
// ################################## Start of SP CODE ########################### // ################################## Start of SP CODE ###########################
// Change width to %04X // Change width to %04X // don't!
sprintf(str,"%s $%04X = #$%02X", chr,opcode[1],GetMem(opcode[1])); sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
// ################################## End of SP CODE ########################### // ################################## End of SP CODE ###########################
break; break;
@ -457,7 +457,7 @@ char *Disassemble(int addr, uint8 *opcode) {
_zeropagex: _zeropagex:
zpIndex(tmp,RX); zpIndex(tmp,RX);
// ################################## Start of SP CODE ########################### // ################################## 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)); sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ########################### // ################################## End of SP CODE ###########################
break; break;
@ -515,8 +515,8 @@ char *Disassemble(int addr, uint8 *opcode) {
_zeropagey: _zeropagey:
zpIndex(tmp,RY); zpIndex(tmp,RY);
// ################################## Start of SP CODE ########################### // ################################## Start of SP CODE ###########################
// Change width to %04X // Change width to %04X // don't!
sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ########################### // ################################## End of SP CODE ###########################
break; break;

View File

@ -19,6 +19,7 @@
* *
* TXC mappers, originally much complex banksitching * 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-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang
* 01-22110-000 (52S ) - MGC-002 2-in-1 Gun * 01-22110-000 (52S ) - MGC-002 2-in-1 Gun
* 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block * 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-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman
* 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior * 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior
* 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1 * 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-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom
* 01-22200-400 (------------) (079 ) - ET.03 F-15 City War * 01-22200-400 (------------) (079 ) - ET.03 F-15 City War
* (172 ) - 1991 Du Ma Racing * (172 ) - 1991 Du Ma Racing

View File

@ -55,7 +55,7 @@ static void M168Power(void) {
SetReadHandler(0x8000, 0xFFFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR);
} }
static void MNNNClose(void) { static void M168Close(void) {
if (CHRRAM) if (CHRRAM)
FCEU_gfree(CHRRAM); FCEU_gfree(CHRRAM);
CHRRAM = NULL; CHRRAM = NULL;
@ -67,7 +67,7 @@ static void StateRestore(int version) {
void Mapper168_Init(CartInfo *info) { void Mapper168_Init(CartInfo *info) {
info->Power = M168Power; info->Power = M168Power;
info->Close = MNNNClose; info->Close = M168Close;
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0);

View File

@ -29,6 +29,12 @@ static uint8 reg[4];
static uint8 *WRAM = NULL; static uint8 *WRAM = NULL;
static uint32 WRAMSIZE; 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 // SND Registers
static uint8 pcm_enable = 0; static uint8 pcm_enable = 0;
static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6; static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6;
@ -40,41 +46,41 @@ static SFORMAT StateRegs[] =
{ 0 } { 0 }
}; };
static int16 step_size[49] = { //static int16 step_size[49] = {
16, 17, 19, 21, 23, 25, 28, 31, 34, 37, // 16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
41, 45, 50, 55, 60, 66, 73, 80, 88, 97, // 41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
107, 118, 130, 143, 157, 173, 190, 209, 230, 253, // 107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
279, 307, 337, 371, 408, 449, 494, 544, 598, 658, // 279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 // 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
}; //49 items //}; //49 items
static int32 step_adj[16] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 }; //static int32 step_adj[16] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 };
//decode stuff //decode stuff
static int32 jedi_table[16 * 49]; //static int32 jedi_table[16 * 49];
static int32 acc = 0; //ADPCM accumulator, initial condition must be 0 //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 decstep = 0; //ADPCM decoding step, initial condition must be 0
static void jedi_table_init() { //static void jedi_table_init() {
int step, nib; // 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++) { //static uint8 decode(uint8 code) {
for (nib = 0; nib < 16; nib++) { // acc += jedi_table[decstep + code];
int value = (2 * (nib & 0x07) + 1) * step_size[step] / 8; // if ((acc & ~0x7ff) != 0) // acc is > 2047
jedi_table[step * 16 + nib] = ((nib & 0x08) != 0) ? -value : value; // acc |= ~0xfff;
} // else acc &= 0xfff;
} // decstep += step_adj[code & 7] * 16;
} // if (decstep < 0) decstep = 0;
// if (decstep > 48 * 16) decstep = 48 * 16;
static uint8 decode(uint8 code) { // return (acc >> 8) & 0xff;
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) { static void Sync(void) {
uint32 sbank = reg[1] & 0x7; uint32 sbank = reg[1] & 0x7;
@ -109,11 +115,11 @@ static DECLFW(M178WriteSnd) {
if (V & 0xF0) { if (V & 0xF0) {
pcm_enable = 1; pcm_enable = 1;
// pcmwrite(0x4011, (V & 0xF) << 3); // pcmwrite(0x4011, (V & 0xF) << 3);
pcmwrite(0x4011, decode(V & 0xf)); // pcmwrite(0x4011, decode(V & 0xf));
} else } else
pcm_enable = 0; pcm_enable = 0;
} else }// else
FCEU_printf("misc %04x:%02x\n", A, V); // FCEU_printf("misc %04x:%02x\n", A, V);
} }
static DECLFR(M178ReadSnd) { static DECLFR(M178ReadSnd) {
@ -123,13 +129,19 @@ static DECLFR(M178ReadSnd) {
return X.DB; 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) { static void M178Power(void) {
reg[0] = reg[1] = reg[2] = reg[3] = 0; reg[0] = reg[1] = reg[2] = reg[3] = SensorDelay = 0;
Sync(); Sync();
pcmwrite = GetWriteHandler(0x4011); // pcmwrite = GetWriteHandler(0x4011);
SetWriteHandler(0x4800, 0x4fff, M178Write); SetWriteHandler(0x4800, 0x4fff, M178Write);
SetWriteHandler(0x5800, 0x5fff, M178WriteSnd); SetWriteHandler(0x5800, 0x5fff, M178WriteSnd);
SetReadHandler(0x5800, 0x5fff, M178ReadSnd); SetReadHandler(0x5800, 0x5fff, M178ReadSnd);
SetReadHandler(0x5000, 0x5000, M178ReadSensor);
SetReadHandler(0x6000, 0x7fff, CartBR); SetReadHandler(0x6000, 0x7fff, CartBR);
SetWriteHandler(0x6000, 0x7fff, CartBW); SetWriteHandler(0x6000, 0x7fff, CartBW);
SetReadHandler(0x8000, 0xffff, CartBR); SetReadHandler(0x8000, 0xffff, CartBR);
@ -137,13 +149,25 @@ static void M178Power(void) {
} }
static void M178SndClk(int a) { static void M178SndClk(int a) {
if (pcm_enable) { SensorDelay += a;
pcm_latch -= a; if(SensorDelay > 0x32768) {
if (pcm_latch <= 0) { SensorDelay -= 32768;
pcm_latch += pcm_clock; GetMouseData (MouseData);
pcm_enable = 0; 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) { static void M178Close(void) {
@ -162,7 +186,7 @@ void Mapper178_Init(CartInfo *info) {
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
MapIRQHook = M178SndClk; MapIRQHook = M178SndClk;
jedi_table_init(); // jedi_table_init();
WRAMSIZE = 32768; WRAMSIZE = 32768;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);

View File

@ -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 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 it under the terms of the GNU General Public License as published by
@ -141,6 +141,7 @@ static DECLFW(WritePRG)
case 0x00: case 0x00:
chr = value & 3; chr = value & 3;
Mirror(value); Mirror(value);
Sync();
break; break;
case 0x01: case 0x01:
prg = value & 15; prg = value & 15;

View File

@ -22,11 +22,12 @@
#include "mapinc.h" #include "mapinc.h"
static uint8 latche; static uint8 latche, mirr;
static SFORMAT StateRegs[] = static SFORMAT StateRegs[] =
{ {
{ &latche, 1, "LATC" }, { &latche, 1, "LATC" },
{ &mirr, 1, "MIRR" },
{ 0 } { 0 }
}; };
@ -36,6 +37,11 @@ static void Sync(void) {
} }
static DECLFW(M36Write) { 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; latche = V;
Sync(); Sync();
} }

View File

@ -41,7 +41,7 @@ static SFORMAT StateRegs[] =
static void Sync(void) { static void Sync(void) {
uint8 i; uint8 i;
if ((preg[3] & 0xC0) == 0xC0) if ((preg[3] & 0xC0) == 0xC0)
setprg8r(0x10, 0x6000, 0); setprg8r(0x10, 0x6000, preg[3] & 0x3F);
else else
setprg8(0x6000, preg[3] & 0x3F); setprg8(0x6000, preg[3] & 0x3F);
setprg8(0x8000, preg[0]); setprg8(0x8000, preg[0]);
@ -258,6 +258,9 @@ void Mapper69_Init(CartInfo *info) {
info->Power = M69Power; info->Power = M69Power;
info->Close = M69Close; info->Close = M69Close;
MapIRQHook = M69IRQHook; MapIRQHook = M69IRQHook;
if(info->ines2)
WRAMSIZE = info->wram_size + info->battery_wram_size;
else
WRAMSIZE = 8192; WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);

View File

@ -303,14 +303,20 @@ static void M212Sync(void) {
} }
void Mapper212_Init(CartInfo *info) { 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 --------------------------- //------------------ Map 213 ---------------------------
static void M213Sync(void) { static void M213Sync(void) {
if(latche & 0x40) {
setprg16(0x8000, (latche & 7));
setprg16(0xC000, (latche & 7));
} else {
setprg32(0x8000, (latche >> 1) & 3); setprg32(0x8000, (latche >> 1) & 3);
}
setchr8((latche >> 3) & 7); setchr8((latche >> 3) & 7);
setmirror(((latche & 1)^((latche >> 6) & 1)) ^ 1);
} }
void Mapper213_Init(CartInfo *info) { void Mapper213_Init(CartInfo *info) {

View File

@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator /* FCE Ultra - NES/Famicom Emulator
* *
* Copyright notice for this file: * Copyright notice for this file:
* Copyright (C) 2015 CaH4e3 * Copyright (C) 2015 CaH4e3, ClusteR
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,70 +20,105 @@
* CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM * CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM
* only MMC3 mode * only MMC3 mode
* *
* 6000 (õõ76x210) | 0õÑ0 * 6000 (xx76x210) | 0xC0
* 6001 (õõõ354õõ) * 6001 (xxx354x)
* 6002 = 0 * 6002 = 0
* 6003 = 0 * 6003 = 0
* *
* hardware tested logic, don't try to understand lol
*/ */
#include "mapinc.h" #include "mapinc.h"
#include "mmc3.h" #include "mmc3.h"
static void COOLBOYCW(uint32 A, uint8 V) { static void COOLBOYCW(uint32 A, uint8 V) {
if(EXPREGS[3] & 0x10) uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80);
setchr8(EXPREGS[2] & 0xF); if (EXPREGS[3] & 0x10) {
else { if (EXPREGS[3] & 0x40) { // Weird mode
uint32 mask = 0xFF; int cbase = (MMC3_cmd & 0x80) << 5;
switch(EXPREGS[0] & 0xC0) { switch (cbase ^ A) { // Don't even try do understand
case 0xC0: case 0x0400:
mask = 0x7F; case 0x0C00: V &= 0x7F; break;
break;
} }
setchr1(A, V & mask); }
// 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) { static void COOLBOYPW(uint32 A, uint8 V) {
uint32 mask, shift; 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); uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2);
switch(EXPREGS[0] & 0xC0) {
case 0x00: // Very weird mode
mask = 0x3F; // 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; break;
case 0x80: case 0xC000:
mask = 0x1F; if (!(MMC3_cmd & 0x40)) V = 0;
break; break;
case 0xC0: case 0xE000:
if(EXPREGS[3] & 0x10) { V = 0;
mask = 0x01 | (EXPREGS[1] & 2);
} else {
mask = 0x0F;
}
break; break;
} }
if(EXPREGS[3] & 0x10) }
setprg8(A, (base << 4) | (V & mask) | ((EXPREGS[3] & (0x0E ^ (EXPREGS[1] & 2))) ));
else // Regular MMC3 mode, internal ROM size can be up to 2048kb!
setprg8(A, (base << 4) | (V & mask)); 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) { static DECLFW(COOLBOYWrite) {
if(A001B & 0x80) if(A001B & 0x80)
CartBW(A,V); CartBW(A,V);
else
if((EXPREGS[3] & 0x80) == 0) { // Deny any further writes when 7th bit is 1 AND 4th is 0
if ((EXPREGS[3] & 0x90) != 0x80) {
EXPREGS[A & 3] = V; EXPREGS[A & 3] = V;
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(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) { static void COOLBOYReset(void) {
MMC3RegReset(); MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
} }
@ -91,18 +126,21 @@ static void COOLBOYReset(void) {
static void COOLBOYPower(void) { static void COOLBOYPower(void) {
GenMMC3Power(); GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
// EXPREGS[0] = 0;
// EXPREGS[1] = 0x60;
// EXPREGS[2] = 0;
// EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite); SetWriteHandler(0x6000, 0x7fff, COOLBOYWrite);
} }
void COOLBOY_Init(CartInfo *info) { void COOLBOY_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 128, 8, 0); GenMMC3_Init(info, 512, 256, 8, 0);
pwrap = COOLBOYPW; pwrap = COOLBOYPW;
cwrap = COOLBOYCW; cwrap = COOLBOYCW;
info->Power = COOLBOYPower; info->Power = COOLBOYPower;
info->Reset = COOLBOYReset; info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR"); AddExState(EXPREGS, 4, 0, "EXPR");
} }

View File

@ -30,7 +30,7 @@ static void (*WSync)(void);
static DECLFW(LatchWrite) { static DECLFW(LatchWrite) {
// FCEU_printf("bs %04x %02x\n",A,V); // FCEU_printf("bs %04x %02x\n",A,V);
if (bus_conflict) if (bus_conflict)
latche = (V == CartBR(A)) ? V : 0; latche = V & CartBR(A);
else else
latche = V; latche = V;
WSync(); WSync();
@ -68,7 +68,48 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
info->Power = LatchPower; info->Power = LatchPower;
info->Close = LatchClose; info->Close = LatchClose;
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
if (wram) { if(info->ines2)
if(info->battery_wram_size + info->wram_size > 0)
wram = 1;
if (wram)
{
if(info->ines2)
{
//I would like to do it in this way, but FCEUX is woefully inadequate
//for instance if WRAMSIZE is large, the cheat pointers may get overwritten. and it's just a giant mess.
//WRAMSIZE = info->battery_wram_size + info->wram_size;
//WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
//if(!info->wram_size && !info->battery_wram_size) {}
//else if(info->wram_size && !info->battery_wram_size)
// SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1);
//else if(!info->wram_size && info->battery_wram_size)
//{
// SetupCartPRGMapping(0x10, WRAM, info->battery_wram_size, 1);
// info->SaveGame[0] = WRAM;
// info->SaveGameLen[0] = info->battery_wram_size;
//} else {
// //well, this is annoying
// SetupCartPRGMapping(0x10, WRAM, info->wram_size, 1);
// SetupCartPRGMapping(0x11, WRAM, info->battery_wram_size, 1); //? ? ? there probably isnt even a way to select this
// info->SaveGame[0] = WRAM + info->wram_size;
// info->SaveGameLen[0] = info->battery_wram_size;
//}
//this is more likely the only practical scenario
WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW);
setprg8r(0x10, 0x6000, 0);
if(info->battery_wram_size)
{
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 8192;
}
}
else
{
WRAMSIZE = 8192; WRAMSIZE = 8192;
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
@ -78,6 +119,8 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
} }
AddExState(WRAM, WRAMSIZE, 0, "WRAM"); AddExState(WRAM, WRAMSIZE, 0, "WRAM");
} }
}
AddExState(&latche, 1, 0, "LATC"); AddExState(&latche, 1, 0, "LATC");
AddExState(&bus_conflict, 1, 0, "BUSC"); AddExState(&bus_conflict, 1, 0, "BUSC");
} }
@ -93,7 +136,7 @@ static DECLFW(NROMWrite) {
static void NROMPower(void) { static void NROMPower(void) {
setprg8r(0x10, 0x6000, 0); // Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB 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); setprg16(0xC000, ~0);
setchr8(0); setchr8(0);

View File

@ -13,12 +13,11 @@
#endif #endif
#endif #endif
#include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#ifdef GEKKO
typedef uint8_t uint8 ; typedef uint8_t uint8 ;
typedef int8_t int8 ; typedef int8_t int8 ;
@ -27,6 +26,16 @@ typedef int16_t int16 ;
typedef uint32_t uint32 ; typedef uint32_t uint32 ;
typedef int32_t int32 ; 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 #define PI 3.14159265358979323846

View File

@ -70,7 +70,7 @@ static void SSSNROMPower(void) {
regs[0] = regs[1] = regs[2] = regs[3] = regs[4] = regs[5] = regs[6] = 0; regs[0] = regs[1] = regs[2] = regs[3] = regs[4] = regs[5] = regs[6] = 0;
regs[7] = 0xff; regs[7] = 0xff;
Sync(); Sync();
memset(WRAM, 0x00, WRAMSIZE); FCEU_MemoryRand(WRAM, WRAMSIZE, true);
// SetWriteHandler(0x0000,0x1FFF,SSSNROMRamWrite); // SetWriteHandler(0x0000,0x1FFF,SSSNROMRamWrite);
SetReadHandler(0x0800, 0x1FFF, CartBR); SetReadHandler(0x0800, 0x1FFF, CartBR);
SetWriteHandler(0x0800, 0x1FFF, CartBW); SetWriteHandler(0x0800, 0x1FFF, CartBW);

View File

@ -34,20 +34,16 @@ static void BMCFK23CCW(uint32 A, uint8 V)
setchr8(EXPREGS[2]|unromchr); setchr8(EXPREGS[2]|unromchr);
else if(EXPREGS[0]&0x20) { else if(EXPREGS[0]&0x20) {
setchr1r(0x10, A, V); setchr1r(0x10, A, V);
} } else {
else
{
uint16 base=(EXPREGS[2]&0x7F)<<3; uint16 base=(EXPREGS[2]&0x7F)<<3;
if(EXPREGS[3]&2) if(EXPREGS[3]&2) {
{
int cbase=(MMC3_cmd&0x80)<<5; int cbase=(MMC3_cmd&0x80)<<5;
setchr1(A,V|base); setchr1(A,V|base);
setchr1(0x0000^cbase,DRegBuf[0]|base); setchr1(0x0000^cbase,DRegBuf[0]|base);
setchr1(0x0400^cbase,EXPREGS[6]|base); setchr1(0x0400^cbase,EXPREGS[6]|base);
setchr1(0x0800^cbase,DRegBuf[1]|base); setchr1(0x0800^cbase,DRegBuf[1]|base);
setchr1(0x0c00^cbase,EXPREGS[7]|base); setchr1(0x0c00^cbase,EXPREGS[7]|base);
} } else
else
setchr1(A,V|base); setchr1(A,V|base);
} }
} }
@ -90,30 +86,28 @@ static void BMCFK23CPW(uint32 A, uint8 V)
uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0); uint32 hiblock = ((EXPREGS[0] & 8) << 4)|((EXPREGS[0] & 0x80) << 1)|(UNIFchrrama?((EXPREGS[2] & 0x40)<<3):0);
uint32 block = (EXPREGS[1] & 0x60) | hiblock; uint32 block = (EXPREGS[1] & 0x60) | hiblock;
uint32 extra = (EXPREGS[3] & 2); uint32 extra = (EXPREGS[3] & 2);
// FCEU_printf("0:%04X:%02X\n",A,V);
if((EXPREGS[0]&7)==4) if((EXPREGS[0]&7)==4)
setprg32(0x8000,EXPREGS[1]>>1); setprg32(0x8000,EXPREGS[1]>>1);
else if ((EXPREGS[0]&7)==3) else if ((EXPREGS[0]&7)==3) {
{
setprg16(0x8000,EXPREGS[1]); setprg16(0x8000,EXPREGS[1]);
setprg16(0xC000,EXPREGS[1]); setprg16(0xC000,EXPREGS[1]);
} } else {
else if(EXPREGS[0]&3) {
{
if(EXPREGS[0]&3)
{
uint32 blocksize = (6)-(EXPREGS[0]&3); uint32 blocksize = (6)-(EXPREGS[0]&3);
uint32 mask = (1<<blocksize)-1; uint32 mask = (1<<blocksize)-1;
V &= mask; V &= mask;
//V &= 63; //? is this a good idea? //V &= 63; //? is this a good idea?
V |= (EXPREGS[1]<<1); V |= (EXPREGS[1]<<1);
// FCEU_printf("1:%04X:%02X\n",A,V);
setprg8(A,V); setprg8(A,V);
} } else {
else
setprg8(A,V & prg_mask); setprg8(A,V & prg_mask);
// FCEU_printf("2:%04X:%02X\n",A,V);
}
if(EXPREGS[3]&2) if(EXPREGS[3]&2) {
{
setprg8(0xC000,EXPREGS[4]); setprg8(0xC000,EXPREGS[4]);
setprg8(0xE000,EXPREGS[5]); setprg8(0xE000,EXPREGS[5]);
} }
@ -124,25 +118,23 @@ static void BMCFK23CPW(uint32 A, uint8 V)
//PRG handler ($8000-$FFFF) //PRG handler ($8000-$FFFF)
static DECLFW(BMCFK23CHiWrite) static DECLFW(BMCFK23CHiWrite)
{ {
if(EXPREGS[0]&0x40) // FCEU_printf("K4:(exp0=%02x)\n",EXPREGS[0]);
{ // FCEU_printf("W0:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
if((EXPREGS[0]&0x60)==0x40) {
// FCEU_printf("W2:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
if(EXPREGS[0]&0x30) if(EXPREGS[0]&0x30)
unromchr=0; unromchr=0;
else else {
{
unromchr=V&3; unromchr=V&3;
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
} }
} } else {
else if((A==0x8001)&&(EXPREGS[3]&2)&&(MMC3_cmd&8)) {
{ // FCEU_printf("W3:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
if((A==0x8001)&&(EXPREGS[3]&2&&MMC3_cmd&8))
{
EXPREGS[4|(MMC3_cmd&3)]=V; EXPREGS[4|(MMC3_cmd&3)]=V;
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
} } else
else
if(A<0xC000) { if(A<0xC000) {
if(UNIFchrrama) { // hacky... strange behaviour, must be bit scramble due to pcb layot restrictions if(UNIFchrrama) { // hacky... strange behaviour, must be bit scramble due to pcb layot restrictions
// check if it not interfer with other dumps // check if it not interfer with other dumps
@ -151,44 +143,48 @@ static DECLFW(BMCFK23CHiWrite)
else if((A==0x8000)&&(V==0x47)) else if((A==0x8000)&&(V==0x47))
V=0x46; V=0x46;
} }
// FCEU_printf("W1:%04X:%02X\n",A,V);
MMC3_CMDWrite(A,V); MMC3_CMDWrite(A,V);
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
} } else {
else
MMC3_IRQWrite(A,V); MMC3_IRQWrite(A,V);
// FCEU_printf("W4:%04X:%02X (exp0=%02x)\n",A,V,EXPREGS[0]);
}
} }
} }
//EXP handler ($5000-$5FFF) //EXP handler ($5000-$5FFF)
static DECLFW(BMCFK23CWrite) static DECLFW(BMCFK23CWrite)
{ {
if(A&(1<<(dipswitch+4))) if(A&(1<<(dipswitch+4))) {
{
//printf("+ "); //printf("+ ");
EXPREGS[A&3]=V; EXPREGS[A&3]=V;
// BUT WHY is there any rom that need it actually?
bool remap = false; bool remap = false;
// FCEU_printf("K3:(exp0=%02x)\n",EXPREGS[0]);
// FCEU_printf("WH0:%04X:%02X\n",A,V);
//sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this. //sometimes writing to reg0 causes remappings to occur. we think the 2 signifies this.
//if not, 0x24 is a value that is known to work //if not, 0x24 is a value that is known to work
//however, the low 4 bits are known to control the mapping mode, so 0x20 is more likely to be the immediate remap flag //however, the low 4 bits are known to control the mapping mode, so 0x20 is more likely to be the immediate remap flag
remap |= ((EXPREGS[0]&0xF0)==0x20); // remap |= ((EXPREGS[0]&0xF0)==0x20);
//this is an actual mapping reg. i think reg0 controls what happens when reg1 is written. anyway, we have to immediately remap these //this is an actual mapping reg. i think reg0 controls what happens when reg1 is written. anyway, we have to immediately remap these
remap |= (A&3)==1; // remap |= (A&3)==1;
//this too. //this too.
remap |= (A&3)==2; // remap |= (A&3)==2;
if(remap) // if(remap) {
{ // FCEU_printf("WH1:%04X:%02X\n",A,V);
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
} // }
} }
if(is_BMCFK23CA) if(is_BMCFK23CA) {
{
if(EXPREGS[3]&2) if(EXPREGS[3]&2)
// FCEU_printf("EXTRA!\n",A);
EXPREGS[0] &= ~7; // hacky hacky! if someone wants extra banking, then for sure doesn't want mode 4 for it! (allow to run A version boards on normal mapper) EXPREGS[0] &= ~7; // hacky hacky! if someone wants extra banking, then for sure doesn't want mode 4 for it! (allow to run A version boards on normal mapper)
} }
@ -199,13 +195,15 @@ static DECLFW(BMCFK23CWrite)
static void BMCFK23CReset(void) static void BMCFK23CReset(void)
{ {
//NOT NECESSARY ANYMORE //NOT NECESSARY ANYMORE
// BUT WHY?
//this little hack makes sure that we try all the dip switch settings eventually, if we reset enough //this little hack makes sure that we try all the dip switch settings eventually, if we reset enough
// dipswitch++; dipswitch++;
// dipswitch&=7; dipswitch&=7;
//printf("BMCFK23C dipswitch set to %d\n",dipswitch); printf("BMCFK23C dipswitch set to %d\n",dipswitch);
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0; EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF; EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
// FCEU_printf("K0:(exp0=%02x)\n",EXPREGS[0]);
MMC3RegReset(); MMC3RegReset();
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
@ -213,15 +211,15 @@ static void BMCFK23CReset(void)
static void BMCFK23CPower(void) static void BMCFK23CPower(void)
{ {
dipswitch = 0;
GenMMC3Power(); GenMMC3Power();
dipswitch = 0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0; EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF; EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
GenMMC3Power(); // FCEU_printf("K1:(exp0=%02x)\n",EXPREGS[0]);
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
} }
static void BMCFK23CAPower(void) static void BMCFK23CAPower(void)
@ -230,10 +228,11 @@ static void BMCFK23CAPower(void)
dipswitch = 0; dipswitch = 0;
EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0; EXPREGS[0]=EXPREGS[1]=EXPREGS[2]=EXPREGS[3]=0;
EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF; EXPREGS[4]=EXPREGS[5]=EXPREGS[6]=EXPREGS[7]=0xFF;
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite); // FCEU_printf("K2:(exp0=%02x)\n",EXPREGS[0]);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd); FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000,0x5fff,BMCFK23CWrite);
SetWriteHandler(0x8000,0xFFFF,BMCFK23CHiWrite);
} }
static void BMCFK23CAClose(void) static void BMCFK23CAClose(void)

View File

@ -35,6 +35,7 @@ static void MALEEPower(void) {
void MALEE_Init(CartInfo *info) { void MALEE_Init(CartInfo *info) {
info->Power = MALEEPower; info->Power = MALEEPower;
FCEU_MemoryRand(WRAM,sizeof(WRAM),true);
SetupCartPRGMapping(0x10, WRAM, 2048, 1); SetupCartPRGMapping(0x10, WRAM, 2048, 1);
AddExState(WRAM, 2048, 0, "WRAM"); AddExState(WRAM, 2048, 0, "WRAM");
} }

View File

@ -22,12 +22,13 @@
#include "mapinc.h" #include "mapinc.h"
static void GenMMC1Power(void); 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 DRegs[4];
static uint8 Buffer, BufferShift; 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 (*MMC1CHRHook4)(uint32 A, uint8 V);
static void (*MMC1PRGHook16)(uint32 A, uint8 V); static void (*MMC1PRGHook16)(uint32 A, uint8 V);
@ -48,9 +49,9 @@ static DECLFR(MAWRAM) {
} }
static void MMC1CHR(void) { static void MMC1CHR(void) {
if (mmc1opts & 4) { if (WRAMSIZE > 0x2000) {
if (DRegs[0] & 0x10) if (WRAMSIZE > 0x4000)
setprg8r(0x10, 0x6000, (DRegs[1] >> 4) & 1); setprg8r(0x10, 0x6000, (DRegs[1] >> 2) & 3);
else else
setprg8r(0x10, 0x6000, (DRegs[1] >> 3) & 1); setprg8r(0x10, 0x6000, (DRegs[1] >> 3) & 1);
} }
@ -73,37 +74,38 @@ static void MMC1CHR(void) {
} }
static void MMC1PRG(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) { if (MMC1PRGHook16) {
switch (DRegs[0] & 0xC) { switch (DRegs[0] & 0xC) {
case 0xC: case 0xC:
MMC1PRGHook16(0x8000, (DRegs[3] + offs)); MMC1PRGHook16(0x8000, (prg_reg + offs_16banks));
MMC1PRGHook16(0xC000, 0xF + offs); MMC1PRGHook16(0xC000, 0xF + offs_16banks);
break; break;
case 0x8: case 0x8:
MMC1PRGHook16(0xC000, (DRegs[3] + offs)); MMC1PRGHook16(0xC000, (prg_reg + offs_16banks));
MMC1PRGHook16(0x8000, offs); MMC1PRGHook16(0x8000, offs_16banks);
break; break;
case 0x0: case 0x0:
case 0x4: case 0x4:
MMC1PRGHook16(0x8000, ((DRegs[3] & ~1) + offs)); MMC1PRGHook16(0x8000, ((prg_reg & ~1) + offs_16banks));
MMC1PRGHook16(0xc000, ((DRegs[3] & ~1) + offs + 1)); MMC1PRGHook16(0xc000, ((prg_reg & ~1) + offs_16banks + 1));
break; break;
} }
} else { } else {
switch (DRegs[0] & 0xC) { switch (DRegs[0] & 0xC) {
case 0xC: case 0xC:
setprg16(0x8000, (DRegs[3] + offs)); setprg16(0x8000, (prg_reg + offs_16banks));
setprg16(0xC000, 0xF + offs); setprg16(0xC000, 0xF + offs_16banks);
break; break;
case 0x8: case 0x8:
setprg16(0xC000, (DRegs[3] + offs)); setprg16(0xC000, (prg_reg + offs_16banks));
setprg16(0x8000, offs); setprg16(0x8000, offs_16banks);
break; break;
case 0x0: case 0x0:
case 0x4: case 0x4:
setprg16(0x8000, ((DRegs[3] & ~1) + offs)); setprg16(0x8000, ((prg_reg & ~1) + offs_16banks));
setprg16(0xc000, ((DRegs[3] & ~1) + offs + 1)); setprg16(0xc000, ((prg_reg & ~1) + offs_16banks + 1));
break; break;
} }
} }
@ -178,21 +180,40 @@ static void MMC1CMReset(void) {
MMC1PRG(); MMC1PRG();
} }
static int DetectMMC1WRAMSize(uint32 crc32) { static int DetectMMC1WRAMSize(CartInfo *info, int *bs) {
switch (crc32) { int ws = 8;
switch (info->CRC32) {
case 0xc6182024: // Romance of the 3 Kingdoms case 0xc6182024: // Romance of the 3 Kingdoms
case 0xabbf7217: // "" "" (J) (PRG0)
case 0xccf35c02: // "" "" (J) (PRG1)
case 0x2225c20f: // Genghis Khan case 0x2225c20f: // Genghis Khan
case 0xfb69743a: // "" "" (J)
case 0x4642dda6: // Nobunaga's Ambition case 0x4642dda6: // Nobunaga's Ambition
case 0x29449ba9: // "" "" (J) case 0x3f7ad415: // "" "" (J) (PRG0)
case 0x2b11e0b0: // "" "" (J) case 0x2b11e0b0: // "" "" (J) (PRG1)
case 0xb8747abf: // Best Play Pro Yakyuu Special (J) *bs = 8;
case 0xc9556b36: // Final Fantasy I & II (J) [!] ws = 16;
FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
return(16);
break; 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; static uint32 NWCIRQCount;
static uint8 NWCRec; static uint8 NWCRec;
@ -243,17 +264,16 @@ void Mapper105_Init(CartInfo *info) {
static void GenMMC1Power(void) { static void GenMMC1Power(void) {
lreset = 0; 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); SetWriteHandler(0x8000, 0xFFFF, MMC1_write);
SetReadHandler(0x8000, 0xFFFF, CartBR); 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); SetReadHandler(0x6000, 0x7FFF, MAWRAM);
SetWriteHandler(0x6000, 0x7FFF, MBWRAM); SetWriteHandler(0x6000, 0x7FFF, MBWRAM);
setprg8r(0x10, 0x6000, 0); setprg8r(0x10, 0x6000, 0);
@ -270,31 +290,24 @@ static void GenMMC1Close(void) {
CHRRAM = WRAM = NULL; 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; is155 = 0;
info->Close = GenMMC1Close; info->Close = GenMMC1Close;
MMC1PRGHook16 = MMC1CHRHook4 = 0; MMC1PRGHook16 = MMC1CHRHook4 = 0;
mmc1opts = 0; WRAMSIZE = wram * 1024;
NONBRAMSIZE = (wram - bram) * 1024;
PRGmask16[0] &= (prg >> 14) - 1; PRGmask16[0] &= (prg >> 14) - 1;
CHRmask4[0] &= (chr >> 12) - 1; CHRmask4[0] &= (chr >> 12) - 1;
CHRmask8[0] &= (chr >> 13) - 1; CHRmask8[0] &= (chr >> 13) - 1;
if (wram) { if (WRAMSIZE) {
WRAM = (uint8*)FCEU_gmalloc(wram * 1024); WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
//mbg 17-jun-08 - this shouldve been cleared to re-initialize save ram SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
//ch4 10-dec-08 - nope, this souldn't AddExState(WRAM, WRAMSIZE, 0, "WRAM");
//mbg 29-mar-09 - no time to debate this, we need to keep from breaking some old stuff. if (bram) {
//we really need to make up a policy for how compatibility and accuracy can be resolved. info->SaveGame[0] = WRAM + NONBRAMSIZE;
memset(WRAM, 0, wram * 1024); info->SaveGameLen[0] = bram * 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 (!chr) { if (!chr) {
@ -312,13 +325,14 @@ static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int battery)
} }
void Mapper1_Init(CartInfo *info) { void Mapper1_Init(CartInfo *info) {
int ws = DetectMMC1WRAMSize(info->CRC32); int bs = info->battery ? 8 : 0;
GenMMC1Init(info, 512, 256, ws, info->battery); int ws = DetectMMC1WRAMSize(info, &bs);
GenMMC1Init(info, 512, 256, ws, bs);
} }
/* Same as mapper 1, without respect for WRAM enable bit. */ /* Same as mapper 1, without respect for WRAM enable bit. */
void Mapper155_Init(CartInfo *info) { void Mapper155_Init(CartInfo *info) {
GenMMC1Init(info, 512, 256, 8, info->battery); GenMMC1Init(info, 512, 256, 8, info->battery ? 8 : 0);
is155 = 1; is155 = 1;
} }
@ -330,7 +344,7 @@ void Mapper171_Init(CartInfo *info) {
} }
void SAROM_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) { void SBROM_Init(CartInfo *info) {
@ -350,7 +364,7 @@ void SGROM_Init(CartInfo *info) {
} }
void SKROM_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) { void SLROM_Init(CartInfo *info) {
@ -382,11 +396,9 @@ void SHROM_Init(CartInfo *info) {
/* */ /* */
void SNROM_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) { void SOROM_Init(CartInfo *info) {
GenMMC1Init(info, 256, 0, 16, info->battery); GenMMC1Init(info, 256, 0, 16, info->battery ? 8 : 0);
} }

View File

@ -279,11 +279,11 @@ void GenMMC3Power(void) {
setprg8r(0x10, 0x6000, 0); setprg8r(0x10, 0x6000, 0);
} }
if (!(mmc3opts & 2)) if (!(mmc3opts & 2))
FCEU_dwmemset(WRAM, 0, WRAMSIZE); FCEU_MemoryRand(WRAM, WRAMSIZE, true);
} }
MMC3RegReset(); MMC3RegReset();
if (CHRRAM) if (CHRRAM)
FCEU_dwmemset(CHRRAM, 0, CHRRAMSIZE); FCEU_MemoryRand(CHRRAM, CHRRAMSIZE, true);
} }
static void GenMMC3Close(void) { 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 &= 0; // hack ;( don't know exactly how it should be
NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4); NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4);
setchr1(A, NV); 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) { static void M45PW(uint32 A, uint8 V) {
V &= (EXPREGS[3] & 0x3F) ^ 0x3F; uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F);
V |= EXPREGS[1]; MV |= EXPREGS[1];
setprg8(A, V); 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) { static DECLFW(M45Write) {
@ -534,7 +539,6 @@ static void M45Reset(void) {
} }
static void M45Power(void) { static void M45Power(void) {
setchr8(0);
GenMMC3Power(); GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0; EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0;
SetWriteHandler(0x5000, 0x7FFF, M45Write); SetWriteHandler(0x5000, 0x7FFF, M45Write);
@ -1039,8 +1043,8 @@ static DECLFW(Mapper196Write) {
} }
static DECLFW(Mapper196WriteLo) { static DECLFW(Mapper196WriteLo) {
EXPREGS[0] = 1; EXPREGS[0] = 1; // hacky
EXPREGS[1] = (V & 0xf) | (V >> 4); EXPREGS[1] = (V & 0xf) | (V >> 4); // this is the same as 189 mapper, but with addr permutations
FixMMC3PRG(MMC3_cmd); FixMMC3PRG(MMC3_cmd);
} }

View File

@ -22,6 +22,13 @@
#include "mapinc.h" #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 (*sfun)(int P);
static void (*psfun)(void); static void (*psfun)(void);
@ -107,15 +114,33 @@ typedef struct __cartdata {
uint8 size; uint8 size;
} cartdata; } cartdata;
#define Sprite16 (PPU[0]& 0x20) //Sprites 8x16/8x8 #define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)]
//#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)]
static inline uint8 * MMC5BGVRAMADR(uint32 A) { 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 (!Sprite16) {
if (mmc5ABMode == 0) if (mmc5ABMode == 0)
return &MMC5SPRVPage[(A) >> 10][(A)]; return &ABANKS[(A) >> 10][(A)];
else else
return &MMC5BGVPage[(A) >> 10][(A)]; return &BBANKS[(A) >> 10][(A)];
} else return &MMC5BGVPage[(A) >> 10][(A)]; } else return &BBANKS[(A) >> 10][(A)];
} }
static void mmc5_PPUWrite(uint32 A, uint8 V) { 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) { extern uint32 NTRefreshAddr;
if (A < 0x2000) { uint8 FASTCALL mmc5_PPURead(uint32 A)
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. bool split = false;
//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 if(newppu)
&& (PPU[1] & 0x10) {
) if((MMC5HackSPMode&0x80) && !(MMC5HackCHRMode&2))
return *MMC5BGVRAMADR(A); {
else return MMC5SPRVPage[(A) >> 10][(A)]; int target = MMC5HackSPMode&0x1f;
} else { int side = MMC5HackSPMode&0x40;
int ht = NTRefreshAddr&31;
if(side==0)
{
if(ht<target) split = true;
}
else
{
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]; 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); MMC5fill = (uint8*)FCEU_gmalloc(1024);
ExRAM = (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(ExRAM, 1024, 0, "ERAM");
AddExState(&MMC5HackSPMode, 1, 0, "SPLM"); AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
AddExState(&MMC5HackSPScroll, 1, 0, "SPLS"); AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
@ -858,8 +978,13 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
if (battery) { if (battery) {
info->SaveGame[0] = WRAM; 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) if (wsize <= 16)
info->SaveGameLen[0] = 8192; info->SaveGameLen[0] = 8192;
else if(wsize == 64)
info->SaveGameLen[0] = 64*1024;
else else
info->SaveGameLen[0] = 32768; info->SaveGameLen[0] = 32768;
} }

View File

@ -57,9 +57,23 @@ static SFORMAT N106_StateRegs[] = {
{ PRG, 3, "PRG" }, { PRG, 3, "PRG" },
{ CHR, 8, "CHR" }, { CHR, 8, "CHR" },
{ NTAPage, 4, "NTA" }, { NTAPage, 4, "NTA" },
{ &gorfus, 1, "GORF" },
{ &dopol, 1, "DOPO" },
{ &gorko, 1, "GORK" },
{ 0 } { 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) { static void SyncPRG(void) {
setprg8(0x8000, PRG[0]); setprg8(0x8000, PRG[0]);
setprg8(0xa000, PRG[1]); setprg8(0xa000, PRG[1]);
@ -179,8 +193,11 @@ static DECLFW(Mapper19_write) {
X6502_IRQEnd(FCEU_IQEXT); X6502_IRQEnd(FCEU_IQEXT);
break; break;
case 0xE000: case 0xE000:
gorko = V & 0xC0;
PRG[0] = V & 0x3F; PRG[0] = V & 0x3F;
if(is210) {
gorko = V>>6;
SyncMirror();
}
SyncPRG(); SyncPRG();
break; break;
case 0xE800: case 0xE800:
@ -333,6 +350,7 @@ static void Mapper19_StateRestore(int version) {
SyncPRG(); SyncPRG();
FixNTAR(); FixNTAR();
FixCRR(); FixCRR();
SyncMirror();
int x; int x;
for (x = 0x40; x < 0x80; x++) for (x = 0x40; x < 0x80; x++)
FixCache(x, IRAM[x]); FixCache(x, IRAM[x]);
@ -382,8 +400,8 @@ static void N106_Power(void) {
FixCRR(); FixCRR();
if (!battery) { if (!battery) {
FCEU_dwmemset(WRAM, 0, 8192); FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
FCEU_dwmemset(IRAM, 0, 128); FCEU_MemoryRand(IRAM, sizeof(IRAM), true);
} }
for (x = 0x40; x < 0x80; x++) for (x = 0x40; x < 0x80; x++)
FixCache(x, IRAM[x]); FixCache(x, IRAM[x]);
@ -401,6 +419,8 @@ void Mapper19_Init(CartInfo *info) {
if (FSettings.SndRate) if (FSettings.SndRate)
Mapper19_ESI(); Mapper19_ESI();
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
FCEU_MemoryRand(IRAM, sizeof(IRAM), true);
AddExState(WRAM, 8192, 0, "WRAM"); AddExState(WRAM, 8192, 0, "WRAM");
AddExState(IRAM, 128, 0, "IRAM"); AddExState(IRAM, 128, 0, "IRAM");
AddExState(N106_StateRegs, ~0, 0, 0); AddExState(N106_StateRegs, ~0, 0, 0);
@ -422,6 +442,7 @@ void Mapper210_Init(CartInfo *info) {
is210 = 1; is210 = 1;
GameStateRestore = Mapper210_StateRestore; GameStateRestore = Mapper210_StateRestore;
info->Power = N106_Power; info->Power = N106_Power;
FCEU_MemoryRand(WRAM, sizeof(WRAM), true);
AddExState(WRAM, 8192, 0, "WRAM"); AddExState(WRAM, 8192, 0, "WRAM");
AddExState(N106_StateRegs, ~0, 0, 0); AddExState(N106_StateRegs, ~0, 0, 0);
} }

View File

@ -113,7 +113,7 @@ static void CSync(void) {
setchr1(0x1800 ^ cswap, block | (bank6 & mask)); setchr1(0x1800 ^ cswap, block | (bank6 & mask));
setchr1(0x1c00 ^ cswap, block | (bank7 & mask)); setchr1(0x1c00 ^ cswap, block | (bank7 & mask));
setmirror(mirror & 1); setmirror((mirror ^ 1) & 1);
} }
static void Sync(void) { static void Sync(void) {
@ -158,7 +158,7 @@ static DECLFW(UNLOneBusWriteMMC3) {
} }
break; break;
} }
case 0xa000: mirror = V ^ 1; CSync(); break; case 0xa000: mirror = V; CSync(); break;
case 0xc000: IRQLatch = V & 0xfe; break; case 0xc000: IRQLatch = V & 0xfe; break;
case 0xc001: IRQReload = 1; break; case 0xc001: IRQReload = 1; break;
case 0xe000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break; case 0xe000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break;

View File

@ -197,7 +197,7 @@ static void UNROM512LSync() {
} }
else if (latche==0x10) else if (latche==0x10)
{ {
for(int i=0;i<(ROM_size*4);i++) for(uint32 i=0;i<(ROM_size*4);i++)
inc_flash_write_count(i>>2,i<<12); 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% :) memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :)
} }
@ -241,7 +241,23 @@ void UNROM512_Init(CartInfo *info) {
else else
chrram_mask = 0x60; chrram_mask = 0x60;
SetupCartMirroring(info->mirror,(info->mirror>=MI_0)?0:1,0); 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; bus_conflict = !info->battery;
latcheinit = 0; latcheinit = 0;
WLSync = UNROM512LSync; WLSync = UNROM512LSync;

View File

@ -20,7 +20,8 @@
#include "mapinc.h" #include "mapinc.h"
static uint8 isPirate, is22; static bool isPirate;
static uint8 is22, reg1mask, reg2mask;
static uint16 IRQCount; static uint16 IRQCount;
static uint8 IRQLatch, IRQa; static uint8 IRQLatch, IRQa;
static uint8 prgreg[2], chrreg[8]; static uint8 prgreg[2], chrreg[8];
@ -61,15 +62,15 @@ static void Sync(void) {
setchr8(0); setchr8(0);
else{ else{
uint8 i; uint8 i;
if(!weirdo) //if(!weirdo)
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22); setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22);
else { //else {
setchr1(0x0000, 0xFC); // setchr1(0x0000, 0xFC);
setchr1(0x0400, 0xFD); // setchr1(0x0400, 0xFD);
setchr1(0x0800, 0xFF); // setchr1(0x0800, 0xFF);
weirdo--; // weirdo--;
} //}
} }
switch (mirr & 0x3) { switch (mirr & 0x3) {
case 0: setmirror(MI_V); break; case 0: setmirror(MI_V); break;
@ -80,7 +81,7 @@ static void Sync(void) {
} }
static DECLFW(VRC24Write) { static DECLFW(VRC24Write) {
A &= 0xF003; A = A & 0xF000 | !!(A & reg2mask) << 1 | !!(A & reg1mask);
if ((A >= 0xB000) && (A <= 0xE003)) { if ((A >= 0xB000) && (A <= 0xE003)) {
if (UNIFchrrama) if (UNIFchrrama)
big_bank = (V & 8) << 2; // my personally many-in-one feature ;) just for support pirate cart 2-in-1 big_bank = (V & 8) << 2; // my personally many-in-one feature ;) just for support pirate cart 2-in-1
@ -126,62 +127,18 @@ static DECLFW(VRC24Write) {
} }
} }
static DECLFW(M21Write) { static void VRC24Power(void) {
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
}
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; big_bank = 0x20;
Sync(); Sync();
if (WRAM) {
setprg8r(0x10, 0x6000, 0); setprg8r(0x10, 0x6000, 0);
SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x6000, 0x7FFF, CartBR);
SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x6000, 0x7FFF, CartBW);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M22Write);
FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM);
} }
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, VRC24Write);
}
void VRC24IRQHook(int a) { void VRC24IRQHook(int a) {
#define LCYCS 341 #define LCYCS 341
@ -210,26 +167,8 @@ static void VRC24Close(void) {
WRAM = NULL; WRAM = NULL;
} }
void Mapper21_Init(CartInfo *info) { static void VRC24_Init(CartInfo *info) {
isPirate = 0; info->Power = VRC24Power;
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) {
info->Close = VRC24Close; info->Close = VRC24Close;
MapIRQHook = VRC24IRQHook; MapIRQHook = VRC24IRQHook;
GameStateRestore = StateRestore; GameStateRestore = StateRestore;
@ -247,23 +186,48 @@ void VRC24_Init(CartInfo *info) {
AddExState(&StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0);
} }
void Mapper23_Init(CartInfo *info) { void Mapper21_Init(CartInfo *info) {
isPirate = 0; isPirate = false;
is22 = 0; 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); VRC24_Init(info);
} }
void Mapper25_Init(CartInfo *info) { void Mapper25_Init(CartInfo *info) {
isPirate = 0; isPirate = false;
is22 = 0; is22 = 0;
info->Power = M25Power; reg1mask = 0xa;
reg2mask = 0x5;
VRC24_Init(info); VRC24_Init(info);
} }
void UNLT230_Init(CartInfo *info) { void UNLT230_Init(CartInfo *info) {
isPirate = 1; isPirate = true;
is22 = 0; is22 = 0;
info->Power = M23Power; reg1mask = 0x15;
reg2mask = 0x2a;
VRC24_Init(info); VRC24_Init(info);
} }

View File

@ -200,27 +200,3 @@ static void M190Close(void) {
static void StateRestore(int version) { static void StateRestore(int version) {
Sync(); 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);
}

View File

@ -86,7 +86,7 @@ static void VRC7SKill(void) {
static void VRC7_ESI(void) { static void VRC7_ESI(void) {
GameExpSound.RChange = VRC7SC; GameExpSound.RChange = VRC7SC;
GameExpSound.Kill = VRC7SKill; 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);
OPLL_reset(VRC7Sound); OPLL_reset(VRC7Sound);
} }

View File

@ -76,6 +76,8 @@ uint8 geniech[3];
uint32 genieaddr[3]; uint32 genieaddr[3];
CartInfo *currCartInfo;
static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram) { static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram) {
uint32 AB = A >> 11; uint32 AB = A >> 11;
int x; int x;

View File

@ -25,6 +25,8 @@ typedef struct {
// other code in the future. // other code in the future.
} CartInfo; } CartInfo;
extern CartInfo *currCartInfo;
void FCEU_SaveGameSave(CartInfo *LocalHWInfo); void FCEU_SaveGameSave(CartInfo *LocalHWInfo);
void FCEU_LoadGameSave(CartInfo *LocalHWInfo); void FCEU_LoadGameSave(CartInfo *LocalHWInfo);
void FCEU_ClearGameSave(CartInfo *LocalHWInfo); void FCEU_ClearGameSave(CartInfo *LocalHWInfo);

View File

@ -216,7 +216,7 @@ void FCEU_LoadGameCheats(FILE *override)
} }
FCEU_DispMessage("Cheats file loaded.",0); //Tells user a cheats file was loaded. 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; char *tbuf=linebuf;
int doc=0; int doc=0;
@ -931,11 +931,13 @@ void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2)
int FCEU_CheatGetByte(uint32 A) int FCEU_CheatGetByte(uint32 A)
{ {
// if(CheatRPtrs[A>>10]) if(A < 0x10000) {
// return CheatRPtrs[A>>10][A]; //adelikat-commenting this stuff out so that lua can see frozen addresses, I hope this doesn't bork stuff. uint32 ret;
/*else*/ if(A < 0x10000) fceuindbg=1;
return ARead[A](A); ret = ARead[A](A);
else fceuindbg=0;
return ret;
} else
return 0; return 0;
} }

View File

@ -34,10 +34,11 @@
* Primitive -> Number | Address | Register | Flag | PC Bank | '(' Connect ')' * Primitive -> Number | Address | Register | Flag | PC Bank | '(' Connect ')'
* Number -> '#' [1-9A-F]* * Number -> '#' [1-9A-F]*
* Address -> '$' [1-9A-F]* | '$' '[' Connect ']' * Address -> '$' [1-9A-F]* | '$' '[' Connect ']'
* Register -> 'A' | 'X' | 'Y' | 'P' * Register -> 'A' | 'X' | 'Y' | 'P' | 'S'
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' * Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V' | 'U' | 'D'
* PC Bank -> 'K' * PC Bank -> 'K'
* Data Bank -> 'T' * Data Bank -> 'T'
* Value -> 'R' | 'W'
*/ */
#include "types.h" #include "types.h"
@ -50,8 +51,9 @@
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
// hack: this address is used by 'T' condition uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
uint16 addressOfTheLastAccessedData = 0; uint8 debugLastOpcode; // used to evaluate 'W' condition
// Next non-whitespace character in string // Next non-whitespace character in string
char next; char next;
@ -137,7 +139,7 @@ int isFlag(char c)
// Determines if a character is a register // Determines if a character is a register
int isRegister(char c) 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 // Determines if a character is for PC bank
@ -152,6 +154,18 @@ int isDataBank(char c)
return c == 'T'; 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 // Reads a hexadecimal number from str
int getNumber(unsigned int* number, const char** str) int getNumber(unsigned int* number, const char** str)
{ {
@ -272,6 +286,40 @@ Condition* Primitive(const char** str, Condition* c)
return 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 */ else if (next == '#') /* Numbers */
{ {
unsigned int number = 0; unsigned int number = 0;

View File

@ -28,6 +28,8 @@
#define TYPE_ADDR 4 #define TYPE_ADDR 4
#define TYPE_PC_BANK 5 #define TYPE_PC_BANK 5
#define TYPE_DATA_BANK 6 #define TYPE_DATA_BANK 6
#define TYPE_VALUE_READ 7
#define TYPE_VALUE_WRITE 8
#define OP_NO 0 #define OP_NO 0
#define OP_EQ 1 #define OP_EQ 1
@ -43,7 +45,9 @@
#define OP_OR 11 #define OP_OR 11
#define OP_AND 12 #define OP_AND 12
extern uint16 addressOfTheLastAccessedData; extern uint16 debugLastAddress;
extern uint8 debugLastOpcode;
//mbg merge 7/18/06 turned into sane c++ //mbg merge 7/18/06 turned into sane c++
struct Condition struct Condition
{ {

View File

@ -18,10 +18,13 @@ char *FCEUI_GetAboutString() {
const char *aboutTemplate = const char *aboutTemplate =
FCEU_NAME_AND_VERSION "\n\n" FCEU_NAME_AND_VERSION "\n\n"
"Administrators:\n" "Administrators:\n"
"zeromus, adelikat, AnS\n\n" "zeromus, punkrockguy318 (Lukas Sabota), feos\n"
"\n"
"Current Contributors:\n" "Current Contributors:\n"
"punkrockguy318 (Lukas Sabota)\n" "CaH4e3, rainwarrior\n"
"CaH4e3, gocha, xhainingx, feos\n" "\n"
"Past Contributors:\n"
"xhainingx, gocha, AnS\n"
"\n" "\n"
"FCEUX 2.0:\n" "FCEUX 2.0:\n"
"mz, nitsujrehtona, SP, Ugly Joe,\n" "mz, nitsujrehtona, SP, Ugly Joe,\n"

View File

@ -77,6 +77,7 @@ int getValue(int type)
case 'Z': return _P & Z_FLAG ? 1 : 0; case 'Z': return _P & Z_FLAG ? 1 : 0;
case 'C': return _P & C_FLAG ? 1 : 0; case 'C': return _P & C_FLAG ? 1 : 0;
case 'P': return _PC; case 'P': return _PC;
case 'S': return _S;
} }
return 0; 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 else if ((A >= 0x4018) && (A < 0x5000)) // AnS: changed the range, so MMC5 ExRAM can be watched in the Hexeditor
return 0xFF; return 0xFF;
if (GameInfo) //adelikat: 11/17/09: Prevent crash if this is called with no game loaded. if (GameInfo) { //adelikat: 11/17/09: Prevent crash if this is called with no game loaded.
return ARead[A](A); uint32 ret;
else return 0; fceuindbg=1;
ret = ARead[A](A);
fceuindbg=0;
return ret;
} else return 0;
} }
uint8 GetPPUMem(uint8 A) { 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 // Evaluates a condition
int evaluate(Condition* c) int evaluate(Condition* c)
{ {
@ -330,7 +361,9 @@ int evaluate(Condition* c)
{ {
case TYPE_ADDR: value1 = GetMem(value1); break; case TYPE_ADDR: value1 = GetMem(value1); break;
case TYPE_PC_BANK: value1 = getBank(_PC); 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; f = value1;
@ -355,7 +388,9 @@ int evaluate(Condition* c)
{ {
case TYPE_ADDR: value2 = GetMem(value2); break; case TYPE_ADDR: value2 = GetMem(value2); break;
case TYPE_PC_BANK: value2 = getBank(_PC); 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) switch (c->op)
@ -367,7 +402,7 @@ int evaluate(Condition* c)
case OP_G: f = value1 > value2; break; case OP_G: f = value1 > value2; break;
case OP_L: f = value1 < value2; break; case OP_L: f = value1 < value2; break;
case OP_MULT: 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_PLUS: f = value1 + value2; break;
case OP_MINUS: f = value1 - value2; break; case OP_MINUS: f = value1 - value2; break;
case OP_OR: 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(!force)
{ {
if (bp_num >= 0 && !condition(&watchpoint[bp_num]))
{
return; // condition rejected
}
//check to see whether we fall in any forbid zone //check to see whether we fall in any forbid zone
for (int i = 0; i < numWPs; i++) for (int i = 0; i < numWPs; i++)
{ {
@ -529,7 +569,7 @@ void BreakHit(int bp_num, bool force)
#endif #endif
} }
uint8 StackAddrBackup = X.S; int StackAddrBackup;
uint16 StackNextIgnorePC = 0xFFFF; uint16 StackNextIgnorePC = 0xFFFF;
///fires a breakpoint ///fires a breakpoint
@ -539,6 +579,9 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
uint8 stackop=0; uint8 stackop=0;
uint8 stackopstartaddr,stackopendaddr; uint8 stackopstartaddr,stackopendaddr;
debugLastAddress = A;
debugLastOpcode = opcode[0];
if (break_asap) if (break_asap)
{ {
break_asap = false; break_asap = false;
@ -601,24 +644,25 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
switch (opcode[0]) { switch (opcode[0]) {
//Push Ops //Push Ops
case 0x08: //Fall to next 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 //Pull Ops
case 0x28: //Fall to next 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) //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; 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) //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; 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) //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; 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++) for (i = 0; i < numWPs; i++)
{ {
// ################################## Start of SP CODE ########################### if ((watchpoint[i].flags & WP_E))
if ((watchpoint[i].flags & WP_E) && condition(&watchpoint[i]))
{ {
// ################################## End of SP CODE ###########################
if (watchpoint[i].flags & BT_P) if (watchpoint[i].flags & BT_P)
{ {
// PPU Mem breaks // PPU Mem breaks
@ -628,11 +672,11 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (watchpoint[i].endaddress) if (watchpoint[i].endaddress)
{ {
if ((watchpoint[i].address <= PPUAddr) && (watchpoint[i].endaddress >= PPUAddr)) if ((watchpoint[i].address <= PPUAddr) && (watchpoint[i].endaddress >= PPUAddr))
BreakHit(i); BREAKHIT(i);
} else } else
{ {
if (watchpoint[i].address == PPUAddr) if (watchpoint[i].address == PPUAddr)
BreakHit(i); BREAKHIT(i);
} }
} }
} else if (watchpoint[i].flags & BT_S) } 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].endaddress)
{ {
if ((watchpoint[i].address <= PPU[3]) && (watchpoint[i].endaddress >= PPU[3])) if ((watchpoint[i].address <= PPU[3]) && (watchpoint[i].endaddress >= PPU[3]))
BreakHit(i); BREAKHIT(i);
} else } else
{ {
if (watchpoint[i].address == PPU[3]) if (watchpoint[i].address == PPU[3])
BreakHit(i); BREAKHIT(i);
} }
} else if ((watchpoint[i].flags & WP_W) && (A == 0x4014)) } else if ((watchpoint[i].flags & WP_W) && (A == 0x4014))
{ {
// Sprite DMA! :P // Sprite DMA! :P
BreakHit(i); BREAKHIT(i);
} }
} else } 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)) || if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address <= A) && (watchpoint[i].endaddress >= A)) ||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC))) ((watchpoint[i].flags & WP_X) && (watchpoint[i].address <= _PC) && (watchpoint[i].endaddress >= _PC)))
BreakHit(i); BREAKHIT(i);
} else } else
{ {
if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) || if (((watchpoint[i].flags & (WP_R | WP_W)) && (watchpoint[i].address == A)) ||
((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC))) ((watchpoint[i].flags & WP_X) && (watchpoint[i].address == _PC)))
BreakHit(i); BREAKHIT(i);
} }
} else } else
{ {
@ -685,11 +729,11 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (watchpoint[i].endaddress) if (watchpoint[i].endaddress)
{ {
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j)) if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i); BREAKHIT(i);
} else } else
{ {
if (watchpoint[i].address == j) if (watchpoint[i].address == j)
BreakHit(i); BREAKHIT(i);
} }
} }
} }
@ -700,7 +744,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
StackNextIgnorePC = 0xFFFF; StackNextIgnorePC = 0xFFFF;
} else } else
{ {
if ((X.S < StackAddrBackup) && (stackop==0)) if (StackAddrBackup != -1 && (X.S < StackAddrBackup) && (stackop==0))
{ {
// Unannounced stack mem breaks // Unannounced stack mem breaks
// Pushes to stack // Pushes to stack
@ -711,15 +755,15 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
if (watchpoint[i].endaddress) if (watchpoint[i].endaddress)
{ {
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j)) if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i); BREAKHIT(i);
} else } else
{ {
if (watchpoint[i].address == j) 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 // Pulls from stack
if (watchpoint[i].flags & WP_R) 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].endaddress)
{ {
if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j)) if ((watchpoint[i].address <= j) && (watchpoint[i].endaddress >= j))
BreakHit(i); BREAKHIT(i);
} else } else
{ {
if (watchpoint[i].address == j) 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. //Update the stack address with the current one, now that changes have registered.
//ZEROMUS THINKS IT MAKES MORE SENSE HERE
StackAddrBackup = X.S; 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 //bbit edited: this is the end of the inserted code
@ -777,9 +828,12 @@ void DebugCycle()
size = opsize[opcode[0]]; size = opsize[opcode[0]];
switch (size) switch (size)
{ {
default:
case 1: break;
case 2: case 2:
opcode[1] = GetMem(_PC + 1); opcode[1] = GetMem(_PC + 1);
break; break;
case 0: // illegal instructions may have operands
case 3: case 3:
opcode[1] = GetMem(_PC + 1); opcode[1] = GetMem(_PC + 1);
opcode[2] = GetMem(_PC + 2); opcode[2] = GetMem(_PC + 2);
@ -803,7 +857,6 @@ void DebugCycle()
case 7: A = (opcode[1] | (opcode[2] << 8)) + _X; break; case 7: A = (opcode[1] | (opcode[2] << 8)) + _X; break;
case 8: A = opcode[1] + _Y; 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) 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); breakpoint(opcode, A, size);

View File

@ -49,13 +49,11 @@ typedef struct {
uint16 address; uint16 address;
uint16 endaddress; uint16 endaddress;
uint8 flags; uint8 flags;
// ################################## Start of SP CODE ###########################
Condition* cond; Condition* cond;
char* condText; char* condText;
char* desc; char* desc;
// ################################## End of SP CODE ###########################
} watchpointinfo; } watchpointinfo;
//mbg merge 7/18/06 had to make this extern //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 *vnapage[4],*VPage[8];
extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset; extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
extern uint32 FCEUPPU_PeekAddress(); extern uint32 FCEUPPU_PeekAddress();
extern int debug_loggingCD;
extern int numWPs; extern int numWPs;
///encapsulates the operational state of the debugger core ///encapsulates the operational state of the debugger core

View File

@ -68,7 +68,7 @@ void FCEUI_NTSCSELTINT(void);
void FCEUI_NTSCDEC(void); void FCEUI_NTSCDEC(void);
void FCEUI_NTSCINC(void); void FCEUI_NTSCINC(void);
void FCEUI_GetNTSCTH(int *tint, int *hue); 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_SetInput(int port, ESI type, void *ptr, int attrib);
void FCEUI_SetInputFC(ESIFC 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) //Set variables for NTSC(0) / PAL(1) / Dendy(2)
//Dendy has PAL framerate and resolution, but ~NTSC timings, and has 50 dummy scanlines to force 50 fps //Dendy has PAL framerate and resolution, but ~NTSC timings, and has 50 dummy scanlines to force 50 fps
void FCEUI_SetRegion(int region); void FCEUI_SetRegion(int region, int notify = 1);
//Convenience function; returns currently emulated video system(0=NTSC, 1=PAL). //Convenience function; returns currently emulated video system(0=NTSC, 1=PAL).
int FCEUI_GetCurrentVidSystem(int *slstart, int *slend); int FCEUI_GetCurrentVidSystem(int *slstart, int *slend);
@ -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. //Sets the base directory(save states, snapshots, etc. are saved in directories below this directory.
void FCEUI_SetBaseDirectory(std::string const & dir); void FCEUI_SetBaseDirectory(std::string const & dir);
//Tells FCE Ultra to copy the palette data pointed to by pal and use it. void FCEUI_SetUserPalette(uint8 *pal, int nEntries);
//Data pointed to by pal needs to be 64*3 bytes in length.
void FCEUI_SetPaletteArray(uint8 *pal);
//Sets up sound code to render sound at the specified rate, in samples //Sets up sound code to render sound at the specified rate, in samples
//per second. Only sample rates of 44100, 48000, and 96000 are currently supported. //per second. Only sample rates of 44100, 48000, and 96000 are currently supported.

View File

@ -56,9 +56,10 @@ extern bool isTaseditorRecording();
extern int32 fps_scale; extern int32 fps_scale;
extern int32 fps_scale_unpaused; extern int32 fps_scale_unpaused;
extern int32 fps_scale_frameadvance; extern int32 fps_scale_frameadvance;
extern void RefreshThrottleFPS();
#endif #endif
extern void RefreshThrottleFPS();
#ifdef _S9XLUA_H #ifdef _S9XLUA_H
#include "fceulua.h" #include "fceulua.h"
#endif #endif
@ -93,6 +94,20 @@ extern void RefreshThrottleFPS();
using namespace std; 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 int AFon = 1, AFoff = 1, AutoFireOffset = 0; //For keeping track of autofire settings
bool justLagged = false; 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) 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 DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated.
bool AutoResumePlay = false; bool AutoResumePlay = false;
char romNameWhenClosingEmulator[2048] = {0}; char romNameWhenClosingEmulator[2048] = {0};
int dendy = 0;
FCEUGI::FCEUGI() FCEUGI::FCEUGI()
: filename(0), : filename(0),
@ -140,10 +154,12 @@ void FCEU_TogglePPU(void) {
if (newppu) { if (newppu) {
FCEU_DispMessage("New PPU loaded", 0); FCEU_DispMessage("New PPU loaded", 0);
FCEUI_printf("New PPU loaded"); FCEUI_printf("New PPU loaded");
overclock_enabled = 0;
} else { } else {
FCEU_DispMessage("Old PPU loaded", 0); FCEU_DispMessage("Old PPU loaded", 0);
FCEUI_printf("Old PPU loaded"); FCEUI_printf("Old PPU loaded");
} }
normalscanlines = (dendy ? 290 : 240)+newppu; // use flag as number!
#ifdef WIN32 #ifdef WIN32
SetMainWindowText(); SetMainWindowText();
#endif #endif
@ -348,16 +364,10 @@ uint8 PAL = 0;
static DECLFW(BRAML) { static DECLFW(BRAML) {
RAM[A] = V; RAM[A] = V;
#ifdef _S9XLUA_H
CallRegisteredLuaMemHook(A, 1, V, LUAMEMHOOK_WRITE);
#endif
} }
static DECLFW(BRAMH) { static DECLFW(BRAMH) {
RAM[A & 0x7FF] = V; RAM[A & 0x7FF] = V;
#ifdef _S9XLUA_H
CallRegisteredLuaMemHook(A & 0x7FF, 1, V, LUAMEMHOOK_WRITE);
#endif
} }
static DECLFR(ARAML) { static DECLFR(ARAML) {
@ -384,7 +394,7 @@ void ResetGameLoaded(void) {
MMC5Hack = 0; MMC5Hack = 0;
PEC586Hack = 0; PEC586Hack = 0;
PAL &= 1; PAL &= 1;
pale = 0; default_palette_selection = 0;
} }
int UNIFLoad(const char *name, FCEUFILE *fp); 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 //attempt to open the files
FCEUFILE *fp; FCEUFILE *fp;
char fullname[2048]; // this name contains both archive name and ROM file name 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 }; const char* romextensions[] = { "nes", "fds", 0 };
fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions); fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions);
@ -488,6 +500,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
// ################################## End of SP CODE ########################### // ################################## End of SP CODE ###########################
#endif #endif
if (OverwriteVidMode)
FCEU_ResetVidSys(); FCEU_ResetVidSys();
if (GameInfo->type != GIT_NSF) if (GameInfo->type != GIT_NSF)
@ -511,6 +524,18 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
FCEU_ResetPalette(); FCEU_ResetPalette();
FCEU_ResetMessages(); // Save state, status messages, etc. 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) if (GameInfo->type != GIT_NSF)
FCEU_LoadGameCheats(0); FCEU_LoadGameCheats(0);
@ -712,10 +737,15 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
extern int KillFCEUXonFrame; extern int KillFCEUXonFrame;
if (KillFCEUXonFrame && (FCEUMOV_GetFrame() >= KillFCEUXonFrame)) if (KillFCEUXonFrame && (FCEUMOV_GetFrame() >= KillFCEUXonFrame))
DoFCEUExit(); DoFCEUExit();
#else
extern int KillFCEUXonFrame;
if (KillFCEUXonFrame && (FCEUMOV_GetFrame() >= KillFCEUXonFrame))
exit(0);
#endif #endif
timestampbase += timestamp; timestampbase += timestamp;
timestamp = 0; timestamp = 0;
soundtimestamp = 0;
*pXBuf = skip ? 0 : XBuf; *pXBuf = skip ? 0 : XBuf;
if (skip == 2) { //If skip = 2, then bypass sound if (skip == 2) { //If skip = 2, then bypass sound
@ -769,17 +799,79 @@ void ResetNES(void) {
//FCEU_DispMessage("Reset", 0); //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; int x = 0;
while (size) { while (size) {
*ptr = (x & 4) ? 0xFF : 0x00; // Huang Di DEBUG MODE enabled by default uint8 v = 0;
// Cybernoid NO MUSIC by default switch (RAMInitOption)
// *ptr = (x & 4) ? 0x7F : 0x00; // Huang Di DEBUG MODE enabled by default {
// Minna no Taabou no Nakayoshi Daisakusen DOESN'T BOOT default:
// Cybernoid NO MUSIC by default case 0:
// *ptr = (x & 1) ? 0x55 : 0xAA; // F-15 Sity War HISCORE is screwed... if (!default_zero) v = (x & 4) ? 0xFF : 0x00;
// 1942 SCORE/HISCORE is screwed... else v = 0x00;
// *ptr = 0xFF; // Work for all cases 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++; x++;
size--; size--;
ptr++; ptr++;
@ -793,18 +885,21 @@ void PowerNES(void) {
FCEUMOV_AddCommand(FCEUNPCMD_POWER); FCEUMOV_AddCommand(FCEUNPCMD_POWER);
if (!GameInfo) return; 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_CheatResetRAM();
FCEU_CheatAddRAM(2, 0, RAM); FCEU_CheatAddRAM(2, 0, RAM);
FCEU_GeniePower(); 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); FCEU_MemoryRand(RAM, 0x800);
SetReadHandler(0x0000, 0xFFFF, ANull); SetReadHandler(0x0000, 0xFFFF, ANull);
@ -845,7 +940,7 @@ void PowerNES(void) {
Update_RAM_Search(); // Update_RAM_Watch() is also called. Update_RAM_Search(); // Update_RAM_Watch() is also called.
#endif #endif
//FCEU_DispMessage("Power on", 0); FCEU_DispMessage("Power on", 0);
} }
void FCEU_ResetVidSys(void) { void FCEU_ResetVidSys(void) {
@ -861,6 +956,14 @@ void FCEU_ResetVidSys(void) {
PAL = w ? 1 : 0; 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); FCEUPPU_SetVideoSystem(w || dendy);
SetSoundVariables(); SetSoundVariables();
} }
@ -877,6 +980,13 @@ void FCEU_printf(char *format, ...) {
vsnprintf(temp, sizeof(temp), format, ap); vsnprintf(temp, sizeof(temp), format, ap);
FCEUD_Message(temp); FCEUD_Message(temp);
#if 0
FILE *ofile;
ofile = fopen("stdout.txt", "ab");
fwrite(temp, 1, strlen(temp), ofile);
fclose(ofile);
#endif
va_end(ap); va_end(ap);
#endif #endif
} }
@ -925,30 +1035,58 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) {
*slend = FSettings.LastSLine; *slend = FSettings.LastSLine;
return(PAL); return(PAL);
} }
/*
// TODO: make use on SDL #ifndef GEKKO
void FCEUI_SetRegion(int region) { void FCEUI_SetRegion(int region, int notify) {
switch (region) { switch (region) {
case 0: // NTSC case 0: // NTSC
normalscanlines = 240;
pal_emulation = 0; pal_emulation = 0;
dendy = 0; dendy = 0;
// until it's fixed on sdl. see issue #740
#ifdef WIN32
if (notify)
{
FCEU_DispMessage("NTSC mode set", 0);
FCEUI_printf("NTSC mode set");
}
#endif
break; break;
case 1: // PAL case 1: // PAL
normalscanlines = 240;
pal_emulation = 1; pal_emulation = 1;
dendy = 0; dendy = 0;
#ifdef WIN32
if (notify)
{
FCEU_DispMessage("PAL mode set", 0);
FCEUI_printf("PAL mode set");
}
#endif
break; break;
case 2: // Dendy case 2: // Dendy
normalscanlines = 290;
pal_emulation = 0; pal_emulation = 0;
dendy = 1; dendy = 1;
#ifdef WIN32
if (notify)
{
FCEU_DispMessage("Dendy mode set", 0);
FCEUI_printf("Dendy mode set");
}
#endif
break; break;
} }
normalscanlines += newppu;
totalscanlines = normalscanlines + (overclock_enabled ? postrenderscanlines : 0);
FCEUI_SetVidSystem(pal_emulation); FCEUI_SetVidSystem(pal_emulation);
RefreshThrottleFPS(); RefreshThrottleFPS();
#ifdef WIN32 #ifdef WIN32
UpdateCheckedMenuItems(); UpdateCheckedMenuItems();
PushCurrentVideoSettings(); PushCurrentVideoSettings();
#endif #endif
}*/ }
#endif
//Enable or disable Game Genie option. //Enable or disable Game Genie option.
void FCEUI_SetGameGenie(bool a) { void FCEUI_SetGameGenie(bool a) {
@ -1052,9 +1190,7 @@ int FCEU_TextScanlineOffsetFromBottom(int y) {
} }
bool FCEU_IsValidUI(EFCEUI ui) { bool FCEU_IsValidUI(EFCEUI ui) {
#ifdef GEKKO #ifndef GEKKO
return true;
#endif
switch (ui) { switch (ui) {
case FCEUI_OPENGAME: case FCEUI_OPENGAME:
case FCEUI_CLOSEGAME: case FCEUI_CLOSEGAME:
@ -1099,6 +1235,7 @@ bool FCEU_IsValidUI(EFCEUI ui) {
if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false; if (!FCEUMOV_Mode(MOVIEMODE_INACTIVE)) return false;
break; break;
} }
#endif
return true; return true;
} }
@ -1165,8 +1302,6 @@ void FCEUXGameInterface(GI command) {
} }
} }
bool FCEUXLoad(const char *name, FCEUFILE *fp) { bool FCEUXLoad(const char *name, FCEUFILE *fp) {
//read ines header //read ines header
iNES_HEADER head; iNES_HEADER head;
@ -1218,11 +1353,26 @@ bool FCEUXLoad(const char *name, FCEUFILE *fp) {
return true; return true;
} }
uint8 FCEU_ReadRomByte(uint32 i) { uint8 FCEU_ReadRomByte(uint32 i) {
extern iNES_HEADER head; extern iNES_HEADER head;
if (i < 16) return *((unsigned char*)&head + i); if (i < 16)
if (i < 16 + PRGsize[0]) return PRGptr[0][i - 16]; return *((unsigned char*)&head + i);
if (i < 16 + PRGsize[0] + CHRsize[0]) return CHRptr[0][i - 16 - PRGsize[0]]; 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; 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;
}

View File

@ -7,13 +7,22 @@ extern int fceuindbg;
extern int newppu; extern int newppu;
void ResetGameLoaded(void); 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 bool AutoResumePlay;
extern char romNameWhenClosingEmulator[]; extern char romNameWhenClosingEmulator[];
#define DECLFR(x) uint8 x (uint32 A) #define DECLFR(x) uint8 x (uint32 A)
#define DECLFW(x) void x (uint32 A, uint8 V) #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 SetReadHandler(int32 start, int32 end, readfunc func);
void SetWriteHandler(int32 start, int32 end, writefunc func); void SetWriteHandler(int32 start, int32 end, writefunc func);
writefunc GetWriteHandler(int32 a); writefunc GetWriteHandler(int32 a);
@ -54,6 +63,7 @@ extern uint8 *RAM; //shared memory modifications
extern int EmulationPaused; extern int EmulationPaused;
uint8 FCEU_ReadRomByte(uint32 i); uint8 FCEU_ReadRomByte(uint32 i);
void FCEU_WriteRomByte(uint32 i, uint8 value);
extern readfunc ARead[0x10000]; extern readfunc ARead[0x10000];
extern writefunc BWrite[0x10000]; extern writefunc BWrite[0x10000];
@ -121,7 +131,7 @@ void FCEU_DispMessage(char *format, int disppos, ...);
void FCEU_DispMessageOnMovie(char *format, ...); void FCEU_DispMessageOnMovie(char *format, ...);
void FCEU_TogglePPU(); 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 DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor);
void FCEU_PutImage(void); void FCEU_PutImage(void);
#ifdef FRAMESKIP #ifdef FRAMESKIP
@ -134,7 +144,7 @@ extern void PushCurrentVideoSettings();
#endif #endif
extern uint8 Exit; extern uint8 Exit;
extern uint8 pale; extern int default_palette_selection;
extern uint8 vsdip; extern uint8 vsdip;
//#define FCEUDEF_DEBUGGER //mbg merge 7/17/06 - cleaning out conditional compiles //#define FCEUDEF_DEBUGGER //mbg merge 7/17/06 - cleaning out conditional compiles

View File

@ -18,10 +18,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h" #include "types.h"
#include "x6502.h" #include "x6502.h"
#include "fceu.h" #include "fceu.h"
@ -37,6 +33,10 @@
#include "driver.h" #include "driver.h"
#include "movie.h" #include "movie.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
// TODO: Add code to put a delay in between the time a disk is inserted // 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 // and the when it can be successfully read/written to. This should
// prevent writes to wrong places OR add code to prevent disk ejects // prevent writes to wrong places OR add code to prevent disk ejects
@ -147,20 +147,26 @@ static void FDSInit(void) {
SelectDisk = 0; SelectDisk = 0;
} }
void FCEU_FDSInsert(void) { void FCEU_FDSInsert(void)
if (FCEUI_EmulationPaused()) EmulationPaused |= 2; {
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)) if (FCEUMOV_Mode(MOVIEMODE_RECORD))
FCEUMOV_AddCommand(FCEUNPCMD_FDSINSERT); FCEUMOV_AddCommand(FCEUNPCMD_FDSINSERT);
if (TotalSides == 0) { if (InDisk == 255)
FCEU_DispMessage("", 0);// remove text "Not FDS; can't eject disk." {
return;
}
if (InDisk == 255) {
//FCEU_DispMessage("Disk %d Side %s Inserted", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); //FCEU_DispMessage("Disk %d Side %s Inserted", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A");
InDisk = SelectDisk; InDisk = SelectDisk;
} else { } else
{
//FCEU_DispMessage("Disk %d Side %s Ejected", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); //FCEU_DispMessage("Disk %d Side %s Ejected", 0, SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A");
InDisk = 255; InDisk = 255;
} }
@ -171,22 +177,27 @@ void FCEU_FDSEject(void)
InDisk=255; InDisk=255;
} }
*/ */
void FCEU_FDSSelect(void) { void FCEU_FDSSelect(void)
if (FCEUI_EmulationPaused()) EmulationPaused |= 2; {
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)) if (FCEUMOV_Mode(MOVIEMODE_RECORD))
FCEUMOV_AddCommand(FCEUNPCMD_FDSSELECT); 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; 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) { static void FDSFix(int a) {
@ -753,13 +764,11 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
CHRRAMSize = 8192; CHRRAMSize = 8192;
CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize);
memset(CHRRAM, 0, CHRRAMSize);
SetupCartCHRMapping(0, CHRRAM, CHRRAMSize, 1); SetupCartCHRMapping(0, CHRRAM, CHRRAMSize, 1);
AddExState(CHRRAM, CHRRAMSize, 0, "CHRR"); AddExState(CHRRAM, CHRRAMSize, 0, "CHRR");
FDSRAMSize = 32768; FDSRAMSize = 32768;
FDSRAM = (uint8*)FCEU_gmalloc(FDSRAMSize); FDSRAM = (uint8*)FCEU_gmalloc(FDSRAMSize);
memset(FDSRAM, 0, FDSRAMSize);
SetupCartPRGMapping(1, FDSRAM, FDSRAMSize, 1); SetupCartPRGMapping(1, FDSRAM, FDSRAMSize, 1);
AddExState(FDSRAM, FDSRAMSize, 0, "FDSR"); AddExState(FDSRAM, FDSRAMSize, 0, "FDSR");

View File

@ -27,10 +27,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <fstream> #include <fstream>
#ifndef WIN32
#include <zlib.h>
#endif
#include "types.h" #include "types.h"
#include "file.h" #include "file.h"
#include "utils/endian.h" #include "utils/endian.h"
@ -49,6 +45,10 @@
#include "driver.h" #include "driver.h"
#include "utils/xstring.h" #include "utils/xstring.h"
#ifndef WIN32
#include <zlib.h>
#endif
using namespace std; using namespace std;
bool bindSavestate = true; //Toggle that determines if a savestate filename will include the movie filename bool bindSavestate = true; //Toggle that determines if a savestate filename will include the movie filename

View File

@ -36,8 +36,10 @@ enum ESI
SI_POWERPADB = 4, SI_POWERPADB = 4,
SI_ARKANOID = 5, SI_ARKANOID = 5,
SI_MOUSE = 6, 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) inline const char* ESI_Name(ESI esi)
@ -50,7 +52,9 @@ inline const char* ESI_Name(ESI esi)
"Power Pad A", "Power Pad A",
"Power Pad B", "Power Pad B",
"Arkanoid Paddle", "Arkanoid Paddle",
"Mouse" "Subor Mouse",
"SNES Pad",
"SNES Mouse"
}; };
if(esi >= SI_NONE && esi <= SI_COUNT) if(esi >= SI_NONE && esi <= SI_COUNT)

View File

@ -30,6 +30,7 @@
{ 0x9b4bad37b5498992LL, "Gradius 2", INESB_HACKED }, { 0x9b4bad37b5498992LL, "Gradius 2", INESB_HACKED },
{ 0xb068d4ac10ef848eLL, "Highway Star", INESB_HACKED }, { 0xb068d4ac10ef848eLL, "Highway Star", INESB_HACKED },
{ 0xbf5175271e5019c3LL, "Kaiketsu Yanchamaru 3", INESB_HACKED }, { 0xbf5175271e5019c3LL, "Kaiketsu Yanchamaru 3", INESB_HACKED },
{ 0x81c1de64550a1531LL, "Nobunaga no Yabou Zenkokuban", INESB_HACKED },
{ 0xfb4b508a236bbba3LL, "Salamander", INESB_HACKED }, { 0xfb4b508a236bbba3LL, "Salamander", INESB_HACKED },
{ 0x1895afc6eef26c7dLL, "Super Mario Bros.", INESB_HACKED }, { 0x1895afc6eef26c7dLL, "Super Mario Bros.", INESB_HACKED },
{ 0x3716c4bebf885344LL, "Super Mario Bros.", INESB_HACKED }, { 0x3716c4bebf885344LL, "Super Mario Bros.", INESB_HACKED },

View File

@ -62,6 +62,7 @@
{0x02cc3973, 3, 1}, /* Ninja Kid */ {0x02cc3973, 3, 1}, /* Ninja Kid */
{0xbc065fc3, 3, 1}, /* Pipe Dream */ {0xbc065fc3, 3, 1}, /* Pipe Dream */
{0xc9ee15a7, 3, -1}, /* 3 is probably best. 41 WILL NOT WORK. */ {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}, {0x22d6d5bd, 4, 1},
{0xd97c31b0, 4, 1}, //Rasaaru Ishii no Childs Quest (J) {0xd97c31b0, 4, 1}, //Rasaaru Ishii no Childs Quest (J)
{0x404b2e8b, 4, 2}, /* Rad Racer 2 */ {0x404b2e8b, 4, 2}, /* Rad Racer 2 */
@ -83,7 +84,6 @@
{0x6e68e31a, 16, 8}, /* Dragon Ball 3*/ {0x6e68e31a, 16, 8}, /* Dragon Ball 3*/
{0x33b899c9, 16, -1}, /* Dragon Ball - Dai Maou Fukkatsu (J) [!] */ {0x33b899c9, 16, -1}, /* Dragon Ball - Dai Maou Fukkatsu (J) [!] */
{0xa262a81f, 16, -1}, /* Rokudenashi Blues (J) */ {0xa262a81f, 16, -1}, /* Rokudenashi Blues (J) */
{0x286fcd20, 23, -1}, /* Ganbare Goemon Gaiden 2 - Tenka no Zaihou (J) [!] */
{0xe4a291ce, 23, -1}, /* World Hero (Unl) [!] */ {0xe4a291ce, 23, -1}, /* World Hero (Unl) [!] */
{0x51e9cd33, 23, -1}, /* World Hero (Unl) [b1] */ {0x51e9cd33, 23, -1}, /* World Hero (Unl) [b1] */
{0x105dd586, 27, -1}, /* Mi Hun Che variations... */ {0x105dd586, 27, -1}, /* Mi Hun Che variations... */
@ -257,10 +257,28 @@
{0x345ee51a, 245, -1}, /* DQ4c */ {0x345ee51a, 245, -1}, /* DQ4c */
{0x57514c6c, 245, -1}, /* Yong Zhe Dou E Long - Dragon Quest VI (Ch) */ {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) [!] */ {0x1d75fd35, 256|0x1000,-1}, /* 2-in-1 - Street Dance + Hit Mouse (Unl) [!] */
{0x6eef8bb7, 257|0x1000,-1}, /* PEC-586 Chinese */ {0x6eef8bb7, 257|0x1000,-1}, /* PEC-586 Chinese */
{0xac7e98fb, 257|0x1000,-1}, /* PEC-586 Chinese No Tape Out */ {0xac7e98fb, 257|0x1000,-1}, /* PEC-586 Chinese No Tape Out */
{0x8d51a23b, 257|0x1000,-1}, /* [KeWang] Chao Ji Wu Bi Han Ka (C) V1 */ {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 */ {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} {0x00000000, -1, -1}

View File

@ -327,7 +327,7 @@ static void CheckHInfo(void) {
{ {
#include "ines-correct.h" #include "ines-correct.h"
}; };
int32 tofix = 0, x; int32 tofix = 0, x, mask;
uint64 partialmd5 = 0; uint64 partialmd5 = 0;
for (x = 0; x < 8; x++) for (x = 0; x < 8; x++)
@ -361,9 +361,13 @@ static void CheckHInfo(void) {
VROM = NULL; VROM = NULL;
tofix |= 8; 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; tofix |= 1;
MapperNo = moo[x].mapper & 0xFF; MapperNo = moo[x].mapper & mask;
} }
} }
if (moo[x].mirror >= 0) { if (moo[x].mirror >= 0) {
@ -561,7 +565,7 @@ static BMAPPINGLocal bmap[] = {
{"FDS UNROM BOARD", 108, Mapper108_Init}, {"FDS UNROM BOARD", 108, Mapper108_Init},
// {"", 109, Mapper109_Init}, // {"", 109, Mapper109_Init},
// {"", 110, Mapper110_Init}, // {"", 110, Mapper110_Init},
// {"", 111, Mapper111_Init}, {"Cheapocabra", 111, Mapper111_Init},
{"ASDER/NTDEC BOARD", 112, Mapper112_Init}, {"ASDER/NTDEC BOARD", 112, Mapper112_Init},
{"HACKER/SACHEN BOARD", 113, Mapper113_Init}, {"HACKER/SACHEN BOARD", 113, Mapper113_Init},
{"MMC3 SG PROT. A", 114, Mapper114_Init}, {"MMC3 SG PROT. A", 114, Mapper114_Init},
@ -640,7 +644,7 @@ static BMAPPINGLocal bmap[] = {
{"", 187, Mapper187_Init}, {"", 187, Mapper187_Init},
{"", 188, Mapper188_Init}, {"", 188, Mapper188_Init},
{"", 189, Mapper189_Init}, {"", 189, Mapper189_Init},
// {"", 190, Mapper190_Init}, {"", 190, Mapper190_Init},
{"", 191, Mapper191_Init}, {"", 191, Mapper191_Init},
{"TW MMC3+VRAM Rev. B", 192, Mapper192_Init}, {"TW MMC3+VRAM Rev. B", 192, Mapper192_Init},
{"NTDEC TC-112", 193, Mapper193_Init}, // War in the Gulf {"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 512-767 is the Supplementary Ideographic Plane -----------
//-------- Mappers 3840-4095 are for rom dumps not publicly released -------- //-------- 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} {"", 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); FCEU_printf(" Total VRAM size: %d\n", iNESCart.vram_size + iNESCart.battery_vram_size);
if(head.ROM_type & 2) 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); 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; GameInterface = iNESGI;
currCartInfo = &iNESCart;
FCEU_printf("\n"); FCEU_printf("\n");
// since apparently the iNES format doesn't store this information, // since apparently the iNES format doesn't store this information,
// guess if the settings should be PAL or NTSC from the ROM name // 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? // 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)") if (strstr(name, "(E)") || strstr(name, "(e)")
|| strstr(name, "(Europe)") || strstr(name, "(PAL)") || strstr(name, "(Europe)") || strstr(name, "(PAL)")
|| strstr(name, "(F)") || strstr(name, "(f)") || strstr(name, "(F)") || strstr(name, "(f)")
@ -990,6 +1009,7 @@ static int iNES_Init(int num) {
case 6: case 6:
case 29: case 29:
case 30: case 30:
case 45:
case 96: CHRRAMSize = 32 * 1024; break; case 96: CHRRAMSize = 32 * 1024; break;
case 176: CHRRAMSize = 128 * 1024; break; case 176: CHRRAMSize = 128 * 1024; break;
default: CHRRAMSize = 8 * 1024; break; default: CHRRAMSize = 8 * 1024; break;
@ -1004,9 +1024,19 @@ static int iNES_Init(int num) {
FCEU_MemoryRand(VROM, CHRRAMSize); FCEU_MemoryRand(VROM, CHRRAMSize);
UNIFchrrama = VROM; UNIFchrrama = VROM;
if(CHRRAMSize == 0)
{
//probably a mistake.
//but (for chrram): "Use of $00 with no CHR ROM implies that the game is wired to map nametable memory in CHR space. The value $00 MUST NOT be used if a mapper isn't defined to allow this. "
//well, i'm not going to do that now. we'll save it for when it's needed
//"it's only mapper 218 and no other mappers"
}
else
{
SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); SetupCartCHRMapping(0, VROM, CHRRAMSize, 1);
AddExState(VROM, CHRRAMSize, 0, "CHRR"); AddExState(VROM, CHRRAMSize, 0, "CHRR");
} }
}
if (head.ROM_type & 8) if (head.ROM_type & 8)
AddExState(ExtraNTARAM, 2048, 0, "EXNR"); AddExState(ExtraNTARAM, 2048, 0, "EXNR");
tmp->init(&iNESCart); tmp->init(&iNESCart);

View File

@ -177,6 +177,7 @@ void Mapper105_Init(CartInfo *);
void Mapper106_Init(CartInfo *); void Mapper106_Init(CartInfo *);
void Mapper107_Init(CartInfo *); void Mapper107_Init(CartInfo *);
void Mapper108_Init(CartInfo *); void Mapper108_Init(CartInfo *);
void Mapper111_Init(CartInfo *);
void Mapper112_Init(CartInfo *); void Mapper112_Init(CartInfo *);
void Mapper113_Init(CartInfo *); void Mapper113_Init(CartInfo *);
void Mapper114_Init(CartInfo *); void Mapper114_Init(CartInfo *);

View File

@ -62,6 +62,8 @@ extern INPUTC *FCEU_InitZapper(int w);
extern INPUTC *FCEU_InitPowerpadA(int w); extern INPUTC *FCEU_InitPowerpadA(int w);
extern INPUTC *FCEU_InitPowerpadB(int w); extern INPUTC *FCEU_InitPowerpadB(int w);
extern INPUTC *FCEU_InitArkanoid(int w); extern INPUTC *FCEU_InitArkanoid(int w);
extern INPUTC *FCEU_InitMouse(int w);
extern INPUTC *FCEU_InitSNESMouse(int w);
extern INPUTCFC *FCEU_InitArkanoidFC(void); extern INPUTCFC *FCEU_InitArkanoidFC(void);
extern INPUTCFC *FCEU_InitSpaceShadow(void); extern INPUTCFC *FCEU_InitSpaceShadow(void);
@ -88,6 +90,7 @@ extern bool movieSubtitles;
static uint8 joy_readbit[2]; static uint8 joy_readbit[2];
uint8 joy[4]={0,0,0,0}; //HACK - should be static but movie needs it 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; static uint8 LastStrobe;
uint8 RawReg4016 = 0; // Joystick strobe (W) uint8 RawReg4016 = 0; // Joystick strobe (W)
@ -107,6 +110,9 @@ static bool FSAttached = false;
JOYPORT joyports[2] = { JOYPORT(0), JOYPORT(1) }; JOYPORT joyports[2] = { JOYPORT(0), JOYPORT(1) };
FCPORT portFC; FCPORT portFC;
FILE* DumpInputFile;
FILE* PlayInputFile;
static DECLFR(JPRead) static DECLFR(JPRead)
{ {
lagFlag = 0; lagFlag = 0;
@ -139,6 +145,12 @@ static DECLFR(JPRead)
} }
} }
if(PlayInputFile)
ret = fgetc(PlayInputFile);
if(DumpInputFile)
fputc(ret,DumpInputFile);
ret|=X.DB&0xC0; ret|=X.DB&0xC0;
return(ret); 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 GPC={ReadGP,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP};
static INPUTC GPCVS={ReadGPVS,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP}; static INPUTC GPCVS={ReadGPVS,0,StrobeGP,UpdateGP,0,0,LogGP,LoadGP};
static INPUTC GPSNES={ReadSNES,0,StrobeSNES,UpdateSNES,0,0,LogSNES,LoadSNES};
void FCEU_DrawInput(uint8 *buf) void FCEU_DrawInput(uint8 *buf)
{ {
@ -390,6 +457,9 @@ static void SetInputStuff(int port)
joyports[port].driver= &GPC; joyports[port].driver= &GPC;
} }
break; break;
case SI_SNES:
joyports[port].driver= &GPSNES;
break;
case SI_ARKANOID: case SI_ARKANOID:
joyports[port].driver=FCEU_InitArkanoid(port); joyports[port].driver=FCEU_InitArkanoid(port);
break; break;
@ -402,6 +472,12 @@ static void SetInputStuff(int port)
case SI_POWERPADB: case SI_POWERPADB:
joyports[port].driver=FCEU_InitPowerpadB(port); joyports[port].driver=FCEU_InitPowerpadB(port);
break; 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: case SI_NONE:
joyports[port].driver=&DummyJPort; joyports[port].driver=&DummyJPort;
break; break;
@ -665,10 +741,11 @@ static void RamSearchOpLTE(void);
static void RamSearchOpGTE(void); static void RamSearchOpGTE(void);
static void RamSearchOpEQ(void); static void RamSearchOpEQ(void);
static void RamSearchOpNE(void); static void RamSearchOpNE(void);
static void DebuggerStepInto(void);
static void FA_SkipLag(void); static void FA_SkipLag(void);
static void OpenRom(void); static void OpenRom(void);
static void CloseRom(void); static void CloseRom(void);
static void ReloadRom(void); void ReloadRom(void);
static void MovieSubtitleToggle(void); static void MovieSubtitleToggle(void);
static void UndoRedoSavestate(void); static void UndoRedoSavestate(void);
static void FCEUI_DoExit(void); static void FCEUI_DoExit(void);
@ -687,6 +764,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_SCREENSHOT, EMUCMDTYPE_MISC, FCEUI_SaveSnapshot, 0, 0, "Screenshot", 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_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_EXIT, EMUCMDTYPE_MISC, FCEUI_DoExit, 0, 0, "Exit", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_SPEED_SLOWEST, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Slowest Speed", 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_SLOWER, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Speed Down", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_SPEED_NORMAL, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Normal Speed", EMUCMDFLAG_TASEDITOR }, { EMUCMD_SPEED_NORMAL, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Normal Speed", EMUCMDFLAG_TASEDITOR },
@ -738,7 +816,6 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_MOVIE_STOP, EMUCMDTYPE_MOVIE, FCEUI_StopMovie, 0, 0, "Stop Movie", 0 }, { EMUCMD_MOVIE_STOP, EMUCMDTYPE_MOVIE, FCEUI_StopMovie, 0, 0, "Stop Movie", 0 },
{ EMUCMD_MOVIE_READONLY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleReadOnly, 0, 0, "Toggle Read-Only", EMUCMDFLAG_TASEDITOR }, { EMUCMD_MOVIE_READONLY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleReadOnly, 0, 0, "Toggle Read-Only", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Toggle Frame Display", EMUCMDFLAG_TASEDITOR }, { EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Toggle Frame Display", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleInputDisplay, 0, 0, "Toggle Input Display", EMUCMDFLAG_TASEDITOR }, { EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleInputDisplay, 0, 0, "Toggle Input Display", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_MOVIE_ICON_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUD_ToggleStatusIcon, 0, 0, "Toggle Status Icon", EMUCMDFLAG_TASEDITOR }, { EMUCMD_MOVIE_ICON_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUD_ToggleStatusIcon, 0, 0, "Toggle Status Icon", EMUCMDFLAG_TASEDITOR },
@ -768,6 +845,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 7", 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_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_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_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_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_1, EMUCMDTYPE_MISC, CommandUsePreset, 0, 0, "Use Input Preset 1", EMUCMDFLAG_TASEDITOR },
@ -776,6 +854,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_MISC_DISPLAY_BG_TOGGLE, EMUCMDTYPE_MISC, BackgroundDisplayToggle, 0, 0, "Toggle Background Display", 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_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_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_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_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_OPENCHEATS, EMUCMDTYPE_TOOL, LaunchCheats, 0, 0, "Open Cheats", EMUCMDFLAG_TASEDITOR },
@ -801,13 +880,16 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_TOOL_RAMSEARCHEQ, EMUCMDTYPE_TOOL, RamSearchOpEQ, 0, 0, "Ram Search - 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_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_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_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_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_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_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_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_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_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])) #define NUM_EMU_CMDS (sizeof(FCEUI_CommandTable)/sizeof(FCEUI_CommandTable[0]))
@ -1119,6 +1201,17 @@ static void RamSearchOpNE(void) {
#endif #endif
} }
static void DebuggerStepInto()
{
#ifdef WIN32
if (GameInfo)
{
extern void DoDebuggerStepInto();
DoDebuggerStepInto();
}
#endif
}
static void FA_SkipLag(void) static void FA_SkipLag(void)
{ {
frameAdvanceLagSkip ^= 1; frameAdvanceLagSkip ^= 1;
@ -1139,7 +1232,7 @@ static void CloseRom(void)
#endif #endif
} }
static void ReloadRom(void) void ReloadRom(void)
{ {
#ifdef WIN32 #ifdef WIN32
if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR)) if (FCEUMOV_Mode(MOVIEMODE_TASEDITOR))

View File

@ -8,6 +8,10 @@
void LagCounterToggle(void); void LagCounterToggle(void);
extern FILE* PlayInputFile;
extern FILE* DumpInputFile;
class MovieRecord; class MovieRecord;
//MBG TODO - COMBINE THESE INPUTC AND INPUTCFC //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... //keep adding these in order of newness or else the hotkey binding configs will get messed up...
EMUCMD_FPS_DISPLAY_TOGGLE, EMUCMD_FPS_DISPLAY_TOGGLE,
EMUCMD_TOOL_DEBUGSTEPINTO,
EMUCMD_MAX EMUCMD_MAX
}; };

View File

@ -18,64 +18,66 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
// implementation of Subor Mouse
// used in Educational Computer 2000
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "share.h" #include "share.h"
typedef struct { typedef struct {
int32 mzx, mzy, mzxold, mzyold; uint8 latch;
uint32 readbit; int32 dx,dy;
uint32 data; uint32 mb;
} MOUSE; } MOUSE;
static MOUSE 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) 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) static uint8 ReadMOUSE(int w)
{ {
uint8 ret=0; uint8 result = Mouse.latch & 0x01;
if(Mouse.readbit>=8) Mouse.latch = (Mouse.latch >> 1) | 0x80;
ret|=1; return result;
else
{
ret|=(Mouse.data>>Mouse.readbit)&1;
if(!fceuindbg)
Mouse.readbit++;
}
return(ret);
} }
static void UpdateMOUSE(int w, void *data, int arg) static void UpdateMOUSE(int w, void *data, int arg)
{ {
uint32 *ptr=(uint32*)data; uint32 *ptr=(uint32*)data;
Mouse.data=0; Mouse.dx += ptr[0]; ptr[0] = 0;
Mouse.mzxold=Mouse.mzx; Mouse.dy += ptr[1]; ptr[1] = 0;
Mouse.mzyold=Mouse.mzy; Mouse.mb = ptr[2];
Mouse.mzx=ptr[0];
Mouse.mzy=ptr[1]; if (Mouse.dx > INERTIA) Mouse.dx = INERTIA;
Mouse.data|=ptr[2]; else if (Mouse.dx < -INERTIA) Mouse.dx = -INERTIA;
if((Mouse.mzxold-Mouse.mzx)>0)
Mouse.data|=0x0C; if (Mouse.dy > INERTIA) Mouse.dy = INERTIA;
else if((Mouse.mzxold-Mouse.mzx)<0) else if (Mouse.dy < -INERTIA) Mouse.dy = -INERTIA;
Mouse.data|=0x04;
if((Mouse.mzyold-Mouse.mzy)>0)
Mouse.data|=0x30;
else if((Mouse.mzyold-Mouse.mzy)<0)
Mouse.data|=0x10;
} }
static INPUTC MOUSEC={ReadMOUSE,0,StrobeMOUSE,UpdateMOUSE,0,0}; static INPUTC MOUSEC={ReadMOUSE,0,StrobeMOUSE,UpdateMOUSE,0,0};
INPUTC *FCEU_InitMouse(int w) INPUTC *FCEU_InitMouse(int w)
{ {
Mouse.mzx=0; memset(&Mouse,0,sizeof(Mouse));
Mouse.mzy=0;
Mouse.mzxold=0;
Mouse.mzyold=0;
Mouse.data=0;
return(&MOUSEC); return(&MOUSEC);
} }

View File

@ -11,6 +11,7 @@
#include "file.h" #include "file.h"
#include "video.h" #include "video.h"
#include "movie.h" #include "movie.h"
#include "cart.h"
#include "fds.h" #include "fds.h"
#include "vsuni.h" #include "vsuni.h"
#ifdef _S9XLUA_H #ifdef _S9XLUA_H
@ -34,6 +35,9 @@ extern void AddRecentMovieFile(const char *filename);
extern bool mustEngageTaseditor; extern bool mustEngageTaseditor;
#endif #endif
extern int RAMInitOption;
extern int RAMInitSeed;
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -107,7 +111,6 @@ int currRerecordCount; // Keep the global value
char lagcounterbuf[32] = {0}; char lagcounterbuf[32] = {0};
#ifdef GEKKO #ifdef GEKKO
void MovieData::clearRecordRange(int start, int len) { } void MovieData::clearRecordRange(int start, int len) { }
void MovieData::eraseRecords(int at, int frames) { } void MovieData::eraseRecords(int at, int frames) { }
@ -454,8 +457,11 @@ void MovieRecord::dump(MovieData* md, EMUFILE* os, int index)
MovieData::MovieData() MovieData::MovieData()
: version(MOVIE_VERSION) : version(MOVIE_VERSION)
, emuVersion(FCEU_VERSION_NUMERIC) , emuVersion(FCEU_VERSION_NUMERIC)
, fds(false)
, palFlag(false) , palFlag(false)
, PPUflag(false) , PPUflag(false)
, RAMInitOption(0)
, RAMInitSeed(0)
, rerecordCount(0) , rerecordCount(0)
, binaryFlag(false) , binaryFlag(false)
, loadFrameCount(-1) , loadFrameCount(-1)
@ -476,6 +482,10 @@ void MovieData::installValue(std::string& key, std::string& val)
installInt(val,fds); installInt(val,fds);
else if(key == "NewPPU") else if(key == "NewPPU")
installBool(val,PPUflag); installBool(val,PPUflag);
else if(key == "RAMInitOption")
installInt(val,RAMInitOption);
else if(key == "RAMInitSeed")
installInt(val,RAMInitSeed);
else if(key == "version") else if(key == "version")
installInt(val,version); installInt(val,version);
else if(key == "emuVersion") 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 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") else if (key == "length")
{ {
installInt(val, loadFrameCount); installInt(val, loadFrameCount);
@ -539,6 +559,8 @@ int MovieData::dump(EMUFILE *os, bool binary)
os->fprintf("port2 %d\n" , ports[2] ); os->fprintf("port2 %d\n" , ports[2] );
os->fprintf("FDS %d\n" , fds?1:0 ); os->fprintf("FDS %d\n" , fds?1:0 );
os->fprintf("NewPPU %d\n" , PPUflag?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;i<comments.size();i++) for(uint32 i=0;i<comments.size();i++)
os->fprintf("comment %s\n" , wcstombs(comments[i]).c_str() ); os->fprintf("comment %s\n" , wcstombs(comments[i]).c_str() );
@ -552,6 +574,9 @@ int MovieData::dump(EMUFILE *os, bool binary)
if(savestate.size()) if(savestate.size())
os->fprintf("savestate %s\n" , BytesToString(&savestate[0],savestate.size()).c_str() ); 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) if (this->loadFrameCount >= 0)
os->fprintf("length %d\n" , this->loadFrameCount); os->fprintf("length %d\n" , this->loadFrameCount);
@ -831,6 +856,8 @@ void FCEUI_StopMovie()
#endif #endif
} }
bool bogorf;
void poweron(bool shouldDisableBatteryLoading) void poweron(bool shouldDisableBatteryLoading)
{ {
//// make a for-movie-recording power-on clear the game's save data, too //// make a for-movie-recording power-on clear the game's save data, too
@ -855,9 +882,9 @@ void poweron(bool shouldDisableBatteryLoading)
//suppressAddPowerCommand=0; //suppressAddPowerCommand=0;
extern int disableBatteryLoading; extern int disableBatteryLoading;
disableBatteryLoading = 1; if(!bogorf) disableBatteryLoading = 1;
PowerNES(); PowerNES();
disableBatteryLoading = 0; if(!bogorf) disableBatteryLoading = 0;
} }
void FCEUMOV_CreateCleanMovie() void FCEUMOV_CreateCleanMovie()
@ -874,6 +901,8 @@ void FCEUMOV_CreateCleanMovie()
currMovieData.ports[2] = portFC.type; currMovieData.ports[2] = portFC.type;
currMovieData.fds = isFDS; currMovieData.fds = isFDS;
currMovieData.PPUflag = (newppu != 0); currMovieData.PPUflag = (newppu != 0);
currMovieData.RAMInitOption = RAMInitOption;
currMovieData.RAMInitSeed = RAMInitSeed;
} }
void FCEUMOV_ClearCommands() void FCEUMOV_ClearCommands()
{ {
@ -897,6 +926,59 @@ void MovieData::dumpSavestateTo(std::vector<uint8>* buf, int compressionLevel)
ms.trim(); ms.trim();
} }
bool MovieData::loadSaveramFrom(std::vector<uint8>* 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<uint8>* 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 //begin playing an existing movie
bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) 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); LoadSubtitles(currMovieData);
delete fp; delete fp;
RAMInitOption = currMovieData.RAMInitOption;
RAMInitSeed = currMovieData.RAMInitSeed;
freshMovie = true; //Movie has been loaded, so it must be unaltered freshMovie = true; //Movie has been loaded, so it must be unaltered
if (bindSavestate) AutoSS = false; //If bind savestate to movie is true, then their isn't a valid auto-save to load, so flag it if (bindSavestate) AutoSS = false; //If bind savestate to movie is true, then their isn't a valid auto-save to load, so flag it
//fully reload the game to reinitialize everything before playing any movie //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; movieFromPoweron = false;
bool success = MovieData::loadSavestateFrom(&currMovieData.savestate); 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? 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; movieFromPoweron = true;
} }
@ -960,6 +1052,8 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
else else
FCEUI_SetVidSystem(0); FCEUI_SetVidSystem(0);
//force the input configuration stored in the movie to apply //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]); 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; movieFromPoweron = true;
poweron(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; movieFromPoweron = false;
MovieData::dumpSavestateTo(&currMovieData.savestate,Z_BEST_COMPRESSION); MovieData::dumpSavestateTo(&currMovieData.savestate,Z_BEST_COMPRESSION);
@ -1481,7 +1583,7 @@ void FCEUMOV_IncrementRerecordCount()
else else
currMovieData.rerecordCount++; currMovieData.rerecordCount++;
#else #else
if (movieMode != MOVIEMODE_TASEDITOR)currRerecordCount++; if (movieMode != MOVIEMODE_TASEDITOR)
currRerecordCount++; currRerecordCount++;
else else
currMovieData.rerecordCount++; 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.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.pal = md.palFlag;
info.ppuflag = md.PPUflag; info.ppuflag = md.PPUflag;
info.RAMInitOption = md.RAMInitOption;
info.RAMInitSeed = md.RAMInitSeed;
info.nosynchack = true; info.nosynchack = true;
info.num_frames = md.records.size(); info.num_frames = md.records.size();
info.md5_of_rom_used = md.romChecksum; info.md5_of_rom_used = md.romChecksum;

View File

@ -23,13 +23,15 @@ enum EMOVIE_FLAG
MOVIE_FLAG_PAL = (1<<2), 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), MOVIE_FLAG_FROM_POWERON = (1<<3),
// set in newer version, used for old movie compatibility // set in newer version, used for old movie compatibility
//TODO - only use this flag to print a warning that the sync might be bad //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 //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 typedef struct
@ -42,6 +44,7 @@ typedef struct
uint32 emu_version_used; // 9813 = 0.98.13 uint32 emu_version_used; // 9813 = 0.98.13
MD5DATA md5_of_rom_used; MD5DATA md5_of_rom_used;
std::string name_of_rom_used; std::string name_of_rom_used;
int RAMInitOption, RAMInitSeed;
std::vector<std::wstring> comments; std::vector<std::wstring> comments;
std::vector<std::string> subtitles; std::vector<std::string> subtitles;
@ -177,6 +180,7 @@ public:
MD5DATA romChecksum; MD5DATA romChecksum;
std::string romFilename; std::string romFilename;
std::vector<uint8> savestate; std::vector<uint8> savestate;
std::vector<uint8> saveram;
std::vector<MovieRecord> records; std::vector<MovieRecord> records;
std::vector<std::wstring> comments; std::vector<std::wstring> comments;
std::vector<std::string> subtitles; std::vector<std::string> subtitles;
@ -198,6 +202,8 @@ public:
int getNumRecords() { return records.size(); } int getNumRecords() { return records.size(); }
int RAMInitOption, RAMInitSeed;
class TDictionary : public std::map<std::string,std::string> class TDictionary : public std::map<std::string,std::string>
{ {
public: public:
@ -238,6 +244,9 @@ public:
static bool loadSavestateFrom(std::vector<uint8>* buf); static bool loadSavestateFrom(std::vector<uint8>* buf);
static void dumpSavestateTo(std::vector<uint8>* buf, int compressionLevel); static void dumpSavestateTo(std::vector<uint8>* buf, int compressionLevel);
static bool loadSaveramFrom(std::vector<uint8>* buf);
static void dumpSaveramTo(std::vector<uint8>* buf, int compressionLevel);
private: private:
void installInt(std::string& val, int& var) void installInt(std::string& val, int& var)
{ {

View File

@ -119,7 +119,7 @@ int FCEUNET_SendFile(uint8 cmd, char *fn)
if(!(fp=FCEUD_UTF8fopen(fn,"rb"))) return(0); if(!(fp=FCEUD_UTF8fopen(fn,"rb"))) return(0);
fstat(fileno(fp),&sb); FCEUX_fstat(fileno(fp),&sb);
len = sb.st_size; len = sb.st_size;
buf = (char*)FCEU_dmalloc(len); //mbg merge 7/17/06 added cast buf = (char*)FCEU_dmalloc(len); //mbg merge 7/17/06 added cast
fread(buf, 1, len, fp); fread(buf, 1, len, fp);

View File

@ -482,6 +482,7 @@ void DrawNSF(uint8 *XBuf)
if(vismode==0) return; if(vismode==0) return;
memset(XBuf,0,256*240); 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); static const int kFgColor = 1;
DrawTextTrans(ClipSidesOffset+XBuf+26*256+4+(((31-strlen((char*)NSFHeader.Artist))<<2)), 256,NSFHeader.Artist, 6); DrawTextTrans(ClipSidesOffset+XBuf+10*256+4+(((31-strlen((char*)NSFHeader.SongName))<<2)), 256, NSFHeader.SongName, kFgColor);
DrawTextTrans(ClipSidesOffset+XBuf+42*256+4+(((31-strlen((char*)NSFHeader.Copyright))<<2)), 256,NSFHeader.Copyright, 6); 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); 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; static uint8 last=0;

View File

@ -31,8 +31,6 @@
#include "palette.h" #include "palette.h"
#include "palettes/palettes.h" #include "palettes/palettes.h"
#ifndef M_PI #ifndef M_PI
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
#endif #endif
@ -42,24 +40,25 @@
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
static int ntsccol=0; 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 ntsctint = 46+10;
static int ntschue = 72; static int ntschue = 72;
bool force_grayscale = false; //the default basic palette
int default_palette_selection = 0;
/* These are dynamically filled/generated palettes: */ //library of default palettes
pal palettei[64]; // Custom palette for an individual game. static pal *default_palette[8]=
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, palette,
rp2c04001, rp2c04001,
@ -68,35 +67,280 @@ static pal *palpoint[8]=
rp2c05004, rp2c05004,
}; };
void FCEUI_SetPaletteArray(uint8 *pal) 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)
{ {
if(!pal) static float const to_float = 1.0f / 0xFF;
palpoint[0]=palette; 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 else
{ {
int x; static unsigned char const tints [8] = { 0, 6, 10, 8, 2, 4, 0, 0 };
palpoint[0]=palettec; int const tint_color = tints [tint];
for(x=0;x<64;x++) float sat = hi * (0.5f - atten_mul * 0.5f) + atten_sub * 0.5f;
y -= sat * 0.5f;
if ( tint >= 3 && tint != 4 )
{ {
palpoint[0][x].r=*((uint8 *)pal+x+x+x); //combined tint bits
palpoint[0][x].g=*((uint8 *)pal+x+x+x+1); sat *= 0.6f;
palpoint[0][x].b=*((uint8 *)pal+x+x+x+2); 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
// Decode the color index
int color = (entry & 0x0F), level = color<0xE ? (entry>>4) & 3 : 1;
// Voltage levels, relative to synch voltage
static const float black=.518f, white=1.962f, attenuation=.746f,
levels[8] = {.350f, .518f, .962f,1.550f, // Signal low
1.094f,1.506f,1.962f,1.962f}; // Signal high
float lo_and_hi[2] = { levels[level + 4 * (color == 0x0)],
levels[level + 4 * (color < 0xD)] };
//fceux alteration: two passes
//1st pass calculates bisqwit's base color
//2nd pass calculates it with deemph
//finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, we could pregenerate the scale factors)
//whatever, it gets the job done.
for(int pass=0;pass<2;pass++)
{
float y=0.f, i=0.f, q=0.f, gamma=1.8f;
for(int p=0; p<12; ++p) // 12 clock cycles per pixel.
{
// NES NTSC modulator (square wave between two voltage levels):
float spot = lo_and_hi[bisqwit_wave(p,color)];
// De-emphasis bits attenuate a part of the signal:
if(pass==1)
{
if(((entry & 0x40) && bisqwit_wave(p,12))
|| ((entry & 0x80) && bisqwit_wave(p, 4))
|| ((entry &0x100) && bisqwit_wave(p, 8))) spot *= attenuation;
}
// Normalize:
float v = (spot - black) / (white-black) / 12.f;
// Ideal TV NTSC demodulator:
y += v;
i += v * std::cos(3.141592653 * p / 6);
q += v * std::sin(3.141592653 * p / 6); // Or cos(... p-3 ... )
// Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives
// the exactly same result, scaled by a factor of 2*cos(pi/12).
}
// Convert YIQ into RGB according to FCC-sanctioned conversion matrix.
int rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f*i + 0.623557f*q,gamma));
int gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f*i + -0.635691f*q,gamma));
int bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f*i + 1.709007f*q,gamma));
if(pass==0) myr = rt, myg = gt, myb = bt;
else
{
float rscale = (float)rt / myr;
float gscale = (float)gt / myg;
float bscale = (float)bt / myb;
#define BCLAMP(x) ((x)<0?0:((x)>255?255:(x)))
if(myr!=0) r = (u8)(BCLAMP(r*rscale));
if(myg!=0) g = (u8)(BCLAMP(g*gscale));
if(myb!=0) b = (u8)(BCLAMP(b*bscale));
}
}
}
//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(); 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);
void FCEUI_SetNTSCTH(int n, int tint, int hue) //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; ntsctint=tint;
ntschue=hue; ntschue=hue;
ntsccol=n; ntsccol_enable = en;
FCEU_ResetPalette(); 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; static uint8 lastd=0;
void SetNESDeemph(uint8 d, int force) void SetNESDeemph_OldHacky(uint8 d, int force)
{ {
static uint16 rtmul[]={ static uint16 rtmul[]={
static_cast<uint16>(32768*1.239), static_cast<uint16>(32768*1.239),
@ -194,6 +438,10 @@ void SetNESDeemph(uint8 d, int force)
// Converted from Kevin Horton's qbasic palette generator. // Converted from Kevin Horton's qbasic palette generator.
static void CalculatePalette(void) static void CalculatePalette(void)
{ {
//PRECONDITION: ntsc palette is enabled
if(!ntsccol_enable)
return;
int x,z; int x,z;
int r,g,b; int r,g,b;
double s,luma,theta; double s,luma,theta;
@ -229,41 +477,16 @@ static void CalculatePalette(void)
if(g<0) g=0; if(g<0) g=0;
if(b<0) b=0; if(b<0) b=0;
paletten[(x<<4)+z].r=r; palette_ntsc[(x<<4)+z].r=r;
paletten[(x<<4)+z].g=g; palette_ntsc[(x<<4)+z].g=g;
paletten[(x<<4)+z].b=b; palette_ntsc[(x<<4)+z].b=b;
} }
//can't call FCEU_ResetPalette(), it would be re-entrant
//see precondition for this function
WritePalette(); WritePalette();
} }
static int ipalette=0;
void FCEU_LoadGamePalette(void)
{
uint8 ptmp[192];
FILE *fp;
char *fn;
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++)
{
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) void FCEU_ResetPalette(void)
{ {
if(GameInfo) if(GameInfo)
@ -275,39 +498,53 @@ void FCEU_ResetPalette(void)
static void ChoosePalette(void) static void ChoosePalette(void)
{ {
//NSF uses a fixed palette always:
if(GameInfo->type==GIT_NSF) if(GameInfo->type==GIT_NSF)
palo=0; palo = default_palette[0];
else if(ipalette) //user palette takes priority over others
palo=palettei; else if(palette_user_available)
else if(ntsccol && !PAL && GameInfo->type!=GIT_VSUNI) palo = palette_user;
//NTSC takes priority next, if it's appropriate
else if(ntsccol_enable && !PAL && GameInfo->type!=GIT_VSUNI)
{ {
palo=paletten; //for NTSC games, we can actually use the NTSC palette
palo = palette_ntsc;
CalculatePalette(); 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 else
palo=palpoint[pale]; {
palo = default_palette[default_palette_selection];
//need to calcualte a deemph on the fly.. sorry. maybe support otherwise later
ApplyDeemphasisComplete(palo);
}
} }
void WritePalette(void) void WritePalette(void)
{ {
int x; int x;
for(x=0;x<7;x++) //set the 'unvarying' palettes to low < 64 palette entries
FCEUD_SetPalette(x,unvpalette[x].r,unvpalette[x].g,unvpalette[x].b); const int unvaried = sizeof(palette_unvarying)/sizeof(palette_unvarying[0]);
if(GameInfo->type==GIT_NSF) for(x=0;x<unvaried;x++)
{ FCEUD_SetPalette(x,palette_unvarying[x].r,palette_unvarying[x].g,palette_unvarying[x].b);
//clear everything else to a deterministic state.
//it seems likely that the text rendering on NSF has been broken since the beginning of fceux, depending on palette entries 205,205,205 everywhere
//this was just whatever msvc filled malloc with. on non-msvc platforms, there was no backdrop on the rendering.
for(x=unvaried;x<256;x++)
FCEUD_SetPalette(x,205,205,205);
//sets palette entries >= 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 #ifdef _S9XLUA_H
FCEU_LuaUpdatePalette(); FCEU_LuaUpdatePalette();
#endif #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) void FCEUI_GetNTSCTH(int *tint, int *hue)
@ -321,7 +558,7 @@ static int controllength=0;
void FCEUI_NTSCDEC(void) void FCEUI_NTSCDEC(void)
{ {
if(ntsccol && GameInfo->type!=GIT_VSUNI &&!PAL && GameInfo->type!=GIT_NSF) if(ntsccol_enable && GameInfo->type!=GIT_VSUNI &&!PAL && GameInfo->type!=GIT_NSF)
{ {
int which; int which;
if(controlselect) if(controlselect)
@ -343,7 +580,7 @@ void FCEUI_NTSCDEC(void)
void FCEUI_NTSCINC(void) void FCEUI_NTSCINC(void)
{ {
if(ntsccol && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF) if(ntsccol_enable && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF)
if(controlselect) if(controlselect)
{ {
if(controllength) if(controllength)
@ -366,12 +603,12 @@ void FCEUI_NTSCINC(void)
void FCEUI_NTSCSELHUE(void) void FCEUI_NTSCSELHUE(void)
{ {
if(ntsccol && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=1;controllength=360;} if(ntsccol_enable && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=1;controllength=360;}
} }
void FCEUI_NTSCSELTINT(void) void FCEUI_NTSCSELTINT(void)
{ {
if(ntsccol && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=2;controllength=360;} if(ntsccol_enable && GameInfo->type!=GIT_VSUNI && !PAL && GameInfo->type!=GIT_NSF){controlselect=2;controllength=360;}
} }
void FCEU_DrawNTSCControlBars(uint8 *XBuf) void FCEU_DrawNTSCControlBars(uint8 *XBuf)

View File

@ -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" #include "rp2c04001.h"
EMPTY_PALETTE_DEEMPH_X_7
}; };
pal rp2c04002[64] = { pal rp2c04002[512] = {
#include "rp2c04002.h" #include "rp2c04002.h"
EMPTY_PALETTE_DEEMPH_X_7
}; };
pal rp2c04003[64] = { pal rp2c04003[512] = {
#include "rp2c04003.h" #include "rp2c04003.h"
EMPTY_PALETTE_DEEMPH_X_7
}; };
pal rp2c05004[64] = { pal rp2c05004[512] = {
#include "rp2c05004.h" #include "rp2c05004.h"
EMPTY_PALETTE_DEEMPH_X_7
}; };
pal unvpalette[7] = { // Fixed palette entries used by the GUI
{ 0x00<<2,0x00<<2,0x00<<2}, // Black pal palette_unvarying[] = {
{ 0x3F<<2,0x3F<<2,0x34<<2}, // White { 0x00<<2,0x00<<2,0x00<<2}, // 0 = Black
{ 0x00<<2,0x00<<2,0x00<<2}, // Black { 0x3F<<2,0x3F<<2,0x34<<2}, // 1 = White
{ 0x1d<<2,0x1d<<2,0x24<<2}, // Greyish { 0x00<<2,0x00<<2,0x00<<2}, // 2 = Black
{ 190,0,0 }, // Redish { 0x1d<<2,0x1d<<2,0x24<<2}, // 3 = Greyish
{ 51,255,51}, // Bright green { 190, 0, 0}, // 4 = Reddish
{ 49,14,200}, { 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 // Default palette
pal palette[64] = { pal palette[512] = {
{ 0x1D<<2, 0x1D<<2, 0x1D<<2 }, /* Value 0 */ { 0x1D<<2, 0x1D<<2, 0x1D<<2 }, /* Value 0 */
{ 0x09<<2, 0x06<<2, 0x23<<2 }, /* Value 1 */ { 0x09<<2, 0x06<<2, 0x23<<2 }, /* Value 1 */
@ -292,4 +320,6 @@ slightly better but too dark:
*/ */
EMPTY_PALETTE_DEEMPH_X_7
}; };

View File

@ -57,7 +57,8 @@
#define PPU_status (PPU[2]) #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 FetchSpriteData(void);
static void RefreshLine(int lastpixel); static void RefreshLine(int lastpixel);
@ -69,6 +70,8 @@ static uint32 ppulut1[256];
static uint32 ppulut2[256]; static uint32 ppulut2[256];
static uint32 ppulut3[128]; static uint32 ppulut3[128];
static bool new_ppu_reset = false;
int test = 0; int test = 0;
template<typename T, int BITS> template<typename T, int BITS>
@ -274,8 +277,24 @@ struct PPUREGS {
v &= 1; v &= 1;
fv &= 7; 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; } 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) { static void makeppulut(void) {
int x; int x;
int y; int y;
@ -337,7 +356,7 @@ uint8 vtoggle = 0;
uint8 XOffset = 0; uint8 XOffset = 0;
uint8 SpriteDMA = 0; // $4014 / Writing $xx copies 256 bytes by reading from $xx00-$xxFF and writing to $2004 (OAM data) 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; 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 MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)]
#define VRAMADR(V) &VPage[(V) >> 10][(V)] #define VRAMADR(V) &VPage[(V) >> 10][(V)]
//mbg 8/6/08 - fix a bug relating to uint8* MMC5BGVRAMADR(uint32 A);
//"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)];
}
//this duplicates logic which is embedded in the ppu rendering code //this duplicates logic which is embedded in the ppu rendering code
//which figures out where to get CHR data from depending on various hack modes //which figures out where to get CHR data from depending on various hack modes
@ -420,7 +428,7 @@ inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) {
} }
volatile int rendercount, vromreadcount, undefinedvromcount, LogAddress = -1; volatile int rendercount, vromreadcount, undefinedvromcount, LogAddress = -1;
unsigned char *cdloggervdata; unsigned char *cdloggervdata = NULL;
unsigned int cdloggerVideoDataSize = 0; unsigned int cdloggerVideoDataSize = 0;
int GetCHRAddress(int A) { int GetCHRAddress(int A) {
@ -428,6 +436,19 @@ int GetCHRAddress(int A) {
int result = &VPage[A >> 10][A] - CHRptr[0]; int result = &VPage[A >> 10][A] - CHRptr[0];
if ((result >= 0) && (result < (int)cdloggerVideoDataSize)) if ((result >= 0) && (result < (int)cdloggerVideoDataSize))
return result; 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; return -1;
} }
@ -441,11 +462,31 @@ int GetCHRAddress(int A) {
if (!(cdloggervdata[addr] & 1)) \ if (!(cdloggervdata[addr] & 1)) \
{ \ { \
cdloggervdata[addr] |= 1; \ cdloggervdata[addr] |= 1; \
if(cdloggerVideoDataSize) { \
if (!(cdloggervdata[addr] & 2)) undefinedvromcount--; \ if (!(cdloggervdata[addr] & 2)) undefinedvromcount--; \
rendercount++; \ 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++; \
} \
} \
} \
} \
} }
uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A) { uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A) {
@ -461,14 +502,11 @@ uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A) {
uint8 ret; uint8 ret;
if (!(tmp & 3)) { if (!(tmp & 3)) {
if (!(tmp & 0xC)) if (!(tmp & 0xC))
ret = PALRAM[0x00]; ret = READPAL(0x00);
else else
ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; ret = READUPAL(((tmp & 0xC) >> 2) - 1);
} else } else
ret = PALRAM[tmp & 0x1F]; ret = READPAL(tmp & 0x1F);
if (GRAYSCALE)
ret &= 0x30;
return ret; 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)) #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; int newppu = 0;
void ppu_getScroll(int &xpos, int &ypos) { void ppu_getScroll(int &xpos, int &ypos) {
@ -665,7 +703,7 @@ static DECLFR(A2007) {
if (!DummyRead && (LogAddress != -1)) { if (!DummyRead && (LogAddress != -1)) {
if (!(cdloggervdata[LogAddress] & 2)) { if (!(cdloggervdata[LogAddress] & 2)) {
cdloggervdata[LogAddress] |= 2; cdloggervdata[LogAddress] |= 2;
if (!(cdloggervdata[LogAddress] & 1)) undefinedvromcount--; if ((!(cdloggervdata[LogAddress] & 1)) && cdloggerVideoDataSize) undefinedvromcount--;
vromreadcount++; vromreadcount++;
} }
} else } else
@ -683,13 +721,11 @@ static DECLFR(A2007) {
//to get a gray color reading //to get a gray color reading
if (!(tmp & 3)) { if (!(tmp & 3)) {
if (!(tmp & 0xC)) if (!(tmp & 0xC))
ret = PALRAM[0x00]; ret = READPAL(0x00);
else else
ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; ret = READUPAL(((tmp & 0xC) >> 2) - 1);
} else } else
ret = PALRAM[tmp & 0x1F]; ret = READPAL(tmp & 0x1F);
if (GRAYSCALE)
ret &= 0x30;
VRAMBuffer = CALL_PPUREAD(RefreshAddr - 0x1000); VRAMBuffer = CALL_PPUREAD(RefreshAddr - 0x1000);
} else { } else {
if (debug_loggingCD && (RefreshAddr < 0x2000)) if (debug_loggingCD && (RefreshAddr < 0x2000))
@ -700,18 +736,18 @@ static DECLFR(A2007) {
RefreshAddr = ppur.get_2007access(); RefreshAddr = ppur.get_2007access();
return ret; return ret;
} else { } else {
//OLDPPU
FCEUPPU_LineUpdate(); FCEUPPU_LineUpdate();
if (tmp >= 0x3F00) { // Palette RAM tied directly to the output data, without VRAM buffer if (tmp >= 0x3F00) { // Palette RAM tied directly to the output data, without VRAM buffer
if (!(tmp & 3)) { if (!(tmp & 3)) {
if (!(tmp & 0xC)) if (!(tmp & 0xC))
ret = PALRAM[0x00]; ret = READPAL(0x00);
else else
ret = UPALRAM[((tmp & 0xC) >> 2) - 1]; ret = READUPAL(((tmp & 0xC) >> 2) - 1);
} else } else
ret = PALRAM[tmp & 0x1F]; ret = READPAL(tmp & 0x1F);
if (GRAYSCALE)
ret &= 0x30;
#ifdef FCEUDEF_DEBUGGER #ifdef FCEUDEF_DEBUGGER
if (!fceuindbg) if (!fceuindbg)
#endif #endif
@ -731,9 +767,14 @@ static DECLFR(A2007) {
if (PPU_hook) PPU_hook(tmp); if (PPU_hook) PPU_hook(tmp);
PPUGenLatch = VRAMBuffer; PPUGenLatch = VRAMBuffer;
if (tmp < 0x2000) { if (tmp < 0x2000) {
if (debug_loggingCD) if (debug_loggingCD)
LogAddress = GetCHRAddress(tmp); LogAddress = GetCHRAddress(tmp);
if(MMC5Hack && newppu)
VRAMBuffer = *MMC5BGVRAMADR(tmp);
else
VRAMBuffer = VPage[tmp >> 10][tmp]; VRAMBuffer = VPage[tmp >> 10][tmp];
} else if (tmp < 0x3F00) } else if (tmp < 0x3F00)
VRAMBuffer = vnapage[(tmp >> 10) & 0x3][tmp & 0x3FF]; VRAMBuffer = vnapage[(tmp >> 10) & 0x3][tmp & 0x3FF];
} }
@ -786,6 +827,8 @@ static DECLFW(B2000) {
static DECLFW(B2001) { static DECLFW(B2001) {
FCEUPPU_LineUpdate(); FCEUPPU_LineUpdate();
if (paldeemphswap)
V = (V&0x9F)|((V&0x40)>>1)|((V&0x20)<<1);
PPUGenLatch = V; PPUGenLatch = V;
PPU[1] = V; PPU[1] = V;
if (V & 0xE0) if (V & 0xE0)
@ -881,6 +924,11 @@ static DECLFW(B2006) {
static DECLFW(B2007) { static DECLFW(B2007) {
uint32 tmp = RefreshAddr & 0x3FFF; uint32 tmp = RefreshAddr & 0x3FFF;
if (debug_loggingCD) {
if(!cdloggerVideoDataSize && (tmp < 0x2000))
cdloggervdata[tmp] = 0;
}
if (newppu) { if (newppu) {
PPUGenLatch = V; PPUGenLatch = V;
RefreshAddr = ppur.get_2007access() & 0x3FFF; RefreshAddr = ppur.get_2007access() & 0x3FFF;
@ -1043,7 +1091,7 @@ static void RefreshLine(int lastpixel) {
if (!ScreenON && !SpriteON) { if (!ScreenON && !SpriteON) {
uint32 tem; 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; tem |= 0x40404040;
FCEU_dwmemset(Pline, tem, numtiles * 8); FCEU_dwmemset(Pline, tem, numtiles * 8);
P += numtiles * 8; P += numtiles * 8;
@ -1064,10 +1112,10 @@ static void RefreshLine(int lastpixel) {
} }
//Priority bits, needed for sprite emulation. //Priority bits, needed for sprite emulation.
Pal[0] |= 64; PALRAM[0] |= 64;
Pal[4] |= 64; PALRAM[4] |= 64;
Pal[8] |= 64; PALRAM[8] |= 64;
Pal[0xC] |= 64; PALRAM[0xC] |= 64;
//This high-level graphics MMC5 emulation code was written for MMC5 carts in "CL" mode. //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. //It's probably not totally correct for carts in "SL" mode.
@ -1145,15 +1193,15 @@ static void RefreshLine(int lastpixel) {
#undef RefreshAddr #undef RefreshAddr
//Reverse changes made before. //Reverse changes made before.
Pal[0] &= 63; PALRAM[0] &= 63;
Pal[4] &= 63; PALRAM[4] &= 63;
Pal[8] &= 63; PALRAM[8] &= 63;
Pal[0xC] &= 63; PALRAM[0xC] &= 63;
RefreshAddr = smorkus; RefreshAddr = smorkus;
if (firsttile <= 2 && 2 < lasttile && !(PPU[1] & 2)) { if (firsttile <= 2 && 2 < lasttile && !(PPU[1] & 2)) {
uint32 tem; 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; tem |= 0x40404040;
*(uint32*)Plinef = *(uint32*)(Plinef + 4) = tem; *(uint32*)Plinef = *(uint32*)(Plinef + 4) = tem;
} }
@ -1161,7 +1209,7 @@ static void RefreshLine(int lastpixel) {
if (!ScreenON) { if (!ScreenON) {
uint32 tem; uint32 tem;
int tstart, tcount; 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; tem |= 0x40404040;
tcount = lasttile - firsttile; tcount = lasttile - firsttile;
@ -1218,11 +1266,16 @@ static void Fixit1(void) {
void MMC5_hb(int); //Ugh ugh ugh. void MMC5_hb(int); //Ugh ugh ugh.
static void DoLine(void) { static void DoLine(void) {
if (scanline >= 240 && scanline != totalscanlines) {
X6502_Run(256 + 69);
scanline++;
X6502_Run(16);
return;
}
int x; 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); uint8 *target = XBuf + ((scanline < 240 ? scanline : 240) << 8);
u8* dtarget = XDBuf + ((scanline < 240 ? scanline : 240) << 8);
if (MMC5Hack) MMC5_hb(scanline); if (MMC5Hack) MMC5_hb(scanline);
@ -1233,7 +1286,7 @@ static void DoLine(void) {
uint32 tem; uint32 tem;
uint8 col; uint8 col;
if (gNoBGFillColor == 0xFF) if (gNoBGFillColor == 0xFF)
col = Pal[0]; col = READPAL(0);
else col = gNoBGFillColor; else col = gNoBGFillColor;
tem = col | (col << 8) | (col << 16) | (col << 24); tem = col | (col << 8) | (col << 16) | (col << 24);
tem |= 0x40404040; tem |= 0x40404040;
@ -1243,12 +1296,16 @@ static void DoLine(void) {
if (SpriteON) if (SpriteON)
CopySprites(target); CopySprites(target);
if (ScreenON || SpriteON) { // Yes, very el-cheapo. //greyscale handling (mask some bits off the color) ? ? ?
if (ScreenON || SpriteON)
{
if (PPU[1] & 0x01) { if (PPU[1] & 0x01) {
for (x = 63; x >= 0; x--) for (x = 63; x >= 0; x--)
*(uint32*)&target[x << 2] = (*(uint32*)&target[x << 2]) & 0x30303030; *(uint32*)&target[x << 2] = (*(uint32*)&target[x << 2]) & 0x30303030;
} }
} }
//some pathetic attempts at deemph
if ((PPU[1] >> 5) == 0x7) { if ((PPU[1] >> 5) == 0x7) {
for (x = 63; x >= 0; x--) for (x = 63; x >= 0; x--)
*(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0xc0c0c0c0; *(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0xc0c0c0c0;
@ -1259,6 +1316,10 @@ static void DoLine(void) {
for (x = 63; x >= 0; x--) for (x = 63; x >= 0; x--)
*(uint32*)&target[x << 2] = ((*(uint32*)&target[x << 2]) & 0x3f3f3f3f) | 0x80808080; *(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; sphitx = 0x100;
if (ScreenON || SpriteON) if (ScreenON || SpriteON)
@ -1362,10 +1423,10 @@ static void FetchSpriteData(void) {
C = VRAMADR(vadr); C = VRAMADR(vadr);
if (SpriteON) if (SpriteON)
RENDER_LOG(vadr); RENDER_LOGP(C);
dst.ca[0] = C[0]; dst.ca[0] = C[0];
if (SpriteON) if (SpriteON)
RENDER_LOG(vadr + 8); RENDER_LOGP(C + 8);
dst.ca[1] = C[8]; dst.ca[1] = C[8];
dst.x = spr->x; dst.x = spr->x;
dst.atr = spr->atr; dst.atr = spr->atr;
@ -1414,14 +1475,14 @@ static void FetchSpriteData(void) {
else else
C = VRAMADR(vadr); C = VRAMADR(vadr);
if (SpriteON) if (SpriteON)
RENDER_LOG(vadr); RENDER_LOGP(C);
dst.ca[0] = C[0]; dst.ca[0] = C[0];
if (ns < 8) { if (ns < 8) {
PPU_hook(0x2000); PPU_hook(0x2000);
PPU_hook(vadr); PPU_hook(vadr);
} }
if (SpriteON) if (SpriteON)
RENDER_LOG(vadr + 8); RENDER_LOGP(C + 8);
dst.ca[1] = C[8]; dst.ca[1] = C[8];
dst.x = spr->x; dst.x = spr->x;
dst.atr = spr->atr; dst.atr = spr->atr;
@ -1466,7 +1527,7 @@ static void RefreshSprites(void) {
int x = spr->x; int x = spr->x;
uint8 *C; uint8 *C;
uint8 *VB; int VB;
pixdata = ppulut1[spr->ca[0]] | ppulut2[spr->ca[1]]; pixdata = ppulut1[spr->ca[0]] | ppulut2[spr->ca[1]];
J = spr->ca[0] | spr->ca[1]; J = spr->ca[0] | spr->ca[1];
@ -1488,75 +1549,75 @@ static void RefreshSprites(void) {
} }
C = sprlinebuf + x; C = sprlinebuf + x;
VB = (PALRAM + 0x10) + ((atr & 3) << 2); VB = (0x10) + ((atr & 3) << 2);
if (atr & SP_BACK) { if (atr & SP_BACK) {
if (atr & H_FLIP) { 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; pixdata >>= 4;
if (J & 0x40) C[6] = VB[pixdata & 3] | 0x40; if (J & 0x40) C[6] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x20) C[5] = VB[pixdata & 3] | 0x40; if (J & 0x20) C[5] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x10) C[4] = VB[pixdata & 3] | 0x40; if (J & 0x10) C[4] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x08) C[3] = VB[pixdata & 3] | 0x40; if (J & 0x08) C[3] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x04) C[2] = VB[pixdata & 3] | 0x40; if (J & 0x04) C[2] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x02) C[1] = VB[pixdata & 3] | 0x40; if (J & 0x02) C[1] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x01) C[0] = VB[pixdata] | 0x40; if (J & 0x01) C[0] = READPAL(VB | pixdata) | 0x40;
} else { } else {
if (J & 0x80) C[0] = VB[pixdata & 3] | 0x40; if (J & 0x80) C[0] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x40) C[1] = VB[pixdata & 3] | 0x40; if (J & 0x40) C[1] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x20) C[2] = VB[pixdata & 3] | 0x40; if (J & 0x20) C[2] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x10) C[3] = VB[pixdata & 3] | 0x40; if (J & 0x10) C[3] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x08) C[4] = VB[pixdata & 3] | 0x40; if (J & 0x08) C[4] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x04) C[5] = VB[pixdata & 3] | 0x40; if (J & 0x04) C[5] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x02) C[6] = VB[pixdata & 3] | 0x40; if (J & 0x02) C[6] = READPAL(VB | (pixdata & 3)) | 0x40;
pixdata >>= 4; pixdata >>= 4;
if (J & 0x01) C[7] = VB[pixdata] | 0x40; if (J & 0x01) C[7] = READPAL(VB | pixdata) | 0x40;
} }
} else { } else {
if (atr & H_FLIP) { if (atr & H_FLIP) {
if (J & 0x80) C[7] = VB[pixdata & 3]; if (J & 0x80) C[7] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x40) C[6] = VB[pixdata & 3]; if (J & 0x40) C[6] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x20) C[5] = VB[pixdata & 3]; if (J & 0x20) C[5] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x10) C[4] = VB[pixdata & 3]; if (J & 0x10) C[4] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x08) C[3] = VB[pixdata & 3]; if (J & 0x08) C[3] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x04) C[2] = VB[pixdata & 3]; if (J & 0x04) C[2] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x02) C[1] = VB[pixdata & 3]; if (J & 0x02) C[1] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x01) C[0] = VB[pixdata]; if (J & 0x01) C[0] = READPAL(VB | pixdata);
} else { } else {
if (J & 0x80) C[0] = VB[pixdata & 3]; if (J & 0x80) C[0] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x40) C[1] = VB[pixdata & 3]; if (J & 0x40) C[1] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x20) C[2] = VB[pixdata & 3]; if (J & 0x20) C[2] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x10) C[3] = VB[pixdata & 3]; if (J & 0x10) C[3] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x08) C[4] = VB[pixdata & 3]; if (J & 0x08) C[4] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x04) C[5] = VB[pixdata & 3]; if (J & 0x04) C[5] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; pixdata >>= 4;
if (J & 0x02) C[6] = VB[pixdata & 3]; if (J & 0x02) C[6] = READPAL(VB | (pixdata & 3));
pixdata >>= 4; 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; scanlines_per_frame = dendy ? 262: 312;
FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; FSettings.FirstSLine = FSettings.UsrFirstSLine[1];
FSettings.LastSLine = FSettings.UsrLastSLine[1]; FSettings.LastSLine = FSettings.UsrLastSLine[1];
//paldeemphswap = 1; // dendy has pal ppu, and pal ppu has these swapped
} else { } else {
scanlines_per_frame = 262; scanlines_per_frame = 262;
FSettings.FirstSLine = FSettings.UsrFirstSLine[0]; FSettings.FirstSLine = FSettings.UsrFirstSLine[0];
FSettings.LastSLine = FSettings.UsrLastSLine[0]; FSettings.LastSLine = FSettings.UsrLastSLine[0];
//paldeemphswap = 0;
} }
} }
@ -1666,8 +1729,7 @@ void FCEUPPU_Reset(void) {
kook = 0; kook = 0;
idleSynch = 1; idleSynch = 1;
ppur.reset(); new_ppu_reset = true; // delay reset of ppur/spr_read until it's ready to start a new frame
spr_read.reset();
} }
void FCEUPPU_Power(void) { void FCEUPPU_Power(void) {
@ -1729,6 +1791,13 @@ int FCEUPPU_Loop(int skip) {
TriggerNMI(); TriggerNMI();
} }
X6502_Run((scanlines_per_frame - 242) * (256 + 85) - 12); 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; PPU_status &= 0x1f;
X6502_Run(256); X6502_Run(256);
@ -1759,7 +1828,7 @@ int FCEUPPU_Loop(int skip) {
kook ^= 1; kook ^= 1;
} }
if (GameInfo->type == GIT_NSF) if (GameInfo->type == GIT_NSF)
X6502_Run((256 + 85) * (dendy ? 290 : 240)); X6502_Run((256 + 85) * normalscanlines);
#ifdef FRAMESKIP #ifdef FRAMESKIP
else if (skip) { else if (skip) {
int y; int y;
@ -1785,24 +1854,42 @@ int FCEUPPU_Loop(int skip) {
} }
#endif #endif
else { else {
int x, max, maxref;
deemp = PPU[1] >> 5; 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]++; deempcnt[deemp]++;
if (scanline < 240) if (scanline < 240)
DEBUG(FCEUD_UpdatePPUView(scanline, 1)); DEBUG(FCEUD_UpdatePPUView(scanline, 1));
DoLine(); DoLine();
if (scanline < normalscanlines || scanline == totalscanlines)
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); 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) { if (deempcnt[x] > max) {
max = deempcnt[x]; max = deempcnt[x];
maxref = x; maxref = x;
} }
deempcnt[x] = 0; deempcnt[x] = 0;
} }
SetNESDeemph(maxref, 0); SetNESDeemph_OldHacky(maxref, 0);
} }
} //else... to if(ppudead) } //else... to if(ppudead)
@ -1902,8 +1989,11 @@ const int kFetchTime = 2;
void runppu(int x) { void runppu(int x) {
ppur.status.cycle = (ppur.status.cycle + x) % ppur.status.end_cycle; ppur.status.cycle = (ppur.status.cycle + x) % ppur.status.end_cycle;
if (!new_ppu_reset) // if resetting, suspend CPU until the first frame
{
X6502_Run(x); X6502_Run(x);
} }
}
//todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory //todo - consider making this a 3 or 4 slot fifo to keep from touching so much memory
struct BGData { struct BGData {
@ -1911,7 +2001,7 @@ struct BGData {
uint8 nt, pecnt, at, pt[2]; uint8 nt, pecnt, at, pt[2];
INLINE void Read() { INLINE void Read() {
RefreshAddr = ppur.get_ntread(); NTRefreshAddr = RefreshAddr = ppur.get_ntread();
if (PEC586Hack) if (PEC586Hack)
ppur.s = (RefreshAddr & 0x200) >> 9; ppur.s = (RefreshAddr & 0x200) >> 9;
pecnt = (RefreshAddr & 1) << 3; pecnt = (RefreshAddr & 1) << 3;
@ -1973,6 +2063,14 @@ static inline int PaletteAdjustPixel(int pixel) {
int framectr = 0; int framectr = 0;
int FCEUX_PPU_Loop(int skip) { 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 //262 scanlines
if (ppudead) { if (ppudead) {
// not quite emulating all the NES power up behavior // 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 ppur.status.sl = 241; //for sprite reads
runppu(delay); //X6502_Run(12); //formerly: runppu(delay);
for(int dot=0;dot<delay;dot++)
runppu(1);
if (VBlankON) TriggerNMI(); if (VBlankON) TriggerNMI();
if (PAL) int sltodo = PAL?70:20;
runppu(70 * (kLineTime) - delay);
else //formerly: runppu(20 * (kLineTime) - delay);
runppu(20 * (kLineTime) - delay); for(int S=0;S<sltodo;S++)
{
for(int dot=(S==0?delay:0);dot<kLineTime;dot++)
runppu(1);
ppur.status.sl++;
}
//this seems to run just before the dummy scanline begins //this seems to run just before the dummy scanline begins
PPU_status = 0; PPU_status = 0;
@ -2032,7 +2138,8 @@ int FCEUX_PPU_Loop(int skip) {
//capture the initial xscroll //capture the initial xscroll
//int xscroll = ppur.fh; //int xscroll = ppur.fh;
//render 241/291 scanlines (1 dummy at beginning, dendy's 50 at the end) //render 241/291 scanlines (1 dummy at beginning, dendy's 50 at the end)
for (int sl = 0; sl < (dendy ? 291 : 241); sl++) { //ignore overclocking!
for (int sl = 0; sl < normalscanlines; sl++) {
spr_read.start_scanline(); spr_read.start_scanline();
g_rasterpos = 0; g_rasterpos = 0;
@ -2048,6 +2155,9 @@ int FCEUX_PPU_Loop(int skip) {
DEBUG(FCEUD_UpdateNTView(scanline = yp, 1)); DEBUG(FCEUD_UpdateNTView(scanline = yp, 1));
} }
//hack to fix SDF ship intro screen with split. is it right?
//well, if we didnt do this, we'd be passing in a negative scanline, so that's a sign something is fishy..
if(sl != 0)
if (MMC5Hack) MMC5_hb(yp); if (MMC5Hack) MMC5_hb(yp);
@ -2064,18 +2174,22 @@ int FCEUX_PPU_Loop(int skip) {
for (int xt = 0; xt < 32; xt++) { for (int xt = 0; xt < 32; xt++) {
bgdata.main[xt + 2].Read(); bgdata.main[xt + 2].Read();
const uint8 blank = (gNoBGFillColor == 0xFF) ? READPAL(0) : gNoBGFillColor;
//ok, we're also going to draw here. //ok, we're also going to draw here.
//unless we're on the first dummy scanline //unless we're on the first dummy scanline
if (sl != 0 && sl < 241) { // cape at 240 for dendy, its PPU does nothing afterwards if (sl != 0 && sl < 241) { // cape at 240 for dendy, its PPU does nothing afterwards
int xstart = xt << 3; int xstart = xt << 3;
oamcount = oamcounts[renderslot]; oamcount = oamcounts[renderslot];
uint8 * const target = XBuf + (yp << 8) + xstart; uint8 * const target = XBuf + (yp << 8) + xstart;
uint8 * const dtarget = XDBuf + (yp << 8) + xstart;
uint8 *ptr = target; uint8 *ptr = target;
uint8 *dptr = dtarget;
int rasterpos = xstart; int rasterpos = xstart;
//check all the conditions that can cause things to render in these 8px //check all the conditions that can cause things to render in these 8px
const bool renderspritenow = SpriteON && rendersprites && (xt > 0 || SpriteLeft8); const bool renderspritenow = SpriteON && (xt > 0 || SpriteLeft8);
const bool renderbgnow = ScreenON && renderbg && (xt > 0 || BGLeft8); const bool renderbgnow = ScreenON && (xt > 0 || BGLeft8);
for (int xp = 0; xp < 8; xp++, rasterpos++, g_rasterpos++) { for (int xp = 0; xp < 8; xp++, rasterpos++, g_rasterpos++) {
//bg pos is different from raster pos due to its offsetability. //bg pos is different from raster pos due to its offsetability.
//so adjust for that here //so adjust for that here
@ -2083,14 +2197,28 @@ int FCEUX_PPU_Loop(int skip) {
const int bgpx = bgpos & 7; const int bgpx = bgpos & 7;
const int bgtile = bgpos >> 3; 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 //generate the BG data
if (renderbgnow) { if (renderbgnow) {
uint8* pt = bgdata.main[bgtile].pt; uint8* pt = bgdata.main[bgtile].pt;
pixel = ((pt[0] >> (7 - bgpx)) & 1) | (((pt[1] >> (7 - bgpx)) & 1) << 1) | bgdata.main[bgtile].at; 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 //look for a sprite to be drawn
bool havepixel = false; bool havepixel = false;
@ -2133,11 +2261,14 @@ int FCEUX_PPU_Loop(int skip) {
//bring in the palette bits and palettize //bring in the palette bits and palettize
spixel |= (oam[2] & 3) << 2; spixel |= (oam[2] & 3) << 2;
pixelcolor = PALRAM[0x10 + spixel];
if (rendersprites)
pixelcolor = READPAL(0x10 + spixel);
} }
} }
*ptr++ = PaletteAdjustPixel(pixelcolor); *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); if (realSprite) runppu(kFetchTime);
@ -2318,6 +2457,8 @@ int FCEUX_PPU_Loop(int skip) {
runppu(1); runppu(1);
} //scanline loop } //scanline loop
DMC_7bit = 0;
if (MMC5Hack) MMC5_hb(240); if (MMC5Hack) MMC5_hb(240);
//idle for one line //idle for one line

View File

@ -9,6 +9,10 @@ void FCEUPPU_SetVideoSystem(int w);
extern void (*PPU_hook)(uint32 A); extern void (*PPU_hook)(uint32 A);
extern void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void); 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 */ /* For cart.c and banksw.h, mostly */
extern uint8 NTARAM[0x800], *vnapage[4]; extern uint8 NTARAM[0x800], *vnapage[4];
extern uint8 PPUNTARAM; extern uint8 PPUNTARAM;
@ -18,10 +22,10 @@ void FCEUPPU_SaveState(void);
void FCEUPPU_LoadState(int version); void FCEUPPU_LoadState(int version);
uint32 FCEUPPU_PeekAddress(); uint32 FCEUPPU_PeekAddress();
uint8* FCEUPPU_GetCHR(uint32 vadr, uint32 refreshaddr); uint8* FCEUPPU_GetCHR(uint32 vadr, uint32 refreshaddr);
int FCEUPPU_GetAttr(int ntnum, int xt, int yt);
void ppu_getScroll(int &xpos, int &ypos); void ppu_getScroll(int &xpos, int &ypos);
#ifdef _MSC_VER #ifdef _MSC_VER
#define FASTCALL __fastcall #define FASTCALL __fastcall
#else #else
@ -34,9 +38,10 @@ extern void (*FFCEUX_PPUWrite)(uint32 A, uint8 V);
extern uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A); extern uint8 FASTCALL FFCEUX_PPURead_Default(uint32 A);
void FFCEUX_PPUWrite_Default(uint32 A, uint8 V); void FFCEUX_PPUWrite_Default(uint32 A, uint8 V);
extern int scanline;
extern int g_rasterpos; extern int g_rasterpos;
extern uint8 PPU[4]; extern uint8 PPU[4];
extern bool DMC_7bit;
extern bool paldeemphswap;
enum PPUPHASE { enum PPUPHASE {
PPUPHASE_VBL, PPUPHASE_BG, PPUPHASE_OBJ PPUPHASE_VBL, PPUPHASE_BG, PPUPHASE_OBJ

View File

@ -89,21 +89,21 @@ pshift[1] <<= 8;
#ifdef PPU_BGFETCH #ifdef PPU_BGFETCH
if (RefreshAddr & 1) { if (RefreshAddr & 1) {
if(ScreenON) if(ScreenON)
RENDER_LOG(vadr + 8); RENDER_LOGP(C + 8);
pshift[0] |= C[8]; pshift[0] |= C[8];
pshift[1] |= C[8]; pshift[1] |= C[8];
} else { } else {
if(ScreenON) if(ScreenON)
RENDER_LOG(vadr); RENDER_LOGP(C);
pshift[0] |= C[0]; pshift[0] |= C[0];
pshift[1] |= C[0]; pshift[1] |= C[0];
} }
#else #else
if(ScreenON) if(ScreenON)
RENDER_LOG(vadr); RENDER_LOGP(C);
pshift[0] |= C[0]; pshift[0] |= C[0];
if(ScreenON) if(ScreenON)
RENDER_LOG(vadr + 8); RENDER_LOGP(C + 8);
pshift[1] |= C[8]; pshift[1] |= C[8];
#endif #endif

View File

@ -58,6 +58,7 @@ uint8 EnabledChannels=0; // $4015 / Sound channels enable and status
uint8 IRQFrameMode=0; // $4017 / Frame counter control / xx000000 uint8 IRQFrameMode=0; // $4017 / Frame counter control / xx000000
uint8 InitialRawDALatch=0; // used only for lua uint8 InitialRawDALatch=0; // used only for lua
bool DMC_7bit = 0; // used to skip overclocking
ENVUNIT EnvUnits[3]; ENVUNIT EnvUnits[3];
static const int RectDuties[4]={1,2,4,6}; 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, 4, 8, 16, 32, 64, 96, 128, 160, 202,
254, 380, 508, 762, 1016, 2034, 4068 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, 4, 7, 14, 30, 60, 88, 118, 148, 188,
236, 354, 472, 708, 944, 1890, 3778 236, 354, 472, 708, 944, 1890, 3778
}; };
const uint32 *NoiseFreqTable = NoiseFreqTableNTSC; // for lua only
static const uint32 NTSCDMCTable[0x10]= static const uint32 NTSCDMCTable[0x10]=
{ {
@ -233,10 +233,8 @@ static DECLFW(Write_PSG)
DoSQ1(); DoSQ1();
EnvUnits[0].Mode=(V&0x30)>>4; EnvUnits[0].Mode=(V&0x30)>>4;
EnvUnits[0].Speed=(V&0xF); EnvUnits[0].Speed=(V&0xF);
#ifdef WIN32
if (swapDuty) if (swapDuty)
V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1);
#endif
break; break;
case 0x1: case 0x1:
sweepon[0]=V&0x80; sweepon[0]=V&0x80;
@ -253,10 +251,8 @@ static DECLFW(Write_PSG)
DoSQ2(); DoSQ2();
EnvUnits[1].Mode=(V&0x30)>>4; EnvUnits[1].Mode=(V&0x30)>>4;
EnvUnits[1].Speed=(V&0xF); EnvUnits[1].Speed=(V&0xF);
#ifdef WIN32
if (swapDuty) if (swapDuty)
V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1); V = (V&0x3F)|((V&0x80)>>1)|((V&0x40)<<1);
#endif
break; break;
case 0x5: case 0x5:
sweepon[1]=V&0x80; sweepon[1]=V&0x80;
@ -315,7 +311,8 @@ static DECLFW(Write_DMCRegs)
switch(A) switch(A)
{ {
case 0x00:DoPCM(); case 0x00:
DoPCM();
LoadDMCPeriod(V&0xF); LoadDMCPeriod(V&0xF);
if(SIRQStat&0x80) if(SIRQStat&0x80)
@ -329,15 +326,24 @@ static DECLFW(Write_DMCRegs)
} }
DMCFormat=V; DMCFormat=V;
break; break;
case 0x01:DoPCM(); case 0x01:
DoPCM();
InitialRawDALatch=V&0x7F; InitialRawDALatch=V&0x7F;
RawDALatch=InitialRawDALatch; 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; break;
case 0x02:DMCAddressLatch=V;break;
case 0x03:DMCSizeLatch=V;break;
} }
} }
static DECLFW(StatusWrite) static DECLFW(StatusWrite)
@ -349,6 +355,7 @@ static DECLFW(StatusWrite)
DoTriangle(); DoTriangle();
DoNoise(); DoNoise();
DoPCM(); DoPCM();
for(x=0;x<4;x++) for(x=0;x<4;x++)
if(!(V&(1<<x))) lengthcount[x]=0; /* Force length counters to 0. */ if(!(V&(1<<x))) lengthcount[x]=0; /* Force length counters to 0. */
@ -1045,7 +1052,7 @@ int FlushEmulateSound(void)
int x; int x;
int32 end,left; int32 end,left;
if(!timestamp) return(0); if(!soundtimestamp) return(0);
if(!FSettings.SndRate) if(!FSettings.SndRate)
{ {
@ -1066,7 +1073,7 @@ int FlushEmulateSound(void)
if(GameExpSound.HiFill) GameExpSound.HiFill(); if(GameExpSound.HiFill) GameExpSound.HiFill();
for(x=timestamp;x;x--) for(x=soundtimestamp;x;x--)
{ {
uint32 b=*tmpo; uint32 b=*tmpo;
*tmpo=(b&65535)+wlookup2[(b>>16)&255]+wlookup1[b>>24]; *tmpo=(b&65535)+wlookup2[(b>>16)&255]+wlookup1[b>>24];

View File

@ -59,7 +59,7 @@ extern unsigned char *cdloggerdata;
extern uint32 soundtsoffs; extern uint32 soundtsoffs;
extern bool swapDuty; extern bool swapDuty;
#define SOUNDTS (timestamp + soundtsoffs) #define SOUNDTS (soundtimestamp + soundtsoffs)
void SetNESSoundMap(void); void SetNESSoundMap(void);
void FrameSoundUpdate(void); void FrameSoundUpdate(void);

View File

@ -974,8 +974,12 @@ void FCEUI_LoadState(const char *fname, bool display_message)
loadStateFailed = 1; loadStateFailed = 1;
return; // state doesn't exist; exit cleanly return; // state doesn't exist; exit cleanly
} }
if (FCEUSS_Load(fname, display_message)) 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 //mbg todo netplay
#if 0 #if 0
if(FCEUnetplay) if(FCEUnetplay)

View File

@ -44,10 +44,9 @@ typedef signed short int16;
typedef signed int int32; typedef signed int int32;
#define dup _dup #define dup _dup
#define stat _stat #define stat _stat
#define fstat _fstat
#define mkdir _mkdir #define mkdir _mkdir
#define alloca _alloca #define alloca _alloca
#define snprintf _snprintf #define FCEUX_fstat _fstat
#if _MSC_VER < 1500 #if _MSC_VER < 1500
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#endif #endif
@ -74,6 +73,8 @@ typedef int32_t int32;
typedef uint8_t uint8; typedef uint8_t uint8;
typedef uint16_t uint16; typedef uint16_t uint16;
typedef uint32_t uint32; typedef uint32_t uint32;
#define FCEUX_fstat fstat
#endif #endif
#ifdef __GNUC__ #ifdef __GNUC__

View File

@ -118,6 +118,7 @@ static void MooMirroring(void) {
if (mirrortodo < 0x4) if (mirrortodo < 0x4)
SetupCartMirroring(mirrortodo, 1, 0); SetupCartMirroring(mirrortodo, 1, 0);
else if (mirrortodo == 0x4) { else if (mirrortodo == 0x4) {
FCEU_MemoryRand(exntar, sizeof(exntar), true);
SetupCartMirroring(4, 1, exntar); SetupCartMirroring(4, 1, exntar);
AddExState(exntar, 2048, 0, "EXNR"); AddExState(exntar, 2048, 0, "EXNR");
} else } else
@ -348,6 +349,7 @@ static BMAPPING bmap[] = {
{ "BS-5", BMCBS5_Init, 0 }, { "BS-5", BMCBS5_Init, 0 },
{ "CC-21", UNLCC21_Init, 0 }, { "CC-21", UNLCC21_Init, 0 },
{ "CITYFIGHT", UNLCITYFIGHT_Init, 0 }, { "CITYFIGHT", UNLCITYFIGHT_Init, 0 },
{ "10-24-C-A1", BMC1024CA1_Init, 0 },
{ "CNROM", CNROM_Init, 0 }, { "CNROM", CNROM_Init, 0 },
{ "CPROM", CPROM_Init, BMCFLAG_16KCHRR }, { "CPROM", CPROM_Init, BMCFLAG_16KCHRR },
{ "D1038", BMCD1038_Init, 0 }, { "D1038", BMCD1038_Init, 0 },
@ -374,6 +376,7 @@ static BMAPPING bmap[] = {
{ "KS7010", UNLKS7010_Init, 0 }, { "KS7010", UNLKS7010_Init, 0 },
{ "KS7012", UNLKS7012_Init, 0 }, { "KS7012", UNLKS7012_Init, 0 },
{ "KS7013B", UNLKS7013B_Init, 0 }, { "KS7013B", UNLKS7013B_Init, 0 },
{ "KS7016", UNLKS7016_Init, 0 },
{ "KS7017", UNLKS7017_Init, 0 }, { "KS7017", UNLKS7017_Init, 0 },
{ "KS7030", UNLKS7030_Init, 0 }, { "KS7030", UNLKS7030_Init, 0 },
{ "KS7031", UNLKS7031_Init, 0 }, { "KS7031", UNLKS7031_Init, 0 },
@ -462,6 +465,16 @@ static BMAPPING bmap[] = {
{ "YOKO", UNLYOKO_Init, 0 }, { "YOKO", UNLYOKO_Init, 0 },
{ "SB-2000", UNLSB2000_Init, 0 }, { "SB-2000", UNLSB2000_Init, 0 },
{ "COOLBOY", COOLBOY_Init, BMCFLAG_256KCHRR }, { "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 } { 0, 0, 0 }
}; };
@ -614,6 +627,7 @@ int UNIFLoad(const char *name, FCEUFILE *fp) {
strcpy(LoadedRomFName, name); //For the debugger list strcpy(LoadedRomFName, name); //For the debugger list
GameInterface = UNIFGI; GameInterface = UNIFGI;
currCartInfo = &UNIFCart;
return 1; return 1;
aborto: aborto:

View File

@ -43,6 +43,7 @@ void BMCGhostbusters63in1_Init(CartInfo *info);
void BMCNTD03_Init(CartInfo *info); void BMCNTD03_Init(CartInfo *info);
void BMCT2271_Init(CartInfo *info); void BMCT2271_Init(CartInfo *info);
void BMCT262_Init(CartInfo *info); void BMCT262_Init(CartInfo *info);
void BMC1024CA1_Init(CartInfo *info);
void CNROM_Init(CartInfo *info); void CNROM_Init(CartInfo *info);
void CPROM_Init(CartInfo *info); void CPROM_Init(CartInfo *info);
void DreamTech01_Init(CartInfo *info); void DreamTech01_Init(CartInfo *info);
@ -122,6 +123,7 @@ void UNLH2288_Init(CartInfo *info);
void UNLKOF97_Init(CartInfo *info); void UNLKOF97_Init(CartInfo *info);
void UNLKS7012_Init(CartInfo *info); void UNLKS7012_Init(CartInfo *info);
void UNLKS7013B_Init(CartInfo *info); void UNLKS7013B_Init(CartInfo *info);
void UNLKS7016_Init(CartInfo *info);
void UNLKS7017_Init(CartInfo *info); void UNLKS7017_Init(CartInfo *info);
void UNLKS7030_Init(CartInfo *info); void UNLKS7030_Init(CartInfo *info);
void UNLKS7031_Init(CartInfo *info); void UNLKS7031_Init(CartInfo *info);
@ -146,6 +148,16 @@ void UNROM512_Init(CartInfo *info);
void UNLSB2000_Init(CartInfo *info); void UNLSB2000_Init(CartInfo *info);
void UNLKS7010_Init(CartInfo *info); void UNLKS7010_Init(CartInfo *info);
void COOLBOY_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 extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM
// bank switcherooing with certain boards... // bank switcherooing with certain boards...

View File

@ -39,11 +39,7 @@ void *FCEU_gmalloc(uint32 size)
FCEU_PrintError("Error allocating memory! Doing a hard exit."); FCEU_PrintError("Error allocating memory! Doing a hard exit.");
exit(1); exit(1);
} }
//mbg 6/17/08 - sometimes this memory is used as RAM or somesuch without clearing first. FCEU_MemoryRand((uint8*)ret,size,true); // initialize according to RAMInitOption, default zero
//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);
return ret; return ret;
} }
@ -57,11 +53,7 @@ void *FCEU_malloc(uint32 size)
FCEU_PrintError("Error allocating memory!"); FCEU_PrintError("Error allocating memory!");
return(0); return(0);
} }
//mbg 6/17/08 - sometimes this memory is used as RAM or somesuch without clearing first. memset(ret,0,size); // initialize to 0
//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);
return ret; return ret;
} }

View File

@ -24,8 +24,8 @@
#define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;} #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_malloc(uint32 size); // initialized to 0
void *FCEU_gmalloc(uint32 size); 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_gfree(void *ptr);
void FCEU_free(void *ptr); void FCEU_free(void *ptr);
void FCEU_memmove(void *d, void *s, uint32 l); void FCEU_memmove(void *d, void *s, uint32 l);

View File

@ -231,8 +231,8 @@ std::string BytesToString(const void* data, int len)
{ {
Base64Table[ input[0] >> 2 ], Base64Table[ input[0] >> 2 ],
Base64Table[ ((input[0] & 0x03) << 4) | (input[1] >> 4) ], Base64Table[ ((input[0] & 0x03) << 4) | (input[1] >> 4) ],
n<2 ? '=' : Base64Table[ ((input[1] & 0x0F) << 2) | (input[2] >> 6) ], static_cast<unsigned char> (n<2 ? '=' : Base64Table[ ((input[1] & 0x0F) << 2) | (input[2] >> 6) ]),
n<3 ? '=' : Base64Table[ input[2] & 0x3F ] static_cast<unsigned char> (n<3 ? '=' : Base64Table[ input[2] & 0x3F ])
}; };
ret.append(output, output+4); ret.append(output, output+4);
} }
@ -296,9 +296,9 @@ bool StringToBytes(const std::string& str, void* data, int len)
} }
unsigned char outpacket[3] = unsigned char outpacket[3] =
{ {
(converted[0] << 2) | (converted[1] >> 4), static_cast<unsigned char>((converted[0] << 2) | (converted[1] >> 4)),
(converted[1] << 4) | (converted[2] >> 2), static_cast<unsigned char>((converted[1] << 4) | (converted[2] >> 2)),
(converted[2] << 6) | (converted[3]) static_cast<unsigned char>((converted[2] << 6) | (converted[3]))
}; };
int outlen = (input[2] == '=') ? 1 : (input[3] == '=' ? 2 : 3); int outlen = (input[2] == '=') ? 1 : (input[3] == '=' ? 2 : 3);
if(outlen > len) outlen = len; if(outlen > len) outlen = len;

View File

@ -26,12 +26,12 @@
//todo - everyone will want to support this eventually, i suppose //todo - everyone will want to support this eventually, i suppose
#ifdef _MSC_VER #ifdef _MSC_VER
#include "svnrev.h" #include "scmrev.h"
#else #else
#ifdef SVN_REV #ifdef SVN_REV
#define SVN_REV_STR SVN_REV #define SCM_REV_STR SCM_REV
#else #else
#define SVN_REV_STR "" #define SCM_REV_STR ""
#endif #endif
#endif #endif
@ -44,7 +44,7 @@
#elif defined(PUBLIC_RELEASE) #elif defined(PUBLIC_RELEASE)
#define FCEU_SUBVERSION_STRING "" #define FCEU_SUBVERSION_STRING ""
#else #else
#define FCEU_SUBVERSION_STRING "-interim svn" SVN_REV_STR #define FCEU_SUBVERSION_STRING "-interim git" SCM_REV_STR
#endif #endif
#if defined(_MSC_VER) #if defined(_MSC_VER)

View File

@ -32,6 +32,7 @@
#include "vsuni.h" #include "vsuni.h"
#include "drawing.h" #include "drawing.h"
#include "driver.h" #include "driver.h"
#ifdef _S9XLUA_H #ifdef _S9XLUA_H
#include "fceulua.h" #include "fceulua.h"
#endif #endif
@ -56,10 +57,17 @@
#include <cstdarg> #include <cstdarg>
#include <zlib.h> #include <zlib.h>
uint8 *XBuf=NULL; //XBuf:
uint8 *XBackBuf=NULL; //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 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 guiMessage;
GUIMESSAGE subtitleMessage; GUIMESSAGE subtitleMessage;
@ -105,12 +113,16 @@ void FCEU_KillVirtualVideo(void)
**/ **/
int FCEU_InitVirtualVideo(void) int FCEU_InitVirtualVideo(void)
{ {
if(!XBuf) /* Some driver code may allocate XBuf externally. */ //Some driver code may allocate XBuf externally.
/* 256 bytes per scanline, * 240 scanline maximum, +16 for alignment, //256 bytes per scanline, * 240 scanline maximum, +16 for alignment,
*/ if(XBuf)
return 1;
if(!(XBuf= (uint8*) (FCEU_malloc(256 * 256 + 16))) || XBuf = (u8*)FCEU_malloc(256 * 256 + 16);
!(XBackBuf= (uint8*) (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; return 0;
} }
@ -124,7 +136,9 @@ int FCEU_InitVirtualVideo(void)
XBuf+=m; XBuf+=m;
} }
memset(XBuf,128,256*256); //*240); memset(XBuf,128,256*256);
memset(XBackBuf,128,256*256);
memset(XBuf,128,256*256);
memset(XBackBuf,128,256*256); memset(XBackBuf,128,256*256);
return 1; return 1;
@ -551,11 +565,14 @@ int GetScreenPixelPalette(int x, int y, bool usebackup) {
int SaveSnapshot(void) int SaveSnapshot(void)
{ {
#ifdef GEKKO
return 0;
#else
int totallines=FSettings.LastSLine-FSettings.FirstSLine+1; int totallines=FSettings.LastSLine-FSettings.FirstSLine+1;
int x,u,y; int x,u,y;
FILE *pp=NULL; FILE *pp=NULL;
uint8 *compmem=NULL; uint8 *compmem=NULL;
uLongf compmemsize=totallines*263+12; uLongf compmemsize=(totallines*263+12)*3;
if(!(compmem=(uint8 *)FCEU_malloc(compmemsize))) if(!(compmem=(uint8 *)FCEU_malloc(compmemsize)))
return 0; 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) if(fwrite(header,8,1,pp)!=1)
goto PNGerr; goto PNGerr;
} }
@ -589,8 +606,8 @@ int SaveSnapshot(void)
chunko[4]=chunko[5]=chunko[6]=0; chunko[4]=chunko[5]=chunko[6]=0;
chunko[7]=totallines; // Height chunko[7]=totallines; // Height
chunko[8]=8; // bit depth chunko[8]=8; // 8 bits per sample(24 bits per pixel)
chunko[9]=3; // Color type; indexed 8-bit chunko[9]=2; // Color type; RGB triplet
chunko[10]=0; // compression: deflate chunko[10]=0; // compression: deflate
chunko[11]=0; // Basic adapative filter set(though none are used). chunko[11]=0; // Basic adapative filter set(though none are used).
chunko[12]=0; // No interlace. chunko[12]=0; // No interlace.
@ -599,19 +616,12 @@ int SaveSnapshot(void)
goto PNGerr; 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 *tmp=XBuf+FSettings.FirstSLine*256;
uint8 *dest,*mal,*mork; 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; goto PNGerr;
// mork=dest=XBuf; // mork=dest=XBuf;
@ -619,11 +629,17 @@ int SaveSnapshot(void)
{ {
*dest=0; // No filter. *dest=0; // No filter.
dest++; dest++;
for(x=256;x;x--,tmp++,dest++) for(x=256;x;x--)
*dest=*tmp; {
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); if(mal) free(mal);
goto PNGerr; goto PNGerr;
@ -647,6 +663,7 @@ PNGerr:
if(pp) if(pp)
fclose(pp); fclose(pp);
return(0); return(0);
#endif
} }
//overloaded SaveSnapshot for "Savesnapshot As" function //overloaded SaveSnapshot for "Savesnapshot As" function

View File

@ -9,6 +9,8 @@ uint32 GetScreenPixel(int x, int y, bool usebackup);
int GetScreenPixelPalette(int x, int y, bool usebackup); int GetScreenPixelPalette(int x, int y, bool usebackup);
extern uint8 *XBuf; extern uint8 *XBuf;
extern uint8 *XBackBuf; extern uint8 *XBackBuf;
extern uint8 *XDBuf;
extern uint8 *XDBackBuf;
extern int ClipSidesOffset; extern int ClipSidesOffset;
extern struct GUIMESSAGE extern struct GUIMESSAGE
{ {

View File

@ -301,7 +301,7 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring) {
while (vs->name) { while (vs->name) {
if (md5partial == vs->md5partial) { if (md5partial == vs->md5partial) {
if (vs->ppu < RCP2C03B) pale = vs->ppu; if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu;
*MapperNo = vs->mapper; *MapperNo = vs->mapper;
*Mirroring = vs->mirroring; *Mirroring = vs->mirroring;
GameInfo->type = GIT_VSUNI; GameInfo->type = GIT_VSUNI;

View File

@ -32,6 +32,7 @@
#include <cstring> #include <cstring>
X6502 X; X6502 X;
uint32 timestamp; uint32 timestamp;
uint32 soundtimestamp;
void (*MapIRQHook)(int a); void (*MapIRQHook)(int a);
#define ADDCYC(x) \ #define ADDCYC(x) \
@ -40,6 +41,7 @@ void (*MapIRQHook)(int a);
_tcount+=__x; \ _tcount+=__x; \
_count-=__x*48; \ _count-=__x*48; \
timestamp+=__x; \ timestamp+=__x; \
if(!overclocking) soundtimestamp+=__x; \
} }
//normal memory read //normal memory read
@ -404,12 +406,14 @@ void X6502_Init(void)
} }
} }
extern int StackAddrBackup;
void X6502_Power(void) void X6502_Power(void)
{ {
_count=_tcount=_IRQlow=_PC=_A=_X=_Y=_P=_PI=_DB=_jammed=0; _count=_tcount=_IRQlow=_PC=_A=_X=_Y=_P=_PI=_DB=_jammed=0;
_S=0xFD; _S=0xFD;
timestamp=0; timestamp=soundtimestamp=0;
X6502_Reset(); X6502_Reset();
StackAddrBackup = -1;
} }
void X6502_Run(int32 cycles) void X6502_Run(int32 cycles)
@ -493,6 +497,8 @@ extern int test; test++;
temp=_tcount; temp=_tcount;
_tcount=0; _tcount=0;
if(MapIRQHook) MapIRQHook(temp); if(MapIRQHook) MapIRQHook(temp);
if (!overclocking)
FCEU_SoundCPUHook(temp); FCEU_SoundCPUHook(temp);
#ifdef _S9XLUA_H #ifdef _S9XLUA_H
CallRegisteredLuaMemHook(_PC, 1, 0, LUAMEMHOOK_EXEC); CallRegisteredLuaMemHook(_PC, 1, 0, LUAMEMHOOK_EXEC);
@ -569,20 +575,58 @@ const uint8 opsize[256] = {
// 8 = Zero Page,Y // 8 = Zero Page,Y
// //
const uint8 optype[256] = { const uint8 optype[256] = {
/*0x00*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0, /*0x00*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0x10*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, /*0x10*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
/*0x20*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, /*0x20*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0x30*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, /*0x30*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
/*0x40*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0, /*0x40*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0x50*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, /*0x50*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
/*0x60*/ 0,1,0,0,0,2,2,0,0,0,0,0,3,3,3,0, /*0x60*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0x70*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, /*0x70*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
/*0x80*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, /*0x80*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0x90*/ 0,4,0,0,5,5,8,0,0,6,0,0,0,7,0,0, /*0x90*/ 0,4,0,3,5,5,8,8,0,6,0,6,7,7,6,6,
/*0xA0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, /*0xA0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0xB0*/ 0,4,0,0,5,5,8,0,0,6,0,0,7,7,6,0, /*0xB0*/ 0,4,0,3,5,5,8,8,0,6,0,6,7,7,6,6,
/*0xC0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, /*0xC0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0xD0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0, /*0xD0*/ 0,4,0,3,5,5,5,5,0,6,0,6,7,7,7,7,
/*0xE0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0, /*0xE0*/ 0,1,0,1,2,2,2,2,0,0,0,0,3,3,3,3,
/*0xF0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0 /*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,
}; };

View File

@ -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 //the optype table is a quick way to grab the addressing mode for any 6502 opcode
extern const uint8 optype[256]; 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 //mbg 6/30/06 - some of this was removed to mimic XD
//#ifdef FCEUDEF_DEBUGGER //#ifdef FCEUDEF_DEBUGGER
@ -47,8 +50,8 @@ void X6502_RunDebug(int32 cycles);
//------------ //------------
extern uint32 timestamp; extern uint32 timestamp;
extern uint32 soundtimestamp;
extern int scanline;
#define N_FLAG 0x80 #define N_FLAG 0x80
#define V_FLAG 0x40 #define V_FLAG 0x40

View File

@ -18,6 +18,10 @@
#include "menu.h" #include "menu.h"
bool turbo = false; bool turbo = false;
bool paldeemphswap = 0;
int dendy;
bool swapDuty;
int KillFCEUXonFrame = 0;
/** /**
* Closes a game. Frees memory, and deinitializes the drivers. * 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 FCEUI_UseInputPreset(int preset) { }
void FCEUD_SoundVolumeAdjust(int n) { } void FCEUD_SoundVolumeAdjust(int n) { }
void FCEUD_SetEmulationSpeed(int cmd) { } void FCEUD_SetEmulationSpeed(int cmd) { }
void GetMouseData(uint32 (&d)[3]) { }