Mercurial > vba-clojure
view src/gb/GB.cpp @ 366:985e91060567
saving progress...
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 09 Apr 2012 12:34:29 -0500 |
parents | 893c753f8088 |
children | a6d060a64246 |
line wrap: on
line source
1 #include <cstdio>2 #include <cstdlib>3 #include <cstring>4 #include <cassert>6 #include "../Port.h"7 #include "../NLS.h"8 #include "GB.h"9 #include "gbCheats.h"10 #include "gbGlobals.h"11 #include "gbMemory.h"12 #include "gbSGB.h"13 #include "gbSound.h"14 #include "../common/unzip.h"15 #include "../common/Util.h"16 #include "../common/System.h"17 #include "../common/movie.h"18 // #include "../common/vbalua.h"20 #ifdef __GNUC__21 #define _stricmp strcasecmp22 #endif24 // FIXME: constant (GB) or boolean (GBA)?!25 #define C_FLAG 0x1026 #define H_FLAG 0x2027 #define N_FLAG 0x4028 #define Z_FLAG 0x8029 extern soundtick_t GB_USE_TICKS_AS;31 u8 * origPix = NULL;32 extern u8 * pix;33 extern u32 extButtons;34 extern bool8 capturePrevious;35 extern int32 captureNumber;36 extern bool8 speedup;38 bool gbUpdateSizes();40 // debugging41 bool memorydebug = false;42 char gbBuffer[2048];44 extern u16 gbLineMix[160];46 // mappers47 void (*mapper)(u16, u8) = NULL;48 void (*mapperRAM)(u16, u8) = NULL;49 u8 (*mapperReadRAM)(u16) = NULL;51 // registers52 gbRegister PC;53 gbRegister SP;54 gbRegister AF;55 gbRegister BC;56 gbRegister DE;57 gbRegister HL;58 u16 IFF;59 // 0xff0460 u8 register_DIV = 0;61 // 0xff0562 u8 register_TIMA = 0;63 // 0xff0664 u8 register_TMA = 0;65 // 0xff0766 u8 register_TAC = 0;67 // 0xff0f68 u8 register_IF = 0;69 // 0xff4070 u8 register_LCDC = 0;71 // 0xff4172 u8 register_STAT = 0;73 // 0xff4274 u8 register_SCY = 0;75 // 0xff4376 u8 register_SCX = 0;77 // 0xff4478 u8 register_LY = 0;79 // 0xff4580 u8 register_LYC = 0;81 // 0xff4682 u8 register_DMA = 0;83 // 0xff4a84 u8 register_WY = 0;85 // 0xff4b86 u8 register_WX = 0;87 // 0xff4f88 u8 register_VBK = 0;89 // 0xff5190 u8 register_HDMA1 = 0;91 // 0xff5292 u8 register_HDMA2 = 0;93 // 0xff5394 u8 register_HDMA3 = 0;95 // 0xff5496 u8 register_HDMA4 = 0;97 // 0xff5598 u8 register_HDMA5 = 0;99 // 0xff70100 u8 register_SVBK = 0;101 // 0xffff102 u8 register_IE = 0;104 // ticks definition105 int32 GBDIV_CLOCK_TICKS = 64;106 int32 GBLCD_MODE_0_CLOCK_TICKS = 51;107 int32 GBLCD_MODE_1_CLOCK_TICKS = 1140;108 int32 GBLCD_MODE_2_CLOCK_TICKS = 20;109 int32 GBLCD_MODE_3_CLOCK_TICKS = 43;110 int32 GBLY_INCREMENT_CLOCK_TICKS = 114;111 int32 GBTIMER_MODE_0_CLOCK_TICKS = 256;112 int32 GBTIMER_MODE_1_CLOCK_TICKS = 4;113 int32 GBTIMER_MODE_2_CLOCK_TICKS = 16;114 int32 GBTIMER_MODE_3_CLOCK_TICKS = 64;115 int32 GBSERIAL_CLOCK_TICKS = 128;116 int32 GBSYNCHRONIZE_CLOCK_TICKS = 52920;118 // state variables120 // interrupt121 int32 gbInterrupt = 0;122 int32 gbInterruptWait = 0;123 // serial124 int32 gbSerialOn = 0;125 int32 gbSerialTicks = 0;126 int32 gbSerialBits = 0;127 // timer128 int32 gbTimerOn = 0;129 int32 gbTimerTicks = 0;130 int32 gbTimerClockTicks = 0;131 int32 gbTimerMode = 0;132 // lcd133 int32 gbLcdMode = 2;134 int32 gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS;135 int32 gbLcdLYIncrementTicks = 0;136 // div137 int32 gbDivTicks = GBDIV_CLOCK_TICKS;138 // cgb139 int32 gbVramBank = 0;140 int32 gbWramBank = 1;141 int32 gbHdmaSource = 0x0000;142 int32 gbHdmaDestination = 0x8000;143 int32 gbHdmaBytes = 0x0000;144 int32 gbHdmaOn = 0;145 int32 gbSpeed = 0;146 // frame counting147 int32 gbFrameCount = 0;148 int32 gbFrameSkip = 0;149 int32 gbFrameSkipCount = 0;150 // timing151 u32 gbLastTime = 0;152 u32 gbElapsedTime = 0;153 u32 gbTimeNow = 0;154 int32 gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS;155 int32 gbDMASpeedVersion = 1;156 // emulator features157 int32 gbBattery = 0;158 int32 gbJoymask[4] = { 0, 0, 0, 0 };160 int32 gbEchoRAMFixOn = 1;162 static bool newFrame = true;163 static bool pauseAfterFrameAdvance = false;165 int32 gbRomSizes[] = { 0x00008000, // 32K166 0x00010000, // 64K167 0x00020000, // 128K168 0x00040000, // 256K169 0x00080000, // 512K170 0x00100000, // 1024K171 0x00200000, // 2048K172 0x00400000, // 4096K173 0x00800000 // 8192K174 };175 int32 gbRomSizesMasks[] = { 0x00007fff,176 0x0000ffff,177 0x0001ffff,178 0x0003ffff,179 0x0007ffff,180 0x000fffff,181 0x001fffff,182 0x003fffff,183 0x007fffff };185 int32 gbRamSizes[6] = { 0x00000000, // 0K186 0x00000800, // 2K187 0x00002000, // 8K188 0x00008000, // 32K189 0x00020000, // 128K190 0x00010000 // 64K191 };193 int32 gbRamSizesMasks[6] = { 0x00000000,194 0x000007ff,195 0x00001fff,196 0x00007fff,197 0x0001ffff,198 0x0000ffff };200 int32 gbCycles[] =201 {202 // 0 1 2 3 4 5 6 7 8 9 a b c d e f203 1, 3, 2, 2, 1, 1, 2, 1, 5, 2, 2, 2, 1, 1, 2, 1, // 0204 1, 3, 2, 2, 1, 1, 2, 1, 3, 2, 2, 2, 1, 1, 2, 1, // 1205 2, 3, 2, 2, 1, 1, 2, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 2206 2, 3, 2, 2, 3, 3, 3, 1, 2, 2, 2, 2, 1, 1, 2, 1, // 3207 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 4208 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 5209 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 6210 2, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, // 7211 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 8212 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // 9213 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // a214 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, // b215 2, 3, 3, 4, 3, 4, 2, 4, 2, 4, 3, 2, 3, 6, 2, 4, // c216 2, 3, 3, 0, 3, 4, 2, 4, 2, 4, 3, 0, 3, 0, 2, 4, // d217 3, 3, 2, 0, 0, 4, 2, 4, 4, 1, 4, 0, 0, 0, 2, 4, // e218 3, 3, 2, 1, 0, 4, 2, 4, 3, 2, 4, 1, 0, 0, 2, 4 // f219 };221 int32 gbCyclesCB[] =222 {223 // 0 1 2 3 4 5 6 7 8 9 a b c d e f224 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 0225 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 1226 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 2227 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, // 3228 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 4229 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 5230 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 6231 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 7232 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 8233 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // 9234 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // a235 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // b236 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // c237 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // d238 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, // e239 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2 // f240 };242 u16 DAATable[] =243 {244 0x0080, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700,245 0x0800, 0x0900, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520,246 0x1000, 0x1100, 0x1200, 0x1300, 0x1400, 0x1500, 0x1600, 0x1700,247 0x1800, 0x1900, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520,248 0x2000, 0x2100, 0x2200, 0x2300, 0x2400, 0x2500, 0x2600, 0x2700,249 0x2800, 0x2900, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520,250 0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500, 0x3600, 0x3700,251 0x3800, 0x3900, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520,252 0x4000, 0x4100, 0x4200, 0x4300, 0x4400, 0x4500, 0x4600, 0x4700,253 0x4800, 0x4900, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520,254 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, 0x5500, 0x5600, 0x5700,255 0x5800, 0x5900, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520,256 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, 0x6700,257 0x6800, 0x6900, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520,258 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700,259 0x7800, 0x7900, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520,260 0x8000, 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700,261 0x8800, 0x8900, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520,262 0x9000, 0x9100, 0x9200, 0x9300, 0x9400, 0x9500, 0x9600, 0x9700,263 0x9800, 0x9900, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,264 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710,265 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,266 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710,267 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,268 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710,269 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,270 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710,271 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,272 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710,273 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,274 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710,275 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,276 0x6010, 0x6110, 0x6210, 0x6310, 0x6410, 0x6510, 0x6610, 0x6710,277 0x6810, 0x6910, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530,278 0x7010, 0x7110, 0x7210, 0x7310, 0x7410, 0x7510, 0x7610, 0x7710,279 0x7810, 0x7910, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530,280 0x8010, 0x8110, 0x8210, 0x8310, 0x8410, 0x8510, 0x8610, 0x8710,281 0x8810, 0x8910, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530,282 0x9010, 0x9110, 0x9210, 0x9310, 0x9410, 0x9510, 0x9610, 0x9710,283 0x9810, 0x9910, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530,284 0xA010, 0xA110, 0xA210, 0xA310, 0xA410, 0xA510, 0xA610, 0xA710,285 0xA810, 0xA910, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530,286 0xB010, 0xB110, 0xB210, 0xB310, 0xB410, 0xB510, 0xB610, 0xB710,287 0xB810, 0xB910, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530,288 0xC010, 0xC110, 0xC210, 0xC310, 0xC410, 0xC510, 0xC610, 0xC710,289 0xC810, 0xC910, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530,290 0xD010, 0xD110, 0xD210, 0xD310, 0xD410, 0xD510, 0xD610, 0xD710,291 0xD810, 0xD910, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530,292 0xE010, 0xE110, 0xE210, 0xE310, 0xE410, 0xE510, 0xE610, 0xE710,293 0xE810, 0xE910, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530,294 0xF010, 0xF110, 0xF210, 0xF310, 0xF410, 0xF510, 0xF610, 0xF710,295 0xF810, 0xF910, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,296 0x0090, 0x0110, 0x0210, 0x0310, 0x0410, 0x0510, 0x0610, 0x0710,297 0x0810, 0x0910, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,298 0x1010, 0x1110, 0x1210, 0x1310, 0x1410, 0x1510, 0x1610, 0x1710,299 0x1810, 0x1910, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,300 0x2010, 0x2110, 0x2210, 0x2310, 0x2410, 0x2510, 0x2610, 0x2710,301 0x2810, 0x2910, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,302 0x3010, 0x3110, 0x3210, 0x3310, 0x3410, 0x3510, 0x3610, 0x3710,303 0x3810, 0x3910, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,304 0x4010, 0x4110, 0x4210, 0x4310, 0x4410, 0x4510, 0x4610, 0x4710,305 0x4810, 0x4910, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,306 0x5010, 0x5110, 0x5210, 0x5310, 0x5410, 0x5510, 0x5610, 0x5710,307 0x5810, 0x5910, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,308 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00,309 0x0E00, 0x0F00, 0x1020, 0x1120, 0x1220, 0x1320, 0x1420, 0x1520,310 0x1600, 0x1700, 0x1800, 0x1900, 0x1A00, 0x1B00, 0x1C00, 0x1D00,311 0x1E00, 0x1F00, 0x2020, 0x2120, 0x2220, 0x2320, 0x2420, 0x2520,312 0x2600, 0x2700, 0x2800, 0x2900, 0x2A00, 0x2B00, 0x2C00, 0x2D00,313 0x2E00, 0x2F00, 0x3020, 0x3120, 0x3220, 0x3320, 0x3420, 0x3520,314 0x3600, 0x3700, 0x3800, 0x3900, 0x3A00, 0x3B00, 0x3C00, 0x3D00,315 0x3E00, 0x3F00, 0x4020, 0x4120, 0x4220, 0x4320, 0x4420, 0x4520,316 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00, 0x4B00, 0x4C00, 0x4D00,317 0x4E00, 0x4F00, 0x5020, 0x5120, 0x5220, 0x5320, 0x5420, 0x5520,318 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x5C00, 0x5D00,319 0x5E00, 0x5F00, 0x6020, 0x6120, 0x6220, 0x6320, 0x6420, 0x6520,320 0x6600, 0x6700, 0x6800, 0x6900, 0x6A00, 0x6B00, 0x6C00, 0x6D00,321 0x6E00, 0x6F00, 0x7020, 0x7120, 0x7220, 0x7320, 0x7420, 0x7520,322 0x7600, 0x7700, 0x7800, 0x7900, 0x7A00, 0x7B00, 0x7C00, 0x7D00,323 0x7E00, 0x7F00, 0x8020, 0x8120, 0x8220, 0x8320, 0x8420, 0x8520,324 0x8600, 0x8700, 0x8800, 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x8D00,325 0x8E00, 0x8F00, 0x9020, 0x9120, 0x9220, 0x9320, 0x9420, 0x9520,326 0x9600, 0x9700, 0x9800, 0x9900, 0x9A00, 0x9B00, 0x9C00, 0x9D00,327 0x9E00, 0x9F00, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,328 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10,329 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,330 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10,331 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,332 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10,333 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,334 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10,335 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,336 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10,337 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,338 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10,339 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,340 0x6610, 0x6710, 0x6810, 0x6910, 0x6A10, 0x6B10, 0x6C10, 0x6D10,341 0x6E10, 0x6F10, 0x7030, 0x7130, 0x7230, 0x7330, 0x7430, 0x7530,342 0x7610, 0x7710, 0x7810, 0x7910, 0x7A10, 0x7B10, 0x7C10, 0x7D10,343 0x7E10, 0x7F10, 0x8030, 0x8130, 0x8230, 0x8330, 0x8430, 0x8530,344 0x8610, 0x8710, 0x8810, 0x8910, 0x8A10, 0x8B10, 0x8C10, 0x8D10,345 0x8E10, 0x8F10, 0x9030, 0x9130, 0x9230, 0x9330, 0x9430, 0x9530,346 0x9610, 0x9710, 0x9810, 0x9910, 0x9A10, 0x9B10, 0x9C10, 0x9D10,347 0x9E10, 0x9F10, 0xA030, 0xA130, 0xA230, 0xA330, 0xA430, 0xA530,348 0xA610, 0xA710, 0xA810, 0xA910, 0xAA10, 0xAB10, 0xAC10, 0xAD10,349 0xAE10, 0xAF10, 0xB030, 0xB130, 0xB230, 0xB330, 0xB430, 0xB530,350 0xB610, 0xB710, 0xB810, 0xB910, 0xBA10, 0xBB10, 0xBC10, 0xBD10,351 0xBE10, 0xBF10, 0xC030, 0xC130, 0xC230, 0xC330, 0xC430, 0xC530,352 0xC610, 0xC710, 0xC810, 0xC910, 0xCA10, 0xCB10, 0xCC10, 0xCD10,353 0xCE10, 0xCF10, 0xD030, 0xD130, 0xD230, 0xD330, 0xD430, 0xD530,354 0xD610, 0xD710, 0xD810, 0xD910, 0xDA10, 0xDB10, 0xDC10, 0xDD10,355 0xDE10, 0xDF10, 0xE030, 0xE130, 0xE230, 0xE330, 0xE430, 0xE530,356 0xE610, 0xE710, 0xE810, 0xE910, 0xEA10, 0xEB10, 0xEC10, 0xED10,357 0xEE10, 0xEF10, 0xF030, 0xF130, 0xF230, 0xF330, 0xF430, 0xF530,358 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, 0xFC10, 0xFD10,359 0xFE10, 0xFF10, 0x00B0, 0x0130, 0x0230, 0x0330, 0x0430, 0x0530,360 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, 0x0C10, 0x0D10,361 0x0E10, 0x0F10, 0x1030, 0x1130, 0x1230, 0x1330, 0x1430, 0x1530,362 0x1610, 0x1710, 0x1810, 0x1910, 0x1A10, 0x1B10, 0x1C10, 0x1D10,363 0x1E10, 0x1F10, 0x2030, 0x2130, 0x2230, 0x2330, 0x2430, 0x2530,364 0x2610, 0x2710, 0x2810, 0x2910, 0x2A10, 0x2B10, 0x2C10, 0x2D10,365 0x2E10, 0x2F10, 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530,366 0x3610, 0x3710, 0x3810, 0x3910, 0x3A10, 0x3B10, 0x3C10, 0x3D10,367 0x3E10, 0x3F10, 0x4030, 0x4130, 0x4230, 0x4330, 0x4430, 0x4530,368 0x4610, 0x4710, 0x4810, 0x4910, 0x4A10, 0x4B10, 0x4C10, 0x4D10,369 0x4E10, 0x4F10, 0x5030, 0x5130, 0x5230, 0x5330, 0x5430, 0x5530,370 0x5610, 0x5710, 0x5810, 0x5910, 0x5A10, 0x5B10, 0x5C10, 0x5D10,371 0x5E10, 0x5F10, 0x6030, 0x6130, 0x6230, 0x6330, 0x6430, 0x6530,372 0x00C0, 0x0140, 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740,373 0x0840, 0x0940, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940,374 0x1040, 0x1140, 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740,375 0x1840, 0x1940, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940,376 0x2040, 0x2140, 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740,377 0x2840, 0x2940, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940,378 0x3040, 0x3140, 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740,379 0x3840, 0x3940, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940,380 0x4040, 0x4140, 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740,381 0x4840, 0x4940, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940,382 0x5040, 0x5140, 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740,383 0x5840, 0x5940, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940,384 0x6040, 0x6140, 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740,385 0x6840, 0x6940, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940,386 0x7040, 0x7140, 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740,387 0x7840, 0x7940, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940,388 0x8040, 0x8140, 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740,389 0x8840, 0x8940, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940,390 0x9040, 0x9140, 0x9240, 0x9340, 0x9440, 0x9540, 0x9640, 0x9740,391 0x9840, 0x9940, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,392 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750,393 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,394 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750,395 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,396 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750,397 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,398 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750,399 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,400 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750,401 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,402 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750,403 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,404 0xA050, 0xA150, 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750,405 0xA850, 0xA950, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950,406 0xB050, 0xB150, 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750,407 0xB850, 0xB950, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950,408 0xC050, 0xC150, 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750,409 0xC850, 0xC950, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950,410 0xD050, 0xD150, 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750,411 0xD850, 0xD950, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950,412 0xE050, 0xE150, 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750,413 0xE850, 0xE950, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950,414 0xF050, 0xF150, 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750,415 0xF850, 0xF950, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950,416 0x00D0, 0x0150, 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750,417 0x0850, 0x0950, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950,418 0x1050, 0x1150, 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750,419 0x1850, 0x1950, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950,420 0x2050, 0x2150, 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750,421 0x2850, 0x2950, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950,422 0x3050, 0x3150, 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750,423 0x3850, 0x3950, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,424 0x4050, 0x4150, 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750,425 0x4850, 0x4950, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,426 0x5050, 0x5150, 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750,427 0x5850, 0x5950, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,428 0x6050, 0x6150, 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750,429 0x6850, 0x6950, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,430 0x7050, 0x7150, 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750,431 0x7850, 0x7950, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,432 0x8050, 0x8150, 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750,433 0x8850, 0x8950, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,434 0x9050, 0x9150, 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750,435 0x9850, 0x9950, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,436 0xFA60, 0xFB60, 0xFC60, 0xFD60, 0xFE60, 0xFF60, 0x00C0, 0x0140,437 0x0240, 0x0340, 0x0440, 0x0540, 0x0640, 0x0740, 0x0840, 0x0940,438 0x0A60, 0x0B60, 0x0C60, 0x0D60, 0x0E60, 0x0F60, 0x1040, 0x1140,439 0x1240, 0x1340, 0x1440, 0x1540, 0x1640, 0x1740, 0x1840, 0x1940,440 0x1A60, 0x1B60, 0x1C60, 0x1D60, 0x1E60, 0x1F60, 0x2040, 0x2140,441 0x2240, 0x2340, 0x2440, 0x2540, 0x2640, 0x2740, 0x2840, 0x2940,442 0x2A60, 0x2B60, 0x2C60, 0x2D60, 0x2E60, 0x2F60, 0x3040, 0x3140,443 0x3240, 0x3340, 0x3440, 0x3540, 0x3640, 0x3740, 0x3840, 0x3940,444 0x3A60, 0x3B60, 0x3C60, 0x3D60, 0x3E60, 0x3F60, 0x4040, 0x4140,445 0x4240, 0x4340, 0x4440, 0x4540, 0x4640, 0x4740, 0x4840, 0x4940,446 0x4A60, 0x4B60, 0x4C60, 0x4D60, 0x4E60, 0x4F60, 0x5040, 0x5140,447 0x5240, 0x5340, 0x5440, 0x5540, 0x5640, 0x5740, 0x5840, 0x5940,448 0x5A60, 0x5B60, 0x5C60, 0x5D60, 0x5E60, 0x5F60, 0x6040, 0x6140,449 0x6240, 0x6340, 0x6440, 0x6540, 0x6640, 0x6740, 0x6840, 0x6940,450 0x6A60, 0x6B60, 0x6C60, 0x6D60, 0x6E60, 0x6F60, 0x7040, 0x7140,451 0x7240, 0x7340, 0x7440, 0x7540, 0x7640, 0x7740, 0x7840, 0x7940,452 0x7A60, 0x7B60, 0x7C60, 0x7D60, 0x7E60, 0x7F60, 0x8040, 0x8140,453 0x8240, 0x8340, 0x8440, 0x8540, 0x8640, 0x8740, 0x8840, 0x8940,454 0x8A60, 0x8B60, 0x8C60, 0x8D60, 0x8E60, 0x8F60, 0x9040, 0x9140,455 0x9240, 0x9340, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,456 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150,457 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,458 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150,459 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,460 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150,461 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,462 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150,463 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,464 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150,465 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,466 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150,467 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,468 0x9A70, 0x9B70, 0x9C70, 0x9D70, 0x9E70, 0x9F70, 0xA050, 0xA150,469 0xA250, 0xA350, 0xA450, 0xA550, 0xA650, 0xA750, 0xA850, 0xA950,470 0xAA70, 0xAB70, 0xAC70, 0xAD70, 0xAE70, 0xAF70, 0xB050, 0xB150,471 0xB250, 0xB350, 0xB450, 0xB550, 0xB650, 0xB750, 0xB850, 0xB950,472 0xBA70, 0xBB70, 0xBC70, 0xBD70, 0xBE70, 0xBF70, 0xC050, 0xC150,473 0xC250, 0xC350, 0xC450, 0xC550, 0xC650, 0xC750, 0xC850, 0xC950,474 0xCA70, 0xCB70, 0xCC70, 0xCD70, 0xCE70, 0xCF70, 0xD050, 0xD150,475 0xD250, 0xD350, 0xD450, 0xD550, 0xD650, 0xD750, 0xD850, 0xD950,476 0xDA70, 0xDB70, 0xDC70, 0xDD70, 0xDE70, 0xDF70, 0xE050, 0xE150,477 0xE250, 0xE350, 0xE450, 0xE550, 0xE650, 0xE750, 0xE850, 0xE950,478 0xEA70, 0xEB70, 0xEC70, 0xED70, 0xEE70, 0xEF70, 0xF050, 0xF150,479 0xF250, 0xF350, 0xF450, 0xF550, 0xF650, 0xF750, 0xF850, 0xF950,480 0xFA70, 0xFB70, 0xFC70, 0xFD70, 0xFE70, 0xFF70, 0x00D0, 0x0150,481 0x0250, 0x0350, 0x0450, 0x0550, 0x0650, 0x0750, 0x0850, 0x0950,482 0x0A70, 0x0B70, 0x0C70, 0x0D70, 0x0E70, 0x0F70, 0x1050, 0x1150,483 0x1250, 0x1350, 0x1450, 0x1550, 0x1650, 0x1750, 0x1850, 0x1950,484 0x1A70, 0x1B70, 0x1C70, 0x1D70, 0x1E70, 0x1F70, 0x2050, 0x2150,485 0x2250, 0x2350, 0x2450, 0x2550, 0x2650, 0x2750, 0x2850, 0x2950,486 0x2A70, 0x2B70, 0x2C70, 0x2D70, 0x2E70, 0x2F70, 0x3050, 0x3150,487 0x3250, 0x3350, 0x3450, 0x3550, 0x3650, 0x3750, 0x3850, 0x3950,488 0x3A70, 0x3B70, 0x3C70, 0x3D70, 0x3E70, 0x3F70, 0x4050, 0x4150,489 0x4250, 0x4350, 0x4450, 0x4550, 0x4650, 0x4750, 0x4850, 0x4950,490 0x4A70, 0x4B70, 0x4C70, 0x4D70, 0x4E70, 0x4F70, 0x5050, 0x5150,491 0x5250, 0x5350, 0x5450, 0x5550, 0x5650, 0x5750, 0x5850, 0x5950,492 0x5A70, 0x5B70, 0x5C70, 0x5D70, 0x5E70, 0x5F70, 0x6050, 0x6150,493 0x6250, 0x6350, 0x6450, 0x6550, 0x6650, 0x6750, 0x6850, 0x6950,494 0x6A70, 0x6B70, 0x6C70, 0x6D70, 0x6E70, 0x6F70, 0x7050, 0x7150,495 0x7250, 0x7350, 0x7450, 0x7550, 0x7650, 0x7750, 0x7850, 0x7950,496 0x7A70, 0x7B70, 0x7C70, 0x7D70, 0x7E70, 0x7F70, 0x8050, 0x8150,497 0x8250, 0x8350, 0x8450, 0x8550, 0x8650, 0x8750, 0x8850, 0x8950,498 0x8A70, 0x8B70, 0x8C70, 0x8D70, 0x8E70, 0x8F70, 0x9050, 0x9150,499 0x9250, 0x9350, 0x9450, 0x9550, 0x9650, 0x9750, 0x9850, 0x9950,500 };502 u8 ZeroTable[] =503 {504 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,505 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,506 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,508 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,516 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,517 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,518 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,519 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0520 };522 #define GBSAVE_GAME_VERSION_1 1523 #define GBSAVE_GAME_VERSION_2 2524 #define GBSAVE_GAME_VERSION_3 3525 #define GBSAVE_GAME_VERSION_4 4526 #define GBSAVE_GAME_VERSION_5 5527 #define GBSAVE_GAME_VERSION_6 6528 #define GBSAVE_GAME_VERSION_7 7529 #define GBSAVE_GAME_VERSION_8 8530 #define GBSAVE_GAME_VERSION_9 9531 #define GBSAVE_GAME_VERSION_10 10532 #define GBSAVE_GAME_VERSION_11 11533 #define GBSAVE_GAME_VERSION_12 12534 #define GBSAVE_GAME_VERSION_13 13535 #define GBSAVE_GAME_VERSION GBSAVE_GAME_VERSION_13537 int inline gbGetValue(int min, int max, int v)538 {539 return (int)(min + (float)(max - min) * (2.0 * (v / 31.0) - (v / 31.0) * (v / 31.0)));540 }542 void gbGenFilter()543 {544 for (int r = 0; r < 32; r++)545 {546 for (int g = 0; g < 32; g++)547 {548 for (int b = 0; b < 32; b++)549 {550 int nr = gbGetValue(gbGetValue(4, 14, g),551 gbGetValue(24, 29, g), r) - 4;552 int ng = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r),553 14 + gbGetValue(0, 3, r), b),554 gbGetValue(24 + gbGetValue(0, 3, r),555 29 + gbGetValue(0, 1, r), b), g) - 4;556 int nb = gbGetValue(gbGetValue(4 + gbGetValue(0, 5, r),557 14 + gbGetValue(0, 3, r), g),558 gbGetValue(24 + gbGetValue(0, 3, r),559 29 + gbGetValue(0, 1, r), g), b) - 4;560 gbColorFilter[(b << 10) | (g << 5) | r] = (nb << 10) | (ng << 5) | nr;561 }562 }563 }564 }566 void gbCopyMemory(u16 d, u16 s, int count)567 {568 while (count)569 {570 gbWriteMemoryQuick(d, gbReadMemoryQuick(s));571 s++;572 d++;573 count--;574 }575 }577 void gbDoHdma()578 {579 gbCopyMemory(gbHdmaDestination, gbHdmaSource, 0x10);581 gbHdmaDestination += 0x10;582 gbHdmaSource += 0x10;584 register_HDMA2 = (register_HDMA2 + 0x10) & 0xFF;585 if (register_HDMA2 == 0x00)586 register_HDMA1++;588 register_HDMA4 = (register_HDMA4 + 0x10) & 0xFF;589 if (register_HDMA4 == 0x00)590 register_HDMA3++;592 if (gbHdmaDestination == 0x96b0)593 gbHdmaBytes = gbHdmaBytes;594 gbHdmaBytes -= 0x10;595 register_HDMA5--;596 if (register_HDMA5 == 0xff)597 gbHdmaOn = 0;598 }600 // fix for Harley and Lego Racers601 void gbCompareLYToLYC()602 {603 if (register_LY == register_LYC)604 {605 // mark that we have a match606 register_STAT |= 4;608 // check if we need an interrupt609 if ((register_STAT & 0x40) && (register_IE & 2))610 gbInterrupt |= 2;611 }612 else // no match613 register_STAT &= 0xfb;614 }616 // FIXME: horrible kludge to workaround the frame timing bug617 static int32 s_gbJoymask[4] = { 0, 0, 0, 0 };619 void gbWriteMemoryWrapped(register u16 address, register u8 value)620 {621 if (address < 0x8000)622 {623 #ifndef FINAL_VERSION624 if (memorydebug && (address > 0x3fff || address < 0x2000))625 {626 log("Memory register write %04x=%02x PC=%04x\n",627 address,628 value,629 PC.W);630 }631 #endif632 if (mapper)633 (*mapper)(address, value);634 return;635 }637 if (address < 0xa000)638 {639 gbWriteMemoryQuick(address, value);640 return;641 }643 if (address < 0xc000)644 {645 #ifndef FINAL_VERSION646 if (memorydebug)647 {648 log("Memory register write %04x=%02x PC=%04x\n",649 address,650 value,651 PC.W);652 }653 #endif655 if (mapper)656 (*mapperRAM)(address, value);657 return;658 }660 if (address < 0xfe00)661 {662 gbWriteMemoryQuick(address, value);663 return;664 }666 if (address < 0xff00)667 {668 gbMemory[address] = value;669 return;670 }672 switch (address & 0x00ff)673 {674 case 0x00:675 {676 gbMemory[0xff00] = ((gbMemory[0xff00] & 0xcf) |677 (value & 0x30));678 if (gbSgbMode)679 {680 gbSgbDoBitTransfer(value);681 }683 return;684 }686 case 0x01:687 {688 gbMemory[0xff01] = value;689 return;690 }692 // serial control693 case 0x02:694 {695 gbSerialOn = (value & 0x80);696 gbMemory[0xff02] = value;697 if (gbSerialOn)698 {699 gbSerialTicks = GBSERIAL_CLOCK_TICKS;700 #ifdef LINK_EMULATION701 if (linkConnected)702 {703 if (value & 1)704 {705 linkSendByte(0x100 | gbMemory[0xFF01]);706 Sleep(5);707 }708 }709 #endif710 }712 gbSerialBits = 0;713 return;714 }716 // DIV register resets on any write717 case 0x04:718 {719 register_DIV = 0;720 return;721 }722 case 0x05:723 register_TIMA = value;724 return;726 case 0x06:727 register_TMA = value;728 return;730 // TIMER control731 case 0x07:732 {733 register_TAC = value;735 gbTimerOn = (value & 4);736 gbTimerMode = value & 3;737 // register_TIMA = register_TMA;738 switch (gbTimerMode)739 {740 case 0:741 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_0_CLOCK_TICKS;742 break;743 case 1:744 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_1_CLOCK_TICKS;745 break;746 case 2:747 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_2_CLOCK_TICKS;748 break;749 case 3:750 gbTimerClockTicks = gbTimerTicks = GBTIMER_MODE_3_CLOCK_TICKS;751 break;752 }753 return;754 }756 case 0x0f:757 {758 register_IF = value;759 gbInterrupt = value;760 return;761 }763 case 0x10:764 case 0x11:765 case 0x12:766 case 0x13:767 case 0x14:768 case 0x15:769 case 0x16:770 case 0x17:771 case 0x18:772 case 0x19:773 case 0x1a:774 case 0x1b:775 case 0x1c:776 case 0x1d:777 case 0x1e:778 case 0x1f:779 case 0x20:780 case 0x21:781 case 0x22:782 case 0x23:783 case 0x24:784 case 0x25:785 case 0x26:786 {787 SOUND_EVENT(address, value);788 return;789 }790 case 0x40:791 {792 int lcdChange = (register_LCDC & 0x80) ^ (value & 0x80);794 if (lcdChange)795 {796 if (value & 0x80)797 {798 gbLcdTicks = GBLCD_MODE_1_CLOCK_TICKS;799 gbLcdMode = 0;800 register_STAT &= 0xfc;801 register_LY = 0x00;802 // FIXME: horrible workaround803 if (gbNullInputHackTempEnabled && !useOldFrameTiming)804 memcpy(gbJoymask, s_gbJoymask, sizeof(gbJoymask));805 }806 else807 {808 gbLcdTicks = 0;809 gbLcdMode = 0;810 register_STAT &= 0xfc;811 register_LY = 0x00;812 // FIXME: horrible workaround813 memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask));814 if (gbNullInputHackTempEnabled && !useOldFrameTiming)815 memset(gbJoymask, 0, sizeof(gbJoymask));816 }817 // compareLYToLYC();818 }819 // don't draw the window if it was not enabled and not being drawn before820 if (!(register_LCDC & 0x20) && (value & 0x20) && gbWindowLine == -1 &&821 register_LY > register_WY)822 gbWindowLine = 144;824 register_LCDC = value;826 return;827 }829 // STAT830 case 0x41:831 {832 //register_STAT = (register_STAT & 0x87) |833 // (value & 0x7c);834 register_STAT = (value & 0xf8) | (register_STAT & 0x07); // fix ?835 // GB bug from Devrs FAQ836 if (!gbCgbMode && (register_LCDC & 0x80) && gbLcdMode < 2)837 gbInterrupt |= 2;838 return;839 }841 // SCY842 case 0x42:843 {844 register_SCY = value;845 return;846 }848 // SCX849 case 0x43:850 {851 register_SCX = value;852 return;853 }855 // LY856 case 0x44:857 {858 // read only859 return;860 }862 // LYC863 case 0x45:864 {865 register_LYC = value;866 if ((register_LCDC & 0x80))867 {868 gbCompareLYToLYC();869 }870 return;871 }873 // DMA!874 case 0x46:875 {876 int source = value * 0x0100;878 gbCopyMemory(0xfe00,879 source,880 0xa0);881 register_DMA = value;882 return;883 }885 // BGP886 case 0x47:887 {888 gbBgp[0] = value & 0x03;889 gbBgp[1] = (value & 0x0c) >> 2;890 gbBgp[2] = (value & 0x30) >> 4;891 gbBgp[3] = (value & 0xc0) >> 6;892 break;893 }895 // OBP0896 case 0x48:897 {898 gbObp0[0] = value & 0x03;899 gbObp0[1] = (value & 0x0c) >> 2;900 gbObp0[2] = (value & 0x30) >> 4;901 gbObp0[3] = (value & 0xc0) >> 6;902 break;903 }905 // OBP1906 case 0x49:907 {908 gbObp1[0] = value & 0x03;909 gbObp1[1] = (value & 0x0c) >> 2;910 gbObp1[2] = (value & 0x30) >> 4;911 gbObp1[3] = (value & 0xc0) >> 6;912 break;913 }915 case 0x4a:916 register_WY = value;917 return;919 case 0x4b:920 register_WX = value;921 return;923 // KEY1924 case 0x4d:925 {926 if (gbCgbMode)927 {928 gbMemory[0xff4d] = (gbMemory[0xff4d] & 0x80) | (value & 1);929 return;930 }931 break;932 }934 // VBK935 case 0x4f:936 {937 if (gbCgbMode)938 {939 value = value & 1;940 if (value == gbVramBank)941 return;943 int vramAddress = value * 0x2000;944 gbMemoryMap[0x08] = &gbVram[vramAddress];945 gbMemoryMap[0x09] = &gbVram[vramAddress + 0x1000];947 gbVramBank = value;948 register_VBK = value;949 }950 return;951 break;952 }954 // HDMA1955 case 0x51:956 {957 if (gbCgbMode)958 {959 if (value > 0x7f && value < 0xa0)960 value = 0;962 gbHdmaSource = (value << 8) | (register_HDMA2 & 0xf0);964 register_HDMA1 = value;965 return;966 }967 break;968 }970 // HDMA2971 case 0x52:972 {973 if (gbCgbMode)974 {975 value = value & 0xf0;977 gbHdmaSource = (register_HDMA1 << 8) | (value);979 register_HDMA2 = value;980 return;981 }982 break;983 }985 // HDMA3986 case 0x53:987 {988 if (gbCgbMode)989 {990 value = value & 0x1f;991 gbHdmaDestination = (value << 8) | (register_HDMA4 & 0xf0);992 gbHdmaDestination += 0x8000;993 register_HDMA3 = value;994 return;995 }996 break;997 }999 // HDMA41000 case 0x54:1001 {1002 if (gbCgbMode)1003 {1004 value = value & 0xf0;1005 gbHdmaDestination = ((register_HDMA3 & 0x1f) << 8) | value;1006 gbHdmaDestination += 0x8000;1007 register_HDMA4 = value;1008 return;1009 }1010 break;1011 }1013 // HDMA51014 case 0x55:1015 {1016 if (gbCgbMode)1017 {1018 gbHdmaBytes = 16 + (value & 0x7f) * 16;1019 if (gbHdmaOn)1020 {1021 if (value & 0x80)1022 {1023 register_HDMA5 = (value & 0x7f);1024 }1025 else1026 {1027 register_HDMA5 = 0xff;1028 gbHdmaOn = 0;1029 }1030 }1031 else1032 {1033 if (value & 0x80)1034 {1035 gbHdmaOn = 1;1036 register_HDMA5 = value & 0x7f;1037 if (gbLcdMode == 0)1038 gbDoHdma();1039 }1040 else1041 {1042 // we need to take the time it takes to complete the transfer into1043 // account... according to GB DEV FAQs, the setup time is the same1044 // for single and double speed, but the actual transfer takes the1045 // same time // (is that a typo?)1046 switch (gbDMASpeedVersion)1047 {1048 case 1: // I believe this is more correct1049 // the lower 7 bits of FF55 specify the Transfer Length (divided by 16, minus 1)1050 // and we make gbDmaTicks twice as many cycles at double speed to make the transfer take the same time1051 if (gbSpeed)1052 gbDmaTicks = 16 * ((value & 0x7f) + 1);1053 else1054 gbDmaTicks = 8 * ((value & 0x7f) + 1);1055 break;1056 case 0: // here for backward compatibility1057 // I think this was a guess that approximates the above in most but not all games1058 if (gbSpeed)1059 gbDmaTicks = 231 + 16 * (value & 0x7f);1060 else1061 gbDmaTicks = 231 + 8 * (value & 0x7f);1062 break;1063 default: // shouldn't happen1064 //assert(0);1065 break;1066 }1067 gbCopyMemory(gbHdmaDestination, gbHdmaSource, gbHdmaBytes);1068 gbHdmaDestination += gbHdmaBytes;1069 gbHdmaSource += gbHdmaBytes;1071 register_HDMA3 = ((gbHdmaDestination - 0x8000) >> 8) & 0x1f;1072 register_HDMA4 = gbHdmaDestination & 0xf0;1073 register_HDMA1 = (gbHdmaSource >> 8) & 0xff;1074 register_HDMA2 = gbHdmaSource & 0xf0;1075 }1076 }1077 return;1078 }1079 break;1080 }1082 // BCPS1083 case 0x68:1084 {1085 if (gbCgbMode)1086 {1087 int paletteIndex = (value & 0x3f) >> 1;1088 int paletteHiLo = (value & 0x01);1090 gbMemory[0xff68] = value;1091 gbMemory[0xff69] = (paletteHiLo ?1092 (gbPalette[paletteIndex] >> 8) :1093 (gbPalette[paletteIndex] & 0x00ff));1094 return;1095 }1096 break;1097 }1099 // BCPD1100 case 0x69:1101 {1102 if (gbCgbMode)1103 {1104 int v = gbMemory[0xff68];1105 int paletteIndex = (v & 0x3f) >> 1;1106 int paletteHiLo = (v & 0x01);1107 gbMemory[0xff69] = value;1108 gbPalette[paletteIndex] = (paletteHiLo ?1109 ((value << 8) | (gbPalette[paletteIndex] & 0xff)) :1110 ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff;1112 if (gbMemory[0xff68] & 0x80)1113 {1114 int index = ((gbMemory[0xff68] & 0x3f) + 1) & 0x3f;1116 gbMemory[0xff68] = (gbMemory[0xff68] & 0x80) | index;1118 gbMemory[0xff69] = (index & 1 ?1119 (gbPalette[index >> 1] >> 8) :1120 (gbPalette[index >> 1] & 0x00ff));1121 }1122 return;1123 }1124 break;1125 }1127 // OCPS1128 case 0x6a:1129 {1130 if (gbCgbMode)1131 {1132 int paletteIndex = (value & 0x3f) >> 1;1133 int paletteHiLo = (value & 0x01);1135 paletteIndex += 32;1137 gbMemory[0xff6a] = value;1138 gbMemory[0xff6b] = (paletteHiLo ?1139 (gbPalette[paletteIndex] >> 8) :1140 (gbPalette[paletteIndex] & 0x00ff));1141 return;1142 }1143 break;1144 }1146 // OCPD1147 case 0x6b:1148 {1149 if (gbCgbMode)1150 {1151 int v = gbMemory[0xff6a];1152 int paletteIndex = (v & 0x3f) >> 1;1153 int paletteHiLo = (v & 0x01);1155 paletteIndex += 32;1157 gbMemory[0xff6b] = value;1158 gbPalette[paletteIndex] = (paletteHiLo ?1159 ((value << 8) | (gbPalette[paletteIndex] & 0xff)) :1160 ((gbPalette[paletteIndex] & 0xff00) | (value))) & 0x7fff;1161 if (gbMemory[0xff6a] & 0x80)1162 {1163 int index = ((gbMemory[0xff6a] & 0x3f) + 1) & 0x3f;1165 gbMemory[0xff6a] = (gbMemory[0xff6a] & 0x80) | index;1167 gbMemory[0xff6b] = (index & 1 ?1168 (gbPalette[(index >> 1) + 32] >> 8) :1169 (gbPalette[(index >> 1) + 32] & 0x00ff));1170 }1171 return;1172 }1173 break;1174 }1176 // SVBK1177 case 0x70:1178 {1179 if (gbCgbMode)1180 {1181 value = value & 7;1183 int bank = value;1184 if (value == 0)1185 bank = 1;1187 if (bank == gbWramBank)1188 return;1190 int wramAddress = bank * 0x1000;1191 gbMemoryMap[0x0d] = &gbWram[wramAddress];1193 gbWramBank = bank;1194 register_SVBK = value;1195 return;1196 }1197 break;1198 }1200 case 0xff:1201 {1202 register_IE = value;1203 register_IF &= value;1204 return;1205 }1206 }1208 gbWriteMemoryQuick(address, value);1209 }1211 u8 gbReadOpcode(register u16 address)1212 {1213 if (gbCheatMap[address])1214 return gbCheatRead(address);1216 // the following fix does more than Echo RAM fix, anyway...1217 switch (gbEchoRAMFixOn ? (address >> 12) & 0x000f : address & 0xf000)1218 {1219 case 0x0a:1220 case 0x0b:1221 if (mapperReadRAM)1222 return mapperReadRAM(address);1223 break;1224 case 0x0f:1225 if (address > 0xff00)1226 {1227 switch (address & 0x00ff)1228 {1229 case 0x04:1230 return register_DIV;1231 case 0x05:1232 return register_TIMA;1233 case 0x06:1234 return register_TMA;1235 case 0x07:1236 return (0xf8 | register_TAC);1237 case 0x0f:1238 return (0xe0 | register_IF);1239 case 0x40:1240 return register_LCDC;1241 case 0x41:1242 return (0x80 | register_STAT);1243 case 0x42:1244 return register_SCY;1245 case 0x43:1246 return register_SCX;1247 case 0x44:1248 return register_LY;1249 case 0x45:1250 return register_LYC;1251 case 0x46:1252 return register_DMA;1253 case 0x4a:1254 return register_WY;1255 case 0x4b:1256 return register_WX;1257 case 0x4f:1258 return (0xfe | register_VBK);1259 case 0x51:1260 return register_HDMA1;1261 case 0x52:1262 return register_HDMA2;1263 case 0x53:1264 return register_HDMA3;1265 case 0x54:1266 return register_HDMA4;1267 case 0x55:1268 return register_HDMA5;1269 case 0x70:1270 return (0xf8 | register_SVBK);1271 case 0xff:1272 return register_IE;1273 }1274 }1275 break;1276 }1277 return gbReadMemoryQuick(address);1278 }1280 void gbWriteMemory(register u16 address, register u8 value)1281 {1282 gbWriteMemoryWrapped(address, value);1283 //CallRegisteredLuaMemHook(address, 1, value, LUAMEMHOOK_WRITE);1284 }1286 u8 gbReadMemory(register u16 address)1287 {1288 if (gbCheatMap[address])1289 return gbCheatRead(address);1291 if (address < 0xa000)1292 return gbReadMemoryQuick(address);1294 if (address < 0xc000)1295 {1296 #ifndef FINAL_VERSION1297 if (memorydebug)1298 {1299 log("Memory register read %04x PC=%04x\n",1300 address,1301 PC.W);1302 }1303 #endif1305 if (mapperReadRAM)1306 return mapperReadRAM(address);1307 return gbReadMemoryQuick(address);1308 }1310 if (address >= 0xff00)1311 {1312 switch (address & 0x00ff)1313 {1314 case 0x00:1315 {1316 if (gbSgbMode)1317 {1318 gbSgbReadingController |= 4;1319 gbSgbResetPacketState();1320 }1322 int b = gbMemory[0xff00];1324 if ((b & 0x30) == 0x20)1325 {1326 b &= 0xf0;1328 int joy = 0;1329 if (gbSgbMode && gbSgbMultiplayer)1330 {1331 switch (gbSgbNextController)1332 {1333 case 0x0f:1334 joy = 0;1335 break;1336 case 0x0e:1337 joy = 1;1338 break;1339 case 0x0d:1340 joy = 2;1341 break;1342 case 0x0c:1343 joy = 3;1344 break;1345 default:1346 joy = 0;1347 }1348 }1349 int joystate = gbJoymask[joy];1350 if (!(joystate & 128))1351 b |= 0x08;1352 if (!(joystate & 64))1353 b |= 0x04;1354 if (!(joystate & 32))1355 b |= 0x02;1356 if (!(joystate & 16))1357 b |= 0x01;1359 gbMemory[0xff00] = b;1360 }1361 else if ((b & 0x30) == 0x10)1362 {1363 b &= 0xf0;1365 int joy = 0;1366 if (gbSgbMode && gbSgbMultiplayer)1367 {1368 switch (gbSgbNextController)1369 {1370 case 0x0f:1371 joy = 0;1372 break;1373 case 0x0e:1374 joy = 1;1375 break;1376 case 0x0d:1377 joy = 2;1378 break;1379 case 0x0c:1380 joy = 3;1381 break;1382 default:1383 joy = 0;1384 }1385 }1386 int joystate = gbJoymask[joy];1387 if (!(joystate & 8))1388 b |= 0x08;1389 if (!(joystate & 4))1390 b |= 0x04;1391 if (!(joystate & 2))1392 b |= 0x02;1393 if (!(joystate & 1))1394 b |= 0x01;1396 gbMemory[0xff00] = b;1397 }1398 else1399 {1400 if (gbSgbMode && gbSgbMultiplayer)1401 {1402 gbMemory[0xff00] = 0xf0 | gbSgbNextController;1403 }1404 else1405 {1406 gbMemory[0xff00] = 0xff;1407 }1408 }1409 }1410 GBSystemCounters.lagged = false;1411 return gbMemory[0xff00];1412 break;1413 case 0x01:1414 return gbMemory[0xff01];1415 case 0x04:1416 return register_DIV;1417 case 0x05:1418 return register_TIMA;1419 case 0x06:1420 return register_TMA;1421 case 0x07:1422 return (0xf8 | register_TAC);1423 case 0x0f:1424 return (0xe0 | register_IF);1425 case 0x40:1426 return register_LCDC;1427 case 0x41:1428 return (0x80 | register_STAT);1429 case 0x42:1430 return register_SCY;1431 case 0x43:1432 return register_SCX;1433 case 0x44:1434 return register_LY;1435 case 0x45:1436 return register_LYC;1437 case 0x46:1438 return register_DMA;1439 case 0x4a:1440 return register_WY;1441 case 0x4b:1442 return register_WX;1443 case 0x4f:1444 return (0xfe | register_VBK);1445 case 0x51:1446 return register_HDMA1;1447 case 0x52:1448 return register_HDMA2;1449 case 0x53:1450 return register_HDMA3;1451 case 0x54:1452 return register_HDMA4;1453 case 0x55:1454 return register_HDMA5;1455 case 0x70:1456 return (0xf8 | register_SVBK);1457 case 0xff:1458 return register_IE;1459 }1460 }1462 return gbReadMemoryQuick(address);1463 }1465 void gbVblank_interrupt()1466 {1467 if (IFF & 0x80)1468 {1469 PC.W++;1470 IFF &= 0x7f;1471 }1472 gbInterrupt &= 0xfe;1474 IFF &= 0x7e;1475 register_IF &= 0xfe;1477 gbWriteMemory(--SP.W, PC.B.B1);1478 gbWriteMemory(--SP.W, PC.B.B0);1479 PC.W = 0x40;1480 }1482 void gbLcd_interrupt()1483 {1484 if (IFF & 0x80)1485 {1486 PC.W++;1487 IFF &= 0x7f;1488 }1489 gbInterrupt &= 0xfd;1490 IFF &= 0x7e;1491 register_IF &= 0xfd;1493 gbWriteMemory(--SP.W, PC.B.B1);1494 gbWriteMemory(--SP.W, PC.B.B0);1496 PC.W = 0x48;1497 }1499 void gbTimer_interrupt()1500 {1501 if (IFF & 0x80)1502 {1503 PC.W++;1504 IFF &= 0x7f;1505 }1506 IFF &= 0x7e;1507 gbInterrupt &= 0xfb;1508 register_IF &= 0xfb;1510 gbWriteMemory(--SP.W, PC.B.B1);1511 gbWriteMemory(--SP.W, PC.B.B0);1513 PC.W = 0x50;1514 }1516 void gbSerial_interrupt()1517 {1518 if (IFF & 0x80)1519 {1520 PC.W++;1521 IFF &= 0x7f;1522 }1523 IFF &= 0x7e;1524 gbInterrupt &= 0xf7;1525 register_IF &= 0xf7;1527 gbWriteMemory(--SP.W, PC.B.B1);1528 gbWriteMemory(--SP.W, PC.B.B0);1530 PC.W = 0x58;1531 }1533 void gbJoypad_interrupt()1534 {1535 if (IFF & 0x80)1536 {1537 PC.W++;1538 IFF &= 0x7f;1539 }1540 IFF &= 0x7e;1541 gbInterrupt &= 0xef;1542 register_IF &= 0xef;1544 gbWriteMemory(--SP.W, PC.B.B1);1545 gbWriteMemory(--SP.W, PC.B.B0);1547 PC.W = 0x60;1548 }1550 void gbSpeedSwitch()1551 {1552 if (gbSpeed == 0)1553 {1554 gbSpeed = 1;1555 GBLCD_MODE_0_CLOCK_TICKS = 51 * 2; //127; //51 * 2;1556 GBLCD_MODE_1_CLOCK_TICKS = 1140 * 2;1557 GBLCD_MODE_2_CLOCK_TICKS = 20 * 2; //52; //20 * 2;1558 GBLCD_MODE_3_CLOCK_TICKS = 43 * 2; //99; //43 * 2;1559 GBDIV_CLOCK_TICKS = 64 * 2;1560 GBLY_INCREMENT_CLOCK_TICKS = 114 * 2;1561 GBTIMER_MODE_0_CLOCK_TICKS = 256; //256*2;1562 GBTIMER_MODE_1_CLOCK_TICKS = 4; //4*2;1563 GBTIMER_MODE_2_CLOCK_TICKS = 16; //16*2;1564 GBTIMER_MODE_3_CLOCK_TICKS = 64; //64*2;1565 GBSERIAL_CLOCK_TICKS = 128 * 2;1566 gbDivTicks *= 2;1567 gbLcdTicks *= 2;1568 gbLcdLYIncrementTicks *= 2;1569 // timerTicks *= 2;1570 // timerClockTicks *= 2;1571 gbSerialTicks *= 2;1572 SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS * 2;1573 soundTicks *= 2;1574 // synchronizeTicks *= 2;1575 // SYNCHRONIZE_CLOCK_TICKS *= 2;1576 }1577 else1578 {1579 gbSpeed = 0;1580 GBLCD_MODE_0_CLOCK_TICKS = 51;1581 GBLCD_MODE_1_CLOCK_TICKS = 1140;1582 GBLCD_MODE_2_CLOCK_TICKS = 20;1583 GBLCD_MODE_3_CLOCK_TICKS = 43;1584 GBDIV_CLOCK_TICKS = 64;1585 GBLY_INCREMENT_CLOCK_TICKS = 114;1586 GBTIMER_MODE_0_CLOCK_TICKS = 256;1587 GBTIMER_MODE_1_CLOCK_TICKS = 4;1588 GBTIMER_MODE_2_CLOCK_TICKS = 16;1589 GBTIMER_MODE_3_CLOCK_TICKS = 64;1590 GBSERIAL_CLOCK_TICKS = 128;1591 gbDivTicks /= 2;1592 gbLcdTicks /= 2;1593 gbLcdLYIncrementTicks /= 2;1594 // timerTicks /= 2;1595 // timerClockTicks /= 2;1596 gbSerialTicks /= 2;1597 SOUND_CLOCK_TICKS = soundQuality * GB_USE_TICKS_AS;1598 soundTicks /= 2;1599 // synchronizeTicks /= 2;1600 // SYNCHRONIZE_CLOCK_TICKS /= 2;1601 }1602 }1604 void gbGetHardwareType()1605 {1606 gbCgbMode = 0;1607 if (gbRom[0x143] & 0x80)1608 {1609 if (gbEmulatorType == 0 ||1610 gbEmulatorType == 1 ||1611 gbEmulatorType == 4 ||1612 gbEmulatorType == 5 ||1613 (gbRom[0x146] != 0x03 && (gbEmulatorType == 2)))1614 {1615 gbCgbMode = 1;1616 }1617 }1619 if (gbSgbMode == 2)1620 {1621 gbSgbMode = 0;1622 return;1623 }1625 gbSgbMode = 0;1626 if (gbRom[0x146] == 0x03)1627 {1628 if (gbEmulatorType == 0 ||1629 gbEmulatorType == 2 ||1630 gbEmulatorType == 5 ||1631 (!(gbRom[0x143] & 0x80) && (gbEmulatorType == 1 || gbEmulatorType == 4)))1632 gbSgbMode = 1;1633 }1634 }1636 void gbReset(bool userReset)1637 {1638 // movie must be closed while opening/creating a movie1639 if (userReset && VBAMovieRecording())1640 {1641 VBAMovieSignalReset();1642 return;1643 }1645 if (!VBAMovieActive())1646 {1647 GBSystemCounters.frameCount = 0;1648 GBSystemCounters.lagCount = 0;1649 GBSystemCounters.extraCount = 0;1650 GBSystemCounters.lagged = true;1651 GBSystemCounters.laggedLast = true;1652 }1654 SP.W = 0xfffe;1655 AF.W = 0x01b0;1656 BC.W = 0x0013;1657 DE.W = 0x00d8;1658 HL.W = 0x014d;1659 PC.W = 0x0100;1660 IFF = 0;1661 gbInterrupt = 1;1662 gbInterruptWait = 0;1664 register_DIV = 0;1665 register_TIMA = 0;1666 register_TMA = 0;1667 register_TAC = 0;1668 register_IF = 1;1669 register_LCDC = 0x91;1670 register_STAT = 0;1671 register_SCY = 0;1672 register_SCX = 0;1673 register_LY = 0;1674 register_LYC = 0;1675 register_DMA = 0;1676 register_WY = 0;1677 register_WX = 0;1678 register_VBK = 0;1679 register_HDMA1 = 0;1680 register_HDMA2 = 0;1681 register_HDMA3 = 0;1682 register_HDMA4 = 0;1683 register_HDMA5 = 0;1684 register_SVBK = 0;1685 register_IE = 0;1687 gbGetHardwareType();1688 if (gbCgbMode)1689 {1690 if (!gbVram)1691 gbVram = (u8 *)malloc(0x4000 + 4);1692 if (!gbWram)1693 gbWram = (u8 *)malloc(0x8000 + 4);1694 memset(gbVram, 0, 0x4000 + 4);1695 memset(gbWram, 0, 0x8000 + 4);1696 }1697 else1698 {1699 if (gbVram)1700 {1701 free(gbVram);1702 gbVram = NULL;1703 }1704 if (gbWram)1705 {1706 free(gbWram);1707 gbWram = NULL;1708 }1709 }1711 // clean LineBuffer1712 if (gbLineBuffer)1713 memset(gbLineBuffer, 0, 160 * sizeof(u16));1714 // clean Pix1715 if (pix)1716 memset(pix, 0, 4 * 257 * 226);1718 if (gbCgbMode)1719 {1720 if (gbSgbMode)1721 {1722 if (gbEmulatorType == 5)1723 AF.W = 0xffb0;1724 else1725 AF.W = 0x01b0;1726 BC.W = 0x0013;1727 DE.W = 0x00d8;1728 HL.W = 0x014d;1729 }1730 else1731 {1732 AF.W = 0x11b0;1733 BC.W = 0x0000;1734 DE.W = 0xff56;1735 HL.W = 0x000d;1736 }1737 if (gbEmulatorType == 4)1738 BC.B.B1 |= 0x01;1740 register_HDMA5 = 0xff;1741 gbMemory[0xff68] = 0xc0;1742 gbMemory[0xff6a] = 0xc0;1744 for (int i = 0; i < 64; i++)1745 gbPalette[i] = 0x7fff;1746 }1747 else1748 {1749 for (int i = 0; i < 8; i++)1750 gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i];1751 }1753 if (gbSpeed)1754 {1755 gbSpeedSwitch();1756 gbMemory[0xff4d] = 0;1757 }1759 gbDivTicks = GBDIV_CLOCK_TICKS;1760 gbLcdMode = 2;1761 gbLcdTicks = GBLCD_MODE_2_CLOCK_TICKS;1762 gbLcdLYIncrementTicks = 0;1763 gbTimerTicks = 0;1764 gbTimerClockTicks = 0;1765 gbSerialTicks = 0;1766 gbSerialBits = 0;1767 gbSerialOn = 0;1768 gbWindowLine = -1;1769 gbTimerOn = 0;1770 gbTimerMode = 0;1771 // gbSynchronizeTicks = GBSYNCHRONIZE_CLOCK_TICKS;1772 gbSpeed = 0;1773 gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0;1775 // FIXME: horrible kludge1776 memset(s_gbJoymask, 0, sizeof(s_gbJoymask));1778 if (gbCgbMode)1779 {1780 gbSpeed = 0;1781 gbHdmaOn = 0;1782 gbHdmaSource = 0x0000;1783 gbHdmaDestination = 0x8000;1784 gbVramBank = 0;1785 gbWramBank = 1;1786 register_LY = 0x90;1787 gbLcdMode = 1;1788 }1790 if (gbSgbMode)1791 {1792 gbSgbReset();1793 }1795 for (int i = 0; i < 4; i++)1796 gbBgp[i] = gbObp0[i] = gbObp1[i] = i;1798 memset(&gbDataMBC1, 0, sizeof(gbDataMBC1));1799 gbDataMBC1.mapperROMBank = 1;1801 gbDataMBC2.mapperRAMEnable = 0;1802 gbDataMBC2.mapperROMBank = 1;1804 memset(&gbDataMBC3, 0, 6 * sizeof(int32));1805 gbDataMBC3.mapperROMBank = 1;1807 memset(&gbDataMBC5, 0, sizeof(gbDataMBC5));1808 gbDataMBC5.mapperROMBank = 1;1809 switch (gbRom[0x147])1810 {1811 case 0x1c:1812 case 0x1d:1813 case 0x1e:1814 gbDataMBC5.isRumbleCartridge = 1;1815 }1817 memset(&gbDataHuC1, 0, sizeof(gbDataHuC1));1818 gbDataHuC1.mapperROMBank = 1;1820 memset(&gbDataHuC3, 0, sizeof(gbDataHuC3));1821 gbDataHuC3.mapperROMBank = 1;1823 gbMemoryMap[0x00] = &gbRom[0x0000];1824 gbMemoryMap[0x01] = &gbRom[0x1000];1825 gbMemoryMap[0x02] = &gbRom[0x2000];1826 gbMemoryMap[0x03] = &gbRom[0x3000];1827 gbMemoryMap[0x04] = &gbRom[0x4000];1828 gbMemoryMap[0x05] = &gbRom[0x5000];1829 gbMemoryMap[0x06] = &gbRom[0x6000];1830 gbMemoryMap[0x07] = &gbRom[0x7000];1831 if (gbCgbMode)1832 {1833 gbMemoryMap[0x08] = &gbVram[0x0000];1834 gbMemoryMap[0x09] = &gbVram[0x1000];1835 gbMemoryMap[0x0a] = &gbMemory[0xa000];1836 gbMemoryMap[0x0b] = &gbMemory[0xb000];1837 gbMemoryMap[0x0c] = &gbMemory[0xc000];1838 gbMemoryMap[0x0d] = &gbWram[0x1000];1839 gbMemoryMap[0x0e] = &gbMemory[0xe000];1840 gbMemoryMap[0x0f] = &gbMemory[0xf000];1841 }1842 else1843 {1844 gbMemoryMap[0x08] = &gbMemory[0x8000];1845 gbMemoryMap[0x09] = &gbMemory[0x9000];1846 gbMemoryMap[0x0a] = &gbMemory[0xa000];1847 gbMemoryMap[0x0b] = &gbMemory[0xb000];1848 gbMemoryMap[0x0c] = &gbMemory[0xc000];1849 gbMemoryMap[0x0d] = &gbMemory[0xd000];1850 gbMemoryMap[0x0e] = &gbMemory[0xe000];1851 gbMemoryMap[0x0f] = &gbMemory[0xf000];1852 }1854 if (gbRam)1855 {1856 gbMemoryMap[0x0a] = &gbRam[0x0000];1857 gbMemoryMap[0x0b] = &gbRam[0x1000];1858 }1860 gbSoundReset();1862 systemResetSensor();1864 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;1866 gbLastTime = systemGetClock();1867 gbFrameCount = 0;1869 systemRefreshScreen();1870 }1872 void gbWriteSaveMBC1(const char *name)1873 {1874 FILE *gzFile = fopen(name, "wb");1876 if (gzFile == NULL)1877 {1878 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);1879 return;1880 }1882 fwrite(gbRam,1883 1,1884 gbRamSize,1885 gzFile);1887 fclose(gzFile);1888 }1890 void gbWriteSaveMBC2(const char *name)1891 {1892 FILE *file = fopen(name, "wb");1894 if (file == NULL)1895 {1896 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);1897 return;1898 }1900 fwrite(&gbMemory[0xa000],1901 1,1902 256,1903 file);1905 fclose(file);1906 }1908 void gbWriteSaveMBC3(const char *name, bool extendedSave)1909 {1910 FILE *gzFile = fopen(name, "wb");1912 if (gzFile == NULL)1913 {1914 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);1915 return;1916 }1918 fwrite(gbRam,1919 1,1920 gbRamSize,1921 gzFile);1923 if (extendedSave)1924 {1925 //assert(sizeof(time_t) == 4);1926 fwrite(&gbDataMBC3.mapperSeconds,1927 1,1928 10 * sizeof(int32) + /*sizeof(time_t)*/4,1929 gzFile);1930 }1932 fclose(gzFile);1933 }1935 void gbWriteSaveMBC5(const char *name)1936 {1937 FILE *gzFile = fopen(name, "wb");1939 if (gzFile == NULL)1940 {1941 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);1942 return;1943 }1945 fwrite(gbRam,1946 1,1947 gbRamSize,1948 gzFile);1950 fclose(gzFile);1951 }1953 void gbWriteSaveMBC7(const char *name)1954 {1955 FILE *file = fopen(name, "wb");1957 if (file == NULL)1958 {1959 systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), name);1960 return;1961 }1963 fwrite(&gbMemory[0xa000],1964 1,1965 256,1966 file);1968 fclose(file);1969 }1971 bool gbReadSaveMBC1(const char *name)1972 {1973 gzFile gzFile = gzopen(name, "rb");1975 if (gzFile == NULL)1976 {1977 return false;1978 }1980 int read = gzread(gzFile,1981 gbRam,1982 gbRamSize);1984 if (read != gbRamSize)1985 {1986 systemMessage(MSG_FAILED_TO_READ_SGM, N_("Failed to read complete save game %s (%d)"), name, read);1987 gzclose(gzFile);1988 return false;1989 }1991 gzclose(gzFile);1992 return true;1993 }1995 bool gbReadSaveMBC2(const char *name)1996 {1997 FILE *file = fopen(name, "rb");1999 if (file == NULL)2000 {2001 return false;2002 }2004 int read = fread(&gbMemory[0xa000],2005 1,2006 256,2007 file);2009 if (read != 256)2010 {2011 systemMessage(MSG_FAILED_TO_READ_SGM,2012 N_("Failed to read complete save game %s (%d)"), name, read);2013 fclose(file);2014 return false;2015 }2017 fclose(file);2018 return true;2019 }2021 bool gbReadSaveMBC3(const char *name)2022 {2023 gzFile gzFile = gzopen(name, "rb");2025 if (gzFile == NULL)2026 {2027 return false;2028 }2030 int read = gzread(gzFile,2031 gbRam,2032 gbRamSize);2034 bool res = true;2036 if (read != gbRamSize)2037 {2038 systemMessage(MSG_FAILED_TO_READ_SGM,2039 N_("Failed to read complete save game %s (%d)"), name, read);2040 }2041 else2042 {2043 //assert(sizeof(time_t) == 4);2044 read = gzread(gzFile,2045 &gbDataMBC3.mapperSeconds,2046 sizeof(int32) * 10 + /*sizeof(time_t)*/4);2048 if (read != (sizeof(int32) * 10 + /*sizeof(time_t)*/4) && read != 0)2049 {2050 systemMessage(MSG_FAILED_TO_READ_RTC,2051 N_("Failed to read RTC from save game %s (continuing)"),2052 name);2053 res = false;2054 }2055 }2057 gzclose(gzFile);2058 return res;2059 }2061 bool gbReadSaveMBC5(const char *name)2062 {2063 gzFile gzFile = gzopen(name, "rb");2065 if (gzFile == NULL)2066 {2067 return false;2068 }2070 int read = gzread(gzFile,2071 gbRam,2072 gbRamSize);2074 if (read != gbRamSize)2075 {2076 systemMessage(MSG_FAILED_TO_READ_SGM,2077 N_("Failed to read complete save game %s (%d)"), name, read);2078 gzclose(gzFile);2079 return false;2080 }2082 gzclose(gzFile);2083 return true;2084 }2086 bool gbReadSaveMBC7(const char *name)2087 {2088 FILE *file = fopen(name, "rb");2090 if (file == NULL)2091 {2092 return false;2093 }2095 int read = fread(&gbMemory[0xa000],2096 1,2097 256,2098 file);2100 if (read != 256)2101 {2102 systemMessage(MSG_FAILED_TO_READ_SGM,2103 N_("Failed to read complete save game %s (%d)"), name, read);2104 fclose(file);2105 return false;2106 }2108 fclose(file);2109 return true;2110 }2112 #if 02113 bool gbLoadBIOS(const char *biosFileName, bool useBiosFile)2114 {2115 useBios = false;2116 if (useBiosFile)2117 {2118 useBios = utilLoadBIOS(bios, biosFileName, gbEmulatorType);2119 if (!useBios)2120 {2121 systemMessage(MSG_INVALID_BIOS_FILE_SIZE, N_("Invalid BOOTROM file"));2122 }2123 }2124 return useBios;2125 }2126 #endif2128 void gbInit()2129 {2130 gbGenFilter();2131 gbSgbInit(); // calls gbSgbReset()... whatever2133 gbMemory = (u8 *)malloc(65536 + 4);2134 memset(gbMemory, 0, 65536 + 4);2135 memset(gbPalette, 0, 2 * 128);2137 // HACK: +4 at start to accomodate the 2xSaI filter reading out of bounds of the leftmost pixel2138 origPix = (u8 *)calloc(1, 4 * 257 * 226 + 4);2139 pix = origPix + 4;2141 gbLineBuffer = (u16 *)malloc(160 * sizeof(u16));2142 }2144 bool gbWriteBatteryFile(const char *file, bool extendedSave)2145 {2146 if (gbBattery)2147 {2148 int type = gbRom[0x147];2150 switch (type)2151 {2152 case 0x03:2153 gbWriteSaveMBC1(file);2154 break;2155 case 0x06:2156 gbWriteSaveMBC2(file);2157 break;2158 case 0x0f:2159 case 0x10:2160 case 0x13:2161 gbWriteSaveMBC3(file, extendedSave);2162 break;2163 case 0x1b:2164 case 0x1e:2165 gbWriteSaveMBC5(file);2166 break;2167 case 0x22:2168 gbWriteSaveMBC7(file);2169 break;2170 case 0xff:2171 gbWriteSaveMBC1(file);2172 break;2173 }2174 }2175 return true;2176 }2178 bool gbWriteBatteryFile(const char *file)2179 {2180 gbWriteBatteryFile(file, true);2181 return true;2182 }2184 bool gbWriteBatteryToStream(gzFile gzfile)2185 {2186 // the GB save code is ugly, so rather than convert it all to use gzFiles, just save it to a temp file...2187 #define TEMP_SAVE_FNAME ("tempvbawrite.sav")2188 bool retVal = gbWriteBatteryFile(TEMP_SAVE_FNAME, true);2190 // ...open the temp file and figure out its size...2191 FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "rb");2192 if (fileTemp == NULL)2193 return false;2194 fseek(fileTemp, 0, SEEK_END);2195 int len = (int) ftell(fileTemp);2197 // ...copy over the temp file...2198 char *temp = new char [len];2199 fseek(fileTemp, 0, SEEK_SET);2200 if (fread(temp, len, 1, fileTemp) != 1)2201 {2202 delete [] temp;2203 fclose(fileTemp);2204 return false;2205 }2206 fclose(fileTemp);2207 utilGzWrite(gzfile, temp, len);2208 delete [] temp;2210 // ... and delete the temp file2211 remove(TEMP_SAVE_FNAME);2212 #undef TEMP_SAVE_FNAME2214 return retVal;2215 }2217 bool gbReadBatteryFile(const char *file)2218 {2219 bool res = false;2220 if (gbBattery)2221 {2222 int type = gbRom[0x147];2224 switch (type)2225 {2226 case 0x03:2227 res = gbReadSaveMBC1(file);2228 break;2229 case 0x06:2230 res = gbReadSaveMBC2(file);2231 break;2232 case 0x0f:2233 case 0x10:2234 case 0x13:2235 if (!gbReadSaveMBC3(file))2236 {2237 struct tm *lt;2238 time_t tmp; //Small kludge to get it working on some systems where time_t has size 8.2240 if (VBAMovieActive() || VBAMovieLoading())2241 {2242 gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter() / 60;2243 lt = gmtime(&tmp);2244 gbDataMBC3.mapperLastTime=(u32)tmp;2245 }2246 else2247 {2248 time(&tmp);2249 gbDataMBC3.mapperLastTime=(u32)tmp;2250 lt = localtime(&tmp);2251 }2252 systemScreenMessage(ctime(&tmp), 4);2253 gbDataMBC3.mapperLastTime=(u32)tmp;2255 gbDataMBC3.mapperSeconds = lt->tm_sec;2256 gbDataMBC3.mapperMinutes = lt->tm_min;2257 gbDataMBC3.mapperHours = lt->tm_hour;2258 gbDataMBC3.mapperDays = lt->tm_yday & 255;2259 gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) |2260 (lt->tm_yday > 255 ? 1 : 0);2261 res = false;2262 break;2263 }2264 time_t tmp;2265 systemScreenMessage(ctime(&tmp), 4);2266 gbDataMBC3.mapperLastTime=(u32)tmp;2267 res = true;2268 break;2269 case 0x1b:2270 case 0x1e:2271 res = gbReadSaveMBC5(file);2272 break;2273 case 0x22:2274 res = gbReadSaveMBC7(file);2275 case 0xff:2276 res = gbReadSaveMBC1(file);2277 break;2278 }2279 }2280 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;2281 return res;2282 }2284 bool gbReadBatteryFromStream(gzFile gzfile)2285 {2286 // the GB save code is ugly, so rather than convert it all to use gzFiles, just copy it to temp RAM...2287 #define TEMP_SAVE_FNAME ("tempvbaread.sav")2288 int pos = gztell(gzfile);2289 int buflen = 1024;2290 // ...make a temp file and write it there...2291 FILE *fileTemp = fopen(TEMP_SAVE_FNAME, "wb");2292 if (fileTemp == NULL)2293 return false;2294 int gzDeflated;2295 char *temp = new char [buflen];2296 while ((gzDeflated = utilGzRead(gzfile, temp, buflen)) != 0)2297 {2298 if (gzDeflated == -1 || fwrite(temp, gzDeflated, 1, fileTemp) != 1)2299 {2300 delete [] temp;2301 fclose(fileTemp);2302 gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that2303 // calls this right now does a seek afterwards so it doesn't matter for now, but it's2304 // still bad)2305 return false;2306 }2307 }2308 gzseek(gzfile, pos, SEEK_SET); /// FIXME: leaves pos in gzfile before save instead of after it (everything that calls this2309 // right now does a seek afterwards so it doesn't matter for now, but it's still bad)2310 fclose(fileTemp);2311 delete [] temp;2313 // ... load from the temp file...2314 bool retVal = gbReadBatteryFile(TEMP_SAVE_FNAME);2316 // ... and delete the temp file2317 remove(TEMP_SAVE_FNAME);2318 #undef TEMP_SAVE_FNAME2320 return retVal;2321 }2323 bool gbReadGSASnapshot(const char *fileName)2324 {2325 FILE *file = fopen(fileName, "rb");2327 if (!file)2328 {2329 systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), fileName);2330 return false;2331 }2333 // long size = ftell(file);2334 fseek(file, 0x4, SEEK_SET);2335 char buffer[16];2336 char buffer2[16];2337 fread(buffer, 1, 15, file);2338 buffer[15] = 0;2339 memcpy(buffer2, &gbRom[0x134], 15);2340 buffer2[15] = 0;2341 if (memcmp(buffer, buffer2, 15))2342 {2343 systemMessage(MSG_CANNOT_IMPORT_SNAPSHOT_FOR,2344 N_("Cannot import snapshot for %s. Current game is %s"),2345 buffer,2346 buffer2);2347 fclose(file);2348 return false;2349 }2350 fseek(file, 0x13, SEEK_SET);2351 int read = 0;2352 int toRead = 0;2353 switch (gbRom[0x147])2354 {2355 case 0x03:2356 case 0x0f:2357 case 0x10:2358 case 0x13:2359 case 0x1b:2360 case 0x1e:2361 case 0xff:2362 read = fread(gbRam, 1, gbRamSize, file);2363 toRead = gbRamSize;2364 break;2365 case 0x06:2366 case 0x22:2367 read = fread(&gbMemory[0xa000], 1, 256, file);2368 toRead = 256;2369 break;2370 default:2371 systemMessage(MSG_UNSUPPORTED_SNAPSHOT_FILE,2372 N_("Unsupported snapshot file %s"),2373 fileName);2374 fclose(file);2375 return false;2376 }2377 fclose(file);2378 gbReset();2379 return true;2380 }2382 variable_desc gbSaveGameStruct[] =2383 {2384 { &PC.W, sizeof(u16) },2385 { &SP.W, sizeof(u16) },2386 { &AF.W, sizeof(u16) },2387 { &BC.W, sizeof(u16) },2388 { &DE.W, sizeof(u16) },2389 { &HL.W, sizeof(u16) },2390 { &IFF, sizeof(u8) },2391 { &GBLCD_MODE_0_CLOCK_TICKS, sizeof(int32) },2392 { &GBLCD_MODE_1_CLOCK_TICKS, sizeof(int32) },2393 { &GBLCD_MODE_2_CLOCK_TICKS, sizeof(int32) },2394 { &GBLCD_MODE_3_CLOCK_TICKS, sizeof(int32) },2395 { &GBDIV_CLOCK_TICKS, sizeof(int32) },2396 { &GBLY_INCREMENT_CLOCK_TICKS, sizeof(int32) },2397 { &GBTIMER_MODE_0_CLOCK_TICKS, sizeof(int32) },2398 { &GBTIMER_MODE_1_CLOCK_TICKS, sizeof(int32) },2399 { &GBTIMER_MODE_2_CLOCK_TICKS, sizeof(int32) },2400 { &GBTIMER_MODE_3_CLOCK_TICKS, sizeof(int32) },2401 { &GBSERIAL_CLOCK_TICKS, sizeof(int32) },2402 { &GBSYNCHRONIZE_CLOCK_TICKS, sizeof(int32) },2403 { &gbDivTicks, sizeof(int32) },2404 { &gbLcdMode, sizeof(int32) },2405 { &gbLcdTicks, sizeof(int32) },2406 { &gbLcdLYIncrementTicks, sizeof(int32) },2407 { &gbTimerTicks, sizeof(int32) },2408 { &gbTimerClockTicks, sizeof(int32) },2409 { &gbSerialTicks, sizeof(int32) },2410 { &gbSerialBits, sizeof(int32) },2411 { &gbInterrupt, sizeof(int32) },2412 { &gbInterruptWait, sizeof(int32) },2413 { &gbSynchronizeTicks, sizeof(int32) },2414 { &gbTimerOn, sizeof(int32) },2415 { &gbTimerMode, sizeof(int32) },2416 { &gbSerialOn, sizeof(int32) },2417 { &gbWindowLine, sizeof(int32) },2418 { &gbCgbMode, sizeof(int32) },2419 { &gbVramBank, sizeof(int32) },2420 { &gbWramBank, sizeof(int32) },2421 { &gbHdmaSource, sizeof(int32) },2422 { &gbHdmaDestination, sizeof(int32) },2423 { &gbHdmaBytes, sizeof(int32) },2424 { &gbHdmaOn, sizeof(int32) },2425 { &gbSpeed, sizeof(int32) },2426 { &gbSgbMode, sizeof(int32) },2427 { ®ister_DIV, sizeof(u8) },2428 { ®ister_TIMA, sizeof(u8) },2429 { ®ister_TMA, sizeof(u8) },2430 { ®ister_TAC, sizeof(u8) },2431 { ®ister_IF, sizeof(u8) },2432 { ®ister_LCDC, sizeof(u8) },2433 { ®ister_STAT, sizeof(u8) },2434 { ®ister_SCY, sizeof(u8) },2435 { ®ister_SCX, sizeof(u8) },2436 { ®ister_LY, sizeof(u8) },2437 { ®ister_LYC, sizeof(u8) },2438 { ®ister_DMA, sizeof(u8) },2439 { ®ister_WY, sizeof(u8) },2440 { ®ister_WX, sizeof(u8) },2441 { ®ister_VBK, sizeof(u8) },2442 { ®ister_HDMA1, sizeof(u8) },2443 { ®ister_HDMA2, sizeof(u8) },2444 { ®ister_HDMA3, sizeof(u8) },2445 { ®ister_HDMA4, sizeof(u8) },2446 { ®ister_HDMA5, sizeof(u8) },2447 { ®ister_SVBK, sizeof(u8) },2448 { ®ister_IE, sizeof(u8) },2449 { &gbBgp[0], sizeof(u8) },2450 { &gbBgp[1], sizeof(u8) },2451 { &gbBgp[2], sizeof(u8) },2452 { &gbBgp[3], sizeof(u8) },2453 { &gbObp0[0], sizeof(u8) },2454 { &gbObp0[1], sizeof(u8) },2455 { &gbObp0[2], sizeof(u8) },2456 { &gbObp0[3], sizeof(u8) },2457 { &gbObp1[0], sizeof(u8) },2458 { &gbObp1[1], sizeof(u8) },2459 { &gbObp1[2], sizeof(u8) },2460 { &gbObp1[3], sizeof(u8) },2461 { NULL, 0 }2462 };2464 bool gbWriteSaveStateToStream(gzFile gzFile)2465 {2467 utilWriteInt(gzFile, GBSAVE_GAME_VERSION);2470 utilGzWrite(gzFile, &gbRom[0x134], 15);2472 utilWriteData(gzFile, gbSaveGameStruct);2474 utilGzWrite(gzFile, &IFF, 2);2476 if (gbSgbMode)2477 {2478 gbSgbSaveGame(gzFile);2479 }2481 utilGzWrite(gzFile, &gbDataMBC1, sizeof(gbDataMBC1));2482 utilGzWrite(gzFile, &gbDataMBC2, sizeof(gbDataMBC2));2483 //assert(sizeof(time_t) == 4);2484 utilGzWrite(gzFile, &gbDataMBC3, sizeof(gbDataMBC3));2485 utilGzWrite(gzFile, &gbDataMBC5, sizeof(gbDataMBC5));2486 utilGzWrite(gzFile, &gbDataHuC1, sizeof(gbDataHuC1));2487 utilGzWrite(gzFile, &gbDataHuC3, sizeof(gbDataHuC3));2489 // yes, this definitely needs to be saved, or loading paused games will show a black screen2490 // this is also necessary to be consistent with what the GBA saving does2491 utilGzWrite(gzFile, pix, 4 * 257 * 226);2493 utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16));2494 // todo: remove2495 utilGzWrite(gzFile, gbPalette, 128 * sizeof(u16));2497 utilGzWrite(gzFile, &gbMemory[0x8000], 0x8000);2500 if (gbRamSize && gbRam)2501 {2502 utilGzWrite(gzFile, gbRam, gbRamSize);2503 }2505 if (gbCgbMode)2506 {2507 utilGzWrite(gzFile, gbVram, 0x4000);2508 utilGzWrite(gzFile, gbWram, 0x8000);2509 }2511 gbSoundSaveGame(gzFile);2513 gbCheatsSaveGame(gzFile);2515 // new to re-recording version:2516 {2517 extern int32 sensorX, sensorY;2518 utilGzWrite(gzFile, &sensorX, sizeof(sensorX));2519 utilGzWrite(gzFile, &sensorY, sizeof(sensorY));2520 utilGzWrite(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get2521 // carried2522 // back on loading a snapshot!2524 bool8 movieActive = VBAMovieActive();2525 utilGzWrite(gzFile, &movieActive, sizeof(movieActive));2526 if (movieActive)2527 {2528 uint8 *movie_freeze_buf = NULL;2529 uint32 movie_freeze_size = 0;2531 VBAMovieFreeze(&movie_freeze_buf, &movie_freeze_size);2532 if (movie_freeze_buf)2533 {2534 utilGzWrite(gzFile, &movie_freeze_size, sizeof(movie_freeze_size));2535 utilGzWrite(gzFile, movie_freeze_buf, movie_freeze_size);2536 delete [] movie_freeze_buf;2537 }2538 else2539 {2540 systemMessage(0, N_("Failed to save movie snapshot."));2541 return false;2542 }2543 }2544 utilGzWrite(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount));2545 }2547 // new to rerecording 19.4 wip (svn r22+):2548 {2549 utilGzWrite(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount));2550 utilGzWrite(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged));2551 utilGzWrite(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast));2552 }2554 utilWriteInt(gzFile, 0x07); // RLM this is the end of file marker.2555 return true;2556 }2559 long gbWriteMemSaveStatePos(char *memory, int available){2560 gzFile gzFile = utilMemGzOpen(memory, available, "w");2562 if (gzFile == NULL)2563 {2564 return false;2565 }2567 bool res = gbWriteSaveStateToStream(gzFile);2569 long pos = utilGzTell(gzFile) + 8;2571 if (pos >= available){2572 pos = 0;2573 }2575 utilGzClose(gzFile);2577 return pos;2579 }2581 bool gbWriteMemSaveState(char *memory, int available)2582 {2583 long pos = gbWriteMemSaveStatePos(memory, available);2584 if (pos > 0) { return true; }2585 else{ return false; }2586 }2588 bool gbWriteSaveState(const char *name)2589 {2590 gzFile gzFile = utilGzOpen(name, "wb");2592 if (gzFile == NULL)2593 return false;2595 bool res = gbWriteSaveStateToStream(gzFile);2597 utilGzClose(gzFile);2598 return res;2599 }2601 static int tempStateID = 0;2602 static int tempFailCount = 0;2603 static bool backupSafe = true;2605 bool gbReadSaveStateFromStream(gzFile gzFile)2606 {2607 int type;2608 char tempBackupName [128];2609 if (backupSafe)2610 {2611 sprintf(tempBackupName, "gbatempsave%d.sav", tempStateID++);2612 gbWriteSaveState(tempBackupName);2613 }2615 int version = utilReadInt(gzFile);2617 if (version > GBSAVE_GAME_VERSION || version < 0)2618 {2619 systemMessage(MSG_UNSUPPORTED_VB_SGM,2620 N_("Unsupported VisualBoy save game version %d"), version);2621 goto failedLoadGB;2622 }2624 u8 romname[20];2626 utilGzRead(gzFile, romname, 15);2628 if (memcmp(&gbRom[0x134], romname, 15) != 0)2629 {2630 systemMessage(MSG_CANNOT_LOAD_SGM_FOR,2631 N_("Cannot load save game for %s. Playing %s"),2632 romname, &gbRom[0x134]);2633 goto failedLoadGB;2634 }2636 utilReadData(gzFile, gbSaveGameStruct);2638 if (version >= GBSAVE_GAME_VERSION_7)2639 {2640 utilGzRead(gzFile, &IFF, 2);2641 }2643 if (gbSgbMode)2644 {2645 gbSgbReadGame(gzFile, version);2646 }2647 else2648 {2649 gbSgbMask = 0; // loading a game at the wrong time causes no display2650 }2652 utilGzRead(gzFile, &gbDataMBC1, sizeof(gbDataMBC1));2653 utilGzRead(gzFile, &gbDataMBC2, sizeof(gbDataMBC2));2654 if (version < GBSAVE_GAME_VERSION_4)2655 // prior to version 4, there was no adjustment for the time the game2656 // was last played, so we have less to read. This needs update if the2657 // structure changes again.2658 utilGzRead(gzFile, &gbDataMBC3, sizeof(int32) * 10);2659 else2660 {2661 //assert(sizeof(time_t) == 4);2662 utilGzRead(gzFile, &gbDataMBC3, sizeof(gbDataMBC3));2663 }2664 utilGzRead(gzFile, &gbDataMBC5, sizeof(gbDataMBC5));2665 utilGzRead(gzFile, &gbDataHuC1, sizeof(gbDataHuC1));2666 utilGzRead(gzFile, &gbDataHuC3, sizeof(gbDataHuC3));2668 if (version >= GBSAVE_GAME_VERSION_12)2669 {2670 utilGzRead(gzFile, pix, 4 * 257 * 226);2671 }2672 else2673 {2674 memset(pix, 0, 257 * 226 * sizeof(u32));2675 // if(version < GBSAVE_GAME_VERSION_5)2676 // utilGzRead(gzFile, pix, 256*224*sizeof(u16));2677 }2679 if (version < GBSAVE_GAME_VERSION_6)2680 {2681 utilGzRead(gzFile, gbPalette, 64 * sizeof(u16));2682 }2683 else2684 utilGzRead(gzFile, gbPalette, 128 * sizeof(u16));2686 // todo: remove2687 utilGzRead(gzFile, gbPalette, 128 * sizeof(u16));2689 if (version < GBSAVE_GAME_VERSION_10)2690 {2691 if (!gbCgbMode && !gbSgbMode)2692 {2693 for (int i = 0; i < 8; i++)2694 gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i];2695 }2696 }2698 utilGzRead(gzFile, &gbMemory[0x8000], 0x8000);2700 if (gbRamSize && gbRam)2701 {2702 utilGzRead(gzFile, gbRam, gbRamSize);2703 }2705 gbMemoryMap[0x00] = &gbRom[0x0000];2706 gbMemoryMap[0x01] = &gbRom[0x1000];2707 gbMemoryMap[0x02] = &gbRom[0x2000];2708 gbMemoryMap[0x03] = &gbRom[0x3000];2709 gbMemoryMap[0x04] = &gbRom[0x4000];2710 gbMemoryMap[0x05] = &gbRom[0x5000];2711 gbMemoryMap[0x06] = &gbRom[0x6000];2712 gbMemoryMap[0x07] = &gbRom[0x7000];2713 gbMemoryMap[0x08] = &gbMemory[0x8000];2714 gbMemoryMap[0x09] = &gbMemory[0x9000];2715 gbMemoryMap[0x0a] = &gbMemory[0xa000];2716 gbMemoryMap[0x0b] = &gbMemory[0xb000];2717 gbMemoryMap[0x0c] = &gbMemory[0xc000];2718 gbMemoryMap[0x0d] = &gbMemory[0xd000];2719 gbMemoryMap[0x0e] = &gbMemory[0xe000];2720 gbMemoryMap[0x0f] = &gbMemory[0xf000];2722 type = gbRom[0x147];2724 switch (type)2725 {2726 case 0x00:2727 case 0x01:2728 case 0x02:2729 case 0x03:2730 // MBC 12731 memoryUpdateMapMBC1();2732 break;2733 case 0x05:2734 case 0x06:2735 // MBC22736 memoryUpdateMapMBC2();2737 break;2738 case 0x0f:2739 case 0x10:2740 case 0x11:2741 case 0x12:2742 case 0x13:2743 // MBC 32744 memoryUpdateMapMBC3();2745 break;2746 case 0x19:2747 case 0x1a:2748 case 0x1b:2749 // MBC52750 memoryUpdateMapMBC5();2751 break;2752 case 0x1c:2753 case 0x1d:2754 case 0x1e:2755 // MBC 5 Rumble2756 memoryUpdateMapMBC5();2757 break;2758 case 0x22:2759 // MBC 72760 memoryUpdateMapMBC7();2761 break;2762 case 0xfe:2763 // HuC32764 memoryUpdateMapHuC3();2765 break;2766 case 0xff:2767 // HuC12768 memoryUpdateMapHuC1();2769 break;2770 }2772 if (gbCgbMode)2773 {2774 if (!gbVram)2775 gbVram = (u8 *)malloc(0x4000 + 4);2776 if (!gbWram)2777 gbWram = (u8 *)malloc(0x8000 + 4);2778 utilGzRead(gzFile, gbVram, 0x4000);2779 utilGzRead(gzFile, gbWram, 0x8000);2781 int value = register_SVBK;2782 if (value == 0)2783 value = 1;2785 gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000];2786 gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000];2787 gbMemoryMap[0x0d] = &gbWram[value * 0x1000];2788 }2789 else2790 {2791 if (gbVram)2792 {2793 free(gbVram);2794 gbVram = NULL;2795 }2796 if (gbWram)2797 {2798 free(gbWram);2799 gbWram = NULL;2800 }2801 }2803 gbSoundReadGame(version, gzFile);2805 #if 02806 if (gbBorderOn)2807 {2808 gbSgbRenderBorder();2809 }2811 systemRefreshScreen();2812 #endif2814 if (version > GBSAVE_GAME_VERSION_1)2815 gbCheatsReadGame(gzFile, version);2817 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;2819 if (version >= GBSAVE_GAME_VERSION_11) // new to re-recording version:2820 {2821 extern int32 sensorX, sensorY; // from SDL.cpp2822 utilGzRead(gzFile, &sensorX, sizeof(sensorX));2823 utilGzRead(gzFile, &sensorY, sizeof(sensorY));2824 utilGzRead(gzFile, gbJoymask, 4 * sizeof(*gbJoymask)); // this has to be saved or old input will incorrectly get carried2825 // back on loading a snapshot!2827 bool8 movieSnapshot;2828 utilGzRead(gzFile, &movieSnapshot, sizeof(movieSnapshot));2829 if (VBAMovieActive() && !movieSnapshot)2830 {2831 systemMessage(0, N_("Can't load a non-movie snapshot while a movie is active."));2832 goto failedLoadGB;2833 }2835 if (movieSnapshot) // even if a movie isn't active we still want to parse through this in case other stuff is added2836 // later on in the save format2837 {2838 uint32 movieInputDataSize = 0;2839 utilGzRead(gzFile, &movieInputDataSize, sizeof(movieInputDataSize));2840 uint8 *local_movie_data = new uint8 [movieInputDataSize];2841 int readBytes = utilGzRead(gzFile, local_movie_data, movieInputDataSize);2842 if (readBytes != movieInputDataSize)2843 {2844 systemMessage(0, N_("Corrupt movie snapshot."));2845 if (local_movie_data)2846 delete [] local_movie_data;2847 goto failedLoadGB;2848 }2849 int code = VBAMovieUnfreeze(local_movie_data, movieInputDataSize);2850 if (local_movie_data)2851 delete [] local_movie_data;2852 if (code != MOVIE_SUCCESS && VBAMovieActive())2853 {2854 char errStr [1024];2855 strcpy(errStr, "Failed to load movie snapshot");2856 switch (code)2857 {2858 case MOVIE_NOT_FROM_THIS_MOVIE:2859 strcat(errStr, ";\nSnapshot not from this movie"); break;2860 case MOVIE_NOT_FROM_A_MOVIE:2861 strcat(errStr, ";\nNot a movie snapshot"); break; // shouldn't get here...2862 case MOVIE_SNAPSHOT_INCONSISTENT:2863 strcat(errStr, ";\nSnapshot inconsistent with movie"); break;2864 case MOVIE_WRONG_FORMAT:2865 strcat(errStr, ";\nWrong format"); break;2866 }2867 strcat(errStr, ".");2868 systemMessage(0, N_(errStr));2869 goto failedLoadGB;2870 }2871 }2872 utilGzRead(gzFile, &GBSystemCounters.frameCount, sizeof(GBSystemCounters.frameCount));2873 }2875 if (version >= GBSAVE_GAME_VERSION_13) // new to rerecording 19.4 wip (svn r22+):2876 {2877 utilGzRead(gzFile, &GBSystemCounters.lagCount, sizeof(GBSystemCounters.lagCount));2878 utilGzRead(gzFile, &GBSystemCounters.lagged, sizeof(GBSystemCounters.lagged));2879 utilGzRead(gzFile, &GBSystemCounters.laggedLast, sizeof(GBSystemCounters.laggedLast));2880 }2882 if (backupSafe)2883 {2884 remove(tempBackupName);2885 tempFailCount = 0;2886 }2888 for (int i = 0; i < 4; ++i)2889 systemSetJoypad(i, gbJoymask[i] & 0xFFFF);2891 // FIXME: horrible kludge2892 memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask));2894 VBAUpdateButtonPressDisplay();2895 VBAUpdateFrameCountDisplay();2896 systemRefreshScreen();2897 return true;2899 failedLoadGB:2900 if (backupSafe)2901 {2902 tempFailCount++;2903 if (tempFailCount < 3) // fail no more than 2 times in a row2904 gbReadSaveState(tempBackupName);2905 remove(tempBackupName);2906 }2907 return false;2908 }2910 bool gbReadMemSaveState(char *memory, int available)2911 {2912 gzFile gzFile = utilMemGzOpen(memory, available, "r");2914 backupSafe = false;2915 bool res = gbReadSaveStateFromStream(gzFile);2916 backupSafe = true;2918 utilGzClose(gzFile);2920 return res;2921 }2923 bool gbReadSaveState(const char *name)2924 {2925 gzFile gzFile = utilGzOpen(name, "rb");2927 if (gzFile == NULL)2928 {2929 return false;2930 }2932 bool res = gbReadSaveStateFromStream(gzFile);2934 utilGzClose(gzFile);2936 return res;2937 }2939 bool gbWritePNGFile(const char *fileName)2940 {2941 if (gbBorderOn)2942 return utilWritePNGFile(fileName, 256, 224, pix);2943 return utilWritePNGFile(fileName, 160, 144, pix);2944 }2946 bool gbWriteBMPFile(const char *fileName)2947 {2948 if (gbBorderOn)2949 return utilWriteBMPFile(fileName, 256, 224, pix);2950 return utilWriteBMPFile(fileName, 160, 144, pix);2951 }2953 void gbCleanUp()2954 {2955 newFrame = true;2957 GBSystemCounters.frameCount = 0;2958 GBSystemCounters.lagCount = 0;2959 GBSystemCounters.extraCount = 0;2960 GBSystemCounters.lagged = true;2961 GBSystemCounters.laggedLast = true;2963 if (gbRam != NULL)2964 {2965 free(gbRam);2966 gbRam = NULL;2967 }2969 if (gbRom != NULL)2970 {2971 free(gbRom);2972 gbRom = NULL;2973 }2975 if (gbMemory != NULL)2976 {2977 free(gbMemory);2978 gbMemory = NULL;2979 }2981 if (gbLineBuffer != NULL)2982 {2983 free(gbLineBuffer);2984 gbLineBuffer = NULL;2985 }2987 if (origPix != NULL)2988 {2989 free(origPix);2990 origPix = NULL;2991 }2992 pix = NULL;2994 gbSgbShutdown();2996 if (gbVram != NULL)2997 {2998 free(gbVram);2999 gbVram = NULL;3000 }3002 if (gbWram != NULL)3003 {3004 free(gbWram);3005 gbWram = NULL;3006 }3008 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;3010 memset(gbJoymask, 0, sizeof(gbJoymask));3011 // FIXME: horrible kludge3012 memset(s_gbJoymask, 0, sizeof(s_gbJoymask));3014 systemClearJoypads();3015 systemResetSensor();3017 // gbLastTime = gbFrameCount = 0;3018 systemRefreshScreen();3019 }3021 bool gbLoadRom(const char *szFile)3022 {3023 int size = 0;3025 if (gbRom != NULL)3026 {3027 gbCleanUp();3028 }3030 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;3032 gbRom = utilLoad(szFile,3033 utilIsGBImage,3034 NULL,3035 size);3036 if (!gbRom)3037 return false;3039 gbRomSize = size;3041 return gbUpdateSizes();3042 }3044 bool gbUpdateSizes()3045 {3046 if (gbRom[0x148] > 8)3047 {3048 systemMessage(MSG_UNSUPPORTED_ROM_SIZE,3049 N_("Unsupported rom size %02x"), gbRom[0x148]);3050 return false;3051 }3053 if (gbRomSize < gbRomSizes[gbRom[0x148]])3054 {3055 gbRom = (u8 *)realloc(gbRom, gbRomSizes[gbRom[0x148]]);3056 }3057 gbRomSize = gbRomSizes[gbRom[0x148]];3058 gbRomSizeMask = gbRomSizesMasks[gbRom[0x148]];3060 if (gbRom[0x149] > 5)3061 {3062 systemMessage(MSG_UNSUPPORTED_RAM_SIZE,3063 N_("Unsupported ram size %02x"), gbRom[0x149]);3064 return false;3065 }3067 gbRamSize = gbRamSizes[gbRom[0x149]];3068 gbRamSizeMask = gbRamSizesMasks[gbRom[0x149]];3070 if (gbRamSize)3071 {3072 gbRam = (u8 *)malloc(gbRamSize + 4);3073 memset(gbRam, 0xFF, gbRamSize + 4);3074 }3076 int type = gbRom[0x147];3078 mapperReadRAM = NULL;3080 switch (type)3081 {3082 case 0x00:3083 case 0x01:3084 case 0x02:3085 case 0x03:3086 // MBC 13087 mapper = mapperMBC1ROM;3088 mapperRAM = mapperMBC1RAM;3089 break;3090 case 0x05:3091 case 0x06:3092 // MBC23093 mapper = mapperMBC2ROM;3094 mapperRAM = mapperMBC2RAM;3095 gbRamSize = 0x200;3096 gbRamSizeMask = 0x1ff;3097 break;3098 case 0x0f:3099 case 0x10:3100 case 0x11:3101 case 0x12:3102 case 0x13:3103 // MBC 33104 mapper = mapperMBC3ROM;3105 mapperRAM = mapperMBC3RAM;3106 mapperReadRAM = mapperMBC3ReadRAM;3107 break;3108 case 0x19:3109 case 0x1a:3110 case 0x1b:3111 // MBC53112 mapper = mapperMBC5ROM;3113 mapperRAM = mapperMBC5RAM;3114 break;3115 case 0x1c:3116 case 0x1d:3117 case 0x1e:3118 // MBC 5 Rumble3119 mapper = mapperMBC5ROM;3120 mapperRAM = mapperMBC5RAM;3121 break;3122 case 0x22:3123 // MBC 73124 mapper = mapperMBC7ROM;3125 mapperRAM = mapperMBC7RAM;3126 mapperReadRAM = mapperMBC7ReadRAM;3127 break;3128 case 0xfe:3129 // HuC33130 mapper = mapperHuC3ROM;3131 mapperRAM = mapperHuC3RAM;3132 mapperReadRAM = mapperHuC3ReadRAM;3133 break;3134 case 0xff:3135 // HuC13136 mapper = mapperHuC1ROM;3137 mapperRAM = mapperHuC1RAM;3138 break;3139 default:3140 systemMessage(MSG_UNKNOWN_CARTRIDGE_TYPE,3141 N_("Unknown cartridge type %02x"), type);3142 return false;3143 }3145 switch (type)3146 {3147 case 0x03:3148 case 0x06:3149 case 0x0f:3150 case 0x10:3151 case 0x13:3152 case 0x1b:3153 case 0x1d:3154 case 0x1e:3155 case 0x22:3156 case 0xff:3157 gbBattery = 1;3158 break;3159 }3161 gbInit();3162 gbReset();3164 return true;3165 }3167 int gbEmulate(int ticksToStop)3168 {3169 int rlm_count = 0;3170 //printf("RLM: Inside the GB!\n");3171 gbRegister tempRegister;3172 u8 tempValue;3173 s8 offset;3175 int clockTicks = 0;3176 gbDmaTicks = 0;3178 register int opcode = 0;3180 u32 newmask = 0;3181 //printf("RLM: newframe = %d\n", newFrame);3182 if (newFrame)3183 {3184 extern void VBAOnExitingFrameBoundary();3185 VBAOnExitingFrameBoundary();3186 //printf("RLM: exiting frame boundary?\n");3187 // update joystick information3188 systemReadJoypads();3190 bool sensor = (gbRom[0x147] == 0x22);3192 // read joystick3193 if (gbSgbMode && gbSgbMultiplayer)3194 {3195 if (gbSgbFourPlayers)3196 {3197 gbJoymask[0] = systemGetJoypad(0, sensor);3198 gbJoymask[1] = systemGetJoypad(1, false);3199 gbJoymask[2] = systemGetJoypad(2, false);3200 gbJoymask[3] = systemGetJoypad(3, false);3201 }3202 else3203 {3204 gbJoymask[0] = systemGetJoypad(0, sensor);3205 gbJoymask[1] = systemGetJoypad(1, false);3206 }3207 }3208 else3209 {3210 gbJoymask[0] = systemGetJoypad(0, sensor);3211 }3213 // FIXME: horrible kludge3214 memcpy(s_gbJoymask, gbJoymask, sizeof(gbJoymask));3216 // if (sensor)3217 // systemUpdateMotionSensor(0);3219 newmask = gbJoymask[0];3220 if (newmask & 0xFF)3221 {3222 gbInterrupt |= 16;3223 }3225 extButtons = (newmask >> 18);3226 speedup = (extButtons & 1) != 0;3228 VBAMovieResetIfRequested();3229 //printf("RLM: before Lua functions\n");3230 //CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION);3231 //printf("RLM: after Lua functions\n");3232 newFrame = false;3233 }3236 //for (;; )3237 // {3238 #ifndef FINAL_VERSION3239 if (systemDebug)3240 {3241 if (!(IFF & 0x80))3242 {3243 if (systemDebug > 1)3244 {3245 sprintf(gbBuffer, "PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x SP=%04x I=%04x\n",3246 PC.W, AF.W, BC.W, DE.W, HL.W, SP.W, IFF);3247 }3248 else3249 {3250 sprintf(gbBuffer, "PC=%04x I=%02x\n", PC.W, IFF);3251 }3252 log(gbBuffer);3253 }3254 }3255 #endif3256 if (IFF & 0x80)3257 {3258 if (register_LCDC & 0x80)3259 {3260 clockTicks = gbLcdTicks;3261 }3262 else3263 clockTicks = 100;3265 if (gbLcdMode == 1 && (gbLcdLYIncrementTicks < clockTicks))3266 clockTicks = gbLcdLYIncrementTicks;3268 if (gbSerialOn && (gbSerialTicks < clockTicks))3269 clockTicks = gbSerialTicks;3271 if (gbTimerOn && (gbTimerTicks < clockTicks))3272 clockTicks = gbTimerTicks;3274 if (soundTicks && (soundTicks < clockTicks))3275 clockTicks = soundTicks;3276 }3277 else3278 {3279 opcode = gbReadOpcode(PC.W);3280 //printf("RLM: calling mem Hook ; %07d\n", rlm_count++);3281 //CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC);3282 PC.W++;3284 if (IFF & 0x100)3285 {3286 IFF &= 0xff;3287 PC.W--;3288 }3290 clockTicks = gbCycles[opcode];3292 switch (opcode)3293 {3294 case 0xCB:3295 // extended opcode3296 //CallRegisteredLuaMemHook(PC.W, 1, opcode, LUAMEMHOOK_EXEC); // is this desired?3297 opcode = gbReadOpcode(PC.W++);3298 clockTicks = gbCyclesCB[opcode];3299 switch (opcode)3300 {3301 #include "gbCodesCB.h"3302 }3303 break;3304 #include "gbCodes.h"3305 }3306 }3308 if (!emulating)3309 return 1;3311 if (gbDmaTicks)3312 {3313 clockTicks += gbDmaTicks;3314 gbDmaTicks = 0;3315 }3317 if (gbSgbMode)3318 {3319 if (gbSgbPacketTimeout)3320 {3321 gbSgbPacketTimeout -= clockTicks;3323 if (gbSgbPacketTimeout <= 0)3324 gbSgbResetPacketState();3325 }3326 }3328 ticksToStop -= clockTicks;3330 // DIV register emulation3331 gbDivTicks -= clockTicks;3332 while (gbDivTicks <= 0)3333 {3334 register_DIV++;3335 gbDivTicks += GBDIV_CLOCK_TICKS;3336 }3338 if (register_LCDC & 0x80)3339 {3340 // LCD stuff3341 gbLcdTicks -= clockTicks;3342 if (gbLcdMode == 1)3343 {3344 // during V-BLANK,we need to increment LY at the same rate!3345 gbLcdLYIncrementTicks -= clockTicks;3346 while (gbLcdLYIncrementTicks <= 0)3347 {3348 gbLcdLYIncrementTicks += GBLY_INCREMENT_CLOCK_TICKS;3350 if (register_LY < 153)3351 {3352 register_LY++;3354 gbCompareLYToLYC();3356 if (register_LY >= 153)3357 gbLcdLYIncrementTicks = 6;3358 }3359 else3360 {3361 register_LY = 0x00;3362 // reset the window line3363 gbWindowLine = -1;3364 gbLcdLYIncrementTicks = GBLY_INCREMENT_CLOCK_TICKS * 2;3365 gbCompareLYToLYC();3366 }3367 }3368 }3370 // our counter is off, see what we need to do3371 while (gbLcdTicks <= 0)3372 {3373 int framesToSkip = systemFramesToSkip();3375 switch (gbLcdMode)3376 {3377 case 0:3378 // H-Blank3379 register_LY++;3381 gbCompareLYToLYC();3383 // check if we reached the V-Blank period3384 if (register_LY == 144)3385 {3386 // Yes, V-Blank3387 // set the LY increment counter3388 gbLcdLYIncrementTicks = gbLcdTicks + GBLY_INCREMENT_CLOCK_TICKS;3389 gbLcdTicks += GBLCD_MODE_1_CLOCK_TICKS;3390 gbLcdMode = 1;3391 if (register_LCDC & 0x80)3392 {3393 gbInterrupt |= 1; // V-Blank interrupt3394 gbInterruptWait = 6;3395 if (register_STAT & 0x10)3396 gbInterrupt |= 2;3397 }3399 systemFrame();3401 ++gbFrameCount;3402 u32 currentTime = systemGetClock();3403 if (currentTime - gbLastTime >= 1000)3404 {3405 systemShowSpeed(int(float(gbFrameCount) * 100000 / (float(currentTime - gbLastTime) * 60) + .5f));3406 gbLastTime = currentTime;3407 gbFrameCount = 0;3408 }3410 ++GBSystemCounters.frameCount;3411 if (GBSystemCounters.lagged)3412 {3413 ++GBSystemCounters.lagCount;3414 }3415 GBSystemCounters.laggedLast = GBSystemCounters.lagged;3416 GBSystemCounters.lagged = true;3418 extern void VBAOnEnteringFrameBoundary();3419 VBAOnEnteringFrameBoundary();3421 newFrame = true;3423 pauseAfterFrameAdvance = systemPauseOnFrame();3425 if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance)3426 {3427 if (gbBorderOn)3428 gbSgbRenderBorder(); // clear unnecessary things on border (e.g. in-game text message)3430 systemRenderFrame();3431 gbFrameSkipCount = 0;3433 bool capturePressed = (extButtons & 2) != 0;3434 if (capturePressed && !capturePrevious)3435 {3436 captureNumber = systemScreenCapture(captureNumber);3437 }3438 capturePrevious = capturePressed && !pauseAfterFrameAdvance;3439 }3440 else3441 {3442 ++gbFrameSkipCount;3443 }3445 if (pauseAfterFrameAdvance)3446 {3447 systemSetPause(true);3448 }3449 }3450 else3451 {3452 // go the the OAM being accessed mode3453 gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS;3454 gbLcdMode = 2;3456 // only one LCD interrupt per line. may need to generalize...3457 if (!(register_STAT & 0x40) ||3458 (register_LY != register_LYC))3459 {3460 if ((register_STAT & 0x28) == 0x20)3461 gbInterrupt |= 2;3462 }3463 }3465 break;3466 case 1:3467 // V-Blank3468 // next mode is OAM being accessed mode3469 gbLcdTicks += GBLCD_MODE_2_CLOCK_TICKS;3470 gbLcdMode = 2;3471 if (!(register_STAT & 0x40) ||3472 (register_LY != register_LYC))3473 {3474 if ((register_STAT & 0x28) == 0x20)3475 gbInterrupt |= 2;3476 }3477 break;3478 case 2:3479 // OAM being accessed mode3481 // next mode is OAM and VRAM in use3482 gbLcdTicks += GBLCD_MODE_3_CLOCK_TICKS;3483 gbLcdMode = 3;3484 break;3485 case 3:3486 // OAM and VRAM in use3487 // next mode is H-Blank3488 if (register_LY < 144)3489 {3490 if (!gbSgbMask)3491 {3492 if (gbFrameSkipCount >= framesToSkip || pauseAfterFrameAdvance)3493 {3494 gbRenderLine();3495 gbDrawSprites();3497 switch (systemColorDepth)3498 {3499 case 16:3501 {3502 u16 *dest = (u16 *)pix +3503 (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1)3504 + gbBorderColumnSkip;3505 for (int x = 0; x < 160; )3506 {3507 *dest++ = systemColorMap16[gbLineMix[x++]];3508 *dest++ = systemColorMap16[gbLineMix[x++]];3509 *dest++ = systemColorMap16[gbLineMix[x++]];3510 *dest++ = systemColorMap16[gbLineMix[x++]];3512 *dest++ = systemColorMap16[gbLineMix[x++]];3513 *dest++ = systemColorMap16[gbLineMix[x++]];3514 *dest++ = systemColorMap16[gbLineMix[x++]];3515 *dest++ = systemColorMap16[gbLineMix[x++]];3517 *dest++ = systemColorMap16[gbLineMix[x++]];3518 *dest++ = systemColorMap16[gbLineMix[x++]];3519 *dest++ = systemColorMap16[gbLineMix[x++]];3520 *dest++ = systemColorMap16[gbLineMix[x++]];3522 *dest++ = systemColorMap16[gbLineMix[x++]];3523 *dest++ = systemColorMap16[gbLineMix[x++]];3524 *dest++ = systemColorMap16[gbLineMix[x++]];3525 *dest++ = systemColorMap16[gbLineMix[x++]];3526 }3527 if (gbBorderOn)3528 dest += gbBorderColumnSkip;3529 *dest++ = 0; // for filters that read one pixel more3530 break;3531 }3532 case 24:3534 {3535 u8 *dest = (u8 *)pix +3536 3 * (gbBorderLineSkip * (register_LY + gbBorderRowSkip) +3537 gbBorderColumnSkip);3538 for (int x = 0; x < 160; )3539 {3540 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3541 dest += 3;3542 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3543 dest += 3;3544 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3545 dest += 3;3546 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3547 dest += 3;3549 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3550 dest += 3;3551 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3552 dest += 3;3553 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3554 dest += 3;3555 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3556 dest += 3;3558 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3559 dest += 3;3560 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3561 dest += 3;3562 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3563 dest += 3;3564 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3565 dest += 3;3567 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3568 dest += 3;3569 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3570 dest += 3;3571 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3572 dest += 3;3573 *((u32 *)dest) = systemColorMap32[gbLineMix[x++]];3574 dest += 3;3575 }3576 break;3577 }3578 case 32:3580 {3581 u32 *dest = (u32 *)pix +3582 (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1)3583 + gbBorderColumnSkip;3584 for (int x = 0; x < 160; )3585 {3586 *dest++ = systemColorMap32[gbLineMix[x++]];3587 *dest++ = systemColorMap32[gbLineMix[x++]];3588 *dest++ = systemColorMap32[gbLineMix[x++]];3589 *dest++ = systemColorMap32[gbLineMix[x++]];3591 *dest++ = systemColorMap32[gbLineMix[x++]];3592 *dest++ = systemColorMap32[gbLineMix[x++]];3593 *dest++ = systemColorMap32[gbLineMix[x++]];3594 *dest++ = systemColorMap32[gbLineMix[x++]];3596 *dest++ = systemColorMap32[gbLineMix[x++]];3597 *dest++ = systemColorMap32[gbLineMix[x++]];3598 *dest++ = systemColorMap32[gbLineMix[x++]];3599 *dest++ = systemColorMap32[gbLineMix[x++]];3601 *dest++ = systemColorMap32[gbLineMix[x++]];3602 *dest++ = systemColorMap32[gbLineMix[x++]];3603 *dest++ = systemColorMap32[gbLineMix[x++]];3604 *dest++ = systemColorMap32[gbLineMix[x++]];3605 }3606 break;3607 }3608 }3609 }3610 }3611 }3612 gbLcdTicks += GBLCD_MODE_0_CLOCK_TICKS;3613 gbLcdMode = 0;3614 // only one LCD interrupt per line. may need to generalize...3615 if (!(register_STAT & 0x40) ||3616 (register_LY != register_LYC))3617 {3618 if (register_STAT & 0x08)3619 gbInterrupt |= 2;3620 }3621 if (gbHdmaOn)3622 {3623 gbDoHdma();3624 }3625 break;3626 }3627 // mark the correct lcd mode on STAT register3628 register_STAT = (register_STAT & 0xfc) | gbLcdMode;3629 }3630 }3632 // serial emulation3633 if (gbSerialOn)3634 {3635 #ifdef LINK_EMULATION3636 if (linkConnected)3637 {3638 gbSerialTicks -= clockTicks;3640 while (gbSerialTicks <= 0)3641 {3642 // increment number of shifted bits3643 gbSerialBits++;3644 linkProc();3645 if (gbSerialOn && (gbMemory[0xff02] & 1))3646 {3647 if (gbSerialBits == 8)3648 {3649 gbSerialBits = 0;3650 gbMemory[0xff01] = 0xff;3651 gbMemory[0xff02] &= 0x7f;3652 gbSerialOn = 0;3653 gbInterrupt |= 8;3654 gbSerialTicks = 0;3655 }3656 }3657 gbSerialTicks += GBSERIAL_CLOCK_TICKS;3658 }3659 }3660 else3661 {3662 #endif3663 if (gbMemory[0xff02] & 1)3664 {3665 gbSerialTicks -= clockTicks;3667 // overflow3668 while (gbSerialTicks <= 0)3669 {3670 // shift serial byte to right and put a 1 bit in its place3671 // gbMemory[0xff01] = 0x80 | (gbMemory[0xff01]>>1);3672 // increment number of shifted bits3673 gbSerialBits++;3674 if (gbSerialBits == 8)3675 {3676 // end of transmission3677 if (gbSerialFunction) // external device3678 gbMemory[0xff01] = gbSerialFunction(gbMemory[0xff01]);3679 else3680 gbMemory[0xff01] = 0xff;3681 gbSerialTicks = 0;3682 gbMemory[0xff02] &= 0x7f;3683 gbSerialOn = 0;3684 gbInterrupt |= 8;3685 gbSerialBits = 0;3686 }3687 else3688 gbSerialTicks += GBSERIAL_CLOCK_TICKS;3689 }3690 }3691 #ifdef LINK_EMULATION3692 }3693 #endif3694 }3696 // timer emulation3697 if (gbTimerOn)3698 {3699 gbTimerTicks -= clockTicks;3701 while (gbTimerTicks <= 0)3702 {3703 register_TIMA++;3705 if (register_TIMA == 0)3706 {3707 // timer overflow!3709 // reload timer modulo3710 register_TIMA = register_TMA;3712 // flag interrupt3713 gbInterrupt |= 4;3714 }3716 gbTimerTicks += gbTimerClockTicks;3717 }3718 }3720 /*3721 if(soundOffFlag)3722 {3723 if(synchronize && !speedup)3724 {3725 synchronizeTicks -= clockTicks;3727 while(synchronizeTicks < 0)3728 {3729 synchronizeTicks += SYNCHRONIZE_CLOCK_TICKS;3731 DWORD now = timeGetTime();3732 gbElapsedTime += (now - timeNow);3734 if(gbElapsedTime < 50)3735 {3736 DWORD diff = 50 - gbElapsedTime;3737 Sleep(diff);3738 timeNow = timeGetTime();3739 elapsedTime = timeNow - now - diff;3740 if((int)elapsedTime < 0)3741 elapsedTime = 0;3742 } else3743 {3744 timeNow = timeGetTime();3745 elapsedTime = 0;3746 }3747 }3748 }3749 }3750 */3752 soundTicks -= clockTicks;3753 while (soundTicks < 0) // must be < 1 when soundtick_t is real data type3754 {3755 soundTicks += SOUND_CLOCK_TICKS;3757 gbSoundTick();3758 }3760 register_IF = gbInterrupt;3762 if (IFF & 0x20)3763 {3764 IFF &= 0xdf;3765 IFF |= 0x01;3766 gbInterruptWait = 0;3767 }3768 else if (gbInterrupt)3769 {3770 if (gbInterruptWait == 0)3771 {3772 // gbInterruptWait = 0;3774 if (IFF & 0x01)3775 {3776 if ((gbInterrupt & 1) && (register_IE & 1))3777 {3778 gbVblank_interrupt();3779 return newFrame;3780 }3782 if ((gbInterrupt & 2) && (register_IE & 2))3783 {3784 gbLcd_interrupt();3785 return newFrame;3786 }3788 if ((gbInterrupt & 4) && (register_IE & 4))3789 {3790 gbTimer_interrupt();3791 return newFrame;3792 }3794 if ((gbInterrupt & 8) && (register_IE & 8))3795 {3796 gbSerial_interrupt();3797 return newFrame;3798 }3800 if ((gbInterrupt & 16) && (register_IE & 16))3801 {3802 gbJoypad_interrupt();3803 return newFrame;3804 }3805 }3806 }3807 else3808 {3809 gbInterruptWait -= clockTicks;3810 if (gbInterruptWait < 0)3811 gbInterruptWait = 0;3812 }3813 }3815 if (useOldFrameTiming)3816 {3817 // old timing code3818 if (ticksToStop > 0)3819 return newFrame;3820 }3821 else3822 {3823 if (!newFrame && (register_LCDC & 0x80) != 0)3824 return newFrame;3825 }3827 if (!(register_LCDC & 0x80))3828 {3829 if (!useOldFrameTiming)3830 {3831 // FIXME: since register_LY can be reset to 0 by some games, frame length is variable3832 // and infinite loops can occurr3833 // for now, it IS necessary to do something on this condition or games like3834 // Megaman would freeze upon low-level restart interrupt sequence (Start+Select+A+B).3835 // the only sensible way to fix this issue is to implement the RIGHT frame timing3836 #ifdef WANTS_INCOMPLETE_WORKAROUND3837 if (systemReadJoypads())3838 {3839 if (gbSgbMode && gbSgbMultiplayer)3840 {3841 if (gbSgbFourPlayers)3842 {3843 gbJoymask[0] = systemGetJoypad(0, false);3844 gbJoymask[1] = systemGetJoypad(1, false);3845 gbJoymask[2] = systemGetJoypad(2, false);3846 gbJoymask[3] = systemGetJoypad(3, false);3847 }3848 else3849 {3850 gbJoymask[0] = systemGetJoypad(0, false);3851 gbJoymask[1] = systemGetJoypad(1, false);3852 }3853 }3854 else3855 {3856 gbJoymask[0] = systemGetJoypad(0, false);3857 }3858 }3859 else3860 gbJoymask[0] = gbJoymask[1] = gbJoymask[2] = gbJoymask[3] = 0;3861 #else3862 #endif3863 }3864 }3866 // makes sure frames are really divided across input sampling boundaries which occur at a constant rate3867 //if (newFrame || useOldFrameTiming)3868 // {3869 /// extern void VBAOnEnteringFrameBoundary();3870 /// VBAOnEnteringFrameBoundary();3872 // break;3873 // }3874 // RLM removing for loop }3875 return newFrame;3876 }3880 //RLM:3881 int getRamSize(){3882 return gbRamSize;3883 }3885 int getRomSize(){3886 return gbRomSize;3887 }3889 void storeMemory(int32* store){3890 int i;3891 int j;3892 for (i = 0; i < 0x10; i++){3893 for (j = 0; j < 0x1000; j++){3894 store[i*0x1000 + j] = (int32) gbMemoryMap[i][j];3895 }3896 }3897 }3899 void writeMemory(int32* newMemory){3900 int i;3901 int j;3902 for (i = 0; i < 0x10; i++){3903 for (j = 0; j< 0x1000; j++){3904 gbMemoryMap[i][j] = (u8)(0xFF & newMemory[i*0x1000 + j]);3905 }3906 }3907 }3909 void storeRam(int32* store){3910 int i;3911 for (i = 0; i < gbRamSize; i++){3912 store[i] = (int32) gbRam[i];3913 }3914 }3916 void storeRom(int32* store){3917 int i;3918 for (i = 0; i < gbRomSize; i++){3919 store[i] = (int32) gbRom[i];3920 }3921 }3923 void writeRom(int32* new_rom){3924 int i;3925 for (i = 0; i < gbRomSize; i++){3926 gbRom[i] = (u8)(0xFF & new_rom[i]);3927 }3928 }3930 void storeWRam(int32* store){3931 int i;3932 for (i = 0; i < 0x8000; i++){3933 store[i] = (int32) gbWram[i];3934 }3935 }3937 void storeVRam(int32* store){3938 int i;3939 for (i = 0; i < 0x4000; i++){3940 store[i] = (int32) gbVram[i];3941 }3942 }3945 void storeRegisters(int32* store){3946 store[0] = (int32) PC.W;3947 store[1] = (int32) SP.W;3948 store[2] = (int32) AF.W;3949 store[3] = (int32) BC.W;3950 store[4] = (int32) DE.W;3951 store[5] = (int32) HL.W;3953 store[6] = (int32) IFF;3955 store[7] = (int32) register_DIV;3956 store[8] = (int32) register_TIMA;3957 store[9] = (int32) register_TMA;3958 store[10] = (int32) register_TAC;3959 store[11] = (int32) register_IF;3960 store[12] = (int32) register_LCDC;3961 store[13] = (int32) register_STAT;3962 store[14] = (int32) register_SCY;3963 store[15] = (int32) register_SCX;3964 store[16] = (int32) register_LY;3965 store[17] = (int32) register_LYC;3966 store[18] = (int32) register_DMA;3967 store[19] = (int32) register_WY;3968 store[20] = (int32) register_WX;3969 store[21] = (int32) register_VBK;3970 store[22] = (int32) register_HDMA1;3971 store[23] = (int32) register_HDMA2;3972 store[24] = (int32) register_HDMA3;3973 store[25] = (int32) register_HDMA4;3974 store[26] = (int32) register_HDMA5;3975 store[27] = (int32) register_SVBK;3976 store[28] = (int32) register_IE;3977 }3979 void setRegisters(int32* registers){3980 PC.W = (u16) (0xFFFF & registers[0]);3981 SP.W = (u16) (0xFFFF & registers[1]);3982 AF.W = (u16) (0xFFFF & registers[2]);3983 BC.W = (u16) (0xFFFF & registers[3]);3984 DE.W = (u16) (0xFFFF & registers[4]);3985 HL.W = (u16) (0xFFFF & registers[5]);3986 IFF = (u16) (0xFFFF & registers[6]);3988 register_DIV = (u8) (0xFF & registers[7]);3989 register_TIMA = (u8) (0xFF & registers[8]);3990 register_TMA = (u8) (0xFF & registers[9]);3991 register_TAC = (u8) (0xFF & registers[10]);3992 register_IF = (u8) (0xFF & registers[11]);3993 register_LCDC = (u8) (0xFF & registers[12]);3994 register_STAT = (u8) (0xFF & registers[13]);3995 register_SCY = (u8) (0xFF & registers[14]);3996 register_SCX = (u8) (0xFF & registers[15]);3997 register_LY = (u8) (0xFF & registers[16]);3998 register_LYC = (u8) (0xFF & registers[17]);3999 register_DMA = (u8) (0xFF & registers[18]);4000 register_WY = (u8) (0xFF & registers[19]);4001 register_WX = (u8) (0xFF & registers[20]);4002 register_VBK = (u8) (0xFF & registers[21]);4003 register_HDMA1 = (u8) (0xFF & registers[22]);4004 register_HDMA2 = (u8) (0xFF & registers[23]);4005 register_HDMA3 = (u8) (0xFF & registers[24]);4006 register_HDMA4 = (u8) (0xFF & registers[25]);4007 register_HDMA5 = (u8) (0xFF & registers[26]);4008 register_SVBK = (u8) (0xFF & registers[27]);4009 register_IE = (u8) (0xFF & registers[28]);4010 }4012 struct EmulatedSystem GBSystem =4013 {4014 // emuMain4015 gbEmulate,4016 // emuReset4017 gbReset,4018 // emuCleanUp4019 gbCleanUp,4020 // emuReadBattery4021 gbReadBatteryFile,4022 // emuWriteBattery4023 gbWriteBatteryFile,4024 // emuReadBatteryFromStream4025 gbReadBatteryFromStream,4026 // emuWriteBatteryToStream4027 gbWriteBatteryToStream,4028 // emuReadState4029 gbReadSaveState,4030 // emuWriteState4031 gbWriteSaveState,4032 // emuReadStateFromStream4033 gbReadSaveStateFromStream,4034 // emuwritestatetostream4035 gbWriteSaveStateToStream,4036 // emuReadMemState4037 gbReadMemSaveState,4038 // emuWriteMemState4039 gbWriteMemSaveState,4040 // emuWritePNG4041 gbWritePNGFile,4042 // emuWriteBMP4043 gbWriteBMPFile,4044 // emuUpdateCPSR4045 NULL,4046 // emuHasDebugger4047 false,4048 // emuCount4049 #ifdef FINAL_VERSION4050 70000 / 4,4051 #else4052 1000,4053 #endif4054 };4056 // is there a reason to use more than one set of counters?4057 EmulatedSystemCounters &GBSystemCounters = systemCounters;4059 /*4060 EmulatedSystemCounters GBSystemCounters =4061 {4062 // frameCount4063 0,4064 // lagCount4065 0,4066 // lagged4067 true,4068 // laggedLast4069 true,4070 };4071 */