Mercurial > vba-clojure
changeset 33:44974c3e093b
found source of problem for video recording
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 05 Mar 2012 01:25:11 -0600 |
parents | 0dc331ec7f27 |
children | 6bde5b67a2b8 |
files | commands.sh src/common/movie.cpp src/gb/GB.cpp src/lua/loadlib.c src/sdl/SDL.cpp |
diffstat | 5 files changed, 4723 insertions(+), 4684 deletions(-) [+] |
line wrap: on
line diff
1.1 --- a/commands.sh Sun Mar 04 22:44:42 2012 -0600 1.2 +++ b/commands.sh Mon Mar 05 01:25:11 2012 -0600 1.3 @@ -1,12 +1,21 @@ 1.4 + 1.5 # This buffer is for notes you don't want to save, and for Lisp evaluation. 1.6 # If you want to create a file, visit that file with C-x C-f, 1.7 # then enter the text in that file's own buffer. 1.8 1.9 1.10 -./VisualBoyAdvance ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc 1.11 +#./VisualBoyAdvance ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc 1.12 1.13 1.14 -./VisualBoyAdvance --recordmovie=./rlm.vbm ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc 1.15 +#./VisualBoyAdvance --recordmovie=./rlm.vbm ../../../pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc 1.16 1.17 +rm -f /home/r/proj/vba-restore/build/movie.vba 1.18 1.19 -./VisualBoyAdvance --recordmovie=/home/r/proj/vba-restore/build/ /home/r/proj/pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc 1.20 \ No newline at end of file 1.21 +cd /home/r/proj/vba-restore/build 1.22 +make install 1.23 + 1.24 +/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 1.25 + 1.26 +#.//VisualBoyAdvance --playmovie=/home/r/proj/vba-restore/build/movie.vba /home/r/proj/pokemon-escape/roms/Pokemon\ Yellow\ \(U\)\ \[C\]\[\!\].gbc 1.27 + 1.28 +hexdump -C /home/r/proj/vba-restore/build/movie.vba
2.1 --- a/src/common/movie.cpp Sun Mar 04 22:44:42 2012 -0600 2.2 +++ b/src/common/movie.cpp Mon Mar 05 01:25:11 2012 -0600 2.3 @@ -73,1613 +73,1628 @@ 2.4 // little-endian integer pop/push functions: 2.5 static inline uint32 Pop32(const uint8 * &ptr) 2.6 { 2.7 - uint32 v = (ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); 2.8 - ptr += 4; 2.9 - return v; 2.10 + uint32 v = (ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); 2.11 + ptr += 4; 2.12 + return v; 2.13 } 2.14 2.15 static inline uint16 Pop16(const uint8 * &ptr) /* const version */ 2.16 { 2.17 - uint16 v = (ptr[0] | (ptr[1] << 8)); 2.18 - ptr += 2; 2.19 - return v; 2.20 + uint16 v = (ptr[0] | (ptr[1] << 8)); 2.21 + ptr += 2; 2.22 + return v; 2.23 } 2.24 2.25 static inline uint16 Pop16(uint8 * &ptr) /* non-const version */ 2.26 { 2.27 - uint16 v = (ptr[0] | (ptr[1] << 8)); 2.28 - ptr += 2; 2.29 - return v; 2.30 + uint16 v = (ptr[0] | (ptr[1] << 8)); 2.31 + ptr += 2; 2.32 + return v; 2.33 } 2.34 2.35 static inline uint8 Pop8(const uint8 * &ptr) 2.36 { 2.37 - return *(ptr)++; 2.38 + return *(ptr)++; 2.39 } 2.40 2.41 static inline void Push32(uint32 v, uint8 * &ptr) 2.42 { 2.43 - ptr[0] = (uint8)(v & 0xff); 2.44 - ptr[1] = (uint8)((v >> 8) & 0xff); 2.45 - ptr[2] = (uint8)((v >> 16) & 0xff); 2.46 - ptr[3] = (uint8)((v >> 24) & 0xff); 2.47 - ptr += 4; 2.48 + ptr[0] = (uint8)(v & 0xff); 2.49 + ptr[1] = (uint8)((v >> 8) & 0xff); 2.50 + ptr[2] = (uint8)((v >> 16) & 0xff); 2.51 + ptr[3] = (uint8)((v >> 24) & 0xff); 2.52 + ptr += 4; 2.53 } 2.54 2.55 static inline void Push16(uint16 v, uint8 * &ptr) 2.56 { 2.57 - ptr[0] = (uint8)(v & 0xff); 2.58 - ptr[1] = (uint8)((v >> 8) & 0xff); 2.59 - ptr += 2; 2.60 + ptr[0] = (uint8)(v & 0xff); 2.61 + ptr[1] = (uint8)((v >> 8) & 0xff); 2.62 + ptr += 2; 2.63 } 2.64 2.65 static inline void Push8(uint8 v, uint8 * &ptr) 2.66 { 2.67 - *ptr++ = v; 2.68 + *ptr++ = v; 2.69 } 2.70 2.71 // little-endian integer read/write functions: 2.72 static inline uint16 Read16(const uint8 *ptr) 2.73 { 2.74 - return ptr[0] | (ptr[1] << 8); 2.75 + return ptr[0] | (ptr[1] << 8); 2.76 } 2.77 2.78 static inline void Write16(uint16 v, uint8 *ptr) 2.79 { 2.80 - ptr[0] = uint8(v & 0xff); 2.81 - ptr[1] = uint8((v >> 8) & 0xff); 2.82 + ptr[0] = uint8(v & 0xff); 2.83 + ptr[1] = uint8((v >> 8) & 0xff); 2.84 } 2.85 2.86 static long file_length(FILE *fp) 2.87 { 2.88 - long cur_pos = ftell(fp); 2.89 - fseek(fp, 0, SEEK_END); 2.90 - long length = ftell(fp); 2.91 - fseek(fp, cur_pos, SEEK_SET); 2.92 - return length; 2.93 + long cur_pos = ftell(fp); 2.94 + fseek(fp, 0, SEEK_END); 2.95 + long length = ftell(fp); 2.96 + fseek(fp, cur_pos, SEEK_SET); 2.97 + return length; 2.98 } 2.99 2.100 static int bytes_per_frame(SMovie &mov) 2.101 { 2.102 - int num_controllers = 0; 2.103 + int num_controllers = 0; 2.104 2.105 - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.106 - if (mov.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.107 - ++num_controllers; 2.108 + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.109 + if (mov.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.110 + ++num_controllers; 2.111 2.112 - return CONTROLLER_DATA_SIZE * num_controllers; 2.113 + return CONTROLLER_DATA_SIZE * num_controllers; 2.114 } 2.115 2.116 static void reserve_buffer_space(uint32 space_needed) 2.117 { 2.118 - if (space_needed > Movie.inputBufferSize) 2.119 - { 2.120 - uint32 ptr_offset = Movie.inputBufferPtr - Movie.inputBuffer; 2.121 - uint32 alloc_chunks = (space_needed - 1) / BUFFER_GROWTH_SIZE + 1; 2.122 - uint32 old_size = Movie.inputBufferSize; 2.123 - Movie.inputBufferSize = BUFFER_GROWTH_SIZE * alloc_chunks; 2.124 - Movie.inputBuffer = (uint8 *)realloc(Movie.inputBuffer, Movie.inputBufferSize); 2.125 - // FIXME: this only fixes the random input problem during dma-frame-skip, but not the skip 2.126 - memset(Movie.inputBuffer + old_size, 0, Movie.inputBufferSize - old_size); 2.127 - Movie.inputBufferPtr = Movie.inputBuffer + ptr_offset; 2.128 - } 2.129 + if (space_needed > Movie.inputBufferSize) 2.130 + { 2.131 + uint32 ptr_offset = Movie.inputBufferPtr - Movie.inputBuffer; 2.132 + uint32 alloc_chunks = (space_needed - 1) / BUFFER_GROWTH_SIZE + 1; 2.133 + uint32 old_size = Movie.inputBufferSize; 2.134 + Movie.inputBufferSize = BUFFER_GROWTH_SIZE * alloc_chunks; 2.135 + Movie.inputBuffer = (uint8 *)realloc(Movie.inputBuffer, Movie.inputBufferSize); 2.136 + // FIXME: this only fixes the random input problem during dma-frame-skip, but not the skip 2.137 + memset(Movie.inputBuffer + old_size, 0, Movie.inputBufferSize - old_size); 2.138 + Movie.inputBufferPtr = Movie.inputBuffer + ptr_offset; 2.139 + } 2.140 } 2.141 2.142 static int read_movie_header(FILE *file, SMovie &movie) 2.143 { 2.144 - assert(file != NULL); 2.145 - assert(VBM_HEADER_SIZE == sizeof(SMovieFileHeader)); // sanity check on the header type definition 2.146 + assert(file != NULL); 2.147 + assert(VBM_HEADER_SIZE == sizeof(SMovieFileHeader)); // sanity check on the header type definition 2.148 2.149 - uint8 headerData [VBM_HEADER_SIZE]; 2.150 + uint8 headerData [VBM_HEADER_SIZE]; 2.151 2.152 - if (fread(headerData, 1, VBM_HEADER_SIZE, file) != VBM_HEADER_SIZE) 2.153 - return MOVIE_WRONG_FORMAT; // if we failed to read in all VBM_HEADER_SIZE bytes of the header 2.154 + if (fread(headerData, 1, VBM_HEADER_SIZE, file) != VBM_HEADER_SIZE) 2.155 + return MOVIE_WRONG_FORMAT; // if we failed to read in all VBM_HEADER_SIZE bytes of the header 2.156 2.157 - const uint8 * ptr = headerData; 2.158 - SMovieFileHeader &header = movie.header; 2.159 + const uint8 * ptr = headerData; 2.160 + SMovieFileHeader &header = movie.header; 2.161 2.162 - header.magic = Pop32(ptr); 2.163 - if (header.magic != VBM_MAGIC) 2.164 - return MOVIE_WRONG_FORMAT; 2.165 + header.magic = Pop32(ptr); 2.166 + if (header.magic != VBM_MAGIC) 2.167 + return MOVIE_WRONG_FORMAT; 2.168 2.169 - header.version = Pop32(ptr); 2.170 - if (header.version != VBM_VERSION) 2.171 - return MOVIE_WRONG_VERSION; 2.172 + header.version = Pop32(ptr); 2.173 + if (header.version != VBM_VERSION) 2.174 + return MOVIE_WRONG_VERSION; 2.175 2.176 - header.uid = Pop32(ptr); 2.177 - header.length_frames = Pop32(ptr) + 1; // HACK: add 1 to the length for compatibility 2.178 - header.rerecord_count = Pop32(ptr); 2.179 + header.uid = Pop32(ptr); 2.180 + header.length_frames = Pop32(ptr) + 1; // HACK: add 1 to the length for compatibility 2.181 + header.rerecord_count = Pop32(ptr); 2.182 2.183 - header.startFlags = Pop8(ptr); 2.184 - header.controllerFlags = Pop8(ptr); 2.185 - header.typeFlags = Pop8(ptr); 2.186 - header.optionFlags = Pop8(ptr); 2.187 + header.startFlags = Pop8(ptr); 2.188 + header.controllerFlags = Pop8(ptr); 2.189 + header.typeFlags = Pop8(ptr); 2.190 + header.optionFlags = Pop8(ptr); 2.191 2.192 - header.saveType = Pop32(ptr); 2.193 - header.flashSize = Pop32(ptr); 2.194 - header.gbEmulatorType = Pop32(ptr); 2.195 + header.saveType = Pop32(ptr); 2.196 + header.flashSize = Pop32(ptr); 2.197 + header.gbEmulatorType = Pop32(ptr); 2.198 2.199 - for (int i = 0; i < 12; i++) 2.200 - header.romTitle[i] = Pop8(ptr); 2.201 + for (int i = 0; i < 12; i++) 2.202 + header.romTitle[i] = Pop8(ptr); 2.203 2.204 - header.minorVersion = Pop8(ptr); 2.205 + header.minorVersion = Pop8(ptr); 2.206 2.207 - header.romCRC = Pop8(ptr); 2.208 - header.romOrBiosChecksum = Pop16(ptr); 2.209 - header.romGameCode = Pop32(ptr); 2.210 + header.romCRC = Pop8(ptr); 2.211 + header.romOrBiosChecksum = Pop16(ptr); 2.212 + header.romGameCode = Pop32(ptr); 2.213 2.214 - header.offset_to_savestate = Pop32(ptr); 2.215 - header.offset_to_controller_data = Pop32(ptr); 2.216 + header.offset_to_savestate = Pop32(ptr); 2.217 + header.offset_to_controller_data = Pop32(ptr); 2.218 2.219 - return MOVIE_SUCCESS; 2.220 + return MOVIE_SUCCESS; 2.221 } 2.222 2.223 static void write_movie_header(FILE *file, const SMovie &movie) 2.224 { 2.225 - assert(ftell(file) == 0); // we assume file points to beginning of movie file 2.226 + assert(ftell(file) == 0); // we assume file points to beginning of movie file 2.227 2.228 - uint8 headerData [VBM_HEADER_SIZE]; 2.229 - uint8 *ptr = headerData; 2.230 - const SMovieFileHeader &header = movie.header; 2.231 + uint8 headerData [VBM_HEADER_SIZE]; 2.232 + uint8 *ptr = headerData; 2.233 + const SMovieFileHeader &header = movie.header; 2.234 2.235 - Push32(header.magic, ptr); 2.236 - Push32(header.version, ptr); 2.237 + Push32(header.magic, ptr); 2.238 + Push32(header.version, ptr); 2.239 2.240 - Push32(header.uid, ptr); 2.241 - Push32(header.length_frames - 1, ptr); // HACK: reduce the length by 1 for compatibility with certain faulty old tools 2.242 - // like TME 2.243 - Push32(header.rerecord_count, ptr); 2.244 + Push32(header.uid, ptr); 2.245 + Push32(header.length_frames - 1, ptr); // HACK: reduce the length by 1 for compatibility with certain faulty old tools 2.246 + // like TME 2.247 + Push32(header.rerecord_count, ptr); 2.248 2.249 - Push8(header.startFlags, ptr); 2.250 - Push8(header.controllerFlags, ptr); 2.251 - Push8(header.typeFlags, ptr); 2.252 - Push8(header.optionFlags, ptr); 2.253 + Push8(header.startFlags, ptr); 2.254 + Push8(header.controllerFlags, ptr); 2.255 + Push8(header.typeFlags, ptr); 2.256 + Push8(header.optionFlags, ptr); 2.257 2.258 - Push32(header.saveType, ptr); 2.259 - Push32(header.flashSize, ptr); 2.260 - Push32(header.gbEmulatorType, ptr); 2.261 + Push32(header.saveType, ptr); 2.262 + Push32(header.flashSize, ptr); 2.263 + Push32(header.gbEmulatorType, ptr); 2.264 2.265 - for (int i = 0; i < 12; ++i) 2.266 - Push8(header.romTitle[i], ptr); 2.267 + for (int i = 0; i < 12; ++i) 2.268 + Push8(header.romTitle[i], ptr); 2.269 2.270 - Push8(header.minorVersion, ptr); 2.271 + Push8(header.minorVersion, ptr); 2.272 2.273 - Push8(header.romCRC, ptr); 2.274 - Push16(header.romOrBiosChecksum, ptr); 2.275 - Push32(header.romGameCode, ptr); 2.276 + Push8(header.romCRC, ptr); 2.277 + Push16(header.romOrBiosChecksum, ptr); 2.278 + Push32(header.romGameCode, ptr); 2.279 2.280 - Push32(header.offset_to_savestate, ptr); 2.281 - Push32(header.offset_to_controller_data, ptr); 2.282 + Push32(header.offset_to_savestate, ptr); 2.283 + Push32(header.offset_to_controller_data, ptr); 2.284 2.285 - fwrite(headerData, 1, VBM_HEADER_SIZE, file); 2.286 + fwrite(headerData, 1, VBM_HEADER_SIZE, file); 2.287 } 2.288 2.289 static void flush_movie_header() 2.290 { 2.291 - assert(Movie.file != 0 && "logical error!"); 2.292 - if (!Movie.file) 2.293 - return; 2.294 + assert(Movie.file != 0 && "logical error!"); 2.295 + if (!Movie.file) 2.296 + return; 2.297 2.298 - long originalPos = ftell(Movie.file); 2.299 + long originalPos = ftell(Movie.file); 2.300 2.301 - // (over-)write the header 2.302 - fseek(Movie.file, 0, SEEK_SET); 2.303 - write_movie_header(Movie.file, Movie); 2.304 + // (over-)write the header 2.305 + fseek(Movie.file, 0, SEEK_SET); 2.306 + write_movie_header(Movie.file, Movie); 2.307 2.308 - fflush(Movie.file); 2.309 + fflush(Movie.file); 2.310 2.311 - fseek(Movie.file, originalPos, SEEK_SET); 2.312 + fseek(Movie.file, originalPos, SEEK_SET); 2.313 } 2.314 2.315 static void flush_movie_frames() 2.316 { 2.317 - assert(Movie.file && "logical error!"); 2.318 - if (!Movie.file) 2.319 - return; 2.320 + assert(Movie.file && "logical error!"); 2.321 + if (!Movie.file) 2.322 + return; 2.323 2.324 - long originalPos = ftell(Movie.file); 2.325 + long originalPos = ftell(Movie.file); 2.326 2.327 - // overwrite the controller data 2.328 - fseek(Movie.file, Movie.header.offset_to_controller_data, SEEK_SET); 2.329 - fwrite(Movie.inputBuffer, 1, Movie.bytesPerFrame * Movie.header.length_frames, Movie.file); 2.330 + // overwrite the controller data 2.331 + fseek(Movie.file, Movie.header.offset_to_controller_data, SEEK_SET); 2.332 + fwrite(Movie.inputBuffer, 1, Movie.bytesPerFrame * Movie.header.length_frames, Movie.file); 2.333 2.334 - fflush(Movie.file); 2.335 + fflush(Movie.file); 2.336 2.337 - fseek(Movie.file, originalPos, SEEK_SET); 2.338 + fseek(Movie.file, originalPos, SEEK_SET); 2.339 } 2.340 2.341 static void truncate_movie(long length) 2.342 { 2.343 - // truncate movie to length 2.344 - // NOTE: it's certain that the savestate block is never after the 2.345 - // controller data block, because the VBM format decrees it. 2.346 + // truncate movie to length 2.347 + // NOTE: it's certain that the savestate block is never after the 2.348 + // controller data block, because the VBM format decrees it. 2.349 2.350 - assert(Movie.file && length >= 0); 2.351 - if (!Movie.file || length < 0) 2.352 - return; 2.353 + assert(Movie.file && length >= 0); 2.354 + if (!Movie.file || length < 0) 2.355 + return; 2.356 2.357 - assert(Movie.header.offset_to_savestate <= Movie.header.offset_to_controller_data); 2.358 - if (Movie.header.offset_to_savestate > Movie.header.offset_to_controller_data) 2.359 - return; 2.360 + assert(Movie.header.offset_to_savestate <= Movie.header.offset_to_controller_data); 2.361 + if (Movie.header.offset_to_savestate > Movie.header.offset_to_controller_data) 2.362 + return; 2.363 2.364 - Movie.header.length_frames = length; 2.365 - flush_movie_header(); 2.366 - const long truncLen = long(Movie.header.offset_to_controller_data + Movie.bytesPerFrame * length); 2.367 - if (file_length(Movie.file) != truncLen) 2.368 - { 2.369 - ftruncate(fileno(Movie.file), truncLen); 2.370 - } 2.371 + Movie.header.length_frames = length; 2.372 + flush_movie_header(); 2.373 + const long truncLen = long(Movie.header.offset_to_controller_data + Movie.bytesPerFrame * length); 2.374 + if (file_length(Movie.file) != truncLen) 2.375 + { 2.376 + ftruncate(fileno(Movie.file), truncLen); 2.377 + } 2.378 } 2.379 2.380 static void remember_input_state() 2.381 { 2.382 - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.383 + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.384 + { 2.385 + if (systemCartridgeType == 0) 2.386 { 2.387 - if (systemCartridgeType == 0) 2.388 - { 2.389 - initialInputs[i] = u16(~P1 & 0x03FF); 2.390 - } 2.391 - else 2.392 - { 2.393 - extern int32 gbJoymask[4]; 2.394 - for (int i = 0; i < 4; ++i) 2.395 - initialInputs[i] = u16(gbJoymask[i] & 0xFFFF); 2.396 - } 2.397 + initialInputs[i] = u16(~P1 & 0x03FF); 2.398 } 2.399 + else 2.400 + { 2.401 + extern int32 gbJoymask[4]; 2.402 + for (int i = 0; i < 4; ++i) 2.403 + initialInputs[i] = u16(gbJoymask[i] & 0xFFFF); 2.404 + } 2.405 + } 2.406 } 2.407 2.408 static void change_state(MovieState new_state) 2.409 { 2.410 #if (defined(WIN32) && !defined(SDL)) 2.411 - theApp.frameSearching = false; 2.412 - theApp.frameSearchSkipping = false; 2.413 + theApp.frameSearching = false; 2.414 + theApp.frameSearchSkipping = false; 2.415 #endif 2.416 2.417 - if (new_state == MOVIE_STATE_NONE) 2.418 + if (new_state == MOVIE_STATE_NONE) 2.419 + { 2.420 + Movie.pauseFrame = -1; 2.421 + 2.422 + if (Movie.state == MOVIE_STATE_NONE) 2.423 + return; 2.424 + 2.425 + truncate_movie(Movie.header.length_frames); 2.426 + 2.427 + fclose(Movie.file); 2.428 + Movie.file = NULL; 2.429 + Movie.currentFrame = 0; 2.430 +#if (defined(WIN32) && !defined(SDL)) 2.431 + // undo changes to border settings 2.432 + { 2.433 + gbBorderOn = prevBorder; 2.434 + theApp.winGbBorderOn = prevWinBorder; 2.435 + gbBorderAutomatic = prevBorderAuto; 2.436 + systemGbBorderOn(); 2.437 + } 2.438 +#endif 2.439 + gbEmulatorType = prevEmulatorType; 2.440 + 2.441 + extern int32 gbDMASpeedVersion; 2.442 + gbDMASpeedVersion = 1; 2.443 + 2.444 + extern int32 gbEchoRAMFixOn; 2.445 + gbEchoRAMFixOn = 1; 2.446 + 2.447 + gbNullInputHackTempEnabled = gbNullInputHackEnabled; 2.448 + 2.449 + if (Movie.inputBuffer) 2.450 { 2.451 - Movie.pauseFrame = -1; 2.452 + free(Movie.inputBuffer); 2.453 + Movie.inputBuffer = NULL; 2.454 + } 2.455 + } 2.456 + else if (new_state == MOVIE_STATE_PLAY) 2.457 + { 2.458 + assert(Movie.file); 2.459 2.460 - if (Movie.state == MOVIE_STATE_NONE) 2.461 - return; 2.462 + // this would cause problems if not dealt with 2.463 + if (Movie.currentFrame >= Movie.header.length_frames) 2.464 + { 2.465 + new_state = MOVIE_STATE_END; 2.466 + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; 2.467 + } 2.468 + } 2.469 + else if (new_state == MOVIE_STATE_RECORD) 2.470 + { 2.471 + assert(Movie.file); 2.472 2.473 - truncate_movie(Movie.header.length_frames); 2.474 - 2.475 - fclose(Movie.file); 2.476 - Movie.file = NULL; 2.477 - Movie.currentFrame = 0; 2.478 -#if (defined(WIN32) && !defined(SDL)) 2.479 - // undo changes to border settings 2.480 - { 2.481 - gbBorderOn = prevBorder; 2.482 - theApp.winGbBorderOn = prevWinBorder; 2.483 - gbBorderAutomatic = prevBorderAuto; 2.484 - systemGbBorderOn(); 2.485 - } 2.486 -#endif 2.487 - gbEmulatorType = prevEmulatorType; 2.488 - 2.489 - extern int32 gbDMASpeedVersion; 2.490 - gbDMASpeedVersion = 1; 2.491 - 2.492 - extern int32 gbEchoRAMFixOn; 2.493 - gbEchoRAMFixOn = 1; 2.494 - 2.495 - gbNullInputHackTempEnabled = gbNullInputHackEnabled; 2.496 - 2.497 - if (Movie.inputBuffer) 2.498 - { 2.499 - free(Movie.inputBuffer); 2.500 - Movie.inputBuffer = NULL; 2.501 - } 2.502 - } 2.503 - else if (new_state == MOVIE_STATE_PLAY) 2.504 + // this would cause problems if not dealt with 2.505 + if (Movie.currentFrame > Movie.header.length_frames) 2.506 { 2.507 - assert(Movie.file); 2.508 - 2.509 - // this would cause problems if not dealt with 2.510 - if (Movie.currentFrame >= Movie.header.length_frames) 2.511 - { 2.512 - new_state = MOVIE_STATE_END; 2.513 - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; 2.514 - } 2.515 - } 2.516 - else if (new_state == MOVIE_STATE_RECORD) 2.517 - { 2.518 - assert(Movie.file); 2.519 - 2.520 - // this would cause problems if not dealt with 2.521 - if (Movie.currentFrame > Movie.header.length_frames) 2.522 - { 2.523 - new_state = MOVIE_STATE_END; 2.524 - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; 2.525 - } 2.526 - 2.527 - fseek(Movie.file, Movie.header.offset_to_controller_data + Movie.bytesPerFrame * Movie.currentFrame, SEEK_SET); 2.528 + new_state = MOVIE_STATE_END; 2.529 + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * Movie.header.length_frames; 2.530 } 2.531 2.532 - if (new_state == MOVIE_STATE_END && Movie.state != MOVIE_STATE_END) 2.533 + fseek(Movie.file, Movie.header.offset_to_controller_data + Movie.bytesPerFrame * Movie.currentFrame, SEEK_SET); 2.534 + } 2.535 + 2.536 + if (new_state == MOVIE_STATE_END && Movie.state != MOVIE_STATE_END) 2.537 + { 2.538 +#if defined(SDL) 2.539 + systemClearJoypads(); 2.540 +#endif 2.541 + systemScreenMessage("Movie end"); 2.542 + } 2.543 + 2.544 + Movie.state = new_state; 2.545 + 2.546 + // checking for movie end 2.547 + bool willPause = false; 2.548 + 2.549 + // if the movie's been set to pause at a certain frame 2.550 + if (Movie.state != MOVIE_STATE_NONE && Movie.pauseFrame >= 0 && Movie.currentFrame == (uint32)Movie.pauseFrame) 2.551 + { 2.552 + Movie.pauseFrame = -1; 2.553 + willPause = true; 2.554 + } 2.555 + 2.556 + if (Movie.state == MOVIE_STATE_END) 2.557 + { 2.558 + if (Movie.currentFrame == Movie.header.length_frames) 2.559 { 2.560 -#if defined(SDL) 2.561 - systemClearJoypads(); 2.562 -#endif 2.563 - systemScreenMessage("Movie end"); 2.564 - } 2.565 - 2.566 - Movie.state = new_state; 2.567 - 2.568 - // checking for movie end 2.569 - bool willPause = false; 2.570 - 2.571 - // if the movie's been set to pause at a certain frame 2.572 - if (Movie.state != MOVIE_STATE_NONE && Movie.pauseFrame >= 0 && Movie.currentFrame == (uint32)Movie.pauseFrame) 2.573 - { 2.574 - Movie.pauseFrame = -1; 2.575 - willPause = true; 2.576 - } 2.577 - 2.578 - if (Movie.state == MOVIE_STATE_END) 2.579 - { 2.580 - if (Movie.currentFrame == Movie.header.length_frames) 2.581 - { 2.582 #if (defined(WIN32) && !defined(SDL)) 2.583 - if (theApp.movieOnEndPause) 2.584 - { 2.585 - willPause = true; 2.586 - } 2.587 + if (theApp.movieOnEndPause) 2.588 + { 2.589 + willPause = true; 2.590 + } 2.591 #else 2.592 - // SDL FIXME 2.593 + // SDL FIXME 2.594 #endif 2.595 2.596 #if (defined(WIN32) && !defined(SDL)) 2.597 - switch (theApp.movieOnEndBehavior) 2.598 - { 2.599 - case 1: 2.600 - // the old behavior 2.601 - //VBAMovieRestart(); 2.602 - break; 2.603 - case 2: 2.604 + switch (theApp.movieOnEndBehavior) 2.605 + { 2.606 + case 1: 2.607 + // the old behavior 2.608 + //VBAMovieRestart(); 2.609 + break; 2.610 + case 2: 2.611 #else 2.612 - // SDL FIXME 2.613 + // SDL FIXME 2.614 #endif 2.615 - if (Movie.RecordedThisSession) 2.616 - { 2.617 - // if user has been recording this movie since the last time it started playing, 2.618 - // they probably don't want the movie to end now during playback, 2.619 - // so switch back to recording when it reaches the end 2.620 - VBAMovieSwitchToRecording(); 2.621 - systemScreenMessage("Recording resumed"); 2.622 - willPause = true; 2.623 - } 2.624 + if (Movie.RecordedThisSession) 2.625 + { 2.626 + // if user has been recording this movie since the last time it started playing, 2.627 + // they probably don't want the movie to end now during playback, 2.628 + // so switch back to recording when it reaches the end 2.629 + VBAMovieSwitchToRecording(); 2.630 + systemScreenMessage("Recording resumed"); 2.631 + willPause = true; 2.632 + } 2.633 #if (defined(WIN32) && !defined(SDL)) 2.634 - break; 2.635 - case 3: 2.636 - // keep open 2.637 - break; 2.638 - case 0: 2.639 - // fall through 2.640 - default: 2.641 - // close movie 2.642 - //VBAMovieStop(false); 2.643 - break; 2.644 - } 2.645 + break; 2.646 + case 3: 2.647 + // keep open 2.648 + break; 2.649 + case 0: 2.650 + // fall through 2.651 + default: 2.652 + // close movie 2.653 + //VBAMovieStop(false); 2.654 + break; 2.655 + } 2.656 #else 2.657 - // SDL FIXME 2.658 + // SDL FIXME 2.659 #endif 2.660 - } 2.661 + } 2.662 #if 1 2.663 - else if (Movie.currentFrame > Movie.header.length_frames) 2.664 - { 2.665 + else if (Movie.currentFrame > Movie.header.length_frames) 2.666 + { 2.667 #if (defined(WIN32) && !defined(SDL)) 2.668 - switch (theApp.movieOnEndBehavior) 2.669 - { 2.670 - case 1: 2.671 - // FIXME: this should be delayed till the current frame ends 2.672 - VBAMovieRestart(); 2.673 - break; 2.674 - case 2: 2.675 - // nothing 2.676 - break; 2.677 - case 3: 2.678 - // keep open 2.679 - break; 2.680 - case 0: 2.681 - // fall through 2.682 - default: 2.683 - // close movie 2.684 - VBAMovieStop(false); 2.685 - break; 2.686 - } 2.687 + switch (theApp.movieOnEndBehavior) 2.688 + { 2.689 + case 1: 2.690 + // FIXME: this should be delayed till the current frame ends 2.691 + VBAMovieRestart(); 2.692 + break; 2.693 + case 2: 2.694 + // nothing 2.695 + break; 2.696 + case 3: 2.697 + // keep open 2.698 + break; 2.699 + case 0: 2.700 + // fall through 2.701 + default: 2.702 + // close movie 2.703 + VBAMovieStop(false); 2.704 + break; 2.705 + } 2.706 #else 2.707 - // SDLFIXME 2.708 + // SDLFIXME 2.709 #endif 2.710 - } 2.711 + } 2.712 #endif 2.713 - } // end if (Movie.state == MOVIE_STATE_END) 2.714 + } // end if (Movie.state == MOVIE_STATE_END) 2.715 2.716 - if (willPause) 2.717 - { 2.718 - systemSetPause(true); 2.719 - } 2.720 + if (willPause) 2.721 + { 2.722 + systemSetPause(true); 2.723 + } 2.724 } 2.725 2.726 void VBAMovieInit() 2.727 { 2.728 - memset(&Movie, 0, sizeof(Movie)); 2.729 - Movie.state = MOVIE_STATE_NONE; 2.730 - Movie.pauseFrame = -1; 2.731 + memset(&Movie, 0, sizeof(Movie)); 2.732 + Movie.state = MOVIE_STATE_NONE; 2.733 + Movie.pauseFrame = -1; 2.734 2.735 - resetSignaled = false; 2.736 - resetSignaledLast = false; 2.737 + resetSignaled = false; 2.738 + resetSignaledLast = false; 2.739 } 2.740 2.741 void VBAMovieGetRomInfo(const SMovie &movieInfo, char romTitle [12], uint32 &romGameCode, uint16 &checksum, uint8 &crc) 2.742 { 2.743 - if (systemCartridgeType == 0) // GBA 2.744 - { 2.745 - extern u8 *bios, *rom; 2.746 - memcpy(romTitle, &rom[0xa0], 12); // GBA TITLE 2.747 - memcpy(&romGameCode, &rom[0xac], 4); // GBA ROM GAME CODE 2.748 - if ((movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0) 2.749 - checksum = utilCalcBIOSChecksum(bios, 4); // GBA BIOS CHECKSUM 2.750 - else 2.751 - checksum = 0; 2.752 - crc = rom[0xbd]; // GBA ROM CRC 2.753 - } 2.754 - else // non-GBA 2.755 - { 2.756 - extern u8 *gbRom; 2.757 - memcpy(romTitle, &gbRom[0x134], 12); // GB TITLE (note this can be 15 but is truncated to 12) 2.758 - romGameCode = (uint32)gbRom[0x146]; // GB ROM UNIT CODE 2.759 + if (systemCartridgeType == 0) // GBA 2.760 + { 2.761 + extern u8 *bios, *rom; 2.762 + memcpy(romTitle, &rom[0xa0], 12); // GBA TITLE 2.763 + memcpy(&romGameCode, &rom[0xac], 4); // GBA ROM GAME CODE 2.764 + if ((movieInfo.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0) 2.765 + checksum = utilCalcBIOSChecksum(bios, 4); // GBA BIOS CHECKSUM 2.766 + else 2.767 + checksum = 0; 2.768 + crc = rom[0xbd]; // GBA ROM CRC 2.769 + } 2.770 + else // non-GBA 2.771 + { 2.772 + extern u8 *gbRom; 2.773 + memcpy(romTitle, &gbRom[0x134], 12); // GB TITLE (note this can be 15 but is truncated to 12) 2.774 + romGameCode = (uint32)gbRom[0x146]; // GB ROM UNIT CODE 2.775 2.776 - checksum = (gbRom[0x14e] << 8) | gbRom[0x14f]; // GB ROM CHECKSUM, read from big-endian 2.777 - crc = gbRom[0x14d]; // GB ROM CRC 2.778 - } 2.779 + checksum = (gbRom[0x14e] << 8) | gbRom[0x14f]; // GB ROM CHECKSUM, read from big-endian 2.780 + crc = gbRom[0x14d]; // GB ROM CRC 2.781 + } 2.782 } 2.783 2.784 #ifdef SDL 2.785 static void GetBatterySaveName(char *buffer) 2.786 { 2.787 - extern char batteryDir[2048], filename[2048]; // from SDL.cpp 2.788 - extern char *sdlGetFilename(char *name); // from SDL.cpp 2.789 - if (batteryDir[0]) 2.790 - sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename)); 2.791 - else 2.792 - sprintf(buffer, "%s.sav", filename); 2.793 + extern char batteryDir[2048], filename[2048]; // from SDL.cpp 2.794 + extern char *sdlGetFilename(char *name); // from SDL.cpp 2.795 + if (batteryDir[0]) 2.796 + sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename)); 2.797 + else 2.798 + sprintf(buffer, "%s.sav", filename); 2.799 } 2.800 2.801 #endif 2.802 2.803 static void SetPlayEmuSettings() 2.804 { 2.805 - prevEmulatorType = gbEmulatorType; 2.806 - gbEmulatorType = Movie.header.gbEmulatorType; 2.807 + prevEmulatorType = gbEmulatorType; 2.808 + gbEmulatorType = Movie.header.gbEmulatorType; 2.809 2.810 #if (defined(WIN32) && !defined(SDL)) 2.811 -// theApp.removeIntros = false; 2.812 - theApp.skipBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; 2.813 - theApp.useBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; 2.814 + // theApp.removeIntros = false; 2.815 + theApp.skipBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; 2.816 + theApp.useBiosFile = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; 2.817 #else 2.818 - extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp 2.819 - extern bool8 useBios, skipBios, removeIntros; // from SDL.cpp 2.820 - useBios = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; 2.821 - skipBios = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; 2.822 - removeIntros = false /*(Movie.header.optionFlags & MOVIE_SETTING_REMOVEINTROS) != 0*/; 2.823 + extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp 2.824 + extern bool8 useBios, skipBios, removeIntros; // from SDL.cpp 2.825 + useBios = (Movie.header.optionFlags & MOVIE_SETTING_USEBIOSFILE) != 0; 2.826 + skipBios = (Movie.header.optionFlags & MOVIE_SETTING_SKIPBIOSFILE) != 0; 2.827 + removeIntros = false /*(Movie.header.optionFlags & MOVIE_SETTING_REMOVEINTROS) != 0*/; 2.828 #endif 2.829 2.830 - extern void SetPrefetchHack(bool); 2.831 - if (systemCartridgeType == 0) // lag disablement applies only to GBA 2.832 - SetPrefetchHack((Movie.header.optionFlags & MOVIE_SETTING_LAGHACK) != 0); 2.833 + extern void SetPrefetchHack(bool); 2.834 + if (systemCartridgeType == 0) // lag disablement applies only to GBA 2.835 + SetPrefetchHack((Movie.header.optionFlags & MOVIE_SETTING_LAGHACK) != 0); 2.836 2.837 - gbNullInputHackTempEnabled = ((Movie.header.optionFlags & MOVIE_SETTING_GBINPUTHACK) != 0); 2.838 + gbNullInputHackTempEnabled = ((Movie.header.optionFlags & MOVIE_SETTING_GBINPUTHACK) != 0); 2.839 2.840 - // some GB/GBC games depend on the sound rate, so just use the highest one 2.841 - systemSoundSetQuality(1); 2.842 - useOldFrameTiming = false; 2.843 + // some GB/GBC games depend on the sound rate, so just use the highest one 2.844 + systemSoundSetQuality(1); 2.845 + useOldFrameTiming = false; 2.846 2.847 - extern int32 gbDMASpeedVersion; 2.848 - if ((Movie.header.optionFlags & MOVIE_SETTING_GBCFF55FIX) != 0) 2.849 - gbDMASpeedVersion = 1; 2.850 - else 2.851 - gbDMASpeedVersion = 0; // old CGB HDMA5 timing was used 2.852 + extern int32 gbDMASpeedVersion; 2.853 + if ((Movie.header.optionFlags & MOVIE_SETTING_GBCFF55FIX) != 0) 2.854 + gbDMASpeedVersion = 1; 2.855 + else 2.856 + gbDMASpeedVersion = 0; // old CGB HDMA5 timing was used 2.857 2.858 - extern int32 gbEchoRAMFixOn; 2.859 - if ((Movie.header.optionFlags & MOVIE_SETTING_GBECHORAMFIX) != 0) 2.860 - gbEchoRAMFixOn = 1; 2.861 - else 2.862 - gbEchoRAMFixOn = 0; 2.863 + extern int32 gbEchoRAMFixOn; 2.864 + if ((Movie.header.optionFlags & MOVIE_SETTING_GBECHORAMFIX) != 0) 2.865 + gbEchoRAMFixOn = 1; 2.866 + else 2.867 + gbEchoRAMFixOn = 0; 2.868 2.869 #if (defined(WIN32) && !defined(SDL)) 2.870 - rtcEnable((Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0); 2.871 - theApp.winSaveType = Movie.header.saveType; 2.872 - theApp.winFlashSize = Movie.header.flashSize; 2.873 + rtcEnable((Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0); 2.874 + theApp.winSaveType = Movie.header.saveType; 2.875 + theApp.winFlashSize = Movie.header.flashSize; 2.876 2.877 - prevBorder = gbBorderOn; 2.878 - prevWinBorder = theApp.winGbBorderOn; 2.879 - prevBorderAuto = gbBorderAutomatic; 2.880 - if ((gbEmulatorType == 2 || gbEmulatorType == 5) 2.881 - && !theApp.hideMovieBorder) // games played in SGB mode can have a border 2.882 + prevBorder = gbBorderOn; 2.883 + prevWinBorder = theApp.winGbBorderOn; 2.884 + prevBorderAuto = gbBorderAutomatic; 2.885 + if ((gbEmulatorType == 2 || gbEmulatorType == 5) 2.886 + && !theApp.hideMovieBorder) // games played in SGB mode can have a border 2.887 + { 2.888 + gbBorderOn = true; 2.889 + theApp.winGbBorderOn = true; 2.890 + gbBorderAutomatic = false; 2.891 + } 2.892 + else 2.893 + { 2.894 + gbBorderOn = false; 2.895 + theApp.winGbBorderOn = false; 2.896 + gbBorderAutomatic = false; 2.897 + if (theApp.hideMovieBorder) 2.898 { 2.899 - gbBorderOn = true; 2.900 - theApp.winGbBorderOn = true; 2.901 - gbBorderAutomatic = false; 2.902 + theApp.hideMovieBorder = false; 2.903 + prevBorder = false; // it might be expected behaviour that it stays hidden after the movie 2.904 } 2.905 - else 2.906 - { 2.907 - gbBorderOn = false; 2.908 - theApp.winGbBorderOn = false; 2.909 - gbBorderAutomatic = false; 2.910 - if (theApp.hideMovieBorder) 2.911 - { 2.912 - theApp.hideMovieBorder = false; 2.913 - prevBorder = false; // it might be expected behaviour that it stays hidden after the movie 2.914 - } 2.915 - } 2.916 - systemGbBorderOn(); 2.917 + } 2.918 + systemGbBorderOn(); 2.919 #else 2.920 - sdlRtcEnable = (Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0; 2.921 - saveType = Movie.header.saveType; 2.922 - sdlFlashSize = Movie.header.flashSize; 2.923 + sdlRtcEnable = (Movie.header.optionFlags & MOVIE_SETTING_RTCENABLE) != 0; 2.924 + saveType = Movie.header.saveType; 2.925 + sdlFlashSize = Movie.header.flashSize; 2.926 #endif 2.927 } 2.928 2.929 static void HardResetAndSRAMClear() 2.930 { 2.931 #if (defined(WIN32) && !defined(SDL)) 2.932 - winEraseBatteryFile(); // delete the damn SRAM file and keep it from being resurrected from RAM 2.933 - MainWnd *temp = ((MainWnd *)theApp.m_pMainWnd); 2.934 - if (!temp->winFileRun(true)) // restart running the game 2.935 - { 2.936 - temp->winFileClose(); 2.937 - } 2.938 + winEraseBatteryFile(); // delete the damn SRAM file and keep it from being resurrected from RAM 2.939 + MainWnd *temp = ((MainWnd *)theApp.m_pMainWnd); 2.940 + if (!temp->winFileRun(true)) // restart running the game 2.941 + { 2.942 + temp->winFileClose(); 2.943 + } 2.944 #else 2.945 - char fname [1024]; 2.946 - GetBatterySaveName(fname); 2.947 - remove(fname); // delete the damn SRAM file 2.948 + char fname [1024]; 2.949 + GetBatterySaveName(fname); 2.950 + remove(fname); // delete the damn SRAM file 2.951 2.952 - // Henceforth, emuCleanUp means "clear out SRAM" 2.953 - //theEmulator.emuCleanUp(); // keep it from being resurrected from RAM <--This is wrong, it'll deallocate all variables --Felipe 2.954 + // Henceforth, emuCleanUp means "clear out SRAM" 2.955 + //theEmulator.emuCleanUp(); // keep it from being resurrected from RAM <--This is wrong, it'll deallocate all variables --Felipe 2.956 2.957 - /// FIXME the correct SDL code to call for a full restart isn't in a function yet 2.958 - theEmulator.emuReset(false); 2.959 + /// FIXME the correct SDL code to call for a full restart isn't in a function yet 2.960 + theEmulator.emuReset(false); 2.961 #endif 2.962 } 2.963 2.964 int VBAMovieOpen(const char *filename, bool8 read_only) 2.965 { 2.966 - loadingMovie = true; 2.967 - uint8 movieReadOnly = read_only ? 1 : 0; 2.968 + loadingMovie = true; 2.969 + uint8 movieReadOnly = read_only ? 1 : 0; 2.970 2.971 - FILE * file; 2.972 - STREAM stream; 2.973 - int result; 2.974 - int fn; 2.975 + FILE * file; 2.976 + STREAM stream; 2.977 + int result; 2.978 + int fn; 2.979 2.980 - char movie_filename[_MAX_PATH]; 2.981 + char movie_filename[_MAX_PATH]; 2.982 #ifdef WIN32 2.983 - _fullpath(movie_filename, filename, _MAX_PATH); 2.984 + _fullpath(movie_filename, filename, _MAX_PATH); 2.985 #else 2.986 - // SDL FIXME: convert to fullpath 2.987 - strncpy(movie_filename, filename, _MAX_PATH); 2.988 - movie_filename[_MAX_PATH - 1] = '\0'; 2.989 + // SDL FIXME: convert to fullpath 2.990 + strncpy(movie_filename, filename, _MAX_PATH); 2.991 + movie_filename[_MAX_PATH - 1] = '\0'; 2.992 #endif 2.993 2.994 - if (movie_filename[0] == '\0') 2.995 - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.996 + if (movie_filename[0] == '\0') 2.997 + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.998 2.999 - if (!emulating) 2.1000 - { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1001 + if (!emulating) 2.1002 + { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1003 2.1004 -// bool alreadyOpen = (Movie.file != NULL && _stricmp(movie_filename, Movie.filename) == 0); 2.1005 + // bool alreadyOpen = (Movie.file != NULL && _stricmp(movie_filename, Movie.filename) == 0); 2.1006 2.1007 -// if (alreadyOpen) 2.1008 - change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it 2.1009 + // if (alreadyOpen) 2.1010 + change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it 2.1011 2.1012 - if (!(file = fopen(movie_filename, "rb+"))) 2.1013 - if (!(file = fopen(movie_filename, "rb"))) 2.1014 - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1015 - //else 2.1016 - // movieReadOnly = 2; // we have to open the movie twice, no need to do this both times 2.1017 + if (!(file = fopen(movie_filename, "rb+"))) 2.1018 + if (!(file = fopen(movie_filename, "rb"))) 2.1019 + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1020 + //else 2.1021 + // movieReadOnly = 2; // we have to open the movie twice, no need to do this both times 2.1022 2.1023 -// if (!alreadyOpen) 2.1024 -// change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one 2.1025 -// 2.1026 -// if (!(file = fopen(movie_filename, "rb+"))) 2.1027 -// if(!(file = fopen(movie_filename, "rb"))) 2.1028 -// {loadingMovie = false; return MOVIE_FILE_NOT_FOUND;} 2.1029 -// else 2.1030 -// movieReadOnly = 2; 2.1031 + // if (!alreadyOpen) 2.1032 + // change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one 2.1033 + // 2.1034 + // if (!(file = fopen(movie_filename, "rb+"))) 2.1035 + // if(!(file = fopen(movie_filename, "rb"))) 2.1036 + // {loadingMovie = false; return MOVIE_FILE_NOT_FOUND;} 2.1037 + // else 2.1038 + // movieReadOnly = 2; 2.1039 2.1040 - // clear out the current movie 2.1041 - VBAMovieInit(); 2.1042 + // clear out the current movie 2.1043 + VBAMovieInit(); 2.1044 2.1045 - // read header 2.1046 - if ((result = read_movie_header(file, Movie)) != MOVIE_SUCCESS) 2.1047 - { 2.1048 - fclose(file); 2.1049 - { loadingMovie = false; return result; } 2.1050 - } 2.1051 + // read header 2.1052 + if ((result = read_movie_header(file, Movie)) != MOVIE_SUCCESS) 2.1053 + { 2.1054 + fclose(file); 2.1055 + { loadingMovie = false; return result; } 2.1056 + } 2.1057 2.1058 - // set emulator settings that make the movie more likely to stay synchronized 2.1059 - SetPlayEmuSettings(); 2.1060 + // set emulator settings that make the movie more likely to stay synchronized 2.1061 + SetPlayEmuSettings(); 2.1062 2.1063 -// extern bool systemLoadBIOS(); 2.1064 -// if (!systemLoadBIOS()) 2.1065 -// { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1066 + // extern bool systemLoadBIOS(); 2.1067 + // if (!systemLoadBIOS()) 2.1068 + // { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1069 2.1070 - // read the metadata / author info from file 2.1071 - fread(Movie.authorInfo, 1, MOVIE_METADATA_SIZE, file); 2.1072 - fn = dup(fileno(file)); // XXX: why does this fail?? it returns -1 but errno == 0 2.1073 - fclose(file); 2.1074 + // read the metadata / author info from file 2.1075 + fread(Movie.authorInfo, 1, MOVIE_METADATA_SIZE, file); 2.1076 + fn = dup(fileno(file)); // XXX: why does this fail?? it returns -1 but errno == 0 2.1077 + fclose(file); 2.1078 2.1079 - // apparently this lseek is necessary 2.1080 - lseek(fn, Movie.header.offset_to_savestate, SEEK_SET); 2.1081 - if (!(stream = utilGzReopen(fn, "rb"))) 2.1082 - if (!(stream = utilGzOpen(movie_filename, "rb"))) 2.1083 - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1084 - else 2.1085 - fn = dup(fileno(file)); 2.1086 - // in case the above dup failed but opening the file normally doesn't fail 2.1087 + // apparently this lseek is necessary 2.1088 + lseek(fn, Movie.header.offset_to_savestate, SEEK_SET); 2.1089 + if (!(stream = utilGzReopen(fn, "rb"))) 2.1090 + if (!(stream = utilGzOpen(movie_filename, "rb"))) 2.1091 + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1092 + else 2.1093 + fn = dup(fileno(file)); 2.1094 + // in case the above dup failed but opening the file normally doesn't fail 2.1095 2.1096 - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) 2.1097 - { 2.1098 - // load the snapshot 2.1099 - result = theEmulator.emuReadStateFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; 2.1100 + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) 2.1101 + { 2.1102 + // load the snapshot 2.1103 + result = theEmulator.emuReadStateFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; 2.1104 2.1105 - // FIXME: Kludge for conversion 2.1106 - remember_input_state(); 2.1107 - } 2.1108 - else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) 2.1109 - { 2.1110 - // 'soft' reset: 2.1111 - theEmulator.emuReset(false); 2.1112 + // FIXME: Kludge for conversion 2.1113 + remember_input_state(); 2.1114 + } 2.1115 + else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) 2.1116 + { 2.1117 + // 'soft' reset: 2.1118 + theEmulator.emuReset(false); 2.1119 2.1120 - // load the SRAM 2.1121 - result = theEmulator.emuReadBatteryFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; 2.1122 - } 2.1123 - else 2.1124 - { 2.1125 - HardResetAndSRAMClear(); 2.1126 - } 2.1127 + // load the SRAM 2.1128 + result = theEmulator.emuReadBatteryFromStream(stream) ? MOVIE_SUCCESS : MOVIE_WRONG_FORMAT; 2.1129 + } 2.1130 + else 2.1131 + { 2.1132 + HardResetAndSRAMClear(); 2.1133 + } 2.1134 2.1135 - utilGzClose(stream); 2.1136 + utilGzClose(stream); 2.1137 2.1138 - if (result != MOVIE_SUCCESS) 2.1139 - { loadingMovie = false; return result; } 2.1140 + if (result != MOVIE_SUCCESS) 2.1141 + { loadingMovie = false; return result; } 2.1142 2.1143 -// if (!(file = fopen(movie_filename, /*read_only ? "rb" :*/ "rb+"))) // want to be able to switch out of read-only later 2.1144 -// { 2.1145 -// if(!Movie.readOnly || !(file = fopen(movie_filename, "rb"))) // try read-only if failed 2.1146 -// return MOVIE_FILE_NOT_FOUND; 2.1147 -// } 2.1148 - if (!(file = fopen(movie_filename, "rb+"))) 2.1149 - if (!(file = fopen(movie_filename, "rb"))) 2.1150 - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1151 - else 2.1152 - movieReadOnly = 2; 2.1153 + // if (!(file = fopen(movie_filename, /*read_only ? "rb" :*/ "rb+"))) // want to be able to switch out of read-only later 2.1154 + // { 2.1155 + // if(!Movie.readOnly || !(file = fopen(movie_filename, "rb"))) // try read-only if failed 2.1156 + // return MOVIE_FILE_NOT_FOUND; 2.1157 + // } 2.1158 + if (!(file = fopen(movie_filename, "rb+"))) 2.1159 + if (!(file = fopen(movie_filename, "rb"))) 2.1160 + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1161 + else 2.1162 + movieReadOnly = 2; 2.1163 2.1164 - // recalculate length of movie from the file size 2.1165 - Movie.bytesPerFrame = bytes_per_frame(Movie); 2.1166 - fseek(file, 0, SEEK_END); 2.1167 - long fileSize = ftell(file); 2.1168 - Movie.header.length_frames = (fileSize - Movie.header.offset_to_controller_data) / Movie.bytesPerFrame; 2.1169 + // recalculate length of movie from the file size 2.1170 + Movie.bytesPerFrame = bytes_per_frame(Movie); 2.1171 + fseek(file, 0, SEEK_END); 2.1172 + long fileSize = ftell(file); 2.1173 + Movie.header.length_frames = (fileSize - Movie.header.offset_to_controller_data) / Movie.bytesPerFrame; 2.1174 2.1175 - if (fseek(file, Movie.header.offset_to_controller_data, SEEK_SET)) 2.1176 - { fclose(file); loadingMovie = false; return MOVIE_WRONG_FORMAT; } 2.1177 + if (fseek(file, Movie.header.offset_to_controller_data, SEEK_SET)) 2.1178 + { fclose(file); loadingMovie = false; return MOVIE_WRONG_FORMAT; } 2.1179 2.1180 - strcpy(Movie.filename, movie_filename); 2.1181 - Movie.file = file; 2.1182 - Movie.inputBufferPtr = Movie.inputBuffer; 2.1183 - Movie.currentFrame = 0; 2.1184 - Movie.readOnly = movieReadOnly; 2.1185 - Movie.RecordedThisSession = false; 2.1186 + strcpy(Movie.filename, movie_filename); 2.1187 + Movie.file = file; 2.1188 + Movie.inputBufferPtr = Movie.inputBuffer; 2.1189 + Movie.currentFrame = 0; 2.1190 + Movie.readOnly = movieReadOnly; 2.1191 + Movie.RecordedThisSession = false; 2.1192 2.1193 - // read controller data 2.1194 - uint32 to_read = Movie.bytesPerFrame * Movie.header.length_frames; 2.1195 - reserve_buffer_space(to_read); 2.1196 - fread(Movie.inputBuffer, 1, to_read, file); 2.1197 + // read controller data 2.1198 + uint32 to_read = Movie.bytesPerFrame * Movie.header.length_frames; 2.1199 + reserve_buffer_space(to_read); 2.1200 + fread(Movie.inputBuffer, 1, to_read, file); 2.1201 2.1202 - change_state(MOVIE_STATE_PLAY); 2.1203 + change_state(MOVIE_STATE_PLAY); 2.1204 2.1205 - char messageString[64] = "Movie "; 2.1206 - bool converted = false; 2.1207 - if (autoConvertMovieWhenPlaying) 2.1208 - { 2.1209 - int result = VBAMovieConvertCurrent(); 2.1210 - if (result == MOVIE_SUCCESS) 2.1211 - strcat(messageString, "converted and "); 2.1212 - else if (result == MOVIE_WRONG_VERSION) 2.1213 - strcat(messageString, "higher revision "); 2.1214 - } 2.1215 + char messageString[64] = "Movie "; 2.1216 + bool converted = false; 2.1217 + if (autoConvertMovieWhenPlaying) 2.1218 + { 2.1219 + int result = VBAMovieConvertCurrent(); 2.1220 + if (result == MOVIE_SUCCESS) 2.1221 + strcat(messageString, "converted and "); 2.1222 + else if (result == MOVIE_WRONG_VERSION) 2.1223 + strcat(messageString, "higher revision "); 2.1224 + } 2.1225 2.1226 - if (Movie.state == MOVIE_STATE_PLAY) 2.1227 - strcat(messageString, "replaying "); 2.1228 - else 2.1229 - strcat(messageString, "finished "); 2.1230 - if (Movie.readOnly) 2.1231 - strcat(messageString, "(read)"); 2.1232 - else 2.1233 - strcat(messageString, "(edit)"); 2.1234 - systemScreenMessage(messageString); 2.1235 + if (Movie.state == MOVIE_STATE_PLAY) 2.1236 + strcat(messageString, "replaying "); 2.1237 + else 2.1238 + strcat(messageString, "finished "); 2.1239 + if (Movie.readOnly) 2.1240 + strcat(messageString, "(read)"); 2.1241 + else 2.1242 + strcat(messageString, "(edit)"); 2.1243 + systemScreenMessage(messageString); 2.1244 2.1245 - VBAUpdateButtonPressDisplay(); 2.1246 - VBAUpdateFrameCountDisplay(); 2.1247 - systemRefreshScreen(); 2.1248 + VBAUpdateButtonPressDisplay(); 2.1249 + VBAUpdateFrameCountDisplay(); 2.1250 + systemRefreshScreen(); 2.1251 2.1252 - { loadingMovie = false; return MOVIE_SUCCESS; } 2.1253 + { loadingMovie = false; return MOVIE_SUCCESS; } 2.1254 } 2.1255 2.1256 static void SetRecordEmuSettings() 2.1257 { 2.1258 - Movie.header.optionFlags = 0; 2.1259 + Movie.header.optionFlags = 0; 2.1260 #if (defined(WIN32) && !defined(SDL)) 2.1261 - if (theApp.useBiosFile) 2.1262 - Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; 2.1263 - if (theApp.skipBiosFile) 2.1264 - Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; 2.1265 - if (rtcIsEnabled()) 2.1266 - Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; 2.1267 - Movie.header.saveType = theApp.winSaveType; 2.1268 - Movie.header.flashSize = theApp.winFlashSize; 2.1269 + if (theApp.useBiosFile) 2.1270 + Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; 2.1271 + if (theApp.skipBiosFile) 2.1272 + Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; 2.1273 + if (rtcIsEnabled()) 2.1274 + Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; 2.1275 + Movie.header.saveType = theApp.winSaveType; 2.1276 + Movie.header.flashSize = theApp.winFlashSize; 2.1277 #else 2.1278 - extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp 2.1279 - extern bool8 useBios, skipBios; // from SDL.cpp 2.1280 - if (useBios) 2.1281 - Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; 2.1282 - if (skipBios) 2.1283 - Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; 2.1284 - if (sdlRtcEnable) 2.1285 - Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; 2.1286 - Movie.header.saveType = saveType; 2.1287 - Movie.header.flashSize = sdlFlashSize; 2.1288 + extern int saveType, sdlRtcEnable, sdlFlashSize; // from SDL.cpp 2.1289 + extern bool8 useBios, skipBios; // from SDL.cpp 2.1290 + if (useBios) 2.1291 + Movie.header.optionFlags |= MOVIE_SETTING_USEBIOSFILE; 2.1292 + if (skipBios) 2.1293 + Movie.header.optionFlags |= MOVIE_SETTING_SKIPBIOSFILE; 2.1294 + if (sdlRtcEnable) 2.1295 + Movie.header.optionFlags |= MOVIE_SETTING_RTCENABLE; 2.1296 + Movie.header.saveType = saveType; 2.1297 + Movie.header.flashSize = sdlFlashSize; 2.1298 #endif 2.1299 - prevEmulatorType = Movie.header.gbEmulatorType = gbEmulatorType; 2.1300 + prevEmulatorType = Movie.header.gbEmulatorType = gbEmulatorType; 2.1301 2.1302 - if (!memLagTempEnabled) 2.1303 - Movie.header.optionFlags |= MOVIE_SETTING_LAGHACK; 2.1304 + if (!memLagTempEnabled) 2.1305 + Movie.header.optionFlags |= MOVIE_SETTING_LAGHACK; 2.1306 2.1307 - if (gbNullInputHackTempEnabled) 2.1308 - Movie.header.optionFlags |= MOVIE_SETTING_GBINPUTHACK; 2.1309 + if (gbNullInputHackTempEnabled) 2.1310 + Movie.header.optionFlags |= MOVIE_SETTING_GBINPUTHACK; 2.1311 2.1312 - Movie.header.optionFlags |= MOVIE_SETTING_GBCFF55FIX; 2.1313 - extern int32 gbDMASpeedVersion; 2.1314 - gbDMASpeedVersion = 1; 2.1315 + Movie.header.optionFlags |= MOVIE_SETTING_GBCFF55FIX; 2.1316 + extern int32 gbDMASpeedVersion; 2.1317 + gbDMASpeedVersion = 1; 2.1318 2.1319 - Movie.header.optionFlags |= MOVIE_SETTING_GBECHORAMFIX; 2.1320 - extern int32 gbEchoRAMFixOn; 2.1321 - gbEchoRAMFixOn = 1; 2.1322 + Movie.header.optionFlags |= MOVIE_SETTING_GBECHORAMFIX; 2.1323 + extern int32 gbEchoRAMFixOn; 2.1324 + gbEchoRAMFixOn = 1; 2.1325 2.1326 - // some GB/GBC games depend on the sound rate, so just use the highest one 2.1327 - systemSoundSetQuality(1); 2.1328 + // some GB/GBC games depend on the sound rate, so just use the highest one 2.1329 + systemSoundSetQuality(1); 2.1330 2.1331 - useOldFrameTiming = false; 2.1332 + useOldFrameTiming = false; 2.1333 2.1334 #if (defined(WIN32) && !defined(SDL)) 2.1335 -// theApp.removeIntros = false; 2.1336 + // theApp.removeIntros = false; 2.1337 2.1338 - prevBorder = gbBorderOn; 2.1339 - prevWinBorder = theApp.winGbBorderOn; 2.1340 - prevBorderAuto = gbBorderAutomatic; 2.1341 - if (gbEmulatorType == 2 || gbEmulatorType == 5) // only games played in SGB mode will have a border 2.1342 - { 2.1343 - gbBorderOn = true; 2.1344 - theApp.winGbBorderOn = true; 2.1345 - gbBorderAutomatic = false; 2.1346 - } 2.1347 - else 2.1348 - { 2.1349 - gbBorderOn = false; 2.1350 - theApp.winGbBorderOn = false; 2.1351 - gbBorderAutomatic = false; 2.1352 - } 2.1353 - systemGbBorderOn(); 2.1354 + prevBorder = gbBorderOn; 2.1355 + prevWinBorder = theApp.winGbBorderOn; 2.1356 + prevBorderAuto = gbBorderAutomatic; 2.1357 + if (gbEmulatorType == 2 || gbEmulatorType == 5) // only games played in SGB mode will have a border 2.1358 + { 2.1359 + gbBorderOn = true; 2.1360 + theApp.winGbBorderOn = true; 2.1361 + gbBorderAutomatic = false; 2.1362 + } 2.1363 + else 2.1364 + { 2.1365 + gbBorderOn = false; 2.1366 + theApp.winGbBorderOn = false; 2.1367 + gbBorderAutomatic = false; 2.1368 + } 2.1369 + systemGbBorderOn(); 2.1370 #else 2.1371 - /// SDLFIXME 2.1372 + /// SDLFIXME 2.1373 #endif 2.1374 } 2.1375 2.1376 uint16 VBAMovieGetCurrentInputOf(int controllerNum, bool normalOnly) 2.1377 { 2.1378 - if (controllerNum < 0 || controllerNum >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) 2.1379 - return 0; 2.1380 + if (controllerNum < 0 || controllerNum >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) 2.1381 + return 0; 2.1382 2.1383 - return normalOnly ? (currentButtons[controllerNum] & BUTTON_REGULAR_MASK) : currentButtons[controllerNum]; 2.1384 + return normalOnly ? (currentButtons[controllerNum] & BUTTON_REGULAR_MASK) : currentButtons[controllerNum]; 2.1385 } 2.1386 2.1387 int VBAMovieCreate(const char *filename, const char *authorInfo, uint8 startFlags, uint8 controllerFlags, uint8 typeFlags) 2.1388 { 2.1389 - // make sure at least one controller is enabled 2.1390 - if ((controllerFlags & MOVIE_CONTROLLERS_ANY_MASK) == 0) 2.1391 - return MOVIE_WRONG_FORMAT; 2.1392 + // make sure at least one controller is enabled 2.1393 + if ((controllerFlags & MOVIE_CONTROLLERS_ANY_MASK) == 0) 2.1394 + return MOVIE_WRONG_FORMAT; 2.1395 2.1396 - if (!emulating) 2.1397 - return MOVIE_UNKNOWN_ERROR; 2.1398 + if (!emulating) 2.1399 + return MOVIE_UNKNOWN_ERROR; 2.1400 2.1401 - loadingMovie = true; 2.1402 + loadingMovie = true; 2.1403 2.1404 - FILE * file; 2.1405 - STREAM stream; 2.1406 - int fn; 2.1407 + FILE * file; 2.1408 + STREAM stream; 2.1409 + int fn; 2.1410 2.1411 - char movie_filename [_MAX_PATH]; 2.1412 + char movie_filename [_MAX_PATH]; 2.1413 #ifdef WIN32 2.1414 - _fullpath(movie_filename, filename, _MAX_PATH); 2.1415 + _fullpath(movie_filename, filename, _MAX_PATH); 2.1416 #else 2.1417 - // FIXME: convert to fullpath 2.1418 - strncpy(movie_filename, filename, _MAX_PATH); 2.1419 - movie_filename[_MAX_PATH - 1] = '\0'; 2.1420 + // FIXME: convert to fullpath 2.1421 + strncpy(movie_filename, filename, _MAX_PATH); 2.1422 + movie_filename[_MAX_PATH - 1] = '\0'; 2.1423 #endif 2.1424 2.1425 - bool alreadyOpen = (Movie.file != NULL && stricmp(movie_filename, Movie.filename) == 0); 2.1426 + bool alreadyOpen = (Movie.file != NULL && stricmp(movie_filename, Movie.filename) == 0); 2.1427 2.1428 - if (alreadyOpen) 2.1429 - change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it 2.1430 + if (alreadyOpen) 2.1431 + change_state(MOVIE_STATE_NONE); // have to stop current movie before trying to re-open it 2.1432 2.1433 - if (movie_filename[0] == '\0') 2.1434 + if (movie_filename[0] == '\0') 2.1435 + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1436 + 2.1437 + if (!(file = fopen(movie_filename, "wb"))) 2.1438 + { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1439 + 2.1440 + if (!alreadyOpen) 2.1441 + change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one 2.1442 + 2.1443 + // clear out the current movie 2.1444 + printf("RLM: movie init\n"); 2.1445 + 2.1446 + VBAMovieInit(); 2.1447 + 2.1448 + // fill in the movie's header 2.1449 + Movie.header.uid = (uint32)time(NULL); 2.1450 + Movie.header.magic = VBM_MAGIC; 2.1451 + Movie.header.version = VBM_VERSION; 2.1452 + Movie.header.rerecord_count = 0; 2.1453 + Movie.header.length_frames = 0; 2.1454 + Movie.header.startFlags = startFlags; 2.1455 + Movie.header.controllerFlags = controllerFlags; 2.1456 + Movie.header.typeFlags = typeFlags; 2.1457 + Movie.header.minorVersion = VBM_REVISION; 2.1458 + 2.1459 + // set emulator settings that make the movie more likely to stay synchronized when it's later played back 2.1460 + SetRecordEmuSettings(); 2.1461 + 2.1462 + // set ROM and BIOS checksums and stuff 2.1463 + VBAMovieGetRomInfo(Movie, Movie.header.romTitle, Movie.header.romGameCode, Movie.header.romOrBiosChecksum, Movie.header.romCRC); 2.1464 + 2.1465 + printf("RLM: Writing movie header\n"); 2.1466 + // write the header to file 2.1467 + write_movie_header(file, Movie); 2.1468 + 2.1469 + printf("RLM: setting metadata\n"); 2.1470 + 2.1471 + // copy over the metadata / author info 2.1472 + VBAMovieSetMetadata("________________Robert McIntyre______________________________________________________________________________________________________________________________________________________________________________________________________________________"); 2.1473 + 2.1474 + printf("RLM: writing metadata\n"); 2.1475 + 2.1476 + // write the metadata / author info to file 2.1477 + 2.1478 + 2.1479 + fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); 2.1480 + 2.1481 + // write snapshot or SRAM if applicable 2.1482 + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT 2.1483 + || Movie.header.startFlags & MOVIE_START_FROM_SRAM) 2.1484 + { 2.1485 + Movie.header.offset_to_savestate = (uint32)ftell(file); 2.1486 + 2.1487 + // close the file and reopen it as a stream: 2.1488 + 2.1489 + fn = dup(fileno(file)); 2.1490 + fclose(file); 2.1491 + 2.1492 + if (!(stream = utilGzReopen(fn, "ab"))) // append mode to start at end, no seek necessary 2.1493 { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1494 2.1495 - if (!(file = fopen(movie_filename, "wb"))) 2.1496 + // write the save data: 2.1497 + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) 2.1498 + { 2.1499 + // save snapshot 2.1500 + if (!theEmulator.emuWriteStateToStream(stream)) 2.1501 + { 2.1502 + utilGzClose(stream); 2.1503 + { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1504 + } 2.1505 + } 2.1506 + else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) 2.1507 + { 2.1508 + // save SRAM 2.1509 + if (!theEmulator.emuWriteBatteryToStream(stream)) 2.1510 + { 2.1511 + utilGzClose(stream); 2.1512 + { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1513 + } 2.1514 + 2.1515 + // 'soft' reset: 2.1516 + theEmulator.emuReset(false); 2.1517 + } 2.1518 + 2.1519 + utilGzClose(stream); 2.1520 + 2.1521 + // reopen the file and seek back to the end 2.1522 + 2.1523 + if (!(file = fopen(movie_filename, "rb+"))) 2.1524 { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1525 2.1526 - if (!alreadyOpen) 2.1527 - change_state(MOVIE_STATE_NONE); // stop current movie when we're able to open the other one 2.1528 + fseek(file, 0, SEEK_END); 2.1529 + } 2.1530 + else // no snapshot or SRAM 2.1531 + { 2.1532 + HardResetAndSRAMClear(); 2.1533 + } 2.1534 2.1535 - // clear out the current movie 2.1536 - VBAMovieInit(); 2.1537 + Movie.header.offset_to_controller_data = (uint32)ftell(file); 2.1538 2.1539 - // fill in the movie's header 2.1540 - Movie.header.uid = (uint32)time(NULL); 2.1541 - Movie.header.magic = VBM_MAGIC; 2.1542 - Movie.header.version = VBM_VERSION; 2.1543 - Movie.header.rerecord_count = 0; 2.1544 - Movie.header.length_frames = 0; 2.1545 - Movie.header.startFlags = startFlags; 2.1546 - Movie.header.controllerFlags = controllerFlags; 2.1547 - Movie.header.typeFlags = typeFlags; 2.1548 - Movie.header.minorVersion = VBM_REVISION; 2.1549 + strcpy(Movie.filename, movie_filename); 2.1550 + Movie.file = file; 2.1551 + Movie.bytesPerFrame = bytes_per_frame(Movie); 2.1552 + Movie.inputBufferPtr = Movie.inputBuffer; 2.1553 + Movie.currentFrame = 0; 2.1554 + Movie.readOnly = false; 2.1555 + Movie.RecordedThisSession = true; 2.1556 2.1557 - // set emulator settings that make the movie more likely to stay synchronized when it's later played back 2.1558 - SetRecordEmuSettings(); 2.1559 + change_state(MOVIE_STATE_RECORD); 2.1560 2.1561 - // set ROM and BIOS checksums and stuff 2.1562 - VBAMovieGetRomInfo(Movie, Movie.header.romTitle, Movie.header.romGameCode, Movie.header.romOrBiosChecksum, Movie.header.romCRC); 2.1563 - 2.1564 - // write the header to file 2.1565 - write_movie_header(file, Movie); 2.1566 - 2.1567 - // copy over the metadata / author info 2.1568 - VBAMovieSetMetadata(authorInfo); 2.1569 - 2.1570 - // write the metadata / author info to file 2.1571 - fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); 2.1572 - 2.1573 - // write snapshot or SRAM if applicable 2.1574 - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT 2.1575 - || Movie.header.startFlags & MOVIE_START_FROM_SRAM) 2.1576 - { 2.1577 - Movie.header.offset_to_savestate = (uint32)ftell(file); 2.1578 - 2.1579 - // close the file and reopen it as a stream: 2.1580 - 2.1581 - fn = dup(fileno(file)); 2.1582 - fclose(file); 2.1583 - 2.1584 - if (!(stream = utilGzReopen(fn, "ab"))) // append mode to start at end, no seek necessary 2.1585 - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1586 - 2.1587 - // write the save data: 2.1588 - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) 2.1589 - { 2.1590 - // save snapshot 2.1591 - if (!theEmulator.emuWriteStateToStream(stream)) 2.1592 - { 2.1593 - utilGzClose(stream); 2.1594 - { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1595 - } 2.1596 - } 2.1597 - else if (Movie.header.startFlags & MOVIE_START_FROM_SRAM) 2.1598 - { 2.1599 - // save SRAM 2.1600 - if (!theEmulator.emuWriteBatteryToStream(stream)) 2.1601 - { 2.1602 - utilGzClose(stream); 2.1603 - { loadingMovie = false; return MOVIE_UNKNOWN_ERROR; } 2.1604 - } 2.1605 - 2.1606 - // 'soft' reset: 2.1607 - theEmulator.emuReset(false); 2.1608 - } 2.1609 - 2.1610 - utilGzClose(stream); 2.1611 - 2.1612 - // reopen the file and seek back to the end 2.1613 - 2.1614 - if (!(file = fopen(movie_filename, "rb+"))) 2.1615 - { loadingMovie = false; return MOVIE_FILE_NOT_FOUND; } 2.1616 - 2.1617 - fseek(file, 0, SEEK_END); 2.1618 - } 2.1619 - else // no snapshot or SRAM 2.1620 - { 2.1621 - HardResetAndSRAMClear(); 2.1622 - } 2.1623 - 2.1624 - Movie.header.offset_to_controller_data = (uint32)ftell(file); 2.1625 - 2.1626 - strcpy(Movie.filename, movie_filename); 2.1627 - Movie.file = file; 2.1628 - Movie.bytesPerFrame = bytes_per_frame(Movie); 2.1629 - Movie.inputBufferPtr = Movie.inputBuffer; 2.1630 - Movie.currentFrame = 0; 2.1631 - Movie.readOnly = false; 2.1632 - Movie.RecordedThisSession = true; 2.1633 - 2.1634 - change_state(MOVIE_STATE_RECORD); 2.1635 - 2.1636 - systemScreenMessage("Recording movie..."); 2.1637 - { loadingMovie = false; return MOVIE_SUCCESS; } 2.1638 + systemScreenMessage("Recording movie..."); 2.1639 + { loadingMovie = false; return MOVIE_SUCCESS; } 2.1640 } 2.1641 2.1642 void VBAUpdateButtonPressDisplay() 2.1643 { 2.1644 - uint32 keys = currentButtons[0] & BUTTON_REGULAR_RECORDING_MASK; 2.1645 + uint32 keys = currentButtons[0] & BUTTON_REGULAR_RECORDING_MASK; 2.1646 2.1647 - const static char KeyMap[] = { 'A', 'B', 's', 'S', '>', '<', '^', 'v', 'R', 'L', '!', '?', '{', '}', 'v', '^' }; 2.1648 - 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 { = } _ 2.1649 - // ? ! 2.1650 - char buffer[256]; 2.1651 - sprintf(buffer, " "); 2.1652 + const static char KeyMap[] = { 'A', 'B', 's', 'S', '>', '<', '^', 'v', 'R', 'L', '!', '?', '{', '}', 'v', '^' }; 2.1653 + 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 { = } _ 2.1654 + // ? ! 2.1655 + char buffer[256]; 2.1656 + sprintf(buffer, " "); 2.1657 2.1658 #ifndef WIN32 2.1659 - // don't bother color-coding autofire and such 2.1660 - int i; 2.1661 - for (i = 0; i < 15; i++) 2.1662 + // don't bother color-coding autofire and such 2.1663 + int i; 2.1664 + for (i = 0; i < 15; i++) 2.1665 + { 2.1666 + int j = KeyOrder[i]; 2.1667 + int mask = (1 << (j)); 2.1668 + buffer[strlen(" ") + i] = ((keys & mask) != 0) ? KeyMap[j] : ' '; 2.1669 + } 2.1670 + 2.1671 + systemScreenMessage(buffer, 2, -1); 2.1672 +#else 2.1673 + const bool eraseAll = !theApp.inputDisplay; 2.1674 + uint32 autoHeldKeys = eraseAll ? 0 : theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; 2.1675 + uint32 autoFireKeys = eraseAll ? 0 : (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; 2.1676 + uint32 pressedKeys = eraseAll ? 0 : keys; 2.1677 + 2.1678 + char colorList[64]; 2.1679 + memset(colorList, 1, strlen(buffer)); 2.1680 + 2.1681 + if (!eraseAll) 2.1682 + { 2.1683 + for (int i = 0; i < 15; i++) 2.1684 { 2.1685 - int j = KeyOrder[i]; 2.1686 - int mask = (1 << (j)); 2.1687 - buffer[strlen(" ") + i] = ((keys & mask) != 0) ? KeyMap[j] : ' '; 2.1688 + const int j = KeyOrder[i]; 2.1689 + const int mask = (1 << (j)); 2.1690 + bool pressed = (pressedKeys & mask) != 0; 2.1691 + const bool autoHeld = (autoHeldKeys & mask) != 0; 2.1692 + const bool autoFired = (autoFireKeys & mask) != 0; 2.1693 + const bool erased = (lastKeys & mask) != 0 && (!pressed && !autoHeld && !autoFired); 2.1694 + extern int textMethod; 2.1695 + if (textMethod != 2 && (autoHeld || (autoFired && !pressed) || erased)) 2.1696 + { 2.1697 + int colorNum = 1; // default is white 2.1698 + if (autoHeld) 2.1699 + colorNum += (pressed ? 2 : 1); // yellow if pressed, red if not 2.1700 + else if (autoFired) 2.1701 + colorNum += 5; // blue if autofired and not currently pressed 2.1702 + else if (erased) 2.1703 + colorNum += 8; // black on black 2.1704 + 2.1705 + colorList[strlen(" ") + i] = colorNum; 2.1706 + pressed = true; 2.1707 + } 2.1708 + buffer[strlen(" ") + i] = pressed ? KeyMap[j] : ' '; 2.1709 } 2.1710 + } 2.1711 2.1712 - systemScreenMessage(buffer, 2, -1); 2.1713 -#else 2.1714 - const bool eraseAll = !theApp.inputDisplay; 2.1715 - uint32 autoHeldKeys = eraseAll ? 0 : theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; 2.1716 - uint32 autoFireKeys = eraseAll ? 0 : (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; 2.1717 - uint32 pressedKeys = eraseAll ? 0 : keys; 2.1718 + lastKeys = currentButtons[0]; 2.1719 + lastKeys |= theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; 2.1720 + lastKeys |= (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; 2.1721 2.1722 - char colorList[64]; 2.1723 - memset(colorList, 1, strlen(buffer)); 2.1724 - 2.1725 - if (!eraseAll) 2.1726 - { 2.1727 - for (int i = 0; i < 15; i++) 2.1728 - { 2.1729 - const int j = KeyOrder[i]; 2.1730 - const int mask = (1 << (j)); 2.1731 - bool pressed = (pressedKeys & mask) != 0; 2.1732 - const bool autoHeld = (autoHeldKeys & mask) != 0; 2.1733 - const bool autoFired = (autoFireKeys & mask) != 0; 2.1734 - const bool erased = (lastKeys & mask) != 0 && (!pressed && !autoHeld && !autoFired); 2.1735 - extern int textMethod; 2.1736 - if (textMethod != 2 && (autoHeld || (autoFired && !pressed) || erased)) 2.1737 - { 2.1738 - int colorNum = 1; // default is white 2.1739 - if (autoHeld) 2.1740 - colorNum += (pressed ? 2 : 1); // yellow if pressed, red if not 2.1741 - else if (autoFired) 2.1742 - colorNum += 5; // blue if autofired and not currently pressed 2.1743 - else if (erased) 2.1744 - colorNum += 8; // black on black 2.1745 - 2.1746 - colorList[strlen(" ") + i] = colorNum; 2.1747 - pressed = true; 2.1748 - } 2.1749 - buffer[strlen(" ") + i] = pressed ? KeyMap[j] : ' '; 2.1750 - } 2.1751 - } 2.1752 - 2.1753 - lastKeys = currentButtons[0]; 2.1754 - lastKeys |= theApp.autoHold & BUTTON_REGULAR_RECORDING_MASK; 2.1755 - lastKeys |= (theApp.autoFire | theApp.autoFire2) & BUTTON_REGULAR_RECORDING_MASK; 2.1756 - 2.1757 - systemScreenMessage(buffer, 2, -1, colorList); 2.1758 + systemScreenMessage(buffer, 2, -1, colorList); 2.1759 #endif 2.1760 } 2.1761 2.1762 void VBAUpdateFrameCountDisplay() 2.1763 { 2.1764 - const int MAGICAL_NUMBER = 64; // FIXME: this won't do any better, but only to remind you of sz issues 2.1765 - char frameDisplayString[MAGICAL_NUMBER]; 2.1766 - char lagFrameDisplayString[MAGICAL_NUMBER]; 2.1767 - char extraCountDisplayString[MAGICAL_NUMBER]; 2.1768 + const int MAGICAL_NUMBER = 64; // FIXME: this won't do any better, but only to remind you of sz issues 2.1769 + char frameDisplayString[MAGICAL_NUMBER]; 2.1770 + char lagFrameDisplayString[MAGICAL_NUMBER]; 2.1771 + char extraCountDisplayString[MAGICAL_NUMBER]; 2.1772 2.1773 #if (defined(WIN32) && !defined(SDL)) 2.1774 - if (theApp.frameCounter) 2.1775 + if (theApp.frameCounter) 2.1776 +#else 2.1777 + /// SDL FIXME 2.1778 +#endif 2.1779 + { 2.1780 + switch (Movie.state) 2.1781 + { 2.1782 + case MOVIE_STATE_PLAY: 2.1783 + case MOVIE_STATE_END: 2.1784 + { 2.1785 + sprintf(frameDisplayString, "%d / %d", Movie.currentFrame, Movie.header.length_frames); 2.1786 + if (!Movie.readOnly) 2.1787 + strcat(frameDisplayString, " (edit)"); 2.1788 + break; 2.1789 + } 2.1790 + case MOVIE_STATE_RECORD: 2.1791 + { 2.1792 + sprintf(frameDisplayString, "%d (record)", Movie.currentFrame); 2.1793 + break; 2.1794 + } 2.1795 + default: 2.1796 + { 2.1797 + sprintf(frameDisplayString, "%d (no movie)", systemCounters.frameCount); 2.1798 + break; 2.1799 + } 2.1800 + } 2.1801 + 2.1802 +#if (defined(WIN32) && !defined(SDL)) 2.1803 + if (theApp.lagCounter) 2.1804 #else 2.1805 /// SDL FIXME 2.1806 #endif 2.1807 { 2.1808 - switch (Movie.state) 2.1809 - { 2.1810 - case MOVIE_STATE_PLAY: 2.1811 - case MOVIE_STATE_END: 2.1812 - { 2.1813 - sprintf(frameDisplayString, "%d / %d", Movie.currentFrame, Movie.header.length_frames); 2.1814 - if (!Movie.readOnly) 2.1815 - strcat(frameDisplayString, " (edit)"); 2.1816 - break; 2.1817 - } 2.1818 - case MOVIE_STATE_RECORD: 2.1819 - { 2.1820 - sprintf(frameDisplayString, "%d (record)", Movie.currentFrame); 2.1821 - break; 2.1822 - } 2.1823 - default: 2.1824 - { 2.1825 - sprintf(frameDisplayString, "%d (no movie)", systemCounters.frameCount); 2.1826 - break; 2.1827 - } 2.1828 - } 2.1829 + // sprintf(lagFrameDisplayString, " %c %d", systemCounters.laggedLast ? '*' : '|', systemCounters.lagCount); 2.1830 + sprintf(lagFrameDisplayString, " | %d%s", systemCounters.lagCount, systemCounters.laggedLast ? " *" : ""); 2.1831 + strcat(frameDisplayString, lagFrameDisplayString); 2.1832 + } 2.1833 2.1834 #if (defined(WIN32) && !defined(SDL)) 2.1835 - if (theApp.lagCounter) 2.1836 -#else 2.1837 - /// SDL FIXME 2.1838 -#endif 2.1839 - { 2.1840 -// sprintf(lagFrameDisplayString, " %c %d", systemCounters.laggedLast ? '*' : '|', systemCounters.lagCount); 2.1841 - sprintf(lagFrameDisplayString, " | %d%s", systemCounters.lagCount, systemCounters.laggedLast ? " *" : ""); 2.1842 - strcat(frameDisplayString, lagFrameDisplayString); 2.1843 - } 2.1844 - 2.1845 -#if (defined(WIN32) && !defined(SDL)) 2.1846 - if (theApp.extraCounter) 2.1847 -#else 2.1848 - /// SDL FIXME 2.1849 -#endif 2.1850 - { 2.1851 - sprintf(extraCountDisplayString, " | %d", systemCounters.frameCount - systemCounters.extraCount); 2.1852 - strcat(frameDisplayString, extraCountDisplayString); 2.1853 - } 2.1854 - } 2.1855 -#if (defined(WIN32) && !defined(SDL)) 2.1856 - else 2.1857 - { 2.1858 - frameDisplayString[0] = '\0'; 2.1859 - } 2.1860 + if (theApp.extraCounter) 2.1861 #else 2.1862 /// SDL FIXME 2.1863 #endif 2.1864 - systemScreenMessage(frameDisplayString, 1, -1); 2.1865 + { 2.1866 + sprintf(extraCountDisplayString, " | %d", systemCounters.frameCount - systemCounters.extraCount); 2.1867 + strcat(frameDisplayString, extraCountDisplayString); 2.1868 + } 2.1869 + } 2.1870 +#if (defined(WIN32) && !defined(SDL)) 2.1871 + else 2.1872 + { 2.1873 + frameDisplayString[0] = '\0'; 2.1874 + } 2.1875 +#else 2.1876 + /// SDL FIXME 2.1877 +#endif 2.1878 + systemScreenMessage(frameDisplayString, 1, -1); 2.1879 } 2.1880 2.1881 // this function should only be called once every frame 2.1882 void VBAMovieUpdateState() 2.1883 { 2.1884 - ++Movie.currentFrame; 2.1885 - 2.1886 - if (Movie.state == MOVIE_STATE_PLAY) 2.1887 + ++Movie.currentFrame; 2.1888 + printf("RLM: inside updateState\n"); 2.1889 + if (Movie.state == MOVIE_STATE_PLAY) 2.1890 + { 2.1891 + Movie.inputBufferPtr += Movie.bytesPerFrame; 2.1892 + if (Movie.currentFrame >= Movie.header.length_frames) 2.1893 { 2.1894 - Movie.inputBufferPtr += Movie.bytesPerFrame; 2.1895 - if (Movie.currentFrame >= Movie.header.length_frames) 2.1896 - { 2.1897 - // the movie ends anyway; what to do next depends on the settings 2.1898 - change_state(MOVIE_STATE_END); 2.1899 - } 2.1900 + // the movie ends anyway; what to do next depends on the settings 2.1901 + change_state(MOVIE_STATE_END); 2.1902 } 2.1903 - else if (Movie.state == MOVIE_STATE_RECORD) 2.1904 - { 2.1905 - // use first fseek? 2.1906 - fwrite(Movie.inputBufferPtr, 1, Movie.bytesPerFrame, Movie.file); 2.1907 - Movie.header.length_frames = Movie.currentFrame; 2.1908 - Movie.inputBufferPtr += Movie.bytesPerFrame; 2.1909 - Movie.RecordedThisSession = true; 2.1910 - flush_movie_header(); 2.1911 - } 2.1912 - else if (Movie.state == MOVIE_STATE_END) 2.1913 - { 2.1914 - change_state(MOVIE_STATE_END); 2.1915 - } 2.1916 + } 2.1917 + else if (Movie.state == MOVIE_STATE_RECORD) 2.1918 + { 2.1919 + printf("RLM: Movie_STATE_RECORD\n"); 2.1920 + // use first fseek? 2.1921 + //TODO: THis is the problem. 2.1922 + //fwrite(Movie.inputBufferPtr, 1, Movie.bytesPerFrame, Movie.file); 2.1923 + printf("RLM: fuck.\n"); 2.1924 + Movie.header.length_frames = Movie.currentFrame; 2.1925 + Movie.inputBufferPtr += Movie.bytesPerFrame; 2.1926 + Movie.RecordedThisSession = true; 2.1927 + flush_movie_header(); 2.1928 + } 2.1929 + else if (Movie.state == MOVIE_STATE_END) 2.1930 + { 2.1931 + change_state(MOVIE_STATE_END); 2.1932 + } 2.1933 } 2.1934 2.1935 void VBAMovieRead(int i, bool /*sensor*/) 2.1936 { 2.1937 - if (Movie.state != MOVIE_STATE_PLAY) 2.1938 - return; 2.1939 + if (Movie.state != MOVIE_STATE_PLAY) 2.1940 + return; 2.1941 2.1942 - if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) 2.1943 - return; // not a controller we're recognizing 2.1944 + if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) 2.1945 + return; // not a controller we're recognizing 2.1946 2.1947 - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.1948 - { 2.1949 - currentButtons[i] = Read16(Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); 2.1950 - } 2.1951 - else 2.1952 - { 2.1953 - currentButtons[i] = 0; // pretend the controller is disconnected 2.1954 - } 2.1955 + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.1956 + { 2.1957 + currentButtons[i] = Read16(Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); 2.1958 + } 2.1959 + else 2.1960 + { 2.1961 + currentButtons[i] = 0; // pretend the controller is disconnected 2.1962 + } 2.1963 2.1964 - if ((currentButtons[i] & BUTTON_MASK_NEW_RESET) != 0) 2.1965 - resetSignaled = true; 2.1966 + if ((currentButtons[i] & BUTTON_MASK_NEW_RESET) != 0) 2.1967 + resetSignaled = true; 2.1968 } 2.1969 2.1970 void VBAMovieWrite(int i, bool /*sensor*/) 2.1971 { 2.1972 - if (Movie.state != MOVIE_STATE_RECORD) 2.1973 - return; 2.1974 + if (Movie.state != MOVIE_STATE_RECORD) 2.1975 + return; 2.1976 2.1977 - if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) 2.1978 - return; // not a controller we're recognizing 2.1979 + if (i < 0 || i >= MOVIE_NUM_OF_POSSIBLE_CONTROLLERS) 2.1980 + return; // not a controller we're recognizing 2.1981 2.1982 - reserve_buffer_space((uint32)((Movie.inputBufferPtr - Movie.inputBuffer) + Movie.bytesPerFrame)); 2.1983 + reserve_buffer_space((uint32)((Movie.inputBufferPtr - Movie.inputBuffer) + Movie.bytesPerFrame)); 2.1984 2.1985 - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.1986 + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.1987 + { 2.1988 + // get the current controller data 2.1989 + uint16 buttonData = currentButtons[i]; 2.1990 + 2.1991 + // mask away the irrelevent bits 2.1992 + buttonData &= BUTTON_REGULAR_MASK | BUTTON_MOTION_MASK; 2.1993 + 2.1994 + // soft-reset "button" for 1 frame if the game is reset while recording 2.1995 + if (resetSignaled) 2.1996 { 2.1997 - // get the current controller data 2.1998 - uint16 buttonData = currentButtons[i]; 2.1999 + buttonData |= BUTTON_MASK_NEW_RESET; 2.2000 + } 2.2001 2.2002 - // mask away the irrelevent bits 2.2003 - buttonData &= BUTTON_REGULAR_MASK | BUTTON_MOTION_MASK; 2.2004 + // backward compatibility kludge 2.2005 + if (resetSignaledLast) 2.2006 + { 2.2007 + buttonData |= BUTTON_MASK_OLD_RESET; 2.2008 + } 2.2009 2.2010 - // soft-reset "button" for 1 frame if the game is reset while recording 2.2011 - if (resetSignaled) 2.2012 - { 2.2013 - buttonData |= BUTTON_MASK_NEW_RESET; 2.2014 - } 2.2015 + Write16(buttonData, Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); 2.2016 2.2017 - // backward compatibility kludge 2.2018 - if (resetSignaledLast) 2.2019 - { 2.2020 - buttonData |= BUTTON_MASK_OLD_RESET; 2.2021 - } 2.2022 - 2.2023 - Write16(buttonData, Movie.inputBufferPtr + CONTROLLER_DATA_SIZE * i); 2.2024 - 2.2025 - // and for display 2.2026 - currentButtons[i] = buttonData; 2.2027 - } 2.2028 - else 2.2029 - { 2.2030 - // pretend the controller is disconnected (otherwise input it gives could cause desync since we're not writing it to the 2.2031 - // movie) 2.2032 - currentButtons[i] = 0; 2.2033 - } 2.2034 + // and for display 2.2035 + currentButtons[i] = buttonData; 2.2036 + } 2.2037 + else 2.2038 + { 2.2039 + // pretend the controller is disconnected (otherwise input it gives could cause desync since we're not writing it to the 2.2040 + // movie) 2.2041 + currentButtons[i] = 0; 2.2042 + } 2.2043 } 2.2044 2.2045 void VBAMovieStop(bool8 suppress_message) 2.2046 { 2.2047 - if (Movie.state != MOVIE_STATE_NONE) 2.2048 - { 2.2049 - change_state(MOVIE_STATE_NONE); 2.2050 - if (!suppress_message) 2.2051 - systemScreenMessage("Movie stop"); 2.2052 - } 2.2053 + if (Movie.state != MOVIE_STATE_NONE) 2.2054 + { 2.2055 + change_state(MOVIE_STATE_NONE); 2.2056 + if (!suppress_message) 2.2057 + systemScreenMessage("Movie stop"); 2.2058 + } 2.2059 } 2.2060 2.2061 int VBAMovieGetInfo(const char *filename, SMovie *info) 2.2062 { 2.2063 - assert(info != NULL); 2.2064 - if (info == NULL) 2.2065 - return -1; 2.2066 + assert(info != NULL); 2.2067 + if (info == NULL) 2.2068 + return -1; 2.2069 2.2070 - FILE * file; 2.2071 - int result; 2.2072 - SMovie &local_movie = *info; 2.2073 + FILE * file; 2.2074 + int result; 2.2075 + SMovie &local_movie = *info; 2.2076 2.2077 - memset(info, 0, sizeof(*info)); 2.2078 - if (filename[0] == '\0') 2.2079 - return MOVIE_FILE_NOT_FOUND; 2.2080 - if (!(file = fopen(filename, "rb"))) 2.2081 - return MOVIE_FILE_NOT_FOUND; 2.2082 + memset(info, 0, sizeof(*info)); 2.2083 + if (filename[0] == '\0') 2.2084 + return MOVIE_FILE_NOT_FOUND; 2.2085 + if (!(file = fopen(filename, "rb"))) 2.2086 + return MOVIE_FILE_NOT_FOUND; 2.2087 2.2088 - // read header 2.2089 - if ((result = (read_movie_header(file, local_movie))) != MOVIE_SUCCESS) 2.2090 - { 2.2091 - fclose(file); 2.2092 - return result; 2.2093 - } 2.2094 + // read header 2.2095 + if ((result = (read_movie_header(file, local_movie))) != MOVIE_SUCCESS) 2.2096 + { 2.2097 + fclose(file); 2.2098 + return result; 2.2099 + } 2.2100 2.2101 - // read the metadata / author info from file 2.2102 - fread(local_movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); 2.2103 + // read the metadata / author info from file 2.2104 + fread(local_movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, file); 2.2105 2.2106 - strncpy(local_movie.filename, filename, _MAX_PATH); 2.2107 - local_movie.filename[_MAX_PATH - 1] = '\0'; 2.2108 + strncpy(local_movie.filename, filename, _MAX_PATH); 2.2109 + local_movie.filename[_MAX_PATH - 1] = '\0'; 2.2110 2.2111 - if (Movie.file != NULL && stricmp(local_movie.filename, Movie.filename) == 0) // alreadyOpen 2.2112 - { 2.2113 - local_movie.bytesPerFrame = Movie.bytesPerFrame; 2.2114 - local_movie.header.length_frames = Movie.header.length_frames; 2.2115 - } 2.2116 - else 2.2117 - { 2.2118 - // recalculate length of movie from the file size 2.2119 - local_movie.bytesPerFrame = bytes_per_frame(local_movie); 2.2120 - fseek(file, 0, SEEK_END); 2.2121 - int fileSize = ftell(file); 2.2122 - local_movie.header.length_frames = 2.2123 - (fileSize - local_movie.header.offset_to_controller_data) / local_movie.bytesPerFrame; 2.2124 - } 2.2125 + if (Movie.file != NULL && stricmp(local_movie.filename, Movie.filename) == 0) // alreadyOpen 2.2126 + { 2.2127 + local_movie.bytesPerFrame = Movie.bytesPerFrame; 2.2128 + local_movie.header.length_frames = Movie.header.length_frames; 2.2129 + } 2.2130 + else 2.2131 + { 2.2132 + // recalculate length of movie from the file size 2.2133 + local_movie.bytesPerFrame = bytes_per_frame(local_movie); 2.2134 + fseek(file, 0, SEEK_END); 2.2135 + int fileSize = ftell(file); 2.2136 + local_movie.header.length_frames = 2.2137 + (fileSize - local_movie.header.offset_to_controller_data) / local_movie.bytesPerFrame; 2.2138 + } 2.2139 2.2140 - fclose(file); 2.2141 + fclose(file); 2.2142 2.2143 - if (access(filename, W_OK)) 2.2144 - info->readOnly = true; 2.2145 + if (access(filename, W_OK)) 2.2146 + info->readOnly = true; 2.2147 2.2148 - return MOVIE_SUCCESS; 2.2149 + return MOVIE_SUCCESS; 2.2150 } 2.2151 2.2152 bool8 VBAMovieActive() 2.2153 { 2.2154 - return (Movie.state != MOVIE_STATE_NONE); 2.2155 + return (Movie.state != MOVIE_STATE_NONE); 2.2156 } 2.2157 2.2158 bool8 VBAMovieLoading() 2.2159 { 2.2160 - return loadingMovie; 2.2161 + return loadingMovie; 2.2162 } 2.2163 2.2164 bool8 VBAMoviePlaying() 2.2165 { 2.2166 - return (Movie.state == MOVIE_STATE_PLAY); 2.2167 + return (Movie.state == MOVIE_STATE_PLAY); 2.2168 } 2.2169 2.2170 bool8 VBAMovieRecording() 2.2171 { 2.2172 - return (Movie.state == MOVIE_STATE_RECORD); 2.2173 + return (Movie.state == MOVIE_STATE_RECORD); 2.2174 } 2.2175 2.2176 bool8 VBAMovieReadOnly() 2.2177 { 2.2178 - if (!VBAMovieActive()) 2.2179 - return false; 2.2180 + if (!VBAMovieActive()) 2.2181 + return false; 2.2182 2.2183 - return Movie.readOnly; 2.2184 + return Movie.readOnly; 2.2185 } 2.2186 2.2187 void VBAMovieToggleReadOnly() 2.2188 { 2.2189 - if (!VBAMovieActive()) 2.2190 - return; 2.2191 + if (!VBAMovieActive()) 2.2192 + return; 2.2193 2.2194 - if (Movie.readOnly != 2) 2.2195 - { 2.2196 - Movie.readOnly = !Movie.readOnly; 2.2197 + if (Movie.readOnly != 2) 2.2198 + { 2.2199 + Movie.readOnly = !Movie.readOnly; 2.2200 2.2201 - systemScreenMessage(Movie.readOnly ? "Movie now read-only" : "Movie now editable"); 2.2202 - } 2.2203 - else 2.2204 - { 2.2205 - systemScreenMessage("Can't toggle read-only movie"); 2.2206 - } 2.2207 + systemScreenMessage(Movie.readOnly ? "Movie now read-only" : "Movie now editable"); 2.2208 + } 2.2209 + else 2.2210 + { 2.2211 + systemScreenMessage("Can't toggle read-only movie"); 2.2212 + } 2.2213 } 2.2214 2.2215 uint32 VBAMovieGetVersion() 2.2216 { 2.2217 - if (!VBAMovieActive()) 2.2218 - return 0; 2.2219 + if (!VBAMovieActive()) 2.2220 + return 0; 2.2221 2.2222 - return Movie.header.version; 2.2223 + return Movie.header.version; 2.2224 } 2.2225 2.2226 uint32 VBAMovieGetMinorVersion() 2.2227 { 2.2228 - if (!VBAMovieActive()) 2.2229 - return 0; 2.2230 + if (!VBAMovieActive()) 2.2231 + return 0; 2.2232 2.2233 - return Movie.header.minorVersion; 2.2234 + return Movie.header.minorVersion; 2.2235 } 2.2236 2.2237 uint32 VBAMovieGetId() 2.2238 { 2.2239 - if (!VBAMovieActive()) 2.2240 - return 0; 2.2241 + if (!VBAMovieActive()) 2.2242 + return 0; 2.2243 2.2244 - return Movie.header.uid; 2.2245 + return Movie.header.uid; 2.2246 } 2.2247 2.2248 uint32 VBAMovieGetLength() 2.2249 { 2.2250 - if (!VBAMovieActive()) 2.2251 - return 0; 2.2252 + if (!VBAMovieActive()) 2.2253 + return 0; 2.2254 2.2255 - return Movie.header.length_frames; 2.2256 + return Movie.header.length_frames; 2.2257 } 2.2258 2.2259 uint32 VBAMovieGetFrameCounter() 2.2260 { 2.2261 - if (!VBAMovieActive()) 2.2262 - return 0; 2.2263 + if (!VBAMovieActive()) 2.2264 + return 0; 2.2265 2.2266 - return Movie.currentFrame; 2.2267 + return Movie.currentFrame; 2.2268 } 2.2269 2.2270 uint32 VBAMovieGetRerecordCount() 2.2271 { 2.2272 - if (!VBAMovieActive()) 2.2273 - return 0; 2.2274 + if (!VBAMovieActive()) 2.2275 + return 0; 2.2276 2.2277 - return Movie.header.rerecord_count; 2.2278 + return Movie.header.rerecord_count; 2.2279 } 2.2280 2.2281 uint32 VBAMovieSetRerecordCount(uint32 newRerecordCount) 2.2282 { 2.2283 - uint32 oldRerecordCount = 0; 2.2284 - if (!VBAMovieActive()) 2.2285 - return 0; 2.2286 + uint32 oldRerecordCount = 0; 2.2287 + if (!VBAMovieActive()) 2.2288 + return 0; 2.2289 2.2290 - oldRerecordCount = Movie.header.rerecord_count; 2.2291 - Movie.header.rerecord_count = newRerecordCount; 2.2292 - return oldRerecordCount; 2.2293 + oldRerecordCount = Movie.header.rerecord_count; 2.2294 + Movie.header.rerecord_count = newRerecordCount; 2.2295 + return oldRerecordCount; 2.2296 } 2.2297 2.2298 std::string VBAMovieGetAuthorInfo() 2.2299 { 2.2300 - if (!VBAMovieActive()) 2.2301 - return ""; 2.2302 + if (!VBAMovieActive()) 2.2303 + return ""; 2.2304 2.2305 - return Movie.authorInfo; 2.2306 + return Movie.authorInfo; 2.2307 } 2.2308 2.2309 std::string VBAMovieGetFilename() 2.2310 { 2.2311 - if (!VBAMovieActive()) 2.2312 - return ""; 2.2313 + if (!VBAMovieActive()) 2.2314 + return ""; 2.2315 2.2316 - return Movie.filename; 2.2317 + return Movie.filename; 2.2318 } 2.2319 2.2320 void VBAMovieFreeze(uint8 * *buf, uint32 *size) 2.2321 { 2.2322 - // sanity check 2.2323 - if (!VBAMovieActive()) 2.2324 - { 2.2325 - return; 2.2326 - } 2.2327 + // sanity check 2.2328 + if (!VBAMovieActive()) 2.2329 + { 2.2330 + return; 2.2331 + } 2.2332 2.2333 - *buf = NULL; 2.2334 - *size = 0; 2.2335 + *buf = NULL; 2.2336 + *size = 0; 2.2337 2.2338 - // compute size needed for the buffer 2.2339 - // room for header.uid, currentFrame, and header.length_frames 2.2340 - uint32 size_needed = sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames); 2.2341 - size_needed += (uint32)(Movie.bytesPerFrame * Movie.header.length_frames); 2.2342 - *buf = new uint8[size_needed]; 2.2343 - *size = size_needed; 2.2344 + // compute size needed for the buffer 2.2345 + // room for header.uid, currentFrame, and header.length_frames 2.2346 + uint32 size_needed = sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames); 2.2347 + size_needed += (uint32)(Movie.bytesPerFrame * Movie.header.length_frames); 2.2348 + *buf = new uint8[size_needed]; 2.2349 + *size = size_needed; 2.2350 2.2351 - uint8 *ptr = *buf; 2.2352 - if (!ptr) 2.2353 - { 2.2354 - return; 2.2355 - } 2.2356 + uint8 *ptr = *buf; 2.2357 + if (!ptr) 2.2358 + { 2.2359 + return; 2.2360 + } 2.2361 2.2362 - Push32(Movie.header.uid, ptr); 2.2363 - Push32(Movie.currentFrame, ptr); 2.2364 - Push32(Movie.header.length_frames - 1, ptr); // HACK: shorten the length by 1 for backward compatibility 2.2365 + Push32(Movie.header.uid, ptr); 2.2366 + Push32(Movie.currentFrame, ptr); 2.2367 + Push32(Movie.header.length_frames - 1, ptr); // HACK: shorten the length by 1 for backward compatibility 2.2368 2.2369 - memcpy(ptr, Movie.inputBuffer, Movie.bytesPerFrame * Movie.header.length_frames); 2.2370 + memcpy(ptr, Movie.inputBuffer, Movie.bytesPerFrame * Movie.header.length_frames); 2.2371 } 2.2372 2.2373 int VBAMovieUnfreeze(const uint8 *buf, uint32 size) 2.2374 { 2.2375 - // sanity check 2.2376 - if (!VBAMovieActive()) 2.2377 + // sanity check 2.2378 + if (!VBAMovieActive()) 2.2379 + { 2.2380 + return MOVIE_NOT_FROM_A_MOVIE; 2.2381 + } 2.2382 + 2.2383 + const uint8 *ptr = buf; 2.2384 + if (size < sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames)) 2.2385 + { 2.2386 + return MOVIE_WRONG_FORMAT; 2.2387 + } 2.2388 + 2.2389 + uint32 movie_id = Pop32(ptr); 2.2390 + uint32 current_frame = Pop32(ptr); 2.2391 + uint32 end_frame = Pop32(ptr) + 1; // HACK: restore the length for backward compatibility 2.2392 + uint32 space_needed = Movie.bytesPerFrame * end_frame; 2.2393 + 2.2394 + if (movie_id != Movie.header.uid) 2.2395 + return MOVIE_NOT_FROM_THIS_MOVIE; 2.2396 + 2.2397 + if (space_needed > size) 2.2398 + return MOVIE_WRONG_FORMAT; 2.2399 + 2.2400 + if (Movie.readOnly) 2.2401 + { 2.2402 + // here, we are going to keep the input data from the movie file 2.2403 + // and simply rewind to the currentFrame pointer 2.2404 + // this will cause a desync if the savestate is not in sync // <-- NOT ANYMORE 2.2405 + // with the on-disk recording data, but it's easily solved 2.2406 + // by loading another savestate or playing the movie from the beginning 2.2407 + 2.2408 + // don't allow loading a state inconsistent with the current movie 2.2409 + uint32 length_history = min(current_frame, Movie.header.length_frames); 2.2410 + if (end_frame < length_history) 2.2411 + return MOVIE_SNAPSHOT_INCONSISTENT; 2.2412 + 2.2413 + uint32 space_shared = Movie.bytesPerFrame * length_history; 2.2414 + if (memcmp(Movie.inputBuffer, ptr, space_shared)) 2.2415 + return MOVIE_SNAPSHOT_INCONSISTENT; 2.2416 + 2.2417 + Movie.currentFrame = current_frame; 2.2418 + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); 2.2419 + } 2.2420 + else 2.2421 + { 2.2422 + // here, we are going to take the input data from the savestate 2.2423 + // and make it the input data for the current movie, then continue 2.2424 + // writing new input data at the currentFrame pointer 2.2425 + Movie.currentFrame = current_frame; 2.2426 + Movie.header.length_frames = end_frame; 2.2427 + if (!VBALuaRerecordCountSkip()) 2.2428 + ++Movie.header.rerecord_count; 2.2429 + 2.2430 + Movie.RecordedThisSession = true; 2.2431 + 2.2432 + // do this before calling reserve_buffer_space() 2.2433 + Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); 2.2434 + reserve_buffer_space(space_needed); 2.2435 + memcpy(Movie.inputBuffer, ptr, space_needed); 2.2436 + 2.2437 + // for consistency, no auto movie conversion here since we don't auto convert the corresponding savestate 2.2438 + flush_movie_header(); 2.2439 + flush_movie_frames(); 2.2440 + } 2.2441 + 2.2442 + change_state(MOVIE_STATE_PLAY); // check for movie end 2.2443 + 2.2444 + // necessary! 2.2445 + resetSignaled = false; 2.2446 + resetSignaledLast = false; 2.2447 + 2.2448 + // necessary to check if there's a reset signal at the previous frame 2.2449 + if (current_frame > 0) 2.2450 + { 2.2451 + const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); 2.2452 + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.2453 { 2.2454 - return MOVIE_NOT_FROM_A_MOVIE; 2.2455 + if ((Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) && (*(Movie.inputBufferPtr+1- Movie.bytesPerFrame) & NEW_RESET)) 2.2456 + { 2.2457 + resetSignaledLast = true; 2.2458 + break; 2.2459 + } 2.2460 } 2.2461 + } 2.2462 2.2463 - const uint8 *ptr = buf; 2.2464 - if (size < sizeof(Movie.header.uid) + sizeof(Movie.currentFrame) + sizeof(Movie.header.length_frames)) 2.2465 - { 2.2466 - return MOVIE_WRONG_FORMAT; 2.2467 - } 2.2468 - 2.2469 - uint32 movie_id = Pop32(ptr); 2.2470 - uint32 current_frame = Pop32(ptr); 2.2471 - uint32 end_frame = Pop32(ptr) + 1; // HACK: restore the length for backward compatibility 2.2472 - uint32 space_needed = Movie.bytesPerFrame * end_frame; 2.2473 - 2.2474 - if (movie_id != Movie.header.uid) 2.2475 - return MOVIE_NOT_FROM_THIS_MOVIE; 2.2476 - 2.2477 - if (space_needed > size) 2.2478 - return MOVIE_WRONG_FORMAT; 2.2479 - 2.2480 - if (Movie.readOnly) 2.2481 - { 2.2482 - // here, we are going to keep the input data from the movie file 2.2483 - // and simply rewind to the currentFrame pointer 2.2484 - // this will cause a desync if the savestate is not in sync // <-- NOT ANYMORE 2.2485 - // with the on-disk recording data, but it's easily solved 2.2486 - // by loading another savestate or playing the movie from the beginning 2.2487 - 2.2488 - // don't allow loading a state inconsistent with the current movie 2.2489 - uint32 length_history = min(current_frame, Movie.header.length_frames); 2.2490 - if (end_frame < length_history) 2.2491 - return MOVIE_SNAPSHOT_INCONSISTENT; 2.2492 - 2.2493 - uint32 space_shared = Movie.bytesPerFrame * length_history; 2.2494 - if (memcmp(Movie.inputBuffer, ptr, space_shared)) 2.2495 - return MOVIE_SNAPSHOT_INCONSISTENT; 2.2496 - 2.2497 - Movie.currentFrame = current_frame; 2.2498 - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); 2.2499 - } 2.2500 - else 2.2501 - { 2.2502 - // here, we are going to take the input data from the savestate 2.2503 - // and make it the input data for the current movie, then continue 2.2504 - // writing new input data at the currentFrame pointer 2.2505 - Movie.currentFrame = current_frame; 2.2506 - Movie.header.length_frames = end_frame; 2.2507 - if (!VBALuaRerecordCountSkip()) 2.2508 - ++Movie.header.rerecord_count; 2.2509 - 2.2510 - Movie.RecordedThisSession = true; 2.2511 - 2.2512 - // do this before calling reserve_buffer_space() 2.2513 - Movie.inputBufferPtr = Movie.inputBuffer + Movie.bytesPerFrame * min(current_frame, Movie.header.length_frames); 2.2514 - reserve_buffer_space(space_needed); 2.2515 - memcpy(Movie.inputBuffer, ptr, space_needed); 2.2516 - 2.2517 - // for consistency, no auto movie conversion here since we don't auto convert the corresponding savestate 2.2518 - flush_movie_header(); 2.2519 - flush_movie_frames(); 2.2520 - } 2.2521 - 2.2522 - change_state(MOVIE_STATE_PLAY); // check for movie end 2.2523 - 2.2524 - // necessary! 2.2525 - resetSignaled = false; 2.2526 - resetSignaledLast = false; 2.2527 - 2.2528 - // necessary to check if there's a reset signal at the previous frame 2.2529 - if (current_frame > 0) 2.2530 - { 2.2531 - const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); 2.2532 - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.2533 - { 2.2534 - if ((Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) && (*(Movie.inputBufferPtr+1- Movie.bytesPerFrame) & NEW_RESET)) 2.2535 - { 2.2536 - resetSignaledLast = true; 2.2537 - break; 2.2538 - } 2.2539 - } 2.2540 - } 2.2541 - 2.2542 - return MOVIE_SUCCESS; 2.2543 + return MOVIE_SUCCESS; 2.2544 } 2.2545 2.2546 bool VBAMovieEnded() 2.2547 { 2.2548 - return (Movie.state == MOVIE_STATE_END); 2.2549 -// return (Movie.state != MOVIE_STATE_NONE && Movie.currentFrame >= Movie.header.length_frames); 2.2550 + return (Movie.state == MOVIE_STATE_END); 2.2551 + // return (Movie.state != MOVIE_STATE_NONE && Movie.currentFrame >= Movie.header.length_frames); 2.2552 } 2.2553 2.2554 bool VBAMovieAllowsRerecording() 2.2555 { 2.2556 - bool allows = (Movie.state != MOVIE_STATE_NONE) && (Movie.currentFrame <= Movie.header.length_frames); 2.2557 - return /*!VBAMovieReadOnly() &&*/ allows; 2.2558 + bool allows = (Movie.state != MOVIE_STATE_NONE) && (Movie.currentFrame <= Movie.header.length_frames); 2.2559 + return /*!VBAMovieReadOnly() &&*/ allows; 2.2560 } 2.2561 2.2562 bool VBAMovieSwitchToPlaying() 2.2563 { 2.2564 - if (!VBAMovieActive()) 2.2565 - return false; 2.2566 + if (!VBAMovieActive()) 2.2567 + return false; 2.2568 2.2569 - if (!Movie.readOnly) 2.2570 - { 2.2571 - VBAMovieToggleReadOnly(); 2.2572 - } 2.2573 + if (!Movie.readOnly) 2.2574 + { 2.2575 + VBAMovieToggleReadOnly(); 2.2576 + } 2.2577 2.2578 - change_state(MOVIE_STATE_PLAY); 2.2579 - if (Movie.state == MOVIE_STATE_PLAY) 2.2580 - systemScreenMessage("Movie replay (continue)"); 2.2581 - else 2.2582 - systemScreenMessage("Movie end"); 2.2583 + change_state(MOVIE_STATE_PLAY); 2.2584 + if (Movie.state == MOVIE_STATE_PLAY) 2.2585 + systemScreenMessage("Movie replay (continue)"); 2.2586 + else 2.2587 + systemScreenMessage("Movie end"); 2.2588 2.2589 - return true; 2.2590 + return true; 2.2591 } 2.2592 2.2593 bool VBAMovieSwitchToRecording() 2.2594 { 2.2595 - if (!VBAMovieAllowsRerecording()) 2.2596 - return false; 2.2597 + if (!VBAMovieAllowsRerecording()) 2.2598 + return false; 2.2599 2.2600 - if (Movie.readOnly) 2.2601 - { 2.2602 - VBAMovieToggleReadOnly(); 2.2603 - } 2.2604 + if (Movie.readOnly) 2.2605 + { 2.2606 + VBAMovieToggleReadOnly(); 2.2607 + } 2.2608 2.2609 - if (!VBALuaRerecordCountSkip()) 2.2610 - ++Movie.header.rerecord_count; 2.2611 + if (!VBALuaRerecordCountSkip()) 2.2612 + ++Movie.header.rerecord_count; 2.2613 2.2614 - change_state(MOVIE_STATE_RECORD); 2.2615 - systemScreenMessage("Movie re-record"); 2.2616 + change_state(MOVIE_STATE_RECORD); 2.2617 + systemScreenMessage("Movie re-record"); 2.2618 2.2619 - //truncate_movie(Movie.currentFrame); 2.2620 + //truncate_movie(Movie.currentFrame); 2.2621 2.2622 - return true; 2.2623 + return true; 2.2624 } 2.2625 2.2626 uint32 VBAMovieGetState() 2.2627 { 2.2628 - // ? 2.2629 - if (!VBAMovieActive()) 2.2630 - return MOVIE_STATE_NONE; 2.2631 + // ? 2.2632 + if (!VBAMovieActive()) 2.2633 + return MOVIE_STATE_NONE; 2.2634 2.2635 - return Movie.state; 2.2636 + return Movie.state; 2.2637 } 2.2638 2.2639 void VBAMovieSignalReset() 2.2640 { 2.2641 - if (VBAMovieActive()) 2.2642 - resetSignaled = true; 2.2643 + if (VBAMovieActive()) 2.2644 + resetSignaled = true; 2.2645 } 2.2646 2.2647 void VBAMovieResetIfRequested() 2.2648 { 2.2649 - if (resetSignaled) 2.2650 - { 2.2651 - theEmulator.emuReset(false); 2.2652 - resetSignaled = false; 2.2653 - resetSignaledLast = true; 2.2654 - } 2.2655 - else 2.2656 - { 2.2657 - resetSignaledLast = false; 2.2658 - } 2.2659 + if (resetSignaled) 2.2660 + { 2.2661 + theEmulator.emuReset(false); 2.2662 + resetSignaled = false; 2.2663 + resetSignaledLast = true; 2.2664 + } 2.2665 + else 2.2666 + { 2.2667 + resetSignaledLast = false; 2.2668 + } 2.2669 } 2.2670 2.2671 void VBAMovieSetMetadata(const char *info) 2.2672 { 2.2673 - if (!memcmp(Movie.authorInfo, info, MOVIE_METADATA_SIZE)) 2.2674 - return; 2.2675 + if (!memcmp(Movie.authorInfo, info, MOVIE_METADATA_SIZE)) 2.2676 + return; 2.2677 2.2678 - memcpy(Movie.authorInfo, info, MOVIE_METADATA_SIZE); // strncpy would omit post-0 bytes 2.2679 - Movie.authorInfo[MOVIE_METADATA_SIZE - 1] = '\0'; 2.2680 + memcpy(Movie.authorInfo, info, MOVIE_METADATA_SIZE); // strncpy would omit post-0 bytes 2.2681 + Movie.authorInfo[MOVIE_METADATA_SIZE - 1] = '\0'; 2.2682 2.2683 - if (Movie.file) 2.2684 - { 2.2685 - // (over-)write the header 2.2686 - fseek(Movie.file, 0, SEEK_SET); 2.2687 - write_movie_header(Movie.file, Movie); 2.2688 + if (Movie.file) 2.2689 + { 2.2690 + // (over-)write the header 2.2691 + fseek(Movie.file, 0, SEEK_SET); 2.2692 2.2693 - // write the metadata / author info to file 2.2694 - fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, Movie.file); 2.2695 + write_movie_header(Movie.file, Movie); 2.2696 2.2697 - fflush(Movie.file); 2.2698 - } 2.2699 + // write the metadata / author info to file 2.2700 + fwrite(Movie.authorInfo, 1, sizeof(char) * MOVIE_METADATA_SIZE, Movie.file); 2.2701 + 2.2702 + fflush(Movie.file); 2.2703 + } 2.2704 + printf("RLM: setMetadata called\n"); 2.2705 + 2.2706 } 2.2707 2.2708 void VBAMovieRestart() 2.2709 { 2.2710 - if (VBAMovieActive()) 2.2711 - { 2.2712 - systemSoundClearBuffer(); 2.2713 + if (VBAMovieActive()) 2.2714 + { 2.2715 + systemSoundClearBuffer(); 2.2716 2.2717 - bool8 modified = Movie.RecordedThisSession; 2.2718 + bool8 modified = Movie.RecordedThisSession; 2.2719 2.2720 - VBAMovieStop(true); 2.2721 + VBAMovieStop(true); 2.2722 2.2723 - char movieName [_MAX_PATH]; 2.2724 - strncpy(movieName, Movie.filename, _MAX_PATH); 2.2725 - movieName[_MAX_PATH - 1] = '\0'; 2.2726 - VBAMovieOpen(movieName, Movie.readOnly); // can't just pass in Movie.filename, since VBAMovieOpen clears out Movie's 2.2727 - // variables 2.2728 + char movieName [_MAX_PATH]; 2.2729 + strncpy(movieName, Movie.filename, _MAX_PATH); 2.2730 + movieName[_MAX_PATH - 1] = '\0'; 2.2731 + VBAMovieOpen(movieName, Movie.readOnly); // can't just pass in Movie.filename, since VBAMovieOpen clears out Movie's 2.2732 + // variables 2.2733 2.2734 - Movie.RecordedThisSession = modified; 2.2735 + Movie.RecordedThisSession = modified; 2.2736 2.2737 - systemScreenMessage("Movie replay (restart)"); 2.2738 - } 2.2739 + systemScreenMessage("Movie replay (restart)"); 2.2740 + } 2.2741 } 2.2742 2.2743 int VBAMovieGetPauseAt() 2.2744 { 2.2745 - return Movie.pauseFrame; 2.2746 + return Movie.pauseFrame; 2.2747 } 2.2748 2.2749 void VBAMovieSetPauseAt(int at) 2.2750 { 2.2751 - Movie.pauseFrame = at; 2.2752 + Movie.pauseFrame = at; 2.2753 } 2.2754 2.2755 /////////////////////// 2.2756 @@ -1688,85 +1703,85 @@ 2.2757 // FIXME: is it safe to convert/flush a movie while recording it (considering fseek() problem)? 2.2758 int VBAMovieConvertCurrent() 2.2759 { 2.2760 - if (!VBAMovieActive()) 2.2761 + if (!VBAMovieActive()) 2.2762 + { 2.2763 + return MOVIE_NOTHING; 2.2764 + } 2.2765 + 2.2766 + if (Movie.header.minorVersion > VBM_REVISION) 2.2767 + { 2.2768 + return MOVIE_WRONG_VERSION; 2.2769 + } 2.2770 + 2.2771 + if (Movie.header.minorVersion == VBM_REVISION) 2.2772 + { 2.2773 + return MOVIE_NOTHING; 2.2774 + } 2.2775 + 2.2776 + Movie.header.minorVersion = VBM_REVISION; 2.2777 + 2.2778 + if (Movie.header.length_frames == 0) // this could happen 2.2779 + { 2.2780 + truncate_movie(0); 2.2781 + return MOVIE_SUCCESS; 2.2782 + } 2.2783 + 2.2784 + // fix movies recorded from snapshots 2.2785 + if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) 2.2786 + { 2.2787 + uint8 *firstFramePtr = Movie.inputBuffer; 2.2788 + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.2789 { 2.2790 - return MOVIE_NOTHING; 2.2791 + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.2792 + { 2.2793 + Push16(initialInputs[i], firstFramePtr); 2.2794 + // note: this is correct since Push16 advances the dest pointer by sizeof u16 2.2795 + } 2.2796 } 2.2797 + } 2.2798 2.2799 - if (Movie.header.minorVersion > VBM_REVISION) 2.2800 + // convert old resets to new ones 2.2801 + const u8 OLD_RESET = u8(BUTTON_MASK_OLD_RESET >> 8); 2.2802 + const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); 2.2803 + for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.2804 + { 2.2805 + if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.2806 { 2.2807 - return MOVIE_WRONG_VERSION; 2.2808 + uint8 *startPtr = Movie.inputBuffer + sizeof(u16) * i + 1; 2.2809 + uint8 *endPtr = Movie.inputBuffer + Movie.bytesPerFrame * (Movie.header.length_frames - 1); 2.2810 + for (; startPtr < endPtr; startPtr += Movie.bytesPerFrame) 2.2811 + { 2.2812 + if (startPtr[Movie.bytesPerFrame] & OLD_RESET) 2.2813 + { 2.2814 + startPtr[0] |= NEW_RESET; 2.2815 + } 2.2816 + } 2.2817 } 2.2818 + } 2.2819 2.2820 - if (Movie.header.minorVersion == VBM_REVISION) 2.2821 - { 2.2822 - return MOVIE_NOTHING; 2.2823 - } 2.2824 - 2.2825 - Movie.header.minorVersion = VBM_REVISION; 2.2826 - 2.2827 - if (Movie.header.length_frames == 0) // this could happen 2.2828 - { 2.2829 - truncate_movie(0); 2.2830 - return MOVIE_SUCCESS; 2.2831 - } 2.2832 - 2.2833 - // fix movies recorded from snapshots 2.2834 - if (Movie.header.startFlags & MOVIE_START_FROM_SNAPSHOT) 2.2835 - { 2.2836 - uint8 *firstFramePtr = Movie.inputBuffer; 2.2837 - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.2838 - { 2.2839 - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.2840 - { 2.2841 - Push16(initialInputs[i], firstFramePtr); 2.2842 - // note: this is correct since Push16 advances the dest pointer by sizeof u16 2.2843 - } 2.2844 - } 2.2845 - } 2.2846 - 2.2847 - // convert old resets to new ones 2.2848 - const u8 OLD_RESET = u8(BUTTON_MASK_OLD_RESET >> 8); 2.2849 - const u8 NEW_RESET = u8(BUTTON_MASK_NEW_RESET >> 8); 2.2850 - for (int i = 0; i < MOVIE_NUM_OF_POSSIBLE_CONTROLLERS; ++i) 2.2851 - { 2.2852 - if (Movie.header.controllerFlags & MOVIE_CONTROLLER(i)) 2.2853 - { 2.2854 - uint8 *startPtr = Movie.inputBuffer + sizeof(u16) * i + 1; 2.2855 - uint8 *endPtr = Movie.inputBuffer + Movie.bytesPerFrame * (Movie.header.length_frames - 1); 2.2856 - for (; startPtr < endPtr; startPtr += Movie.bytesPerFrame) 2.2857 - { 2.2858 - if (startPtr[Movie.bytesPerFrame] & OLD_RESET) 2.2859 - { 2.2860 - startPtr[0] |= NEW_RESET; 2.2861 - } 2.2862 - } 2.2863 - } 2.2864 - } 2.2865 - 2.2866 - flush_movie_header(); 2.2867 - flush_movie_frames(); 2.2868 - return MOVIE_SUCCESS; 2.2869 + flush_movie_header(); 2.2870 + flush_movie_frames(); 2.2871 + return MOVIE_SUCCESS; 2.2872 } 2.2873 2.2874 bool VBAMovieTuncateAtCurrentFrame() 2.2875 { 2.2876 - if (!VBAMovieActive()) 2.2877 - return false; 2.2878 + if (!VBAMovieActive()) 2.2879 + return false; 2.2880 2.2881 - truncate_movie(Movie.currentFrame); 2.2882 - change_state(MOVIE_STATE_END); 2.2883 - systemScreenMessage("Movie truncated"); 2.2884 + truncate_movie(Movie.currentFrame); 2.2885 + change_state(MOVIE_STATE_END); 2.2886 + systemScreenMessage("Movie truncated"); 2.2887 2.2888 - return true; 2.2889 + return true; 2.2890 } 2.2891 2.2892 bool VBAMovieFixHeader() 2.2893 { 2.2894 - if (!VBAMovieActive()) 2.2895 - return false; 2.2896 + if (!VBAMovieActive()) 2.2897 + return false; 2.2898 2.2899 - flush_movie_header(); 2.2900 - systemScreenMessage("Movie header fixed"); 2.2901 - return true; 2.2902 + flush_movie_header(); 2.2903 + systemScreenMessage("Movie header fixed"); 2.2904 + return true; 2.2905 }
3.1 --- a/src/gb/GB.cpp Sun Mar 04 22:44:42 2012 -0600 3.2 +++ b/src/gb/GB.cpp Mon Mar 05 01:25:11 2012 -0600 3.3 @@ -163,361 +163,361 @@ 3.4 static bool pauseAfterFrameAdvance = false; 3.5 3.6 int32 gbRomSizes[] = { 0x00008000, // 32K 3.7 - 0x00010000, // 64K 3.8 - 0x00020000, // 128K 3.9 - 0x00040000, // 256K 3.10 - 0x00080000, // 512K 3.11 - 0x00100000, // 1024K 3.12 - 0x00200000, // 2048K 3.13 - 0x00400000, // 4096K 3.14 - 0x00800000 // 8192K 3.15 + 0x00010000, // 64K 3.16 + 0x00020000, // 128K 3.17 + 0x00040000, // 256K 3.18 + 0x00080000, // 512K 3.19 + 0x00100000, // 1024K 3.20 + 0x00200000, // 2048K 3.21 + 0x00400000, // 4096K 3.22 + 0x00800000 // 8192K 3.23 }; 3.24 int32 gbRomSizesMasks[] = { 0x00007fff, 3.25 - 0x0000ffff, 3.26 - 0x0001ffff, 3.27 - 0x0003ffff, 3.28 - 0x0007ffff, 3.29 - 0x000fffff, 3.30 - 0x001fffff, 3.31 - 0x003fffff, 3.32 - 0x007fffff }; 3.33 + 0x0000ffff, 3.34 + 0x0001ffff, 3.35 + 0x0003ffff, 3.36 + 0x0007ffff, 3.37 + 0x000fffff, 3.38 + 0x001fffff, 3.39 + 0x003fffff, 3.40 + 0x007fffff }; 3.41 3.42 int32 gbRamSizes[6] = { 0x00000000, // 0K 3.43 - 0x00000800, // 2K 3.44 - 0x00002000, // 8K 3.45 - 0x00008000, // 32K 3.46 - 0x00020000, // 128K 3.47 - 0x00010000 // 64K 3.48 + 0x00000800, // 2K 3.49 + 0x00002000, // 8K 3.50 + 0x00008000, // 32K 3.51 + 0x00020000, // 128K 3.52 + 0x00010000 // 64K 3.53 }; 3.54 3.55 int32 gbRamSizesMasks[6] = { 0x00000000, 3.56 - 0x000007ff, 3.57 - 0x00001fff, 3.58 - 0x00007fff, 3.59 - 0x0001ffff, 3.60 - 0x0000ffff }; 3.61 + 0x000007ff, 3.62 + 0x00001fff, 3.63 + 0x00007fff, 3.64 + 0x0001ffff, 3.65 + 0x0000ffff }; 3.66 3.67 int32 gbCycles[] = 3.68 -{ 3.69 -// 0 1 2 3 4 5 6 7 8 9 a b c d e f 3.70 - 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 3.71 - 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 3.72 - 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 3.73 - 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 3.74 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 3.75 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 3.76 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 3.77 - 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 3.78 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 3.79 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 3.80 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a 3.81 - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b 3.82 - 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c 3.83 - 2, 3, 3, 0, 3, 4, 2, 4, 2, 4, 3, 0, 3, 0, 2, 4, // d 3.84 - 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4, // e 3.85 - 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4 // f 3.86 -}; 3.87 + { 3.88 + // 0 1 2 3 4 5 6 7 8 9 a b c d e f 3.89 + 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0 3.90 + 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1 3.91 + 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2 3.92 + 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3 3.93 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4 3.94 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5 3.95 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6 3.96 + 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7 3.97 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8 3.98 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9 3.99 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a 3.100 + 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b 3.101 + 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c 3.102 + 2, 3, 3, 0, 3, 4, 2, 4, 2, 4, 3, 0, 3, 0, 2, 4, // d 3.103 + 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4, // e 3.104 + 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4 // f 3.105 + }; 3.106 3.107 int32 gbCyclesCB[] = 3.108 -{ 3.109 -// 0 1 2 3 4 5 6 7 8 9 a b c d e f 3.110 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 3.111 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 3.112 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 3.113 - 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 3.114 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 3.115 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 3.116 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 3.117 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 3.118 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 8 3.119 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 9 3.120 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // a 3.121 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // b 3.122 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // c 3.123 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // d 3.124 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // e 3.125 - 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 // f 3.126 -}; 3.127 + { 3.128 + // 0 1 2 3 4 5 6 7 8 9 a b c d e f 3.129 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0 3.130 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1 3.131 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2 3.132 + 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3 3.133 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4 3.134 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5 3.135 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6 3.136 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7 3.137 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 8 3.138 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 9 3.139 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // a 3.140 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // b 3.141 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // c 3.142 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // d 3.143 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // e 3.144 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 // f 3.145 + }; 3.146 3.147 u16 DAATable[] = 3.148 -{ 3.149 - 0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, 3.150 - 0x0800, 0x0900, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, 3.151 - 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, 3.152 - 0x1800, 0x1900, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, 3.153 - 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, 3.154 - 0x2800, 0x2900, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, 3.155 - 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, 3.156 - 0x3800, 0x3900, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, 3.157 - 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, 3.158 - 0x4800, 0x4900, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, 3.159 - 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, 3.160 - 0x5800, 0x5900, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, 3.161 - 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700, 3.162 - 0x6800, 0x6900, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, 3.163 - 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, 3.164 - 0x7800, 0x7900, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, 3.165 - 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 3.166 - 0x8800, 0x8900, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, 3.167 - 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700, 3.168 - 0x9800, 0x9900, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.169 - 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, 3.170 - 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.171 - 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, 3.172 - 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.173 - 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, 3.174 - 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.175 - 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, 3.176 - 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.177 - 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, 3.178 - 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.179 - 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, 3.180 - 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.181 - 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710, 3.182 - 0x6810, 0x6910, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, 3.183 - 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710, 3.184 - 0x7810, 0x7910, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, 3.185 - 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710, 3.186 - 0x8810, 0x8910, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, 3.187 - 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710, 3.188 - 0x9810, 0x9910, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, 3.189 - 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710, 3.190 - 0xA810, 0xA910, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, 3.191 - 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710, 3.192 - 0xB810, 0xB910, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, 3.193 - 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710, 3.194 - 0xC810, 0xC910, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, 3.195 - 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710, 3.196 - 0xD810, 0xD910, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, 3.197 - 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710, 3.198 - 0xE810, 0xE910, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, 3.199 - 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710, 3.200 - 0xF810, 0xF910, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.201 - 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, 3.202 - 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.203 - 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, 3.204 - 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.205 - 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, 3.206 - 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.207 - 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, 3.208 - 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.209 - 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, 3.210 - 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.211 - 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, 3.212 - 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.213 - 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 3.214 - 0x0E00, 0x0F00, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, 3.215 - 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, 3.216 - 0x1E00, 0x1F00, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, 3.217 - 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, 3.218 - 0x2E00, 0x2F00, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, 3.219 - 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, 3.220 - 0x3E00, 0x3F00, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, 3.221 - 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, 3.222 - 0x4E00, 0x4F00, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, 3.223 - 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, 3.224 - 0x5E00, 0x5F00, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, 3.225 - 0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00, 3.226 - 0x6E00, 0x6F00, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, 3.227 - 0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00, 3.228 - 0x7E00, 0x7F00, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, 3.229 - 0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00, 3.230 - 0x8E00, 0x8F00, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, 3.231 - 0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00, 3.232 - 0x9E00, 0x9F00, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.233 - 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, 3.234 - 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.235 - 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, 3.236 - 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.237 - 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, 3.238 - 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.239 - 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, 3.240 - 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.241 - 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, 3.242 - 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.243 - 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, 3.244 - 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.245 - 0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10, 3.246 - 0x6E10, 0x6F10, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, 3.247 - 0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10, 3.248 - 0x7E10, 0x7F10, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, 3.249 - 0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10, 3.250 - 0x8E10, 0x8F10, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, 3.251 - 0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10, 3.252 - 0x9E10, 0x9F10, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, 3.253 - 0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10, 3.254 - 0xAE10, 0xAF10, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, 3.255 - 0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10, 3.256 - 0xBE10, 0xBF10, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, 3.257 - 0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10, 3.258 - 0xCE10, 0xCF10, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, 3.259 - 0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10, 3.260 - 0xDE10, 0xDF10, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, 3.261 - 0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10, 3.262 - 0xEE10, 0xEF10, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, 3.263 - 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10, 3.264 - 0xFE10, 0xFF10, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.265 - 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, 3.266 - 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.267 - 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, 3.268 - 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.269 - 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, 3.270 - 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.271 - 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, 3.272 - 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.273 - 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, 3.274 - 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.275 - 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, 3.276 - 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.277 - 0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 3.278 - 0x0840, 0x0940, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, 3.279 - 0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 3.280 - 0x1840, 0x1940, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, 3.281 - 0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 3.282 - 0x2840, 0x2940, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, 3.283 - 0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 3.284 - 0x3840, 0x3940, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, 3.285 - 0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 3.286 - 0x4840, 0x4940, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, 3.287 - 0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 3.288 - 0x5840, 0x5940, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, 3.289 - 0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 3.290 - 0x6840, 0x6940, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, 3.291 - 0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 3.292 - 0x7840, 0x7940, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, 3.293 - 0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 3.294 - 0x8840, 0x8940, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, 3.295 - 0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740, 3.296 - 0x9840, 0x9940, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.297 - 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 3.298 - 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.299 - 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 3.300 - 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.301 - 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 3.302 - 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.303 - 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 3.304 - 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.305 - 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 3.306 - 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.307 - 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 3.308 - 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.309 - 0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 3.310 - 0xA850, 0xA950, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, 3.311 - 0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 3.312 - 0xB850, 0xB950, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, 3.313 - 0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 3.314 - 0xC850, 0xC950, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, 3.315 - 0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 3.316 - 0xD850, 0xD950, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, 3.317 - 0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 3.318 - 0xE850, 0xE950, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, 3.319 - 0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 3.320 - 0xF850, 0xF950, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, 3.321 - 0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 3.322 - 0x0850, 0x0950, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, 3.323 - 0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 3.324 - 0x1850, 0x1950, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, 3.325 - 0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 3.326 - 0x2850, 0x2950, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, 3.327 - 0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 3.328 - 0x3850, 0x3950, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.329 - 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 3.330 - 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.331 - 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 3.332 - 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.333 - 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 3.334 - 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.335 - 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 3.336 - 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.337 - 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 3.338 - 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.339 - 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 3.340 - 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.341 - 0xFA60, 0xFB60, 0xFC60, 0xFD60, 0xFE60, 0xFF60, 0x00C0, 0x0140, 3.342 - 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, 3.343 - 0x0A60, 0x0B60, 0x0C60, 0x0D60, 0x0E60, 0x0F60, 0x1040, 0x1140, 3.344 - 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, 3.345 - 0x1A60, 0x1B60, 0x1C60, 0x1D60, 0x1E60, 0x1F60, 0x2040, 0x2140, 3.346 - 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, 3.347 - 0x2A60, 0x2B60, 0x2C60, 0x2D60, 0x2E60, 0x2F60, 0x3040, 0x3140, 3.348 - 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, 3.349 - 0x3A60, 0x3B60, 0x3C60, 0x3D60, 0x3E60, 0x3F60, 0x4040, 0x4140, 3.350 - 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, 3.351 - 0x4A60, 0x4B60, 0x4C60, 0x4D60, 0x4E60, 0x4F60, 0x5040, 0x5140, 3.352 - 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, 3.353 - 0x5A60, 0x5B60, 0x5C60, 0x5D60, 0x5E60, 0x5F60, 0x6040, 0x6140, 3.354 - 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, 3.355 - 0x6A60, 0x6B60, 0x6C60, 0x6D60, 0x6E60, 0x6F60, 0x7040, 0x7140, 3.356 - 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, 3.357 - 0x7A60, 0x7B60, 0x7C60, 0x7D60, 0x7E60, 0x7F60, 0x8040, 0x8140, 3.358 - 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, 3.359 - 0x8A60, 0x8B60, 0x8C60, 0x8D60, 0x8E60, 0x8F60, 0x9040, 0x9140, 3.360 - 0x9240, 0x9340, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.361 - 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, 3.362 - 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.363 - 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, 3.364 - 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.365 - 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, 3.366 - 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.367 - 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, 3.368 - 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.369 - 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, 3.370 - 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.371 - 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, 3.372 - 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.373 - 0x9A70, 0x9B70, 0x9C70, 0x9D70, 0x9E70, 0x9F70, 0xA050, 0xA150, 3.374 - 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, 3.375 - 0xAA70, 0xAB70, 0xAC70, 0xAD70, 0xAE70, 0xAF70, 0xB050, 0xB150, 3.376 - 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, 3.377 - 0xBA70, 0xBB70, 0xBC70, 0xBD70, 0xBE70, 0xBF70, 0xC050, 0xC150, 3.378 - 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, 3.379 - 0xCA70, 0xCB70, 0xCC70, 0xCD70, 0xCE70, 0xCF70, 0xD050, 0xD150, 3.380 - 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, 3.381 - 0xDA70, 0xDB70, 0xDC70, 0xDD70, 0xDE70, 0xDF70, 0xE050, 0xE150, 3.382 - 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, 3.383 - 0xEA70, 0xEB70, 0xEC70, 0xED70, 0xEE70, 0xEF70, 0xF050, 0xF150, 3.384 - 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, 3.385 - 0xFA70, 0xFB70, 0xFC70, 0xFD70, 0xFE70, 0xFF70, 0x00D0, 0x0150, 3.386 - 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, 3.387 - 0x0A70, 0x0B70, 0x0C70, 0x0D70, 0x0E70, 0x0F70, 0x1050, 0x1150, 3.388 - 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, 3.389 - 0x1A70, 0x1B70, 0x1C70, 0x1D70, 0x1E70, 0x1F70, 0x2050, 0x2150, 3.390 - 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, 3.391 - 0x2A70, 0x2B70, 0x2C70, 0x2D70, 0x2E70, 0x2F70, 0x3050, 0x3150, 3.392 - 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.393 - 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, 3.394 - 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.395 - 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, 3.396 - 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.397 - 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, 3.398 - 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.399 - 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, 3.400 - 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.401 - 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, 3.402 - 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.403 - 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, 3.404 - 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.405 -}; 3.406 + { 3.407 + 0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, 3.408 + 0x0800, 0x0900, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, 3.409 + 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700, 3.410 + 0x1800, 0x1900, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, 3.411 + 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700, 3.412 + 0x2800, 0x2900, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, 3.413 + 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700, 3.414 + 0x3800, 0x3900, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, 3.415 + 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700, 3.416 + 0x4800, 0x4900, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, 3.417 + 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700, 3.418 + 0x5800, 0x5900, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, 3.419 + 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700, 3.420 + 0x6800, 0x6900, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, 3.421 + 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, 3.422 + 0x7800, 0x7900, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, 3.423 + 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 3.424 + 0x8800, 0x8900, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, 3.425 + 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700, 3.426 + 0x9800, 0x9900, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.427 + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, 3.428 + 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.429 + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, 3.430 + 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.431 + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, 3.432 + 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.433 + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, 3.434 + 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.435 + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, 3.436 + 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.437 + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, 3.438 + 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.439 + 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710, 3.440 + 0x6810, 0x6910, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, 3.441 + 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710, 3.442 + 0x7810, 0x7910, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, 3.443 + 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710, 3.444 + 0x8810, 0x8910, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, 3.445 + 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710, 3.446 + 0x9810, 0x9910, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, 3.447 + 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710, 3.448 + 0xA810, 0xA910, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, 3.449 + 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710, 3.450 + 0xB810, 0xB910, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, 3.451 + 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710, 3.452 + 0xC810, 0xC910, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, 3.453 + 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710, 3.454 + 0xD810, 0xD910, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, 3.455 + 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710, 3.456 + 0xE810, 0xE910, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, 3.457 + 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710, 3.458 + 0xF810, 0xF910, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.459 + 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710, 3.460 + 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.461 + 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710, 3.462 + 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.463 + 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710, 3.464 + 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.465 + 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710, 3.466 + 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.467 + 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710, 3.468 + 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.469 + 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710, 3.470 + 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.471 + 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 3.472 + 0x0E00, 0x0F00, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520, 3.473 + 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00, 3.474 + 0x1E00, 0x1F00, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520, 3.475 + 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00, 3.476 + 0x2E00, 0x2F00, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520, 3.477 + 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00, 3.478 + 0x3E00, 0x3F00, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520, 3.479 + 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00, 3.480 + 0x4E00, 0x4F00, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520, 3.481 + 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00, 3.482 + 0x5E00, 0x5F00, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520, 3.483 + 0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00, 3.484 + 0x6E00, 0x6F00, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520, 3.485 + 0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00, 3.486 + 0x7E00, 0x7F00, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520, 3.487 + 0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00, 3.488 + 0x8E00, 0x8F00, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520, 3.489 + 0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00, 3.490 + 0x9E00, 0x9F00, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.491 + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, 3.492 + 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.493 + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, 3.494 + 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.495 + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, 3.496 + 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.497 + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, 3.498 + 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.499 + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, 3.500 + 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.501 + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, 3.502 + 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.503 + 0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10, 3.504 + 0x6E10, 0x6F10, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530, 3.505 + 0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10, 3.506 + 0x7E10, 0x7F10, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530, 3.507 + 0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10, 3.508 + 0x8E10, 0x8F10, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530, 3.509 + 0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10, 3.510 + 0x9E10, 0x9F10, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530, 3.511 + 0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10, 3.512 + 0xAE10, 0xAF10, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530, 3.513 + 0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10, 3.514 + 0xBE10, 0xBF10, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530, 3.515 + 0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10, 3.516 + 0xCE10, 0xCF10, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530, 3.517 + 0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10, 3.518 + 0xDE10, 0xDF10, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530, 3.519 + 0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10, 3.520 + 0xEE10, 0xEF10, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530, 3.521 + 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10, 3.522 + 0xFE10, 0xFF10, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530, 3.523 + 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10, 3.524 + 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530, 3.525 + 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10, 3.526 + 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530, 3.527 + 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10, 3.528 + 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 3.529 + 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10, 3.530 + 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530, 3.531 + 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10, 3.532 + 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530, 3.533 + 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10, 3.534 + 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530, 3.535 + 0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 3.536 + 0x0840, 0x0940, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, 3.537 + 0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 3.538 + 0x1840, 0x1940, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, 3.539 + 0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 3.540 + 0x2840, 0x2940, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, 3.541 + 0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 3.542 + 0x3840, 0x3940, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, 3.543 + 0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 3.544 + 0x4840, 0x4940, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, 3.545 + 0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 3.546 + 0x5840, 0x5940, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, 3.547 + 0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 3.548 + 0x6840, 0x6940, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, 3.549 + 0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 3.550 + 0x7840, 0x7940, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, 3.551 + 0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 3.552 + 0x8840, 0x8940, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, 3.553 + 0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740, 3.554 + 0x9840, 0x9940, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.555 + 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 3.556 + 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.557 + 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 3.558 + 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.559 + 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 3.560 + 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.561 + 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 3.562 + 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.563 + 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 3.564 + 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.565 + 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 3.566 + 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.567 + 0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 3.568 + 0xA850, 0xA950, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, 3.569 + 0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 3.570 + 0xB850, 0xB950, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, 3.571 + 0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 3.572 + 0xC850, 0xC950, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, 3.573 + 0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 3.574 + 0xD850, 0xD950, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, 3.575 + 0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 3.576 + 0xE850, 0xE950, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, 3.577 + 0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 3.578 + 0xF850, 0xF950, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, 3.579 + 0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 3.580 + 0x0850, 0x0950, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, 3.581 + 0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 3.582 + 0x1850, 0x1950, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, 3.583 + 0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 3.584 + 0x2850, 0x2950, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, 3.585 + 0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 3.586 + 0x3850, 0x3950, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.587 + 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 3.588 + 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.589 + 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 3.590 + 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.591 + 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 3.592 + 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.593 + 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 3.594 + 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.595 + 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 3.596 + 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.597 + 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 3.598 + 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.599 + 0xFA60, 0xFB60, 0xFC60, 0xFD60, 0xFE60, 0xFF60, 0x00C0, 0x0140, 3.600 + 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940, 3.601 + 0x0A60, 0x0B60, 0x0C60, 0x0D60, 0x0E60, 0x0F60, 0x1040, 0x1140, 3.602 + 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940, 3.603 + 0x1A60, 0x1B60, 0x1C60, 0x1D60, 0x1E60, 0x1F60, 0x2040, 0x2140, 3.604 + 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940, 3.605 + 0x2A60, 0x2B60, 0x2C60, 0x2D60, 0x2E60, 0x2F60, 0x3040, 0x3140, 3.606 + 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940, 3.607 + 0x3A60, 0x3B60, 0x3C60, 0x3D60, 0x3E60, 0x3F60, 0x4040, 0x4140, 3.608 + 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940, 3.609 + 0x4A60, 0x4B60, 0x4C60, 0x4D60, 0x4E60, 0x4F60, 0x5040, 0x5140, 3.610 + 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940, 3.611 + 0x5A60, 0x5B60, 0x5C60, 0x5D60, 0x5E60, 0x5F60, 0x6040, 0x6140, 3.612 + 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940, 3.613 + 0x6A60, 0x6B60, 0x6C60, 0x6D60, 0x6E60, 0x6F60, 0x7040, 0x7140, 3.614 + 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940, 3.615 + 0x7A60, 0x7B60, 0x7C60, 0x7D60, 0x7E60, 0x7F60, 0x8040, 0x8140, 3.616 + 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940, 3.617 + 0x8A60, 0x8B60, 0x8C60, 0x8D60, 0x8E60, 0x8F60, 0x9040, 0x9140, 3.618 + 0x9240, 0x9340, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.619 + 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, 3.620 + 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.621 + 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, 3.622 + 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.623 + 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, 3.624 + 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.625 + 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, 3.626 + 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.627 + 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, 3.628 + 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.629 + 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, 3.630 + 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.631 + 0x9A70, 0x9B70, 0x9C70, 0x9D70, 0x9E70, 0x9F70, 0xA050, 0xA150, 3.632 + 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950, 3.633 + 0xAA70, 0xAB70, 0xAC70, 0xAD70, 0xAE70, 0xAF70, 0xB050, 0xB150, 3.634 + 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950, 3.635 + 0xBA70, 0xBB70, 0xBC70, 0xBD70, 0xBE70, 0xBF70, 0xC050, 0xC150, 3.636 + 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950, 3.637 + 0xCA70, 0xCB70, 0xCC70, 0xCD70, 0xCE70, 0xCF70, 0xD050, 0xD150, 3.638 + 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950, 3.639 + 0xDA70, 0xDB70, 0xDC70, 0xDD70, 0xDE70, 0xDF70, 0xE050, 0xE150, 3.640 + 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950, 3.641 + 0xEA70, 0xEB70, 0xEC70, 0xED70, 0xEE70, 0xEF70, 0xF050, 0xF150, 3.642 + 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950, 3.643 + 0xFA70, 0xFB70, 0xFC70, 0xFD70, 0xFE70, 0xFF70, 0x00D0, 0x0150, 3.644 + 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950, 3.645 + 0x0A70, 0x0B70, 0x0C70, 0x0D70, 0x0E70, 0x0F70, 0x1050, 0x1150, 3.646 + 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950, 3.647 + 0x1A70, 0x1B70, 0x1C70, 0x1D70, 0x1E70, 0x1F70, 0x2050, 0x2150, 3.648 + 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950, 3.649 + 0x2A70, 0x2B70, 0x2C70, 0x2D70, 0x2E70, 0x2F70, 0x3050, 0x3150, 3.650 + 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950, 3.651 + 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150, 3.652 + 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950, 3.653 + 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150, 3.654 + 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950, 3.655 + 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150, 3.656 + 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950, 3.657 + 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150, 3.658 + 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950, 3.659 + 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150, 3.660 + 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950, 3.661 + 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150, 3.662 + 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950, 3.663 + }; 3.664 3.665 u8 ZeroTable[] = 3.666 -{ 3.667 - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.668 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.669 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.670 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.671 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.672 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.673 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.674 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.675 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.676 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.677 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.678 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.679 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.680 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.681 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.682 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 3.683 -}; 3.684 + { 3.685 + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.686 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.687 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.688 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.689 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.690 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.691 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.692 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.693 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.694 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.695 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.696 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.697 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.698 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.699 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.700 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 3.701 + }; 3.702 3.703 #define GBSAVE_GAME_VERSION_1 1 3.704 #define GBSAVE_GAME_VERSION_2 2 3.705 @@ -536,81 +536,81 @@ 3.706 3.707 int inline gbGetValue(int min, int max, int v) 3.708 { 3.709 - return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0))); 3.710 + return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0))); 3.711 } 3.712 3.713 void gbGenFilter() 3.714 { 3.715 - for (int r = 0; r < 32; r++) 3.716 + for (int r = 0; r < 32; r++) 3.717 + { 3.718 + for (int g = 0; g < 32; g++) 3.719 { 3.720 - for (int g = 0; g < 32; g++) 3.721 - { 3.722 - for (int b = 0; b < 32; b++) 3.723 - { 3.724 - int nr = gbGetValue(gbGetValue(4, 14, g), 3.725 - gbGetValue(24, 29, g), r) - 4; 3.726 - int ng = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), 3.727 - 14 + gbGetValue(0, 3, r), b), 3.728 - gbGetValue(24 + gbGetValue(0, 3, r), 3.729 - 29 + gbGetValue(0, 1, r), b), g) - 4; 3.730 - int nb = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), 3.731 - 14 + gbGetValue(0, 3, r), g), 3.732 - gbGetValue(24 + gbGetValue(0, 3, r), 3.733 - 29 + gbGetValue(0, 1, r), g), b) - 4; 3.734 - gbColorFilter[(b << 10) | (g << 5) | r] = (nb << 10) | (ng << 5) | nr; 3.735 - } 3.736 - } 3.737 + for (int b = 0; b < 32; b++) 3.738 + { 3.739 + int nr = gbGetValue(gbGetValue(4, 14, g), 3.740 + gbGetValue(24, 29, g), r) - 4; 3.741 + int ng = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), 3.742 + 14 + gbGetValue(0, 3, r), b), 3.743 + gbGetValue(24 + gbGetValue(0, 3, r), 3.744 + 29 + gbGetValue(0, 1, r), b), g) - 4; 3.745 + int nb = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r), 3.746 + 14 + gbGetValue(0, 3, r), g), 3.747 + gbGetValue(24 + gbGetValue(0, 3, r), 3.748 + 29 + gbGetValue(0, 1, r), g), b) - 4; 3.749 + gbColorFilter[(b << 10) | (g << 5) | r] = (nb << 10) | (ng << 5) | nr; 3.750 + } 3.751 } 3.752 + } 3.753 } 3.754 3.755 void gbCopyMemory(u16 d, u16 s, int count) 3.756 { 3.757 - while (count) 3.758 - { 3.759 - gbWriteMemoryQuick(d, gbReadMemoryQuick(s)); 3.760 - s++; 3.761 - d++; 3.762 - count--; 3.763 - } 3.764 + while (count) 3.765 + { 3.766 + gbWriteMemoryQuick(d, gbReadMemoryQuick(s)); 3.767 + s++; 3.768 + d++; 3.769 + count--; 3.770 + } 3.771 } 3.772 3.773 void gbDoHdma() 3.774 { 3.775 - gbCopyMemory(gbHdmaDestination, gbHdmaSource, 0x10); 3.776 - 3.777 - gbHdmaDestination += 0x10; 3.778 - gbHdmaSource += 0x10; 3.779 - 3.780 - register_HDMA2 = (register_HDMA2 + 0x10) & 0xFF; 3.781 - if (register_HDMA2 == 0x00) 3.782 - register_HDMA1++; 3.783 - 3.784 - register_HDMA4 = (register_HDMA4 + 0x10) & 0xFF; 3.785 - if (register_HDMA4 == 0x00) 3.786 - register_HDMA3++; 3.787 - 3.788 - if (gbHdmaDestination == 0x96b0) 3.789 - gbHdmaBytes = gbHdmaBytes; 3.790 - gbHdmaBytes -= 0x10; 3.791 - register_HDMA5--; 3.792 - if (register_HDMA5 == 0xff) 3.793 - gbHdmaOn = 0; 3.794 + gbCopyMemory(gbHdmaDestination, gbHdmaSource, 0x10); 3.795 + 3.796 + gbHdmaDestination += 0x10; 3.797 + gbHdmaSource += 0x10; 3.798 + 3.799 + register_HDMA2 = (register_HDMA2 + 0x10) & 0xFF; 3.800 + if (register_HDMA2 == 0x00) 3.801 + register_HDMA1++; 3.802 + 3.803 + register_HDMA4 = (register_HDMA4 + 0x10) & 0xFF; 3.804 + if (register_HDMA4 == 0x00) 3.805 + register_HDMA3++; 3.806 + 3.807 + if (gbHdmaDestination == 0x96b0) 3.808 + gbHdmaBytes = gbHdmaBytes; 3.809 + gbHdmaBytes -= 0x10; 3.810 + register_HDMA5--; 3.811 + if (register_HDMA5 == 0xff) 3.812 + gbHdmaOn = 0; 3.813 } 3.814 3.815 // fix for Harley and Lego Racers 3.816 void gbCompareLYToLYC() 3.817 { 3.818 - if (register_LY == register_LYC) 3.819 - { 3.820 - // mark that we have a match 3.821 - register_STAT |= 4; 3.822 - 3.823 - // check if we need an interrupt 3.824 - if ((register_STAT & 0x40) && (register_IE & 2)) 3.825 - gbInterrupt |= 2; 3.826 - } 3.827 - else // no match 3.828 - register_STAT &= 0xfb; 3.829 + if (register_LY == register_LYC) 3.830 + { 3.831 + // mark that we have a match 3.832 + register_STAT |= 4; 3.833 + 3.834 + // check if we need an interrupt 3.835 + if ((register_STAT & 0x40) && (register_IE & 2)) 3.836 + gbInterrupt |= 2; 3.837 + } 3.838 + else // no match 3.839 + register_STAT &= 0xfb; 3.840 } 3.841 3.842 // FIXME: horrible kludge to workaround the frame timing bug 3.843 @@ -618,1971 +618,1971 @@ 3.844 3.845 void gbWriteMemoryWrapped(register u16 address, register u8 value) 3.846 { 3.847 - if (address < 0x8000) 3.848 + if (address < 0x8000) 3.849 + { 3.850 +#ifndef FINAL_VERSION 3.851 + if (memorydebug && (address > 0x3fff || address < 0x2000)) 3.852 { 3.853 + log("Memory register write %04x=%02x PC=%04x\n", 3.854 + address, 3.855 + value, 3.856 + PC.W); 3.857 + } 3.858 +#endif 3.859 + if (mapper) 3.860 + (*mapper)(address, value); 3.861 + return; 3.862 + } 3.863 + 3.864 + if (address < 0xa000) 3.865 + { 3.866 + gbWriteMemoryQuick(address, value); 3.867 + return; 3.868 + } 3.869 + 3.870 + if (address < 0xc000) 3.871 + { 3.872 #ifndef FINAL_VERSION 3.873 - if (memorydebug && (address > 0x3fff || address < 0x2000)) 3.874 - { 3.875 - log("Memory register write %04x=%02x PC=%04x\n", 3.876 - address, 3.877 - value, 3.878 - PC.W); 3.879 - } 3.880 + if (memorydebug) 3.881 + { 3.882 + log("Memory register write %04x=%02x PC=%04x\n", 3.883 + address, 3.884 + value, 3.885 + PC.W); 3.886 + } 3.887 #endif 3.888 - if (mapper) 3.889 - (*mapper)(address, value); 3.890 - return; 3.891 + 3.892 + if (mapper) 3.893 + (*mapperRAM)(address, value); 3.894 + return; 3.895 + } 3.896 + 3.897 + if (address < 0xfe00) 3.898 + { 3.899 + gbWriteMemoryQuick(address, value); 3.900 + return; 3.901 + } 3.902 + 3.903 + if (address < 0xff00) 3.904 + { 3.905 + gbMemory[address] = value; 3.906 + return; 3.907 + } 3.908 + 3.909 + switch (address & 0x00ff) 3.910 + { 3.911 + case 0x00: 3.912 + { 3.913 + gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | 3.914 + (value & 0x30)); 3.915 + if (gbSgbMode) 3.916 + { 3.917 + gbSgbDoBitTransfer(value); 3.918 + } 3.919 + 3.920 + return; 3.921 + } 3.922 + 3.923 + case 0x01: 3.924 + { 3.925 + gbMemory[0xff01] = value; 3.926 + return; 3.927 + } 3.928 + 3.929 + // serial control 3.930 + case 0x02: 3.931 + { 3.932 + gbSerialOn = (value & 0x80); 3.933 + gbMemory[0xff02] = value; 3.934 + if (gbSerialOn) 3.935 + { 3.936 + gbSerialTicks = GBSERIAL_CLOCK_TICKS; 3.937 +#ifdef LINK_EMULATION 3.938 + if (linkConnected) 3.939 + { 3.940 + if (value & 1) 3.941 + { 3.942 + linkSendByte(0x100 | gbMemory[0xFF01]); 3.943 + Sleep(5); 3.944 + } 3.945 + } 3.946 +#endif 3.947 + } 3.948 + 3.949 + gbSerialBits = 0; 3.950 + return; 3.951 + } 3.952 + 3.953 + // DIV register resets on any write 3.954 + case 0x04: 3.955 + { 3.956 + register_DIV = 0; 3.957 + return; 3.958 + } 3.959 + case 0x05: 3.960 + register_TIMA = value; 3.961 + return; 3.962 + 3.963 + case 0x06: 3.964 + register_TMA = value; 3.965 + return; 3.966 + 3.967 + // TIMER control 3.968 + case 0x07: 3.969 + { 3.970 + register_TAC = value; 3.971 + 3.972 + gbTimerOn = (value & 4); 3.973 + gbTimerMode = value & 3; 3.974 + // register_TIMA = register_TMA; 3.975 + switch (gbTimerMode) 3.976 + { 3.977 + case 0: 3.978 + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; 3.979 + break; 3.980 + case 1: 3.981 + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS; 3.982 + break; 3.983 + case 2: 3.984 + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS; 3.985 + break; 3.986 + case 3: 3.987 + gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS; 3.988 + break; 3.989 + } 3.990 + return; 3.991 + } 3.992 + 3.993 + case 0x0f: 3.994 + { 3.995 + register_IF = value; 3.996 + gbInterrupt = value; 3.997 + return; 3.998 + } 3.999 + 3.1000 + case 0x10: 3.1001 + case 0x11: 3.1002 + case 0x12: 3.1003 + case 0x13: 3.1004 + case 0x14: 3.1005 + case 0x15: 3.1006 + case 0x16: 3.1007 + case 0x17: 3.1008 + case 0x18: 3.1009 + case 0x19: 3.1010 + case 0x1a: 3.1011 + case 0x1b: 3.1012 + case 0x1c: 3.1013 + case 0x1d: 3.1014 + case 0x1e: 3.1015 + case 0x1f: 3.1016 + case 0x20: 3.1017 + case 0x21: 3.1018 + case 0x22: 3.1019 + case 0x23: 3.1020 + case 0x24: 3.1021 + case 0x25: 3.1022 + case 0x26: 3.1023 + { 3.1024 + SOUND_EVENT(address, value); 3.1025 + return; 3.1026 + } 3.1027 + case 0x40: 3.1028 + { 3.1029 + int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); 3.1030 + 3.1031 + if (lcdChange) 3.1032 + { 3.1033 + if (value & 0x80) 3.1034 + { 3.1035 + gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS; 3.1036 + gbLcdMode = 0; 3.1037 + register_STAT &= 0xfc; 3.1038 + register_LY = 0x00; 3.1039 + // FIXME: horrible workaround 3.1040 + if (gbNullInputHackTempEnabled && !useOldFrameTiming) 3.1041 + memcpy(gbJoymask, s_gbJoymask, sizeof(gbJoymask)); 3.1042 + } 3.1043 + else 3.1044 + { 3.1045 + gbLcdTicks = 0; 3.1046 + gbLcdMode = 0; 3.1047 + register_STAT &= 0xfc; 3.1048 + register_LY = 0x00; 3.1049 + // FIXME: horrible workaround 3.1050 + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); 3.1051 + if (gbNullInputHackTempEnabled && !useOldFrameTiming) 3.1052 + memset(gbJoymask, 0, sizeof(gbJoymask)); 3.1053 + } 3.1054 + // compareLYToLYC(); 3.1055 + } 3.1056 + // don't draw the window if it was not enabled and not being drawn before 3.1057 + if (!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 && 3.1058 + register_LY > register_WY) 3.1059 + gbWindowLine = 144; 3.1060 + 3.1061 + register_LCDC = value; 3.1062 + 3.1063 + return; 3.1064 + } 3.1065 + 3.1066 + // STAT 3.1067 + case 0x41: 3.1068 + { 3.1069 + //register_STAT = (register_STAT & 0x87) | 3.1070 + // (value & 0x7c); 3.1071 + register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? 3.1072 + // GB bug from Devrs FAQ 3.1073 + if (!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2) 3.1074 + gbInterrupt |= 2; 3.1075 + return; 3.1076 + } 3.1077 + 3.1078 + // SCY 3.1079 + case 0x42: 3.1080 + { 3.1081 + register_SCY = value; 3.1082 + return; 3.1083 + } 3.1084 + 3.1085 + // SCX 3.1086 + case 0x43: 3.1087 + { 3.1088 + register_SCX = value; 3.1089 + return; 3.1090 + } 3.1091 + 3.1092 + // LY 3.1093 + case 0x44: 3.1094 + { 3.1095 + // read only 3.1096 + return; 3.1097 + } 3.1098 + 3.1099 + // LYC 3.1100 + case 0x45: 3.1101 + { 3.1102 + register_LYC = value; 3.1103 + if ((register_LCDC & 0x80)) 3.1104 + { 3.1105 + gbCompareLYToLYC(); 3.1106 + } 3.1107 + return; 3.1108 + } 3.1109 + 3.1110 + // DMA! 3.1111 + case 0x46: 3.1112 + { 3.1113 + int source = value * 0x0100; 3.1114 + 3.1115 + gbCopyMemory(0xfe00, 3.1116 + source, 3.1117 + 0xa0); 3.1118 + register_DMA = value; 3.1119 + return; 3.1120 + } 3.1121 + 3.1122 + // BGP 3.1123 + case 0x47: 3.1124 + { 3.1125 + gbBgp[0] = value & 0x03; 3.1126 + gbBgp[1] = (value & 0x0c) >> 2; 3.1127 + gbBgp[2] = (value & 0x30) >> 4; 3.1128 + gbBgp[3] = (value & 0xc0) >> 6; 3.1129 + break; 3.1130 + } 3.1131 + 3.1132 + // OBP0 3.1133 + case 0x48: 3.1134 + { 3.1135 + gbObp0[0] = value & 0x03; 3.1136 + gbObp0[1] = (value & 0x0c) >> 2; 3.1137 + gbObp0[2] = (value & 0x30) >> 4; 3.1138 + gbObp0[3] = (value & 0xc0) >> 6; 3.1139 + break; 3.1140 + } 3.1141 + 3.1142 + // OBP1 3.1143 + case 0x49: 3.1144 + { 3.1145 + gbObp1[0] = value & 0x03; 3.1146 + gbObp1[1] = (value & 0x0c) >> 2; 3.1147 + gbObp1[2] = (value & 0x30) >> 4; 3.1148 + gbObp1[3] = (value & 0xc0) >> 6; 3.1149 + break; 3.1150 + } 3.1151 + 3.1152 + case 0x4a: 3.1153 + register_WY = value; 3.1154 + return; 3.1155 + 3.1156 + case 0x4b: 3.1157 + register_WX = value; 3.1158 + return; 3.1159 + 3.1160 + // KEY1 3.1161 + case 0x4d: 3.1162 + { 3.1163 + if (gbCgbMode) 3.1164 + { 3.1165 + gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1); 3.1166 + return; 3.1167 + } 3.1168 + break; 3.1169 + } 3.1170 + 3.1171 + // VBK 3.1172 + case 0x4f: 3.1173 + { 3.1174 + if (gbCgbMode) 3.1175 + { 3.1176 + value = value & 1; 3.1177 + if (value == gbVramBank) 3.1178 + return; 3.1179 + 3.1180 + int vramAddress = value * 0x2000; 3.1181 + gbMemoryMap[0x08] = &gbVram[vramAddress]; 3.1182 + gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; 3.1183 + 3.1184 + gbVramBank = value; 3.1185 + register_VBK = value; 3.1186 + } 3.1187 + return; 3.1188 + break; 3.1189 + } 3.1190 + 3.1191 + // HDMA1 3.1192 + case 0x51: 3.1193 + { 3.1194 + if (gbCgbMode) 3.1195 + { 3.1196 + if (value > 0x7f && value < 0xa0) 3.1197 + value = 0; 3.1198 + 3.1199 + gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0); 3.1200 + 3.1201 + register_HDMA1 = value; 3.1202 + return; 3.1203 + } 3.1204 + break; 3.1205 + } 3.1206 + 3.1207 + // HDMA2 3.1208 + case 0x52: 3.1209 + { 3.1210 + if (gbCgbMode) 3.1211 + { 3.1212 + value = value & 0xf0; 3.1213 + 3.1214 + gbHdmaSource = (register_HDMA1 << 8) | (value); 3.1215 + 3.1216 + register_HDMA2 = value; 3.1217 + return; 3.1218 + } 3.1219 + break; 3.1220 + } 3.1221 + 3.1222 + // HDMA3 3.1223 + case 0x53: 3.1224 + { 3.1225 + if (gbCgbMode) 3.1226 + { 3.1227 + value = value & 0x1f; 3.1228 + gbHdmaDestination = (value << 8) | (register_HDMA4 & 0xf0); 3.1229 + gbHdmaDestination += 0x8000; 3.1230 + register_HDMA3 = value; 3.1231 + return; 3.1232 + } 3.1233 + break; 3.1234 + } 3.1235 + 3.1236 + // HDMA4 3.1237 + case 0x54: 3.1238 + { 3.1239 + if (gbCgbMode) 3.1240 + { 3.1241 + value = value & 0xf0; 3.1242 + gbHdmaDestination = ((register_HDMA3 & 0x1f) << 8) | value; 3.1243 + gbHdmaDestination += 0x8000; 3.1244 + register_HDMA4 = value; 3.1245 + return; 3.1246 + } 3.1247 + break; 3.1248 + } 3.1249 + 3.1250 + // HDMA5 3.1251 + case 0x55: 3.1252 + { 3.1253 + if (gbCgbMode) 3.1254 + { 3.1255 + gbHdmaBytes = 16 + (value & 0x7f) * 16; 3.1256 + if (gbHdmaOn) 3.1257 + { 3.1258 + if (value & 0x80) 3.1259 + { 3.1260 + register_HDMA5 = (value & 0x7f); 3.1261 + } 3.1262 + else 3.1263 + { 3.1264 + register_HDMA5 = 0xff; 3.1265 + gbHdmaOn = 0; 3.1266 + } 3.1267 + } 3.1268 + else 3.1269 + { 3.1270 + if (value & 0x80) 3.1271 + { 3.1272 + gbHdmaOn = 1; 3.1273 + register_HDMA5 = value & 0x7f; 3.1274 + if (gbLcdMode == 0) 3.1275 + gbDoHdma(); 3.1276 + } 3.1277 + else 3.1278 + { 3.1279 + // we need to take the time it takes to complete the transfer into 3.1280 + // account... according to GB DEV FAQs, the setup time is the same 3.1281 + // for single and double speed, but the actual transfer takes the 3.1282 + // same time // (is that a typo?) 3.1283 + switch (gbDMASpeedVersion) 3.1284 + { 3.1285 + case 1: // I believe this is more correct 3.1286 + // the lower 7 bits of FF55 specify the Transfer Length (divided by 16, minus 1) 3.1287 + // and we make gbDmaTicks twice as many cycles at double speed to make the transfer take the same time 3.1288 + if (gbSpeed) 3.1289 + gbDmaTicks = 16 * ((value & 0x7f) + 1); 3.1290 + else 3.1291 + gbDmaTicks = 8 * ((value & 0x7f) + 1); 3.1292 + break; 3.1293 + case 0: // here for backward compatibility 3.1294 + // I think this was a guess that approximates the above in most but not all games 3.1295 + if (gbSpeed) 3.1296 + gbDmaTicks = 231 + 16 * (value & 0x7f); 3.1297 + else 3.1298 + gbDmaTicks = 231 + 8 * (value & 0x7f); 3.1299 + break; 3.1300 + default: // shouldn't happen 3.1301 + //assert(0); 3.1302 + break; 3.1303 + } 3.1304 + gbCopyMemory(gbHdmaDestination, gbHdmaSource, gbHdmaBytes); 3.1305 + gbHdmaDestination += gbHdmaBytes; 3.1306 + gbHdmaSource += gbHdmaBytes; 3.1307 + 3.1308 + register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; 3.1309 + register_HDMA4 = gbHdmaDestination & 0xf0; 3.1310 + register_HDMA1 = (gbHdmaSource >> 8) & 0xff; 3.1311 + register_HDMA2 = gbHdmaSource & 0xf0; 3.1312 + } 3.1313 + } 3.1314 + return; 3.1315 + } 3.1316 + break; 3.1317 + } 3.1318 + 3.1319 + // BCPS 3.1320 + case 0x68: 3.1321 + { 3.1322 + if (gbCgbMode) 3.1323 + { 3.1324 + int paletteIndex = (value & 0x3f) >> 1; 3.1325 + int paletteHiLo = (value & 0x01); 3.1326 + 3.1327 + gbMemory[0xff68] = value; 3.1328 + gbMemory[0xff69] = (paletteHiLo ? 3.1329 + (gbPalette[paletteIndex] >> 8) : 3.1330 + (gbPalette[paletteIndex] & 0x00ff)); 3.1331 + return; 3.1332 + } 3.1333 + break; 3.1334 + } 3.1335 + 3.1336 + // BCPD 3.1337 + case 0x69: 3.1338 + { 3.1339 + if (gbCgbMode) 3.1340 + { 3.1341 + int v = gbMemory[0xff68]; 3.1342 + int paletteIndex = (v & 0x3f) >> 1; 3.1343 + int paletteHiLo = (v & 0x01); 3.1344 + gbMemory[0xff69] = value; 3.1345 + gbPalette[paletteIndex] = (paletteHiLo ? 3.1346 + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : 3.1347 + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; 3.1348 + 3.1349 + if (gbMemory[0xff68] & 0x80) 3.1350 + { 3.1351 + int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f; 3.1352 + 3.1353 + gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index; 3.1354 + 3.1355 + gbMemory[0xff69] = (index & 1 ? 3.1356 + (gbPalette[index >> 1] >> 8) : 3.1357 + (gbPalette[index >> 1] & 0x00ff)); 3.1358 + } 3.1359 + return; 3.1360 + } 3.1361 + break; 3.1362 + } 3.1363 + 3.1364 + // OCPS 3.1365 + case 0x6a: 3.1366 + { 3.1367 + if (gbCgbMode) 3.1368 + { 3.1369 + int paletteIndex = (value & 0x3f) >> 1; 3.1370 + int paletteHiLo = (value & 0x01); 3.1371 + 3.1372 + paletteIndex += 32; 3.1373 + 3.1374 + gbMemory[0xff6a] = value; 3.1375 + gbMemory[0xff6b] = (paletteHiLo ? 3.1376 + (gbPalette[paletteIndex] >> 8) : 3.1377 + (gbPalette[paletteIndex] & 0x00ff)); 3.1378 + return; 3.1379 + } 3.1380 + break; 3.1381 + } 3.1382 + 3.1383 + // OCPD 3.1384 + case 0x6b: 3.1385 + { 3.1386 + if (gbCgbMode) 3.1387 + { 3.1388 + int v = gbMemory[0xff6a]; 3.1389 + int paletteIndex = (v & 0x3f) >> 1; 3.1390 + int paletteHiLo = (v & 0x01); 3.1391 + 3.1392 + paletteIndex += 32; 3.1393 + 3.1394 + gbMemory[0xff6b] = value; 3.1395 + gbPalette[paletteIndex] = (paletteHiLo ? 3.1396 + ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : 3.1397 + ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; 3.1398 + if (gbMemory[0xff6a] & 0x80) 3.1399 + { 3.1400 + int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f; 3.1401 + 3.1402 + gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index; 3.1403 + 3.1404 + gbMemory[0xff6b] = (index & 1 ? 3.1405 + (gbPalette[(index >> 1) + 32] >> 8) : 3.1406 + (gbPalette[(index >> 1) + 32] & 0x00ff)); 3.1407 + } 3.1408 + return; 3.1409 + } 3.1410 + break; 3.1411 + } 3.1412 + 3.1413 + // SVBK 3.1414 + case 0x70: 3.1415 + { 3.1416 + if (gbCgbMode) 3.1417 + { 3.1418 + value = value & 7; 3.1419 + 3.1420 + int bank = value; 3.1421 + if (value == 0) 3.1422 + bank = 1; 3.1423 + 3.1424 + if (bank == gbWramBank) 3.1425 + return; 3.1426 + 3.1427 + int wramAddress = bank * 0x1000; 3.1428 + gbMemoryMap[0x0d] = &gbWram[wramAddress]; 3.1429 + 3.1430 + gbWramBank = bank; 3.1431 + register_SVBK = value; 3.1432 + return; 3.1433 + } 3.1434 + break; 3.1435 + } 3.1436 + 3.1437 + case 0xff: 3.1438 + { 3.1439 + register_IE = value; 3.1440 + register_IF &= value; 3.1441 + return; 3.1442 + } 3.1443 + } 3.1444 + 3.1445 + gbWriteMemoryQuick(address, value); 3.1446 +} 3.1447 + 3.1448 +u8 gbReadOpcode(register u16 address) 3.1449 +{ 3.1450 + if (gbCheatMap[address]) 3.1451 + return gbCheatRead(address); 3.1452 + 3.1453 + // the following fix does more than Echo RAM fix, anyway... 3.1454 + switch (gbEchoRAMFixOn ? (address >> 12) & 0x000f : address & 0xf000) 3.1455 + { 3.1456 + case 0x0a: 3.1457 + case 0x0b: 3.1458 + if (mapperReadRAM) 3.1459 + return mapperReadRAM(address); 3.1460 + break; 3.1461 + case 0x0f: 3.1462 + if (address > 0xff00) 3.1463 + { 3.1464 + switch (address & 0x00ff) 3.1465 + { 3.1466 + case 0x04: 3.1467 + return register_DIV; 3.1468 + case 0x05: 3.1469 + return register_TIMA; 3.1470 + case 0x06: 3.1471 + return register_TMA; 3.1472 + case 0x07: 3.1473 + return (0xf8 | register_TAC); 3.1474 + case 0x0f: 3.1475 + return (0xe0 | register_IF); 3.1476 + case 0x40: 3.1477 + return register_LCDC; 3.1478 + case 0x41: 3.1479 + return (0x80 | register_STAT); 3.1480 + case 0x42: 3.1481 + return register_SCY; 3.1482 + case 0x43: 3.1483 + return register_SCX; 3.1484 + case 0x44: 3.1485 + return register_LY; 3.1486 + case 0x45: 3.1487 + return register_LYC; 3.1488 + case 0x46: 3.1489 + return register_DMA; 3.1490 + case 0x4a: 3.1491 + return register_WY; 3.1492 + case 0x4b: 3.1493 + return register_WX; 3.1494 + case 0x4f: 3.1495 + return (0xfe | register_VBK); 3.1496 + case 0x51: 3.1497 + return register_HDMA1; 3.1498 + case 0x52: 3.1499 + return register_HDMA2; 3.1500 + case 0x53: 3.1501 + return register_HDMA3; 3.1502 + case 0x54: 3.1503 + return register_HDMA4; 3.1504 + case 0x55: 3.1505 + return register_HDMA5; 3.1506 + case 0x70: 3.1507 + return (0xf8 | register_SVBK); 3.1508 + case 0xff: 3.1509 + return register_IE; 3.1510 + } 3.1511 } 3.1512 - 3.1513 - if (address < 0xa000) 3.1514 + break; 3.1515 + } 3.1516 + return gbReadMemoryQuick(address); 3.1517 +} 3.1518 + 3.1519 +void gbWriteMemory(register u16 address, register u8 value) 3.1520 +{ 3.1521 + gbWriteMemoryWrapped(address, value); 3.1522 + CallRegisteredLuaMemHook(address, 1, value, LUAMEMHOOK_WRITE); 3.1523 +} 3.1524 + 3.1525 +u8 gbReadMemory(register u16 address) 3.1526 +{ 3.1527 + if (gbCheatMap[address]) 3.1528 + return gbCheatRead(address); 3.1529 + 3.1530 + if (address < 0xa000) 3.1531 + return gbReadMemoryQuick(address); 3.1532 + 3.1533 + if (address < 0xc000) 3.1534 + { 3.1535 +#ifndef FINAL_VERSION 3.1536 + if (memorydebug) 3.1537 { 3.1538 - gbWriteMemoryQuick(address, value); 3.1539 - return; 3.1540 + log("Memory register read %04x PC=%04x\n", 3.1541 + address, 3.1542 + PC.W); 3.1543 } 3.1544 - 3.1545 - if (address < 0xc000) 3.1546 - { 3.1547 -#ifndef FINAL_VERSION 3.1548 - if (memorydebug) 3.1549 - { 3.1550 - log("Memory register write %04x=%02x PC=%04x\n", 3.1551 - address, 3.1552 - value, 3.1553 - PC.W); 3.1554 - } 3.1555 #endif 3.1556 3.1557 - if (mapper) 3.1558 - (*mapperRAM)(address, value); 3.1559 - return; 3.1560 - } 3.1561 - 3.1562 - if (address < 0xfe00) 3.1563 - { 3.1564 - gbWriteMemoryQuick(address, value); 3.1565 - return; 3.1566 - } 3.1567 - 3.1568 - if (address < 0xff00) 3.1569 - { 3.1570 - gbMemory[address] = value; 3.1571 - return; 3.1572 - } 3.1573 - 3.1574 - switch (address & 0x00ff) 3.1575 + if (mapperReadRAM) 3.1576 + return mapperReadRAM(address); 3.1577 + return gbReadMemoryQuick(address); 3.1578 + } 3.1579 + 3.1580 + if (address >= 0xff00) 3.1581 + { 3.1582 + switch (address & 0x00ff) 3.1583 { 3.1584 case 0x00: 3.1585 - { 3.1586 - gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) | 3.1587 - (value & 0x30)); 3.1588 - if (gbSgbMode) 3.1589 - { 3.1590 - gbSgbDoBitTransfer(value); 3.1591 - } 3.1592 - 3.1593 - return; 3.1594 + { 3.1595 + if (gbSgbMode) 3.1596 + { 3.1597 + gbSgbReadingController |= 4; 3.1598 + gbSgbResetPacketState(); 3.1599 + } 3.1600 + 3.1601 + int b = gbMemory[0xff00]; 3.1602 + 3.1603 + if ((b & 0x30) == 0x20) 3.1604 + { 3.1605 + b &= 0xf0; 3.1606 + 3.1607 + int joy = 0; 3.1608 + if (gbSgbMode && gbSgbMultiplayer) 3.1609 + { 3.1610 + switch (gbSgbNextController) 3.1611 + { 3.1612 + case 0x0f: 3.1613 + joy = 0; 3.1614 + break; 3.1615 + case 0x0e: 3.1616 + joy = 1; 3.1617 + break; 3.1618 + case 0x0d: 3.1619 + joy = 2; 3.1620 + break; 3.1621 + case 0x0c: 3.1622 + joy = 3; 3.1623 + break; 3.1624 + default: 3.1625 + joy = 0; 3.1626 + } 3.1627 + } 3.1628 + int joystate = gbJoymask[joy]; 3.1629 + if (!(joystate & 128)) 3.1630 + b |= 0x08; 3.1631 + if (!(joystate & 64)) 3.1632 + b |= 0x04; 3.1633 + if (!(joystate & 32)) 3.1634 + b |= 0x02; 3.1635 + if (!(joystate & 16)) 3.1636 + b |= 0x01; 3.1637 + 3.1638 + gbMemory[0xff00] = b; 3.1639 + } 3.1640 + else if ((b & 0x30) == 0x10) 3.1641 + { 3.1642 + b &= 0xf0; 3.1643 + 3.1644 + int joy = 0; 3.1645 + if (gbSgbMode && gbSgbMultiplayer) 3.1646 + { 3.1647 + switch (gbSgbNextController) 3.1648 + { 3.1649 + case 0x0f: 3.1650 + joy = 0; 3.1651 + break; 3.1652 + case 0x0e: 3.1653 + joy = 1; 3.1654 + break; 3.1655 + case 0x0d: 3.1656 + joy = 2; 3.1657 + break; 3.1658 + case 0x0c: 3.1659 + joy = 3; 3.1660 + break; 3.1661 + default: 3.1662 + joy = 0; 3.1663 + } 3.1664 + } 3.1665 + int joystate = gbJoymask[joy]; 3.1666 + if (!(joystate & 8)) 3.1667 + b |= 0x08; 3.1668 + if (!(joystate & 4)) 3.1669 + b |= 0x04; 3.1670 + if (!(joystate & 2)) 3.1671 + b |= 0x02; 3.1672 + if (!(joystate & 1)) 3.1673 + b |= 0x01; 3.1674 + 3.1675 + gbMemory[0xff00] = b; 3.1676 + } 3.1677 + else 3.1678 + { 3.1679 + if (gbSgbMode && gbSgbMultiplayer) 3.1680 + { 3.1681 + gbMemory[0xff00] = 0xf0 | gbSgbNextController; 3.1682 + } 3.1683 + else 3.1684 + { 3.1685 + gbMemory[0xff00] = 0xff; 3.1686 + } 3.1687 + } 3.1688 + } 3.1689 + GBSystemCounters.lagged = false; 3.1690 + return gbMemory[0xff00]; 3.1691 + break; 3.1692 + case 0x01: 3.1693 + return gbMemory[0xff01]; 3.1694 + case 0x04: 3.1695 + return register_DIV; 3.1696 + case 0x05: 3.1697 + return register_TIMA; 3.1698 + case 0x06: 3.1699 + return register_TMA; 3.1700 + case 0x07: 3.1701 + return (0xf8 | register_TAC); 3.1702 + case 0x0f: 3.1703 + return (0xe0 | register_IF); 3.1704 + case 0x40: 3.1705 + return register_LCDC; 3.1706 + case 0x41: 3.1707 + return (0x80 | register_STAT); 3.1708 + case 0x42: 3.1709 + return register_SCY; 3.1710 + case 0x43: 3.1711 + return register_SCX; 3.1712 + case 0x44: 3.1713 + return register_LY; 3.1714 + case 0x45: 3.1715 + return register_LYC; 3.1716 + case 0x46: 3.1717 + return register_DMA; 3.1718 + case 0x4a: 3.1719 + return register_WY; 3.1720 + case 0x4b: 3.1721 + return register_WX; 3.1722 + case 0x4f: 3.1723 + return (0xfe | register_VBK); 3.1724 + case 0x51: 3.1725 + return register_HDMA1; 3.1726 + case 0x52: 3.1727 + return register_HDMA2; 3.1728 + case 0x53: 3.1729 + return register_HDMA3; 3.1730 + case 0x54: 3.1731 + return register_HDMA4; 3.1732 + case 0x55: 3.1733 + return register_HDMA5; 3.1734 + case 0x70: 3.1735 + return (0xf8 | register_SVBK); 3.1736 + case 0xff: 3.1737 + return register_IE; 3.1738 } 3.1739 - 3.1740 - case 0x01: 3.1741 - { 3.1742 - gbMemory[0xff01] = value; 3.1743 - return; 3.1744 - } 3.1745 - 3.1746 - // serial control 3.1747 - case 0x02: 3.1748 - { 3.1749 - gbSerialOn = (value & 0x80); 3.1750 - gbMemory[0xff02] = value; 3.1751 - if (gbSerialOn) 3.1752 - { 3.1753 - gbSerialTicks = GBSERIAL_CLOCK_TICKS; 3.1754 -#ifdef LINK_EMULATION 3.1755 - if (linkConnected) 3.1756 - { 3.1757 - if (value & 1) 3.1758 - { 3.1759 - linkSendByte(0x100 | gbMemory[0xFF01]); 3.1760 - Sleep(5); 3.1761 - } 3.1762 - } 3.1763 -#endif 3.1764 - } 3.1765 - 3.1766 - gbSerialBits = 0; 3.1767 - return; 3.1768 - } 3.1769 - 3.1770 - // DIV register resets on any write 3.1771 - case 0x04: 3.1772 - { 3.1773 - register_DIV = 0; 3.1774 - return; 3.1775 - } 3.1776 - case 0x05: 3.1777 - register_TIMA = value; 3.1778 - return; 3.1779 - 3.1780 - case 0x06: 3.1781 - register_TMA = value; 3.1782 - return; 3.1783 - 3.1784 - // TIMER control 3.1785 - case 0x07: 3.1786 - { 3.1787 - register_TAC = value; 3.1788 - 3.1789 - gbTimerOn = (value & 4); 3.1790 - gbTimerMode = value & 3; 3.1791 - // register_TIMA = register_TMA; 3.1792 - switch (gbTimerMode) 3.1793 - { 3.1794 - case 0: 3.1795 - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS; 3.1796 - break; 3.1797 - case 1: 3.1798 - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS; 3.1799 - break; 3.1800 - case 2: 3.1801 - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS; 3.1802 - break; 3.1803 - case 3: 3.1804 - gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS; 3.1805 - break; 3.1806 - } 3.1807 - return; 3.1808 - } 3.1809 - 3.1810 - case 0x0f: 3.1811 - { 3.1812 - register_IF = value; 3.1813 - gbInterrupt = value; 3.1814 - return; 3.1815 - } 3.1816 - 3.1817 - case 0x10: 3.1818 - case 0x11: 3.1819 - case 0x12: 3.1820 - case 0x13: 3.1821 - case 0x14: 3.1822 - case 0x15: 3.1823 - case 0x16: 3.1824 - case 0x17: 3.1825 - case 0x18: 3.1826 - case 0x19: 3.1827 - case 0x1a: 3.1828 - case 0x1b: 3.1829 - case 0x1c: 3.1830 - case 0x1d: 3.1831 - case 0x1e: 3.1832 - case 0x1f: 3.1833 - case 0x20: 3.1834 - case 0x21: 3.1835 - case 0x22: 3.1836 - case 0x23: 3.1837 - case 0x24: 3.1838 - case 0x25: 3.1839 - case 0x26: 3.1840 - { 3.1841 - SOUND_EVENT(address, value); 3.1842 - return; 3.1843 - } 3.1844 - case 0x40: 3.1845 - { 3.1846 - int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80); 3.1847 - 3.1848 - if (lcdChange) 3.1849 - { 3.1850 - if (value & 0x80) 3.1851 - { 3.1852 - gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS; 3.1853 - gbLcdMode = 0; 3.1854 - register_STAT &= 0xfc; 3.1855 - register_LY = 0x00; 3.1856 - // FIXME: horrible workaround 3.1857 - if (gbNullInputHackTempEnabled && !useOldFrameTiming) 3.1858 - memcpy(gbJoymask, s_gbJoymask, sizeof(gbJoymask)); 3.1859 - } 3.1860 - else 3.1861 - { 3.1862 - gbLcdTicks = 0; 3.1863 - gbLcdMode = 0; 3.1864 - register_STAT &= 0xfc; 3.1865 - register_LY = 0x00; 3.1866 - // FIXME: horrible workaround 3.1867 - memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); 3.1868 - if (gbNullInputHackTempEnabled && !useOldFrameTiming) 3.1869 - memset(gbJoymask, 0, sizeof(gbJoymask)); 3.1870 - } 3.1871 - // compareLYToLYC(); 3.1872 - } 3.1873 - // don't draw the window if it was not enabled and not being drawn before 3.1874 - if (!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 && 3.1875 - register_LY > register_WY) 3.1876 - gbWindowLine = 144; 3.1877 - 3.1878 - register_LCDC = value; 3.1879 - 3.1880 - return; 3.1881 - } 3.1882 - 3.1883 - // STAT 3.1884 - case 0x41: 3.1885 - { 3.1886 - //register_STAT = (register_STAT & 0x87) | 3.1887 - // (value & 0x7c); 3.1888 - register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ? 3.1889 - // GB bug from Devrs FAQ 3.1890 - if (!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2) 3.1891 - gbInterrupt |= 2; 3.1892 - return; 3.1893 - } 3.1894 - 3.1895 - // SCY 3.1896 - case 0x42: 3.1897 - { 3.1898 - register_SCY = value; 3.1899 - return; 3.1900 - } 3.1901 - 3.1902 - // SCX 3.1903 - case 0x43: 3.1904 - { 3.1905 - register_SCX = value; 3.1906 - return; 3.1907 - } 3.1908 - 3.1909 - // LY 3.1910 - case 0x44: 3.1911 - { 3.1912 - // read only 3.1913 - return; 3.1914 - } 3.1915 - 3.1916 - // LYC 3.1917 - case 0x45: 3.1918 - { 3.1919 - register_LYC = value; 3.1920 - if ((register_LCDC & 0x80)) 3.1921 - { 3.1922 - gbCompareLYToLYC(); 3.1923 - } 3.1924 - return; 3.1925 - } 3.1926 - 3.1927 - // DMA! 3.1928 - case 0x46: 3.1929 - { 3.1930 - int source = value * 0x0100; 3.1931 - 3.1932 - gbCopyMemory(0xfe00, 3.1933 - source, 3.1934 - 0xa0); 3.1935 - register_DMA = value; 3.1936 - return; 3.1937 - } 3.1938 - 3.1939 - // BGP 3.1940 - case 0x47: 3.1941 - { 3.1942 - gbBgp[0] = value & 0x03; 3.1943 - gbBgp[1] = (value & 0x0c) >> 2; 3.1944 - gbBgp[2] = (value & 0x30) >> 4; 3.1945 - gbBgp[3] = (value & 0xc0) >> 6; 3.1946 - break; 3.1947 - } 3.1948 - 3.1949 - // OBP0 3.1950 - case 0x48: 3.1951 - { 3.1952 - gbObp0[0] = value & 0x03; 3.1953 - gbObp0[1] = (value & 0x0c) >> 2; 3.1954 - gbObp0[2] = (value & 0x30) >> 4; 3.1955 - gbObp0[3] = (value & 0xc0) >> 6; 3.1956 - break; 3.1957 - } 3.1958 - 3.1959 - // OBP1 3.1960 - case 0x49: 3.1961 - { 3.1962 - gbObp1[0] = value & 0x03; 3.1963 - gbObp1[1] = (value & 0x0c) >> 2; 3.1964 - gbObp1[2] = (value & 0x30) >> 4; 3.1965 - gbObp1[3] = (value & 0xc0) >> 6; 3.1966 - break; 3.1967 - } 3.1968 - 3.1969 - case 0x4a: 3.1970 - register_WY = value; 3.1971 - return; 3.1972 - 3.1973 - case 0x4b: 3.1974 - register_WX = value; 3.1975 - return; 3.1976 - 3.1977 - // KEY1 3.1978 - case 0x4d: 3.1979 - { 3.1980 - if (gbCgbMode) 3.1981 - { 3.1982 - gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1); 3.1983 - return; 3.1984 - } 3.1985 - break; 3.1986 - } 3.1987 - 3.1988 - // VBK 3.1989 - case 0x4f: 3.1990 - { 3.1991 - if (gbCgbMode) 3.1992 - { 3.1993 - value = value & 1; 3.1994 - if (value == gbVramBank) 3.1995 - return; 3.1996 - 3.1997 - int vramAddress = value * 0x2000; 3.1998 - gbMemoryMap[0x08] = &gbVram[vramAddress]; 3.1999 - gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000]; 3.2000 - 3.2001 - gbVramBank = value; 3.2002 - register_VBK = value; 3.2003 - } 3.2004 - return; 3.2005 - break; 3.2006 - } 3.2007 - 3.2008 - // HDMA1 3.2009 - case 0x51: 3.2010 - { 3.2011 - if (gbCgbMode) 3.2012 - { 3.2013 - if (value > 0x7f && value < 0xa0) 3.2014 - value = 0; 3.2015 - 3.2016 - gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0); 3.2017 - 3.2018 - register_HDMA1 = value; 3.2019 - return; 3.2020 - } 3.2021 - break; 3.2022 - } 3.2023 - 3.2024 - // HDMA2 3.2025 - case 0x52: 3.2026 - { 3.2027 - if (gbCgbMode) 3.2028 - { 3.2029 - value = value & 0xf0; 3.2030 - 3.2031 - gbHdmaSource = (register_HDMA1 << 8) | (value); 3.2032 - 3.2033 - register_HDMA2 = value; 3.2034 - return; 3.2035 - } 3.2036 - break; 3.2037 - } 3.2038 - 3.2039 - // HDMA3 3.2040 - case 0x53: 3.2041 - { 3.2042 - if (gbCgbMode) 3.2043 - { 3.2044 - value = value & 0x1f; 3.2045 - gbHdmaDestination = (value << 8) | (register_HDMA4 & 0xf0); 3.2046 - gbHdmaDestination += 0x8000; 3.2047 - register_HDMA3 = value; 3.2048 - return; 3.2049 - } 3.2050 - break; 3.2051 - } 3.2052 - 3.2053 - // HDMA4 3.2054 - case 0x54: 3.2055 - { 3.2056 - if (gbCgbMode) 3.2057 - { 3.2058 - value = value & 0xf0; 3.2059 - gbHdmaDestination = ((register_HDMA3 & 0x1f) << 8) | value; 3.2060 - gbHdmaDestination += 0x8000; 3.2061 - register_HDMA4 = value; 3.2062 - return; 3.2063 - } 3.2064 - break; 3.2065 - } 3.2066 - 3.2067 - // HDMA5 3.2068 - case 0x55: 3.2069 - { 3.2070 - if (gbCgbMode) 3.2071 - { 3.2072 - gbHdmaBytes = 16 + (value & 0x7f) * 16; 3.2073 - if (gbHdmaOn) 3.2074 - { 3.2075 - if (value & 0x80) 3.2076 - { 3.2077 - register_HDMA5 = (value & 0x7f); 3.2078 - } 3.2079 - else 3.2080 - { 3.2081 - register_HDMA5 = 0xff; 3.2082 - gbHdmaOn = 0; 3.2083 - } 3.2084 - } 3.2085 - else 3.2086 - { 3.2087 - if (value & 0x80) 3.2088 - { 3.2089 - gbHdmaOn = 1; 3.2090 - register_HDMA5 = value & 0x7f; 3.2091 - if (gbLcdMode == 0) 3.2092 - gbDoHdma(); 3.2093 - } 3.2094 - else 3.2095 - { 3.2096 - // we need to take the time it takes to complete the transfer into 3.2097 - // account... according to GB DEV FAQs, the setup time is the same 3.2098 - // for single and double speed, but the actual transfer takes the 3.2099 - // same time // (is that a typo?) 3.2100 - switch (gbDMASpeedVersion) 3.2101 - { 3.2102 - case 1: // I believe this is more correct 3.2103 - // the lower 7 bits of FF55 specify the Transfer Length (divided by 16, minus 1) 3.2104 - // and we make gbDmaTicks twice as many cycles at double speed to make the transfer take the same time 3.2105 - if (gbSpeed) 3.2106 - gbDmaTicks = 16 * ((value & 0x7f) + 1); 3.2107 - else 3.2108 - gbDmaTicks = 8 * ((value & 0x7f) + 1); 3.2109 - break; 3.2110 - case 0: // here for backward compatibility 3.2111 - // I think this was a guess that approximates the above in most but not all games 3.2112 - if (gbSpeed) 3.2113 - gbDmaTicks = 231 + 16 * (value & 0x7f); 3.2114 - else 3.2115 - gbDmaTicks = 231 + 8 * (value & 0x7f); 3.2116 - break; 3.2117 - default: // shouldn't happen 3.2118 - //assert(0); 3.2119 - break; 3.2120 - } 3.2121 - gbCopyMemory(gbHdmaDestination, gbHdmaSource, gbHdmaBytes); 3.2122 - gbHdmaDestination += gbHdmaBytes; 3.2123 - gbHdmaSource += gbHdmaBytes; 3.2124 - 3.2125 - register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f; 3.2126 - register_HDMA4 = gbHdmaDestination & 0xf0; 3.2127 - register_HDMA1 = (gbHdmaSource >> 8) & 0xff; 3.2128 - register_HDMA2 = gbHdmaSource & 0xf0; 3.2129 - } 3.2130 - } 3.2131 - return; 3.2132 - } 3.2133 - break; 3.2134 - } 3.2135 - 3.2136 - // BCPS 3.2137 - case 0x68: 3.2138 - { 3.2139 - if (gbCgbMode) 3.2140 - { 3.2141 - int paletteIndex = (value & 0x3f) >> 1; 3.2142 - int paletteHiLo = (value & 0x01); 3.2143 - 3.2144 - gbMemory[0xff68] = value; 3.2145 - gbMemory[0xff69] = (paletteHiLo ? 3.2146 - (gbPalette[paletteIndex] >> 8) : 3.2147 - (gbPalette[paletteIndex] & 0x00ff)); 3.2148 - return; 3.2149 - } 3.2150 - break; 3.2151 - } 3.2152 - 3.2153 - // BCPD 3.2154 - case 0x69: 3.2155 - { 3.2156 - if (gbCgbMode) 3.2157 - { 3.2158 - int v = gbMemory[0xff68]; 3.2159 - int paletteIndex = (v & 0x3f) >> 1; 3.2160 - int paletteHiLo = (v & 0x01); 3.2161 - gbMemory[0xff69] = value; 3.2162 - gbPalette[paletteIndex] = (paletteHiLo ? 3.2163 - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : 3.2164 - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; 3.2165 - 3.2166 - if (gbMemory[0xff68] & 0x80) 3.2167 - { 3.2168 - int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f; 3.2169 - 3.2170 - gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index; 3.2171 - 3.2172 - gbMemory[0xff69] = (index & 1 ? 3.2173 - (gbPalette[index >> 1] >> 8) : 3.2174 - (gbPalette[index >> 1] & 0x00ff)); 3.2175 - } 3.2176 - return; 3.2177 - } 3.2178 - break; 3.2179 - } 3.2180 - 3.2181 - // OCPS 3.2182 - case 0x6a: 3.2183 - { 3.2184 - if (gbCgbMode) 3.2185 - { 3.2186 - int paletteIndex = (value & 0x3f) >> 1; 3.2187 - int paletteHiLo = (value & 0x01); 3.2188 - 3.2189 - paletteIndex += 32; 3.2190 - 3.2191 - gbMemory[0xff6a] = value; 3.2192 - gbMemory[0xff6b] = (paletteHiLo ? 3.2193 - (gbPalette[paletteIndex] >> 8) : 3.2194 - (gbPalette[paletteIndex] & 0x00ff)); 3.2195 - return; 3.2196 - } 3.2197 - break; 3.2198 - } 3.2199 - 3.2200 - // OCPD 3.2201 - case 0x6b: 3.2202 - { 3.2203 - if (gbCgbMode) 3.2204 - { 3.2205 - int v = gbMemory[0xff6a]; 3.2206 - int paletteIndex = (v & 0x3f) >> 1; 3.2207 - int paletteHiLo = (v & 0x01); 3.2208 - 3.2209 - paletteIndex += 32; 3.2210 - 3.2211 - gbMemory[0xff6b] = value; 3.2212 - gbPalette[paletteIndex] = (paletteHiLo ? 3.2213 - ((value << 8) | (gbPalette[paletteIndex] & 0xff)) : 3.2214 - ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff; 3.2215 - if (gbMemory[0xff6a] & 0x80) 3.2216 - { 3.2217 - int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f; 3.2218 - 3.2219 - gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index; 3.2220 - 3.2221 - gbMemory[0xff6b] = (index & 1 ? 3.2222 - (gbPalette[(index >> 1) + 32] >> 8) : 3.2223 - (gbPalette[(index >> 1) + 32] & 0x00ff)); 3.2224 - } 3.2225 - return; 3.2226 - } 3.2227 - break; 3.2228 - } 3.2229 - 3.2230 - // SVBK 3.2231 - case 0x70: 3.2232 - { 3.2233 - if (gbCgbMode) 3.2234 - { 3.2235 - value = value & 7; 3.2236 - 3.2237 - int bank = value; 3.2238 - if (value == 0) 3.2239 - bank = 1; 3.2240 - 3.2241 - if (bank == gbWramBank) 3.2242 - return; 3.2243 - 3.2244 - int wramAddress = bank * 0x1000; 3.2245 - gbMemoryMap[0x0d] = &gbWram[wramAddress]; 3.2246 - 3.2247 - gbWramBank = bank; 3.2248 - register_SVBK = value; 3.2249 - return; 3.2250 - } 3.2251 - break; 3.2252 - } 3.2253 - 3.2254 - case 0xff: 3.2255 - { 3.2256 - register_IE = value; 3.2257 - register_IF &= value; 3.2258 - return; 3.2259 - } 3.2260 - } 3.2261 - 3.2262 - gbWriteMemoryQuick(address, value); 3.2263 -} 3.2264 - 3.2265 -u8 gbReadOpcode(register u16 address) 3.2266 -{ 3.2267 - if (gbCheatMap[address]) 3.2268 - return gbCheatRead(address); 3.2269 - 3.2270 - // the following fix does more than Echo RAM fix, anyway... 3.2271 - switch (gbEchoRAMFixOn ? (address >> 12) & 0x000f : address & 0xf000) 3.2272 - { 3.2273 - case 0x0a: 3.2274 - case 0x0b: 3.2275 - if (mapperReadRAM) 3.2276 - return mapperReadRAM(address); 3.2277 - break; 3.2278 - case 0x0f: 3.2279 - if (address > 0xff00) 3.2280 - { 3.2281 - switch (address & 0x00ff) 3.2282 - { 3.2283 - case 0x04: 3.2284 - return register_DIV; 3.2285 - case 0x05: 3.2286 - return register_TIMA; 3.2287 - case 0x06: 3.2288 - return register_TMA; 3.2289 - case 0x07: 3.2290 - return (0xf8 | register_TAC); 3.2291 - case 0x0f: 3.2292 - return (0xe0 | register_IF); 3.2293 - case 0x40: 3.2294 - return register_LCDC; 3.2295 - case 0x41: 3.2296 - return (0x80 | register_STAT); 3.2297 - case 0x42: 3.2298 - return register_SCY; 3.2299 - case 0x43: 3.2300 - return register_SCX; 3.2301 - case 0x44: 3.2302 - return register_LY; 3.2303 - case 0x45: 3.2304 - return register_LYC; 3.2305 - case 0x46: 3.2306 - return register_DMA; 3.2307 - case 0x4a: 3.2308 - return register_WY; 3.2309 - case 0x4b: 3.2310 - return register_WX; 3.2311 - case 0x4f: 3.2312 - return (0xfe | register_VBK); 3.2313 - case 0x51: 3.2314 - return register_HDMA1; 3.2315 - case 0x52: 3.2316 - return register_HDMA2; 3.2317 - case 0x53: 3.2318 - return register_HDMA3; 3.2319 - case 0x54: 3.2320 - return register_HDMA4; 3.2321 - case 0x55: 3.2322 - return register_HDMA5; 3.2323 - case 0x70: 3.2324 - return (0xf8 | register_SVBK); 3.2325 - case 0xff: 3.2326 - return register_IE; 3.2327 - } 3.2328 - } 3.2329 - break; 3.2330 - } 3.2331 - return gbReadMemoryQuick(address); 3.2332 -} 3.2333 - 3.2334 -void gbWriteMemory(register u16 address, register u8 value) 3.2335 -{ 3.2336 - gbWriteMemoryWrapped(address, value); 3.2337 - CallRegisteredLuaMemHook(address, 1, value, LUAMEMHOOK_WRITE); 3.2338 -} 3.2339 - 3.2340 -u8 gbReadMemory(register u16 address) 3.2341 -{ 3.2342 - if (gbCheatMap[address]) 3.2343 - return gbCheatRead(address); 3.2344 - 3.2345 - if (address < 0xa000) 3.2346 - return gbReadMemoryQuick(address); 3.2347 - 3.2348 - if (address < 0xc000) 3.2349 - { 3.2350 -#ifndef FINAL_VERSION 3.2351 - if (memorydebug) 3.2352 - { 3.2353 - log("Memory register read %04x PC=%04x\n", 3.2354 - address, 3.2355 - PC.W); 3.2356 - } 3.2357 -#endif 3.2358 - 3.2359 - if (mapperReadRAM) 3.2360 - return mapperReadRAM(address); 3.2361 - return gbReadMemoryQuick(address); 3.2362 - } 3.2363 - 3.2364 - if (address >= 0xff00) 3.2365 - { 3.2366 - switch (address & 0x00ff) 3.2367 - { 3.2368 - case 0x00: 3.2369 - { 3.2370 - if (gbSgbMode) 3.2371 - { 3.2372 - gbSgbReadingController |= 4; 3.2373 - gbSgbResetPacketState(); 3.2374 - } 3.2375 - 3.2376 - int b = gbMemory[0xff00]; 3.2377 - 3.2378 - if ((b & 0x30) == 0x20) 3.2379 - { 3.2380 - b &= 0xf0; 3.2381 - 3.2382 - int joy = 0; 3.2383 - if (gbSgbMode && gbSgbMultiplayer) 3.2384 - { 3.2385 - switch (gbSgbNextController) 3.2386 - { 3.2387 - case 0x0f: 3.2388 - joy = 0; 3.2389 - break; 3.2390 - case 0x0e: 3.2391 - joy = 1; 3.2392 - break; 3.2393 - case 0x0d: 3.2394 - joy = 2; 3.2395 - break; 3.2396 - case 0x0c: 3.2397 - joy = 3; 3.2398 - break; 3.2399 - default: 3.2400 - joy = 0; 3.2401 - } 3.2402 - } 3.2403 - int joystate = gbJoymask[joy]; 3.2404 - if (!(joystate & 128)) 3.2405 - b |= 0x08; 3.2406 - if (!(joystate & 64)) 3.2407 - b |= 0x04; 3.2408 - if (!(joystate & 32)) 3.2409 - b |= 0x02; 3.2410 - if (!(joystate & 16)) 3.2411 - b |= 0x01; 3.2412 - 3.2413 - gbMemory[0xff00] = b; 3.2414 - } 3.2415 - else if ((b & 0x30) == 0x10) 3.2416 - { 3.2417 - b &= 0xf0; 3.2418 - 3.2419 - int joy = 0; 3.2420 - if (gbSgbMode && gbSgbMultiplayer) 3.2421 - { 3.2422 - switch (gbSgbNextController) 3.2423 - { 3.2424 - case 0x0f: 3.2425 - joy = 0; 3.2426 - break; 3.2427 - case 0x0e: 3.2428 - joy = 1; 3.2429 - break; 3.2430 - case 0x0d: 3.2431 - joy = 2; 3.2432 - break; 3.2433 - case 0x0c: 3.2434 - joy = 3; 3.2435 - break; 3.2436 - default: 3.2437 - joy = 0; 3.2438 - } 3.2439 - } 3.2440 - int joystate = gbJoymask[joy]; 3.2441 - if (!(joystate & 8)) 3.2442 - b |= 0x08; 3.2443 - if (!(joystate & 4)) 3.2444 - b |= 0x04; 3.2445 - if (!(joystate & 2)) 3.2446 - b |= 0x02; 3.2447 - if (!(joystate & 1)) 3.2448 - b |= 0x01; 3.2449 - 3.2450 - gbMemory[0xff00] = b; 3.2451 - } 3.2452 - else 3.2453 - { 3.2454 - if (gbSgbMode && gbSgbMultiplayer) 3.2455 - { 3.2456 - gbMemory[0xff00] = 0xf0 | gbSgbNextController; 3.2457 - } 3.2458 - else 3.2459 - { 3.2460 - gbMemory[0xff00] = 0xff; 3.2461 - } 3.2462 - } 3.2463 - } 3.2464 - GBSystemCounters.lagged = false; 3.2465 - return gbMemory[0xff00]; 3.2466 - break; 3.2467 - case 0x01: 3.2468 - return gbMemory[0xff01]; 3.2469 - case 0x04: 3.2470 - return register_DIV; 3.2471 - case 0x05: 3.2472 - return register_TIMA; 3.2473 - case 0x06: 3.2474 - return register_TMA; 3.2475 - case 0x07: 3.2476 - return (0xf8 | register_TAC); 3.2477 - case 0x0f: 3.2478 - return (0xe0 | register_IF); 3.2479 - case 0x40: 3.2480 - return register_LCDC; 3.2481 - case 0x41: 3.2482 - return (0x80 | register_STAT); 3.2483 - case 0x42: 3.2484 - return register_SCY; 3.2485 - case 0x43: 3.2486 - return register_SCX; 3.2487 - case 0x44: 3.2488 - return register_LY; 3.2489 - case 0x45: 3.2490 - return register_LYC; 3.2491 - case 0x46: 3.2492 - return register_DMA; 3.2493 - case 0x4a: 3.2494 - return register_WY; 3.2495 - case 0x4b: 3.2496 - return register_WX; 3.2497 - case 0x4f: 3.2498 - return (0xfe | register_VBK); 3.2499 - case 0x51: 3.2500 - return register_HDMA1; 3.2501 - case 0x52: 3.2502 - return register_HDMA2; 3.2503 - case 0x53: 3.2504 - return register_HDMA3; 3.2505 - case 0x54: 3.2506 - return register_HDMA4; 3.2507 - case 0x55: 3.2508 - return register_HDMA5; 3.2509 - case 0x70: 3.2510 - return (0xf8 | register_SVBK); 3.2511 - case 0xff: 3.2512 - return register_IE; 3.2513 - } 3.2514 - } 3.2515 - 3.2516 - return gbReadMemoryQuick(address); 3.2517 + } 3.2518 + 3.2519 + return gbReadMemoryQuick(address); 3.2520 } 3.2521 3.2522 void gbVblank_interrupt() 3.2523 { 3.2524 - if (IFF & 0x80) 3.2525 - { 3.2526 - PC.W++; 3.2527 - IFF &= 0x7f; 3.2528 - } 3.2529 - gbInterrupt &= 0xfe; 3.2530 - 3.2531 - IFF &= 0x7e; 3.2532 - register_IF &= 0xfe; 3.2533 - 3.2534 - gbWriteMemory(--SP.W, PC.B.B1); 3.2535 - gbWriteMemory(--SP.W, PC.B.B0); 3.2536 - PC.W = 0x40; 3.2537 + if (IFF & 0x80) 3.2538 + { 3.2539 + PC.W++; 3.2540 + IFF &= 0x7f; 3.2541 + } 3.2542 + gbInterrupt &= 0xfe; 3.2543 + 3.2544 + IFF &= 0x7e; 3.2545 + register_IF &= 0xfe; 3.2546 + 3.2547 + gbWriteMemory(--SP.W, PC.B.B1); 3.2548 + gbWriteMemory(--SP.W, PC.B.B0); 3.2549 + PC.W = 0x40; 3.2550 } 3.2551 3.2552 void gbLcd_interrupt() 3.2553 { 3.2554 - if (IFF & 0x80) 3.2555 - { 3.2556 - PC.W++; 3.2557 - IFF &= 0x7f; 3.2558 - } 3.2559 - gbInterrupt &= 0xfd; 3.2560 - IFF &= 0x7e; 3.2561 - register_IF &= 0xfd; 3.2562 - 3.2563 - gbWriteMemory(--SP.W, PC.B.B1); 3.2564 - gbWriteMemory(--SP.W, PC.B.B0); 3.2565 - 3.2566 - PC.W = 0x48; 3.2567 + if (IFF & 0x80) 3.2568 + { 3.2569 + PC.W++; 3.2570 + IFF &= 0x7f; 3.2571 + } 3.2572 + gbInterrupt &= 0xfd; 3.2573 + IFF &= 0x7e; 3.2574 + register_IF &= 0xfd; 3.2575 + 3.2576 + gbWriteMemory(--SP.W, PC.B.B1); 3.2577 + gbWriteMemory(--SP.W, PC.B.B0); 3.2578 + 3.2579 + PC.W = 0x48; 3.2580 } 3.2581 3.2582 void gbTimer_interrupt() 3.2583 { 3.2584 - if (IFF & 0x80) 3.2585 - { 3.2586 - PC.W++; 3.2587 - IFF &= 0x7f; 3.2588 - } 3.2589 - IFF &= 0x7e; 3.2590 - gbInterrupt &= 0xfb; 3.2591 - register_IF &= 0xfb; 3.2592 - 3.2593 - gbWriteMemory(--SP.W, PC.B.B1); 3.2594 - gbWriteMemory(--SP.W, PC.B.B0); 3.2595 - 3.2596 - PC.W = 0x50; 3.2597 + if (IFF & 0x80) 3.2598 + { 3.2599 + PC.W++; 3.2600 + IFF &= 0x7f; 3.2601 + } 3.2602 + IFF &= 0x7e; 3.2603 + gbInterrupt &= 0xfb; 3.2604 + register_IF &= 0xfb; 3.2605 + 3.2606 + gbWriteMemory(--SP.W, PC.B.B1); 3.2607 + gbWriteMemory(--SP.W, PC.B.B0); 3.2608 + 3.2609 + PC.W = 0x50; 3.2610 } 3.2611 3.2612 void gbSerial_interrupt() 3.2613 { 3.2614 - if (IFF & 0x80) 3.2615 - { 3.2616 - PC.W++; 3.2617 - IFF &= 0x7f; 3.2618 - } 3.2619 - IFF &= 0x7e; 3.2620 - gbInterrupt &= 0xf7; 3.2621 - register_IF &= 0xf7; 3.2622 - 3.2623 - gbWriteMemory(--SP.W, PC.B.B1); 3.2624 - gbWriteMemory(--SP.W, PC.B.B0); 3.2625 - 3.2626 - PC.W = 0x58; 3.2627 + if (IFF & 0x80) 3.2628 + { 3.2629 + PC.W++; 3.2630 + IFF &= 0x7f; 3.2631 + } 3.2632 + IFF &= 0x7e; 3.2633 + gbInterrupt &= 0xf7; 3.2634 + register_IF &= 0xf7; 3.2635 + 3.2636 + gbWriteMemory(--SP.W, PC.B.B1); 3.2637 + gbWriteMemory(--SP.W, PC.B.B0); 3.2638 + 3.2639 + PC.W = 0x58; 3.2640 } 3.2641 3.2642 void gbJoypad_interrupt() 3.2643 { 3.2644 - if (IFF & 0x80) 3.2645 - { 3.2646 - PC.W++; 3.2647 - IFF &= 0x7f; 3.2648 - } 3.2649 - IFF &= 0x7e; 3.2650 - gbInterrupt &= 0xef; 3.2651 - register_IF &= 0xef; 3.2652 - 3.2653 - gbWriteMemory(--SP.W, PC.B.B1); 3.2654 - gbWriteMemory(--SP.W, PC.B.B0); 3.2655 - 3.2656 - PC.W = 0x60; 3.2657 + if (IFF & 0x80) 3.2658 + { 3.2659 + PC.W++; 3.2660 + IFF &= 0x7f; 3.2661 + } 3.2662 + IFF &= 0x7e; 3.2663 + gbInterrupt &= 0xef; 3.2664 + register_IF &= 0xef; 3.2665 + 3.2666 + gbWriteMemory(--SP.W, PC.B.B1); 3.2667 + gbWriteMemory(--SP.W, PC.B.B0); 3.2668 + 3.2669 + PC.W = 0x60; 3.2670 } 3.2671 3.2672 void gbSpeedSwitch() 3.2673 { 3.2674 - if (gbSpeed == 0) 3.2675 - { 3.2676 - gbSpeed = 1; 3.2677 - GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; //127; //51 * 2; 3.2678 - GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; 3.2679 - GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; //52; //20 * 2; 3.2680 - GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; //99; //43 * 2; 3.2681 - GBDIV_CLOCK_TICKS = 64 * 2; 3.2682 - GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; 3.2683 - GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2; 3.2684 - GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2; 3.2685 - GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2; 3.2686 - GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2; 3.2687 - GBSERIAL_CLOCK_TICKS = 128 * 2; 3.2688 - gbDivTicks *= 2; 3.2689 - gbLcdTicks *= 2; 3.2690 - gbLcdLYIncrementTicks *= 2; 3.2691 - // timerTicks *= 2; 3.2692 - // timerClockTicks *= 2; 3.2693 - gbSerialTicks *= 2; 3.2694 - SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS * 2; 3.2695 - soundTicks *= 2; 3.2696 - // synchronizeTicks *= 2; 3.2697 - // SYNCHRONIZE_CLOCK_TICKS *= 2; 3.2698 - } 3.2699 - else 3.2700 - { 3.2701 - gbSpeed = 0; 3.2702 - GBLCD_MODE_0_CLOCK_TICKS = 51; 3.2703 - GBLCD_MODE_1_CLOCK_TICKS = 1140; 3.2704 - GBLCD_MODE_2_CLOCK_TICKS = 20; 3.2705 - GBLCD_MODE_3_CLOCK_TICKS = 43; 3.2706 - GBDIV_CLOCK_TICKS = 64; 3.2707 - GBLY_INCREMENT_CLOCK_TICKS = 114; 3.2708 - GBTIMER_MODE_0_CLOCK_TICKS = 256; 3.2709 - GBTIMER_MODE_1_CLOCK_TICKS = 4; 3.2710 - GBTIMER_MODE_2_CLOCK_TICKS = 16; 3.2711 - GBTIMER_MODE_3_CLOCK_TICKS = 64; 3.2712 - GBSERIAL_CLOCK_TICKS = 128; 3.2713 - gbDivTicks /= 2; 3.2714 - gbLcdTicks /= 2; 3.2715 - gbLcdLYIncrementTicks /= 2; 3.2716 - // timerTicks /= 2; 3.2717 - // timerClockTicks /= 2; 3.2718 - gbSerialTicks /= 2; 3.2719 - SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS; 3.2720 - soundTicks /= 2; 3.2721 - // synchronizeTicks /= 2; 3.2722 - // SYNCHRONIZE_CLOCK_TICKS /= 2; 3.2723 - } 3.2724 + if (gbSpeed == 0) 3.2725 + { 3.2726 + gbSpeed = 1; 3.2727 + GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; //127; //51 * 2; 3.2728 + GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2; 3.2729 + GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; //52; //20 * 2; 3.2730 + GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; //99; //43 * 2; 3.2731 + GBDIV_CLOCK_TICKS = 64 * 2; 3.2732 + GBLY_INCREMENT_CLOCK_TICKS = 114 * 2; 3.2733 + GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2; 3.2734 + GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2; 3.2735 + GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2; 3.2736 + GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2; 3.2737 + GBSERIAL_CLOCK_TICKS = 128 * 2; 3.2738 + gbDivTicks *= 2; 3.2739 + gbLcdTicks *= 2; 3.2740 + gbLcdLYIncrementTicks *= 2; 3.2741 + // timerTicks *= 2; 3.2742 + // timerClockTicks *= 2; 3.2743 + gbSerialTicks *= 2; 3.2744 + SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS * 2; 3.2745 + soundTicks *= 2; 3.2746 + // synchronizeTicks *= 2; 3.2747 + // SYNCHRONIZE_CLOCK_TICKS *= 2; 3.2748 + } 3.2749 + else 3.2750 + { 3.2751 + gbSpeed = 0; 3.2752 + GBLCD_MODE_0_CLOCK_TICKS = 51; 3.2753 + GBLCD_MODE_1_CLOCK_TICKS = 1140; 3.2754 + GBLCD_MODE_2_CLOCK_TICKS = 20; 3.2755 + GBLCD_MODE_3_CLOCK_TICKS = 43; 3.2756 + GBDIV_CLOCK_TICKS = 64; 3.2757 + GBLY_INCREMENT_CLOCK_TICKS = 114; 3.2758 + GBTIMER_MODE_0_CLOCK_TICKS = 256; 3.2759 + GBTIMER_MODE_1_CLOCK_TICKS = 4; 3.2760 + GBTIMER_MODE_2_CLOCK_TICKS = 16; 3.2761 + GBTIMER_MODE_3_CLOCK_TICKS = 64; 3.2762 + GBSERIAL_CLOCK_TICKS = 128; 3.2763 + gbDivTicks /= 2; 3.2764 + gbLcdTicks /= 2; 3.2765 + gbLcdLYIncrementTicks /= 2; 3.2766 + // timerTicks /= 2; 3.2767 + // timerClockTicks /= 2; 3.2768 + gbSerialTicks /= 2; 3.2769 + SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS; 3.2770 + soundTicks /= 2; 3.2771 + // synchronizeTicks /= 2; 3.2772 + // SYNCHRONIZE_CLOCK_TICKS /= 2; 3.2773 + } 3.2774 } 3.2775 3.2776 void gbGetHardwareType() 3.2777 { 3.2778 - gbCgbMode = 0; 3.2779 - if (gbRom[0x143] & 0x80) 3.2780 + gbCgbMode = 0; 3.2781 + if (gbRom[0x143] & 0x80) 3.2782 + { 3.2783 + if (gbEmulatorType == 0 || 3.2784 + gbEmulatorType == 1 || 3.2785 + gbEmulatorType == 4 || 3.2786 + gbEmulatorType == 5 || 3.2787 + (gbRom[0x146] != 0x03 && (gbEmulatorType == 2))) 3.2788 { 3.2789 - if (gbEmulatorType == 0 || 3.2790 - gbEmulatorType == 1 || 3.2791 - gbEmulatorType == 4 || 3.2792 - gbEmulatorType == 5 || 3.2793 - (gbRom[0x146] != 0x03 && (gbEmulatorType == 2))) 3.2794 - { 3.2795 - gbCgbMode = 1; 3.2796 - } 3.2797 + gbCgbMode = 1; 3.2798 } 3.2799 - 3.2800 - if (gbSgbMode == 2) 3.2801 - { 3.2802 - gbSgbMode = 0; 3.2803 - return; 3.2804 - } 3.2805 - 3.2806 - gbSgbMode = 0; 3.2807 - if (gbRom[0x146] == 0x03) 3.2808 - { 3.2809 - if (gbEmulatorType == 0 || 3.2810 - gbEmulatorType == 2 || 3.2811 - gbEmulatorType == 5 || 3.2812 - (!(gbRom[0x143] & 0x80) && (gbEmulatorType == 1 || gbEmulatorType == 4))) 3.2813 - gbSgbMode = 1; 3.2814 - } 3.2815 + } 3.2816 + 3.2817 + if (gbSgbMode == 2) 3.2818 + { 3.2819 + gbSgbMode = 0; 3.2820 + return; 3.2821 + } 3.2822 + 3.2823 + gbSgbMode = 0; 3.2824 + if (gbRom[0x146] == 0x03) 3.2825 + { 3.2826 + if (gbEmulatorType == 0 || 3.2827 + gbEmulatorType == 2 || 3.2828 + gbEmulatorType == 5 || 3.2829 + (!(gbRom[0x143] & 0x80) && (gbEmulatorType == 1 || gbEmulatorType == 4))) 3.2830 + gbSgbMode = 1; 3.2831 + } 3.2832 } 3.2833 3.2834 void gbReset(bool userReset) 3.2835 { 3.2836 - // movie must be closed while opening/creating a movie 3.2837 - if (userReset && VBAMovieRecording()) 3.2838 + // movie must be closed while opening/creating a movie 3.2839 + if (userReset && VBAMovieRecording()) 3.2840 + { 3.2841 + VBAMovieSignalReset(); 3.2842 + return; 3.2843 + } 3.2844 + 3.2845 + if (!VBAMovieActive()) 3.2846 + { 3.2847 + GBSystemCounters.frameCount = 0; 3.2848 + GBSystemCounters.lagCount = 0; 3.2849 + GBSystemCounters.extraCount = 0; 3.2850 + GBSystemCounters.lagged = true; 3.2851 + GBSystemCounters.laggedLast = true; 3.2852 + } 3.2853 + 3.2854 + SP.W = 0xfffe; 3.2855 + AF.W = 0x01b0; 3.2856 + BC.W = 0x0013; 3.2857 + DE.W = 0x00d8; 3.2858 + HL.W = 0x014d; 3.2859 + PC.W = 0x0100; 3.2860 + IFF = 0; 3.2861 + gbInterrupt = 1; 3.2862 + gbInterruptWait = 0; 3.2863 + 3.2864 + register_DIV = 0; 3.2865 + register_TIMA = 0; 3.2866 + register_TMA = 0; 3.2867 + register_TAC = 0; 3.2868 + register_IF = 1; 3.2869 + register_LCDC = 0x91; 3.2870 + register_STAT = 0; 3.2871 + register_SCY = 0; 3.2872 + register_SCX = 0; 3.2873 + register_LY = 0; 3.2874 + register_LYC = 0; 3.2875 + register_DMA = 0; 3.2876 + register_WY = 0; 3.2877 + register_WX = 0; 3.2878 + register_VBK = 0; 3.2879 + register_HDMA1 = 0; 3.2880 + register_HDMA2 = 0; 3.2881 + register_HDMA3 = 0; 3.2882 + register_HDMA4 = 0; 3.2883 + register_HDMA5 = 0; 3.2884 + register_SVBK = 0; 3.2885 + register_IE = 0; 3.2886 + 3.2887 + gbGetHardwareType(); 3.2888 + if (gbCgbMode) 3.2889 + { 3.2890 + if (!gbVram) 3.2891 + gbVram = (u8 *)malloc(0x4000 + 4); 3.2892 + if (!gbWram) 3.2893 + gbWram = (u8 *)malloc(0x8000 + 4); 3.2894 + memset(gbVram, 0, 0x4000 + 4); 3.2895 + memset(gbWram, 0, 0x8000 + 4); 3.2896 + } 3.2897 + else 3.2898 + { 3.2899 + if (gbVram) 3.2900 { 3.2901 - VBAMovieSignalReset(); 3.2902 - return; 3.2903 + free(gbVram); 3.2904 + gbVram = NULL; 3.2905 } 3.2906 - 3.2907 - if (!VBAMovieActive()) 3.2908 + if (gbWram) 3.2909 { 3.2910 - GBSystemCounters.frameCount = 0; 3.2911 - GBSystemCounters.lagCount = 0; 3.2912 - GBSystemCounters.extraCount = 0; 3.2913 - GBSystemCounters.lagged = true; 3.2914 - GBSystemCounters.laggedLast = true; 3.2915 + free(gbWram); 3.2916 + gbWram = NULL; 3.2917 } 3.2918 - 3.2919 - SP.W = 0xfffe; 3.2920 - AF.W = 0x01b0; 3.2921 - BC.W = 0x0013; 3.2922 - DE.W = 0x00d8; 3.2923 - HL.W = 0x014d; 3.2924 - PC.W = 0x0100; 3.2925 - IFF = 0; 3.2926 - gbInterrupt = 1; 3.2927 - gbInterruptWait = 0; 3.2928 - 3.2929 - register_DIV = 0; 3.2930 - register_TIMA = 0; 3.2931 - register_TMA = 0; 3.2932 - register_TAC = 0; 3.2933 - register_IF = 1; 3.2934 - register_LCDC = 0x91; 3.2935 - register_STAT = 0; 3.2936 - register_SCY = 0; 3.2937 - register_SCX = 0; 3.2938 - register_LY = 0; 3.2939 - register_LYC = 0; 3.2940 - register_DMA = 0; 3.2941 - register_WY = 0; 3.2942 - register_WX = 0; 3.2943 - register_VBK = 0; 3.2944 - register_HDMA1 = 0; 3.2945 - register_HDMA2 = 0; 3.2946 - register_HDMA3 = 0; 3.2947 - register_HDMA4 = 0; 3.2948 - register_HDMA5 = 0; 3.2949 - register_SVBK = 0; 3.2950 - register_IE = 0; 3.2951 - 3.2952 - gbGetHardwareType(); 3.2953 - if (gbCgbMode) 3.2954 + } 3.2955 + 3.2956 + // clean LineBuffer 3.2957 + if (gbLineBuffer) 3.2958 + memset(gbLineBuffer, 0, 160 * sizeof(u16)); 3.2959 + // clean Pix 3.2960 + if (pix) 3.2961 + memset(pix, 0, 4 * 257 * 226); 3.2962 + 3.2963 + if (gbCgbMode) 3.2964 + { 3.2965 + if (gbSgbMode) 3.2966 { 3.2967 - if (!gbVram) 3.2968 - gbVram = (u8 *)malloc(0x4000 + 4); 3.2969 - if (!gbWram) 3.2970 - gbWram = (u8 *)malloc(0x8000 + 4); 3.2971 - memset(gbVram, 0, 0x4000 + 4); 3.2972 - memset(gbWram, 0, 0x8000 + 4); 3.2973 + if (gbEmulatorType == 5) 3.2974 + AF.W = 0xffb0; 3.2975 + else 3.2976 + AF.W = 0x01b0; 3.2977 + BC.W = 0x0013; 3.2978 + DE.W = 0x00d8; 3.2979 + HL.W = 0x014d; 3.2980 } 3.2981 - else 3.2982 + else 3.2983 { 3.2984 - if (gbVram) 3.2985 - { 3.2986 - free(gbVram); 3.2987 - gbVram = NULL; 3.2988 - } 3.2989 - if (gbWram) 3.2990 - { 3.2991 - free(gbWram); 3.2992 - gbWram = NULL; 3.2993 - } 3.2994 + AF.W = 0x11b0; 3.2995 + BC.W = 0x0000; 3.2996 + DE.W = 0xff56; 3.2997 + HL.W = 0x000d; 3.2998 } 3.2999 - 3.3000 - // clean LineBuffer 3.3001 - if (gbLineBuffer) 3.3002 - memset(gbLineBuffer, 0, 160 * sizeof(u16)); 3.3003 - // clean Pix 3.3004 - if (pix) 3.3005 - memset(pix, 0, 4 * 257 * 226); 3.3006 - 3.3007 - if (gbCgbMode) 3.3008 - { 3.3009 - if (gbSgbMode) 3.3010 - { 3.3011 - if (gbEmulatorType == 5) 3.3012 - AF.W = 0xffb0; 3.3013 - else 3.3014 - AF.W = 0x01b0; 3.3015 - BC.W = 0x0013; 3.3016 - DE.W = 0x00d8; 3.3017 - HL.W = 0x014d; 3.3018 - } 3.3019 - else 3.3020 - { 3.3021 - AF.W = 0x11b0; 3.3022 - BC.W = 0x0000; 3.3023 - DE.W = 0xff56; 3.3024 - HL.W = 0x000d; 3.3025 - } 3.3026 - if (gbEmulatorType == 4) 3.3027 - BC.B.B1 |= 0x01; 3.3028 - 3.3029 - register_HDMA5 = 0xff; 3.3030 - gbMemory[0xff68] = 0xc0; 3.3031 - gbMemory[0xff6a] = 0xc0; 3.3032 - 3.3033 - for (int i = 0; i < 64; i++) 3.3034 - gbPalette[i] = 0x7fff; 3.3035 - } 3.3036 - else 3.3037 - { 3.3038 - for (int i = 0; i < 8; i++) 3.3039 - gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; 3.3040 - } 3.3041 - 3.3042 - if (gbSpeed) 3.3043 - { 3.3044 - gbSpeedSwitch(); 3.3045 - gbMemory[0xff4d] = 0; 3.3046 - } 3.3047 - 3.3048 - gbDivTicks = GBDIV_CLOCK_TICKS; 3.3049 - gbLcdMode = 2; 3.3050 - gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS; 3.3051 - gbLcdLYIncrementTicks = 0; 3.3052 - gbTimerTicks = 0; 3.3053 - gbTimerClockTicks = 0; 3.3054 - gbSerialTicks = 0; 3.3055 - gbSerialBits = 0; 3.3056 - gbSerialOn = 0; 3.3057 - gbWindowLine = -1; 3.3058 - gbTimerOn = 0; 3.3059 - gbTimerMode = 0; 3.3060 - // gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; 3.3061 - gbSpeed = 0; 3.3062 - gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; 3.3063 - 3.3064 - // FIXME: horrible kludge 3.3065 - memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); 3.3066 - 3.3067 - if (gbCgbMode) 3.3068 - { 3.3069 - gbSpeed = 0; 3.3070 - gbHdmaOn = 0; 3.3071 - gbHdmaSource = 0x0000; 3.3072 - gbHdmaDestination = 0x8000; 3.3073 - gbVramBank = 0; 3.3074 - gbWramBank = 1; 3.3075 - register_LY = 0x90; 3.3076 - gbLcdMode = 1; 3.3077 - } 3.3078 - 3.3079 - if (gbSgbMode) 3.3080 - { 3.3081 - gbSgbReset(); 3.3082 - } 3.3083 - 3.3084 - for (int i = 0; i < 4; i++) 3.3085 - gbBgp[i] = gbObp0[i] = gbObp1[i] = i; 3.3086 - 3.3087 - memset(&gbDataMBC1, 0, sizeof(gbDataMBC1)); 3.3088 - gbDataMBC1.mapperROMBank = 1; 3.3089 - 3.3090 - gbDataMBC2.mapperRAMEnable = 0; 3.3091 - gbDataMBC2.mapperROMBank = 1; 3.3092 - 3.3093 - memset(&gbDataMBC3, 0, 6 * sizeof(int32)); 3.3094 - gbDataMBC3.mapperROMBank = 1; 3.3095 - 3.3096 - memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); 3.3097 - gbDataMBC5.mapperROMBank = 1; 3.3098 - switch (gbRom[0x147]) 3.3099 - { 3.3100 - case 0x1c: 3.3101 - case 0x1d: 3.3102 - case 0x1e: 3.3103 - gbDataMBC5.isRumbleCartridge = 1; 3.3104 - } 3.3105 - 3.3106 - memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); 3.3107 - gbDataHuC1.mapperROMBank = 1; 3.3108 - 3.3109 - memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); 3.3110 - gbDataHuC3.mapperROMBank = 1; 3.3111 - 3.3112 - gbMemoryMap[0x00] = &gbRom[0x0000]; 3.3113 - gbMemoryMap[0x01] = &gbRom[0x1000]; 3.3114 - gbMemoryMap[0x02] = &gbRom[0x2000]; 3.3115 - gbMemoryMap[0x03] = &gbRom[0x3000]; 3.3116 - gbMemoryMap[0x04] = &gbRom[0x4000]; 3.3117 - gbMemoryMap[0x05] = &gbRom[0x5000]; 3.3118 - gbMemoryMap[0x06] = &gbRom[0x6000]; 3.3119 - gbMemoryMap[0x07] = &gbRom[0x7000]; 3.3120 - if (gbCgbMode) 3.3121 - { 3.3122 - gbMemoryMap[0x08] = &gbVram[0x0000]; 3.3123 - gbMemoryMap[0x09] = &gbVram[0x1000]; 3.3124 - gbMemoryMap[0x0a] = &gbMemory[0xa000]; 3.3125 - gbMemoryMap[0x0b] = &gbMemory[0xb000]; 3.3126 - gbMemoryMap[0x0c] = &gbMemory[0xc000]; 3.3127 - gbMemoryMap[0x0d] = &gbWram[0x1000]; 3.3128 - gbMemoryMap[0x0e] = &gbMemory[0xe000]; 3.3129 - gbMemoryMap[0x0f] = &gbMemory[0xf000]; 3.3130 - } 3.3131 - else 3.3132 - { 3.3133 - gbMemoryMap[0x08] = &gbMemory[0x8000]; 3.3134 - gbMemoryMap[0x09] = &gbMemory[0x9000]; 3.3135 - gbMemoryMap[0x0a] = &gbMemory[0xa000]; 3.3136 - gbMemoryMap[0x0b] = &gbMemory[0xb000]; 3.3137 - gbMemoryMap[0x0c] = &gbMemory[0xc000]; 3.3138 - gbMemoryMap[0x0d] = &gbMemory[0xd000]; 3.3139 - gbMemoryMap[0x0e] = &gbMemory[0xe000]; 3.3140 - gbMemoryMap[0x0f] = &gbMemory[0xf000]; 3.3141 - } 3.3142 - 3.3143 - if (gbRam) 3.3144 - { 3.3145 - gbMemoryMap[0x0a] = &gbRam[0x0000]; 3.3146 - gbMemoryMap[0x0b] = &gbRam[0x1000]; 3.3147 - } 3.3148 - 3.3149 - gbSoundReset(); 3.3150 - 3.3151 - systemResetSensor(); 3.3152 - 3.3153 - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.3154 - 3.3155 - gbLastTime = systemGetClock(); 3.3156 - gbFrameCount = 0; 3.3157 - 3.3158 - systemRefreshScreen(); 3.3159 + if (gbEmulatorType == 4) 3.3160 + BC.B.B1 |= 0x01; 3.3161 + 3.3162 + register_HDMA5 = 0xff; 3.3163 + gbMemory[0xff68] = 0xc0; 3.3164 + gbMemory[0xff6a] = 0xc0; 3.3165 + 3.3166 + for (int i = 0; i < 64; i++) 3.3167 + gbPalette[i] = 0x7fff; 3.3168 + } 3.3169 + else 3.3170 + { 3.3171 + for (int i = 0; i < 8; i++) 3.3172 + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; 3.3173 + } 3.3174 + 3.3175 + if (gbSpeed) 3.3176 + { 3.3177 + gbSpeedSwitch(); 3.3178 + gbMemory[0xff4d] = 0; 3.3179 + } 3.3180 + 3.3181 + gbDivTicks = GBDIV_CLOCK_TICKS; 3.3182 + gbLcdMode = 2; 3.3183 + gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS; 3.3184 + gbLcdLYIncrementTicks = 0; 3.3185 + gbTimerTicks = 0; 3.3186 + gbTimerClockTicks = 0; 3.3187 + gbSerialTicks = 0; 3.3188 + gbSerialBits = 0; 3.3189 + gbSerialOn = 0; 3.3190 + gbWindowLine = -1; 3.3191 + gbTimerOn = 0; 3.3192 + gbTimerMode = 0; 3.3193 + // gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS; 3.3194 + gbSpeed = 0; 3.3195 + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; 3.3196 + 3.3197 + // FIXME: horrible kludge 3.3198 + memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); 3.3199 + 3.3200 + if (gbCgbMode) 3.3201 + { 3.3202 + gbSpeed = 0; 3.3203 + gbHdmaOn = 0; 3.3204 + gbHdmaSource = 0x0000; 3.3205 + gbHdmaDestination = 0x8000; 3.3206 + gbVramBank = 0; 3.3207 + gbWramBank = 1; 3.3208 + register_LY = 0x90; 3.3209 + gbLcdMode = 1; 3.3210 + } 3.3211 + 3.3212 + if (gbSgbMode) 3.3213 + { 3.3214 + gbSgbReset(); 3.3215 + } 3.3216 + 3.3217 + for (int i = 0; i < 4; i++) 3.3218 + gbBgp[i] = gbObp0[i] = gbObp1[i] = i; 3.3219 + 3.3220 + memset(&gbDataMBC1, 0, sizeof(gbDataMBC1)); 3.3221 + gbDataMBC1.mapperROMBank = 1; 3.3222 + 3.3223 + gbDataMBC2.mapperRAMEnable = 0; 3.3224 + gbDataMBC2.mapperROMBank = 1; 3.3225 + 3.3226 + memset(&gbDataMBC3, 0, 6 * sizeof(int32)); 3.3227 + gbDataMBC3.mapperROMBank = 1; 3.3228 + 3.3229 + memset(&gbDataMBC5, 0, sizeof(gbDataMBC5)); 3.3230 + gbDataMBC5.mapperROMBank = 1; 3.3231 + switch (gbRom[0x147]) 3.3232 + { 3.3233 + case 0x1c: 3.3234 + case 0x1d: 3.3235 + case 0x1e: 3.3236 + gbDataMBC5.isRumbleCartridge = 1; 3.3237 + } 3.3238 + 3.3239 + memset(&gbDataHuC1, 0, sizeof(gbDataHuC1)); 3.3240 + gbDataHuC1.mapperROMBank = 1; 3.3241 + 3.3242 + memset(&gbDataHuC3, 0, sizeof(gbDataHuC3)); 3.3243 + gbDataHuC3.mapperROMBank = 1; 3.3244 + 3.3245 + gbMemoryMap[0x00] = &gbRom[0x0000]; 3.3246 + gbMemoryMap[0x01] = &gbRom[0x1000]; 3.3247 + gbMemoryMap[0x02] = &gbRom[0x2000]; 3.3248 + gbMemoryMap[0x03] = &gbRom[0x3000]; 3.3249 + gbMemoryMap[0x04] = &gbRom[0x4000]; 3.3250 + gbMemoryMap[0x05] = &gbRom[0x5000]; 3.3251 + gbMemoryMap[0x06] = &gbRom[0x6000]; 3.3252 + gbMemoryMap[0x07] = &gbRom[0x7000]; 3.3253 + if (gbCgbMode) 3.3254 + { 3.3255 + gbMemoryMap[0x08] = &gbVram[0x0000]; 3.3256 + gbMemoryMap[0x09] = &gbVram[0x1000]; 3.3257 + gbMemoryMap[0x0a] = &gbMemory[0xa000]; 3.3258 + gbMemoryMap[0x0b] = &gbMemory[0xb000]; 3.3259 + gbMemoryMap[0x0c] = &gbMemory[0xc000]; 3.3260 + gbMemoryMap[0x0d] = &gbWram[0x1000]; 3.3261 + gbMemoryMap[0x0e] = &gbMemory[0xe000]; 3.3262 + gbMemoryMap[0x0f] = &gbMemory[0xf000]; 3.3263 + } 3.3264 + else 3.3265 + { 3.3266 + gbMemoryMap[0x08] = &gbMemory[0x8000]; 3.3267 + gbMemoryMap[0x09] = &gbMemory[0x9000]; 3.3268 + gbMemoryMap[0x0a] = &gbMemory[0xa000]; 3.3269 + gbMemoryMap[0x0b] = &gbMemory[0xb000]; 3.3270 + gbMemoryMap[0x0c] = &gbMemory[0xc000]; 3.3271 + gbMemoryMap[0x0d] = &gbMemory[0xd000]; 3.3272 + gbMemoryMap[0x0e] = &gbMemory[0xe000]; 3.3273 + gbMemoryMap[0x0f] = &gbMemory[0xf000]; 3.3274 + } 3.3275 + 3.3276 + if (gbRam) 3.3277 + { 3.3278 + gbMemoryMap[0x0a] = &gbRam[0x0000]; 3.3279 + gbMemoryMap[0x0b] = &gbRam[0x1000]; 3.3280 + } 3.3281 + 3.3282 + gbSoundReset(); 3.3283 + 3.3284 + systemResetSensor(); 3.3285 + 3.3286 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.3287 + 3.3288 + gbLastTime = systemGetClock(); 3.3289 + gbFrameCount = 0; 3.3290 + 3.3291 + systemRefreshScreen(); 3.3292 } 3.3293 3.3294 void gbWriteSaveMBC1(const char *name) 3.3295 { 3.3296 - FILE *gzFile = fopen(name, "wb"); 3.3297 - 3.3298 - if (gzFile == NULL) 3.3299 - { 3.3300 - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3301 - return; 3.3302 - } 3.3303 - 3.3304 - fwrite(gbRam, 3.3305 - 1, 3.3306 - gbRamSize, 3.3307 - gzFile); 3.3308 - 3.3309 - fclose(gzFile); 3.3310 + FILE *gzFile = fopen(name, "wb"); 3.3311 + 3.3312 + if (gzFile == NULL) 3.3313 + { 3.3314 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3315 + return; 3.3316 + } 3.3317 + 3.3318 + fwrite(gbRam, 3.3319 + 1, 3.3320 + gbRamSize, 3.3321 + gzFile); 3.3322 + 3.3323 + fclose(gzFile); 3.3324 } 3.3325 3.3326 void gbWriteSaveMBC2(const char *name) 3.3327 { 3.3328 - FILE *file = fopen(name, "wb"); 3.3329 - 3.3330 - if (file == NULL) 3.3331 - { 3.3332 - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3333 - return; 3.3334 - } 3.3335 - 3.3336 - fwrite(&gbMemory[0xa000], 3.3337 - 1, 3.3338 - 256, 3.3339 - file); 3.3340 - 3.3341 - fclose(file); 3.3342 + FILE *file = fopen(name, "wb"); 3.3343 + 3.3344 + if (file == NULL) 3.3345 + { 3.3346 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3347 + return; 3.3348 + } 3.3349 + 3.3350 + fwrite(&gbMemory[0xa000], 3.3351 + 1, 3.3352 + 256, 3.3353 + file); 3.3354 + 3.3355 + fclose(file); 3.3356 } 3.3357 3.3358 void gbWriteSaveMBC3(const char *name, bool extendedSave) 3.3359 { 3.3360 - FILE *gzFile = fopen(name, "wb"); 3.3361 - 3.3362 - if (gzFile == NULL) 3.3363 - { 3.3364 - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3365 - return; 3.3366 - } 3.3367 - 3.3368 - fwrite(gbRam, 3.3369 - 1, 3.3370 - gbRamSize, 3.3371 - gzFile); 3.3372 - 3.3373 - if (extendedSave) 3.3374 - { 3.3375 - //assert(sizeof(time_t) == 4); 3.3376 - fwrite(&gbDataMBC3.mapperSeconds, 3.3377 - 1, 3.3378 - 10 * sizeof(int32) + /*sizeof(time_t)*/4, 3.3379 - gzFile); 3.3380 - } 3.3381 - 3.3382 - fclose(gzFile); 3.3383 + FILE *gzFile = fopen(name, "wb"); 3.3384 + 3.3385 + if (gzFile == NULL) 3.3386 + { 3.3387 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3388 + return; 3.3389 + } 3.3390 + 3.3391 + fwrite(gbRam, 3.3392 + 1, 3.3393 + gbRamSize, 3.3394 + gzFile); 3.3395 + 3.3396 + if (extendedSave) 3.3397 + { 3.3398 + //assert(sizeof(time_t) == 4); 3.3399 + fwrite(&gbDataMBC3.mapperSeconds, 3.3400 + 1, 3.3401 + 10 * sizeof(int32) + /*sizeof(time_t)*/4, 3.3402 + gzFile); 3.3403 + } 3.3404 + 3.3405 + fclose(gzFile); 3.3406 } 3.3407 3.3408 void gbWriteSaveMBC5(const char *name) 3.3409 { 3.3410 - FILE *gzFile = fopen(name, "wb"); 3.3411 - 3.3412 - if (gzFile == NULL) 3.3413 - { 3.3414 - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3415 - return; 3.3416 - } 3.3417 - 3.3418 - fwrite(gbRam, 3.3419 - 1, 3.3420 - gbRamSize, 3.3421 - gzFile); 3.3422 - 3.3423 - fclose(gzFile); 3.3424 + FILE *gzFile = fopen(name, "wb"); 3.3425 + 3.3426 + if (gzFile == NULL) 3.3427 + { 3.3428 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3429 + return; 3.3430 + } 3.3431 + 3.3432 + fwrite(gbRam, 3.3433 + 1, 3.3434 + gbRamSize, 3.3435 + gzFile); 3.3436 + 3.3437 + fclose(gzFile); 3.3438 } 3.3439 3.3440 void gbWriteSaveMBC7(const char *name) 3.3441 { 3.3442 - FILE *file = fopen(name, "wb"); 3.3443 - 3.3444 - if (file == NULL) 3.3445 - { 3.3446 - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3447 - return; 3.3448 - } 3.3449 - 3.3450 - fwrite(&gbMemory[0xa000], 3.3451 - 1, 3.3452 - 256, 3.3453 - file); 3.3454 - 3.3455 - fclose(file); 3.3456 + FILE *file = fopen(name, "wb"); 3.3457 + 3.3458 + if (file == NULL) 3.3459 + { 3.3460 + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name); 3.3461 + return; 3.3462 + } 3.3463 + 3.3464 + fwrite(&gbMemory[0xa000], 3.3465 + 1, 3.3466 + 256, 3.3467 + file); 3.3468 + 3.3469 + fclose(file); 3.3470 } 3.3471 3.3472 bool gbReadSaveMBC1(const char *name) 3.3473 { 3.3474 - gzFile gzFile = gzopen(name, "rb"); 3.3475 - 3.3476 - if (gzFile == NULL) 3.3477 - { 3.3478 - return false; 3.3479 - } 3.3480 - 3.3481 - int read = gzread(gzFile, 3.3482 - gbRam, 3.3483 - gbRamSize); 3.3484 - 3.3485 - if (read != gbRamSize) 3.3486 - { 3.3487 - systemMessage(MSG_FAILED_TO_READ_SGM, N_("Failed to read complete save game %s (%d)"), name, read); 3.3488 - gzclose(gzFile); 3.3489 - return false; 3.3490 - } 3.3491 - 3.3492 - gzclose(gzFile); 3.3493 - return true; 3.3494 + gzFile gzFile = gzopen(name, "rb"); 3.3495 + 3.3496 + if (gzFile == NULL) 3.3497 + { 3.3498 + return false; 3.3499 + } 3.3500 + 3.3501 + int read = gzread(gzFile, 3.3502 + gbRam, 3.3503 + gbRamSize); 3.3504 + 3.3505 + if (read != gbRamSize) 3.3506 + { 3.3507 + systemMessage(MSG_FAILED_TO_READ_SGM, N_("Failed to read complete save game %s (%d)"), name, read); 3.3508 + gzclose(gzFile); 3.3509 + return false; 3.3510 + } 3.3511 + 3.3512 + gzclose(gzFile); 3.3513 + return true; 3.3514 } 3.3515 3.3516 bool gbReadSaveMBC2(const char *name) 3.3517 { 3.3518 - FILE *file = fopen(name, "rb"); 3.3519 - 3.3520 - if (file == NULL) 3.3521 - { 3.3522 - return false; 3.3523 - } 3.3524 - 3.3525 - int read = fread(&gbMemory[0xa000], 3.3526 - 1, 3.3527 - 256, 3.3528 - file); 3.3529 - 3.3530 - if (read != 256) 3.3531 - { 3.3532 - systemMessage(MSG_FAILED_TO_READ_SGM, 3.3533 - N_("Failed to read complete save game %s (%d)"), name, read); 3.3534 - fclose(file); 3.3535 - return false; 3.3536 - } 3.3537 - 3.3538 - fclose(file); 3.3539 - return true; 3.3540 + FILE *file = fopen(name, "rb"); 3.3541 + 3.3542 + if (file == NULL) 3.3543 + { 3.3544 + return false; 3.3545 + } 3.3546 + 3.3547 + int read = fread(&gbMemory[0xa000], 3.3548 + 1, 3.3549 + 256, 3.3550 + file); 3.3551 + 3.3552 + if (read != 256) 3.3553 + { 3.3554 + systemMessage(MSG_FAILED_TO_READ_SGM, 3.3555 + N_("Failed to read complete save game %s (%d)"), name, read); 3.3556 + fclose(file); 3.3557 + return false; 3.3558 + } 3.3559 + 3.3560 + fclose(file); 3.3561 + return true; 3.3562 } 3.3563 3.3564 bool gbReadSaveMBC3(const char *name) 3.3565 { 3.3566 - gzFile gzFile = gzopen(name, "rb"); 3.3567 - 3.3568 - if (gzFile == NULL) 3.3569 + gzFile gzFile = gzopen(name, "rb"); 3.3570 + 3.3571 + if (gzFile == NULL) 3.3572 + { 3.3573 + return false; 3.3574 + } 3.3575 + 3.3576 + int read = gzread(gzFile, 3.3577 + gbRam, 3.3578 + gbRamSize); 3.3579 + 3.3580 + bool res = true; 3.3581 + 3.3582 + if (read != gbRamSize) 3.3583 + { 3.3584 + systemMessage(MSG_FAILED_TO_READ_SGM, 3.3585 + N_("Failed to read complete save game %s (%d)"), name, read); 3.3586 + } 3.3587 + else 3.3588 + { 3.3589 + //assert(sizeof(time_t) == 4); 3.3590 + read = gzread(gzFile, 3.3591 + &gbDataMBC3.mapperSeconds, 3.3592 + sizeof(int32) * 10 + /*sizeof(time_t)*/4); 3.3593 + 3.3594 + if (read != (sizeof(int32) * 10 + /*sizeof(time_t)*/4) && read != 0) 3.3595 { 3.3596 - return false; 3.3597 + systemMessage(MSG_FAILED_TO_READ_RTC, 3.3598 + N_("Failed to read RTC from save game %s (continuing)"), 3.3599 + name); 3.3600 + res = false; 3.3601 } 3.3602 - 3.3603 - int read = gzread(gzFile, 3.3604 - gbRam, 3.3605 - gbRamSize); 3.3606 - 3.3607 - bool res = true; 3.3608 - 3.3609 - if (read != gbRamSize) 3.3610 - { 3.3611 - systemMessage(MSG_FAILED_TO_READ_SGM, 3.3612 - N_("Failed to read complete save game %s (%d)"), name, read); 3.3613 - } 3.3614 - else 3.3615 - { 3.3616 - //assert(sizeof(time_t) == 4); 3.3617 - read = gzread(gzFile, 3.3618 - &gbDataMBC3.mapperSeconds, 3.3619 - sizeof(int32) * 10 + /*sizeof(time_t)*/4); 3.3620 - 3.3621 - if (read != (sizeof(int32) * 10 + /*sizeof(time_t)*/4) && read != 0) 3.3622 - { 3.3623 - systemMessage(MSG_FAILED_TO_READ_RTC, 3.3624 - N_("Failed to read RTC from save game %s (continuing)"), 3.3625 - name); 3.3626 - res = false; 3.3627 - } 3.3628 - } 3.3629 - 3.3630 - gzclose(gzFile); 3.3631 - return res; 3.3632 + } 3.3633 + 3.3634 + gzclose(gzFile); 3.3635 + return res; 3.3636 } 3.3637 3.3638 bool gbReadSaveMBC5(const char *name) 3.3639 { 3.3640 - gzFile gzFile = gzopen(name, "rb"); 3.3641 - 3.3642 - if (gzFile == NULL) 3.3643 - { 3.3644 - return false; 3.3645 - } 3.3646 - 3.3647 - int read = gzread(gzFile, 3.3648 - gbRam, 3.3649 - gbRamSize); 3.3650 - 3.3651 - if (read != gbRamSize) 3.3652 - { 3.3653 - systemMessage(MSG_FAILED_TO_READ_SGM, 3.3654 - N_("Failed to read complete save game %s (%d)"), name, read); 3.3655 - gzclose(gzFile); 3.3656 - return false; 3.3657 - } 3.3658 - 3.3659 - gzclose(gzFile); 3.3660 - return true; 3.3661 + gzFile gzFile = gzopen(name, "rb"); 3.3662 + 3.3663 + if (gzFile == NULL) 3.3664 + { 3.3665 + return false; 3.3666 + } 3.3667 + 3.3668 + int read = gzread(gzFile, 3.3669 + gbRam, 3.3670 + gbRamSize); 3.3671 + 3.3672 + if (read != gbRamSize) 3.3673 + { 3.3674 + systemMessage(MSG_FAILED_TO_READ_SGM, 3.3675 + N_("Failed to read complete save game %s (%d)"), name, read); 3.3676 + gzclose(gzFile); 3.3677 + return false; 3.3678 + } 3.3679 + 3.3680 + gzclose(gzFile); 3.3681 + return true; 3.3682 } 3.3683 3.3684 bool gbReadSaveMBC7(const char *name) 3.3685 { 3.3686 - FILE *file = fopen(name, "rb"); 3.3687 - 3.3688 - if (file == NULL) 3.3689 - { 3.3690 - return false; 3.3691 - } 3.3692 - 3.3693 - int read = fread(&gbMemory[0xa000], 3.3694 - 1, 3.3695 - 256, 3.3696 - file); 3.3697 - 3.3698 - if (read != 256) 3.3699 - { 3.3700 - systemMessage(MSG_FAILED_TO_READ_SGM, 3.3701 - N_("Failed to read complete save game %s (%d)"), name, read); 3.3702 - fclose(file); 3.3703 - return false; 3.3704 - } 3.3705 - 3.3706 - fclose(file); 3.3707 - return true; 3.3708 + FILE *file = fopen(name, "rb"); 3.3709 + 3.3710 + if (file == NULL) 3.3711 + { 3.3712 + return false; 3.3713 + } 3.3714 + 3.3715 + int read = fread(&gbMemory[0xa000], 3.3716 + 1, 3.3717 + 256, 3.3718 + file); 3.3719 + 3.3720 + if (read != 256) 3.3721 + { 3.3722 + systemMessage(MSG_FAILED_TO_READ_SGM, 3.3723 + N_("Failed to read complete save game %s (%d)"), name, read); 3.3724 + fclose(file); 3.3725 + return false; 3.3726 + } 3.3727 + 3.3728 + fclose(file); 3.3729 + return true; 3.3730 } 3.3731 3.3732 #if 0 3.3733 bool gbLoadBIOS(const char *biosFileName, bool useBiosFile) 3.3734 { 3.3735 - useBios = false; 3.3736 - if (useBiosFile) 3.3737 + useBios = false; 3.3738 + if (useBiosFile) 3.3739 + { 3.3740 + useBios = utilLoadBIOS(bios, biosFileName, gbEmulatorType); 3.3741 + if (!useBios) 3.3742 { 3.3743 - useBios = utilLoadBIOS(bios, biosFileName, gbEmulatorType); 3.3744 - if (!useBios) 3.3745 - { 3.3746 - systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file")); 3.3747 - } 3.3748 + systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file")); 3.3749 } 3.3750 - return useBios; 3.3751 + } 3.3752 + return useBios; 3.3753 } 3.3754 #endif 3.3755 3.3756 void gbInit() 3.3757 { 3.3758 - gbGenFilter(); 3.3759 - gbSgbInit(); // calls gbSgbReset()... whatever 3.3760 - 3.3761 - gbMemory = (u8 *)malloc(65536 + 4); 3.3762 - memset(gbMemory, 0, 65536 + 4); 3.3763 - memset(gbPalette, 0, 2 * 128); 3.3764 - 3.3765 - // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel 3.3766 - origPix = (u8 *)calloc(1, 4 * 257 * 226 + 4); 3.3767 - pix = origPix + 4; 3.3768 - 3.3769 - gbLineBuffer = (u16 *)malloc(160 * sizeof(u16)); 3.3770 + gbGenFilter(); 3.3771 + gbSgbInit(); // calls gbSgbReset()... whatever 3.3772 + 3.3773 + gbMemory = (u8 *)malloc(65536 + 4); 3.3774 + memset(gbMemory, 0, 65536 + 4); 3.3775 + memset(gbPalette, 0, 2 * 128); 3.3776 + 3.3777 + // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel 3.3778 + origPix = (u8 *)calloc(1, 4 * 257 * 226 + 4); 3.3779 + pix = origPix + 4; 3.3780 + 3.3781 + gbLineBuffer = (u16 *)malloc(160 * sizeof(u16)); 3.3782 } 3.3783 3.3784 bool gbWriteBatteryFile(const char *file, bool extendedSave) 3.3785 { 3.3786 - if (gbBattery) 3.3787 - { 3.3788 - int type = gbRom[0x147]; 3.3789 - 3.3790 - switch (type) 3.3791 - { 3.3792 - case 0x03: 3.3793 - gbWriteSaveMBC1(file); 3.3794 - break; 3.3795 - case 0x06: 3.3796 - gbWriteSaveMBC2(file); 3.3797 - break; 3.3798 - case 0x0f: 3.3799 - case 0x10: 3.3800 - case 0x13: 3.3801 - gbWriteSaveMBC3(file, extendedSave); 3.3802 - break; 3.3803 - case 0x1b: 3.3804 - case 0x1e: 3.3805 - gbWriteSaveMBC5(file); 3.3806 - break; 3.3807 - case 0x22: 3.3808 - gbWriteSaveMBC7(file); 3.3809 - break; 3.3810 - case 0xff: 3.3811 - gbWriteSaveMBC1(file); 3.3812 - break; 3.3813 - } 3.3814 - } 3.3815 - return true; 3.3816 -} 3.3817 - 3.3818 -bool gbWriteBatteryFile(const char *file) 3.3819 -{ 3.3820 - gbWriteBatteryFile(file, true); 3.3821 - return true; 3.3822 -} 3.3823 - 3.3824 -bool gbWriteBatteryToStream(gzFile gzfile) 3.3825 -{ 3.3826 - // the GB save code is ugly, so rather than convert it all to use gzFiles, just save it to a temp file... 3.3827 -#define TEMP_SAVE_FNAME ("tempvbawrite.sav") 3.3828 - bool retVal = gbWriteBatteryFile(TEMP_SAVE_FNAME, true); 3.3829 - 3.3830 - // ...open the temp file and figure out its size... 3.3831 - FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "rb"); 3.3832 - if (fileTemp == NULL) 3.3833 - return false; 3.3834 - fseek(fileTemp, 0, SEEK_END); 3.3835 - int len = (int) ftell(fileTemp); 3.3836 - 3.3837 - // ...copy over the temp file... 3.3838 - char *temp = new char [len]; 3.3839 - fseek(fileTemp, 0, SEEK_SET); 3.3840 - if (fread(temp, len, 1, fileTemp) != 1) 3.3841 - { 3.3842 - delete [] temp; 3.3843 - fclose(fileTemp); 3.3844 - return false; 3.3845 - } 3.3846 - fclose(fileTemp); 3.3847 - utilGzWrite(gzfile, temp, len); 3.3848 - delete [] temp; 3.3849 - 3.3850 - // ... and delete the temp file 3.3851 - remove(TEMP_SAVE_FNAME); 3.3852 -#undef TEMP_SAVE_FNAME 3.3853 - 3.3854 - return retVal; 3.3855 -} 3.3856 - 3.3857 -bool gbReadBatteryFile(const char *file) 3.3858 -{ 3.3859 - bool res = false; 3.3860 - if (gbBattery) 3.3861 - { 3.3862 - int type = gbRom[0x147]; 3.3863 - 3.3864 - switch (type) 3.3865 - { 3.3866 - case 0x03: 3.3867 - res = gbReadSaveMBC1(file); 3.3868 - break; 3.3869 - case 0x06: 3.3870 - res = gbReadSaveMBC2(file); 3.3871 - break; 3.3872 - case 0x0f: 3.3873 - case 0x10: 3.3874 - case 0x13: 3.3875 - if (!gbReadSaveMBC3(file)) 3.3876 - { 3.3877 - struct tm *lt; 3.3878 - time_t tmp; //Small kludge to get it working on some systems where time_t has size 8. 3.3879 - 3.3880 - if (VBAMovieActive() || VBAMovieLoading()) 3.3881 - { 3.3882 - gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter() / 60; 3.3883 - lt = gmtime(&tmp); 3.3884 - gbDataMBC3.mapperLastTime=(u32)tmp; 3.3885 - } 3.3886 - else 3.3887 - { 3.3888 - time(&tmp); 3.3889 - gbDataMBC3.mapperLastTime=(u32)tmp; 3.3890 - lt = localtime(&tmp); 3.3891 - } 3.3892 - systemScreenMessage(ctime(&tmp), 4); 3.3893 - gbDataMBC3.mapperLastTime=(u32)tmp; 3.3894 - 3.3895 - gbDataMBC3.mapperSeconds = lt->tm_sec; 3.3896 - gbDataMBC3.mapperMinutes = lt->tm_min; 3.3897 - gbDataMBC3.mapperHours = lt->tm_hour; 3.3898 - gbDataMBC3.mapperDays = lt->tm_yday & 255; 3.3899 - gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | 3.3900 - (lt->tm_yday > 255 ? 1 : 0); 3.3901 - res = false; 3.3902 - break; 3.3903 - } 3.3904 - time_t tmp; 3.3905 - systemScreenMessage(ctime(&tmp), 4); 3.3906 - gbDataMBC3.mapperLastTime=(u32)tmp; 3.3907 - res = true; 3.3908 - break; 3.3909 - case 0x1b: 3.3910 - case 0x1e: 3.3911 - res = gbReadSaveMBC5(file); 3.3912 - break; 3.3913 - case 0x22: 3.3914 - res = gbReadSaveMBC7(file); 3.3915 - case 0xff: 3.3916 - res = gbReadSaveMBC1(file); 3.3917 - break; 3.3918 - } 3.3919 - } 3.3920 - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.3921 - return res; 3.3922 -} 3.3923 - 3.3924 -bool gbReadBatteryFromStream(gzFile gzfile) 3.3925 -{ 3.3926 - // the GB save code is ugly, so rather than convert it all to use gzFiles, just copy it to temp RAM... 3.3927 -#define TEMP_SAVE_FNAME ("tempvbaread.sav") 3.3928 - int pos = gztell(gzfile); 3.3929 - int buflen = 1024; 3.3930 - // ...make a temp file and write it there... 3.3931 - FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "wb"); 3.3932 - if (fileTemp == NULL) 3.3933 - return false; 3.3934 - int gzDeflated; 3.3935 - char *temp = new char [buflen]; 3.3936 - while ((gzDeflated = utilGzRead(gzfile, temp, buflen)) != 0) 3.3937 - { 3.3938 - if (gzDeflated == -1 || fwrite(temp, gzDeflated, 1, fileTemp) != 1) 3.3939 - { 3.3940 - delete [] temp; 3.3941 - fclose(fileTemp); 3.3942 - gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that 3.3943 - // calls this right now does a seek afterwards so it doesn't matter for now, but it's 3.3944 - // still bad) 3.3945 - return false; 3.3946 - } 3.3947 - } 3.3948 - gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that calls this 3.3949 - // right now does a seek afterwards so it doesn't matter for now, but it's still bad) 3.3950 - fclose(fileTemp); 3.3951 - delete [] temp; 3.3952 - 3.3953 - // ... load from the temp file... 3.3954 - bool retVal = gbReadBatteryFile(TEMP_SAVE_FNAME); 3.3955 - 3.3956 - // ... and delete the temp file 3.3957 - remove(TEMP_SAVE_FNAME); 3.3958 -#undef TEMP_SAVE_FNAME 3.3959 - 3.3960 - return retVal; 3.3961 -} 3.3962 - 3.3963 -bool gbReadGSASnapshot(const char *fileName) 3.3964 -{ 3.3965 - FILE *file = fopen(fileName, "rb"); 3.3966 - 3.3967 - if (!file) 3.3968 - { 3.3969 - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); 3.3970 - return false; 3.3971 - } 3.3972 - 3.3973 - // long size = ftell(file); 3.3974 - fseek(file, 0x4, SEEK_SET); 3.3975 - char buffer[16]; 3.3976 - char buffer2[16]; 3.3977 - fread(buffer, 1, 15, file); 3.3978 - buffer[15] = 0; 3.3979 - memcpy(buffer2, &gbRom[0x134], 15); 3.3980 - buffer2[15] = 0; 3.3981 - if (memcmp(buffer, buffer2, 15)) 3.3982 - { 3.3983 - systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, 3.3984 - N_("Cannot import snapshot for %s. Current game is %s"), 3.3985 - buffer, 3.3986 - buffer2); 3.3987 - fclose(file); 3.3988 - return false; 3.3989 - } 3.3990 - fseek(file, 0x13, SEEK_SET); 3.3991 - int read = 0; 3.3992 - int toRead = 0; 3.3993 - switch (gbRom[0x147]) 3.3994 + if (gbBattery) 3.3995 + { 3.3996 + int type = gbRom[0x147]; 3.3997 + 3.3998 + switch (type) 3.3999 { 3.4000 case 0x03: 3.4001 + gbWriteSaveMBC1(file); 3.4002 + break; 3.4003 + case 0x06: 3.4004 + gbWriteSaveMBC2(file); 3.4005 + break; 3.4006 case 0x0f: 3.4007 case 0x10: 3.4008 case 0x13: 3.4009 + gbWriteSaveMBC3(file, extendedSave); 3.4010 + break; 3.4011 case 0x1b: 3.4012 case 0x1e: 3.4013 + gbWriteSaveMBC5(file); 3.4014 + break; 3.4015 + case 0x22: 3.4016 + gbWriteSaveMBC7(file); 3.4017 + break; 3.4018 case 0xff: 3.4019 - read = fread(gbRam, 1, gbRamSize, file); 3.4020 - toRead = gbRamSize; 3.4021 - break; 3.4022 + gbWriteSaveMBC1(file); 3.4023 + break; 3.4024 + } 3.4025 + } 3.4026 + return true; 3.4027 +} 3.4028 + 3.4029 +bool gbWriteBatteryFile(const char *file) 3.4030 +{ 3.4031 + gbWriteBatteryFile(file, true); 3.4032 + return true; 3.4033 +} 3.4034 + 3.4035 +bool gbWriteBatteryToStream(gzFile gzfile) 3.4036 +{ 3.4037 + // the GB save code is ugly, so rather than convert it all to use gzFiles, just save it to a temp file... 3.4038 +#define TEMP_SAVE_FNAME ("tempvbawrite.sav") 3.4039 + bool retVal = gbWriteBatteryFile(TEMP_SAVE_FNAME, true); 3.4040 + 3.4041 + // ...open the temp file and figure out its size... 3.4042 + FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "rb"); 3.4043 + if (fileTemp == NULL) 3.4044 + return false; 3.4045 + fseek(fileTemp, 0, SEEK_END); 3.4046 + int len = (int) ftell(fileTemp); 3.4047 + 3.4048 + // ...copy over the temp file... 3.4049 + char *temp = new char [len]; 3.4050 + fseek(fileTemp, 0, SEEK_SET); 3.4051 + if (fread(temp, len, 1, fileTemp) != 1) 3.4052 + { 3.4053 + delete [] temp; 3.4054 + fclose(fileTemp); 3.4055 + return false; 3.4056 + } 3.4057 + fclose(fileTemp); 3.4058 + utilGzWrite(gzfile, temp, len); 3.4059 + delete [] temp; 3.4060 + 3.4061 + // ... and delete the temp file 3.4062 + remove(TEMP_SAVE_FNAME); 3.4063 +#undef TEMP_SAVE_FNAME 3.4064 + 3.4065 + return retVal; 3.4066 +} 3.4067 + 3.4068 +bool gbReadBatteryFile(const char *file) 3.4069 +{ 3.4070 + bool res = false; 3.4071 + if (gbBattery) 3.4072 + { 3.4073 + int type = gbRom[0x147]; 3.4074 + 3.4075 + switch (type) 3.4076 + { 3.4077 + case 0x03: 3.4078 + res = gbReadSaveMBC1(file); 3.4079 + break; 3.4080 case 0x06: 3.4081 + res = gbReadSaveMBC2(file); 3.4082 + break; 3.4083 + case 0x0f: 3.4084 + case 0x10: 3.4085 + case 0x13: 3.4086 + if (!gbReadSaveMBC3(file)) 3.4087 + { 3.4088 + struct tm *lt; 3.4089 + time_t tmp; //Small kludge to get it working on some systems where time_t has size 8. 3.4090 + 3.4091 + if (VBAMovieActive() || VBAMovieLoading()) 3.4092 + { 3.4093 + gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter() / 60; 3.4094 + lt = gmtime(&tmp); 3.4095 + gbDataMBC3.mapperLastTime=(u32)tmp; 3.4096 + } 3.4097 + else 3.4098 + { 3.4099 + time(&tmp); 3.4100 + gbDataMBC3.mapperLastTime=(u32)tmp; 3.4101 + lt = localtime(&tmp); 3.4102 + } 3.4103 + systemScreenMessage(ctime(&tmp), 4); 3.4104 + gbDataMBC3.mapperLastTime=(u32)tmp; 3.4105 + 3.4106 + gbDataMBC3.mapperSeconds = lt->tm_sec; 3.4107 + gbDataMBC3.mapperMinutes = lt->tm_min; 3.4108 + gbDataMBC3.mapperHours = lt->tm_hour; 3.4109 + gbDataMBC3.mapperDays = lt->tm_yday & 255; 3.4110 + gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | 3.4111 + (lt->tm_yday > 255 ? 1 : 0); 3.4112 + res = false; 3.4113 + break; 3.4114 + } 3.4115 + time_t tmp; 3.4116 + systemScreenMessage(ctime(&tmp), 4); 3.4117 + gbDataMBC3.mapperLastTime=(u32)tmp; 3.4118 + res = true; 3.4119 + break; 3.4120 + case 0x1b: 3.4121 + case 0x1e: 3.4122 + res = gbReadSaveMBC5(file); 3.4123 + break; 3.4124 case 0x22: 3.4125 - read = fread(&gbMemory[0xa000], 1, 256, file); 3.4126 - toRead = 256; 3.4127 - break; 3.4128 - default: 3.4129 - systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, 3.4130 - N_("Unsupported snapshot file %s"), 3.4131 - fileName); 3.4132 - fclose(file); 3.4133 - return false; 3.4134 + res = gbReadSaveMBC7(file); 3.4135 + case 0xff: 3.4136 + res = gbReadSaveMBC1(file); 3.4137 + break; 3.4138 } 3.4139 - fclose(file); 3.4140 - gbReset(); 3.4141 - return true; 3.4142 + } 3.4143 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.4144 + return res; 3.4145 } 3.4146 3.4147 +bool gbReadBatteryFromStream(gzFile gzfile) 3.4148 +{ 3.4149 + // the GB save code is ugly, so rather than convert it all to use gzFiles, just copy it to temp RAM... 3.4150 +#define TEMP_SAVE_FNAME ("tempvbaread.sav") 3.4151 + int pos = gztell(gzfile); 3.4152 + int buflen = 1024; 3.4153 + // ...make a temp file and write it there... 3.4154 + FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "wb"); 3.4155 + if (fileTemp == NULL) 3.4156 + return false; 3.4157 + int gzDeflated; 3.4158 + char *temp = new char [buflen]; 3.4159 + while ((gzDeflated = utilGzRead(gzfile, temp, buflen)) != 0) 3.4160 + { 3.4161 + if (gzDeflated == -1 || fwrite(temp, gzDeflated, 1, fileTemp) != 1) 3.4162 + { 3.4163 + delete [] temp; 3.4164 + fclose(fileTemp); 3.4165 + gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that 3.4166 + // calls this right now does a seek afterwards so it doesn't matter for now, but it's 3.4167 + // still bad) 3.4168 + return false; 3.4169 + } 3.4170 + } 3.4171 + gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that calls this 3.4172 + // right now does a seek afterwards so it doesn't matter for now, but it's still bad) 3.4173 + fclose(fileTemp); 3.4174 + delete [] temp; 3.4175 + 3.4176 + // ... load from the temp file... 3.4177 + bool retVal = gbReadBatteryFile(TEMP_SAVE_FNAME); 3.4178 + 3.4179 + // ... and delete the temp file 3.4180 + remove(TEMP_SAVE_FNAME); 3.4181 +#undef TEMP_SAVE_FNAME 3.4182 + 3.4183 + return retVal; 3.4184 +} 3.4185 + 3.4186 +bool gbReadGSASnapshot(const char *fileName) 3.4187 +{ 3.4188 + FILE *file = fopen(fileName, "rb"); 3.4189 + 3.4190 + if (!file) 3.4191 + { 3.4192 + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName); 3.4193 + return false; 3.4194 + } 3.4195 + 3.4196 + // long size = ftell(file); 3.4197 + fseek(file, 0x4, SEEK_SET); 3.4198 + char buffer[16]; 3.4199 + char buffer2[16]; 3.4200 + fread(buffer, 1, 15, file); 3.4201 + buffer[15] = 0; 3.4202 + memcpy(buffer2, &gbRom[0x134], 15); 3.4203 + buffer2[15] = 0; 3.4204 + if (memcmp(buffer, buffer2, 15)) 3.4205 + { 3.4206 + systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR, 3.4207 + N_("Cannot import snapshot for %s. Current game is %s"), 3.4208 + buffer, 3.4209 + buffer2); 3.4210 + fclose(file); 3.4211 + return false; 3.4212 + } 3.4213 + fseek(file, 0x13, SEEK_SET); 3.4214 + int read = 0; 3.4215 + int toRead = 0; 3.4216 + switch (gbRom[0x147]) 3.4217 + { 3.4218 + case 0x03: 3.4219 + case 0x0f: 3.4220 + case 0x10: 3.4221 + case 0x13: 3.4222 + case 0x1b: 3.4223 + case 0x1e: 3.4224 + case 0xff: 3.4225 + read = fread(gbRam, 1, gbRamSize, file); 3.4226 + toRead = gbRamSize; 3.4227 + break; 3.4228 + case 0x06: 3.4229 + case 0x22: 3.4230 + read = fread(&gbMemory[0xa000], 1, 256, file); 3.4231 + toRead = 256; 3.4232 + break; 3.4233 + default: 3.4234 + systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE, 3.4235 + N_("Unsupported snapshot file %s"), 3.4236 + fileName); 3.4237 + fclose(file); 3.4238 + return false; 3.4239 + } 3.4240 + fclose(file); 3.4241 + gbReset(); 3.4242 + return true; 3.4243 +} 3.4244 + 3.4245 variable_desc gbSaveGameStruct[] = 3.4246 -{ 3.4247 - { &PC.W, sizeof(u16) }, 3.4248 - { &SP.W, sizeof(u16) }, 3.4249 - { &AF.W, sizeof(u16) }, 3.4250 - { &BC.W, sizeof(u16) }, 3.4251 - { &DE.W, sizeof(u16) }, 3.4252 - { &HL.W, sizeof(u16) }, 3.4253 - { &IFF, sizeof(u8) }, 3.4254 - { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int32) }, 3.4255 - { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int32) }, 3.4256 - { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int32) }, 3.4257 - { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int32) }, 3.4258 - { &GBDIV_CLOCK_TICKS, sizeof(int32) }, 3.4259 - { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int32) }, 3.4260 - { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int32) }, 3.4261 - { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int32) }, 3.4262 - { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int32) }, 3.4263 - { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int32) }, 3.4264 - { &GBSERIAL_CLOCK_TICKS, sizeof(int32) }, 3.4265 - { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int32) }, 3.4266 - { &gbDivTicks, sizeof(int32) }, 3.4267 - { &gbLcdMode, sizeof(int32) }, 3.4268 - { &gbLcdTicks, sizeof(int32) }, 3.4269 - { &gbLcdLYIncrementTicks, sizeof(int32) }, 3.4270 - { &gbTimerTicks, sizeof(int32) }, 3.4271 - { &gbTimerClockTicks, sizeof(int32) }, 3.4272 - { &gbSerialTicks, sizeof(int32) }, 3.4273 - { &gbSerialBits, sizeof(int32) }, 3.4274 - { &gbInterrupt, sizeof(int32) }, 3.4275 - { &gbInterruptWait, sizeof(int32) }, 3.4276 - { &gbSynchronizeTicks, sizeof(int32) }, 3.4277 - { &gbTimerOn, sizeof(int32) }, 3.4278 - { &gbTimerMode, sizeof(int32) }, 3.4279 - { &gbSerialOn, sizeof(int32) }, 3.4280 - { &gbWindowLine, sizeof(int32) }, 3.4281 - { &gbCgbMode, sizeof(int32) }, 3.4282 - { &gbVramBank, sizeof(int32) }, 3.4283 - { &gbWramBank, sizeof(int32) }, 3.4284 - { &gbHdmaSource, sizeof(int32) }, 3.4285 - { &gbHdmaDestination, sizeof(int32) }, 3.4286 - { &gbHdmaBytes, sizeof(int32) }, 3.4287 - { &gbHdmaOn, sizeof(int32) }, 3.4288 - { &gbSpeed, sizeof(int32) }, 3.4289 - { &gbSgbMode, sizeof(int32) }, 3.4290 - { ®ister_DIV, sizeof(u8) }, 3.4291 - { ®ister_TIMA, sizeof(u8) }, 3.4292 - { ®ister_TMA, sizeof(u8) }, 3.4293 - { ®ister_TAC, sizeof(u8) }, 3.4294 - { ®ister_IF, sizeof(u8) }, 3.4295 - { ®ister_LCDC, sizeof(u8) }, 3.4296 - { ®ister_STAT, sizeof(u8) }, 3.4297 - { ®ister_SCY, sizeof(u8) }, 3.4298 - { ®ister_SCX, sizeof(u8) }, 3.4299 - { ®ister_LY, sizeof(u8) }, 3.4300 - { ®ister_LYC, sizeof(u8) }, 3.4301 - { ®ister_DMA, sizeof(u8) }, 3.4302 - { ®ister_WY, sizeof(u8) }, 3.4303 - { ®ister_WX, sizeof(u8) }, 3.4304 - { ®ister_VBK, sizeof(u8) }, 3.4305 - { ®ister_HDMA1, sizeof(u8) }, 3.4306 - { ®ister_HDMA2, sizeof(u8) }, 3.4307 - { ®ister_HDMA3, sizeof(u8) }, 3.4308 - { ®ister_HDMA4, sizeof(u8) }, 3.4309 - { ®ister_HDMA5, sizeof(u8) }, 3.4310 - { ®ister_SVBK, sizeof(u8) }, 3.4311 - { ®ister_IE, sizeof(u8) }, 3.4312 - { &gbBgp[0], sizeof(u8) }, 3.4313 - { &gbBgp[1], sizeof(u8) }, 3.4314 - { &gbBgp[2], sizeof(u8) }, 3.4315 - { &gbBgp[3], sizeof(u8) }, 3.4316 - { &gbObp0[0], sizeof(u8) }, 3.4317 - { &gbObp0[1], sizeof(u8) }, 3.4318 - { &gbObp0[2], sizeof(u8) }, 3.4319 - { &gbObp0[3], sizeof(u8) }, 3.4320 - { &gbObp1[0], sizeof(u8) }, 3.4321 - { &gbObp1[1], sizeof(u8) }, 3.4322 - { &gbObp1[2], sizeof(u8) }, 3.4323 - { &gbObp1[3], sizeof(u8) }, 3.4324 - { NULL, 0 } 3.4325 -}; 3.4326 + { 3.4327 + { &PC.W, sizeof(u16) }, 3.4328 + { &SP.W, sizeof(u16) }, 3.4329 + { &AF.W, sizeof(u16) }, 3.4330 + { &BC.W, sizeof(u16) }, 3.4331 + { &DE.W, sizeof(u16) }, 3.4332 + { &HL.W, sizeof(u16) }, 3.4333 + { &IFF, sizeof(u8) }, 3.4334 + { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int32) }, 3.4335 + { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int32) }, 3.4336 + { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int32) }, 3.4337 + { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int32) }, 3.4338 + { &GBDIV_CLOCK_TICKS, sizeof(int32) }, 3.4339 + { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int32) }, 3.4340 + { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int32) }, 3.4341 + { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int32) }, 3.4342 + { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int32) }, 3.4343 + { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int32) }, 3.4344 + { &GBSERIAL_CLOCK_TICKS, sizeof(int32) }, 3.4345 + { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int32) }, 3.4346 + { &gbDivTicks, sizeof(int32) }, 3.4347 + { &gbLcdMode, sizeof(int32) }, 3.4348 + { &gbLcdTicks, sizeof(int32) }, 3.4349 + { &gbLcdLYIncrementTicks, sizeof(int32) }, 3.4350 + { &gbTimerTicks, sizeof(int32) }, 3.4351 + { &gbTimerClockTicks, sizeof(int32) }, 3.4352 + { &gbSerialTicks, sizeof(int32) }, 3.4353 + { &gbSerialBits, sizeof(int32) }, 3.4354 + { &gbInterrupt, sizeof(int32) }, 3.4355 + { &gbInterruptWait, sizeof(int32) }, 3.4356 + { &gbSynchronizeTicks, sizeof(int32) }, 3.4357 + { &gbTimerOn, sizeof(int32) }, 3.4358 + { &gbTimerMode, sizeof(int32) }, 3.4359 + { &gbSerialOn, sizeof(int32) }, 3.4360 + { &gbWindowLine, sizeof(int32) }, 3.4361 + { &gbCgbMode, sizeof(int32) }, 3.4362 + { &gbVramBank, sizeof(int32) }, 3.4363 + { &gbWramBank, sizeof(int32) }, 3.4364 + { &gbHdmaSource, sizeof(int32) }, 3.4365 + { &gbHdmaDestination, sizeof(int32) }, 3.4366 + { &gbHdmaBytes, sizeof(int32) }, 3.4367 + { &gbHdmaOn, sizeof(int32) }, 3.4368 + { &gbSpeed, sizeof(int32) }, 3.4369 + { &gbSgbMode, sizeof(int32) }, 3.4370 + { ®ister_DIV, sizeof(u8) }, 3.4371 + { ®ister_TIMA, sizeof(u8) }, 3.4372 + { ®ister_TMA, sizeof(u8) }, 3.4373 + { ®ister_TAC, sizeof(u8) }, 3.4374 + { ®ister_IF, sizeof(u8) }, 3.4375 + { ®ister_LCDC, sizeof(u8) }, 3.4376 + { ®ister_STAT, sizeof(u8) }, 3.4377 + { ®ister_SCY, sizeof(u8) }, 3.4378 + { ®ister_SCX, sizeof(u8) }, 3.4379 + { ®ister_LY, sizeof(u8) }, 3.4380 + { ®ister_LYC, sizeof(u8) }, 3.4381 + { ®ister_DMA, sizeof(u8) }, 3.4382 + { ®ister_WY, sizeof(u8) }, 3.4383 + { ®ister_WX, sizeof(u8) }, 3.4384 + { ®ister_VBK, sizeof(u8) }, 3.4385 + { ®ister_HDMA1, sizeof(u8) }, 3.4386 + { ®ister_HDMA2, sizeof(u8) }, 3.4387 + { ®ister_HDMA3, sizeof(u8) }, 3.4388 + { ®ister_HDMA4, sizeof(u8) }, 3.4389 + { ®ister_HDMA5, sizeof(u8) }, 3.4390 + { ®ister_SVBK, sizeof(u8) }, 3.4391 + { ®ister_IE, sizeof(u8) }, 3.4392 + { &gbBgp[0], sizeof(u8) }, 3.4393 + { &gbBgp[1], sizeof(u8) }, 3.4394 + { &gbBgp[2], sizeof(u8) }, 3.4395 + { &gbBgp[3], sizeof(u8) }, 3.4396 + { &gbObp0[0], sizeof(u8) }, 3.4397 + { &gbObp0[1], sizeof(u8) }, 3.4398 + { &gbObp0[2], sizeof(u8) }, 3.4399 + { &gbObp0[3], sizeof(u8) }, 3.4400 + { &gbObp1[0], sizeof(u8) }, 3.4401 + { &gbObp1[1], sizeof(u8) }, 3.4402 + { &gbObp1[2], sizeof(u8) }, 3.4403 + { &gbObp1[3], sizeof(u8) }, 3.4404 + { NULL, 0 } 3.4405 + }; 3.4406 3.4407 bool gbWriteSaveStateToStream(gzFile gzFile) 3.4408 { 3.4409 - utilWriteInt(gzFile, GBSAVE_GAME_VERSION); 3.4410 - 3.4411 - utilGzWrite(gzFile, &gbRom[0x134], 15); 3.4412 - 3.4413 - utilWriteData(gzFile, gbSaveGameStruct); 3.4414 - 3.4415 - utilGzWrite(gzFile, &IFF, 2); 3.4416 - 3.4417 - if (gbSgbMode) 3.4418 - { 3.4419 - gbSgbSaveGame(gzFile); 3.4420 - } 3.4421 - 3.4422 - utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); 3.4423 - utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); 3.4424 - //assert(sizeof(time_t) == 4); 3.4425 - utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); 3.4426 - utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); 3.4427 - utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); 3.4428 - utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); 3.4429 - 3.4430 - // yes, this definitely needs to be saved, or loading paused games will show a black screen 3.4431 - // this is also necessary to be consistent with what the GBA saving does 3.4432 - utilGzWrite(gzFile, pix, 4 * 257 * 226); 3.4433 - 3.4434 - utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); 3.4435 - // todo: remove 3.4436 - utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); 3.4437 - 3.4438 - utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); 3.4439 - 3.4440 - if (gbRamSize && gbRam) 3.4441 - { 3.4442 - utilGzWrite(gzFile, gbRam, gbRamSize); 3.4443 - } 3.4444 - 3.4445 - if (gbCgbMode) 3.4446 - { 3.4447 - utilGzWrite(gzFile, gbVram, 0x4000); 3.4448 - utilGzWrite(gzFile, gbWram, 0x8000); 3.4449 - } 3.4450 - 3.4451 - gbSoundSaveGame(gzFile); 3.4452 - 3.4453 - gbCheatsSaveGame(gzFile); 3.4454 - 3.4455 - // new to re-recording version: 3.4456 - { 3.4457 - extern int32 sensorX, sensorY; 3.4458 - utilGzWrite(gzFile, &sensorX, sizeof(sensorX)); 3.4459 - utilGzWrite(gzFile, &sensorY, sizeof(sensorY)); 3.4460 - utilGzWrite(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get 3.4461 - // carried 3.4462 - // back on loading a snapshot! 3.4463 - 3.4464 - bool8 movieActive = VBAMovieActive(); 3.4465 - utilGzWrite(gzFile, &movieActive, sizeof(movieActive)); 3.4466 - if (movieActive) 3.4467 - { 3.4468 - uint8 *movie_freeze_buf = NULL; 3.4469 - uint32 movie_freeze_size = 0; 3.4470 - 3.4471 - VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size); 3.4472 - if (movie_freeze_buf) 3.4473 - { 3.4474 - utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size)); 3.4475 - utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size); 3.4476 - delete [] movie_freeze_buf; 3.4477 - } 3.4478 - else 3.4479 - { 3.4480 - systemMessage(0, N_("Failed to save movie snapshot.")); 3.4481 - return false; 3.4482 - } 3.4483 - } 3.4484 - utilGzWrite(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); 3.4485 - } 3.4486 - 3.4487 - // new to rerecording 19.4 wip (svn r22+): 3.4488 - { 3.4489 - utilGzWrite(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); 3.4490 - utilGzWrite(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); 3.4491 - utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); 3.4492 - } 3.4493 - 3.4494 - return true; 3.4495 + utilWriteInt(gzFile, GBSAVE_GAME_VERSION); 3.4496 + 3.4497 + utilGzWrite(gzFile, &gbRom[0x134], 15); 3.4498 + 3.4499 + utilWriteData(gzFile, gbSaveGameStruct); 3.4500 + 3.4501 + utilGzWrite(gzFile, &IFF, 2); 3.4502 + 3.4503 + if (gbSgbMode) 3.4504 + { 3.4505 + gbSgbSaveGame(gzFile); 3.4506 + } 3.4507 + 3.4508 + utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); 3.4509 + utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); 3.4510 + //assert(sizeof(time_t) == 4); 3.4511 + utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); 3.4512 + utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); 3.4513 + utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); 3.4514 + utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); 3.4515 + 3.4516 + // yes, this definitely needs to be saved, or loading paused games will show a black screen 3.4517 + // this is also necessary to be consistent with what the GBA saving does 3.4518 + utilGzWrite(gzFile, pix, 4 * 257 * 226); 3.4519 + 3.4520 + utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); 3.4521 + // todo: remove 3.4522 + utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16)); 3.4523 + 3.4524 + utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000); 3.4525 + 3.4526 + if (gbRamSize && gbRam) 3.4527 + { 3.4528 + utilGzWrite(gzFile, gbRam, gbRamSize); 3.4529 + } 3.4530 + 3.4531 + if (gbCgbMode) 3.4532 + { 3.4533 + utilGzWrite(gzFile, gbVram, 0x4000); 3.4534 + utilGzWrite(gzFile, gbWram, 0x8000); 3.4535 + } 3.4536 + 3.4537 + gbSoundSaveGame(gzFile); 3.4538 + 3.4539 + gbCheatsSaveGame(gzFile); 3.4540 + 3.4541 + // new to re-recording version: 3.4542 + { 3.4543 + extern int32 sensorX, sensorY; 3.4544 + utilGzWrite(gzFile, &sensorX, sizeof(sensorX)); 3.4545 + utilGzWrite(gzFile, &sensorY, sizeof(sensorY)); 3.4546 + utilGzWrite(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get 3.4547 + // carried 3.4548 + // back on loading a snapshot! 3.4549 + 3.4550 + bool8 movieActive = VBAMovieActive(); 3.4551 + utilGzWrite(gzFile, &movieActive, sizeof(movieActive)); 3.4552 + if (movieActive) 3.4553 + { 3.4554 + uint8 *movie_freeze_buf = NULL; 3.4555 + uint32 movie_freeze_size = 0; 3.4556 + 3.4557 + VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size); 3.4558 + if (movie_freeze_buf) 3.4559 + { 3.4560 + utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size)); 3.4561 + utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size); 3.4562 + delete [] movie_freeze_buf; 3.4563 + } 3.4564 + else 3.4565 + { 3.4566 + systemMessage(0, N_("Failed to save movie snapshot.")); 3.4567 + return false; 3.4568 + } 3.4569 + } 3.4570 + utilGzWrite(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); 3.4571 + } 3.4572 + 3.4573 + // new to rerecording 19.4 wip (svn r22+): 3.4574 + { 3.4575 + utilGzWrite(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); 3.4576 + utilGzWrite(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); 3.4577 + utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); 3.4578 + } 3.4579 + 3.4580 + return true; 3.4581 } 3.4582 3.4583 bool gbWriteMemSaveState(char *memory, int available) 3.4584 { 3.4585 - gzFile gzFile = utilMemGzOpen(memory, available, "w"); 3.4586 - 3.4587 - if (gzFile == NULL) 3.4588 - { 3.4589 - return false; 3.4590 - } 3.4591 - 3.4592 - bool res = gbWriteSaveStateToStream(gzFile); 3.4593 - 3.4594 - long pos = utilGzTell(gzFile) + 8; 3.4595 - 3.4596 - if (pos >= (available)) 3.4597 - res = false; 3.4598 - 3.4599 - utilGzClose(gzFile); 3.4600 - 3.4601 - return res; 3.4602 + gzFile gzFile = utilMemGzOpen(memory, available, "w"); 3.4603 + 3.4604 + if (gzFile == NULL) 3.4605 + { 3.4606 + return false; 3.4607 + } 3.4608 + 3.4609 + bool res = gbWriteSaveStateToStream(gzFile); 3.4610 + 3.4611 + long pos = utilGzTell(gzFile) + 8; 3.4612 + 3.4613 + if (pos >= (available)) 3.4614 + res = false; 3.4615 + 3.4616 + utilGzClose(gzFile); 3.4617 + 3.4618 + return res; 3.4619 } 3.4620 3.4621 bool gbWriteSaveState(const char *name) 3.4622 { 3.4623 - gzFile gzFile = utilGzOpen(name, "wb"); 3.4624 - 3.4625 - if (gzFile == NULL) 3.4626 - return false; 3.4627 - 3.4628 - bool res = gbWriteSaveStateToStream(gzFile); 3.4629 - 3.4630 - utilGzClose(gzFile); 3.4631 - return res; 3.4632 + gzFile gzFile = utilGzOpen(name, "wb"); 3.4633 + 3.4634 + if (gzFile == NULL) 3.4635 + return false; 3.4636 + 3.4637 + bool res = gbWriteSaveStateToStream(gzFile); 3.4638 + 3.4639 + utilGzClose(gzFile); 3.4640 + return res; 3.4641 } 3.4642 3.4643 static int tempStateID = 0; 3.4644 @@ -2591,1328 +2591,1331 @@ 3.4645 3.4646 bool gbReadSaveStateFromStream(gzFile gzFile) 3.4647 { 3.4648 - int type; 3.4649 - char tempBackupName [128]; 3.4650 - if (backupSafe) 3.4651 + int type; 3.4652 + char tempBackupName [128]; 3.4653 + if (backupSafe) 3.4654 + { 3.4655 + sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++); 3.4656 + gbWriteSaveState(tempBackupName); 3.4657 + } 3.4658 + 3.4659 + int version = utilReadInt(gzFile); 3.4660 + 3.4661 + if (version > GBSAVE_GAME_VERSION || version < 0) 3.4662 + { 3.4663 + systemMessage(MSG_UNSUPPORTED_VB_SGM, 3.4664 + N_("Unsupported VisualBoy save game version %d"), version); 3.4665 + goto failedLoadGB; 3.4666 + } 3.4667 + 3.4668 + u8 romname[20]; 3.4669 + 3.4670 + utilGzRead(gzFile, romname, 15); 3.4671 + 3.4672 + if (memcmp(&gbRom[0x134], romname, 15) != 0) 3.4673 + { 3.4674 + systemMessage(MSG_CANNOT_LOAD_SGM_FOR, 3.4675 + N_("Cannot load save game for %s. Playing %s"), 3.4676 + romname, &gbRom[0x134]); 3.4677 + goto failedLoadGB; 3.4678 + } 3.4679 + 3.4680 + utilReadData(gzFile, gbSaveGameStruct); 3.4681 + 3.4682 + if (version >= GBSAVE_GAME_VERSION_7) 3.4683 + { 3.4684 + utilGzRead(gzFile, &IFF, 2); 3.4685 + } 3.4686 + 3.4687 + if (gbSgbMode) 3.4688 + { 3.4689 + gbSgbReadGame(gzFile, version); 3.4690 + } 3.4691 + else 3.4692 + { 3.4693 + gbSgbMask = 0; // loading a game at the wrong time causes no display 3.4694 + } 3.4695 + 3.4696 + utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); 3.4697 + utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); 3.4698 + if (version < GBSAVE_GAME_VERSION_4) 3.4699 + // prior to version 4, there was no adjustment for the time the game 3.4700 + // was last played, so we have less to read. This needs update if the 3.4701 + // structure changes again. 3.4702 + utilGzRead(gzFile, &gbDataMBC3, sizeof(int32) * 10); 3.4703 + else 3.4704 + { 3.4705 + //assert(sizeof(time_t) == 4); 3.4706 + utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); 3.4707 + } 3.4708 + utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); 3.4709 + utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); 3.4710 + utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); 3.4711 + 3.4712 + if (version >= GBSAVE_GAME_VERSION_12) 3.4713 + { 3.4714 + utilGzRead(gzFile, pix, 4 * 257 * 226); 3.4715 + } 3.4716 + else 3.4717 + { 3.4718 + memset(pix, 0, 257 * 226 * sizeof(u32)); 3.4719 + // if(version < GBSAVE_GAME_VERSION_5) 3.4720 + // utilGzRead(gzFile, pix, 256*224*sizeof(u16)); 3.4721 + } 3.4722 + 3.4723 + if (version < GBSAVE_GAME_VERSION_6) 3.4724 + { 3.4725 + utilGzRead(gzFile, gbPalette, 64 * sizeof(u16)); 3.4726 + } 3.4727 + else 3.4728 + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); 3.4729 + 3.4730 + // todo: remove 3.4731 + utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); 3.4732 + 3.4733 + if (version < GBSAVE_GAME_VERSION_10) 3.4734 + { 3.4735 + if (!gbCgbMode && !gbSgbMode) 3.4736 { 3.4737 - sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++); 3.4738 - gbWriteSaveState(tempBackupName); 3.4739 + for (int i = 0; i < 8; i++) 3.4740 + gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; 3.4741 } 3.4742 - 3.4743 - int version = utilReadInt(gzFile); 3.4744 - 3.4745 - if (version > GBSAVE_GAME_VERSION || version < 0) 3.4746 + } 3.4747 + 3.4748 + utilGzRead(gzFile, &gbMemory[0x8000], 0x8000); 3.4749 + 3.4750 + if (gbRamSize && gbRam) 3.4751 + { 3.4752 + utilGzRead(gzFile, gbRam, gbRamSize); 3.4753 + } 3.4754 + 3.4755 + gbMemoryMap[0x00] = &gbRom[0x0000]; 3.4756 + gbMemoryMap[0x01] = &gbRom[0x1000]; 3.4757 + gbMemoryMap[0x02] = &gbRom[0x2000]; 3.4758 + gbMemoryMap[0x03] = &gbRom[0x3000]; 3.4759 + gbMemoryMap[0x04] = &gbRom[0x4000]; 3.4760 + gbMemoryMap[0x05] = &gbRom[0x5000]; 3.4761 + gbMemoryMap[0x06] = &gbRom[0x6000]; 3.4762 + gbMemoryMap[0x07] = &gbRom[0x7000]; 3.4763 + gbMemoryMap[0x08] = &gbMemory[0x8000]; 3.4764 + gbMemoryMap[0x09] = &gbMemory[0x9000]; 3.4765 + gbMemoryMap[0x0a] = &gbMemory[0xa000]; 3.4766 + gbMemoryMap[0x0b] = &gbMemory[0xb000]; 3.4767 + gbMemoryMap[0x0c] = &gbMemory[0xc000]; 3.4768 + gbMemoryMap[0x0d] = &gbMemory[0xd000]; 3.4769 + gbMemoryMap[0x0e] = &gbMemory[0xe000]; 3.4770 + gbMemoryMap[0x0f] = &gbMemory[0xf000]; 3.4771 + 3.4772 + type = gbRom[0x147]; 3.4773 + 3.4774 + switch (type) 3.4775 + { 3.4776 + case 0x00: 3.4777 + case 0x01: 3.4778 + case 0x02: 3.4779 + case 0x03: 3.4780 + // MBC 1 3.4781 + memoryUpdateMapMBC1(); 3.4782 + break; 3.4783 + case 0x05: 3.4784 + case 0x06: 3.4785 + // MBC2 3.4786 + memoryUpdateMapMBC2(); 3.4787 + break; 3.4788 + case 0x0f: 3.4789 + case 0x10: 3.4790 + case 0x11: 3.4791 + case 0x12: 3.4792 + case 0x13: 3.4793 + // MBC 3 3.4794 + memoryUpdateMapMBC3(); 3.4795 + break; 3.4796 + case 0x19: 3.4797 + case 0x1a: 3.4798 + case 0x1b: 3.4799 + // MBC5 3.4800 + memoryUpdateMapMBC5(); 3.4801 + break; 3.4802 + case 0x1c: 3.4803 + case 0x1d: 3.4804 + case 0x1e: 3.4805 + // MBC 5 Rumble 3.4806 + memoryUpdateMapMBC5(); 3.4807 + break; 3.4808 + case 0x22: 3.4809 + // MBC 7 3.4810 + memoryUpdateMapMBC7(); 3.4811 + break; 3.4812 + case 0xfe: 3.4813 + // HuC3 3.4814 + memoryUpdateMapHuC3(); 3.4815 + break; 3.4816 + case 0xff: 3.4817 + // HuC1 3.4818 + memoryUpdateMapHuC1(); 3.4819 + break; 3.4820 + } 3.4821 + 3.4822 + if (gbCgbMode) 3.4823 + { 3.4824 + if (!gbVram) 3.4825 + gbVram = (u8 *)malloc(0x4000 + 4); 3.4826 + if (!gbWram) 3.4827 + gbWram = (u8 *)malloc(0x8000 + 4); 3.4828 + utilGzRead(gzFile, gbVram, 0x4000); 3.4829 + utilGzRead(gzFile, gbWram, 0x8000); 3.4830 + 3.4831 + int value = register_SVBK; 3.4832 + if (value == 0) 3.4833 + value = 1; 3.4834 + 3.4835 + gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; 3.4836 + gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; 3.4837 + gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; 3.4838 + } 3.4839 + else 3.4840 + { 3.4841 + if (gbVram) 3.4842 { 3.4843 - systemMessage(MSG_UNSUPPORTED_VB_SGM, 3.4844 - N_("Unsupported VisualBoy save game version %d"), version); 3.4845 - goto failedLoadGB; 3.4846 + free(gbVram); 3.4847 + gbVram = NULL; 3.4848 } 3.4849 - 3.4850 - u8 romname[20]; 3.4851 - 3.4852 - utilGzRead(gzFile, romname, 15); 3.4853 - 3.4854 - if (memcmp(&gbRom[0x134], romname, 15) != 0) 3.4855 + if (gbWram) 3.4856 { 3.4857 - systemMessage(MSG_CANNOT_LOAD_SGM_FOR, 3.4858 - N_("Cannot load save game for %s. Playing %s"), 3.4859 - romname, &gbRom[0x134]); 3.4860 - goto failedLoadGB; 3.4861 + free(gbWram); 3.4862 + gbWram = NULL; 3.4863 } 3.4864 - 3.4865 - utilReadData(gzFile, gbSaveGameStruct); 3.4866 - 3.4867 - if (version >= GBSAVE_GAME_VERSION_7) 3.4868 + } 3.4869 + 3.4870 + gbSoundReadGame(version, gzFile); 3.4871 + 3.4872 +#if 0 3.4873 + if (gbBorderOn) 3.4874 + { 3.4875 + gbSgbRenderBorder(); 3.4876 + } 3.4877 + 3.4878 + systemRefreshScreen(); 3.4879 +#endif 3.4880 + 3.4881 + if (version > GBSAVE_GAME_VERSION_1) 3.4882 + gbCheatsReadGame(gzFile, version); 3.4883 + 3.4884 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.4885 + 3.4886 + if (version >= GBSAVE_GAME_VERSION_11) // new to re-recording version: 3.4887 + { 3.4888 + extern int32 sensorX, sensorY; // from SDL.cpp 3.4889 + utilGzRead(gzFile, &sensorX, sizeof(sensorX)); 3.4890 + utilGzRead(gzFile, &sensorY, sizeof(sensorY)); 3.4891 + utilGzRead(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get carried 3.4892 + // back on loading a snapshot! 3.4893 + 3.4894 + bool8 movieSnapshot; 3.4895 + utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot)); 3.4896 + if (VBAMovieActive() && !movieSnapshot) 3.4897 { 3.4898 - utilGzRead(gzFile, &IFF, 2); 3.4899 + systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active.")); 3.4900 + goto failedLoadGB; 3.4901 } 3.4902 3.4903 - if (gbSgbMode) 3.4904 + if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added 3.4905 + // later on in the save format 3.4906 { 3.4907 - gbSgbReadGame(gzFile, version); 3.4908 + uint32 movieInputDataSize = 0; 3.4909 + utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize)); 3.4910 + uint8 *local_movie_data = new uint8 [movieInputDataSize]; 3.4911 + int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize); 3.4912 + if (readBytes != movieInputDataSize) 3.4913 + { 3.4914 + systemMessage(0, N_("Corrupt movie snapshot.")); 3.4915 + if (local_movie_data) 3.4916 + delete [] local_movie_data; 3.4917 + goto failedLoadGB; 3.4918 + } 3.4919 + int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize); 3.4920 + if (local_movie_data) 3.4921 + delete [] local_movie_data; 3.4922 + if (code != MOVIE_SUCCESS && VBAMovieActive()) 3.4923 + { 3.4924 + char errStr [1024]; 3.4925 + strcpy(errStr, "Failed to load movie snapshot"); 3.4926 + switch (code) 3.4927 + { 3.4928 + case MOVIE_NOT_FROM_THIS_MOVIE: 3.4929 + strcat(errStr, ";\nSnapshot not from this movie"); break; 3.4930 + case MOVIE_NOT_FROM_A_MOVIE: 3.4931 + strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here... 3.4932 + case MOVIE_SNAPSHOT_INCONSISTENT: 3.4933 + strcat(errStr, ";\nSnapshot inconsistent with movie"); break; 3.4934 + case MOVIE_WRONG_FORMAT: 3.4935 + strcat(errStr, ";\nWrong format"); break; 3.4936 + } 3.4937 + strcat(errStr, "."); 3.4938 + systemMessage(0, N_(errStr)); 3.4939 + goto failedLoadGB; 3.4940 + } 3.4941 } 3.4942 - else 3.4943 - { 3.4944 - gbSgbMask = 0; // loading a game at the wrong time causes no display 3.4945 - } 3.4946 - 3.4947 - utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1)); 3.4948 - utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2)); 3.4949 - if (version < GBSAVE_GAME_VERSION_4) 3.4950 - // prior to version 4, there was no adjustment for the time the game 3.4951 - // was last played, so we have less to read. This needs update if the 3.4952 - // structure changes again. 3.4953 - utilGzRead(gzFile, &gbDataMBC3, sizeof(int32) * 10); 3.4954 - else 3.4955 - { 3.4956 - //assert(sizeof(time_t) == 4); 3.4957 - utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3)); 3.4958 - } 3.4959 - utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5)); 3.4960 - utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1)); 3.4961 - utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3)); 3.4962 - 3.4963 - if (version >= GBSAVE_GAME_VERSION_12) 3.4964 - { 3.4965 - utilGzRead(gzFile, pix, 4 * 257 * 226); 3.4966 - } 3.4967 - else 3.4968 - { 3.4969 - memset(pix, 0, 257 * 226 * sizeof(u32)); 3.4970 -// if(version < GBSAVE_GAME_VERSION_5) 3.4971 -// utilGzRead(gzFile, pix, 256*224*sizeof(u16)); 3.4972 - } 3.4973 - 3.4974 - if (version < GBSAVE_GAME_VERSION_6) 3.4975 - { 3.4976 - utilGzRead(gzFile, gbPalette, 64 * sizeof(u16)); 3.4977 - } 3.4978 - else 3.4979 - utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); 3.4980 - 3.4981 - // todo: remove 3.4982 - utilGzRead(gzFile, gbPalette, 128 * sizeof(u16)); 3.4983 - 3.4984 - if (version < GBSAVE_GAME_VERSION_10) 3.4985 - { 3.4986 - if (!gbCgbMode && !gbSgbMode) 3.4987 - { 3.4988 - for (int i = 0; i < 8; i++) 3.4989 - gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i]; 3.4990 - } 3.4991 - } 3.4992 - 3.4993 - utilGzRead(gzFile, &gbMemory[0x8000], 0x8000); 3.4994 - 3.4995 - if (gbRamSize && gbRam) 3.4996 - { 3.4997 - utilGzRead(gzFile, gbRam, gbRamSize); 3.4998 - } 3.4999 - 3.5000 - gbMemoryMap[0x00] = &gbRom[0x0000]; 3.5001 - gbMemoryMap[0x01] = &gbRom[0x1000]; 3.5002 - gbMemoryMap[0x02] = &gbRom[0x2000]; 3.5003 - gbMemoryMap[0x03] = &gbRom[0x3000]; 3.5004 - gbMemoryMap[0x04] = &gbRom[0x4000]; 3.5005 - gbMemoryMap[0x05] = &gbRom[0x5000]; 3.5006 - gbMemoryMap[0x06] = &gbRom[0x6000]; 3.5007 - gbMemoryMap[0x07] = &gbRom[0x7000]; 3.5008 - gbMemoryMap[0x08] = &gbMemory[0x8000]; 3.5009 - gbMemoryMap[0x09] = &gbMemory[0x9000]; 3.5010 - gbMemoryMap[0x0a] = &gbMemory[0xa000]; 3.5011 - gbMemoryMap[0x0b] = &gbMemory[0xb000]; 3.5012 - gbMemoryMap[0x0c] = &gbMemory[0xc000]; 3.5013 - gbMemoryMap[0x0d] = &gbMemory[0xd000]; 3.5014 - gbMemoryMap[0x0e] = &gbMemory[0xe000]; 3.5015 - gbMemoryMap[0x0f] = &gbMemory[0xf000]; 3.5016 - 3.5017 - type = gbRom[0x147]; 3.5018 - 3.5019 - switch (type) 3.5020 - { 3.5021 - case 0x00: 3.5022 - case 0x01: 3.5023 - case 0x02: 3.5024 - case 0x03: 3.5025 - // MBC 1 3.5026 - memoryUpdateMapMBC1(); 3.5027 - break; 3.5028 - case 0x05: 3.5029 - case 0x06: 3.5030 - // MBC2 3.5031 - memoryUpdateMapMBC2(); 3.5032 - break; 3.5033 - case 0x0f: 3.5034 - case 0x10: 3.5035 - case 0x11: 3.5036 - case 0x12: 3.5037 - case 0x13: 3.5038 - // MBC 3 3.5039 - memoryUpdateMapMBC3(); 3.5040 - break; 3.5041 - case 0x19: 3.5042 - case 0x1a: 3.5043 - case 0x1b: 3.5044 - // MBC5 3.5045 - memoryUpdateMapMBC5(); 3.5046 - break; 3.5047 - case 0x1c: 3.5048 - case 0x1d: 3.5049 - case 0x1e: 3.5050 - // MBC 5 Rumble 3.5051 - memoryUpdateMapMBC5(); 3.5052 - break; 3.5053 - case 0x22: 3.5054 - // MBC 7 3.5055 - memoryUpdateMapMBC7(); 3.5056 - break; 3.5057 - case 0xfe: 3.5058 - // HuC3 3.5059 - memoryUpdateMapHuC3(); 3.5060 - break; 3.5061 - case 0xff: 3.5062 - // HuC1 3.5063 - memoryUpdateMapHuC1(); 3.5064 - break; 3.5065 - } 3.5066 - 3.5067 - if (gbCgbMode) 3.5068 - { 3.5069 - if (!gbVram) 3.5070 - gbVram = (u8 *)malloc(0x4000 + 4); 3.5071 - if (!gbWram) 3.5072 - gbWram = (u8 *)malloc(0x8000 + 4); 3.5073 - utilGzRead(gzFile, gbVram, 0x4000); 3.5074 - utilGzRead(gzFile, gbWram, 0x8000); 3.5075 - 3.5076 - int value = register_SVBK; 3.5077 - if (value == 0) 3.5078 - value = 1; 3.5079 - 3.5080 - gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000]; 3.5081 - gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000]; 3.5082 - gbMemoryMap[0x0d] = &gbWram[value * 0x1000]; 3.5083 - } 3.5084 - else 3.5085 - { 3.5086 - if (gbVram) 3.5087 - { 3.5088 - free(gbVram); 3.5089 - gbVram = NULL; 3.5090 - } 3.5091 - if (gbWram) 3.5092 - { 3.5093 - free(gbWram); 3.5094 - gbWram = NULL; 3.5095 - } 3.5096 - } 3.5097 - 3.5098 - gbSoundReadGame(version, gzFile); 3.5099 - 3.5100 -#if 0 3.5101 - if (gbBorderOn) 3.5102 - { 3.5103 - gbSgbRenderBorder(); 3.5104 - } 3.5105 - 3.5106 - systemRefreshScreen(); 3.5107 -#endif 3.5108 - 3.5109 - if (version > GBSAVE_GAME_VERSION_1) 3.5110 - gbCheatsReadGame(gzFile, version); 3.5111 - 3.5112 - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.5113 - 3.5114 - if (version >= GBSAVE_GAME_VERSION_11) // new to re-recording version: 3.5115 - { 3.5116 - extern int32 sensorX, sensorY; // from SDL.cpp 3.5117 - utilGzRead(gzFile, &sensorX, sizeof(sensorX)); 3.5118 - utilGzRead(gzFile, &sensorY, sizeof(sensorY)); 3.5119 - utilGzRead(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get carried 3.5120 - // back on loading a snapshot! 3.5121 - 3.5122 - bool8 movieSnapshot; 3.5123 - utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot)); 3.5124 - if (VBAMovieActive() && !movieSnapshot) 3.5125 - { 3.5126 - systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active.")); 3.5127 - goto failedLoadGB; 3.5128 - } 3.5129 - 3.5130 - if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added 3.5131 - // later on in the save format 3.5132 - { 3.5133 - uint32 movieInputDataSize = 0; 3.5134 - utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize)); 3.5135 - uint8 *local_movie_data = new uint8 [movieInputDataSize]; 3.5136 - int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize); 3.5137 - if (readBytes != movieInputDataSize) 3.5138 - { 3.5139 - systemMessage(0, N_("Corrupt movie snapshot.")); 3.5140 - if (local_movie_data) 3.5141 - delete [] local_movie_data; 3.5142 - goto failedLoadGB; 3.5143 - } 3.5144 - int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize); 3.5145 - if (local_movie_data) 3.5146 - delete [] local_movie_data; 3.5147 - if (code != MOVIE_SUCCESS && VBAMovieActive()) 3.5148 - { 3.5149 - char errStr [1024]; 3.5150 - strcpy(errStr, "Failed to load movie snapshot"); 3.5151 - switch (code) 3.5152 - { 3.5153 - case MOVIE_NOT_FROM_THIS_MOVIE: 3.5154 - strcat(errStr, ";\nSnapshot not from this movie"); break; 3.5155 - case MOVIE_NOT_FROM_A_MOVIE: 3.5156 - strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here... 3.5157 - case MOVIE_SNAPSHOT_INCONSISTENT: 3.5158 - strcat(errStr, ";\nSnapshot inconsistent with movie"); break; 3.5159 - case MOVIE_WRONG_FORMAT: 3.5160 - strcat(errStr, ";\nWrong format"); break; 3.5161 - } 3.5162 - strcat(errStr, "."); 3.5163 - systemMessage(0, N_(errStr)); 3.5164 - goto failedLoadGB; 3.5165 - } 3.5166 - } 3.5167 - utilGzRead(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); 3.5168 - } 3.5169 - 3.5170 - if (version >= GBSAVE_GAME_VERSION_13) // new to rerecording 19.4 wip (svn r22+): 3.5171 - { 3.5172 - utilGzRead(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); 3.5173 - utilGzRead(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); 3.5174 - utilGzRead(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); 3.5175 - } 3.5176 - 3.5177 - if (backupSafe) 3.5178 - { 3.5179 - remove(tempBackupName); 3.5180 - tempFailCount = 0; 3.5181 - } 3.5182 - 3.5183 - for (int i = 0; i < 4; ++i) 3.5184 - systemSetJoypad(i, gbJoymask[i] & 0xFFFF); 3.5185 - 3.5186 - // FIXME: horrible kludge 3.5187 - memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); 3.5188 - 3.5189 - VBAUpdateButtonPressDisplay(); 3.5190 - VBAUpdateFrameCountDisplay(); 3.5191 - systemRefreshScreen(); 3.5192 - return true; 3.5193 - 3.5194 -failedLoadGB: 3.5195 - if (backupSafe) 3.5196 - { 3.5197 - tempFailCount++; 3.5198 - if (tempFailCount < 3) // fail no more than 2 times in a row 3.5199 - gbReadSaveState(tempBackupName); 3.5200 - remove(tempBackupName); 3.5201 - } 3.5202 - return false; 3.5203 + utilGzRead(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount)); 3.5204 + } 3.5205 + 3.5206 + if (version >= GBSAVE_GAME_VERSION_13) // new to rerecording 19.4 wip (svn r22+): 3.5207 + { 3.5208 + utilGzRead(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount)); 3.5209 + utilGzRead(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged)); 3.5210 + utilGzRead(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast)); 3.5211 + } 3.5212 + 3.5213 + if (backupSafe) 3.5214 + { 3.5215 + remove(tempBackupName); 3.5216 + tempFailCount = 0; 3.5217 + } 3.5218 + 3.5219 + for (int i = 0; i < 4; ++i) 3.5220 + systemSetJoypad(i, gbJoymask[i] & 0xFFFF); 3.5221 + 3.5222 + // FIXME: horrible kludge 3.5223 + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); 3.5224 + 3.5225 + VBAUpdateButtonPressDisplay(); 3.5226 + VBAUpdateFrameCountDisplay(); 3.5227 + systemRefreshScreen(); 3.5228 + return true; 3.5229 + 3.5230 + failedLoadGB: 3.5231 + if (backupSafe) 3.5232 + { 3.5233 + tempFailCount++; 3.5234 + if (tempFailCount < 3) // fail no more than 2 times in a row 3.5235 + gbReadSaveState(tempBackupName); 3.5236 + remove(tempBackupName); 3.5237 + } 3.5238 + return false; 3.5239 } 3.5240 3.5241 bool gbReadMemSaveState(char *memory, int available) 3.5242 { 3.5243 - gzFile gzFile = utilMemGzOpen(memory, available, "r"); 3.5244 - 3.5245 - backupSafe = false; 3.5246 - bool res = gbReadSaveStateFromStream(gzFile); 3.5247 - backupSafe = true; 3.5248 - 3.5249 - utilGzClose(gzFile); 3.5250 - 3.5251 - return res; 3.5252 + gzFile gzFile = utilMemGzOpen(memory, available, "r"); 3.5253 + 3.5254 + backupSafe = false; 3.5255 + bool res = gbReadSaveStateFromStream(gzFile); 3.5256 + backupSafe = true; 3.5257 + 3.5258 + utilGzClose(gzFile); 3.5259 + 3.5260 + return res; 3.5261 } 3.5262 3.5263 bool gbReadSaveState(const char *name) 3.5264 { 3.5265 - gzFile gzFile = utilGzOpen(name, "rb"); 3.5266 - 3.5267 - if (gzFile == NULL) 3.5268 - { 3.5269 - return false; 3.5270 - } 3.5271 - 3.5272 - bool res = gbReadSaveStateFromStream(gzFile); 3.5273 - 3.5274 - utilGzClose(gzFile); 3.5275 - 3.5276 - return res; 3.5277 + gzFile gzFile = utilGzOpen(name, "rb"); 3.5278 + 3.5279 + if (gzFile == NULL) 3.5280 + { 3.5281 + return false; 3.5282 + } 3.5283 + 3.5284 + bool res = gbReadSaveStateFromStream(gzFile); 3.5285 + 3.5286 + utilGzClose(gzFile); 3.5287 + 3.5288 + return res; 3.5289 } 3.5290 3.5291 bool gbWritePNGFile(const char *fileName) 3.5292 { 3.5293 - if (gbBorderOn) 3.5294 - return utilWritePNGFile(fileName, 256, 224, pix); 3.5295 - return utilWritePNGFile(fileName, 160, 144, pix); 3.5296 + if (gbBorderOn) 3.5297 + return utilWritePNGFile(fileName, 256, 224, pix); 3.5298 + return utilWritePNGFile(fileName, 160, 144, pix); 3.5299 } 3.5300 3.5301 bool gbWriteBMPFile(const char *fileName) 3.5302 { 3.5303 - if (gbBorderOn) 3.5304 - return utilWriteBMPFile(fileName, 256, 224, pix); 3.5305 - return utilWriteBMPFile(fileName, 160, 144, pix); 3.5306 + if (gbBorderOn) 3.5307 + return utilWriteBMPFile(fileName, 256, 224, pix); 3.5308 + return utilWriteBMPFile(fileName, 160, 144, pix); 3.5309 } 3.5310 3.5311 void gbCleanUp() 3.5312 { 3.5313 - newFrame = true; 3.5314 - 3.5315 - GBSystemCounters.frameCount = 0; 3.5316 - GBSystemCounters.lagCount = 0; 3.5317 - GBSystemCounters.extraCount = 0; 3.5318 - GBSystemCounters.lagged = true; 3.5319 - GBSystemCounters.laggedLast = true; 3.5320 - 3.5321 - if (gbRam != NULL) 3.5322 - { 3.5323 - free(gbRam); 3.5324 - gbRam = NULL; 3.5325 - } 3.5326 - 3.5327 - if (gbRom != NULL) 3.5328 - { 3.5329 - free(gbRom); 3.5330 - gbRom = NULL; 3.5331 - } 3.5332 - 3.5333 - if (gbMemory != NULL) 3.5334 - { 3.5335 - free(gbMemory); 3.5336 - gbMemory = NULL; 3.5337 - } 3.5338 - 3.5339 - if (gbLineBuffer != NULL) 3.5340 - { 3.5341 - free(gbLineBuffer); 3.5342 - gbLineBuffer = NULL; 3.5343 - } 3.5344 - 3.5345 - if (origPix != NULL) 3.5346 - { 3.5347 - free(origPix); 3.5348 - origPix = NULL; 3.5349 - } 3.5350 - pix = NULL; 3.5351 - 3.5352 - gbSgbShutdown(); 3.5353 - 3.5354 - if (gbVram != NULL) 3.5355 - { 3.5356 - free(gbVram); 3.5357 - gbVram = NULL; 3.5358 - } 3.5359 - 3.5360 - if (gbWram != NULL) 3.5361 - { 3.5362 - free(gbWram); 3.5363 - gbWram = NULL; 3.5364 - } 3.5365 - 3.5366 - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.5367 - 3.5368 - memset(gbJoymask, 0, sizeof(gbJoymask)); 3.5369 - // FIXME: horrible kludge 3.5370 - memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); 3.5371 - 3.5372 - systemClearJoypads(); 3.5373 - systemResetSensor(); 3.5374 - 3.5375 -// gbLastTime = gbFrameCount = 0; 3.5376 - systemRefreshScreen(); 3.5377 + newFrame = true; 3.5378 + 3.5379 + GBSystemCounters.frameCount = 0; 3.5380 + GBSystemCounters.lagCount = 0; 3.5381 + GBSystemCounters.extraCount = 0; 3.5382 + GBSystemCounters.lagged = true; 3.5383 + GBSystemCounters.laggedLast = true; 3.5384 + 3.5385 + if (gbRam != NULL) 3.5386 + { 3.5387 + free(gbRam); 3.5388 + gbRam = NULL; 3.5389 + } 3.5390 + 3.5391 + if (gbRom != NULL) 3.5392 + { 3.5393 + free(gbRom); 3.5394 + gbRom = NULL; 3.5395 + } 3.5396 + 3.5397 + if (gbMemory != NULL) 3.5398 + { 3.5399 + free(gbMemory); 3.5400 + gbMemory = NULL; 3.5401 + } 3.5402 + 3.5403 + if (gbLineBuffer != NULL) 3.5404 + { 3.5405 + free(gbLineBuffer); 3.5406 + gbLineBuffer = NULL; 3.5407 + } 3.5408 + 3.5409 + if (origPix != NULL) 3.5410 + { 3.5411 + free(origPix); 3.5412 + origPix = NULL; 3.5413 + } 3.5414 + pix = NULL; 3.5415 + 3.5416 + gbSgbShutdown(); 3.5417 + 3.5418 + if (gbVram != NULL) 3.5419 + { 3.5420 + free(gbVram); 3.5421 + gbVram = NULL; 3.5422 + } 3.5423 + 3.5424 + if (gbWram != NULL) 3.5425 + { 3.5426 + free(gbWram); 3.5427 + gbWram = NULL; 3.5428 + } 3.5429 + 3.5430 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.5431 + 3.5432 + memset(gbJoymask, 0, sizeof(gbJoymask)); 3.5433 + // FIXME: horrible kludge 3.5434 + memset(s_gbJoymask, 0, sizeof(s_gbJoymask)); 3.5435 + 3.5436 + systemClearJoypads(); 3.5437 + systemResetSensor(); 3.5438 + 3.5439 + // gbLastTime = gbFrameCount = 0; 3.5440 + systemRefreshScreen(); 3.5441 } 3.5442 3.5443 bool gbLoadRom(const char *szFile) 3.5444 { 3.5445 - int size = 0; 3.5446 - 3.5447 - if (gbRom != NULL) 3.5448 - { 3.5449 - gbCleanUp(); 3.5450 - } 3.5451 - 3.5452 - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.5453 - 3.5454 - gbRom = utilLoad(szFile, 3.5455 - utilIsGBImage, 3.5456 - NULL, 3.5457 - size); 3.5458 - if (!gbRom) 3.5459 - return false; 3.5460 - 3.5461 - gbRomSize = size; 3.5462 - 3.5463 - return gbUpdateSizes(); 3.5464 + int size = 0; 3.5465 + 3.5466 + if (gbRom != NULL) 3.5467 + { 3.5468 + gbCleanUp(); 3.5469 + } 3.5470 + 3.5471 + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; 3.5472 + 3.5473 + gbRom = utilLoad(szFile, 3.5474 + utilIsGBImage, 3.5475 + NULL, 3.5476 + size); 3.5477 + if (!gbRom) 3.5478 + return false; 3.5479 + 3.5480 + gbRomSize = size; 3.5481 + 3.5482 + return gbUpdateSizes(); 3.5483 } 3.5484 3.5485 bool gbUpdateSizes() 3.5486 { 3.5487 - if (gbRom[0x148] > 8) 3.5488 - { 3.5489 - systemMessage(MSG_UNSUPPORTED_ROM_SIZE, 3.5490 - N_("Unsupported rom size %02x"), gbRom[0x148]); 3.5491 - return false; 3.5492 - } 3.5493 - 3.5494 - if (gbRomSize < gbRomSizes[gbRom[0x148]]) 3.5495 - { 3.5496 - gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); 3.5497 - } 3.5498 - gbRomSize = gbRomSizes[gbRom[0x148]]; 3.5499 - gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; 3.5500 - 3.5501 - if (gbRom[0x149] > 5) 3.5502 - { 3.5503 - systemMessage(MSG_UNSUPPORTED_RAM_SIZE, 3.5504 - N_("Unsupported ram size %02x"), gbRom[0x149]); 3.5505 - return false; 3.5506 - } 3.5507 - 3.5508 - gbRamSize = gbRamSizes[gbRom[0x149]]; 3.5509 - gbRamSizeMask = gbRamSizesMasks[gbRom[0x149]]; 3.5510 - 3.5511 - if (gbRamSize) 3.5512 - { 3.5513 - gbRam = (u8 *)malloc(gbRamSize + 4); 3.5514 - memset(gbRam, 0xFF, gbRamSize + 4); 3.5515 - } 3.5516 - 3.5517 - int type = gbRom[0x147]; 3.5518 - 3.5519 - mapperReadRAM = NULL; 3.5520 - 3.5521 - switch (type) 3.5522 - { 3.5523 - case 0x00: 3.5524 - case 0x01: 3.5525 - case 0x02: 3.5526 - case 0x03: 3.5527 - // MBC 1 3.5528 - mapper = mapperMBC1ROM; 3.5529 - mapperRAM = mapperMBC1RAM; 3.5530 - break; 3.5531 - case 0x05: 3.5532 - case 0x06: 3.5533 - // MBC2 3.5534 - mapper = mapperMBC2ROM; 3.5535 - mapperRAM = mapperMBC2RAM; 3.5536 - gbRamSize = 0x200; 3.5537 - gbRamSizeMask = 0x1ff; 3.5538 - break; 3.5539 - case 0x0f: 3.5540 - case 0x10: 3.5541 - case 0x11: 3.5542 - case 0x12: 3.5543 - case 0x13: 3.5544 - // MBC 3 3.5545 - mapper = mapperMBC3ROM; 3.5546 - mapperRAM = mapperMBC3RAM; 3.5547 - mapperReadRAM = mapperMBC3ReadRAM; 3.5548 - break; 3.5549 - case 0x19: 3.5550 - case 0x1a: 3.5551 - case 0x1b: 3.5552 - // MBC5 3.5553 - mapper = mapperMBC5ROM; 3.5554 - mapperRAM = mapperMBC5RAM; 3.5555 - break; 3.5556 - case 0x1c: 3.5557 - case 0x1d: 3.5558 - case 0x1e: 3.5559 - // MBC 5 Rumble 3.5560 - mapper = mapperMBC5ROM; 3.5561 - mapperRAM = mapperMBC5RAM; 3.5562 - break; 3.5563 - case 0x22: 3.5564 - // MBC 7 3.5565 - mapper = mapperMBC7ROM; 3.5566 - mapperRAM = mapperMBC7RAM; 3.5567 - mapperReadRAM = mapperMBC7ReadRAM; 3.5568 - break; 3.5569 - case 0xfe: 3.5570 - // HuC3 3.5571 - mapper = mapperHuC3ROM; 3.5572 - mapperRAM = mapperHuC3RAM; 3.5573 - mapperReadRAM = mapperHuC3ReadRAM; 3.5574 - break; 3.5575 - case 0xff: 3.5576 - // HuC1 3.5577 - mapper = mapperHuC1ROM; 3.5578 - mapperRAM = mapperHuC1RAM; 3.5579 - break; 3.5580 - default: 3.5581 - systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE, 3.5582 - N_("Unknown cartridge type %02x"), type); 3.5583 - return false; 3.5584 - } 3.5585 - 3.5586 - switch (type) 3.5587 - { 3.5588 - case 0x03: 3.5589 - case 0x06: 3.5590 - case 0x0f: 3.5591 - case 0x10: 3.5592 - case 0x13: 3.5593 - case 0x1b: 3.5594 - case 0x1d: 3.5595 - case 0x1e: 3.5596 - case 0x22: 3.5597 - case 0xff: 3.5598 - gbBattery = 1; 3.5599 - break; 3.5600 - } 3.5601 - 3.5602 - gbInit(); 3.5603 - gbReset(); 3.5604 - 3.5605 - return true; 3.5606 + if (gbRom[0x148] > 8) 3.5607 + { 3.5608 + systemMessage(MSG_UNSUPPORTED_ROM_SIZE, 3.5609 + N_("Unsupported rom size %02x"), gbRom[0x148]); 3.5610 + return false; 3.5611 + } 3.5612 + 3.5613 + if (gbRomSize < gbRomSizes[gbRom[0x148]]) 3.5614 + { 3.5615 + gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]); 3.5616 + } 3.5617 + gbRomSize = gbRomSizes[gbRom[0x148]]; 3.5618 + gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]]; 3.5619 + 3.5620 + if (gbRom[0x149] > 5) 3.5621 + { 3.5622 + systemMessage(MSG_UNSUPPORTED_RAM_SIZE, 3.5623 + N_("Unsupported ram size %02x"), gbRom[0x149]); 3.5624 + return false; 3.5625 + } 3.5626 + 3.5627 + gbRamSize = gbRamSizes[gbRom[0x149]]; 3.5628 + gbRamSizeMask = gbRamSizesMasks[gbRom[0x149]]; 3.5629 + 3.5630 + if (gbRamSize) 3.5631 + { 3.5632 + gbRam = (u8 *)malloc(gbRamSize + 4); 3.5633 + memset(gbRam, 0xFF, gbRamSize + 4); 3.5634 + } 3.5635 + 3.5636 + int type = gbRom[0x147]; 3.5637 + 3.5638 + mapperReadRAM = NULL; 3.5639 + 3.5640 + switch (type) 3.5641 + { 3.5642 + case 0x00: 3.5643 + case 0x01: 3.5644 + case 0x02: 3.5645 + case 0x03: 3.5646 + // MBC 1 3.5647 + mapper = mapperMBC1ROM; 3.5648 + mapperRAM = mapperMBC1RAM; 3.5649 + break; 3.5650 + case 0x05: 3.5651 + case 0x06: 3.5652 + // MBC2 3.5653 + mapper = mapperMBC2ROM; 3.5654 + mapperRAM = mapperMBC2RAM; 3.5655 + gbRamSize = 0x200; 3.5656 + gbRamSizeMask = 0x1ff; 3.5657 + break; 3.5658 + case 0x0f: 3.5659 + case 0x10: 3.5660 + case 0x11: 3.5661 + case 0x12: 3.5662 + case 0x13: 3.5663 + // MBC 3 3.5664 + mapper = mapperMBC3ROM; 3.5665 + mapperRAM = mapperMBC3RAM; 3.5666 + mapperReadRAM = mapperMBC3ReadRAM; 3.5667 + break; 3.5668 + case 0x19: 3.5669 + case 0x1a: 3.5670 + case 0x1b: 3.5671 + // MBC5 3.5672 + mapper = mapperMBC5ROM; 3.5673 + mapperRAM = mapperMBC5RAM; 3.5674 + break; 3.5675 + case 0x1c: 3.5676 + case 0x1d: 3.5677 + case 0x1e: 3.5678 + // MBC 5 Rumble 3.5679 + mapper = mapperMBC5ROM; 3.5680 + mapperRAM = mapperMBC5RAM; 3.5681 + break; 3.5682 + case 0x22: 3.5683 + // MBC 7 3.5684 + mapper = mapperMBC7ROM; 3.5685 + mapperRAM = mapperMBC7RAM; 3.5686 + mapperReadRAM = mapperMBC7ReadRAM; 3.5687 + break; 3.5688 + case 0xfe: 3.5689 + // HuC3 3.5690 + mapper = mapperHuC3ROM; 3.5691 + mapperRAM = mapperHuC3RAM; 3.5692 + mapperReadRAM = mapperHuC3ReadRAM; 3.5693 + break; 3.5694 + case 0xff: 3.5695 + // HuC1 3.5696 + mapper = mapperHuC1ROM; 3.5697 + mapperRAM = mapperHuC1RAM; 3.5698 + break; 3.5699 + default: 3.5700 + systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE, 3.5701 + N_("Unknown cartridge type %02x"), type); 3.5702 + return false; 3.5703 + } 3.5704 + 3.5705 + switch (type) 3.5706 + { 3.5707 + case 0x03: 3.5708 + case 0x06: 3.5709 + case 0x0f: 3.5710 + case 0x10: 3.5711 + case 0x13: 3.5712 + case 0x1b: 3.5713 + case 0x1d: 3.5714 + case 0x1e: 3.5715 + case 0x22: 3.5716 + case 0xff: 3.5717 + gbBattery = 1; 3.5718 + break; 3.5719 + } 3.5720 + 3.5721 + gbInit(); 3.5722 + gbReset(); 3.5723 + 3.5724 + return true; 3.5725 } 3.5726 3.5727 void gbEmulate(int ticksToStop) 3.5728 { 3.5729 - gbRegister tempRegister; 3.5730 - u8 tempValue; 3.5731 - s8 offset; 3.5732 - 3.5733 - int clockTicks = 0; 3.5734 - gbDmaTicks = 0; 3.5735 - 3.5736 - register int opcode = 0; 3.5737 - 3.5738 - u32 newmask = 0; 3.5739 - if (newFrame) 3.5740 + printf("RLM: Inside the GB!\n"); 3.5741 + gbRegister tempRegister; 3.5742 + u8 tempValue; 3.5743 + s8 offset; 3.5744 + 3.5745 + int clockTicks = 0; 3.5746 + gbDmaTicks = 0; 3.5747 + 3.5748 + register int opcode = 0; 3.5749 + 3.5750 + u32 newmask = 0; 3.5751 + printf("RLM: newframe = %d\n", newFrame); 3.5752 + if (newFrame) 3.5753 + { 3.5754 + extern void VBAOnExitingFrameBoundary(); 3.5755 + VBAOnExitingFrameBoundary(); 3.5756 + printf("RLM: exiting frame boundary?\n"); 3.5757 + // update joystick information 3.5758 + systemReadJoypads(); 3.5759 + 3.5760 + bool sensor = (gbRom[0x147] == 0x22); 3.5761 + 3.5762 + // read joystick 3.5763 + if (gbSgbMode && gbSgbMultiplayer) 3.5764 { 3.5765 - extern void VBAOnExitingFrameBoundary(); 3.5766 - VBAOnExitingFrameBoundary(); 3.5767 - 3.5768 - // update joystick information 3.5769 - systemReadJoypads(); 3.5770 - 3.5771 - bool sensor = (gbRom[0x147] == 0x22); 3.5772 - 3.5773 - // read joystick 3.5774 - if (gbSgbMode && gbSgbMultiplayer) 3.5775 + if (gbSgbFourPlayers) 3.5776 + { 3.5777 + gbJoymask[0] = systemGetJoypad(0, sensor); 3.5778 + gbJoymask[1] = systemGetJoypad(1, false); 3.5779 + gbJoymask[2] = systemGetJoypad(2, false); 3.5780 + gbJoymask[3] = systemGetJoypad(3, false); 3.5781 + } 3.5782 + else 3.5783 + { 3.5784 + gbJoymask[0] = systemGetJoypad(0, sensor); 3.5785 + gbJoymask[1] = systemGetJoypad(1, false); 3.5786 + } 3.5787 + } 3.5788 + else 3.5789 + { 3.5790 + gbJoymask[0] = systemGetJoypad(0, sensor); 3.5791 + } 3.5792 + 3.5793 + // FIXME: horrible kludge 3.5794 + memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); 3.5795 + 3.5796 + // if (sensor) 3.5797 + // systemUpdateMotionSensor(0); 3.5798 + 3.5799 + newmask = gbJoymask[0]; 3.5800 + if (newmask & 0xFF) 3.5801 + { 3.5802 + gbInterrupt |= 16; 3.5803 + } 3.5804 + 3.5805 + extButtons = (newmask >> 18); 3.5806 + speedup = (extButtons & 1) != 0; 3.5807 + 3.5808 + VBAMovieResetIfRequested(); 3.5809 + printf("RLM: before Lua functions\n"); 3.5810 + //CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); 3.5811 + printf("RLM: after Lua functions\n"); 3.5812 + newFrame = false; 3.5813 + } 3.5814 + 3.5815 + 3.5816 + for (;; ) 3.5817 + { 3.5818 +#ifndef FINAL_VERSION 3.5819 + if (systemDebug) 3.5820 + { 3.5821 + if (!(IFF & 0x80)) 3.5822 + { 3.5823 + if (systemDebug > 1) 3.5824 { 3.5825 - if (gbSgbFourPlayers) 3.5826 + sprintf(gbBuffer, "PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n", 3.5827 + PC.W, AF.W, BC.W, DE.W, HL.W, SP.W, IFF); 3.5828 + } 3.5829 + else 3.5830 + { 3.5831 + sprintf(gbBuffer, "PC=%04x I=%02x\n", PC.W, IFF); 3.5832 + } 3.5833 + log(gbBuffer); 3.5834 + } 3.5835 + } 3.5836 +#endif 3.5837 + if (IFF & 0x80) 3.5838 + { 3.5839 + if (register_LCDC & 0x80) 3.5840 + { 3.5841 + clockTicks = gbLcdTicks; 3.5842 + } 3.5843 + else 3.5844 + clockTicks = 100; 3.5845 + 3.5846 + if (gbLcdMode == 1 && (gbLcdLYIncrementTicks < clockTicks)) 3.5847 + clockTicks = gbLcdLYIncrementTicks; 3.5848 + 3.5849 + if (gbSerialOn && (gbSerialTicks < clockTicks)) 3.5850 + clockTicks = gbSerialTicks; 3.5851 + 3.5852 + if (gbTimerOn && (gbTimerTicks < clockTicks)) 3.5853 + clockTicks = gbTimerTicks; 3.5854 + 3.5855 + if (soundTicks && (soundTicks < clockTicks)) 3.5856 + clockTicks = soundTicks; 3.5857 + } 3.5858 + else 3.5859 + { 3.5860 + opcode = gbReadOpcode(PC.W); 3.5861 + CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); 3.5862 + PC.W++; 3.5863 + 3.5864 + if (IFF & 0x100) 3.5865 + { 3.5866 + IFF &= 0xff; 3.5867 + PC.W--; 3.5868 + } 3.5869 + 3.5870 + clockTicks = gbCycles[opcode]; 3.5871 + 3.5872 + switch (opcode) 3.5873 + { 3.5874 + case 0xCB: 3.5875 + // extended opcode 3.5876 + //CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); // is this desired? 3.5877 + opcode = gbReadOpcode(PC.W++); 3.5878 + clockTicks = gbCyclesCB[opcode]; 3.5879 + switch (opcode) 3.5880 + { 3.5881 +#include "gbCodesCB.h" 3.5882 + } 3.5883 + break; 3.5884 +#include "gbCodes.h" 3.5885 + } 3.5886 + } 3.5887 + 3.5888 + if (!emulating) 3.5889 + return; 3.5890 + 3.5891 + if (gbDmaTicks) 3.5892 + { 3.5893 + clockTicks += gbDmaTicks; 3.5894 + gbDmaTicks = 0; 3.5895 + } 3.5896 + 3.5897 + if (gbSgbMode) 3.5898 + { 3.5899 + if (gbSgbPacketTimeout) 3.5900 + { 3.5901 + gbSgbPacketTimeout -= clockTicks; 3.5902 + 3.5903 + if (gbSgbPacketTimeout <= 0) 3.5904 + gbSgbResetPacketState(); 3.5905 + } 3.5906 + } 3.5907 + 3.5908 + ticksToStop -= clockTicks; 3.5909 + 3.5910 + // DIV register emulation 3.5911 + gbDivTicks -= clockTicks; 3.5912 + while (gbDivTicks <= 0) 3.5913 + { 3.5914 + register_DIV++; 3.5915 + gbDivTicks += GBDIV_CLOCK_TICKS; 3.5916 + } 3.5917 + 3.5918 + if (register_LCDC & 0x80) 3.5919 + { 3.5920 + // LCD stuff 3.5921 + gbLcdTicks -= clockTicks; 3.5922 + if (gbLcdMode == 1) 3.5923 + { 3.5924 + // during V-BLANK,we need to increment LY at the same rate! 3.5925 + gbLcdLYIncrementTicks -= clockTicks; 3.5926 + while (gbLcdLYIncrementTicks <= 0) 3.5927 + { 3.5928 + gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; 3.5929 + 3.5930 + if (register_LY < 153) 3.5931 + { 3.5932 + register_LY++; 3.5933 + 3.5934 + gbCompareLYToLYC(); 3.5935 + 3.5936 + if (register_LY >= 153) 3.5937 + gbLcdLYIncrementTicks = 6; 3.5938 + } 3.5939 + else 3.5940 + { 3.5941 + register_LY = 0x00; 3.5942 + // reset the window line 3.5943 + gbWindowLine = -1; 3.5944 + gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2; 3.5945 + gbCompareLYToLYC(); 3.5946 + } 3.5947 + } 3.5948 + } 3.5949 + 3.5950 + // our counter is off, see what we need to do 3.5951 + while (gbLcdTicks <= 0) 3.5952 + { 3.5953 + int framesToSkip = systemFramesToSkip(); 3.5954 + 3.5955 + switch (gbLcdMode) 3.5956 + { 3.5957 + case 0: 3.5958 + // H-Blank 3.5959 + register_LY++; 3.5960 + 3.5961 + gbCompareLYToLYC(); 3.5962 + 3.5963 + // check if we reached the V-Blank period 3.5964 + if (register_LY == 144) 3.5965 + { 3.5966 + // Yes, V-Blank 3.5967 + // set the LY increment counter 3.5968 + gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS; 3.5969 + gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; 3.5970 + gbLcdMode = 1; 3.5971 + if (register_LCDC & 0x80) 3.5972 { 3.5973 - gbJoymask[0] = systemGetJoypad(0, sensor); 3.5974 - gbJoymask[1] = systemGetJoypad(1, false); 3.5975 - gbJoymask[2] = systemGetJoypad(2, false); 3.5976 - gbJoymask[3] = systemGetJoypad(3, false); 3.5977 + gbInterrupt |= 1; // V-Blank interrupt 3.5978 + gbInterruptWait = 6; 3.5979 + if (register_STAT & 0x10) 3.5980 + gbInterrupt |= 2; 3.5981 } 3.5982 - else 3.5983 + 3.5984 + systemFrame(); 3.5985 + 3.5986 + ++gbFrameCount; 3.5987 + u32 currentTime = systemGetClock(); 3.5988 + if (currentTime - gbLastTime >= 1000) 3.5989 { 3.5990 - gbJoymask[0] = systemGetJoypad(0, sensor); 3.5991 - gbJoymask[1] = systemGetJoypad(1, false); 3.5992 + systemShowSpeed(int(float(gbFrameCount) * 100000 / (float(currentTime - gbLastTime) * 60) + .5f)); 3.5993 + gbLastTime = currentTime; 3.5994 + gbFrameCount = 0; 3.5995 } 3.5996 + 3.5997 + ++GBSystemCounters.frameCount; 3.5998 + if (GBSystemCounters.lagged) 3.5999 + { 3.6000 + ++GBSystemCounters.lagCount; 3.6001 + } 3.6002 + GBSystemCounters.laggedLast = GBSystemCounters.lagged; 3.6003 + GBSystemCounters.lagged = true; 3.6004 + 3.6005 + extern void VBAOnEnteringFrameBoundary(); 3.6006 + VBAOnEnteringFrameBoundary(); 3.6007 + 3.6008 + newFrame = true; 3.6009 + 3.6010 + pauseAfterFrameAdvance = systemPauseOnFrame(); 3.6011 + 3.6012 + if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) 3.6013 + { 3.6014 + if (gbBorderOn) 3.6015 + gbSgbRenderBorder(); // clear unnecessary things on border (e.g. in-game text message) 3.6016 + 3.6017 + systemRenderFrame(); 3.6018 + gbFrameSkipCount = 0; 3.6019 + 3.6020 + bool capturePressed = (extButtons & 2) != 0; 3.6021 + if (capturePressed && !capturePrevious) 3.6022 + { 3.6023 + captureNumber = systemScreenCapture(captureNumber); 3.6024 + } 3.6025 + capturePrevious = capturePressed && !pauseAfterFrameAdvance; 3.6026 + } 3.6027 + else 3.6028 + { 3.6029 + ++gbFrameSkipCount; 3.6030 + } 3.6031 + 3.6032 + if (pauseAfterFrameAdvance) 3.6033 + { 3.6034 + systemSetPause(true); 3.6035 + } 3.6036 + } 3.6037 + else 3.6038 + { 3.6039 + // go the the OAM being accessed mode 3.6040 + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; 3.6041 + gbLcdMode = 2; 3.6042 + 3.6043 + // only one LCD interrupt per line. may need to generalize... 3.6044 + if (!(register_STAT & 0x40) || 3.6045 + (register_LY != register_LYC)) 3.6046 + { 3.6047 + if ((register_STAT & 0x28) == 0x20) 3.6048 + gbInterrupt |= 2; 3.6049 + } 3.6050 + } 3.6051 + 3.6052 + break; 3.6053 + case 1: 3.6054 + // V-Blank 3.6055 + // next mode is OAM being accessed mode 3.6056 + gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; 3.6057 + gbLcdMode = 2; 3.6058 + if (!(register_STAT & 0x40) || 3.6059 + (register_LY != register_LYC)) 3.6060 + { 3.6061 + if ((register_STAT & 0x28) == 0x20) 3.6062 + gbInterrupt |= 2; 3.6063 + } 3.6064 + break; 3.6065 + case 2: 3.6066 + // OAM being accessed mode 3.6067 + 3.6068 + // next mode is OAM and VRAM in use 3.6069 + gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS; 3.6070 + gbLcdMode = 3; 3.6071 + break; 3.6072 + case 3: 3.6073 + // OAM and VRAM in use 3.6074 + // next mode is H-Blank 3.6075 + if (register_LY < 144) 3.6076 + { 3.6077 + if (!gbSgbMask) 3.6078 + { 3.6079 + if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) 3.6080 + { 3.6081 + gbRenderLine(); 3.6082 + gbDrawSprites(); 3.6083 + 3.6084 + switch (systemColorDepth) 3.6085 + { 3.6086 + case 16: 3.6087 + 3.6088 + { 3.6089 + u16 *dest = (u16 *)pix + 3.6090 + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1) 3.6091 + + gbBorderColumnSkip; 3.6092 + for (int x = 0; x < 160; ) 3.6093 + { 3.6094 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6095 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6096 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6097 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6098 + 3.6099 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6100 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6101 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6102 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6103 + 3.6104 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6105 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6106 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6107 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6108 + 3.6109 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6110 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6111 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6112 + *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6113 + } 3.6114 + if (gbBorderOn) 3.6115 + dest += gbBorderColumnSkip; 3.6116 + *dest++ = 0; // for filters that read one pixel more 3.6117 + break; 3.6118 + } 3.6119 + case 24: 3.6120 + 3.6121 + { 3.6122 + u8 *dest = (u8 *)pix + 3.6123 + 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + 3.6124 + gbBorderColumnSkip); 3.6125 + for (int x = 0; x < 160; ) 3.6126 + { 3.6127 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6128 + dest += 3; 3.6129 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6130 + dest += 3; 3.6131 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6132 + dest += 3; 3.6133 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6134 + dest += 3; 3.6135 + 3.6136 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6137 + dest += 3; 3.6138 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6139 + dest += 3; 3.6140 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6141 + dest += 3; 3.6142 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6143 + dest += 3; 3.6144 + 3.6145 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6146 + dest += 3; 3.6147 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6148 + dest += 3; 3.6149 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6150 + dest += 3; 3.6151 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6152 + dest += 3; 3.6153 + 3.6154 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6155 + dest += 3; 3.6156 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6157 + dest += 3; 3.6158 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6159 + dest += 3; 3.6160 + *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6161 + dest += 3; 3.6162 + } 3.6163 + break; 3.6164 + } 3.6165 + case 32: 3.6166 + 3.6167 + { 3.6168 + u32 *dest = (u32 *)pix + 3.6169 + (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1) 3.6170 + + gbBorderColumnSkip; 3.6171 + for (int x = 0; x < 160; ) 3.6172 + { 3.6173 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6174 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6175 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6176 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6177 + 3.6178 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6179 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6180 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6181 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6182 + 3.6183 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6184 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6185 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6186 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6187 + 3.6188 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6189 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6190 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6191 + *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6192 + } 3.6193 + break; 3.6194 + } 3.6195 + } 3.6196 + } 3.6197 + } 3.6198 + } 3.6199 + gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS; 3.6200 + gbLcdMode = 0; 3.6201 + // only one LCD interrupt per line. may need to generalize... 3.6202 + if (!(register_STAT & 0x40) || 3.6203 + (register_LY != register_LYC)) 3.6204 + { 3.6205 + if (register_STAT & 0x08) 3.6206 + gbInterrupt |= 2; 3.6207 + } 3.6208 + if (gbHdmaOn) 3.6209 + { 3.6210 + gbDoHdma(); 3.6211 + } 3.6212 + break; 3.6213 } 3.6214 - else 3.6215 + // mark the correct lcd mode on STAT register 3.6216 + register_STAT = (register_STAT & 0xfc) | gbLcdMode; 3.6217 + } 3.6218 + } 3.6219 + 3.6220 + // serial emulation 3.6221 + if (gbSerialOn) 3.6222 + { 3.6223 +#ifdef LINK_EMULATION 3.6224 + if (linkConnected) 3.6225 + { 3.6226 + gbSerialTicks -= clockTicks; 3.6227 + 3.6228 + while (gbSerialTicks <= 0) 3.6229 { 3.6230 - gbJoymask[0] = systemGetJoypad(0, sensor); 3.6231 + // increment number of shifted bits 3.6232 + gbSerialBits++; 3.6233 + linkProc(); 3.6234 + if (gbSerialOn && (gbMemory[0xff02] & 1)) 3.6235 + { 3.6236 + if (gbSerialBits == 8) 3.6237 + { 3.6238 + gbSerialBits = 0; 3.6239 + gbMemory[0xff01] = 0xff; 3.6240 + gbMemory[0xff02] &= 0x7f; 3.6241 + gbSerialOn = 0; 3.6242 + gbInterrupt |= 8; 3.6243 + gbSerialTicks = 0; 3.6244 + } 3.6245 + } 3.6246 + gbSerialTicks += GBSERIAL_CLOCK_TICKS; 3.6247 } 3.6248 - 3.6249 - // FIXME: horrible kludge 3.6250 - memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask)); 3.6251 - 3.6252 -// if (sensor) 3.6253 -// systemUpdateMotionSensor(0); 3.6254 - 3.6255 - newmask = gbJoymask[0]; 3.6256 - if (newmask & 0xFF) 3.6257 + } 3.6258 + else 3.6259 + { 3.6260 +#endif 3.6261 + if (gbMemory[0xff02] & 1) 3.6262 { 3.6263 - gbInterrupt |= 16; 3.6264 + gbSerialTicks -= clockTicks; 3.6265 + 3.6266 + // overflow 3.6267 + while (gbSerialTicks <= 0) 3.6268 + { 3.6269 + // shift serial byte to right and put a 1 bit in its place 3.6270 + // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); 3.6271 + // increment number of shifted bits 3.6272 + gbSerialBits++; 3.6273 + if (gbSerialBits == 8) 3.6274 + { 3.6275 + // end of transmission 3.6276 + if (gbSerialFunction) // external device 3.6277 + gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); 3.6278 + else 3.6279 + gbMemory[0xff01] = 0xff; 3.6280 + gbSerialTicks = 0; 3.6281 + gbMemory[0xff02] &= 0x7f; 3.6282 + gbSerialOn = 0; 3.6283 + gbInterrupt |= 8; 3.6284 + gbSerialBits = 0; 3.6285 + } 3.6286 + else 3.6287 + gbSerialTicks += GBSERIAL_CLOCK_TICKS; 3.6288 + } 3.6289 } 3.6290 - 3.6291 - extButtons = (newmask >> 18); 3.6292 - speedup = (extButtons & 1) != 0; 3.6293 - 3.6294 - VBAMovieResetIfRequested(); 3.6295 - 3.6296 - CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION); 3.6297 - 3.6298 - newFrame = false; 3.6299 +#ifdef LINK_EMULATION 3.6300 + } 3.6301 +#endif 3.6302 } 3.6303 3.6304 - for (;; ) 3.6305 + // timer emulation 3.6306 + if (gbTimerOn) 3.6307 { 3.6308 -#ifndef FINAL_VERSION 3.6309 - if (systemDebug) 3.6310 + gbTimerTicks -= clockTicks; 3.6311 + 3.6312 + while (gbTimerTicks <= 0) 3.6313 + { 3.6314 + register_TIMA++; 3.6315 + 3.6316 + if (register_TIMA == 0) 3.6317 { 3.6318 - if (!(IFF & 0x80)) 3.6319 + // timer overflow! 3.6320 + 3.6321 + // reload timer modulo 3.6322 + register_TIMA = register_TMA; 3.6323 + 3.6324 + // flag interrupt 3.6325 + gbInterrupt |= 4; 3.6326 + } 3.6327 + 3.6328 + gbTimerTicks += gbTimerClockTicks; 3.6329 + } 3.6330 + } 3.6331 + 3.6332 + /* 3.6333 + if(soundOffFlag) 3.6334 + { 3.6335 + if(synchronize && !speedup) 3.6336 + { 3.6337 + synchronizeTicks -= clockTicks; 3.6338 + 3.6339 + while(synchronizeTicks < 0) 3.6340 + { 3.6341 + synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS; 3.6342 + 3.6343 + DWORD now = timeGetTime(); 3.6344 + gbElapsedTime += (now - timeNow); 3.6345 + 3.6346 + if(gbElapsedTime < 50) 3.6347 + { 3.6348 + DWORD diff = 50 - gbElapsedTime; 3.6349 + Sleep(diff); 3.6350 + timeNow = timeGetTime(); 3.6351 + elapsedTime = timeNow - now - diff; 3.6352 + if((int)elapsedTime < 0) 3.6353 + elapsedTime = 0; 3.6354 + } else 3.6355 + { 3.6356 + timeNow = timeGetTime(); 3.6357 + elapsedTime = 0; 3.6358 + } 3.6359 + } 3.6360 + } 3.6361 + } 3.6362 + */ 3.6363 + 3.6364 + soundTicks -= clockTicks; 3.6365 + while (soundTicks < 0) // must be < 1 when soundtick_t is real data type 3.6366 + { 3.6367 + soundTicks += SOUND_CLOCK_TICKS; 3.6368 + 3.6369 + gbSoundTick(); 3.6370 + } 3.6371 + 3.6372 + register_IF = gbInterrupt; 3.6373 + 3.6374 + if (IFF & 0x20) 3.6375 + { 3.6376 + IFF &= 0xdf; 3.6377 + IFF |= 0x01; 3.6378 + gbInterruptWait = 0; 3.6379 + } 3.6380 + else if (gbInterrupt) 3.6381 + { 3.6382 + if (gbInterruptWait == 0) 3.6383 + { 3.6384 + // gbInterruptWait = 0; 3.6385 + 3.6386 + if (IFF & 0x01) 3.6387 + { 3.6388 + if ((gbInterrupt & 1) && (register_IE & 1)) 3.6389 + { 3.6390 + gbVblank_interrupt(); 3.6391 + continue; 3.6392 + } 3.6393 + 3.6394 + if ((gbInterrupt & 2) && (register_IE & 2)) 3.6395 + { 3.6396 + gbLcd_interrupt(); 3.6397 + continue; 3.6398 + } 3.6399 + 3.6400 + if ((gbInterrupt & 4) && (register_IE & 4)) 3.6401 + { 3.6402 + gbTimer_interrupt(); 3.6403 + continue; 3.6404 + } 3.6405 + 3.6406 + if ((gbInterrupt & 8) && (register_IE & 8)) 3.6407 + { 3.6408 + gbSerial_interrupt(); 3.6409 + continue; 3.6410 + } 3.6411 + 3.6412 + if ((gbInterrupt & 16) && (register_IE & 16)) 3.6413 + { 3.6414 + gbJoypad_interrupt(); 3.6415 + continue; 3.6416 + } 3.6417 + } 3.6418 + } 3.6419 + else 3.6420 + { 3.6421 + gbInterruptWait -= clockTicks; 3.6422 + if (gbInterruptWait < 0) 3.6423 + gbInterruptWait = 0; 3.6424 + } 3.6425 + } 3.6426 + 3.6427 + if (useOldFrameTiming) 3.6428 + { 3.6429 + // old timing code 3.6430 + if (ticksToStop > 0) 3.6431 + continue; 3.6432 + } 3.6433 + else 3.6434 + { 3.6435 + if (!newFrame && (register_LCDC & 0x80) != 0) 3.6436 + continue; 3.6437 + } 3.6438 + 3.6439 + if (!(register_LCDC & 0x80)) 3.6440 + { 3.6441 + if (!useOldFrameTiming) 3.6442 + { 3.6443 + // FIXME: since register_LY can be reset to 0 by some games, frame length is variable 3.6444 + // and infinite loops can occurr 3.6445 + // for now, it IS necessary to do something on this condition or games like 3.6446 + // Megaman would freeze upon low-level restart interrupt sequence (Start+Select+A+B). 3.6447 + // the only sensible way to fix this issue is to implement the RIGHT frame timing 3.6448 +#ifdef WANTS_INCOMPLETE_WORKAROUND 3.6449 + if (systemReadJoypads()) 3.6450 + { 3.6451 + if (gbSgbMode && gbSgbMultiplayer) 3.6452 + { 3.6453 + if (gbSgbFourPlayers) 3.6454 { 3.6455 - if (systemDebug > 1) 3.6456 - { 3.6457 - sprintf(gbBuffer, "PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n", 3.6458 - PC.W, AF.W, BC.W, DE.W, HL.W, SP.W, IFF); 3.6459 - } 3.6460 - else 3.6461 - { 3.6462 - sprintf(gbBuffer, "PC=%04x I=%02x\n", PC.W, IFF); 3.6463 - } 3.6464 - log(gbBuffer); 3.6465 + gbJoymask[0] = systemGetJoypad(0, false); 3.6466 + gbJoymask[1] = systemGetJoypad(1, false); 3.6467 + gbJoymask[2] = systemGetJoypad(2, false); 3.6468 + gbJoymask[3] = systemGetJoypad(3, false); 3.6469 } 3.6470 + else 3.6471 + { 3.6472 + gbJoymask[0] = systemGetJoypad(0, false); 3.6473 + gbJoymask[1] = systemGetJoypad(1, false); 3.6474 + } 3.6475 + } 3.6476 + else 3.6477 + { 3.6478 + gbJoymask[0] = systemGetJoypad(0, false); 3.6479 + } 3.6480 } 3.6481 -#endif 3.6482 - if (IFF & 0x80) 3.6483 - { 3.6484 - if (register_LCDC & 0x80) 3.6485 - { 3.6486 - clockTicks = gbLcdTicks; 3.6487 - } 3.6488 - else 3.6489 - clockTicks = 100; 3.6490 - 3.6491 - if (gbLcdMode == 1 && (gbLcdLYIncrementTicks < clockTicks)) 3.6492 - clockTicks = gbLcdLYIncrementTicks; 3.6493 - 3.6494 - if (gbSerialOn && (gbSerialTicks < clockTicks)) 3.6495 - clockTicks = gbSerialTicks; 3.6496 - 3.6497 - if (gbTimerOn && (gbTimerTicks < clockTicks)) 3.6498 - clockTicks = gbTimerTicks; 3.6499 - 3.6500 - if (soundTicks && (soundTicks < clockTicks)) 3.6501 - clockTicks = soundTicks; 3.6502 - } 3.6503 - else 3.6504 - { 3.6505 - opcode = gbReadOpcode(PC.W); 3.6506 - CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); 3.6507 - PC.W++; 3.6508 - 3.6509 - if (IFF & 0x100) 3.6510 - { 3.6511 - IFF &= 0xff; 3.6512 - PC.W--; 3.6513 - } 3.6514 - 3.6515 - clockTicks = gbCycles[opcode]; 3.6516 - 3.6517 - switch (opcode) 3.6518 - { 3.6519 - case 0xCB: 3.6520 - // extended opcode 3.6521 - //CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); // is this desired? 3.6522 - opcode = gbReadOpcode(PC.W++); 3.6523 - clockTicks = gbCyclesCB[opcode]; 3.6524 - switch (opcode) 3.6525 - { 3.6526 -#include "gbCodesCB.h" 3.6527 - } 3.6528 - break; 3.6529 -#include "gbCodes.h" 3.6530 - } 3.6531 - } 3.6532 - 3.6533 - if (!emulating) 3.6534 - return; 3.6535 - 3.6536 - if (gbDmaTicks) 3.6537 - { 3.6538 - clockTicks += gbDmaTicks; 3.6539 - gbDmaTicks = 0; 3.6540 - } 3.6541 - 3.6542 - if (gbSgbMode) 3.6543 - { 3.6544 - if (gbSgbPacketTimeout) 3.6545 - { 3.6546 - gbSgbPacketTimeout -= clockTicks; 3.6547 - 3.6548 - if (gbSgbPacketTimeout <= 0) 3.6549 - gbSgbResetPacketState(); 3.6550 - } 3.6551 - } 3.6552 - 3.6553 - ticksToStop -= clockTicks; 3.6554 - 3.6555 - // DIV register emulation 3.6556 - gbDivTicks -= clockTicks; 3.6557 - while (gbDivTicks <= 0) 3.6558 - { 3.6559 - register_DIV++; 3.6560 - gbDivTicks += GBDIV_CLOCK_TICKS; 3.6561 - } 3.6562 - 3.6563 - if (register_LCDC & 0x80) 3.6564 - { 3.6565 - // LCD stuff 3.6566 - gbLcdTicks -= clockTicks; 3.6567 - if (gbLcdMode == 1) 3.6568 - { 3.6569 - // during V-BLANK,we need to increment LY at the same rate! 3.6570 - gbLcdLYIncrementTicks -= clockTicks; 3.6571 - while (gbLcdLYIncrementTicks <= 0) 3.6572 - { 3.6573 - gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS; 3.6574 - 3.6575 - if (register_LY < 153) 3.6576 - { 3.6577 - register_LY++; 3.6578 - 3.6579 - gbCompareLYToLYC(); 3.6580 - 3.6581 - if (register_LY >= 153) 3.6582 - gbLcdLYIncrementTicks = 6; 3.6583 - } 3.6584 - else 3.6585 - { 3.6586 - register_LY = 0x00; 3.6587 - // reset the window line 3.6588 - gbWindowLine = -1; 3.6589 - gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2; 3.6590 - gbCompareLYToLYC(); 3.6591 - } 3.6592 - } 3.6593 - } 3.6594 - 3.6595 - // our counter is off, see what we need to do 3.6596 - while (gbLcdTicks <= 0) 3.6597 - { 3.6598 - int framesToSkip = systemFramesToSkip(); 3.6599 - 3.6600 - switch (gbLcdMode) 3.6601 - { 3.6602 - case 0: 3.6603 - // H-Blank 3.6604 - register_LY++; 3.6605 - 3.6606 - gbCompareLYToLYC(); 3.6607 - 3.6608 - // check if we reached the V-Blank period 3.6609 - if (register_LY == 144) 3.6610 - { 3.6611 - // Yes, V-Blank 3.6612 - // set the LY increment counter 3.6613 - gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS; 3.6614 - gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS; 3.6615 - gbLcdMode = 1; 3.6616 - if (register_LCDC & 0x80) 3.6617 - { 3.6618 - gbInterrupt |= 1; // V-Blank interrupt 3.6619 - gbInterruptWait = 6; 3.6620 - if (register_STAT & 0x10) 3.6621 - gbInterrupt |= 2; 3.6622 - } 3.6623 - 3.6624 - systemFrame(); 3.6625 - 3.6626 - ++gbFrameCount; 3.6627 - u32 currentTime = systemGetClock(); 3.6628 - if (currentTime - gbLastTime >= 1000) 3.6629 - { 3.6630 - systemShowSpeed(int(float(gbFrameCount) * 100000 / (float(currentTime - gbLastTime) * 60) + .5f)); 3.6631 - gbLastTime = currentTime; 3.6632 - gbFrameCount = 0; 3.6633 - } 3.6634 - 3.6635 - ++GBSystemCounters.frameCount; 3.6636 - if (GBSystemCounters.lagged) 3.6637 - { 3.6638 - ++GBSystemCounters.lagCount; 3.6639 - } 3.6640 - GBSystemCounters.laggedLast = GBSystemCounters.lagged; 3.6641 - GBSystemCounters.lagged = true; 3.6642 - 3.6643 - extern void VBAOnEnteringFrameBoundary(); 3.6644 - VBAOnEnteringFrameBoundary(); 3.6645 - 3.6646 - newFrame = true; 3.6647 - 3.6648 - pauseAfterFrameAdvance = systemPauseOnFrame(); 3.6649 - 3.6650 - if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) 3.6651 - { 3.6652 - if (gbBorderOn) 3.6653 - gbSgbRenderBorder(); // clear unnecessary things on border (e.g. in-game text message) 3.6654 - 3.6655 - systemRenderFrame(); 3.6656 - gbFrameSkipCount = 0; 3.6657 - 3.6658 - bool capturePressed = (extButtons & 2) != 0; 3.6659 - if (capturePressed && !capturePrevious) 3.6660 - { 3.6661 - captureNumber = systemScreenCapture(captureNumber); 3.6662 - } 3.6663 - capturePrevious = capturePressed && !pauseAfterFrameAdvance; 3.6664 - } 3.6665 - else 3.6666 - { 3.6667 - ++gbFrameSkipCount; 3.6668 - } 3.6669 - 3.6670 - if (pauseAfterFrameAdvance) 3.6671 - { 3.6672 - systemSetPause(true); 3.6673 - } 3.6674 - } 3.6675 - else 3.6676 - { 3.6677 - // go the the OAM being accessed mode 3.6678 - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; 3.6679 - gbLcdMode = 2; 3.6680 - 3.6681 - // only one LCD interrupt per line. may need to generalize... 3.6682 - if (!(register_STAT & 0x40) || 3.6683 - (register_LY != register_LYC)) 3.6684 - { 3.6685 - if ((register_STAT & 0x28) == 0x20) 3.6686 - gbInterrupt |= 2; 3.6687 - } 3.6688 - } 3.6689 - 3.6690 - break; 3.6691 - case 1: 3.6692 - // V-Blank 3.6693 - // next mode is OAM being accessed mode 3.6694 - gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS; 3.6695 - gbLcdMode = 2; 3.6696 - if (!(register_STAT & 0x40) || 3.6697 - (register_LY != register_LYC)) 3.6698 - { 3.6699 - if ((register_STAT & 0x28) == 0x20) 3.6700 - gbInterrupt |= 2; 3.6701 - } 3.6702 - break; 3.6703 - case 2: 3.6704 - // OAM being accessed mode 3.6705 - 3.6706 - // next mode is OAM and VRAM in use 3.6707 - gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS; 3.6708 - gbLcdMode = 3; 3.6709 - break; 3.6710 - case 3: 3.6711 - // OAM and VRAM in use 3.6712 - // next mode is H-Blank 3.6713 - if (register_LY < 144) 3.6714 - { 3.6715 - if (!gbSgbMask) 3.6716 - { 3.6717 - if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance) 3.6718 - { 3.6719 - gbRenderLine(); 3.6720 - gbDrawSprites(); 3.6721 - 3.6722 - switch (systemColorDepth) 3.6723 - { 3.6724 - case 16: 3.6725 - 3.6726 - { 3.6727 - u16 *dest = (u16 *)pix + 3.6728 - (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1) 3.6729 - + gbBorderColumnSkip; 3.6730 - for (int x = 0; x < 160; ) 3.6731 - { 3.6732 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6733 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6734 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6735 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6736 - 3.6737 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6738 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6739 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6740 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6741 - 3.6742 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6743 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6744 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6745 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6746 - 3.6747 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6748 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6749 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6750 - *dest++ = systemColorMap16[gbLineMix[x++]]; 3.6751 - } 3.6752 - if (gbBorderOn) 3.6753 - dest += gbBorderColumnSkip; 3.6754 - *dest++ = 0; // for filters that read one pixel more 3.6755 - break; 3.6756 - } 3.6757 - case 24: 3.6758 - 3.6759 - { 3.6760 - u8 *dest = (u8 *)pix + 3.6761 - 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) + 3.6762 - gbBorderColumnSkip); 3.6763 - for (int x = 0; x < 160; ) 3.6764 - { 3.6765 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6766 - dest += 3; 3.6767 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6768 - dest += 3; 3.6769 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6770 - dest += 3; 3.6771 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6772 - dest += 3; 3.6773 - 3.6774 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6775 - dest += 3; 3.6776 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6777 - dest += 3; 3.6778 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6779 - dest += 3; 3.6780 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6781 - dest += 3; 3.6782 - 3.6783 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6784 - dest += 3; 3.6785 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6786 - dest += 3; 3.6787 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6788 - dest += 3; 3.6789 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6790 - dest += 3; 3.6791 - 3.6792 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6793 - dest += 3; 3.6794 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6795 - dest += 3; 3.6796 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6797 - dest += 3; 3.6798 - *((u32 *)dest) = systemColorMap32[gbLineMix[x++]]; 3.6799 - dest += 3; 3.6800 - } 3.6801 - break; 3.6802 - } 3.6803 - case 32: 3.6804 - 3.6805 - { 3.6806 - u32 *dest = (u32 *)pix + 3.6807 - (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1) 3.6808 - + gbBorderColumnSkip; 3.6809 - for (int x = 0; x < 160; ) 3.6810 - { 3.6811 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6812 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6813 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6814 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6815 - 3.6816 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6817 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6818 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6819 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6820 - 3.6821 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6822 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6823 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6824 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6825 - 3.6826 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6827 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6828 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6829 - *dest++ = systemColorMap32[gbLineMix[x++]]; 3.6830 - } 3.6831 - break; 3.6832 - } 3.6833 - } 3.6834 - } 3.6835 - } 3.6836 - } 3.6837 - gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS; 3.6838 - gbLcdMode = 0; 3.6839 - // only one LCD interrupt per line. may need to generalize... 3.6840 - if (!(register_STAT & 0x40) || 3.6841 - (register_LY != register_LYC)) 3.6842 - { 3.6843 - if (register_STAT & 0x08) 3.6844 - gbInterrupt |= 2; 3.6845 - } 3.6846 - if (gbHdmaOn) 3.6847 - { 3.6848 - gbDoHdma(); 3.6849 - } 3.6850 - break; 3.6851 - } 3.6852 - // mark the correct lcd mode on STAT register 3.6853 - register_STAT = (register_STAT & 0xfc) | gbLcdMode; 3.6854 - } 3.6855 - } 3.6856 - 3.6857 - // serial emulation 3.6858 - if (gbSerialOn) 3.6859 - { 3.6860 -#ifdef LINK_EMULATION 3.6861 - if (linkConnected) 3.6862 - { 3.6863 - gbSerialTicks -= clockTicks; 3.6864 - 3.6865 - while (gbSerialTicks <= 0) 3.6866 - { 3.6867 - // increment number of shifted bits 3.6868 - gbSerialBits++; 3.6869 - linkProc(); 3.6870 - if (gbSerialOn && (gbMemory[0xff02] & 1)) 3.6871 - { 3.6872 - if (gbSerialBits == 8) 3.6873 - { 3.6874 - gbSerialBits = 0; 3.6875 - gbMemory[0xff01] = 0xff; 3.6876 - gbMemory[0xff02] &= 0x7f; 3.6877 - gbSerialOn = 0; 3.6878 - gbInterrupt |= 8; 3.6879 - gbSerialTicks = 0; 3.6880 - } 3.6881 - } 3.6882 - gbSerialTicks += GBSERIAL_CLOCK_TICKS; 3.6883 - } 3.6884 - } 3.6885 - else 3.6886 - { 3.6887 -#endif 3.6888 - if (gbMemory[0xff02] & 1) 3.6889 - { 3.6890 - gbSerialTicks -= clockTicks; 3.6891 - 3.6892 - // overflow 3.6893 - while (gbSerialTicks <= 0) 3.6894 - { 3.6895 - // shift serial byte to right and put a 1 bit in its place 3.6896 - // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1); 3.6897 - // increment number of shifted bits 3.6898 - gbSerialBits++; 3.6899 - if (gbSerialBits == 8) 3.6900 - { 3.6901 - // end of transmission 3.6902 - if (gbSerialFunction) // external device 3.6903 - gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]); 3.6904 - else 3.6905 - gbMemory[0xff01] = 0xff; 3.6906 - gbSerialTicks = 0; 3.6907 - gbMemory[0xff02] &= 0x7f; 3.6908 - gbSerialOn = 0; 3.6909 - gbInterrupt |= 8; 3.6910 - gbSerialBits = 0; 3.6911 - } 3.6912 - else 3.6913 - gbSerialTicks += GBSERIAL_CLOCK_TICKS; 3.6914 - } 3.6915 - } 3.6916 -#ifdef LINK_EMULATION 3.6917 - } 3.6918 -#endif 3.6919 - } 3.6920 - 3.6921 - // timer emulation 3.6922 - if (gbTimerOn) 3.6923 - { 3.6924 - gbTimerTicks -= clockTicks; 3.6925 - 3.6926 - while (gbTimerTicks <= 0) 3.6927 - { 3.6928 - register_TIMA++; 3.6929 - 3.6930 - if (register_TIMA == 0) 3.6931 - { 3.6932 - // timer overflow! 3.6933 - 3.6934 - // reload timer modulo 3.6935 - register_TIMA = register_TMA; 3.6936 - 3.6937 - // flag interrupt 3.6938 - gbInterrupt |= 4; 3.6939 - } 3.6940 - 3.6941 - gbTimerTicks += gbTimerClockTicks; 3.6942 - } 3.6943 - } 3.6944 - 3.6945 - /* 3.6946 - if(soundOffFlag) 3.6947 - { 3.6948 - if(synchronize && !speedup) 3.6949 - { 3.6950 - synchronizeTicks -= clockTicks; 3.6951 - 3.6952 - while(synchronizeTicks < 0) 3.6953 - { 3.6954 - synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS; 3.6955 - 3.6956 - DWORD now = timeGetTime(); 3.6957 - gbElapsedTime += (now - timeNow); 3.6958 - 3.6959 - if(gbElapsedTime < 50) 3.6960 - { 3.6961 - DWORD diff = 50 - gbElapsedTime; 3.6962 - Sleep(diff); 3.6963 - timeNow = timeGetTime(); 3.6964 - elapsedTime = timeNow - now - diff; 3.6965 - if((int)elapsedTime < 0) 3.6966 - elapsedTime = 0; 3.6967 - } else 3.6968 - { 3.6969 - timeNow = timeGetTime(); 3.6970 - elapsedTime = 0; 3.6971 - } 3.6972 - } 3.6973 - } 3.6974 - } 3.6975 - */ 3.6976 - 3.6977 - soundTicks -= clockTicks; 3.6978 - while (soundTicks < 0) // must be < 1 when soundtick_t is real data type 3.6979 - { 3.6980 - soundTicks += SOUND_CLOCK_TICKS; 3.6981 - 3.6982 - gbSoundTick(); 3.6983 - } 3.6984 - 3.6985 - register_IF = gbInterrupt; 3.6986 - 3.6987 - if (IFF & 0x20) 3.6988 - { 3.6989 - IFF &= 0xdf; 3.6990 - IFF |= 0x01; 3.6991 - gbInterruptWait = 0; 3.6992 - } 3.6993 - else if (gbInterrupt) 3.6994 - { 3.6995 - if (gbInterruptWait == 0) 3.6996 - { 3.6997 - // gbInterruptWait = 0; 3.6998 - 3.6999 - if (IFF & 0x01) 3.7000 - { 3.7001 - if ((gbInterrupt & 1) && (register_IE & 1)) 3.7002 - { 3.7003 - gbVblank_interrupt(); 3.7004 - continue; 3.7005 - } 3.7006 - 3.7007 - if ((gbInterrupt & 2) && (register_IE & 2)) 3.7008 - { 3.7009 - gbLcd_interrupt(); 3.7010 - continue; 3.7011 - } 3.7012 - 3.7013 - if ((gbInterrupt & 4) && (register_IE & 4)) 3.7014 - { 3.7015 - gbTimer_interrupt(); 3.7016 - continue; 3.7017 - } 3.7018 - 3.7019 - if ((gbInterrupt & 8) && (register_IE & 8)) 3.7020 - { 3.7021 - gbSerial_interrupt(); 3.7022 - continue; 3.7023 - } 3.7024 - 3.7025 - if ((gbInterrupt & 16) && (register_IE & 16)) 3.7026 - { 3.7027 - gbJoypad_interrupt(); 3.7028 - continue; 3.7029 - } 3.7030 - } 3.7031 - } 3.7032 - else 3.7033 - { 3.7034 - gbInterruptWait -= clockTicks; 3.7035 - if (gbInterruptWait < 0) 3.7036 - gbInterruptWait = 0; 3.7037 - } 3.7038 - } 3.7039 - 3.7040 - if (useOldFrameTiming) 3.7041 - { 3.7042 - // old timing code 3.7043 - if (ticksToStop > 0) 3.7044 - continue; 3.7045 - } 3.7046 - else 3.7047 - { 3.7048 - if (!newFrame && (register_LCDC & 0x80) != 0) 3.7049 - continue; 3.7050 - } 3.7051 - 3.7052 - if (!(register_LCDC & 0x80)) 3.7053 - { 3.7054 - if (!useOldFrameTiming) 3.7055 - { 3.7056 - // FIXME: since register_LY can be reset to 0 by some games, frame length is variable 3.7057 - // and infinite loops can occurr 3.7058 - // for now, it IS necessary to do something on this condition or games like 3.7059 - // Megaman would freeze upon low-level restart interrupt sequence (Start+Select+A+B). 3.7060 - // the only sensible way to fix this issue is to implement the RIGHT frame timing 3.7061 -#ifdef WANTS_INCOMPLETE_WORKAROUND 3.7062 - if (systemReadJoypads()) 3.7063 - { 3.7064 - if (gbSgbMode && gbSgbMultiplayer) 3.7065 - { 3.7066 - if (gbSgbFourPlayers) 3.7067 - { 3.7068 - gbJoymask[0] = systemGetJoypad(0, false); 3.7069 - gbJoymask[1] = systemGetJoypad(1, false); 3.7070 - gbJoymask[2] = systemGetJoypad(2, false); 3.7071 - gbJoymask[3] = systemGetJoypad(3, false); 3.7072 - } 3.7073 - else 3.7074 - { 3.7075 - gbJoymask[0] = systemGetJoypad(0, false); 3.7076 - gbJoymask[1] = systemGetJoypad(1, false); 3.7077 - } 3.7078 - } 3.7079 - else 3.7080 - { 3.7081 - gbJoymask[0] = systemGetJoypad(0, false); 3.7082 - } 3.7083 - } 3.7084 - else 3.7085 - gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; 3.7086 + else 3.7087 + gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0; 3.7088 #else 3.7089 #endif 3.7090 - } 3.7091 - } 3.7092 - 3.7093 - // makes sure frames are really divided across input sampling boundaries which occur at a constant rate 3.7094 - if (newFrame || useOldFrameTiming) 3.7095 - { 3.7096 -/// extern void VBAOnEnteringFrameBoundary(); 3.7097 -/// VBAOnEnteringFrameBoundary(); 3.7098 - 3.7099 - break; 3.7100 - } 3.7101 + } 3.7102 } 3.7103 + 3.7104 + // makes sure frames are really divided across input sampling boundaries which occur at a constant rate 3.7105 + if (newFrame || useOldFrameTiming) 3.7106 + { 3.7107 + /// extern void VBAOnEnteringFrameBoundary(); 3.7108 + /// VBAOnEnteringFrameBoundary(); 3.7109 + 3.7110 + break; 3.7111 + } 3.7112 + } 3.7113 } 3.7114 3.7115 struct EmulatedSystem GBSystem = 3.7116 -{ 3.7117 - // emuMain 3.7118 - gbEmulate, 3.7119 - // emuReset 3.7120 - gbReset, 3.7121 - // emuCleanUp 3.7122 - gbCleanUp, 3.7123 - // emuReadBattery 3.7124 - gbReadBatteryFile, 3.7125 - // emuWriteBattery 3.7126 - gbWriteBatteryFile, 3.7127 - // emuReadBatteryFromStream 3.7128 - gbReadBatteryFromStream, 3.7129 - // emuWriteBatteryToStream 3.7130 - gbWriteBatteryToStream, 3.7131 - // emuReadState 3.7132 - gbReadSaveState, 3.7133 - // emuWriteState 3.7134 - gbWriteSaveState, 3.7135 - // emuReadStateFromStream 3.7136 - gbReadSaveStateFromStream, 3.7137 - // emuWriteStateToStream 3.7138 - gbWriteSaveStateToStream, 3.7139 - // emuReadMemState 3.7140 - gbReadMemSaveState, 3.7141 - // emuWriteMemState 3.7142 - gbWriteMemSaveState, 3.7143 - // emuWritePNG 3.7144 - gbWritePNGFile, 3.7145 - // emuWriteBMP 3.7146 - gbWriteBMPFile, 3.7147 - // emuUpdateCPSR 3.7148 - NULL, 3.7149 - // emuHasDebugger 3.7150 - false, 3.7151 - // emuCount 3.7152 + { 3.7153 + // emuMain 3.7154 + gbEmulate, 3.7155 + // emuReset 3.7156 + gbReset, 3.7157 + // emuCleanUp 3.7158 + gbCleanUp, 3.7159 + // emuReadBattery 3.7160 + gbReadBatteryFile, 3.7161 + // emuWriteBattery 3.7162 + gbWriteBatteryFile, 3.7163 + // emuReadBatteryFromStream 3.7164 + gbReadBatteryFromStream, 3.7165 + // emuWriteBatteryToStream 3.7166 + gbWriteBatteryToStream, 3.7167 + // emuReadState 3.7168 + gbReadSaveState, 3.7169 + // emuWriteState 3.7170 + gbWriteSaveState, 3.7171 + // emuReadStateFromStream 3.7172 + gbReadSaveStateFromStream, 3.7173 + // emuWriteStateToStream 3.7174 + gbWriteSaveStateToStream, 3.7175 + // emuReadMemState 3.7176 + gbReadMemSaveState, 3.7177 + // emuWriteMemState 3.7178 + gbWriteMemSaveState, 3.7179 + // emuWritePNG 3.7180 + gbWritePNGFile, 3.7181 + // emuWriteBMP 3.7182 + gbWriteBMPFile, 3.7183 + // emuUpdateCPSR 3.7184 + NULL, 3.7185 + // emuHasDebugger 3.7186 + false, 3.7187 + // emuCount 3.7188 #ifdef FINAL_VERSION 3.7189 - 70000 / 4, 3.7190 + 70000 / 4, 3.7191 #else 3.7192 - 1000, 3.7193 + 1000, 3.7194 #endif 3.7195 -}; 3.7196 + }; 3.7197 3.7198 // is there a reason to use more than one set of counters? 3.7199 EmulatedSystemCounters &GBSystemCounters = systemCounters; 3.7200 3.7201 /* 3.7202 - EmulatedSystemCounters GBSystemCounters = 3.7203 - { 3.7204 - // frameCount 3.7205 - 0, 3.7206 - // lagCount 3.7207 - 0, 3.7208 - // lagged 3.7209 - true, 3.7210 - // laggedLast 3.7211 - true, 3.7212 - }; 3.7213 - */ 3.7214 + EmulatedSystemCounters GBSystemCounters = 3.7215 + { 3.7216 + // frameCount 3.7217 + 0, 3.7218 + // lagCount 3.7219 + 0, 3.7220 + // lagged 3.7221 + true, 3.7222 + // laggedLast 3.7223 + true, 3.7224 + }; 3.7225 +*/
4.1 --- a/src/lua/loadlib.c Sun Mar 04 22:44:42 2012 -0600 4.2 +++ b/src/lua/loadlib.c Mon Mar 05 01:25:11 2012 -0600 4.3 @@ -424,7 +424,7 @@ 4.4 funcname = mkfuncname(L, name); 4.5 if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { 4.6 if (stat != ERRFUNC) loaderror(L, filename); /* real error */ 4.7 - lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, 4.8 + lua_pushfstring(L, "\n\tno module " LUA_QS " in derp " LUA_QS, 4.9 name, filename); 4.10 return 1; /* function not found */ 4.11 }
5.1 --- a/src/sdl/SDL.cpp Sun Mar 04 22:44:42 2012 -0600 5.2 +++ b/src/sdl/SDL.cpp Mon Mar 05 01:25:11 2012 -0600 5.3 @@ -1966,6 +1966,7 @@ 5.4 5.5 void file_run() 5.6 { 5.7 + printf("RLM: file_run\n"); 5.8 utilGetBaseName(szFile, filename); 5.9 char *p = strrchr(filename, '.'); 5.10 5.11 @@ -1989,7 +1990,8 @@ 5.12 failed = !gbLoadRom(szFile); 5.13 if(!failed) { 5.14 systemCartridgeType = 1; 5.15 - theEmulator = GBSystem; 5.16 + printf("RLM: choosing GBSystem\n"); 5.17 + theEmulator = GBSystem; 5.18 if(sdlAutoIPS) { 5.19 int size = gbRomSize; 5.20 utilApplyIPS(ipsname, &gbRom, &size); 5.21 @@ -2007,7 +2009,7 @@ 5.22 // if(cpuEnhancedDetection && cpuSaveType == 0) { 5.23 // utilGBAFindSave(rom, size); 5.24 // } 5.25 - 5.26 + 5.27 sdlApplyPerImagePreferences(); 5.28 5.29 systemCartridgeType = 0; 5.30 @@ -2183,7 +2185,7 @@ 5.31 5.32 case 'r': 5.33 if(optarg == NULL) { 5.34 - fprintf(stderr, "ERROR: --recordMovie ('r') needs movie filename as option\n"); 5.35 + fprintf(stderr, "ERROR: --recordmovie ('r') needs movie filename as option\n"); 5.36 exit(-1); 5.37 } 5.38 strcpy(movieFileName, optarg); 5.39 @@ -2192,7 +2194,7 @@ 5.40 case 'p': // play without read-only (editable) 5.41 fprintf (stderr, "-p got called!\n"); 5.42 if(optarg == NULL) { 5.43 - fprintf(stderr, "ERROR: --playMovie ('p') needs movie filename as option\n"); 5.44 + fprintf(stderr, "ERROR: --playmovie ('p') needs movie filename as option\n"); 5.45 exit(-1); 5.46 } 5.47 strcpy(movieFileName, optarg); 5.48 @@ -2201,7 +2203,7 @@ 5.49 case 'w': // play with read-only 5.50 fprintf (stderr, "-w got called!\n"); 5.51 if(optarg == NULL) { 5.52 - fprintf(stderr, "ERROR: --watchMovie ('w') needs movie filename as option\n"); 5.53 + fprintf(stderr, "ERROR: --watchmovie ('w') needs movie filename as option\n"); 5.54 exit(-1); 5.55 } 5.56 strcpy(movieFileName, optarg); 5.57 @@ -2271,6 +2273,8 @@ 5.58 } 5.59 } 5.60 5.61 + printf("RLM: derpy loves you!\n"); 5.62 + printf("RLM: useMovie: %d (1 is record)\n", useMovie); 5.63 if(sdlPrintUsage) { 5.64 usage(argv[0]); 5.65 exit(-1); 5.66 @@ -2317,6 +2321,7 @@ 5.67 { 5.68 szFile = argv[optind]; 5.69 file_run(); 5.70 + printf("RLM: file_run() done\n"); 5.71 } 5.72 else 5.73 { 5.74 @@ -2336,7 +2341,7 @@ 5.75 5.76 //CPUInit(biosFileName, useBios); 5.77 CPUInit(); 5.78 - CPUReset(); 5.79 + CPUReset(); 5.80 } 5.81 5.82 if(debuggerStub) 5.83 @@ -2615,6 +2620,7 @@ 5.84 soundInit(); 5.85 5.86 autoFrameSkipLastTime = throttleLastTime = systemGetClock(); 5.87 + printf("RLM: and now for the movie part!\n"); 5.88 5.89 switch(useMovie) 5.90 { 5.91 @@ -2635,13 +2641,14 @@ 5.92 sdlReadBattery(); 5.93 break; 5.94 } 5.95 + printf("RLM: still alive after movie switch\n"); 5.96 SDL_WM_SetCaption("VisualBoyAdvance", NULL); 5.97 5.98 char *moviefile = getenv("AUTODEMO"); 5.99 -// fprintf (stderr, "Checking for AUTODEMO...\n"); 5.100 + fprintf (stderr, "Checking for AUTODEMO...\n"); 5.101 if (moviefile) 5.102 { 5.103 -// fprintf (stderr, "I got a filename OMG!\nCalling VBAMovieOpen...\n"); 5.104 + fprintf (stderr, "I got a filename OMG!\nCalling VBAMovieOpen...\n"); 5.105 VBAMovieOpen(moviefile, true); 5.106 } 5.107 5.108 @@ -2650,7 +2657,9 @@ 5.109 if(debugger && theEmulator.emuHasDebugger) 5.110 dbgMain(); 5.111 else { 5.112 - theEmulator.emuMain(theEmulator.emuCount); 5.113 + printf("RLM: emulator main\n"); 5.114 + theEmulator.emuMain(theEmulator.emuCount); 5.115 + printf("RLM: emulator main called\n"); 5.116 if(rewindSaveNeeded && rewindMemory && theEmulator.emuWriteMemState) { 5.117 rewindCount++; 5.118 if(rewindCount > 8) 5.119 @@ -3605,14 +3614,17 @@ 5.120 5.121 void VBAOnEnteringFrameBoundary() 5.122 { 5.123 - CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); 5.124 - 5.125 - if (VBALuaRunning()) 5.126 - { 5.127 - VBALuaFrameBoundary(); 5.128 - } 5.129 - 5.130 - VBAMovieUpdateState(); 5.131 + printf("RLM: Entering Frame Boundary\n"); 5.132 + CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); 5.133 + 5.134 + if (VBALuaRunning()) 5.135 + { 5.136 + VBALuaFrameBoundary(); 5.137 + } 5.138 + 5.139 + printf("RLM: Movie state update pending\n"); 5.140 + VBAMovieUpdateState(); 5.141 + printf("RLM: Movie state updated\n"); 5.142 } 5.143 5.144 void VBAOnExitingFrameBoundary()