# HG changeset patch # User Robert McIntyre # Date 1330932311 21600 # Node ID 44974c3e093bef96fbecbb87517ae42ad6e66c50 # Parent 0dc331ec7f2702272f036fc30380b4059ce40f46 found source of problem for video recording diff -r 0dc331ec7f27 -r 44974c3e093b commands.sh --- a/commands.sh Sun Mar 04 22:44:42 2012 -0600 +++ b/commands.sh Mon Mar 05 01:25:11 2012 -0600 @@ -1,12 +1,21 @@ + # This buffer is for notes you don't want to save, and for Lisp evaluation. # If you want to create a file, visit that file with C-x C-f, # then enter the text in that file's own buffer. -./VisualBoyAdvance ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc +#./VisualBoyAdvance ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc -./VisualBoyAdvance --recordmovie=./rlm.vbm ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc +#./VisualBoyAdvance --recordmovie=./rlm.vbm ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc +rm -f /home/r/proj/vba-restore/build/movie.vba -./VisualBoyAdvance --recordmovie=/home/r/proj/vba-restore/build/ /home/r/proj/pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc \ No newline at end of file +cd /home/r/proj/vba-restore/build +make install + +/home/r/proj/vba-restore/build/artifacts/bin/VisualBoyAdvance --recordmovie=/home/r/proj/vba-restore/build/movie.vba /home/r/proj/pokemon-escape/roms/yellow.gbc + +#.//VisualBoyAdvance --playmovie=/home/r/proj/vba-restore/build/movie.vba /home/r/proj/pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc + +hexdump -C /home/r/proj/vba-restore/build/movie.vba diff -r 0dc331ec7f27 -r 44974c3e093b src/common/movie.cpp --- a/src/common/movie.cpp Sun Mar 04 22:44:42 2012 -0600 +++ b/src/common/movie.cpp Mon Mar 05 01:25:11 2012 -0600 @@ -73,1613 +73,1628 @@ // little-endian integer pop/push functions: static inline uint32 Pop32(const uint8 * &ptr) { - uint32 v = (ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); - ptr += 4; - return v; + uint32 v = (ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); + ptr += 4; + return v; } static inline uint16 Pop16(const uint8 * &ptr) /* const version */ { - uint16 v = (ptr[0] | (ptr[1] << 8)); - ptr += 2; - return v; + uint16 v = (ptr[0] | (ptr[1] << 8)); + ptr += 2; + return v; } static inline uint16 Pop16(uint8 * &ptr) /* non-const version */ { - uint16 v = (ptr[0] | (ptr[1] << 8)); - ptr += 2; - return v; + uint16 v = (ptr[0] | (ptr[1] << 8)); + ptr += 2; + return v; } static inline uint8 Pop8(const uint8 * &ptr) { - return *(ptr)++; + return *(ptr)++; } static inline void Push32(uint32 v, uint8 * &ptr) { - ptr[0] = (uint8)(v & 0xff); - ptr[1] = (uint8)((v >> 8) & 0xff); - ptr[2] = (uint8)((v >> 16) & 0xff); - ptr[3] = (uint8)((v >> 24) & 0xff); - ptr += 4; + ptr[0] = (uint8)(v & 0xff); + ptr[1] = (uint8)((v >> 8) & 0xff); + ptr[2] = (uint8)((v >> 16) & 0xff); + ptr[3] = (uint8)((v >> 24) & 0xff); + ptr += 4; } static inline void Push16(uint16 v, uint8 * &ptr) { - ptr[0] = (uint8)(v & 0xff); - ptr[1] = (uint8)((v >> 8) & 0xff); - ptr += 2; + ptr[0] = (uint8)(v & 0xff); + ptr[1] = (uint8)((v >> 8) & 0xff); + ptr += 2; } static inline void Push8(uint8 v, uint8 * &ptr) { - *ptr++ = v; + *ptr++ = v; } // little-endian integer read/write functions: static inline uint16 Read16(const uint8 *ptr) { - return ptr[0] | (ptr[1] << 8); + return ptr[0] | (ptr[1] << 8); } static inline void Write16(uint16 v, uint8 *ptr) { - ptr[0] = uint8(v & 0xff); - ptr[1] = uint8((v >> 8) & 0xff); + ptr[0] = uint8(v & 0xff); + ptr[1] = uint8((v >> 8) & 0xff); } static long file_length(FILE *fp) { - long cur_pos = ftell(fp); - fseek(fp, 0, SEEK_END); - long length = ftell(fp); - fseek(fp, cur_pos, SEEK_SET); - return length; + long cur_pos = ftell(fp); + fseek(fp, 0, SEEK_END); + long length = ftell(fp); + fseek(fp, cur_pos, SEEK_SET); + return length; } static int bytes_per_frame(SMovie &mov) { - int num_controllers = 0; + int num_controllers = 0; - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) - if (mov.header.controllerFlags & MOVIE_CONTROLLER(i)) - ++num_controllers; + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) + if (mov.header.controllerFlags & MOVIE_CONTROLLER(i)) + ++num_controllers; - return CONTROLLER_DATA_SIZE * num_controllers; + return CONTROLLER_DATA_SIZE * num_controllers; } static void reserve_buffer_space(uint32 space_needed) { - if (space_needed > Movie.inputBufferSize) - { - uint32 ptr_offset = Movie.inputBufferPtr - Movie.inputBuffer; - uint32 alloc_chunks = (space_needed - 1) / BUFFER_GROWTH_SIZE + 1; - uint32 old_size = Movie.inputBufferSize; - Movie.inputBufferSize = BUFFER_GROWTH_SIZE * alloc_chunks; - Movie.inputBuffer = (uint8 *)realloc(Movie.inputBuffer, Movie.inputBufferSize); - // FIXME: this only fixes the random input problem during dma-frame-skip, but not the skip - memset(Movie.inputBuffer + old_size, 0, Movie.inputBufferSize - old_size); - Movie.inputBufferPtr = Movie.inputBuffer + ptr_offset; - } + if (space_needed > Movie.inputBufferSize) + { + uint32 ptr_offset = Movie.inputBufferPtr - Movie.inputBuffer; + uint32 alloc_chunks = (space_needed - 1) / BUFFER_GROWTH_SIZE + 1; + uint32 old_size = Movie.inputBufferSize; + Movie.inputBufferSize = BUFFER_GROWTH_SIZE * alloc_chunks; + Movie.inputBuffer = (uint8 *)realloc(Movie.inputBuffer, Movie.inputBufferSize); + // FIXME: this only fixes the random input problem during dma-frame-skip, but not the skip + memset(Movie.inputBuffer + old_size, 0, Movie.inputBufferSize - old_size); + Movie.inputBufferPtr = Movie.inputBuffer + ptr_offset; + } } static int read_movie_header(FILE *file, SMovie &movie) { - assert(file != NULL); - assert(VBM_HEADER_SIZE == sizeof(SMovieFileHeader)); // sanity check on the header type definition + assert(file != NULL); + assert(VBM_HEADER_SIZE == sizeof(SMovieFileHeader)); // sanity check on the header type definition - uint8 headerData [VBM_HEADER_SIZE]; + uint8 headerData [VBM_HEADER_SIZE]; - if (fread(headerData, 1, VBM_HEADER_SIZE, file) != VBM_HEADER_SIZE) - return MOVIE_WRONG_FORMAT; // if we failed to read in all VBM_HEADER_SIZE bytes of the header + if (fread(headerData, 1, VBM_HEADER_SIZE, file) != VBM_HEADER_SIZE) + return MOVIE_WRONG_FORMAT; // if we failed to read in all VBM_HEADER_SIZE bytes of the header - const uint8 * ptr = headerData; - SMovieFileHeader &header = movie.header; + const uint8 * ptr = headerData; + SMovieFileHeader &header = movie.header; - header.magic = Pop32(ptr); - if (header.magic != VBM_MAGIC) - return MOVIE_WRONG_FORMAT; + header.magic = Pop32(ptr); + if (header.magic != VBM_MAGIC) + return MOVIE_WRONG_FORMAT; - header.version = Pop32(ptr); - if (header.version != VBM_VERSION) - return MOVIE_WRONG_VERSION; + header.version = Pop32(ptr); + if (header.version != VBM_VERSION) + return MOVIE_WRONG_VERSION; - header.uid = Pop32(ptr); - header.length_frames = Pop32(ptr) + 1; // HACK: add 1 to the length for compatibility - header.rerecord_count = Pop32(ptr); + header.uid = Pop32(ptr); + header.length_frames = Pop32(ptr) + 1; // HACK: add 1 to the length for compatibility + header.rerecord_count = Pop32(ptr); - header.startFlags = Pop8(ptr); - header.controllerFlags = Pop8(ptr); - header.typeFlags = Pop8(ptr); - header.optionFlags = Pop8(ptr); + header.startFlags = Pop8(ptr); + header.controllerFlags = Pop8(ptr); + header.typeFlags = Pop8(ptr); + header.optionFlags = Pop8(ptr); - header.saveType = Pop32(ptr); - header.flashSize = Pop32(ptr); - header.gbEmulatorType = Pop32(ptr); + header.saveType = Pop32(ptr); + header.flashSize = Pop32(ptr); + header.gbEmulatorType = Pop32(ptr); - for (int i = 0; i < 12; i++) - header.romTitle[i] = Pop8(ptr); + for (int i = 0; i < 12; i++) + header.romTitle[i] = Pop8(ptr); - header.minorVersion = Pop8(ptr); + header.minorVersion = Pop8(ptr); - header.romCRC = Pop8(ptr); - header.romOrBiosChecksum = Pop16(ptr); - header.romGameCode = Pop32(ptr); + header.romCRC = Pop8(ptr); + header.romOrBiosChecksum = Pop16(ptr); + header.romGameCode = Pop32(ptr); - header.offset_to_savestate = Pop32(ptr); - header.offset_to_controller_data = Pop32(ptr); + header.offset_to_savestate = Pop32(ptr); + header.offset_to_controller_data = Pop32(ptr); - return MOVIE_SUCCESS; + return MOVIE_SUCCESS; } static void write_movie_header(FILE *file, const SMovie &movie) { - assert(ftell(file) == 0); // we assume file points to beginning of movie file + assert(ftell(file) == 0); // we assume file points to beginning of movie file - uint8 headerData [VBM_HEADER_SIZE]; - uint8 *ptr = headerData; - const SMovieFileHeader &header = movie.header; + uint8 headerData [VBM_HEADER_SIZE]; + uint8 *ptr = headerData; + const SMovieFileHeader &header = movie.header; - Push32(header.magic, ptr); - Push32(header.version, ptr); + Push32(header.magic, ptr); + Push32(header.version, ptr); - Push32(header.uid, ptr); - Push32(header.length_frames - 1, ptr); // HACK: reduce the length by 1 for compatibility with certain faulty old tools - // like TME - Push32(header.rerecord_count, ptr); + Push32(header.uid, ptr); + Push32(header.length_frames - 1, ptr); // HACK: reduce the length by 1 for compatibility with certain faulty old tools + // like TME + Push32(header.rerecord_count, ptr); - Push8(header.startFlags, ptr); - Push8(header.controllerFlags, ptr); - Push8(header.typeFlags, ptr); - Push8(header.optionFlags, ptr); + Push8(header.startFlags, ptr); + Push8(header.controllerFlags, ptr); + Push8(header.typeFlags, ptr); + Push8(header.optionFlags, ptr); - Push32(header.saveType, ptr); - Push32(header.flashSize, ptr); - Push32(header.gbEmulatorType, ptr); + Push32(header.saveType, ptr); + Push32(header.flashSize, ptr); + Push32(header.gbEmulatorType, ptr); - for (int i = 0; i < 12; ++i) - Push8(header.romTitle[i], ptr); + for (int i = 0; i < 12; ++i) + Push8(header.romTitle[i], ptr); - Push8(header.minorVersion, ptr); + Push8(header.minorVersion, ptr); - Push8(header.romCRC, ptr); - Push16(header.romOrBiosChecksum, ptr); - Push32(header.romGameCode, ptr); + Push8(header.romCRC, ptr); + Push16(header.romOrBiosChecksum, ptr); + Push32(header.romGameCode, ptr); - Push32(header.offset_to_savestate, ptr); - Push32(header.offset_to_controller_data, ptr); + Push32(header.offset_to_savestate, ptr); + Push32(header.offset_to_controller_data, ptr); - fwrite(headerData, 1, VBM_HEADER_SIZE, file); + fwrite(headerData, 1, VBM_HEADER_SIZE, file); } static void flush_movie_header() { - assert(Movie.file != 0 && "logical error!"); - if (!Movie.file) - return; + assert(Movie.file != 0 && "logical error!"); + if (!Movie.file) + return; - long originalPos = ftell(Movie.file); + long originalPos = ftell(Movie.file); - // (over-)write the header - fseek(Movie.file, 0, SEEK_SET); - write_movie_header(Movie.file, Movie); + // (over-)write the header + fseek(Movie.file, 0, SEEK_SET); + write_movie_header(Movie.file, Movie); - fflush(Movie.file); + fflush(Movie.file); - fseek(Movie.file, originalPos, SEEK_SET); + fseek(Movie.file, originalPos, SEEK_SET); } static void flush_movie_frames() { - assert(Movie.file && "logical error!"); - if (!Movie.file) - return; + assert(Movie.file && "logical error!"); + if (!Movie.file) + return; - long originalPos = ftell(Movie.file); + long originalPos = ftell(Movie.file); - // overwrite the controller data - fseek(Movie.file, Movie.header.offset_to_controller_data, SEEK_SET); - fwrite(Movie.inputBuffer, 1, Movie.bytesPerFrame * Movie.header.length_frames, Movie.file); + // overwrite the controller data + fseek(Movie.file, Movie.header.offset_to_controller_data, SEEK_SET); + fwrite(Movie.inputBuffer, 1, Movie.bytesPerFrame * Movie.header.length_frames, Movie.file); - fflush(Movie.file); + fflush(Movie.file); - fseek(Movie.file, originalPos, SEEK_SET); + fseek(Movie.file, originalPos, SEEK_SET); } static void truncate_movie(long length) { - // truncate movie to length - // NOTE: it's certain that the savestate block is never after the - // controller data block, because the VBM format decrees it. + // truncate movie to length + // NOTE: it's certain that the savestate block is never after the + // controller data block, because the VBM format decrees it. - assert(Movie.file && length >= 0); - if (!Movie.file || length < 0) - return; + assert(Movie.file && length >= 0); + if (!Movie.file || length < 0) + return; - assert(Movie.header.offset_to_savestate <= Movie.header.offset_to_controller_data); - if (Movie.header.offset_to_savestate > Movie.header.offset_to_controller_data) - return; + assert(Movie.header.offset_to_savestate <= Movie.header.offset_to_controller_data); + if (Movie.header.offset_to_savestate > Movie.header.offset_to_controller_data) + return; - Movie.header.length_frames = length; - flush_movie_header(); - const long truncLen = long(Movie.header.offset_to_controller_data + Movie.bytesPerFrame * length); - if (file_length(Movie.file) != truncLen) - { - ftruncate(fileno(Movie.file), truncLen); - } + Movie.header.length_frames = length; + flush_movie_header(); + const long truncLen = long(Movie.header.offset_to_controller_data + Movie.bytesPerFrame * length); + if (file_length(Movie.file) != truncLen) + { + ftruncate(fileno(Movie.file), truncLen); + } } static void remember_input_state() { - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) + { + if (systemCartridgeType == 0) { - if (systemCartridgeType == 0) - { - initialInputs[i] = u16(~P1 & 0x03FF); - } - else - { - extern int32 gbJoymask[4]; - for (int i = 0; i < 4; ++i) - initialInputs[i] = u16(gbJoymask[i] & 0xFFFF); - } + initialInputs[i] = u16(~P1 & 0x03FF); } + else + { + extern int32 gbJoymask[4]; + for (int i = 0; i < 4; ++i) + initialInputs[i] = u16(gbJoymask[i] & 0xFFFF); + } + } } static void change_state(MovieState new_state) { #if (defined(WIN32) && !defined(SDL)) - theApp.frameSearching = false; - theApp.frameSearchSkipping = false; + theApp.frameSearching = false; + theApp.frameSearchSkipping = false; #endif - if (new_state == MOVIE_STATE_NONE) + if (new_state == MOVIE_STATE_NONE) + { + Movie.pauseFrame = -1; + + if (Movie.state == MOVIE_STATE_NONE) + return; + + truncate_movie(Movie.header.length_frames); + + fclose(Movie.file); + Movie.file = NULL; + Movie.currentFrame = 0; +#if (defined(WIN32) && !defined(SDL)) + // undo changes to border settings + { + gbBorderOn = prevBorder; + theApp.winGbBorderOn = prevWinBorder; + gbBorderAutomatic = prevBorderAuto; + systemGbBorderOn(); + } +#endif + gbEmulatorType = prevEmulatorType; + + extern int32 gbDMASpeedVersion; + gbDMASpeedVersion = 1; + + extern int32 gbEchoRAMFixOn; + gbEchoRAMFixOn = 1; + + gbNullInputHackTempEnabled = gbNullInputHackEnabled; + + if (Movie.inputBuffer) { - Movie.pauseFrame = -1; + free(Movie.inputBuffer); + Movie.inputBuffer = NULL; + } + } + else if (new_state == MOVIE_STATE_PLAY) + { + assert(Movie.file); - if (Movie.state == MOVIE_STATE_NONE) - return; + // this would cause problems if not dealt with + if (Movie.currentFrame >= Movie.header.length_frames) + { + new_state = MOVIE_STATE_END; + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; + } + } + else if (new_state == MOVIE_STATE_RECORD) + { + assert(Movie.file); - truncate_movie(Movie.header.length_frames); - - fclose(Movie.file); - Movie.file = NULL; - Movie.currentFrame = 0; -#if (defined(WIN32) && !defined(SDL)) - // undo changes to border settings - { - gbBorderOn = prevBorder; - theApp.winGbBorderOn = prevWinBorder; - gbBorderAutomatic = prevBorderAuto; - systemGbBorderOn(); - } -#endif - gbEmulatorType = prevEmulatorType; - - extern int32 gbDMASpeedVersion; - gbDMASpeedVersion = 1; - - extern int32 gbEchoRAMFixOn; - gbEchoRAMFixOn = 1; - - gbNullInputHackTempEnabled = gbNullInputHackEnabled; - - if (Movie.inputBuffer) - { - free(Movie.inputBuffer); - Movie.inputBuffer = NULL; - } - } - else if (new_state == MOVIE_STATE_PLAY) + // this would cause problems if not dealt with + if (Movie.currentFrame > Movie.header.length_frames) { - assert(Movie.file); - - // this would cause problems if not dealt with - if (Movie.currentFrame >= Movie.header.length_frames) - { - new_state = MOVIE_STATE_END; - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; - } - } - else if (new_state == MOVIE_STATE_RECORD) - { - assert(Movie.file); - - // this would cause problems if not dealt with - if (Movie.currentFrame > Movie.header.length_frames) - { - new_state = MOVIE_STATE_END; - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; - } - - fseek(Movie.file, Movie.header.offset_to_controller_data + Movie.bytesPerFrame * Movie.currentFrame, SEEK_SET); + new_state = MOVIE_STATE_END; + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; } - if (new_state == MOVIE_STATE_END && Movie.state != MOVIE_STATE_END) + fseek(Movie.file, Movie.header.offset_to_controller_data + Movie.bytesPerFrame * Movie.currentFrame, SEEK_SET); + } + + if (new_state == MOVIE_STATE_END && Movie.state != MOVIE_STATE_END) + { +#if defined(SDL) + systemClearJoypads(); +#endif + systemScreenMessage("Movie end"); + } + + Movie.state = new_state; + + // checking for movie end + bool willPause = false; + + // if the movie's been set to pause at a certain frame + if (Movie.state != MOVIE_STATE_NONE && Movie.pauseFrame >= 0 && Movie.currentFrame == (uint32)Movie.pauseFrame) + { + Movie.pauseFrame = -1; + willPause = true; + } + + if (Movie.state == MOVIE_STATE_END) + { + if (Movie.currentFrame == Movie.header.length_frames) { -#if defined(SDL) - systemClearJoypads(); -#endif - systemScreenMessage("Movie end"); - } - - Movie.state = new_state; - - // checking for movie end - bool willPause = false; - - // if the movie's been set to pause at a certain frame - if (Movie.state != MOVIE_STATE_NONE && Movie.pauseFrame >= 0 && Movie.currentFrame == (uint32)Movie.pauseFrame) - { - Movie.pauseFrame = -1; - willPause = true; - } - - if (Movie.state == MOVIE_STATE_END) - { - if (Movie.currentFrame == Movie.header.length_frames) - { #if (defined(WIN32) && !defined(SDL)) - if (theApp.movieOnEndPause) - { - willPause = true; - } + if (theApp.movieOnEndPause) + { + willPause = true; + } #else - // SDL FIXME + // SDL FIXME #endif #if (defined(WIN32) && !defined(SDL)) - switch (theApp.movieOnEndBehavior) - { - case 1: - // the old behavior - //VBAMovieRestart(); - break; - case 2: + switch (theApp.movieOnEndBehavior) + { + case 1: + // the old behavior + //VBAMovieRestart(); + break; + case 2: #else - // SDL FIXME + // SDL FIXME #endif - if (Movie.RecordedThisSession) - { - // if user has been recording this movie since the last time it started playing, - // they probably don't want the movie to end now during playback, - // so switch back to recording when it reaches the end - VBAMovieSwitchToRecording(); - systemScreenMessage("Recording resumed"); - willPause = true; - } + if (Movie.RecordedThisSession) + { + // if user has been recording this movie since the last time it started playing, + // they probably don't want the movie to end now during playback, + // so switch back to recording when it reaches the end + VBAMovieSwitchToRecording(); + systemScreenMessage("Recording resumed"); + willPause = true; + } #if (defined(WIN32) && !defined(SDL)) - break; - case 3: - // keep open - break; - case 0: - // fall through - default: - // close movie - //VBAMovieStop(false); - break; - } + break; + case 3: + // keep open + break; + case 0: + // fall through + default: + // close movie + //VBAMovieStop(false); + break; + } #else - // SDL FIXME + // SDL FIXME #endif - } + } #if 1 - else if (Movie.currentFrame > Movie.header.length_frames) - { + else if (Movie.currentFrame > Movie.header.length_frames) + { #if (defined(WIN32) && !defined(SDL)) - switch (theApp.movieOnEndBehavior) - { - case 1: - // FIXME: this should be delayed till the current frame ends - VBAMovieRestart(); - break; - case 2: - // nothing - break; - case 3: - // keep open - break; - case 0: - // fall through - default: - // close movie - VBAMovieStop(false); - break; - } + switch (theApp.movieOnEndBehavior) + { + case 1: + // FIXME: this should be delayed till the current frame ends + VBAMovieRestart(); + break; + case 2: + // nothing + break; + case 3: + // keep open + break; + case 0: + // fall through + default: + // close movie + VBAMovieStop(false); + break; + } #else - // SDLFIXME + // SDLFIXME #endif - } + } #endif - } // end if (Movie.state == MOVIE_STATE_END) + } // end if (Movie.state == MOVIE_STATE_END) - if (willPause) - { - systemSetPause(true); - } + if (willPause) + { + systemSetPause(true); + } } void VBAMovieInit() { - memset(&Movie, 0, sizeof(Movie)); - Movie.state = MOVIE_STATE_NONE; - Movie.pauseFrame = -1; + memset(&Movie, 0, sizeof(Movie)); + Movie.state = MOVIE_STATE_NONE; + Movie.pauseFrame = -1; - resetSignaled = false; - resetSignaledLast = false; + resetSignaled = false; + resetSignaledLast = false; } void VBAMovieGetRomInfo(const SMovie &movieInfo, char romTitle [12], uint32 &romGameCode, uint16 &checksum, uint8 &crc) { - if (systemCartridgeType == 0) // GBA - { - extern u8 *bios, *rom; - memcpy(romTitle, &rom[0xa0], 12); // GBA TITLE - memcpy(&romGameCode, &rom[0xac], 4); // GBA ROM GAME CODE - if ((movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0) - checksum = utilCalcBIOSChecksum(bios, 4); // GBA BIOS CHECKSUM - else - checksum = 0; - crc = rom[0xbd]; // GBA ROM CRC - } - else // non-GBA - { - extern u8 *gbRom; - memcpy(romTitle, &gbRom[0x134], 12); // GB TITLE (note this can be 15 but is truncated to 12) - romGameCode = (uint32)gbRom[0x146]; // GB ROM UNIT CODE + if (systemCartridgeType == 0) // GBA + { + extern u8 *bios, *rom; + memcpy(romTitle, &rom[0xa0], 12); // GBA TITLE + memcpy(&romGameCode, &rom[0xac], 4); // GBA ROM GAME CODE + if ((movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0) + checksum = utilCalcBIOSChecksum(bios, 4); // GBA BIOS CHECKSUM + else + checksum = 0; + crc = rom[0xbd]; // GBA ROM CRC + } + else // non-GBA + { + extern u8 *gbRom; + memcpy(romTitle, &gbRom[0x134], 12); // GB TITLE (note this can be 15 but is truncated to 12) + romGameCode = (uint32)gbRom[0x146]; // GB ROM UNIT CODE - checksum = (gbRom[0x14e] << 8) | gbRom[0x14f]; // GB ROM CHECKSUM, read from big-endian - crc = gbRom[0x14d]; // GB ROM CRC - } + checksum = (gbRom[0x14e] << 8) | gbRom[0x14f]; // GB ROM CHECKSUM, read from big-endian + crc = gbRom[0x14d]; // GB ROM CRC + } } #ifdef SDL static void GetBatterySaveName(char *buffer) { - extern char batteryDir[2048], filename[2048]; // from SDL.cpp - extern char *sdlGetFilename(char *name); // from SDL.cpp - if (batteryDir[0]) - sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename)); - else - sprintf(buffer, "%s.sav", filename); + extern char batteryDir[2048], filename[2048]; // from SDL.cpp + extern char *sdlGetFilename(char *name); // from SDL.cpp + if (batteryDir[0]) + sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename)); + else + sprintf(buffer, "%s.sav", filename); } #endif static void SetPlayEmuSettings() { - prevEmulatorType = gbEmulatorType; - gbEmulatorType = Movie.header.gbEmulatorType; + prevEmulatorType = gbEmulatorType; + gbEmulatorType = Movie.header.gbEmulatorType; #if (defined(WIN32) && !defined(SDL)) -// theApp.removeIntros = false; - theApp.skipBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; - theApp.useBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; + // theApp.removeIntros = false; + theApp.skipBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; + theApp.useBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; #else - extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp - extern bool8 useBios, skipBios, removeIntros; // from SDL.cpp - useBios = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; - skipBios = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; - removeIntros = false /*(Movie.header.optionFlags & MOVIE_SETTING_REMOVEINTROS) != 0*/; + extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp + extern bool8 useBios, skipBios, removeIntros; // from SDL.cpp + useBios = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; + skipBios = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; + removeIntros = false /*(Movie.header.optionFlags & MOVIE_SETTING_REMOVEINTROS) != 0*/; #endif - extern void SetPrefetchHack(bool); - if (systemCartridgeType == 0) // lag disablement applies only to GBA - SetPrefetchHack((Movie.header.optionFlags & MOVIE_SETTING_LAGHACK) != 0); + extern void SetPrefetchHack(bool); + if (systemCartridgeType == 0) // lag disablement applies only to GBA + SetPrefetchHack((Movie.header.optionFlags & MOVIE_SETTING_LAGHACK) != 0); - gbNullInputHackTempEnabled = ((Movie.header.optionFlags & MOVIE_SETTING_GBINPUTHACK) != 0); + gbNullInputHackTempEnabled = ((Movie.header.optionFlags & MOVIE_SETTING_GBINPUTHACK) != 0); - // some GB/GBC games depend on the sound rate, so just use the highest one - systemSoundSetQuality(1); - useOldFrameTiming = false; + // some GB/GBC games depend on the sound rate, so just use the highest one + systemSoundSetQuality(1); + useOldFrameTiming = false; - extern int32 gbDMASpeedVersion; - if ((Movie.header.optionFlags & MOVIE_SETTING_GBCFF55FIX) != 0) - gbDMASpeedVersion = 1; - else - gbDMASpeedVersion = 0; // old CGB HDMA5 timing was used + extern int32 gbDMASpeedVersion; + if ((Movie.header.optionFlags & MOVIE_SETTING_GBCFF55FIX) != 0) + gbDMASpeedVersion = 1; + else + gbDMASpeedVersion = 0; // old CGB HDMA5 timing was used - extern int32 gbEchoRAMFixOn; - if ((Movie.header.optionFlags & MOVIE_SETTING_GBECHORAMFIX) != 0) - gbEchoRAMFixOn = 1; - else - gbEchoRAMFixOn = 0; + extern int32 gbEchoRAMFixOn; + if ((Movie.header.optionFlags & MOVIE_SETTING_GBECHORAMFIX) != 0) + gbEchoRAMFixOn = 1; + else + gbEchoRAMFixOn = 0; #if (defined(WIN32) && !defined(SDL)) - rtcEnable((Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0); - theApp.winSaveType = Movie.header.saveType; - theApp.winFlashSize = Movie.header.flashSize; + rtcEnable((Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0); + theApp.winSaveType = Movie.header.saveType; + theApp.winFlashSize = Movie.header.flashSize; - prevBorder = gbBorderOn; - prevWinBorder = theApp.winGbBorderOn; - prevBorderAuto = gbBorderAutomatic; - if ((gbEmulatorType == 2 || gbEmulatorType == 5) - && !theApp.hideMovieBorder) // games played in SGB mode can have a border + prevBorder = gbBorderOn; + prevWinBorder = theApp.winGbBorderOn; + prevBorderAuto = gbBorderAutomatic; + if ((gbEmulatorType == 2 || gbEmulatorType == 5) + && !theApp.hideMovieBorder) // games played in SGB mode can have a border + { + gbBorderOn = true; + theApp.winGbBorderOn = true; + gbBorderAutomatic = false; + } + else + { + gbBorderOn = false; + theApp.winGbBorderOn = false; + gbBorderAutomatic = false; + if (theApp.hideMovieBorder) { - gbBorderOn = true; - theApp.winGbBorderOn = true; - gbBorderAutomatic = false; + theApp.hideMovieBorder = false; + prevBorder = false; // it might be expected behaviour that it stays hidden after the movie } - else - { - gbBorderOn = false; - theApp.winGbBorderOn = false; - gbBorderAutomatic = false; - if (theApp.hideMovieBorder) - { - theApp.hideMovieBorder = false; - prevBorder = false; // it might be expected behaviour that it stays hidden after the movie - } - } - systemGbBorderOn(); + } + systemGbBorderOn(); #else - sdlRtcEnable = (Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0; - saveType = Movie.header.saveType; - sdlFlashSize = Movie.header.flashSize; + sdlRtcEnable = (Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0; + saveType = Movie.header.saveType; + sdlFlashSize = Movie.header.flashSize; #endif } static void HardResetAndSRAMClear() { #if (defined(WIN32) && !defined(SDL)) - winEraseBatteryFile(); // delete the damn SRAM file and keep it from being resurrected from RAM - MainWnd *temp = ((MainWnd *)theApp.m_pMainWnd); - if (!temp->winFileRun(true)) // restart running the game - { - temp->winFileClose(); - } + winEraseBatteryFile(); // delete the damn SRAM file and keep it from being resurrected from RAM + MainWnd *temp = ((MainWnd *)theApp.m_pMainWnd); + if (!temp->winFileRun(true)) // restart running the game + { + temp->winFileClose(); + } #else - char fname [1024]; - GetBatterySaveName(fname); - remove(fname); // delete the damn SRAM file + char fname [1024]; + GetBatterySaveName(fname); + remove(fname); // delete the damn SRAM file - // Henceforth, emuCleanUp means "clear out SRAM" - //theEmulator.emuCleanUp(); // keep it from being resurrected from RAM <--This is wrong, it'll deallocate all variables --Felipe + // Henceforth, emuCleanUp means "clear out SRAM" + //theEmulator.emuCleanUp(); // keep it from being resurrected from RAM <--This is wrong, it'll deallocate all variables --Felipe - /// FIXME the correct SDL code to call for a full restart isn't in a function yet - theEmulator.emuReset(false); + /// FIXME the correct SDL code to call for a full restart isn't in a function yet + theEmulator.emuReset(false); #endif } int VBAMovieOpen(const char *filename, bool8 read_only) { - loadingMovie = true; - uint8 movieReadOnly = read_only ? 1 : 0; + loadingMovie = true; + uint8 movieReadOnly = read_only ? 1 : 0; - FILE * file; - STREAM stream; - int result; - int fn; + FILE * file; + STREAM stream; + int result; + int fn; - char movie_filename[_MAX_PATH]; + char movie_filename[_MAX_PATH]; #ifdef WIN32 - _fullpath(movie_filename, filename, _MAX_PATH); + _fullpath(movie_filename, filename, _MAX_PATH); #else - // SDL FIXME: convert to fullpath - strncpy(movie_filename, filename, _MAX_PATH); - movie_filename[_MAX_PATH - 1] = '\0'; + // SDL FIXME: convert to fullpath + strncpy(movie_filename, filename, _MAX_PATH); + movie_filename[_MAX_PATH - 1] = '\0'; #endif - if (movie_filename[0] == '\0') - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } + if (movie_filename[0] == '\0') + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - if (!emulating) - { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } + if (!emulating) + { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } -// bool alreadyOpen = (Movie.file != NULL && _stricmp(movie_filename, Movie.filename) == 0); + // bool alreadyOpen = (Movie.file != NULL && _stricmp(movie_filename, Movie.filename) == 0); -// if (alreadyOpen) - change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it + // if (alreadyOpen) + change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it - if (!(file = fopen(movie_filename, "rb+"))) - if (!(file = fopen(movie_filename, "rb"))) - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - //else - // movieReadOnly = 2; // we have to open the movie twice, no need to do this both times + if (!(file = fopen(movie_filename, "rb+"))) + if (!(file = fopen(movie_filename, "rb"))) + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } + //else + // movieReadOnly = 2; // we have to open the movie twice, no need to do this both times -// if (!alreadyOpen) -// change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one -// -// if (!(file = fopen(movie_filename, "rb+"))) -// if(!(file = fopen(movie_filename, "rb"))) -// {loadingMovie = false; return MOVIE_FILE_NOT_FOUND;} -// else -// movieReadOnly = 2; + // if (!alreadyOpen) + // change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one + // + // if (!(file = fopen(movie_filename, "rb+"))) + // if(!(file = fopen(movie_filename, "rb"))) + // {loadingMovie = false; return MOVIE_FILE_NOT_FOUND;} + // else + // movieReadOnly = 2; - // clear out the current movie - VBAMovieInit(); + // clear out the current movie + VBAMovieInit(); - // read header - if ((result = read_movie_header(file, Movie)) != MOVIE_SUCCESS) - { - fclose(file); - { loadingMovie = false; return result; } - } + // read header + if ((result = read_movie_header(file, Movie)) != MOVIE_SUCCESS) + { + fclose(file); + { loadingMovie = false; return result; } + } - // set emulator settings that make the movie more likely to stay synchronized - SetPlayEmuSettings(); + // set emulator settings that make the movie more likely to stay synchronized + SetPlayEmuSettings(); -// extern bool systemLoadBIOS(); -// if (!systemLoadBIOS()) -// { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } + // extern bool systemLoadBIOS(); + // if (!systemLoadBIOS()) + // { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } - // read the metadata / author info from file - fread(Movie.authorInfo, 1, MOVIE_METADATA_SIZE, file); - fn = dup(fileno(file)); // XXX: why does this fail?? it returns -1 but errno == 0 - fclose(file); + // read the metadata / author info from file + fread(Movie.authorInfo, 1, MOVIE_METADATA_SIZE, file); + fn = dup(fileno(file)); // XXX: why does this fail?? it returns -1 but errno == 0 + fclose(file); - // apparently this lseek is necessary - lseek(fn, Movie.header.offset_to_savestate, SEEK_SET); - if (!(stream = utilGzReopen(fn, "rb"))) - if (!(stream = utilGzOpen(movie_filename, "rb"))) - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - else - fn = dup(fileno(file)); - // in case the above dup failed but opening the file normally doesn't fail + // apparently this lseek is necessary + lseek(fn, Movie.header.offset_to_savestate, SEEK_SET); + if (!(stream = utilGzReopen(fn, "rb"))) + if (!(stream = utilGzOpen(movie_filename, "rb"))) + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } + else + fn = dup(fileno(file)); + // in case the above dup failed but opening the file normally doesn't fail - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) - { - // load the snapshot - result = theEmulator.emuReadStateFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) + { + // load the snapshot + result = theEmulator.emuReadStateFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; - // FIXME: Kludge for conversion - remember_input_state(); - } - else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) - { - // 'soft' reset: - theEmulator.emuReset(false); + // FIXME: Kludge for conversion + remember_input_state(); + } + else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) + { + // 'soft' reset: + theEmulator.emuReset(false); - // load the SRAM - result = theEmulator.emuReadBatteryFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; - } - else - { - HardResetAndSRAMClear(); - } + // load the SRAM + result = theEmulator.emuReadBatteryFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; + } + else + { + HardResetAndSRAMClear(); + } - utilGzClose(stream); + utilGzClose(stream); - if (result != MOVIE_SUCCESS) - { loadingMovie = false; return result; } + if (result != MOVIE_SUCCESS) + { loadingMovie = false; return result; } -// if (!(file = fopen(movie_filename, /*read_only ? "rb" :*/ "rb+"))) // want to be able to switch out of read-only later -// { -// if(!Movie.readOnly || !(file = fopen(movie_filename, "rb"))) // try read-only if failed -// return MOVIE_FILE_NOT_FOUND; -// } - if (!(file = fopen(movie_filename, "rb+"))) - if (!(file = fopen(movie_filename, "rb"))) - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - else - movieReadOnly = 2; + // if (!(file = fopen(movie_filename, /*read_only ? "rb" :*/ "rb+"))) // want to be able to switch out of read-only later + // { + // if(!Movie.readOnly || !(file = fopen(movie_filename, "rb"))) // try read-only if failed + // return MOVIE_FILE_NOT_FOUND; + // } + if (!(file = fopen(movie_filename, "rb+"))) + if (!(file = fopen(movie_filename, "rb"))) + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } + else + movieReadOnly = 2; - // recalculate length of movie from the file size - Movie.bytesPerFrame = bytes_per_frame(Movie); - fseek(file, 0, SEEK_END); - long fileSize = ftell(file); - Movie.header.length_frames = (fileSize - Movie.header.offset_to_controller_data) / Movie.bytesPerFrame; + // recalculate length of movie from the file size + Movie.bytesPerFrame = bytes_per_frame(Movie); + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + Movie.header.length_frames = (fileSize - Movie.header.offset_to_controller_data) / Movie.bytesPerFrame; - if (fseek(file, Movie.header.offset_to_controller_data, SEEK_SET)) - { fclose(file); loadingMovie = false; return MOVIE_WRONG_FORMAT; } + if (fseek(file, Movie.header.offset_to_controller_data, SEEK_SET)) + { fclose(file); loadingMovie = false; return MOVIE_WRONG_FORMAT; } - strcpy(Movie.filename, movie_filename); - Movie.file = file; - Movie.inputBufferPtr = Movie.inputBuffer; - Movie.currentFrame = 0; - Movie.readOnly = movieReadOnly; - Movie.RecordedThisSession = false; + strcpy(Movie.filename, movie_filename); + Movie.file = file; + Movie.inputBufferPtr = Movie.inputBuffer; + Movie.currentFrame = 0; + Movie.readOnly = movieReadOnly; + Movie.RecordedThisSession = false; - // read controller data - uint32 to_read = Movie.bytesPerFrame * Movie.header.length_frames; - reserve_buffer_space(to_read); - fread(Movie.inputBuffer, 1, to_read, file); + // read controller data + uint32 to_read = Movie.bytesPerFrame * Movie.header.length_frames; + reserve_buffer_space(to_read); + fread(Movie.inputBuffer, 1, to_read, file); - change_state(MOVIE_STATE_PLAY); + change_state(MOVIE_STATE_PLAY); - char messageString[64] = "Movie "; - bool converted = false; - if (autoConvertMovieWhenPlaying) - { - int result = VBAMovieConvertCurrent(); - if (result == MOVIE_SUCCESS) - strcat(messageString, "converted and "); - else if (result == MOVIE_WRONG_VERSION) - strcat(messageString, "higher revision "); - } + char messageString[64] = "Movie "; + bool converted = false; + if (autoConvertMovieWhenPlaying) + { + int result = VBAMovieConvertCurrent(); + if (result == MOVIE_SUCCESS) + strcat(messageString, "converted and "); + else if (result == MOVIE_WRONG_VERSION) + strcat(messageString, "higher revision "); + } - if (Movie.state == MOVIE_STATE_PLAY) - strcat(messageString, "replaying "); - else - strcat(messageString, "finished "); - if (Movie.readOnly) - strcat(messageString, "(read)"); - else - strcat(messageString, "(edit)"); - systemScreenMessage(messageString); + if (Movie.state == MOVIE_STATE_PLAY) + strcat(messageString, "replaying "); + else + strcat(messageString, "finished "); + if (Movie.readOnly) + strcat(messageString, "(read)"); + else + strcat(messageString, "(edit)"); + systemScreenMessage(messageString); - VBAUpdateButtonPressDisplay(); - VBAUpdateFrameCountDisplay(); - systemRefreshScreen(); + VBAUpdateButtonPressDisplay(); + VBAUpdateFrameCountDisplay(); + systemRefreshScreen(); - { loadingMovie = false; return MOVIE_SUCCESS; } + { loadingMovie = false; return MOVIE_SUCCESS; } } static void SetRecordEmuSettings() { - Movie.header.optionFlags = 0; + Movie.header.optionFlags = 0; #if (defined(WIN32) && !defined(SDL)) - if (theApp.useBiosFile) - Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; - if (theApp.skipBiosFile) - Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; - if (rtcIsEnabled()) - Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; - Movie.header.saveType = theApp.winSaveType; - Movie.header.flashSize = theApp.winFlashSize; + if (theApp.useBiosFile) + Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; + if (theApp.skipBiosFile) + Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; + if (rtcIsEnabled()) + Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; + Movie.header.saveType = theApp.winSaveType; + Movie.header.flashSize = theApp.winFlashSize; #else - extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp - extern bool8 useBios, skipBios; // from SDL.cpp - if (useBios) - Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; - if (skipBios) - Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; - if (sdlRtcEnable) - Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; - Movie.header.saveType = saveType; - Movie.header.flashSize = sdlFlashSize; + extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp + extern bool8 useBios, skipBios; // from SDL.cpp + if (useBios) + Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; + if (skipBios) + Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; + if (sdlRtcEnable) + Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; + Movie.header.saveType = saveType; + Movie.header.flashSize = sdlFlashSize; #endif - prevEmulatorType = Movie.header.gbEmulatorType = gbEmulatorType; + prevEmulatorType = Movie.header.gbEmulatorType = gbEmulatorType; - if (!memLagTempEnabled) - Movie.header.optionFlags |= MOVIE_SETTING_LAGHACK; + if (!memLagTempEnabled) + Movie.header.optionFlags |= MOVIE_SETTING_LAGHACK; - if (gbNullInputHackTempEnabled) - Movie.header.optionFlags |= MOVIE_SETTING_GBINPUTHACK; + if (gbNullInputHackTempEnabled) + Movie.header.optionFlags |= MOVIE_SETTING_GBINPUTHACK; - Movie.header.optionFlags |= MOVIE_SETTING_GBCFF55FIX; - extern int32 gbDMASpeedVersion; - gbDMASpeedVersion = 1; + Movie.header.optionFlags |= MOVIE_SETTING_GBCFF55FIX; + extern int32 gbDMASpeedVersion; + gbDMASpeedVersion = 1; - Movie.header.optionFlags |= MOVIE_SETTING_GBECHORAMFIX; - extern int32 gbEchoRAMFixOn; - gbEchoRAMFixOn = 1; + Movie.header.optionFlags |= MOVIE_SETTING_GBECHORAMFIX; + extern int32 gbEchoRAMFixOn; + gbEchoRAMFixOn = 1; - // some GB/GBC games depend on the sound rate, so just use the highest one - systemSoundSetQuality(1); + // some GB/GBC games depend on the sound rate, so just use the highest one + systemSoundSetQuality(1); - useOldFrameTiming = false; + useOldFrameTiming = false; #if (defined(WIN32) && !defined(SDL)) -// theApp.removeIntros = false; + // theApp.removeIntros = false; - prevBorder = gbBorderOn; - prevWinBorder = theApp.winGbBorderOn; - prevBorderAuto = gbBorderAutomatic; - if (gbEmulatorType == 2 || gbEmulatorType == 5) // only games played in SGB mode will have a border - { - gbBorderOn = true; - theApp.winGbBorderOn = true; - gbBorderAutomatic = false; - } - else - { - gbBorderOn = false; - theApp.winGbBorderOn = false; - gbBorderAutomatic = false; - } - systemGbBorderOn(); + prevBorder = gbBorderOn; + prevWinBorder = theApp.winGbBorderOn; + prevBorderAuto = gbBorderAutomatic; + if (gbEmulatorType == 2 || gbEmulatorType == 5) // only games played in SGB mode will have a border + { + gbBorderOn = true; + theApp.winGbBorderOn = true; + gbBorderAutomatic = false; + } + else + { + gbBorderOn = false; + theApp.winGbBorderOn = false; + gbBorderAutomatic = false; + } + systemGbBorderOn(); #else - /// SDLFIXME + /// SDLFIXME #endif } uint16 VBAMovieGetCurrentInputOf(int controllerNum, bool normalOnly) { - if (controllerNum < 0 || controllerNum >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) - return 0; + if (controllerNum < 0 || controllerNum >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) + return 0; - return normalOnly ? (currentButtons[controllerNum] & BUTTON_REGULAR_MASK) : currentButtons[controllerNum]; + return normalOnly ? (currentButtons[controllerNum] & BUTTON_REGULAR_MASK) : currentButtons[controllerNum]; } int VBAMovieCreate(const char *filename, const char *authorInfo, uint8 startFlags, uint8 controllerFlags, uint8 typeFlags) { - // make sure at least one controller is enabled - if ((controllerFlags & MOVIE_CONTROLLERS_ANY_MASK) == 0) - return MOVIE_WRONG_FORMAT; + // make sure at least one controller is enabled + if ((controllerFlags & MOVIE_CONTROLLERS_ANY_MASK) == 0) + return MOVIE_WRONG_FORMAT; - if (!emulating) - return MOVIE_UNKNOWN_ERROR; + if (!emulating) + return MOVIE_UNKNOWN_ERROR; - loadingMovie = true; + loadingMovie = true; - FILE * file; - STREAM stream; - int fn; + FILE * file; + STREAM stream; + int fn; - char movie_filename [_MAX_PATH]; + char movie_filename [_MAX_PATH]; #ifdef WIN32 - _fullpath(movie_filename, filename, _MAX_PATH); + _fullpath(movie_filename, filename, _MAX_PATH); #else - // FIXME: convert to fullpath - strncpy(movie_filename, filename, _MAX_PATH); - movie_filename[_MAX_PATH - 1] = '\0'; + // FIXME: convert to fullpath + strncpy(movie_filename, filename, _MAX_PATH); + movie_filename[_MAX_PATH - 1] = '\0'; #endif - bool alreadyOpen = (Movie.file != NULL && stricmp(movie_filename, Movie.filename) == 0); + bool alreadyOpen = (Movie.file != NULL && stricmp(movie_filename, Movie.filename) == 0); - if (alreadyOpen) - change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it + if (alreadyOpen) + change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it - if (movie_filename[0] == '\0') + if (movie_filename[0] == '\0') + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } + + if (!(file = fopen(movie_filename, "wb"))) + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } + + if (!alreadyOpen) + change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one + + // clear out the current movie + printf("RLM: movie init\n"); + + VBAMovieInit(); + + // fill in the movie's header + Movie.header.uid = (uint32)time(NULL); + Movie.header.magic = VBM_MAGIC; + Movie.header.version = VBM_VERSION; + Movie.header.rerecord_count = 0; + Movie.header.length_frames = 0; + Movie.header.startFlags = startFlags; + Movie.header.controllerFlags = controllerFlags; + Movie.header.typeFlags = typeFlags; + Movie.header.minorVersion = VBM_REVISION; + + // set emulator settings that make the movie more likely to stay synchronized when it's later played back + SetRecordEmuSettings(); + + // set ROM and BIOS checksums and stuff + VBAMovieGetRomInfo(Movie, Movie.header.romTitle, Movie.header.romGameCode, Movie.header.romOrBiosChecksum, Movie.header.romCRC); + + printf("RLM: Writing movie header\n"); + // write the header to file + write_movie_header(file, Movie); + + printf("RLM: setting metadata\n"); + + // copy over the metadata / author info + VBAMovieSetMetadata("________________Robert McIntyre______________________________________________________________________________________________________________________________________________________________________________________________________________________"); + + printf("RLM: writing metadata\n"); + + // write the metadata / author info to file + + + fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); + + // write snapshot or SRAM if applicable + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT + || Movie.header.startFlags & MOVIE_START_FROM_SRAM) + { + Movie.header.offset_to_savestate = (uint32)ftell(file); + + // close the file and reopen it as a stream: + + fn = dup(fileno(file)); + fclose(file); + + if (!(stream = utilGzReopen(fn, "ab"))) // append mode to start at end, no seek necessary { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - if (!(file = fopen(movie_filename, "wb"))) + // write the save data: + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) + { + // save snapshot + if (!theEmulator.emuWriteStateToStream(stream)) + { + utilGzClose(stream); + { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } + } + } + else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) + { + // save SRAM + if (!theEmulator.emuWriteBatteryToStream(stream)) + { + utilGzClose(stream); + { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } + } + + // 'soft' reset: + theEmulator.emuReset(false); + } + + utilGzClose(stream); + + // reopen the file and seek back to the end + + if (!(file = fopen(movie_filename, "rb+"))) { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - if (!alreadyOpen) - change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one + fseek(file, 0, SEEK_END); + } + else // no snapshot or SRAM + { + HardResetAndSRAMClear(); + } - // clear out the current movie - VBAMovieInit(); + Movie.header.offset_to_controller_data = (uint32)ftell(file); - // fill in the movie's header - Movie.header.uid = (uint32)time(NULL); - Movie.header.magic = VBM_MAGIC; - Movie.header.version = VBM_VERSION; - Movie.header.rerecord_count = 0; - Movie.header.length_frames = 0; - Movie.header.startFlags = startFlags; - Movie.header.controllerFlags = controllerFlags; - Movie.header.typeFlags = typeFlags; - Movie.header.minorVersion = VBM_REVISION; + strcpy(Movie.filename, movie_filename); + Movie.file = file; + Movie.bytesPerFrame = bytes_per_frame(Movie); + Movie.inputBufferPtr = Movie.inputBuffer; + Movie.currentFrame = 0; + Movie.readOnly = false; + Movie.RecordedThisSession = true; - // set emulator settings that make the movie more likely to stay synchronized when it's later played back - SetRecordEmuSettings(); + change_state(MOVIE_STATE_RECORD); - // set ROM and BIOS checksums and stuff - VBAMovieGetRomInfo(Movie, Movie.header.romTitle, Movie.header.romGameCode, Movie.header.romOrBiosChecksum, Movie.header.romCRC); - - // write the header to file - write_movie_header(file, Movie); - - // copy over the metadata / author info - VBAMovieSetMetadata(authorInfo); - - // write the metadata / author info to file - fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); - - // write snapshot or SRAM if applicable - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT - || Movie.header.startFlags & MOVIE_START_FROM_SRAM) - { - Movie.header.offset_to_savestate = (uint32)ftell(file); - - // close the file and reopen it as a stream: - - fn = dup(fileno(file)); - fclose(file); - - if (!(stream = utilGzReopen(fn, "ab"))) // append mode to start at end, no seek necessary - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - - // write the save data: - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) - { - // save snapshot - if (!theEmulator.emuWriteStateToStream(stream)) - { - utilGzClose(stream); - { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } - } - } - else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) - { - // save SRAM - if (!theEmulator.emuWriteBatteryToStream(stream)) - { - utilGzClose(stream); - { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } - } - - // 'soft' reset: - theEmulator.emuReset(false); - } - - utilGzClose(stream); - - // reopen the file and seek back to the end - - if (!(file = fopen(movie_filename, "rb+"))) - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } - - fseek(file, 0, SEEK_END); - } - else // no snapshot or SRAM - { - HardResetAndSRAMClear(); - } - - Movie.header.offset_to_controller_data = (uint32)ftell(file); - - strcpy(Movie.filename, movie_filename); - Movie.file = file; - Movie.bytesPerFrame = bytes_per_frame(Movie); - Movie.inputBufferPtr = Movie.inputBuffer; - Movie.currentFrame = 0; - Movie.readOnly = false; - Movie.RecordedThisSession = true; - - change_state(MOVIE_STATE_RECORD); - - systemScreenMessage("Recording movie..."); - { loadingMovie = false; return MOVIE_SUCCESS; } + systemScreenMessage("Recording movie..."); + { loadingMovie = false; return MOVIE_SUCCESS; } } void VBAUpdateButtonPressDisplay() { - uint32 keys = currentButtons[0] & BUTTON_REGULAR_RECORDING_MASK; + uint32 keys = currentButtons[0] & BUTTON_REGULAR_RECORDING_MASK; - const static char KeyMap[] = { 'A', 'B', 's', 'S', '>', '<', '^', 'v', 'R', 'L', '!', '?', '{', '}', 'v', '^' }; - const static int KeyOrder[] = { 5, 6, 4, 7, 0, 1, 9, 8, 3, 2, 12, 15, 13, 14, 11, 10 }; // < ^ > v A B L R S s { = } _ - // ? ! - char buffer[256]; - sprintf(buffer, " "); + const static char KeyMap[] = { 'A', 'B', 's', 'S', '>', '<', '^', 'v', 'R', 'L', '!', '?', '{', '}', 'v', '^' }; + const static int KeyOrder[] = { 5, 6, 4, 7, 0, 1, 9, 8, 3, 2, 12, 15, 13, 14, 11, 10 }; // < ^ > v A B L R S s { = } _ + // ? ! + char buffer[256]; + sprintf(buffer, " "); #ifndef WIN32 - // don't bother color-coding autofire and such - int i; - for (i = 0; i < 15; i++) + // don't bother color-coding autofire and such + int i; + for (i = 0; i < 15; i++) + { + int j = KeyOrder[i]; + int mask = (1 << (j)); + buffer[strlen(" ") + i] = ((keys & mask) != 0) ? KeyMap[j] : ' '; + } + + systemScreenMessage(buffer, 2, -1); +#else + const bool eraseAll = !theApp.inputDisplay; + uint32 autoHeldKeys = eraseAll ? 0 : theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; + uint32 autoFireKeys = eraseAll ? 0 : (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; + uint32 pressedKeys = eraseAll ? 0 : keys; + + char colorList[64]; + memset(colorList, 1, strlen(buffer)); + + if (!eraseAll) + { + for (int i = 0; i < 15; i++) { - int j = KeyOrder[i]; - int mask = (1 << (j)); - buffer[strlen(" ") + i] = ((keys & mask) != 0) ? KeyMap[j] : ' '; + const int j = KeyOrder[i]; + const int mask = (1 << (j)); + bool pressed = (pressedKeys & mask) != 0; + const bool autoHeld = (autoHeldKeys & mask) != 0; + const bool autoFired = (autoFireKeys & mask) != 0; + const bool erased = (lastKeys & mask) != 0 && (!pressed && !autoHeld && !autoFired); + extern int textMethod; + if (textMethod != 2 && (autoHeld || (autoFired && !pressed) || erased)) + { + int colorNum = 1; // default is white + if (autoHeld) + colorNum += (pressed ? 2 : 1); // yellow if pressed, red if not + else if (autoFired) + colorNum += 5; // blue if autofired and not currently pressed + else if (erased) + colorNum += 8; // black on black + + colorList[strlen(" ") + i] = colorNum; + pressed = true; + } + buffer[strlen(" ") + i] = pressed ? KeyMap[j] : ' '; } + } - systemScreenMessage(buffer, 2, -1); -#else - const bool eraseAll = !theApp.inputDisplay; - uint32 autoHeldKeys = eraseAll ? 0 : theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; - uint32 autoFireKeys = eraseAll ? 0 : (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; - uint32 pressedKeys = eraseAll ? 0 : keys; + lastKeys = currentButtons[0]; + lastKeys |= theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; + lastKeys |= (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; - char colorList[64]; - memset(colorList, 1, strlen(buffer)); - - if (!eraseAll) - { - for (int i = 0; i < 15; i++) - { - const int j = KeyOrder[i]; - const int mask = (1 << (j)); - bool pressed = (pressedKeys & mask) != 0; - const bool autoHeld = (autoHeldKeys & mask) != 0; - const bool autoFired = (autoFireKeys & mask) != 0; - const bool erased = (lastKeys & mask) != 0 && (!pressed && !autoHeld && !autoFired); - extern int textMethod; - if (textMethod != 2 && (autoHeld || (autoFired && !pressed) || erased)) - { - int colorNum = 1; // default is white - if (autoHeld) - colorNum += (pressed ? 2 : 1); // yellow if pressed, red if not - else if (autoFired) - colorNum += 5; // blue if autofired and not currently pressed - else if (erased) - colorNum += 8; // black on black - - colorList[strlen(" ") + i] = colorNum; - pressed = true; - } - buffer[strlen(" ") + i] = pressed ? KeyMap[j] : ' '; - } - } - - lastKeys = currentButtons[0]; - lastKeys |= theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; - lastKeys |= (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; - - systemScreenMessage(buffer, 2, -1, colorList); + systemScreenMessage(buffer, 2, -1, colorList); #endif } void VBAUpdateFrameCountDisplay() { - const int MAGICAL_NUMBER = 64; // FIXME: this won't do any better, but only to remind you of sz issues - char frameDisplayString[MAGICAL_NUMBER]; - char lagFrameDisplayString[MAGICAL_NUMBER]; - char extraCountDisplayString[MAGICAL_NUMBER]; + const int MAGICAL_NUMBER = 64; // FIXME: this won't do any better, but only to remind you of sz issues + char frameDisplayString[MAGICAL_NUMBER]; + char lagFrameDisplayString[MAGICAL_NUMBER]; + char extraCountDisplayString[MAGICAL_NUMBER]; #if (defined(WIN32) && !defined(SDL)) - if (theApp.frameCounter) + if (theApp.frameCounter) +#else + /// SDL FIXME +#endif + { + switch (Movie.state) + { + case MOVIE_STATE_PLAY: + case MOVIE_STATE_END: + { + sprintf(frameDisplayString, "%d / %d", Movie.currentFrame, Movie.header.length_frames); + if (!Movie.readOnly) + strcat(frameDisplayString, " (edit)"); + break; + } + case MOVIE_STATE_RECORD: + { + sprintf(frameDisplayString, "%d (record)", Movie.currentFrame); + break; + } + default: + { + sprintf(frameDisplayString, "%d (no movie)", systemCounters.frameCount); + break; + } + } + +#if (defined(WIN32) && !defined(SDL)) + if (theApp.lagCounter) #else /// SDL FIXME #endif { - switch (Movie.state) - { - case MOVIE_STATE_PLAY: - case MOVIE_STATE_END: - { - sprintf(frameDisplayString, "%d / %d", Movie.currentFrame, Movie.header.length_frames); - if (!Movie.readOnly) - strcat(frameDisplayString, " (edit)"); - break; - } - case MOVIE_STATE_RECORD: - { - sprintf(frameDisplayString, "%d (record)", Movie.currentFrame); - break; - } - default: - { - sprintf(frameDisplayString, "%d (no movie)", systemCounters.frameCount); - break; - } - } + // sprintf(lagFrameDisplayString, " %c %d", systemCounters.laggedLast ? '*' : '|', systemCounters.lagCount); + sprintf(lagFrameDisplayString, " | %d%s", systemCounters.lagCount, systemCounters.laggedLast ? " *" : ""); + strcat(frameDisplayString, lagFrameDisplayString); + } #if (defined(WIN32) && !defined(SDL)) - if (theApp.lagCounter) -#else - /// SDL FIXME -#endif - { -// sprintf(lagFrameDisplayString, " %c %d", systemCounters.laggedLast ? '*' : '|', systemCounters.lagCount); - sprintf(lagFrameDisplayString, " | %d%s", systemCounters.lagCount, systemCounters.laggedLast ? " *" : ""); - strcat(frameDisplayString, lagFrameDisplayString); - } - -#if (defined(WIN32) && !defined(SDL)) - if (theApp.extraCounter) -#else - /// SDL FIXME -#endif - { - sprintf(extraCountDisplayString, " | %d", systemCounters.frameCount - systemCounters.extraCount); - strcat(frameDisplayString, extraCountDisplayString); - } - } -#if (defined(WIN32) && !defined(SDL)) - else - { - frameDisplayString[0] = '\0'; - } + if (theApp.extraCounter) #else /// SDL FIXME #endif - systemScreenMessage(frameDisplayString, 1, -1); + { + sprintf(extraCountDisplayString, " | %d", systemCounters.frameCount - systemCounters.extraCount); + strcat(frameDisplayString, extraCountDisplayString); + } + } +#if (defined(WIN32) && !defined(SDL)) + else + { + frameDisplayString[0] = '\0'; + } +#else + /// SDL FIXME +#endif + systemScreenMessage(frameDisplayString, 1, -1); } // this function should only be called once every frame void VBAMovieUpdateState() { - ++Movie.currentFrame; - - if (Movie.state == MOVIE_STATE_PLAY) + ++Movie.currentFrame; + printf("RLM: inside updateState\n"); + if (Movie.state == MOVIE_STATE_PLAY) + { + Movie.inputBufferPtr += Movie.bytesPerFrame; + if (Movie.currentFrame >= Movie.header.length_frames) { - Movie.inputBufferPtr += Movie.bytesPerFrame; - if (Movie.currentFrame >= Movie.header.length_frames) - { - // the movie ends anyway; what to do next depends on the settings - change_state(MOVIE_STATE_END); - } + // the movie ends anyway; what to do next depends on the settings + change_state(MOVIE_STATE_END); } - else if (Movie.state == MOVIE_STATE_RECORD) - { - // use first fseek? - fwrite(Movie.inputBufferPtr, 1, Movie.bytesPerFrame, Movie.file); - Movie.header.length_frames = Movie.currentFrame; - Movie.inputBufferPtr += Movie.bytesPerFrame; - Movie.RecordedThisSession = true; - flush_movie_header(); - } - else if (Movie.state == MOVIE_STATE_END) - { - change_state(MOVIE_STATE_END); - } + } + else if (Movie.state == MOVIE_STATE_RECORD) + { + printf("RLM: Movie_STATE_RECORD\n"); + // use first fseek? + //TODO: THis is the problem. + //fwrite(Movie.inputBufferPtr, 1, Movie.bytesPerFrame, Movie.file); + printf("RLM: fuck.\n"); + Movie.header.length_frames = Movie.currentFrame; + Movie.inputBufferPtr += Movie.bytesPerFrame; + Movie.RecordedThisSession = true; + flush_movie_header(); + } + else if (Movie.state == MOVIE_STATE_END) + { + change_state(MOVIE_STATE_END); + } } void VBAMovieRead(int i, bool /*sensor*/) { - if (Movie.state != MOVIE_STATE_PLAY) - return; + if (Movie.state != MOVIE_STATE_PLAY) + return; - if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) - return; // not a controller we're recognizing + if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) + return; // not a controller we're recognizing - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) - { - currentButtons[i] = Read16(Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); - } - else - { - currentButtons[i] = 0; // pretend the controller is disconnected - } + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) + { + currentButtons[i] = Read16(Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); + } + else + { + currentButtons[i] = 0; // pretend the controller is disconnected + } - if ((currentButtons[i] & BUTTON_MASK_NEW_RESET) != 0) - resetSignaled = true; + if ((currentButtons[i] & BUTTON_MASK_NEW_RESET) != 0) + resetSignaled = true; } void VBAMovieWrite(int i, bool /*sensor*/) { - if (Movie.state != MOVIE_STATE_RECORD) - return; + if (Movie.state != MOVIE_STATE_RECORD) + return; - if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) - return; // not a controller we're recognizing + if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) + return; // not a controller we're recognizing - reserve_buffer_space((uint32)((Movie.inputBufferPtr - Movie.inputBuffer) + Movie.bytesPerFrame)); + reserve_buffer_space((uint32)((Movie.inputBufferPtr - Movie.inputBuffer) + Movie.bytesPerFrame)); - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) + { + // get the current controller data + uint16 buttonData = currentButtons[i]; + + // mask away the irrelevent bits + buttonData &= BUTTON_REGULAR_MASK | BUTTON_MOTION_MASK; + + // soft-reset "button" for 1 frame if the game is reset while recording + if (resetSignaled) { - // get the current controller data - uint16 buttonData = currentButtons[i]; + buttonData |= BUTTON_MASK_NEW_RESET; + } - // mask away the irrelevent bits - buttonData &= BUTTON_REGULAR_MASK | BUTTON_MOTION_MASK; + // backward compatibility kludge + if (resetSignaledLast) + { + buttonData |= BUTTON_MASK_OLD_RESET; + } - // soft-reset "button" for 1 frame if the game is reset while recording - if (resetSignaled) - { - buttonData |= BUTTON_MASK_NEW_RESET; - } + Write16(buttonData, Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); - // backward compatibility kludge - if (resetSignaledLast) - { - buttonData |= BUTTON_MASK_OLD_RESET; - } - - Write16(buttonData, Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); - - // and for display - currentButtons[i] = buttonData; - } - else - { - // pretend the controller is disconnected (otherwise input it gives could cause desync since we're not writing it to the - // movie) - currentButtons[i] = 0; - } + // and for display + currentButtons[i] = buttonData; + } + else + { + // pretend the controller is disconnected (otherwise input it gives could cause desync since we're not writing it to the + // movie) + currentButtons[i] = 0; + } } void VBAMovieStop(bool8 suppress_message) { - if (Movie.state != MOVIE_STATE_NONE) - { - change_state(MOVIE_STATE_NONE); - if (!suppress_message) - systemScreenMessage("Movie stop"); - } + if (Movie.state != MOVIE_STATE_NONE) + { + change_state(MOVIE_STATE_NONE); + if (!suppress_message) + systemScreenMessage("Movie stop"); + } } int VBAMovieGetInfo(const char *filename, SMovie *info) { - assert(info != NULL); - if (info == NULL) - return -1; + assert(info != NULL); + if (info == NULL) + return -1; - FILE * file; - int result; - SMovie &local_movie = *info; + FILE * file; + int result; + SMovie &local_movie = *info; - memset(info, 0, sizeof(*info)); - if (filename[0] == '\0') - return MOVIE_FILE_NOT_FOUND; - if (!(file = fopen(filename, "rb"))) - return MOVIE_FILE_NOT_FOUND; + memset(info, 0, sizeof(*info)); + if (filename[0] == '\0') + return MOVIE_FILE_NOT_FOUND; + if (!(file = fopen(filename, "rb"))) + return MOVIE_FILE_NOT_FOUND; - // read header - if ((result = (read_movie_header(file, local_movie))) != MOVIE_SUCCESS) - { - fclose(file); - return result; - } + // read header + if ((result = (read_movie_header(file, local_movie))) != MOVIE_SUCCESS) + { + fclose(file); + return result; + } - // read the metadata / author info from file - fread(local_movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); + // read the metadata / author info from file + fread(local_movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); - strncpy(local_movie.filename, filename, _MAX_PATH); - local_movie.filename[_MAX_PATH - 1] = '\0'; + strncpy(local_movie.filename, filename, _MAX_PATH); + local_movie.filename[_MAX_PATH - 1] = '\0'; - if (Movie.file != NULL && stricmp(local_movie.filename, Movie.filename) == 0) // alreadyOpen - { - local_movie.bytesPerFrame = Movie.bytesPerFrame; - local_movie.header.length_frames = Movie.header.length_frames; - } - else - { - // recalculate length of movie from the file size - local_movie.bytesPerFrame = bytes_per_frame(local_movie); - fseek(file, 0, SEEK_END); - int fileSize = ftell(file); - local_movie.header.length_frames = - (fileSize - local_movie.header.offset_to_controller_data) / local_movie.bytesPerFrame; - } + if (Movie.file != NULL && stricmp(local_movie.filename, Movie.filename) == 0) // alreadyOpen + { + local_movie.bytesPerFrame = Movie.bytesPerFrame; + local_movie.header.length_frames = Movie.header.length_frames; + } + else + { + // recalculate length of movie from the file size + local_movie.bytesPerFrame = bytes_per_frame(local_movie); + fseek(file, 0, SEEK_END); + int fileSize = ftell(file); + local_movie.header.length_frames = + (fileSize - local_movie.header.offset_to_controller_data) / local_movie.bytesPerFrame; + } - fclose(file); + fclose(file); - if (access(filename, W_OK)) - info->readOnly = true; + if (access(filename, W_OK)) + info->readOnly = true; - return MOVIE_SUCCESS; + return MOVIE_SUCCESS; } bool8 VBAMovieActive() { - return (Movie.state != MOVIE_STATE_NONE); + return (Movie.state != MOVIE_STATE_NONE); } bool8 VBAMovieLoading() { - return loadingMovie; + return loadingMovie; } bool8 VBAMoviePlaying() { - return (Movie.state == MOVIE_STATE_PLAY); + return (Movie.state == MOVIE_STATE_PLAY); } bool8 VBAMovieRecording() { - return (Movie.state == MOVIE_STATE_RECORD); + return (Movie.state == MOVIE_STATE_RECORD); } bool8 VBAMovieReadOnly() { - if (!VBAMovieActive()) - return false; + if (!VBAMovieActive()) + return false; - return Movie.readOnly; + return Movie.readOnly; } void VBAMovieToggleReadOnly() { - if (!VBAMovieActive()) - return; + if (!VBAMovieActive()) + return; - if (Movie.readOnly != 2) - { - Movie.readOnly = !Movie.readOnly; + if (Movie.readOnly != 2) + { + Movie.readOnly = !Movie.readOnly; - systemScreenMessage(Movie.readOnly ? "Movie now read-only" : "Movie now editable"); - } - else - { - systemScreenMessage("Can't toggle read-only movie"); - } + systemScreenMessage(Movie.readOnly ? "Movie now read-only" : "Movie now editable"); + } + else + { + systemScreenMessage("Can't toggle read-only movie"); + } } uint32 VBAMovieGetVersion() { - if (!VBAMovieActive()) - return 0; + if (!VBAMovieActive()) + return 0; - return Movie.header.version; + return Movie.header.version; } uint32 VBAMovieGetMinorVersion() { - if (!VBAMovieActive()) - return 0; + if (!VBAMovieActive()) + return 0; - return Movie.header.minorVersion; + return Movie.header.minorVersion; } uint32 VBAMovieGetId() { - if (!VBAMovieActive()) - return 0; + if (!VBAMovieActive()) + return 0; - return Movie.header.uid; + return Movie.header.uid; } uint32 VBAMovieGetLength() { - if (!VBAMovieActive()) - return 0; + if (!VBAMovieActive()) + return 0; - return Movie.header.length_frames; + return Movie.header.length_frames; } uint32 VBAMovieGetFrameCounter() { - if (!VBAMovieActive()) - return 0; + if (!VBAMovieActive()) + return 0; - return Movie.currentFrame; + return Movie.currentFrame; } uint32 VBAMovieGetRerecordCount() { - if (!VBAMovieActive()) - return 0; + if (!VBAMovieActive()) + return 0; - return Movie.header.rerecord_count; + return Movie.header.rerecord_count; } uint32 VBAMovieSetRerecordCount(uint32 newRerecordCount) { - uint32 oldRerecordCount = 0; - if (!VBAMovieActive()) - return 0; + uint32 oldRerecordCount = 0; + if (!VBAMovieActive()) + return 0; - oldRerecordCount = Movie.header.rerecord_count; - Movie.header.rerecord_count = newRerecordCount; - return oldRerecordCount; + oldRerecordCount = Movie.header.rerecord_count; + Movie.header.rerecord_count = newRerecordCount; + return oldRerecordCount; } std::string VBAMovieGetAuthorInfo() { - if (!VBAMovieActive()) - return ""; + if (!VBAMovieActive()) + return ""; - return Movie.authorInfo; + return Movie.authorInfo; } std::string VBAMovieGetFilename() { - if (!VBAMovieActive()) - return ""; + if (!VBAMovieActive()) + return ""; - return Movie.filename; + return Movie.filename; } void VBAMovieFreeze(uint8 * *buf, uint32 *size) { - // sanity check - if (!VBAMovieActive()) - { - return; - } + // sanity check + if (!VBAMovieActive()) + { + return; + } - *buf = NULL; - *size = 0; + *buf = NULL; + *size = 0; - // compute size needed for the buffer - // room for header.uid, currentFrame, and header.length_frames - uint32 size_needed = sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames); - size_needed += (uint32)(Movie.bytesPerFrame * Movie.header.length_frames); - *buf = new uint8[size_needed]; - *size = size_needed; + // compute size needed for the buffer + // room for header.uid, currentFrame, and header.length_frames + uint32 size_needed = sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames); + size_needed += (uint32)(Movie.bytesPerFrame * Movie.header.length_frames); + *buf = new uint8[size_needed]; + *size = size_needed; - uint8 *ptr = *buf; - if (!ptr) - { - return; - } + uint8 *ptr = *buf; + if (!ptr) + { + return; + } - Push32(Movie.header.uid, ptr); - Push32(Movie.currentFrame, ptr); - Push32(Movie.header.length_frames - 1, ptr); // HACK: shorten the length by 1 for backward compatibility + Push32(Movie.header.uid, ptr); + Push32(Movie.currentFrame, ptr); + Push32(Movie.header.length_frames - 1, ptr); // HACK: shorten the length by 1 for backward compatibility - memcpy(ptr, Movie.inputBuffer, Movie.bytesPerFrame * Movie.header.length_frames); + memcpy(ptr, Movie.inputBuffer, Movie.bytesPerFrame * Movie.header.length_frames); } int VBAMovieUnfreeze(const uint8 *buf, uint32 size) { - // sanity check - if (!VBAMovieActive()) + // sanity check + if (!VBAMovieActive()) + { + return MOVIE_NOT_FROM_A_MOVIE; + } + + const uint8 *ptr = buf; + if (size < sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames)) + { + return MOVIE_WRONG_FORMAT; + } + + uint32 movie_id = Pop32(ptr); + uint32 current_frame = Pop32(ptr); + uint32 end_frame = Pop32(ptr) + 1; // HACK: restore the length for backward compatibility + uint32 space_needed = Movie.bytesPerFrame * end_frame; + + if (movie_id != Movie.header.uid) + return MOVIE_NOT_FROM_THIS_MOVIE; + + if (space_needed > size) + return MOVIE_WRONG_FORMAT; + + if (Movie.readOnly) + { + // here, we are going to keep the input data from the movie file + // and simply rewind to the currentFrame pointer + // this will cause a desync if the savestate is not in sync // <-- NOT ANYMORE + // with the on-disk recording data, but it's easily solved + // by loading another savestate or playing the movie from the beginning + + // don't allow loading a state inconsistent with the current movie + uint32 length_history = min(current_frame, Movie.header.length_frames); + if (end_frame < length_history) + return MOVIE_SNAPSHOT_INCONSISTENT; + + uint32 space_shared = Movie.bytesPerFrame * length_history; + if (memcmp(Movie.inputBuffer, ptr, space_shared)) + return MOVIE_SNAPSHOT_INCONSISTENT; + + Movie.currentFrame = current_frame; + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); + } + else + { + // here, we are going to take the input data from the savestate + // and make it the input data for the current movie, then continue + // writing new input data at the currentFrame pointer + Movie.currentFrame = current_frame; + Movie.header.length_frames = end_frame; + if (!VBALuaRerecordCountSkip()) + ++Movie.header.rerecord_count; + + Movie.RecordedThisSession = true; + + // do this before calling reserve_buffer_space() + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); + reserve_buffer_space(space_needed); + memcpy(Movie.inputBuffer, ptr, space_needed); + + // for consistency, no auto movie conversion here since we don't auto convert the corresponding savestate + flush_movie_header(); + flush_movie_frames(); + } + + change_state(MOVIE_STATE_PLAY); // check for movie end + + // necessary! + resetSignaled = false; + resetSignaledLast = false; + + // necessary to check if there's a reset signal at the previous frame + if (current_frame > 0) + { + const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) { - return MOVIE_NOT_FROM_A_MOVIE; + if ((Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) && (*(Movie.inputBufferPtr+1- Movie.bytesPerFrame) & NEW_RESET)) + { + resetSignaledLast = true; + break; + } } + } - const uint8 *ptr = buf; - if (size < sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames)) - { - return MOVIE_WRONG_FORMAT; - } - - uint32 movie_id = Pop32(ptr); - uint32 current_frame = Pop32(ptr); - uint32 end_frame = Pop32(ptr) + 1; // HACK: restore the length for backward compatibility - uint32 space_needed = Movie.bytesPerFrame * end_frame; - - if (movie_id != Movie.header.uid) - return MOVIE_NOT_FROM_THIS_MOVIE; - - if (space_needed > size) - return MOVIE_WRONG_FORMAT; - - if (Movie.readOnly) - { - // here, we are going to keep the input data from the movie file - // and simply rewind to the currentFrame pointer - // this will cause a desync if the savestate is not in sync // <-- NOT ANYMORE - // with the on-disk recording data, but it's easily solved - // by loading another savestate or playing the movie from the beginning - - // don't allow loading a state inconsistent with the current movie - uint32 length_history = min(current_frame, Movie.header.length_frames); - if (end_frame < length_history) - return MOVIE_SNAPSHOT_INCONSISTENT; - - uint32 space_shared = Movie.bytesPerFrame * length_history; - if (memcmp(Movie.inputBuffer, ptr, space_shared)) - return MOVIE_SNAPSHOT_INCONSISTENT; - - Movie.currentFrame = current_frame; - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); - } - else - { - // here, we are going to take the input data from the savestate - // and make it the input data for the current movie, then continue - // writing new input data at the currentFrame pointer - Movie.currentFrame = current_frame; - Movie.header.length_frames = end_frame; - if (!VBALuaRerecordCountSkip()) - ++Movie.header.rerecord_count; - - Movie.RecordedThisSession = true; - - // do this before calling reserve_buffer_space() - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); - reserve_buffer_space(space_needed); - memcpy(Movie.inputBuffer, ptr, space_needed); - - // for consistency, no auto movie conversion here since we don't auto convert the corresponding savestate - flush_movie_header(); - flush_movie_frames(); - } - - change_state(MOVIE_STATE_PLAY); // check for movie end - - // necessary! - resetSignaled = false; - resetSignaledLast = false; - - // necessary to check if there's a reset signal at the previous frame - if (current_frame > 0) - { - const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) - { - if ((Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) && (*(Movie.inputBufferPtr+1- Movie.bytesPerFrame) & NEW_RESET)) - { - resetSignaledLast = true; - break; - } - } - } - - return MOVIE_SUCCESS; + return MOVIE_SUCCESS; } bool VBAMovieEnded() { - return (Movie.state == MOVIE_STATE_END); -// return (Movie.state != MOVIE_STATE_NONE && Movie.currentFrame >= Movie.header.length_frames); + return (Movie.state == MOVIE_STATE_END); + // return (Movie.state != MOVIE_STATE_NONE && Movie.currentFrame >= Movie.header.length_frames); } bool VBAMovieAllowsRerecording() { - bool allows = (Movie.state != MOVIE_STATE_NONE) && (Movie.currentFrame <= Movie.header.length_frames); - return /*!VBAMovieReadOnly() &&*/ allows; + bool allows = (Movie.state != MOVIE_STATE_NONE) && (Movie.currentFrame <= Movie.header.length_frames); + return /*!VBAMovieReadOnly() &&*/ allows; } bool VBAMovieSwitchToPlaying() { - if (!VBAMovieActive()) - return false; + if (!VBAMovieActive()) + return false; - if (!Movie.readOnly) - { - VBAMovieToggleReadOnly(); - } + if (!Movie.readOnly) + { + VBAMovieToggleReadOnly(); + } - change_state(MOVIE_STATE_PLAY); - if (Movie.state == MOVIE_STATE_PLAY) - systemScreenMessage("Movie replay (continue)"); - else - systemScreenMessage("Movie end"); + change_state(MOVIE_STATE_PLAY); + if (Movie.state == MOVIE_STATE_PLAY) + systemScreenMessage("Movie replay (continue)"); + else + systemScreenMessage("Movie end"); - return true; + return true; } bool VBAMovieSwitchToRecording() { - if (!VBAMovieAllowsRerecording()) - return false; + if (!VBAMovieAllowsRerecording()) + return false; - if (Movie.readOnly) - { - VBAMovieToggleReadOnly(); - } + if (Movie.readOnly) + { + VBAMovieToggleReadOnly(); + } - if (!VBALuaRerecordCountSkip()) - ++Movie.header.rerecord_count; + if (!VBALuaRerecordCountSkip()) + ++Movie.header.rerecord_count; - change_state(MOVIE_STATE_RECORD); - systemScreenMessage("Movie re-record"); + change_state(MOVIE_STATE_RECORD); + systemScreenMessage("Movie re-record"); - //truncate_movie(Movie.currentFrame); + //truncate_movie(Movie.currentFrame); - return true; + return true; } uint32 VBAMovieGetState() { - // ? - if (!VBAMovieActive()) - return MOVIE_STATE_NONE; + // ? + if (!VBAMovieActive()) + return MOVIE_STATE_NONE; - return Movie.state; + return Movie.state; } void VBAMovieSignalReset() { - if (VBAMovieActive()) - resetSignaled = true; + if (VBAMovieActive()) + resetSignaled = true; } void VBAMovieResetIfRequested() { - if (resetSignaled) - { - theEmulator.emuReset(false); - resetSignaled = false; - resetSignaledLast = true; - } - else - { - resetSignaledLast = false; - } + if (resetSignaled) + { + theEmulator.emuReset(false); + resetSignaled = false; + resetSignaledLast = true; + } + else + { + resetSignaledLast = false; + } } void VBAMovieSetMetadata(const char *info) { - if (!memcmp(Movie.authorInfo, info, MOVIE_METADATA_SIZE)) - return; + if (!memcmp(Movie.authorInfo, info, MOVIE_METADATA_SIZE)) + return; - memcpy(Movie.authorInfo, info, MOVIE_METADATA_SIZE); // strncpy would omit post-0 bytes - Movie.authorInfo[MOVIE_METADATA_SIZE - 1] = '\0'; + memcpy(Movie.authorInfo, info, MOVIE_METADATA_SIZE); // strncpy would omit post-0 bytes + Movie.authorInfo[MOVIE_METADATA_SIZE - 1] = '\0'; - if (Movie.file) - { - // (over-)write the header - fseek(Movie.file, 0, SEEK_SET); - write_movie_header(Movie.file, Movie); + if (Movie.file) + { + // (over-)write the header + fseek(Movie.file, 0, SEEK_SET); - // write the metadata / author info to file - fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, Movie.file); + write_movie_header(Movie.file, Movie); - fflush(Movie.file); - } + // write the metadata / author info to file + fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, Movie.file); + + fflush(Movie.file); + } + printf("RLM: setMetadata called\n"); + } void VBAMovieRestart() { - if (VBAMovieActive()) - { - systemSoundClearBuffer(); + if (VBAMovieActive()) + { + systemSoundClearBuffer(); - bool8 modified = Movie.RecordedThisSession; + bool8 modified = Movie.RecordedThisSession; - VBAMovieStop(true); + VBAMovieStop(true); - char movieName [_MAX_PATH]; - strncpy(movieName, Movie.filename, _MAX_PATH); - movieName[_MAX_PATH - 1] = '\0'; - VBAMovieOpen(movieName, Movie.readOnly); // can't just pass in Movie.filename, since VBAMovieOpen clears out Movie's - // variables + char movieName [_MAX_PATH]; + strncpy(movieName, Movie.filename, _MAX_PATH); + movieName[_MAX_PATH - 1] = '\0'; + VBAMovieOpen(movieName, Movie.readOnly); // can't just pass in Movie.filename, since VBAMovieOpen clears out Movie's + // variables - Movie.RecordedThisSession = modified; + Movie.RecordedThisSession = modified; - systemScreenMessage("Movie replay (restart)"); - } + systemScreenMessage("Movie replay (restart)"); + } } int VBAMovieGetPauseAt() { - return Movie.pauseFrame; + return Movie.pauseFrame; } void VBAMovieSetPauseAt(int at) { - Movie.pauseFrame = at; + Movie.pauseFrame = at; } /////////////////////// @@ -1688,85 +1703,85 @@ // FIXME: is it safe to convert/flush a movie while recording it (considering fseek() problem)? int VBAMovieConvertCurrent() { - if (!VBAMovieActive()) + if (!VBAMovieActive()) + { + return MOVIE_NOTHING; + } + + if (Movie.header.minorVersion > VBM_REVISION) + { + return MOVIE_WRONG_VERSION; + } + + if (Movie.header.minorVersion == VBM_REVISION) + { + return MOVIE_NOTHING; + } + + Movie.header.minorVersion = VBM_REVISION; + + if (Movie.header.length_frames == 0) // this could happen + { + truncate_movie(0); + return MOVIE_SUCCESS; + } + + // fix movies recorded from snapshots + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) + { + uint8 *firstFramePtr = Movie.inputBuffer; + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) { - return MOVIE_NOTHING; + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) + { + Push16(initialInputs[i], firstFramePtr); + // note: this is correct since Push16 advances the dest pointer by sizeof u16 + } } + } - if (Movie.header.minorVersion > VBM_REVISION) + // convert old resets to new ones + const u8 OLD_RESET = u8(BUTTON_MASK_OLD_RESET >> 8); + const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) + { + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) { - return MOVIE_WRONG_VERSION; + uint8 *startPtr = Movie.inputBuffer + sizeof(u16) * i + 1; + uint8 *endPtr = Movie.inputBuffer + Movie.bytesPerFrame * (Movie.header.length_frames - 1); + for (; startPtr < endPtr; startPtr += Movie.bytesPerFrame) + { + if (startPtr[Movie.bytesPerFrame] & OLD_RESET) + { + startPtr[0] |= NEW_RESET; + } + } } + } - if (Movie.header.minorVersion == VBM_REVISION) - { - return MOVIE_NOTHING; - } - - Movie.header.minorVersion = VBM_REVISION; - - if (Movie.header.length_frames == 0) // this could happen - { - truncate_movie(0); - return MOVIE_SUCCESS; - } - - // fix movies recorded from snapshots - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) - { - uint8 *firstFramePtr = Movie.inputBuffer; - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) - { - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) - { - Push16(initialInputs[i], firstFramePtr); - // note: this is correct since Push16 advances the dest pointer by sizeof u16 - } - } - } - - // convert old resets to new ones - const u8 OLD_RESET = u8(BUTTON_MASK_OLD_RESET >> 8); - const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) - { - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) - { - uint8 *startPtr = Movie.inputBuffer + sizeof(u16) * i + 1; - uint8 *endPtr = Movie.inputBuffer + Movie.bytesPerFrame * (Movie.header.length_frames - 1); - for (; startPtr < endPtr; startPtr += Movie.bytesPerFrame) - { - if (startPtr[Movie.bytesPerFrame] & OLD_RESET) - { - startPtr[0] |= NEW_RESET; - } - } - } - } - - flush_movie_header(); - flush_movie_frames(); - return MOVIE_SUCCESS; + flush_movie_header(); + flush_movie_frames(); + return MOVIE_SUCCESS; } bool VBAMovieTuncateAtCurrentFrame() { - if (!VBAMovieActive()) - return false; + if (!VBAMovieActive()) + return false; - truncate_movie(Movie.currentFrame); - change_state(MOVIE_STATE_END); - systemScreenMessage("Movie truncated"); + truncate_movie(Movie.currentFrame); + change_state(MOVIE_STATE_END); + systemScreenMessage("Movie truncated"); - return true; + return true; } bool VBAMovieFixHeader() { - if (!VBAMovieActive()) - return false; + if (!VBAMovieActive()) + return false; - flush_movie_header(); - systemScreenMessage("Movie header fixed"); - return true; + flush_movie_header(); + systemScreenMessage("Movie header fixed"); + return true; } diff -r 0dc331ec7f27 -r 44974c3e093b src/gb/GB.cpp --- a/src/gb/GB.cpp Sun Mar 04 22:44:42 2012 -0600 +++ b/src/gb/GB.cpp Mon Mar 05 01:25:11 2012 -0600 @@ -163,361 +163,361 @@ static bool pauseAfterFrameAdvance = false; int32 gbRomSizes[] = { 0x00008000, // 32K - 0x00010000, // 64K - 0x00020000, // 128K - 0x00040000, // 256K - 0x00080000, // 512K - 0x00100000, // 1024K - 0x00200000, // 2048K - 0x00400000, // 4096K - 0x00800000 // 8192K + 0x00010000, // 64K + 0x00020000, // 128K + 0x00040000, // 256K + 0x00080000, // 512K + 0x00100000, // 1024K + 0x00200000, // 2048K + 0x00400000, // 4096K + 0x00800000 // 8192K }; int32 gbRomSizesMasks[] = { 0x00007fff, - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff }; + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff }; int32 gbRamSizes[6] = { 0x00000000, // 0K - 0x00000800, // 2K - 0x00002000, // 8K - 0x00008000, // 32K - 0x00020000, // 128K - 0x00010000 // 64K + 0x00000800, // 2K + 0x00002000, // 8K + 0x00008000, // 32K + 0x00020000, // 128K + 0x00010000 // 64K }; int32 gbRamSizesMasks[6] = { 0x00000000, - 0x000007ff, - 0x00001fff, - 0x00007fff, - 0x0001ffff, - 0x0000ffff }; + 0x000007ff, + 0x00001fff, + 0x00007fff, + 0x0001ffff, + 0x0000ffff }; int32 gbCycles[] = -{ -// 0 1 2 3 4 5 6 7 8 9 a b c d e f - 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 - 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 - 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 - 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 - 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b - 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c - 2, 3, 3, 0, 3, 4, 2, 4, 2, 4, 3, 0, 3, 0, 2, 4, // d - 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4, // e - 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4 // f -}; + { + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 + 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 + 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 + 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 + 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b + 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c + 2, 3, 3, 0, 3, 4, 2, 4, 2, 4, 3, 0, 3, 0, 2, 4, // d + 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4, // e + 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4 // f + }; int32 gbCyclesCB[] = -{ -// 0 1 2 3 4 5 6 7 8 9 a b c d e f - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 8 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 9 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // a - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // b - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // c - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // d - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // e - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 // f -}; + { + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 8 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 9 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // a + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // b + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // c + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // d + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // e + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 // f + }; u16 DAATable[] = -{ - 0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, - 0x0800, 0x0900, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, - 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, - 0x1800, 0x1900, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, - 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, - 0x2800, 0x2900, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, - 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, - 0x3800, 0x3900, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, - 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, - 0x4800, 0x4900, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, - 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, - 0x5800, 0x5900, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, - 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700, - 0x6800, 0x6900, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, - 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, - 0x7800, 0x7900, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, - 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, - 0x8800, 0x8900, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, - 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700, - 0x9800, 0x9900, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, - 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, - 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, - 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, - 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, - 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, - 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, - 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, - 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, - 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, - 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, - 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, - 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, - 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710, - 0x6810, 0x6910, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, - 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710, - 0x7810, 0x7910, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, - 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710, - 0x8810, 0x8910, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, - 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710, - 0x9810, 0x9910, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, - 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710, - 0xA810, 0xA910, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, - 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710, - 0xB810, 0xB910, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, - 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710, - 0xC810, 0xC910, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, - 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710, - 0xD810, 0xD910, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, - 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710, - 0xE810, 0xE910, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, - 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710, - 0xF810, 0xF910, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, - 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, - 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, - 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, - 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, - 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, - 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, - 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, - 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, - 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, - 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, - 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, - 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, - 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, - 0x0E00, 0x0F00, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, - 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, - 0x1E00, 0x1F00, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, - 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, - 0x2E00, 0x2F00, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, - 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, - 0x3E00, 0x3F00, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, - 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, - 0x4E00, 0x4F00, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, - 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, - 0x5E00, 0x5F00, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, - 0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00, - 0x6E00, 0x6F00, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, - 0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00, - 0x7E00, 0x7F00, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, - 0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00, - 0x8E00, 0x8F00, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, - 0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00, - 0x9E00, 0x9F00, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, - 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, - 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, - 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, - 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, - 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, - 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, - 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, - 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, - 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, - 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, - 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, - 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, - 0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10, - 0x6E10, 0x6F10, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, - 0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10, - 0x7E10, 0x7F10, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, - 0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10, - 0x8E10, 0x8F10, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, - 0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10, - 0x9E10, 0x9F10, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, - 0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10, - 0xAE10, 0xAF10, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, - 0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10, - 0xBE10, 0xBF10, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, - 0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10, - 0xCE10, 0xCF10, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, - 0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10, - 0xDE10, 0xDF10, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, - 0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10, - 0xEE10, 0xEF10, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, - 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10, - 0xFE10, 0xFF10, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, - 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, - 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, - 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, - 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, - 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, - 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, - 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, - 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, - 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, - 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, - 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, - 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, - 0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, - 0x0840, 0x0940, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, - 0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, - 0x1840, 0x1940, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, - 0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, - 0x2840, 0x2940, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, - 0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, - 0x3840, 0x3940, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, - 0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, - 0x4840, 0x4940, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, - 0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, - 0x5840, 0x5940, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, - 0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, - 0x6840, 0x6940, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, - 0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, - 0x7840, 0x7940, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, - 0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, - 0x8840, 0x8940, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, - 0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740, - 0x9840, 0x9940, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, - 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, - 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, - 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, - 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, - 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, - 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, - 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, - 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, - 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, - 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, - 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, - 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, - 0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, - 0xA850, 0xA950, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, - 0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, - 0xB850, 0xB950, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, - 0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, - 0xC850, 0xC950, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, - 0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, - 0xD850, 0xD950, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, - 0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, - 0xE850, 0xE950, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, - 0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, - 0xF850, 0xF950, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, - 0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, - 0x0850, 0x0950, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, - 0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, - 0x1850, 0x1950, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, - 0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, - 0x2850, 0x2950, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, - 0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, - 0x3850, 0x3950, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, - 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, - 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, - 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, - 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, - 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, - 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, - 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, - 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, - 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, - 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, - 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, - 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, - 0xFA60, 0xFB60, 0xFC60, 0xFD60, 0xFE60, 0xFF60, 0x00C0, 0x0140, - 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, - 0x0A60, 0x0B60, 0x0C60, 0x0D60, 0x0E60, 0x0F60, 0x1040, 0x1140, - 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, - 0x1A60, 0x1B60, 0x1C60, 0x1D60, 0x1E60, 0x1F60, 0x2040, 0x2140, - 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, - 0x2A60, 0x2B60, 0x2C60, 0x2D60, 0x2E60, 0x2F60, 0x3040, 0x3140, - 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, - 0x3A60, 0x3B60, 0x3C60, 0x3D60, 0x3E60, 0x3F60, 0x4040, 0x4140, - 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, - 0x4A60, 0x4B60, 0x4C60, 0x4D60, 0x4E60, 0x4F60, 0x5040, 0x5140, - 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, - 0x5A60, 0x5B60, 0x5C60, 0x5D60, 0x5E60, 0x5F60, 0x6040, 0x6140, - 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, - 0x6A60, 0x6B60, 0x6C60, 0x6D60, 0x6E60, 0x6F60, 0x7040, 0x7140, - 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, - 0x7A60, 0x7B60, 0x7C60, 0x7D60, 0x7E60, 0x7F60, 0x8040, 0x8140, - 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, - 0x8A60, 0x8B60, 0x8C60, 0x8D60, 0x8E60, 0x8F60, 0x9040, 0x9140, - 0x9240, 0x9340, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, - 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, - 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, - 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, - 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, - 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, - 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, - 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, - 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, - 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, - 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, - 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, - 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, - 0x9A70, 0x9B70, 0x9C70, 0x9D70, 0x9E70, 0x9F70, 0xA050, 0xA150, - 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, - 0xAA70, 0xAB70, 0xAC70, 0xAD70, 0xAE70, 0xAF70, 0xB050, 0xB150, - 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, - 0xBA70, 0xBB70, 0xBC70, 0xBD70, 0xBE70, 0xBF70, 0xC050, 0xC150, - 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, - 0xCA70, 0xCB70, 0xCC70, 0xCD70, 0xCE70, 0xCF70, 0xD050, 0xD150, - 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, - 0xDA70, 0xDB70, 0xDC70, 0xDD70, 0xDE70, 0xDF70, 0xE050, 0xE150, - 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, - 0xEA70, 0xEB70, 0xEC70, 0xED70, 0xEE70, 0xEF70, 0xF050, 0xF150, - 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, - 0xFA70, 0xFB70, 0xFC70, 0xFD70, 0xFE70, 0xFF70, 0x00D0, 0x0150, - 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, - 0x0A70, 0x0B70, 0x0C70, 0x0D70, 0x0E70, 0x0F70, 0x1050, 0x1150, - 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, - 0x1A70, 0x1B70, 0x1C70, 0x1D70, 0x1E70, 0x1F70, 0x2050, 0x2150, - 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, - 0x2A70, 0x2B70, 0x2C70, 0x2D70, 0x2E70, 0x2F70, 0x3050, 0x3150, - 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, - 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, - 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, - 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, - 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, - 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, - 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, - 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, - 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, - 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, - 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, - 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, - 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, -}; + { + 0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, + 0x0800, 0x0900, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, + 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, + 0x1800, 0x1900, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, + 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, + 0x2800, 0x2900, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, + 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, + 0x3800, 0x3900, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, + 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, + 0x4800, 0x4900, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, + 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, + 0x5800, 0x5900, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, + 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700, + 0x6800, 0x6900, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, + 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, + 0x7800, 0x7900, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, + 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, + 0x8800, 0x8900, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, + 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700, + 0x9800, 0x9900, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, + 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, + 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, + 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, + 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, + 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, + 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710, + 0x6810, 0x6910, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, + 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710, + 0x7810, 0x7910, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, + 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710, + 0x8810, 0x8910, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, + 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710, + 0x9810, 0x9910, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, + 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710, + 0xA810, 0xA910, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, + 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710, + 0xB810, 0xB910, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, + 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710, + 0xC810, 0xC910, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, + 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710, + 0xD810, 0xD910, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, + 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710, + 0xE810, 0xE910, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, + 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710, + 0xF810, 0xF910, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, + 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, + 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, + 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, + 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, + 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, + 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, + 0x0E00, 0x0F00, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, + 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, + 0x1E00, 0x1F00, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, + 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, + 0x2E00, 0x2F00, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, + 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, + 0x3E00, 0x3F00, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, + 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, + 0x4E00, 0x4F00, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, + 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, + 0x5E00, 0x5F00, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, + 0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00, + 0x6E00, 0x6F00, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, + 0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00, + 0x7E00, 0x7F00, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, + 0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00, + 0x8E00, 0x8F00, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, + 0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00, + 0x9E00, 0x9F00, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, + 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, + 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, + 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, + 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, + 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, + 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10, + 0x6E10, 0x6F10, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, + 0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10, + 0x7E10, 0x7F10, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, + 0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10, + 0x8E10, 0x8F10, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, + 0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10, + 0x9E10, 0x9F10, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, + 0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10, + 0xAE10, 0xAF10, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, + 0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10, + 0xBE10, 0xBF10, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, + 0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10, + 0xCE10, 0xCF10, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, + 0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10, + 0xDE10, 0xDF10, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, + 0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10, + 0xEE10, 0xEF10, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, + 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10, + 0xFE10, 0xFF10, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, + 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, + 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, + 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, + 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, + 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, + 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, + 0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, + 0x0840, 0x0940, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, + 0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, + 0x1840, 0x1940, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, + 0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, + 0x2840, 0x2940, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, + 0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, + 0x3840, 0x3940, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, + 0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, + 0x4840, 0x4940, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, + 0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, + 0x5840, 0x5940, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, + 0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, + 0x6840, 0x6940, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, + 0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, + 0x7840, 0x7940, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, + 0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, + 0x8840, 0x8940, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, + 0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740, + 0x9840, 0x9940, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, + 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, + 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, + 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, + 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, + 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, + 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, + 0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, + 0xA850, 0xA950, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, + 0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, + 0xB850, 0xB950, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, + 0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, + 0xC850, 0xC950, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, + 0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, + 0xD850, 0xD950, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, + 0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, + 0xE850, 0xE950, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, + 0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, + 0xF850, 0xF950, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, + 0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, + 0x0850, 0x0950, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, + 0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, + 0x1850, 0x1950, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, + 0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, + 0x2850, 0x2950, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, + 0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, + 0x3850, 0x3950, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, + 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, + 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, + 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, + 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, + 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, + 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, + 0xFA60, 0xFB60, 0xFC60, 0xFD60, 0xFE60, 0xFF60, 0x00C0, 0x0140, + 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, + 0x0A60, 0x0B60, 0x0C60, 0x0D60, 0x0E60, 0x0F60, 0x1040, 0x1140, + 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, + 0x1A60, 0x1B60, 0x1C60, 0x1D60, 0x1E60, 0x1F60, 0x2040, 0x2140, + 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, + 0x2A60, 0x2B60, 0x2C60, 0x2D60, 0x2E60, 0x2F60, 0x3040, 0x3140, + 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, + 0x3A60, 0x3B60, 0x3C60, 0x3D60, 0x3E60, 0x3F60, 0x4040, 0x4140, + 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, + 0x4A60, 0x4B60, 0x4C60, 0x4D60, 0x4E60, 0x4F60, 0x5040, 0x5140, + 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, + 0x5A60, 0x5B60, 0x5C60, 0x5D60, 0x5E60, 0x5F60, 0x6040, 0x6140, + 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, + 0x6A60, 0x6B60, 0x6C60, 0x6D60, 0x6E60, 0x6F60, 0x7040, 0x7140, + 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, + 0x7A60, 0x7B60, 0x7C60, 0x7D60, 0x7E60, 0x7F60, 0x8040, 0x8140, + 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, + 0x8A60, 0x8B60, 0x8C60, 0x8D60, 0x8E60, 0x8F60, 0x9040, 0x9140, + 0x9240, 0x9340, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, + 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, + 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, + 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, + 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, + 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, + 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, + 0x9A70, 0x9B70, 0x9C70, 0x9D70, 0x9E70, 0x9F70, 0xA050, 0xA150, + 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, + 0xAA70, 0xAB70, 0xAC70, 0xAD70, 0xAE70, 0xAF70, 0xB050, 0xB150, + 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, + 0xBA70, 0xBB70, 0xBC70, 0xBD70, 0xBE70, 0xBF70, 0xC050, 0xC150, + 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, + 0xCA70, 0xCB70, 0xCC70, 0xCD70, 0xCE70, 0xCF70, 0xD050, 0xD150, + 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, + 0xDA70, 0xDB70, 0xDC70, 0xDD70, 0xDE70, 0xDF70, 0xE050, 0xE150, + 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, + 0xEA70, 0xEB70, 0xEC70, 0xED70, 0xEE70, 0xEF70, 0xF050, 0xF150, + 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, + 0xFA70, 0xFB70, 0xFC70, 0xFD70, 0xFE70, 0xFF70, 0x00D0, 0x0150, + 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, + 0x0A70, 0x0B70, 0x0C70, 0x0D70, 0x0E70, 0x0F70, 0x1050, 0x1150, + 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, + 0x1A70, 0x1B70, 0x1C70, 0x1D70, 0x1E70, 0x1F70, 0x2050, 0x2150, + 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, + 0x2A70, 0x2B70, 0x2C70, 0x2D70, 0x2E70, 0x2F70, 0x3050, 0x3150, + 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, + 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, + 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, + 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, + 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, + 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, + 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, + 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, + 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, + 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, + 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, + 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, + 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, + }; u8 ZeroTable[] = -{ - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; + { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; #define GBSAVE_GAME_VERSION_1 1 #define GBSAVE_GAME_VERSION_2 2 @@ -536,81 +536,81 @@ int inline gbGetValue(int min, int max, int v) { - return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0))); + return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0))); } void gbGenFilter() { - for (int r = 0; r < 32; r++) + for (int r = 0; r < 32; r++) + { + for (int g = 0; g < 32; g++) { - for (int g = 0; g < 32; g++) - { - for (int b = 0; b < 32; b++) - { - int nr = gbGetValue(gbGetValue(4, 14, g), - gbGetValue(24, 29, g), r) - 4; - int ng = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), - 14 + gbGetValue(0, 3, r), b), - gbGetValue(24 + gbGetValue(0, 3, r), - 29 + gbGetValue(0, 1, r), b), g) - 4; - int nb = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), - 14 + gbGetValue(0, 3, r), g), - gbGetValue(24 + gbGetValue(0, 3, r), - 29 + gbGetValue(0, 1, r), g), b) - 4; - gbColorFilter[(b << 10) | (g << 5) | r] = (nb << 10) | (ng << 5) | nr; - } - } + for (int b = 0; b < 32; b++) + { + int nr = gbGetValue(gbGetValue(4, 14, g), + gbGetValue(24, 29, g), r) - 4; + int ng = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), + 14 + gbGetValue(0, 3, r), b), + gbGetValue(24 + gbGetValue(0, 3, r), + 29 + gbGetValue(0, 1, r), b), g) - 4; + int nb = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), + 14 + gbGetValue(0, 3, r), g), + gbGetValue(24 + gbGetValue(0, 3, r), + 29 + gbGetValue(0, 1, r), g), b) - 4; + gbColorFilter[(b << 10) | (g << 5) | r] = (nb << 10) | (ng << 5) | nr; + } } + } } void gbCopyMemory(u16 d, u16 s, int count) { - while (count) - { - gbWriteMemoryQuick(d, gbReadMemoryQuick(s)); - s++; - d++; - count--; - } + while (count) + { + gbWriteMemoryQuick(d, gbReadMemoryQuick(s)); + s++; + d++; + count--; + } } void gbDoHdma() { - gbCopyMemory(gbHdmaDestination, gbHdmaSource, 0x10); - - gbHdmaDestination += 0x10; - gbHdmaSource += 0x10; - - register_HDMA2 = (register_HDMA2 + 0x10) & 0xFF; - if (register_HDMA2 == 0x00) - register_HDMA1++; - - register_HDMA4 = (register_HDMA4 + 0x10) & 0xFF; - if (register_HDMA4 == 0x00) - register_HDMA3++; - - if (gbHdmaDestination == 0x96b0) - gbHdmaBytes = gbHdmaBytes; - gbHdmaBytes -= 0x10; - register_HDMA5--; - if (register_HDMA5 == 0xff) - gbHdmaOn = 0; + gbCopyMemory(gbHdmaDestination, gbHdmaSource, 0x10); + + gbHdmaDestination += 0x10; + gbHdmaSource += 0x10; + + register_HDMA2 = (register_HDMA2 + 0x10) & 0xFF; + if (register_HDMA2 == 0x00) + register_HDMA1++; + + register_HDMA4 = (register_HDMA4 + 0x10) & 0xFF; + if (register_HDMA4 == 0x00) + register_HDMA3++; + + if (gbHdmaDestination == 0x96b0) + gbHdmaBytes = gbHdmaBytes; + gbHdmaBytes -= 0x10; + register_HDMA5--; + if (register_HDMA5 == 0xff) + gbHdmaOn = 0; } // fix for Harley and Lego Racers void gbCompareLYToLYC() { - if (register_LY == register_LYC) - { - // mark that we have a match - register_STAT |= 4; - - // check if we need an interrupt - if ((register_STAT & 0x40) && (register_IE & 2)) - gbInterrupt |= 2; - } - else // no match - register_STAT &= 0xfb; + if (register_LY == register_LYC) + { + // mark that we have a match + register_STAT |= 4; + + // check if we need an interrupt + if ((register_STAT & 0x40) && (register_IE & 2)) + gbInterrupt |= 2; + } + else // no match + register_STAT &= 0xfb; } // FIXME: horrible kludge to workaround the frame timing bug @@ -618,1971 +618,1971 @@ void gbWriteMemoryWrapped(register u16 address, register u8 value) { - if (address < 0x8000) + if (address < 0x8000) + { +#ifndef FINAL_VERSION + if (memorydebug && (address > 0x3fff || address < 0x2000)) { + log("Memory register write %04x=%02x PC=%04x\n", + address, + value, + PC.W); + } +#endif + if (mapper) + (*mapper)(address, value); + return; + } + + if (address < 0xa000) + { + gbWriteMemoryQuick(address, value); + return; + } + + if (address < 0xc000) + { #ifndef FINAL_VERSION - if (memorydebug && (address > 0x3fff || address < 0x2000)) - { - log("Memory register write %04x=%02x PC=%04x\n", - address, - value, - PC.W); - } + if (memorydebug) + { + log("Memory register write %04x=%02x PC=%04x\n", + address, + value, + PC.W); + } #endif - if (mapper) - (*mapper)(address, value); - return; + + if (mapper) + (*mapperRAM)(address, value); + return; + } + + if (address < 0xfe00) + { + gbWriteMemoryQuick(address, value); + return; + } + + if (address < 0xff00) + { + gbMemory[address] = value; + return; + } + + switch (address & 0x00ff) + { + case 0x00: + { + gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | + (value & 0x30)); + if (gbSgbMode) + { + gbSgbDoBitTransfer(value); + } + + return; + } + + case 0x01: + { + gbMemory[0xff01] = value; + return; + } + + // serial control + case 0x02: + { + gbSerialOn = (value & 0x80); + gbMemory[0xff02] = value; + if (gbSerialOn) + { + gbSerialTicks = GBSERIAL_CLOCK_TICKS; +#ifdef LINK_EMULATION + if (linkConnected) + { + if (value & 1) + { + linkSendByte(0x100 | gbMemory[0xFF01]); + Sleep(5); + } + } +#endif + } + + gbSerialBits = 0; + return; + } + + // DIV register resets on any write + case 0x04: + { + register_DIV = 0; + return; + } + case 0x05: + register_TIMA = value; + return; + + case 0x06: + register_TMA = value; + return; + + // TIMER control + case 0x07: + { + register_TAC = value; + + gbTimerOn = (value & 4); + gbTimerMode = value & 3; + // register_TIMA = register_TMA; + switch (gbTimerMode) + { + case 0: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; + break; + case 1: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS; + break; + case 2: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS; + break; + case 3: + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS; + break; + } + return; + } + + case 0x0f: + { + register_IF = value; + gbInterrupt = value; + return; + } + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + { + SOUND_EVENT(address, value); + return; + } + case 0x40: + { + int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); + + if (lcdChange) + { + if (value & 0x80) + { + gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS; + gbLcdMode = 0; + register_STAT &= 0xfc; + register_LY = 0x00; + // FIXME: horrible workaround + if (gbNullInputHackTempEnabled && !useOldFrameTiming) + memcpy(gbJoymask, s_gbJoymask, sizeof(gbJoymask)); + } + else + { + gbLcdTicks = 0; + gbLcdMode = 0; + register_STAT &= 0xfc; + register_LY = 0x00; + // FIXME: horrible workaround + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); + if (gbNullInputHackTempEnabled && !useOldFrameTiming) + memset(gbJoymask, 0, sizeof(gbJoymask)); + } + // compareLYToLYC(); + } + // don't draw the window if it was not enabled and not being drawn before + if (!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 && + register_LY > register_WY) + gbWindowLine = 144; + + register_LCDC = value; + + return; + } + + // STAT + case 0x41: + { + //register_STAT = (register_STAT & 0x87) | + // (value & 0x7c); + register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? + // GB bug from Devrs FAQ + if (!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2) + gbInterrupt |= 2; + return; + } + + // SCY + case 0x42: + { + register_SCY = value; + return; + } + + // SCX + case 0x43: + { + register_SCX = value; + return; + } + + // LY + case 0x44: + { + // read only + return; + } + + // LYC + case 0x45: + { + register_LYC = value; + if ((register_LCDC & 0x80)) + { + gbCompareLYToLYC(); + } + return; + } + + // DMA! + case 0x46: + { + int source = value * 0x0100; + + gbCopyMemory(0xfe00, + source, + 0xa0); + register_DMA = value; + return; + } + + // BGP + case 0x47: + { + gbBgp[0] = value & 0x03; + gbBgp[1] = (value & 0x0c) >> 2; + gbBgp[2] = (value & 0x30) >> 4; + gbBgp[3] = (value & 0xc0) >> 6; + break; + } + + // OBP0 + case 0x48: + { + gbObp0[0] = value & 0x03; + gbObp0[1] = (value & 0x0c) >> 2; + gbObp0[2] = (value & 0x30) >> 4; + gbObp0[3] = (value & 0xc0) >> 6; + break; + } + + // OBP1 + case 0x49: + { + gbObp1[0] = value & 0x03; + gbObp1[1] = (value & 0x0c) >> 2; + gbObp1[2] = (value & 0x30) >> 4; + gbObp1[3] = (value & 0xc0) >> 6; + break; + } + + case 0x4a: + register_WY = value; + return; + + case 0x4b: + register_WX = value; + return; + + // KEY1 + case 0x4d: + { + if (gbCgbMode) + { + gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1); + return; + } + break; + } + + // VBK + case 0x4f: + { + if (gbCgbMode) + { + value = value & 1; + if (value == gbVramBank) + return; + + int vramAddress = value * 0x2000; + gbMemoryMap[0x08] = &gbVram[vramAddress]; + gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; + + gbVramBank = value; + register_VBK = value; + } + return; + break; + } + + // HDMA1 + case 0x51: + { + if (gbCgbMode) + { + if (value > 0x7f && value < 0xa0) + value = 0; + + gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0); + + register_HDMA1 = value; + return; + } + break; + } + + // HDMA2 + case 0x52: + { + if (gbCgbMode) + { + value = value & 0xf0; + + gbHdmaSource = (register_HDMA1 << 8) | (value); + + register_HDMA2 = value; + return; + } + break; + } + + // HDMA3 + case 0x53: + { + if (gbCgbMode) + { + value = value & 0x1f; + gbHdmaDestination = (value << 8) | (register_HDMA4 & 0xf0); + gbHdmaDestination += 0x8000; + register_HDMA3 = value; + return; + } + break; + } + + // HDMA4 + case 0x54: + { + if (gbCgbMode) + { + value = value & 0xf0; + gbHdmaDestination = ((register_HDMA3 & 0x1f) << 8) | value; + gbHdmaDestination += 0x8000; + register_HDMA4 = value; + return; + } + break; + } + + // HDMA5 + case 0x55: + { + if (gbCgbMode) + { + gbHdmaBytes = 16 + (value & 0x7f) * 16; + if (gbHdmaOn) + { + if (value & 0x80) + { + register_HDMA5 = (value & 0x7f); + } + else + { + register_HDMA5 = 0xff; + gbHdmaOn = 0; + } + } + else + { + if (value & 0x80) + { + gbHdmaOn = 1; + register_HDMA5 = value & 0x7f; + if (gbLcdMode == 0) + gbDoHdma(); + } + else + { + // we need to take the time it takes to complete the transfer into + // account... according to GB DEV FAQs, the setup time is the same + // for single and double speed, but the actual transfer takes the + // same time // (is that a typo?) + switch (gbDMASpeedVersion) + { + case 1: // I believe this is more correct + // the lower 7 bits of FF55 specify the Transfer Length (divided by 16, minus 1) + // and we make gbDmaTicks twice as many cycles at double speed to make the transfer take the same time + if (gbSpeed) + gbDmaTicks = 16 * ((value & 0x7f) + 1); + else + gbDmaTicks = 8 * ((value & 0x7f) + 1); + break; + case 0: // here for backward compatibility + // I think this was a guess that approximates the above in most but not all games + if (gbSpeed) + gbDmaTicks = 231 + 16 * (value & 0x7f); + else + gbDmaTicks = 231 + 8 * (value & 0x7f); + break; + default: // shouldn't happen + //assert(0); + break; + } + gbCopyMemory(gbHdmaDestination, gbHdmaSource, gbHdmaBytes); + gbHdmaDestination += gbHdmaBytes; + gbHdmaSource += gbHdmaBytes; + + register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; + register_HDMA4 = gbHdmaDestination & 0xf0; + register_HDMA1 = (gbHdmaSource >> 8) & 0xff; + register_HDMA2 = gbHdmaSource & 0xf0; + } + } + return; + } + break; + } + + // BCPS + case 0x68: + { + if (gbCgbMode) + { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); + + gbMemory[0xff68] = value; + gbMemory[0xff69] = (paletteHiLo ? + (gbPalette[paletteIndex] >> 8) : + (gbPalette[paletteIndex] & 0x00ff)); + return; + } + break; + } + + // BCPD + case 0x69: + { + if (gbCgbMode) + { + int v = gbMemory[0xff68]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); + gbMemory[0xff69] = value; + gbPalette[paletteIndex] = (paletteHiLo ? + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + + if (gbMemory[0xff68] & 0x80) + { + int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f; + + gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index; + + gbMemory[0xff69] = (index & 1 ? + (gbPalette[index >> 1] >> 8) : + (gbPalette[index >> 1] & 0x00ff)); + } + return; + } + break; + } + + // OCPS + case 0x6a: + { + if (gbCgbMode) + { + int paletteIndex = (value & 0x3f) >> 1; + int paletteHiLo = (value & 0x01); + + paletteIndex += 32; + + gbMemory[0xff6a] = value; + gbMemory[0xff6b] = (paletteHiLo ? + (gbPalette[paletteIndex] >> 8) : + (gbPalette[paletteIndex] & 0x00ff)); + return; + } + break; + } + + // OCPD + case 0x6b: + { + if (gbCgbMode) + { + int v = gbMemory[0xff6a]; + int paletteIndex = (v & 0x3f) >> 1; + int paletteHiLo = (v & 0x01); + + paletteIndex += 32; + + gbMemory[0xff6b] = value; + gbPalette[paletteIndex] = (paletteHiLo ? + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; + if (gbMemory[0xff6a] & 0x80) + { + int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f; + + gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index; + + gbMemory[0xff6b] = (index & 1 ? + (gbPalette[(index >> 1) + 32] >> 8) : + (gbPalette[(index >> 1) + 32] & 0x00ff)); + } + return; + } + break; + } + + // SVBK + case 0x70: + { + if (gbCgbMode) + { + value = value & 7; + + int bank = value; + if (value == 0) + bank = 1; + + if (bank == gbWramBank) + return; + + int wramAddress = bank * 0x1000; + gbMemoryMap[0x0d] = &gbWram[wramAddress]; + + gbWramBank = bank; + register_SVBK = value; + return; + } + break; + } + + case 0xff: + { + register_IE = value; + register_IF &= value; + return; + } + } + + gbWriteMemoryQuick(address, value); +} + +u8 gbReadOpcode(register u16 address) +{ + if (gbCheatMap[address]) + return gbCheatRead(address); + + // the following fix does more than Echo RAM fix, anyway... + switch (gbEchoRAMFixOn ? (address >> 12) & 0x000f : address & 0xf000) + { + case 0x0a: + case 0x0b: + if (mapperReadRAM) + return mapperReadRAM(address); + break; + case 0x0f: + if (address > 0xff00) + { + switch (address & 0x00ff) + { + case 0x04: + return register_DIV; + case 0x05: + return register_TIMA; + case 0x06: + return register_TMA; + case 0x07: + return (0xf8 | register_TAC); + case 0x0f: + return (0xe0 | register_IF); + case 0x40: + return register_LCDC; + case 0x41: + return (0x80 | register_STAT); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + return register_LY; + case 0x45: + return register_LYC; + case 0x46: + return register_DMA; + case 0x4a: + return register_WY; + case 0x4b: + return register_WX; + case 0x4f: + return (0xfe | register_VBK); + case 0x51: + return register_HDMA1; + case 0x52: + return register_HDMA2; + case 0x53: + return register_HDMA3; + case 0x54: + return register_HDMA4; + case 0x55: + return register_HDMA5; + case 0x70: + return (0xf8 | register_SVBK); + case 0xff: + return register_IE; + } } - - if (address < 0xa000) + break; + } + return gbReadMemoryQuick(address); +} + +void gbWriteMemory(register u16 address, register u8 value) +{ + gbWriteMemoryWrapped(address, value); + CallRegisteredLuaMemHook(address, 1, value, LUAMEMHOOK_WRITE); +} + +u8 gbReadMemory(register u16 address) +{ + if (gbCheatMap[address]) + return gbCheatRead(address); + + if (address < 0xa000) + return gbReadMemoryQuick(address); + + if (address < 0xc000) + { +#ifndef FINAL_VERSION + if (memorydebug) { - gbWriteMemoryQuick(address, value); - return; + log("Memory register read %04x PC=%04x\n", + address, + PC.W); } - - if (address < 0xc000) - { -#ifndef FINAL_VERSION - if (memorydebug) - { - log("Memory register write %04x=%02x PC=%04x\n", - address, - value, - PC.W); - } #endif - if (mapper) - (*mapperRAM)(address, value); - return; - } - - if (address < 0xfe00) - { - gbWriteMemoryQuick(address, value); - return; - } - - if (address < 0xff00) - { - gbMemory[address] = value; - return; - } - - switch (address & 0x00ff) + if (mapperReadRAM) + return mapperReadRAM(address); + return gbReadMemoryQuick(address); + } + + if (address >= 0xff00) + { + switch (address & 0x00ff) { case 0x00: - { - gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | - (value & 0x30)); - if (gbSgbMode) - { - gbSgbDoBitTransfer(value); - } - - return; + { + if (gbSgbMode) + { + gbSgbReadingController |= 4; + gbSgbResetPacketState(); + } + + int b = gbMemory[0xff00]; + + if ((b & 0x30) == 0x20) + { + b &= 0xf0; + + int joy = 0; + if (gbSgbMode && gbSgbMultiplayer) + { + switch (gbSgbNextController) + { + case 0x0f: + joy = 0; + break; + case 0x0e: + joy = 1; + break; + case 0x0d: + joy = 2; + break; + case 0x0c: + joy = 3; + break; + default: + joy = 0; + } + } + int joystate = gbJoymask[joy]; + if (!(joystate & 128)) + b |= 0x08; + if (!(joystate & 64)) + b |= 0x04; + if (!(joystate & 32)) + b |= 0x02; + if (!(joystate & 16)) + b |= 0x01; + + gbMemory[0xff00] = b; + } + else if ((b & 0x30) == 0x10) + { + b &= 0xf0; + + int joy = 0; + if (gbSgbMode && gbSgbMultiplayer) + { + switch (gbSgbNextController) + { + case 0x0f: + joy = 0; + break; + case 0x0e: + joy = 1; + break; + case 0x0d: + joy = 2; + break; + case 0x0c: + joy = 3; + break; + default: + joy = 0; + } + } + int joystate = gbJoymask[joy]; + if (!(joystate & 8)) + b |= 0x08; + if (!(joystate & 4)) + b |= 0x04; + if (!(joystate & 2)) + b |= 0x02; + if (!(joystate & 1)) + b |= 0x01; + + gbMemory[0xff00] = b; + } + else + { + if (gbSgbMode && gbSgbMultiplayer) + { + gbMemory[0xff00] = 0xf0 | gbSgbNextController; + } + else + { + gbMemory[0xff00] = 0xff; + } + } + } + GBSystemCounters.lagged = false; + return gbMemory[0xff00]; + break; + case 0x01: + return gbMemory[0xff01]; + case 0x04: + return register_DIV; + case 0x05: + return register_TIMA; + case 0x06: + return register_TMA; + case 0x07: + return (0xf8 | register_TAC); + case 0x0f: + return (0xe0 | register_IF); + case 0x40: + return register_LCDC; + case 0x41: + return (0x80 | register_STAT); + case 0x42: + return register_SCY; + case 0x43: + return register_SCX; + case 0x44: + return register_LY; + case 0x45: + return register_LYC; + case 0x46: + return register_DMA; + case 0x4a: + return register_WY; + case 0x4b: + return register_WX; + case 0x4f: + return (0xfe | register_VBK); + case 0x51: + return register_HDMA1; + case 0x52: + return register_HDMA2; + case 0x53: + return register_HDMA3; + case 0x54: + return register_HDMA4; + case 0x55: + return register_HDMA5; + case 0x70: + return (0xf8 | register_SVBK); + case 0xff: + return register_IE; } - - case 0x01: - { - gbMemory[0xff01] = value; - return; - } - - // serial control - case 0x02: - { - gbSerialOn = (value & 0x80); - gbMemory[0xff02] = value; - if (gbSerialOn) - { - gbSerialTicks = GBSERIAL_CLOCK_TICKS; -#ifdef LINK_EMULATION - if (linkConnected) - { - if (value & 1) - { - linkSendByte(0x100 | gbMemory[0xFF01]); - Sleep(5); - } - } -#endif - } - - gbSerialBits = 0; - return; - } - - // DIV register resets on any write - case 0x04: - { - register_DIV = 0; - return; - } - case 0x05: - register_TIMA = value; - return; - - case 0x06: - register_TMA = value; - return; - - // TIMER control - case 0x07: - { - register_TAC = value; - - gbTimerOn = (value & 4); - gbTimerMode = value & 3; - // register_TIMA = register_TMA; - switch (gbTimerMode) - { - case 0: - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; - break; - case 1: - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS; - break; - case 2: - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS; - break; - case 3: - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS; - break; - } - return; - } - - case 0x0f: - { - register_IF = value; - gbInterrupt = value; - return; - } - - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - { - SOUND_EVENT(address, value); - return; - } - case 0x40: - { - int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); - - if (lcdChange) - { - if (value & 0x80) - { - gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS; - gbLcdMode = 0; - register_STAT &= 0xfc; - register_LY = 0x00; - // FIXME: horrible workaround - if (gbNullInputHackTempEnabled && !useOldFrameTiming) - memcpy(gbJoymask, s_gbJoymask, sizeof(gbJoymask)); - } - else - { - gbLcdTicks = 0; - gbLcdMode = 0; - register_STAT &= 0xfc; - register_LY = 0x00; - // FIXME: horrible workaround - memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); - if (gbNullInputHackTempEnabled && !useOldFrameTiming) - memset(gbJoymask, 0, sizeof(gbJoymask)); - } - // compareLYToLYC(); - } - // don't draw the window if it was not enabled and not being drawn before - if (!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 && - register_LY > register_WY) - gbWindowLine = 144; - - register_LCDC = value; - - return; - } - - // STAT - case 0x41: - { - //register_STAT = (register_STAT & 0x87) | - // (value & 0x7c); - register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? - // GB bug from Devrs FAQ - if (!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2) - gbInterrupt |= 2; - return; - } - - // SCY - case 0x42: - { - register_SCY = value; - return; - } - - // SCX - case 0x43: - { - register_SCX = value; - return; - } - - // LY - case 0x44: - { - // read only - return; - } - - // LYC - case 0x45: - { - register_LYC = value; - if ((register_LCDC & 0x80)) - { - gbCompareLYToLYC(); - } - return; - } - - // DMA! - case 0x46: - { - int source = value * 0x0100; - - gbCopyMemory(0xfe00, - source, - 0xa0); - register_DMA = value; - return; - } - - // BGP - case 0x47: - { - gbBgp[0] = value & 0x03; - gbBgp[1] = (value & 0x0c) >> 2; - gbBgp[2] = (value & 0x30) >> 4; - gbBgp[3] = (value & 0xc0) >> 6; - break; - } - - // OBP0 - case 0x48: - { - gbObp0[0] = value & 0x03; - gbObp0[1] = (value & 0x0c) >> 2; - gbObp0[2] = (value & 0x30) >> 4; - gbObp0[3] = (value & 0xc0) >> 6; - break; - } - - // OBP1 - case 0x49: - { - gbObp1[0] = value & 0x03; - gbObp1[1] = (value & 0x0c) >> 2; - gbObp1[2] = (value & 0x30) >> 4; - gbObp1[3] = (value & 0xc0) >> 6; - break; - } - - case 0x4a: - register_WY = value; - return; - - case 0x4b: - register_WX = value; - return; - - // KEY1 - case 0x4d: - { - if (gbCgbMode) - { - gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1); - return; - } - break; - } - - // VBK - case 0x4f: - { - if (gbCgbMode) - { - value = value & 1; - if (value == gbVramBank) - return; - - int vramAddress = value * 0x2000; - gbMemoryMap[0x08] = &gbVram[vramAddress]; - gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; - - gbVramBank = value; - register_VBK = value; - } - return; - break; - } - - // HDMA1 - case 0x51: - { - if (gbCgbMode) - { - if (value > 0x7f && value < 0xa0) - value = 0; - - gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0); - - register_HDMA1 = value; - return; - } - break; - } - - // HDMA2 - case 0x52: - { - if (gbCgbMode) - { - value = value & 0xf0; - - gbHdmaSource = (register_HDMA1 << 8) | (value); - - register_HDMA2 = value; - return; - } - break; - } - - // HDMA3 - case 0x53: - { - if (gbCgbMode) - { - value = value & 0x1f; - gbHdmaDestination = (value << 8) | (register_HDMA4 & 0xf0); - gbHdmaDestination += 0x8000; - register_HDMA3 = value; - return; - } - break; - } - - // HDMA4 - case 0x54: - { - if (gbCgbMode) - { - value = value & 0xf0; - gbHdmaDestination = ((register_HDMA3 & 0x1f) << 8) | value; - gbHdmaDestination += 0x8000; - register_HDMA4 = value; - return; - } - break; - } - - // HDMA5 - case 0x55: - { - if (gbCgbMode) - { - gbHdmaBytes = 16 + (value & 0x7f) * 16; - if (gbHdmaOn) - { - if (value & 0x80) - { - register_HDMA5 = (value & 0x7f); - } - else - { - register_HDMA5 = 0xff; - gbHdmaOn = 0; - } - } - else - { - if (value & 0x80) - { - gbHdmaOn = 1; - register_HDMA5 = value & 0x7f; - if (gbLcdMode == 0) - gbDoHdma(); - } - else - { - // we need to take the time it takes to complete the transfer into - // account... according to GB DEV FAQs, the setup time is the same - // for single and double speed, but the actual transfer takes the - // same time // (is that a typo?) - switch (gbDMASpeedVersion) - { - case 1: // I believe this is more correct - // the lower 7 bits of FF55 specify the Transfer Length (divided by 16, minus 1) - // and we make gbDmaTicks twice as many cycles at double speed to make the transfer take the same time - if (gbSpeed) - gbDmaTicks = 16 * ((value & 0x7f) + 1); - else - gbDmaTicks = 8 * ((value & 0x7f) + 1); - break; - case 0: // here for backward compatibility - // I think this was a guess that approximates the above in most but not all games - if (gbSpeed) - gbDmaTicks = 231 + 16 * (value & 0x7f); - else - gbDmaTicks = 231 + 8 * (value & 0x7f); - break; - default: // shouldn't happen - //assert(0); - break; - } - gbCopyMemory(gbHdmaDestination, gbHdmaSource, gbHdmaBytes); - gbHdmaDestination += gbHdmaBytes; - gbHdmaSource += gbHdmaBytes; - - register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; - register_HDMA4 = gbHdmaDestination & 0xf0; - register_HDMA1 = (gbHdmaSource >> 8) & 0xff; - register_HDMA2 = gbHdmaSource & 0xf0; - } - } - return; - } - break; - } - - // BCPS - case 0x68: - { - if (gbCgbMode) - { - int paletteIndex = (value & 0x3f) >> 1; - int paletteHiLo = (value & 0x01); - - gbMemory[0xff68] = value; - gbMemory[0xff69] = (paletteHiLo ? - (gbPalette[paletteIndex] >> 8) : - (gbPalette[paletteIndex] & 0x00ff)); - return; - } - break; - } - - // BCPD - case 0x69: - { - if (gbCgbMode) - { - int v = gbMemory[0xff68]; - int paletteIndex = (v & 0x3f) >> 1; - int paletteHiLo = (v & 0x01); - gbMemory[0xff69] = value; - gbPalette[paletteIndex] = (paletteHiLo ? - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; - - if (gbMemory[0xff68] & 0x80) - { - int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f; - - gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index; - - gbMemory[0xff69] = (index & 1 ? - (gbPalette[index >> 1] >> 8) : - (gbPalette[index >> 1] & 0x00ff)); - } - return; - } - break; - } - - // OCPS - case 0x6a: - { - if (gbCgbMode) - { - int paletteIndex = (value & 0x3f) >> 1; - int paletteHiLo = (value & 0x01); - - paletteIndex += 32; - - gbMemory[0xff6a] = value; - gbMemory[0xff6b] = (paletteHiLo ? - (gbPalette[paletteIndex] >> 8) : - (gbPalette[paletteIndex] & 0x00ff)); - return; - } - break; - } - - // OCPD - case 0x6b: - { - if (gbCgbMode) - { - int v = gbMemory[0xff6a]; - int paletteIndex = (v & 0x3f) >> 1; - int paletteHiLo = (v & 0x01); - - paletteIndex += 32; - - gbMemory[0xff6b] = value; - gbPalette[paletteIndex] = (paletteHiLo ? - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; - if (gbMemory[0xff6a] & 0x80) - { - int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f; - - gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index; - - gbMemory[0xff6b] = (index & 1 ? - (gbPalette[(index >> 1) + 32] >> 8) : - (gbPalette[(index >> 1) + 32] & 0x00ff)); - } - return; - } - break; - } - - // SVBK - case 0x70: - { - if (gbCgbMode) - { - value = value & 7; - - int bank = value; - if (value == 0) - bank = 1; - - if (bank == gbWramBank) - return; - - int wramAddress = bank * 0x1000; - gbMemoryMap[0x0d] = &gbWram[wramAddress]; - - gbWramBank = bank; - register_SVBK = value; - return; - } - break; - } - - case 0xff: - { - register_IE = value; - register_IF &= value; - return; - } - } - - gbWriteMemoryQuick(address, value); -} - -u8 gbReadOpcode(register u16 address) -{ - if (gbCheatMap[address]) - return gbCheatRead(address); - - // the following fix does more than Echo RAM fix, anyway... - switch (gbEchoRAMFixOn ? (address >> 12) & 0x000f : address & 0xf000) - { - case 0x0a: - case 0x0b: - if (mapperReadRAM) - return mapperReadRAM(address); - break; - case 0x0f: - if (address > 0xff00) - { - switch (address & 0x00ff) - { - case 0x04: - return register_DIV; - case 0x05: - return register_TIMA; - case 0x06: - return register_TMA; - case 0x07: - return (0xf8 | register_TAC); - case 0x0f: - return (0xe0 | register_IF); - case 0x40: - return register_LCDC; - case 0x41: - return (0x80 | register_STAT); - case 0x42: - return register_SCY; - case 0x43: - return register_SCX; - case 0x44: - return register_LY; - case 0x45: - return register_LYC; - case 0x46: - return register_DMA; - case 0x4a: - return register_WY; - case 0x4b: - return register_WX; - case 0x4f: - return (0xfe | register_VBK); - case 0x51: - return register_HDMA1; - case 0x52: - return register_HDMA2; - case 0x53: - return register_HDMA3; - case 0x54: - return register_HDMA4; - case 0x55: - return register_HDMA5; - case 0x70: - return (0xf8 | register_SVBK); - case 0xff: - return register_IE; - } - } - break; - } - return gbReadMemoryQuick(address); -} - -void gbWriteMemory(register u16 address, register u8 value) -{ - gbWriteMemoryWrapped(address, value); - CallRegisteredLuaMemHook(address, 1, value, LUAMEMHOOK_WRITE); -} - -u8 gbReadMemory(register u16 address) -{ - if (gbCheatMap[address]) - return gbCheatRead(address); - - if (address < 0xa000) - return gbReadMemoryQuick(address); - - if (address < 0xc000) - { -#ifndef FINAL_VERSION - if (memorydebug) - { - log("Memory register read %04x PC=%04x\n", - address, - PC.W); - } -#endif - - if (mapperReadRAM) - return mapperReadRAM(address); - return gbReadMemoryQuick(address); - } - - if (address >= 0xff00) - { - switch (address & 0x00ff) - { - case 0x00: - { - if (gbSgbMode) - { - gbSgbReadingController |= 4; - gbSgbResetPacketState(); - } - - int b = gbMemory[0xff00]; - - if ((b & 0x30) == 0x20) - { - b &= 0xf0; - - int joy = 0; - if (gbSgbMode && gbSgbMultiplayer) - { - switch (gbSgbNextController) - { - case 0x0f: - joy = 0; - break; - case 0x0e: - joy = 1; - break; - case 0x0d: - joy = 2; - break; - case 0x0c: - joy = 3; - break; - default: - joy = 0; - } - } - int joystate = gbJoymask[joy]; - if (!(joystate & 128)) - b |= 0x08; - if (!(joystate & 64)) - b |= 0x04; - if (!(joystate & 32)) - b |= 0x02; - if (!(joystate & 16)) - b |= 0x01; - - gbMemory[0xff00] = b; - } - else if ((b & 0x30) == 0x10) - { - b &= 0xf0; - - int joy = 0; - if (gbSgbMode && gbSgbMultiplayer) - { - switch (gbSgbNextController) - { - case 0x0f: - joy = 0; - break; - case 0x0e: - joy = 1; - break; - case 0x0d: - joy = 2; - break; - case 0x0c: - joy = 3; - break; - default: - joy = 0; - } - } - int joystate = gbJoymask[joy]; - if (!(joystate & 8)) - b |= 0x08; - if (!(joystate & 4)) - b |= 0x04; - if (!(joystate & 2)) - b |= 0x02; - if (!(joystate & 1)) - b |= 0x01; - - gbMemory[0xff00] = b; - } - else - { - if (gbSgbMode && gbSgbMultiplayer) - { - gbMemory[0xff00] = 0xf0 | gbSgbNextController; - } - else - { - gbMemory[0xff00] = 0xff; - } - } - } - GBSystemCounters.lagged = false; - return gbMemory[0xff00]; - break; - case 0x01: - return gbMemory[0xff01]; - case 0x04: - return register_DIV; - case 0x05: - return register_TIMA; - case 0x06: - return register_TMA; - case 0x07: - return (0xf8 | register_TAC); - case 0x0f: - return (0xe0 | register_IF); - case 0x40: - return register_LCDC; - case 0x41: - return (0x80 | register_STAT); - case 0x42: - return register_SCY; - case 0x43: - return register_SCX; - case 0x44: - return register_LY; - case 0x45: - return register_LYC; - case 0x46: - return register_DMA; - case 0x4a: - return register_WY; - case 0x4b: - return register_WX; - case 0x4f: - return (0xfe | register_VBK); - case 0x51: - return register_HDMA1; - case 0x52: - return register_HDMA2; - case 0x53: - return register_HDMA3; - case 0x54: - return register_HDMA4; - case 0x55: - return register_HDMA5; - case 0x70: - return (0xf8 | register_SVBK); - case 0xff: - return register_IE; - } - } - - return gbReadMemoryQuick(address); + } + + return gbReadMemoryQuick(address); } void gbVblank_interrupt() { - if (IFF & 0x80) - { - PC.W++; - IFF &= 0x7f; - } - gbInterrupt &= 0xfe; - - IFF &= 0x7e; - register_IF &= 0xfe; - - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - PC.W = 0x40; + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + gbInterrupt &= 0xfe; + + IFF &= 0x7e; + register_IF &= 0xfe; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + PC.W = 0x40; } void gbLcd_interrupt() { - if (IFF & 0x80) - { - PC.W++; - IFF &= 0x7f; - } - gbInterrupt &= 0xfd; - IFF &= 0x7e; - register_IF &= 0xfd; - - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - - PC.W = 0x48; + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + gbInterrupt &= 0xfd; + IFF &= 0x7e; + register_IF &= 0xfd; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x48; } void gbTimer_interrupt() { - if (IFF & 0x80) - { - PC.W++; - IFF &= 0x7f; - } - IFF &= 0x7e; - gbInterrupt &= 0xfb; - register_IF &= 0xfb; - - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - - PC.W = 0x50; + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + IFF &= 0x7e; + gbInterrupt &= 0xfb; + register_IF &= 0xfb; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x50; } void gbSerial_interrupt() { - if (IFF & 0x80) - { - PC.W++; - IFF &= 0x7f; - } - IFF &= 0x7e; - gbInterrupt &= 0xf7; - register_IF &= 0xf7; - - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - - PC.W = 0x58; + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + IFF &= 0x7e; + gbInterrupt &= 0xf7; + register_IF &= 0xf7; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x58; } void gbJoypad_interrupt() { - if (IFF & 0x80) - { - PC.W++; - IFF &= 0x7f; - } - IFF &= 0x7e; - gbInterrupt &= 0xef; - register_IF &= 0xef; - - gbWriteMemory(--SP.W, PC.B.B1); - gbWriteMemory(--SP.W, PC.B.B0); - - PC.W = 0x60; + if (IFF & 0x80) + { + PC.W++; + IFF &= 0x7f; + } + IFF &= 0x7e; + gbInterrupt &= 0xef; + register_IF &= 0xef; + + gbWriteMemory(--SP.W, PC.B.B1); + gbWriteMemory(--SP.W, PC.B.B0); + + PC.W = 0x60; } void gbSpeedSwitch() { - if (gbSpeed == 0) - { - gbSpeed = 1; - GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; //127; //51 * 2; - GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; - GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; //52; //20 * 2; - GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; //99; //43 * 2; - GBDIV_CLOCK_TICKS = 64 * 2; - GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; - GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2; - GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2; - GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2; - GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2; - GBSERIAL_CLOCK_TICKS = 128 * 2; - gbDivTicks *= 2; - gbLcdTicks *= 2; - gbLcdLYIncrementTicks *= 2; - // timerTicks *= 2; - // timerClockTicks *= 2; - gbSerialTicks *= 2; - SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS * 2; - soundTicks *= 2; - // synchronizeTicks *= 2; - // SYNCHRONIZE_CLOCK_TICKS *= 2; - } - else - { - gbSpeed = 0; - GBLCD_MODE_0_CLOCK_TICKS = 51; - GBLCD_MODE_1_CLOCK_TICKS = 1140; - GBLCD_MODE_2_CLOCK_TICKS = 20; - GBLCD_MODE_3_CLOCK_TICKS = 43; - GBDIV_CLOCK_TICKS = 64; - GBLY_INCREMENT_CLOCK_TICKS = 114; - GBTIMER_MODE_0_CLOCK_TICKS = 256; - GBTIMER_MODE_1_CLOCK_TICKS = 4; - GBTIMER_MODE_2_CLOCK_TICKS = 16; - GBTIMER_MODE_3_CLOCK_TICKS = 64; - GBSERIAL_CLOCK_TICKS = 128; - gbDivTicks /= 2; - gbLcdTicks /= 2; - gbLcdLYIncrementTicks /= 2; - // timerTicks /= 2; - // timerClockTicks /= 2; - gbSerialTicks /= 2; - SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS; - soundTicks /= 2; - // synchronizeTicks /= 2; - // SYNCHRONIZE_CLOCK_TICKS /= 2; - } + if (gbSpeed == 0) + { + gbSpeed = 1; + GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; //127; //51 * 2; + GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; + GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; //52; //20 * 2; + GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; //99; //43 * 2; + GBDIV_CLOCK_TICKS = 64 * 2; + GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; + GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2; + GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2; + GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2; + GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2; + GBSERIAL_CLOCK_TICKS = 128 * 2; + gbDivTicks *= 2; + gbLcdTicks *= 2; + gbLcdLYIncrementTicks *= 2; + // timerTicks *= 2; + // timerClockTicks *= 2; + gbSerialTicks *= 2; + SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS * 2; + soundTicks *= 2; + // synchronizeTicks *= 2; + // SYNCHRONIZE_CLOCK_TICKS *= 2; + } + else + { + gbSpeed = 0; + GBLCD_MODE_0_CLOCK_TICKS = 51; + GBLCD_MODE_1_CLOCK_TICKS = 1140; + GBLCD_MODE_2_CLOCK_TICKS = 20; + GBLCD_MODE_3_CLOCK_TICKS = 43; + GBDIV_CLOCK_TICKS = 64; + GBLY_INCREMENT_CLOCK_TICKS = 114; + GBTIMER_MODE_0_CLOCK_TICKS = 256; + GBTIMER_MODE_1_CLOCK_TICKS = 4; + GBTIMER_MODE_2_CLOCK_TICKS = 16; + GBTIMER_MODE_3_CLOCK_TICKS = 64; + GBSERIAL_CLOCK_TICKS = 128; + gbDivTicks /= 2; + gbLcdTicks /= 2; + gbLcdLYIncrementTicks /= 2; + // timerTicks /= 2; + // timerClockTicks /= 2; + gbSerialTicks /= 2; + SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS; + soundTicks /= 2; + // synchronizeTicks /= 2; + // SYNCHRONIZE_CLOCK_TICKS /= 2; + } } void gbGetHardwareType() { - gbCgbMode = 0; - if (gbRom[0x143] & 0x80) + gbCgbMode = 0; + if (gbRom[0x143] & 0x80) + { + if (gbEmulatorType == 0 || + gbEmulatorType == 1 || + gbEmulatorType == 4 || + gbEmulatorType == 5 || + (gbRom[0x146] != 0x03 && (gbEmulatorType == 2))) { - if (gbEmulatorType == 0 || - gbEmulatorType == 1 || - gbEmulatorType == 4 || - gbEmulatorType == 5 || - (gbRom[0x146] != 0x03 && (gbEmulatorType == 2))) - { - gbCgbMode = 1; - } + gbCgbMode = 1; } - - if (gbSgbMode == 2) - { - gbSgbMode = 0; - return; - } - - gbSgbMode = 0; - if (gbRom[0x146] == 0x03) - { - if (gbEmulatorType == 0 || - gbEmulatorType == 2 || - gbEmulatorType == 5 || - (!(gbRom[0x143] & 0x80) && (gbEmulatorType == 1 || gbEmulatorType == 4))) - gbSgbMode = 1; - } + } + + if (gbSgbMode == 2) + { + gbSgbMode = 0; + return; + } + + gbSgbMode = 0; + if (gbRom[0x146] == 0x03) + { + if (gbEmulatorType == 0 || + gbEmulatorType == 2 || + gbEmulatorType == 5 || + (!(gbRom[0x143] & 0x80) && (gbEmulatorType == 1 || gbEmulatorType == 4))) + gbSgbMode = 1; + } } void gbReset(bool userReset) { - // movie must be closed while opening/creating a movie - if (userReset && VBAMovieRecording()) + // movie must be closed while opening/creating a movie + if (userReset && VBAMovieRecording()) + { + VBAMovieSignalReset(); + return; + } + + if (!VBAMovieActive()) + { + GBSystemCounters.frameCount = 0; + GBSystemCounters.lagCount = 0; + GBSystemCounters.extraCount = 0; + GBSystemCounters.lagged = true; + GBSystemCounters.laggedLast = true; + } + + SP.W = 0xfffe; + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; + PC.W = 0x0100; + IFF = 0; + gbInterrupt = 1; + gbInterruptWait = 0; + + register_DIV = 0; + register_TIMA = 0; + register_TMA = 0; + register_TAC = 0; + register_IF = 1; + register_LCDC = 0x91; + register_STAT = 0; + register_SCY = 0; + register_SCX = 0; + register_LY = 0; + register_LYC = 0; + register_DMA = 0; + register_WY = 0; + register_WX = 0; + register_VBK = 0; + register_HDMA1 = 0; + register_HDMA2 = 0; + register_HDMA3 = 0; + register_HDMA4 = 0; + register_HDMA5 = 0; + register_SVBK = 0; + register_IE = 0; + + gbGetHardwareType(); + if (gbCgbMode) + { + if (!gbVram) + gbVram = (u8 *)malloc(0x4000 + 4); + if (!gbWram) + gbWram = (u8 *)malloc(0x8000 + 4); + memset(gbVram, 0, 0x4000 + 4); + memset(gbWram, 0, 0x8000 + 4); + } + else + { + if (gbVram) { - VBAMovieSignalReset(); - return; + free(gbVram); + gbVram = NULL; } - - if (!VBAMovieActive()) + if (gbWram) { - GBSystemCounters.frameCount = 0; - GBSystemCounters.lagCount = 0; - GBSystemCounters.extraCount = 0; - GBSystemCounters.lagged = true; - GBSystemCounters.laggedLast = true; + free(gbWram); + gbWram = NULL; } - - SP.W = 0xfffe; - AF.W = 0x01b0; - BC.W = 0x0013; - DE.W = 0x00d8; - HL.W = 0x014d; - PC.W = 0x0100; - IFF = 0; - gbInterrupt = 1; - gbInterruptWait = 0; - - register_DIV = 0; - register_TIMA = 0; - register_TMA = 0; - register_TAC = 0; - register_IF = 1; - register_LCDC = 0x91; - register_STAT = 0; - register_SCY = 0; - register_SCX = 0; - register_LY = 0; - register_LYC = 0; - register_DMA = 0; - register_WY = 0; - register_WX = 0; - register_VBK = 0; - register_HDMA1 = 0; - register_HDMA2 = 0; - register_HDMA3 = 0; - register_HDMA4 = 0; - register_HDMA5 = 0; - register_SVBK = 0; - register_IE = 0; - - gbGetHardwareType(); - if (gbCgbMode) + } + + // clean LineBuffer + if (gbLineBuffer) + memset(gbLineBuffer, 0, 160 * sizeof(u16)); + // clean Pix + if (pix) + memset(pix, 0, 4 * 257 * 226); + + if (gbCgbMode) + { + if (gbSgbMode) { - if (!gbVram) - gbVram = (u8 *)malloc(0x4000 + 4); - if (!gbWram) - gbWram = (u8 *)malloc(0x8000 + 4); - memset(gbVram, 0, 0x4000 + 4); - memset(gbWram, 0, 0x8000 + 4); + if (gbEmulatorType == 5) + AF.W = 0xffb0; + else + AF.W = 0x01b0; + BC.W = 0x0013; + DE.W = 0x00d8; + HL.W = 0x014d; } - else + else { - if (gbVram) - { - free(gbVram); - gbVram = NULL; - } - if (gbWram) - { - free(gbWram); - gbWram = NULL; - } + AF.W = 0x11b0; + BC.W = 0x0000; + DE.W = 0xff56; + HL.W = 0x000d; } - - // clean LineBuffer - if (gbLineBuffer) - memset(gbLineBuffer, 0, 160 * sizeof(u16)); - // clean Pix - if (pix) - memset(pix, 0, 4 * 257 * 226); - - if (gbCgbMode) - { - if (gbSgbMode) - { - if (gbEmulatorType == 5) - AF.W = 0xffb0; - else - AF.W = 0x01b0; - BC.W = 0x0013; - DE.W = 0x00d8; - HL.W = 0x014d; - } - else - { - AF.W = 0x11b0; - BC.W = 0x0000; - DE.W = 0xff56; - HL.W = 0x000d; - } - if (gbEmulatorType == 4) - BC.B.B1 |= 0x01; - - register_HDMA5 = 0xff; - gbMemory[0xff68] = 0xc0; - gbMemory[0xff6a] = 0xc0; - - for (int i = 0; i < 64; i++) - gbPalette[i] = 0x7fff; - } - else - { - for (int i = 0; i < 8; i++) - gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; - } - - if (gbSpeed) - { - gbSpeedSwitch(); - gbMemory[0xff4d] = 0; - } - - gbDivTicks = GBDIV_CLOCK_TICKS; - gbLcdMode = 2; - gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS; - gbLcdLYIncrementTicks = 0; - gbTimerTicks = 0; - gbTimerClockTicks = 0; - gbSerialTicks = 0; - gbSerialBits = 0; - gbSerialOn = 0; - gbWindowLine = -1; - gbTimerOn = 0; - gbTimerMode = 0; - // gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; - gbSpeed = 0; - gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; - - // FIXME: horrible kludge - memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); - - if (gbCgbMode) - { - gbSpeed = 0; - gbHdmaOn = 0; - gbHdmaSource = 0x0000; - gbHdmaDestination = 0x8000; - gbVramBank = 0; - gbWramBank = 1; - register_LY = 0x90; - gbLcdMode = 1; - } - - if (gbSgbMode) - { - gbSgbReset(); - } - - for (int i = 0; i < 4; i++) - gbBgp[i] = gbObp0[i] = gbObp1[i] = i; - - memset(&gbDataMBC1, 0, sizeof(gbDataMBC1)); - gbDataMBC1.mapperROMBank = 1; - - gbDataMBC2.mapperRAMEnable = 0; - gbDataMBC2.mapperROMBank = 1; - - memset(&gbDataMBC3, 0, 6 * sizeof(int32)); - gbDataMBC3.mapperROMBank = 1; - - memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); - gbDataMBC5.mapperROMBank = 1; - switch (gbRom[0x147]) - { - case 0x1c: - case 0x1d: - case 0x1e: - gbDataMBC5.isRumbleCartridge = 1; - } - - memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); - gbDataHuC1.mapperROMBank = 1; - - memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); - gbDataHuC3.mapperROMBank = 1; - - gbMemoryMap[0x00] = &gbRom[0x0000]; - gbMemoryMap[0x01] = &gbRom[0x1000]; - gbMemoryMap[0x02] = &gbRom[0x2000]; - gbMemoryMap[0x03] = &gbRom[0x3000]; - gbMemoryMap[0x04] = &gbRom[0x4000]; - gbMemoryMap[0x05] = &gbRom[0x5000]; - gbMemoryMap[0x06] = &gbRom[0x6000]; - gbMemoryMap[0x07] = &gbRom[0x7000]; - if (gbCgbMode) - { - gbMemoryMap[0x08] = &gbVram[0x0000]; - gbMemoryMap[0x09] = &gbVram[0x1000]; - gbMemoryMap[0x0a] = &gbMemory[0xa000]; - gbMemoryMap[0x0b] = &gbMemory[0xb000]; - gbMemoryMap[0x0c] = &gbMemory[0xc000]; - gbMemoryMap[0x0d] = &gbWram[0x1000]; - gbMemoryMap[0x0e] = &gbMemory[0xe000]; - gbMemoryMap[0x0f] = &gbMemory[0xf000]; - } - else - { - gbMemoryMap[0x08] = &gbMemory[0x8000]; - gbMemoryMap[0x09] = &gbMemory[0x9000]; - gbMemoryMap[0x0a] = &gbMemory[0xa000]; - gbMemoryMap[0x0b] = &gbMemory[0xb000]; - gbMemoryMap[0x0c] = &gbMemory[0xc000]; - gbMemoryMap[0x0d] = &gbMemory[0xd000]; - gbMemoryMap[0x0e] = &gbMemory[0xe000]; - gbMemoryMap[0x0f] = &gbMemory[0xf000]; - } - - if (gbRam) - { - gbMemoryMap[0x0a] = &gbRam[0x0000]; - gbMemoryMap[0x0b] = &gbRam[0x1000]; - } - - gbSoundReset(); - - systemResetSensor(); - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - gbLastTime = systemGetClock(); - gbFrameCount = 0; - - systemRefreshScreen(); + if (gbEmulatorType == 4) + BC.B.B1 |= 0x01; + + register_HDMA5 = 0xff; + gbMemory[0xff68] = 0xc0; + gbMemory[0xff6a] = 0xc0; + + for (int i = 0; i < 64; i++) + gbPalette[i] = 0x7fff; + } + else + { + for (int i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; + } + + if (gbSpeed) + { + gbSpeedSwitch(); + gbMemory[0xff4d] = 0; + } + + gbDivTicks = GBDIV_CLOCK_TICKS; + gbLcdMode = 2; + gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS; + gbLcdLYIncrementTicks = 0; + gbTimerTicks = 0; + gbTimerClockTicks = 0; + gbSerialTicks = 0; + gbSerialBits = 0; + gbSerialOn = 0; + gbWindowLine = -1; + gbTimerOn = 0; + gbTimerMode = 0; + // gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; + gbSpeed = 0; + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; + + // FIXME: horrible kludge + memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); + + if (gbCgbMode) + { + gbSpeed = 0; + gbHdmaOn = 0; + gbHdmaSource = 0x0000; + gbHdmaDestination = 0x8000; + gbVramBank = 0; + gbWramBank = 1; + register_LY = 0x90; + gbLcdMode = 1; + } + + if (gbSgbMode) + { + gbSgbReset(); + } + + for (int i = 0; i < 4; i++) + gbBgp[i] = gbObp0[i] = gbObp1[i] = i; + + memset(&gbDataMBC1, 0, sizeof(gbDataMBC1)); + gbDataMBC1.mapperROMBank = 1; + + gbDataMBC2.mapperRAMEnable = 0; + gbDataMBC2.mapperROMBank = 1; + + memset(&gbDataMBC3, 0, 6 * sizeof(int32)); + gbDataMBC3.mapperROMBank = 1; + + memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); + gbDataMBC5.mapperROMBank = 1; + switch (gbRom[0x147]) + { + case 0x1c: + case 0x1d: + case 0x1e: + gbDataMBC5.isRumbleCartridge = 1; + } + + memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); + gbDataHuC1.mapperROMBank = 1; + + memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); + gbDataHuC3.mapperROMBank = 1; + + gbMemoryMap[0x00] = &gbRom[0x0000]; + gbMemoryMap[0x01] = &gbRom[0x1000]; + gbMemoryMap[0x02] = &gbRom[0x2000]; + gbMemoryMap[0x03] = &gbRom[0x3000]; + gbMemoryMap[0x04] = &gbRom[0x4000]; + gbMemoryMap[0x05] = &gbRom[0x5000]; + gbMemoryMap[0x06] = &gbRom[0x6000]; + gbMemoryMap[0x07] = &gbRom[0x7000]; + if (gbCgbMode) + { + gbMemoryMap[0x08] = &gbVram[0x0000]; + gbMemoryMap[0x09] = &gbVram[0x1000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbWram[0x1000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + } + else + { + gbMemoryMap[0x08] = &gbMemory[0x8000]; + gbMemoryMap[0x09] = &gbMemory[0x9000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbMemory[0xd000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + } + + if (gbRam) + { + gbMemoryMap[0x0a] = &gbRam[0x0000]; + gbMemoryMap[0x0b] = &gbRam[0x1000]; + } + + gbSoundReset(); + + systemResetSensor(); + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + gbLastTime = systemGetClock(); + gbFrameCount = 0; + + systemRefreshScreen(); } void gbWriteSaveMBC1(const char *name) { - FILE *gzFile = fopen(name, "wb"); - - if (gzFile == NULL) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - gbRamSize, - gzFile); - - fclose(gzFile); + FILE *gzFile = fopen(name, "wb"); + + if (gzFile == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + gbRamSize, + gzFile); + + fclose(gzFile); } void gbWriteSaveMBC2(const char *name) { - FILE *file = fopen(name, "wb"); - - if (file == NULL) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(&gbMemory[0xa000], - 1, - 256, - file); - - fclose(file); + FILE *file = fopen(name, "wb"); + + if (file == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(&gbMemory[0xa000], + 1, + 256, + file); + + fclose(file); } void gbWriteSaveMBC3(const char *name, bool extendedSave) { - FILE *gzFile = fopen(name, "wb"); - - if (gzFile == NULL) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - gbRamSize, - gzFile); - - if (extendedSave) - { - //assert(sizeof(time_t) == 4); - fwrite(&gbDataMBC3.mapperSeconds, - 1, - 10 * sizeof(int32) + /*sizeof(time_t)*/4, - gzFile); - } - - fclose(gzFile); + FILE *gzFile = fopen(name, "wb"); + + if (gzFile == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + gbRamSize, + gzFile); + + if (extendedSave) + { + //assert(sizeof(time_t) == 4); + fwrite(&gbDataMBC3.mapperSeconds, + 1, + 10 * sizeof(int32) + /*sizeof(time_t)*/4, + gzFile); + } + + fclose(gzFile); } void gbWriteSaveMBC5(const char *name) { - FILE *gzFile = fopen(name, "wb"); - - if (gzFile == NULL) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(gbRam, - 1, - gbRamSize, - gzFile); - - fclose(gzFile); + FILE *gzFile = fopen(name, "wb"); + + if (gzFile == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(gbRam, + 1, + gbRamSize, + gzFile); + + fclose(gzFile); } void gbWriteSaveMBC7(const char *name) { - FILE *file = fopen(name, "wb"); - - if (file == NULL) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); - return; - } - - fwrite(&gbMemory[0xa000], - 1, - 256, - file); - - fclose(file); + FILE *file = fopen(name, "wb"); + + if (file == NULL) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); + return; + } + + fwrite(&gbMemory[0xa000], + 1, + 256, + file); + + fclose(file); } bool gbReadSaveMBC1(const char *name) { - gzFile gzFile = gzopen(name, "rb"); - - if (gzFile == NULL) - { - return false; - } - - int read = gzread(gzFile, - gbRam, - gbRamSize); - - if (read != gbRamSize) - { - systemMessage(MSG_FAILED_TO_READ_SGM, N_("Failed to read complete save game %s (%d)"), name, read); - gzclose(gzFile); - return false; - } - - gzclose(gzFile); - return true; + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + int read = gzread(gzFile, + gbRam, + gbRamSize); + + if (read != gbRamSize) + { + systemMessage(MSG_FAILED_TO_READ_SGM, N_("Failed to read complete save game %s (%d)"), name, read); + gzclose(gzFile); + return false; + } + + gzclose(gzFile); + return true; } bool gbReadSaveMBC2(const char *name) { - FILE *file = fopen(name, "rb"); - - if (file == NULL) - { - return false; - } - - int read = fread(&gbMemory[0xa000], - 1, - 256, - file); - - if (read != 256) - { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Failed to read complete save game %s (%d)"), name, read); - fclose(file); - return false; - } - - fclose(file); - return true; + FILE *file = fopen(name, "rb"); + + if (file == NULL) + { + return false; + } + + int read = fread(&gbMemory[0xa000], + 1, + 256, + file); + + if (read != 256) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + fclose(file); + return false; + } + + fclose(file); + return true; } bool gbReadSaveMBC3(const char *name) { - gzFile gzFile = gzopen(name, "rb"); - - if (gzFile == NULL) + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + int read = gzread(gzFile, + gbRam, + gbRamSize); + + bool res = true; + + if (read != gbRamSize) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + } + else + { + //assert(sizeof(time_t) == 4); + read = gzread(gzFile, + &gbDataMBC3.mapperSeconds, + sizeof(int32) * 10 + /*sizeof(time_t)*/4); + + if (read != (sizeof(int32) * 10 + /*sizeof(time_t)*/4) && read != 0) { - return false; + systemMessage(MSG_FAILED_TO_READ_RTC, + N_("Failed to read RTC from save game %s (continuing)"), + name); + res = false; } - - int read = gzread(gzFile, - gbRam, - gbRamSize); - - bool res = true; - - if (read != gbRamSize) - { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Failed to read complete save game %s (%d)"), name, read); - } - else - { - //assert(sizeof(time_t) == 4); - read = gzread(gzFile, - &gbDataMBC3.mapperSeconds, - sizeof(int32) * 10 + /*sizeof(time_t)*/4); - - if (read != (sizeof(int32) * 10 + /*sizeof(time_t)*/4) && read != 0) - { - systemMessage(MSG_FAILED_TO_READ_RTC, - N_("Failed to read RTC from save game %s (continuing)"), - name); - res = false; - } - } - - gzclose(gzFile); - return res; + } + + gzclose(gzFile); + return res; } bool gbReadSaveMBC5(const char *name) { - gzFile gzFile = gzopen(name, "rb"); - - if (gzFile == NULL) - { - return false; - } - - int read = gzread(gzFile, - gbRam, - gbRamSize); - - if (read != gbRamSize) - { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Failed to read complete save game %s (%d)"), name, read); - gzclose(gzFile); - return false; - } - - gzclose(gzFile); - return true; + gzFile gzFile = gzopen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + int read = gzread(gzFile, + gbRam, + gbRamSize); + + if (read != gbRamSize) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + gzclose(gzFile); + return false; + } + + gzclose(gzFile); + return true; } bool gbReadSaveMBC7(const char *name) { - FILE *file = fopen(name, "rb"); - - if (file == NULL) - { - return false; - } - - int read = fread(&gbMemory[0xa000], - 1, - 256, - file); - - if (read != 256) - { - systemMessage(MSG_FAILED_TO_READ_SGM, - N_("Failed to read complete save game %s (%d)"), name, read); - fclose(file); - return false; - } - - fclose(file); - return true; + FILE *file = fopen(name, "rb"); + + if (file == NULL) + { + return false; + } + + int read = fread(&gbMemory[0xa000], + 1, + 256, + file); + + if (read != 256) + { + systemMessage(MSG_FAILED_TO_READ_SGM, + N_("Failed to read complete save game %s (%d)"), name, read); + fclose(file); + return false; + } + + fclose(file); + return true; } #if 0 bool gbLoadBIOS(const char *biosFileName, bool useBiosFile) { - useBios = false; - if (useBiosFile) + useBios = false; + if (useBiosFile) + { + useBios = utilLoadBIOS(bios, biosFileName, gbEmulatorType); + if (!useBios) { - useBios = utilLoadBIOS(bios, biosFileName, gbEmulatorType); - if (!useBios) - { - systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file")); - } + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file")); } - return useBios; + } + return useBios; } #endif void gbInit() { - gbGenFilter(); - gbSgbInit(); // calls gbSgbReset()... whatever - - gbMemory = (u8 *)malloc(65536 + 4); - memset(gbMemory, 0, 65536 + 4); - memset(gbPalette, 0, 2 * 128); - - // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel - origPix = (u8 *)calloc(1, 4 * 257 * 226 + 4); - pix = origPix + 4; - - gbLineBuffer = (u16 *)malloc(160 * sizeof(u16)); + gbGenFilter(); + gbSgbInit(); // calls gbSgbReset()... whatever + + gbMemory = (u8 *)malloc(65536 + 4); + memset(gbMemory, 0, 65536 + 4); + memset(gbPalette, 0, 2 * 128); + + // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel + origPix = (u8 *)calloc(1, 4 * 257 * 226 + 4); + pix = origPix + 4; + + gbLineBuffer = (u16 *)malloc(160 * sizeof(u16)); } bool gbWriteBatteryFile(const char *file, bool extendedSave) { - if (gbBattery) - { - int type = gbRom[0x147]; - - switch (type) - { - case 0x03: - gbWriteSaveMBC1(file); - break; - case 0x06: - gbWriteSaveMBC2(file); - break; - case 0x0f: - case 0x10: - case 0x13: - gbWriteSaveMBC3(file, extendedSave); - break; - case 0x1b: - case 0x1e: - gbWriteSaveMBC5(file); - break; - case 0x22: - gbWriteSaveMBC7(file); - break; - case 0xff: - gbWriteSaveMBC1(file); - break; - } - } - return true; -} - -bool gbWriteBatteryFile(const char *file) -{ - gbWriteBatteryFile(file, true); - return true; -} - -bool gbWriteBatteryToStream(gzFile gzfile) -{ - // the GB save code is ugly, so rather than convert it all to use gzFiles, just save it to a temp file... -#define TEMP_SAVE_FNAME ("tempvbawrite.sav") - bool retVal = gbWriteBatteryFile(TEMP_SAVE_FNAME, true); - - // ...open the temp file and figure out its size... - FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "rb"); - if (fileTemp == NULL) - return false; - fseek(fileTemp, 0, SEEK_END); - int len = (int) ftell(fileTemp); - - // ...copy over the temp file... - char *temp = new char [len]; - fseek(fileTemp, 0, SEEK_SET); - if (fread(temp, len, 1, fileTemp) != 1) - { - delete [] temp; - fclose(fileTemp); - return false; - } - fclose(fileTemp); - utilGzWrite(gzfile, temp, len); - delete [] temp; - - // ... and delete the temp file - remove(TEMP_SAVE_FNAME); -#undef TEMP_SAVE_FNAME - - return retVal; -} - -bool gbReadBatteryFile(const char *file) -{ - bool res = false; - if (gbBattery) - { - int type = gbRom[0x147]; - - switch (type) - { - case 0x03: - res = gbReadSaveMBC1(file); - break; - case 0x06: - res = gbReadSaveMBC2(file); - break; - case 0x0f: - case 0x10: - case 0x13: - if (!gbReadSaveMBC3(file)) - { - struct tm *lt; - time_t tmp; //Small kludge to get it working on some systems where time_t has size 8. - - if (VBAMovieActive() || VBAMovieLoading()) - { - gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter() / 60; - lt = gmtime(&tmp); - gbDataMBC3.mapperLastTime=(u32)tmp; - } - else - { - time(&tmp); - gbDataMBC3.mapperLastTime=(u32)tmp; - lt = localtime(&tmp); - } - systemScreenMessage(ctime(&tmp), 4); - gbDataMBC3.mapperLastTime=(u32)tmp; - - gbDataMBC3.mapperSeconds = lt->tm_sec; - gbDataMBC3.mapperMinutes = lt->tm_min; - gbDataMBC3.mapperHours = lt->tm_hour; - gbDataMBC3.mapperDays = lt->tm_yday & 255; - gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | - (lt->tm_yday > 255 ? 1 : 0); - res = false; - break; - } - time_t tmp; - systemScreenMessage(ctime(&tmp), 4); - gbDataMBC3.mapperLastTime=(u32)tmp; - res = true; - break; - case 0x1b: - case 0x1e: - res = gbReadSaveMBC5(file); - break; - case 0x22: - res = gbReadSaveMBC7(file); - case 0xff: - res = gbReadSaveMBC1(file); - break; - } - } - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - return res; -} - -bool gbReadBatteryFromStream(gzFile gzfile) -{ - // the GB save code is ugly, so rather than convert it all to use gzFiles, just copy it to temp RAM... -#define TEMP_SAVE_FNAME ("tempvbaread.sav") - int pos = gztell(gzfile); - int buflen = 1024; - // ...make a temp file and write it there... - FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "wb"); - if (fileTemp == NULL) - return false; - int gzDeflated; - char *temp = new char [buflen]; - while ((gzDeflated = utilGzRead(gzfile, temp, buflen)) != 0) - { - if (gzDeflated == -1 || fwrite(temp, gzDeflated, 1, fileTemp) != 1) - { - delete [] temp; - fclose(fileTemp); - gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that - // calls this right now does a seek afterwards so it doesn't matter for now, but it's - // still bad) - return false; - } - } - gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that calls this - // right now does a seek afterwards so it doesn't matter for now, but it's still bad) - fclose(fileTemp); - delete [] temp; - - // ... load from the temp file... - bool retVal = gbReadBatteryFile(TEMP_SAVE_FNAME); - - // ... and delete the temp file - remove(TEMP_SAVE_FNAME); -#undef TEMP_SAVE_FNAME - - return retVal; -} - -bool gbReadGSASnapshot(const char *fileName) -{ - FILE *file = fopen(fileName, "rb"); - - if (!file) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); - return false; - } - - // long size = ftell(file); - fseek(file, 0x4, SEEK_SET); - char buffer[16]; - char buffer2[16]; - fread(buffer, 1, 15, file); - buffer[15] = 0; - memcpy(buffer2, &gbRom[0x134], 15); - buffer2[15] = 0; - if (memcmp(buffer, buffer2, 15)) - { - systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, - N_("Cannot import snapshot for %s. Current game is %s"), - buffer, - buffer2); - fclose(file); - return false; - } - fseek(file, 0x13, SEEK_SET); - int read = 0; - int toRead = 0; - switch (gbRom[0x147]) + if (gbBattery) + { + int type = gbRom[0x147]; + + switch (type) { case 0x03: + gbWriteSaveMBC1(file); + break; + case 0x06: + gbWriteSaveMBC2(file); + break; case 0x0f: case 0x10: case 0x13: + gbWriteSaveMBC3(file, extendedSave); + break; case 0x1b: case 0x1e: + gbWriteSaveMBC5(file); + break; + case 0x22: + gbWriteSaveMBC7(file); + break; case 0xff: - read = fread(gbRam, 1, gbRamSize, file); - toRead = gbRamSize; - break; + gbWriteSaveMBC1(file); + break; + } + } + return true; +} + +bool gbWriteBatteryFile(const char *file) +{ + gbWriteBatteryFile(file, true); + return true; +} + +bool gbWriteBatteryToStream(gzFile gzfile) +{ + // the GB save code is ugly, so rather than convert it all to use gzFiles, just save it to a temp file... +#define TEMP_SAVE_FNAME ("tempvbawrite.sav") + bool retVal = gbWriteBatteryFile(TEMP_SAVE_FNAME, true); + + // ...open the temp file and figure out its size... + FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "rb"); + if (fileTemp == NULL) + return false; + fseek(fileTemp, 0, SEEK_END); + int len = (int) ftell(fileTemp); + + // ...copy over the temp file... + char *temp = new char [len]; + fseek(fileTemp, 0, SEEK_SET); + if (fread(temp, len, 1, fileTemp) != 1) + { + delete [] temp; + fclose(fileTemp); + return false; + } + fclose(fileTemp); + utilGzWrite(gzfile, temp, len); + delete [] temp; + + // ... and delete the temp file + remove(TEMP_SAVE_FNAME); +#undef TEMP_SAVE_FNAME + + return retVal; +} + +bool gbReadBatteryFile(const char *file) +{ + bool res = false; + if (gbBattery) + { + int type = gbRom[0x147]; + + switch (type) + { + case 0x03: + res = gbReadSaveMBC1(file); + break; case 0x06: + res = gbReadSaveMBC2(file); + break; + case 0x0f: + case 0x10: + case 0x13: + if (!gbReadSaveMBC3(file)) + { + struct tm *lt; + time_t tmp; //Small kludge to get it working on some systems where time_t has size 8. + + if (VBAMovieActive() || VBAMovieLoading()) + { + gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter() / 60; + lt = gmtime(&tmp); + gbDataMBC3.mapperLastTime=(u32)tmp; + } + else + { + time(&tmp); + gbDataMBC3.mapperLastTime=(u32)tmp; + lt = localtime(&tmp); + } + systemScreenMessage(ctime(&tmp), 4); + gbDataMBC3.mapperLastTime=(u32)tmp; + + gbDataMBC3.mapperSeconds = lt->tm_sec; + gbDataMBC3.mapperMinutes = lt->tm_min; + gbDataMBC3.mapperHours = lt->tm_hour; + gbDataMBC3.mapperDays = lt->tm_yday & 255; + gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | + (lt->tm_yday > 255 ? 1 : 0); + res = false; + break; + } + time_t tmp; + systemScreenMessage(ctime(&tmp), 4); + gbDataMBC3.mapperLastTime=(u32)tmp; + res = true; + break; + case 0x1b: + case 0x1e: + res = gbReadSaveMBC5(file); + break; case 0x22: - read = fread(&gbMemory[0xa000], 1, 256, file); - toRead = 256; - break; - default: - systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, - N_("Unsupported snapshot file %s"), - fileName); - fclose(file); - return false; + res = gbReadSaveMBC7(file); + case 0xff: + res = gbReadSaveMBC1(file); + break; } - fclose(file); - gbReset(); - return true; + } + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + return res; } +bool gbReadBatteryFromStream(gzFile gzfile) +{ + // the GB save code is ugly, so rather than convert it all to use gzFiles, just copy it to temp RAM... +#define TEMP_SAVE_FNAME ("tempvbaread.sav") + int pos = gztell(gzfile); + int buflen = 1024; + // ...make a temp file and write it there... + FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "wb"); + if (fileTemp == NULL) + return false; + int gzDeflated; + char *temp = new char [buflen]; + while ((gzDeflated = utilGzRead(gzfile, temp, buflen)) != 0) + { + if (gzDeflated == -1 || fwrite(temp, gzDeflated, 1, fileTemp) != 1) + { + delete [] temp; + fclose(fileTemp); + gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that + // calls this right now does a seek afterwards so it doesn't matter for now, but it's + // still bad) + return false; + } + } + gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that calls this + // right now does a seek afterwards so it doesn't matter for now, but it's still bad) + fclose(fileTemp); + delete [] temp; + + // ... load from the temp file... + bool retVal = gbReadBatteryFile(TEMP_SAVE_FNAME); + + // ... and delete the temp file + remove(TEMP_SAVE_FNAME); +#undef TEMP_SAVE_FNAME + + return retVal; +} + +bool gbReadGSASnapshot(const char *fileName) +{ + FILE *file = fopen(fileName, "rb"); + + if (!file) + { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); + return false; + } + + // long size = ftell(file); + fseek(file, 0x4, SEEK_SET); + char buffer[16]; + char buffer2[16]; + fread(buffer, 1, 15, file); + buffer[15] = 0; + memcpy(buffer2, &gbRom[0x134], 15); + buffer2[15] = 0; + if (memcmp(buffer, buffer2, 15)) + { + systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, + N_("Cannot import snapshot for %s. Current game is %s"), + buffer, + buffer2); + fclose(file); + return false; + } + fseek(file, 0x13, SEEK_SET); + int read = 0; + int toRead = 0; + switch (gbRom[0x147]) + { + case 0x03: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1e: + case 0xff: + read = fread(gbRam, 1, gbRamSize, file); + toRead = gbRamSize; + break; + case 0x06: + case 0x22: + read = fread(&gbMemory[0xa000], 1, 256, file); + toRead = 256; + break; + default: + systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, + N_("Unsupported snapshot file %s"), + fileName); + fclose(file); + return false; + } + fclose(file); + gbReset(); + return true; +} + variable_desc gbSaveGameStruct[] = -{ - { &PC.W, sizeof(u16) }, - { &SP.W, sizeof(u16) }, - { &AF.W, sizeof(u16) }, - { &BC.W, sizeof(u16) }, - { &DE.W, sizeof(u16) }, - { &HL.W, sizeof(u16) }, - { &IFF, sizeof(u8) }, - { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int32) }, - { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int32) }, - { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int32) }, - { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int32) }, - { &GBDIV_CLOCK_TICKS, sizeof(int32) }, - { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int32) }, - { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int32) }, - { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int32) }, - { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int32) }, - { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int32) }, - { &GBSERIAL_CLOCK_TICKS, sizeof(int32) }, - { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int32) }, - { &gbDivTicks, sizeof(int32) }, - { &gbLcdMode, sizeof(int32) }, - { &gbLcdTicks, sizeof(int32) }, - { &gbLcdLYIncrementTicks, sizeof(int32) }, - { &gbTimerTicks, sizeof(int32) }, - { &gbTimerClockTicks, sizeof(int32) }, - { &gbSerialTicks, sizeof(int32) }, - { &gbSerialBits, sizeof(int32) }, - { &gbInterrupt, sizeof(int32) }, - { &gbInterruptWait, sizeof(int32) }, - { &gbSynchronizeTicks, sizeof(int32) }, - { &gbTimerOn, sizeof(int32) }, - { &gbTimerMode, sizeof(int32) }, - { &gbSerialOn, sizeof(int32) }, - { &gbWindowLine, sizeof(int32) }, - { &gbCgbMode, sizeof(int32) }, - { &gbVramBank, sizeof(int32) }, - { &gbWramBank, sizeof(int32) }, - { &gbHdmaSource, sizeof(int32) }, - { &gbHdmaDestination, sizeof(int32) }, - { &gbHdmaBytes, sizeof(int32) }, - { &gbHdmaOn, sizeof(int32) }, - { &gbSpeed, sizeof(int32) }, - { &gbSgbMode, sizeof(int32) }, - { ®ister_DIV, sizeof(u8) }, - { ®ister_TIMA, sizeof(u8) }, - { ®ister_TMA, sizeof(u8) }, - { ®ister_TAC, sizeof(u8) }, - { ®ister_IF, sizeof(u8) }, - { ®ister_LCDC, sizeof(u8) }, - { ®ister_STAT, sizeof(u8) }, - { ®ister_SCY, sizeof(u8) }, - { ®ister_SCX, sizeof(u8) }, - { ®ister_LY, sizeof(u8) }, - { ®ister_LYC, sizeof(u8) }, - { ®ister_DMA, sizeof(u8) }, - { ®ister_WY, sizeof(u8) }, - { ®ister_WX, sizeof(u8) }, - { ®ister_VBK, sizeof(u8) }, - { ®ister_HDMA1, sizeof(u8) }, - { ®ister_HDMA2, sizeof(u8) }, - { ®ister_HDMA3, sizeof(u8) }, - { ®ister_HDMA4, sizeof(u8) }, - { ®ister_HDMA5, sizeof(u8) }, - { ®ister_SVBK, sizeof(u8) }, - { ®ister_IE, sizeof(u8) }, - { &gbBgp[0], sizeof(u8) }, - { &gbBgp[1], sizeof(u8) }, - { &gbBgp[2], sizeof(u8) }, - { &gbBgp[3], sizeof(u8) }, - { &gbObp0[0], sizeof(u8) }, - { &gbObp0[1], sizeof(u8) }, - { &gbObp0[2], sizeof(u8) }, - { &gbObp0[3], sizeof(u8) }, - { &gbObp1[0], sizeof(u8) }, - { &gbObp1[1], sizeof(u8) }, - { &gbObp1[2], sizeof(u8) }, - { &gbObp1[3], sizeof(u8) }, - { NULL, 0 } -}; + { + { &PC.W, sizeof(u16) }, + { &SP.W, sizeof(u16) }, + { &AF.W, sizeof(u16) }, + { &BC.W, sizeof(u16) }, + { &DE.W, sizeof(u16) }, + { &HL.W, sizeof(u16) }, + { &IFF, sizeof(u8) }, + { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int32) }, + { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int32) }, + { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int32) }, + { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int32) }, + { &GBDIV_CLOCK_TICKS, sizeof(int32) }, + { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int32) }, + { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int32) }, + { &GBSERIAL_CLOCK_TICKS, sizeof(int32) }, + { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int32) }, + { &gbDivTicks, sizeof(int32) }, + { &gbLcdMode, sizeof(int32) }, + { &gbLcdTicks, sizeof(int32) }, + { &gbLcdLYIncrementTicks, sizeof(int32) }, + { &gbTimerTicks, sizeof(int32) }, + { &gbTimerClockTicks, sizeof(int32) }, + { &gbSerialTicks, sizeof(int32) }, + { &gbSerialBits, sizeof(int32) }, + { &gbInterrupt, sizeof(int32) }, + { &gbInterruptWait, sizeof(int32) }, + { &gbSynchronizeTicks, sizeof(int32) }, + { &gbTimerOn, sizeof(int32) }, + { &gbTimerMode, sizeof(int32) }, + { &gbSerialOn, sizeof(int32) }, + { &gbWindowLine, sizeof(int32) }, + { &gbCgbMode, sizeof(int32) }, + { &gbVramBank, sizeof(int32) }, + { &gbWramBank, sizeof(int32) }, + { &gbHdmaSource, sizeof(int32) }, + { &gbHdmaDestination, sizeof(int32) }, + { &gbHdmaBytes, sizeof(int32) }, + { &gbHdmaOn, sizeof(int32) }, + { &gbSpeed, sizeof(int32) }, + { &gbSgbMode, sizeof(int32) }, + { ®ister_DIV, sizeof(u8) }, + { ®ister_TIMA, sizeof(u8) }, + { ®ister_TMA, sizeof(u8) }, + { ®ister_TAC, sizeof(u8) }, + { ®ister_IF, sizeof(u8) }, + { ®ister_LCDC, sizeof(u8) }, + { ®ister_STAT, sizeof(u8) }, + { ®ister_SCY, sizeof(u8) }, + { ®ister_SCX, sizeof(u8) }, + { ®ister_LY, sizeof(u8) }, + { ®ister_LYC, sizeof(u8) }, + { ®ister_DMA, sizeof(u8) }, + { ®ister_WY, sizeof(u8) }, + { ®ister_WX, sizeof(u8) }, + { ®ister_VBK, sizeof(u8) }, + { ®ister_HDMA1, sizeof(u8) }, + { ®ister_HDMA2, sizeof(u8) }, + { ®ister_HDMA3, sizeof(u8) }, + { ®ister_HDMA4, sizeof(u8) }, + { ®ister_HDMA5, sizeof(u8) }, + { ®ister_SVBK, sizeof(u8) }, + { ®ister_IE, sizeof(u8) }, + { &gbBgp[0], sizeof(u8) }, + { &gbBgp[1], sizeof(u8) }, + { &gbBgp[2], sizeof(u8) }, + { &gbBgp[3], sizeof(u8) }, + { &gbObp0[0], sizeof(u8) }, + { &gbObp0[1], sizeof(u8) }, + { &gbObp0[2], sizeof(u8) }, + { &gbObp0[3], sizeof(u8) }, + { &gbObp1[0], sizeof(u8) }, + { &gbObp1[1], sizeof(u8) }, + { &gbObp1[2], sizeof(u8) }, + { &gbObp1[3], sizeof(u8) }, + { NULL, 0 } + }; bool gbWriteSaveStateToStream(gzFile gzFile) { - utilWriteInt(gzFile, GBSAVE_GAME_VERSION); - - utilGzWrite(gzFile, &gbRom[0x134], 15); - - utilWriteData(gzFile, gbSaveGameStruct); - - utilGzWrite(gzFile, &IFF, 2); - - if (gbSgbMode) - { - gbSgbSaveGame(gzFile); - } - - utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); - utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); - //assert(sizeof(time_t) == 4); - utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); - utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); - utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); - utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); - - // yes, this definitely needs to be saved, or loading paused games will show a black screen - // this is also necessary to be consistent with what the GBA saving does - utilGzWrite(gzFile, pix, 4 * 257 * 226); - - utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); - // todo: remove - utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); - - utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); - - if (gbRamSize && gbRam) - { - utilGzWrite(gzFile, gbRam, gbRamSize); - } - - if (gbCgbMode) - { - utilGzWrite(gzFile, gbVram, 0x4000); - utilGzWrite(gzFile, gbWram, 0x8000); - } - - gbSoundSaveGame(gzFile); - - gbCheatsSaveGame(gzFile); - - // new to re-recording version: - { - extern int32 sensorX, sensorY; - utilGzWrite(gzFile, &sensorX, sizeof(sensorX)); - utilGzWrite(gzFile, &sensorY, sizeof(sensorY)); - utilGzWrite(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get - // carried - // back on loading a snapshot! - - bool8 movieActive = VBAMovieActive(); - utilGzWrite(gzFile, &movieActive, sizeof(movieActive)); - if (movieActive) - { - uint8 *movie_freeze_buf = NULL; - uint32 movie_freeze_size = 0; - - VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size); - if (movie_freeze_buf) - { - utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size)); - utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size); - delete [] movie_freeze_buf; - } - else - { - systemMessage(0, N_("Failed to save movie snapshot.")); - return false; - } - } - utilGzWrite(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); - } - - // new to rerecording 19.4 wip (svn r22+): - { - utilGzWrite(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); - utilGzWrite(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); - utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); - } - - return true; + utilWriteInt(gzFile, GBSAVE_GAME_VERSION); + + utilGzWrite(gzFile, &gbRom[0x134], 15); + + utilWriteData(gzFile, gbSaveGameStruct); + + utilGzWrite(gzFile, &IFF, 2); + + if (gbSgbMode) + { + gbSgbSaveGame(gzFile); + } + + utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); + utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); + //assert(sizeof(time_t) == 4); + utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + + // yes, this definitely needs to be saved, or loading paused games will show a black screen + // this is also necessary to be consistent with what the GBA saving does + utilGzWrite(gzFile, pix, 4 * 257 * 226); + + utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); + // todo: remove + utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); + + utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); + + if (gbRamSize && gbRam) + { + utilGzWrite(gzFile, gbRam, gbRamSize); + } + + if (gbCgbMode) + { + utilGzWrite(gzFile, gbVram, 0x4000); + utilGzWrite(gzFile, gbWram, 0x8000); + } + + gbSoundSaveGame(gzFile); + + gbCheatsSaveGame(gzFile); + + // new to re-recording version: + { + extern int32 sensorX, sensorY; + utilGzWrite(gzFile, &sensorX, sizeof(sensorX)); + utilGzWrite(gzFile, &sensorY, sizeof(sensorY)); + utilGzWrite(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get + // carried + // back on loading a snapshot! + + bool8 movieActive = VBAMovieActive(); + utilGzWrite(gzFile, &movieActive, sizeof(movieActive)); + if (movieActive) + { + uint8 *movie_freeze_buf = NULL; + uint32 movie_freeze_size = 0; + + VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size); + if (movie_freeze_buf) + { + utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size)); + utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size); + delete [] movie_freeze_buf; + } + else + { + systemMessage(0, N_("Failed to save movie snapshot.")); + return false; + } + } + utilGzWrite(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); + } + + // new to rerecording 19.4 wip (svn r22+): + { + utilGzWrite(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); + utilGzWrite(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); + utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); + } + + return true; } bool gbWriteMemSaveState(char *memory, int available) { - gzFile gzFile = utilMemGzOpen(memory, available, "w"); - - if (gzFile == NULL) - { - return false; - } - - bool res = gbWriteSaveStateToStream(gzFile); - - long pos = utilGzTell(gzFile) + 8; - - if (pos >= (available)) - res = false; - - utilGzClose(gzFile); - - return res; + gzFile gzFile = utilMemGzOpen(memory, available, "w"); + + if (gzFile == NULL) + { + return false; + } + + bool res = gbWriteSaveStateToStream(gzFile); + + long pos = utilGzTell(gzFile) + 8; + + if (pos >= (available)) + res = false; + + utilGzClose(gzFile); + + return res; } bool gbWriteSaveState(const char *name) { - gzFile gzFile = utilGzOpen(name, "wb"); - - if (gzFile == NULL) - return false; - - bool res = gbWriteSaveStateToStream(gzFile); - - utilGzClose(gzFile); - return res; + gzFile gzFile = utilGzOpen(name, "wb"); + + if (gzFile == NULL) + return false; + + bool res = gbWriteSaveStateToStream(gzFile); + + utilGzClose(gzFile); + return res; } static int tempStateID = 0; @@ -2591,1328 +2591,1331 @@ bool gbReadSaveStateFromStream(gzFile gzFile) { - int type; - char tempBackupName [128]; - if (backupSafe) + int type; + char tempBackupName [128]; + if (backupSafe) + { + sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++); + gbWriteSaveState(tempBackupName); + } + + int version = utilReadInt(gzFile); + + if (version > GBSAVE_GAME_VERSION || version < 0) + { + systemMessage(MSG_UNSUPPORTED_VB_SGM, + N_("Unsupported VisualBoy save game version %d"), version); + goto failedLoadGB; + } + + u8 romname[20]; + + utilGzRead(gzFile, romname, 15); + + if (memcmp(&gbRom[0x134], romname, 15) != 0) + { + systemMessage(MSG_CANNOT_LOAD_SGM_FOR, + N_("Cannot load save game for %s. Playing %s"), + romname, &gbRom[0x134]); + goto failedLoadGB; + } + + utilReadData(gzFile, gbSaveGameStruct); + + if (version >= GBSAVE_GAME_VERSION_7) + { + utilGzRead(gzFile, &IFF, 2); + } + + if (gbSgbMode) + { + gbSgbReadGame(gzFile, version); + } + else + { + gbSgbMask = 0; // loading a game at the wrong time causes no display + } + + utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); + utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); + if (version < GBSAVE_GAME_VERSION_4) + // prior to version 4, there was no adjustment for the time the game + // was last played, so we have less to read. This needs update if the + // structure changes again. + utilGzRead(gzFile, &gbDataMBC3, sizeof(int32) * 10); + else + { + //assert(sizeof(time_t) == 4); + utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); + } + utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); + utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); + utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); + + if (version >= GBSAVE_GAME_VERSION_12) + { + utilGzRead(gzFile, pix, 4 * 257 * 226); + } + else + { + memset(pix, 0, 257 * 226 * sizeof(u32)); + // if(version < GBSAVE_GAME_VERSION_5) + // utilGzRead(gzFile, pix, 256*224*sizeof(u16)); + } + + if (version < GBSAVE_GAME_VERSION_6) + { + utilGzRead(gzFile, gbPalette, 64 * sizeof(u16)); + } + else + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); + + // todo: remove + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); + + if (version < GBSAVE_GAME_VERSION_10) + { + if (!gbCgbMode && !gbSgbMode) { - sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++); - gbWriteSaveState(tempBackupName); + for (int i = 0; i < 8; i++) + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; } - - int version = utilReadInt(gzFile); - - if (version > GBSAVE_GAME_VERSION || version < 0) + } + + utilGzRead(gzFile, &gbMemory[0x8000], 0x8000); + + if (gbRamSize && gbRam) + { + utilGzRead(gzFile, gbRam, gbRamSize); + } + + gbMemoryMap[0x00] = &gbRom[0x0000]; + gbMemoryMap[0x01] = &gbRom[0x1000]; + gbMemoryMap[0x02] = &gbRom[0x2000]; + gbMemoryMap[0x03] = &gbRom[0x3000]; + gbMemoryMap[0x04] = &gbRom[0x4000]; + gbMemoryMap[0x05] = &gbRom[0x5000]; + gbMemoryMap[0x06] = &gbRom[0x6000]; + gbMemoryMap[0x07] = &gbRom[0x7000]; + gbMemoryMap[0x08] = &gbMemory[0x8000]; + gbMemoryMap[0x09] = &gbMemory[0x9000]; + gbMemoryMap[0x0a] = &gbMemory[0xa000]; + gbMemoryMap[0x0b] = &gbMemory[0xb000]; + gbMemoryMap[0x0c] = &gbMemory[0xc000]; + gbMemoryMap[0x0d] = &gbMemory[0xd000]; + gbMemoryMap[0x0e] = &gbMemory[0xe000]; + gbMemoryMap[0x0f] = &gbMemory[0xf000]; + + type = gbRom[0x147]; + + switch (type) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + // MBC 1 + memoryUpdateMapMBC1(); + break; + case 0x05: + case 0x06: + // MBC2 + memoryUpdateMapMBC2(); + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + // MBC 3 + memoryUpdateMapMBC3(); + break; + case 0x19: + case 0x1a: + case 0x1b: + // MBC5 + memoryUpdateMapMBC5(); + break; + case 0x1c: + case 0x1d: + case 0x1e: + // MBC 5 Rumble + memoryUpdateMapMBC5(); + break; + case 0x22: + // MBC 7 + memoryUpdateMapMBC7(); + break; + case 0xfe: + // HuC3 + memoryUpdateMapHuC3(); + break; + case 0xff: + // HuC1 + memoryUpdateMapHuC1(); + break; + } + + if (gbCgbMode) + { + if (!gbVram) + gbVram = (u8 *)malloc(0x4000 + 4); + if (!gbWram) + gbWram = (u8 *)malloc(0x8000 + 4); + utilGzRead(gzFile, gbVram, 0x4000); + utilGzRead(gzFile, gbWram, 0x8000); + + int value = register_SVBK; + if (value == 0) + value = 1; + + gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; + gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; + gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; + } + else + { + if (gbVram) { - systemMessage(MSG_UNSUPPORTED_VB_SGM, - N_("Unsupported VisualBoy save game version %d"), version); - goto failedLoadGB; + free(gbVram); + gbVram = NULL; } - - u8 romname[20]; - - utilGzRead(gzFile, romname, 15); - - if (memcmp(&gbRom[0x134], romname, 15) != 0) + if (gbWram) { - systemMessage(MSG_CANNOT_LOAD_SGM_FOR, - N_("Cannot load save game for %s. Playing %s"), - romname, &gbRom[0x134]); - goto failedLoadGB; + free(gbWram); + gbWram = NULL; } - - utilReadData(gzFile, gbSaveGameStruct); - - if (version >= GBSAVE_GAME_VERSION_7) + } + + gbSoundReadGame(version, gzFile); + +#if 0 + if (gbBorderOn) + { + gbSgbRenderBorder(); + } + + systemRefreshScreen(); +#endif + + if (version > GBSAVE_GAME_VERSION_1) + gbCheatsReadGame(gzFile, version); + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + if (version >= GBSAVE_GAME_VERSION_11) // new to re-recording version: + { + extern int32 sensorX, sensorY; // from SDL.cpp + utilGzRead(gzFile, &sensorX, sizeof(sensorX)); + utilGzRead(gzFile, &sensorY, sizeof(sensorY)); + utilGzRead(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get carried + // back on loading a snapshot! + + bool8 movieSnapshot; + utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot)); + if (VBAMovieActive() && !movieSnapshot) { - utilGzRead(gzFile, &IFF, 2); + systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active.")); + goto failedLoadGB; } - if (gbSgbMode) + if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added + // later on in the save format { - gbSgbReadGame(gzFile, version); + uint32 movieInputDataSize = 0; + utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize)); + uint8 *local_movie_data = new uint8 [movieInputDataSize]; + int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize); + if (readBytes != movieInputDataSize) + { + systemMessage(0, N_("Corrupt movie snapshot.")); + if (local_movie_data) + delete [] local_movie_data; + goto failedLoadGB; + } + int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize); + if (local_movie_data) + delete [] local_movie_data; + if (code != MOVIE_SUCCESS && VBAMovieActive()) + { + char errStr [1024]; + strcpy(errStr, "Failed to load movie snapshot"); + switch (code) + { + case MOVIE_NOT_FROM_THIS_MOVIE: + strcat(errStr, ";\nSnapshot not from this movie"); break; + case MOVIE_NOT_FROM_A_MOVIE: + strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here... + case MOVIE_SNAPSHOT_INCONSISTENT: + strcat(errStr, ";\nSnapshot inconsistent with movie"); break; + case MOVIE_WRONG_FORMAT: + strcat(errStr, ";\nWrong format"); break; + } + strcat(errStr, "."); + systemMessage(0, N_(errStr)); + goto failedLoadGB; + } } - else - { - gbSgbMask = 0; // loading a game at the wrong time causes no display - } - - utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); - utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); - if (version < GBSAVE_GAME_VERSION_4) - // prior to version 4, there was no adjustment for the time the game - // was last played, so we have less to read. This needs update if the - // structure changes again. - utilGzRead(gzFile, &gbDataMBC3, sizeof(int32) * 10); - else - { - //assert(sizeof(time_t) == 4); - utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); - } - utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); - utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); - utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); - - if (version >= GBSAVE_GAME_VERSION_12) - { - utilGzRead(gzFile, pix, 4 * 257 * 226); - } - else - { - memset(pix, 0, 257 * 226 * sizeof(u32)); -// if(version < GBSAVE_GAME_VERSION_5) -// utilGzRead(gzFile, pix, 256*224*sizeof(u16)); - } - - if (version < GBSAVE_GAME_VERSION_6) - { - utilGzRead(gzFile, gbPalette, 64 * sizeof(u16)); - } - else - utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); - - // todo: remove - utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); - - if (version < GBSAVE_GAME_VERSION_10) - { - if (!gbCgbMode && !gbSgbMode) - { - for (int i = 0; i < 8; i++) - gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; - } - } - - utilGzRead(gzFile, &gbMemory[0x8000], 0x8000); - - if (gbRamSize && gbRam) - { - utilGzRead(gzFile, gbRam, gbRamSize); - } - - gbMemoryMap[0x00] = &gbRom[0x0000]; - gbMemoryMap[0x01] = &gbRom[0x1000]; - gbMemoryMap[0x02] = &gbRom[0x2000]; - gbMemoryMap[0x03] = &gbRom[0x3000]; - gbMemoryMap[0x04] = &gbRom[0x4000]; - gbMemoryMap[0x05] = &gbRom[0x5000]; - gbMemoryMap[0x06] = &gbRom[0x6000]; - gbMemoryMap[0x07] = &gbRom[0x7000]; - gbMemoryMap[0x08] = &gbMemory[0x8000]; - gbMemoryMap[0x09] = &gbMemory[0x9000]; - gbMemoryMap[0x0a] = &gbMemory[0xa000]; - gbMemoryMap[0x0b] = &gbMemory[0xb000]; - gbMemoryMap[0x0c] = &gbMemory[0xc000]; - gbMemoryMap[0x0d] = &gbMemory[0xd000]; - gbMemoryMap[0x0e] = &gbMemory[0xe000]; - gbMemoryMap[0x0f] = &gbMemory[0xf000]; - - type = gbRom[0x147]; - - switch (type) - { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - // MBC 1 - memoryUpdateMapMBC1(); - break; - case 0x05: - case 0x06: - // MBC2 - memoryUpdateMapMBC2(); - break; - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - // MBC 3 - memoryUpdateMapMBC3(); - break; - case 0x19: - case 0x1a: - case 0x1b: - // MBC5 - memoryUpdateMapMBC5(); - break; - case 0x1c: - case 0x1d: - case 0x1e: - // MBC 5 Rumble - memoryUpdateMapMBC5(); - break; - case 0x22: - // MBC 7 - memoryUpdateMapMBC7(); - break; - case 0xfe: - // HuC3 - memoryUpdateMapHuC3(); - break; - case 0xff: - // HuC1 - memoryUpdateMapHuC1(); - break; - } - - if (gbCgbMode) - { - if (!gbVram) - gbVram = (u8 *)malloc(0x4000 + 4); - if (!gbWram) - gbWram = (u8 *)malloc(0x8000 + 4); - utilGzRead(gzFile, gbVram, 0x4000); - utilGzRead(gzFile, gbWram, 0x8000); - - int value = register_SVBK; - if (value == 0) - value = 1; - - gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; - gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; - gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; - } - else - { - if (gbVram) - { - free(gbVram); - gbVram = NULL; - } - if (gbWram) - { - free(gbWram); - gbWram = NULL; - } - } - - gbSoundReadGame(version, gzFile); - -#if 0 - if (gbBorderOn) - { - gbSgbRenderBorder(); - } - - systemRefreshScreen(); -#endif - - if (version > GBSAVE_GAME_VERSION_1) - gbCheatsReadGame(gzFile, version); - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - if (version >= GBSAVE_GAME_VERSION_11) // new to re-recording version: - { - extern int32 sensorX, sensorY; // from SDL.cpp - utilGzRead(gzFile, &sensorX, sizeof(sensorX)); - utilGzRead(gzFile, &sensorY, sizeof(sensorY)); - utilGzRead(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get carried - // back on loading a snapshot! - - bool8 movieSnapshot; - utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot)); - if (VBAMovieActive() && !movieSnapshot) - { - systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active.")); - goto failedLoadGB; - } - - if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added - // later on in the save format - { - uint32 movieInputDataSize = 0; - utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize)); - uint8 *local_movie_data = new uint8 [movieInputDataSize]; - int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize); - if (readBytes != movieInputDataSize) - { - systemMessage(0, N_("Corrupt movie snapshot.")); - if (local_movie_data) - delete [] local_movie_data; - goto failedLoadGB; - } - int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize); - if (local_movie_data) - delete [] local_movie_data; - if (code != MOVIE_SUCCESS && VBAMovieActive()) - { - char errStr [1024]; - strcpy(errStr, "Failed to load movie snapshot"); - switch (code) - { - case MOVIE_NOT_FROM_THIS_MOVIE: - strcat(errStr, ";\nSnapshot not from this movie"); break; - case MOVIE_NOT_FROM_A_MOVIE: - strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here... - case MOVIE_SNAPSHOT_INCONSISTENT: - strcat(errStr, ";\nSnapshot inconsistent with movie"); break; - case MOVIE_WRONG_FORMAT: - strcat(errStr, ";\nWrong format"); break; - } - strcat(errStr, "."); - systemMessage(0, N_(errStr)); - goto failedLoadGB; - } - } - utilGzRead(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); - } - - if (version >= GBSAVE_GAME_VERSION_13) // new to rerecording 19.4 wip (svn r22+): - { - utilGzRead(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); - utilGzRead(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); - utilGzRead(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); - } - - if (backupSafe) - { - remove(tempBackupName); - tempFailCount = 0; - } - - for (int i = 0; i < 4; ++i) - systemSetJoypad(i, gbJoymask[i] & 0xFFFF); - - // FIXME: horrible kludge - memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); - - VBAUpdateButtonPressDisplay(); - VBAUpdateFrameCountDisplay(); - systemRefreshScreen(); - return true; - -failedLoadGB: - if (backupSafe) - { - tempFailCount++; - if (tempFailCount < 3) // fail no more than 2 times in a row - gbReadSaveState(tempBackupName); - remove(tempBackupName); - } - return false; + utilGzRead(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); + } + + if (version >= GBSAVE_GAME_VERSION_13) // new to rerecording 19.4 wip (svn r22+): + { + utilGzRead(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); + utilGzRead(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); + utilGzRead(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); + } + + if (backupSafe) + { + remove(tempBackupName); + tempFailCount = 0; + } + + for (int i = 0; i < 4; ++i) + systemSetJoypad(i, gbJoymask[i] & 0xFFFF); + + // FIXME: horrible kludge + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); + + VBAUpdateButtonPressDisplay(); + VBAUpdateFrameCountDisplay(); + systemRefreshScreen(); + return true; + + failedLoadGB: + if (backupSafe) + { + tempFailCount++; + if (tempFailCount < 3) // fail no more than 2 times in a row + gbReadSaveState(tempBackupName); + remove(tempBackupName); + } + return false; } bool gbReadMemSaveState(char *memory, int available) { - gzFile gzFile = utilMemGzOpen(memory, available, "r"); - - backupSafe = false; - bool res = gbReadSaveStateFromStream(gzFile); - backupSafe = true; - - utilGzClose(gzFile); - - return res; + gzFile gzFile = utilMemGzOpen(memory, available, "r"); + + backupSafe = false; + bool res = gbReadSaveStateFromStream(gzFile); + backupSafe = true; + + utilGzClose(gzFile); + + return res; } bool gbReadSaveState(const char *name) { - gzFile gzFile = utilGzOpen(name, "rb"); - - if (gzFile == NULL) - { - return false; - } - - bool res = gbReadSaveStateFromStream(gzFile); - - utilGzClose(gzFile); - - return res; + gzFile gzFile = utilGzOpen(name, "rb"); + + if (gzFile == NULL) + { + return false; + } + + bool res = gbReadSaveStateFromStream(gzFile); + + utilGzClose(gzFile); + + return res; } bool gbWritePNGFile(const char *fileName) { - if (gbBorderOn) - return utilWritePNGFile(fileName, 256, 224, pix); - return utilWritePNGFile(fileName, 160, 144, pix); + if (gbBorderOn) + return utilWritePNGFile(fileName, 256, 224, pix); + return utilWritePNGFile(fileName, 160, 144, pix); } bool gbWriteBMPFile(const char *fileName) { - if (gbBorderOn) - return utilWriteBMPFile(fileName, 256, 224, pix); - return utilWriteBMPFile(fileName, 160, 144, pix); + if (gbBorderOn) + return utilWriteBMPFile(fileName, 256, 224, pix); + return utilWriteBMPFile(fileName, 160, 144, pix); } void gbCleanUp() { - newFrame = true; - - GBSystemCounters.frameCount = 0; - GBSystemCounters.lagCount = 0; - GBSystemCounters.extraCount = 0; - GBSystemCounters.lagged = true; - GBSystemCounters.laggedLast = true; - - if (gbRam != NULL) - { - free(gbRam); - gbRam = NULL; - } - - if (gbRom != NULL) - { - free(gbRom); - gbRom = NULL; - } - - if (gbMemory != NULL) - { - free(gbMemory); - gbMemory = NULL; - } - - if (gbLineBuffer != NULL) - { - free(gbLineBuffer); - gbLineBuffer = NULL; - } - - if (origPix != NULL) - { - free(origPix); - origPix = NULL; - } - pix = NULL; - - gbSgbShutdown(); - - if (gbVram != NULL) - { - free(gbVram); - gbVram = NULL; - } - - if (gbWram != NULL) - { - free(gbWram); - gbWram = NULL; - } - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - memset(gbJoymask, 0, sizeof(gbJoymask)); - // FIXME: horrible kludge - memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); - - systemClearJoypads(); - systemResetSensor(); - -// gbLastTime = gbFrameCount = 0; - systemRefreshScreen(); + newFrame = true; + + GBSystemCounters.frameCount = 0; + GBSystemCounters.lagCount = 0; + GBSystemCounters.extraCount = 0; + GBSystemCounters.lagged = true; + GBSystemCounters.laggedLast = true; + + if (gbRam != NULL) + { + free(gbRam); + gbRam = NULL; + } + + if (gbRom != NULL) + { + free(gbRom); + gbRom = NULL; + } + + if (gbMemory != NULL) + { + free(gbMemory); + gbMemory = NULL; + } + + if (gbLineBuffer != NULL) + { + free(gbLineBuffer); + gbLineBuffer = NULL; + } + + if (origPix != NULL) + { + free(origPix); + origPix = NULL; + } + pix = NULL; + + gbSgbShutdown(); + + if (gbVram != NULL) + { + free(gbVram); + gbVram = NULL; + } + + if (gbWram != NULL) + { + free(gbWram); + gbWram = NULL; + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + memset(gbJoymask, 0, sizeof(gbJoymask)); + // FIXME: horrible kludge + memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); + + systemClearJoypads(); + systemResetSensor(); + + // gbLastTime = gbFrameCount = 0; + systemRefreshScreen(); } bool gbLoadRom(const char *szFile) { - int size = 0; - - if (gbRom != NULL) - { - gbCleanUp(); - } - - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - - gbRom = utilLoad(szFile, - utilIsGBImage, - NULL, - size); - if (!gbRom) - return false; - - gbRomSize = size; - - return gbUpdateSizes(); + int size = 0; + + if (gbRom != NULL) + { + gbCleanUp(); + } + + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + + gbRom = utilLoad(szFile, + utilIsGBImage, + NULL, + size); + if (!gbRom) + return false; + + gbRomSize = size; + + return gbUpdateSizes(); } bool gbUpdateSizes() { - if (gbRom[0x148] > 8) - { - systemMessage(MSG_UNSUPPORTED_ROM_SIZE, - N_("Unsupported rom size %02x"), gbRom[0x148]); - return false; - } - - if (gbRomSize < gbRomSizes[gbRom[0x148]]) - { - gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); - } - gbRomSize = gbRomSizes[gbRom[0x148]]; - gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; - - if (gbRom[0x149] > 5) - { - systemMessage(MSG_UNSUPPORTED_RAM_SIZE, - N_("Unsupported ram size %02x"), gbRom[0x149]); - return false; - } - - gbRamSize = gbRamSizes[gbRom[0x149]]; - gbRamSizeMask = gbRamSizesMasks[gbRom[0x149]]; - - if (gbRamSize) - { - gbRam = (u8 *)malloc(gbRamSize + 4); - memset(gbRam, 0xFF, gbRamSize + 4); - } - - int type = gbRom[0x147]; - - mapperReadRAM = NULL; - - switch (type) - { - case 0x00: - case 0x01: - case 0x02: - case 0x03: - // MBC 1 - mapper = mapperMBC1ROM; - mapperRAM = mapperMBC1RAM; - break; - case 0x05: - case 0x06: - // MBC2 - mapper = mapperMBC2ROM; - mapperRAM = mapperMBC2RAM; - gbRamSize = 0x200; - gbRamSizeMask = 0x1ff; - break; - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - // MBC 3 - mapper = mapperMBC3ROM; - mapperRAM = mapperMBC3RAM; - mapperReadRAM = mapperMBC3ReadRAM; - break; - case 0x19: - case 0x1a: - case 0x1b: - // MBC5 - mapper = mapperMBC5ROM; - mapperRAM = mapperMBC5RAM; - break; - case 0x1c: - case 0x1d: - case 0x1e: - // MBC 5 Rumble - mapper = mapperMBC5ROM; - mapperRAM = mapperMBC5RAM; - break; - case 0x22: - // MBC 7 - mapper = mapperMBC7ROM; - mapperRAM = mapperMBC7RAM; - mapperReadRAM = mapperMBC7ReadRAM; - break; - case 0xfe: - // HuC3 - mapper = mapperHuC3ROM; - mapperRAM = mapperHuC3RAM; - mapperReadRAM = mapperHuC3ReadRAM; - break; - case 0xff: - // HuC1 - mapper = mapperHuC1ROM; - mapperRAM = mapperHuC1RAM; - break; - default: - systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE, - N_("Unknown cartridge type %02x"), type); - return false; - } - - switch (type) - { - case 0x03: - case 0x06: - case 0x0f: - case 0x10: - case 0x13: - case 0x1b: - case 0x1d: - case 0x1e: - case 0x22: - case 0xff: - gbBattery = 1; - break; - } - - gbInit(); - gbReset(); - - return true; + if (gbRom[0x148] > 8) + { + systemMessage(MSG_UNSUPPORTED_ROM_SIZE, + N_("Unsupported rom size %02x"), gbRom[0x148]); + return false; + } + + if (gbRomSize < gbRomSizes[gbRom[0x148]]) + { + gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); + } + gbRomSize = gbRomSizes[gbRom[0x148]]; + gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; + + if (gbRom[0x149] > 5) + { + systemMessage(MSG_UNSUPPORTED_RAM_SIZE, + N_("Unsupported ram size %02x"), gbRom[0x149]); + return false; + } + + gbRamSize = gbRamSizes[gbRom[0x149]]; + gbRamSizeMask = gbRamSizesMasks[gbRom[0x149]]; + + if (gbRamSize) + { + gbRam = (u8 *)malloc(gbRamSize + 4); + memset(gbRam, 0xFF, gbRamSize + 4); + } + + int type = gbRom[0x147]; + + mapperReadRAM = NULL; + + switch (type) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + // MBC 1 + mapper = mapperMBC1ROM; + mapperRAM = mapperMBC1RAM; + break; + case 0x05: + case 0x06: + // MBC2 + mapper = mapperMBC2ROM; + mapperRAM = mapperMBC2RAM; + gbRamSize = 0x200; + gbRamSizeMask = 0x1ff; + break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + // MBC 3 + mapper = mapperMBC3ROM; + mapperRAM = mapperMBC3RAM; + mapperReadRAM = mapperMBC3ReadRAM; + break; + case 0x19: + case 0x1a: + case 0x1b: + // MBC5 + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + break; + case 0x1c: + case 0x1d: + case 0x1e: + // MBC 5 Rumble + mapper = mapperMBC5ROM; + mapperRAM = mapperMBC5RAM; + break; + case 0x22: + // MBC 7 + mapper = mapperMBC7ROM; + mapperRAM = mapperMBC7RAM; + mapperReadRAM = mapperMBC7ReadRAM; + break; + case 0xfe: + // HuC3 + mapper = mapperHuC3ROM; + mapperRAM = mapperHuC3RAM; + mapperReadRAM = mapperHuC3ReadRAM; + break; + case 0xff: + // HuC1 + mapper = mapperHuC1ROM; + mapperRAM = mapperHuC1RAM; + break; + default: + systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE, + N_("Unknown cartridge type %02x"), type); + return false; + } + + switch (type) + { + case 0x03: + case 0x06: + case 0x0f: + case 0x10: + case 0x13: + case 0x1b: + case 0x1d: + case 0x1e: + case 0x22: + case 0xff: + gbBattery = 1; + break; + } + + gbInit(); + gbReset(); + + return true; } void gbEmulate(int ticksToStop) { - gbRegister tempRegister; - u8 tempValue; - s8 offset; - - int clockTicks = 0; - gbDmaTicks = 0; - - register int opcode = 0; - - u32 newmask = 0; - if (newFrame) + printf("RLM: Inside the GB!\n"); + gbRegister tempRegister; + u8 tempValue; + s8 offset; + + int clockTicks = 0; + gbDmaTicks = 0; + + register int opcode = 0; + + u32 newmask = 0; + printf("RLM: newframe = %d\n", newFrame); + if (newFrame) + { + extern void VBAOnExitingFrameBoundary(); + VBAOnExitingFrameBoundary(); + printf("RLM: exiting frame boundary?\n"); + // update joystick information + systemReadJoypads(); + + bool sensor = (gbRom[0x147] == 0x22); + + // read joystick + if (gbSgbMode && gbSgbMultiplayer) { - extern void VBAOnExitingFrameBoundary(); - VBAOnExitingFrameBoundary(); - - // update joystick information - systemReadJoypads(); - - bool sensor = (gbRom[0x147] == 0x22); - - // read joystick - if (gbSgbMode && gbSgbMultiplayer) + if (gbSgbFourPlayers) + { + gbJoymask[0] = systemGetJoypad(0, sensor); + gbJoymask[1] = systemGetJoypad(1, false); + gbJoymask[2] = systemGetJoypad(2, false); + gbJoymask[3] = systemGetJoypad(3, false); + } + else + { + gbJoymask[0] = systemGetJoypad(0, sensor); + gbJoymask[1] = systemGetJoypad(1, false); + } + } + else + { + gbJoymask[0] = systemGetJoypad(0, sensor); + } + + // FIXME: horrible kludge + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); + + // if (sensor) + // systemUpdateMotionSensor(0); + + newmask = gbJoymask[0]; + if (newmask & 0xFF) + { + gbInterrupt |= 16; + } + + extButtons = (newmask >> 18); + speedup = (extButtons & 1) != 0; + + VBAMovieResetIfRequested(); + printf("RLM: before Lua functions\n"); + //CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); + printf("RLM: after Lua functions\n"); + newFrame = false; + } + + + for (;; ) + { +#ifndef FINAL_VERSION + if (systemDebug) + { + if (!(IFF & 0x80)) + { + if (systemDebug > 1) { - if (gbSgbFourPlayers) + sprintf(gbBuffer, "PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n", + PC.W, AF.W, BC.W, DE.W, HL.W, SP.W, IFF); + } + else + { + sprintf(gbBuffer, "PC=%04x I=%02x\n", PC.W, IFF); + } + log(gbBuffer); + } + } +#endif + if (IFF & 0x80) + { + if (register_LCDC & 0x80) + { + clockTicks = gbLcdTicks; + } + else + clockTicks = 100; + + if (gbLcdMode == 1 && (gbLcdLYIncrementTicks < clockTicks)) + clockTicks = gbLcdLYIncrementTicks; + + if (gbSerialOn && (gbSerialTicks < clockTicks)) + clockTicks = gbSerialTicks; + + if (gbTimerOn && (gbTimerTicks < clockTicks)) + clockTicks = gbTimerTicks; + + if (soundTicks && (soundTicks < clockTicks)) + clockTicks = soundTicks; + } + else + { + opcode = gbReadOpcode(PC.W); + CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); + PC.W++; + + if (IFF & 0x100) + { + IFF &= 0xff; + PC.W--; + } + + clockTicks = gbCycles[opcode]; + + switch (opcode) + { + case 0xCB: + // extended opcode + //CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); // is this desired? + opcode = gbReadOpcode(PC.W++); + clockTicks = gbCyclesCB[opcode]; + switch (opcode) + { +#include "gbCodesCB.h" + } + break; +#include "gbCodes.h" + } + } + + if (!emulating) + return; + + if (gbDmaTicks) + { + clockTicks += gbDmaTicks; + gbDmaTicks = 0; + } + + if (gbSgbMode) + { + if (gbSgbPacketTimeout) + { + gbSgbPacketTimeout -= clockTicks; + + if (gbSgbPacketTimeout <= 0) + gbSgbResetPacketState(); + } + } + + ticksToStop -= clockTicks; + + // DIV register emulation + gbDivTicks -= clockTicks; + while (gbDivTicks <= 0) + { + register_DIV++; + gbDivTicks += GBDIV_CLOCK_TICKS; + } + + if (register_LCDC & 0x80) + { + // LCD stuff + gbLcdTicks -= clockTicks; + if (gbLcdMode == 1) + { + // during V-BLANK,we need to increment LY at the same rate! + gbLcdLYIncrementTicks -= clockTicks; + while (gbLcdLYIncrementTicks <= 0) + { + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; + + if (register_LY < 153) + { + register_LY++; + + gbCompareLYToLYC(); + + if (register_LY >= 153) + gbLcdLYIncrementTicks = 6; + } + else + { + register_LY = 0x00; + // reset the window line + gbWindowLine = -1; + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2; + gbCompareLYToLYC(); + } + } + } + + // our counter is off, see what we need to do + while (gbLcdTicks <= 0) + { + int framesToSkip = systemFramesToSkip(); + + switch (gbLcdMode) + { + case 0: + // H-Blank + register_LY++; + + gbCompareLYToLYC(); + + // check if we reached the V-Blank period + if (register_LY == 144) + { + // Yes, V-Blank + // set the LY increment counter + gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS; + gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; + gbLcdMode = 1; + if (register_LCDC & 0x80) { - gbJoymask[0] = systemGetJoypad(0, sensor); - gbJoymask[1] = systemGetJoypad(1, false); - gbJoymask[2] = systemGetJoypad(2, false); - gbJoymask[3] = systemGetJoypad(3, false); + gbInterrupt |= 1; // V-Blank interrupt + gbInterruptWait = 6; + if (register_STAT & 0x10) + gbInterrupt |= 2; } - else + + systemFrame(); + + ++gbFrameCount; + u32 currentTime = systemGetClock(); + if (currentTime - gbLastTime >= 1000) { - gbJoymask[0] = systemGetJoypad(0, sensor); - gbJoymask[1] = systemGetJoypad(1, false); + systemShowSpeed(int(float(gbFrameCount) * 100000 / (float(currentTime - gbLastTime) * 60) + .5f)); + gbLastTime = currentTime; + gbFrameCount = 0; } + + ++GBSystemCounters.frameCount; + if (GBSystemCounters.lagged) + { + ++GBSystemCounters.lagCount; + } + GBSystemCounters.laggedLast = GBSystemCounters.lagged; + GBSystemCounters.lagged = true; + + extern void VBAOnEnteringFrameBoundary(); + VBAOnEnteringFrameBoundary(); + + newFrame = true; + + pauseAfterFrameAdvance = systemPauseOnFrame(); + + if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) + { + if (gbBorderOn) + gbSgbRenderBorder(); // clear unnecessary things on border (e.g. in-game text message) + + systemRenderFrame(); + gbFrameSkipCount = 0; + + bool capturePressed = (extButtons & 2) != 0; + if (capturePressed && !capturePrevious) + { + captureNumber = systemScreenCapture(captureNumber); + } + capturePrevious = capturePressed && !pauseAfterFrameAdvance; + } + else + { + ++gbFrameSkipCount; + } + + if (pauseAfterFrameAdvance) + { + systemSetPause(true); + } + } + else + { + // go the the OAM being accessed mode + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdMode = 2; + + // only one LCD interrupt per line. may need to generalize... + if (!(register_STAT & 0x40) || + (register_LY != register_LYC)) + { + if ((register_STAT & 0x28) == 0x20) + gbInterrupt |= 2; + } + } + + break; + case 1: + // V-Blank + // next mode is OAM being accessed mode + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; + gbLcdMode = 2; + if (!(register_STAT & 0x40) || + (register_LY != register_LYC)) + { + if ((register_STAT & 0x28) == 0x20) + gbInterrupt |= 2; + } + break; + case 2: + // OAM being accessed mode + + // next mode is OAM and VRAM in use + gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS; + gbLcdMode = 3; + break; + case 3: + // OAM and VRAM in use + // next mode is H-Blank + if (register_LY < 144) + { + if (!gbSgbMask) + { + if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) + { + gbRenderLine(); + gbDrawSprites(); + + switch (systemColorDepth) + { + case 16: + + { + u16 *dest = (u16 *)pix + + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1) + + gbBorderColumnSkip; + for (int x = 0; x < 160; ) + { + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + *dest++ = systemColorMap16[gbLineMix[x++]]; + } + if (gbBorderOn) + dest += gbBorderColumnSkip; + *dest++ = 0; // for filters that read one pixel more + break; + } + case 24: + + { + u8 *dest = (u8 *)pix + + 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + + gbBorderColumnSkip); + for (int x = 0; x < 160; ) + { + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; + dest += 3; + } + break; + } + case 32: + + { + u32 *dest = (u32 *)pix + + (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1) + + gbBorderColumnSkip; + for (int x = 0; x < 160; ) + { + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + *dest++ = systemColorMap32[gbLineMix[x++]]; + } + break; + } + } + } + } + } + gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS; + gbLcdMode = 0; + // only one LCD interrupt per line. may need to generalize... + if (!(register_STAT & 0x40) || + (register_LY != register_LYC)) + { + if (register_STAT & 0x08) + gbInterrupt |= 2; + } + if (gbHdmaOn) + { + gbDoHdma(); + } + break; } - else + // mark the correct lcd mode on STAT register + register_STAT = (register_STAT & 0xfc) | gbLcdMode; + } + } + + // serial emulation + if (gbSerialOn) + { +#ifdef LINK_EMULATION + if (linkConnected) + { + gbSerialTicks -= clockTicks; + + while (gbSerialTicks <= 0) { - gbJoymask[0] = systemGetJoypad(0, sensor); + // increment number of shifted bits + gbSerialBits++; + linkProc(); + if (gbSerialOn && (gbMemory[0xff02] & 1)) + { + if (gbSerialBits == 8) + { + gbSerialBits = 0; + gbMemory[0xff01] = 0xff; + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbInterrupt |= 8; + gbSerialTicks = 0; + } + } + gbSerialTicks += GBSERIAL_CLOCK_TICKS; } - - // FIXME: horrible kludge - memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); - -// if (sensor) -// systemUpdateMotionSensor(0); - - newmask = gbJoymask[0]; - if (newmask & 0xFF) + } + else + { +#endif + if (gbMemory[0xff02] & 1) { - gbInterrupt |= 16; + gbSerialTicks -= clockTicks; + + // overflow + while (gbSerialTicks <= 0) + { + // shift serial byte to right and put a 1 bit in its place + // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); + // increment number of shifted bits + gbSerialBits++; + if (gbSerialBits == 8) + { + // end of transmission + if (gbSerialFunction) // external device + gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); + else + gbMemory[0xff01] = 0xff; + gbSerialTicks = 0; + gbMemory[0xff02] &= 0x7f; + gbSerialOn = 0; + gbInterrupt |= 8; + gbSerialBits = 0; + } + else + gbSerialTicks += GBSERIAL_CLOCK_TICKS; + } } - - extButtons = (newmask >> 18); - speedup = (extButtons & 1) != 0; - - VBAMovieResetIfRequested(); - - CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); - - newFrame = false; +#ifdef LINK_EMULATION + } +#endif } - for (;; ) + // timer emulation + if (gbTimerOn) { -#ifndef FINAL_VERSION - if (systemDebug) + gbTimerTicks -= clockTicks; + + while (gbTimerTicks <= 0) + { + register_TIMA++; + + if (register_TIMA == 0) { - if (!(IFF & 0x80)) + // timer overflow! + + // reload timer modulo + register_TIMA = register_TMA; + + // flag interrupt + gbInterrupt |= 4; + } + + gbTimerTicks += gbTimerClockTicks; + } + } + + /* + if(soundOffFlag) + { + if(synchronize && !speedup) + { + synchronizeTicks -= clockTicks; + + while(synchronizeTicks < 0) + { + synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS; + + DWORD now = timeGetTime(); + gbElapsedTime += (now - timeNow); + + if(gbElapsedTime < 50) + { + DWORD diff = 50 - gbElapsedTime; + Sleep(diff); + timeNow = timeGetTime(); + elapsedTime = timeNow - now - diff; + if((int)elapsedTime < 0) + elapsedTime = 0; + } else + { + timeNow = timeGetTime(); + elapsedTime = 0; + } + } + } + } + */ + + soundTicks -= clockTicks; + while (soundTicks < 0) // must be < 1 when soundtick_t is real data type + { + soundTicks += SOUND_CLOCK_TICKS; + + gbSoundTick(); + } + + register_IF = gbInterrupt; + + if (IFF & 0x20) + { + IFF &= 0xdf; + IFF |= 0x01; + gbInterruptWait = 0; + } + else if (gbInterrupt) + { + if (gbInterruptWait == 0) + { + // gbInterruptWait = 0; + + if (IFF & 0x01) + { + if ((gbInterrupt & 1) && (register_IE & 1)) + { + gbVblank_interrupt(); + continue; + } + + if ((gbInterrupt & 2) && (register_IE & 2)) + { + gbLcd_interrupt(); + continue; + } + + if ((gbInterrupt & 4) && (register_IE & 4)) + { + gbTimer_interrupt(); + continue; + } + + if ((gbInterrupt & 8) && (register_IE & 8)) + { + gbSerial_interrupt(); + continue; + } + + if ((gbInterrupt & 16) && (register_IE & 16)) + { + gbJoypad_interrupt(); + continue; + } + } + } + else + { + gbInterruptWait -= clockTicks; + if (gbInterruptWait < 0) + gbInterruptWait = 0; + } + } + + if (useOldFrameTiming) + { + // old timing code + if (ticksToStop > 0) + continue; + } + else + { + if (!newFrame && (register_LCDC & 0x80) != 0) + continue; + } + + if (!(register_LCDC & 0x80)) + { + if (!useOldFrameTiming) + { + // FIXME: since register_LY can be reset to 0 by some games, frame length is variable + // and infinite loops can occurr + // for now, it IS necessary to do something on this condition or games like + // Megaman would freeze upon low-level restart interrupt sequence (Start+Select+A+B). + // the only sensible way to fix this issue is to implement the RIGHT frame timing +#ifdef WANTS_INCOMPLETE_WORKAROUND + if (systemReadJoypads()) + { + if (gbSgbMode && gbSgbMultiplayer) + { + if (gbSgbFourPlayers) { - if (systemDebug > 1) - { - sprintf(gbBuffer, "PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n", - PC.W, AF.W, BC.W, DE.W, HL.W, SP.W, IFF); - } - else - { - sprintf(gbBuffer, "PC=%04x I=%02x\n", PC.W, IFF); - } - log(gbBuffer); + gbJoymask[0] = systemGetJoypad(0, false); + gbJoymask[1] = systemGetJoypad(1, false); + gbJoymask[2] = systemGetJoypad(2, false); + gbJoymask[3] = systemGetJoypad(3, false); } + else + { + gbJoymask[0] = systemGetJoypad(0, false); + gbJoymask[1] = systemGetJoypad(1, false); + } + } + else + { + gbJoymask[0] = systemGetJoypad(0, false); + } } -#endif - if (IFF & 0x80) - { - if (register_LCDC & 0x80) - { - clockTicks = gbLcdTicks; - } - else - clockTicks = 100; - - if (gbLcdMode == 1 && (gbLcdLYIncrementTicks < clockTicks)) - clockTicks = gbLcdLYIncrementTicks; - - if (gbSerialOn && (gbSerialTicks < clockTicks)) - clockTicks = gbSerialTicks; - - if (gbTimerOn && (gbTimerTicks < clockTicks)) - clockTicks = gbTimerTicks; - - if (soundTicks && (soundTicks < clockTicks)) - clockTicks = soundTicks; - } - else - { - opcode = gbReadOpcode(PC.W); - CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); - PC.W++; - - if (IFF & 0x100) - { - IFF &= 0xff; - PC.W--; - } - - clockTicks = gbCycles[opcode]; - - switch (opcode) - { - case 0xCB: - // extended opcode - //CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); // is this desired? - opcode = gbReadOpcode(PC.W++); - clockTicks = gbCyclesCB[opcode]; - switch (opcode) - { -#include "gbCodesCB.h" - } - break; -#include "gbCodes.h" - } - } - - if (!emulating) - return; - - if (gbDmaTicks) - { - clockTicks += gbDmaTicks; - gbDmaTicks = 0; - } - - if (gbSgbMode) - { - if (gbSgbPacketTimeout) - { - gbSgbPacketTimeout -= clockTicks; - - if (gbSgbPacketTimeout <= 0) - gbSgbResetPacketState(); - } - } - - ticksToStop -= clockTicks; - - // DIV register emulation - gbDivTicks -= clockTicks; - while (gbDivTicks <= 0) - { - register_DIV++; - gbDivTicks += GBDIV_CLOCK_TICKS; - } - - if (register_LCDC & 0x80) - { - // LCD stuff - gbLcdTicks -= clockTicks; - if (gbLcdMode == 1) - { - // during V-BLANK,we need to increment LY at the same rate! - gbLcdLYIncrementTicks -= clockTicks; - while (gbLcdLYIncrementTicks <= 0) - { - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; - - if (register_LY < 153) - { - register_LY++; - - gbCompareLYToLYC(); - - if (register_LY >= 153) - gbLcdLYIncrementTicks = 6; - } - else - { - register_LY = 0x00; - // reset the window line - gbWindowLine = -1; - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2; - gbCompareLYToLYC(); - } - } - } - - // our counter is off, see what we need to do - while (gbLcdTicks <= 0) - { - int framesToSkip = systemFramesToSkip(); - - switch (gbLcdMode) - { - case 0: - // H-Blank - register_LY++; - - gbCompareLYToLYC(); - - // check if we reached the V-Blank period - if (register_LY == 144) - { - // Yes, V-Blank - // set the LY increment counter - gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS; - gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; - gbLcdMode = 1; - if (register_LCDC & 0x80) - { - gbInterrupt |= 1; // V-Blank interrupt - gbInterruptWait = 6; - if (register_STAT & 0x10) - gbInterrupt |= 2; - } - - systemFrame(); - - ++gbFrameCount; - u32 currentTime = systemGetClock(); - if (currentTime - gbLastTime >= 1000) - { - systemShowSpeed(int(float(gbFrameCount) * 100000 / (float(currentTime - gbLastTime) * 60) + .5f)); - gbLastTime = currentTime; - gbFrameCount = 0; - } - - ++GBSystemCounters.frameCount; - if (GBSystemCounters.lagged) - { - ++GBSystemCounters.lagCount; - } - GBSystemCounters.laggedLast = GBSystemCounters.lagged; - GBSystemCounters.lagged = true; - - extern void VBAOnEnteringFrameBoundary(); - VBAOnEnteringFrameBoundary(); - - newFrame = true; - - pauseAfterFrameAdvance = systemPauseOnFrame(); - - if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) - { - if (gbBorderOn) - gbSgbRenderBorder(); // clear unnecessary things on border (e.g. in-game text message) - - systemRenderFrame(); - gbFrameSkipCount = 0; - - bool capturePressed = (extButtons & 2) != 0; - if (capturePressed && !capturePrevious) - { - captureNumber = systemScreenCapture(captureNumber); - } - capturePrevious = capturePressed && !pauseAfterFrameAdvance; - } - else - { - ++gbFrameSkipCount; - } - - if (pauseAfterFrameAdvance) - { - systemSetPause(true); - } - } - else - { - // go the the OAM being accessed mode - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdMode = 2; - - // only one LCD interrupt per line. may need to generalize... - if (!(register_STAT & 0x40) || - (register_LY != register_LYC)) - { - if ((register_STAT & 0x28) == 0x20) - gbInterrupt |= 2; - } - } - - break; - case 1: - // V-Blank - // next mode is OAM being accessed mode - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; - gbLcdMode = 2; - if (!(register_STAT & 0x40) || - (register_LY != register_LYC)) - { - if ((register_STAT & 0x28) == 0x20) - gbInterrupt |= 2; - } - break; - case 2: - // OAM being accessed mode - - // next mode is OAM and VRAM in use - gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS; - gbLcdMode = 3; - break; - case 3: - // OAM and VRAM in use - // next mode is H-Blank - if (register_LY < 144) - { - if (!gbSgbMask) - { - if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) - { - gbRenderLine(); - gbDrawSprites(); - - switch (systemColorDepth) - { - case 16: - - { - u16 *dest = (u16 *)pix + - (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1) - + gbBorderColumnSkip; - for (int x = 0; x < 160; ) - { - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - *dest++ = systemColorMap16[gbLineMix[x++]]; - } - if (gbBorderOn) - dest += gbBorderColumnSkip; - *dest++ = 0; // for filters that read one pixel more - break; - } - case 24: - - { - u8 *dest = (u8 *)pix + - 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + - gbBorderColumnSkip); - for (int x = 0; x < 160; ) - { - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; - dest += 3; - } - break; - } - case 32: - - { - u32 *dest = (u32 *)pix + - (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1) - + gbBorderColumnSkip; - for (int x = 0; x < 160; ) - { - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - *dest++ = systemColorMap32[gbLineMix[x++]]; - } - break; - } - } - } - } - } - gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS; - gbLcdMode = 0; - // only one LCD interrupt per line. may need to generalize... - if (!(register_STAT & 0x40) || - (register_LY != register_LYC)) - { - if (register_STAT & 0x08) - gbInterrupt |= 2; - } - if (gbHdmaOn) - { - gbDoHdma(); - } - break; - } - // mark the correct lcd mode on STAT register - register_STAT = (register_STAT & 0xfc) | gbLcdMode; - } - } - - // serial emulation - if (gbSerialOn) - { -#ifdef LINK_EMULATION - if (linkConnected) - { - gbSerialTicks -= clockTicks; - - while (gbSerialTicks <= 0) - { - // increment number of shifted bits - gbSerialBits++; - linkProc(); - if (gbSerialOn && (gbMemory[0xff02] & 1)) - { - if (gbSerialBits == 8) - { - gbSerialBits = 0; - gbMemory[0xff01] = 0xff; - gbMemory[0xff02] &= 0x7f; - gbSerialOn = 0; - gbInterrupt |= 8; - gbSerialTicks = 0; - } - } - gbSerialTicks += GBSERIAL_CLOCK_TICKS; - } - } - else - { -#endif - if (gbMemory[0xff02] & 1) - { - gbSerialTicks -= clockTicks; - - // overflow - while (gbSerialTicks <= 0) - { - // shift serial byte to right and put a 1 bit in its place - // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); - // increment number of shifted bits - gbSerialBits++; - if (gbSerialBits == 8) - { - // end of transmission - if (gbSerialFunction) // external device - gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); - else - gbMemory[0xff01] = 0xff; - gbSerialTicks = 0; - gbMemory[0xff02] &= 0x7f; - gbSerialOn = 0; - gbInterrupt |= 8; - gbSerialBits = 0; - } - else - gbSerialTicks += GBSERIAL_CLOCK_TICKS; - } - } -#ifdef LINK_EMULATION - } -#endif - } - - // timer emulation - if (gbTimerOn) - { - gbTimerTicks -= clockTicks; - - while (gbTimerTicks <= 0) - { - register_TIMA++; - - if (register_TIMA == 0) - { - // timer overflow! - - // reload timer modulo - register_TIMA = register_TMA; - - // flag interrupt - gbInterrupt |= 4; - } - - gbTimerTicks += gbTimerClockTicks; - } - } - - /* - if(soundOffFlag) - { - if(synchronize && !speedup) - { - synchronizeTicks -= clockTicks; - - while(synchronizeTicks < 0) - { - synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS; - - DWORD now = timeGetTime(); - gbElapsedTime += (now - timeNow); - - if(gbElapsedTime < 50) - { - DWORD diff = 50 - gbElapsedTime; - Sleep(diff); - timeNow = timeGetTime(); - elapsedTime = timeNow - now - diff; - if((int)elapsedTime < 0) - elapsedTime = 0; - } else - { - timeNow = timeGetTime(); - elapsedTime = 0; - } - } - } - } - */ - - soundTicks -= clockTicks; - while (soundTicks < 0) // must be < 1 when soundtick_t is real data type - { - soundTicks += SOUND_CLOCK_TICKS; - - gbSoundTick(); - } - - register_IF = gbInterrupt; - - if (IFF & 0x20) - { - IFF &= 0xdf; - IFF |= 0x01; - gbInterruptWait = 0; - } - else if (gbInterrupt) - { - if (gbInterruptWait == 0) - { - // gbInterruptWait = 0; - - if (IFF & 0x01) - { - if ((gbInterrupt & 1) && (register_IE & 1)) - { - gbVblank_interrupt(); - continue; - } - - if ((gbInterrupt & 2) && (register_IE & 2)) - { - gbLcd_interrupt(); - continue; - } - - if ((gbInterrupt & 4) && (register_IE & 4)) - { - gbTimer_interrupt(); - continue; - } - - if ((gbInterrupt & 8) && (register_IE & 8)) - { - gbSerial_interrupt(); - continue; - } - - if ((gbInterrupt & 16) && (register_IE & 16)) - { - gbJoypad_interrupt(); - continue; - } - } - } - else - { - gbInterruptWait -= clockTicks; - if (gbInterruptWait < 0) - gbInterruptWait = 0; - } - } - - if (useOldFrameTiming) - { - // old timing code - if (ticksToStop > 0) - continue; - } - else - { - if (!newFrame && (register_LCDC & 0x80) != 0) - continue; - } - - if (!(register_LCDC & 0x80)) - { - if (!useOldFrameTiming) - { - // FIXME: since register_LY can be reset to 0 by some games, frame length is variable - // and infinite loops can occurr - // for now, it IS necessary to do something on this condition or games like - // Megaman would freeze upon low-level restart interrupt sequence (Start+Select+A+B). - // the only sensible way to fix this issue is to implement the RIGHT frame timing -#ifdef WANTS_INCOMPLETE_WORKAROUND - if (systemReadJoypads()) - { - if (gbSgbMode && gbSgbMultiplayer) - { - if (gbSgbFourPlayers) - { - gbJoymask[0] = systemGetJoypad(0, false); - gbJoymask[1] = systemGetJoypad(1, false); - gbJoymask[2] = systemGetJoypad(2, false); - gbJoymask[3] = systemGetJoypad(3, false); - } - else - { - gbJoymask[0] = systemGetJoypad(0, false); - gbJoymask[1] = systemGetJoypad(1, false); - } - } - else - { - gbJoymask[0] = systemGetJoypad(0, false); - } - } - else - gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; + else + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; #else #endif - } - } - - // makes sure frames are really divided across input sampling boundaries which occur at a constant rate - if (newFrame || useOldFrameTiming) - { -/// extern void VBAOnEnteringFrameBoundary(); -/// VBAOnEnteringFrameBoundary(); - - break; - } + } } + + // makes sure frames are really divided across input sampling boundaries which occur at a constant rate + if (newFrame || useOldFrameTiming) + { + /// extern void VBAOnEnteringFrameBoundary(); + /// VBAOnEnteringFrameBoundary(); + + break; + } + } } struct EmulatedSystem GBSystem = -{ - // emuMain - gbEmulate, - // emuReset - gbReset, - // emuCleanUp - gbCleanUp, - // emuReadBattery - gbReadBatteryFile, - // emuWriteBattery - gbWriteBatteryFile, - // emuReadBatteryFromStream - gbReadBatteryFromStream, - // emuWriteBatteryToStream - gbWriteBatteryToStream, - // emuReadState - gbReadSaveState, - // emuWriteState - gbWriteSaveState, - // emuReadStateFromStream - gbReadSaveStateFromStream, - // emuWriteStateToStream - gbWriteSaveStateToStream, - // emuReadMemState - gbReadMemSaveState, - // emuWriteMemState - gbWriteMemSaveState, - // emuWritePNG - gbWritePNGFile, - // emuWriteBMP - gbWriteBMPFile, - // emuUpdateCPSR - NULL, - // emuHasDebugger - false, - // emuCount + { + // emuMain + gbEmulate, + // emuReset + gbReset, + // emuCleanUp + gbCleanUp, + // emuReadBattery + gbReadBatteryFile, + // emuWriteBattery + gbWriteBatteryFile, + // emuReadBatteryFromStream + gbReadBatteryFromStream, + // emuWriteBatteryToStream + gbWriteBatteryToStream, + // emuReadState + gbReadSaveState, + // emuWriteState + gbWriteSaveState, + // emuReadStateFromStream + gbReadSaveStateFromStream, + // emuWriteStateToStream + gbWriteSaveStateToStream, + // emuReadMemState + gbReadMemSaveState, + // emuWriteMemState + gbWriteMemSaveState, + // emuWritePNG + gbWritePNGFile, + // emuWriteBMP + gbWriteBMPFile, + // emuUpdateCPSR + NULL, + // emuHasDebugger + false, + // emuCount #ifdef FINAL_VERSION - 70000 / 4, + 70000 / 4, #else - 1000, + 1000, #endif -}; + }; // is there a reason to use more than one set of counters? EmulatedSystemCounters &GBSystemCounters = systemCounters; /* - EmulatedSystemCounters GBSystemCounters = - { - // frameCount - 0, - // lagCount - 0, - // lagged - true, - // laggedLast - true, - }; - */ + EmulatedSystemCounters GBSystemCounters = + { + // frameCount + 0, + // lagCount + 0, + // lagged + true, + // laggedLast + true, + }; +*/ diff -r 0dc331ec7f27 -r 44974c3e093b src/lua/loadlib.c --- a/src/lua/loadlib.c Sun Mar 04 22:44:42 2012 -0600 +++ b/src/lua/loadlib.c Mon Mar 05 01:25:11 2012 -0600 @@ -424,7 +424,7 @@ funcname = mkfuncname(L, name); if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { if (stat != ERRFUNC) loaderror(L, filename); /* real error */ - lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, + lua_pushfstring(L, "\n\tno module " LUA_QS " in derp " LUA_QS, name, filename); return 1; /* function not found */ } diff -r 0dc331ec7f27 -r 44974c3e093b src/sdl/SDL.cpp --- a/src/sdl/SDL.cpp Sun Mar 04 22:44:42 2012 -0600 +++ b/src/sdl/SDL.cpp Mon Mar 05 01:25:11 2012 -0600 @@ -1966,6 +1966,7 @@ void file_run() { + printf("RLM: file_run\n"); utilGetBaseName(szFile, filename); char *p = strrchr(filename, '.'); @@ -1989,7 +1990,8 @@ failed = !gbLoadRom(szFile); if(!failed) { systemCartridgeType = 1; - theEmulator = GBSystem; + printf("RLM: choosing GBSystem\n"); + theEmulator = GBSystem; if(sdlAutoIPS) { int size = gbRomSize; utilApplyIPS(ipsname, &gbRom, &size); @@ -2007,7 +2009,7 @@ // if(cpuEnhancedDetection && cpuSaveType == 0) { // utilGBAFindSave(rom, size); // } - + sdlApplyPerImagePreferences(); systemCartridgeType = 0; @@ -2183,7 +2185,7 @@ case 'r': if(optarg == NULL) { - fprintf(stderr, "ERROR: --recordMovie ('r') needs movie filename as option\n"); + fprintf(stderr, "ERROR: --recordmovie ('r') needs movie filename as option\n"); exit(-1); } strcpy(movieFileName, optarg); @@ -2192,7 +2194,7 @@ case 'p': // play without read-only (editable) fprintf (stderr, "-p got called!\n"); if(optarg == NULL) { - fprintf(stderr, "ERROR: --playMovie ('p') needs movie filename as option\n"); + fprintf(stderr, "ERROR: --playmovie ('p') needs movie filename as option\n"); exit(-1); } strcpy(movieFileName, optarg); @@ -2201,7 +2203,7 @@ case 'w': // play with read-only fprintf (stderr, "-w got called!\n"); if(optarg == NULL) { - fprintf(stderr, "ERROR: --watchMovie ('w') needs movie filename as option\n"); + fprintf(stderr, "ERROR: --watchmovie ('w') needs movie filename as option\n"); exit(-1); } strcpy(movieFileName, optarg); @@ -2271,6 +2273,8 @@ } } + printf("RLM: derpy loves you!\n"); + printf("RLM: useMovie: %d (1 is record)\n", useMovie); if(sdlPrintUsage) { usage(argv[0]); exit(-1); @@ -2317,6 +2321,7 @@ { szFile = argv[optind]; file_run(); + printf("RLM: file_run() done\n"); } else { @@ -2336,7 +2341,7 @@ //CPUInit(biosFileName, useBios); CPUInit(); - CPUReset(); + CPUReset(); } if(debuggerStub) @@ -2615,6 +2620,7 @@ soundInit(); autoFrameSkipLastTime = throttleLastTime = systemGetClock(); + printf("RLM: and now for the movie part!\n"); switch(useMovie) { @@ -2635,13 +2641,14 @@ sdlReadBattery(); break; } + printf("RLM: still alive after movie switch\n"); SDL_WM_SetCaption("VisualBoyAdvance", NULL); char *moviefile = getenv("AUTODEMO"); -// fprintf (stderr, "Checking for AUTODEMO...\n"); + fprintf (stderr, "Checking for AUTODEMO...\n"); if (moviefile) { -// fprintf (stderr, "I got a filename OMG!\nCalling VBAMovieOpen...\n"); + fprintf (stderr, "I got a filename OMG!\nCalling VBAMovieOpen...\n"); VBAMovieOpen(moviefile, true); } @@ -2650,7 +2657,9 @@ if(debugger && theEmulator.emuHasDebugger) dbgMain(); else { - theEmulator.emuMain(theEmulator.emuCount); + printf("RLM: emulator main\n"); + theEmulator.emuMain(theEmulator.emuCount); + printf("RLM: emulator main called\n"); if(rewindSaveNeeded && rewindMemory && theEmulator.emuWriteMemState) { rewindCount++; if(rewindCount > 8) @@ -3605,14 +3614,17 @@ void VBAOnEnteringFrameBoundary() { - CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); - - if (VBALuaRunning()) - { - VBALuaFrameBoundary(); - } - - VBAMovieUpdateState(); + printf("RLM: Entering Frame Boundary\n"); + CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); + + if (VBALuaRunning()) + { + VBALuaFrameBoundary(); + } + + printf("RLM: Movie state update pending\n"); + VBAMovieUpdateState(); + printf("RLM: Movie state updated\n"); } void VBAOnExitingFrameBoundary()