update to FCEUX 2.6.6+ (git 2b8f6e7)

This commit is contained in:
Daryl Borth 2025-03-23 14:17:12 -06:00
parent b96d133042
commit 911f8906cf
108 changed files with 5968 additions and 2125 deletions

View File

@ -49,7 +49,7 @@ Wii/GameCube.
* Artwork (artwork, cover or screenshot) support
* Famicom 3D System support
* IPS/UPS automatic patching support
* NES Compatibility Based on FCEUX 2.6.4+ (git def5768)
* NES Compatibility Based on FCEUX 2.6.6+ (git 2b8f6e7)
* Open Source!
@ -57,6 +57,7 @@ Wii/GameCube.
[3.5.5]
* Updated to the latest FCEUX 2.6.6+ (git 2b8f6e7)
* Compiled with latest devkitPPC/libogc2
* Added Digital Prime (FBX) palette

View File

@ -74,29 +74,30 @@ static int LoadCheats (int length)
if(doc)
{
char *neo=&tbuf[4+2+2+1+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x%*[:]%02x",&addr,&val,&compare)!=3)
char *neo = &tbuf[4+2+2+1+1+1];
if(sscanf(tbuf, "%04x%*[:]%02x%*[:]%02x", &addr, &val, &compare) != 3)
continue;
namebuf=(char *)malloc(strlen(neo)+1);
strcpy(namebuf,neo);
strcpy(namebuf, neo);
}
else
{
char *neo=&tbuf[4+2+1+1];
if(sscanf(tbuf,"%04x%*[:]%02x",&addr,&val)!=2)
char *neo = &tbuf[4+2+1+1];
if(sscanf(tbuf, "%04x%*[:]%02x", &addr, &val) != 2)
continue;
namebuf=(char *)malloc(strlen(neo)+1);
strcpy(namebuf,neo);
strcpy(namebuf, neo);
}
for(x=0;x<(int)strlen(namebuf);x++)
for(x = 0; x < (int)strlen(namebuf); x++)
{
if(namebuf[x]==10 || namebuf[x]==13)
if(namebuf[x] == 10 || namebuf[x] == 13)
{
namebuf[x]=0;
namebuf[x] = 0;
break;
}
else if(namebuf[x]<0x20) namebuf[x]=' ';
else if(namebuf[x] > 0x00 && namebuf[x] < 0x20)
namebuf[x] = 0x20;
}
AddCheatEntry(namebuf,addr,val,doc?compare:-1,status,type);

View File

@ -79,6 +79,7 @@ char appPath[1024] = { 0 };
int frameskip = 0;
int turbomode = 0;
unsigned char * nesrom = NULL;
int eoptions=0;
/****************************************************************************
* Shutdown / Reboot / Exit

View File

@ -1,529 +0,0 @@
/// \file
/// \brief 6502 assembler and disassembler
#include "types.h"
#include "utils/xstring.h"
#include "debug.h"
#include "asm.h"
#include "x6502.h"
#include <cstring>
#include <cstdlib>
#include <cstdio>
///assembles the string to an instruction located at addr, storing opcodes in output buffer
int Assemble(unsigned char *output, int addr, char *str) {
//unsigned char opcode[3] = { 0,0,0 };
output[0] = output[1] = output[2] = 0;
char astr[128],ins[4];
int len = strlen(str);
if ((!len) || (len > 127)) return 1;
strcpy(astr,str);
str_ucase(astr);
sscanf(astr,"%3s",ins); //get instruction
if (strlen(ins) != 3) return 1;
strcpy(astr,strstr(astr,ins)+3); //heheh, this is probably a bad idea, but let's do it anyway!
if ((astr[0] != ' ') && (astr[0] != 0)) return 1;
//remove all whitespace
str_strip(astr,STRIP_SP|STRIP_TAB|STRIP_CR|STRIP_LF);
//repair syntax
chr_replace(astr,'[','('); //brackets
chr_replace(astr,']',')');
chr_replace(astr,'{','(');
chr_replace(astr,'}',')');
chr_replace(astr,';',0); //comments
str_replace(astr,"0X","$"); //miscellaneous
//This does the following:
// 1) Sets opcode[0] on success, else returns 1.
// 2) Parses text in *astr to build the rest of the assembled
// data in 'opcode', else returns 1 on error.
if (!strlen(astr)) {
//Implied instructions
if (!strcmp(ins,"BRK")) output[0] = 0x00;
else if (!strcmp(ins,"PHP")) output[0] = 0x08;
else if (!strcmp(ins,"ASL")) output[0] = 0x0A;
else if (!strcmp(ins,"CLC")) output[0] = 0x18;
else if (!strcmp(ins,"PLP")) output[0] = 0x28;
else if (!strcmp(ins,"ROL")) output[0] = 0x2A;
else if (!strcmp(ins,"SEC")) output[0] = 0x38;
else if (!strcmp(ins,"RTI")) output[0] = 0x40;
else if (!strcmp(ins,"PHA")) output[0] = 0x48;
else if (!strcmp(ins,"LSR")) output[0] = 0x4A;
else if (!strcmp(ins,"CLI")) output[0] = 0x58;
else if (!strcmp(ins,"RTS")) output[0] = 0x60;
else if (!strcmp(ins,"PLA")) output[0] = 0x68;
else if (!strcmp(ins,"ROR")) output[0] = 0x6A;
else if (!strcmp(ins,"SEI")) output[0] = 0x78;
else if (!strcmp(ins,"DEY")) output[0] = 0x88;
else if (!strcmp(ins,"TXA")) output[0] = 0x8A;
else if (!strcmp(ins,"TYA")) output[0] = 0x98;
else if (!strcmp(ins,"TXS")) output[0] = 0x9A;
else if (!strcmp(ins,"TAY")) output[0] = 0xA8;
else if (!strcmp(ins,"TAX")) output[0] = 0xAA;
else if (!strcmp(ins,"CLV")) output[0] = 0xB8;
else if (!strcmp(ins,"TSX")) output[0] = 0xBA;
else if (!strcmp(ins,"INY")) output[0] = 0xC8;
else if (!strcmp(ins,"DEX")) output[0] = 0xCA;
else if (!strcmp(ins,"CLD")) output[0] = 0xD8;
else if (!strcmp(ins,"INX")) output[0] = 0xE8;
else if (!strcmp(ins,"NOP")) output[0] = 0xEA;
else if (!strcmp(ins,"SED")) output[0] = 0xF8;
else return 1;
}
else {
//Instructions with Operands
if (!strcmp(ins,"ORA")) output[0] = 0x01;
else if (!strcmp(ins,"ASL")) output[0] = 0x06;
else if (!strcmp(ins,"BPL")) output[0] = 0x10;
else if (!strcmp(ins,"JSR")) output[0] = 0x20;
else if (!strcmp(ins,"AND")) output[0] = 0x21;
else if (!strcmp(ins,"BIT")) output[0] = 0x24;
else if (!strcmp(ins,"ROL")) output[0] = 0x26;
else if (!strcmp(ins,"BMI")) output[0] = 0x30;
else if (!strcmp(ins,"EOR")) output[0] = 0x41;
else if (!strcmp(ins,"LSR")) output[0] = 0x46;
else if (!strcmp(ins,"JMP")) output[0] = 0x4C;
else if (!strcmp(ins,"BVC")) output[0] = 0x50;
else if (!strcmp(ins,"ADC")) output[0] = 0x61;
else if (!strcmp(ins,"ROR")) output[0] = 0x66;
else if (!strcmp(ins,"BVS")) output[0] = 0x70;
else if (!strcmp(ins,"STA")) output[0] = 0x81;
else if (!strcmp(ins,"STY")) output[0] = 0x84;
else if (!strcmp(ins,"STX")) output[0] = 0x86;
else if (!strcmp(ins,"BCC")) output[0] = 0x90;
else if (!strcmp(ins,"LDY")) output[0] = 0xA0;
else if (!strcmp(ins,"LDA")) output[0] = 0xA1;
else if (!strcmp(ins,"LDX")) output[0] = 0xA2;
else if (!strcmp(ins,"BCS")) output[0] = 0xB0;
else if (!strcmp(ins,"CPY")) output[0] = 0xC0;
else if (!strcmp(ins,"CMP")) output[0] = 0xC1;
else if (!strcmp(ins,"DEC")) output[0] = 0xC6;
else if (!strcmp(ins,"BNE")) output[0] = 0xD0;
else if (!strcmp(ins,"CPX")) output[0] = 0xE0;
else if (!strcmp(ins,"SBC")) output[0] = 0xE1;
else if (!strcmp(ins,"INC")) output[0] = 0xE6;
else if (!strcmp(ins,"BEQ")) output[0] = 0xF0;
else return 1;
{
//Parse Operands
// It's not the sexiest thing ever, but it works well enough!
//TODO:
// Add branches.
// Fix certain instructions. (Setting bits is not 100% perfect.)
// Fix instruction/operand matching. (Instructions like "jmp ($94),Y" are no good!)
// Optimizations?
int tmpint;
char tmpchr,tmpstr[20];
if (sscanf(astr,"#$%2X%c",&tmpint,&tmpchr) == 1) { //#Immediate
switch (output[0]) {
case 0x20: case 0x4C: //Jumps
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
case 0x90: case 0xB0: case 0xD0: case 0xF0:
case 0x06: case 0x24: case 0x26: case 0x46: //Other instructions incapable of #Immediate
case 0x66: case 0x81: case 0x84: case 0x86:
case 0xC6: case 0xE6:
return 1;
default:
//cheap hack for certain instructions
switch (output[0]) {
case 0xA0: case 0xA2: case 0xC0: case 0xE0:
break;
default:
output[0] |= 0x08;
break;
}
output[1] = tmpint;
break;
}
}
else if (sscanf(astr,"$%4X%c",&tmpint,&tmpchr) == 1) { //Absolute, Zero Page, Branch, or Jump
switch (output[0]) {
case 0x20: case 0x4C: //Jumps
output[1] = (tmpint & 0xFF);
output[2] = (tmpint >> 8);
break;
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
case 0x90: case 0xB0: case 0xD0: case 0xF0:
tmpint -= (addr+2);
if ((tmpint < -128) || (tmpint > 127)) return 1;
output[1] = (tmpint & 0xFF);
break;
//return 1; //FIX ME
default:
if (tmpint > 0xFF) { //Absolute
output[0] |= 0x0C;
output[1] = (tmpint & 0xFF);
output[2] = (tmpint >> 8);
}
else { //Zero Page
output[0] |= 0x04;
output[1] = (tmpint & 0xFF);
}
break;
}
}
else if (sscanf(astr,"$%4X%s",&tmpint,tmpstr) == 2) { //Absolute,X, Zero Page,X, Absolute,Y or Zero Page,Y
if (!strcmp(tmpstr,",X")) { //Absolute,X or Zero Page,X
switch (output[0]) {
case 0x20: case 0x4C: //Jumps
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
case 0x90: case 0xB0: case 0xD0: case 0xF0:
case 0x24: case 0x86: case 0xA2: case 0xC0: //Other instructions incapable of Absolute,X or Zero Page,X
case 0xE0:
return 1;
default:
if (tmpint > 0xFF) { //Absolute
if (output[0] == 0x84) return 1; //No STY Absolute,X!
output[0] |= 0x1C;
output[1] = (tmpint & 0xFF);
output[2] = (tmpint >> 8);
}
else { //Zero Page
output[0] |= 0x14;
output[1] = (tmpint & 0xFF);
}
break;
}
}
else if (!strcmp(tmpstr,",Y")) { //Absolute,Y or Zero Page,Y
switch (output[0]) {
case 0x20: case 0x4C: //Jumps
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
case 0x90: case 0xB0: case 0xD0: case 0xF0:
case 0x06: case 0x24: case 0x26: case 0x46: //Other instructions incapable of Absolute,Y or Zero Page,Y
case 0x66: case 0x84: case 0x86: case 0xA0:
case 0xC0: case 0xC6: case 0xE0: case 0xE6:
return 1;
case 0xA2: //cheap hack for LDX
output[0] |= 0x04;
default:
if (tmpint > 0xFF) { //Absolute
if (output[0] == 0x86) return 1; //No STX Absolute,Y!
output[0] |= 0x18;
output[1] = (tmpint & 0xFF);
output[2] = (tmpint >> 8);
}
else { //Zero Page
if ((output[0] != 0x86) && (output[0] != 0xA2)) return 1; //only STX and LDX Absolute,Y!
output[0] |= 0x10;
output[1] = (tmpint & 0xFF);
}
break;
}
}
else return 1;
}
else if (sscanf(astr,"($%4X%s",&tmpint,tmpstr) == 2) { //Jump (Indirect), (Indirect,X) or (Indirect),Y
switch (output[0]) {
case 0x20: //Jumps
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
case 0x90: case 0xB0: case 0xD0: case 0xF0:
case 0x06: case 0x24: case 0x26: case 0x46: //Other instructions incapable of Jump (Indirect), (Indirect,X) or (Indirect),Y
case 0x66: case 0x84: case 0x86: case 0xA0:
case 0xA2: case 0xC0: case 0xC6: case 0xE0:
case 0xE6:
return 1;
default:
if ((!strcmp(tmpstr,")")) && (output[0] == 0x4C)) { //Jump (Indirect)
output[0] = 0x6C;
output[1] = (tmpint & 0xFF);
output[2] = (tmpint >> 8);
}
else if ((!strcmp(tmpstr,",X)")) && (tmpint <= 0xFF) && (output[0] != 0x4C)) { //(Indirect,X)
output[1] = (tmpint & 0xFF);
}
else if ((!strcmp(tmpstr,"),Y")) && (tmpint <= 0xFF) && (output[0] != 0x4C)) { //(Indirect),Y
output[0] |= 0x10;
output[1] = (tmpint & 0xFF);
}
else return 1;
break;
}
}
else return 1;
}
}
return 0;
}
///disassembles the opcodes in the buffer assuming the provided address. Uses GetMem() and 6502 current registers to query referenced values. returns a static string buffer.
char *Disassemble(int addr, uint8 *opcode) {
static char str[64]={0},chr[5]={0};
uint16 tmp,tmp2;
//these may be replaced later with passed-in values to make a lighter-weight disassembly mode that may not query the referenced values
#define RX (X.X)
#define RY (X.Y)
switch (opcode[0]) {
#define relative(a) { \
if (((a)=opcode[1])&0x80) (a) = addr-(((a)-1)^0xFF); \
else (a)+=addr; \
}
#define absolute(a) { \
(a) = opcode[1] | opcode[2]<<8; \
}
#define zpIndex(a,i) { \
(a) = (opcode[1]+(i))&0xFF; \
}
#define indirectX(a) { \
(a) = (opcode[1]+RX)&0xFF; \
(a) = GetMem((a)) | (GetMem(((a)+1)&0xff))<<8; \
}
#define indirectY(a) { \
(a) = GetMem(opcode[1]) | (GetMem((opcode[1]+1)&0xff))<<8; \
(a) += RY; \
}
#ifdef BRK_3BYTE_HACK
case 0x00:
sprintf(str,"BRK %02X %02X", opcode[1], opcode[2]);
break;
#else
case 0x00: strcpy(str,"BRK"); break;
#endif
//odd, 1-byte opcodes
case 0x08: strcpy(str,"PHP"); break;
case 0x0A: strcpy(str,"ASL"); break;
case 0x18: strcpy(str,"CLC"); break;
case 0x28: strcpy(str,"PLP"); break;
case 0x2A: strcpy(str,"ROL"); break;
case 0x38: strcpy(str,"SEC"); break;
case 0x40: strcpy(str,"RTI"); break;
case 0x48: strcpy(str,"PHA"); break;
case 0x4A: strcpy(str,"LSR"); break;
case 0x58: strcpy(str,"CLI"); break;
case 0x60: strcpy(str,"RTS"); break;
case 0x68: strcpy(str,"PLA"); break;
case 0x6A: strcpy(str,"ROR"); break;
case 0x78: strcpy(str,"SEI"); break;
case 0x88: strcpy(str,"DEY"); break;
case 0x8A: strcpy(str,"TXA"); break;
case 0x98: strcpy(str,"TYA"); break;
case 0x9A: strcpy(str,"TXS"); break;
case 0xA8: strcpy(str,"TAY"); break;
case 0xAA: strcpy(str,"TAX"); break;
case 0xB8: strcpy(str,"CLV"); break;
case 0xBA: strcpy(str,"TSX"); break;
case 0xC8: strcpy(str,"INY"); break;
case 0xCA: strcpy(str,"DEX"); break;
case 0xD8: strcpy(str,"CLD"); break;
case 0xE8: strcpy(str,"INX"); break;
case 0xEA: strcpy(str,"NOP"); break;
case 0xF8: strcpy(str,"SED"); break;
//(Indirect,X)
case 0x01: strcpy(chr,"ORA"); goto _indirectx;
case 0x21: strcpy(chr,"AND"); goto _indirectx;
case 0x41: strcpy(chr,"EOR"); goto _indirectx;
case 0x61: strcpy(chr,"ADC"); goto _indirectx;
case 0x81: strcpy(chr,"STA"); goto _indirectx;
case 0xA1: strcpy(chr,"LDA"); goto _indirectx;
case 0xC1: strcpy(chr,"CMP"); goto _indirectx;
case 0xE1: strcpy(chr,"SBC"); goto _indirectx;
_indirectx:
indirectX(tmp);
sprintf(str,"%s ($%02X,X) @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
break;
//Zero Page
case 0x05: strcpy(chr,"ORA"); goto _zeropage;
case 0x06: strcpy(chr,"ASL"); goto _zeropage;
case 0x24: strcpy(chr,"BIT"); goto _zeropage;
case 0x25: strcpy(chr,"AND"); goto _zeropage;
case 0x26: strcpy(chr,"ROL"); goto _zeropage;
case 0x45: strcpy(chr,"EOR"); goto _zeropage;
case 0x46: strcpy(chr,"LSR"); goto _zeropage;
case 0x65: strcpy(chr,"ADC"); goto _zeropage;
case 0x66: strcpy(chr,"ROR"); goto _zeropage;
case 0x84: strcpy(chr,"STY"); goto _zeropage;
case 0x85: strcpy(chr,"STA"); goto _zeropage;
case 0x86: strcpy(chr,"STX"); goto _zeropage;
case 0xA4: strcpy(chr,"LDY"); goto _zeropage;
case 0xA5: strcpy(chr,"LDA"); goto _zeropage;
case 0xA6: strcpy(chr,"LDX"); goto _zeropage;
case 0xC4: strcpy(chr,"CPY"); goto _zeropage;
case 0xC5: strcpy(chr,"CMP"); goto _zeropage;
case 0xC6: strcpy(chr,"DEC"); goto _zeropage;
case 0xE4: strcpy(chr,"CPX"); goto _zeropage;
case 0xE5: strcpy(chr,"SBC"); goto _zeropage;
case 0xE6: strcpy(chr,"INC"); goto _zeropage;
_zeropage:
// ################################## Start of SP CODE ###########################
// Change width to %04X // don't!
sprintf(str,"%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
// ################################## End of SP CODE ###########################
break;
//#Immediate
case 0x09: strcpy(chr,"ORA"); goto _immediate;
case 0x29: strcpy(chr,"AND"); goto _immediate;
case 0x49: strcpy(chr,"EOR"); goto _immediate;
case 0x69: strcpy(chr,"ADC"); goto _immediate;
//case 0x89: strcpy(chr,"STA"); goto _immediate; //baka, no STA #imm!!
case 0xA0: strcpy(chr,"LDY"); goto _immediate;
case 0xA2: strcpy(chr,"LDX"); goto _immediate;
case 0xA9: strcpy(chr,"LDA"); goto _immediate;
case 0xC0: strcpy(chr,"CPY"); goto _immediate;
case 0xC9: strcpy(chr,"CMP"); goto _immediate;
case 0xE0: strcpy(chr,"CPX"); goto _immediate;
case 0xE9: strcpy(chr,"SBC"); goto _immediate;
_immediate:
sprintf(str,"%s #$%02X", chr,opcode[1]);
break;
//Absolute
case 0x0D: strcpy(chr,"ORA"); goto _absolute;
case 0x0E: strcpy(chr,"ASL"); goto _absolute;
case 0x2C: strcpy(chr,"BIT"); goto _absolute;
case 0x2D: strcpy(chr,"AND"); goto _absolute;
case 0x2E: strcpy(chr,"ROL"); goto _absolute;
case 0x4D: strcpy(chr,"EOR"); goto _absolute;
case 0x4E: strcpy(chr,"LSR"); goto _absolute;
case 0x6D: strcpy(chr,"ADC"); goto _absolute;
case 0x6E: strcpy(chr,"ROR"); goto _absolute;
case 0x8C: strcpy(chr,"STY"); goto _absolute;
case 0x8D: strcpy(chr,"STA"); goto _absolute;
case 0x8E: strcpy(chr,"STX"); goto _absolute;
case 0xAC: strcpy(chr,"LDY"); goto _absolute;
case 0xAD: strcpy(chr,"LDA"); goto _absolute;
case 0xAE: strcpy(chr,"LDX"); goto _absolute;
case 0xCC: strcpy(chr,"CPY"); goto _absolute;
case 0xCD: strcpy(chr,"CMP"); goto _absolute;
case 0xCE: strcpy(chr,"DEC"); goto _absolute;
case 0xEC: strcpy(chr,"CPX"); goto _absolute;
case 0xED: strcpy(chr,"SBC"); goto _absolute;
case 0xEE: strcpy(chr,"INC"); goto _absolute;
_absolute:
absolute(tmp);
sprintf(str,"%s $%04X = #$%02X", chr,tmp,GetMem(tmp));
break;
//branches
case 0x10: strcpy(chr,"BPL"); goto _branch;
case 0x30: strcpy(chr,"BMI"); goto _branch;
case 0x50: strcpy(chr,"BVC"); goto _branch;
case 0x70: strcpy(chr,"BVS"); goto _branch;
case 0x90: strcpy(chr,"BCC"); goto _branch;
case 0xB0: strcpy(chr,"BCS"); goto _branch;
case 0xD0: strcpy(chr,"BNE"); goto _branch;
case 0xF0: strcpy(chr,"BEQ"); goto _branch;
_branch:
relative(tmp);
sprintf(str,"%s $%04X", chr,tmp);
break;
//(Indirect),Y
case 0x11: strcpy(chr,"ORA"); goto _indirecty;
case 0x31: strcpy(chr,"AND"); goto _indirecty;
case 0x51: strcpy(chr,"EOR"); goto _indirecty;
case 0x71: strcpy(chr,"ADC"); goto _indirecty;
case 0x91: strcpy(chr,"STA"); goto _indirecty;
case 0xB1: strcpy(chr,"LDA"); goto _indirecty;
case 0xD1: strcpy(chr,"CMP"); goto _indirecty;
case 0xF1: strcpy(chr,"SBC"); goto _indirecty;
_indirecty:
indirectY(tmp);
sprintf(str,"%s ($%02X),Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
break;
//Zero Page,X
case 0x15: strcpy(chr,"ORA"); goto _zeropagex;
case 0x16: strcpy(chr,"ASL"); goto _zeropagex;
case 0x35: strcpy(chr,"AND"); goto _zeropagex;
case 0x36: strcpy(chr,"ROL"); goto _zeropagex;
case 0x55: strcpy(chr,"EOR"); goto _zeropagex;
case 0x56: strcpy(chr,"LSR"); goto _zeropagex;
case 0x75: strcpy(chr,"ADC"); goto _zeropagex;
case 0x76: strcpy(chr,"ROR"); goto _zeropagex;
case 0x94: strcpy(chr,"STY"); goto _zeropagex;
case 0x95: strcpy(chr,"STA"); goto _zeropagex;
case 0xB4: strcpy(chr,"LDY"); goto _zeropagex;
case 0xB5: strcpy(chr,"LDA"); goto _zeropagex;
case 0xD5: strcpy(chr,"CMP"); goto _zeropagex;
case 0xD6: strcpy(chr,"DEC"); goto _zeropagex;
case 0xF5: strcpy(chr,"SBC"); goto _zeropagex;
case 0xF6: strcpy(chr,"INC"); goto _zeropagex;
_zeropagex:
zpIndex(tmp,RX);
// ################################## Start of SP CODE ###########################
// Change width to %04X // don't!
sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
//Absolute,Y
case 0x19: strcpy(chr,"ORA"); goto _absolutey;
case 0x39: strcpy(chr,"AND"); goto _absolutey;
case 0x59: strcpy(chr,"EOR"); goto _absolutey;
case 0x79: strcpy(chr,"ADC"); goto _absolutey;
case 0x99: strcpy(chr,"STA"); goto _absolutey;
case 0xB9: strcpy(chr,"LDA"); goto _absolutey;
case 0xBE: strcpy(chr,"LDX"); goto _absolutey;
case 0xD9: strcpy(chr,"CMP"); goto _absolutey;
case 0xF9: strcpy(chr,"SBC"); goto _absolutey;
_absolutey:
absolute(tmp);
tmp2=(tmp+RY);
sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2));
break;
//Absolute,X
case 0x1D: strcpy(chr,"ORA"); goto _absolutex;
case 0x1E: strcpy(chr,"ASL"); goto _absolutex;
case 0x3D: strcpy(chr,"AND"); goto _absolutex;
case 0x3E: strcpy(chr,"ROL"); goto _absolutex;
case 0x5D: strcpy(chr,"EOR"); goto _absolutex;
case 0x5E: strcpy(chr,"LSR"); goto _absolutex;
case 0x7D: strcpy(chr,"ADC"); goto _absolutex;
case 0x7E: strcpy(chr,"ROR"); goto _absolutex;
case 0x9D: strcpy(chr,"STA"); goto _absolutex;
case 0xBC: strcpy(chr,"LDY"); goto _absolutex;
case 0xBD: strcpy(chr,"LDA"); goto _absolutex;
case 0xDD: strcpy(chr,"CMP"); goto _absolutex;
case 0xDE: strcpy(chr,"DEC"); goto _absolutex;
case 0xFD: strcpy(chr,"SBC"); goto _absolutex;
case 0xFE: strcpy(chr,"INC"); goto _absolutex;
_absolutex:
absolute(tmp);
tmp2=(tmp+RX);
sprintf(str,"%s $%04X,X @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2));
break;
//jumps
case 0x20: strcpy(chr,"JSR"); goto _jump;
case 0x4C: strcpy(chr,"JMP"); goto _jump;
case 0x6C: absolute(tmp); sprintf(str,"JMP ($%04X) = $%04X", tmp,GetMem(tmp)|GetMem(tmp+1)<<8); break;
_jump:
absolute(tmp);
sprintf(str,"%s $%04X", chr,tmp);
break;
//Zero Page,Y
case 0x96: strcpy(chr,"STX"); goto _zeropagey;
case 0xB6: strcpy(chr,"LDX"); goto _zeropagey;
_zeropagey:
zpIndex(tmp,RY);
// ################################## Start of SP CODE ###########################
// Change width to %04X // don't!
sprintf(str,"%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
// ################################## End of SP CODE ###########################
break;
//UNDEFINED
default: strcpy(str,"ERROR"); break;
}
return str;
}

View File

@ -1,2 +0,0 @@
int Assemble(unsigned char *output, int addr, char *str);
char *Disassemble(int addr, uint8 *opcode);

View File

@ -48,7 +48,7 @@ static void M121CW(uint32 A, uint8 V) {
if (PRGsize[0] == CHRsize[0]) { // A9713 multigame extension hack!
setchr1(A, V | ((EXPREGS[3] & 0x80) << 1));
} else {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);

View File

@ -24,7 +24,7 @@
static uint16 latchea;
static uint8 latched;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
{ &latchea, 2, "AREG" },
@ -108,8 +108,7 @@ void Mapper15_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2012 CaH4e3
* Copyright (C) 2024 negativeExponent
*
* 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
@ -18,42 +18,48 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* NES 2.0 Mapper 471 denotes the Impact Soft IM1 circuit board, used for
* Haratyler (without HG or MP) and Haraforce. It is basically INES Mapper 201
* with the addition of a scanline IRQ.*/
#include "mapinc.h"
static uint8 regs[8];
static uint32 latch;
static SFORMAT StateRegs[] =
{
{ regs, 8, "REGS" },
{ 0 }
};
static void Sync(void) {
setprg8(0x8000, regs[0]);
setprg8(0xA000, regs[2]);
setprg8(0xC000, regs[4]);
setprg8(0xE000, ~0);
setchr4(0x0000, regs[6]);
setchr4(0x1000, regs[7]);
static void Sync() {
setprg32(0x8000, latch);
setchr8(latch);
}
static DECLFW(M151Write) {
regs[(A >> 12) & 7] = V;
static DECLFW(Write) {
X6502_IRQEnd(FCEU_IQEXT);
latch = A;
Sync();
}
static void M151Power(void) {
static void Reset() {
latch = 0;
Sync();
}
static void Power() {
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M151Write);
SetWriteHandler(0x8000, 0xFFFF, Write);
Reset();
}
static void StateRestore(int version) {
Sync();
}
void Mapper151_Init(CartInfo *info) {
info->Power = M151Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
static void HBHook() {
X6502_IRQBegin(FCEU_IQEXT);
}
void Mapper471_Init(CartInfo *info) {
info->Power = Power;
info->Reset = Reset;
GameHBIRQHook = HBHook;
GameStateRestore = StateRestore;
AddExState(&latch, sizeof(latch), 0, "LATC");
}

View File

@ -27,7 +27,7 @@
static uint8 laststrobe, trigger;
static uint8 reg[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static writefunc pcmwrite;
@ -123,8 +123,7 @@ void Mapper164_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
@ -172,8 +171,7 @@ void Mapper163_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
@ -223,8 +221,7 @@ void UNLFS304_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;

View File

@ -23,7 +23,7 @@
static uint8 reg;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -73,8 +73,7 @@ void Mapper177_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -27,7 +27,7 @@
static uint8 reg[4];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
// Tennis with VR sensor, very simple behaviour
extern void GetMouseData(uint32 (&md)[3]);
@ -192,8 +192,7 @@ void Mapper178_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");

View File

@ -16,6 +16,9 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* The Moero!! Pro Yakyuu series have an ADPCM chip with internal ROM,
* used for voice samples (not dumped, so emulation isn't possible)
*/
#include "mapinc.h"
@ -24,7 +27,7 @@ static uint8 preg[4], creg[8];
static uint8 IRQa, mirr;
static int32 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -125,8 +128,7 @@ void Mapper18_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -22,7 +22,7 @@
#include "mmc3.h"
static void M187CW(uint32 A, uint8 V) {
if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
setchr1(A, V | 0x100);
else
setchr1(A, V);

View File

@ -1,38 +0,0 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2020
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
#include "../ines.h"
static uint8 mirror;
static uint8 mask;
static void M218Power(void) {
setchr8(0);
setprg32(0x8000, 0);
SetReadHandler(0x8000, 0xFFFF, CartBR);
}
void Mapper218_Init(CartInfo* info) {
if (head.ROM_type & 0x08)
SetupCartMirroring(MI_0 + (head.ROM_type & 0x01), 1, NULL);
SetupCartCHRMapping(0, NTARAM, 2048, 1);
info->Power = M218Power;
}

View File

@ -1,30 +1,40 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
*
* Copyright notice for this file:
* Copyright (C) 2011 CaH4e3
* Copyright (C) 2019 Libretro Team
* Copyright (C) 2020
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* PCB-018 board, discrete multigame cart 110-in-1
*
* Mapper 225
* Mapper 255
*
*/
/* 2020-2-20 - merge mapper 255, re-implement extra RAM */
#include "mapinc.h"
static uint8 prot[4], prg, mode, chr, mirr;
static uint8 extraRAM[4], prg, mode, chr, mirr;
static SFORMAT StateRegs[] =
{
{ prot, 4, "PROT" },
{ extraRAM, 4, "PROT" },
{ &prg, 1, "PRG" },
{ &chr, 1, "CHR" },
{ &mode, 1, "MODE" },
@ -36,14 +46,15 @@ static void Sync(void) {
if (mode) {
setprg16(0x8000, prg);
setprg16(0xC000, prg);
} else
}
else
setprg32(0x8000, prg >> 1);
setchr8(chr);
setmirror(mirr ^ 1);
}
static DECLFW(M225Write) {
uint32 bank = (A >> 14) & 1;
uint8 bank = (A >> 14) & 1;
mirr = (A >> 13) & 1;
mode = (A >> 12) & 1;
chr = (A & 0x3f) | (bank << 6);
@ -52,35 +63,28 @@ static DECLFW(M225Write) {
}
static DECLFW(M225LoWrite) {
if (A & 0x800) {
prot[A & 0x03] = V;
}
/* e.g. 115-in-1 [p1][!] CRC32 0xb39d30b4 */
if (A & 0x800) extraRAM[A & 3] = V & 0x0F;
}
static DECLFR(M225LoRead) {
if (A & 0x800) {
return prot[A & 3] & 0x0F;
}
if (A & 0x800) return extraRAM[A & 3];
return X.DB;
}
static void M225Power(void) {
prg = 0;
chr = 0;
mode = 0;
mirr = 0;
Sync();
SetReadHandler(0x5000, 0x5FFF, M225LoRead);
SetWriteHandler(0x5000, 0x5FFF, M225LoWrite);
SetReadHandler(0x5000, 0x5fff, M225LoRead);
SetWriteHandler(0x5000, 0x5fff, M225LoWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M225Write);
}
static void M225Reset(void) {
prg = 0;
chr = 0;
mode = 0;
mirr = 0;
Sync();
}
@ -94,3 +98,7 @@ void Mapper225_Init(CartInfo *info) {
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper255_Init(CartInfo *info) {
Mapper225_Init(info);
}

View File

@ -19,36 +19,79 @@
*/
#include "mapinc.h"
#include "../ines.h"
static uint16 cmdreg = 0;
static uint8 openbus = 0;
// For carts with extra 128K prg rom (Contra)
static uint8 unrom = 0;
static uint8 unromData = 0;
static uint32 PRGROMSize = 0;
static uint16 cmdreg;
static SFORMAT StateRegs[] =
{
{ &cmdreg, 2, "CREG" },
{ &openbus, 1, "OB" },
{ &unrom, 1, "UROM" },
{ &unromData, 1, "UDTA" },
{ 0 }
};
static void Sync(void) {
if (cmdreg & 0x400)
setmirror(MI_0);
else
setmirror(((cmdreg >> 13) & 1) ^ 1);
if (cmdreg & 0x800) {
setprg16(0x8000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
setprg16(0xC000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
} else
setprg32(0x8000, ((cmdreg & 0x300) >> 4) | (cmdreg & 0x1F));
if (unrom) {
int PRGPageCount = PRGROMSize / (16 * 1024);
setprg16(0x8000, PRGPageCount & 0xC0 | (unromData & 7));
setprg16(0xC000, PRGPageCount & 0xC0 | 7);
setmirror(MI_V);
} else {
uint8 bank = ((cmdreg & 0x300) >> 3) | (cmdreg & 0x1F);
if (bank >= (PRGROMSize / (32 * 1024))) {
openbus = 1;
} else {
if (cmdreg & 0x400)
setmirror(MI_0);
else
setmirror(((cmdreg >> 13) & 1) ^ 1);
if (cmdreg & 0x800) {
setprg16(0x8000, (bank << 1) | ((cmdreg >> 12) & 1));
setprg16(0xC000, (bank << 1) | ((cmdreg >> 12) & 1));
} else
setprg32(0x8000, bank);
}
}
}
static DECLFR(M235Read) {
if (openbus) {
openbus = 0;
return X.DB;
}
return CartBR(A);
}
static DECLFW(M235Write) {
cmdreg = A;
unromData = V;
Sync();
}
static void M235Reset(void) {
cmdreg = 0;
unromData = 0;
if (PRGROMSize & 0x20000)
unrom = (unrom + 1) & 1;
Sync();
}
static void M235Power(void) {
setchr8(0);
SetWriteHandler(0x8000, 0xFFFF, M235Write);
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetReadHandler(0x8000, 0xFFFF, M235Read);
cmdreg = 0;
unromData = 0;
unrom = 0;
Sync();
}
@ -57,7 +100,11 @@ static void M235Restore(int version) {
}
void Mapper235_Init(CartInfo *info) {
info->Reset = M235Reset;
info->Power = M235Power;
GameStateRestore = M235Restore;
AddExState(&StateRegs, ~0, 0, 0);
// needs raw, non-pow2 PRGROM size for comparison
PRGROMSize = head.ROM_size * 16384;
}

View File

@ -22,7 +22,7 @@
static uint8 regs[8];
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE = 0;
static SFORMAT StateRegs[] =
{
@ -79,8 +79,7 @@ void Mapper246_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -23,9 +23,9 @@
static uint8 creg[8], preg[2];
static int32 IRQa, IRQCount, IRQClock, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
static uint32 CHRRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -127,8 +127,7 @@ void Mapper252_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -23,9 +23,9 @@
static uint8 chrlo[8], chrhi[8], prg[2], mirr, vlock;
static int32 IRQa, IRQCount, IRQLatch, IRQClock;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
static uint32 CHRRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -144,8 +144,7 @@ void Mapper253_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -0,0 +1,98 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
static uint16 latchAddr;
static uint8 latchData;
static uint8 submapper;
static SFORMAT StateRegs[] =
{
{ &latchAddr, 2, "ADDR" },
{ &latchData, 1, "DATA" },
{ 0 }
};
static void Mapper354_Sync(void)
{
int prg = latchData & 0x3F | latchAddr << 2 & 0x40 | latchAddr >> 5 & 0x80;
switch (latchAddr & 7)
{
case 0: case 4:
setprg32(0x8000, prg >> 1);
break;
case 1:
setprg16(0x8000, prg);
setprg16(0xC000, prg | 7);
break;
case 2: case 6:
setprg8(0x8000, prg << 1 | latchData >> 7);
setprg8(0xA000, prg << 1 | latchData >> 7);
setprg8(0xC000, prg << 1 | latchData >> 7);
setprg8(0xE000, prg << 1 | latchData >> 7);
break;
case 3: case 7:
setprg16(0x8000, prg);
setprg16(0xC000, prg);
break;
case 5:
setprg8(0x6000, prg << 1 | latchData >> 7);
setprg32(0x8000, prg >> 1 | 3);
break;
}
SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], (latchAddr & 8) ? 0 : 1);
setchr8(0);
setmirror(latchData & 0x40 ? MI_H : MI_V);
}
static DECLFW(Mapper354_WriteLatch)
{
latchData = V;
latchAddr = A & 0xFFFF;
Mapper354_Sync();
}
static void Mapper354_Reset(void)
{
latchAddr = latchData = 0;
Mapper354_Sync();
}
static void Mapper354_Power(void)
{
latchAddr = latchData = 0;
SetReadHandler(0x6000, 0xFFFF, CartBR);
SetWriteHandler(submapper == 1 ? 0xE000 : 0xF000, 0xFFFF, Mapper354_WriteLatch);
Mapper354_Sync();
}
static void StateRestore(int version) {
Mapper354_Sync();
}
void Mapper354_Init(CartInfo *info)
{
submapper = info->submapper;
info->Power = Mapper354_Power;
info->Reset = Mapper354_Reset;
GameStateRestore = StateRestore;
AddExState(StateRegs, ~0, 0, 0);
}

View File

@ -0,0 +1,147 @@
/* FCEUmm - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2024
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mapinc.h"
#include "../ines.h"
static uint8 reg[4];
static uint8 IRQCount;
static uint8 IRQReload;
static uint8 IRQa;
static uint8 serialControl;
static uint32 serialAddress;
static SFORMAT StateRegs[] = {
{ reg, 4, "REGS" },
{ &IRQCount, 1, "IRQC" },
{ &IRQReload, 1, "IRQR" },
{ &IRQa, 1, "IRQA" },
{ &serialAddress, 4, "ADDR" },
{ &serialControl, 1, "CTRL" },
{ 0 }
};
static void Sync(void) {
setprg4(0x5000, 0x01);
setprg8(0x6000, reg[0]);
setprg8(0x8000, reg[1]);
setprg8(0xA000, reg[2]);
setprg4(0xD000, 0x07);
setprg8(0xE000, 0x04);
setchr4(0x0000, reg[3]);
setchr4(0x1000, ~0x02);
}
static uint64 lreset;
static uint32 laddr;
static DECLFR(M413ReadPCM) {
uint8 ret = X.DB;
if ((A == laddr) && ((timestampbase + timestamp) < (lreset + 4))) {
return ret;
}
if (serialControl & 0x02) {
ret = MiscROM[serialAddress++ & (MiscROM_size - 1)];
} else {
ret = MiscROM[serialAddress & (MiscROM_size - 1)];
}
laddr = A;
lreset = timestampbase + timestamp;
return ret;
}
static DECLFW(M413Write) {
switch (A & 0xF000) {
case 0x8000:
IRQReload = V;
break;
case 0x9000:
IRQCount = 0;
break;
case 0xA000:
case 0xB000:
IRQa = (A & 0x1000) != 0;
if (!IRQa) {
X6502_IRQEnd(FCEU_IQEXT);
}
break;
case 0xC000:
serialAddress = (serialAddress << 1) | (V >> 7);
break;
case 0xD000:
serialControl = V;
break;
case 0xE000:
case 0xF000:
reg[V >> 6] = V & 0x3F;
Sync();
break;
}
}
static void M413Power(void) {
serialAddress = 0;
serialControl = 0;
IRQCount = 0;
IRQReload = 0;
IRQa = 0;
reg[0] = 0;
reg[1] = 0;
reg[2] = 0;
reg[3] = 0;
laddr = 0;
lreset = 0;
Sync();
SetReadHandler(0x4800, 0x4FFF, M413ReadPCM);
SetReadHandler(0x5000, 0x7FFF, CartBR);
SetReadHandler(0x8000, 0xBFFF, CartBR);
SetReadHandler(0xC000, 0xCFFF, M413ReadPCM);
SetReadHandler(0xD000, 0xFFFF, CartBR);
SetWriteHandler(0x8000, 0xFFFF, M413Write);
}
static void M413IRQHook(void) {
if (IRQCount == 0) {
IRQCount = IRQReload;
} else {
IRQCount--;
}
if ((IRQCount == 0) && IRQa) {
X6502_IRQBegin(FCEU_IQEXT);
}
}
static void StateRestore(int version) {
Sync();
}
void Mapper413_Init(CartInfo *info) {
info->Power = M413Power;
GameHBIRQHook = M413IRQHook;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}

View File

@ -0,0 +1,216 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2024 negativeExponent
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* NES 2.0 Mapper 451 is used for the homebrew game Haratyler HP/MP. It is
* basically a homebrew TLROM-like circuit board that implements the MMC3
* register's in an unusual fashion, and saves the high score to flash ROM */
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x10;
const int FLASH_CHIP = 0x11;
const int FLASH_SECTOR_SIZE = 64 * 1024;
const int magic_addr1 = 0x0555;
const int magic_addr2 = 0x02AA;
static uint8 flash_state, flash_id_mode;
static uint8 *flash_data;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 flash_id[2];
static DECLFW(M451FlashWrite)
{
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = (A & 0xFFF);
flash_buffer_v[flash_state] = V;
flash_state++;
// enter flash ID mode
if ((flash_state == 2) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[1] == magic_addr1) && (flash_buffer_v[1] == 0x90)) {
flash_id_mode = 0;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == magic_addr1) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == magic_addr2) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - flash_data;
int sector = offset / FLASH_SECTOR_SIZE;
for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
}
// erase chip
if ((flash_state == 6) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == magic_addr1) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == magic_addr2) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_a[4] == magic_addr1) && (flash_buffer_v[4] == 0x10)) {
memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == magic_addr1) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == magic_addr2) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == magic_addr1) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - flash_data;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0x00FF) != (magic_addr1 & 0x00FF)) && ((A & 0x00FF) != (magic_addr2 & 0x00FF))) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
flash_id_mode = 0;
}
FixMMC3PRG(MMC3_cmd);
}
static void M451FixPRG(uint32 A, uint8 V) {
setprg8r(FLASH_CHIP, 0x8000, 0);
setprg8r(FLASH_CHIP, 0xA000, 0x10 | ((EXPREGS[0] << 2) & 0x08) | (EXPREGS[0] & 0x01));
setprg8r(FLASH_CHIP, 0xC000, 0x20 | ((EXPREGS[0] << 2) & 0x08) | (EXPREGS[0] & 0x01));
setprg8r(FLASH_CHIP, 0xE000, 0x30);
}
static void M451FixCHR(uint32 A, uint8 V) {
setchr8(EXPREGS[0] & 0x01);
}
static DECLFR(M451Read) {
if (flash_state == 0x90) {
return flash_id[A & 1];
}
return CartBR(A);
}
static DECLFW(M451Write) {
M451FlashWrite(A, V);
switch (A & 0xE000) {
case 0xA000:
MMC3_CMDWrite(0xA000, A & 0x01);
break;
case 0xC000:
A &= 0xFF;
MMC3_IRQWrite(0xC000, A - 1);
MMC3_IRQWrite(0xC001, 0);
MMC3_IRQWrite(0xE000 + ((A == 0xFF) ? 0x00 : 0x01), 0x00);
break;
case 0xE000:
EXPREGS[0] = A & 0x03;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
break;
}
}
static void M451Power(void) {
GenMMC3Power();
SetReadHandler(0x8000, 0xFFFF, M451Read);
SetWriteHandler(0x8000, 0xFFFF, M451Write);
}
static void StateRestore(int version) {
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void M451Close(void) {
if(flash_data)
FCEU_gfree(flash_data);
flash_data = NULL;
}
static void M451FlashReset(void)
{
if (flash_data)
{
size_t flash_size = PRGsize[ROM_CHIP];
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
}
}
void Mapper451_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 16, 0, 0);
pwrap = M451FixPRG;
cwrap = M451FixCHR;
info->Power = M451Power;
info->Close = M451Close;
GameStateRestore = StateRestore;
flash_state = 0;
flash_id_mode = 0;
info->battery = 1;
// Allocate memory for flash
size_t flash_size = PRGsize[ROM_CHIP];
flash_data = (uint8*)FCEU_gmalloc(flash_size);
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
SetupCartPRGMapping(FLASH_CHIP, flash_data, flash_size, 1);
info->addSaveGameBuf( flash_data, flash_size, M451FlashReset );
flash_id[0] = 0x37;
flash_id[1] = 0x86;
SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0);
AddExState(flash_data, flash_size, 0, "FLSH");
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(&flash_id_mode, sizeof(flash_id_mode), 0, "FLMD");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
}

View File

@ -24,7 +24,7 @@ static uint8 chr_reg[4];
static uint8 kogame, prg_reg, nt1, nt2, mirr;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE, count;
static uint32 WRAMSIZE=0, count=0;
static SFORMAT StateRegs[] =
{
@ -156,8 +156,7 @@ void Mapper68_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -25,7 +25,7 @@ static uint8 cmdreg, preg[4], creg[8], mirr;
static uint8 IRQa;
static int32 IRQCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -266,8 +266,7 @@ void Mapper69_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
Mapper69_ESI();

View File

@ -17,13 +17,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Moero!! Pro Tennis have ADPCM codec on-board, PROM isn't dumped, emulation isn't
* possible just now.
* Moero!! Pro Tennis and Moero!! Pro Yakyuu '88 Ketteiban have an ADPCM chip with
* internal ROM, used for voice samples (not dumped, so emulation isn't possible)
*/
#include "mapinc.h"
static uint8 preg, creg;
static void (*Sync)(void);
static SFORMAT StateRegs[] =
{
@ -32,13 +33,19 @@ static SFORMAT StateRegs[] =
{ 0 }
};
static void Sync(void) {
static void M72Sync(void) {
setprg16(0x8000, preg);
setprg16(0xC000, ~0);
setchr8(creg);
}
static DECLFW(M72Write) {
static void M92Sync(void) {
setprg16(0x8000, 0);
setprg16(0xC000, preg);
setchr8(creg);
}
static DECLFW(Write) {
if (V & 0x80)
preg = V & 0xF;
if (V & 0x40)
@ -46,10 +53,10 @@ static DECLFW(M72Write) {
Sync();
}
static void M72Power(void) {
static void Power(void) {
Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x6000, 0xFFFF, M72Write);
SetWriteHandler(0x8000, 0xFFFF, Write);
}
static void StateRestore(int version) {
@ -57,7 +64,16 @@ static void StateRestore(int version) {
}
void Mapper72_Init(CartInfo *info) {
info->Power = M72Power;
Sync = M72Sync;
info->Power = Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);
}
void Mapper92_Init(CartInfo *info) {
Sync = M92Sync;
info->Power = Power;
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -169,8 +169,7 @@ void Mapper80_Init(CartInfo *info) {
GameStateRestore = StateRestore;
if (info->battery) {
info->SaveGame[0] = wram;
info->SaveGameLen[0] = 256;
info->addSaveGameBuf( wram, sizeof(wram) );
}
AddExState(&StateRegs80, ~0, 0, 0);

View File

@ -25,7 +25,7 @@
static uint8 regs[9], ctrl;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -90,8 +90,7 @@ void Mapper82_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -92,8 +92,7 @@ void MapperNNN_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
*/
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -26,7 +26,8 @@ static uint8 dipswitch;
static void (*WSync)(void);
static readfunc defread;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 hasBattery = 0;
static DECLFW(LatchWrite) {
latche = A;
@ -77,8 +78,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint16
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
@ -122,7 +122,7 @@ static void UNL43272Sync(void) {
if ((latche & 0x81) == 0x81) {
setprg32(0x8000, (latche & 0x38) >> 3);
} else
FCEU_printf("unrecognized command %04!\n", latche);
FCEU_printf("unrecognized command %04x!\n", latche);
setchr8(0);
setmirror(0);
}
@ -181,6 +181,7 @@ void Mapper59_Init(CartInfo *info) {
}
//------------------ Map 061 ---------------------------
static void M61Sync(void) {
if (((latche & 0x10) << 1) ^ (latche & 0x20)) {
setprg16(0x8000, ((latche & 0xF) << 1) | (((latche & 0x20) >> 4)));
@ -195,30 +196,21 @@ void Mapper61_Init(CartInfo *info) {
Latch_Init(info, M61Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0);
}
//------------------ Map 092 ---------------------------
// Another two-in-one mapper, two Jaleco carts uses similar
// hardware, but with different wiring.
// Original code provided by LULU
// Additionally, PCB contains DSP extra sound chip, used for voice samples (unemulated)
//------------------ Map 174 ---------------------------
static void M92Sync(void) {
uint8 reg = latche & 0xF0;
setprg16(0x8000, 0);
if (latche >= 0x9000) {
switch (reg) {
case 0xD0: setprg16(0xc000, latche & 15); break;
case 0xE0: setchr8(latche & 15); break;
}
static void M174Sync(void) {
if (latche & 0x80) {
setprg32(0x8000, (latche >> 5) & 3);
} else {
switch (reg) {
case 0xB0: setprg16(0xc000, latche & 15); break;
case 0x70: setchr8(latche & 15); break;
}
setprg16(0x8000, (latche >> 4) & 7);
setprg16(0xC000, (latche >> 4) & 7);
}
setchr8((latche >> 1) & 7);
setmirror((latche & 1) ^ 1);
}
void Mapper92_Init(CartInfo *info) {
Latch_Init(info, M92Sync, NULL, 0x80B0, 0x8000, 0xFFFF, 0);
void Mapper174_Init(CartInfo *info) {
Latch_Init(info, M174Sync, NULL, 0, 0x8000, 0xFFFF, 0);
}
//------------------ Map 200 ---------------------------
@ -342,20 +334,17 @@ void Mapper217_Init(CartInfo *info) {
}
//------------------ Map 227 ---------------------------
static void M227Sync(void) {
uint32 S = latche & 1;
uint32 p = ((latche >> 2) & 0x1F) + ((latche & 0x100) >> 3);
uint32 L = (latche >> 9) & 1;
// ok, according to nesdev wiki (refrenced to the nesdev dumping thread) there is a CHR write protection bit7.
// however, this bit clearly determined a specific PRG layout for some game but does not meant to have additional
// functionality. as I see from the menu code, it disables the chr writing before run an actual game.
// this fix here makes happy both waixing rpgs and multigame menus at once. can't veryfy it on a hardware
// but if I find some i'll definitly do this.
if ((latche & 0xF000) == 0xF000)
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
// Only Waixing appear to have battery flag enabled, while multicarts don't.
// Multicarts needs CHR-RAM protect in NROM modes, so only apply CHR-RAM protect
// on non battery-enabled carts.
if (!hasBattery && (latche & 0x80) == 0x80)
/* CHR-RAM write protect hack, needed for some multicarts */
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0);
else
SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1);
@ -393,6 +382,7 @@ static void M227Sync(void) {
void Mapper227_Init(CartInfo *info) {
Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1);
hasBattery = info->battery;
}
//------------------ Map 229 ---------------------------

View File

@ -29,7 +29,7 @@ static uint8 IRQa;
static int16 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -178,9 +178,12 @@ static void x24c02_write(uint8 data) {
x24c02_addr <<= 1;
x24c02_addr |= sda;
} else {
if (sda) // READ COMMAND
if ((x24c02_addr & 0x78) != 0x50) { // WRONG DEVICE ADDRESS
x24c02_out = 1;
x24c02_state = X24C0X_STANDBY;
} else if (sda) // READ COMMAND
x24c02_state = X24C0X_READ;
else // WRITE COMMAND
else // WRITE COMMAND
x24c02_state = X24C0X_WORD;
}
x24c02_bitcount++;
@ -317,8 +320,7 @@ void Mapper16_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook;
info->battery = 1;
info->SaveGame[0] = x24c0x_data + 256;
info->SaveGameLen[0] = 256;
info->addSaveGameBuf( x24c0x_data + 256, 256 );
AddExState(x24c0x_data, 256, 0, "DATA");
AddExState(&x24c02StateRegs, ~0, 0, 0);
@ -333,8 +335,7 @@ void Mapper159_Init(CartInfo *info) {
MapIRQHook = BandaiIRQHook;
info->battery = 1;
info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 128;
info->addSaveGameBuf( x24c0x_data, 128 );
AddExState(x24c0x_data, 128, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
@ -378,8 +379,7 @@ void Mapper153_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
@ -599,8 +599,7 @@ void Mapper157_Init(CartInfo *info) {
GameInfo->cspecial = SIS_DATACH;
info->battery = 1;
info->SaveGame[0] = x24c0x_data;
info->SaveGameLen[0] = 512;
info->addSaveGameBuf( x24c0x_data, 512 );
AddExState(x24c0x_data, 512, 0, "DATA");
AddExState(&x24c01StateRegs, ~0, 0, 0);
AddExState(&x24c02StateRegs, ~0, 0, 0);

View File

@ -252,8 +252,7 @@ void Mapper111_Init(CartInfo *info) {
if (flash)
{
FLASHROM = (uint8*)FCEU_gmalloc(FLASHROMSIZE);
info->SaveGame[0] = FLASHROM;
info->SaveGameLen[0] = FLASHROMSIZE;
info->addSaveGameBuf( FLASHROM, FLASHROMSIZE );
AddExState(FLASHROM, FLASHROMSIZE, 0, "FROM");
AddExState(&FlashRegs, ~0, 0, 0);

View File

@ -21,7 +21,7 @@
*
* COOLBOY cartridges use registers at address $6xxx
* MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000
*
*
* $xxx0
* 7 bit 0
* ---- ----
@ -29,12 +29,11 @@
* |||| ||||
* |||| |+++-- PRG offset (PRG A19, A18, A17)
* |||| +----- Alternate CHR A17
* ||++------- PRG offset (PRG A24, A23)
* ||++------- PRG offset (PRG A24, A23), CHR offset (CHR A19, A18)
* |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
* +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*
* $xxx1
*
* 7 bit 0
* ---- ----
* GHIJ KKLx
@ -55,15 +54,16 @@
* $xxx3
* 7 bit 0
* ---- ----
* NPxP QQRx
* || | |||
* || | +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
* || +------- 1: GNROM mode; 0: MMC3 mode
* || | (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
* || | 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
* NPZP QQRx
* |||| |||
* |||| +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
* |||+------- 1: GNROM mode; 0: MMC3 mode
* |||| (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
* |||| 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
* ||+-------- 1: Also enable PRG RAM in $5000-$5FFF
* |+-+------- Banking mode
* |+--------- "Weird MMC3 mode"
* +---------- Lockout (prevent further writes to these four registers, only works in MMC3 mode)
* +---------- Lockout (prevent further writes to all registers but the one at $xxx2, only works in MMC3 mode)
*
* Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper,
* which allows you to rewrite flash memory without soldering.
@ -75,25 +75,90 @@
#include "mapinc.h"
#include "mmc3.h"
#include "../ines.h"
static void COOLBOYCW(uint32 A, uint8 V) {
uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80);
if (EXPREGS[3] & 0x10) {
if (EXPREGS[3] & 0x40) { // Weird mode
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x11;
const int FLASH_CHIP = 0x12;
const uint32 FLASH_SECTOR_SIZE = 128 * 1024;
extern uint8* WRAM;
static uint8* CFI = NULL;
static uint8* Flash = NULL;
static uint8 flash_save = 0;
static uint8 flash_state = 0;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 cfi_mode = 0;
static uint16 regs_base = 0;
static uint8 flag23 = 0;
static uint8 flag45 = 0;
static uint8 flag67 = 0;
static uint8 flag89 = 0;
// Macronix 256-mbit memory CFI data
const uint8 cfi_data[] =
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00,
0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x03,
0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x19,
0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01,
0x00, 0x08, 0x00, 0x00, 0x02, 0x95, 0xA5, 0x05,
0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
static void AA6023CW(uint32 A, uint8 V) {
if (flag89) {
/*
$xxx0
7 bit 0
---- ----
AB.C DEEE
|| | ||||
|| | |+++-- PRG offset (PRG A19, A18, A17)
|| | +----- Alternate CHR A17
|| +------- 1=Write-protect CHR-RAM
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
*/
if (EXPREGS[0] & 0b00010000)
SetupCartCHRMapping(0, VROM, CHRsize[0], 0); // write-protect CHR-RAM
else
SetupCartCHRMapping(0, VROM, CHRsize[0], 1); // allow CHR writes
}
uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000);
if (EXPREGS[3] & 0b00010000) {
if (EXPREGS[3] & 0b01000000) { // Weird mode
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0400:
case 0x0C00: V &= 0x7F; break;
}
}
// Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit
(V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit
| ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits
| ((A >> 10) & 7) // 2-0 bits
| ((EXPREGS[0] & 0b00110000) << 4) // There are some ROMs with 1 MiB CHR-ROM
);
} else {
if (EXPREGS[3] & 0x40) { // Weird mode, again
}
else {
if (EXPREGS[3] & 0b01000000) { // Weird mode, again
int cbase = (MMC3_cmd & 0x80) << 5;
switch (cbase ^ A) { // Don't even try do understand
case 0x0000: V = DRegBuf[0]; break;
@ -103,18 +168,81 @@ static void COOLBOYCW(uint32 A, uint8 V) {
}
}
// 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));
// Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
setchr1(A,
(V & mask)
| (((EXPREGS[0] & 0x08) << 4) & ~mask)
| ((EXPREGS[0] & 0b00110000) << 4)); // There are some ROMs with 1 MiB CHR-ROM
}
}
static void COOLBOYPW(uint32 A, uint8 V) {
uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2);
uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2);
static void AA6023PW(uint32 A, uint8 V) {
uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]};
// Submappers has scrambled bits
if (flag23) {
/*
$xxx1
7 bit 0
---- ----
GHIL JKKx
|||| |||
|||| +++--- PRG offset (in order: PRG A20, A21, A22)
|||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100101)
| ((CREGS[1] & 0b00001000) << 1) // PRG A20
| ((CREGS[1] & 0b00000010) << 2) // PRG A22
| ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size
}
if (flag45) {
/*
$xxx0
7 bit 0
---- ----
ABCC DEEE
|||| ||||
|||| |+++-- PRG offset (PRG A19, A18, A17)
|||| +----- Alternate CHR A17
||++------- PRG offset (PRG A21, A20)
|+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
+---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
$xxx1
7 bit 0
---- ----
GHIx xxLx
||| |
||| +--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
|+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
+---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
*/
CREGS[1] = (CREGS[1] & 0b11100011)
| ((CREGS[0] & 0b00100000) >> 3) // PRG A21
| (CREGS[0] & 0b00010000); // PRG A20
CREGS[0] &= 0b11001111;
}
uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2);
uint32 base = ((CREGS[0] & 0b00000111) >> 0) | ((CREGS[1] & 0b00010000) >> 1) | ((CREGS[1] & 0b00001100) << 2) | ((CREGS[0] & 0b00110000) << 2);
if (flash_save && cfi_mode) {
setprg32r(CFI_CHIP, 0x8000, 0);
return;
}
int chip = !flash_save ? ROM_CHIP : FLASH_CHIP;
// There are ROMs with multiple PRG ROM chips
int chip_offset = 0;
if (flag67 && EXPREGS[0] & 0b00001000) {
chip_offset += ROM_size;
}
// Very weird mode
// Last banks are first in this mode, ignored when MMC3_cmd&0x40
if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
if ((CREGS[3] & 0b01000000) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
switch (A & 0xE000) {
case 0xC000:
case 0xE000:
@ -123,91 +251,234 @@ static void COOLBOYPW(uint32 A, uint8 V) {
}
}
// Regular MMC3 mode, internal ROM size can be up to 2048kb!
if (!(EXPREGS[3] & 0x10))
setprg8(A, (((base << 4) & ~mask)) | (V & mask));
else { // NROM mode
if (!(CREGS[3] & 0x10)) {
// Regular MMC3 mode but can be extended to 2MiB
setprg8r(chip, A, ((((base << 4) & ~mask)) | (V & mask)) + chip_offset);
}
else {
// NROM mode
mask &= 0xF0;
uint8 emask;
if ((((EXPREGS[1] & 2) != 0))) // 32kb mode
emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13);
if (CREGS[1] & 0b00000010) // 32kb mode
emask = (CREGS[3] & 0b00001100) | ((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
emask = CREGS[3] & 0b00001110;
setprg8r(chip, A, (
((base << 4) & ~mask) // 7-4 bits are from base
| (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
) + chip_offset); // For multi-chip ROMs
}
}
static DECLFW(COOLBOYWrite) {
if(A001B & 0x80)
CartBW(A,V);
static DECLFW(AA6023WramWrite) {
if (A001B & 0x80)
CartBW(A, V);
}
static DECLFW(AA6023Write) {
if (A >= 0x6000) {
AA6023WramWrite(A, V);
}
// Deny any further writes when 7th bit is 1 AND 4th is 0
if ((EXPREGS[3] & 0x90) != 0x80) {
EXPREGS[A & 3] = V;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void COOLBOYReset(void) {
static DECLFW(AA6023FlashWrite) {
if (A < 0xC000)
MMC3_CMDWrite(A, V);
else
MMC3_IRQWrite(A, V);
if (!flash_save) return;
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = A & 0xFFF;
flash_buffer_v[flash_state] = V;
flash_state++;
// enter CFI mode
if ((flash_state == 1) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) {
cfi_mode = 1;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - Flash;
int sector = offset / FLASH_SECTOR_SIZE;
for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
Flash[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
flash_state = 0;
}
// erase chip, lol
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x10)) {
memset(Flash, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - Flash;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
cfi_mode = 0;
}
FixMMC3PRG(MMC3_cmd);
}
static void AA6023Reset(void) {
MMC3RegReset();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
flash_state = 0;
cfi_mode = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void COOLBOYPower(void) {
static void AA6023Power(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite);
if (regs_base != 0x5000)
SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
SetWriteHandler(0x6000, 0x7fff, AA6023WramWrite);
SetWriteHandler(regs_base, regs_base + 0x0fff, AA6023Write);
SetWriteHandler(0x8000, 0xFFFF, AA6023FlashWrite);
SetReadHandler(0x8000, 0xFFFF, CartBR);
}
static void MINDKIDSPower(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
static void AA6023Restore(int version) {
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite);
}
static void AA6023Close(void) {
if (WRAM)
FCEU_gfree(WRAM);
if (Flash)
FCEU_gfree(Flash);
if (CFI)
FCEU_gfree(CFI);
WRAM = Flash = CFI = NULL;
}
void CommonInit(CartInfo* info, int submapper)
{
GenMMC3_Init(info, 2048, info->vram_size / 1024, !info->ines2 ? 8 : (info->wram_size + info->battery_wram_size) / 1024, info->battery);
pwrap = AA6023PW;
cwrap = AA6023CW;
switch (submapper)
{
case 2:
regs_base = 0x7000;
break;
case 0:
case 4:
case 6:
case 8:
regs_base = 0x6000;
break;
case 1:
case 3:
case 5:
case 7:
case 9:
regs_base = 0x5000;
break;
default:
FCEU_PrintError("Submapper #%d is not supported", submapper);
}
flag23 = (submapper == 2) || (submapper == 3);
flag45 = (submapper == 4) || (submapper == 5);
flag67 = (submapper == 6) || (submapper == 7);
flag89 = (submapper == 8) || (submapper == 9);
info->Power = AA6023Power;
info->Reset = AA6023Reset;
info->Close = AA6023Close;
GameStateRestore = AA6023Restore;
flash_save = info->battery;
if (flash_save) {
CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2);
for (size_t i = 0; i < sizeof(cfi_data); i++) {
CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i];
}
SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0);
Flash = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]);
for (unsigned int i = 0; i < PRGsize[ROM_CHIP]; i++) {
Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]];
}
SetupCartPRGMapping(FLASH_CHIP, Flash, PRGsize[ROM_CHIP], 1);
info->addSaveGameBuf( Flash, PRGsize[ROM_CHIP] );
}
AddExState(EXPREGS, 4, 0, "EXPR");
if (flash_save)
{
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
AddExState(&cfi_mode, sizeof(cfi_mode), 0, "CFIM");
AddExState(Flash, PRGsize[ROM_CHIP], 0, "FLAS");
}
}
// Registers at $6xxx
void COOLBOY_Init(CartInfo *info) {
GenMMC3_Init(info, 2048, 256, 8, 1);
pwrap = COOLBOYPW;
cwrap = COOLBOYCW;
info->Power = COOLBOYPower;
info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR");
void COOLBOY_Init(CartInfo* info) {
CommonInit(info, 0);
}
// Registers at $5xxx
void MINDKIDS_Init(CartInfo *info) {
GenMMC3_Init(info, 2048, 256, 8, 1);
pwrap = COOLBOYPW;
cwrap = COOLBOYCW;
info->Power = MINDKIDSPower;
info->Reset = COOLBOYReset;
AddExState(EXPREGS, 4, 0, "EXPR");
void MINDKIDS_Init(CartInfo* info) {
CommonInit(info, 1);
}
// For NES 2.0 loader
void SMD132_SMD133_Init(CartInfo *info) {
switch (info->submapper)
{
case 0:
COOLBOY_Init(info);
break;
case 1:
MINDKIDS_Init(info);
break;
default:
FCEU_PrintError("Unknown submapper: #%d.", info->submapper);
break;
}
void AA6023_Init(CartInfo* info) {
CommonInit(info, info->submapper);
}

File diff suppressed because it is too large Load Diff

View File

@ -21,11 +21,12 @@
#include "mapinc.h"
#include "../ines.h"
static uint8 latche, latcheinit, bus_conflict;
static uint16 addrreg0, addrreg1;
static uint8 latche=0, latcheinit=0, bus_conflict=0;
static uint16 addrreg0=0, addrreg1=0;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static void (*WSync)(void);
static uint32 WRAMSIZE=0;
static void (*WSync)(void) = nullptr;
static uint8 submapper;
static DECLFW(LatchWrite) {
// FCEU_printf("bs %04x %02x\n",A,V);
@ -68,6 +69,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
info->Power = LatchPower;
info->Close = LatchClose;
GameStateRestore = StateRestore;
submapper = info->submapper;
if(info->ines2)
if(info->battery_wram_size + info->wram_size > 0)
wram = 1;
@ -85,14 +87,12 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
//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;
// info->addSaveGameBuf( WRAM, 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;
// info->addSaveGameBuf( WRAM + info->wram_size, info->battery_wram_size );
//}
//this is more likely the only practical scenario
@ -104,8 +104,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
setprg8r(0x10, 0x6000, 0);
if(info->battery_wram_size)
{
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 8192;
info->addSaveGameBuf( WRAM, 8192 );
}
}
else
@ -114,8 +113,7 @@ static void Latch_Init(CartInfo *info, void (*proc)(void), uint8 init, uint16 ad
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
@ -158,8 +156,7 @@ void NROM_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}
@ -300,7 +297,11 @@ static void M78Sync() {
setprg16(0x8000, (latche & 7));
setprg16(0xc000, ~0);
setchr8(latche >> 4);
setmirror(MI_0 + ((latche >> 3) & 1));
if (submapper == 3) {
setmirror((latche >> 3) & 1);
} else {
setmirror(MI_0 + ((latche >> 3) & 1));
}
}
void Mapper78_Init(CartInfo *info) {
@ -308,7 +309,8 @@ void Mapper78_Init(CartInfo *info) {
}
//------------------ Map 86 ---------------------------
// Moero!! Pro Yakyuu has an ADPCM chip with internal ROM,
// used for voice samples (not dumped, so emulation isn't possible)
static void M86Sync(void) {
setprg32(0x8000, (latche >> 4) & 3);
setchr8((latche & 3) | ((latche >> 4) & 4));
@ -369,31 +371,14 @@ void Mapper94_Init(CartInfo *info) {
//------------------ Map 97 ---------------------------
static void M97Sync(void) {
setchr8(0);
setprg16(0x8000, ~0);
setprg16(0xc000, latche & 15);
switch (latche >> 6) {
case 0: break;
case 1: setmirror(MI_H); break;
case 2: setmirror(MI_V); break;
case 3: break;
}
setchr8(((latche >> 1) & 1) | ((latche << 1) & 2));
setmirror((latche >> 7) & 1);
setchr8(0);
}
void Mapper97_Init(CartInfo *info) {
Latch_Init(info, M97Sync, ~0, 0x8000, 0xFFFF, 0, 0);
}
//------------------ Map 101 ---------------------------
static void M101Sync(void) {
setprg32(0x8000, 0);
setchr8(latche);
}
void Mapper101_Init(CartInfo *info) {
Latch_Init(info, M101Sync, ~0, 0x6000, 0x7FFF, 0, 0);
Latch_Init(info, M97Sync, ~0, 0x8000, 0xBFFF, 0, 0);
}
//------------------ Map 107 ---------------------------
@ -474,6 +459,39 @@ void Mapper203_Init(CartInfo *info) {
Latch_Init(info, M203Sync, 0, 0x8000, 0xFFFF, 0, 0);
}
//------------------ Map 218 ---------------------------
static void Mapper218_Power()
{
//doesn't really matter
SetReadHandler(0x6000, 0xFFFF, &CartBROB);
}
void Mapper218_Init(CartInfo *info)
{
info->Power = &Mapper218_Power;
//fixed PRG mapping
setprg32(0x8000, 0);
//this mapper is supposed to interpret the iNES header bits specially
static const uint8 mirrorings[] = {MI_V,MI_H,MI_0,MI_1};
SetupCartMirroring(mirrorings[info->mirrorAs2Bits],1,nullptr);
//cryptic logic to effect the CHR RAM mappings by mapping 1k blocks to NTARAM according to how the pins are wired
//this could be done by bit logic, but this is self-documenting
static const uint8 mapping[] = {
0,1,0,1,0,1,0,1, //mirrorAs2Bits==0
0,0,1,1,0,0,1,1, //mirrorAs2Bits==1
0,0,0,0,1,1,1,1, //mirrorAs2Bits==2
0,0,0,0,0,0,0,0 //mirrorAs2Bits==3
};
for(int i=0;i<8;i++)
VPageR[i] = &NTARAM[mapping[info->mirrorAs2Bits*8+i]];
PPUCHRRAM = 0xFF;
}
//------------------ Map 240 ---------------------------
static void M240Sync(void) {

View File

@ -70,8 +70,7 @@ void UNLEDU2000_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(32768);
SetupCartPRGMapping(0x10, WRAM, 32768, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 32768;
info->addSaveGameBuf( WRAM, 32768 );
}
AddExState(WRAM, 32768, 0, "WRAM");
AddExState(StateRegs, ~0, 0, 0);

View File

@ -141,8 +141,7 @@ void Mapper6_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -28,17 +28,19 @@
static uint8 DRegs[4];
static uint8 Buffer, BufferShift;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static uint8 *WRAM = NULL;
static int kanji_pos, kanji_page, r40C0;
static int IRQa, IRQCount;
FCEU_MAYBE_UNUSED
static DECLFW(MBWRAM) {
if (!(DRegs[3] & 0x10))
Page[A >> 11][A] = V;
}
FCEU_MAYBE_UNUSED
static DECLFR(MAWRAM) {
if (DRegs[3] & 0x10)
return X.DB;
@ -254,8 +256,7 @@ void FNS_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
AddExState(DRegs, 4, 0, "DREG");
AddExState(&lreset, 8, 1, "LRST");

View File

@ -0,0 +1,88 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2022 Cluster
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* NES 2.0 Mapper 470 denotes the INX_007T_V01 multicart circuit board,
* used for the Retro-Bit re-release of Battletoads and Double Dragon.
* It is basically AOROM with an additional outer bank register at $5000-$5FFF
* whose data selects the 256 KiB outer bank.
*
* $5000-$5FFF
* 7 bit 0
* ---- ----
* xxxx xxOO
* ||
* ++- Select outer 256 KB PRG ROM bank for CPU $8000-$FFFF
*
* $8000-$FFFF
* 7 bit 0
* ---- ----
* xxxM xPPP
* | |||
* | +++- Select inner 32 KB PRG ROM bank for CPU $8000-$FFFF
* +------ Select 1 KB VRAM page for all 4 nametables
*
*/
#include "mapinc.h"
static uint8 latch_out, latch_in;
static void INX_007T_Sync() {
setprg32(0x8000, (latch_in & 0b111) | (latch_out << 3));
setmirror(MI_0 + ((latch_in >> 4) & 1));
setchr8(0);
}
static void StateRestore(int version) {
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteLow)
{
latch_out = V;
INX_007T_Sync();
}
static DECLFW(INX_007T_WriteHi)
{
latch_in = V;
INX_007T_Sync();
}
static void INX_007T_Power(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
SetWriteHandler(0x5000,0x5FFF, INX_007T_WriteLow);
SetWriteHandler(0x8000, 0xFFFF, INX_007T_WriteHi);
}
static void INX_007T_Reset(void) {
latch_in = latch_out = 0;
INX_007T_Sync();
}
void INX_007T_Init(CartInfo *info) {
info->Power = INX_007T_Power;
info->Reset = INX_007T_Reset;
GameStateRestore = StateRestore;
SetupCartMirroring(MI_0, 0, NULL);
AddExState(&latch_out, 1, 0, "LATO");
AddExState(&latch_in, 1, 0, "LATI");
}

View File

@ -306,8 +306,7 @@ static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int bram) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (bram) {
info->SaveGame[0] = WRAM + NONBRAMSIZE;
info->SaveGameLen[0] = bram * 1024;
info->addSaveGameBuf( WRAM + NONBRAMSIZE, bram * 1024 );
}
}
if (!chr) {

View File

@ -25,7 +25,7 @@
static uint8 is10;
static uint8 creg[4], latch0, latch1, preg, mirr;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -130,8 +130,7 @@ void Mapper10_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -324,8 +324,7 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) {
if (battery) {
mmc3opts |= 2;
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
// KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support
@ -364,8 +363,10 @@ static void M4Power(void) {
void Mapper4_Init(CartInfo *info) {
int ws = 8;
if ((info->CRC32 == 0x93991433 || info->CRC32 == 0xaf65aa84)) {
FCEU_printf("Low-G-Man can not work normally in the iNES format.\nThis game has been recognized by its CRC32 value, and the appropriate changes will be made so it will run.\nIf you wish to hack this game, you should use the UNIF format for your hack.\n\n");
if (info->ines2) {
ws = (info->wram_size + info->battery_wram_size) / 1024;
} else if ((info->CRC32 == 0x93991433 || info->CRC32 == 0xaf65aa84)) {
FCEU_printf("Low-G-Man can not work normally in the iNES format.\nThis game has been recognized by its CRC32 value, and the appropriate changes will be made so it will run.\nIf you wish to hack this game, you should use the NES 2.0 format for your hack.\n\n");
ws = 0;
}
GenMMC3_Init(info, 512, 256, ws, info->battery);
@ -499,38 +500,38 @@ void Mapper44_Init(CartInfo *info) {
// ---------------------------- Mapper 45 -------------------------------
static void M45CW(uint32 A, uint8 V) {
if (!UNIFchrrama) {
uint32 NV = V;
if (EXPREGS[2] & 8)
NV &= (1 << ((EXPREGS[2] & 7) + 1)) - 1;
else
if (EXPREGS[2])
NV &= 0; // hack ;( don't know exactly how it should be
NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4);
setchr1(A, NV);
} else
// setchr8(0); // i don't know what cart need this, but a new one need other lol
setchr1(A, V);
uint32 NV = V;
const int mask = ((EXPREGS[2] & 0x0F) > 7)
? ((1 << (EXPREGS[2] & 0x0F) << 3) - 1)
: 0;
NV |= (EXPREGS[0] & mask) | ((EXPREGS[2] & 0xF0) << 4);
setchr1(A, NV);
}
static void M45PW(uint32 A, uint8 V) {
uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F);
MV |= EXPREGS[1];
if(UNIFchrrama)
MV |= ((EXPREGS[2] & 0x40) << 2);
uint32 MV = V;
const int mask = (EXPREGS[3] & 0x3F) ^ 0x3F;
MV |= (EXPREGS[1] & 0x3F & mask) | (EXPREGS[1] & 0xC0);
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) {
if (EXPREGS[3] & 0x40) {
WRAM[A - 0x6000] = V;
return;
WRAM[A - 0x6000] = V;
if (!(A & 1))
{
if (EXPREGS[3] & 0x40) {
WRAM[A - 0x6000] = V;
return;
}
EXPREGS[EXPREGS[4]] = V;
EXPREGS[4] = (EXPREGS[4] + 1) & 3;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
else {
// lock reset
EXPREGS[3] &= ~0x40;
}
EXPREGS[EXPREGS[4]] = V;
EXPREGS[4] = (EXPREGS[4] + 1) & 3;
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static DECLFR(M45Read) {
@ -551,7 +552,7 @@ static void M45Reset(void) {
static void M45Power(void) {
GenMMC3Power();
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = EXPREGS[4] = EXPREGS[5] = 0;
SetWriteHandler(0x5000, 0x7FFF, M45Write);
SetWriteHandler(0x6000, 0x7FFF, M45Write);
SetReadHandler(0x5000, 0x5FFF, M45Read);
}
@ -861,32 +862,52 @@ void Mapper119_Init(CartInfo *info) {
// ---------------------------- Mapper 134 ------------------------------
static void M134PW(uint32 A, uint8 V) {
setprg8(A, (V & 0x1F) | ((EXPREGS[0] & 2) << 4));
if ((EXPREGS[1] & 0x88) == 0x80)
setprg32(A, (EXPREGS[0] & 0x10) | ((EXPREGS[1] & 2) << 2)); // NROM-256
else if ((EXPREGS[1] & 0x88) == 0x88)
setprg16(0x8000 | (A & 0x4000), ((EXPREGS[0] & 0x10) << 1) | ((V & 0x10) >> 1) | ((EXPREGS[1] & 3) << 3)); // NROM-128
else if (EXPREGS[1] & 4)
setprg8(A, ((EXPREGS[0] & 0x10) << 2) | (V & 0x0F) | ((EXPREGS[1] & 3) << 4)); // MMC3 128KB mask
else
setprg8(A, ((EXPREGS[0] & 0x10) << 2) | (V & 0x1F) | ((EXPREGS[1] & 2) << 4)); // MMC3 256KB mask
}
static void M134CW(uint32 A, uint8 V) {
setchr1(A, (V & 0xFF) | ((EXPREGS[0] & 0x20) << 3));
// CNROM mode. Unclear. Untested.
if (EXPREGS[0] & 0x08)
setchr8(EXPREGS[2]);
else if (EXPREGS[1] & 0x40)
setchr1(A, ((EXPREGS[0] & 0x20) << 4) | (V & 0x7F) | ((EXPREGS[1] & 0x30) << 3)); // 128KB mask
else
setchr1(A, ((EXPREGS[0] & 0x20) << 4) | (V & 0xFF) | ((EXPREGS[1] & 0x20) << 3)); // 256KB mask
}
static DECLFW(M134Write) {
EXPREGS[0] = V;
if (EXPREGS[0] & 0x80)
{
// locked (except $6002.0-1)
if ((A & 3) == 2)
EXPREGS[2] = (EXPREGS[2] & 0xFC) | (V & 3);
return;
}
EXPREGS[A & 3] = V;
FixMMC3CHR(MMC3_cmd);
FixMMC3PRG(MMC3_cmd);
}
static void M134Power(void) {
EXPREGS[0] = 0;
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
GenMMC3Power();
SetWriteHandler(0x6001, 0x6001, M134Write);
SetWriteHandler(0x6000, 0x7FFF, M134Write);
}
static void M134Reset(void) {
EXPREGS[0] = 0;
EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
MMC3RegReset();
}
void Mapper134_Init(CartInfo *info) {
GenMMC3_Init(info, 256, 256, 0, 0);
GenMMC3_Init(info, 512, 512, 0, 0);
pwrap = M134PW;
cwrap = M134CW;
info->Power = M134Power;
@ -1137,20 +1158,73 @@ void Mapper198_Init(CartInfo *info) {
info->Power = M195Power;
}
// ---------------------------- Mapper 205 ------------------------------
// GN-45 BOARD
/* ---------------------------- Mapper 205 ------------------------------ */
/* UNIF boardname BMC-JC-016-2
https://wiki.nesdev.com/w/index.php/INES_Mapper_205 */
/* 2023-02 : Update reg write logic and add solder pad */
static void M205PW(uint32 A, uint8 V) {
// GN-30A - íà÷àëüíàÿ ìàñêà äîëæíà áûòü 1F + àïïàðàòíûé ïåðåêëþ÷àòåëü íà øèíå àäðåñà
setprg8(A, (V & 0x0f) | EXPREGS[0]);
uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x0F : 0x1F);
if (PRGsize[1]) { // split-rom variant
setprg8r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank);
} else {
setprg8(A, EXPREGS[0] << 4 | bank);
}
}
static void M205CW(uint32 A, uint8 V) {
// GN-30A - íà÷àëüíàÿ ìàñêà äîëæíà áûòü FF
uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x7F : 0xFF);
if (CHRsize[1]) { // split-rom variant
setchr1r((EXPREGS[0] & 3) ? (EXPREGS[0] - 1) : 0, A, bank);
} else {
setchr1(A, (EXPREGS[0] << 7) | bank);
}
}
static DECLFW(M205Write) {
EXPREGS[0] = V & 3;
if (V & 1) {
EXPREGS[0] |= EXPREGS[1];
}
CartBW(A, V);
FixMMC3PRG(MMC3_cmd);
FixMMC3CHR(MMC3_cmd);
}
static void M205Reset(void) {
EXPREGS[0] = 0;
EXPREGS[1] ^= 2; /* solder pad */
MMC3RegReset();
}
static void M205Power(void) {
EXPREGS[0] = EXPREGS[1] = 0;
GenMMC3Power();
SetWriteHandler(0x6000, 0x7FFF, M205Write);
}
void Mapper205_Init(CartInfo *info) {
GenMMC3_Init(info, 256, 128, 0, 0);
pwrap = M205PW;
cwrap = M205CW;
info->Power = M205Power;
info->Reset = M205Reset;
AddExState(EXPREGS, 2, 0, "EXPR");
}
/* --------------------------- GN-45 BOARD ------------------------------ */
/* Mapper 361 and 366, previously assigned as Mapper 205 */
static void GN45PW(uint32 A, uint8 V) {
setprg8(A, (V & 0x0f) | EXPREGS[0]);
}
static void GN45CW(uint32 A, uint8 V) {
setchr1(A, (V & 0x7F) | (EXPREGS[0] << 3));
}
static DECLFW(M205Write0) {
static DECLFW(GN45Write0) {
if (EXPREGS[2] == 0) {
EXPREGS[0] = A & 0x30;
EXPREGS[2] = A & 0x80;
@ -1160,7 +1234,7 @@ static DECLFW(M205Write0) {
CartBW(A, V);
}
static DECLFW(M205Write1) {
static DECLFW(GN45Write1) {
if (EXPREGS[2] == 0) {
EXPREGS[0] = V & 0x30;
FixMMC3PRG(MMC3_cmd);
@ -1169,23 +1243,23 @@ static DECLFW(M205Write1) {
CartBW(A, V);
}
static void M205Reset(void) {
static void GN45Reset(void) {
EXPREGS[0] = EXPREGS[2] = 0;
MMC3RegReset();
}
static void M205Power(void) {
static void GN45Power(void) {
GenMMC3Power();
SetWriteHandler(0x6000, 0x6fff, M205Write0);
SetWriteHandler(0x7000, 0x7fff, M205Write1); // OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein
SetWriteHandler(0x6000, 0x6fff, GN45Write0);
SetWriteHandler(0x7000, 0x7fff, GN45Write1); /* OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein */
}
void Mapper205_Init(CartInfo *info) {
void GN45_Init(CartInfo *info) {
GenMMC3_Init(info, 128, 128, 8, 0);
pwrap = M205PW;
cwrap = M205CW;
info->Power = M205Power;
info->Reset = M205Reset;
pwrap = GN45PW;
cwrap = GN45CW;
info->Power = GN45Power;
info->Reset = GN45Reset;
AddExState(EXPREGS, 1, 0, "EXPR");
}
@ -1376,6 +1450,7 @@ static DECLFW(M406IRQWrite) {
MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
}
FCEU_MAYBE_UNUSED
static DECLFW(M406Write) {
}

View File

@ -307,8 +307,7 @@ cartdata MMC5CartList[] =
#define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0]))
int DetectMMC5WRAMSize(uint32 crc32) {
int x;
for (x = 0; x < MMC5_NOCARTS; x++) {
for (size_t x = 0; x < MMC5_NOCARTS; x++) {
if (crc32 == MMC5CartList[x].crc32) {
if(MMC5CartList[x].size > 1)
FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
@ -425,7 +424,7 @@ static void MMC5PRG(void) {
switch (mmc5psize & 3) {
case 0:
MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1;
setprg32(0x8000, ((PRGBanks[1] & 0x7F) >> 2));
setprg32(0x8000, ((PRGBanks[3] & 0x7F) >> 2));
for (x = 0; x < 4; x++)
MMC5MemIn[1 + x] = 1;
break;
@ -904,14 +903,14 @@ static void GenMMC5Power(void) {
PRGBanks.fill(0xFF);
WRAMPage = 0;
CHRBanksA.fill(0xFF);
CHRBanksB.fill(0xFF);
CHRBanksA.fill(0);
CHRBanksB.fill(0);
WRAMMaskEnable.fill(0xFF);
mmc5ABMode = 0;
IRQScanline = 0;
IRQEnable = 0;
CHRMode = 0;
NTAMirroring = NTFill = ATFill = 0xFF;
NTAMirroring = NTFill = ATFill = 0;
MMC5IRQR = 0;
MMC5LineCounter = 0;
mmc5psize = mmc5vsize = 3;
@ -1022,22 +1021,23 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) {
MMC5battery = battery;
if (battery) {
info->SaveGame[0] = WRAM;
uint32 saveGameSize = 0;
if (info->ines2)
{
info->SaveGameLen[0] = info->battery_wram_size;
saveGameSize = info->battery_wram_size;
}
else
{
//this is more complex than it looks because it MUST BE, I guess. is there an assumption that only 8KB of 16KB is battery backed? That's NES mappers for you
//I added 64KB for the new 64KB homebrews
if (wsize <= 16)
info->SaveGameLen[0] = 8192;
saveGameSize = 8192;
else if(wsize == 64)
info->SaveGameLen[0] = 64*1024;
saveGameSize = 64*1024;
else
info->SaveGameLen[0] = 32768;
saveGameSize = 32768;
}
info->addSaveGameBuf( WRAM, saveGameSize );
}
MMC5HackVROMMask = CHRmask4[0];

View File

@ -429,10 +429,8 @@ void Mapper19_Init(CartInfo *info) {
AddExState(N106_StateRegs, ~0, 0, 0);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = 8192;
info->SaveGame[1] = IRAM;
info->SaveGameLen[1] = 128;
info->addSaveGameBuf( WRAM, 8192 );
info->addSaveGameBuf( IRAM, 128 );
}
}

View File

@ -320,8 +320,7 @@ void UNLOneBus_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
}
}

View File

@ -54,8 +54,7 @@ void SA9602B_Init(CartInfo *info) {
GenMMC3_Init(info, 512, 0, 0, 0);
pwrap = SA9602BPW;
mmc3opts |= 2;
info->SaveGame[0] = UNIFchrrama;
info->SaveGameLen[0] = 32 * 1024;
info->addSaveGameBuf( UNIFchrrama, 32 * 1024 );
info->Power = SA9602BPower;
AddExState(EXPREGS, 2, 0, "EXPR");
}

View File

@ -24,7 +24,7 @@ static uint8 preg[8];
static uint8 IRQa;
static int16 IRQCount, IRQLatch;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
/*
static uint8 *CHRRAM = NULL;
static uint32 CHRRAMSIZE;
@ -187,8 +187,7 @@ void UNLSB2000_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -21,7 +21,7 @@
#include "mapinc.h"
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
unsigned int *GetKeyboard(void); // FIXME: 10/28 - now implemented in SDL as well. should we rename this to a FCEUI_* function?
@ -90,8 +90,7 @@ void Transformer_Init(CartInfo *info) {
WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE);
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
}

View File

@ -1,7 +1,7 @@
/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
* Copyright (C) 2014 CaitSith2
* Copyright (C) 2014 CaitSith2, 2022 Cluster
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,7 +19,7 @@
*/
/*
* Roms still using NES 1.0 format should be loaded as 32K CHR RAM.
* Roms still using NES 1.0 format should be loaded as 8K CHR RAM.
* Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present.
* UNIF doesn't have this problem, because unique board names can define this information.
* The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K
@ -28,6 +28,7 @@
* Known games to use this board are:
* Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled)
* Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled)
* Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled)
* Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space),
* it otherwise functions identically.
*/
@ -35,211 +36,159 @@
#include "mapinc.h"
#include "../ines.h"
static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false;
const int ROM_CHIP = 0x00;
const int CFI_CHIP = 0x10;
const int FLASH_CHIP = 0x11;
const int FLASH_SECTOR_SIZE = 4 * 1024;
static uint8 flash_save, flash_state, flash_id_mode, latche, bus_conflict;
static uint16 latcha;
static uint8 *flashdata;
static uint32 *flash_write_count;
static uint8 *FlashPage[32];
//static uint32 *FlashWriteCountPage[32];
//static uint8 flashloaded = false;
static uint8 *flash_data;
static uint16 flash_buffer_a[10];
static uint8 flash_buffer_v[10];
static uint8 flash_id[2];
static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank;
static void (*WLSync)(void);
static void (*WHSync)(void);
static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
uint32 AB = A >> 11;
int x;
if (p)
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = p - A;
}
static void UNROM512_Sync() {
int chip;
if (flash_save)
chip = !flash_id_mode ? FLASH_CHIP : CFI_CHIP;
else
for (x = (s >> 1) - 1; x >= 0; x--) {
FlashPage[AB + x] = 0;
}
}
void setfprg16(uint32 A, uint32 V) {
if (PRGsize[0] >= 16384) {
V &= PRGmask16[0];
setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
} else {
uint32 VA = V << 3;
int x;
for (x = 0; x < 8; x++)
setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
}
}
void inc_flash_write_count(uint8 bank, uint32 A)
{
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)])
flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
}
uint32 GetFlashWriteCount(uint8 bank, uint32 A)
{
return flash_write_count[(bank*4) + ((A&0x3000)>>12)];
chip = ROM_CHIP;
setprg16r(chip, 0x8000, latche);
setprg16r(chip, 0xc000, ~0);
setchr8(latche >> 5);
setmirror(MI_0 + ((latche >> 7) & 1));
}
static void StateRestore(int version) {
WHSync();
UNROM512_Sync();
}
static DECLFW(UNROM512LLatchWrite)
static DECLFW(UNROM512FlashWrite)
{
latche = V;
latcha = A;
WLSync();
if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
flash_buffer_a[flash_state] = (A & 0x3FFF) | ((latche & 1) << 14);
flash_buffer_v[flash_state] = V;
flash_state++;
// enter flash ID mode
if ((flash_state == 2) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[1] == 0x5555) && (flash_buffer_v[1] == 0x90)) {
flash_id_mode = 0;
flash_state = 0;
}
// erase sector
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_v[5] == 0x30)) {
int offset = &Page[A >> 11][A] - flash_data;
int sector = offset / FLASH_SECTOR_SIZE;
for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
}
// erase chip
if ((flash_state == 6) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
(flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
(flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
(flash_buffer_a[4] == 0x5555) && (flash_buffer_v[4] == 0x10)) {
memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
FCEU_printf("Flash chip erased.\n");
flash_state = 0;
}
// write byte
if ((flash_state == 4) &&
(flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
(flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
(flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0xA0)) {
int offset = &Page[A >> 11][A] - flash_data;
if (CartBR(A) != 0xFF) {
FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
}
else {
CartBW(A, V);
}
flash_state = 0;
}
}
// not a command
if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
flash_state = 0;
}
// reset
if (V == 0xF0) {
flash_state = 0;
flash_id_mode = 0;
}
UNROM512_Sync();
}
static DECLFW(UNROM512HLatchWrite)
{
if (bus_conflict)
latche = (V == CartBR(A)) ? V : 0;
latche = V & CartBR(A);
else
latche = V;
latcha = A;
WHSync();
}
static DECLFR(UNROM512LatchRead)
{
uint8 flash_id[3]={0xB5,0xB6,0xB7};
if(software_id)
{
if(A&1)
return flash_id[ROM_size>>4];
else
return 0xBF;
}
if(flash_save)
{
if(A < 0xC000)
{
if(GetFlashWriteCount(flash_bank,A))
return FlashPage[A >> 11][A];
}
else
{
if(GetFlashWriteCount(ROM_size-1,A))
return FlashPage[A >> 11][A];
}
}
return Page[A >> 11][A];
UNROM512_Sync();
}
static void UNROM512LatchPower(void) {
latche = latcheinit;
WHSync();
SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead);
latche = 0;
UNROM512_Sync();
SetReadHandler(0x8000, 0xFFFF, CartBR);
if(!flash_save)
SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite);
else
{
SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite);
SetWriteHandler(0x8000,0xBFFF,UNROM512FlashWrite);
SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite);
}
}
static void UNROM512LatchClose(void) {
if(flash_write_count)
FCEU_gfree(flash_write_count);
if(flashdata)
FCEU_gfree(flashdata);
flash_write_count = NULL;
flashdata = NULL;
if(flash_data)
FCEU_gfree(flash_data);
flash_data = NULL;
}
static void UNROM512LSync() {
int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA};
int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55};
int erase_b[5]={1,0,1,1,0};
if(flash_mode==0)
{
if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state]))
{
flash_state++;
if(flash_state == 5)
{
flash_mode=1;
}
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1))
{
flash_state++;
flash_mode=2;
}
else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1))
{
flash_state=0;
software_id=true;
}
else
{
if(latche==0xF0)
software_id=false;
flash_state=0;
}
}
else if(flash_mode==1) //Chip Erase or Sector Erase
{
if(latche==0x30)
{
inc_flash_write_count(flash_bank,latcha);
memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000);
}
else if (latche==0x10)
{
for(uint32 i=0;i<(ROM_size*4);i++)
inc_flash_write_count(i>>2,i<<12);
memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :)
}
flash_state=0;
flash_mode=0;
}
else if(flash_mode==2) //Byte Program
{
if(!GetFlashWriteCount(flash_bank,latcha))
{
inc_flash_write_count(flash_bank,latcha);
memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000);
}
FlashPage[latcha>>11][latcha]&=latche;
flash_state=0;
flash_mode=0;
}
}
static void UNROM512HSync()
static void UNROM512_FlashReset(void)
{
flash_bank=latche&(ROM_size-1);
setprg16(0x8000, flash_bank);
setprg16(0xc000, ~0);
setfprg16(0x8000, flash_bank);
setfprg16(0xC000, ~0);
setchr8r(0, (latche & chrram_mask) >> 5);
setmirror(MI_0+(latche>>7));
if (flash_data)
{
size_t flash_size = PRGsize[ROM_CHIP];
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
}
}
void UNROM512_Init(CartInfo *info) {
flash_state=0;
flash_bank=0;
flash_save=info->battery;
info->Power = UNROM512LatchPower;
info->Close = UNROM512LatchClose;
GameStateRestore = StateRestore;
if(info->vram_size == 8192)
chrram_mask = 0;
else if (info->vram_size == 16384)
chrram_mask = 0x20;
else
chrram_mask = 0x60;
flash_state = 0;
flash_id_mode = 0;
flash_save = info->battery;
bus_conflict = !info->battery; // Is it required by any game?
int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2);
switch (mirror)
@ -258,28 +207,29 @@ void UNROM512_Init(CartInfo *info) {
break;
}
bus_conflict = !info->battery;
latcheinit = 0;
WLSync = UNROM512LSync;
WHSync = UNROM512HSync;
info->Power = UNROM512LatchPower;
info->Close = UNROM512LatchClose;
GameStateRestore = StateRestore;
if(flash_save)
{
flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000);
flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32));
info->SaveGame[0] = (uint8*)flash_write_count;
info->SaveGame[1] = flashdata;
info->SaveGameLen[0] = ROM_size*4*sizeof(uint32);
info->SaveGameLen[1] = ROM_size*0x4000;
AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT");
AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA");
AddExState(&flash_state,1,0,"FLASH_STATE");
AddExState(&flash_mode,1,0,"FLASH_MODE");
AddExState(&flash_bank,1,0,"FLASH_BANK");
AddExState(&latcha,2,0,"LATA");
// Allocate memory for flash
size_t flash_size = PRGsize[ROM_CHIP];
flash_data = (uint8*)FCEU_gmalloc(flash_size);
// Copy ROM to flash data
for (size_t i = 0; i < flash_size; i++) {
flash_data[i] = PRGptr[ROM_CHIP][i];
}
SetupCartPRGMapping(FLASH_CHIP, flash_data, flash_size, 1);
info->addSaveGameBuf( flash_data, flash_size, UNROM512_FlashReset );
flash_id[0] = 0xBF;
flash_id[1] = 0xB5 + (ROM_size >> 4);
SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0);
AddExState(flash_data, flash_size, 0, "FLSH");
AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
AddExState(&flash_id_mode, sizeof(flash_id_mode), 0, "FLMD");
AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
}
AddExState(&latche, 1, 0, "LATC");
AddExState(&bus_conflict, 1, 0, "BUSC");
AddExState(&latcha, sizeof(latcha), 0, "LATA");
AddExState(&latche, sizeof(latche), 0, "LATC");
AddExState(&bus_conflict, sizeof(bus_conflict), 0, "BUSC");
}

View File

@ -23,7 +23,7 @@
static bool isPirate;
static uint8 is22, reg1mask, reg2mask;
static uint16 IRQCount;
static uint8 IRQLatch, IRQa;
static uint8 IRQLatch, IRQa, IRQMode;
static uint8 prgreg[2], chrreg[8];
static uint16 chrhi[8];
static uint8 regcmd, irqcmd, mirr, big_bank;
@ -45,6 +45,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 2, "IRQC" },
{ &IRQLatch, 1, "IRQL" },
{ &IRQa, 1, "IRQA" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@ -115,7 +116,7 @@ static DECLFW(VRC24Write) {
case 0x9003: regcmd = V; Sync(); break;
case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xF0; IRQLatch |= V & 0xF; break;
case 0xF001: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0x0F; IRQLatch |= V << 4; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQMode = V & 4; IRQa = V & 2; irqcmd = V & 1; break;
case 0xF003: X6502_IRQEnd(FCEU_IQEXT); IRQa = irqcmd; break;
}
}
@ -136,16 +137,28 @@ static void VRC24Power(void) {
void VRC24IRQHook(int a) {
#define LCYCS 341
if (IRQa) {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
if (IRQMode) {
acount += a;
while (acount > 0) {
acount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
acount += a * 3;
if (acount >= LCYCS) {
while (acount >= LCYCS) {
acount -= LCYCS;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
}
}
}
}
@ -172,8 +185,7 @@ static void VRC24_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if(info->battery) {
info->SaveGame[0]=WRAM;
info->SaveGameLen[0]=WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -254,11 +254,10 @@ void QTAi_Init(CartInfo *info) {
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
// note, only extrnal cart's SRAM is battery backed, the the part on the main cartridge is just
// an additional work ram. so we may save only half here, but I forgot what part is saved lol, will
// find out later.
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -25,10 +25,10 @@
static uint8 is26;
static uint8 prg[2], chr[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
static SFORMAT StateRegs[] =
{
@ -40,6 +40,7 @@ static SFORMAT StateRegs[] =
{ &IRQLatch, 1, "IRQL" },
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ &IRQMode, 1, "IRQM" },
{ 0 }
};
@ -109,6 +110,7 @@ static DECLFW(VRC6Write) {
case 0xE003: chr[7] = V; Sync(); break;
case 0xF000: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF001:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@ -132,13 +134,25 @@ static void VRC6Power(void) {
static void VRC6IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@ -365,8 +379,7 @@ void Mapper26_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
AddExState(&StateRegs, ~0, 0, 0);

View File

@ -21,10 +21,10 @@
#include "mapinc.h"
static uint8 vrc7idx, preg[3], creg[8], mirr;
static uint8 IRQLatch, IRQa, IRQd;
static uint8 IRQLatch, IRQa, IRQd, IRQMode;
static int32 IRQCount, CycleCount;
static uint8 *WRAM = NULL;
static uint32 WRAMSIZE;
static uint32 WRAMSIZE=0;
#include "emu2413.h"
@ -44,6 +44,7 @@ static SFORMAT StateRegs[] =
{ &IRQCount, 4, "IRQC" },
{ &CycleCount, 4, "CYCC" },
{ (void**)VRC7Sound_saveptr, sizeof(*VRC7Sound) | FCEUSTATE_INDIRECT, "VRC7" },
{ &IRQMode, 1, "IRQM" },
{0}
};
@ -134,6 +135,7 @@ static DECLFW(VRC7Write) {
case 0xE000: mirr = V & 3; Sync(); break;
case 0xE010: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
case 0xF000:
IRQMode = V & 4;
IRQa = V & 2;
IRQd = V & 1;
if (V & 2)
@ -165,13 +167,25 @@ static void VRC7Close(void)
static void VRC7IRQHook(int a) {
if (IRQa) {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
if (IRQMode) {
CycleCount += a;
while (CycleCount > 0) {
CycleCount--;
IRQCount++;
if (IRQCount & 0x100) {
X6502_IRQBegin(FCEU_IQEXT);
IRQCount = IRQLatch;
}
}
} else {
CycleCount += a * 3;
while(CycleCount >= 341) {
CycleCount -= 341;
IRQCount++;
if (IRQCount == 0x100) {
IRQCount = IRQLatch;
X6502_IRQBegin(FCEU_IQEXT);
}
}
}
}
@ -190,8 +204,7 @@ void Mapper85_Init(CartInfo *info) {
SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1);
AddExState(WRAM, WRAMSIZE, 0, "WRAM");
if (info->battery) {
info->SaveGame[0] = WRAM;
info->SaveGameLen[0] = WRAMSIZE;
info->addSaveGameBuf( WRAM, WRAMSIZE );
}
GameStateRestore = StateRestore;
VRC7_ESI();

View File

@ -540,19 +540,28 @@ void FCEU_GeniePower(void) {
}
void FCEU_SaveGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) {
void FCEU_SaveGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty())
{
FILE *sp;
std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav");
if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL) {
if ((sp = FCEUD_UTF8fopen(soot, "wb")) == NULL)
{
FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n", soot.c_str());
} else {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x]) {
fwrite(LocalHWInfo->SaveGame[x], 1,
LocalHWInfo->SaveGameLen[x], sp);
}
else
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
fwrite(LocalHWInfo->SaveGame[x].bufptr, 1,
LocalHWInfo->SaveGame[x].buflen, sp);
}
}
fclose(sp);
}
}
}
@ -560,25 +569,46 @@ void FCEU_SaveGameSave(CartInfo *LocalHWInfo) {
// hack, movie.cpp has to communicate with this function somehow
int disableBatteryLoading = 0;
void FCEU_LoadGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0] && !disableBatteryLoading) {
void FCEU_LoadGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty() && !disableBatteryLoading)
{
FILE *sp;
std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav");
sp = FCEUD_UTF8fopen(soot, "rb");
if (sp != NULL) {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x])
fread(LocalHWInfo->SaveGame[x], 1, LocalHWInfo->SaveGameLen[x], sp);
if (sp != NULL)
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
if ( fread(LocalHWInfo->SaveGame[x].bufptr, 1, LocalHWInfo->SaveGame[x].buflen, sp) != LocalHWInfo->SaveGame[x].buflen )
{
FCEU_printf("Warning save game data read came up short!\n");
}
}
}
fclose(sp);
}
}
}
//clears all save memory. call this if you want to pretend the saveram has been reset (it doesnt touch what is on disk though)
void FCEU_ClearGameSave(CartInfo *LocalHWInfo) {
if (LocalHWInfo->battery && LocalHWInfo->SaveGame[0]) {
for (int x = 0; x < 4; x++)
if (LocalHWInfo->SaveGame[x])
memset(LocalHWInfo->SaveGame[x], 0, LocalHWInfo->SaveGameLen[x]);
void FCEU_ClearGameSave(CartInfo *LocalHWInfo)
{
if (LocalHWInfo->battery && !LocalHWInfo->SaveGame.empty())
{
for (size_t x = 0; x < LocalHWInfo->SaveGame.size(); x++)
{
if (LocalHWInfo->SaveGame[x].bufptr)
{
memset(LocalHWInfo->SaveGame[x].bufptr, 0, LocalHWInfo->SaveGame[x].buflen);
}
if (LocalHWInfo->SaveGame[x].resetFunc)
{
LocalHWInfo->SaveGame[x].resetFunc();
}
}
}
}

View File

@ -1,20 +1,46 @@
#ifndef CART_H
#define CART_H
typedef struct {
#include <vector>
struct CartInfo
{
// Set by mapper/board code:
void (*Power)(void);
void (*Reset)(void);
void (*Close)(void);
uint8 *SaveGame[4]; // Pointers to memory to save/load.
uint32 SaveGameLen[4]; // How much memory to save/load.
struct SaveGame_t
{
uint8 *bufptr; // Pointer to memory to save/load.
uint32 buflen; // How much memory to save/load.
void (*resetFunc)(void); // Callback to reset save game memory
SaveGame_t(void)
: bufptr(nullptr), buflen(0), resetFunc(nullptr)
{
}
};
std::vector <SaveGame_t> SaveGame;
void addSaveGameBuf( uint8* bufptrIn, uint32 buflenIn, void (*resetFuncIn)(void) = nullptr )
{
SaveGame_t tmp;
tmp.bufptr = bufptrIn;
tmp.buflen = buflenIn;
tmp.resetFunc = resetFuncIn;
SaveGame.push_back( tmp );
}
// Set by iNES/UNIF loading code.
int mirror; // As set in the header or chunk.
// iNES/UNIF specific. Intended
// to help support games like "Karnov"
// that are not really MMC3 but are
// set to mapper 4.
// iNES/UNIF specific. Intended
// to help support games like "Karnov"
// that are not really MMC3 but are
// set to mapper 4.
int mirrorAs2Bits;
int battery; // Presence of an actual battery.
int ines2;
int submapper; // Submappers as defined by NES 2.0
@ -26,7 +52,33 @@ typedef struct {
uint32 CRC32; // Should be set by the iNES/UNIF loading
// code, used by mapper/board code, maybe
// other code in the future.
} CartInfo;
CartInfo(void)
{
clear();
}
void clear(void)
{
Power = nullptr;
Reset = nullptr;
Close = nullptr;
SaveGame.clear();
mirror = 0;
mirrorAs2Bits = 0;
battery = 0;
ines2 = 0;
submapper = 0;
wram_size = 0;
battery_wram_size = 0;
vram_size = 0;
battery_vram_size = 0;
memset( MD5, 0, sizeof(MD5));
CRC32 = 0;
};
};
extern CartInfo *currCartInfo;

View File

@ -58,8 +58,17 @@ void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p)
CheatRPtrs[AB+x]=p-A;
}
// Cheat change event callback. Called whenever cheat map is changed or recalculated.
static void (*cheatsChangeEventCB)(void*) = nullptr;
static void* cheatsChangeEventUserData = nullptr;
CHEATF_SUBFAST SubCheats[256] = { 0 };
void FCEU_SetCheatChangeEventCallback( void (*func)(void*), void* userData )
{
cheatsChangeEventCB = func;
cheatsChangeEventUserData = userData;
}
CHEATF_SUBFAST SubCheats[256];
uint32 numsubcheats = 0;
int globalCheatDisabled = 0;
int disableAutoLSCheats = 0;
@ -132,6 +141,11 @@ void RebuildSubCheats(void)
}
FrozenAddressCount = numsubcheats; //Update the frozen address list
// Notify the system of a change
if (cheatsChangeEventCB != nullptr)
{
cheatsChangeEventCB( cheatsChangeEventUserData );
}
}
void FCEU_PowerCheats()
@ -157,22 +171,17 @@ static void CheatMemErr(void)
FCEUD_PrintError("Error allocating memory for cheat data.");
}
int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
void AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
{
struct CHEATF *temp;
if(!(temp = (struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF))))
{
CheatMemErr();
return(0);
}
CHEATF *temp = new CHEATF();
temp->name = strcpy((char*) FCEU_dmalloc(strlen(name) + 1), name);
temp->name = name;
temp->addr = addr;
temp->val = val;
temp->status = status;
temp->compare = compare;
temp->type = type;
temp->next = 0;
temp->next = nullptr;
if(cheats)
{
@ -181,8 +190,6 @@ int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int sta
}
else
cheats = cheatsl = temp;
return (1);
}
/* The "override_existing" parameter is used only in cheat dialog import.
@ -305,14 +312,13 @@ void FCEU_SaveGameCheats(FILE* fp, int release)
fputc(':', fp);
if (next->compare >= 0)
fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name);
fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name.c_str());
else
fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name);
fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name.c_str());
if (release) free(next->name);
struct CHEATF *t = next;
next = next->next;
if (release) free(t);
if (release) delete t;
}
}
@ -332,8 +338,7 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
{
struct CHEATF *last=next;
next=next->next;
free(last->name);
free(last);
delete last;
if(!next) break;
}
cheats=cheatsl=0;
@ -376,14 +381,15 @@ void FCEU_FlushGameCheats(FILE *override, int nosave)
}
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type, int status, bool rebuild)
{
if(!AddCheatEntry(name, addr, val, compare, 1, type))
return 0;
AddCheatEntry(name, addr, val, compare, status, type);
savecheats = 1;
RebuildSubCheats();
if (rebuild)
{
RebuildSubCheats();
}
return 1;
}
@ -414,8 +420,7 @@ int FCEUI_DelCheat(uint32 which)
else
cheats=cheatsl=0; // No (more) cheats.
}
free(cur->name); // Now that all references to this cheat are removed,
free(cur); // free the memory.
delete cur; // free the memory.
break;
} // *END REMOVE THIS CHEAT*
@ -450,18 +455,18 @@ void FCEU_ApplyPeriodicCheats(void)
}
void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
{
struct CHEATF *next=cheats;
while(next)
{
if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break;
if(!callb(next->name.c_str(),next->addr,next->val,next->compare,next->status,next->type,data)) break;
next=next->next;
}
}
int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
{
struct CHEATF *next=cheats;
uint32 x=0;
@ -599,7 +604,7 @@ int FCEUI_DecodePAR(const char *str, int *a, int *v, int *c, int *type)
/* name can be NULL if the name isn't going to be changed. */
/* same goes for a, v, and s(except the values of each one must be <0) */
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int s, int type)
int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int c, int s, int type)
{
struct CHEATF *next = cheats;
uint32 x = 0;
@ -609,13 +614,7 @@ int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int
if(x == which)
{
if(name)
{
char *t;
if((t = (char *)realloc(next->name, strlen(name) + 1)))
strcpy(next->name = t, name);
else
return 0;
}
next->name = *name;
if(a >= 0)
next->addr = a;
if(v >= 0)
@ -661,7 +660,7 @@ int FCEUI_ToggleCheat(uint32 which)
int FCEUI_GlobalToggleCheat(int global_enabled)
{
int _numsubcheats = numsubcheats;
unsigned int _numsubcheats = numsubcheats;
globalCheatDisabled = !global_enabled;
RebuildSubCheats();
return _numsubcheats != numsubcheats;
@ -910,11 +909,7 @@ int FCEU_DeleteAllCheats(void)
while (cur)
{
next = cur->next;
if ( cur->name )
{
free(cur->name);
}
free(cur);
delete cur;
cur = next;
}
cheats = cheatsl = 0;

View File

@ -33,16 +33,24 @@ extern int disableAutoLSCheats;
int FCEU_DisableAllCheats(void);
int FCEU_DeleteAllCheats(void);
typedef struct {
void FCEU_SetCheatChangeEventCallback( void (*func)(void*) = nullptr, void* userData = nullptr );
struct CHEATF_SUBFAST
{
uint16 addr;
uint8 val;
int compare;
readfunc PrevRead;
} CHEATF_SUBFAST;
CHEATF_SUBFAST(void)
{
addr = 0; val = 0; compare = 0; PrevRead = nullptr;
}
};
struct CHEATF {
struct CHEATF *next;
char *name;
std::string name;
uint16 addr;
uint8 val;
int compare; /* -1 for no compare. */

View File

@ -41,6 +41,10 @@
* Value -> 'R' | 'W'
*/
#ifdef GEKKO
#else
#include "types.h"
#include "conddebug.h"
#include "utils/memory.h"
@ -52,17 +56,17 @@
#include <cctype>
uint16 debugLastAddress = 0; // used by 'T' and 'R' conditions
uint8 debugLastOpcode; // used to evaluate 'W' condition
uint8 debugLastOpcode = 0; // used to evaluate 'W' condition
// Next non-whitespace character in string
char next;
static char next = 0;
int ishex(char c)
static int ishex(char c)
{
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
void scan(const char** str)
static void scan(const char** str)
{
do
{
@ -71,40 +75,37 @@ void scan(const char** str)
} while (isspace(next));
}
// Frees a condition and all of it's sub conditions
void freeTree(Condition* c)
{
if (c->lhs) freeTree(c->lhs);
if (c->rhs) freeTree(c->rhs);
free(c);
}
// Generic function to handle all infix operators but the last one in the precedence hierarchy. : '(' E ')'
Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
static Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
{
Condition* t = nextPart(str);
Condition* t1;
Condition* mid;
int op;
if (t == nullptr)
{
return nullptr;
}
while ((op = operators(str)))
{
scan(str);
t1 = nextPart(str);
if (t1 == 0)
if (t1 == nullptr)
{
if(t)
freeTree(t);
delete t;
return 0;
}
mid = (Condition*)FCEU_dmalloc(sizeof(Condition));
if (!mid)
return NULL;
memset(mid, 0, sizeof(Condition));
mid = new Condition();
if (mid == nullptr)
{
delete t;
delete t1;
return nullptr;
}
mid->lhs = t;
mid->rhs = t1;
@ -117,7 +118,7 @@ Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), i
}
// Generic handler for two-character operators
int TwoCharOperator(const char** str, char c1, char c2, int op)
static int TwoCharOperator(const char** str, char c1, char c2, int op)
{
if (next == c1 && **str == c2)
{
@ -131,43 +132,43 @@ int TwoCharOperator(const char** str, char c1, char c2, int op)
}
// Determines if a character is a flag
int isFlag(char c)
static int isFlag(char c)
{
return c == 'N' || c == 'I' || c == 'C' || c == 'V' || c == 'Z' || c == 'B' || c == 'U' || c == 'D';
}
// Determines if a character is a register
int isRegister(char c)
static int isRegister(char c)
{
return c == 'A' || c == 'X' || c == 'Y' || c == 'P' || c == 'S';
}
// Determines if a character is for PC bank
int isPCBank(char c)
static int isPCBank(char c)
{
return c == 'K';
}
// Determines if a character is for Data bank
int isDataBank(char c)
static int isDataBank(char c)
{
return c == 'T';
}
// Determines if a character is for value read
int isValueRead(char c)
static int isValueRead(char c)
{
return c == 'R';
}
// Determines if a character is for value write
int isValueWrite(char c)
static int isValueWrite(char c)
{
return c == 'W';
}
// Reads a hexadecimal number from str
int getNumber(unsigned int* number, const char** str)
static int getNumber(unsigned int* number, const char** str)
{
// char buffer[5];
@ -185,10 +186,10 @@ int getNumber(unsigned int* number, const char** str)
return 1;
}
Condition* Connect(const char** str);
static Condition* Connect(const char** str);
// Handles the following part of the grammar: '(' E ')'
Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
static Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
{
if (next == openPar)
{
@ -216,7 +217,7 @@ Condition* Parentheses(const char** str, Condition* c, char openPar, char closeP
* Check for primitives
* Flags, Registers, Numbers, Addresses and parentheses
*/
Condition* Primitive(const char** str, Condition* c)
static Condition* Primitive(const char** str, Condition* c)
{
if (isFlag(next)) /* Flags */
{
@ -394,24 +395,22 @@ Condition* Primitive(const char** str, Condition* c)
}
/* Handle * and / operators */
Condition* Term(const char** str)
static Condition* Term(const char** str)
{
Condition* t;
Condition* t1;
Condition* mid;
t = (Condition*)FCEU_dmalloc(sizeof(Condition));
t = new Condition();
if (!t)
if (t == nullptr)
{
return NULL;
}
memset(t, 0, sizeof(Condition));
if (!Primitive(str, t))
{
freeTree(t);
delete t;
return 0;
}
@ -421,22 +420,25 @@ Condition* Term(const char** str)
scan(str);
if (!(t1 = (Condition*)FCEU_dmalloc(sizeof(Condition))))
return NULL;
memset(t1, 0, sizeof(Condition));
if ((t1 = new Condition()) == nullptr)
{
delete t;
return nullptr;
}
if (!Primitive(str, t1))
{
freeTree(t);
freeTree(t1);
delete t;
delete t1;
return 0;
}
if (!(mid = (Condition*)FCEU_dmalloc(sizeof(Condition))))
return NULL;
memset(mid, 0, sizeof(Condition));
if ((mid = new Condition()) == nullptr)
{
delete t;
delete t1;
return nullptr;
}
mid->lhs = t;
mid->rhs = t1;
@ -449,7 +451,7 @@ Condition* Term(const char** str)
}
/* Check for + and - operators */
int SumOperators(const char** str)
static int SumOperators(const char** str)
{
switch (next)
{
@ -460,13 +462,13 @@ int SumOperators(const char** str)
}
/* Handle + and - operators */
Condition* Sum(const char** str)
static Condition* Sum(const char** str)
{
return InfixOperator(str, Term, SumOperators);
}
/* Check for <=, =>, ==, !=, > and < operators */
int CompareOperators(const char** str)
static int CompareOperators(const char** str)
{
int val = TwoCharOperator(str, '=', '=', OP_EQ);
if (val) return val;
@ -490,13 +492,13 @@ int CompareOperators(const char** str)
}
/* Handle <=, =>, ==, !=, > and < operators */
Condition* Compare(const char** str)
static Condition* Compare(const char** str)
{
return InfixOperator(str, Sum, CompareOperators);
}
/* Check for || or && operators */
int ConnectOperators(const char** str)
static int ConnectOperators(const char** str)
{
int val = TwoCharOperator(str, '|', '|', OP_OR);
if(val) return val;
@ -508,7 +510,7 @@ int ConnectOperators(const char** str)
}
/* Handle || and && operators */
Condition* Connect(const char** str)
static Condition* Connect(const char** str)
{
return InfixOperator(str, Compare, ConnectOperators);
}
@ -521,6 +523,12 @@ Condition* generateCondition(const char* str)
scan(&str);
c = Connect(&str);
if (!c || next != 0) return 0;
if (!c || next != 0)
{
if (c) delete c;
return 0;
}
else return c;
}
#endif

View File

@ -61,9 +61,28 @@ struct Condition
unsigned int type2;
unsigned int value2;
Condition(void)
{
op = 0;
lhs = rhs = nullptr;
type1 = value1 = 0;
type2 = value2 = 0;
};
~Condition(void)
{
if (lhs)
{
delete lhs;
}
if (rhs)
{
delete rhs;
}
}
};
void freeTree(Condition* c);
Condition* generateCondition(const char* str);
#endif

View File

@ -11,12 +11,14 @@
#include <cstdio>
#include <cstdlib>
static char *aboutString = 0;
static std::string aboutString;
#ifndef FCEUX_BUILD_TIMESTAMP
#define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__
#endif
//#pragma message( "Compiling using C++ Std: " __FCEU_STRINGIZE(__cplusplus) )
// returns a string suitable for use in an aboutbox
const char *FCEUI_GetAboutString(void)
{
@ -26,7 +28,7 @@ const char *FCEUI_GetAboutString(void)
"zeromus, feos\n"
"\n"
"Current Contributors:\n"
"CaH4e3, rainwarrior, owomomo, punkrockguy318\n"
"CaH4e3, rainwarrior, owomomo, punkrockguy318, Cluster\n"
"\n"
"Past Contributors:\n"
"xhainingx, gocha, AnS, mjbudd77\n"
@ -55,14 +57,17 @@ const char *FCEUI_GetAboutString(void)
"\n"
FCEUX_BUILD_TIMESTAMP "\n";
if (aboutString) return aboutString;
if (aboutString.size() > 0) return aboutString.c_str();
const char *compilerString = FCEUD_GetCompilerString();
//allocate the string and concatenate the template with the compiler string
if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1)))
return NULL;
char cppVersion[128];
sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
return aboutString;
snprintf( cppVersion, sizeof(cppVersion), "\nCompiled using C++ Language Standard: %li\n", __cplusplus);
aboutString.assign( aboutTemplate );
aboutString.append( compilerString );
aboutString.append( cppVersion );
return aboutString.c_str();
}

View File

@ -1,3 +1,9 @@
#ifdef GEKKO
int debug_loggingCD = 0;
int StackAddrBackup;
void IncrementInstructionsCounters() {}
#else
/// \file
/// \brief Implements core debugging facilities
#include "types.h"
@ -6,6 +12,7 @@
#include "cart.h"
#include "ines.h"
#include "debug.h"
#include "debugsymboltable.h"
#include "driver.h"
#include "ppu.h"
@ -18,10 +25,23 @@ unsigned int debuggerPageSize = 14;
int vblankScanLines = 0; //Used to calculate scanlines 240-261 (vblank)
int vblankPixel = 0; //Used to calculate the pixels in vblank
int offsetStringToInt(unsigned int type, const char* offsetBuffer)
struct TraceInstructionCallback
{
void (*func)(uint8 *opcode, int size) = nullptr;
TraceInstructionCallback* next = nullptr;
};
static TraceInstructionCallback* traceInstructionCB = nullptr;
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk)
{
int offset = -1;
if (conversionOk)
{
*conversionOk = false;
}
if (sscanf(offsetBuffer,"%7X",(unsigned int *)&offset) == EOF)
{
return -1;
@ -29,18 +49,41 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
if (type & BT_P)
{
if (conversionOk)
{
*conversionOk = (offset >= 0) && (offset < 0x4000);
}
return offset & 0x3FFF;
}
else if (type & BT_S)
{
if (conversionOk)
{
*conversionOk = (offset >= 0) && (offset < 0x100);
}
return offset & 0x00FF;
}
else if (type & BT_R)
{
if (conversionOk)
{
*conversionOk = (offset >= 0);
}
return offset;
}
else // BT_C
{
auto sym = debugSymbolTable.getSymbolAtAnyBank(offsetBuffer);
if (sym)
{
if (conversionOk)
{
*conversionOk = true;
}
return sym->offset() & 0xFFFF;
}
int type = GIT_CART;
if (GameInfo)
@ -48,21 +91,26 @@ int offsetStringToInt(unsigned int type, const char* offsetBuffer)
type = GameInfo->type;
}
if (type == GIT_NSF) { //NSF Breakpoint keywords
if (strcmp(offsetBuffer,"LOAD") == 0) return (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
if (strcmp(offsetBuffer,"INIT") == 0) return (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
if (strcmp(offsetBuffer,"PLAY") == 0) return (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
if (strcmp(offsetBuffer,"LOAD") == 0) offset = (NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh<<8));
else if (strcmp(offsetBuffer,"INIT") == 0) offset = (NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh<<8));
else if (strcmp(offsetBuffer,"PLAY") == 0) offset = (NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh<<8));
}
else if (type == GIT_FDS) { //FDS Breakpoint keywords
if (strcmp(offsetBuffer,"NMI1") == 0) return (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
if (strcmp(offsetBuffer,"NMI2") == 0) return (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
if (strcmp(offsetBuffer,"NMI3") == 0) return (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
if (strcmp(offsetBuffer,"NMI1") == 0) offset = (GetMem(0xDFF6) | (GetMem(0xDFF7)<<8));
else if (strcmp(offsetBuffer,"NMI2") == 0) offset = (GetMem(0xDFF8) | (GetMem(0xDFF9)<<8));
else if (strcmp(offsetBuffer,"NMI3") == 0) offset = (GetMem(0xDFFA) | (GetMem(0xDFFB)<<8));
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xDFFC) | (GetMem(0xDFFD)<<8));
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xDFFE) | (GetMem(0xDFFF)<<8));
}
else { //NES Breakpoint keywords
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) return (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
if (strcmp(offsetBuffer,"RST") == 0) return (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) return (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
if ((strcmp(offsetBuffer,"NMI") == 0) || (strcmp(offsetBuffer,"VBL") == 0)) offset = (GetMem(0xFFFA) | (GetMem(0xFFFB)<<8));
else if (strcmp(offsetBuffer,"RST") == 0) offset = (GetMem(0xFFFC) | (GetMem(0xFFFD)<<8));
else if ((strcmp(offsetBuffer,"IRQ") == 0) || (strcmp(offsetBuffer,"BRK") == 0)) offset = (GetMem(0xFFFE) | (GetMem(0xFFFF)<<8));
}
if (conversionOk)
{
*conversionOk = (offset >= 0) && (offset < 0x10000);
}
}
@ -131,7 +179,7 @@ int checkCondition(const char* condition, int num)
// Remove the old breakpoint condition before adding a new condition.
if (watchpoint[num].cond)
{
freeTree(watchpoint[num].cond);
delete watchpoint[num].cond;
free(watchpoint[num].condText);
watchpoint[num].cond = 0;
watchpoint[num].condText = 0;
@ -145,8 +193,8 @@ int checkCondition(const char* condition, int num)
{
watchpoint[num].cond = c;
watchpoint[num].condText = (char*)malloc(strlen(condition) + 1);
if (!watchpoint[num].condText)
return 0;
if (!watchpoint[num].condText)
return 0;
strcpy(watchpoint[num].condText, condition);
}
else
@ -161,7 +209,7 @@ int checkCondition(const char* condition, int num)
// Remove the old breakpoint condition
if (watchpoint[num].cond)
{
freeTree(watchpoint[num].cond);
delete watchpoint[num].cond;
free(watchpoint[num].condText);
watchpoint[num].cond = 0;
watchpoint[num].condText = 0;
@ -258,7 +306,7 @@ int getBank(int offs)
//Anything over FFFFF will kill it.
//GetNesFileAddress doesn't work well with Unif files
int addr = GetNesFileAddress(offs)-16;
int addr = GetNesFileAddress(offs)-NES_HEADER_SIZE;
if (GameInfo && GameInfo->type==GIT_NSF)
return addr != -1 ? addr / 0x1000 : -1;
@ -270,12 +318,12 @@ int GetNesFileAddress(int A){
if((A < 0x6000) || (A > 0xFFFF))return -1;
result = &Page[A>>11][A]-PRGptr[0];
if((result > (int)(PRGsize[0])) || (result < 0))return -1;
else return result+16; //16 bytes for the header remember
else return result+NES_HEADER_SIZE; //16 bytes for the header remember
}
int GetRomAddress(int A){
int i;
uint8 *p = GetNesPRGPointer(A-=16);
uint8 *p = GetNesPRGPointer(A-=NES_HEADER_SIZE);
for(i = 16;i < 32;i++){
if((&Page[i][i<<11] <= p) && (&Page[i][(i+1)<<11] > p))break;
}
@ -512,7 +560,7 @@ void LogCDData(uint8 *opcode, uint16 A, int size)
case 4: memop = 0x20; break;
}
if ((j = GetPRGAddress(A)) != -1)
if (((j = GetPRGAddress(A)) != -1) && (opcode[0] != 0x4C) && (opcode[0] != 0x6C))
{
if (opwrite[opcode[0]] == 0)
{
@ -527,7 +575,12 @@ void LogCDData(uint8 *opcode, uint16 A, int size)
newDataHit = true;
}
}
else
// Unclear why the write destination's access types gets reset for FDS...
// See:
// - https://github.com/TASEmulators/fceux/commit/a4fa6225a04b5ab8d3dfca3fc9abd7190bceec85
// - https://github.com/TASEmulators/fceux/commit/b10b6254c3d5c9519a85cb4382cdb22846d2e394
// - https://github.com/TASEmulators/fceux/commit/67942accc72149ae028d58f36419b64ea8651db9?diff=unified&w=1
else if(GameInfo && GameInfo->type == GIT_FDS)
{
if (cdloggerdata[j] & 1)
{
@ -642,7 +695,8 @@ uint16 StackNextIgnorePC = 0xFFFF;
///fires a breakpoint
static void breakpoint(uint8 *opcode, uint16 A, int size) {
int i, j, romAddrPC;
int i, romAddrPC;
unsigned int j;
uint8 brk_type;
uint8 stackop=0;
uint8 stackopstartaddr=0,stackopendaddr=0;
@ -783,7 +837,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
{
if (watchpoint[i].flags & BT_R)
{
if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == romAddrPC) )
if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == static_cast<unsigned int>(romAddrPC)) )
{
BREAKHIT(i);
}
@ -814,7 +868,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// TXS and TSX only deal with the pointer.
if (watchpoint[i].flags & stackop)
{
for (j = (stackopstartaddr|0x0100); j <= (stackopendaddr|0x0100); j++)
for (j = (stackopstartaddr|0x0100); j <= (static_cast<unsigned int>(stackopendaddr)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
@ -840,7 +894,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// Pushes to stack
if (watchpoint[i].flags & WP_W)
{
for (j = (X.S|0x0100); j < (StackAddrBackup|0x0100); j++)
for (j = (X.S|0x0100); j < (static_cast<unsigned int>(StackAddrBackup)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
@ -858,7 +912,7 @@ static void breakpoint(uint8 *opcode, uint16 A, int size) {
// Pulls from stack
if (watchpoint[i].flags & WP_R)
{
for (j = (StackAddrBackup|0x0100); j < (X.S|0x0100); j++)
for (j = (StackAddrBackup|0x0100); j < (static_cast<unsigned int>(X.S)|0x0100); j++)
{
if (watchpoint[i].endaddress)
{
@ -954,5 +1008,83 @@ void DebugCycle()
if(debug_loggingCD)
LogCDData(opcode, A, size);
#ifdef __WIN_DRIVER__
FCEUD_TraceInstruction(opcode, size);
#else
// Use callback pointer that can be null checked, this saves on the overhead
// of calling a function for every instruction when we aren't tracing.
if (traceInstructionCB != nullptr)
{
auto* cb = traceInstructionCB;
while (cb != nullptr)
{
cb->func(opcode, size);
cb = cb->next;
}
}
#endif
}
void* FCEUI_TraceInstructionRegister( void (*func)(uint8*,int) )
{
TraceInstructionCallback* cb = nullptr;
if (traceInstructionCB == nullptr)
{
cb = traceInstructionCB = new TraceInstructionCallback();
cb->func = func;
}
else
{
cb = traceInstructionCB;
while (cb != nullptr)
{
if (cb->func == func)
{
// This function has already been registered, don't double add.
return nullptr;
}
if (cb->next == nullptr)
{
auto* newCB = new TraceInstructionCallback();
newCB->func = func;
cb->next = newCB;
return newCB;
}
cb = cb->next;
}
}
return cb;
}
bool FCEUI_TraceInstructionUnregisterHandle( void* handle )
{
TraceInstructionCallback* cb, *cb_prev, *cb_handle;
cb_handle = static_cast<TraceInstructionCallback*>(handle);
cb_prev = nullptr;
cb = traceInstructionCB;
while (cb != nullptr)
{
if (cb == cb_handle)
{ // Match we are going to remove from list and delete
if (cb_prev != nullptr)
{
cb_prev = cb->next;
}
else
{
traceInstructionCB = cb->next;
}
delete cb;
return true;
}
cb_prev = cb;
cb = cb->next;
}
return false;
}
#endif

View File

@ -172,7 +172,10 @@ DebuggerState &FCEUI_Debugger();
//#define WRITE_BREAKPOINT 16
//#define EXECUTE_BREAKPOINT 32
int offsetStringToInt(unsigned int type, const char* offsetBuffer);
int offsetStringToInt(unsigned int type, const char* offsetBuffer, bool *conversionOk = nullptr);
unsigned int NewBreak(const char* name, int start, int end, unsigned int type, const char* condition, unsigned int num, bool enable);
void* FCEUI_TraceInstructionRegister( void (*func)(uint8*,int) );
bool FCEUI_TraceInstructionUnregisterHandle( void* handle );
#endif

View File

@ -346,7 +346,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf)
hasPlayRecIcon = true;
}
if(FCEUI_EmulationPaused())
if( EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER) )
drawstatus(XBuf-ClipSidesOffset,3,28,hasPlayRecIcon?-16:0);
}
}

View File

@ -23,7 +23,7 @@ ArchiveScanRecord FCEUD_ScanArchive(std::string fname);
const char *FCEUD_GetCompilerString();
//This makes me feel dirty for some reason.
void FCEU_printf(const char *format, ...);
void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
#define FCEUI_printf FCEU_printf
//Video interface
@ -192,12 +192,12 @@ void TaseditorManualFunction(void);
int32 FCEUI_GetDesiredFPS(void);
void FCEUI_SaveSnapshot(void);
void FCEUI_SaveSnapshotAs(void);
void FCEU_DispMessage(const char *format, int disppos, ...);
void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 3 );
#define FCEUI_DispMessage FCEU_DispMessage
int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type);
int FCEUI_DecodeGG(const char *str, int *a, int *v, int *c);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type);
int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type, int status = 1, bool rebuild = true);
int FCEUI_DelCheat(uint32 which);
int FCEUI_ToggleCheat(uint32 which);
int FCEUI_GlobalToggleCheat(int global_enable);
@ -207,10 +207,10 @@ void FCEUI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a,
void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data), void *data);
void FCEUI_CheatSearchBegin(void);
void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2);
void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare,int s, int type);
int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int compare,int s, int type);
void FCEUI_CheatSearchShowExcluded(void);
void FCEUI_CheatSearchSetCurrentAsOriginal(void);
@ -254,6 +254,8 @@ void FCEUI_VSUniToggleDIP(int w);
uint8 FCEUI_VSUniGetDIPs(void);
void FCEUI_VSUniSetDIP(int w, int state);
void FCEUI_VSUniCoin(void);
void FCEUI_VSUniCoin2(void);
void FCEUI_VSUniService(void);
void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make it an EMUCMDFN
//int FCEUI_FDSEject(void);
@ -271,6 +273,10 @@ void FCEUI_ClearEmulationFrameStepped();
void FCEUI_SetEmulationPaused(int val);
///toggles the paused bit (bit0) for EmulationPaused. caused FCEUD_DebugUpdate() to fire if the emulation pauses
void FCEUI_ToggleEmulationPause();
void FCEUI_PauseForDuration(int secs);
int FCEUI_PauseFramesRemaining();
void FCEUI_SetNetPlayPause(bool value);
bool FCEUI_GetNetPlayPause();
//indicates whether input aids should be drawn (such as crosshairs, etc; usually in fullscreen mode)
bool FCEUD_ShouldDrawInputAids();
@ -361,7 +367,11 @@ bool FCEU_IsValidUI(EFCEUI ui);
#ifdef __cplusplus
extern "C"
{
#endif
FILE *FCEUI_UTF8fopen_C(const char *n, const char *m);
#ifdef __cplusplus
} // extern C
#endif
FILE *FCEUI_UTF8fopen_C(const char *n, const char *m);
#endif //__DRIVER_H_

View File

@ -116,26 +116,31 @@ bool movieSubtitles = true; //Toggle for displaying movie subtitles
bool DebuggerWasUpdated = false; //To prevent the debugger from updating things without being updated.
bool AutoResumePlay = false;
char romNameWhenClosingEmulator[2048] = {0};
static unsigned int pauseTimer = 0;
FCEUGI::FCEUGI()
: filename(0),
archiveFilename(0)
{
//printf("%08x",opsize); // WTF?!
}
FCEUGI::~FCEUGI()
{
if (name)
{
free(name);
name = nullptr;
}
if (filename)
{
free(filename);
filename = NULL;
filename = nullptr;
}
if (archiveFilename)
{
free(archiveFilename);
archiveFilename = NULL;
archiveFilename = nullptr;
}
}
@ -181,7 +186,6 @@ static void FCEU_CloseGame(void)
}
#ifdef __WIN_DRIVER__
extern char LoadedRomFName[2048];
if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))
FCEUD_PrintError("Couldn't store debugging data");
CDLoggerROMClosed();
@ -193,7 +197,7 @@ static void FCEU_CloseGame(void)
if (GameInfo->name) {
free(GameInfo->name);
GameInfo->name = NULL;
GameInfo->name = nullptr;
}
if (GameInfo->type != GIT_NSF) {
@ -209,6 +213,8 @@ static void FCEU_CloseGame(void)
GameInterface(GI_CLOSE);
FCEU_StateRecorderStop();
FCEUI_StopMovie();
ResetExState(0, 0);
@ -221,15 +227,15 @@ static void FCEU_CloseGame(void)
FCEU_CloseGenie();
delete GameInfo;
GameInfo = NULL;
GameInfo = nullptr;
currFrameCounter = 0;
//Reset flags for Undo/Redo/Auto Savestating //adelikat: TODO: maybe this stuff would be cleaner as a struct or class
lastSavestateMade[0] = 0;
lastSavestateMade.clear();
undoSS = false;
redoSS = false;
lastLoadstateMade[0] = 0;
lastLoadstateMade.clear();
undoLS = false;
redoLS = false;
AutoSS = false;
@ -240,7 +246,7 @@ static void FCEU_CloseGame(void)
uint64 timestampbase;
FCEUGI *GameInfo = NULL;
FCEUGI *GameInfo = nullptr;
void (*GameInterface)(GI h);
void (*GameStateRestore)(int version);
@ -271,9 +277,13 @@ int AutosaveFrequency = 256; // Number of frames between autosaves
int EnableAutosave = 0;
///a wrapper for unzip.c
extern "C" FILE *FCEUI_UTF8fopen_C(const char *n, const char *m) {
return ::FCEUD_UTF8fopen(n, m);
}
extern "C"
{
FILE *FCEUI_UTF8fopen_C(const char *n, const char *m)
{
return ::FCEUD_UTF8fopen(n, m);
}
} // extern C
static DECLFW(BNull) {
}
@ -301,8 +311,8 @@ void FlushGenieRW(void) {
}
free(AReadG);
free(BWriteG);
AReadG = NULL;
BWriteG = NULL;
AReadG = nullptr;
BWriteG = nullptr;
RWWrap = 0;
}
}
@ -368,7 +378,7 @@ static void AllocBuffers() {
static void FreeBuffers() {
FCEU_free(RAM);
RAM = NULL;
RAM = nullptr;
}
//------
@ -395,14 +405,14 @@ void ResetGameLoaded(void) {
if (GameInfo) FCEU_CloseGame();
EmulationPaused = 0; //mbg 5/8/08 - loading games while paused was bad news. maybe this fixes it
GameStateRestore = 0;
PPU_hook = NULL;
GameHBIRQHook = NULL;
FFCEUX_PPURead = NULL;
FFCEUX_PPUWrite = NULL;
PPU_hook = nullptr;
GameHBIRQHook = nullptr;
FFCEUX_PPURead = nullptr;
FFCEUX_PPUWrite = nullptr;
if (GameExpSound.Kill)
GameExpSound.Kill();
memset(&GameExpSound, 0, sizeof(GameExpSound));
MapIRQHook = NULL;
MapIRQHook = nullptr;
MMC5Hack = 0;
PEC586Hack = 0;
QTAIHack = 0;
@ -421,7 +431,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
//----------
//attempt to open the files
FCEUFILE *fp;
char fullname[2048]; // this name contains both archive name and ROM file name
std::string fullname; // this name contains both archive name and ROM file name
int lastpal = PAL;
int lastdendy = dendy;
@ -431,7 +441,7 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
// currently there's only one situation:
// the user clicked cancel form the open from archive dialog
int userCancel = 0;
fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions, &userCancel);
fp = FCEU_fopen(name, LoadedRomFNamePatchToUse[0] ? LoadedRomFNamePatchToUse : nullptr, "rb", 0, -1, romextensions, &userCancel);
if (!fp)
{
@ -443,16 +453,19 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
}
else if (fp->archiveFilename != "")
{
strcpy(fullname, fp->archiveFilename.c_str());
strcat(fullname, "|");
strcat(fullname, fp->filename.c_str());
} else
strcpy(fullname, name);
fullname.assign(fp->archiveFilename.c_str());
fullname.append("|");
fullname.append(fp->filename.c_str());
}
else
{
fullname.assign(name);
}
// reset loaded game BEFORE it's loading.
ResetGameLoaded();
//file opened ok. start loading.
FCEU_printf("Loading %s...\n\n", fullname);
FCEU_printf("Loading %s...\n\n", fullname.c_str());
GetFileBase(fp->filename.c_str());
//reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing
MasterRomInfoParams = TMasterRomInfoParams();
@ -464,12 +477,12 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
FCEU_CloseGame();
GameInfo = new FCEUGI();
memset( (void*)GameInfo, 0, sizeof(FCEUGI));
GameInfo->filename = strdup(fp->filename.c_str());
if (fp->archiveFilename != "")
GameInfo->archiveFilename = strdup(fp->archiveFilename.c_str());
GameInfo->archiveCount = fp->archiveCount;
GameInfo->archiveIndex = fp->archiveIndex;
GameInfo->soundchan = 0;
GameInfo->soundrate = 0;
@ -484,16 +497,16 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
bool FCEUXLoad(const char *name, FCEUFILE * fp);
int load_result;
load_result = iNESLoad(fullname, fp, OverwriteVidMode);
load_result = iNESLoad(fullname.c_str(), fp, OverwriteVidMode);
if (load_result == LOADER_INVALID_FORMAT)
{
load_result = NSFLoad(fullname, fp);
load_result = NSFLoad(fullname.c_str(), fp);
if (load_result == LOADER_INVALID_FORMAT)
{
load_result = UNIFLoad(fullname, fp);
load_result = UNIFLoad(fullname.c_str(), fp);
if (load_result == LOADER_INVALID_FORMAT)
{
load_result = FDSLoad(fullname, fp);
load_result = FDSLoad(fullname.c_str(), fp);
}
}
}
@ -502,7 +515,6 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
#ifdef __WIN_DRIVER__
// ################################## Start of SP CODE ###########################
extern char LoadedRomFName[2048];
extern int loadDebugDataFailed;
if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str())))
@ -591,6 +603,12 @@ FCEUGI *FCEUI_LoadGameVirtual(const char *name, int OverwriteVidMode, bool silen
}
FCEU_fclose(fp);
if ( FCEU_StateRecorderIsEnabled() )
{
FCEU_StateRecorderStart();
}
return GameInfo;
}
@ -723,8 +741,12 @@ extern unsigned int frameAdvHoldTimer;
///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame
void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) {
#ifndef GEKKO
FCEU_PROFILE_FUNC(prof, "Emulate Single Frame");
#endif
//skip initiates frame skip if 1, or frame skip and sound skip if 2
int r, ssize;
FCEU_MAYBE_UNUSED int r;
int ssize;
JustFrameAdvanced = false;
@ -741,7 +763,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
{
EmulationPaused = EMULATIONPAUSED_FA;
}
if (frameAdvance_Delay_count < frameAdvanceDelayScaled)
if ( static_cast<unsigned int>(frameAdvance_Delay_count) < frameAdvanceDelayScaled)
{
frameAdvance_Delay_count++;
}
@ -753,6 +775,22 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
#endif
}
if (EmulationPaused & EMULATIONPAUSED_TIMER)
{
if (pauseTimer > 0)
{
pauseTimer--;
}
else
{
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
}
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
{
EmulationPaused &= ~EMULATIONPAUSED_TIMER;
}
}
if (EmulationPaused & EMULATIONPAUSED_FA)
{
// the user is holding Frame Advance key
@ -776,7 +814,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
RefreshThrottleFPS();
}
#endif
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
if (EmulationPaused & (EMULATIONPAUSED_PAUSED | EMULATIONPAUSED_TIMER | EMULATIONPAUSED_NETPLAY) )
{
// emulator is paused
memcpy(XBuf, XBackBuf, 256*256);
@ -790,6 +828,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
AutoFire();
UpdateAutosave();
FCEU_StateRecorderUpdate();
#ifdef _S9XLUA_H
FCEU_LuaFrameBoundary();
@ -1253,8 +1292,52 @@ void FCEUI_FrameAdvanceEnd(void) {
}
void FCEUI_FrameAdvance(void) {
frameAdvanceRequested = true;
frameAdvance_Delay_count = 0;
frameAdvanceRequested = true;
}
void FCEUI_PauseForDuration(int secs)
{
int framesPerSec;
// If already paused, do nothing
if (EmulationPaused & EMULATIONPAUSED_PAUSED)
{
return;
}
if (PAL || dendy)
{
framesPerSec = 50;
}
else
{
framesPerSec = 60;
}
pauseTimer = framesPerSec * secs;
EmulationPaused |= EMULATIONPAUSED_TIMER;
}
int FCEUI_PauseFramesRemaining(void)
{
return (EmulationPaused & EMULATIONPAUSED_TIMER) ? pauseTimer : 0;
}
bool FCEUI_GetNetPlayPause()
{
return (EmulationPaused & EMULATIONPAUSED_NETPLAY) ? true : false;
}
void FCEUI_SetNetPlayPause(bool value)
{
if (value)
{
EmulationPaused |= EMULATIONPAUSED_NETPLAY;
}
else
{
EmulationPaused &= ~EMULATIONPAUSED_NETPLAY;
}
}
static int AutosaveCounter = 0;
@ -1271,7 +1354,7 @@ void UpdateAutosave(void) {
FCEUSS_Save(f, false);
AutoSS = true; //Flag that an auto-savestate was made
free(f);
f = NULL;
f = nullptr;
AutosaveStatus[AutosaveIndex] = 1;
}
}
@ -1285,7 +1368,7 @@ void FCEUI_RewindToLastAutosave(void) {
f = strdup(FCEU_MakeFName(FCEUMKF_AUTOSTATE, AutosaveIndex, 0).c_str());
FCEUSS_Load(f);
free(f);
f = NULL;
f = nullptr;
//Set pointer to previous available slot
if (AutosaveStatus[(AutosaveIndex + AutosaveQty - 1) % AutosaveQty] == 1) {

View File

@ -139,10 +139,10 @@ extern FCEUS FSettings;
bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists
void FCEU_PrintError(const char *format, ...);
void FCEU_printf(const char *format, ...);
void FCEU_DispMessage(const char *format, int disppos, ...);
void FCEU_DispMessageOnMovie(const char *format, ...);
void FCEU_PrintError( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 3 );
void FCEU_DispMessageOnMovie( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
void FCEU_TogglePPU();
void SetNESDeemph_OldHacky(uint8 d, int force);
@ -181,8 +181,11 @@ extern uint8 vsdip;
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#define EMULATIONPAUSED_PAUSED 1
#define EMULATIONPAUSED_FA 2
#define EMULATIONPAUSED_PAUSED 0x01
#define EMULATIONPAUSED_TIMER 0x02
#define EMULATIONPAUSED_FA 0x04
#define EMULATIONPAUSED_NETPLAY 0x08
#define FRAMEADVANCE_DELAY_DEFAULT 10
#define NES_HEADER_SIZE 16

View File

@ -29,6 +29,7 @@
#include "state.h"
#include "file.h"
#include "cart.h"
#include "ines.h"
#include "netplay.h"
#include "driver.h"
#include "movie.h"
@ -578,21 +579,30 @@ void FDSSoundReset(void) {
static DECLFW(FDSWrite) {
switch (A) {
case 0x4020:
X6502_IRQEnd(FCEU_IQEXT);
IRQLatch &= 0xFF00;
IRQLatch |= V;
break;
case 0x4021:
X6502_IRQEnd(FCEU_IQEXT);
IRQLatch &= 0xFF;
IRQLatch |= V << 8;
break;
case 0x4022:
X6502_IRQEnd(FCEU_IQEXT);
IRQCount = IRQLatch;
IRQa = V & 3;
if (FDSRegs[3] & 1) {
IRQa = V & 0x03;
if (IRQa & IRQ_Enabled) {
IRQCount = IRQLatch;
} else {
X6502_IRQEnd(FCEU_IQEXT);
}
}
break;
case 0x4023:
if (!(V & 0x01)) {
IRQa &= ~IRQ_Enabled;
X6502_IRQEnd(FCEU_IQEXT);
X6502_IRQEnd(FCEU_IQEXT2);
}
break;
case 0x4023: break;
case 0x4024:
if (mapperFDS_diskinsert && ~mapperFDS_control & 0x04) {
@ -859,8 +869,8 @@ int FDSLoad(const char *name, FCEUFILE *fp) {
FDSSoundStateAdd();
for (x = 0; x < TotalSides; x++) {
char temp[5];
sprintf(temp, "DDT%d", x);
char temp[8];
snprintf(temp, sizeof(temp), "DDT%d", x);
AddExState(diskdata[x], 65500, 0, temp);
}

View File

@ -65,7 +65,7 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp)
if(!ips) return;
char* buf = (char*)FCEU_dmalloc(fp->size);
char* buf = (char*)FCEU_malloc(fp->size);
memcpy(buf,fp->EnsureMemorystream()->buf(),fp->size);
@ -104,13 +104,7 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp)
if((offset+size)>(uint32)fp->size)
{
// Probably a little slow.
char *newbuf=(char *)realloc(buf,offset+size);
if(!newbuf)
{
free(buf); buf=NULL;
FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n",count);
goto end;
}
char *newbuf=(char *)FCEU_realloc(buf,offset+size);
buf=newbuf;
memset(buf+fp->size,0,offset+size-fp->size);
fp->size=offset+size;
@ -129,17 +123,15 @@ void ApplyIPS(FILE *ips, FCEUFILE* fp)
if((offset+size)>(uint32)fp->size)
{
// Probably a little slow.
char *newbuf=(char *)realloc(buf,offset+size);
if(!newbuf)
{
free(buf); buf=NULL;
FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n",count);
goto end;
}
char *newbuf=(char *)FCEU_realloc(buf,offset+size);
buf=newbuf;
memset(buf+fp->size,0,offset+size-fp->size);
fp->size=offset+size;
}
if ( fread(buf+offset,1,size,ips) != static_cast<size_t>(size) )
{
FCEU_printf(" Warn IPS data read came up short!\n");
}
fread(buf+offset,1,size,ips);
}
count++;
}
@ -152,7 +144,7 @@ end:
std::string FCEU_MakeIpsFilename(FileBaseInfo fbi) {
char ret[FILENAME_MAX] = "";
sprintf(ret,"%s" PSS "%s%s.ips",fbi.filebasedirectory.c_str(),fbi.filebase.c_str(),fbi.ext.c_str());
snprintf(ret, sizeof(ret), "%s" PSS "%s%s.ips",fbi.filebasedirectory.c_str(),fbi.filebase.c_str(),fbi.ext.c_str());
return ret;
}
@ -322,9 +314,9 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, const char *mode, cha
{
uint32 magic;
magic = fp->fgetc();
magic|=fp->fgetc()<<8;
magic|=fp->fgetc()<<16;
magic = (fp->fgetc() & 0x00ff);
magic|= (fp->fgetc() & 0x00ff) << 8;
magic|= (fp->fgetc() & 0x00ff) << 16;
fp->fseek(0,SEEK_SET);
if(magic==0x088b1f) {
@ -334,7 +326,7 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, const char *mode, cha
if(gzfile) {
delete fp;
int size;
size_t size;
for(size=0; gzgetc(gzfile) != EOF; size++) {}
EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(size);
gzseek(gzfile,0,SEEK_SET);
@ -453,13 +445,12 @@ int FCEU_fisarchive(FCEUFILE *fp)
std::string GetMfn() //Retrieves the movie filename from curMovieFilename (for adding to savestate and auto-save files)
{
std::string movieFilenamePart;
extern char curMovieFilename[512];
if(*curMovieFilename)
{
if (!curMovieFilename.empty())
{
char drv[PATH_MAX], dir[PATH_MAX], name[PATH_MAX], ext[PATH_MAX];
splitpath(curMovieFilename,drv,dir,name,ext);
splitpath(curMovieFilename.c_str(),drv,dir,name,ext);
movieFilenamePart = std::string(".") + name;
}
}
return movieFilenamePart;
}
@ -491,7 +482,7 @@ void FCEUI_SetDirOverride(int which, char *n)
va_list ap;
int ret;
if(!(*strp=(char*)FCEU_dmalloc(2048))) //mbg merge 7/17/06 cast to char*
if(!(*strp=(char*)FCEU_malloc(2048))) //mbg merge 7/17/06 cast to char*
return(0);
va_start(ap,fmt);
ret=vsnprintf(*strp,2048,fmt,ap);
@ -623,9 +614,9 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1)
struct stat fileInfo;
do {
if(odirs[FCEUIOD_MOVIES])
sprintf(ret,"%s" PSS "%s-%d.fm2",odirs[FCEUIOD_MOVIES],FileBase, id1);
snprintf(ret, sizeof(ret), "%s" PSS "%s-%d.fm2",odirs[FCEUIOD_MOVIES],FileBase, id1);
else
sprintf(ret,"%s" PSS "movies" PSS "%s-%d.fm2",BaseDirectory.c_str(),FileBase, id1);
snprintf(ret, sizeof(ret), "%s" PSS "movies" PSS "%s-%d.fm2",BaseDirectory.c_str(),FileBase, id1);
id1++;
} while (stat(ret, &fileInfo) == 0);
break;
@ -649,19 +640,19 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1)
if(odirs[FCEUIOD_STATES])
{
sprintf(ret,"%s" PSS "%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
} else
{
sprintf(ret,"%s" PSS "fcs" PSS "%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "fcs" PSS "%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1);
}
if(stat(ret,&tmpstat)==-1)
{
if(odirs[FCEUIOD_STATES])
{
sprintf(ret,"%s" PSS "%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "%s%s.fc%d",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
} else
{
sprintf(ret,"%s" PSS "fcs" PSS "%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "fcs" PSS "%s%s.fc%d",BaseDirectory.c_str(),FileBase,mfn,id1);
}
}
}
@ -670,46 +661,46 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1)
{
if(odirs[FCEUIOD_STATES])
{
sprintf(ret,"%s" PSS "%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase);
} else
{
sprintf(ret,"%s" PSS "fcs" PSS "%s-resume.fcs",BaseDirectory.c_str(),FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "fcs" PSS "%s-resume.fcs",BaseDirectory.c_str(),FileBase);
}
if(stat(ret,&tmpstat)==-1)
{
if(odirs[FCEUIOD_STATES])
{
sprintf(ret,"%s" PSS "%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "%s-resume.fcs",odirs[FCEUIOD_STATES],FileBase);
} else
{
sprintf(ret,"%s" PSS "fcs" PSS "%s-resume.fcs",BaseDirectory.c_str(),FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "fcs" PSS "%s-resume.fcs",BaseDirectory.c_str(),FileBase);
}
}
}
break;
case FCEUMKF_SNAP:
if(odirs[FCEUIOD_SNAPS])
sprintf(ret,"%s" PSS "%s-%d.%s",odirs[FCEUIOD_SNAPS],FileBase,id1,cd1);
snprintf(ret, sizeof(ret), "%s" PSS "%s-%d.%s",odirs[FCEUIOD_SNAPS],FileBase,id1,cd1);
else
sprintf(ret,"%s" PSS "snaps" PSS "%s-%d.%s",BaseDirectory.c_str(),FileBase,id1,cd1);
snprintf(ret, sizeof(ret), "%s" PSS "snaps" PSS "%s-%d.%s",BaseDirectory.c_str(),FileBase,id1,cd1);
break;
case FCEUMKF_FDS:
if(odirs[FCEUIOD_NV])
sprintf(ret,"%s" PSS "%s.fds",odirs[FCEUIOD_NV],FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "%s.fds",odirs[FCEUIOD_NV],FileBase);
else
sprintf(ret,"%s" PSS "sav" PSS "%s.fds",BaseDirectory.c_str(),FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "sav" PSS "%s.fds",BaseDirectory.c_str(),FileBase);
break;
case FCEUMKF_SAV:
if(odirs[FCEUIOD_NV])
sprintf(ret,"%s" PSS "%s.%s",odirs[FCEUIOD_NV],FileBase,cd1);
snprintf(ret, sizeof(ret), "%s" PSS "%s.%s",odirs[FCEUIOD_NV],FileBase,cd1);
else
sprintf(ret,"%s" PSS "sav" PSS "%s.%s",BaseDirectory.c_str(),FileBase,cd1);
snprintf(ret, sizeof(ret), "%s" PSS "sav" PSS "%s.%s",BaseDirectory.c_str(),FileBase,cd1);
if(stat(ret,&tmpstat)==-1)
{
if(odirs[FCEUIOD_NV])
sprintf(ret,"%s" PSS "%s.%s",odirs[FCEUIOD_NV],FileBase,cd1);
snprintf(ret, sizeof(ret), "%s" PSS "%s.%s",odirs[FCEUIOD_NV],FileBase,cd1);
else
sprintf(ret,"%s" PSS "sav" PSS "%s.%s",BaseDirectory.c_str(),FileBase,cd1);
snprintf(ret, sizeof(ret), "%s" PSS "sav" PSS "%s.%s",BaseDirectory.c_str(),FileBase,cd1);
}
break;
case FCEUMKF_AUTOSTATE:
@ -727,52 +718,52 @@ std::string FCEU_MakeFName(int type, int id1, const char *cd1)
if(odirs[FCEUIOD_STATES])
{
sprintf(ret,"%s" PSS "%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
} else
{
sprintf(ret,"%s" PSS "fcs" PSS "%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "fcs" PSS "%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1);
}
if(stat(ret,&tmpstat)==-1)
{
if(odirs[FCEUIOD_STATES])
{
sprintf(ret,"%s" PSS "%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "%s%s-autosave%d.fcs",odirs[FCEUIOD_STATES],FileBase,mfn,id1);
} else
{
sprintf(ret,"%s" PSS "fcs" PSS "%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1);
snprintf(ret, sizeof(ret), "%s" PSS "fcs" PSS "%s%s-autosave%d.fcs",BaseDirectory.c_str(),FileBase,mfn,id1);
}
}
break;
case FCEUMKF_CHEAT:
if(odirs[FCEUIOD_CHEATS])
sprintf(ret,"%s" PSS "%s.cht",odirs[FCEUIOD_CHEATS],FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "%s.cht",odirs[FCEUIOD_CHEATS],FileBase);
else
sprintf(ret,"%s" PSS "cheats" PSS "%s.cht",BaseDirectory.c_str(),FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "cheats" PSS "%s.cht",BaseDirectory.c_str(),FileBase);
break;
case FCEUMKF_IPS:
strcpy(ret,FCEU_MakeIpsFilename(CurrentFileBase()).c_str());
break;
case FCEUMKF_GGROM:sprintf(ret,"%s" PSS "gg.rom",BaseDirectory.c_str());break;
case FCEUMKF_GGROM:snprintf(ret, sizeof(ret), "%s" PSS "gg.rom",BaseDirectory.c_str());break;
case FCEUMKF_FDSROM:
if(odirs[FCEUIOD_FDSROM])
sprintf(ret,"%s" PSS "disksys.rom",odirs[FCEUIOD_FDSROM]);
snprintf(ret, sizeof(ret), "%s" PSS "disksys.rom",odirs[FCEUIOD_FDSROM]);
else
sprintf(ret,"%s" PSS "disksys.rom",BaseDirectory.c_str());
snprintf(ret, sizeof(ret), "%s" PSS "disksys.rom",BaseDirectory.c_str());
break;
case FCEUMKF_PALETTE:sprintf(ret,"%s" PSS "%s.pal",BaseDirectory.c_str(),FileBase);break;
case FCEUMKF_PALETTE:snprintf(ret, sizeof(ret), "%s" PSS "%s.pal",BaseDirectory.c_str(),FileBase);break;
case FCEUMKF_MOVIEGLOB:
//these globs use ??? because we can load multiple formats
if(odirs[FCEUIOD_MOVIES])
sprintf(ret,"%s" PSS "*.???",odirs[FCEUIOD_MOVIES]);
snprintf(ret, sizeof(ret), "%s" PSS "*.???",odirs[FCEUIOD_MOVIES]);
else
sprintf(ret,"%s" PSS "movies" PSS "*.???",BaseDirectory.c_str());
snprintf(ret, sizeof(ret), "%s" PSS "movies" PSS "*.???",BaseDirectory.c_str());
break;
case FCEUMKF_MOVIEGLOB2:sprintf(ret,"%s" PSS "*.???",BaseDirectory.c_str());break;
case FCEUMKF_MOVIEGLOB2:snprintf(ret, sizeof(ret), "%s" PSS "*.???",BaseDirectory.c_str());break;
case FCEUMKF_STATEGLOB:
if(odirs[FCEUIOD_STATES])
sprintf(ret,"%s" PSS "%s*.fc?",odirs[FCEUIOD_STATES],FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "%s*.fc?",odirs[FCEUIOD_STATES],FileBase);
else
sprintf(ret,"%s" PSS "fcs" PSS "%s*.fc?",BaseDirectory.c_str(),FileBase);
snprintf(ret, sizeof(ret), "%s" PSS "fcs" PSS "%s*.fc?",BaseDirectory.c_str(),FileBase);
break;
}

View File

@ -35,7 +35,7 @@ struct FCEUFILE {
int archiveIndex;
//the size of the file
int size;
size_t size;
//whether the file is contained in an archive
bool isArchive() { return archiveCount > 0; }

View File

@ -37,7 +37,7 @@ void SexyFilter2(int32 *in, int32 count)
while(count--)
{
int64 dropcurrent;
dropcurrent=((*in<<16)-acc)>>3;
dropcurrent=( int32(uint32(*in)<<16)-acc)>>3;
acc+=dropcurrent;
*in=acc>>16;
@ -167,10 +167,10 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover)
void MakeFilters(int32 rate)
{
const int32 *tabs[6]={C44100NTSC,C44100PAL,C48000NTSC,C48000PAL,C96000NTSC,
C96000PAL};
const int32 *sq2tabs[6]={SQ2C44100NTSC,SQ2C44100PAL,SQ2C48000NTSC,SQ2C48000PAL,
SQ2C96000NTSC,SQ2C96000PAL};
const int32 *tabs[8]={C44100NTSC,C44100PAL,C48000NTSC,C48000PAL,C96000NTSC,
C96000PAL, nullptr, nullptr};
const int32 *sq2tabs[8]={SQ2C44100NTSC,SQ2C44100PAL,SQ2C48000NTSC,SQ2C48000PAL,
SQ2C96000NTSC,SQ2C96000PAL, nullptr, nullptr};
const int32 *tmp;
int32 x;

View File

@ -16,12 +16,34 @@ enum EGIV
GIV_USER = 2, //What was set by FCEUI_SetVidSys().
};
enum EGIPPU
{
GIPPU_USER = 0,
GIPPU_RP2C04_0001 = 1,
GIPPU_RP2C04_0002 = 2,
GIPPU_RP2C04_0003 = 3,
GIPPU_RP2C04_0004 = 4,
GIPPU_RC2C03B = 5,
GIPPU_RC2C05_01 = 6,
GIPPU_RC2C05_02 = 7,
GIPPU_RC2C05_03 = 8,
GIPPU_RC2C05_04 = 9,
};
enum EGIVS
{
EGIVS_NORMAL = 0,
EGIVS_RBI = 1, // RBI Baseball protection
EGIVS_TKO = 2, // TKO Boxing protection
EGIVS_XEVIOUS = 3, // Super Xevious protection
};
enum ESIS
{
SIS_NONE = 0,
SIS_DATACH = 1,
SIS_NWC = 2,
SIS_VSUNISYSTEM = 3,
SIS_VSUNISYSTEM = 3, // Is it used?
SIS_NSF = 4,
};
@ -44,6 +66,8 @@ enum ESI
SI_COUNT = SI_LCDCOMP_ZAPPER
};
inline const char* ESI_Name(ESI esi)
{
static const char * const names[] =
@ -129,24 +153,29 @@ struct FCEUGI
FCEUGI();
~FCEUGI();
uint8 *name; //Game name, UTF8 encoding
int mappernum;
uint8 *name = nullptr; //Game name, UTF8 encoding
int mappernum = 0;
EGIT type;
EGIV vidsys; //Current emulated video system;
ESI input[2]; //Desired input for emulated input ports 1 and 2; -1 for unknown desired input.
ESIFC inputfc; //Desired Famicom expansion port device. -1 for unknown desired input.
ESIS cspecial; //Special cart expansion: DIP switches, barcode reader, etc.
EGIT type = GIT_CART;
EGIV vidsys = GIV_USER; //Current emulated video system;
ESI input[2] = { SI_UNSET, SI_UNSET }; //Desired input for emulated input ports 1 and 2; -1 for unknown desired input.
ESIFC inputfc = SIFC_UNSET; //Desired Famicom expansion port device. -1 for unknown desired input.
ESIS cspecial = SIS_NONE; //Special cart expansion: DIP switches, barcode reader, etc.
EGIPPU vs_ppu = GIPPU_USER; //PPU type for Vs. System
EGIVS vs_type = EGIVS_NORMAL; //Vs. System type
uint8 vs_cswitch = SIS_NONE; // Switch first and second controllers for Vs. System
MD5DATA MD5;
//mbg 6/8/08 - ???
int soundrate; //For Ogg Vorbis expansion sound wacky support. 0 for default.
int soundchan; //Number of sound channels.
int soundrate = 0; //For Ogg Vorbis expansion sound wacky support. 0 for default.
int soundchan = 0; //Number of sound channels.
char* filename;
char* archiveFilename;
int archiveCount;
char* filename = nullptr;
char* archiveFilename = nullptr;
int archiveCount = 0; // the number of files that were in the archive
int archiveIndex = -1; // the index of the file within the archive
bool loadedFromTmpFile = false; // Was loaded from temporary file, file most likely no longer exists
};
#endif

View File

@ -129,9 +129,9 @@
{0xd4a76b07, 79, 0}, /* F-15 City Wars*/
{0x1eb4a920, 79, 1}, /* Double Strike */
{0x3e1271d5, 79, 1}, /* Tiles of Fate */
{0x0da5e32e, 87, 1}, /* Urusei Yatsura */
{0xd2699893, 88, 0}, /* Dragon Spirit */
{0xbb7c5f7a, 89, 8}, /* Mito Koumon or something similar */
{0x0da5e32e, 101, -1}, /* new Uruusey Yatsura */
{0x8eab381c, 113, 1}, /* Death Bots */
{0x6a03d3f3, 114, -1},
{0x0d98db53, 114, -1}, /* Pocahontas */

View File

@ -37,6 +37,7 @@
#include "cheat.h"
#include "vsuni.h"
#include "driver.h"
#include "input.h"
#include <cstdio>
#include <cstdlib>
@ -48,6 +49,7 @@ extern SFORMAT FCEUVSUNI_STATEINFO[];
uint8 *trainerpoo = NULL;
uint8 *ROM = NULL;
uint8 *VROM = NULL;
uint8 *MiscROM = NULL;
uint8 *ExtraNTARAM = NULL;
iNES_HEADER head;
@ -58,9 +60,12 @@ static CartInfo iNESCart;
#endif
uint8 Mirroring = 0;
uint8 MirroringAs2bits = 0;
uint32 ROM_size = 0;
uint32 VROM_size = 0;
char LoadedRomFName[2048]; //mbg merge 7/17/06 added
uint32 MiscROM_size = 0;
char LoadedRomFName[4096]; //mbg merge 7/17/06 added
char LoadedRomFNamePatchToUse[4096];
static int CHRRAMSize = -1;
static int iNES_Init(int num);
@ -111,11 +116,11 @@ void iNESGI(GI h) { //bbit edited: removed static keyword
if (iNESCart.Close)
iNESCart.Close();
if (ROM) {
free(ROM);
FCEU_free(ROM);
ROM = NULL;
}
if (VROM) {
free(VROM);
FCEU_free(VROM);
VROM = NULL;
}
if (trainerpoo) {
@ -145,6 +150,9 @@ struct INPSEL {
ESIFC inputfc;
};
/*
* Function to set input controllers based on CRC
*/
static void SetInput(void) {
static struct INPSEL moo[] =
{
@ -157,9 +165,9 @@ static void SetInput(void) {
{0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World
{0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting
{0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Dai Undoukai
{0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Duck Hunt
{0x24598791, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Duck Hunt
{0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Edu (As)
{0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Educational Computer 2000
{0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Educational Computer 2000
{0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88
{0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A
{0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a
@ -219,6 +227,7 @@ static void SetInput(void) {
{0x67b126b9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FAMINETSYS }, // Famicom Network System
{0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET }
};
int x = 0;
while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) {
@ -232,6 +241,64 @@ static void SetInput(void) {
}
}
struct INPSEL_NES20 {
uint8 expansion_id;
ESI input1;
ESI input2;
ESIFC inputfc;
};
/*
* Function to set input controllers based on NES 2.0 header
*/
extern int eoptions;
static void SetInputNes20(uint8 expansion) {
static struct INPSEL_NES20 moo[] =
{
{0x01, SI_GAMEPAD, SI_GAMEPAD, SIFC_UNSET }, // Standard NES/Famicom controllers
{0x02, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // NES Four Score/Satellite with two additional standard controllers
{0x03, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, // Famicom Four Players Adapter with two additional standard controllers using the "simple" protocol
{0x04, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // Vs. System (1P via $4016)
{0x05, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // Vs. System (1P via $4017)
{0x07, SI_ZAPPER, SI_NONE, SIFC_NONE }, // Vs. Zapper
{0x08, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Zapper ($4017)
{0x0A, SI_UNSET, SI_UNSET, SIFC_SHADOW }, // Bandai Hyper Shot Lightgun
{0x0B, SI_UNSET, SI_POWERPADA, SIFC_UNSET }, // Power Pad Side A
{0x0C, SI_UNSET, SI_POWERPADB, SIFC_UNSET }, // Power Pad Side B
{0x0D, SI_UNSET, SI_UNSET, SIFC_FTRAINERA }, // Family Trainer Side A
{0x0E, SI_UNSET, SI_UNSET, SIFC_FTRAINERB }, // Family Trainer Side B
{0x0F, SI_UNSET, SI_ARKANOID, SIFC_UNSET }, // Arkanoid Vaus Controller (NES)
{0x10, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid Vaus Controller (Famicom)
{0x12, SI_UNSET, SI_UNSET, SIFC_HYPERSHOT }, // Konami Hyper Shot Controller
{0x15, SI_UNSET, SI_UNSET, SIFC_MAHJONG }, // Jissen Mahjong Controller
{0x17, SI_UNSET, SI_UNSET, SIFC_OEKAKIDS }, // Oeka Kids Tablet
{0x18, SI_UNSET, SI_UNSET, SIFC_BWORLD }, // Sunsoft Barcode Battler
{0x1B, SI_UNSET, SI_UNSET, SIFC_TOPRIDER }, // Top Rider (Inflatable Bicycle)
{0x23, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC Keyboard plus Famicom Data Recorder
{0x24, SI_UNSET, SI_UNSET, SIFC_PEC586KB }, // Dongda PEC-586 Keyboard
{0x26, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor Keyboard
//{0x27, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Subor Keyboard plus mouse (3x8-bit protocol)
{0x28, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Subor Keyboard plus mouse (24-bit protocol)
{0x29, SI_UNSET, SI_SNES_MOUSE, SIFC_UNSET }, // SNES Mouse
{0, SI_UNSET, SI_UNSET, SIFC_UNSET }
};
int x = 0;
if (expansion == 0x02)
eoptions |= 32768; // dirty hack to enable Four-Score
GameInfo->vs_cswitch = expansion == 0x05;
while (moo[x].expansion_id) {
if (moo[x].expansion_id == expansion) {
GameInfo->input[0] = moo[x].input1;
GameInfo->input[1] = moo[x].input2;
GameInfo->inputfc = moo[x].inputfc;
break; }
x++;
}
}
#define INESB_INCOMPLETE 1
#define INESB_CORRUPT 2
#define INESB_HACKED 4
@ -280,7 +347,7 @@ static const TMasterRomInfo sMasterRomInfo[] = {
const TMasterRomInfo* MasterRomInfo;
TMasterRomInfoParams MasterRomInfoParams;
static void CheckHInfo(void) {
static void CheckHInfo(uint64 partialmd5) {
/* ROM images that have the battery-backed bit set in the header that really
don't have battery-backed RAM is not that big of a problem, so I'll
treat this differently by only listing games that should have battery-backed RAM.
@ -331,14 +398,9 @@ static void CheckHInfo(void) {
#include "ines-correct.h"
};
int32 tofix = 0, x, mask;
uint64 partialmd5 = 0;
for (x = 0; x < 8; x++)
partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8);
CheckBad(partialmd5);
MasterRomInfo = NULL;
for (int i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) {
for (size_t i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) {
const TMasterRomInfo& info = sMasterRomInfo[i];
if (info.md5lower != partialmd5)
continue;
@ -347,7 +409,7 @@ static void CheckHInfo(void) {
if (!info.params) break;
std::vector<std::string> toks = tokenize_str(info.params, ",");
for (int j = 0; j < (int)toks.size(); j++) {
for (size_t j = 0; j < toks.size(); j++) {
std::vector<std::string> parts = tokenize_str(toks[j], "=");
MasterRomInfoParams[parts[0]] = parts[1];
}
@ -417,21 +479,33 @@ static void CheckHInfo(void) {
if (MapperNo == 99)
Mirroring = 2;
if (tofix) {
char gigastr[768];
strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");
if (tofix)
{
char tmpStr[128];
std::string gigastr;
gigastr.reserve(768);
gigastr.assign("The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");
if (tofix & 1)
sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo);
if (tofix & 2) {
{
snprintf(tmpStr, sizeof(tmpStr), "The mapper number should be set to %d. ", MapperNo);
gigastr.append(tmpStr);
}
if (tofix & 2)
{
const char *mstr[3] = { "Horizontal", "Vertical", "Four-screen" };
sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]);
snprintf(tmpStr, sizeof(tmpStr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]);
gigastr.append(tmpStr);
}
if (tofix & 4)
strcat(gigastr, "The battery-backed bit should be set. ");
{
gigastr.append("The battery-backed bit should be set. ");
}
if (tofix & 8)
strcat(gigastr, "This game should not have any CHR ROM. ");
strcat(gigastr, "\n");
FCEU_printf("%s", gigastr);
{
gigastr.append("This game should not have any CHR ROM. ");
}
gigastr.append("\n");
FCEU_printf("%s", gigastr.c_str());
}
}
@ -477,7 +551,7 @@ BMAPPINGLocal bmap[] = {
{"100-in-1", 15, Mapper15_Init},
{"BANDAI 24C02", 16, Mapper16_Init},
{"FFE Rev. B", 17, Mapper17_Init},
{"JALECO SS880006", 18, Mapper18_Init}, // JF-NNX (EB89018-30007) boards
{"JALECO SS88006", 18, Mapper18_Init}, // JF-NNX (EB89018-30007) boards
{"Namcot 106", 19, Mapper19_Init},
// {"", 20, Mapper20_Init},
{"Konami VRC2/VRC4 A", 21, Mapper21_Init},
@ -487,7 +561,7 @@ BMAPPINGLocal bmap[] = {
{"Konami VRC2/VRC4 D", 25, Mapper25_Init},
{"Konami VRC6 Rev. B", 26, Mapper26_Init},
{"CC-21 MI HUN CHE", 27, UNLCC21_Init}, // Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards
{"", 28, Mapper28_Init},
{"ACTION 53", 28, Mapper28_Init},
{"RET-CUFROM", 29, Mapper29_Init},
{"UNROM 512", 30, UNROM512_Init},
{"infiniteneslives-NSF", 31, Mapper31_Init},
@ -560,7 +634,7 @@ BMAPPINGLocal bmap[] = {
// {"", 98, Mapper98_Init},
{"VS Uni/Dual- system", 99, Mapper99_Init},
// {"", 100, Mapper100_Init},
{"", 101, Mapper101_Init},
// {"", 101, Mapper101_Init}, // Deprecated, dupe
// {"", 102, Mapper102_Init},
{"FDS DOKIDOKI FULL", 103, Mapper103_Init},
// {"", 104, Mapper104_Init},
@ -577,7 +651,7 @@ BMAPPINGLocal bmap[] = {
{"MMC3 PIRATE A", 115, Mapper115_Init},
{"MMC1/MMC3/VRC PIRATE",116, UNLSL12_Init},
{"FUTURE MEDIA BOARD", 117, Mapper117_Init},
{"TSKROM", 118, TKSROM_Init},
{"TKSROM", 118, TKSROM_Init},
{"NES-TQROM", 119, Mapper119_Init},
{"FDS TOBIDASE", 120, Mapper120_Init},
{"MMC3 PIRATE PROT. A", 121, Mapper121_Init},
@ -585,7 +659,7 @@ BMAPPINGLocal bmap[] = {
{"MMC3 PIRATE H2288", 123, UNLH2288_Init},
// {"", 124, Mapper124_Init},
{"FDS LH32", 125, LH32_Init},
{"PowerJoy 84-in-1", 126, Mapper126_Init},
// {"", 126, Mapper126_Init},
// {"", 127, Mapper127_Init},
// {"", 128, Mapper128_Init},
// {"", 129, Mapper129_Init},
@ -610,11 +684,11 @@ BMAPPINGLocal bmap[] = {
{"SA0037", 148, SA0037_Init},
{"SA0036", 149, SA0036_Init},
{"S74LS374N", 150, S74LS374N_Init},
{"", 151, Mapper151_Init},
{"", 152, Mapper152_Init},
// {"", 151, Mapper151_Init}, // Deprecated, dupe
{"BA SARA DISCRETE", 152, Mapper152_Init},
{"BANDAI SRAM", 153, Mapper153_Init}, // Bandai board 16 with SRAM instead of EEPROM
{"", 154, Mapper154_Init},
{"", 155, Mapper155_Init},
{"MMC1A", 155, Mapper155_Init}, // No WRAM disable
{"", 156, Mapper156_Init},
{"BANDAI BARCODE", 157, Mapper157_Init},
// {"", 158, Mapper158_Init},
@ -633,21 +707,21 @@ BMAPPINGLocal bmap[] = {
{"", 171, Mapper171_Init},
{"", 172, Mapper172_Init},
{"", 173, Mapper173_Init},
// {"", 174, Mapper174_Init},
{"NTDec 5-in-1", 174, Mapper174_Init},
{"", 175, Mapper175_Init},
{"BMCFK23C", 176, BMCFK23C_Init}, // zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it.
{"", 177, Mapper177_Init},
{"", 178, Mapper178_Init},
// {"", 179, Mapper179_Init},
{"", 180, Mapper180_Init},
{"UNROM+74HC08", 180, Mapper180_Init}, // Crazy Climber
{"", 181, Mapper181_Init},
// {"", 182, Mapper182_Init}, // Deprecated, dupe
{"", 183, Mapper183_Init},
{"", 184, Mapper184_Init},
{"", 185, Mapper185_Init},
{"", 186, Mapper186_Init},
{"SUNSOFT-K", 184, Mapper184_Init}, // Sunsoft-1 mapper
{"CNROM+SECURITY", 185, Mapper185_Init},
{"STUDY BOX", 186, Mapper186_Init},
{"", 187, Mapper187_Init},
{"", 188, Mapper188_Init},
{"KARAOKE STUDIO", 188, Mapper188_Init},
{"", 189, Mapper189_Init},
{"", 190, Mapper190_Init},
{"", 191, Mapper191_Init},
@ -664,7 +738,7 @@ BMAPPINGLocal bmap[] = {
{"", 202, Mapper202_Init},
{"", 203, Mapper203_Init},
{"", 204, Mapper204_Init},
{"", 205, Mapper205_Init},
{"JC-016-2", 205, Mapper205_Init},
{"NAMCOT 108 Rev. C", 206, Mapper206_Init}, // Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3
{"TAITO X1-005 Rev. B", 207, Mapper207_Init},
{"", 208, Mapper208_Init},
@ -677,7 +751,7 @@ BMAPPINGLocal bmap[] = {
{"", 215, UNL8237_Init},
{"", 216, Mapper216_Init},
{"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper
{"Magic Floor", 218, Mapper218_Init},
{"", 218, Mapper218_Init},
{"UNLA9746", 219, UNLA9746_Init},
{"Debug Mapper", 220, QTAi_Init},
{"UNLN625092", 221, UNLN625092_Init},
@ -687,8 +761,8 @@ BMAPPINGLocal bmap[] = {
{"", 225, Mapper225_Init},
{"BMC 22+20-in-1", 226, Mapper226_Init},
{"", 227, Mapper227_Init},
{"", 228, Mapper228_Init},
{"", 229, Mapper229_Init},
{"ACTIVE ENTERPRISES", 228, Mapper228_Init},
{"BMC 31-in-1", 229, Mapper229_Init},
{"BMC Contra+22-in-1", 230, Mapper230_Init},
{"", 231, Mapper231_Init},
{"BMC QUATTRO", 232, Mapper232_Init},
@ -714,7 +788,7 @@ BMAPPINGLocal bmap[] = {
{"SAN GUO ZHI PIRATE", 252, Mapper252_Init},
{"DRAGON BALL PIRATE", 253, Mapper253_Init},
{"", 254, Mapper254_Init},
// {"", 255, Mapper255_Init}, // No good dumps for this mapper
{"", 255, Mapper255_Init}, // dupe of 225
//-------- Mappers 256-511 is the Supplementary Multilingual Plane ----------
//-------- Mappers 512-767 is the Supplementary Ideographic Plane -----------
@ -731,9 +805,17 @@ BMAPPINGLocal bmap[] = {
{"F-15 MMC3 Based", 259, BMCF15_Init},
{"HP10xx/H20xx Boards", 260, BMCHPxx_Init},
{"810544-CA-1", 261, BMC810544CA1_Init},
{"SMD132/SMD133", 268, SMD132_SMD133_Init},
{"AA6023/AA6023B", 268, AA6023_Init},
{"OK-411", 361, GN45_Init},
{"GN-45", 366, GN45_Init},
{"COOLGIRL", 342, COOLGIRL_Init },
{"FAM250/81-01-39-C/SCHI-24", 354, Mapper354_Init },
{"Impact Soft MMC3 Flash Board", 406, Mapper406_Init },
{"Super Russian Roulette", 413, Mapper413_Init },
{"INX_007T_V01", 470, INX_007T_Init },
{"Haratyler HP/MP", 451, Mapper451_Init },
{"Impact Soft IM1", 471, Mapper471_Init },
{"KONAMI QTAi Board", 547, QTAi_Init },
@ -741,14 +823,20 @@ BMAPPINGLocal bmap[] = {
};
int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
int result;
struct md5_context md5;
uint64 partialmd5 = 0;
const char* mappername = "Not Listed";
size_t filesize = FCEU_fgetsize(fp);
if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4))
return LOADER_INVALID_FORMAT;
// Remove header size from filesize
filesize -= 16;
head.cleanup();
memset(&iNESCart, 0, sizeof(iNESCart));
iNESCart.clear();
iNES2 = ((head.ROM_type2 & 0x0C) == 0x08);
if(iNES2)
@ -770,34 +858,39 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
} else
Mirroring = (head.ROM_type & 1);
int not_round_size;
MirroringAs2bits = head.ROM_type & 1;
if (head.ROM_type & 8) MirroringAs2bits |= 2;
int not_round_size = 0;
int rom_size_bytes = 0;
int vrom_size_bytes = 0;
if (!iNES2) {
not_round_size = head.ROM_size;
not_round_size = head.ROM_size << 14;
}
else {
if ((head.Upper_ROM_VROM_size & 0x0F) != 0x0F)
// simple notation
not_round_size = head.ROM_size | ((head.Upper_ROM_VROM_size & 0x0F) << 8);
not_round_size = (head.ROM_size | ((head.Upper_ROM_VROM_size & 0x0F) << 8)) << 14;
else
// exponent-multiplier notation
not_round_size = ((1 << (head.ROM_size >> 2)) * ((head.ROM_size & 0b11) * 2 + 1)) >> 14;
not_round_size = ((1 << (head.ROM_size >> 2)) * ((head.ROM_size & 0b11) * 2 + 1));
}
if (!head.ROM_size && !iNES2)
ROM_size = 256;
rom_size_bytes = 256 << 14;
else
ROM_size = uppow2(not_round_size);
rom_size_bytes = uppow2(not_round_size);
VROM_size = uppow2(head.VROM_size | (iNES2?((head.Upper_ROM_VROM_size & 0xF0)<<4):0));
if (!iNES2) {
VROM_size = uppow2(head.VROM_size);
vrom_size_bytes = uppow2(head.VROM_size << 13);
}
else {
if ((head.Upper_ROM_VROM_size & 0xF0) != 0xF0)
// simple notation
VROM_size = uppow2(head.VROM_size | ((head.Upper_ROM_VROM_size & 0xF0) << 4));
vrom_size_bytes = uppow2((head.VROM_size | ((head.Upper_ROM_VROM_size & 0xF0) << 4)) << 13);
else
VROM_size = ((1 << (head.VROM_size >> 2)) * ((head.VROM_size & 0b11) * 2 + 1)) >> 13;
vrom_size_bytes = ((1 << (head.VROM_size >> 2)) * ((head.VROM_size & 0b11) * 2 + 1));
}
int round = true;
@ -813,52 +906,111 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
}
}
if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL)
return 0;
memset(ROM, 0xFF, ROM_size << 14);
ROM_size = rom_size_bytes >> 14;
VROM_size = vrom_size_bytes >> 13;
if (VROM_size) {
if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) {
free(ROM);
ROM = NULL;
FCEU_PrintError("Unable to allocate memory.");
return LOADER_HANDLED_ERROR;
ROM = (uint8*)FCEU_malloc(rom_size_bytes);
memset(ROM, 0xFF, rom_size_bytes);
if (vrom_size_bytes) {
VROM = (uint8*)FCEU_malloc(vrom_size_bytes);
memset(VROM, 0xFF, vrom_size_bytes);
}
// Set Vs. System flag if need
if (!iNES2) {
GameInfo->type = !(head.ROM_type2 & 1) ? GIT_CART : GIT_VSUNI;
}
else {
switch (!(head.ROM_type2 & 2) ? (head.ROM_type2 & 3) : (head.VS_hardware & 0xF)) {
case 0:
GameInfo->type = GIT_CART;
break;
case 1:
GameInfo->type = GIT_VSUNI;
break;
default:
FCEU_PrintError("Game type is not supported at all.");
goto init_error;
}
}
// Set Vs. System PPU type if need
if (GameInfo->type == GIT_VSUNI && !(head.ROM_type2 & 2)) {
switch (head.VS_hardware & 0xF) {
case 0x0: GameInfo->vs_ppu = GIPPU_RC2C03B; break;
//case 0x1: GameInfo->vs_ppu = GIPPU_RPC2C03C; break;
case 0x2: GameInfo->vs_ppu = GIPPU_RP2C04_0001; break;
case 0x3: GameInfo->vs_ppu = GIPPU_RP2C04_0002; break;
case 0x4: GameInfo->vs_ppu = GIPPU_RP2C04_0003; break;
case 0x5: GameInfo->vs_ppu = GIPPU_RP2C04_0004; break;
case 0x6: GameInfo->vs_ppu = GIPPU_RC2C03B; break;
//case 0x7: GameInfo->ppu = GIPPU_RPC2C03C; break;
case 0x8: GameInfo->vs_ppu = GIPPU_RC2C05_01; break;
case 0x9: GameInfo->vs_ppu = GIPPU_RC2C05_02; break;
case 0xA: GameInfo->vs_ppu = GIPPU_RC2C05_03; break;
case 0xB: GameInfo->vs_ppu = GIPPU_RC2C05_04; break;
//case 0xC: GameInfo->ppu = GIPPU_RPC2C05_05; break;
default:
FCEU_PrintError("Vs. System PPU type is not supported at all.");
goto init_error;
}
switch (head.VS_hardware >> 4) {
case 0x0: GameInfo->vs_type = EGIVS_NORMAL; break;
case 0x1: GameInfo->vs_type = EGIVS_RBI; break;
case 0x2: GameInfo->vs_type = EGIVS_TKO; break;
case 0x3: GameInfo->vs_type = EGIVS_XEVIOUS; break;
default:
FCEU_PrintError("Vs. System type is not supported at all.");
goto init_error;
}
memset(VROM, 0xFF, VROM_size << 13);
}
if (head.ROM_type & 4) { /* Trainer */
trainerpoo = (uint8*)FCEU_gmalloc(512);
FCEU_fread(trainerpoo, 512, 1, fp);
filesize -= 512;
}
ResetCartMapping();
ResetExState(0, 0);
SetupCartPRGMapping(0, ROM, ROM_size << 14, 0);
SetupCartPRGMapping(0, ROM, rom_size_bytes, 0);
FCEU_fread(ROM, 0x4000, (round) ? ROM_size : not_round_size, fp);
FCEU_fread(ROM, 1, (round) ? rom_size_bytes : not_round_size, fp);
if (VROM_size)
FCEU_fread(VROM, 0x2000, VROM_size, fp);
if (vrom_size_bytes)
FCEU_fread(VROM, 1, vrom_size_bytes, fp);
// Misc ROMS
if ((head.misc_roms & 0x03) && !(head.ROM_type & 4)) {
MiscROM_size = filesize - rom_size_bytes - vrom_size_bytes;
MiscROM = (uint8 *)FCEU_malloc(MiscROM_size);
memset(MiscROM, 0xFF, MiscROM_size);
FCEU_fread(MiscROM, 1, MiscROM_size, fp);
FCEU_printf(" Misc ROM size : %d\n", MiscROM_size);
}
md5_starts(&md5);
md5_update(&md5, ROM, ROM_size << 14);
md5_starts(&md5);
md5_update(&md5, ROM, rom_size_bytes);
iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14);
iNESGameCRC32 = CalcCRC32(0, ROM, rom_size_bytes);
if (VROM_size) {
iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13);
md5_update(&md5, VROM, VROM_size << 13);
if (vrom_size_bytes) {
iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, vrom_size_bytes);
md5_update(&md5, VROM, vrom_size_bytes);
}
md5_finish(&md5, iNESCart.MD5);
memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5));
for (int x = 0; x < 8; x++)
partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8);
iNESCart.CRC32 = iNESGameCRC32;
FCEU_printf(" PRG ROM: %d x 16KiB = %d KiB\n", round ? ROM_size : not_round_size, (round ? ROM_size : not_round_size) * 16);
FCEU_printf(" CHR ROM: %d x 8KiB = %d KiB\n", VROM_size, VROM_size * 8);
FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32);
FCEU_printf(" PRG ROM: %d x 16KiB = %d KiB\n", (round ? rom_size_bytes : not_round_size) >> 14, ((round ? rom_size_bytes : not_round_size) >> 14) * 16);
FCEU_printf(" CHR ROM: %d x 8KiB = %d KiB\n", (vrom_size_bytes >> 13), (vrom_size_bytes >> 13) * 8);
FCEU_printf(" ROM CRC32: 0x%08x\n", iNESGameCRC32);
{
int x;
FCEU_printf(" ROM MD5: 0x");
@ -867,9 +1019,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
FCEU_printf("\n");
}
const char* mappername = "Not Listed";
for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
for (size_t mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
if (bmap[mappertest].number == MapperNo) {
mappername = bmap[mappertest].name;
break;
@ -892,25 +1042,21 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
FCEU_printf(" WRAM backed by battery: %d KiB\n", iNESCart.battery_wram_size / 1024);
FCEU_printf(" VRAM backed by battery: %d KiB\n", iNESCart.battery_vram_size / 1024);
}
if (head.misc_roms & 0x03) FCEU_printf(" Misc ROM: %d KiB\n", MiscROM_size / 1024);
}
SetInput();
CheckHInfo();
{
int x;
uint64 partialmd5 = 0;
// Input can be overriden by NES 2.0 header
if (iNES2) SetInputNes20(head.expansion);
CheckHInfo(partialmd5);
FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);
CheckBad(partialmd5);
for (x = 0; x < 8; x++) {
partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8);
}
FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);
}
/* Must remain here because above functions might change value of
VROM_size and free(VROM).
*/
if (VROM_size)
SetupCartCHRMapping(0, VROM, VROM_size * 0x2000, 0);
if (vrom_size_bytes)
SetupCartCHRMapping(0, VROM, vrom_size_bytes, 0);
if (Mirroring == 2) {
ExtraNTARAM = (uint8*)FCEU_gmalloc(2048);
@ -922,8 +1068,9 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
iNESCart.battery = (head.ROM_type & 2) ? 1 : 0;
iNESCart.mirror = Mirroring;
iNESCart.mirrorAs2Bits = MirroringAs2bits;
int result = iNES_Init(MapperNo);
result = iNES_Init(MapperNo);
switch(result)
{
case 0:
@ -935,6 +1082,8 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
FCEU_PrintError("Unable to allocate CHR-RAM.");
break;
}
init_error:
if (ROM) free(ROM);
if (VROM) free(VROM);
if (trainerpoo) free(trainerpoo);
@ -973,13 +1122,7 @@ init_ok:
|| strstr(name, "(Europe)") || strstr(name, "(PAL)")
|| strstr(name, "(F)") || strstr(name, "(f)")
|| strstr(name, "(G)") || strstr(name, "(g)")
|| strstr(name, "(I)") || strstr(name, "(i)")
|| strstr(name, "(S)") || strstr(name, "(s)")
|| strstr(name, "(France)") || strstr(name, "(Germany)")
|| strstr(name, "(Italy)") || strstr(name, "(Spain)")
|| strstr(name, "(Sweden)") || strstr(name, "(Sw)")
|| strstr(name, "(Australia)") || strstr(name, "(A)")
|| strstr(name, "(a)"))
|| strstr(name, "(I)") || strstr(name, "(i)"))
FCEUI_SetVidSystem(1);
else
FCEUI_SetVidSystem(0);
@ -1005,7 +1148,7 @@ int iNesSaveAs(const char* name)
//caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename.
FILE *fp;
if (GameInfo->type != GIT_CART) return 0;
if ((GameInfo->type != GIT_CART) && (GameInfo->type != GIT_VSUNI)) return 0;
if (GameInterface != iNESGI) return 0;
fp = fopen(name, "wb");

View File

@ -25,6 +25,8 @@
#include <string.h>
#include <map>
#include "cart.h"
struct TMasterRomInfo
{
uint64 md5lower;
@ -40,30 +42,35 @@ public:
//mbg merge 6/29/06
extern uint8 *ROM;
extern uint8 *VROM;
extern uint8 *MiscROM;
extern uint32 VROM_size;
extern uint32 ROM_size;
extern uint32 MiscROM_size;
extern uint8 *ExtraNTARAM;
extern uint8 **VPageR;
extern int iNesSave(void); //bbit Edited: line added
extern int iNesSaveAs(const char* name);
extern char LoadedRomFName[2048]; //bbit Edited: line added
extern char LoadedRomFName[4096]; //bbit Edited: line added
extern char LoadedRomFNamePatchToUse[4096];
extern char *iNesShortFName(void);
extern const TMasterRomInfo* MasterRomInfo;
extern TMasterRomInfoParams MasterRomInfoParams;
//mbg merge 7/19/06 changed to c++ decl format
struct iNES_HEADER {
char ID[4]; /*NES^Z*/ // 0-3
uint8 ROM_size; // 4
uint8 VROM_size; // 5
uint8 ROM_type; // 6
uint8 ROM_type2; // 7
uint8 ROM_type3; // 8
uint8 Upper_ROM_VROM_size; // 9
uint8 RAM_size; // 10
uint8 VRAM_size; // 11
uint8 TV_system; // 12
uint8 VS_hardware; // 13
uint8 reserved[2]; // 14, 15
char ID[4]; /*NES^Z*/ // 0-3
uint8 ROM_size; // 4
uint8 VROM_size; // 5
uint8 ROM_type; // 6
uint8 ROM_type2; // 7
uint8 ROM_type3; // 8
uint8 Upper_ROM_VROM_size; // 9
uint8 RAM_size; // 10
uint8 VRAM_size; // 11
uint8 TV_system; // 12
uint8 VS_hardware; // 13
uint8 misc_roms; // 14
uint8 expansion; // 15
void cleanup()
{
@ -204,6 +211,7 @@ void Mapper170_Init(CartInfo *);
void Mapper171_Init(CartInfo *);
void Mapper172_Init(CartInfo *);
void Mapper173_Init(CartInfo *);
void Mapper174_Init(CartInfo *);
void Mapper175_Init(CartInfo *);
void Mapper177_Init(CartInfo *);
void Mapper178_Init(CartInfo *);
@ -270,7 +278,15 @@ void Mapper250_Init(CartInfo *);
void Mapper252_Init(CartInfo *);
void Mapper253_Init(CartInfo *);
void Mapper254_Init(CartInfo *);
void Mapper255_Init(CartInfo *);
void Mapper354_Init(CartInfo *);
void Mapper406_Init(CartInfo *);
void Mapper413_Init(CartInfo *);
void Mapper451_Init(CartInfo *);
void Mapper471_Init(CartInfo *);
void INX_007T_Init(CartInfo* info);
void GN45_Init(CartInfo *info); /* previously mapper 205 */
typedef struct {
const char *name;

View File

@ -106,6 +106,8 @@ uint8 FCEU_GetJoyJoy(void)
}
extern uint8 coinon;
extern uint8 coinon2;
extern uint8 service;
//set to true if the fourscore is attached
static bool FSAttached = false;
@ -232,6 +234,10 @@ static uint8 ReadGPVS(int w)
return ret;
}
#ifdef __FCEU_QSCRIPT_ENABLE__
extern uint8_t FCEU_JSReadJoypad(int which, uint8_t phyState);
#endif
static void UpdateGP(int w, void *data, int arg)
{
if(w==0) //adelikat, 3/14/09: Changing the joypads to inclusive OR the user's joypad + the Lua joypad, this way lua only takes over the buttons it explicity says to
@ -245,6 +251,11 @@ static void UpdateGP(int w, void *data, int arg)
joy[0] = *(uint32 *)joyports[0].ptr;;
joy[2] = *(uint32 *)joyports[0].ptr >> 16;
#endif
#ifdef __FCEU_QSCRIPT_ENABLE__
joy[0]= FCEU_JSReadJoypad(0,joy[0]);
joy[2]= FCEU_JSReadJoypad(2,joy[2]);
#endif
}
else
{
@ -257,8 +268,12 @@ static void UpdateGP(int w, void *data, int arg)
joy[1] = *(uint32 *)joyports[1].ptr >> 8;
joy[3] = *(uint32 *)joyports[1].ptr >> 24;
#endif
}
#ifdef __FCEU_QSCRIPT_ENABLE__
joy[1]= FCEU_JSReadJoypad(1,joy[1]);
joy[3]= FCEU_JSReadJoypad(3,joy[3]);
#endif
}
}
static void LogGP(int w, MovieRecord* mr)
@ -419,6 +434,10 @@ void FCEU_DrawInput(uint8 *buf)
portFC.driver->Draw(buf,portFC.attrib);
}
#ifdef __FCEU_QNETWORK_ENABLE__
extern bool NetPlayActive(void);
void NetPlayReadInputFrame(uint8_t* joy);
#endif
void FCEU_UpdateInput(void)
{
@ -431,8 +450,17 @@ void FCEU_UpdateInput(void)
portFC.driver->Update(portFC.ptr,portFC.attrib);
}
if(GameInfo->type==GIT_VSUNI)
if(coinon) coinon--;
if (GameInfo->type == GIT_VSUNI) {
if (coinon) coinon--;
if (coinon2) coinon2--;
if (service) service--;
}
#ifdef __FCEU_QNETWORK_ENABLE__
if (NetPlayActive())
{
NetPlayReadInputFrame(joy);
}
#endif
if(FCEUnetplay)
NetplayUpdate(joy);
@ -454,7 +482,11 @@ static DECLFR(VSUNIRead0)
ret|=(vsdip&3)<<3;
if(coinon)
ret|=0x4;
ret |= 0x20;
if (coinon2)
ret |= 0x40;
if (service)
ret |= 0x04;
return ret;
}
@ -668,7 +700,9 @@ void FCEU_DoSimpleCommand(int cmd)
{
case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert();break;
case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect();break;
case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break;
case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(0); break;
case FCEUNPCMD_VSUNICOIN2: FCEU_VSUniCoin(1); break;
case FCEUNPCMD_VSUNISERVICE: FCEU_VSUniService(); break;
case FCEUNPCMD_VSUNIDIP0:
case FCEUNPCMD_VSUNIDIP0+1:
case FCEUNPCMD_VSUNIDIP0+2:
@ -726,6 +760,22 @@ void FCEUI_VSUniCoin(void)
FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
}
void FCEUI_VSUniCoin2(void)
{
if (!FCEU_IsValidUI(FCEUI_INSERT_COIN))
return;
FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN2);
}
void FCEUI_VSUniService(void)
{
if (!FCEU_IsValidUI(FCEUI_INSERT_COIN))
return;
FCEU_QSimpleCommand(FCEUNPCMD_VSUNISERVICE);
}
//Resets the frame counter if movie inactive and rom is reset or power-cycle
void ResetFrameCounter()
{
@ -798,6 +848,7 @@ static void RamSearchOpLTE(void);
static void RamSearchOpGTE(void);
static void RamSearchOpEQ(void);
static void RamSearchOpNE(void);
static void ToggleCheats(void);
static void DebuggerStepInto(void);
static void FA_SkipLag(void);
static void OpenRom(void);
@ -900,17 +951,17 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_FDS_EJECT_INSERT, EMUCMDTYPE_FDS, FCEUI_FDSInsert, 0, 0, "Eject or Insert FDS Disk", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_FDS_SIDE_SELECT, EMUCMDTYPE_FDS, FCEUI_FDSSelect, 0, 0, "Switch FDS Disk Side", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_VSUNI_TOGGLE_DIP_0, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 0", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_1, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 1", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_2, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 2", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_3, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 3", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_4, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 4", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_5, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 5", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_6, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 6", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 7", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_8, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 8", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_9, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 9", 0 },
{ EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin #1", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_VSUNI_COIN_2, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin2, 0, 0, "Insert Coin #2", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_VSUNI_SERVICE_BUTTON, EMUCMDTYPE_VSUNI, FCEUI_VSUniService, 0, 0, "Service Button", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_VSUNI_TOGGLE_DIP_0, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 0", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_1, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 1", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_2, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 2", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_3, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 3", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_4, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 4", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_5, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 5", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_6, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 6", 0 },
{ EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 7", 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 },
@ -945,6 +996,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
{ EMUCMD_TOOL_RAMSEARCHGTE, EMUCMDTYPE_TOOL, RamSearchOpGTE, 0, 0, "Ram Search - Greater Than or Equal", 0},
{ EMUCMD_TOOL_RAMSEARCHEQ, EMUCMDTYPE_TOOL, RamSearchOpEQ, 0, 0, "Ram Search - Equal", 0},
{ EMUCMD_TOOL_RAMSEARCHNE, EMUCMDTYPE_TOOL, RamSearchOpNE, 0, 0, "Ram Search - Not Equal", 0},
{ EMUCMD_TOOL_TOGGLECHEATS, EMUCMDTYPE_TOOL, ToggleCheats, 0, 0, "Toggle Cheats", 0},
{ EMUCMD_RERECORD_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_MovieToggleRerecordDisplay,0, 0, "Toggle Rerecord Display", EMUCMDFLAG_TASEDITOR },
{ EMUCMD_TASEDITOR_REWIND, EMUCMDTYPE_TASEDITOR, TaseditorRewindOn, TaseditorRewindOff, 0, "Frame Rewind", EMUCMDFLAG_TASEDITOR },
@ -960,12 +1012,12 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
#define NUM_EMU_CMDS (sizeof(FCEUI_CommandTable)/sizeof(FCEUI_CommandTable[0]))
static int execcmd, i;
static int execcmd;
void FCEUI_HandleEmuCommands(TestCommandState* testfn)
{
bool taseditor = FCEUMOV_Mode(MOVIEMODE_TASEDITOR);
for(i=0; i<NUM_EMU_CMDS; ++i)
for(size_t i=0; i<NUM_EMU_CMDS; ++i)
{
int new_state;
int old_state = FCEUI_CommandTable[i].state;
@ -1268,6 +1320,18 @@ static void RamSearchOpNE(void) {
#endif
}
extern int globalCheatDisabled;
extern unsigned int FrozenAddressCount;
static void ToggleCheats()
{
FCEUI_GlobalToggleCheat(globalCheatDisabled);
FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount);
#ifdef __WIN_DRIVER__
UpdateCheatRelatedWindow();
UpdateCheatListGroupBoxUI();
#endif
}
static void DebuggerStepInto()
{
#ifdef __WIN_DRIVER__
@ -1377,7 +1441,7 @@ static void TaseditorCommand(void)
**/
EMUCMDTABLE* GetEmuCommandById(int cmd)
{
for (i = 0; i<NUM_EMU_CMDS; ++i)
for (size_t i = 0; i<NUM_EMU_CMDS; ++i)
{
if (FCEUI_CommandTable[i].cmd == cmd)
return &FCEUI_CommandTable[i];

View File

@ -197,8 +197,8 @@ enum EMUCMD
EMUCMD_VSUNI_TOGGLE_DIP_5,
EMUCMD_VSUNI_TOGGLE_DIP_6,
EMUCMD_VSUNI_TOGGLE_DIP_7,
EMUCMD_VSUNI_TOGGLE_DIP_8,
EMUCMD_VSUNI_TOGGLE_DIP_9,
EMUCMD_VSUNI_COIN_2,
EMUCMD_VSUNI_SERVICE_BUTTON,
EMUCMD_MISC_AUTOSAVE,
EMUCMD_MISC_SHOWSTATES,
EMUCMD_MISC_USE_INPUT_PRESET_1,
@ -259,6 +259,8 @@ enum EMUCMD
EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,
EMUCMD_MOVIE_RECORD_MODE_INSERT,
EMUCMD_TOOL_TOGGLECHEATS,
EMUCMD_MAX
};

View File

@ -22,14 +22,7 @@
#include <stdlib.h>
#include "share.h"
typedef struct {
uint32 mzx,mzy,mzb;
int zap_readbit;
int bogo;
int zappo;
uint64 zaphit;
} ZAPPER;
#include "zapper.h"
static ZAPPER ZD;

View File

@ -10,7 +10,7 @@ struct ZAPPER
uint8 bogo;
int zappo;
uint64 zaphit;
uint32 lastInput;
uint32 lastInput;
};
#endif

View File

@ -110,7 +110,7 @@ SFORMAT FCEUMOV_STATEINFO[]={
{ 0 }
};
char curMovieFilename[512] = {0};
std::string curMovieFilename;
MovieData currMovieData;
MovieData defaultMovieData;
int currRerecordCount; // Keep the global value
@ -306,7 +306,7 @@ void MovieRecord::dumpJoy(EMUFILE* os, uint8 joystate)
void MovieRecord::parseJoy(EMUFILE* is, uint8& joystate)
{
char buf[8];
char buf[8] = {0};
is->fread(buf,8);
joystate = 0;
for(int i=0;i<8;i++)
@ -468,6 +468,7 @@ MovieData::MovieData()
, rerecordCount(0)
, binaryFlag(false)
, loadFrameCount(-1)
, fourscore(false)
, microphone(false)
, RAMInitOption(0)
, RAMInitSeed(0)
@ -751,7 +752,7 @@ bool LoadFM2(MovieData& movieData, EMUFILE* fp, int size, bool stopAfterHeader)
{
LoadFM2_binarychunk(movieData, fp, size);
return true;
} else if (isnewline && movieData.loadFrameCount == movieData.records.size())
} else if (isnewline && static_cast<size_t>(movieData.loadFrameCount) == movieData.records.size())
// exit prematurely if loaded the specified amound of records
return true;
switch(state)
@ -865,7 +866,10 @@ static EMUFILE *openRecordingMovie(const char* fname)
FCEU_PrintError("Error opening movie output file: %s", fname);
return NULL;
}
strcpy(curMovieFilename, fname);
if ( fname != curMovieFilename.c_str() )
{
curMovieFilename.assign(fname);
}
return osRecordingMovie;
}
@ -885,7 +889,7 @@ static void RedumpWholeMovieFile(bool justToggledRecording = false)
bool recording = (movieMode == MOVIEMODE_RECORD);
assert((NULL != osRecordingMovie) == (recording != justToggledRecording) && "osRecordingMovie should be consistent with movie mode!");
if (NULL == openRecordingMovie(curMovieFilename))
if (NULL == openRecordingMovie(curMovieFilename.c_str()))
return;
currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/, recording);
@ -933,7 +937,7 @@ static void OnMovieClosed()
{
assert(movieMode == MOVIEMODE_INACTIVE);
curMovieFilename[0] = 0; //No longer a current movie filename
curMovieFilename.clear(); //No longer a current movie filename
freshMovie = false; //No longer a fresh movie loaded
if (bindSavestate) AutoSS = false; //If bind movies to savestates is true, then there is no longer a valid auto-save to load
@ -1039,23 +1043,23 @@ bool MovieData::loadSaveramFrom(std::vector<uint8>* buf)
return false;
}
for(int i=0;i<4;i++)
for (size_t i=0;i<currCartInfo->SaveGame.size();i++)
{
int len = ms.read32le();
if(!currCartInfo->SaveGame[i] && len!=0)
if( (currCartInfo->SaveGame[i].bufptr == nullptr) && (len!=0) )
{
FCEU_PrintError("movie battery load mismatch 2");
return false;
}
if(currCartInfo->SaveGameLen[i] != len)
if(currCartInfo->SaveGame[i].buflen != static_cast<size_t>(len))
{
FCEU_PrintError("movie battery load mismatch 3");
return false;
}
ms.fread(currCartInfo->SaveGame[i], len);
ms.fread(currCartInfo->SaveGame[i].bufptr, len);
}
return true;
@ -1066,16 +1070,15 @@ 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++)
for(size_t i=0;i<currCartInfo->SaveGame.size();i++)
{
if(!currCartInfo->SaveGame[i])
if (!currCartInfo->SaveGame[i].bufptr)
{
ms.write32le((u32)0);
continue;
}
ms.write32le(currCartInfo->SaveGameLen[i]);
ms.fwrite(currCartInfo->SaveGame[i], currCartInfo->SaveGameLen[i]);
ms.write32le( static_cast<uint32>(currCartInfo->SaveGame[i].buflen) );
ms.fwrite(currCartInfo->SaveGame[i].bufptr, currCartInfo->SaveGame[i].buflen);
}
}
@ -1098,7 +1101,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe)
currMovieData = MovieData();
strcpy(curMovieFilename, fname);
curMovieFilename.assign(fname);
FCEUFILE *fp = FCEU_fopen(fname,0,"rb",0);
if (!fp) return false;
if(fp->isArchive() && !_read_only) {
@ -1279,7 +1282,11 @@ void FCEUMOV_AddInputState()
if (mr->command_fds_select())
FCEU_FDSSelect();
if (mr->command_vs_insertcoin())
FCEU_VSUniCoin();
FCEU_VSUniCoin(0);
if (mr->command_vs_insertcoin2())
FCEU_VSUniCoin(1);
if (mr->command_vs_service())
FCEU_VSUniService();
_currCommand = 0;
} else
#endif
@ -1307,14 +1314,18 @@ void FCEUMOV_AddInputState()
if(mr->command_fds_select())
FCEU_FDSSelect();
if (mr->command_vs_insertcoin())
FCEU_VSUniCoin();
FCEU_VSUniCoin(0);
if (mr->command_vs_insertcoin2())
FCEU_VSUniCoin(1);
if (mr->command_vs_service())
FCEU_VSUniService();
joyports[0].load(mr);
joyports[1].load(mr);
}
//if we are on the last frame, then pause the emulator if the player requested it
if (currFrameCounter == currMovieData.records.size()-1)
if ( static_cast<size_t>(currFrameCounter) == currMovieData.records.size()-1)
{
if(FCEUD_PauseAfterPlayback())
{
@ -1385,6 +1396,8 @@ void FCEUMOV_AddCommand(int cmd)
case FCEUNPCMD_FDSINSERT: cmd = MOVIECMD_FDS_INSERT; break;
case FCEUNPCMD_FDSSELECT: cmd = MOVIECMD_FDS_SELECT; break;
case FCEUNPCMD_VSUNICOIN: cmd = MOVIECMD_VS_INSERTCOIN; break;
case FCEUNPCMD_VSUNICOIN2: cmd = MOVIECMD_VS_INSERTCOIN2; break;
case FCEUNPCMD_VSUNISERVICE: cmd = MOVIECMD_VS_SERVICE; break;
// all other netplay commands (e.g. FCEUNPCMD_VSUNIDIP0) are not supported by movie recorder for now
default: return;
}
@ -1404,22 +1417,22 @@ void FCEU_DrawMovies(uint8 *XBuf)
if (movieMode == MOVIEMODE_PLAY)
{
sprintf(counterbuf, "%d/%d%s%s", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
snprintf(counterbuf, sizeof(counterbuf), "%d/%d%s%s", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
} else if (movieMode == MOVIEMODE_RECORD)
{
if (movieRecordMode == MOVIE_RECORD_MODE_TRUNCATE)
sprintf(counterbuf, "%d%s%s (record)", currFrameCounter, GetMovieRecordModeStr(), GetMovieReadOnlyStr()); // nearly classic
snprintf(counterbuf, sizeof(counterbuf), "%d%s%s (record)", currFrameCounter, GetMovieRecordModeStr(), GetMovieReadOnlyStr()); // nearly classic
else
sprintf(counterbuf, "%d/%d%s%s (record)", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
snprintf(counterbuf, sizeof(counterbuf), "%d/%d%s%s (record)", currFrameCounter, (int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
} else if (movieMode == MOVIEMODE_FINISHED)
{
sprintf(counterbuf,"%d/%d%s%s (finished)",currFrameCounter,(int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
snprintf(counterbuf, sizeof(counterbuf), "%d/%d%s%s (finished)",currFrameCounter,(int)currMovieData.records.size(), GetMovieRecordModeStr(), GetMovieReadOnlyStr());
color = 0x17; //Show red to get attention
} else if (movieMode == MOVIEMODE_TASEDITOR)
{
sprintf(counterbuf,"%d",currFrameCounter);
snprintf(counterbuf, sizeof(counterbuf),"%d",currFrameCounter);
} else
sprintf(counterbuf,"%d (no movie)",currFrameCounter);
snprintf(counterbuf, sizeof(counterbuf),"%d (no movie)",currFrameCounter);
if (counterbuf[0])
DrawTextTrans(ClipSidesOffset+XBuf+FCEU_TextScanlineOffsetFromBottom(30)+1, 256, (uint8*)counterbuf, color+0x80);
@ -1427,7 +1440,7 @@ void FCEU_DrawMovies(uint8 *XBuf)
if (rerecord_display && movieMode != MOVIEMODE_INACTIVE)
{
char counterbuf[32] = {0};
sprintf(counterbuf, "%d", currMovieData.rerecordCount);
snprintf(counterbuf, sizeof(counterbuf), "%d", currMovieData.rerecordCount);
if (counterbuf[0])
DrawTextTrans(ClipSidesOffset+XBuf+FCEU_TextScanlineOffsetFromBottom(50)+1, 256, (uint8*)counterbuf, 0x28+0x80);
@ -1440,7 +1453,7 @@ void FCEU_DrawLagCounter(uint8 *XBuf)
{
// If currently lagging - display red, else display green
uint8 color = (lagFlag) ? (0x16+0x80) : (0x2A+0x80);
sprintf(lagcounterbuf, "%d", lagCounter);
snprintf(lagcounterbuf, sizeof(lagcounterbuf), "%d", lagCounter);
if(lagcounterbuf[0])
DrawTextTrans(ClipSidesOffset + XBuf + FCEU_TextScanlineOffsetFromBottom(40) + 1, 256, (uint8*)lagcounterbuf, color);
}
@ -1474,7 +1487,7 @@ int CheckTimelines(MovieData& stateMovie, MovieData& currMovie)
}
static bool load_successful;
static bool load_successful = false;
bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
{
@ -1493,7 +1506,7 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
#endif
movie_readonly = true;
}
if (FCEU_isFileInArchive(curMovieFilename))
if (FCEU_isFileInArchive(curMovieFilename.c_str()))
{
//a little rule: cant load states in read+write mode with a movie from an archive.
//so we are going to switch it to readonly mode in that case
@ -1628,10 +1641,10 @@ bool FCEUMOV_ReadState(EMUFILE* is, uint32 size)
//TODO: turn frame counter to red to get attention
if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user
{
FCEU_PrintError("Error: Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
FCEU_PrintError("Error: Savestate taken from a frame (%d) after the final frame in the savestated movie (%zi) cannot be verified against current movie (%zi). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
FCEUI_StopMovie();
} else
FCEU_PrintError("Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
FCEU_PrintError("Savestate taken from a frame (%d) after the final frame in the savestated movie (%zi) cannot be verified against current movie (%zi). This is not permitted.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
return false;
}
}
@ -1691,18 +1704,20 @@ bool FCEUMOV_PostLoad(void)
void FCEUMOV_IncrementRerecordCount()
{
bool skip = false;
#ifdef _S9XLUA_H
if(!FCEU_LuaRerecordCountSkip())
skip = skip || FCEU_LuaRerecordCountSkip();
#endif
#ifdef __FCEU_QSCRIPT_ENABLE__
extern bool FCEU_JSRerecordCountSkip();
skip = skip || FCEU_JSRerecordCountSkip();
#endif
if(!skip)
if (movieMode != MOVIEMODE_TASEDITOR)
currRerecordCount++;
else
currMovieData.rerecordCount++;
#else
if (movieMode != MOVIEMODE_TASEDITOR)
currRerecordCount++;
else
currMovieData.rerecordCount++;
#endif
if (movieMode != MOVIEMODE_TASEDITOR)
currMovieData.rerecordCount = currRerecordCount;
}
@ -1787,7 +1802,7 @@ void FCEUI_MovieToggleReadOnly()
strcpy(message, "Movie is now Read+Write");
strcat(message, GetMovieModeStr());
FCEU_DispMessage(message,0);
FCEU_DispMessage("%s",0,message);
}
void FCEUI_MovieToggleRecording()
@ -1831,7 +1846,7 @@ void FCEUI_MovieToggleRecording()
strcat(message, GetMovieModeStr());
FCEU_DispMessage(message, 0);
FCEU_DispMessage("%s",0,message);
}
void FCEUI_MovieInsertFrame()
@ -1858,7 +1873,7 @@ void FCEUI_MovieInsertFrame()
strcat(message, GetMovieModeStr());
}
FCEU_DispMessage(message, 0);
FCEU_DispMessage("%s",0,message);
}
void FCEUI_MovieDeleteFrame()
@ -1896,7 +1911,7 @@ void FCEUI_MovieDeleteFrame()
strcat(message, GetMovieModeStr());
}
FCEU_DispMessage(message, 0);
FCEU_DispMessage("%s",0,message);
}
void FCEUI_MovieTruncate()
@ -1934,7 +1949,7 @@ void FCEUI_MovieTruncate()
strcat(message, GetMovieModeStr());
}
FCEU_DispMessage(message, 0);
FCEU_DispMessage("%s",0,message);
}
void FCEUI_MovieNextRecordMode()
@ -2004,7 +2019,7 @@ void FCEUI_MoviePlayFromBeginning(void)
#endif
}
string FCEUI_GetMovieName(void)
std::string FCEUI_GetMovieName(void)
{
return curMovieFilename;
}
@ -2098,9 +2113,9 @@ void FCEUI_CreateMovieFile(std::string fn)
void FCEUI_MakeBackupMovie(bool dispMessage)
{
//This function generates backup movie files
string currentFn; //Current movie fillename
string backupFn; //Target backup filename
string tempFn; //temp used in back filename creation
std::string currentFn; //Current movie fillename
std::string backupFn; //Target backup filename
std::string tempFn; //temp used in back filename creation
stringstream stream;
int x; //Temp variable for string manip
bool exist = false; //Used to test if filename exists

View File

@ -81,7 +81,9 @@ enum EMOVIECMD
MOVIECMD_POWER = 2,
MOVIECMD_FDS_INSERT = 4,
MOVIECMD_FDS_SELECT = 8,
MOVIECMD_VS_INSERTCOIN = 16
MOVIECMD_VS_INSERTCOIN = 16,
MOVIECMD_VS_INSERTCOIN2 = 32,
MOVIECMD_VS_SERVICE = 64
};
EMOVIEMODE FCEUMOV_Mode();
@ -131,6 +133,8 @@ public:
bool command_fds_insert() { return (commands & MOVIECMD_FDS_INSERT) != 0; }
bool command_fds_select() { return (commands & MOVIECMD_FDS_SELECT) != 0; }
bool command_vs_insertcoin() { return (commands & MOVIECMD_VS_INSERTCOIN) != 0; }
bool command_vs_insertcoin2() { return (commands & MOVIECMD_VS_INSERTCOIN2) != 0; }
bool command_vs_service() { return (commands & MOVIECMD_VS_SERVICE) != 0; }
void toggleBit(int joy, int bit)
{
@ -210,7 +214,7 @@ public:
//whether microphone is enabled
bool microphone;
int getNumRecords() { return (int)records.size(); }
int getNumRecords() { return static_cast<int>( records.size() ); }
int RAMInitOption, RAMInitSeed;
@ -271,7 +275,7 @@ private:
extern MovieData currMovieData;
extern int currFrameCounter;
extern char curMovieFilename[512];
extern std::string curMovieFilename;
extern bool subtitlesOnAVI;
extern bool freshMovie;
extern bool movie_readonly;

View File

@ -122,7 +122,10 @@ int FCEUNET_SendFile(uint8 cmd, char *fn)
FCEUX_fstat(fileno(fp),&sb);
len = sb.st_size;
buf = (char*)FCEU_dmalloc(len); //mbg merge 7/17/06 added cast
fread(buf, 1, len, fp);
if ( fread(buf, 1, len, fp) != static_cast<size_t>(len) )
{
FCEU_printf("Warning: FCEUNET_SendFile failed to load complete file.\n");
}
fclose(fp);
cbuf = (char*)FCEU_dmalloc(4 + len + len / 1000 + 12); //mbg merge 7/17/06 added cast

View File

@ -7,7 +7,10 @@ extern int FCEUnetplay;
#define FCEUNPCMD_POWER 0x02
#define FCEUNPCMD_VSUNICOIN 0x07
#define FCEUNPCMD_VSUNIDIP0 0x08
#define FCEUNPCMD_VSUNIDIP0 0x08
#define FCEUNPCMD_VSUNICOIN2 0x20
#define FCEUNPCMD_VSUNISERVICE 0x21
#define FCEUNPCMD_FDSINSERTx 0x10
#define FCEUNPCMD_FDSINSERT 0x18
//#define FCEUNPCMD_FDSEJECT 0x19

View File

@ -32,6 +32,7 @@
#include "file.h"
#include "fds.h"
#include "cart.h"
#include "ines.h"
#include "input.h"
#include "state.h"
#include "driver.h"
@ -123,8 +124,6 @@ static uint16 PlayAddr; //configuration
static uint16 InitAddr; //configuration
static uint16 LoadAddr; //configuration
extern char LoadedRomFName[2048];
NSF_HEADER NSFHeader; //mbg merge 6/29/06 - needs to be global
void NSFMMC5_Close(void);
@ -582,7 +581,7 @@ void DrawNSF(uint8 *XBuf)
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:", kFgColor);
sprintf(snbuf,"<%d/%d>",CurrentSong,NSFHeader.TotalSongs);
snprintf(snbuf, sizeof(snbuf), "<%d/%d>",CurrentSong,NSFHeader.TotalSongs);
DrawTextTrans(XBuf+82*256+4+(((31-strlen(snbuf))<<2)), 256, (uint8*)snbuf, kFgColor);
{

View File

@ -88,6 +88,7 @@ pal *palo = NULL;
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
FCEU_MAYBE_UNUSED
static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
{
static float const to_float = 1.0f / 0xFF;
@ -253,6 +254,7 @@ static void ApplyDeemphasisBisqwit(int entry, u8& r, u8& g, u8& b)
}
//classic algorithm
FCEU_MAYBE_UNUSED
static void ApplyDeemphasisClassic(int entry, u8& r, u8& g, u8& b)
{
//DEEMPH BITS MAY BE ORDERED WRONG. PLEASE CHECK

View File

@ -1,74 +0,0 @@
/* Quick conversion stuff for MAME->FCE Ultra */
#include <stdio.h>
#include "../types.h"
#include "../palette.h"
#include "palettes.h"
/* check 0x08 */
static uint8 rp2c04001_colortable[] =
{
0x35, 0x23, 0x16, 0x22, 0x1c, 0x09, 0xff, 0x15, /* 0x00 - 0x07 */
0x20, 0x00, 0x27, 0x05, 0x04, 0x27, 0x08, 0x30, /* 0x08 - 0x0f */
0x21, 0xff, 0xff, 0x29, 0x3c, 0x32, 0x36, 0x12, /* 0x10 - 0x17 */
0xff, 0x2b, 0x0f, 0xff, 0x20, 0x10, 0x24, 0x01, /* 0x18 - 0x1f */
0xff, 0x31, 0xff, 0x2a, 0x2c, 0x0c, 0xff, 0xff, /* 0x20 - 0x27 */
0xff, 0x07, 0x34, 0x06, 0x13, 0x02, 0x26, 0x0f, /* 0x28 - 0x2f */
0xff, 0x19, 0x10, 0x0a, 0x39, 0xff, 0x37, 0x17, /* 0x30 - 0x37 */
0xff, 0x11, 0x09, 0xff, 0x39, 0x25, 0x18, 0xff /* 0x38 - 0x3f */
};
/* RP2C04-002 */
static uint8 rp2c04002_colortable[] =
{
0x0f, 0x27, 0x18, 0xff, 0x3a, 0x25, 0xff, 0x31, /* 0x00 - 0x07 */
0x16, 0x13, 0x38, 0x34, 0x20, 0x23, 0xff, 0x0b, /* 0x08 - 0x0f */
0xff, 0x21, 0x06, 0xff, 0x1b, 0x29, 0xff, 0x22, /* 0x10 - 0x17 */
0xff, 0x24, 0xff, 0x2b, 0xff, 0x08, 0xff, 0x03, /* 0x18 - 0x1f */
0xff, 0x36, 0x26, 0x33, 0x11, 0xff, 0x10, 0x02, /* 0x20 - 0x27 */
0x14, 0xff, 0x00, 0x09, 0x12, 0x0f, 0x37, 0x30, /* 0x28 - 0x2f */
0xff, 0xff, 0x2a, 0x17, 0x0c, 0x01, 0x15, 0x19, /* 0x30 - 0x37 */
0xff, 0x2c, 0x07, 0x37, 0xff, 0x05, 0x0a, 0x00 /* 0x38 - 0x3f */
};
/* RP2C04-003 */
/* Check 0x00. Used in Dr Mario. */
static uint8 rp2c04003_colortable[] =
{
0x03, 0xff, 0xff, 0x00, 0x1a, 0x30, 0x31, 0x09, /* 0x00 - 0x07 */
0x01, 0x0f, 0x36, 0x08, 0x15, 0xff, 0xff, 0x30, /* 0x08 - 0x0f */
0x22, 0x1c, 0xff, 0x12, 0x19, 0x18, 0x17, 0x1b, /* 0x10 - 0x17 */
0x00, 0xff, 0xff, 0x02, 0x16, 0x06, 0xff, 0x35, /* 0x18 - 0x1f */
0x23, 0xff, 0x0f, 0x37, 0xff, 0x27, 0x26, 0x30, /* 0x20 - 0x27 */
0x29, 0xff, 0x21, 0x24, 0x11, 0xff, 0x0f, 0xff, /* 0x28 - 0x2f */
0x2c, 0xff, 0xff, 0xff, 0x07, 0x2a, 0x28, 0xff, /* 0x30 - 0x37 */
0x0a, 0xff, 0x32, 0x37, 0x13, 0xff, 0xff, 0x0c /* 0x38 - 0x3f */
};
/* RP2C05-004 */
/* check 0x1d, 0x38 */
static uint8 rp2c05004_colortable[] =
{
0x18, 0xff, 0x1c, 0x28, 0xff, 0xff, 0x01, 0x17, /* 0x00 - 0x07 */
0x10, 0x0f, 0x2a, 0x0f, 0x36, 0x37, 0x1a, 0xff, /* 0x08 - 0x0f */
0x25, 0xff, 0x12, 0xff, 0x0f, 0xff, 0xff, 0x26, /* 0x10 - 0x17 */
0xff, 0xff, 0x22, 0x19, 0xff, 0x0f, 0x3a, 0x21, /* 0x18 - 0x1f */
0x05, 0x0a, 0x07, 0x01, 0x13, 0xff, 0x00, 0x15, /* 0x20 - 0x27 */
0x0c, 0xff, 0x11, 0xff, 0xff, 0x38, 0xff, 0xff, /* 0x28 - 0x2f */
0xff, 0xff, 0x08, 0x16, 0xff, 0xff, 0x30, 0x3c, /* 0x30 - 0x37 */
0x0f, 0x27, 0xff, 0x31, 0x29, 0xff, 0x30, 0x09 /* 0x38 - 0x3f */
};
main()
{
int x;
for(x=0;x<64;x++)
{
// if(x <= 0x20)
// if(rp2c04002_colortable[x] == 0xFF) rp2c04002_colortable[x]= 0x30;
printf("{0x%02x, 0x%02x, 0x%02x},\n",palette[rp2c04001_colortable[x]&0x3F].r,
palette[rp2c04001_colortable[x]&0x3F].g,
palette[rp2c04001_colortable[x]&0x3F].b);
}
}

View File

@ -56,73 +56,76 @@ pal palette_unvarying[] = {
};
#define P64(x) (((x)<<2)|((x>>4)&3))
// Default palette
pal palette[512] = {
{ P64(0x1D), P64(0x1D), P64(0x1D)}, /* Value 0 */
{ P64(0x09), P64(0x06), P64(0x23)}, /* Value 1 */
{ P64(0x00), P64(0x00), P64(0x2A)}, /* Value 2 */
{ P64(0x11), P64(0x00), P64(0x27)}, /* Value 3 */
{ P64(0x23), P64(0x00), P64(0x1D)}, /* Value 4 */
{ P64(0x2A), P64(0x00), P64(0x04)}, /* Value 5 */
{ P64(0x29), P64(0x00), P64(0x00)}, /* Value 6 */
{ P64(0x1F), P64(0x02), P64(0x00)}, /* Value 7 */
{ P64(0x10), P64(0x0B), P64(0x00)}, /* Value 8 */
{ P64(0x00), P64(0x11), P64(0x00)}, /* Value 9 */
{ P64(0x00), P64(0x14), P64(0x00)}, /* Value 10 */
{ P64(0x00), P64(0x0F), P64(0x05)}, /* Value 11 */
{ P64(0x06), P64(0x0F), P64(0x17)}, /* Value 12 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 13 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 14 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 15 */
{ P64(0x2F), P64(0x2F), P64(0x2F)}, /* Value 16 */
{ P64(0x00), P64(0x1C), P64(0x3B)}, /* Value 17 */
{ P64(0x08), P64(0x0E), P64(0x3B)}, /* Value 18 */
{ P64(0x20), P64(0x00), P64(0x3C)}, /* Value 19 */
{ P64(0x2F), P64(0x00), P64(0x2F)}, /* Value 20 */
{ P64(0x39), P64(0x00), P64(0x16)}, /* Value 21 */
{ P64(0x36), P64(0x0A), P64(0x00)}, /* Value 22 */
{ P64(0x32), P64(0x13), P64(0x03)}, /* Value 23 */
{ P64(0x22), P64(0x1C), P64(0x00)}, /* Value 24 */
{ P64(0x00), P64(0x25), P64(0x00)}, /* Value 25 */
{ P64(0x00), P64(0x2A), P64(0x00)}, /* Value 26 */
{ P64(0x00), P64(0x24), P64(0x0E)}, /* Value 27 */
{ P64(0x00), P64(0x20), P64(0x22)}, /* Value 28 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 29 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 30 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 31 */
{ P64(0x3F), P64(0x3F), P64(0x3F)}, /* Value 32 */
{ P64(0x0F), P64(0x2F), P64(0x3F)}, /* Value 33 */
{ P64(0x17), P64(0x25), P64(0x3F)}, /* Value 34 */
{ P64(0x33), P64(0x22), P64(0x3F)}, /* Value 35 */
{ P64(0x3D), P64(0x1E), P64(0x3F)}, /* Value 36 */
{ P64(0x3F), P64(0x1D), P64(0x2D)}, /* Value 37 */
{ P64(0x3F), P64(0x1D), P64(0x18)}, /* Value 38 */
{ P64(0x3F), P64(0x26), P64(0x0E)}, /* Value 39 */
{ P64(0x3C), P64(0x2F), P64(0x0F)}, /* Value 40 */
{ P64(0x20), P64(0x34), P64(0x04)}, /* Value 41 */
{ P64(0x13), P64(0x37), P64(0x12)}, /* Value 42 */
{ P64(0x16), P64(0x3E), P64(0x26)}, /* Value 43 */
{ P64(0x00), P64(0x3A), P64(0x36)}, /* Value 44 */
{ P64(0x1E), P64(0x1E), P64(0x1E)}, /* Value 45 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 46 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 47 */
{ P64(0x3F), P64(0x3F), P64(0x3F)}, /* Value 48 */
{ P64(0x2A), P64(0x39), P64(0x3F)}, /* Value 49 */
{ P64(0x31), P64(0x35), P64(0x3F)}, /* Value 50 */
{ P64(0x35), P64(0x32), P64(0x3F)}, /* Value 51 */
{ P64(0x3F), P64(0x31), P64(0x3F)}, /* Value 52 */
{ P64(0x3F), P64(0x31), P64(0x36)}, /* Value 53 */
{ P64(0x3F), P64(0x2F), P64(0x2C)}, /* Value 54 */
{ P64(0x3F), P64(0x36), P64(0x2A)}, /* Value 55 */
{ P64(0x3F), P64(0x39), P64(0x28)}, /* Value 56 */
{ P64(0x38), P64(0x3F), P64(0x28)}, /* Value 57 */
{ P64(0x2A), P64(0x3C), P64(0x2F)}, /* Value 58 */
{ P64(0x2C), P64(0x3F), P64(0x33)}, /* Value 59 */
{ P64(0x27), P64(0x3F), P64(0x3C)}, /* Value 60 */
{ P64(0x31), P64(0x31), P64(0x31)}, /* Value 61 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 62 */
{ P64(0x00), P64(0x00), P64(0x00)}, /* Value 63 */
{ 0x1D<<2, 0x1D<<2, 0x1D<<2 }, /* Value 0 */
{ 0x09<<2, 0x06<<2, 0x23<<2 }, /* Value 1 */
{ 0x00<<2, 0x00<<2, 0x2A<<2 }, /* Value 2 */
{ 0x11<<2, 0x00<<2, 0x27<<2 }, /* Value 3 */
{ 0x23<<2, 0x00<<2, 0x1D<<2 }, /* Value 4 */
{ 0x2A<<2, 0x00<<2, 0x04<<2 }, /* Value 5 */
{ 0x29<<2, 0x00<<2, 0x00<<2 }, /* Value 6 */
{ 0x1F<<2, 0x02<<2, 0x00<<2 }, /* Value 7 */
{ 0x10<<2, 0x0B<<2, 0x00<<2 }, /* Value 8 */
{ 0x00<<2, 0x11<<2, 0x00<<2 }, /* Value 9 */
{ 0x00<<2, 0x14<<2, 0x00<<2 }, /* Value 10 */
{ 0x00<<2, 0x0F<<2, 0x05<<2 }, /* Value 11 */
{ 0x06<<2, 0x0F<<2, 0x17<<2 }, /* Value 12 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 13 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 14 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 15 */
{ 0x2F<<2, 0x2F<<2, 0x2F<<2 }, /* Value 16 */
{ 0x00<<2, 0x1C<<2, 0x3B<<2 }, /* Value 17 */
{ 0x08<<2, 0x0E<<2, 0x3B<<2 }, /* Value 18 */
{ 0x20<<2, 0x00<<2, 0x3C<<2 }, /* Value 19 */
{ 0x2F<<2, 0x00<<2, 0x2F<<2 }, /* Value 20 */
{ 0x39<<2, 0x00<<2, 0x16<<2 }, /* Value 21 */
{ 0x36<<2, 0x0A<<2, 0x00<<2 }, /* Value 22 */
{ 0x32<<2, 0x13<<2, 0x03<<2 }, /* Value 23 */
{ 0x22<<2, 0x1C<<2, 0x00<<2 }, /* Value 24 */
{ 0x00<<2, 0x25<<2, 0x00<<2 }, /* Value 25 */
{ 0x00<<2, 0x2A<<2, 0x00<<2 }, /* Value 26 */
{ 0x00<<2, 0x24<<2, 0x0E<<2 }, /* Value 27 */
{ 0x00<<2, 0x20<<2, 0x22<<2 }, /* Value 28 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 29 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 30 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 31 */
{ 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 32 */
{ 0x0F<<2, 0x2F<<2, 0x3F<<2 }, /* Value 33 */
{ 0x17<<2, 0x25<<2, 0x3F<<2 }, /* Value 34 */
{ 0x33<<2, 0x22<<2, 0x3F<<2 }, /* Value 35 */
{ 0x3D<<2, 0x1E<<2, 0x3F<<2 }, /* Value 36 */
{ 0x3F<<2, 0x1D<<2, 0x2D<<2 }, /* Value 37 */
{ 0x3F<<2, 0x1D<<2, 0x18<<2 }, /* Value 38 */
{ 0x3F<<2, 0x26<<2, 0x0E<<2 }, /* Value 39 */
{ 0x3C<<2, 0x2F<<2, 0x0F<<2 }, /* Value 40 */
{ 0x20<<2, 0x34<<2, 0x04<<2 }, /* Value 41 */
{ 0x13<<2, 0x37<<2, 0x12<<2 }, /* Value 42 */
{ 0x16<<2, 0x3E<<2, 0x26<<2 }, /* Value 43 */
{ 0x00<<2, 0x3A<<2, 0x36<<2 }, /* Value 44 */
{ 0x1E<<2, 0x1E<<2, 0x1E<<2 }, /* Value 45 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 46 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 47 */
{ 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 48 */
{ 0x2A<<2, 0x39<<2, 0x3F<<2 }, /* Value 49 */
{ 0x31<<2, 0x35<<2, 0x3F<<2 }, /* Value 50 */
{ 0x35<<2, 0x32<<2, 0x3F<<2 }, /* Value 51 */
{ 0x3F<<2, 0x31<<2, 0x3F<<2 }, /* Value 52 */
{ 0x3F<<2, 0x31<<2, 0x36<<2 }, /* Value 53 */
{ 0x3F<<2, 0x2F<<2, 0x2C<<2 }, /* Value 54 */
{ 0x3F<<2, 0x36<<2, 0x2A<<2 }, /* Value 55 */
{ 0x3F<<2, 0x39<<2, 0x28<<2 }, /* Value 56 */
{ 0x38<<2, 0x3F<<2, 0x28<<2 }, /* Value 57 */
{ 0x2A<<2, 0x3C<<2, 0x2F<<2 }, /* Value 58 */
{ 0x2C<<2, 0x3F<<2, 0x33<<2 }, /* Value 59 */
{ 0x27<<2, 0x3F<<2, 0x3C<<2 }, /* Value 60 */
{ 0x31<<2, 0x31<<2, 0x31<<2 }, /* Value 61 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 62 */
{ 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 63 */
#undef P64
//luke's .16+ palette
//{0x60, 0x60, 0x60}, /* Value 0 */

View File

@ -57,6 +57,7 @@
#define PPU_status (PPU[2])
#define READPALNOGS(ofs) (PALRAM[(ofs)])
#define READPAL(ofs) (PALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF))
#define READUPAL(ofs) (UPALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF))
@ -455,13 +456,24 @@ volatile int rendercount, vromreadcount, undefinedvromcount, LogAddress = -1;
unsigned char *cdloggervdata = NULL;
unsigned int cdloggerVideoDataSize = 0;
int GetCHRAddress(int A) {
if (cdloggerVideoDataSize) {
int result = &VPage[A >> 10][A] - CHRptr[0];
int GetCHRAddress(int A)
{
if (cdloggerVideoDataSize)
{
int result = -1;
if ( (A >= 0) && (A < 0x2000) )
{
result = &VPage[A >> 10][A] - CHRptr[0];
}
if ((result >= 0) && (result < (int)cdloggerVideoDataSize))
{
return result;
} else
if(A < 0x2000) return A;
}
}
else
{
if ( (A >= 0) && (A < 0x2000) ) return A;
}
return -1;
}
@ -1722,10 +1734,17 @@ void FCEUPPU_Reset(void) {
void FCEUPPU_Power(void) {
int x;
memset(NTARAM, 0x00, 0x800);
memset(PALRAM, 0x00, 0x20);
memset(UPALRAM, 0x00, 0x03);
memset(SPRAM, 0x00, 0x100);
// initialize PPU memory regions according to settings
FCEU_MemoryRand(NTARAM, 0x800, true);
FCEU_MemoryRand(PALRAM, 0x20, true);
FCEU_MemoryRand(SPRAM, 0x100, true);
// palettes can only store values up to $3F, and PALRAM X4/X8/XC are mirrors of X0 for rendering purposes (UPALRAM is used for $2007 readback)
for (x = 0; x < 0x20; ++x) PALRAM[x] &= 0x3F;
UPALRAM[0] = PALRAM[0x04];
UPALRAM[1] = PALRAM[0x08];
UPALRAM[2] = PALRAM[0x0C];
PALRAM[0x0C] = PALRAM[0x08] = PALRAM[0x04] = PALRAM[0x00];
PALRAM[0x1C] = PALRAM[0x18] = PALRAM[0x14] = PALRAM[0x10];
FCEUPPU_Reset();
for (x = 0x2000; x < 0x4000; x += 8) {
@ -1987,6 +2006,7 @@ void runppu(int x) {
struct BGData {
struct Record {
uint8 nt, pecnt, at, pt[2], qtnt;
uint8 ppu1[8];
INLINE void Read() {
NTRefreshAddr = RefreshAddr = ppur.get_ntread();
@ -1998,7 +2018,12 @@ struct BGData {
}
pecnt = (RefreshAddr & 1) << 3;
nt = CALL_PPUREAD(RefreshAddr);
runppu(kFetchTime);
ppu1[0] = PPU[1];
runppu(1);
ppu1[1] = PPU[1];
runppu(1);
RefreshAddr = ppur.get_atread();
at = CALL_PPUREAD(RefreshAddr);
@ -2010,37 +2035,57 @@ struct BGData {
at <<= 2;
//horizontal scroll clocked at cycle 3 and then
//vertical scroll at 251
ppu1[2] = PPU[1];
runppu(1);
if (PPUON) {
ppur.increment_hsc();
if (ppur.status.cycle == 251)
ppur.increment_vs();
}
ppu1[3] = PPU[1];
runppu(1);
ppur.par = nt;
RefreshAddr = ppur.get_ptread();
if (PEC586Hack) {
pt[0] = CALL_PPUREAD(RefreshAddr | pecnt);
runppu(kFetchTime);
ppu1[4] = PPU[1];
runppu(1);
ppu1[5] = PPU[1];
runppu(1);
pt[1] = CALL_PPUREAD(RefreshAddr | pecnt);
runppu(kFetchTime);
ppu1[6] = PPU[1];
runppu(1);
ppu1[7] = PPU[1];
runppu(1);
} else if (QTAIHack && (qtnt & 0x40)) {
pt[0] = *(CHRptr[0] + RefreshAddr);
runppu(kFetchTime);
ppu1[4] = PPU[1];
runppu(1);
ppu1[5] = PPU[1];
runppu(1);
RefreshAddr |= 8;
pt[1] = *(CHRptr[0] + RefreshAddr);
runppu(kFetchTime);
ppu1[6] = PPU[1];
runppu(1);
ppu1[7] = PPU[1];
runppu(1);
} else {
if (ScreenON)
RENDER_LOG(RefreshAddr);
pt[0] = CALL_PPUREAD(RefreshAddr);
runppu(kFetchTime);
ppu1[4] = PPU[1];
runppu(1);
ppu1[5] = PPU[1];
runppu(1);
RefreshAddr |= 8;
if (ScreenON)
RENDER_LOG(RefreshAddr);
pt[1] = CALL_PPUREAD(RefreshAddr);
runppu(kFetchTime);
ppu1[6] = PPU[1];
runppu(1);
ppu1[7] = PPU[1];
runppu(1);
}
}
};
@ -2216,7 +2261,7 @@ int FCEUX_PPU_Loop(int skip) {
pixel = ((pt[0] >> (7 - bgpx)) & 1) | (((pt[1] >> (7 - bgpx)) & 1) << 1) | bgdata.main[bgtile].at;
}
if (renderbg)
pixelcolor = READPAL(pixel);
pixelcolor = READPALNOGS(pixel);
//look for a sprite to be drawn
bool havepixel = false;
@ -2261,12 +2306,25 @@ int FCEUX_PPU_Loop(int skip) {
spixel |= (oam[2] & 3) << 2;
if (rendersprites)
pixelcolor = READPAL(0x10 + spixel);
pixelcolor = READPALNOGS(0x10 + spixel);
}
}
*ptr++ = PaletteAdjustPixel(pixelcolor);
*dptr++= PPU[1]>>5; //grab deemph
//apply grayscale.. kind of clunky
//really we need to read the entire palette instead of just ppu1
//this will be needed for special color effects probably (very fine rainbows and whatnot?)
//are you allowed to chang the palette mid-line anyway? well you can definitely change the grayscale flag as we know from the FF1 "polygon" effect
if(bgdata.main[xt+2].ppu1[xp]&1)
pixelcolor &= 0x30;
//this does deemph stuff inside it.. which is probably wrong...
*ptr = PaletteAdjustPixel(pixelcolor);
ptr++;
//grab deemph..
//I guess this works the same way as the grayscale, ideally?
*dptr++ = bgdata.main[xt+2].ppu1[xp]>>5;
}
}
}

View File

@ -6,7 +6,7 @@ uint8 tmpd;
#endif
#ifndef PPUT_MMC5SP
uint8 zz;
FCEU_MAYBE_UNUSED uint8 zz;
#else
uint8 xs, ys;
xs = X1;
@ -87,9 +87,14 @@ pshift[1] <<= 8;
#else
#ifdef PPU_VRC5FETCH
if(tmpd & 0x40)
if(tmpd & 0x40) {
if (CHRsize[0] == (128 * 1024)) {
// NOTE: address 128K CHR-ROM using offsets into 256K CHR-ROM data
// https://www.nesdev.org/wiki/NES_2.0_Mapper_547#Kanji_ROM_layout
vadr = ((vadr & 0x00007) << 1) | ((vadr & 0x00010) >> 4) | ((vadr & 0x3FFE0) >> 1);
}
C = CHRptr[0] + vadr;
else
} else
C = VRAMADR(vadr);
#else
C = VRAMADR(vadr);

View File

@ -534,9 +534,10 @@ static INLINE void DMCDMA(void)
PrepDPCM();
else
{
SIRQStat|=0x80;
if(DMCFormat&0x80)
if(DMCFormat&0x80) {
SIRQStat|=0x80;
X6502_IRQBegin(FCEU_IQDPCM);
}
}
}
}

View File

@ -63,6 +63,7 @@ using namespace std;
static void (*SPreSave)(void) = NULL;
static void (*SPostSave)(void) = NULL;
static void (*SPostLoad)(bool) = NULL;
static int SaveStateStatus[10];
static int StateShow;
@ -84,11 +85,11 @@ bool backupSavestates = true;
bool compressSavestates = true; //By default FCEUX compresses savestates when a movie is inactive.
// a temp memory stream. We'll be dumping some data here and then compress
EMUFILE_MEMORY memory_savestate;
static EMUFILE_MEMORY memory_savestate;
// temporary buffer for compressed data of a savestate
std::vector<uint8> compressed_buf;
static std::vector<uint8> compressed_buf;
#define SFMDATA_SIZE (64)
#define SFMDATA_SIZE (128)
static SFORMAT SFMDATA[SFMDATA_SIZE];
static int SFEXINDEX;
@ -110,7 +111,7 @@ SFORMAT SFCPU[]={
{ &X.Y, 1, "Y\0\0"},
{ &X.S, 1, "S\0\0"},
{ &X.P, 1, "P\0\0"},
{ &X.DB, 1, "DB"},
{ &X.DB, 1, "DB\0"},
{ &RAM, 0x800 | FCEUSTATE_INDIRECT, "RAM", },
{ 0 }
};
@ -133,7 +134,7 @@ static int SubWrite(EMUFILE* os, SFORMAT *sf)
while(sf->v)
{
if(sf->s==~0) //Link to another struct
if(sf->s==~0u) //Link to another struct
{
uint32 tmp;
@ -152,7 +153,7 @@ static int SubWrite(EMUFILE* os, SFORMAT *sf)
os->fwrite(sf->desc,4);
write32le(sf->s&(~FCEUSTATE_FLAGS),os);
#ifndef LSB_FIRST
#ifdef FCEU_BIG_ENDIAN
if(sf->s&RLSB)
FlipByteOrder((uint8*)sf->v,sf->s&(~FCEUSTATE_FLAGS));
#endif
@ -163,7 +164,7 @@ static int SubWrite(EMUFILE* os, SFORMAT *sf)
os->fwrite((char*)sf->v,sf->s&(~FCEUSTATE_FLAGS));
//Now restore the original byte order.
#ifndef LSB_FIRST
#ifdef FCEU_BIG_ENDIAN
if(sf->s&RLSB)
FlipByteOrder((uint8*)sf->v,sf->s&(~FCEUSTATE_FLAGS));
#endif
@ -191,7 +192,7 @@ static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc)
{
while(sf->v)
{
if(sf->s==~0) // Link to another SFORMAT structure.
if(sf->s==~0u) // Link to another SFORMAT structure.
{
SFORMAT *tmp;
if((tmp= CheckS((SFORMAT *)sf->v, tsize, desc) ))
@ -231,7 +232,7 @@ static bool ReadStateChunk(EMUFILE* is, SFORMAT *sf, int size)
else
is->fread((char *)tmp->v,tmp->s&(~FCEUSTATE_FLAGS));
#ifndef LSB_FIRST
#ifdef FCEU_BIG_ENDIAN
if(tmp->s&RLSB)
FlipByteOrder((uint8*)tmp->v,tmp->s&(~FCEUSTATE_FLAGS));
#endif
@ -307,13 +308,24 @@ static bool ReadStateChunks(EMUFILE* is, int32 totalsize)
// load back buffer
{
extern uint8 *XBackBuf;
if(is->fread((char*)XBackBuf,size) != size)
ret = false;
//ignore 8 garbage bytes, whose idea was it to write these or even have them there in the first place
if(size == 256*256+8)
{
if(is->fread((char*)XBackBuf,256*256) != 256*256)
ret = false;
is->fseek(8,SEEK_CUR);
}
else
{
if(is->fread((char*)XBackBuf,size) != size)
ret = false;
}
//MBG TODO - can this be moved to a better place?
//does it even make sense, displaying XBuf when its XBackBuf we just loaded?
#ifdef __WIN_DRIVER__
else
if(ret)
{
FCEUD_BlitScreen(XBuf);
UpdateFCEUWindow();
@ -334,7 +346,7 @@ static bool ReadStateChunks(EMUFILE* is, int32 totalsize)
if(!warned)
{
char str [256];
sprintf(str, "Warning: Found unknown save chunk of type %d.\nThis could indicate the save state is corrupted\nor made with a different (incompatible) emulator version.", t);
snprintf(str, sizeof(str), "Warning: Found unknown save chunk of type %d.\nThis could indicate the save state is corrupted\nor made with a different (incompatible) emulator version.", t);
FCEUD_PrintError(str);
warned=true;
}
@ -404,7 +416,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel)
// save back buffer
{
extern uint8 *XBackBuf;
uint32 size = 256 * 256 + 8;
uint32 size = 256 * 256;
os->fputc(8);
write32le(size, os);
os->fwrite((char*)XBackBuf,size);
@ -416,7 +428,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel)
if(SPostSave) SPostSave();
//save the length of the file
int len = memory_savestate.size();
size_t len = memory_savestate.size();
//sanity check: len and totalsize should be the same
if(len != totalsize)
@ -427,7 +439,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel)
int error = Z_OK;
uint8* cbuf = (uint8*)memory_savestate.buf();
uLongf comprlen = -1;
uLongf comprlen = ~0lu;
if(compressionLevel != Z_NO_COMPRESSION && (compressSavestates || FCEUMOV_Mode(MOVIEMODE_TASEDITOR)))
{
// worst case compression: zlib says "0.1% larger than sourceLen plus 12 bytes"
@ -446,7 +458,7 @@ bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel)
//dump it to the destination file
outstream->fwrite((char*)header,16);
outstream->fwrite((char*)cbuf,comprlen==-1?totalsize:comprlen);
outstream->fwrite((char*)cbuf,comprlen==~0lu?totalsize:comprlen);
return error == Z_OK;
}
@ -500,13 +512,12 @@ void FCEUSS_Save(const char *fname, bool display_message)
LuaSaveData saveData;
CallRegisteredLuaSaveFunctions(CurrentState, saveData);
char luaSaveFilename [512];
strncpy(luaSaveFilename, fn, 512);
luaSaveFilename[512-(1+7/*strlen(".luasav")*/)] = '\0';
strcat(luaSaveFilename, ".luasav");
std::string luaSaveFilename;
luaSaveFilename.assign(fn.c_str());
luaSaveFilename.append(".luasav");
if(saveData.recordList)
{
FILE* luaSaveFile = fopen(luaSaveFilename, "wb");
FILE* luaSaveFile = fopen(luaSaveFilename.c_str(), "wb");
if(luaSaveFile)
{
saveData.ExportRecords(luaSaveFile);
@ -515,7 +526,7 @@ void FCEUSS_Save(const char *fname, bool display_message)
}
else
{
unlink(luaSaveFilename);
unlink(luaSaveFilename.c_str());
}
}
#endif
@ -629,6 +640,11 @@ int FCEUSS_LoadFP_old(EMUFILE* is, ENUM_SSLOADPARAMS params)
return(x);
}
#ifdef __QT_DRIVER__
// Qt Driver NetPlay state load handler. This is to control state loading
// during netplay, only hosts can load states and clients can request loads.
bool NetPlayStateLoadReq(EMUFILE* is);
#endif
bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params)
{
@ -655,29 +671,37 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params)
return ret;
}
int totalsize = FCEU_de32lsb(header + 4);
int stateversion = FCEU_de32lsb(header + 8);
int comprlen = FCEU_de32lsb(header + 12);
#ifdef __QT_DRIVER__
if ( NetPlayStateLoadReq(is) )
{
return false;
}
#endif
size_t totalsize = FCEU_de32lsb(header + 4);
int stateversion = FCEU_de32lsb(header + 8);
uint32_t comprlen = FCEU_de32lsb(header + 12);
// reinit memory_savestate
// memory_savestate is global variable which already has its vector of bytes, so no need to allocate memory every time we use save/loadstate
if ((int)(memory_savestate.get_vec())->size() < totalsize)
if ((memory_savestate.get_vec())->size() < totalsize)
(memory_savestate.get_vec())->resize(totalsize);
memory_savestate.set_len(totalsize);
memory_savestate.unfail();
memory_savestate.fseek(0, SEEK_SET);
if(comprlen != -1)
if(comprlen != ~0u)
{
// the savestate is compressed: read from is to compressed_buf, then decompress from compressed_buf to memory_savestate.vec
if ((int)compressed_buf.size() < comprlen) compressed_buf.resize(comprlen);
if (compressed_buf.size() < comprlen) compressed_buf.resize(comprlen);
is->fread(&compressed_buf[0], comprlen);
uLongf uncomprlen = totalsize;
int error = uncompress(memory_savestate.buf(), &uncomprlen, &compressed_buf[0], comprlen);
if(error != Z_OK || uncomprlen != totalsize)
return false; // we dont need to restore the backup here because we havent messed with the emulator state yet
} else
}
else
{
// the savestate is not compressed: just read from is to memory_savestate.vec
is->fread(memory_savestate.buf(), totalsize);
@ -700,15 +724,25 @@ bool FCEUSS_LoadFP(EMUFILE* is, ENUM_SSLOADPARAMS params)
FCEUPPU_LoadState(stateversion);
FCEUSND_LoadState(stateversion);
x=FCEUMOV_PostLoad();
} else if (backup)
}
else if (backup)
{
msBackupSavestate.fseek(0,SEEK_SET);
FCEUSS_LoadFP(&msBackupSavestate,SSLOADPARAM_NOBACKUP);
}
// Post state load callback that is used to notify driver code that a new state load occurred.
if (SPostLoad != NULL)
{
SPostLoad(x);
}
return x;
}
void FCEUSS_SetLoadCallback( void (*cb)(bool) )
{
SPostLoad = cb;
}
bool FCEUSS_Load(const char *fname, bool display_message)
{
@ -759,18 +793,19 @@ bool FCEUSS_Load(const char *fname, bool display_message)
{
char szFilename[260]={0};
splitpath(fname, 0, 0, szFilename, 0);
if (display_message)
if (display_message)
{
FCEU_DispMessage("State %s loaded.", 0, szFilename);
//FCEU_DispMessage("State %s loaded. Filename: %s", 0, szFilename, fn);
}
} else
FCEU_DispMessage("State %s loaded.", 0, szFilename);
//FCEU_DispMessage("State %s loaded. Filename: %s", 0, szFilename, fn.c_str());
}
}
else
{
if (display_message)
if (display_message)
{
FCEU_DispMessage("State %d loaded.", 0, CurrentState);
//FCEU_DispMessage("State %d loaded. Filename: %s", 0, CurrentState, fn);
}
FCEU_DispMessage("State %d loaded.", 0, CurrentState);
//FCEU_DispMessage("State %d loaded. Filename: %s", 0, CurrentState, fn.c_str());
}
SaveStateStatus[CurrentState] = 1;
}
delete st;
@ -780,11 +815,10 @@ bool FCEUSS_Load(const char *fname, bool display_message)
{
LuaSaveData saveData;
char luaSaveFilename [512];
strncpy(luaSaveFilename, fn, 512);
luaSaveFilename[512-(1+7/*strlen(".luasav")*/)] = '\0';
strcat(luaSaveFilename, ".luasav");
FILE* luaSaveFile = fopen(luaSaveFilename, "rb");
std::string luaSaveFilename;
luaSaveFilename.assign(fn.c_str());
luaSaveFilename.append(".luasav");
FILE* luaSaveFile = fopen(luaSaveFilename.c_str(), "rb");
if(luaSaveFile)
{
saveData.ImportRecords(luaSaveFile);
@ -796,7 +830,7 @@ bool FCEUSS_Load(const char *fname, bool display_message)
#endif
#ifdef __WIN_DRIVER__
Update_RAM_Search(); // Update_RAM_Watch() is also called.
Update_RAM_Search(); // Update_RAM_Watch() is also called.
#endif
//Update input display if movie is loaded
@ -806,7 +840,8 @@ bool FCEUSS_Load(const char *fname, bool display_message)
cur_input_display = FCEU_GetJoyJoy(); //Input display should show the last buttons pressed (stored in the savestate)
return true;
} else
}
else
{
if(!fname)
SaveStateStatus[CurrentState] = 1;
@ -816,7 +851,6 @@ bool FCEUSS_Load(const char *fname, bool display_message)
FCEU_DispMessage("Error(s) reading state %d!", 0, CurrentState);
//FCEU_DispMessage("Error(s) reading state %d! Filename: %s", 0, CurrentState, fn);
}
delete st;
return 0;
}
}
@ -848,7 +882,7 @@ void ResetExState(void (*PreSave)(void), void (*PostSave)(void))
for(x=0;x<SFEXINDEX;x++)
{
if(SFMDATA[x].desc)
free( (void*)SFMDATA[x].desc);
FCEU_free( (void*)SFMDATA[x].desc);
}
// adelikat, 3/14/09: had to add this to clear out the size parameter. NROM(mapper 0) games were having savestate crashes if loaded after a non NROM game because the size variable was carrying over and causing savestates to save too much data
SFMDATA[0].s = 0;
@ -1103,7 +1137,7 @@ string GetBackupFileName()
string filename;
int x;
filename = strdup(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0).c_str()); //Generate normal savestate filename
filename = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0); //Generate normal savestate filename
x = filename.find_last_of("."); //Find last dot
filename = filename.substr(0,x); //Chop off file extension
filename.append(".bak.fc0"); //add .bak
@ -1169,3 +1203,16 @@ void RedoLoadState()
redoLS = false; //Flag that RedoLoadState can not be run again
undoLS = true; //Flag that LoadBackup can be run again
}
int FCEU_StateRecorderStart(void) { return 0; }
int FCEU_StateRecorderStop(void) { return 0; }
int FCEU_StateRecorderUpdate(void) { return 0; }
bool FCEU_StateRecorderIsEnabled(void) { return false; }
void FCEU_StateRecorderSetEnabled(bool enabled) { }
bool FCEU_StateRecorderRunning(void) { return false; }
int FCEU_StateRecorderGetMaxSnaps(void) { return 0; }
int FCEU_StateRecorderGetNumSnapsSaved(void) { return 0; }
int FCEU_StateRecorderLoadState(int snapIndex) { return -1; }
int FCEU_StateRecorderGetStateIndex(void) { return 0; }
int FCEU_StateRecorderLoadPrevState(void) { return -1; }
int FCEU_StateRecorderLoadNextState(void) { return -1; }

View File

@ -27,6 +27,7 @@ enum ENUM_SSLOADPARAMS
void FCEUSS_Save(const char *, bool display_message=true);
bool FCEUSS_Load(const char *, bool display_message=true);
void FCEUSS_SetLoadCallback( void (*cb)(bool) );
//zlib values: 0 (none) through 9 (max) or -1 (default)
bool FCEUSS_SaveMS(EMUFILE* outstream, int compressionLevel);
@ -78,3 +79,16 @@ extern bool backupSavestates; //Whether or not to make backups, true by defaul
bool CheckBackupSaveStateExist(); //Checks if backupsavestate exists
extern bool compressSavestates; //Whether or not to compress non-movie savestates (by default, yes)
int FCEU_StateRecorderStart(void);
int FCEU_StateRecorderStop(void);
int FCEU_StateRecorderUpdate(void);
bool FCEU_StateRecorderRunning(void);
bool FCEU_StateRecorderIsEnabled(void);
void FCEU_StateRecorderSetEnabled(bool enabled);
int FCEU_StateRecorderGetMaxSnaps(void);
int FCEU_StateRecorderGetNumSnapsSaved(void);
int FCEU_StateRecorderGetStateIndex(void);
int FCEU_StateRecorderLoadState(int snapIndex);
int FCEU_StateRecorderLoadPrevState(void);
int FCEU_StateRecorderLoadNextState(void);

View File

@ -22,6 +22,9 @@
#ifndef __FCEU_TYPES
#define __FCEU_TYPES
#include <stdlib.h>
#include <new>
//enables a hack designed for debugging dragon warrior 3 which treats BRK as a 3-byte opcode
//#define BRK_3BYTE_HACK
@ -62,6 +65,8 @@ typedef signed int int32;
#define alloca __builtin_alloca
#endif
//#include <typeinfo>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@ -91,9 +96,6 @@ typedef uint32_t uint32;
#define GINLINE /* Can't declare a function INLINE
and global in MSVC. Bummer.
*/
#define PSS_STYLE 2 /* Does MSVC compile for anything
other than Windows/DOS targets?
*/
#if _MSC_VER >= 1300
#pragma warning(disable:4244) //warning C4244: '=' : conversion from 'uint32' to 'uint8', possible loss of data
@ -105,6 +107,17 @@ typedef uint32_t uint32;
#endif
#endif
#if defined(__linux__) || defined(__APPLE__) || defined(__unix__)
#define PSS_STYLE 1
#elif defined(MSVC)
#define PSS_STYLE 2 /* Does MSVC compile for anything
other than Windows/DOS targets?
*/
#endif
#if PSS_STYLE==2
#define PSS "\\"
@ -131,7 +144,7 @@ typedef uint32_t uint32;
#endif
#if defined(WIN32) && !defined(__QT_DRIVER__)
#if defined(WIN32) && !defined(__QT_DRIVER__) && !defined(__WIN_DRIVER__)
#define __WIN_DRIVER__
#endif
@ -143,6 +156,114 @@ typedef uint8 (*readfunc)(uint32 A);
#define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1];
#endif
#define __FCEU_STRINGIZE2(x) #x
#define __FCEU_STRINGIZE(x) __FCEU_STRINGIZE2(x)
#define FCEU_CPP_HAS_STD(x) ( defined(__cplusplus) && (__cplusplus >= x) )
#ifdef __has_cpp_attribute
#define FCEU_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#define FCEU_HAS_CPP_ATTRIBUTE(x) 0
#endif
#define FCEU_UNUSED(x) (void)(x)
#define FCEU_CRASH() int *_dumbPointer = nullptr; *_dumbPointer = 0xdeadbeef
#if FCEU_CPP_HAS_STD(201603L) || FCEU_HAS_CPP_ATTRIBUTE(maybe_unused)
#define FCEU_MAYBE_UNUSED [[maybe_unused]]
#else
#define FCEU_MAYBE_UNUSED
#endif
#if defined(_MSC_VER)
// Microsoft compiler won't catch format issues, but VS IDE can catch on analysis mode
#define __FCEU_PRINTF_FORMAT _In_z_ _Printf_format_string_
#define __FCEU_PRINTF_ATTRIBUTE( fmt, va )
#elif defined(__GNUC__) || defined(__clang__) || FCEU_HAS_CPP_ATTRIBUTE(format)
// GCC and Clang compilers will perform printf format type checks, useful for catching format errors.
#define __FCEU_PRINTF_FORMAT
#define __FCEU_PRINTF_ATTRIBUTE( fmt, va ) __attribute__((__format__(__printf__, fmt, va)))
#else
#define __FCEU_PRINTF_FORMAT
#define __FCEU_PRINTF_ATTRIBUTE( fmt, va )
#endif
#if defined(__cplusplus)
// Scoped pointer ensures that memory pointed to by this object gets cleaned up
// and deallocated when this object goes out of scope. Helps prevent memory leaks
// on temporary memory allocations in functions with early outs.
enum fceuAllocType
{
FCEU_ALLOC_TYPE_NEW = 0,
FCEU_ALLOC_TYPE_NEW_ARRAY,
FCEU_ALLOC_TYPE_MALLOC
};
template <typename T>
class fceuScopedPtr
{
public:
fceuScopedPtr( T *ptrIn = nullptr, enum fceuAllocType allocType = FCEU_ALLOC_TYPE_NEW )
{
//printf("Scoped Pointer Constructor <%s>: %p\n", typeid(T).name(), ptrIn );
ptr = ptrIn;
_allocType = allocType;
}
~fceuScopedPtr(void)
{
//printf("Scoped Pointer Destructor <%s>: %p\n", typeid(T).name(), ptr );
Delete();
}
T* operator= (T *ptrIn)
{
ptr = ptrIn;
return ptr;
}
T* get(void)
{
return ptr;
}
void Delete(void)
{
if (ptr)
{
switch (_allocType)
{
case FCEU_ALLOC_TYPE_MALLOC:
{
::free(ptr);
}
break;
case FCEU_ALLOC_TYPE_NEW_ARRAY:
{
delete [] ptr;
}
break;
default:
case FCEU_ALLOC_TYPE_NEW:
{
delete ptr;
}
break;
}
ptr = nullptr;
}
}
private:
T *ptr;
enum fceuAllocType _allocType;
};
#endif // __cplusplus
#include "utils/endian.h"
#endif

View File

@ -108,7 +108,7 @@ static void ResetUNIF(void) {
vramo = 0;
boardname = 0;
mirrortodo = 0;
memset(&UNIFCart, 0, sizeof(UNIFCart));
UNIFCart.clear();
UNIFchrrama = 0;
}
@ -144,7 +144,7 @@ static int DoMirroring(FCEUFILE *fp) {
return(0);
FCEU_printf(" %02x", t);
}
FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n", uchead.info);
FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n");
mirrortodo = 0;
}
return(1);
@ -165,9 +165,9 @@ static int NAME(FCEUFILE *fp) {
namebuf[index] = 0;
FCEU_printf("%s\n", namebuf);
if (!GameInfo->name) {
GameInfo->name = (uint8*)malloc(strlen(namebuf) + 1); //mbg merge 7/17/06 added cast
strcpy((char*)GameInfo->name, namebuf); //mbg merge 7/17/06 added cast
if (GameInfo->name == nullptr)
{
GameInfo->name = (uint8*)strdup(namebuf);
}
return(1);
}
@ -479,6 +479,8 @@ static BMAPPING bmap[] = {
{ "FNS", FNS_Init, BMCFLAG_16KCHRR },
{ "BS-400R", BS400R_Init, 0 },
{ "BS-4040R", BS4040R_Init, 0 },
{ "COOLGIRL", COOLGIRL_Init, BMCFLAG_256KCHRR },
{ "JC-016-2", Mapper205_Init, 0 },
{ 0, 0, 0 }
};

View File

@ -162,7 +162,8 @@ void MINDKIDS_Init(CartInfo *info);
void FNS_Init(CartInfo *info);
void BS400R_Init(CartInfo *info);
void BS4040R_Init(CartInfo *info);
void SMD132_SMD133_Init(CartInfo *info);
void AA6023_Init(CartInfo *info);
void COOLGIRL_Init(CartInfo* info);
extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM
// bank switcherooing with certain boards...

View File

@ -121,7 +121,7 @@ int read32le(uint32 *Bufo, FILE *fp)
uint32 buf;
if(fread(&buf,1,4,fp)<4)
return 0;
#ifdef LSB_FIRST
#ifdef FCEU_LITTLE_ENDIAN
*(uint32*)Bufo=buf;
#else
*(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
@ -134,7 +134,7 @@ int read16le(uint16 *Bufo, std::istream *is)
uint16 buf;
if(is->read((char*)&buf,2).gcount() != 2)
return 0;
#ifdef LSB_FIRST
#ifdef FCEU_LITTLE_ENDIAN
*Bufo=buf;
#else
*Bufo = FCEU_de16lsb((uint8*)&buf);
@ -148,7 +148,7 @@ int read64le(uint64 *Bufo, std::istream *is)
uint64 buf;
if(is->read((char*)&buf,8).gcount() != 8)
return 0;
#ifdef LSB_FIRST
#ifdef FCEU_LITTLE_ENDIAN
*Bufo=buf;
#else
*Bufo = FCEU_de64lsb((uint8*)&buf);
@ -162,7 +162,7 @@ int read32le(uint32 *Bufo, std::istream *is)
uint32 buf;
if(is->read((char*)&buf,4).gcount() != 4)
return 0;
#ifdef LSB_FIRST
#ifdef FCEU_LITTLE_ENDIAN
*(uint32*)Bufo=buf;
#else
*(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
@ -173,7 +173,7 @@ int read32le(uint32 *Bufo, std::istream *is)
///reads a little endian 16bit value from the specified file
int read16le(char *d, FILE *fp)
{
#ifdef LSB_FIRST
#ifdef FCEU_LITTLE_ENDIAN
return((fread(d,1,2,fp)<2)?0:2);
#else
int ret;

View File

@ -107,5 +107,13 @@ int writele(T *Bufo, EMUFILE*os)
}
}
#ifdef __BIG_ENDIAN__
# define FCEU_BIG_ENDIAN
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
# define FCEU_BIG_ENDIAN
#else
# define FCEU_LITTLE_ENDIAN
#endif
#endif //__FCEU_ENDIAN

View File

@ -28,53 +28,90 @@
#include "../fceu.h"
#include "memory.h"
///allocates the specified number of bytes. exits process if this fails
void *FCEU_gmalloc(uint32 size)
void *FCEU_amalloc(size_t size, size_t alignment)
{
void *ret;
ret=malloc(size);
if(!ret)
{
FCEU_PrintError("Error allocating memory! Doing a hard exit.");
exit(1);
}
FCEU_MemoryRand((uint8*)ret,size,true); // initialize according to RAMInitOption, default zero
return ret;
size = (size + alignment - 1) & ~(alignment-1);
#ifdef _MSC_VER
void *ret = _aligned_malloc(size,alignment);
#else
void *ret = aligned_alloc(alignment,size);
#endif
if(!ret)
FCEU_abort("Error allocating memory!");
return ret;
}
///allocates the specified number of bytes. returns null if this fails
void *FCEU_malloc(uint32 size)
void FCEU_afree(void* ptr)
{
void *ret;
ret=malloc(size);
if(!ret)
{
FCEU_PrintError("Error allocating memory!");
return(0);
}
memset(ret,0,size); // initialize to 0
return ret;
#ifdef _MSC_VER
_aligned_free(ptr);
#else
free(ptr);
#endif
}
static void *_FCEU_malloc(size_t size)
{
void* ret = malloc(size);
if(!ret)
FCEU_abort("Error allocating memory!");
return ret;
}
static void _FCEU_free(void* ptr)
{
free(ptr);
}
void *FCEU_gmalloc(size_t size)
{
void *ret = _FCEU_malloc(size);
// initialize according to RAMInitOption, default zero
FCEU_MemoryRand((uint8*)ret,size,true);
return ret;
}
void *FCEU_malloc(size_t size)
{
void *ret = _FCEU_malloc(size);
memset(ret, 0, size);
return ret;
}
///frees memory allocated with FCEU_gmalloc
void FCEU_gfree(void *ptr)
{
free(ptr);
_FCEU_free(ptr);
}
///frees memory allocated with FCEU_malloc
void FCEU_free(void *ptr) // Might do something with this and FCEU_malloc later...
void FCEU_free(void *ptr)
{
free(ptr);
_FCEU_free(ptr);
}
void *FCEU_dmalloc(uint32 size)
void *FCEU_dmalloc(size_t size)
{
return malloc(size);
return FCEU_malloc(size);
}
void FCEU_dfree(void *ptr)
{
free(ptr);
return FCEU_free(ptr);
}
void* FCEU_realloc(void* ptr, size_t size)
{
return realloc(ptr,size);
}
void FCEU_abort(const char* message)
{
if(message) FCEU_PrintError("%s", message);
abort();
}

View File

@ -24,13 +24,34 @@
#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); // initialized to 0
void *FCEU_gmalloc(uint32 size); // used by boards for WRAM etc, initialized to 0 (default) or other via RAMInitOption
void FCEU_gfree(void *ptr);
void FCEU_free(void *ptr);
void FCEU_memmove(void *d, void *s, uint32 l);
//returns a buffer initialized to 0
void *FCEU_malloc(size_t size);
// wrapper for debugging when its needed, otherwise act like
// normal malloc/free
void *FCEU_dmalloc(uint32 size);
//returns a buffer, with jumbled initial contents
//used by boards for WRAM etc, initialized to 0 (default) or other via RAMInitOption
void *FCEU_gmalloc(size_t size);
//free memory allocated with FCEU_gmalloc
void FCEU_gfree(void *ptr);
//returns an aligned buffer, initialized to 0
//the alignment will default to the largest thing you could ever sensibly want for massively aligned cache friendly buffers
void *FCEU_amalloc(size_t size, size_t alignment = 256);
//frees memory allocated with FCEU_amalloc
void FCEU_afree(void* ptr);
//free memory allocated with FCEU_malloc
void FCEU_free(void *ptr);
//reallocate memory allocated with FCEU_malloc
void* FCEU_realloc(void* ptr, size_t size);
//don't use these. change them if you find them.
void *FCEU_dmalloc(size_t size);
//don't use these. change them if you find them.
void FCEU_dfree(void *ptr);
//aborts the process for fatal errors
void FCEU_abort(const char* message = nullptr);

View File

@ -194,7 +194,7 @@ static const struct Base64Table
data[62] = '+'; // 62
data[63] = '/'; // 63
// create ascii->value mapping (but due to overlap, write it to highbit region)
for(a=0; a<64; ++a) data[data[a]^0x80] = a; //
for(a=0; a<64; ++a) data[data[a]^0x80] = static_cast<unsigned char>(a); //
data[((unsigned char)'=') ^ 0x80] = 0;
}
unsigned char operator[] (size_t pos) const { return data[pos]; }

View File

@ -61,15 +61,15 @@
#endif
#define FCEU_VERSION_MAJOR 2
#define FCEU_VERSION_MINOR 6
#define FCEU_VERSION_PATCH 4
#define FCEU_VERSION_MINOR 7
#define FCEU_VERSION_PATCH 0
#define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) )
#define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) )
#define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 )
#define FCEU_VERSION_PATCH_DECODE(x) (x % 100)
#define FCEU_VERSION_STRING "2.6.4" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
#define FCEU_VERSION_STRING "2.7.0" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
#define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING
#endif

View File

@ -87,23 +87,25 @@ std::string AsSnapshotName =""; //adelikat:this will set the snapshot name whe
void FCEUI_SetSnapshotAsName(std::string name) { AsSnapshotName = name; }
std::string FCEUI_GetSnapshotAsName() { return AsSnapshotName; }
static void FCEU_DrawPauseCountDown(uint8 *XBuf) { }
void FCEU_KillVirtualVideo(void)
{
if ( XBuf )
{
FCEU_free(XBuf); XBuf = NULL;
FCEU_afree(XBuf); XBuf = NULL;
}
if ( XBackBuf )
{
FCEU_free(XBackBuf); XBackBuf = NULL;
FCEU_afree(XBackBuf); XBackBuf = NULL;
}
if ( XDBuf )
{
FCEU_free(XDBuf); XDBuf = NULL;
FCEU_afree(XDBuf); XDBuf = NULL;
}
if ( XDBackBuf )
{
FCEU_free(XDBackBuf); XDBackBuf = NULL;
FCEU_afree(XDBackBuf); XDBackBuf = NULL;
}
//printf("Video Core Cleanup\n");
}
@ -116,32 +118,22 @@ void FCEU_KillVirtualVideo(void)
int FCEU_InitVirtualVideo(void)
{
//Some driver code may allocate XBuf externally.
//256 bytes per scanline, * 240 scanline maximum, +16 for alignment,
//256 bytes per scanline, * 240 scanline maximum
if(XBuf)
return 1;
XBuf = (u8*)FCEU_malloc(256 * 256 + 16);
XBackBuf = (u8*)FCEU_malloc(256 * 256 + 16);
XDBuf = (u8*)FCEU_malloc(256 * 256 + 16);
XDBackBuf = (u8*)FCEU_malloc(256 * 256 + 16);
if(!XBuf || !XBackBuf || !XDBuf || !XDBackBuf)
{
return 0;
}
XBuf = (u8*)FCEU_amalloc(256 * 256);
XBackBuf = (u8*)FCEU_amalloc(256 * 256);
XDBuf = (u8*)FCEU_amalloc(256 * 256);
XDBackBuf = (u8*)FCEU_amalloc(256 * 256);
xbsave = XBuf;
if( sizeof(uint8*) == 4 )
{
uintptr_t m = (uintptr_t)XBuf;
m = ( 8 - m) & 7;
XBuf+=m;
}
memset(XBuf,128,256*256);
memset(XBackBuf,128,256*256);
memset(XBuf,128,256*256);
memset(XBackBuf,128,256*256);
memset(XDBuf,0,256*256);
memset(XDBackBuf,0,256*256);
return 1;
}
@ -264,6 +256,7 @@ void FCEU_PutImage(void)
FCEU_DrawLagCounter(XBuf);
FCEU_DrawNTSCControlBars(XBuf);
FCEU_DrawRecordingStatus(XBuf);
FCEU_DrawPauseCountDown(XBuf);
ShowFPS();
}
@ -400,7 +393,7 @@ void snapAVI()
FCEUI_AviVideoUpdate(XBuf);
}
void FCEU_DispMessageOnMovie(const char *format, ...)
void FCEU_DispMessageOnMovie( __FCEU_PRINTF_FORMAT const char *format, ...)
{
va_list ap;
@ -419,7 +412,7 @@ void FCEU_DispMessageOnMovie(const char *format, ...)
guiMessage.howlong = 0;
}
void FCEU_DispMessage(const char *format, int disppos=0, ...)
void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos=0, ...)
{
va_list ap;
@ -432,7 +425,7 @@ void FCEU_DispMessage(const char *format, int disppos=0, ...)
vsnprintf(temp,sizeof(temp),format,ap);
va_end(ap);
strcat(temp, "\n");
FCEU_printf(temp);
FCEU_printf("%s",temp);
if ( vidGuiMsgEna )
{
@ -777,7 +770,7 @@ void ShowFPS(void)
if ( da > FCEUD_GetTimeFreq() )
{
sprintf(fpsmsg, "%.1f", (double)boopcount / ((double)da / FCEUD_GetTimeFreq()));
snprintf(fpsmsg, sizeof(fpsmsg), "%.1f", (double)boopcount / ((double)da / FCEUD_GetTimeFreq()));
boopcount = 0;
boop_ts = ts;

Some files were not shown because too many files have changed in this diff Show More