sync to FCEUX svn

This commit is contained in:
dborth 2009-07-17 22:54:58 +00:00
parent a44b9cf52e
commit 5b8602dadf
19 changed files with 605 additions and 212 deletions

View File

@ -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();

View File

@ -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
{

View File

@ -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;

View File

@ -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: ;
}
}
}

View File

@ -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;

View File

@ -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

View File

@ -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
}

View File

@ -218,6 +218,7 @@ enum EMUCMD
//-----------------------------
EMUCMD_MISC_DISPLAY_MOVIESUBTITLES,
EMUCMD_MISC_UNDOREDOSAVESTATE,
EMUCMD_MISC_TOGGLEFULLSCREEN,
EMUCMD_MAX
};

View File

@ -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
}
}

View File

@ -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_

View File

@ -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);

View File

@ -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++;
}

View File

@ -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

View File

@ -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;

View File

@ -332,7 +332,7 @@ static bool ReadStateChunks(std::istream* is, int32 totalsize)
return ret;
}
int CurrentState=1;
int CurrentState=0;
extern int geniestage;

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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
};
};