mirror of
https://github.com/dborth/fceugx.git
synced 2025-01-05 21:38:17 +01:00
sync to FCEUX svn
This commit is contained in:
parent
a44b9cf52e
commit
5b8602dadf
@ -50,7 +50,7 @@ static INLINE void MMC5BGVROM_BANK8(uint32 V) {if(CHRptr[0]){V&=CHRmask8[0];MMC5
|
||||
|
||||
static uint8 PRGBanks[4];
|
||||
static uint8 WRAMPage;
|
||||
static uint8 CHRBanksA[8], CHRBanksB[4];
|
||||
static uint16 CHRBanksA[8], CHRBanksB[4];
|
||||
static uint8 WRAMMaskEnable[2];
|
||||
uint8 mmc5ABMode; /* A=0, B=1 */
|
||||
|
||||
@ -352,7 +352,8 @@ static DECLFW(Mapper5_write)
|
||||
if(A>=0x5120&&A<=0x5127)
|
||||
{
|
||||
mmc5ABMode = 0;
|
||||
CHRBanksA[A&7]=V;
|
||||
CHRBanksA[A&7]=V | ((MMC50x5130&0x3)<<8); //if we had a test case for this then we could test this, but it hasnt been verified
|
||||
//CHRBanksA[A&7]=V;
|
||||
MMC5CHRA();
|
||||
}
|
||||
else switch(A)
|
||||
@ -416,6 +417,8 @@ static DECLFW(Mapper5_write)
|
||||
}
|
||||
ATFill=V;
|
||||
break;
|
||||
case 0x5130: MMC50x5130=V;break;
|
||||
|
||||
case 0x5200: MMC5HackSPMode=V;break;
|
||||
case 0x5201: MMC5HackSPScroll=(V>>3)&0x1F;break;
|
||||
case 0x5202: MMC5HackSPPage=V&0x3F;break;
|
||||
@ -804,8 +807,8 @@ static void GenMMC5Reset(void)
|
||||
|
||||
static SFORMAT MMC5_StateRegs[]={
|
||||
{ PRGBanks, 4, "PRGB"},
|
||||
{ CHRBanksA, 8, "CHRA"},
|
||||
{ CHRBanksB, 4, "CHRB"},
|
||||
{ CHRBanksA, 16, "CHRA"},
|
||||
{ CHRBanksB, 8, "CHRB"},
|
||||
{ &WRAMPage, 1, "WRMP"},
|
||||
{ WRAMMaskEnable, 2, "WRME"},
|
||||
{ &mmc5ABMode, 1, "ABMD"},
|
||||
@ -844,6 +847,7 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery)
|
||||
AddExState(&MMC5HackSPMode, 1, 0, "SPLM");
|
||||
AddExState(&MMC5HackSPScroll, 1, 0, "SPLS");
|
||||
AddExState(&MMC5HackSPPage, 1, 0, "SPLP");
|
||||
AddExState(&MMC50x5130, 1, 0, "5130");
|
||||
|
||||
MMC5WRAMsize=wsize/8;
|
||||
BuildWRAMSizeTable();
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include "types.h"
|
||||
#include "fceu.h"
|
||||
#include "ppu.h"
|
||||
@ -293,7 +293,7 @@ void setchr8r(int r, unsigned int V)
|
||||
if(CHRram[r])
|
||||
PPUCHRRAM|=(255);
|
||||
else
|
||||
PPUCHRRAM&=~(255);
|
||||
PPUCHRRAM=0;
|
||||
}
|
||||
|
||||
void setchr1(unsigned int A, unsigned int V)
|
||||
@ -640,7 +640,7 @@ void FCEU_SaveGameSave(CartInfo *LocalHWInfo)
|
||||
std::string soot = FCEU_MakeFName(FCEUMKF_SAV,0,"sav");
|
||||
if((sp=FCEUD_UTF8fopen(soot,"wb"))==NULL)
|
||||
{
|
||||
FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot);
|
||||
FCEU_PrintError("WRAM file \"%s\" cannot be written to.\n",soot.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -38,6 +38,7 @@ extern int MMC5Hack;
|
||||
extern uint8 *MMC5HackVROMPTR;
|
||||
extern uint8 MMC5HackCHRMode;
|
||||
extern uint8 MMC5HackSPMode;
|
||||
extern uint8 MMC50x5130;
|
||||
extern uint8 MMC5HackSPScroll;
|
||||
extern uint8 MMC5HackSPPage;
|
||||
|
||||
|
@ -242,7 +242,7 @@ zpfail:
|
||||
unzCloseCurrentFile(tz);
|
||||
unzClose(tz);
|
||||
|
||||
FCEUFILE *fceufp=fceufp = new FCEUFILE();
|
||||
FCEUFILE *fceufp = new FCEUFILE();
|
||||
fceufp->stream = ms;
|
||||
fceufp->size = size;
|
||||
return fceufp;
|
||||
@ -259,7 +259,7 @@ FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext
|
||||
|
||||
bool read = (std::string)mode == "rb";
|
||||
bool write = (std::string)mode == "wb";
|
||||
if(read&&write || (!read&&!write))
|
||||
if((read&&write) || (!read&&!write))
|
||||
{
|
||||
FCEU_PrintError("invalid file open mode specified (only wb and rb are supported)");
|
||||
return 0;
|
||||
@ -764,4 +764,4 @@ void FCEUARCHIVEFILEINFO::FilterByExtension(const char** ext)
|
||||
this->erase(begin()+i);
|
||||
ok: ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -753,6 +753,33 @@ int iNesSave(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
int iNesSaveAs(char* name)
|
||||
{
|
||||
//adelikat: TODO: iNesSave() and this have pretty much the same code, outsource the common code to a single function
|
||||
FILE *fp;
|
||||
|
||||
if(GameInfo->type != GIT_CART)return 0;
|
||||
if(GameInterface!=iNESGI)return 0;
|
||||
|
||||
fp = fopen(name,"wb");
|
||||
int x = 0;
|
||||
if (!fp)
|
||||
int x = 1;
|
||||
if(fwrite(&head,1,16,fp)!=16)return 0;
|
||||
|
||||
if(head.ROM_type&4) /* Trainer */
|
||||
{
|
||||
fwrite(trainerpoo,512,1,fp);
|
||||
}
|
||||
|
||||
fwrite(ROM,0x4000,ROM_size,fp);
|
||||
|
||||
if(head.VROM_size)fwrite(VROM,0x2000,head.VROM_size,fp);
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//para edit: added function below
|
||||
char *iNesShortFName() {
|
||||
char *ret;
|
||||
|
@ -74,6 +74,7 @@ extern uint8 *VROM;
|
||||
extern uint32 VROM_size;
|
||||
extern uint32 ROM_size;
|
||||
extern int iNesSave(); //bbit Edited: line added
|
||||
extern int iNesSaveAs(char* name);
|
||||
extern char LoadedRomFName[2048]; //bbit Edited: line added
|
||||
|
||||
//mbg merge 7/19/06 changed to c++ decl format
|
||||
|
@ -202,6 +202,9 @@ static void UpdateGP(int w, void *data, int arg)
|
||||
joy[2]= FCEU_LuaUsingJoypad(2) ? (FCEU_LuaReadJoypad(2) | (*(uint32 *)joyports[0].ptr >> 16)) : *(uint32 *)joyports[0].ptr >> 16;
|
||||
if (FCEU_LuaReadJoypadFalse(2))
|
||||
joy[2] &= FCEU_LuaReadJoypadFalse(2);
|
||||
#else // without this, there seems to be no input at all without Lua
|
||||
joy[0] = *(uint32 *)joyports[0].ptr;;
|
||||
joy[2] = *(uint32 *)joyports[0].ptr >> 16;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -215,6 +218,9 @@ static void UpdateGP(int w, void *data, int arg)
|
||||
joy[3]= FCEU_LuaUsingJoypad(3) ? (FCEU_LuaReadJoypad(3) | (*(uint32 *)joyports[1].ptr >> 24)) : *(uint32 *)joyports[1].ptr >> 24;
|
||||
if (FCEU_LuaReadJoypadFalse(3))
|
||||
joy[3] &= FCEU_LuaReadJoypadFalse(3);
|
||||
#else // same goes for the other two pads
|
||||
joy[1] = *(uint32 *)joyports[1].ptr >> 8;
|
||||
joy[3] = *(uint32 *)joyports[1].ptr >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -609,6 +615,7 @@ static void CloseRom(void);
|
||||
static void MovieSubtitleToggle(void);
|
||||
static void UndoRedoSavestate(void);
|
||||
static void FCEUI_DoExit(void);
|
||||
static void ToggleFullscreen(void);
|
||||
|
||||
struct EMUCMDTABLE FCEUI_CommandTable[]=
|
||||
{
|
||||
@ -619,8 +626,6 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
|
||||
{ EMUCMD_SCREENSHOT, EMUCMDTYPE_MISC, FCEUI_SaveSnapshot, 0, 0, "Screenshot", EMUCMDFLAG_TASEDIT },
|
||||
{ EMUCMD_HIDE_MENU_TOGGLE, EMUCMDTYPE_MISC, FCEUD_HideMenuToggle, 0, 0, "Hide Menu Toggle", EMUCMDFLAG_TASEDIT },
|
||||
{ EMUCMD_EXIT, EMUCMDTYPE_MISC, FCEUI_DoExit, 0, 0, "Exit", 0},
|
||||
//adelikat: CaH4e3, perhaps finding the true cause should be on the person who made the change?
|
||||
//Also, removing the windows only function from this table. This is a core file and should stay compatible with the SDL build
|
||||
{ EMUCMD_SPEED_SLOWEST, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Slowest Speed", 0 },
|
||||
{ EMUCMD_SPEED_SLOWER, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Speed Down", 0 },
|
||||
{ EMUCMD_SPEED_NORMAL, EMUCMDTYPE_SPEED, CommandEmulationSpeed, 0, 0, "Normal Speed", 0 },
|
||||
@ -671,7 +676,7 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
|
||||
{ EMUCMD_MOVIE_PLAY_FROM_BEGINNING, EMUCMDTYPE_MOVIE, FCEUI_MoviePlayFromBeginning, 0, 0, "Play Movie From Beginning", 0 },
|
||||
{ EMUCMD_MOVIE_STOP, EMUCMDTYPE_MOVIE, FCEUI_StopMovie, 0, 0, "Stop Movie", 0 },
|
||||
{ EMUCMD_MOVIE_READONLY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleReadOnly, 0, 0, "Toggle Read-Only", EMUCMDFLAG_TASEDIT },
|
||||
{ EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Movie Frame Display Toggle", 0 },
|
||||
{ EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, EMUCMDTYPE_MOVIE, FCEUI_MovieToggleFrameDisplay, 0, 0, "Frame Display Toggle", 0 },
|
||||
|
||||
{ EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_ToggleInputDisplay, 0, 0, "Toggle Input Display", 0 },
|
||||
{ EMUCMD_MOVIE_ICON_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUD_ToggleStatusIcon, 0, 0, "Toggle Status Icon", 0 },
|
||||
@ -722,15 +727,12 @@ struct EMUCMDTABLE FCEUI_CommandTable[]=
|
||||
{ EMUCMD_OPENROM, EMUCMDTYPE_TOOL, OpenRom, 0, 0, "Open ROM", 0},
|
||||
{ EMUCMD_CLOSEROM, EMUCMDTYPE_TOOL, CloseRom, 0, 0, "Close ROM", 0},
|
||||
{ EMUCMD_MISC_DISPLAY_MOVIESUBTITLES, EMUCMDTYPE_MISC, MovieSubtitleToggle,0,0,"Toggle Movie Subtitles", 0},
|
||||
{ EMUCMD_MISC_UNDOREDOSAVESTATE, EMUCMDTYPE_MISC, UndoRedoSavestate, 0,0,"Undo/Redo Savestate", 0}
|
||||
{ EMUCMD_MISC_UNDOREDOSAVESTATE, EMUCMDTYPE_MISC, UndoRedoSavestate, 0,0,"Undo/Redo Savestate", 0},
|
||||
{ EMUCMD_MISC_TOGGLEFULLSCREEN, EMUCMDTYPE_MISC, ToggleFullscreen, 0, 0, "Toggle Fullscreen", 0}
|
||||
};
|
||||
|
||||
#define NUM_EMU_CMDS (sizeof(FCEUI_CommandTable)/sizeof(FCEUI_CommandTable[0]))
|
||||
|
||||
// jabberwoocky my son, don't be aware lol
|
||||
// this is much mindfucking thing i ever seen here
|
||||
// even when i fixed it, there is a lot of possibilities to break all key input stuff with one
|
||||
// unarranged command enumerator.
|
||||
static int execcmd, i;
|
||||
|
||||
void FCEUI_HandleEmuCommands(TestCommandState* testfn)
|
||||
@ -949,4 +951,18 @@ static void FCEUI_DoExit(void)
|
||||
#ifdef WIN32
|
||||
DoFCEUExit();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ToggleFullscreen(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
extern int SetVideoMode(int fs); //adelikat: Yeah, I know, hacky
|
||||
extern void UpdateCheckedMenuItems();
|
||||
|
||||
UpdateCheckedMenuItems();
|
||||
changerecursive=1;
|
||||
if(!SetVideoMode(fullscreen^1))
|
||||
SetVideoMode(fullscreen);
|
||||
changerecursive=0;
|
||||
#endif
|
||||
}
|
@ -218,6 +218,7 @@ enum EMUCMD
|
||||
//-----------------------------
|
||||
EMUCMD_MISC_DISPLAY_MOVIESUBTITLES,
|
||||
EMUCMD_MISC_UNDOREDOSAVESTATE,
|
||||
EMUCMD_MISC_TOGGLEFULLSCREEN,
|
||||
EMUCMD_MAX
|
||||
};
|
||||
|
||||
|
@ -34,11 +34,12 @@
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
extern void AddRecentMovieFile(const char *filename);
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define MOVIE_VERSION 3
|
||||
#define MOVIE_VERSION 3
|
||||
|
||||
extern char FileBase[];
|
||||
extern bool AutoSS; //Declared in fceu.cpp, keeps track if a auto-savestate has been made
|
||||
@ -105,7 +106,7 @@ void MovieData::clearRecordRange(int start, int len)
|
||||
void MovieData::insertEmpty(int at, int frames)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
if(at == -1)
|
||||
if(at == -1)
|
||||
{
|
||||
int currcount = records.size();
|
||||
records.resize(records.size()+frames);
|
||||
@ -465,7 +466,7 @@ bool FCEUI_GetLagged(void)
|
||||
|
||||
bool FCEUMOV_ShouldPause(void)
|
||||
{
|
||||
if(pauseframe && currFrameCounter == pauseframe)
|
||||
if(pauseframe && currFrameCounter == (pauseframe-1)) //adelikat: changed to pauseframe -1 to prevent an off by 1 error. THis is probably the hackiest solution but I think it would cause some major restructuring to fix it properly.
|
||||
{
|
||||
pauseframe = 0; //only pause once!
|
||||
return true;
|
||||
@ -529,7 +530,7 @@ static void LoadFM2_binarychunk(MovieData& movieData, std::istream* fp, int size
|
||||
}
|
||||
|
||||
//yuck... another custom text parser.
|
||||
static bool LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopAfterHeader)
|
||||
bool LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopAfterHeader)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
//first, look for an fcm signature
|
||||
@ -780,11 +781,11 @@ void MovieData::dumpSavestateTo(std::vector<char>* buf, int compressionLevel)
|
||||
}
|
||||
|
||||
//begin playing an existing movie
|
||||
void FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _pauseframe)
|
||||
bool FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _pauseframe)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
if(!tasedit && !FCEU_IsValidUI(FCEUI_PLAYMOVIE))
|
||||
return;
|
||||
return true; //adelikat: file did not fail to load, so let's return true here, just do nothing
|
||||
|
||||
assert(fname);
|
||||
|
||||
@ -796,17 +797,22 @@ void FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _paus
|
||||
//--------------
|
||||
|
||||
currMovieData = MovieData();
|
||||
|
||||
|
||||
strcpy(curMovieFilename, fname);
|
||||
FCEUFILE *fp = FCEU_fopen(fname,0,"rb",0);
|
||||
if (!fp) return;
|
||||
if (!fp) return false;
|
||||
if(fp->isArchive() && !_read_only) {
|
||||
FCEU_PrintError("Cannot open a movie in read+write from an archive.");
|
||||
return;
|
||||
return true; //adelikat: file did not fail to load, so return true (false is only for file not exist/unable to open errors
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
//Add to the recent movie menu
|
||||
AddRecentMovieFile(fname);
|
||||
#endif
|
||||
|
||||
LoadFM2(currMovieData, fp->stream, INT_MAX, false);
|
||||
LoadSubtitles();
|
||||
LoadSubtitles(currMovieData);
|
||||
delete fp;
|
||||
|
||||
freshMovie = true; //Movie has been loaded, so it must be unaltered
|
||||
@ -818,7 +824,7 @@ void FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _paus
|
||||
if(currMovieData.savestate.size() != 0)
|
||||
{
|
||||
bool success = MovieData::loadSavestateFrom(&currMovieData.savestate);
|
||||
if(!success) return;
|
||||
if(!success) return true; //adelikat: I guess return true here? False is only for a bad movie filename, if it got this far the file was god?
|
||||
}
|
||||
|
||||
//if there is no savestate, we won't have this crucial piece of information at the start of the movie.
|
||||
@ -852,7 +858,7 @@ void FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _paus
|
||||
else
|
||||
FCEU_DispMessage("Replay started Read+Write.");
|
||||
}
|
||||
|
||||
|
||||
#ifdef CREATE_AVI
|
||||
if(LoggingEnabled)
|
||||
{
|
||||
@ -860,6 +866,9 @@ void FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _paus
|
||||
LoggingEnabled = 2;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1326,16 +1335,16 @@ bool FCEUI_MovieGetInfo(FCEUFILE* fp, MOVIE_INFO& info, bool skipFrameCount)
|
||||
}
|
||||
|
||||
//This function creates an array of frame numbers and corresponding strings for displaying subtitles
|
||||
void LoadSubtitles(void)
|
||||
void LoadSubtitles(MovieData moviedata)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
extern std::vector<string> subtitles;
|
||||
for(uint32 i=0;i<currMovieData.subtitles.size();i++)
|
||||
for(uint32 i=0; i < moviedata.subtitles.size() ; i++)
|
||||
{
|
||||
std::string& subtitle = currMovieData.subtitles[i];
|
||||
std::string& subtitle = moviedata.subtitles[i];
|
||||
size_t splitat = subtitle.find_first_of(' ');
|
||||
std::string key, value;
|
||||
|
||||
|
||||
//If we can't split them, then don't process this one
|
||||
if(splitat == std::string::npos)
|
||||
{
|
||||
@ -1381,6 +1390,16 @@ void FCEU_DisplaySubtitles(char *format, ...)
|
||||
#endif
|
||||
}
|
||||
|
||||
void FCEUI_CreateMovieFile(std::string fn)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
MovieData md = currMovieData; //Get current movie data
|
||||
std::fstream* outf = FCEUD_UTF8_fstream(fn, "wb"); //open/create file
|
||||
md.dump(outf,false); //dump movie data
|
||||
delete outf; //clean up, delete file object
|
||||
#endif
|
||||
}
|
||||
|
||||
void FCEUI_MakeBackupMovie(bool dispMessage)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
@ -1411,13 +1430,13 @@ void FCEUI_MakeBackupMovie(bool dispMessage)
|
||||
backupFn.append(".bak"); //add extension
|
||||
|
||||
exist = CheckFileExists(backupFn.c_str()); //Check if file exists
|
||||
|
||||
if (!exist)
|
||||
|
||||
if (!exist)
|
||||
break; //Yeah yeah, I should use a do loop or something
|
||||
else
|
||||
{
|
||||
backupFn = tempFn; //Before we loop again, reset the filename
|
||||
|
||||
|
||||
if (backNum == 999) //If 999 exists, we have overflowed, let's handle that
|
||||
{
|
||||
backupFn.append("-001.bak"); //We are going to simply overwrite 001.bak
|
||||
@ -1426,15 +1445,11 @@ void FCEUI_MakeBackupMovie(bool dispMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MovieData md = currMovieData; //Get current movie data
|
||||
std::fstream* outf = FCEUD_UTF8_fstream(backupFn, "wb"); //open/create file
|
||||
md.dump(outf,false); //dump movie data
|
||||
delete outf; //clean up, delete file object
|
||||
|
||||
FCEUI_CreateMovieFile(backupFn);
|
||||
|
||||
//TODO, decide if fstream successfully opened the file and print error message if it doesn't
|
||||
|
||||
if (dispMessage) //If we should inform the user
|
||||
if (dispMessage) //If we should inform the user
|
||||
{
|
||||
if (overflow)
|
||||
FCEUI_DispMessage("Backup overflow, overwriting %s",backupFn.c_str()); //Inform user of overflow
|
||||
@ -1448,26 +1463,26 @@ bool CheckFileExists(const char* filename)
|
||||
{
|
||||
#ifndef GEKKO
|
||||
//This function simply checks to see if the given filename exists
|
||||
string checkFilename;
|
||||
string checkFilename;
|
||||
|
||||
if (filename)
|
||||
checkFilename = filename;
|
||||
|
||||
|
||||
//Check if this filename exists
|
||||
fstream test;
|
||||
test.open(checkFilename.c_str(),fstream::in);
|
||||
|
||||
|
||||
if (test.fail())
|
||||
{
|
||||
test.close();
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
test.close();
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ enum EMOVIE_FLAG
|
||||
//an ARCHAIC flag which means the movie was recorded from a soft reset.
|
||||
//WHY would you do this?? do not create any new movies with this flag
|
||||
MOVIE_FLAG_FROM_RESET = (1<<1),
|
||||
|
||||
|
||||
MOVIE_FLAG_PAL = (1<<2),
|
||||
|
||||
//movie was recorded from poweron. the alternative is from a savestate (or from reset)
|
||||
@ -41,7 +41,6 @@ typedef struct
|
||||
uint32 emu_version_used; // 9813 = 0.98.13
|
||||
MD5DATA md5_of_rom_used;
|
||||
std::string name_of_rom_used;
|
||||
|
||||
#ifndef GEKKO
|
||||
std::vector<std::wstring> comments;
|
||||
#endif
|
||||
@ -93,7 +92,7 @@ class MovieRecord
|
||||
|
||||
public:
|
||||
ValueArray<uint8,4> joysticks;
|
||||
|
||||
|
||||
struct {
|
||||
uint8 x,y,b,bogo;
|
||||
uint64 zaphit;
|
||||
@ -133,7 +132,7 @@ public:
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
|
||||
//a waste of memory in lots of cases.. maybe make it a pointer later?
|
||||
std::vector<char> savestate;
|
||||
|
||||
@ -143,7 +142,7 @@ public:
|
||||
void dumpBinary(MovieData* md, std::ostream* os, int index);
|
||||
void parseJoy(std::istream* is, uint8& joystate);
|
||||
void dumpJoy(std::ostream* os, uint8 joystate);
|
||||
|
||||
|
||||
static const char mnemonics[8];
|
||||
|
||||
private:
|
||||
@ -154,7 +153,7 @@ class MovieData
|
||||
{
|
||||
public:
|
||||
MovieData();
|
||||
|
||||
|
||||
|
||||
int version;
|
||||
int emuVersion;
|
||||
@ -179,7 +178,7 @@ public:
|
||||
int ports[3];
|
||||
//whether fourscore is enabled
|
||||
bool fourscore;
|
||||
|
||||
|
||||
//----TasEdit stuff---
|
||||
int greenZoneCount;
|
||||
//----
|
||||
@ -219,7 +218,7 @@ public:
|
||||
int dump(std::ostream* os, bool binary);
|
||||
void clearRecordRange(int start, int len);
|
||||
void insertEmpty(int at, int frames);
|
||||
|
||||
|
||||
static bool loadSavestateFrom(std::vector<char>* buf);
|
||||
static void dumpSavestateTo(std::vector<char>* buf, int compressionLevel);
|
||||
void TryDumpIncremental();
|
||||
@ -246,10 +245,11 @@ extern bool autoMovieBackup;
|
||||
//--------------------------------------------------
|
||||
bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists
|
||||
void FCEUI_MakeBackupMovie(bool dispMessage);
|
||||
void FCEUI_CreateMovieFile(std::string fn);
|
||||
#ifndef GEKKO
|
||||
void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author);
|
||||
#endif
|
||||
void FCEUI_LoadMovie(const char *fname, bool read_only, bool tasedit, int _stopframe);
|
||||
bool FCEUI_LoadMovie(const char *fname, bool read_only, bool tasedit, int _stopframe);
|
||||
void FCEUI_MoviePlayFromBeginning(void);
|
||||
void FCEUI_StopMovie(void);
|
||||
bool FCEUI_MovieGetInfo(FCEUFILE* fp, MOVIE_INFO& info, bool skipFrameCount = false);
|
||||
@ -263,8 +263,8 @@ std::string FCEUI_GetMovieName(void);
|
||||
void FCEUI_MovieToggleFrameDisplay();
|
||||
void FCEUI_ToggleInputDisplay(void);
|
||||
|
||||
void LoadSubtitles(void);
|
||||
void LoadSubtitles(MovieData);
|
||||
void ProcessSubtitles(void);
|
||||
void FCEU_DisplaySubtitles(char *format, ...);
|
||||
|
||||
#endif //__MOVIE_H_
|
||||
#endif //__MOVIE_H_
|
@ -343,8 +343,9 @@ case 0x6B: {
|
||||
/* ASR */
|
||||
case 0x4B: LD_IM(AND;LSRA);
|
||||
|
||||
/* ATX(OAL) Is this(OR with $EE) correct? */
|
||||
case 0xAB: LD_IM(_A|=0xEE;AND;_X=_A);
|
||||
/* ATX(OAL) Is this(OR with $EE) correct? Blargg did some test
|
||||
and found the constant to be OR with is $FF for NES */
|
||||
case 0xAB: LD_IM(_A|=0xFF;AND;_X=_A);
|
||||
|
||||
/* AXS */
|
||||
case 0xCB: LD_IM(AXS);
|
||||
|
@ -49,6 +49,7 @@
|
||||
#define SpriteON (PPU[1]&0x10) //Show Sprite
|
||||
#define ScreenON (PPU[1]&0x08) //Show screen
|
||||
#define PPUON (PPU[1]&0x18) //PPU should operate
|
||||
#define GRAYSCALE (PPU[1]&0x01) //Grayscale (AND palette entries with 0x30)
|
||||
|
||||
#define SpriteLeft8 (PPU[1]&0x04)
|
||||
#define BGLeft8 (PPU[1]&0x02)
|
||||
@ -99,6 +100,24 @@ struct BITREVLUT {
|
||||
};
|
||||
BITREVLUT<uint8,8> bitrevlut;
|
||||
|
||||
struct PPUSTATUS
|
||||
{
|
||||
int sl;
|
||||
int cycle, end_cycle;
|
||||
};
|
||||
struct SPRITE_READ
|
||||
{
|
||||
int num;
|
||||
int count;
|
||||
int fetch;
|
||||
int found;
|
||||
int found_pos[8];
|
||||
int ret;
|
||||
int last;
|
||||
int mode;
|
||||
};
|
||||
struct SPRITE_READ spr_read = { 0 };
|
||||
|
||||
//uses the internal counters concept at http://nesdev.icequake.net/PPU%20addressing.txt
|
||||
struct PPUREGS {
|
||||
uint32 fv;//3
|
||||
@ -110,13 +129,17 @@ struct PPUREGS {
|
||||
uint32 s;//1
|
||||
uint32 par;//8
|
||||
uint32 ar;//2
|
||||
|
||||
uint32 _fv, _v, _h, _vt, _ht;
|
||||
|
||||
|
||||
uint32 _fv, _v, _h, _vt, _ht;
|
||||
|
||||
struct PPUSTATUS status;
|
||||
|
||||
PPUREGS()
|
||||
: fv(0), v(0), h(0), vt(0), ht(0), fh(0), s(0), par(0), ar(0)
|
||||
, _fv(0), _v(0), _h(0), _vt(0), _ht(0)
|
||||
{}
|
||||
{ status.cycle = 0; status.end_cycle = 341;
|
||||
status.sl = 241;
|
||||
}
|
||||
|
||||
void install_latches() {
|
||||
fv = _fv;
|
||||
@ -127,9 +150,6 @@ struct PPUREGS {
|
||||
}
|
||||
|
||||
void install_h_latches() {
|
||||
if(ht!=_ht || h != _h) {
|
||||
int zzz=9;
|
||||
}
|
||||
ht = _ht;
|
||||
h = _h;
|
||||
}
|
||||
@ -261,6 +281,7 @@ uint8 *MMC5HackExNTARAMPtr=0;
|
||||
uint8 *MMC5HackVROMPTR=0;
|
||||
uint8 MMC5HackCHRMode=0;
|
||||
uint8 MMC5HackSPMode=0;
|
||||
uint8 MMC50x5130=0;
|
||||
uint8 MMC5HackSPScroll=0;
|
||||
uint8 MMC5HackSPPage=0;
|
||||
|
||||
@ -291,8 +312,8 @@ static uint32 scanlines_per_frame;
|
||||
uint8 PPU[4];
|
||||
uint8 PPUSPL;
|
||||
uint8 NTARAM[0x800],PALRAM[0x20],SPRAM[0x100],SPRBUF[0x100];
|
||||
|
||||
|
||||
uint8 UPALRAM[0x03]; //for 0x4/0x8/0xC addresses in palette, the ones in
|
||||
//0x20 are 0 to not break fceu rendering.
|
||||
|
||||
|
||||
#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)]
|
||||
@ -320,6 +341,7 @@ uint8* FCEUPPU_GetCHR(uint32 vadr, uint32 refreshaddr) {
|
||||
if(MMC5HackCHRMode==1) {
|
||||
uint8 *C = MMC5HackVROMPTR;
|
||||
C += (((MMC5HackExNTARAMPtr[refreshaddr & 0x3ff]) & 0x3f & MMC5HackVROMMask) << 12) + (vadr & 0xfff);
|
||||
C += (MMC50x5130&0x3)<<18; //11-jun-2009 for kuja_killer
|
||||
return C;
|
||||
} else {
|
||||
return MMC5BGVRAMADR(vadr);
|
||||
@ -343,23 +365,29 @@ int FCEUPPU_GetAttr(int ntnum, int xt, int yt) {
|
||||
inline void FFCEUX_PPUWrite_Default(uint32 A, uint8 V) {
|
||||
uint32 tmp = A;
|
||||
|
||||
if(tmp>=0x3F00)
|
||||
{
|
||||
// hmmm....
|
||||
if(!(tmp&0xf))
|
||||
PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=V&0x3F;
|
||||
else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f;
|
||||
}
|
||||
else if(tmp<0x2000)
|
||||
{
|
||||
if(PPUCHRRAM&(1<<(tmp>>10)))
|
||||
VPage[tmp>>10][tmp]=V;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(PPUNTARAM&(1<<((tmp&0xF00)>>10)))
|
||||
vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V;
|
||||
}
|
||||
if(tmp<0x2000)
|
||||
{
|
||||
if(PPUCHRRAM&(1<<(tmp>>10)))
|
||||
VPage[tmp>>10][tmp]=V;
|
||||
}
|
||||
else if (tmp<0x3F00)
|
||||
{
|
||||
if(PPUNTARAM&(1<<((tmp&0xF00)>>10)))
|
||||
vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(tmp & 3))
|
||||
{
|
||||
if (!(tmp & 0xC))
|
||||
PALRAM[0x00] = PALRAM[0x04] =
|
||||
PALRAM[0x08] = PALRAM[0x0C] = V & 0x3F;
|
||||
else
|
||||
UPALRAM[((tmp & 0xC) >> 2) - 1] = V & 0x3F;
|
||||
}
|
||||
else
|
||||
PALRAM[tmp & 0x1F] = V & 0x3F;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 FFCEUX_PPURead_Default(uint32 A) {
|
||||
@ -369,10 +397,27 @@ uint8 FFCEUX_PPURead_Default(uint32 A) {
|
||||
{
|
||||
return VPage[tmp>>10][tmp];
|
||||
}
|
||||
else
|
||||
else if (tmp < 0x3F00)
|
||||
{
|
||||
return vnapage[(tmp>>10)&0x3][tmp&0x3FF];
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 ret;
|
||||
if (!(tmp & 3))
|
||||
{
|
||||
if (!(tmp & 0xC))
|
||||
ret = PALRAM[0x00];
|
||||
else
|
||||
ret = UPALRAM[((tmp & 0xC) >> 2) - 1];
|
||||
}
|
||||
else
|
||||
ret = PALRAM[tmp & 0x1F];
|
||||
|
||||
if (GRAYSCALE)
|
||||
ret &= 0x30;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -419,6 +464,191 @@ static DECLFR(A2002)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DECLFR(A2004)
|
||||
{
|
||||
if (newppu)
|
||||
{
|
||||
if ((ppur.status.sl < 241) && PPUON)
|
||||
{
|
||||
/* from cycles 0 to 63, the
|
||||
* 32 byte OAM buffer gets init
|
||||
* to 0xFF */
|
||||
if (ppur.status.cycle < 64)
|
||||
return spr_read.ret = 0xFF;
|
||||
else
|
||||
{
|
||||
for (int i = spr_read.last;
|
||||
i != ppur.status.cycle; ++i)
|
||||
{
|
||||
if (i < 256)
|
||||
{
|
||||
switch (spr_read.mode)
|
||||
{
|
||||
case 0:
|
||||
if (spr_read.count < 2)
|
||||
spr_read.ret = (PPU[3] & 0xF8)
|
||||
+ (spr_read.count << 2);
|
||||
else
|
||||
spr_read.ret = spr_read.count << 2;
|
||||
spr_read.found_pos[spr_read.found] =
|
||||
spr_read.ret;
|
||||
|
||||
spr_read.ret = SPRAM[spr_read.ret];
|
||||
|
||||
if (i & 1) //odd cycle
|
||||
{
|
||||
//see if in range
|
||||
if ( !((ppur.status.sl - 1 -
|
||||
spr_read.ret)
|
||||
& ~(Sprite16 ? 0xF : 0x7)) )
|
||||
|
||||
{
|
||||
++spr_read.found;
|
||||
spr_read.fetch = 1;
|
||||
spr_read.mode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++spr_read.count == 64)
|
||||
{
|
||||
spr_read.mode = 4;
|
||||
spr_read.count = 0;
|
||||
}
|
||||
else if (spr_read.found == 8)
|
||||
{
|
||||
spr_read.fetch = 0;
|
||||
spr_read.mode = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //sprite is in range fetch next 3 bytes
|
||||
if (i & 1)
|
||||
{
|
||||
++spr_read.fetch;
|
||||
if (spr_read.fetch == 4)
|
||||
{
|
||||
spr_read.fetch = 1;
|
||||
if (++spr_read.count == 64)
|
||||
{
|
||||
spr_read.count = 0;
|
||||
spr_read.mode = 4;
|
||||
}
|
||||
else if (spr_read.found == 8)
|
||||
{
|
||||
spr_read.fetch = 0;
|
||||
spr_read.mode = 2;
|
||||
}
|
||||
else
|
||||
spr_read.mode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (spr_read.count < 2)
|
||||
spr_read.ret = (PPU[3] & 0xF8)
|
||||
+ (spr_read.count << 2);
|
||||
else
|
||||
spr_read.ret = spr_read.count << 2;
|
||||
|
||||
spr_read.ret = SPRAM[spr_read.ret |
|
||||
spr_read.fetch];
|
||||
break;
|
||||
case 2: //8th sprite fetched
|
||||
spr_read.ret = SPRAM[(spr_read.count << 2)
|
||||
| spr_read.fetch];
|
||||
if (i & 1)
|
||||
{
|
||||
if ( !((ppur.status.sl - 1 -
|
||||
SPRAM[((spr_read.count << 2)
|
||||
| spr_read.fetch)])
|
||||
& ~((Sprite16) ? 0xF : 0x7)) )
|
||||
{
|
||||
spr_read.fetch = 1;
|
||||
spr_read.mode = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++spr_read.count == 64)
|
||||
{
|
||||
spr_read.count = 0;
|
||||
spr_read.mode = 4;
|
||||
}
|
||||
spr_read.fetch =
|
||||
(spr_read.fetch + 1) & 3;
|
||||
}
|
||||
}
|
||||
spr_read.ret = spr_read.count;
|
||||
break;
|
||||
case 3: //9th sprite overflow detected
|
||||
spr_read.ret = SPRAM[spr_read.count
|
||||
| spr_read.fetch];
|
||||
if (i & 1)
|
||||
{
|
||||
if (++spr_read.fetch == 4)
|
||||
{
|
||||
spr_read.count = (spr_read.count
|
||||
+ 1) & 63;
|
||||
spr_read.mode = 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: //read OAM[n][0] until hblank
|
||||
if (i & 1)
|
||||
spr_read.count =
|
||||
(spr_read.count + 1) & 63;
|
||||
spr_read.fetch = 0;
|
||||
spr_read.ret = SPRAM[spr_read.count << 2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (i < 320)
|
||||
{
|
||||
spr_read.ret = (i & 0x38) >> 3;
|
||||
if (spr_read.found < (spr_read.ret + 1))
|
||||
{
|
||||
if (spr_read.num)
|
||||
{
|
||||
spr_read.ret = SPRAM[252];
|
||||
spr_read.num = 0;
|
||||
}
|
||||
else
|
||||
spr_read.ret = 0xFF;
|
||||
}
|
||||
else if ((i & 7) < 4)
|
||||
{
|
||||
spr_read.ret =
|
||||
SPRAM[spr_read.found_pos[spr_read.ret]
|
||||
| spr_read.fetch++];
|
||||
if (spr_read.fetch == 4)
|
||||
spr_read.fetch = 0;
|
||||
}
|
||||
else
|
||||
spr_read.ret = SPRAM[spr_read.found_pos
|
||||
[spr_read.ret | 3]];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!spr_read.found)
|
||||
spr_read.ret = SPRAM[252];
|
||||
else
|
||||
spr_read.ret = SPRAM[spr_read.found_pos[0]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
spr_read.last = ppur.status.cycle;
|
||||
return spr_read.ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
return SPRAM[PPU[3]];
|
||||
}
|
||||
else
|
||||
{
|
||||
FCEUPPU_LineUpdate();
|
||||
return PPUGenLatch;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFR(A200x) /* Not correct for $2004 reads. */
|
||||
{
|
||||
FCEUPPU_LineUpdate();
|
||||
@ -456,14 +686,34 @@ static DECLFR(A2007)
|
||||
uint32 tmp=RefreshAddr&0x3FFF;
|
||||
|
||||
if(newppu) {
|
||||
//mbg
|
||||
ret = VRAMBuffer;
|
||||
RefreshAddr = ppur.get_2007access();
|
||||
VRAMBuffer = CALL_PPUREAD(RefreshAddr);
|
||||
ret = VRAMBuffer;
|
||||
RefreshAddr = ppur.get_2007access() & 0x3FFF;
|
||||
if ((RefreshAddr & 0x3F00) == 0x3F00)
|
||||
{
|
||||
//if it is in the palette range bypass the
|
||||
//delayed read, and what gets filled in the temp
|
||||
//buffer is the address - 0x1000, also
|
||||
//if grayscale is set then the return is AND with 0x30
|
||||
//to get a gray color reading
|
||||
if (!(tmp & 3))
|
||||
{
|
||||
if (!(tmp & 0xC))
|
||||
ret = PALRAM[0x00];
|
||||
else
|
||||
ret = UPALRAM[((tmp & 0xC) >> 2) - 1];
|
||||
}
|
||||
else
|
||||
ret = PALRAM[tmp & 0x1F];
|
||||
if (GRAYSCALE)
|
||||
ret &= 0x30;
|
||||
VRAMBuffer = CALL_PPUREAD(RefreshAddr - 0x1000);
|
||||
}
|
||||
else
|
||||
VRAMBuffer = CALL_PPUREAD(RefreshAddr);
|
||||
ppur.increment2007(INC32!=0);
|
||||
RefreshAddr = ppur.get_2007access();
|
||||
return ret;
|
||||
} else {
|
||||
return ret;
|
||||
} else {
|
||||
FCEUPPU_LineUpdate();
|
||||
|
||||
ret=VRAMBuffer;
|
||||
@ -478,7 +728,7 @@ static DECLFR(A2007)
|
||||
{
|
||||
VRAMBuffer=VPage[tmp>>10][tmp];
|
||||
}
|
||||
else
|
||||
else if (tmp < 0x3F00)
|
||||
{
|
||||
VRAMBuffer=vnapage[(tmp>>10)&0x3][tmp&0x3FF];
|
||||
}
|
||||
@ -525,7 +775,7 @@ static DECLFW(B2001)
|
||||
if(V&0xE0)
|
||||
deemp=V>>5;
|
||||
}
|
||||
|
||||
//
|
||||
static DECLFW(B2002)
|
||||
{
|
||||
PPUGenLatch=V;
|
||||
@ -542,21 +792,32 @@ static DECLFW(B2003)
|
||||
static DECLFW(B2004)
|
||||
{
|
||||
//printf("Wr: %04x:$%02x\n",A,V);
|
||||
|
||||
PPUGenLatch=V;
|
||||
if(PPUSPL>=8)
|
||||
{
|
||||
if(PPU[3]>=8)
|
||||
SPRAM[PPU[3]]=V;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("$%02x:$%02x\n",PPUSPL,V);
|
||||
SPRAM[PPUSPL]=V;
|
||||
}
|
||||
PPU[3]++;
|
||||
PPUSPL++;
|
||||
|
||||
PPUGenLatch=V;
|
||||
if (newppu)
|
||||
{
|
||||
//the attribute upper bits are not connected
|
||||
//so AND them out on write, since reading them
|
||||
//should return 0 in those bits.
|
||||
if ((PPU[3] & 3) == 2)
|
||||
V &= 0xE3;
|
||||
SPRAM[PPU[3]] = V;
|
||||
PPU[3] = (PPU[3] + 1) & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(PPUSPL>=8)
|
||||
{
|
||||
if(PPU[3]>=8)
|
||||
SPRAM[PPU[3]]=V;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("$%02x:$%02x\n",PPUSPL,V);
|
||||
SPRAM[PPUSPL]=V;
|
||||
}
|
||||
PPU[3]++;
|
||||
PPUSPL++;
|
||||
}
|
||||
}
|
||||
|
||||
static DECLFW(B2005)
|
||||
@ -618,15 +879,8 @@ static DECLFW(B2006)
|
||||
ppur._ht = V&31;
|
||||
|
||||
ppur.install_latches();
|
||||
|
||||
if(RefreshAddr==0x18DE) {
|
||||
int zzz=9;
|
||||
}
|
||||
}
|
||||
|
||||
if(ppur._fv == 1) {
|
||||
int zzz=9;
|
||||
}
|
||||
vtoggle^=1;
|
||||
}
|
||||
|
||||
@ -635,7 +889,7 @@ static DECLFW(B2007)
|
||||
uint32 tmp=RefreshAddr&0x3FFF;
|
||||
|
||||
if(newppu) {
|
||||
RefreshAddr = ppur.get_2007access();
|
||||
RefreshAddr = ppur.get_2007access() & 0x3FFF;
|
||||
CALL_PPUWRITE(RefreshAddr,V);
|
||||
//printf("%04x ",RefreshAddr);
|
||||
ppur.increment2007(INC32!=0);
|
||||
@ -644,13 +898,6 @@ static DECLFW(B2007)
|
||||
else
|
||||
{
|
||||
//printf("%04x ",tmp);
|
||||
if(tmp==0x2679)
|
||||
{
|
||||
int zzz=9;
|
||||
}
|
||||
if(tmp == 0x3f13 ) {
|
||||
int zzz=9;
|
||||
}
|
||||
PPUGenLatch=V;
|
||||
if(tmp>=0x3F00)
|
||||
{
|
||||
@ -1539,7 +1786,6 @@ void FCEUPPU_Reset(void)
|
||||
vtoggle = 0;
|
||||
ppudead = 2;
|
||||
kook = 0;
|
||||
|
||||
// XOffset=0;
|
||||
}
|
||||
|
||||
@ -1548,7 +1794,8 @@ void FCEUPPU_Power(void)
|
||||
int x;
|
||||
|
||||
memset(NTARAM,0x00,0x800);
|
||||
memset(PALRAM,0x00,0x20);
|
||||
memset(PALRAM,0x00,0x20);
|
||||
memset(UPALRAM,0x00,0x03);
|
||||
memset(SPRAM,0x00,0x100);
|
||||
FCEUPPU_Reset();
|
||||
|
||||
@ -1562,7 +1809,7 @@ void FCEUPPU_Power(void)
|
||||
BWrite[x+2]=B2002;
|
||||
ARead[x+3]=A200x;
|
||||
BWrite[x+3]=B2003;
|
||||
ARead[x+4]=A200x; //A2004;
|
||||
ARead[x+4]=A2004; //A2004;
|
||||
BWrite[x+4]=B2004;
|
||||
ARead[x+5]=A200x;
|
||||
BWrite[x+5]=B2005;
|
||||
@ -1753,11 +2000,13 @@ int pputime=0;
|
||||
int totpputime=0;
|
||||
const int kLineTime=341;
|
||||
const int kFetchTime=2;
|
||||
int idleSynch = 0;
|
||||
int idleSynch = 1;
|
||||
|
||||
void runppu(int x) {
|
||||
//pputime+=x;
|
||||
//if(cputodo<200) return;
|
||||
ppur.status.cycle = (ppur.status.cycle + x) %
|
||||
ppur.status.end_cycle;
|
||||
X6502_Run(x);
|
||||
//pputime -= cputodo<<2;
|
||||
}
|
||||
@ -1774,24 +2023,30 @@ struct BGData {
|
||||
|
||||
RefreshAddr = ppur.get_atread();
|
||||
at = CALL_PPUREAD(RefreshAddr);
|
||||
runppu(kFetchTime);
|
||||
|
||||
|
||||
//modify at to get appropriate palette shift
|
||||
if(ppur.vt&2) at >>= 4;
|
||||
if(ppur.ht&2) at >>= 2;
|
||||
at &= 0x03;
|
||||
at <<= 2;
|
||||
|
||||
ppur.par = nt;
|
||||
//horizontal scroll clocked at cycle 3 and then
|
||||
//vertical scroll at 251
|
||||
runppu(1);
|
||||
if (PPUON)
|
||||
{
|
||||
ppur.increment_hsc();
|
||||
if (ppur.status.cycle == 251)
|
||||
ppur.increment_vs();
|
||||
}
|
||||
runppu(1);
|
||||
|
||||
ppur.par = nt;
|
||||
RefreshAddr = ppur.get_ptread();
|
||||
pt[0] = CALL_PPUREAD(RefreshAddr);
|
||||
runppu(kFetchTime);
|
||||
RefreshAddr |= 8;
|
||||
pt[1] = CALL_PPUREAD(RefreshAddr);
|
||||
runppu(kFetchTime);
|
||||
|
||||
if(PPUON)
|
||||
ppur.increment_hsc();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1802,15 +2057,24 @@ struct BGData {
|
||||
int framectr=0;
|
||||
int FCEUX_PPU_Loop(int skip) {
|
||||
//262 scanlines
|
||||
|
||||
if(ppudead)
|
||||
{
|
||||
memset(XBuf, 0x80, 256*240);
|
||||
runppu(262*kLineTime);
|
||||
ppudead--;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (ppudead)
|
||||
{
|
||||
/* not quite emulating all the NES power up behavior
|
||||
* since it is known that the NES ignores writes to some
|
||||
* register before around a full frame, but no games
|
||||
* should write to those regs during that time, it needs
|
||||
* to wait for vblank */
|
||||
ppur.status.sl = 241;
|
||||
if (PAL)
|
||||
runppu(70*kLineTime);
|
||||
else
|
||||
runppu(20*kLineTime);
|
||||
ppur.status.sl = 0;
|
||||
runppu(242*kLineTime);
|
||||
ppudead = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
{
|
||||
PPU_status |= 0x80;
|
||||
ppuphase = PPUPHASE_VBL;
|
||||
@ -1818,16 +2082,20 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
//Not sure if this is correct. According to Matt Conte and my own tests, it is.
|
||||
//Timing is probably off, though.
|
||||
//NOTE: Not having this here breaks a Super Donkey Kong game.
|
||||
//PPU[3]=PPUSPL=0;
|
||||
|
||||
PPU[3]=PPUSPL=0;
|
||||
const int delay = 20; //fceu used 12 here but I couldnt get it to work in marble madness and pirates.
|
||||
runppu(delay); //X6502_Run(12);
|
||||
|
||||
ppur.status.sl = 241; //for sprite reads
|
||||
|
||||
runppu(delay); //X6502_Run(12);
|
||||
if(VBlankON) TriggerNMI();
|
||||
runppu(20*(kLineTime)-delay);
|
||||
|
||||
if (PAL)
|
||||
runppu(70*(kLineTime)-delay);
|
||||
else
|
||||
runppu(20*(kLineTime)-delay);
|
||||
|
||||
//this seems to run just before the dummy scanline begins
|
||||
PPU_status&=0x1f;
|
||||
|
||||
PPU_status = 0;
|
||||
//this early out caused metroid to fail to boot. I am leaving it here as a reminder of what not to do
|
||||
//if(!PPUON) { runppu(kLineTime*242); goto finish; }
|
||||
|
||||
@ -1837,8 +2105,8 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
//rendering data for the first time in a frame (this update won't happen if
|
||||
//all rendering is disabled via 2001.3 and 2001.4).
|
||||
|
||||
if(PPUON)
|
||||
ppur.install_latches();
|
||||
//if(PPUON)
|
||||
// ppur.install_latches();
|
||||
|
||||
uint8 oams[2][64][7];
|
||||
int oamcounts[2]={0,0};
|
||||
@ -1847,11 +2115,19 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
|
||||
//capture the initial xscroll
|
||||
//int xscroll = ppur.fh;
|
||||
|
||||
//render 241 scanlines (including 1 dummy at beginning)
|
||||
for(int sl=0;sl<241;sl++) {
|
||||
int yp = sl-1;
|
||||
spr_read.num = 1;
|
||||
spr_read.found = 0;
|
||||
spr_read.fetch = 1;
|
||||
spr_read.count = 0;
|
||||
spr_read.last = 64;
|
||||
spr_read.mode = 0;
|
||||
memset(spr_read.found_pos, 0, sizeof(spr_read.found_pos));
|
||||
|
||||
ppur.status.sl = sl;
|
||||
|
||||
int yp = sl-1;
|
||||
ppuphase = PPUPHASE_BG;
|
||||
|
||||
if(sl != 0) {
|
||||
@ -1875,7 +2151,7 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
for(int xt=0;xt<32;xt++) {
|
||||
bgdata.main[xt+2].Read();
|
||||
|
||||
//ok, we're also going to draw here.
|
||||
//ok, we're also going to draw here.
|
||||
//unless we're on the first dummy scanline
|
||||
if(sl != 0) {
|
||||
int xstart = xt<<3;
|
||||
@ -1887,7 +2163,6 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
//check all the conditions that can cause things to render in these 8px
|
||||
bool renderspritenow = SpriteON && rendersprites && (xt>0 || SpriteLeft8);
|
||||
bool renderbgnow = ScreenON && renderbg && (xt>0 || BGLeft8);
|
||||
|
||||
for(int xp=0;xp<8;xp++,rasterpos++) {
|
||||
|
||||
//bg pos is different from raster pos due to its offsetability.
|
||||
@ -1987,14 +2262,19 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
//FV is clocked by the PPU's horizontal blanking impulse, and therefore will increment every scanline.
|
||||
//well, according to (which?) tests, maybe at the end of hblank.
|
||||
//but, according to what it took to get crystalis working, it is at the beginning of hblank.
|
||||
if(PPUON && sl != 0)
|
||||
ppur.increment_vs();
|
||||
|
||||
//this is done at cycle 251
|
||||
//rendering scanline, it doesn't need to be scanline 0,
|
||||
//because on the first scanline when the increment is 0, the vs_scroll is reloaded.
|
||||
//if(PPUON && sl != 0)
|
||||
// ppur.increment_vs();
|
||||
|
||||
//todo - think about clearing oams to a predefined value to force deterministic behavior
|
||||
|
||||
//so.. this is the end of hblank. latch horizontal scroll values
|
||||
if(PPUON && sl != 0)
|
||||
ppur.install_h_latches();
|
||||
//do it cycle at 251
|
||||
if(PPUON && sl != 0)
|
||||
ppur.install_h_latches();
|
||||
|
||||
ppuphase = PPUPHASE_OBJ;
|
||||
|
||||
@ -2035,7 +2315,23 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
patternAddress += line&7;
|
||||
|
||||
//garbage nametable fetches
|
||||
if(realSprite) runppu(kFetchTime);
|
||||
//reset the scroll counter, happens at cycle 304
|
||||
if (realSprite)
|
||||
{
|
||||
if ((sl == 0) && PPUON)
|
||||
{
|
||||
if (ppur.status.cycle == 304)
|
||||
{
|
||||
runppu(1);
|
||||
ppur.install_latches();
|
||||
runppu(1);
|
||||
}
|
||||
else
|
||||
runppu(kFetchTime);
|
||||
}
|
||||
else
|
||||
runppu(kFetchTime);
|
||||
}
|
||||
|
||||
if(((PPU[0]&0x38)!=0x18) && s == 2 && SpriteON ) {
|
||||
//(The MMC3 scanline counter is based entirely on PPU A12, triggered on rising edges (after the line remains low for a sufficiently long period of time))
|
||||
@ -2050,15 +2346,16 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
|
||||
if(realSprite) runppu(kFetchTime);
|
||||
|
||||
|
||||
//pattern table fetches
|
||||
RefreshAddr = patternAddress;
|
||||
oam[4] = CALL_PPUREAD(RefreshAddr);
|
||||
if(realSprite) runppu(kFetchTime);
|
||||
|
||||
RefreshAddr += 8;
|
||||
oam[5] = CALL_PPUREAD(RefreshAddr);
|
||||
if(realSprite) runppu(kFetchTime);
|
||||
|
||||
|
||||
//hflip
|
||||
if(!(oam[2]&0x40)) {
|
||||
oam[4] = bitrevlut[oam[4]];
|
||||
@ -2077,29 +2374,32 @@ int FCEUX_PPU_Loop(int skip) {
|
||||
//same nametable address that points to the 3rd tile to be rendered on the
|
||||
//screen (or basically, the first nametable address that will be accessed when
|
||||
//the PPU is fetching background data on the next scanline).
|
||||
//(not implemented yet)
|
||||
//(not implemented yet)
|
||||
runppu(kFetchTime);
|
||||
if (sl == 0)
|
||||
{
|
||||
if (idleSynch && PPUON && !PAL)
|
||||
ppur.status.end_cycle = 340;
|
||||
else
|
||||
ppur.status.end_cycle = 341;
|
||||
idleSynch ^= 1;
|
||||
}
|
||||
else
|
||||
ppur.status.end_cycle = 341;
|
||||
runppu(kFetchTime);
|
||||
|
||||
|
||||
//After memory access 170, the PPU simply rests for 4 cycles (or the
|
||||
//After memory access 170, the PPU simply rests for 4 cycles (or the
|
||||
//equivelant of half a memory access cycle) before repeating the whole
|
||||
//pixel/scanline rendering process. If the scanline being rendered is the very
|
||||
//first one on every second frame, then this delay simply doesn't exist.
|
||||
if(sl==0 && idleSynch==0)
|
||||
{}
|
||||
else
|
||||
runppu(1);
|
||||
}
|
||||
|
||||
idleSynch ++;
|
||||
if(idleSynch==2) idleSynch = 0;
|
||||
if (ppur.status.end_cycle == 341)
|
||||
runppu(1);
|
||||
}
|
||||
|
||||
if(MMC5Hack && PPUON) MMC5_hb(240);
|
||||
|
||||
//idle for one line
|
||||
runppu(kLineTime);
|
||||
|
||||
framectr++;
|
||||
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ pshift[1]<<=8;
|
||||
C = MMC5HackVROMPTR;
|
||||
C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f &
|
||||
MMC5HackVROMMask) << 12) + (vadr & 0xfff);
|
||||
C += (MMC50x5130&0x3)<<18; //11-jun-2009 for kuja_killer
|
||||
#elif defined(PPUT_MMC5)
|
||||
C=MMC5BGVRAMADR(vadr);
|
||||
#else
|
||||
|
@ -89,25 +89,41 @@ static int32 sqacc[2];
|
||||
static int32 lengthcount[4];
|
||||
static const uint8 lengthtable[0x20]=
|
||||
{
|
||||
0x5*2,0x7f*2,0xA*2,0x1*2,0x14*2,0x2*2,0x28*2,0x3*2,0x50*2,0x4*2,0x1E*2,0x5*2,0x7*2,0x6*2,0x0E*2,0x7*2,
|
||||
0x6*2,0x08*2,0xC*2,0x9*2,0x18*2,0xa*2,0x30*2,0xb*2,0x60*2,0xc*2,0x24*2,0xd*2,0x8*2,0xe*2,0x10*2,0xf*2
|
||||
10,254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14,
|
||||
12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30
|
||||
};
|
||||
|
||||
static const uint32 NoiseFreqTable[0x10]=
|
||||
|
||||
static const uint32 NoiseFreqTableNTSC[0x10] =
|
||||
{
|
||||
2,4,8,0x10,0x20,0x30,0x40,0x50,0x65,0x7f,0xbe,0xfe,0x17d,0x1fc,0x3f9,0x7f2
|
||||
4, 8, 16, 32, 64, 96, 128, 160, 202,
|
||||
254, 380, 508, 762, 1016, 2034, 4068
|
||||
};
|
||||
|
||||
static const uint32 NoiseFreqTablePAL[0x10] =
|
||||
{
|
||||
4, 7, 14, 30, 60, 88, 118, 148, 188,
|
||||
236, 354, 472, 708, 944, 1890, 3778
|
||||
};
|
||||
|
||||
static const uint32 *NoiseFreqTable = NoiseFreqTableNTSC;
|
||||
|
||||
static const uint32 NTSCDMCTable[0x10]=
|
||||
{
|
||||
428,380,340,320,286,254,226,214,
|
||||
190,160,142,128,106, 84 ,72,54
|
||||
};
|
||||
|
||||
/* Previous values for PAL DMC was value - 1,
|
||||
* I am not certain if this is if FCEU handled
|
||||
* PAL differently or not, the NTSC values are right,
|
||||
* so I am assuming that the current value is handled
|
||||
* the same way NTSC is handled. */
|
||||
|
||||
static const uint32 PALDMCTable[0x10]=
|
||||
{
|
||||
397, 353, 315, 297, 265, 235, 209, 198,
|
||||
176, 148, 131, 118, 98, 78, 66, 50,
|
||||
398, 354, 316, 298, 276, 236, 210, 198,
|
||||
176, 148, 132, 118, 98, 78, 66, 50
|
||||
};
|
||||
|
||||
// $4010 - Frequency
|
||||
@ -575,7 +591,7 @@ static INLINE void RDoSQ(int x) //Int x decides if this is Square Wave 1 or 2
|
||||
|
||||
//Modify Square wave volume based on channel volume modifiers
|
||||
//adelikat: Note: the formulat x = x * y /100 does not yield exact results, but is "close enough" and avoids the need for using double vales or implicit cohersion which are slower (we need speed here)
|
||||
ampx = x ? FSettings.Square1Volume : FSettings.Square2Volume; // TODO OPTIMIZE ME!
|
||||
ampx = x ? FSettings.Square2Volume : FSettings.Square1Volume; // TODO OPTIMIZE ME!
|
||||
if (ampx != 256) amp = (amp * ampx) / 256; // CaH4e3: fixed - setting up maximum volume for square2 caused complete mute square2 channel
|
||||
|
||||
amp<<=24;
|
||||
@ -837,7 +853,9 @@ static void RDoTriangleNoisePCMLQ(void)
|
||||
if(noiseacc<=0)
|
||||
{
|
||||
rea2:
|
||||
noiseacc+=NoiseFreqTable[PSG[0xE]&0xF]<<(16+2);
|
||||
//used to added <<(16+2) when the noise table
|
||||
//values were half.
|
||||
noiseacc+=NoiseFreqTable[PSG[0xE]&0xF]<<(16+1);
|
||||
nreg=(nreg<<1)+(((nreg>>nshift)^(nreg>>14))&1);
|
||||
nreg&=0x7fff;
|
||||
noiseout=amptab[(nreg>>0xe)];
|
||||
@ -876,7 +894,9 @@ static void RDoTriangleNoisePCMLQ(void)
|
||||
if(noiseacc<=0)
|
||||
{
|
||||
area2:
|
||||
noiseacc+=NoiseFreqTable[PSG[0xE]&0xF]<<(16+2);
|
||||
//used to be added <<(16+2) when the noise table
|
||||
//values were half.
|
||||
noiseacc+=NoiseFreqTable[PSG[0xE]&0xF]<<(16+1);
|
||||
nreg=(nreg<<1)+(((nreg>>nshift)^(nreg>>14))&1);
|
||||
nreg&=0x7fff;
|
||||
noiseout=amptab[(nreg>>0xe)];
|
||||
@ -927,7 +947,7 @@ static void RDoNoise(void)
|
||||
if(!wlcount[3])
|
||||
{
|
||||
uint8 feedback;
|
||||
wlcount[3]=NoiseFreqTable[PSG[0xE]&0xF]<<1;
|
||||
wlcount[3]=NoiseFreqTable[PSG[0xE]&0xF];
|
||||
feedback=((nreg>>8)&1)^((nreg>>14)&1);
|
||||
nreg=(nreg<<1)+feedback;
|
||||
nreg&=0x7fff;
|
||||
@ -942,7 +962,7 @@ static void RDoNoise(void)
|
||||
if(!wlcount[3])
|
||||
{
|
||||
uint8 feedback;
|
||||
wlcount[3]=NoiseFreqTable[PSG[0xE]&0xF]<<1;
|
||||
wlcount[3]=NoiseFreqTable[PSG[0xE]&0xF];
|
||||
feedback=((nreg>>13)&1)^((nreg>>14)&1);
|
||||
nreg=(nreg<<1)+feedback;
|
||||
nreg&=0x7fff;
|
||||
@ -1063,25 +1083,32 @@ due to that whole MegaMan 2 Game Genie thing.
|
||||
|
||||
void FCEUSND_Reset(void)
|
||||
{
|
||||
int x;
|
||||
|
||||
int x;
|
||||
|
||||
IRQFrameMode=0x0;
|
||||
fhcnt=fhinc;
|
||||
fcnt=0;
|
||||
fhcnt=fhinc;
|
||||
fcnt=0;
|
||||
nreg=1;
|
||||
|
||||
nreg=1;
|
||||
for(x=0;x<2;x++)
|
||||
if (PAL)
|
||||
NoiseFreqTable = NoiseFreqTablePAL;
|
||||
else
|
||||
NoiseFreqTable = NoiseFreqTableNTSC;
|
||||
|
||||
for(x=0;x<2;x++)
|
||||
{
|
||||
wlcount[x]=2048;
|
||||
if(nesincsize) // lq mode
|
||||
sqacc[x]=((uint32)2048<<17)/nesincsize;
|
||||
else
|
||||
sqacc[x]=1;
|
||||
sweepon[x]=0;
|
||||
curfreq[x]=0;
|
||||
wlcount[x]=2048;
|
||||
if(nesincsize) // lq mode
|
||||
sqacc[x]=((uint32)2048<<17)/nesincsize;
|
||||
else
|
||||
sqacc[x]=1;
|
||||
sweepon[x]=0;
|
||||
curfreq[x]=0;
|
||||
}
|
||||
wlcount[2]=1; //2048;
|
||||
wlcount[3]=2048;
|
||||
|
||||
wlcount[2]=1; //2048;
|
||||
wlcount[3]=2048;
|
||||
|
||||
DMCHaveDMA=DMCHaveSample=0;
|
||||
SIRQStat=0x00;
|
||||
|
||||
|
@ -332,7 +332,7 @@ static bool ReadStateChunks(std::istream* is, int32 totalsize)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CurrentState=1;
|
||||
int CurrentState=0;
|
||||
extern int geniestage;
|
||||
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
#define __FCEU_TYPES
|
||||
|
||||
#define FCEU_NAME "FCEUX"
|
||||
#define FCEU_VERSION_STRING "2.1.0a"
|
||||
#define FCEU_VERSION_STRING "2.1.1-interim"
|
||||
#define FCEU_VERSION_NUMERIC 20100
|
||||
#define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING
|
||||
|
||||
|
@ -237,8 +237,8 @@ char *md5_asciistr(MD5DATA& md5)
|
||||
|
||||
for(x=0;x<16;x++)
|
||||
{
|
||||
str[x*2]=trans[digest[x]&0x0F];
|
||||
str[x*2+1]=trans[digest[x]>>4];
|
||||
str[x*2]=trans[digest[x]>>4];
|
||||
str[x*2+1]=trans[digest[x]&0x0F];
|
||||
}
|
||||
return(str);
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ private:
|
||||
throw new std::runtime_error("memory_streambuf is not expandable");
|
||||
|
||||
size_t newcapacity;
|
||||
if(upto == 0)
|
||||
if(upto == -1)
|
||||
newcapacity = capacity + capacity/2 + 2;
|
||||
else
|
||||
newcapacity = std::max(upto,capacity);
|
||||
|
@ -29,7 +29,6 @@
|
||||
#endif
|
||||
|
||||
#include "x6502abbrev.h"
|
||||
|
||||
X6502 X;
|
||||
uint32 timestamp;
|
||||
void (*MapIRQHook)(int a);
|
||||
@ -574,4 +573,4 @@ const uint8 optype[256] = {
|
||||
/*0xD0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0xE0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0xF0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user